/******************************************************************************* * Copyright (c) 2009, 2012 Andrew Gvozdev 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: * Andrew Gvozdev - initial API and implementation *******************************************************************************/ package org.eclipse.cdt.core.language.settings.providers; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import org.eclipse.cdt.core.AbstractExecutableExtensionBase; import org.eclipse.cdt.core.settings.model.ICConfigurationDescription; import org.eclipse.cdt.core.settings.model.ICLanguageSettingEntry; import org.eclipse.cdt.internal.core.settings.model.SettingsModelMessages; import org.eclipse.core.resources.IResource; /** * {@code LanguageSettingsBaseProvider} is a basic implementation of {@link ILanguageSettingsProvider} * for the extensions defined by {@code org.eclipse.cdt.core.LanguageSettingsProvider} extension point. * * This implementation supports "static" list of entries for languages specified in * the extension point. * * @since 5.4 */ public class LanguageSettingsBaseProvider extends AbstractExecutableExtensionBase implements ILanguageSettingsProvider { /** Language scope, i.e. list of languages the entries will be provided for. */ protected List<String> languageScope = null; /** Provider-specific properties */ protected Map<String, String> properties = new HashMap<String, String>(); /** List of entries defined by this provider. */ private List<ICLanguageSettingEntry> entries = null; /** * Default constructor. */ public LanguageSettingsBaseProvider() { super(); } /** * Constructor. Creates an "empty" non-configured provider. * * @param id - id of the provider. * @param name - name of the provider to be presented to a user. */ public LanguageSettingsBaseProvider(String id, String name) { super(id, name); } /** * Constructor. * * @param id - id of the provider. * @param name - name of the provider to be presented to a user. * @param languages - list of languages the {@code entries} provided for. * {@code languages} can be {@code null}, in this case the {@code entries} * are provided for any language. * @param entries - the list of language settings entries this provider provides. * If {@code null} is passed, the provider creates an empty list. */ public LanguageSettingsBaseProvider(String id, String name, List<String> languages, List<ICLanguageSettingEntry> entries) { super(id, name); this.languageScope = languages!=null ? new ArrayList<String>(languages) : null; this.entries = getPooledList(entries); } /** * Constructor. * * @param id - id of the provider. * @param name - name of the provider to be presented to a user. * @param languages - list of languages the {@code entries} provided for. * {@code languages} can be {@code null}, in this case the {@code entries} * are provided for any language. * @param entries - the list of language settings entries this provider provides. * If {@code null} is passed, the provider creates an empty list. * @param properties - custom properties as the means to customize providers. */ public LanguageSettingsBaseProvider(String id, String name, List<String> languages, List<ICLanguageSettingEntry> entries, Map<String, String> properties) { super(id, name); this.languageScope = languages!=null ? new ArrayList<String>(languages) : null; this.entries = getPooledList(entries); if (properties != null) this.properties = new HashMap<String, String>(properties); } /** * A method to configure the provider. The initialization of provider from * the extension point is done in 2 steps. First, the class is created as * an executable extension using the default provider. Then this method is * used to configure the provider. *<br><br> * It is not allowed to reconfigure the provider. * * @param id - id of the provider. * @param name - name of the provider to be presented to a user. * @param languages - list of languages the {@code entries} provided for. * {@code languages} can be {@code null}, in this case the {@code entries} * are provided for any language. * @param entries - the list of language settings entries this provider provides. * If {@code null} is passed, the provider creates an empty list. * @param properties - custom properties as the means to customize providers. * * @throws UnsupportedOperationException if an attempt to reconfigure provider is made. */ public void configureProvider(String id, String name, List<String> languages, List<ICLanguageSettingEntry> entries, Map<String, String> properties) { if (this.entries!=null || !this.properties.isEmpty()) throw new UnsupportedOperationException(SettingsModelMessages.getString("LanguageSettingsBaseProvider.CanBeConfiguredOnlyOnce")); //$NON-NLS-1$ setId(id); setName(name); this.languageScope = languages!=null ? new ArrayList<String>(languages) : null; this.entries = getPooledList(entries); if (properties != null) this.properties = new HashMap<String, String>(properties); } /** * {@code LanguageSettingsBaseProvider} keeps the list of key-value pairs * so extenders of this class can customize the provider. The properties * of {@code LanguageSettingsBaseProvider} come from the extension in plugin.xml * although the extenders can provide their own method. * <br><br> * Please note that empty string value is treated as "default" value and * the same as {@code null} and the same as missing property, which allows * {@link #equals(Object)} evaluate the property as equal while comparing providers. * * @param key - property to check the value. * @return value of the property. If the property is missing returns empty string. */ public String getProperty(String key) { String value = properties.get(key); if (value == null) { value = ""; //$NON-NLS-1$ } return value; } /** * Convenience method to get boolean property. * @see #getProperty(String) * * @param key - property to check the value. * @return boolean value of the property. If the property is missing or cannot be * interpreted as boolean returns {@code false}. */ public boolean getPropertyBool(String key) { return Boolean.parseBoolean(properties.get(key)); } private List<ICLanguageSettingEntry> getPooledList(List<ICLanguageSettingEntry> entries) { if (entries != null) { return LanguageSettingsStorage.getPooledList(entries); } return null; } /** * {@inheritDoc} * * @param languageId - language id. If {@code null}, then entries defined for * the language scope are returned. See {@link #getLanguageScope()} * * @return unmodifiable list of setting entries or {@code null} if no settings defined. * the list is internally pooled and guaranteed to be the same object for equal * lists. */ @Override public List<ICLanguageSettingEntry> getSettingEntries(ICConfigurationDescription cfgDescription, IResource rc, String languageId) { if (languageScope == null) { return entries; } for (String lang : languageScope) { if (lang.equals(languageId)) { return entries; } } return null; } /** * @return the unmodifiable list of languages this provider provides for. * If {@code null}, the provider provides for any language. */ public List<String> getLanguageScope() { if (languageScope==null) return null; return Collections.unmodifiableList(languageScope); } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((getId() == null) ? 0 : getId().hashCode()); result = prime * result + ((getName() == null) ? 0 : getName().hashCode()); result = prime * result + ((entries == null) ? 0 : entries.hashCode()); result = prime * result + ((languageScope == null) ? 0 : languageScope.hashCode()); // exclude field "properties" because of special rules for equals() result = prime * result + getClass().hashCode(); return result; } /** * @return {@code true} if the objects are equal, {@code false } otherwise. * @see java.lang.Object#equals(java.lang.Object) */ @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; LanguageSettingsBaseProvider other = (LanguageSettingsBaseProvider) obj; String id = getId(); String otherId = other.getId(); if (id == null) { if (otherId != null) return false; } else if (!id.equals(otherId)) return false; String name = getName(); String otherName = other.getName(); if (name == null) { if (otherName != null) return false; } else if (!name.equals(otherName)) return false; if (entries == null) { if (other.entries != null) return false; } else if (!entries.equals(other.entries)) return false; if (languageScope == null) { if (other.languageScope != null) return false; } else if (!languageScope.equals(other.languageScope)) return false; if (properties == null) { if (other.properties != null) return false; } else if (other.properties == null) { return false; } else { // The trouble to ensure default properties are equal to missing ones. Set<String> keys = new HashSet<String>(properties.keySet()); keys.addAll(other.properties.keySet()); for (String key : keys) { String value = properties.get(key); if (value == null || value.equals(Boolean.FALSE.toString())) value = ""; //$NON-NLS-1$ String otherValue = other.properties.get(key); if (otherValue == null || otherValue.equals(Boolean.FALSE.toString())) otherValue = ""; //$NON-NLS-1$ if (!value.equals(otherValue)) return false; } } return true; } }