This Bugzilla instance is a read-only archive of historic NetBeans bug reports. To report a bug in NetBeans please follow the project's instructions for reporting issues.

View | Details | Raw Unified | Return to bug 91529
Collapse All | Expand All

(-)openide/nodes/src/org/openide/nodes/AsynchChildren.java (+162 lines)
Added Link Here
1
/*
2
 * The contents of this file are subject to the terms of the Common Development
3
 * and Distribution License (the License). You may not use this file except in
4
 * compliance with the License.
5
 *
6
 * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7
 * or http://www.netbeans.org/cddl.txt.
8
 *
9
 * When distributing Covered Code, include this CDDL Header Notice in each file
10
 * and include the License file at http://www.netbeans.org/cddl.txt.
11
 * If applicable, add the following below the CDDL Header, with the fields
12
 * enclosed by brackets [] replaced by your own identifying information:
13
 * "Portions Copyrighted [year] [name of copyright owner]"
14
 *
15
 * The Original Software is NetBeans. The Initial Developer of the Original
16
 * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17
 * Microsystems, Inc. All Rights Reserved.
18
 */
19
package org.openide.nodes;
20
21
import java.awt.Image;
22
import java.lang.Thread;
23
import java.util.Collections;
24
import java.util.List;
25
import org.openide.util.NbBundle;
26
import org.openide.util.RequestProcessor;
27
import org.openide.util.Utilities;
28
29
/**
30
 * Children object which creates its keys on a background thread.  To use,
31
 * implement AsynchChildren.Provider and pass that to the constructor.
32
 *
33
 * @author Tim Boudreau
34
 */
35
public final class AsynchChildren extends Children.Keys <Object> {
36
    private final Provider provider;
37
    private final RequestProcessor.Task task;
38
    private static final RequestProcessor PROC = new RequestProcessor("Asynch " //NOI18N
39
             + "children creator", Thread.NORM_PRIORITY, true); //NOI18N
40
    private final R r = new R();
41
    /**
42
     * Create a new AsyncChildren instance with the passed provider object
43
     * which will manufacture key objects and nodes.
44
     * @param provider An object which can provide a list of keys and make
45
     *        Nodes for them
46
     */ 
47
    public AsynchChildren(Provider provider) {
48
        this.provider = provider;
49
        task = PROC.create(r, true);
50
    }
51
    
52
    protected void addNotify() {
53
        if (task.isFinished() || r.cancelled) {
54
            r.cancelled = false;
55
            setKeys (new Object[] { new WaitNode() });
56
            task.schedule(0);
57
        }
58
    }
59
    
60
    @SuppressWarnings("unchecked")    
61
    protected void removeNotify() {
62
        r.cancelled = true;
63
        task.cancel();
64
        setKeys (Collections.EMPTY_LIST);
65
    }
66
    
67
    /**
68
     * Notify this AsynchChildren that it should reconstruct its children,
69
     * calling <code>provider.asynchCreateKeys()</code> and setting the
70
     * keys to that.  Call this method if the list of child objects is known
71
     * or likely to have changed.
72
     * @param immediate If true, the keys are updated synchronously from the
73
     *  calling thread.  Set this to true only if you know that updating
74
     *  the keys will <i>not</i> be an expensive or time-consuming operation.
75
     */ 
76
    @SuppressWarnings("unchecked") //NOI18N
77
    public void update(boolean immediate) {
78
        if (immediate) {
79
            setKeys (provider.asynchCreateKeys());
80
        } else {
81
            task.schedule (0);
82
        }
83
    }
84
    
85
    public Node[] getNodes(boolean optimalResult) {
86
        if (optimalResult) {
87
            task.waitFinished();
88
        }
89
        return super.getNodes();
90
    }
91
    
92
    @SuppressWarnings("unchecked")
93
    protected Node[] createNodes(Object key) {
94
        if (key instanceof WaitNode) {
95
            return new Node[] { (Node) key };
96
        } else {
97
            return provider.createNodes (key);
98
        }
99
    }
100
101
    /**
102
     * Factory for keys and child nodes for an instance of AsynchChildren.
103
     */ 
104
    public static interface Provider <T extends Object> {
105
        /**
106
         * Create Nodes for a given key object (one from the <code>List</code>
107
         * returned by asynchCreateKeys()).
108
         * @param key An object from the list returned by 
109
         *        <code>asynchCreateKeys()</code>
110
         * @return zero or more Nodes to represent this key
111
         */
112
        public Node[] createNodes (T key);
113
        /**
114
         * Create a list of keys which can be individually passed to
115
         * createNodes() to create child Nodes.  Implementations of
116
         * this method should regularly check Thread.interrupted(), and
117
         * if it returns true (meaning the parent Node was collapsed or
118
         * destroyed), stop creating keys immediately and return
119
         * null.  This method is guaranteed <i>not</i> to be called on the
120
         * AWT event thread.
121
         * 
122
         * @return A <code>List</code> of objects to use as keys, or null 
123
         *         if cancelled
124
         */ 
125
        public List <T> asynchCreateKeys();
126
    }
127
    
128
    private final class R implements Runnable {
129
        volatile boolean cancelled = false;
130
        
131
        @SuppressWarnings("unchecked")
132
        public void run() {
133
            if (Thread.interrupted()) {
134
                doSetKeys (Collections.EMPTY_LIST);
135
                return;
136
            }
137
            List <Object> keys = provider.asynchCreateKeys();
138
            if (keys == null || Thread.interrupted()) {
139
                keys = Collections.EMPTY_LIST;
140
            }
141
            doSetKeys (keys);
142
        }
143
        
144
        private void doSetKeys (List <Object> keys) {
145
            setKeys (keys);
146
            justComputeNodes();
147
        }
148
    
149
    }
150
    
151
    //We need a type that no Children class will use as a key
152
    private static final class WaitNode extends AbstractNode {
153
        public WaitNode () {
154
            super (Children.LEAF);
155
            setDisplayName (NbBundle.getMessage (WaitNode.class, "LBL_WAIT")); //NOI18N
156
        }
157
        
158
        public Image getIcon (int type) {
159
            return Utilities.loadImage ("org/openide/nodes/wait.gif"); //NOI18N
160
        }
161
    }
162
}
(-)openide/nodes/src/org/openide/nodes/Bundle.properties (+2 lines)
Lines 71-73 Link Here
71
# NodeMimeTypeCut=application/x-java-openide-nodecut;class=org.openide.nodes.NodeTransfer$Cut
71
# NodeMimeTypeCut=application/x-java-openide-nodecut;class=org.openide.nodes.NodeTransfer$Cut
72
# NodeMimeTypeCopy=application/x-java-openide-nodecopy;class=org.openide.nodes.NodeTransfer$Copy
72
# NodeMimeTypeCopy=application/x-java-openide-nodecopy;class=org.openide.nodes.NodeTransfer$Copy
73
# NodeMimeTypePaste=application/x-java-openide-nodepaste;class=org.openide.nodes.NodeTransfer$Paste
73
# NodeMimeTypePaste=application/x-java-openide-nodepaste;class=org.openide.nodes.NodeTransfer$Paste
74
75
LBL_WAIT=Please Wait...
(-)openide/nodes/test/unit/src/org/openide/nodes/AsynchChildrenTest.java (+135 lines)
Added Link Here
1
/*
2
 * The contents of this file are subject to the terms of the Common Development
3
 * and Distribution License (the License). You may not use this file except in
4
 * compliance with the License.
5
 *
6
 * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7
 * or http://www.netbeans.org/cddl.txt.
8
 *
9
 * When distributing Covered Code, include this CDDL Header Notice in each file
10
 * and include the License file at http://www.netbeans.org/cddl.txt.
11
 * If applicable, add the following below the CDDL Header, with the fields
12
 * enclosed by brackets [] replaced by your own identifying information:
13
 * "Portions Copyrighted [year] [name of copyright owner]"
14
 *
15
 * The Original Software is NetBeans. The Initial Developer of the Original
16
 * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17
 * Microsystems, Inc. All Rights Reserved.
18
 */
19
20
package org.openide.nodes;
21
22
import java.awt.EventQueue;
23
import java.beans.*;
24
import java.util.*;
25
import junit.framework.TestCase;
26
import org.openide.nodes.*;
27
import org.openide.util.NbBundle;
28
29
/** Test for AsynchChildren
30
 * 
31
 * @author Tim Boudreau
32
 */
33
public class AsynchChildrenTest extends TestCase {
34
35
    public AsynchChildrenTest(String name) {
36
        super(name);
37
    }
38
    
39
    private ProviderImpl provider;
40
    private AsynchChildren kids;
41
    private Node n;
42
    public void setUp() throws Exception {
43
        provider = new ProviderImpl();
44
        kids = new AsynchChildren (provider);
45
        n = new AbstractNode (kids);
46
    }
47
    
48
    public void testGetNodesWaits() throws Exception {
49
        System.out.println("testGetNodesWaits");
50
        
51
        kids.addNotify();
52
        Node[] n = new Node[0];
53
        for (int i = 0; i < 5 && n.length != 4; i++) {
54
            n = kids.getNodes(true);
55
            java.lang.Thread.currentThread().sleep(400);
56
        }
57
        assertEquals (4, n.length);
58
    }
59
    
60
    public void testInitialNodeIsWaitNode() throws Exception {
61
        System.out.println("testInitialNodeIsWaitNode");
62
        Runnable r = new Runnable() {
63
            public void run() {
64
                provider.wait = true;
65
                kids.addNotify();
66
                Node[] n = kids.getNodes (false);
67
                assertEquals (1, n.length);
68
                assertEquals (NbBundle.getMessage(AsynchChildren.class, "LBL_WAIT"),
69
                        n[0].getDisplayName());
70
                provider.wait = false;
71
                for (int i = 0; i < 5 && n.length != 4; i++) {
72
                    try {
73
                        n = kids.getNodes(true);
74
                        java.lang.Thread.currentThread().sleep(200);
75
                    } catch (InterruptedException ex) {
76
                    }
77
                }
78
                assertTrue (n.length == 4);
79
            }
80
        };
81
        EventQueue.invokeAndWait (r);
82
    }
83
    
84
    public void testCancel() throws Exception {
85
        System.out.println("testCancel");
86
        Runnable r = new Runnable() {
87
            public void run() {
88
                provider.wait = true;
89
                kids.addNotify();
90
                kids.removeNotify();
91
                provider.wait = false;
92
                Node[] n = new Node[0];
93
                for (int i = 0; i < 5 && n.length != 0; i++) {
94
                    try {
95
                        n = kids.getNodes(true);
96
                        java.lang.Thread.currentThread().sleep(200);
97
                    } catch (InterruptedException ex) {
98
                    }
99
                }
100
                assertEquals (0, n.length);            
101
            }
102
        };
103
        EventQueue.invokeAndWait (r);
104
    }
105
        
106
     static final class ProviderImpl implements AsynchChildren.Provider <String> {
107
        
108
        boolean wait = false;
109
        
110
        public Node[] createNodes(String key) {
111
            AbstractNode nd = new AbstractNode (Children.LEAF);
112
            nd.setDisplayName (key);
113
            return new Node[] { nd };
114
        }
115
116
        public List asynchCreateKeys() {
117
            while (wait) {
118
                try {
119
                    Thread.currentThread().sleep (200);
120
                } catch (Exception e) {
121
                    
122
                }
123
            }
124
            if (Thread.interrupted()) {
125
                return null;
126
            }
127
            List <String> result = new ArrayList <String> ();
128
            result.add ("A");
129
            result.add ("B");
130
            result.add ("C");
131
            result.add ("D");
132
            return result;
133
        }
134
    }
135
}

Return to bug 91529