KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > modules > ruby > rubyproject > RubyActionProvider


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.rubyproject;
21
22 import java.awt.Dialog JavaDoc;
23 import java.awt.event.MouseEvent JavaDoc;
24 import java.io.File JavaDoc;
25 import java.io.IOException JavaDoc;
26 import java.net.MalformedURLException JavaDoc;
27 import java.net.URL JavaDoc;
28 import java.text.MessageFormat JavaDoc;
29 import java.util.Arrays JavaDoc;
30 import java.util.Collection JavaDoc;
31 import java.util.HashSet JavaDoc;
32 import java.util.LinkedHashSet JavaDoc;
33 import java.util.Set JavaDoc;
34 import java.util.regex.Pattern JavaDoc;
35 import javax.swing.JButton JavaDoc;
36 import javax.swing.event.ChangeEvent JavaDoc;
37 import javax.swing.event.ChangeListener JavaDoc;
38 import org.netbeans.api.project.ProjectInformation;
39 import org.netbeans.modules.ruby.rubyproject.execution.ExecutionDescriptor;
40 import org.netbeans.modules.ruby.rubyproject.execution.ExecutionService;
41 import org.netbeans.modules.ruby.rubyproject.api.RubyInstallation;
42 import org.netbeans.api.project.ProjectManager;
43 import org.netbeans.api.project.ProjectUtils;
44 import org.netbeans.modules.ruby.rubyproject.api.RubyExecution;
45 import org.netbeans.modules.ruby.rubyproject.execution.FileLocator;
46 import org.netbeans.modules.ruby.rubyproject.ui.customizer.RubyProjectProperties;
47 import org.netbeans.modules.ruby.rubyproject.ui.customizer.MainClassChooser;
48 import org.netbeans.modules.ruby.rubyproject.ui.customizer.MainClassWarning;
49 import org.netbeans.spi.project.ActionProvider;
50 import org.netbeans.modules.ruby.spi.project.support.rake.RakeProjectHelper;
51 import org.netbeans.modules.ruby.spi.project.support.rake.EditableProperties;
52 import org.netbeans.spi.project.ui.support.DefaultProjectOperations;
53 import org.openide.DialogDescriptor;
54 import org.openide.DialogDisplayer;
55 import org.openide.ErrorManager;
56 import org.openide.LifecycleManager;
57 import org.openide.awt.HtmlBrowser;
58 import org.openide.awt.MouseUtils;
59 import org.openide.cookies.SaveCookie;
60 import org.openide.filesystems.FileObject;
61 import org.openide.filesystems.FileUtil;
62 import org.openide.loaders.DataObject;
63 import org.openide.loaders.DataObjectNotFoundException;
64 import org.openide.util.Exceptions;
65 import org.openide.util.Lookup;
66 import org.openide.util.NbBundle;
67
68 /** Action provider of the Ruby project. This is the place where to do
69  * strange things to Ruby actions. E.g. compile-single.
70  */

71 public class RubyActionProvider implements ActionProvider {
72     /**
73      * Standard command for running rdoc on a project.
74      * @see org.netbeans.spi.project.ActionProvider
75      */

76     public static final String JavaDoc COMMAND_RDOC = "rdoc"; // NOI18N
77

78     // Commands available from Ruby project
79
private static final String JavaDoc[] supportedActions = {
80         COMMAND_BUILD,
81         COMMAND_CLEAN,
82         COMMAND_REBUILD,
83         COMMAND_RDOC,
84 // COMMAND_COMPILE_SINGLE,
85
COMMAND_RUN,
86         COMMAND_RUN_SINGLE,
87 // COMMAND_DEBUG,
88
// COMMAND_DEBUG_SINGLE,
89
// COMMAND_TEST,
90
COMMAND_TEST_SINGLE,
91 // COMMAND_DEBUG_TEST_SINGLE,
92
// COMMAND_DEBUG_STEP_INTO,
93
COMMAND_DELETE,
94         COMMAND_COPY,
95         COMMAND_MOVE,
96         COMMAND_RENAME,
97     };
98     
99     
100     // Project
101
RubyProject project;
102     
103     // Ant project helper of the project
104
private UpdateHelper updateHelper;
105     
106         
107     /**Set of commands which are affected by background scanning*/
108     final Set JavaDoc<String JavaDoc> bkgScanSensitiveActions;
109     
110     public RubyActionProvider( RubyProject project, UpdateHelper updateHelper ) {
111         this.bkgScanSensitiveActions = new HashSet JavaDoc<String JavaDoc>(Arrays.asList(new String JavaDoc[] {
112             COMMAND_RUN,
113             COMMAND_RUN_SINGLE,
114 // COMMAND_DEBUG,
115
// COMMAND_DEBUG_SINGLE,
116
// COMMAND_DEBUG_STEP_INTO
117
}));
118             
119         this.updateHelper = updateHelper;
120         this.project = project;
121     }
122     
123     public String JavaDoc[] getSupportedActions() {
124         return supportedActions;
125     }
126     
127     private void runRubyScript(FileObject fileObject, String JavaDoc target, String JavaDoc displayName, final Lookup context) {
128         String JavaDoc applicationArgs = project.evaluator().getProperty(RubyProjectProperties.APPLICATION_ARGS);
129         String JavaDoc options = project.evaluator().getProperty(RubyProjectProperties.RUN_JVM_ARGS);
130
131         if (options != null && options.trim().length() == 0) {
132             options = null;
133         }
134         if (applicationArgs != null && applicationArgs.trim().length() == 0) {
135             applicationArgs = null;
136         }
137
138         // Set the load path from the source and test folders.
139
// Load paths are additive so users can add their own in the
140
// options field as well.
141
FileObject[] srcPath = project.getSourceRoots().getRoots();
142         FileObject[] testPath = project.getTestSourceRoots().getRoots();
143         StringBuilder JavaDoc sb = new StringBuilder JavaDoc();
144         if (srcPath != null && srcPath.length > 0) {
145             for (FileObject root : srcPath) {
146                 if (sb.length() > 0) {
147                     sb.append(' ');
148                 }
149                 sb.append("-I\"");
150                 sb.append(FileUtil.toFile(root).getAbsoluteFile());
151                 sb.append("\"");
152             }
153         }
154         if (testPath != null && testPath.length > 0) {
155             for (FileObject root : testPath) {
156                 if (sb.length() > 0) {
157                     sb.append(' ');
158                 }
159                 sb.append("-I\"");
160                 sb.append(FileUtil.toFile(root).getAbsoluteFile());
161                 sb.append("\"");
162             }
163         }
164         String JavaDoc includePath = sb.toString();
165         if (options != null) {
166             options = includePath + " " + options;
167         } else {
168             options = includePath;
169         }
170
171         // Locate the target and specify it by full path.
172
// This is necessary because JRuby and Ruby don't locate the script from the load
173
// path it seems.
174
if (!new File JavaDoc(target).exists()) {
175             if (srcPath != null && srcPath.length > 0) {
176                 boolean found = false; // Prefer the first match
177
for (FileObject root : srcPath) {
178                     FileObject fo = root.getFileObject(target);
179                     if (fo != null) {
180                         target = FileUtil.toFile(fo).getAbsolutePath();
181                         found = true;
182                         break;
183                     }
184                 }
185                 if (!found && testPath != null) {
186                     for (FileObject root : testPath) {
187                         FileObject fo = root.getFileObject(target);
188                         if (fo != null) {
189                             target = FileUtil.toFile(fo).getAbsolutePath();
190                             break;
191                         }
192                     }
193                 }
194             }
195         }
196
197         String JavaDoc runDir = project.evaluator().getProperty(RubyProjectProperties.RUN_WORK_DIR);
198         File JavaDoc pwd = getSourceFolder();
199         if (runDir != null && runDir.length() > 0) {
200             File JavaDoc dir = new File JavaDoc(runDir);
201             if (!dir.exists()) {
202                 // Is it relative to the project directory?
203
dir = new File JavaDoc(FileUtil.toFile(project.getProjectDirectory()), runDir);
204                 if (!dir.exists()) {
205                     // Could it be relative to one of the source folders?
206
if (srcPath != null && srcPath.length > 0) {
207                         for (FileObject root : srcPath) {
208                             dir = new File JavaDoc(FileUtil.toFile(root), runDir);
209                             if (dir.exists()) {
210                                 break;
211                             }
212                         }
213                     }
214                 }
215             }
216             if (dir.exists()) {
217                 pwd = dir;
218             }
219         }
220
221         new ExecutionService(new ExecutionDescriptor(displayName, pwd, target).
222                 showSuspended(true).
223                 allowInput().
224                 fileObject(fileObject).
225                 initialArgs(options).
226                 additionalArgs(applicationArgs).
227                 fileLocator(new RubyFileLocator(context)).
228                 addOutputRecognizer(RubyExecution.RUBY_COMPILER)).
229                 run();
230     }
231         
232     public void invokeAction(final String JavaDoc command, final Lookup context) throws IllegalArgumentException JavaDoc {
233         // Initialize the configuration: find a way to pass this to the launched child process!
234
//RubyConfigurationProvider.Config c = context.lookup(RubyConfigurationProvider.Config.class);
235
//if (c != null) {
236
// String config;
237
// if (c.name != null) {
238
// config = c.name;
239
// } else {
240
// // Invalid but overrides any valid setting in config.properties.
241
// config = "";
242
// }
243
// Properties p = new Properties();
244
// p.setProperty(RubyConfigurationProvider.PROP_CONFIG, config);
245
// TODO: Somehow pass the properties to the launched process, and have it digest it
246
//}
247

248         
249         // TODO Check for valid installation of Ruby and Rake
250
if (COMMAND_RUN.equals(command)) {
251             if (!RubyInstallation.getInstance().isValidRuby(true)) {
252                 return;
253             }
254             if (!RubyInstallation.getInstance().isValidRake(true)) {
255                 return;
256             }
257
258             String JavaDoc config = project.evaluator().getProperty(RubyConfigurationProvider.PROP_CONFIG);
259             String JavaDoc path;
260             if (config == null || config.length() == 0) {
261                 path = RakeProjectHelper.PROJECT_PROPERTIES_PATH;
262             } else {
263                 // Set main class for a particular config only.
264
path = "nbproject/configs/" + config + ".properties"; // NOI18N
265
}
266             EditableProperties ep = updateHelper.getProperties(path);
267
268             // check project's main class
269
// Check whether main class is defined in this config. Note that we use the evaluator,
270
// not ep.getProperty(MAIN_CLASS), since it is permissible for the default pseudoconfig
271
// to define a main class - in this case an active config need not override it.
272
String JavaDoc mainClass = project.evaluator().getProperty(RubyProjectProperties.MAIN_CLASS);
273             MainClassStatus result = isSetMainClass (project.getSourceRoots().getRoots(), mainClass);
274             if (context.lookup(RubyConfigurationProvider.Config.class) != null) {
275                 // If a specific config was selected, just skip this check for now.
276
// XXX would ideally check that that config in fact had a main class.
277
// But then evaluator.getProperty(MAIN_CLASS) would be inaccurate.
278
// Solvable but punt on it for now.
279
result = MainClassStatus.SET_AND_VALID;
280             }
281             if (result != MainClassStatus.SET_AND_VALID) {
282                 do {
283                     // show warning, if cancel then return
284
if (showMainClassWarning (mainClass, ProjectUtils.getInformation(project).getDisplayName(), ep,result)) {
285                         return;
286                     }
287                     // No longer use the evaluator: have not called putProperties yet so it would not work.
288
mainClass = ep.get(RubyProjectProperties.MAIN_CLASS);
289                     result=isSetMainClass (project.getSourceRoots().getRoots(), mainClass);
290                 } while (result != MainClassStatus.SET_AND_VALID);
291                 try {
292                     if (updateHelper.requestSave()) {
293                         updateHelper.putProperties(path, ep);
294                         ProjectManager.getDefault().saveProject(project);
295                     }
296                     else {
297                         return;
298                     }
299                 } catch (IOException JavaDoc ioe) {
300                     ErrorManager.getDefault().log(ErrorManager.INFORMATIONAL, "Error while saving project: " + ioe);
301                 }
302             }
303
304             // Save all files first
305
LifecycleManager.getDefault().saveAll();
306             
307             String JavaDoc displayName = (mainClass != null) ? "Ruby" : "Rake"; // TODO - internationalize
308

309             ProjectInformation info = ProjectUtils.getInformation(project);
310             if (info != null) {
311                 displayName = info.getDisplayName();
312             }
313
314             if (mainClass != null) {
315                 // TODO - compute mainclass
316
FileObject fileObject = null;
317                 runRubyScript(fileObject, mainClass, displayName, context);
318                 return;
319             }
320
321             // Default to running rake
322

323             RubyFileLocator fileLocator = new RubyFileLocator(context);
324             File JavaDoc pwd = getSourceFolder(); // Or project directory?
325
new ExecutionService(new ExecutionDescriptor(displayName, pwd, RubyInstallation.getInstance().getRake()).
326                     fileLocator(new RubyFileLocator(context)).
327                     addOutputRecognizer(RubyExecution.RUBY_COMPILER)).
328                     run();
329             
330             return;
331         } else if (COMMAND_RUN_SINGLE.equals(command)) {
332             if (!RubyInstallation.getInstance().isValidRuby(true)) {
333                 return;
334             }
335
336             FileObject[] fos = findSources(context);
337             if (fos == null) {
338                 fos = findTestSources(context, false);
339             }
340             if (fos == null || fos.length == 0) {
341                 return;
342             }
343             FileObject file = fos[0];
344             
345             // Save the file
346
try {
347                 DataObject dobj = DataObject.find(file);
348                 if (dobj != null) {
349                     SaveCookie saveCookie = dobj.getCookie(SaveCookie.class);
350                     if (saveCookie != null) {
351                         saveCookie.save();
352                     }
353                 }
354             } catch (DataObjectNotFoundException donfe) {
355                 ErrorManager.getDefault().notify(donfe);
356             } catch (IOException JavaDoc ioe) {
357                 ErrorManager.getDefault().notify(ioe);
358             }
359             
360             //String target = FileUtil.getRelativePath(getRoot(project.getSourceRoots().getRoots(),file), file);
361
runRubyScript(file, FileUtil.toFile(file).getAbsolutePath(), file.getNameExt(), context);
362             return;
363         } else if (COMMAND_BUILD.equals(command)) {
364             if (!RubyInstallation.getInstance().isValidRake(true)) {
365                 return;
366             }
367
368             // Save all files first
369
LifecycleManager.getDefault().saveAll();
370             
371             String JavaDoc displayName = "Rake"; // TODO - internationalize
372
File JavaDoc pwd = getSourceFolder(); // Or project directory?
373
new ExecutionService(new ExecutionDescriptor(displayName, pwd, RubyInstallation.getInstance().getRake()).
374                     fileLocator(new RubyFileLocator(context)).
375                     addOutputRecognizer(RubyExecution.RUBY_COMPILER)).
376                     run();
377             return;
378         } else if (COMMAND_CLEAN.equals(command)) {
379             if (!RubyInstallation.getInstance().isValidRake(true)) {
380                 return;
381             }
382
383             //RubyFileLocator fileLocator = new RubyFileLocator(context);
384
String JavaDoc displayName = "Rake"; // TODO - internationalize
385
File JavaDoc pwd = getSourceFolder(); // Or project directory?
386
new ExecutionService(new ExecutionDescriptor(displayName, pwd, RubyInstallation.getInstance().getRake(), "clean").
387                     fileLocator(new RubyFileLocator(context)).
388                     addOutputRecognizer(RubyExecution.RUBY_COMPILER)).
389                     run();
390             return;
391         }
392         
393         if (COMMAND_RDOC.equals(command)) {
394             if (!RubyInstallation.getInstance().isValidRDoc(true)) {
395                 return;
396             }
397
398             LifecycleManager.getDefault().saveAll();
399             File JavaDoc pwd = FileUtil.toFile(project.getProjectDirectory());
400
401             Runnable JavaDoc showBrowser = new Runnable JavaDoc() {
402                 public void run() {
403                     // TODO - wait for the file to be created
404
// Open brower on the doc directory
405
FileObject doc = project.getProjectDirectory().getFileObject("doc");
406                     if (doc != null) {
407                         FileObject index = doc.getFileObject("index.html");
408                         if (index != null) {
409                             try {
410                                 URL JavaDoc url = FileUtil.toFile(index).toURI().toURL();
411
412                                 HtmlBrowser.URLDisplayer.getDefault().showURL(url);
413                             }
414                             catch (MalformedURLException JavaDoc ex) {
415                                 ErrorManager.getDefault().notify(ex);
416                             };
417                         }
418                     }
419                 }
420             };
421             
422             RubyFileLocator fileLocator = new RubyFileLocator(context);
423             String JavaDoc displayName = "Ruby Documentation"; // TODO - internationalize
424
new ExecutionService(new ExecutionDescriptor(displayName, pwd, RubyInstallation.getInstance().getRDoc()).
425                     fileLocator(fileLocator).
426                     postBuild(showBrowser).
427                     addOutputRecognizer(RubyExecution.RUBY_COMPILER)).
428                     run();
429             
430             return;
431         }
432         
433         if (COMMAND_TEST_SINGLE.equals(command)) {
434             if (!RubyInstallation.getInstance().isValidRuby(true)) {
435                 return;
436             }
437             FileObject[] files = findTestSourcesForSources(context);
438
439             FileObject file = findSources(context)[0];
440             
441             // Save the file
442
try {
443                 DataObject dobj = DataObject.find(file);
444                 if (dobj != null) {
445                     SaveCookie saveCookie = dobj.getCookie(SaveCookie.class);
446                     if (saveCookie != null) {
447                         saveCookie.save();
448                     }
449                 }
450             } catch (DataObjectNotFoundException donfe) {
451                 ErrorManager.getDefault().notify(donfe);
452             } catch (IOException JavaDoc ioe) {
453                 ErrorManager.getDefault().notify(ioe);
454             }
455             
456             String JavaDoc target = FileUtil.getRelativePath(getRoot(project.getSourceRoots().getRoots(),file), file);
457             String JavaDoc displayName = file.getNameExt();
458             File JavaDoc pwd = getSourceFolder();
459             new ExecutionService(new ExecutionDescriptor(displayName, pwd, target).
460                     showSuspended(true).
461                     allowInput().
462                     fileLocator(new RubyFileLocator(context)).
463                     addOutputRecognizer(RubyExecution.RUBY_COMPILER)).
464                     run();
465
466             return;
467         }
468
469         // XXX TODO
470
if (COMMAND_TEST.equals(command)) {
471             if (!RubyInstallation.getInstance().isValidRuby(true)) {
472                 return;
473             }
474
475             FileObject[] files = findTestSourcesForSources(context);
476
477             //return;
478
throw new RuntimeException JavaDoc("Not yet implemented");
479         }
480         
481         
482         if (COMMAND_DELETE.equals(command)) {
483             DefaultProjectOperations.performDefaultDeleteOperation(project);
484             return;
485         }
486         
487         if (COMMAND_COPY.equals(command)) {
488             DefaultProjectOperations.performDefaultCopyOperation(project);
489             return;
490         }
491         
492         if (COMMAND_MOVE.equals(command)) {
493             DefaultProjectOperations.performDefaultMoveOperation(project);
494             return;
495         }
496         
497         if (COMMAND_RENAME.equals(command)) {
498             DefaultProjectOperations.performDefaultRenameOperation(project, null);
499             return;
500         }
501     }
502     
503 // /**
504
// * @return array of targets or null to stop execution; can return empty array
505
// */
506
// private String[] getTargetNames(String command, Lookup context, Properties p) throws IllegalArgumentException {
507
// String[] targetNames = new String[0];
508
// if ( command.equals( COMMAND_COMPILE_SINGLE ) ) {
509
// throw new RuntimeException("Not yet implemented");
510
// FileObject[] sourceRoots = project.getSourceRoots().getRoots();
511
// FileObject[] files = findSourcesAndPackages( context, sourceRoots);
512
// boolean recursive = (context.lookup(NonRecursiveFolder.class) == null);
513
// if (files != null) {
514
// p.setProperty("javac.includes", ActionUtils.antIncludesList(files, getRoot(sourceRoots,files[0]), recursive)); // NOI18N
515
// targetNames = new String[] {"compile-single"}; // NOI18N
516
// }
517
// else {
518
// FileObject[] testRoots = project.getTestSourceRoots().getRoots();
519
// files = findSourcesAndPackages(context, testRoots);
520
// p.setProperty("javac.includes", ActionUtils.antIncludesList(files, getRoot(testRoots,files[0]), recursive)); // NOI18N
521
// targetNames = new String[] {"compile-test-single"}; // NOI18N
522
// }
523
// }
524
// else if ( command.equals( COMMAND_TEST_SINGLE ) ) {
525
// FileObject[] files = findTestSourcesForSources(context);
526
// targetNames = setupTestSingle(p, files);
527
// }
528
// else if ( command.equals( COMMAND_DEBUG_TEST_SINGLE ) ) {
529
// FileObject[] files = findTestSourcesForSources(context);
530
// targetNames = setupDebugTestSingle(p, files);
531
// } else if (command.equals (COMMAND_RUN_SINGLE) || command.equals (COMMAND_DEBUG_SINGLE)) {
532
// FileObject[] files = findTestSources(context, false);
533
// if (files != null) {
534
// if (command.equals(COMMAND_RUN_SINGLE)) {
535
// targetNames = setupTestSingle(p, files);
536
// } else {
537
// targetNames = setupDebugTestSingle(p, files);
538
// }
539
// } else {
540
// FileObject file = findSources(context)[0];
541
// String clazz = FileUtil.getRelativePath(getRoot(project.getSourceRoots().getRoots(),file), file);
542
//// p.setProperty("javac.includes", clazz); // NOI18N
543
// // Convert foo/FooTest.java -> foo.FooTest
544
// // XXX What about Ruby?
545
// if (clazz.endsWith(".java")) { // NOI18N
546
// clazz = clazz.substring(0, clazz.length() - 5);
547
// }
548
// clazz = clazz.replace('/','.');
549
//
550
// if (!RubyProjectUtil.hasMainMethod (file)) {
551
// NotifyDescriptor nd = new NotifyDescriptor.Message(NbBundle.getMessage(RubyActionProvider.class, "LBL_No_Main_Classs_Found", clazz), NotifyDescriptor.INFORMATION_MESSAGE);
552
// DialogDisplayer.getDefault().notify(nd);
553
// return null;
554
// } else {
555
// if (command.equals (COMMAND_RUN_SINGLE)) {
556
// p.setProperty("run.class", clazz); // NOI18N
557
// targetNames = (String[])commands.get(COMMAND_RUN_SINGLE);
558
// } else {
559
// p.setProperty("debug.class", clazz); // NOI18N
560
// targetNames = (String[])commands.get(COMMAND_DEBUG_SINGLE);
561
// }
562
// }
563
// }
564
// }
565
// return targetNames;
566
// }
567

568     public boolean isActionEnabled( String JavaDoc command, Lookup context ) {
569 // FileObject buildXml = findBuildXml();
570
// if ( buildXml == null || !buildXml.isValid()) {
571
// return false;
572
// }
573
if ( command.equals( COMMAND_COMPILE_SINGLE ) ) {
574             return findSourcesAndPackages( context, project.getSourceRoots().getRoots()) != null
575                     || findSourcesAndPackages( context, project.getTestSourceRoots().getRoots()) != null;
576         }
577         else if ( command.equals( COMMAND_TEST_SINGLE ) ) {
578             return findTestSourcesForSources(context) != null;
579         }
580         else if ( command.equals( COMMAND_DEBUG_TEST_SINGLE ) ) {
581             FileObject[] files = findTestSourcesForSources(context);
582             return files != null && files.length == 1;
583         } else if (command.equals(COMMAND_RUN_SINGLE) ||
584                         command.equals(COMMAND_DEBUG_SINGLE)) {
585             FileObject fos[] = findSources(context);
586             if (fos != null && fos.length == 1) {
587                 return true;
588             }
589             fos = findTestSources(context, false);
590             return fos != null && fos.length == 1;
591         } else {
592             // other actions are global
593
return true;
594         }
595     }
596     
597     
598    
599     // Private methods -----------------------------------------------------------------
600

601     
602     private static final Pattern JavaDoc SRCDIRJAVA = Pattern.compile("\\.java$"); // NOI18N
603
private static final String JavaDoc SUBST = "Test.java"; // NOI18N
604

605     /** Find selected sources, the sources has to be under single source root,
606      * @param context the lookup in which files should be found
607      */

608     private FileObject[] findSources(Lookup context) {
609         FileObject[] srcPath = project.getSourceRoots().getRoots();
610         for (int i=0; i< srcPath.length; i++) {
611             FileObject[] files = findSelectedFiles(context, srcPath[i], RubyInstallation.RUBY_MIME_TYPE, true); // NOI18N
612
if (files != null) {
613                 return files;
614             }
615         }
616         return null;
617     }
618
619     private FileObject[] findSourcesAndPackages (Lookup context, FileObject srcDir) {
620         if (srcDir != null) {
621             FileObject[] files = findSelectedFiles(context, srcDir, null, true); // NOI18N
622
//Check if files are either packages or Ruby files
623
if (files != null) {
624                 for (int i = 0; i < files.length; i++) {
625                     if (!files[i].isFolder() && files[i].getMIMEType().equals(RubyInstallation.RUBY_MIME_TYPE)) {
626                         return null;
627                     }
628                 }
629             }
630             return files;
631         } else {
632             return null;
633         }
634     }
635     
636     private FileObject[] findSourcesAndPackages (Lookup context, FileObject[] srcRoots) {
637         for (int i=0; i<srcRoots.length; i++) {
638             FileObject[] result = findSourcesAndPackages(context, srcRoots[i]);
639             if (result != null) {
640                 return result;
641             }
642         }
643         return null;
644     }
645     
646     /** Find either selected tests or tests which belong to selected source files
647      */

648     private FileObject[] findTestSources(Lookup context, boolean checkInSrcDir) {
649         //XXX: Ugly, should be rewritten
650
FileObject[] testSrcPath = project.getTestSourceRoots().getRoots();
651         for (int i=0; i< testSrcPath.length; i++) {
652             FileObject[] files = findSelectedFiles(context, testSrcPath[i], RubyInstallation.RUBY_MIME_TYPE, true); // NOI18N
653
if (files != null) {
654                 return files;
655             }
656         }
657 // if (checkInSrcDir && testSrcPath.length>0) {
658
// FileObject[] files = findSources (context);
659
// if (files != null) {
660
// //Try to find the test under the test roots
661
// FileObject srcRoot = getRoot(project.getSourceRoots().getRoots(),files[0]);
662
// for (int i=0; i<testSrcPath.length; i++) {
663
// FileObject[] files2 = ActionUtils.regexpMapFiles(files,srcRoot, SRCDIRJAVA, testSrcPath[i], SUBST, true);
664
// if (files2 != null) {
665
// return files2;
666
// }
667
// }
668
// }
669
// }
670
return null;
671     }
672    
673
674     /** Find tests corresponding to selected sources.
675      */

676     private FileObject[] findTestSourcesForSources(Lookup context) {
677         FileObject[] sourceFiles = findSources(context);
678         if (sourceFiles == null) {
679             return null;
680         }
681         FileObject[] testSrcPath = project.getTestSourceRoots().getRoots();
682         if (testSrcPath.length == 0) {
683             return null;
684         }
685         FileObject[] srcPath = project.getSourceRoots().getRoots();
686         FileObject srcDir = getRoot(srcPath, sourceFiles[0]);
687 // for (int i=0; i<testSrcPath.length; i++) {
688
// FileObject[] files2 = ActionUtils.regexpMapFiles(sourceFiles, srcDir, SRCDIRJAVA, testSrcPath[i], SUBST, true);
689
// if (files2 != null) {
690
// return files2;
691
// }
692
// }
693
// return null;
694
return new FileObject[] { srcDir }; // XXX This is bogus
695
}
696     
697     private FileObject getRoot (FileObject[] roots, FileObject file) {
698         assert file != null : "File can't be null"; //NOI18N
699
FileObject srcDir = null;
700         for (int i=0; i< roots.length; i++) {
701             assert roots[i] != null : "Source Path Root can't be null"; //NOI18N
702
if (FileUtil.isParentOf(roots[i],file) || roots[i].equals(file)) {
703                 srcDir = roots[i];
704                 break;
705             }
706         }
707         return srcDir;
708     }
709     
710     private static enum MainClassStatus {
711         SET_AND_VALID,
712         SET_BUT_INVALID,
713         UNSET
714     }
715
716     /**
717      * Tests if the main class is set
718      * @param sourcesRoots source roots
719      * @param mainClass main class name
720      * @return status code
721      */

722     private MainClassStatus isSetMainClass(FileObject[] sourcesRoots, String JavaDoc mainClass) {
723
724         // support for unit testing
725
if (MainClassChooser.unitTestingSupport_hasMainMethodResult != null) {
726             return MainClassChooser.unitTestingSupport_hasMainMethodResult ? MainClassStatus.SET_AND_VALID : MainClassStatus.SET_BUT_INVALID;
727         }
728
729         if (mainClass == null || mainClass.length () == 0) {
730             return MainClassStatus.UNSET;
731         }
732         
733         //ClassPath classPath = ClassPath.getClassPath (sourcesRoots[0], ClassPath.EXECUTE); //Single compilation unit
734
if (RubyProjectUtil.isMainClass (mainClass, sourcesRoots)) {
735             return MainClassStatus.SET_AND_VALID;
736         }
737         return MainClassStatus.SET_BUT_INVALID;
738     }
739     
740     /**
741      * Asks user for name of main class
742      * @param mainClass current main class
743      * @param projectName the name of project
744      * @param ep project.properties to possibly edit
745      * @param messgeType type of dialog
746      * @return true if user selected main class
747      */

748     private boolean showMainClassWarning(String JavaDoc mainClass, String JavaDoc projectName, EditableProperties ep, MainClassStatus messageType) {
749         boolean canceled;
750         final JButton JavaDoc okButton = new JButton JavaDoc (NbBundle.getMessage (RubyActionProvider.class, "LBL_MainClassWarning_ChooseMainClass_OK")); // NOI18N
751
okButton.getAccessibleContext().setAccessibleDescription (NbBundle.getMessage (RubyActionProvider.class, "AD_MainClassWarning_ChooseMainClass_OK"));
752         
753         // main class goes wrong => warning
754
String JavaDoc message;
755         switch (messageType) {
756             case UNSET:
757                 message = MessageFormat.format (NbBundle.getMessage(RubyActionProvider.class,"LBL_MainClassNotFound"), new Object JavaDoc[] {
758                     projectName
759                 });
760                 break;
761             case SET_BUT_INVALID:
762                 message = MessageFormat.format (NbBundle.getMessage(RubyActionProvider.class,"LBL_MainClassWrong"), new Object JavaDoc[] {
763                     mainClass,
764                     projectName
765                 });
766                 break;
767             default:
768                 throw new IllegalArgumentException JavaDoc ();
769         }
770         final MainClassWarning panel = new MainClassWarning (message,project.getSourceRoots().getRoots());
771         Object JavaDoc[] options = new Object JavaDoc[] {
772             okButton,
773             DialogDescriptor.CANCEL_OPTION
774         };
775         
776         panel.addChangeListener (new ChangeListener JavaDoc () {
777            public void stateChanged (ChangeEvent JavaDoc e) {
778                if (e.getSource () instanceof MouseEvent JavaDoc && MouseUtils.isDoubleClick (((MouseEvent JavaDoc)e.getSource ()))) {
779                    // click button and the finish dialog with selected class
780
okButton.doClick ();
781                } else {
782                    okButton.setEnabled (panel.getSelectedMainClass () != null);
783                }
784            }
785         });
786         
787         okButton.setEnabled (false);
788         DialogDescriptor desc = new DialogDescriptor (panel,
789             NbBundle.getMessage (RubyActionProvider.class, "CTL_MainClassWarning_Title", ProjectUtils.getInformation(project).getDisplayName()), // NOI18N
790
true, options, options[0], DialogDescriptor.BOTTOM_ALIGN, null, null);
791         desc.setMessageType (DialogDescriptor.INFORMATION_MESSAGE);
792         Dialog JavaDoc dlg = DialogDisplayer.getDefault ().createDialog (desc);
793         dlg.setVisible (true);
794         if (desc.getValue() != options[0]) {
795             canceled = true;
796         } else {
797             mainClass = panel.getSelectedMainClass ();
798             canceled = false;
799             ep.put(RubyProjectProperties.MAIN_CLASS, mainClass == null ? "" : mainClass);
800         }
801         dlg.dispose();
802
803         return canceled;
804     }
805     
806     // From the ant module - ActionUtils.
807
// However, I've modified it to do its search based on mime type rather than file suffixes
808
// (since some Ruby files do not use a .rb extension and are discovered based on the initial shebang line)
809

810     public static FileObject[] findSelectedFiles(Lookup context, FileObject dir, String JavaDoc mimeType, boolean strict) {
811         if (dir != null && !dir.isFolder()) {
812             throw new IllegalArgumentException JavaDoc("Not a folder: " + dir); // NOI18N
813
}
814         Collection JavaDoc<FileObject> files = new LinkedHashSet JavaDoc<FileObject>(); // #50644: remove dupes
815
// XXX this should perhaps also check for FileObject's...
816
for (DataObject d : context.lookupAll(DataObject.class)) {
817             FileObject f = d.getPrimaryFile();
818             boolean matches = FileUtil.toFile(f) != null;
819             if (dir != null) {
820                 matches &= (FileUtil.isParentOf(dir, f) || dir == f);
821             }
822             if (mimeType != null) {
823                 matches &= f.getMIMEType().equals(mimeType);
824             }
825             // Generally only files from one project will make sense.
826
// Currently the action UI infrastructure (PlaceHolderAction)
827
// checks for that itself. Should there be another check here?
828
if (matches) {
829                 files.add(f);
830             } else if (strict) {
831                 return null;
832             }
833         }
834         if (files.isEmpty()) {
835             return null;
836         }
837         return files.toArray(new FileObject[files.size()]);
838     }
839     
840
841     private class RubyFileLocator implements FileLocator {
842         private Lookup context;
843
844         RubyFileLocator(Lookup context) {
845             this.context = context;
846         }
847
848         public FileObject find(String JavaDoc file) {
849             FileObject[] fos = null;
850             if (context != Lookup.EMPTY) {
851         
852                 // First check roots and search by relative path.
853
FileObject[] srcPath = project.getSourceRoots().getRoots();
854                 if (srcPath != null) {
855                     for (FileObject root : srcPath) {
856                         FileObject f = root.getFileObject(file);
857                         if (f != null) {
858                             return f;
859                         }
860                     }
861                 }
862
863                 // Next try searching the set of source files
864
fos = findSources(context);
865                 if (fos != null) {
866                     for (FileObject fo : fos) {
867                         if (fo.getNameExt().equals(file)) {
868                             return fo;
869                         }
870                     }
871                 }
872             }
873
874             // Manual search
875
FileObject[] srcPath = project.getSourceRoots().getRoots();
876             for (FileObject root : srcPath) {
877                 // First see if this path is relative to the root
878
try {
879                     File JavaDoc f = new File JavaDoc(FileUtil.toFile(root), file);
880                     if (f.exists()) {
881                         f = f.getCanonicalFile();
882                         return FileUtil.toFileObject(f);
883                     }
884                 } catch (IOException JavaDoc ioe) {
885                     Exceptions.printStackTrace(ioe);
886                 }
887                 
888                 // Search recursively for the given file below the path
889
FileObject fo = findFile(root, file);
890                 if (fo != null) {
891                     return fo;
892                 }
893             }
894             
895             return null;
896         }
897         
898         private FileObject findFile(FileObject fo, String JavaDoc name) {
899             if (name.equals(fo.getNameExt())) {
900                 return fo;
901             }
902             
903             for (FileObject child : fo.getChildren()) {
904                 FileObject found = findFile(child, name);
905                 if (found != null) {
906                     return found;
907                 }
908             }
909             
910             return null;
911         }
912     }
913
914     private File JavaDoc getSourceFolder() {
915         // Default to using the project source directory
916
FileObject[] srcPath = project.getSourceRoots().getRoots();
917         if (srcPath != null && srcPath.length > 0) {
918             return FileUtil.toFile(srcPath[0]);
919         } else {
920             return FileUtil.toFile(project.getProjectDirectory());
921         }
922     }
923 }
924
Popular Tags