diff options
author | John Cortell | 2010-05-25 20:26:14 +0000 |
---|---|---|
committer | John Cortell | 2010-05-25 20:26:14 +0000 |
commit | 72fbc7d39431752019d81548dff5f01015b341d2 (patch) | |
tree | 493042b9fb42ab354af0e63672fc403776af8a11 /launch/org.eclipse.cdt.launch/src | |
parent | c58a08aaad2ad5eb69da91f1d6e14e26e75d513c (diff) | |
download | org.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')
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 |