blob: 29eb0de10d587c55a574e780dec8dd9ed04b1d9a [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2015 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
* Anton Leherbauer (Wind River) - [296800] UI build actions should not lock the workspace
*******************************************************************************/
package org.eclipse.ui.actions;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IncrementalProjectBuilder;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.SubMonitor;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.dialogs.ErrorDialog;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.IWorkbenchCommandConstants;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.internal.ide.IDEInternalWorkbenchImages;
import org.eclipse.ui.internal.ide.IDEWorkbenchMessages;
import org.eclipse.ui.internal.ide.IDEWorkbenchPlugin;
import org.eclipse.ui.internal.ide.IIDEHelpContextIds;
import org.eclipse.ui.internal.ide.actions.BuildUtilities;
import org.eclipse.ui.progress.IProgressConstants2;
import org.eclipse.ui.statushandlers.StatusManager;
/**
* Standard action for full and incremental builds of all projects within the
* workspace.
* <p>
* This class may be instantiated; it is not intended to be subclassed.
* </p>
* @noextend This class is not intended to be subclassed by clients.
*/
public class GlobalBuildAction extends Action implements
ActionFactory.IWorkbenchAction {
/**
* The type of build performed by this action. Can be either
* <code>IncrementalProjectBuilder.INCREMENTAL_BUILD</code> or
* <code>IncrementalProjectBuilder.FULL_BUILD</code>.
*/
private int buildType;
/**
* The workbench window; or <code>null</code> if this action has been
* <code>dispose</code>d.
*/
private IWorkbenchWindow workbenchWindow;
/**
* Creates a new action of the appropriate type. The action id is
* <code>IWorkbenchActionConstants.BUILD</code> for incremental builds and
* <code>IWorkbenchActionConstants.REBUILD_ALL</code> for full builds.
*
* @param workbench
* the active workbench
* @param shell
* the shell for any dialogs
* @param type
* the type of build; one of
* <code>IncrementalProjectBuilder.INCREMENTAL_BUILD</code> or
* <code>IncrementalProjectBuilder.FULL_BUILD</code>
*
* @deprecated use GlobalBuildAction(IWorkbenchWindow, type) instead
*/
@Deprecated
public GlobalBuildAction(IWorkbench workbench, Shell shell, int type) {
// always use active window; ignore shell
this(workbench.getActiveWorkbenchWindow(), type);
Assert.isNotNull(shell);
}
/**
* Creates a new action of the appropriate type. The action id is
* <code>IWorkbenchActionConstants.BUILD</code> for incremental builds and
* <code>IWorkbenchActionConstants.REBUILD_ALL</code> for full builds.
*
* @param window
* the window in which this action appears
* @param type
* the type of build; one of
* <code>IncrementalProjectBuilder.INCREMENTAL_BUILD</code> or
* <code>IncrementalProjectBuilder.FULL_BUILD</code>
*/
public GlobalBuildAction(IWorkbenchWindow window, int type) {
Assert.isNotNull(window);
this.workbenchWindow = window;
setBuildType(type);
}
/**
* Sets the build type.
*
* @param type
* the type of build; one of
* <code>IncrementalProjectBuilder.INCREMENTAL_BUILD</code> or
* <code>IncrementalProjectBuilder.FULL_BUILD</code>
*/
private void setBuildType(int type) {
// allow AUTO_BUILD as well for backwards compatibility, but treat it
// the same as INCREMENTAL_BUILD
switch (type) {
case IncrementalProjectBuilder.INCREMENTAL_BUILD:
case IncrementalProjectBuilder.AUTO_BUILD:
setText(IDEWorkbenchMessages.GlobalBuildAction_text);
setToolTipText(IDEWorkbenchMessages.GlobalBuildAction_toolTip);
setId("build"); //$NON-NLS-1$
workbenchWindow.getWorkbench().getHelpSystem().setHelp(this,
IIDEHelpContextIds.GLOBAL_INCREMENTAL_BUILD_ACTION);
setImageDescriptor(IDEInternalWorkbenchImages
.getImageDescriptor(IDEInternalWorkbenchImages.IMG_ETOOL_BUILD_EXEC));
setDisabledImageDescriptor(IDEInternalWorkbenchImages
.getImageDescriptor(IDEInternalWorkbenchImages.IMG_ETOOL_BUILD_EXEC_DISABLED));
setActionDefinitionId(IWorkbenchCommandConstants.PROJECT_BUILD_ALL);
break;
case IncrementalProjectBuilder.FULL_BUILD:
setText(IDEWorkbenchMessages.GlobalBuildAction_rebuildText);
setToolTipText(IDEWorkbenchMessages.GlobalBuildAction_rebuildToolTip);
setId("rebuildAll"); //$NON-NLS-1$
workbenchWindow.getWorkbench().getHelpSystem().setHelp(this,
IIDEHelpContextIds.GLOBAL_FULL_BUILD_ACTION);
setActionDefinitionId("org.eclipse.ui.project.rebuildAll"); //$NON-NLS-1$
break;
default:
throw new IllegalArgumentException("Invalid build type"); //$NON-NLS-1$
}
this.buildType = type;
}
/**
* Returns the shell to use.
*/
private Shell getShell() {
return workbenchWindow.getShell();
}
/**
* Returns the operation name to use
*/
private String getOperationMessage() {
if (buildType == IncrementalProjectBuilder.INCREMENTAL_BUILD) {
return IDEWorkbenchMessages.GlobalBuildAction_buildOperationTitle;
}
return IDEWorkbenchMessages.GlobalBuildAction_rebuildAllOperationTitle;
}
/**
* Builds all projects within the workspace. Does not save any open editors.
*/
public void doBuild() {
doBuildOperation();
}
/**
* Invokes a build on all projects within the workspace. Reports any errors
* with the build to the user.
*/
/* package */void doBuildOperation() {
Job buildJob = new Job(IDEWorkbenchMessages.GlobalBuildAction_jobTitle) {
@Override
protected IStatus run(IProgressMonitor monitor) {
SubMonitor subMonitor = SubMonitor.convert(monitor, getOperationMessage(), 100);
try {
ResourcesPlugin.getWorkspace().build(buildType, subMonitor.split(100));
} catch (CoreException e) {
return e.getStatus();
}
return Status.OK_STATUS;
}
@Override
public boolean belongsTo(Object family) {
return ResourcesPlugin.FAMILY_MANUAL_BUILD == family;
}
};
buildJob.setUser(true);
buildJob.setProperty(IProgressConstants2.SHOW_IN_TASKBAR_ICON_PROPERTY, Boolean.TRUE);
buildJob.schedule();
}
/**
* Returns an array of all projects in the workspace
*/
/* package */IProject[] getWorkspaceProjects() {
return ResourcesPlugin.getWorkspace().getRoot().getProjects();
}
@Override
public void run() {
if (workbenchWindow == null) {
// action has been disposed
return;
}
// Do nothing if there are no projects...
IProject[] roots = getWorkspaceProjects();
if (roots.length < 1) {
return;
}
// Verify that there are builders registered on at
// least one project
if (!verifyBuildersAvailable(roots)) {
return;
}
if (!verifyNoManualRunning()) {
return;
}
// Save all resources prior to doing build
BuildUtilities.saveEditors(null);
// Perform the build on all the projects
doBuildOperation();
}
/**
* Checks that there is at least one project with a builder registered on
* it.
*/
/* package */boolean verifyBuildersAvailable(IProject[] roots) {
try {
for (IProject root : roots) {
if (root.isAccessible()) {
if (root.getDescription().getBuildSpec().length > 0) {
return true;
}
}
}
} catch (CoreException e) {
StatusManager.getManager().handle(e, IDEWorkbenchPlugin.IDE_WORKBENCH);
ErrorDialog
.openError(
getShell(),
IDEWorkbenchMessages.GlobalBuildAction_buildProblems,
NLS.bind(IDEWorkbenchMessages.GlobalBuildAction_internalError, e.getMessage()),
e.getStatus());
return false;
}
return false;
}
@Override
public void dispose() {
if (workbenchWindow == null) {
// action has already been disposed
return;
}
workbenchWindow = null;
}
/**
* Verify that no manual build is running. If it is then give the use the
* option to cancel. If they cancel, cancel the jobs and return true,
* otherwise return false.
*
* @return whether or not there is a manual build job running.
*/
private boolean verifyNoManualRunning() {
Job[] buildJobs = Job.getJobManager().find(
ResourcesPlugin.FAMILY_MANUAL_BUILD);
if (buildJobs.length == 0) {
return true;
}
boolean cancel = MessageDialog.openQuestion(getShell(),
IDEWorkbenchMessages.GlobalBuildAction_BuildRunningTitle,
IDEWorkbenchMessages.GlobalBuildAction_BuildRunningMessage);
if (cancel) {
for (Job job : buildJobs) {
job.cancel();
}
}
//If they cancelled get them to do it again.
return false;
}
}