KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > modules > ruby > railsprojects > ui > RailsLogicalViewProvider


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.ruby.railsprojects.ui;
21
22 import java.awt.Image JavaDoc;
23 import java.awt.event.ActionEvent JavaDoc;
24 import java.beans.PropertyChangeEvent JavaDoc;
25 import java.beans.PropertyChangeListener JavaDoc;
26 import java.io.CharConversionException JavaDoc;
27 import java.io.IOException JavaDoc;
28 import java.util.ArrayList JavaDoc;
29 import java.util.Arrays JavaDoc;
30 import java.util.Collection JavaDoc;
31 import java.util.HashMap JavaDoc;
32 import java.util.HashSet JavaDoc;
33 import java.util.Iterator JavaDoc;
34 import java.util.List JavaDoc;
35 import java.util.Map JavaDoc;
36 import java.util.ResourceBundle JavaDoc;
37 import java.util.Set JavaDoc;
38 import javax.swing.AbstractAction JavaDoc;
39 import javax.swing.Action JavaDoc;
40 import javax.swing.JSeparator JavaDoc;
41 import javax.swing.event.ChangeEvent JavaDoc;
42 import javax.swing.event.ChangeListener JavaDoc;
43 import org.netbeans.modules.ruby.railsprojects.GenerateAction;
44 import org.netbeans.modules.ruby.railsprojects.RailsActionProvider;
45 import org.netbeans.api.project.FileOwnerQuery;
46 import org.netbeans.api.project.Project;
47 import org.netbeans.api.project.ProjectUtils;
48 import org.netbeans.api.project.SourceGroup;
49 import org.netbeans.api.project.Sources;
50 import org.netbeans.modules.ruby.railsprojects.RailsProjectUtil;
51 import org.netbeans.modules.ruby.railsprojects.ui.customizer.RailsProjectProperties;
52 import org.netbeans.modules.ruby.railsprojects.RailsProject;
53 import org.netbeans.modules.ruby.railsprojects.SourceRoots;
54 import org.netbeans.modules.ruby.railsprojects.UpdateHelper;
55 import org.netbeans.spi.project.ActionProvider;
56 import org.netbeans.spi.project.SubprojectProvider;
57 import org.netbeans.modules.ruby.spi.project.support.rake.PropertyEvaluator;
58 import org.netbeans.modules.ruby.spi.project.support.rake.ReferenceHelper;
59 import org.netbeans.spi.project.ui.LogicalViewProvider;
60 import org.netbeans.spi.project.ui.support.CommonProjectActions;
61 import org.netbeans.spi.project.ui.support.NodeFactorySupport;
62 import org.netbeans.spi.project.ui.support.DefaultProjectOperations;
63 import org.netbeans.spi.project.ui.support.ProjectSensitiveActions;
64 import org.openide.ErrorManager;
65 import org.openide.actions.FindAction;
66 import org.openide.actions.ToolsAction;
67 import org.openide.filesystems.FileObject;
68 import org.openide.filesystems.FileStateInvalidException;
69 import org.openide.filesystems.FileStatusEvent;
70 import org.openide.filesystems.FileStatusListener;
71 import org.openide.filesystems.FileSystem;
72 import org.openide.filesystems.FileUtil;
73 import org.openide.filesystems.Repository;
74 import org.openide.loaders.DataFolder;
75 import org.openide.loaders.DataObject;
76 import org.openide.loaders.DataObjectNotFoundException;
77 import org.openide.loaders.FolderLookup;
78 import org.openide.modules.SpecificationVersion;
79 import org.openide.nodes.AbstractNode;
80 import org.openide.nodes.Node;
81 import org.openide.util.HelpCtx;
82 import org.openide.util.Lookup;
83 import org.openide.util.NbBundle;
84 import org.openide.util.RequestProcessor;
85 import org.openide.util.Utilities;
86 import org.openide.util.WeakListeners;
87 import org.openide.util.actions.SystemAction;
88 import org.openide.util.lookup.Lookups;
89 import org.openide.xml.XMLUtil;
90
91 /**
92  * Support for creating logical views.
93  * @author Petr Hrebejk
94  */

95 public class RailsLogicalViewProvider implements LogicalViewProvider {
96     
97     //private static final RequestProcessor BROKEN_LINKS_RP = new RequestProcessor("RubyPhysicalViewProvider.BROKEN_LINKS_RP"); // NOI18N
98

99     private final RailsProject project;
100     private final UpdateHelper helper;
101     private final PropertyEvaluator evaluator;
102     private final SubprojectProvider spp;
103     private final ReferenceHelper resolver;
104     private List JavaDoc changeListeners;
105     
106     public RailsLogicalViewProvider(RailsProject project, UpdateHelper helper, PropertyEvaluator evaluator, SubprojectProvider spp, ReferenceHelper resolver) {
107         this.project = project;
108         assert project != null;
109         this.helper = helper;
110         assert helper != null;
111         this.evaluator = evaluator;
112         assert evaluator != null;
113         this.spp = spp;
114         assert spp != null;
115         this.resolver = resolver;
116     }
117     
118     public Node createLogicalView() {
119         return new RailsLogicalViewRootNode();
120     }
121     
122     public PropertyEvaluator getEvaluator() {
123         return evaluator;
124     }
125     
126     public ReferenceHelper getRefHelper() {
127         return resolver;
128     }
129     
130     public UpdateHelper getUpdateHelper() {
131         return helper;
132     }
133     
134     public Node findPath(Node root, Object JavaDoc target) {
135         Project project = (Project) root.getLookup().lookup(Project.class);
136         if (project == null) {
137             return null;
138         }
139         
140         if (target instanceof FileObject) {
141             FileObject fo = (FileObject) target;
142             Project owner = FileOwnerQuery.getOwner(fo);
143             if (!project.equals(owner)) {
144                 return null; // Don't waste time if project does not own the fo
145
}
146             
147             Node[] nodes = root.getChildren().getNodes(true);
148             for (int i = 0; i < nodes.length; i++) {
149                 TreeRootNode.PathFinder pf2 = (TreeRootNode.PathFinder) nodes[i].getLookup().lookup(TreeRootNode.PathFinder.class);
150                 if (pf2 != null) {
151                     Node n = pf2.findPath(nodes[i], target);
152                     if (n != null) {
153                         return n;
154                     }
155                 }
156             }
157         }
158         
159         return null;
160     }
161     
162     
163     
164     public synchronized void addChangeListener(ChangeListener JavaDoc l) {
165         if (this.changeListeners == null) {
166             this.changeListeners = new ArrayList JavaDoc();
167         }
168         this.changeListeners.add(l);
169     }
170     
171     public synchronized void removeChangeListener(ChangeListener JavaDoc l) {
172         if (this.changeListeners == null) {
173             return;
174         }
175         this.changeListeners.remove(l);
176     }
177     
178     /**
179      * Used by RailsProjectCustomizer to mark the project as broken when it warns user
180      * about project's broken references and advices him to use BrokenLinksAction to correct it.
181      *
182      */

183     public void testBroken() {
184         ChangeListener JavaDoc[] _listeners;
185         synchronized (this) {
186             if (this.changeListeners == null) {
187                 return;
188             }
189             _listeners = (ChangeListener JavaDoc[]) this.changeListeners.toArray(
190                     new ChangeListener JavaDoc[this.changeListeners.size()]);
191         }
192         ChangeEvent JavaDoc event = new ChangeEvent JavaDoc(this);
193         for (int i=0; i < _listeners.length; i++) {
194             _listeners[i].stateChanged(event);
195         }
196     }
197     
198 // private static Lookup createLookup( Project project ) {
199
// DataFolder rootFolder = DataFolder.findFolder(project.getProjectDirectory());
200
// // XXX Remove root folder after FindAction rewrite
201
// return Lookups.fixed(new Object[] {project, rootFolder});
202
// }
203

204     
205     // Private innerclasses ----------------------------------------------------------------
206

207     private static final String JavaDoc[] BREAKABLE_PROPERTIES = new String JavaDoc[] {
208         RailsProjectProperties.JAVAC_CLASSPATH,
209         RailsProjectProperties.RUN_CLASSPATH,
210         RailsProjectProperties.DEBUG_CLASSPATH,
211         RailsProjectProperties.RUN_TEST_CLASSPATH,
212         RailsProjectProperties.DEBUG_TEST_CLASSPATH,
213         RailsProjectProperties.JAVAC_TEST_CLASSPATH,
214     };
215     
216     private static Image JavaDoc brokenProjectBadge = Utilities.loadImage("org/netbeans/modules/ruby/railsprojects/ui/resources/brokenProjectBadge.gif", true);
217     
218     /** Filter node containin additional features for the Ruby physical
219      */

220     private final class RailsLogicalViewRootNode extends AbstractNode implements Runnable JavaDoc, FileStatusListener, ChangeListener JavaDoc, PropertyChangeListener JavaDoc {
221         private Set JavaDoc files;
222         private Map JavaDoc fileSystemListeners;
223         private RequestProcessor.Task task;
224         private final Object JavaDoc privateLock = new Object JavaDoc();
225         private boolean iconChange;
226         private boolean nameChange;
227         private ChangeListener JavaDoc sourcesListener;
228         private Map JavaDoc groupsListeners;
229         
230         public RailsLogicalViewRootNode() {
231             super(NodeFactorySupport.createCompositeChildren(project, "Projects/org-netbeans-modules-ruby-railsprojects/Nodes"), // NOI18N
232
Lookups.singleton(project));
233             setIconBaseWithExtension("org/netbeans/modules/ruby/railsprojects/ui/resources/rails.png"); // NOI18N
234
super.setName( ProjectUtils.getInformation( project ).getDisplayName() );
235             setProjectFiles(project);
236         }
237         
238         protected final void setProjectFiles(Project project) {
239             Sources sources = ProjectUtils.getSources(project); // returns singleton
240
if (sourcesListener == null) {
241                 sourcesListener = WeakListeners.change(this, sources);
242                 sources.addChangeListener(sourcesListener);
243             }
244             setGroups(Arrays.asList(sources.getSourceGroups(Sources.TYPE_GENERIC)));
245         }
246         
247         
248         private final void setGroups(Collection JavaDoc groups) {
249             if (groupsListeners != null) {
250                 Iterator JavaDoc it = groupsListeners.keySet().iterator();
251                 while (it.hasNext()) {
252                     SourceGroup group = (SourceGroup) it.next();
253                     PropertyChangeListener JavaDoc pcl = (PropertyChangeListener JavaDoc) groupsListeners.get(group);
254                     group.removePropertyChangeListener(pcl);
255                 }
256             }
257             groupsListeners = new HashMap JavaDoc();
258             Set JavaDoc roots = new HashSet JavaDoc();
259             Iterator JavaDoc it = groups.iterator();
260             while (it.hasNext()) {
261                 SourceGroup group = (SourceGroup) it.next();
262                 PropertyChangeListener JavaDoc pcl = WeakListeners.propertyChange(this, group);
263                 groupsListeners.put(group, pcl);
264                 group.addPropertyChangeListener(pcl);
265                 FileObject fo = group.getRootFolder();
266                 roots.add(fo);
267             }
268             setFiles(roots);
269         }
270         
271         protected final void setFiles(Set JavaDoc files) {
272             if (fileSystemListeners != null) {
273                 Iterator JavaDoc it = fileSystemListeners.keySet().iterator();
274                 while (it.hasNext()) {
275                     FileSystem fs = (FileSystem) it.next();
276                     FileStatusListener fsl = (FileStatusListener) fileSystemListeners.get(fs);
277                     fs.removeFileStatusListener(fsl);
278                 }
279             }
280             
281             fileSystemListeners = new HashMap JavaDoc();
282             this.files = files;
283             if (files == null) {
284                 return;
285             }
286             
287             Iterator JavaDoc it = files.iterator();
288             Set JavaDoc hookedFileSystems = new HashSet JavaDoc();
289             while (it.hasNext()) {
290                 FileObject fo = (FileObject) it.next();
291                 try {
292                     FileSystem fs = fo.getFileSystem();
293                     if (hookedFileSystems.contains(fs)) {
294                         continue;
295                     }
296                     hookedFileSystems.add(fs);
297                     FileStatusListener fsl = FileUtil.weakFileStatusListener(this, fs);
298                     fs.addFileStatusListener(fsl);
299                     fileSystemListeners.put(fs, fsl);
300                 } catch (FileStateInvalidException e) {
301                     ErrorManager err = ErrorManager.getDefault();
302                     err.annotate(e, ErrorManager.UNKNOWN, "Cannot get " + fo + " filesystem, ignoring...", null, null, null); // NO18N
303
err.notify(ErrorManager.INFORMATIONAL, e);
304                 }
305             }
306         }
307         
308 // public String getHtmlDisplayName() {
309
// String dispName = super.getDisplayName();
310
// try {
311
// dispName = XMLUtil.toElementContent(dispName);
312
// } catch (CharConversionException ex) {
313
// return dispName;
314
// }
315
// // XXX text colors should be taken from UIManager, not hard-coded!
316
// //return broken || illegalState ? "<font color=\"#A40000\">" + dispName + "</font>" : null; //NOI18N
317
// return null;
318
// }
319

320         public Image JavaDoc getIcon(int type) {
321             Image JavaDoc img = getMyIcon(type);
322             
323             if (files != null && files.iterator().hasNext()) {
324                 try {
325                     FileObject fo = (FileObject) files.iterator().next();
326                     img = fo.getFileSystem().getStatus().annotateIcon(img, type, files);
327                 } catch (FileStateInvalidException e) {
328                     ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, e);
329                 }
330             }
331             
332             return img;
333         }
334         
335         private Image JavaDoc getMyIcon(int type) {
336             Image JavaDoc original = super.getIcon(type);
337 // return broken || illegalState ? Utilities.mergeImages(original, brokenProjectBadge, 8, 0) : original;
338
return original;
339         }
340         
341         public Image JavaDoc getOpenedIcon(int type) {
342             Image JavaDoc img = getMyOpenedIcon(type);
343             
344             if (files != null && files.iterator().hasNext()) {
345                 try {
346                     FileObject fo = (FileObject) files.iterator().next();
347                     img = fo.getFileSystem().getStatus().annotateIcon(img, type, files);
348                 } catch (FileStateInvalidException e) {
349                     ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, e);
350                 }
351             }
352             
353             return img;
354         }
355         
356         private Image JavaDoc getMyOpenedIcon(int type) {
357             Image JavaDoc original = super.getOpenedIcon(type);
358             //return broken || illegalState ? Utilities.mergeImages(original, brokenProjectBadge, 8, 0) : original;
359
return original;
360         }
361         
362         public void run() {
363             boolean fireIcon;
364             boolean fireName;
365             synchronized (privateLock) {
366                 fireIcon = iconChange;
367                 fireName = nameChange;
368                 iconChange = false;
369                 nameChange = false;
370             }
371             if (fireIcon) {
372                 fireIconChange();
373                 fireOpenedIconChange();
374             }
375             if (fireName) {
376                 fireDisplayNameChange(null, null);
377             }
378         }
379         
380         public void annotationChanged(FileStatusEvent event) {
381             if (task == null) {
382                 task = RequestProcessor.getDefault().create(this);
383             }
384             
385             synchronized (privateLock) {
386                 if ((iconChange == false && event.isIconChange()) || (nameChange == false && event.isNameChange())) {
387                     Iterator JavaDoc it = files.iterator();
388                     while (it.hasNext()) {
389                         FileObject fo = (FileObject) it.next();
390                         if (event.hasChanged(fo)) {
391                             iconChange |= event.isIconChange();
392                             nameChange |= event.isNameChange();
393                         }
394                     }
395                 }
396             }
397             
398             task.schedule(50); // batch by 50 ms
399
}
400         
401         // sources change
402
public void stateChanged(ChangeEvent JavaDoc e) {
403             setProjectFiles(project);
404         }
405         
406         // group change
407
public void propertyChange(PropertyChangeEvent JavaDoc evt) {
408             setProjectFiles(project);
409         }
410         
411         public Action JavaDoc[] getActions( boolean context ) {
412             return getAdditionalActions();
413         }
414         
415         public boolean canRename() {
416             return true;
417         }
418         
419         public void setName(String JavaDoc s) {
420             DefaultProjectOperations.performDefaultRenameOperation(project, s);
421         }
422         
423         public HelpCtx getHelpCtx() {
424             return new HelpCtx(RailsLogicalViewRootNode.class);
425         }
426         
427         /*
428         public boolean canDestroy() {
429             return true;
430         }
431          
432         public void destroy() throws IOException {
433             System.out.println("Destroy " + project.getProjectDirectory());
434             LogicalViews.closeProjectAction().actionPerformed(new ActionEvent(this, 0, ""));
435             project.getProjectDirectory().delete();
436         }
437          */

438         
439         // Private methods -------------------------------------------------------------
440

441         private Action JavaDoc[] getAdditionalActions() {
442             
443             ResourceBundle JavaDoc bundle = NbBundle.getBundle(RailsLogicalViewProvider.class);
444             
445             List JavaDoc actions = new ArrayList JavaDoc();
446             
447             actions.add(SystemAction.get(GenerateAction.class));
448             actions.add(null);
449             actions.add(CommonProjectActions.newFileAction());
450             actions.add(null);
451             //actions.add(ProjectSensitiveActions.projectCommandAction(ActionProvider.COMMAND_BUILD, bundle.getString("LBL_BuildAction_Name"), null)); // NOI18N
452
//actions.add(ProjectSensitiveActions.projectCommandAction(ActionProvider.COMMAND_REBUILD, bundle.getString("LBL_RebuildAction_Name"), null)); // NOI18N
453
//actions.add(ProjectSensitiveActions.projectCommandAction(ActionProvider.COMMAND_CLEAN, bundle.getString("LBL_CleanAction_Name"), null)); // NOI18N
454
//actions.add(null);
455
actions.add(ProjectSensitiveActions.projectCommandAction(RailsActionProvider.COMMAND_RDOC, bundle.getString("LBL_RDocAction_Name"), null)); // NOI18N
456
actions.add(null);
457             actions.add(ProjectSensitiveActions.projectCommandAction(ActionProvider.COMMAND_RUN, bundle.getString("LBL_RunAction_Name"), null)); // NOI18N
458
//actions.add(ProjectSensitiveActions.projectCommandAction(ActionProvider.COMMAND_DEBUG, bundle.getString("LBL_DebugAction_Name"), null)); // NOI18N
459
//actions.add(ProjectSensitiveActions.projectCommandAction(ActionProvider.COMMAND_TEST, bundle.getString("LBL_TestAction_Name"), null)); // NOI18N
460
actions.add(CommonProjectActions.setProjectConfigurationAction());
461             actions.add(null);
462             actions.add(CommonProjectActions.setAsMainProjectAction());
463             actions.add(CommonProjectActions.openSubprojectsAction());
464             actions.add(CommonProjectActions.closeProjectAction());
465             actions.add(null);
466             actions.add(CommonProjectActions.renameProjectAction());
467             actions.add(CommonProjectActions.moveProjectAction());
468             actions.add(CommonProjectActions.copyProjectAction());
469             actions.add(CommonProjectActions.deleteProjectAction());
470             actions.add(null);
471             actions.add(SystemAction.get(FindAction.class));
472             
473             // honor 57874 contact
474

475             try {
476                 FileObject fo = Repository.getDefault().getDefaultFileSystem().findResource("Projects/Actions"); // NOI18N
477
if (fo != null) {
478                     DataObject dobj = DataObject.find(fo);
479                     FolderLookup actionRegistry = new FolderLookup((DataFolder)dobj);
480                     Lookup.Template query = new Lookup.Template(Object JavaDoc.class);
481                     Lookup lookup = actionRegistry.getLookup();
482                     Iterator JavaDoc it = lookup.lookup(query).allInstances().iterator();
483                     if (it.hasNext()) {
484                         actions.add(null);
485                     }
486                     while (it.hasNext()) {
487                         Object JavaDoc next = it.next();
488                         if (next instanceof Action JavaDoc) {
489                             actions.add(next);
490                         } else if (next instanceof JSeparator JavaDoc) {
491                             actions.add(null);
492                         }
493                     }
494                 }
495             } catch (DataObjectNotFoundException ex) {
496                 // data folder for existing fileobject expected
497
ErrorManager.getDefault().notify(ex);
498             }
499             
500             actions.add(null);
501             actions.add(SystemAction.get(ToolsAction.class));
502             actions.add(null);
503             actions.add(CommonProjectActions.customizeProjectAction());
504             
505             return (Action JavaDoc[]) actions.toArray(new Action JavaDoc[actions.size()]);
506             
507         }
508     }
509 }
510
Popular Tags