/*******************************************************************************
* Copyright (c) 2005, 2010 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package com.redhat.ceylon.eclipse.core.launch;
import static com.redhat.ceylon.eclipse.ui.CeylonPlugin.PLUGIN_ID;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.debug.core.DebugPlugin;
import org.eclipse.debug.core.ILaunchConfiguration;
import org.eclipse.debug.core.ILaunchConfigurationType;
import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.internal.debug.ui.IJavaDebugHelpContextIds;
import org.eclipse.jdt.internal.debug.ui.JDIDebugUIPlugin;
import org.eclipse.jdt.internal.debug.ui.actions.ControlAccessibleListener;
import org.eclipse.jdt.internal.debug.ui.launcher.AbstractJavaMainTab;
import org.eclipse.jdt.internal.debug.ui.launcher.LauncherMessages;
import org.eclipse.jdt.launching.IJavaLaunchConfigurationConstants;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.PlatformUI;
import com.redhat.ceylon.model.typechecker.model.Declaration;
import com.redhat.ceylon.model.typechecker.model.Module;
import com.redhat.ceylon.eclipse.core.builder.CeylonNature;
import com.redhat.ceylon.eclipse.ui.CeylonResources;
/**
* A launch configuration tab that displays and edits Ceylon project and
* module name launch configuration attributes.
*/
public class CeylonModuleTab extends AbstractJavaMainTab {
private Text fModuleText;
private Text fTopLevelText;
private Button fModuleSearchButton;
private Button fTopLevelSearchButton;
private Button verboseCheck;
private Button fStopInMainCheckButton;
public void createControl(Composite parent) {
Composite comp = SWTFactory.createComposite(parent, parent.getFont(), 1, 1, GridData.FILL_BOTH);
((GridLayout)comp.getLayout()).verticalSpacing = 0;
createProjectEditor(comp);
createVerticalSpacer(comp, 1);
createModuleEditor(comp, "Module:");
createVerticalSpacer(comp, 1);
createDeclarationEditor(comp, "Runnable function or class (must be toplevel and shared, with no parameters):");
setControl(comp);
PlatformUI.getWorkbench().getHelpSystem().setHelp(getControl(), IJavaDebugHelpContextIds.LAUNCH_CONFIGURATION_DIALOG_MAIN_TAB);
}
public Image getImage() {
return CeylonResources.MODULE;
}
public String getName() {
return "Module";
}
/**
* @see org.eclipse.debug.ui.AbstractLaunchConfigurationTab#getId()
*
* @since 3.3
*/
public String getId() {
return PLUGIN_ID + ".ceylonModuleTab"; //$NON-NLS-1$
}
/**
* Show a dialog that lists all modules in project
*/
protected void handleModuleSearchButtonSelected() {
Module mod = LaunchHelper.chooseModule(LaunchHelper.getProjectFromName(this.fProjText.getText()), true);
if (mod != null) {
if (mod.isDefaultModule()) {
fModuleText.setText(Module.DEFAULT_MODULE_NAME);
} else {
fModuleText.setText(LaunchHelper.getFullModuleName(mod));
}
Declaration topLevel = LaunchHelper.getDefaultRunnableForModule(mod);
// fill the field, else leave blank
if (topLevel != null) {
this.fTopLevelText.setText(LaunchHelper.getTopLevelDisplayName(topLevel));
}
}
}
/**
* Show a dialog that lists all runnable types
*/
protected void handleSearchButtonSelected() {
Declaration d = LaunchHelper.chooseDeclaration(
LaunchHelper.getDeclarationsForModule(
fProjText.getText(), fModuleText.getText()));
if (d != null) {
fTopLevelText.setText(LaunchHelper.getTopLevelDisplayName(d));
// unique situation in which default module was selected but that the type belongs to a module
Module mod = LaunchHelper.getModule(d);
if (mod != null && !mod.isDefaultModule()) {
fModuleText.setText(LaunchHelper.getModuleFullName(d));
}
}
}
public void initializeFrom(ILaunchConfiguration config) {
super.initializeFrom(config); // sets project
try { // exception in any value renders existing config useless, so combining
fModuleText.setText(
config.getAttribute(ICeylonLaunchConfigurationConstants.ATTR_MODULE_NAME, EMPTY_STRING));
fTopLevelText.setText(
config.getAttribute(ICeylonLaunchConfigurationConstants.ATTR_TOPLEVEL_NAME, EMPTY_STRING));
verboseCheck.setSelection(
config.getAttribute(ICeylonLaunchConfigurationConstants.ATTR_LAUNCH_VERBOSE, false));
updateStopInMainFromConfig(config);
} catch (CoreException ce) {
JDIDebugUIPlugin.log(ce);
}
}
public boolean isValid(ILaunchConfiguration config) {
setErrorMessage(null);
setMessage(null);
String projectName = fProjText.getText().trim();
IProject project = LaunchHelper.getProjectFromName(projectName);
if (project != null) {
if (!project.exists()) {
setErrorMessage("The project " + projectName + " does no exist.");
return false;
}
if (!project.isOpen()) {
setErrorMessage("The project " + projectName + " is not opened");
return false;
}
if (!CeylonNature.isEnabled(project)) {
setErrorMessage("The project " + projectName + " is not a Ceylon project");
return false;
}
try {
ILaunchConfigurationType launchType = getCurrentLaunchConfiguration().getType();
boolean javaEnabled = LaunchHelper.isBuilderEnabled(project,
ICeylonLaunchConfigurationConstants.CAN_LAUNCH_AS_CEYLON_JAVA_MODULE);
boolean jsEnabled = LaunchHelper.isBuilderEnabled(project,
ICeylonLaunchConfigurationConstants.CAN_LAUNCH_AS_CEYLON_JAVASCIPT_MODULE);
if (launchType.equals(DebugPlugin.getDefault().getLaunchManager()
.getLaunchConfigurationType(ICeylonLaunchConfigurationConstants.ID_CEYLON_JAVA_MODULE))
&& !javaEnabled) {
setErrorMessage("The project " + projectName + " is not enabled to run as a Java module");
return false;
}
if (launchType.equals(DebugPlugin.getDefault().getLaunchManager()
.getLaunchConfigurationType(ICeylonLaunchConfigurationConstants.ID_CEYLON_JAVASCRIPT_MODULE))
&& !jsEnabled) {
setErrorMessage("The project " + projectName + " is not enabled to run as a JavaScript module");
return false;
}
} catch (CoreException e) {
e.printStackTrace(); // TODO logger
}
} else {
return false;
}
String moduleName = fModuleText.getText().trim();
if (moduleName == null || moduleName.length() == 0) {
setErrorMessage("The Ceylon module is not specified");
return false;
}
if (!LaunchHelper.isModuleInProject(project, moduleName)) {
setErrorMessage("Ceylon module not found in project");
return false;
}
String topLevelName = fTopLevelText.getText().trim();
if (topLevelName == null || topLevelName.length() == 0) {
setErrorMessage("The top level class or function is not specified");
return false;
}
if (!LaunchHelper.isModuleContainsTopLevel(project, moduleName,
LaunchHelper.getTopLevelNormalName(moduleName, topLevelName))) {
setErrorMessage("The top level class not found in module or is not runnable");
return false;
}
// can't think of anything else
return true;
}
public void performApply(ILaunchConfigurationWorkingCopy config) {
config.setAttribute(IJavaLaunchConfigurationConstants.ATTR_PROJECT_NAME, fProjText.getText().trim());
config.setAttribute(ICeylonLaunchConfigurationConstants.ATTR_MODULE_NAME, fModuleText.getText().trim());
config.setAttribute(ICeylonLaunchConfigurationConstants.ATTR_TOPLEVEL_NAME, fTopLevelText.getText().trim());
config.setAttribute(ICeylonLaunchConfigurationConstants.ATTR_LAUNCH_VERBOSE, verboseCheck.getSelection());
mapResources(config);
// attribute added in 2.1, so null must be used instead of false for backwards compatibility
if (fStopInMainCheckButton.getSelection()) {
config.setAttribute(IJavaLaunchConfigurationConstants.ATTR_STOP_IN_MAIN, true);
}
else {
config.setAttribute(IJavaLaunchConfigurationConstants.ATTR_STOP_IN_MAIN, (String)null);
}
}
public void setDefaults(ILaunchConfigurationWorkingCopy config) {
IJavaElement javaElement = getContext();
if (javaElement != null) {
initializeJavaProject(javaElement, config);
}
else {
config.setAttribute(IJavaLaunchConfigurationConstants.ATTR_PROJECT_NAME, EMPTY_STRING);
}
String projectName = "";
String moduleName = null;
String topLevelName = null;
if (javaElement == null) {
return;
}
Module module = null;
if (getContext().getJavaProject().exists()) {
module = LaunchHelper.getDefaultOrOnlyModule(getContext().getJavaProject().getProject(), true);
projectName = getContext().getJavaProject().getProject().getName();
}
if (module != null) {
moduleName = LaunchHelper.getFullModuleName(module);
}
if (moduleName == null) {
moduleName = EMPTY_STRING;
}
config.setAttribute(ICeylonLaunchConfigurationConstants.ATTR_MODULE_NAME, moduleName);
if (moduleName.length() > 0) {
moduleName = getLaunchConfigurationDialog().generateName(moduleName);
}
Declaration topLevel = null;
if (module != null) {
topLevel = LaunchHelper.getDefaultRunnableForModule(module);
}
if (topLevel != null) {
topLevelName = LaunchHelper.getRunnableName(topLevel);
}
if (topLevelName == null) {
topLevelName = EMPTY_STRING;
}
config.setAttribute(ICeylonLaunchConfigurationConstants.ATTR_TOPLEVEL_NAME, topLevelName);
if (topLevelName.length() > 0) {
topLevelName = getLaunchConfigurationDialog().generateName(topLevelName);
}
config.rename(projectName + " \u2014 " + moduleName + " \u2014 " + topLevelName);
}
protected void createModuleEditor(Composite parent, String text) {
Group group = SWTFactory.createGroup(parent, text, 2, 1, GridData.FILL_HORIZONTAL);
fModuleText = SWTFactory.createSingleText(group, 1);
fModuleText.addModifyListener(new ModifyListener() {
public void modifyText(ModifyEvent e) {
updateLaunchConfigurationDialog();
}
});
ControlAccessibleListener.addListener(fModuleText, group.getText());
fModuleSearchButton = createPushButton(group, LauncherMessages.AbstractJavaMainTab_2, null);
fModuleSearchButton.addSelectionListener(new SelectionListener() {
public void widgetDefaultSelected(SelectionEvent e) {
}
public void widgetSelected(SelectionEvent e) {
handleModuleSearchButtonSelected();
}
});
}
protected void createDeclarationEditor(Composite parent, String text) {
Group group = SWTFactory.createGroup(parent, text, 2, 1, GridData.FILL_HORIZONTAL);
fTopLevelText = SWTFactory.createSingleText(group, 1);
fTopLevelText.addModifyListener(new ModifyListener() {
public void modifyText(ModifyEvent e) {
updateLaunchConfigurationDialog();
}
});
ControlAccessibleListener.addListener(fModuleText, group.getText());
fTopLevelSearchButton = createPushButton(group, LauncherMessages.AbstractJavaMainTab_2, null);
fTopLevelSearchButton.addSelectionListener(new SelectionListener() {
public void widgetDefaultSelected(SelectionEvent e) {
}
public void widgetSelected(SelectionEvent e) {
handleSearchButtonSelected();
}
});
Composite checks = SWTFactory.createComposite(group, 2, 2, GridData.BEGINNING);
verboseCheck = createCheckButton(checks, "Verbose output"); // creating here just for visual alignment
verboseCheck.addSelectionListener(getDefaultListener());
fStopInMainCheckButton = SWTFactory.createCheckButton(checks, "St&op inside", null, false, 1);
fStopInMainCheckButton.addSelectionListener(getDefaultListener());
}
/**
* updates the stop in main attribute from the specified launch config
* @param config the config to load the stop in main attribute from
*/
private void updateStopInMainFromConfig(ILaunchConfiguration config) {
boolean stop = false;
try {
stop = config.getAttribute(IJavaLaunchConfigurationConstants.ATTR_STOP_IN_MAIN, false);
}
catch (CoreException e) {JDIDebugUIPlugin.log(e);}
fStopInMainCheckButton.setSelection(stop);
}
}