package org.jbehave.plugin.eclipse;
import java.lang.reflect.InvocationTargetException;
import java.text.MessageFormat;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IWorkspace;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.debug.core.ILaunchConfiguration;
import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
import org.eclipse.jdt.core.IClassFile;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IJavaModel;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IMember;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.search.IJavaSearchConstants;
import org.eclipse.jdt.core.search.IJavaSearchScope;
import org.eclipse.jdt.core.search.SearchEngine;
import org.eclipse.jdt.debug.ui.launchConfigurations.JavaLaunchTab;
import org.eclipse.jdt.internal.debug.ui.JDIDebugUIPlugin;
import org.eclipse.jdt.internal.debug.ui.launcher.MainMethodSearchEngine;
import org.eclipse.jdt.internal.ui.dialogs.OpenTypeSelectionDialog2;
import org.eclipse.jdt.launching.IJavaLaunchConfigurationConstants;
import org.eclipse.jdt.ui.JavaElementLabelProvider;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.viewers.ILabelProvider;
import org.eclipse.jface.window.Window;
import org.eclipse.swt.SWT;
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.Font;
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.Shell;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.dialogs.ElementListSelectionDialog;
public class JBehaveMainTab extends JavaLaunchTab {
private static final String BEHAVIOUR_CHOOSING_ERROR = "Behaviour Choosing Error";
private static final Image behaviourIcon= createImage("icons/behave.gif"); //$NON-NLS-1$
// Project UI widgets
protected Text projectText;
protected Button projectButton;
// Main class UI widgets
protected Text behaviourText;
protected Button searchButton;
protected static final String EMPTY_STRING = ""; //$NON-NLS-1$
protected static Image createImage(String path) {
return JBehavePlugin.getImageDescriptor(path).createImage();
}
/**
* A listener which handles widget change events for the controls
* in this tab.
*/
private class WidgetListener implements ModifyListener, SelectionListener {
public void modifyText(ModifyEvent e) {
updateLaunchConfigurationDialog();
}
public void widgetSelected(SelectionEvent e) {
Object source = e.getSource();
if (source == projectButton) {
handleProjectButtonSelected();
} else if (source == searchButton) {
handleBehaviourSearchButtonSelected();
} else {
updateLaunchConfigurationDialog();
}
}
public void widgetDefaultSelected(SelectionEvent e) {
}
}
private WidgetListener listener = new WidgetListener();
/**
* @see org.eclipse.debug.ui.ILaunchConfigurationTab#createControl(Composite)
*/
public void createControl(Composite parent) {
Font font = parent.getFont();
Composite comp = new Composite(parent, SWT.NONE);
setControl(comp);
// PlatformUI.getWorkbench().getHelpSystem().setHelp(getControl(), IJavaDebugHelpContextIds.LAUNCH_CONFIGURATION_DIALOG_MAIN_TAB);
GridLayout topLayout = new GridLayout();
topLayout.verticalSpacing = 0;
comp.setLayout(topLayout);
comp.setFont(font);
createProjectEditor(comp);
createVerticalSpacer(comp, 1);
createBehaviorTypeEditor(comp);
createVerticalSpacer(comp, 1);
}
/**
* Creates the widgets for specifying a main type.
*
* @param parent the parent composite
*/
private void createBehaviorTypeEditor(Composite parent) {
Font font= parent.getFont();
Group behaviorGroup= new Group(parent, SWT.NONE);
behaviorGroup.setText("Behaviour Class"); //$NON-NLS-1$
GridData gd = new GridData(GridData.FILL_HORIZONTAL);
behaviorGroup.setLayoutData(gd);
GridLayout layout = new GridLayout();
layout.numColumns = 2;
behaviorGroup.setLayout(layout);
behaviorGroup.setFont(font);
behaviourText = new Text(behaviorGroup, SWT.SINGLE | SWT.BORDER);
gd = new GridData(GridData.FILL_HORIZONTAL);
behaviourText.setLayoutData(gd);
behaviourText.setFont(font);
behaviourText.addModifyListener(listener);
searchButton = createPushButton(behaviorGroup, "Search...", null); //$NON-NLS-1$
searchButton.addSelectionListener(listener);
}
/**
* Creates the widgets for specifying a main type.
*
* @param parent the parent composite
*/
private void createProjectEditor(Composite parent) {
Font font= parent.getFont();
Group group= new Group(parent, SWT.NONE);
group.setText("Choose a project to matcher the search for behaviour types"); //$NON-NLS-1$
GridData gd = new GridData(GridData.FILL_HORIZONTAL);
group.setLayoutData(gd);
GridLayout layout = new GridLayout();
layout.numColumns = 2;
group.setLayout(layout);
group.setFont(font);
projectText = new Text(group, SWT.SINGLE | SWT.BORDER);
gd = new GridData(GridData.FILL_HORIZONTAL);
projectText.setLayoutData(gd);
projectText.setFont(font);
projectText.addModifyListener(listener);
projectButton = createPushButton(group, "Browse...", null); //$NON-NLS-1$
projectButton.addSelectionListener(listener);
}
/**
* @see org.eclipse.debug.ui.ILaunchConfigurationTab#initializeFrom(ILaunchConfiguration)
*/
public void initializeFrom(ILaunchConfiguration config) {
updateProjectFromConfig(config);
updateBehaviorTypeFromConfig(config);
}
protected void updateProjectFromConfig(ILaunchConfiguration config) {
String projectName = ""; //$NON-NLS-1$
try {
projectName = config.getAttribute(IJavaLaunchConfigurationConstants.ATTR_PROJECT_NAME, EMPTY_STRING);
} catch (CoreException ce) {
JBehavePlugin.log(ce);
}
projectText.setText(projectName);
}
protected void updateBehaviorTypeFromConfig(ILaunchConfiguration config) {
String behaviorTypeName = ""; //$NON-NLS-1$
try {
behaviorTypeName = config.getAttribute(
JBehaveLaunchConfiguration.ATTR_BEHAVIOUR_CLASS, EMPTY_STRING);
} catch (CoreException ce) {
JBehavePlugin.log(ce);
}
behaviourText.setText(behaviorTypeName);
}
/**
* @see org.eclipse.debug.ui.ILaunchConfigurationTab#performApply(ILaunchConfigurationWorkingCopy)
*/
public void performApply(ILaunchConfigurationWorkingCopy config) {
ConfigurationState state = new ConfigurationState();
state.setProjectName(projectText.getText().trim());
state.setBehaviorClass(behaviourText.getText().trim());
state.setAttributes(config);
}
/**
* @see org.eclipse.debug.ui.ILaunchConfigurationTab#dispose()
*/
public void dispose() {
}
/**
* Show a dialog that lists all main types
*/
protected void handleBehaviourSearchButtonSelected() {
Shell shell = getShell();
IJavaProject javaProject = getJavaProject();
OpenTypeSelectionDialog2 dialog= new OpenTypeSelectionDialog2(
shell, false,
PlatformUI.getWorkbench().getProgressService(),
null, IJavaSearchConstants.TYPE);
dialog.setTitle("Search Behaviour Class");
dialog.setMessage("Search for the behaviour class to verify");
int result= dialog.open();
if (result != IDialogConstants.OK_ID)
return;
Object[] types= dialog.getResult();
if (types != null && types.length > 0) {
IType type= (IType)types[0];
behaviourText.setText(type.getFullyQualifiedName('.'));
javaProject = type.getJavaProject();
projectText.setText(javaProject.getElementName());
}
}
/**
* Show a dialog that lets the user select a project. This in turn provides
* context for the main type, allowing the user to key a main type name, or
* constraining the search for main types to the specified project.
*/
protected void handleProjectButtonSelected() {
IJavaProject project = chooseJavaProject();
if (project == null) {
return;
}
String projectName = project.getElementName();
projectText.setText(projectName);
}
/**
* Realize a Java Project selection dialog and return the first selected project,
* or null if there was none.
*/
protected IJavaProject chooseJavaProject() {
IJavaProject[] projects;
try {
projects= JavaCore.create(getWorkspaceRoot()).getJavaProjects();
} catch (JavaModelException e) {
JDIDebugUIPlugin.log(e);
projects= new IJavaProject[0];
}
ILabelProvider labelProvider= new JavaElementLabelProvider(JavaElementLabelProvider.SHOW_DEFAULT);
ElementListSelectionDialog dialog= new ElementListSelectionDialog(getShell(), labelProvider);
dialog.setTitle("Project Select"); //$NON-NLS-1$
dialog.setMessage("Choose a project to constrain the search for behaviour type"); //$NON-NLS-1$
dialog.setElements(projects);
IJavaProject javaProject = getJavaProject();
if (javaProject != null) {
dialog.setInitialSelections(new Object[] { javaProject });
}
if (dialog.open() == Window.OK) {
return (IJavaProject) dialog.getFirstResult();
}
return null;
}
/**
* Return the IJavaProject corresponding to the project name in the project name
* text field, or null if the text does not match a project name.
*/
protected IJavaProject getJavaProject() {
String projectName = projectText.getText().trim();
if (projectName.length() < 1) {
return null;
}
return getJavaModel().getJavaProject(projectName);
}
/**
* Convenience method to get the workspace root.
*/
private IWorkspaceRoot getWorkspaceRoot() {
return ResourcesPlugin.getWorkspace().getRoot();
}
/**
* Convenience method to get access to the java model.
*/
private IJavaModel getJavaModel() {
return JavaCore.create(getWorkspaceRoot());
}
/**
* @see org.eclipse.debug.ui.ILaunchConfigurationTab#isValid(ILaunchConfiguration)
*/
public boolean isValid(ILaunchConfiguration config) {
setErrorMessage(null);
setMessage(null);
String name = projectText.getText().trim();
if (name.length() > 0) {
IWorkspace workspace = ResourcesPlugin.getWorkspace();
IStatus status = workspace.validateName(name, IResource.PROJECT);
if (status.isOK()) {
IProject project= ResourcesPlugin.getWorkspace().getRoot().getProject(name);
if (!project.exists()) {
setErrorMessage(MessageFormat.format(BEHAVIOUR_CHOOSING_ERROR, new String[] {name})); //$NON-NLS-1$
return false;
}
if (!project.isOpen()) {
setErrorMessage(MessageFormat.format(BEHAVIOUR_CHOOSING_ERROR, new String[] {name})); //$NON-NLS-1$
return false;
}
} else {
setErrorMessage(MessageFormat.format(BEHAVIOUR_CHOOSING_ERROR, new String[]{status.getMessage()})); //$NON-NLS-1$
return false;
}
}
name = behaviourText.getText().trim();
if (name.length() == 0) {
setErrorMessage("Behaviour type not specified"); //$NON-NLS-1$
return false;
}
return true;
}
/**
* @see org.eclipse.debug.ui.ILaunchConfigurationTab#setDefaults(ILaunchConfigurationWorkingCopy)
*/
public void setDefaults(ILaunchConfigurationWorkingCopy config) {
IJavaElement javaElement = getContext();
if (javaElement != null) {
initializeJavaProject(javaElement, config);
} else {
// We set empty attributes for project & main type so that when one config is
// compared to another, the existence of empty attributes doesn't cause an
// incorrect result (the performApply() method can result in empty values
// for these attributes being set on a config if there is nothing in the
// corresponding text boxes)
config.setAttribute(IJavaLaunchConfigurationConstants.ATTR_PROJECT_NAME, ""); //$NON-NLS-1$
}
initializeBehaviourTypeAndName(javaElement, config);
}
/**
* Set the main type & name attributes on the working copy based on the IJavaElement
*/
protected void initializeBehaviourTypeAndName(IJavaElement javaElement, ILaunchConfigurationWorkingCopy config) {
String name= null;
if (javaElement instanceof IMember) {
IMember member = (IMember)javaElement;
if (member.isBinary()) {
javaElement = member.getClassFile();
} else {
javaElement = member.getCompilationUnit();
}
}
if (javaElement instanceof ICompilationUnit || javaElement instanceof IClassFile) {
try {
IJavaSearchScope scope = SearchEngine.createJavaSearchScope(new IJavaElement[]{javaElement}, false);
MainMethodSearchEngine engine = new MainMethodSearchEngine();
IType[] types = engine.searchMainMethods(getLaunchConfigurationDialog(), scope, false);
if (types != null && (types.length > 0)) {
// Simply grab the first main type found in the searched element
name = types[0].getFullyQualifiedName();
}
} catch (InterruptedException ie) {
} catch (InvocationTargetException ite) {
}
}
if (name == null) {
name= ""; //$NON-NLS-1$
}
config.setAttribute(IJavaLaunchConfigurationConstants.ATTR_MAIN_TYPE_NAME, name);
if (name.length() > 0) {
int index = name.lastIndexOf('.');
if (index > 0) {
name = name.substring(index + 1);
}
name = getLaunchConfigurationDialog().generateName(name);
config.rename(name);
}
}
/**
* @see org.eclipse.debug.ui.ILaunchConfigurationTab#getName()
*/
public String getName() {
return "Behaviour";
}
/**
* @see org.eclipse.debug.ui.ILaunchConfigurationTab#getImage()
*/
public Image getImage() {
return behaviourIcon;
}
/* (non-Javadoc)
* @see org.eclipse.debug.ui.ILaunchConfigurationTab#activated(org.eclipse.debug.core.ILaunchConfigurationWorkingCopy)
*/
public void activated(ILaunchConfigurationWorkingCopy workingCopy) {
// do nothing when activated
}
/* (non-Javadoc)
* @see org.eclipse.debug.ui.ILaunchConfigurationTab#deactivated(org.eclipse.debug.core.ILaunchConfigurationWorkingCopy)
*/
public void deactivated(ILaunchConfigurationWorkingCopy workingCopy) {
// do nothing when deactivated
}
}