/******************************************************************************* * Copyright (c) 2007, 2016 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 * Sergey Prigogin (Google) * Anton Gorenkov - Enable the "Index unused headers" preference by default (Bug 377992) * IBM Corporation * Marc-Andre Laperle (Ericsson) *******************************************************************************/ package org.eclipse.cdt.internal.core.pdom.indexer; import java.util.Map; import java.util.Properties; import org.eclipse.cdt.core.CCorePlugin; import org.eclipse.cdt.core.dom.IPDOMManager; import org.eclipse.cdt.internal.core.CCoreInternals; import org.eclipse.cdt.internal.core.LocalProjectScope; import org.eclipse.cdt.internal.core.pdom.IndexUpdatePolicy; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.ProjectScope; import org.eclipse.core.runtime.Platform; import org.eclipse.core.runtime.preferences.ConfigurationScope; import org.eclipse.core.runtime.preferences.DefaultScope; import org.eclipse.core.runtime.preferences.IEclipsePreferences; import org.eclipse.core.runtime.preferences.IEclipsePreferences.IPreferenceChangeListener; import org.eclipse.core.runtime.preferences.IPreferencesService; import org.eclipse.core.runtime.preferences.InstanceScope; import org.osgi.service.prefs.BackingStoreException; import org.osgi.service.prefs.Preferences; /** * Access to indexer properties. * @since 4.0 */ public class IndexerPreferences { public static final int SCOPE_INSTANCE = 0; public static final int SCOPE_PROJECT_PRIVATE = 1; public static final int SCOPE_PROJECT_SHARED = 2; public static final int UPDATE_POLICY_IMMEDIATE= 0; public static final int UPDATE_POLICY_LAZY= 1; public static final int UPDATE_POLICY_MANUAL= 2; public static final String KEY_INDEXER_ID= "indexerId"; //$NON-NLS-1$ public static final String KEY_INDEX_ALL_FILES= "indexAllFiles"; //$NON-NLS-1$ public static final String KEY_INDEX_UNUSED_HEADERS_WITH_DEFAULT_LANG= "indexUnusedHeadersWithDefaultLang"; //$NON-NLS-1$ public static final String KEY_INDEX_UNUSED_HEADERS_WITH_ALTERNATE_LANG= "indexUnusedHeadersWithAlternateLang"; //$NON-NLS-1$ public static final String KEY_INDEX_ON_OPEN= "indexOnOpen"; //$NON-NLS-1$ public static final String KEY_INCLUDE_HEURISTICS= "useHeuristicIncludeResolution"; //$NON-NLS-1$ public static final String KEY_SKIP_ALL_REFERENCES= "skipReferences"; //$NON-NLS-1$ public static final String KEY_SKIP_IMPLICIT_REFERENCES= "skipImplicitReferences"; //$NON-NLS-1$ public static final String KEY_SKIP_TYPE_REFERENCES= "skipTypeReferences"; //$NON-NLS-1$ public static final String KEY_SKIP_MACRO_REFERENCES= "skipMacroReferences"; //$NON-NLS-1$ public static final String KEY_UPDATE_POLICY= "updatePolicy"; //$NON-NLS-1$ public static final String KEY_SKIP_FILES_LARGER_THAN_MB = "skipFilesLargerThanMB"; //$NON-NLS-1$ public static final String KEY_SKIP_INCLUDED_FILES_LARGER_THAN_MB = "skipIncludedFilesLargerThanMB"; //$NON-NLS-1$ private static final String KEY_INDEXER_PREFS_SCOPE = "preferenceScope"; //$NON-NLS-1$ private static final String KEY_INDEX_IMPORT_LOCATION = "indexImportLocation"; //$NON-NLS-1$ public static final String KEY_REINDEX_ON_CONFIG_CHANGE = "reindexOnConfigChange"; //$NON-NLS-1$ public static final String KEY_REINDEX_ON_INDEXER_CHANGE = "reindexOnIndexerChange"; //$NON-NLS-1$ public static final String KEY_INDEX_ALL_HEADER_VERSIONS= "indexAllHeaderVersions"; //$NON-NLS-1$ public static final String KEY_INDEX_ALL_VERSIONS_SPECIFIC_HEADERS= "indexAllVersionsSpecificHeaders"; //$NON-NLS-1$ private static final String DEFAULT_INDEX_IMPORT_LOCATION = ".settings/cdt-index.zip"; //$NON-NLS-1$ private static final int DEFAULT_UPDATE_POLICY= 0; public static final int DEFAULT_FILE_SIZE_LIMIT_MB = 8; public static final int DEFAULT_INCLUDED_FILE_SIZE_LIMIT_MB = 16; private static final String QUALIFIER = CCorePlugin.PLUGIN_ID; private static final String INDEXER_NODE = "indexer"; //$NON-NLS-1$ /** * Returns the scope that is selected for the project. * @param project * @return one of {@link #SCOPE_INSTANCE}, {@link #SCOPE_PROJECT_SHARED} or * {@link #SCOPE_PROJECT_PRIVATE}. */ public static int getScope(IProject project) { int scope= SCOPE_INSTANCE; if (project != null) { Preferences ppp= getLocalPreferences(project); scope= ppp.getInt(KEY_INDEXER_PREFS_SCOPE, -1); if (scope == -1) { scope= determineScopeOnFirstUse(project); } if (scope != SCOPE_INSTANCE) { if (get(project, scope, KEY_INDEXER_ID, null) == null) { scope= SCOPE_INSTANCE; ppp.putInt(KEY_INDEXER_PREFS_SCOPE, scope); CCoreInternals.savePreferences(project, false); } } } return scope; } /** * Sets the scope that shall be used for the project. * Must be one of {@link #SCOPE_INSTANCE}, {@link #SCOPE_PROJECT_SHARED} or * {@link #SCOPE_PROJECT_PRIVATE}. */ public static int setScope(IProject project, int scope) { if (project == null) throw new IllegalArgumentException(); boolean makeCopy= false; switch (scope) { case SCOPE_INSTANCE: break; case SCOPE_PROJECT_PRIVATE: case SCOPE_PROJECT_SHARED: makeCopy= true; break; default: throw new IllegalArgumentException(); } if (makeCopy) { Preferences[] prefs= getPreferences(project, scope); if (prefs[0].get(KEY_INDEXER_ID, null) == null) { Preferences ppp= getLocalPreferences(project); int oldScope= ppp.getInt(KEY_INDEXER_PREFS_SCOPE, SCOPE_INSTANCE); Properties props= getProperties(project, oldScope); setProperties(prefs[0], props); } } Preferences ppp= getLocalPreferences(project); ppp.putInt(KEY_INDEXER_PREFS_SCOPE, scope); return scope; } /** * Sets the scope that shall be used for the project. * Must be one of {@link #UPDATE_POLICY_IMMEDIATE}, {@link #UPDATE_POLICY_LAZY} or * {@link #UPDATE_POLICY_MANUAL}. */ public static void setUpdatePolicy(IProject project, int policy) { switch (policy) { case UPDATE_POLICY_IMMEDIATE: case UPDATE_POLICY_LAZY: case UPDATE_POLICY_MANUAL: break; default: throw new IllegalArgumentException(); } // no support for project specific policies. getInstancePreferences().put(KEY_UPDATE_POLICY, String.valueOf(policy)); } /** * Returns the properties for the indexer of a project. */ public static Properties getProperties(IProject project) { return getProperties(project, getScope(project)); } /** * Returns the properties for the indexer of a project for a * specific scope. */ public static Properties getProperties(IProject project, int scope) { Preferences[] prefs= getPreferences(project, scope); Properties props= new Properties(); for (int i= 0; i < prefs.length; i++) { readProperties(prefs[i], props); if (i == 0) { migrateProperties(props); } } return props; } private static void migrateProperties(Properties props) { if (props.get(KEY_INDEX_UNUSED_HEADERS_WITH_DEFAULT_LANG) == null) { // backward compatibility if (Boolean.parseBoolean((String) props.get(KEY_INDEX_ALL_FILES))) { props.put(KEY_INDEX_UNUSED_HEADERS_WITH_DEFAULT_LANG, "true"); //$NON-NLS-1$ } } } public static Properties getDefaultIndexerProperties() { Preferences prefs= getDefaultPreferences(); Properties props= new Properties(); readProperties(prefs, props); return props; } public static int getDefaultUpdatePolicy() { Preferences[] prefs = new Preferences[] { getDefaultPreferences() }; return getUpdatePolicy(prefs); } /** * Adds or changes indexer properties for a project. */ public static void setProperties(IProject project, int scope, Properties props) { Preferences[] prefs= getPreferences(project, scope); setProperties(prefs[0], props); } private static void setProperties(Preferences prefs, Properties props) { for (Map.Entry<Object, Object> entry : props.entrySet()) { String key = (String) entry.getKey(); String val = (String) entry.getValue(); prefs.put(key, val); } } /** * Returns an indexer property for the given project. * @since 4.0 */ public static String get(IProject project, String key, String defval) { IPreferencesService prefService = Platform.getPreferencesService(); Preferences[] prefs= IndexerPreferences.getPreferences(project); return prefService.get(key, defval, prefs); } /** * Returns an indexer property in a scope for the given project. * @since 4.0 */ private static String get(IProject project, int scope, String key, String defval) { IPreferencesService prefService = Platform.getPreferencesService(); Preferences[] prefs= IndexerPreferences.getPreferences(project, scope); return prefService.get(key, defval, prefs); } /** * Adds or changes an indexer property for the given project. */ public static void set(final IProject project, String key, String value) { if (getScope(project) == SCOPE_INSTANCE) { setScope(project, SCOPE_PROJECT_PRIVATE); } final Preferences[] prefs= IndexerPreferences.getPreferences(project.getProject()); prefs[0].put(key, value); } /** * Sets up the initial indexing preferences for the project. */ private static int determineScopeOnFirstUse(IProject project) { int scope= SCOPE_INSTANCE; Preferences prjPrefs= getProjectPreferences(project); if (prjPrefs.get(KEY_INDEXER_ID, null) != null) { scope= SCOPE_PROJECT_SHARED; } getLocalPreferences(project).putInt(KEY_INDEXER_PREFS_SCOPE, scope); CCoreInternals.savePreferences(project, false); return scope; } private static Preferences[] getPreferences(IProject project) { return getPreferences(project, getScope(project)); } private static Preferences[] getPreferences(IProject project, int scope) { if (project != null) { switch (scope) { case SCOPE_PROJECT_PRIVATE: return new Preferences[] { getLocalPreferences(project) }; case SCOPE_PROJECT_SHARED: return new Preferences[] { getProjectPreferences(project) }; } } return getInstancePreferencesArray(); } private static Preferences[] getInstancePreferencesArray() { return new Preferences[] { getInstancePreferences(), getConfigurationPreferences(), getDefaultPreferences() }; } private static Preferences getInstancePreferences() { return InstanceScope.INSTANCE.getNode(QUALIFIER).node(INDEXER_NODE); } private static Preferences getConfigurationPreferences() { return ConfigurationScope.INSTANCE.getNode(QUALIFIER).node(INDEXER_NODE); } private static Preferences getDefaultPreferences() { return DefaultScope.INSTANCE.getNode(QUALIFIER).node(INDEXER_NODE); } public static Preferences getProjectPreferences(IProject project) { return new ProjectScope(project).getNode(QUALIFIER).node(INDEXER_NODE); } private static Preferences getLocalPreferences(IProject project) { return new LocalProjectScope(project).getNode(QUALIFIER).node(INDEXER_NODE); } private static void readProperties(Preferences preferences, Properties props) { try { String[] keys = preferences.keys(); for (String key : keys) { if (props.get(key) == null) { String val= preferences.get(key, null); if (val != null) { props.put(key, val); } } } } catch (BackingStoreException e) { } } public static void initializeDefaultPreferences(IEclipsePreferences defaultPreferences) { Preferences prefs= defaultPreferences.node(INDEXER_NODE); prefs.put(KEY_INDEXER_ID, IPDOMManager.ID_FAST_INDEXER); prefs.putBoolean(KEY_INDEX_ALL_FILES, true); prefs.putBoolean(KEY_INDEX_UNUSED_HEADERS_WITH_DEFAULT_LANG, true); prefs.putBoolean(KEY_INDEX_UNUSED_HEADERS_WITH_ALTERNATE_LANG, false); prefs.putBoolean(KEY_INDEX_ON_OPEN, false); prefs.putBoolean(KEY_INCLUDE_HEURISTICS, true); prefs.putInt(KEY_SKIP_FILES_LARGER_THAN_MB, DEFAULT_FILE_SIZE_LIMIT_MB); prefs.putInt(KEY_SKIP_INCLUDED_FILES_LARGER_THAN_MB, DEFAULT_INCLUDED_FILE_SIZE_LIMIT_MB); prefs.putBoolean(KEY_SKIP_ALL_REFERENCES, false); prefs.putBoolean(KEY_SKIP_IMPLICIT_REFERENCES, false); prefs.putBoolean(KEY_SKIP_TYPE_REFERENCES, false); prefs.putBoolean(KEY_SKIP_MACRO_REFERENCES, false); prefs.put(KEY_INDEX_IMPORT_LOCATION, DEFAULT_INDEX_IMPORT_LOCATION); prefs.putBoolean(KEY_INDEX_ALL_HEADER_VERSIONS, false); } public static void setDefaultIndexerId(String defaultId) { getDefaultPreferences().put(KEY_INDEXER_ID, defaultId); } public static void addChangeListener(IProject prj, IPreferenceChangeListener pcl) { Preferences node= getProjectPreferences(prj); addListener(node, pcl); node= getLocalPreferences(prj); addListener(node, pcl); node= getInstancePreferences(); addListener(node, pcl); } private static void addListener(Preferences node, IPreferenceChangeListener pcl) { if (node instanceof IEclipsePreferences) { IEclipsePreferences enode= (IEclipsePreferences) node; enode.addPreferenceChangeListener(pcl); } } public static void removeChangeListener(IProject prj, IPreferenceChangeListener pcl) { Preferences node= getProjectPreferences(prj); removeListener(node, pcl); node= getLocalPreferences(prj); removeListener(node, pcl); node= getInstancePreferences(); removeListener(node, pcl); } private static void removeListener(Preferences node, IPreferenceChangeListener pcl) { if (node instanceof IEclipsePreferences) { IEclipsePreferences enode= (IEclipsePreferences) node; enode.removePreferenceChangeListener(pcl); } } public static String getIndexImportLocation(IProject project) { Preferences[] prefs; if (project != null) { prefs= new Preferences[] { getProjectPreferences(project), getInstancePreferences(), getConfigurationPreferences(), getDefaultPreferences() }; } else { prefs= new Preferences[] { getInstancePreferences(), getConfigurationPreferences(), getDefaultPreferences() }; } return Platform.getPreferencesService().get(KEY_INDEX_IMPORT_LOCATION, DEFAULT_INDEX_IMPORT_LOCATION, prefs); } public static void setIndexImportLocation(IProject project, String location) { if (!location.equals(getIndexImportLocation(project))) { getProjectPreferences(project).put(KEY_INDEX_IMPORT_LOCATION, location); } } public static int getUpdatePolicy(IProject project) { // no support for project specific policies Preferences[] prefs= getInstancePreferencesArray(); return getUpdatePolicy(prefs); } private static int getUpdatePolicy(Preferences[] prefs) { String val= Platform.getPreferencesService().get(KEY_UPDATE_POLICY, null, prefs); if (val != null) { try { int result= Integer.parseInt(val); switch (result) { case IndexUpdatePolicy.POST_CHANGE: case IndexUpdatePolicy.POST_BUILD: case IndexUpdatePolicy.MANUAL: return result; } } catch (Exception e) { CCorePlugin.log(e); } } return DEFAULT_UPDATE_POLICY; } public static boolean preferDefaultLanguage(IProject project) { IPreferencesService prefService = Platform.getPreferencesService(); Preferences[] prefs= IndexerPreferences.getPreferences(project); if (Boolean.parseBoolean(prefService.get(KEY_INDEX_UNUSED_HEADERS_WITH_ALTERNATE_LANG, null, prefs)) && Boolean.parseBoolean(prefService.get(KEY_INDEX_ALL_FILES, null, prefs)) && !Boolean.parseBoolean(prefService.get(KEY_INDEX_UNUSED_HEADERS_WITH_DEFAULT_LANG, null, prefs))) { return false; } return true; } public static boolean preferDefaultLanguage(Properties props) { if (Boolean.parseBoolean((String) props.get(KEY_INDEX_UNUSED_HEADERS_WITH_ALTERNATE_LANG)) && Boolean.parseBoolean((String) props.get(KEY_INDEX_ALL_FILES)) && !Boolean.parseBoolean((String) props.get(KEY_INDEX_UNUSED_HEADERS_WITH_DEFAULT_LANG))) { return false; } return true; } public static void setReindexOnConfigChange(IProject project, boolean shouldReindexOnConfigChange) { if (shouldReindexOnConfigChange != getReindexOnConfigChange(project)) { getProjectPreferences(project).putBoolean(KEY_REINDEX_ON_CONFIG_CHANGE, shouldReindexOnConfigChange); } } public static boolean getReindexOnConfigChange(IProject project) { return getProjectPreferences(project).getBoolean(KEY_REINDEX_ON_CONFIG_CHANGE, true); } public static void setReindexOnIndexerChange(IProject project, boolean shouldReindexOnIndexerChange) { if (shouldReindexOnIndexerChange != getReindexOnIndexerChange(project)) { getProjectPreferences(project).putBoolean(KEY_REINDEX_ON_INDEXER_CHANGE, shouldReindexOnIndexerChange); } } public static boolean getReindexOnIndexerChange(IProject project) { return getProjectPreferences(project).getBoolean(KEY_REINDEX_ON_INDEXER_CHANGE, true); } }