package org.easyb.launch.launcher;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.lang.StringUtils;
import org.easyb.launch.EasybLaunchActivator;
import org.easyb.launch.ILaunchConstants;
import org.easyb.launch.search.BehaviourSearch;
import org.easyb.launch.utils.WidgetUtil;
import org.easyb.launch.viewerfilters.ContainerViewerFilter;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
import org.eclipse.debug.core.ILaunchConfiguration;
import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
import org.eclipse.debug.ui.AbstractLaunchConfigurationTab;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IJavaModel;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.launching.IJavaLaunchConfigurationConstants;
import org.eclipse.jdt.ui.JavaElementLabelProvider;
import org.eclipse.jdt.ui.StandardJavaElementContentProvider;
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.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
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.Label;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.dialogs.ElementListSelectionDialog;
import org.eclipse.ui.dialogs.ElementTreeSelectionDialog;
/**
* Main Easyb configuration tab allowing the user to select a single
* story in a project or multiple stories from a folder or project.
* Thanks to JUnit plugin where most the inspiration for this class came
* from.
* @author whiteda
*
*/
//TODO Class is getting too big refactor
public class BehaviourLaunchMainTab extends AbstractLaunchConfigurationTab
{
private final static String MAIN_TAB_NAME = "easyb_main_tab";
//Single story controls
private Text txtProject;
private Text txtStory;
private Button btnRadioSingleStory;
private Button btnProject;
private Button btnStory;
private Label lblProj;
private Label lblStory;
//Multi story controls
private Button btnRadioMultiStory;
private Text txtMultiStories;
private Button btnMultiStory;
private IJavaElement container;
private IFile storyFile;
private final ILabelProvider elementLabelProvider= new JavaElementLabelProvider();
private class EasybMainTabListener extends SelectionAdapter implements ModifyListener {
@Override
public void modifyText(ModifyEvent event) {
//If this is the single story mode then the project might of been triggered
//so enable the single story box
if(btnRadioSingleStory.getSelection()){
setEnableSingleStory(true);
}
updateLaunchConfigurationDialog();
}
}
private SelectionAdapter projectSelectionListener = new SelectionAdapter(){
public void widgetSelected(SelectionEvent e){
IJavaProject proj = chooseJavaProject();
txtProject.setText(proj.getElementName());
updateLaunchConfigurationDialog();
}
};
private SelectionAdapter resourceSelectionAdapter = new SelectionAdapter(){
public void widgetSelected(SelectionEvent e){
updateElement(chooseContainer(container));
updateLaunchConfigurationDialog();
}
};
private SelectionAdapter storySelectionAdapter = new SelectionAdapter(){
public void widgetSelected(SelectionEvent e){
updateStory(chooseStory());
updateLaunchConfigurationDialog();
}
};
private EasybMainTabListener tabListener = new EasybMainTabListener();
@Override
public void createControl(Composite parent) {
Composite comp = new Composite(parent,SWT.NONE);
setControl(comp);
GridLayout mainLayout = new GridLayout(3,false);
comp.setLayout(mainLayout);
createSingleStoryControls(comp);
createMultiStoryControls(comp);
}
@Override
public String getName() {
return MAIN_TAB_NAME;
}
@Override
public void initializeFrom(ILaunchConfiguration config) {
try {
txtProject.setText(config.getAttribute(
IJavaLaunchConfigurationConstants.ATTR_PROJECT_NAME, ""));
} catch (CoreException ce) {
EasybLaunchActivator.Log("Unable to set project name for launch", ce);
setErrorMessage("Unable to set project from configuration");
}
initialiseStoriesfromConfiguration(config);
}
public void dispose() {
super.dispose();
if(elementLabelProvider!=null){
elementLabelProvider.dispose();
}
}
@Override
public void performApply(ILaunchConfigurationWorkingCopy config) {
config.setAttribute(
IJavaLaunchConfigurationConstants.ATTR_PROJECT_NAME,StringUtils.trimToEmpty(txtProject.getText()));
try{
List<String> stories = getStoriesFullPaths();
config.setAttribute( ILaunchConstants.LAUNCH_ATTR_STORIES_FULL_PATH,stories);
}catch(CoreException cex){
EasybLaunchActivator.Log("Unable apply configuration due to exception while retrieving story locations", cex);
setErrorMessage("Unable apply configuration due to exception while retrieving story locations");
}
if(container !=null){
config.setAttribute(
ILaunchConstants.LAUNCH_ATTR_CONTAINER_HANDLE,container.getHandleIdentifier());
}
if(storyFile!=null){
config.setAttribute(
ILaunchConstants.LAUNCH_ATTR_STORY_PATH,storyFile.getProjectRelativePath().toPortableString());
}
config.setAttribute(
ILaunchConstants.LAUNCH_ATTR_IS_SINGLE_STORY,btnRadioSingleStory.getSelection());
}
@Override
public void setDefaults(ILaunchConfigurationWorkingCopy config) {
IProject proj =
EasybLaunchActivator.getDefault().getSelectedProject();
if(proj!=null){
config.setAttribute(
IJavaLaunchConfigurationConstants.ATTR_PROJECT_NAME,proj.getName());
}
}
@Override
public boolean isValid(ILaunchConfiguration launchConfig) {
setErrorMessage(null);
if(!super.isValid(launchConfig)){
return false;
}
if(btnRadioSingleStory.getSelection()){
if(StringUtils.isBlank(txtProject.getText())){
setErrorMessage("A project has not been set");
return false;
}
if(StringUtils.isBlank(txtStory.getText())){
setErrorMessage("A story has not been set");
return false;
}
}else if(btnRadioMultiStory.getSelection()){
if(StringUtils.isBlank(txtMultiStories.getText())){
setErrorMessage("A Project,Package or Folder has not been selected");
return false;
}
}
return true;
}
protected void initialiseStoriesfromConfiguration(ILaunchConfiguration config){
try {
String containerHandle = config.getAttribute(
ILaunchConstants.LAUNCH_ATTR_CONTAINER_HANDLE, "");
if(!StringUtils.isBlank(containerHandle)){
container = JavaCore.create(containerHandle);
txtMultiStories.setText(container.getElementName());
}
} catch (CoreException ce) {
EasybLaunchActivator.Log("Unable to set project,resource or package name for launch",ce);
setErrorMessage("Unable to set project,folder or package for stories from configuration");
}
try{
String storyProjectPath = config.getAttribute(
ILaunchConstants.LAUNCH_ATTR_STORY_PATH, "");
IPath path = null;
if(!StringUtils.isBlank(storyProjectPath))
{
path = Path.fromPortableString(storyProjectPath);
}
IJavaProject javaProject = getJavaProject();
if(javaProject !=null){
IProject project = javaProject.getProject();
if(project.findMember(path) instanceof IFile){
storyFile = (IFile)project.findMember(path);
}else{
setErrorMessage("Unable to locate "+storyProjectPath+" in project");
}
}else{
setErrorMessage("No project has been set for story");
}
if(storyFile!=null){
txtStory.setText(storyFile.getName());
}else if(!StringUtils.isBlank(storyProjectPath)){
txtStory.setText(storyProjectPath);
}
} catch (CoreException ce) {
EasybLaunchActivator.Log("Unable to set story for launch",ce);
setErrorMessage("Unable to set story for launch");
}
try{
boolean isSingleStory = config.getAttribute(
ILaunchConstants.LAUNCH_ATTR_IS_SINGLE_STORY,true);
setEnableSingleStory(isSingleStory);
setEnableProject(isSingleStory);
setEnableMultiStory(!isSingleStory);
btnRadioSingleStory.setSelection(isSingleStory);
btnRadioMultiStory.setSelection(!isSingleStory);
}catch(CoreException ce){
EasybLaunchActivator.Log("Unable to set single or multi story radio buttons",ce);
setErrorMessage("Unable to set single or multi story radio buttons");
}
}
protected List<String> getStoriesFullPaths()throws CoreException{
List<String> stories = null;
if(btnRadioSingleStory.getSelection() && storyFile !=null){
String singleStory = (storyFile==null?"":storyFile.getRawLocation().toOSString());
stories = new ArrayList<String>(1);
stories.add(singleStory);
}else if(container!=null){
stories = BehaviourSearch.findStoryPaths(container.getResource());
}
return stories;
}
private void createSingleStoryControls(Composite comp){
btnRadioSingleStory = new Button(comp,SWT.RADIO);
btnRadioSingleStory.setText("Run a single story");
GridData gridData = new GridData();
gridData.horizontalSpan = 3;
btnRadioSingleStory.setLayoutData(gridData);
btnRadioSingleStory.setSelection(true);
btnRadioSingleStory.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
if (btnRadioSingleStory.getSelection()){
changeStoryMode();
}
}
});
lblProj = new Label(comp,SWT.NONE);
lblProj.setText("Project:");
gridData = new GridData();
gridData.horizontalIndent = 25;
lblProj.setLayoutData(gridData);
txtProject = new Text(comp, SWT.SINGLE | SWT.BORDER);
txtProject.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
txtProject.addModifyListener(tabListener);
btnProject = new Button(comp,SWT.PUSH);
btnProject.setText("Browse");
btnProject.addSelectionListener(projectSelectionListener);
setButtonGridData(btnProject);
lblStory = new Label(comp,SWT.NONE);
lblStory.setText("Story:");
gridData = new GridData();
gridData.horizontalIndent = 25;
lblStory.setLayoutData(gridData);
txtStory = new Text(comp, SWT.SINGLE | SWT.BORDER);
txtStory.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
txtStory.addModifyListener(tabListener);
btnStory = new Button(comp,SWT.PUSH);
btnStory.setText("Browse");
setButtonGridData(btnStory);
btnStory.addSelectionListener(storySelectionAdapter);
}
private void createMultiStoryControls(Composite comp){
btnRadioMultiStory = new Button(comp,SWT.RADIO);
btnRadioMultiStory.setText("Run stories from project,package or source folder");
GridData gridData = new GridData();
gridData.horizontalSpan = 3;
btnRadioMultiStory.setLayoutData(gridData);
btnRadioMultiStory.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
if (btnRadioMultiStory.getSelection()){
changeStoryMode();
}
}
});
txtMultiStories = new Text(comp, SWT.SINGLE | SWT.BORDER | SWT.READ_ONLY);
txtMultiStories.addModifyListener(tabListener);
gridData = new GridData(GridData.FILL_HORIZONTAL);
gridData.horizontalIndent= 25;
gridData.horizontalSpan = 2;
txtMultiStories.setLayoutData(gridData);
btnMultiStory = new Button(comp,SWT.PUSH);
btnMultiStory.setText("Browse");
btnMultiStory.addSelectionListener(resourceSelectionAdapter);
setButtonGridData(btnMultiStory);
}
private void setButtonGridData(Button button){
GridData gridData= new GridData();
button.setLayoutData(gridData);
WidgetUtil.setButtonDimensionHint(button);
}
private void changeStoryMode(){
boolean singleStory = btnRadioSingleStory.getSelection();
setEnableProject(singleStory);
setEnableSingleStory(singleStory);
setEnableMultiStory(!singleStory);
updateLaunchConfigurationDialog();
}
private void setEnableProject(boolean enabled){
lblProj.setEnabled(enabled);
txtProject.setEnabled(enabled);
btnProject.setEnabled(enabled);
}
private void setEnableSingleStory(boolean enabled){
if(StringUtils.isBlank(txtProject.getText())){
enabled = false;
}
lblStory.setEnabled(enabled);
txtStory.setEnabled(enabled);
btnStory.setEnabled(enabled);
}
private void setEnableMultiStory(boolean enabled){
txtMultiStories.setEnabled(enabled);
btnMultiStory.setEnabled(enabled);
}
private void updateElement(IJavaElement newElement){
if(newElement==null){
return;
}
container = newElement;
txtMultiStories.setText(elementLabelProvider.getText(container));
updateLaunchConfigurationDialog();
}
private void updateStory(IFile file){
if(file==null){
return;
}
storyFile = file;
txtStory.setText(storyFile.getName());
}
private IWorkspaceRoot getWorkspaceRoot(){
return ResourcesPlugin.getWorkspace().getRoot();
}
private IJavaProject chooseJavaProject() {
IJavaProject[] projects;
try {
projects= JavaCore.create(getWorkspaceRoot()).getJavaProjects();
} catch (JavaModelException e) {
EasybLaunchActivator.getDefault().getLog().log(e.getStatus());
projects= new IJavaProject[0];
}
ILabelProvider labelProvider= new JavaElementLabelProvider(JavaElementLabelProvider.SHOW_DEFAULT);
ElementListSelectionDialog dialog= new ElementListSelectionDialog(getShell(), labelProvider);
dialog.setTitle("Projects");
dialog.setMessage("Please choose a project");
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;
}
private IJavaProject getJavaProject(){
String projTxt = StringUtils.trimToEmpty(txtProject.getText());
if(StringUtils.isBlank(projTxt)){
return null;
}
IJavaModel model = JavaCore.create(getWorkspaceRoot());
return model.getJavaProject(projTxt);
}
private IJavaElement chooseContainer(IJavaElement initElement) {
StandardJavaElementContentProvider provider= new StandardJavaElementContentProvider();
ILabelProvider labelProvider= new JavaElementLabelProvider(JavaElementLabelProvider.SHOW_DEFAULT);
ElementTreeSelectionDialog dialog= new ElementTreeSelectionDialog(getShell(), labelProvider, provider);
dialog.setTitle("Elements");
dialog.setMessage("Choose a project,package or folder");
dialog.addFilter(new ContainerViewerFilter());
dialog.setInput(JavaCore.create(getWorkspaceRoot()));
dialog.setInitialSelection(initElement);
dialog.setAllowMultiple(false);
if (dialog.open() == Window.OK) {
Object element= dialog.getFirstResult();
return (IJavaElement)element;
}
return null;
}
private IFile chooseStory(){
try
{
IJavaProject javaProject = getJavaProject();
IFile[] files = BehaviourSearch.findStoryFiles(javaProject.getResource());
BehaviourElementSelectorDialog dialog=
new BehaviourElementSelectorDialog(getShell(),files);
dialog.setTitle("Stories");
dialog.setMessage("Choose a story");
if (dialog.open() == Window.OK) {
Object element= dialog.getFirstResult();
return (IFile)element;
}
}catch(CoreException cex){
EasybLaunchActivator.Log("Unable to locate storys for story browse", cex);
setErrorMessage("Unable to locate storys for story browse");
}
return null;
}
}