Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohn Cortell2010-05-25 20:26:14 +0000
committerJohn Cortell2010-05-25 20:26:14 +0000
commit72fbc7d39431752019d81548dff5f01015b341d2 (patch)
tree493042b9fb42ab354af0e63672fc403776af8a11 /launch/org.eclipse.cdt.launch/src
parentc58a08aaad2ad5eb69da91f1d6e14e26e75d513c (diff)
downloadorg.eclipse.cdt-72fbc7d39431752019d81548dff5f01015b341d2.tar.gz
org.eclipse.cdt-72fbc7d39431752019d81548dff5f01015b341d2.tar.xz
org.eclipse.cdt-72fbc7d39431752019d81548dff5f01015b341d2.zip
Bug 309126: Build before launch does too much building with project references
Diffstat (limited to 'launch/org.eclipse.cdt.launch/src')
-rw-r--r--launch/org.eclipse.cdt.launch/src/org/eclipse/cdt/launch/AbstractCLaunchDelegate2.java393
-rw-r--r--launch/org.eclipse.cdt.launch/src/org/eclipse/cdt/launch/internal/ui/BuildErrPrompter.java152
-rw-r--r--launch/org.eclipse.cdt.launch/src/org/eclipse/cdt/launch/internal/ui/LaunchMessages.properties5
3 files changed, 454 insertions, 96 deletions
diff --git a/launch/org.eclipse.cdt.launch/src/org/eclipse/cdt/launch/AbstractCLaunchDelegate2.java b/launch/org.eclipse.cdt.launch/src/org/eclipse/cdt/launch/AbstractCLaunchDelegate2.java
index ced7b2e3cfc..7c674773b13 100644
--- a/launch/org.eclipse.cdt.launch/src/org/eclipse/cdt/launch/AbstractCLaunchDelegate2.java
+++ b/launch/org.eclipse.cdt.launch/src/org/eclipse/cdt/launch/AbstractCLaunchDelegate2.java
@@ -11,30 +11,44 @@
package org.eclipse.cdt.launch;
import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import org.eclipse.cdt.core.CCorePlugin;
import org.eclipse.cdt.core.model.ICModelMarker;
import org.eclipse.cdt.core.model.ICProject;
import org.eclipse.cdt.core.settings.model.ICConfigurationDescription;
import org.eclipse.cdt.core.settings.model.ICProjectDescription;
import org.eclipse.cdt.debug.core.CDebugUtils;
import org.eclipse.cdt.debug.core.ICDTLaunchConfigurationConstants;
+import org.eclipse.cdt.launch.internal.ui.BuildErrPrompter;
import org.eclipse.cdt.launch.internal.ui.LaunchMessages;
-import org.eclipse.cdt.ui.newui.CDTPropertyManager;
+import org.eclipse.cdt.launch.internal.ui.LaunchUIPlugin;
+import org.eclipse.core.resources.ICommand;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.IWorkspaceRunnable;
import org.eclipse.core.resources.IncrementalProjectBuilder;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.MultiStatus;
+import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.core.runtime.Status;
-import org.eclipse.core.runtime.SubProgressMonitor;
+import org.eclipse.core.runtime.SubMonitor;
+import org.eclipse.debug.core.DebugPlugin;
import org.eclipse.debug.core.ILaunch;
import org.eclipse.debug.core.ILaunchConfiguration;
+import org.eclipse.debug.core.IStatusHandler;
import org.eclipse.debug.core.model.LaunchConfigurationDelegate;
+import org.eclipse.debug.internal.core.DebugCoreMessages;
+import org.eclipse.debug.internal.core.IInternalDebugCoreConstants;
/**
* AbstractCLaunchDelegate2 is used by most DSF based debuggers. It replaces AbstractCLaunchDelegate
@@ -53,8 +67,6 @@ public abstract class AbstractCLaunchDelegate2 extends LaunchConfigurationDelega
private boolean workspaceBuildBeforeLaunch;
private boolean requireCProject;
- private IProject project;
- private String preLaunchBuildConfiguration;
public AbstractCLaunchDelegate2() {
super();
@@ -89,10 +101,16 @@ public abstract class AbstractCLaunchDelegate2 extends LaunchConfigurationDelega
}
return referencedProjSet;
}
-
+
/**
- * Returns the order list of projects to build before launching.
- * Used in buildForLaunch()
+ * Even though we override the base behavior and only build the single
+ * project referenced in the launch configuration (and not any of the
+ * projects it references), we still want to implement this as the base will
+ * also use the list to determine what files need be saved, and there it's
+ * not much of a burden to include any referenced projects
+ *
+ * @see org.eclipse.debug.core.model.LaunchConfigurationDelegate#getBuildOrder(org.eclipse.debug.core.ILaunchConfiguration,
+ * java.lang.String)
*/
@Override
protected IProject[] getBuildOrder(ILaunchConfiguration configuration, String mode) throws CoreException {
@@ -133,12 +151,6 @@ public abstract class AbstractCLaunchDelegate2 extends LaunchConfigurationDelega
return orderedProjects;
}
- /* Used in finalLaunchCheck() */
- @Override
- protected IProject[] getProjectsForProblemSearch(ILaunchConfiguration configuration, String mode) throws CoreException {
- return getBuildOrder(configuration, mode);
- }
-
/**
* Searches for compile errors in the specified project
* Used in finalLaunchCheck()
@@ -190,8 +202,7 @@ public abstract class AbstractCLaunchDelegate2 extends LaunchConfigurationDelega
}
/**
- * Builds the current project and all of it's prerequisite projects if
- * necessary. Respects specified build order if any exists.
+ * Builds the project referenced in the launch configuration
*
* @param configuration
* the configuration being launched
@@ -206,59 +217,295 @@ public abstract class AbstractCLaunchDelegate2 extends LaunchConfigurationDelega
*/
@Override
public boolean buildForLaunch(ILaunchConfiguration configuration, String mode, IProgressMonitor monitor) throws CoreException {
+ try {
+ SubMonitor submon = SubMonitor.convert(monitor, "", 1); //$NON-NLS-1$
- workspaceBuildBeforeLaunch = true;
-
- // check the build before launch setting and honor it
- int buildBeforeLaunchValue = configuration.getAttribute(ICDTLaunchConfigurationConstants.ATTR_BUILD_BEFORE_LAUNCH,
- ICDTLaunchConfigurationConstants.BUILD_BEFORE_LAUNCH_USE_WORKSPACE_SETTING);
+ workspaceBuildBeforeLaunch = true;
- // we shouldn't be getting called if the workspace setting is disabled, so assume we need to
- // build unless the user explicitly disabled it in the main tab of the launch.
- if (buildBeforeLaunchValue == ICDTLaunchConfigurationConstants.BUILD_BEFORE_LAUNCH_DISABLED) {
+ IProject project = null;
+ ICProject cProject = CDebugUtils.getCProject(configuration);
+ if (cProject != null) {
+ project = cProject.getProject();
+ }
+
+ if (project == null) {
+ return false;
+ }
+
+ // check the build before launch setting and honor it
+ int buildBeforeLaunchValue = configuration.getAttribute(ICDTLaunchConfigurationConstants.ATTR_BUILD_BEFORE_LAUNCH,
+ ICDTLaunchConfigurationConstants.BUILD_BEFORE_LAUNCH_USE_WORKSPACE_SETTING);
+
+ // we shouldn't be getting called if the workspace setting is disabled, so assume we need to
+ // build unless the user explicitly disabled it in the main tab of the launch.
+ if (buildBeforeLaunchValue == ICDTLaunchConfigurationConstants.BUILD_BEFORE_LAUNCH_DISABLED) {
+ return false;
+ }
+
+ // The attribute value will be "" if 'Use Active' is selected
+ String buildConfigID = configuration.getAttribute(ICDTLaunchConfigurationConstants.ATTR_PROJECT_BUILD_CONFIG_ID, ""); //$NON-NLS-1$
+ if (buildConfigID.length() == 0) {
+ buildConfigID = null;
+ }
+
+ buildProject(project, buildConfigID, submon.newChild(1));
return false;
}
+ finally {
+ if (monitor != null) {
+ monitor.done();
+ }
+ }
+ }
- setBuildConfiguration(configuration, project);
+ /**
+ * This is an specialization of the platform method
+ * LaunchConfigurationDelegate#buildProjects(IProject[], IProgressMonitor).
+ * It builds only one project and it builds a particular CDT build
+ * configuration of it. It was added to address bug 309126 and 312709
+ *
+ * @param project
+ * the project to build
+ * @param buildConfigID
+ * the specific build configuration to build, or null to build
+ * the active one
+ * @param monitor
+ * progress monitor
+ * @throws CoreException
+ */
+ protected void buildProject(final IProject project, final String buildConfigID, IProgressMonitor monitor) throws CoreException {
- return super.buildForLaunch(configuration, mode, monitor);
+ // Some day, this will hopefully be a simple pass-thru to a cdt.core
+ // utility. See bug 313927
+
+ IWorkspaceRunnable build = new IWorkspaceRunnable(){
+ public void run(IProgressMonitor pm) throws CoreException {
+ final int TOTAL_TICKS = 1000;
+ SubMonitor localmonitor = SubMonitor.convert(pm, "", TOTAL_TICKS); //$NON-NLS-1$
+
+ try {
+ // Number of times we'll end up calling IProject.build()
+ final int buildCount = (buildConfigID == null) ? 1 : project.getDescription().getBuildSpec().length;
+ final int subtaskTicks = TOTAL_TICKS / buildCount;
+
+ if (buildConfigID != null) {
+ // Build a specific configuration
+
+ // To pass args, we have to specify the builder name.
+ // There can be multiple so this can require multiple
+ // builds. Note that this happens under the covers in
+ // the 'else' (args-less) case below
+ Map<String,String> cfgIdArgs = AbstractCLaunchDelegate2.cfgIdsToMap(new String[] {buildConfigID}, new HashMap<String,String>());
+ cfgIdArgs.put(CONTENTS, CONTENTS_CONFIGURATION_IDS);
+ ICommand[] commands = project.getDescription().getBuildSpec();
+ assert buildCount == commands.length;
+ for (ICommand command : commands) {
+ @SuppressWarnings("unchecked")
+ Map<String, String> args = command.getArguments();
+ if (args == null) {
+ args = new HashMap<String, String>(cfgIdArgs);
+ }
+ else {
+ args.putAll(cfgIdArgs);
+ }
+
+ if (localmonitor.isCanceled()) {
+ throw new OperationCanceledException();
+ }
+ project.build(IncrementalProjectBuilder.INCREMENTAL_BUILD, command.getBuilderName(), args, localmonitor.newChild(subtaskTicks));
+ }
+ }
+ else {
+ // Build the active configuration
+ project.build(IncrementalProjectBuilder.INCREMENTAL_BUILD, localmonitor.newChild(subtaskTicks));
+ }
+ } finally {
+ if (pm != null) {
+ pm.done();
+ }
+ }
+ }
+ };
+ ResourcesPlugin.getWorkspace().run(build, monitor);
}
- @Override
- public boolean preLaunchCheck(ILaunchConfiguration configuration, String mode, IProgressMonitor monitor) throws CoreException {
- ICProject cProject = CDebugUtils.getCProject(configuration);
- if (cProject != null) {
- project = cProject.getProject();
+ /** TODO: Temporarily duplicated from BuilderFactory. Remove when 313927 is addressed */
+ static final String CONFIGURATION_IDS = "org.eclipse.cdt.make.core.configurationIds"; //$NON-NLS-1$
+
+ /** TODO: Temporarily duplicated from BuilderFactory. Remove when 313927 is addressed */
+ static final String CONTENTS = "org.eclipse.cdt.make.core.contents"; //$NON-NLS-1$
+
+ /** TODO: Temporarily duplicated from BuilderFactory. Remove when 313927 is addressed */
+ static final String CONTENTS_CONFIGURATION_IDS = "org.eclipse.cdt.make.core.configurationIds"; //$NON-NLS-1$
+
+ /** TODO: Temporarily duplicated from BuilderFactory. Remove when 313927 is addressed */
+ private static Map<String, String> cfgIdsToMap(String ids[], Map<String, String> map){
+ map.put(CONFIGURATION_IDS, encodeList(Arrays.asList(ids)));
+ return map;
+ }
+
+ /** TODO: Temporarily duplicated from BuilderFactory. Remove when 313927 is addressed */
+ private static String encodeList(List<String> values) {
+ StringBuffer str = new StringBuffer();
+ Iterator<String> entries = values.iterator();
+ while (entries.hasNext()) {
+ String entry = entries.next();
+ str.append(escapeChars(entry, "|\\", '\\')); //$NON-NLS-1$
+ str.append("|"); //$NON-NLS-1$
+ }
+ return str.toString();
+ }
+
+ /** TODO: Temporarily duplicated from BuilderFactory. Remove when 313927 is addressed */
+ private static String escapeChars(String string, String escapeChars, char escapeChar) {
+ StringBuffer str = new StringBuffer(string);
+ for (int i = 0; i < str.length(); i++) {
+ if (escapeChars.indexOf(str.charAt(i)) != -1) {
+ str.insert(i, escapeChar);
+ i++;
+ }
}
- return super.preLaunchCheck(configuration, mode, monitor);
+ return str.toString();
}
+
+ /**
+ * The platform has a generic prompter object that redirects to an
+ * appropriate prompter based on the status object. The value-add it
+ * provides is that it can be invoked from a non-GUI thread.
+ */
+ private static final IStatus uiPromptStatus = new Status(IStatus.ERROR, "org.eclipse.debug.ui", 200, IInternalDebugCoreConstants.EMPTY_STRING, null); //$NON-NLS-1$
+
+ /** Status object used to fish out our BuildErrPrompter */
+ private static final IStatus promptStatusMainProj = new Status(IStatus.ERROR, LaunchUIPlugin.getUniqueIdentifier(), BuildErrPrompter.STATUS_CODE_ERR_IN_MAIN_PROJ, IInternalDebugCoreConstants.EMPTY_STRING, null);
+
+ /** Status object used to fish out our BuildErrPrompter */
+ private static final IStatus promptStatusReferencedProjs = new Status(IStatus.ERROR, LaunchUIPlugin.getUniqueIdentifier(), BuildErrPrompter.STATUS_CODE_ERR_IN_REFERENCED_PROJS, IInternalDebugCoreConstants.EMPTY_STRING, null);
+
+ private Object[] createPrompterArgs(ILaunchConfiguration launchConfig) throws CoreException {
+
+ IProject project = CDebugUtils.getCProject(launchConfig).getProject();
+
+ Object[] args = new Object[3];
+
+ // The launch configuration
+ args[0] = launchConfig;
+
+ // The name of the project
+ args[1] = project.getName();
+
+ // The name of the build configuration. Empty string if the
+ // setting is "Active" or the selected configuration is the
+ // active one, otherwise the name of the configuration.
+ args[2] = ""; //$NON-NLS-1$
+ String buildConfigId = launchConfig.getAttribute(ICDTLaunchConfigurationConstants.ATTR_PROJECT_BUILD_CONFIG_ID, ""); //$NON-NLS-1$
+ if (buildConfigId.length() > 0) {
+ ICProjectDescription desc = CCorePlugin.getDefault().getProjectDescription(project, false);
+ if (desc != null) {
+ ICConfigurationDescription cfgDescActive = desc.getActiveConfiguration();
+ ICConfigurationDescription cfgDesc = desc.getConfigurationById(buildConfigId);
+ if (cfgDesc != cfgDescActive) {
+ if (cfgDesc != null) {
+ args[2] = cfgDesc.getName();
+ }
+ else {
+ // TODO: not sure if and when this could ever happen, but just in case...
+ args[2] = "???"; //$NON-NLS-1$
+ }
+ }
+ }
+ }
+
+ return args;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.core.model.LaunchConfigurationDelegate#finalLaunchCheck(org.eclipse.debug.core.ILaunchConfiguration, java.lang.String, org.eclipse.core.runtime.IProgressMonitor)
+ */
@Override
public boolean finalLaunchCheck(ILaunchConfiguration configuration, String mode, IProgressMonitor monitor) throws CoreException {
- if (!workspaceBuildBeforeLaunch) {
- // buildForLaunch was not called which means that the workspace pref is disabled. see if the user enabled the
- // launch specific setting in the main tab. if so, we do call buildBeforeLaunch here.
- if (ICDTLaunchConfigurationConstants.BUILD_BEFORE_LAUNCH_ENABLED == configuration.getAttribute(ICDTLaunchConfigurationConstants.ATTR_BUILD_BEFORE_LAUNCH,
- ICDTLaunchConfigurationConstants.BUILD_BEFORE_LAUNCH_USE_WORKSPACE_SETTING)) {
-
- IProgressMonitor buildMonitor = new SubProgressMonitor(monitor, 10, SubProgressMonitor.PREPEND_MAIN_LABEL_TO_SUBTASK);
- buildMonitor.beginTask(LaunchMessages.getString("AbstractCLaunchDelegate.BuildBeforeLaunch"), 10); //$NON-NLS-1$
- buildMonitor.subTask(LaunchMessages.getString("AbstractCLaunchDelegate.PerformingBuild")); //$NON-NLS-1$
- if (buildForLaunch(configuration, mode, new SubProgressMonitor(buildMonitor, 7))) {
- buildMonitor.subTask(LaunchMessages.getString("AbstractCLaunchDelegate.PerformingIncrementalBuild")); //$NON-NLS-1$
- ResourcesPlugin.getWorkspace().build(IncrementalProjectBuilder.INCREMENTAL_BUILD, new SubProgressMonitor(buildMonitor, 3));
+ try {
+ SubMonitor localMonitor = SubMonitor.convert(monitor, LaunchMessages.getString("AbstractCLaunchDelegate.BuildBeforeLaunch"), 10); //$NON-NLS-1$
+
+ if (!workspaceBuildBeforeLaunch) {
+ // buildForLaunch was not called which means that the workspace pref is disabled. see if the user enabled the
+ // launch specific setting in the main tab. if so, we do call buildBeforeLaunch here.
+ if (ICDTLaunchConfigurationConstants.BUILD_BEFORE_LAUNCH_ENABLED == configuration.getAttribute(ICDTLaunchConfigurationConstants.ATTR_BUILD_BEFORE_LAUNCH,
+ ICDTLaunchConfigurationConstants.BUILD_BEFORE_LAUNCH_USE_WORKSPACE_SETTING)) {
+
+ localMonitor.subTask(LaunchMessages.getString("AbstractCLaunchDelegate.PerformingBuild")); //$NON-NLS-1$
+ if (buildForLaunch(configuration, mode, localMonitor.newChild(7))) {
+ localMonitor.subTask(LaunchMessages.getString("AbstractCLaunchDelegate.PerformingIncrementalBuild")); //$NON-NLS-1$
+ ResourcesPlugin.getWorkspace().build(IncrementalProjectBuilder.INCREMENTAL_BUILD, localMonitor.newChild(3));
+ }
+ }
+ }
+
+ // We can just call our super's implementation to have it check for
+ // build errors, but it is too generic. It doesn't know the concept
+ // of a CDT build configuration, and the fact that we requested the
+ // build of a particular one (which, btw, may not be the active one
+ // for the project). We want to put up a more informative error
+ // dialog if there are errors.
+ boolean continueLaunch = true;
+ ICProject cproject = CDebugUtils.getCProject(configuration);
+ if (cproject != null) {
+ IProject project = cproject.getProject();
+ localMonitor.subTask(DebugCoreMessages.LaunchConfigurationDelegate_6);
+ if (existsProblems(project)) {
+ // There's a build error in the main project
+
+ // Put up the error dialog.
+ IStatusHandler prompter = DebugPlugin.getDefault().getStatusHandler(uiPromptStatus);
+ if (prompter != null) {
+ continueLaunch = ((Boolean) prompter.handleStatus(promptStatusMainProj, createPrompterArgs(configuration))).booleanValue();
+ }
+ else {
+ assert false;
+ }
}
else {
- buildMonitor.worked(3); /* No incremental build required */
+ // No build error in the main project but see if there's one
+ // in any of its referenced projects
+ IProject[] projects = getBuildOrder(configuration, mode);
+ for (IProject proj : projects) {
+ // The array will contain the top level project.
+ // Ignore it since we handled it above
+ if (proj == project) {
+ continue;
+ }
+
+ if (existsProblems(proj)) {
+ // Put up the error dialog.
+ IStatusHandler prompter = DebugPlugin.getDefault().getStatusHandler(uiPromptStatus);
+ prompter = DebugPlugin.getDefault().getStatusHandler(uiPromptStatus);
+ if (prompter != null) {
+ continueLaunch = ((Boolean) prompter.handleStatus(promptStatusReferencedProjs, createPrompterArgs(configuration))).booleanValue();
+ }
+ else {
+ assert false;
+ }
+
+ // The error message says "one or more" and doesn't mention names.
+ break;
+ }
+ }
}
}
+
+ // Note that we do not call our super implementation (platform).
+ // That's because it'll just re-do everything we've done here in a
+ // non-customized way. However, we need to keep an eye out for any
+ // future additions to the platform's logic.
+
+ return continueLaunch;
+ }
+ finally {
+ workspaceBuildBeforeLaunch = false; // reset for future run
+ if (monitor != null) {
+ monitor.done();
+ }
}
- boolean continueLaunch = super.finalLaunchCheck(configuration, mode, monitor);
-
- if (continueLaunch) // If no problems then restore the previous build configuration. Otherwise leave it so the user can fix the build issues.
- resetBuildConfiguration(project);
-
- return continueLaunch;
}
protected ICProject verifyCProject(ILaunchConfiguration config) throws CoreException {
@@ -285,52 +532,6 @@ public abstract class AbstractCLaunchDelegate2 extends LaunchConfigurationDelega
}
/**
- * Sets up a project for building by making sure the active configuration is the one used
- * when the launch was created.
- * @param configuration
- * @param buildProject
- */
- private void setBuildConfiguration(ILaunchConfiguration configuration, IProject buildProject) {
-
- try {
- if (buildProject != null)
- {
- String buildConfigID = configuration.getAttribute(ICDTLaunchConfigurationConstants.ATTR_PROJECT_BUILD_CONFIG_ID, ""); //$NON-NLS-1$
- ICProjectDescription projDes = CDTPropertyManager.getProjectDescription(buildProject);
-
- if (buildConfigID.length() > 0 && projDes != null)
- {
- ICConfigurationDescription buildConfiguration = projDes.getConfigurationById(buildConfigID);
- if (buildConfiguration != null) {
- preLaunchBuildConfiguration = projDes.getActiveConfiguration().getId();
- buildConfiguration.setActive();
- CDTPropertyManager.performOk(null);
- }
- }
- }
-
- } catch (CoreException e) {}
- }
-
- private void resetBuildConfiguration(IProject buildProject) {
- // Restore the active configuration if it was changed for the launch
- if (preLaunchBuildConfiguration != null) {
- ICProjectDescription projDes = CDTPropertyManager.getProjectDescription(buildProject);
-
- if (preLaunchBuildConfiguration.length() > 0 && projDes != null)
- {
- ICConfigurationDescription buildConfiguration = projDes.getConfigurationById(preLaunchBuildConfiguration);
- if (buildConfiguration != null) {
- buildConfiguration.setActive();
- CDTPropertyManager.performOk(null);
- }
- }
-
- }
- preLaunchBuildConfiguration = null;
- }
-
- /**
* @return the ID of the plugin hosting the launch delegate. It's used to
* create {@link IStatus} objects.
*/
diff --git a/launch/org.eclipse.cdt.launch/src/org/eclipse/cdt/launch/internal/ui/BuildErrPrompter.java b/launch/org.eclipse.cdt.launch/src/org/eclipse/cdt/launch/internal/ui/BuildErrPrompter.java
new file mode 100644
index 00000000000..24699b4737d
--- /dev/null
+++ b/launch/org.eclipse.cdt.launch/src/org/eclipse/cdt/launch/internal/ui/BuildErrPrompter.java
@@ -0,0 +1,152 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2010 IBM Corporation, Freescale Semiconductor 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
+ * Freescale Semiconductor - customized for use in CDT
+ *******************************************************************************/
+
+package org.eclipse.cdt.launch.internal.ui;
+
+import java.text.MessageFormat;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.debug.core.ILaunchConfiguration;
+import org.eclipse.debug.core.IStatusHandler;
+import org.eclipse.debug.internal.ui.DebugUIPlugin;
+import org.eclipse.debug.internal.ui.IInternalDebugUIConstants;
+import org.eclipse.debug.internal.ui.launchConfigurations.LaunchConfigurationsMessages;
+import org.eclipse.debug.ui.DebugUITools;
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.dialogs.MessageDialogWithToggle;
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.swt.widgets.Shell;
+
+/**
+ * This class is a customization of the platform's
+ * CompileErrorProjectPromptStatusHandler. We use it to put up a more
+ * CDT-centric message when building before a launch and there is an error in
+ * the project. We want to let the user know what specific build configuration
+ * is having a build error when the configuration is not the active one.
+ * See https://bugs.eclipse.org/bugs/show_bug.cgi?id=309126#c11
+ */
+public class BuildErrPrompter implements IStatusHandler {
+
+ /**
+ * Status code indicating there was an error in the main project. Linked to
+ * BuildErrPrompter via our statusHandlers extension (see plugin.xml)
+ */
+ public static final int STATUS_CODE_ERR_IN_MAIN_PROJ = 1002;
+
+ /**
+ * Status code indicating there was an error in a project referenced by the
+ * main project. Linked to BuildErrPrompter via our statusHandlers extension
+ * (see plugin.xml)
+ */
+ public static final int STATUS_CODE_ERR_IN_REFERENCED_PROJS = 1003;
+
+ /**
+ * Source is an array of three things, in the following order
+ * <ul>
+ * <li>launch configuration that was invoked
+ * <li>the name of the project the launch first attempted to build
+ * <li>the name of the build configuration that was built, or empty string
+ * if it was the active one. This argument should be non-empty ONLY if a
+ * not-active configuration was built.
+ * <ul>
+ *
+ * @see org.eclipse.debug.core.IStatusHandler#handleStatus(org.eclipse.core.runtime.IStatus,
+ * java.lang.Object)
+ */
+ public Object handleStatus(IStatus status, Object source) throws CoreException {
+
+ if (!(source instanceof Object[])) {
+ assert false : "status handler not given expected arguments"; //$NON-NLS-1$
+ return Boolean.TRUE;
+ }
+
+ Object[] args = (Object[])source;
+ if (args.length != 3 ||
+ !(args[0] instanceof ILaunchConfiguration) ||
+ !(args[1] instanceof String) ||
+ !(args[2] instanceof String)) {
+ assert false : "status handler not given expected arguments"; //$NON-NLS-1$
+ return Boolean.TRUE;
+ }
+
+ final ILaunchConfiguration launchConfig = (ILaunchConfiguration)args[0];
+ final String projectName = (String)args[1];
+ final String buildConfigName = (String)args[2];
+
+ // The platform does this check; we should, too
+ if (DebugUITools.isPrivate(launchConfig)) {
+ return Boolean.TRUE;
+ }
+
+ Shell shell = DebugUIPlugin.getShell();
+ String title = LaunchConfigurationsMessages.CompileErrorPromptStatusHandler_0;
+ String message;
+ if (status.getCode() == STATUS_CODE_ERR_IN_MAIN_PROJ) {
+ if (buildConfigName.length() > 0) {
+ message = MessageFormat.format(
+ LaunchMessages.getString("BuildErrPrompter.error_in_specific_config"), projectName, buildConfigName); //$NON-NLS-1$
+ }
+ else {
+ message = MessageFormat.format(
+ LaunchMessages.getString("BuildErrPrompter.error_in_active_config"), projectName); //$NON-NLS-1$
+ }
+ }
+ else if (status.getCode() == STATUS_CODE_ERR_IN_REFERENCED_PROJS) {
+ if (buildConfigName.length() > 0) {
+ message = MessageFormat.format(
+ LaunchMessages.getString("BuildErrPrompter.error_in_referenced_project_specific"), //$NON-NLS-1$
+ projectName, buildConfigName);
+ }
+ else {
+ message = MessageFormat.format(
+ LaunchMessages.getString("BuildErrPrompter.error_in_referenced_project_active"), //$NON-NLS-1$
+ projectName);
+ }
+ }
+ else {
+ assert false : "this prompter was called for an unexpected status"; //$NON-NLS-1$
+ return Boolean.TRUE;
+ }
+
+ // The rest is monkey-see, monkey-do (copied from
+ // CompileErrorProjectPromptStatusHandler)
+
+ IPreferenceStore store = DebugUIPlugin.getDefault().getPreferenceStore();
+ String pref = store.getString(IInternalDebugUIConstants.PREF_CONTINUE_WITH_COMPILE_ERROR);
+ if (pref != null) {
+ if (pref.equals(MessageDialogWithToggle.ALWAYS)) {
+ return Boolean.TRUE;
+ }
+ }
+ MessageDialogWithToggle dialog = new MessageDialogWithToggle(shell,
+ title,
+ null,
+ message,
+ MessageDialog.QUESTION,
+ new String[] {IDialogConstants.PROCEED_LABEL, IDialogConstants.CANCEL_LABEL},
+ 0,
+ LaunchConfigurationsMessages.CompileErrorProjectPromptStatusHandler_1,
+ false);
+ int open = dialog.open();
+ if (open == IDialogConstants.PROCEED_ID) {
+ if(dialog.getToggleState()) {
+ store.setValue(IInternalDebugUIConstants.PREF_CONTINUE_WITH_COMPILE_ERROR, MessageDialogWithToggle.ALWAYS);
+ }
+ return Boolean.TRUE;
+ }
+ else {
+ return Boolean.FALSE;
+ }
+ }
+}
diff --git a/launch/org.eclipse.cdt.launch/src/org/eclipse/cdt/launch/internal/ui/LaunchMessages.properties b/launch/org.eclipse.cdt.launch/src/org/eclipse/cdt/launch/internal/ui/LaunchMessages.properties
index c9b1b62b423..33c8c6a503c 100644
--- a/launch/org.eclipse.cdt.launch/src/org/eclipse/cdt/launch/internal/ui/LaunchMessages.properties
+++ b/launch/org.eclipse.cdt.launch/src/org/eclipse/cdt/launch/internal/ui/LaunchMessages.properties
@@ -199,3 +199,8 @@ MultiLaunchConfigurationTabGroup.15=Launch {0} is filtered.
MultiLaunchConfigurationTabGroup.16=Must have at least one valid enabled launch.
ProjectRenameChange.name=Update launch configuration "{0}"
ProjectRenameChange.saveFailed=Failed to save updated launch configuration "{0}"
+
+BuildErrPrompter.error_in_specific_config=Errors exist in project \"{0}\" having built not-active build configuration \"{1}\". Proceed with launch?
+BuildErrPrompter.error_in_active_config=Errors exist in the active configuration of project \"{0}\". Proceed with launch?
+BuildErrPrompter.error_in_referenced_project_specific=One or more projects referenced by project \"{0}\", build configuration \"{1}\" has build errors. See Problems view for details. Keep in mind that the errors may be in build configurations that are not the active ones. Continue anyway?
+BuildErrPrompter.error_in_referenced_project_active=One or more projects referenced by the active configuration of project \"{0}\" has build errors. See Problems view for details. Keep in mind that the errors may be in build configurations that are not the active ones. Continue anyway? \ No newline at end of file

Back to the top