KickJava   Java API By Example, From Geeks To Geeks.

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


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.text.MessageFormat JavaDoc;
25 import java.util.ArrayList JavaDoc;
26 import java.util.Collections JavaDoc;
27 import java.util.StringTokenizer JavaDoc;
28 import javax.swing.Action JavaDoc;
29 import javax.swing.event.ChangeEvent JavaDoc;
30 import javax.swing.event.ChangeListener JavaDoc;
31 import javax.swing.event.EventListenerList JavaDoc;
32 import org.netbeans.api.project.Project;
33 import org.netbeans.api.project.ProjectUtils;
34 import org.netbeans.api.project.ProjectInformation;
35 import org.netbeans.api.project.SourceGroup;
36 import org.netbeans.api.project.Sources;
37 import org.netbeans.api.queries.VisibilityQuery;
38 import org.netbeans.spi.project.ui.support.CommonProjectActions;
39 import org.openide.ErrorManager;
40 import org.openide.filesystems.FileObject;
41 import org.openide.filesystems.FileUtil;
42 import org.openide.loaders.ChangeableDataFilter;
43 import org.openide.loaders.DataFilter;
44 import org.openide.loaders.DataFolder;
45 import org.openide.loaders.DataObject;
46 import org.openide.loaders.DataObjectNotFoundException;
47 import org.openide.nodes.FilterNode;
48 import org.openide.nodes.Node;
49 import org.openide.nodes.NodeNotFoundException;
50 import org.openide.nodes.NodeOp;
51 import org.openide.util.NbBundle;
52 import org.openide.util.Lookup;
53 import org.openide.util.WeakListeners;
54 import org.openide.util.lookup.Lookups;
55 import org.openide.util.lookup.ProxyLookup;
56
57 /**
58  * Support for creating logical views.
59  * @author Jesse Glick, Petr Hrebejk
60  */

61 public class PhysicalView {
62         
63     public static boolean isProjectDirNode( Node n ) {
64         return n instanceof GroupNode && ((GroupNode)n).isProjectDir;
65     }
66     
67     public static Node[] createNodesForProject( Project p ) {
68         Sources s = ProjectUtils.getSources(p);
69         SourceGroup[] groups = s.getSourceGroups(Sources.TYPE_GENERIC);
70                 
71         FileObject projectDirectory = p.getProjectDirectory();
72         SourceGroup projectDirGroup = null;
73         
74         // First find the source group which will represent the project
75
for( int i = 0; i < groups.length; i++ ) {
76             FileObject groupRoot = groups[i].getRootFolder();
77             if ( projectDirectory.equals( groupRoot ) ||
78                  FileUtil.isParentOf( groupRoot, projectDirectory ) ) {
79                 if ( projectDirGroup != null ) {
80                     // more than once => Illegal
81
projectDirGroup = null;
82                     break;
83                 }
84                 else {
85                     projectDirGroup = groups[i];
86                 }
87             }
88         }
89         
90         if ( projectDirGroup == null ) {
91             // Illegal project
92
ErrorManager.getDefault().log(ErrorManager.WARNING,
93                     "Project " + p + // NOI18N
94
"either does not contain it's project directory under the " + // NOI18N
95
"Generic source groups or the project directory is under " + // NOI18N
96
"more than one source group"); // NOI18N
97
return new Node[0];
98         }
99         
100                     
101         // Create the nodes
102
ArrayList JavaDoc<Node> nodesList = new ArrayList JavaDoc<Node>( groups.length );
103         nodesList.add(/*new GroupContainmentFilterNode(*/new GroupNode(p, projectDirGroup, true, DataFolder.findFolder(projectDirGroup.getRootFolder()))/*, projectDirGroup)*/);
104         
105         for( int i = 0; i < groups.length; i++ ) {
106             
107             if ( groups[i] == projectDirGroup ) {
108                 continue;
109             }
110             
111             nodesList.add(/*new GroupContainmentFilterNode(*/new GroupNode(p, groups[i], false, DataFolder.findFolder(groups[i].getRootFolder()))/*, groups[i])*/);
112         }
113         
114         Node nodes[] = new Node[ nodesList.size() ];
115         nodesList.toArray( nodes );
116         return nodes;
117     }
118    
119     static final class VisibilityQueryDataFilter implements ChangeListener JavaDoc, ChangeableDataFilter {
120         
121         EventListenerList JavaDoc ell = new EventListenerList JavaDoc();
122         
123         public VisibilityQueryDataFilter() {
124             VisibilityQuery.getDefault().addChangeListener( this );
125         }
126                 
127         public boolean acceptDataObject(DataObject obj) {
128             FileObject fo = obj.getPrimaryFile();
129             return VisibilityQuery.getDefault().isVisible( fo );
130         }
131         
132         public void stateChanged( ChangeEvent JavaDoc e) {
133             Object JavaDoc[] listeners = ell.getListenerList();
134             ChangeEvent JavaDoc event = null;
135             for (int i = listeners.length-2; i>=0; i-=2) {
136                 if (listeners[i] == ChangeListener JavaDoc.class) {
137                     if ( event == null) {
138                         event = new ChangeEvent JavaDoc( this );
139                     }
140                     ((ChangeListener JavaDoc)listeners[i+1]).stateChanged( event );
141                 }
142             }
143         }
144     
145         public void addChangeListener( ChangeListener JavaDoc listener ) {
146             ell.add( ChangeListener JavaDoc.class, listener );
147         }
148                         
149         public void removeChangeListener( ChangeListener JavaDoc listener ) {
150             ell.remove( ChangeListener JavaDoc.class, listener );
151         }
152         
153     }
154     
155     static final class GroupNode extends FilterNode implements PropertyChangeListener JavaDoc {
156         
157         private static final DataFilter VISIBILITY_QUERY_FILTER = new VisibilityQueryDataFilter();
158         
159         static final String JavaDoc GROUP_NAME_PATTERN = NbBundle.getMessage(
160             PhysicalView.class, "FMT_PhysicalView_GroupName" ); // NOI18N
161

162         private Project project;
163         private ProjectInformation pi;
164         private SourceGroup group;
165         private boolean isProjectDir;
166
167         public GroupNode(Project project, SourceGroup group, boolean isProjectDir, DataFolder dataFolder ) {
168             super( dataFolder.getNodeDelegate(),
169                    dataFolder.createNodeChildren( VISIBILITY_QUERY_FILTER ),
170                    createLookup( project, group, dataFolder ) );
171
172             this.project = project;
173             this.pi = ProjectUtils.getInformation( project );
174             this.group = group;
175             this.isProjectDir = isProjectDir;
176             pi.addPropertyChangeListener(WeakListeners.propertyChange(this, pi));
177             group.addPropertyChangeListener( WeakListeners.propertyChange( this, group ) );
178         }
179
180         // XXX May need to change icons as well
181

182         public String JavaDoc getName() {
183             if ( isProjectDir ) {
184                 return pi.getName();
185             }
186             else {
187                 String JavaDoc n = group.getName();
188                 if (n == null) {
189                     n = "???"; // NOI18N
190
ErrorManager.getDefault().log(ErrorManager.WARNING, "SourceGroup impl of type " + group.getClass().getName() + " specified a null getName(); this is illegal");
191                 }
192                 return n;
193             }
194         }
195
196         public String JavaDoc getDisplayName() {
197             if ( isProjectDir ) {
198                 return pi.getDisplayName();
199             }
200             else {
201                 return MessageFormat.format( GROUP_NAME_PATTERN,
202                     new Object JavaDoc[] { group.getDisplayName(), pi.getDisplayName(), getOriginal().getDisplayName() } );
203             }
204         }
205
206         public String JavaDoc getShortDescription() {
207             FileObject gdir = group.getRootFolder();
208             String JavaDoc dir = FileUtil.getFileDisplayName(gdir);
209             return NbBundle.getMessage(PhysicalView.class,
210                                        isProjectDir ? "HINT_project" : "HINT_group", // NOI18N
211
dir);
212         }
213
214         public boolean canRename() {
215             return false;
216         }
217
218         public boolean canCut() {
219             return false;
220         }
221
222         public boolean canCopy() {
223             // At least for now.
224
return false;
225         }
226
227         public boolean canDestroy() {
228             return false;
229         }
230
231         public Action JavaDoc[] getActions( boolean context ) {
232
233             if ( context ) {
234                 return super.getActions( true );
235             }
236             else {
237                 Action JavaDoc[] folderActions = super.getActions( false );
238                 Action JavaDoc[] projectActions;
239                 
240                 if ( isProjectDir ) {
241                     // If this is project dir then the properties action
242
// has to be replaced to invoke project customizer
243
projectActions = new Action JavaDoc[ folderActions.length ];
244                     for ( int i = 0; i < folderActions.length; i++ ) {
245                         if ( folderActions[i] instanceof org.openide.actions.PropertiesAction ) {
246                             projectActions[i] = CommonProjectActions.customizeProjectAction();
247                         }
248                         else {
249                             projectActions[i] = folderActions[i];
250                         }
251                     }
252                 }
253                 else {
254                     projectActions = folderActions;
255                 }
256                 
257                 return projectActions;
258             }
259         }
260
261         // Private methods -------------------------------------------------
262

263         public void propertyChange(PropertyChangeEvent JavaDoc evt) {
264             String JavaDoc prop = evt.getPropertyName();
265             if (ProjectInformation.PROP_DISPLAY_NAME.equals(prop)) {
266                 fireDisplayNameChange(null, null);
267             } else if (ProjectInformation.PROP_NAME.equals(prop)) {
268                 fireNameChange(null, null);
269             } else if (ProjectInformation.PROP_ICON.equals(prop)) {
270                 // OK, ignore
271
} else if ( "name".equals(prop) ) { // NOI18N
272
fireNameChange(null, null);
273             } else if ( "displayName".equals(prop) ) { // NOI18N
274
fireDisplayNameChange(null, null);
275             } else if ( "icon".equals(prop) ) { // NOI18N
276
// OK, ignore
277
} else if ( "rootFolder".equals(prop) ) { // NOI18N
278
// XXX Do something to children and lookup
279
fireNameChange(null, null);
280                 fireDisplayNameChange(null, null);
281                 fireShortDescriptionChange(null, null);
282             } else if (SourceGroup.PROP_CONTAINERSHIP.equals(prop)) {
283                 // OK, ignore
284
} else {
285                 assert false : "Attempt to fire an unsupported property change event from " + pi.getClass().getName() + ": " + prop;
286             }
287         }
288         
289         private static Lookup createLookup( Project p, SourceGroup group, DataFolder dataFolder ) {
290             return new ProxyLookup(new Lookup[] {
291                 dataFolder.getNodeDelegate().getLookup(),
292                 Lookups.fixed( new Object JavaDoc[] { p, new PathFinder( group ) } ),
293                 p.getLookup(),
294             });
295         }
296
297     }
298     
299     /* XXX disabled for now pending resolution of interaction with planned VCS annotations (color only):
300     /**
301      * Specially displays nodes corresponding to files which are not contained in this source group.
302      * /
303     private static final class GroupContainmentFilterNode extends FilterNode {
304         
305         private final SourceGroup g;
306         
307         public GroupContainmentFilterNode(Node orig, SourceGroup g) {
308             super(orig, orig.isLeaf() ? Children.LEAF : new GroupContainmentFilterChildren(orig, g));
309             this.g = g;
310         }
311         
312         public String getHtmlDisplayName() {
313             Node orig = getOriginal();
314             DataObject d = (DataObject) orig.getCookie(DataObject.class);
315             assert d != null : orig;
316             FileObject f = d.getPrimaryFile();
317             String barename = orig.getHtmlDisplayName();
318             if (!FileUtil.isParentOf(g.getRootFolder(), f) || g.contains(f)) {
319                 // Leave it alone.
320                 return barename;
321             }
322             // Try to grey it out.
323             if (barename == null) {
324                 try {
325                     barename = XMLUtil.toElementContent(orig.getDisplayName());
326                 } catch (CharConversionException e) {
327                     // Never mind.
328                     return null;
329                 }
330             }
331             return "<font color='!Label.disabledForeground'>" + barename + "</font>"; // NOI18N
332         }
333         
334         private static final class GroupContainmentFilterChildren extends FilterNode.Children {
335             
336             private final SourceGroup g;
337             
338             public GroupContainmentFilterChildren(Node orig, SourceGroup g) {
339                 super(orig);
340                 this.g = g;
341             }
342             
343             protected Node copyNode(Node node) {
344                 if (original.getCookie(DataFolder.class) != null && node.getCookie(DataObject.class) != null) {
345                     return new GroupContainmentFilterNode(node, g);
346                 } else {
347                     return super.copyNode(node);
348                 }
349             }
350             
351         }
352         
353     }
354      */

355     
356     public static class PathFinder {
357         
358         private SourceGroup group;
359         
360         public PathFinder( SourceGroup group ) {
361             this.group = group;
362         }
363         
364         public Node findPath( Node root, Object JavaDoc object ) {
365                  
366             if ( !( object instanceof FileObject ) ) {
367                 return null;
368             }
369             
370             FileObject fo = (FileObject)object;
371             FileObject groupRoot = group.getRootFolder();
372             if ( FileUtil.isParentOf( groupRoot, fo ) /* && group.contains( fo ) */ ) {
373                 // The group contains the object
374

375                 String JavaDoc relPath = FileUtil.getRelativePath( groupRoot, fo );
376                 
377                 ArrayList JavaDoc<String JavaDoc> path = new ArrayList JavaDoc<String JavaDoc>();
378                 StringTokenizer JavaDoc strtok = new StringTokenizer JavaDoc( relPath, "/" );
379                 while( strtok.hasMoreTokens() ) {
380                    path.add( strtok.nextToken() );
381                 }
382                 
383                 String JavaDoc name = fo.getName();
384                 
385                 try {
386                     DataObject dobj = DataObject.find( fo );
387                     name = dobj.getNodeDelegate().getName();
388                 }
389                 catch( DataObjectNotFoundException e ) {
390                 }
391                 
392                 path.set( path.size() - 1, name );
393                                  
394                 try {
395                     return NodeOp.findPath( root, Collections.enumeration( path ) );
396                 }
397                 catch ( NodeNotFoundException e ) {
398                     return null;
399                 }
400             }
401             else if ( groupRoot.equals( fo ) ) {
402                 return root;
403             }
404
405             return null;
406         }
407                     
408     }
409     
410 }
411
Popular Tags