/* * Copyright (c) 2013, the Dart project authors. * * Licensed under the Eclipse Public License v1.0 (the "License"); you may not use this file except * in compliance with the License. You may obtain a copy of the License at * * http://www.eclipse.org/legal/epl-v10.html * * Unless required by applicable law or agreed to in writing, software distributed under the License * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express * or implied. See the License for the specific language governing permissions and limitations under * the License. */ package com.google.dart.tools.core.internal; import com.google.dart.tools.core.DartCore; import com.google.dart.tools.core.DartPreferenceConstants; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.Platform; import org.eclipse.core.runtime.jobs.Job; import org.eclipse.core.runtime.preferences.DefaultScope; import org.eclipse.core.runtime.preferences.IEclipsePreferences; import org.eclipse.core.runtime.preferences.IEclipsePreferences.PreferenceChangeEvent; import org.eclipse.core.runtime.preferences.IPreferencesService; import org.eclipse.core.runtime.preferences.IScopeContext; import org.eclipse.core.runtime.preferences.InstanceScope; import org.osgi.service.prefs.BackingStoreException; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.Map; /** * Manages {@link DartCore} options. * * @coverage dart.tools.core */ public class OptionManager { private static class EclipsePreferencesListener implements IEclipsePreferences.IPreferenceChangeListener { @Override public void preferenceChange(IEclipsePreferences.PreferenceChangeEvent event) { //TODO (pquitslund): respond to preference updates } } private HashMap<String, String> optionsCache; private HashSet<String> optionNames = new HashSet<String>(20); private final IEclipsePreferences[] preferencesLookup = new IEclipsePreferences[2]; private EclipsePreferencesListener instancePreferencesListener = new EclipsePreferencesListener(); private IEclipsePreferences.IPreferenceChangeListener propertyListener; private IEclipsePreferences.IPreferenceChangeListener resourcesPropertyListener; private static final int PREF_INSTANCE = 0; private static final int PREF_DEFAULT = 1; /** * Listener on eclipse preferences default/instance node changes. */ private IEclipsePreferences.INodeChangeListener instanceNodeListener = new IEclipsePreferences.INodeChangeListener() { @Override public void added(IEclipsePreferences.NodeChangeEvent event) { // do nothing } @Override public void removed(IEclipsePreferences.NodeChangeEvent event) { if (event.getChild() == OptionManager.this.preferencesLookup[PREF_INSTANCE]) { OptionManager.this.preferencesLookup[PREF_INSTANCE] = getInstanceScope().getNode( DartCore.PLUGIN_ID); OptionManager.this.preferencesLookup[PREF_INSTANCE].addPreferenceChangeListener(new EclipsePreferencesListener()); } } }; private IEclipsePreferences.INodeChangeListener defaultNodeListener = new IEclipsePreferences.INodeChangeListener() { @Override public void added(IEclipsePreferences.NodeChangeEvent event) { // do nothing } @Override public void removed(IEclipsePreferences.NodeChangeEvent event) { if (event.getChild() == OptionManager.this.preferencesLookup[PREF_DEFAULT]) { OptionManager.this.preferencesLookup[PREF_DEFAULT] = getDefaultScope().getNode( DartCore.PLUGIN_ID); } } }; /** * The shared unique instance. */ private static OptionManager instance; /** * Return the unique Option Manager instance. * * @return the unique Option Manager */ public synchronized static OptionManager getInstance() { if (instance == null) { instance = new OptionManager(); instance.doStartup(); } return instance; } public static void shutdown() { if (instance != null) { instance.doShutdown(); } } private OptionManager() { initializePreferences(); } /** * Utility method for returning one option value only. Equivalent to * <code>getOptions().get(optionName)</code> Note that it may answer <code>null</code> if this * option does not exist. * <p> * Helper constants have been defined on DartPreferenceConstants for each of the option IDs * (categorized in Code assist option ID, Compiler option ID and Core option ID) and some of their * acceptable values (categorized in Option value). Some options accept open value sets beyond the * documented constant values. * <p> * Note: each release may add new options. * * @param optionName the name of the option whose value is to be returned * @return the value of a given option */ public String getOption(String optionName) { DartCore.notYetImplemented(); // if (DartCore.CORE_ENCODING.equals(optionName)){ // return DartCore.getEncoding(); // } String propertyName = optionName; if (optionNames.contains(propertyName)) { IPreferencesService service = Platform.getPreferencesService(); String value = service.get(optionName, null, preferencesLookup); return value == null ? null : value.trim(); } return null; } /** * Return the table of the current options. Initially, all options have their default values, and * this method returns a table that includes all known options. * <p> * Helper constants have been defined on DartPreferenceConstants for each of the option IDs * (categorized in Code assist option ID, Compiler option ID and Core option ID) and some of their * acceptable values (categorized in Option value). Some options accept open value sets beyond the * documented constant values. * <p> * Note: each release may add new options. * <p> * Returns a default set of options even if the platform is not running. * </p> * * @return table of current settings of all options (key type: <code>String</code>; value type: * <code>String * </code>) */ public HashMap<String, String> getOptions() { // return cached options if already computed HashMap<String, String> cachedOptions; // use a local variable to avoid race // condition (see // https://bugs.eclipse.org/bugs/show_bug.cgi?id=256329 // ) if ((cachedOptions = optionsCache) != null) { return new HashMap<String, String>(cachedOptions); } if (!Platform.isRunning()) { optionsCache = getDefaultOptionsNoInitialization(); return new HashMap<String, String>(optionsCache); } // init HashMap<String, String> options = new HashMap<String, String>(10); IPreferencesService service = Platform.getPreferencesService(); // set options using preferences service lookup Iterator<String> iterator = optionNames.iterator(); while (iterator.hasNext()) { String propertyName = iterator.next(); String propertyValue = service.get(propertyName, null, preferencesLookup); if (propertyValue != null) { options.put(propertyName, propertyValue); } } optionsCache = new HashMap<String, String>(options); // return built map return options; } private void doShutdown() { IEclipsePreferences preferences = getInstanceScope().getNode(DartCore.PLUGIN_ID); try { preferences.flush(); } catch (BackingStoreException e) { DartCore.logError("Could not save DartCore preferences", e); //$NON-NLS-1$ } // Stop listening to preferences changes preferences.removePreferenceChangeListener(propertyListener); ((IEclipsePreferences) preferencesLookup[PREF_DEFAULT].parent()).removeNodeChangeListener(defaultNodeListener); preferencesLookup[PREF_DEFAULT] = null; ((IEclipsePreferences) preferencesLookup[PREF_INSTANCE].parent()).removeNodeChangeListener(instanceNodeListener); preferencesLookup[PREF_INSTANCE].removePreferenceChangeListener(instancePreferencesListener); preferencesLookup[PREF_INSTANCE] = null; String resourcesPluginId = ResourcesPlugin.getPlugin().getBundle().getSymbolicName(); getInstanceScope().getNode(resourcesPluginId).removePreferenceChangeListener( resourcesPropertyListener); // wait for the initialization job to finish try { Job.getJobManager().join(DartCore.PLUGIN_ID, null); } catch (InterruptedException e) { // ignore } } private void doStartup() { try { // Initialize eclipse preferences initializePreferences(); // Listen to preference changes propertyListener = new IEclipsePreferences.IPreferenceChangeListener() { @Override public void preferenceChange(PreferenceChangeEvent event) { OptionManager.this.optionsCache = null; } }; getInstanceScope().getNode(DartCore.PLUGIN_ID).addPreferenceChangeListener(propertyListener); // listen for encoding changes (see // https://bugs.eclipse.org/bugs/show_bug.cgi?id=255501 ) resourcesPropertyListener = new IEclipsePreferences.IPreferenceChangeListener() { @Override public void preferenceChange(PreferenceChangeEvent event) { if (ResourcesPlugin.PREF_ENCODING.equals(event.getKey())) { OptionManager.this.optionsCache = null; } } }; String resourcesPluginId = ResourcesPlugin.getPlugin().getBundle().getSymbolicName(); getInstanceScope().getNode(resourcesPluginId).addPreferenceChangeListener( resourcesPropertyListener); } catch (RuntimeException e) { shutdown(); throw e; } } // Do not modify without modifying getDefaultOptions() private HashMap<String, String> getDefaultOptionsNoInitialization() { DartCore.notYetImplemented(); // Map defaultOptionsMap = new CompilerOptions().getMap(); // compiler // defaults Map<String, String> defaultOptionsMap = new HashMap<String, String>(); // Formatter settings //defaultOptionsMap.putAll(DefaultCodeFormatterConstants.getEclipseDefaultSettings()); // CodeAssist settings defaultOptionsMap.put( DartPreferenceConstants.CODEASSIST_VISIBILITY_CHECK, DartPreferenceConstants.DISABLED); defaultOptionsMap.put( DartPreferenceConstants.CODEASSIST_DEPRECATION_CHECK, DartPreferenceConstants.DISABLED); defaultOptionsMap.put( DartPreferenceConstants.CODEASSIST_IMPLICIT_QUALIFICATION, DartPreferenceConstants.DISABLED); defaultOptionsMap.put(DartPreferenceConstants.CODEASSIST_FIELD_PREFIXES, ""); //$NON-NLS-1$ defaultOptionsMap.put(DartPreferenceConstants.CODEASSIST_STATIC_FIELD_PREFIXES, ""); //$NON-NLS-1$ defaultOptionsMap.put(DartPreferenceConstants.CODEASSIST_STATIC_FINAL_FIELD_PREFIXES, ""); //$NON-NLS-1$ defaultOptionsMap.put(DartPreferenceConstants.CODEASSIST_LOCAL_PREFIXES, ""); //$NON-NLS-1$ defaultOptionsMap.put(DartPreferenceConstants.CODEASSIST_ARGUMENT_PREFIXES, ""); //$NON-NLS-1$ defaultOptionsMap.put(DartPreferenceConstants.CODEASSIST_FIELD_SUFFIXES, ""); //$NON-NLS-1$ defaultOptionsMap.put(DartPreferenceConstants.CODEASSIST_STATIC_FIELD_SUFFIXES, ""); //$NON-NLS-1$ defaultOptionsMap.put(DartPreferenceConstants.CODEASSIST_STATIC_FINAL_FIELD_SUFFIXES, ""); //$NON-NLS-1$ defaultOptionsMap.put(DartPreferenceConstants.CODEASSIST_LOCAL_SUFFIXES, ""); //$NON-NLS-1$ defaultOptionsMap.put(DartPreferenceConstants.CODEASSIST_ARGUMENT_SUFFIXES, ""); //$NON-NLS-1$ defaultOptionsMap.put( DartPreferenceConstants.CODEASSIST_FORBIDDEN_REFERENCE_CHECK, DartPreferenceConstants.ENABLED); defaultOptionsMap.put( DartPreferenceConstants.CODEASSIST_DISCOURAGED_REFERENCE_CHECK, DartPreferenceConstants.DISABLED); defaultOptionsMap.put( DartPreferenceConstants.CODEASSIST_CAMEL_CASE_MATCH, DartPreferenceConstants.ENABLED); return new HashMap<String, String>(defaultOptionsMap); } private IScopeContext getDefaultScope() { return DefaultScope.INSTANCE; } private IScopeContext getInstanceScope() { return InstanceScope.INSTANCE; } private void initializePreferences() { // Create lookups preferencesLookup[PREF_INSTANCE] = getInstanceScope().getNode(DartCore.PLUGIN_ID); preferencesLookup[PREF_DEFAULT] = getDefaultScope().getNode(DartCore.PLUGIN_ID); // Listen to instance preferences node removal from parent in order to // refresh stored one instanceNodeListener = new IEclipsePreferences.INodeChangeListener() { @Override public void added(IEclipsePreferences.NodeChangeEvent event) { // do nothing } @Override public void removed(IEclipsePreferences.NodeChangeEvent event) { if (event.getChild() == OptionManager.this.preferencesLookup[PREF_INSTANCE]) { OptionManager.this.preferencesLookup[PREF_INSTANCE] = getInstanceScope().getNode( DartCore.PLUGIN_ID); OptionManager.this.preferencesLookup[PREF_INSTANCE].addPreferenceChangeListener(new EclipsePreferencesListener()); } } }; ((IEclipsePreferences) preferencesLookup[PREF_INSTANCE].parent()).addNodeChangeListener(instanceNodeListener); preferencesLookup[PREF_INSTANCE].addPreferenceChangeListener(instancePreferencesListener = new EclipsePreferencesListener()); // Listen to default preferences node removal from parent in order to // refresh stored one defaultNodeListener = new IEclipsePreferences.INodeChangeListener() { @Override public void added(IEclipsePreferences.NodeChangeEvent event) { // do nothing } @Override public void removed(IEclipsePreferences.NodeChangeEvent event) { if (event.getChild() == OptionManager.this.preferencesLookup[PREF_DEFAULT]) { OptionManager.this.preferencesLookup[PREF_DEFAULT] = getDefaultScope().getNode( DartCore.PLUGIN_ID); } } }; ((IEclipsePreferences) preferencesLookup[PREF_DEFAULT].parent()).addNodeChangeListener(defaultNodeListener); } }