KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > modules > project > ui > ProjectTab


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.netbeans.modules.project.ui;
21
22 import java.awt.BorderLayout JavaDoc;
23 import java.awt.Image JavaDoc;
24 import java.awt.Rectangle JavaDoc;
25 import java.awt.event.ActionEvent JavaDoc;
26 import java.beans.PropertyChangeEvent JavaDoc;
27 import java.beans.PropertyChangeListener JavaDoc;
28 import java.beans.PropertyVetoException JavaDoc;
29 import java.io.IOException JavaDoc;
30 import java.io.ObjectInput JavaDoc;
31 import java.io.ObjectOutput JavaDoc;
32 import java.util.ArrayList JavaDoc;
33 import java.util.Arrays JavaDoc;
34 import java.util.Enumeration JavaDoc;
35 import java.util.HashMap JavaDoc;
36 import java.util.Iterator JavaDoc;
37 import java.util.List JavaDoc;
38 import java.util.Map JavaDoc;
39 import javax.swing.AbstractAction JavaDoc;
40 import javax.swing.Action JavaDoc;
41 import javax.swing.ActionMap JavaDoc;
42 import javax.swing.SwingUtilities JavaDoc;
43 import javax.swing.text.DefaultEditorKit JavaDoc;
44 import javax.swing.tree.DefaultTreeModel JavaDoc;
45 import javax.swing.tree.TreeNode JavaDoc;
46 import javax.swing.tree.TreePath JavaDoc;
47 import javax.swing.tree.TreeModel JavaDoc;
48 import org.netbeans.api.project.FileOwnerQuery;
49 import org.netbeans.api.project.Project;
50 import org.netbeans.api.project.ProjectUtils;
51 import org.netbeans.api.project.ui.OpenProjects;
52 import org.netbeans.modules.project.ui.groups.Group;
53 import org.netbeans.spi.project.ActionProvider;
54 import org.openide.DialogDisplayer;
55 import org.openide.ErrorManager;
56 import org.openide.NotifyDescriptor;
57 import org.openide.awt.StatusDisplayer;
58 import org.openide.explorer.ExplorerManager;
59 import org.openide.explorer.ExplorerUtils;
60 import org.openide.explorer.view.BeanTreeView;
61 import org.openide.explorer.view.Visualizer;
62 import org.openide.filesystems.FileObject;
63 import org.openide.nodes.Node;
64 import org.openide.nodes.NodeNotFoundException;
65 import org.openide.nodes.NodeOp;
66 import org.openide.util.HelpCtx;
67 import org.openide.util.NbBundle;
68 import org.openide.util.RequestProcessor;
69 import org.openide.util.Utilities;
70 import org.openide.windows.TopComponent;
71 import org.openide.windows.WindowManager;
72
73 /** TopComponment for viewing open projects.
74  * <P>
75  * PENEDING : Fix persistence when new Winsys allows
76  *
77  * @author Petr Hrebejk
78  */

79 public class ProjectTab extends TopComponent
80                         implements ExplorerManager.Provider {
81                 
82     public static final String JavaDoc ID_LOGICAL = "projectTabLogical_tc"; // NOI18N
83
public static final String JavaDoc ID_PHYSICAL = "projectTab_tc"; // NOI18N
84

85     private static final Image JavaDoc ICON_LOGICAL = org.openide.util.Utilities.loadImage( "org/netbeans/modules/project/ui/resources/projectTab.gif" );
86     private static final Image JavaDoc ICON_PHYSICAL = org.openide.util.Utilities.loadImage( "org/netbeans/modules/project/ui/resources/filesTab.gif" );
87     
88     private static Map JavaDoc<String JavaDoc, ProjectTab> tabs = new HashMap JavaDoc<String JavaDoc, ProjectTab>();
89                             
90     private transient final ExplorerManager manager;
91     private transient Node JavaDoc rootNode;
92     
93     private String JavaDoc id;
94     private transient final ProjectTreeView btv;
95                          
96     public ProjectTab( String JavaDoc id ) {
97         this();
98         this.id = id;
99         initValues();
100     }
101     
102     public ProjectTab() {
103         
104         // See #36315
105
manager = new ExplorerManager();
106         
107         ActionMap JavaDoc map = getActionMap();
108         map.put(DefaultEditorKit.copyAction, ExplorerUtils.actionCopy(manager));
109         map.put(DefaultEditorKit.cutAction, ExplorerUtils.actionCut(manager));
110         map.put(DefaultEditorKit.pasteAction, ExplorerUtils.actionPaste(manager));
111         map.put("delete", new DelegatingAction(ActionProvider.COMMAND_DELETE, ExplorerUtils.actionDelete(manager, true)));
112         
113         initComponents();
114         
115         btv = new ProjectTreeView(); // Add the BeanTreeView
116

117         btv.setDragSource (true);
118         
119         btv.setRootVisible(false);
120         
121         add( btv, BorderLayout.CENTER );
122         
123         associateLookup( ExplorerUtils.createLookup(manager, map) );
124         
125     }
126
127     /**
128      * Update display to reflect {@link org.netbeans.modules.project.ui.groups.Group#getActiveGroup}.
129      * @param group current group, or null
130      */

131     public void setGroup(Group g) {
132         if (id.equals(ID_LOGICAL)) {
133             if (g != null) {
134                 setName(NbBundle.getMessage(ProjectTab.class, "LBL_projectTabLogical_tc_with_group", g.getName()));
135             } else {
136                 setName(NbBundle.getMessage(ProjectTab.class, "LBL_projectTabLogical_tc"));
137             }
138         } else {
139             setName(NbBundle.getMessage(ProjectTab.class, "LBL_projectTab_tc"));
140         }
141         // Seems to be useless: setToolTipText(getName());
142
}
143
144     private void initValues() {
145         setGroup(Group.getActiveGroup());
146         
147         if (id.equals(ID_LOGICAL)) {
148             setIcon( ICON_LOGICAL );
149         }
150         else {
151             setIcon( ICON_PHYSICAL );
152         }
153             
154         if ( rootNode == null ) {
155             // Create the node which lists open projects
156
rootNode = new ProjectsRootNode(id.equals(ID_LOGICAL) ? ProjectsRootNode.LOGICAL_VIEW : ProjectsRootNode.PHYSICAL_VIEW);
157         }
158         manager.setRootContext( rootNode );
159     }
160             
161     /** Explorer manager implementation
162      */

163     public ExplorerManager getExplorerManager() {
164         return manager;
165     }
166     
167     /* Singleton accessor. As ProjectTab is persistent singleton this
168      * accessor makes sure that ProjectTab is deserialized by window system.
169      * Uses known unique TopComponent ID TC_ID = "projectTab_tc" to get ProjectTab instance
170      * from window system. "projectTab_tc" is name of settings file defined in module layer.
171      * For example ProjectTabAction uses this method to create instance if necessary.
172      */

173     public static synchronized ProjectTab findDefault( String JavaDoc tcID ) {
174
175         ProjectTab tab = tabs.get(tcID);
176         
177         if ( tab == null ) {
178             //If settings file is correctly defined call of WindowManager.findTopComponent() will
179
//call TestComponent00.getDefault() and it will set static field component.
180

181             TopComponent tc = WindowManager.getDefault().findTopComponent( tcID );
182             if (tc != null) {
183                 if (!(tc instanceof ProjectTab)) {
184                     //This should not happen. Possible only if some other module
185
//defines different settings file with the same name but different class.
186
//Incorrect settings file?
187
IllegalStateException JavaDoc exc = new IllegalStateException JavaDoc
188                     ("Incorrect settings file. Unexpected class returned." // NOI18N
189
+ " Expected:" + ProjectTab.class.getName() // NOI18N
190
+ " Returned:" + tc.getClass().getName()); // NOI18N
191
ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, exc);
192                     //Fallback to accessor reserved for window system.
193
tab = ProjectTab.getDefault( tcID );
194                 }
195                 else {
196                     tab = (ProjectTab)tc;
197                 }
198             }
199             else {
200                 //This should not happen when settings file is correctly defined in module layer.
201
//TestComponent00 cannot be deserialized
202
//Fallback to accessor reserved for window system.
203
tab = ProjectTab.getDefault( tcID );
204             }
205         }
206         return tab;
207     }
208     
209     /* Singleton accessor reserved for window system ONLY. Used by window system to create
210      * ProjectTab instance from settings file when method is given. Use <code>findDefault</code>
211      * to get correctly deserialized instance of ProjectTab */

212     public static synchronized ProjectTab getDefault( String JavaDoc tcID ) {
213         
214         ProjectTab tab = tabs.get(tcID);
215         
216         if ( tab == null ) {
217             tab = new ProjectTab( tcID );
218             tabs.put( tcID, tab );
219         }
220         
221         return tab;
222     }
223     
224     public static TopComponent getLogical() {
225         return getDefault( ID_LOGICAL );
226     }
227     
228     public static TopComponent getPhysical() {
229         return getDefault( ID_PHYSICAL );
230     }
231     
232     protected String JavaDoc preferredID () {
233         return id;
234     }
235     
236     public HelpCtx getHelpCtx() {
237         return ExplorerUtils.getHelpCtx(
238             manager.getSelectedNodes(),
239             ID_LOGICAL.equals( id ) ? new HelpCtx( "ProjectTab_Projects" ) : new HelpCtx( "ProjectTab_Files" ) );
240     }
241
242      
243     public int getPersistenceType() {
244         return TopComponent.PERSISTENCE_ALWAYS;
245     }
246     
247     // APPEARANCE
248

249     /** This method is called from within the constructor to
250      * initialize the form.
251      * WARNING: Do NOT modify this code. The content of this method is
252      * always regenerated by the FormEditor.
253      */

254     private void initComponents() {//GEN-BEGIN:initComponents
255

256         setLayout(new java.awt.BorderLayout JavaDoc());
257
258     }//GEN-END:initComponents
259

260     
261     // Variables declaration - do not modify//GEN-BEGIN:variables
262
// End of variables declaration//GEN-END:variables
263

264     @SuppressWarnings JavaDoc("deprecation")
265     public boolean requestFocusInWindow() {
266         super.requestFocusInWindow();
267         return btv.requestFocusInWindow();
268     }
269
270     //#41258: In the SDI, requestFocus is called rather than requestFocusInWindow:
271
@SuppressWarnings JavaDoc("deprecation")
272     public void requestFocus() {
273         super.requestFocus();
274         btv.requestFocus();
275     }
276     
277     // PERSISTENCE
278

279     private static final long serialVersionUID = 9374872358L;
280     
281     public void writeExternal (ObjectOutput JavaDoc out) throws IOException JavaDoc {
282         super.writeExternal( out );
283         
284         out.writeObject( id );
285         out.writeObject( rootNode.getHandle() );
286         out.writeObject( btv.getExpandedPaths() );
287         out.writeObject( getSelectedPaths() );
288     }
289
290     @SuppressWarnings JavaDoc("unchecked")
291     public void readExternal (ObjectInput JavaDoc in) throws IOException JavaDoc, ClassNotFoundException JavaDoc {
292         super.readExternal( in );
293         id = (String JavaDoc)in.readObject();
294         rootNode = ((Node.Handle JavaDoc)in.readObject()).getNode();
295     List JavaDoc<String JavaDoc[]> exPaths = (List JavaDoc<String JavaDoc[]>)in.readObject();
296         List JavaDoc<String JavaDoc[]> selPaths = null;
297         try {
298             selPaths = (List JavaDoc<String JavaDoc[]>)in.readObject();
299         }
300         catch ( java.io.OptionalDataException JavaDoc e ) {
301             // Sel paths missing
302
}
303         initValues();
304 // fix for #55701 (Expanding of previously expanded folder in explorer slows down startup)
305
// the expansion scales very bad now and can prolong startup up to several minutes
306
// disabling the expansion of nodes after start altogether
307
// (thus getting back to how it worked in NB 4.0 FCS, but letting the user turn it back on)
308
if (System.getProperty ("netbeans.keep.expansion") != null)
309         {
310             btv.expandNodes( exPaths );
311             selectPaths( selPaths );
312         }
313
314     }
315     
316     // MANAGING ACTIONS
317

318     protected void componentActivated() {
319         ExplorerUtils.activateActions(manager, true);
320     }
321     
322     protected void componentDeactivated() {
323         ExplorerUtils.activateActions(manager, false);
324     }
325
326     @Override JavaDoc
327     public Action JavaDoc[] getActions() {
328         Action JavaDoc[] actions = super.getActions();
329         if (ID_LOGICAL.equals(id)) {
330             List JavaDoc<Action JavaDoc> allActions = new ArrayList JavaDoc<Action JavaDoc>(Arrays.asList(manager.getRootContext().getActions(false)));
331             allActions.add(null);
332             allActions.addAll(Arrays.asList(actions));
333             return allActions.toArray(new Action JavaDoc[allActions.size()]);
334         } else {
335             return actions;
336         }
337     }
338
339
340
341     // SEARCHING NODES
342

343     // Called from the SelectNodeAction
344

345     private final RequestProcessor RP = new RequestProcessor();
346     
347     public void selectNodeAsync(final FileObject object) {
348         
349         setCursor( Utilities.createProgressCursor( this ) );
350         open();
351         requestActive();
352         
353         // Do it in different thread than AWT
354
RP.post( new Runnable JavaDoc() {
355             public void run() {
356                 ProjectsRootNode root = (ProjectsRootNode)manager.getRootContext();
357                  Node JavaDoc tempNode = root.findNode( object );
358                  if (tempNode == null) {
359                      Project project = FileOwnerQuery.getOwner(object);
360                      if (project != null && !OpenProjectList.getDefault().isOpen(project)) {
361                          DialogDisplayer dd = DialogDisplayer.getDefault();
362                          String JavaDoc message = NbBundle.getMessage(ProjectTab.class, "MSG_openProject_confirm", //NOI18N
363
ProjectUtils.getInformation(project).getDisplayName());
364                          String JavaDoc title = NbBundle.getMessage(ProjectTab.class, "MSG_openProject_confirm_title");//NOI18N
365
NotifyDescriptor.Confirmation confirm =
366                                  new NotifyDescriptor.Confirmation(message, title, NotifyDescriptor.OK_CANCEL_OPTION);
367                          DialogDisplayer.getDefault().notify(confirm);
368                          if (confirm.getValue() == NotifyDescriptor.OK_OPTION) {
369                              if (!OpenProjectList.getDefault().isOpen(project)) {
370                                  OpenProjects.getDefault().open(new Project[] { project }, false);
371                              }
372                              tempNode = root.findNode( object );
373                          }
374                      }
375                  }
376                  final Node JavaDoc selectedNode = tempNode;
377                   // Back to AWT // Back to AWT
378
SwingUtilities.invokeLater( new Runnable JavaDoc() {
379                     public void run() {
380                         if ( selectedNode != null ) {
381                             try {
382                                 manager.setSelectedNodes( new Node JavaDoc[] { selectedNode } );
383                                 btv.scrollToNode(selectedNode);
384                                 StatusDisplayer.getDefault().setStatusText( "" ); // NOI18N
385
}
386                             catch ( PropertyVetoException JavaDoc e ) {
387                                 // Bad day node found but can't be selected
388
}
389                         }
390                         else {
391                             StatusDisplayer.getDefault().setStatusText(
392                                 NbBundle.getMessage( ProjectTab.class,
393                                                      ID_LOGICAL.equals( id ) ? "MSG_NodeNotFound_ProjectsTab" : "MSG_NodeNotFound_FilesTab" ) ); // NOI18N
394
}
395                         setCursor( null );
396                     }
397                 } );
398             }
399         } );
400          
401     }
402     
403     public boolean selectNode(FileObject object) {
404         // System.out.println("Selecting node " + id + " : " + object + " -AWT- " + SwingUtilities.isEventDispatchThread() );
405

406         ProjectsRootNode root = (ProjectsRootNode)manager.getRootContext();
407         Node JavaDoc selectedNode = root.findNode( object );
408         if ( selectedNode != null ) {
409             try {
410                 manager.setSelectedNodes( new Node JavaDoc[] { selectedNode } );
411                 btv.scrollToNode(selectedNode);
412                 return true;
413             }
414             catch ( PropertyVetoException JavaDoc e ) {
415                 // Bad day node found but can't be selected
416
return false;
417             }
418         }
419         
420         return false;
421     }
422     
423     public void expandNode( Node JavaDoc node ) {
424         btv.expandNode( node );
425     }
426     
427     private List JavaDoc<String JavaDoc[]> getSelectedPaths() {
428         Node JavaDoc selectedNodes[] = manager.getSelectedNodes();
429         List JavaDoc<String JavaDoc[]> result = new ArrayList JavaDoc<String JavaDoc[]>();
430         Node JavaDoc rootNode = manager.getRootContext();
431                 
432         for( int i = 0; i < selectedNodes.length; i++ ) {
433             String JavaDoc[] path = NodeOp.createPath( selectedNodes[i], rootNode );
434             if ( path != null ) {
435                 result.add( path );
436             }
437         }
438         
439         return result;
440     }
441     
442     
443     private void selectPaths( List JavaDoc<String JavaDoc[]> paths ) {
444         
445         if ( paths == null ) {
446             return;
447         }
448         
449         List JavaDoc<Node JavaDoc> selectedNodes = new ArrayList JavaDoc<Node JavaDoc>();
450         
451         Node JavaDoc rootNode = manager.getRootContext();
452         
453         for( Iterator JavaDoc<String JavaDoc[]> it = paths.iterator(); it.hasNext(); ) {
454             String JavaDoc[] sp = it.next();
455             try {
456                 Node JavaDoc n = NodeOp.findPath( rootNode, sp );
457                 if ( n != null ) {
458                     selectedNodes.add( n );
459                 }
460             }
461             catch( NodeNotFoundException e ) {
462                 // Node wont be added
463
}
464         }
465         
466         if ( !selectedNodes.isEmpty() ) {
467             Node JavaDoc nodes[] = new Node JavaDoc[ selectedNodes.size() ];
468             selectedNodes.toArray( nodes );
469             try {
470                 manager.setSelectedNodes( nodes );
471             }
472             catch( PropertyVetoException JavaDoc e ) {
473                 // Bad day no selection change
474
}
475         }
476         
477     }
478     
479     // Private innerclasses ----------------------------------------------------
480

481     /** Extending bean treeview. To be able to persist the selected paths
482      */

483     private class ProjectTreeView extends BeanTreeView {
484         public void scrollToNode(Node JavaDoc n) {
485             TreeNode JavaDoc tn = Visualizer.findVisualizer( n );
486             if (tn == null) return;
487
488             TreeModel JavaDoc model = tree.getModel();
489             if (!(model instanceof DefaultTreeModel JavaDoc)) return;
490
491             TreePath JavaDoc path = new TreePath JavaDoc(((DefaultTreeModel JavaDoc)model).getPathToRoot(tn));
492             Rectangle JavaDoc r = tree.getPathBounds(path);
493             if (r != null) tree.scrollRectToVisible(r);
494     }
495                         
496         public List JavaDoc<String JavaDoc[]> getExpandedPaths() {
497
498             List JavaDoc<String JavaDoc[]> result = new ArrayList JavaDoc<String JavaDoc[]>();
499             
500             TreeNode JavaDoc rtn = Visualizer.findVisualizer( rootNode );
501             TreePath JavaDoc tp = new TreePath JavaDoc( rtn ); // Get the root
502

503             for( Enumeration JavaDoc exPaths = tree.getExpandedDescendants( tp ); exPaths != null && exPaths.hasMoreElements(); ) {
504                 TreePath JavaDoc ep = (TreePath JavaDoc)exPaths.nextElement();
505                 Node JavaDoc en = Visualizer.findNode( ep.getLastPathComponent() );
506                 String JavaDoc[] path = NodeOp.createPath( en, rootNode );
507                 
508                 // System.out.print("EXP "); ProjectTab.print( path );
509

510                 result.add( path );
511             }
512             
513             return result;
514             
515         }
516         
517         /** Expands all the paths, when exists
518          */

519         public void expandNodes( List JavaDoc exPaths ) {
520             
521             for( Iterator JavaDoc it = exPaths.iterator(); it.hasNext(); ) {
522                 String JavaDoc[] sp = (String JavaDoc[])it.next();
523                 TreePath JavaDoc tp = stringPath2TreePath( sp );
524                 
525                 if ( tp != null ) {
526                     showPath( tp );
527                 }
528             }
529         }
530         
531                 
532         
533         /** Converts path of strings to TreePath if exists null otherwise
534          */

535         private TreePath JavaDoc stringPath2TreePath( String JavaDoc[] sp ) {
536
537             try {
538                 Node JavaDoc n = NodeOp.findPath( rootNode, sp );
539                 
540                 // Create the tree path
541
TreeNode JavaDoc tns[] = new TreeNode JavaDoc[ sp.length + 1 ];
542                 
543                 for ( int i = sp.length; i >= 0; i--) {
544                     if ( n == null ) { // Fix for 54832 it seems that sometimes
545
return null; // we get unparented node
546
}
547                     tns[i] = Visualizer.findVisualizer( n );
548                     n = n.getParentNode();
549                 }
550                 return new TreePath JavaDoc( tns );
551             }
552             catch ( NodeNotFoundException e ) {
553                 return null;
554             }
555         }
556         
557     }
558     
559     private class DelegatingAction extends AbstractAction JavaDoc implements PropertyChangeListener JavaDoc {
560         
561         private Action JavaDoc explorerAction;
562         private String JavaDoc projectAction;
563         
564         public DelegatingAction(String JavaDoc projectAction, Action JavaDoc explorerAction) {
565             this.projectAction = projectAction;
566             this.explorerAction = explorerAction;
567             
568             manager.addPropertyChangeListener(this);
569             explorerAction.addPropertyChangeListener(this);
570         }
571         
572         private boolean isProject() {
573             Node JavaDoc[] nodes = manager.getSelectedNodes();
574             
575             if (nodes.length == 1) {
576                 return nodes[0].getParentNode() == rootNode;
577             }
578             
579             return false;
580         }
581         
582         public void actionPerformed(ActionEvent JavaDoc e) {
583             if (isProject()) {
584                 Node JavaDoc[] nodes = manager.getSelectedNodes();
585                 Project p = nodes[0].getLookup().lookup(Project.class);
586                 
587                 assert p != null;
588                 
589                 ActionProvider ap = p.getLookup().lookup(ActionProvider.class);
590                 
591                 ap.invokeAction(projectAction, nodes[0].getLookup());
592             } else {
593                 explorerAction.actionPerformed(e);
594             }
595         }
596         
597         public void updateIsEnabled() {
598             if (isProject()) {
599                 Node JavaDoc[] nodes = manager.getSelectedNodes();
600                 Project p = nodes[0].getLookup().lookup(Project.class);
601                 
602                 if (p == null) {
603                     setEnabled(false);
604                     return ;
605                 }
606                 
607                 ActionProvider ap = p.getLookup().lookup(ActionProvider.class);
608                 
609                 //Fix for #60946: check whether the action is supported before asking whether it is enabled:
610
String JavaDoc[] sa = ap != null ? ap.getSupportedActions() : new String JavaDoc[0];
611                 int k = sa.length;
612                 
613                 for (int i = 0; i < k; i++) {
614                     if (ActionProvider.COMMAND_DELETE.equals(sa [i])) {
615                         setEnabled(ap.isActionEnabled(projectAction, nodes[0].getLookup()));
616                         return ;
617                     }
618                 }
619                 
620                 setEnabled(false);
621             } else {
622                 setEnabled(explorerAction.isEnabled());
623             }
624         }
625         
626         public void propertyChange(PropertyChangeEvent JavaDoc evt) {
627             //a bit brute force:
628
updateIsEnabled();
629         }
630         
631     }
632     
633 }
634
Popular Tags