/*******************************************************************************
* Copyright (c) 2010, 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.internal.ui.language.settings.providers;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.IExtension;
import org.eclipse.core.runtime.IExtensionPoint;
import org.eclipse.core.runtime.IExtensionRegistry;
import org.eclipse.core.runtime.Platform;
import org.eclipse.cdt.core.language.settings.providers.ILanguageSettingsProvider;
import org.eclipse.cdt.ui.CDTSharedImages;
import org.eclipse.cdt.ui.CUIPlugin;
import org.eclipse.cdt.ui.dialogs.ICOptionPage;
/**
* This class manages extensions of extension point org.eclipse.cdt.core.LanguageSettingsProvider
* which defines appearance and behavior of UI controls for Language Settings Providers.
*
* @noextend This class is not intended to be subclassed by clients.
* @noinstantiate This class is not intended to be instantiated by clients.
*/
public class LanguageSettingsProviderAssociationManager {
/** Name of the extension point for contributing language settings provider associations */
private static final String PROVIDER_ASSOCIATION_EXTENSION_POINT_SIMPLE_ID = "LanguageSettingsProviderAssociation"; //$NON-NLS-1$
private static final String ELEM_ID_ASSOCIATION = "id-association"; //$NON-NLS-1$
private static final String ELEM_CLASS_ASSOCIATION = "class-association"; //$NON-NLS-1$
private static final String ATTR_ID = "id"; //$NON-NLS-1$
private static final String ATTR_CLASS = "class"; //$NON-NLS-1$
private static final String ATTR_ICON = "icon"; //$NON-NLS-1$
private static final String ATTR_PAGE = "page"; //$NON-NLS-1$
private static final String ATTR_UI_CLEAR_ENTRIES = "ui-clear-entries"; //$NON-NLS-1$
private static final String ATTR_UI_EDIT_ENTRIES = "ui-edit-entries"; //$NON-NLS-1$
private static boolean isLoaded = false;
private static List<URL> loadedIcons = new ArrayList<URL>();
private static Map<String, URL> fImagesUrlById = new HashMap<String, URL>();
private static Map<String, URL> fImagesUrlByClass = new HashMap<String, URL>();
private static List<String> fRegirestedIds = new ArrayList<String>();
private static List<String> fRegisteredClasses = new ArrayList<String>();
private static Map<String, Map<String, String>> fAssociationsById = new HashMap<String, Map<String, String>>();
private static Map<String, Map<String, String>> fAssociationsByClass = new HashMap<String, Map<String, String>>();
/**
* Load extensions into memory maps.
*/
private static void loadExtensions() {
if (isLoaded) {
return;
}
isLoaded = true;
IExtensionRegistry registry = Platform.getExtensionRegistry();
IExtensionPoint extension = registry.getExtensionPoint(CUIPlugin.PLUGIN_ID, PROVIDER_ASSOCIATION_EXTENSION_POINT_SIMPLE_ID);
if (extension != null) {
IExtension[] extensions = extension.getExtensions();
for (IExtension ext : extensions) {
@SuppressWarnings("unused")
String extensionID = ext.getUniqueIdentifier();
for (IConfigurationElement cfgEl : ext.getConfigurationElements()) {
if (cfgEl.getName().equals(ELEM_ID_ASSOCIATION)) {
String id = cfgEl.getAttribute(ATTR_ID);
URL url = getIconUrl(cfgEl);
fImagesUrlById.put(id, url);
fRegirestedIds.add(id);
Map<String, String> properties = new HashMap<String, String>();
putNotEmpty(properties, ATTR_PAGE, cfgEl.getAttribute(ATTR_PAGE));
putNotEmpty(properties, ATTR_UI_CLEAR_ENTRIES, cfgEl.getAttribute(ATTR_UI_CLEAR_ENTRIES));
putNotEmpty(properties, ATTR_UI_EDIT_ENTRIES, cfgEl.getAttribute(ATTR_UI_EDIT_ENTRIES));
fAssociationsById.put(id, properties);
} else if (cfgEl.getName().equals(ELEM_CLASS_ASSOCIATION)) {
String className = cfgEl.getAttribute(ATTR_CLASS);
URL url = getIconUrl(cfgEl);
fImagesUrlByClass.put(className, url);
String pageClass = cfgEl.getAttribute(ATTR_PAGE);
if (pageClass != null && pageClass.length() > 0) {
fRegisteredClasses.add(className);
}
Map<String, String> properties = new HashMap<String, String>();
putNotEmpty(properties, ATTR_PAGE, cfgEl.getAttribute(ATTR_PAGE));
putNotEmpty(properties, ATTR_UI_CLEAR_ENTRIES, cfgEl.getAttribute(ATTR_UI_CLEAR_ENTRIES));
putNotEmpty(properties, ATTR_UI_EDIT_ENTRIES, cfgEl.getAttribute(ATTR_UI_EDIT_ENTRIES));
fAssociationsByClass.put(className, properties);
}
}
}
}
}
/**
* Put value into properties ignoring nulls.
*/
private static void putNotEmpty(Map<String, String> properties, String key, String value) {
if (value != null)
properties.put(key, value);
}
/**
* Find icon URL in its bundle.
*/
private static URL getIconUrl(IConfigurationElement config) {
URL url = null;
try {
String iconName = config.getAttribute(ATTR_ICON);
if (iconName != null) {
URL pluginInstallUrl = Platform.getBundle(config.getDeclaringExtension().getContributor().getName()).getEntry("/"); //$NON-NLS-1$
url = new URL(pluginInstallUrl, iconName);
if (loadedIcons.contains(url)) {
return url;
}
}
} catch (MalformedURLException e) {
CUIPlugin.log(e);
}
loadedIcons.add(url);
if (url != null) {
CDTSharedImages.register(url);
}
return url;
}
/**
* Get image URL for language settings provider with the given ID.
*
* @param providerId - ID of language settings provider.
* @return image URL or {@code null}.
*/
public static URL getImageUrl(String providerId) {
loadExtensions();
return fImagesUrlById.get(providerId);
}
/**
* Create an Options page for language settings provider with given ID.
*/
private static ICOptionPage createOptionsPageById(String providerId) {
loadExtensions();
if (fRegirestedIds.contains(providerId)) {
IExtensionRegistry registry = Platform.getExtensionRegistry();
IExtensionPoint extension = registry.getExtensionPoint(CUIPlugin.PLUGIN_ID, PROVIDER_ASSOCIATION_EXTENSION_POINT_SIMPLE_ID);
if (extension != null) {
IExtension[] extensions = extension.getExtensions();
for (IExtension ext : extensions) {
try {
@SuppressWarnings("unused")
String extensionID = ext.getUniqueIdentifier();
for (IConfigurationElement cfgEl : ext.getConfigurationElements()) {
if (cfgEl.getName().equals(ELEM_ID_ASSOCIATION)) {
String id = cfgEl.getAttribute(ATTR_ID);
if (providerId.equals(id)) {
String pageClass = cfgEl.getAttribute(ATTR_PAGE);
if (pageClass != null && pageClass.trim().length() > 0) {
ICOptionPage page = (ICOptionPage) cfgEl.createExecutableExtension(ATTR_PAGE);
return page;
}
}
}
}
} catch (Exception e) {
CUIPlugin.log("Cannot load LanguageSettingsProviderAssociation extension " + ext.getUniqueIdentifier(), e); //$NON-NLS-1$
}
}
}
}
return null;
}
/**
* Create an Options page for language settings provider class by its name.
*/
private static ICOptionPage createOptionsPageByClass(String providerClassName) {
loadExtensions();
if (fRegisteredClasses.contains(providerClassName)) {
IExtensionRegistry registry = Platform.getExtensionRegistry();
IExtensionPoint extension = registry.getExtensionPoint(CUIPlugin.PLUGIN_ID, PROVIDER_ASSOCIATION_EXTENSION_POINT_SIMPLE_ID);
if (extension != null) {
IExtension[] extensions = extension.getExtensions();
for (IExtension ext : extensions) {
try {
@SuppressWarnings("unused")
String extensionID = ext.getUniqueIdentifier();
for (IConfigurationElement cfgEl : ext.getConfigurationElements()) {
if (cfgEl.getName().equals(ELEM_CLASS_ASSOCIATION)) {
String className = cfgEl.getAttribute(ATTR_CLASS);
if (providerClassName.equals(className)) {
String pageClass = cfgEl.getAttribute(ATTR_PAGE);
if (pageClass!=null && pageClass.trim().length()>0) {
ICOptionPage page = (ICOptionPage) cfgEl.createExecutableExtension(ATTR_PAGE);
return page;
}
}
}
}
} catch (Exception e) {
CUIPlugin.log("Cannot load LanguageSettingsProviderAssociation extension " + ext.getUniqueIdentifier(), e); //$NON-NLS-1$
}
}
}
}
return null;
}
/**
* Returns Language Settings Provider image registered for closest superclass
* or interface.
*
* @param providerClass - class to find Language Settings Provider image.
* @return image or {@code null}
*/
public static URL getImage(Class<? extends ILanguageSettingsProvider> providerClass) {
URL url = null;
outer: for (Class<?> c = providerClass; c != null; c = c.getSuperclass()) {
url = getImageURL(c);
if (url != null) {
break;
}
// this does not check for super-interfaces, feel free to implement as needed
for (Class<?> i : c.getInterfaces()) {
url = getImageURL(i);
if (url != null) {
break outer;
}
}
}
return url;
}
/**
* Return image URL registered for the given class.
*/
private static URL getImageURL(Class<?> clazz) {
String className = clazz.getCanonicalName();
for (Entry<String, URL> entry : fImagesUrlByClass.entrySet()) {
if (entry.getKey().equals(className)) {
return entry.getValue();
}
}
return null;
}
/**
* Returns language settings provider Options page registered for closest superclass.
*
* @param provider - instance of provider to create Options page for.
* @return image or {@code null}.
*/
public static ICOptionPage createOptionsPage(ILanguageSettingsProvider provider) {
String id = provider.getId();
ICOptionPage optionsPage = createOptionsPageById(id);
if (optionsPage != null) {
return optionsPage;
}
Class<? extends ILanguageSettingsProvider> clazz = provider.getClass();
outer: for (Class<?> c = clazz ;c != null; c = c.getSuperclass()) {
optionsPage = createOptionsPageByClass(c);
if (optionsPage != null) {
break;
}
// this does not check for super-interfaces, feel free to implement as needed
for (Class<?> i : c.getInterfaces()) {
optionsPage = createOptionsPageByClass(i);
if (optionsPage != null) {
break outer;
}
}
}
return optionsPage;
}
/**
* Create an Options page for language settings provider class.
*/
private static ICOptionPage createOptionsPageByClass(Class<?> clazz) {
ICOptionPage optionsPage = null;
String className = clazz.getCanonicalName();
if (fRegisteredClasses.contains(className)) {
optionsPage = createOptionsPageByClass(className);
}
return optionsPage;
}
/**
* Returns value of the attribute of the provider by id or closest superclass.
*/
private static boolean getBooleanAttribute(ILanguageSettingsProvider provider, String attr) {
loadExtensions();
String id = provider.getId();
Map<String, String> properties = fAssociationsById.get(id);
if (properties != null) {
return Boolean.parseBoolean(properties.get(attr));
}
for (Class<?> c = provider.getClass();c != null; c = c.getSuperclass()) {
String className = c.getCanonicalName();
properties = fAssociationsByClass.get(className);
if (properties != null) {
return Boolean.parseBoolean(properties.get(attr));
}
// this does not check for superinterfaces, feel free to implement as needed
for (Class<?> i : c.getInterfaces()) {
String interfaceName = i.getCanonicalName();
properties = fAssociationsByClass.get(interfaceName);
if (properties != null) {
return Boolean.parseBoolean(properties.get(attr));
}
}
}
return false;
}
/**
* Check if the user is allowed to edit language settings provider entries in UI.
* @param provider - language settings provider.
* @return {@code true} if editing is allowed or {@code false} if not.
*/
public static boolean isAllowedToEditEntries(ILanguageSettingsProvider provider) {
return getBooleanAttribute(provider, ATTR_UI_EDIT_ENTRIES);
}
/**
* Check if the user is allowed to clear language settings provider entries in UI.
* @param provider - language settings provider.
* @return {@code true} if clearing is allowed or {@code false} if not.
*/
public static boolean isAllowedToClear(ILanguageSettingsProvider provider) {
return getBooleanAttribute(provider, ATTR_UI_CLEAR_ENTRIES);
}
}