/*******************************************************************************
* Copyright (c) 2012, 2015 Pivotal Software, Inc.
* 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:
* Pivotal Software, Inc. - initial API and implementation
*******************************************************************************/
package org.springsource.ide.eclipse.gradle.ui.launch;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.debug.core.ILaunchConfiguration;
import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
import org.eclipse.debug.ui.AbstractLaunchConfigurationTab;
import org.eclipse.jface.layout.GridDataFactory;
import org.eclipse.jface.text.Document;
import org.eclipse.jface.text.DocumentEvent;
import org.eclipse.jface.text.IDocumentListener;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.StyleRange;
import org.eclipse.swt.custom.StyledText;
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.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PlatformUI;
import org.springsource.ide.eclipse.gradle.core.GradleCore;
import org.springsource.ide.eclipse.gradle.core.GradleNature;
import org.springsource.ide.eclipse.gradle.core.GradleProject;
import org.springsource.ide.eclipse.gradle.core.classpathcontainer.FastOperationFailedException;
import org.springsource.ide.eclipse.gradle.core.launch.GradleLaunchConfigurationDelegate;
import org.springsource.ide.eclipse.gradle.core.util.GradleProjectIndex;
import org.springsource.ide.eclipse.gradle.ui.cli.editor.TasksViewer;
/**
* @author Kris De Volder
* @author Alex Boyko
*/
public class GradleLaunchTasksTab extends AbstractLaunchConfigurationTab {
private static final boolean DEBUG = false;
private static final String CTRL_SPACE_LABEL = "<Ctrl> + <Space>";
private static final String EDITOR_INFO_LABEL = "Type tasks in the editor below. Use " + CTRL_SPACE_LABEL + " to activate content assistant.";
private Combo projectCombo;
private GradleProject project;
private GradleProjectIndex tasksIndex= new GradleProjectIndex();
private TasksViewer tasksViewer;
private Button refreshButton;
public void createControl(Composite parent) {
Composite page = new Composite(parent, SWT.NONE);
GridLayout layout = new GridLayout(1, false);
page.setLayout(layout);
createProjectCombo(page);
createTaskEditor(page);
setControl(page);
}
private void createProjectCombo(Composite _parent) {
GridDataFactory grabHor = GridDataFactory.fillDefaults().grab(true, false);
Composite parent = new Composite(_parent, SWT.NONE);
parent.setLayout(new GridLayout(3,false));
grabHor.applyTo(parent);
Label label = new Label(parent, SWT.NONE);
label.setText("Project");
projectCombo = new Combo(parent, SWT.DROP_DOWN|SWT.READ_ONLY);
List<GradleProject> projects = getGradleProjects();
String[] items = new String[projects.size()];
int i = 0;
for (GradleProject p : projects) {
items[i++] = p.getName();
}
projectCombo.setItems(items);
if (project!=null) {
projectCombo.setText(project.getName());
}
projectCombo.addModifyListener(new ModifyListener() {
public void modifyText(ModifyEvent e) {
String newProjectName = projectCombo.getText();
if ("".equals(newProjectName)) {
setProject(null);
setTasksDocument("");
} else {
IProject newProject = ResourcesPlugin.getWorkspace().getRoot().getProject(newProjectName);
setProject(GradleCore.create(newProject));
setTasksDocument(tasksViewer.getSourceViewer().getDocument().get());
}
}
});
refreshButton = new Button(parent, SWT.PUSH);
refreshButton.setText("Refresh");
refreshButton.setToolTipText("Rebuild the gradle model and refresh the task list");
refreshButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent evt) {
GradleProject currentProject = project;
if (currentProject != null) {
try {
project.requestGradleModelRefresh();
} catch (CoreException e) {
// ignore
}
tasksIndex.setProject(project);
}
}
});
grabHor.align(SWT.RIGHT, SWT.CENTER).applyTo(refreshButton);
}
private List<GradleProject> getGradleProjects() {
IProject[] projects = ResourcesPlugin.getWorkspace().getRoot().getProjects();
ArrayList<GradleProject> result = new ArrayList<GradleProject>();
for (IProject p : projects) {
try {
if (p.isAccessible() && p.hasNature(GradleNature.NATURE_ID)) {
result.add(GradleCore.create(p));
}
} catch (CoreException e) {
GradleCore.log(e);
}
}
return result;
}
private void createTaskEditor(final Composite parent) {
StyledText styledText = new StyledText(parent, SWT.READ_ONLY | SWT.WRAP);
styledText.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
styledText.setBackground(parent.getBackground());
styledText.setText(EDITOR_INFO_LABEL);
styledText.setStyleRange(new StyleRange(EDITOR_INFO_LABEL
.indexOf(CTRL_SPACE_LABEL), CTRL_SPACE_LABEL.length(),
styledText.getForeground(), styledText.getBackground(),
SWT.BOLD | SWT.ITALIC));
tasksViewer = new TasksViewer(parent, tasksIndex, false);
tasksViewer.setActivateContentAssistOnEmptyDocument(true);
tasksViewer.getSourceViewer().getControl().setLayoutData(new GridData(GridData.FILL_BOTH));
setTasksDocument("");
}
public void setDefaults(ILaunchConfigurationWorkingCopy configuration) {
setProject(getContext());
if (tasksViewer != null) {
setTasksDocument("");
}
}
private void setProject(GradleProject project) {
//TODO: when restoring from persistent conf, can get non-existent projects...
// how to handle that case?
if (this.project==project) //Don't do anything if project is unchanged
return;
this.project = project;
tasksIndex.setProject(project);
if (projectCombo!=null) {
if (project!=null) {
projectCombo.setText(project.getName());
} else {
projectCombo.deselectAll();
}
}
updateLaunchConfigurationDialog();
}
private GradleProject getContext() {
IWorkbench wb = PlatformUI.getWorkbench();
IWorkbenchWindow win = wb.getActiveWorkbenchWindow();
IWorkbenchPage page = win==null ? null : win.getActivePage();
if (page != null) {
ISelection selection = page.getSelection();
if (selection instanceof IStructuredSelection) {
IStructuredSelection ss = (IStructuredSelection)selection;
if (!ss.isEmpty()) {
Object obj = ss.getFirstElement();
if (obj instanceof IResource) {
IResource rsrc = (IResource) obj;
IProject prj = rsrc.getProject();
if (prj!=null) {
return GradleCore.create(prj);
}
}
}
}
IEditorPart part = page.getActiveEditor();
if (part != null) {
IEditorInput input = part.getEditorInput();
IResource rsrc = (IResource) input.getAdapter(IResource.class);
if (rsrc!=null) {
IProject prj = rsrc.getProject();
if (prj!=null) {
return GradleCore.create(prj);
}
}
}
}
return null;
}
public void initializeFrom(ILaunchConfiguration conf) {
debug(">>> initializing Gradle launch tab");
try {
for (Object attName : conf.getAttributes().keySet()) {
debug(""+attName);
}
} catch (CoreException e) {
GradleCore.log(e);
}
debug("<<< initializing Gradle launch tab");
setProject(GradleLaunchConfigurationDelegate.getProject(conf));
setTasksDocument(GradleLaunchConfigurationDelegate.getTasks(conf));
}
private void setTasksDocument(String tasks) {
Document document = new Document(tasks);
document.addDocumentListener(new IDocumentListener() {
@Override
public void documentChanged(DocumentEvent event) {
GradleLaunchTasksTab.this.updateLaunchConfigurationDialog();
}
@Override
public void documentAboutToBeChanged(DocumentEvent event) {
// empty
}
});
tasksViewer.setDocument(document);
}
@Override
public void updateLaunchConfigurationDialog() {
super.updateLaunchConfigurationDialog();
}
private static void debug(String string) {
if (DEBUG) {
System.out.println(string);
}
}
@Override
public boolean canSave() {
//Don't allow saving until the model is properly initialized. If it isn't, the checkboxes in the tree
//don't have well defined state.
return haveGradleModel();
}
public boolean isValid() {
return canSave();
}
public void performApply(ILaunchConfigurationWorkingCopy conf) {
GradleLaunchConfigurationDelegate.setProject(conf, project);
GradleLaunchConfigurationDelegate.setTasks(conf, tasksViewer.getSourceViewer().getDocument().get());
}
private boolean haveGradleModel() {
try {
return project != null && project.getGradleModel()!=null;
} catch (FastOperationFailedException e) {
} catch (CoreException e) {
GradleCore.log(e);
}
return false;
}
public String getName() {
return "Gradle Tasks";
}
@Override
public void dispose() {
if (tasksViewer != null) {
tasksViewer.dispose();
}
super.dispose();
}
}