diff --git a/build/org.eclipse.cdt.managedbuilder.core.tests/tests/org/eclipse/cdt/managedbuilder/language/settings/providers/tests/GCCBuildCommandParserTest.java b/build/org.eclipse.cdt.managedbuilder.core.tests/tests/org/eclipse/cdt/managedbuilder/language/settings/providers/tests/GCCBuildCommandParserTest.java index f18c4eb9b0d..a5b7670a4f6 100644 --- a/build/org.eclipse.cdt.managedbuilder.core.tests/tests/org/eclipse/cdt/managedbuilder/language/settings/providers/tests/GCCBuildCommandParserTest.java +++ b/build/org.eclipse.cdt.managedbuilder.core.tests/tests/org/eclipse/cdt/managedbuilder/language/settings/providers/tests/GCCBuildCommandParserTest.java @@ -195,6 +195,7 @@ public class GCCBuildCommandParserTest extends BaseTestCase { assertEquals(null, provider.getLanguageScope()); assertEquals(null, provider.getSettingEntries(null, null, null)); assertEquals("", provider.getCompilerPattern()); + assertEquals(AbstractBuildCommandParser.ResourceScope.FILE, provider.getResourceScope()); } { @@ -218,6 +219,8 @@ public class GCCBuildCommandParserTest extends BaseTestCase { // setters provider.setCompilerPattern(CUSTOM_PARAMETER_2); assertEquals(CUSTOM_PARAMETER_2, provider.getCompilerPattern()); + provider.setResourceScope(AbstractBuildCommandParser.ResourceScope.PROJECT); + assertEquals(AbstractBuildCommandParser.ResourceScope.PROJECT, provider.getResourceScope()); } } @@ -236,11 +239,23 @@ public class GCCBuildCommandParserTest extends BaseTestCase { // configure provider parser.setResolvingPaths(false); assertFalse(parser.equals(clone0)); + parser.setResourceScope(AbstractBuildCommandParser.ResourceScope.PROJECT); + assertEquals(AbstractBuildCommandParser.ResourceScope.PROJECT, parser.getResourceScope()); + parser.setResourceScope(AbstractBuildCommandParser.ResourceScope.FOLDER); + assertEquals(AbstractBuildCommandParser.ResourceScope.FOLDER, parser.getResourceScope()); + parser.setResourceScope(AbstractBuildCommandParser.ResourceScope.FILE); + assertEquals(AbstractBuildCommandParser.ResourceScope.FILE, parser.getResourceScope()); - // check another clone after configuring + // check another clone after changing settings { + parser.setResolvingPaths(false); + assertFalse(parser.equals(clone0)); + parser.setResourceScope(AbstractBuildCommandParser.ResourceScope.PROJECT); + assertEquals(AbstractBuildCommandParser.ResourceScope.PROJECT, parser.getResourceScope()); MockBuildCommandParser clone = parser.clone(); assertTrue(parser.equals(clone)); + assertEquals(parser.isResolvingPaths(), clone.isResolvingPaths()); + assertEquals(parser.getResourceScope(), clone.getResourceScope()); } // check 'expand relative paths' flag @@ -251,6 +266,16 @@ public class GCCBuildCommandParserTest extends BaseTestCase { assertFalse(parser.equals(clone)); } + // check resource scope + { + parser.setResourceScope(AbstractBuildCommandParser.ResourceScope.PROJECT); + assertEquals(AbstractBuildCommandParser.ResourceScope.PROJECT, parser.getResourceScope()); + MockBuildCommandParser clone = parser.clone(); + assertEquals(AbstractBuildCommandParser.ResourceScope.PROJECT, clone.getResourceScope()); + clone.setResourceScope(AbstractBuildCommandParser.ResourceScope.FOLDER); + assertFalse(parser.equals(clone)); + } + // check cloneShallow() { MockBuildCommandParser parser2 = parser.clone(); diff --git a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/language/settings/providers/AbstractBuildCommandParser.java b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/language/settings/providers/AbstractBuildCommandParser.java index efaf4829f8c..4c4f52c1729 100644 --- a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/language/settings/providers/AbstractBuildCommandParser.java +++ b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/language/settings/providers/AbstractBuildCommandParser.java @@ -21,6 +21,10 @@ import org.eclipse.cdt.core.IMarkerGenerator; import org.eclipse.cdt.core.errorparsers.RegexErrorParser; import org.eclipse.cdt.core.errorparsers.RegexErrorPattern; import org.eclipse.cdt.core.language.settings.providers.LanguageSettingsManager; +import org.eclipse.cdt.core.settings.model.ICLanguageSettingEntry; +import org.eclipse.cdt.internal.core.language.settings.providers.LanguageSettingsLogger; +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IResource; /** * Abstract class for providers parsing compiler option from build command when present in build output. @@ -29,12 +33,24 @@ import org.eclipse.cdt.core.language.settings.providers.LanguageSettingsManager; */ public abstract class AbstractBuildCommandParser extends AbstractLanguageSettingsOutputScanner { public static final Object JOB_FAMILY_BUILD_COMMAND_PARSER = "org.eclipse.cdt.managedbuilder.AbstractBuildCommandParser"; //$NON-NLS-1$ + private static final String ATTR_PARAMETER = "parameter"; //$NON-NLS-1$ + private static final String ATTR_RESOURCE_SCOPE = "resource-scope"; //$NON-NLS-1$ + private static final String VALUE_FILE_SCOPE = "per-file"; //$NON-NLS-1$ + private static final String VALUE_FOLDER_SCOPE = "per-folder"; //$NON-NLS-1$ + private static final String VALUE_PROJECT_SCOPE = "per-project"; //$NON-NLS-1$ + private static final String LEADING_PATH_PATTERN = "\\S+[/\\\\]"; //$NON-NLS-1$ private static final Pattern OPTIONS_PATTERN = Pattern.compile("-[^\\s\"']*(\\s*((\".*?\")|('.*?')|([^-\\s][^\\s]+)))?"); //$NON-NLS-1$ private static final int OPTION_GROUP = 0; + public enum ResourceScope { + FILE, + FOLDER, + PROJECT, + } + /** * Note: design patterns to keep file group the same and matching {@link #FILE_GROUP} */ @@ -45,6 +61,8 @@ public abstract class AbstractBuildCommandParser extends AbstractLanguageSetting }; private static final int FILE_GROUP = 2; + // cached value from properties, do not need to use in equals() and hashCode() + private ResourceScope resourceScope = null; /** * The compiler command pattern without specifying compiler options. @@ -76,6 +94,85 @@ public abstract class AbstractBuildCommandParser extends AbstractLanguageSetting return "\\s*\"?("+LEADING_PATH_PATTERN+")?(" + compilerPattern + ")\"?"; } + /** + * @return resource scope of the entries, i.e. level in resource hierarchy where language settings entries + * will be applied by the provider. Resource scope can be one of the following: + *
- {@code AbstractBuildCommandParser.ResourceScope.FILE} - apply entries to the file being parsed. + *
- {@code AbstractBuildCommandParser.ResourceScope.FOLDER} - apply entries to the enclosing folder. + *
- {@code AbstractBuildCommandParser.ResourceScope.PROJECT} - apply entries to the project level. + */ + public ResourceScope getResourceScope() { + if (resourceScope == null) { + String scopeStr = getProperty(ATTR_RESOURCE_SCOPE); + if (scopeStr.equals(VALUE_FILE_SCOPE)) { + resourceScope = ResourceScope.FILE; + } else if (scopeStr.equals(VALUE_FOLDER_SCOPE)) { + resourceScope = ResourceScope.FOLDER; + } else if (scopeStr.equals(VALUE_PROJECT_SCOPE)) { + resourceScope = ResourceScope.PROJECT; + } else { + resourceScope = ResourceScope.FILE; + } + } + return resourceScope; + } + + /** + * Set resource scope of the entries, i.e. level in resource hierarchy where language settings entries + * will be applied by the provider. + * + * @param rcScope - resource scope can be one of the following: + *
- {@code AbstractBuildCommandParser.ResourceScope.FILE} - apply entries to the file being parsed. + *
- {@code AbstractBuildCommandParser.ResourceScope.FOLDER} - apply entries to the enclosing folder. + *
- {@code AbstractBuildCommandParser.ResourceScope.PROJECT} - apply entries to the project level. + */ + public void setResourceScope(ResourceScope rcScope) { + resourceScope = rcScope; + switch (rcScope) { + case FILE: + setProperty(ATTR_RESOURCE_SCOPE, VALUE_FILE_SCOPE); + break; + case FOLDER: + setProperty(ATTR_RESOURCE_SCOPE, VALUE_FOLDER_SCOPE); + break; + case PROJECT: + setProperty(ATTR_RESOURCE_SCOPE, VALUE_PROJECT_SCOPE); + break; + default: + setProperty(ATTR_RESOURCE_SCOPE, VALUE_FILE_SCOPE); + break; + } + } + + @Override + protected void setSettingEntries(List entries) { + IResource rc = null; + switch (getResourceScope()) { + case FILE: + rc = currentResource; + break; + case FOLDER: + if (currentResource instanceof IFile) { + rc = currentResource.getParent(); + } + break; + case PROJECT: + if (currentResource != null) { + rc = currentResource.getProject(); + } + break; + default: + break; + + } + setSettingEntries(currentCfgDescription, rc, currentLanguageId, entries); + + // AG FIXME - temporary log to remove before CDT Juno release + LanguageSettingsLogger.logInfo(getPrefixForLog() + + getClass().getSimpleName() + " collected " + (entries!=null ? ("" + entries.size()) : "null") + " entries for " + rc); + + } + /** * Adjust count for file group taking into consideration extra groups added by {@link #getCompilerPatternExtended()}. */ diff --git a/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/internal/ui/language/settings/providers/GCCBuildCommandParserOptionPage.java b/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/internal/ui/language/settings/providers/GCCBuildCommandParserOptionPage.java index b3e7a70615a..c438cb93082 100644 --- a/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/internal/ui/language/settings/providers/GCCBuildCommandParserOptionPage.java +++ b/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/internal/ui/language/settings/providers/GCCBuildCommandParserOptionPage.java @@ -30,6 +30,7 @@ import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Group; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Text; @@ -46,7 +47,10 @@ public final class GCCBuildCommandParserOptionPage extends AbstractLanguageSetti private Button runOnceRadioButton; private Button runEveryBuildRadioButton; private Button expandRelativePathCheckBox; - private Button applyToProjectCheckBox; + + private Button scopeProjectRadioButton; + private Button scopeFolderRadioButton; + private Button scopeFileRadioButton; /* @@ -157,25 +161,97 @@ public final class GCCBuildCommandParserOptionPage extends AbstractLanguageSetti } + Group resourceScopeGroup = new Group(composite, SWT.NONE); { - applyToProjectCheckBox = new Button(composite, SWT.CHECK); - applyToProjectCheckBox.setText("Apply discovered settings on project level"); +// resourceScopeGroup.setText("Define scope of discovered entries"); +// resourceScopeGroup.setText("Apply discovered entries to"); + resourceScopeGroup.setText("Scope to keep discovered entries"); + resourceScopeGroup.setLayout(new GridLayout(2, false)); GridData gd = new GridData(GridData.FILL_HORIZONTAL); gd.horizontalSpan = 2; - applyToProjectCheckBox.setLayoutData(gd); + resourceScopeGroup.setLayoutData(gd); + } -// applyToProjectCheckBox.setSelection(provider.isExpandRelativePaths()); -// applyToProjectCheckBox.setEnabled(fEditable); - applyToProjectCheckBox.setSelection(false); - applyToProjectCheckBox.setEnabled(false); - applyToProjectCheckBox.addSelectionListener(new SelectionAdapter() { + { + scopeFileRadioButton = new Button(resourceScopeGroup, SWT.RADIO); + scopeFileRadioButton.setText("Per file, use when settings vary for different files"); +// applyToResourceRadioButton.setText("File level, use when settings vary for different files"); + GridData gd = new GridData(GridData.FILL_HORIZONTAL); + gd.horizontalSpan = 2; + scopeFileRadioButton.setLayoutData(gd); + + scopeFileRadioButton.setSelection(provider.getResourceScope() == AbstractBuildCommandParser.ResourceScope.FILE); + scopeFileRadioButton.setEnabled(fEditable); + scopeFileRadioButton.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { - boolean enabled = applyToProjectCheckBox.getSelection(); + boolean enabled = scopeFileRadioButton.getSelection(); AbstractBuildCommandParser provider = getRawProvider(); - if (enabled != provider.isResolvingPaths()) { + if (enabled != (provider.getResourceScope() == AbstractBuildCommandParser.ResourceScope.FILE)) { AbstractBuildCommandParser selectedProvider = getWorkingCopy(providerId); - selectedProvider.setResolvingPaths(enabled); + selectedProvider.setResourceScope(AbstractBuildCommandParser.ResourceScope.FILE); + providerTab.refreshItem(selectedProvider); + } + } + + @Override + public void widgetDefaultSelected(SelectionEvent e) { + widgetSelected(e); + } + + }); + + } + + { + scopeFolderRadioButton = new Button(resourceScopeGroup, SWT.RADIO); + scopeFolderRadioButton.setText("Per folder, use when settings are the same for all files in a folder"); +// applyToEnclosingFolderRadioButton.setText("Enclosing folder, use when settings are the same for all files in a folder"); + GridData gd = new GridData(GridData.FILL_HORIZONTAL); + gd.horizontalSpan = 2; + scopeFolderRadioButton.setLayoutData(gd); + + scopeFolderRadioButton.setSelection(provider.getResourceScope() == AbstractBuildCommandParser.ResourceScope.FOLDER); + scopeFolderRadioButton.setEnabled(fEditable); + scopeFolderRadioButton.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + boolean enabled = scopeFolderRadioButton.getSelection(); + AbstractBuildCommandParser provider = getRawProvider(); + if (enabled != (provider.getResourceScope() == AbstractBuildCommandParser.ResourceScope.FOLDER)) { + AbstractBuildCommandParser selectedProvider = getWorkingCopy(providerId); + selectedProvider.setResourceScope(AbstractBuildCommandParser.ResourceScope.FOLDER); + providerTab.refreshItem(selectedProvider); + } + } + + @Override + public void widgetDefaultSelected(SelectionEvent e) { + widgetSelected(e); + } + + }); + + } + + { + scopeProjectRadioButton = new Button(resourceScopeGroup, SWT.RADIO); + scopeProjectRadioButton.setText("Per project, use when settings are the same for all files in the project"); +// applyToProjectRadioButton.setText("Project level, use when settings are the same for all files in the project"); + GridData gd = new GridData(GridData.FILL_HORIZONTAL); + gd.horizontalSpan = 2; + scopeProjectRadioButton.setLayoutData(gd); + + scopeProjectRadioButton.setSelection(provider.getResourceScope() == AbstractBuildCommandParser.ResourceScope.PROJECT); + scopeProjectRadioButton.setEnabled(fEditable); + scopeProjectRadioButton.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + boolean enabled = scopeProjectRadioButton.getSelection(); + AbstractBuildCommandParser provider = getRawProvider(); + if (enabled != (provider.getResourceScope() == AbstractBuildCommandParser.ResourceScope.PROJECT)) { + AbstractBuildCommandParser selectedProvider = getWorkingCopy(providerId); + selectedProvider.setResourceScope(AbstractBuildCommandParser.ResourceScope.PROJECT); providerTab.refreshItem(selectedProvider); } }