/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
*
* Oracle and Java are registered trademarks of Oracle and/or its affiliates.
* Other names may be trademarks of their respective owners.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common
* Development and Distribution License("CDDL") (collectively, the
* "License"). You may not use this file except in compliance with the
* License. You can obtain a copy of the License at
* http://www.netbeans.org/cddl-gplv2.html
* or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
* specific language governing permissions and limitations under the
* License. When distributing the software, include this License Header
* Notice in each file and include the License file at
* nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the GPL Version 2 section of the License file that
* accompanied this code. If applicable, add the following below the
* License Header, with the fields enclosed by brackets [] replaced by
* your own identifying information:
* "Portions Copyrighted [year] [name of copyright owner]"
*
* Contributor(s):
*
* The Original Software is NetBeans. The Initial Developer of the Original
* Software is Sun Microsystems, Inc. Portions Copyright 1997-2008 Sun
* Microsystems, Inc. All Rights Reserved.
*
* If you wish your version of this file to be governed by only the CDDL
* or only the GPL Version 2, indicate your decision by adding
* "[Contributor] elects to include this software in this distribution
* under the [CDDL or GPL Version 2] license." If you do not indicate a
* single choice of license, a recipient has the option to distribute
* your version of this file under either the CDDL, the GPL Version 2 or
* to extend the choice of license to its licensees as provided above.
* However, if you add GPL Version 2 code and therefore, elected the GPL
* Version 2 license, then the option applies only if the new code is
* made subject to such option by the copyright holder.
*/
package org.netbeans.modules.ruby.rubyproject;
import org.netbeans.modules.ruby.rubyproject.rake.RakeSupport;
import java.awt.Dialog;
import java.awt.Toolkit;
import java.awt.event.MouseEvent;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.text.MessageFormat;
import javax.swing.JButton;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import org.netbeans.api.project.ProjectInformation;
import org.netbeans.api.project.ProjectManager;
import org.netbeans.modules.ruby.platform.execution.RubyExecutionDescriptor;
import org.netbeans.api.ruby.platform.RubyInstallation;
import org.netbeans.api.project.ProjectUtils;
import org.netbeans.api.ruby.platform.RubyPlatform;
import org.netbeans.api.extexecution.ExecutionService;
import org.netbeans.api.extexecution.print.LineConvertor;
import org.netbeans.api.extexecution.print.LineConvertors;
import org.netbeans.modules.csl.api.DeclarationFinder.DeclarationLocation;
import org.netbeans.modules.ruby.platform.execution.RubyLineConvertorFactory;
import org.netbeans.modules.ruby.platform.execution.RubyProcessCreator;
import org.netbeans.modules.ruby.rubyproject.rake.RakeRunner;
import org.netbeans.modules.ruby.rubyproject.spi.TestRunner;
import org.netbeans.modules.ruby.rubyproject.ui.customizer.RubyProjectProperties;
import org.netbeans.modules.ruby.rubyproject.ui.customizer.MainClassChooser;
import org.netbeans.modules.ruby.rubyproject.ui.customizer.MainClassWarning;
import org.netbeans.modules.ruby.spi.project.support.rake.RakeProjectHelper;
import org.netbeans.spi.project.ui.support.DefaultProjectOperations;
import org.openide.DialogDescriptor;
import org.openide.DialogDisplayer;
import org.openide.ErrorManager;
import org.openide.LifecycleManager;
import org.openide.awt.HtmlBrowser;
import org.openide.awt.MouseUtils;
import org.openide.filesystems.FileObject;
import org.openide.filesystems.FileUtil;
import org.openide.util.Lookup;
import org.openide.util.NbBundle;
import org.netbeans.modules.ruby.codecoverage.RubyCoverageProvider;
import org.netbeans.modules.ruby.rubyproject.spi.TestRunner.TestType;
import org.openide.util.EditableProperties;
/**
* Action provider of the Ruby project.
*/
public final class RubyActionProvider extends RubyBaseActionProvider {
/**
* Standard command for running the IRB console on a project
*/
public static final String COMMAND_IRB_CONSOLE = "irb-console"; // NOI18N
// Commands available from Ruby project
private static final String[] supportedActions = {
COMMAND_BUILD,
COMMAND_CLEAN,
COMMAND_REBUILD,
COMMAND_AUTOTEST,
COMMAND_AUTOSPEC,
COMMAND_RDOC,
COMMAND_IRB_CONSOLE,
COMMAND_RUN,
COMMAND_RUN_SINGLE,
COMMAND_DEBUG,
COMMAND_DEBUG_SINGLE,
COMMAND_TEST,
COMMAND_RSPEC,
COMMAND_TEST_SINGLE,
COMMAND_DEBUG_TEST_SINGLE,
COMMAND_DELETE,
COMMAND_COPY,
COMMAND_MOVE,
COMMAND_RENAME,
};
private final static String[] MIME_TYPES = new String[] {
RubyInstallation.RUBY_MIME_TYPE
};
final RubyProject project;
public RubyActionProvider(RubyProject project, UpdateHelper updateHelper) {
super(project, updateHelper);
this.project = project;
}
@Override
protected FileObject[] getSourceRoots() {
return project.getSourceRoots().getRoots();
}
@Override
protected FileObject[] getTestSourceRoots() {
return project.getTestSourceRoots().getRoots();
}
@Override
protected String[] getMimeTypes() {
return MIME_TYPES;
}
public String[] getSupportedActions() {
return supportedActions;
}
public RubyExecutionDescriptor getScriptDescriptor(File pwd, FileObject fileObject, String target,
String displayName, final Lookup context, final boolean debug,
LineConvertor... extraConvertors) {
String rubyOptions = SharedRubyProjectProperties.getRubyOptions(project);
String includePath = RubyProjectUtil.getLoadPath(project);
if (rubyOptions != null) {
rubyOptions = includePath + " " + rubyOptions; // NOI18N
} else {
rubyOptions = includePath;
}
FileObject[] srcPath = project.getSourceRoots().getRoots();
FileObject[] testPath = project.getTestSourceRoots().getRoots();
target = locate(target, srcPath, testPath);
if (pwd == null) {
String runDir = project.evaluator().getProperty(RubyProjectProperties.RUN_WORK_DIR);
pwd = getSourceFolder();
if (runDir != null && runDir.length() > 0) {
File dir = new File(runDir);
if (!dir.exists()) {
// Is it relative to the project directory?
dir = new File(FileUtil.toFile(project.getProjectDirectory()), runDir);
if (!dir.exists()) {
// Could it be relative to one of the source folders?
if (srcPath != null && srcPath.length > 0) {
for (FileObject root : srcPath) {
dir = new File(FileUtil.toFile(root), runDir);
if (dir.exists()) {
break;
}
}
}
}
}
if (dir.exists()) {
pwd = dir;
}
}
}
String classPath = project.evaluator().getProperty(RubyProjectProperties.JAVAC_CLASSPATH);
String jvmArgs = project.evaluator().getProperty(RubyProjectProperties.JVM_ARGS);
RubyExecutionDescriptor desc = new RubyExecutionDescriptor(getPlatform(), displayName, pwd, target);
desc.debug(debug);
desc.showSuspended(true);
desc.allowInput();
desc.fileObject(fileObject);
desc.jvmArguments(jvmArgs);
desc.initialArgs(rubyOptions);
desc.classPath(classPath);
desc.additionalArgs(getApplicationArguments());
desc.fileLocator(new RubyFileLocator(context, project));
desc.addStandardRecognizers();
desc.addOutConvertor(LineConvertors.filePattern(desc.getFileLocator(),
RubyLineConvertorFactory.RUBY_TEST_OUTPUT,
RubyLineConvertorFactory.EXT_RE
,1,2));
desc.addErrConvertor(LineConvertors.filePattern(desc.getFileLocator(),
RubyLineConvertorFactory.RUBY_TEST_OUTPUT,
RubyLineConvertorFactory.EXT_RE
,1,2));
desc.setEncoding(getSourceEncoding());
if (extraConvertors != null) {
for (LineConvertor extra : extraConvertors) {
desc.addOutConvertor(extra);
}
}
RubyCoverageProvider coverageProvider = RubyCoverageProvider.get(project);
if (coverageProvider != null && coverageProvider.isEnabled()) {
desc = coverageProvider.wrapWithCoverage(desc, false, null);
}
return desc;
}
private String locate(String target, final FileObject[] srcPath, final FileObject[] testPath) {
// Locate the target and specify it by full path. This is necessary
// because JRuby and Ruby don't locate the script from the load path it
// seems.
if (!new File(target).exists() && srcPath != null && srcPath.length > 0) {
boolean found = false; // Prefer the first match
for (FileObject root : srcPath) {
FileObject fo = root.getFileObject(target);
if (fo != null) {
target = FileUtil.toFile(fo).getAbsolutePath();
found = true;
break;
}
}
if (!found && testPath != null) {
for (FileObject root : testPath) {
FileObject fo = root.getFileObject(target);
if (fo != null) {
target = FileUtil.toFile(fo).getAbsolutePath();
break;
}
}
}
}
return target;
}
private void openIrbConsole(Lookup context) {
RubyPlatform platform = getPlatform();
String irbPath = platform.findExecutable("irb"); // NOI18N
if (irbPath == null) {
Toolkit.getDefaultToolkit().beep();
return;
}
String displayName = NbBundle.getMessage(RubyActionProvider.class, "CTL_IrbTopComponent");
File pwd = FileUtil.toFile(project.getProjectDirectory());
String classPath = project.evaluator().getProperty(RubyProjectProperties.JAVAC_CLASSPATH);
RubyExecutionDescriptor desc =
new RubyExecutionDescriptor(platform, displayName, pwd, irbPath).
showSuspended(false).
showProgress(false).
classPath(classPath).
allowInput().
additionalArgs("--simple-prompt", "--noreadline"). // NOI18N
//additionalArgs(getApplicationArguments()).
fileLocator(new RubyFileLocator(context, project)).
addStandardRecognizers();
RubyProcessCreator rpc = new RubyProcessCreator(desc, getSourceEncoding());
ExecutionService.newService(rpc, desc.toExecutionDescriptor(), displayName).run();
}
public void invokeAction(final String command, final Lookup context) throws IllegalArgumentException {
// Initialize the configuration: find a way to pass this to the launched child process!
//RubyConfigurationProvider.Config c = context.lookup(RubyConfigurationProvider.Config.class);
//if (c != null) {
// String config;
// if (c.name != null) {
// config = c.name;
// } else {
// // Invalid but overrides any valid setting in config.properties.
// config = "";
// }
// Properties p = new Properties();
// p.setProperty(RubyConfigurationProvider.PROP_CONFIG, config);
// TODO: Somehow pass the properties to the launched process, and have it digest it
//}
RubyPlatform platform = RubyPlatform.platformFor(project);
assert platform != null : "Action '" + command + "' should be disabled when platform is invalid";
// TODO Check for valid installation of Ruby and Rake
if (COMMAND_RUN.equals(command) || COMMAND_DEBUG.equals(command)) {
if (!platform.isValid(true)) {
return;
}
String config = project.evaluator().getProperty(RubyConfigurationProvider.PROP_CONFIG);
String path;
if (config == null || config.length() == 0) {
path = RakeProjectHelper.PROJECT_PROPERTIES_PATH;
} else {
// Set main class for a particular config only.
path = "nbproject/configs/" + config + ".properties"; // NOI18N
}
EditableProperties ep = getUpdateHelper().getProperties(path);
// check project's main class
// Check whether main class is defined in this config. Note that we use the evaluator,
// not ep.getProperty(MAIN_CLASS), since it is permissible for the default pseudoconfig
// to define a main class - in this case an active config need not override it.
String mainClass = project.evaluator().getProperty(RubyProjectProperties.MAIN_CLASS);
MainClassStatus result = isSetMainClass (project.getSourceRoots().getRoots(), mainClass);
if (context.lookup(RubyConfigurationProvider.Config.class) != null) {
// If a specific config was selected, just skip this check for now.
// XXX would ideally check that that config in fact had a main class.
// But then evaluator.getProperty(MAIN_CLASS) would be inaccurate.
// Solvable but punt on it for now.
result = MainClassStatus.SET_AND_VALID;
}
if (result != MainClassStatus.SET_AND_VALID) {
do {
// show warning, if cancel then return
if (showMainClassWarning (mainClass, ProjectUtils.getInformation(project).getDisplayName(), ep,result)) {
return;
}
// No longer use the evaluator: have not called putProperties yet so it would not work.
mainClass = ep.get(RubyProjectProperties.MAIN_CLASS);
result=isSetMainClass (project.getSourceRoots().getRoots(), mainClass);
} while (result != MainClassStatus.SET_AND_VALID);
try {
if (getUpdateHelper().requestSave()) {
getUpdateHelper().putProperties(path, ep);
ProjectManager.getDefault().saveProject(project);
}
else {
return;
}
} catch (IOException ioe) {
ErrorManager.getDefault().log(ErrorManager.INFORMATIONAL, "Error while saving project: " + ioe); // NOI18N
}
}
// Save all files first
LifecycleManager.getDefault().saveAll();
String displayName = (mainClass != null) ?
NbBundle.getMessage(RubyActionProvider.class, "Ruby") :
NbBundle.getMessage(RubyActionProvider.class, "Rake");
ProjectInformation info = ProjectUtils.getInformation(project);
if (info != null) {
displayName = info.getDisplayName();
}
if (mainClass != null) {
// TODO - compute mainclass
FileObject fileObject = null;
runRubyScript(fileObject, mainClass, displayName, context, COMMAND_DEBUG.equals(command));
return;
}
// Default to running rake
if (!platform.hasRubyGemsInstalled(true) || !platform.hasValidRake(true)) {
return;
}
RubyFileLocator fileLocator = new RubyFileLocator(context, project);
File pwd = getSourceFolder(); // Or project directory?
String classPath = project.evaluator().getProperty(RubyProjectProperties.JAVAC_CLASSPATH);
RubyExecutionDescriptor desc = new RubyExecutionDescriptor(platform, displayName, pwd, platform.getRake()).
fileLocator(fileLocator).
allowInput().
classPath(classPath).
appendJdkToPath(platform.isJRuby()).
addStandardRecognizers().
addErrConvertor(LineConvertors.filePattern(fileLocator,
RubyLineConvertorFactory.RUBY_TEST_OUTPUT,
RubyLineConvertorFactory.EXT_RE, 1, 2)).
addOutConvertor(LineConvertors.filePattern(fileLocator,
RubyLineConvertorFactory.RUBY_TEST_OUTPUT,
RubyLineConvertorFactory.EXT_RE, 1, 2));
RubyCoverageProvider coverageProvider = RubyCoverageProvider.get(project);
if (coverageProvider != null && coverageProvider.isEnabled()) {
desc = coverageProvider.wrapWithCoverage(desc, false, null);
}
RubyProcessCreator rpc = new RubyProcessCreator(desc, getSourceEncoding());
ExecutionService.newService(rpc, desc.toExecutionDescriptor(), displayName);
return;
} else if (COMMAND_RUN_SINGLE.equals(command) || COMMAND_DEBUG_SINGLE.equals(command)) {
if (!platform.isValid(true)) {
return;
}
FileObject file = getCurrentFile(context);
if (RakeSupport.isRakeFile(file)) {
if (!platform.hasValidRake(true)) {
return;
}
// Save all files first - this rake file could be accessing other files
LifecycleManager.getDefault().saveAll();
RakeRunner runner = new RakeRunner(project);
runner.setRakeFile(file);
runner.setFileLocator(new RubyFileLocator(context, project));
runner.showWarnings(true);
runner.setDebug(COMMAND_DEBUG_SINGLE.equals(command));
runner.run();
return;
}
RSpecSupport rspec = new RSpecSupport(project);
if (rspec.isRSpecInstalled() && RSpecSupport.isSpecFile(file)) {
// Save all files first - this rake file could be accessing other files
LifecycleManager.getDefault().saveAll();
TestRunner rspecRunner = Util.getTestRunner(TestRunner.TestType.RSPEC);
if (rspecRunner != null) {
rspecRunner.runTest(file, COMMAND_DEBUG_SINGLE.equals(command));
} else {
rspec.runRSpec(null, file, file.getName(), new RubyFileLocator(context, project), true,
COMMAND_DEBUG_SINGLE.equals(command));
}
return;
}
saveFile(file);
//String target = FileUtil.getRelativePath(getRoot(project.getSourceRoots().getRoots(),file), file);
if (file.getName().endsWith("_test")) { // NOI18N
// Run test normally - don't pop up browser
TestRunner testRunner = Util.getTestRunner(TestRunner.TestType.TEST_UNIT);
if (testRunner != null) {
testRunner.getInstance().runTest(file, COMMAND_DEBUG_SINGLE.equals(command));
return;
}
}
runRubyScript(file, FileUtil.toFile(file).getAbsolutePath(),
file.getNameExt(), context, COMMAND_DEBUG_SINGLE.equals(command), (LineConvertor) null);
return;
} else if (COMMAND_REBUILD.equals(command) || COMMAND_BUILD.equals(command) || COMMAND_CLEAN.equals(command)) {
RakeRunner runner = new RakeRunner(project);
runner.showWarnings(true);
if (COMMAND_REBUILD.equals(command)) {
runner.run("clean", "gem"); // NOI18N
} else if (COMMAND_BUILD.equals(command)) {
runner.run("gem"); // NOI18N
} else { // if(COMMAND_CLEAN.equals(command)) {
runner.run("clean"); // NOI18N
}
return;
}
if (COMMAND_RDOC.equals(command)) {
LifecycleManager.getDefault().saveAll();
File pwd = FileUtil.toFile(project.getProjectDirectory());
Runnable showBrowser = new Runnable() {
public void run() {
// TODO - wait for the file to be created
// Open brower on the doc directory
FileObject doc = project.getProjectDirectory().getFileObject("doc"); // NOI18N
if (doc != null) {
FileObject index = doc.getFileObject("index.html"); // NOI18N
if (index != null) {
try {
URL url = FileUtil.toFile(index).toURI().toURL();
HtmlBrowser.URLDisplayer.getDefault().showURL(url);
}
catch (MalformedURLException ex) {
ErrorManager.getDefault().notify(ex);
}
}
}
}
};
RubyFileLocator fileLocator = new RubyFileLocator(context, project);
String displayName = NbBundle.getMessage(RubyActionProvider.class, "RubyDocumentation");
RubyExecutionDescriptor desc = new RubyExecutionDescriptor(platform, displayName, pwd).
additionalArgs("-r", "rdoc/rdoc", "-e", "begin; r = RDoc::RDoc.new; r.document(ARGV); end"). // NOI18N
fileLocator(fileLocator).
postBuild(showBrowser).
addStandardRecognizers();
RubyProcessCreator rpc = new RubyProcessCreator(desc, getSourceEncoding());
ExecutionService.newService(rpc, desc.toExecutionDescriptor(), displayName).run();
return;
}
if (COMMAND_AUTOTEST.equals(command)) {
if (AutoTestSupport.isInstalled(project, TestType.AUTOTEST)) {
AutoTestSupport support = new AutoTestSupport(context, project, getSourceEncoding());
support.setClassPath(project.evaluator().getProperty(RubyProjectProperties.JAVAC_CLASSPATH));
support.start(TestType.AUTOTEST);
}
return;
}
if (COMMAND_AUTOSPEC.equals(command)) {
if (AutoTestSupport.isInstalled(project, TestType.AUTOSPEC)) {
AutoTestSupport support = new AutoTestSupport(context, project, getSourceEncoding());
support.setClassPath(project.evaluator().getProperty(RubyProjectProperties.JAVAC_CLASSPATH));
support.start(TestType.AUTOSPEC);
}
return;
}
if (COMMAND_TEST_SINGLE.equals(command) || COMMAND_DEBUG_TEST_SINGLE.equals(command)) {
if (!platform.isValid(true)) {
return;
}
// Run test normally - don't pop up browser
FileObject file = getCurrentFile(context);
if (file == null) {
return;
}
saveFile(file);
// If we try to "test" a file that has a corresponding test file,
// run/debug the test file instead
DeclarationLocation location = new GotoTest().findTest(file, -1);
if (location != DeclarationLocation.NONE) {
file = location.getFileObject();
// Save the test file too
saveFile(file);
}
boolean isDebug = COMMAND_DEBUG_TEST_SINGLE.equals(command);
RSpecSupport rspec = new RSpecSupport(project);
if (rspec.isRSpecInstalled() && RSpecSupport.isSpecFile(file)) {
TestRunner rspecRunner = Util.getTestRunner(TestRunner.TestType.RSPEC);
if (rspecRunner != null) {
rspecRunner.runTest(file, isDebug);
} else {
rspec.runRSpec(null, file, file.getName(), new RubyFileLocator(context, project), true,
isDebug);
}
return;
}
TestRunner testRunner = Util.getTestRunner(TestRunner.TestType.TEST_UNIT);
if (testRunner != null) {
testRunner.getInstance().runTest(file, isDebug);
} else {
runRubyScript(file, FileUtil.toFile(file).getAbsolutePath(),
file.getNameExt(), context, isDebug, new TestNotifierLineConvertor(true, true));
}
}
if (COMMAND_TEST.equals(command)) {
TestRunner testRunner = Util.getTestRunner(TestRunner.TestType.TEST_UNIT);
boolean testTaskExist = RakeSupport.getRakeTask(project, TEST_TASK_NAME) != null;
if (testTaskExist) {
File pwd = FileUtil.toFile(project.getProjectDirectory());
RakeRunner runner = new RakeRunner(project);
runner.setPWD(pwd);
runner.setFileLocator(new RubyFileLocator(context, project));
runner.showWarnings(true);
runner.setDebug(COMMAND_DEBUG_SINGLE.equals(command));
runner.run(TEST_TASK_NAME);
} else if (testRunner != null) {
testRunner.getInstance().runAllTests(project, false);
}
return;
}
if (COMMAND_RSPEC.equals(command)) {
boolean rspecTaskExists = RakeSupport.getRakeTask(project, RSPEC_TASK_NAME) != null;
TestRunner testRunner = Util.getTestRunner(TestRunner.TestType.RSPEC);
if (rspecTaskExists) {
File pwd = FileUtil.toFile(project.getProjectDirectory());
RakeRunner runner = new RakeRunner(project);
runner.setPWD(pwd);
runner.setFileLocator(new RubyFileLocator(context, project));
runner.showWarnings(true);
runner.run(RSPEC_TASK_NAME); // NOI18N
} else if (testRunner != null) {
testRunner.getInstance().runAllTests(project, false);
}
return;
}
if (COMMAND_RSPEC_ALL.equals(command)) {
TestRunner testRunner = Util.getTestRunner(TestRunner.TestType.RSPEC);
if (testRunner != null) {
testRunner.getInstance().runAllTests(project, false);
}
return;
}
if (COMMAND_IRB_CONSOLE.equals(command)) {
openIrbConsole(context);
return;
}
if (COMMAND_DELETE.equals(command)) {
DefaultProjectOperations.performDefaultDeleteOperation(project);
return;
}
if (COMMAND_COPY.equals(command)) {
DefaultProjectOperations.performDefaultCopyOperation(project);
return;
}
if (COMMAND_MOVE.equals(command)) {
DefaultProjectOperations.performDefaultMoveOperation(project);
return;
}
if (COMMAND_RENAME.equals(command)) {
DefaultProjectOperations.performDefaultRenameOperation(project, null);
return;
}
}
public boolean isActionEnabled( String command, Lookup context ) {
if (getPlatform() == null) {
return false;
}
if ( command.equals( COMMAND_COMPILE_SINGLE ) ) {
return findSourcesAndPackages( context, project.getSourceRoots().getRoots()) != null
|| findSourcesAndPackages( context, project.getTestSourceRoots().getRoots()) != null;
} else if (command.equals(COMMAND_RUN_SINGLE) ||
command.equals(COMMAND_DEBUG_SINGLE)) {
if (RakeSupport.isRakeFileSelected(context)) {
return true;
}
FileObject fos[] = findSources(context);
if (fos != null && fos.length == 1) {
return true;
}
fos = findTestSources(context);
return fos != null && fos.length == 1;
} else {
// other actions are global
return true;
}
}
protected FileObject[] findSourcesAndPackages (Lookup context, FileObject srcDir) {
if (srcDir != null) {
FileObject[] files = findSelectedFiles(context, srcDir, null, true); // NOI18N
//Check if files are either packages or Ruby files
if (files != null) {
for (int i = 0; i < files.length; i++) {
if (!files[i].isFolder() && files[i].getMIMEType().equals(RubyInstallation.RUBY_MIME_TYPE)) {
return null;
}
}
}
return files;
} else {
return null;
}
}
private FileObject[] findSourcesAndPackages (Lookup context, FileObject[] srcRoots) {
for (int i=0; i<srcRoots.length; i++) {
FileObject[] result = findSourcesAndPackages(context, srcRoots[i]);
if (result != null) {
return result;
}
}
return null;
}
private FileObject getRoot (FileObject[] roots, FileObject file) {
assert file != null : "File can't be null"; //NOI18N
FileObject srcDir = null;
for (int i=0; i< roots.length; i++) {
assert roots[i] != null : "Source Path Root can't be null"; //NOI18N
if (FileUtil.isParentOf(roots[i],file) || roots[i].equals(file)) {
srcDir = roots[i];
break;
}
}
return srcDir;
}
private static enum MainClassStatus {
SET_AND_VALID,
SET_BUT_INVALID,
UNSET
}
/**
* Tests if the main class is set.
*
* @param sourcesRoots source roots
* @param mainClass main class name
* @return status code
*/
private MainClassStatus isSetMainClass(FileObject[] sourcesRoots, String mainClass) {
// support for unit testing
if (MainClassChooser.unitTestingSupport_hasMainMethodResult != null) {
return MainClassChooser.unitTestingSupport_hasMainMethodResult ? MainClassStatus.SET_AND_VALID : MainClassStatus.SET_BUT_INVALID;
}
if (mainClass == null || mainClass.length () == 0) {
return MainClassStatus.UNSET;
}
//ClassPath classPath = ClassPath.getClassPath (sourcesRoots[0], ClassPath.EXECUTE); //Single compilation unit
if (RubyProjectUtil.isMainClass (mainClass, sourcesRoots)) {
return MainClassStatus.SET_AND_VALID;
}
return MainClassStatus.SET_BUT_INVALID;
}
/**
* Asks user for name of main class.
*
* @param mainClass current main class
* @param projectName the name of project
* @param ep project.properties to possibly edit
* @param messgeType type of dialog
* @return true if user selected main class
*/
private boolean showMainClassWarning(String mainClass, String projectName, EditableProperties ep, MainClassStatus messageType) {
boolean canceled;
final JButton okButton = new JButton (NbBundle.getMessage (RubyActionProvider.class, "LBL_MainClassWarning_ChooseMainClass_OK")); // NOI18N
okButton.getAccessibleContext().setAccessibleDescription (NbBundle.getMessage (RubyActionProvider.class, "AD_MainClassWarning_ChooseMainClass_OK"));
// main class goes wrong => warning
String message;
switch (messageType) {
case UNSET:
message = MessageFormat.format (NbBundle.getMessage(RubyActionProvider.class,"LBL_MainClassNotFound"), new Object[] {
projectName
});
break;
case SET_BUT_INVALID:
message = MessageFormat.format (NbBundle.getMessage(RubyActionProvider.class,"LBL_MainClassWrong"), new Object[] {
mainClass,
projectName
});
break;
default:
throw new IllegalArgumentException ();
}
final MainClassWarning panel = new MainClassWarning (message,project.getSourceRoots().getRoots());
Object[] options = new Object[] {
okButton,
DialogDescriptor.CANCEL_OPTION
};
panel.addChangeListener (new ChangeListener () {
public void stateChanged (ChangeEvent e) {
if (e.getSource () instanceof MouseEvent && MouseUtils.isDoubleClick (((MouseEvent)e.getSource ()))) {
// click button and the finish dialog with selected class
okButton.doClick ();
} else {
okButton.setEnabled (panel.getSelectedMainClass () != null);
}
}
});
okButton.setEnabled (false);
DialogDescriptor desc = new DialogDescriptor (panel,
NbBundle.getMessage (RubyActionProvider.class, "CTL_MainClassWarning_Title", ProjectUtils.getInformation(project).getDisplayName()), // NOI18N
true, options, options[0], DialogDescriptor.BOTTOM_ALIGN, null, null);
desc.setMessageType (DialogDescriptor.INFORMATION_MESSAGE);
Dialog dlg = DialogDisplayer.getDefault ().createDialog (desc);
dlg.setVisible (true);
if (desc.getValue() != options[0]) {
canceled = true;
} else {
mainClass = panel.getSelectedMainClass ();
canceled = false;
ep.put(RubyProjectProperties.MAIN_CLASS, mainClass == null ? "" : mainClass);
}
dlg.dispose();
return canceled;
}
// From the ant module - ActionUtils.
// However, I've modified it to do its search based on mime type rather than
// file suffixes (since some Ruby files do not use a .rb extension and are
// discovered based on the initial shebang line)
private File getSourceFolder() {
// Default to using the project source directory
FileObject[] srcPath = project.getSourceRoots().getRoots();
if (srcPath != null && srcPath.length > 0) {
return FileUtil.toFile(srcPath[0]);
} else {
return FileUtil.toFile(project.getProjectDirectory());
}
}
}