Source Code Cross Referenced for FilterNode.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:        package org.openide.nodes;
0042:
0043:        import java.lang.ref.Reference;
0044:        import java.lang.reflect.Method;
0045:        import org.openide.util.HelpCtx;
0046:        import org.openide.util.Lookup;
0047:        import org.openide.util.LookupEvent;
0048:        import org.openide.util.LookupListener;
0049:        import org.openide.util.WeakSet;
0050:        import org.openide.util.actions.SystemAction;
0051:        import org.openide.util.datatransfer.NewType;
0052:        import org.openide.util.datatransfer.PasteType;
0053:
0054:        import java.awt.Image;
0055:        import java.awt.datatransfer.Transferable;
0056:
0057:        import java.beans.PropertyChangeEvent;
0058:        import java.beans.PropertyChangeListener;
0059:
0060:        import java.io.IOException;
0061:
0062:        import java.lang.ref.WeakReference;
0063:
0064:        import java.util.*;
0065:        import java.util.logging.Level;
0066:        import java.util.logging.Logger;
0067:        import org.openide.nodes.Node.PropertySet;
0068:        import org.openide.util.Exceptions;
0069:        import org.openide.util.Lookup.Item;
0070:
0071:        /** A proxy for another node.
0072:         * Unless otherwise mentioned, all methods of the original node are delegated to.
0073:         * If desired, you can disable delegation of certain methods which are concrete in <code>Node</code>
0074:         * by calling {@link #disableDelegation}.
0075:         *
0076:         * <p><strong>Note:</strong> it is fine to subclass this class and use
0077:         * it to filter things. But please do not ever try to cast a node to
0078:         * <code>FilterNode</code>: it probably means you are doing something
0079:         * wrong. Instead, ask whatever <code>Node</code> you have for a proper
0080:         * kind of cookie (e.g. <code>DataObject</code>).
0081:         *
0082:         * @author Jaroslav Tulach
0083:         */
0084:        public class FilterNode extends Node {
0085:            /** Whether to delegate <code>setName</code>. */
0086:            protected static final int DELEGATE_SET_NAME = 1 << 0;
0087:
0088:            /** Whether to delegate <code>getName</code>. */
0089:            protected static final int DELEGATE_GET_NAME = 1 << 1;
0090:
0091:            /** Whether to delegate <code>setDisplayName</code>. */
0092:            protected static final int DELEGATE_SET_DISPLAY_NAME = 1 << 2;
0093:
0094:            /** Whether to delegate <code>getDisplayName</code>. */
0095:            protected static final int DELEGATE_GET_DISPLAY_NAME = 1 << 3;
0096:
0097:            /** Whether to delegate <code>setShortDescription</code>. */
0098:            protected static final int DELEGATE_SET_SHORT_DESCRIPTION = 1 << 4;
0099:
0100:            /** Whether to delegate <code>getShortDescription</code>. */
0101:            protected static final int DELEGATE_GET_SHORT_DESCRIPTION = 1 << 5;
0102:
0103:            /** Whether to delegate <code>destroy</code>. */
0104:            protected static final int DELEGATE_DESTROY = 1 << 6;
0105:
0106:            /** Whether to delegate <code>getActions</code>. */
0107:            protected static final int DELEGATE_GET_ACTIONS = 1 << 7;
0108:
0109:            /** Whether to delegate <code>getContextActions</code>. */
0110:            protected static final int DELEGATE_GET_CONTEXT_ACTIONS = 1 << 8;
0111:
0112:            /** Whether to delegate <code>setValue</code>.
0113:             * @since 4.25
0114:             */
0115:            protected static final int DELEGATE_SET_VALUE = 1 << 9;
0116:
0117:            /** Whether to delegate <code>getValue</code>.
0118:             * @since 4.25
0119:             */
0120:            protected static final int DELEGATE_GET_VALUE = 1 << 10;
0121:
0122:            /** Mask indicating delegation of all possible methods. */
0123:            private static final int DELEGATE_ALL = DELEGATE_SET_NAME
0124:                    | DELEGATE_GET_NAME | DELEGATE_SET_DISPLAY_NAME
0125:                    | DELEGATE_GET_DISPLAY_NAME
0126:                    | DELEGATE_SET_SHORT_DESCRIPTION
0127:                    | DELEGATE_GET_SHORT_DESCRIPTION | DELEGATE_DESTROY
0128:                    | DELEGATE_GET_ACTIONS | DELEGATE_GET_CONTEXT_ACTIONS
0129:                    | DELEGATE_SET_VALUE | DELEGATE_GET_VALUE;
0130:            private static final Map<Class<?>, Boolean> overridesGetDisplayNameCache = new WeakHashMap<Class<?>, Boolean>(
0131:                    27);
0132:            private static final Map<Class<?>, Boolean> replaceProvidedLookupCache = new WeakHashMap<Class<?>, Boolean>(
0133:                    27);
0134:
0135:            /** Depth of stack trace.
0136:             */
0137:            private static volatile int hashCodeDepth;
0138:
0139:            /** node to delegate to */
0140:            private Node original;
0141:
0142:            /** listener to property changes,
0143:             * accessible thru getPropertyChangeListener
0144:             */
0145:            private PropertyChangeListener propL;
0146:
0147:            /** listener to node changes
0148:             * Accessible thru get node listener
0149:             */
0150:            private NodeListener nodeL;
0151:
0152:            // Note: int (not long) to avoid need to ever synchronize when accessing it
0153:            // (Java VM spec does not guarantee that long's will be stored atomically)
0154:
0155:            /** @see #delegating */
0156:            private int delegateMask;
0157:
0158:            /** Is PropertyChangeListener attached to original node */
0159:            private boolean pchlAttached = false;
0160:
0161:            /** children provided or created the default ones? */
0162:            private boolean childrenProvided;
0163:
0164:            /** Create proxy.
0165:             * @param original the node to delegate to
0166:             */
0167:            public FilterNode(Node original) {
0168:                this (original, null);
0169:            }
0170:
0171:            /** Create proxy with a different set of children.
0172:             *
0173:             * @param original the node to delegate to
0174:             * @param children a set of children for this node
0175:             */
0176:            public FilterNode(Node original, org.openide.nodes.Children children) {
0177:                this (original, children, new FilterLookup());
0178:            }
0179:
0180:            /** Constructs new filter node with a provided children and lookup.
0181:             * The lookup is used to implement {@link FilterNode#getCookie} calls that just call
0182:             * <code>lookup.lookup(clazz)</code>. If this constructor is used,
0183:             * the code shall not override {@link FilterNode#getCookie} method, but do all
0184:             * its state manipulation in the lookup. Look at {@link Node#Node}
0185:             * constructor for best practices usage of this constructor.
0186:             *
0187:             * @param original the node we delegate to
0188:             * @param children the children to use for the filter node or <code>null</code> if
0189:             *    default children should be provided
0190:             * @param lookup lookup to use. Do not pass <CODE>orginal.getLookup()</CODE> into this parameter.
0191:             *        In such case use the {@link #FilterNode(Node, Children)} constructor.
0192:             *
0193:             * @since 4.4
0194:             */
0195:            public FilterNode(Node original,
0196:                    org.openide.nodes.Children children, Lookup lookup) {
0197:                super (
0198:                        (children == null) ? (original.isLeaf() ? org.openide.nodes.Children.LEAF
0199:                                : new Children(original))
0200:                                : children, lookup);
0201:
0202:                this .childrenProvided = children != null;
0203:                this .original = original;
0204:                init();
0205:
0206:                Lookup lkp = internalLookup(false);
0207:
0208:                if (lkp instanceof  FilterLookup) {
0209:                    ((FilterLookup) lkp).ownNode(this );
0210:                } else {
0211:                    if (lkp == null) {
0212:                        // rely on default NodeLookup around getCookie. 
0213:                        getNodeListener();
0214:                    }
0215:                }
0216:            }
0217:
0218:            /** Overrides package private method of a node that allows us to say
0219:             * that the lookup provided in the constructor should be replaced by
0220:             * something else
0221:             *
0222:             * @param lookup
0223:             * @return lookup or null
0224:             */
0225:            final Lookup replaceProvidedLookup(Lookup lookup) {
0226:                synchronized (replaceProvidedLookupCache) {
0227:                    Boolean b = replaceProvidedLookupCache.get(getClass());
0228:
0229:                    if (b == null) {
0230:                        b = !overridesAMethod("getCookie", Class.class); // NOI18N
0231:                        replaceProvidedLookupCache.put(getClass(), b);
0232:                    }
0233:
0234:                    return b ? lookup : null;
0235:                }
0236:            }
0237:
0238:            /** Checks whether subclass overrides a method
0239:             */
0240:            private boolean overridesAMethod(String name, Class... arguments) {
0241:                if (getClass() == FilterNode.class) {
0242:                    return false;
0243:                }
0244:
0245:                // we are subclass of FilterNode
0246:                try {
0247:                    Method m = getClass().getMethod(name, arguments);
0248:
0249:                    if (m.getDeclaringClass() != FilterNode.class) {
0250:                        // ok somebody overriden getCookie method
0251:                        return true;
0252:                    }
0253:                } catch (NoSuchMethodException ex) {
0254:                    Exceptions.printStackTrace(ex);
0255:                }
0256:
0257:                return false;
0258:            }
0259:
0260:            /** Initializes the node.
0261:             */
0262:            private void init() {
0263:                delegateMask = DELEGATE_ALL;
0264:            }
0265:
0266:            void notifyPropertyChangeListenerAdded(PropertyChangeListener l) {
0267:                if (!pchlAttached) {
0268:                    original
0269:                            .addPropertyChangeListener(getPropertyChangeListener());
0270:                    pchlAttached = true;
0271:                }
0272:            }
0273:
0274:            void notifyPropertyChangeListenerRemoved(PropertyChangeListener l) {
0275:                if (getPropertyChangeListenersCount() == 0) {
0276:                    original
0277:                            .removePropertyChangeListener(getPropertyChangeListener());
0278:                    pchlAttached = false;
0279:                }
0280:            }
0281:
0282:            /** Removes all listeners (property and node) on
0283:             * the original node. Called from {@link NodeListener#nodeDestroyed},
0284:             * but can be called by any subclass to stop reflecting changes
0285:             * in the original node.
0286:             */
0287:            @Override
0288:            protected void finalize() {
0289:                original
0290:                        .removePropertyChangeListener(getPropertyChangeListener());
0291:                original.removeNodeListener(getNodeListener());
0292:            }
0293:
0294:            /** Enable delegation of a set of methods.
0295:             * These will be delegated to the original node.
0296:             * Since all available methods are delegated by default, normally you will not need to call this.
0297:             * @param mask bitwise disjunction of <code>DELEGATE_XXX</code> constants
0298:             * @throws IllegalArgumentException if the mask is invalid
0299:             */
0300:            protected final void enableDelegation(int mask) {
0301:                if ((mask & ~DELEGATE_ALL) != 0) {
0302:                    throw new IllegalArgumentException("Bad delegation mask: "
0303:                            + mask); // NOI18N
0304:                }
0305:
0306:                delegateMask |= mask;
0307:            }
0308:
0309:            /** Disable delegation of a set of methods.
0310:             * The methods will retain their behavior from {@link Node}.
0311:             * <p>For example, if you wish to subclass <code>FilterNode</code>, giving your
0312:             * node a distinctive display name and tooltip, and performing some special
0313:             * action upon deletion, you may do so without risk of affecting the original
0314:             * node as follows:
0315:             * <br><code><pre>
0316:             * public MyNode extends FilterNode {
0317:             *   public MyNode (Node orig) {
0318:             *     super (orig, new MyChildren (orig));
0319:             *     disableDelegation (DELEGATE_GET_DISPLAY_NAME | DELEGATE_SET_DISPLAY_NAME |
0320:             *                        DELEGATE_GET_SHORT_DESCRIPTION | DELEGATE_SET_SHORT_DESCRIPTION |
0321:             *                        DELEGATE_DESTROY);
0322:             *     // these will affect only the filter node:
0323:             *     setDisplayName ("Linking -> " + orig.getDisplayName ());
0324:             *     setShortDescription ("Something different.");
0325:             *   }
0326:             *   public boolean canRename () { return false; }
0327:             *   public void destroy () throws IOException {
0328:             *     doMyCleanup ();
0329:             *     super.destroy (); // calls Node.destroy(), not orig.destroy()
0330:             *   }
0331:             * }
0332:             * </pre></code>
0333:             * <br>You may still manually delegate where desired using {@link #getOriginal}.
0334:             * Other methods abstract in <code>Node</code> may simply be overridden without
0335:             * any special handling.
0336:             * @param mask bitwise disjunction of <code>DELEGATE_XXX</code> constants
0337:             * @throws IllegalArgumentException if the mask is invalid
0338:             */
0339:            protected final void disableDelegation(int mask) {
0340:                if ((mask & ~DELEGATE_ALL) != 0) {
0341:                    throw new IllegalArgumentException("Bad delegation mask: "
0342:                            + mask); // NOI18N
0343:                }
0344:
0345:                delegateMask &= ~mask;
0346:            }
0347:
0348:            /** Test whether we are currently delegating to some method. */
0349:            private final boolean delegating(int what) {
0350:                return (delegateMask & what) != 0;
0351:            }
0352:
0353:            /** Create new filter node for the original.
0354:             * Subclasses do not have to override this, but if they do not,
0355:             * the default implementation will filter the subclass filter, which is not
0356:             * very efficient.
0357:             * @return copy of this node
0358:             */
0359:            public Node cloneNode() {
0360:                if (isDefault()) {
0361:                    // this is realy filter node without changed behaviour
0362:                    // with the normal children => use normal constructor for the
0363:                    // original node
0364:                    return new FilterNode(original);
0365:                } else {
0366:                    // create filter node for this node to reflect changed
0367:                    // behaviour
0368:                    return new FilterNode(this );
0369:                }
0370:            }
0371:
0372:            /** Tries to prevent issue 46993 by checking whether a node
0373:             * to be set as original is actually pointing to this node.
0374:             * @exception IllegalArgumentException if the check fails
0375:             * @return always true
0376:             */
0377:            private boolean checkIfIamAccessibleFromOriginal(Node original) {
0378:                if (this  == original) {
0379:                    throw new IllegalArgumentException(
0380:                            "Node cannot be its own original (even thru indirect chain)"); // NOI18N
0381:                }
0382:
0383:                if (original instanceof  FilterNode) {
0384:                    FilterNode f = (FilterNode) original;
0385:                    checkIfIamAccessibleFromOriginal(f.original);
0386:                }
0387:
0388:                return true;
0389:            }
0390:
0391:            /** Changes the original node for this node.
0392:             *@param original The new original node.
0393:             *@param changeChildren If set to <CODE>true</CODE> changes children
0394:             * of this node according to the new original node. If you pass
0395:             * children which are not instance of class
0396:             * {@link FilterNode.Children} into the constructor set this
0397:             * parameter to <CODE>false</CODE>. Be aware
0398:             * that this method aquires
0399:             * write lock on the nodes hierarchy ({@link Children#MUTEX}). Take care not to call this method
0400:             * under read lock.
0401:             *
0402:             *@throws java.lang.IllegalStateException if children which are not
0403:             * instance of <CODE>FilterNode.Children</CODE> were passed
0404:             * into the constructor and the method was called with the parameter
0405:             * <CODE>changeChildren</CODE> set to <CODE>true</CODE>.
0406:             *@since 1.39
0407:             */
0408:            protected final void changeOriginal(Node original,
0409:                    boolean changeChildren) {
0410:                if (changeChildren
0411:                        && !(getChildren() instanceof  FilterNode.Children)
0412:                        && !(getChildren() == Children.LEAF /* && original.isLeaf () */)) {
0413:                    throw new IllegalStateException(
0414:                            "Can't change implicitly defined Children on FilterNode"); // NOI18N
0415:                }
0416:
0417:                assert checkIfIamAccessibleFromOriginal(original) : ""; // NOI18N
0418:
0419:                try {
0420:                    Children.PR.enterWriteAccess();
0421:
0422:                    // First remove the listeners from current original node
0423:                    this .original.removeNodeListener(getNodeListener());
0424:
0425:                    if (pchlAttached) {
0426:                        this .original
0427:                                .removePropertyChangeListener(getPropertyChangeListener());
0428:                    }
0429:
0430:                    // Set the new original node
0431:                    this .original = original;
0432:
0433:                    // attach listeners to new original node
0434:                    this .original.addNodeListener(getNodeListener());
0435:
0436:                    if (pchlAttached) {
0437:                        this .original
0438:                                .addPropertyChangeListener(getPropertyChangeListener());
0439:                    }
0440:
0441:                    // Reset children's original node.
0442:                    if (changeChildren /* && !original.isLeaf () */) {
0443:                        if (original.isLeaf()
0444:                                && (getChildren() != Children.LEAF)) {
0445:                            setChildren(Children.LEAF);
0446:                        } else if (!original.isLeaf()
0447:                                && (getChildren() == Children.LEAF)) {
0448:                            setChildren(new Children(original));
0449:                        } else if (!original.isLeaf()
0450:                                && (getChildren() != Children.LEAF)) {
0451:                            ((FilterNode.Children) getChildren())
0452:                                    .changeOriginal(original);
0453:                        }
0454:                    }
0455:                } finally {
0456:                    Children.PR.exitWriteAccess();
0457:                }
0458:
0459:                // Fire all sorts of events (everything gets changed after we
0460:                // reset the original node.)
0461:                Lookup lkp = internalLookup(false);
0462:
0463:                if (lkp instanceof  FilterLookup) {
0464:                    ((FilterLookup) lkp).checkNode();
0465:                }
0466:
0467:                fireCookieChange();
0468:                fireNameChange(null, null);
0469:                fireDisplayNameChange(null, null);
0470:                fireShortDescriptionChange(null, null);
0471:                fireIconChange();
0472:                fireOpenedIconChange();
0473:                firePropertySetsChange(null, null);
0474:            }
0475:
0476:            // ------------- START OF DELEGATED METHODS ------------
0477:            @Override
0478:            public void setValue(String attributeName, Object value) {
0479:                if (delegating(DELEGATE_SET_VALUE)) {
0480:                    original.setValue(attributeName, value);
0481:                } else {
0482:                    super .setValue(attributeName, value);
0483:                }
0484:            }
0485:
0486:            @Override
0487:            public Object getValue(String attributeName) {
0488:                if (delegating(DELEGATE_GET_VALUE)) {
0489:                    return original.getValue(attributeName);
0490:                } else {
0491:                    return super .getValue(attributeName);
0492:                }
0493:            }
0494:
0495:            /* Setter for system name. Fires info about property change.
0496:             * @param s the string
0497:             */
0498:            @Override
0499:            public void setName(String s) {
0500:                if (delegating(DELEGATE_SET_NAME)) {
0501:                    original.setName(s);
0502:                } else {
0503:                    super .setName(s);
0504:                }
0505:            }
0506:
0507:            /* @return the name of the original node
0508:             */
0509:            @Override
0510:            public String getName() {
0511:                if (delegating(DELEGATE_GET_NAME)) {
0512:                    return original.getName();
0513:                } else {
0514:                    return super .getName();
0515:                }
0516:            }
0517:
0518:            /* Setter for display name. Fires info about property change.
0519:             * @param s the string
0520:             */
0521:            @Override
0522:            public void setDisplayName(String s) {
0523:                if (delegating(DELEGATE_SET_DISPLAY_NAME)) {
0524:                    original.setDisplayName(s);
0525:                } else {
0526:                    super .setDisplayName(s);
0527:                }
0528:            }
0529:
0530:            /* @return the display name of the original node
0531:             */
0532:            @Override
0533:            public String getDisplayName() {
0534:                if (delegating(DELEGATE_GET_DISPLAY_NAME)) {
0535:                    return original.getDisplayName();
0536:                } else {
0537:                    return super .getDisplayName();
0538:                }
0539:            }
0540:
0541:            /* Setter for short description. Fires info about property change.
0542:             * @param s the string
0543:             */
0544:            @Override
0545:            public void setShortDescription(String s) {
0546:                if (delegating(DELEGATE_SET_SHORT_DESCRIPTION)) {
0547:                    original.setShortDescription(s);
0548:                } else {
0549:                    super .setShortDescription(s);
0550:                }
0551:            }
0552:
0553:            /* @return the description of the original node
0554:             */
0555:            @Override
0556:            public String getShortDescription() {
0557:                if (delegating(DELEGATE_GET_SHORT_DESCRIPTION)) {
0558:                    return original.getShortDescription();
0559:                } else {
0560:                    return super .getShortDescription();
0561:                }
0562:            }
0563:
0564:            /* Finds an icon for this node. Delegates to the original.
0565:             *
0566:             * @see java.bean.BeanInfo
0567:             * @param type constants from <CODE>java.bean.BeanInfo</CODE>
0568:             * @return icon to use to represent the bean
0569:             */
0570:            public Image getIcon(int type) {
0571:                return original.getIcon(type);
0572:            }
0573:
0574:            /* Finds an icon for this node. This icon should represent the node
0575:             * when it is opened (if it can have children). Delegates to original.
0576:             *
0577:             * @see java.bean.BeanInfo
0578:             * @param type constants from <CODE>java.bean.BeanInfo</CODE>
0579:             * @return icon to use to represent the bean when opened
0580:             */
0581:            public Image getOpenedIcon(int type) {
0582:                return original.getOpenedIcon(type);
0583:            }
0584:
0585:            public HelpCtx getHelpCtx() {
0586:                return original.getHelpCtx();
0587:            }
0588:
0589:            /* Can the original node be renamed?
0590:             *
0591:             * @return true if the node can be renamed
0592:             */
0593:            public boolean canRename() {
0594:                return original.canRename();
0595:            }
0596:
0597:            /* Can the original node be deleted?
0598:             * @return <CODE>true</CODE> if can, <CODE>false</CODE> otherwise
0599:             */
0600:            public boolean canDestroy() {
0601:                return original.canDestroy();
0602:            }
0603:
0604:            /* Degelates the delete operation to original.
0605:             */
0606:            @Override
0607:            public void destroy() throws java.io.IOException {
0608:                if (delegating(DELEGATE_DESTROY)) {
0609:                    original.destroy();
0610:                } else {
0611:                    super .destroy();
0612:                }
0613:            }
0614:
0615:            /** Used to access the destroy method when original nodes
0616:             * has been deleted
0617:             */
0618:            private final void originalDestroyed() {
0619:                try {
0620:                    super .destroy();
0621:                } catch (IOException ex) {
0622:                    Logger.getLogger(FilterNode.class.getName()).log(
0623:                            Level.WARNING, null, ex);
0624:                }
0625:            }
0626:
0627:            /* Getter for the list of property sets. Delegates to original.
0628:             *
0629:             * @return the array of property sets.
0630:             */
0631:            public PropertySet[] getPropertySets() {
0632:                return original.getPropertySets();
0633:            }
0634:
0635:            /* Called when an object is to be copied to clipboard.
0636:             * @return the transferable object dedicated to represent the
0637:             *    content of clipboard
0638:             * @exception IOException is thrown when the
0639:             *    operation cannot be performed
0640:             */
0641:            public Transferable clipboardCopy() throws IOException {
0642:                return original.clipboardCopy();
0643:            }
0644:
0645:            /* Called when an object is to be cut to clipboard.
0646:             * @return the transferable object dedicated to represent the
0647:             *    content of clipboard
0648:             * @exception IOException is thrown when the
0649:             *    operation cannot be performed
0650:             */
0651:            public Transferable clipboardCut() throws IOException {
0652:                return original.clipboardCut();
0653:            }
0654:
0655:            /* Returns true if this object allows copying.
0656:             * @returns true if this object allows copying.
0657:             */
0658:            public boolean canCopy() {
0659:                return original.canCopy();
0660:            }
0661:
0662:            /* Returns true if this object allows cutting.
0663:             * @returns true if this object allows cutting.
0664:             */
0665:            public boolean canCut() {
0666:                return original.canCut();
0667:            }
0668:
0669:            public Transferable drag() throws IOException {
0670:                return original.drag();
0671:            }
0672:
0673:            /* Default implementation that tries to delegate the implementation
0674:             * to the createPasteTypes method. Simply calls the method and
0675:             * tries to take the first provided argument. Ignores the action
0676:             * argument and index.
0677:             *
0678:             * @param t the transferable
0679:             * @param action the drag'n'drop action to do DnDConstants.ACTION_MOVE, ACTION_COPY, ACTION_LINK
0680:             * @param index index between children the drop occured at or -1 if not specified
0681:             * @return null if the transferable cannot be accepted or the paste type
0682:             *    to execute when the drop occures
0683:             */
0684:            public PasteType getDropType(Transferable t, int action, int index) {
0685:                return original.getDropType(t, action, index);
0686:            }
0687:
0688:            /* Which paste operations are allowed when transferable t is in clipboard?
0689:             * @param t the transferable in clipboard
0690:             * @return array of operations that are allowed
0691:             */
0692:            public PasteType[] getPasteTypes(Transferable t) {
0693:                return original.getPasteTypes(t);
0694:            }
0695:
0696:            /* Support for new types that can be created in this node.
0697:             * @return array of new type operations that are allowed
0698:             */
0699:            public NewType[] getNewTypes() {
0700:                return original.getNewTypes();
0701:            }
0702:
0703:            /* Delegates to original.
0704:             *
0705:             * @return array of system actions that should be in popup menu
0706:             */
0707:            @Override
0708:            @Deprecated
0709:            public SystemAction[] getActions() {
0710:                if (delegating(DELEGATE_GET_ACTIONS)) {
0711:                    return original.getActions();
0712:                } else {
0713:                    return super .getActions();
0714:                }
0715:            }
0716:
0717:            /* Delegates to original
0718:             */
0719:            @Override
0720:            @Deprecated
0721:            public SystemAction[] getContextActions() {
0722:                if (delegating(DELEGATE_GET_CONTEXT_ACTIONS)) {
0723:                    return original.getContextActions();
0724:                } else {
0725:                    return super .getContextActions();
0726:                }
0727:            }
0728:
0729:            /*
0730:             * @return default action of the original node or null
0731:             */
0732:            @Override
0733:            @Deprecated
0734:            public SystemAction getDefaultAction() {
0735:                return original.getDefaultAction();
0736:            }
0737:
0738:            @Override
0739:            public javax.swing.Action[] getActions(boolean context) {
0740:                if (context) {
0741:                    if (!delegating(DELEGATE_GET_ACTIONS)
0742:                            || overridesAMethod("getContextActions")) { // NOI18N
0743:
0744:                        return super .getActions(context);
0745:                    }
0746:                } else {
0747:                    if (!delegating(DELEGATE_GET_CONTEXT_ACTIONS)
0748:                            || overridesAMethod("getActions")) { // NOI18N
0749:
0750:                        return super .getActions(context);
0751:                    }
0752:                }
0753:
0754:                javax.swing.Action[] retValue;
0755:                retValue = original.getActions(context);
0756:
0757:                return retValue;
0758:            }
0759:
0760:            @Override
0761:            public javax.swing.Action getPreferredAction() {
0762:                javax.swing.Action retValue;
0763:
0764:                if (overridesAMethod("getDefaultAction")) { // NOI18N
0765:                    retValue = super .getPreferredAction();
0766:                } else {
0767:                    retValue = original.getPreferredAction();
0768:                }
0769:
0770:                return retValue;
0771:            }
0772:
0773:            /** Get a display name containing HTML markup.  <strong><b>Note:</b> If you subclass
0774:             * FilterNode and override <code>getDisplayName()</code>, this method will
0775:             * always return null unless you override it as well (assuming that if you're
0776:             * changing the display name, you don't want an HTML display name constructed
0777:             * from the original node's display name to be what shows up in views of
0778:             * this node).</strong>  If <code>getDisplayName()</code> is not overridden,
0779:             * this method will return whatever the original node returns from this
0780:             * method.
0781:             * <p>
0782:             * Note that if you do override <code>getDisplayName</code>, you should also override
0783:             * this method to return null.
0784:             *
0785:             *
0786:             *
0787:             * @see org.openide.nodes.Node#getHtmlDisplayName
0788:             * @return An HTML display name, if available, or null if no display name
0789:             * is available   */
0790:            @Override
0791:            public String getHtmlDisplayName() {
0792:                if (overridesGetDisplayName()) {
0793:                    return null;
0794:                } else {
0795:                    return delegating(DELEGATE_GET_DISPLAY_NAME) ? original
0796:                            .getHtmlDisplayName() : super .getHtmlDisplayName();
0797:                }
0798:            }
0799:
0800:            private boolean overridesGetDisplayName() {
0801:                synchronized (overridesGetDisplayNameCache) {
0802:                    Boolean b = overridesGetDisplayNameCache.get(getClass());
0803:
0804:                    if (b == null) {
0805:                        b = overridesAMethod("getDisplayName"); // NOI18N
0806:                        overridesGetDisplayNameCache.put(getClass(), b);
0807:                    }
0808:
0809:                    return b;
0810:                }
0811:            }
0812:
0813:            /*
0814:             * @return <CODE>true</CODE> if the original has a customizer.
0815:             */
0816:            public boolean hasCustomizer() {
0817:                return original.hasCustomizer();
0818:            }
0819:
0820:            /* Returns the customizer component.
0821:             * @return the component or <CODE>null</CODE> if there is no customizer
0822:             */
0823:            public java.awt.Component getCustomizer() {
0824:                return original.getCustomizer();
0825:            }
0826:
0827:            /** Delegates to original, if no special lookup provided in constructor,
0828:             * Otherwise it delegates to the lookup. Never override this method
0829:             * if the lookup is provided in constructor.
0830:             *
0831:             * @param type the class to look for
0832:             * @return instance of that class or null if this class of cookie
0833:             *    is not supported
0834:             * @see Node#getCookie
0835:             */
0836:            @Override
0837:            public <T extends Node.Cookie> T getCookie(Class<T> type) {
0838:                Lookup l = internalLookup(true);
0839:
0840:                if (l != null) {
0841:                    Object res = l.lookup(type);
0842:                    return type.isInstance(res) && res instanceof  Node.Cookie ? type
0843:                            .cast(res)
0844:                            : null;
0845:                }
0846:
0847:                return original.getCookie(type);
0848:            }
0849:
0850:            /** If this is FilterNode without any changes (subclassed, changed children)
0851:             * and the original provides handle, stores them and
0852:             * returns a new handle for the proxy.
0853:             * <p>Subclasses <strong>must</strong> override this if they wish for their nodes to be
0854:             * properly serializable.
0855:             *
0856:             * @return the handle, or <code>null</code> if this node is subclassed or
0857:             *    uses changed children
0858:             */
0859:            public Node.Handle getHandle() {
0860:                if (!isDefault()) {
0861:                    // subclasses has to implement the method by its own
0862:                    return null;
0863:                }
0864:
0865:                Node.Handle original = this .original.getHandle();
0866:
0867:                if (original == null) {
0868:                    // no original handle => no handle here
0869:                    return null;
0870:                }
0871:
0872:                return new FilterHandle(original);
0873:            }
0874:
0875:            /** Test equality of original nodes.
0876:             * Note that for subclasses of <code>FilterNode</code>, or filter nodes with non-default children,
0877:             * the test reverts to object identity.
0878:             * <strong>Note:</strong> if you wish that the {@link Index} cookie works correctly on
0879:             * filtered nodes and their subnodes, and you are subclassing <code>FilterNode</code> or
0880:             * using non-default children, you will probably want to override this method to test
0881:             * equality of the specified node with this filter node's original node; otherwise Move Up
0882:             * and Move Down actions may be disabled.
0883:             * <p>Note though that it is often better to provide your own index cookie from a filter
0884:             * node. Only then it is possible to change the number of children relative to the original.
0885:             * And in many cases this is easier anyway, as for example with
0886:             * <code>DataFolder.Index</code> for data folders.
0887:             * @param o something to compare to, presumably a node or <code>FilterNode</code> of one
0888:             * @return true if this node's original node is the same as the parameter (or original node of parameter)
0889:             */
0890:            @Override
0891:            public boolean equals(Object o) {
0892:                // VERY DANGEROUS! Completely messes up visualizers and often original node is displayed rather than filter.
0893:                // Jst: I know that it is dangerous, but some code probably depends on it
0894:                if (!(o instanceof  Node)) {
0895:                    return false; // something else or null
0896:                }
0897:
0898:                if (this  == o) {
0899:                    return true; // shortcut
0900:                }
0901:
0902:                // get the "most original" ones....
0903:                Node left = getRepresentation(this );
0904:                Node right = getRepresentation((Node) o);
0905:
0906:                // cover nondefault FilterNodes (possibly) deep in the stack
0907:                if ((left instanceof  FilterNode)
0908:                        || (right instanceof  FilterNode)) {
0909:                    return left == right;
0910:                }
0911:
0912:                return left.equals(right);
0913:            }
0914:
0915:            private static Node getRepresentation(Node n) {
0916:                while (n instanceof  FilterNode) {
0917:                    FilterNode fn = (FilterNode) n;
0918:
0919:                    if (!fn.isDefault()) {
0920:                        return n;
0921:                    }
0922:
0923:                    n = fn.original;
0924:                }
0925:
0926:                return n; // either node or nondefault FilterNode
0927:            }
0928:
0929:            /** Hash by original nodes.
0930:             * Note that for subclasses of <code>FilterNode</code>, or filter nodes with non-default children,
0931:             * the hash reverts to the identity hash code.
0932:             * @return the delegated hash code
0933:             */
0934:            public int hashCode() {
0935:                try {
0936:                    assert hashCodeLogging(true) : ""; // NOI18N
0937:
0938:                    int result = isDefault() ? original.hashCode() : System
0939:                            .identityHashCode(this );
0940:                    assert hashCodeLogging(false) : ""; // NOI18N
0941:
0942:                    return result;
0943:                } catch (StackError err) {
0944:                    err.add(this );
0945:                    throw err;
0946:                }
0947:            }
0948:
0949:            /** Method for tracing the issue 46993. Counts the depth of execution
0950:             * and if larger than 1000 throws debugging exception.
0951:             */
0952:            private static boolean hashCodeLogging(boolean enter) {
0953:                if (hashCodeDepth > 1000) {
0954:                    hashCodeDepth = 0;
0955:                    throw new StackError();
0956:                }
0957:
0958:                if (enter) {
0959:                    hashCodeDepth++;
0960:                } else {
0961:                    hashCodeDepth--;
0962:                }
0963:
0964:                return true;
0965:            }
0966:
0967:            //  public String toString () {
0968:            //    return super.toString () + " original has children: " + original.getChildren ().getNodesCount (); // NOI18N
0969:            //  }
0970:            // ----------- END OF DELEGATED METHODS ------------
0971:
0972:            /** Get the original node.
0973:             * <p><strong>Yes</strong> this is supposed to be protected! If you
0974:             * are not subclassing <code>FilterNode</code> yourself, you should
0975:             * not be calling it (nor casting to <code>FilterNode</code>). Use
0976:             * cookies instead.
0977:             * @return the node proxied to
0978:             */
0979:            protected Node getOriginal() {
0980:                return original;
0981:            }
0982:
0983:            /** Create a property change listener that allows listening on the
0984:             * original node properties (contained in property sets) and propagating
0985:             * them to the proxy.
0986:             * <P>
0987:             * This method is called during initialization and allows subclasses
0988:             * to modify the default behaviour.
0989:             *
0990:             * @return a {@link PropertyChangeAdapter} in the default implementation
0991:             */
0992:            protected PropertyChangeListener createPropertyChangeListener() {
0993:                return new PropertyChangeAdapter(this );
0994:            }
0995:
0996:            /** Creates a node listener that allows listening on the
0997:             * original node and propagating events to the proxy.
0998:             * <p>Intended for overriding by subclasses, as with {@link #createPropertyChangeListener}.
0999:             *
1000:             * @return a {@link FilterNode.NodeAdapter} in the default implementation
1001:             */
1002:            protected NodeListener createNodeListener() {
1003:                return new NodeAdapter(this );
1004:            }
1005:
1006:            /** Getter for property change listener.
1007:             */
1008:            synchronized PropertyChangeListener getPropertyChangeListener() {
1009:                if (propL == null) {
1010:                    propL = createPropertyChangeListener();
1011:                }
1012:
1013:                return propL;
1014:            }
1015:
1016:            /** Getter for node listener.
1017:             */
1018:            synchronized NodeListener getNodeListener() {
1019:                if (nodeL == null) {
1020:                    nodeL = createNodeListener();
1021:                    getOriginal().addNodeListener(nodeL);
1022:                }
1023:
1024:                return nodeL;
1025:            }
1026:
1027:            /** Notified from Node that a listener has been added.
1028:             * Thus we force initialization of listeners.
1029:             */
1030:            final void listenerAdded() {
1031:                getNodeListener();
1032:            }
1033:
1034:            /** Check method whether the node has default behaviour or
1035:             * if it is either subclass of uses different children.
1036:             * @return true if it is default
1037:             */
1038:            private boolean isDefault() {
1039:                //System.err.print ("FilterNode.isDefault: ");
1040:                if (getClass() != FilterNode.class) {
1041:                    //System.err.println("false\n\tsubclass of FilterNode");
1042:                    return false;
1043:                }
1044:
1045:                return !childrenProvided;
1046:            }
1047:
1048:            /**
1049:             * This method is used to change the Children from Children.LEAF to Children
1050:             * typically used to when there is a setChildren() on the original node
1051:             * setChildren will fire the appropriate events
1052:             */
1053:            final void updateChildren() {
1054:                if (isDefault()) {
1055:                    org.openide.nodes.Children newChildren = null;
1056:
1057:                    try {
1058:                        Children.PR.enterReadAccess();
1059:
1060:                        if ((original.hierarchy == Children.LEAF)
1061:                                && (hierarchy != Children.LEAF)) {
1062:                            newChildren = Children.LEAF;
1063:                        } else if ((original.hierarchy != Children.LEAF)
1064:                                && (hierarchy == Children.LEAF)) {
1065:                            newChildren = new Children(original);
1066:                        }
1067:                    } finally {
1068:                        Children.PR.exitReadAccess();
1069:                    }
1070:
1071:                    if (newChildren != null) {
1072:                        final org.openide.nodes.Children set = newChildren;
1073:                        Children.MUTEX.postWriteRequest(new Runnable() {
1074:                            public void run() {
1075:                                setChildren(set);
1076:                            }
1077:                        });
1078:                    }
1079:                }
1080:            }
1081:
1082:            /** An exception to be thrown from hashCode() to debug issue 46993.
1083:             */
1084:            private static class StackError extends StackOverflowError {
1085:                private IdentityHashMap<FilterNode, FilterNode> nodes;
1086:
1087:                public void add(FilterNode n) {
1088:                    if (nodes == null) {
1089:                        nodes = new IdentityHashMap<FilterNode, FilterNode>();
1090:                    }
1091:
1092:                    if (!nodes.containsKey(n)) {
1093:                        nodes.put(n, n);
1094:                    }
1095:                }
1096:
1097:                @Override
1098:                public String getMessage() {
1099:                    StringBuffer sb = new StringBuffer();
1100:                    sb.append("StackOver in FilterNodes:\n"); // NOI18N
1101:
1102:                    for (FilterNode f : nodes.keySet()) {
1103:                        sb.append("  class: "); // NOI18N
1104:                        sb.append(f.getClass().getName());
1105:                        sb.append(" id: "); // NOI18N
1106:                        sb.append(Integer.toString(System.identityHashCode(f),
1107:                                16));
1108:                        sb.append("\n"); // NOI18N
1109:                    }
1110:
1111:                    return sb.toString();
1112:                }
1113:            }
1114:
1115:            /** Adapter that listens on changes in an original node
1116:             * and refires them in a proxy.
1117:             * This adapter is created during
1118:             * initialization in  {@link FilterNode#createPropertyChangeListener}. The method
1119:             * can be overridden and this class used as the super class for the
1120:             * new implementation.
1121:             * <P>
1122:             * A reference to the proxy is stored by weak reference, so it does not
1123:             * prevent the node from being finalized.
1124:             */
1125:            protected static class PropertyChangeAdapter extends Object
1126:                    implements  PropertyChangeListener {
1127:                private Reference<FilterNode> fn;
1128:
1129:                /** Create a new adapter.
1130:                 * @param fn the proxy
1131:                 */
1132:                public PropertyChangeAdapter(FilterNode fn) {
1133:                    this .fn = new WeakReference<FilterNode>(fn);
1134:                }
1135:
1136:                /* Find the node we are attached to. If it is not null call property
1137:                 * change method with two arguments.
1138:                 */
1139:                public final void propertyChange(PropertyChangeEvent ev) {
1140:                    FilterNode fn = this .fn.get();
1141:
1142:                    if (fn == null) {
1143:                        return;
1144:                    }
1145:
1146:                    propertyChange(fn, ev);
1147:                }
1148:
1149:                /** Actually propagate the event.
1150:                 * Intended for overriding.
1151:                 * @param fn the proxy
1152:                 * @param ev the event
1153:                 */
1154:                protected void propertyChange(FilterNode fn,
1155:                        PropertyChangeEvent ev) {
1156:                    fn.firePropertyChange(ev.getPropertyName(), ev
1157:                            .getOldValue(), ev.getNewValue());
1158:                }
1159:            }
1160:
1161:            /** Adapter that listens on changes in an original node and refires them
1162:             * in a proxy. Created in {@link FilterNode#createNodeListener}.
1163:             * @see FilterNode.PropertyChangeAdapter
1164:             */
1165:            protected static class NodeAdapter extends Object implements 
1166:                    NodeListener {
1167:                private Reference<FilterNode> fn;
1168:
1169:                /** Create an adapter.
1170:                 * @param fn the proxy
1171:                 */
1172:                public NodeAdapter(FilterNode fn) {
1173:                    this .fn = new WeakReference<FilterNode>(fn);
1174:                }
1175:
1176:                /* Tests if the reference to the node provided in costructor is
1177:                 * still valid (it has not been finalized) and if so, calls propertyChange (Node, ev).
1178:                 */
1179:                public final void propertyChange(PropertyChangeEvent ev) {
1180:                    FilterNode fn = this .fn.get();
1181:
1182:                    if (fn == null) {
1183:                        return;
1184:                    }
1185:
1186:                    propertyChange(fn, ev);
1187:                }
1188:
1189:                /** Actually refire the change event in a subclass.
1190:                 * The default implementation ignores changes of the <code>parentNode</code> property but refires
1191:                 * everything else.
1192:                 *
1193:                 * @param fn the filter node
1194:                 * @param ev the event to fire
1195:                 */
1196:                protected void propertyChange(FilterNode fn,
1197:                        PropertyChangeEvent ev) {
1198:                    String n = ev.getPropertyName();
1199:
1200:                    if (n.equals(Node.PROP_PARENT_NODE)) {
1201:                        // does nothing
1202:                        return;
1203:                    }
1204:
1205:                    if (n.equals(Node.PROP_DISPLAY_NAME)) {
1206:                        fn.fireOwnPropertyChange(PROP_DISPLAY_NAME, (String) ev
1207:                                .getOldValue(), (String) ev.getNewValue());
1208:
1209:                        return;
1210:                    }
1211:
1212:                    if (n.equals(Node.PROP_NAME)) {
1213:                        fn.fireOwnPropertyChange(PROP_NAME, (String) ev
1214:                                .getOldValue(), (String) ev.getNewValue());
1215:
1216:                        return;
1217:                    }
1218:
1219:                    if (n.equals(Node.PROP_SHORT_DESCRIPTION)) {
1220:                        fn.fireOwnPropertyChange(PROP_SHORT_DESCRIPTION,
1221:                                (String) ev.getOldValue(), (String) ev
1222:                                        .getNewValue());
1223:
1224:                        return;
1225:                    }
1226:
1227:                    if (n.equals(Node.PROP_ICON)) {
1228:                        fn.fireIconChange();
1229:
1230:                        return;
1231:                    }
1232:
1233:                    if (n.equals(Node.PROP_OPENED_ICON)) {
1234:                        fn.fireOpenedIconChange();
1235:
1236:                        return;
1237:                    }
1238:
1239:                    if (n.equals(Node.PROP_PROPERTY_SETS)) {
1240:                        fn.firePropertySetsChange((PropertySet[]) ev
1241:                                .getOldValue(), (PropertySet[]) ev
1242:                                .getNewValue());
1243:
1244:                        return;
1245:                    }
1246:
1247:                    if (n.equals(Node.PROP_COOKIE)) {
1248:                        fn.fireCookieChange();
1249:
1250:                        return;
1251:                    }
1252:
1253:                    if (n.equals(Node.PROP_LEAF)) {
1254:                        fn.updateChildren();
1255:
1256:                        /*
1257:                        fn.fireOwnPropertyChange(
1258:                            Node.PROP_LEAF, ev.getOldValue(), ev.getNewValue()
1259:                        );
1260:                         */
1261:                    }
1262:                }
1263:
1264:                /** Does nothing.
1265:                 * @param ev event describing the action
1266:                 */
1267:                public void childrenAdded(NodeMemberEvent ev) {
1268:                }
1269:
1270:                /** Does nothing.
1271:                 * @param ev event describing the action
1272:                 */
1273:                public void childrenRemoved(NodeMemberEvent ev) {
1274:                }
1275:
1276:                /** Does nothing.
1277:                 * @param ev event describing the action
1278:                 */
1279:                public void childrenReordered(NodeReorderEvent ev) {
1280:                }
1281:
1282:                /* Does nothing.
1283:                 * @param ev event describing the node
1284:                 */
1285:                public final void nodeDestroyed(NodeEvent ev) {
1286:                    FilterNode fn = this .fn.get();
1287:
1288:                    if (fn == null) {
1289:                        return;
1290:                    }
1291:
1292:                    fn.originalDestroyed();
1293:                }
1294:            }
1295:
1296:            /** Children for a filter node. Listens on changes in subnodes of
1297:             * the original node and asks this filter node to creates representatives for
1298:             * these subnodes.
1299:             * <P>
1300:             * This class is used as the default for subnodes of filter node, but
1301:             * subclasses may modify it or provide a totally different implementation.
1302:             * <p><code>FilterNode.Children</code> is not well suited to cases where you need to insert
1303:             * additional nodes at the beginning or end of the list, or where you may need
1304:             * to merge together multiple original children lists, or reorder them, etc.
1305:             * That is because the keys are of type <code>Node</code>, one for each original
1306:             * child, and the keys are reset during {@link #addNotify}, {@link #filterChildrenAdded},
1307:             * {@link #filterChildrenRemoved}, and {@link #filterChildrenReordered}, so it is
1308:             * not trivial to use different keys: you would need to override <code>addNotify</code>
1309:             * (calling super first!) and the other three update methods. For such complex cases
1310:             * you will do better by creating your own <code>Children.Keys</code> subclass, setting
1311:             * keys that are useful to you, and keeping a <code>NodeListener</code> on the original
1312:             * node to handle changes.
1313:             */
1314:            public static class Children extends
1315:                    org.openide.nodes.Children.Keys<Node> implements  Cloneable {
1316:                /** Original node. Should not be modified. */
1317:                protected Node original;
1318:
1319:                /** node listener on original */
1320:                private ChildrenAdapter nodeL;
1321:
1322:                /** Create children.
1323:                 * @param or original node to take children from */
1324:                public Children(Node or) {
1325:                    original = or;
1326:                }
1327:
1328:                /** Sets the original children for this children. 
1329:                 * Be aware that this method aquires
1330:                 * write lock on the nodes hierarchy ({@link Children#MUTEX}). 
1331:                 * Take care not to call this method under read lock.
1332:                 * @param original The new original node.
1333:                 * @since 1.39
1334:                 */
1335:                protected final void changeOriginal(Node original) {
1336:                    try {
1337:                        PR.enterWriteAccess();
1338:
1339:                        boolean wasAttached = nodeL != null;
1340:
1341:                        // uregister from the original node
1342:                        if (wasAttached) {
1343:                            this .original.removeNodeListener(nodeL);
1344:                            nodeL = null;
1345:                        }
1346:
1347:                        // reset the original node
1348:                        this .original = original;
1349:
1350:                        if (wasAttached) {
1351:                            addNotifyImpl();
1352:                        }
1353:                    } finally {
1354:                        PR.exitWriteAccess();
1355:                    }
1356:                }
1357:
1358:                /** Closes the listener, if any, on the original node.
1359:                 */
1360:                @Override
1361:                protected void finalize() {
1362:                    if (nodeL != null) {
1363:                        original.removeNodeListener(nodeL);
1364:                    }
1365:
1366:                    nodeL = null;
1367:                }
1368:
1369:                /* Clones the children object.
1370:                 */
1371:                @Override
1372:                public Object clone() {
1373:                    return new Children(original);
1374:                }
1375:
1376:                /** Initializes listening to changes in original node.
1377:                 */
1378:                @Override
1379:                protected void addNotify() {
1380:                    addNotifyImpl();
1381:                }
1382:
1383:                private void addNotifyImpl() {
1384:                    // add itself to reflect to changes children of original node
1385:                    nodeL = new ChildrenAdapter(this );
1386:                    original.addNodeListener(nodeL);
1387:
1388:                    updateKeys();
1389:                }
1390:
1391:                /** Clears current keys, because all mirrored nodes disappeared.
1392:                 */
1393:                @Override
1394:                protected void removeNotify() {
1395:                    setKeys(Collections.<Node> emptySet());
1396:
1397:                    if (nodeL != null) {
1398:                        original.removeNodeListener(nodeL);
1399:                        nodeL = null;
1400:                    }
1401:                }
1402:
1403:                /** Allows subclasses to override
1404:                 * creation of node representants for nodes in the mirrored children
1405:                 * list. The default implementation simply uses {@link Node#cloneNode}.
1406:                 * <p>Note that this method is only suitable for a 1-to-1 mirroring.
1407:                 *
1408:                 * @param node node to create copy of
1409:                 * @return copy of the original node
1410:                 */
1411:                protected Node copyNode(Node node) {
1412:                    return node.cloneNode();
1413:                }
1414:
1415:                /* Implements find of child by finding the original child and then [PENDING]
1416:                 * @param name of node to find
1417:                 * @return the node or null
1418:                 */
1419:                @Override
1420:                public Node findChild(String name) {
1421:                    original.getChildren().findChild(name);
1422:
1423:                    return super .findChild(name);
1424:                }
1425:
1426:                /** Create nodes representing copies of the original node's children.
1427:                 * The default implementation returns exactly one representative for each original node,
1428:                 * as returned by {@link #copyNode}.
1429:                 * Subclasses may override this to avoid displaying a copy of an original child at all,
1430:                 * or even to display multiple nodes representing the original.
1431:                 * @param key the original child node
1432:                 * @return zero or more nodes representing the original child node
1433:                 */
1434:                protected Node[] createNodes(Node key) {
1435:                    // is run under read access lock so nobody can change children
1436:                    return new Node[] { copyNode(key) };
1437:                }
1438:
1439:                /* Delegates to children of the original node.
1440:                 *
1441:                 * @param arr nodes to add
1442:                 * @return true/false
1443:                 */
1444:                @Override
1445:                @Deprecated
1446:                public boolean add(Node[] arr) {
1447:                    return original.getChildren().add(arr);
1448:                }
1449:
1450:                /* Delegates to filter node.
1451:                 * @param arr nodes to remove
1452:                 * @return true/false
1453:                 */
1454:                @Override
1455:                @Deprecated
1456:                public boolean remove(Node[] arr) {
1457:                    return original.getChildren().remove(arr);
1458:                }
1459:
1460:                /** Called when the filter node adds a new child.
1461:                 * The default implementation makes a corresponding change.
1462:                 * @param ev info about the change
1463:                 */
1464:                protected void filterChildrenAdded(NodeMemberEvent ev) {
1465:                    updateKeys();
1466:                }
1467:
1468:                /** Called when the filter node removes a child.
1469:                 * The default implementation makes a corresponding change.
1470:                 * @param ev info about the change
1471:                 */
1472:                protected void filterChildrenRemoved(NodeMemberEvent ev) {
1473:                    updateKeys();
1474:                }
1475:
1476:                /** Called when the filter node reorders its children.
1477:                 * The default implementation makes a corresponding change.
1478:                 * @param ev info about the change
1479:                 */
1480:                protected void filterChildrenReordered(NodeReorderEvent ev) {
1481:                    updateKeys();
1482:                }
1483:
1484:                /** variable to notify that there is a cyclic update.
1485:                 * Used only in updateKeys method
1486:                 */
1487:
1488:                //    private transient boolean cyclic;
1489:                /** Update keys from original nodes */
1490:                private void updateKeys() {
1491:                    ChildrenAdapter runnable = nodeL;
1492:
1493:                    if (runnable != null) {
1494:                        runnable.run();
1495:                    }
1496:                }
1497:
1498:                /**
1499:                 * Implementation that ensures the original node is fully initialized
1500:                 * if optimal result is requested.
1501:                 *
1502:                 * @param optimalResult if <code>true</code>, the method will block
1503:                 * until the original node is fully initialized.
1504:                 * @since 3.9
1505:                 */
1506:                @Override
1507:                public Node[] getNodes(boolean optimalResult) {
1508:                    if (optimalResult) {
1509:                        setKeys(original.getChildren().getNodes(true));
1510:                    }
1511:
1512:                    return getNodes();
1513:                }
1514:            }
1515:
1516:            /** Adapter that listens on changes in the original node and fires them
1517:             * in this node.
1518:             * Used as the default listener in {@link FilterNode.Children},
1519:             * and is intended for refinement by its subclasses.
1520:             */
1521:            private static class ChildrenAdapter extends Object implements 
1522:                    NodeListener, Runnable {
1523:                /** children object to notify about addition of children.
1524:                 * Can be null. Set from Children's initNodes method.
1525:                 */
1526:                private Reference<Children> children;
1527:
1528:                /** Create a new adapter.
1529:                 * @param ch the children list
1530:                 */
1531:                public ChildrenAdapter(Children ch) {
1532:                    this .children = new WeakReference<Children>(ch);
1533:                }
1534:
1535:                /** Called to update the content of children.
1536:                 */
1537:                public void run() {
1538:                    Children ch = children.get();
1539:
1540:                    if (ch != null) {
1541:                        Node[] arr = ch.original.getChildren().getNodes();
1542:                        ch.setKeys(arr);
1543:                    }
1544:                }
1545:
1546:                /** Does nothing.
1547:                 * @param ev the event
1548:                 */
1549:                public void propertyChange(PropertyChangeEvent ev) {
1550:                }
1551:
1552:                /* Informs that a set of new children has been added.
1553:                 * @param ev event describing the action
1554:                 */
1555:                public void childrenAdded(NodeMemberEvent ev) {
1556:                    Children children = this .children.get();
1557:
1558:                    if (children == null) {
1559:                        return;
1560:                    }
1561:
1562:                    children.filterChildrenAdded(ev);
1563:                }
1564:
1565:                /* Informs that a set of children has been removed.
1566:                 * @param ev event describing the action
1567:                 */
1568:                public void childrenRemoved(NodeMemberEvent ev) {
1569:                    Children children = this .children.get();
1570:
1571:                    if (children == null) {
1572:                        return;
1573:                    }
1574:
1575:                    children.filterChildrenRemoved(ev);
1576:                }
1577:
1578:                /* Informs that a set of children has been reordered.
1579:                 * @param ev event describing the action
1580:                 */
1581:                public void childrenReordered(NodeReorderEvent ev) {
1582:                    Children children = this .children.get();
1583:
1584:                    if (children == null) {
1585:                        return;
1586:                    }
1587:
1588:                    children.filterChildrenReordered(ev);
1589:                }
1590:
1591:                /** Does nothing.
1592:                 * @param ev the event
1593:                 */
1594:                public void nodeDestroyed(NodeEvent ev) {
1595:                }
1596:            }
1597:
1598:            /** Filter node handle.
1599:             */
1600:            private static final class FilterHandle implements  Node.Handle {
1601:                static final long serialVersionUID = 7928908039428333839L;
1602:                private Node.Handle original;
1603:
1604:                public FilterHandle(Node.Handle original) {
1605:                    this .original = original;
1606:                }
1607:
1608:                public Node getNode() throws IOException {
1609:                    return new FilterNode(original.getNode());
1610:                }
1611:
1612:                @Override
1613:                public String toString() {
1614:                    return "FilterHandle[" + original + "]"; // NOI18N
1615:                }
1616:            }
1617:
1618:            /** Special ProxyLookup
1619:             */
1620:            private static final class FilterLookup extends Lookup {
1621:                /** node we belong to */
1622:                private FilterNode node;
1623:
1624:                /** lookup we delegate too */
1625:                private Lookup delegate;
1626:
1627:                /** set of all results associated to this lookup */
1628:                private Set<ProxyResult> results;
1629:
1630:                FilterLookup() {
1631:                }
1632:
1633:                /** Registers own node.
1634:                 */
1635:                public void ownNode(FilterNode n) {
1636:                    this .node = n;
1637:                }
1638:
1639:                /** A method that replaces instance of original node
1640:                 * with a new one
1641:                 */
1642:                private <T> T replaceNodes(T orig, Class<T> clazz) {
1643:                    if (isNodeQuery(clazz) && (orig == node.getOriginal())
1644:                            && clazz.isInstance(node)) {
1645:                        return clazz.cast(node);
1646:                    } else {
1647:                        return orig;
1648:                    }
1649:                }
1650:
1651:                /** Changes the node we delegate to if necessary.
1652:                 * @param n the node to delegate to
1653:                 */
1654:                public Lookup checkNode() {
1655:                    Lookup l = node.getOriginal().getLookup();
1656:
1657:                    if (delegate == l) {
1658:                        return l;
1659:                    }
1660:
1661:                    Iterator<ProxyResult> toCheck = null;
1662:
1663:                    synchronized (this ) {
1664:                        if (l != delegate) {
1665:                            this .delegate = l;
1666:
1667:                            if (results != null) {
1668:                                toCheck = new ArrayList<ProxyResult>(results)
1669:                                        .iterator();
1670:                            }
1671:                        }
1672:                    }
1673:
1674:                    if (toCheck != null) {
1675:                        // update
1676:
1677:                        while (toCheck.hasNext()) {
1678:                            ProxyResult p = toCheck.next();
1679:
1680:                            if (p.updateLookup(l)) {
1681:                                p.resultChanged(null);
1682:                            }
1683:                        }
1684:                    }
1685:
1686:                    return delegate;
1687:                }
1688:
1689:                public <T> Result<T> lookup(Template<T> template) {
1690:                    ProxyResult<T> p = new ProxyResult<T>(template);
1691:
1692:                    synchronized (this ) {
1693:                        if (results == null) {
1694:                            results = new WeakSet<ProxyResult>();
1695:                        }
1696:
1697:                        results.add(p);
1698:                    }
1699:
1700:                    return p;
1701:                }
1702:
1703:                public <T> T lookup(Class<T> clazz) {
1704:                    T result = checkNode().lookup(clazz);
1705:
1706:                    if (result == null && clazz.isInstance(node)) {
1707:                        result = clazz.cast(node);
1708:                    }
1709:
1710:                    return replaceNodes(result, clazz);
1711:                }
1712:
1713:                /** Finds out whether a query for a class can be influenced
1714:                 * by a state of the "nodes" lookup and whether we should
1715:                 * initialize listening
1716:                 */
1717:                private static boolean isNodeQuery(Class<?> c) {
1718:                    return Node.class.isAssignableFrom(c)
1719:                            || c.isAssignableFrom(Node.class);
1720:                }
1721:
1722:                @Override
1723:                public <T> Item<T> lookupItem(Template<T> template) {
1724:                    boolean nodeQ = isNodeQuery(template.getType());
1725:                    Item<T> i = checkNode().lookupItem(template);
1726:
1727:                    if (nodeQ
1728:                            && i == null
1729:                            && template.getType().isInstance(node)
1730:                            && (template.getInstance() == null || template
1731:                                    .getInstance() == node)) {
1732:                        i = checkNode().lookupItem(
1733:                                wackohacko(template.getId(), template
1734:                                        .getInstance()));
1735:                    }
1736:
1737:                    return nodeQ && i != null ? new FilterItem<T>(i, template
1738:                            .getType()) : i;
1739:                }
1740:
1741:                @SuppressWarnings("unchecked")
1742:                // cannot type-check this but ought to be safe
1743:                private static <T> Lookup.Template<T> wackohacko(String id,
1744:                        T instance) {
1745:                    return new Lookup.Template(Node.class, id, instance);
1746:                }
1747:
1748:                /**
1749:                 * Result used in SimpleLookup. It holds a reference to the collection
1750:                 * passed in constructor. As the contents of this lookup result never
1751:                 * changes the addLookupListener and removeLookupListener are empty.
1752:                 */
1753:                private final class ProxyResult<T> extends Result<T> implements 
1754:                        LookupListener {
1755:                    /** Template used for this result. It is never null.*/
1756:                    private Template<T> template;
1757:
1758:                    /** result to delegate to */
1759:                    private Lookup.Result<T> delegate;
1760:
1761:                    /** listeners set */
1762:                    private javax.swing.event.EventListenerList listeners;
1763:
1764:                    /** Just remembers the supplied argument in variable template.*/
1765:                    ProxyResult(Template<T> template) {
1766:                        this .template = template;
1767:                    }
1768:
1769:                    /** Checks state of the result
1770:                     */
1771:                    private Result<T> checkResult() {
1772:                        updateLookup(checkNode());
1773:
1774:                        return this .delegate;
1775:                    }
1776:
1777:                    /** Updates the state of the lookup.
1778:                     * @return true if the lookup really changed
1779:                     */
1780:                    public boolean updateLookup(Lookup l) {
1781:                        Collection<? extends Item<T>> oldPairs = (delegate != null) ? delegate
1782:                                .allItems()
1783:                                : null;
1784:
1785:                        synchronized (this ) {
1786:                            if (delegate != null) {
1787:                                delegate.removeLookupListener(this );
1788:                            }
1789:
1790:                            delegate = l.lookup(template);
1791:
1792:                            if (template.getType().isAssignableFrom(
1793:                                    node.getClass())
1794:                                    && delegate.allItems().isEmpty()) {
1795:                                delegate = l.lookup(wackohacko(
1796:                                        template.getId(), template
1797:                                                .getInstance()));
1798:                            }
1799:
1800:                            delegate.addLookupListener(this );
1801:                        }
1802:
1803:                        if (oldPairs == null) {
1804:                            // nobody knows about a change
1805:                            return false;
1806:                        }
1807:
1808:                        Collection<? extends Item<T>> newPairs = delegate
1809:                                .allItems();
1810:
1811:                        return !oldPairs.equals(newPairs);
1812:                    }
1813:
1814:                    public synchronized void addLookupListener(LookupListener l) {
1815:                        if (listeners == null) {
1816:                            listeners = new javax.swing.event.EventListenerList();
1817:                        }
1818:
1819:                        listeners.add(LookupListener.class, l);
1820:                    }
1821:
1822:                    public synchronized void removeLookupListener(
1823:                            LookupListener l) {
1824:                        if (listeners != null) {
1825:                            listeners.remove(LookupListener.class, l);
1826:                        }
1827:                    }
1828:
1829:                    public Collection<? extends T> allInstances() {
1830:                        Collection<? extends T> c = checkResult()
1831:                                .allInstances();
1832:
1833:                        if (isNodeQuery(template.getType())) {
1834:                            List<T> ll = new ArrayList<T>(c.size());
1835:                            for (T o : c) {
1836:                                ll.add(replaceNodes(o, template.getType()));
1837:                            }
1838:                            if (ll.isEmpty()
1839:                                    && template.getType().isInstance(node)) {
1840:                                if (template.getInstance() == null
1841:                                        || template.getInstance() == node) {
1842:                                    ll.add(template.getType().cast(node));
1843:                                }
1844:                            }
1845:
1846:                            return ll;
1847:                        } else {
1848:                            return c;
1849:                        }
1850:                    }
1851:
1852:                    @Override
1853:                    public Set<Class<? extends T>> allClasses() {
1854:                        return checkResult().allClasses();
1855:                    }
1856:
1857:                    @Override
1858:                    public Collection<? extends Item<T>> allItems() {
1859:                        return checkResult().allItems();
1860:                    }
1861:
1862:                    /** A change in lookup occured.
1863:                     * @param ev event describing the change
1864:                     *
1865:                     */
1866:                    public void resultChanged(LookupEvent anEvent) {
1867:                        javax.swing.event.EventListenerList l = this .listeners;
1868:
1869:                        if (l == null) {
1870:                            return;
1871:                        }
1872:
1873:                        Object[] listeners = l.getListenerList();
1874:
1875:                        if (listeners.length == 0) {
1876:                            return;
1877:                        }
1878:
1879:                        LookupEvent ev = new LookupEvent(this );
1880:
1881:                        for (int i = listeners.length - 1; i >= 0; i -= 2) {
1882:                            LookupListener ll = (LookupListener) listeners[i];
1883:                            ll.resultChanged(ev);
1884:                        }
1885:                    }
1886:                }
1887:
1888:                // end of ProxyResult
1889:
1890:                /** Item that exchanges the original node for the FilterNode */
1891:                private final class FilterItem<T> extends Lookup.Item<T> {
1892:                    private Item<T> delegate;
1893:                    private Class<T> clazz;
1894:
1895:                    FilterItem(Item<T> d, Class<T> clazz) {
1896:                        this .delegate = d;
1897:                        this .clazz = clazz;
1898:                    }
1899:
1900:                    public String getDisplayName() {
1901:                        return delegate.getDisplayName();
1902:                    }
1903:
1904:                    public String getId() {
1905:                        return delegate.getId();
1906:                    }
1907:
1908:                    public T getInstance() {
1909:                        return replaceNodes(delegate.getInstance(), clazz);
1910:                    }
1911:
1912:                    public Class<? extends T> getType() {
1913:                        return delegate.getType();
1914:                    }
1915:                }
1916:            }
1917:            // end of FilterLookup
1918:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.