Source Code Cross Referenced for Node.java in  » IDE-Netbeans » openide » org » openide » nodes » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » IDE Netbeans » openide » org.openide.nodes 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
0003:         *
0004:         * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
0005:         *
0006:         * The contents of this file are subject to the terms of either the GNU
0007:         * General Public License Version 2 only ("GPL") or the Common
0008:         * Development and Distribution License("CDDL") (collectively, the
0009:         * "License"). You may not use this file except in compliance with the
0010:         * License. You can obtain a copy of the License at
0011:         * http://www.netbeans.org/cddl-gplv2.html
0012:         * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
0013:         * specific language governing permissions and limitations under the
0014:         * License.  When distributing the software, include this License Header
0015:         * Notice in each file and include the License file at
0016:         * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
0017:         * particular file as subject to the "Classpath" exception as provided
0018:         * by Sun in the GPL Version 2 section of the License file that
0019:         * accompanied this code. If applicable, add the following below the
0020:         * License Header, with the fields enclosed by brackets [] replaced by
0021:         * your own identifying information:
0022:         * "Portions Copyrighted [year] [name of copyright owner]"
0023:         *
0024:         * Contributor(s):
0025:         *
0026:         * The Original Software is NetBeans. The Initial Developer of the Original
0027:         * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
0028:         * Microsystems, Inc. All Rights Reserved.
0029:         *
0030:         * If you wish your version of this file to be governed by only the CDDL
0031:         * or only the GPL Version 2, indicate your decision by adding
0032:         * "[Contributor] elects to include this software in this distribution
0033:         * under the [CDDL or GPL Version 2] license." If you do not indicate a
0034:         * single choice of license, a recipient has the option to distribute
0035:         * your version of this file under either the CDDL, the GPL Version 2 or
0036:         * to extend the choice of license to its licensees as provided above.
0037:         * However, if you add GPL Version 2 code and therefore, elected the GPL
0038:         * Version 2 license, then the option applies only if the new code is
0039:         * made subject to such option by the copyright holder.
0040:         */
0041:
0042:        package org.openide.nodes;
0043:
0044:        import java.awt.Image;
0045:        import java.awt.datatransfer.Transferable;
0046:        import java.beans.FeatureDescriptor;
0047:        import java.beans.PropertyChangeEvent;
0048:        import java.beans.PropertyChangeListener;
0049:        import java.beans.PropertyEditor;
0050:        import java.io.IOException;
0051:        import java.io.PrintWriter;
0052:        import java.io.StringWriter;
0053:        import java.lang.ref.Reference;
0054:        import java.lang.ref.SoftReference;
0055:        import java.lang.ref.WeakReference;
0056:        import java.lang.reflect.InvocationTargetException;
0057:        import java.util.HashSet;
0058:        import java.util.Map;
0059:        import java.util.Set;
0060:        import java.util.WeakHashMap;
0061:        import java.util.logging.Level;
0062:        import java.util.logging.Logger;
0063:        import javax.swing.Action;
0064:        import javax.swing.JPopupMenu;
0065:        import javax.swing.event.EventListenerList;
0066:        import org.openide.util.HelpCtx;
0067:        import org.openide.util.Lookup;
0068:        import org.openide.util.LookupEvent;
0069:        import org.openide.util.LookupListener;
0070:        import org.openide.util.NbBundle;
0071:        import org.openide.util.actions.SystemAction;
0072:        import org.openide.util.datatransfer.NewType;
0073:        import org.openide.util.datatransfer.PasteType;
0074:
0075:        /** A <em>node</em> represents one element in a hierarchy of objects (beans).
0076:         * It provides all methods that are needed for communication between
0077:         * an explorer view and the bean.
0078:         * <P>
0079:         * The node has three purposes:
0080:         * <OL>
0081:         *   <LI>visually represent the object in the tree hierarchy (i.e. Explorer)
0082:         *   <LI>provide sets of properties for that object (i.e. Component Inspector, Property Sheet)
0083:         *   <LI>offer actions to perform on itself
0084:         * </OL>
0085:         * <P>
0086:         * Frequently nodes are created to represent <code>DataObject</code>s.
0087:         * But they may also represent anything to be displayed to the user or manipulated programmatically,
0088:         * even if they have no data directly stored behind them; for example, a control panel or debugger
0089:         * breakpoint.
0090:         * <P>
0091:         * There are two listeners in this class: {@link PropertyChangeListener}
0092:         * and {@link NodeListener} (which extends <code>PropertyChangeListener</code>). The first
0093:         * is designed to listen on properties that can be returned from
0094:         * {@link #getPropertySets}, the later for listening on changes in the
0095:         * node itself (including the name, children, parent, set of properties,
0096:         * icons, etc.). Be sure to distinguish between these two.
0097:         * <P>
0098:         * The node is cloneable. When a node is cloned, it is initialized
0099:         * with an empty set of listeners and no parent. The display name and short description
0100:         * are copied to the new node. The set of properties is <em>shared</em>.
0101:         * <P>
0102:         * Implements {@link org.openide.util.Lookup.Provider} since 3.11.
0103:         *
0104:         * @author Jaroslav Tulach,
0105:         */
0106:        public abstract class Node extends FeatureDescriptor implements 
0107:                Lookup.Provider, HelpCtx.Provider {
0108:            /** An empty leaf node. */
0109:            public static final Node EMPTY = new AbstractNode(Children.LEAF);
0110:
0111:            /* here is list of property names that can be changed in the Node object.
0112:             * These properties can be notified to the <CODE>NodeListener</CODE>.
0113:             */
0114:
0115:            /** Property for node display name. */
0116:            public static final String PROP_DISPLAY_NAME = "displayName"; // NOI18N
0117:
0118:            /** Property for internal (not displayable) name of a node. This name is often used to
0119:             * look up a node in the hierarchy, so it should be chosen to be simple.
0120:             */
0121:            public static final String PROP_NAME = "name"; // NOI18N
0122:
0123:            /** Property for short description of a node. */
0124:            public static final String PROP_SHORT_DESCRIPTION = "shortDescription"; // NOI18N
0125:
0126:            /** Property for the normal (closed) icon of a node. */
0127:            public static final String PROP_ICON = "icon"; // NOI18N
0128:
0129:            /** Property for the opened icon of a node. */
0130:            public static final String PROP_OPENED_ICON = "openedIcon"; // NOI18N
0131:
0132:            /** Property for a node's parent. */
0133:            public static final String PROP_PARENT_NODE = "parentNode"; // NOI18N
0134:
0135:            /** Property for a node's list of property sets. */
0136:            public static final String PROP_PROPERTY_SETS = "propertySets"; // NOI18N
0137:
0138:            /** Property for a node's cookie set. */
0139:            public static final String PROP_COOKIE = "cookie"; // NOI18N
0140:
0141:            /** Property saying whether the Node is Leaf
0142:             *@since 3.1
0143:             */
0144:            public static final String PROP_LEAF = "leaf"; // NOI18N
0145:
0146:            /** Error manager used for logging and its precomputed err.isLoggable(Level.FINE) 
0147:             */
0148:            private static final Logger err = Logger
0149:                    .getLogger("org.openide.nodes.Node"); //NOI18N;
0150:
0151:            /** cache of all created lookups */
0152:            private static Map<EventListenerList, Reference<Lookup>> lookups = new WeakHashMap<EventListenerList, Reference<Lookup>>(
0153:                    37);
0154:
0155:            /** class.property names we have warned about for #31413 */
0156:            private static final Set<String> warnedBadProperties = new HashSet<String>(
0157:                    100);
0158:
0159:            /** template for changes in cookies */
0160:            private static final Lookup.Template<Node.Cookie> TEMPL_COOKIE = new Lookup.Template<Node.Cookie>(
0161:                    Node.Cookie.class);
0162:
0163:            /** Lock for initialization */
0164:            private static final Object INIT_LOCK = new Object();
0165:
0166:            /** children representing parent node (Children or ChildrenArray),
0167:             * for synchronization reasons must be changed only
0168:             * under the Children.MUTEX lock
0169:             */
0170:            private Object parent;
0171:
0172:            /** children list, for synch. reasons change only under Children.MUTEX
0173:             * lock
0174:             */
0175:            Children hierarchy;
0176:
0177:            /** listeners for changes in hierarchy.
0178:             */
0179:            private transient EventListenerList listeners;
0180:
0181:            /** Creates a new node with a given hierarchy of children.
0182:             * @param h the children to use for this node
0183:             * @exception IllegalStateException if the children object is already in use by
0184:             *   a different node
0185:             */
0186:            protected Node(Children h) throws IllegalStateException {
0187:                this (h, null);
0188:            }
0189:
0190:            /** Creates a new node with a given hierarchy of children and a lookup
0191:             * providing content for {@link #getCookie} and {@link #getLookup} methods.
0192:             * <p>
0193:             * As the lookup needs to be constructed before Node's constructor is called,
0194:             * it might not be obvious how to add Node or other objects into it without
0195:             * type casting. Here is the recommended suggestion that uses public/private
0196:             * pair of constructors:
0197:             * <PRE>
0198:            <span class="keyword">public</span> <span class="function-name">MyNode</span><span class="constant">(</span><span class="variable-name">Children</span> <span class="variable-name">ch</span><span class="constant">,</span> <span class="variable-name">FileObject</span> <span class="variable-name">fil</span><span class="variable-name">e</span><span class="constant">)</span> <span class="constant">{</span>
0199:                <span class="keyword">this</span><span class="constant">(</span><span class="variable-name">ch</span><span class="constant">, </span><span class="variable-name">file</span><span class="constant">,</span> <span class="keyword">new</span> <span class="function-name">InstanceContent</span><span class="constant">(</span><span class="constant">)</span><span class="constant">)</span><span class="constant">;</span>
0200:            <span class="constant">}</span>
0201:
0202:            <span class="comment">/** A private constructor that takes an InstanceContent and</span>
0203:            <span class="comment">     * uses it as internals for the Node lookup and also allow us</span>
0204:            <span class="comment">     * to modify the content, for example by adding a reference </span>
0205:            <span class="comment">     * to the node itself or any other object we want to represent.</span>
0206:            <span class="comment">     *</span>
0207:            <span class="comment">     * @param ch children we wish to use</span>
0208:            <span class="comment">     * @param file sample object we wish to have in lookup</span>
0209:            <span class="comment">     * @param content the content created by the first constructor</span>
0210:            <span class="comment">     *<b></b>/</span>
0211:            <span class="keyword">private</span> <span class="function-name">MyNode</span><span class="constant">(</span><span class="variable-name">Children</span> <span class="variable-name">ch</span><span class="constant">,</span> <span class="variable-name">FileObject</span> <span class="variable-name">file</span><span class="constant">,</span> <span class="variable-name">InstanceContent</span> <span class="variable-name">content</span><span class="constant">)</span> <span class="constant">{</span>
0212:                <span class="keyword">super</span><span class="constant">(</span><span class="variable-name">ch</span><span class="constant">,</span> <span class="keyword">new</span> <span class="function-name">AbstractLookup</span><span class="constant">(</span><span class="variable-name">content</span><span class="constant">)</span><span class="constant">)</span><span class="constant">;</span>
0213:                <span class="comment">// adds the node to our own lookup</span>
0214:                <span class="variable-name">content</span><span class="constant">.</span><span class="function-name">add</span> <span class="constant">(</span><span class="keyword">this</span><span class="constant">)</span><span class="constant">;</span>
0215:                <span class="comment">// adds additional items to the lookup</span>
0216:                <span class="variable-name">content</span><span class="constant">.</span><span class="function-name">add</span> <span class="constant">(</span><span class="variable-name">file</span><span class="constant">)</span><span class="constant">;</span>
0217:            <span class="constant">}</span>
0218:            </PRE>
0219:             *
0220:             * @since 3.11
0221:             * @param h the children to use for this node
0222:             * @param lookup the lookup to provide content of {@link #getLookup}
0223:             *   and also {@link #getCookie}
0224:             * @exception IllegalStateException if the children object is already in use by
0225:             *   a different node
0226:             */
0227:            protected Node(Children h, Lookup lookup)
0228:                    throws IllegalStateException {
0229:                this .hierarchy = h;
0230:
0231:                // allow subclasses (FilterNode) to update the lookup
0232:                lookup = replaceProvidedLookup(lookup);
0233:
0234:                if (lookup != null) {
0235:                    this .listeners = new LookupEventList(lookup);
0236:                } else {
0237:                    this .listeners = new EventListenerList();
0238:                }
0239:
0240:                // attaches to this node
0241:                h.attachTo(this );
0242:            }
0243:
0244:            /** Method for subclasses to modify provided lookup before its use.
0245:             * This implementation does nothing.
0246:             */
0247:            Lookup replaceProvidedLookup(Lookup l) {
0248:                return l;
0249:            }
0250:
0251:            /** Method that gives access to internal lookup.
0252:             * @param init should it be really initialized (ready for queries) or need not be
0253:             * @return lookup or null
0254:             */
0255:            final Lookup internalLookup(boolean init) {
0256:                if (listeners instanceof  LookupEventList) {
0257:                    return ((LookupEventList) listeners).init(init);
0258:                } else {
0259:                    return null;
0260:                }
0261:            }
0262:
0263:            /** Implements {@link Object#clone} to behave correctly if cloning is desired.
0264:             * But {@link Cloneable} is <em>not</em> declared by default.
0265:             * <P>
0266:             * The default implementation checks whether the child list implements
0267:             * <code>Cloneable</code>, and if so, it clones the children.
0268:             * If the child list does not support cloning, {@link Children#LEAF} is used
0269:             * instead for the children. The parent of this node is set to <code>null</code> and an empty set
0270:             * of listeners is attached to the node.
0271:             *
0272:             * @return the cloned version of the node
0273:             * @exception CloneNotSupportedException if the children cannot be cloned
0274:             *    in spite of implementing <code>Cloneable</code>
0275:             */
0276:            protected Object clone() throws CloneNotSupportedException {
0277:                Node n = (Node) super .clone();
0278:                Children hier2;
0279:
0280:                if (hierarchy instanceof  Cloneable) {
0281:                    hier2 = (Children) hierarchy.cloneHierarchy();
0282:                } else {
0283:                    hier2 = Children.LEAF;
0284:                }
0285:
0286:                // attach the hierarchy
0287:                n.hierarchy = hier2;
0288:                hier2.attachTo(n);
0289:
0290:                // no parent
0291:                n.parent = null;
0292:
0293:                // empty set of listeners
0294:                if (listeners instanceof  LookupEventList) {
0295:                    n.listeners = new LookupEventList(internalLookup(false));
0296:                } else {
0297:                    n.listeners = new EventListenerList();
0298:                }
0299:
0300:                return n;
0301:            }
0302:
0303:            /** Clone the node. The newly created node should reference the same
0304:             * object is this node does, but it should not be inserted as a child
0305:             * to any other node. Also it should have an empty set of listeners.
0306:             * In all other respects the node should behave exactly as the
0307:             * original one does.
0308:             *
0309:             * @return copy of this node
0310:             */
0311:            public abstract Node cloneNode();
0312:
0313:            /** Finds the children we are attached to.
0314:             * @return children
0315:             */
0316:            private Children getParentChildren() {
0317:                Object p = this .parent;
0318:                return (p instanceof  ChildrenArray) ? ((ChildrenArray) p)
0319:                        .getChildren() : (Children) p;
0320:            }
0321:
0322:            /** Method that allows Children to change the parent children of
0323:             * the node when the node is add to a children.
0324:             *
0325:             * @param parent the children that wants to contain this node
0326:             * @param index index that will be assigned to this node
0327:             * @exception IllegalStateException if this node already belongs to a children
0328:             */
0329:            final synchronized void assignTo(Children parent, int index) {
0330:                Children ch = getParentChildren();
0331:
0332:                if ((ch != null) && (ch != parent)) {
0333:                    throw new IllegalStateException("Cannot initialize "
0334:                            + index + "th child of node " + parent.getNode()
0335:                            + "; it already belongs to node " + ch.getNode()); // NOI18N
0336:                }
0337:
0338:                if (!(this .parent instanceof  ChildrenArray)) {
0339:                    this .parent = parent;
0340:                }
0341:            }
0342:
0343:            /** Code that reassigns the reference from to parent from its
0344:             * Children to its ChildrenArray.
0345:             */
0346:            final synchronized void reassignTo(Children currentParent,
0347:                    ChildrenArray itsArray) {
0348:                if ((this .parent != currentParent) && (this .parent != itsArray)) {
0349:                    throw new IllegalStateException(
0350:                            "Unauthorized call to change parent: "
0351:                                    + this .parent + " and should be: "
0352:                                    + currentParent);
0353:                }
0354:
0355:                this .parent = itsArray;
0356:            }
0357:
0358:            /** Deassigns the node from a children, when it is removed from
0359:             * a children.
0360:             */
0361:            final synchronized void deassignFrom(Children parent) {
0362:                Children p = getParentChildren();
0363:
0364:                if (parent != p) {
0365:                    throw new IllegalArgumentException(
0366:                            "Deassign from wrong parent. Old: " + p
0367:                                    + " Caller: " + parent); //NOI18N
0368:                }
0369:
0370:                this .parent = null;
0371:            }
0372:
0373:            /** Set the system name. Fires a property change event.
0374:             * @param s the new name
0375:             * @exception IllegalArgumentException if the new name cannot represent
0376:             *    a valid node name
0377:             */
0378:            public void setName(String s) {
0379:                String name = super .getName();
0380:
0381:                if ((name == null) || !name.equals(s)) {
0382:                    super .setName(s);
0383:                    fireNameChange(name, s);
0384:                }
0385:            }
0386:
0387:            /** Set the display name. Fires a property change event.
0388:             * @param s the new name
0389:             */
0390:            public void setDisplayName(String s) {
0391:                String displayName = super .getDisplayName();
0392:
0393:                if ((displayName == null) || !displayName.equals(s)) {
0394:                    super .setDisplayName(s);
0395:                    fireDisplayNameChange(displayName, s);
0396:                }
0397:            }
0398:
0399:            /** Set the short description of the node. Fires a property change event.
0400:             * <p>This description may be used for tool tips, etc.
0401:             * @param s the new description
0402:             */
0403:            public void setShortDescription(String s) {
0404:                String descr = super .getShortDescription();
0405:
0406:                if ((descr == null) || !descr.equals(s)) {
0407:                    super .setShortDescription(s);
0408:                    fireShortDescriptionChange(descr, s);
0409:                }
0410:            }
0411:
0412:            /** Find an icon for this node (in the closed state).
0413:             * @param type constant from {@link java.beans.BeanInfo}
0414:             * @return icon to use to represent the node
0415:             */
0416:            public abstract Image getIcon(int type);
0417:
0418:            /** Find an icon for this node (in the open state).
0419:             * This icon is used when the node may have children and is expanded.
0420:             *
0421:             * @param type constant from {@link java.beans.BeanInfo}
0422:             * @return icon to use to represent the node when open
0423:             */
0424:            public abstract Image getOpenedIcon(int type);
0425:
0426:            /** Get context help associated with this node.
0427:             * @return the context help object (could be <code>null</code> or {@link HelpCtx#DEFAULT_HELP})
0428:             */
0429:            public abstract HelpCtx getHelpCtx();
0430:
0431:            /** Get the list of children.
0432:             * @return the children
0433:             */
0434:            public final Children getChildren() {
0435:                updateChildren();
0436:
0437:                return hierarchy;
0438:            }
0439:
0440:            /** Can be overridden in subclasses (probably in FilterNode) to check
0441:             * whether children are of the right subclass
0442:             */
0443:            void updateChildren() {
0444:            }
0445:
0446:            /** Allows to change Children of the node. Call to this method aquires
0447:             * write lock on the nodes hierarchy. Take care not to call this method
0448:             * under read lock.<BR>
0449:             *
0450:             * @param ch New children to be set on the node.
0451:             * @since 3.1
0452:             */
0453:            protected final void setChildren(final Children ch) {
0454:                Children.MUTEX.postWriteRequest(new Runnable() {
0455:                    public void run() {
0456:                        Node[] oldNodes = null;
0457:
0458:                        if (hierarchy.isInitialized()) {
0459:                            oldNodes = hierarchy.getNodes();
0460:                        }
0461:                        hierarchy.detachFrom();
0462:
0463:                        boolean wasLeaf = hierarchy == Children.LEAF;
0464:
0465:                        hierarchy = ch;
0466:                        hierarchy.attachTo(Node.this );
0467:
0468:                        if (wasLeaf != (hierarchy == Children.LEAF)) {
0469:                            fireOwnPropertyChange(PROP_LEAF, wasLeaf,
0470:                                    hierarchy == Children.LEAF);
0471:                        }
0472:
0473:                        if ((oldNodes != null) && !wasLeaf) {
0474:                            fireSubNodesChange(false, oldNodes, oldNodes);
0475:                            Node[] arr = hierarchy.getNodes();
0476:                            if (arr.length > 0) {
0477:                                fireSubNodesChange(true, arr, null);
0478:                            }
0479:                        }
0480:                    }
0481:                });
0482:            }
0483:
0484:            /** Test whether the node is a leaf, or may contain children.
0485:             * @return <code>true</code> if the children list is actually {@link Children#LEAF}
0486:             */
0487:            public final boolean isLeaf() {
0488:                updateChildren();
0489:
0490:                return hierarchy == Children.LEAF;
0491:            }
0492:
0493:            /** Get the parent node.
0494:             * @return the parent node, or <CODE>null</CODE> if this node is the root of a hierarchy
0495:             */
0496:            public final Node getParentNode() {
0497:                // if contained in a list return its parent node
0498:                Children ch = getParentChildren();
0499:
0500:                return (ch == null) ? null : ch.getNode();
0501:            }
0502:
0503:            /** Test whether this node can be renamed.
0504:             * If true, one can use {@link #getName} to obtain the current name and
0505:             * {@link #setName} to change it.
0506:             *
0507:             * @return <code>true</code> if the node can be renamed
0508:             */
0509:            public abstract boolean canRename();
0510:
0511:            /** Test whether this node can be deleted.
0512:             * @return <CODE>true</CODE> if can
0513:             */
0514:            public abstract boolean canDestroy();
0515:
0516:            // [PENDING] "valid" property?  --jglick // NOI18N
0517:
0518:            /** Remove the node from its parent and deletes it.
0519:             * The default
0520:             * implementation obtains write access to
0521:             * the {@link Children#MUTEX children's lock}, and removes
0522:             * the node from its parent (if any). Also fires a property change.
0523:             * <P>
0524:             * This may be overridden by subclasses to do any additional
0525:             * cleanup.
0526:             *
0527:             * @exception IOException if something fails
0528:             */
0529:            public void destroy() throws IOException {
0530:                Children.MUTEX.postWriteRequest(new Runnable() {
0531:                    public void run() {
0532:                        Children p = getParentChildren();
0533:
0534:                        if (p != null) {
0535:                            // remove itself from parent
0536:                            p.remove(new Node[] { Node.this  });
0537:                        }
0538:
0539:                        // sets the valid flag to false and fires prop. change
0540:                        fireNodeDestroyed();
0541:                    }
0542:                });
0543:            }
0544:
0545:            /** Get the list of property sets for this node.
0546:             * E.g. typically there may be one for normal Bean properties, one for expert
0547:             * properties, and one for hidden properties.
0548:             *
0549:             * @return the property sets
0550:             */
0551:            public abstract PropertySet[] getPropertySets();
0552:
0553:            /** Called when a node is to be copied to the clipboard.
0554:             * @return the transferable object representing the
0555:             *    content of the clipboard
0556:             * @exception IOException when the
0557:             *    copy cannot be performed
0558:             */
0559:            public abstract Transferable clipboardCopy() throws IOException;
0560:
0561:            /** Called when a node is to be cut to the clipboard.
0562:             * @return the transferable object representing the
0563:             *    content of the clipboard
0564:             * @exception IOException when the
0565:             *    cut cannot be performed
0566:             */
0567:            public abstract Transferable clipboardCut() throws IOException;
0568:
0569:            /** Called when a drag is started with this node.
0570:             * The node can attach a transfer listener to ExTransferable and
0571:             * will be then notified about progress of the drag (accept/reject).
0572:             *
0573:             * @return transferable to represent this node during a drag
0574:             * @exception IOException if a drag cannot be started
0575:             */
0576:            public abstract Transferable drag() throws IOException;
0577:
0578:            /** Test whether this node permits copying.
0579:             * @return <code>true</code> if so
0580:             */
0581:            public abstract boolean canCopy();
0582:
0583:            /** Test whether this node permits cutting.
0584:             * @return <code>true</code> if so
0585:             */
0586:            public abstract boolean canCut();
0587:
0588:            /** Determine which paste operations are allowed when a given transferable is in the clipboard.
0589:             * For example, a node representing a Java package will permit classes to be pasted into it.
0590:             * @param t the transferable in the clipboard
0591:             * @return array of operations that are allowed
0592:             */
0593:            public abstract PasteType[] getPasteTypes(Transferable t);
0594:
0595:            /** Determine if there is a paste operation that can be performed
0596:             * on provided transferable. Used by drag'n'drop code to check
0597:             * whether the drop is possible.
0598:             *
0599:             * @param t the transferable
0600:             * @param action the drag'n'drop action to do DnDConstants.ACTION_MOVE, ACTION_COPY, ACTION_LINK
0601:             * @param index index between children the drop occurred at or -1 if not specified
0602:             * @return null if the transferable cannot be accepted or the paste type
0603:             *    to execute when the drop occurs
0604:             */
0605:            public abstract PasteType getDropType(Transferable t, int action,
0606:                    int index);
0607:
0608:            /** Get the new types that can be created in this node.
0609:             * For example, a node representing a Java package will permit classes to be added.
0610:             * @return array of new type operations that are allowed
0611:             */
0612:            public abstract NewType[] getNewTypes();
0613:
0614:            /** Get the set of actions that are associated with this node.
0615:             * This set is used to construct the context menu for the node.
0616:             *
0617:             * <P>
0618:             * By default this method delegates to the deprecated getActions or getContextActions
0619:             * method depending on the value of supplied argument.
0620:             * <P>
0621:             * It is supposed to be overridden by subclasses accordingly.
0622:             *
0623:             * @param context whether to find actions for context meaning or for the
0624:             *   node itself
0625:             * @return a list of actions (you may include nulls for separators)
0626:             * @since 3.29
0627:             */
0628:            public Action[] getActions(boolean context) {
0629:                return context ? getContextActions() : getActions();
0630:            }
0631:
0632:            /** Get the set of actions associated with this node.
0633:             * This may be used e.g. in constructing a {@link #getContextMenu context menu}.
0634:             *
0635:             * <P>
0636:             * By default returns the actions in {@link NodeOp#getDefaultActions}.
0637:             *
0638:             * @return system actions appropriate to the node
0639:             * @deprecated Use getActions (false) instead.
0640:             */
0641:            @Deprecated
0642:            public SystemAction[] getActions() {
0643:                return NodeOp.getDefaultActions();
0644:            }
0645:
0646:            /** Get a special set of actions
0647:             * for situations when this node is displayed as a context.
0648:             * <p>For example, right-clicking on a parent node in a hierarchical view (such as
0649:             * the normal Explorer) should use <code>getActions</code>. However, if this node
0650:             * is serving as the parent of a (say) a window tab full of icons (e.g., in
0651:             * <code>IconView</code>), and the users right-clicks on
0652:             * the empty space in this pane, then this method should be used to get
0653:             * the appropriate actions for a context menu.
0654:             * <p>Note that in the Windows UI system, e.g., these action sets are quite different.
0655:             *
0656:             * @return actions for a context. In the default implementation, same as {@link #getActions}.
0657:             * @deprecated Use getActions (true) instead.
0658:             */
0659:            @Deprecated
0660:            public SystemAction[] getContextActions() {
0661:                return getActions();
0662:            }
0663:
0664:            /** Gets the default action for this node.
0665:             * @return <code>null</code> indicating there should be none default action
0666:             * @deprecated Use {@link #getPreferredAction} instead.
0667:             */
0668:            @Deprecated
0669:            public SystemAction getDefaultAction() {
0670:                return null;
0671:            }
0672:
0673:            /** Gets the preferred action for this node.
0674:             * This action can but need not to be one from the action array returned
0675:             * from {@link #getActions(boolean)}.
0676:             * In case it is, the context menu created from those actions
0677:             * is encouraged to highlight the preferred action.
0678:             * Override in subclasses accordingly.
0679:             *
0680:             * @return the preferred action, or <code>null</code> if there is none
0681:             * @since 3.29
0682:             */
0683:            public Action getPreferredAction() {
0684:                return getDefaultAction();
0685:            }
0686:
0687:            /** Make a context menu for this node.
0688:             * The menu is constructed from the set of actions returned by {@link #getActions}.
0689:             *
0690:             * @return the context menu
0691:             */
0692:            public final JPopupMenu getContextMenu() {
0693:                return NodeOp.findContextMenuImpl(new Node[] { this  }, null);
0694:            }
0695:
0696:            /** Test whether there is a customizer for this node. If true,
0697:             * the customizer can be obtained via {@link #getCustomizer}.
0698:             *
0699:             * @return <CODE>true</CODE> if there is a customizer
0700:             */
0701:            public abstract boolean hasCustomizer();
0702:
0703:            /** Get the customizer component.
0704:             * @return the component, or <CODE>null</CODE> if there is no customizer
0705:             */
0706:            public abstract java.awt.Component getCustomizer();
0707:
0708:            /** Get a cookie for this node.
0709:             * <P>
0710:             * The set of cookies can change. If a node changes its set of
0711:             * cookies, it fires a property change event with {@link #PROP_COOKIE}.
0712:             * <P>
0713:             * If the Node was constructed with a <code>Lookup</code> in constructor
0714:             * than this method delegates to the provided lookup object.
0715:             *
0716:             * @param type the representation class of the cookie
0717:             * @return a cookie assignable to that class, or <code>null</code> if this node has no such cookie
0718:             * @see Lookup
0719:             */
0720:            public <T extends Node.Cookie> T getCookie(Class<T> type) {
0721:                Lookup l = internalLookup(true);
0722:
0723:                if (l != null) {
0724:                    Object obj = l.lookup(type);
0725:                    if (Node.Cookie.class.isInstance(obj)) {
0726:                        return type.cast(obj);
0727:                    }
0728:                    CookieSet.enhancedQueryMode(l, type);
0729:                }
0730:
0731:                return null;
0732:            }
0733:
0734:            /** Obtains a Lookup representing additional content of this Node.
0735:             * If the lookup was provided in a constructor, it is returned here,
0736:             * if not, a lookup based on the content of <link>getCookie</link>
0737:             * method is provided.
0738:             *
0739:             * @return lookup for this node
0740:             * @since 3.11
0741:             */
0742:            public final Lookup getLookup() {
0743:                synchronized (listeners) {
0744:                    Lookup l = internalLookup(true);
0745:
0746:                    if (l != null) {
0747:                        return l;
0748:                    }
0749:
0750:                    l = findDelegatingLookup();
0751:
0752:                    if (l != null) {
0753:                        return l;
0754:                    }
0755:
0756:                    // create new lookup and use it
0757:                    NodeLookup nl = new NodeLookup(this );
0758:                    registerDelegatingLookup(nl);
0759:
0760:                    return nl;
0761:                }
0762:            }
0763:
0764:            /** Return a variant of the display name containing HTML markup
0765:             * conforming to the limited subset of font-markup HTML supported by
0766:             * the lightweight HTML renderer <code>org.openide.awt.HtmlRenderer</code>
0767:             * (font color, bold, italic and strike-through supported; font
0768:             * colors can be UIManager color keys if they are prefixed with
0769:             * a ! character, i.e. <samp>&lt;font color='!controlShadow'&gt;</samp>).
0770:             * Enclosing <samp>&lt;html&gt;</samp> tags are not needed. If returning non-null, HTML
0771:             * markup characters that should be literally rendered must be
0772:             * escaped (<samp>&gt;</samp> becomes <samp>&amp;gt;</samp> and so forth).
0773:             * <p><strong>This method should return either an HTML display name
0774:             * or null; it should not return the non-HTML display name.</strong>
0775:             * <p>
0776:             * Note there is no property corresponding to the HTML display name -
0777:             * if it should change, a change in the display name should be fired; this
0778:             * should not be a mechanism for returning anything other than a marked
0779:             * up version of the return value of <code>getDisplayName</code>.
0780:             *
0781:             * @see org.openide.awt.HtmlRenderer
0782:             * @since 4.30
0783:             * @return a String containing conformant HTML markup which
0784:             *  represents the display name, or null.  The default implementation
0785:             *  returns null.  */
0786:            public String getHtmlDisplayName() {
0787:                return null;
0788:            }
0789:
0790:            /** Register delegating lookup so it can always be found.
0791:             */
0792:            final void registerDelegatingLookup(NodeLookup l) {
0793:                // to have just one thread accessing the static lookups variable
0794:                synchronized (lookups) {
0795:                    lookups.put(listeners, new WeakReference<Lookup>(l));
0796:                }
0797:            }
0798:
0799:            /** Finds delegating lookup that was previously registered
0800:             * @return the lookup or null if nothing was registered or the
0801:             *    lookup was GCed.
0802:             */
0803:            final Lookup findDelegatingLookup() {
0804:                Reference<Lookup> ref = lookups.get(listeners);
0805:
0806:                return (ref == null) ? null : ref.get();
0807:            }
0808:
0809:            /** Obtain handle for this node (for serialization).
0810:             * The handle can be serialized and {@link Handle#getNode} used after
0811:             * deserialization to obtain the original node.
0812:             *
0813:             * @return the handle, or <code>null</code> if this node is not persistable
0814:             */
0815:            public abstract Node.Handle getHandle();
0816:
0817:            /** Add a listener to changes in the node's intrinsic properties (name, cookies, etc.).
0818:             * <P>
0819:             * The listener is not notified about changes in subnodes until the
0820:             * method <CODE>getChildren().getNodes()</CODE> is called.
0821:             * @param l the listener to add
0822:             */
0823:            public final void addNodeListener(NodeListener l) {
0824:                listeners.add(NodeListener.class, l);
0825:                listenerAdded();
0826:            }
0827:
0828:            /** A method to notify FilterNode that a listenerAdded has been added */
0829:            void listenerAdded() {
0830:            }
0831:
0832:            /** Remove a node listener.
0833:             * @param l the listener
0834:             */
0835:            public final void removeNodeListener(NodeListener l) {
0836:                listeners.remove(NodeListener.class, l);
0837:            }
0838:
0839:            /** Add a listener to the node's computed Bean properties.
0840:             * @param l the listener
0841:             */
0842:            public final void addPropertyChangeListener(PropertyChangeListener l) {
0843:                int count = -1;
0844:
0845:                if (err.isLoggable(Level.FINE)) {
0846:                    count = getPropertyChangeListenersCount();
0847:                }
0848:
0849:                listeners.add(PropertyChangeListener.class, l);
0850:
0851:                if (err.isLoggable(Level.FINE)) {
0852:                    err.log(Level.FINE, "ADD - " + getName() + " [" + count
0853:                            + "]->[" + getPropertyChangeListenersCount() + "] "
0854:                            + l);
0855:                }
0856:
0857:                notifyPropertyChangeListenerAdded(l);
0858:            }
0859:
0860:            /** Called to notify subclasses (FilterNode) about addition of
0861:             * PropertyChangeListener.
0862:             */
0863:            void notifyPropertyChangeListenerAdded(PropertyChangeListener l) {
0864:            }
0865:
0866:            /** Returns the number of property change listeners attached to this node
0867:             */
0868:            int getPropertyChangeListenersCount() {
0869:                return listeners.getListenerCount(PropertyChangeListener.class);
0870:            }
0871:
0872:            /** Allows to figure out, whether the node has any
0873:             * PropertyChangeListeners attached.
0874:             * @return True if node has one or more PropertyChangeListeners attached.
0875:             * @since 1.36
0876:             */
0877:            protected final boolean hasPropertyChangeListener() {
0878:                return getPropertyChangeListenersCount() > 0;
0879:            }
0880:
0881:            /** Remove a Bean property change listener.
0882:             * @param l the listener
0883:             */
0884:            public final void removePropertyChangeListener(
0885:                    PropertyChangeListener l) {
0886:                int count = -1;
0887:
0888:                if (err.isLoggable(Level.FINE)) {
0889:                    count = getPropertyChangeListenersCount();
0890:                }
0891:
0892:                listeners.remove(PropertyChangeListener.class, l);
0893:
0894:                if (err.isLoggable(Level.FINE)) {
0895:                    err.log(Level.FINE, "RMV - " + getName() + " [" + count
0896:                            + "]->[" + getPropertyChangeListenersCount() + "] "
0897:                            + l);
0898:                }
0899:
0900:                notifyPropertyChangeListenerRemoved(l);
0901:            }
0902:
0903:            /** Called to notify subclasses (FilterNode) about removal of
0904:             * PropertyChangeListener.
0905:             */
0906:            void notifyPropertyChangeListenerRemoved(PropertyChangeListener l) {
0907:            }
0908:
0909:            /** Fire a property change event.
0910:             *
0911:             * @param name name of changed property (from {@link #getPropertySets}); may be null
0912:             * @param o old value; may be null
0913:             * @param n new value; may be null
0914:             * @see PropertyChangeEvent
0915:             */
0916:            protected final void firePropertyChange(String name, Object o,
0917:                    Object n) {
0918:                // First check if this property actually exists - if not warn! See #31413.
0919:                if (err.isLoggable(Level.WARNING) && (name != null)
0920:                        && propertySetsAreKnown()) {
0921:                    Node.PropertySet[] pss = getPropertySets();
0922:                    boolean exists = false;
0923:
0924:                    for (int i = 0; i < pss.length; i++) {
0925:                        Node.Property[] ps = pss[i].getProperties();
0926:
0927:                        for (int j = 0; j < ps.length; j++) {
0928:                            if (ps[j].getName().equals(name)) {
0929:                                exists = true;
0930:
0931:                                break;
0932:                            }
0933:                        }
0934:                    }
0935:
0936:                    if (!exists) {
0937:                        synchronized (warnedBadProperties) {
0938:                            String clazz = getClass().getName();
0939:
0940:                            if (warnedBadProperties.add(clazz + "." + name)) {
0941:                                StringWriter w = new StringWriter();
0942:                                IllegalStateException ise = new IllegalStateException(
0943:                                        "Warning - the node \""
0944:                                                + getDisplayName()
0945:                                                + "\" ["
0946:                                                + clazz
0947:                                                + "] is trying to fire the property "
0948:                                                + name
0949:                                                + " which is not included in its property sets. This is illegal. See IZ #31413 for details."); // NOI18N
0950:                                ise.printStackTrace(new PrintWriter(w));
0951:                                Logger.getLogger(Node.class.getName()).warning(
0952:                                        w.toString());
0953:                            }
0954:                        }
0955:                    }
0956:                }
0957:
0958:                // do not fire if the values are the same
0959:                if ((o != null) && (n != null) && ((o == n) || o.equals(n))) {
0960:                    return;
0961:                }
0962:
0963:                PropertyChangeEvent ev = null;
0964:
0965:                Object[] listeners = this .listeners.getListenerList();
0966:
0967:                // Process the listeners last to first, notifying
0968:                // those that are interested in this event
0969:                for (int i = listeners.length - 2; i >= 0; i -= 2) {
0970:                    if (listeners[i] == PropertyChangeListener.class) {
0971:                        // Lazily create the event:
0972:                        if (ev == null) {
0973:                            ev = new PropertyChangeEvent(this , name, o, n);
0974:                        }
0975:
0976:                        ((PropertyChangeListener) listeners[i + 1])
0977:                                .propertyChange(ev);
0978:                    }
0979:                }
0980:            }
0981:
0982:            /**
0983:             * If true, property sets have definitely been computed, and it is fine
0984:             * to call {@link #getPropertySets} without fear of killing laziness.
0985:             * Used from {@link #firePropertyChange} to only check for bad properties
0986:             * if the set of properties has already been computed. Otherwise, don't
0987:             * bother. Subclasses may override - {@link AbstractNode} does.
0988:             */
0989:            boolean propertySetsAreKnown() {
0990:                return false;
0991:            }
0992:
0993:            /** Allow subclasses that override the getName method to fire
0994:             * the changes of the name by itself. Please notice that default
0995:             * implementation of setName will fire the change by itself.
0996:             */
0997:            protected final void fireNameChange(String o, String n) {
0998:                fireOwnPropertyChange(PROP_NAME, o, n);
0999:            }
1000:
1001:            /** Allow subclasses that override the getDisplayName method to fire
1002:             * the changes of the name by itself. Please notice that default
1003:             * implementation of setDisplayName will fire the change by itself.
1004:             */
1005:            protected final void fireDisplayNameChange(String o, String n) {
1006:                fireOwnPropertyChange(PROP_DISPLAY_NAME, o, n);
1007:            }
1008:
1009:            /** Allow subclasses that override the getShortDescription method to fire
1010:             * the changes of the description by itself. Please notice that default
1011:             * implementation of setShortDescription will fire the change by itself.
1012:             */
1013:            protected final void fireShortDescriptionChange(String o, String n) {
1014:                fireOwnPropertyChange(PROP_SHORT_DESCRIPTION, o, n);
1015:            }
1016:
1017:            /** Fire a change event for {@link #PROP_ICON}.
1018:             */
1019:            protected final void fireIconChange() {
1020:                fireOwnPropertyChange(PROP_ICON, null, null);
1021:            }
1022:
1023:            /** Fire a change event for {@link #PROP_OPENED_ICON}.
1024:             */
1025:            protected final void fireOpenedIconChange() {
1026:                fireOwnPropertyChange(PROP_OPENED_ICON, null, null);
1027:            }
1028:
1029:            /** Fires info about some structural change in children. Providing
1030:             * type of operation and set of children changed generates event describing
1031:             * the change.
1032:             *
1033:             *
1034:             * @param addAction <CODE>true</CODE> if the set of children has been added,
1035:             *   false if it has been removed
1036:             * @param delta the array with changed children
1037:             * @param from the array of nodes to take indices from.
1038:             *   Can be null if one should find indices from current set of nodes
1039:             */
1040:            final void fireSubNodesChange(boolean addAction, Node[] delta,
1041:                    Node[] from) {
1042:                NodeMemberEvent ev = null;
1043:
1044:                Object[] listeners = this .listeners.getListenerList();
1045:
1046:                // Process the listeners last to first, notifying
1047:                // those that are interested in this event
1048:                for (int i = listeners.length - 2; i >= 0; i -= 2) {
1049:                    if (listeners[i] == NodeListener.class) {
1050:                        // Lazily create the event:
1051:                        if (ev == null) {
1052:                            ev = new NodeMemberEvent(this , addAction, delta,
1053:                                    from);
1054:                        }
1055:
1056:                        if (addAction) {
1057:                            ((NodeListener) listeners[i + 1]).childrenAdded(ev);
1058:                        } else {
1059:                            ((NodeListener) listeners[i + 1])
1060:                                    .childrenRemoved(ev);
1061:                        }
1062:                    }
1063:                }
1064:            }
1065:
1066:            /** Fires info about reordering of some children.
1067:             *
1068:             * @param indices array of integers describing the permutation
1069:             */
1070:            final void fireReorderChange(int[] indices) {
1071:                NodeReorderEvent ev = null;
1072:
1073:                Object[] listeners = this .listeners.getListenerList();
1074:
1075:                // Process the listeners last to first, notifying
1076:                // those that are interested in this event
1077:                for (int i = listeners.length - 2; i >= 0; i -= 2) {
1078:                    if (listeners[i] == NodeListener.class) {
1079:                        // Lazily create the event:
1080:                        if (ev == null) {
1081:                            ev = new NodeReorderEvent(this , indices);
1082:                        }
1083:
1084:                        ((NodeListener) listeners[i + 1]).childrenReordered(ev);
1085:                    }
1086:                }
1087:            }
1088:
1089:            /** To all node listeners fire node destroyed notification.
1090:             */
1091:            protected final void fireNodeDestroyed() {
1092:                NodeEvent ev = null;
1093:
1094:                Object[] listeners = this .listeners.getListenerList();
1095:
1096:                // Process the listeners last to first, notifying
1097:                // those that are interested in this event
1098:                for (int i = listeners.length - 2; i >= 0; i -= 2) {
1099:                    if (listeners[i] == NodeListener.class) {
1100:                        // Lazily create the event:
1101:                        if (ev == null) {
1102:                            ev = new NodeEvent(this );
1103:                        }
1104:
1105:                        ((NodeListener) listeners[i + 1]).nodeDestroyed(ev);
1106:                    }
1107:                }
1108:            }
1109:
1110:            /** Fires info about change of parent node.
1111:             * @param o old node
1112:             * @param n new parent
1113:             */
1114:            final void fireParentNodeChange(Node o, Node n) {
1115:                fireOwnPropertyChange(PROP_PARENT_NODE, o, n);
1116:            }
1117:
1118:            /** Fires a (Bean) property change event (for {@link #PROP_PROPERTY_SETS}).
1119:             * @param o the old set
1120:             * @param n the new set
1121:             */
1122:            protected final void firePropertySetsChange(PropertySet[] o,
1123:                    PropertySet[] n) {
1124:                fireOwnPropertyChange(PROP_PROPERTY_SETS, o, n);
1125:            }
1126:
1127:            /** Fires a change event for {@link #PROP_COOKIE}.
1128:             * The old and new values are set to null.
1129:             */
1130:            protected final void fireCookieChange() {
1131:                Lookup l = findDelegatingLookup();
1132:
1133:                if (l instanceof  NodeLookup) {
1134:                    ((NodeLookup) l).updateLookupAsCookiesAreChanged(null);
1135:                }
1136:
1137:                fireOwnPropertyChange(PROP_COOKIE, null, null);
1138:            }
1139:
1140:            /** Fires info about change of own property.
1141:             * @param name name of property
1142:             * @param o old value
1143:             * @param n new value
1144:             */
1145:            final void fireOwnPropertyChange(String name, Object o, Object n) {
1146:                // do not fire if the values are the same
1147:                if ((o != null) && (n != null) && ((o == n) || o.equals(n))) {
1148:                    return;
1149:                }
1150:
1151:                PropertyChangeEvent ev = null;
1152:
1153:                Object[] listeners = this .listeners.getListenerList();
1154:
1155:                // Process the listeners last to first, notifying
1156:                // those that are interested in this event
1157:                for (int i = listeners.length - 2; i >= 0; i -= 2) {
1158:                    if (listeners[i] == NodeListener.class) {
1159:                        // Lazily create the event:
1160:                        if (ev == null) {
1161:                            ev = new PropertyChangeEvent(this , name, o, n);
1162:                        }
1163:
1164:                        ((NodeListener) listeners[i + 1]).propertyChange(ev);
1165:                    }
1166:                }
1167:            }
1168:
1169:            /** Compares for equality. Does special treatment of
1170:             * FilterNodes. If argument is FilterNode then this node can be
1171:             * equal with it if it is its original.
1172:             *
1173:             * @param obj object to compare
1174:             * @return true if the obj is <code>==</code> or is filter node of this node
1175:             */
1176:            public boolean equals(Object obj) {
1177:                if (obj instanceof  FilterNode) {
1178:                    return ((FilterNode) obj).equals(this );
1179:                }
1180:
1181:                return this  == obj;
1182:            }
1183:
1184:            /** Obtains a resource string from bundle.
1185:             * @param resName resource name
1186:             * @return the string
1187:             */
1188:            static String getString(final String resName) {
1189:                return NbBundle.getBundle(Node.class).getString(resName);
1190:            }
1191:
1192:            public String toString() {
1193:                return super .toString() + "[Name=" + getName()
1194:                        + ", displayName=" + getDisplayName() + "]"; // NOI18N
1195:            }
1196:
1197:            /** Marker interface for all cookies.
1198:             * <P>
1199:             * Most examples are present in {@link org.openide.cookies}.
1200:             */
1201:            public static interface Cookie {
1202:            }
1203:
1204:            /** Serializable node reference. The node should not
1205:             * be serialized directly but via this handle. One can obtain a handle
1206:             * by a call to {@link Node#getHandle}.
1207:             * <P>
1208:             * If that methods returns a non-<code>null</code> value, one can serialize it,
1209:             * and after deserialization
1210:             * use {@link #getNode} to obtain the original node.
1211:             */
1212:            public static interface Handle extends java.io.Serializable {
1213:                /** @deprecated Only public by accident. */
1214:                @Deprecated
1215:                /* public static final */long serialVersionUID = -4518262478987434353L;
1216:
1217:                /** Reconstitute the node for this handle.
1218:                 *
1219:                 * @return the node for this handle
1220:                 * @exception IOException if the node cannot be created
1221:                 */
1222:                public Node getNode() throws java.io.IOException;
1223:            }
1224:
1225:            /** Class that represents one set of properties. A usual bean has three
1226:             * sets of properties: normal, expert, and events.
1227:             * <p>You may associate context help with this object, if desired, by setting
1228:             * a {@link FeatureDescriptor#setValue custom property} with the name <code>helpID</code>
1229:             * and value of type <code>String</code> giving a help ID.
1230:             * Normally this is unnecessary as help for the whole {@link Node} will be used by default.
1231:             */
1232:            public static abstract class PropertySet extends FeatureDescriptor {
1233:                /** Default constructor. */
1234:                public PropertySet() {
1235:                }
1236:
1237:                /** Create a property set.
1238:                 * @param name system name of the property set
1239:                 * @param displayName human presentable name
1240:                 * @param shortDescription description for the set
1241:                 */
1242:                public PropertySet(String name, String displayName,
1243:                        String shortDescription) {
1244:                    super .setName(name);
1245:                    super .setDisplayName(displayName);
1246:                    super .setShortDescription(shortDescription);
1247:                }
1248:
1249:                /** Get the list of contained properties.
1250:                 * This list can contain both {@link Node.Property} and {@link Node.IndexedProperty} elements.
1251:                 *
1252:                 * @return the properties
1253:                 */
1254:                public abstract Property<?>[] getProperties();
1255:
1256:                /* Compares just the names.
1257:                 * @param propertySet The object to compare to
1258:                 */
1259:                public boolean equals(Object propertySet) {
1260:                    if (!(propertySet instanceof  PropertySet)) {
1261:                        return false;
1262:                    }
1263:
1264:                    return ((PropertySet) propertySet).getName().equals(
1265:                            getName());
1266:                }
1267:
1268:                /* Returns a hash code value for the object.
1269:                 *
1270:                 * @return int hashcode
1271:                 */
1272:                public int hashCode() {
1273:                    return getName().hashCode();
1274:                }
1275:
1276:                /** Return a variant of the display name containing HTML markup
1277:                 * conforming to the limited subset of font-markup HTML supported by
1278:                 * the lightweight HTML renderer org.openide.awt.HtmlRenderer
1279:                 * (font color, bold, italic and strikethrough supported; font
1280:                 * colors can be UIManager color keys if they are prefixed with
1281:                 * a ! character, i.e. &lt;font color=&amp;'controlShadow'&gt;).
1282:                 * Enclosing HTML tags are not needed.
1283:                 * <p><strong>This method should return either an HTML display name
1284:                 * or null; it should not return the non-HTML display name if no
1285:                 * markup is needed.</strong>
1286:                 *
1287:                 * @see org.openide.awt.HtmlRenderer
1288:                 * @since 4.30
1289:                 * @return a String containing conformant, legal HTML markup which
1290:                 *  represents the display name, or null.  The default implementation
1291:                 *  returns null.  */
1292:                public String getHtmlDisplayName() {
1293:                    return null;
1294:                }
1295:            }
1296:
1297:            /** Description of a Bean property on a node, and operations on it.
1298:             * <p>You may associate context help with this object, if desired, by setting
1299:             * a {@link FeatureDescriptor#setValue custom property} with the name <code>helpID</code>
1300:             * and value of type <code>String</code> giving a help ID.
1301:             * Normally this is unnecessary as help for the whole {@link Node} will be used by default.
1302:             * <p><strong>Important:</strong> the {@link FeatureDescriptor#getName code name} you use for the
1303:             * property is relevant not only for making properties of a node unique, but also for
1304:             * {@link Node#firePropertyChange firing property changes}.
1305:             * @param T the type of bean
1306:             */
1307:            public static abstract class Property<T> extends FeatureDescriptor {
1308:                /**
1309:                 * Contains classNames of incorrectly implemented properties which have
1310:                 * been already logged by an ErrorManager.<br>
1311:                 * For more information see the
1312:                 * <a href="http://openide.netbeans.org/issues/show_bug.cgi?id=51907">
1313:                 * discussion in issuezilla</a>
1314:                 */
1315:                private static final Set<String> warnedNames = new HashSet<String>();
1316:
1317:                /** type that this property works with */
1318:                private Class<T> type;
1319:
1320:                //Soft caching of property editor references to improve JTable
1321:                //property sheet performance
1322:                private Reference<PropertyEditor> edRef = null;
1323:
1324:                /** Constructor.
1325:                 * @param valueType type of the property
1326:                 */
1327:                public Property(Class<T> valueType) {
1328:                    this .type = valueType;
1329:                    super .setName(""); // NOI18N
1330:                }
1331:
1332:                /** Get the value type. This is the representation class of the property.
1333:                 * Remember that e.g. {@link Boolean <code>Boolean.class</code>} means that values are <code>Boolean</code>
1334:                 * objects; to specify the primitive type, use e.g. {@link Boolean#TYPE}.
1335:                 * In the latter case, {@link #getValue} and {@link #setValue} will still operate on the wrapper object.
1336:                 * @return the type
1337:                 */
1338:                public Class<T> getValueType() {
1339:                    return type;
1340:                }
1341:
1342:                /** Test whether the property is readable.
1343:                 * @return <CODE>true</CODE> if it is
1344:                 */
1345:                public abstract boolean canRead();
1346:
1347:                /** Get the value.
1348:                 * @return the value of the property
1349:                 * @exception IllegalAccessException cannot access the called method
1350:                 * @exception InvocationTargetException an exception during invocation
1351:                 */
1352:                public abstract T getValue() throws IllegalAccessException,
1353:                        InvocationTargetException;
1354:
1355:                /** Test whether the property is writable.
1356:                 * @return <CODE>true</CODE> if the read of the value is supported
1357:                 */
1358:                public abstract boolean canWrite();
1359:
1360:                /** Set the value.
1361:                 * @param val the new value of the property
1362:                 * @exception IllegalAccessException cannot access the called method
1363:                 * @exception IllegalArgumentException wrong argument
1364:                 * @exception InvocationTargetException an exception during invocation
1365:                 */
1366:                public abstract void setValue(T val)
1367:                        throws IllegalAccessException,
1368:                        IllegalArgumentException, InvocationTargetException;
1369:
1370:                /** Test whether the property had a default value.
1371:                 * @return <code>true</code> if it does (<code>false</code> by default)
1372:                 */
1373:                public boolean supportsDefaultValue() {
1374:                    return false;
1375:                }
1376:
1377:                /** Restore this property to its default value, if supported.
1378:                 * In the default implementation, does nothing.
1379:                 * Typically you would just call e.g. <code>setValue(default)</code>.
1380:                 * Note that it is not permitted for this call to throw {@link IllegalArgumentException},
1381:                 * though the other two exceptions from {@link #setValue} may be passed through.
1382:                 * @exception IllegalAccessException cannot access the called method
1383:                 * @exception InvocationTargetException an exception during invocation
1384:                 */
1385:                public void restoreDefaultValue()
1386:                        throws IllegalAccessException,
1387:                        InvocationTargetException {
1388:                }
1389:
1390:                /**
1391:                 * This method indicates whether the current value is the same as
1392:                 * the value that would otherwise be restored by calling
1393:                 * <code>restoreDefaultValue()</code> (if <code>supportsDefaultValue()</code>
1394:                 * returns true). The default implementation returns true and
1395:                 * it is recommended to also return true when <code>supportsDefaultValue()</code>
1396:                 * returns false (if we do not support default value any value can
1397:                 * be considered as the default). If <code>supportsDefaultValue()</code>
1398:                 * returns false this method will not be called by the default
1399:                 * implementation of property sheet.
1400:                 * @since 3.19
1401:                 */
1402:                public boolean isDefaultValue() {
1403:                    String name = getClass().getName();
1404:
1405:                    // Issue 51907 backward compatibility
1406:                    if (supportsDefaultValue() && warnedNames.add(name)) {
1407:                        Logger
1408:                                .getLogger(Node.Property.class.getName())
1409:                                .log(
1410:                                        Level.WARNING,
1411:                                        "Class "
1412:                                                + name
1413:                                                + " must override isDefaultValue() since it "
1414:                                                + "overrides supportsDefaultValue() to be true");
1415:                    }
1416:
1417:                    return true;
1418:                }
1419:
1420:                /** Get a property editor for this property.
1421:                 * The default implementation tries to use {@link java.beans.PropertyEditorManager}.
1422:                 * @return the property editor, or <CODE>null</CODE> if there is no editor  */
1423:                public PropertyEditor getPropertyEditor() {
1424:                    if (type == null) {
1425:                        return null;
1426:                    }
1427:
1428:                    PropertyEditor result = null;
1429:
1430:                    if (edRef != null) {
1431:                        result = edRef.get();
1432:                    }
1433:
1434:                    if (result == null) {
1435:                        result = java.beans.PropertyEditorManager
1436:                                .findEditor(type);
1437:                        edRef = new SoftReference<PropertyEditor>(result);
1438:                    }
1439:
1440:                    return result;
1441:                }
1442:
1443:                /* Standard equals implementation for all property
1444:                 * classes.
1445:                 * @param property The object to compare to
1446:                 */
1447:                @Override
1448:                public boolean equals(Object property) {
1449:                    // fix #32845 - check for non-matching types and also for null values
1450:                    // coming in input parameter 'property'
1451:                    if (!(property instanceof  Property)) {
1452:                        return false;
1453:                    }
1454:
1455:                    Class<?> propValueType = ((Property) property)
1456:                            .getValueType();
1457:                    Class<?> valueType = getValueType();
1458:
1459:                    if (((propValueType == null) && (valueType != null))
1460:                            || ((propValueType != null) && (valueType == null))) {
1461:                        return false;
1462:                    }
1463:
1464:                    return ((Property) property).getName().equals(getName())
1465:                            && (((propValueType == null) && (valueType == null)) || propValueType
1466:                                    .equals(valueType));
1467:                }
1468:
1469:                /* Returns a hash code value for the object.
1470:                 *
1471:                 * @return int hashcode
1472:                 */
1473:                @Override
1474:                public int hashCode() {
1475:                    Class<?> valueType = getValueType();
1476:
1477:                    return getName().hashCode()
1478:                            * ((valueType == null) ? 1 : valueType.hashCode());
1479:                }
1480:
1481:                /** Return a variant of the display name containing HTML markup
1482:                 * conforming to the limited subset of font-markup HTML supported by
1483:                 * the lightweight HTML renderer {@link org.openide.awt.HtmlRenderer}
1484:                 * (font color, bold, italic and strike-through supported; font
1485:                 * colors can be UIManager color keys if they are prefixed with
1486:                 * a ! character, i.e. &lt;font color=&amp;'controlShadow'&gt;).
1487:                 * Enclosing HTML tags are not needed.
1488:                 * <p><strong>This method should return either an HTML display name
1489:                 * or null; it should not return the non-HTML display name.
1490:                 *
1491:                 * @see org.openide.awt.HtmlRenderer
1492:                 * @since 4.30
1493:                 * @return a String containing conformant, legal HTML markup which
1494:                 *  represents the display name, or null.  The default implementation
1495:                 *  returns null.  */
1496:                public String getHtmlDisplayName() {
1497:                    return null;
1498:                }
1499:            }
1500:
1501:            /** Description of an indexed property and operations on it.
1502:             * @param T type of the whole property
1503:             * @param E type of one element
1504:             */
1505:            public static abstract class IndexedProperty<T, E> extends
1506:                    Node.Property<T> {
1507:                /** type of element that this property works with */
1508:                private Class<E> elementType;
1509:
1510:                /** Constructor.
1511:                 * @param valueType type of the property
1512:                 */
1513:                public IndexedProperty(Class<T> valueType, Class<E> elementType) {
1514:                    super (valueType);
1515:                    this .elementType = elementType;
1516:                }
1517:
1518:                /** Test whether the property is readable by index.
1519:                 * @return <CODE>true</CODE> if so
1520:                 */
1521:                public abstract boolean canIndexedRead();
1522:
1523:                /** Get the element type of the property (not the type of the whole property).
1524:                 * @return the type
1525:                 */
1526:                public Class<E> getElementType() {
1527:                    return elementType;
1528:                }
1529:
1530:                /** Get the value of the property at an index.
1531:                 *
1532:                 * @param index the index
1533:                 * @return the value at that index
1534:                 * @exception IllegalAccessException cannot access the called method
1535:                 * @exception IllegalArgumentException wrong argument
1536:                 * @exception InvocationTargetException an exception during invocation
1537:                 */
1538:                public abstract E getIndexedValue(int index)
1539:                        throws IllegalAccessException,
1540:                        IllegalArgumentException, InvocationTargetException;
1541:
1542:                /** Test whether the property is writable by index.
1543:                 * @return <CODE>true</CODE> if so
1544:                 */
1545:                public abstract boolean canIndexedWrite();
1546:
1547:                /** Set the value of the property at an index.
1548:                 *
1549:                 * @param indx the index
1550:                 * @param val the value to set
1551:                 * @exception IllegalAccessException cannot access the called method
1552:                 * @exception IllegalArgumentException wrong argument
1553:                 * @exception InvocationTargetException an exception during invocation
1554:                 */
1555:                public abstract void setIndexedValue(int indx, E val)
1556:                        throws IllegalAccessException,
1557:                        IllegalArgumentException, InvocationTargetException;
1558:
1559:                /** Get a property editor for individual elements in this property.
1560:                 * @return the property editor for elements
1561:                 */
1562:                public PropertyEditor getIndexedPropertyEditor() {
1563:                    return java.beans.PropertyEditorManager
1564:                            .findEditor(elementType);
1565:                }
1566:
1567:                /* Standard equals implementation for all property
1568:                 * classes.
1569:                 * @param property The object to compare to
1570:                 */
1571:                @Override
1572:                public boolean equals(Object property) {
1573:                    try {
1574:                        if (!super .equals(property)) {
1575:                            return false;
1576:                        }
1577:
1578:                        Class<?> propElementType = ((IndexedProperty) property)
1579:                                .getElementType();
1580:                        Class<?> elementType = getElementType();
1581:
1582:                        if (((propElementType == null) && (elementType != null))
1583:                                || ((propElementType != null) && (elementType == null))) {
1584:                            return false;
1585:                        }
1586:
1587:                        return (((propElementType == null) && (elementType == null)) || propElementType
1588:                                .equals(elementType));
1589:                    } catch (ClassCastException e) {
1590:                        return false;
1591:                    }
1592:                }
1593:
1594:                /* Returns a hash code value for the object.
1595:                 *
1596:                 * @return int hashcode
1597:                 */
1598:                @Override
1599:                public int hashCode() {
1600:                    Class<?> ementType = getElementType();
1601:
1602:                    return super .hashCode()
1603:                            * ((elementType == null) ? 1 : elementType
1604:                                    .hashCode());
1605:                }
1606:            }
1607:
1608:            /** Special subclass of EventListenerList that can also listen on changes in
1609:             * a lookup.
1610:             */
1611:            private final class LookupEventList extends EventListenerList
1612:                    implements  LookupListener {
1613:                public final Lookup lookup;
1614:                private Lookup.Result<Node.Cookie> result;
1615:
1616:                public LookupEventList(Lookup l) {
1617:                    this .lookup = l;
1618:                }
1619:
1620:                public Lookup init(boolean init) {
1621:                    boolean doInit = false;
1622:
1623:                    synchronized (INIT_LOCK) {
1624:                        if (init && (result == null)) {
1625:                            result = lookup.lookup(TEMPL_COOKIE);
1626:                            assert result != null : "Null lookup result from "
1627:                                    + lookup + " in " + Node.this ;
1628:                            result.addLookupListener(this );
1629:                            doInit = true;
1630:                        }
1631:                    }
1632:
1633:                    if (doInit) {
1634:                        result.allItems();
1635:                    }
1636:
1637:                    return lookup;
1638:                }
1639:
1640:                public void resultChanged(LookupEvent ev) {
1641:                    if (Node.this  instanceof  FilterNode) {
1642:                        FilterNode f = (FilterNode) Node.this ;
1643:
1644:                        // See #40734 and NodeLookupTest and CookieActionIsTooSlowTest. 
1645:                        if (f.getOriginal() == NodeLookup.NO_COOKIE_CHANGE
1646:                                .get()) {
1647:                            // this is not real cookie change, do not fire it
1648:                            // issue 40734
1649:                            return;
1650:                        }
1651:                    }
1652:
1653:                    fireCookieChange();
1654:                }
1655:            }
1656:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.