/*******************************************************************************
* Copyright (c) 2012 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.actions;
import java.util.ArrayList;
import java.util.LinkedHashSet;
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.core.runtime.IAdaptable;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.ui.IObjectActionDelegate;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.IWorkingSet;
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.util.ExceptionUtil;
import org.springsource.ide.eclipse.gradle.core.util.GradleRunnable;
import org.springsource.ide.eclipse.gradle.ui.GradleUI;
/**
* Abstract superclass for actions that require one or more projects to be selected.
*
* @author Kris De Volder
*/
public abstract class GradleProjectActionDelegate implements IObjectActionDelegate {
//TODO: all subclasses to support applying action to multiple projects.
/**
* This is private for a good reason: to force subclasses from getting it into a local
* varaible. The typical use pattern in subclasses is to create jobs and schedule these jobs.
* Since this field is mutable, it would be a bad idea for a job to refer to it. By the time
* the job executes, the list of projects may have changed!
*/
private LinkedHashSet<IProject> projects = new LinkedHashSet<IProject>();
public void selectionChanged(IAction action, ISelection _selection) {
if (_selection instanceof IStructuredSelection) {
projects = new LinkedHashSet<IProject>(); //Mustn't reuse
IStructuredSelection selection = (IStructuredSelection) _selection;
if (!selection.isEmpty()) {
for (Object element : selection.toArray()) {
if (element instanceof IProject) {
projects.add((IProject) element);
} else if (element instanceof IResource) {
projects.add(((IResource) element).getProject());
} else if (element instanceof IAdaptable) {
IAdaptable adaptable = (IAdaptable) element;
IProject project = (IProject) adaptable.getAdapter( IProject.class );
if(project == null) {
IResource resource = (IResource) adaptable.getAdapter( IResource.class );
if (resource != null ) {
project = resource.getProject();
}
}
if (project != null ) {
projects.add(project);
}
} else if (element instanceof IWorkingSet) {
IWorkingSet workingSet = (IWorkingSet) element;
for (IAdaptable adaptable : workingSet.getElements()) {
IProject project = (IProject) adaptable.getAdapter(IProject.class);
if (project != null) {
projects.add(project);
continue;
}
// In case a working set has something other than a project
IResource resource = (IResource) adaptable.getAdapter(IResource.class);
if (resource != null && resource.getProject() != null) {
projects.add(resource.getProject());
continue;
}
}
}
}
}
}
action.setEnabled(isEnabled());
}
protected final boolean isEnabled() {
try {
for (IProject project : getProjects()) {
if (!isEnabled(project)) {
return false;
}
}
return !projects.isEmpty();
} catch (CoreException e) {
GradleUI.log(e);
return false;
}
}
/**
* Test whether action can be enabled for a single project. If multiple projects are selected, this method
* is used to determine enablement for each project. The action will be enabled if all selected projects
* meet the condition.
*/
protected boolean isEnabled(IProject project) throws CoreException {
return project!=null && project.isAccessible() && project.hasNature(GradleNature.NATURE_ID);
}
protected List<IProject> getProjects() {
// Make copy, don't share state! This is used by jobs that may be run concurrently and/or much later on!
return new ArrayList<IProject>(projects);
}
public void setActivePart(IAction action, IWorkbenchPart targetPart) {
}
/**
* For implementations of operations that really don't expect more than one project this method conveniently
* returns the first selected project. If the enablement condition on the menu are set correctly, this should
* in fact be the only project.
*/
protected IProject getProject() {
if (!projects.isEmpty()) {
for (IProject p : projects) {
return p;
}
}
return null;
}
/**
* For implementations of operations that really don't expect more than one project this method conveniently
* returns the first selected project. If the enablement condition on the menu are set correctly, this should
* in fact be the only project.
*/
protected IJavaProject getJavaProject() {
IProject project = getProject();
if (project!=null) {
return JavaCore.create(project);
}
return null;
}
/**
* For implementations of operations that really don't expect more than one project this method conveniently
* returns the first selected project. If the enablement condition on the menu are set correctly, this should
* in fact be the only project.
*/
protected GradleProject getGradleProject() {
IProject project = getProject();
if (project!=null) {
return GradleCore.create(project);
}
return null;
}
/**
* TODO: get rid of this method and replace its uses with a 'user' job.
*/
protected void runInUi(GradleRunnable runnable) {
IWorkbenchWindow context = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
try {
PlatformUI.getWorkbench().getProgressService().runInUI(context, runnable, ResourcesPlugin.getWorkspace().getRuleFactory().buildRule());
} catch (Exception e) {
GradleUI.log(e);
String msg = ExceptionUtil.getMessage(e);
if (msg!=null) {
MessageDialog.openError(null, runnable.toString()+" Failed", msg);
}
}
}
}