KickJava   Java API By Example, From Geeks To Geeks.

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


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.beans.PropertyChangeEvent JavaDoc;
23 import java.beans.PropertyChangeListener JavaDoc;
24 import java.io.CharConversionException JavaDoc;
25 import java.lang.ref.Reference JavaDoc;
26 import java.lang.ref.WeakReference JavaDoc;
27 import java.text.MessageFormat JavaDoc;
28 import java.util.ArrayList JavaDoc;
29 import java.util.Arrays JavaDoc;
30 import java.util.Collection JavaDoc;
31 import java.util.Collections JavaDoc;
32 import java.util.Iterator JavaDoc;
33 import java.util.List JavaDoc;
34 import java.util.ResourceBundle JavaDoc;
35 import java.util.WeakHashMap JavaDoc;
36 import javax.swing.Action JavaDoc;
37 import javax.swing.JSeparator JavaDoc;
38 import javax.swing.SwingUtilities JavaDoc;
39 import javax.swing.event.ChangeEvent JavaDoc;
40 import javax.swing.event.ChangeListener JavaDoc;
41 import org.netbeans.api.project.FileOwnerQuery;
42 import org.netbeans.api.project.Project;
43 import org.netbeans.api.project.ProjectUtils;
44 import org.netbeans.api.project.Sources;
45 import org.netbeans.spi.project.ui.LogicalViewProvider;
46 import org.openide.ErrorManager;
47 import org.openide.filesystems.FileObject;
48 import org.openide.filesystems.Repository;
49 import org.openide.loaders.DataFolder;
50 import org.openide.loaders.FolderLookup;
51 import org.openide.nodes.AbstractNode;
52 import org.openide.nodes.Children;
53 import org.openide.nodes.FilterNode;
54 import org.openide.nodes.Node;
55 import org.openide.util.Lookup;
56 import org.openide.util.NbBundle;
57 import org.openide.util.WeakListeners;
58 import org.openide.util.lookup.Lookups;
59 import org.openide.util.lookup.ProxyLookup;
60 import org.openide.xml.XMLUtil;
61 import org.openidex.search.SearchInfo;
62 import org.openidex.search.SearchInfoFactory;
63
64 /** Root node for list of open projects
65  * @author Petr Hrebejk
66  */

67 public class ProjectsRootNode extends AbstractNode {
68     
69     static final int PHYSICAL_VIEW = 0;
70     static final int LOGICAL_VIEW = 1;
71         
72     private static final String JavaDoc ICON_BASE = "org/netbeans/modules/project/ui/resources/projectsRootNode.gif"; //NOI18N
73
private static final String JavaDoc ACTIONS_FOLDER = "ProjectsTabActions"; // NOI18N
74

75     private ResourceBundle JavaDoc bundle;
76     private final int type;
77     
78     public ProjectsRootNode( int type ) {
79         super( new ProjectChildren( type ) );
80         setIconBaseWithExtension( ICON_BASE );
81         this.type = type;
82     }
83         
84     public String JavaDoc getName() {
85         return ( "OpenProjects" ); // NOI18N
86
}
87     
88     public String JavaDoc getDisplayName() {
89         if ( this.bundle == null ) {
90             this.bundle = NbBundle.getBundle( ProjectsRootNode.class );
91         }
92         return bundle.getString( "LBL_OpenProjectsNode_Name" ); // NOI18N
93
}
94     
95     public boolean canRename() {
96         return false;
97     }
98         
99     public Node.Handle getHandle() {
100         return new Handle(type);
101     }
102     
103     public Action JavaDoc[] getActions( boolean context ) {
104         if (context || type == PHYSICAL_VIEW) {
105             return new Action JavaDoc[0];
106         } else {
107             List JavaDoc<Action JavaDoc> actions = new ArrayList JavaDoc<Action JavaDoc>();
108             DataFolder actionsFolder = DataFolder.findFolder(Repository.getDefault().getDefaultFileSystem().findResource(ACTIONS_FOLDER));
109             for (Object JavaDoc o: new FolderLookup(actionsFolder).getLookup().lookupAll(Object JavaDoc.class)) {
110                 if (o instanceof Action JavaDoc) {
111                     actions.add((Action JavaDoc) o);
112                 } else if (o instanceof JSeparator JavaDoc) {
113                     actions.add(null);
114                 }
115             }
116             return actions.toArray(new Action JavaDoc[actions.size()]);
117         }
118     }
119     
120     /** Finds node for given object in the view
121      * @return the node or null if the node was not found
122      */

123     Node findNode(FileObject target) {
124         
125         ProjectChildren ch = (ProjectChildren)getChildren();
126         
127         if ( ch.type == LOGICAL_VIEW ) {
128             Node[] nodes = ch.getNodes( true );
129             // Speed up search in case we have an owner project - look in its node first.
130
Project ownerProject = FileOwnerQuery.getOwner(target);
131             for (int lookOnlyInOwnerProject = (ownerProject != null) ? 0 : 1; lookOnlyInOwnerProject < 2; lookOnlyInOwnerProject++) {
132                 for (int i = 0; i < nodes.length; i++) {
133                     Project p = (Project) nodes[i].getLookup().lookup(Project.class);
134                     assert p != null : "Should have had a Project in lookup of " + nodes[i];
135                     if (lookOnlyInOwnerProject == 0 && p != ownerProject) {
136                         continue; // but try again (in next outer loop) as a fallback
137
}
138                     LogicalViewProvider lvp = (LogicalViewProvider) p.getLookup().lookup(LogicalViewProvider.class);
139                     if (lvp != null) {
140                         // XXX (cf. #63554): really should be calling this on DataObject usually, since
141
// DataNode does *not* currently have a FileObject in its lookup (should it?)
142
// ...but it is not clear who has implemented findPath to assume FileObject!
143
Node selectedNode = lvp.findPath(nodes[i], target);
144                         if (selectedNode != null) {
145                             return selectedNode;
146                         }
147                     }
148                 }
149             }
150             return null;
151             
152         }
153         else if ( ch.type == PHYSICAL_VIEW ) {
154             Node[] nodes = ch.getNodes( true );
155             for( int i = 0; i < nodes.length; i++ ) {
156                 // XXX could do similar optimization as for LOGICAL_VIEW; every nodes[i] must have some Project in its lookup
157
PhysicalView.PathFinder pf = (PhysicalView.PathFinder)nodes[i].getLookup().lookup( PhysicalView.PathFinder.class );
158                 if ( pf != null ) {
159                     Node n = pf.findPath( nodes[i], target );
160                     if ( n != null ) {
161                         return n;
162                     }
163                 }
164             }
165             return null;
166         }
167         else {
168             return null;
169         }
170     }
171     
172     private static class Handle implements Node.Handle {
173
174         private static final long serialVersionUID = 78374332058L;
175         
176         private int viewType;
177         
178         public Handle( int viewType ) {
179             this.viewType = viewType;
180         }
181         
182         public Node getNode() {
183             return new ProjectsRootNode( viewType );
184         }
185         
186     }
187        
188     
189     // XXX Needs to listen to project rename
190
// However project rename is currently disabled so it is not a big deal
191
static class ProjectChildren extends Children.Keys<Project> implements ChangeListener JavaDoc, PropertyChangeListener JavaDoc {
192         
193         private java.util.Map JavaDoc <Sources,Reference JavaDoc<Project>> sources2projects = new WeakHashMap JavaDoc<Sources,Reference JavaDoc<Project>>();
194         
195         int type;
196         
197         public ProjectChildren( int type ) {
198             this.type = type;
199             OpenProjectList.getDefault().addPropertyChangeListener( this );
200         }
201         
202         // Children.Keys impl --------------------------------------------------
203

204         public void addNotify() {
205             setKeys( getKeys() );
206         }
207         
208         public void removeNotify() {
209             for (Sources sources : sources2projects.keySet()) {
210                 sources.removeChangeListener( this );
211             }
212             sources2projects.clear();
213             setKeys(Collections.<Project>emptySet());
214         }
215         
216         protected Node[] createNodes(Project project) {
217             LogicalViewProvider lvp = project.getLookup().lookup(LogicalViewProvider.class);
218             
219             Node nodes[] = null;
220                         
221             if ( type == PHYSICAL_VIEW ) {
222                 Sources sources = ProjectUtils.getSources( project );
223                 sources.removeChangeListener( this );
224                 sources.addChangeListener( this );
225                 sources2projects.put( sources, new WeakReference JavaDoc<Project>( project ) );
226                 nodes = PhysicalView.createNodesForProject( project );
227             }
228             else if ( lvp == null ) {
229                 ErrorManager.getDefault().log(ErrorManager.WARNING, "Warning - project " + ProjectUtils.getInformation(project).getName() + " failed to supply a LogicalViewProvider in its lookup"); // NOI18N
230
Sources sources = ProjectUtils.getSources( project );
231                 sources.removeChangeListener( this );
232                 sources.addChangeListener( this );
233                 nodes = PhysicalView.createNodesForProject( project );
234                 if ( nodes.length > 0 ) {
235                     nodes = new Node[] { nodes[0] };
236                 }
237                 else {
238                     nodes = new Node[] { Node.EMPTY };
239                 }
240             }
241             else {
242                 nodes = new Node[] { lvp.createLogicalView() };
243                 if (nodes[0].getLookup().lookup(Project.class) != project) {
244                     // Various actions, badging, etc. are not going to work.
245
ErrorManager.getDefault().log(ErrorManager.WARNING, "Warning - project " + ProjectUtils.getInformation(project).getName() + " failed to supply itself in the lookup of the root node of its own logical view"); // NOI18N
246
}
247             }
248
249             Node[] badgedNodes = new Node[ nodes.length ];
250             for( int i = 0; i < nodes.length; i++ ) {
251                 if ( type == PHYSICAL_VIEW && !PhysicalView.isProjectDirNode( nodes[i] ) ) {
252                     // Don't badge external sources
253
badgedNodes[i] = nodes[i];
254                 }
255                 else {
256                     badgedNodes[i] = new BadgingNode( nodes[i],
257                                                       type == LOGICAL_VIEW );
258                 }
259             }
260                         
261             return badgedNodes;
262         }
263         
264         // PropertyChangeListener impl -----------------------------------------
265

266         public void propertyChange( PropertyChangeEvent JavaDoc e ) {
267             if ( OpenProjectList.PROPERTY_OPEN_PROJECTS.equals( e.getPropertyName() ) ) {
268                 setKeys( getKeys() );
269             }
270         }
271         
272         // Change listener impl ------------------------------------------------
273

274         public void stateChanged( ChangeEvent JavaDoc e ) {
275             
276             Reference JavaDoc<Project> projectRef = sources2projects.get(e.getSource());
277             if ( projectRef == null ) {
278                 return;
279             }
280             
281             final Project project = projectRef.get();
282             
283             if ( project == null ) {
284                 return;
285             }
286             
287             // Fix for 50259, callers sometimes hold locks
288
SwingUtilities.invokeLater( new Runnable JavaDoc() {
289                 public void run() {
290                     refreshKey( project );
291                 }
292             } );
293         }
294                                 
295         // Own methods ---------------------------------------------------------
296

297         public Collection JavaDoc<Project> getKeys() {
298             List JavaDoc<Project> projects = Arrays.asList( OpenProjectList.getDefault().getOpenProjects() );
299             Collections.sort( projects, OpenProjectList.PROJECT_BY_DISPLAYNAME );
300             
301             return projects;
302         }
303                                                 
304     }
305         
306     private static final class BadgingNode extends FilterNode implements PropertyChangeListener JavaDoc {
307
308         private static String JavaDoc badgedNamePattern = NbBundle.getMessage( ProjectsRootNode.class, "LBL_MainProject_BadgedNamePattern" );
309         
310         public BadgingNode( Node n, boolean addSearchInfo ) {
311             super( n,
312                    null, //default children
313
addSearchInfo
314                    ? new ProxyLookup( new Lookup[] {
315                          n.getLookup(),
316                          Lookups.singleton(alwaysSearchableSearchInfo(SearchInfoFactory
317                                             .createSearchInfoBySubnodes(n))),
318                     })
319                    : n.getLookup() );
320             OpenProjectList.getDefault().addPropertyChangeListener( WeakListeners.propertyChange( this, OpenProjectList.getDefault() ) );
321         }
322         
323         public String JavaDoc getDisplayName() {
324             String JavaDoc original = super.getDisplayName();
325             return isMain() ? MessageFormat.format( badgedNamePattern, new Object JavaDoc[] { original } ) : original;
326         }
327
328         public String JavaDoc getHtmlDisplayName() {
329             String JavaDoc htmlName = getOriginal().getHtmlDisplayName();
330             String JavaDoc dispName = null;
331             if (isMain() && htmlName == null) {
332                 dispName = super.getDisplayName();
333                 try {
334                     dispName = XMLUtil.toElementContent(dispName);
335                 } catch (CharConversionException JavaDoc ex) {
336                     // ignore
337
}
338             }
339             return isMain() ? "<b>" + (htmlName == null ? dispName : htmlName) + "</b>" : htmlName; //NOI18N
340
}
341
342         public void propertyChange( PropertyChangeEvent JavaDoc e ) {
343             if ( OpenProjectList.PROPERTY_MAIN_PROJECT.equals( e.getPropertyName() ) ) {
344                 fireDisplayNameChange( null, null );
345             }
346         }
347
348         private boolean isMain() {
349             Project p = (Project)getLookup().lookup( Project.class );
350             return p != null && OpenProjectList.getDefault().isMainProject( p );
351         }
352         
353     }
354     
355     /**
356      * Produce a {@link SearchInfo} variant that is always searchable, for speed.
357      * @see "#48685"
358      */

359     static SearchInfo alwaysSearchableSearchInfo(SearchInfo i) {
360         return new AlwaysSearchableSearchInfo(i);
361     }
362     
363     private static final class AlwaysSearchableSearchInfo implements SearchInfo {
364         
365         private final SearchInfo delegate;
366         
367         public AlwaysSearchableSearchInfo(SearchInfo delegate) {
368             this.delegate = delegate;
369         }
370
371         public boolean canSearch() {
372             return true;
373         }
374
375         public Iterator JavaDoc/*<DataObject>*/ objectsToSearch() {
376             return delegate.objectsToSearch();
377         }
378         
379     }
380     
381 }
382
Popular Tags