KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > core > windows > services > NodeOperationImpl


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
21 package org.netbeans.core.windows.services;
22
23
24 import java.beans.PropertyChangeEvent JavaDoc;
25 import java.beans.PropertyChangeListener JavaDoc;
26 import java.util.Iterator JavaDoc;
27 import java.util.WeakHashMap JavaDoc;
28 import org.netbeans.core.NbMainExplorer;
29 import org.netbeans.core.NbSheet;
30 import org.openide.DialogDescriptor;
31 import org.openide.DialogDisplayer;
32 import org.openide.explorer.ExplorerManager;
33 import org.openide.nodes.*;
34 import org.openide.util.HelpCtx;
35 import org.openide.util.Mutex;
36 import org.openide.util.NbBundle;
37 import org.openide.util.UserCancelException;
38 import org.openide.util.WeakSet;
39 import org.openide.windows.Mode;
40 import org.openide.windows.TopComponent;
41 import org.openide.windows.WindowManager;
42
43 import javax.swing.*;
44 import java.awt.*;
45 import java.util.HashSet JavaDoc;
46 import java.util.Set JavaDoc;
47 import javax.swing.border.EmptyBorder JavaDoc;
48
49
50 // XXX Before as org.netbeans.core.NbNodeOperation.
51

52 /** Class that provides operations on nodes. Any part of system can
53  * ask for opening a customizer or explorer on any node. These actions
54  * are accessible thru this class.
55  *
56  * @author Ian Formanek
57  */

58 public final class NodeOperationImpl extends NodeOperation {
59
60     /** Shows an explorer on the given root Node.
61     * @param n the Node that will be the rootContext of the explored hierarchy
62     */

63     public void explore (final Node n) {
64         Mutex.EVENT.readAccess (new Runnable JavaDoc () {
65                 public void run () {
66                     NbMainExplorer.ExplorerTab et = new NonPersistentExplorerTab ();
67                     et.setRootContext (n);
68                     et.adjustComponentPersistence();
69
70                     Mode target = WindowManager.getDefault().findMode("explorer");
71                     if (target != null) {
72                         target.dockInto(et);
73                     }
74                     et.open();
75                     et.requestActive();
76                 }
77             });
78     }
79
80     /** Tries to open customization for specified node. The dialog is
81     * open in modal mode and the function returns after successful
82     * customization.
83     *
84     * @param n the node to customize
85     * @return <CODE>true</CODE> if the node has customizer,
86     * <CODE>false</CODE> if not
87     */

88     public boolean customize (Node n) {
89         final Component customizer = n.getCustomizer ();
90         if (customizer == null) return false;
91         return Mutex.EVENT.readAccess (new Mutex.Action<Boolean JavaDoc> () {
92                 public Boolean JavaDoc run () {
93                     if (customizer instanceof NbPresenter) { // #9466
94
((NbPresenter) customizer).pack ();
95                         ((NbPresenter) customizer).show ();
96                         return Boolean.TRUE;
97                     }
98                     if (customizer instanceof Window) {
99                         ((Window) customizer).pack ();
100                         customizer.setVisible (true);
101                         return Boolean.TRUE;
102                     }
103                     
104                     // preserve help context and explorer provider of customizer
105
JPanel p = null;
106                     if (customizer instanceof ExplorerManager.Provider) {
107                         p = new ExplorerProviderFwd(customizer, (ExplorerManager.Provider)customizer);
108                     } else {
109                         p = new HelpFwdPanel(customizer);
110                     }
111                     p.setLayout(new BorderLayout());
112                     p.getAccessibleContext().setAccessibleDescription(
113                         NbBundle.getMessage(NodeOperationImpl.class, "CTL_Customizer_dialog_title"));
114                     
115                     // #21547 adjust for XML that relies on container managed borders
116
// please DELETE after #19821 is fixed, immediatelly
117
if (customizer.getClass().getName().startsWith("org.netbeans.modules.xml.catalog")) { // NOI18N
118
p.setBorder(BorderFactory.createEmptyBorder(12, 12, 0, 11));
119                     }
120                     // end of future DELETE
121

122                     p.add(customizer, BorderLayout.CENTER);
123                     
124                     // present it
125
DialogDescriptor dd = new DialogDescriptor
126                         (p,
127                          NbBundle.getMessage(NodeOperationImpl.class, "CTL_Customizer_dialog_title"));
128                     dd.setOptions(new Object JavaDoc[] { DialogDescriptor.CLOSED_OPTION });
129
130                     Dialog dialog = org.openide.DialogDisplayer.getDefault ().createDialog(dd);
131                     dialog.pack();
132                     dialog.setVisible(true);
133                     return Boolean.TRUE;
134                 }
135             }).booleanValue ();
136     }
137
138     /** Panel, decorates given inner panel with forwarding of help context.
139      * It will probably also decorate customizer with border (when #19821 is fixed)
140      */

141      private static class HelpFwdPanel extends JPanel implements HelpCtx.Provider {
142         private Component innerComp;
143         private boolean active = false;
144         
145         /** Not instantiatable outside */
146         private HelpFwdPanel (Component innerComp) {
147             this.innerComp = innerComp;
148         }
149         
150         public HelpCtx getHelpCtx () {
151             try {
152                 //??? eliminate recursion it delegates to parent (this)
153
if (active) return null;
154                 active = true;
155                 return HelpCtx.findHelp(innerComp);
156             } finally {
157                 active = false;
158             }
159         }
160                                                    
161     } // end of HelpFwdPanel
162

163     /** Decorates given panel with explorer provider functionality, forwarding
164      * to given original provider. */

165     private static final class ExplorerProviderFwd extends HelpFwdPanel
166                 implements ExplorerManager.Provider {
167         private ExplorerManager.Provider explProvider;
168         
169         /** Not instantiatable outside */
170         private ExplorerProviderFwd (Component innerComp, ExplorerManager.Provider explProvider) {
171             super(innerComp);
172             this.explProvider = explProvider;
173         }
174                                                       
175         /** Forwards to original explorer provider.
176          */

177         public ExplorerManager getExplorerManager() {
178             return explProvider.getExplorerManager();
179         }
180         
181      } // end of CustomizerDecorator
182

183     /** Opens a modal propertySheet on given Node
184     * @param n the node to show properties for
185     */

186     public void showProperties (Node n) {
187         Dialog d = findCachedPropertiesDialog( n );
188         if( null == d ) {
189             NbSheet s = new NbSheet ();
190             Node[] nds = new Node[] { n };
191             s.setNodes (nds);
192             openProperties(s, nds);
193         } else {
194             d.setVisible( true );
195             d.toFront();
196             d.requestFocusInWindow();
197         }
198     }
199
200     /** Opens a modal propertySheet on given set of Nodes
201     * @param n the array of nodes to show properties for
202     */

203     public void showProperties (Node[] nodes) {
204         Dialog d = findCachedPropertiesDialog( nodes );
205         if( null == d ) {
206             NbSheet s = new NbSheet ();
207             s.setNodes (nodes);
208             openProperties(s, nodes);
209         } else {
210             d.setVisible( true );
211             d.toFront();
212             d.requestFocusInWindow();
213         }
214     }
215     
216     //#79126 - cache the open properties windows and reuse them if the Nodes
217
//are the same
218
private static WeakSet<Node[]> nodeCache = new WeakSet<Node[]>();
219     private static WeakHashMap JavaDoc<Node[], Dialog> dialogCache = new WeakHashMap JavaDoc<Node[], Dialog>();
220     
221     private static Dialog findCachedPropertiesDialog( Node n ) {
222         return findCachedPropertiesDialog( new Node[] { n } );
223     }
224     
225     private static Dialog findCachedPropertiesDialog( Node[] nodes ) {
226         for( Iterator JavaDoc<Node[]> it=nodeCache.iterator(); it.hasNext(); ) {
227             Node[] cached = it.next();
228             if( cached.length != nodes.length )
229                 continue;
230             boolean match = true;
231             for( int i=0; i<cached.length; i++ ) {
232                 if( !cached[i].equals( nodes[i] ) ) {
233                     match = false;
234                     break;
235                 }
236             }
237             if( match ) {
238                 return dialogCache.get( cached );
239             }
240         }
241         return null;
242     }
243
244     /** Opens explorer for specified root in modal mode. The set
245     * of selected components is returned as a result. The acceptor
246     * should be asked each time selected nodes changes to accept or
247     * reject the current result. This should affect for example the
248     * <EM>OK</EM> button.
249     *
250     * @param title is a title that will be displayed as a title of the window
251     * @param root the root to explore
252     * @param acceptor the class that is asked for accepting or rejecting
253     * current selection
254     * @param top is a component that will be displayed on the top
255     * @return array of selected (and accepted) nodes
256     *
257     * @exception UserCancelException selection interrupted by user
258     */

259     public Node[] select (String JavaDoc title, String JavaDoc rootTitle, Node root, NodeAcceptor acceptor, Component top)
260     throws UserCancelException {
261         final FileSelector selector = new FileSelector(rootTitle, root, acceptor, top);
262         selector.setBorder(new EmptyBorder JavaDoc(12, 12, 0, 12));
263         DialogDescriptor dd = new DialogDescriptor(selector, title, true,
264                                                    selector.getOptions(),
265                                                    selector.getSelectOption(), DialogDescriptor.DEFAULT_ALIGN,
266                                                    HelpCtx.DEFAULT_HELP, null);
267         Object JavaDoc ret = DialogDisplayer.getDefault().notify(dd);
268         if (ret != selector.getSelectOption()) {
269             throw new UserCancelException ();
270         }
271         return selector.getNodes ();
272     }
273
274     /** Helper method, opens properties top component in single mode
275     * and requests a focus for it */

276     private static void openProperties (final TopComponent tc, final Node[] nds) {
277         // XXX #36492 in NbSheet the name is set asynch from setNodes.
278
// Mutex.EVENT.readAccess (new Runnable () { // PENDING
279
javax.swing.SwingUtilities.invokeLater(new Runnable JavaDoc() {
280                 public void run () {
281                     boolean modal;
282                     if(NbPresenter.currentModalDialog == null) {
283                         modal = false;
284                     } else {
285                         modal = true;
286                     }
287                     
288                     Dialog dlg = org.openide.DialogDisplayer.getDefault().createDialog(new DialogDescriptor (
289                         tc,
290                         tc.getName(),
291                         modal,
292                         new Object JavaDoc [] {DialogDescriptor.CLOSED_OPTION},
293                         DialogDescriptor.CLOSED_OPTION,
294                         DialogDescriptor.BOTTOM_ALIGN,
295                         null,
296                         null
297                     ));
298                     //fix for issue #40323
299
SheetNodesListener listener = new SheetNodesListener(dlg, tc);
300                     listener.attach(nds);
301                     
302                     nodeCache.add( nds );
303                     dialogCache.put( nds, dlg );
304                     
305                     dlg.setVisible(true);
306                 }
307             });
308     }
309     
310     /** Not serializable explorer tab used in explore from here.
311      */

312     private static class NonPersistentExplorerTab extends NbMainExplorer.ExplorerTab {
313         public int getPersistenceType() {
314             return PERSISTENCE_NEVER;
315         }
316         
317         protected String JavaDoc preferredID() {
318             return "NonPersistentExplorerTab";
319         }
320     }
321
322     /**
323      * fix for issue #40323 the prop dialog needs to be closed when the nodes it displayes are destroyed.
324      */

325     private static class SheetNodesListener extends NodeAdapter implements PropertyChangeListener JavaDoc {
326
327         private Dialog dialog;
328         private Set<Node> listenerSet;
329         /** top component we listen to for name changes */
330         private TopComponent tc;
331         
332         SheetNodesListener(Dialog dialog, TopComponent tc) {
333             this.dialog = dialog;
334             this.tc = tc;
335             tc.addPropertyChangeListener(this);
336         }
337         
338         public void propertyChange (PropertyChangeEvent JavaDoc pce) {
339             if ("name".equals(pce.getPropertyName())) {
340                 dialog.setTitle((String JavaDoc) pce.getNewValue());
341             }
342         }
343         
344         public void attach(Node[] nodes) {
345             listenerSet = new HashSet JavaDoc<Node>(nodes.length * 2);
346             for (int i = 0; i < nodes.length; i++) {
347                 listenerSet.add(nodes[i]);
348                 nodes[i].addNodeListener(this);
349             };
350         }
351
352         /** Fired when the node is deleted.
353          * @param ev event describing the node
354          */

355         public void nodeDestroyed(NodeEvent ev) {
356             Node destroyedNode = ev.getNode();
357             // stop to listen to destroyed node
358
destroyedNode.removeNodeListener(this);
359             listenerSet.remove(destroyedNode);
360             // close top component (our outer class) if last node was destroyed
361
if (listenerSet.isEmpty()) {
362                 // #68943 - stop to listen, as we are waving goodbye :-)
363
tc.removePropertyChangeListener(this);
364                 Mutex.EVENT.readAccess(new Runnable JavaDoc() {
365                     public void run() {
366                         dialog.setVisible(false);
367                         dialog.dispose();
368                         dialog = null;
369                     }
370                 });
371             }
372         }
373     }
374     
375 }
376
Popular Tags