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 38185
Collapse All | Expand All

(-)src/org/openide/explorer/ExplorerUtils.java (-13 / +31 lines)
Lines 36-60 Link Here
36
 * should make your component implement {@link ExplorerManager.Provider} and
36
 * should make your component implement {@link ExplorerManager.Provider} and
37
 * {@link org.openide.util.Lookup.Provider} and register actions in your component's {@link ActionMap}:
37
 * {@link org.openide.util.Lookup.Provider} and register actions in your component's {@link ActionMap}:
38
<pre>
38
<pre>
39
<span class="keyword">public</span> <span class="keyword">class</span> <span class="type">YourComponent</span> <span class="keyword">extends</span> <span class="type">TopComponent</span> <span class="comment">// or JPanel, etc.
39
<span class="keyword">public</span> <span class="keyword">class</span> <span class="type">YourComponent</span> <span class="keyword">extends</span> <span class="type">TopComponent</span>
40
</span>        <span class="keyword">implements</span> <span class="type">ExplorerManager.Provider</span>, <span class="type">Lookup.Provider</span> {
40
<span class="keyword">implements</span> <span class="type">ExplorerManager.Provider</span>, <span class="type">Lookup.Provider</span> {
41
    <span class="keyword">private</span> <span class="type">ExplorerManager</span> <span class="variable-name">manager</span>;
41
    <span class="keyword">private</span> <span class="type">ExplorerManager</span> <span class="variable-name">manager</span>;
42
    <span class="keyword">private</span> <span class="type">Lookup</span> <span class="variable-name">lookup</span>;
43
    <span class="keyword">public</span> <span class="type">YourComponent</span>() {
42
    <span class="keyword">public</span> <span class="type">YourComponent</span>() {
44
        manager = <span class="keyword">new</span> <span class="type">ExplorerManager</span>();
43
        <span class="keyword">this</span> (<span class="keyword">new</span> <span class="type">ExplorerManager</span>(), <span class="keyword">new</span> <span class="type">ActionMap</span>());
45
        <span class="type">ActionMap</span> <span class="variable-name">map</span> = getActionMap();
44
    }
45
    <span class="keyword">private</span> <span class="type">YourComponent</span>(ExplorerManager em, ActionMap map) {
46
        <span class="comment">// following line tells the top component which lookup should be associated with it</span>
47
        <span class="keyword">super </span> (ExplorerUtils.createLookup (em, map));
48
        <span class="keyword">this</span>.manager = em;
46
        map.put(DefaultEditorKit.copyAction, ExplorerUtils.actionCopy(manager));
49
        map.put(DefaultEditorKit.copyAction, ExplorerUtils.actionCopy(manager));
47
        map.put(DefaultEditorKit.cutAction, ExplorerUtils.actionCut(manager));
50
        map.put(DefaultEditorKit.cutAction, ExplorerUtils.actionCut(manager));
48
        map.put(DefaultEditorKit.pasteAction, ExplorerUtils.actionPaste(manager));
51
        map.put(DefaultEditorKit.pasteAction, ExplorerUtils.actionPaste(manager));
49
        map.put(<span class="string">"delete"</span>, ExplorerUtils.actionDelete(manager, <span class="constant">true</span>)); <span class="comment">// or false
52
        map.put(<span class="string">"delete"</span>, ExplorerUtils.actionDelete(manager, <span class="constant">true</span>)); <span class="comment">// or false
50
</span>        lookup = ExplorerUtils.createLookup (manager, map);
53
</span>    }
51
    }
52
    <span class="keyword">public</span> <span class="type">ExplorerManager</span> <span class="function-name">getExplorerManager</span>() {
54
    <span class="keyword">public</span> <span class="type">ExplorerManager</span> <span class="function-name">getExplorerManager</span>() {
53
        <span class="keyword">return</span> manager;
55
        <span class="keyword">return</span> manager;
54
    }
56
    }
55
    <span class="keyword">public</span> <span class="type">Lookup</span> <span class="function-name">getLookup</span>() {
56
        <span class="keyword">return</span> lookup;
57
    }
58
    <span class="comment">// It is good idea to switch all listeners on and off when the
57
    <span class="comment">// It is good idea to switch all listeners on and off when the
59
</span>    <span class="comment">// component is shown or hidden. In the case of TopComponent use:
58
</span>    <span class="comment">// component is shown or hidden. In the case of TopComponent use:
60
</span>    <span class="keyword">protected</span> <span class="type">void</span> <span class="function-name">componentActivated</span>() {
59
</span>    <span class="keyword">protected</span> <span class="type">void</span> <span class="function-name">componentActivated</span>() {
Lines 70-84 Link Here
70
 * turn the listeners on and off:
69
 * turn the listeners on and off:
71
<pre>
70
<pre>
72
<span class="keyword">public</span> <span class="keyword">class</span> <span class="type">YourComponent</span> <span class="keyword">extends</span> <span class="type">JPanel</span>
71
<span class="keyword">public</span> <span class="keyword">class</span> <span class="type">YourComponent</span> <span class="keyword">extends</span> <span class="type">JPanel</span>
73
        <span class="keyword">implements</span> <span class="type">ExplorerManager.Provider</span>, <span class="type">Lookup.Provider</span> {
72
<span class="keyword">implements</span> <span class="type">ExplorerManager.Provider</span>, <span class="type">Lookup.Provider</span> {
74
    <span class="comment">// fields as before...
73
    <span class="keyword">private</span> <span class="type">ExplorerManager</span> <span class="variable-name">manager</span>;
74
    <span class="keyword">private</span> <span class="type">Lookup</span> <span class="variable-name">lookup</span>;
75
</span>    <span class="keyword">public</span> <span class="type">YourComponent</span>() {
75
</span>    <span class="keyword">public</span> <span class="type">YourComponent</span>() {
76
        <span class="comment">// ...as before, but add e.g.:
76
        <span class="comment">// same as before...</span>
77
        manager = <span class="keyword">new</span> <span class="type">ExplorerManager</span>();
78
        <span class="type">ActionMap</span> <span class="variable-name">map</span> = getActionMap();
79
        map.put(DefaultEditorKit.copyAction, ExplorerUtils.actionCopy(manager));
80
        map.put(DefaultEditorKit.cutAction, ExplorerUtils.actionCut(manager));
81
        map.put(DefaultEditorKit.pasteAction, ExplorerUtils.actionPaste(manager));
82
        map.put(<span class="string">"delete"</span>, ExplorerUtils.actionDelete(manager, <span class="constant">true</span>)); <span class="comment">// or false
83
</span>
84
        <span class="comment">// ...but add e.g.:
77
</span>        <span class="type">InputMap</span> <span class="variable-name">keys</span> = getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
85
</span>        <span class="type">InputMap</span> <span class="variable-name">keys</span> = getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
78
        keys.put(KeyStroke.getKeyStroke(<span class="string">"control c"</span>), DefaultEditorKit.copyAction);
86
        keys.put(KeyStroke.getKeyStroke(<span class="string">"control c"</span>), DefaultEditorKit.copyAction);
79
        keys.put(KeyStroke.getKeyStroke(<span class="string">"control x"</span>), DefaultEditorKit.cutAction);
87
        keys.put(KeyStroke.getKeyStroke(<span class="string">"control x"</span>), DefaultEditorKit.cutAction);
80
        keys.put(KeyStroke.getKeyStroke(<span class="string">"control v"</span>), DefaultEditorKit.pasteAction);
88
        keys.put(KeyStroke.getKeyStroke(<span class="string">"control v"</span>), DefaultEditorKit.pasteAction);
81
        keys.put(KeyStroke.getKeyStroke(<span class="string">"DELETE"</span>), <span class="string">"delete"</span>);
89
        keys.put(KeyStroke.getKeyStroke(<span class="string">"DELETE"</span>), <span class="string">"delete"</span>);
90
91
        <span class="comment">// ...and initialization of lookup variable</span>
92
        lookup = ExplorerUtils.createLookup (manager, map);
93
    }
94
    <span class="comment">// ...method as before and getLookup</span>
95
    <span class="keyword">public</span> <span class="type">ExplorerManager</span> <span class="function-name">getExplorerManager</span>() {
96
        <span class="keyword">return</span> manager;
97
    }
98
    <span class="keyword">public</span> <span class="type">Lookup</span> <span class="function-name">getLookup</span>() {
99
        <span class="keyword">return</span> lookup;
82
    }
100
    }
83
    <span class="comment">// ...methods as before, but replace componentActivated and
101
    <span class="comment">// ...methods as before, but replace componentActivated and
84
</span>    <span class="comment">// componentDeactivated with e.g.:
102
</span>    <span class="comment">// componentDeactivated with e.g.:
(-)src/org/openide/windows/TopComponent.java (-9 / +95 lines)
Lines 36-41 Link Here
36
import javax.accessibility.AccessibleContext;
36
import javax.accessibility.AccessibleContext;
37
import javax.accessibility.AccessibleRole;
37
import javax.accessibility.AccessibleRole;
38
import javax.swing.Action;
38
import javax.swing.Action;
39
import javax.swing.ActionMap;
39
import javax.swing.JComponent;
40
import javax.swing.JComponent;
40
import javax.swing.KeyStroke;
41
import javax.swing.KeyStroke;
41
import javax.swing.SwingUtilities;
42
import javax.swing.SwingUtilities;
Lines 93-101 Link Here
93
    private static Object defaultLookupLock = new Object ();
94
    private static Object defaultLookupLock = new Object ();
94
    
95
    
95
    /** reference to Lookup with default implementation for the 
96
    /** reference to Lookup with default implementation for the 
96
     * component
97
     * component or the lookup associated with the component itself
97
     */
98
     */
98
    private java.lang.ref.Reference defaultLookupRef = new WeakReference(null);
99
    private Object defaultLookupRef;
99
100
100
    /** Listener to the data object's node or null */
101
    /** Listener to the data object's node or null */
101
    private NodeName nodeName;
102
    private NodeName nodeName;
Lines 120-127 Link Here
120
    /** Create a top component.
121
    /** Create a top component.
121
    */
122
    */
122
    public TopComponent () {
123
    public TopComponent () {
124
        this (null);
125
    }
126
    
127
    /** Creates a top component for a provided lookup that will delegate
128
     * take and synchronize activated nodes and ActionMap from a provided
129
     * lookup. The lookup will also be returned from {@link getLookup} method,
130
     * if not overriden.
131
     *
132
     * @param lookup the lookup to associate with
133
     * @since JST-PENDING
134
     */
135
    public TopComponent (Lookup lookup) {
136
        if (lookup != null) {
137
            setLookup (lookup, true);
138
            ActionMap map = (ActionMap)lookup.lookup (ActionMap.class);
139
            if (map != null) {
140
                setActionMap (map);
141
            }
142
        }
143
        
123
        enableEvents (java.awt.AWTEvent.KEY_EVENT_MASK);
144
        enableEvents (java.awt.AWTEvent.KEY_EVENT_MASK);
124
145
        
125
        // #27731 TopComponent itself shouldn't get the focus.
146
        // #27731 TopComponent itself shouldn't get the focus.
126
        // XXX What to do in case nothing in TopComponent is focusable?
147
        // XXX What to do in case nothing in TopComponent is focusable?
127
        setFocusable(false);
148
        setFocusable(false);
Lines 129-134 Link Here
129
        initActionMap();
150
        initActionMap();
130
    }
151
    }
131
    
152
    
153
    
132
    /** Create a top component associated with a data object.
154
    /** Create a top component associated with a data object.
133
    * Currently the data object is used to set the component's name
155
    * Currently the data object is used to set the component's name
134
    * (which will be updated according to the object's node delegate) by
156
    * (which will be updated according to the object's node delegate) by
Lines 206-218 Link Here
206
            return;
228
            return;
207
        }
229
        }
208
230
209
        // XXX Update lookup.
231
        Lookup lookup = getLookup (false);
210
        Object lookup = defaultLookupRef.get ();
211
        if (lookup instanceof DefaultTopComponentLookup) {
232
        if (lookup instanceof DefaultTopComponentLookup) {
212
            ((DefaultTopComponentLookup)lookup).updateLookups(activatedNodes);
233
            ((DefaultTopComponentLookup)lookup).updateLookups(activatedNodes);
213
        }
234
        }
214
235
215
216
        Node[] old = this.activatedNodes;
236
        Node[] old = this.activatedNodes;
217
        this.activatedNodes = activatedNodes;
237
        this.activatedNodes = activatedNodes;
218
238
Lines 758-767 Link Here
758
     * @since 3.29
778
     * @since 3.29
759
     */
779
     */
760
    public Lookup getLookup() {
780
    public Lookup getLookup() {
781
        return getLookup (true);
782
    }
783
    
784
    
785
    /** 
786
     * @param init should a lookup be initialized if it is not?
787
     * @return lookup or null
788
     */
789
    private Lookup getLookup (boolean init) {
761
        synchronized (defaultLookupLock) {
790
        synchronized (defaultLookupLock) {
762
            Object l = defaultLookupRef.get ();
791
            if (defaultLookupRef instanceof Lookup) {
763
            if (l instanceof Lookup) {
792
                return (Lookup)defaultLookupRef;
764
                return (Lookup)l;
793
            }
794
            
795
            if (defaultLookupRef instanceof java.lang.ref.Reference) {
796
                Object l = ((java.lang.ref.Reference)defaultLookupRef).get ();
797
                if (l instanceof Lookup) {
798
                    return (Lookup)l;
799
                }
800
            }
801
            
802
            if (!init) {
803
                return null;
765
            }
804
            }
766
            
805
            
767
            Lookup lookup = new DefaultTopComponentLookup (this); // Lookup of activated nodes and action map
806
            Lookup lookup = new DefaultTopComponentLookup (this); // Lookup of activated nodes and action map
Lines 770-775 Link Here
770
        }
809
        }
771
    }
810
    }
772
    
811
    
812
    /** Associates the provided lookup with the component. So it will
813
     * be returned from {@link getLookup} method.
814
     *
815
     * @param lookup the lookup to associate
816
     * @param sync synchronize return value of getActivatedNodes() with the 
817
     *   content of lookup?
818
     * @exception IllegalStateException if there already is a lookup registered
819
     *   with this component
820
     */
821
    final void setLookup (Lookup lookup, boolean sync) {
822
        synchronized (defaultLookupLock) {
823
            if (defaultLookupRef != null) throw new IllegalStateException ("Trying to set lookup " + lookup + " but there already is " + defaultLookupRef + " for component: " + this); // NOI18N
824
            
825
            defaultLookupRef = lookup;
826
            
827
            if (sync) {
828
                new SynchronizeNodes (lookup);
829
            }
830
        }
831
    }
832
    
773
    /** This class provides the connection between the node name and
833
    /** This class provides the connection between the node name and
774
    * a name of the component.
834
    * a name of the component.
775
    */
835
    */
Lines 1031-1034 Link Here
1031
1091
1032
    } // end of Replacer inner class
1092
    } // end of Replacer inner class
1033
1093
1094
    /** Synchronization between Lookup and getActivatedNodes
1095
     */
1096
    private class SynchronizeNodes implements org.openide.util.LookupListener, Runnable {
1097
        private Lookup.Result res;
1098
        
1099
        public SynchronizeNodes (Lookup l) {
1100
            res = l.lookup (new Lookup.Template (Node.class));
1101
            res.addLookupListener (this);
1102
            resultChanged (null);
1103
        }
1104
        
1105
        public void resultChanged (org.openide.util.LookupEvent ev) {
1106
            if (TopComponent.this.isVisible () && SwingUtilities.isEventDispatchThread ()) {
1107
                // replan
1108
                SwingUtilities.invokeLater (this);
1109
            } else {
1110
                // run immediatelly
1111
                run ();
1112
            }
1113
        }
1114
        
1115
        public void run () {
1116
            setActivatedNodes ((Node[])res.allInstances ().toArray (new Node[0]));
1117
        }
1118
        
1119
    } // end of SynchronizeNodes
1034
}
1120
}
(-)test/unit/src/org/openide/explorer/ExplorerUtilCreateLookupTest.java (-15 / +3 lines)
Lines 53-73 Link Here
53
        return new NbTestSuite(ExplorerUtilCreateLookupTest.class);
53
        return new NbTestSuite(ExplorerUtilCreateLookupTest.class);
54
    }
54
    }
55
    
55
    
56
    /** Run all tests in AWT thread */
56
    
57
    public final void run(final junit.framework.TestResult result) {
57
    protected boolean runInEQ () {
58
        try {
58
        return true;
59
            // XXX ExplorerManager when updating selected nodes
60
            // replanes all firing into AWT thread, therefore the test
61
            // has to run in AWT.
62
            javax.swing.SwingUtilities.invokeAndWait(new Runnable() {
63
                public void run() {
64
                    ExplorerUtilCreateLookupTest.super.run (result);
65
                }
66
            });
67
        } catch (Exception ex) {
68
            ex.printStackTrace();
69
            throw new IllegalStateException ();
70
        }
71
    }
59
    }
72
    
60
    
73
    /** Setup component with lookup.
61
    /** Setup component with lookup.
(-)test/unit/src/org/openide/windows/TopComponentLookupToNodesBridge.java (+116 lines)
Added Link Here
1
/*
2
 *                 Sun Public License Notice
3
 * 
4
 * The contents of this file are subject to the Sun Public License
5
 * Version 1.0 (the "License"). You may not use this file except in
6
 * compliance with the License. A copy of the License is available at
7
 * http://www.sun.com/
8
 * 
9
 * The Original Code is NetBeans. The Initial Developer of the Original
10
 * Code is Sun Microsystems, Inc. Portions Copyright 1997-2003 Sun
11
 * Microsystems, Inc. All Rights Reserved.
12
 */
13
14
package org.openide.windows;
15
16
17
import junit.framework.*;
18
19
import org.netbeans.junit.*;
20
import org.openide.cookies.*;
21
import org.openide.nodes.*;
22
import org.openide.util.*;
23
import org.openide.util.lookup.AbstractLookup;
24
import org.openide.util.lookup.InstanceContent;
25
26
/**
27
 * Checks behaviour of a bridge that listens on a provided lookup
28
 * and initializes activated nodes according to the nodes in the
29
 * lookup.
30
 *
31
 * @author Jaroslav Tulach, Jesse Glick
32
 */
33
public final class TopComponentLookupToNodesBridge extends NbTestCase {
34
    /** own action map */
35
    protected javax.swing.ActionMap map;
36
    /** top component we work on */
37
    protected TopComponent top;
38
    /** instance in the lookup */
39
    protected InstanceContent ic;
40
    /** its lookup */
41
    protected Lookup lookup;
42
    
43
    public TopComponentLookupToNodesBridge (String testName) {
44
        super(testName);
45
    }
46
    
47
    public static void main(String[] args) {
48
        junit.textui.TestRunner.run(suite());
49
    }
50
    
51
    public static Test suite() {
52
        return new NbTestSuite(TopComponentLookupToNodesBridge.class);
53
    }
54
    
55
    /** Setup component with lookup.
56
     */
57
    protected void setUp () {
58
        System.setProperty ("org.openide.util.Lookup", "-");
59
        
60
        map = new javax.swing.ActionMap ();
61
        ic = new InstanceContent ();
62
        ic.add (map);
63
        
64
        lookup = new AbstractLookup (ic);
65
        top = new TopComponent (lookup);
66
    }
67
    
68
69
    public void testTheLookupIsReturned () {
70
        assertEquals ("Lookup provided to TC in constructor is returned", lookup, top.getLookup ());
71
    }
72
    
73
    public void testActionMapIsTakenFromTheLookupIfProvided () {
74
        assertEquals ("Action map is set", map, top.getActionMap ());
75
        ic.set (java.util.Collections.singleton (new javax.swing.ActionMap ()), null);
76
        assertEquals ("And is not changed (right now) if modified in list", map, top.getActionMap ());
77
    }
78
    
79
    public void testEmptyLookupGeneratesZeroLengthArray () {
80
        assertNotNull ("Array is there", top.getActivatedNodes ());
81
        assertEquals ("No nodes", 0, top.getActivatedNodes ().length);
82
    }
83
    
84
    public void testNodeIsThereIfInLookup () {
85
        class Listener implements java.beans.PropertyChangeListener {
86
            public int cnt;
87
            public String name; 
88
            
89
            public void propertyChange (java.beans.PropertyChangeEvent ev) {
90
                cnt++;
91
                name = ev.getPropertyName ();
92
            }
93
        }
94
        
95
        Listener l = new Listener ();
96
        top.addPropertyChangeListener (l);
97
        
98
        ic.add (Node.EMPTY);
99
        
100
        assertNotNull ("Array exists", top.getActivatedNodes ());
101
        assertEquals ("One node", 1, top.getActivatedNodes ().length);
102
        assertEquals ("The node", Node.EMPTY, top.getActivatedNodes ()[0]);
103
        assertEquals ("One PCE", 1, l.cnt);
104
        assertEquals ("Name of property", "activatedNodes", l.name);
105
106
        
107
        ic.set (java.util.Collections.nCopies (2, Node.EMPTY), null);
108
        
109
        assertEquals ("Two nodes", 2, top.getActivatedNodes ().length);
110
        assertEquals ("The same", Node.EMPTY, top.getActivatedNodes ()[0]);
111
        assertEquals ("The same", Node.EMPTY, top.getActivatedNodes ()[1]);
112
        assertEquals ("second PCE change", 2, l.cnt);
113
        assertEquals ("Name of property", "activatedNodes", l.name);
114
        
115
    }
116
}

Return to bug 38185