| /******************************************************************************* |
| * 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 ?? |
| } |
| } |
| } |
| } |