blob: 4c44ba3cb67b09f05d193aa21145248408a635c1 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2012 Brian de Alwis 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:
* Brian de Alwis - cobbled together from other sources
* Angelo Zerr <angelo.zerr@gmail.com> - likely source of initial implementation
*******************************************************************************/
package org.eclipse.e4.ui.css.core.impl.engine;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import org.eclipse.core.internal.runtime.RuntimeLog;
import org.eclipse.core.runtime.CoreException;
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.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.e4.ui.css.core.dom.CSSStylableElement;
import org.eclipse.e4.ui.css.core.dom.properties.ICSSPropertyHandler;
import org.eclipse.e4.ui.css.core.dom.properties.providers.AbstractCSSPropertyHandlerProvider;
import org.eclipse.e4.ui.css.core.engine.CSSEngine;
import org.w3c.dom.css.CSSStyleDeclaration;
import org.w3c.dom.css.CSSValue;
public class RegistryCSSPropertyHandlerProvider extends
AbstractCSSPropertyHandlerProvider {
private static final String ATTR_COMPOSITE = "composite";
private static final String ATTR_ADAPTER = "adapter";
private static final String ATTR_NAME = "name";
private static final String ATTR_PROPERTY_NAME = "property-name";
private static final String ATTR_HANDLER = "handler";
private static final String ATTR_DEPRECATED = "deprecated";
private static final String PROPERTY_HANDLERS_EXTPOINT = "org.eclipse.e4.ui.css.core.propertyHandler";
/* the handlers extension point was originally in .swt */
private static final String DEPRECATED_PROPERTY_HANDLERS_EXTPOINT = "org.eclipse.e4.ui.css.swt.property.handler";
private IExtensionRegistry registry;
private boolean hasDeprecatedProperties = false; // mild optimization for
// getCSSProperties()
private Map<String, Map<String, ICSSPropertyHandler>> propertyHandlerMap = new HashMap<String, Map<String, ICSSPropertyHandler>>();;
public RegistryCSSPropertyHandlerProvider(IExtensionRegistry registry) {
this.registry = registry;
if (configure(DEPRECATED_PROPERTY_HANDLERS_EXTPOINT)) {
System.err.println("Extension point "
+ DEPRECATED_PROPERTY_HANDLERS_EXTPOINT
+ " is deprecated; use " + PROPERTY_HANDLERS_EXTPOINT);
}
configure(PROPERTY_HANDLERS_EXTPOINT);
}
public RegistryCSSPropertyHandlerProvider(IExtensionRegistry registry,
String extensionPointId) {
this.registry = registry;
// FIXME: should install a registry listener to make this dynamic
configure(extensionPointId);
}
/** @return true if some extensions were found */
protected boolean configure(String extensionPointId) {
IExtensionPoint extPoint = registry.getExtensionPoint(extensionPointId);
if (extPoint == null) {
return false;
}
IExtension[] extensions = extPoint.getExtensions();
if (extensions.length == 0) {
return false;
}
Map<String, Map<String, ICSSPropertyHandler>> handlersMap = new HashMap<String, Map<String, ICSSPropertyHandler>>();
for (IExtension e : extensions) {
for (IConfigurationElement ce : e.getConfigurationElements()) {
if (ce.getName().equals(ATTR_HANDLER)) {
// a single handler may implement a number of properties
String name = ce.getAttribute(ATTR_COMPOSITE);
String adapter = ce.getAttribute(ATTR_ADAPTER);
// if (className.equals(adapter)) {
IConfigurationElement[] children = ce.getChildren();
String[] names = new String[children.length];
String[] deprecated = new String[children.length];
for (int i = 0; i < children.length; i++) {
if (children[i].getName().equals(ATTR_PROPERTY_NAME)) {
names[i] = children[i].getAttribute(ATTR_NAME);
deprecated[i] = children[i]
.getAttribute(ATTR_DEPRECATED);
if (deprecated[i] != null) {
hasDeprecatedProperties = true;
}
}
}
try {
Map<String, ICSSPropertyHandler> adaptersMap = handlersMap
.get(adapter);
if (adaptersMap == null) {
handlersMap
.put(adapter,
adaptersMap = new HashMap<String, ICSSPropertyHandler>());
}
if (!adaptersMap.containsKey(name)) {
Object t = ce
.createExecutableExtension(ATTR_HANDLER);
if (t instanceof ICSSPropertyHandler) {
for (int i = 0; i < names.length; i++) {
adaptersMap
.put(names[i],
deprecated[i] == null ? (ICSSPropertyHandler) t
: new DeprecatedPropertyHandlerWrapper(
(ICSSPropertyHandler) t,
deprecated[i]));
}
} else {
logError("invalid property handler for " + name);
}
}
} catch (CoreException e1) {
logError("invalid property handler for " + name + ": "
+ e1);
}
}
}
}
propertyHandlerMap.putAll(handlersMap);
return true;
}
public Collection<ICSSPropertyHandler> getCSSPropertyHandlers(
String property) throws Exception {
List<ICSSPropertyHandler> handlers = new ArrayList<ICSSPropertyHandler>();
for (Map<String, ICSSPropertyHandler> perElement : propertyHandlerMap
.values()) {
ICSSPropertyHandler h = perElement.get(property);
if (h != null) {
handlers.add(h);
}
}
return handlers;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.e4.ui.css.core.dom.properties.providers.
* AbstractCSSPropertyHandlerProvider
* #getDefaultCSSStyleDeclaration(org.eclipse
* .e4.ui.css.core.engine.CSSEngine,
* org.eclipse.e4.ui.css.core.dom.CSSStylableElement,
* org.w3c.dom.css.CSSStyleDeclaration)
*/
protected CSSStyleDeclaration getDefaultCSSStyleDeclaration(
CSSEngine engine, CSSStylableElement stylableElement,
CSSStyleDeclaration newStyle, String pseudoE) throws Exception {
if (stylableElement.getDefaultStyleDeclaration(pseudoE) != null)
return stylableElement.getDefaultStyleDeclaration(pseudoE);
if (newStyle != null) {
StringBuffer style = null;
int length = newStyle.getLength();
for (int i = 0; i < length; i++) {
String propertyName = newStyle.item(i);
String[] compositePropertiesNames = engine
.getCSSCompositePropertiesNames(propertyName);
if (compositePropertiesNames != null) {
for (int j = 0; j < compositePropertiesNames.length; j++) {
propertyName = compositePropertiesNames[j];
String s = getCSSPropertyStyle(engine, stylableElement,
propertyName, pseudoE);
if (s != null) {
if (style == null)
style = new StringBuffer();
style.append(s);
}
}
} else {
String s = getCSSPropertyStyle(engine, stylableElement,
propertyName, pseudoE);
if (s != null) {
if (style == null)
style = new StringBuffer();
style.append(s);
}
}
}
if (style != null) {
CSSStyleDeclaration defaultStyleDeclaration = engine
.parseStyleDeclaration(style.toString());
stylableElement.setDefaultStyleDeclaration(pseudoE,
defaultStyleDeclaration);
return defaultStyleDeclaration;
}
}
return stylableElement.getDefaultStyleDeclaration(pseudoE);
}
public Collection<ICSSPropertyHandler> getCSSPropertyHandlers(
Object element, String property) throws Exception {
List<ICSSPropertyHandler> handlers = new ArrayList<ICSSPropertyHandler>();
Class<?> clazz = element.getClass();
while (clazz != Object.class) {
if (propertyHandlerMap.containsKey(clazz.getName())) {
ICSSPropertyHandler handler = propertyHandlerMap.get(
clazz.getName()).get(property);
if (handler != null) {
handlers.add(handler);
}
}
clazz = clazz.getSuperclass();
}
return handlers;
}
public Collection<String> getCSSProperties(Object element) {
// don't include deprecated elements
Set<String> properties = new HashSet<String>();
Class<?> clazz = element.getClass();
while (clazz != Object.class) {
Map<String, ICSSPropertyHandler> handlerMap = propertyHandlerMap
.get(clazz.getName());
if (handlerMap != null) {
if (!hasDeprecatedProperties) {
properties.addAll(handlerMap.keySet());
} else {
for (Entry<String, ICSSPropertyHandler> entry : handlerMap
.entrySet()) {
if (!(entry.getValue() instanceof DeprecatedPropertyHandlerWrapper)) {
properties.add(entry.getKey());
}
}
}
}
clazz = clazz.getSuperclass();
}
return properties;
}
protected void logError(String message) {
// we log as an error to ensure it's shown
RuntimeLog.log(new Status(IStatus.ERROR, "org.eclipse.e4.ui.css.core",
message));
}
private class DeprecatedPropertyHandlerWrapper implements
ICSSPropertyHandler {
private ICSSPropertyHandler delegate;
private String message;
private Set<String> logged = new HashSet<String>();
DeprecatedPropertyHandlerWrapper(ICSSPropertyHandler handler,
String message) {
delegate = handler;
this.message = message;
}
public boolean applyCSSProperty(Object element, String property,
CSSValue value, String pseudo, CSSEngine engine)
throws Exception {
logIfNecessary(property);
return delegate.applyCSSProperty(element, property, value, pseudo,
engine);
}
public String retrieveCSSProperty(Object element, String property,
String pseudo, CSSEngine engine) throws Exception {
logIfNecessary(property);
return delegate.retrieveCSSProperty(element, property, pseudo,
engine);
}
private void logIfNecessary(String property) {
if (!logged.contains(property)) {
logged.add(property);
logError("CSS property '" + property
+ "' has been deprecated: " + message);
}
}
}
}