From fbc67e72a2bb7fed8343cccbccdbbe7e06f534e9 Mon Sep 17 00:00:00 2001 From: Andrew Gvozdev Date: Thu, 7 Jul 2011 12:29:41 -0400 Subject: [PATCH] Initial commit of new Scanner Discovery for CDT - bug 290631. See prior history on GitHub https://github.com/angvoz/SD80/, branch sd80 --- .../plugin.xml | 14 + .../make/scannerdiscovery/AllSD80Tests.java | 26 + .../GCCBuildCommandParserTest.java | 1904 +++++++++++++++++ .../ScannerDiscoveryTests.java | 4 +- build/org.eclipse.cdt.make.core/plugin.xml | 9 + .../AbstractBuildCommandParser.java | 130 ++ ...AbstractLanguageSettingsOutputScanner.java | 821 +++++++ .../scannerconfig/GCCBuildCommandParser.java | 72 + .../ILanguageSettingsBuildOutputScanner.java | 29 + ...ILanguageSettingsBuiltinSpecsDetector.java | 28 + .../ILanguageSettingsOutputScanner.java | 35 + .../icons/obj16/inspect_system.gif | Bin 0 -> 553 bytes .../icons/obj16/log_obj.gif | Bin 0 -> 335 bytes .../icons/obj16/search.gif | Bin 0 -> 347 bytes .../org.eclipse.cdt.make.ui/plugin.properties | 3 + build/org.eclipse.cdt.make.ui/plugin.xml | 31 + .../GCCBuildCommandParserOptionPage.java | 370 ++++ .../ScannerDiscoveryConsole.java | 39 + .../tests/suite/AllManagedBuildTests.java | 2 + .../scannerconfig/tests/AllSD80Tests.java | 29 + .../tests/GCCBuiltinSpecsDetectorTest.java | 659 ++++++ .../plugin.xml | 28 + .../schema/buildDefinitions.exsd | 45 +- .../CfgScannerConfigProfileManager.java | 36 + .../core/ExternalBuildRunner.java | 89 +- .../managedbuilder/core/IConfiguration.java | 3 + .../cdt/managedbuilder/core/IToolChain.java | 9 + .../core/InternalBuildRunner.java | 66 +- .../core/ManagedBuildManager.java | 145 ++ .../internal/core/CommonBuilder.java | 3 + .../internal/core/Configuration.java | 8 + .../internal/core/MultiConfiguration.java | 5 + .../internal/core/ToolChain.java | 8 + .../AbstractBuiltinSpecsDetector.java | 508 +++++ .../GCCBuiltinSpecsDetector.java | 135 ++ .../MBSLanguageSettingsProvider.java | 113 + .../plugin.xml | 25 +- .../ui/tests/util/TestConfiguration.java | 5 + .../ui/tests/util/TestToolchain.java | 9 +- .../icons/obj16/mbs.gif | Bin 0 -> 380 bytes .../icons/obj16/search.gif | Bin 0 -> 347 bytes .../plugin.properties | 1 + .../plugin.xml | 11 + .../managedbuilder/internal/ui/Messages.java | 2 + .../internal/ui/Messages.properties | 1 + .../BuiltinSpecsDetectorOptionPage.java | 325 +++ .../ui/preferences/PropertyPageDefsTab.java | 11 +- .../ui/preferences/WizardDefaultsTab.java | 8 + .../ui/wizards/MBSWizardHandler.java | 35 +- .../ui/wizards/NewMakeProjFromExisting.java | 35 +- .../wizards/NewMakeProjFromExistingPage.java | 23 + .../ui/wizards/STDWizardHandler.java | 42 +- .../ram/MemoryEFSExtensionProvider.java | 33 + .../AllLanguageSettingsProvidersTests.java | 32 + .../LanguageSettingsExtensionsTests.java | 324 +++ .../LanguageSettingsManagerTests.java | 781 +++++++ ...nguageSettingsPersistenceProjectTests.java | 839 ++++++++ ...guageSettingsScannerInfoProviderTests.java | 893 ++++++++ .../LanguageSettingsSerializableTests.java | 1146 ++++++++++ .../MockLanguageSettingsBaseProvider.java | 19 + .../MockLanguageSettingsEditableProvider.java | 30 + .../MockLanguageSettingsProvider.java | 28 + ...kLanguageSettingsSerializableProvider.java | 25 + .../cdt/core/model/tests/AllCoreTests.java | 3 + .../index/tests/IndexProviderManagerTest.java | 7 + core/org.eclipse.cdt.core.tests/plugin.xml | 157 ++ .../cdt/core/testplugin/CModelMock.java | 416 ++++ .../org.eclipse.cdt.core/META-INF/MANIFEST.MF | 2 + .../providers/ILanguageSettingsProvider.java | 65 + .../LanguageSettingsBaseProvider.java | 175 ++ .../providers/LanguageSettingsManager.java | 204 ++ .../LanguageSettingsManager_TBD.java | 99 + .../LanguageSettingsSerializable.java | 504 +++++ .../LanguageSettingsSerializableEditable.java | 28 + .../model/ACExclusionFilterEntry.java | 3 +- .../cdt/core/settings/model/ACPathEntry.java | 8 +- .../model/ICConfigurationDescription.java | 27 + .../core/settings/model/ICSettingEntry.java | 15 + .../ILanguageSettingsEditableProvider.java | 34 + .../LanguageSettingEntriesSerializer.java | 20 +- .../model/util/PathEntryTranslator.java | 48 +- .../LanguageSettingsExtensionManager.java | 517 +++++ .../providers/LanguageSettingsLogger.java | 79 + .../LanguageSettingsProvidersSerializer.java | 456 ++++ .../LanguageSettingsScannerInfoProvider.java | 325 +++ .../model/CConfigurationDescription.java | 19 + .../model/CConfigurationDescriptionCache.java | 34 + .../model/CConfigurationSpecSettings.java | 42 +- .../model/DescriptionScannerInfoProvider.java | 4 + .../model/MultiConfigDescription.java | 13 + .../model/ScannerInfoProviderProxy.java | 11 + .../model/SettingsModelMessages.properties | 6 +- .../xml/XmlProjectDescriptionStorage.java | 4 + core/org.eclipse.cdt.core/plugin.properties | 1 + core/org.eclipse.cdt.core/plugin.xml | 5 +- .../schema/LanguageSettingsProvider.exsd | 264 +++ .../core/AbstractExecutableExtensionBase.java | 83 + .../src/org/eclipse/cdt/core/CCorePlugin.java | 2 +- .../eclipse/cdt/core/ErrorParserManager.java | 2 +- .../org/eclipse/cdt/core/ICConsoleParser.java | 25 + .../cdt/core/resources/ScannerProvider.java | 9 + .../internal/core/ConsoleOutputSniffer.java | 30 +- core/org.eclipse.cdt.ui/META-INF/MANIFEST.MF | 1 + .../icons/obj16/filesyst.gif | Bin 310 -> 144 bytes .../icons/obj16/frameworks.gif | Bin 0 -> 904 bytes .../icons/obj16/ls_entries.gif | Bin 0 -> 386 bytes .../icons/obj16/ls_entries_provider.gif | Bin 0 -> 371 bytes .../icons/obj16/provider_ls_obj.gif | Bin 0 -> 186 bytes .../org.eclipse.cdt.ui/icons/obj16/search.gif | Bin 0 -> 347 bytes .../icons/ovr16/cfg_ovr.gif | Bin 0 -> 155 bytes .../icons/ovr16/edited_ov.gif | Bin 0 -> 167 bytes .../icons/ovr16/empty_ovr.png | Bin 0 -> 335 bytes .../icons/ovr16/global_ovr.gif | Bin 0 -> 271 bytes .../icons/ovr16/import_co.gif | Bin 0 -> 68 bytes .../icons/ovr16/link_ovr.gif | Bin 0 -> 169 bytes .../icons/ovr16/lock_ovr.gif | Bin 0 -> 115 bytes .../icons/ovr16/overlay-has-context.gif | Bin 0 -> 162 bytes .../icons/ovr16/project_co.gif | Bin 0 -> 112 bytes core/org.eclipse.cdt.ui/plugin.properties | 8 +- core/org.eclipse.cdt.ui/plugin.xml | 43 + .../LanguageSettingsProviderAssociation.exsd | 155 ++ .../eclipse/cdt/internal/ui/ImageCombo.java | 1471 +++++++++++++ ...ractLanguageSettingProviderOptionPage.java | 13 + .../providers/LanguageSettingEntryDialog.java | 644 ++++++ .../providers/LanguageSettingsEntriesTab.java | 1128 ++++++++++ .../LanguageSettingsProviderAssociation.java | 246 +++ .../LanguageSettingsProviderTab.java | 1059 +++++++++ ...anguageSettingsProvidersLabelProvider.java | 118 + .../Page_LanguageSettingsProviders.java | 41 + .../UserLanguageSettingsProvider.java | 47 + .../ui/newui/LanguageSettingsImages.java | 195 ++ .../cdt/internal/ui/newui/Messages.java | 11 + .../cdt/internal/ui/newui/Messages.properties | 11 + .../internal/ui/newui/StatusMessageLine.java | 81 + .../viewsupport/ProblemsLabelDecorator.java | 4 +- .../org/eclipse/cdt/ui/CDTSharedImages.java | 18 + .../cdt/ui/newui/AbstractCPropertyTab.java | 7 + .../cdt/ui/newui/AbstractLangsListTab.java | 109 +- .../org/eclipse/cdt/ui/newui/CDTPrefUtil.java | 2 + .../cdt/ui/wizards/CDTMainWizardPage.java | 19 + .../plugin.xml | 20 +- .../xlc/core/XlcBuiltinSpecsDetector.java | 97 + 142 files changed, 19260 insertions(+), 123 deletions(-) create mode 100644 build/org.eclipse.cdt.make.core.tests/plugin.xml create mode 100644 build/org.eclipse.cdt.make.core.tests/src/org/eclipse/cdt/make/scannerdiscovery/AllSD80Tests.java create mode 100644 build/org.eclipse.cdt.make.core.tests/src/org/eclipse/cdt/make/scannerdiscovery/GCCBuildCommandParserTest.java create mode 100644 build/org.eclipse.cdt.make.core/src/org/eclipse/cdt/make/core/scannerconfig/AbstractBuildCommandParser.java create mode 100644 build/org.eclipse.cdt.make.core/src/org/eclipse/cdt/make/core/scannerconfig/AbstractLanguageSettingsOutputScanner.java create mode 100644 build/org.eclipse.cdt.make.core/src/org/eclipse/cdt/make/core/scannerconfig/GCCBuildCommandParser.java create mode 100644 build/org.eclipse.cdt.make.core/src/org/eclipse/cdt/make/core/scannerconfig/ILanguageSettingsBuildOutputScanner.java create mode 100644 build/org.eclipse.cdt.make.core/src/org/eclipse/cdt/make/core/scannerconfig/ILanguageSettingsBuiltinSpecsDetector.java create mode 100644 build/org.eclipse.cdt.make.core/src/org/eclipse/cdt/make/core/scannerconfig/ILanguageSettingsOutputScanner.java create mode 100644 build/org.eclipse.cdt.make.ui/icons/obj16/inspect_system.gif create mode 100644 build/org.eclipse.cdt.make.ui/icons/obj16/log_obj.gif create mode 100644 build/org.eclipse.cdt.make.ui/icons/obj16/search.gif create mode 100644 build/org.eclipse.cdt.make.ui/src/org/eclipse/cdt/make/internal/ui/preferences/GCCBuildCommandParserOptionPage.java create mode 100644 build/org.eclipse.cdt.make.ui/src/org/eclipse/cdt/make/internal/ui/scannerconfig/ScannerDiscoveryConsole.java create mode 100644 build/org.eclipse.cdt.managedbuilder.core.tests/tests/org/eclipse/cdt/build/core/scannerconfig/tests/AllSD80Tests.java create mode 100644 build/org.eclipse.cdt.managedbuilder.core.tests/tests/org/eclipse/cdt/build/core/scannerconfig/tests/GCCBuiltinSpecsDetectorTest.java create mode 100644 build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/scannerconfig/AbstractBuiltinSpecsDetector.java create mode 100644 build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/scannerconfig/GCCBuiltinSpecsDetector.java create mode 100644 build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/scannerconfig/MBSLanguageSettingsProvider.java create mode 100644 build/org.eclipse.cdt.managedbuilder.ui/icons/obj16/mbs.gif create mode 100644 build/org.eclipse.cdt.managedbuilder.ui/icons/obj16/search.gif create mode 100644 build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/ui/preferences/BuiltinSpecsDetectorOptionPage.java create mode 100644 core/org.eclipse.cdt.core.tests/misc/org/eclipse/cdt/core/internal/tests/filesystem/ram/MemoryEFSExtensionProvider.java create mode 100644 core/org.eclipse.cdt.core.tests/model/org/eclipse/cdt/core/language/settings/providers/AllLanguageSettingsProvidersTests.java create mode 100644 core/org.eclipse.cdt.core.tests/model/org/eclipse/cdt/core/language/settings/providers/LanguageSettingsExtensionsTests.java create mode 100644 core/org.eclipse.cdt.core.tests/model/org/eclipse/cdt/core/language/settings/providers/LanguageSettingsManagerTests.java create mode 100644 core/org.eclipse.cdt.core.tests/model/org/eclipse/cdt/core/language/settings/providers/LanguageSettingsPersistenceProjectTests.java create mode 100644 core/org.eclipse.cdt.core.tests/model/org/eclipse/cdt/core/language/settings/providers/LanguageSettingsScannerInfoProviderTests.java create mode 100644 core/org.eclipse.cdt.core.tests/model/org/eclipse/cdt/core/language/settings/providers/LanguageSettingsSerializableTests.java create mode 100644 core/org.eclipse.cdt.core.tests/model/org/eclipse/cdt/core/language/settings/providers/MockLanguageSettingsBaseProvider.java create mode 100644 core/org.eclipse.cdt.core.tests/model/org/eclipse/cdt/core/language/settings/providers/MockLanguageSettingsEditableProvider.java create mode 100644 core/org.eclipse.cdt.core.tests/model/org/eclipse/cdt/core/language/settings/providers/MockLanguageSettingsProvider.java create mode 100644 core/org.eclipse.cdt.core.tests/model/org/eclipse/cdt/core/language/settings/providers/MockLanguageSettingsSerializableProvider.java create mode 100644 core/org.eclipse.cdt.core.tests/suite/org/eclipse/cdt/core/testplugin/CModelMock.java create mode 100644 core/org.eclipse.cdt.core/model/org/eclipse/cdt/core/language/settings/providers/ILanguageSettingsProvider.java create mode 100644 core/org.eclipse.cdt.core/model/org/eclipse/cdt/core/language/settings/providers/LanguageSettingsBaseProvider.java create mode 100644 core/org.eclipse.cdt.core/model/org/eclipse/cdt/core/language/settings/providers/LanguageSettingsManager.java create mode 100644 core/org.eclipse.cdt.core/model/org/eclipse/cdt/core/language/settings/providers/LanguageSettingsManager_TBD.java create mode 100644 core/org.eclipse.cdt.core/model/org/eclipse/cdt/core/language/settings/providers/LanguageSettingsSerializable.java create mode 100644 core/org.eclipse.cdt.core/model/org/eclipse/cdt/core/language/settings/providers/LanguageSettingsSerializableEditable.java create mode 100644 core/org.eclipse.cdt.core/model/org/eclipse/cdt/core/settings/model/ILanguageSettingsEditableProvider.java create mode 100644 core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/language/settings/providers/LanguageSettingsExtensionManager.java create mode 100644 core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/language/settings/providers/LanguageSettingsLogger.java create mode 100644 core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/language/settings/providers/LanguageSettingsProvidersSerializer.java create mode 100644 core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/language/settings/providers/LanguageSettingsScannerInfoProvider.java create mode 100644 core/org.eclipse.cdt.core/schema/LanguageSettingsProvider.exsd create mode 100644 core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/AbstractExecutableExtensionBase.java create mode 100644 core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/ICConsoleParser.java create mode 100644 core/org.eclipse.cdt.ui/icons/obj16/frameworks.gif create mode 100644 core/org.eclipse.cdt.ui/icons/obj16/ls_entries.gif create mode 100644 core/org.eclipse.cdt.ui/icons/obj16/ls_entries_provider.gif create mode 100644 core/org.eclipse.cdt.ui/icons/obj16/provider_ls_obj.gif create mode 100644 core/org.eclipse.cdt.ui/icons/obj16/search.gif create mode 100644 core/org.eclipse.cdt.ui/icons/ovr16/cfg_ovr.gif create mode 100644 core/org.eclipse.cdt.ui/icons/ovr16/edited_ov.gif create mode 100644 core/org.eclipse.cdt.ui/icons/ovr16/empty_ovr.png create mode 100644 core/org.eclipse.cdt.ui/icons/ovr16/global_ovr.gif create mode 100644 core/org.eclipse.cdt.ui/icons/ovr16/import_co.gif create mode 100644 core/org.eclipse.cdt.ui/icons/ovr16/link_ovr.gif create mode 100644 core/org.eclipse.cdt.ui/icons/ovr16/lock_ovr.gif create mode 100644 core/org.eclipse.cdt.ui/icons/ovr16/overlay-has-context.gif create mode 100644 core/org.eclipse.cdt.ui/icons/ovr16/project_co.gif create mode 100644 core/org.eclipse.cdt.ui/schema/LanguageSettingsProviderAssociation.exsd create mode 100644 core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/ImageCombo.java create mode 100644 core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/language/settings/providers/AbstractLanguageSettingProviderOptionPage.java create mode 100644 core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/language/settings/providers/LanguageSettingEntryDialog.java create mode 100644 core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/language/settings/providers/LanguageSettingsEntriesTab.java create mode 100644 core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/language/settings/providers/LanguageSettingsProviderAssociation.java create mode 100644 core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/language/settings/providers/LanguageSettingsProviderTab.java create mode 100644 core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/language/settings/providers/LanguageSettingsProvidersLabelProvider.java create mode 100644 core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/language/settings/providers/Page_LanguageSettingsProviders.java create mode 100644 core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/language/settings/providers/UserLanguageSettingsProvider.java create mode 100644 core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/newui/LanguageSettingsImages.java create mode 100644 core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/newui/StatusMessageLine.java create mode 100644 xlc/org.eclipse.cdt.managedbuilder.xlc.core/src/org/eclipse/cdt/managedbuilder/xlc/core/XlcBuiltinSpecsDetector.java diff --git a/build/org.eclipse.cdt.make.core.tests/plugin.xml b/build/org.eclipse.cdt.make.core.tests/plugin.xml new file mode 100644 index 00000000000..f0a7adef70f --- /dev/null +++ b/build/org.eclipse.cdt.make.core.tests/plugin.xml @@ -0,0 +1,14 @@ + + + + + + + + diff --git a/build/org.eclipse.cdt.make.core.tests/src/org/eclipse/cdt/make/scannerdiscovery/AllSD80Tests.java b/build/org.eclipse.cdt.make.core.tests/src/org/eclipse/cdt/make/scannerdiscovery/AllSD80Tests.java new file mode 100644 index 00000000000..f4b900a04c7 --- /dev/null +++ b/build/org.eclipse.cdt.make.core.tests/src/org/eclipse/cdt/make/scannerdiscovery/AllSD80Tests.java @@ -0,0 +1,26 @@ +/******************************************************************************* + * Copyright (c) 2010, 2011 Andrew Gvozdev 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: + * Andrew Gvozdev - initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.make.scannerdiscovery; + +import junit.framework.TestSuite; + +public class AllSD80Tests extends TestSuite { + + public static TestSuite suite() { + return new AllSD80Tests(); + } + + public AllSD80Tests() { + super(AllSD80Tests.class.getName()); + + addTestSuite(GCCBuildCommandParserTest.class); + } +} diff --git a/build/org.eclipse.cdt.make.core.tests/src/org/eclipse/cdt/make/scannerdiscovery/GCCBuildCommandParserTest.java b/build/org.eclipse.cdt.make.core.tests/src/org/eclipse/cdt/make/scannerdiscovery/GCCBuildCommandParserTest.java new file mode 100644 index 00000000000..1f71546aaca --- /dev/null +++ b/build/org.eclipse.cdt.make.core.tests/src/org/eclipse/cdt/make/scannerdiscovery/GCCBuildCommandParserTest.java @@ -0,0 +1,1904 @@ +/******************************************************************************* + * Copyright (c) 2009, 2011 Andrew Gvozdev 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: + * Andrew Gvozdev - initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.make.scannerdiscovery; + +import java.net.URI; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import junit.framework.TestCase; + +import org.eclipse.cdt.core.ErrorParserManager; +import org.eclipse.cdt.core.language.settings.providers.LanguageSettingsManager; +import org.eclipse.cdt.core.model.CoreModel; +import org.eclipse.cdt.core.settings.model.CIncludeFileEntry; +import org.eclipse.cdt.core.settings.model.CIncludePathEntry; +import org.eclipse.cdt.core.settings.model.CLibraryFileEntry; +import org.eclipse.cdt.core.settings.model.CLibraryPathEntry; +import org.eclipse.cdt.core.settings.model.CMacroEntry; +import org.eclipse.cdt.core.settings.model.CMacroFileEntry; +import org.eclipse.cdt.core.settings.model.ICConfigurationDescription; +import org.eclipse.cdt.core.settings.model.ICLanguageSetting; +import org.eclipse.cdt.core.settings.model.ICLanguageSettingEntry; +import org.eclipse.cdt.core.settings.model.ICProjectDescription; +import org.eclipse.cdt.core.settings.model.ICProjectDescriptionManager; +import org.eclipse.cdt.core.settings.model.ICSettingEntry; +import org.eclipse.cdt.core.testplugin.ResourceHelper; +import org.eclipse.cdt.internal.core.XmlUtil; +import org.eclipse.cdt.internal.core.settings.model.CProjectDescriptionManager; +import org.eclipse.cdt.make.core.scannerconfig.AbstractBuildCommandParser; +import org.eclipse.cdt.make.core.scannerconfig.GCCBuildCommandParser; +import org.eclipse.cdt.make.core.scannerconfig.ILanguageSettingsBuildOutputScanner; +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IFolder; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.Path; +import org.eclipse.core.runtime.Platform; +import org.eclipse.core.runtime.content.IContentType; +import org.eclipse.core.runtime.content.IContentTypeManager; +import org.eclipse.core.runtime.content.IContentTypeSettings; +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +public class GCCBuildCommandParserTest extends TestCase { + // ID of the parser taken from the extension point + private static final String GCC_BUILD_COMMAND_PARSER_EXT = "org.eclipse.cdt.make.core.build.command.parser.gcc"; //$NON-NLS-1$ + + private static final String ELEM_TEST = "test"; + private static final String LANG_CPP = "org.eclipse.cdt.core.g++"; + + // those attributes must match that in AbstractBuiltinSpecsDetector + private static final String ATTR_EXPAND_RELATIVE_PATHS = "expand-relative-paths"; //$NON-NLS-1$ + + private class MockBuildCommandParser extends AbstractBuildCommandParser implements Cloneable { + @Override + protected AbstractOptionParser[] getOptionParsers() { + return new AbstractOptionParser[] {}; + } + @Override + public MockBuildCommandParser cloneShallow() throws CloneNotSupportedException { + return (MockBuildCommandParser) super.cloneShallow(); + } + @Override + public MockBuildCommandParser clone() throws CloneNotSupportedException { + return (MockBuildCommandParser) super.clone(); + } + } + + @Override + protected void setUp() throws Exception { + } + + @Override + protected void tearDown() throws Exception { + ResourceHelper.cleanUp(); + } + + private ICConfigurationDescription[] getConfigurationDescriptions(IProject project) { + CoreModel coreModel = CoreModel.getDefault(); + ICProjectDescriptionManager mngr = coreModel.getProjectDescriptionManager(); + // project description + ICProjectDescription projectDescription = mngr.getProjectDescription(project); + assertNotNull(projectDescription); + assertEquals(1, projectDescription.getConfigurations().length); + // configuration description + ICConfigurationDescription[] cfgDescriptions = projectDescription.getConfigurations(); + return cfgDescriptions; + } + + /** + * Sets build working directory for DefaultSettingConfiguration being tested. + */ + private void setBuilderCWD(IProject project, IPath buildCWD) throws CoreException { + CProjectDescriptionManager manager = CProjectDescriptionManager.getInstance(); + { + ICProjectDescription prjDescription = manager.getProjectDescription(project, true); + assertNotNull(prjDescription); + ICConfigurationDescription cfgDescription = prjDescription.getDefaultSettingConfiguration(); + assertNotNull(cfgDescription); + + cfgDescription.getBuildSetting().setBuilderCWD(buildCWD); + manager.setProjectDescription(project, prjDescription); + // doublecheck builderCWD + IPath actualBuildCWD = cfgDescription.getBuildSetting().getBuilderCWD(); + assertEquals(buildCWD, actualBuildCWD); + } + { + // triplecheck builderCWD for different project/configuration descriptions + ICProjectDescription prjDescription = CProjectDescriptionManager.getInstance().getProjectDescription(project, false); + assertNotNull(prjDescription); + ICConfigurationDescription cfgDescription = prjDescription.getDefaultSettingConfiguration(); + assertNotNull(cfgDescription); + + } + } + + private void setReference(IProject project, final IProject projectReferenced) throws CoreException { + { + CoreModel coreModel = CoreModel.getDefault(); + ICProjectDescriptionManager mngr = coreModel.getProjectDescriptionManager(); + // project description + ICProjectDescription projectDescription = mngr.getProjectDescription(project); + assertNotNull(projectDescription); + assertEquals(1, projectDescription.getConfigurations().length); + // configuration description + ICConfigurationDescription[] cfgDescriptions = projectDescription.getConfigurations(); + ICConfigurationDescription cfgDescription = cfgDescriptions[0]; + + final ICConfigurationDescription cfgDescriptionReferenced = getConfigurationDescriptions(projectReferenced)[0]; + cfgDescription.setReferenceInfo(new HashMap() {{ put(projectReferenced.getName(), cfgDescriptionReferenced.getId()); }}); + coreModel.setProjectDescription(project, projectDescription); + } + + { + // doublecheck that it's set as expected + ICConfigurationDescription[] cfgDescriptions = getConfigurationDescriptions(project); + ICConfigurationDescription cfgDescription = cfgDescriptions[0]; + Map refs = cfgDescription.getReferenceInfo(); + assertEquals(1, refs.size()); + Set referencedProjectsNames = new LinkedHashSet(refs.keySet()); + assertEquals(projectReferenced.getName(), referencedProjectsNames.toArray()[0]); + } + + } + + + public void testAbstractBuildCommandParser_CloneAndEquals() throws Exception { + // create instance to compare to + MockBuildCommandParser parser = new MockBuildCommandParser(); + assertEquals(true, parser.isResolvingPaths()); + + // check clone after initialization + MockBuildCommandParser clone0 = parser.clone(); + assertTrue(parser.equals(clone0)); + + // configure provider + parser.setResolvingPaths(false); + assertFalse(parser.equals(clone0)); + + // check another clone after configuring + { + MockBuildCommandParser clone = parser.clone(); + assertTrue(parser.equals(clone)); + } + + // check 'expand relative paths' flag + { + MockBuildCommandParser clone = parser.clone(); + boolean expandRelativePaths = clone.isResolvingPaths(); + clone.setResolvingPaths( ! expandRelativePaths ); + assertFalse(parser.equals(clone)); + } + + // check cloneShallow() + { + MockBuildCommandParser parser2 = parser.clone(); + MockBuildCommandParser clone = parser2.cloneShallow(); + assertTrue(parser2.equals(clone)); + } + + } + + public void testAbstractBuildCommandParser_Serialize() throws Exception { + { + // create empty XML + Document doc = XmlUtil.newDocument(); + Element rootElement = XmlUtil.appendElement(doc, ELEM_TEST); + + // load it to new provider + MockBuildCommandParser parser = new MockBuildCommandParser(); + parser.load(rootElement); + assertEquals(true, parser.isResolvingPaths()); + } + + Element elementProvider; + { + // define mock parser + MockBuildCommandParser parser = new MockBuildCommandParser(); + assertEquals(true, parser.isResolvingPaths()); + + // redefine the settings + parser.setResolvingPaths(false); + assertEquals(false, parser.isResolvingPaths()); + + // serialize in XML + Document doc = XmlUtil.newDocument(); + Element rootElement = XmlUtil.appendElement(doc, ELEM_TEST); + elementProvider = parser.serialize(rootElement); + String xmlString = XmlUtil.toString(doc); + + assertTrue(xmlString.contains(ATTR_EXPAND_RELATIVE_PATHS)); + } + { + // create another instance of the provider + MockBuildCommandParser parser = new MockBuildCommandParser(); + assertEquals(true, parser.isResolvingPaths()); + + // load element + parser.load(elementProvider); + assertEquals(false, parser.isResolvingPaths()); + } + } + + public void testAbstractBuildCommandParser_Nulls() throws Exception { + MockBuildCommandParser parser = new MockBuildCommandParser(); + parser.startup(null); + parser.processLine(null); + parser.shutdown(); + + List entries = parser.getSettingEntries(null, null, null); + assertNull(entries); + } + + public void testAbstractBuildCommandParser_Basic() throws Exception { + // Create model project and accompanied descriptions + String projectName = getName(); + IProject project = ResourceHelper.createCDTProjectWithConfig(projectName); + ICConfigurationDescription[] cfgDescriptions = getConfigurationDescriptions(project); + ICConfigurationDescription cfgDescription = cfgDescriptions[0]; + + final IFile file=ResourceHelper.createFile(project, "file.cpp"); + + // create test class + ILanguageSettingsBuildOutputScanner parser = new MockBuildCommandParser() { + @Override + public boolean processLine(String line, ErrorParserManager epm) { + // pretending that we parsed the line + currentResource = file; + List entries = new ArrayList(); + ICLanguageSettingEntry entry = new CMacroEntry("MACRO", "VALUE", ICSettingEntry.BUILTIN); + entries.add(entry); + setSettingEntries(entries); + return true; + } + }; + // parse line + parser.startup(cfgDescription); + parser.processLine("gcc -DMACRO=VALUE file.cpp"); + parser.shutdown(); + + // sanity check that it does not return same values for all inputs + List noentries = parser.getSettingEntries(null, null, null); + assertNull(noentries); + + // check populated entries + ICLanguageSetting ls = cfgDescription.getLanguageSettingForFile(file.getProjectRelativePath(), true); + String languageId = ls.getLanguageId(); + + List entries = parser.getSettingEntries(cfgDescription, file, languageId); + CMacroEntry expected = new CMacroEntry("MACRO", "VALUE", ICSettingEntry.BUILTIN); + assertEquals(expected, entries.get(0)); + } + +// public void testGCCBuildCommandParser_Nulls() throws Exception { +// GCCBuildCommandParser parser = (GCCBuildCommandParser) LanguageSettingsManager.getExtensionProviderCopy(GCC_BUILD_COMMAND_PARSER_EXT); +// parser.startup(null); +// parser.processLine(null); +// parser.shutdown(); +// +// List entries = parser.getSettingEntries(null, null, null); +// assertNull(entries); +// } + + /** + */ + public void testOneEntry() throws Exception { + // Create model project and accompanied descriptions + String projectName = getName(); + IProject project = ResourceHelper.createCDTProjectWithConfig(projectName); + ICConfigurationDescription[] cfgDescriptions = getConfigurationDescriptions(project); + ICConfigurationDescription cfgDescription = cfgDescriptions[0]; + + IFile file=ResourceHelper.createFile(project, "file.cpp"); + ICLanguageSetting ls = cfgDescription.getLanguageSettingForFile(file.getProjectRelativePath(), true); + String languageId = ls.getLanguageId(); + + // create GCCBuildCommandParser + GCCBuildCommandParser parser = (GCCBuildCommandParser) LanguageSettingsManager.getExtensionProviderCopy(GCC_BUILD_COMMAND_PARSER_EXT); + + // parse line + parser.startup(cfgDescription); + parser.processLine("gcc -I/path0 file.cpp"); + parser.shutdown(); + + // check populated entries + List entries = parser.getSettingEntries(cfgDescription, file, languageId); + { + IPath path = new Path("/path0").setDevice(project.getLocation().getDevice()); + CIncludePathEntry expected = new CIncludePathEntry(path, 0); + CIncludePathEntry entry = (CIncludePathEntry)entries.get(0); + assertEquals(expected.getName(), entry.getName()); + assertEquals(expected.getValue(), entry.getValue()); + assertEquals(expected.getKind(), entry.getKind()); + assertEquals(expected.getFlags(), entry.getFlags()); + assertEquals(expected, entry); + } + } + + /** + */ + public void testGccFlavors() throws Exception { + // Create model project and accompanied descriptions + String projectName = getName(); + IProject project = ResourceHelper.createCDTProjectWithConfig(projectName); + ICConfigurationDescription[] cfgDescriptions = getConfigurationDescriptions(project); + ICConfigurationDescription cfgDescription = cfgDescriptions[0]; + + IFile file1=ResourceHelper.createFile(project, "file1.cpp"); + IFile file2=ResourceHelper.createFile(project, "file2.cpp"); + IFile file3=ResourceHelper.createFile(project, "file3.cpp"); + IFile file4=ResourceHelper.createFile(project, "file4.cpp"); + IFile file5=ResourceHelper.createFile(project, "file5.cpp"); + ICLanguageSetting ls = cfgDescription.getLanguageSettingForFile(file1.getProjectRelativePath(), true); + String languageId = ls.getLanguageId(); + + // create GCCBuildCommandParser + GCCBuildCommandParser parser = (GCCBuildCommandParser) LanguageSettingsManager.getExtensionProviderCopy(GCC_BUILD_COMMAND_PARSER_EXT); + + // parse line + parser.startup(cfgDescription); + parser.processLine("gcc -I/path0 file1.cpp"); + parser.processLine("gcc-4.2 -I/path0 file2.cpp"); + parser.processLine("g++ -I/path0 file3.cpp"); + parser.processLine("c++ -I/path0 file4.cpp"); + parser.processLine("\"gcc\" -I/path0 file5.cpp"); + parser.shutdown(); + + // check populated entries + IPath path0 = new Path("/path0").setDevice(project.getLocation().getDevice()); + { + List entries = parser.getSettingEntries(cfgDescription, file1, languageId); + assertEquals(new CIncludePathEntry(path0, 0), entries.get(0)); + } + { + List entries = parser.getSettingEntries(cfgDescription, file2, languageId); + assertEquals(new CIncludePathEntry(path0, 0), entries.get(0)); + } + { + List entries = parser.getSettingEntries(cfgDescription, file3, languageId); + assertEquals(new CIncludePathEntry(path0, 0), entries.get(0)); + } + { + List entries = parser.getSettingEntries(cfgDescription, file4, languageId); + assertEquals(new CIncludePathEntry(path0, 0), entries.get(0)); + } + { + List entries = parser.getSettingEntries(cfgDescription, file5, languageId); + assertEquals(new CIncludePathEntry(path0, 0), entries.get(0)); + } + } + + /** + */ + public void testCIncludePathEntry() throws Exception { + // Create model project and accompanied descriptions + String projectName = getName(); + IProject project = ResourceHelper.createCDTProjectWithConfig(projectName); + ICConfigurationDescription[] cfgDescriptions = getConfigurationDescriptions(project); + ICConfigurationDescription cfgDescription = cfgDescriptions[0]; + + IFile file=ResourceHelper.createFile(project, "file.cpp"); + ICLanguageSetting ls = cfgDescription.getLanguageSettingForFile(file.getProjectRelativePath(), true); + String languageId = ls.getLanguageId(); + + // create GCCBuildCommandParser + GCCBuildCommandParser parser = (GCCBuildCommandParser) LanguageSettingsManager.getExtensionProviderCopy(GCC_BUILD_COMMAND_PARSER_EXT); + + // parse line + parser.startup(cfgDescription); + parser.processLine("gcc" + // regular + + " -I/path0 " + // space after -I + + " -I /path1 " + // unknown option, should be ignored + + " -? " + // double-quoted path with spaces + + " -I\"/path with spaces\"" + // single-quoted path with spaces + + " -I'/path with spaces2'" + // second single-quoted and space after -I + + " -I '/path with spaces3'" + + " file.cpp"); + parser.shutdown(); + + // check populated entries + List entries = parser.getSettingEntries(cfgDescription, file, languageId); + { + IPath path = new Path("/path0").setDevice(project.getLocation().getDevice()); + CIncludePathEntry expected = new CIncludePathEntry(path, 0); + CIncludePathEntry entry = (CIncludePathEntry)entries.get(0); + assertEquals(expected.getName(), entry.getName()); + assertEquals(expected.getValue(), entry.getValue()); + assertEquals(expected.getKind(), entry.getKind()); + assertEquals(expected.getFlags(), entry.getFlags()); + assertEquals(expected, entry); + } + { + IPath path = new Path("/path1").setDevice(project.getLocation().getDevice()); + CIncludePathEntry expected = new CIncludePathEntry(path, 0); + CIncludePathEntry entry = (CIncludePathEntry)entries.get(1); + assertEquals(expected, entry); + } + { + IPath path = new Path("/path with spaces").setDevice(project.getLocation().getDevice()); + CIncludePathEntry expected = new CIncludePathEntry(path, 0); + CIncludePathEntry entry = (CIncludePathEntry)entries.get(2); + assertEquals(expected, entry); + } + { + IPath path = new Path("/path with spaces2").setDevice(project.getLocation().getDevice()); + CIncludePathEntry expected = new CIncludePathEntry(path, 0); + CIncludePathEntry entry = (CIncludePathEntry)entries.get(3); + assertEquals(expected, entry); + } + { + IPath path = new Path("/path with spaces3").setDevice(project.getLocation().getDevice()); + CIncludePathEntry expected = new CIncludePathEntry(path, 0); + CIncludePathEntry entry = (CIncludePathEntry)entries.get(4); + assertEquals(expected, entry); + } + } + + /** + */ + public void testCMacroEntry() throws Exception { + // Create model project and accompanied descriptions + String projectName = getName(); + IProject project = ResourceHelper.createCDTProjectWithConfig(projectName); + ICConfigurationDescription[] cfgDescriptions = getConfigurationDescriptions(project); + ICConfigurationDescription cfgDescription = cfgDescriptions[0]; + + IFile file=ResourceHelper.createFile(project, "file.cpp"); + ICLanguageSetting ls = cfgDescription.getLanguageSettingForFile(file.getProjectRelativePath(), true); + String languageId = ls.getLanguageId(); + + // create GCCBuildCommandParser + GCCBuildCommandParser parser = (GCCBuildCommandParser) LanguageSettingsManager.getExtensionProviderCopy(GCC_BUILD_COMMAND_PARSER_EXT); + + // parse line + parser.startup(cfgDescription); + parser.processLine("gcc " + + " -DMACRO0" + + " -DMACRO1=value" + + " -DMACRO2=\"value with spaces\"" + + " -DMACRO3='value with spaces'" + + " -DMACRO4='\"quoted value\"'" + + " -D'MACRO5=\"quoted value\"'" + + " -DMACRO6=\\\"escape-quoted value\\\"" + + " -DMACRO7=\"'single-quoted value'\"" + + " file.cpp"); + parser.shutdown(); + + // check populated entries + List entries = parser.getSettingEntries(cfgDescription, file, languageId); + { + CMacroEntry expected = new CMacroEntry("MACRO0", "", 0); + CMacroEntry entry = (CMacroEntry)entries.get(0); + assertEquals(expected.getName(), entry.getName()); + assertEquals(expected.getValue(), entry.getValue()); + assertEquals(expected.getKind(), entry.getKind()); + assertEquals(expected.getFlags(), entry.getFlags()); + assertEquals(expected, entry); + } + { + CMacroEntry expected = new CMacroEntry("MACRO1", "value", 0); + CMacroEntry entry = (CMacroEntry)entries.get(1); + assertEquals(expected, entry); + } + { + CMacroEntry expected = new CMacroEntry("MACRO2", "value with spaces", 0); + CMacroEntry entry = (CMacroEntry)entries.get(2); + assertEquals(expected, entry); + } + { + CMacroEntry expected = new CMacroEntry("MACRO3", "value with spaces", 0); + CMacroEntry entry = (CMacroEntry)entries.get(3); + assertEquals(expected, entry); + } + { + CMacroEntry expected = new CMacroEntry("MACRO4", "\"quoted value\"", 0); + CMacroEntry entry = (CMacroEntry)entries.get(4); + assertEquals(expected, entry); + } + { + CMacroEntry expected = new CMacroEntry("MACRO5", "\"quoted value\"", 0); + CMacroEntry entry = (CMacroEntry)entries.get(5); + assertEquals(expected, entry); + } + { + CMacroEntry expected = new CMacroEntry("MACRO6", "\"escape-quoted value\"", 0); + CMacroEntry entry = (CMacroEntry)entries.get(6); + assertEquals(expected, entry); + } + { + CMacroEntry expected = new CMacroEntry("MACRO7", "'single-quoted value'", 0); + CMacroEntry entry = (CMacroEntry)entries.get(7); + assertEquals(expected, entry); + } + } + + /** + */ + public void testCMacroEntry_undef() throws Exception { + // Create model project and accompanied descriptions + String projectName = getName(); + IProject project = ResourceHelper.createCDTProjectWithConfig(projectName); + ICConfigurationDescription[] cfgDescriptions = getConfigurationDescriptions(project); + ICConfigurationDescription cfgDescription = cfgDescriptions[0]; + + IFile file=ResourceHelper.createFile(project, "file.cpp"); + ICLanguageSetting ls = cfgDescription.getLanguageSettingForFile(file.getProjectRelativePath(), true); + String languageId = ls.getLanguageId(); + + // create GCCBuildCommandParser + GCCBuildCommandParser parser = (GCCBuildCommandParser) LanguageSettingsManager.getExtensionProviderCopy(GCC_BUILD_COMMAND_PARSER_EXT); + + // parse line + parser.startup(cfgDescription); + parser.processLine("gcc " + + " -UMACRO" + + " file.cpp"); + parser.shutdown(); + + // check populated entries + List entries = parser.getSettingEntries(cfgDescription, file, languageId); + { + assertEquals(new CMacroEntry("MACRO", null, ICSettingEntry.UNDEFINED), entries.get(0)); + } + } + + /** + */ + public void testCIncludeFileEntry() throws Exception { + // Create model project and accompanied descriptions + String projectName = getName(); + IProject project = ResourceHelper.createCDTProjectWithConfig(projectName); + ICConfigurationDescription[] cfgDescriptions = getConfigurationDescriptions(project); + ICConfigurationDescription cfgDescription = cfgDescriptions[0]; + + IFile file=ResourceHelper.createFile(project, "file.cpp"); + ICLanguageSetting ls = cfgDescription.getLanguageSettingForFile(file.getProjectRelativePath(), true); + String languageId = ls.getLanguageId(); + + // create GCCBuildCommandParser + GCCBuildCommandParser parser = (GCCBuildCommandParser) LanguageSettingsManager.getExtensionProviderCopy(GCC_BUILD_COMMAND_PARSER_EXT); + + // parse line + parser.startup(cfgDescription); + parser.processLine("gcc " + + " -include /include.file1" + + " -include '/include.file with spaces'" + + " -include ../../include.file2" + + " -include include.file3" + + " -include ../../include-file-with-dashes" + + " file.cpp"); + parser.shutdown(); + + // check populated entries + List entries = parser.getSettingEntries(cfgDescription, file, languageId); + { + IPath incFile = new Path("/include.file1").setDevice(project.getLocation().getDevice()); + CIncludeFileEntry expected = new CIncludeFileEntry(incFile, 0); + CIncludeFileEntry entry = (CIncludeFileEntry)entries.get(0); + assertEquals(expected.getName(), entry.getName()); + assertEquals(expected.getValue(), entry.getValue()); + assertEquals(expected.getKind(), entry.getKind()); + assertEquals(expected.getFlags(), entry.getFlags()); + assertEquals(expected, entry); + } + + { + IPath incFile = new Path("/include.file with spaces").setDevice(project.getLocation().getDevice()); + assertEquals(new CIncludeFileEntry(incFile, 0), entries.get(1)); + } + { + assertEquals(new CIncludeFileEntry(project.getLocation().removeLastSegments(2).append("include.file2"), 0), entries.get(2)); + assertEquals(new CIncludeFileEntry(project.getFullPath().append("include.file3"), ICSettingEntry.VALUE_WORKSPACE_PATH | ICSettingEntry.RESOLVED), entries.get(3)); + assertEquals(new CIncludeFileEntry(project.getLocation().removeLastSegments(2).append("include-file-with-dashes"), 0), entries.get(4)); + } + } + + /** + */ + public void testCMacroFileEntry() throws Exception { + // Create model project and accompanied descriptions + String projectName = getName(); + IProject project = ResourceHelper.createCDTProjectWithConfig(projectName); + ICConfigurationDescription[] cfgDescriptions = getConfigurationDescriptions(project); + ICConfigurationDescription cfgDescription = cfgDescriptions[0]; + + IFile file=ResourceHelper.createFile(project, "file.cpp"); + ICLanguageSetting ls = cfgDescription.getLanguageSettingForFile(file.getProjectRelativePath(), true); + String languageId = ls.getLanguageId(); + + // create GCCBuildCommandParser + GCCBuildCommandParser parser = (GCCBuildCommandParser) LanguageSettingsManager.getExtensionProviderCopy(GCC_BUILD_COMMAND_PARSER_EXT); + + // parse line + parser.startup(cfgDescription); + parser.processLine("gcc -macros macro.file file.cpp"); + parser.processLine("gcc " + + " -macros /macro.file" + + " -macros '/macro.file with spaces'" + + " file.cpp"); + parser.shutdown(); + + // check populated entries + List entries = parser.getSettingEntries(cfgDescription, file, languageId); + { + IPath path = new Path("/macro.file").setDevice(project.getLocation().getDevice()); + CMacroFileEntry expected = new CMacroFileEntry(path, 0); + CMacroFileEntry entry = (CMacroFileEntry)entries.get(0); + assertEquals(expected.getName(), entry.getName()); + assertEquals(expected.getValue(), entry.getValue()); + assertEquals(expected.getKind(), entry.getKind()); + assertEquals(expected.getFlags(), entry.getFlags()); + assertEquals(expected, entry); + } + { + IPath path = new Path("/macro.file with spaces").setDevice(project.getLocation().getDevice()); + CMacroFileEntry expected = new CMacroFileEntry(path, 0); + CMacroFileEntry entry = (CMacroFileEntry)entries.get(1); + assertEquals(expected, entry); + } + } + + /** + */ + public void testCLibraryPathEntry() throws Exception { + // Create model project and accompanied descriptions + String projectName = getName(); + IProject project = ResourceHelper.createCDTProjectWithConfig(projectName); + ICConfigurationDescription[] cfgDescriptions = getConfigurationDescriptions(project); + ICConfigurationDescription cfgDescription = cfgDescriptions[0]; + + IFile file=ResourceHelper.createFile(project, "file.cpp"); + ICLanguageSetting ls = cfgDescription.getLanguageSettingForFile(file.getProjectRelativePath(), true); + String languageId = ls.getLanguageId(); + + // create GCCBuildCommandParser + GCCBuildCommandParser parser = (GCCBuildCommandParser) LanguageSettingsManager.getExtensionProviderCopy(GCC_BUILD_COMMAND_PARSER_EXT); + + // parse line + parser.startup(cfgDescription); + parser.processLine("gcc " + + " -L/path0" + + " -L'/path with spaces'" + + " file.cpp"); + parser.shutdown(); + + // check populated entries + List entries = parser.getSettingEntries(cfgDescription, file, languageId); + { + IPath path = new Path("/path0").setDevice(project.getLocation().getDevice()); + CLibraryPathEntry expected = new CLibraryPathEntry(path, 0); + CLibraryPathEntry entry = (CLibraryPathEntry)entries.get(0); + assertEquals(expected.getName(), entry.getName()); + assertEquals(expected.getValue(), entry.getValue()); + assertEquals(expected.getKind(), entry.getKind()); + assertEquals(expected.getFlags(), entry.getFlags()); + assertEquals(expected, entry); + } + { + IPath path = new Path("/path with spaces").setDevice(project.getLocation().getDevice()); + CLibraryPathEntry expected = new CLibraryPathEntry(path, 0); + CLibraryPathEntry entry = (CLibraryPathEntry)entries.get(1); + assertEquals(expected, entry); + } + } + + /** + */ + public void testCLibraryFileEntry() throws Exception { + // Create model project and accompanied descriptions + String projectName = getName(); + IProject project = ResourceHelper.createCDTProjectWithConfig(projectName); + ICConfigurationDescription[] cfgDescriptions = getConfigurationDescriptions(project); + ICConfigurationDescription cfgDescription = cfgDescriptions[0]; + + IFile file=ResourceHelper.createFile(project, "file.cpp"); + ICLanguageSetting ls = cfgDescription.getLanguageSettingForFile(file.getProjectRelativePath(), true); + String languageId = ls.getLanguageId(); + + // create GCCBuildCommandParser + GCCBuildCommandParser parser = (GCCBuildCommandParser) LanguageSettingsManager.getExtensionProviderCopy(GCC_BUILD_COMMAND_PARSER_EXT); + + // parse line + parser.startup(cfgDescription); + parser.processLine("gcc -ldomain file.cpp"); + parser.shutdown(); + + // check populated entries + List entries = parser.getSettingEntries(cfgDescription, file, languageId); + CLibraryFileEntry expected = new CLibraryFileEntry("libdomain.a", 0); + CLibraryFileEntry entry = (CLibraryFileEntry) entries.get(0); + assertEquals(expected.getName(), entry.getName()); + assertEquals(expected.getValue(), entry.getValue()); + assertEquals(expected.getKind(), entry.getKind()); + assertEquals(expected.getFlags(), entry.getFlags()); + assertEquals(expected, entry); + } + + /** + */ + public void testMixedSettingEntries() throws Exception { + // Create model project and accompanied descriptions + String projectName = getName(); + IProject project = ResourceHelper.createCDTProjectWithConfig(projectName); + ICConfigurationDescription[] cfgDescriptions = getConfigurationDescriptions(project); + ICConfigurationDescription cfgDescription = cfgDescriptions[0]; + + IFile file=ResourceHelper.createFile(project, "file.cpp"); + ICLanguageSetting ls = cfgDescription.getLanguageSettingForFile(file.getProjectRelativePath(), true); + String languageId = ls.getLanguageId(); + + // create GCCBuildCommandParser + GCCBuildCommandParser parser = (GCCBuildCommandParser) LanguageSettingsManager.getExtensionProviderCopy(GCC_BUILD_COMMAND_PARSER_EXT); + + // parse line + parser.startup(cfgDescription); + parser.processLine("gcc" + + " -I/path0 " + + " -DMACRO1=value" + + " -v" + + " -ldomain" + + " -E" + + " -I /path1 " + + " -DMACRO2=\"value with spaces\"" + + " -I\"/path with spaces\"" + + " -o file.exe" + + " -L/usr/lib" + + " file.cpp" + + " -mtune=pentiumpro" + ); + parser.shutdown(); + + // check populated entries + List entries = parser.getSettingEntries(cfgDescription, file, languageId); +// + " -I/path0 " + { + IPath path = new Path("/path0").setDevice(project.getLocation().getDevice()); + CIncludePathEntry expected = new CIncludePathEntry(path, 0); + assertEquals(expected, entries.get(0)); + } +// + " -DMACRO1=value" + { + CMacroEntry expected = new CMacroEntry("MACRO1", "value", 0); + assertEquals(expected, entries.get(1)); + } +// + " -ldomain" + { + CLibraryFileEntry expected = new CLibraryFileEntry("libdomain.a", 0); + assertEquals(expected, entries.get(2)); + } +// + " -I /path1 " + { + IPath path = new Path("/path1").setDevice(project.getLocation().getDevice()); + CIncludePathEntry expected = new CIncludePathEntry(path, 0); + assertEquals(expected, entries.get(3)); + } +// + " -DMACRO2=\"value with spaces\"" + { + CMacroEntry expected = new CMacroEntry("MACRO2", "value with spaces", 0); + assertEquals(expected, entries.get(4)); + } +// + " -I\"/path with spaces\"" + { + IPath path = new Path("/path with spaces").setDevice(project.getLocation().getDevice()); + CIncludePathEntry expected = new CIncludePathEntry(path, 0); + assertEquals(expected, entries.get(5)); + } +// + " -L/usr/lib" + { + IPath path = new Path("/usr/lib").setDevice(project.getLocation().getDevice()); + CLibraryPathEntry expected = new CLibraryPathEntry(path, 0); + assertEquals(expected, entries.get(6)); + } + + assertEquals(7, entries.size()); + } + + /** + */ + public void testFileMissing() throws Exception { + // Create model project and accompanied descriptions + String projectName = getName(); + IProject project = ResourceHelper.createCDTProjectWithConfig(projectName); + ICConfigurationDescription[] cfgDescriptions = getConfigurationDescriptions(project); + ICConfigurationDescription cfgDescription = cfgDescriptions[0]; + + // create GCCBuildCommandParser + GCCBuildCommandParser parser = (GCCBuildCommandParser) LanguageSettingsManager.getExtensionProviderCopy(GCC_BUILD_COMMAND_PARSER_EXT); + + // parse line + parser.startup(cfgDescription); + parser.processLine("gcc -I/path0 missing.cpp"); + parser.shutdown(); + + // check entries + assertTrue(parser.isEmpty()); + } + + /** + */ + public void testFileAbsolutePath() throws Exception { + // Create model project and accompanied descriptions + String projectName = getName(); + IProject project = ResourceHelper.createCDTProjectWithConfig(projectName); + IFile file=ResourceHelper.createFile(project, "file.cpp"); + ICConfigurationDescription[] cfgDescriptions = getConfigurationDescriptions(project); + ICConfigurationDescription cfgDescription = cfgDescriptions[0]; + + ICLanguageSetting ls = cfgDescription.getLanguageSettingForFile(file.getProjectRelativePath(), true); + String languageId = ls.getLanguageId(); + + // create GCCBuildCommandParser + GCCBuildCommandParser parser = (GCCBuildCommandParser) LanguageSettingsManager.getExtensionProviderCopy(GCC_BUILD_COMMAND_PARSER_EXT); + + // parse line + parser.startup(cfgDescription); + parser.processLine("gcc " + + "-I/path0 " + + "-I. " + + file.getLocation().toOSString()); + parser.shutdown(); + + // check entries + IPath path0 = new Path("/path0").setDevice(project.getLocation().getDevice()); + { + List entries = parser.getSettingEntries(cfgDescription, file, languageId); + assertEquals(new CIncludePathEntry(path0, 0), entries.get(0)); + assertEquals(new CIncludePathEntry(project.getFullPath(), ICSettingEntry.VALUE_WORKSPACE_PATH | ICSettingEntry.RESOLVED), entries.get(1)); + } + } + + /** + */ + public void testFileAbsolutePath_NoProject() throws Exception { + // Create model project and accompanied descriptions + String projectName = getName(); + IProject project = ResourceHelper.createCDTProjectWithConfig(projectName); + IFile file=ResourceHelper.createFile(project, "file.cpp"); + ICConfigurationDescription[] cfgDescriptions = getConfigurationDescriptions(project); + ICConfigurationDescription cfgDescription = cfgDescriptions[0]; + + ICLanguageSetting ls = cfgDescription.getLanguageSettingForFile(file.getProjectRelativePath(), true); + String languageId = ls.getLanguageId(); + + // create GCCBuildCommandParser + GCCBuildCommandParser parser = (GCCBuildCommandParser) LanguageSettingsManager.getExtensionProviderCopy(GCC_BUILD_COMMAND_PARSER_EXT); + + // parse line + parser.startup(null); + parser.processLine("gcc " + + "-I/path0 " + + "-I. " + + file.getLocation().toOSString()); + parser.shutdown(); + + // check entries + IPath path0 = new Path("/path0").setDevice(project.getLocation().getDevice()); + { + List entries = parser.getSettingEntries(null, file, languageId); + assertEquals(new CIncludePathEntry(path0, 0), entries.get(0)); + assertEquals(new CIncludePathEntry(file.getParent().getFullPath(), ICSettingEntry.VALUE_WORKSPACE_PATH | ICSettingEntry.RESOLVED), entries.get(1)); + } + } + + /** + */ + public void testFileWithSpaces() throws Exception { + // Create model project and accompanied descriptions + String projectName = getName(); + IProject project = ResourceHelper.createCDTProjectWithConfig(projectName); + ICConfigurationDescription[] cfgDescriptions = getConfigurationDescriptions(project); + ICConfigurationDescription cfgDescription = cfgDescriptions[0]; + + IFile file1=ResourceHelper.createFile(project, "file with spaces 1.cpp"); + IFile file2=ResourceHelper.createFile(project, "file with spaces 2.cpp"); + IFile file3=ResourceHelper.createFile(project, "file with spaces 3.cpp"); + IFile file4=ResourceHelper.createFile(project, "file with spaces 4.cpp"); + ICLanguageSetting ls = cfgDescription.getLanguageSettingForFile(file1.getProjectRelativePath(), true); + String languageId = ls.getLanguageId(); + + // create GCCBuildCommandParser + GCCBuildCommandParser parser = (GCCBuildCommandParser) LanguageSettingsManager.getExtensionProviderCopy(GCC_BUILD_COMMAND_PARSER_EXT); + + // parse line + parser.startup(cfgDescription); + parser.processLine("gcc -I/path0 'file with spaces 1.cpp'"); + parser.processLine("gcc -I/path0 \"file with spaces 2.cpp\""); + parser.processLine("gcc -I/path0 'file with spaces 3.cpp'\n"); + parser.processLine("gcc -I/path0 'file with spaces 4.cpp'\r\n"); + parser.shutdown(); + + // check populated entries + IPath path0 = new Path("/path0").setDevice(project.getLocation().getDevice()); + { + // in single quotes + List entries = parser.getSettingEntries(cfgDescription, file1, languageId); + CIncludePathEntry expected = new CIncludePathEntry(path0, 0); + assertEquals(expected, entries.get(0)); + } + { + // in double quotes + List entries = parser.getSettingEntries(cfgDescription, file2, languageId); + CIncludePathEntry expected = new CIncludePathEntry(path0, 0); + assertEquals(expected, entries.get(0)); + } + { + // Unix EOL + List entries = parser.getSettingEntries(cfgDescription, file3, languageId); + CIncludePathEntry expected = new CIncludePathEntry(path0, 0); + assertEquals(expected, entries.get(0)); + } + { + // Windows EOL + List entries = parser.getSettingEntries(cfgDescription, file4, languageId); + CIncludePathEntry expected = new CIncludePathEntry(path0, 0); + assertEquals(expected, entries.get(0)); + } + } + + /** + */ + public void testEndOfLine() throws Exception { + // Create model project and accompanied descriptions + String projectName = getName(); + IProject project = ResourceHelper.createCDTProjectWithConfig(projectName); + ICConfigurationDescription[] cfgDescriptions = getConfigurationDescriptions(project); + ICConfigurationDescription cfgDescription = cfgDescriptions[0]; + + IFile file0=ResourceHelper.createFile(project, "file0.cpp"); + IFile file1=ResourceHelper.createFile(project, "file1.cpp"); + IFile file2=ResourceHelper.createFile(project, "file2.cpp"); + ICLanguageSetting ls = cfgDescription.getLanguageSettingForFile(file0.getProjectRelativePath(), true); + String languageId = ls.getLanguageId(); + + // create GCCBuildCommandParser + GCCBuildCommandParser parser = (GCCBuildCommandParser) LanguageSettingsManager.getExtensionProviderCopy(GCC_BUILD_COMMAND_PARSER_EXT); + + // parse line + parser.startup(cfgDescription); + parser.processLine("gcc -I/path0 file0.cpp"); + parser.processLine("gcc -I/path0 file1.cpp\n"); + parser.processLine("gcc -I/path0 file2.cpp\r\n"); + parser.shutdown(); + + // check populated entries + IPath path0 = new Path("/path0").setDevice(project.getLocation().getDevice()); + { + List entries = parser.getSettingEntries(cfgDescription, file0, languageId); + CIncludePathEntry expected = new CIncludePathEntry(path0, 0); + CIncludePathEntry entry = (CIncludePathEntry)entries.get(0); + assertEquals(expected, entry); + } + { + List entries = parser.getSettingEntries(cfgDescription, file1, languageId); + CIncludePathEntry expected = new CIncludePathEntry(path0, 0); + CIncludePathEntry entry = (CIncludePathEntry)entries.get(0); + assertEquals(expected, entry); + } + { + List entries = parser.getSettingEntries(cfgDescription, file2, languageId); + CIncludePathEntry expected = new CIncludePathEntry(path0, 0); + CIncludePathEntry entry = (CIncludePathEntry)entries.get(0); + assertEquals(expected, entry); + } + } + + /** + */ + public void testPathEntry_DriveLetter() throws Exception { + // do not test on non-windows systems where drive letters are not supported + if (! Platform.getOS().equals(Platform.OS_WIN32)) + return; + + // Create model project and accompanied descriptions + String projectName = getName(); + IProject project = ResourceHelper.createCDTProjectWithConfig(projectName); + ICConfigurationDescription[] cfgDescriptions = getConfigurationDescriptions(project); + ICConfigurationDescription cfgDescription = cfgDescriptions[0]; + + IFile file=ResourceHelper.createFile(project, "file.cpp"); + ICLanguageSetting ls = cfgDescription.getLanguageSettingForFile(file.getProjectRelativePath(), true); + String languageId = ls.getLanguageId(); + + // create GCCBuildCommandParser + GCCBuildCommandParser parser = (GCCBuildCommandParser) LanguageSettingsManager.getExtensionProviderCopy(GCC_BUILD_COMMAND_PARSER_EXT); + parser.setResolvingPaths(true); + + // parse line + parser.startup(cfgDescription); + parser.processLine("gcc " + + " -IC:\\path" + + " file.cpp"); + parser.shutdown(); + + // check populated entries + IPath path0 = new Path("C:\\path").setDevice(project.getLocation().getDevice()); + { + List entries = parser.getSettingEntries(cfgDescription, file, languageId); + CIncludePathEntry expected = new CIncludePathEntry(path0, 0); + assertEquals(expected, entries.get(0)); + } + } + + /** + */ + public void testPathEntry_ExpandRelativePath() throws Exception { + // Create model project and accompanied descriptions + String projectName = getName(); + IProject project = ResourceHelper.createCDTProjectWithConfig(projectName); + ICConfigurationDescription[] cfgDescriptions = getConfigurationDescriptions(project); + ICConfigurationDescription cfgDescription = cfgDescriptions[0]; + + IFile file=ResourceHelper.createFile(project, "file.cpp"); + IFolder folder=ResourceHelper.createFolder(project, "Folder"); + IFolder folderComposite=ResourceHelper.createFolder(project, "Folder-Icomposite"); + ICLanguageSetting ls = cfgDescription.getLanguageSettingForFile(file.getProjectRelativePath(), true); + String languageId = ls.getLanguageId(); + + // create GCCBuildCommandParser + GCCBuildCommandParser parser = (GCCBuildCommandParser) LanguageSettingsManager.getExtensionProviderCopy(GCC_BUILD_COMMAND_PARSER_EXT); + parser.setResolvingPaths(true); + + // parse line + parser.startup(cfgDescription); + parser.processLine("gcc " + + " -I." + + " -I.." + + " -IFolder" + + " -IFolder-Icomposite" // to test case when "-I" is a part of folder name + + " file.cpp"); + parser.shutdown(); + + // check populated entries + List entries = parser.getSettingEntries(cfgDescription, file, languageId); + { + // check that relative paths are relative to CWD which is the location of the project + assertEquals(new CIncludePathEntry(project.getFullPath(), ICSettingEntry.VALUE_WORKSPACE_PATH | ICSettingEntry.RESOLVED), entries.get(0)); + assertEquals(new CIncludePathEntry(project.getLocation().removeLastSegments(1), 0), entries.get(1)); + assertEquals(new CIncludePathEntry(folder.getFullPath(), ICSettingEntry.VALUE_WORKSPACE_PATH | ICSettingEntry.RESOLVED), entries.get(2)); + assertEquals(new CIncludePathEntry(folderComposite.getFullPath(), ICSettingEntry.VALUE_WORKSPACE_PATH | ICSettingEntry.RESOLVED), entries.get(3)); + } + } + + /** + */ + public void testPathEntry_DoNotExpandRelativePath() throws Exception { + // Create model project and accompanied descriptions + String projectName = getName(); + IProject project = ResourceHelper.createCDTProjectWithConfig(projectName); + ICConfigurationDescription[] cfgDescriptions = getConfigurationDescriptions(project); + ICConfigurationDescription cfgDescription = cfgDescriptions[0]; + + IFile file=ResourceHelper.createFile(project, "file.cpp"); + @SuppressWarnings("unused") + IFolder folder=ResourceHelper.createFolder(project, "Folder"); + ICLanguageSetting ls = cfgDescription.getLanguageSettingForFile(file.getProjectRelativePath(), true); + String languageId = ls.getLanguageId(); + + // create GCCBuildCommandParser with expandRelativePaths=false + GCCBuildCommandParser parser = (GCCBuildCommandParser) LanguageSettingsManager.getExtensionProviderCopy(GCC_BUILD_COMMAND_PARSER_EXT); + parser.setResolvingPaths(false); + + // parse line + parser.startup(cfgDescription); + parser.processLine("gcc " + + " -I." + + " -I.." + + " -IFolder" + + " file.cpp"); + parser.shutdown(); + + // check populated entries + List entries = parser.getSettingEntries(cfgDescription, file, languageId); + { + assertEquals(new CIncludePathEntry(".", 0), entries.get(0)); + assertEquals(new CIncludePathEntry("..", 0), entries.get(1)); + assertEquals(new CIncludePathEntry("Folder", 0), entries.get(2)); + } + } + + /** + */ + public void testPathEntry_DuplicatePath() throws Exception { + // Create model project and accompanied descriptions + String projectName = getName(); + IProject project = ResourceHelper.createCDTProjectWithConfig(projectName); + ICConfigurationDescription[] cfgDescriptions = getConfigurationDescriptions(project); + ICConfigurationDescription cfgDescription = cfgDescriptions[0]; + + IFile file=ResourceHelper.createFile(project, "file.cpp"); + IFolder folder=ResourceHelper.createFolder(project, "Folder"); + ICLanguageSetting ls = cfgDescription.getLanguageSettingForFile(file.getProjectRelativePath(), true); + String languageId = ls.getLanguageId(); + + // create GCCBuildCommandParser + GCCBuildCommandParser parser = (GCCBuildCommandParser) LanguageSettingsManager.getExtensionProviderCopy(GCC_BUILD_COMMAND_PARSER_EXT); + parser.setResolvingPaths(true); + + // parse line + parser.startup(cfgDescription); + parser.processLine("gcc " + + " -IFolder" + + " -IFolder" + + " file.cpp"); + parser.shutdown(); + + // check populated entries + List entries = parser.getSettingEntries(cfgDescription, file, languageId); + { + assertEquals(new CIncludePathEntry(folder.getFullPath(), ICSettingEntry.VALUE_WORKSPACE_PATH | ICSettingEntry.RESOLVED), entries.get(0)); + assertEquals(1, entries.size()); + } + } + + /** + */ + public void testPathEntry_FollowCWD() throws Exception { + // Create model project and accompanied descriptions + String projectName = getName(); + IProject project = ResourceHelper.createCDTProjectWithConfig(projectName); + ICConfigurationDescription[] cfgDescriptions = getConfigurationDescriptions(project); + ICConfigurationDescription cfgDescription = cfgDescriptions[0]; + + IFolder buildDir=ResourceHelper.createFolder(project, "BuildDir"); + IFolder folder=ResourceHelper.createFolder(project, "BuildDir/Folder"); + IFile file=ResourceHelper.createFile(project, "BuildDir/file.cpp"); + @SuppressWarnings("unused") + IFile fakeFile=ResourceHelper.createFile(project, "file.cpp"); + ICLanguageSetting ls = cfgDescription.getLanguageSettingForFile(file.getProjectRelativePath(), true); + String languageId = ls.getLanguageId(); + + // create GCCBuildCommandParser + GCCBuildCommandParser parser = (GCCBuildCommandParser) LanguageSettingsManager.getExtensionProviderCopy(GCC_BUILD_COMMAND_PARSER_EXT); + ErrorParserManager epm = new ErrorParserManager(project, null); + epm.pushDirectoryURI(buildDir.getLocationURI()); + + // parse line + parser.startup(cfgDescription); + parser.processLine("gcc " + + " -I." + + " -I.." + + " -I../../.." + + " -IFolder" + + " -IMissingFolder" + + " file.cpp", + epm); + parser.shutdown(); + + // check populated entries + List entries = parser.getSettingEntries(cfgDescription, file, languageId); + { + assertEquals(new CIncludePathEntry(buildDir.getFullPath(), ICSettingEntry.VALUE_WORKSPACE_PATH | ICSettingEntry.RESOLVED), entries.get(0)); + assertEquals(new CIncludePathEntry(buildDir.getFullPath().removeLastSegments(1), ICSettingEntry.VALUE_WORKSPACE_PATH | ICSettingEntry.RESOLVED), entries.get(1)); + assertEquals(new CIncludePathEntry(buildDir.getLocation().removeLastSegments(3), 0), entries.get(2)); + assertEquals(new CIncludePathEntry(folder.getFullPath(), ICSettingEntry.VALUE_WORKSPACE_PATH | ICSettingEntry.RESOLVED), entries.get(3)); + assertEquals(new CIncludePathEntry(buildDir.getFullPath().append("MissingFolder"), ICSettingEntry.VALUE_WORKSPACE_PATH | ICSettingEntry.RESOLVED), entries.get(4)); + } + } + + /** + */ + public void testPathEntry_GuessCWD() throws Exception { + // Create model project and accompanied descriptions + String projectName = getName(); + IProject project = ResourceHelper.createCDTProjectWithConfig(projectName); + ICConfigurationDescription[] cfgDescriptions = getConfigurationDescriptions(project); + ICConfigurationDescription cfgDescription = cfgDescriptions[0]; + + IFolder folder=ResourceHelper.createFolder(project, "BuildDir/Folder"); + IFile file=ResourceHelper.createFile(project, "BuildDir/file.cpp"); + ICLanguageSetting ls = cfgDescription.getLanguageSettingForFile(file.getProjectRelativePath(), true); + String languageId = ls.getLanguageId(); + + // create GCCBuildCommandParser + GCCBuildCommandParser parser = (GCCBuildCommandParser) LanguageSettingsManager.getExtensionProviderCopy(GCC_BUILD_COMMAND_PARSER_EXT); + + ErrorParserManager epm = new ErrorParserManager(project, null); + + // parse line + parser.startup(cfgDescription); + parser.processLine("gcc " + + " -IFolder" + + " file.cpp", + epm); + parser.shutdown(); + + // check populated entries + List entries = parser.getSettingEntries(cfgDescription, file, languageId); + assertEquals(new CIncludePathEntry(folder.getFullPath(), ICSettingEntry.VALUE_WORKSPACE_PATH | ICSettingEntry.RESOLVED), entries.get(0)); + } + + /** + */ + public void testPathEntry_NonExistentCWD_Workspace() throws Exception { + // Create model project and accompanied descriptions + String projectName = getName(); + IProject project = ResourceHelper.createCDTProjectWithConfig(projectName); + ICConfigurationDescription[] cfgDescriptions = getConfigurationDescriptions(project); + ICConfigurationDescription cfgDescription = cfgDescriptions[0]; + + IFolder buildDir=project.getFolder("Missing/Folder"); + IFile file=ResourceHelper.createFile(project, "file.cpp"); + ICLanguageSetting ls = cfgDescription.getLanguageSettingForFile(file.getProjectRelativePath(), true); + String languageId = ls.getLanguageId(); + + // create GCCBuildCommandParser + GCCBuildCommandParser parser = (GCCBuildCommandParser) LanguageSettingsManager.getExtensionProviderCopy(GCC_BUILD_COMMAND_PARSER_EXT); + + ErrorParserManager epm = new ErrorParserManager(project, null); + epm.pushDirectoryURI(buildDir.getLocationURI()); + + // parse line + parser.startup(cfgDescription); + parser.processLine("gcc " + + " -I." + + " -I.." + + " -IFolder" + + " ../file.cpp", + epm); + parser.shutdown(); + + // check populated entries + List entries = parser.getSettingEntries(cfgDescription, file, languageId); + { + assertEquals(new CIncludePathEntry(buildDir.getFullPath(), ICSettingEntry.VALUE_WORKSPACE_PATH | ICSettingEntry.RESOLVED), entries.get(0)); + assertEquals(new CIncludePathEntry(buildDir.getFullPath().removeLastSegments(1), ICSettingEntry.VALUE_WORKSPACE_PATH | ICSettingEntry.RESOLVED), entries.get(1)); + assertEquals(new CIncludePathEntry(buildDir.getFullPath().append("Folder"), ICSettingEntry.VALUE_WORKSPACE_PATH | ICSettingEntry.RESOLVED), entries.get(2)); + } + } + + /** + */ + public void testPathEntry_NonExistentCWD_Filesystem() throws Exception { + // Create model project and accompanied descriptions + String projectName = getName(); + IProject project = ResourceHelper.createCDTProjectWithConfig(projectName); + ICConfigurationDescription[] cfgDescriptions = getConfigurationDescriptions(project); + ICConfigurationDescription cfgDescription = cfgDescriptions[0]; + + IFile file=ResourceHelper.createFile(project, "file.cpp"); + ICLanguageSetting ls = cfgDescription.getLanguageSettingForFile(file.getProjectRelativePath(), true); + String languageId = ls.getLanguageId(); + + // create GCCBuildCommandParser + GCCBuildCommandParser parser = (GCCBuildCommandParser) LanguageSettingsManager.getExtensionProviderCopy(GCC_BUILD_COMMAND_PARSER_EXT); + + ErrorParserManager epm = new ErrorParserManager(project, null); + URI uriBuildDir = new URI("file:/non-existing/path"); + epm.pushDirectoryURI(uriBuildDir); + + // parse line + parser.startup(cfgDescription); + parser.processLine("gcc " + + " -I." + + " -I.." + + " -IFolder" + + " ../file.cpp", + epm); + parser.shutdown(); + + // check populated entries + List entries = parser.getSettingEntries(cfgDescription, file, languageId); + { + IPath buildPath = new Path(uriBuildDir.getPath()).setDevice(project.getLocation().getDevice()); + assertEquals(new CIncludePathEntry(buildPath, 0), entries.get(0)); + assertEquals(new CIncludePathEntry(buildPath.removeLastSegments(1), 0), entries.get(1)); + assertEquals(new CIncludePathEntry(buildPath.append("Folder"), 0), entries.get(2)); + } + } + + /** + */ + public void testPathEntry_MappedRemoteFolder() throws Exception { + // Create model project and accompanied descriptions + String projectName = getName(); + IProject project = ResourceHelper.createCDTProjectWithConfig(projectName); + ICConfigurationDescription[] cfgDescriptions = getConfigurationDescriptions(project); + ICConfigurationDescription cfgDescription = cfgDescriptions[0]; + + IFolder buildDir=ResourceHelper.createFolder(project, "Local/BuildDir"); + IFolder folder=ResourceHelper.createFolder(project, "Local/BuildDir/Folder"); + IFolder folder2=ResourceHelper.createFolder(project, "Local/BuildDir/Folder2"); + IFile file=ResourceHelper.createFile(project, "Local/BuildDir/file.cpp"); + ICLanguageSetting ls = cfgDescription.getLanguageSettingForFile(file.getProjectRelativePath(), true); + String languageId = ls.getLanguageId(); + + // create GCCBuildCommandParser + GCCBuildCommandParser parser = (GCCBuildCommandParser) LanguageSettingsManager.getExtensionProviderCopy(GCC_BUILD_COMMAND_PARSER_EXT); + + ErrorParserManager epm = new ErrorParserManager(project, null); + URI uriBuildDir = new URI("file:/BuildDir"); + epm.pushDirectoryURI(uriBuildDir); + + // parse line + parser.startup(cfgDescription); + parser.processLine("gcc " + + " -I." + + " -I/BuildDir/Folder" + + " -I../BuildDir/Folder2" + + " -I/BuildDir/MissingFolder" + + " -I../BuildDir/MissingFolder2" + + " /BuildDir/file.cpp", + epm); + parser.shutdown(); + + // check populated entries + List entries = parser.getSettingEntries(cfgDescription, file, languageId); + { + assertEquals(new CIncludePathEntry(buildDir.getFullPath(), ICSettingEntry.VALUE_WORKSPACE_PATH | ICSettingEntry.RESOLVED), entries.get(0)); + assertEquals(new CIncludePathEntry(folder.getFullPath(), ICSettingEntry.VALUE_WORKSPACE_PATH | ICSettingEntry.RESOLVED), entries.get(1)); + assertEquals(new CIncludePathEntry(folder2.getFullPath(), ICSettingEntry.VALUE_WORKSPACE_PATH | ICSettingEntry.RESOLVED), entries.get(2)); + assertEquals(new CIncludePathEntry(buildDir.getFullPath().append("MissingFolder"), ICSettingEntry.VALUE_WORKSPACE_PATH | ICSettingEntry.RESOLVED), entries.get(3)); + assertEquals(new CIncludePathEntry(buildDir.getFullPath().append("MissingFolder2"), ICSettingEntry.VALUE_WORKSPACE_PATH | ICSettingEntry.RESOLVED), entries.get(4)); + } + } + + /** + */ + public void testPathEntry_MappedFolderInProject() throws Exception { + // Create model project and accompanied descriptions + String projectName = getName(); + IProject project = ResourceHelper.createCDTProjectWithConfig(projectName); + ICConfigurationDescription[] cfgDescriptions = getConfigurationDescriptions(project); + ICConfigurationDescription cfgDescription = cfgDescriptions[0]; + + IFile file=ResourceHelper.createFile(project, "BuildDir/file.cpp"); + IFolder mappedFolder=ResourceHelper.createFolder(project, "Mapped/Folder"); + IFolder folder=ResourceHelper.createFolder(project, "Mapped/Folder/Subfolder"); + @SuppressWarnings("unused") + IFolder ambiguousFolder1=ResourceHelper.createFolder(project, "One/Ambiguous/Folder"); + @SuppressWarnings("unused") + IFolder ambiguousFolder2=ResourceHelper.createFolder(project, "Another/Ambiguous/Folder"); + + ICLanguageSetting ls = cfgDescription.getLanguageSettingForFile(file.getProjectRelativePath(), true); + String languageId = ls.getLanguageId(); + + // create GCCBuildCommandParser + GCCBuildCommandParser parser = (GCCBuildCommandParser) LanguageSettingsManager.getExtensionProviderCopy(GCC_BUILD_COMMAND_PARSER_EXT); + ErrorParserManager epm = new ErrorParserManager(project, null); + + // parse line + parser.startup(cfgDescription); + parser.processLine("gcc " + + " -I/Folder/Subfolder" + + " -I/Mapped/Folder" + + " -I/Ambiguous/Folder" + + " -I/Missing/Folder" + + " file.cpp", + epm); + parser.shutdown(); + + // check populated entries + List entries = parser.getSettingEntries(cfgDescription, file, languageId); + { + assertEquals(new CIncludePathEntry(folder.getFullPath(), ICSettingEntry.VALUE_WORKSPACE_PATH | ICSettingEntry.RESOLVED), entries.get(0)); + assertEquals(new CIncludePathEntry(mappedFolder.getFullPath(), ICSettingEntry.VALUE_WORKSPACE_PATH | ICSettingEntry.RESOLVED), entries.get(1)); + } + { + IPath path = new Path("/Ambiguous/Folder").setDevice(file.getLocation().getDevice()); + assertEquals(new CIncludePathEntry(path, 0), entries.get(2)); + } + { + IPath path = new Path("/Missing/Folder").setDevice(file.getLocation().getDevice()); + assertEquals(new CIncludePathEntry(path, 0), entries.get(3)); + } + } + + /** + */ + public void testPathEntry_MappedFolderInAnotherProject() throws Exception { + // Create model project and accompanied descriptions + String projectName = getName(); + IProject project = ResourceHelper.createCDTProjectWithConfig(projectName); + ICConfigurationDescription[] cfgDescriptions = getConfigurationDescriptions(project); + ICConfigurationDescription cfgDescription = cfgDescriptions[0]; + + // create files and folders + IFile file=ResourceHelper.createFile(project, "file.cpp"); + // another project + IProject anotherProject = ResourceHelper.createCDTProjectWithConfig(projectName+"-another"); + IFolder folder=ResourceHelper.createFolder(anotherProject, "Mapped/Folder/Subfolder"); + @SuppressWarnings("unused") + IFolder ambiguousFolder1=ResourceHelper.createFolder(anotherProject, "One/Ambiguous/Folder"); + @SuppressWarnings("unused") + IFolder ambiguousFolder2=ResourceHelper.createFolder(anotherProject, "Another/Ambiguous/Folder"); + + + ICLanguageSetting ls = cfgDescription.getLanguageSettingForFile(file.getProjectRelativePath(), true); + String languageId = ls.getLanguageId(); + + // create GCCBuildCommandParser + GCCBuildCommandParser parser = (GCCBuildCommandParser) LanguageSettingsManager.getExtensionProviderCopy(GCC_BUILD_COMMAND_PARSER_EXT); + ErrorParserManager epm = new ErrorParserManager(project, null); + + // parse line + parser.startup(cfgDescription); + parser.processLine("gcc " + + " -I/Folder/Subfolder" + + " -I/Ambiguous/Folder" + + " -I/Missing/Folder" + + " file.cpp", + epm); + parser.shutdown(); + + // check populated entries + List entries = parser.getSettingEntries(cfgDescription, file, languageId); + { + assertEquals(new CIncludePathEntry(folder.getFullPath(), ICSettingEntry.VALUE_WORKSPACE_PATH | ICSettingEntry.RESOLVED), entries.get(0)); + } + { + IPath path = new Path("/Ambiguous/Folder").setDevice(file.getLocation().getDevice()); + assertEquals(new CIncludePathEntry(path, 0), entries.get(1)); + } + { + IPath path = new Path("/Missing/Folder").setDevice(file.getLocation().getDevice()); + assertEquals(new CIncludePathEntry(path, 0), entries.get(2)); + } + } + + /** + */ + public void testPathEntry_MappedFolderInReferencedProject() throws Exception { + // Create model project and accompanied descriptions + String projectName = getName(); + + // create main project + IProject project = ResourceHelper.createCDTProjectWithConfig(projectName); + IFile file=ResourceHelper.createFile(project, "file.cpp"); + + // create another project (non-referenced) + IProject anotherProject = ResourceHelper.createCDTProjectWithConfig(projectName+"-another"); + @SuppressWarnings("unused") + IFolder folderInAnotherProject=ResourceHelper.createFolder(anotherProject, "Mapped/Folder/Subfolder"); + + // create referenced project + IProject referencedProject = ResourceHelper.createCDTProjectWithConfig(projectName+"-referenced"); + IFolder folderInReferencedProject=ResourceHelper.createFolder(referencedProject, "Mapped/Folder/Subfolder"); + @SuppressWarnings("unused") + IFolder ambiguousFolder1=ResourceHelper.createFolder(referencedProject, "One/Ambiguous/Folder"); + @SuppressWarnings("unused") + IFolder ambiguousFolder2=ResourceHelper.createFolder(referencedProject, "Another/Ambiguous/Folder"); + + setReference(project, referencedProject); + + // get cfgDescription and language to work with + ICConfigurationDescription[] cfgDescriptions = getConfigurationDescriptions(project); + ICConfigurationDescription cfgDescription = cfgDescriptions[0]; + ICLanguageSetting ls = cfgDescription.getLanguageSettingForFile(file.getProjectRelativePath(), true); + String languageId = ls.getLanguageId(); + + // create GCCBuildCommandParser + GCCBuildCommandParser parser = (GCCBuildCommandParser) LanguageSettingsManager.getExtensionProviderCopy(GCC_BUILD_COMMAND_PARSER_EXT); + ErrorParserManager epm = new ErrorParserManager(project, null); + + // parse line + parser.startup(cfgDescription); + parser.processLine("gcc " + + " -I/Folder/Subfolder" + + " -I/Ambiguous/Folder" + + " file.cpp", + epm); + parser.shutdown(); + + // check populated entries + List entries = parser.getSettingEntries(cfgDescription, file, languageId); + { + assertEquals(new CIncludePathEntry(folderInReferencedProject.getFullPath(), ICSettingEntry.VALUE_WORKSPACE_PATH | ICSettingEntry.RESOLVED), entries.get(0)); + + IPath path = new Path("/Ambiguous/Folder").setDevice(file.getLocation().getDevice()); + assertEquals(new CIncludePathEntry(path, 0), entries.get(1)); + } + } + + /** + */ + public void testPathEntry_NavigateSymbolicLinkUpAbsolute() throws Exception { + // do not test on systems where symbolic links are not supported + if (!ResourceHelper.isSymbolicLinkSupported()) + return; + + // Create model project and accompanied descriptions + String projectName = getName(); + IProject project = ResourceHelper.createCDTProjectWithConfig(projectName); + ICConfigurationDescription[] cfgDescriptions = getConfigurationDescriptions(project); + ICConfigurationDescription cfgDescription = cfgDescriptions[0]; + + String languageId = LANG_CPP; + IFile file=ResourceHelper.createFile(project, "file.cpp"); + + // create link on the filesystem + IPath dir1 = ResourceHelper.createTemporaryFolder(); + IPath dir2 = dir1.removeLastSegments(1); + IPath linkPath = dir1.append("linked"); + ResourceHelper.createSymbolicLink(linkPath, dir2); + + // create GCCBuildCommandParser + GCCBuildCommandParser parser = (GCCBuildCommandParser) LanguageSettingsManager.getExtensionProviderCopy(GCC_BUILD_COMMAND_PARSER_EXT); + ErrorParserManager epm = new ErrorParserManager(project, null); + + // parse line + parser.startup(cfgDescription); + // "../" should navigate along filesystem path, not along the link itself + parser.processLine("gcc -I"+linkPath.toString()+"/.."+" file.cpp", epm); + parser.shutdown(); + + // check populated entries + { + List entries = parser.getSettingEntries(cfgDescription, file, languageId); + CIncludePathEntry expected = new CIncludePathEntry(dir2.removeLastSegments(1), 0); + assertEquals(expected, entries.get(0)); + } + } + + /** + */ + public void testPathEntry_NavigateSymbolicLinkUpRelative() throws Exception { + // do not test on systems where symbolic links are not supported + if (!ResourceHelper.isSymbolicLinkSupported()) + return; + + // Create model project and accompanied descriptions + String projectName = getName(); + IProject project = ResourceHelper.createCDTProjectWithConfig(projectName); + ICConfigurationDescription[] cfgDescriptions = getConfigurationDescriptions(project); + ICConfigurationDescription cfgDescription = cfgDescriptions[0]; + + String languageId = LANG_CPP; + IFile file=ResourceHelper.createFile(project, "file.cpp"); + + // create link + IFolder folder = ResourceHelper.createFolder(project, "folder"); + IFolder subfolder = ResourceHelper.createFolder(project, "folder/subfolder"); + IPath linkPath = project.getLocation().append("linked"); + ResourceHelper.createSymbolicLink(linkPath, subfolder.getLocation()); + + // create GCCBuildCommandParser + GCCBuildCommandParser parser = (GCCBuildCommandParser) LanguageSettingsManager.getExtensionProviderCopy(GCC_BUILD_COMMAND_PARSER_EXT); + ErrorParserManager epm = new ErrorParserManager(project, null); + + // parse line + parser.startup(cfgDescription); + // "../" should navigate along filesystem path, not along the link itself + parser.processLine("gcc -Ilinked/.."+" file.cpp", epm); + parser.shutdown(); + + // check populated entries + { + List entries = parser.getSettingEntries(cfgDescription, file, languageId); + CIncludePathEntry expected = new CIncludePathEntry(folder.getFullPath(), ICSettingEntry.VALUE_WORKSPACE_PATH | ICSettingEntry.RESOLVED); + assertEquals(expected, entries.get(0)); + } + } + + /** + */ + public void testPathEntry_BuildDirDefinedByConfiguration_RelativePath() throws Exception { + // Create model project and accompanied descriptions + String projectName = getName(); + IProject project = ResourceHelper.createCDTProjectWithConfig(projectName); + // Create resources trying to confuse the parser + @SuppressWarnings("unused") + IFile fileInProjectRoot=ResourceHelper.createFile(project, "file.cpp"); + @SuppressWarnings("unused") + IFolder includeDirInProjectRoot=ResourceHelper.createFolder(project, "include"); + // Create resources meant to be found + IFolder buildDir=ResourceHelper.createFolder(project, "BuildDir"); + IFile file=ResourceHelper.createFile(project, "BuildDir/file.cpp"); + IFolder includeDir=ResourceHelper.createFolder(project, "BuildDir/include"); + // Change build dir + setBuilderCWD(project, buildDir.getLocation()); + + ICConfigurationDescription[] cfgDescriptions = getConfigurationDescriptions(project); + ICConfigurationDescription cfgDescription = cfgDescriptions[0]; + + ICLanguageSetting ls = cfgDescription.getLanguageSettingForFile(file.getProjectRelativePath(), true); + String languageId = ls.getLanguageId(); + + // create GCCBuildCommandParser + GCCBuildCommandParser parser = (GCCBuildCommandParser) LanguageSettingsManager.getExtensionProviderCopy(GCC_BUILD_COMMAND_PARSER_EXT); + + // parse line + parser.startup(cfgDescription); + parser.processLine("gcc " + + " -I." + + " -Iinclude" + + " file.cpp"); + parser.shutdown(); + + // check populated entries + List entries = parser.getSettingEntries(cfgDescription, file, languageId); + { + assertEquals(new CIncludePathEntry(buildDir.getFullPath(), ICSettingEntry.VALUE_WORKSPACE_PATH | ICSettingEntry.RESOLVED), entries.get(0)); + assertEquals(new CIncludePathEntry(includeDir.getFullPath(), ICSettingEntry.VALUE_WORKSPACE_PATH | ICSettingEntry.RESOLVED), entries.get(1)); + } + } + + /** + */ + public void testPathEntry_BuildDirDefinedByConfiguration_AbsolutePath() throws Exception { + // Create model project and accompanied descriptions + String projectName = getName(); + IProject project = ResourceHelper.createCDTProjectWithConfig(projectName); + // Create resources trying to confuse the parser + @SuppressWarnings("unused") + IFile fileInProjectRoot=ResourceHelper.createFile(project, "file.cpp"); + @SuppressWarnings("unused") + IFolder includeDirInProjectRoot=ResourceHelper.createFolder(project, "include"); + // Create resources meant to be found + IFolder buildDir=ResourceHelper.createFolder(project, "BuildDir"); + IFile file=ResourceHelper.createFile(project, "BuildDir/file.cpp"); + IFolder includeDir=ResourceHelper.createFolder(project, "BuildDir/include"); + // Change build dir + setBuilderCWD(project, buildDir.getLocation()); + + ICConfigurationDescription[] cfgDescriptions = getConfigurationDescriptions(project); + ICConfigurationDescription cfgDescription = cfgDescriptions[0]; + + ICLanguageSetting ls = cfgDescription.getLanguageSettingForFile(file.getProjectRelativePath(), true); + String languageId = ls.getLanguageId(); + + // create GCCBuildCommandParser + GCCBuildCommandParser parser = (GCCBuildCommandParser) LanguageSettingsManager.getExtensionProviderCopy(GCC_BUILD_COMMAND_PARSER_EXT); + + // parse line + parser.startup(cfgDescription); + parser.processLine("gcc " + + " -I." + + " -Iinclude" + + " " + file.getLocation().toOSString() + ); + parser.shutdown(); + + // check populated entries + List entries = parser.getSettingEntries(cfgDescription, file, languageId); + { + assertEquals(new CIncludePathEntry(buildDir.getFullPath(), ICSettingEntry.VALUE_WORKSPACE_PATH | ICSettingEntry.RESOLVED), entries.get(0)); + assertEquals(new CIncludePathEntry(includeDir.getFullPath(), ICSettingEntry.VALUE_WORKSPACE_PATH | ICSettingEntry.RESOLVED), entries.get(1)); + } + + } + + public void testContentType_None() throws Exception { + MockBuildCommandParser parser = new MockBuildCommandParser() { + @Override + protected String parseForResourceName(String line) { + return "file.wrong-content-type"; + } + }; + parser.startup(null); + parser.processLine("gcc file.wrong-content-type"); + parser.shutdown(); + + List entries = parser.getSettingEntries(null, null, null); + assertNull(entries); + } + + /** + */ + public void testContentType_Mismatch() throws Exception { + // Create model project and accompanied descriptions + String projectName = getName(); + IProject project = ResourceHelper.createCDTProjectWithConfig(projectName); + ICConfigurationDescription[] cfgDescriptions = getConfigurationDescriptions(project); + ICConfigurationDescription cfgDescription = cfgDescriptions[0]; + ResourceHelper.createFile(project, "file.c"); + + // create GCCBuildCommandParser + GCCBuildCommandParser parser = (GCCBuildCommandParser) LanguageSettingsManager.getExtensionProviderCopy(GCC_BUILD_COMMAND_PARSER_EXT); + // restrict the parser's language scope to C++ only + parser.setLanguageScope(new ArrayList() {{add(LANG_CPP);}}); + + // parse line + parser.startup(cfgDescription); + parser.processLine("gcc -I/path0 file.c"); + parser.shutdown(); + + assertTrue(parser.isEmpty()); + } + + /** + */ + public void testContentType_FileExtensions() throws Exception { + // Create model project and accompanied descriptions + String projectName = getName(); + IProject project = ResourceHelper.createCDTProjectWithConfig(projectName); + ICConfigurationDescription[] cfgDescriptions = getConfigurationDescriptions(project); + ICConfigurationDescription cfgDescription = cfgDescriptions[0]; + + String languageId = LANG_CPP; + // add custom extension to C++ content type + IContentTypeManager manager = Platform.getContentTypeManager(); + IContentType contentType = manager.findContentTypeFor("file.cpp"); + contentType.addFileSpec("x++", IContentTypeSettings.FILE_EXTENSION_SPEC); + + IFile file=ResourceHelper.createFile(project, "file.x++"); + IContentType contentTypeX = manager.findContentTypeFor("file.x++"); + assertEquals(contentType, contentTypeX); + + // create GCCBuildCommandParser + GCCBuildCommandParser parser = (GCCBuildCommandParser) LanguageSettingsManager.getExtensionProviderCopy(GCC_BUILD_COMMAND_PARSER_EXT); + + // parse line + parser.startup(cfgDescription); + parser.processLine("gcc -I/path0 file.x++"); + parser.shutdown(); + + // check populated entries + IPath path0 = new Path("/path0").setDevice(project.getLocation().getDevice()); + { + List entries = parser.getSettingEntries(cfgDescription, file, languageId); + CIncludePathEntry expected = new CIncludePathEntry(path0, 0); + assertEquals(expected, entries.get(0)); + } + } + + /** + */ + public void testUpperCase() throws Exception { + // Create model project and accompanied descriptions + String projectName = getName(); + IProject project = ResourceHelper.createCDTProjectWithConfig(projectName); + ICConfigurationDescription[] cfgDescriptions = getConfigurationDescriptions(project); + ICConfigurationDescription cfgDescription = cfgDescriptions[0]; + + String languageId = LANG_CPP; + + IFile file=ResourceHelper.createFile(project, "file.cpp"); + + // create GCCBuildCommandParser + GCCBuildCommandParser parser = (GCCBuildCommandParser) LanguageSettingsManager.getExtensionProviderCopy(GCC_BUILD_COMMAND_PARSER_EXT); + ErrorParserManager epm = new ErrorParserManager(project, null); + + // parse line + parser.startup(cfgDescription); + parser.processLine("gcc -I/path0 FILE.CPP", epm); + parser.shutdown(); + + // check populated entries + IPath path0 = new Path("/path0").setDevice(project.getLocation().getDevice()); + { + List entries = parser.getSettingEntries(cfgDescription, file, languageId); + CIncludePathEntry expected = new CIncludePathEntry(path0, 0); + assertEquals(expected, entries.get(0)); + } + } + + /** + */ + public void testBoostBjam() throws Exception { + // Create model project and accompanied descriptions + String projectName = getName(); + IProject project = ResourceHelper.createCDTProjectWithConfig(projectName); + ICConfigurationDescription[] cfgDescriptions = getConfigurationDescriptions(project); + ICConfigurationDescription cfgDescription = cfgDescriptions[0]; + + IFile file=ResourceHelper.createFile(project, "libs/python/src/numeric.cpp"); + ICLanguageSetting ls = cfgDescription.getLanguageSettingForFile(file.getProjectRelativePath(), true); + String languageId = ls.getLanguageId(); + + // create GCCBuildCommandParser + GCCBuildCommandParser parser = (GCCBuildCommandParser) LanguageSettingsManager.getExtensionProviderCopy(GCC_BUILD_COMMAND_PARSER_EXT); + + // parse line + parser.startup(cfgDescription); + // "g++" -ftemplate-depth-128 -O0 -fno-inline -Wall -g -mthreads -DBOOST_ALL_NO_LIB=1 -DBOOST_PYTHON_SOURCE -DBOOST_PYTHON_STATIC_LIB -I"." -I"/Python25/Include" -c -o "bin.v2/libs/python/build/gcc-mingw-3.4.5/debug/link-static/threading-multi/numeric.o" "libs/python/src/numeric.cpp" + parser.processLine(" \"g++\"" + + " -ftemplate-depth-128 -O0 -fno-inline -Wall -g -mthreads" + + " -DBOOST_ALL_NO_LIB=1" + + " -DBOOST_PYTHON_SOURCE" + + " -DBOOST_PYTHON_STATIC_LIB" + + " -I\".\"" + + " -I\"/Python1025/Include\"" + + " -c -o \"bin.v2/libs/python/build/gcc-mingw-3.4.5/debug/link-static/threading-multi/numeric.o\"" + + " libs/python/src/numeric.cpp"); + parser.shutdown(); + + // check populated entries + { + List entries = parser.getSettingEntries(cfgDescription, file, languageId); + assertEquals(new CMacroEntry("BOOST_ALL_NO_LIB", "1", 0), entries.get(0)); + assertEquals(new CMacroEntry("BOOST_PYTHON_SOURCE", "", 0), entries.get(1)); + assertEquals(new CMacroEntry("BOOST_PYTHON_STATIC_LIB", "", 0), entries.get(2)); + assertEquals(new CIncludePathEntry(project.getFullPath(), ICSettingEntry.VALUE_WORKSPACE_PATH | ICSettingEntry.RESOLVED), entries.get(3)); + assertEquals(new CIncludePathEntry(new Path("/Python1025/Include").setDevice(project.getLocation().getDevice()), 0), entries.get(4)); + assertEquals(5, entries.size()); + } + } + + /** + */ + public void testPathEntry_Efs() throws Exception { + // Create model project and accompanied descriptions + String projectName = getName(); + IProject project = ResourceHelper.createCDTProjectWithConfig(projectName); + ICConfigurationDescription[] cfgDescriptions = getConfigurationDescriptions(project); + ICConfigurationDescription cfgDescription = cfgDescriptions[0]; + + // create folder structure + @SuppressWarnings("unused") + IFolder buildDir=ResourceHelper.createEfsFolder(project, "BuildDir", new URI("mem:/EfsProject/BuildDir")); + IFolder folder=ResourceHelper.createEfsFolder(project, "BuildDir/Folder", new URI("mem:/EfsProject/BuildDir/Folder")); + IFile file=ResourceHelper.createEfsFile(project, "BuildDir/file.cpp", new URI("mem:/EfsProject/BuildDir/file.cpp")); + ICLanguageSetting ls = cfgDescription.getLanguageSettingForFile(file.getProjectRelativePath(), true); + String languageId = ls.getLanguageId(); + + // create GCCBuildCommandParser + GCCBuildCommandParser parser = (GCCBuildCommandParser) LanguageSettingsManager.getExtensionProviderCopy(GCC_BUILD_COMMAND_PARSER_EXT); + ErrorParserManager epm = new ErrorParserManager(project, null); + + // parse line + parser.startup(cfgDescription); + parser.processLine("gcc " + + " -IFolder" + + " -I/Absolute/Folder" + + " file.cpp", + epm); + parser.shutdown(); + + // check populated entries + List entries = parser.getSettingEntries(cfgDescription, file, languageId); + { + String device = project.getLocation().getDevice(); + assertEquals(new CIncludePathEntry(folder.getFullPath(), ICSettingEntry.VALUE_WORKSPACE_PATH | ICSettingEntry.RESOLVED), entries.get(0)); + assertEquals(new CIncludePathEntry(new Path("/Absolute/Folder").setDevice(device), 0), entries.get(1)); + } + } + + /** + */ + public void testPathEntry_EfsMappedFolder() throws Exception { + // Create model project and accompanied descriptions + String projectName = getName(); + IProject project = ResourceHelper.createCDTProjectWithConfig(projectName); + ICConfigurationDescription[] cfgDescriptions = getConfigurationDescriptions(project); + ICConfigurationDescription cfgDescription = cfgDescriptions[0]; + + // create folder structure + @SuppressWarnings("unused") + IFolder buildDir=ResourceHelper.createEfsFolder(project, "BuildDir", new URI("mem:/MappedEfsProject/BuildDir")); + @SuppressWarnings("unused") + IFolder folder=ResourceHelper.createEfsFolder(project, "BuildDir/Folder", new URI("mem:/MappedEfsProject/BuildDir/Folder")); + IFile file=ResourceHelper.createEfsFile(project, "BuildDir/file.cpp", new URI("mem:/MappedEfsProject/BuildDir/file.cpp")); + ICLanguageSetting ls = cfgDescription.getLanguageSettingForFile(file.getProjectRelativePath(), true); + String languageId = ls.getLanguageId(); + + // create GCCBuildCommandParser + GCCBuildCommandParser parser = (GCCBuildCommandParser) LanguageSettingsManager.getExtensionProviderCopy(GCC_BUILD_COMMAND_PARSER_EXT); + ErrorParserManager epm = new ErrorParserManager(project, null); + + // parse line + parser.startup(cfgDescription); + parser.processLine("gcc " + + " -I/BeingMappedFrom/Folder" // mapped to local folder in EFSExtensionProvider extension point + + " file.cpp", + epm); + parser.shutdown(); + + // check populated entries + List entries = parser.getSettingEntries(cfgDescription, file, languageId); + { + String device = project.getLocation().getDevice(); + assertEquals(new CIncludePathEntry(new Path("/LocallyMappedTo/Folder").setDevice(device), 0), entries.get(0)); + } + } + +} diff --git a/build/org.eclipse.cdt.make.core.tests/src/org/eclipse/cdt/make/scannerdiscovery/ScannerDiscoveryTests.java b/build/org.eclipse.cdt.make.core.tests/src/org/eclipse/cdt/make/scannerdiscovery/ScannerDiscoveryTests.java index 973802190a0..75eed421b16 100644 --- a/build/org.eclipse.cdt.make.core.tests/src/org/eclipse/cdt/make/scannerdiscovery/ScannerDiscoveryTests.java +++ b/build/org.eclipse.cdt.make.core.tests/src/org/eclipse/cdt/make/scannerdiscovery/ScannerDiscoveryTests.java @@ -1,12 +1,12 @@ /******************************************************************************* - * Copyright (c) 2007, 2009 Wind River Systems, Inc. and others. + * Copyright (c) 2007, 2009 Andrew Gvozdev 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: - * Markus Schorn - initial API and implementation + * Andrew Gvozdev - initial API and implementation *******************************************************************************/ package org.eclipse.cdt.make.scannerdiscovery; diff --git a/build/org.eclipse.cdt.make.core/plugin.xml b/build/org.eclipse.cdt.make.core/plugin.xml index 03f6d45a78a..d9ac29dfc6d 100644 --- a/build/org.eclipse.cdt.make.core/plugin.xml +++ b/build/org.eclipse.cdt.make.core/plugin.xml @@ -182,5 +182,14 @@ class="org.eclipse.cdt.make.internal.core.dataprovider.MakeConfigurationDataProvider" /> + + + + diff --git a/build/org.eclipse.cdt.make.core/src/org/eclipse/cdt/make/core/scannerconfig/AbstractBuildCommandParser.java b/build/org.eclipse.cdt.make.core/src/org/eclipse/cdt/make/core/scannerconfig/AbstractBuildCommandParser.java new file mode 100644 index 00000000000..e6a9d2de807 --- /dev/null +++ b/build/org.eclipse.cdt.make.core/src/org/eclipse/cdt/make/core/scannerconfig/AbstractBuildCommandParser.java @@ -0,0 +1,130 @@ +/******************************************************************************* + * Copyright (c) 2009, 2011 Andrew Gvozdev 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: + * Andrew Gvozdev - initial API and implementation + *******************************************************************************/ + +package org.eclipse.cdt.make.core.scannerconfig; + +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.eclipse.cdt.core.ErrorParserManager; +import org.eclipse.cdt.core.IErrorParser2; +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; + +public abstract class AbstractBuildCommandParser extends AbstractLanguageSettingsOutputScanner implements + ILanguageSettingsBuildOutputScanner { + + private static final Pattern OPTIONS_PATTERN = Pattern.compile("-[^\\s\"']*(\\s*((\".*?\")|('.*?')|([^-\\s][^\\s]+)))?"); //$NON-NLS-1$ + private static final int OPTION_GROUP = 0; + + /** + * Note: design patterns to keep file group the same and matching {@link #FILE_GROUP} + */ + @SuppressWarnings("nls") + private static final String[] PATTERN_TEMPLATES = { + "\\s*\"?${COMPILER_PATTERN}\"?.*\\s" + "()([^'\"\\s]*\\.${EXTENSIONS_PATTERN})(\\s.*)?[\r\n]*", // compiling unquoted file + "\\s*\"?${COMPILER_PATTERN}\"?.*\\s" + "(['\"])(.*\\.${EXTENSIONS_PATTERN})\\${COMPILER_GROUPS+1}(\\s.*)?[\r\n]*" // compiling quoted file + }; + private static final int FILE_GROUP = 2; + + + @SuppressWarnings("nls") + private String getCompilerCommandPattern() { + String parameter = getCustomParameter(); + return "(" + parameter + ")"; + } + + private int adjustFileGroup() { + return countGroups(getCompilerCommandPattern()) + FILE_GROUP; + } + + private String makePattern(String template) { + @SuppressWarnings("nls") + String pattern = template + .replace("${COMPILER_PATTERN}", getCompilerCommandPattern()) + .replace("${EXTENSIONS_PATTERN}", getPatternFileExtensions()) + .replace("${COMPILER_GROUPS+1}", new Integer(countGroups(getCompilerCommandPattern()) + 1).toString()); + return pattern; + } + + @Override + protected String parseForResourceName(String line) { + if (line==null) { + return null; + } + + for (String template : PATTERN_TEMPLATES) { + String pattern = makePattern(template); + Matcher fileMatcher = Pattern.compile(pattern).matcher(line); + if (fileMatcher.matches()) { + int fileGroup = adjustFileGroup(); + String sourceFileName = fileMatcher.group(fileGroup); + return sourceFileName; + } + } + return null; + } + + @Override + protected List parseForOptions(String line) { + if (line==null || currentResource==null) { + return null; + } + + List options = new ArrayList(); + Matcher optionMatcher = OPTIONS_PATTERN.matcher(line); + while (optionMatcher.find()) { + String option = optionMatcher.group(OPTION_GROUP); + if (option!=null) { + options.add(option); + } + } + return options; + } + + // This is redundant but let us keep it here to navigate in java code easier + @Override + public boolean processLine(String line, ErrorParserManager epm) { + return super.processLine(line, epm); + } + + /** + * Trivial Error Parser which allows highlighting of output lines matching the patterns + * of this parser. Intended for better troubleshooting experience. + * Implementers are supposed to add the error parser as an extension. Initialize with + * build command parser extension ID. + */ + protected static abstract class AbstractBuildCommandPatternHighlighter extends RegexErrorParser implements IErrorParser2 { + public AbstractBuildCommandPatternHighlighter(String buildCommandParserPluginExtension) { + init(buildCommandParserPluginExtension); + } + + protected void init(String buildCommandParserId) { + AbstractBuildCommandParser buildCommandParser = (AbstractBuildCommandParser) LanguageSettingsManager.getExtensionProviderCopy(buildCommandParserId); + for (String template : PATTERN_TEMPLATES) { + String pattern = buildCommandParser.makePattern(template); + String fileExpr = "$"+buildCommandParser.adjustFileGroup(); //$NON-NLS-1$ + String descExpr = "$0"; //$NON-NLS-1$ + addPattern(new RegexErrorPattern(pattern, fileExpr, null, descExpr, null, IMarkerGenerator.SEVERITY_WARNING, true)); + } + } + + public int getProcessLineBehaviour() { + return KEEP_LONGLINES; + } + } + + +} diff --git a/build/org.eclipse.cdt.make.core/src/org/eclipse/cdt/make/core/scannerconfig/AbstractLanguageSettingsOutputScanner.java b/build/org.eclipse.cdt.make.core/src/org/eclipse/cdt/make/core/scannerconfig/AbstractLanguageSettingsOutputScanner.java new file mode 100644 index 00000000000..4f30aaba5f5 --- /dev/null +++ b/build/org.eclipse.cdt.make.core/src/org/eclipse/cdt/make/core/scannerconfig/AbstractLanguageSettingsOutputScanner.java @@ -0,0 +1,821 @@ +/******************************************************************************* + * Copyright (c) 2009, 2011 Andrew Gvozdev 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: + * Andrew Gvozdev - initial API and implementation + *******************************************************************************/ + +package org.eclipse.cdt.make.core.scannerconfig; + +import java.io.File; +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.eclipse.cdt.core.ErrorParserManager; +import org.eclipse.cdt.core.language.settings.providers.LanguageSettingsSerializable; +import org.eclipse.cdt.core.model.ILanguage; +import org.eclipse.cdt.core.model.LanguageManager; +import org.eclipse.cdt.core.settings.model.ICConfigurationDescription; +import org.eclipse.cdt.core.settings.model.ICLanguageSettingEntry; +import org.eclipse.cdt.core.settings.model.ICSettingEntry; +import org.eclipse.cdt.core.settings.model.util.CDataUtil; +import org.eclipse.cdt.internal.core.XmlUtil; +import org.eclipse.cdt.make.core.MakeCorePlugin; +import org.eclipse.cdt.utils.EFSExtensionManager; +import org.eclipse.core.filesystem.EFS; +import org.eclipse.core.resources.IContainer; +import org.eclipse.core.resources.IFolder; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.IWorkspaceRoot; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Path; +import org.eclipse.core.runtime.Platform; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.content.IContentType; +import org.eclipse.core.runtime.content.IContentTypeManager; +import org.w3c.dom.Element; + +public abstract class AbstractLanguageSettingsOutputScanner extends LanguageSettingsSerializable implements + ILanguageSettingsOutputScanner { + + protected static final String ATTR_EXPAND_RELATIVE_PATHS = "expand-relative-paths"; //$NON-NLS-1$ + + protected ICConfigurationDescription currentCfgDescription = null; + protected IProject currentProject = null; + protected IResource currentResource = null; + protected String currentLanguageId = null; + + protected ErrorParserManager errorParserManager = null; + protected String parsedResourceName = null; + protected boolean isResolvingPaths = true; + + protected static abstract class AbstractOptionParser { + protected final Pattern pattern; + protected final String patternStr; + protected String nameExpression; + protected String valueExpression; + protected int extraFlag = 0; + protected int kind = 0; + private String parsedName; + private String parsedValue; + + public AbstractOptionParser(int kind, String pattern, String nameExpression, String valueExpression, int extraFlag) { + this.kind = kind; + this.patternStr = pattern; + this.nameExpression = nameExpression; + this.valueExpression = valueExpression; + this.extraFlag = extraFlag; + + this.pattern = Pattern.compile(pattern); + } + + public ICLanguageSettingEntry createEntry(String name, String value, int flag) { + return (ICLanguageSettingEntry) CDataUtil.createEntry(kind, name, value, null, flag | extraFlag); + } + + /** + * TODO: explain + */ + protected String extractOption(String input) { + @SuppressWarnings("nls") + String option = input.replaceFirst("(" + patternStr + ").*", "$1"); + return option; + } + + protected String parseStr(Matcher matcher, String str) { + if (str != null) + return matcher.replaceAll(str); + return null; + } + + protected boolean isPathKind() { + return kind == ICSettingEntry.INCLUDE_PATH || kind == ICSettingEntry.INCLUDE_FILE + || kind == ICSettingEntry.MACRO_FILE || kind == ICSettingEntry.LIBRARY_PATH; + } + + public boolean parseOption(String option) { + String opt = extractOption(option); + Matcher matcher = pattern.matcher(opt); + boolean isMatch = matcher.matches(); + if (isMatch) { + parsedName = parseStr(matcher, nameExpression); + parsedValue = parseStr(matcher, valueExpression); + } + return isMatch; + } + + } + + protected static class IncludePathOptionParser extends AbstractOptionParser { + public IncludePathOptionParser(String pattern, String nameExpression) { + super(ICLanguageSettingEntry.INCLUDE_PATH, pattern, nameExpression, nameExpression, 0); + } + public IncludePathOptionParser(String pattern, String nameExpression, int extraFlag) { + super(ICLanguageSettingEntry.INCLUDE_PATH, pattern, nameExpression, nameExpression, extraFlag); + } + } + + protected static class IncludeFileOptionParser extends AbstractOptionParser { + public IncludeFileOptionParser(String pattern, String nameExpression) { + super(ICLanguageSettingEntry.INCLUDE_FILE, pattern, nameExpression, nameExpression, 0); + } + public IncludeFileOptionParser(String pattern, String nameExpression, int extraFlag) { + super(ICLanguageSettingEntry.INCLUDE_FILE, pattern, nameExpression, nameExpression, extraFlag); + } + } + + protected static class MacroOptionParser extends AbstractOptionParser { + public MacroOptionParser(String pattern, String nameExpression, String valueExpression) { + super(ICLanguageSettingEntry.MACRO, pattern, nameExpression, valueExpression, 0); + } + public MacroOptionParser(String pattern, String nameExpression, String valueExpression, int extraFlag) { + super(ICLanguageSettingEntry.MACRO, pattern, nameExpression, valueExpression, extraFlag); + } + public MacroOptionParser(String pattern, String nameExpression, int extraFlag) { + super(ICLanguageSettingEntry.MACRO, pattern, nameExpression, null, extraFlag); + } + } + + protected static class MacroFileOptionParser extends AbstractOptionParser { + public MacroFileOptionParser(String pattern, String nameExpression) { + super(ICLanguageSettingEntry.MACRO_FILE, pattern, nameExpression, nameExpression, 0); + } + public MacroFileOptionParser(String pattern, String nameExpression, int extraFlag) { + super(ICLanguageSettingEntry.MACRO_FILE, pattern, nameExpression, nameExpression, extraFlag); + } + } + + protected static class LibraryPathOptionParser extends AbstractOptionParser { + public LibraryPathOptionParser(String pattern, String nameExpression) { + super(ICLanguageSettingEntry.LIBRARY_PATH, pattern, nameExpression, nameExpression, 0); + } + public LibraryPathOptionParser(String pattern, String nameExpression, int extraFlag) { + super(ICLanguageSettingEntry.LIBRARY_PATH, pattern, nameExpression, nameExpression, extraFlag); + } + } + + protected static class LibraryFileOptionParser extends AbstractOptionParser { + public LibraryFileOptionParser(String pattern, String nameExpression) { + super(ICLanguageSettingEntry.LIBRARY_FILE, pattern, nameExpression, nameExpression, 0); + } + public LibraryFileOptionParser(String pattern, String nameExpression, int extraFlag) { + super(ICLanguageSettingEntry.LIBRARY_FILE, pattern, nameExpression, nameExpression, extraFlag); + } + } + + /** + * Parse the line returning the resource name as appears in the output. + * This is the resource where {@link ICLanguageSettingEntry} list is being added. + * + * @param line - one input line from the output stripped from end of line characters. + * @return the resource name as appears in the output or {@code null}. + * Note that {@code null} can have different semantics and can mean "no resource found" + * or "applicable to any resource". By default "no resource found" is used in this + * abstract class but extenders can handle otherwise. + */ + protected abstract String parseForResourceName(String line); + + /** + * Parse the line returning the list of substrings to be treated each as input to + * the option parsers. It is assumed that each substring presents one + * {@link ICLanguageSettingEntry} (for example compiler options {@code -I/path} or + * {@code -DMACRO=1}. + * + * @param line - one input line from the output stripped from end of line characters. + * @return list of substrings representing language settings entries. + */ + protected abstract List parseForOptions(String line); + + /** + * @return array of option parsers defining how to parse a string to + * {@link ICLanguageSettingEntry}. + * See {@link AbstractOptionParser} and its specific extenders. + */ + protected abstract AbstractOptionParser[] getOptionParsers(); + + public boolean isResolvingPaths() { + return isResolvingPaths; + } + + public void setResolvingPaths(boolean resolvePaths) { + this.isResolvingPaths = resolvePaths; + } + + + public void startup(ICConfigurationDescription cfgDescription) throws CoreException { + currentCfgDescription = cfgDescription; + currentProject = cfgDescription != null ? cfgDescription.getProjectDescription().getProject() : null; + } + + public boolean processLine(String line) { + return processLine(line, null); + } + + public void shutdown() { + } + + public boolean processLine(String line, ErrorParserManager epm) { + errorParserManager = epm; + parsedResourceName = parseForResourceName(line); + + currentLanguageId = determineLanguage(parsedResourceName); + if (!isLanguageInScope(currentLanguageId)) + return false; + + currentResource = findResource(parsedResourceName); + + /** + * Where source tree starts if mapped. This kind of mapping is useful for example in cases when + * the absolute path to the source file on the remote system is simulated inside a project in the + * workspace. + */ + URI mappedRootURI = null; + URI buildDirURI = null; + + if (isResolvingPaths) { + if (currentResource!=null) { + mappedRootURI = getMappedRootURI(currentResource, parsedResourceName); + } + buildDirURI = getBuildDirURI(mappedRootURI); + } + + List entries = new ArrayList(); + + List options = parseForOptions(line); + if (options!=null) { + for (String option : options) { + for (AbstractOptionParser optionParser : getOptionParsers()) { + try { + if (optionParser.parseOption(option)) { + ICLanguageSettingEntry entry = null; + if (isResolvingPaths && optionParser.isPathKind()) { + URI baseURI = new Path(optionParser.parsedName).isAbsolute() ? mappedRootURI : buildDirURI; + entry = createResolvedPathEntry(optionParser, optionParser.parsedName, 0, baseURI); + } else { + entry = optionParser.createEntry(optionParser.parsedName, optionParser.parsedValue, 0); + } + + if (entry != null && !entries.contains(entry)) { + entries.add(entry); + break; + } + } + } catch (Throwable e) { + // protect from rogue parsers extending this class + MakeCorePlugin.log(e); + } + } + } + if (entries.size() > 0) { + setSettingEntries(entries); + } else { + setSettingEntries(null); + } + } + return false; + } + + protected void setSettingEntries(List entries) { + setSettingEntries(currentCfgDescription, currentResource, currentLanguageId, entries); + + // TODO - for debugging only, eventually remove + IStatus status = new Status(IStatus.INFO, MakeCorePlugin.PLUGIN_ID, getClass().getSimpleName() + + " collected " + (entries!=null ? ("" + entries.size()) : "null") + " entries for " + currentResource); + MakeCorePlugin.log(status); + } + + protected String determineLanguage(String parsedResourceName) { + if (parsedResourceName==null) + return null; + + String fileName = new Path(parsedResourceName).lastSegment().toString(); + IContentTypeManager manager = Platform.getContentTypeManager(); + IContentType contentType = manager.findContentTypeFor(fileName); + if (contentType==null) + return null; + + ILanguage lang = LanguageManager.getInstance().getLanguage(contentType); + if (lang==null) + return null; + + return lang.getId(); + } + + protected boolean isLanguageInScope(String languageId) { + List languageIds = getLanguageScope(); + return languageIds == null || languageIds.contains(languageId); + } + + protected String getPatternFileExtensions() { + IContentTypeManager manager = Platform.getContentTypeManager(); + + Set fileExts = new HashSet(); + + IContentType contentTypeCpp = manager.getContentType("org.eclipse.cdt.core.cxxSource"); //$NON-NLS-1$ + fileExts.addAll(Arrays.asList(contentTypeCpp.getFileSpecs(IContentType.FILE_EXTENSION_SPEC))); + + IContentType contentTypeC = manager.getContentType("org.eclipse.cdt.core.cSource"); //$NON-NLS-1$ + fileExts.addAll(Arrays.asList(contentTypeC.getFileSpecs(IContentType.FILE_EXTENSION_SPEC))); + + String pattern = expressionLogicalOr(fileExts); + + return pattern; + } + + private ICLanguageSettingEntry createResolvedPathEntry(AbstractOptionParser optionParser, + String parsedPath, int flag, URI baseURI) { + + ICLanguageSettingEntry entry; + String resolvedPath = null; + + URI uri = determineURI(parsedPath, baseURI); + IResource rc = null; + if (uri != null && uri.isAbsolute()) { + rc = findResourceForLocationURI(uri, optionParser.kind, currentProject); + } + if (rc != null) { + IPath path = rc.getFullPath(); + resolvedPath = path.toString(); + flag = flag | ICSettingEntry.VALUE_WORKSPACE_PATH | ICSettingEntry.RESOLVED; + } else { + IPath path = getFilesystemLocation(uri); + if (path != null && new File(path.toString()).exists()) { + resolvedPath = path.toString(); + } + if (resolvedPath == null) { + Set referencedProjectsNames = new LinkedHashSet(); + if (currentCfgDescription!=null) { + Map refs = currentCfgDescription.getReferenceInfo(); + referencedProjectsNames.addAll(refs.keySet()); + } + IResource resource = resolveResourceInWorkspace(parsedPath, currentProject, referencedProjectsNames); + if (resource != null) { + path = resource.getFullPath(); + resolvedPath = path.toString(); + flag = flag | ICSettingEntry.VALUE_WORKSPACE_PATH | ICSettingEntry.RESOLVED; + } + } + if (resolvedPath==null && path!=null) { + resolvedPath = path.toString(); + } + } + + if (resolvedPath==null) { + resolvedPath = parsedPath; + } + + entry = optionParser.createEntry(resolvedPath, resolvedPath, flag); + return entry; + } + + private IResource findResource(String parsedResourceName) { + if (parsedResourceName==null) + return null; + + IResource sourceFile = null; + + // try ErrorParserManager + if (errorParserManager != null) { + sourceFile = errorParserManager.findFileName(parsedResourceName); + } + // try to find absolute path in the workspace + if (sourceFile == null && new Path(parsedResourceName).isAbsolute()) { + URI uri = org.eclipse.core.filesystem.URIUtil.toURI(parsedResourceName); + sourceFile = findFileForLocationURI(uri, currentProject); + } + // try path relative to build dir from configuration + if (sourceFile == null && currentCfgDescription != null) { + IPath builderCWD = currentCfgDescription.getBuildSetting().getBuilderCWD(); + if (builderCWD!=null) { + IPath path = builderCWD.append(parsedResourceName); + URI uri = org.eclipse.core.filesystem.URIUtil.toURI(path); + sourceFile = findFileForLocationURI(uri, currentProject); + } + } + // try path relative to the project + if (sourceFile == null && currentProject != null) { + sourceFile = currentProject.findMember(parsedResourceName); + } + return sourceFile; + } + + private URI getBuildDirURI(URI mappedRootURI) { + URI buildDirURI = null; + + URI cwdURI = null; + if (currentResource!=null && parsedResourceName!=null && !new Path(parsedResourceName).isAbsolute()) { + cwdURI = findBaseLocationURI(currentResource.getLocationURI(), parsedResourceName); + } + if (cwdURI == null && errorParserManager != null) { + cwdURI = errorParserManager.getWorkingDirectoryURI(); + } + + String cwdPath = cwdURI != null ? EFSExtensionManager.getDefault().getPathFromURI(cwdURI) : null; + if (cwdPath != null && mappedRootURI != null) { + buildDirURI = EFSExtensionManager.getDefault().append(mappedRootURI, cwdPath); + } else { + buildDirURI = cwdURI; + } + + if (buildDirURI == null && currentCfgDescription != null) { + IPath builderCWD = currentCfgDescription.getBuildSetting().getBuilderCWD(); + buildDirURI = org.eclipse.core.filesystem.URIUtil.toURI(builderCWD); + } + + if (buildDirURI == null && currentProject != null) { + buildDirURI = currentProject.getLocationURI(); + } + + if (buildDirURI == null && currentResource != null) { + IContainer container; + if (currentResource instanceof IContainer) { + container = (IContainer) currentResource; + } else { + container = currentResource.getParent(); + } + buildDirURI = container.getLocationURI(); + } + return buildDirURI; + } + + /** + * Determine URI appending to baseURI when possible. + * + * @param pathStr - path to the resource, can be absolute or relative + * @param baseURI - base {@link URI} where path to the resource is rooted + * @return {@link URI} of the resource + */ + private static URI determineURI(String pathStr, URI baseURI) { + URI uri = null; + + if (baseURI==null) { + if (new Path(pathStr).isAbsolute()) { + uri = resolvePathFromBaseLocation(pathStr, Path.ROOT); + } + } else if (baseURI.getScheme().equals(EFS.SCHEME_FILE)) { + // location on the local filesystem + IPath baseLocation = org.eclipse.core.filesystem.URIUtil.toPath(baseURI); + // careful not to use Path here but 'pathStr' as String as we want to properly navigate symlinks + uri = resolvePathFromBaseLocation(pathStr, baseLocation); + } else { + // use canonicalized path here, in particular replace all '\' with '/' for Windows paths + Path path = new Path(pathStr); + uri = EFSExtensionManager.getDefault().append(baseURI, path.toString()); + } + + if (uri == null) { + // if everything fails just wrap string to URI + uri = org.eclipse.core.filesystem.URIUtil.toURI(pathStr); + } + return uri; + } + + private static IResource resolveResourceInWorkspace(String parsedName, IProject preferredProject, Set referencedProjectsNames) { + IPath path = new Path(parsedName); + if (path.equals(new Path(".")) || path.equals(new Path(".."))) { //$NON-NLS-1$ //$NON-NLS-2$ + return null; + } + + // prefer current project + if (preferredProject!=null) { + List result = findPathInFolder(path, preferredProject); + int size = result.size(); + if (size==1) { // found the one + return result.get(0); + } else if (size>1) { // ambiguous + return null; + } + } + + IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot(); + + // then prefer referenced projects + if (referencedProjectsNames.size() > 0) { + IResource rc = null; + for (String prjName : referencedProjectsNames) { + IProject prj = root.getProject(prjName); + if (prj.isOpen()) { + List result = findPathInFolder(path, prj); + int size = result.size(); + if (size==1 && rc==null) { + rc = result.get(0); + } else if (size > 0) { + // ambiguous + rc = null; + break; + } + } + } + if (rc!=null) { + return rc; + } + } + + // then check all other projects in workspace + IProject[] projects = root.getProjects(); + if (projects.length > 0) { + IResource rc = null; + for (IProject prj : projects) { + if (!prj.equals(preferredProject) && !referencedProjectsNames.contains(prj.getName()) && prj.isOpen()) { + List result = findPathInFolder(path, prj); + int size = result.size(); + if (size==1 && rc==null) { + rc = result.get(0); + } else if (size > 0) { + // ambiguous + rc = null; + break; + } + } + } + if (rc!=null) { + return rc; + } + } + + // not found or ambiguous + return null; + } + + private static List findPathInFolder(IPath path, IContainer folder) { + List paths = new ArrayList(); + IResource resource = folder.findMember(path); + if (resource != null) { + paths.add(resource); + } + + try { + for (IResource res : folder.members()) { + if (res instanceof IContainer) { + paths.addAll(findPathInFolder(path, (IContainer) res)); + } + } + } catch (CoreException e) { + // ignore + } + + return paths; + } + + private static IResource findFileForLocationURI(URI uri, IProject preferredProject) { + IResource sourceFile; + IResource result = null; + IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot(); + IResource[] resources = root.findFilesForLocationURI(uri); + if (resources.length > 0) { + result = resources[0]; + if (preferredProject!=null) { + for (IResource rc : resources) { + if (rc.getProject().equals(preferredProject)) { + result = rc; + break; + } + } + } + } + sourceFile = result; + return sourceFile; + } + + private static URI findBaseLocationURI(URI fileURI, String relativeFileName) { + URI cwdURI = null; + String path = fileURI.getPath(); + + String[] segments = relativeFileName.split("[/\\\\]"); //$NON-NLS-1$ + + // start removing segments from the end of the path + for (int i = segments.length - 1; i >= 0; i--) { + String lastSegment = segments[i]; + if (lastSegment.length() > 0 && !lastSegment.equals(".")) { //$NON-NLS-1$ + if (lastSegment.equals("..")) { //$NON-NLS-1$ + // navigating ".." in the other direction is ambiguous, bailing out + return null; + } else { + if (path.endsWith("/" + lastSegment)) { //$NON-NLS-1$ + int pos = path.lastIndexOf(lastSegment); + path = path.substring(0, pos); + continue; + } else { + // ouch, relativeFileName does not match fileURI, bailing out + return null; + } + } + } + } + + try { + cwdURI = new URI(fileURI.getScheme(), fileURI.getUserInfo(), fileURI.getHost(), + fileURI.getPort(), path, fileURI.getQuery(), fileURI.getFragment()); + } catch (URISyntaxException e) { + // It should be valid URI here or something is wrong + MakeCorePlugin.log(e); + } + + return cwdURI; + } + + /** + * In case when absolute path is mapped to the source tree in a project + * this function will try to figure mapping and return "mapped root", + * i.e URI where the root path would be mapped. The mapped root will be + * used to prepend to other "absolute" paths where appropriate. + * + * @param sourceFile - a resource referred by parsed path + * @param parsedResourceName - path as appears in the output + * @return mapped path as URI + */ + private static URI getMappedRootURI(IResource sourceFile, String parsedResourceName) { + URI fileURI = sourceFile.getLocationURI(); + String mappedRoot = "/"; //$NON-NLS-1$ + + if (parsedResourceName!=null) { + IPath parsedSrcPath = new Path(parsedResourceName); + if (parsedSrcPath.isAbsolute()) { + IPath absPath = sourceFile.getLocation(); + int absSegmentsCount = absPath.segmentCount(); + int relSegmentsCount = parsedSrcPath.segmentCount(); + if (absSegmentsCount >= relSegmentsCount) { + IPath ending = absPath.removeFirstSegments(absSegmentsCount - relSegmentsCount); + ending = ending.setDevice(parsedSrcPath.getDevice()).makeAbsolute(); + if (ending.equals(parsedSrcPath.makeAbsolute())) { + mappedRoot = absPath.removeLastSegments(relSegmentsCount).toString(); + } + } + } + } + URI uri = EFSExtensionManager.getDefault().createNewURIFromPath(fileURI, mappedRoot); + return uri; + } + + /** + * The manipulations here are done to resolve "../" navigation for symbolic links where "link/.." cannot + * be collapsed as it must follow the real filesystem path. {@link java.io.File#getCanonicalPath()} deals + * with that correctly but {@link Path} or {@link URI} try to normalize the path which would be incorrect + * here. + */ + private static URI resolvePathFromBaseLocation(String name, IPath baseLocation) { + String pathName = name; + if (baseLocation != null && !baseLocation.isEmpty()) { + String device = new Path(pathName).getDevice(); + if (device != null && device.length() > 0) { + pathName = pathName.substring(device.length()); + } + pathName = pathName.replace(File.separatorChar, '/'); + + baseLocation = baseLocation.addTrailingSeparator(); + if (pathName.startsWith("/")) { //$NON-NLS-1$ + pathName = pathName.substring(1); + } + pathName = baseLocation.toString() + pathName; + } + + try { + File file = new File(pathName); + file = file.getCanonicalFile(); + return file.toURI(); + } catch (IOException e) { + // if error just leave it as is + } + + URI uri = org.eclipse.core.filesystem.URIUtil.toURI(pathName); + return uri; + } + + private static IResource findResourceForLocationURI(URI uri, int kind, IProject preferredProject) { + if (uri==null) + return null; + + IResource resource = null; + + switch (kind) { + case ICSettingEntry.INCLUDE_PATH: + case ICSettingEntry.LIBRARY_PATH: + resource = findContainerForLocationURI(uri, preferredProject); + break; + case ICSettingEntry.INCLUDE_FILE: + case ICSettingEntry.MACRO_FILE: + resource = findFileForLocationURI(uri, preferredProject); + break; + } + + return resource; + } + + private static IResource findContainerForLocationURI(URI uri, IProject preferredProject) { + IResource resource = null; + IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot(); + IResource[] resources = root.findContainersForLocationURI(uri); + if (resources.length > 0) { + for (IResource rc : resources) { + if ((rc instanceof IProject || rc instanceof IFolder)) { // treat IWorkspaceRoot as non-workspace path + IProject prj = rc instanceof IProject ? (IProject)rc : rc.getProject(); + if (prj.equals(preferredProject)) { + resource = rc; + break; + } + if (resource==null) { + resource=rc; // to be deterministic the first qualified resource has preference + } + } + } + } + return resource; + } + + private static IPath getFilesystemLocation(URI uri) { + if (uri==null) + return null; + + // EFSExtensionManager mapping + String pathStr = EFSExtensionManager.getDefault().getMappedPath(uri); + uri = org.eclipse.core.filesystem.URIUtil.toURI(pathStr); + + try { + File file = new java.io.File(uri); + String canonicalPathStr = file.getCanonicalPath(); + return new Path(canonicalPathStr); + } catch (Exception e) { + MakeCorePlugin.log(e); + } + return null; + } + + @SuppressWarnings("nls") + private static String expressionLogicalOr(Set fileExts) { + String pattern = "("; + for (String ext : fileExts) { + if (pattern.length() != 1) + pattern += "|"; + pattern += "(" + Pattern.quote(ext) + ")"; + ext = ext.toUpperCase(); + if (!fileExts.contains(ext)) { + pattern += "|(" + Pattern.quote(ext) + ")"; + } + } + pattern += ")"; + return pattern; + } + + protected static int countGroups(String str) { + @SuppressWarnings("nls") + int count = str.replaceAll("[^\\(]", "").length(); + return count; + } + + @Override + public Element serialize(Element parentElement) { + Element elementProvider = super.serialize(parentElement); + elementProvider.setAttribute(ATTR_EXPAND_RELATIVE_PATHS, Boolean.toString(isResolvingPaths)); + return elementProvider; + } + + @Override + public void load(Element providerNode) { + super.load(providerNode); + + String expandRelativePathsValue = XmlUtil.determineAttributeValue(providerNode, ATTR_EXPAND_RELATIVE_PATHS); + if (expandRelativePathsValue!=null) + isResolvingPaths = Boolean.parseBoolean(expandRelativePathsValue); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = super.hashCode(); + result = prime * result + (isResolvingPaths ? 1231 : 1237); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (!super.equals(obj)) + return false; + if (getClass() != obj.getClass()) + return false; + AbstractLanguageSettingsOutputScanner other = (AbstractLanguageSettingsOutputScanner) obj; + if (isResolvingPaths != other.isResolvingPaths) + return false; + return true; + } + +} diff --git a/build/org.eclipse.cdt.make.core/src/org/eclipse/cdt/make/core/scannerconfig/GCCBuildCommandParser.java b/build/org.eclipse.cdt.make.core/src/org/eclipse/cdt/make/core/scannerconfig/GCCBuildCommandParser.java new file mode 100644 index 00000000000..1594c0b1898 --- /dev/null +++ b/build/org.eclipse.cdt.make.core/src/org/eclipse/cdt/make/core/scannerconfig/GCCBuildCommandParser.java @@ -0,0 +1,72 @@ +/******************************************************************************* + * Copyright (c) 2009, 2011 Andrew Gvozdev 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: + * Andrew Gvozdev - initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.make.core.scannerconfig; + + +import org.eclipse.cdt.core.errorparsers.RegexErrorPattern; +import org.eclipse.cdt.core.settings.model.ICSettingEntry; +import org.eclipse.cdt.core.settings.model.ILanguageSettingsEditableProvider; + +public class GCCBuildCommandParser extends AbstractBuildCommandParser implements + ILanguageSettingsEditableProvider { + @SuppressWarnings("nls") + static final AbstractOptionParser[] optionParsers = { + new IncludePathOptionParser("-I\\s*([\"'])(.*)\\1", "$2"), + new IncludePathOptionParser("-I\\s*([^\\s\"']*)", "$1"), + new IncludeFileOptionParser("-include\\s*([\"'])(.*)\\1", "$2"), + new IncludeFileOptionParser("-include\\s*([^\\s\"']*)", "$1"), + new MacroOptionParser("-D\\s*([\"'])([^=]*)(=(.*))?\\1", "$2", "$4"), + new MacroOptionParser("-D\\s*([^\\s=\"']*)=(\\\\([\"']))(.*?)\\2", "$1", "$3$4$3"), + new MacroOptionParser("-D\\s*([^\\s=\"']*)=([\"'])(.*?)\\2", "$1", "$3"), + new MacroOptionParser("-D\\s*([^\\s=\"']*)(=([^\\s\"']*))?", "$1", "$3"), + new MacroOptionParser("-U\\s*([^\\s=\"']*)", "$1", ICSettingEntry.UNDEFINED), + new MacroFileOptionParser("-macros\\s*([\"'])(.*)\\1", "$2"), + new MacroFileOptionParser("-macros\\s*([^\\s\"']*)", "$1"), + new LibraryPathOptionParser("-L\\s*([\"'])(.*)\\1", "$2"), + new LibraryPathOptionParser("-L\\s*([^\\s\"']*)", "$1"), + new LibraryFileOptionParser("-l\\s*([^\\s\"']*)", "lib$1.a"), }; + + @Override + protected AbstractOptionParser[] getOptionParsers() { + return optionParsers; + } + + @Override + public GCCBuildCommandParser cloneShallow() throws CloneNotSupportedException { + return (GCCBuildCommandParser) super.cloneShallow(); + } + + @Override + public GCCBuildCommandParser clone() throws CloneNotSupportedException { + return (GCCBuildCommandParser) super.clone(); + } + + public static class GCCBuildCommandPatternHighlighter extends AbstractBuildCommandParser.AbstractBuildCommandPatternHighlighter { + // ID of the parser taken from the extension point + private static final String GCC_BUILD_COMMAND_PARSER_EXT = "org.eclipse.cdt.make.core.build.command.parser.gcc"; //$NON-NLS-1$ + + public GCCBuildCommandPatternHighlighter() { + super(GCC_BUILD_COMMAND_PARSER_EXT); + } + + @Override + public Object clone() throws CloneNotSupportedException { + GCCBuildCommandPatternHighlighter that = new GCCBuildCommandPatternHighlighter(); + that.setId(getId()); + that.setName(getName()); + for (RegexErrorPattern pattern : getPatterns()) { + that.addPattern((RegexErrorPattern)pattern.clone()); + } + return that; + } + } + +} diff --git a/build/org.eclipse.cdt.make.core/src/org/eclipse/cdt/make/core/scannerconfig/ILanguageSettingsBuildOutputScanner.java b/build/org.eclipse.cdt.make.core/src/org/eclipse/cdt/make/core/scannerconfig/ILanguageSettingsBuildOutputScanner.java new file mode 100644 index 00000000000..51615891c53 --- /dev/null +++ b/build/org.eclipse.cdt.make.core/src/org/eclipse/cdt/make/core/scannerconfig/ILanguageSettingsBuildOutputScanner.java @@ -0,0 +1,29 @@ +/******************************************************************************* + * Copyright (c) 2011, 2011 Andrew Gvozdev 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: + * Andrew Gvozdev - initial API and implementation + *******************************************************************************/ + +package org.eclipse.cdt.make.core.scannerconfig; + +import org.eclipse.cdt.core.ErrorParserManager; +import org.eclipse.cdt.core.IErrorParser; +import org.eclipse.cdt.internal.core.ConsoleOutputSniffer; + +/** + * Note: IErrorParser interface is used here to work around {@link ConsoleOutputSniffer} having + * no access from CDT core to build packages. + */ +public interface ILanguageSettingsBuildOutputScanner extends ILanguageSettingsOutputScanner, IErrorParser { + + /** + * This method is expected to populate this.settingEntries with specific values + * parsed from supplied lines. + */ + public boolean processLine(String line, ErrorParserManager epm); +} diff --git a/build/org.eclipse.cdt.make.core/src/org/eclipse/cdt/make/core/scannerconfig/ILanguageSettingsBuiltinSpecsDetector.java b/build/org.eclipse.cdt.make.core/src/org/eclipse/cdt/make/core/scannerconfig/ILanguageSettingsBuiltinSpecsDetector.java new file mode 100644 index 00000000000..e094fb18dc6 --- /dev/null +++ b/build/org.eclipse.cdt.make.core/src/org/eclipse/cdt/make/core/scannerconfig/ILanguageSettingsBuiltinSpecsDetector.java @@ -0,0 +1,28 @@ +/******************************************************************************* + * Copyright (c) 2011, 2011 Andrew Gvozdev 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: + * Andrew Gvozdev - initial API and implementation + *******************************************************************************/ + +package org.eclipse.cdt.make.core.scannerconfig; + +import java.io.IOException; +import java.util.List; + +import org.eclipse.cdt.core.language.settings.providers.ILanguageSettingsProvider; +import org.eclipse.cdt.core.settings.model.ICConfigurationDescription; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.IProgressMonitor; + +public interface ILanguageSettingsBuiltinSpecsDetector extends ILanguageSettingsProvider { + public List getLanguageScope(); + public void run(IProject project, String languageId, IPath workingDirectory, String[] env, IProgressMonitor monitor) throws CoreException, IOException; + public void run(ICConfigurationDescription cfgDescription, String languageId, IPath workingDirectory, String[] env, IProgressMonitor monitor) throws CoreException, IOException; +} diff --git a/build/org.eclipse.cdt.make.core/src/org/eclipse/cdt/make/core/scannerconfig/ILanguageSettingsOutputScanner.java b/build/org.eclipse.cdt.make.core/src/org/eclipse/cdt/make/core/scannerconfig/ILanguageSettingsOutputScanner.java new file mode 100644 index 00000000000..642322f2d36 --- /dev/null +++ b/build/org.eclipse.cdt.make.core/src/org/eclipse/cdt/make/core/scannerconfig/ILanguageSettingsOutputScanner.java @@ -0,0 +1,35 @@ +/******************************************************************************* + * Copyright (c) 2009, 2009 Andrew Gvozdev (Quoin Inc.) 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: + * Andrew Gvozdev (Quoin Inc.) - initial API and implementation + *******************************************************************************/ + +package org.eclipse.cdt.make.core.scannerconfig; + +import java.util.List; + +import org.eclipse.cdt.core.ICConsoleParser; +import org.eclipse.cdt.core.language.settings.providers.ILanguageSettingsProvider; +import org.eclipse.cdt.core.settings.model.ICConfigurationDescription; +import org.eclipse.cdt.core.settings.model.ICLanguageSettingEntry; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.runtime.CoreException; + +/** + * TODO: Is this interface superfluous? + */ +public interface ILanguageSettingsOutputScanner extends ILanguageSettingsProvider, ICConsoleParser { + + // Inherited from ICConsoleParser + public void startup(ICConfigurationDescription cfgDescription) throws CoreException; + public boolean processLine(String line); + public void shutdown(); + + // Inherited from ICLanguageSettingsProvider + public List getSettingEntries(ICConfigurationDescription cfgDescription, IResource rc, String languageId); +} diff --git a/build/org.eclipse.cdt.make.ui/icons/obj16/inspect_system.gif b/build/org.eclipse.cdt.make.ui/icons/obj16/inspect_system.gif new file mode 100644 index 0000000000000000000000000000000000000000..d68100a748898719a2c9a143ac0d6763ebde2f5e GIT binary patch literal 553 zcmZ?wbhEHb6krfwIOf9;Vr7!!r&8(f(3F=qCo81AAgiM=v!gJpt1zRzxUjRNps~HJ zu4DSF_J%nf^=-XV+WKeD=_{EuwXb*Dl9|(H&YxK{XJ*Zu8Pg`sTDWXp{+@X@3l>ga zv#4O{lBpY)mo8eddC{t^TUXa^TGP30P5qiR3)ZilyL#QqEt_Vo-?DfAj)_}$Y}vf? z;I=(ScJDv1fB&u{2iN}DXLIoIiDO5$A3ApO%!y4GPOZIo>D;9&*REbYclr9Qn>TO$ zxfgT)?uA?T9^AeE@X_NZ&z?Pd@#4k%cdtKv`t;??m+xObfByRQ&%Zg}zJLGo>&x%o zzyJOF_kR!r#h)yU3=H)QIt)MniW3L+wubtq=9bnbHCnQMuxbn?E#L3)ZDx;_@r#aum z$dP4>x0jP>o2@27^AWxvl)hmM=8bB*YIHYRDTl@iK87YGY** L`SDqVgTWdAt^i(L literal 0 HcmV?d00001 diff --git a/build/org.eclipse.cdt.make.ui/icons/obj16/log_obj.gif b/build/org.eclipse.cdt.make.ui/icons/obj16/log_obj.gif new file mode 100644 index 0000000000000000000000000000000000000000..aebeab820d82ab024a82b9e03c4b284b4e2f0a48 GIT binary patch literal 335 zcmZ?wbhEHb6krfwSgOR(F=0i+i~}=fOq?}q!o1nN9SaUDn%A{#Vf%_jZL1fztX7DfgJdj=f_AOQKvfi362{8SH}s5+07 zrH6COgguw2x~z?Io{*wEIZ}k_&Ibjny>aTEr_;~oSudJ+_LwvS!;`ib{Dm)n{})e5 z3(Lq1DJf$J70Ogl=qT%p%#@QWnL2|fP()_#ym{*RNf? z`oQk}`*!YKK6~ljZF_cZ+HvgAv6IJ69zSyY;J$;WPMkV&@Th0*!vFtI{{R2)-9{Q{xYzi!ojzd!Hm)rnuOPWpOf;{Cn#PZn9eTp#{=Q|#Kl_?H9)`m^Y_v_E|osjQ0xhPeU?V7 zFYefq7px@erW32aOhZI~o1e+F);Uj8NSKj>%P7ZHO;TK&kDY#h literal 0 HcmV?d00001 diff --git a/build/org.eclipse.cdt.make.ui/plugin.properties b/build/org.eclipse.cdt.make.ui/plugin.properties index 21b341f00ec..4db795b46c4 100644 --- a/build/org.eclipse.cdt.make.ui/plugin.properties +++ b/build/org.eclipse.cdt.make.ui/plugin.properties @@ -44,6 +44,9 @@ PreferenceBuildSettings.name=Settings ErrorParsersTab.name=Error Parsers ErrorParsersTab.tooltip=Error Parsers scan build output and report errors in Problems view +LanguageSettingsProvidersTab.name=Discovery +LanguageSettingsProvidersTab.tooltip=Language settings providers + PreferenceMakeProject.name=New Make Projects PreferenceMake.name=Make Targets PreferenceMakefileEditor.name=Makefile Editor diff --git a/build/org.eclipse.cdt.make.ui/plugin.xml b/build/org.eclipse.cdt.make.ui/plugin.xml index 002d57859e9..c9c87cb44f6 100644 --- a/build/org.eclipse.cdt.make.ui/plugin.xml +++ b/build/org.eclipse.cdt.make.ui/plugin.xml @@ -470,6 +470,14 @@ tooltip="%ErrorParsersTab.tooltip" weight="020"> + + + + + + + + + + + + + + diff --git a/build/org.eclipse.cdt.make.ui/src/org/eclipse/cdt/make/internal/ui/preferences/GCCBuildCommandParserOptionPage.java b/build/org.eclipse.cdt.make.ui/src/org/eclipse/cdt/make/internal/ui/preferences/GCCBuildCommandParserOptionPage.java new file mode 100644 index 00000000000..d5bf8f74541 --- /dev/null +++ b/build/org.eclipse.cdt.make.ui/src/org/eclipse/cdt/make/internal/ui/preferences/GCCBuildCommandParserOptionPage.java @@ -0,0 +1,370 @@ +/******************************************************************************* + * Copyright (c) 2009, 2010 Andrew Gvozdev 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: + * Andrew Gvozdev - Initial API and implementation + *******************************************************************************/ + +package org.eclipse.cdt.make.internal.ui.preferences; + +import org.eclipse.cdt.core.language.settings.providers.ILanguageSettingsProvider; +import org.eclipse.cdt.core.language.settings.providers.LanguageSettingsManager; +import org.eclipse.cdt.internal.ui.language.settings.providers.AbstractLanguageSettingProviderOptionPage; +import org.eclipse.cdt.internal.ui.newui.StatusMessageLine; +import org.eclipse.cdt.make.core.scannerconfig.AbstractBuildCommandParser; +import org.eclipse.cdt.utils.ui.controls.ControlFactory; +import org.eclipse.core.runtime.Assert; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.jface.dialogs.Dialog; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.ModifyEvent; +import org.eclipse.swt.events.ModifyListener; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +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; + +/** + * Options page for TODO + * + */ +public final class GCCBuildCommandParserOptionPage extends AbstractLanguageSettingProviderOptionPage { + private boolean fEditable; + + private Text inputCommand; + + private StatusMessageLine fStatusLine; + private Button runOnceRadioButton; + private Button runEveryBuildRadioButton; + private Button expandRelativePathCheckBox; + private Button applyToProjectCheckBox; + + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.dialogs.IDialogPage#createControl(org.eclipse.swt.widgets.Composite) + */ + @Override + public void createControl(Composite parent) { +// Composite optionsPageComposite = new Composite(composite, SWT.NULL); + fEditable = parent.isEnabled(); + + final Composite composite = new Composite(parent, SWT.NONE); + { + GridLayout layout = new GridLayout(); + layout.numColumns = 2; + layout.marginWidth = 1; + layout.marginHeight = 1; + layout.marginRight = 1; + composite.setLayout(layout); + composite.setLayoutData(new GridData(GridData.FILL_BOTH)); + Dialog.applyDialogFont(composite); + + GridData gd = new GridData(GridData.FILL_HORIZONTAL); + gd.horizontalSpan = 2; + composite.setLayoutData(gd); + } + + +// Group groupRun = new Group(composite, SWT.SHADOW_ETCHED_IN); +//// groupRun.setText("Language Settings Provider Options"); +// +// GridLayout gridLayoutRun = new GridLayout(); +//// GridLayout gridLayoutRun = new GridLayout(2, true); +//// gridLayoutRun.makeColumnsEqualWidth = false; +//// gridLayoutRun.marginRight = -10; +//// gridLayoutRun.marginLeft = -4; +// groupRun.setLayout(gridLayoutRun); +//// GridData gdRun = new GridData(GridData.FILL_HORIZONTAL); +//// gdRun.horizontalSpan = 2; +//// groupRun.setLayoutData(gdRun); + + AbstractBuildCommandParser provider = getRawProvider(); +// { +// runOnceRadioButton = new Button(groupRun, SWT.RADIO); +// runOnceRadioButton.setText("Run only once"); //$NON-NLS-1$ +// // b1.setToolTipText(UIMessages.getString("EnvironmentTab.3")); //$NON-NLS-1$ +// GridData gd = new GridData(GridData.FILL_HORIZONTAL); +// gd.horizontalSpan = 3; +// runOnceRadioButton.setLayoutData(gd); +// runOnceRadioButton.setSelection(provider.isRunOnce()); +// runOnceRadioButton.setEnabled(fEditable); +// runOnceRadioButton.addSelectionListener(new SelectionAdapter() { +// @Override +// public void widgetSelected(SelectionEvent evt) { +// boolean runOnceEnabled = runOnceRadioButton.getSelection(); +// if (runOnceEnabled) { +// AbstractBuildCommandParser provider = getRawProvider(); +// if (runOnceEnabled != provider.isRunOnce()) { +// AbstractBuildCommandParser selectedProvider = getWorkingCopy(providerId); +// selectedProvider.setRunOnce(runOnceEnabled); +// providerTab.refreshItem(selectedProvider); +// } +// } +// } +// +// }); +// } +// { +// runEveryBuildRadioButton = new Button(groupRun, SWT.RADIO); +// runEveryBuildRadioButton.setText("Activate on every build"); //$NON-NLS-1$ +// runEveryBuildRadioButton.setSelection(!provider.isRunOnce()); +// runEveryBuildRadioButton.setEnabled(fEditable); +// GridData gd = new GridData(GridData.FILL_HORIZONTAL); +// gd.horizontalSpan = 3; +// runEveryBuildRadioButton.setLayoutData(gd); +// runEveryBuildRadioButton.addSelectionListener(new SelectionAdapter() { +// @Override +// public void widgetSelected(SelectionEvent evt) { +// boolean runEveryBuildEnabled = runEveryBuildRadioButton.getSelection(); +// if (runEveryBuildEnabled) { +// AbstractBuildCommandParser provider = getRawProvider(); +// if (runEveryBuildEnabled != !provider.isRunOnce()) { +// AbstractBuildCommandParser selectedProvider = getWorkingCopy(providerId); +// selectedProvider.setRunOnce(!runEveryBuildEnabled); +// providerTab.refreshItem(selectedProvider); +// } +// } +// } +// }); +// } + + // Compiler specs command + { + Label label = ControlFactory.createLabel(composite, "Compiler command pattern:"); + GridData gd = new GridData(); + gd.horizontalSpan = 1; + label.setLayoutData(gd); + label.setEnabled(fEditable); + } + + { + inputCommand = ControlFactory.createTextField(composite, SWT.SINGLE | SWT.BORDER); + String customParameter = provider.getCustomParameter(); + inputCommand.setText(customParameter!=null ? customParameter : ""); + + GridData gd = new GridData(); + gd.horizontalSpan = 1; + gd.grabExcessHorizontalSpace = true; + gd.horizontalAlignment = SWT.FILL; + inputCommand.setLayoutData(gd); + inputCommand.setEnabled(fEditable); + + inputCommand.addModifyListener(new ModifyListener() { + public void modifyText(ModifyEvent e) { + String text = inputCommand.getText(); + AbstractBuildCommandParser provider = getRawProvider(); + if (!text.equals(provider.getCustomParameter())) { + AbstractBuildCommandParser selectedProvider = getWorkingCopy(providerId); + selectedProvider.setCustomParameter(text); + providerTab.refreshItem(selectedProvider); + } + } + }); + } + +// { +// Button button = ControlFactory.createPushButton(composite, "Browse..."); +// button.setEnabled(fEditable); +// button.addSelectionListener(new SelectionAdapter() { +// +// @Override +// public void widgetSelected(SelectionEvent evt) { +//// handleAddr2LineButtonSelected(); +// //updateLaunchConfigurationDialog(); +// } +// +// }); +// +// } + +// { +// final Button button = new Button(composite, SWT.PUSH); +// button.setFont(parent.getFont()); +// String text = fProvider.isEmpty() ? "Run Now (TODO)" : "Clear"; +// button.setText(text); +//// button.addSelectionListener(this); +// GridData data = new GridData(); +// data.horizontalSpan = 2; +//// data.horizontalAlignment = GridData.BEGINNING; +//// data.widthHint = 60; +// button.setLayoutData(data); +// // TODO +// button.setEnabled(fEditable && !fProvider.isEmpty()); +// +// button.addSelectionListener(new SelectionAdapter() { +// +// @Override +// public void widgetSelected(SelectionEvent evt) { +// if (fProvider.isEmpty()) { +// // TODO +// } else { +// fProvider.clear(); +// } +// // TODO +// button.setEnabled(fEditable && !fProvider.isEmpty()); +// String text = fProvider.isEmpty() ? "Run Now (TODO)" : "Clear"; +// button.setText(text); +// button.pack(); +// } +// +// }); +// +// } + +// // Compiler specs command +// { +// Label label = ControlFactory.createLabel(composite, "Parsing rules:"); +// GridData gd = new GridData(); +// gd.horizontalSpan = 2; +// label.setLayoutData(gd); +//// Label newLabel = new Label(composite, SWT.NONE); +////// ((GridData) newLabel.getLayoutData()).horizontalSpan = 1; +//// newLabel.setText("Command to get compiler specs:"); +// } + + +// createPatternsTable(group, composite); + + + + + + + + +// Group group = new Group(parent, SWT.SHADOW_ETCHED_IN); +// group.setText(DialogsMessages.RegexErrorParserOptionPage_Title); +// +// GridLayout gridLayout = new GridLayout(2, true); +// gridLayout.makeColumnsEqualWidth = false; +// gridLayout.marginRight = -10; +// gridLayout.marginLeft = -4; +// group.setLayout(gridLayout); +// group.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); +// +// Composite composite = new Composite(group, SWT.NONE); +// GridLayout layout = new GridLayout(); +// layout.numColumns = 2; +// layout.marginWidth = 1; +// layout.marginHeight = 1; +// layout.marginRight = 1; +// composite.setLayout(layout); +// composite.setLayoutData(new GridData(GridData.FILL_BOTH)); +// Dialog.applyDialogFont(composite); +// +// if (!fEditable) +// createLinkToPreferences(composite); +// +// createPatternsTable(group, composite); +// +// if (fEditable) { +// createButtons(composite); +// } + + { + expandRelativePathCheckBox = new Button(composite, SWT.CHECK); + expandRelativePathCheckBox.setText("Use heuristics to resolve paths"); + GridData gd = new GridData(GridData.FILL_HORIZONTAL); + gd.horizontalSpan = 2; + expandRelativePathCheckBox.setLayoutData(gd); + + expandRelativePathCheckBox.setSelection(provider.isResolvingPaths()); + expandRelativePathCheckBox.setEnabled(fEditable); + expandRelativePathCheckBox.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + boolean enabled = expandRelativePathCheckBox.getSelection(); + AbstractBuildCommandParser provider = getRawProvider(); + if (enabled != provider.isResolvingPaths()) { + AbstractBuildCommandParser selectedProvider = getWorkingCopy(providerId); + selectedProvider.setResolvingPaths(enabled); + providerTab.refreshItem(selectedProvider); + } + } + + @Override + public void widgetDefaultSelected(SelectionEvent e) { + widgetSelected(e); + } + + }); + + } + + { + applyToProjectCheckBox = new Button(composite, SWT.CHECK); + applyToProjectCheckBox.setText("Apply discovered settings on project level"); + GridData gd = new GridData(GridData.FILL_HORIZONTAL); + gd.horizontalSpan = 2; + applyToProjectCheckBox.setLayoutData(gd); + +// applyToProjectCheckBox.setSelection(provider.isExpandRelativePaths()); +// applyToProjectCheckBox.setEnabled(fEditable); + applyToProjectCheckBox.setSelection(false); + applyToProjectCheckBox.setEnabled(false); + applyToProjectCheckBox.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + boolean enabled = applyToProjectCheckBox.getSelection(); + AbstractBuildCommandParser provider = getRawProvider(); + if (enabled != provider.isResolvingPaths()) { + AbstractBuildCommandParser selectedProvider = getWorkingCopy(providerId); + selectedProvider.setResolvingPaths(enabled); + providerTab.refreshItem(selectedProvider); + } + } + + @Override + public void widgetDefaultSelected(SelectionEvent e) { + widgetSelected(e); + } + + }); + + } + +// // Status line +// if (fEditable) { +// fStatusLine = new StatusMessageLine(composite, SWT.LEFT, 2); +// IStatus status = new Status(IStatus.WARNING, CUIPlugin.PLUGIN_ID, "Note that currently not all options are persisted (FIXME)"); +// fStatusLine.setErrorStatus(status); +// } + + setControl(composite); + } + + private AbstractBuildCommandParser getRawProvider() { + ILanguageSettingsProvider provider = LanguageSettingsManager.getRawProvider(providerTab.getProvider(providerId)); + Assert.isTrue(provider instanceof AbstractBuildCommandParser); + return (AbstractBuildCommandParser) provider; + } + + private AbstractBuildCommandParser getWorkingCopy(String providerId) { + ILanguageSettingsProvider provider = providerTab.getWorkingCopy(providerId); + Assert.isTrue(provider instanceof AbstractBuildCommandParser); + return (AbstractBuildCommandParser) provider; + } + + @Override + public void performApply(IProgressMonitor monitor) throws CoreException { + // handled by LanguageSettingsProviderTab + } + + @Override + public void performDefaults() { + // handled by LanguageSettingsProviderTab + } + +} diff --git a/build/org.eclipse.cdt.make.ui/src/org/eclipse/cdt/make/internal/ui/scannerconfig/ScannerDiscoveryConsole.java b/build/org.eclipse.cdt.make.ui/src/org/eclipse/cdt/make/internal/ui/scannerconfig/ScannerDiscoveryConsole.java new file mode 100644 index 00000000000..e5590d9fd43 --- /dev/null +++ b/build/org.eclipse.cdt.make.ui/src/org/eclipse/cdt/make/internal/ui/scannerconfig/ScannerDiscoveryConsole.java @@ -0,0 +1,39 @@ +/******************************************************************************* + * Copyright (c) 2010, 2011 Andrew Gvozdev 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: + * Andrew Gvozdev - Initial API and implementation + *******************************************************************************/ + +package org.eclipse.cdt.make.internal.ui.scannerconfig; + +import java.net.URL; + +import org.eclipse.cdt.internal.ui.buildconsole.CBuildConsole; +import org.eclipse.cdt.internal.ui.language.settings.providers.LanguageSettingsProviderAssociation; + +public class ScannerDiscoveryConsole extends CBuildConsole { + + /** + * {@inheritDoc} + * @param consoleId - a console ID is expected here which then is used as menu context ID. + * @param defaultIconUrl - if {@code LanguageSettingsProviderAssociation} extension point + * defines URL by provider id, {@code defaultIconUrl} will be ignored and the URL from the extension + * point will be used. If not, supplied {@code defaultIconUrl} will be used. + */ + @Override + public void init(String consoleId, String name, URL defaultIconUrl) { + URL iconUrl = LanguageSettingsProviderAssociation.getImageUrl(consoleId); + if (iconUrl==null) { + iconUrl = defaultIconUrl; + } + + super.init(consoleId, name, iconUrl); + } + + +} diff --git a/build/org.eclipse.cdt.managedbuilder.core.tests/suite/org/eclipse/cdt/managedbuilder/tests/suite/AllManagedBuildTests.java b/build/org.eclipse.cdt.managedbuilder.core.tests/suite/org/eclipse/cdt/managedbuilder/tests/suite/AllManagedBuildTests.java index 65fdaadca1d..6ea149057a4 100644 --- a/build/org.eclipse.cdt.managedbuilder.core.tests/suite/org/eclipse/cdt/managedbuilder/tests/suite/AllManagedBuildTests.java +++ b/build/org.eclipse.cdt.managedbuilder.core.tests/suite/org/eclipse/cdt/managedbuilder/tests/suite/AllManagedBuildTests.java @@ -16,6 +16,7 @@ import junit.framework.Test; import junit.framework.TestSuite; import org.eclipse.cdt.build.core.scannerconfig.tests.CfgScannerConfigProfileManagerTests; +import org.eclipse.cdt.build.core.scannerconfig.tests.GCCBuiltinSpecsDetectorTest; import org.eclipse.cdt.build.core.scannerconfig.tests.GCCSpecsConsoleParserTest; import org.eclipse.cdt.core.CCorePlugin; import org.eclipse.cdt.core.dom.IPDOMManager; @@ -59,6 +60,7 @@ public class AllManagedBuildTests { // build.core.scannerconfig.tests suite.addTest(CfgScannerConfigProfileManagerTests.suite()); suite.addTestSuite(GCCSpecsConsoleParserTest.class); + suite.addTestSuite(GCCBuiltinSpecsDetectorTest.class); // managedbuilder.core.tests suite.addTest(ManagedBuildCoreTests20.suite()); diff --git a/build/org.eclipse.cdt.managedbuilder.core.tests/tests/org/eclipse/cdt/build/core/scannerconfig/tests/AllSD80Tests.java b/build/org.eclipse.cdt.managedbuilder.core.tests/tests/org/eclipse/cdt/build/core/scannerconfig/tests/AllSD80Tests.java new file mode 100644 index 00000000000..d339b469792 --- /dev/null +++ b/build/org.eclipse.cdt.managedbuilder.core.tests/tests/org/eclipse/cdt/build/core/scannerconfig/tests/AllSD80Tests.java @@ -0,0 +1,29 @@ +/******************************************************************************* + * Copyright (c) 2010, 2011 Andrew Gvozdev 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: + * Andrew Gvozdev - initial API and implementation + *******************************************************************************/ + +package org.eclipse.cdt.build.core.scannerconfig.tests; + +import org.eclipse.cdt.build.core.scannerconfig.tests.GCCBuiltinSpecsDetectorTest; + +import junit.framework.TestSuite; + +public class AllSD80Tests extends TestSuite { + + public static TestSuite suite() { + return new AllSD80Tests(); + } + + public AllSD80Tests() { + super(AllSD80Tests.class.getName()); + + addTestSuite(GCCBuiltinSpecsDetectorTest.class); + } +} diff --git a/build/org.eclipse.cdt.managedbuilder.core.tests/tests/org/eclipse/cdt/build/core/scannerconfig/tests/GCCBuiltinSpecsDetectorTest.java b/build/org.eclipse.cdt.managedbuilder.core.tests/tests/org/eclipse/cdt/build/core/scannerconfig/tests/GCCBuiltinSpecsDetectorTest.java new file mode 100644 index 00000000000..5e5ff994266 --- /dev/null +++ b/build/org.eclipse.cdt.managedbuilder.core.tests/tests/org/eclipse/cdt/build/core/scannerconfig/tests/GCCBuiltinSpecsDetectorTest.java @@ -0,0 +1,659 @@ +/******************************************************************************* + * Copyright (c) 2009 Andrew Gvozdev 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: + * Andrew Gvozdev - Initial API and implementation + *******************************************************************************/ + package org.eclipse.cdt.build.core.scannerconfig.tests; + +import java.io.IOException; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.List; + +import junit.framework.TestCase; + +import org.eclipse.cdt.core.model.CoreModel; +import org.eclipse.cdt.core.settings.model.CIncludeFileEntry; +import org.eclipse.cdt.core.settings.model.CIncludePathEntry; +import org.eclipse.cdt.core.settings.model.CLibraryFileEntry; +import org.eclipse.cdt.core.settings.model.CLibraryPathEntry; +import org.eclipse.cdt.core.settings.model.CMacroEntry; +import org.eclipse.cdt.core.settings.model.CMacroFileEntry; +import org.eclipse.cdt.core.settings.model.ICConfigurationDescription; +import org.eclipse.cdt.core.settings.model.ICLanguageSettingEntry; +import org.eclipse.cdt.core.settings.model.ICProjectDescription; +import org.eclipse.cdt.core.settings.model.ICProjectDescriptionManager; +import org.eclipse.cdt.core.settings.model.ICSettingEntry; +import org.eclipse.cdt.core.testplugin.ResourceHelper; +import org.eclipse.cdt.internal.core.XmlUtil; +import org.eclipse.cdt.managedbuilder.internal.scannerconfig.AbstractBuiltinSpecsDetector; +import org.eclipse.cdt.managedbuilder.internal.scannerconfig.GCCBuiltinSpecsDetector; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.Path; +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +public class GCCBuiltinSpecsDetectorTest extends TestCase { + private static final String PROVIDER_ID = "provider.id"; + private static final String PROVIDER_NAME = "provider name"; + private static final String LANGUAGE_ID = "language.test.id"; + private static final String LANGUAGE_ID_C = "org.eclipse.cdt.core.gcc"; + private static final String LANGUAGE_ID_CPP = "org.eclipse.cdt.core.g++"; + private static final String CUSTOM_PARAMETER = "customParameter"; + private static final String ELEM_TEST = "test"; + + // those attributes must match that in AbstractBuiltinSpecsDetector + private static final String ATTR_CONSOLE = "console"; //$NON-NLS-1$ + private static final String ATTR_RUN_ONCE = "run-once"; //$NON-NLS-1$ + + private class MockBuiltinSpecsDetector extends AbstractBuiltinSpecsDetector { + @Override + protected String getToolchainId() { + return null; + } + @Override + protected List parseForOptions(String line) { + return null; + } + @Override + protected AbstractOptionParser[] getOptionParsers() { + return null; + } + } + + @Override + protected void setUp() throws Exception { + } + + @Override + protected void tearDown() throws Exception { + ResourceHelper.cleanUp(); + } + + private ICConfigurationDescription[] getConfigurationDescriptions(IProject project) { + CoreModel coreModel = CoreModel.getDefault(); + ICProjectDescriptionManager mngr = coreModel.getProjectDescriptionManager(); + // project description + ICProjectDescription projectDescription = mngr.getProjectDescription(project); + assertNotNull(projectDescription); + assertEquals(1, projectDescription.getConfigurations().length); + // configuration description + ICConfigurationDescription[] cfgDescriptions = projectDescription.getConfigurations(); + return cfgDescriptions; + } + + public void testAbstractBuiltinSpecsDetector_GettersSetters() throws Exception { + // define mock detector + MockBuiltinSpecsDetector detector = new MockBuiltinSpecsDetector(); + + detector.configureProvider(PROVIDER_ID, PROVIDER_NAME, null, null, null); + assertEquals(PROVIDER_ID, detector.getId()); + assertEquals(PROVIDER_NAME, detector.getName()); + assertEquals(null, detector.getLanguageScope()); + assertEquals(null, detector.getSettingEntries(null, null, null)); + assertEquals(null, detector.getCustomParameter()); + + List languages = new ArrayList(); + languages.add(LANGUAGE_ID); + List entries = new ArrayList(); + ICLanguageSettingEntry entry = new CMacroEntry("MACRO", "VALUE", ICSettingEntry.BUILTIN | ICSettingEntry.READONLY); + entries.add(entry); + + detector.configureProvider(PROVIDER_ID, PROVIDER_NAME, languages, entries, CUSTOM_PARAMETER); + assertEquals(PROVIDER_ID, detector.getId()); + assertEquals(PROVIDER_NAME, detector.getName()); + assertEquals(languages, detector.getLanguageScope()); + assertEquals(entries, detector.getSettingEntries(null, null, null)); + assertEquals(CUSTOM_PARAMETER, detector.getCustomParameter()); + + assertEquals(true, detector.isRunOnce()); + detector.setRunOnce(false); + assertEquals(false, detector.isRunOnce()); + } + + public void testAbstractBuiltinSpecsDetector_CloneAndEquals() throws Exception { + // define mock detector + class MockDetectorCloneable extends MockBuiltinSpecsDetector implements Cloneable { + @Override + public MockDetectorCloneable clone() throws CloneNotSupportedException { + return (MockDetectorCloneable) super.clone(); + } + @Override + public MockDetectorCloneable cloneShallow() throws CloneNotSupportedException { + return (MockDetectorCloneable) super.cloneShallow(); + } + } + + // create instance to compare to + MockDetectorCloneable detector = new MockDetectorCloneable(); + + List languages = new ArrayList(); + languages.add(LANGUAGE_ID); + List entries = new ArrayList(); + ICLanguageSettingEntry entry = new CMacroEntry("MACRO", "VALUE", ICSettingEntry.BUILTIN | ICSettingEntry.READONLY); + entries.add(entry); + + // check clone after initialization + MockDetectorCloneable clone0 = detector.clone(); + assertTrue(detector.equals(clone0)); + + // configure provider + detector.configureProvider(PROVIDER_ID, PROVIDER_NAME, languages, entries, CUSTOM_PARAMETER); + assertEquals(true, detector.isRunOnce()); + detector.setRunOnce(false); + assertFalse(detector.equals(clone0)); + + // check another clone after configuring + { + MockDetectorCloneable clone = detector.clone(); + assertTrue(detector.equals(clone)); + } + + // check custom parameter + { + MockDetectorCloneable clone = detector.clone(); + clone.setCustomParameter("changed"); + assertFalse(detector.equals(clone)); + } + + // check language scope + { + MockDetectorCloneable clone = detector.clone(); + clone.setLanguageScope(null); + assertFalse(detector.equals(clone)); + } + + // check 'run once' flag + { + MockDetectorCloneable clone = detector.clone(); + boolean runOnce = clone.isRunOnce(); + clone.setRunOnce( ! runOnce ); + assertFalse(detector.equals(clone)); + } + + // check console flag + { + MockDetectorCloneable clone = detector.clone(); + boolean isConsoleEnabled = clone.isConsoleEnabled(); + clone.setConsoleEnabled( ! isConsoleEnabled ); + assertFalse(detector.equals(clone)); + } + + // check entries + { + MockDetectorCloneable clone = detector.clone(); + clone.setSettingEntries(null, null, null, null); + assertFalse(detector.equals(clone)); + } + + // check cloneShallow() + { + MockDetectorCloneable detector2 = detector.clone(); + MockDetectorCloneable clone = detector2.cloneShallow(); + assertFalse(detector2.equals(clone)); + detector2.setSettingEntries(null, null, null, null); + assertTrue(detector2.equals(clone)); + } + + } + + /** + */ + public void testAbstractBuiltinSpecsDetector_Serialize() throws Exception { + { + // create empty XML + Document doc = XmlUtil.newDocument(); + Element rootElement = XmlUtil.appendElement(doc, ELEM_TEST); + + // load it to new provider + MockBuiltinSpecsDetector detector = new MockBuiltinSpecsDetector(); + detector.load(rootElement); + assertEquals(true, detector.isRunOnce()); + assertEquals(false, detector.isConsoleEnabled()); + } + + Element elementProvider; + { + // define mock detector + MockBuiltinSpecsDetector detector = new MockBuiltinSpecsDetector(); + assertEquals(true, detector.isRunOnce()); + assertEquals(false, detector.isConsoleEnabled()); + + // redefine the settings + detector.setRunOnce(false); + assertEquals(false, detector.isRunOnce()); + detector.setConsoleEnabled(true); + assertEquals(true, detector.isConsoleEnabled()); + + // serialize in XML + Document doc = XmlUtil.newDocument(); + Element rootElement = XmlUtil.appendElement(doc, ELEM_TEST); + elementProvider = detector.serialize(rootElement); + String xmlString = XmlUtil.toString(doc); + + assertTrue(xmlString.contains(ATTR_RUN_ONCE)); + assertTrue(xmlString.contains(ATTR_CONSOLE)); + } + { + // create another instance of the provider + MockBuiltinSpecsDetector detector = new MockBuiltinSpecsDetector(); + assertEquals(true, detector.isRunOnce()); + assertEquals(false, detector.isConsoleEnabled()); + + // load element + detector.load(elementProvider); + assertEquals(false, detector.isRunOnce()); + assertEquals(true, detector.isConsoleEnabled()); + } + } + + + + public void testAbstractBuiltinSpecsDetector_Nulls() throws Exception { + { + // test AbstractBuiltinSpecsDetector.run(...); + MockBuiltinSpecsDetector detector = new MockBuiltinSpecsDetector(); + detector.run((IProject)null, null, null, null, null); + // Do not test with (ICConfigurationDescription)null as it is not allowed + } + + { + // test AbstractBuiltinSpecsDetector.processLine(...) flow + MockBuiltinSpecsDetector detector = new MockBuiltinSpecsDetector(); + detector.startup(null); + detector.processLine(null); + detector.shutdown(); + } + + } + + public void testAbstractBuiltinSpecsDetector_RunConfiguration() throws Exception { + // Create model project and accompanied descriptions + String projectName = getName(); + IProject project = ResourceHelper.createCDTProjectWithConfig(projectName); + ICConfigurationDescription[] cfgDescriptions = getConfigurationDescriptions(project); + + ICConfigurationDescription cfgDescription = cfgDescriptions[0]; + + AbstractBuiltinSpecsDetector detector = new GCCBuiltinSpecsDetector() { + @Override + protected boolean runProgram(String command, String[] env, IPath workingDirectory, IProgressMonitor monitor, + OutputStream consoleOut, OutputStream consoleErr) throws CoreException, IOException { + printLine(consoleOut, "#define MACRO VALUE"); + consoleOut.close(); + consoleErr.close(); + return true; + } + }; + + detector.setLanguageScope(new ArrayList() {{add(LANGUAGE_ID);}}); + + detector.run(cfgDescription, LANGUAGE_ID, null, null, null); + assertFalse(detector.isEmpty()); + + List noentries = detector.getSettingEntries(null, null, null); + assertNull(noentries); + + List entries = detector.getSettingEntries(cfgDescription, null, LANGUAGE_ID); + ICLanguageSettingEntry expected = new CMacroEntry("MACRO", "VALUE", ICSettingEntry.BUILTIN | ICSettingEntry.READONLY); + assertEquals(expected, entries.get(0)); + } + + public void testAbstractBuiltinSpecsDetector_RunProject() throws Exception { + // Create model project and accompanied descriptions + String projectName = getName(); + IProject project = ResourceHelper.createCDTProjectWithConfig(projectName); + + AbstractBuiltinSpecsDetector detector = new GCCBuiltinSpecsDetector() { + @Override + protected boolean runProgram(String command, String[] env, IPath workingDirectory, IProgressMonitor monitor, + OutputStream consoleOut, OutputStream consoleErr) throws CoreException, IOException { + printLine(consoleOut, "#define MACRO VALUE"); + consoleOut.close(); + consoleErr.close(); + return true; + } + }; + + detector.setLanguageScope(new ArrayList() {{add(LANGUAGE_ID);}}); + + detector.run(project, LANGUAGE_ID, null, null, null); + assertFalse(detector.isEmpty()); + + List entries = detector.getSettingEntries(null, null, LANGUAGE_ID); + ICLanguageSettingEntry expected = new CMacroEntry("MACRO", "VALUE", ICSettingEntry.BUILTIN | ICSettingEntry.READONLY); + assertEquals(expected, entries.get(0)); + } + + public void testAbstractBuiltinSpecsDetector_RunOnce() throws Exception { + // Create model project and accompanied descriptions + String projectName = getName(); + IProject project = ResourceHelper.createCDTProjectWithConfig(projectName); + ICConfigurationDescription[] cfgDescriptions = getConfigurationDescriptions(project); + ICConfigurationDescription cfgDescription = cfgDescriptions[0]; + + // Define mock detector which collects number of entries equal to count + AbstractBuiltinSpecsDetector detector = new MockBuiltinSpecsDetector() { + int count=0; + @Override + public boolean processLine(String line) { + count++; + for (int i=0;i entries = detector.getSettingEntries(null, null, LANGUAGE_ID_C); + assertEquals(1, entries.size()); + } + + // run second time + detector.run(project, LANGUAGE_ID_C, null, null, null); + { + List entries = detector.getSettingEntries(null, null, LANGUAGE_ID_C); + assertEquals(2, entries.size()); + } + + // set to run once + detector.setRunOnce(true); + assertEquals(true, detector.isRunOnce()); + assertFalse(detector.isEmpty()); + + detector.run(project, LANGUAGE_ID_C, null, null, null); + { + // should not collect when provider is not empty + List entries = detector.getSettingEntries(null, null, LANGUAGE_ID_C); + assertEquals(2, entries.size()); + } + + detector.run(cfgDescription, LANGUAGE_ID_C, null, null, null); + { + // should not collect when provider is not empty + List entries = detector.getSettingEntries(null, null, LANGUAGE_ID_C); + assertEquals(2, entries.size()); + } + } + + public void testAbstractBuiltinSpecsDetector_GroupSettings() throws Exception { + // define benchmarks + final CIncludePathEntry includePath_1 = new CIncludePathEntry("/include/path_1", ICSettingEntry.BUILTIN | ICSettingEntry.READONLY); + final CIncludePathEntry includePath_2 = new CIncludePathEntry("/include/path_2", ICSettingEntry.BUILTIN | ICSettingEntry.READONLY); + final CIncludeFileEntry includeFile_1 = new CIncludeFileEntry(new Path("/include.file1"), ICSettingEntry.BUILTIN | ICSettingEntry.READONLY); + final CIncludeFileEntry includeFile_2 = new CIncludeFileEntry(new Path("/include.file2"), ICSettingEntry.BUILTIN | ICSettingEntry.READONLY); + final CMacroEntry macro_1 = new CMacroEntry("MACRO_1", "", ICSettingEntry.BUILTIN | ICSettingEntry.READONLY); + final CMacroEntry macro_2 = new CMacroEntry("MACRO_2", "", ICSettingEntry.BUILTIN | ICSettingEntry.READONLY |ICSettingEntry.UNDEFINED); + final CMacroFileEntry macroFile_1 = new CMacroFileEntry(new Path("/macro.file1"), ICSettingEntry.BUILTIN | ICSettingEntry.READONLY); + final CMacroFileEntry macroFile_2 = new CMacroFileEntry(new Path("/macro.file2"), ICSettingEntry.BUILTIN | ICSettingEntry.READONLY); + final CLibraryPathEntry libraryPath_1 = new CLibraryPathEntry(new Path("/lib/path_1"), ICSettingEntry.BUILTIN | ICSettingEntry.READONLY); + final CLibraryPathEntry libraryPath_2 = new CLibraryPathEntry(new Path("/lib/path_2"), ICSettingEntry.BUILTIN | ICSettingEntry.READONLY); + final CLibraryFileEntry libraryFile_1 = new CLibraryFileEntry("lib_1.a", ICSettingEntry.BUILTIN | ICSettingEntry.READONLY); + final CLibraryFileEntry libraryFile_2 = new CLibraryFileEntry("lib_2.a", ICSettingEntry.BUILTIN | ICSettingEntry.READONLY); + + // Define mock detector adding unorganized entries + AbstractBuiltinSpecsDetector detector = new MockBuiltinSpecsDetector() { + @Override + public boolean processLine(String line) { + detectedSettingEntries.add(libraryFile_1); + detectedSettingEntries.add(libraryPath_1); + detectedSettingEntries.add(macroFile_1); + detectedSettingEntries.add(macro_1); + detectedSettingEntries.add(includeFile_1); + detectedSettingEntries.add(includePath_1); + + detectedSettingEntries.add(includePath_2); + detectedSettingEntries.add(includeFile_2); + detectedSettingEntries.add(macro_2); + detectedSettingEntries.add(macroFile_2); + detectedSettingEntries.add(libraryPath_2); + detectedSettingEntries.add(libraryFile_2); + return true; + } + }; + + // run specs detector + detector.startup(null); + detector.processLine(""); + detector.shutdown(); + + + // compare benchmarks, expected well-sorted + List entries = detector.getSettingEntries(null, null, null); + + int i=0; + assertEquals(includePath_1, entries.get(i++)); + assertEquals(includePath_2, entries.get(i++)); + assertEquals(includeFile_1, entries.get(i++)); + assertEquals(includeFile_2, entries.get(i++)); + assertEquals(macro_1, entries.get(i++)); + assertEquals(macro_2, entries.get(i++)); + assertEquals(macroFile_1, entries.get(i++)); + assertEquals(macroFile_2, entries.get(i++)); + assertEquals(libraryPath_1, entries.get(i++)); + assertEquals(libraryPath_2, entries.get(i++)); + assertEquals(libraryFile_1, entries.get(i++)); + assertEquals(libraryFile_2, entries.get(i++)); + + assertEquals(12, entries.size()); + } + + public void testGCCBuiltinSpecsDetector_Macro_NoValue() throws Exception { + AbstractBuiltinSpecsDetector detector = new GCCBuiltinSpecsDetector(); + + detector.startup(null); + detector.processLine("#define MACRO"); + detector.shutdown(); + + List entries = detector.getSettingEntries(null, null, null); + ICLanguageSettingEntry expected = new CMacroEntry("MACRO", null, ICSettingEntry.BUILTIN | ICSettingEntry.READONLY); + assertEquals(expected, entries.get(0)); + } + + public void testGCCBuiltinSpecsDetector_ResolvedCommand() throws Exception { + class MockGCCBuiltinSpecsDetector extends GCCBuiltinSpecsDetector { + @Override + public String resolveCommand(String languageId) throws CoreException { + return super.resolveCommand(languageId); + } + } + { + MockGCCBuiltinSpecsDetector detector = new MockGCCBuiltinSpecsDetector(); + detector.setLanguageScope(new ArrayList() {{add(LANGUAGE_ID_C);}}); + detector.setCustomParameter("${COMMAND} -E -P -v -dD ${INPUTS}"); + + String resolvedCommand = detector.resolveCommand(LANGUAGE_ID_C); + assertTrue(resolvedCommand.startsWith("gcc -E -P -v -dD ")); + assertTrue(resolvedCommand.endsWith("spec.c")); + detector.shutdown(); + } + { + MockGCCBuiltinSpecsDetector detector = new MockGCCBuiltinSpecsDetector(); + detector.setLanguageScope(new ArrayList() {{add(LANGUAGE_ID_C);}}); + detector.setCustomParameter("${COMMAND} -E -P -v -dD file.${EXT}"); + + String resolvedCommand = detector.resolveCommand(LANGUAGE_ID_C); + assertTrue(resolvedCommand.startsWith("gcc -E -P -v -dD ")); + assertTrue(resolvedCommand.endsWith("file.c")); + detector.shutdown(); + } + } + + public void testGCCBuiltinSpecsDetector_Macro_NoArgs() throws Exception { + AbstractBuiltinSpecsDetector detector = new GCCBuiltinSpecsDetector(); + + detector.startup(null); + detector.processLine("#define MACRO VALUE"); + detector.shutdown(); + + List entries = detector.getSettingEntries(null, null, null); + ICLanguageSettingEntry expected = new CMacroEntry("MACRO", "VALUE", ICSettingEntry.BUILTIN | ICSettingEntry.READONLY); + assertEquals(expected, entries.get(0)); + } + + public void testGCCBuiltinSpecsDetector_Macro_Const() throws Exception { + AbstractBuiltinSpecsDetector detector = new GCCBuiltinSpecsDetector(); + + detector.startup(null); + detector.processLine("#define MACRO (3)"); + detector.shutdown(); + + List entries = detector.getSettingEntries(null, null, null); + ICLanguageSettingEntry expected = new CMacroEntry("MACRO", "(3)", ICSettingEntry.BUILTIN | ICSettingEntry.READONLY); + assertEquals(expected, entries.get(0)); + } + + public void testGCCBuiltinSpecsDetector_Macro_EmptyArgList() throws Exception { + AbstractBuiltinSpecsDetector detector = new GCCBuiltinSpecsDetector(); + + detector.startup(null); + detector.processLine("#define MACRO() VALUE"); + detector.shutdown(); + + List entries = detector.getSettingEntries(null, null, null); + ICLanguageSettingEntry expected = new CMacroEntry("MACRO()", "VALUE", ICSettingEntry.BUILTIN | ICSettingEntry.READONLY); + assertEquals(expected, entries.get(0)); + } + + public void testGCCBuiltinSpecsDetector_Macro_ParamUnused() throws Exception { + AbstractBuiltinSpecsDetector detector = new GCCBuiltinSpecsDetector(); + + detector.startup(null); + detector.processLine("#define MACRO(X) VALUE"); + detector.shutdown(); + + List entries = detector.getSettingEntries(null, null, null); + ICLanguageSettingEntry expected = new CMacroEntry("MACRO(X)", "VALUE", ICSettingEntry.BUILTIN | ICSettingEntry.READONLY); + assertEquals(expected, entries.get(0)); + } + + public void testGCCBuiltinSpecsDetector_Macro_ParamSpace() throws Exception { + AbstractBuiltinSpecsDetector detector = new GCCBuiltinSpecsDetector(); + + detector.startup(null); + detector.processLine("#define MACRO(P1, P2) VALUE(P1, P2)"); + detector.shutdown(); + + List entries = detector.getSettingEntries(null, null, null); + ICLanguageSettingEntry expected = new CMacroEntry("MACRO(P1, P2)", "VALUE(P1, P2)", ICSettingEntry.BUILTIN | ICSettingEntry.READONLY); + assertEquals(expected, entries.get(0)); + } + + public void testGCCBuiltinSpecsDetector_Macro_ArgsNoValue() throws Exception { + AbstractBuiltinSpecsDetector detector = new GCCBuiltinSpecsDetector(); + + detector.startup(null); + detector.processLine("#define MACRO(P1, P2) "); + detector.shutdown(); + + List entries = detector.getSettingEntries(null, null, null); + ICLanguageSettingEntry expected = new CMacroEntry("MACRO(P1, P2)", null, ICSettingEntry.BUILTIN | ICSettingEntry.READONLY); + assertEquals(expected, entries.get(0)); + } + + public void testGCCBuiltinSpecsDetector_Includes() throws Exception { + // Create model project and folders to test + String projectName = getName(); + IProject project = ResourceHelper.createCDTProject(projectName); + IPath tmpPath = ResourceHelper.createTemporaryFolder(); + ResourceHelper.createFolder(project, "/misplaced/include1"); + ResourceHelper.createFolder(project, "/local/include"); + ResourceHelper.createFolder(project, "/usr/include"); + ResourceHelper.createFolder(project, "/usr/include2"); + ResourceHelper.createFolder(project, "/misplaced/include2"); + ResourceHelper.createFolder(project, "/System/Library/Frameworks"); + ResourceHelper.createFolder(project, "/Library/Frameworks"); + ResourceHelper.createFolder(project, "/misplaced/include3"); + String loc = tmpPath.toString(); + + GCCBuiltinSpecsDetector detector = new GCCBuiltinSpecsDetector(); + detector.startup(null); + + detector.processLine(" "+loc+"/misplaced/include1"); + detector.processLine("#include \"...\" search starts here:"); + detector.processLine(" "+loc+"/local/include"); + detector.processLine("#include <...> search starts here:"); + detector.processLine(" "+loc+"/usr/include"); + detector.processLine(" "+loc+"/usr/include/../include2"); + detector.processLine(" "+loc+"/missing/folder"); + detector.processLine(" "+loc+"/Library/Frameworks (framework directory)"); + detector.processLine("End of search list."); + detector.processLine(" "+loc+"/misplaced/include2"); + detector.processLine("Framework search starts here:"); + detector.processLine(" "+loc+"/System/Library/Frameworks"); + detector.processLine("End of search list."); + detector.processLine(" "+loc+"/misplaced/include3"); + detector.shutdown(); + + List entries = detector.getSettingEntries(null, null, null); + assertEquals(new CIncludePathEntry(loc+"/local/include", ICSettingEntry.LOCAL | ICSettingEntry.BUILTIN | ICSettingEntry.READONLY), + entries.get(0)); + assertEquals(new CIncludePathEntry(loc+"/usr/include", ICSettingEntry.BUILTIN | ICSettingEntry.READONLY), + entries.get(1)); + assertEquals(new CIncludePathEntry(loc+"/usr/include2", ICSettingEntry.BUILTIN | ICSettingEntry.READONLY), + entries.get(2)); + assertEquals(new CIncludePathEntry(loc+"/missing/folder", ICSettingEntry.BUILTIN | ICSettingEntry.READONLY), + entries.get(3)); + assertEquals(new CIncludePathEntry(loc+"/Library/Frameworks", ICSettingEntry.FRAMEWORKS_MAC | ICSettingEntry.BUILTIN | ICSettingEntry.READONLY), + entries.get(4)); + assertEquals(new CIncludePathEntry(loc+"/System/Library/Frameworks", ICSettingEntry.FRAMEWORKS_MAC | ICSettingEntry.BUILTIN | ICSettingEntry.READONLY), + entries.get(5)); + assertEquals(6, entries.size()); + } + + public void testGCCBuiltinSpecsDetector_Includes_SymbolicLinkUp() throws Exception { + // do not test on systems where symbolic links are not supported + if (!ResourceHelper.isSymbolicLinkSupported()) + return; + + // Create model project and folders to test + String projectName = getName(); + @SuppressWarnings("unused") + IProject project = ResourceHelper.createCDTProject(projectName); + // create link on the filesystem + IPath dir1 = ResourceHelper.createTemporaryFolder(); + IPath dir2 = dir1.removeLastSegments(1); + IPath linkPath = dir1.append("linked"); + ResourceHelper.createSymbolicLink(linkPath, dir2); + + AbstractBuiltinSpecsDetector detector = new GCCBuiltinSpecsDetector(); + + detector.startup(null); + detector.processLine("#include <...> search starts here:"); + detector.processLine(" "+linkPath.toString()+"/.."); + detector.processLine("End of search list."); + detector.shutdown(); + + // check populated entries + List entries = detector.getSettingEntries(null, null, null); + CIncludePathEntry expected = new CIncludePathEntry(dir2.removeLastSegments(1), ICSettingEntry.BUILTIN | ICSettingEntry.READONLY); + assertEquals(expected, entries.get(0)); + assertEquals(1, entries.size()); + } + +} diff --git a/build/org.eclipse.cdt.managedbuilder.core/plugin.xml b/build/org.eclipse.cdt.managedbuilder.core/plugin.xml index 532aee8a5f0..fa816ec68e8 100644 --- a/build/org.eclipse.cdt.managedbuilder.core/plugin.xml +++ b/build/org.eclipse.cdt.managedbuilder.core/plugin.xml @@ -308,6 +308,7 @@ @@ -597,6 +598,25 @@ + + + + + + + + + + + + + + diff --git a/build/org.eclipse.cdt.managedbuilder.core/schema/buildDefinitions.exsd b/build/org.eclipse.cdt.managedbuilder.core/schema/buildDefinitions.exsd index 83e75654f87..842d0059706 100644 --- a/build/org.eclipse.cdt.managedbuilder.core/schema/buildDefinitions.exsd +++ b/build/org.eclipse.cdt.managedbuilder.core/schema/buildDefinitions.exsd @@ -263,7 +263,16 @@ Specifying this attribute is fully equivalent to specifying the "org.eclips - The semi-colon separated list of the default error parsers to be used with this configuration. The list is ordered with the first error parser on the list invoked first, the second error parser second, and so on. The list may contain the error parsers defined by CDT and/or other installed error parser extensions. The list of error parsers to be used may be changed by the user on a per-configuration basis. When specified, this overrides the tool-chain errorParsers attribute. + The semi-colon separated list of the default error parsers to be used with this configuration. The list is ordered with the first error parser on the list invoked first, the second error parser second, and so on. The list may contain the error parsers defined by CDT and/or other installed error parser extensions. The list of error parsers to be used may be changed by the user on a per-configuration basis. When specified, this overrides the tool-chain errorParsers attribute. + + + + + + + Semicolon-separated list of providers ID implementing ILanguageSettingProvider interface. +This field could be amended with toolchain-level providers list by using ${Toolchain} keyword. Provider ID can be prefixed with "*", in this case shared instance of the provider defined on workspace level is used. Also provider ID can be prefixed with "-" which will cause id to be removed from the preceeding list including providers defined with ${Toolchain} keyword. +If this field is not specified, "*org.eclipse.cdt.managedbuilder.core.LanguageSettingsProvider" (MBS Language Settings Provider) is used by default. @@ -405,7 +414,15 @@ Specifying this attribute is fully equivalent to specifying the "org.eclips - The semi-colon separated list of the default error parsers to be used with this tool-chain. The list is ordered with the first error parser on the list invoked first, the second error parser second, and so on. The list may contain the error parsers defined by CDT and/or other installed error parser extensions. When specified, this overrides the tool errorParsers attributes of the tool children of the tool-chain and the builder child of the tool-chain. + The semi-colon separated list of the default error parsers to be used with this tool-chain. The list is ordered with the first error parser on the list invoked first, the second error parser second, and so on. The list may contain the error parsers defined by CDT and/or other installed error parser extensions. When specified, this overrides the tool errorParsers attributes of the tool children of the tool-chain and the builder child of the tool-chain. + + + + + + + Semicolon-separated list of providers ID implementing ILanguageSettingProvider interface. Provider ID can be prefixed with "*", in this case shared instance of the provider defined on workspace level is used. +This list could be adjusted on configuration level in the corresponding attribute. @@ -732,14 +749,14 @@ The pathConverter of a toolchain applies for all tools of the toolchain except i - Specifies whether this Tool represents a user-define custom build step. The default is false. When True, the default value of the commandLinePattern attribute changes to “$(command)”. + Specifies whether this Tool represents a user-define custom build step. The default is false. When True, the default value of the commandLinePattern attribute changes to “$(command)�. - Specifies a string that is written to the build output prior to each invocation of the tool. The default value is “Invoking tool-name (tool-id)…” + Specifies a string that is written to the build output prior to each invocation of the tool. The default value is “Invoking tool-name (tool-id)…� @@ -1066,7 +1083,7 @@ Overrides language id specified with the languageId attribute. - The id of the input type that is used in determining the build “rules” for the output type and for the default name of the output file. The default is the input type with primaryInput == true. + The id of the input type that is used in determining the build “rules� for the output type and for the default name of the output file. The default is the input type with primaryInput == true. @@ -1080,7 +1097,7 @@ Overrides language id specified with the languageId attribute. - Some tools produce files with a special prefix that must be specified. For example, a librarian on POSIX systems expects the output to be libtarget.a, so 'lib' would be the prefix. The default is to use the Tool “outputPrefix” attribute if primaryOutput is True, otherwise the default is an empty string. This attribute supports MBS configuration context macros. + Some tools produce files with a special prefix that must be specified. For example, a librarian on POSIX systems expects the output to be libtarget.a, so 'lib' would be the prefix. The default is to use the Tool “outputPrefix� attribute if primaryOutput is True, otherwise the default is an empty string. This attribute supports MBS configuration context macros. @@ -2016,11 +2033,11 @@ If the "buildPathResolver" attribute is specified, the "pathDelim Represents the applicability type for this enablement. Can contain the following values: -UI_VISIBILITY – the given enablement expression specifies whether the option is to be visible in UI, -UI_ENABLEMENT – the given enablement expression specifies the enable state of the controls that represent the option in UI, -CMD_USAGE – the given enablement expression specifies whether the option is to be used in command line +UI_VISIBILITY – the given enablement expression specifies whether the option is to be visible in UI, +UI_ENABLEMENT – the given enablement expression specifies the enable state of the controls that represent the option in UI, +CMD_USAGE – the given enablement expression specifies whether the option is to be used in command line CONTAINER_ATTRIBUTE - the given enablement expressions specifies thecontainer attribute value -ALL – this value means the combination of all the above values. +ALL – this value means the combination of all the above values. Several types could be specified simultaneously using the "|" as a delimiter, e.g.: type="UI_VISIBILITY|CMD_USAGE" @@ -2154,7 +2171,7 @@ Default value is true. - Specifies the expected value. If the current option value matches the value specified in this attribute, the checkOption element is treated as true, otherwise – as false. + Specifies the expected value. If the current option value matches the value specified in this attribute, the checkOption element is treated as true, otherwise – as false. The expected value could be specified either as a string that may contain build macros or as a regular expression. During the comparison, the build macros are resolved and the option value is checked to match the resulting string or regular expression. The way the expected value is specified and treated depends on the value of the isRegex attribute @@ -2169,14 +2186,14 @@ The expected value could be specified either as a string that may contain build - The id of the option which is to be compared with the option specified with the “optionId” attribute. The default is the id of the option that holds this expression. If the “value” attribute is specified, both the “otherOptionId” and the “otherHolderId” attributes are ignored. When searching for the option to be checked, MBS will examine all the options the holder contains along with all superclasses of each option to find the option with the specified id. + The id of the option which is to be compared with the option specified with the “optionId� attribute. The default is the id of the option that holds this expression. If the “value� attribute is specified, both the “otherOptionId� and the “otherHolderId� attributes are ignored. When searching for the option to be checked, MBS will examine all the options the holder contains along with all superclasses of each option to find the option with the specified id. - The option holder id that holds the option specified with the “otherOptionId” attribute. The default is the id of the holder that holds the container of this expression. If the “value” attribute is specified, both the “otherOptionId” and the “otherHolderId” attributes are ingnored. When searching for the needed holder, MBS will examine all the holders the current configuration contains along with all superclasses of each holder in order to find the holder with the specified id. + The option holder id that holds the option specified with the “otherOptionId� attribute. The default is the id of the holder that holds the container of this expression. If the “value� attribute is specified, both the “otherOptionId� and the “otherHolderId� attributes are ingnored. When searching for the needed holder, MBS will examine all the holders the current configuration contains along with all superclasses of each holder in order to find the holder with the specified id. @@ -2200,7 +2217,7 @@ The expected value could be specified either as a string that may contain build - Specifies the expected value. If the current string specified in the “string” attribute matches the value specified in this attribute, the checkString element is treated as true, otherwise – as false. + Specifies the expected value. If the current string specified in the “string� attribute matches the value specified in this attribute, the checkString element is treated as true, otherwise – as false. The expected value could be specified either as a string that might contain the build macros or as a regular expression. The way the value is specified and treated depends on the value of the isRegex attribute. diff --git a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/build/internal/core/scannerconfig2/CfgScannerConfigProfileManager.java b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/build/internal/core/scannerconfig2/CfgScannerConfigProfileManager.java index bef0ef6047f..632659b2a55 100644 --- a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/build/internal/core/scannerconfig2/CfgScannerConfigProfileManager.java +++ b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/build/internal/core/scannerconfig2/CfgScannerConfigProfileManager.java @@ -10,8 +10,14 @@ *******************************************************************************/ package org.eclipse.cdt.build.internal.core.scannerconfig2; +import java.util.Collection; +import java.util.Map; + import org.eclipse.cdt.build.core.scannerconfig.CfgInfoContext; import org.eclipse.cdt.build.core.scannerconfig.ICfgScannerConfigBuilderInfo2Set; +import org.eclipse.cdt.core.settings.model.ICConfigurationDescription; +import org.eclipse.cdt.core.settings.model.ICProjectDescription; +import org.eclipse.cdt.make.core.scannerconfig.IScannerConfigBuilderInfo2; import org.eclipse.cdt.make.core.scannerconfig.InfoContext; import org.eclipse.cdt.make.core.scannerconfig.ScannerConfigScope; import org.eclipse.cdt.make.internal.core.scannerconfig2.ScannerConfigProfile; @@ -44,4 +50,34 @@ public class CfgScannerConfigProfileManager { return new CfgInfoContext(cfg).toInfoContext(); return new InfoContext(project); } + + public static boolean disableScannerDiscovery(IConfiguration cfg) { + boolean isChanged = false; + + ICfgScannerConfigBuilderInfo2Set info2set = getCfgScannerConfigBuildInfo(cfg); + Map infoMap = info2set.getInfoMap(); + Collection infos = infoMap.values(); + for (IScannerConfigBuilderInfo2 info2 : infos) { + isChanged = isChanged || info2.isAutoDiscoveryEnabled(); + info2.setAutoDiscoveryEnabled(false); + } + return isChanged; + } + + public static boolean disableScannerDiscovery(ICProjectDescription prjDescription) { + boolean isChanged = false; + + ICConfigurationDescription[] cfgDescs = prjDescription.getConfigurations(); + if (cfgDescs!=null) { + for (ICConfigurationDescription cfgDesc : cfgDescs) { + IConfiguration cfg = ManagedBuildManager.getConfigurationForDescription(cfgDesc); + boolean changed=CfgScannerConfigProfileManager.disableScannerDiscovery(cfg); + if (changed) { + isChanged = true; + } + + } + } + return isChanged; + } } diff --git a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/core/ExternalBuildRunner.java b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/core/ExternalBuildRunner.java index 42940a74288..171046d3e2c 100644 --- a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/core/ExternalBuildRunner.java +++ b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/core/ExternalBuildRunner.java @@ -25,15 +25,23 @@ import org.eclipse.cdt.build.core.scannerconfig.ICfgScannerConfigBuilderInfo2Set import org.eclipse.cdt.build.internal.core.scannerconfig2.CfgScannerConfigProfileManager; import org.eclipse.cdt.core.CCorePlugin; import org.eclipse.cdt.core.ErrorParserManager; +import org.eclipse.cdt.core.ICConsoleParser; import org.eclipse.cdt.core.ICommandLauncher; +import org.eclipse.cdt.core.IConsoleParser; import org.eclipse.cdt.core.IMarkerGenerator; import org.eclipse.cdt.core.envvar.IEnvironmentVariable; import org.eclipse.cdt.core.envvar.IEnvironmentVariableManager; +import org.eclipse.cdt.core.language.settings.providers.ILanguageSettingsProvider; +import org.eclipse.cdt.core.language.settings.providers.LanguageSettingsManager; +import org.eclipse.cdt.core.language.settings.providers.LanguageSettingsManager_TBD; import org.eclipse.cdt.core.model.ICModelMarker; import org.eclipse.cdt.core.resources.IConsole; import org.eclipse.cdt.core.resources.RefreshScopeManager; import org.eclipse.cdt.core.settings.model.ICConfigurationDescription; +import org.eclipse.cdt.core.settings.model.ICProjectDescription; import org.eclipse.cdt.internal.core.ConsoleOutputSniffer; +import org.eclipse.cdt.internal.core.language.settings.providers.LanguageSettingsProvidersSerializer; +import org.eclipse.cdt.make.core.scannerconfig.ILanguageSettingsBuiltinSpecsDetector; import org.eclipse.cdt.make.core.scannerconfig.IScannerConfigBuilderInfo2; import org.eclipse.cdt.make.core.scannerconfig.IScannerInfoCollector; import org.eclipse.cdt.make.core.scannerconfig.IScannerInfoConsoleParser; @@ -114,6 +122,23 @@ public class ExternalBuildRunner extends AbstractBuildRunner { break; } + URI workingDirectoryURI = ManagedBuildManager.getBuildLocationURI(configuration, builder); + final String pathFromURI = EFSExtensionManager.getDefault().getPathFromURI(workingDirectoryURI); + if(pathFromURI == null) { + throw new CoreException(new Status(IStatus.ERROR, ManagedBuilderCorePlugin.PLUGIN_ID, ManagedMakeMessages.getString("ManagedMakeBuilder.message.error"), null)); //$NON-NLS-1$ + } + + IPath workingDirectory = new Path(pathFromURI); + + // Set the environment + Map envMap = getEnvironment(builder); + String[] env = getEnvStrings(envMap); + + ICConfigurationDescription cfgDescription = ManagedBuildManager.getDescriptionForConfiguration(configuration); + if (kind!=IncrementalProjectBuilder.CLEAN_BUILD) { + ManagedBuildManager.runBuiltinSpecsDetectors(cfgDescription, workingDirectory, env, monitor); + } + consoleHeader[1] = configuration.getName(); consoleHeader[2] = project.getName(); buf.append(NEWLINE); @@ -135,14 +160,6 @@ public class ExternalBuildRunner extends AbstractBuildRunner { if (markers != null) workspace.deleteMarkers(markers); - URI workingDirectoryURI = ManagedBuildManager.getBuildLocationURI(configuration, builder); - final String pathFromURI = EFSExtensionManager.getDefault().getPathFromURI(workingDirectoryURI); - if(pathFromURI == null) { - throw new CoreException(new Status(IStatus.ERROR, ManagedBuilderCorePlugin.PLUGIN_ID, ManagedMakeMessages.getString("ManagedMakeBuilder.message.error"), null)); //$NON-NLS-1$ - } - - IPath workingDirectory = new Path(pathFromURI); - String[] targets = getTargets(kind, builder); if (targets.length != 0 && targets[targets.length - 1].equals(builder.getCleanBuildTarget())) isClean = true; @@ -153,9 +170,6 @@ public class ExternalBuildRunner extends AbstractBuildRunner { // Print the command for visual interaction. launcher.showCommand(true); - // Set the environment - Map envMap = getEnvironment(builder); - String[] env = getEnvStrings(envMap); String[] buildArguments = targets; String[] newArgs = CommandLineUtil.argumentsToArray(builder.getBuildArguments()); @@ -175,9 +189,15 @@ public class ExternalBuildRunner extends AbstractBuildRunner { OutputStream stderr = streamMon; // Sniff console output for scanner info - ConsoleOutputSniffer sniffer = createBuildOutputSniffer(stdout, stderr, project, configuration, workingDirectory, markerGenerator, null); - OutputStream consoleOut = (sniffer == null ? stdout : sniffer.getOutputStream()); - OutputStream consoleErr = (sniffer == null ? stderr : sniffer.getErrorStream()); + OutputStream consoleOut = stdout; + OutputStream consoleErr = stderr; + if (kind!=IncrementalProjectBuilder.CLEAN_BUILD) { + ConsoleOutputSniffer sniffer = createBuildOutputSniffer(stdout, stderr, project, configuration, workingDirectory, markerGenerator, null, epm); + if (sniffer!=null) { + consoleOut = sniffer.getOutputStream(); + consoleErr = sniffer.getErrorStream(); + } + } Process p = launcher.execute(buildCommand, buildArguments, env, workingDirectory, monitor); if (p != null) { try { @@ -193,6 +213,14 @@ public class ExternalBuildRunner extends AbstractBuildRunner { errMsg = launcher.getErrorMessage(); monitor.subTask(ManagedMakeMessages.getResourceString("MakeBuilder.Updating_project")); //$NON-NLS-1$ + // AG: FIXME +// try { +// LanguageSettingsManager.serialize(cfgDescription); +// } catch (CoreException e) { +// // TODO Auto-generated catch block +// e.printStackTrace(); +// } + try { // Do not allow the cancel of the refresh, since the builder is external // to Eclipse, files may have been created/modified and we will be out-of-sync. @@ -245,6 +273,11 @@ public class ExternalBuildRunner extends AbstractBuildRunner { consoleOut.close(); consoleErr.close(); cos.close(); + if (kind!=IncrementalProjectBuilder.CLEAN_BUILD) { + LanguageSettingsManager_TBD.serializeWorkspaceProviders(); + ICProjectDescription prjDescription = CCorePlugin.getDefault().getProjectDescription(project, false); + LanguageSettingsProvidersSerializer.serializeLanguageSettings(prjDescription); + } } } catch (Exception e) { ManagedBuilderCorePlugin.log(e); @@ -337,10 +370,11 @@ public class ExternalBuildRunner extends AbstractBuildRunner { IConfiguration cfg, IPath workingDirectory, IMarkerGenerator markerGenerator, - IScannerInfoCollector collector){ + IScannerInfoCollector collector, + ErrorParserManager epm){ ICfgScannerConfigBuilderInfo2Set container = CfgScannerConfigProfileManager.getCfgScannerConfigBuildInfo(cfg); Map map = container.getInfoMap(); - List clParserList = new ArrayList(); + List clParserList = new ArrayList(); if(container.isPerRcTypeDiscovery()){ for (IResourceInfo rcInfo : cfg.getResourceInfos()) { @@ -370,9 +404,25 @@ public class ExternalBuildRunner extends AbstractBuildRunner { contributeToConsoleParserList(project, map, new CfgInfoContext(cfg), workingDirectory, markerGenerator, collector, clParserList); } + ICConfigurationDescription cfgDescription = ManagedBuildManager.getDescriptionForConfiguration(cfg); + List lsProviders = cfgDescription.getLanguageSettingProviders(); + for (ILanguageSettingsProvider lsProvider : lsProviders) { + ILanguageSettingsProvider rawProvider = LanguageSettingsManager.getRawProvider(lsProvider); + if (rawProvider instanceof ICConsoleParser && !(rawProvider instanceof ILanguageSettingsBuiltinSpecsDetector)) { + ICConsoleParser consoleParser = (ICConsoleParser) rawProvider; + try { + consoleParser.startup(cfgDescription); + clParserList.add(consoleParser); + } catch (CoreException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + } + if(clParserList.size() != 0){ - return new ConsoleOutputSniffer(outputStream, errorStream, - clParserList.toArray(new IScannerInfoConsoleParser[clParserList.size()])); + IConsoleParser[] parsers = clParserList.toArray(new IConsoleParser[clParserList.size()]); + return new ConsoleOutputSniffer(outputStream, errorStream, parsers, epm); } return null; @@ -385,7 +435,7 @@ public class ExternalBuildRunner extends AbstractBuildRunner { IPath workingDirectory, IMarkerGenerator markerGenerator, IScannerInfoCollector collector, - List parserList){ + List parserList){ IScannerConfigBuilderInfo2 info = map.get(context); InfoContext ic = context.toInfoContext(); boolean added = false; @@ -416,5 +466,4 @@ public class ExternalBuildRunner extends AbstractBuildRunner { return added; } - } diff --git a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/core/IConfiguration.java b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/core/IConfiguration.java index 8b7f0499dce..3ab54cf1ec7 100644 --- a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/core/IConfiguration.java +++ b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/core/IConfiguration.java @@ -46,6 +46,7 @@ public interface IConfiguration extends IBuildObject, IBuildObjectPropertiesCont // Schema element names public static final String CONFIGURATION_ELEMENT_NAME = "configuration"; //$NON-NLS-1$ public static final String ERROR_PARSERS = "errorParsers"; //$NON-NLS-1$ + public static final String LANGUAGE_SETTINGS_PROVIDERS = "languageSettingsProviders"; public static final String EXTENSION = "artifactExtension"; //$NON-NLS-1$ public static final String PARENT = "parent"; //$NON-NLS-1$ @@ -170,6 +171,8 @@ public interface IConfiguration extends IBuildObject, IBuildObjectPropertiesCont */ public String[] getErrorParserList(); + public String getDefaultLanguageSettingsProvidersIds(); + /** * Projects have C or CC natures. Tools can specify a filter so they are not * misapplied to a project. This method allows the caller to retrieve a list diff --git a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/core/IToolChain.java b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/core/IToolChain.java index 57cba447fca..34a1a4331b7 100644 --- a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/core/IToolChain.java +++ b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/core/IToolChain.java @@ -53,6 +53,8 @@ public interface IToolChain extends IBuildObject, IHoldsOptions { // The attribute name for the scanner info collector public static final String SCANNER_CONFIG_PROFILE_ID = "scannerConfigDiscoveryProfileId"; //$NON-NLS-1$ + public static final String LANGUAGE_SETTINGS_PROVIDERS = "languageSettingsProviders"; + /** * Returns the configuration that is the parent of this tool-chain. * @@ -261,6 +263,13 @@ public interface IToolChain extends IBuildObject, IHoldsOptions { */ public void setErrorParserIds(String ids); + /** + * Returns the default language settings providers IDs. + * + * @return the default language settings providers IDs separated by semicolon or {@code null} if none. + */ + public String getDefaultLanguageSettingsProvidersIds(); + /** * Returns the scanner config discovery profile id or null if none. * diff --git a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/core/InternalBuildRunner.java b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/core/InternalBuildRunner.java index b8f525e1a1b..933d9750483 100644 --- a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/core/InternalBuildRunner.java +++ b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/core/InternalBuildRunner.java @@ -13,14 +13,26 @@ package org.eclipse.cdt.managedbuilder.core; import java.io.IOException; import java.io.OutputStream; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import org.eclipse.cdt.core.CCorePlugin; import org.eclipse.cdt.core.ConsoleOutputStream; import org.eclipse.cdt.core.ErrorParserManager; import org.eclipse.cdt.core.IMarkerGenerator; +import org.eclipse.cdt.core.language.settings.providers.ILanguageSettingsProvider; +import org.eclipse.cdt.core.language.settings.providers.LanguageSettingsManager_TBD; import org.eclipse.cdt.core.model.ICModelMarker; import org.eclipse.cdt.core.resources.IConsole; +import org.eclipse.cdt.core.settings.model.ICConfigurationDescription; +import org.eclipse.cdt.core.settings.model.ICProjectDescription; +import org.eclipse.cdt.internal.core.language.settings.providers.LanguageSettingsProvidersSerializer; +import org.eclipse.cdt.make.core.scannerconfig.ILanguageSettingsBuildOutputScanner; import org.eclipse.cdt.managedbuilder.buildmodel.BuildDescriptionManager; import org.eclipse.cdt.managedbuilder.buildmodel.IBuildDescription; +import org.eclipse.cdt.managedbuilder.internal.buildmodel.BuildDescription; import org.eclipse.cdt.managedbuilder.internal.buildmodel.BuildStateManager; import org.eclipse.cdt.managedbuilder.internal.buildmodel.DescriptionBuilder; import org.eclipse.cdt.managedbuilder.internal.buildmodel.IBuildModelBuilder; @@ -35,6 +47,7 @@ import org.eclipse.core.resources.IResourceDelta; import org.eclipse.core.resources.IWorkspace; import org.eclipse.core.resources.IncrementalProjectBuilder; import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.NullProgressMonitor; @@ -61,6 +74,21 @@ public class InternalBuildRunner extends AbstractBuildRunner { private static final String NOTHING_BUILT = "ManagedMakeBuilder.message.no.build"; //$NON-NLS-1$ private static final String BUILD_ERROR = "ManagedMakeBuilder.message.error"; //$NON-NLS-1$ + + // TODO: same function is present in CommandBuilder and BuildProcessManager + private String[] mapToStringArray(Map map){ + if(map == null) + return null; + + List list = new ArrayList(); + + for (Entry entry : map.entrySet()) { + list.add(entry.getKey() + '=' + entry.getValue()); + } + + return list.toArray(new String[list.size()]); + } + @Override public boolean invokeBuild(int kind, IProject project, IConfiguration configuration, IBuilder builder, IConsole console, IMarkerGenerator markerGenerator, @@ -96,6 +124,16 @@ public class InternalBuildRunner extends AbstractBuildRunner { // Get a build console for the project StringBuffer buf = new StringBuffer(); + + IBuildDescription des = BuildDescriptionManager.createBuildDescription(configuration, cBS, delta, flags); + + IPath workingDirectory = des.getDefaultBuildDirLocation(); + String[] env = null; + if (des instanceof BuildDescription) { + Map envMap = ((BuildDescription)des).getEnvironment(); + env = mapToStringArray(envMap); + } + consoleOutStream = console.getOutputStream(); String[] consoleHeader = new String[3]; if(buildIncrementaly) @@ -119,11 +157,28 @@ public class InternalBuildRunner extends AbstractBuildRunner { buf.append(System.getProperty("line.separator", "\n")); //$NON-NLS-1$ //$NON-NLS-2$ buf.append(System.getProperty("line.separator", "\n")); //$NON-NLS-1$ //$NON-NLS-2$ } + + if (kind!=IncrementalProjectBuilder.CLEAN_BUILD) { + ICConfigurationDescription cfgDescription = ManagedBuildManager.getDescriptionForConfiguration(configuration); + ManagedBuildManager.runBuiltinSpecsDetectors(cfgDescription, workingDirectory, env, monitor); + + List providers = cfgDescription.getLanguageSettingProviders(); + for (ILanguageSettingsProvider provider : providers) { + if (provider instanceof ILanguageSettingsBuildOutputScanner) { + buf.append(System.getProperty("line.separator", "\n")); //$NON-NLS-1$ //$NON-NLS-2$ + String msg = ManagedMakeMessages.getFormattedString("BOP Language Settings Provider [{0}] is not supported by Internal Builder.", provider.getName()); + buf.append("**** "+msg+" ****"); + buf.append(System.getProperty("line.separator", "\n")); //$NON-NLS-1$ //$NON-NLS-2$ + buf.append(System.getProperty("line.separator", "\n")); //$NON-NLS-1$ //$NON-NLS-2$ + + ManagedBuilderCorePlugin.error(msg); + } + } + } + consoleOutStream.write(buf.toString().getBytes()); consoleOutStream.flush(); - IBuildDescription des = BuildDescriptionManager.createBuildDescription(configuration, cBS, delta, flags); - DescriptionBuilder dBuilder = null; if (!isParallel) dBuilder = new DescriptionBuilder(des, buildIncrementaly, resumeOnErr, cBS); @@ -193,6 +248,12 @@ public class InternalBuildRunner extends AbstractBuildRunner { consoleOutStream.flush(); epmOutputStream.close(); epmOutputStream = null; + if (kind!=IncrementalProjectBuilder.CLEAN_BUILD) { + LanguageSettingsManager_TBD.serializeWorkspaceProviders(); + ICProjectDescription prjDescription = CCorePlugin.getDefault().getProjectDescription(project, false); + LanguageSettingsProvidersSerializer.serializeLanguageSettings(prjDescription); + } + // Generate any error markers that the build has discovered monitor.subTask(ManagedMakeMessages .getResourceString(MARKERS)); @@ -240,5 +301,4 @@ public class InternalBuildRunner extends AbstractBuildRunner { } return false; } - } diff --git a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/core/ManagedBuildManager.java b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/core/ManagedBuildManager.java index 6d8981d5bcc..296753806cd 100644 --- a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/core/ManagedBuildManager.java +++ b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/core/ManagedBuildManager.java @@ -49,17 +49,27 @@ import javax.xml.transform.stream.StreamResult; import org.eclipse.cdt.core.AbstractCExtension; import org.eclipse.cdt.core.CCorePlugin; +import org.eclipse.cdt.core.index.IIndexManager; +import org.eclipse.cdt.core.language.settings.providers.ILanguageSettingsProvider; +import org.eclipse.cdt.core.language.settings.providers.LanguageSettingsManager; +import org.eclipse.cdt.core.language.settings.providers.LanguageSettingsManager_TBD; import org.eclipse.cdt.core.model.CoreModel; import org.eclipse.cdt.core.model.CoreModelUtil; +import org.eclipse.cdt.core.model.ICElement; +import org.eclipse.cdt.core.model.ICProject; import org.eclipse.cdt.core.parser.IScannerInfo; import org.eclipse.cdt.core.parser.IScannerInfoChangeListener; import org.eclipse.cdt.core.settings.model.ICConfigurationDescription; +import org.eclipse.cdt.core.settings.model.ICFolderDescription; +import org.eclipse.cdt.core.settings.model.ICLanguageSetting; import org.eclipse.cdt.core.settings.model.ICMultiConfigDescription; import org.eclipse.cdt.core.settings.model.ICProjectDescription; import org.eclipse.cdt.core.settings.model.ICProjectDescriptionManager; import org.eclipse.cdt.core.settings.model.ICSettingEntry; import org.eclipse.cdt.core.settings.model.XmlStorageUtil; import org.eclipse.cdt.core.settings.model.extension.CConfigurationData; +import org.eclipse.cdt.make.core.MakeCorePlugin; +import org.eclipse.cdt.make.core.scannerconfig.ILanguageSettingsBuiltinSpecsDetector; import org.eclipse.cdt.managedbuilder.buildproperties.IBuildProperty; import org.eclipse.cdt.managedbuilder.buildproperties.IBuildPropertyManager; import org.eclipse.cdt.managedbuilder.envvar.IEnvironmentBuildPathsChangeListener; @@ -149,6 +159,7 @@ import org.w3c.dom.ProcessingInstruction; */ public class ManagedBuildManager extends AbstractCExtension { + public static final String MBS_LANGUAGE_SETTINGS_PROVIDER = "org.eclipse.cdt.managedbuilder.core.LanguageSettingsProvider"; // private static final QualifiedName buildInfoProperty = new QualifiedName(ManagedBuilderCorePlugin.getUniqueIdentifier(), "managedBuildInfo"); //$NON-NLS-1$ private static final String ROOT_NODE_NAME = "ManagedProjectBuildInfo"; //$NON-NLS-1$ public static final String SETTINGS_FILE_NAME = ".cdtbuild"; //$NON-NLS-1$ @@ -4714,4 +4725,138 @@ public class ManagedBuildManager extends AbstractCExtension { return true; // no target platform - nothing to check. } + private static String getLanguageSettingsProvidersStr(IToolChain toolchain) { + for (;toolchain!=null;toolchain=toolchain.getSuperClass()) { + String providersIdsStr = toolchain.getDefaultLanguageSettingsProvidersIds(); + if (providersIdsStr!=null) { + return providersIdsStr; + } + } + return ""; + } + + private static String getLanguageSettingsProvidersStr(IConfiguration cfg) { + for (;cfg!=null;cfg=cfg.getParent()) { + String providersIdsStr = cfg.getDefaultLanguageSettingsProvidersIds(); + if (providersIdsStr!=null) { + return providersIdsStr; + } + } + return ""; + } + + public static List getLanguageSettingsProviders(IConfiguration cfg) { + List providers = new ArrayList(); + + String providersIdsStr = getLanguageSettingsProvidersStr(cfg); + if (providersIdsStr!=null) { + if (providersIdsStr.contains("${Toolchain}")) { + IToolChain toolchain = cfg.getToolChain(); + String toolchainProvidersIds = getLanguageSettingsProvidersStr(toolchain); + if (toolchainProvidersIds==null) { + toolchainProvidersIds=""; + } + providersIdsStr = providersIdsStr.replaceAll("\\$\\{Toolchain\\}", toolchainProvidersIds); + } + List providersIds = Arrays.asList(providersIdsStr.split(String.valueOf(LanguageSettingsManager_TBD.PROVIDER_DELIMITER))); + for (String id : providersIds) { + id = id.trim(); + ILanguageSettingsProvider provider = null; + if (id.startsWith("*")) { + id = id.substring(1); + provider = LanguageSettingsManager.getWorkspaceProvider(id); + } else if (id.startsWith("-")) { + id = id.substring(1); + for (ILanguageSettingsProvider pr : providers) { + if (pr.getId().equals(id)) { + providers.remove(pr); + // Has to break as the collection is invalidated + // TODO: remove all elements or better use unique list + break; + } + } + } else if (id.length()>0){ + provider = LanguageSettingsManager.getExtensionProviderCopy(id); + } + if (provider!=null) { + providers.add(provider); + } + } + } + + if (providers.isEmpty()) { + // Add MBS provider for unsuspecting toolchains (backward compatibility) + ILanguageSettingsProvider provider = LanguageSettingsManager.getWorkspaceProvider(MBS_LANGUAGE_SETTINGS_PROVIDER); + providers.add(provider); + } + + if (!isProviderThere(providers, LanguageSettingsManager_TBD.PROVIDER_UI_USER)) { + ILanguageSettingsProvider provider = LanguageSettingsManager.getExtensionProviderCopy(LanguageSettingsManager_TBD.PROVIDER_UI_USER); + providers.add(0, provider); + } + + return providers; + } + + private static boolean isProviderThere(List providers, String id) { + for (ILanguageSettingsProvider provider : providers) { + if (provider.getId().equals(id)) { + return true; + } + } + return false; + } + + /** + * TODO - better home? + */ + static public void runBuiltinSpecsDetectors(ICConfigurationDescription cfgDescription, IPath workingDirectory, + String[] env, IProgressMonitor monitor) { + IProject project = cfgDescription.getProjectDescription().getProject(); + ICFolderDescription rootFolderDescription = cfgDescription.getRootFolderDescription(); + List languageIds = new ArrayList(); + for (ICLanguageSetting languageSetting : rootFolderDescription.getLanguageSettings()) { + String id = languageSetting.getLanguageId(); + if (id!=null) { + languageIds.add(id); + } + } + + for (ILanguageSettingsProvider provider : cfgDescription.getLanguageSettingProviders()) { + ILanguageSettingsProvider rawProvider = LanguageSettingsManager.getRawProvider(provider); + if (rawProvider instanceof ILanguageSettingsBuiltinSpecsDetector) { + ILanguageSettingsBuiltinSpecsDetector detector = (ILanguageSettingsBuiltinSpecsDetector)rawProvider; + boolean isWorkspaceProvider = LanguageSettingsManager.isWorkspaceProvider(provider); + for (String languageId : languageIds) { + if (detector.getLanguageScope()==null || detector.getLanguageScope().contains(languageId)) { + try { + if (isWorkspaceProvider) { + detector.run(project, languageId, workingDirectory, env, monitor); + } else { + detector.run(cfgDescription, languageId, workingDirectory, env, monitor); + } + // detector.shutdown() is called from ConsoleOutputSniffer + } catch (Throwable e) { + IStatus status = new Status(IStatus.ERROR, MakeCorePlugin.PLUGIN_ID, "Internal error in BuiltinSpecsDetector "+detector.getId(), e); + MakeCorePlugin.log(status); + } + } + } + } + } + + + // AG: FIXME +// LanguageSettingsManager.serialize(cfgDescription); + // AG: FIXME - rather send event that ls settings changed + ICProject icProject = CoreModel.getDefault().create(project); + ICElement[] tuSelection = new ICElement[] {icProject}; + try { + CCorePlugin.getIndexManager().update(tuSelection, IIndexManager.UPDATE_ALL | IIndexManager.UPDATE_EXTERNAL_FILES_FOR_PROJECT); + } catch (CoreException e) { + IStatus status = new Status(IStatus.ERROR, ManagedBuilderCorePlugin.PLUGIN_ID, "Error updating CDT index", e); + ManagedBuilderCorePlugin.log(status); + } + } + } diff --git a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/core/CommonBuilder.java b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/core/CommonBuilder.java index 3167b768e3e..06bf6f49a73 100644 --- a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/core/CommonBuilder.java +++ b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/core/CommonBuilder.java @@ -26,6 +26,8 @@ import java.util.Set; import org.eclipse.cdt.core.CCorePlugin; import org.eclipse.cdt.core.ConsoleOutputStream; import org.eclipse.cdt.core.ProblemMarkerInfo; +import org.eclipse.cdt.core.language.settings.providers.ILanguageSettingsProvider; +import org.eclipse.cdt.core.language.settings.providers.LanguageSettingsManager_TBD; import org.eclipse.cdt.core.model.CoreModel; import org.eclipse.cdt.core.resources.ACBuilder; import org.eclipse.cdt.core.resources.IConsole; @@ -145,6 +147,7 @@ public class CommonBuilder extends ACBuilder { private final IConfiguration fCfg; private final IBuilder fBuilder; private IConsole fConsole; + CfgBuildInfo(IBuilder builder, boolean isForegound){ this.fBuilder = builder; this.fCfg = builder.getParent().getParent(); diff --git a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/core/Configuration.java b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/core/Configuration.java index ef84a29dc1e..a2093855a1c 100644 --- a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/core/Configuration.java +++ b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/core/Configuration.java @@ -105,6 +105,7 @@ public class Configuration extends BuildObject implements IConfiguration, IBuild private String cleanCommand; private String artifactExtension; private String errorParserIds; + private String defaultLanguageSettingsProvidersIds; private String prebuildStep; private String postbuildStep; private String preannouncebuildStep; @@ -784,6 +785,9 @@ public class Configuration extends BuildObject implements IConfiguration, IBuild // Get the semicolon separated list of IDs of the error parsers errorParserIds = SafeStringInterner.safeIntern(element.getAttribute(ERROR_PARSERS)); + // Get the initial/default language setttings providers IDs + defaultLanguageSettingsProvidersIds = SafeStringInterner.safeIntern(element.getAttribute(LANGUAGE_SETTINGS_PROVIDERS)); + // Get the artifact extension artifactExtension = SafeStringInterner.safeIntern(element.getAttribute(EXTENSION)); @@ -1425,6 +1429,10 @@ public class Configuration extends BuildObject implements IConfiguration, IBuild return set; } + public String getDefaultLanguageSettingsProvidersIds() { + return defaultLanguageSettingsProvidersIds; + } + /* (non-Javadoc) * @see org.eclipse.cdt.managedbuilder.core.IConfiguration#setArtifactExtension(java.lang.String) */ diff --git a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/core/MultiConfiguration.java b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/core/MultiConfiguration.java index d9834448cad..a2bfbc22137 100644 --- a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/core/MultiConfiguration.java +++ b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/core/MultiConfiguration.java @@ -403,6 +403,11 @@ public class MultiConfiguration extends MultiItemsHolder implements return s; } + public String getDefaultLanguageSettingsProvidersIds() { + ManagedBuilderCorePlugin.error("Default Language Settings Providers are not supported in multiconfiguration mode"); + return null; + } + /* (non-Javadoc) * @see org.eclipse.cdt.managedbuilder.core.IConfiguration#getFilteredTools() */ diff --git a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/core/ToolChain.java b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/core/ToolChain.java index 6dd49708b6f..fb0bca68433 100644 --- a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/core/ToolChain.java +++ b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/core/ToolChain.java @@ -85,6 +85,7 @@ public class ToolChain extends HoldsOptions implements IToolChain, IMatchKeyProv private String targetToolIds; private String secondaryOutputIds; private Boolean isAbstract; + private String defaultLanguageSettingsProvidersIds; private String scannerConfigDiscoveryProfileId; private String versionsSupported; private String convertToId; @@ -554,6 +555,9 @@ public class ToolChain extends HoldsOptions implements IToolChain, IMatchKeyProv // Get the target tool id targetToolIds = SafeStringInterner.safeIntern(element.getAttribute(TARGET_TOOL)); + // Get the initial/default language setttings providers IDs + defaultLanguageSettingsProvidersIds = element.getAttribute(LANGUAGE_SETTINGS_PROVIDERS); + // Get the scanner config discovery profile id scannerConfigDiscoveryProfileId = SafeStringInterner.safeIntern(element.getAttribute(SCANNER_CONFIG_PROFILE_ID)); String tmp = element.getAttribute(RESOURCE_TYPE_BASED_DISCOVERY); @@ -1501,6 +1505,10 @@ public class ToolChain extends HoldsOptions implements IToolChain, IMatchKeyProv setDirty(true); } + public String getDefaultLanguageSettingsProvidersIds() { + return defaultLanguageSettingsProvidersIds; + } + /* (non-Javadoc) * @see org.eclipse.cdt.managedbuilder.core.IToolChain#getScannerConfigDiscoveryProfileId() */ diff --git a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/scannerconfig/AbstractBuiltinSpecsDetector.java b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/scannerconfig/AbstractBuiltinSpecsDetector.java new file mode 100644 index 00000000000..4b0a3ac816e --- /dev/null +++ b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/scannerconfig/AbstractBuiltinSpecsDetector.java @@ -0,0 +1,508 @@ +/******************************************************************************* + * Copyright (c) 2009, 2011 Andrew Gvozdev 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: + * Andrew Gvozdev - initial API and implementation + *******************************************************************************/ + +package org.eclipse.cdt.managedbuilder.internal.scannerconfig; + +import java.io.IOException; +import java.io.OutputStream; +import java.net.URL; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.eclipse.cdt.core.CCorePlugin; +import org.eclipse.cdt.core.CommandLauncher; +import org.eclipse.cdt.core.ErrorParserManager; +import org.eclipse.cdt.core.ICommandLauncher; +import org.eclipse.cdt.core.IConsoleParser; +import org.eclipse.cdt.core.model.ILanguageDescriptor; +import org.eclipse.cdt.core.model.LanguageManager; +import org.eclipse.cdt.core.resources.IConsole; +import org.eclipse.cdt.core.settings.model.ICConfigurationDescription; +import org.eclipse.cdt.core.settings.model.ICLanguageSettingEntry; +import org.eclipse.cdt.internal.core.ConsoleOutputSniffer; +import org.eclipse.cdt.internal.core.XmlUtil; +import org.eclipse.cdt.make.core.MakeCorePlugin; +import org.eclipse.cdt.make.core.scannerconfig.AbstractLanguageSettingsOutputScanner; +import org.eclipse.cdt.make.core.scannerconfig.ILanguageSettingsBuiltinSpecsDetector; +import org.eclipse.cdt.make.internal.core.MakeMessages; +import org.eclipse.cdt.make.internal.core.StreamMonitor; +import org.eclipse.cdt.make.internal.core.scannerconfig2.SCMarkerGenerator; +import org.eclipse.cdt.managedbuilder.core.IInputType; +import org.eclipse.cdt.managedbuilder.core.ITool; +import org.eclipse.cdt.managedbuilder.core.IToolChain; +import org.eclipse.cdt.managedbuilder.core.ManagedBuildManager; +import org.eclipse.cdt.managedbuilder.core.ManagedBuilderCorePlugin; +import org.eclipse.cdt.utils.CommandLineUtil; +import org.eclipse.cdt.utils.PathUtil; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.runtime.Assert; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.NullProgressMonitor; +import org.eclipse.core.runtime.Path; +import org.eclipse.core.runtime.Platform; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.SubProgressMonitor; +import org.w3c.dom.Element; + +public abstract class AbstractBuiltinSpecsDetector extends AbstractLanguageSettingsOutputScanner implements ILanguageSettingsBuiltinSpecsDetector { + private static final String NEWLINE = System.getProperty("line.separator", "\n"); //$NON-NLS-1$ //$NON-NLS-2$ + private static final String PLUGIN_CDT_MAKE_UI_ID = "org.eclipse.cdt.make.ui"; //$NON-NLS-1$ + private static final String GMAKE_ERROR_PARSER_ID = "org.eclipse.cdt.core.GmakeErrorParser"; //$NON-NLS-1$ + private static final String PATH_ENV = "PATH"; //$NON-NLS-1$ + private static final String ATTR_RUN_ONCE = "run-once"; //$NON-NLS-1$ + private static final String ATTR_CONSOLE = "console"; //$NON-NLS-1$ + + protected static final String COMPILER_MACRO = "${COMMAND}"; //$NON-NLS-1$ + protected static final String SPEC_FILE_MACRO = "${INPUTS}"; //$NON-NLS-1$ + protected static final String SPEC_EXT_MACRO = "${EXT}"; //$NON-NLS-1$ + protected static final String SPEC_FILE_BASE = "spec."; //$NON-NLS-1$ + + private String currentCommandResolved = null; + protected List detectedSettingEntries = null; + + private boolean runOnce = true; + private boolean isConsoleEnabled = false; + protected java.io.File specFile = null; + protected boolean preserveSpecFile = false; + + /** + * TODO + */ + protected abstract String getToolchainId(); + + @Override + public void configureProvider(String id, String name, List languages, List entries, String customParameter) { + super.configureProvider(id, name, languages, entries, customParameter); + + runOnce = true; + } + + public void setRunOnce(boolean once) { + runOnce = once; + } + + public boolean isRunOnce() { + return runOnce; + } + + public void setConsoleEnabled(boolean enable) { + isConsoleEnabled = enable; + } + + public boolean isConsoleEnabled() { + return isConsoleEnabled; + } + + protected String resolveCommand(String languageId) throws CoreException { + String cmd = getCustomParameter(); + + if (cmd!=null && (cmd.contains(COMPILER_MACRO) || cmd.contains(SPEC_FILE_MACRO) || cmd.contains(SPEC_EXT_MACRO))) { + String toolchainId = getToolchainId(); + ITool tool = getTool(toolchainId, languageId); + if (tool==null) { + IStatus status = new Status(IStatus.ERROR, ManagedBuilderCorePlugin.PLUGIN_ID, "Provider "+getId() + +" unable to find the compiler tool for language " + languageId + + "in toolchain " + toolchainId); + throw new CoreException(status); + } + + if (cmd.contains(COMPILER_MACRO)) { + String compiler = getCompilerCommand(tool); + cmd = cmd.replace(COMPILER_MACRO, compiler); + } + if (cmd.contains(SPEC_FILE_MACRO)) { + String specFileName = getSpecFile(languageId, tool); + cmd = cmd.replace(SPEC_FILE_MACRO, specFileName); + } + if (cmd.contains(SPEC_EXT_MACRO)) { + String specFileExt = getSpecExt(languageId, tool); + cmd = cmd.replace(SPEC_EXT_MACRO, specFileExt); + } + } + return cmd; + } + + /** + * TODO + */ + @Override + protected String parseForResourceName(String line) { + // This works as if workspace-wide + return null; + } + + @Override + protected String determineLanguage(String parsedResourceName) { + // language id is supposed to be set by run(), just return it + return currentLanguageId; + } + + @Override + public void startup(ICConfigurationDescription cfgDescription) throws CoreException { + // for workspace provider cfgDescription is used to figure out the current project for build console + currentCfgDescription = cfgDescription; + if (cfgDescription!=null) { + currentProject = cfgDescription.getProjectDescription().getProject(); + } + + detectedSettingEntries = new ArrayList(); + currentCommandResolved = customParameter; + + specFile = null; + + currentCommandResolved = resolveCommand(currentLanguageId); + } + + @Override + public void shutdown() { + if (detectedSettingEntries!=null && detectedSettingEntries.size()>0) { + groupEntries(detectedSettingEntries); + setSettingEntries(currentCfgDescription, currentResource, currentLanguageId, detectedSettingEntries); + + IStatus status = new Status(IStatus.INFO, MakeCorePlugin.PLUGIN_ID, getClass().getSimpleName() + + " collected " + detectedSettingEntries.size() + " entries" + " for language " + currentLanguageId); + ManagedBuilderCorePlugin.log(status); + } + detectedSettingEntries = null; + + if (specFile!=null && !preserveSpecFile) { + specFile.delete(); + specFile = null; + } + + currentCommandResolved = null; + } + + protected void groupEntries(List inputEntries) { + Map> groupedEntries = new HashMap>(); + int kindMax = 0; + for (ICLanguageSettingEntry entry : inputEntries) { + int kind = entry.getKind(); + if (kind>kindMax) { + kindMax = kind; + } + + List entries = groupedEntries.get(kind); + if (entries==null) { + entries = new ArrayList(); + groupedEntries.put(kind, entries); + } + entries.add(entry); + } + + inputEntries.clear(); + + for (int kind=1;kind<=kindMax;kind++) { + List entries = groupedEntries.get(kind); + if (entries!=null) { + inputEntries.addAll(entries); + } + } + } + + public void run(IProject project, String languageId, IPath workingDirectory, String[] env, + IProgressMonitor monitor) throws CoreException, IOException { + if (isRunOnce() && !isEmpty()) { + return; + } + + currentProject = project; + currentLanguageId = languageId; + startup(null); + + run(workingDirectory, env, monitor); + } + + public void run(ICConfigurationDescription cfgDescription, String languageId, IPath workingDirectory, + String[] env, IProgressMonitor monitor) throws CoreException, IOException { + Assert.isNotNull(cfgDescription); + + if (isRunOnce() && !isEmpty()) { + return; + } + + currentLanguageId = languageId; + startup(cfgDescription); + + run(workingDirectory, env, monitor); + } + + + /** + * TODO: test case for this function + */ + private void run(IPath workingDirectory, String[] env, IProgressMonitor monitor) + throws CoreException, IOException { + + IConsole console; + if (isConsoleEnabled) { + console = startProviderConsole(); + } else { + // that looks in extension points registry and won't find the id + console = CCorePlugin.getDefault().getConsole(MakeCorePlugin.PLUGIN_ID + ".console.hidden"); //$NON-NLS-1$ + } + console.start(currentProject); + OutputStream cos = console.getOutputStream(); + + ErrorParserManager epm = null; + if (currentProject!=null) { + epm = new ErrorParserManager(currentProject, new SCMarkerGenerator(), new String[] {GMAKE_ERROR_PARSER_ID}); + epm.setOutputStream(cos); + } + + if (monitor==null) { + monitor = new NullProgressMonitor(); + } + StreamMonitor streamMon = new StreamMonitor(new SubProgressMonitor(monitor, 70), epm, 100); + OutputStream stdout = streamMon; + OutputStream stderr = streamMon; + + String msg = "Running scanner discovery: " + getName(); + monitor.subTask(msg); + printLine(stdout, "**** " + msg + " ****" + NEWLINE); + + ConsoleOutputSniffer sniffer = new ConsoleOutputSniffer(stdout, stderr, new IConsoleParser[] { this }); + OutputStream consoleOut = sniffer.getOutputStream(); + OutputStream consoleErr = sniffer.getErrorStream(); + + boolean isSuccess = false; + try { + isSuccess = runProgram(currentCommandResolved, env, workingDirectory, monitor, consoleOut, consoleErr); + } catch (Exception e) { + ManagedBuilderCorePlugin.log(e); + } + if (!isSuccess) { + try { + consoleOut.close(); + } catch (IOException e) { + ManagedBuilderCorePlugin.log(e); + } + try { + consoleErr.close(); + } catch (IOException e) { + ManagedBuilderCorePlugin.log(e); + } + } + } + + protected boolean runProgram(String command, String[] env, IPath workingDirectory, IProgressMonitor monitor, + OutputStream consoleOut, OutputStream consoleErr) throws CoreException, IOException { + + if (command==null || command.trim().length()==0) { + return false; + } + + String errMsg = null; + ICommandLauncher launcher = new CommandLauncher(); + + launcher.setProject(currentProject); + + // Print the command for visual interaction. + launcher.showCommand(true); + + String[] cmdArray = CommandLineUtil.argumentsToArray(command); + IPath program = new Path(cmdArray[0]); + String[] args = new String[0]; + if (cmdArray.length>1) { + args = new String[cmdArray.length-1]; + System.arraycopy(cmdArray, 1, args, 0, args.length); + } + + Process p = launcher.execute(program, args, env, workingDirectory, monitor); + + if (p != null) { + // Before launching give visual cues via the monitor + monitor.subTask("Invoking command " + command); + if (launcher.waitAndRead(consoleOut, consoleErr, new SubProgressMonitor(monitor, 0)) + != ICommandLauncher.OK) { + errMsg = launcher.getErrorMessage(); + } + } else { + errMsg = launcher.getErrorMessage(); + } + if (errMsg!=null) { + String errorPrefix = MakeMessages.getString("ExternalScannerInfoProvider.Error_Prefix"); //$NON-NLS-1$ + + String msg = MakeMessages.getFormattedString("ExternalScannerInfoProvider.Provider_Error", command); + printLine(consoleErr, errorPrefix + msg + NEWLINE); + + // Launching failed, trying to figure out possible cause + String envPath = getEnvVar(env, PATH_ENV); + if (!program.isAbsolute() && PathUtil.findProgramLocation(program.toString(), envPath) == null) { + printLine(consoleErr, errMsg); + msg = MakeMessages.getFormattedString("ExternalScannerInfoProvider.Working_Directory", workingDirectory); //$NON-NLS-1$ + msg = MakeMessages.getFormattedString("ExternalScannerInfoProvider.Program_Not_In_Path", program); //$NON-NLS-1$ + printLine(consoleErr, errorPrefix + msg + NEWLINE); + printLine(consoleErr, PATH_ENV + "=[" + envPath + "]" + NEWLINE); //$NON-NLS-1$ //$NON-NLS-2$ + } else { + printLine(consoleErr, errorPrefix + errMsg); + msg = MakeMessages.getFormattedString("ExternalScannerInfoProvider.Working_Directory", workingDirectory); //$NON-NLS-1$ + printLine(consoleErr, PATH_ENV + "=[" + envPath + "]" + NEWLINE); //$NON-NLS-1$ //$NON-NLS-2$ + } + return false; + } + + return true; + } + + /** + * TODO + */ + @Override + protected void setSettingEntries(List entries) { + // Builtin specs detectors collect entries not per line but for the whole output + if (entries!=null) + detectedSettingEntries.addAll(entries); + } + + private IConsole startProviderConsole() { + ILanguageDescriptor ld = LanguageManager.getInstance().getLanguageDescriptor(currentLanguageId); + + String consoleId = MakeCorePlugin.PLUGIN_ID + '.' + getId() + '.' + currentLanguageId; + String consoleName = getName() + ", " + ld.getName(); + URL defaultIcon = Platform.getBundle(PLUGIN_CDT_MAKE_UI_ID).getEntry("icons/obj16/inspect_system.gif"); + + IConsole console = CCorePlugin.getDefault().getConsole("org.eclipse.cdt.make.internal.ui.scannerconfig.ScannerDiscoveryConsole", consoleId, consoleName, defaultIcon); + return console; + } + + private String getEnvVar(String[] envStrings, String envVar) { + String envPath = null; + if (envStrings!=null) { + String varPrefix = envVar+'='; + for (String envStr : envStrings) { + if (envStr.startsWith(varPrefix)) { + envPath = envStr.substring(varPrefix.length()); + break; + } + } + } else { + envPath = System.getenv(envVar); + } + return envPath; + } + + private ITool getTool(String toolchainId, String languageId) { + IToolChain toolchain = ManagedBuildManager.getExtensionToolChain(toolchainId); + if (toolchain != null) { + ITool[] tools = toolchain.getTools(); + for (ITool tool : tools) { + IInputType[] inputTypes = tool.getInputTypes(); + for (IInputType inType : inputTypes) { + String lang = inType.getLanguageId(tool); + if (languageId.equals(lang)) + return tool; + } + } + } + ManagedBuilderCorePlugin.error("Unable to find tool in toolchain="+toolchainId+" for language="+languageId); + return null; + } + + private String getCompilerCommand(ITool tool) { + String compiler = tool.getToolCommand(); + if (compiler.length()==0) { + String msg = "Unable to find compiler command in toolchain="+getToolchainId(); + ManagedBuilderCorePlugin.error(msg); + } + return compiler; + } + + private String getSpecFile(String languageId, ITool tool) { + String ext = getSpecExt(languageId, tool); + + String specFileName = SPEC_FILE_BASE + ext; + IPath workingLocation = MakeCorePlugin.getWorkingDirectory(); + IPath fileLocation = workingLocation.append(specFileName); + + specFile = new java.io.File(fileLocation.toOSString()); + // will preserve spec file if it was already there otherwise will delete upon finishing + preserveSpecFile = specFile.exists(); + if (!preserveSpecFile) { + try { + specFile.createNewFile(); + } catch (IOException e) { + ManagedBuilderCorePlugin.log(e); + } + } + + return fileLocation.toString(); + } + + private String getSpecExt(String languageId, ITool tool) { + String ext = ""; + String[] srcFileExtensions = tool.getAllInputExtensions(); + if (srcFileExtensions!=null && srcFileExtensions.length>0) { + ext = srcFileExtensions[0]; + } + if (ext.length()==0) { + ManagedBuilderCorePlugin.error("Unable to find file extension for language "+languageId); + } + return ext; + } + + protected void printLine(OutputStream stream, String msg) throws IOException { + stream.write((msg + NEWLINE).getBytes()); + stream.flush(); + } + + @Override + public Element serialize(Element parentElement) { + Element elementProvider = super.serialize(parentElement); + elementProvider.setAttribute(ATTR_RUN_ONCE, Boolean.toString(runOnce)); + elementProvider.setAttribute(ATTR_CONSOLE, Boolean.toString(isConsoleEnabled)); + return elementProvider; + } + + @Override + public void load(Element providerNode) { + super.load(providerNode); + + String runOnceValue = XmlUtil.determineAttributeValue(providerNode, ATTR_RUN_ONCE); + if (runOnceValue!=null) + runOnce = Boolean.parseBoolean(runOnceValue); + + String consoleValue = XmlUtil.determineAttributeValue(providerNode, ATTR_CONSOLE); + if (consoleValue!=null) + isConsoleEnabled = Boolean.parseBoolean(consoleValue); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = super.hashCode(); + result = prime * result + (runOnce ? 1231 : 1237); + result = prime * result + (isConsoleEnabled ? 1231 : 1237); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (!super.equals(obj)) + return false; + if (!(obj instanceof AbstractBuiltinSpecsDetector)) + return false; + AbstractBuiltinSpecsDetector other = (AbstractBuiltinSpecsDetector) obj; + if (runOnce != other.runOnce) + return false; + if (isConsoleEnabled != other.isConsoleEnabled) + return false; + return true; + } +} diff --git a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/scannerconfig/GCCBuiltinSpecsDetector.java b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/scannerconfig/GCCBuiltinSpecsDetector.java new file mode 100644 index 00000000000..d5fee24780e --- /dev/null +++ b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/scannerconfig/GCCBuiltinSpecsDetector.java @@ -0,0 +1,135 @@ +/******************************************************************************* + * Copyright (c) 2009, 2011 Andrew Gvozdev 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: + * Andrew Gvozdev - initial API and implementation + *******************************************************************************/ + +package org.eclipse.cdt.managedbuilder.internal.scannerconfig; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.cdt.core.settings.model.ICConfigurationDescription; +import org.eclipse.cdt.core.settings.model.ICSettingEntry; +import org.eclipse.cdt.core.settings.model.ILanguageSettingsEditableProvider; +import org.eclipse.core.runtime.CoreException; + +/** + * Class to detect built-in compiler settings. Note that currently this class is hardwired + * to GCC toolchain {@code cdt.managedbuild.toolchain.gnu.base}. + * + */ +public class GCCBuiltinSpecsDetector extends AbstractBuiltinSpecsDetector implements ILanguageSettingsEditableProvider { + // must match the toolchain definition in org.eclipse.cdt.managedbuilder.core.buildDefinitions extension point + private static final String GCC_TOOLCHAIN_ID = "cdt.managedbuild.toolchain.gnu.base"; //$NON-NLS-1$ + + private enum State {NONE, EXPECTING_LOCAL_INCLUDE, EXPECTING_SYSTEM_INCLUDE, EXPECTING_FRAMEWORKS} + State state = State.NONE; + + @SuppressWarnings("nls") + static final AbstractOptionParser[] optionParsers = { + new IncludePathOptionParser("#include \"(\\S.*)\"", "$1", ICSettingEntry.BUILTIN | ICSettingEntry.READONLY | ICSettingEntry.LOCAL), + new IncludePathOptionParser("#include <(\\S.*)>", "$1", ICSettingEntry.BUILTIN | ICSettingEntry.READONLY), + new IncludePathOptionParser("#framework <(\\S.*)>", "$1", ICSettingEntry.BUILTIN | ICSettingEntry.READONLY | ICSettingEntry.FRAMEWORKS_MAC), + new MacroOptionParser("#define (\\S*\\(.*?\\)) *(.*)", "$1", "$2", ICSettingEntry.BUILTIN | ICSettingEntry.READONLY), + new MacroOptionParser("#define (\\S*) *(.*)", "$1", "$2", ICSettingEntry.BUILTIN | ICSettingEntry.READONLY), + }; + + @Override + protected String getToolchainId() { + return GCC_TOOLCHAIN_ID; + } + + @Override + protected AbstractOptionParser[] getOptionParsers() { + return optionParsers; + } + + private List makeList(final String line) { + return new ArrayList() {{ add(line); }}; + } + + @Override + protected List parseForOptions(String line) { + line = line.trim(); + + // contribution of -dD option + if (line.startsWith("#define")) { + return makeList(line); + } + + /** + +Framework search starts here: + /System/Library/Frameworks + /Library/Frameworks +End of framework search list. + + */ + + // contribution of includes + if (line.equals("#include \"...\" search starts here:")) { + state = State.EXPECTING_LOCAL_INCLUDE; + } else if (line.equals("#include <...> search starts here:")) { + state = State.EXPECTING_SYSTEM_INCLUDE; + } else if (line.startsWith("End of search list.")) { + state = State.NONE; + } else if (line.equals("Framework search starts here:")) { + state = State.EXPECTING_FRAMEWORKS; + } else if (line.startsWith("End of framework search list.")) { + state = State.NONE; + } else if (state==State.EXPECTING_LOCAL_INCLUDE) { + // making that up for the parser to figure out + line = "#include \""+line+"\""; + return makeList(line); + } else { + String frameworkIndicator = "(framework directory)"; + if (state==State.EXPECTING_SYSTEM_INCLUDE) { + // making that up for the parser to figure out + if (line.contains(frameworkIndicator)) { + line = "#framework <"+line.replace(frameworkIndicator, "").trim()+">"; + } else { + line = "#include <"+line+">"; + } + return makeList(line); + } else if (state==State.EXPECTING_FRAMEWORKS) { + // making that up for the parser to figure out + line = "#framework <"+line.replace(frameworkIndicator, "").trim()+">"; + return makeList(line); + } + } + + return null; + } + + @Override + public void startup(ICConfigurationDescription cfgDescription) throws CoreException { + super.startup(cfgDescription); + + state = State.NONE; + } + + @Override + public void shutdown() { + state = State.NONE; + + super.shutdown(); + } + + @Override + public GCCBuiltinSpecsDetector cloneShallow() throws CloneNotSupportedException { + return (GCCBuiltinSpecsDetector) super.cloneShallow(); + } + + @Override + public GCCBuiltinSpecsDetector clone() throws CloneNotSupportedException { + return (GCCBuiltinSpecsDetector) super.clone(); + } + + +} diff --git a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/scannerconfig/MBSLanguageSettingsProvider.java b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/scannerconfig/MBSLanguageSettingsProvider.java new file mode 100644 index 00000000000..ebddb38e568 --- /dev/null +++ b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/scannerconfig/MBSLanguageSettingsProvider.java @@ -0,0 +1,113 @@ +/******************************************************************************* + * Copyright (c) 2009, 2009 Andrew Gvozdev (Quoin Inc.) 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: + * Andrew Gvozdev (Quoin Inc.) - initial API and implementation + *******************************************************************************/ + +package org.eclipse.cdt.managedbuilder.internal.scannerconfig; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.cdt.core.AbstractExecutableExtensionBase; +import org.eclipse.cdt.core.language.settings.providers.ILanguageSettingsProvider; +import org.eclipse.cdt.core.settings.model.ICConfigurationDescription; +import org.eclipse.cdt.core.settings.model.ICFileDescription; +import org.eclipse.cdt.core.settings.model.ICFolderDescription; +import org.eclipse.cdt.core.settings.model.ICLanguageSetting; +import org.eclipse.cdt.core.settings.model.ICLanguageSettingEntry; +import org.eclipse.cdt.core.settings.model.ICResourceDescription; +import org.eclipse.cdt.core.settings.model.ICSettingBase; +import org.eclipse.cdt.core.settings.model.ILanguageSettingsEditableProvider; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.runtime.IPath; + +//public class MBSLanguageSettingsProvider extends AbstractExecutableExtensionBase implements ILanguageSettingsEditableProvider { +public class MBSLanguageSettingsProvider extends AbstractExecutableExtensionBase implements ILanguageSettingsProvider { + + public List getSettingEntries(ICConfigurationDescription cfgDescription, IResource rc, String languageId) { + + IPath projectPath = rc.getProjectRelativePath(); + ICResourceDescription rcDescription = cfgDescription.getResourceDescription(projectPath, false); + + List list = new ArrayList(); + for (ICLanguageSetting languageSetting : getLanguageSettings(rcDescription)) { + if (languageSetting!=null) { + String id = languageSetting.getLanguageId(); + if (id!=null && id.equals(languageId)) { + int kindsBits = languageSetting.getSupportedEntryKinds(); + for (int kind=1;kind<=kindsBits;kind<<=1) { + if ((kindsBits & kind) != 0) { + list.addAll(languageSetting.getSettingEntriesList(kind)); + } + } + } else { +// System.err.println("languageSetting id=null: name=" + languageSetting.getName()); + } + } else { + System.err.println("languageSetting=null: rcDescription=" + rcDescription.getName()); + } + } + return list; + } + + private ICLanguageSetting[] getLanguageSettings(ICResourceDescription rcDescription) { + ICLanguageSetting[] array = null; + switch (rcDescription.getType()) { + case ICSettingBase.SETTING_PROJECT: + case ICSettingBase.SETTING_CONFIGURATION: + case ICSettingBase.SETTING_FOLDER: + ICFolderDescription foDes = (ICFolderDescription)rcDescription; + array = foDes.getLanguageSettings(); + break; + case ICSettingBase.SETTING_FILE: + ICFileDescription fiDes = (ICFileDescription)rcDescription; + ICLanguageSetting ls = fiDes.getLanguageSetting(); + if (ls!=null) { + array = new ICLanguageSetting[] { ls }; + } + } + if (array==null) { + array = new ICLanguageSetting[0]; + } + return array; + } + + public void setSettingEntries(ICConfigurationDescription cfgDescription, IResource rc, String languageId, + List entries) { + +// lang.setSettingEntries(kind, entries); + IPath projectPath = rc.getProjectRelativePath(); + ICResourceDescription rcDescription = cfgDescription.getResourceDescription(projectPath, false); + + for (ICLanguageSetting languageSetting : getLanguageSettings(rcDescription)) { + if (languageSetting!=null) { + String id = languageSetting.getLanguageId(); + if (id!=null && id.equals(languageId)) { + int kindsBits = languageSetting.getSupportedEntryKinds(); + for (int kind=1;kind<=kindsBits;kind<<=1) { + if ((kindsBits & kind) != 0) { + List list = new ArrayList(entries.size()); + for (ICLanguageSettingEntry entry : entries) { + if (entry.getKind()==kind) { + list.add(entry); + } + } + languageSetting.setSettingEntries(kind, list); + } + } + } else { +// System.err.println("languageSetting id=null: name=" + languageSetting.getName()); + } + } else { + System.err.println("languageSetting=null: rcDescription=" + rcDescription.getName()); + } + } + } + +} diff --git a/build/org.eclipse.cdt.managedbuilder.gnu.ui/plugin.xml b/build/org.eclipse.cdt.managedbuilder.gnu.ui/plugin.xml index f26ee076aae..77ada67aea3 100644 --- a/build/org.eclipse.cdt.managedbuilder.gnu.ui/plugin.xml +++ b/build/org.eclipse.cdt.managedbuilder.gnu.ui/plugin.xml @@ -1665,10 +1665,11 @@ + osList="linux,hpux,aix,qnx" + targetTool="cdt.managedbuild.tool.gnu.c.linker;cdt.managedbuild.tool.gnu.cpp.linker;cdt.managedbuild.tool.gnu.archiver"> @@ -1802,6 +1804,7 @@ configurationEnvironmentSupplier="org.eclipse.cdt.managedbuilder.gnu.mingw.MingwEnvironmentVariableSupplier" id="cdt.managedbuild.toolchain.gnu.mingw.base" isToolChainSupported="org.eclipse.cdt.managedbuilder.gnu.mingw.MingwIsToolChainSupported" + languageSettingsProviders="org.eclipse.cdt.make.core.build.command.parser.gcc;*org.eclipse.cdt.managedbuilder.core.gcc.specs.detector" name="%ToolChainName.MinGW" osList="win32" targetTool="cdt.managedbuild.tool.gnu.cpp.linker.mingw.base;cdt.managedbuild.tool.gnu.c.linker.mingw.base;cdt.managedbuild.tool.gnu.archiver"> @@ -2043,9 +2046,9 @@ + id="cdt.managedbuild.config.gnu.base" + languageSettingsProviders="org.eclipse.cdt.ui.user.LanguageSettingsProvider;org.eclipse.cdt.managedbuilder.core.LanguageSettingsProvider;${Toolchain};-org.eclipse.cdt.make.core.build.command.parser.gcc"> + cleanCommand="rm -rf" + id="cdt.managedbuild.config.gnu.cygwin.base" + languageSettingsProviders="org.eclipse.cdt.ui.user.LanguageSettingsProvider;org.eclipse.cdt.managedbuilder.core.LanguageSettingsProvider;${Toolchain};-org.eclipse.cdt.make.core.build.command.parser.gcc"> + cleanCommand="rm -rf" + id="cdt.managedbuild.config.gnu.mingw.base" + languageSettingsProviders="org.eclipse.cdt.ui.user.LanguageSettingsProvider;org.eclipse.cdt.managedbuilder.core.LanguageSettingsProvider;${Toolchain};-org.eclipse.cdt.make.core.build.command.parser.gcc"> 6OU;p2od-v(ryHCI0eg5_C^Y2eze}DS+``eE{|Nqbb z|Nr>^-yi;y3lx8{FfuUMGw3h?0mx4bY%>qcFYwTj>UV1w@+?_1@3g#9gNBhqgn+X| z04rDPLM7*Y3S1LzU07IPl0A11n=G3mo1k#K#M)^p%BpP4Dr)Q^Y!V_2{Pr@7HPkiO`uQ0o gjx#thaci<^7Tce=e9B3th+W3%^0B=>ZjKDr0Hf`~-v9sr literal 0 HcmV?d00001 diff --git a/build/org.eclipse.cdt.managedbuilder.ui/icons/obj16/search.gif b/build/org.eclipse.cdt.managedbuilder.ui/icons/obj16/search.gif new file mode 100644 index 0000000000000000000000000000000000000000..d540a01f4d9eeb9d2951f30cee165c7370e9fc6a GIT binary patch literal 347 zcmZ?wbhEHb6krfwxXQq=Vd*RNf? z`oQk}`*!YKK6~ljZF_cZ+HvgAv6IJ69zSyY;J$;WPMkV&@Th0*!vFtI{{R2)-9{Q{xYzi!ojzd!Hm)rnuOPWpOf;{Cn#PZn9eTp#{=Q|#Kl_?H9)`m^Y_v_E|osjQ0xhPeU?V7 zFYefq7px@erW32aOhZI~o1e+F);Uj8NSKj>%P7ZHO;TK&kDY#h literal 0 HcmV?d00001 diff --git a/build/org.eclipse.cdt.managedbuilder.ui/plugin.properties b/build/org.eclipse.cdt.managedbuilder.ui/plugin.properties index f511362e8b3..fce07128cfd 100644 --- a/build/org.eclipse.cdt.managedbuilder.ui/plugin.properties +++ b/build/org.eclipse.cdt.managedbuilder.ui/plugin.properties @@ -92,6 +92,7 @@ Source.location=Source Location Output.location=Output Location Binary.parsers=Binary Parsers Error.parsers=Error Parsers +Language.settings.providers=Discovery Data.hierarchy=Data Hierarchy Preferred.toolchains=Preferred Toolchains Wizard.defaults=Wizard Defaults diff --git a/build/org.eclipse.cdt.managedbuilder.ui/plugin.xml b/build/org.eclipse.cdt.managedbuilder.ui/plugin.xml index 94449d3aaf7..6db04757aef 100644 --- a/build/org.eclipse.cdt.managedbuilder.ui/plugin.xml +++ b/build/org.eclipse.cdt.managedbuilder.ui/plugin.xml @@ -648,5 +648,16 @@ + + + + + + diff --git a/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/internal/ui/Messages.java b/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/internal/ui/Messages.java index 7d4180d427f..e445ffb8dc3 100644 --- a/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/internal/ui/Messages.java +++ b/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/internal/ui/Messages.java @@ -210,6 +210,8 @@ public class Messages extends NLS { public static String PropertyPageDefsTab_8; public static String PropertyPageDefsTab_9; public static String PropertyPageDefsTab_showIncludeFileTab; + public static String PropertyPageDefsTab_showProvidersTab; + public static String RefreshPolicyExceptionDialog_addButtonLabel; public static String RefreshPolicyExceptionDialog_addDialogLabel; public static String RefreshPolicyExceptionDialog_AddExceptionInfoDialog_message; public static String RefreshPolicyExceptionDialog_AddExceptionInfoDialog_title; diff --git a/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/internal/ui/Messages.properties b/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/internal/ui/Messages.properties index 9b176b659e6..5185ed82802 100644 --- a/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/internal/ui/Messages.properties +++ b/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/internal/ui/Messages.properties @@ -272,6 +272,7 @@ PropertyPageDefsTab_7=Show disc. page names if they are unique. Else show profil PropertyPageDefsTab_8=Always show names + profile IDs PropertyPageDefsTab_9=Always show profile IDs only PropertyPageDefsTab_showIncludeFileTab=Display "Include Files" tab +PropertyPageDefsTab_showProvidersTab=Display new experimental Scanner Discovery Providers tabs ProjectConvert_convertersList=Converters List AbstractPrefPage_0=\ Preference settings will be applied to new projects \n only when there were no toolchains selected. diff --git a/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/ui/preferences/BuiltinSpecsDetectorOptionPage.java b/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/ui/preferences/BuiltinSpecsDetectorOptionPage.java new file mode 100644 index 00000000000..12885afab20 --- /dev/null +++ b/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/ui/preferences/BuiltinSpecsDetectorOptionPage.java @@ -0,0 +1,325 @@ +/******************************************************************************* + * Copyright (c) 2009, 2010 Andrew Gvozdev 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: + * Andrew Gvozdev - Initial API and implementation + *******************************************************************************/ + +package org.eclipse.cdt.managedbuilder.ui.preferences; + +import org.eclipse.cdt.core.language.settings.providers.ILanguageSettingsProvider; +import org.eclipse.cdt.core.language.settings.providers.LanguageSettingsManager; +import org.eclipse.cdt.internal.ui.language.settings.providers.AbstractLanguageSettingProviderOptionPage; +import org.eclipse.cdt.internal.ui.newui.StatusMessageLine; +import org.eclipse.cdt.managedbuilder.internal.scannerconfig.AbstractBuiltinSpecsDetector; +import org.eclipse.cdt.utils.ui.controls.ControlFactory; +import org.eclipse.core.runtime.Assert; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.jface.dialogs.Dialog; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.ModifyEvent; +import org.eclipse.swt.events.ModifyListener; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +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; + +/** + * Options page for TODO + * + */ +public final class BuiltinSpecsDetectorOptionPage extends AbstractLanguageSettingProviderOptionPage { + private boolean fEditable; + + private Text inputCommand; + + private StatusMessageLine fStatusLine; + private Button runOnceRadioButton; + private Button runEveryBuildRadioButton; + private Button allocateConsoleCheckBox; + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.dialogs.IDialogPage#createControl(org.eclipse.swt.widgets.Composite) + */ + @Override + public void createControl(Composite parent) { +// Composite optionsPageComposite = new Composite(composite, SWT.NULL); + fEditable = parent.isEnabled(); + + final Composite composite = new Composite(parent, SWT.NONE); + { + GridLayout layout = new GridLayout(); + layout.numColumns = 2; + layout.marginWidth = 1; + layout.marginHeight = 1; + layout.marginRight = 1; + composite.setLayout(layout); + composite.setLayoutData(new GridData(GridData.FILL_BOTH)); + Dialog.applyDialogFont(composite); + + GridData gd = new GridData(GridData.FILL_HORIZONTAL); + gd.horizontalSpan = 2; + composite.setLayoutData(gd); + } + + + Group groupRun = new Group(composite, SWT.SHADOW_ETCHED_IN); +// groupRun.setText("Language Settings Provider Options"); + + GridLayout gridLayoutRun = new GridLayout(); +// GridLayout gridLayoutRun = new GridLayout(2, true); +// gridLayoutRun.makeColumnsEqualWidth = false; +// gridLayoutRun.marginRight = -10; +// gridLayoutRun.marginLeft = -4; + groupRun.setLayout(gridLayoutRun); +// GridData gdRun = new GridData(GridData.FILL_HORIZONTAL); +// gdRun.horizontalSpan = 2; +// groupRun.setLayoutData(gdRun); + + AbstractBuiltinSpecsDetector provider = getRawProvider(); + { + runOnceRadioButton = new Button(groupRun, SWT.RADIO); + runOnceRadioButton.setText("Run only once"); //$NON-NLS-1$ + // b1.setToolTipText(UIMessages.getString("EnvironmentTab.3")); //$NON-NLS-1$ + GridData gd = new GridData(GridData.FILL_HORIZONTAL); + gd.horizontalSpan = 3; + runOnceRadioButton.setLayoutData(gd); + runOnceRadioButton.setSelection(provider.isRunOnce()); + runOnceRadioButton.setEnabled(fEditable); + runOnceRadioButton.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent evt) { + boolean runOnceEnabled = runOnceRadioButton.getSelection(); + if (runOnceEnabled) { + AbstractBuiltinSpecsDetector provider = getRawProvider(); + if (runOnceEnabled != provider.isRunOnce()) { + AbstractBuiltinSpecsDetector selectedProvider = getWorkingCopy(providerId); + selectedProvider.setRunOnce(runOnceEnabled); + providerTab.refreshItem(selectedProvider); + } + } + } + + }); + } + { + runEveryBuildRadioButton = new Button(groupRun, SWT.RADIO); + runEveryBuildRadioButton.setText("Activate on every build"); //$NON-NLS-1$ + runEveryBuildRadioButton.setSelection(!provider.isRunOnce()); + runEveryBuildRadioButton.setEnabled(fEditable); + GridData gd = new GridData(GridData.FILL_HORIZONTAL); + gd.horizontalSpan = 3; + runEveryBuildRadioButton.setLayoutData(gd); + runEveryBuildRadioButton.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent evt) { + boolean runEveryBuildEnabled = runEveryBuildRadioButton.getSelection(); + if (runEveryBuildEnabled) { + AbstractBuiltinSpecsDetector provider = getRawProvider(); + if (runEveryBuildEnabled != !provider.isRunOnce()) { + AbstractBuiltinSpecsDetector selectedProvider = getWorkingCopy(providerId); + selectedProvider.setRunOnce(!runEveryBuildEnabled); + providerTab.refreshItem(selectedProvider); + } + } + } + }); + } + + // Compiler specs command + { + Label label = ControlFactory.createLabel(composite, "Command to get compiler specs:"); + GridData gd = new GridData(); + gd.horizontalSpan = 2; + label.setLayoutData(gd); + label.setEnabled(fEditable); + } + + { + inputCommand = ControlFactory.createTextField(composite, SWT.SINGLE | SWT.BORDER); + String customParameter = provider.getCustomParameter(); + inputCommand.setText(customParameter!=null ? customParameter : ""); + inputCommand.setEnabled(fEditable); + inputCommand.addModifyListener(new ModifyListener() { + public void modifyText(ModifyEvent e) { + String text = inputCommand.getText(); + AbstractBuiltinSpecsDetector provider = getRawProvider(); + if (!text.equals(provider.getCustomParameter())) { + AbstractBuiltinSpecsDetector selectedProvider = getWorkingCopy(providerId); + selectedProvider.setCustomParameter(text); + providerTab.refreshItem(selectedProvider); + } + } + }); + } + + { + Button button = ControlFactory.createPushButton(composite, "Browse..."); + button.setEnabled(fEditable); + button.addSelectionListener(new SelectionAdapter() { + + @Override + public void widgetSelected(SelectionEvent evt) { +// handleAddr2LineButtonSelected(); + //updateLaunchConfigurationDialog(); + } + + }); + + } + +// { +// final Button button = new Button(composite, SWT.PUSH); +// button.setFont(parent.getFont()); +// String text = fProvider.isEmpty() ? "Run Now (TODO)" : "Clear"; +// button.setText(text); +//// button.addSelectionListener(this); +// GridData data = new GridData(); +// data.horizontalSpan = 2; +//// data.horizontalAlignment = GridData.BEGINNING; +//// data.widthHint = 60; +// button.setLayoutData(data); +// // TODO +// button.setEnabled(fEditable && !fProvider.isEmpty()); +// +// button.addSelectionListener(new SelectionAdapter() { +// +// @Override +// public void widgetSelected(SelectionEvent evt) { +// if (fProvider.isEmpty()) { +// // TODO +// } else { +// fProvider.clear(); +// } +// // TODO +// button.setEnabled(fEditable && !fProvider.isEmpty()); +// String text = fProvider.isEmpty() ? "Run Now (TODO)" : "Clear"; +// button.setText(text); +// button.pack(); +// } +// +// }); +// +// } + +// // Compiler specs command +// { +// Label label = ControlFactory.createLabel(composite, "Parsing rules:"); +// GridData gd = new GridData(); +// gd.horizontalSpan = 2; +// label.setLayoutData(gd); +//// Label newLabel = new Label(composite, SWT.NONE); +////// ((GridData) newLabel.getLayoutData()).horizontalSpan = 1; +//// newLabel.setText("Command to get compiler specs:"); +// } + + +// createPatternsTable(group, composite); + + + + + + + + +// Group group = new Group(parent, SWT.SHADOW_ETCHED_IN); +// group.setText(DialogsMessages.RegexErrorParserOptionPage_Title); +// +// GridLayout gridLayout = new GridLayout(2, true); +// gridLayout.makeColumnsEqualWidth = false; +// gridLayout.marginRight = -10; +// gridLayout.marginLeft = -4; +// group.setLayout(gridLayout); +// group.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); +// +// Composite composite = new Composite(group, SWT.NONE); +// GridLayout layout = new GridLayout(); +// layout.numColumns = 2; +// layout.marginWidth = 1; +// layout.marginHeight = 1; +// layout.marginRight = 1; +// composite.setLayout(layout); +// composite.setLayoutData(new GridData(GridData.FILL_BOTH)); +// Dialog.applyDialogFont(composite); +// +// if (!fEditable) +// createLinkToPreferences(composite); +// +// createPatternsTable(group, composite); +// +// if (fEditable) { +// createButtons(composite); +// } + + { + allocateConsoleCheckBox = new Button(composite, SWT.CHECK); + allocateConsoleCheckBox.setText("Allocate console in the Console View"); + allocateConsoleCheckBox.setSelection(provider.isConsoleEnabled()); + allocateConsoleCheckBox.setEnabled(fEditable); + allocateConsoleCheckBox.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + boolean enabled = allocateConsoleCheckBox.getSelection(); + AbstractBuiltinSpecsDetector provider = getRawProvider(); + if (enabled != provider.isConsoleEnabled()) { + AbstractBuiltinSpecsDetector selectedProvider = getWorkingCopy(providerId); + selectedProvider.setConsoleEnabled(enabled); + providerTab.refreshItem(selectedProvider); + } + } + + @Override + public void widgetDefaultSelected(SelectionEvent e) { + widgetSelected(e); + } + + }); + + } + +// // Status line +// if (fEditable) { +// fStatusLine = new StatusMessageLine(composite, SWT.LEFT, 2); +// IStatus status = new Status(IStatus.WARNING, CUIPlugin.PLUGIN_ID, "Note that currently not all options are persisted (FIXME)"); +// fStatusLine.setErrorStatus(status); +// } + + setControl(composite); + } + + private AbstractBuiltinSpecsDetector getRawProvider() { + ILanguageSettingsProvider provider = LanguageSettingsManager.getRawProvider(providerTab.getProvider(providerId)); + Assert.isTrue(provider instanceof AbstractBuiltinSpecsDetector); + return (AbstractBuiltinSpecsDetector) provider; + } + + private AbstractBuiltinSpecsDetector getWorkingCopy(String providerId) { + ILanguageSettingsProvider provider = providerTab.getWorkingCopy(providerId); + Assert.isTrue(provider instanceof AbstractBuiltinSpecsDetector); + return (AbstractBuiltinSpecsDetector) provider; + } + + @Override + public void performApply(IProgressMonitor monitor) throws CoreException { + // handled by LanguageSettingsProviderTab + } + + @Override + public void performDefaults() { + // handled by LanguageSettingsProviderTab + } + +} diff --git a/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/ui/preferences/PropertyPageDefsTab.java b/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/ui/preferences/PropertyPageDefsTab.java index 458f7e517a1..245dde59395 100644 --- a/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/ui/preferences/PropertyPageDefsTab.java +++ b/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/ui/preferences/PropertyPageDefsTab.java @@ -12,9 +12,9 @@ package org.eclipse.cdt.managedbuilder.ui.preferences; import org.eclipse.cdt.core.settings.model.ICResourceDescription; +import org.eclipse.cdt.managedbuilder.internal.ui.Messages; import org.eclipse.cdt.ui.newui.AbstractCPropertyTab; import org.eclipse.cdt.ui.newui.CDTPrefUtil; -import org.eclipse.cdt.managedbuilder.internal.ui.Messages; import org.eclipse.swt.SWT; import org.eclipse.swt.layout.FillLayout; import org.eclipse.swt.layout.GridData; @@ -38,6 +38,7 @@ public class PropertyPageDefsTab extends AbstractCPropertyTab { private Button show_mng; private Button show_tool; private Button show_exp; + private Button show_providers_tab; // temporary checkbox for scanner discovery Providers tab private Button show_tipbox; private Button b_0; @@ -74,6 +75,11 @@ public class PropertyPageDefsTab extends AbstractCPropertyTab { show_exp.setText(Messages.PropertyPageDefsTab_10); show_exp.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + show_providers_tab = new Button(usercomp, SWT.CHECK); + show_providers_tab.setText(Messages.PropertyPageDefsTab_showProvidersTab + ", " //$NON-NLS-1$ + + org.eclipse.cdt.internal.ui.newui.Messages.CDTMainWizardPage_TrySD90); + show_providers_tab.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + show_tipbox = new Button(usercomp, SWT.CHECK); show_tipbox.setText(Messages.PropertyPageDefsTab_16); show_tipbox.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); @@ -117,6 +123,7 @@ public class PropertyPageDefsTab extends AbstractCPropertyTab { show_mng.setSelection(!CDTPrefUtil.getBool(CDTPrefUtil.KEY_NOMNG)); show_tool.setSelection(!CDTPrefUtil.getBool(CDTPrefUtil.KEY_NOTOOLM)); show_exp.setSelection(CDTPrefUtil.getBool(CDTPrefUtil.KEY_EXPORT)); + show_providers_tab.setSelection(!CDTPrefUtil.getBool(CDTPrefUtil.KEY_NO_SHOW_PROVIDERS)); show_tipbox.setSelection(CDTPrefUtil.getBool(CDTPrefUtil.KEY_TIPBOX)); switch (CDTPrefUtil.getInt(CDTPrefUtil.KEY_DISC_NAMES)) { @@ -140,6 +147,7 @@ public class PropertyPageDefsTab extends AbstractCPropertyTab { CDTPrefUtil.setBool(CDTPrefUtil.KEY_NOMNG, !show_mng.getSelection()); CDTPrefUtil.setBool(CDTPrefUtil.KEY_NOTOOLM, !show_tool.getSelection()); CDTPrefUtil.setBool(CDTPrefUtil.KEY_EXPORT, show_exp.getSelection()); + CDTPrefUtil.setBool(CDTPrefUtil.KEY_NO_SHOW_PROVIDERS, !show_providers_tab.getSelection()); CDTPrefUtil.setBool(CDTPrefUtil.KEY_TIPBOX, show_tipbox.getSelection()); int x = 0; if (b_1.getSelection()) x = 1; @@ -160,6 +168,7 @@ public class PropertyPageDefsTab extends AbstractCPropertyTab { show_mng.setSelection(true); show_tool.setSelection(true); show_exp.setSelection(false); + show_providers_tab.setSelection(false); show_tipbox.setSelection(false); b_0.setSelection(true); b_1.setSelection(false); diff --git a/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/ui/preferences/WizardDefaultsTab.java b/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/ui/preferences/WizardDefaultsTab.java index 636382cc660..03b4f0a8f1f 100644 --- a/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/ui/preferences/WizardDefaultsTab.java +++ b/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/ui/preferences/WizardDefaultsTab.java @@ -30,6 +30,7 @@ public class WizardDefaultsTab extends AbstractCPropertyTab { private Button show_sup; private Button show_oth; + private Button checkBoxTryNewSD; @Override public void createControls(Composite parent) { @@ -44,20 +45,27 @@ public class WizardDefaultsTab extends AbstractCPropertyTab { show_oth.setText(Messages.WizardDefaultsTab_1); show_oth.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + checkBoxTryNewSD = new Button(usercomp, SWT.CHECK); + checkBoxTryNewSD.setText(org.eclipse.cdt.internal.ui.newui.Messages.CDTMainWizardPage_TrySD90); + checkBoxTryNewSD.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + show_sup.setSelection(!CDTPrefUtil.getBool(CDTPrefUtil.KEY_NOSUPP)); show_oth.setSelection(CDTPrefUtil.getBool(CDTPrefUtil.KEY_OTHERS)); + checkBoxTryNewSD.setSelection(CDTPrefUtil.getBool(CDTPrefUtil.KEY_NEWSD)); } @Override protected void performOK() { CDTPrefUtil.setBool(CDTPrefUtil.KEY_NOSUPP, !show_sup.getSelection()); CDTPrefUtil.setBool(CDTPrefUtil.KEY_OTHERS, show_oth.getSelection()); + CDTPrefUtil.setBool(CDTPrefUtil.KEY_NEWSD, checkBoxTryNewSD.getSelection()); } @Override protected void performDefaults() { show_sup.setSelection(true); show_oth.setSelection(false); + checkBoxTryNewSD.setSelection(true); } @Override diff --git a/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/ui/wizards/MBSWizardHandler.java b/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/ui/wizards/MBSWizardHandler.java index 14fa0ce258b..ef874834d15 100644 --- a/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/ui/wizards/MBSWizardHandler.java +++ b/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/ui/wizards/MBSWizardHandler.java @@ -23,6 +23,9 @@ import java.util.SortedMap; import java.util.TreeMap; import java.util.TreeSet; +import org.eclipse.cdt.build.internal.core.scannerconfig2.CfgScannerConfigProfileManager; +import org.eclipse.cdt.core.language.settings.providers.ILanguageSettingsProvider; +import org.eclipse.cdt.core.language.settings.providers.LanguageSettingsManager; import org.eclipse.cdt.core.model.CoreModel; import org.eclipse.cdt.core.settings.model.ICConfigurationDescription; import org.eclipse.cdt.core.settings.model.ICProjectDescription; @@ -41,8 +44,8 @@ import org.eclipse.cdt.managedbuilder.core.ManagedBuildManager; import org.eclipse.cdt.managedbuilder.internal.core.Configuration; import org.eclipse.cdt.managedbuilder.internal.core.ManagedBuildInfo; import org.eclipse.cdt.managedbuilder.internal.core.ManagedProject; -import org.eclipse.cdt.managedbuilder.ui.properties.ManagedBuilderUIPlugin; import org.eclipse.cdt.managedbuilder.internal.ui.Messages; +import org.eclipse.cdt.managedbuilder.ui.properties.ManagedBuilderUIPlugin; import org.eclipse.cdt.ui.newui.CDTPrefUtil; import org.eclipse.cdt.ui.templateengine.IWizardDataPage; import org.eclipse.cdt.ui.templateengine.Template; @@ -549,6 +552,13 @@ public class MBSWizardHandler extends CWizardHandler { } private void setProjectDescription(IProject project, boolean defaults, boolean onFinish, IProgressMonitor monitor) throws CoreException { + boolean isTryingNewSD = false; + IWizardPage page = getStartingPage(); + if (page instanceof CDTMainWizardPage) { + CDTMainWizardPage mainWizardPage = (CDTMainWizardPage)page; + isTryingNewSD = mainWizardPage.isTryingNewSD(); + } + ICProjectDescriptionManager mngr = CoreModel.getDefault().getProjectDescriptionManager(); ICProjectDescription des = mngr.createProjectDescription(project, false, !onFinish); ManagedBuildInfo info = ManagedBuildManager.createBuildInfo(project); @@ -594,9 +604,32 @@ public class MBSWizardHandler extends CWizardHandler { cfgDebug = cfgDes; if (cfgFirst == null) // select at least first configuration cfgFirst = cfgDes; + + if (isTryingNewSD) { + CfgScannerConfigProfileManager.disableScannerDiscovery(config); + + List providers = ManagedBuildManager.getLanguageSettingsProviders(config); + cfgDes.setLanguageSettingProviders(providers); + } else { + ILanguageSettingsProvider provider = LanguageSettingsManager.getWorkspaceProvider(ManagedBuildManager.MBS_LANGUAGE_SETTINGS_PROVIDER); + List providers = new ArrayList(); + providers.add(provider); + cfgDes.setLanguageSettingProviders(providers); + } + monitor.worked(work); } mngr.setProjectDescription(project, des); + + // FIXME if scanner discovery is empty it is "fixed" deeply inside setProjectDescription(), taking the easy road here for the moment + if (isTryingNewSD) { + des = mngr.getProjectDescription(project); + boolean isChanged = CfgScannerConfigProfileManager.disableScannerDiscovery(des); + + if (isChanged) { + mngr.setProjectDescription(project, des); + } + } } @Override diff --git a/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/ui/wizards/NewMakeProjFromExisting.java b/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/ui/wizards/NewMakeProjFromExisting.java index 3e5767ffabb..666a8dce04f 100644 --- a/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/ui/wizards/NewMakeProjFromExisting.java +++ b/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/ui/wizards/NewMakeProjFromExisting.java @@ -11,10 +11,16 @@ package org.eclipse.cdt.managedbuilder.ui.wizards; import java.lang.reflect.InvocationTargetException; +import java.util.ArrayList; +import java.util.List; +import org.eclipse.cdt.build.internal.core.scannerconfig2.CfgScannerConfigProfileManager; import org.eclipse.cdt.core.CCProjectNature; import org.eclipse.cdt.core.CCorePlugin; +import org.eclipse.cdt.core.language.settings.providers.ILanguageSettingsProvider; +import org.eclipse.cdt.core.language.settings.providers.LanguageSettingsManager; import org.eclipse.cdt.core.model.CoreModel; +import org.eclipse.cdt.core.settings.model.ICConfigurationDescription; import org.eclipse.cdt.core.settings.model.ICProjectDescription; import org.eclipse.cdt.core.settings.model.ICProjectDescriptionManager; import org.eclipse.cdt.core.settings.model.extension.CConfigurationData; @@ -68,6 +74,7 @@ public class NewMakeProjFromExisting extends Wizard implements IImportWizard, IN final String locationStr = page.getLocation(); final boolean isCPP = page.isCPP(); final IToolChain toolChain = page.getToolChain(); + final boolean isTryingNewSD = page.isTryingNewSD(); IRunnableWithProgress op = new WorkspaceModifyOperation() { @Override @@ -109,13 +116,39 @@ public class NewMakeProjFromExisting extends Wizard implements IImportWizard, IN IBuilder builder = config.getEditableBuilder(); builder.setManagedBuildOn(false); CConfigurationData data = config.getConfigurationData(); - projDesc.createConfiguration(ManagedBuildManager.CFG_DATA_PROVIDER_ID, data); + ICConfigurationDescription cfgDes = projDesc.createConfiguration(ManagedBuildManager.CFG_DATA_PROVIDER_ID, data); + + if (isTryingNewSD) { + CfgScannerConfigProfileManager.disableScannerDiscovery(config); + + List providers = ManagedBuildManager.getLanguageSettingsProviders(config); + cfgDes.setLanguageSettingProviders(providers); + } else { + ILanguageSettingsProvider provider = LanguageSettingsManager.getWorkspaceProvider(ManagedBuildManager.MBS_LANGUAGE_SETTINGS_PROVIDER); + List providers = new ArrayList(); + providers.add(provider); + cfgDes.setLanguageSettingProviders(providers); + } + + monitor.worked(1); pdMgr.setProjectDescription(project, projDesc); + + // FIXME if scanner discovery is empty it is "fixed" deeply inside setProjectDescription(), taking the easy road here for the moment + if (isTryingNewSD) { + ICProjectDescriptionManager mngr = CoreModel.getDefault().getProjectDescriptionManager(); + ICProjectDescription des = mngr.getProjectDescription(project); + boolean isChanged = CfgScannerConfigProfileManager.disableScannerDiscovery(des); + + if (isChanged) { + mngr.setProjectDescription(project, des); + } + } } catch (Throwable e) { ManagedBuilderUIPlugin.log(e); } + monitor.done(); } }; diff --git a/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/ui/wizards/NewMakeProjFromExistingPage.java b/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/ui/wizards/NewMakeProjFromExistingPage.java index 31e61531fff..0b584fe8aa4 100644 --- a/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/ui/wizards/NewMakeProjFromExistingPage.java +++ b/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/ui/wizards/NewMakeProjFromExistingPage.java @@ -19,6 +19,8 @@ import java.util.Map; import org.eclipse.cdt.managedbuilder.core.IToolChain; import org.eclipse.cdt.managedbuilder.core.ManagedBuildManager; import org.eclipse.cdt.managedbuilder.internal.ui.Messages; +import org.eclipse.cdt.ui.CUIPlugin; +import org.eclipse.cdt.ui.newui.CDTPrefUtil; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IWorkspaceRoot; import org.eclipse.core.resources.ResourcesPlugin; @@ -52,6 +54,9 @@ public class NewMakeProjFromExistingPage extends WizardPage { List tcList; Map tcMap = new HashMap(); + private Button checkBoxTryNewSD; + + protected NewMakeProjFromExistingPage() { super(Messages.NewMakeProjFromExistingPage_0); setTitle(Messages.NewMakeProjFromExistingPage_1); @@ -71,6 +76,21 @@ public class NewMakeProjFromExistingPage extends WizardPage { addLanguageSelector(comp); addToolchainSelector(comp); + checkBoxTryNewSD = new Button(comp, SWT.CHECK); + checkBoxTryNewSD.setText(org.eclipse.cdt.internal.ui.newui.Messages.CDTMainWizardPage_TrySD90); + GridData gd = new GridData(GridData.FILL_HORIZONTAL); + gd.horizontalSpan = 2; + checkBoxTryNewSD.setLayoutData(gd); + + + // restore settings from preferences + boolean isTryNewSD = true; + boolean contains = CUIPlugin.getDefault().getPreferenceStore().contains(CDTPrefUtil.KEY_NEWSD); + if (contains) { + isTryNewSD = CDTPrefUtil.getBool(CDTPrefUtil.KEY_NEWSD); + } + checkBoxTryNewSD.setSelection(isTryNewSD); + setControl(comp); } @@ -208,4 +228,7 @@ public class NewMakeProjFromExistingPage extends WizardPage { return selection.length != 0 ? tcMap.get(selection[0]) : null; } + public boolean isTryingNewSD() { + return checkBoxTryNewSD.getSelection(); + } } diff --git a/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/ui/wizards/STDWizardHandler.java b/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/ui/wizards/STDWizardHandler.java index b5128f0ef2e..83951ab46c9 100644 --- a/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/ui/wizards/STDWizardHandler.java +++ b/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/ui/wizards/STDWizardHandler.java @@ -11,7 +11,14 @@ *******************************************************************************/ package org.eclipse.cdt.managedbuilder.ui.wizards; +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.cdt.build.internal.core.scannerconfig2.CfgScannerConfigProfileManager; +import org.eclipse.cdt.core.language.settings.providers.ILanguageSettingsProvider; +import org.eclipse.cdt.core.language.settings.providers.LanguageSettingsManager; import org.eclipse.cdt.core.model.CoreModel; +import org.eclipse.cdt.core.settings.model.ICConfigurationDescription; import org.eclipse.cdt.core.settings.model.ICProjectDescription; import org.eclipse.cdt.core.settings.model.ICProjectDescriptionManager; import org.eclipse.cdt.core.settings.model.extension.CConfigurationData; @@ -24,10 +31,12 @@ import org.eclipse.cdt.managedbuilder.internal.core.ManagedBuildInfo; import org.eclipse.cdt.managedbuilder.internal.core.ManagedProject; import org.eclipse.cdt.managedbuilder.internal.core.ToolChain; import org.eclipse.cdt.managedbuilder.internal.ui.Messages; +import org.eclipse.cdt.ui.wizards.CDTMainWizardPage; import org.eclipse.core.resources.IProject; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.jface.wizard.IWizard; +import org.eclipse.jface.wizard.IWizardPage; import org.eclipse.swt.widgets.Composite; /** @@ -71,6 +80,14 @@ public class STDWizardHandler extends MBSWizardHandler { private void setProjectDescription(IProject project, boolean defaults, boolean onFinish, IProgressMonitor monitor) throws CoreException { + + boolean isTryingNewSD = false; + IWizardPage page = getStartingPage(); + if (page instanceof CDTMainWizardPage) { + CDTMainWizardPage mainWizardPage = (CDTMainWizardPage)page; + isTryingNewSD = mainWizardPage.isTryingNewSD(); + } + ICProjectDescriptionManager mngr = CoreModel.getDefault().getProjectDescriptionManager(); ICProjectDescription des = mngr.createProjectDescription(project, false, !onFinish); ManagedBuildInfo info = ManagedBuildManager.createBuildInfo(project); @@ -99,10 +116,33 @@ public class STDWizardHandler extends MBSWizardHandler { } cfg.setArtifactName(mProj.getDefaultArtifactName()); CConfigurationData data = cfg.getConfigurationData(); - des.createConfiguration(ManagedBuildManager.CFG_DATA_PROVIDER_ID, data); + ICConfigurationDescription cfgDes = des.createConfiguration(ManagedBuildManager.CFG_DATA_PROVIDER_ID, data); + + if (isTryingNewSD) { + CfgScannerConfigProfileManager.disableScannerDiscovery(cfg); + + List providers = ManagedBuildManager.getLanguageSettingsProviders(cfg); + cfgDes.setLanguageSettingProviders(providers); + } else { + ILanguageSettingsProvider provider = LanguageSettingsManager.getWorkspaceProvider(ManagedBuildManager.MBS_LANGUAGE_SETTINGS_PROVIDER); + List providers = new ArrayList(); + providers.add(provider); + cfgDes.setLanguageSettingProviders(providers); + } + monitor.worked(work); } mngr.setProjectDescription(project, des); + + // FIXME if scanner discovery is empty it is "fixed" deeply inside setProjectDescription(), taking the easy road here for the moment + if (isTryingNewSD) { + des = mngr.getProjectDescription(project); + boolean isChanged = CfgScannerConfigProfileManager.disableScannerDiscovery(des); + + if (isChanged) { + mngr.setProjectDescription(project, des); + } + } } public boolean canCreateWithoutToolchain() { return true; } diff --git a/core/org.eclipse.cdt.core.tests/misc/org/eclipse/cdt/core/internal/tests/filesystem/ram/MemoryEFSExtensionProvider.java b/core/org.eclipse.cdt.core.tests/misc/org/eclipse/cdt/core/internal/tests/filesystem/ram/MemoryEFSExtensionProvider.java new file mode 100644 index 00000000000..279f507aae8 --- /dev/null +++ b/core/org.eclipse.cdt.core.tests/misc/org/eclipse/cdt/core/internal/tests/filesystem/ram/MemoryEFSExtensionProvider.java @@ -0,0 +1,33 @@ +/******************************************************************************* + * Copyright (c) 2010, 2011 Andrew Gvozdev 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: + * Andrew Gvozdev - initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.core.internal.tests.filesystem.ram; + +import java.net.URI; + +import org.eclipse.cdt.core.EFSExtensionProvider; + +/** + * Test stub to test EFSExtensionProvider mappings. + * + */ +public class MemoryEFSExtensionProvider extends EFSExtensionProvider { + + public String getMappedPath(URI locationURI) { + + String path = locationURI.getPath(); + if (path.contains("/BeingMappedFrom/Folder")) { + return path.replaceFirst("/BeingMappedFrom/Folder", "/LocallyMappedTo/Folder"); + } + + return super.getMappedPath(locationURI); + } + +} diff --git a/core/org.eclipse.cdt.core.tests/model/org/eclipse/cdt/core/language/settings/providers/AllLanguageSettingsProvidersTests.java b/core/org.eclipse.cdt.core.tests/model/org/eclipse/cdt/core/language/settings/providers/AllLanguageSettingsProvidersTests.java new file mode 100644 index 00000000000..fb9b5be8379 --- /dev/null +++ b/core/org.eclipse.cdt.core.tests/model/org/eclipse/cdt/core/language/settings/providers/AllLanguageSettingsProvidersTests.java @@ -0,0 +1,32 @@ +/******************************************************************************* + * Copyright (c) 2010, 2011 Andrew Gvozdev 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: + * Andrew Gvozdev - Initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.core.language.settings.providers; + +import junit.framework.Test; +import junit.framework.TestSuite; + + +public class AllLanguageSettingsProvidersTests { + public static void main(String[] args) { + junit.textui.TestRunner.run(suite()); + } + + public static Test suite() { + TestSuite suite = new TestSuite(AllLanguageSettingsProvidersTests.class.getName()); + + suite.addTest(LanguageSettingsExtensionsTests.suite()); + suite.addTest(LanguageSettingsManagerTests.suite()); + suite.addTest(LanguageSettingsSerializableTests.suite()); + suite.addTest(LanguageSettingsPersistenceProjectTests.suite()); + suite.addTest(LanguageSettingsScannerInfoProviderTests.suite()); + return suite; + } +} diff --git a/core/org.eclipse.cdt.core.tests/model/org/eclipse/cdt/core/language/settings/providers/LanguageSettingsExtensionsTests.java b/core/org.eclipse.cdt.core.tests/model/org/eclipse/cdt/core/language/settings/providers/LanguageSettingsExtensionsTests.java new file mode 100644 index 00000000000..3a95102a247 --- /dev/null +++ b/core/org.eclipse.cdt.core.tests/model/org/eclipse/cdt/core/language/settings/providers/LanguageSettingsExtensionsTests.java @@ -0,0 +1,324 @@ +/******************************************************************************* + * Copyright (c) 2009, 2010 Andrew Gvozdev 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: + * Andrew Gvozdev - Initial API and implementation + *******************************************************************************/ + +package org.eclipse.cdt.core.language.settings.providers; + +import java.util.ArrayList; +import java.util.List; + +import junit.framework.TestCase; +import junit.framework.TestSuite; + +import org.eclipse.cdt.core.settings.model.CIncludeFileEntry; +import org.eclipse.cdt.core.settings.model.CIncludePathEntry; +import org.eclipse.cdt.core.settings.model.CLibraryFileEntry; +import org.eclipse.cdt.core.settings.model.CLibraryPathEntry; +import org.eclipse.cdt.core.settings.model.CMacroEntry; +import org.eclipse.cdt.core.settings.model.CMacroFileEntry; +import org.eclipse.cdt.core.settings.model.ICLanguageSettingEntry; +import org.eclipse.cdt.core.settings.model.ICSettingEntry; +import org.eclipse.cdt.core.settings.model.ILanguageSettingsEditableProvider; +import org.eclipse.cdt.internal.core.language.settings.providers.LanguageSettingsExtensionManager; +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.Path; + +/** + * Test cases testing LanguageSettingsProvider functionality + */ +public class LanguageSettingsExtensionsTests extends TestCase { + // These should match corresponding entries defined in plugin.xml + private static final String EXTENSION_BASE_PROVIDER_ID = "org.eclipse.cdt.core.tests.language.settings.base.provider"; + private static final String EXTENSION_BASE_PROVIDER_NAME = "Test Plugin Language Settings Base Provider"; + private static final String EXTENSION_BASE_PROVIDER_LANG_ID = "org.eclipse.cdt.core.tests.language.id"; + private static final String EXTENSION_BASE_PROVIDER_PARAMETER = "custom parameter"; + private static final String EXTENSION_CUSTOM_PROVIDER_ID = "org.eclipse.cdt.core.tests.custom.language.settings.provider"; + private static final String EXTENSION_CUSTOM_PROVIDER_NAME = "Test Plugin Language Settings Provider"; + private static final String EXTENSION_BASE_SUBCLASS_PROVIDER_ID = "org.eclipse.cdt.core.tests.language.settings.base.provider.subclass"; + private static final String EXTENSION_BASE_SUBCLASS_PROVIDER_PARAMETER = "custom parameter subclass"; + private static final String EXTENSION_SERIALIZABLE_PROVIDER_ID = "org.eclipse.cdt.core.tests.custom.serializable.language.settings.provider"; + private static final String EXTENSION_EDITABLE_PROVIDER_ID = "org.eclipse.cdt.core.tests.custom.editable.language.settings.provider"; + + // These are made up + private static final String PROVIDER_0 = "test.provider.0.id"; + private static final String PROVIDER_NAME_0 = "test.provider.0.name"; + private static final String LANG_ID = "test.lang.id"; + private static final IFile FILE_0 = ResourcesPlugin.getWorkspace().getRoot().getFile(new Path("/project/path0")); + + /** + * Constructor. + * @param name - name of the test. + */ + public LanguageSettingsExtensionsTests(String name) { + super(name); + + } + + @Override + protected void setUp() throws Exception { + } + + @Override + protected void tearDown() throws Exception { + } + + /** + * @return - new TestSuite. + */ + public static TestSuite suite() { + return new TestSuite(LanguageSettingsExtensionsTests.class); + } + + /** + * main function of the class. + * + * @param args - arguments + */ + public static void main(String[] args) { + junit.textui.TestRunner.run(suite()); + } + + /** + * Check that regular ICLanguageSettingsProvider extension defined in plugin.xml is accessible. + */ + public void testExtension() throws Exception { + { + List providers = LanguageSettingsManager.getWorkspaceProviders(); + List ids = new ArrayList(); + for (ILanguageSettingsProvider provider : providers) { + ids.add(provider.getId()); + } + assertTrue("extension " + EXTENSION_BASE_PROVIDER_ID + " not found", ids.contains(EXTENSION_BASE_PROVIDER_ID)); + } + + { + // test provider not in the list + ILanguageSettingsProvider providerExt = LanguageSettingsManager.getExtensionProviderCopy("missing.povider"); + assertTrue(LanguageSettingsManager.isWorkspaceProvider(providerExt)); + ILanguageSettingsProvider rawProvider = LanguageSettingsManager.getRawProvider(providerExt); + assertNull(rawProvider); + } + + // get test plugin extension provider + ILanguageSettingsProvider providerExt = LanguageSettingsManager.getExtensionProviderCopy(EXTENSION_BASE_PROVIDER_ID); + assertTrue(LanguageSettingsManager.isWorkspaceProvider(providerExt)); + + // get raw extension provider + ILanguageSettingsProvider rawProvider = LanguageSettingsManager.getRawProvider(providerExt); + assertTrue(rawProvider instanceof LanguageSettingsBaseProvider); + LanguageSettingsBaseProvider provider = (LanguageSettingsBaseProvider)rawProvider; + assertEquals(EXTENSION_BASE_PROVIDER_ID, provider.getId()); + assertEquals(EXTENSION_BASE_PROVIDER_NAME, provider.getName()); + assertEquals(EXTENSION_BASE_PROVIDER_PARAMETER, provider.getCustomParameter()); + + // attempt to get entries for wrong language + assertNull(provider.getSettingEntries(null, FILE_0, LANG_ID)); + + // benchmarks matching extension point definition + List entriesExt = new ArrayList(); + entriesExt.add(new CIncludePathEntry("/usr/include/", + ICSettingEntry.BUILTIN + | ICSettingEntry.LOCAL + | ICSettingEntry.RESOLVED + | ICSettingEntry.VALUE_WORKSPACE_PATH + | ICSettingEntry.UNDEFINED + )); + entriesExt.add(new CMacroEntry("TEST_DEFINE", "100", 0)); + entriesExt.add(new CIncludeFileEntry("/include/file.inc", 0)); + entriesExt.add(new CLibraryPathEntry("/usr/lib/", 0)); + entriesExt.add(new CLibraryFileEntry("libdomain.a", 0)); + entriesExt.add(new CMacroFileEntry("/macro/file.mac", 0)); + + // retrieve entries from extension point + List actual = provider.getSettingEntries(null, FILE_0, EXTENSION_BASE_PROVIDER_LANG_ID); + for (int i=0;i actual = provider.getSettingEntries(null, FILE_0, LANG_ID); + for (int i=0;i languages = new ArrayList(2); + languages.add("bogus.language.id"); + languages.add(LANG_ID); + + // add default provider + LanguageSettingsBaseProvider provider = new LanguageSettingsBaseProvider( + PROVIDER_0, PROVIDER_NAME_0, languages, entries); + + { + // attempt to get entries for wrong language + List actual = provider.getSettingEntries(null, FILE_0, "wrong.lang.id"); + assertNull(actual); + } + + { + // retrieve the entries + List actual = provider.getSettingEntries(null, FILE_0, LANG_ID); + assertEquals(entries.get(0), actual.get(0)); + assertNotSame(entries, actual); + // retrieve languages + List actualLanguageIds = provider.getLanguageScope(); + for (String languageId: languages) { + assertTrue(actualLanguageIds.contains(languageId)); + } + assertEquals(languages.size(), actualLanguageIds.size()); + } + } + + /** + * TODO + */ + public void testSerializableProvider() throws Exception { + // get test plugin extension for serializable provider + ILanguageSettingsProvider providerExt = LanguageSettingsManager.getExtensionProviderCopy(EXTENSION_SERIALIZABLE_PROVIDER_ID); + assertTrue(LanguageSettingsManager.isWorkspaceProvider(providerExt)); + + // get raw extension provider + ILanguageSettingsProvider rawProvider = LanguageSettingsManager.getRawProvider(providerExt); + assertTrue(rawProvider instanceof LanguageSettingsSerializable); + LanguageSettingsSerializable provider = (LanguageSettingsSerializable) rawProvider; + + assertEquals(null, provider.getLanguageScope()); + assertEquals("", provider.getCustomParameter()); + + List expected = new ArrayList(); + expected.add(new CMacroEntry("MACRO", "value", 0)); + assertEquals(expected, provider.getSettingEntries(null, null, null)); + } + + /** + * TODO + */ + public void testEditableProvider() throws Exception { + // Non-editable providers cannot be copied so they are singletons + { + // get test plugin extension for serializable provider + ILanguageSettingsProvider providerExt = LanguageSettingsManager.getExtensionProviderCopy(EXTENSION_SERIALIZABLE_PROVIDER_ID); + assertTrue(LanguageSettingsManager.isWorkspaceProvider(providerExt)); + + // get raw extension provider + ILanguageSettingsProvider rawProvider = LanguageSettingsManager.getRawProvider(providerExt); + assertTrue(rawProvider instanceof LanguageSettingsSerializable); + assertTrue(LanguageSettingsExtensionManager.equalsExtensionProvider(rawProvider)); + + // compare with workspace provider + ILanguageSettingsProvider providerWsp = LanguageSettingsManager.getWorkspaceProvider(EXTENSION_SERIALIZABLE_PROVIDER_ID); + ILanguageSettingsProvider providerWspRaw = LanguageSettingsManager.getRawProvider(providerWsp); + assertSame(rawProvider, providerWspRaw); + } + + // Editable providers are retrieved by copy + { + ILanguageSettingsProvider providerExt = LanguageSettingsManager.getExtensionProviderCopy(EXTENSION_EDITABLE_PROVIDER_ID); + assertFalse(LanguageSettingsManager.isWorkspaceProvider(providerExt)); + assertTrue(providerExt instanceof ILanguageSettingsEditableProvider); + assertTrue(LanguageSettingsExtensionManager.equalsExtensionProvider(providerExt)); + + ILanguageSettingsProvider providerExt2 = LanguageSettingsManager.getExtensionProviderCopy(EXTENSION_EDITABLE_PROVIDER_ID); + assertNotSame(providerExt, providerExt2); + assertEquals(providerExt, providerExt2); + + ILanguageSettingsProvider providerWsp = LanguageSettingsManager.getWorkspaceProvider(EXTENSION_EDITABLE_PROVIDER_ID); + ILanguageSettingsProvider providerWspRaw = LanguageSettingsManager.getRawProvider(providerWsp); + assertNotSame(providerExt, providerWspRaw); + assertEquals(providerExt, providerWspRaw); + assertTrue(LanguageSettingsExtensionManager.equalsExtensionProvider(providerWspRaw)); + } + + // Test shallow copy + { + ILanguageSettingsProvider provider = LanguageSettingsManager.getExtensionProviderCopy(EXTENSION_EDITABLE_PROVIDER_ID); + assertNotNull(provider); + assertTrue(provider instanceof ILanguageSettingsEditableProvider); + + ILanguageSettingsProvider providerShallow = LanguageSettingsExtensionManager.getExtensionProviderShallow(EXTENSION_EDITABLE_PROVIDER_ID); + assertNotNull(providerShallow); + assertTrue(providerShallow instanceof ILanguageSettingsEditableProvider); + assertFalse(provider.equals(providerShallow)); + + assertFalse(LanguageSettingsExtensionManager.equalsExtensionProvider(providerShallow)); + assertTrue(LanguageSettingsExtensionManager.equalsExtensionProviderShallow((ILanguageSettingsEditableProvider) providerShallow)); + + } + } + +// /** +// * LanguageSettingsBaseProvider is not allowed to be configured twice. +// */ +// public void testBaseProviderConfigure() throws Exception { +// // create LanguageSettingsBaseProvider +// LanguageSettingsBaseProvider provider = new LanguageSettingsBaseProvider(); +// List entries = new ArrayList(); +// entries.add(new CIncludePathEntry("/usr/include/", 0)); +// // configure it +// provider.configureProvider("id", "name", null, entries, null); +// +// try { +// // attempt to configure it twice should fail +// provider.configureProvider("id", "name", null, entries, null); +// fail("LanguageSettingsBaseProvider is not allowed to be configured twice"); +// } catch (UnsupportedOperationException e) { +// } +// } + +} diff --git a/core/org.eclipse.cdt.core.tests/model/org/eclipse/cdt/core/language/settings/providers/LanguageSettingsManagerTests.java b/core/org.eclipse.cdt.core.tests/model/org/eclipse/cdt/core/language/settings/providers/LanguageSettingsManagerTests.java new file mode 100644 index 00000000000..066ac866a66 --- /dev/null +++ b/core/org.eclipse.cdt.core.tests/model/org/eclipse/cdt/core/language/settings/providers/LanguageSettingsManagerTests.java @@ -0,0 +1,781 @@ +/******************************************************************************* + * Copyright (c) 2009, 2010 Andrew Gvozdev 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: + * Andrew Gvozdev - Initial API and implementation + *******************************************************************************/ + +package org.eclipse.cdt.core.language.settings.providers; + +import java.util.ArrayList; +import java.util.List; + +import junit.framework.TestCase; +import junit.framework.TestSuite; + +import org.eclipse.cdt.core.AbstractExecutableExtensionBase; +import org.eclipse.cdt.core.model.CoreModel; +import org.eclipse.cdt.core.settings.model.CIncludePathEntry; +import org.eclipse.cdt.core.settings.model.CMacroEntry; +import org.eclipse.cdt.core.settings.model.ICConfigurationDescription; +import org.eclipse.cdt.core.settings.model.ICLanguageSettingEntry; +import org.eclipse.cdt.core.settings.model.ICProjectDescription; +import org.eclipse.cdt.core.settings.model.ICSettingEntry; +import org.eclipse.cdt.core.testplugin.CModelMock; +import org.eclipse.cdt.core.testplugin.ResourceHelper; +import org.eclipse.cdt.internal.core.language.settings.providers.LanguageSettingsExtensionManager; +import org.eclipse.cdt.internal.core.settings.model.CConfigurationDescription; +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IFolder; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.Path; + +/** + * Test cases testing LanguageSettingsProvider functionality + */ +public class LanguageSettingsManagerTests extends TestCase { + // Should match id of extension point defined in plugin.xml + private static final String EXTENSION_BASE_PROVIDER_ID = "org.eclipse.cdt.core.tests.language.settings.base.provider"; + private static final String EXTENSION_EDITABLE_PROVIDER_ID = "org.eclipse.cdt.core.tests.custom.editable.language.settings.provider"; + private static final String EXTENSION_EDITABLE_PROVIDER_NAME = "Test Plugin Editable Language Settings Provider"; + + private static final IFile FILE_0 = ResourcesPlugin.getWorkspace().getRoot().getFile(new Path("/project/path0")); + private static final String CFG_ID = "test.configuration.id"; + private static final String LANG_ID = "test.lang.id"; + private static final String PROVIDER_0 = "test.provider.0.id"; + private static final String PROVIDER_1 = "test.provider.1.id"; + private static final String PROVIDER_2 = "test.provider.2.id"; + private static final String PROVIDER_NAME_0 = "test.provider.0.name"; + private static final String PROVIDER_NAME_1 = "test.provider.1.name"; + private static final String PROVIDER_NAME_2 = "test.provider.2.name"; + + class MockConfigurationDescription extends CModelMock.DummyCConfigurationDescription { + List providers = new ArrayList(); + public MockConfigurationDescription(String id) { + super(id); + } + + @Override + public void setLanguageSettingProviders(List providers) { + this.providers = new ArrayList(providers); + } + + @Override + public List getLanguageSettingProviders() { + return providers; + } + } + + private class MockProvider extends AbstractExecutableExtensionBase implements ILanguageSettingsProvider { + private List entries; + + public MockProvider(String id, String name, List entries) { + super(id, name); + this.entries = entries; + } + + public List getSettingEntries(ICConfigurationDescription cfgDescription, IResource rc, String languageId) { + return entries; + } + } + + + /** + * Constructor. + * @param name - name of the test. + */ + public LanguageSettingsManagerTests(String name) { + super(name); + + } + + @Override + protected void setUp() throws Exception { + } + + @Override + protected void tearDown() throws Exception { + LanguageSettingsManager.setWorkspaceProviders(null); + ResourceHelper.cleanUp(); + } + + /** + * @return - new TestSuite. + */ + public static TestSuite suite() { + return new TestSuite(LanguageSettingsManagerTests.class); + } + + /** + * main function of the class. + * + * @param args - arguments + */ + public static void main(String[] args) { + junit.textui.TestRunner.run(suite()); + } + + /** + * Test ICConfigurationDescription API (getters and setters). + */ + public void testConfigurationDescription_Providers() throws Exception { + ICConfigurationDescription cfgDescription = new MockConfigurationDescription(CFG_ID); + + // set providers + ILanguageSettingsProvider provider1 = new MockProvider(PROVIDER_1, PROVIDER_NAME_1, null); + ILanguageSettingsProvider provider2 = new MockProvider(PROVIDER_2, PROVIDER_NAME_2, null); + List providers = new ArrayList(); + providers.add(provider1); + providers.add(provider2); + cfgDescription.setLanguageSettingProviders(providers); + + // get providers + List actual = cfgDescription.getLanguageSettingProviders(); + assertEquals(provider1, actual.get(0)); + assertEquals(provider2, actual.get(1)); + assertEquals(providers.size(), actual.size()); + assertNotSame(actual, providers); + } + + /** + * Test to ensure uniqueness of ids for providers kept in configuration description. + */ + public void testConfigurationDescription_ProvidersUniqueId() throws Exception { + // Create model project and accompanied descriptions + String projectName = getName(); + IProject project = ResourceHelper.createCDTProjectWithConfig(projectName); + ICProjectDescription writableProjDescription = CoreModel.getDefault().getProjectDescription(project, true); + + ICConfigurationDescription[] cfgDescriptions = writableProjDescription.getConfigurations(); + ICConfigurationDescription cfgDescription = cfgDescriptions[0]; + assertTrue(cfgDescription instanceof CConfigurationDescription); + + // attempt to add duplicate providers + MockProvider dupe1 = new MockProvider(PROVIDER_0, PROVIDER_NAME_1, null); + MockProvider dupe2 = new MockProvider(PROVIDER_0, PROVIDER_NAME_2, null); + + List providers = new ArrayList(); + providers.add(dupe1); + providers.add(dupe2); + + try { + cfgDescription.setLanguageSettingProviders(providers); + fail("cfgDescription.setLanguageSettingProviders() should not accept duplicate providers"); + } catch (Exception e) { + // Exception is welcome here + } + } + + /** + * Test various cases of ill-defined providers. + */ + public void testRudeProviders() throws Exception { + ICConfigurationDescription cfgDescription = new MockConfigurationDescription(CFG_ID); + // set impolite provider returning null by getSettingEntries() + ILanguageSettingsProvider providerNull = new MockProvider(PROVIDER_1, PROVIDER_NAME_1, null); + { + List providers = new ArrayList(); + providers.add(providerNull); + cfgDescription.setLanguageSettingProviders(providers); + } + + // use provider returning null, no exception should be recorded + { + List actual = LanguageSettingsManager + .getSettingEntriesUpResourceTree(providerNull, cfgDescription, FILE_0, LANG_ID); + assertNotNull(actual); + assertEquals(0, actual.size()); + } + { + List actual = LanguageSettingsManager + .getSettingEntriesByKind(cfgDescription, FILE_0, LANG_ID, 0); + assertNotNull(actual); + assertEquals(0, actual.size()); + } + + // set impolite provider returning null in getSettingEntries() array + ILanguageSettingsProvider providerNull_2 = new MockProvider(PROVIDER_2, PROVIDER_NAME_2, + new ArrayList() { + { // init via static initializer + add(null); + } + }); + + { + List providers = new ArrayList(); + providers.add(providerNull); + cfgDescription.setLanguageSettingProviders(providers); + } + + // use provider returning null as item in array + { + List actual = LanguageSettingsManager + .getSettingEntriesUpResourceTree(providerNull_2, cfgDescription, FILE_0, LANG_ID); + assertNotNull(actual); + assertEquals(1, actual.size()); + } + { + List actual = LanguageSettingsManager + .getSettingEntriesByKind(cfgDescription, FILE_0, LANG_ID, 0); + assertNotNull(actual); + assertEquals(0, actual.size()); + } + + // use careless provider causing an exception + { + ILanguageSettingsProvider providerNPE = new MockProvider(PROVIDER_1, PROVIDER_NAME_1, null) { + public List getSettingEntries(ICConfigurationDescription cfgDescription, IResource rc, String languageId) { + throw new NullPointerException("Can you handle me?"); + } + }; + try { + List actual = LanguageSettingsManager + .getSettingEntriesUpResourceTree(providerNPE, null, null, LANG_ID); + assertNotNull(actual); + assertEquals(0, actual.size()); + } catch (Throwable e) { + fail("Exceptions are expected to be swallowed (after logging) but got " + e); + } + } + } + + /** + * Test simple use case. + */ + public void testProvider_Basic() throws Exception { + final ICConfigurationDescription modelCfgDescription = new MockConfigurationDescription(CFG_ID); + + final List entries = new ArrayList(); + entries.add(new CIncludePathEntry("path0", 0)); + + List providers = new ArrayList(); + // define provider returning entries when configuration id matches and null otherwise + ILanguageSettingsProvider providerYes = new MockProvider(PROVIDER_0, PROVIDER_NAME_0, null) { + @Override + public List getSettingEntries(ICConfigurationDescription cfgDescription, IResource rc, String languageId) { + if (cfgDescription.getId().equals(modelCfgDescription.getId())) { + return entries; + } + return null; + } + + }; + providers.add(providerYes); + // define provider returning null when configuration id matches and some entries otherwise + ILanguageSettingsProvider providerNo = new MockProvider(PROVIDER_1, PROVIDER_NAME_1, null) { + @Override + public List getSettingEntries(ICConfigurationDescription cfgDescription, IResource rc, String languageId) { + if (cfgDescription.getId().equals(modelCfgDescription.getId())) { + return null; + } + return entries; + } + + }; + providers.add(providerNo); + modelCfgDescription.setLanguageSettingProviders(providers); + + { + // retrieve the entries with provider returning the given list + List actual = LanguageSettingsManager + .getSettingEntriesUpResourceTree(providerYes, modelCfgDescription, FILE_0, LANG_ID); + assertEquals(entries.get(0), actual.get(0)); + assertEquals(entries.size(), actual.size()); + } + + { + // retrieve the entries with provider returning empty list + List actual = LanguageSettingsManager + .getSettingEntriesUpResourceTree(providerNo, modelCfgDescription, FILE_0, LANG_ID); + assertEquals(0, actual.size()); + } + } + + /** + * Test regular functionality with a few providers. + */ + public void testProvider_Regular() throws Exception { + ICConfigurationDescription cfgDescription = new MockConfigurationDescription(CFG_ID); + + // create couple of providers + List entries1 = new ArrayList(); + entries1.add(new CIncludePathEntry("value1", 1)); + entries1.add(new CIncludePathEntry("value2", 2)); + + List entries2 = new ArrayList(); + entries2.add(new CIncludePathEntry("value1", 1)); + entries2.add(new CIncludePathEntry("value2", 2)); + entries2.add(new CIncludePathEntry("value3", 2)); + + ILanguageSettingsProvider provider1 = new MockProvider(PROVIDER_1, PROVIDER_NAME_1, entries1); + ILanguageSettingsProvider provider2 = new MockProvider(PROVIDER_2, PROVIDER_NAME_2, entries2); + List providers = new ArrayList(); + providers.add(provider1); + providers.add(provider2); + cfgDescription.setLanguageSettingProviders(providers); + + { + // retrieve the entries for provider-1 + List actual = LanguageSettingsManager + .getSettingEntriesUpResourceTree(provider1, cfgDescription, FILE_0, LANG_ID); + assertNotSame(entries1, actual); + + ICLanguageSettingEntry[] entriesArray = entries1.toArray(new ICLanguageSettingEntry[0]); + ICLanguageSettingEntry[] actualArray = actual.toArray(new ICLanguageSettingEntry[0]); + for (int i=0;i entries = new ArrayList(); + entries.add(new CIncludePathEntry("path0", 0)); + List providers = new ArrayList(); + ILanguageSettingsProvider provider = new MockProvider(PROVIDER_0, PROVIDER_NAME_0, null) { + @Override + public List getSettingEntries(ICConfigurationDescription cfgDescription, IResource rc, String languageId) { + if (rc.equals(parentFolder)) { + return entries; + } + if (rc.equals(emptySettingsPath)) { + return new ArrayList(0); + } + return null; + } + + }; + providers.add(provider); + cfgDescription.setLanguageSettingProviders(providers); + + { + // retrieve entries for a derived resource (in a subfolder) + IFile derived = ResourceHelper.createFile(project, "/ParentFolder/Subfolder/resource"); + List actual = LanguageSettingsManager + .getSettingEntriesUpResourceTree(provider, cfgDescription, derived, LANG_ID); + // taken from parent folder + assertEquals(entries.get(0),actual.get(0)); + assertEquals(entries.size(), actual.size()); + } + + { + // retrieve entries for not related resource + IFile notRelated = ResourcesPlugin.getWorkspace().getRoot().getFile(new Path("/AnotherFolder/Subfolder/resource")); + List actual = LanguageSettingsManager + .getSettingEntriesUpResourceTree(provider, cfgDescription, notRelated, LANG_ID); + assertEquals(0, actual.size()); + } + + { + // test distinction between no settings and empty settings + List actual = LanguageSettingsManager + .getSettingEntriesUpResourceTree(provider, cfgDescription, emptySettingsPath, LANG_ID); + // NOT taken from parent folder + assertEquals(0, actual.size()); + } + } + + /** + */ + public void testProvider_DefaultEntries() throws Exception { + // Create model project and accompanied descriptions + String projectName = getName(); + IProject project = ResourceHelper.createCDTProjectWithConfig(projectName); + ICProjectDescription prjDescription = CoreModel.getDefault().getProjectDescription(project); + ICConfigurationDescription[] cfgDescriptions = prjDescription.getConfigurations(); + + ICConfigurationDescription cfgDescription = cfgDescriptions[0]; + assertTrue(cfgDescription instanceof CConfigurationDescription); + + final IFolder parentFolder = ResourceHelper.createFolder(project, "/ParentFolder/"); + assertNotNull(parentFolder); + final IFile emptySettingsPath = ResourceHelper.createFile(project, "/ParentFolder/Subfolder/empty"); + assertNotNull(emptySettingsPath); + + // store the entries as default entries + final List entries = new ArrayList(); + entries.add(new CIncludePathEntry("path0", 0)); + List providers = new ArrayList(); + ILanguageSettingsProvider provider = new MockProvider(PROVIDER_0, PROVIDER_NAME_0, null) { + @Override + public List getSettingEntries(ICConfigurationDescription cfgDescription, IResource rc, String languageId) { + if (cfgDescription==null && rc==null) { + return entries; + } + return null; + } + + }; + providers.add(provider); + cfgDescription.setLanguageSettingProviders(providers); + + { + // retrieve entries for a resource + IFile derived = ResourceHelper.createFile(project, "/ParentFolder/Subfolder/resource"); + List actual = LanguageSettingsManager + .getSettingEntriesUpResourceTree(provider, cfgDescription, derived, LANG_ID); + // default entries given + assertEquals(entries.get(0),actual.get(0)); + assertEquals(entries.size(), actual.size()); + } + } + + /** + * Test ability to get entries by kind. + */ + public void testEntriesByKind_Regular() throws Exception { + ICConfigurationDescription cfgDescription = new MockConfigurationDescription(CFG_ID); + + // contribute the entries + List entries = new ArrayList(); + entries.add(new CIncludePathEntry("path0", 0)); + entries.add(new CMacroEntry("MACRO0", "value0",0)); + entries.add(new CIncludePathEntry("path1", 0)); + entries.add(new CMacroEntry("MACRO1", "value1",0)); + entries.add(new CIncludePathEntry("path2", 0)); + + ILanguageSettingsProvider provider0 = new MockProvider(PROVIDER_0, PROVIDER_NAME_0, entries); + List providers = new ArrayList(); + providers.add(provider0); + cfgDescription.setLanguageSettingProviders(providers); + + // retrieve entries by kind + List includes = LanguageSettingsManager + .getSettingEntriesByKind(cfgDescription, FILE_0, LANG_ID, ICSettingEntry.INCLUDE_PATH); + assertEquals(new CIncludePathEntry("path0", 0),includes.get(0)); + assertEquals(new CIncludePathEntry("path1", 0),includes.get(1)); + assertEquals(new CIncludePathEntry("path2", 0),includes.get(2)); + assertEquals(3, includes.size()); + + List macros = LanguageSettingsManager + .getSettingEntriesByKind(cfgDescription, FILE_0, LANG_ID, ICSettingEntry.MACRO); + assertEquals(new CMacroEntry("MACRO0", "value0",0), macros.get(0)); + assertEquals(new CMacroEntry("MACRO1", "value1",0), macros.get(1)); + assertEquals(2, macros.size()); + } + + /** + * Test how conflicting entries are resolved. + */ + public void testEntriesByKind_ConflictingEntries() throws Exception { + ICConfigurationDescription cfgDescription = new MockConfigurationDescription(CFG_ID); + + // contribute the entries + List entries = new ArrayList(); + entries.add(new CIncludePathEntry("path", ICSettingEntry.BUILTIN)); + entries.add(new CIncludePathEntry("path", ICSettingEntry.UNDEFINED)); + entries.add(new CIncludePathEntry("path", 0)); + + ILanguageSettingsProvider provider0 = new MockProvider(PROVIDER_0, PROVIDER_NAME_0, entries); + List providers = new ArrayList(); + providers.add(provider0); + cfgDescription.setLanguageSettingProviders(providers); + + // retrieve entries by kind, only first entry should be returned + List includes = LanguageSettingsManager + .getSettingEntriesByKind(cfgDescription, FILE_0, LANG_ID, ICSettingEntry.INCLUDE_PATH); + assertEquals(1, includes.size()); + assertEquals(entries.get(0),includes.get(0)); + } + + /** + * Check handling of {@link ICSettingEntry#UNDEFINED} flag. + */ + public void testEntriesByKind_Undefined() throws Exception { + ICConfigurationDescription cfgDescription = new MockConfigurationDescription(CFG_ID); + + // contribute the entries + List entries = new ArrayList(); + entries.add(new CIncludePathEntry("path", ICSettingEntry.UNDEFINED)); + entries.add(new CIncludePathEntry("path", 0)); + + ILanguageSettingsProvider provider0 = new MockProvider(PROVIDER_0, PROVIDER_NAME_0, entries); + List providers = new ArrayList(); + providers.add(provider0); + cfgDescription.setLanguageSettingProviders(providers); + + // retrieve entries by kind, no entries should be returned + List includes = LanguageSettingsManager + .getSettingEntriesByKind(cfgDescription, FILE_0, LANG_ID, ICSettingEntry.INCLUDE_PATH); + assertEquals(0, includes.size()); + } + + /** + * Check handling of local vs. system entries, see {@link ICSettingEntry#LOCAL} flag. + */ + public void testEntriesByKind_LocalAndSystem() throws Exception { + ICConfigurationDescription cfgDescription = new MockConfigurationDescription(CFG_ID); + + // contribute the entries + List entries = new ArrayList(); + CIncludePathEntry localIncludeEntry = new CIncludePathEntry("path-local", ICSettingEntry.LOCAL); + CIncludePathEntry systemIncludeEntry = new CIncludePathEntry("path-system", 0); + entries.add(localIncludeEntry); + entries.add(systemIncludeEntry); + + ILanguageSettingsProvider provider0 = new MockProvider(PROVIDER_0, PROVIDER_NAME_0, entries); + List providers = new ArrayList(); + providers.add(provider0); + cfgDescription.setLanguageSettingProviders(providers); + + { + // retrieve local entries + List includes = LanguageSettingsExtensionManager + .getLocalSettingEntriesByKind(cfgDescription, FILE_0, LANG_ID, ICSettingEntry.INCLUDE_PATH); + assertEquals(localIncludeEntry, includes.get(0)); + assertEquals(1, includes.size()); + } + + { + // retrieve system entries + List includes = LanguageSettingsExtensionManager + .getSystemSettingEntriesByKind(cfgDescription, FILE_0, LANG_ID, ICSettingEntry.INCLUDE_PATH); + assertEquals(systemIncludeEntry, includes.get(0)); + assertEquals(1, includes.size()); + } + + { + // retrieve both local and system + List includes = LanguageSettingsExtensionManager + .getSettingEntriesByKind(cfgDescription, FILE_0, LANG_ID, ICSettingEntry.INCLUDE_PATH); + assertEquals(entries.get(0), includes.get(0)); + assertEquals(entries.get(1), includes.get(1)); + assertEquals(2, includes.size()); + } + } + + /** + * Test conflicting entries contributed by different providers. + */ + public void testEntriesByKind_ConflictingProviders() throws Exception { + ICConfigurationDescription cfgDescription = new MockConfigurationDescription(CFG_ID); + + // contribute the entries + List providers = new ArrayList(); + + // contribute the higher ranked entries + List entriesHigh = new ArrayList(); + entriesHigh.add(new CIncludePathEntry("path0", ICSettingEntry.RESOLVED)); + entriesHigh.add(new CIncludePathEntry("path1", 0)); + entriesHigh.add(new CIncludePathEntry("path2", ICSettingEntry.UNDEFINED)); + ILanguageSettingsProvider highRankProvider = new MockProvider(PROVIDER_2, PROVIDER_NAME_2, entriesHigh); + providers.add(highRankProvider); + + // contribute the lower ranked entries + List entriesLow = new ArrayList(); + entriesLow.add(new CIncludePathEntry("path0", ICSettingEntry.BUILTIN)); + entriesLow.add(new CIncludePathEntry("path1", ICSettingEntry.UNDEFINED)); + entriesLow.add(new CIncludePathEntry("path2", 0)); + entriesLow.add(new CIncludePathEntry("path3", 0)); + ILanguageSettingsProvider lowRankProvider = new MockProvider(PROVIDER_1, PROVIDER_NAME_1, entriesLow); + providers.add(lowRankProvider); + + cfgDescription.setLanguageSettingProviders(providers); + + // retrieve entries by kind + List includes = LanguageSettingsManager + .getSettingEntriesByKind(cfgDescription, FILE_0, LANG_ID, ICSettingEntry.INCLUDE_PATH); + // path0 is taken from higher priority provider + assertEquals(entriesHigh.get(0),includes.get(0)); + // path1 disablement by lower priority provider is ignored + assertEquals(entriesHigh.get(1),includes.get(1)); + // path2 is removed because of DISABLED flag of high priority provider + // path3 gets there from low priority provider + assertEquals(entriesLow.get(3),includes.get(2)); + assertEquals(3, includes.size()); + } + + /** + * Test ability to serialize providers for a configuration. + */ + public void testConfigurationDescription_SerializeProviders() throws Exception { + // Create model project and accompanied descriptions + String projectName = getName(); + IProject project = ResourceHelper.createCDTProjectWithConfig(projectName); + ICProjectDescription writableProjDescription = CoreModel.getDefault().getProjectDescription(project, true); + + ICConfigurationDescription[] cfgDescriptions = writableProjDescription.getConfigurations(); + ICConfigurationDescription cfgDescription = cfgDescriptions[0]; + assertTrue(cfgDescription instanceof CConfigurationDescription); + + ILanguageSettingsProvider workspaceProvider = LanguageSettingsManager.getWorkspaceProvider(EXTENSION_BASE_PROVIDER_ID); + assertNotNull(workspaceProvider); + { + // ensure no test provider is set yet + List providers = cfgDescription.getLanguageSettingProviders(); + assertEquals(0, providers.size()); + } + { + // set test provider + List providers = new ArrayList(); + providers.add(workspaceProvider); + cfgDescription.setLanguageSettingProviders(providers); + } + { + // check that test provider got there + List providers = cfgDescription.getLanguageSettingProviders(); + assertEquals(workspaceProvider, providers.get(0)); + } + + { + // serialize + CoreModel.getDefault().setProjectDescription(project, writableProjDescription); + // close and reopen the project + project.close(null); + project.open(null); + } + + { + // check that test provider got loaded + ICProjectDescription prjDescription = CoreModel.getDefault().getProjectDescription(project); + ICConfigurationDescription[] loadedCfgDescriptions = prjDescription.getConfigurations(); + ICConfigurationDescription loadedCfgDescription = loadedCfgDescriptions[0]; + assertTrue(cfgDescription instanceof CConfigurationDescription); + + List loadedProviders = loadedCfgDescription.getLanguageSettingProviders(); + assertTrue(LanguageSettingsManager.isWorkspaceProvider(loadedProviders.get(0))); + } + + } + + /** + * Test a workspace provider basics. + */ + public void testWorkspaceProvider_Basic() throws Exception { + // get workspace provider + ILanguageSettingsProvider provider = LanguageSettingsManager.getWorkspaceProvider(EXTENSION_EDITABLE_PROVIDER_ID); + assertEquals(EXTENSION_EDITABLE_PROVIDER_ID, provider.getId()); + assertEquals(EXTENSION_EDITABLE_PROVIDER_NAME, provider.getName()); + + // get raw provider + ILanguageSettingsProvider rawProvider = LanguageSettingsManager.getRawProvider(provider); + assertEquals(EXTENSION_EDITABLE_PROVIDER_ID, rawProvider.getId()); + assertEquals(EXTENSION_EDITABLE_PROVIDER_NAME, rawProvider.getName()); + assertTrue(rawProvider instanceof LanguageSettingsSerializable); + // assert they are not the same object + assertNotSame(provider, rawProvider); + + { + // make sure entries are the same + List entries = provider.getSettingEntries(null, null, null); + assertEquals(1, entries.size()); // defined in the extension + List rawEntries = rawProvider.getSettingEntries(null, null, null); + assertEquals(entries, rawEntries); + } + + { + // set new entries to the raw provider + List newEntries = new ArrayList(); + newEntries.add(new CIncludePathEntry("path0", 0)); + newEntries.add(new CIncludePathEntry("path1", 0)); + ((LanguageSettingsSerializable)rawProvider).setSettingEntries(null, null, null, newEntries); + + // check that the workspace provider gets them too + List newRawEntries = rawProvider.getSettingEntries(null, null, null); + assertEquals(newEntries, newRawEntries); + assertEquals(2, newEntries.size()); + } + } + + /** + * Test workspace providers equality. + */ + public void testWorkspaceProvider_Equals() throws Exception { + ILanguageSettingsProvider providerA = LanguageSettingsManager.getWorkspaceProvider(EXTENSION_EDITABLE_PROVIDER_ID); + ILanguageSettingsProvider providerB = LanguageSettingsManager.getWorkspaceProvider(EXTENSION_EDITABLE_PROVIDER_ID); + assertEquals(providerA, providerB); + } + + /** + * Test ability to replace underlying raw provider. + */ + public void testWorkspaceProvider_ReplaceRawProvider() throws Exception { + // get sample workspace provider + ILanguageSettingsProvider provider = LanguageSettingsManager.getWorkspaceProvider(EXTENSION_EDITABLE_PROVIDER_ID); + { + // check on its entries + List entries = provider.getSettingEntries(null, null, null); + assertEquals(1, entries.size()); // defined in the extension + } + + // define new entries for the raw provider + List newEntries = new ArrayList(); + newEntries.add(new CIncludePathEntry("path0", 0)); + newEntries.add(new CIncludePathEntry("path1", 0)); + newEntries.add(new CIncludePathEntry("path2", 0)); + + { + // replace raw provider + List providers = new ArrayList(); + LanguageSettingsSerializable newRawProvider = new LanguageSettingsSerializable(EXTENSION_EDITABLE_PROVIDER_ID, PROVIDER_NAME_0); + newRawProvider.setSettingEntries(null, null, null, newEntries); + providers.add(newRawProvider); + LanguageSettingsManager.setWorkspaceProviders(providers); + } + + { + // check that provider provides the new entries + List entries = provider.getSettingEntries(null, null, null); + assertEquals(newEntries.size(), entries.size()); + assertEquals(newEntries, entries); + } + } + + /** + * Test ability to be called with workspace provider as well (NOOP). + */ + public void testWorkspaceProvider_ReplaceWithWorkspaceProvider() throws Exception { + // get sample workspace provider + ILanguageSettingsProvider provider = LanguageSettingsManager.getWorkspaceProvider(EXTENSION_EDITABLE_PROVIDER_ID); + ILanguageSettingsProvider rawProvider = LanguageSettingsManager.getRawProvider(provider); + assertNotSame(provider, rawProvider); + + // attempt to "replace" with workspace provider (which is a wrapper around raw provider), should be NOOP + List providers = new ArrayList(); + providers.add(provider); + LanguageSettingsManager.setWorkspaceProviders(providers); + ILanguageSettingsProvider newRawProvider = LanguageSettingsManager.getRawProvider(provider); + assertSame(rawProvider, newRawProvider); + + // check for no side effect + assertSame(provider, providers.get(0)); + } +} diff --git a/core/org.eclipse.cdt.core.tests/model/org/eclipse/cdt/core/language/settings/providers/LanguageSettingsPersistenceProjectTests.java b/core/org.eclipse.cdt.core.tests/model/org/eclipse/cdt/core/language/settings/providers/LanguageSettingsPersistenceProjectTests.java new file mode 100644 index 00000000000..ef7a1544b84 --- /dev/null +++ b/core/org.eclipse.cdt.core.tests/model/org/eclipse/cdt/core/language/settings/providers/LanguageSettingsPersistenceProjectTests.java @@ -0,0 +1,839 @@ +/******************************************************************************* + * Copyright (c) 2009 Andrew Gvozdev 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: + * Andrew Gvozdev - Initial API and implementation + *******************************************************************************/ + +package org.eclipse.cdt.core.language.settings.providers; + +import java.util.ArrayList; +import java.util.List; + +import junit.framework.TestCase; +import junit.framework.TestSuite; + +import org.eclipse.cdt.core.model.CoreModel; +import org.eclipse.cdt.core.settings.model.CIncludePathEntry; +import org.eclipse.cdt.core.settings.model.ICConfigurationDescription; +import org.eclipse.cdt.core.settings.model.ICLanguageSettingEntry; +import org.eclipse.cdt.core.settings.model.ICProjectDescription; +import org.eclipse.cdt.core.settings.model.ICProjectDescriptionManager; +import org.eclipse.cdt.core.testplugin.CModelMock; +import org.eclipse.cdt.core.testplugin.ResourceHelper; +import org.eclipse.cdt.internal.core.XmlUtil; +import org.eclipse.cdt.internal.core.language.settings.providers.LanguageSettingsProvidersSerializer; +import org.eclipse.cdt.internal.core.settings.model.CProjectDescriptionManager; +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IProject; +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +/** + * Test cases testing LanguageSettingsProvider functionality + */ +public class LanguageSettingsPersistenceProjectTests extends TestCase { + // Should match id of extension point defined in plugin.xml + private static final String EXTENSION_PROVIDER_ID = "org.eclipse.cdt.core.tests.language.settings.base.provider.subclass"; + private static final String EXTENSION_PROVIDER_NAME = "Test Plugin Base Provider Subclass"; + private static final String EXTENSION_SERIALIZABLE_PROVIDER_ID = "org.eclipse.cdt.core.tests.custom.serializable.language.settings.provider"; + + private static final String CFG_ID = "test.configuration.id.0"; + private static final String CFG_ID_2 = "test.configuration.id.2"; + private static final String PROVIDER_0 = "test.provider.0.id"; + private static final String PROVIDER_2 = "test.provider.2.id"; + private static final String PROVIDER_NAME_0 = "test.provider.0.name"; + private static final String PROVIDER_NAME_2 = "test.provider.2.name"; + private static final String PROVIDER_ID_WSP = "test.provider.workspace.id"; + private static final String PROVIDER_NAME_WSP = "test.provider.workspace.name"; + private static final String CUSTOM_PARAMETER = "custom parameter"; + private static final String ELEM_TEST = "test"; + + private static CoreModel coreModel = CoreModel.getDefault(); + + class MockConfigurationDescription extends CModelMock.DummyCConfigurationDescription { + List providers; + public MockConfigurationDescription(String id) { + super(id); + } + + @Override + public void setLanguageSettingProviders(List providers) { + this.providers = new ArrayList(providers); + } + + @Override + public List getLanguageSettingProviders() { + return providers; + } + } + class MockProjectDescription extends CModelMock.DummyCProjectDescription { + ICConfigurationDescription[] cfgDescriptions; + + public MockProjectDescription(ICConfigurationDescription[] cfgDescriptions) { + this.cfgDescriptions = cfgDescriptions; + } + + public MockProjectDescription(ICConfigurationDescription cfgDescription) { + this.cfgDescriptions = new ICConfigurationDescription[] { cfgDescription }; + } + + @Override + public ICConfigurationDescription[] getConfigurations() { + return cfgDescriptions; + + } + + @Override + public ICConfigurationDescription getConfigurationById(String id) { + for (ICConfigurationDescription cfgDescription : cfgDescriptions) { + if (cfgDescription.getId().equals(id)) + return cfgDescription; + } + return null; + } + } + + private class MockProvider extends LanguageSettingsSerializable { + public MockProvider(String id, String name) { + super(id, name); + } + } + + + /** + * Constructor. + * @param name - name of the test. + */ + public LanguageSettingsPersistenceProjectTests(String name) { + super(name); + + } + + @Override + protected void setUp() throws Exception { + } + + @Override + protected void tearDown() throws Exception { + LanguageSettingsManager.setWorkspaceProviders(null); + ResourceHelper.cleanUp(); + } + + /** + * @return - new TestSuite. + */ + public static TestSuite suite() { + return new TestSuite(LanguageSettingsPersistenceProjectTests.class); + } + + /** + * main function of the class. + * + * @param args - arguments + */ + public static void main(String[] args) { + junit.textui.TestRunner.run(suite()); + } + + private ICConfigurationDescription[] getConfigurationDescriptions(IProject project) { + ICProjectDescriptionManager mngr = coreModel.getProjectDescriptionManager(); + // project description + ICProjectDescription projectDescription = mngr.getProjectDescription(project); + assertNotNull(projectDescription); + assertEquals(1, projectDescription.getConfigurations().length); + // configuration description + ICConfigurationDescription[] cfgDescriptions = projectDescription.getConfigurations(); + assertNotNull(cfgDescriptions); + return cfgDescriptions; + } + + private ICConfigurationDescription getFirstConfigurationDescription(IProject project) { + ICConfigurationDescription[] cfgDescriptions = getConfigurationDescriptions(project); + + ICConfigurationDescription cfgDescription = cfgDescriptions[0]; + assertNotNull(cfgDescription); + + return cfgDescription; + } + + /** + */ + public void testWorkspacePersistence_ModifiedExtensionProvider() throws Exception { + List entries = new ArrayList(); + entries.add(new CIncludePathEntry("path0", 0)); + + { + // get the raw extension provider + ILanguageSettingsProvider provider = LanguageSettingsManager.getWorkspaceProvider(EXTENSION_SERIALIZABLE_PROVIDER_ID); + LanguageSettingsSerializable extProvider = (LanguageSettingsSerializable) LanguageSettingsManager.getRawProvider(provider); + assertNotNull(extProvider); + assertEquals(EXTENSION_SERIALIZABLE_PROVIDER_ID, extProvider.getId()); + + // add entries + extProvider.setSettingEntries(null, null, null, entries); + List actual = extProvider.getSettingEntries(null, null, null); + assertEquals(entries.get(0), actual.get(0)); + assertEquals(entries.size(), actual.size()); + + // serialize language settings of workspace providers + LanguageSettingsProvidersSerializer.serializeLanguageSettingsWorkspace(); + + // clear the provider + extProvider.setSettingEntries(null, null, null, null); + } + + { + // doublecheck it's clean + ILanguageSettingsProvider provider = LanguageSettingsManager.getWorkspaceProvider(EXTENSION_SERIALIZABLE_PROVIDER_ID); + List actual = provider.getSettingEntries(null, null, null); + assertNull(actual); + } + { + // re-load and check language settings of the provider + LanguageSettingsProvidersSerializer.loadLanguageSettingsWorkspace(); + + ILanguageSettingsProvider provider = LanguageSettingsManager.getWorkspaceProvider(EXTENSION_SERIALIZABLE_PROVIDER_ID); + assertEquals(EXTENSION_SERIALIZABLE_PROVIDER_ID, provider.getId()); + List actual = provider.getSettingEntries(null, null, null); + assertEquals(entries.get(0), actual.get(0)); + assertEquals(entries.size(), actual.size()); + } + } + + /** + */ + public void testWorkspacePersistence_GlobalProvider() throws Exception { + { + // get the raw extension provider + ILanguageSettingsProvider provider = LanguageSettingsManager.getWorkspaceProvider(EXTENSION_SERIALIZABLE_PROVIDER_ID); + LanguageSettingsSerializable rawProvider = (LanguageSettingsSerializable) LanguageSettingsManager.getRawProvider(provider); + assertNotNull(rawProvider); + assertEquals(EXTENSION_SERIALIZABLE_PROVIDER_ID, rawProvider.getId()); + + // customize provider + rawProvider.setCustomParameter(CUSTOM_PARAMETER); + assertEquals(CUSTOM_PARAMETER, rawProvider.getCustomParameter()); + } + { + // save workspace provider (as opposed to raw provider) + List providers = new ArrayList(); + ILanguageSettingsProvider provider = LanguageSettingsManager.getWorkspaceProvider(EXTENSION_SERIALIZABLE_PROVIDER_ID); + providers.add(provider); + LanguageSettingsManager.setWorkspaceProviders(providers); + } + { + // check that it has not cleared + ILanguageSettingsProvider provider = LanguageSettingsManager.getWorkspaceProvider(EXTENSION_SERIALIZABLE_PROVIDER_ID); + LanguageSettingsSerializable rawProvider = (LanguageSettingsSerializable) LanguageSettingsManager.getRawProvider(provider); + assertEquals(CUSTOM_PARAMETER, rawProvider.getCustomParameter()); + } + } + + /** + */ + public void testWorkspacePersistence_ShadowedExtensionProvider() throws Exception { + { + // get the raw extension provider + ILanguageSettingsProvider provider = LanguageSettingsManager.getWorkspaceProvider(EXTENSION_PROVIDER_ID); + ILanguageSettingsProvider rawProvider = LanguageSettingsManager.getRawProvider(provider); + // confirm its type and name + assertTrue(rawProvider instanceof LanguageSettingsBaseProvider); + assertEquals(EXTENSION_PROVIDER_ID, rawProvider.getId()); + assertEquals(EXTENSION_PROVIDER_NAME, rawProvider.getName()); + } + { + // replace extension provider + ILanguageSettingsProvider provider = new MockLanguageSettingsSerializableProvider(EXTENSION_PROVIDER_ID, PROVIDER_NAME_0); + List providers = new ArrayList(); + providers.add(provider); + // note that this will also serialize workspace providers + LanguageSettingsManager.setWorkspaceProviders(providers); + } + { + // doublecheck it's in the list + ILanguageSettingsProvider provider = LanguageSettingsManager.getWorkspaceProvider(EXTENSION_PROVIDER_ID); + ILanguageSettingsProvider rawProvider = LanguageSettingsManager.getRawProvider(provider); + assertTrue(rawProvider instanceof MockLanguageSettingsSerializableProvider); + assertEquals(EXTENSION_PROVIDER_ID, rawProvider.getId()); + assertEquals(PROVIDER_NAME_0, rawProvider.getName()); + } + + { + // re-load to check serialization + LanguageSettingsProvidersSerializer.loadLanguageSettingsWorkspace(); + + ILanguageSettingsProvider provider = LanguageSettingsManager.getWorkspaceProvider(EXTENSION_PROVIDER_ID); + ILanguageSettingsProvider rawProvider = LanguageSettingsManager.getRawProvider(provider); + assertTrue(rawProvider instanceof MockLanguageSettingsSerializableProvider); + assertEquals(EXTENSION_PROVIDER_ID, rawProvider.getId()); + assertEquals(PROVIDER_NAME_0, rawProvider.getName()); + } + + { + // reset workspace providers, that will also serialize + LanguageSettingsManager.setWorkspaceProviders(null); + } + { + // doublecheck original one is in the list + ILanguageSettingsProvider provider = LanguageSettingsManager.getWorkspaceProvider(EXTENSION_PROVIDER_ID); + ILanguageSettingsProvider rawProvider = LanguageSettingsManager.getRawProvider(provider); + assertTrue(rawProvider instanceof LanguageSettingsBaseProvider); + assertEquals(EXTENSION_PROVIDER_ID, rawProvider.getId()); + assertEquals(EXTENSION_PROVIDER_NAME, rawProvider.getName()); + } + { + // re-load to check serialization + LanguageSettingsProvidersSerializer.loadLanguageSettingsWorkspace(); + + ILanguageSettingsProvider provider = LanguageSettingsManager.getWorkspaceProvider(EXTENSION_PROVIDER_ID); + ILanguageSettingsProvider rawProvider = LanguageSettingsManager.getRawProvider(provider); + assertTrue(rawProvider instanceof LanguageSettingsBaseProvider); + assertEquals(EXTENSION_PROVIDER_ID, rawProvider.getId()); + assertEquals(EXTENSION_PROVIDER_NAME, rawProvider.getName()); + } + } + + /** + */ + public void testProjectPersistence_SerializableProviderDOM() throws Exception { + Element rootElement = null; + + List entries = new ArrayList(); + entries.add(new CIncludePathEntry("path0", 0)); + + { + // create a provider + MockProjectDescription mockPrjDescription = new MockProjectDescription(new MockConfigurationDescription(CFG_ID)); + + ICConfigurationDescription[] cfgDescriptions = mockPrjDescription.getConfigurations(); + ICConfigurationDescription cfgDescription = cfgDescriptions[0]; + assertNotNull(cfgDescription); + + LanguageSettingsSerializable serializableProvider = new LanguageSettingsSerializable(PROVIDER_0, PROVIDER_NAME_0); + serializableProvider.setSettingEntries(null, null, null, entries); + + ArrayList providers = new ArrayList(); + providers.add(serializableProvider); + cfgDescription.setLanguageSettingProviders(providers); + + // prepare DOM storage + Document doc = XmlUtil.newDocument(); + rootElement = XmlUtil.appendElement(doc, ELEM_TEST); + // serialize language settings to the DOM + LanguageSettingsProvidersSerializer.serializeLanguageSettings(rootElement, mockPrjDescription); + } + { + // re-load and check language settings of the newly loaded provider + MockProjectDescription mockPrjDescription = new MockProjectDescription(new MockConfigurationDescription(CFG_ID)); + LanguageSettingsProvidersSerializer.loadLanguageSettings(rootElement, mockPrjDescription); + + ICConfigurationDescription[] cfgDescriptions = mockPrjDescription.getConfigurations(); + assertNotNull(cfgDescriptions); + assertEquals(1, cfgDescriptions.length); + ICConfigurationDescription cfgDescription = cfgDescriptions[0]; + assertNotNull(cfgDescription); + + List providers = cfgDescription.getLanguageSettingProviders(); + assertNotNull(providers); + assertEquals(1, providers.size()); + ILanguageSettingsProvider provider = providers.get(0); + assertTrue(provider instanceof LanguageSettingsSerializable); + + List actual = provider.getSettingEntries(null, null, null); + assertEquals(entries.get(0), actual.get(0)); + assertEquals(entries.size(), actual.size()); + } + } + + /** + */ + public void testProjectPersistence_TwoConfigurationsDOM() throws Exception { + Element rootElement = null; + + List entries = new ArrayList(); + entries.add(new CIncludePathEntry("path0", 0)); + List entries2 = new ArrayList(); + entries2.add(new CIncludePathEntry("path2", 0)); + + { + // create a project description with 2 configuration descriptions + MockProjectDescription mockPrjDescription = new MockProjectDescription( + new MockConfigurationDescription[] { + new MockConfigurationDescription(CFG_ID), + new MockConfigurationDescription(CFG_ID_2), + }); + { + ICConfigurationDescription[] cfgDescriptions = mockPrjDescription.getConfigurations(); + assertNotNull(cfgDescriptions); + assertEquals(2, cfgDescriptions.length); + { + // populate configuration 1 with provider + ICConfigurationDescription cfgDescription1 = cfgDescriptions[0]; + assertNotNull(cfgDescription1); + assertEquals(CFG_ID, cfgDescription1.getId()); + LanguageSettingsSerializable provider1 = new LanguageSettingsSerializable(PROVIDER_0, PROVIDER_NAME_0); + provider1.setSettingEntries(null, null, null, entries); + ArrayList providers = new ArrayList(); + providers.add(provider1); + cfgDescription1.setLanguageSettingProviders(providers); + } + { + // populate configuration 2 with provider + ICConfigurationDescription cfgDescription2 = cfgDescriptions[1]; + assertNotNull(cfgDescription2); + assertEquals(CFG_ID_2, cfgDescription2.getId()); + LanguageSettingsSerializable provider2 = new LanguageSettingsSerializable(PROVIDER_0, PROVIDER_NAME_0); + provider2.setSettingEntries(null, null, null, entries2); + ArrayList providers = new ArrayList(); + providers.add(provider2); + cfgDescription2.setLanguageSettingProviders(providers); + } + } + + { + // doublecheck both configuration descriptions + ICConfigurationDescription[] cfgDescriptions = mockPrjDescription.getConfigurations(); + assertNotNull(cfgDescriptions); + assertEquals(2, cfgDescriptions.length); + { + // doublecheck configuration 1 + ICConfigurationDescription cfgDescription1 = cfgDescriptions[0]; + assertNotNull(cfgDescription1); + List providers = cfgDescription1.getLanguageSettingProviders(); + assertNotNull(providers); + assertEquals(1, providers.size()); + ILanguageSettingsProvider provider = providers.get(0); + assertNotNull(provider); + List actual = provider.getSettingEntries(null, null, null); + assertEquals(entries.get(0), actual.get(0)); + assertEquals(entries.size(), actual.size()); + } + { + // doublecheck configuration 2 + ICConfigurationDescription cfgDescription2 = cfgDescriptions[1]; + assertNotNull(cfgDescription2); + List providers = cfgDescription2.getLanguageSettingProviders(); + assertNotNull(providers); + assertEquals(1, providers.size()); + ILanguageSettingsProvider provider = providers.get(0); + assertNotNull(provider); + List actual2 = provider.getSettingEntries(null, null, null); + assertEquals(entries2.get(0), actual2.get(0)); + assertEquals(entries2.size(), actual2.size()); + } + } + + // prepare DOM storage + Document doc = XmlUtil.newDocument(); + rootElement = XmlUtil.appendElement(doc, ELEM_TEST); + // serialize language settings to the DOM + LanguageSettingsProvidersSerializer.serializeLanguageSettings(rootElement, mockPrjDescription); + } + { + // re-create a project description and re-load language settings for each configuration + MockProjectDescription mockPrjDescription = new MockProjectDescription( + new MockConfigurationDescription[] { + new MockConfigurationDescription(CFG_ID), + new MockConfigurationDescription(CFG_ID_2), + }); + // load + LanguageSettingsProvidersSerializer.loadLanguageSettings(rootElement, mockPrjDescription); + + ICConfigurationDescription[] cfgDescriptions = mockPrjDescription.getConfigurations(); + assertNotNull(cfgDescriptions); + assertEquals(2, cfgDescriptions.length); + { + // check configuration 1 + ICConfigurationDescription cfgDescription1 = cfgDescriptions[0]; + assertNotNull(cfgDescription1); + List providers = cfgDescription1.getLanguageSettingProviders(); + assertNotNull(providers); + assertEquals(1, providers.size()); + ILanguageSettingsProvider provider = providers.get(0); + assertNotNull(provider); + List actual = provider.getSettingEntries(null, null, null); + assertEquals(entries.get(0), actual.get(0)); + assertEquals(entries.size(), actual.size()); + } + { + // check configuration 2 + ICConfigurationDescription cfgDescription2 = cfgDescriptions[1]; + assertNotNull(cfgDescription2); + List providers = cfgDescription2.getLanguageSettingProviders(); + assertNotNull(providers); + assertEquals(1, providers.size()); + ILanguageSettingsProvider provider = providers.get(0); + assertNotNull(provider); + List actual2 = provider.getSettingEntries(null, null, null); + assertEquals(entries2.get(0), actual2.get(0)); + assertEquals(entries2.size(), actual2.size()); + } + } + } + + /** + */ + public void testProjectPersistence_SubclassedSerializableProviderDOM() throws Exception { + Element rootElement = null; + + List entries = new ArrayList(); + entries.add(new CIncludePathEntry("path0", 0)); + + { + // create a provider + MockProjectDescription mockPrjDescription = new MockProjectDescription(new MockConfigurationDescription(CFG_ID)); + + ICConfigurationDescription[] cfgDescriptions = mockPrjDescription.getConfigurations(); + ICConfigurationDescription cfgDescription = cfgDescriptions[0]; + assertNotNull(cfgDescription); + + LanguageSettingsSerializable serializableProvider = new MockLanguageSettingsSerializableProvider(PROVIDER_0, PROVIDER_NAME_0); + serializableProvider.setSettingEntries(null, null, null, entries); + + ArrayList providers = new ArrayList(); + providers.add(serializableProvider); + cfgDescription.setLanguageSettingProviders(providers); + + // prepare DOM storage + Document doc = XmlUtil.newDocument(); + rootElement = XmlUtil.appendElement(doc, ELEM_TEST); + // serialize language settings to the DOM + LanguageSettingsProvidersSerializer.serializeLanguageSettings(rootElement, mockPrjDescription); + } + { + // re-load and check language settings of the newly loaded provider + MockProjectDescription mockPrjDescription = new MockProjectDescription(new MockConfigurationDescription(CFG_ID)); + LanguageSettingsProvidersSerializer.loadLanguageSettings(rootElement, mockPrjDescription); + + ICConfigurationDescription[] cfgDescriptions = mockPrjDescription.getConfigurations(); + assertNotNull(cfgDescriptions); + assertEquals(1, cfgDescriptions.length); + ICConfigurationDescription cfgDescription = cfgDescriptions[0]; + assertNotNull(cfgDescription); + + List providers = cfgDescription.getLanguageSettingProviders(); + assertNotNull(providers); + assertEquals(1, providers.size()); + ILanguageSettingsProvider provider = providers.get(0); + assertTrue(provider instanceof MockLanguageSettingsSerializableProvider); + + List actual = provider.getSettingEntries(null, null, null); + assertEquals(entries.get(0), actual.get(0)); + assertEquals(entries.size(), actual.size()); + } + } + + /** + */ + public void testProjectPersistence_ReferenceExtensionProviderDOM() throws Exception { + Element rootElement = null; + + // provider of other type (not LanguageSettingsSerializable) defined as an extension + ILanguageSettingsProvider providerExt = LanguageSettingsManager.getWorkspaceProvider(EXTENSION_PROVIDER_ID); + + { + // create cfg description + MockProjectDescription mockPrjDescription = new MockProjectDescription(new MockConfigurationDescription(CFG_ID)); + ICConfigurationDescription[] cfgDescriptions = mockPrjDescription.getConfigurations(); + ICConfigurationDescription cfgDescription = cfgDescriptions[0]; + assertNotNull(cfgDescription); + + // populate with provider defined as extension + List providers = new ArrayList(); + providers.add(providerExt); + cfgDescription.setLanguageSettingProviders(providers); + + // prepare DOM storage + Document doc = XmlUtil.newDocument(); + rootElement = XmlUtil.appendElement(doc, ELEM_TEST); + // serialize language settings to the DOM + LanguageSettingsProvidersSerializer.serializeLanguageSettings(rootElement, mockPrjDescription); + } + { + // re-load + MockProjectDescription mockPrjDescription = new MockProjectDescription(new MockConfigurationDescription(CFG_ID)); + LanguageSettingsProvidersSerializer.loadLanguageSettings(rootElement, mockPrjDescription); + + ICConfigurationDescription[] cfgDescriptions = mockPrjDescription.getConfigurations(); + assertNotNull(cfgDescriptions); + assertEquals(1, cfgDescriptions.length); + ICConfigurationDescription cfgDescription = cfgDescriptions[0]; + assertNotNull(cfgDescription); + + // and check the newly loaded provider which should be workspace provider + List providers = cfgDescription.getLanguageSettingProviders(); + assertNotNull(providers); + assertEquals(1, providers.size()); + ILanguageSettingsProvider provider = providers.get(0); + assertNotNull(provider); + assertTrue(LanguageSettingsManager.isWorkspaceProvider(provider)); + } + } + + /** + */ + public void testProjectPersistence_OverrideExtensionProviderDOM() throws Exception { + Element rootElement = null; + + // provider set on workspace level overriding an extension + String idExt = EXTENSION_PROVIDER_ID; + ILanguageSettingsProvider providerExt = LanguageSettingsManager.getWorkspaceProvider(idExt); + assertNotNull(providerExt); + { + // create cfg description + MockProjectDescription mockPrjDescription = new MockProjectDescription(new MockConfigurationDescription(CFG_ID)); + ICConfigurationDescription[] cfgDescriptions = mockPrjDescription.getConfigurations(); + ICConfigurationDescription cfgDescription = cfgDescriptions[0]; + assertNotNull(cfgDescription); + + // populate with provider overriding the extension (must be SerializableLanguageSettingsProvider or a class from another extension) + ILanguageSettingsProvider providerOverride = new MockLanguageSettingsSerializableProvider(idExt, PROVIDER_NAME_0); + List providers = new ArrayList(); + providers.add(providerOverride); + cfgDescription.setLanguageSettingProviders(providers); + + + // prepare DOM storage + Document doc = XmlUtil.newDocument(); + rootElement = XmlUtil.appendElement(doc, ELEM_TEST); + // serialize language settings to the DOM + LanguageSettingsProvidersSerializer.serializeLanguageSettings(rootElement, mockPrjDescription); + } + { + // re-load + MockProjectDescription mockPrjDescription = new MockProjectDescription(new MockConfigurationDescription(CFG_ID)); + LanguageSettingsProvidersSerializer.loadLanguageSettings(rootElement, mockPrjDescription); + + ICConfigurationDescription[] cfgDescriptions = mockPrjDescription.getConfigurations(); + assertNotNull(cfgDescriptions); + assertEquals(1, cfgDescriptions.length); + ICConfigurationDescription cfgDescription = cfgDescriptions[0]; + assertNotNull(cfgDescription); + + // check the newly loaded provider + List providers = cfgDescription.getLanguageSettingProviders(); + assertNotNull(providers); + assertEquals(1, providers.size()); + ILanguageSettingsProvider provider = providers.get(0); + assertNotNull(provider); + assertTrue(provider instanceof MockLanguageSettingsSerializableProvider); + assertEquals(idExt, provider.getId()); + assertEquals(PROVIDER_NAME_0, provider.getName()); + } + } + + + /** + */ + public void testProjectPersistence_MixedProvidersDOM() throws Exception { + Element rootElement = null; + + List entries_31 = new ArrayList(); + entries_31.add(new CIncludePathEntry("path0", 0)); + + List entries_32 = new ArrayList(); + entries_32.add(new CIncludePathEntry("path2", 0)); + + ILanguageSettingsProvider providerExt; + ILanguageSettingsProvider providerWsp; + { + // Define providers a bunch + MockProjectDescription mockPrjDescription = new MockProjectDescription(new MockConfigurationDescription(CFG_ID)); + { + ICConfigurationDescription[] cfgDescriptions = mockPrjDescription.getConfigurations(); + ICConfigurationDescription cfgDescription = cfgDescriptions[0]; + assertNotNull(cfgDescription); + + // 1. Provider reference to extension from plugin.xml + providerExt = LanguageSettingsManager.getWorkspaceProvider(EXTENSION_PROVIDER_ID); + + // 2. TODO Provider reference to provider defined in the project + + // 3. Providers defined in a configuration + // 3.1 + LanguageSettingsSerializable mockProvider1 = new LanguageSettingsSerializable(PROVIDER_0, PROVIDER_NAME_0); + mockProvider1.setSettingEntries(null, null, null, entries_31); + // 3.2 + LanguageSettingsSerializable mockProvider2 = new MockLanguageSettingsSerializableProvider(PROVIDER_2, PROVIDER_NAME_2); + mockProvider2.setSettingEntries(null, null, null, entries_32); + + ArrayList providers = new ArrayList(); + providers.add(providerExt); + providers.add(mockProvider1); + providers.add(mockProvider2); + cfgDescription.setLanguageSettingProviders(providers); + } + + // prepare DOM storage + Document doc = XmlUtil.newDocument(); + rootElement = XmlUtil.appendElement(doc, ELEM_TEST); + // serialize language settings to the DOM + LanguageSettingsProvidersSerializer.serializeLanguageSettings(rootElement, mockPrjDescription); + XmlUtil.toString(doc); + } + { + // re-load and check language settings of the newly loaded provider + MockProjectDescription mockPrjDescription = new MockProjectDescription(new MockConfigurationDescription(CFG_ID)); + LanguageSettingsProvidersSerializer.loadLanguageSettings(rootElement, mockPrjDescription); + + ICConfigurationDescription[] cfgDescriptions = mockPrjDescription.getConfigurations(); + assertNotNull(cfgDescriptions); + assertEquals(1, cfgDescriptions.length); + ICConfigurationDescription cfgDescription = cfgDescriptions[0]; + + List providers = cfgDescription.getLanguageSettingProviders(); + assertNotNull(providers); + // 1. Provider reference to extension from plugin.xml + ILanguageSettingsProvider provider0 = providers.get(0); + assertTrue(LanguageSettingsManager.isWorkspaceProvider(provider0)); + + // 2. TODO Provider reference to provider defined in the project + + // 3. Providers defined in a configuration + // 3.1 + { + ILanguageSettingsProvider provider1 = providers.get(1); + assertTrue(provider1 instanceof LanguageSettingsSerializable); + List actual = provider1.getSettingEntries(null, null, null); + assertEquals(entries_31.get(0), actual.get(0)); + assertEquals(entries_31.size(), actual.size()); + } + // 3.2 + { + ILanguageSettingsProvider provider2 = providers.get(2); + assertTrue(provider2 instanceof MockLanguageSettingsSerializableProvider); + List actual = provider2.getSettingEntries(null, null, null); + assertEquals(entries_32.get(0), actual.get(0)); + assertEquals(entries_32.size(), actual.size()); + } + assertEquals(3, providers.size()); + } + } + + /** + */ + public void testProjectPersistence_RealProject() throws Exception { + IProject project = ResourceHelper.createCDTProjectWithConfig(this.getName()); + String xmlStorageFileLocation; + String xmlOutOfTheWay; + + List entries = new ArrayList(); + entries.add(new CIncludePathEntry("path0", 0)); + + { + // get project descriptions + ICProjectDescription writableProjDescription = coreModel.getProjectDescription(project); + assertNotNull(writableProjDescription); + ICConfigurationDescription[] cfgDescriptions = writableProjDescription.getConfigurations(); + assertEquals(1, cfgDescriptions.length); + ICConfigurationDescription cfgDescription = cfgDescriptions[0]; + + // create a provider + LanguageSettingsSerializable mockProvider = new LanguageSettingsSerializable(PROVIDER_0, PROVIDER_NAME_0); + mockProvider.setSettingEntries(cfgDescription, null, null, entries); + List providers = new ArrayList(); + providers.add(mockProvider); + cfgDescription.setLanguageSettingProviders(providers); + List storedProviders = cfgDescription.getLanguageSettingProviders(); + assertEquals(1, storedProviders.size()); + + // write to project description + coreModel.setProjectDescription(project, writableProjDescription); + IFile xmlStorageFile = project.getFile(".settings/language.settings.xml"); + assertTrue(xmlStorageFile.exists()); + xmlStorageFileLocation = xmlStorageFile.getLocation().toOSString(); + } + { + coreModel.getProjectDescription(project); + ICConfigurationDescription cfgDescription = getFirstConfigurationDescription(project); + List providers = cfgDescription.getLanguageSettingProviders(); + assertEquals(1, providers.size()); + ILanguageSettingsProvider provider = providers.get(0); + assertTrue(provider instanceof LanguageSettingsSerializable); + assertEquals(PROVIDER_0, provider.getId()); + assertEquals(PROVIDER_NAME_0, provider.getName()); + + List actual = provider.getSettingEntries(cfgDescription, null, null); + assertEquals(entries.get(0), actual.get(0)); + assertEquals(entries.size(), actual.size()); + } + { + // Move storage out of the way + java.io.File xmlFile = new java.io.File(xmlStorageFileLocation); + xmlOutOfTheWay = xmlStorageFileLocation+".out-of-the-way"; + java.io.File xmlFileOut = new java.io.File(xmlOutOfTheWay); + xmlFile.renameTo(xmlFileOut); + assertFalse(xmlFile.exists()); + assertTrue(xmlFileOut.exists()); + } + + { + // clear configuration + ICProjectDescription writableProjDescription = coreModel.getProjectDescription(project); + ICConfigurationDescription[] cfgDescriptions = writableProjDescription.getConfigurations(); + assertEquals(1, cfgDescriptions.length); + ICConfigurationDescription cfgDescription = cfgDescriptions[0]; + assertNotNull(cfgDescription); + + cfgDescription.setLanguageSettingProviders(new ArrayList()); + coreModel.setProjectDescription(project, writableProjDescription); + List providers = cfgDescription.getLanguageSettingProviders(); + assertEquals(0, providers.size()); + } + { + // re-check if it really took it + ICConfigurationDescription cfgDescription = getFirstConfigurationDescription(project); + List providers = cfgDescription.getLanguageSettingProviders(); + assertEquals(0, providers.size()); + } + { + // close the project + project.close(null); + } + { + // open to double-check the data is not kept in some other kind of cache + project.open(null); + ICConfigurationDescription cfgDescription = getFirstConfigurationDescription(project); + List providers = cfgDescription.getLanguageSettingProviders(); + assertEquals(0, providers.size()); + // and close + project.close(null); + } + + { + // Move storage back + java.io.File xmlFile = new java.io.File(xmlStorageFileLocation); + xmlFile.delete(); + assertFalse("File "+xmlFile+ " still exist", xmlFile.exists()); + java.io.File xmlFileOut = new java.io.File(xmlOutOfTheWay); + xmlFileOut.renameTo(xmlFile); + assertTrue("File "+xmlFile+ " does not exist", xmlFile.exists()); + assertFalse("File "+xmlFileOut+ " still exist", xmlFileOut.exists()); + } + + { + // Remove project from internal cache + CProjectDescriptionManager.getInstance().projectClosedRemove(project); + // open project and check if providers are loaded + project.open(null); + ICConfigurationDescription cfgDescription = getFirstConfigurationDescription(project); + List providers = cfgDescription.getLanguageSettingProviders(); + assertEquals(1, providers.size()); + ILanguageSettingsProvider loadedProvider = providers.get(0); + assertTrue(loadedProvider instanceof LanguageSettingsSerializable); + assertEquals(PROVIDER_0, loadedProvider.getId()); + assertEquals(PROVIDER_NAME_0, loadedProvider.getName()); + + List actual = loadedProvider.getSettingEntries(cfgDescription, null, null); + assertEquals(entries.get(0), actual.get(0)); + assertEquals(entries.size(), actual.size()); + } + } + + +} diff --git a/core/org.eclipse.cdt.core.tests/model/org/eclipse/cdt/core/language/settings/providers/LanguageSettingsScannerInfoProviderTests.java b/core/org.eclipse.cdt.core.tests/model/org/eclipse/cdt/core/language/settings/providers/LanguageSettingsScannerInfoProviderTests.java new file mode 100644 index 00000000000..5615a97bd41 --- /dev/null +++ b/core/org.eclipse.cdt.core.tests/model/org/eclipse/cdt/core/language/settings/providers/LanguageSettingsScannerInfoProviderTests.java @@ -0,0 +1,893 @@ +/******************************************************************************* + * Copyright (c) 2009, 2010 Andrew Gvozdev 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: + * Andrew Gvozdev - Initial API and implementation + *******************************************************************************/ + +package org.eclipse.cdt.core.language.settings.providers; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import junit.framework.TestCase; +import junit.framework.TestSuite; + +import org.eclipse.cdt.core.model.ILanguage; +import org.eclipse.cdt.core.model.LanguageManager; +import org.eclipse.cdt.core.parser.ExtendedScannerInfo; +import org.eclipse.cdt.core.settings.model.CIncludeFileEntry; +import org.eclipse.cdt.core.settings.model.CIncludePathEntry; +import org.eclipse.cdt.core.settings.model.CMacroEntry; +import org.eclipse.cdt.core.settings.model.CMacroFileEntry; +import org.eclipse.cdt.core.settings.model.ICConfigurationDescription; +import org.eclipse.cdt.core.settings.model.ICFolderDescription; +import org.eclipse.cdt.core.settings.model.ICLanguageSetting; +import org.eclipse.cdt.core.settings.model.ICLanguageSettingEntry; +import org.eclipse.cdt.core.settings.model.ICProjectDescription; +import org.eclipse.cdt.core.settings.model.ICSettingEntry; +import org.eclipse.cdt.core.testplugin.ResourceHelper; +import org.eclipse.cdt.internal.core.language.settings.providers.LanguageSettingsScannerInfoProvider; +import org.eclipse.cdt.internal.core.settings.model.CProjectDescriptionManager; +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IFolder; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.Path; + +/** + * Test cases testing LanguageSettingsProvider functionality + */ +public class LanguageSettingsScannerInfoProviderTests extends TestCase { + private static final IFile FAKE_FILE = ResourcesPlugin.getWorkspace().getRoot().getFile(new Path("/project/path0")); + private static final String PROVIDER_ID = "test.provider.id"; + private static final String PROVIDER_ID_2 = "test.provider.id.2"; + private static final String PROVIDER_NAME = "test.provider.name"; + + private class MockProvider extends LanguageSettingsBaseProvider implements ILanguageSettingsProvider { + private final List entries; + + public MockProvider(String id, String name, List entries) { + super(id, name); + this.entries = entries; + } + + @Override + public List getSettingEntries(ICConfigurationDescription cfgDescription, IResource rc, String languageId) { + return entries; + } + } + + /** + * Constructor. + * @param name - name of the test. + */ + public LanguageSettingsScannerInfoProviderTests(String name) { + super(name); + + } + + @Override + protected void setUp() throws Exception { + } + + @Override + protected void tearDown() throws Exception { + ResourceHelper.cleanUp(); + } + + /** + * @return - new TestSuite. + */ + public static TestSuite suite() { + return new TestSuite(LanguageSettingsScannerInfoProviderTests.class); + } + + /** + * main function of the class. + * + * @param args - arguments + */ + public static void main(String[] args) { + junit.textui.TestRunner.run(suite()); + } + + /** + * Sets build working directory for DefaultSettingConfiguration being tested. + */ + private void setBuilderCWD(IProject project, IPath buildCWD) throws CoreException { + CProjectDescriptionManager manager = CProjectDescriptionManager.getInstance(); + { + ICProjectDescription prjDescription = manager.getProjectDescription(project, true); + assertNotNull(prjDescription); + ICConfigurationDescription cfgDescription = prjDescription.getDefaultSettingConfiguration(); + assertNotNull(cfgDescription); + + cfgDescription.getBuildSetting().setBuilderCWD(buildCWD); + manager.setProjectDescription(project, prjDescription); + // doublecheck builderCWD + IPath actualBuildCWD = cfgDescription.getBuildSetting().getBuilderCWD(); + assertEquals(buildCWD, actualBuildCWD); + } + { + // triplecheck builderCWD for different project/configuration descriptions + ICProjectDescription prjDescription = CProjectDescriptionManager.getInstance().getProjectDescription(project, false); + assertNotNull(prjDescription); + ICConfigurationDescription cfgDescription = prjDescription.getDefaultSettingConfiguration(); + assertNotNull(cfgDescription); + + } + } + + /** + * Test cases when some objects are null. + */ + public void testNulls() throws Exception { + { + // Handle project==null + IResource root = ResourcesPlugin.getWorkspace().getRoot(); + assertNull(root.getProject()); + + LanguageSettingsScannerInfoProvider scannerInfoProvider = new LanguageSettingsScannerInfoProvider(); + ExtendedScannerInfo info = scannerInfoProvider.getScannerInformation(root); + assertEquals(0, info.getIncludePaths().length); + assertEquals(0, info.getDefinedSymbols().size()); + assertEquals(0, info.getIncludeFiles().length); + assertEquals(0, info.getMacroFiles().length); + assertEquals(0, info.getLocalIncludePath().length); + } + + { + // Handle prjDescription==null + IProject project = FAKE_FILE.getProject(); + ICProjectDescription prjDescription = CProjectDescriptionManager.getInstance().getProjectDescription(project, false); + assertNull(prjDescription); + + LanguageSettingsScannerInfoProvider scannerInfoProvider = new LanguageSettingsScannerInfoProvider(); + ExtendedScannerInfo info = scannerInfoProvider.getScannerInformation(FAKE_FILE); + assertEquals(0, info.getIncludePaths().length); + assertEquals(0, info.getDefinedSymbols().size()); + assertEquals(0, info.getIncludeFiles().length); + assertEquals(0, info.getMacroFiles().length); + assertEquals(0, info.getLocalIncludePath().length); + } + + { + // Handle language==null + LanguageSettingsScannerInfoProvider scannerInfoProvider = new LanguageSettingsScannerInfoProvider(); + IProject project = ResourceHelper.createCDTProjectWithConfig(getName()); + IFile file = ResourceHelper.createFile(project, "file"); + + ICProjectDescription prjDescription = CProjectDescriptionManager.getInstance().getProjectDescription(project, false); + assertNotNull(prjDescription); + ICConfigurationDescription cfgDescription = prjDescription.getDefaultSettingConfiguration(); + assertNotNull(cfgDescription); + ILanguage language = LanguageManager.getInstance().getLanguageForFile(file, cfgDescription); + assertNull(language); + + ExtendedScannerInfo info = scannerInfoProvider.getScannerInformation(file); + assertEquals(0, info.getIncludePaths().length); + assertEquals(0, info.getDefinedSymbols().size()); + assertEquals(0, info.getIncludeFiles().length); + assertEquals(0, info.getMacroFiles().length); + assertEquals(0, info.getLocalIncludePath().length); + } + } + + /** + * Test empty scanner info. + */ + public void testEmpty() throws Exception { + LanguageSettingsScannerInfoProvider scannerInfoProvider = new LanguageSettingsScannerInfoProvider(); + IProject project = ResourceHelper.createCDTProjectWithConfig(getName()); + IFile file = ResourceHelper.createFile(project, "file.c"); + + // confirm that language==null + ICProjectDescription prjDescription = CProjectDescriptionManager.getInstance().getProjectDescription(project, false); + assertNotNull(prjDescription); + ICConfigurationDescription cfgDescription = prjDescription.getDefaultSettingConfiguration(); + assertNotNull(cfgDescription); + ILanguage language = LanguageManager.getInstance().getLanguageForFile(file, cfgDescription); + assertNotNull(language); + + // test that the info is empty + ExtendedScannerInfo info = scannerInfoProvider.getScannerInformation(file); + assertEquals(0, info.getIncludePaths().length); + assertEquals(0, info.getDefinedSymbols().size()); + assertEquals(0, info.getIncludeFiles().length); + assertEquals(0, info.getMacroFiles().length); + assertEquals(0, info.getLocalIncludePath().length); + } + + /** + * Test regular cases. + */ + public void testRegular() throws Exception { + // create a project + IProject project = ResourceHelper.createCDTProjectWithConfig(getName()); + ICProjectDescription prjDescription = CProjectDescriptionManager.getInstance().getProjectDescription(project, false); + assertNotNull(prjDescription); + ICConfigurationDescription cfgDescription = prjDescription.getDefaultSettingConfiguration(); + assertNotNull(cfgDescription); + + // sample file + IFile file = ResourceHelper.createFile(project, "file.c"); + + // sanity test of language + ILanguage language = LanguageManager.getInstance().getLanguageForFile(file, cfgDescription); + assertNotNull(language); + + // contribute the entries + IFolder includeFolder = ResourceHelper.createFolder(project, "/include-path"); + IFolder includeLocalFolder = ResourceHelper.createFolder(project, "/local-include-path"); + IFile macroFile = ResourceHelper.createFile(project, "macro-file"); + IFile includeFile = ResourceHelper.createFile(project, "include-file"); + + CIncludePathEntry includePathEntry = new CIncludePathEntry(includeFolder, 0); + CIncludePathEntry includeLocalPathEntry = new CIncludePathEntry(includeLocalFolder, ICSettingEntry.LOCAL); // #include "..." + CMacroEntry macroEntry = new CMacroEntry("MACRO", "value",0); + CIncludeFileEntry includeFileEntry = new CIncludeFileEntry(includeFile, 0); + CMacroFileEntry macroFileEntry = new CMacroFileEntry(macroFile, 0); + + List entries = new ArrayList(); + entries.add(includePathEntry); + entries.add(includeLocalPathEntry); + entries.add(macroEntry); + entries.add(includeFileEntry); + entries.add(macroFileEntry); + + // add provider to the configuration + ILanguageSettingsProvider provider = new MockProvider(PROVIDER_ID, PROVIDER_NAME, entries); + List providers = new ArrayList(); + providers.add(provider); + cfgDescription.setLanguageSettingProviders(providers); + + // test that the scannerInfoProvider gets the entries + LanguageSettingsScannerInfoProvider scannerInfoProvider = new LanguageSettingsScannerInfoProvider(); + ExtendedScannerInfo info = scannerInfoProvider.getScannerInformation(file); + String[] actualIncludePaths = info.getIncludePaths(); + Map actualDefinedSymbols = info.getDefinedSymbols(); + String[] actualIncludeFiles = info.getIncludeFiles(); + String[] actualMacroFiles = info.getMacroFiles(); + String[] actualLocalIncludePath = info.getLocalIncludePath(); + // include paths + assertEquals(includeFolder.getLocation(), new Path(actualIncludePaths[0])); + assertEquals(1, actualIncludePaths.length); + // macros + assertEquals(macroEntry.getValue(), actualDefinedSymbols.get(macroEntry.getName())); + assertEquals(1, actualDefinedSymbols.size()); + // include file + assertEquals(includeFile.getLocation(), new Path(actualIncludeFiles[0])); + assertEquals(1, actualIncludeFiles.length); + // macro file + assertEquals(macroFile.getLocation(), new Path(actualMacroFiles[0])); + assertEquals(1, actualMacroFiles.length); + // local include files + assertEquals(includeLocalFolder.getLocation(), new Path(actualLocalIncludePath[0])); + assertEquals(1, actualLocalIncludePath.length); + } + + /** + * Test "local" flag (#include "..."). + */ + public void testLocal() throws Exception { + // create a project + IProject project = ResourceHelper.createCDTProjectWithConfig(getName()); + ICProjectDescription prjDescription = CProjectDescriptionManager.getInstance().getProjectDescription(project, false); + assertNotNull(prjDescription); + ICConfigurationDescription cfgDescription = prjDescription.getDefaultSettingConfiguration(); + assertNotNull(cfgDescription); + + // sample file + IFile file = ResourceHelper.createFile(project, "file.c"); + + // contribute the entries + IFolder incFolder = ResourceHelper.createFolder(project, "include"); + IFolder incFolder2 = ResourceHelper.createFolder(project, "include2"); + CIncludePathEntry includePathEntry = new CIncludePathEntry(incFolder, 0); + CIncludePathEntry includeLocalPathEntry = new CIncludePathEntry(incFolder, ICSettingEntry.LOCAL); // #include "..." + CIncludePathEntry includeLocalPathEntry2 = new CIncludePathEntry(incFolder2, ICSettingEntry.LOCAL); // #include "..." + CIncludePathEntry includePathEntry2 = new CIncludePathEntry(incFolder2, 0); + + List entries = new ArrayList(); + entries.add(includePathEntry); + entries.add(includeLocalPathEntry); + // reverse order for incPath2 + entries.add(includeLocalPathEntry2); + entries.add(includePathEntry2); + + // add provider to the configuration + ILanguageSettingsProvider provider = new MockProvider(PROVIDER_ID, PROVIDER_NAME, entries); + List providers = new ArrayList(); + providers.add(provider); + cfgDescription.setLanguageSettingProviders(providers); + + // test that the scannerInfoProvider gets the entries + LanguageSettingsScannerInfoProvider scannerInfoProvider = new LanguageSettingsScannerInfoProvider(); + ExtendedScannerInfo info = scannerInfoProvider.getScannerInformation(file); + String[] actualIncludePaths = info.getIncludePaths(); + String[] actualLocalIncludePath = info.getLocalIncludePath(); + // include paths + assertEquals(incFolder.getLocation(), new Path(actualIncludePaths[0])); + assertEquals(incFolder2.getLocation(), new Path(actualIncludePaths[1])); + assertEquals(2, actualIncludePaths.length); + // local include files + assertEquals(incFolder.getLocation(), new Path(actualLocalIncludePath[0])); + assertEquals(incFolder2.getLocation(), new Path(actualLocalIncludePath[1])); + assertEquals(2, actualLocalIncludePath.length); + } + + /** + * Test Mac frameworks. + */ + public void testFramework() throws Exception { + // create a project + IProject project = ResourceHelper.createCDTProjectWithConfig(getName()); + ICProjectDescription prjDescription = CProjectDescriptionManager.getInstance().getProjectDescription(project, false); + assertNotNull(prjDescription); + ICConfigurationDescription cfgDescription = prjDescription.getDefaultSettingConfiguration(); + assertNotNull(cfgDescription); + + // sample file + IFile file = ResourceHelper.createFile(project, "file.c"); + + // contribute the entries + IFolder frameworkFolder = ResourceHelper.createFolder(project, "Fmwk"); + CIncludePathEntry frameworkPathEntry = new CIncludePathEntry(frameworkFolder, ICSettingEntry.FRAMEWORKS_MAC); + + List entries = new ArrayList(); + entries.add(frameworkPathEntry); + + // add provider to the configuration + ILanguageSettingsProvider provider = new MockProvider(PROVIDER_ID, PROVIDER_NAME, entries); + List providers = new ArrayList(); + providers.add(provider); + cfgDescription.setLanguageSettingProviders(providers); + + // test that the scannerInfoProvider gets the entries + LanguageSettingsScannerInfoProvider scannerInfoProvider = new LanguageSettingsScannerInfoProvider(); + ExtendedScannerInfo info = scannerInfoProvider.getScannerInformation(file); + String[] actualIncludePaths = info.getIncludePaths(); + // include paths + assertEquals(frameworkFolder.getLocation().append("/__framework__.framework/Headers/__header__"), + new Path(actualIncludePaths[0])); + assertEquals(frameworkFolder.getLocation().append("/__framework__.framework/PrivateHeaders/__header__"), + new Path(actualIncludePaths[1])); + assertEquals(2, actualIncludePaths.length); + } + + /** + * Test duplicate entries. + */ + public void testDuplicate() throws Exception { + // create a project + IProject project = ResourceHelper.createCDTProjectWithConfig(getName()); + ICProjectDescription prjDescription = CProjectDescriptionManager.getInstance().getProjectDescription(project, false); + assertNotNull(prjDescription); + ICConfigurationDescription cfgDescription = prjDescription.getDefaultSettingConfiguration(); + assertNotNull(cfgDescription); + + // sample file + IFile file = ResourceHelper.createFile(project, "file.c"); + + // contribute the entries + IFolder incFolder = ResourceHelper.createFolder(project, "include"); + CIncludePathEntry includePathEntry = new CIncludePathEntry(incFolder, 0); + CIncludePathEntry includeLocalPathEntry = new CIncludePathEntry(incFolder, ICSettingEntry.LOCAL); // #include "..." + CIncludePathEntry includePathEntry2 = new CIncludePathEntry(incFolder, 0); + CIncludePathEntry includeLocalPathEntry2 = new CIncludePathEntry(incFolder, ICSettingEntry.LOCAL); // #include "..." + + List entries = new ArrayList(); + entries.add(includePathEntry); + entries.add(includeLocalPathEntry); + entries.add(includePathEntry2); + entries.add(includeLocalPathEntry2); + + // add provider to the configuration + ILanguageSettingsProvider provider = new MockProvider(PROVIDER_ID, PROVIDER_NAME, entries); + List providers = new ArrayList(); + providers.add(provider); + cfgDescription.setLanguageSettingProviders(providers); + + // test that the scannerInfoProvider gets the entries + LanguageSettingsScannerInfoProvider scannerInfoProvider = new LanguageSettingsScannerInfoProvider(); + ExtendedScannerInfo info = scannerInfoProvider.getScannerInformation(file); + String[] actualIncludePaths = info.getIncludePaths(); + String[] actualLocalIncludePath = info.getLocalIncludePath(); + // include paths + assertEquals(incFolder.getLocation(), new Path(actualIncludePaths[0])); + assertEquals(1, actualIncludePaths.length); + // local include files + assertEquals(incFolder.getLocation(), new Path(actualLocalIncludePath[0])); + assertEquals(1, actualLocalIncludePath.length); + } + + /** + * Test include path managed by eclipse as a workspace path. + */ + public void testWorkspacePath() throws Exception { + // create a project + IProject project = ResourceHelper.createCDTProjectWithConfig(getName()); + ICProjectDescription prjDescription = CProjectDescriptionManager.getInstance().getProjectDescription(project, false); + assertNotNull(prjDescription); + ICConfigurationDescription cfgDescription = prjDescription.getDefaultSettingConfiguration(); + assertNotNull(cfgDescription); + + // create sample file + IFile file = ResourceHelper.createFile(project, "file.c"); + // eclipse-managed folder in workspace + IFolder incWorkspace_1 = ResourceHelper.createFolder(project, "include_1"); + IPath incWorkspaceLocation_1 = incWorkspace_1.getLocation(); + IFolder incWorkspace_2 = ResourceHelper.createFolder(project, "include_2"); + IPath incWorkspacePath_2 = incWorkspace_2.getFullPath(); + IPath incWorkspaceLocation_2 = incWorkspace_2.getLocation(); + IFolder incWorkspace_3 = ResourceHelper.createFolder(project, "include_3"); + // "relative" should make no difference for VALUE_WORKSPACE_PATH + IPath incWorkspaceRelativePath_3 = incWorkspace_3.getFullPath().makeRelative(); + IPath incWorkspaceLocation_3 = incWorkspace_3.getLocation(); + // folder defined by absolute path on the filesystem + IPath incFilesystem = ResourceHelper.createWorkspaceFolder("includeFilesystem"); + + // contribute the entries + CIncludePathEntry incWorkspaceEntry_1 = new CIncludePathEntry(incWorkspace_1, 0); + CIncludePathEntry incWorkspaceEntry_2 = new CIncludePathEntry(incWorkspacePath_2, ICSettingEntry.VALUE_WORKSPACE_PATH | ICSettingEntry.RESOLVED); + CIncludePathEntry incWorkspaceEntry_3 = new CIncludePathEntry(incWorkspaceRelativePath_3, ICSettingEntry.VALUE_WORKSPACE_PATH | ICSettingEntry.RESOLVED); + CIncludePathEntry incFilesystemEntry = new CIncludePathEntry(incFilesystem, 0); + + List entries = new ArrayList(); + entries.add(incWorkspaceEntry_1); + entries.add(incWorkspaceEntry_2); + entries.add(incWorkspaceEntry_3); + entries.add(incFilesystemEntry); + + // add provider to the configuration + ILanguageSettingsProvider provider = new MockProvider(PROVIDER_ID, PROVIDER_NAME, entries); + List providers = new ArrayList(); + providers.add(provider); + cfgDescription.setLanguageSettingProviders(providers); + + // test the entries received from the scannerInfoProvider + LanguageSettingsScannerInfoProvider scannerInfoProvider = new LanguageSettingsScannerInfoProvider(); + ExtendedScannerInfo info = scannerInfoProvider.getScannerInformation(file); + String[] actualIncludePaths = info.getIncludePaths(); + + assertEquals(incWorkspaceLocation_1, new Path(actualIncludePaths[0])); + assertEquals(incWorkspaceLocation_2, new Path(actualIncludePaths[1])); + assertEquals(incWorkspaceLocation_3, new Path(actualIncludePaths[2])); + assertEquals(incFilesystem, new Path(actualIncludePaths[3])); + assertEquals(4, actualIncludePaths.length); + + } + + /** + * Confirm that device letter is prepended on filesystems that support that. + */ + public void testFilesystemPathNoDriveLetter() throws Exception { + // create a project + IProject project = ResourceHelper.createCDTProjectWithConfig(getName()); + // change drive on build working directory + String buildCwdDevice = project.getLocation().getDevice(); + +// // Test manually with a device which is different from project location device (path should exist) +// IPath buildCWD = new Path("D:/build/path"); +// String buildCwdDevice = buildCWD.getDevice(); + + // get project/configuration descriptions + ICProjectDescription prjDescription = CProjectDescriptionManager.getInstance().getProjectDescription(project, false); + assertNotNull(prjDescription); + ICConfigurationDescription cfgDescription = prjDescription.getDefaultSettingConfiguration(); + assertNotNull(cfgDescription); + + // create sample file + IFile file = ResourceHelper.createFile(project, "file.c"); + + // contribute the entries + // no-drive-letter folder defined by absolute path on the filesystem + IPath incFilesystem = ResourceHelper.createWorkspaceFolder("includeFilesystem").setDevice(null); + CIncludePathEntry incFilesystemEntry = new CIncludePathEntry(incFilesystem, 0); + List entries = new ArrayList(); + entries.add(incFilesystemEntry); + + // add provider to the configuration + ILanguageSettingsProvider provider = new MockProvider(PROVIDER_ID, PROVIDER_NAME, entries); + List providers = new ArrayList(); + providers.add(provider); + cfgDescription.setLanguageSettingProviders(providers); + + // test the entries received from the scannerInfoProvider + LanguageSettingsScannerInfoProvider scannerInfoProvider = new LanguageSettingsScannerInfoProvider(); + ExtendedScannerInfo info = scannerInfoProvider.getScannerInformation(file); + String[] actualIncludePaths = info.getIncludePaths(); + + IPath expectedInclude = incFilesystem.setDevice(buildCwdDevice); + assertEquals(expectedInclude, new Path(actualIncludePaths[0])); + assertEquals(1, actualIncludePaths.length); + } + + /** + * Test relative paths. + */ + public void testRelativePath() throws Exception { + // create a project + String prjName = getName(); + IProject project = ResourceHelper.createCDTProjectWithConfig(prjName); + String relativePath = "include"; + IFolder buildFolder = ResourceHelper.createFolder(project, "buildDir"); + IFolder relativeFolder = ResourceHelper.createFolder(project, "buildDir/"+relativePath); + IFolder relativeFolderProjName = ResourceHelper.createFolder(project, "buildDir/"+prjName); + String markedResolved = "-MarkedResolved"; + IFolder relativeFolderProjNameResolved = ResourceHelper.createFolder(project, "buildDir/" + prjName+markedResolved); + IPath buildCWD=buildFolder.getLocation(); + setBuilderCWD(project, buildCWD); + + // get project/configuration descriptions + ICProjectDescription prjDescription = CProjectDescriptionManager.getInstance().getProjectDescription(project, false); + assertNotNull(prjDescription); + ICConfigurationDescription cfgDescription = prjDescription.getDefaultSettingConfiguration(); + assertNotNull(cfgDescription); + + // create sample file + IFile file = ResourceHelper.createFile(project, "file.c"); + + // contribute the entries + CIncludePathEntry incRelativeEntry = new CIncludePathEntry(new Path(relativePath), 0); + CIncludePathEntry incProjNameEntry = new CIncludePathEntry(new Path("${ProjName}"), 0); + CIncludePathEntry incProjNameMarkedResolvedEntry = new CIncludePathEntry(new Path("${ProjName}"+markedResolved), ICSettingEntry.RESOLVED); + List entries = new ArrayList(); + entries.add(incRelativeEntry); + entries.add(incProjNameEntry); + entries.add(incProjNameMarkedResolvedEntry); + + // add provider to the configuration + ILanguageSettingsProvider provider = new MockProvider(PROVIDER_ID, PROVIDER_NAME, entries); + List providers = new ArrayList(); + providers.add(provider); + cfgDescription.setLanguageSettingProviders(providers); + + // test the entries received from the scannerInfoProvider + LanguageSettingsScannerInfoProvider scannerInfoProvider = new LanguageSettingsScannerInfoProvider(); + ExtendedScannerInfo info = scannerInfoProvider.getScannerInformation(file); + String[] actualIncludePaths = info.getIncludePaths(); + + // pair of entries, one from build dir another relative path + assertEquals(relativeFolder.getLocation(), new Path(actualIncludePaths[0])); + assertEquals(new Path(relativePath), new Path(actualIncludePaths[1])); + + // pair of entries, one resolved from build dir another expanded relative path + assertEquals(relativeFolderProjName.getLocation(), new Path(actualIncludePaths[2])); + assertEquals(new Path(prjName), new Path(actualIncludePaths[3])); + + // if marked RESOLVED only that path stays + assertEquals(new Path("${ProjName}"+markedResolved), new Path(actualIncludePaths[4])); + + assertEquals(5, actualIncludePaths.length); + } + + /** + * Test relative paths - some combinations of dot paths. + */ + public void testRelativePathWithDots() throws Exception { + // create a project + IProject project = ResourceHelper.createCDTProjectWithConfig(getName()); + // set build CWD + IFolder buildFolder = ResourceHelper.createFolder(project, "buildDir"); + IPath buildCWD=buildFolder.getLocation(); + setBuilderCWD(project, buildCWD); + + // define a few variations of paths + String relativePath_dot = "."; + String relativePath_dot_slash = "./"; + String relativePath_dot_slash_path = "./include"; + IFolder relativeFolder_dot_slash_path = ResourceHelper.createFolder(project, "buildDir/include"); + String relativePath_dotdot = ".."; + String relativePath_dotdot_slash = "../"; + String relativePath_dotdot_slash_path = "../include"; + IFolder relativeFolder_dotdot_slash_path = ResourceHelper.createFolder(project, "include"); + String locationPath_dotdot_path = buildCWD.toString()+"/../include2"; + IFolder incFolder_dotdot_slash_path = ResourceHelper.createFolder(project, "include2"); // "/ProjPath/buildDir/../include2" + + // get project/configuration descriptions + ICProjectDescription prjDescription = CProjectDescriptionManager.getInstance().getProjectDescription(project, false); + assertNotNull(prjDescription); + ICConfigurationDescription cfgDescription = prjDescription.getDefaultSettingConfiguration(); + assertNotNull(cfgDescription); + + // create sample file + IFile file = ResourceHelper.createFile(project, "file.c"); + + // contribute the entries + CIncludePathEntry incRelativeEntry_dot = new CIncludePathEntry(new Path(relativePath_dot), 0); + CIncludePathEntry incRelativeEntry_dot_slash_path = new CIncludePathEntry(new Path(relativePath_dot_slash_path), 0); + CIncludePathEntry incRelativeEntry_dotdot = new CIncludePathEntry(new Path(relativePath_dotdot), 0); + CIncludePathEntry incRelativeEntry_dotdot_slash_path = new CIncludePathEntry(new Path(relativePath_dotdot_slash_path), 0); + CIncludePathEntry incEntry_dotdot_path = new CIncludePathEntry(locationPath_dotdot_path, 0); + // use LOCAL flag not to clash with plain dot entries + CIncludePathEntry incRelativeEntry_dotdot_slash = new CIncludePathEntry(new Path(relativePath_dotdot_slash), ICSettingEntry.LOCAL); + CIncludePathEntry incRelativeEntry_dot_slash = new CIncludePathEntry(new Path(relativePath_dot_slash), ICSettingEntry.LOCAL); + + List entries = new ArrayList(); + entries.add(incRelativeEntry_dot); + entries.add(incRelativeEntry_dot_slash); + entries.add(incRelativeEntry_dot_slash_path); + entries.add(incRelativeEntry_dotdot); + entries.add(incRelativeEntry_dotdot_slash); + entries.add(incRelativeEntry_dotdot_slash_path); + entries.add(incEntry_dotdot_path); + + // add provider to the configuration + ILanguageSettingsProvider provider = new MockProvider(PROVIDER_ID, PROVIDER_NAME, entries); + List providers = new ArrayList(); + providers.add(provider); + cfgDescription.setLanguageSettingProviders(providers); + + // test the entries received from the scannerInfoProvider + LanguageSettingsScannerInfoProvider scannerInfoProvider = new LanguageSettingsScannerInfoProvider(); + ExtendedScannerInfo info = scannerInfoProvider.getScannerInformation(file); + String[] actualIncludePaths = info.getIncludePaths(); + String[] actualLocalIncludePaths = info.getLocalIncludePath(); + + IPath expectedLocation_dot = buildFolder.getLocation(); + IPath expectedLocation_dot_slash = buildFolder.getLocation(); + IPath expectedLocation_dot_slash_path = relativeFolder_dot_slash_path.getLocation(); + IPath expectedLocation_dotdot = project.getLocation(); + IPath expectedLocation_dotdot_slash = project.getLocation(); + IPath expectedLocation_dotdot_slash_path = relativeFolder_dotdot_slash_path.getLocation(); + + assertEquals(expectedLocation_dot, new Path(actualIncludePaths[0])); + assertEquals(".", actualIncludePaths[1]); + assertEquals(expectedLocation_dot_slash_path, new Path(actualIncludePaths[2])); + assertEquals(new Path(relativePath_dot_slash_path), new Path(actualIncludePaths[3])); + + assertEquals(expectedLocation_dotdot, new Path(actualIncludePaths[4])); + assertEquals("..", actualIncludePaths[5]); + assertEquals(expectedLocation_dotdot_slash_path, new Path(actualIncludePaths[6])); + assertEquals(new Path(relativePath_dotdot_slash_path), new Path(actualIncludePaths[7])); + assertTrue(actualIncludePaths[7].startsWith("..")); + assertEquals(new Path(locationPath_dotdot_path), new Path(actualIncludePaths[8])); + assertTrue(actualIncludePaths[8].contains("..")); + assertEquals(9, actualIncludePaths.length); + + assertEquals(expectedLocation_dot_slash, new Path(actualLocalIncludePaths[0])); + assertEquals(new Path(relativePath_dot_slash), new Path(actualLocalIncludePaths[1])); + assertTrue(actualLocalIncludePaths[1].startsWith(".")); + assertEquals(expectedLocation_dotdot_slash, new Path(actualLocalIncludePaths[2])); + assertEquals(new Path(relativePath_dotdot_slash), new Path(actualLocalIncludePaths[3])); + assertTrue(actualLocalIncludePaths[3].startsWith("..")); + assertEquals(4, actualLocalIncludePaths.length); + } + + /** + * Test if build/environment variables are expanded + */ + public void testEnvironmentVars() throws Exception { + // create a project + IProject project = ResourceHelper.createCDTProjectWithConfig(getName()); + IFolder folder = ResourceHelper.createFolder(project, "Folder"); + String envPathStr = "${ProjDirPath}/Folder"; + + // get project/configuration descriptions + ICProjectDescription prjDescription = CProjectDescriptionManager.getInstance().getProjectDescription(project, false); + assertNotNull(prjDescription); + ICConfigurationDescription cfgDescription = prjDescription.getDefaultSettingConfiguration(); + assertNotNull(cfgDescription); + + // create sample file + IFile file = ResourceHelper.createFile(project, "file.c"); + + // contribute the entries + CIncludePathEntry incRelativeEntry = new CIncludePathEntry(envPathStr, 0); + List entries = new ArrayList(); + entries.add(incRelativeEntry); + + // add provider to the configuration + ILanguageSettingsProvider provider = new MockProvider(PROVIDER_ID, PROVIDER_NAME, entries); + List providers = new ArrayList(); + providers.add(provider); + cfgDescription.setLanguageSettingProviders(providers); + + // test the entries received from the scannerInfoProvider + LanguageSettingsScannerInfoProvider scannerInfoProvider = new LanguageSettingsScannerInfoProvider(); + ExtendedScannerInfo info = scannerInfoProvider.getScannerInformation(file); + String[] actualIncludePaths = info.getIncludePaths(); + + IPath expectedLocation = folder.getLocation(); + assertEquals(expectedLocation, new Path(actualIncludePaths[0])); + assertEquals(1, actualIncludePaths.length); + } + + /** + * Test from parent folder's entries. + */ + public void testParentFolder() throws Exception { + class MockProviderForResource extends LanguageSettingsBaseProvider implements ILanguageSettingsProvider { + private IResource rc; + private final List entries; + + public MockProviderForResource(IResource rc, List entries) { + this.rc = rc; + this.entries = entries; + } + + @Override + public List getSettingEntries(ICConfigurationDescription cfgDescription, IResource rc, String languageId) { + if (this.rc.equals(rc)) + return entries; + return null; + } + } + + // create a project + IProject project = ResourceHelper.createCDTProjectWithConfig(getName()); + ICProjectDescription prjDescription = CProjectDescriptionManager.getInstance().getProjectDescription(project, false); + assertNotNull(prjDescription); + ICConfigurationDescription cfgDescription = prjDescription.getDefaultSettingConfiguration(); + assertNotNull(cfgDescription); + + // sample file + IFolder parentFolder = ResourceHelper.createFolder(project, "ParentFolder"); + IFile file = ResourceHelper.createFile(project, "ParentFolder/file.c"); + + // contribute the entries + IFolder incFolder = ResourceHelper.createFolder(project, "include"); + CIncludePathEntry includePathEntry = new CIncludePathEntry(incFolder, 0); + + List entries = new ArrayList(); + entries.add(includePathEntry); + + // add provider for parent folder + ILanguageSettingsProvider provider = new MockProviderForResource(parentFolder, entries); + assertNull(provider.getSettingEntries(cfgDescription, file, null)); + assertEquals(includePathEntry, provider.getSettingEntries(cfgDescription, parentFolder, null).get(0)); + + List providers = new ArrayList(); + providers.add(provider); + cfgDescription.setLanguageSettingProviders(providers); + + // test that the scannerInfoProvider gets the entries for + LanguageSettingsScannerInfoProvider scannerInfoProvider = new LanguageSettingsScannerInfoProvider(); + ExtendedScannerInfo info = scannerInfoProvider.getScannerInformation(file); + String[] actualIncludePaths = info.getIncludePaths(); + // include paths + assertEquals(incFolder.getLocation(), new Path(actualIncludePaths[0])); + assertEquals(1, actualIncludePaths.length); + } + + /** + * Test resolved paths. + */ + public void testResolvedPath() throws Exception { + // create a project + IProject project = ResourceHelper.createCDTProjectWithConfig(getName()); + IFolder folder = ResourceHelper.createFolder(project, "Folder"); + String envPathStr = "${ProjDirPath}/Folder"; + + // get project/configuration descriptions + ICProjectDescription prjDescription = CProjectDescriptionManager.getInstance().getProjectDescription(project, false); + assertNotNull(prjDescription); + ICConfigurationDescription cfgDescription = prjDescription.getDefaultSettingConfiguration(); + assertNotNull(cfgDescription); + + // create sample file + IFile file = ResourceHelper.createFile(project, "file.c"); + + // contribute the entries + CIncludePathEntry incRelativeEntry = new CIncludePathEntry(envPathStr, ICSettingEntry.RESOLVED); + List entries = new ArrayList(); + entries.add(incRelativeEntry); + + // add provider to the configuration + ILanguageSettingsProvider provider = new MockProvider(PROVIDER_ID, PROVIDER_NAME, entries); + List providers = new ArrayList(); + providers.add(provider); + cfgDescription.setLanguageSettingProviders(providers); + + // test the entries received from the scannerInfoProvider + LanguageSettingsScannerInfoProvider scannerInfoProvider = new LanguageSettingsScannerInfoProvider(); + ExtendedScannerInfo info = scannerInfoProvider.getScannerInformation(file); + String[] actualIncludePaths = info.getIncludePaths(); + + // test that RESOLVED entries are not modified + IPath expectedLocation = new Path(envPathStr); + assertEquals(expectedLocation, new Path(actualIncludePaths[0])); + assertEquals(1, actualIncludePaths.length); + } + + private List getLanguages(IFolder folder, ICConfigurationDescription cfgDescription) { + // Get first 2 languages + IPath rcPath = folder.getProjectRelativePath(); + ICFolderDescription rcDes = (ICFolderDescription) cfgDescription.getResourceDescription(rcPath, false); + ICLanguageSetting[] langSettings = rcDes.getLanguageSettings(); + assertNotNull(langSettings); + + List languageIds = new ArrayList(); + for (ICLanguageSetting ls : langSettings) { + String langId = ls.getLanguageId(); + if (langId!=null && !languageIds.contains(langId)) { + languageIds.add(langId); + } + } + return languageIds; + } + + /** + * Test composition of 2 languages. + */ + public void testResourceLanguages() throws Exception { + class MockProviderLang extends LanguageSettingsBaseProvider implements ILanguageSettingsProvider { + private final String langId; + private final List entries; + + public MockProviderLang(String id, String name, String langId, List entries) { + super(id, name); + this.langId = langId; + this.entries = entries; + } + + @Override + public List getSettingEntries(ICConfigurationDescription cfgDescription, IResource rc, String languageId) { + if (langId==null || langId.equals(languageId)) + return entries; + return new ArrayList(); + } + } + + // create a project + IProject project = ResourceHelper.createCDTProjectWithConfig(getName()); + IFolder folder = ResourceHelper.createFolder(project, "Folder"); + + IFolder incFolderA = ResourceHelper.createFolder(project, "includeA"); + IFolder incFolderB = ResourceHelper.createFolder(project, "includeB"); + IFolder incFolderC = ResourceHelper.createFolder(project, "includeC"); + + // get project/configuration descriptions + ICProjectDescription prjDescription = CProjectDescriptionManager.getInstance().getProjectDescription(project, false); + assertNotNull(prjDescription); + ICConfigurationDescription cfgDescription = prjDescription.getDefaultSettingConfiguration(); + assertNotNull(cfgDescription); + + // find 2 languages applicable to the folder + List languageIds = getLanguages(folder, cfgDescription); + assertTrue(languageIds.size() >= 2); + String langId1 = languageIds.get(0); + String langId2 = languageIds.get(1); + + // define overlapping entries + CIncludePathEntry incEntryA = new CIncludePathEntry(incFolderA, 0); + CIncludePathEntry incEntryB = new CIncludePathEntry(incFolderB, 0); + CIncludePathEntry incEntryC = new CIncludePathEntry(incFolderC, 0); + List entries1 = new ArrayList(); + entries1.add(incEntryA); + entries1.add(incEntryB); + List entries2 = new ArrayList(); + entries2.add(incEntryC); + entries2.add(incEntryB); + + // add providers to the configuration + ILanguageSettingsProvider provider1 = new MockProviderLang(PROVIDER_ID, PROVIDER_NAME, langId1, entries1); + ILanguageSettingsProvider provider2 = new MockProviderLang(PROVIDER_ID_2, PROVIDER_NAME, langId2, entries2); + List providers = new ArrayList(); + providers.add(provider1); + providers.add(provider2); + cfgDescription.setLanguageSettingProviders(providers); + + // test the entries received from the scannerInfoProvider + LanguageSettingsScannerInfoProvider scannerInfoProvider = new LanguageSettingsScannerInfoProvider(); + ExtendedScannerInfo info = scannerInfoProvider.getScannerInformation(folder); + String[] actualIncludePaths = info.getIncludePaths(); + + // Test that the result is the union of entries + assertEquals(incFolderA.getLocation(), new Path(actualIncludePaths[0])); + assertEquals(incFolderB.getLocation(), new Path(actualIncludePaths[1])); + assertEquals(incFolderC.getLocation(), new Path(actualIncludePaths[2])); + assertEquals(3, actualIncludePaths.length); + } + +} diff --git a/core/org.eclipse.cdt.core.tests/model/org/eclipse/cdt/core/language/settings/providers/LanguageSettingsSerializableTests.java b/core/org.eclipse.cdt.core.tests/model/org/eclipse/cdt/core/language/settings/providers/LanguageSettingsSerializableTests.java new file mode 100644 index 00000000000..0cde8b59f0a --- /dev/null +++ b/core/org.eclipse.cdt.core.tests/model/org/eclipse/cdt/core/language/settings/providers/LanguageSettingsSerializableTests.java @@ -0,0 +1,1146 @@ +/******************************************************************************* + * Copyright (c) 2009 Andrew Gvozdev 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: + * Andrew Gvozdev - Initial API and implementation + *******************************************************************************/ + +package org.eclipse.cdt.core.language.settings.providers; + +import java.util.ArrayList; +import java.util.List; + +import junit.framework.TestCase; +import junit.framework.TestSuite; + +import org.eclipse.cdt.core.settings.model.CIncludeFileEntry; +import org.eclipse.cdt.core.settings.model.CIncludePathEntry; +import org.eclipse.cdt.core.settings.model.CLibraryFileEntry; +import org.eclipse.cdt.core.settings.model.CLibraryPathEntry; +import org.eclipse.cdt.core.settings.model.CMacroEntry; +import org.eclipse.cdt.core.settings.model.CMacroFileEntry; +import org.eclipse.cdt.core.settings.model.ICConfigurationDescription; +import org.eclipse.cdt.core.settings.model.ICLanguageSettingEntry; +import org.eclipse.cdt.core.testplugin.CModelMock; +import org.eclipse.cdt.core.testplugin.ResourceHelper; +import org.eclipse.cdt.internal.core.XmlUtil; +import org.eclipse.cdt.internal.core.language.settings.providers.LanguageSettingsProvidersSerializer; +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IFolder; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.Path; +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +/** + * Test cases testing LanguageSettingsProvider functionality + */ +public class LanguageSettingsSerializableTests extends TestCase { + // Should match id of extension point defined in plugin.xml + private static final String EXTENSION_SERIALIZABLE_PROVIDER_ID = "org.eclipse.cdt.core.tests.custom.serializable.language.settings.provider"; + + private static final String CFG_ID = "test.configuration.id"; + private static final String CFG_ID_1 = "test.configuration.id.1"; + private static final String CFG_ID_2 = "test.configuration.id.2"; + private static final ICConfigurationDescription MOCK_CFG = new CModelMock.DummyCConfigurationDescription(CFG_ID); + private static final IResource MOCK_RC = ResourcesPlugin.getWorkspace().getRoot(); + private static final String LANG_ID = "test.lang.id"; + private static final String LANG_ID_1 = "test.lang.id.1"; + private static final String LANG_ID_2 = "test.lang.id.2"; + private static final String PROVIDER_NULL = "test.provider.null.id"; + private static final String PROVIDER_1 = "test.provider.1.id"; + private static final String PROVIDER_2 = "test.provider.2.id"; + private static final String PROVIDER_NAME_NULL = "test.provider.null.name"; + private static final String PROVIDER_NAME_1 = "test.provider.1.name"; + private static final String PROVIDER_NAME_2 = "test.provider.2.name"; + private static final String CUSTOM_PARAMETER = "custom.parameter"; + + private static final String ELEM_TEST = "test"; + + /** + * Constructor. + * @param name - name of the test. + */ + public LanguageSettingsSerializableTests(String name) { + super(name); + + } + + @Override + protected void setUp() throws Exception { + } + + @Override + protected void tearDown() throws Exception { + ResourceHelper.cleanUp(); + } + + /** + * @return - new TestSuite. + */ + public static TestSuite suite() { + return new TestSuite(LanguageSettingsSerializableTests.class); + } + + /** + * main function of the class. + * + * @param args - arguments + */ + public static void main(String[] args) { + junit.textui.TestRunner.run(suite()); + } + + /** + */ + public void testProvider() throws Exception { + // benchmark data + List entries = new ArrayList(); + entries.add(new CIncludePathEntry("path0", 0)); + List languages = new ArrayList(); + languages.add(LANG_ID); + + // create a provider + LanguageSettingsSerializable mockProvider = new LanguageSettingsSerializable(PROVIDER_1, PROVIDER_NAME_1); + // test isEmpty() + assertTrue(mockProvider.isEmpty()); + + // test setters and getters + mockProvider.setId(PROVIDER_2); + assertEquals(PROVIDER_2, mockProvider.getId()); + mockProvider.setName(PROVIDER_NAME_2); + assertEquals(PROVIDER_NAME_2, mockProvider.getName()); + mockProvider.setCustomParameter(CUSTOM_PARAMETER); + assertEquals(CUSTOM_PARAMETER, mockProvider.getCustomParameter()); + mockProvider.setLanguageScope(languages); + assertEquals(languages, mockProvider.getLanguageScope()); + mockProvider.setLanguageScope(null); + assertEquals(null, mockProvider.getLanguageScope()); + + mockProvider.setSettingEntries(null, MOCK_RC, LANG_ID, entries); + List actual = mockProvider.getSettingEntries(null, MOCK_RC, LANG_ID); + assertEquals(entries.get(0), actual.get(0)); + assertEquals(entries.size(), actual.size()); + assertFalse(mockProvider.isEmpty()); + + // test clear() + mockProvider.clear(); + assertTrue(mockProvider.isEmpty()); + } + + /** + */ + public void testNoProviders() throws Exception { + // serialize language settings of user defined providers (on workspace level) + LanguageSettingsProvidersSerializer.serializeLanguageSettingsWorkspace(); + LanguageSettingsProvidersSerializer.loadLanguageSettingsWorkspace(); + + // test passes if no exception was thrown + } + + /** + */ + public void testEmptyProvider() throws Exception { + Element elementProvider; + { + // create null provider + LanguageSettingsSerializable providerNull = new LanguageSettingsSerializable(PROVIDER_NULL, PROVIDER_NAME_NULL); + assertNull(providerNull.getSettingEntries(null, null, null)); + // set and get null entries + providerNull.setSettingEntries(null, null, null, null); + assertNull(providerNull.getSettingEntries(null, null, null)); + + Document doc = XmlUtil.newDocument(); + Element rootElement = XmlUtil.appendElement(doc, ELEM_TEST); + elementProvider = providerNull.serialize(rootElement); + String xmlString = XmlUtil.toString(doc); + assertTrue(xmlString.contains(PROVIDER_NULL)); + } + { + // re-load and check language settings of the newly loaded provider + LanguageSettingsSerializable provider = new LanguageSettingsSerializable(elementProvider); + assertEquals(PROVIDER_NULL, provider.getId()); + List actual = provider.getSettingEntries(null, null, null); + assertNull(actual); + } + } + + /** + */ + public void testCustomParameter() throws Exception { + Element elementProvider; + { + // create provider with custom parameter + LanguageSettingsSerializable provider = new LanguageSettingsSerializable(PROVIDER_1, PROVIDER_NAME_1); + provider.setCustomParameter(CUSTOM_PARAMETER); + assertEquals(CUSTOM_PARAMETER, provider.getCustomParameter()); + + Document doc = XmlUtil.newDocument(); + Element rootElement = XmlUtil.appendElement(doc, ELEM_TEST); + elementProvider = provider.serialize(rootElement); + String xmlString = XmlUtil.toString(doc); + assertTrue(xmlString.contains(CUSTOM_PARAMETER)); + } + { + // re-load and check custom parameter of the newly loaded provider + LanguageSettingsSerializable provider = new LanguageSettingsSerializable(elementProvider); + assertEquals(CUSTOM_PARAMETER, provider.getCustomParameter()); + } + } + + /** + */ + public void testLanguages() throws Exception { + List expectedLanguageIds = new ArrayList(); + expectedLanguageIds.add(LANG_ID); + expectedLanguageIds.add(LANG_ID_1); + + Element elementProvider; + { + // create provider with custom language scope + LanguageSettingsSerializable provider = new LanguageSettingsSerializable(PROVIDER_1, PROVIDER_NAME_1); + provider.setLanguageScope(expectedLanguageIds); + List actualIds = provider.getLanguageScope(); + assertEquals(LANG_ID, actualIds.get(0)); + assertEquals(LANG_ID_1, actualIds.get(1)); + assertEquals(2, actualIds.size()); + + Document doc = XmlUtil.newDocument(); + Element rootElement = XmlUtil.appendElement(doc, ELEM_TEST); + elementProvider = provider.serialize(rootElement); + String xmlString = XmlUtil.toString(doc); + assertTrue(xmlString.contains(LANG_ID)); + assertTrue(xmlString.contains(LANG_ID_1)); + } + { + // re-load and check language settings of the newly loaded provider + LanguageSettingsSerializable provider = new LanguageSettingsSerializable(elementProvider); + List actualIds = provider.getLanguageScope(); + assertEquals(expectedLanguageIds.get(0), actualIds.get(0)); + assertEquals(expectedLanguageIds.get(1), actualIds.get(1)); + assertEquals(expectedLanguageIds.size(), actualIds.size()); + } + } + + /** + */ + public void testLanguageScope() throws Exception { + // benchmark entries + List entries = new ArrayList(); + entries.add(new CIncludePathEntry("path0", 0)); + + // define the scope + List expectedLanguageIds = new ArrayList(); + expectedLanguageIds.add(LANG_ID); + expectedLanguageIds.add(LANG_ID_1); + + Element elementProvider; + { + // create provider with no scope by default + LanguageSettingsSerializable provider = new LanguageSettingsSerializable(PROVIDER_1, PROVIDER_NAME_1); + // set entries for the whole language scope (now langId=null) + provider.setSettingEntries(null, null, null, entries); + { + // doublecheck for language scope itself + List actual = provider.getSettingEntries(null, null, null); + assertEquals(entries, actual); + } + { + // doublecheck for any language + List actual = provider.getSettingEntries(null, null, LANG_ID_2); + assertEquals(entries, actual); + } + + // set the scope + provider.setLanguageScope(expectedLanguageIds); + List actualIds = provider.getLanguageScope(); + assertEquals(LANG_ID, actualIds.get(0)); + assertEquals(LANG_ID_1, actualIds.get(1)); + assertEquals(2, actualIds.size()); + + { + // check for language scope itself + List actual = provider.getSettingEntries(null, null, null); + assertEquals(entries, actual); + } + { + // check for language in the language scope + List actual = provider.getSettingEntries(null, null, LANG_ID); + assertEquals(entries, actual); + } + { + // check for language not in scope + List actual = provider.getSettingEntries(null, null, LANG_ID_2); + assertNull(actual); + } + + Document doc = XmlUtil.newDocument(); + Element rootElement = XmlUtil.appendElement(doc, ELEM_TEST); + elementProvider = provider.serialize(rootElement); + String xmlString = XmlUtil.toString(doc); + assertTrue(xmlString.contains(LANG_ID)); + assertTrue(xmlString.contains(LANG_ID_1)); + } + { + // re-load and check language settings of the newly loaded provider + LanguageSettingsSerializable provider = new LanguageSettingsSerializable(elementProvider); + List actualIds = provider.getLanguageScope(); + assertEquals(expectedLanguageIds.get(0), actualIds.get(0)); + assertEquals(expectedLanguageIds.get(1), actualIds.get(1)); + assertEquals(expectedLanguageIds.size(), actualIds.size()); + + { + // check for language scope itself + List actual = provider.getSettingEntries(null, null, null); + assertEquals(entries, actual); + } + { + // check for language in the language scope + List actual = provider.getSettingEntries(null, null, LANG_ID); + assertEquals(entries, actual); + } + { + // check for language not in scope + List actual = provider.getSettingEntries(null, null, LANG_ID_2); + assertNull(actual); + } + } + } + + /** + */ + public void testNullConfiguration() throws Exception { + // provider/configuration/language/resource/settingEntry + Element elementProvider; + List entries = new ArrayList(); + entries.add(new CIncludePathEntry("path0", 0)); + { + // create a provider and serialize its settings + LanguageSettingsSerializable provider = new LanguageSettingsSerializable(PROVIDER_1, PROVIDER_NAME_1); + provider.setSettingEntries(null, MOCK_RC, LANG_ID, entries); + + Document doc = XmlUtil.newDocument(); + Element rootElement = XmlUtil.appendElement(doc, ELEM_TEST); + elementProvider = provider.serialize(rootElement); + + // verify that "configuration" element is collapsed and not saved in XML + String xmlString = XmlUtil.toString(doc); + assertFalse(xmlString.contains(" actual = provider.getSettingEntries(null, MOCK_RC, LANG_ID); + assertEquals(entries.get(0), actual.get(0)); + } + } + + /** + */ + public void testNullLanguage() throws Exception { + // provider/configuration/language/resource/settingEntry + Element elementProvider; + List entries = new ArrayList(); + entries.add(new CIncludePathEntry("path0", 0)); + { + // create a provider and serialize its settings + LanguageSettingsSerializable provider = new LanguageSettingsSerializable(PROVIDER_1, PROVIDER_NAME_1); + provider.setSettingEntries(MOCK_CFG, MOCK_RC, null, entries); + + Document doc = XmlUtil.newDocument(); + Element rootElement = XmlUtil.appendElement(doc, ELEM_TEST); + elementProvider = provider.serialize(rootElement); + + // verify that "language" element is collapsed and not saved in XML + String xmlString = XmlUtil.toString(doc); + assertFalse(xmlString.contains(" actual = provider.getSettingEntries(MOCK_CFG, MOCK_RC, null); + assertEquals(entries.get(0), actual.get(0)); + } + } + + + /** + */ + public void testNullLanguageScope() throws Exception { + // define benchmark entries + List entriesNullLanguage = new ArrayList(); + entriesNullLanguage.add(new CIncludePathEntry("path_null", 0)); + List entriesLanguage = new ArrayList(); + entriesLanguage.add(new CIncludePathEntry("path", 0)); + + Element elementProvider; + + { + // create a provider + LanguageSettingsSerializable provider = new LanguageSettingsSerializable(PROVIDER_1, PROVIDER_NAME_1); + assertEquals(null, provider.getLanguageScope()); + + // add null language + provider.setSettingEntries(null, MOCK_RC, null, entriesNullLanguage); + assertEquals(null, provider.getLanguageScope()); + { + // getter by null language + List actual = provider.getSettingEntries(null, MOCK_RC, null); + assertEquals(entriesNullLanguage.get(0), actual.get(0)); + assertEquals(entriesNullLanguage.size(), actual.size()); + } + { + // getter by any language - should return same entries as null + List actual = provider.getSettingEntries(null, MOCK_RC, LANG_ID); + assertEquals(entriesNullLanguage.get(0), actual.get(0)); + assertEquals(entriesNullLanguage.size(), actual.size()); + } + + // add non-null language + provider.setSettingEntries(MOCK_CFG, MOCK_RC, LANG_ID, entriesLanguage); + assertNull(provider.getLanguageScope()); + { + // getter by null language + List actual = provider.getSettingEntries(null, MOCK_RC, null); + assertEquals(entriesNullLanguage.get(0), actual.get(0)); + assertEquals(entriesNullLanguage.size(), actual.size()); + } + { + // getter by the language + List actual = provider.getSettingEntries(null, MOCK_RC, LANG_ID); + assertEquals(entriesLanguage.get(0), actual.get(0)); + assertEquals(entriesLanguage.size(), actual.size()); + } + + // provider/configuration/language/resource/settingEntry + Document doc = XmlUtil.newDocument(); + Element rootElement = XmlUtil.appendElement(doc, ELEM_TEST); + elementProvider = provider.serialize(rootElement); + + // verify that "language" element is saved in XML + String xmlString = XmlUtil.toString(doc); + assertTrue(xmlString.contains(" actual = provider.getSettingEntries(null, MOCK_RC, null); + assertEquals(entriesNullLanguage.get(0), actual.get(0)); + assertEquals(entriesNullLanguage.size(), actual.size()); + } + { + // getter by the language + List actual = provider.getSettingEntries(null, MOCK_RC, LANG_ID); + assertEquals(entriesLanguage.get(0), actual.get(0)); + assertEquals(entriesLanguage.size(), actual.size()); + } + } + } + + /** + */ + public void testNullResource() throws Exception { + // provider/configuration/language/resource/settingEntry + Element elementProvider; + List entries = new ArrayList(); + entries.add(new CIncludePathEntry("path0", 0)); + { + // create a provider and serialize its settings + LanguageSettingsSerializable provider = new LanguageSettingsSerializable(PROVIDER_1, PROVIDER_NAME_1); + provider.setSettingEntries(MOCK_CFG, null, LANG_ID, entries); + + Document doc = XmlUtil.newDocument(); + Element rootElement = XmlUtil.appendElement(doc, ELEM_TEST); + elementProvider = provider.serialize(rootElement); + + // verify that "resource" element is collapsed and not saved in XML + String xmlString = XmlUtil.toString(doc); + assertFalse(xmlString.contains(" actual = provider.getSettingEntries(MOCK_CFG, null, LANG_ID); + assertEquals(entries.get(0), actual.get(0)); + } + } + + /** + */ + public void testNullConfigurationLanguage() throws Exception { + // provider/configuration/language/resource/settingEntry + Element elementProvider; + List entries = new ArrayList(); + entries.add(new CIncludePathEntry("path0", 0)); + { + // create a provider and serialize its settings + LanguageSettingsSerializable provider = new LanguageSettingsSerializable(PROVIDER_1, PROVIDER_NAME_1); + provider.setSettingEntries(null, MOCK_RC, null, entries); + + Document doc = XmlUtil.newDocument(); + Element rootElement = XmlUtil.appendElement(doc, ELEM_TEST); + elementProvider = provider.serialize(rootElement); + + // verify that element is collapsed and not saved in XML + String xmlString = XmlUtil.toString(doc); + assertFalse(xmlString.contains(" actual = provider.getSettingEntries(null, MOCK_RC, null); + assertEquals(entries.get(0), actual.get(0)); + } + } + + /** + */ + public void testNullConfigurationResource() throws Exception { + // provider/configuration/language/resource/settingEntry + Element elementProvider; + List entries = new ArrayList(); + entries.add(new CIncludePathEntry("path0", 0)); + { + // create a provider and serialize its settings + LanguageSettingsSerializable provider = new LanguageSettingsSerializable(PROVIDER_1, PROVIDER_NAME_1); + provider.setSettingEntries(null, null, LANG_ID, entries); + + Document doc = XmlUtil.newDocument(); + Element rootElement = XmlUtil.appendElement(doc, ELEM_TEST); + elementProvider = provider.serialize(rootElement); + + // verify that element is collapsed and not saved in XML + String xmlString = XmlUtil.toString(doc); + assertFalse(xmlString.contains(" actual = provider.getSettingEntries(null, null, LANG_ID); + assertEquals(entries.get(0), actual.get(0)); + } + } + + /** + */ + public void testNullLanguageResource() throws Exception { + // provider/configuration/language/resource/settingEntry + Element elementProvider; + List entries = new ArrayList(); + entries.add(new CIncludePathEntry("path0", 0)); + { + // create a provider and serialize its settings + LanguageSettingsSerializable provider = new LanguageSettingsSerializable(PROVIDER_1, PROVIDER_NAME_1); + provider.setSettingEntries(MOCK_CFG, null, null, entries); + + Document doc = XmlUtil.newDocument(); + Element rootElement = XmlUtil.appendElement(doc, ELEM_TEST); + elementProvider = provider.serialize(rootElement); + + // verify that element is collapsed and not saved in XML + String xmlString = XmlUtil.toString(doc); + assertFalse(xmlString.contains(" actual = provider.getSettingEntries(MOCK_CFG, null, null); + assertEquals(entries.get(0), actual.get(0)); + } + } + + /** + */ + public void testNullConfigurationLanguageResourceFlag() throws Exception { + // provider/configuration/language/resource/settingEntry + Element elementProvider; + List entries = new ArrayList(); + int flag = 0; + entries.add(new CIncludePathEntry("path0", flag)); + { + // create a provider and serialize its settings + LanguageSettingsSerializable provider = new LanguageSettingsSerializable(PROVIDER_1, PROVIDER_NAME_1); + provider.setSettingEntries(null, null, null, entries); + + Document doc = XmlUtil.newDocument(); + Element rootElement = XmlUtil.appendElement(doc, ELEM_TEST); + elementProvider = provider.serialize(rootElement); + + // verify that element is collapsed and not saved in XML + String xmlString = XmlUtil.toString(doc); + assertFalse(xmlString.contains(" actual = provider.getSettingEntries(null, null, null); + assertEquals(entries.get(0), actual.get(0)); + } + } + + /** + */ + public void testCIncludePathEntry() throws Exception { + Element elementProvider; + List entries = new ArrayList(); + entries.add(new CIncludePathEntry("path0", 1)); + { + // create a provider and serialize its settings + LanguageSettingsSerializable provider = new LanguageSettingsSerializable(PROVIDER_1, PROVIDER_NAME_1); + provider.setSettingEntries(null, null, null, entries); + + Document doc = XmlUtil.newDocument(); + Element rootElement = XmlUtil.appendElement(doc, ELEM_TEST); + elementProvider = provider.serialize(rootElement); + } + { + // re-load and check language settings of the newly loaded provider + LanguageSettingsSerializable provider = new LanguageSettingsSerializable(elementProvider); + assertEquals(PROVIDER_1, provider.getId()); + + List actual = provider.getSettingEntries(null, null, null); + ICLanguageSettingEntry entry = actual.get(0); + assertTrue(entry instanceof CIncludePathEntry); + + CIncludePathEntry includePathEntry = (CIncludePathEntry)entry; + assertEquals(entries.get(0).getName(), includePathEntry.getName()); + assertEquals(entries.get(0).getValue(), includePathEntry.getValue()); + assertEquals(entries.get(0).getKind(), includePathEntry.getKind()); + assertEquals(entries.get(0).getFlags(), includePathEntry.getFlags()); + assertEquals(entries.get(0), includePathEntry); + } + } + + /** + */ + public void testCIncludeFileEntry() throws Exception { + Element elementProvider; + List entries = new ArrayList(); + entries.add(new CIncludeFileEntry("name", 1)); + { + // create a provider and serialize its settings + LanguageSettingsSerializable provider = new LanguageSettingsSerializable(PROVIDER_1, PROVIDER_NAME_1); + provider.setSettingEntries(null, null, null, entries); + + Document doc = XmlUtil.newDocument(); + Element rootElement = XmlUtil.appendElement(doc, ELEM_TEST); + elementProvider = provider.serialize(rootElement); + } + { + // re-load and check language settings of the newly loaded provider + LanguageSettingsSerializable provider = new LanguageSettingsSerializable(elementProvider); + assertEquals(PROVIDER_1, provider.getId()); + + List actual = provider.getSettingEntries(null, null, null); + ICLanguageSettingEntry entry = actual.get(0); + assertTrue(entry instanceof CIncludeFileEntry); + CIncludeFileEntry includeFileEntry = (CIncludeFileEntry)entry; + assertEquals(entries.get(0).getName(), includeFileEntry.getName()); + assertEquals(entries.get(0).getValue(), includeFileEntry.getValue()); + assertEquals(entries.get(0).getKind(), includeFileEntry.getKind()); + assertEquals(entries.get(0).getFlags(), includeFileEntry.getFlags()); + assertEquals(entries.get(0), includeFileEntry); + } + } + + /** + */ + public void testCMacroEntry() throws Exception { + Element elementProvider; + List entries = new ArrayList(); + entries.add(new CMacroEntry("MACRO0", "value0",1)); + { + // create a provider and serialize its settings + LanguageSettingsSerializable provider = new LanguageSettingsSerializable(PROVIDER_1, PROVIDER_NAME_1); + provider.setSettingEntries(null, null, null, entries); + + Document doc = XmlUtil.newDocument(); + Element rootElement = XmlUtil.appendElement(doc, ELEM_TEST); + elementProvider = provider.serialize(rootElement); + } + { + // re-load and check language settings of the newly loaded provider + LanguageSettingsSerializable provider = new LanguageSettingsSerializable(elementProvider); + assertEquals(PROVIDER_1, provider.getId()); + + List actual = provider.getSettingEntries(null, null, null); + ICLanguageSettingEntry entry = actual.get(0); + assertTrue(entry instanceof CMacroEntry); + CMacroEntry macroEntry = (CMacroEntry)entry; + assertEquals(entries.get(0).getName(), macroEntry.getName()); + assertEquals(entries.get(0).getValue(), macroEntry.getValue()); + assertEquals(entries.get(0).getKind(), macroEntry.getKind()); + assertEquals(entries.get(0).getFlags(), macroEntry.getFlags()); + assertEquals(entries.get(0), macroEntry); + } + } + + /** + */ + public void testCMacroFileEntry() throws Exception { + Element elementProvider; + List entries = new ArrayList(); + entries.add(new CMacroFileEntry("name", 1)); + { + // create a provider and serialize its settings + LanguageSettingsSerializable provider = new LanguageSettingsSerializable(PROVIDER_1, PROVIDER_NAME_1); + provider.setSettingEntries(null, null, null, entries); + + Document doc = XmlUtil.newDocument(); + Element rootElement = XmlUtil.appendElement(doc, ELEM_TEST); + elementProvider = provider.serialize(rootElement); + } + { + // re-load and check language settings of the newly loaded provider + LanguageSettingsSerializable provider = new LanguageSettingsSerializable(elementProvider); + assertEquals(PROVIDER_1, provider.getId()); + + List actual = provider.getSettingEntries(null, null, null); + ICLanguageSettingEntry entry = actual.get(0); + assertTrue(entry instanceof CMacroFileEntry); + CMacroFileEntry macroFileEntry = (CMacroFileEntry)entry; + assertEquals(entries.get(0).getName(), macroFileEntry.getName()); + assertEquals(entries.get(0).getValue(), macroFileEntry.getValue()); + assertEquals(entries.get(0).getKind(), macroFileEntry.getKind()); + assertEquals(entries.get(0).getFlags(), macroFileEntry.getFlags()); + assertEquals(entries.get(0), macroFileEntry); + } + } + + /** + */ + public void testCLibraryPathEntry() throws Exception { + Element elementProvider; + List entries = new ArrayList(); + entries.add(new CLibraryPathEntry("name", 1)); + { + // create a provider and serialize its settings + LanguageSettingsSerializable provider = new LanguageSettingsSerializable(PROVIDER_1, PROVIDER_NAME_1); + provider.setSettingEntries(null, null, null, entries); + + Document doc = XmlUtil.newDocument(); + Element rootElement = XmlUtil.appendElement(doc, ELEM_TEST); + elementProvider = provider.serialize(rootElement); + } + { + // re-load and check language settings of the newly loaded provider + LanguageSettingsSerializable provider = new LanguageSettingsSerializable(elementProvider); + assertEquals(PROVIDER_1, provider.getId()); + + List actual = provider.getSettingEntries(null, null, null); + ICLanguageSettingEntry entry = actual.get(0); + assertTrue(entry instanceof CLibraryPathEntry); + CLibraryPathEntry libraryPathEntry = (CLibraryPathEntry)entry; + assertEquals(entries.get(0).getName(), libraryPathEntry.getName()); + assertEquals(entries.get(0).getValue(), libraryPathEntry.getValue()); + assertEquals(entries.get(0).getKind(), libraryPathEntry.getKind()); + assertEquals(entries.get(0).getFlags(), libraryPathEntry.getFlags()); + assertEquals(entries.get(0), libraryPathEntry); + } + } + + /** + */ + public void testCLibraryFileEntry() throws Exception { + Element elementProvider; + List entries = new ArrayList(); + entries.add(new CLibraryFileEntry("name", 1)); + { + // create a provider and serialize its settings + LanguageSettingsSerializable provider = new LanguageSettingsSerializable(PROVIDER_1, PROVIDER_NAME_1); + provider.setSettingEntries(null, null, null, entries); + + Document doc = XmlUtil.newDocument(); + Element rootElement = XmlUtil.appendElement(doc, ELEM_TEST); + elementProvider = provider.serialize(rootElement); + } + { + // re-load and check language settings of the newly loaded provider + LanguageSettingsSerializable provider = new LanguageSettingsSerializable(elementProvider); + assertEquals(PROVIDER_1, provider.getId()); + + List actual = provider.getSettingEntries(null, null, null); + ICLanguageSettingEntry entry = actual.get(0); + assertTrue(entry instanceof CLibraryFileEntry); + CLibraryFileEntry libraryFileEntry = (CLibraryFileEntry)entry; + assertEquals(entries.get(0).getName(), libraryFileEntry.getName()); + assertEquals(entries.get(0).getValue(), libraryFileEntry.getValue()); + assertEquals(entries.get(0).getKind(), libraryFileEntry.getKind()); + assertEquals(entries.get(0).getFlags(), libraryFileEntry.getFlags()); + assertEquals(entries.get(0), libraryFileEntry); + } + } + + /** + */ + public void testMixedSettingEntries() throws Exception { + Element elementProvider; + List entries = new ArrayList(); + entries.add(new CMacroEntry("MACRO0", "value0",1)); + entries.add(new CIncludePathEntry("path0", 1)); + entries.add(new CIncludePathEntry("path1", 1)); + { + // create a provider and serialize its settings + LanguageSettingsSerializable provider = new LanguageSettingsSerializable(PROVIDER_1, PROVIDER_NAME_1); + provider.setSettingEntries(null, null, null, entries); + + Document doc = XmlUtil.newDocument(); + Element rootElement = XmlUtil.appendElement(doc, ELEM_TEST); + elementProvider = provider.serialize(rootElement); + } + { + // re-load and check language settings of the newly loaded provider + LanguageSettingsSerializable provider = new LanguageSettingsSerializable(elementProvider); + assertEquals(PROVIDER_1, provider.getId()); + + List actual = provider.getSettingEntries(null, null, null); + assertEquals(entries.get(0), actual.get(0)); + assertEquals(entries.get(1), actual.get(1)); + assertEquals(entries.get(2), actual.get(2)); + assertEquals(entries.size(), actual.size()); + } + } + + /** + */ + public void testLanguageAndNull() throws Exception { + Element elementProvider = null; + + List entries = new ArrayList(); + entries.add(new CIncludePathEntry("path0", 0)); + List entries2 = new ArrayList(); + entries2.add(new CIncludePathEntry("path2", 0)); + + { + // create a provider + LanguageSettingsSerializable mockProvider = null; + mockProvider = new LanguageSettingsSerializable(PROVIDER_1, PROVIDER_NAME_1); + mockProvider.setSettingEntries(null, null, null, entries); + mockProvider.setSettingEntries(null, null, LANG_ID, entries2); + + // serialize language settings to DOM + Document doc = XmlUtil.newDocument(); + Element rootElement = XmlUtil.appendElement(doc, ELEM_TEST); + elementProvider = mockProvider.serialize(rootElement); + } + { + // re-load and check language settings of the newly loaded provider + LanguageSettingsSerializable loadedProvider = new LanguageSettingsSerializable(elementProvider); + + List actual = loadedProvider.getSettingEntries(null, null, null); + assertEquals(entries.get(0), actual.get(0)); + assertEquals(entries.size(), actual.size()); + + List actual2 = loadedProvider.getSettingEntries(null, null, LANG_ID); + assertEquals(entries2.get(0), actual2.get(0)); + assertEquals(entries2.size(), actual2.size()); + } + } + + /** + */ + public void testTwoLanguages() throws Exception { + Element elementProvider = null; + + List entries = new ArrayList(); + entries.add(new CIncludePathEntry("path0", 0)); + List entries2 = new ArrayList(); + entries2.add(new CIncludePathEntry("path2", 0)); + + { + // create a provider + LanguageSettingsSerializable mockProvider = null; + mockProvider = new LanguageSettingsSerializable(PROVIDER_1, PROVIDER_NAME_1); + mockProvider.setSettingEntries(null, null, LANG_ID_1, entries); + mockProvider.setSettingEntries(null, null, LANG_ID_2, entries2); + + // serialize language settings to DOM + Document doc = XmlUtil.newDocument(); + Element rootElement = XmlUtil.appendElement(doc, ELEM_TEST); + elementProvider = mockProvider.serialize(rootElement); + String xml = XmlUtil.toString(elementProvider.getOwnerDocument()); +// fail(xml); // for debugging + } + { + // re-load and check language settings of the newly loaded provider + LanguageSettingsSerializable loadedProvider = new LanguageSettingsSerializable(elementProvider); + + List actual = loadedProvider.getSettingEntries(null, null, LANG_ID_1); + assertEquals(entries.get(0), actual.get(0)); + assertEquals(entries.size(), actual.size()); + + List actual2 = loadedProvider.getSettingEntries(null, null, LANG_ID_2); + assertEquals(entries2.get(0), actual2.get(0)); + assertEquals(entries2.size(), actual2.size()); + } + } + + /** + */ + public void testTwoResources() throws Exception { + // Create resources + IProject project = ResourceHelper.createCDTProjectWithConfig(this.getName()); + IFile rc1 = ResourceHelper.createFile(project, "rc1"); + assertNotNull(rc1); + IFile rc2 = ResourceHelper.createFile(project, "rc2"); + assertNotNull(rc2); + assertFalse(rc1.getFullPath().equals(rc2.getFullPath())); + + Element elementProvider = null; + + List entries = new ArrayList(); + entries.add(new CIncludePathEntry("path0", 0)); + List entries2 = new ArrayList(); + entries2.add(new CIncludePathEntry("path2", 0)); + + { + // create a provider + LanguageSettingsSerializable mockProvider = null; + mockProvider = new LanguageSettingsSerializable(PROVIDER_1, PROVIDER_NAME_1); + mockProvider.setSettingEntries(null, rc1, null, entries); + mockProvider.setSettingEntries(null, rc2, null, entries2); + + // serialize language settings to DOM + Document doc = XmlUtil.newDocument(); + Element rootElement = XmlUtil.appendElement(doc, ELEM_TEST); + elementProvider = mockProvider.serialize(rootElement); + String xml = XmlUtil.toString(elementProvider.getOwnerDocument()); +// fail(xml); // for debugging + } + { + // re-load and check language settings of the newly loaded provider + LanguageSettingsSerializable loadedProvider = new LanguageSettingsSerializable(elementProvider); + + List actual = loadedProvider.getSettingEntries(null, rc1, null); + assertEquals(entries.get(0), actual.get(0)); + assertEquals(entries.size(), actual.size()); + + List actual2 = loadedProvider.getSettingEntries(null, rc2, null); + assertEquals(entries2.get(0), actual2.get(0)); + assertEquals(entries2.size(), actual2.size()); + } + } + + /** + */ + public void testParentFolder() throws Exception { + // Create model project and accompanied descriptions + IProject project = ResourceHelper.createCDTProjectWithConfig(this.getName()); + + // Create resources + IFolder parentFolder = ResourceHelper.createFolder(project, "/ParentFolder/"); + assertNotNull(parentFolder); + IFile emptySettingsPath = ResourceHelper.createFile(project, "/ParentFolder/Subfolder/empty"); + assertNotNull(emptySettingsPath); + + // Create provider + LanguageSettingsSerializable provider = new LanguageSettingsSerializable(PROVIDER_1, PROVIDER_NAME_1); + + // store the entries in parent folder + List entries = new ArrayList(); + entries.add(new CIncludePathEntry("path0", 0)); + provider.setSettingEntries(null, parentFolder, LANG_ID, entries); + provider.setSettingEntries(null, emptySettingsPath, LANG_ID, new ArrayList()); + + { + // retrieve entries for a parent folder itself + List actual = provider.getSettingEntries(null, parentFolder, LANG_ID); + assertEquals(entries,actual); + assertEquals(entries.size(), actual.size()); + } + + { + // retrieve entries for a derived resource (in a subfolder) + IFile derived = ResourceHelper.createFile(project, "/ParentFolder/Subfolder/resource"); + List actual = provider.getSettingEntries(null, derived, LANG_ID); + // NOT taken from parent folder + assertEquals(null,actual); + } + + { + // retrieve entries for not related resource + IFile notRelated = ResourcesPlugin.getWorkspace().getRoot().getFile(new Path("/AnotherFolder/Subfolder/resource")); + List actual = provider.getSettingEntries(null, notRelated, LANG_ID); + assertEquals(null,actual); + } + + { + // test distinction between no settings and empty settings + List actual = provider.getSettingEntries(null, emptySettingsPath, LANG_ID); + // NOT taken from parent folder and not null + assertEquals(0, actual.size()); + } + } + + /** + */ + public void testEquals() throws Exception { + List sampleEntries_1 = new ArrayList(); + sampleEntries_1.add(new CMacroEntry("MACRO0", "value0",1)); + sampleEntries_1.add(new CIncludePathEntry("path0", 1)); + sampleEntries_1.add(new CIncludePathEntry("path1", 1)); + + List sampleEntries_2 = new ArrayList(); + sampleEntries_2.add(new CIncludePathEntry("path0", 1)); + + List sampleLanguages = new ArrayList(); + sampleLanguages.add(LANG_ID); + + // create a model provider + LanguageSettingsSerializable provider1 = new LanguageSettingsSerializable(PROVIDER_1, PROVIDER_NAME_1); + provider1.setLanguageScope(sampleLanguages); + provider1.setCustomParameter(CUSTOM_PARAMETER); + provider1.setSettingEntries(MOCK_CFG, MOCK_RC, LANG_ID, sampleEntries_1); + provider1.setSettingEntries(null, null, LANG_ID, sampleEntries_2); + + { + // create another provider with the same data + LanguageSettingsSerializable provider2 = new LanguageSettingsSerializable(PROVIDER_1, PROVIDER_NAME_1); + assertFalse(provider1.equals(provider2)); + assertFalse(provider1.hashCode()==provider2.hashCode()); + + provider2.setSettingEntries(MOCK_CFG, MOCK_RC, LANG_ID, sampleEntries_1); + assertFalse(provider1.equals(provider2)); + assertFalse(provider1.hashCode()==provider2.hashCode()); + + provider2.setSettingEntries(null, null, LANG_ID, sampleEntries_2); + assertFalse(provider1.equals(provider2)); + assertFalse(provider1.hashCode()==provider2.hashCode()); + + provider2.setLanguageScope(sampleLanguages); + assertFalse(provider1.equals(provider2)); + assertFalse(provider1.hashCode()==provider2.hashCode()); + + provider2.setCustomParameter(CUSTOM_PARAMETER); + assertTrue(provider1.equals(provider2)); + assertTrue(provider1.hashCode()==provider2.hashCode()); + + // check different ID + provider2.setId(PROVIDER_2); + assertFalse(provider1.equals(provider2)); + assertFalse(provider1.hashCode()==provider2.hashCode()); + } + + { + // check that subclasses are not equal + LanguageSettingsSerializable providerSub1 = new LanguageSettingsSerializable() {}; + LanguageSettingsSerializable providerSub2 = new LanguageSettingsSerializable() {}; + assertFalse(providerSub1.equals(providerSub2)); + assertFalse(providerSub1.hashCode()==providerSub2.hashCode()); + } + } + + /** + */ + public void testClone() throws Exception { + // define sample data + List sampleEntries_1 = new ArrayList(); + sampleEntries_1.add(new CMacroEntry("MACRO0", "value0",1)); + sampleEntries_1.add(new CIncludePathEntry("path0", 1)); + sampleEntries_1.add(new CIncludePathEntry("path1", 1)); + + List sampleEntries_2 = new ArrayList(); + sampleEntries_2.add(new CIncludePathEntry("path0", 1)); + + List sampleLanguages = new ArrayList(); + sampleLanguages.add(LANG_ID); + + // create a model provider + class LanguageSettingsSerializableMock extends LanguageSettingsSerializable implements Cloneable { + public LanguageSettingsSerializableMock(String id, String name) { + super(id, name); + } + @Override + public LanguageSettingsSerializableMock clone() throws CloneNotSupportedException { + return (LanguageSettingsSerializableMock) super.clone(); + } + + } + LanguageSettingsSerializableMock provider1 = new LanguageSettingsSerializableMock(PROVIDER_1, PROVIDER_NAME_1); + provider1.setLanguageScope(sampleLanguages); + provider1.setCustomParameter(CUSTOM_PARAMETER); + provider1.setSettingEntries(MOCK_CFG, MOCK_RC, LANG_ID, sampleEntries_1); + provider1.setSettingEntries(null, null, LANG_ID, sampleEntries_2); + + // clone provider + LanguageSettingsSerializableMock providerClone = provider1.clone(); + assertNotSame(provider1, providerClone); + assertTrue(provider1.equals(providerClone)); + assertTrue(provider1.getClass()==providerClone.getClass()); + assertEquals(provider1.getCustomParameter(), providerClone.getCustomParameter()); + assertEquals(provider1.getLanguageScope().get(0), providerClone.getLanguageScope().get(0)); + + List actual1 = providerClone.getSettingEntries(MOCK_CFG, MOCK_RC, LANG_ID); + assertNotSame(sampleEntries_1, actual1); + assertEquals(sampleEntries_1.get(0), actual1.get(0)); + assertEquals(sampleEntries_1.get(1), actual1.get(1)); + assertEquals(sampleEntries_1.get(2), actual1.get(2)); + assertEquals(sampleEntries_1.size(), actual1.size()); + + List actual2 = providerClone.getSettingEntries(null, null, LANG_ID); + assertNotSame(sampleEntries_2, actual2); + assertEquals(sampleEntries_2.get(0), actual2.get(0)); + assertEquals(sampleEntries_2.size(), actual2.size()); + } + + /** + */ + public void testCloneShallow() throws Exception { + // define sample data + List sampleLanguages = new ArrayList(); + sampleLanguages.add(LANG_ID); + + // create a model provider + class LanguageSettingsSerializableMock extends LanguageSettingsSerializable implements Cloneable { + public LanguageSettingsSerializableMock(String id, String name) { + super(id, name); + } + @Override + public LanguageSettingsSerializableMock cloneShallow() throws CloneNotSupportedException { + return (LanguageSettingsSerializableMock) super.cloneShallow(); + } + + } + LanguageSettingsSerializableMock provider1 = new LanguageSettingsSerializableMock(PROVIDER_1, PROVIDER_NAME_1); + provider1.setLanguageScope(sampleLanguages); + provider1.setCustomParameter(CUSTOM_PARAMETER); + + List entries = new ArrayList(); + entries.add(new CIncludePathEntry("path", 1)); + provider1.setSettingEntries(null, null, null, entries); + + // clone provider + LanguageSettingsSerializableMock providerClone = provider1.cloneShallow(); + assertNotSame(provider1, providerClone); + assertFalse(provider1.equals(providerClone)); + assertTrue(provider1.getClass()==providerClone.getClass()); + assertEquals(provider1.getCustomParameter(), providerClone.getCustomParameter()); + assertEquals(provider1.getLanguageScope().get(0), providerClone.getLanguageScope().get(0)); + + List actual = providerClone.getSettingEntries(null, null, null); + assertNull(actual); + } +} + + diff --git a/core/org.eclipse.cdt.core.tests/model/org/eclipse/cdt/core/language/settings/providers/MockLanguageSettingsBaseProvider.java b/core/org.eclipse.cdt.core.tests/model/org/eclipse/cdt/core/language/settings/providers/MockLanguageSettingsBaseProvider.java new file mode 100644 index 00000000000..afae2a4cb50 --- /dev/null +++ b/core/org.eclipse.cdt.core.tests/model/org/eclipse/cdt/core/language/settings/providers/MockLanguageSettingsBaseProvider.java @@ -0,0 +1,19 @@ +/******************************************************************************* + * Copyright (c) 2009, 2009 Andrew Gvozdev (Quoin Inc.) 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: + * Andrew Gvozdev (Quoin Inc.) - initial API and implementation + *******************************************************************************/ + +package org.eclipse.cdt.core.language.settings.providers; + +import org.eclipse.cdt.core.language.settings.providers.LanguageSettingsBaseProvider; + + +public class MockLanguageSettingsBaseProvider extends LanguageSettingsBaseProvider { + +} diff --git a/core/org.eclipse.cdt.core.tests/model/org/eclipse/cdt/core/language/settings/providers/MockLanguageSettingsEditableProvider.java b/core/org.eclipse.cdt.core.tests/model/org/eclipse/cdt/core/language/settings/providers/MockLanguageSettingsEditableProvider.java new file mode 100644 index 00000000000..bdb11b3d7e7 --- /dev/null +++ b/core/org.eclipse.cdt.core.tests/model/org/eclipse/cdt/core/language/settings/providers/MockLanguageSettingsEditableProvider.java @@ -0,0 +1,30 @@ +/******************************************************************************* + * Copyright (c) 2009, 2011 Andrew Gvozdev 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: + * Andrew Gvozdev - initial API and implementation + *******************************************************************************/ + +package org.eclipse.cdt.core.language.settings.providers; + +import org.eclipse.cdt.core.language.settings.providers.LanguageSettingsSerializable; +import org.eclipse.cdt.core.settings.model.ILanguageSettingsEditableProvider; + + +public class MockLanguageSettingsEditableProvider extends LanguageSettingsSerializable implements ILanguageSettingsEditableProvider { + public MockLanguageSettingsEditableProvider() { + super(); + } + + public MockLanguageSettingsEditableProvider cloneShallow() throws CloneNotSupportedException { + return (MockLanguageSettingsEditableProvider) super.cloneShallow(); + } + + public MockLanguageSettingsEditableProvider clone() throws CloneNotSupportedException { + return (MockLanguageSettingsEditableProvider) super.clone(); + } +} diff --git a/core/org.eclipse.cdt.core.tests/model/org/eclipse/cdt/core/language/settings/providers/MockLanguageSettingsProvider.java b/core/org.eclipse.cdt.core.tests/model/org/eclipse/cdt/core/language/settings/providers/MockLanguageSettingsProvider.java new file mode 100644 index 00000000000..96024c7db45 --- /dev/null +++ b/core/org.eclipse.cdt.core.tests/model/org/eclipse/cdt/core/language/settings/providers/MockLanguageSettingsProvider.java @@ -0,0 +1,28 @@ +/******************************************************************************* + * Copyright (c) 2009, 2009 Andrew Gvozdev (Quoin Inc.) 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: + * Andrew Gvozdev (Quoin Inc.) - initial API and implementation + *******************************************************************************/ + +package org.eclipse.cdt.core.language.settings.providers; + +import java.util.List; + +import org.eclipse.cdt.core.AbstractExecutableExtensionBase; +import org.eclipse.cdt.core.language.settings.providers.ILanguageSettingsProvider; +import org.eclipse.cdt.core.settings.model.ICConfigurationDescription; +import org.eclipse.cdt.core.settings.model.ICLanguageSettingEntry; +import org.eclipse.core.resources.IResource; + +public class MockLanguageSettingsProvider extends AbstractExecutableExtensionBase + implements ILanguageSettingsProvider { + + public List getSettingEntries(ICConfigurationDescription cfgDescription, IResource rc, String languageId) { + return null; + } +} diff --git a/core/org.eclipse.cdt.core.tests/model/org/eclipse/cdt/core/language/settings/providers/MockLanguageSettingsSerializableProvider.java b/core/org.eclipse.cdt.core.tests/model/org/eclipse/cdt/core/language/settings/providers/MockLanguageSettingsSerializableProvider.java new file mode 100644 index 00000000000..276a3400b93 --- /dev/null +++ b/core/org.eclipse.cdt.core.tests/model/org/eclipse/cdt/core/language/settings/providers/MockLanguageSettingsSerializableProvider.java @@ -0,0 +1,25 @@ +/******************************************************************************* + * Copyright (c) 2009, 2009 Andrew Gvozdev (Quoin Inc.) 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: + * Andrew Gvozdev (Quoin Inc.) - initial API and implementation + *******************************************************************************/ + +package org.eclipse.cdt.core.language.settings.providers; + +import org.eclipse.cdt.core.language.settings.providers.LanguageSettingsSerializable; + + +public class MockLanguageSettingsSerializableProvider extends LanguageSettingsSerializable { + public MockLanguageSettingsSerializableProvider() { + super(); + } + + public MockLanguageSettingsSerializableProvider(String id, String name) { + super(id, name); + } +} diff --git a/core/org.eclipse.cdt.core.tests/model/org/eclipse/cdt/core/model/tests/AllCoreTests.java b/core/org.eclipse.cdt.core.tests/model/org/eclipse/cdt/core/model/tests/AllCoreTests.java index b6738d6a07d..7544599c04b 100644 --- a/core/org.eclipse.cdt.core.tests/model/org/eclipse/cdt/core/model/tests/AllCoreTests.java +++ b/core/org.eclipse.cdt.core.tests/model/org/eclipse/cdt/core/model/tests/AllCoreTests.java @@ -14,6 +14,7 @@ package org.eclipse.cdt.core.model.tests; import junit.framework.Test; import junit.framework.TestSuite; +import org.eclipse.cdt.core.language.settings.providers.AllLanguageSettingsProvidersTests; import org.eclipse.cdt.core.settings.model.AllCProjectDescriptionTests; import org.eclipse.cdt.core.settings.model.PathSettingsContainerTests; @@ -60,6 +61,8 @@ public class AllCoreTests { suite.addTest(AsmModelBuilderTest.suite()); suite.addTest(CModelBuilderBugsTest.suite()); suite.addTest(Bug311189.suite()); + + suite.addTest(AllLanguageSettingsProvidersTests.suite()); return suite; } diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/IndexProviderManagerTest.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/IndexProviderManagerTest.java index c4cb84e7459..de9df4893f5 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/IndexProviderManagerTest.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/IndexProviderManagerTest.java @@ -25,6 +25,7 @@ import org.eclipse.cdt.core.index.IIndex; import org.eclipse.cdt.core.index.provider.IIndexProvider; import org.eclipse.cdt.core.internal.index.provider.test.DummyProviderTraces; import org.eclipse.cdt.core.internal.index.provider.test.Providers; +import org.eclipse.cdt.core.language.settings.providers.ILanguageSettingsProvider; import org.eclipse.cdt.core.model.CoreModel; import org.eclipse.cdt.core.model.ICProject; import org.eclipse.cdt.core.parser.util.ArrayUtil; @@ -704,6 +705,12 @@ class MockConfig implements ICConfigurationDescription { } public void setReadOnly(boolean readOnly, boolean keepModify) {} + + public void setLanguageSettingProviders(List providers) {} + + public List getLanguageSettingProviders() { + return null; + } } /* diff --git a/core/org.eclipse.cdt.core.tests/plugin.xml b/core/org.eclipse.cdt.core.tests/plugin.xml index 4e9b99437e5..4c4418fc9fe 100644 --- a/core/org.eclipse.cdt.core.tests/plugin.xml +++ b/core/org.eclipse.cdt.core.tests/plugin.xml @@ -159,6 +159,13 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + getReferenceInfo() { + return null; + } + + public void setReferenceInfo(Map refs) throws WriteAccessException { + } + + public ICExternalSetting[] getExternalSettings() { + return null; + } + + public ICExternalSetting createExternalSetting(String[] languageIDs, + String[] contentTypeIds, String[] extensions, + ICSettingEntry[] entries) throws WriteAccessException { + return null; + } + + public void removeExternalSetting(ICExternalSetting setting) throws WriteAccessException { + } + + public void removeExternalSettings() throws WriteAccessException { + } + + public ICBuildSetting getBuildSetting() { + return null; + } + + public ICdtVariablesContributor getBuildVariablesContributor() { + return null; + } + + public Object getSessionProperty(QualifiedName name) { + return null; + } + + public void setSessionProperty(QualifiedName name, Object value) { + } + + public void setName(String name) throws WriteAccessException { + } + + public ICConfigExtensionReference[] get(String extensionPointID) { + return null; + } + + public ICConfigExtensionReference create(String extensionPoint, String extension) throws CoreException { + return null; + } + + public void remove(ICConfigExtensionReference ext) throws CoreException { + } + + public void remove(String extensionPoint) throws CoreException { + } + + public boolean isPreferenceConfiguration() { + return false; + } + + public ICLanguageSetting getLanguageSettingForFile(IPath path, boolean ignoreExludeStatus) { + return null; + } + + public void setExternalSettingsProviderIds(String[] ids) { + } + + public String[] getExternalSettingsProviderIds() { + return null; + } + + public void updateExternalSettingsProviders(String[] ids) throws WriteAccessException { + } + + public CConfigurationStatus getConfigurationStatus() { + return null; + } + + public void setLanguageSettingProviders(List providers) { + } + + public List getLanguageSettingProviders() { + return null; + } + + } +} diff --git a/core/org.eclipse.cdt.core/META-INF/MANIFEST.MF b/core/org.eclipse.cdt.core/META-INF/MANIFEST.MF index 238adb9b4f9..0949e2d8844 100644 --- a/core/org.eclipse.cdt.core/META-INF/MANIFEST.MF +++ b/core/org.eclipse.cdt.core/META-INF/MANIFEST.MF @@ -27,6 +27,7 @@ Export-Package: org.eclipse.cdt.core, org.eclipse.cdt.core.index.export, org.eclipse.cdt.core.index.provider, org.eclipse.cdt.core.language, + org.eclipse.cdt.core.language.settings.providers, org.eclipse.cdt.core.model, org.eclipse.cdt.core.model.util, org.eclipse.cdt.core.parser, @@ -66,6 +67,7 @@ Export-Package: org.eclipse.cdt.core, org.eclipse.cdt.internal.core.index.provider;x-internal:=true, org.eclipse.cdt.internal.core.indexer;x-internal:=true, org.eclipse.cdt.internal.core.language;x-friends:="org.eclipse.cdt.ui", + org.eclipse.cdt.internal.core.language.settings.providers;x-internal:=true, org.eclipse.cdt.internal.core.model;x-friends:="org.eclipse.cdt.ui,org.eclipse.cdt.debug.core,org.eclipse.cdt.debug.ui", org.eclipse.cdt.internal.core.model.ext;x-friends:="org.eclipse.cdt.ui", org.eclipse.cdt.internal.core.parser;x-internal:=true, diff --git a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/core/language/settings/providers/ILanguageSettingsProvider.java b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/core/language/settings/providers/ILanguageSettingsProvider.java new file mode 100644 index 00000000000..e8a30f39a24 --- /dev/null +++ b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/core/language/settings/providers/ILanguageSettingsProvider.java @@ -0,0 +1,65 @@ +/******************************************************************************* + * Copyright (c) 2009, 2010 Andrew Gvozdev (Quoin Inc.) 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: + * Andrew Gvozdev (Quoin Inc.) - initial API and implementation + *******************************************************************************/ + +package org.eclipse.cdt.core.language.settings.providers; + +import java.util.List; + +import org.eclipse.cdt.core.model.LanguageManager; +import org.eclipse.cdt.core.settings.model.ICConfigurationDescription; +import org.eclipse.cdt.core.settings.model.ICLanguageSettingEntry; +import org.eclipse.cdt.core.settings.model.ICSettingEntry; +import org.eclipse.core.resources.IResource; + +/** + * Base interface to provide list of {@link ICLanguageSettingEntry}. + * This interface is used to deliver additions to compiler options such as + * include paths (-I) or preprocessor defines (-D) and others (see + * {@link ICSettingEntry#INCLUDE_PATH} and other kinds). + * + * To define a provider like that use extension point + * {@code org.eclipse.cdt.core.LanguageSettingsProvider} and implement this + * interface. CDT provides a few general use implementations such as + * {@link LanguageSettingsBaseProvider} which could be used out of the box or + * extended. See extension point schema description LanguageSettingsProvider.exsd + * for more details. + * + * @since 6.0 + */ +public interface ILanguageSettingsProvider { + /** + * Id is used to keep track of the providers internally. Use unique id + * to represent the provider. + * + * @return Id of the provider. + */ + public String getId(); + + /** + * Name is used to present the provider to the end user in UI. + * + * @return name of the provider. + */ + public String getName(); + + /** + * Returns the list of setting entries for the given configuration description, + * resource and language. + * + * @param cfgDescription - configuration description. + * @param rc - resource such as file or folder. + * @param languageId - language id + * (see {@link LanguageManager#getLanguageForFile(org.eclipse.core.resources.IFile, ICConfigurationDescription)}). + * + * @return the list of setting entries or {@code null} if no settings defined. + */ + public List getSettingEntries(ICConfigurationDescription cfgDescription, IResource rc, String languageId); +} diff --git a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/core/language/settings/providers/LanguageSettingsBaseProvider.java b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/core/language/settings/providers/LanguageSettingsBaseProvider.java new file mode 100644 index 00000000000..a97bb4ce46c --- /dev/null +++ b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/core/language/settings/providers/LanguageSettingsBaseProvider.java @@ -0,0 +1,175 @@ +/******************************************************************************* + * Copyright (c) 2009, 2010 Andrew Gvozdev (Quoin Inc.) 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: + * Andrew Gvozdev (Quoin Inc.) - initial API and implementation + *******************************************************************************/ + +package org.eclipse.cdt.core.language.settings.providers; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.eclipse.cdt.core.AbstractExecutableExtensionBase; +import org.eclipse.cdt.core.settings.model.ICConfigurationDescription; +import org.eclipse.cdt.core.settings.model.ICLanguageSettingEntry; +import org.eclipse.cdt.internal.core.settings.model.SettingsModelMessages; +import org.eclipse.core.resources.IResource; + +/** + * {@code LanguageSettingsBaseProvider} is a basic implementation of {@link ILanguageSettingsProvider} + * defined in {@code org.eclipse.cdt.core.LanguageSettingsProvider} extension point. + * + * This implementation supports "static" list of entries for languages specified in + * the extension point. + * + * @since 6.0 + */ +public class LanguageSettingsBaseProvider extends AbstractExecutableExtensionBase implements ILanguageSettingsProvider { + /** Language scope, i.e. list of languages the entries will be provided for. */ + protected List languageScope = null; + + /** Custom parameter. Intended for providers extending this class. */ + protected String customParameter = null; + + /** List of entries defined by this provider. */ + private List entries = null; + + /** + * Default constructor. + */ + public LanguageSettingsBaseProvider() { + } + + /** + * Constructor. Creates an "empty" provider. + * + * @param id - id of the provider. + * @param name - name of the provider to be presented to a user. + */ + public LanguageSettingsBaseProvider(String id, String name) { + super(id, name); + } + + /** + * Constructor. + * + * @param id - id of the provider. + * @param name - name of the provider to be presented to a user. + * @param languages - list of languages the {@code entries} provided for. + * {@code languages} can be {@code null}, in this case the {@code entries} + * are provided for any language. + * @param entries - the list of language settings entries this provider provides. + * If {@code null} is passed, the provider creates an empty list. + */ + public LanguageSettingsBaseProvider(String id, String name, List languages, List entries) { + super(id, name); + this.languageScope = languages!=null ? new ArrayList(languages) : null; + this.entries = cloneList(entries); + } + + /** + * Constructor. + * + * @param id - id of the provider. + * @param name - name of the provider to be presented to a user. + * @param languages - list of languages the {@code entries} provided for. + * {@code languages} can be {@code null}, in this case the {@code entries} + * are provided for any language. + * @param entries - the list of language settings entries this provider provides. + * If {@code null} is passed, the provider creates an empty list. + * @param customParameter - a custom parameter as the means to customize + * providers extending this class. + */ + public LanguageSettingsBaseProvider(String id, String name, List languages, List entries, String customParameter) { + super(id, name); + this.languageScope = languages!=null ? new ArrayList(languages) : null; + this.entries = cloneList(entries); + this.customParameter = customParameter; + } + + /** + * A method to configure the provider. The initialization of provider from + * the extension point is done in 2 steps. First, the class is created as + * an executable extension using the default provider. Then this method is + * used to configure the provider. + * + * FIXME It is not allowed to reconfigure the provider. + * + * @param id - id of the provider. + * @param name - name of the provider to be presented to a user. + * @param languages - list of languages the {@code entries} provided for. + * {@code languages} can be {@code null}, in this case the {@code entries} + * are provided for any language. + * @param entries - the list of language settings entries this provider provides. + * If {@code null} is passed, the provider creates an empty list. + * @param customParameter - a custom parameter as the means to customize + * providers extending this class from extension definition in {@code plugin.xml}. + * + * FIXME @throws UnsupportedOperationException if an attempt to reconfigure provider is made. + */ + public void configureProvider(String id, String name, List languages, List entries, String customParameter) { +// if (this.entries!=null) +// throw new UnsupportedOperationException(SettingsModelMessages.getString("LanguageSettingsBaseProvider.CanBeConfiguredOnlyOnce")); //$NON-NLS-1$ + + setId(id); + setName(name); + this.languageScope = languages!=null ? new ArrayList(languages) : null; + this.entries = cloneList(entries); + this.customParameter = customParameter; + } + + /** + * {@inheritDoc} + * @param cfgDescription - configuration description. + * @param rc - resource such as file or folder. + * @param languageId - language id. If {@code null}, then entries defined for + * the language scope are returned. See {@link #getLanguageScope()} + */ + public List getSettingEntries(ICConfigurationDescription cfgDescription, IResource rc, String languageId) { + if (languageScope==null) { + if (entries==null) + return null; + return Collections.unmodifiableList(entries); + } + for (String lang : languageScope) { + if (lang.equals(languageId)) { + if (entries==null) + return null; + return Collections.unmodifiableList(entries); + } + } + return null; + } + + /** + * @return the list of languages this provider provides for. + * If {@code null}, the provider provides for any language. + */ + public List getLanguageScope() { + if (languageScope==null) + return null; + return Collections.unmodifiableList(languageScope); + } + + /** + * @return the custom parameter defined in the extension in {@code plugin.xml}. + */ + public String getCustomParameter() { + return customParameter; + } + + /** + * @param entries + * @return copy of the list of the entries. + */ + private List cloneList(List entries) { + return entries!=null ? new ArrayList(entries) : null; + } + +} diff --git a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/core/language/settings/providers/LanguageSettingsManager.java b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/core/language/settings/providers/LanguageSettingsManager.java new file mode 100644 index 00000000000..b837908fe1f --- /dev/null +++ b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/core/language/settings/providers/LanguageSettingsManager.java @@ -0,0 +1,204 @@ +/******************************************************************************* + * Copyright (c) 2009, 2010 Andrew Gvozdev (Quoin Inc.) 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: + * Andrew Gvozdev (Quoin Inc.) - initial API and implementation + *******************************************************************************/ + +package org.eclipse.cdt.core.language.settings.providers; + +import java.util.List; + +import org.eclipse.cdt.core.CCorePlugin; +import org.eclipse.cdt.core.settings.model.ICConfigurationDescription; +import org.eclipse.cdt.core.settings.model.ICLanguageSettingEntry; +import org.eclipse.cdt.core.settings.model.ICSettingEntry; +import org.eclipse.cdt.core.settings.model.ILanguageSettingsEditableProvider; +import org.eclipse.cdt.internal.core.LocalProjectScope; +import org.eclipse.cdt.internal.core.language.settings.providers.LanguageSettingsExtensionManager; +import org.eclipse.cdt.internal.core.language.settings.providers.LanguageSettingsProvidersSerializer; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.preferences.InstanceScope; +import org.osgi.service.prefs.BackingStoreException; +import org.osgi.service.prefs.Preferences; + +/** + * A collection of utility methods to manage language settings providers. + * See {@link ILanguageSettingsProvider}. + * + * @since 6.0 + */ +public class LanguageSettingsManager { + /** @noreference This field is temporary and not intended to be referenced by clients. */ + public static String USE_LANGUAGE_SETTINGS_PROVIDERS_PREFERENCE = "enabled"; //$NON-NLS-1$ + public static boolean USE_LANGUAGE_SETTINGS_PROVIDERS_DEFAULT = true; + + private static final String PREFERENCES_QUALIFIER = CCorePlugin.PLUGIN_ID; + private static final String LANGUAGE_SETTINGS_PROVIDERS_NODE = "languageSettingsProviders"; //$NON-NLS-1$ + + /** + * Returns the list of setting entries of the given provider + * for the given configuration description, resource and language. + * This method reaches to the parent folder of the resource recursively + * in case the resource does not define the entries for the given provider. + * + * @param provider - language settings provider. + * @param cfgDescription - configuration description. + * @param rc - resource such as file or folder. + * @param languageId - language id. + * + * @return the list of setting entries. Never returns {@code null} + * although individual providers return {@code null} if no settings defined. + */ + public static List getSettingEntriesUpResourceTree(ILanguageSettingsProvider provider, ICConfigurationDescription cfgDescription, IResource rc, String languageId) { + return LanguageSettingsExtensionManager.getSettingEntriesUpResourceTree(provider, cfgDescription, rc, languageId); + } + + /** + * Returns the list of setting entries of a certain kind (such as include paths) + * for the given configuration description, resource and language. This is a + * combined list for all providers taking into account settings of parent folder + * if settings for the given resource are not defined. + * + * @param cfgDescription - configuration description. + * @param rc - resource such as file or folder. + * @param languageId - language id. + * @param kind - kind of language settings entries, such as + * {@link ICSettingEntry#INCLUDE_PATH} etc. This is a binary flag + * and it is possible to specify composite kind. + * Use {@link ICSettingEntry#ALL} to get all kinds. + * + * @return the list of setting entries. + */ + // FIXME: get rid of callers PathEntryTranslator and DescriptionScannerInfoProvider + public static List getSettingEntriesByKind(ICConfigurationDescription cfgDescription, IResource rc, String languageId, int kind) { + return LanguageSettingsExtensionManager.getSettingEntriesByKind(cfgDescription, rc, languageId, kind); + } + + /** + * Get Language Settings Provider defined in the workspace. That includes user-defined + * providers and after that providers defined as extensions via + * {@code org.eclipse.cdt.core.LanguageSettingsProvider} extension point. + * That returns actual object, any modifications will affect any configuration + * referring to the provider. + * + * @param id - id of provider to find. + * @return the provider or {@code null} if provider is not defined. + */ + public static ILanguageSettingsProvider getWorkspaceProvider(String id) { + return LanguageSettingsProvidersSerializer.getWorkspaceProvider(id); + } + + /** + * @return a list of language settings providers defined on workspace level. + * That includes user-defined providers and after that providers defined as + * extensions via {@code org.eclipse.cdt.core.LanguageSettingsProvider} + * extension point. + */ + public static List getWorkspaceProviders() { + return LanguageSettingsProvidersSerializer.getWorkspaceProviders(); + } + + /** + * Checks if the provider is defined on the workspace level. + * + * @param provider - provider to check. + * @return {@code true} if the given provider is workspace provider, {@code false} otherwise. + */ + public static boolean isWorkspaceProvider(ILanguageSettingsProvider provider) { + return LanguageSettingsProvidersSerializer.isWorkspaceProvider(provider); + } + + /** + * TODO - helper method for often used chunk of code + * @param provider + * @return ILanguageSettingsProvider + */ + public static ILanguageSettingsProvider getRawProvider(ILanguageSettingsProvider provider) { + if (LanguageSettingsManager.isWorkspaceProvider(provider)){ + provider = LanguageSettingsProvidersSerializer.getRawWorkspaceProvider(provider.getId()); + } + return provider; + } + + + /** + * Set and store in workspace area user defined providers. + * + * @param providers - array of user defined workspace providers. + * Note that those providers will shadow extension providers with the same ID. + * All not shadowed extension providers will be added to the list to be present + * as workspace providers. {@code null} is equivalent to passing an empty array + * and so will reset workspace providers to match extension providers. + * @throws CoreException in case of problems (such as problems with persistence). + */ + public static void setWorkspaceProviders(List providers) throws CoreException { + LanguageSettingsProvidersSerializer.setWorkspaceProviders(providers); + } + + /** + * Get Language Settings Provider defined via + * {@code org.eclipse.cdt.core.LanguageSettingsProvider} extension point. + * + * @param id - ID of provider to find. + * @return the copy of the provider if possible (i.e. for {@link ILanguageSettingsEditableProvider}) + * or workspace provider if provider is not copyable. + */ + public static ILanguageSettingsProvider getExtensionProviderCopy(String id) { + ILanguageSettingsProvider provider = null; + try { + provider = LanguageSettingsExtensionManager.getExtensionProviderClone(id); + } catch (CloneNotSupportedException e) { + // from here falls to get workspace provider + } + if (provider==null) + provider = LanguageSettingsManager.getWorkspaceProvider(id); + + return provider; + } + + private static Preferences getPreferences(IProject project) { + if (project == null) + return InstanceScope.INSTANCE.getNode(PREFERENCES_QUALIFIER).node(LANGUAGE_SETTINGS_PROVIDERS_NODE); + else + return new LocalProjectScope(project).getNode(PREFERENCES_QUALIFIER).node(LANGUAGE_SETTINGS_PROVIDERS_NODE); + } + + /** + * Checks if Language Settings functionality is enabled for given project. + * + * @param project - project to check the preference + * @return {@code true} if functionality is enabled + * + * @noreference This method is temporary and not intended to be referenced by clients. + */ + public static boolean isLanguageSettingsProvidersEnabled(IProject project) { + Preferences pref = LanguageSettingsManager.getPreferences(project); + return pref.getBoolean(LanguageSettingsManager.USE_LANGUAGE_SETTINGS_PROVIDERS_PREFERENCE, LanguageSettingsManager.USE_LANGUAGE_SETTINGS_PROVIDERS_DEFAULT); + } + + /** + * Enable/disable Language Settings functionality for the given project. + * + * @param project + * @param value {@code true} to enable or {@code false} to disable the functionality. + * + * @noreference This method is temporary and not intended to be referenced by clients. + */ + public static void setLanguageSettingsProvidersEnabled(IProject project, boolean value) { + Preferences pref = LanguageSettingsManager.getPreferences(project); + pref.putBoolean(LanguageSettingsManager.USE_LANGUAGE_SETTINGS_PROVIDERS_PREFERENCE, value); + try { + pref.flush(); + } catch (BackingStoreException e) { + CCorePlugin.log(e); + } + } + +} diff --git a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/core/language/settings/providers/LanguageSettingsManager_TBD.java b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/core/language/settings/providers/LanguageSettingsManager_TBD.java new file mode 100644 index 00000000000..b92da74a593 --- /dev/null +++ b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/core/language/settings/providers/LanguageSettingsManager_TBD.java @@ -0,0 +1,99 @@ +/******************************************************************************* + * Copyright (c) 2009, 2009 Andrew Gvozdev (Quoin Inc.) 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: + * Andrew Gvozdev (Quoin Inc.) - initial API and implementation + *******************************************************************************/ + +package org.eclipse.cdt.core.language.settings.providers; + +import java.util.List; + +import org.eclipse.cdt.core.CCorePlugin; +import org.eclipse.cdt.core.settings.model.ICConfigurationDescription; +import org.eclipse.cdt.core.settings.model.ICFileDescription; +import org.eclipse.cdt.core.settings.model.ICFolderDescription; +import org.eclipse.cdt.core.settings.model.ICLanguageSetting; +import org.eclipse.cdt.core.settings.model.ICLanguageSettingEntry; +import org.eclipse.cdt.core.settings.model.ICResourceDescription; +import org.eclipse.cdt.core.settings.model.ILanguageSettingsEditableProvider; +import org.eclipse.cdt.internal.core.language.settings.providers.LanguageSettingsExtensionManager; +import org.eclipse.cdt.internal.core.language.settings.providers.LanguageSettingsProvidersSerializer; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.runtime.CoreException; + +/** + * TODO + * This layer of language settings in TODO + * + * Duplicate entries are filtered where only first entry is preserved. + * + */ +public class LanguageSettingsManager_TBD { + public static final String PROVIDER_UNKNOWN = "org.eclipse.cdt.projectmodel.4.0.0"; + public static final String PROVIDER_UI_USER = "org.eclipse.cdt.ui.user.LanguageSettingsProvider"; + public static final char PROVIDER_DELIMITER = LanguageSettingsProvidersSerializer.PROVIDER_DELIMITER; + + private static ICLanguageSetting[] getLanguageIds(ICResourceDescription rcDescription) { + if (rcDescription instanceof ICFileDescription) { + ICFileDescription fileDescription = (ICFileDescription)rcDescription; + return new ICLanguageSetting[] {fileDescription.getLanguageSetting()}; + } else if (rcDescription instanceof ICFolderDescription) { + ICFolderDescription folderDescription = (ICFolderDescription)rcDescription; + return folderDescription.getLanguageSettings(); + } + + return null; + } + + public static boolean isCustomizedResource(ICConfigurationDescription cfgDescription, IResource rc) { + if (rc instanceof IProject) + return false; + + for (ILanguageSettingsProvider provider: cfgDescription.getLanguageSettingProviders()) { + // FIXME +// if (!LanguageSettingsManager.isWorkspaceProvider(provider)) { + if (provider instanceof ILanguageSettingsEditableProvider || provider instanceof LanguageSettingsSerializable) { + ICResourceDescription rcDescription = cfgDescription.getResourceDescription(rc.getProjectRelativePath(), false); + for (ICLanguageSetting languageSetting : getLanguageIds(rcDescription)) { + String languageId = languageSetting.getLanguageId(); + if (languageId!=null) { + List list = provider.getSettingEntries(cfgDescription, rc, languageId); + if (list!=null) { + List listDefault = provider.getSettingEntries(null, null, languageId); + if (!list.equals(listDefault)) + return true; + } + } + } + } + } + + return false; + } + + @Deprecated // Shouldn't be API + public static void serializeWorkspaceProviders() throws CoreException { + LanguageSettingsProvidersSerializer.serializeLanguageSettingsWorkspace(); + } + + public static boolean isReconfigured(ILanguageSettingsProvider provider) { + if (provider instanceof ILanguageSettingsEditableProvider) { + try { + return ! LanguageSettingsExtensionManager.equalsExtensionProviderShallow((ILanguageSettingsEditableProvider) provider); + } catch (Exception e) { + CCorePlugin.log("Internal Error: cannot clone provider "+provider.getId(), e); + } + } + return false; + } + + public static boolean isEqualExtensionProvider(ILanguageSettingsProvider provider) { + return LanguageSettingsExtensionManager.equalsExtensionProvider(provider); + } +} diff --git a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/core/language/settings/providers/LanguageSettingsSerializable.java b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/core/language/settings/providers/LanguageSettingsSerializable.java new file mode 100644 index 00000000000..709a84e67d6 --- /dev/null +++ b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/core/language/settings/providers/LanguageSettingsSerializable.java @@ -0,0 +1,504 @@ +/******************************************************************************* + * Copyright (c) 2009, 2010 Andrew Gvozdev (Quoin Inc.) 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: + * Andrew Gvozdev (Quoin Inc.) - initial API and implementation + *******************************************************************************/ + +package org.eclipse.cdt.core.language.settings.providers; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +import org.eclipse.cdt.core.settings.model.CIncludeFileEntry; +import org.eclipse.cdt.core.settings.model.CIncludePathEntry; +import org.eclipse.cdt.core.settings.model.CLibraryFileEntry; +import org.eclipse.cdt.core.settings.model.CLibraryPathEntry; +import org.eclipse.cdt.core.settings.model.CMacroEntry; +import org.eclipse.cdt.core.settings.model.CMacroFileEntry; +import org.eclipse.cdt.core.settings.model.ICConfigurationDescription; +import org.eclipse.cdt.core.settings.model.ICLanguageSettingEntry; +import org.eclipse.cdt.core.settings.model.ICSettingEntry; +import org.eclipse.cdt.core.settings.model.util.LanguageSettingEntriesSerializer; +import org.eclipse.cdt.internal.core.XmlUtil; +import org.eclipse.core.resources.IResource; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + + +public class LanguageSettingsSerializable extends LanguageSettingsBaseProvider { + public static final String ELEM_PROVIDER = "provider"; //$NON-NLS-1$ + private static final String ATTR_ID = "id"; //$NON-NLS-1$ + + private static final String ELEM_LANGUAGE_SCOPE = "language-scope"; //$NON-NLS-1$ + private static final String ELEM_LANGUAGE = "language"; //$NON-NLS-1$ + private static final String ELEM_RESOURCE = "resource"; //$NON-NLS-1$ + private static final String ATTR_PROJECT_PATH = "project-relative-path"; //$NON-NLS-1$ + + private static final String ELEM_ENTRY = "entry"; //$NON-NLS-1$ + private static final String ATTR_KIND = "kind"; //$NON-NLS-1$ + private static final String ATTR_NAME = "name"; //$NON-NLS-1$ + private static final String ATTR_CLASS = "class"; //$NON-NLS-1$ + private static final String ATTR_PARAMETER = "parameter"; //$NON-NLS-1$ + private static final String ATTR_VALUE = "value"; //$NON-NLS-1$ + + private static final String ELEM_FLAG = "flag"; //$NON-NLS-1$ + + + private Map>> fStorage = new HashMap>>(); + + public LanguageSettingsSerializable() { + super(); + } + + public LanguageSettingsSerializable(String id, String name) { + super(id, name); + } + + public LanguageSettingsSerializable(Element elementProvider) { + super(); + load(elementProvider); + } + + @Override + public void configureProvider(String id, String name, List languages, List entries, String customParameter) { + // do not pass entries to super, keep them in local storage + super.configureProvider(id, name, languages, null, customParameter); + + fStorage.clear(); + + if (entries!=null) { + // note that these entries are intended to be retrieved by LanguageSettingsManager.getSettingEntriesUpResourceTree() + // when the whole resource hierarchy has been traversed up + setSettingEntries(null, null, null, entries); + } + } + + /** + * @return {@code true} if the provider does not keep any settings yet or {@code false} if there are some. + */ + public boolean isEmpty() { + return fStorage.isEmpty(); + } + + /** + * Set the language scope of the provider. + * + * @param languages - the list of languages this provider provides for. + * If {@code null}, the provider provides for any language. + * + * @see #getLanguageScope() + */ + public void setLanguageScope(List languages) { + if (languages==null) + this.languageScope = null; + else + this.languageScope = new ArrayList(languages); + } + + public void setCustomParameter(String customParameter) { + this.customParameter = customParameter; + } + + public void clear() { + fStorage.clear(); + } + + // TODO: look for refactoring this method + private void setSettingEntriesInternal(String rcProjectPath, String languageId, List entries) { + if (entries!=null) { + Map> langMap = fStorage.get(languageId); + if (langMap==null) { + langMap = new HashMap>(); + fStorage.put(languageId, langMap); + } + langMap.put(rcProjectPath, entries); + } else { + // do not keep nulls in the tables + Map> langMap = fStorage.get(languageId); + if (langMap!=null) { + langMap.remove(rcProjectPath); + if (langMap.size()==0) { + fStorage.remove(languageId); + } + } + } + } + + /** + * Sets language settings entries for the provider. + * Note that the entries are not persisted at that point. To persist use TODO + * + * @param cfgDescription - configuration description. + * @param rc - resource such as file or folder. + * @param languageId - language id. If {@code null}, then entries are considered to be defined for + * the language scope. See {@link #getLanguageScope()} + * @param entries - language settings entries to set. + */ + public void setSettingEntries(ICConfigurationDescription cfgDescription, IResource rc, String languageId, List entries) { + String rcProjectPath = rc!=null ? rc.getProjectRelativePath().toString() : null; + setSettingEntriesInternal(rcProjectPath, languageId, entries); + } + + /** + * {@inheritDoc} + */ + @Override + public List getSettingEntries(ICConfigurationDescription cfgDescription, IResource rc, String languageId) { + Map> langMap = fStorage.get(languageId); + if (langMap!=null) { + String rcProjectPath = rc!=null ? rc.getProjectRelativePath().toString() : null; + List entries = langMap.get(rcProjectPath); + if (entries!=null) + return Collections.unmodifiableList(entries); + } + + if (languageId!=null && (languageScope==null || languageScope.contains(languageId))) { + List entries = getSettingEntries(cfgDescription, rc, null); + return entries; + } + + return null; + } + + /* + + + + + + + + + */ + // provider/configuration/language/resource/entry + public Element serialize(Element parentElement) { + Element elementProvider = XmlUtil.appendElement(parentElement, ELEM_PROVIDER, new String[] { + ATTR_ID, getId(), + ATTR_NAME, getName(), + ATTR_CLASS, getClass().getCanonicalName(), + ATTR_PARAMETER, getCustomParameter(), + }); + + if (languageScope!=null) { + for (String langId : languageScope) { + XmlUtil.appendElement(elementProvider, ELEM_LANGUAGE_SCOPE, new String[] {ATTR_ID, langId}); + } + } + for (Entry>> entryLang : fStorage.entrySet()) { + serializeLanguage(elementProvider, entryLang); + } + return elementProvider; + } + + private void serializeLanguage(Element parentElement, Entry>> entryLang) { + String langId = entryLang.getKey(); + if (langId!=null) { + Element elementLanguage = XmlUtil.appendElement(parentElement, ELEM_LANGUAGE, new String[] {ATTR_ID, langId}); + parentElement = elementLanguage; + } + for (Entry> entryRc : entryLang.getValue().entrySet()) { + serializeResource(parentElement, entryRc); + } + } + + private void serializeResource(Element parentElement, Entry> entryRc) { + String rcProjectPath = entryRc.getKey(); + if (rcProjectPath!=null) { + Element elementRc = XmlUtil.appendElement(parentElement, ELEM_RESOURCE, new String[] {ATTR_PROJECT_PATH, rcProjectPath}); + parentElement = elementRc; + } + serializeSettingEntries(parentElement, entryRc.getValue()); + } + + private void serializeSettingEntries(Element parentElement, List settingEntries) { + for (ICLanguageSettingEntry entry : settingEntries) { + Element elementSettingEntry = XmlUtil.appendElement(parentElement, ELEM_ENTRY, new String[] { + ATTR_KIND, LanguageSettingEntriesSerializer.kindToString(entry.getKind()), + ATTR_NAME, entry.getName(), + }); + switch(entry.getKind()) { + case ICSettingEntry.MACRO: + elementSettingEntry.setAttribute(ATTR_VALUE, entry.getValue()); + break; +// case ICLanguageSettingEntry.LIBRARY_FILE: + // TODO: sourceAttachment fields need to be covered +// break; + } + int flags = entry.getFlags(); + if (flags!=0) { + // Element elementFlag = + XmlUtil.appendElement(elementSettingEntry, ELEM_FLAG, new String[] { + ATTR_VALUE, LanguageSettingEntriesSerializer.composeFlagsString(entry.getFlags()) + }); + } + } + } + + private ICLanguageSettingEntry loadSettingEntry(Node parentElement) { + String settingKind = XmlUtil.determineAttributeValue(parentElement, ATTR_KIND); + String settingName = XmlUtil.determineAttributeValue(parentElement, ATTR_NAME); + + NodeList flagNodes = parentElement.getChildNodes(); + int flags = 0; + for (int i=0;i settings = new ArrayList(); + NodeList nodes = providerNode.getChildNodes(); + for (int i=0;i0) { + setSettingEntriesInternal(null, null, settings); + } + } + } + + private void loadLanguageScopeElement(Node parentNode) { + if (languageScope==null) { + languageScope = new ArrayList(); + } + String id = XmlUtil.determineAttributeValue(parentNode, ATTR_ID); + languageScope.add(id); + + } + + private void loadLanguageElement(Node parentNode, String cfgId) { + String langId = XmlUtil.determineAttributeValue(parentNode, ATTR_ID); + if (langId.length()==0) { + langId=null; + } + + List settings = new ArrayList(); + NodeList nodes = parentNode.getChildNodes(); + for (int i=0;i0) { + setSettingEntriesInternal(null, langId, settings); + } + } + + private void loadResourceElement(Node parentNode, String cfgId, String langId) { + String rcProjectPath = XmlUtil.determineAttributeValue(parentNode, ATTR_PROJECT_PATH); + + List settings = new ArrayList(); + NodeList nodes = parentNode.getChildNodes(); + for (int i=0;i0) { + setSettingEntriesInternal(rcProjectPath, langId, settings); + } + } + + private Map>> cloneStorage() { + Map>> storageClone = new HashMap>>(); +// Set>>>> entrySetCfg = fStorage.entrySet(); +// for (Entry>>> entryCfg : entrySetCfg) { +// String cfgDescriptionId = entryCfg.getKey(); +// Map>> mapLang = entryCfg.getValue(); +// Map>> mapLangClone = new HashMap>>(); + Set>>> entrySetLang = fStorage.entrySet(); + for (Entry>> entryLang : entrySetLang) { + String langId = entryLang.getKey(); + Map> mapRc = entryLang.getValue(); + Map> mapRcClone = new HashMap>(); + Set>> entrySetRc = mapRc.entrySet(); + for (Entry> entryRc : entrySetRc) { + String rcProjectPath = entryRc.getKey(); + List lsEntries = entryRc.getValue(); + List lsEntriesClone = new ArrayList(lsEntries); + mapRcClone.put(rcProjectPath, lsEntriesClone); + } +// mapLangClone.put(langId, mapRcClone); + storageClone.put(langId, mapRcClone); + } +// } + return storageClone; + } + + protected LanguageSettingsSerializable cloneShallow() throws CloneNotSupportedException { + LanguageSettingsSerializable clone = (LanguageSettingsSerializable)super.clone(); + if (languageScope!=null) + clone.languageScope = new ArrayList(languageScope); + + clone.fStorage = new HashMap>>(); + return clone; + } + + /* (non-Javadoc) + * @see java.lang.Object#clone() + */ + @Override + protected LanguageSettingsSerializable clone() throws CloneNotSupportedException { + LanguageSettingsSerializable clone = cloneShallow(); + clone.fStorage = cloneStorage(); + return clone; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((getId() == null) ? 0 : getId().hashCode()); + result = prime * result + ((getName() == null) ? 0 : getName().hashCode()); + result = prime * result + ((languageScope == null) ? 0 : languageScope.hashCode()); + result = prime * result + ((customParameter == null) ? 0 : customParameter.hashCode()); + result = prime * result + ((fStorage == null) ? 0 : fStorage.hashCode()); + result = prime * result + getClass().hashCode(); + return result; + } + + /** + * @return {@code true} if the objects are equal, {@code false } otherwise. + * + * @see java.lang.Object#equals(java.lang.Object) + */ + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + LanguageSettingsSerializable other = (LanguageSettingsSerializable) obj; + + String id = getId(); + String otherId = other.getId(); + if (id == null) { + if (otherId != null) + return false; + } else if (!id.equals(otherId)) + return false; + + String name = getName(); + String otherName = other.getName(); + if (name == null) { + if (otherName != null) + return false; + } else if (!name.equals(otherName)) + return false; + + if (languageScope == null) { + if (other.languageScope != null) + return false; + } else if (!languageScope.equals(other.languageScope)) + return false; + + if (customParameter == null) { + if (other.customParameter != null) + return false; + } else if (!customParameter.equals(other.customParameter)) + return false; + + if (fStorage == null) { + if (other.fStorage != null) + return false; + } else if (!fStorage.equals(other.fStorage)) + return false; + return true; + } +} diff --git a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/core/language/settings/providers/LanguageSettingsSerializableEditable.java b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/core/language/settings/providers/LanguageSettingsSerializableEditable.java new file mode 100644 index 00000000000..1a0fe61a846 --- /dev/null +++ b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/core/language/settings/providers/LanguageSettingsSerializableEditable.java @@ -0,0 +1,28 @@ +/******************************************************************************* + * Copyright (c) 2009, 2011 Andrew Gvozdev 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: + * Andrew Gvozdev - initial API and implementation + *******************************************************************************/ + +package org.eclipse.cdt.core.language.settings.providers; + +// TODO: move ILanguageSettingsEditableProvider here +import org.eclipse.cdt.core.settings.model.ILanguageSettingsEditableProvider; + +public class LanguageSettingsSerializableEditable extends LanguageSettingsSerializable implements ILanguageSettingsEditableProvider { + @Override + public LanguageSettingsSerializableEditable clone() throws CloneNotSupportedException { + return (LanguageSettingsSerializableEditable) super.clone(); + } + + @Override + public LanguageSettingsSerializableEditable cloneShallow() throws CloneNotSupportedException { + return (LanguageSettingsSerializableEditable) super.cloneShallow(); + } + +} diff --git a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/core/settings/model/ACExclusionFilterEntry.java b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/core/settings/model/ACExclusionFilterEntry.java index 061696b7136..fc103cb66e4 100644 --- a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/core/settings/model/ACExclusionFilterEntry.java +++ b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/core/settings/model/ACExclusionFilterEntry.java @@ -36,8 +36,9 @@ public abstract class ACExclusionFilterEntry extends ACPathEntry implements ICEx this.exclusionPatterns = exclusionPatterns != null ? (IPath[])exclusionPatterns.clone() : new IPath[0]; } + /** @since 5.3 */ @Override - protected final boolean isFile() { + public final boolean isFile() { return false; } diff --git a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/core/settings/model/ACPathEntry.java b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/core/settings/model/ACPathEntry.java index 363b4d6a9a1..a7d0557d3e8 100644 --- a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/core/settings/model/ACPathEntry.java +++ b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/core/settings/model/ACPathEntry.java @@ -15,8 +15,7 @@ import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.Path; -public abstract class ACPathEntry extends ACSettingEntry - implements ICPathEntry { +public abstract class ACPathEntry extends ACSettingEntry implements ICPathEntry { // IPath fFullPath; // IPath fLocation; // private IPath fPath; @@ -67,7 +66,10 @@ public abstract class ACPathEntry extends ACSettingEntry return null; } - protected abstract boolean isFile(); + /** + * @since 5.3 + */ + public abstract boolean isFile(); public IPath getLocation() { if(!isValueWorkspacePath()) diff --git a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/core/settings/model/ICConfigurationDescription.java b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/core/settings/model/ICConfigurationDescription.java index 6e54e180496..e58bc9ad55a 100644 --- a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/core/settings/model/ICConfigurationDescription.java +++ b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/core/settings/model/ICConfigurationDescription.java @@ -10,9 +10,11 @@ *******************************************************************************/ package org.eclipse.cdt.core.settings.model; +import java.util.List; import java.util.Map; import org.eclipse.cdt.core.cdtvariables.ICdtVariablesContributor; +import org.eclipse.cdt.core.language.settings.providers.ILanguageSettingsProvider; import org.eclipse.cdt.core.model.CoreModel; import org.eclipse.cdt.core.settings.model.extension.CConfigurationData; import org.eclipse.cdt.core.settings.model.extension.CConfigurationDataProvider; @@ -386,4 +388,29 @@ public interface ICConfigurationDescription extends ICSettingContainer, ICSettin void updateExternalSettingsProviders(String[] ids) throws WriteAccessException; CConfigurationStatus getConfigurationStatus(); + + /** + * Sets the list of language settings providers. Language settings providers are + * used to supply language settings {@link ICLanguageSettingEntry} such as include paths + * or preprocessor macros. + * + * @param providers the list of providers to assign to the configuration description. + * + * @since 6.0 + */ + public void setLanguageSettingProviders(List providers); + + /** + * Returns the list of language settings providers. Language settings providers are + * used to supply language settings {@link ICLanguageSettingEntry} such as include paths + * or preprocessor macros. + * + * @return the list of providers to assign to the configuration description. This + * returns immutable list. Use {@link #setLanguageSettingProviders(List)} to change. + * This method does not return {@code null}. + * + * @since 6.0 + */ + public List getLanguageSettingProviders(); + } diff --git a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/core/settings/model/ICSettingEntry.java b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/core/settings/model/ICSettingEntry.java index 3adc824a568..4cef66d3750 100644 --- a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/core/settings/model/ICSettingEntry.java +++ b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/core/settings/model/ICSettingEntry.java @@ -46,6 +46,21 @@ public interface ICSettingEntry { */ int RESOLVED = 1 << 4; + /** + * Flag {@code UNDEFINED} indicates that the entry should not be defined. + * It's main purpose to provide the means to negate entries defined elsewhere. + * + * @since 6.0 + */ + int UNDEFINED = 1 << 5; + + /** + * Flag {@code FRAMEWORKS_MAC} applies for path entries. Such a path entry will be treated + * in a special way to imitate resolving paths by Apple's version of gcc, see bug 69529. + * . + */ + int FRAMEWORKS_MAC = 1 << 6; + int INCLUDE_PATH = 1; int INCLUDE_FILE = 1 << 1; int MACRO = 1 << 2; diff --git a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/core/settings/model/ILanguageSettingsEditableProvider.java b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/core/settings/model/ILanguageSettingsEditableProvider.java new file mode 100644 index 00000000000..7b15e893d76 --- /dev/null +++ b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/core/settings/model/ILanguageSettingsEditableProvider.java @@ -0,0 +1,34 @@ +/******************************************************************************* + * Copyright (c) 2009, 2009 Andrew Gvozdev (Quoin Inc.) 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: + * Andrew Gvozdev (Quoin Inc.) - initial API and implementation + *******************************************************************************/ + +package org.eclipse.cdt.core.settings.model; + +import java.util.List; + +import org.eclipse.cdt.core.language.settings.providers.ILanguageSettingsProvider; +import org.eclipse.cdt.core.language.settings.providers.LanguageSettingsSerializable; +import org.eclipse.core.resources.IResource; + +/** + * This interface is used in UI to identify classes allowing user to modify settings externally + * contrary to some subclasses of {@link LanguageSettingsSerializable} managing + * their settings themselves and not providing such option to the user. + * + */ +public interface ILanguageSettingsEditableProvider extends ILanguageSettingsProvider, Cloneable { + + public void setSettingEntries(ICConfigurationDescription cfgDescription, IResource rc, String languageId, List entries); + public boolean isEmpty(); + public void clear(); + + public ILanguageSettingsEditableProvider cloneShallow() throws CloneNotSupportedException; + public ILanguageSettingsEditableProvider clone() throws CloneNotSupportedException; +} diff --git a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/core/settings/model/util/LanguageSettingEntriesSerializer.java b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/core/settings/model/util/LanguageSettingEntriesSerializer.java index a889fa9f68f..7047e40fd55 100644 --- a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/core/settings/model/util/LanguageSettingEntriesSerializer.java +++ b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/core/settings/model/util/LanguageSettingEntriesSerializer.java @@ -59,6 +59,8 @@ public class LanguageSettingEntriesSerializer { public static final String LOCAL = "LOCAL"; //$NON-NLS-1$ public static final String VALUE_WORKSPACE_PATH = "VALUE_WORKSPACE_PATH"; //$NON-NLS-1$ public static final String RESOLVED = "RESOLVED"; //$NON-NLS-1$ + private static final String UNDEFINED = "UNDEFINED"; //$NON-NLS-1$ + private static final String FRAMEWORK = "FRAMEWORK"; //$NON-NLS-1$ public static final String FLAGS_SEPARATOR = "|"; //$NON-NLS-1$ @@ -280,10 +282,22 @@ public class LanguageSettingEntriesSerializer { buf.append(RESOLVED); } + if((flags & ICLanguageSettingEntry.UNDEFINED) != 0){ + if(buf.length() != 0) + buf.append(FLAGS_SEPARATOR); + + buf.append(UNDEFINED); + } + if((flags & ICLanguageSettingEntry.FRAMEWORKS_MAC) != 0){ + if(buf.length() != 0) + buf.append(FLAGS_SEPARATOR); + + buf.append(FRAMEWORK); + } return buf.toString(); } - private static int composeFlags(String flagsString){ + public static int composeFlags(String flagsString){ if(flagsString == null || flagsString.length() == 0) return 0; @@ -302,6 +316,10 @@ public class LanguageSettingEntriesSerializer { flags |= ICLanguageSettingEntry.VALUE_WORKSPACE_PATH; if(RESOLVED.equals(f)) flags |= ICLanguageSettingEntry.RESOLVED; + if(UNDEFINED.equals(f)) + flags |= ICLanguageSettingEntry.UNDEFINED; + if(FRAMEWORK.equals(f)) + flags |= ICLanguageSettingEntry.FRAMEWORKS_MAC; } return flags; diff --git a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/core/settings/model/util/PathEntryTranslator.java b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/core/settings/model/util/PathEntryTranslator.java index f399fdbbdde..e7a41760ebb 100644 --- a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/core/settings/model/util/PathEntryTranslator.java +++ b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/core/settings/model/util/PathEntryTranslator.java @@ -26,6 +26,7 @@ import org.eclipse.cdt.core.CCorePlugin; import org.eclipse.cdt.core.cdtvariables.CdtVariableException; import org.eclipse.cdt.core.cdtvariables.ICdtVariable; import org.eclipse.cdt.core.cdtvariables.ICdtVariableManager; +import org.eclipse.cdt.core.language.settings.providers.LanguageSettingsManager; import org.eclipse.cdt.core.model.CModelException; import org.eclipse.cdt.core.model.CoreModel; import org.eclipse.cdt.core.model.CoreModelUtil; @@ -68,6 +69,7 @@ import org.eclipse.cdt.internal.core.CharOperation; import org.eclipse.cdt.internal.core.cdtvariables.CoreVariableSubstitutor; import org.eclipse.cdt.internal.core.cdtvariables.DefaultVariableContextInfo; import org.eclipse.cdt.internal.core.cdtvariables.ICoreVariableContextInfo; +import org.eclipse.cdt.internal.core.language.settings.providers.LanguageSettingsLogger; import org.eclipse.cdt.internal.core.model.APathEntry; import org.eclipse.cdt.internal.core.model.CModelStatus; import org.eclipse.cdt.internal.core.model.PathEntry; @@ -2002,7 +2004,7 @@ public class PathEntryTranslator { } } - public static PathEntryCollector collectEntries(IProject project, ICConfigurationDescription des) { + public static PathEntryCollector collectEntries(IProject project, final ICConfigurationDescription des) { CConfigurationData data = getCfgData(des); ReferenceSettingsInfo refInfo = new ReferenceSettingsInfo(des); @@ -2036,10 +2038,12 @@ public class PathEntryTranslator { public boolean visit(PathSettingsContainer container) { CResourceData data = (CResourceData)container.getValue(); if (data != null) { + AG_log(des, kinds, data); // AG FIXME REMOVEME + PathEntryCollector child = cr.createChild(container.getPath()); for (int kind : kinds) { List list = new ArrayList(); - if (collectResourceDataEntries(kind, data, list)) { + if (collectResourceDataEntries(des, kind, data, list)) { ICLanguageSettingEntry[] entries = list.toArray(new ICLanguageSettingEntry[list.size()]); child.setEntries(kind, entries, exportedSettings); } @@ -2047,11 +2051,28 @@ public class PathEntryTranslator { } return true; } + + // AG FIXME REMOVEME + private void AG_log(final ICConfigurationDescription des, final int[] kinds, CResourceData data) { + String kindsStr=""; + for (int kind : kinds) { + String kstr = LanguageSettingEntriesSerializer.kindToString(kind); + if (kindsStr.length()==0) { + kindsStr = kstr; + } else { + kindsStr += "|" + kstr; + } + } + final IProject prj = des.getProjectDescription().getProject(); + String log_msg = "path="+prj+"/"+data.getPath()+", kind=["+kindsStr+"]"+" (PathEntryTranslator.collectEntries())"; + LanguageSettingsLogger.logInfo(log_msg); + } + }); return cr; } - private static boolean collectResourceDataEntries(int kind, CResourceData data, List list) { + private static boolean collectResourceDataEntries(ICConfigurationDescription des, int kind, CResourceData data, List list) { CLanguageData[] lDatas = null; if (data instanceof CFolderData) { lDatas = ((CFolderData)data).getLanguageDatas(); @@ -2068,6 +2089,17 @@ public class PathEntryTranslator { return false; } + + IProject project = des.getProjectDescription().getProject(); + if (LanguageSettingsManager.isLanguageSettingsProvidersEnabled(project)) { + IResource rc = getResource(project, data.getPath()); + for (CLanguageData lData : lDatas) { + list.addAll(LanguageSettingsManager.getSettingEntriesByKind(des, rc, lData.getLanguageId(), kind)); + } + return list.size()>0; + + } + // Legacy logic boolean supported = false; for (CLanguageData lData : lDatas) { if (collectLanguageDataEntries(kind, lData, list)) @@ -2092,4 +2124,14 @@ public class PathEntryTranslator { PathEntryCollector cr = collectEntries(project, cfg); return cr.getEntries(flags, cfg); } + + private static IResource getResource(IProject project, IPath workspacePath) { + IResource rc; + if (project!=null) { + rc = project.findMember(workspacePath); + } else { + rc = ResourcesPlugin.getWorkspace().getRoot().findMember(workspacePath); + } + return rc; + } } diff --git a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/language/settings/providers/LanguageSettingsExtensionManager.java b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/language/settings/providers/LanguageSettingsExtensionManager.java new file mode 100644 index 00000000000..d595114bea7 --- /dev/null +++ b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/language/settings/providers/LanguageSettingsExtensionManager.java @@ -0,0 +1,517 @@ +/******************************************************************************* + * Copyright (c) 2009, 2010 Andrew Gvozdev (Quoin Inc.) 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: + * Andrew Gvozdev (Quoin Inc.) - initial API and implementation + *******************************************************************************/ + +package org.eclipse.cdt.internal.core.language.settings.providers; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Set; +import java.util.TreeSet; + +import org.eclipse.cdt.core.AbstractExecutableExtensionBase; +import org.eclipse.cdt.core.CCorePlugin; +import org.eclipse.cdt.core.language.settings.providers.ILanguageSettingsProvider; +import org.eclipse.cdt.core.language.settings.providers.LanguageSettingsBaseProvider; +import org.eclipse.cdt.core.language.settings.providers.LanguageSettingsSerializable; +import org.eclipse.cdt.core.settings.model.ICConfigurationDescription; +import org.eclipse.cdt.core.settings.model.ICLanguageSettingEntry; +import org.eclipse.cdt.core.settings.model.ICSettingEntry; +import org.eclipse.cdt.core.settings.model.ILanguageSettingsEditableProvider; +import org.eclipse.cdt.core.settings.model.util.CDataUtil; +import org.eclipse.cdt.core.settings.model.util.LanguageSettingEntriesSerializer; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.IWorkspaceRoot; +import org.eclipse.core.runtime.Assert; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IConfigurationElement; +import org.eclipse.core.runtime.IExtension; +import org.eclipse.core.runtime.IExtensionPoint; +import org.eclipse.core.runtime.IExtensionRegistry; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Platform; +import org.eclipse.core.runtime.Status; + +/** + * Class {@code LanguageSettingsExtensionManager} manages {@link ILanguageSettingsProvider} extensions + */ +public class LanguageSettingsExtensionManager { + /** Name of the extension point for contributing language settings */ + final static String PROVIDER_EXTENSION_FULL_ID = "org.eclipse.cdt.core.LanguageSettingsProvider"; //$NON-NLS-1$ + final static String PROVIDER_EXTENSION_SIMPLE_ID = "LanguageSettingsProvider"; //$NON-NLS-1$ + + static final String ELEM_PROVIDER = "provider"; //$NON-NLS-1$ + static final String ATTR_CLASS = "class"; //$NON-NLS-1$ + static final String ATTR_ID = "id"; //$NON-NLS-1$ + static final String ATTR_NAME = "name"; //$NON-NLS-1$ + static final String ATTR_PARAMETER = "parameter"; //$NON-NLS-1$ + + static final String ELEM_LANGUAGE_SCOPE = "language-scope"; //$NON-NLS-1$ + + static final String ELEM_ENTRY = "entry"; //$NON-NLS-1$ + static final String ELEM_FLAG = "flag"; //$NON-NLS-1$ + static final String ATTR_KIND = "kind"; //$NON-NLS-1$ + static final String ATTR_VALUE = "value"; //$NON-NLS-1$ + + /** + * Extension providers loaded once. If the provider is editable (read cloneable) + * external callers get copy rather than real instance. + */ + private static final LinkedHashMap fExtensionProviders = new LinkedHashMap(); + + /** + * Providers loaded initially via static initializer. + */ + static { + try { + loadProviderExtensions(); + } catch (Throwable e) { + CCorePlugin.log("Error loading language settings providers extensions", e); //$NON-NLS-1$ + } finally { + } + } + + /** + * Load language settings providers contributed via the extension point. + */ + synchronized private static void loadProviderExtensions() { + // sort by name - for the providers taken from platform extensions + Set sortedProviders = new TreeSet( + new Comparator() { + public int compare(ILanguageSettingsProvider pr1, ILanguageSettingsProvider pr2) { + return pr1.getName().compareTo(pr2.getName()); + } + } + ); + + loadProviderExtensions(Platform.getExtensionRegistry(), sortedProviders); + + fExtensionProviders.clear(); + for (ILanguageSettingsProvider provider : sortedProviders) { + fExtensionProviders.put(provider.getId(), provider); + } + } + + /** + * Load contributed extensions from extension registry. + * + * @param registry - extension registry + * @param providers - resulting set of providers + */ + private static void loadProviderExtensions(IExtensionRegistry registry, Set providers) { + providers.clear(); + IExtensionPoint extension = registry.getExtensionPoint(CCorePlugin.PLUGIN_ID, PROVIDER_EXTENSION_SIMPLE_ID); + if (extension != null) { + IExtension[] extensions = extension.getExtensions(); + for (IExtension ext : extensions) { + for (IConfigurationElement cfgEl : ext.getConfigurationElements()) { + ILanguageSettingsProvider provider = null; + String id=null; + try { + if (cfgEl.getName().equals(ELEM_PROVIDER)) { + id = determineAttributeValue(cfgEl, ATTR_ID); + provider = createExecutableExtension(cfgEl); + configureExecutableProvider(provider, cfgEl); + providers.add(provider); + } + } catch (Throwable e) { + CCorePlugin.log("Cannot load LanguageSettingsProvider extension id=" + id, e); //$NON-NLS-1$ + } + } + } + } + } + + + private static String determineAttributeValue(IConfigurationElement ce, String attr) { + String value = ce.getAttribute(attr); + return value!=null ? value : ""; //$NON-NLS-1$ + } + + /** + * Creates empty non-configured provider as executable extension from extension point definition. + * If "class" attribute is empty {@link LanguageSettingsBaseProvider} is created. + * + * @param ce - configuration element with provider definition + * @return new non-configured provider + * @throws CoreException in case of failure + */ + private static ILanguageSettingsProvider createExecutableExtension(IConfigurationElement ce) throws CoreException { + String ceClass = ce.getAttribute(ATTR_CLASS); + ILanguageSettingsProvider provider = null; + if (ceClass==null || ceClass.trim().length()==0 || ceClass.equals(LanguageSettingsBaseProvider.class.getCanonicalName())) { + provider = new LanguageSettingsBaseProvider(); + } else { + provider = (ILanguageSettingsProvider)ce.createExecutableExtension(ATTR_CLASS); + } + + return provider; + } + + + /** + * Configure language settings provider with parameters defined in XML metadata. + * + * @param provider - empty non-configured provider. + * @param ce - configuration element from registry representing XML. + */ + private static void configureExecutableProvider(ILanguageSettingsProvider provider, IConfigurationElement ce) { + String ceId = determineAttributeValue(ce, ATTR_ID); + String ceName = determineAttributeValue(ce, ATTR_NAME); + String ceParameter = determineAttributeValue(ce, ATTR_PARAMETER); + List languages = null; + List entries = null; + + for (IConfigurationElement ceLang : ce.getChildren(ELEM_LANGUAGE_SCOPE)) { + String langId = determineAttributeValue(ceLang, ATTR_ID); + if (langId.trim().length()>0) { + if (languages==null) { + languages = new ArrayList(); + } + languages.add(langId); + } + } + + for (IConfigurationElement ceEntry : ce.getChildren(ELEM_ENTRY)) { + try { + int entryKind = LanguageSettingEntriesSerializer.stringToKind(determineAttributeValue(ceEntry, ATTR_KIND)); + String entryName = determineAttributeValue(ceEntry, ATTR_NAME); + String entryValue = determineAttributeValue(ceEntry, ATTR_VALUE); + + int flags = 0; + for (IConfigurationElement ceFlags : ceEntry.getChildren(ELEM_FLAG)) { + int bitFlag = LanguageSettingEntriesSerializer.composeFlags(determineAttributeValue(ceFlags, ATTR_VALUE)); + flags |= bitFlag; + } + + ICLanguageSettingEntry entry = (ICLanguageSettingEntry) CDataUtil.createEntry( + entryKind, entryName, entryValue, null, flags); + + if (entries == null) + entries = new ArrayList(); + entries.add(entry); + + } catch (Exception e) { + CCorePlugin.log("Error creating language settings entry ", e); //$NON-NLS-1$ + } + } + + if (provider instanceof LanguageSettingsBaseProvider) { + ((LanguageSettingsBaseProvider) provider).configureProvider(ceId, ceName, languages, entries, ceParameter); + } else if (provider instanceof AbstractExecutableExtensionBase) { + ((AbstractExecutableExtensionBase) provider).setId(ceId); + ((AbstractExecutableExtensionBase) provider).setName(ceName); + } + } + + /** + * Creates empty non-configured provider from extension point definition. The method will + * inspect extension registry for extension point "org.eclipse.cdt.core.LanguageSettingsProvider" + * to determine bundle and instantiate the class. + * ID and name of provider are assigned from first extension point encountered. + * + * @param className - full qualified class name of provider. + * @param registry - extension registry + * @return new non-configured provider + */ + private static ILanguageSettingsProvider createProviderCarcass(String className, IExtensionRegistry registry) { + if (className==null || className.length()==0) { + return new LanguageSettingsBaseProvider(); + } + + try { + IExtensionPoint extension = registry.getExtensionPoint(CCorePlugin.PLUGIN_ID, PROVIDER_EXTENSION_SIMPLE_ID); + if (extension != null) { + IExtension[] extensions = extension.getExtensions(); + for (IExtension ext : extensions) { + for (IConfigurationElement cfgEl : ext.getConfigurationElements()) { + if (cfgEl.getName().equals(ELEM_PROVIDER) && className.equals(cfgEl.getAttribute(ATTR_CLASS))) { + ILanguageSettingsProvider provider = createExecutableExtension(cfgEl); + if (provider instanceof AbstractExecutableExtensionBase) { + String ceId = determineAttributeValue(cfgEl, ATTR_ID); + String ceName = determineAttributeValue(cfgEl, ATTR_NAME); + ((AbstractExecutableExtensionBase) provider).setId(ceId); + ((AbstractExecutableExtensionBase) provider).setName(ceName); + } + return provider; + } + } + } + } + } catch (Exception e) { + CCorePlugin.log("Error creating language settings provider.", e); //$NON-NLS-1$ + } + return null; + } + + /** + * Create an instance of language settings provider of given class name. + * + * @param className - class name to instantiate. + * @return new instance of language settings provider. + */ + /*package*/ static ILanguageSettingsProvider getProviderInstance(String className) { + if (className==null || className.equals(LanguageSettingsSerializable.class.getName())) { + return new LanguageSettingsSerializable(); + } + + ILanguageSettingsProvider provider = createProviderCarcass(className, Platform.getExtensionRegistry()); + if (provider==null) { + IStatus status = new Status(IStatus.ERROR, CCorePlugin.PLUGIN_ID, "Not able to load provider class=" + className); + CCorePlugin.log(new CoreException(status)); + } + return provider; + } + + /** + * Get Language Settings Provider defined via + * {@code org.eclipse.cdt.core.LanguageSettingsProvider} extension point. + * + * @param id - ID of provider to find. + * @return the clone of the provider or {@code null} if provider is not defined. + * @throws CloneNotSupportedException if the provider is not cloneable + */ + public static ILanguageSettingsProvider getExtensionProviderClone(String id) throws CloneNotSupportedException { + ILanguageSettingsProvider provider = fExtensionProviders.get(id); + if (provider!=null) { + if (!(provider instanceof ILanguageSettingsEditableProvider)) + throw new CloneNotSupportedException("Not able to clone provider " + provider.getClass()); + + provider = ((ILanguageSettingsEditableProvider) provider).clone(); + } + return provider; + } + + /** + * TODO + * + * @param id + * @return + */ + public static ILanguageSettingsProvider getExtensionProviderShallow(String id) { + ILanguageSettingsProvider provider = fExtensionProviders.get(id); + if (provider instanceof ILanguageSettingsEditableProvider) { + try { + return ((ILanguageSettingsEditableProvider) provider).cloneShallow(); + } catch (CloneNotSupportedException e) { + IStatus status = new Status(IStatus.ERROR, CCorePlugin.PLUGIN_ID, "Not able to clone provider " + provider.getClass()); + CCorePlugin.log(new CoreException(status)); + return null; + } + } + return provider; + } + + /** + * @return list of providers contributed by all extensions. Preferable copy but if not possible + * will return raw provider. + */ + /*package*/ static List getExtensionProvidersInternal() { + ArrayList list = new ArrayList(fExtensionProviders.size()); + for (String id : fExtensionProviders.keySet()) { + ILanguageSettingsProvider extensionProvider = null; + try { + extensionProvider = getExtensionProviderClone(id); + } catch (CloneNotSupportedException e) { + // from here falls to get raw extension provider + } + if (extensionProvider==null) + extensionProvider = fExtensionProviders.get(id); + + if (extensionProvider!=null) + list.add(extensionProvider); + } + return list; + } + + private static List safeGetSettingEntries(ILanguageSettingsProvider provider, + ICConfigurationDescription cfgDescription, IResource rc, String languageId) { + + try { + return provider.getSettingEntries(cfgDescription, rc, languageId); + } catch (Throwable e) { + String cfgId = cfgDescription!=null ? cfgDescription.getId() : null; + String msg = "Exception in provider "+provider.getId()+": getSettingEntries("+cfgId+", "+rc+", "+languageId+")"; + CCorePlugin.log(msg, e); + // return empty array to prevent climbing up the resource tree + return new ArrayList(0); + } + } + + /** + * Returns the list of setting entries of the given provider + * for the given configuration description, resource and language. + * This method reaches to the parent folder of the resource recursively + * in case the resource does not define the entries for the given provider. + * + * @param provider - language settings provider. + * @param cfgDescription - configuration description. + * @param rc - resource such as file or folder. + * @param languageId - language id. + * + * @return the list of setting entries. Never returns {@code null} + * although individual providers mandated to return {@code null} if no settings defined. + */ + public static List getSettingEntriesUpResourceTree(ILanguageSettingsProvider provider, ICConfigurationDescription cfgDescription, IResource rc, String languageId) { + Assert.isTrue( !(rc instanceof IWorkspaceRoot) ); + if (provider!=null) { + List entries = safeGetSettingEntries(provider, cfgDescription, rc, languageId); + if (entries!=null) { + return new ArrayList(entries); + } + if (rc!=null) { + IResource parentFolder = (rc instanceof IProject) ? null : rc.getParent(); + if (parentFolder!=null) { + return getSettingEntriesUpResourceTree(provider, cfgDescription, parentFolder, languageId); + } + // if out of parent resources - get default entries for the applicable language scope + entries = safeGetSettingEntries(provider, null, null, languageId); + if (entries!=null) { + return new ArrayList(entries); + } + } + } + + return new ArrayList(0); + } + + private static boolean checkBit(int flags, int bit) { + return (flags & bit) == bit; + } + + /** + * Returns the list of setting entries of a certain kind (such as include paths) + * for the given configuration description, resource and language. This is a + * combined list for all providers taking into account settings of parent folder + * if settings for the given resource are not defined. + * + * @param cfgDescription - configuration description. + * @param rc - resource such as file or folder. + * @param languageId - language id. + * @param kind - kind of language settings entries, such as + * {@link ICSettingEntry#INCLUDE_PATH} etc. This is a binary flag + * and it is possible to specify composite kind. + * Use {@link ICSettingEntry#ALL} to get all kinds. + * @param checkLocality - specifies if parameter {@code isLocal} should be considered. + * @param isLocal - {@code true} if "local" entries should be provided and + * {@code false} for "system" entries. This makes sense for include paths where + * [#include "..."] is "local" and [#include <...>] is system. + * + * @return the list of setting entries found. + */ + private static List getSettingEntriesByKind(ICConfigurationDescription cfgDescription, + IResource rc, String languageId, int kind, boolean checkLocality, boolean isLocal) { + + List entries = new ArrayList(); + List alreadyAdded = new ArrayList(); + + List providers = cfgDescription.getLanguageSettingProviders(); + for (ILanguageSettingsProvider provider: providers) { + List providerEntries = getSettingEntriesUpResourceTree(provider, cfgDescription, rc, languageId); + for (ICLanguageSettingEntry entry : providerEntries) { + if (entry!=null) { + String entryName = entry.getName(); + boolean isRightKind = (entry.getKind() & kind) != 0; + // Only first entry is considered + // Entry flagged as "UNDEFINED" prevents adding entry with the same name down the line + if (isRightKind && !alreadyAdded.contains(entryName)) { + int flags = entry.getFlags(); + boolean isRightLocal = !checkLocality || (checkBit(flags, ICSettingEntry.LOCAL) == isLocal); + if (isRightLocal) { + if (!checkBit(flags, ICSettingEntry.UNDEFINED)) { + entries.add(entry); + } + alreadyAdded.add(entryName); + } + } + } + } + } + + return entries; + } + + /** + * Returns the list of setting entries of a certain kind (such as include paths) + * for the given configuration description, resource and language. This is a + * combined list for all providers taking into account settings of parent folder + * if settings for the given resource are not defined. For include paths both + * local (#include "...") and system (#include <...>) entries are returned. + * + * @param cfgDescription - configuration description. + * @param rc - resource such as file or folder. + * @param languageId - language id. + * @param kind - kind of language settings entries, such as + * {@link ICSettingEntry#INCLUDE_PATH} etc. This is a binary flag + * and it is possible to specify composite kind. + * Use {@link ICSettingEntry#ALL} to get all kinds. + * + * @return the list of setting entries. + */ + public static List getSettingEntriesByKind(ICConfigurationDescription cfgDescription, IResource rc, String languageId, int kind) { + return getSettingEntriesByKind(cfgDescription, rc, languageId, kind, /* checkLocality */ false, /* isLocal */ false); + } + + /** + * Returns the list of "system" (such as [#include <...>]) setting entries of a certain kind + * for the given configuration description, resource and language. This is a + * combined list for all providers taking into account settings of parent folder + * if settings for the given resource are not defined. + * + * @param cfgDescription - configuration description. + * @param rc - resource such as file or folder. + * @param languageId - language id. + * @param kind - kind of language settings entries, such as + * {@link ICSettingEntry#INCLUDE_PATH} etc. This is a binary flag + * and it is possible to specify composite kind. + * Use {@link ICSettingEntry#ALL} to get all kinds. + * + * @return the list of setting entries. + */ + public static List getSystemSettingEntriesByKind(ICConfigurationDescription cfgDescription, IResource rc, String languageId, int kind) { + return getSettingEntriesByKind(cfgDescription, rc, languageId, kind, /* checkLocality */ true, /* isLocal */ false); + } + + /** + * Returns the list of "local" (such as [#include "..."]) setting entries of a certain kind + * for the given configuration description, resource and language. This is a + * combined list for all providers taking into account settings of parent folder + * if settings for the given resource are not defined. + * + * @param cfgDescription - configuration description. + * @param rc - resource such as file or folder. + * @param languageId - language id. + * @param kind - kind of language settings entries, such as + * {@link ICSettingEntry#INCLUDE_PATH} etc. This is a binary flag + * and it is possible to specify composite kind. + * Use {@link ICSettingEntry#ALL} to get all kinds. + * + * @return the list of setting entries. + */ + public static List getLocalSettingEntriesByKind(ICConfigurationDescription cfgDescription, IResource rc, String languageId, int kind) { + return getSettingEntriesByKind(cfgDescription, rc, languageId, kind, /* checkLocality */ true, /* isLocal */ true); + } + + public static boolean equalsExtensionProviderShallow(ILanguageSettingsEditableProvider provider) throws CloneNotSupportedException { + String id = provider.getId(); + ILanguageSettingsProvider extensionProviderShallow = getExtensionProviderShallow(id); + return provider.cloneShallow().equals(extensionProviderShallow); + } + + public static boolean equalsExtensionProvider(ILanguageSettingsProvider provider) { + String id = provider.getId(); + ILanguageSettingsProvider extensionProvider = fExtensionProviders.get(id); + return provider.equals(extensionProvider); + } + +} diff --git a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/language/settings/providers/LanguageSettingsLogger.java b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/language/settings/providers/LanguageSettingsLogger.java new file mode 100644 index 00000000000..7483b4100bf --- /dev/null +++ b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/language/settings/providers/LanguageSettingsLogger.java @@ -0,0 +1,79 @@ +package org.eclipse.cdt.internal.core.language.settings.providers; + +import org.eclipse.cdt.core.CCorePlugin; +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; + +@Deprecated +public class LanguageSettingsLogger { + + /** + * + */ + private static final boolean ENABLED = false; + + // AG FIXME + /** + * @param msg + * @noreference This method is not intended to be referenced by clients. + */ + @Deprecated + public static void logInfo(String msg) { + if (ENABLED) { + Exception e = new Exception(msg); + IStatus status = new Status(IStatus.INFO, CCorePlugin.PLUGIN_ID, msg, e); + CCorePlugin.log(status); + } + } + + // AG FIXME + /** + * @param msg + * @noreference This method is not intended to be referenced by clients. + */ + @Deprecated + public static void logWarning(String msg) { + if (ENABLED) { + Exception e = new Exception(msg); + IStatus status = new Status(IStatus.WARNING, CCorePlugin.PLUGIN_ID, msg, e); + CCorePlugin.log(status); + } + } + + // AG FIXME + /** + * @param msg + * @noreference This method is not intended to be referenced by clients. + */ + @Deprecated + public static void logError(String msg) { + if (ENABLED) { + Exception e = new Exception(msg); + IStatus status = new Status(IStatus.ERROR, CCorePlugin.PLUGIN_ID, msg, e); + CCorePlugin.log(status); + } + } + + // AG FIXME + /** + * @param rc + * @param who - pass "this" (calling class instance) here + * @noreference This method is not intended to be referenced by clients. + */ + @Deprecated + public static void logScannerInfoProvider(IResource rc, Object who) { + if (ENABLED) { + String msg = "rc="+rc+" <-- "+who.getClass().getSimpleName(); + if (rc instanceof IFile) { + LanguageSettingsLogger.logInfo(msg); + } else if (rc instanceof IProject) { + LanguageSettingsLogger.logWarning(msg); + } else { + LanguageSettingsLogger.logError(msg); + } + } + } +} \ No newline at end of file diff --git a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/language/settings/providers/LanguageSettingsProvidersSerializer.java b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/language/settings/providers/LanguageSettingsProvidersSerializer.java new file mode 100644 index 00000000000..6868b13c53d --- /dev/null +++ b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/language/settings/providers/LanguageSettingsProvidersSerializer.java @@ -0,0 +1,456 @@ +package org.eclipse.cdt.internal.core.language.settings.providers; + +import java.net.URI; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.eclipse.cdt.core.CCorePlugin; +import org.eclipse.cdt.core.language.settings.providers.ILanguageSettingsProvider; +import org.eclipse.cdt.core.language.settings.providers.LanguageSettingsSerializable; +import org.eclipse.cdt.core.settings.model.ICConfigurationDescription; +import org.eclipse.cdt.core.settings.model.ICLanguageSettingEntry; +import org.eclipse.cdt.core.settings.model.ICProjectDescription; +import org.eclipse.cdt.core.settings.model.ILanguageSettingsEditableProvider; +import org.eclipse.cdt.internal.core.XmlUtil; +import org.eclipse.core.filesystem.URIUtil; +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IFolder; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.runtime.Assert; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +public class LanguageSettingsProvidersSerializer { + + private static final String STORAGE_WORKSPACE_LANGUAGE_SETTINGS = "language.settings.xml"; //$NON-NLS-1$ + private static final String SETTINGS_FOLDER_NAME = ".settings/"; //$NON-NLS-1$ + private static final String STORAGE_PROJECT_LANGUAGE_SETTINGS = "language.settings.xml"; //$NON-NLS-1$ + public static final char PROVIDER_DELIMITER = ';'; + private static final String MBS_LANGUAGE_SETTINGS_PROVIDER = "org.eclipse.cdt.managedbuilder.core.LanguageSettingsProvider"; + private static final String ELEM_PLUGIN = "plugin"; //$NON-NLS-1$ + private static final String ELEM_EXTENSION = "extension"; //$NON-NLS-1$ + private static final String ATTR_POINT = "point"; //$NON-NLS-1$ + private static final String ELEM_PROJECT = "project"; //$NON-NLS-1$ + private static final String ELEM_CONFIGURATION = "configuration"; //$NON-NLS-1$ + private static final String ELEM_PROVIDER_REFERENCE = "provider-reference"; //$NON-NLS-1$ + /** Cache of globally available providers to be consumed by calling clients */ + private static Map rawGlobalWorkspaceProviders = new HashMap(); + private static Object serializingLock = new Object(); + + private static class LanguageSettingsWorkspaceProvider implements ILanguageSettingsProvider { + private String providerId; + + public LanguageSettingsWorkspaceProvider(String id) { + Assert.isNotNull(id); + Assert.isTrue(id.length()>0); + providerId = id; + } + + public String getId() { + return providerId; + } + + public String getName() { + ILanguageSettingsProvider rawProvider = getRawProvider(); + String name = rawProvider!=null ? rawProvider.getName() : null; + return name; + } + + public List getSettingEntries(ICConfigurationDescription cfgDescription, IResource rc, String languageId) { + ILanguageSettingsProvider rawProvider = getRawProvider(); + List entries = rawProvider!=null ? rawProvider.getSettingEntries(cfgDescription, rc, languageId) : null; + return entries; + } + + /** + * Do not cache the "raw" provider as workspace provider can be changed at any time. + */ + private ILanguageSettingsProvider getRawProvider() { + return LanguageSettingsProvidersSerializer.getRawWorkspaceProvider(providerId); + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof LanguageSettingsWorkspaceProvider) { + LanguageSettingsWorkspaceProvider that = (LanguageSettingsWorkspaceProvider) obj; + return providerId.equals(that.providerId); + } + return false; + } + /** + * Method toString() for debugging purposes. + */ + @SuppressWarnings("nls") + @Override + public String toString() { + return "id="+getId()+", name="+getName(); + } + } + + + /** static initializer */ + static { + try { + loadLanguageSettingsWorkspace(); + } catch (Throwable e) { + CCorePlugin.log("Error loading workspace language settings providers", e); //$NON-NLS-1$ + } finally { + } + } + + /** + * Set and store in workspace area user defined providers. + * + * @param providers - array of user defined providers + * @throws CoreException in case of problems + */ + public static void setWorkspaceProviders(List providers) throws CoreException { + setWorkspaceProvidersInternal(providers); + serializeLanguageSettingsWorkspace(); + } + + /** + * Internal method to set user defined providers in memory. + * + * @param providers - list of user defined providers. If {@code null} + * is passed user defined providers are cleared. + */ + private static void setWorkspaceProvidersInternal(List providers) { + Map rawWorkspaceProviders = new HashMap(); + List extensionProviders = new ArrayList(LanguageSettingsExtensionManager.getExtensionProvidersInternal()); + for (ILanguageSettingsProvider rawExtensionProvider : extensionProviders) { + if (rawExtensionProvider!=null) { + rawWorkspaceProviders.put(rawExtensionProvider.getId(), rawExtensionProvider); + } + } + + if (providers!=null) { + List rawProviders = new ArrayList(); + for (ILanguageSettingsProvider provider : providers) { + if (isWorkspaceProvider(provider)) { + provider = rawGlobalWorkspaceProviders.get(provider.getId()); + } + if (provider!=null) { + rawProviders.add(provider); + } + } + for (ILanguageSettingsProvider provider : rawProviders) { + rawWorkspaceProviders.put(provider.getId(), provider); + } + } + + rawGlobalWorkspaceProviders = rawWorkspaceProviders; + } + + /** + * TODO: refactor with ErrorParserManager + * + * @param store - name of the store + * @return location of the store in the plug-in state area + */ + private static URI getStoreLocation(String store) { + IPath location = CCorePlugin.getDefault().getStateLocation().append(store); + URI uri = URIUtil.toURI(location); + return uri; + } + + public static void serializeLanguageSettingsWorkspace() throws CoreException { + URI uriLocation = getStoreLocation(STORAGE_WORKSPACE_LANGUAGE_SETTINGS); + List serializableExtensionProviders = new ArrayList(); + for (ILanguageSettingsProvider provider : rawGlobalWorkspaceProviders.values()) { + if (provider instanceof LanguageSettingsSerializable) { + // serialize all editable providers which are different from corresponding extension + // and serialize all serializable ones that are not editable (those are singletons and we don't know whether they changed) + if (!(provider instanceof ILanguageSettingsEditableProvider) || !LanguageSettingsExtensionManager.equalsExtensionProvider(provider)) { + serializableExtensionProviders.add((LanguageSettingsSerializable)provider); + } + } + } + try { + if (serializableExtensionProviders.isEmpty()) { + java.io.File file = new java.io.File(uriLocation); + synchronized (serializingLock) { + file.delete(); + } + return; + } + + Document doc = XmlUtil.newDocument(); + Element rootElement = XmlUtil.appendElement(doc, ELEM_PLUGIN); + Element elementExtension = XmlUtil.appendElement(rootElement, ELEM_EXTENSION, new String[] {ATTR_POINT, LanguageSettingsExtensionManager.PROVIDER_EXTENSION_FULL_ID}); + + for (LanguageSettingsSerializable provider : serializableExtensionProviders) { + provider.serialize(elementExtension); + } + + synchronized (serializingLock) { + XmlUtil.serializeXml(doc, uriLocation); + } + + } catch (Exception e) { + CCorePlugin.log("Internal error while trying to serialize language settings", e); //$NON-NLS-1$ + IStatus s = new Status(IStatus.ERROR, CCorePlugin.PLUGIN_ID, "Internal error while trying to serialize language settings", e); + throw new CoreException(s); + } + } + + public static void loadLanguageSettingsWorkspace() throws CoreException { + List providers = null; + + URI uriLocation = getStoreLocation(STORAGE_WORKSPACE_LANGUAGE_SETTINGS); + + Document doc = null; + try { + synchronized (serializingLock) { + doc = XmlUtil.loadXml(uriLocation); + } + } catch (Exception e) { + CCorePlugin.log("Can't load preferences from file "+uriLocation, e); //$NON-NLS-1$ + } + + if (doc!=null) { + Element rootElement = doc.getDocumentElement(); + NodeList providerNodes = rootElement.getElementsByTagName(LanguageSettingsSerializable.ELEM_PROVIDER); + + List userDefinedProvidersIds = new ArrayList(); + for (int i=0;i(); + + if (!LanguageSettingsExtensionManager.equalsExtensionProvider(provider)) { + providers.add(provider); + } + } + } + } + setWorkspaceProvidersInternal(providers); + } + + public static void serializeLanguageSettings(Element parentElement, ICProjectDescription prjDescription) throws CoreException { + ICConfigurationDescription[] cfgDescriptions = prjDescription.getConfigurations(); + for (ICConfigurationDescription cfgDescription : cfgDescriptions) { + Element elementConfiguration = XmlUtil.appendElement(parentElement, ELEM_CONFIGURATION, new String[] { + LanguageSettingsExtensionManager.ATTR_ID, cfgDescription.getId(), + LanguageSettingsExtensionManager.ATTR_NAME, cfgDescription.getName(), + }); + List providers = cfgDescription.getLanguageSettingProviders(); + if (providers.size()>0) { + Element elementExtension = XmlUtil.appendElement(elementConfiguration, ELEM_EXTENSION, new String[] { + ATTR_POINT, LanguageSettingsExtensionManager.PROVIDER_EXTENSION_FULL_ID}); + for (ILanguageSettingsProvider provider : providers) { + if (isWorkspaceProvider(provider)) { + // Element elementProviderReference = + XmlUtil.appendElement(elementExtension, ELEM_PROVIDER_REFERENCE, new String[] { + LanguageSettingsExtensionManager.ATTR_ID, provider.getId()}); + continue; + } + if (provider instanceof LanguageSettingsSerializable) { + ((LanguageSettingsSerializable) provider).serialize(elementExtension); + } else { + // Element elementProvider = + XmlUtil.appendElement(elementExtension, LanguageSettingsExtensionManager.ELEM_PROVIDER, new String[] { + LanguageSettingsExtensionManager.ATTR_ID, provider.getId(), + LanguageSettingsExtensionManager.ATTR_NAME, provider.getName(), + LanguageSettingsExtensionManager.ATTR_CLASS, provider.getClass().getCanonicalName(), + }); + } + } + } + } + } + + private static IFile getStorage(IProject project) throws CoreException { + IFolder folder = project.getFolder(SETTINGS_FOLDER_NAME); + if (!folder.exists()) { + folder.create(true, true, null); + } + IFile storage = folder.getFile(STORAGE_PROJECT_LANGUAGE_SETTINGS); + return storage; + } + + public static void serializeLanguageSettings(ICProjectDescription prjDescription) throws CoreException { + IProject project = prjDescription.getProject(); + try { + Document doc = XmlUtil.newDocument(); + Element rootElement = XmlUtil.appendElement(doc, ELEM_PROJECT); + serializeLanguageSettings(rootElement, prjDescription); + + IFile file = getStorage(project); + synchronized (serializingLock){ + XmlUtil.serializeXml(doc, file); + } + + } catch (Exception e) { + IStatus s = new Status(IStatus.ERROR, CCorePlugin.PLUGIN_ID, "Internal error while trying to serialize language settings", e); + CCorePlugin.log(s); + throw new CoreException(s); + } + } + + public static void loadLanguageSettings(Element parentElement, ICProjectDescription prjDescription) { + /* + + + + + + + + + */ + NodeList configurationNodes = parentElement.getChildNodes(); + for (int ic=0;ic providers = new ArrayList(); + String cfgId = XmlUtil.determineAttributeValue(cfgNode, LanguageSettingsExtensionManager.ATTR_ID); + @SuppressWarnings("unused") + String cfgName = XmlUtil.determineAttributeValue(cfgNode, LanguageSettingsExtensionManager.ATTR_NAME); + + NodeList extensionAndReferenceNodes = cfgNode.getChildNodes(); + for (int ie=0;ie + loadLanguageSettings(rootElement, prjDescription); + } catch (Exception e) { + CCorePlugin.log("Can't load preferences from file "+file.getLocation(), e); //$NON-NLS-1$ + } + + if (doc!=null) { + } + + } else { + // Already existing legacy projects + ICConfigurationDescription[] cfgDescriptions = prjDescription.getConfigurations(); + for (ICConfigurationDescription cfgDescription : cfgDescriptions) { + if (cfgDescription!=null) { + List providers = new ArrayList(2); + ILanguageSettingsProvider userProvider = getWorkspaceProvider(MBS_LANGUAGE_SETTINGS_PROVIDER); + providers.add(userProvider); + cfgDescription.setLanguageSettingProviders(providers); + } + } + + } + } + + /** + * FIXME Get Language Settings Provider defined in the workspace. That includes user-defined + * providers and after that providers defined as extensions via + * {@code org.eclipse.cdt.core.LanguageSettingsProvider} extension point. + * That returns actual object, any modifications will affect any configuration + * referring to the provider. + * + * @param id - ID of provider to find. + * @return the provider or {@code null} if provider is not defined. + */ + public static ILanguageSettingsProvider getWorkspaceProvider(String id) { + return new LanguageSettingsWorkspaceProvider(id); + } + + public static ILanguageSettingsProvider getRawWorkspaceProvider(String id) { + return rawGlobalWorkspaceProviders.get(id); + } + + /** + * TODO + * @return ordered set of providers defined in the workspace which include contributed through extension + user defined ones + * + */ + public static List getWorkspaceProviders() { + ArrayList workspaceProviders = new ArrayList(); + for (ILanguageSettingsProvider rawProvider : rawGlobalWorkspaceProviders.values()) { + workspaceProviders.add(new LanguageSettingsWorkspaceProvider(rawProvider.getId())); + } + return workspaceProviders; + } + + /** + * Checks if the provider is defined on the workspace level. + * + * @param provider - provider to check. + * @return {@code true} if the given provider is workspace provider, {@code false} otherwise. + * + */ + public static boolean isWorkspaceProvider(ILanguageSettingsProvider provider) { + return provider instanceof LanguageSettingsWorkspaceProvider; + } +} \ No newline at end of file diff --git a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/language/settings/providers/LanguageSettingsScannerInfoProvider.java b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/language/settings/providers/LanguageSettingsScannerInfoProvider.java new file mode 100644 index 00000000000..0b6f4b8a1c5 --- /dev/null +++ b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/language/settings/providers/LanguageSettingsScannerInfoProvider.java @@ -0,0 +1,325 @@ +/******************************************************************************* + * Copyright (c) 2010, 2010 Andrew Gvozdev (Quoin Inc.) 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: + * Andrew Gvozdev (Quoin Inc.) - initial API and implementation + *******************************************************************************/ + +package org.eclipse.cdt.internal.core.language.settings.providers; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; + +import org.eclipse.cdt.core.CCorePlugin; +import org.eclipse.cdt.core.cdtvariables.CdtVariableException; +import org.eclipse.cdt.core.cdtvariables.ICdtVariableManager; +import org.eclipse.cdt.core.model.ILanguage; +import org.eclipse.cdt.core.model.LanguageManager; +import org.eclipse.cdt.core.parser.ExtendedScannerInfo; +import org.eclipse.cdt.core.parser.IScannerInfoChangeListener; +import org.eclipse.cdt.core.parser.IScannerInfoProvider; +import org.eclipse.cdt.core.settings.model.ACPathEntry; +import org.eclipse.cdt.core.settings.model.ICConfigurationDescription; +import org.eclipse.cdt.core.settings.model.ICFolderDescription; +import org.eclipse.cdt.core.settings.model.ICLanguageSetting; +import org.eclipse.cdt.core.settings.model.ICLanguageSettingEntry; +import org.eclipse.cdt.core.settings.model.ICLanguageSettingPathEntry; +import org.eclipse.cdt.core.settings.model.ICMacroEntry; +import org.eclipse.cdt.core.settings.model.ICProjectDescription; +import org.eclipse.cdt.core.settings.model.ICSettingEntry; +import org.eclipse.cdt.internal.core.settings.model.CProjectDescriptionManager; +import org.eclipse.cdt.internal.core.settings.model.SettingsModelMessages; +import org.eclipse.core.resources.IContainer; +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Path; +import org.eclipse.core.runtime.Status; +import org.eclipse.osgi.util.NLS; + +/** + * Implementation of {@link IScannerInfoProvider} backed by the list of + * language settings providers of "default settings configuration" + * (see {@link ICProjectDescription#getDefaultSettingConfiguration()}). + * + */ +public class LanguageSettingsScannerInfoProvider implements IScannerInfoProvider { + private static final ExtendedScannerInfo DUMMY_SCANNER_INFO = new ExtendedScannerInfo(); + + public ExtendedScannerInfo getScannerInformation(IResource rc) { + // AG FIXME + LanguageSettingsLogger.logScannerInfoProvider(rc, this); + + IProject project = rc.getProject(); + if (project==null) + return DUMMY_SCANNER_INFO; + + ICProjectDescription prjDescription = CProjectDescriptionManager.getInstance().getProjectDescription(project, false); + if (prjDescription==null) + return DUMMY_SCANNER_INFO; + + ICConfigurationDescription cfgDescription = prjDescription.getDefaultSettingConfiguration(); + if (cfgDescription==null) + return DUMMY_SCANNER_INFO; + + List languageIds = getLanguageIds(cfgDescription, rc); + if (languageIds==null || languageIds.size()==0) { + return DUMMY_SCANNER_INFO; + } + + LinkedHashSet includePathEntries = new LinkedHashSet(); + LinkedHashSet includePathLocalEntries = new LinkedHashSet(); + LinkedHashSet includeFileEntries = new LinkedHashSet(); + LinkedHashSet macroFileEntries = new LinkedHashSet(); + LinkedHashSet macroEntries = new LinkedHashSet(); + + for (String langId : languageIds) { + List incSys = LanguageSettingsExtensionManager.getSystemSettingEntriesByKind(cfgDescription, rc, langId, + ICSettingEntry.INCLUDE_PATH); + includePathEntries.addAll(incSys); + + List incLocal = LanguageSettingsExtensionManager.getLocalSettingEntriesByKind(cfgDescription, rc, langId, + ICSettingEntry.INCLUDE_PATH); + includePathLocalEntries.addAll(incLocal); + + List incFiles = LanguageSettingsExtensionManager.getSettingEntriesByKind(cfgDescription, rc, langId, + ICSettingEntry.INCLUDE_FILE); + includeFileEntries.addAll(incFiles); + + List macroFiles = LanguageSettingsExtensionManager.getSettingEntriesByKind(cfgDescription, rc, langId, + ICSettingEntry.MACRO_FILE); + macroFileEntries.addAll(macroFiles); + + List macros = LanguageSettingsExtensionManager.getSettingEntriesByKind(cfgDescription, rc, langId, + ICSettingEntry.MACRO); + macroEntries.addAll(macros); + } + + String[] includePaths = convertToLocations(includePathEntries, cfgDescription); + String[] includePathsLocal = convertToLocations(includePathLocalEntries, cfgDescription); + String[] includeFiles = convertToLocations(includeFileEntries, cfgDescription); + String[] macroFiles = convertToLocations(macroFileEntries, cfgDescription); + + Map definedMacros = new HashMap(); + for (ICLanguageSettingEntry entry : macroEntries) { + ICMacroEntry macroEntry = (ICMacroEntry)entry; + String name = macroEntry.getName(); + String value = macroEntry.getValue(); + definedMacros.put(name, value); + } + + return new ExtendedScannerInfo(definedMacros, includePaths, macroFiles, includeFiles, includePathsLocal); + } + + private List getLanguageIds(ICConfigurationDescription cfgDescription, IResource resource) { + List languageIds = null; + if (resource instanceof IFile) { + String langId = getLanguageIdForFile(cfgDescription, resource); + if (langId!=null) { + languageIds = new ArrayList(1); + languageIds.add(langId); + } + } else if (resource instanceof IContainer) { // IResource can be either IFile or IContainer + languageIds = getLanguageIdsForFolder(cfgDescription, (IContainer) resource); + } + if (languageIds==null || languageIds.size()==0) { + String msg = NLS.bind(SettingsModelMessages.getString("LanguageSettingsScannerInfoProvider.UnableToDetermineLanguage"), resource.toString()); //$NON-NLS-1$ + CCorePlugin.log(new CoreException(new Status(IStatus.ERROR, CCorePlugin.PLUGIN_ID, msg))); + } + return languageIds; + } + + private String getLanguageIdForFile(ICConfigurationDescription cfgDescription, IResource resource) { + // For files using LanguageManager + try { + ILanguage language = LanguageManager.getInstance().getLanguageForFile((IFile) resource, cfgDescription); + if (language!=null) { + return language.getId(); + } + } catch (CoreException e) { + CCorePlugin.log(e); + } + return null; + } + + private List getLanguageIdsForFolder(ICConfigurationDescription cfgDescription, IContainer resource) { + // Using MBS for folders. That will take language ID from input type of applicable tools in the toolchain. + List languageIds = new ArrayList(); + + ICFolderDescription rcDes = null; + ICLanguageSetting[] langSettings = null; + if (resource.getType() == IResource.FOLDER) { // but not IResource.PROJECT + IPath rcPath = resource.getProjectRelativePath(); + rcDes = (ICFolderDescription) cfgDescription.getResourceDescription(rcPath, false); + langSettings = rcDes.getLanguageSettings(); + } + if (langSettings==null || langSettings.length==0) { + // not found or IResource.PROJECT + ICFolderDescription rootDes = cfgDescription.getRootFolderDescription(); + langSettings = rootDes.getLanguageSettings(); + } + + if (langSettings!=null) { + for (ICLanguageSetting ls : langSettings) { + String langId = ls.getLanguageId(); + if (langId!=null && !languageIds.contains(langId)) { + languageIds.add(langId); + } + } + } + + return languageIds; + } + + private IPath expandVariables(IPath path, ICConfigurationDescription cfgDescription) { + ICdtVariableManager varManager = CCorePlugin.getDefault().getCdtVariableManager(); + String pathStr = path.toString(); + try { + pathStr = varManager.resolveValue(pathStr, "", null, cfgDescription); //$NON-NLS-1$ + } catch (CdtVariableException e) { + // Swallow exceptions but also log them + CCorePlugin.log(e); + } + IPath resolvedLoc = new Path(pathStr); + return resolvedLoc; + } + + /** + * Get build working directory for the provided configuration. Returns + * project location if none defined. + */ + private static IPath getBuildCWD(ICConfigurationDescription cfgDescription) { + IPath buildCWD = cfgDescription.getBuildSetting().getBuilderCWD(); + if (buildCWD==null) { + IProject project = cfgDescription.getProjectDescription().getProject(); + buildCWD = project.getLocation(); + } else { + ICdtVariableManager mngr = CCorePlugin.getDefault().getCdtVariableManager(); + try { + // FIXME IPath buildCWD can hold variables i.e. ${workspace_loc:/path} + String buildPathString = buildCWD.toString(); + buildPathString = mngr.resolveValue(buildPathString, "", null, cfgDescription); + buildCWD = new Path(buildPathString); + } catch (CdtVariableException e) { + CCorePlugin.log(e); + } + + } + buildCWD = buildCWD.addTrailingSeparator(); + return buildCWD; + } + + /** + * Resolve location to file system location in a configuration context. + * Resolving includes replacing build/environment variables with values, making relative path absolute etc. + * + * @param location - location to resolve. If relative, it is taken to be rooted in build working directory. + * @param cfgDescription - the configuration context. + * @return resolved file system location. + */ + private static String resolveEntry(String location, ICConfigurationDescription cfgDescription) { + // Substitute build/environment variables + ICdtVariableManager varManager = CCorePlugin.getDefault().getCdtVariableManager(); + try { + location = varManager.resolveValue(location, "", null, cfgDescription); //$NON-NLS-1$ + } catch (CdtVariableException e) { + // Swallow exceptions but also log them + CCorePlugin.log(e); + } + // use OS file separators (i.e. '\' on Windows) + if (java.io.File.separatorChar != '/') { + location = location.replace('/', java.io.File.separatorChar); + } + + // note that we avoid using org.eclipse.core.runtime.Path for manipulations being careful + // to preserve "../" segments and not let collapsing them which is not correct for symbolic links. + Path locPath = new Path(location); + if (locPath.isAbsolute() && locPath.getDevice()==null) { + // prepend device (C:) for Windows + IPath buildCWD = getBuildCWD(cfgDescription); + String device = buildCWD.getDevice(); + if (device!=null) + location = device + location; + } + if (!locPath.isAbsolute()) { + // consider relative path to be from build working directory + IPath buildCWD = getBuildCWD(cfgDescription); + location = buildCWD.toOSString() + locPath; + } + return location; + } + + /** + * Convert the path entries to absolute file system locations represented as String array. + * Resolve the entries which are not resolved. + * + * @param entriesPath - language settings path entries. + * @param cfgDescription - configuration description for resolving entries. + * @return array of the locations. + */ + private String[] convertToLocations(LinkedHashSet entriesPath, ICConfigurationDescription cfgDescription){ + List locations = new ArrayList(entriesPath.size()); + for (ICLanguageSettingEntry entry : entriesPath) { + ACPathEntry entryPath = (ACPathEntry)entry; + if (entryPath.isValueWorkspacePath()) { + IPath loc = entryPath.getLocation(); + if (loc!=null) { + if (checkBit(entryPath.getFlags(), ICSettingEntry.FRAMEWORKS_MAC)) { + locations.add(loc.append("/__framework__.framework/Headers/__header__").toOSString()); + locations.add(loc.append("/__framework__.framework/PrivateHeaders/__header__").toOSString()); + } else { + locations.add(loc.toOSString()); + } + } + } else { + String locStr = entryPath.getName(); + if (entryPath.isResolved()) { + locations.add(locStr); + } else { + locStr = resolveEntry(locStr, cfgDescription); + if (locStr!=null) { + if (checkBit(entryPath.getFlags(), ICSettingEntry.FRAMEWORKS_MAC)) { + locations.add(locStr+"/__framework__.framework/Headers/__header__"); + locations.add(locStr+"/__framework__.framework/PrivateHeaders/__header__"); + } else { + locations.add(locStr); + // add relative paths again for indexer to resolve from source file location + IPath unresolvedPath = entryPath.getLocation(); + if (!unresolvedPath.isAbsolute()) { + IPath expandedPath = expandVariables(unresolvedPath, cfgDescription); + if (!expandedPath.isAbsolute()) { + locations.add(expandedPath.toOSString()); + } + } + } + } + } + } + } + + return locations.toArray(new String[locations.size()]); + } + + private static boolean checkBit(int flags, int bit) { + return (flags & bit) == bit; + } + + public void subscribe(IResource resource, IScannerInfoChangeListener listener) { + // Handled by ScannerInfoProviderProxy for the moment + } + + public void unsubscribe(IResource resource, IScannerInfoChangeListener listener) { + // Handled by ScannerInfoProviderProxy for the moment + } + +} diff --git a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/settings/model/CConfigurationDescription.java b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/settings/model/CConfigurationDescription.java index 0edac50159b..8b359afaf4c 100644 --- a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/settings/model/CConfigurationDescription.java +++ b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/settings/model/CConfigurationDescription.java @@ -18,6 +18,7 @@ import java.util.Map; import org.eclipse.cdt.core.CCorePlugin; import org.eclipse.cdt.core.cdtvariables.ICdtVariablesContributor; +import org.eclipse.cdt.core.language.settings.providers.ILanguageSettingsProvider; import org.eclipse.cdt.core.settings.model.CConfigurationStatus; import org.eclipse.cdt.core.settings.model.ICBuildSetting; import org.eclipse.cdt.core.settings.model.ICConfigExtensionReference; @@ -765,4 +766,22 @@ public class CConfigurationDescription extends CDataProxyContainer implements IC CConfigurationStatus status = data.getStatus(); return status != null ? status : CConfigurationStatus.CFG_STATUS_OK; } + + public void setLanguageSettingProviders(List providers) { + try { + CConfigurationSpecSettings specSettings = getSpecSettings(); + specSettings.setLanguageSettingProviders(providers); + } catch (CoreException e) { + CCorePlugin.log(e); + } +} + + public List getLanguageSettingProviders() { + try { + return getSpecSettings().getLanguageSettingProviders(); + } catch (CoreException e) { + CCorePlugin.log(e); + } + return null; + } } diff --git a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/settings/model/CConfigurationDescriptionCache.java b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/settings/model/CConfigurationDescriptionCache.java index 95f54d667c7..0c64dbc3ce3 100644 --- a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/settings/model/CConfigurationDescriptionCache.java +++ b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/settings/model/CConfigurationDescriptionCache.java @@ -16,6 +16,7 @@ import java.util.Map; import org.eclipse.cdt.core.cdtvariables.ICdtVariable; import org.eclipse.cdt.core.cdtvariables.ICdtVariablesContributor; +import org.eclipse.cdt.core.language.settings.providers.ILanguageSettingsProvider; import org.eclipse.cdt.core.settings.model.CConfigurationStatus; import org.eclipse.cdt.core.settings.model.ICBuildSetting; import org.eclipse.cdt.core.settings.model.ICConfigExtensionReference; @@ -53,6 +54,28 @@ import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.QualifiedName; +/** + * CConfigurationDescriptionCache is a proxy class for serialization of configuration description data. + * + * An inspection of the scenario where user changes project properties and saves it yields + * following sequence of events: + * - Initialization: + * - After eclipse started a project is being opened. A new CConfigurationDescriptionCache is created + * with CConfigurationDescriptionCache(ICStorageElement storage, CProjectDescription parent) constructor. + * - Any clients needed ICConfigurationDescription get CConfigurationDescription using constructor + * CConfigurationDescription(CConfigurationData data, String buildSystemId, ICDataProxyContainer cr) + * where the CConfigurationDescriptionCache is passed as data. The reference to cache is kept in field fCfgCache. + * - fCfgCache is used to getSpecSettings() CConfigurationSpecSettings, after that fCfgCache is set to null. + * - User enters project properties/settings: + * - another CConfigurationDescription (settings configuration) created using the same constructor setting fCfgCache + * to the CConfigurationDescriptionCache. + * - User changes settings (in the settings configuration CConfigurationDescription) and saves it: + * - new CConfigurationDescriptionCache is created from the CConfigurationDescription via constructor + * CConfigurationDescriptionCache(ICConfigurationDescription baseDescription, ...) where + * baseDescription is saved as fBaseDescription. + * - CConfigurationDescriptionCache.applyData(...) is used to persist the data. at that point + * reference fBaseDescription gets set to null. + */ public class CConfigurationDescriptionCache extends CDefaultConfigurationData implements ICConfigurationDescription, IInternalCCfgInfo, ICachedData { private CProjectDescription fParent; @@ -535,4 +558,15 @@ public class CConfigurationDescriptionCache extends CDefaultConfigurationData return status != null ? status : CConfigurationStatus.CFG_STATUS_OK; } + public void setLanguageSettingProviders(List providers) { +// FIXME? - not sure +// if(!fInitializing) +// throw ExceptionFactory.createIsReadOnlyException(); + + fSpecSettings.setLanguageSettingProviders(providers); + } + + public List getLanguageSettingProviders() { + return fSpecSettings.getLanguageSettingProviders(); + } } diff --git a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/settings/model/CConfigurationSpecSettings.java b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/settings/model/CConfigurationSpecSettings.java index ae5a488764f..63dd2cac673 100644 --- a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/settings/model/CConfigurationSpecSettings.java +++ b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/settings/model/CConfigurationSpecSettings.java @@ -11,15 +11,19 @@ *******************************************************************************/ package org.eclipse.cdt.internal.core.settings.model; +import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashMap; +import java.util.List; import java.util.Map; -import java.util.Set; import java.util.Map.Entry; +import java.util.Set; import org.eclipse.cdt.core.CCorePlugin; +import org.eclipse.cdt.core.language.settings.providers.ILanguageSettingsProvider; import org.eclipse.cdt.core.settings.model.CExternalSetting; import org.eclipse.cdt.core.settings.model.ICBuildSetting; import org.eclipse.cdt.core.settings.model.ICConfigExtensionReference; @@ -37,9 +41,11 @@ import org.eclipse.cdt.internal.core.COwner; import org.eclipse.cdt.internal.core.COwnerConfiguration; import org.eclipse.cdt.internal.core.cdtvariables.StorableCdtVariables; import org.eclipse.cdt.internal.core.envvar.EnvironmentVariableManager; +import org.eclipse.cdt.internal.core.language.settings.providers.LanguageSettingsProvidersSerializer; import org.eclipse.cdt.utils.envvar.StorableEnvironment; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.QualifiedName; +import org.eclipse.osgi.util.NLS; /** * CConfigurationSpecSettings impelements ICSettingsStorage @@ -87,6 +93,8 @@ public class CConfigurationSpecSettings implements ICSettingsStorage{ // private CConfigBasedDescriptor fDescriptor; // private Map fExternalSettingsProviderMap; + private List fLanguageSettingsProviders = new ArrayList(0); + private class DeltaSet { public Set extSet; public Set idSet; @@ -179,6 +187,8 @@ public class CConfigurationSpecSettings implements ICSettingsStorage{ fOwner = base.fOwner; copyExtensionInfo(base); + + fLanguageSettingsProviders = new ArrayList(base.getLanguageSettingProviders()); } // private void copyRefInfos(Map infosMap){ @@ -971,4 +981,34 @@ public class CConfigurationSpecSettings implements ICSettingsStorage{ public void updateExternalSettingsProviders(String[] ids){ ExtensionContainerFactory.updateReferencedProviderIds(fCfg, ids); } + + /** + * Adds list of {@link ILanguageSettingsProvider} to the specs. + * Note that only unique IDs are accepted. + * + * @param providers - list of providers to keep in the specs. + */ + public void setLanguageSettingProviders(List providers) { + fLanguageSettingsProviders.clear(); + Set ids = new HashSet(); + for (ILanguageSettingsProvider provider : providers) { + String id = provider.getId(); + if (provider==LanguageSettingsProvidersSerializer.getRawWorkspaceProvider(id)) { + String msg = "Error: Attempt to add to the configuration raw global provider " + id; + throw new IllegalArgumentException(msg); + } + if (!ids.contains(id)) { + fLanguageSettingsProviders.add(provider); + ids.add(id); + } else { + String msg = NLS.bind(SettingsModelMessages.getString("CConfigurationSpecSettings.MustHaveUniqueID"), id); //$NON-NLS-1$ + throw new IllegalArgumentException(msg); + } + } + fIsModified = true; + } + + public List getLanguageSettingProviders() { + return Collections.unmodifiableList(fLanguageSettingsProviders); + } } diff --git a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/settings/model/DescriptionScannerInfoProvider.java b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/settings/model/DescriptionScannerInfoProvider.java index 1951c3aa5cc..f7d7e7008b3 100644 --- a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/settings/model/DescriptionScannerInfoProvider.java +++ b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/settings/model/DescriptionScannerInfoProvider.java @@ -34,6 +34,7 @@ import org.eclipse.cdt.core.settings.model.ICProjectDescriptionListener; import org.eclipse.cdt.core.settings.model.ICResourceDescription; import org.eclipse.cdt.core.settings.model.ICSettingBase; import org.eclipse.cdt.core.settings.model.ICSettingEntry; +import org.eclipse.cdt.internal.core.language.settings.providers.LanguageSettingsLogger; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.IWorkspaceRoot; @@ -74,6 +75,9 @@ public class DescriptionScannerInfoProvider implements IScannerInfoProvider, ICP } public IScannerInfo getScannerInformation(IResource resource) { + // AG FIXME + LanguageSettingsLogger.logScannerInfoProvider(resource, this); + if(!fInited) updateProjCfgInfo(CProjectDescriptionManager.getInstance().getProjectDescription(fProject, false)); diff --git a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/settings/model/MultiConfigDescription.java b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/settings/model/MultiConfigDescription.java index a6838481d1c..bff75bff4b8 100644 --- a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/settings/model/MultiConfigDescription.java +++ b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/settings/model/MultiConfigDescription.java @@ -14,9 +14,11 @@ package org.eclipse.cdt.internal.core.settings.model; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; +import java.util.List; import java.util.Map; import org.eclipse.cdt.core.cdtvariables.ICdtVariablesContributor; +import org.eclipse.cdt.core.language.settings.providers.ILanguageSettingsProvider; import org.eclipse.cdt.core.settings.model.CConfigurationStatus; import org.eclipse.cdt.core.settings.model.ICBuildSetting; import org.eclipse.cdt.core.settings.model.ICConfigExtensionReference; @@ -581,4 +583,15 @@ public class MultiConfigDescription extends MultiItemsHolder implements fCfgs[i].removeStorage(id); } + public void setLanguageSettingProviders(List providers) { + if (DEBUG) + System.out.println("Bad multi access: MultiConfigDescription.setLanguageSettingProviders()"); //$NON-NLS-1$ + } + + public List getLanguageSettingProviders() { + if (DEBUG) + System.out.println("Bad multi access: MultiConfigDescription.getLanguageSettingProviders()"); //$NON-NLS-1$ + return null; + } + } diff --git a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/settings/model/ScannerInfoProviderProxy.java b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/settings/model/ScannerInfoProviderProxy.java index 89e13e57c98..64cf620e576 100644 --- a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/settings/model/ScannerInfoProviderProxy.java +++ b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/settings/model/ScannerInfoProviderProxy.java @@ -16,13 +16,19 @@ import java.util.List; import java.util.Map; import org.eclipse.cdt.core.CCorePlugin; +import org.eclipse.cdt.core.language.settings.providers.LanguageSettingsManager; import org.eclipse.cdt.core.parser.IScannerInfo; import org.eclipse.cdt.core.parser.IScannerInfoChangeListener; import org.eclipse.cdt.core.parser.IScannerInfoProvider; import org.eclipse.cdt.core.settings.model.ICConfigurationDescription; +import org.eclipse.cdt.internal.core.language.settings.providers.LanguageSettingsScannerInfoProvider; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; +/** + * TODO fProvider is going to be deprecated in favor of {@link LanguageSettingsScannerInfoProvider}. + * + */ public class ScannerInfoProviderProxy extends AbstractCExtensionProxy implements IScannerInfoProvider, IScannerInfoChangeListener{ private Map> listeners; private IScannerInfoProvider fProvider; @@ -33,6 +39,11 @@ public class ScannerInfoProviderProxy extends AbstractCExtensionProxy implements } public IScannerInfo getScannerInformation(IResource resource) { + if (LanguageSettingsManager.isLanguageSettingsProvidersEnabled(getProject())) { + LanguageSettingsScannerInfoProvider lsProvider = new LanguageSettingsScannerInfoProvider(); + return lsProvider.getScannerInformation(resource); + } + // Legacy logic providerRequested(); return fProvider.getScannerInformation(resource); } diff --git a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/settings/model/SettingsModelMessages.properties b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/settings/model/SettingsModelMessages.properties index a37c844b3f2..09dd9fd56cb 100644 --- a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/settings/model/SettingsModelMessages.properties +++ b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/settings/model/SettingsModelMessages.properties @@ -15,8 +15,9 @@ CConfigurationDescription.0=data was not created CConfigurationDescription.1=expected proxy of type ICFileDescription, but was CConfigurationDescription.2=data was not created CConfigurationDescription.3=expected proxy of type ICFolderDescription, but was -CConfigurationStatus.1=configurations settings invalid CConfigurationDescriptionCache.0=description is read only +CConfigurationSpecSettings.MustHaveUniqueID=Language Settings Providers must have unique ID. Duplicate ID={0} +CConfigurationStatus.1=configurations settings invalid CProjectConverterDesciptor.0=illegal provider implementation CProjectConverterDesciptor.1=no provider defined CProjectDescriptionManager.1=required build system is not installed @@ -49,5 +50,8 @@ CExternalSettingsManager.3=writable ref info is requested for the read only conf CfgExportSettingContainerFactory.2=invalid id: project name not specified ExtensionContainerFactory.4=invalid setting provider class specified ExtensionContainerFactory.5=provider element not specified +LanguageSettingsBaseProvider.CanBeConfiguredOnlyOnce=LanguageSettingsBaseProvider can be configured only once +LanguageSettingsScannerInfoProvider.UnableToDetermineLanguage=Error getting ScannerInfo: Unable to determine language for resource {0} SettingsContext.0=no project associated with the context SettingsContext.1=can not accept the not-context project description + diff --git a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/settings/model/xml/XmlProjectDescriptionStorage.java b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/settings/model/xml/XmlProjectDescriptionStorage.java index a7ef3579cca..f48a2d6d2bf 100644 --- a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/settings/model/xml/XmlProjectDescriptionStorage.java +++ b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/settings/model/xml/XmlProjectDescriptionStorage.java @@ -34,6 +34,7 @@ import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; import org.eclipse.cdt.core.CCorePlugin; +import org.eclipse.cdt.core.language.settings.providers.LanguageSettingsManager_TBD; import org.eclipse.cdt.core.settings.model.ICProjectDescription; import org.eclipse.cdt.core.settings.model.ICProjectDescriptionManager; import org.eclipse.cdt.core.settings.model.ICSettingsStorage; @@ -42,6 +43,7 @@ import org.eclipse.cdt.core.settings.model.extension.ICProjectConverter; import org.eclipse.cdt.core.settings.model.util.CDataUtil; import org.eclipse.cdt.internal.core.XmlUtil; import org.eclipse.cdt.internal.core.envvar.ContributedEnvironment; +import org.eclipse.cdt.internal.core.language.settings.providers.LanguageSettingsProvidersSerializer; import org.eclipse.cdt.internal.core.settings.model.AbstractCProjectDescriptionStorage; import org.eclipse.cdt.internal.core.settings.model.CProjectDescription; import org.eclipse.cdt.internal.core.settings.model.CProjectDescriptionManager; @@ -170,6 +172,7 @@ public class XmlProjectDescriptionStorage extends AbstractCProjectDescriptionSto serializingLock.acquire(); projectModificaitonStamp = serialize(fDes.getProject(), ICProjectDescriptionStorageType.STORAGE_FILE_NAME, fElement); ((ContributedEnvironment) CCorePlugin.getDefault().getBuildEnvironmentManager().getContributedEnvironment()).serialize(fDes); + LanguageSettingsProvidersSerializer.serializeLanguageSettings(fDes); } finally { serializingLock.release(); Job.getJobManager().removeJobChangeListener(notifyJobCanceller); @@ -481,6 +484,7 @@ public class XmlProjectDescriptionStorage extends AbstractCProjectDescriptionSto // Update the modification stamp projectModificaitonStamp = getModificationStamp(project.getFile(ICProjectDescriptionStorageType.STORAGE_FILE_NAME)); CProjectDescription des = new CProjectDescription(project, new XmlStorage(storage), storage, true, false); + LanguageSettingsProvidersSerializer.loadLanguageSettings(des); try { setThreadLocalProjectDesc(des); des.loadDatas(); diff --git a/core/org.eclipse.cdt.core/plugin.properties b/core/org.eclipse.cdt.core/plugin.properties index e791b820771..892f8ccb2ec 100644 --- a/core/org.eclipse.cdt.core/plugin.properties +++ b/core/org.eclipse.cdt.core/plugin.properties @@ -26,6 +26,7 @@ ErrorParser.name=Error Parser BinaryParser.name=Binary Parser PathEntryStore.name=Path Entry Store ScannerInfoProvider.name=Scanner Information Provider +LanguageSettingsProvider.name=Language Settings Provider CIndexer.name= C/C++ Indexer language.name= CDT Language diff --git a/core/org.eclipse.cdt.core/plugin.xml b/core/org.eclipse.cdt.core/plugin.xml index 3cb166b1acb..c8167c62bf1 100644 --- a/core/org.eclipse.cdt.core/plugin.xml +++ b/core/org.eclipse.cdt.core/plugin.xml @@ -638,8 +638,9 @@ - - + + + + + + + + + + + This extension point is used to contribute a new Language Settings Provider. A Language Settings Provider is used to get additions to compiler options such as include paths (-I) or preprocessor defines (-D) and others into the project model. + + + + + + + + + + + + + + + + + + + + + + + + ID of the extension point, not used + + + + + + + Name of the extension point, not used + + + + + + + + + + + + + The definition of a language settings provider. + + + + + + + + + + + A fully qualified name of the Java class that implements <samp>org.eclipse.cdt.core.settings.model.ILanguageSettingsProvider</samp> interface. If empty, <samp>org.eclipse.cdt.core.language.settings.providers.LanguageSettingsBaseProvider</samp> is used by default which provides basic functionality defined by this extension point. +If there is a need to configure a provider, attribute parameter could be used in a class extending <samp>LanguageSettingsBaseProvider</samp>. + + + + + + + + + + Unique ID of the provider + + + + + + + Name of the provider. This name will be presented to a user in UI. + + + + + + + A custom parameter to initialize provider. Used to deliver command for GCCBuiltinSpecsDetector as an example. + + + + + + + + + + The definition of language scope. Includes the list of language ID this provider is applicable to. If a language scope is not present, the provider will provide for any language. + + + + + + + ID of the language for which this provider provides the entries. As an example, those are languages contributed by CDT (see extension org.eclipse.cdt.core.language): +<p>- "<samp>org.eclipse.cdt.core.gcc</samp>" for C,</p> +<p>- "<samp>org.eclipse.cdt.core.g++</samp>" for C++.</p> + + + + + + + + + + The Language Settings Entries used to provide additions to compiler options such as include paths (-I) or preprocessor defines (-D) and others into the project model. + + + + + + + + + + Kind of language settings entry which maps to compiler options. For example, following mapping is used for gcc options: + +<br><samp>"-I"</samp> : includePath +<br>"<samp>-D</samp>" : macro +<br>"<samp>-include</samp>" : includeFile +<br>"<samp>-L</samp>" : libraryPath +<br>"<samp>-l</samp>" : libraryFile +<br>"<samp>-imacros</samp>" : macroFile + + + + + + + + + + + + + + + + + + + + + + + "name" attribute maps to path for the entries representing a path to a folder or file and to name for <samp>macro</samp> kind representing name-value pair. For example: +<br>"<samp>/usr/include/</samp>" +<br>"<samp>MACRO</samp>" (for <samp>#define MACRO value</samp>) +<br>Note that relative paths are treated as rooted in build working directory (when applicable). + + + + + + + "value" attribute is used for <samp>macro</samp> kind representing name-value pair only. It is not used for the entries representing a path. For example: +<br>"<samp>value</samp>" (for <samp>#define MACRO value</samp>) + + + + + + + + + + Combination of flags for the entry. + + + + + + + A value of the flag. Corresponds to <samp>ICSettingEntry</samp> flags, see JavaDoc there for more details. Here is an excerpt from the Javadoc for the flags intended to be used with this extension point (the others might be not supported): + <br>- <samp>BUILTIN</samp> : Indicates settings built in a tool (compiler) itself. That kind of settings are not passed as options to a compiler but indexer or other clients might need them. + <br>- <samp>LOCAL</samp> : Applicable for <samp>includePath</samp> only which could be local (#include "...") or system (#include <...>). If an <samp>includePath</samp> is not marked as <samp>LOCAL</samp> it is treated as system. + <br>- <samp>RESOLVED</samp> : Indicates that the entries do not need to be resolved such as expansion of environment variables, normalizing the path against build working directory etc. + <br>- <samp>VALUE_WORKSPACE_PATH</samp> : is used to indicate that the entry is a resource managed by eclipse in the workspace. The path is rooted in the workspace root. + <br>- <samp>UNDEFINED</samp> : indicates that the entry should not be defined, corresponds to <samp>-U</samp> option of gcc compiler. If this flag is defined it will negate entries with the same name (and kind) for all providers down the list. + + + + + + + + + + + + + + + + + + + + + + + + + + CDT 9.0 + + + + + + + + + [Enter extension point usage example here.] + + + + + + + + + Plug-ins that want to extend this extension point must implement <samp>org.eclipse.cdt.core.language.settings.providers.ILanguageSettingsProvider</samp> interface. +<br/> +For those cases where contributed settings entries (representing the compiler options) are not changed dynamically it is sufficient to configure existing class LanguageSettingsBaseProvider which is provided by default. +<br/> + + + + + + + + + [Enter information about supplied implementation of this extension point.] + + + + + + + + + Copyright (c) 2009, 2010 Andrew Gvozdev (Quoin Inc.) 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 + + + + diff --git a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/AbstractExecutableExtensionBase.java b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/AbstractExecutableExtensionBase.java new file mode 100644 index 00000000000..d56988056f6 --- /dev/null +++ b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/AbstractExecutableExtensionBase.java @@ -0,0 +1,83 @@ +/******************************************************************************* + * Copyright (c) 2009, 2010 Andrew Gvozdev (Quoin Inc.) 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: + * Andrew Gvozdev (Quoin Inc.) - initial API and implementation + *******************************************************************************/ + +package org.eclipse.cdt.core; + +/** + * Helper abstract class serving as a base for creating a frame of executable class + * defined as an extension in plugin.xml. + * + */ +public abstract class AbstractExecutableExtensionBase { + private String fId; + private String fName; + + /** + * Default constructor will initialize with the name of the class + * using reflection mechanism. + */ + public AbstractExecutableExtensionBase() { + fName = this.getClass().getSimpleName(); + fId = this.getClass().getCanonicalName(); + } + + /** + * Constructor to initialize with ID and name of the extension. + * + * @param id - ID of the extension. + * @param name - name of the extension. + */ + public AbstractExecutableExtensionBase(String id, String name) { + fName = name; + fId = id; + } + + /** + * Set extension ID. + * + * @param id of extension + */ + public void setId(String id) { + fId = id; + } + + /** + * Set extension name. + * + * @param name of extension + */ + public void setName(String name) { + fName = name; + } + + /** + * @return id of extension + */ + public String getId() { + return fId; + } + + /** + * @return name of extension + */ + public String getName() { + return fName; + } + + /** + * Method toString() for debugging purposes. + */ + @SuppressWarnings("nls") + @Override + public String toString() { + return "id="+fId+", name="+fName; + } +} diff --git a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/CCorePlugin.java b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/CCorePlugin.java index e39749b1a02..08d5bd5b470 100644 --- a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/CCorePlugin.java +++ b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/CCorePlugin.java @@ -526,7 +526,7 @@ public class CCorePlugin extends Plugin { * * @return CDT console adapter. */ - private IConsole getConsole(String extConsoleId, String contextId, String name, URL iconUrl) { + public IConsole getConsole(String extConsoleId, String contextId, String name, URL iconUrl) { try { IExtensionPoint extensionPoint = Platform.getExtensionRegistry().getExtensionPoint(CCorePlugin.PLUGIN_ID, "CBuildConsole"); //$NON-NLS-1$ if (extensionPoint != null) { diff --git a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/ErrorParserManager.java b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/ErrorParserManager.java index aa5fe227db2..f1d0fa7e9a5 100644 --- a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/ErrorParserManager.java +++ b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/ErrorParserManager.java @@ -697,7 +697,7 @@ outer: * @return URI * @since 5.1 */ - private URI toURI(IPath path) { + public URI toURI(IPath path) { // try { URI baseURI = getWorkingDirectoryURI(); String uriString = path.toString(); diff --git a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/ICConsoleParser.java b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/ICConsoleParser.java new file mode 100644 index 00000000000..44b216124bc --- /dev/null +++ b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/ICConsoleParser.java @@ -0,0 +1,25 @@ +/******************************************************************************* + * Copyright (c) 2009, 2011 Andrew Gvozdev 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: + * Andrew Gvozdev - initial API and implementation + *******************************************************************************/ + +package org.eclipse.cdt.core; + +import org.eclipse.cdt.core.settings.model.ICConfigurationDescription; +import org.eclipse.core.runtime.CoreException; + +/** + * TODO - this interface assumes configuration description. CDT project + * can be without configurations, in that case IProject should be passed + * to startup somehow. Perhaps another interface "IPConsoleParser" could + * be created when needed? + */ +public interface ICConsoleParser extends IConsoleParser { + public void startup(ICConfigurationDescription cfgDescription) throws CoreException; +} diff --git a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/resources/ScannerProvider.java b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/resources/ScannerProvider.java index 68dca092569..b349cb6b9e0 100644 --- a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/resources/ScannerProvider.java +++ b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/resources/ScannerProvider.java @@ -29,8 +29,10 @@ import org.eclipse.cdt.core.model.IMacroFileEntry; import org.eclipse.cdt.core.parser.IScannerInfo; import org.eclipse.cdt.core.parser.IScannerInfoChangeListener; import org.eclipse.cdt.core.parser.IScannerInfoProvider; +import org.eclipse.cdt.internal.core.language.settings.providers.LanguageSettingsLogger; import org.eclipse.cdt.internal.core.model.PathEntryManager; import org.eclipse.cdt.internal.core.settings.model.ScannerInfoProviderProxy; +import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.runtime.IPath; @@ -95,6 +97,13 @@ public class ScannerProvider extends AbstractCExtension implements IScannerInfoP * @see org.eclipse.cdt.core.parser.IScannerInfoProvider#getScannerInformation(org.eclipse.core.resources.IResource) */ public IScannerInfo getScannerInformation(IResource resource) { + // AG FIXME + if (resource instanceof IFile) { + LanguageSettingsLogger.logInfo("rc="+resource+" (ScannerProvider.getScannerInformation())"); + } else { + LanguageSettingsLogger.logWarning("rc="+resource+" (ScannerProvider.getScannerInformation())"); + } + IPath resPath = resource.getFullPath(); try { diff --git a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/core/ConsoleOutputSniffer.java b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/core/ConsoleOutputSniffer.java index aa357dd991a..bf81b071c09 100644 --- a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/core/ConsoleOutputSniffer.java +++ b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/core/ConsoleOutputSniffer.java @@ -13,7 +13,10 @@ package org.eclipse.cdt.internal.core; import java.io.IOException; import java.io.OutputStream; +import org.eclipse.cdt.core.CCorePlugin; +import org.eclipse.cdt.core.ErrorParserManager; import org.eclipse.cdt.core.IConsoleParser; +import org.eclipse.cdt.core.IErrorParser; /** @@ -127,6 +130,8 @@ public class ConsoleOutputSniffer { private OutputStream consoleErrorStream; private IConsoleParser[] parsers; + private ErrorParserManager errorParserManager = null; + public ConsoleOutputSniffer(IConsoleParser[] parsers) { this.parsers = parsers; } @@ -137,6 +142,11 @@ public class ConsoleOutputSniffer { this.consoleErrorStream = errorStream; } + public ConsoleOutputSniffer(OutputStream outputStream, OutputStream errorStream, IConsoleParser[] parsers, ErrorParserManager epm) { + this(outputStream, errorStream, parsers); + this.errorParserManager = epm; + } + /** * Returns an output stream that will be sniffed. * This stream should be hooked up so the command @@ -166,7 +176,13 @@ public class ConsoleOutputSniffer { public synchronized void closeConsoleOutputStream() throws IOException { if (nOpens > 0 && --nOpens == 0) { for (int i = 0; i < parsers.length; ++i) { + try { parsers[i].shutdown(); + } catch (Throwable e) { + // Report exception if any but let all the parsers chance to shutdown. + CCorePlugin.log(e); + } finally { + } } } } @@ -177,8 +193,18 @@ public class ConsoleOutputSniffer { * @param line */ private synchronized void processLine(String line) { - for (int i = 0; i < parsers.length; ++i) { - parsers[i].processLine(line); + for (IConsoleParser parser : parsers) { + try { + if (parser instanceof IErrorParser) { + // IErrorParser interface is used here only to pass ErrorParserManager + // which keeps track of CWD and provides useful methods for locating files + ((IErrorParser)parser).processLine(line, errorParserManager); + } else { + parser.processLine(line); + } + } catch (Throwable e) { + CCorePlugin.log(e); + } } } diff --git a/core/org.eclipse.cdt.ui/META-INF/MANIFEST.MF b/core/org.eclipse.cdt.ui/META-INF/MANIFEST.MF index 643438de4c3..27dff622aef 100644 --- a/core/org.eclipse.cdt.ui/META-INF/MANIFEST.MF +++ b/core/org.eclipse.cdt.ui/META-INF/MANIFEST.MF @@ -29,6 +29,7 @@ Export-Package: org.eclipse.cdt.internal.corext;x-internal:=true, org.eclipse.cdt.internal.ui.includebrowser;x-internal:=true, org.eclipse.cdt.internal.ui.indexview;x-internal:=true, org.eclipse.cdt.internal.ui.language;x-internal:=true, + org.eclipse.cdt.internal.ui.language.settings.providers;x-internal:=true, org.eclipse.cdt.internal.ui.navigator;x-internal:=true, org.eclipse.cdt.internal.ui.newui;x-internal:=true, org.eclipse.cdt.internal.ui.preferences;x-internal:=true, diff --git a/core/org.eclipse.cdt.ui/icons/obj16/filesyst.gif b/core/org.eclipse.cdt.ui/icons/obj16/filesyst.gif index 13ce11b1490b0691db9fc3b2a7a2a2055a5cf965..4b98a62c6eed7401e6fc5d44a2b319fdf56097de 100644 GIT binary patch literal 144 zcmZ?wbhEHb6krfw*v!BnlDS$SwCmuD|Ns9V|Nn8t|I3v-n!S$n`mZQ;UQyyaC(8~f z!GHu5f3h$#FmN;IfW$y%FtFGbob+71_gjX~`5)5h0xF3*POJPp9*Uh5I`d`89Sd{T mDpsFa%+I%fXlM~*P%zM%8#eWtcG&6%MSItj?e1V;um%8#wKpgL literal 310 zcmZ?wbhEHb6krfwxXQp_5i-F#Vya!t47-?VZYlHA>(@?NeB3%}s%zRpx3q<>Df3;^ z=DVfM_sd_oXx)M9kKaz+bzP!<*zR#sLvHa2#4 zb`A~>7!1bA$;rjV1&71Axw(0GczAhv`S|$w`S}F|1Ox>Ig@l9<2!yb(u!x9=sHmuz zm>3d?6c-nlkdTm+l$4T^l9ra1k&%&=m6el|L!nUe^70A_3W|z~N=iz~%E~G#Dypig zYHDig>gpOA8k(A#T3TA#+S)ogI=Z^LdU|^L`uYY228M=)Mn*=)#>OTlCZ?vQW@cvQ z=H_TL+QPyDgTY|2SR4+A$Kx$6Ev>AqtgWpH1cHr?jjgS%ot>S%y}g5jgQKIPlarIP zv$Knfi>s@vo12@vySs;nho`5fmzS5fx3`avkFT$+3kweqkBEqfjEszmii(boj){qhjg5_qi;ItsPe@2eOiWBlN=i;nPDx2g zO-)TpOG{5r&&bHg%*@Qn%F52p&dJHi&CSir%OjCUWHLEFKfj=$ps=v8sHmv8xVWUG zq_niOtgNiOyu6~KqO!8Gs;a8Gy1J&Orna`WuCA`WzP_QMp|P>Csi~>Cxw)mKrM0!S zt*x!Sy}hHOqqDQKtE;QKySt~Sr?+5S8jdpW$b9;MxcXxMxfB*3C@c8)n^z`)n{QUCr^7{Jv_V)Jv{{Hdt z@%29;KfxdX_yQEZCw!j(Ai=;FGXgi=y-kL|QC`25YpFPvUnX$KgpC>Il0Pg69nps& zm2np$h&ZGoseqA0qs|VT2NL8_aH3$V%m-ttg1k{!KHJAIgSNSZjV$qwL z&{OL*vEJigk^S^0x4EsZi#nV)b#g85a$3{lu)UvWL%-dY3ASak_xyiUfAGcsJI}x0 zfBEC#s~?Zve1G!h=d*V|pTGa{>ch`JACA8L^y|ad-=Dtz{`%wh_n*Ii{`&KuGNAaA zg^_{5o15rEb(&zAA)EYfpgZl2uvGVX>2@ zUU4}*ZwbSP5LHh{-FM|v;`}|m{NyDY<<(nTg**k-BpG`p)l#I@1U&^*pcz@*{`l= zUE9F6rjc!WliT_h_PMRDi#nV)b#iU#=3d_Aw5G>ldq2;He!DFbY|Ccv`TwZ?|D%RG z&%fV)`QzcMACKOAfAZ$%vv)uLzhC|Q{f|HIkG}fw^UsH)Z$JI|@b&knufMJ}l zr)oo!s%n^+(o8YM$_hnAA!%XV#nRFWavW-YCxzrX!|zxvtj4Szly-PFmorJH+uKhOV1_5U9={CR(L zbv^6a2DUYgZ0lRtC#EqhuVVTC|33rKK=CIFBLjmVgAPas$W8`U^8}T?l+1Y~F;9Tj9mdfG~EN$3i2aI`GVt=ykbz`*RNf? z`oQk}`*!YKK6~ljZF_cZ+HvgAv6IJ69zSyY;J$;WPMkV&@Th0*!vFtI{{R2)-9{Q{xYzi!ojzd!Hm)rnuOPWpOf;{Cn#PZn9eTp#{=Q|#Kl_?H9)`m^Y_v_E|osjQ0xhPeU?V7 zFYefq7px@erW32aOhZI~o1e+F);Uj8NSKj>%P7ZHO;TK&kDY#h literal 0 HcmV?d00001 diff --git a/core/org.eclipse.cdt.ui/icons/ovr16/cfg_ovr.gif b/core/org.eclipse.cdt.ui/icons/ovr16/cfg_ovr.gif new file mode 100644 index 0000000000000000000000000000000000000000..f82aa5fbb497b50db3e558a244f15cf0f695c8c9 GIT binary patch literal 155 zcmZ?wbhEHbWMg1sXc1+Qa&46LY~cu<^J|3Jh1PA|dq&N(!Z@HZp>ApQj9uH0 z-*(HJ)4%@g@&h-XzWws!_us$&{{8>|pMf}__>+Z^fkB8t2c#TiCj+a>0u`@7OE;d! j9f6w-IBz>$j+3?x7IEPn{37>k44ofy`glX(f`bOrc?xK=gK zDXW`S(>k}JVMcB1tj;OR9>4z4J#G15DcpTGsJ6w(z^Q^SiVO zy0#0ucM7|Ah`4u%dUT3$5eL_B&Q0x%zw+Pzo$cYkyV0+RE8j%?`u*0ulkaBiziwpwgJJFk W))VPjF;{__89ZJ6T-G@yGywo)347)M literal 0 HcmV?d00001 diff --git a/core/org.eclipse.cdt.ui/icons/ovr16/global_ovr.gif b/core/org.eclipse.cdt.ui/icons/ovr16/global_ovr.gif new file mode 100644 index 0000000000000000000000000000000000000000..2888b2eefa908bc38baf63757b37267cab962d9a GIT binary patch literal 271 zcmZ?wbhEHbWM^P!SgOiUnpY5(v^c47O;*u_$h;L{NzFld>!WifW!KIxtnLl3SmE4% zrKo#W_~IjxQ&(ASz3g=GVdT=S`I|Q{ym)cV&1;Jf%$>5Ock7i|NAI>R+2*-t@5b{N z4$qtGa{bcOnbVqQPw%{aX2I?2=YBjt@&C*H+H~jt)CP(_Sr{1@>=|?zfB@tt2R5Ap zmyRiI%<&TPXkjr>QCrOS>`}lUr=G(HKHv6mP&#?odu56RN7J&60xVqf6&S1mYv!xl literal 0 HcmV?d00001 diff --git a/core/org.eclipse.cdt.ui/icons/ovr16/import_co.gif b/core/org.eclipse.cdt.ui/icons/ovr16/import_co.gif new file mode 100644 index 0000000000000000000000000000000000000000..b0a24b278447ece4d5bf72be153df525cc7568af GIT binary patch literal 68 zcmZ?wbhEHbWMN=oSj50^?AXUsr#=}MEHN%v>`=a(H)hs7z8?<6Bz_r7#OSp^$SR; literal 0 HcmV?d00001 diff --git a/core/org.eclipse.cdt.ui/icons/ovr16/lock_ovr.gif b/core/org.eclipse.cdt.ui/icons/ovr16/lock_ovr.gif new file mode 100644 index 0000000000000000000000000000000000000000..4499ad076d3032c1962f605cbcc968287e0dc2b2 GIT binary patch literal 115 zcmZ?wbhEHbWM|-D*v!E2?P7A5LYwJeD^zUu0gD_M|kyjcq#X zro?u|@%JYS{{R1TG*Q3z1RNtUjM)3+y5os|8M&b1TX);+PR=0 z6U6-gp8*UMf3h$#Fz_ + + + + + + + + + + + + + + + + + + + + + + + + + + + + [Enter description of this extension point.] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + [Enter the first release in which this extension point appears.] + + + + + + + + + [Enter extension point usage example here.] + + + + + + + + + [Enter API information here.] + + + + + + + + + [Enter information about supplied implementation of this extension point.] + + + + + diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/ImageCombo.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/ImageCombo.java new file mode 100644 index 00000000000..8b71742590a --- /dev/null +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/ImageCombo.java @@ -0,0 +1,1471 @@ +/******************************************************************************* + * Copyright (c) 2000, 2005 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 + * Tom Seidel - enhancements for image-handling + *******************************************************************************/ +package org.eclipse.cdt.internal.ui; + +import java.util.Arrays; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.SWTException; +import org.eclipse.swt.accessibility.ACC; +import org.eclipse.swt.accessibility.AccessibleAdapter; +import org.eclipse.swt.accessibility.AccessibleControlAdapter; +import org.eclipse.swt.accessibility.AccessibleControlEvent; +import org.eclipse.swt.accessibility.AccessibleEvent; +import org.eclipse.swt.accessibility.AccessibleTextAdapter; +import org.eclipse.swt.accessibility.AccessibleTextEvent; +import org.eclipse.swt.events.ModifyListener; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.events.SelectionListener; +import org.eclipse.swt.graphics.Color; +import org.eclipse.swt.graphics.Font; +import org.eclipse.swt.graphics.GC; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.graphics.Rectangle; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Layout; +import org.eclipse.swt.widgets.Listener; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.Table; +import org.eclipse.swt.widgets.TableItem; +import org.eclipse.swt.widgets.Text; +import org.eclipse.swt.widgets.TypedListener; +import org.eclipse.swt.widgets.Widget; + +/** + * The ImageCombo class represents a selectable user interface object + * that combines a text field and a table and issues notification + * when an item is selected from the table. + *

+ * Note that although this class is a subclass of Composite, + * it does not make sense to add children to it, or set a layout on it. + *

+ *
+ *
Styles: + *
BORDER, READ_ONLY, FLAT
+ *
Events: + *
Selection
+ *
+ */ +public final class ImageCombo extends Composite { + + Text text; + Table table; + int visibleItemCount = 5; + Shell popup; + Button arrow; + boolean hasFocus; + Listener listener, filter; + Color foreground, background; + Font font; + +/** + * Constructs a new instance of this class given its parent + * and a style value describing its behavior and appearance. + *

+ * The style value is either one of the style constants defined in + * class SWT which is applicable to instances of this + * class, or must be built by bitwise OR'ing together + * (that is, using the int "|" operator) two or more + * of those SWT style constants. The class description + * lists the style constants that are applicable to the class. + * Style bits are also inherited from superclasses. + *

+ * + * @param parent a widget which will be the parent of the new instance (cannot be null) + * @param style the style of widget to construct + * + * @exception IllegalArgumentException
    + *
  • ERROR_NULL_ARGUMENT - if the parent is null
  • + *
+ * @exception SWTException
    + *
  • ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent
  • + *
+ * + * @see SWT#BORDER + * @see SWT#READ_ONLY + * @see SWT#FLAT + * @see Widget#getStyle() + */ +public ImageCombo (Composite parent, int style) { + super (parent, style = checkStyle (style)); + + int textStyle = SWT.SINGLE; + if ((style & SWT.READ_ONLY) != 0) textStyle |= SWT.READ_ONLY; + if ((style & SWT.FLAT) != 0) textStyle |= SWT.FLAT; + text = new Text (this, SWT.NONE); + int arrowStyle = SWT.ARROW | SWT.DOWN; + if ((style & SWT.FLAT) != 0) arrowStyle |= SWT.FLAT; + arrow = new Button (this, arrowStyle); + + listener = new Listener () { + public void handleEvent (Event event) { + if (popup == event.widget) { + popupEvent (event); + return; + } + if (text == event.widget) { + textEvent (event); + return; + } + if (table == event.widget) { + listEvent (event); + return; + } + if (arrow == event.widget) { + arrowEvent (event); + return; + } + if (ImageCombo.this == event.widget) { + comboEvent (event); + return; + } + if (getShell () == event.widget) { + handleFocus (SWT.FocusOut); + } + } + }; + filter = new Listener() { + public void handleEvent(Event event) { + Shell shell = ((Control)event.widget).getShell (); + if (shell == ImageCombo.this.getShell ()) { + handleFocus (SWT.FocusOut); + } + } + }; + + int [] comboEvents = {SWT.Dispose, SWT.Move, SWT.Resize}; + for (int i=0; i + *
  • ERROR_NULL_ARGUMENT - if the string is null
  • + * + * @exception SWTException
      + *
    • ERROR_WIDGET_DISPOSED - if the receiver has been disposed
    • + *
    • ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
    • + *
    + * + * @see #add(String,int) + */ +public void add (String string, Image image) { + checkWidget(); + if (string == null) SWT.error (SWT.ERROR_NULL_ARGUMENT); + TableItem newItem = new TableItem(this.table,SWT.NONE); + newItem.setText(string); + if (image != null) newItem.setImage(image); +} +/** + * Adds the argument to the receiver's list at the given + * zero-relative index. + *

    + * Note: To add an item at the end of the list, use the + * result of calling getItemCount() as the + * index or use add(String). + *

    + * + * @param string the new item + * @param index the index for the item + * + * @exception IllegalArgumentException
      + *
    • ERROR_NULL_ARGUMENT - if the string is null
    • + *
    • ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the list (inclusive)
    • + *
    + * @exception SWTException
      + *
    • ERROR_WIDGET_DISPOSED - if the receiver has been disposed
    • + *
    • ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
    • + *
    + * + * @see #add(String) + */ +public void add (String string,Image image, int index) { + checkWidget(); + if (string == null) SWT.error (SWT.ERROR_NULL_ARGUMENT); + TableItem newItem = new TableItem(this.table,SWT.NONE,index); + if (image != null) newItem.setImage(image); +} +/** + * Adds the listener to the collection of listeners who will + * be notified when the receiver's text is modified, by sending + * it one of the messages defined in the ModifyListener + * interface. + * + * @param listener the listener which should be notified + * + * @exception IllegalArgumentException
      + *
    • ERROR_NULL_ARGUMENT - if the listener is null
    • + *
    + * @exception SWTException
      + *
    • ERROR_WIDGET_DISPOSED - if the receiver has been disposed
    • + *
    • ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
    • + *
    + * + * @see ModifyListener + * @see #removeModifyListener + */ +public void addModifyListener (ModifyListener listener) { + checkWidget(); + if (listener == null) SWT.error (SWT.ERROR_NULL_ARGUMENT); + TypedListener typedListener = new TypedListener (listener); + addListener (SWT.Modify, typedListener); +} +/** + * Adds the listener to the collection of listeners who will + * be notified when the receiver's selection changes, by sending + * it one of the messages defined in the SelectionListener + * interface. + *

    + * widgetSelected is called when the combo's list selection changes. + * widgetDefaultSelected is typically called when ENTER is pressed the combo's text area. + *

    + * + * @param listener the listener which should be notified + * + * @exception IllegalArgumentException
      + *
    • ERROR_NULL_ARGUMENT - if the listener is null
    • + *
    + * @exception SWTException
      + *
    • ERROR_WIDGET_DISPOSED - if the receiver has been disposed
    • + *
    • ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
    • + *
    + * + * @see SelectionListener + * @see #removeSelectionListener + * @see SelectionEvent + */ +public void addSelectionListener(SelectionListener listener) { + checkWidget(); + if (listener == null) SWT.error (SWT.ERROR_NULL_ARGUMENT); + TypedListener typedListener = new TypedListener (listener); + addListener (SWT.Selection,typedListener); + addListener (SWT.DefaultSelection,typedListener); +} +void arrowEvent (Event event) { + switch (event.type) { + case SWT.FocusIn: { + handleFocus (SWT.FocusIn); + break; + } + case SWT.Selection: { + dropDown (!isDropped ()); + break; + } + } +} +/** + * Sets the selection in the receiver's text field to an empty + * selection starting just before the first character. If the + * text field is editable, this has the effect of placing the + * i-beam at the start of the text. + *

    + * Note: To clear the selected items in the receiver's list, + * use deselectAll(). + *

    + * + * @exception SWTException
      + *
    • ERROR_WIDGET_DISPOSED - if the receiver has been disposed
    • + *
    • ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
    • + *
    + * + * @see #deselectAll + */ +public void clearSelection () { + checkWidget (); + text.clearSelection (); + table.deselectAll (); +} +void comboEvent (Event event) { + switch (event.type) { + case SWT.Dispose: + if (popup != null && !popup.isDisposed ()) { + table.removeListener (SWT.Dispose, listener); + popup.dispose (); + } + Shell shell = getShell (); + shell.removeListener (SWT.Deactivate, listener); + Display display = getDisplay (); + display.removeFilter (SWT.FocusIn, filter); + popup = null; + text = null; + table = null; + arrow = null; + break; + case SWT.Move: + dropDown (false); + break; + case SWT.Resize: + internalLayout (false); + break; + } +} + +public Point computeSize (int wHint, int hHint, boolean changed) { + checkWidget (); + int width = 0, height = 0; + String[] items = getStringsFromTable(); + int textWidth = 0; + GC gc = new GC (text); + int spacer = gc.stringExtent (" ").x; //$NON-NLS-1$ + for (int i = 0; i < items.length; i++) { + textWidth = Math.max (gc.stringExtent (items[i]).x, textWidth); + } + gc.dispose(); + Point textSize = text.computeSize (SWT.DEFAULT, SWT.DEFAULT, changed); + Point arrowSize = arrow.computeSize (SWT.DEFAULT, SWT.DEFAULT, changed); + Point listSize = table.computeSize (wHint, SWT.DEFAULT, changed); + int borderWidth = getBorderWidth (); + + height = Math.max (hHint, Math.max (textSize.y, arrowSize.y) + 2*borderWidth); + width = Math.max (wHint, Math.max (textWidth + 2*spacer + arrowSize.x + 2*borderWidth, listSize.x)); + return new Point (width, height); +} +void createPopup(int selectionIndex) { + // create shell and list + popup = new Shell (getShell (), SWT.NO_TRIM | SWT.ON_TOP); + int style = getStyle (); + int listStyle = SWT.SINGLE | SWT.V_SCROLL; + if ((style & SWT.FLAT) != 0) listStyle |= SWT.FLAT; + if ((style & SWT.RIGHT_TO_LEFT) != 0) listStyle |= SWT.RIGHT_TO_LEFT; + if ((style & SWT.LEFT_TO_RIGHT) != 0) listStyle |= SWT.LEFT_TO_RIGHT; + // create a table instead of a list. + table = new Table (popup, listStyle); + if (font != null) table.setFont (font); + if (foreground != null) table.setForeground (foreground); + if (background != null) table.setBackground (background); + + int [] popupEvents = {SWT.Close, SWT.Paint, SWT.Deactivate}; + for (int i=0; i + *
  • ERROR_WIDGET_DISPOSED - if the receiver has been disposed
  • + *
  • ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
  • + * + */ +public void deselect (int index) { + checkWidget (); + table.deselect (index); +} +/** + * Deselects all selected items in the receiver's list. + *

    + * Note: To clear the selection in the receiver's text field, + * use clearSelection(). + *

    + * + * @exception SWTException
      + *
    • ERROR_WIDGET_DISPOSED - if the receiver has been disposed
    • + *
    • ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
    • + *
    + * + * @see #clearSelection + */ +public void deselectAll () { + checkWidget (); + table.deselectAll (); +} +void dropDown (boolean drop) { + if (drop == isDropped ()) return; + if (!drop) { + popup.setVisible (false); + if (!isDisposed ()&& arrow.isFocusControl()) { + text.setFocus(); + } + return; + } + + if (getShell() != popup.getParent ()) { + TableItem[] items = table.getItems (); + int selectionIndex = table.getSelectionIndex (); + table.removeListener (SWT.Dispose, listener); + popup.dispose(); + popup = null; + table = null; + createPopup (selectionIndex); + } + + Point size = getSize (); + int itemCount = table.getItemCount (); + itemCount = (itemCount == 0) ? visibleItemCount : Math.min(visibleItemCount, itemCount); + int itemHeight = table.getItemHeight () * itemCount; + Point listSize = table.computeSize (SWT.DEFAULT, itemHeight, false); + table.setBounds (1, 1, Math.max (size.x - 2, listSize.x), listSize.y); + + int index = table.getSelectionIndex (); + if (index != -1) table.setTopIndex (index); + Display display = getDisplay (); + Rectangle listRect = table.getBounds (); + Rectangle parentRect = display.map (getParent (), null, getBounds ()); + Point comboSize = getSize (); + Rectangle displayRect = getMonitor ().getClientArea (); + int width = Math.max (comboSize.x, listRect.width + 2); + int height = listRect.height + 2; + int x = parentRect.x; + int y = parentRect.y + comboSize.y; + if (y + height > displayRect.y + displayRect.height) y = parentRect.y - height; + popup.setBounds (x, y, width, height); + popup.setVisible (true); + table.setFocus (); +} +/* + * Return the Label immediately preceding the receiver in the z-order, + * or null if none. + */ +Label getAssociatedLabel () { + Control[] siblings = getParent ().getChildren (); + for (int i = 0; i < siblings.length; i++) { + if (siblings [i] == ImageCombo.this) { + if (i > 0 && siblings [i-1] instanceof Label) { + return (Label) siblings [i-1]; + } + } + } + return null; +} +public Control [] getChildren () { + checkWidget(); + return new Control [0]; +} +/** + * Gets the editable state. + * + * @return whether or not the reciever is editable + * + * @exception SWTException
      + *
    • ERROR_WIDGET_DISPOSED - if the receiver has been disposed
    • + *
    • ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
    • + *
    + * + * @since 3.0 + */ +public boolean getEditable () { + checkWidget (); + return text.getEditable(); +} +/** + * Returns the item at the given, zero-relative index in the + * receiver's list. Throws an exception if the index is out + * of range. + * + * @param index the index of the item to return + * @return the item at the given index + * + * @exception IllegalArgumentException
      + *
    • ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the list minus 1 (inclusive)
    • + *
    + * @exception SWTException
      + *
    • ERROR_WIDGET_DISPOSED - if the receiver has been disposed
    • + *
    • ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
    • + *
    + */ +public TableItem getItem (int index) { + checkWidget(); + return this.table.getItem (index); +} +/** + * Returns the number of items contained in the receiver's list. + * + * @return the number of items + * + * @exception SWTException
      + *
    • ERROR_WIDGET_DISPOSED - if the receiver has been disposed
    • + *
    • ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
    • + *
    + */ +public int getItemCount () { + checkWidget (); + return table.getItemCount (); +} +/** + * Returns the height of the area which would be used to + * display one of the items in the receiver's list. + * + * @return the height of one item + * + * @exception SWTException
      + *
    • ERROR_WIDGET_DISPOSED - if the receiver has been disposed
    • + *
    • ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
    • + *
    + */ +public int getItemHeight () { + checkWidget (); + return table.getItemHeight (); +} +/** + * Returns an array of Strings which are the items + * in the receiver's list. + *

    + * Note: This is not the actual structure used by the receiver + * to maintain its list of items, so modifying the array will + * not affect the receiver. + *

    + * + * @return the items in the receiver's list + * + * @exception SWTException
      + *
    • ERROR_WIDGET_DISPOSED - if the receiver has been disposed
    • + *
    • ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
    • + *
    + */ +public TableItem [] getItems () { + checkWidget (); + return table.getItems (); +} +char getMnemonic (String string) { + int index = 0; + int length = string.length (); + do { + while ((index < length) && (string.charAt (index) != '&')) index++; + if (++index >= length) return '\0'; + if (string.charAt (index) != '&') return string.charAt (index); + index++; + } while (index < length); + return '\0'; +} + +String [] getStringsFromTable() +{ + String[] items = new String[this.table.getItems().length]; + for (int i = 0, n = items.length; i < n; i++) { + items[i]=this.table.getItem(i).getText(); + } + return items; +} +/** + * Returns a Point whose x coordinate is the start + * of the selection in the receiver's text field, and whose y + * coordinate is the end of the selection. The returned values + * are zero-relative. An "empty" selection as indicated by + * the the x and y coordinates having the same value. + * + * @return a point representing the selection start and end + * + * @exception SWTException
      + *
    • ERROR_WIDGET_DISPOSED - if the receiver has been disposed
    • + *
    • ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
    • + *
    + */ +public Point getSelection () { + checkWidget (); + return text.getSelection (); +} +/** + * Returns the zero-relative index of the item which is currently + * selected in the receiver's list, or -1 if no item is selected. + * + * @return the index of the selected item + * + * @exception SWTException
      + *
    • ERROR_WIDGET_DISPOSED - if the receiver has been disposed
    • + *
    • ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
    • + *
    + */ +public int getSelectionIndex () { + checkWidget (); + return table.getSelectionIndex (); +} +public int getStyle () { + int style = super.getStyle (); + style &= ~SWT.READ_ONLY; + if (!text.getEditable()) style |= SWT.READ_ONLY; + return style; +} +/** + * Returns a string containing a copy of the contents of the + * receiver's text field. + * + * @return the receiver's text + * + * @exception SWTException
      + *
    • ERROR_WIDGET_DISPOSED - if the receiver has been disposed
    • + *
    • ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
    • + *
    + */ +public String getText () { + checkWidget (); + return text.getText (); +} +/** + * Returns the height of the receivers's text field. + * + * @return the text height + * + * @exception SWTException
      + *
    • ERROR_WIDGET_DISPOSED - if the receiver has been disposed
    • + *
    • ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
    • + *
    + */ +public int getTextHeight () { + checkWidget (); + return text.getLineHeight (); +} +/** + * Returns the maximum number of characters that the receiver's + * text field is capable of holding. If this has not been changed + * by setTextLimit(), it will be the constant + * Combo.LIMIT. + * + * @return the text limit + * + * @exception SWTException
      + *
    • ERROR_WIDGET_DISPOSED - if the receiver has been disposed
    • + *
    • ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
    • + *
    + */ +public int getTextLimit () { + checkWidget (); + return text.getTextLimit (); +} +/** + * Gets the number of items that are visible in the drop + * down portion of the receiver's list. + * + * @return the number of items that are visible + * + * @exception SWTException
      + *
    • ERROR_WIDGET_DISPOSED - if the receiver has been disposed
    • + *
    • ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
    • + *
    + * + * @since 3.0 + */ +public int getVisibleItemCount () { + checkWidget (); + return visibleItemCount; +} +void handleFocus (int type) { + if (isDisposed ()) return; + switch (type) { + case SWT.FocusIn: { + if (hasFocus) return; + if (getEditable ()) text.selectAll (); + hasFocus = true; + Shell shell = getShell (); + shell.removeListener (SWT.Deactivate, listener); + shell.addListener (SWT.Deactivate, listener); + Display display = getDisplay (); + display.removeFilter (SWT.FocusIn, filter); + display.addFilter (SWT.FocusIn, filter); + Event e = new Event (); + notifyListeners (SWT.FocusIn, e); + break; + } + case SWT.FocusOut: { + if (!hasFocus) return; + Control focusControl = getDisplay ().getFocusControl (); + if (focusControl == arrow || focusControl == table || focusControl == text) return; + hasFocus = false; + Shell shell = getShell (); + shell.removeListener(SWT.Deactivate, listener); + Display display = getDisplay (); + display.removeFilter (SWT.FocusIn, filter); + Event e = new Event (); + notifyListeners (SWT.FocusOut, e); + break; + } + } +} +/** + * Searches the receiver's list starting at the first item + * (index 0) until an item is found that is equal to the + * argument, and returns the index of that item. If no item + * is found, returns -1. + * + * @param string the search item + * @return the index of the item + * + * @exception IllegalArgumentException
      + *
    • ERROR_NULL_ARGUMENT - if the string is null
    • + *
    + * @exception SWTException
      + *
    • ERROR_WIDGET_DISPOSED - if the receiver has been disposed
    • + *
    • ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
    • + *
    + */ +public int indexOf (String string) { + checkWidget (); + if (string == null) SWT.error (SWT.ERROR_NULL_ARGUMENT); + return Arrays.asList(getStringsFromTable()).indexOf (string); +} + + +void initAccessible() { + AccessibleAdapter accessibleAdapter = new AccessibleAdapter () { + public void getName (AccessibleEvent e) { + String name = null; + Label label = getAssociatedLabel (); + if (label != null) { + name = stripMnemonic (label.getText()); + } + e.result = name; + } + public void getKeyboardShortcut(AccessibleEvent e) { + String shortcut = null; + Label label = getAssociatedLabel (); + if (label != null) { + String text = label.getText (); + if (text != null) { + char mnemonic = getMnemonic (text); + if (mnemonic != '\0') { + shortcut = "Alt+"+mnemonic; //$NON-NLS-1$ + } + } + } + e.result = shortcut; + } + public void getHelp (AccessibleEvent e) { + e.result = getToolTipText (); + } + }; + getAccessible ().addAccessibleListener (accessibleAdapter); + text.getAccessible ().addAccessibleListener (accessibleAdapter); + table.getAccessible ().addAccessibleListener (accessibleAdapter); + + arrow.getAccessible ().addAccessibleListener (new AccessibleAdapter() { + public void getName (AccessibleEvent e) { + e.result = isDropped () ? SWT.getMessage ("SWT_Close") : SWT.getMessage ("SWT_Open"); //$NON-NLS-1$ //$NON-NLS-2$ + } + public void getKeyboardShortcut (AccessibleEvent e) { + e.result = "Alt+Down Arrow"; //$NON-NLS-1$ + } + public void getHelp (AccessibleEvent e) { + e.result = getToolTipText (); + } + }); + + getAccessible().addAccessibleTextListener (new AccessibleTextAdapter() { + public void getCaretOffset (AccessibleTextEvent e) { + e.offset = text.getCaretPosition (); + } + }); + + getAccessible().addAccessibleControlListener (new AccessibleControlAdapter() { + public void getChildAtPoint (AccessibleControlEvent e) { + Point testPoint = toControl (e.x, e.y); + if (getBounds ().contains (testPoint)) { + e.childID = ACC.CHILDID_SELF; + } + } + + public void getLocation (AccessibleControlEvent e) { + Rectangle location = getBounds (); + Point pt = toDisplay (location.x, location.y); + e.x = pt.x; + e.y = pt.y; + e.width = location.width; + e.height = location.height; + } + + public void getChildCount (AccessibleControlEvent e) { + e.detail = 0; + } + + public void getRole (AccessibleControlEvent e) { + e.detail = ACC.ROLE_COMBOBOX; + } + + public void getState (AccessibleControlEvent e) { + e.detail = ACC.STATE_NORMAL; + } + + public void getValue (AccessibleControlEvent e) { + e.result = getText (); + } + }); + + text.getAccessible ().addAccessibleControlListener (new AccessibleControlAdapter () { + public void getRole (AccessibleControlEvent e) { + e.detail = text.getEditable () ? ACC.ROLE_TEXT : ACC.ROLE_LABEL; + } + }); + + arrow.getAccessible ().addAccessibleControlListener (new AccessibleControlAdapter() { + public void getDefaultAction (AccessibleControlEvent e) { + e.result = isDropped () ? SWT.getMessage ("SWT_Close") : SWT.getMessage ("SWT_Open"); //$NON-NLS-1$ //$NON-NLS-2$ + } + }); +} +boolean isDropped () { + return popup.getVisible (); +} +public boolean isFocusControl () { + checkWidget(); + if (text.isFocusControl () || arrow.isFocusControl () || table.isFocusControl () || popup.isFocusControl ()) { + return true; + } + return super.isFocusControl (); +} +void internalLayout (boolean changed) { + if (isDropped ()) dropDown (false); + Rectangle rect = getClientArea (); + int width = rect.width; + int height = rect.height; + Point arrowSize = arrow.computeSize (SWT.DEFAULT, height, changed); + text.setBounds (0, 0, width - arrowSize.x, height); + arrow.setBounds (width - arrowSize.x, 0, arrowSize.x, arrowSize.y); +} +void listEvent (Event event) { + switch (event.type) { + case SWT.Dispose: + if (getShell () != popup.getParent ()) { + TableItem[] items = table.getItems (); + int selectionIndex = table.getSelectionIndex (); + popup = null; + table = null; + createPopup (selectionIndex); + } + break; + case SWT.FocusIn: { + handleFocus (SWT.FocusIn); + break; + } + case SWT.MouseUp: { + if (event.button != 1) return; + dropDown (false); + break; + } + case SWT.Selection: { + int index = table.getSelectionIndex (); + if (index == -1) return; + text.setText (table.getItem (index).getText()); + text.selectAll (); + table.setSelection (index); + Event e = new Event (); + e.time = event.time; + e.stateMask = event.stateMask; + e.doit = event.doit; + notifyListeners (SWT.Selection, e); + event.doit = e.doit; + break; + } + case SWT.Traverse: { + switch (event.detail) { + case SWT.TRAVERSE_RETURN: + case SWT.TRAVERSE_ESCAPE: + case SWT.TRAVERSE_ARROW_PREVIOUS: + case SWT.TRAVERSE_ARROW_NEXT: + event.doit = false; + break; + } + Event e = new Event (); + e.time = event.time; + e.detail = event.detail; + e.doit = event.doit; + e.character = event.character; + e.keyCode = event.keyCode; + notifyListeners (SWT.Traverse, e); + event.doit = e.doit; + event.detail = e.detail; + break; + } + case SWT.KeyUp: { + Event e = new Event (); + e.time = event.time; + e.character = event.character; + e.keyCode = event.keyCode; + e.stateMask = event.stateMask; + notifyListeners (SWT.KeyUp, e); + break; + } + case SWT.KeyDown: { + if (event.character == SWT.ESC) { + // Escape key cancels popup list + dropDown (false); + } + if ((event.stateMask & SWT.ALT) != 0 && (event.keyCode == SWT.ARROW_UP || event.keyCode == SWT.ARROW_DOWN)) { + dropDown (false); + } + if (event.character == SWT.CR) { + // Enter causes default selection + dropDown (false); + Event e = new Event (); + e.time = event.time; + e.stateMask = event.stateMask; + notifyListeners (SWT.DefaultSelection, e); + } + // At this point the widget may have been disposed. + // If so, do not continue. + if (isDisposed ()) break; + Event e = new Event(); + e.time = event.time; + e.character = event.character; + e.keyCode = event.keyCode; + e.stateMask = event.stateMask; + notifyListeners(SWT.KeyDown, e); + break; + + } + } +} + +void popupEvent(Event event) { + switch (event.type) { + case SWT.Paint: + // draw black rectangle around list + Rectangle listRect = table.getBounds(); + Color black = getDisplay().getSystemColor(SWT.COLOR_BLACK); + event.gc.setForeground(black); + event.gc.drawRectangle(0, 0, listRect.width + 1, listRect.height + 1); + break; + case SWT.Close: + event.doit = false; + dropDown (false); + break; + case SWT.Deactivate: + dropDown (false); + break; + } +} +public void redraw () { + super.redraw(); + text.redraw(); + arrow.redraw(); + if (popup.isVisible()) table.redraw(); +} +public void redraw (int x, int y, int width, int height, boolean all) { + super.redraw(x, y, width, height, true); +} + +/** + * Removes the item from the receiver's list at the given + * zero-relative index. + * + * @param index the index for the item + * + * @exception IllegalArgumentException
      + *
    • ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the list minus 1 (inclusive)
    • + *
    + * @exception SWTException
      + *
    • ERROR_WIDGET_DISPOSED - if the receiver has been disposed
    • + *
    • ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
    • + *
    + */ +public void remove (int index) { + checkWidget(); + table.remove (index); +} +/** + * Removes the items from the receiver's list which are + * between the given zero-relative start and end + * indices (inclusive). + * + * @param start the start of the range + * @param end the end of the range + * + * @exception IllegalArgumentException
      + *
    • ERROR_INVALID_RANGE - if either the start or end are not between 0 and the number of elements in the list minus 1 (inclusive)
    • + *
    + * @exception SWTException
      + *
    • ERROR_WIDGET_DISPOSED - if the receiver has been disposed
    • + *
    • ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
    • + *
    + */ +public void remove (int start, int end) { + checkWidget(); + table.remove (start, end); +} +/** + * Searches the receiver's list starting at the first item + * until an item is found that is equal to the argument, + * and removes that item from the list. + * + * @param string the item to remove + * + * @exception IllegalArgumentException
      + *
    • ERROR_NULL_ARGUMENT - if the string is null
    • + *
    • ERROR_INVALID_ARGUMENT - if the string is not found in the list
    • + *
    + * @exception SWTException
      + *
    • ERROR_WIDGET_DISPOSED - if the receiver has been disposed
    • + *
    • ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
    • + *
    + */ +public void remove (String string) { + checkWidget(); + if (string == null) SWT.error (SWT.ERROR_NULL_ARGUMENT); + int index = -1; + for (int i = 0, n = table.getItemCount(); i < n; i++) { + if (table.getItem(i).getText().equals(string)) { + index = i; + break; + } + } + remove(index); +} +/** + * Removes all of the items from the receiver's list and clear the + * contents of receiver's text field. + *

    + * @exception SWTException

      + *
    • ERROR_WIDGET_DISPOSED - if the receiver has been disposed
    • + *
    • ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
    • + *
    + */ +public void removeAll () { + checkWidget(); + text.setText (""); //$NON-NLS-1$ + table.removeAll (); +} +/** + * Removes the listener from the collection of listeners who will + * be notified when the receiver's text is modified. + * + * @param listener the listener which should no longer be notified + * + * @exception IllegalArgumentException
      + *
    • ERROR_NULL_ARGUMENT - if the listener is null
    • + *
    + * @exception SWTException
      + *
    • ERROR_WIDGET_DISPOSED - if the receiver has been disposed
    • + *
    • ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
    • + *
    + * + * @see ModifyListener + * @see #addModifyListener + */ +public void removeModifyListener (ModifyListener listener) { + checkWidget(); + if (listener == null) SWT.error (SWT.ERROR_NULL_ARGUMENT); + removeListener(SWT.Modify, listener); +} +/** + * Removes the listener from the collection of listeners who will + * be notified when the receiver's selection changes. + * + * @param listener the listener which should no longer be notified + * + * @exception IllegalArgumentException
      + *
    • ERROR_NULL_ARGUMENT - if the listener is null
    • + *
    + * @exception SWTException
      + *
    • ERROR_WIDGET_DISPOSED - if the receiver has been disposed
    • + *
    • ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
    • + *
    + * + * @see SelectionListener + * @see #addSelectionListener + */ +public void removeSelectionListener (SelectionListener listener) { + checkWidget(); + if (listener == null) SWT.error (SWT.ERROR_NULL_ARGUMENT); + removeListener(SWT.Selection, listener); + removeListener(SWT.DefaultSelection,listener); +} +/** + * Selects the item at the given zero-relative index in the receiver's + * list. If the item at the index was already selected, it remains + * selected. Indices that are out of range are ignored. + * + * @param index the index of the item to select + * + * @exception SWTException
      + *
    • ERROR_WIDGET_DISPOSED - if the receiver has been disposed
    • + *
    • ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
    • + *
    + */ +public void select (int index) { + checkWidget(); + if (index == -1) { + table.deselectAll (); + text.setText (""); //$NON-NLS-1$ + return; + } + if (0 <= index && index < table.getItemCount()) { + if (index != getSelectionIndex()) { + text.setText (table.getItem (index).getText()); + text.selectAll (); + table.select (index); + table.showSelection (); + } + } +} +public void setBackground (Color color) { + super.setBackground(color); + background = color; + if (text != null) text.setBackground(color); + if (table != null) table.setBackground(color); + if (arrow != null) arrow.setBackground(color); +} +/** + * Sets the editable state. + * + * @param editable the new editable state + * + * @exception SWTException
      + *
    • ERROR_WIDGET_DISPOSED - if the receiver has been disposed
    • + *
    • ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
    • + *
    + * + * @since 3.0 + */ +public void setEditable (boolean editable) { + checkWidget (); + text.setEditable(editable); +} +public void setEnabled (boolean enabled) { + super.setEnabled(enabled); + if (popup != null) popup.setVisible (false); + if (text != null) text.setEnabled(enabled); + if (arrow != null) arrow.setEnabled(enabled); +} +public boolean setFocus () { + checkWidget(); + return text.setFocus (); +} +public void setFont (Font font) { + super.setFont (font); + this.font = font; + text.setFont (font); + table.setFont (font); + internalLayout (true); +} +public void setForeground (Color color) { + super.setForeground(color); + foreground = color; + if (text != null) text.setForeground(color); + if (table != null) table.setForeground(color); + if (arrow != null) arrow.setForeground(color); +} +/** + * Sets the text of the item in the receiver's list at the given + * zero-relative index to the string argument. This is equivalent + * to remove'ing the old item at the index, and then + * add'ing the new item at that index. + * + * @param index the index for the item + * @param string the new text for the item + * + * @exception IllegalArgumentException
      + *
    • ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the list minus 1 (inclusive)
    • + *
    • ERROR_NULL_ARGUMENT - if the string is null
    • + *
    + * @exception SWTException
      + *
    • ERROR_WIDGET_DISPOSED - if the receiver has been disposed
    • + *
    • ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
    • + *
    + */ +public void setItem (int index, String string, Image image) { + checkWidget(); + remove(index); + add(string,image,index); +} +/** + * Sets the receiver's list to be the given array of items. + * + * @param items the array of items + * + * @exception IllegalArgumentException
      + *
    • ERROR_NULL_ARGUMENT - if the items array is null
    • + *
    • ERROR_INVALID_ARGUMENT - if an item in the items array is null
    • + *
    + * @exception SWTException
      + *
    • ERROR_WIDGET_DISPOSED - if the receiver has been disposed
    • + *
    • ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
    • + *
    + */ +public void setItems (String [] items) { + checkWidget (); + this.table.removeAll(); + for (int i = 0, n = items.length; i < n; i++) { + add(items[i],null); + } + if (!text.getEditable ()) text.setText (""); //$NON-NLS-1$ +} + +/** + * Sets the layout which is associated with the receiver to be + * the argument which may be null. + *

    + * Note : No Layout can be set on this Control because it already + * manages the size and position of its children. + *

    + * + * @param layout the receiver's new layout or null + * + * @exception SWTException
      + *
    • ERROR_WIDGET_DISPOSED - if the receiver has been disposed
    • + *
    • ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
    • + *
    + */ +public void setLayout (Layout layout) { + checkWidget (); + return; +} +/** + * Sets the selection in the receiver's text field to the + * range specified by the argument whose x coordinate is the + * start of the selection and whose y coordinate is the end + * of the selection. + * + * @param selection a point representing the new selection start and end + * + * @exception IllegalArgumentException
      + *
    • ERROR_NULL_ARGUMENT - if the point is null
    • + *
    + * @exception SWTException
      + *
    • ERROR_WIDGET_DISPOSED - if the receiver has been disposed
    • + *
    • ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
    • + *
    + */ +public void setSelection (Point selection) { + checkWidget(); + if (selection == null) SWT.error (SWT.ERROR_NULL_ARGUMENT); + text.setSelection (selection.x, selection.y); +} + +/** + * Sets the contents of the receiver's text field to the + * given string. + *

    + * Note: The text field in a Combo is typically + * only capable of displaying a single line of text. Thus, + * setting the text to a string containing line breaks or + * other special characters will probably cause it to + * display incorrectly. + *

    + * + * @param string the new text + * + * @exception IllegalArgumentException
      + *
    • ERROR_NULL_ARGUMENT - if the string is null
    • + *
    + * @exception SWTException
      + *
    • ERROR_WIDGET_DISPOSED - if the receiver has been disposed
    • + *
    • ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
    • + *
    + */ +public void setText (String string) { + checkWidget(); + if (string == null) SWT.error (SWT.ERROR_NULL_ARGUMENT); + int index = -1; + for (int i = 0, n = table.getItemCount(); i < n; i++) { + if (table.getItem(i).getText().equals(string)) { + index = i; + break; + } + } + if (index == -1) { + table.deselectAll (); + text.setText (string); + return; + } + text.setText (string); + text.selectAll (); + table.setSelection (index); + table.showSelection (); +} +/** + * Sets the maximum number of characters that the receiver's + * text field is capable of holding to be the argument. + * + * @param limit new text limit + * + * @exception IllegalArgumentException
      + *
    • ERROR_CANNOT_BE_ZERO - if the limit is zero
    • + *
    + * @exception SWTException
      + *
    • ERROR_WIDGET_DISPOSED - if the receiver has been disposed
    • + *
    • ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
    • + *
    + */ +public void setTextLimit (int limit) { + checkWidget(); + text.setTextLimit (limit); +} + +public void setToolTipText (String string) { + checkWidget(); + super.setToolTipText(string); + arrow.setToolTipText (string); + text.setToolTipText (string); +} + +public void setVisible (boolean visible) { + super.setVisible(visible); + if (!visible) popup.setVisible(false); +} +/** + * Sets the number of items that are visible in the drop + * down portion of the receiver's list. + * + * @param count the new number of items to be visible + * + * @exception SWTException
      + *
    • ERROR_WIDGET_DISPOSED - if the receiver has been disposed
    • + *
    • ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
    • + *
    + * + * @since 3.0 + */ +public void setVisibleItemCount (int count) { + checkWidget (); + if (count < 0) return; + visibleItemCount = count; +} +String stripMnemonic (String string) { + int index = 0; + int length = string.length (); + do { + while ((index < length) && (string.charAt (index) != '&')) index++; + if (++index >= length) return string; + if (string.charAt (index) != '&') { + return string.substring(0, index-1) + string.substring(index, length); + } + index++; + } while (index < length); + return string; +} +void textEvent (Event event) { + switch (event.type) { + case SWT.FocusIn: { + handleFocus (SWT.FocusIn); + break; + } + case SWT.KeyDown: { + if (event.character == SWT.CR) { + dropDown (false); + Event e = new Event (); + e.time = event.time; + e.stateMask = event.stateMask; + notifyListeners (SWT.DefaultSelection, e); + } + //At this point the widget may have been disposed. + // If so, do not continue. + if (isDisposed ()) break; + + if (event.keyCode == SWT.ARROW_UP || event.keyCode == SWT.ARROW_DOWN) { + event.doit = false; + if ((event.stateMask & SWT.ALT) != 0) { + boolean dropped = isDropped (); + text.selectAll (); + if (!dropped) setFocus (); + dropDown (!dropped); + break; + } + + int oldIndex = getSelectionIndex (); + if (event.keyCode == SWT.ARROW_UP) { + select (Math.max (oldIndex - 1, 0)); + } else { + select (Math.min (oldIndex + 1, getItemCount () - 1)); + } + if (oldIndex != getSelectionIndex ()) { + Event e = new Event(); + e.time = event.time; + e.stateMask = event.stateMask; + notifyListeners (SWT.Selection, e); + } + //At this point the widget may have been disposed. + // If so, do not continue. + if (isDisposed ()) break; + } + + // Further work : Need to add support for incremental search in + // pop up list as characters typed in text widget + + Event e = new Event (); + e.time = event.time; + e.character = event.character; + e.keyCode = event.keyCode; + e.stateMask = event.stateMask; + notifyListeners (SWT.KeyDown, e); + break; + } + case SWT.KeyUp: { + Event e = new Event (); + e.time = event.time; + e.character = event.character; + e.keyCode = event.keyCode; + e.stateMask = event.stateMask; + notifyListeners (SWT.KeyUp, e); + break; + } + case SWT.Modify: { + table.deselectAll (); + Event e = new Event (); + e.time = event.time; + notifyListeners (SWT.Modify, e); + break; + } + case SWT.MouseDown: { + if (event.button != 1) return; + if (text.getEditable ()) return; + boolean dropped = isDropped (); + text.selectAll (); + if (!dropped) setFocus (); + dropDown (!dropped); + break; + } + case SWT.MouseUp: { + if (event.button != 1) return; + if (text.getEditable ()) return; + text.selectAll (); + break; + } + case SWT.Traverse: { + switch (event.detail) { + case SWT.TRAVERSE_RETURN: + case SWT.TRAVERSE_ARROW_PREVIOUS: + case SWT.TRAVERSE_ARROW_NEXT: + // The enter causes default selection and + // the arrow keys are used to manipulate the list contents so + // do not use them for traversal. + event.doit = false; + break; + } + + Event e = new Event (); + e.time = event.time; + e.detail = event.detail; + e.doit = event.doit; + e.character = event.character; + e.keyCode = event.keyCode; + notifyListeners (SWT.Traverse, e); + event.doit = e.doit; + event.detail = e.detail; + break; + } + } +} +} diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/language/settings/providers/AbstractLanguageSettingProviderOptionPage.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/language/settings/providers/AbstractLanguageSettingProviderOptionPage.java new file mode 100644 index 00000000000..7ac9d439827 --- /dev/null +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/language/settings/providers/AbstractLanguageSettingProviderOptionPage.java @@ -0,0 +1,13 @@ +package org.eclipse.cdt.internal.ui.language.settings.providers; + +import org.eclipse.cdt.ui.dialogs.AbstractCOptionPage; + +public abstract class AbstractLanguageSettingProviderOptionPage extends AbstractCOptionPage { + protected LanguageSettingsProviderTab providerTab; + protected String providerId; + + protected void init(LanguageSettingsProviderTab providerTab, String providerId) { + this.providerTab = providerTab; + this.providerId = providerId; + } +} diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/language/settings/providers/LanguageSettingEntryDialog.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/language/settings/providers/LanguageSettingEntryDialog.java new file mode 100644 index 00000000000..ef4be0ea722 --- /dev/null +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/language/settings/providers/LanguageSettingEntryDialog.java @@ -0,0 +1,644 @@ +/******************************************************************************* + * Copyright (c) 2010, 2010 Andrew Gvozdev 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: + * Andrew Gvozdev (Quoin Inc.) - initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.internal.ui.language.settings.providers; + +import org.eclipse.core.resources.IProject; +import org.eclipse.jface.dialogs.IDialogConstants; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.ModifyEvent; +import org.eclipse.swt.events.ModifyListener; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.events.SelectionListener; +import org.eclipse.swt.graphics.Image; +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.Control; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.Text; + +import org.eclipse.cdt.core.settings.model.CIncludeFileEntry; +import org.eclipse.cdt.core.settings.model.CIncludePathEntry; +import org.eclipse.cdt.core.settings.model.CLibraryFileEntry; +import org.eclipse.cdt.core.settings.model.CLibraryPathEntry; +import org.eclipse.cdt.core.settings.model.CMacroEntry; +import org.eclipse.cdt.core.settings.model.CMacroFileEntry; +import org.eclipse.cdt.core.settings.model.ICConfigurationDescription; +import org.eclipse.cdt.core.settings.model.ICLanguageSettingEntry; +import org.eclipse.cdt.core.settings.model.ICSettingEntry; +import org.eclipse.cdt.ui.CDTSharedImages; +import org.eclipse.cdt.ui.newui.AbstractCPropertyTab; +import org.eclipse.cdt.ui.newui.AbstractPropertyDialog; + +import org.eclipse.cdt.internal.ui.ImageCombo; +import org.eclipse.cdt.internal.ui.newui.LanguageSettingsImages; +import org.eclipse.cdt.internal.ui.newui.Messages; + +/** + * @noextend This class is not intended to be subclassed by clients. + */ +public class LanguageSettingEntryDialog extends AbstractPropertyDialog { + private static final String SLASH = "/"; //$NON-NLS-1$ + + private ICConfigurationDescription cfgDescription; + private IProject project; + private ICLanguageSettingEntry entry; + private boolean clearValue; + private int kind; + + private Label iconComboKind; + private ImageCombo comboKind; + private ImageCombo comboPathCategory; + private Label labelInput; + public Text inputName; + private Label checkBoxValue; + public Text inputValue; + private Button buttonBrowse; + private Button buttonVars; + private Button checkBoxBuiltIn; + private Button checkBoxFramework; + + private Button checkBoxAllCfgs; + private Button checkBoxAllLangs; + + private Button buttonOk; + private Button buttonCancel; + + + private static final int COMBO_INDEX_INCLUDE_PATH = 0; + private static final int COMBO_INDEX_MACRO = 1; + private static final int COMBO_INDEX_INCLUDE_FILE = 2; + private static final int COMBO_INDEX_MACRO_FILE = 3; + private static final int COMBO_INDEX_LIBRARY_PATH = 4; + private static final int COMBO_INDEX_LIBRARY_FILE = 5; + + final private String [] comboKindItems = { + "Include Directory", + "Preprocessor Macro", + "Include File", + "Preprocessor Macros File", + "Library Path", + "Library", + }; + final private Image[] comboKindImages = { + CDTSharedImages.getImage(CDTSharedImages.IMG_OBJS_INCLUDES_FOLDER), + CDTSharedImages.getImage(CDTSharedImages.IMG_OBJS_MACRO), + CDTSharedImages.getImage(CDTSharedImages.IMG_OBJS_TUNIT_HEADER), + CDTSharedImages.getImage(CDTSharedImages.IMG_OBJS_MACROS_FILE), + CDTSharedImages.getImage(CDTSharedImages.IMG_OBJS_LIBRARY_FOLDER), + CDTSharedImages.getImage(CDTSharedImages.IMG_OBJS_LIBRARY), + }; + + private static final int COMBO_PATH_INDEX_PROJECT = 0; + private static final int COMBO_PATH_INDEX_WORKSPACE = 1; + private static final int COMBO_PATH_INDEX_FILESYSTEM = 2; + + final private String [] pathCategories = { + "Project-Relative", + "Workspace Path", + "Filesystem", + }; + final private Image[] pathCategoryImages = { + CDTSharedImages.getImage(CDTSharedImages.IMG_ETOOL_PROJECT), + CDTSharedImages.getImage(CDTSharedImages.IMG_OBJS_WORKSPACE), + CDTSharedImages.getImage(CDTSharedImages.IMG_OBJS_FILESYSTEM), + }; + + + + private ICLanguageSettingEntry[] entries; + private Composite comp1; + + public LanguageSettingEntryDialog(Shell parent, ICConfigurationDescription cfgDescription, int kind) { + super(parent, ""); + this.cfgDescription = cfgDescription; + this.project = cfgDescription.getProjectDescription().getProject(); + this.entry = null; + this.clearValue = true; + this.kind = kind; + } + + /** + * This constructor is intended to be used with {@code clearValue=true} for "Add" dialogs + * where provided entry is used as a template. + */ + public LanguageSettingEntryDialog(Shell parent, ICConfigurationDescription cfgDescription, ICLanguageSettingEntry entry, boolean clearValue) { + super(parent, ""); + this.cfgDescription = cfgDescription; + this.project = cfgDescription.getProjectDescription().getProject(); + this.entry = entry; + this.kind = entry!=null ? entry.getKind() : ICSettingEntry.INCLUDE_PATH; + this.clearValue = clearValue; + } + + /** + * This constructor is used for "Edit" dialogs to edit provided entry + */ + public LanguageSettingEntryDialog(Shell parent, ICConfigurationDescription cfgDescription, ICLanguageSettingEntry entry) { + this(parent, cfgDescription, entry, false); + } + + private int comboIndexToKind(int index) { + int kind=0; + switch (index) { + case COMBO_INDEX_INCLUDE_PATH: + kind = ICSettingEntry.INCLUDE_PATH; + break; + case COMBO_INDEX_MACRO: + kind = ICSettingEntry.MACRO; + break; + case COMBO_INDEX_INCLUDE_FILE: + kind = ICSettingEntry.INCLUDE_FILE; + break; + case COMBO_INDEX_MACRO_FILE: + kind = ICSettingEntry.MACRO_FILE; + break; + case COMBO_INDEX_LIBRARY_PATH: + kind = ICSettingEntry.LIBRARY_PATH; + break; + case COMBO_INDEX_LIBRARY_FILE: + kind = ICSettingEntry.LIBRARY_FILE; + break; + } + return kind; + } + + private int kindToComboIndex(int kind) { + int index=0; + switch (kind) { + case ICSettingEntry.INCLUDE_PATH: + index = COMBO_INDEX_INCLUDE_PATH; + break; + case ICSettingEntry.MACRO: + index = COMBO_INDEX_MACRO; + break; + case ICSettingEntry.INCLUDE_FILE: + index = COMBO_INDEX_INCLUDE_FILE; + break; + case ICSettingEntry.MACRO_FILE: + index = COMBO_INDEX_MACRO_FILE; + break; + case ICSettingEntry.LIBRARY_PATH: + index = COMBO_INDEX_LIBRARY_PATH; + break; + case ICSettingEntry.LIBRARY_FILE: + index = COMBO_INDEX_LIBRARY_FILE; + break; + } + return index; + } + + @Override + protected Control createDialogArea(Composite parent) { + parent.setLayout(new GridLayout(4, false)); + GridData gd; + + // Composite comp1 + comp1 = new Composite (parent, SWT.NONE); + gd = new GridData(GridData.FILL_HORIZONTAL); + gd.verticalAlignment = SWT.TOP; + gd.horizontalSpan = 7; + comp1.setLayoutData(gd); + comp1.setLayout(new GridLayout(7, false)); + + // Icon for kind + iconComboKind = new Label (comp1, SWT.NONE); + gd = new GridData(); + gd.verticalAlignment = SWT.TOP; + gd.horizontalAlignment = SWT.RIGHT; + iconComboKind.setLayoutData(gd); + iconComboKind.setText("Select Kind:"); + int kindToComboIndex = kindToComboIndex(kind); + iconComboKind.setImage(comboKindImages[kindToComboIndex]); + + // Combo for the setting entry kind + comboKind = new ImageCombo(comp1, SWT.DROP_DOWN | SWT.READ_ONLY | SWT.BORDER); + for (int i = 0; i < comboKindItems.length; i++) { + comboKind.add(comboKindItems[i], comboKindImages[i]); + } + comboKind.setText(comboKindItems[kindToComboIndex]); + + comboKind.addSelectionListener(new SelectionListener() { + public void widgetSelected(SelectionEvent e) { + updateImages(); + setButtons(); + } + public void widgetDefaultSelected(SelectionEvent e) { + widgetSelected(e); + + } + }); + comboKind.setEnabled(clearValue); + + + // + // Icon for path category + final Label comboPathCategoryIcon = new Label (comp1, SWT.NONE); + gd = new GridData(GridData.GRAB_HORIZONTAL | GridData.HORIZONTAL_ALIGN_END); + gd.verticalAlignment = SWT.TOP; + gd.widthHint = 15; + comboPathCategoryIcon.setLayoutData(gd); + comboPathCategoryIcon.setText(""); + + // Combo for path category + comboPathCategory = new ImageCombo(comp1, SWT.DROP_DOWN | SWT.READ_ONLY | SWT.BORDER); + for (int i = 0; i < pathCategories.length; i++) { + comboPathCategory.add(pathCategories[i], pathCategoryImages[i]); + } + int pcindex = COMBO_PATH_INDEX_PROJECT; + if (entry!=null) { + if ( (entry.getFlags() & ICSettingEntry.VALUE_WORKSPACE_PATH) == 0) { + pcindex = COMBO_PATH_INDEX_FILESYSTEM; + } else { + if (entry.getName().startsWith(SLASH)) { + pcindex = COMBO_PATH_INDEX_WORKSPACE; + } else { + pcindex = COMBO_PATH_INDEX_PROJECT; + } + } + + } + comboPathCategory.setText(pathCategories[pcindex]); + gd = new GridData(SWT.FILL, SWT.NONE, false, false); + gd.verticalAlignment = SWT.TOP; + gd.horizontalSpan = 4; + comboPathCategory.setLayoutData(gd); + + comboPathCategory.addSelectionListener(new SelectionListener() { + public void widgetSelected(SelectionEvent e) { + updateImages(); + setButtons(); + } + public void widgetDefaultSelected(SelectionEvent e) { + widgetSelected(e); + + } + }); + + // Dir/File/Name label + labelInput = new Label(comp1, SWT.NONE); + labelInput.setText("Dir:"); + gd = new GridData(); + labelInput.setLayoutData(gd); + + // Dir/File/Name input + inputName = new Text(comp1, SWT.SINGLE | SWT.BORDER); + if (entry!=null && !clearValue) { + inputName.setText(entry.getName()); + } + gd = new GridData(GridData.FILL_HORIZONTAL | GridData.GRAB_HORIZONTAL); + gd.horizontalSpan = 2; + gd.widthHint = 200; + inputName.setLayoutData(gd); + inputName.addModifyListener(new ModifyListener() { + public void modifyText(ModifyEvent e) { + setButtons(); + }}); + + inputName.setFocus(); + inputName.setSelection(0, inputName.getText().length()); + + // Value label + checkBoxValue = new Label(comp1, SWT.NONE); + checkBoxValue.setText("Value:"); + gd = new GridData(); + checkBoxValue.setLayoutData(gd); + + // Path button + buttonBrowse = new Button(comp1, SWT.PUSH); + buttonBrowse.setText("..."); + buttonBrowse.setImage(pathCategoryImages[0]); + buttonBrowse.setLayoutData(new GridData()); + buttonBrowse.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent event) { + buttonPressed(event); + } + }); + + // Variables button + buttonVars = new Button(comp1, SWT.PUSH); + buttonVars.setText(AbstractCPropertyTab.VARIABLESBUTTON_NAME); + buttonVars.setLayoutData(new GridData()); + buttonVars.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent event) { + buttonPressed(event); + } + }); + + // Value input. Located after the other controls to get sufficient width + int comboPathWidth = comboPathCategory.computeSize(SWT.DEFAULT, SWT.NONE).x; + inputValue = new Text(comp1, SWT.SINGLE | SWT.BORDER); + if (entry!=null && !clearValue) { + inputValue.setText(entry.getValue()); + } + gd = new GridData(SWT.FILL, SWT.NONE, false, false); + gd.widthHint = comboPathWidth; + inputValue.setLayoutData(gd); + + if (entry!=null && kind==ICSettingEntry.MACRO && !clearValue) { + inputValue.setFocus(); + inputValue.setSelection(0, inputValue.getText().length()); + } + + // Checkboxes + Composite compCheckboxes = new Composite (parent, SWT.NONE); + gd = new GridData(GridData.FILL_HORIZONTAL); + gd.verticalAlignment = SWT.TOP; + gd.horizontalSpan = 4; + compCheckboxes.setLayoutData(gd); + compCheckboxes.setLayout(new GridLayout(1, false)); + + // Checkbox "Built-In" + checkBoxBuiltIn = new Button(compCheckboxes, SWT.CHECK); + checkBoxBuiltIn.setText("Treat as Built-In (Ignore during build)"); + checkBoxBuiltIn.setSelection(entry!=null && (entry.getFlags()&ICSettingEntry.BUILTIN)!=0); + gd = new GridData(GridData.FILL_HORIZONTAL); + checkBoxBuiltIn.setLayoutData(gd); + checkBoxBuiltIn.addSelectionListener(new SelectionListener() { + + public void widgetSelected(SelectionEvent e) { + updateImages(); + setButtons(); + } + + public void widgetDefaultSelected(SelectionEvent e) { + widgetSelected(e); + } + }); + + // Checkbox "Framework" + checkBoxFramework = new Button(compCheckboxes, SWT.CHECK); + checkBoxFramework.setText("Framework folder (Mac only)"); + checkBoxFramework.setSelection(entry!=null && (entry.getFlags()&ICSettingEntry.FRAMEWORKS_MAC)!=0); + gd = new GridData(GridData.FILL_HORIZONTAL); + checkBoxFramework.setLayoutData(gd); + checkBoxFramework.addSelectionListener(new SelectionListener() { + + public void widgetSelected(SelectionEvent e) { + updateImages(); + setButtons(); + } + + public void widgetDefaultSelected(SelectionEvent e) { + widgetSelected(e); + } + }); + + // Separator + @SuppressWarnings("unused") + Label separator = new Label(compCheckboxes, SWT.SEPARATOR | SWT.HORIZONTAL | SWT.SHADOW_NONE); + + // Checkbox "All configurations" + checkBoxAllCfgs = new Button(compCheckboxes, SWT.CHECK); + checkBoxAllCfgs.setText(Messages.IncludeDialog_2); + gd = new GridData(GridData.FILL_HORIZONTAL); + checkBoxAllCfgs.setLayoutData(gd); + checkBoxAllCfgs.setEnabled(false); + checkBoxAllCfgs.setToolTipText("Not implemented yet"); + + // Checkbox "All languages" + checkBoxAllLangs = new Button(compCheckboxes, SWT.CHECK); + checkBoxAllLangs.setText(Messages.IncludeDialog_3); + gd = new GridData(GridData.FILL_HORIZONTAL); + checkBoxAllLangs.setLayoutData(gd); + checkBoxAllLangs.setEnabled(false); + checkBoxAllLangs.setToolTipText("Not implemented yet"); + + // Buttons + Composite compButtons = new Composite (parent, SWT.FILL); + gd = new GridData(SWT.RIGHT, SWT.BOTTOM, false, false); + gd.horizontalSpan = 4; + gd.grabExcessVerticalSpace = true; + compButtons.setLayoutData(gd); + compButtons.setLayout(new GridLayout(4, false)); + + // placeholder + Label placeholder = new Label(compButtons, 0); + placeholder.setLayoutData(new GridData(GridData.GRAB_HORIZONTAL)); + + // Button OK + buttonOk = new Button(compButtons, SWT.PUSH); + buttonOk.setText(IDialogConstants.OK_LABEL); + gd = new GridData(); + gd.widthHint = buttonVars.computeSize(SWT.DEFAULT,SWT.NONE).x; + buttonOk.setLayoutData(gd); + buttonOk.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent event) { + buttonPressed(event); + } + }); + + // Button Cancel + buttonCancel = new Button(compButtons, SWT.PUSH); + buttonCancel.setText(IDialogConstants.CANCEL_LABEL); + gd = new GridData(); + gd.widthHint = buttonVars.computeSize(SWT.DEFAULT, SWT.NONE).x; + buttonCancel.setLayoutData(gd); + buttonCancel.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent event) { + buttonPressed(event); + } + }); + + parent.getShell().setDefaultButton(buttonOk); + parent.pack(); + + updateImages(); + setButtons(); + return parent; + } + + private void setButtons() { + int kindSelectionIndex = comboKind.getSelectionIndex(); + boolean isMacroSelected = kindSelectionIndex==COMBO_INDEX_MACRO; + comboPathCategory.setVisible(!isMacroSelected); + buttonBrowse.setVisible(!isMacroSelected); + buttonVars.setVisible(!isMacroSelected); + checkBoxValue.setVisible(isMacroSelected); + inputValue.setVisible(isMacroSelected); + + ((GridData)checkBoxValue.getLayoutData()).exclude = !isMacroSelected; + ((GridData)inputValue.getLayoutData()).exclude = !isMacroSelected; + + ((GridData)buttonBrowse.getLayoutData()).exclude = isMacroSelected; + ((GridData)buttonVars.getLayoutData()).exclude = isMacroSelected; + + switch (kindSelectionIndex) { + case COMBO_INDEX_INCLUDE_PATH: + case COMBO_INDEX_LIBRARY_PATH: + labelInput.setText("Path:"); + break; + case COMBO_INDEX_INCLUDE_FILE: + case COMBO_INDEX_MACRO_FILE: + case COMBO_INDEX_LIBRARY_FILE: + labelInput.setText("File:"); + break; + case COMBO_INDEX_MACRO: + default: + labelInput.setText("Name:"); + } + + inputValue.setEnabled(isMacroSelected); + + int indexPathKind = comboPathCategory.getSelectionIndex(); + boolean isProjectSelected = indexPathKind==COMBO_PATH_INDEX_PROJECT; + boolean isWorkspaceSelected = indexPathKind==COMBO_PATH_INDEX_WORKSPACE; + boolean isFilesystemSelected = indexPathKind==COMBO_PATH_INDEX_FILESYSTEM; + + String path = inputName.getText(); + if (path.trim().length()==0) { + buttonOk.setEnabled(false); + } else { + buttonOk.setEnabled((isProjectSelected && !path.startsWith(SLASH)) || + (isWorkspaceSelected && path.startsWith(SLASH)) || isFilesystemSelected); + } + + buttonVars.setEnabled(isFilesystemSelected); + + comp1.layout(true); + } + + @Override + public void buttonPressed(SelectionEvent e) { + String s=null; + if (e.widget.equals(buttonOk)) { + String name = inputName.getText(); + text1 = name; + String value = inputValue.getText(); + check1 = checkBoxAllCfgs.getSelection(); + check3 = checkBoxAllLangs.getSelection(); + result = true; + + int flagBuiltIn = checkBoxBuiltIn.getSelection() ? ICSettingEntry.BUILTIN : 0; + int flagFramework = checkBoxFramework.getSelection() ? ICSettingEntry.FRAMEWORKS_MAC : 0; + int indexPathKind = comboPathCategory.getSelectionIndex(); + int kind = comboKind.getSelectionIndex(); + boolean isProjectPath = indexPathKind==COMBO_PATH_INDEX_PROJECT; + boolean isWorkspacePath = (kind!=COMBO_INDEX_MACRO) && (isProjectPath || indexPathKind==COMBO_PATH_INDEX_WORKSPACE); + int flagWorkspace = isWorkspacePath ? ICSettingEntry.VALUE_WORKSPACE_PATH : 0; + int flags = flagBuiltIn | flagWorkspace | flagFramework; + + ICLanguageSettingEntry entry=null; + switch (comboKind.getSelectionIndex()) { + case COMBO_INDEX_INCLUDE_PATH: + entry = new CIncludePathEntry(name, flags); + break; + case COMBO_INDEX_MACRO: + // note that value=null is not supported by CMacroEntry + entry = new CMacroEntry(name, value, flags); + break; + case COMBO_INDEX_INCLUDE_FILE: + entry = new CIncludeFileEntry(name, flags); + break; + case COMBO_INDEX_MACRO_FILE: + entry = new CMacroFileEntry(name, flags); + break; + case COMBO_INDEX_LIBRARY_PATH: + entry = new CLibraryPathEntry(name, flags); + break; + case COMBO_INDEX_LIBRARY_FILE: + entry = new CLibraryFileEntry(name, flags); + break; + default: + result = false; + } + + entries = new ICLanguageSettingEntry[] {entry}; + shell.dispose(); + } else if (e.widget.equals(buttonCancel)) { + shell.dispose(); + } else if (e.widget.equals(buttonBrowse)) { + boolean isDirectory = false; + boolean isFile = false; + switch (comboKind.getSelectionIndex()) { + case COMBO_INDEX_INCLUDE_PATH: + case COMBO_INDEX_LIBRARY_PATH: + isDirectory = true; + break; + case COMBO_INDEX_INCLUDE_FILE: + case COMBO_INDEX_MACRO_FILE: + case COMBO_INDEX_LIBRARY_FILE: + isFile = true; + break; + case COMBO_INDEX_MACRO: + break; + } + + if (isDirectory) { + switch (comboPathCategory.getSelectionIndex()) { + case COMBO_PATH_INDEX_WORKSPACE: + s = AbstractCPropertyTab.getWorkspaceDirDialog(shell, inputName.getText()); + break; + case COMBO_PATH_INDEX_PROJECT: + s = AbstractCPropertyTab.getProjectDirDialog(shell, inputName.getText(), project); + break; + case COMBO_PATH_INDEX_FILESYSTEM: + s = AbstractCPropertyTab.getFileSystemDirDialog(shell, inputName.getText()); + break; + } + } else if (isFile) { + switch (comboPathCategory.getSelectionIndex()) { + case COMBO_PATH_INDEX_WORKSPACE: + s = AbstractCPropertyTab.getWorkspaceFileDialog(shell, inputName.getText()); + break; + case COMBO_PATH_INDEX_PROJECT: + s = AbstractCPropertyTab.getProjectFileDialog(shell, inputName.getText(), project); + break; + case COMBO_PATH_INDEX_FILESYSTEM: + s = AbstractCPropertyTab.getFileSystemFileDialog(shell, inputName.getText()); + break; + } + } + + if (s != null) { + s = strip_wsp(s); + if (comboPathCategory.getSelectionIndex()==COMBO_PATH_INDEX_PROJECT && s.startsWith(SLASH+project.getName()+SLASH)) { + s=s.substring(project.getName().length()+2); + } + inputName.setText(s); + } + } else if (e.widget.equals(buttonVars)) { + s = AbstractCPropertyTab.getVariableDialog(shell, cfgDescription); + if (s != null) inputName.insert(s); + } + } + + public ICLanguageSettingEntry[] getEntries() { + return entries; + } + + private void updateImages() { + int indexEntryKind = comboKind.getSelectionIndex(); + int indexPathKind = comboPathCategory.getSelectionIndex(); + shell.setText("Add " + comboKindItems[indexEntryKind]); + + int kind = comboIndexToKind(indexEntryKind); + int flagBuiltin = checkBoxBuiltIn.getSelection() ? ICSettingEntry.BUILTIN : 0; + int flagFramework = checkBoxFramework.getSelection() ? ICSettingEntry.FRAMEWORKS_MAC : 0; + boolean isWorkspacePath = indexPathKind==COMBO_PATH_INDEX_PROJECT || indexPathKind==COMBO_PATH_INDEX_WORKSPACE; + int flagWorkspace = isWorkspacePath ? ICSettingEntry.VALUE_WORKSPACE_PATH : 0; + int flags = flagBuiltin | flagWorkspace | flagFramework; + Image image = LanguageSettingsImages.getImage(kind, flags, indexPathKind==COMBO_PATH_INDEX_PROJECT); + + iconComboKind.setImage(image); + shell.setImage(image); + + buttonBrowse.setImage(pathCategoryImages[indexPathKind]); + } + +} diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/language/settings/providers/LanguageSettingsEntriesTab.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/language/settings/providers/LanguageSettingsEntriesTab.java new file mode 100644 index 00000000000..09c5ab848ca --- /dev/null +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/language/settings/providers/LanguageSettingsEntriesTab.java @@ -0,0 +1,1128 @@ +/******************************************************************************* + * Copyright (c) 2010, 2011 Andrew Gvozdev 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: + * Andrew Gvozdev - Initial API and implementation + *******************************************************************************/ + +package org.eclipse.cdt.internal.ui.language.settings.providers; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.jface.viewers.IDecoration; +import org.eclipse.jface.viewers.ITreeContentProvider; +import org.eclipse.jface.viewers.TreeViewer; +import org.eclipse.jface.viewers.Viewer; +import org.eclipse.swt.SWT; +import org.eclipse.swt.custom.SashForm; +import org.eclipse.swt.events.PaintEvent; +import org.eclipse.swt.events.PaintListener; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.graphics.Image; +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.Tree; +import org.eclipse.swt.widgets.TreeColumn; +import org.eclipse.swt.widgets.TreeItem; + +import org.eclipse.cdt.core.language.settings.providers.ILanguageSettingsProvider; +import org.eclipse.cdt.core.language.settings.providers.LanguageSettingsBaseProvider; +import org.eclipse.cdt.core.language.settings.providers.LanguageSettingsManager; +import org.eclipse.cdt.core.language.settings.providers.LanguageSettingsManager_TBD; +import org.eclipse.cdt.core.language.settings.providers.LanguageSettingsSerializable; +import org.eclipse.cdt.core.model.ILanguageDescriptor; +import org.eclipse.cdt.core.model.LanguageManager; +import org.eclipse.cdt.core.model.util.CDTListComparator; +import org.eclipse.cdt.core.settings.model.ICConfigurationDescription; +import org.eclipse.cdt.core.settings.model.ICFileDescription; +import org.eclipse.cdt.core.settings.model.ICFolderDescription; +import org.eclipse.cdt.core.settings.model.ICLanguageSetting; +import org.eclipse.cdt.core.settings.model.ICLanguageSettingEntry; +import org.eclipse.cdt.core.settings.model.ICResourceDescription; +import org.eclipse.cdt.core.settings.model.ICSettingBase; +import org.eclipse.cdt.core.settings.model.ICSettingEntry; +import org.eclipse.cdt.core.settings.model.ILanguageSettingsEditableProvider; +import org.eclipse.cdt.ui.CDTSharedImages; +import org.eclipse.cdt.ui.CUIPlugin; +import org.eclipse.cdt.ui.newui.AbstractCPropertyTab; +import org.eclipse.cdt.ui.newui.CDTPrefUtil; + +import org.eclipse.cdt.internal.ui.newui.LanguageSettingsImages; +import org.eclipse.cdt.internal.ui.newui.Messages; +import org.eclipse.cdt.internal.ui.newui.StatusMessageLine; + + +/** + * This tab presents language settings entries categorized by language + * settings providers. + * + *@noinstantiate This class is not intended to be instantiated by clients. + *@noextend This class is not intended to be subclassed by clients. + */ +public class LanguageSettingsEntriesTab extends AbstractCPropertyTab { + private static final int[] DEFAULT_ENTRIES_SASH_WEIGHTS = new int[] { 10, 30 }; + + private SashForm sashFormEntries; + private Tree treeLanguages; + private Tree treeEntries; + private TreeViewer treeEntriesViewer; + private ICLanguageSetting currentLanguageSetting = null; + private ICLanguageSetting[] allLanguages; + + private Button builtInCheckBox; + private Button enableProvidersCheckBox; + private StatusMessageLine fStatusLine; + + private Page_LanguageSettingsProviders masterPropertyPage = null; + + private static final int BUTTON_ADD = 0; + private static final int BUTTON_EDIT = 1; + private static final int BUTTON_DELETE = 2; + // there is a separator instead of button #3 + private static final int BUTTON_MOVE_UP = 4; + private static final int BUTTON_MOVE_DOWN = 5; + + private final static String[] BUTTON_LABELS = { + ADD_STR, + EDIT_STR, + DEL_STR, + null, + MOVEUP_STR, + MOVEDOWN_STR, + }; + private static final String CLEAR_STR = Messages.LanguageSettingsProviderTab_Clear; + + private Map> initialProvidersMap = new HashMap>(); + private boolean initialEnablement =false; + + private class EntriesTreeLabelProvider extends LanguageSettingsProvidersLabelProvider { + @Override + protected String[] getOverlayKeys(ILanguageSettingsProvider provider) { + String[] overlayKeys = super.getOverlayKeys(provider); + +// if (LanguageSettingsManager.isWorkspaceProvider(provider)) +// provider = LanguageSettingsManager.getRawWorkspaceProvider(provider.getId()); +// + if (currentLanguageSetting != null) { + IResource rc = getResource(); + List entries = getSettingEntries(provider); + if (entries == null && !(rc instanceof IProject)) { + List entriesParent = getSettingEntriesUpResourceTree(provider); + if (entriesParent != null /*&& entriesParent.size() > 0*/) { + overlayKeys[IDecoration.TOP_RIGHT] = CDTSharedImages.IMG_OVR_PARENT; + } + } else if (provider instanceof ILanguageSettingsEditableProvider && (page.isForFile() || page.isForFolder())) { + // Assuming that the default entries for a resource are always null. + // Using that for performance reasons. See note in PerformDefaults(). + String languageId = currentLanguageSetting.getLanguageId(); + List entriesParent = provider.getSettingEntries(null, null, languageId); + if (entries!=null && !entries.equals(entriesParent)) { + overlayKeys[IDecoration.TOP_RIGHT] = CDTSharedImages.IMG_OVR_SETTING; + } + } + } + + // TODO + ICConfigurationDescription cfgDescription = getConfigurationDescription(); + List initialProviders = initialProvidersMap.get(cfgDescription.getId()); + if (initialProviders!=null && !initialProviders.contains(provider)) { + overlayKeys[IDecoration.TOP_RIGHT] = CDTSharedImages.IMG_OVR_EDITED; + } + return overlayKeys; + } + + @Override + public Image getImage(Object element) { + if (element instanceof ICLanguageSettingEntry) { + ICLanguageSettingEntry entry = (ICLanguageSettingEntry) element; + return LanguageSettingsImages.getImage(entry); + } + + return super.getImage(element); + } + + @Override + public String getText(Object element) { + if (element instanceof ICLanguageSettingEntry) { + ICLanguageSettingEntry entry = (ICLanguageSettingEntry) element; + String s = entry.getName(); + if ((entry.getKind() == ICSettingEntry.MACRO) && (entry.getFlags()&ICSettingEntry.UNDEFINED) == 0) { + s = s + '=' + entry.getValue(); + } + return s; + } + + return super.getText(element); + } + } + + /** + * Content provider for setting entries tree. + */ + private class EntriesTreeContentProvider implements ITreeContentProvider { + public Object[] getElements(Object inputElement) { + return getChildren(inputElement); + } + + public Object[] getChildren(Object parentElement) { + if (parentElement instanceof Object[]) + return (Object[]) parentElement; + if (parentElement instanceof ILanguageSettingsProvider) { + ILanguageSettingsProvider lsProvider = (ILanguageSettingsProvider)parentElement; + List entriesList = getSettingEntriesUpResourceTree(lsProvider); + + if (builtInCheckBox.getSelection()==false) { + for (Iterator iter = entriesList.iterator(); iter.hasNext();) { + ICLanguageSettingEntry entry = iter.next(); + if (entry.isBuiltIn()) { + iter.remove(); + } + } + } + + if (entriesList!=null) { + return entriesList.toArray(); + } + } + return null; + } + + public Object getParent(Object element) { + return null; + } + + public boolean hasChildren(Object element) { + Object[] children = getChildren(element); + return children!=null && children.length>0; + } + + public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { + } + + public void dispose() { + } + + } + + /** + * Shortcut for getting the current resource for the property page. + */ + private IResource getResource() { + return (IResource)page.getElement(); + } + + /** + * Shortcut for getting the current configuration description. + */ + private ICConfigurationDescription getConfigurationDescription() { + return getResDesc().getConfiguration(); + } + + /** + * Shortcut for getting the currently selected provider. + */ + private ILanguageSettingsProvider getSelectedProvider() { + ILanguageSettingsProvider provider = null; + + TreeItem[] items = treeEntries.getSelection(); + if (items.length>0) { + TreeItem item = items[0]; + Object itemData = item.getData(); + if (itemData instanceof ICLanguageSettingEntry) { + item = item.getParentItem(); + if (item!=null) { + itemData = item.getData(); + } + } + if (itemData instanceof ILanguageSettingsProvider) { + provider = (ILanguageSettingsProvider)itemData; + } + } + return provider; + } + + /** + * Shortcut for getting the currently selected setting entry. + */ + private ICLanguageSettingEntry getSelectedEntry() { + ICLanguageSettingEntry entry = null; + + TreeItem[] selItems = treeEntries.getSelection(); + if (selItems.length==0) { + return null; + } + + TreeItem item = selItems[0]; + Object itemData = item.getData(); + if (itemData instanceof ICLanguageSettingEntry) { + entry = (ICLanguageSettingEntry)itemData; + } + return entry; + } + + /** + * Shortcut for getting setting entries for current context. {@link LanguageSettingsManager} + * will be checking parent resources if no settings defined for current resource. + * + * @return list of setting entries for the current context. + */ + private List getSettingEntriesUpResourceTree(ILanguageSettingsProvider provider) { + if (currentLanguageSetting==null) + return null; + + String languageId = currentLanguageSetting.getLanguageId(); + if (languageId==null) + return null; + + ICConfigurationDescription cfgDescription = getConfigurationDescription(); + IResource rc = getResource(); + List entries = LanguageSettingsManager.getSettingEntriesUpResourceTree(provider, cfgDescription, rc, languageId); + return entries; + } + + /** + * Shortcut for getting setting entries for current context without checking the parent resource. + * @return list of setting entries for the current context. + */ + private List getSettingEntries(ILanguageSettingsProvider provider) { + String languageId = currentLanguageSetting.getLanguageId(); + if (languageId==null) + return null; + + ICConfigurationDescription cfgDescription = getConfigurationDescription(); + IResource rc = getResource(); + return provider.getSettingEntries(cfgDescription, rc, languageId); + } + + private void addTreeForLanguages(Composite comp) { + treeLanguages = new Tree(comp, SWT.BORDER | SWT.SINGLE | SWT.H_SCROLL); + treeLanguages.setLayoutData(new GridData(GridData.FILL_VERTICAL)); + treeLanguages.setHeaderVisible(true); + + treeLanguages.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + TreeItem[] items = treeLanguages.getSelection(); + if (items.length > 0) { + ICLanguageSetting langSetting = (ICLanguageSetting) items[0].getData(); + if (langSetting != null) { + currentLanguageSetting = langSetting; + updateTreeEntries(); + updateButtons(); + } + } + } + }); + + final TreeColumn columnLanguages = new TreeColumn(treeLanguages, SWT.NONE); + columnLanguages.setText(Messages.AbstractLangsListTab_Languages); + columnLanguages.setWidth(200); + columnLanguages.setResizable(false); + columnLanguages.setToolTipText(Messages.AbstractLangsListTab_Languages); + + treeLanguages.addPaintListener(new PaintListener() { + public void paintControl(PaintEvent e) { + int x = treeLanguages.getBounds().width - 5; + if (columnLanguages.getWidth() != x) + columnLanguages.setWidth(x); + } + }); + + } + + private void addTreeForEntries(Composite comp) { + treeEntries = new Tree(comp, SWT.BORDER | SWT.SINGLE | SWT.H_SCROLL | SWT.V_SCROLL); + treeEntries.setLayoutData(new GridData(GridData.FILL_VERTICAL)); + treeEntries.setHeaderVisible(true); + treeEntries.setLinesVisible(true); + + final TreeColumn treeCol = new TreeColumn(treeEntries, SWT.NONE); + treeEntries.addPaintListener(new PaintListener() { + public void paintControl(PaintEvent e) { + int x = treeEntries.getClientArea().width; + if (treeCol.getWidth() != x) + treeCol.setWidth(x); + } + }); + + treeCol.setText(Messages.LanguageSettingsProviderTab_SettingEntries); + treeCol.setWidth(200); + treeCol.setResizable(false); + treeCol.setToolTipText(Messages.LanguageSettingsProviderTab_SettingEntriesTooltip); + + treeEntriesViewer = new TreeViewer(treeEntries); + treeEntriesViewer.setContentProvider(new EntriesTreeContentProvider()); + treeEntriesViewer.setLabelProvider(new EntriesTreeLabelProvider()); + + treeEntriesViewer.setUseHashlookup(true); + + treeEntries.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + updateStatusLine(); + updateButtons(); + } + + @Override + public void widgetDefaultSelected(SelectionEvent e) { + if (buttonIsEnabled(BUTTON_EDIT) && treeEntries.getSelection().length>0) + buttonPressed(BUTTON_EDIT); + } + }); + + } + + private void trackInitialSettings() { + if (!page.isForPrefs()) { + ICConfigurationDescription[] cfgDescriptions = page.getCfgsEditable(); + for (ICConfigurationDescription cfgDescription : cfgDescriptions) { + if (cfgDescription!=null) { + String cfgId = cfgDescription.getId(); + List initialProviders = cfgDescription.getLanguageSettingProviders(); + initialProvidersMap.put(cfgId, initialProviders); + } + } + initialEnablement = LanguageSettingsManager.isLanguageSettingsProvidersEnabled(page.getProject()); + } + } + + @Override + public void createControls(Composite parent) { + super.createControls(parent); + usercomp.setLayout(new GridLayout()); + GridData gd = (GridData) usercomp.getLayoutData(); + // Discourage settings entry table from trying to show all its items at once, see bug 264330 + gd.heightHint =1; + + if (page instanceof Page_LanguageSettingsProviders) { + masterPropertyPage = (Page_LanguageSettingsProviders) page; + } + + trackInitialSettings(); + + // SashForms for each mode + createShowEntriesSashForm(); + + // Status line + fStatusLine = new StatusMessageLine(usercomp, SWT.LEFT, 2); + + // "Show built-ins" checkbox + builtInCheckBox = setupCheck(usercomp, Messages.AbstractLangsListTab_ShowBuiltin, 1, GridData.FILL_HORIZONTAL); + builtInCheckBox.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + updateTreeEntries(); + } + }); + builtInCheckBox.setSelection(true); + builtInCheckBox.setEnabled(true); + + // "I want to try new scanner discovery" temporary checkbox + enableProvidersCheckBox = setupCheck(usercomp, Messages.CDTMainWizardPage_TrySD90, 2, GridData.FILL_HORIZONTAL); + enableProvidersCheckBox.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + boolean enabled = enableProvidersCheckBox.getSelection(); + if (masterPropertyPage!=null) + masterPropertyPage.setLanguageSettingsProvidersEnabled(enabled); + enableControls(enabled); + updateStatusLine(); + } + }); + + if (masterPropertyPage!=null) + enableProvidersCheckBox.setSelection(masterPropertyPage.isLanguageSettingsProvidersEnabled()); + else + enableProvidersCheckBox.setSelection(LanguageSettingsManager.isLanguageSettingsProvidersEnabled(page.getProject())); + // display but disable the checkbox for file/folder resource + enableProvidersCheckBox.setEnabled(page.isForProject()/* && !isConfigureMode*/); + enableControls(enableProvidersCheckBox.getSelection()); + + initButtons(BUTTON_LABELS); + updateData(getResDesc()); + } + + private void createShowEntriesSashForm() { + sashFormEntries = new SashForm(usercomp,SWT.HORIZONTAL); + + GridData gd = new GridData(GridData.FILL_BOTH); + gd.horizontalSpan = 2; + gd.grabExcessVerticalSpace = true; + sashFormEntries.setLayoutData(gd); + + GridLayout layout = new GridLayout(); + sashFormEntries.setLayout(layout); + + addTreeForLanguages(sashFormEntries); + addTreeForEntries(sashFormEntries); + + sashFormEntries.setWeights(DEFAULT_ENTRIES_SASH_WEIGHTS); + } + + private void enableControls(boolean enable) { + sashFormEntries.setEnabled(enable); + treeLanguages.setEnabled(enable); + treeEntries.setEnabled(enable); + builtInCheckBox.setEnabled(enable); + + buttoncomp.setEnabled(enable); + + if (enable) { + updateTreeEntries(); + } else { + disableButtons(); + } + } + + private void disableButtons() { + buttonSetEnabled(BUTTON_ADD, false); + buttonSetEnabled(BUTTON_EDIT, false); + buttonSetEnabled(BUTTON_DELETE, false); + buttonSetEnabled(BUTTON_MOVE_UP, false); + buttonSetEnabled(BUTTON_MOVE_DOWN, false); +// buttonSetEnabled(BUTTON_CONFIGURE, false); + } + + /** + * Updates state for all buttons. Called when table selection changes. + */ + @Override + protected void updateButtons() { + ILanguageSettingsProvider provider = getSelectedProvider(); + ICLanguageSettingEntry entry = getSelectedEntry(); + List entries = getSettingEntriesUpResourceTree(provider); + + boolean isEntrySelected = entry!=null; + boolean isProviderSelected = !isEntrySelected && (provider!=null); + + boolean isProviderEditable = provider instanceof ILanguageSettingsEditableProvider; +// boolean isUserProvider = provider instanceof UserLanguageSettingsProvider; + + boolean canAdd = isProviderEditable; + boolean canEdit = isProviderEditable && isEntrySelected; + boolean canDelete = isProviderEditable && isEntrySelected; + boolean canClear = isProviderEditable && isProviderSelected && entries!=null && entries.size()>0; + + boolean canMoveUp = false; + boolean canMoveDown = false; + if (isProviderEditable && isEntrySelected && entries!=null) { + int last = entries.size()-1; + int pos = getExactIndex(entries, entry); + + if (pos>=0 && pos<=last) { + canMoveUp = pos!=0; + canMoveDown = pos!=last; + } + } + + buttonSetText(BUTTON_DELETE, isProviderSelected ? CLEAR_STR : DEL_STR); + + buttonSetEnabled(BUTTON_ADD, canAdd); + buttonSetEnabled(BUTTON_EDIT, canEdit); + buttonSetEnabled(BUTTON_DELETE, canDelete || canClear); + + buttonSetEnabled(BUTTON_MOVE_UP, canMoveUp); + buttonSetEnabled(BUTTON_MOVE_DOWN, canMoveDown); + + } + + /** + * Displays warning message - if any - for selected language settings entry. + */ + private void updateStatusLine() { + IStatus status=null; + if (enableProvidersCheckBox.getSelection()==true) { + status = LanguageSettingsImages.getStatus(getSelectedEntry()); + } + if (status==null || status==Status.OK_STATUS) { + ILanguageSettingsProvider provider = getSelectedProvider(); + if (provider!=null && !(provider instanceof UserLanguageSettingsProvider)) { + String msg = "Setting entries for this provider are supplied by system and are not editable."; + status = new Status(IStatus.INFO, CUIPlugin.PLUGIN_ID, msg); + } + } + fStatusLine.setErrorStatus(status); + } + + /** + * Handle buttons + */ + @Override + public void buttonPressed(int buttonIndex) { + ILanguageSettingsProvider selectedProvider = getSelectedProvider(); + ICLanguageSettingEntry selectedEntry = getSelectedEntry(); + + switch (buttonIndex) { + case BUTTON_ADD: + performAdd(selectedProvider); + break; + case BUTTON_EDIT: + performEdit(selectedProvider, selectedEntry); + break; + case BUTTON_DELETE: + performDelete(selectedProvider, selectedEntry); + break; +// case BUTTON_CONFIGURE: +// performConfigure(selectedProvider); +// break; + case BUTTON_MOVE_UP: + performMoveUp(selectedProvider, selectedEntry); + break; + case BUTTON_MOVE_DOWN: + performMoveDown(selectedProvider, selectedEntry); + break; + default: + } + treeEntries.setFocus(); + } + + /** + * That method returns exact position of an element in the list. + * Note that {@link List#indexOf(Object)} returns position of the first element + * equals to the given one, not exact element. + * + * @param entries + * @param entry + * @return exact position of the element or -1 of not found. + */ + private int getExactIndex(List entries, ICLanguageSettingEntry entry) { + if (entries!=null) { + for (int i=0;i0) { + treeEntries.showItem(providerItem.getItems()[0]); + } + TreeItem entryItem = findEntryItem(providerId, entry); + if (entryItem!=null) { + treeEntries.showItem(entryItem); + treeEntries.select(entryItem); + } + } + } + + private void addEntry(ILanguageSettingsProvider provider, ICLanguageSettingEntry entry) { + if (provider!=null && entry != null) { + String providerId = provider.getId(); + + List entries = getWritableEntries(provider); + ICLanguageSettingEntry selectedEntry = getSelectedEntry(); + int pos = getExactIndex(entries, selectedEntry); + entries.add(pos+1, entry); + saveEntries(provider, entries); + + updateTreeEntries(); + selectItem(providerId, entry); + updateButtons(); + } + } + + private void saveEntries(ILanguageSettingsProvider provider, List entries) { + ICConfigurationDescription cfgDescription = getConfigurationDescription(); + IResource rc = getResource(); + String languageId = currentLanguageSetting.getLanguageId(); + + if (provider instanceof LanguageSettingsSerializable) { + if (entries!=null && rc!=null) { + List parentEntries = null; + if (rc instanceof IProject) { + parentEntries = new ArrayList(); + } else { + parentEntries = LanguageSettingsManager.getSettingEntriesUpResourceTree(provider, cfgDescription, rc.getParent(), languageId); + } + if (entries.equals(parentEntries)) { + // to use parent entries instead + entries = null; + } + } + ((LanguageSettingsSerializable)provider).setSettingEntries(cfgDescription, rc, languageId, entries); + } + } + + private List getWritableEntries(ILanguageSettingsProvider provider) { + ICConfigurationDescription cfgDescription = getConfigurationDescription(); + IResource rc = getResource(); + String languageId = currentLanguageSetting.getLanguageId(); + + List entries = provider.getSettingEntries(cfgDescription, rc, languageId); + if (entries==null) { + entries = getSettingEntriesUpResourceTree(provider); + } + entries = new ArrayList(entries); + return entries; + } + + private ICLanguageSettingEntry doAdd() { + ICLanguageSettingEntry selectedEntry = getSelectedEntry(); + ICConfigurationDescription cfgDescription = getConfigurationDescription(); + LanguageSettingEntryDialog dlg = new LanguageSettingEntryDialog(usercomp.getShell(), cfgDescription, selectedEntry, true); + if (dlg.open()) { + return dlg.getEntries()[0]; + } + return null; + } + + private void performAdd(ILanguageSettingsProvider selectedProvider) { + if (selectedProvider instanceof ILanguageSettingsEditableProvider) { + ICLanguageSettingEntry settingEntry = doAdd(); + if (settingEntry!=null) { + selectedProvider = arrangeEditedCopy((ILanguageSettingsEditableProvider)selectedProvider); + addEntry(selectedProvider, settingEntry); + } + } + } + + /** + * @param selectedProvider + * @return + */ + private ILanguageSettingsEditableProvider arrangeEditedCopy(ILanguageSettingsEditableProvider selectedProvider) { + ICConfigurationDescription cfgDescription = getConfigurationDescription(); + List initialProviders = initialProvidersMap.get(cfgDescription.getId()); + if (initialProviders.contains(selectedProvider)) { + List providers = new ArrayList(cfgDescription.getLanguageSettingProviders()); + int pos = providers.indexOf(selectedProvider); + if (pos>=0) { + try { + selectedProvider = selectedProvider.clone(); + providers.set(pos, selectedProvider); + cfgDescription.setLanguageSettingProviders(providers); + } catch (CloneNotSupportedException e) { + CUIPlugin.log("Internal Error: cannot clone provider "+selectedProvider.getId(), e); + } + } else { + CUIPlugin.getDefault().logErrorMessage("Internal Error: cannot find provider "+selectedProvider.getId()); + } + } + return selectedProvider; + } + + private ICLanguageSettingEntry doEdit(ICLanguageSettingEntry ent) { + ICLanguageSettingEntry selectedEntry = getSelectedEntry(); + ICConfigurationDescription cfgDecsription = getConfigurationDescription(); + LanguageSettingEntryDialog dlg = new LanguageSettingEntryDialog(usercomp.getShell(), cfgDecsription, selectedEntry); + if (dlg.open()) { + return dlg.getEntries()[0]; + } + return null; + } + + private void performEdit(ILanguageSettingsProvider selectedProvider, ICLanguageSettingEntry selectedEntry) { + if (selectedProvider instanceof ILanguageSettingsEditableProvider) { + ICLanguageSettingEntry settingEntry = doEdit(selectedEntry); + if (settingEntry!=null) { + selectedProvider = arrangeEditedCopy((ILanguageSettingsEditableProvider)selectedProvider); + deleteEntry(selectedProvider, selectedEntry); + addEntry(selectedProvider, settingEntry); + } + } + } + + private void deleteEntry(ILanguageSettingsProvider provider, ICLanguageSettingEntry entry) { + if (provider!=null && entry != null) { + String providerId = provider.getId(); + + List entries = getWritableEntries(provider); + int pos = getExactIndex(getSettingEntriesUpResourceTree(provider), entry); + entries.remove(entry); + saveEntries(provider, entries); + + if (pos>=entries.size()) + pos = entries.size()-1; + ICLanguageSettingEntry nextEntry = pos>=0 ? entries.get(pos) : null; + + updateTreeEntries(); + selectItem(providerId, nextEntry); + updateButtons(); + } + } + + private void clearProvider(ILanguageSettingsProvider provider) { + if (provider!=null) { + String providerId = provider.getId(); + List empty = new ArrayList(); + saveEntries(provider, empty); + + updateTreeEntries(); + selectItem(providerId, null); + updateButtons(); + } + } + + private void performDelete(ILanguageSettingsProvider selectedProvider, ICLanguageSettingEntry selectedEntry) { + if (selectedProvider instanceof ILanguageSettingsEditableProvider) { + selectedProvider = arrangeEditedCopy((ILanguageSettingsEditableProvider)selectedProvider); + if (selectedEntry!=null) { + deleteEntry(selectedProvider, selectedEntry); + } else { + clearProvider(selectedProvider); + } + } + } + + private void moveEntry(ILanguageSettingsProvider provider, ICLanguageSettingEntry entry, boolean up) { + if (provider!=null && entry != null) { + String providerId = provider.getId(); + + List entries = getWritableEntries(provider); + int pos = getExactIndex(entries, entry); + int newPos = up ? pos-1 : pos+1; + Collections.swap(entries, pos, newPos); + saveEntries(provider, entries); + + updateTreeEntries(); + selectItem(providerId, entry); + updateButtons(); + } + } + + private void performMoveUp(ILanguageSettingsProvider selectedProvider, ICLanguageSettingEntry selectedEntry) { + if (selectedEntry!=null && (selectedProvider instanceof ILanguageSettingsEditableProvider)) { + selectedProvider = arrangeEditedCopy((ILanguageSettingsEditableProvider)selectedProvider); + moveEntry(selectedProvider, selectedEntry, true); + } + } + + private void performMoveDown(ILanguageSettingsProvider selectedProvider, ICLanguageSettingEntry selectedEntry) { + if (selectedEntry!=null && (selectedProvider instanceof ILanguageSettingsEditableProvider)) { + selectedProvider = arrangeEditedCopy((ILanguageSettingsEditableProvider)selectedProvider); + moveEntry(selectedProvider, selectedEntry, false); + } + } + + /** + * Get list of providers to display in the settings entry tree. + */ + private List getProviders(ICLanguageSetting languageSetting) { + List itemsList = new LinkedList(); + if (languageSetting!=null) { + String langId = languageSetting.getLanguageId(); + if (langId != null) { + IResource rc = getResource(); + ICConfigurationDescription cfgDescription = getConfigurationDescription(); + if (rc!=null && cfgDescription!=null) { + List cfgProviders = cfgDescription.getLanguageSettingProviders(); + for (ILanguageSettingsProvider cfgProvider : cfgProviders) { + ILanguageSettingsProvider rawProvider = LanguageSettingsManager.getRawProvider(cfgProvider); + if (rawProvider instanceof LanguageSettingsBaseProvider) { + // filter out providers incapable of providing entries for this language + List languageIds = ((LanguageSettingsBaseProvider)rawProvider).getLanguageScope(); + if (languageIds!=null && !languageIds.contains(langId)) { + continue; + } + } + itemsList.add(cfgProvider); + } + } + } + } + return itemsList; + } + + /** + * Refreshes the entries tree in "Show Entries" mode. + */ + public void updateTreeEntries() { + List tableItems = getProviders(currentLanguageSetting); + treeEntriesViewer.setInput(tableItems.toArray(new Object[tableItems.size()])); + updateStatusLine(); + updateButtons(); + } + + private ICLanguageSetting[] getLangSettings(ICResourceDescription rcDes) { + switch (rcDes.getType()) { + case ICSettingBase.SETTING_PROJECT: + case ICSettingBase.SETTING_CONFIGURATION: + case ICSettingBase.SETTING_FOLDER: + ICFolderDescription foDes = (ICFolderDescription) rcDes; + return foDes.getLanguageSettings(); + case ICSettingBase.SETTING_FILE: + ICFileDescription fiDes = (ICFileDescription) rcDes; + ICLanguageSetting langSetting = fiDes.getLanguageSetting(); + return (langSetting != null) ? new ICLanguageSetting[] { langSetting } : null; + } + return null; + } + + private void updateTreeLanguages(ICResourceDescription rcDes) { + treeLanguages.removeAll(); + TreeItem selectedLanguageItem = null; + allLanguages = getLangSettings(rcDes); + if (allLanguages != null) { + Arrays.sort(allLanguages, CDTListComparator.getInstance()); + for (ICLanguageSetting langSetting : allLanguages) { + String langId = langSetting.getLanguageId(); + if (langId==null || langId.length()==0) + continue; + + LanguageManager langManager = LanguageManager.getInstance(); + ILanguageDescriptor langDes = langManager.getLanguageDescriptor(langId); + if (langDes == null) + continue; + + langId = langDes.getName(); + if (langId == null || langId.length()==0) + continue; + + TreeItem t = new TreeItem(treeLanguages, SWT.NONE); + t.setText(0, langId); + t.setData(langSetting); + if (selectedLanguageItem == null) { + if (currentLanguageSetting!=null) { + if (currentLanguageSetting.getLanguageId().equals(langSetting.getLanguageId())) { + selectedLanguageItem = t; + currentLanguageSetting = langSetting; + } + } else { + selectedLanguageItem = t; + currentLanguageSetting = langSetting; + } + } + } + + if (selectedLanguageItem != null) { + treeLanguages.setSelection(selectedLanguageItem); + } + } + } + + /** + * Called when configuration changed Refreshes languages list entries tree. + */ + @Override + public void updateData(ICResourceDescription rcDes) { + if (!canBeVisible()) + return; + + if (rcDes!=null) { + if (page.isMultiCfg()) { + setAllVisible(false, null); + return; + } else { + setAllVisible(true, null); + } + + updateTreeLanguages(rcDes); + updateTreeEntries(); + if (masterPropertyPage!=null) { + boolean enabled = masterPropertyPage.isLanguageSettingsProvidersEnabled(); + enableProvidersCheckBox.setSelection(enabled); + enableControls(enabled); + } + } + updateButtons(); + } + + @Override + protected void performDefaults() { + // This page restores defaults for file/folder only. + // Project and Preferences page are restored by LanguageSettingsProviderTab. + if (page.isForFile() || page.isForFolder()) { + // The logic below is not exactly correct as the default for a resource could be different than null. + // It is supposed to match the one taken from extension for the same resource which in theory can be non-null. + // However for the performance reasons for resource decorators where the same logic is used + // we use null for resetting file/folder resource which should be correct in most cases. + // Count that as a feature. + boolean changed = false; + ICConfigurationDescription cfgDescription = getConfigurationDescription(); + IResource rc = getResource(); + List providers = cfgDescription.getLanguageSettingProviders(); + List writableProviders = new ArrayList(providers.size()); + +providers: for (ILanguageSettingsProvider provider : providers) { + ILanguageSettingsEditableProvider writableProvider = null; + if (provider instanceof ILanguageSettingsEditableProvider) { + TreeItem[] tisLang = treeLanguages.getItems(); + for (TreeItem tiLang : tisLang) { + Object item = tiLang.getData(); + if (item instanceof ICLanguageSetting) { + String languageId = ((ICLanguageSetting)item).getLanguageId(); + if (languageId!=null) { + if (provider.getSettingEntries(cfgDescription, rc, languageId)!=null) { + try { + // clone providers to be able to "Cancel" in UI + if (writableProvider==null) { + writableProvider = ((ILanguageSettingsEditableProvider) provider).clone(); + } + writableProvider.setSettingEntries(cfgDescription, rc, languageId, null); + changed = true; + } catch (CloneNotSupportedException e) { + CUIPlugin.log("Internal Error: cannot clone provider "+provider.getId(), e); + continue providers; + } + } + } + } + } + } + if (writableProvider!=null) + writableProviders.add(writableProvider); + else + writableProviders.add(provider); + } + if (changed) { + cfgDescription.setLanguageSettingProviders(writableProviders); +// updateTreeEntries(); +// updateData(getResDesc()); + List tableItems = getProviders(currentLanguageSetting); + treeEntriesViewer.setInput(tableItems.toArray(new Object[tableItems.size()])); + } + } + } + + @Override + protected void performApply(ICResourceDescription srcRcDescription, ICResourceDescription destRcDescription) { + if (!page.isForPrefs()) { + ICConfigurationDescription srcCfgDescription = srcRcDescription.getConfiguration(); + ICConfigurationDescription destCfgDescription = destRcDescription.getConfiguration(); + + List providers = srcCfgDescription.getLanguageSettingProviders(); + destCfgDescription.setLanguageSettingProviders(providers); + } + + if (!page.isForPrefs()) { + ICConfigurationDescription sd = srcRcDescription.getConfiguration(); + ICConfigurationDescription dd = destRcDescription.getConfiguration(); + List newProviders = sd.getLanguageSettingProviders(); + dd.setLanguageSettingProviders(newProviders); + } + + performOK(); + } + + @Override + protected void performOK() { + if (page.isForProject() && enableProvidersCheckBox!=null) { + boolean enabled = enableProvidersCheckBox.getSelection(); + if (masterPropertyPage!=null) + enabled = masterPropertyPage.isLanguageSettingsProvidersEnabled(); + LanguageSettingsManager.setLanguageSettingsProvidersEnabled(page.getProject(), enabled); + enableProvidersCheckBox.setSelection(enabled); + } + + try { + LanguageSettingsManager_TBD.serializeWorkspaceProviders(); + } catch (CoreException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + throw new UnsupportedOperationException("Internal Error"); + } + + trackInitialSettings(); + updateData(getResDesc()); + } + + @Override + public boolean canBeVisible() { + if (CDTPrefUtil.getBool(CDTPrefUtil.KEY_NO_SHOW_PROVIDERS)) + return false; + if (page.isForPrefs()) + return true; + + ICLanguageSetting [] langSettings = getLangSettings(getResDesc()); + if (langSettings == null) + return false; + + for (ICLanguageSetting langSetting : langSettings) { + String langId = langSetting.getLanguageId(); + if (langId!=null && langId.length()>0) { + LanguageManager langManager = LanguageManager.getInstance(); + ILanguageDescriptor langDes = langManager.getLanguageDescriptor(langId); + if (langDes != null) + return true; + } + } + + return false; + } + + /** + * Shortcut for setting setting entries for current context. + * + */ + private void setSettingEntries(ILanguageSettingsEditableProvider provider, List entries) { + ICConfigurationDescription cfgDescription = getConfigurationDescription(); + IResource rc = getResource(); + String languageId = currentLanguageSetting.getLanguageId(); + if (languageId!=null) + provider.setSettingEntries(cfgDescription, rc, languageId, entries); + } + + @Override + protected boolean isIndexerAffected() { +// List newProvidersList = null; +// ICConfigurationDescription cfgDescription = getConfigurationDescription(); +// if (cfgDescription!=null) { +// newProvidersList = cfgDescription.getLanguageSettingProviders(); +// } +// boolean newEnablement = LanguageSettingsManager.isLanguageSettingsProvidersEnabled(page.getProject()); +// +// boolean isEqualList = (newProvidersList==initialProvidersList) || (newProvidersList!=null && newProvidersList.equals(initialProvidersList)); +// return newEnablement!=initialEnablement || (newEnablement==true && !isEqualList); + // FIXME + return true; + } + +} diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/language/settings/providers/LanguageSettingsProviderAssociation.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/language/settings/providers/LanguageSettingsProviderAssociation.java new file mode 100644 index 00000000000..76537635cd5 --- /dev/null +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/language/settings/providers/LanguageSettingsProviderAssociation.java @@ -0,0 +1,246 @@ +package org.eclipse.cdt.internal.ui.language.settings.providers; + +import java.net.MalformedURLException; +import java.net.URL; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +import org.eclipse.core.runtime.IConfigurationElement; +import org.eclipse.core.runtime.IExtension; +import org.eclipse.core.runtime.IExtensionPoint; +import org.eclipse.core.runtime.IExtensionRegistry; +import org.eclipse.core.runtime.Platform; + +import org.eclipse.cdt.core.language.settings.providers.ILanguageSettingsProvider; +import org.eclipse.cdt.ui.CDTSharedImages; +import org.eclipse.cdt.ui.CUIPlugin; +import org.eclipse.cdt.ui.dialogs.ICOptionPage; + +public class LanguageSettingsProviderAssociation { + public static final String LANGUAGE_SETTINGS_PROVIDER_UI = "LanguageSettingsProviderAssociation"; //$NON-NLS-1$ + + private static final String ELEM_ID_ASSOCIATION = "id-association"; //$NON-NLS-1$ + private static final String ELEM_CLASS_ASSOCIATION = "class-association"; //$NON-NLS-1$ + private static final String ATTR_ID = "id"; //$NON-NLS-1$ + private static final String ATTR_CLASS = "class"; //$NON-NLS-1$ + private static final String ATTR_ICON = "icon"; //$NON-NLS-1$ + private static final String ATTR_PAGE = "page"; //$NON-NLS-1$ + + static private List loadedIcons = null; + static private Map fImagesUrlById = null; + static private Map fImagesUrlByClass = null; + static private List fRegirestedIds = null; + static private List fRegisteredClasses = null; + + private static void loadExtensions() { + if (loadedIcons!=null) { + return; + } + if (loadedIcons==null) loadedIcons = new ArrayList(); + if (fImagesUrlById==null) fImagesUrlById = new HashMap(); + if (fImagesUrlByClass==null) fImagesUrlByClass = new HashMap(); + if (fRegirestedIds==null) fRegirestedIds = new ArrayList(); + if (fRegisteredClasses==null) fRegisteredClasses = new ArrayList(); + + IExtensionRegistry registry = Platform.getExtensionRegistry(); + IExtensionPoint extension = registry.getExtensionPoint(CUIPlugin.PLUGIN_ID, LanguageSettingsProviderAssociation.LANGUAGE_SETTINGS_PROVIDER_UI); + if (extension != null) { + IExtension[] extensions = extension.getExtensions(); + for (IExtension ext : extensions) { + @SuppressWarnings("unused") + String extensionID = ext.getUniqueIdentifier(); + for (IConfigurationElement cfgEl : ext.getConfigurationElements()) { + if (cfgEl.getName().equals(ELEM_ID_ASSOCIATION)) { + String id = cfgEl.getAttribute(ATTR_ID); + URL url = getIconUrl(cfgEl); + fImagesUrlById.put(id, url); + fRegirestedIds.add(id); + } else if (cfgEl.getName().equals(ELEM_CLASS_ASSOCIATION)) { + String className = cfgEl.getAttribute(ATTR_CLASS); + URL url = getIconUrl(cfgEl); + fImagesUrlByClass.put(className, url); + String pageClass = cfgEl.getAttribute(ATTR_PAGE); + if (pageClass!=null && pageClass.trim().length()>0) { + fRegisteredClasses.add(className); + } + } + } + } + } + + } + + private static URL getIconUrl(IConfigurationElement config) { + URL url = null; + try { + String iconName = config.getAttribute(ATTR_ICON); + if (iconName != null) { + URL pluginInstallUrl = Platform.getBundle(config.getDeclaringExtension().getContributor().getName()).getEntry("/"); //$NON-NLS-1$ + url = new URL(pluginInstallUrl, iconName); + if (loadedIcons.contains(url)) + return url; + } + } catch (MalformedURLException exception) {} + + loadedIcons.add(url); + if (url!=null) { + CDTSharedImages.register(url); + } + + return url; + } + + public static URL getImageUrl(String id) { + if (fImagesUrlById==null) { + loadExtensions(); + } + return fImagesUrlById.get(id); + } + + private static ICOptionPage createOptionsPageById(String providerId) { + if (fRegirestedIds==null) { + loadExtensions(); + } + if (fRegirestedIds.contains(providerId)) { + IExtensionRegistry registry = Platform.getExtensionRegistry(); + IExtensionPoint extension = registry.getExtensionPoint(CUIPlugin.PLUGIN_ID, LanguageSettingsProviderAssociation.LANGUAGE_SETTINGS_PROVIDER_UI); + if (extension != null) { + IExtension[] extensions = extension.getExtensions(); + for (IExtension ext : extensions) { + try { + @SuppressWarnings("unused") + String extensionID = ext.getUniqueIdentifier(); + for (IConfigurationElement cfgEl : ext.getConfigurationElements()) { + if (cfgEl.getName().equals(ELEM_ID_ASSOCIATION)) { + String id = cfgEl.getAttribute(ATTR_ID); + if (providerId.equals(id)) { + String pageClass = cfgEl.getAttribute(ATTR_PAGE); + if (pageClass!=null && pageClass.trim().length()>0) { + ICOptionPage page = (ICOptionPage) cfgEl.createExecutableExtension(ATTR_PAGE); + return page; + } + } + } + } + } catch (Exception e) { + CUIPlugin.log("Cannot load LanguageSettingsProviderAssociation extension " + ext.getUniqueIdentifier(), e); //$NON-NLS-1$ + } + } + } + } + return null; + } + + private static ICOptionPage createOptionsPageByClass(String providerClassName) { + if (fRegisteredClasses==null) { + loadExtensions(); + } + if (fRegisteredClasses.contains(providerClassName)) { + IExtensionRegistry registry = Platform.getExtensionRegistry(); + IExtensionPoint extension = registry.getExtensionPoint(CUIPlugin.PLUGIN_ID, LanguageSettingsProviderAssociation.LANGUAGE_SETTINGS_PROVIDER_UI); + if (extension != null) { + IExtension[] extensions = extension.getExtensions(); + for (IExtension ext : extensions) { + try { + @SuppressWarnings("unused") + String extensionID = ext.getUniqueIdentifier(); + for (IConfigurationElement cfgEl : ext.getConfigurationElements()) { + if (cfgEl.getName().equals(ELEM_CLASS_ASSOCIATION)) { + String className = cfgEl.getAttribute(ATTR_CLASS); + if (providerClassName.equals(className)) { + String pageClass = cfgEl.getAttribute(ATTR_PAGE); + if (pageClass!=null && pageClass.trim().length()>0) { + ICOptionPage page = (ICOptionPage) cfgEl.createExecutableExtension(ATTR_PAGE); + return page; + } + } + } + } + } catch (Exception e) { + CUIPlugin.log("Cannot load LanguageSettingsProviderAssociation extension " + ext.getUniqueIdentifier(), e); //$NON-NLS-1$ + } + } + } + } + return null; + } + + /** + * Returns Language Settings Provider image registered for closest superclass + * or interface. + * + * @param clazz - class to find Language Settings Provider image. + * @return image or {@code null} + */ + public static URL getImage(Class clazz) { + URL url = null; + + outer: for (Class cl=clazz;cl!=null;cl=cl.getSuperclass()) { + url = getImageURL(cl); + if (url!=null) + break; + + // this does not check for superinterfaces, feel free to implement as needed + for (Class in : cl.getInterfaces()) { + url = getImageURL(in); + if (url!=null) + break outer; + } + } + return url; + } + + private static URL getImageURL(Class clazz) { + String className = clazz.getCanonicalName(); + Set> entrySet = fImagesUrlByClass.entrySet(); + for (Entry entry : entrySet) { + if (entry.getKey().equals(className)) { + return entry.getValue(); + } + } + return null; + } + + /** + * Returns Language Settings Provider image registered for closest superclass. + * @param provider TODO + * @return image or {@code null} + */ + public static ICOptionPage createOptionsPage(ILanguageSettingsProvider provider) { + String id = provider.getId(); + ICOptionPage optionsPage = createOptionsPageById(id); + if (optionsPage!=null) { + return optionsPage; + } + + Class clazz = provider.getClass(); + outer: for (Class cl=clazz;cl!=null;cl=cl.getSuperclass()) { + optionsPage = createOptionsPageByClass(cl); + if (optionsPage!=null) + break; + + // this does not check for superinterfaces, feel free to implement as needed + for (Class in : cl.getInterfaces()) { + optionsPage = createOptionsPageByClass(in); + if (optionsPage!=null) + break outer; + } + } + return optionsPage; + } + + private static ICOptionPage createOptionsPageByClass(Class c) { + ICOptionPage optionsPage = null; + String className = c.getCanonicalName(); + if (fRegisteredClasses.contains(className)) { + optionsPage = createOptionsPageByClass(className); + } + return optionsPage; + } + + +} diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/language/settings/providers/LanguageSettingsProviderTab.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/language/settings/providers/LanguageSettingsProviderTab.java new file mode 100644 index 00000000000..afcc404fad5 --- /dev/null +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/language/settings/providers/LanguageSettingsProviderTab.java @@ -0,0 +1,1059 @@ +/******************************************************************************* + * Copyright (c) 2010, 2011 Andrew Gvozdev 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: + * Andrew Gvozdev - Initial API and implementation + *******************************************************************************/ + +package org.eclipse.cdt.internal.ui.language.settings.providers; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.TreeSet; + +import org.eclipse.core.resources.IResource; +import org.eclipse.core.runtime.Assert; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.jface.viewers.ArrayContentProvider; +import org.eclipse.jface.viewers.CheckStateChangedEvent; +import org.eclipse.jface.viewers.CheckboxTableViewer; +import org.eclipse.jface.viewers.ICheckStateListener; +import org.eclipse.jface.viewers.IDecoration; +import org.eclipse.swt.SWT; +import org.eclipse.swt.custom.SashForm; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +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.Event; +import org.eclipse.swt.widgets.Group; +import org.eclipse.swt.widgets.Link; +import org.eclipse.swt.widgets.Listener; +import org.eclipse.swt.widgets.Table; +import org.eclipse.ui.dialogs.PreferencesUtil; + +import org.eclipse.cdt.core.language.settings.providers.ILanguageSettingsProvider; +import org.eclipse.cdt.core.language.settings.providers.LanguageSettingsManager; +import org.eclipse.cdt.core.language.settings.providers.LanguageSettingsManager_TBD; +import org.eclipse.cdt.core.model.ILanguageDescriptor; +import org.eclipse.cdt.core.model.LanguageManager; +import org.eclipse.cdt.core.settings.model.ICConfigurationDescription; +import org.eclipse.cdt.core.settings.model.ICFileDescription; +import org.eclipse.cdt.core.settings.model.ICFolderDescription; +import org.eclipse.cdt.core.settings.model.ICLanguageSetting; +import org.eclipse.cdt.core.settings.model.ICResourceDescription; +import org.eclipse.cdt.core.settings.model.ICSettingBase; +import org.eclipse.cdt.core.settings.model.ILanguageSettingsEditableProvider; +import org.eclipse.cdt.ui.CDTSharedImages; +import org.eclipse.cdt.ui.CUIPlugin; +import org.eclipse.cdt.ui.dialogs.DialogsMessages; +import org.eclipse.cdt.ui.dialogs.ICOptionPage; +import org.eclipse.cdt.ui.newui.AbstractCPropertyTab; +import org.eclipse.cdt.ui.newui.CDTPrefUtil; +import org.eclipse.cdt.utils.ui.controls.TabFolderLayout; + +import org.eclipse.cdt.internal.ui.newui.Messages; +import org.eclipse.cdt.internal.ui.newui.StatusMessageLine; + +/** + * This tab presents language settings entries categorized by language + * settings providers. + * + *@noinstantiate This class is not intended to be instantiated by clients. + *@noextend This class is not intended to be subclassed by clients. + */ +public class LanguageSettingsProviderTab extends AbstractCPropertyTab { + private static final String WORKSPACE_PREFERENCE_PAGE = "org.eclipse.cdt.ui.preferences.BuildSettingProperties"; //$NON-NLS-1$ + // TODO: generalize + private static final String TEST_PLUGIN_ID_PATTERN = "org.eclipse.cdt.*.tests.*"; //$NON-NLS-1$ + +// private static final String RENAME_STR = "Rename..."; +// private static final String RUN_STR = Messages.LanguageSettingsProviderTab_Run; + private static final String CLEAR_STR = Messages.LanguageSettingsProviderTab_Clear; + private static final String RESET_STR = "Reset"; + +// private static final int BUTTON_RENAME = 0; +// private static final int BUTTON_RUN = 0; + private static final int BUTTON_CLEAR = 0; + private static final int BUTTON_RESET = 1; + // there is a separator instead of button #2 + private static final int BUTTON_MOVE_UP = 3; + private static final int BUTTON_MOVE_DOWN = 4; + + private final static String[] BUTTON_LABELS_PROJECT = { +// RENAME_STR, +// RUN_STR, + CLEAR_STR, + RESET_STR, + null, + MOVEUP_STR, + MOVEDOWN_STR, + }; + + private final static String[] BUTTON_LABELS_PREF = { +// RENAME_STR, +// RUN_STR, + CLEAR_STR, + RESET_STR, + }; + + private static final int[] DEFAULT_CONFIGURE_SASH_WEIGHTS = new int[] { 50, 50 }; + private SashForm sashFormConfigure; + + private Table tableProviders; + private CheckboxTableViewer tableProvidersViewer; + private Group groupOptionsPage; + private ICOptionPage currentOptionsPage = null; + private Composite compositeOptionsPage; + + private Button enableProvidersCheckBox; + private StatusMessageLine fStatusLine; + + private Button globalProviderCheckBox = null; + private Link linkWorkspacePreferences = null; + + private Page_LanguageSettingsProviders masterPropertyPage = null; + + /** + * List of providers presented to the user. + * For global providers included in a configuration this contains references + * not raw providers. + */ + private List presentedProviders = null; + private final Map optionsPageMap = new HashMap(); + private Map> initialProvidersByCfg = new HashMap>(); + + private boolean initialEnablement = false; + + /** + * Returns current working copy of the provider. Creates one if it has not been created yet. + * Used by option pages when there is a need to modify the provider. + * Warning: Do not cache the result as the provider can be replaced at any time. + * @param providerId + * + * @return the provider + */ + public ILanguageSettingsProvider getWorkingCopy(String providerId) { + ILanguageSettingsProvider provider = findProvider(providerId, presentedProviders); + if (isWorkingCopy(provider)) + return provider; + + ILanguageSettingsProvider rawProvider = LanguageSettingsManager.getRawProvider(provider); + Assert.isTrue(rawProvider instanceof ILanguageSettingsEditableProvider); + + ILanguageSettingsEditableProvider editableProvider = (ILanguageSettingsEditableProvider)rawProvider; + try { + ILanguageSettingsEditableProvider newProvider = editableProvider.clone(); + replaceSelectedProvider(newProvider); + return newProvider; + + } catch (CloneNotSupportedException e) { + CUIPlugin.log("Error cloning provider " + editableProvider.getId(), e); + // TODO warning dialog for user? + } + + return null; + } + + private class ProvidersTableLabelProvider extends LanguageSettingsProvidersLabelProvider { + @Override + protected String[] getOverlayKeys(ILanguageSettingsProvider provider) { + String[] overlayKeys = super.getOverlayKeys(provider); + + ILanguageSettingsProvider rawProvider = page.isForPrefs() ? LanguageSettingsManager.getRawProvider(provider) : provider; + if (LanguageSettingsManager_TBD.isReconfigured(rawProvider)) { + overlayKeys[IDecoration.TOP_RIGHT] = CDTSharedImages.IMG_OVR_SETTING; + } + + if (isWorkingCopy(provider)) { + overlayKeys[IDecoration.TOP_RIGHT] = CDTSharedImages.IMG_OVR_EDITED; + } + return overlayKeys; + } + } + + /** + * Shortcut for getting the current resource for the property page. + */ + private IResource getResource() { + return (IResource)page.getElement(); + } + + /** + * Shortcut for getting the current configuration description. + */ + private ICConfigurationDescription getConfigurationDescription() { + if (page.isForPrefs()) + return null; + + ICConfigurationDescription cfgDescription = getResDesc().getConfiguration(); + return cfgDescription; + } + + /** + * Shortcut for getting the currently selected provider. + */ + private ILanguageSettingsProvider getSelectedProvider() { + ILanguageSettingsProvider provider = null; + + int pos = tableProviders.getSelectionIndex(); + if (pos >= 0 && pos initialProviders = cfgDescription.getLanguageSettingProviders(); + initialProvidersByCfg.put(cfgId, initialProviders); + } + } + initialEnablement = LanguageSettingsManager.isLanguageSettingsProvidersEnabled(page.getProject()); + } + } + + @Override + public void createControls(Composite parent) { + super.createControls(parent); + usercomp.setLayout(new GridLayout()); + GridData gd = (GridData) usercomp.getLayoutData(); + // Discourage settings entry table from trying to show all its items at once, see bug 264330 + gd.heightHint =1; + + if (page instanceof Page_LanguageSettingsProviders) { + masterPropertyPage = (Page_LanguageSettingsProviders) page; + } + + trackInitialSettings(); + + // SashForms for each mode + createConfigureSashForm(); + + // Status line + fStatusLine = new StatusMessageLine(usercomp, SWT.LEFT, 2); + + // "I want to try new scanner discovery" temporary checkbox + enableProvidersCheckBox = setupCheck(usercomp, Messages.CDTMainWizardPage_TrySD90, 2, GridData.FILL_HORIZONTAL); + enableProvidersCheckBox.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + boolean enabled = enableProvidersCheckBox.getSelection(); + if (masterPropertyPage!=null) + masterPropertyPage.setLanguageSettingsProvidersEnabled(enabled); + enableControls(enabled); + updateStatusLine(); + } + }); + + if (masterPropertyPage!=null) + enableProvidersCheckBox.setSelection(masterPropertyPage.isLanguageSettingsProvidersEnabled()); + else + enableProvidersCheckBox.setSelection(LanguageSettingsManager.isLanguageSettingsProvidersEnabled(page.getProject())); + // display but disable the checkbox for file/folder resource + enableProvidersCheckBox.setEnabled(page.isForProject() /*|| page.isForPrefs()*/); + enableControls(enableProvidersCheckBox.getSelection()); + + if (page.isForPrefs()) { + initButtons(BUTTON_LABELS_PREF); + } else { + initButtons(BUTTON_LABELS_PROJECT); + } + updateData(getResDesc()); + } + + private void createConfigureSashForm() { + // SashForm for Configure + sashFormConfigure = new SashForm(usercomp, SWT.VERTICAL); + GridLayout layout = new GridLayout(); + sashFormConfigure.setLayout(layout); + + // Providers table + Composite compositeSashForm = new Composite(sashFormConfigure, SWT.BORDER | SWT.SINGLE); + compositeSashForm.setLayout(new GridLayout()); + + // items checkboxes only for project properties page + tableProviders = new Table(compositeSashForm, page.isForPrefs() ? SWT.NONE : SWT.CHECK); + tableProviders.setLayoutData(new GridData(GridData.FILL_BOTH)); + tableProviders.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + displaySelectedOptionPage(); + updateButtons(); + } + }); + tableProvidersViewer = new CheckboxTableViewer(tableProviders); + tableProvidersViewer.setContentProvider(new ArrayContentProvider()); + tableProvidersViewer.setLabelProvider(new ProvidersTableLabelProvider()); + + tableProvidersViewer.addCheckStateListener(new ICheckStateListener() { + public void checkStateChanged(CheckStateChangedEvent e) { + saveCheckedProviders(e.getElement()); + tableProvidersViewer.update(e.getElement(), null); + }}); + + createOptionsControl(); + + sashFormConfigure.setWeights(DEFAULT_CONFIGURE_SASH_WEIGHTS); + enableSashForm(sashFormConfigure, true); + } + + private Link createLinkToPreferences(final Composite parent) { + Link link = new Link(parent, SWT.NONE); +// // FIXME +// link.setText(DialogsMessages.RegexErrorParserOptionPage_LinkToPreferencesMessage + " Select Discovery Tab."); + + link.addListener(SWT.Selection, new Listener() { + public void handleEvent(Event event) { + // Use event.text to tell which link was used + PreferencesUtil.createPreferenceDialogOn(parent.getShell(), WORKSPACE_PREFERENCE_PAGE, null, null).open(); + } + }); + + return link; + } + + // Called from globalProviderCheckBox listener + private void toggleGlobalProvider(ILanguageSettingsProvider oldProvider, boolean toGlobal) { + ILanguageSettingsProvider newProvider = null; + + String id = oldProvider.getId(); + if (toGlobal) { + newProvider = LanguageSettingsManager.getWorkspaceProvider(id); + } else { + // Local provider instance chosen + try { + ILanguageSettingsProvider rawProvider = LanguageSettingsManager.getRawProvider(oldProvider); + if (rawProvider instanceof ILanguageSettingsEditableProvider) { + newProvider = ((ILanguageSettingsEditableProvider) rawProvider).cloneShallow(); + } + } catch (CloneNotSupportedException e) { + CUIPlugin.log("Error cloning provider " + oldProvider.getId(), e); + } + } + if (newProvider!=null) { + replaceSelectedProvider(newProvider); + + ICConfigurationDescription cfgDescription = getConfigurationDescription(); + initializeOptionsPage(newProvider, cfgDescription); + displaySelectedOptionPage(); + } + } + + private void replaceSelectedProvider(ILanguageSettingsProvider newProvider) { + int pos = tableProviders.getSelectionIndex(); + presentedProviders.set(pos, newProvider); + tableProvidersViewer.setInput(presentedProviders); + tableProviders.setSelection(pos); + + ICConfigurationDescription cfgDescription = null; + if (!page.isForPrefs()) { + cfgDescription = getConfigurationDescription(); + + List cfgProviders = new ArrayList(cfgDescription.getLanguageSettingProviders()); + pos = getProviderIndex(newProvider.getId(), cfgProviders); + cfgProviders.set(pos, newProvider); + cfgDescription.setLanguageSettingProviders(cfgProviders); + tableProvidersViewer.setCheckedElements(cfgProviders.toArray(new ILanguageSettingsProvider[0])); + } + refreshItem(newProvider); + } + + public void refreshItem(ILanguageSettingsProvider provider) { + tableProvidersViewer.refresh(provider); + updateButtons(); + } + + private void createOptionsControl() { + groupOptionsPage = new Group(sashFormConfigure, SWT.SHADOW_ETCHED_IN); + groupOptionsPage.setText("Language Settings Provider Options"); + groupOptionsPage.setLayout(new GridLayout(2, false)); + + if (!page.isForPrefs()) { + if (globalProviderCheckBox==null) { + globalProviderCheckBox = new Button(groupOptionsPage, SWT.CHECK); + globalProviderCheckBox.setText("Use global provider sharing settings among projects"); + globalProviderCheckBox.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + boolean isGlobal = globalProviderCheckBox.getSelection(); + ILanguageSettingsProvider provider = getSelectedProvider(); + if (isGlobal != LanguageSettingsManager.isWorkspaceProvider(provider)) { + toggleGlobalProvider(provider, isGlobal); + } + } + + @Override + public void widgetDefaultSelected(SelectionEvent e) { + widgetSelected(e); + } + + }); + + linkWorkspacePreferences = createLinkToPreferences(groupOptionsPage); + } + } + + compositeOptionsPage = new Composite(groupOptionsPage, SWT.NONE); + compositeOptionsPage.setLayout(new TabFolderLayout()); + } + + private void enableSashForm(SashForm sashForm, boolean enable) { + sashForm.setVisible(enable); + // Some of woodoo to fill properties page vertically and still keep right border visible in preferences + GridData gd = new GridData(enable || page.isForPrefs() ? GridData.FILL_BOTH : SWT.NONE); + gd.horizontalSpan = 2; + gd.heightHint = enable ? SWT.DEFAULT : 0; + sashForm.setLayoutData(gd); + } + + private void enableControls(boolean enable) { + sashFormConfigure.setEnabled(enable); + tableProviders.setEnabled(enable); + compositeOptionsPage.setEnabled(enable); + + buttoncomp.setEnabled(enable); + + if (enable) { + displaySelectedOptionPage(); + } else { + if (currentOptionsPage != null) { + currentOptionsPage.setVisible(false); + } + disableButtons(); + } + } + + /** + * Populate provider tables and their option pages which are used in Configure mode + */ + private void updateProvidersTable() { + ILanguageSettingsProvider selectedProvider = getSelectedProvider(); + String selectedId = selectedProvider!=null ? selectedProvider.getId() : null; + + // update viewer if the list of providers changed + tableProvidersViewer.setInput(presentedProviders); + + ICConfigurationDescription cfgDescription = getConfigurationDescription(); + if (cfgDescription!=null) { + List cfgProviders = cfgDescription.getLanguageSettingProviders(); + tableProvidersViewer.setCheckedElements(cfgProviders.toArray(new ILanguageSettingsProvider[0])); + } + + if (selectedId!=null) { + for (int i=0; i idsList = new ArrayList(); + + List providers; + ICConfigurationDescription cfgDescription = getConfigurationDescription(); + if (cfgDescription!=null) { + providers = new ArrayList(cfgDescription.getLanguageSettingProviders()); + for (ILanguageSettingsProvider provider : providers) { + idsList.add(provider.getId()); + } + } else { + providers = new ArrayList(); + } + + List workspaceProviders = LanguageSettingsManager.getWorkspaceProviders(); + + // ensure sorting by name all unchecked providers + Set allAvailableProvidersSet = new TreeSet(new Comparator() { + public int compare(ILanguageSettingsProvider prov1, ILanguageSettingsProvider prov2) { + Boolean isTest1 = prov1.getId().matches(TEST_PLUGIN_ID_PATTERN); + Boolean isTest2 = prov2.getId().matches(TEST_PLUGIN_ID_PATTERN); + int result = isTest1.compareTo(isTest2); + if (result==0) + result = prov1.getName().compareTo(prov2.getName()); + return result; + } + }); + allAvailableProvidersSet.addAll(workspaceProviders); + + for (ILanguageSettingsProvider provider : allAvailableProvidersSet) { + String id = provider.getId(); + if (!idsList.contains(id)) { + providers.add(provider); + idsList.add(id); + } + } + + // renders better when using temporary + presentedProviders = providers; + tableProvidersViewer.setInput(presentedProviders); + } + + private ICOptionPage createOptionsPage(ILanguageSettingsProvider provider, ICConfigurationDescription cfgDescription) { + ICOptionPage optionsPage = null; + if (provider!=null) { + ILanguageSettingsProvider rawProvider = LanguageSettingsManager.getRawProvider(provider); + if (rawProvider!=null) { + optionsPage = LanguageSettingsProviderAssociation.createOptionsPage(rawProvider); + } + + if (optionsPage instanceof AbstractLanguageSettingProviderOptionPage) { + ((AbstractLanguageSettingProviderOptionPage)optionsPage).init(this, provider.getId()); + } + } + + return optionsPage; + } + + private void initializeOptionsPage(ILanguageSettingsProvider provider, ICConfigurationDescription cfgDescription) { + ICOptionPage optionsPage = createOptionsPage(provider, cfgDescription); + + if (optionsPage!=null) { + ILanguageSettingsProvider rawProvider = LanguageSettingsManager.getRawProvider(provider); + boolean isEditableForProject = page.isForProject() && provider instanceof ILanguageSettingsEditableProvider; + boolean isEditableForPrefs = page.isForPrefs() && rawProvider instanceof ILanguageSettingsEditableProvider; + boolean isEditable = isEditableForProject || isEditableForPrefs; + compositeOptionsPage.setEnabled(isEditable); + + String id = (provider!=null) ? provider.getId() : null; + optionsPageMap.put(id, optionsPage); + optionsPage.setContainer(page); + optionsPage.createControl(compositeOptionsPage); + optionsPage.setVisible(false); + compositeOptionsPage.layout(true); + } + } + + private void displaySelectedOptionPage() { + if (currentOptionsPage != null) { + currentOptionsPage.setVisible(false); + } + + ILanguageSettingsProvider provider = getSelectedProvider(); + String id = (provider!=null) ? provider.getId() : null; + + boolean isGlobal = LanguageSettingsManager.isWorkspaceProvider(provider); + ILanguageSettingsProvider rawProvider = LanguageSettingsManager.getRawProvider(provider); + + currentOptionsPage = optionsPageMap.get(id); + + boolean isChecked = tableProvidersViewer.getChecked(provider); + if (!page.isForPrefs()) { + boolean isRawProviderEditable = rawProvider instanceof ILanguageSettingsEditableProvider; + globalProviderCheckBox.setSelection(isGlobal); + globalProviderCheckBox.setEnabled(isChecked && isRawProviderEditable); + globalProviderCheckBox.setVisible(provider!=null); + + boolean needPreferencesLink=isGlobal && currentOptionsPage!=null; + // TODO: message + linkWorkspacePreferences.setText(needPreferencesLink ? DialogsMessages.RegexErrorParserOptionPage_LinkToPreferencesMessage + " Select Discovery Tab." : ""); + linkWorkspacePreferences.pack(); + } + + if (currentOptionsPage != null) { + boolean isEditableForProject = page.isForProject() && provider instanceof ILanguageSettingsEditableProvider; + boolean isEditableForPrefs = page.isForPrefs() && rawProvider instanceof ILanguageSettingsEditableProvider; + boolean isEditable = isEditableForProject || isEditableForPrefs; + currentOptionsPage.getControl().setEnabled(isEditable); + currentOptionsPage.setVisible(true); + + compositeOptionsPage.setEnabled(isEditable); +// compositeOptionsPage.layout(true); + } + } + + + private void saveCheckedProviders(Object selectedElement) { + if (page.isForProject()) { + Object[] checked = tableProvidersViewer.getCheckedElements(); + List providers = new ArrayList(checked.length); + for (Object element : checked) { + ILanguageSettingsProvider provider = (ILanguageSettingsProvider)element; + providers.add(provider); + } + ICConfigurationDescription cfgDescription = getConfigurationDescription(); + cfgDescription.setLanguageSettingProviders(providers); + + if (selectedElement!=null) { + tableProvidersViewer.update(selectedElement, null); + if (selectedElement instanceof ILanguageSettingsProvider) { + ILanguageSettingsProvider selectedProvider = (ILanguageSettingsProvider) selectedElement; + initializeOptionsPage(selectedProvider, cfgDescription); + displaySelectedOptionPage(); + } + } + } + } + + private void disableButtons() { +// buttonSetEnabled(BUTTON_RENAME, false); +// buttonSetEnabled(BUTTON_RUN, false); + buttonSetEnabled(BUTTON_CLEAR, false); + buttonSetEnabled(BUTTON_RESET, false); + buttonSetEnabled(BUTTON_MOVE_UP, false); + buttonSetEnabled(BUTTON_MOVE_DOWN, false); +// buttonSetEnabled(BUTTON_CONFIGURE, false); + } + + /** + * Updates state for all buttons. Called when table selection changes. + */ + @Override + protected void updateButtons() { + ILanguageSettingsProvider provider = getSelectedProvider(); + boolean isProviderSelected =provider!=null; + boolean canForWorkspace = isProviderSelected && page.isForPrefs(); + boolean canForProject = isProviderSelected && page.isForProject() && !LanguageSettingsManager.isWorkspaceProvider(provider); + + int pos = tableProviders.getSelectionIndex(); + int count = tableProviders.getItemCount(); + int last = count - 1; + boolean isRangeOk = pos >= 0 && pos <= last; + + ILanguageSettingsProvider rawProvider = LanguageSettingsManager.getRawProvider(provider); + boolean canClear = false; + if (rawProvider instanceof ILanguageSettingsEditableProvider) { + if (!((ILanguageSettingsEditableProvider) rawProvider).isEmpty()) { + canClear = canForWorkspace || canForProject; + } + } + + boolean canReset = false; + if (rawProvider!=null && (canForWorkspace || canForProject)) { + canReset = ! LanguageSettingsManager_TBD.isEqualExtensionProvider(rawProvider); + } + + boolean canMoveUp = page.isForProject() && isProviderSelected && isRangeOk && pos!=0; + boolean canMoveDown = page.isForProject() && isProviderSelected && isRangeOk && pos!=last; + +// buttonSetEnabled(BUTTON_RENAME, false); +// buttonSetEnabled(BUTTON_RUN, false); + buttonSetEnabled(BUTTON_CLEAR, canClear); + buttonSetEnabled(BUTTON_RESET, canReset); + buttonSetEnabled(BUTTON_MOVE_UP, canMoveUp); + buttonSetEnabled(BUTTON_MOVE_DOWN, canMoveDown); + } + + /** + * Displays warning message - if any - for selected language settings entry. + */ + private void updateStatusLine() { +// IStatus status=null; +// fStatusLine.setErrorStatus(status); + } + + /** + * Handle buttons + */ + @Override + public void buttonPressed(int buttonIndex) { + ILanguageSettingsProvider selectedProvider = getSelectedProvider(); + + switch (buttonIndex) { +// case BUTTON_RENAME: +// performRename(selectedProvider); +// break; +// case BUTTON_RUN: +// performRun(selectedProvider); +// break; + case BUTTON_CLEAR: + performClear(selectedProvider); + break; + case BUTTON_RESET: + performReset(selectedProvider); + break; + case BUTTON_MOVE_UP: + performMoveUp(selectedProvider); + break; + case BUTTON_MOVE_DOWN: + performMoveDown(selectedProvider); + break; + default: + } + } + + private void performClear(ILanguageSettingsProvider selectedProvider) { + if (isWorkingCopy(selectedProvider)) { + if (selectedProvider instanceof ILanguageSettingsEditableProvider) { + ILanguageSettingsEditableProvider editableProvider = (ILanguageSettingsEditableProvider) selectedProvider; + editableProvider.clear(); + tableProvidersViewer.update(selectedProvider, null); + } + } else { + ILanguageSettingsProvider rawProvider = LanguageSettingsManager.getRawProvider(selectedProvider); + if (rawProvider instanceof ILanguageSettingsEditableProvider) { + ILanguageSettingsEditableProvider editableProvider = (ILanguageSettingsEditableProvider) rawProvider; + + try { + ILanguageSettingsEditableProvider newProvider = editableProvider.cloneShallow(); + replaceSelectedProvider(newProvider); + + ICConfigurationDescription cfgDescription = getConfigurationDescription(); + initializeOptionsPage(newProvider, cfgDescription); + displaySelectedOptionPage(); + + } catch (CloneNotSupportedException e) { + CUIPlugin.log("Error cloning provider " + editableProvider.getId(), e); + return; + } + } + + } + updateButtons(); + } + + private void performReset(ILanguageSettingsProvider selectedProvider) { + ILanguageSettingsProvider newProvider = LanguageSettingsManager.getExtensionProviderCopy(selectedProvider.getId()); + replaceSelectedProvider(newProvider); + + ICConfigurationDescription cfgDescription = getConfigurationDescription(); + initializeOptionsPage(newProvider, cfgDescription); + displaySelectedOptionPage(); + updateButtons(); + } + + private boolean isWorkingCopy(ILanguageSettingsProvider provider) { + boolean isWorkingCopy = false; + if (page.isForPrefs()) { + isWorkingCopy = ! LanguageSettingsManager.isWorkspaceProvider(provider); + } else { + if (!LanguageSettingsManager.isWorkspaceProvider(provider)) { + ICConfigurationDescription cfgDescription = getConfigurationDescription(); + List initialProviders = initialProvidersByCfg.get(cfgDescription.getId()); + isWorkingCopy = ! initialProviders.contains(provider); + } + + } + return isWorkingCopy; + } + + private void performMoveUp(ILanguageSettingsProvider selectedProvider) { + int pos = presentedProviders.indexOf(selectedProvider); + if (pos > 0) { + moveProvider(pos, pos-1); + } + } + + private void performMoveDown(ILanguageSettingsProvider selectedProvider) { + int pos = presentedProviders.indexOf(selectedProvider); + int last = presentedProviders.size() - 1; + if (pos >= 0 && pos < last) { + moveProvider(pos, pos+1); + } + } + + private void moveProvider(int oldPos, int newPos) { + Collections.swap(presentedProviders, oldPos, newPos); + + updateProvidersTable(); + tableProviders.setSelection(newPos); + + saveCheckedProviders(null); + updateButtons(); + } + + private ICLanguageSetting[] getLangSettings(ICResourceDescription rcDes) { + switch (rcDes.getType()) { + case ICSettingBase.SETTING_PROJECT: + case ICSettingBase.SETTING_CONFIGURATION: + case ICSettingBase.SETTING_FOLDER: + ICFolderDescription foDes = (ICFolderDescription) rcDes; + return foDes.getLanguageSettings(); + case ICSettingBase.SETTING_FILE: + ICFileDescription fiDes = (ICFileDescription) rcDes; + ICLanguageSetting langSetting = fiDes.getLanguageSetting(); + return (langSetting != null) ? new ICLanguageSetting[] { langSetting } : null; + } + return null; + } + + /** + * Called when configuration changed + */ + @Override + public void updateData(ICResourceDescription rcDes) { + if (!canBeVisible()) + return; + + if (rcDes!=null) { + if (page.isMultiCfg()) { + setAllVisible(false, null); + return; + } else { + setAllVisible(true, null); + } + + if (masterPropertyPage!=null) { + boolean enabled = masterPropertyPage.isLanguageSettingsProvidersEnabled(); + enableProvidersCheckBox.setSelection(enabled); + enableControls(enabled); + } + } + + // for Preference page initialize providers list just once as no configuration here to change + // and re-initializing could ruins modified providers in case of switching tabs or pages + if (!page.isForPrefs() || presentedProviders==null) { + initializeProviders(); + } + updateProvidersTable(); + updateButtons(); + } + + @Override + protected void performDefaults() { + if (enableProvidersCheckBox==null || enableProvidersCheckBox.getSelection()==false) + return; + + if (page.isForPrefs() || page.isForProject()) { + if (MessageDialog.openQuestion(usercomp.getShell(), + Messages.LanguageSettingsProviderTab_TitleResetProviders, + Messages.LanguageSettingsProviderTab_AreYouSureToResetProviders)) { + + if (page.isForProject()) { + ICConfigurationDescription cfgDescription = getConfigurationDescription(); + List cfgProviders = new ArrayList(cfgDescription.getLanguageSettingProviders()); + boolean atLeastOneChanged = false; + for (int i=0;i providers = new ArrayList(presentedProviders); + for (int i=0;i destProviders = new ArrayList(); + + List srcProviders = srcCfgDescription.getLanguageSettingProviders(); + for (ILanguageSettingsProvider pro : srcProviders) { + // TODO: clone + destProviders.add(pro); + } + + destCfgDescription.setLanguageSettingProviders(destProviders); + } + + if (!page.isForPrefs()) { + ICConfigurationDescription sd = srcRcDescription.getConfiguration(); + ICConfigurationDescription dd = destRcDescription.getConfiguration(); + List newProviders = sd.getLanguageSettingProviders(); + dd.setLanguageSettingProviders(newProviders); + } + + performOK(); + } + + @Override + protected void performOK() { + if (!page.isForPrefs()) { + // FIXME: for now only handles current configuration + ICResourceDescription rcDesc = getResDesc(); + IResource rc = getResource(); + ICConfigurationDescription cfgDescription = rcDesc.getConfiguration(); + + List destProviders = new ArrayList(); + List providers = cfgDescription.getLanguageSettingProviders(); + for (ILanguageSettingsProvider pro : providers) { + // TODO: clone + destProviders.add(pro); + } + cfgDescription.setLanguageSettingProviders(destProviders); + } + + // Build Settings page + if (page.isForPrefs()) { + try { + LanguageSettingsManager.setWorkspaceProviders(presentedProviders); + } catch (CoreException e) { + CUIPlugin.log("Error setting user defined providers", e); + } + initializeProviders(); + } + + if (page.isForProject() && enableProvidersCheckBox!=null) { + boolean enabled = enableProvidersCheckBox.getSelection(); + if (masterPropertyPage!=null) + enabled = masterPropertyPage.isLanguageSettingsProvidersEnabled(); + LanguageSettingsManager.setLanguageSettingsProvidersEnabled(page.getProject(), enabled); + enableProvidersCheckBox.setSelection(enabled); + } + + Collection optionPages = optionsPageMap.values(); + for (ICOptionPage op : optionPages) { + try { + op.performApply(null); + } catch (CoreException e) { + CUIPlugin.log("Error applying options page", e); + } + } + + try { + LanguageSettingsManager_TBD.serializeWorkspaceProviders(); + } catch (CoreException e) { + CUIPlugin.log("Internal Error", e); + throw new UnsupportedOperationException("Internal Error"); + } + + trackInitialSettings(); + updateData(getResDesc()); + } + + @Override + public boolean canBeVisible() { + if (CDTPrefUtil.getBool(CDTPrefUtil.KEY_NO_SHOW_PROVIDERS)) + return false; + if (page.isForPrefs()) + return true; + + if (!page.isForProject()) + return false; + + ICLanguageSetting [] langSettings = getLangSettings(getResDesc()); + if (langSettings == null) + return false; + + for (ICLanguageSetting langSetting : langSettings) { + String langId = langSetting.getLanguageId(); + if (langId!=null && langId.length()>0) { + LanguageManager langManager = LanguageManager.getInstance(); + ILanguageDescriptor langDes = langManager.getLanguageDescriptor(langId); + if (langDes != null) + return true; + } + } + + return false; + } + + @Override + protected boolean isIndexerAffected() { + List newProvidersList = null; + ICConfigurationDescription cfgDescription = getConfigurationDescription(); + if (cfgDescription!=null) { + newProvidersList = cfgDescription.getLanguageSettingProviders(); + } + boolean newEnablement = LanguageSettingsManager.isLanguageSettingsProvidersEnabled(page.getProject()); + + // TODO + boolean isEqualList = false; +// boolean isEqualList = (newProvidersList==initialProvidersMap) || (newProvidersList!=null && newProvidersList.equals(initialProvidersMap)); + return newEnablement!=initialEnablement || (newEnablement==true && !isEqualList); + } + + private ILanguageSettingsProvider findRawProvider(String id, List providers) { + for (ILanguageSettingsProvider provider : providers) { + if (provider.getId().equals(id)) { + provider = LanguageSettingsManager.getRawProvider(provider); + return provider; + } + } + return null; + } + + private ILanguageSettingsProvider findProvider(String id, List providers) { + for (ILanguageSettingsProvider provider : providers) { + if (provider.getId().equals(id)) { + return provider; + } + } + return null; + } + + public ILanguageSettingsProvider getProvider(String id) { + return findProvider(id, presentedProviders); + } + + private int getProviderIndex(String id, List providers) { + int pos = 0; + for (ILanguageSettingsProvider p : providers) { + if (p.getId().equals(id)) + return pos; + pos++; + } + return -1; + } + +// private void informOptionPages(boolean apply) { +// Collection pages = optionsPageMap.values(); +// for (ICOptionPage dynamicPage : pages) { +// if (dynamicPage!=null && dynamicPage.isValid() && dynamicPage.getControl() != null) { +// try { +// if (apply) +// dynamicPage.performApply(new NullProgressMonitor()); +// else +// dynamicPage.performDefaults(); +// } catch (CoreException e) { +// CUIPlugin.log("ErrorParsTab.error.OnApplyingSettings", e); +// } +// } +// } +//} + +} diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/language/settings/providers/LanguageSettingsProvidersLabelProvider.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/language/settings/providers/LanguageSettingsProvidersLabelProvider.java new file mode 100644 index 00000000000..0a810a02498 --- /dev/null +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/language/settings/providers/LanguageSettingsProvidersLabelProvider.java @@ -0,0 +1,118 @@ +/******************************************************************************* + * Copyright (c) 2010, 2011 Andrew Gvozdev 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: + * Andrew Gvozdev - Initial API and implementation + *******************************************************************************/ + +package org.eclipse.cdt.internal.ui.language.settings.providers; + +import java.net.URL; + +import org.eclipse.jface.viewers.IDecoration; +import org.eclipse.jface.viewers.LabelProvider; +import org.eclipse.swt.graphics.Image; + +import org.eclipse.cdt.core.language.settings.providers.ILanguageSettingsProvider; +import org.eclipse.cdt.core.language.settings.providers.LanguageSettingsManager; +import org.eclipse.cdt.core.language.settings.providers.LanguageSettingsSerializable; +import org.eclipse.cdt.ui.CDTSharedImages; + + +/** + * Label provider for language settings providers. + * + */ +class LanguageSettingsProvidersLabelProvider extends LabelProvider { + private static final String TEST_PLUGIN_ID_PATTERN = "org.eclipse.cdt.*.tests.*"; //$NON-NLS-1$ + private static final String OOPS = "OOPS"; //$NON-NLS-1$ + + /** + * Returns base image key (for image without overlay). + */ + protected String getBaseKey(ILanguageSettingsProvider provider) { + String imageKey = null; + // try id-association + String id = provider.getId(); + URL url = LanguageSettingsProviderAssociation.getImageUrl(id); + // try class-association + if (url==null) { + ILanguageSettingsProvider rawProvider = LanguageSettingsManager.getRawProvider(provider); + if (rawProvider!=null) { + url = LanguageSettingsProviderAssociation.getImage(rawProvider.getClass()); + } + } + if (url!=null) { + imageKey = url.toString(); + } + + if (imageKey==null) { + if (id.matches(TEST_PLUGIN_ID_PATTERN)) { + imageKey = CDTSharedImages.IMG_OBJS_CDT_TESTING; + } else { + imageKey = CDTSharedImages.IMG_OBJS_EXTENSION; + } + } + return imageKey; + } + + /** + * Returns keys for image overlays. Returning {@code null} is not allowed. + */ + protected String[] getOverlayKeys(ILanguageSettingsProvider provider) { + String[] overlayKeys = new String[5]; + { // TODO temporary for debugging +// final String MBS_LANGUAGE_SETTINGS_PROVIDER = "org.eclipse.cdt.managedbuilder.core.LanguageSettingsProvider"; +// boolean isSpecial = provider.getId().equals(MBS_LANGUAGE_SETTINGS_PROVIDER); + + ILanguageSettingsProvider rawProvider = LanguageSettingsManager.getRawProvider(provider); + if (rawProvider instanceof LanguageSettingsSerializable) { + if (((LanguageSettingsSerializable)rawProvider).isEmpty()) { + overlayKeys[IDecoration.BOTTOM_RIGHT] = CDTSharedImages.IMG_OVR_EMPTY; + } + } + + if (LanguageSettingsManager.isWorkspaceProvider(provider) /*&& !isSpecial*/) { + overlayKeys[IDecoration.TOP_LEFT] = CDTSharedImages.IMG_OVR_GLOBAL; +// overlayKeys[IDecoration.TOP_LEFT] = CDTSharedImages.IMG_OVR_REFERENCE; +// overlayKeys[IDecoration.TOP_RIGHT] = CDTSharedImages.IMG_OVR_PARENT; +// overlayKeys[IDecoration.BOTTOM_RIGHT] = CDTSharedImages.IMG_OVR_LINK; + } else { +// overlayKeys[IDecoration.TOP_LEFT] = CDTSharedImages.IMG_OVR_CONFIGURATION; +// overlayKeys[IDecoration.TOP_LEFT] = CDTSharedImages.IMG_OVR_INDEXED; +// overlayKeys[IDecoration.TOP_LEFT] = CDTSharedImages.IMG_OVR_CONTEXT; + +// overlayKeys[IDecoration.TOP_LEFT] = CDTSharedImages.IMG_OVR_PROJECT; + } + + } + return overlayKeys; + } + + @Override + public Image getImage(Object element) { + if (element instanceof ILanguageSettingsProvider) { + ILanguageSettingsProvider provider = (ILanguageSettingsProvider)element; + String imageKey = getBaseKey(provider); + String[] overlayKeys = getOverlayKeys(provider); + return CDTSharedImages.getImageOverlaid(imageKey, overlayKeys); + } + return null; + } + + @Override + public String getText(Object element) { + if (element instanceof ILanguageSettingsProvider) { + String name = ((ILanguageSettingsProvider) element).getName(); + if (name!=null) + return name; + String id = ((ILanguageSettingsProvider) element).getId(); + return "[ Not accessible id="+id+" ]"; + } + return OOPS; + } +} \ No newline at end of file diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/language/settings/providers/Page_LanguageSettingsProviders.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/language/settings/providers/Page_LanguageSettingsProviders.java new file mode 100644 index 00000000000..ef6d4c3f495 --- /dev/null +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/language/settings/providers/Page_LanguageSettingsProviders.java @@ -0,0 +1,41 @@ +/******************************************************************************* + * Copyright (c) 2007, 2010 Intel 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: + * Intel Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.internal.ui.language.settings.providers; + +import org.eclipse.cdt.core.language.settings.providers.LanguageSettingsManager; +import org.eclipse.cdt.ui.newui.AbstractPage; +import org.eclipse.cdt.ui.newui.ICPropertyTab; + + +/** + * @noextend This class is not intended to be subclassed by clients. + * @noinstantiate This class is not intended to be instantiated by clients. + */ +public class Page_LanguageSettingsProviders extends AbstractPage { + private Boolean isLanguageSettingsProvidersEnabled = null; + + @Override + protected boolean isSingle() { + return false; + } + + public boolean isLanguageSettingsProvidersEnabled() { + if (isLanguageSettingsProvidersEnabled==null) { + isLanguageSettingsProvidersEnabled = LanguageSettingsManager.isLanguageSettingsProvidersEnabled(getProject()); + } + return isLanguageSettingsProvidersEnabled; + } + + public void setLanguageSettingsProvidersEnabled(boolean enable) { + isLanguageSettingsProvidersEnabled = enable; + forEach(ICPropertyTab.UPDATE,getResDesc()); + } +} diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/language/settings/providers/UserLanguageSettingsProvider.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/language/settings/providers/UserLanguageSettingsProvider.java new file mode 100644 index 00000000000..2dee6cb8000 --- /dev/null +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/language/settings/providers/UserLanguageSettingsProvider.java @@ -0,0 +1,47 @@ +/******************************************************************************* + * Copyright (c) 2009, 2009 Andrew Gvozdev (Quoin Inc.) 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: + * Andrew Gvozdev (Quoin Inc.) - initial API and implementation + *******************************************************************************/ + +package org.eclipse.cdt.internal.ui.language.settings.providers; + +import org.eclipse.cdt.core.language.settings.providers.LanguageSettingsSerializable; +import org.eclipse.cdt.core.settings.model.ILanguageSettingsEditableProvider; + +/** + * Provider to support user interface for language settings. The important difference with + * {@link LanguageSettingsSerializable} is that it implements {@link ILanguageSettingsEditableProvider}. + * + */ +public class UserLanguageSettingsProvider extends LanguageSettingsSerializable implements ILanguageSettingsEditableProvider { + + @Override + public int hashCode() { + return super.hashCode()*13 + 1; + } + + @Override + public boolean equals(Object o) { + if (o instanceof UserLanguageSettingsProvider) { + return super.equals(o); + } + return false; + } + + @Override + public UserLanguageSettingsProvider cloneShallow() throws CloneNotSupportedException { + return (UserLanguageSettingsProvider)super.cloneShallow(); + } + + @Override + public UserLanguageSettingsProvider clone() throws CloneNotSupportedException { + return (UserLanguageSettingsProvider)super.clone(); + } + +} diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/newui/LanguageSettingsImages.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/newui/LanguageSettingsImages.java new file mode 100644 index 00000000000..32f06aad27a --- /dev/null +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/newui/LanguageSettingsImages.java @@ -0,0 +1,195 @@ +/******************************************************************************* + * Copyright (c) 2010 Andrew Gvozdev 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: + * Andrew Gvozdev - Initial API and implementation + *******************************************************************************/ + +package org.eclipse.cdt.internal.ui.newui; + +import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Path; +import org.eclipse.core.runtime.Status; +import org.eclipse.jface.viewers.IDecoration; +import org.eclipse.swt.graphics.Image; + +import org.eclipse.cdt.core.settings.model.ACPathEntry; +import org.eclipse.cdt.core.settings.model.CMacroEntry; +import org.eclipse.cdt.core.settings.model.ICLanguageSettingEntry; +import org.eclipse.cdt.core.settings.model.ICSettingEntry; +import org.eclipse.cdt.ui.CDTSharedImages; +import org.eclipse.cdt.ui.CUIPlugin; + +/** + * Helper class to provide unified images for {@link ICLanguageSettingEntry}. + */ +public class LanguageSettingsImages { + public static Image getImage(int kind, int flags, boolean isProjectRelative) { + String imageKey = getImageKey(kind, flags, isProjectRelative); + if (imageKey!=null) { +// String overlayKey = getErrorOverlayKey(kind, flags, isProjectRelative); +// if (overlayKey!=null) { +// return getOverlaidImage(imageKey, overlayKey, IDecoration.BOTTOM_LEFT); +// } + return CDTSharedImages.getImage(imageKey); + } + return null; + } + + /** + * Returns image for the given entry from internally managed repository including + * necessary overlays. This method is shortcut for {@link #getImage(ICLanguageSettingEntry, String)} + * when no project is available. + * + * @param entry - language settings entry to get an image for. + * @return the image for the entry with appropriate overlays. + */ + public static Image getImage(ICLanguageSettingEntry entry) { + return getImage(entry, null); + } + + /** + * Returns image for the given entry from internally managed repository including + * necessary overlays. + * + * @param entry - language settings entry to get an image for. + * @param projectName - pass project name if available. That lets to put "project" metaphor + * on the image. Pass {@code null} if no project name is available. + * @return the image for the entry with appropriate overlays. + */ + public static Image getImage(ICLanguageSettingEntry entry, String projectName) { + int kind = entry.getKind(); + boolean isWorkspacePath = (entry.getFlags() & ICSettingEntry.VALUE_WORKSPACE_PATH) != 0; + String path = entry.getName(); + boolean isProjectRelative = projectName!=null && isWorkspacePath && path.startsWith(IPath.SEPARATOR+projectName+IPath.SEPARATOR); + // FIXME + isProjectRelative = isProjectRelative || (isWorkspacePath && path.charAt(0)!=IPath.SEPARATOR); + int flags = entry.getFlags(); + String imageKey = getImageKey(kind, flags, isProjectRelative); + if (imageKey!=null) { + if ((entry.getFlags()&ICSettingEntry.UNDEFINED) == ICSettingEntry.UNDEFINED) + return CDTSharedImages.getImageOverlaid(imageKey, CDTSharedImages.IMG_OVR_INACTIVE, IDecoration.BOTTOM_LEFT); + + if (entry instanceof ACPathEntry) { + String overlayKey=null; + IStatus status = getStatus(entry); + switch (status.getSeverity()) { + case IStatus.ERROR: + overlayKey = CDTSharedImages.IMG_OVR_ERROR; + break; + case IStatus.WARNING: + overlayKey = CDTSharedImages.IMG_OVR_WARNING; + break; + case IStatus.INFO: + overlayKey = CDTSharedImages.IMG_OVR_WARNING; + break; + } + return CDTSharedImages.getImageOverlaid(imageKey, overlayKey, IDecoration.BOTTOM_LEFT); + } + return CDTSharedImages.getImage(imageKey); + } + return null; + } + + /** + * Checking if the entry points to existing or accessible location. + */ + private static boolean isLocationOk(ACPathEntry entry) { + // have to trust paths which contain variables + if (entry.getName().contains("${")) //$NON-NLS-1$ + return true; + + boolean exists = true; + boolean isWorkspacePath = (entry.getFlags() & ICSettingEntry.VALUE_WORKSPACE_PATH) != 0; + if (isWorkspacePath) { + IPath path = new Path(entry.getValue()); + IResource rc = ResourcesPlugin.getWorkspace().getRoot().findMember(path); + exists = rc!=null && rc.isAccessible(); + } else { + String pathname = entry.getName(); + java.io.File file = new java.io.File(pathname); + exists = file.exists(); + } + return exists; + } + + /** + * Defines status object for the status message line. + * + * @param entry - the entry to check status on. + * @return a status object defining severity and message. + */ + public static IStatus getStatus(ICLanguageSettingEntry entry) { + if (entry instanceof ACPathEntry) { + ACPathEntry acEntry = (ACPathEntry)entry; + IPath path = new Path(acEntry.getName()); + if (!path.isAbsolute()) { + String msg = "Using relative paths is ambiguous and not recommended. It can cause unexpected side-effects."; + return new Status(IStatus.INFO, CUIPlugin.PLUGIN_ID, msg); + } + if (!isLocationOk(acEntry)) { + String msg; + if (acEntry.isFile()) + msg = "The selected file does not exist or not accessible."; + else + msg = "The selected folder does not exist or not accessible."; + return new Status(IStatus.WARNING, CUIPlugin.PLUGIN_ID, msg); + } + + } + return Status.OK_STATUS; + } + + /** + * @return the base key for the image. + */ + private static String getImageKey(int kind, int flag, boolean isProjectRelative) { + String imageKey = null; + + boolean isWorkspacePath = (flag & ICSettingEntry.VALUE_WORKSPACE_PATH) != 0; + boolean isBuiltin = (flag & ICSettingEntry.BUILTIN) != 0; + boolean isFramework = (flag & ICSettingEntry.FRAMEWORKS_MAC) != 0; + + switch (kind) { + case ICSettingEntry.INCLUDE_PATH: + if (isWorkspacePath) + if (isProjectRelative) + imageKey = CDTSharedImages.IMG_OBJS_INCLUDES_FOLDER_PROJECT; + else + imageKey = CDTSharedImages.IMG_OBJS_INCLUDES_FOLDER_WORKSPACE; + else if (isFramework) + imageKey = CDTSharedImages.IMG_OBJS_FRAMEWORKS_FOLDER; + else if (isBuiltin) + imageKey = CDTSharedImages.IMG_OBJS_INCLUDES_FOLDER_SYSTEM; + else + imageKey = CDTSharedImages.IMG_OBJS_INCLUDES_FOLDER; + break; + case ICSettingEntry.INCLUDE_FILE: + imageKey = CDTSharedImages.IMG_OBJS_TUNIT_HEADER; + break; + case ICSettingEntry.MACRO: + imageKey = CDTSharedImages.IMG_OBJS_MACRO; + break; + case ICSettingEntry.MACRO_FILE: + imageKey = CDTSharedImages.IMG_OBJS_MACROS_FILE; + break; + case ICSettingEntry.LIBRARY_PATH: + imageKey = CDTSharedImages.IMG_OBJS_LIBRARY_FOLDER; + break; + case ICSettingEntry.LIBRARY_FILE: + imageKey = CDTSharedImages.IMG_OBJS_LIBRARY; + break; + } + if (imageKey==null) + imageKey = CDTSharedImages.IMG_OBJS_UNKNOWN_TYPE; + return imageKey; + } + +} diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/newui/Messages.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/newui/Messages.java index fe48a3b97b8..ba35da75ca9 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/newui/Messages.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/newui/Messages.java @@ -84,6 +84,7 @@ public class Messages extends NLS { public static String CDTCommonProjectWizard_creatingProject; public static String CDTMainWizardPage_0; public static String CDTMainWizardPage_1; + public static String CDTMainWizardPage_TrySD90; public static String CLocationOutputTab_0; public static String CLocationSourceTab_0; public static String CLocationTab_0; @@ -186,6 +187,16 @@ public class Messages extends NLS { public static String IncludeTab_2; public static String IncludeTab_export; public static String IncludeTab_import; + public static String LanguageSettingsProviderTab_AreYouSureToResetProviders; + public static String LanguageSettingsProviderTab_Clear; + public static String LanguageSettingsProviderTab_Configure; + public static String LanguageSettingsProviderTab_ErrorPerformingDefaults; + public static String LanguageSettingsProviderTab_ProviderOptions; +// public static String LanguageSettingsProviderTab_Run; + public static String LanguageSettingsProviderTab_SettingEntries; + public static String LanguageSettingsProviderTab_SettingEntriesTooltip; + public static String LanguageSettingsProviderTab_ShowEntries; + public static String LanguageSettingsProviderTab_TitleResetProviders; public static String LanguagesTab_0; public static String LanguagesTab_1; public static String LibraryPathTab_1; diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/newui/Messages.properties b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/newui/Messages.properties index 80f166a65c7..e26bd03bb53 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/newui/Messages.properties +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/newui/Messages.properties @@ -166,6 +166,16 @@ IncludeDialog_0=Directory: IncludeDialog_1=File: IncludeDialog_2=Add to all configurations IncludeDialog_3=Add to all languages +LanguageSettingsProviderTab_AreYouSureToResetProviders=Are you sure you want to reset all customized language settings providers? +LanguageSettingsProviderTab_Clear=Clear Entries +LanguageSettingsProviderTab_Configure=Configure +LanguageSettingsProviderTab_ErrorPerformingDefaults=Error restoring defaults for language settings providers +LanguageSettingsProviderTab_ProviderOptions=Language Settings Provider Options +#LanguageSettingsProviderTab_Run=Run +LanguageSettingsProviderTab_SettingEntries=Setting Entries +LanguageSettingsProviderTab_SettingEntriesTooltip=Setting Entries +LanguageSettingsProviderTab_ShowEntries=Show Entries +LanguageSettingsProviderTab_TitleResetProviders=Reset Language Settings Providers LanguagesTab_0=Content type LanguagesTab_1=Language LibraryPathTab_1=Add... @@ -269,6 +279,7 @@ StringVariableSelectionDialog_message=&Choose a variable (? = any character, * = StringVariableSelectionDialog_columnDescription=&Variable Description: CDTMainWizardPage_0=Project name cannot contain '\#' symbol CDTMainWizardPage_1=Project category is selected. Expand the category and select a concrete project type. +CDTMainWizardPage_TrySD90=I want to try new upcoming version of Scanner Discovery in CDT 9.0 (v.0.1.0) CProjectWizard_0=Add C Project Nature CCProjectWizard_0=Add CC Project Nature WorkingSetConfigAction_21=Building project diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/newui/StatusMessageLine.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/newui/StatusMessageLine.java new file mode 100644 index 00000000000..aacedf2cbcb --- /dev/null +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/newui/StatusMessageLine.java @@ -0,0 +1,81 @@ +/******************************************************************************* + * Copyright (c) 2010 Andrew Gvozdev 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: + * Andrew Gvozdev - Initial API and implementation + *******************************************************************************/ + +package org.eclipse.cdt.internal.ui.newui; + +import org.eclipse.core.runtime.IStatus; +import org.eclipse.jface.dialogs.Dialog; +import org.eclipse.jface.resource.JFaceResources; +import org.eclipse.swt.SWT; +import org.eclipse.swt.custom.CLabel; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.widgets.Composite; + +/** + * A message line displaying a status. + * See also org.eclipse.jface.dialogs.StatusDialog.MessageLine. + */ +public class StatusMessageLine { + private CLabel fLabel; + + /** + * Constructor. + * + * @param parent - parent element. + * @param style - the style of the control. Refer to {@link CLabel#CLabel(Composite, int)}. + * @param span - how many columns it should span. + */ + public StatusMessageLine(Composite parent, int style, int span) { + fLabel = new CLabel(parent, style); + if (span!=1) { + GridData gd = new GridData(SWT.FILL, SWT.NONE, true, false); + gd.horizontalSpan = span; + fLabel.setLayoutData(gd); + } + } + + /** + * Find an image associated with the status. + */ + private Image findImage(IStatus status) { + if (status.isOK()) { + return null; + } else if (status.matches(IStatus.ERROR)) { + return JFaceResources.getImage(Dialog.DLG_IMG_MESSAGE_ERROR); + } else if (status.matches(IStatus.WARNING)) { + return JFaceResources.getImage(Dialog.DLG_IMG_MESSAGE_WARNING); + } else if (status.matches(IStatus.INFO)) { + return JFaceResources.getImage(Dialog.DLG_IMG_MESSAGE_INFO); + } + return null; + } + + /** + * Assign {@link IStatus} object to the message line. The status should provide + * severity for the icon and message to display. + * + * @param status - status object for the message line. + */ + public void setErrorStatus(IStatus status) { + if (status != null && !status.isOK()) { + String message = status.getMessage(); + if (message != null && message.length() > 0) { + fLabel.setText(message); + fLabel.setImage(findImage(status)); + fLabel.layout(); + return; + } + } + fLabel.setText(""); //$NON-NLS-1$ + fLabel.setImage(null); + } +} \ No newline at end of file diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/viewsupport/ProblemsLabelDecorator.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/viewsupport/ProblemsLabelDecorator.java index 17232c410cc..e576c176e62 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/viewsupport/ProblemsLabelDecorator.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/viewsupport/ProblemsLabelDecorator.java @@ -29,6 +29,7 @@ import org.eclipse.swt.graphics.Point; import org.eclipse.swt.graphics.Rectangle; import org.eclipse.ui.texteditor.MarkerUtilities; +import org.eclipse.cdt.core.language.settings.providers.LanguageSettingsManager_TBD; import org.eclipse.cdt.core.model.CModelException; import org.eclipse.cdt.core.model.CoreModel; import org.eclipse.cdt.core.model.ICElement; @@ -387,7 +388,8 @@ public class ProblemsLabelDecorator implements ILabelDecorator, ILightweightLabe if (cfgDescription != null) { IPath path = rc.getProjectRelativePath(); ICResourceDescription rcDescription = cfgDescription.getResourceDescription(path, true); - if (rcDescription != null) + boolean isLSCustomized = LanguageSettingsManager_TBD.isCustomizedResource(cfgDescription, rc); + if (rcDescription != null || isLSCustomized) result |= TICK_CONFIGURATION; } } diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/CDTSharedImages.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/CDTSharedImages.java index 73cbf49068b..95c5d4618d5 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/CDTSharedImages.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/CDTSharedImages.java @@ -116,6 +116,7 @@ public class CDTSharedImages { public static final String IMG_OBJS_INCLUDES_FOLDER_WORKSPACE = "icons/obj16/wsp_includefolder.gif"; //$NON-NLS-1$ public static final String IMG_OBJS_QUOTE_INCLUDES_FOLDER = "icons/obj16/hfolder_quote_obj.gif"; //$NON-NLS-1$ public static final String IMG_OBJS_INCLUDES_FOLDER_SYSTEM = "icons/obj16/fldr_sys_obj.gif"; //$NON-NLS-1$ + public static final String IMG_OBJS_FRAMEWORKS_FOLDER = "icons/obj16/frameworks.gif"; //$NON-NLS-1$ public static final String IMG_OBJS_MACROS_FILE= "icons/obj16/macros_file.gif"; //$NON-NLS-1$ public static final String IMG_OBJS_LIBRARY_FOLDER= "icons/obj16/fldr_lib_obj.gif"; // $NON-NLS-1$ //$NON-NLS-1$ public static final String IMG_OBJS_ORDER = "icons/obj16/cp_order_obj.gif"; //$NON-NLS-1$ @@ -208,6 +209,23 @@ public class CDTSharedImages { public static final String IMG_VIEW_PIN_ACTION_B = "icons/obj16/toolbar_pinned_b.gif"; //$NON-NLS-1$ public static final String IMG_VIEW_PIN_ACTION_MULTI = "icons/obj16/toolbar_pinned_multi.gif"; //$NON-NLS-1$ + // Language Settings Images + public static final String IMG_OBJS_LANG_SETTINGS_PROVIDER = "icons/obj16/ls_entries_provider.gif"; //$NON-NLS-1$ + public static final String IMG_ETOOL_PROJECT = "icons/etool16/prj_obj.gif"; //$NON-NLS-1$ + + public static final String IMG_OVR_GLOBAL = "icons/ovr16/global_ovr.gif"; //$NON-NLS-1$ + public static final String IMG_OVR_IMPORT = "icons/ovr16/import_co.gif"; //$NON-NLS-1$ + public static final String IMG_OVR_LINK = "icons/ovr16/link_ovr.gif"; //$NON-NLS-1$ + public static final String IMG_OVR_CONFIGURATION = "icons/ovr16/cfg_ovr.gif"; //$NON-NLS-1$ + public static final String IMG_OVR_PARENT = "icons/ovr16/path_inherit_co.gif"; //$NON-NLS-1$ + public static final String IMG_OVR_INDEXED = "icons/ovr16/indexedFile.gif"; //$NON-NLS-1$ + public static final String IMG_OVR_REFERENCE = "icons/ovr16/referencedby_co.gif"; //$NON-NLS-1$ + public static final String IMG_OVR_PROJECT = "icons/ovr16/project_co.gif"; //$NON-NLS-1$ + public static final String IMG_OVR_CONTEXT = "icons/ovr16/overlay-has-context.gif"; //$NON-NLS-1$ + public static final String IMG_OVR_LOCK = "icons/ovr16/lock_ovr.gif"; //$NON-NLS-1$ + public static final String IMG_OVR_EDITED = "icons/ovr16/edited_ov.gif"; //$NON-NLS-1$ + public static final String IMG_OVR_EMPTY = "icons/ovr16/empty_ovr.png"; //$NON-NLS-1$ + /** * The method finds URL of the image corresponding to the key which could be project-relative path * of the image in org.eclipse.cdt.ui plugin or a (previously registered) string representation of URL diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/newui/AbstractCPropertyTab.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/newui/AbstractCPropertyTab.java index 2ff7b9cd963..691ea16bf74 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/newui/AbstractCPropertyTab.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/newui/AbstractCPropertyTab.java @@ -94,6 +94,7 @@ public abstract class AbstractCPropertyTab implements ICPropertyTab { public static final String EDIT_STR = Messages.FileListControl_edit; public static final String MOVEUP_STR = Messages.FileListControl_moveup; public static final String MOVEDOWN_STR = Messages.FileListControl_movedown; + public static final String PROJECTBUTTON_NAME = "Project..."; public static final String WORKSPACEBUTTON_NAME = Messages.FileListControl_button_workspace; public static final String FILESYSTEMBUTTON_NAME = Messages.FileListControl_button_fs; public static final String VARIABLESBUTTON_NAME = Messages.AbstractCPropertyTab_1; @@ -450,6 +451,12 @@ public abstract class AbstractCPropertyTab implements ICPropertyTab { public static String getWorkspaceFileDialog(Shell shell, String text) { return getWorkspaceDialog(shell, text, false, null); } + public static String getProjectDirDialog(Shell shell, String text, IProject prj) { + return getWorkspaceDialog(shell, text, true, prj); + } + public static String getProjectFileDialog(Shell shell, String text, IProject prj) { + return getWorkspaceDialog(shell, text, false, prj); + } private static String getWorkspaceDialog(Shell shell, String text, boolean dir, IProject prj) { String currentPathText; diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/newui/AbstractLangsListTab.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/newui/AbstractLangsListTab.java index 7528b6f7fde..38318888296 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/newui/AbstractLangsListTab.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/newui/AbstractLangsListTab.java @@ -9,6 +9,7 @@ * Intel Corporation - initial API and implementation * IBM Corporation * Markus Schorn (Wind River Systems) + * Andrew Gvozdev (Quoin Inc.) *******************************************************************************/ package org.eclipse.cdt.ui.newui; @@ -18,6 +19,7 @@ import java.util.Comparator; import java.util.LinkedList; import java.util.List; +import org.eclipse.core.resources.IProject; import org.eclipse.jface.resource.JFaceResources; import org.eclipse.jface.viewers.IFontProvider; import org.eclipse.jface.viewers.IStructuredContentProvider; @@ -66,9 +68,10 @@ import org.eclipse.cdt.core.settings.model.ICSettingBase; import org.eclipse.cdt.core.settings.model.ICSettingEntry; import org.eclipse.cdt.core.settings.model.MultiLanguageSetting; import org.eclipse.cdt.core.settings.model.util.CDataUtil; -import org.eclipse.cdt.ui.CDTSharedImages; +import org.eclipse.cdt.internal.ui.newui.LanguageSettingsImages; import org.eclipse.cdt.internal.ui.newui.Messages; +import org.eclipse.cdt.internal.ui.newui.StatusMessageLine; public abstract class AbstractLangsListTab extends AbstractCPropertyTab { protected Table table; @@ -78,6 +81,8 @@ public abstract class AbstractLangsListTab extends AbstractCPropertyTab { protected Button showBIButton; protected boolean toAllCfgs = false; protected boolean toAllLang = false; + private StatusMessageLine fStatusLine; + /** @deprecated as of CDT 8.0. {@code linkStringListMode} is used instead. */ @Deprecated protected Label lb1, lb2; @@ -120,12 +125,6 @@ public abstract class AbstractLangsListTab extends AbstractCPropertyTab { private static final Comparator comp = CDTListComparator.getInstance(); - private final static Image IMG_FOLDER = CDTSharedImages.getImage(CDTSharedImages.IMG_OBJS_FOLDER); - private final static Image IMG_INCLUDES_FOLDER = CDTSharedImages.getImage(CDTSharedImages.IMG_OBJS_INCLUDES_FOLDER); - private final static Image IMG_BUILTIN_FOLDER = CDTSharedImages.getImage(CDTSharedImages.IMG_OBJS_INCLUDES_FOLDER_SYSTEM); - private final static Image IMG_WORKSPACE = CDTSharedImages.getImage(CDTSharedImages.IMG_OBJS_WORKSPACE); - private final static Image IMG_INCLUDES_FOLDER_WORKSPACE = CDTSharedImages.getImage(CDTSharedImages.IMG_OBJS_INCLUDES_FOLDER_WORKSPACE); - private final static Image IMG_MACRO = CDTSharedImages.getImage(CDTSharedImages.IMG_OBJS_MACRO); private static final int[] DEFAULT_SASH_WEIGHTS = new int[] { 10, 30 }; @Override @@ -182,11 +181,12 @@ public abstract class AbstractLangsListTab extends AbstractCPropertyTab { public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {} }); - tv.setLabelProvider(new RichLabelProvider()); + tv.setLabelProvider(new LanguageSettingsEntriesLabelProvider()); table.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { + updateStatusLine(); updateButtons(); } @@ -205,6 +205,8 @@ public abstract class AbstractLangsListTab extends AbstractCPropertyTab { setColumnToFit(); }}); + fStatusLine = new StatusMessageLine(usercomp, SWT.LEFT, 2); + showBIButton = setupCheck(usercomp, Messages.AbstractLangsListTab_ShowBuiltin, 1, GridData.GRAB_HORIZONTAL); gd = (GridData) showBIButton.getLayoutData(); showBIButton.addSelectionListener(new SelectionAdapter() { @@ -226,6 +228,17 @@ public abstract class AbstractLangsListTab extends AbstractCPropertyTab { updateData(getResDesc()); } + /** + * @return selected entry when only one is selected or {@code null}. + */ + private ICLanguageSettingEntry getSelectedEntry() { + int index = table.getSelectionIndex(); + if (index<0 || table.getSelectionIndices().length!=1) + return null; + + return (ICLanguageSettingEntry)(table.getItem(index).getData()); + } + /** * Used to display UI control for multiple configurations string list mode * (see Multiple Configurations Edit Preference page). @@ -236,6 +249,14 @@ public abstract class AbstractLangsListTab extends AbstractCPropertyTab { stringListModeControl.updateStringListModeControl(); } + /** + * Displays warning message - if any - for selected language settings entry. + * Multiline selection is not supported. + */ + private void updateStatusLine() { + fStatusLine.setErrorStatus(LanguageSettingsImages.getStatus(getSelectedEntry())); + } + /** * Updates state for all buttons * Called when table selection changes. @@ -342,6 +363,7 @@ public abstract class AbstractLangsListTab extends AbstractCPropertyTab { } updateStringListModeControl(); + updateStatusLine(); updateButtons(); } @@ -682,67 +704,60 @@ public abstract class AbstractLangsListTab extends AbstractCPropertyTab { } // Extended label provider - private class RichLabelProvider extends LabelProvider implements IFontProvider, ITableLabelProvider /*, IColorProvider*/{ - public RichLabelProvider(){} + private class LanguageSettingsEntriesLabelProvider extends LabelProvider implements IFontProvider, ITableLabelProvider /*, IColorProvider*/{ @Override public Image getImage(Object element) { return getColumnImage(element, 0); } + public Image getColumnImage(Object element, int columnIndex) { - if (columnIndex > 0) return null; - if (! (element instanceof ICLanguageSettingEntry)) return null; - - ICLanguageSettingEntry le = (ICLanguageSettingEntry) element; - if (le.getKind() == ICSettingEntry.MACRO) - return IMG_MACRO; - if ((le.getFlags() & ICSettingEntry.BUILTIN) != 0) - return IMG_BUILTIN_FOLDER; - - boolean isWorkspacePath = (le.getFlags() & ICSettingEntry.VALUE_WORKSPACE_PATH) != 0; - if (le.getKind() == ICSettingEntry.INCLUDE_PATH || le.getKind() == ICSettingEntry.INCLUDE_FILE) { - if (isWorkspacePath) - return IMG_INCLUDES_FOLDER_WORKSPACE; - else - return IMG_INCLUDES_FOLDER; - } else { - if (isWorkspacePath) - return IMG_WORKSPACE; - else - return IMG_FOLDER; + if (columnIndex==0 && (element instanceof ICLanguageSettingEntry)) { + ICConfigurationDescription cfg = getResDesc().getConfiguration(); + IProject project = cfg.getProjectDescription().getProject(); + return LanguageSettingsImages.getImage((ICLanguageSettingEntry) element, project.getName()); } + return null; } + @Override public String getText(Object element) { return getColumnText(element, 0); } + public String getColumnText(Object element, int columnIndex) { - if (! (element instanceof ICLanguageSettingEntry)) { - return (columnIndex == 0) ? element.toString() : EMPTY_STR; - } - ICLanguageSettingEntry le = (ICLanguageSettingEntry) element; - if (columnIndex == 0) { - String s = le.getName(); - if (exported.contains(resolve(le))) - s = s + Messages.AbstractLangsListTab_ExportIndicator; - return s; - } - if (le.getKind() == ICSettingEntry.MACRO) { + if (element instanceof ICLanguageSettingEntry) { + ICLanguageSettingEntry entry = (ICLanguageSettingEntry) element; switch (columnIndex) { - case 1: return le.getValue(); + case 0: + String name = entry.getName(); + if (exported.contains(resolve(entry))) + name = name + Messages.AbstractLangsListTab_ExportIndicator; + return name; + case 1: + if (entry.getKind() == ICSettingEntry.MACRO) { + return entry.getValue(); } + return null; + } + } else if (columnIndex == 0) { + return element.toString(); } - return EMPTY_STR; + + return null; } public Font getFont(Object element) { - if (! (element instanceof ICLanguageSettingEntry)) return null; - ICLanguageSettingEntry le = (ICLanguageSettingEntry) element; - if (le.isBuiltIn()) return null; // built in - if (le.isReadOnly()) // read only + if (element instanceof ICLanguageSettingEntry) { + ICLanguageSettingEntry entry = (ICLanguageSettingEntry) element; + if (entry.isBuiltIn()) + return null; + if (entry.isReadOnly()) return JFaceResources.getFontRegistry().getItalic(JFaceResources.DIALOG_FONT); // normal return JFaceResources.getFontRegistry().getBold(JFaceResources.DIALOG_FONT); } + return null; + } } public ICLanguageSetting[] getLangSetting(ICResourceDescription rcDes) { diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/newui/CDTPrefUtil.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/newui/CDTPrefUtil.java index 4422ba202a0..58594cf3146 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/newui/CDTPrefUtil.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/newui/CDTPrefUtil.java @@ -33,11 +33,13 @@ import org.eclipse.cdt.internal.ui.workingsets.WorkingSetConfigurationManager; public class CDTPrefUtil { // boolean keys (KEY_NO-s are to be inverted !) public static final String KEY_NOSUPP = "wizard.show.unsupported.disable"; //$NON-NLS-1$ + public static final String KEY_NEWSD = "wizard.try.new.sd.enable"; //$NON-NLS-1$ public static final String KEY_OTHERS = "wizard.group.others.enable"; //$NON-NLS-1$ public static final String KEY_NOMNG = "properties.manage.config.disable"; //$NON-NLS-1$ public static final String KEY_DTREE = "properties.data.hierarchy.enable"; //$NON-NLS-1$ public static final String KEY_NOTOOLM = "properties.toolchain.modification.disable"; //$NON-NLS-1$ public static final String KEY_EXPORT = "properties.export.page.enable"; //$NON-NLS-1$ + public static final String KEY_NO_SHOW_PROVIDERS = "properties.providers.tab.disable"; //$NON-NLS-1$ /** @since 5.2 Show the "Include Files" settings entry tab */ public static final String KEY_SHOW_INC_FILES = "properties.includefiles.page.enable"; //$NON-NLS-1$ /** @since 5.2 */ diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/wizards/CDTMainWizardPage.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/wizards/CDTMainWizardPage.java index f214a9fd72b..589b32ece43 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/wizards/CDTMainWizardPage.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/wizards/CDTMainWizardPage.java @@ -67,6 +67,7 @@ import org.eclipse.cdt.internal.ui.newui.Messages; private Tree tree; private Composite right; private Button show_sup; + private Button checkBoxTryNewSD; private Label right_label; public CWizardHandler h_selected = null; @@ -154,6 +155,20 @@ import org.eclipse.cdt.internal.ui.newui.Messages; // restore settings from preferences show_sup.setSelection(!CDTPrefUtil.getBool(CDTPrefUtil.KEY_NOSUPP)); + + checkBoxTryNewSD = new Button(c, SWT.CHECK); + checkBoxTryNewSD.setText(Messages.CDTMainWizardPage_TrySD90); + /* GridData */gd = new GridData(GridData.FILL_HORIZONTAL); + gd.horizontalSpan = 2; + checkBoxTryNewSD.setLayoutData(gd); + + // restore settings from preferences + boolean isTryNewSD = true; + boolean contains = CUIPlugin.getDefault().getPreferenceStore().contains(CDTPrefUtil.KEY_NEWSD); + if (contains) { + isTryNewSD = CDTPrefUtil.getBool(CDTPrefUtil.KEY_NEWSD); + } + checkBoxTryNewSD.setSelection(isTryNewSD); } @Override @@ -478,5 +493,9 @@ import org.eclipse.cdt.internal.ui.newui.Messages; public List filterItems(List items) { return items; } + + public boolean isTryingNewSD() { + return checkBoxTryNewSD.getSelection(); + } } diff --git a/xlc/org.eclipse.cdt.managedbuilder.xlc.core/plugin.xml b/xlc/org.eclipse.cdt.managedbuilder.xlc.core/plugin.xml index 37b503d103b..668e82b3759 100644 --- a/xlc/org.eclipse.cdt.managedbuilder.xlc.core/plugin.xml +++ b/xlc/org.eclipse.cdt.managedbuilder.xlc.core/plugin.xml @@ -74,6 +74,24 @@ class="org.eclipse.cdt.make.xlc.core.scannerconfig.XlCSpecsConsoleParser"> - + + + + + + + + + + diff --git a/xlc/org.eclipse.cdt.managedbuilder.xlc.core/src/org/eclipse/cdt/managedbuilder/xlc/core/XlcBuiltinSpecsDetector.java b/xlc/org.eclipse.cdt.managedbuilder.xlc.core/src/org/eclipse/cdt/managedbuilder/xlc/core/XlcBuiltinSpecsDetector.java new file mode 100644 index 00000000000..056ca8305dd --- /dev/null +++ b/xlc/org.eclipse.cdt.managedbuilder.xlc.core/src/org/eclipse/cdt/managedbuilder/xlc/core/XlcBuiltinSpecsDetector.java @@ -0,0 +1,97 @@ +/******************************************************************************* + * Copyright (c) 2009, 2011 Andrew Gvozdev 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: + * Andrew Gvozdev - initial API and implementation + *******************************************************************************/ + +package org.eclipse.cdt.managedbuilder.xlc.core; + +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.eclipse.cdt.core.settings.model.ICSettingEntry; +import org.eclipse.cdt.core.settings.model.ILanguageSettingsEditableProvider; +import org.eclipse.cdt.managedbuilder.internal.scannerconfig.AbstractBuiltinSpecsDetector; + + +/** + * + +> xlC -E -V -P -w ~/tmp/spec.C +export XL_CONFIG=/etc/vac.cfg:xlC +/usr/vac/exe/xlCcpp /home/me/tmp/spec.C - -qc++=/usr/vacpp/include -D_AIX -D_AIX32 -D_AIX41 -D_AIX43 -D_AIX50 -D_AIX51 -D_AIX52 -D_IBMR2 -D_POWER -E -P -w -qlanglvl=ansi -qansialias +rm /tmp/xlcW0lt4Jia +rm /tmp/xlcW1lt4Jib +rm /tmp/xlcW2lt4Jic + + */ + +/** + * Class to detect built-in compiler settings. Note that currently this class is hardwired + * to GCC toolchain {@code cdt.managedbuild.toolchain.gnu.base}. + * + */ +public class XlcBuiltinSpecsDetector extends AbstractBuiltinSpecsDetector implements ILanguageSettingsEditableProvider { + // must match the toolchain definition in org.eclipse.cdt.managedbuilder.core.buildDefinitions extension point + // FIXME - ill defined XLC toolchain +// private static final String XLC_TOOLCHAIN_ID = "cdt.managedbuild.toolchain.xlc.exe.debug"; //$NON-NLS-1$ + private static final String GCC_TOOLCHAIN_ID = "cdt.managedbuild.toolchain.gnu.base"; //$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; + + @SuppressWarnings("nls") + private static final AbstractOptionParser[] optionParsers = { + new IncludePathOptionParser("-I\\s*([\"'])(.*)\\1", "$2", ICSettingEntry.BUILTIN | ICSettingEntry.READONLY | ICSettingEntry.LOCAL), + new IncludePathOptionParser("-I\\s*([^\\s\"']*)", "$1", ICSettingEntry.BUILTIN | ICSettingEntry.READONLY), + new IncludePathOptionParser("-qc\\+\\+=\\s*([^\\s\"']*)", "$1", ICSettingEntry.BUILTIN | ICSettingEntry.READONLY), + new MacroOptionParser("-D\\s*([\"'])([^=]*)(=(.*))?\\1", "$2", "$4", ICSettingEntry.BUILTIN | ICSettingEntry.READONLY), + new MacroOptionParser("-D\\s*([^\\s=\"']*)=(\\\\([\"']))(.*?)\\2", "$1", "$3$4$3", ICSettingEntry.BUILTIN | ICSettingEntry.READONLY), + new MacroOptionParser("-D\\s*([^\\s=\"']*)=([\"'])(.*?)\\2", "$1", "$3", ICSettingEntry.BUILTIN | ICSettingEntry.READONLY), + new MacroOptionParser("-D\\s*([^\\s=\"']*)(=([^\\s\"']*))?", "$1", "$3", ICSettingEntry.BUILTIN | ICSettingEntry.READONLY), + }; + + @Override + protected String getToolchainId() { +// return XLC_TOOLCHAIN_ID; + return GCC_TOOLCHAIN_ID; + } + + @Override + protected AbstractOptionParser[] getOptionParsers() { + return optionParsers; + } + + @Override + protected List parseForOptions(String line) { + List options = new ArrayList(); + Matcher optionMatcher = OPTIONS_PATTERN.matcher(line); + while (optionMatcher.find()) { + String option = optionMatcher.group(OPTION_GROUP); + if (option!=null) { + options.add(option); + } + } + return options; + } + + + @Override + public XlcBuiltinSpecsDetector cloneShallow() throws CloneNotSupportedException { + return (XlcBuiltinSpecsDetector) super.cloneShallow(); + } + + @Override + public XlcBuiltinSpecsDetector clone() throws CloneNotSupportedException { + return (XlcBuiltinSpecsDetector) super.clone(); + } + + +}