/*******************************************************************************
* Copyright (c) 2000, 2010 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
* Alex Collins (Broadcom Corp.)
*******************************************************************************/
package org.eclipse.cdt.internal.ui.cview;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import org.eclipse.core.resources.ICommand;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IncrementalProjectBuilder;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jface.action.GroupMarker;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.window.IShellProvider;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.ui.IActionBars;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchPartSite;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.actions.BuildAction;
import org.eclipse.ui.ide.IDEActionFactory;
import org.eclipse.ui.ide.ResourceUtil;
import org.eclipse.cdt.ui.CUIPlugin;
/**
* This is the action group for workspace actions such as Build
*/
public class BuildGroup extends CViewActionGroup {
/**
* An internal class which overrides the 'shouldPerformResourcePruning'
* method so that referenced projects aren't build twice . (The CDT
* managedbuild builds CDT reference project configuration as part of
* building the top-level project).
*
* Also ensure that files in referenced projects are saved automatically
* before build.
*/
public static class CDTBuildAction extends BuildAction {
public CDTBuildAction(IShellProvider shell, int kind) {
super(shell, kind);
}
@Override
@SuppressWarnings("unchecked")
public void run() {
// Ensure we correctly save files in all referenced projects before build
Set<IProject> prjs = new HashSet<IProject>();
for (IResource resource : (List<IResource>)getSelectedResources()) {
IProject project = resource.getProject();
if (project != null) {
prjs.add(project);
try {
prjs.addAll(Arrays.asList(project.getReferencedProjects()));
} catch (CoreException e) {
// Project not accessible or not open
}
}
}
saveEditors(prjs);
// Clear the build console, and open a stream
CUIPlugin.getDefault().startGlobalConsole();
// Now delegate to the parent
super.run();
}
/**
* Taken from inaccessible o.e.ui.ide.BuildUtilities.java
*
* Causes all editors to save any modified resources in the provided collection
* of projects depending on the user's preference.
* @param projects The projects in which to save editors, or <code>null</code>
* to save editors in all projects.
*/
private static void saveEditors(Collection<IProject> projects) {
if (!BuildAction.isSaveAllSet()) {
return;
}
IWorkbenchWindow[] windows = PlatformUI.getWorkbench().getWorkbenchWindows();
for (IWorkbenchWindow window : windows) {
IWorkbenchPage[] pages = window.getPages();
for (IWorkbenchPage page : pages) {
if (projects == null) {
page.saveAllEditors(false);
} else {
IEditorPart[] editors = page.getDirtyEditors();
for (IEditorPart editor : editors) {
IFile inputFile = ResourceUtil.getFile(editor.getEditorInput());
if (inputFile != null) {
if (projects.contains(inputFile.getProject())) {
page.saveEditor(editor, false);
}
}
}
}
}
}
}
}
private static class RebuildAction extends CDTBuildAction {
public RebuildAction(IShellProvider shell) {
super(shell, IncrementalProjectBuilder.FULL_BUILD);
}
@Override
protected void invokeOperation(IResource resource, IProgressMonitor monitor)
throws CoreException {
// these are both async. NOT what I want.
((IProject) resource).build(IncrementalProjectBuilder.CLEAN_BUILD, monitor);
((IProject) resource).build(IncrementalProjectBuilder.FULL_BUILD, monitor);
}
}
private BuildAction buildAction;
private BuildAction rebuildAction;
private BuildAction cleanAction;
// Menu tags for the build
final String BUILD_GROUP_MARKER = "buildGroup"; //$NON-NLS-1$
final String BUILD_GROUP_MARKER_END = "end-buildGroup"; //$NON-NLS-1$
public BuildGroup(CView cview) {
super(cview);
}
@Override
public void fillActionBars(IActionBars actionBars) {
actionBars.setGlobalActionHandler(IDEActionFactory.BUILD_PROJECT.getId(), buildAction);
}
/**
* Adds the build actions to the context menu.
* <p>
* The following conditions apply: build-only projects selected, auto build
* disabled, at least one * builder present
* </p>
* <p>
* No disabled action should be on the context menu.
* </p>
*
* @param menu
* context menu to add actions to
*/
@Override
public void fillContextMenu(IMenuManager menu) {
IStructuredSelection selection = (IStructuredSelection) getContext().getSelection();
boolean isProjectSelection = true;
boolean hasOpenProjects = false;
boolean hasClosedProjects = false;
boolean hasBuilder = true; // false if any project is closed or does
// not have builder
menu.add(new GroupMarker(BUILD_GROUP_MARKER));
Iterator<?> resources = selection.iterator();
while (resources.hasNext() && (!hasOpenProjects || !hasClosedProjects || hasBuilder || isProjectSelection)) {
Object next = resources.next();
IProject project = null;
if (next instanceof IProject) {
project = (IProject) next;
} else if (next instanceof IAdaptable) {
IResource res = (IResource)((IAdaptable)next).getAdapter(IResource.class);
if (res instanceof IProject) {
project = (IProject) res;
}
}
if (project == null) {
isProjectSelection = false;
continue;
}
if (project.isOpen()) {
hasOpenProjects = true;
if (hasBuilder && !hasBuilder(project)) {
hasBuilder = false;
}
} else {
hasClosedProjects = true;
hasBuilder = false;
}
}
if (!selection.isEmpty() && isProjectSelection && hasBuilder) {
buildAction.selectionChanged(selection);
menu.add(buildAction);
// rebuildAction.selectionChanged(selection);
// menu.add(rebuildAction);
cleanAction.selectionChanged(selection);
menu.add(cleanAction);
}
menu.add(new GroupMarker(BUILD_GROUP_MARKER_END));
}
/**
* Handles a key pressed event by invoking the appropriate action.
*/
@Override
public void handleKeyPressed(KeyEvent event) {
}
/**
* Returns whether there are builders configured on the given project.
*
* @return <code>true</code> if it has builders, <code>false</code> if
* not, or if this could not be determined
*/
boolean hasBuilder(IProject project) {
try {
ICommand[] commands = project.getDescription().getBuildSpec();
if (commands.length > 0) return true;
} catch (CoreException e) {
// Cannot determine if project has builders. Project is closed
// or does not exist. Fall through to return false.
}
return false;
}
@Override
protected void makeActions() {
final IWorkbenchPartSite site = getCView().getSite();
buildAction = new CDTBuildAction(site, IncrementalProjectBuilder.INCREMENTAL_BUILD);
buildAction.setText(CViewMessages.BuildAction_label);
cleanAction = new CDTBuildAction(site, IncrementalProjectBuilder.CLEAN_BUILD);
cleanAction.setText(CViewMessages.CleanAction_label);
rebuildAction = new RebuildAction(site);
rebuildAction.setText(CViewMessages.RebuildAction_label);
}
@Override
public void updateActionBars() {
IStructuredSelection selection = (IStructuredSelection) getContext().getSelection();
buildAction.selectionChanged(selection);
}
}