001: /*******************************************************************************
002: * Copyright (c) 2000, 2006 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: *******************************************************************************/package org.eclipse.ui.actions;
011:
012: import java.util.ArrayList;
013: import java.util.Arrays;
014: import java.util.HashSet;
015: import java.util.Iterator;
016: import java.util.List;
017:
018: import org.eclipse.core.resources.ICommand;
019: import org.eclipse.core.resources.IProject;
020: import org.eclipse.core.resources.IResource;
021: import org.eclipse.core.resources.IWorkspace;
022: import org.eclipse.core.resources.IWorkspaceRoot;
023: import org.eclipse.core.resources.IncrementalProjectBuilder;
024: import org.eclipse.core.resources.ResourcesPlugin;
025: import org.eclipse.core.runtime.CoreException;
026: import org.eclipse.core.runtime.IProgressMonitor;
027: import org.eclipse.jface.preference.IPreferenceStore;
028: import org.eclipse.jface.viewers.IStructuredSelection;
029: import org.eclipse.jface.viewers.StructuredSelection;
030: import org.eclipse.swt.widgets.Shell;
031: import org.eclipse.ui.IWorkbenchWindow;
032: import org.eclipse.ui.PlatformUI;
033: import org.eclipse.ui.internal.ide.IDEInternalPreferences;
034: import org.eclipse.ui.internal.ide.IDEWorkbenchMessages;
035: import org.eclipse.ui.internal.ide.IDEWorkbenchPlugin;
036: import org.eclipse.ui.internal.ide.IIDEHelpContextIds;
037: import org.eclipse.ui.internal.ide.actions.BuildUtilities;
038:
039: /**
040: * Standard actions for full and incremental builds of the selected project(s).
041: * <p>
042: * This class may be instantiated; it is not intended to be subclassed.
043: * </p>
044: */
045: public class BuildAction extends WorkspaceAction {
046:
047: /**
048: * The id of an incremental build action.
049: */
050: public static final String ID_BUILD = PlatformUI.PLUGIN_ID
051: + ".BuildAction";//$NON-NLS-1$
052:
053: /**
054: * The id of a rebuild all action.
055: */
056: public static final String ID_REBUILD_ALL = PlatformUI.PLUGIN_ID
057: + ".RebuildAllAction";//$NON-NLS-1$
058:
059: private int buildType;
060:
061: /**
062: * The list of IProjects to build (computed lazily).
063: */
064: private List projectsToBuild = null;
065:
066: /**
067: * Creates a new action of the appropriate type. The action id is
068: * <code>ID_BUILD</code> for incremental builds and <code>ID_REBUILD_ALL</code>
069: * for full builds.
070: *
071: * @param shell the shell for any dialogs
072: * @param type the type of build; one of
073: * <code>IncrementalProjectBuilder.INCREMENTAL_BUILD</code> or
074: * <code>IncrementalProjectBuilder.FULL_BUILD</code>
075: */
076: public BuildAction(Shell shell, int type) {
077: super (shell, "");//$NON-NLS-1$
078:
079: if (type == IncrementalProjectBuilder.INCREMENTAL_BUILD) {
080: setText(IDEWorkbenchMessages.BuildAction_text);
081: setToolTipText(IDEWorkbenchMessages.BuildAction_toolTip);
082: setId(ID_BUILD);
083: PlatformUI.getWorkbench().getHelpSystem().setHelp(this ,
084: IIDEHelpContextIds.INCREMENTAL_BUILD_ACTION);
085: } else {
086: setText(IDEWorkbenchMessages.RebuildAction_text);
087: setToolTipText(IDEWorkbenchMessages.RebuildAction_tooltip);
088: setId(ID_REBUILD_ALL);
089: PlatformUI.getWorkbench().getHelpSystem().setHelp(this ,
090: IIDEHelpContextIds.FULL_BUILD_ACTION);
091: }
092:
093: this .buildType = type;
094: }
095:
096: /**
097: * Adds the given project and all of its prerequisities, transitively,
098: * to the provided set.
099: */
100: private void addAllProjects(IProject project, HashSet projects) {
101: if (project == null || !project.isAccessible()
102: || projects.contains(project)) {
103: return;
104: }
105: projects.add(project);
106: try {
107: IProject[] preReqs = project.getReferencedProjects();
108: for (int i = 0; i < preReqs.length; i++) {
109: addAllProjects(preReqs[i], projects);
110: }
111: } catch (CoreException e) {
112: //ignore inaccessible projects
113: }
114: }
115:
116: /* (non-Javadoc)
117: * Method declared on WorkspaceAction.
118: */
119: protected List getActionResources() {
120: return getProjectsToBuild();
121: }
122:
123: /* (non-Javadoc)
124: * Method declared on WorkspaceAction.
125: */
126: protected String getOperationMessage() {
127: return IDEWorkbenchMessages.BuildAction_operationMessage;
128: }
129:
130: /* (non-Javadoc)
131: * Method declared on WorkspaceAction.
132: */
133: protected String getProblemsMessage() {
134: return IDEWorkbenchMessages.BuildAction_problemMessage;
135: }
136:
137: /* (non-Javadoc)
138: * Method declared on WorkspaceAction.
139: */
140: protected String getProblemsTitle() {
141: return IDEWorkbenchMessages.BuildAction_problemTitle;
142: }
143:
144: /**
145: * Returns the projects to build.
146: * This contains the set of projects which have builders, across all selected resources.
147: */
148: List getProjectsToBuild() {
149: if (projectsToBuild == null) {
150: projectsToBuild = new ArrayList(3);
151: for (Iterator i = getSelectedResources().iterator(); i
152: .hasNext();) {
153: IResource resource = (IResource) i.next();
154: IProject project = resource.getProject();
155: if (project != null) {
156: if (!projectsToBuild.contains(project)) {
157: if (hasBuilder(project)) {
158: projectsToBuild.add(project);
159: }
160: }
161: }
162: }
163: }
164: return projectsToBuild;
165: }
166:
167: /**
168: * Returns whether there are builders configured on the given project.
169: *
170: * @return <code>true</code> if it has builders,
171: * <code>false</code> if not, or if this couldn't be determined
172: */
173: boolean hasBuilder(IProject project) {
174: if (!project.isAccessible())
175: return false;
176: try {
177: ICommand[] commands = project.getDescription()
178: .getBuildSpec();
179: if (commands.length > 0) {
180: return true;
181: }
182: } catch (CoreException e) {
183: // this method is called when selection changes, so
184: // just fall through if it fails.
185: // this shouldn't happen anyway, since the list of selected resources
186: // has already been checked for accessibility before this is called
187: }
188: return false;
189: }
190:
191: /* (non-Javadoc)
192: * Method declared on WorkspaceAction.
193: */
194: protected void invokeOperation(IResource resource,
195: IProgressMonitor monitor) throws CoreException {
196: ((IProject) resource).build(buildType, monitor);
197: }
198:
199: /* (non-Javadoc)
200: * Method declared on Action
201: */
202: public boolean isEnabled() {
203: //update enablement based on active window and part
204: IWorkbenchWindow window = PlatformUI.getWorkbench()
205: .getActiveWorkbenchWindow();
206: if (window != null) {
207: selectionChanged(new StructuredSelection(BuildUtilities
208: .findSelectedProjects(window)));
209: }
210: return super .isEnabled();
211: }
212:
213: /**
214: * Returns whether the user's preference is set to automatically save modified
215: * resources before a manual build is done.
216: *
217: * @return <code>true</code> if Save All Before Build is enabled
218: */
219: public static boolean isSaveAllSet() {
220: IPreferenceStore store = IDEWorkbenchPlugin.getDefault()
221: .getPreferenceStore();
222: return store
223: .getBoolean(IDEInternalPreferences.SAVE_ALL_BEFORE_BUILD);
224: }
225:
226: /* (non-Javadoc)
227: * Method declared on WorkspaceAction.
228: *
229: * Change the order of the resources so that
230: * it matches the build order. Closed and
231: * non existant projects are eliminated. Also,
232: * any projects in cycles are eliminated.
233: */
234: List pruneResources(List resourceCollection) {
235: //recursively compute project prerequisites
236: HashSet toBuild = new HashSet();
237: for (Iterator it = resourceCollection.iterator(); it.hasNext();) {
238: addAllProjects((IProject) it.next(), toBuild);
239: }
240:
241: // Optimize...
242: if (toBuild.size() < 2) {
243: return resourceCollection;
244: }
245:
246: // Try the workspace's description build order if specified
247: String[] orderedNames = ResourcesPlugin.getWorkspace()
248: .getDescription().getBuildOrder();
249: if (orderedNames != null) {
250: List orderedProjects = new ArrayList(toBuild.size());
251: IWorkspaceRoot root = ResourcesPlugin.getWorkspace()
252: .getRoot();
253: for (int i = 0; i < orderedNames.length; i++) {
254: IProject handle = root.getProject(orderedNames[i]);
255: if (toBuild.contains(handle)) {
256: orderedProjects.add(handle);
257: toBuild.remove(handle);
258: }
259: }
260: //Add anything not specified before we return
261: orderedProjects.addAll(toBuild);
262: return orderedProjects;
263: }
264:
265: // Try the project prerequisite order then
266: IProject[] projects = new IProject[toBuild.size()];
267: projects = (IProject[]) toBuild.toArray(projects);
268: IWorkspace.ProjectOrder po = ResourcesPlugin.getWorkspace()
269: .computeProjectOrder(projects);
270: ArrayList orderedProjects = new ArrayList();
271: orderedProjects.addAll(Arrays.asList(po.projects));
272: return orderedProjects;
273: }
274:
275: /* (non-Javadoc)
276: * Method declared on IAction; overrides method on WorkspaceAction.
277: * This override allows the user to save the contents of selected
278: * open editors so that the updated contents will be used for building.
279: */
280: public void run() {
281: List projects = getProjectsToBuild();
282: if (projects == null || projects.isEmpty()) {
283: return;
284: }
285:
286: // Save all resources prior to doing build
287: BuildUtilities.saveEditors(projects);
288: runInBackground(ResourcesPlugin.getWorkspace().getRuleFactory()
289: .buildRule(), ResourcesPlugin.FAMILY_MANUAL_BUILD);
290: }
291:
292: /* (non-Javadoc)
293: * Method declared on WorkspaceAction.
294: */
295: protected boolean shouldPerformResourcePruning() {
296: return true;
297: }
298:
299: /**
300: * The <code>BuildAction</code> implementation of this
301: * <code>SelectionListenerAction</code> method ensures that this action is
302: * enabled only if all of the selected resources have buildable projects.
303: */
304: protected boolean updateSelection(IStructuredSelection s) {
305: projectsToBuild = null;
306: IProject[] projects = (IProject[]) getProjectsToBuild()
307: .toArray(new IProject[0]);
308: return BuildUtilities.isEnabled(projects,
309: IncrementalProjectBuilder.INCREMENTAL_BUILD);
310: }
311: }
|