Source Code Cross Referenced for Children.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.lang.ref.Reference;
0045:        import java.lang.ref.WeakReference;
0046:        import java.util.ArrayList;
0047:        import java.util.Arrays;
0048:        import java.util.Collection;
0049:        import java.util.Collections;
0050:        import java.util.Comparator;
0051:        import java.util.Enumeration;
0052:        import java.util.HashMap;
0053:        import java.util.HashSet;
0054:        import java.util.Iterator;
0055:        import java.util.LinkedList;
0056:        import java.util.List;
0057:        import java.util.Set;
0058:        import java.util.TreeSet;
0059:        import java.util.logging.Level;
0060:        import java.util.logging.Logger;
0061:        import org.openide.util.Enumerations;
0062:        import org.openide.util.Mutex;
0063:
0064:        /** 
0065:         * Factory for the child Nodes of a Node.  Every Node has a Children object.
0066:         * Children are initially un-initialized, and child Nodes are created on
0067:         * demand when, for example, the Node is expanded in an Explorer view.
0068:         * If you know your Node has no child nodes, pass <code>Children.LEAF</code>.
0069:         * Typically a Children object will create a Collection of objects from
0070:         * some data model, and create one or more Nodes for each object on demand.
0071:         * 
0072:         * If initializing the list of children of a Node is time-consuming (i.e. it
0073:         * does I/O, parses a file or some other expensive operation), implement
0074:         * ChildFactory and pass it to Children.create (theFactory, true) to have
0075:         * the child nodes be computed asynchronously on a background thread.
0076:         *
0077:         * <p>In almost all cases you want to subclass ChildFactory and pass it to
0078:         * Children.create(), or subclass {@link Children.Keys}.
0079:         * Subclassing <code>Children</code> directly is not recommended.
0080:         * 
0081:         * @author Jaroslav Tulach
0082:         */
0083:        public abstract class Children extends Object {
0084:            /** A package internal accessor object to provide priviledged
0085:             * access to children.
0086:             */
0087:            static final Mutex.Privileged PR = new Mutex.Privileged();
0088:
0089:            /** Lock for access to hierarchy of all node lists.
0090:             * Anyone who needs to ensure that there will not
0091:             * be shared accesses to hierarchy nodes can use this
0092:             * mutex.
0093:             * <P>
0094:             * All operations on the hierarchy of nodes (add, remove, etc.) are
0095:             * done in the {@link Mutex#writeAccess} method of this lock, so if someone
0096:             * needs for a certain amount of time to forbid modification,
0097:             * he can execute his code in {@link Mutex#readAccess}.
0098:             */
0099:            public static final Mutex MUTEX = new Mutex(PR);
0100:
0101:            /** The object representing an empty set of children. Should
0102:             * be used to represent the children of leaf nodes. The same
0103:             * object may be used by all such nodes.
0104:             */
0105:            public static final Children LEAF = new Empty();
0106:            private static final Object LOCK = new Object();
0107:            private static final Logger LOG_GET_ARRAY = Logger
0108:                    .getLogger("org.openide.nodes.Children.getArray"); // NOI18N
0109:
0110:            /** parent node for all nodes in this list (can be null) */
0111:            private Node parent;
0112:
0113:            /** mapping from entries to info about them */
0114:            private java.util.Map<Entry, Info> map;
0115:
0116:            /** collection of all entries */
0117:            private Collection<? extends Entry> entries = Collections
0118:                    .emptyList();
0119:
0120:            private Reference<ChildrenArray> array = new WeakReference<ChildrenArray>(
0121:                    null);
0122:
0123:            /** Obtains references to array holder. If it does not exist, it is
0124:             * created.
0125:             *
0126:             * @param cannotWorkBetter array of size 1 or null, will contain true, if
0127:             *    the getArray cannot be initialized (we are under read access
0128:             *    and another thread is responsible for initialization, in such case
0129:             *    give up on computation of best result
0130:             */
0131:            private Thread initThread;
0132:
0133:            /*
0134:              private StringBuffer debug = new StringBuffer ();
0135:
0136:              private void printStackTrace() {
0137:                Exception e = new Exception ();
0138:                java.io.StringWriter w1 = new java.io.StringWriter ();
0139:                java.io.PrintWriter w = new java.io.PrintWriter (w1);
0140:                e.printStackTrace(w);
0141:                w.close ();
0142:                debug.append (w1.toString ());
0143:                debug.append ('\n');
0144:              }
0145:             */
0146:
0147:            /** Constructor.
0148:             */
0149:            public Children() {
0150:            }
0151:
0152:            /** Setter of parent node for this list of children. Each children in the list
0153:             * will have this node set as parent. The parent node will return nodes in
0154:             * this list as its children.
0155:             * <P>
0156:             * This method is called from the Node constructor
0157:             *
0158:             * @param n node to attach to
0159:             * @exception IllegalStateException when this object is already used with
0160:             *    different node
0161:             */
0162:            final void attachTo(final Node n) throws IllegalStateException {
0163:                // special treatment for LEAF object.
0164:                if (this  == LEAF) {
0165:                    // do not attaches the node because the LEAF cannot have children
0166:                    // and that is why it need not set parent node for them
0167:                    return;
0168:                }
0169:
0170:                synchronized (this ) {
0171:                    if (parent != null) {
0172:                        // already used
0173:                        throw new IllegalStateException(
0174:                                "An instance of Children may not be used for more than one parent node."); // NOI18N
0175:                    }
0176:
0177:                    // attach itself as a node list for given node
0178:                    parent = n;
0179:                }
0180:
0181:                // this is the only place where parent is changed,
0182:                // but only under readAccess => double check if
0183:                // it happened correctly
0184:                try {
0185:                    PR.enterReadAccess();
0186:
0187:                    Node[] nodes = testNodes();
0188:
0189:                    if (nodes == null) {
0190:                        return;
0191:                    }
0192:
0193:                    // fire the change
0194:                    for (int i = 0; i < nodes.length; i++) {
0195:                        Node node = nodes[i];
0196:                        node.assignTo(Children.this , i);
0197:                        node.fireParentNodeChange(null, parent);
0198:                    }
0199:                } finally {
0200:                    PR.exitReadAccess();
0201:                }
0202:            }
0203:
0204:            /** Called when the node changes it's children to different nodes.
0205:             *
0206:             * @param n node to detach from
0207:             * @exception IllegalStateException if children were already detached
0208:             */
0209:            final void detachFrom() {
0210:                // special treatment for LEAF object.
0211:                if (this  == LEAF) {
0212:                    // no need to do anything
0213:                    return;
0214:                }
0215:
0216:                Node oldParent = null;
0217:
0218:                synchronized (this ) {
0219:                    if (parent == null) {
0220:                        // already detached
0221:                        throw new IllegalStateException(
0222:                                "Trying to detach children which do not have parent"); // NOI18N
0223:                    }
0224:
0225:                    // remember old parent 
0226:                    oldParent = parent;
0227:
0228:                    // attach itself as a node list for given node
0229:                    parent = null;
0230:                }
0231:
0232:                // this is the only place where parent is changed,
0233:                // but only under readAccess => double check if
0234:                // it happened correctly
0235:                try {
0236:                    PR.enterReadAccess();
0237:
0238:                    Node[] nodes = testNodes();
0239:
0240:                    if (nodes == null) {
0241:                        return;
0242:                    }
0243:
0244:                    // fire the change
0245:                    for (int i = 0; i < nodes.length; i++) {
0246:                        Node node = nodes[i];
0247:                        node.deassignFrom(Children.this );
0248:                        node.fireParentNodeChange(oldParent, null);
0249:                    }
0250:                } finally {
0251:                    PR.exitReadAccess();
0252:                }
0253:            }
0254:
0255:            /**
0256:             * Create a <code>Children</code> object using the passed <code>ChildFactory</code>
0257:             * object.  The <code>ChildFactory</code> will be asked to create a list
0258:             * of model objects that are the children;  then for each object in the list,
0259:             * {@link ChildFactory#createNodesFor} will be called to instantiate
0260:             * one or more <code>Node</code>s for that object.
0261:             * @param factory a factory which will provide child objects
0262:             * @param asynchronous If true, the factory will always be called to
0263:             *   create the list of keys on
0264:             *   a background thread, displaying a &quot;Please Wait&quot; child node until
0265:             *   some or all child nodes have been computed. If so,
0266:             *   when it is expanded, the node that owns
0267:             *   the returned <code>Children</code> object will display a &quot;Please Wait&quot;
0268:             *   node while the children are computed in the background.  Pass true
0269:             *   for any case where computing child nodes is expensive and should
0270:             *   not be done in the event thread.
0271:             * @return a children object which
0272:             *   will invoke the factory instance as needed to supply model
0273:             *   objects and child nodes for it
0274:             * @throws IllegalStateException if the passed factory has already
0275:             *   been used in a previous call to this method
0276:             * @since org.openide.nodes 7.1
0277:             */
0278:            public static <T> Children create(ChildFactory<T> factory,
0279:                    boolean asynchronous) {
0280:                if (factory == null)
0281:                    throw new NullPointerException("Null factory");
0282:                return asynchronous ? new AsynchChildren<T>(factory)
0283:                        : new SynchChildren<T>(factory);
0284:            }
0285:
0286:            /** Get the parent node of these children.
0287:             * @return the node attached to this children object, or <code>null</code> if there is none yet
0288:             */
0289:            protected final Node getNode() {
0290:                return parent;
0291:            }
0292:
0293:            /** Allows access to the clone method for Node.
0294:             * @return cloned hierarchy
0295:             * @exception CloneNotSupportedException if not supported
0296:             */
0297:            final Object cloneHierarchy() throws CloneNotSupportedException {
0298:                return clone();
0299:            }
0300:
0301:            /** Handles cloning in the right way, that can be later extended by
0302:             * subclasses. Of course each subclass that wishes to support cloning
0303:             * must implement the <code>Cloneable</code> interface, otherwise this method throws
0304:             * <code>CloneNotSupportedException</code>.
0305:             *
0306:             * @return cloned version of this object, with the same class, uninitialized and without
0307:             *   a parent node
0308:             * *exception CloneNotSupportedException if <code>Cloneable</code> interface is not implemented
0309:             */
0310:            protected Object clone() throws CloneNotSupportedException {
0311:                Children ch = (Children) super .clone();
0312:
0313:                ch.parent = null;
0314:                ch.map = null;
0315:                ch.entries = Collections.emptyList();
0316:                ch.array = new WeakReference<ChildrenArray>(null);
0317:
0318:                return ch;
0319:            }
0320:
0321:            /**
0322:             * Add nodes to this container but <strong>do not call this method</strong>.
0323:             * If you think you need to do this probably you really wanted to use
0324:             * {@link Children.Keys#setKeys} instead.
0325:             * The parent node of these nodes
0326:             * is changed to the parent node of this list. Each node can be added
0327:             * only once. If there is some reason a node cannot be added, for example
0328:             * if the node expects only a special type of subnodes, the method should
0329:             * do nothing and return <code>false</code> to signal that the addition has not been successful.
0330:             * <P>
0331:             * This method should be implemented by subclasses to filter some nodes, etc.
0332:             *
0333:             * @param nodes set of nodes to add to the list
0334:             * @return <code>true</code> if successfully added
0335:             */
0336:            public abstract boolean add(final Node[] nodes);
0337:
0338:            /** Remove nodes from the list. Only nodes that are present are
0339:             * removed.
0340:             *
0341:             * @param nodes nodes to be removed
0342:             * @return <code>true</code> if the nodes could be removed
0343:             */
0344:            public abstract boolean remove(final Node[] nodes);
0345:
0346:            /** Get the nodes as an enumeration.
0347:             * @return enumeration of nodes
0348:             */
0349:            public final Enumeration<Node> nodes() {
0350:                return Enumerations.array(getNodes());
0351:            }
0352:
0353:            /** Find a child node by name.
0354:             * This may be overridden in subclasses to provide a more advanced way of finding the
0355:             * child, but the default implementation simply scans through the list of nodes
0356:             * to find the first one with the requested name.
0357:             * <p>Normally the list of nodes should have been computed by the time this returns,
0358:             * but see {@link #getNodes()} for an important caveat as to why this may not
0359:             * be doing what you want and what to do instead.
0360:             * @param name (code) name of child node to find or <code>null</code> if any arbitrary child may
0361:             *    be returned
0362:             * @return the node or <code>null</code> if it could not be found
0363:             */
0364:            public Node findChild(String name) {
0365:                Node[] list = getNodes();
0366:
0367:                if (list.length == 0) {
0368:                    return null;
0369:                }
0370:
0371:                if (name == null) {
0372:                    // return any node
0373:                    return list[0];
0374:                }
0375:
0376:                for (int i = 0; i < list.length; i++) {
0377:                    if (name.equals(list[i].getName())) {
0378:                        // ok, we have found it
0379:                        return list[i];
0380:                    }
0381:                }
0382:
0383:                return null;
0384:            }
0385:
0386:            /** Method that can be used to test whether the children content has
0387:             * ever been used or it is still not initalized.
0388:             * @return true if children has been used before
0389:             * @see #addNotify
0390:             */
0391:            protected final boolean isInitialized() {
0392:                ChildrenArray arr = array.get();
0393:
0394:                return (arr != null) && arr.isInitialized();
0395:            }
0396:
0397:            /** Get's the node at given position. Package private right now
0398:             * to allow tests to use it.
0399:             */
0400:            final Node getNodeAt(int i) {
0401:                return getNodes()[i];
0402:            }
0403:
0404:            /** Get a (sorted) array of nodes in this list.
0405:             * If the children object is not yet initialized,
0406:             * it will be (using {@link #addNotify}) before
0407:             * the nodes are returned.
0408:             * <p><strong>Warning:</strong> not all children
0409:             * implementations do a complete calculation at
0410:             * this point, see {@link #getNodes(boolean)}
0411:             * @return array of nodes
0412:             */
0413:
0414:            //  private static String off = ""; // NOI18N
0415:            public final Node[] getNodes() {
0416:                //Thread.dumpStack();
0417:                //System.err.println(off + "getNodes: " + getNode ());
0418:                boolean[] results = new boolean[2];
0419:
0420:                for (;;) {
0421:                    results[1] = isInitialized();
0422:
0423:                    // initializes the ChildrenArray possibly calls 
0424:                    // addNotify if this is for the first time
0425:                    ChildrenArray array = getArray(results); // fils results[0]
0426:
0427:                    Node[] nodes;
0428:
0429:                    try {
0430:                        PR.enterReadAccess();
0431:
0432:                        nodes = array.nodes();
0433:                    } finally {
0434:                        PR.exitReadAccess();
0435:                    }
0436:
0437:                    final boolean IS_LOG_GET_ARRAY = LOG_GET_ARRAY
0438:                            .isLoggable(Level.FINE);
0439:                    if (IS_LOG_GET_ARRAY) {
0440:                        LOG_GET_ARRAY.fine("  length     : " + nodes.length); // NOI18N
0441:                        LOG_GET_ARRAY.fine("  entries    : " + entries); // NOI18N
0442:                        LOG_GET_ARRAY.fine("  init now   : " + isInitialized()); // NOI18N
0443:                    }
0444:                    // if not initialized that means that after
0445:                    // we computed the nodes, somebody changed them (as a
0446:                    // result of addNotify) => we have to compute them
0447:                    // again
0448:                    if (results[1]) {
0449:                        // otherwise it is ok.
0450:                        return nodes;
0451:                    }
0452:
0453:                    if (results[0]) {
0454:                        // looks like the result cannot be computed, just give empty one
0455:                        return (nodes == null) ? new Node[0] : nodes;
0456:                    }
0457:                }
0458:            }
0459:
0460:            /** Get a (sorted) array of nodes in this list.
0461:             *
0462:             * This method is usefull if you need a fully initialized array of nodes
0463:             * for things like MenuView, node navigation from scripts/tests and so on.
0464:             * But in general if you are trying to get useful data by calling
0465:             * this method, you are probably doing something wrong.
0466:             * Usually you should be asking some underlying model
0467:             * for information, not the nodes for children. For example,
0468:             * <code>DataFolder.getChildren()</code>
0469:             * is a much more appropriate way to get what you want for the case of folder children.
0470:             *
0471:             * If you're extending children, you should make sure this method
0472:             * will return a complete list of nodes. The default implementation will do
0473:             * this correctly so long as your subclass implement findChild(null)
0474:             * to initialize all subnodes.
0475:             *
0476:             * <p><strong>Note:</strong>You should not call this method from inside
0477:             * <code>{@link org.openide.nodes.Children#MUTEX Children.MUTEX}.readAccess()</code>.
0478:             * If you do so, the <code>Node</code> will be unable to update its state
0479:             * before you leave the <code>readAccess()</code>.
0480:             *
0481:             * @since 2.17
0482:             *
0483:             * @param optimalResult whether to try to get a fully initialized array
0484:             * or to simply delegate to {@link #getNodes()}
0485:             * @return array of nodes
0486:             */
0487:            public Node[] getNodes(boolean optimalResult) {
0488:                ChildrenArray hold;
0489:                Node find;
0490:                if (optimalResult) {
0491:                    final boolean IS_LOG_GET_ARRAY = LOG_GET_ARRAY
0492:                            .isLoggable(Level.FINE);
0493:                    if (IS_LOG_GET_ARRAY) {
0494:                        LOG_GET_ARRAY.fine("computing optimal result");// NOI18N
0495:                    }
0496:                    hold = getArray(null);
0497:                    if (IS_LOG_GET_ARRAY) {
0498:                        LOG_GET_ARRAY.fine("optimal result is here: " + hold);// NOI18N
0499:                    }
0500:                    find = findChild(null);
0501:                    if (IS_LOG_GET_ARRAY) {
0502:                        LOG_GET_ARRAY.fine("Find child got: " + find); // NOI18N
0503:                    }
0504:                }
0505:
0506:                return getNodes();
0507:            }
0508:
0509:            /** Get the number of nodes in the list.
0510:             * @return the count
0511:             */
0512:            public final int getNodesCount() {
0513:                return getNodes().length;
0514:            }
0515:
0516:            //
0517:            // StateNotifications
0518:            //
0519:
0520:            /** Called when children are first asked for nodes.
0521:             * Typical implementations at this time calculate
0522:             * their node list (or keys for {@link Children.Keys} etc.).<BR>
0523:             * Notice: call to getNodes() inside of this method will return
0524:             * an empty array of nodes.
0525:             * @see #isInitialized
0526:             */
0527:            protected void addNotify() {
0528:            }
0529:
0530:            /** Called when all the children Nodes are freed from memory.
0531:             * Typical implementations at this time clear all the keys
0532:             * (in case of {@link Children.Keys}) etc.
0533:             *
0534:             * Note that this is usually not the best place for unregistering
0535:             * listeners, etc., as listeners usually keep the child nodes
0536:             * in memory, preventing them from being collected, thus preventing
0537:             * this method to be called in the first place.
0538:             */
0539:            protected void removeNotify() {
0540:            }
0541:
0542:            /** Method that can be overriden in subclasses to
0543:             * do additional work and then call addNotify.
0544:             */
0545:            void callAddNotify() {
0546:                addNotify();
0547:            }
0548:
0549:            //
0550:            // ChildrenArray operations call only under lock
0551:            //
0552:
0553:            /** @return either nodes associated with this children or null if
0554:             * they are not created
0555:             */
0556:            private Node[] testNodes() {
0557:                ChildrenArray arr = array.get();
0558:
0559:                return (arr == null) ? null : arr.nodes();
0560:            }
0561:
0562:            private ChildrenArray getArray(boolean[] cannotWorkBetter) {
0563:                final boolean IS_LOG_GET_ARRAY = LOG_GET_ARRAY
0564:                        .isLoggable(Level.FINE);
0565:
0566:                ChildrenArray arr;
0567:                boolean doInitialize = false;
0568:                synchronized (LOCK) {
0569:                    arr = array.get();
0570:
0571:                    if (arr == null) {
0572:                        arr = new ChildrenArray();
0573:
0574:                        // register the array with the children
0575:                        registerChildrenArray(arr, true);
0576:                        doInitialize = true;
0577:                        initThread = Thread.currentThread();
0578:                    }
0579:                }
0580:
0581:                if (doInitialize) {
0582:                    if (IS_LOG_GET_ARRAY) {
0583:                        LOG_GET_ARRAY.fine("Initialize " + this  + " on "
0584:                                + Thread.currentThread()); // NOI18N
0585:                    }
0586:
0587:                    // this call can cause a lot of callbacks => be prepared
0588:                    // to handle them as clean as possible
0589:                    try {
0590:                        this .callAddNotify();
0591:
0592:                        if (IS_LOG_GET_ARRAY) {
0593:                            LOG_GET_ARRAY
0594:                                    .fine("addNotify successfully called for "
0595:                                            + this  + " on "
0596:                                            + Thread.currentThread()); // NOI18N
0597:                        }
0598:                    } finally {
0599:                        boolean notifyLater;
0600:                        notifyLater = MUTEX.isReadAccess();
0601:
0602:                        if (IS_LOG_GET_ARRAY) {
0603:                            LOG_GET_ARRAY.fine("notifyAll for " + this  + " on "
0604:                                    + Thread.currentThread()
0605:                                    + "  notifyLater: " + notifyLater); // NOI18N
0606:                        }
0607:
0608:                        // now attach to children, so when children == null => we are
0609:                        // not fully initialized!!!!
0610:                        arr.children = this ;
0611:                        class SetAndNotify implements  Runnable {
0612:                            public ChildrenArray toSet;
0613:                            public Children whatSet;
0614:
0615:                            public void run() {
0616:                                synchronized (LOCK) {
0617:                                    initThread = null;
0618:                                    LOCK.notifyAll();
0619:                                }
0620:
0621:                                if (IS_LOG_GET_ARRAY) {
0622:                                    LOG_GET_ARRAY.fine("notifyAll done"); // NOI18N
0623:                                }
0624:
0625:                            }
0626:                        }
0627:
0628:                        SetAndNotify setAndNotify = new SetAndNotify();
0629:                        setAndNotify.toSet = arr;
0630:                        setAndNotify.whatSet = this ;
0631:
0632:                        if (notifyLater) {
0633:                            // the notify to the lock has to be done later than
0634:                            // setKeys is executed, otherwise the result of addNotify
0635:                            // might not be visible to other threads
0636:                            // fix for issue 50308
0637:                            MUTEX.postWriteRequest(setAndNotify);
0638:                        } else {
0639:                            setAndNotify.run();
0640:                        }
0641:                    }
0642:                } else {
0643:                    // otherwise, if not initialize yet (arr.children) wait 
0644:                    // for the initialization to finish, but only if we can wait
0645:                    if (MUTEX.isReadAccess() || MUTEX.isWriteAccess()
0646:                            || (initThread == Thread.currentThread())) {
0647:                        // fail, we are in read access
0648:                        if (IS_LOG_GET_ARRAY) {
0649:                            LOG_GET_ARRAY.log(Level.FINE,
0650:                                    "cannot initialize better " + this 
0651:                                            + // NOI18N
0652:                                            " on " + Thread.currentThread()
0653:                                            + // NOI18N
0654:                                            " read access: "
0655:                                            + MUTEX.isReadAccess() + // NOI18N
0656:                                            " initThread: " + initThread, // NOI18N
0657:                                    new Exception("StackTrace") // NOI18N
0658:                                    );
0659:                        }
0660:
0661:                        if (cannotWorkBetter != null) {
0662:                            cannotWorkBetter[0] = true;
0663:                        }
0664:
0665:                        return arr;
0666:                    }
0667:
0668:                    // otherwise we can wait
0669:                    synchronized (LOCK) {
0670:                        while (initThread != null) {
0671:                            if (IS_LOG_GET_ARRAY) {
0672:                                LOG_GET_ARRAY.fine("waiting for children for "
0673:                                        + this  + // NOI18N
0674:                                        " on " + Thread.currentThread() // NOI18N
0675:                                );
0676:                            }
0677:
0678:                            try {
0679:                                LOCK.wait();
0680:                            } catch (InterruptedException ex) {
0681:                            }
0682:                        }
0683:                    }
0684:                    if (IS_LOG_GET_ARRAY) {
0685:                        LOG_GET_ARRAY.fine(" children are here for " + this  + // NOI18N
0686:                                " on " + Thread.currentThread() + // NOI18N
0687:                                " children " + arr.children);
0688:                    }
0689:                }
0690:
0691:                return arr;
0692:            }
0693:
0694:            /** Clears the nodes
0695:             */
0696:            private void clearNodes() {
0697:                ChildrenArray arr = array.get();
0698:
0699:                //System.err.println(off + "  clearNodes: " + getNode ());
0700:                if (arr != null) {
0701:                    // clear the array
0702:                    arr.clear();
0703:                }
0704:            }
0705:
0706:            /** Forces finalization of nodes for given info.
0707:             * Called from finalizer of Info.
0708:             */
0709:            final void finalizeNodes() {
0710:                ChildrenArray arr = array.get();
0711:
0712:                if (arr != null) {
0713:                    arr.finalizeNodes();
0714:                }
0715:            }
0716:
0717:            /** Registration of ChildrenArray.
0718:             * @param chArr the associated ChildrenArray
0719:             * @param weak use weak or hard reference
0720:             */
0721:            final void registerChildrenArray(final ChildrenArray chArr,
0722:                    boolean weak) {
0723:                final boolean IS_LOG_GET_ARRAY = LOG_GET_ARRAY
0724:                        .isLoggable(Level.FINE);
0725:                if (IS_LOG_GET_ARRAY) {
0726:                    LOG_GET_ARRAY.fine("registerChildrenArray: " + chArr
0727:                            + " weak: " + weak); // NOI18N
0728:                }
0729:                if (weak) {
0730:                    this .array = new WeakReference<ChildrenArray>(chArr);
0731:                } else {
0732:                    // hold the children hard
0733:                    this .array = new WeakReference<ChildrenArray>(chArr) {
0734:                        @Override
0735:                        public ChildrenArray get() {
0736:                            return chArr;
0737:                        }
0738:                    };
0739:                }
0740:
0741:                chArr.pointedBy(this .array);
0742:                if (IS_LOG_GET_ARRAY) {
0743:                    LOG_GET_ARRAY.fine("pointed by: " + chArr + " to: "
0744:                            + this .array); // NOI18N
0745:                }
0746:            }
0747:
0748:            /** Finalized.
0749:             */
0750:            final void finalizedChildrenArray(Reference caller) {
0751:                final boolean IS_LOG_GET_ARRAY = LOG_GET_ARRAY
0752:                        .isLoggable(Level.FINE);
0753:                // usually in removeNotify setKeys is called => better require write access
0754:                try {
0755:                    PR.enterWriteAccess();
0756:
0757:                    if (IS_LOG_GET_ARRAY) {
0758:                        LOG_GET_ARRAY.fine("previous array: " + array
0759:                                + " caller: " + caller);
0760:                    }
0761:                    if (array == caller) {
0762:                        // really finalized and not reconstructed
0763:                        removeNotify();
0764:                    }
0765:
0766:                    /*
0767:                    else {
0768:                        System.out.println("Strange removeNotify " + caller + " : " + value );
0769:                    }
0770:                     */
0771:                } finally {
0772:                    PR.exitWriteAccess();
0773:                }
0774:            }
0775:
0776:            /** Computes the nodes now.
0777:             */
0778:            final Node[] justComputeNodes() {
0779:                if (map == null) {
0780:                    map = Collections.synchronizedMap(new HashMap<Entry, Info>(
0781:                            17));
0782:
0783:                    //      debug.append ("Map initialized\n"); // NOI18N
0784:                    //      printStackTrace();
0785:                }
0786:
0787:                List<Node> l = new LinkedList<Node>();
0788:                for (Entry entry : entries) {
0789:                    Info info = findInfo(entry);
0790:
0791:                    try {
0792:                        l.addAll(info.nodes());
0793:                    } catch (RuntimeException ex) {
0794:                        NodeOp.warning(ex);
0795:                    }
0796:                }
0797:
0798:                Node[] arr = l.toArray(new Node[l.size()]);
0799:
0800:                // initialize parent nodes
0801:                for (int i = 0; i < arr.length; i++) {
0802:                    Node n = arr[i];
0803:                    n.assignTo(this , i);
0804:                    n.fireParentNodeChange(null, parent);
0805:                }
0806:
0807:                return arr;
0808:            }
0809:
0810:            /** Finds info for given entry, or registers
0811:             * it, if not registered yet.
0812:             */
0813:            private Info findInfo(Entry entry) {
0814:                synchronized (map) {
0815:                    Info info = map.get(entry);
0816:
0817:                    if (info == null) {
0818:                        info = new Info(entry);
0819:                        map.put(entry, info);
0820:
0821:                        //      debug.append ("Put: " + entry + " info: " + info); // NOI18N
0822:                        //      debug.append ('\n');
0823:                        //      printStackTrace();
0824:                    }
0825:                    return info;
0826:                }
0827:            }
0828:
0829:            //
0830:            // Entries
0831:            //
0832:
0833:            /** Access to copy of current entries.
0834:             * @return copy of entries in the objects
0835:             */
0836:            final List<Entry> getEntries() {
0837:                return new ArrayList<Entry>(this .entries);
0838:            }
0839:
0840:            final void setEntries(Collection<? extends Entry> entries) {
0841:                final boolean IS_LOG_GET_ARRAY = LOG_GET_ARRAY
0842:                        .isLoggable(Level.FINE);
0843:                // current list of nodes
0844:                ChildrenArray holder = array.get();
0845:
0846:                if (IS_LOG_GET_ARRAY) {
0847:                    LOG_GET_ARRAY.fine("setEntries for " + this  + " on "
0848:                            + Thread.currentThread()); // NOI18N
0849:                    LOG_GET_ARRAY.fine("       values: " + entries); // NOI18N
0850:                    LOG_GET_ARRAY.fine("       holder: " + holder); // NOI18N
0851:                }
0852:                if (holder == null) {
0853:                    //      debug.append ("Set1: " + entries); // NOI18N
0854:                    //      printStackTrace();
0855:                    this .entries = entries;
0856:
0857:                    if (map != null) {
0858:                        map.keySet().retainAll(new HashSet<Entry>(entries));
0859:                    }
0860:
0861:                    return;
0862:                }
0863:
0864:                Node[] current = holder.nodes();
0865:
0866:                if (current == null) {
0867:                    // the initialization is not finished yet =>
0868:                    //      debug.append ("Set2: " + entries); // NOI18N
0869:                    //      printStackTrace();
0870:                    this .entries = entries;
0871:
0872:                    if (map != null) {
0873:                        map.keySet().retainAll(new HashSet<Entry>(entries));
0874:                    }
0875:
0876:                    return;
0877:                }
0878:
0879:                // if there are old items in the map, remove them to
0880:                // reflect current state
0881:                map.keySet().retainAll(new HashSet<Entry>(this .entries));
0882:
0883:                // what should be removed
0884:                Set<Entry> toRemove = new HashSet<Entry>(map.keySet());
0885:                Set<Entry> entriesSet = new HashSet<Entry>(entries);
0886:                toRemove.removeAll(entriesSet);
0887:
0888:                if (!toRemove.isEmpty()) {
0889:                    // notify removing, the set must be ready for
0890:                    // callbacks with questions
0891:                    updateRemove(current, toRemove);
0892:                    current = holder.nodes();
0893:                }
0894:
0895:                // change the order of entries, notifies
0896:                // it and again brings children to up-to-date state
0897:                Collection<Info> toAdd = updateOrder(current, entries);
0898:
0899:                if (!toAdd.isEmpty()) {
0900:                    // toAdd contains Info objects that should
0901:                    // be added
0902:                    updateAdd(toAdd, entries);
0903:                }
0904:            }
0905:
0906:            private void checkInfo(Info info, Entry entry,
0907:                    Collection<? extends Entry> entries,
0908:                    java.util.Map<Entry, Info> map) {
0909:                if (info == null) {
0910:                    throw new IllegalStateException(
0911:                            "Error in "
0912:                                    + getClass().getName()
0913:                                    + " with entry "
0914:                                    + entry
0915:                                    + " from among "
0916:                                    + entries
0917:                                    + " in "
0918:                                    + map
0919:                                    + // NOI18N
0920:                                    " probably caused by faulty key implementation."
0921:                                    + // NOI18N
0922:                                    " The key hashCode() and equals() methods must behave as for an IMMUTABLE object"
0923:                                    + // NOI18N
0924:                                    " and the hashCode() must return the same value for equals() keys."); // NOI18N
0925:                }
0926:            }
0927:
0928:            /** Removes the objects from the children.
0929:             */
0930:            private void updateRemove(Node[] current, Set<Entry> toRemove) {
0931:                List<Node> nodes = new LinkedList<Node>();
0932:
0933:                for (Entry en : toRemove) {
0934:                    Info info = map.remove(en);
0935:
0936:                    //debug.append ("Removed: " + en + " info: " + info); // NOI18N
0937:                    //debug.append ('\n');
0938:                    //printStackTrace();
0939:                    checkInfo(info, en, null, map);
0940:
0941:                    nodes.addAll(info.nodes());
0942:                }
0943:
0944:                // modify the current set of entries and empty the list of nodes
0945:                // so it has to be recreated again
0946:                //debug.append ("Current : " + this.entries + '\n'); // NOI18N
0947:                this .entries.removeAll(toRemove);
0948:
0949:                //debug.append ("Removing: " + toRemove + '\n'); // NOI18N
0950:                //debug.append ("New     : " + this.entries + '\n'); // NOI18N
0951:                //printStackTrace();
0952:                clearNodes();
0953:
0954:                notifyRemove(nodes, current);
0955:            }
0956:
0957:            /** Notifies that a set of nodes has been removed from
0958:             * children. It is necessary that the system is already
0959:             * in consistent state, so any callbacks will return
0960:             * valid values.
0961:             *
0962:             * @param nodes list of removed nodes
0963:             * @param current state of nodes
0964:             * @return array of nodes that were deleted
0965:             */
0966:            Node[] notifyRemove(Collection<Node> nodes, Node[] current) {
0967:                //System.err.println("notifyRemove from: " + getNode ());
0968:                //System.err.println("notifyRemove: " + nodes);
0969:                //System.err.println("Current     : " + Arrays.asList (current));
0970:                //Thread.dumpStack();
0971:                //Keys.last.printStackTrace();
0972:                // [TODO] Children do not have always a parent
0973:                // see Services->FIRST ($SubLevel.class)
0974:                // during a deserialization it may have parent == null
0975:                Node[] arr = nodes.toArray(new Node[nodes.size()]);
0976:
0977:                if (parent == null) {
0978:                    return arr;
0979:                }
0980:
0981:                // fire change of nodes
0982:                parent.fireSubNodesChange(false, // remove
0983:                        arr, current);
0984:
0985:                // fire change of parent
0986:                Iterator it = nodes.iterator();
0987:
0988:                while (it.hasNext()) {
0989:                    Node n = (Node) it.next();
0990:                    n.deassignFrom(this );
0991:                    n.fireParentNodeChange(parent, null);
0992:                }
0993:
0994:                return arr;
0995:            }
0996:
0997:            /** Updates the order of entries.
0998:             * @param current current state of nodes
0999:             * @param entries new set of entries
1000:             * @return list of infos that should be added
1001:             */
1002:            private List<Info> updateOrder(Node[] current,
1003:                    Collection<? extends Entry> newEntries) {
1004:                List<Info> toAdd = new LinkedList<Info>();
1005:
1006:                // that assignes entries their begining position in the array
1007:                // of nodes
1008:                java.util.Map<Info, Integer> offsets = new HashMap<Info, Integer>();
1009:
1010:                {
1011:                    int previousPos = 0;
1012:
1013:                    for (Entry entry : entries) {
1014:                        Info info = map.get(entry);
1015:                        checkInfo(info, entry, entries, map);
1016:
1017:                        offsets.put(info, previousPos);
1018:
1019:                        previousPos += info.length();
1020:                    }
1021:                }
1022:
1023:                // because map can contain some additional items,
1024:                // that has not been garbage collected yet,
1025:                // retain only those that are in current list of
1026:                // entries
1027:                map.keySet().retainAll(new HashSet<Entry>(entries));
1028:
1029:                int[] perm = new int[current.length];
1030:                int currentPos = 0;
1031:                int permSize = 0;
1032:                List<Entry> reorderedEntries = null;
1033:
1034:                for (Entry entry : newEntries) {
1035:                    Info info = map.get(entry);
1036:
1037:                    if (info == null) {
1038:                        // this info has to be added
1039:                        info = new Info(entry);
1040:                        toAdd.add(info);
1041:                    } else {
1042:                        int len = info.length();
1043:
1044:                        if (reorderedEntries == null) {
1045:                            reorderedEntries = new LinkedList<Entry>();
1046:                        }
1047:
1048:                        reorderedEntries.add(entry);
1049:
1050:                        // already there => test if it should not be reordered
1051:                        Integer previousInt = offsets.get(info);
1052:
1053:                        /*
1054:                                if (previousInt == null) {
1055:                                  System.err.println("Offsets: " + offsets);
1056:                                  System.err.println("Info: " + info);
1057:                                  System.err.println("Entry: " + info.entry);
1058:                                  System.err.println("This entries: " + this.entries);
1059:                                  System.err.println("Entries: " + entries);
1060:                                  System.err.println("Map: " + map);
1061:
1062:                                  System.err.println("---------vvvvv");
1063:                                  System.err.println(debug);
1064:                                  System.err.println("---------^^^^^");
1065:
1066:                                }
1067:                         */
1068:                        int previousPos = previousInt;
1069:
1070:                        if (currentPos != previousPos) {
1071:                            for (int i = 0; i < len; i++) {
1072:                                perm[previousPos + i] = 1 + currentPos + i;
1073:                            }
1074:
1075:                            permSize += len;
1076:                        }
1077:                    }
1078:
1079:                    currentPos += info.length();
1080:                }
1081:
1082:                if (permSize > 0) {
1083:                    // now the perm array contains numbers 1 to ... and
1084:                    // 0 one places where no permutation occures =>
1085:                    // decrease numbers, replace zeros
1086:                    for (int i = 0; i < perm.length; i++) {
1087:                        if (perm[i] == 0) {
1088:                            // fixed point
1089:                            perm[i] = i;
1090:                        } else {
1091:                            // decrease
1092:                            perm[i]--;
1093:                        }
1094:                    }
1095:
1096:                    // reorderedEntries are not null
1097:                    this .entries = reorderedEntries;
1098:
1099:                    //      debug.append ("Set3: " + this.entries); // NOI18N
1100:                    //      printStackTrace();
1101:                    // notify the permutation to the parent
1102:                    clearNodes();
1103:
1104:                    //System.err.println("Paremutaiton! " + getNode ());
1105:                    Node p = parent;
1106:
1107:                    if (p != null) {
1108:                        p.fireReorderChange(perm);
1109:                    }
1110:                }
1111:
1112:                return toAdd;
1113:            }
1114:
1115:            /** Updates the state of children by adding given Infos.
1116:             * @param infos list of Info objects to add
1117:             * @param entries the final state of entries that should occur
1118:             */
1119:            private void updateAdd(Collection<Info> infos,
1120:                    Collection<? extends Entry> entries) {
1121:                List<Node> nodes = new LinkedList<Node>();
1122:                for (Info info : infos) {
1123:                    nodes.addAll(info.nodes());
1124:                    map.put(info.entry, info);
1125:
1126:                    //      debug.append ("updateadd: " + info.entry + " info: " + info + '\n'); // NOI18N
1127:                    //      printStackTrace();
1128:                }
1129:
1130:                this .entries = entries;
1131:
1132:                //      debug.append ("Set4: " + entries); // NOI18N
1133:                //      printStackTrace();
1134:                clearNodes();
1135:
1136:                notifyAdd(nodes);
1137:            }
1138:
1139:            /** Notifies that a set of nodes has been add to
1140:             * children. It is necessary that the system is already
1141:             * in consistent state, so any callbacks will return
1142:             * valid values.
1143:             *
1144:             * @param nodes list of removed nodes
1145:             */
1146:            private void notifyAdd(Collection<Node> nodes) {
1147:                // notify about parent change
1148:                for (Node n : nodes) {
1149:                    n.assignTo(this , -1);
1150:                    n.fireParentNodeChange(null, parent);
1151:                }
1152:
1153:                Node[] arr = nodes.toArray(new Node[nodes.size()]);
1154:
1155:                Node n = parent;
1156:
1157:                if (n != null) {
1158:                    n.fireSubNodesChange(true, arr, null);
1159:                }
1160:            }
1161:
1162:            /** Refreshes content of one entry. Updates the state of children
1163:             * appropriately.
1164:             */
1165:            final void refreshEntry(Entry entry) {
1166:                // current list of nodes
1167:                ChildrenArray holder = array.get();
1168:
1169:                if (holder == null) {
1170:                    return;
1171:                }
1172:
1173:                Node[] current = holder.nodes();
1174:
1175:                if (current == null) {
1176:                    // the initialization is not finished yet =>
1177:                    return;
1178:                }
1179:
1180:                // because map can contain some additional items,
1181:                // that has not been garbage collected yet,
1182:                // retain only those that are in current list of
1183:                // entries
1184:                map.keySet().retainAll(new HashSet<Entry>(this .entries));
1185:
1186:                Info info = map.get(entry);
1187:
1188:                if (info == null) {
1189:                    // refresh of entry that is not present =>
1190:                    return;
1191:                }
1192:
1193:                Collection<Node> oldNodes = info.nodes();
1194:                Collection<Node> newNodes = info.entry.nodes();
1195:
1196:                if (oldNodes.equals(newNodes)) {
1197:                    // nodes are the same =>
1198:                    return;
1199:                }
1200:
1201:                Set<Node> toRemove = new HashSet<Node>(oldNodes);
1202:                toRemove.removeAll(new HashSet<Node>(newNodes));
1203:
1204:                if (!toRemove.isEmpty()) {
1205:                    // notify removing, the set must be ready for
1206:                    // callbacks with questions
1207:                    // modifies the list associated with the info
1208:                    oldNodes.removeAll(toRemove);
1209:                    clearNodes();
1210:
1211:                    // now everything should be consistent => notify the remove
1212:                    notifyRemove(toRemove, current);
1213:
1214:                    current = holder.nodes();
1215:                }
1216:
1217:                List<Node> toAdd = refreshOrder(entry, oldNodes, newNodes);
1218:                info.useNodes(newNodes);
1219:
1220:                if (!toAdd.isEmpty()) {
1221:                    // modifies the list associated with the info
1222:                    clearNodes();
1223:                    notifyAdd(toAdd);
1224:                }
1225:            }
1226:
1227:            /** Updates the order of nodes after a refresh.
1228:             * @param entry the refreshed entry
1229:             * @param oldNodes nodes that are currently in the list
1230:             * @param newNodes new nodes (defining the order of oldNodes and some more)
1231:             * @return list of infos that should be added
1232:             */
1233:            private List<Node> refreshOrder(Entry entry,
1234:                    Collection<Node> oldNodes, Collection<Node> newNodes) {
1235:                List<Node> toAdd = new LinkedList<Node>();
1236:
1237:                int currentPos = 0;
1238:
1239:                // cycle thru all entries to find index of the entry
1240:                Iterator<? extends Entry> it1 = this .entries.iterator();
1241:
1242:                for (;;) {
1243:                    Entry e = it1.next();
1244:
1245:                    if (e.equals(entry)) {
1246:                        break;
1247:                    }
1248:
1249:                    Info info = findInfo(e);
1250:                    currentPos += info.length();
1251:                }
1252:
1253:                Set<Node> oldNodesSet = new HashSet<Node>(oldNodes);
1254:                Set<Node> toProcess = new HashSet<Node>(oldNodesSet);
1255:
1256:                Node[] permArray = new Node[oldNodes.size()];
1257:                Iterator<Node> it2 = newNodes.iterator();
1258:
1259:                int pos = 0;
1260:
1261:                while (it2.hasNext()) {
1262:                    Node n = it2.next();
1263:
1264:                    if (oldNodesSet.remove(n)) {
1265:                        // the node is in the old set => test for permuation
1266:                        permArray[pos++] = n;
1267:                    } else {
1268:                        if (!toProcess.contains(n)) {
1269:                            // if the node has not been processed yet
1270:                            toAdd.add(n);
1271:                        } else {
1272:                            it2.remove();
1273:                        }
1274:                    }
1275:                }
1276:
1277:                // JST: If you get IllegalArgumentException in following code
1278:                // then it can be cause by wrong synchronization between
1279:                // equals and hashCode methods. First of all check them!
1280:                int[] perm = NodeOp.computePermutation(oldNodes
1281:                        .toArray(new Node[oldNodes.size()]), permArray);
1282:
1283:                if (perm != null) {
1284:                    // apply the permutation
1285:                    clearNodes();
1286:
1287:                    // temporarily change the nodes the entry should use
1288:                    findInfo(entry).useNodes(Arrays.asList(permArray));
1289:
1290:                    Node p = parent;
1291:
1292:                    if (p != null) {
1293:                        p.fireReorderChange(perm);
1294:                    }
1295:                }
1296:
1297:                return toAdd;
1298:            }
1299:
1300:            /** Interface that provides a set of nodes.
1301:             */
1302:            static interface Entry {
1303:                /** Set of nodes associated with this entry.
1304:                 */
1305:                public Collection<Node> nodes();
1306:            }
1307:
1308:            /** Information about an entry. Contains number of nodes,
1309:             * position in the array of nodes, etc.
1310:             */
1311:            final class Info extends Object {
1312:                int length;
1313:                final Entry entry;
1314:
1315:                public Info(Entry entry) {
1316:                    this .entry = entry;
1317:                }
1318:
1319:                /** Finalizes the content of ChildrenArray.
1320:                 */
1321:                protected void finalize() {
1322:                    finalizeNodes();
1323:                }
1324:
1325:                public Collection<Node> nodes() {
1326:                    // forces creation of the array
1327:                    ChildrenArray arr = getArray(null);
1328:
1329:                    return arr.nodesFor(this );
1330:                }
1331:
1332:                public void useNodes(Collection<Node> nodes) {
1333:                    // forces creation of the array
1334:                    ChildrenArray arr = getArray(null);
1335:
1336:                    arr.useNodes(this , nodes);
1337:
1338:                    // assign all there nodes the new children
1339:                    for (Node n : nodes) {
1340:                        n.assignTo(Children.this , -1);
1341:                        n.fireParentNodeChange(null, parent);
1342:                    }
1343:                }
1344:
1345:                public int length() {
1346:                    return length;
1347:                }
1348:
1349:                @Override
1350:                public String toString() {
1351:                    return "Children.Info[" + entry + ",length=" + length + "]"; // NOI18N
1352:                }
1353:            }
1354:
1355:            /** Empty list of children. Does not allow anybody to insert a node.
1356:             * Treated especially in the attachTo method.
1357:             */
1358:            private static final class Empty extends Children {
1359:                Empty() {
1360:                }
1361:
1362:                /** @return false, does no action */
1363:                public boolean add(Node[] nodes) {
1364:                    return false;
1365:                }
1366:
1367:                /** @return false, does no action */
1368:                public boolean remove(Node[] nodes) {
1369:                    return false;
1370:                }
1371:            }
1372:
1373:            /** Implements the storage of node children by an array.
1374:             * Each new child is added at the end of the array. The nodes are
1375:             * returned in the order they were inserted.
1376:             *
1377:             * <p><strong>
1378:             * Directly subclassing this class is discouraged.
1379:             * {@link Children.Keys} is preferable.
1380:             * </strong>
1381:             */
1382:            public static class Array extends Children implements  Cloneable {
1383:                /** the entry used for all nodes in the following collection
1384:                 * this object is used for synchronization of operations that
1385:                 * need to be synchronized on this instance of Children, but
1386:                 * we cannot synchronize on this instance because it is public
1387:                 * and somebody else could synchronize too.
1388:                 */
1389:                private Entry nodesEntry;
1390:
1391:                /** vector of added children */
1392:                protected Collection<Node> nodes;
1393:
1394:                /** Constructs a new list and allows a subclass to
1395:                 * provide its own implementation of <code>Collection</code> to store
1396:                 * data in. The collection should be empty and should not
1397:                 * be directly accessed in any way after creation.
1398:                 *
1399:                 * @param c collection to store data in
1400:                 */
1401:                protected Array(Collection<Node> c) {
1402:                    this ();
1403:                    nodes = c;
1404:                }
1405:
1406:                /** Constructs a new array children without any assigned collection.
1407:                 * The collection will be created by a call to method initCollection the
1408:                 * first time, children will be used.
1409:                 */
1410:                public Array() {
1411:                    nodesEntry = createNodesEntry();
1412:                    this .setEntries(Collections.singleton(getNodesEntry()));
1413:                }
1414:
1415:                /** Clones all nodes that are contained in the children list.
1416:                 *
1417:                 * @return the cloned array for this children
1418:                 */
1419:                public Object clone() {
1420:                    try {
1421:                        final Children.Array ar = (Array) super .clone();
1422:
1423:                        try {
1424:                            PR.enterReadAccess();
1425:
1426:                            if (nodes != null) {
1427:                                // nodes already initilized
1428:                                // used to create the right type of collection
1429:                                // clears the content of the collection
1430:                                // JST: hack, but I have no better idea how to write this
1431:                                //     pls. notice that in initCollection you can test
1432:                                //     whether nodes == null => real initialization
1433:                                //             nodes != null => only create new empty collection
1434:                                ar.nodes = ar.initCollection();
1435:                                ar.nodes.clear();
1436:
1437:                                // insert copies of the nodes
1438:                                for (Node n : nodes) {
1439:                                    ar.nodes.add(n.cloneNode());
1440:                                }
1441:                            }
1442:                        } finally {
1443:                            PR.exitReadAccess();
1444:                        }
1445:
1446:                        return ar;
1447:                    } catch (CloneNotSupportedException e) {
1448:                        // this cannot happen
1449:                        throw new InternalError();
1450:                    }
1451:                }
1452:
1453:                /** Allow subclasses to create a collection, the first time the
1454:                 * children are used. It is called only if the collection has not
1455:                 * been passed in the constructor.
1456:                 * <P>
1457:                 * The current implementation returns ArrayList.
1458:                 *
1459:                 * @return empty or initialized collection to use
1460:                 */
1461:                protected Collection<Node> initCollection() {
1462:                    return new ArrayList<Node>();
1463:                }
1464:
1465:                /** This method can be called by subclasses that
1466:                 * directly modify the nodes collection to update the
1467:                 * state of the nodes appropriatelly.
1468:                 * This method should be called under
1469:                 * MUTEX.writeAccess.
1470:                 */
1471:                final void refreshImpl() {
1472:                    if (isInitialized()) {
1473:                        Array.this .refreshEntry(getNodesEntry());
1474:                        super .getArray(null).nodes();
1475:                    } else if (nodes != null) {
1476:                        for (Node n : nodes) {
1477:                            n.assignTo(this , -1);
1478:                        }
1479:                    }
1480:                }
1481:
1482:                /** This method can be called by subclasses that
1483:                 * directly modify the nodes collection to update the
1484:                 * state of the nodes appropriatelly.
1485:                 */
1486:                protected final void refresh() {
1487:                    MUTEX.postWriteRequest(new Runnable() {
1488:                        public void run() {
1489:                            refreshImpl();
1490:                        }
1491:                    });
1492:                }
1493:
1494:                /** Getter for the entry.
1495:                 */
1496:                final Entry getNodesEntry() {
1497:                    return nodesEntry;
1498:                }
1499:
1500:                /** This method allows subclasses (only in this package) to
1501:                 * provide own version of entry. Usefull for SortedArray.
1502:                 */
1503:                Entry createNodesEntry() {
1504:                    return new AE();
1505:                }
1506:
1507:                /** Getter for nodes.
1508:                 */
1509:                final Collection<Node> getCollection() {
1510:                    synchronized (getNodesEntry()) {
1511:                        if (nodes == null) {
1512:                            nodes = initCollection();
1513:                        }
1514:                    }
1515:
1516:                    return nodes;
1517:                }
1518:
1519:                /*
1520:                 * @param arr nodes to add
1521:                 * @return true if changed false if not
1522:                 */
1523:                public boolean add(final Node[] arr) {
1524:                    synchronized (getNodesEntry()) {
1525:                        if (!getCollection().addAll(Arrays.asList(arr))) {
1526:                            // no change to the collection
1527:                            return false;
1528:                        }
1529:
1530:                        ;
1531:                    }
1532:
1533:                    refresh();
1534:
1535:                    return true;
1536:                }
1537:
1538:                /*
1539:                 * @param arr nodes to remove
1540:                 * @return true if changed false if not
1541:                 */
1542:                public boolean remove(final Node[] arr) {
1543:                    synchronized (getNodesEntry()) {
1544:                        if (!getCollection().removeAll(Arrays.asList(arr))) {
1545:                            // the collection was not changed
1546:                            return false;
1547:                        }
1548:                    }
1549:
1550:                    refresh();
1551:
1552:                    return true;
1553:                }
1554:
1555:                /** One entry that holds all the nodes in the collection
1556:                 * member called nodes.
1557:                 */
1558:                private final class AE extends Object implements  Entry {
1559:                    AE() {
1560:                    }
1561:
1562:                    /** List of elements.
1563:                     */
1564:                    public Collection<Node> nodes() {
1565:                        Collection<Node> c = getCollection();
1566:
1567:                        if (c.isEmpty()) {
1568:                            return Collections.emptyList();
1569:                        } else {
1570:                            return new ArrayList<Node>(c);
1571:                        }
1572:                    }
1573:
1574:                    @Override
1575:                    public String toString() {
1576:                        return "Children.Array.AE" + getCollection(); // NOI18N
1577:                    }
1578:
1579:                }
1580:            }
1581:
1582:            /** Implements the storage of node children by a map.
1583:             * This class also permits
1584:             * association of a key with any node and to remove nodes by key.
1585:             * Subclasses should reasonably
1586:             * implement {@link #add} and {@link #remove}.
1587:             * @param T the key type
1588:             */
1589:            public static class Map<T> extends Children {
1590:                /** A map to use to store children in.
1591:                 * Keys are <code>Object</code>s, values are {@link Node}s.
1592:                 * Do <em>not</em> modify elements in the map! Use it only for read access.
1593:                 */
1594:                protected java.util.Map<T, Node> nodes;
1595:
1596:                /** Constructs a new list with a supplied map object.
1597:                 * Should be used by subclasses desiring an alternate storage method.
1598:                 * The map must not be explicitly modified after creation.
1599:                 *
1600:                 * @param m the map to use for this list
1601:                 */
1602:                protected Map(java.util.Map<T, Node> m) {
1603:                    nodes = m;
1604:                }
1605:
1606:                /** Constructs a new list using {@link HashMap}.
1607:                 */
1608:                public Map() {
1609:                }
1610:
1611:                /** Getter for the map.
1612:                 * Ensures that the map has been initialized.
1613:                 */
1614:                final java.util.Map<T, Node> getMap() {
1615:                    // package private only to simplify access from inner classes
1616:                    if (nodes == null) {
1617:                        nodes = initMap();
1618:                    }
1619:
1620:                    return nodes;
1621:                }
1622:
1623:                /** Called on first use.
1624:                 */
1625:                final void callAddNotify() {
1626:                    this .setEntries(createEntries(getMap()));
1627:
1628:                    super .callAddNotify();
1629:                }
1630:
1631:                /** Method that allows subclasses (SortedMap) to redefine
1632:                 * order of entries.
1633:                 * @param map the map (Object, Node)
1634:                 * @return collection of (Entry)
1635:                 */
1636:                Collection<? extends Entry> createEntries(
1637:                        java.util.Map<T, Node> map) {
1638:                    List<ME> l = new LinkedList<ME>();
1639:                    for (java.util.Map.Entry<T, Node> e : map.entrySet()) {
1640:                        l.add(new ME(e.getKey(), e.getValue()));
1641:                    }
1642:                    return l;
1643:                }
1644:
1645:                /** Allows subclasses that directly modifies the
1646:                 * map with nodes to synchronize the state of the children.
1647:                 * This method should be called under
1648:                 * MUTEX.writeAccess.
1649:                 */
1650:                final void refreshImpl() {
1651:                    this .setEntries(createEntries(getMap()));
1652:                }
1653:
1654:                /** Allows subclasses that directly modifies the
1655:                 * map with nodes to synchronize the state of the children.
1656:                 */
1657:                protected final void refresh() {
1658:                    try {
1659:                        PR.enterWriteAccess();
1660:                        refreshImpl();
1661:                    } finally {
1662:                        PR.exitWriteAccess();
1663:                    }
1664:                }
1665:
1666:                /** Allows subclasses that directly modifies the
1667:                 * map with nodes to synchronize the state of the children.
1668:                 * This method should be called under
1669:                 * MUTEX.writeAccess.
1670:                 *
1671:                 * @param key the key that should be refreshed
1672:                 */
1673:                final void refreshKeyImpl(T key) {
1674:                    this .refreshEntry(new ME(key, null));
1675:                }
1676:
1677:                /** Allows subclasses that directly modifies the
1678:                 * map with nodes to synchronize the state of the children.
1679:                 *
1680:                 * @param key the key that should be refreshed
1681:                 */
1682:                protected final void refreshKey(final T key) {
1683:                    try {
1684:                        PR.enterWriteAccess();
1685:                        refreshKeyImpl(key);
1686:                    } finally {
1687:                        PR.exitWriteAccess();
1688:                    }
1689:                }
1690:
1691:                /** Add a collection of new key/value pairs into the map.
1692:                 * The supplied map may contain any keys, but the values must be {@link Node}s.
1693:                 *
1694:                 * @param map the map with pairs to add
1695:                 */
1696:                protected final void putAll(
1697:                        final java.util.Map<? extends T, ? extends Node> map) {
1698:                    try {
1699:                        PR.enterWriteAccess();
1700:                        nodes.putAll(map);
1701:                        refreshImpl();
1702:
1703:                        // PENDING sometime we should also call refreshKey...
1704:                    } finally {
1705:                        PR.exitWriteAccess();
1706:                    }
1707:                }
1708:
1709:                /** Add one key and one node to the list.
1710:                 * @param key the key
1711:                 * @param node the node
1712:                 */
1713:                protected final void put(final T key, final Node node) {
1714:                    try {
1715:                        PR.enterWriteAccess();
1716:
1717:                        if (nodes.put(key, node) != null) {
1718:                            refreshKeyImpl(key);
1719:                        } else {
1720:                            refreshImpl();
1721:                        }
1722:                    } finally {
1723:                        PR.exitWriteAccess();
1724:                    }
1725:                }
1726:
1727:                /** Remove some children from the list by key.
1728:                 * @param keys collection of keys to remove
1729:                 */
1730:                protected final void removeAll(
1731:                        final Collection<? extends T> keys) {
1732:                    try {
1733:                        PR.enterWriteAccess();
1734:                        nodes.keySet().removeAll(keys);
1735:                        refreshImpl();
1736:                    } finally {
1737:                        PR.exitWriteAccess();
1738:                    }
1739:                }
1740:
1741:                /** Remove a given child node from the list by its key.
1742:                 * @param key key to remove
1743:                 */
1744:                protected void remove(final T key) {
1745:                    try {
1746:                        PR.enterWriteAccess();
1747:
1748:                        if (nodes.remove(key) != null) {
1749:                            refreshImpl();
1750:                        }
1751:                    } finally {
1752:                        PR.exitWriteAccess();
1753:                    }
1754:                }
1755:
1756:                /** Initialize some nodes. Allows a subclass to
1757:                 * provide a default map to initialize the map with.
1758:                 * Called only if the map has not been provided in the constructor.
1759:                 *
1760:                 * <P>
1761:                 * The default implementation returns <code>new HashMap (7)</code>.
1762:                 *
1763:                 * @return a map from keys to nodes
1764:                 */
1765:                protected java.util.Map<T, Node> initMap() {
1766:                    return new HashMap<T, Node>(7);
1767:                }
1768:
1769:                /** Does nothing. Should be reimplemented in a subclass wishing
1770:                 * to support external addition of nodes.
1771:                 *
1772:                 * @param arr nodes to add
1773:                 * @return <code>false</code> in the default implementation
1774:                 */
1775:                public boolean add(Node[] arr) {
1776:                    return false;
1777:                }
1778:
1779:                /** Does nothing. Should be reimplemented in a subclass wishing
1780:                 * to support external removal of nodes.
1781:                 * @param arr nodes to remove
1782:                 * @return <code>false</code> in the default implementation
1783:                 */
1784:                public boolean remove(Node[] arr) {
1785:                    return false;
1786:                }
1787:
1788:                /** Entry mapping one key to the node.
1789:                 */
1790:                final static class ME extends Object implements  Entry {
1791:                    /** key */
1792:                    public Object key;
1793:
1794:                    /** node set */
1795:                    public Node node;
1796:
1797:                    /** Constructor.
1798:                     */
1799:                    public ME(Object key, Node node) {
1800:                        this .key = key;
1801:                        this .node = node;
1802:                    }
1803:
1804:                    /** Nodes */
1805:                    public Collection<Node> nodes() {
1806:                        return Collections.singleton(node);
1807:                    }
1808:
1809:                    /** Hash code.
1810:                     */
1811:                    public int hashCode() {
1812:                        return key.hashCode();
1813:                    }
1814:
1815:                    /** Equals.
1816:                     */
1817:                    public boolean equals(Object o) {
1818:                        if (o instanceof  ME) {
1819:                            ME me = (ME) o;
1820:
1821:                            return key.equals(me.key);
1822:                        }
1823:
1824:                        return false;
1825:                    }
1826:
1827:                    public String toString() {
1828:                        return "Key (" + key + ")"; // NOI18N
1829:                    }
1830:                }
1831:            }
1832:
1833:            /** Maintains a list of children sorted by the provided comparator in an array.
1834:             * The comparator can change during the lifetime of the children, in which case
1835:             * the children are resorted.
1836:             */
1837:            public static class SortedArray extends Children.Array {
1838:                /** comparator to use */
1839:                private Comparator<? super  Node> comp;
1840:
1841:                /** Create an empty list of children. */
1842:                public SortedArray() {
1843:                }
1844:
1845:                /** Create an empty list with a specified storage method.
1846:                 *
1847:                 * @param c collection to store data in
1848:                 * @see Children.Array#Children.Array(Collection)
1849:                 */
1850:                protected SortedArray(Collection<Node> c) {
1851:                    super (c);
1852:                }
1853:
1854:                /** Set the comparator. The children will be resorted.
1855:                 * The comparator is used to compare Nodes, if no
1856:                 * comparator is used then nodes will be compared by
1857:                 * the use of natural ordering.
1858:                 *
1859:                 * @param c the new comparator
1860:                 */
1861:                public void setComparator(final Comparator<? super  Node> c) {
1862:                    try {
1863:                        PR.enterWriteAccess();
1864:                        comp = c;
1865:                        refresh();
1866:                    } finally {
1867:                        PR.exitWriteAccess();
1868:                    }
1869:                }
1870:
1871:                /** Get the current comparator.
1872:                 * @return the comparator
1873:                 */
1874:                public Comparator<? super  Node> getComparator() {
1875:                    return comp;
1876:                }
1877:
1878:                /** This method allows subclasses (only in this package) to
1879:                 * provide own version of entry. Useful for SortedArray.
1880:                 */
1881:                Entry createNodesEntry() {
1882:                    return new SAE();
1883:                }
1884:
1885:                /** One entry that holds all the nodes in the collection
1886:                 * member called nodes.
1887:                 */
1888:                private final class SAE extends Object implements  Entry {
1889:                    /** Constructor that provides the original comparator.
1890:                     */
1891:                    public SAE() {
1892:                    }
1893:
1894:                    /** List of elements.
1895:                     */
1896:                    public Collection<Node> nodes() {
1897:                        List<Node> al = new ArrayList<Node>(getCollection());
1898:                        Collections.sort(al, comp);
1899:
1900:                        return al;
1901:                    }
1902:                }
1903:            }
1904:
1905:            // end of SortedArray
1906:
1907:            /** Maintains a list of children sorted by the provided comparator in a map.
1908:             * Similar to {@link Children.SortedArray}.
1909:             */
1910:            public static class SortedMap<T> extends Children.Map<T> {
1911:                /** comparator to use */
1912:                private Comparator<? super  Node> comp;
1913:
1914:                /** Create an empty list. */
1915:                public SortedMap() {
1916:                }
1917:
1918:                /** Create an empty list with a specific storage method.
1919:                 *
1920:                 * @param map the map to use with this object
1921:                 * @see Children.Map#Children.Map(java.util.Map)
1922:                 */
1923:                protected SortedMap(java.util.Map<T, Node> map) {
1924:                    super (map);
1925:                }
1926:
1927:                /** Set the comparator. The children will be resorted.
1928:                 * The comparator is used to compare Nodes, if no
1929:                 * comparator is used then values will be compared by
1930:                 * the use of natural ordering.
1931:                 *
1932:                 * @param c the new comparator that should compare nodes
1933:                 */
1934:                public void setComparator(final Comparator<? super  Node> c) {
1935:                    try {
1936:                        PR.enterWriteAccess();
1937:                        comp = c;
1938:                        refresh();
1939:                    } finally {
1940:                        PR.exitWriteAccess();
1941:                    }
1942:                }
1943:
1944:                /** Get the current comparator.
1945:                 * @return the comparator
1946:                 */
1947:                public Comparator<? super  Node> getComparator() {
1948:                    return comp;
1949:                }
1950:
1951:                /** Method that allows subclasses (SortedMap) to redefine
1952:                 * order of entries.
1953:                 * @param map the map (Object, Node)
1954:                 * @return collection of (Entry)
1955:                 */
1956:                Collection<? extends Entry> createEntries(
1957:                        java.util.Map<T, Node> map) {
1958:                    // SME objects use natural ordering
1959:                    Set<ME> l = new TreeSet<ME>(new SMComparator());
1960:
1961:                    for (java.util.Map.Entry<T, Node> e : map.entrySet()) {
1962:                        l.add(new ME(e.getKey(), e.getValue()));
1963:                    }
1964:
1965:                    return l;
1966:                }
1967:
1968:                /** Sorted map entry can be used for comparing.
1969:                 */
1970:                final class SMComparator implements  Comparator<ME> {
1971:                    public int compare(ME me1, ME me2) {
1972:                        Comparator<? super  Node> c = comp;
1973:
1974:                        if (c == null) {
1975:                            // compare keys
1976:                            @SuppressWarnings("unchecked")
1977:                            // we just assume that it is comparable, not statically checked
1978:                            int r = ((Comparable) me1.key).compareTo(me2.key);
1979:                            return r;
1980:                        } else {
1981:                            return c.compare(me1.node, me2.node);
1982:                        }
1983:                    }
1984:                }
1985:            }
1986:
1987:            // end of SortedMap
1988:
1989:            /** Implements an array of child nodes associated nonuniquely with keys and sorted by these keys.
1990:             * There is a {@link #createNodes(Object) method} that should for each
1991:             * key create an array of nodes that represents the key.
1992:             *
1993:             * <p>This class is preferable to {@link Children.Array} because
1994:             * <ol>
1995:             * <li>It more clearly separates model from view and encourages use of a discrete model.
1996:             * <li>It correctly handles adding, removing, and reordering children while preserving
1997:             *     existing node selections in a tree (or other) view where possible.
1998:             * </ol>
1999:             *
2000:             * <p>Typical usage:
2001:             * <ol>
2002:             * <li>Subclass.
2003:             * <li>Decide what type your key should be.
2004:             * <li>Implement {@link #createNodes} to create some nodes
2005:             * (usually exactly one) per key.
2006:             * <li>Override {@link Children#addNotify} to compute a set of keys
2007:             * and set it using {@link #setKeys(Collection)}.
2008:             * The collection may be ordered.
2009:             * <li>Override {@link Children#removeNotify} to just call
2010:             * <code>setKeys</code> on {@link Collections#EMPTY_SET}.
2011:             * <li>When your model changes, call <code>setKeys</code>
2012:             * with the new set of keys. <code>Children.Keys</code> will
2013:             * be smart and calculate exactly what it needs to do effficiently.
2014:             * <li><i>(Optional)</i> if your notion of what the node for a
2015:             * given key changes (but the key stays the same), you can
2016:             * call {@link #refreshKey}. Usually this is not necessary.
2017:             * </ol>
2018:             * Note that for simple cases, it may be preferable to subclass
2019:             * <a href="ChildFactory.html">ChildFactory</a> and pass the result to
2020:             * <a href="Children.html#create(org.openide.nodes.ChildFactory, boolean)">
2021:             * create()</a>; doing so makes it easy to switch to using child
2022:             * nodes computed on a background thread if necessary for performance
2023:             * reasons.
2024:             * @param T the type of the key
2025:             */
2026:            public static abstract class Keys<T> extends Children.Array {
2027:                /** the last runnable (created in method setKeys) for each children object.
2028:                 */
2029:                private static java.util.Map<Keys<?>, Runnable> lastRuns = new HashMap<Keys<?>, Runnable>(
2030:                        11);
2031:
2032:                /** add array children before or after keys ones */
2033:                private boolean before;
2034:
2035:                public Keys() {
2036:                    super ();
2037:                }
2038:
2039:                /** Special handling for clonning.
2040:                 */
2041:                public Object clone() {
2042:                    Keys<?> k = (Keys<?>) super .clone();
2043:
2044:                    return k;
2045:                }
2046:
2047:                /**
2048:                 * @deprecated Do not use! Just call {@link #setKeys(Collection)} with a larger set.
2049:                 */
2050:                @Deprecated
2051:                public boolean add(Node[] arr) {
2052:                    return super .add(arr);
2053:                }
2054:
2055:                /**
2056:                 * @deprecated Do not use! Just call {@link #setKeys(Collection)} with a smaller set.
2057:                 */
2058:                @Deprecated
2059:                public boolean remove(final Node[] arr) {
2060:                    try {
2061:                        PR.enterWriteAccess();
2062:
2063:                        if (nodes != null) {
2064:                            // removing from array, just if the array nodes are 
2065:                            // really created
2066:                            // expecting arr.length == 1, which is the usual case
2067:                            for (int i = 0; i < arr.length; i++) {
2068:                                if (!nodes.contains(arr[i])) {
2069:                                    arr[i] = null;
2070:                                }
2071:                            }
2072:
2073:                            super .remove(arr);
2074:                        }
2075:                    } finally {
2076:                        PR.exitWriteAccess();
2077:                    }
2078:
2079:                    return true;
2080:                }
2081:
2082:                /** Refresh the child nodes for a given key.
2083:                 *
2084:                 * @param key the key to refresh
2085:                 */
2086:                protected final void refreshKey(final T key) {
2087:                    MUTEX.postWriteRequest(new Runnable() {
2088:                        public void run() {
2089:                            Keys.this .refreshEntry(new KE(key));
2090:                        }
2091:                    });
2092:                }
2093:
2094:                /** Set new keys for this children object. Setting of keys
2095:                 * does not necessarily lead to the creation of nodes. It happens only
2096:                 * when the list has already been initialized.
2097:                 *
2098:                 * @param keysSet the keys for the nodes (collection of any objects)
2099:                 */
2100:                protected final void setKeys(Collection<? extends T> keysSet) {
2101:                    boolean asserts = false;
2102:                    assert asserts = true;
2103:                    int sz = keysSet.size();
2104:                    if (asserts && sz < 10) {
2105:                        List<? extends T> keys = new ArrayList<T>(keysSet);
2106:                        for (int i = 0; i < sz - 1; i++) {
2107:                            T a = keys.get(i);
2108:                            for (int j = i + 1; j < sz; j++) {
2109:                                T b = keys.get(j);
2110:                                assert !(a.equals(b) && a.hashCode() != b
2111:                                        .hashCode()) : "bad equals/hashCode in "
2112:                                        + a + " vs. " + b;
2113:                            }
2114:                        }
2115:                    }
2116:
2117:                    final List<Entry> l = new ArrayList<Entry>(
2118:                            keysSet.size() + 1);
2119:
2120:                    if (before) {
2121:                        l.add(getNodesEntry());
2122:                    }
2123:
2124:                    KE updator = new KE();
2125:                    updator.updateList(keysSet, l);
2126:
2127:                    if (!before) {
2128:                        l.add(getNodesEntry());
2129:                    }
2130:
2131:                    applyKeys(l);
2132:                }
2133:
2134:                /** Set keys for this list.
2135:                 *
2136:                 * @param keys the keys for the nodes
2137:                 * @see #setKeys(Collection)
2138:                 */
2139:                protected final void setKeys(final T[] keys) {
2140:                    boolean asserts = false;
2141:                    assert asserts = true;
2142:                    int sz = keys.length;
2143:                    if (asserts && sz < 10) {
2144:                        for (int i = 0; i < sz - 1; i++) {
2145:                            T a = keys[i];
2146:                            for (int j = i + 1; j < sz; j++) {
2147:                                T b = keys[j];
2148:                                assert !(a.equals(b) && a.hashCode() != b
2149:                                        .hashCode()) : "bad equals/hashCode in "
2150:                                        + a + " vs. " + b;
2151:                            }
2152:                        }
2153:                    }
2154:
2155:                    final List<Entry> l = new ArrayList<Entry>(keys.length + 1);
2156:
2157:                    KE updator = new KE();
2158:
2159:                    if (before) {
2160:                        l.add(getNodesEntry());
2161:                    }
2162:
2163:                    updator.updateList(keys, l);
2164:
2165:                    if (!before) {
2166:                        l.add(getNodesEntry());
2167:                    }
2168:
2169:                    applyKeys(l);
2170:                }
2171:
2172:                /** Applies the keys.
2173:                 */
2174:                private void applyKeys(final List<? extends Entry> l) {
2175:                    Runnable invoke = new Runnable() {
2176:                        public void run() {
2177:                            if (keysCheck(Keys.this , this )) {
2178:                                // no next request after me
2179:                                Keys.this .setEntries(l);
2180:
2181:                                // clear this runnable
2182:                                keysExit(Keys.this , this );
2183:                            }
2184:                        }
2185:                    };
2186:
2187:                    keysEnter(this , invoke);
2188:                    MUTEX.postWriteRequest(invoke);
2189:                }
2190:
2191:                /** Set whether new nodes should be added to the beginning or end of sublists for a given key.
2192:                 * Generally should not be used.
2193:                 * @param b <code>true</code> if the children should be added before
2194:                 */
2195:                protected final void setBefore(final boolean b) {
2196:                    try {
2197:                        PR.enterWriteAccess();
2198:
2199:                        if (before != b) {
2200:                            List<Entry> l = Keys.this .getEntries();
2201:                            l.remove(getNodesEntry());
2202:                            before = b;
2203:
2204:                            if (b) {
2205:                                l.add(0, getNodesEntry());
2206:                            } else {
2207:                                l.add(getNodesEntry());
2208:                            }
2209:
2210:                            Keys.this .setEntries(l);
2211:                        }
2212:                    } finally {
2213:                        PR.exitWriteAccess();
2214:                    }
2215:                }
2216:
2217:                /** Create nodes for a given key.
2218:                 * @param key the key
2219:                 * @return child nodes for this key or null if there should be no
2220:                 *    nodes for this key
2221:                 */
2222:                protected abstract Node[] createNodes(T key);
2223:
2224:                /** Called when the nodes have been removed from the children.
2225:                 * This method should allow subclasses to clean the nodes somehow.
2226:                 * <p>
2227:                 * Current implementation notifies all listeners on the nodes
2228:                 * that nodes have been deleted.
2229:                 *
2230:                 * @param arr array of deleted nodes
2231:                 */
2232:                protected void destroyNodes(Node[] arr) {
2233:                    for (int i = 0; i < arr.length; i++) {
2234:                        arr[i].fireNodeDestroyed();
2235:                    }
2236:                }
2237:
2238:                /** Notifies the children class that nodes has been released.
2239:                 */
2240:                Node[] notifyRemove(Collection<Node> nodes, Node[] current) {
2241:                    Node[] arr = super .notifyRemove(nodes, current);
2242:                    destroyNodes(arr);
2243:
2244:                    return arr;
2245:                }
2246:
2247:                /** Enter of setKeys.
2248:                 * @param ch the children
2249:                 * @param run runnable
2250:                 */
2251:                private static synchronized void keysEnter(Keys<?> ch,
2252:                        Runnable run) {
2253:                    lastRuns.put(ch, run);
2254:                }
2255:
2256:                /** Clears the entry for the children
2257:                 * @param ch children
2258:                 */
2259:                private static synchronized void keysExit(Keys ch, Runnable r) {
2260:                    Runnable reg = lastRuns.remove(ch);
2261:
2262:                    if ((reg != null) && !reg.equals(r)) {
2263:                        lastRuns.put(ch, reg);
2264:                    }
2265:                }
2266:
2267:                /** Check whether the runnable is "the current" for given children.
2268:                 * @param ch children
2269:                 * @param run runnable
2270:                 * @return true if the runnable shoul run
2271:                 */
2272:                private static synchronized boolean keysCheck(Keys ch,
2273:                        Runnable run) {
2274:                    return run == lastRuns.get(ch);
2275:                }
2276:
2277:                /** Entry for a key
2278:                 */
2279:                private final class KE extends Dupl<T> {
2280:                    /** Has default constructor that allows to create a factory
2281:                     * of KE objects for use with updateList
2282:                     */
2283:                    public KE() {
2284:                    }
2285:
2286:                    /** Creates directly an instance of the KE object.
2287:                     */
2288:                    public KE(T key) {
2289:                        this .key = key;
2290:                    }
2291:
2292:                    /** Nodes are taken from the create nodes.
2293:                     */
2294:                    public Collection<Node> nodes() {
2295:                        Node[] arr = createNodes(getKey());
2296:
2297:                        if (arr == null) {
2298:                            return Collections.emptyList();
2299:                        } else {
2300:                            return new LinkedList<Node>(Arrays.asList(arr));
2301:                        }
2302:                    }
2303:
2304:                    @Override
2305:                    public String toString() {
2306:                        String s = getKey().toString();
2307:                        if (s.length() > 80) {
2308:                            s = s.substring(0, 80);
2309:                        }
2310:                        return "Children.Keys.KE[" + s + "," + getCnt() + "]"; // NOI18N
2311:                    }
2312:                }
2313:            }
2314:
2315:            // end of Keys
2316:
2317:            /** Supporting class that provides support for duplicated
2318:             * objects that still should not be equal.
2319:             * <P>
2320:             * It counts the number of times an object has been
2321:             * added to the collection and if the same object is added
2322:             * more than once it is indexed by a number.
2323:             */
2324:            private static abstract class Dupl<T> implements  Cloneable, Entry {
2325:                /** the key either real value or Dupl (Dupl (Dupl (... value ...)))*/
2326:                protected Object key;
2327:
2328:                Dupl() {
2329:                }
2330:
2331:                /** Updates the second collection with values from the first one.
2332:                 * If there is a multiple occurrence of an object in the first collection
2333:                 * a Dupl for the object is created to encapsulate it.
2334:                 */
2335:                public final void updateList(Collection<? extends T> src,
2336:                        Collection<? super  Dupl<T>> target) {
2337:                    java.util.Map<T, Object> map = new HashMap<T, Object>(src
2338:                            .size() * 2);
2339:                    for (T o : src) {
2340:                        updateListAndMap(o, target, map);
2341:                    }
2342:                }
2343:
2344:                /** Updates the second collection with values from the first array.
2345:                 * If there is a multiple occurrence of an object in the first array
2346:                 * a Dupl for the object is created to encapsulate it.
2347:                 */
2348:                public final void updateList(T[] arr,
2349:                        Collection<? super  Dupl<T>> target) {
2350:                    java.util.Map<T, Object> map = new HashMap<T, Object>(
2351:                            arr.length * 2);
2352:                    for (T o : arr) {
2353:                        updateListAndMap(o, target, map);
2354:                    }
2355:                }
2356:
2357:                /** Updates the linked list and the map with right
2358:                 * values. The map is used to count the number of times
2359:                 * a element occurs in the list.
2360:                 *
2361:                 * @param obj object to add
2362:                 * @param list the list to add obj to
2363:                 * @param map to track number of occurrences in the array
2364:                 */
2365:                public final void updateListAndMap(T obj,
2366:                        Collection<? super  Dupl<T>> list,
2367:                        java.util.Map<T, Object> map) {
2368:                    // optimized for first occurrence
2369:                    // of each object because often occurrences should be rare
2370:                    Object prev = map.put(obj, this );
2371:
2372:                    if (prev == null) {
2373:                        // first occurrence of object obj
2374:                        list.add(createInstance(obj, 0));
2375:
2376:                        return;
2377:                    } else {
2378:                        if (prev == this ) {
2379:                            // second occurrence of the object
2380:                            map.put(obj, 1);
2381:                            list.add(createInstance(obj, 1));
2382:
2383:                            return;
2384:                        } else {
2385:                            int cnt = ((Integer) prev) + 1;
2386:                            map.put(obj, cnt);
2387:                            list.add(createInstance(obj, cnt));
2388:
2389:                            return;
2390:                        }
2391:                    }
2392:                }
2393:
2394:                /** Gets the key represented by this object.
2395:                 * @return the key
2396:                 */
2397:                @SuppressWarnings("unchecked")
2398:                // data structure really weird
2399:                public final T getKey() {
2400:                    if (key instanceof  Dupl) {
2401:                        return (T) ((Dupl) key).getKey();
2402:                    } else {
2403:                        return (T) key;
2404:                    }
2405:                }
2406:
2407:                /** Counts the index of this key.
2408:                 * @return integer
2409:                 */
2410:                public final int getCnt() {
2411:                    int cnt = 0;
2412:                    Dupl d = this ;
2413:
2414:                    while (d.key instanceof  Dupl) {
2415:                        d = (Dupl) d.key;
2416:                        cnt++;
2417:                    }
2418:
2419:                    return cnt;
2420:                }
2421:
2422:                /** Create instance of Dupl (uses cloning of the class)
2423:                 */
2424:                @SuppressWarnings("unchecked")
2425:                // data structure really weird
2426:                private final Dupl<T> createInstance(Object obj, int cnt) {
2427:                    try {
2428:                        // creates the chain of Dupl (Dupl (Dupl (obj))) where
2429:                        // for cnt = 0 the it would look like Dupl (obj)
2430:                        // for cnt = 1 like Dupl (Dupl (obj))
2431:                        Dupl d = (Dupl) this .clone();
2432:                        Dupl first = d;
2433:
2434:                        while (cnt-- > 0) {
2435:                            Dupl n = (Dupl) this .clone();
2436:                            d.key = n;
2437:                            d = n;
2438:                        }
2439:
2440:                        d.key = obj;
2441:
2442:                        return first;
2443:                    } catch (CloneNotSupportedException ex) {
2444:                        throw new InternalError();
2445:                    }
2446:                }
2447:
2448:                @Override
2449:                public int hashCode() {
2450:                    return getKey().hashCode();
2451:                }
2452:
2453:                @Override
2454:                public boolean equals(Object o) {
2455:                    if (o instanceof  Dupl) {
2456:                        Dupl d = (Dupl) o;
2457:
2458:                        return getKey().equals(d.getKey())
2459:                                && (getCnt() == d.getCnt());
2460:                    }
2461:
2462:                    return false;
2463:                }
2464:            }
2465:
2466:            /*
2467:              static void printNodes (Node[] n) {
2468:                for (int i = 0; i < n.length; i++) {
2469:                  System.out.println ("  " + i + ". " + n[i].getName () + " number: " + System.identityHashCode (n[i]));
2470:                }
2471:                }
2472:             */
2473:            /* JST: Useful test routine ;-) *
2474:            static {
2475:              final TopComponent.Registry r = TopComponent.getRegistry ();
2476:              r.addPropertyChangeListener (new PropertyChangeListener () {
2477:                Node last = new AbstractNode (LEAF);
2478:
2479:                public void propertyChange (PropertyChangeEvent ev) {
2480:                  Node[] arr = r.getCurrentNodes ();
2481:                  if (arr != null && arr.length == 1) {
2482:                    last = arr[0];
2483:                  }
2484:                  System.out.println (
2485:                    "Activated node: " + last + " \nparent: " + last.getParentNode ()
2486:                  );
2487:                }
2488:              });
2489:            }
2490:             */
2491:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.