blob: 827704c354b8a1ba27800419b4310b76b0d77c9c [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2006, 2014 Wind River Systems, Inc. and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Markus Schorn - initial API and implementation
*******************************************************************************/
package org.eclipse.cdt.internal.core;
import org.eclipse.cdt.core.CCorePlugin;
import org.eclipse.cdt.core.model.CoreModel;
import org.eclipse.cdt.internal.core.pdom.indexer.IndexerPreferences;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.ProjectScope;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.content.IContentType;
import org.eclipse.core.runtime.content.IContentTypeMatcher;
import org.eclipse.core.runtime.content.IContentTypeSettings;
import org.eclipse.core.runtime.preferences.IScopeContext;
import org.osgi.service.prefs.BackingStoreException;
import org.osgi.service.prefs.Preferences;
/**
* Handles the access to the content types of the platform.
* @author markus.schorn@windriver.com
*/
public class CContentTypes {
private static final String PREF_LOCAL_CONTENT_TYPE_SETTINGS = "enabled"; //$NON-NLS-1$
private static final Preferences PROJECT_SCOPE = Platform.getPreferencesService().getRootNode().node(ProjectScope.SCOPE);
private static final String CONTENT_TYPE_PREF_NODE = "content-types"; //$NON-NLS-1$
private static final String FULLPATH_CONTENT_TYPE_PREF_NODE = Platform.PI_RUNTIME + IPath.SEPARATOR + CONTENT_TYPE_PREF_NODE;
/**
* Implementation for {@link CCorePlugin#getContentType(IProject, String)}.
*/
public static IContentType getContentType(IProject project, String filename) {
if (filename == null) {
return null;
}
IContentTypeMatcher matcher= null;
IScopeContext scopeCtx= null;
boolean preferCpp= true;
if (project != null) {
// try with the project settings
try {
matcher= project.getContentTypeMatcher();
if (usesProjectSpecificContentTypes(project)) {
scopeCtx= new ProjectScope(project);
}
if (CoreModel.hasCNature(project)) {
preferCpp= CoreModel.hasCCNature(project) == IndexerPreferences.preferDefaultLanguage(project);
}
} catch (CoreException e) {
// fallback to workspace wide definitions.
matcher= Platform.getContentTypeManager();
}
} else {
matcher= Platform.getContentTypeManager();
}
IContentType[] cts = matcher.findContentTypesFor(filename);
switch (cts.length) {
case 0:
return null;
case 1:
return cts[0];
}
int maxPossiblePriority= scopeCtx == null ? 11 : 101;
int bestPriority= -1;
IContentType bestResult= null;
for (int i = 0; i < cts.length; i++) {
IContentType candidate= cts[i];
int priority= 0;
try {
if (scopeCtx != null) {
IContentTypeSettings settings= candidate.getSettings(scopeCtx);
if (isStrictlyAssociatedWith(settings, filename)) {
priority= 100;
}
}
if (priority == 0 && bestPriority < 100) {
if (isStrictlyAssociatedWith(candidate, filename)) {
priority= 10;
}
}
if (isPreferredContentType(candidate, preferCpp)) {
priority+= 1;
}
} catch (CoreException e) {
// skip it
}
if (priority > bestPriority) {
if (priority == maxPossiblePriority) {
return candidate;
}
bestPriority= priority;
bestResult= candidate;
}
}
return bestResult;
}
private static boolean isPreferredContentType(IContentType candidate, boolean preferCpp) {
while (candidate != null) {
String id= candidate.getId();
if (CCorePlugin.CONTENT_TYPE_CXXHEADER.equals(id) ||
CCorePlugin.CONTENT_TYPE_CXXSOURCE.equals(id)) {
return preferCpp;
}
if (CCorePlugin.CONTENT_TYPE_CHEADER.equals(id) ||
CCorePlugin.CONTENT_TYPE_CSOURCE.equals(id)) {
return !preferCpp;
}
candidate= candidate.getBaseType();
}
return false;
}
private static boolean isStrictlyAssociatedWith(IContentTypeSettings settings, String filename) {
String[] namespecs= settings.getFileSpecs(IContentType.FILE_NAME_SPEC);
for (int i = 0; i < namespecs.length; i++) {
String name = namespecs[i];
if (name.equals(filename)) {
return true;
}
}
// check the file extensions only
int dotPosition = filename.lastIndexOf('.');
if (dotPosition >= 0 && dotPosition < filename.length()-1) {
String fileExtension= filename.substring(dotPosition + 1);
String[] extensions= settings.getFileSpecs(IContentType.FILE_EXTENSION_SPEC);
for (int i = 0; i < extensions.length; i++) {
String ext = extensions[i];
if (ext.equals(fileExtension)) {
return true;
}
}
}
return false;
}
/**
* This method is copied from the resources plugin and figures out whether
* project specific settings are enabled or not.
* Implementation for {@link CCorePlugin#usesProjectSpecificContentTypes(IProject)}.
*/
public static boolean usesProjectSpecificContentTypes(IProject project) {
String projectName= project.getName();
try {
// be careful looking up for our node so not to create any nodes as side effect
Preferences node = PROJECT_SCOPE;
//TODO once bug 90500 is fixed, should be simpler
// for now, take the long way
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) {
// exception treated when retrieving the project preferences
}
return false;
}
/**
* Implementation for {@link CCorePlugin#setUseProjectSpecificContentTypes(IProject, boolean)}.
*/
public static void setUseProjectSpecificContentTypes(IProject project, boolean val) {
ProjectScope projectScope = new ProjectScope(project);
Preferences contentTypePrefs = projectScope.getNode(FULLPATH_CONTENT_TYPE_PREF_NODE);
if (usesProjectSpecificContentTypes(project) != val) {
// enable project-specific settings for this project
contentTypePrefs.putBoolean(PREF_LOCAL_CONTENT_TYPE_SETTINGS, val);
try {
contentTypePrefs.flush();
} catch (BackingStoreException e) {
// ignore ??
}
}
}
}