1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-04-29 19:45:01 +02:00

ILanguageSettingsChangeEvent notifications

This commit is contained in:
Andrew Gvozdev 2011-10-30 00:46:14 -04:00
parent babba4a0a7
commit 5fffd285f0
20 changed files with 1826 additions and 669 deletions

View file

@ -18,9 +18,14 @@ import junit.framework.TestCase;
import junit.framework.TestSuite; import junit.framework.TestSuite;
import org.eclipse.cdt.core.model.CoreModel; import org.eclipse.cdt.core.model.CoreModel;
import org.eclipse.cdt.core.settings.model.CMacroEntry;
import org.eclipse.cdt.core.settings.model.ICConfigurationDescription; 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.ICProjectDescription;
import org.eclipse.cdt.core.testplugin.ResourceHelper; import org.eclipse.cdt.core.testplugin.ResourceHelper;
import org.eclipse.cdt.internal.core.language.settings.providers.ILanguageSettingsChangeEvent;
import org.eclipse.cdt.internal.core.language.settings.providers.ILanguageSettingsChangeListener;
import org.eclipse.cdt.internal.core.language.settings.providers.LanguageSettingsProvidersSerializer;
import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IProject;
/** /**
@ -29,12 +34,38 @@ import org.eclipse.core.resources.IProject;
public class LanguageSettingsListenersTests extends TestCase { public class LanguageSettingsListenersTests extends TestCase {
// Must match provider id defined as extension point // Must match provider id defined as extension point
private static final String EXTENSION_REGISTERER_PROVIDER_ID = "org.eclipse.cdt.core.tests.language.settings.listener.registerer.provider"; private static final String EXTENSION_REGISTERER_PROVIDER_ID = "org.eclipse.cdt.core.tests.language.settings.listener.registerer.provider";
private static final String EXTENSION_EDITABLE_PROVIDER_ID = "org.eclipse.cdt.core.tests.custom.editable.language.settings.provider";
private static final String PROVIDER_1 = "test.provider.1.id"; private static final String PROVIDER_1 = "test.provider.1.id";
private static final String PROVIDER_NAME_1 = "test.provider.1.name"; private static final String PROVIDER_NAME_1 = "test.provider.1.name";
private static final String PROVIDER_CUSTOM_GLOBAL = "test.provider.custom.global.id"; private static final String PROVIDER_CUSTOM_GLOBAL = "test.provider.custom.global.id";
private static final String PROVIDER_CUSTOM_GLOBAL_NAME = "test.provider.custom.global.name"; private static final String PROVIDER_CUSTOM_GLOBAL_NAME = "test.provider.custom.global.name";
private static final CMacroEntry SAMPLE_LSE = new CMacroEntry("MACRO", "value",0);
private class MockLanguageSettingsChangeListener implements ILanguageSettingsChangeListener {
private int count = 0;
private ILanguageSettingsChangeEvent lastEvent = null;
public void handleEvent(ILanguageSettingsChangeEvent event) {
count++;
lastEvent = event;
}
public int getCount() {
return count;
}
public void resetCount() {
count = 0;
lastEvent = null;
}
public ILanguageSettingsChangeEvent getLastEvent() {
return lastEvent;
}
}
private MockLanguageSettingsChangeListener mockLseListener = new MockLanguageSettingsChangeListener();
/** /**
* Constructor. * Constructor.
* @param name - name of the test. * @param name - name of the test.
@ -50,6 +81,7 @@ public class LanguageSettingsListenersTests extends TestCase {
@Override @Override
protected void tearDown() throws Exception { protected void tearDown() throws Exception {
LanguageSettingsProvidersSerializer.unregisterLanguageSettingsChangeListener(mockLseListener);
LanguageSettingsManager.setWorkspaceProviders(null); LanguageSettingsManager.setWorkspaceProviders(null);
ResourceHelper.cleanUp(); ResourceHelper.cleanUp();
} }
@ -489,6 +521,543 @@ public class LanguageSettingsListenersTests extends TestCase {
} }
} }
/**
*/
public void testNotification_cfgProvider_AddEmptyProvider() throws Exception {
IProject project = ResourceHelper.createCDTProjectWithConfig(this.getName());
// First clear default providers
{
// get project descriptions
ICProjectDescription writableProjDescription = CoreModel.getDefault().getProjectDescription(project);
assertNotNull(writableProjDescription);
ICConfigurationDescription[] cfgDescriptions = writableProjDescription.getConfigurations();
assertEquals(1, cfgDescriptions.length);
ICConfigurationDescription cfgDescription = cfgDescriptions[0];
// clear providers
List<ILanguageSettingsProvider> providers = new ArrayList<ILanguageSettingsProvider>();
cfgDescription.setLanguageSettingProviders(providers);
List<ILanguageSettingsProvider> storedProviders = cfgDescription.getLanguageSettingProviders();
assertEquals(0, storedProviders.size());
// write to project description
CoreModel.getDefault().setProjectDescription(project, writableProjDescription);
}
// register mock listener to inspect the notifications
LanguageSettingsProvidersSerializer.registerLanguageSettingsChangeListener(mockLseListener);
assertEquals(0, mockLseListener.getCount());
assertEquals(null, mockLseListener.getLastEvent());
// Add empty provider
{
// get project descriptions
ICProjectDescription writableProjDescription = CoreModel.getDefault().getProjectDescription(project);
assertNotNull(writableProjDescription);
ICConfigurationDescription[] cfgDescriptions = writableProjDescription.getConfigurations();
assertEquals(1, cfgDescriptions.length);
ICConfigurationDescription cfgDescription = cfgDescriptions[0];
// create a provider and add to cfgDescription
ILanguageSettingsProvider mockProvider = new MockLanguageSettingsEditableProvider(PROVIDER_1, PROVIDER_NAME_1);
List<ILanguageSettingsProvider> providers = new ArrayList<ILanguageSettingsProvider>();
providers.add(mockProvider);
cfgDescription.setLanguageSettingProviders(providers);
List<ILanguageSettingsProvider> storedProviders = cfgDescription.getLanguageSettingProviders();
assertEquals(1, storedProviders.size());
// write to project description
CoreModel.getDefault().setProjectDescription(project, writableProjDescription);
}
// No notifications expected
assertEquals(0, mockLseListener.getCount());
assertEquals(null, mockLseListener.getLastEvent());
}
/**
*/
public void testNotification_cfgProvider_AddNonEmptyProvider() throws Exception {
IProject project = ResourceHelper.createCDTProjectWithConfig(this.getName());
// First clear default providers
{
// get project descriptions
ICProjectDescription writableProjDescription = CoreModel.getDefault().getProjectDescription(project);
assertNotNull(writableProjDescription);
ICConfigurationDescription[] cfgDescriptions = writableProjDescription.getConfigurations();
assertEquals(1, cfgDescriptions.length);
ICConfigurationDescription cfgDescription = cfgDescriptions[0];
// clear providers
List<ILanguageSettingsProvider> providers = new ArrayList<ILanguageSettingsProvider>();
cfgDescription.setLanguageSettingProviders(providers);
List<ILanguageSettingsProvider> storedProviders = cfgDescription.getLanguageSettingProviders();
assertEquals(0, storedProviders.size());
// write to project description
CoreModel.getDefault().setProjectDescription(project, writableProjDescription);
}
// register mock listener to inspect the notifications
LanguageSettingsProvidersSerializer.registerLanguageSettingsChangeListener(mockLseListener);
assertEquals(0, mockLseListener.getCount());
assertEquals(null, mockLseListener.getLastEvent());
// Add non-empty provider
{
// get project descriptions
ICProjectDescription writableProjDescription = CoreModel.getDefault().getProjectDescription(project);
assertNotNull(writableProjDescription);
ICConfigurationDescription[] cfgDescriptions = writableProjDescription.getConfigurations();
assertEquals(1, cfgDescriptions.length);
ICConfigurationDescription cfgDescription = cfgDescriptions[0];
String cfgDescriptionId = cfgDescription.getId();
// create a provider and add entries
MockLanguageSettingsEditableProvider mockProvider = new MockLanguageSettingsEditableProvider(PROVIDER_1, PROVIDER_NAME_1);
List<ICLanguageSettingEntry> entries = new ArrayList<ICLanguageSettingEntry>();
entries.add(SAMPLE_LSE);
mockProvider.setSettingEntries(cfgDescription, project, null, entries);
List<ILanguageSettingsProvider> providers = new ArrayList<ILanguageSettingsProvider>();
providers.add(mockProvider);
cfgDescription.setLanguageSettingProviders(providers);
List<ILanguageSettingsProvider> storedProviders = cfgDescription.getLanguageSettingProviders();
assertEquals(1, storedProviders.size());
// write to project description
CoreModel.getDefault().setProjectDescription(project, writableProjDescription);
// inspect notifications
assertEquals(1, mockLseListener.getCount());
ILanguageSettingsChangeEvent event = mockLseListener.getLastEvent();
assertNotNull(event);
assertEquals(project.getName(), event.getProjectName());
assertEquals(1, event.getConfigurationDescriptionIds().length);
assertEquals(cfgDescriptionId, event.getConfigurationDescriptionIds()[0]);
assertEquals(1, event.getResources(cfgDescriptionId).length);
assertEquals(project, event.getResources(cfgDescriptionId)[0]);
}
}
/**
*/
public void testNotification_cfgProvider_SerializeEntries() throws Exception {
IProject project = ResourceHelper.createCDTProjectWithConfig(this.getName());
// add the mock provider
{
// get project descriptions
ICProjectDescription writableProjDescription = CoreModel.getDefault().getProjectDescription(project);
assertNotNull(writableProjDescription);
ICConfigurationDescription[] cfgDescriptions = writableProjDescription.getConfigurations();
assertEquals(1, cfgDescriptions.length);
ICConfigurationDescription cfgDescription = cfgDescriptions[0];
// create a provider and add to cfgDescription
List<ILanguageSettingsProvider> providers = new ArrayList<ILanguageSettingsProvider>();
providers.add(new MockLanguageSettingsEditableProvider(PROVIDER_1, PROVIDER_NAME_1));
cfgDescription.setLanguageSettingProviders(providers);
List<ILanguageSettingsProvider> storedProviders = cfgDescription.getLanguageSettingProviders();
assertEquals(1, storedProviders.size());
// write to project description
CoreModel.getDefault().setProjectDescription(project, writableProjDescription);
}
// register mock listener to inspect the notifications
LanguageSettingsProvidersSerializer.registerLanguageSettingsChangeListener(mockLseListener);
assertEquals(0, mockLseListener.getCount());
assertEquals(null, mockLseListener.getLastEvent());
// Change the provider's entries
{
// get project descriptions
ICProjectDescription prjDescription = CoreModel.getDefault().getProjectDescription(project, false);
assertNotNull(prjDescription);
ICConfigurationDescription[] cfgDescriptions = prjDescription.getConfigurations();
assertEquals(1, cfgDescriptions.length);
ICConfigurationDescription cfgDescription = cfgDescriptions[0];
String cfgDescriptionId = cfgDescription.getId();
// Add entries
List<ICLanguageSettingEntry> entries = new ArrayList<ICLanguageSettingEntry>();
entries.add(SAMPLE_LSE);
List<ILanguageSettingsProvider> providers = cfgDescription.getLanguageSettingProviders();
assertEquals(1, providers.size());
assertTrue(providers.get(0) instanceof MockLanguageSettingsEditableProvider);
MockLanguageSettingsEditableProvider mockProvider = (MockLanguageSettingsEditableProvider) providers.get(0);
mockProvider.setSettingEntries(cfgDescription, project, null, entries);
assertEquals(0, mockLseListener.getCount());
assertEquals(null, mockLseListener.getLastEvent());
// Serialize settings
LanguageSettingsProvidersSerializer.serializeLanguageSettings(prjDescription);
// inspect event
assertEquals(1, mockLseListener.getCount());
ILanguageSettingsChangeEvent event = mockLseListener.getLastEvent();
assertNotNull(event);
assertEquals(project.getName(), event.getProjectName());
assertEquals(1, event.getConfigurationDescriptionIds().length);
assertEquals(cfgDescriptionId, event.getConfigurationDescriptionIds()[0]);
assertEquals(1, event.getResources(cfgDescriptionId).length);
assertEquals(project, event.getResources(cfgDescriptionId)[0]);
// TODO - drill to the entries
}
}
/**
*/
public void testNotification_cfgProvider_SerializeEntriesConcurrent() throws Exception {
IProject project = ResourceHelper.createCDTProjectWithConfig(this.getName());
// add the mock provider
{
// get project descriptions
ICProjectDescription writableProjDescription = CoreModel.getDefault().getProjectDescription(project);
assertNotNull(writableProjDescription);
ICConfigurationDescription[] cfgDescriptions = writableProjDescription.getConfigurations();
assertEquals(1, cfgDescriptions.length);
ICConfigurationDescription cfgDescription = cfgDescriptions[0];
// create a provider and add to cfgDescription
List<ILanguageSettingsProvider> providers = new ArrayList<ILanguageSettingsProvider>();
providers.add(new MockLanguageSettingsEditableProvider(PROVIDER_1, PROVIDER_NAME_1));
cfgDescription.setLanguageSettingProviders(providers);
List<ILanguageSettingsProvider> storedProviders = cfgDescription.getLanguageSettingProviders();
assertEquals(1, storedProviders.size());
// write to project description
CoreModel.getDefault().setProjectDescription(project, writableProjDescription);
}
// register mock listener to inspect the notifications
LanguageSettingsProvidersSerializer.registerLanguageSettingsChangeListener(mockLseListener);
assertEquals(0, mockLseListener.getCount());
assertEquals(null, mockLseListener.getLastEvent());
// Change the provider's entries concurrently
// get project descriptions
ICProjectDescription prjDescription_1 = CoreModel.getDefault().getProjectDescription(project, false);
assertNotNull(prjDescription_1);
ICProjectDescription prjDescription_2 = CoreModel.getDefault().getProjectDescription(project, false);
assertNotNull(prjDescription_2);
{
ICConfigurationDescription[] cfgDescriptions = prjDescription_1.getConfigurations();
assertEquals(1, cfgDescriptions.length);
ICConfigurationDescription cfgDescriptionWritable = cfgDescriptions[0];
String cfgDescriptionId = cfgDescriptionWritable.getId();
// Add entries
List<ICLanguageSettingEntry> entries = new ArrayList<ICLanguageSettingEntry>();
entries.add(SAMPLE_LSE);
List<ILanguageSettingsProvider> providers = cfgDescriptionWritable.getLanguageSettingProviders();
assertEquals(1, providers.size());
assertTrue(providers.get(0) instanceof MockLanguageSettingsEditableProvider);
MockLanguageSettingsEditableProvider mockProvider = (MockLanguageSettingsEditableProvider) providers.get(0);
mockProvider.setSettingEntries(cfgDescriptionWritable, project, null, entries);
// reset count
mockLseListener.resetCount();
assertEquals(0, mockLseListener.getCount());
assertNull(mockLseListener.getLastEvent());
// Serialize settings
LanguageSettingsProvidersSerializer.serializeLanguageSettings(prjDescription_1);
// inspect event
assertEquals(1, mockLseListener.getCount());
ILanguageSettingsChangeEvent event = mockLseListener.getLastEvent();
assertNotNull(event);
assertEquals(project.getName(), event.getProjectName());
assertEquals(1, event.getConfigurationDescriptionIds().length);
assertEquals(cfgDescriptionId, event.getConfigurationDescriptionIds()[0]);
assertEquals(1, event.getResources(cfgDescriptionId).length);
assertEquals(project, event.getResources(cfgDescriptionId)[0]);
// TODO - drill to the entries
}
{
ICConfigurationDescription[] cfgDescriptions = prjDescription_2.getConfigurations();
assertEquals(1, cfgDescriptions.length);
ICConfigurationDescription cfgDescriptionWritable = cfgDescriptions[0];
String cfgDescriptionId = cfgDescriptionWritable.getId();
// Add same entries
List<ICLanguageSettingEntry> entries = new ArrayList<ICLanguageSettingEntry>();
entries.add(SAMPLE_LSE);
List<ILanguageSettingsProvider> providers = cfgDescriptionWritable.getLanguageSettingProviders();
assertEquals(1, providers.size());
assertTrue(providers.get(0) instanceof MockLanguageSettingsEditableProvider);
MockLanguageSettingsEditableProvider mockProvider = (MockLanguageSettingsEditableProvider) providers.get(0);
mockProvider.setSettingEntries(cfgDescriptionWritable, project, null, entries);
// reset count
mockLseListener.resetCount();
assertEquals(0, mockLseListener.getCount());
assertNull(mockLseListener.getLastEvent());
// Serialize settings
LanguageSettingsProvidersSerializer.serializeLanguageSettings(prjDescription_2);
// inspect event
assertEquals(0, mockLseListener.getCount());
ILanguageSettingsChangeEvent event = mockLseListener.getLastEvent();
assertNull(event);
}
}
/**
*/
public void testNotification_globalProvider_AddEmptyProvider() throws Exception {
IProject project = ResourceHelper.createCDTProjectWithConfig(this.getName());
// First clear default providers
{
// get project descriptions
ICProjectDescription writableProjDescription = CoreModel.getDefault().getProjectDescription(project);
assertNotNull(writableProjDescription);
ICConfigurationDescription[] cfgDescriptions = writableProjDescription.getConfigurations();
assertEquals(1, cfgDescriptions.length);
ICConfigurationDescription cfgDescription = cfgDescriptions[0];
// clear providers
List<ILanguageSettingsProvider> providers = new ArrayList<ILanguageSettingsProvider>();
cfgDescription.setLanguageSettingProviders(providers);
List<ILanguageSettingsProvider> storedProviders = cfgDescription.getLanguageSettingProviders();
assertEquals(0, storedProviders.size());
// write to project description
CoreModel.getDefault().setProjectDescription(project, writableProjDescription);
}
// register mock listener to inspect the notifications
LanguageSettingsProvidersSerializer.registerLanguageSettingsChangeListener(mockLseListener);
assertEquals(0, mockLseListener.getCount());
assertEquals(null, mockLseListener.getLastEvent());
// Add empty global provider
{
// get project descriptions
ICProjectDescription writableProjDescription = CoreModel.getDefault().getProjectDescription(project);
assertNotNull(writableProjDescription);
ICConfigurationDescription[] cfgDescriptions = writableProjDescription.getConfigurations();
assertEquals(1, cfgDescriptions.length);
ICConfigurationDescription cfgDescription = cfgDescriptions[0];
// retrieve a global provider
ILanguageSettingsProvider wspProvider = LanguageSettingsManager.getWorkspaceProvider(EXTENSION_EDITABLE_PROVIDER_ID);
assertNotNull(wspProvider);
ILanguageSettingsProvider rawProvider = LanguageSettingsManager.getRawProvider(wspProvider);
assertTrue(rawProvider instanceof MockLanguageSettingsEditableProvider);
// clear it
((MockLanguageSettingsEditableProvider) rawProvider).clear();
assertEquals(null, wspProvider.getSettingEntries(cfgDescription, project, null));
// add the provider to cfgDescription
List<ILanguageSettingsProvider> providers = new ArrayList<ILanguageSettingsProvider>();
providers.add(wspProvider);
cfgDescription.setLanguageSettingProviders(providers);
List<ILanguageSettingsProvider> storedProviders = cfgDescription.getLanguageSettingProviders();
assertEquals(1, storedProviders.size());
// write to project description
CoreModel.getDefault().setProjectDescription(project, writableProjDescription);
}
// No notifications expected
assertEquals(0, mockLseListener.getCount());
assertEquals(null, mockLseListener.getLastEvent());
}
/**
*/
public void testNotification_globalProvider_AddNonEmptyProvider() throws Exception {
IProject project = ResourceHelper.createCDTProjectWithConfig(this.getName());
// First clear default providers
{
// get project descriptions
ICProjectDescription writableProjDescription = CoreModel.getDefault().getProjectDescription(project);
assertNotNull(writableProjDescription);
ICConfigurationDescription[] cfgDescriptions = writableProjDescription.getConfigurations();
assertEquals(1, cfgDescriptions.length);
ICConfigurationDescription cfgDescription = cfgDescriptions[0];
// clear providers
List<ILanguageSettingsProvider> providers = new ArrayList<ILanguageSettingsProvider>();
cfgDescription.setLanguageSettingProviders(providers);
List<ILanguageSettingsProvider> storedProviders = cfgDescription.getLanguageSettingProviders();
assertEquals(0, storedProviders.size());
// write to project description
CoreModel.getDefault().setProjectDescription(project, writableProjDescription);
}
// register mock listener to inspect the notifications
LanguageSettingsProvidersSerializer.registerLanguageSettingsChangeListener(mockLseListener);
assertEquals(0, mockLseListener.getCount());
assertEquals(null, mockLseListener.getLastEvent());
// Add non-empty provider
{
// get project descriptions
ICProjectDescription writableProjDescription = CoreModel.getDefault().getProjectDescription(project);
assertNotNull(writableProjDescription);
ICConfigurationDescription[] cfgDescriptions = writableProjDescription.getConfigurations();
assertEquals(1, cfgDescriptions.length);
ICConfigurationDescription cfgDescription = cfgDescriptions[0];
String cfgDescriptionId = cfgDescription.getId();
// retrieve a global provider
ILanguageSettingsProvider wspProvider = LanguageSettingsManager.getWorkspaceProvider(EXTENSION_EDITABLE_PROVIDER_ID);
assertNotNull(wspProvider);
ILanguageSettingsProvider rawProvider = LanguageSettingsManager.getRawProvider(wspProvider);
assertTrue(rawProvider instanceof MockLanguageSettingsEditableProvider);
((MockLanguageSettingsEditableProvider) rawProvider).clear();
// add entries
List<ICLanguageSettingEntry> entries = new ArrayList<ICLanguageSettingEntry>();
entries.add(SAMPLE_LSE);
((MockLanguageSettingsEditableProvider) rawProvider).setSettingEntries(cfgDescription, project, null, entries);
assertEquals(SAMPLE_LSE, wspProvider.getSettingEntries(cfgDescription, project, null).get(0));
// add the provider to cfgDescription
List<ILanguageSettingsProvider> providers = new ArrayList<ILanguageSettingsProvider>();
providers.add(wspProvider);
cfgDescription.setLanguageSettingProviders(providers);
List<ILanguageSettingsProvider> storedProviders = cfgDescription.getLanguageSettingProviders();
assertEquals(1, storedProviders.size());
// write to project description
CoreModel.getDefault().setProjectDescription(project, writableProjDescription);
// inspect notifications
assertEquals(1, mockLseListener.getCount());
ILanguageSettingsChangeEvent event = mockLseListener.getLastEvent();
assertNotNull(event);
assertEquals(project.getName(), event.getProjectName());
assertEquals(1, event.getConfigurationDescriptionIds().length);
assertEquals(cfgDescriptionId, event.getConfigurationDescriptionIds()[0]);
assertEquals(1, event.getResources(cfgDescriptionId).length);
assertEquals(project, event.getResources(cfgDescriptionId)[0]);
}
}
/**
*/
public void testNotification_globalProvider_SerializeEntries() throws Exception {
IProject project = ResourceHelper.createCDTProjectWithConfig(this.getName());
// register mock listener to inspect the notifications
LanguageSettingsProvidersSerializer.registerLanguageSettingsChangeListener(mockLseListener);
// Add empty global provider
{
// get project descriptions
ICProjectDescription writableProjDescription = CoreModel.getDefault().getProjectDescription(project);
assertNotNull(writableProjDescription);
ICConfigurationDescription[] cfgDescriptions = writableProjDescription.getConfigurations();
assertEquals(1, cfgDescriptions.length);
ICConfigurationDescription cfgDescription = cfgDescriptions[0];
// retrieve a global provider
ILanguageSettingsProvider wspProvider = LanguageSettingsManager.getWorkspaceProvider(EXTENSION_EDITABLE_PROVIDER_ID);
assertNotNull(wspProvider);
ILanguageSettingsProvider rawProvider = LanguageSettingsManager.getRawProvider(wspProvider);
assertTrue(rawProvider instanceof MockLanguageSettingsEditableProvider);
// clear it
((MockLanguageSettingsEditableProvider) rawProvider).clear();
assertEquals(null, wspProvider.getSettingEntries(cfgDescription, project, null));
// add the provider to cfgDescription
List<ILanguageSettingsProvider> providers = new ArrayList<ILanguageSettingsProvider>();
providers.add(wspProvider);
cfgDescription.setLanguageSettingProviders(providers);
List<ILanguageSettingsProvider> storedProviders = cfgDescription.getLanguageSettingProviders();
assertEquals(1, storedProviders.size());
// write to project description
CoreModel.getDefault().setProjectDescription(project, writableProjDescription);
}
// Change the provider's entries
{
// retrieve a global provider
ILanguageSettingsProvider wspProvider = LanguageSettingsManager.getWorkspaceProvider(EXTENSION_EDITABLE_PROVIDER_ID);
assertNotNull(wspProvider);
ILanguageSettingsProvider rawProvider = LanguageSettingsManager.getRawProvider(wspProvider);
assertTrue(rawProvider instanceof MockLanguageSettingsEditableProvider);
((MockLanguageSettingsEditableProvider) rawProvider).clear();
// add entries
List<ICLanguageSettingEntry> entries = new ArrayList<ICLanguageSettingEntry>();
entries.add(SAMPLE_LSE);
((MockLanguageSettingsEditableProvider) rawProvider).setSettingEntries(null, project, null, entries);
assertEquals(SAMPLE_LSE, wspProvider.getSettingEntries(null, project, null).get(0));
// reset count
mockLseListener.resetCount();
assertEquals(0, mockLseListener.getCount());
assertEquals(null, mockLseListener.getLastEvent());
// Serialize settings
LanguageSettingsProvidersSerializer.serializeLanguageSettingsWorkspace();
// get cfgDescriptionId
ICProjectDescription prjDescription = CoreModel.getDefault().getProjectDescription(project, false);
assertNotNull(prjDescription);
ICConfigurationDescription[] cfgDescriptions = prjDescription.getConfigurations();
assertEquals(1, cfgDescriptions.length);
ICConfigurationDescription cfgDescription = cfgDescriptions[0];
String cfgDescriptionId = cfgDescription.getId();
// inspect event
assertEquals(1, mockLseListener.getCount());
ILanguageSettingsChangeEvent event = mockLseListener.getLastEvent();
assertNotNull(event);
assertEquals(project.getName(), event.getProjectName());
assertEquals(1, event.getConfigurationDescriptionIds().length);
assertEquals(cfgDescriptionId, event.getConfigurationDescriptionIds()[0]);
assertEquals(1, event.getResources(cfgDescriptionId).length);
assertEquals(project, event.getResources(cfgDescriptionId)[0]);
// TODO - drill to the entries
}
// Change the provider's entries back (bug was found for this case)
{
// retrieve a global provider
ILanguageSettingsProvider wspProvider = LanguageSettingsManager.getWorkspaceProvider(EXTENSION_EDITABLE_PROVIDER_ID);
assertNotNull(wspProvider);
ILanguageSettingsProvider rawProvider = LanguageSettingsManager.getRawProvider(wspProvider);
assertTrue(rawProvider instanceof MockLanguageSettingsEditableProvider);
// clear the provider again
((MockLanguageSettingsEditableProvider) rawProvider).clear();
// reset count
mockLseListener.resetCount();
assertEquals(0, mockLseListener.getCount());
assertEquals(null, mockLseListener.getLastEvent());
// Serialize settings
LanguageSettingsProvidersSerializer.serializeLanguageSettingsWorkspace();
// get cfgDescriptionId
ICProjectDescription prjDescription = CoreModel.getDefault().getProjectDescription(project, false);
assertNotNull(prjDescription);
ICConfigurationDescription[] cfgDescriptions = prjDescription.getConfigurations();
assertEquals(1, cfgDescriptions.length);
ICConfigurationDescription cfgDescription = cfgDescriptions[0];
String cfgDescriptionId = cfgDescription.getId();
// inspect event
assertEquals(1, mockLseListener.getCount());
ILanguageSettingsChangeEvent event = mockLseListener.getLastEvent();
assertNotNull(event);
assertEquals(project.getName(), event.getProjectName());
assertEquals(1, event.getConfigurationDescriptionIds().length);
assertEquals(cfgDescriptionId, event.getConfigurationDescriptionIds()[0]);
assertEquals(1, event.getResources(cfgDescriptionId).length);
assertEquals(project, event.getResources(cfgDescriptionId)[0]);
// TODO - drill to the entries
}
}
} }

View file

@ -28,7 +28,7 @@ import org.eclipse.cdt.core.settings.model.ICProjectDescription;
import org.eclipse.cdt.core.settings.model.ICSettingEntry; import org.eclipse.cdt.core.settings.model.ICSettingEntry;
import org.eclipse.cdt.core.testplugin.CModelMock; import org.eclipse.cdt.core.testplugin.CModelMock;
import org.eclipse.cdt.core.testplugin.ResourceHelper; import org.eclipse.cdt.core.testplugin.ResourceHelper;
import org.eclipse.cdt.internal.core.language.settings.providers.LanguageSettingsExtensionManager; import org.eclipse.cdt.internal.core.language.settings.providers.LanguageSettingsProvidersSerializer;
import org.eclipse.cdt.internal.core.settings.model.CConfigurationDescription; import org.eclipse.cdt.internal.core.settings.model.CConfigurationDescription;
import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder; import org.eclipse.core.resources.IFolder;
@ -561,7 +561,7 @@ public class LanguageSettingsManagerTests extends TestCase {
{ {
// retrieve local entries // retrieve local entries
List<ICLanguageSettingEntry> includes = LanguageSettingsExtensionManager List<ICLanguageSettingEntry> includes = LanguageSettingsProvidersSerializer
.getLocalSettingEntriesByKind(cfgDescription, FILE_0, LANG_ID, ICSettingEntry.INCLUDE_PATH); .getLocalSettingEntriesByKind(cfgDescription, FILE_0, LANG_ID, ICSettingEntry.INCLUDE_PATH);
assertEquals(localIncludeEntry, includes.get(0)); assertEquals(localIncludeEntry, includes.get(0));
assertEquals(1, includes.size()); assertEquals(1, includes.size());
@ -569,7 +569,7 @@ public class LanguageSettingsManagerTests extends TestCase {
{ {
// retrieve system entries // retrieve system entries
List<ICLanguageSettingEntry> includes = LanguageSettingsExtensionManager List<ICLanguageSettingEntry> includes = LanguageSettingsProvidersSerializer
.getSystemSettingEntriesByKind(cfgDescription, FILE_0, LANG_ID, ICSettingEntry.INCLUDE_PATH); .getSystemSettingEntriesByKind(cfgDescription, FILE_0, LANG_ID, ICSettingEntry.INCLUDE_PATH);
assertEquals(systemIncludeEntry, includes.get(0)); assertEquals(systemIncludeEntry, includes.get(0));
assertEquals(1, includes.size()); assertEquals(1, includes.size());
@ -577,7 +577,7 @@ public class LanguageSettingsManagerTests extends TestCase {
{ {
// retrieve both local and system // retrieve both local and system
List<ICLanguageSettingEntry> includes = LanguageSettingsExtensionManager List<ICLanguageSettingEntry> includes = LanguageSettingsProvidersSerializer
.getSettingEntriesByKind(cfgDescription, FILE_0, LANG_ID, ICSettingEntry.INCLUDE_PATH); .getSettingEntriesByKind(cfgDescription, FILE_0, LANG_ID, ICSettingEntry.INCLUDE_PATH);
assertEquals(entries.get(0), includes.get(0)); assertEquals(entries.get(0), includes.get(0));
assertEquals(entries.get(1), includes.get(1)); assertEquals(entries.get(1), includes.get(1));
@ -799,7 +799,7 @@ public class LanguageSettingsManagerTests extends TestCase {
LanguageSettingsSerializable provider = new LanguageSettingsSerializable(PROVIDER_1, PROVIDER_NAME_1); LanguageSettingsSerializable provider = new LanguageSettingsSerializable(PROVIDER_1, PROVIDER_NAME_1);
provider.setSettingEntries(null, file, null, entries); provider.setSettingEntries(null, file, null, entries);
// build the hierarchy // build the hierarchy
LanguageSettingsExtensionManager.buildResourceTree(provider, null, null, project); LanguageSettingsProvidersSerializer.buildResourceTree(provider, null, null, project);
// check that entries go to highest possible level // check that entries go to highest possible level
assertEquals(entries, LanguageSettingsManager.getSettingEntriesUpResourceTree(provider, null, file, null)); assertEquals(entries, LanguageSettingsManager.getSettingEntriesUpResourceTree(provider, null, file, null));

View file

@ -19,6 +19,10 @@ public class MockLanguageSettingsEditableProvider extends LanguageSettingsSerial
super(); super();
} }
public MockLanguageSettingsEditableProvider(String id, String name) {
super(id, name);
}
public MockLanguageSettingsEditableProvider cloneShallow() throws CloneNotSupportedException { public MockLanguageSettingsEditableProvider cloneShallow() throws CloneNotSupportedException {
return (MockLanguageSettingsEditableProvider) super.cloneShallow(); return (MockLanguageSettingsEditableProvider) super.cloneShallow();
} }

View file

@ -54,7 +54,7 @@ public class LanguageSettingsManager {
* although individual providers return {@code null} if no settings defined. * although individual providers return {@code null} if no settings defined.
*/ */
public static List<ICLanguageSettingEntry> getSettingEntriesUpResourceTree(ILanguageSettingsProvider provider, ICConfigurationDescription cfgDescription, IResource rc, String languageId) { public static List<ICLanguageSettingEntry> getSettingEntriesUpResourceTree(ILanguageSettingsProvider provider, ICConfigurationDescription cfgDescription, IResource rc, String languageId) {
return LanguageSettingsExtensionManager.getSettingEntriesUpResourceTree(provider, cfgDescription, rc, languageId); return LanguageSettingsProvidersSerializer.getSettingEntriesUpResourceTree(provider, cfgDescription, rc, languageId);
} }
/** /**
@ -71,7 +71,7 @@ public class LanguageSettingsManager {
* @param project - the project which is considered the root of the resource tree. * @param project - the project which is considered the root of the resource tree.
*/ */
public static void buildResourceTree(LanguageSettingsSerializable provider, ICConfigurationDescription cfgDescription, String languageId, IProject project) { public static void buildResourceTree(LanguageSettingsSerializable provider, ICConfigurationDescription cfgDescription, String languageId, IProject project) {
LanguageSettingsExtensionManager.buildResourceTree(provider, cfgDescription, languageId, project); LanguageSettingsProvidersSerializer.buildResourceTree(provider, cfgDescription, languageId, project);
} }
@ -93,7 +93,7 @@ public class LanguageSettingsManager {
*/ */
// FIXME: get rid of callers PathEntryTranslator and DescriptionScannerInfoProvider // FIXME: get rid of callers PathEntryTranslator and DescriptionScannerInfoProvider
public static List<ICLanguageSettingEntry> getSettingEntriesByKind(ICConfigurationDescription cfgDescription, IResource rc, String languageId, int kind) { public static List<ICLanguageSettingEntry> getSettingEntriesByKind(ICConfigurationDescription cfgDescription, IResource rc, String languageId, int kind) {
return LanguageSettingsExtensionManager.getSettingEntriesByKind(cfgDescription, rc, languageId, kind); return LanguageSettingsProvidersSerializer.getSettingEntriesByKind(cfgDescription, rc, languageId, kind);
} }
/** /**

View file

@ -20,7 +20,6 @@ import org.eclipse.cdt.internal.core.language.settings.providers.LanguageSetting
import org.eclipse.cdt.internal.core.language.settings.providers.LanguageSettingsProvidersSerializer; import org.eclipse.cdt.internal.core.language.settings.providers.LanguageSettingsProvidersSerializer;
import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
/** /**
* This temporary class keeps the utility methods being looking for better home * This temporary class keeps the utility methods being looking for better home
@ -53,11 +52,6 @@ public class LanguageSettingsManager_TBD {
return false; return false;
} }
@Deprecated // Shouldn't be API
public static void serializeWorkspaceProviders() throws CoreException {
LanguageSettingsProvidersSerializer.serializeLanguageSettingsWorkspace();
}
public static boolean isReconfigured(ILanguageSettingsProvider provider) { public static boolean isReconfigured(ILanguageSettingsProvider provider) {
if (provider instanceof ILanguageSettingsEditableProvider) { if (provider instanceof ILanguageSettingsEditableProvider) {
try { try {

View file

@ -12,13 +12,9 @@
package org.eclipse.cdt.core.language.settings.providers; package org.eclipse.cdt.core.language.settings.providers;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.Set;
import org.eclipse.cdt.core.settings.model.ICConfigurationDescription; import org.eclipse.cdt.core.settings.model.ICConfigurationDescription;
import org.eclipse.cdt.core.settings.model.ICLanguageSettingEntry; import org.eclipse.cdt.core.settings.model.ICLanguageSettingEntry;
@ -26,7 +22,7 @@ import org.eclipse.cdt.core.settings.model.ICSettingEntry;
import org.eclipse.cdt.core.settings.model.util.CDataUtil; import org.eclipse.cdt.core.settings.model.util.CDataUtil;
import org.eclipse.cdt.core.settings.model.util.LanguageSettingEntriesSerializer; import org.eclipse.cdt.core.settings.model.util.LanguageSettingEntriesSerializer;
import org.eclipse.cdt.internal.core.XmlUtil; import org.eclipse.cdt.internal.core.XmlUtil;
import org.eclipse.cdt.internal.core.parser.util.WeakHashSet; import org.eclipse.cdt.internal.core.language.settings.providers.LanguageSettingsStorage;
import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.IResource;
import org.w3c.dom.Element; import org.w3c.dom.Element;
import org.w3c.dom.Node; import org.w3c.dom.Node;
@ -45,45 +41,17 @@ public class LanguageSettingsSerializable extends LanguageSettingsBaseProvider {
private static final String ATTR_ID = "id"; //$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_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_NAME = "name"; //$NON-NLS-1$
private static final String ATTR_VALUE = "value"; //$NON-NLS-1$
private static final String ATTR_CLASS = "class"; //$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_PARAMETER = "parameter"; //$NON-NLS-1$
private static final String ELEM_FLAG = "flag"; //$NON-NLS-1$
private static final String ATTR_STORE_ENTRIES = "store-entries"; //$NON-NLS-1$ private static final String ATTR_STORE_ENTRIES = "store-entries"; //$NON-NLS-1$
private static final String VALUE_WORKSPACE = "workspace"; //$NON-NLS-1$ private static final String VALUE_WORKSPACE = "workspace"; //$NON-NLS-1$
private static final String VALUE_PROJECT = "project"; //$NON-NLS-1$ private static final String VALUE_PROJECT = "project"; //$NON-NLS-1$
/**
* Pool of LSE lists implemented as WeakHashSet. That allows to gain memory savings
* at the expense of CPU time. WeakHashSet handles garbage collection when a list is not
* referenced anywhere else. See JavaDoc {@link java.lang.ref.WeakReference} about weak reference objects.
*/
private static WeakHashSet<List<ICLanguageSettingEntry>> listPool = new WeakHashSet<List<ICLanguageSettingEntry>>() {
@Override
public synchronized List<ICLanguageSettingEntry> add(List<ICLanguageSettingEntry> list) {
return super.add(list);
}
};
/** Tells if language settings entries are persisted with the project or in workspace area while serializing. */ /** Tells if language settings entries are persisted with the project or in workspace area while serializing. */
private boolean storeEntriesInProjectArea = false; private boolean storeEntriesInProjectArea = false;
/** private LanguageSettingsStorage fStorage = new LanguageSettingsStorage();
* Storage to keep settings entries. Note that it is not necessary to keep configuration in the maps
* as the configuration is always the one provider belongs to.
*/
private Map<String, // languageId
Map<String, // resource project path
List<ICLanguageSettingEntry>>> fStorage = new HashMap<String, Map<String, List<ICLanguageSettingEntry>>>();
/** /**
* Default constructor. This constructor has to be always followed with setting id and name of the provider. * Default constructor. This constructor has to be always followed with setting id and name of the provider.
@ -185,57 +153,6 @@ public class LanguageSettingsSerializable extends LanguageSettingsBaseProvider {
fStorage.clear(); fStorage.clear();
} }
/**
* Internal convenience method to set language settings entries.
*/
private void setSettingEntriesInternal(String rcProjectPath, String languageId, List<ICLanguageSettingEntry> entries) {
if (entries!=null) {
Map<String, List<ICLanguageSettingEntry>> langMap = fStorage.get(languageId);
if (langMap==null) {
langMap = new HashMap<String, List<ICLanguageSettingEntry>>();
fStorage.put(languageId, langMap);
}
List<ICLanguageSettingEntry> sortedEntries = listPool.add(Collections.unmodifiableList(sortEntries(entries)));
langMap.put(rcProjectPath, sortedEntries);
} else {
// do not keep nulls in the tables
Map<String, List<ICLanguageSettingEntry>> langMap = fStorage.get(languageId);
if (langMap!=null) {
langMap.remove(rcProjectPath);
if (langMap.size()==0) {
fStorage.remove(languageId);
}
}
}
}
/**
* Some providers may collect entries in pretty much random order. For the purposes of
* predictability, UI usability and efficient storage the entries are sorted by kinds
* and secondary by name for kinds where the secondary order is not significant.
*
* @param entries - list of entries to sort.
* @return - sorted entries.
*/
protected List<ICLanguageSettingEntry> sortEntries(List<ICLanguageSettingEntry> entries) {
List<ICLanguageSettingEntry> sortedEntries = new ArrayList<ICLanguageSettingEntry>(entries);
Collections.sort(sortedEntries, new Comparator<ICLanguageSettingEntry>(){
/**
* This comparator sorts by kinds first and the macros are sorted additionally by name.
*/
public int compare(ICLanguageSettingEntry entry0, ICLanguageSettingEntry entry1) {
int kind0 = entry0.getKind();
int kind1 = entry1.getKind();
if (kind0==ICSettingEntry.MACRO && kind1==ICSettingEntry.MACRO) {
return entry0.getName().compareTo(entry1.getName());
}
return kind0 - kind1;
}});
return sortedEntries;
}
/** /**
* Sets language settings entries for the provider. * Sets language settings entries for the provider.
* Note that the entries are not persisted at that point. To persist use TODO * Note that the entries are not persisted at that point. To persist use TODO
@ -248,7 +165,12 @@ public class LanguageSettingsSerializable extends LanguageSettingsBaseProvider {
*/ */
public void setSettingEntries(ICConfigurationDescription cfgDescription, IResource rc, String languageId, List<ICLanguageSettingEntry> entries) { public void setSettingEntries(ICConfigurationDescription cfgDescription, IResource rc, String languageId, List<ICLanguageSettingEntry> entries) {
String rcProjectPath = rc!=null ? rc.getProjectRelativePath().toString() : null; String rcProjectPath = rc!=null ? rc.getProjectRelativePath().toString() : null;
setSettingEntriesInternal(rcProjectPath, languageId, entries); fStorage.setSettingEntries(rcProjectPath, languageId, entries);
// // TODO - not sure what is more efficient, to do that or not to do that?
// if (fStorage.equals(lastPersistedState)) {
// lastPersistedState = null;
// }
} }
/** /**
@ -256,28 +178,27 @@ public class LanguageSettingsSerializable extends LanguageSettingsBaseProvider {
* <br> Note that this list is <b>unmodifiable</b>. To modify the list copy it, change and use * <br> Note that this list is <b>unmodifiable</b>. To modify the list copy it, change and use
* {@link #setSettingEntries(ICConfigurationDescription, IResource, String, List)}. * {@link #setSettingEntries(ICConfigurationDescription, IResource, String, List)}.
* *
* <br/> Note also that <b>you can compare these lists with simple equality operator ==</b>,
* as lists themselves are backed by WeakHashSet<List<ICLanguageSettingEntry>> where
* identical copies (deep comparison is used) are replaced with the same one instance.
*/ */
@Override @Override
public List<ICLanguageSettingEntry> getSettingEntries(ICConfigurationDescription cfgDescription, IResource rc, String languageId) { public List<ICLanguageSettingEntry> getSettingEntries(ICConfigurationDescription cfgDescription, IResource rc, String languageId) {
Map<String, List<ICLanguageSettingEntry>> langMap = fStorage.get(languageId); List<ICLanguageSettingEntry> entries = fStorage.getSettingEntries(cfgDescription, rc, languageId);
if (langMap!=null) { if (entries == null) {
String rcProjectPath = rc!=null ? rc.getProjectRelativePath().toString() : null; if (languageId!=null && (languageScope==null || languageScope.contains(languageId))) {
List<ICLanguageSettingEntry> entries = langMap.get(rcProjectPath); entries = getSettingEntries(cfgDescription, rc, null);
if (entries!=null) }
return entries;
} }
if (languageId!=null && (languageScope==null || languageScope.contains(languageId))) { return entries;
List<ICLanguageSettingEntry> entries = getSettingEntries(cfgDescription, rc, null);
return entries;
}
return null;
} }
/** /**
* Serialize the provider under parent XML element. * Serialize the provider under parent XML element.
* This is convenience method not intended to be overridden on purpose. * This is convenience method not intended to be overridden on purpose.
* Override {@link #serializeAttributes(Element)} or
* {@link #serializeEntries(Element)} instead.
* *
* @param parentElement - element where to serialize. * @param parentElement - element where to serialize.
* @return - newly created <provider> element. That element will already be * @return - newly created <provider> element. That element will already be
@ -329,98 +250,18 @@ public class LanguageSettingsSerializable extends LanguageSettingsBaseProvider {
* @param elementProvider - element where to serialize the entries. * @param elementProvider - element where to serialize the entries.
*/ */
public void serializeEntries(Element elementProvider) { public void serializeEntries(Element elementProvider) {
for (Entry<String, Map<String, List<ICLanguageSettingEntry>>> entryLang : fStorage.entrySet()) { fStorage.serializeEntries(elementProvider);
serializeLanguage(elementProvider, entryLang);
}
} }
/**
* Serialize the provider entries for a given language list.
*/
private void serializeLanguage(Element parentElement, Entry<String, Map<String, List<ICLanguageSettingEntry>>> entryLang) {
String langId = entryLang.getKey();
if (langId!=null) {
Element elementLanguage = XmlUtil.appendElement(parentElement, ELEM_LANGUAGE, new String[] {ATTR_ID, langId});
parentElement = elementLanguage;
}
for (Entry<String, List<ICLanguageSettingEntry>> entryRc : entryLang.getValue().entrySet()) {
serializeResource(parentElement, entryRc);
}
}
/**
* Serialize the provider entries for a given resource list.
*/
private void serializeResource(Element parentElement, Entry<String, List<ICLanguageSettingEntry>> 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());
}
/**
* Serialize given settings entries.
*/
private void serializeSettingEntries(Element parentElement, List<ICLanguageSettingEntry> 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 may 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())
});
}
}
}
/**
* Load a setting entry from XML element.
*/
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<flagNodes.getLength();i++) {
Node flagNode = flagNodes.item(i);
if(flagNode.getNodeType() != Node.ELEMENT_NODE || !ELEM_FLAG.equals(flagNode.getNodeName()))
continue;
String settingFlags = XmlUtil.determineAttributeValue(flagNode, ATTR_VALUE);
int bitFlag = LanguageSettingEntriesSerializer.composeFlags(settingFlags);
flags |= bitFlag;
}
String settingValue = null;
int kind = LanguageSettingEntriesSerializer.stringToKind(settingKind);
if (kind == ICSettingEntry.MACRO)
settingValue = XmlUtil.determineAttributeValue(parentElement, ATTR_VALUE);
ICLanguageSettingEntry entry = (ICLanguageSettingEntry) CDataUtil.createEntry(kind, settingName, settingValue, null, flags);
return entry;
}
/** /**
* Load provider from XML provider element. * Load provider from XML provider element.
* This is convenience method not intended to be overridden on purpose.
* Override {@link #loadAttributes(Element)} or
* {@link #loadEntries(Element)} instead.
*
* @param providerNode - XML element <provider> to load provider from. * @param providerNode - XML element <provider> to load provider from.
*/ */
public void load(Element providerNode) { final public void load(Element providerNode) {
fStorage.clear(); fStorage.clear();
languageScope = null; languageScope = null;
@ -431,6 +272,18 @@ public class LanguageSettingsSerializable extends LanguageSettingsBaseProvider {
} }
} }
/**
* Determine and set language scope from given XML node.
*/
private void loadLanguageScopeElement(Node parentNode) {
if (languageScope==null) {
languageScope = new ArrayList<String>();
}
String id = XmlUtil.determineAttributeValue(parentNode, ATTR_ID);
languageScope.add(id);
}
/** /**
* Load attributes from XML provider element. * Load attributes from XML provider element.
* @param providerNode - XML element <provider> to load attributes from. * @param providerNode - XML element <provider> to load attributes from.
@ -464,123 +317,7 @@ public class LanguageSettingsSerializable extends LanguageSettingsBaseProvider {
* @param providerNode - parent XML element <provider> where entries are defined. * @param providerNode - parent XML element <provider> where entries are defined.
*/ */
public void loadEntries(Element providerNode) { public void loadEntries(Element providerNode) {
List<ICLanguageSettingEntry> settings = new ArrayList<ICLanguageSettingEntry>(); fStorage.loadEntries(providerNode);
NodeList nodes = providerNode.getChildNodes();
for (int i=0;i<nodes.getLength();i++) {
Node elementNode = nodes.item(i);
if(elementNode.getNodeType() != Node.ELEMENT_NODE)
continue;
if (ELEM_LANGUAGE.equals(elementNode.getNodeName())) {
loadLanguageElement(elementNode, null);
} else if (ELEM_RESOURCE.equals(elementNode.getNodeName())) {
loadResourceElement(elementNode, null, null);
} else if (ELEM_ENTRY.equals(elementNode.getNodeName())) {
ICLanguageSettingEntry entry = loadSettingEntry(elementNode);
if (entry!=null) {
settings.add(entry);
}
}
}
// set settings
if (settings.size()>0) {
setSettingEntriesInternal(null, null, settings);
}
}
/**
* Determine and set language scope from given XML node.
*/
private void loadLanguageScopeElement(Node parentNode) {
if (languageScope==null) {
languageScope = new ArrayList<String>();
}
String id = XmlUtil.determineAttributeValue(parentNode, ATTR_ID);
languageScope.add(id);
}
/**
* Load entries defined in language element.
*/
private void loadLanguageElement(Node parentNode, String cfgId) {
String langId = XmlUtil.determineAttributeValue(parentNode, ATTR_ID);
if (langId.length()==0) {
langId=null;
}
List<ICLanguageSettingEntry> settings = new ArrayList<ICLanguageSettingEntry>();
NodeList nodes = parentNode.getChildNodes();
for (int i=0;i<nodes.getLength();i++) {
Node elementNode = nodes.item(i);
if(elementNode.getNodeType() != Node.ELEMENT_NODE)
continue;
if (ELEM_RESOURCE.equals(elementNode.getNodeName())) {
loadResourceElement(elementNode, cfgId, langId);
} else if (ELEM_ENTRY.equals(elementNode.getNodeName())) {
ICLanguageSettingEntry entry = loadSettingEntry(elementNode);
if (entry!=null) {
settings.add(entry);
}
}
}
// set settings
if (settings.size()>0) {
setSettingEntriesInternal(null, langId, settings);
}
}
/**
* Load entries defined in resource element.
*/
private void loadResourceElement(Node parentNode, String cfgId, String langId) {
String rcProjectPath = XmlUtil.determineAttributeValue(parentNode, ATTR_PROJECT_PATH);
List<ICLanguageSettingEntry> settings = new ArrayList<ICLanguageSettingEntry>();
NodeList nodes = parentNode.getChildNodes();
for (int i=0;i<nodes.getLength();i++) {
Node elementNode = nodes.item(i);
if(elementNode.getNodeType() != Node.ELEMENT_NODE)
continue;
if (ELEM_ENTRY.equals(elementNode.getNodeName())) {
ICLanguageSettingEntry entry = loadSettingEntry(elementNode);
if (entry!=null) {
settings.add(entry);
}
}
}
// set settings
if (settings.size()>0) {
setSettingEntriesInternal(rcProjectPath, langId, settings);
}
}
/**
* Clone storage for the entries. Copies references for lists of entries as a whole.
* Note that is OK as the lists kept in storage are unmodifiable.
*/
private Map<String, Map<String, List<ICLanguageSettingEntry>>> cloneStorage() {
Map<String, // languageId
Map<String, // resource
List<ICLanguageSettingEntry>>> storageClone = new HashMap<String, Map<String, List<ICLanguageSettingEntry>>>();
Set<Entry<String, Map<String, List<ICLanguageSettingEntry>>>> entrySetLang = fStorage.entrySet();
for (Entry<String, Map<String, List<ICLanguageSettingEntry>>> entryLang : entrySetLang) {
String langId = entryLang.getKey();
Map<String, List<ICLanguageSettingEntry>> mapRc = entryLang.getValue();
Map<String, List<ICLanguageSettingEntry>> mapRcClone = new HashMap<String, List<ICLanguageSettingEntry>>();
Set<Entry<String, List<ICLanguageSettingEntry>>> entrySetRc = mapRc.entrySet();
for (Entry<String, List<ICLanguageSettingEntry>> entryRc : entrySetRc) {
String rcProjectPath = entryRc.getKey();
List<ICLanguageSettingEntry> lsEntries = entryRc.getValue();
// don't need to clone entries, they are from the LSE pool
mapRcClone.put(rcProjectPath, lsEntries);
}
storageClone.put(langId, mapRcClone);
}
return storageClone;
} }
/** /**
@ -592,7 +329,7 @@ public class LanguageSettingsSerializable extends LanguageSettingsBaseProvider {
if (languageScope!=null) if (languageScope!=null)
clone.languageScope = new ArrayList<String>(languageScope); clone.languageScope = new ArrayList<String>(languageScope);
clone.fStorage = new HashMap<String, Map<String, List<ICLanguageSettingEntry>>>(); clone.fStorage = new LanguageSettingsStorage();
return clone; return clone;
} }
@ -610,7 +347,7 @@ public class LanguageSettingsSerializable extends LanguageSettingsBaseProvider {
@Override @Override
protected LanguageSettingsSerializable clone() throws CloneNotSupportedException { protected LanguageSettingsSerializable clone() throws CloneNotSupportedException {
LanguageSettingsSerializable clone = cloneShallowInternal(); LanguageSettingsSerializable clone = cloneShallowInternal();
clone.fStorage = cloneStorage(); clone.fStorage = fStorage.cloneStorage();
return clone; return clone;
} }
@ -680,4 +417,11 @@ public class LanguageSettingsSerializable extends LanguageSettingsBaseProvider {
return false; return false;
return true; return true;
} }
/**
* @noreference This method is not intended to be referenced by clients.
*/
public LanguageSettingsStorage getStorageInternal() {
return fStorage;
}
} }

View file

@ -13,7 +13,8 @@ package org.eclipse.cdt.core.language.settings.providers;
// TODO: move ILanguageSettingsEditableProvider here // TODO: move ILanguageSettingsEditableProvider here
public class LanguageSettingsSerializableEditable extends LanguageSettingsSerializable implements ILanguageSettingsEditableProvider { // TODO this one is unused - remove
final public class LanguageSettingsSerializableEditable extends LanguageSettingsSerializable implements ILanguageSettingsEditableProvider {
@Override @Override
public LanguageSettingsSerializableEditable clone() throws CloneNotSupportedException { public LanguageSettingsSerializableEditable clone() throws CloneNotSupportedException {
return (LanguageSettingsSerializableEditable) super.clone(); return (LanguageSettingsSerializableEditable) super.clone();

View file

@ -395,6 +395,8 @@ public interface ICConfigurationDescription extends ICSettingContainer, ICSettin
* or preprocessor macros. * or preprocessor macros.
* *
* @param providers the list of providers to assign to the configuration description. * @param providers the list of providers to assign to the configuration description.
* Warning: the providers will be cloned before actual addition to the project model
* due to TODO - very important reason but I forgot why by now.
* *
* @since 6.0 * @since 6.0
*/ */

View file

@ -0,0 +1,36 @@
/*******************************************************************************
* 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.internal.core.language.settings.providers;
import org.eclipse.cdt.core.settings.model.ICLanguageSettingEntry;
import org.eclipse.core.resources.IResource;
/**
* Contains the details of changes that occurred as a result of modifying
* language settings entries {@link ICLanguageSettingEntry}.
*
* @noextend This interface is not intended to be extended by clients.
* @noimplement This interface is not intended to be implemented by clients.
*/
public interface ILanguageSettingsChangeEvent {
public String getProjectName();
public String[] getConfigurationDescriptionIds();
public IResource[] getResources(String cfgDescriptionId);
// // AG - YAGNI
// public List<ICLanguageSettingEntry> getSettingEntriesOld(ICConfigurationDescription cfgDescription, IResource rc, String languageId);
// public List<ICLanguageSettingEntry> getSettingEntriesNew(ICConfigurationDescription cfgDescription, IResource rc, String languageId);
// // AG - or maybe
// ILanguageSettingsDelta getDelta(ICConfigurationDescription cfgDescription);
}

View file

@ -0,0 +1,22 @@
/*******************************************************************************
* 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.internal.core.language.settings.providers;
/**
* Listens to changes in language settings.
*/
public interface ILanguageSettingsChangeListener {
/**
* Indicates that language settings have been changed.
* @param event
*/
public void handleEvent(ILanguageSettingsChangeEvent event);
}

View file

@ -0,0 +1,155 @@
/*******************************************************************************
* 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.internal.core.language.settings.providers;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
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.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.runtime.Assert;
// TODO possibly make an interface from that
public class LanguageSettingsDelta {
// maps need to be ordered by providers
private LinkedHashMap<String, // providerId
LanguageSettingsStorage> oldLanguageSettingsState;
private LinkedHashMap<String, // providerId
LanguageSettingsStorage> newLanguageSettingsState;
public LanguageSettingsDelta(LinkedHashMap<String, LanguageSettingsStorage> oldState, LinkedHashMap<String, LanguageSettingsStorage> newState) {
oldLanguageSettingsState = oldState;
newLanguageSettingsState = newState;
}
// FIXME - this API is no good
public Set<IResource> getChangedResources(IProject project, ICConfigurationDescription cfgDescription) {
Set<IResource> resources = new HashSet<IResource>();
// Ordered collections
Collection<LanguageSettingsStorage> oldStateStorages = oldLanguageSettingsState.values();
Collection<LanguageSettingsStorage> newStateStorages = newLanguageSettingsState.values();
for (LanguageSettingsStorage lss : oldStateStorages) {
// Map<String, // languageId
// Map<String, // resource project path
// List<ICLanguageSettingEntry>>>
Map<String, Map<String, List<ICLanguageSettingEntry>>> mapInternal = lss.getMapInternal();
synchronized (mapInternal) {
for (Entry<String, Map<String, List<ICLanguageSettingEntry>>> entryLang : mapInternal.entrySet()) {
String langId = entryLang.getKey();
for (Entry<String, List<ICLanguageSettingEntry>> entryRc : entryLang.getValue().entrySet()) {
String rcName = entryRc.getKey();
IResource rc = (rcName != null) ? project.findMember(rcName) : project;
if (resources.contains(rc))
continue;
List<ICLanguageSettingEntry> lsEntriesOld = entryRc.getValue();
List<ICLanguageSettingEntry> lsEntriesNew = getSettingEntries(newStateStorages, cfgDescription, rc, langId);
if (!lsEntriesNew.equals(lsEntriesOld) && !(lsEntriesOld==null && lsEntriesNew.size()==0)) {
resources.add(rc);
}
}
}
}
}
for (LanguageSettingsStorage lss : newStateStorages) {
// Map<String, // languageId
// Map<String, // resource project path
// List<ICLanguageSettingEntry>>>
Map<String, Map<String, List<ICLanguageSettingEntry>>> mapInternal = lss.getMapInternal();
synchronized (mapInternal) {
for (Entry<String, Map<String, List<ICLanguageSettingEntry>>> entryLang : mapInternal.entrySet()) {
String langId = entryLang.getKey();
for (Entry<String, List<ICLanguageSettingEntry>> entryRc : entryLang.getValue().entrySet()) {
String rcName = entryRc.getKey();
IResource rc = (rcName != null) ? project.findMember(rcName) : project;
if (resources.contains(rc))
continue;
List<ICLanguageSettingEntry> lsEntriesNew = entryRc.getValue();
List<ICLanguageSettingEntry> lsEntriesOld = getSettingEntries(oldStateStorages, cfgDescription, rc, langId);
if (!lsEntriesOld.equals(lsEntriesNew) && !(lsEntriesNew==null && lsEntriesOld.size()==0)) {
resources.add(rc);
}
}
}
}
}
return resources;
}
private static boolean checkBit(int flags, int bit) {
return (flags & bit) == bit;
}
private static List<ICLanguageSettingEntry> getSettingEntries(Collection<LanguageSettingsStorage> stores, ICConfigurationDescription cfgDescription, IResource rc, String languageId) {
List<ICLanguageSettingEntry> entries = new ArrayList<ICLanguageSettingEntry>();
List<String> alreadyAdded = new ArrayList<String>();
for (LanguageSettingsStorage store: stores) {
List<ICLanguageSettingEntry> providerEntries = getSettingEntriesUpResourceTree(store, cfgDescription, rc, languageId);
for (ICLanguageSettingEntry entry : providerEntries) {
if (entry!=null) {
String entryName = entry.getName();
// Only first entry is considered
// Entry flagged as "UNDEFINED" prevents adding entry with the same name down the line
if (!alreadyAdded.contains(entryName)) {
int flags = entry.getFlags();
if (!checkBit(flags, ICSettingEntry.UNDEFINED)) {
entries.add(entry);
}
alreadyAdded.add(entryName);
}
}
}
}
return entries;
}
private static List<ICLanguageSettingEntry> getSettingEntriesUpResourceTree(LanguageSettingsStorage store, ICConfigurationDescription cfgDescription, IResource rc, String languageId) {
Assert.isTrue( !(rc instanceof IWorkspaceRoot) );
if (store!=null) {
List<ICLanguageSettingEntry> entries = store.getSettingEntries(cfgDescription, rc, languageId);
if (entries!=null) {
return new ArrayList<ICLanguageSettingEntry>(entries);
}
if (rc!=null) {
IResource parentFolder = (rc instanceof IProject) ? null : rc.getParent();
if (parentFolder!=null) {
return getSettingEntriesUpResourceTree(store, cfgDescription, parentFolder, languageId);
}
// if out of parent resources - get default entries for the applicable language scope
entries = store.getSettingEntries(null, null, languageId);
if (entries!=null) {
return new ArrayList<ICLanguageSettingEntry>(entries);
}
}
}
return new ArrayList<ICLanguageSettingEntry>(0);
}
}

View file

@ -13,10 +13,8 @@ package org.eclipse.cdt.internal.core.language.settings.providers;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Comparator; import java.util.Comparator;
import java.util.HashMap;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.TreeSet; import java.util.TreeSet;
@ -26,19 +24,9 @@ import org.eclipse.cdt.core.language.settings.providers.ILanguageSettingsEditabl
import org.eclipse.cdt.core.language.settings.providers.ILanguageSettingsProvider; 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.LanguageSettingsBaseProvider;
import org.eclipse.cdt.core.language.settings.providers.LanguageSettingsSerializable; 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.ICLanguageSettingEntry;
import org.eclipse.cdt.core.settings.model.ICSettingEntry;
import org.eclipse.cdt.core.settings.model.util.CDataUtil; import org.eclipse.cdt.core.settings.model.util.CDataUtil;
import org.eclipse.cdt.core.settings.model.util.LanguageSettingEntriesSerializer; import org.eclipse.cdt.core.settings.model.util.LanguageSettingEntriesSerializer;
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.resources.IWorkspaceRoot;
import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IConfigurationElement; import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.IExtension; import org.eclipse.core.runtime.IExtension;
@ -340,267 +328,6 @@ public class LanguageSettingsExtensionManager {
return list; return list;
} }
private static List<ICLanguageSettingEntry> 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<ICLanguageSettingEntry>(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<ICLanguageSettingEntry> getSettingEntriesUpResourceTree(ILanguageSettingsProvider provider, ICConfigurationDescription cfgDescription, IResource rc, String languageId) {
Assert.isTrue( !(rc instanceof IWorkspaceRoot) );
if (provider!=null) {
List<ICLanguageSettingEntry> entries = safeGetSettingEntries(provider, cfgDescription, rc, languageId);
if (entries!=null) {
return new ArrayList<ICLanguageSettingEntry>(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<ICLanguageSettingEntry>(entries);
}
}
}
return new ArrayList<ICLanguageSettingEntry>(0);
}
/**
* Builds for the provider a nice looking resource tree to present hierarchical view to the user.
* Note that it is not advisable to "compact" the tree because of potential loss of information
* which is especially important during partial or incremental builds.
*
* @param provider - language settings provider to build the tree for.
* @param cfgDescription - configuration description.
* @param languageId - language ID.
* @param folder - container where the tree roots.
*/
public static void buildResourceTree(LanguageSettingsSerializable provider, ICConfigurationDescription cfgDescription, String languageId, IContainer folder) {
IResource[] members = null;
try {
members = folder.members();
} catch (Exception e) {
CCorePlugin.log(e);
}
if (members==null)
return;
for (IResource rc : members) {
if (rc instanceof IContainer) {
buildResourceTree(provider, cfgDescription, languageId, (IContainer) rc);
}
}
int rcNumber = members.length;
Map<List<ICLanguageSettingEntry>, Integer> listMap = new HashMap<List<ICLanguageSettingEntry>, Integer>();
// on the first pass find majority entries
List<ICLanguageSettingEntry> majorityEntries = null;
List<ICLanguageSettingEntry> candidate = null;
int candidateCount = 0;
for (IResource rc : members) {
if (!isLanguageInScope(rc, cfgDescription, languageId)) {
rcNumber--;
} else {
List<ICLanguageSettingEntry> entries = provider.getSettingEntries(null, rc, languageId);
if (entries==null && rc instanceof IContainer) {
rcNumber--;
} else {
Integer count = listMap.get(entries);
if (count==null) {
count = 0;
}
count++;
if (count>candidateCount) {
candidateCount = count;
candidate = entries;
}
listMap.put(entries, count);
}
}
if (candidateCount > rcNumber/2) {
majorityEntries = candidate;
break;
}
}
if (majorityEntries!=null) {
provider.setSettingEntries(cfgDescription, folder, languageId, majorityEntries);
}
// second pass - assign the entries to the folders
for (IResource rc : members) {
List<ICLanguageSettingEntry> entries = provider.getSettingEntries(null, rc, languageId);
if (entries!=null && entries==majorityEntries) {
if (!(rc instanceof IFile)) { // preserve information which files were collected
provider.setSettingEntries(cfgDescription, rc, languageId, null);
}
}
}
}
private static boolean isLanguageInScope(IResource rc, ICConfigurationDescription cfgDescription, String languageId) {
if (rc instanceof IFile) {
ILanguage lang = null;
try {
lang = LanguageManager.getInstance().getLanguageForFile((IFile) rc, cfgDescription);
} catch (CoreException e) {
CCorePlugin.log("Error loading language settings providers extensions", e); //$NON-NLS-1$
}
if (lang==null || (languageId!=null && !languageId.equals(lang.getId()))) {
return false;
}
}
return true;
}
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<ICLanguageSettingEntry> getSettingEntriesByKind(ICConfigurationDescription cfgDescription,
IResource rc, String languageId, int kind, boolean checkLocality, boolean isLocal) {
List<ICLanguageSettingEntry> entries = new ArrayList<ICLanguageSettingEntry>();
List<String> alreadyAdded = new ArrayList<String>();
List<ILanguageSettingsProvider> providers = cfgDescription.getLanguageSettingProviders();
for (ILanguageSettingsProvider provider: providers) {
List<ICLanguageSettingEntry> 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<ICLanguageSettingEntry> 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<ICLanguageSettingEntry> 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<ICLanguageSettingEntry> 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 { public static boolean equalsExtensionProviderShallow(ILanguageSettingsEditableProvider provider) throws CloneNotSupportedException {
String id = provider.getId(); String id = provider.getId();
ILanguageSettingsProvider extensionProviderShallow = getExtensionProviderShallow(id); ILanguageSettingsProvider extensionProviderShallow = getExtensionProviderShallow(id);

View file

@ -25,19 +25,29 @@ import org.eclipse.cdt.core.language.settings.providers.ILanguageSettingsProvide
import org.eclipse.cdt.core.language.settings.providers.LanguageSettingsManager; import org.eclipse.cdt.core.language.settings.providers.LanguageSettingsManager;
import org.eclipse.cdt.core.language.settings.providers.LanguageSettingsSerializable; import org.eclipse.cdt.core.language.settings.providers.LanguageSettingsSerializable;
import org.eclipse.cdt.core.language.settings.providers.ScannerDiscoveryLegacySupport; import org.eclipse.cdt.core.language.settings.providers.ScannerDiscoveryLegacySupport;
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.ICConfigurationDescription;
import org.eclipse.cdt.core.settings.model.ICLanguageSettingEntry; import org.eclipse.cdt.core.settings.model.ICLanguageSettingEntry;
import org.eclipse.cdt.core.settings.model.ICProjectDescription; import org.eclipse.cdt.core.settings.model.ICProjectDescription;
import org.eclipse.cdt.core.settings.model.ICSettingEntry;
import org.eclipse.cdt.internal.core.XmlUtil; import org.eclipse.cdt.internal.core.XmlUtil;
import org.eclipse.cdt.internal.core.settings.model.CConfigurationSpecSettings;
import org.eclipse.cdt.internal.core.settings.model.CProjectDescriptionManager;
import org.eclipse.cdt.internal.core.settings.model.IInternalCCfgInfo;
import org.eclipse.core.filesystem.URIUtil; import org.eclipse.core.filesystem.URIUtil;
import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder; import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.Assert; import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.ListenerList;
import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.ILock; import org.eclipse.core.runtime.jobs.ILock;
import org.eclipse.core.runtime.jobs.Job; import org.eclipse.core.runtime.jobs.Job;
@ -61,11 +71,15 @@ public class LanguageSettingsProvidersSerializer {
private static final String ELEM_CONFIGURATION = "configuration"; //$NON-NLS-1$ private static final String ELEM_CONFIGURATION = "configuration"; //$NON-NLS-1$
private static final String ELEM_PROVIDER = "provider"; //$NON-NLS-1$ private static final String ELEM_PROVIDER = "provider"; //$NON-NLS-1$
private static final String ELEM_PROVIDER_REFERENCE = "provider-reference"; //$NON-NLS-1$ private static final String ELEM_PROVIDER_REFERENCE = "provider-reference"; //$NON-NLS-1$
private static ILock serializingLock = Job.getJobManager().newLock(); private static ILock serializingLock = Job.getJobManager().newLock();
/** Cache of globally available providers to be consumed by calling clients */ /** Cache of globally available providers to be consumed by calling clients */
private static Map<String, ILanguageSettingsProvider> rawGlobalWorkspaceProviders = new HashMap<String, ILanguageSettingsProvider>(); private static Map<String, ILanguageSettingsProvider> rawGlobalWorkspaceProviders = new HashMap<String, ILanguageSettingsProvider>();
private static Map<String, ILanguageSettingsProvider> globalWorkspaceProviders = new HashMap<String, ILanguageSettingsProvider>(); private static Map<String, ILanguageSettingsProvider> globalWorkspaceProviders = new HashMap<String, ILanguageSettingsProvider>();
private static ListenerList fLanguageSettingsChangeListeners = new ListenerList(ListenerList.IDENTITY);
private static class ListenerAssociation { private static class ListenerAssociation {
private ICListenerRegisterer listener; private ICListenerRegisterer listener;
private ICConfigurationDescription cfgDescription; private ICConfigurationDescription cfgDescription;
@ -161,6 +175,75 @@ public class LanguageSettingsProvidersSerializer {
} }
} }
private static class LanguageSettingsChangeEvent implements ILanguageSettingsChangeEvent {
private String projectName = null;
private Map<String /*cfg*/, LanguageSettingsDelta> deltaMap = new HashMap<String, LanguageSettingsDelta>();
private IResource[] resources = null;
/**
* The act of creating event resets internal delta count in configuration state.
* That implies that when the event is retrieved it must be fired or delta will go missing.
* That side effect is here to ensure atomic processing of firing & resetting the delta.
*/
public LanguageSettingsChangeEvent(ICProjectDescription prjDescription) {
Assert.isTrue(prjDescription.isReadOnly());
projectName = prjDescription.getName();
ICConfigurationDescription[] cfgDescriptions = prjDescription.getConfigurations();
for (ICConfigurationDescription cfgDescription : cfgDescriptions) {
if (cfgDescription instanceof IInternalCCfgInfo) {
CConfigurationSpecSettings specSettings = null;
try {
specSettings = ((IInternalCCfgInfo) cfgDescription).getSpecSettings();
} catch (CoreException e) {
CCorePlugin.log(e);
}
if (specSettings != null) {
LanguageSettingsDelta delta = specSettings.dropDelta();
if (delta != null)
deltaMap.put(cfgDescription.getId(), delta);
} else {
IStatus ss = new Status(IStatus.ERROR, CCorePlugin.PLUGIN_ID, "Internal error: Missing specSettings for " + cfgDescription.getClass().getSimpleName());
CCorePlugin.log(new Status(IStatus.ERROR, CCorePlugin.PLUGIN_ID, ss.getMessage(), new CoreException(ss)));
}
}
}
}
public String getProjectName() {
return projectName;
}
public String[] getConfigurationDescriptionIds() {
String[] ids = deltaMap.keySet().toArray(new String[deltaMap.size()]);
return ids;
}
public IResource[] getResources(String cfgDescriptionId) {
if (resources == null) {
LanguageSettingsDelta delta = deltaMap.get(cfgDescriptionId);
if (delta == null) {
resources = new IResource[0];
} else {
IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject(projectName);
ICProjectDescription prjDescription = CProjectDescriptionManager.getInstance().getProjectDescription(project, false);
ICConfigurationDescription cfgDescription = prjDescription.getDefaultSettingConfiguration();
resources = delta.getChangedResources(project, cfgDescription).toArray(new IResource[0]);
}
}
return resources;
}
@Override
public String toString() {
return "LanguageSettingsChangeEvent for project=[" + getProjectName() + "]"
+ ", configurations=" + deltaMap.keySet()
;
}
}
/** static initializer */ /** static initializer */
static { static {
@ -261,24 +344,66 @@ public class LanguageSettingsProvidersSerializer {
rawGlobalWorkspaceProviders = rawWorkspaceProviders; rawGlobalWorkspaceProviders = rawWorkspaceProviders;
} }
private static List<LanguageSettingsChangeEvent> createLanguageLettingsChangeEvents(List<LanguageSettingsSerializable> serializableProviders) {
List<LanguageSettingsChangeEvent> events = new ArrayList<LanguageSettingsProvidersSerializer.LanguageSettingsChangeEvent>();
List<String> serializableIds = new ArrayList<String>();
for (LanguageSettingsSerializable provider : serializableProviders) {
serializableIds.add(provider.getId());
}
IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
IProject[] projects = root.getProjects();
projects:
for (IProject project : projects) {
if (project.isAccessible()) {
ICProjectDescription prjDescription = CCorePlugin.getDefault().getProjectDescription(project, false);
if (prjDescription != null) {
ICConfigurationDescription[] cfgDescriptions = prjDescription.getConfigurations();
for (ICConfigurationDescription cfgDescription : cfgDescriptions) {
for (ILanguageSettingsProvider provider : cfgDescription.getLanguageSettingProviders()) {
if (isWorkspaceProvider(provider) && serializableIds.contains(provider.getId())) {
LanguageSettingsChangeEvent event = new LanguageSettingsChangeEvent(prjDescription);
if (event.getConfigurationDescriptionIds().length > 0) {
events.add(event);
}
continue projects;
}
}
}
}
}
}
return events;
}
public static void serializeLanguageSettingsWorkspace() throws CoreException { public static void serializeLanguageSettingsWorkspace() throws CoreException {
// AG TODO - remove the log
CCorePlugin.log(new Status(IStatus.WARNING, CCorePlugin.PLUGIN_ID, IStatus.OK,
"LanguageSettingsProvidersSerializer.serializeLanguageSettingsWorkspace()", new Exception()));
URI uriStoreWsp = getStoreInWorkspaceArea(STORAGE_WORKSPACE_LANGUAGE_SETTINGS); URI uriStoreWsp = getStoreInWorkspaceArea(STORAGE_WORKSPACE_LANGUAGE_SETTINGS);
List<LanguageSettingsSerializable> serializableExtensionProviders = new ArrayList<LanguageSettingsSerializable>(); List<LanguageSettingsSerializable> serializableWorkspaceProviders = new ArrayList<LanguageSettingsSerializable>();
for (ILanguageSettingsProvider provider : rawGlobalWorkspaceProviders.values()) { for (ILanguageSettingsProvider provider : rawGlobalWorkspaceProviders.values()) {
if (provider instanceof LanguageSettingsSerializable) { if (provider instanceof LanguageSettingsSerializable) {
// serialize all editable providers which are different from corresponding extension // 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) // 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)) { if (!(provider instanceof ILanguageSettingsEditableProvider) || !LanguageSettingsExtensionManager.equalsExtensionProvider(provider)) {
serializableExtensionProviders.add((LanguageSettingsSerializable)provider); serializableWorkspaceProviders.add((LanguageSettingsSerializable)provider);
} }
} }
} }
try { try {
if (serializableExtensionProviders.isEmpty()) { List<LanguageSettingsChangeEvent> events = null;
if (serializableWorkspaceProviders.isEmpty()) {
java.io.File fileStoreWsp = new java.io.File(uriStoreWsp); java.io.File fileStoreWsp = new java.io.File(uriStoreWsp);
serializingLock.acquire();
try { try {
serializingLock.acquire();
fileStoreWsp.delete(); fileStoreWsp.delete();
// manufacture events while inside the lock
events = createLanguageLettingsChangeEvents(serializableWorkspaceProviders);
} finally { } finally {
serializingLock.release(); serializingLock.release();
} }
@ -287,17 +412,23 @@ public class LanguageSettingsProvidersSerializer {
Element rootElement = XmlUtil.appendElement(doc, ELEM_PLUGIN); Element rootElement = XmlUtil.appendElement(doc, ELEM_PLUGIN);
Element elementExtension = XmlUtil.appendElement(rootElement, ELEM_EXTENSION, new String[] {ATTR_POINT, LanguageSettingsExtensionManager.PROVIDER_EXTENSION_FULL_ID}); Element elementExtension = XmlUtil.appendElement(rootElement, ELEM_EXTENSION, new String[] {ATTR_POINT, LanguageSettingsExtensionManager.PROVIDER_EXTENSION_FULL_ID});
for (LanguageSettingsSerializable provider : serializableExtensionProviders) { for (LanguageSettingsSerializable provider : serializableWorkspaceProviders) {
provider.serialize(elementExtension); provider.serialize(elementExtension);
} }
serializingLock.acquire();
try { try {
serializingLock.acquire();
XmlUtil.serializeXml(doc, uriStoreWsp); XmlUtil.serializeXml(doc, uriStoreWsp);
// manufacture events while inside the lock
events = createLanguageLettingsChangeEvents(serializableWorkspaceProviders);
} finally { } finally {
serializingLock.release(); serializingLock.release();
} }
} }
// notify the listeners outside the lock
for (LanguageSettingsChangeEvent event : events) {
notifyLanguageSettingsChangeListeners(event);
}
} catch (Exception e) { } catch (Exception e) {
CCorePlugin.log("Internal error while trying to serialize language settings", e); //$NON-NLS-1$ CCorePlugin.log("Internal error while trying to serialize language settings", e); //$NON-NLS-1$
@ -414,6 +545,10 @@ public class LanguageSettingsProvidersSerializer {
public static void serializeLanguageSettings(ICProjectDescription prjDescription) throws CoreException { public static void serializeLanguageSettings(ICProjectDescription prjDescription) throws CoreException {
IProject project = prjDescription.getProject(); IProject project = prjDescription.getProject();
// AG TODO - remove the log
CCorePlugin.log(new Status(IStatus.WARNING, CCorePlugin.PLUGIN_ID, IStatus.OK,
"LanguageSettingsProvidersSerializer.serializeLanguageSettings() for " + project, new Exception()));
try { try {
// Document to store in project area // Document to store in project area
Document docStorePrj = XmlUtil.newDocument(); Document docStorePrj = XmlUtil.newDocument();
@ -422,26 +557,37 @@ public class LanguageSettingsProvidersSerializer {
Document docStoreWsp = XmlUtil.newDocument(); Document docStoreWsp = XmlUtil.newDocument();
Element projectElementStoreWsp = XmlUtil.appendElement(docStoreWsp, ELEM_PROJECT); Element projectElementStoreWsp = XmlUtil.appendElement(docStoreWsp, ELEM_PROJECT);
serializeLanguageSettingsInternal(projectElementStorePrj, projectElementStoreWsp, prjDescription);
IFile fileStorePrj = getStoreInProjectArea(project);
// The project store should not be absent. Absent store means legacy project, not 0 providers. // The project store should not be absent. Absent store means legacy project, not 0 providers.
XmlUtil.serializeXml(docStorePrj, fileStorePrj); IFile fileStorePrj = getStoreInProjectArea(project);
URI uriStoreWsp = getStoreInWorkspaceArea(project.getName()+'.'+STORAGE_WORKSPACE_LANGUAGE_SETTINGS);
LanguageSettingsChangeEvent event = null;
URI uriStoreWsp = null;
boolean isWorkspaceStoreEmpty = projectElementStoreWsp.getChildNodes().getLength() == 0;
uriStoreWsp = getStoreInWorkspaceArea(project.getName()+'.'+STORAGE_WORKSPACE_LANGUAGE_SETTINGS);
serializingLock.acquire();
try { try {
serializingLock.acquire();
// Note that need for serialization may exist even if LSE event delta is empty,
// as number or properties of providers may differ
serializeLanguageSettingsInternal(projectElementStorePrj, projectElementStoreWsp, prjDescription);
XmlUtil.serializeXml(docStorePrj, fileStorePrj);
// project-specific location in workspace area // project-specific location in workspace area
boolean isWorkspaceStoreEmpty = projectElementStoreWsp.getChildNodes().getLength() == 0;
if (!isWorkspaceStoreEmpty) { if (!isWorkspaceStoreEmpty) {
XmlUtil.serializeXml(docStoreWsp, uriStoreWsp); XmlUtil.serializeXml(docStoreWsp, uriStoreWsp);
} else { } else {
new java.io.File(uriStoreWsp).delete(); new java.io.File(uriStoreWsp).delete();
} }
// manufacture the event only if serialization was successful
event = new LanguageSettingsChangeEvent(prjDescription);
} finally { } finally {
serializingLock.release(); serializingLock.release();
} }
// notify the listeners outside the lock
if (event.getConfigurationDescriptionIds().length > 0) {
notifyLanguageSettingsChangeListeners(event);
}
} catch (Exception e) { } catch (Exception e) {
IStatus s = new Status(IStatus.ERROR, CCorePlugin.PLUGIN_ID, "Internal error while trying to serialize language settings", e); IStatus s = new Status(IStatus.ERROR, CCorePlugin.PLUGIN_ID, "Internal error while trying to serialize language settings", e);
@ -510,8 +656,16 @@ public class LanguageSettingsProvidersSerializer {
} }
ICConfigurationDescription cfgDescription = prjDescription.getConfigurationById(cfgId); ICConfigurationDescription cfgDescription = prjDescription.getConfigurationById(cfgId);
if (cfgDescription!=null) if (cfgDescription!=null) {
cfgDescription.setLanguageSettingProviders(providers); cfgDescription.setLanguageSettingProviders(providers);
if (cfgDescription instanceof IInternalCCfgInfo) {
try {
((IInternalCCfgInfo) cfgDescription).getSpecSettings().dropDelta();
} catch (CoreException e) {
CCorePlugin.log(e);
}
}
}
} }
} }
@ -839,8 +993,9 @@ public class LanguageSettingsProvidersSerializer {
try { try {
provider = ((ILanguageSettingsEditableProvider) provider).clone(); provider = ((ILanguageSettingsEditableProvider) provider).clone();
} catch (CloneNotSupportedException e) { } catch (CloneNotSupportedException e) {
IStatus status = new Status(IStatus.ERROR, CCorePlugin.PLUGIN_ID, "Not able to clone provider " + provider.getClass()); IStatus status = new Status(IStatus.ERROR, CCorePlugin.PLUGIN_ID, Status.OK,
CCorePlugin.log(new CoreException(status)); "Not able to clone provider " + provider.getClass(), e);
CCorePlugin.log(status);
} }
} }
newProviders.add(provider); newProviders.add(provider);
@ -848,4 +1003,300 @@ public class LanguageSettingsProvidersSerializer {
return new ArrayList<ILanguageSettingsProvider>(newProviders); return new ArrayList<ILanguageSettingsProvider>(newProviders);
} }
/**
* Adds a listener that will be notified of changes in language settings.
*
* @param listener the ILanguageMappingChangeListener to add
*/
public static void registerLanguageSettingsChangeListener(ILanguageSettingsChangeListener listener) {
fLanguageSettingsChangeListeners.add(listener);
}
/**
* Removes a language settings change listener.
*
* @param listener the ILanguageMappingChangeListener to remove.
*/
public static void unregisterLanguageSettingsChangeListener(ILanguageSettingsChangeListener listener) {
fLanguageSettingsChangeListeners.remove(listener);
}
/**
* Notifies all language settings change listeners of a change.
*
* @param event the ILanguageSettingsChangeEvent event to be broadcast.
*/
public static void notifyLanguageSettingsChangeListeners(ILanguageSettingsChangeEvent event) {
// AG TODO - remove the log
CCorePlugin.log(new Status(IStatus.WARNING, CCorePlugin.PLUGIN_ID, IStatus.OK,
"Firing " + event, new Exception()));
Object[] listeners = fLanguageSettingsChangeListeners.getListeners();
for (Object obj : listeners) {
ILanguageSettingsChangeListener listener = (ILanguageSettingsChangeListener) obj;
listener.handleEvent(event);
}
}
private static List<ICLanguageSettingEntry> 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<ICLanguageSettingEntry>(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<ICLanguageSettingEntry> getSettingEntriesUpResourceTree(ILanguageSettingsProvider provider, ICConfigurationDescription cfgDescription, IResource rc, String languageId) {
Assert.isTrue( !(rc instanceof IWorkspaceRoot) );
if (provider!=null) {
List<ICLanguageSettingEntry> entries = safeGetSettingEntries(provider, cfgDescription, rc, languageId);
if (entries!=null) {
return new ArrayList<ICLanguageSettingEntry>(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<ICLanguageSettingEntry>(entries);
}
}
}
return new ArrayList<ICLanguageSettingEntry>(0);
}
/**
* Builds for the provider a nice looking resource tree to present hierarchical view to the user.
* Note that it is not advisable to "compact" the tree because of potential loss of information
* which is especially important during partial or incremental builds.
*
* @param provider - language settings provider to build the tree for.
* @param cfgDescription - configuration description.
* @param languageId - language ID.
* @param folder - container where the tree roots.
*/
public static void buildResourceTree(LanguageSettingsSerializable provider, ICConfigurationDescription cfgDescription, String languageId, IContainer folder) {
IResource[] members = null;
try {
members = folder.members();
} catch (Exception e) {
CCorePlugin.log(e);
}
if (members==null)
return;
for (IResource rc : members) {
if (rc instanceof IContainer) {
buildResourceTree(provider, cfgDescription, languageId, (IContainer) rc);
}
}
int rcNumber = members.length;
Map<List<ICLanguageSettingEntry>, Integer> listMap = new HashMap<List<ICLanguageSettingEntry>, Integer>();
// on the first pass find majority entries
List<ICLanguageSettingEntry> majorityEntries = null;
List<ICLanguageSettingEntry> candidate = null;
int candidateCount = 0;
for (IResource rc : members) {
if (!isLanguageInScope(rc, cfgDescription, languageId)) {
rcNumber--;
} else {
List<ICLanguageSettingEntry> entries = provider.getSettingEntries(null, rc, languageId);
if (entries==null && rc instanceof IContainer) {
rcNumber--;
} else {
Integer count = listMap.get(entries);
if (count==null) {
count = 0;
}
count++;
if (count>candidateCount) {
candidateCount = count;
candidate = entries;
}
listMap.put(entries, count);
}
}
if (candidateCount > rcNumber/2) {
majorityEntries = candidate;
break;
}
}
if (majorityEntries!=null) {
provider.setSettingEntries(cfgDescription, folder, languageId, majorityEntries);
}
// second pass - assign the entries to the folders
for (IResource rc : members) {
List<ICLanguageSettingEntry> entries = provider.getSettingEntries(null, rc, languageId);
if (entries!=null && entries==majorityEntries) {
if (!(rc instanceof IFile)) { // preserve information which files were collected
provider.setSettingEntries(cfgDescription, rc, languageId, null);
}
}
}
}
private static boolean isLanguageInScope(IResource rc, ICConfigurationDescription cfgDescription, String languageId) {
if (rc instanceof IFile) {
ILanguage lang = null;
try {
lang = LanguageManager.getInstance().getLanguageForFile((IFile) rc, cfgDescription);
} catch (CoreException e) {
CCorePlugin.log("Error loading language settings providers extensions", e); //$NON-NLS-1$
}
if (lang==null || (languageId!=null && !languageId.equals(lang.getId()))) {
return false;
}
}
return true;
}
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<ICLanguageSettingEntry> getSettingEntriesByKind(ICConfigurationDescription cfgDescription,
IResource rc, String languageId, int kind, boolean checkLocality, boolean isLocal) {
List<ICLanguageSettingEntry> entries = new ArrayList<ICLanguageSettingEntry>();
List<String> alreadyAdded = new ArrayList<String>();
List<ILanguageSettingsProvider> providers = cfgDescription.getLanguageSettingProviders();
for (ILanguageSettingsProvider provider: providers) {
List<ICLanguageSettingEntry> 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<ICLanguageSettingEntry> 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<ICLanguageSettingEntry> 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<ICLanguageSettingEntry> getLocalSettingEntriesByKind(ICConfigurationDescription cfgDescription, IResource rc, String languageId, int kind) {
return getSettingEntriesByKind(cfgDescription, rc, languageId, kind, /* checkLocality */ true, /* isLocal */ true);
}
} }

View file

@ -80,23 +80,23 @@ public class LanguageSettingsScannerInfoProvider implements IScannerInfoProvider
LinkedHashSet<ICLanguageSettingEntry> macroEntries = new LinkedHashSet<ICLanguageSettingEntry>(); LinkedHashSet<ICLanguageSettingEntry> macroEntries = new LinkedHashSet<ICLanguageSettingEntry>();
for (String langId : languageIds) { for (String langId : languageIds) {
List<ICLanguageSettingEntry> incSys = LanguageSettingsExtensionManager.getSystemSettingEntriesByKind(cfgDescription, rc, langId, List<ICLanguageSettingEntry> incSys = LanguageSettingsProvidersSerializer.getSystemSettingEntriesByKind(cfgDescription, rc, langId,
ICSettingEntry.INCLUDE_PATH); ICSettingEntry.INCLUDE_PATH);
includePathEntries.addAll(incSys); includePathEntries.addAll(incSys);
List<ICLanguageSettingEntry> incLocal = LanguageSettingsExtensionManager.getLocalSettingEntriesByKind(cfgDescription, rc, langId, List<ICLanguageSettingEntry> incLocal = LanguageSettingsProvidersSerializer.getLocalSettingEntriesByKind(cfgDescription, rc, langId,
ICSettingEntry.INCLUDE_PATH); ICSettingEntry.INCLUDE_PATH);
includePathLocalEntries.addAll(incLocal); includePathLocalEntries.addAll(incLocal);
List<ICLanguageSettingEntry> incFiles = LanguageSettingsExtensionManager.getSettingEntriesByKind(cfgDescription, rc, langId, List<ICLanguageSettingEntry> incFiles = LanguageSettingsProvidersSerializer.getSettingEntriesByKind(cfgDescription, rc, langId,
ICSettingEntry.INCLUDE_FILE); ICSettingEntry.INCLUDE_FILE);
includeFileEntries.addAll(incFiles); includeFileEntries.addAll(incFiles);
List<ICLanguageSettingEntry> macroFiles = LanguageSettingsExtensionManager.getSettingEntriesByKind(cfgDescription, rc, langId, List<ICLanguageSettingEntry> macroFiles = LanguageSettingsProvidersSerializer.getSettingEntriesByKind(cfgDescription, rc, langId,
ICSettingEntry.MACRO_FILE); ICSettingEntry.MACRO_FILE);
macroFileEntries.addAll(macroFiles); macroFileEntries.addAll(macroFiles);
List<ICLanguageSettingEntry> macros = LanguageSettingsExtensionManager.getSettingEntriesByKind(cfgDescription, rc, langId, List<ICLanguageSettingEntry> macros = LanguageSettingsProvidersSerializer.getSettingEntriesByKind(cfgDescription, rc, langId,
ICSettingEntry.MACRO); ICSettingEntry.MACRO);
macroEntries.addAll(macros); macroEntries.addAll(macros);
} }

View file

@ -0,0 +1,378 @@
package org.eclipse.cdt.internal.core.language.settings.providers;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
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.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.core.settings.model.util.LanguageSettingEntriesSerializer;
import org.eclipse.cdt.internal.core.XmlUtil;
import org.eclipse.cdt.internal.core.parser.util.WeakHashSet;
import org.eclipse.core.resources.IResource;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
public class LanguageSettingsStorage {
private static final String ELEM_LANGUAGE = "language"; //$NON-NLS-1$
private static final String ATTR_LANGUAGE_ID = "id"; //$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_VALUE = "value"; //$NON-NLS-1$
private static final String ELEM_FLAG = "flag"; //$NON-NLS-1$
/**
* Storage to keep settings entries. Note that it is not necessary to keep configuration in the maps
* as the configuration is always the one provider belongs to.
*/
private Map<String, // languageId
Map<String, // resource project path
List<ICLanguageSettingEntry>>> fStorage = new HashMap<String, Map<String, List<ICLanguageSettingEntry>>>();
/**
* Pool of LSE lists implemented as WeakHashSet. That allows to gain memory savings
* at the expense of CPU time. WeakHashSet handles garbage collection when a list is not
* referenced anywhere else. See JavaDoc {@link java.lang.ref.WeakReference} about weak reference objects.
*/
private static WeakHashSet<List<ICLanguageSettingEntry>> listPool = new WeakHashSet<List<ICLanguageSettingEntry>>() {
@Override
public synchronized List<ICLanguageSettingEntry> add(List<ICLanguageSettingEntry> list) {
return super.add(list);
}
};
/**
* <br> Note that this list is <b>unmodifiable</b>. To modify the list copy it, change and use
* {@link #setSettingEntries(ICConfigurationDescription, IResource, String, List)}.
*
*/
public List<ICLanguageSettingEntry> getSettingEntries(ICConfigurationDescription cfgDescription, IResource rc, String languageId) {
List<ICLanguageSettingEntry> entries = null;
Map<String, List<ICLanguageSettingEntry>> langMap = fStorage.get(languageId);
if (langMap!=null) {
String rcProjectPath = rc!=null ? rc.getProjectRelativePath().toString() : null;
entries = langMap.get(rcProjectPath);
}
return entries;
}
/**
* Some providers may collect entries in pretty much random order. For the purposes of
* predictability, UI usability and efficient storage the entries are sorted by kinds
* and secondary by name for kinds where the secondary order is not significant.
*
* @param entries - list of entries to sort.
* @return - sorted entries.
*/
private List<ICLanguageSettingEntry> sortEntries(List<ICLanguageSettingEntry> entries) {
List<ICLanguageSettingEntry> sortedEntries = new ArrayList<ICLanguageSettingEntry>(entries);
Collections.sort(sortedEntries, new Comparator<ICLanguageSettingEntry>(){
/**
* This comparator sorts by kinds first and the macros are sorted additionally by name.
*/
public int compare(ICLanguageSettingEntry entry0, ICLanguageSettingEntry entry1) {
int kind0 = entry0.getKind();
int kind1 = entry1.getKind();
if (kind0==ICSettingEntry.MACRO && kind1==ICSettingEntry.MACRO) {
return entry0.getName().compareTo(entry1.getName());
}
return kind0 - kind1;
}});
return sortedEntries;
}
/**
*
*/
public void setSettingEntries(String rcProjectPath, String languageId, List<ICLanguageSettingEntry> entries) {
synchronized (fStorage) {
if (entries!=null) {
Map<String, List<ICLanguageSettingEntry>> langMap = fStorage.get(languageId);
if (langMap==null) {
langMap = new HashMap<String, List<ICLanguageSettingEntry>>();
fStorage.put(languageId, langMap);
}
List<ICLanguageSettingEntry> sortedEntries = listPool.add(Collections.unmodifiableList(sortEntries(entries)));
langMap.put(rcProjectPath, sortedEntries);
} else {
// do not keep nulls in the tables
Map<String, List<ICLanguageSettingEntry>> langMap = fStorage.get(languageId);
if (langMap!=null) {
langMap.remove(rcProjectPath);
if (langMap.size()==0) {
fStorage.remove(languageId);
}
}
}
}
}
/**
* @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();
}
/**
* Clear all the entries for all configurations, all resources and all languages.
*/
public void clear() {
synchronized (fStorage) {
fStorage.clear();
}
}
/**
* Serialize the provider entries under parent XML element.
* @param elementProvider - element where to serialize the entries.
*/
public void serializeEntries(Element elementProvider) {
synchronized (fStorage) {
for (Entry<String, Map<String, List<ICLanguageSettingEntry>>> entryLang : fStorage.entrySet()) {
serializeLanguage(elementProvider, entryLang);
}
}
}
/**
* Serialize the provider entries for a given language list.
*/
private void serializeLanguage(Element parentElement, Entry<String, Map<String, List<ICLanguageSettingEntry>>> entryLang) {
String langId = entryLang.getKey();
if (langId!=null) {
Element elementLanguage = XmlUtil.appendElement(parentElement, ELEM_LANGUAGE, new String[] {ATTR_LANGUAGE_ID, langId});
parentElement = elementLanguage;
}
for (Entry<String, List<ICLanguageSettingEntry>> entryRc : entryLang.getValue().entrySet()) {
serializeResource(parentElement, entryRc);
}
}
/**
* Serialize the provider entries for a given resource list.
*/
private void serializeResource(Element parentElement, Entry<String, List<ICLanguageSettingEntry>> 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());
}
/**
* Serialize given settings entries.
*/
private void serializeSettingEntries(Element parentElement, List<ICLanguageSettingEntry> 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 may 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())
});
}
}
}
/**
* Load provider entries from XML provider element.
* @param providerNode - parent XML element <provider> where entries are defined.
*/
public void loadEntries(Element providerNode) {
List<ICLanguageSettingEntry> settings = new ArrayList<ICLanguageSettingEntry>();
NodeList nodes = providerNode.getChildNodes();
for (int i=0;i<nodes.getLength();i++) {
Node elementNode = nodes.item(i);
if(elementNode.getNodeType() != Node.ELEMENT_NODE)
continue;
if (ELEM_LANGUAGE.equals(elementNode.getNodeName())) {
loadLanguageElement(elementNode, null);
} else if (ELEM_RESOURCE.equals(elementNode.getNodeName())) {
loadResourceElement(elementNode, null, null);
} else if (ELEM_ENTRY.equals(elementNode.getNodeName())) {
ICLanguageSettingEntry entry = loadSettingEntry(elementNode);
if (entry!=null) {
settings.add(entry);
}
}
}
// set settings
if (settings.size()>0) {
setSettingEntries(null, null, settings);
}
}
/**
* Load a setting entry from XML element.
*/
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<flagNodes.getLength();i++) {
Node flagNode = flagNodes.item(i);
if(flagNode.getNodeType() != Node.ELEMENT_NODE || !ELEM_FLAG.equals(flagNode.getNodeName()))
continue;
String settingFlags = XmlUtil.determineAttributeValue(flagNode, ATTR_VALUE);
int bitFlag = LanguageSettingEntriesSerializer.composeFlags(settingFlags);
flags |= bitFlag;
}
String settingValue = null;
int kind = LanguageSettingEntriesSerializer.stringToKind(settingKind);
if (kind == ICSettingEntry.MACRO)
settingValue = XmlUtil.determineAttributeValue(parentElement, ATTR_VALUE);
ICLanguageSettingEntry entry = (ICLanguageSettingEntry) CDataUtil.createEntry(kind, settingName, settingValue, null, flags);
return entry;
}
/**
* Load entries defined in language element.
*/
private void loadLanguageElement(Node parentNode, String cfgId) {
String langId = XmlUtil.determineAttributeValue(parentNode, ATTR_LANGUAGE_ID);
if (langId.length()==0) {
langId=null;
}
List<ICLanguageSettingEntry> settings = new ArrayList<ICLanguageSettingEntry>();
NodeList nodes = parentNode.getChildNodes();
for (int i=0;i<nodes.getLength();i++) {
Node elementNode = nodes.item(i);
if(elementNode.getNodeType() != Node.ELEMENT_NODE)
continue;
if (ELEM_RESOURCE.equals(elementNode.getNodeName())) {
loadResourceElement(elementNode, cfgId, langId);
} else if (ELEM_ENTRY.equals(elementNode.getNodeName())) {
ICLanguageSettingEntry entry = loadSettingEntry(elementNode);
if (entry!=null) {
settings.add(entry);
}
}
}
// set settings
if (settings.size()>0) {
setSettingEntries(null, langId, settings);
}
}
/**
* Load entries defined in resource element.
*/
private void loadResourceElement(Node parentNode, String cfgId, String langId) {
String rcProjectPath = XmlUtil.determineAttributeValue(parentNode, ATTR_PROJECT_PATH);
List<ICLanguageSettingEntry> settings = new ArrayList<ICLanguageSettingEntry>();
NodeList nodes = parentNode.getChildNodes();
for (int i=0;i<nodes.getLength();i++) {
Node elementNode = nodes.item(i);
if(elementNode.getNodeType() != Node.ELEMENT_NODE)
continue;
if (ELEM_ENTRY.equals(elementNode.getNodeName())) {
ICLanguageSettingEntry entry = loadSettingEntry(elementNode);
if (entry!=null) {
settings.add(entry);
}
}
}
// set settings
if (settings.size()>0) {
setSettingEntries(rcProjectPath, langId, settings);
}
}
/**
* @noreference This method is not intended to be referenced by clients.
* Warning: but if you use it make sure you synchronize on it while traversing.
*/
Map<String, Map<String, List<ICLanguageSettingEntry>>> getMapInternal() {
return fStorage;
}
/**
* Clone storage for the entries. Copies references for lists of entries as a whole.
* Note that is OK as the lists kept in storage are unmodifiable.
*/
public LanguageSettingsStorage cloneStorage() {
LanguageSettingsStorage storageClone = new LanguageSettingsStorage();
synchronized (fStorage) {
Set<Entry<String, Map<String, List<ICLanguageSettingEntry>>>> entrySetLang = fStorage.entrySet();
for (Entry<String, Map<String, List<ICLanguageSettingEntry>>> entryLang : entrySetLang) {
String langId = entryLang.getKey();
Map<String, List<ICLanguageSettingEntry>> mapRc = entryLang.getValue();
Map<String, List<ICLanguageSettingEntry>> mapRcClone = new HashMap<String, List<ICLanguageSettingEntry>>();
Set<Entry<String, List<ICLanguageSettingEntry>>> entrySetRc = mapRc.entrySet();
for (Entry<String, List<ICLanguageSettingEntry>> entryRc : entrySetRc) {
String rcProjectPath = entryRc.getKey();
List<ICLanguageSettingEntry> lsEntries = entryRc.getValue();
// don't need to clone entries, they are from the LSE pool
mapRcClone.put(rcProjectPath, lsEntries);
}
storageClone.fStorage.put(langId, mapRcClone);
}
}
return storageClone;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((fStorage == null) ? 0 : fStorage.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
LanguageSettingsStorage other = (LanguageSettingsStorage) obj;
if (fStorage == null) {
if (other.fStorage != null)
return false;
} else if (!fStorage.equals(other.fStorage))
return false;
return true;
}
}

View file

@ -24,6 +24,8 @@ import java.util.Set;
import org.eclipse.cdt.core.CCorePlugin; import org.eclipse.cdt.core.CCorePlugin;
import org.eclipse.cdt.core.language.settings.providers.ILanguageSettingsProvider; 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.core.settings.model.CExternalSetting; import org.eclipse.cdt.core.settings.model.CExternalSetting;
import org.eclipse.cdt.core.settings.model.ICBuildSetting; import org.eclipse.cdt.core.settings.model.ICBuildSetting;
import org.eclipse.cdt.core.settings.model.ICConfigExtensionReference; import org.eclipse.cdt.core.settings.model.ICConfigExtensionReference;
@ -41,7 +43,9 @@ import org.eclipse.cdt.internal.core.COwner;
import org.eclipse.cdt.internal.core.COwnerConfiguration; import org.eclipse.cdt.internal.core.COwnerConfiguration;
import org.eclipse.cdt.internal.core.cdtvariables.StorableCdtVariables; import org.eclipse.cdt.internal.core.cdtvariables.StorableCdtVariables;
import org.eclipse.cdt.internal.core.envvar.EnvironmentVariableManager; import org.eclipse.cdt.internal.core.envvar.EnvironmentVariableManager;
import org.eclipse.cdt.internal.core.language.settings.providers.LanguageSettingsDelta;
import org.eclipse.cdt.internal.core.language.settings.providers.LanguageSettingsProvidersSerializer; import org.eclipse.cdt.internal.core.language.settings.providers.LanguageSettingsProvidersSerializer;
import org.eclipse.cdt.internal.core.language.settings.providers.LanguageSettingsStorage;
import org.eclipse.cdt.utils.envvar.StorableEnvironment; import org.eclipse.cdt.utils.envvar.StorableEnvironment;
import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.QualifiedName; import org.eclipse.core.runtime.QualifiedName;
@ -94,6 +98,8 @@ public class CConfigurationSpecSettings implements ICSettingsStorage{
// private Map fExternalSettingsProviderMap; // private Map fExternalSettingsProviderMap;
private List<ILanguageSettingsProvider> fLanguageSettingsProviders = new ArrayList<ILanguageSettingsProvider>(0); private List<ILanguageSettingsProvider> fLanguageSettingsProviders = new ArrayList<ILanguageSettingsProvider>(0);
private LinkedHashMap<String /*provider*/, LanguageSettingsStorage> lspPersistedState = new LinkedHashMap<String, LanguageSettingsStorage>();
private class DeltaSet { private class DeltaSet {
public Set<ICConfigExtensionReference> extSet; public Set<ICConfigExtensionReference> extSet;
@ -189,6 +195,10 @@ public class CConfigurationSpecSettings implements ICSettingsStorage{
copyExtensionInfo(base); copyExtensionInfo(base);
fLanguageSettingsProviders = LanguageSettingsProvidersSerializer.cloneProviders(base.getLanguageSettingProviders()); fLanguageSettingsProviders = LanguageSettingsProvidersSerializer.cloneProviders(base.getLanguageSettingProviders());
for (String providerId : base.lspPersistedState.keySet()) {
LanguageSettingsStorage clone = base.lspPersistedState.get(providerId).cloneStorage();
lspPersistedState.put(providerId, clone);
}
} }
// private void copyRefInfos(Map infosMap){ // private void copyRefInfos(Map infosMap){
@ -1011,4 +1021,40 @@ public class CConfigurationSpecSettings implements ICSettingsStorage{
public List<ILanguageSettingsProvider> getLanguageSettingProviders() { public List<ILanguageSettingsProvider> getLanguageSettingProviders() {
return Collections.unmodifiableList(fLanguageSettingsProviders); return Collections.unmodifiableList(fLanguageSettingsProviders);
} }
/**
* Returns delta and atomically updates last persisted state to the new state.
* That implies that the delta needs to be used to fire an event of it will
* be lost.
*/
public LanguageSettingsDelta dropDelta() {
LanguageSettingsDelta languageSettingsDelta = null;
// newState gets shallow map first
LinkedHashMap<String, LanguageSettingsStorage> newStateShallow = new LinkedHashMap<String, LanguageSettingsStorage>();
for (ILanguageSettingsProvider provider : fLanguageSettingsProviders) {
if (LanguageSettingsManager.isWorkspaceProvider(provider)) {
provider = LanguageSettingsManager.getRawProvider(provider);
}
if (provider instanceof LanguageSettingsSerializable) {
LanguageSettingsStorage store = ((LanguageSettingsSerializable) provider).getStorageInternal();
if (!store.isEmpty()) {
newStateShallow.put(provider.getId(), store);
}
}
}
if (!newStateShallow.equals(lspPersistedState)) {
// do deep copy if the state needs to be saved
LinkedHashMap<String, LanguageSettingsStorage> newStateDeep = new LinkedHashMap<String, LanguageSettingsStorage>();
for (Entry<String, LanguageSettingsStorage> entry : newStateShallow.entrySet()) {
String providerId = entry.getKey();
LanguageSettingsStorage store = entry.getValue();
newStateDeep.put(providerId, store.cloneStorage());
}
languageSettingsDelta = new LanguageSettingsDelta(lspPersistedState, newStateDeep);
lspPersistedState = newStateDeep;
}
return languageSettingsDelta;
}
} }

View file

@ -0,0 +1,77 @@
/*******************************************************************************
* 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.internal.core.pdom;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.cdt.core.CCorePlugin;
import org.eclipse.cdt.core.index.IIndexManager;
import org.eclipse.cdt.core.model.ICElement;
import org.eclipse.cdt.core.model.ICProject;
import org.eclipse.cdt.core.settings.model.ICConfigurationDescription;
import org.eclipse.cdt.core.settings.model.ICProjectDescription;
import org.eclipse.cdt.internal.core.language.settings.providers.ILanguageSettingsChangeEvent;
import org.eclipse.cdt.internal.core.language.settings.providers.ILanguageSettingsChangeListener;
import org.eclipse.cdt.internal.core.model.CModelManager;
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.IStatus;
import org.eclipse.core.runtime.Status;
/**
* This class handles changes in language settings for the PDOM by reindexing the appropriate resources.
*/
public class LanguageSettingsChangeListener implements ILanguageSettingsChangeListener {
private IIndexManager fManager;
public LanguageSettingsChangeListener(IIndexManager manager) {
fManager = manager;
}
public void handleEvent(ILanguageSettingsChangeEvent event) {
String projectName = event.getProjectName();
IWorkspaceRoot wspRoot = ResourcesPlugin.getWorkspace().getRoot();
IProject project = wspRoot.getProject(projectName);
ICProjectDescription prjDescription = CCorePlugin.getDefault().getProjectDescription(project);
ICConfigurationDescription indexedCfgDescription = prjDescription.getDefaultSettingConfiguration();
CModelManager manager = CModelManager.getDefault();
IResource[] resources = event.getResources(indexedCfgDescription.getId());
if (resources.length > 0) {
ICProject cProject = manager.getCModel().getCProject(project);
List<ICElement> elements = new ArrayList<ICElement>();
for (IResource rc : resources) {
// AG TODO - remove the log
CCorePlugin.log(new Status(IStatus.WARNING, CCorePlugin.PLUGIN_ID,
"LanguageSettingsChangeListener"+"["+System.identityHashCode(this)+"]"+".handleEvent() for " + rc, new Exception()));
elements.add(manager.create(rc, cProject));
}
try {
fManager.update(elements.toArray(new ICElement[elements.size()]), IIndexManager.UPDATE_ALL);
} catch (CoreException e) {
CCorePlugin.log(e);
}
}
}
}

View file

@ -60,6 +60,7 @@ import org.eclipse.cdt.core.model.ITranslationUnit;
import org.eclipse.cdt.core.model.LanguageManager; import org.eclipse.cdt.core.model.LanguageManager;
import org.eclipse.cdt.core.settings.model.CProjectDescriptionEvent; import org.eclipse.cdt.core.settings.model.CProjectDescriptionEvent;
import org.eclipse.cdt.core.settings.model.ICProjectDescriptionListener; import org.eclipse.cdt.core.settings.model.ICProjectDescriptionListener;
import org.eclipse.cdt.core.settings.model.util.LanguageSettingEntriesSerializer;
import org.eclipse.cdt.internal.core.CCoreInternals; import org.eclipse.cdt.internal.core.CCoreInternals;
import org.eclipse.cdt.internal.core.index.IIndexFragment; import org.eclipse.cdt.internal.core.index.IIndexFragment;
import org.eclipse.cdt.internal.core.index.IWritableIndex; import org.eclipse.cdt.internal.core.index.IWritableIndex;
@ -68,6 +69,7 @@ import org.eclipse.cdt.internal.core.index.IndexChangeEvent;
import org.eclipse.cdt.internal.core.index.IndexFactory; import org.eclipse.cdt.internal.core.index.IndexFactory;
import org.eclipse.cdt.internal.core.index.IndexerStateEvent; import org.eclipse.cdt.internal.core.index.IndexerStateEvent;
import org.eclipse.cdt.internal.core.index.provider.IndexProviderManager; import org.eclipse.cdt.internal.core.index.provider.IndexProviderManager;
import org.eclipse.cdt.internal.core.language.settings.providers.LanguageSettingsProvidersSerializer;
import org.eclipse.cdt.internal.core.pdom.PDOM.IListener; import org.eclipse.cdt.internal.core.pdom.PDOM.IListener;
import org.eclipse.cdt.internal.core.pdom.db.ChunkCache; import org.eclipse.cdt.internal.core.pdom.db.ChunkCache;
import org.eclipse.cdt.internal.core.pdom.dom.IPDOMLinkageFactory; import org.eclipse.cdt.internal.core.pdom.dom.IPDOMLinkageFactory;
@ -163,6 +165,7 @@ public class PDOMManager implements IWritableIndexManager, IListener {
private CModelListener fCModelListener= new CModelListener(this); private CModelListener fCModelListener= new CModelListener(this);
private ILanguageMappingChangeListener fLanguageChangeListener = new LanguageMappingChangeListener(this); private ILanguageMappingChangeListener fLanguageChangeListener = new LanguageMappingChangeListener(this);
private LanguageSettingsChangeListener fLanguageSettingsChangeListener = new LanguageSettingsChangeListener(this);
private final ICProjectDescriptionListener fProjectDescriptionListener; private final ICProjectDescriptionListener fProjectDescriptionListener;
private final JobChangeListener fJobChangeListener; private final JobChangeListener fJobChangeListener;
private final IPreferenceChangeListener fPreferenceChangeListener; private final IPreferenceChangeListener fPreferenceChangeListener;
@ -235,6 +238,7 @@ public class PDOMManager implements IWritableIndexManager, IListener {
ResourcesPlugin.getWorkspace().addResourceChangeListener(fCModelListener, IResourceChangeEvent.POST_BUILD); ResourcesPlugin.getWorkspace().addResourceChangeListener(fCModelListener, IResourceChangeEvent.POST_BUILD);
model.addElementChangedListener(fCModelListener); model.addElementChangedListener(fCModelListener);
LanguageManager.getInstance().registerLanguageChangeListener(fLanguageChangeListener); LanguageManager.getInstance().registerLanguageChangeListener(fLanguageChangeListener);
LanguageSettingsProvidersSerializer.registerLanguageSettingsChangeListener(fLanguageSettingsChangeListener);
final int types= CProjectDescriptionEvent.DATA_APPLIED; final int types= CProjectDescriptionEvent.DATA_APPLIED;
CCorePlugin.getDefault().getProjectDescriptionManager().addCProjectDescriptionListener(fProjectDescriptionListener, types); CCorePlugin.getDefault().getProjectDescriptionManager().addCProjectDescriptionListener(fProjectDescriptionListener, types);
@ -255,6 +259,7 @@ public class PDOMManager implements IWritableIndexManager, IListener {
final CoreModel model = CoreModel.getDefault(); final CoreModel model = CoreModel.getDefault();
model.removeElementChangedListener(fCModelListener); model.removeElementChangedListener(fCModelListener);
ResourcesPlugin.getWorkspace().removeResourceChangeListener(fCModelListener); ResourcesPlugin.getWorkspace().removeResourceChangeListener(fCModelListener);
LanguageSettingsProvidersSerializer.unregisterLanguageSettingsChangeListener(fLanguageSettingsChangeListener);
LanguageManager.getInstance().unregisterLanguageChangeListener(fLanguageChangeListener); LanguageManager.getInstance().unregisterLanguageChangeListener(fLanguageChangeListener);
PDOMIndexerJob jobToCancel= null; PDOMIndexerJob jobToCancel= null;
synchronized (fTaskQueue) { synchronized (fTaskQueue) {

View file

@ -21,7 +21,6 @@ import java.util.Map;
import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.Status;
import org.eclipse.jface.viewers.IDecoration; import org.eclipse.jface.viewers.IDecoration;
@ -47,7 +46,6 @@ import org.eclipse.cdt.core.language.settings.providers.ILanguageSettingsEditabl
import org.eclipse.cdt.core.language.settings.providers.ILanguageSettingsProvider; 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.LanguageSettingsBaseProvider;
import org.eclipse.cdt.core.language.settings.providers.LanguageSettingsManager; 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.language.settings.providers.LanguageSettingsSerializable;
import org.eclipse.cdt.core.language.settings.providers.ScannerDiscoveryLegacySupport; import org.eclipse.cdt.core.language.settings.providers.ScannerDiscoveryLegacySupport;
import org.eclipse.cdt.core.model.ILanguage; import org.eclipse.cdt.core.model.ILanguage;
@ -1020,14 +1018,6 @@ providers: for (ILanguageSettingsProvider provider : providers) {
enableProvidersCheckBox.setSelection(enabled); enableProvidersCheckBox.setSelection(enabled);
} }
try {
LanguageSettingsManager_TBD.serializeWorkspaceProviders();
} catch (CoreException e) {
// TODO Auto-generated catch block
e.printStackTrace();
throw new UnsupportedOperationException("Internal Error");
}
trackInitialSettings(); trackInitialSettings();
updateData(getResDesc()); updateData(getResDesc());
} }
@ -1063,19 +1053,4 @@ providers: for (ILanguageSettingsProvider provider : providers) {
provider.setSettingEntries(cfgDescription, rc, currentLanguageId, entries); provider.setSettingEntries(cfgDescription, rc, currentLanguageId, entries);
} }
@Override
protected boolean isIndexerAffected() {
// List<ILanguageSettingsProvider> 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;
}
} }

View file

@ -51,14 +51,8 @@ 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.LanguageSettingsManager_TBD;
import org.eclipse.cdt.core.language.settings.providers.LanguageSettingsSerializable; import org.eclipse.cdt.core.language.settings.providers.LanguageSettingsSerializable;
import org.eclipse.cdt.core.language.settings.providers.ScannerDiscoveryLegacySupport; import org.eclipse.cdt.core.language.settings.providers.ScannerDiscoveryLegacySupport;
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.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.ICResourceDescription;
import org.eclipse.cdt.core.settings.model.ICSettingBase;
import org.eclipse.cdt.ui.CDTSharedImages; import org.eclipse.cdt.ui.CDTSharedImages;
import org.eclipse.cdt.ui.CUIPlugin; import org.eclipse.cdt.ui.CUIPlugin;
import org.eclipse.cdt.ui.dialogs.ICOptionPage; import org.eclipse.cdt.ui.dialogs.ICOptionPage;
@ -66,7 +60,6 @@ import org.eclipse.cdt.ui.newui.AbstractCPropertyTab;
import org.eclipse.cdt.ui.newui.CDTPrefUtil; import org.eclipse.cdt.ui.newui.CDTPrefUtil;
import org.eclipse.cdt.utils.ui.controls.TabFolderLayout; import org.eclipse.cdt.utils.ui.controls.TabFolderLayout;
import org.eclipse.cdt.internal.ui.newui.Messages; import org.eclipse.cdt.internal.ui.newui.Messages;
import org.eclipse.cdt.internal.ui.newui.StatusMessageLine; import org.eclipse.cdt.internal.ui.newui.StatusMessageLine;
@ -983,13 +976,6 @@ public class LanguageSettingsProviderTab extends AbstractCPropertyTab {
} }
} }
try {
LanguageSettingsManager_TBD.serializeWorkspaceProviders();
} catch (CoreException e) {
CUIPlugin.log("Internal Error", e);
throw new UnsupportedOperationException("Internal Error");
}
trackInitialSettings(); trackInitialSettings();
updateData(getResDesc()); updateData(getResDesc());
} }
@ -1002,21 +988,6 @@ public class LanguageSettingsProviderTab extends AbstractCPropertyTab {
return page.isForPrefs() || page.isForProject(); return page.isForPrefs() || page.isForProject();
} }
@Override
protected boolean isIndexerAffected() {
List<ILanguageSettingsProvider> newProvidersList = null;
ICConfigurationDescription cfgDescription = getConfigurationDescription();
if (cfgDescription!=null) {
newProvidersList = cfgDescription.getLanguageSettingProviders();
}
boolean newEnablement = ScannerDiscoveryLegacySupport.isLanguageSettingsProvidersFunctionalityEnabled(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<ILanguageSettingsProvider> providers) { private ILanguageSettingsProvider findRawProvider(String id, List<ILanguageSettingsProvider> providers) {
for (ILanguageSettingsProvider provider : providers) { for (ILanguageSettingsProvider provider : providers) {
if (provider.getId().equals(id)) { if (provider.getId().equals(id)) {