package org.eclipse.core.internal.resources;
import java.util.*;
import org.eclipse.core.internal.utils.Cache;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.ProjectScope;
import org.eclipse.core.runtime.*;
import org.eclipse.core.runtime.content.IContentType;
import org.eclipse.core.runtime.content.IContentTypeManager.ISelectionPolicy;
import org.eclipse.core.runtime.content.IContentTypeMatcher;
import org.eclipse.core.runtime.preferences.*;
import org.osgi.service.prefs.BackingStoreException;
import org.osgi.service.prefs.Preferences;
public class ProjectContentTypes {
private class ProjectContentTypeSelectionPolicy implements ISelectionPolicy, IScopeContext {
private Project project;
private IScopeContext projectScope;
public ProjectContentTypeSelectionPolicy(Project project) {
this.project = project;
this.projectScope = new ProjectScope(project);
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (!(obj instanceof IScopeContext))
return false;
IScopeContext other = (IScopeContext) obj;
if (!getName().equals(other.getName()))
return false;
IPath location = getLocation();
return location == null ? other.getLocation() == null : location.equals(other.getLocation());
}
private IScopeContext getDelegate() {
if (!usesContentTypePreferences(project.getName()))
return InstanceScope.INSTANCE;
return projectScope;
}
@Override
public IPath getLocation() {
return getDelegate().getLocation();
}
@Override
public String getName() {
return getDelegate().getName();
}
@Override
public IEclipsePreferences getNode(String qualifier) {
return getDelegate().getNode(qualifier);
}
@Override
public int hashCode() {
return getName().hashCode();
}
@Override
public IContentType[] select(IContentType[] candidates, boolean fileName, boolean content) {
return ProjectContentTypes.this.select(project, candidates, fileName, content);
}
}
private static final String CONTENT_TYPE_PREF_NODE = "content-types";
private static final String PREF_LOCAL_CONTENT_TYPE_SETTINGS = "enabled";
private static final Preferences PROJECT_SCOPE = Platform.getPreferencesService().getRootNode().node(ProjectScope.SCOPE);
private Cache contentTypesPerProject;
private Workspace workspace;
static boolean usesContentTypePreferences(String projectName) {
try {
Preferences node = PROJECT_SCOPE;
if (!node.nodeExists(projectName))
return false;
node = node.node(projectName);
if (!node.nodeExists(Platform.PI_RUNTIME))
return false;
node = node.node(Platform.PI_RUNTIME);
if (!node.nodeExists(CONTENT_TYPE_PREF_NODE))
return false;
node = node.node(CONTENT_TYPE_PREF_NODE);
return node.getBoolean(PREF_LOCAL_CONTENT_TYPE_SETTINGS, false);
} catch (BackingStoreException e) {
}
return false;
}
public ProjectContentTypes(Workspace workspace) {
this.workspace = workspace;
this.contentTypesPerProject = new Cache(5, 30, 0.4);
}
private Set<String> collectAssociatedContentTypes(Project project) {
String[] enabledNatures = workspace.getNatureManager().getEnabledNatures(project);
if (enabledNatures.length == 0)
return Collections.EMPTY_SET;
Set<String> related = new HashSet<>(enabledNatures.length);
for (String enabledNature : enabledNatures) {
ProjectNatureDescriptor descriptor = (ProjectNatureDescriptor) workspace.getNatureDescriptor(enabledNature);
if (descriptor == null)
continue;
String[] natureContentTypes = descriptor.getContentTypeIds();
related.addAll(Arrays.asList(natureContentTypes));
}
return related;
}
public void contentTypePreferencesChanged(IProject project) {
final ProjectInfo info = (ProjectInfo) ((Project) project).getResourceInfo(false, false);
if (info != null)
info.setMatcher(null);
}
private IContentTypeMatcher createMatcher(Project project) {
ProjectContentTypeSelectionPolicy projectContentTypeSelectionPolicy = new ProjectContentTypeSelectionPolicy(project);
return Platform.getContentTypeManager().getMatcher(projectContentTypeSelectionPolicy, projectContentTypeSelectionPolicy);
}
@SuppressWarnings({"unchecked"})
private Set<String> getAssociatedContentTypes(Project project) {
final ResourceInfo info = project.getResourceInfo(false, false);
if (info == null)
return null;
final String projectName = project.getName();
synchronized (contentTypesPerProject) {
Cache.Entry entry = contentTypesPerProject.getEntry(projectName);
if (entry != null)
if (entry.getTimestamp() == info.getContentId())
return (Set<String>) entry.getCached();
Set<String> result = collectAssociatedContentTypes(project);
if (entry == null)
entry = contentTypesPerProject.addEntry(projectName, result, info.getContentId());
else {
entry.setTimestamp(info.getContentId());
entry.setCached(result);
}
return result;
}
}
public IContentTypeMatcher getMatcherFor(Project project) throws CoreException {
ProjectInfo info = (ProjectInfo) project.getResourceInfo(false, false);
if (info == null)
project.checkAccessible(project.getFlags(null));
IContentTypeMatcher matcher = info.getMatcher();
if (matcher != null)
return matcher;
matcher = createMatcher(project);
info.setMatcher(matcher);
return matcher;
}
final IContentType[] select(Project project, IContentType[] candidates, boolean fileName, boolean content) {
if (candidates.length < 2)
return candidates;
final Set<String> associated = getAssociatedContentTypes(project);
if (associated == null || associated.isEmpty())
return candidates;
int associatedCount = 0;
for (int i = 0; i < candidates.length; i++)
if (associated.contains(candidates[i].getId())) {
if (associatedCount < i) {
final IContentType promoted = candidates[i];
for (int j = i; j > associatedCount; j--)
candidates[j] = candidates[j - 1];
candidates[associatedCount] = promoted;
}
associatedCount++;
}
return candidates;
}
}