/******************************************************************************* * Copyright (c) 2008 Hallvard Traetteberg. * 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: * Hallvard Traetteberg - initial API and implementation ******************************************************************************/ package org.eclipse.e4.tm.builder; import java.lang.reflect.Array; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import org.eclipse.core.runtime.IAdaptable; import org.eclipse.e4.tm.stringconverter.StringConversion; import org.eclipse.e4.tm.stringconverter.StringConverterContext; import org.eclipse.e4.tm.stringconverters.AbstractClassStringConverter; import org.eclipse.e4.tm.stringconverters.ClassStringConverter; import org.eclipse.emf.ecore.EClass; import org.eclipse.emf.ecore.EModelElement; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.EStructuralFeature; import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.emf.ecore.resource.URIConverter; import org.eclipse.emf.ecore.resource.impl.ExtensibleURIConverterImpl; import org.eclipse.emf.ecore.util.EcoreUtil; public abstract class AbstractBuilder implements IBuilder, StringConverterContext, IBinderContext { protected Object getToolkitComposite(Object context, Class<?> c) { if (c.isInstance(context)) { return context; } if (context instanceof IAdaptable) { return ((IAdaptable)context).getAdapter(c); } return null; } private Object root = null; public <T> T getRootObject(Class<T> c) { return adapt(root, c); } public void build(EObject control, Object context) { root = context; update(control); fireObjectHandled(IBuilderListener.BUILD, control, context); } private URIConverter uriConverter; public URIConverter getUriConverter() { if (uriConverter == null) { uriConverter = new ExtensibleURIConverterImpl(); } return uriConverter; } public void build(Resource res, Object context) { EObject eObject = res.getContents().get(0); // for (EObject eObject: res.getContents()) { build(eObject, context); // } } // private List<Object> disposables = new ArrayList<Object>(); public void registerDisposable(Object disposable) { disposables.add(disposable); } private StringConversion stringConversion = new StringConversion(); { stringConversion.setStringConverterContext(this); } public StringConversion getStringConverter() { return stringConversion; } public <T> T convert(String value, Class<T> klass) throws Exception { return stringConversion.convert(value, klass); } // private AbstractClassStringConverter classResolver = new ClassStringConverter(); public AbstractClassStringConverter getClassResolver() { return classResolver; } public Class<?> resolve(String className) { return classResolver.resolve(className); } public void dispose() { for (Object disposable: disposables) { dispose(disposable); } for (EObject eObject: eObject2ObjectMap.keySet()) { dispose(eObject); } eObject2ObjectMap.clear(); } static void dispose(Object disposable) { try { disposable.getClass().getMethod("dispose").invoke(disposable); } catch (Exception e) { } } // public static String getClassAnnotation(EClass eClass, String uri, String key, String def) { ArrayList<EClass> superClasses = new ArrayList<EClass>(eClass.getEAllSuperTypes()); superClasses.add(0, eClass); for (Iterator<EClass> it = superClasses.iterator(); it.hasNext();) { EClass superClass = it.next(); String value = EcoreUtil.getAnnotation(superClass, uri, key); if (value != null) { return value; } } return def; } public static String getFeatureAnnotation(EStructuralFeature feature, EClass realClass, String uri, String key, String def) { String value = null; EClass subClass = realClass; while (value == null && subClass != null && subClass != feature.eContainer()) { String altUri = uri + "#" + subClass.getName(); value = EcoreUtil.getAnnotation(feature, altUri, key); List<EClass> superTypes = subClass.getESuperTypes(); // try superclasses? subClass = (superTypes.size() > 0 ? superTypes.get(0) : null); } if (value == null) { value = EcoreUtil.getAnnotation(feature, uri, key); } if (value == null) { value = AbstractBuilder.getClassAnnotation(feature.getEContainingClass(), uri, key, def); } return value; } public static String getAnnotation(EModelElement element, String uri, String key, String def) { String value = EcoreUtil.getAnnotation(element, uri, key); return (value != null ? value : def); } public static String casify(String s, Boolean cas) { if (s.length() > 0 && cas != null) { char first = s.charAt(0); s = (cas.booleanValue() ? Character.toUpperCase(first) : Character.toLowerCase(first)) + s.substring(1); } return s; } // private Map<EObject, Object> eObject2ObjectMap = new HashMap<EObject, Object>(); private Map<Object, EObject> object2EObjectMap = new HashMap<Object, EObject>(); public <T> T getObject(EObject eObject, Class<T> c) { return getObject(eObject, c, false); } public EObject getEObject(Object object) { return object2EObjectMap.get(object); } public void putObject(EObject eObject, Object object) { eObject2ObjectMap.put(eObject, object); if (object != null) { object2EObjectMap.put(object, eObject); } } protected <T> T getObject(EObject eObject, Class<T> c, boolean searchContainers) { EObject eO = eObject; while ((eO == eObject || searchContainers) && eO != null) { Object o = eObject2ObjectMap.get(eO); if (! c.isInstance(o)) { // use eO to make sure we adapt using appropriate IBinder o = adapt(eO, o, c); } if (c.isInstance(o)) { return (T)o; } eO = eO.eContainer(); } return null; } private List<IBuilderListener> builderListeners = new ArrayList<IBuilderListener>(); public void addBuilderListener(IBuilderListener listener) { builderListeners.add(listener); } public void removeBuilderListener(IBuilderListener listener) { builderListeners.remove(listener); } public void fireObjectHandled(int id, EObject eObject, Object object) { for (IBuilderListener listener : builderListeners) { listener.objectHandled(id, eObject, object); } } public Object update(EObject eObject) { Object object = eObject2ObjectMap.get(eObject); IBinder binder = getBinder(eObject, true); Object newObject = binder.update(eObject, object, this); if (newObject != null) { eObject2ObjectMap.put(eObject, newObject); } fireObjectHandled(IBuilderListener.UPDATE, eObject, object); return newObject; } public void dispose(EObject eObject) { Object object = eObject2ObjectMap.get(eObject); if (object != null) { IBinder binder = getBinder(eObject, false); if (binder != null) { binder.dispose(eObject, object, this); fireObjectHandled(IBuilderListener.DISPOSE, eObject, object); } } } public void updateStyle(EObject eObject) { Object object = eObject2ObjectMap.get(eObject); IBinder binder = getBinder(eObject, false); if (binder != null) { binder.updateStyle(eObject, object, this); } fireObjectHandled(IBuilderListener.STYLED, eObject, object); } private BinderFactory binderFactory = new EClassNameBinderFactory(this); protected IBinder getBinder(EObject eObject, boolean throwException) { IBinder binder = binderFactory.getBinder(eObject); if (binder == null && throwException) { throw new RuntimeException("Couldn't get IBinder for eClass " + eObject.eClass().getName()); } return binder; } // support for IBinderContext public <T> T adapt(EObject eObject, Object value, Class<T> c) { if (eObject == null) { return adapt(value, c); } IBinder binder = getBinder(eObject, true); Object o = binder.adapt(value, c); if (! c.isInstance(o)) { o = adapt(value, c); } return (T)(c.isInstance(o) ? o : null); } public <T> T adapt(Object value, Class<T> c) { if (c.isPrimitive()) { c = ClassStringConverter.getObjectClass(c); } if (value == null) { if (c == URIConverter.class) { return (T)getUriConverter(); } return getRootObject(c); } else if (c.isInstance(value)) { return (T)value; } else if (value instanceof Collection && c.isArray()) { Collection<?> collection = (Collection<?>)value; Class<?> elementType = c.getComponentType(); Object array = Array.newInstance(elementType, collection.size()); int i = 0; for (Iterator<?> it = collection.iterator(); it.hasNext();) { Object o = it.next(); Object o2 = adapt(o, elementType); Array.set(array, i++, o2); } return (T)array; } else if (value instanceof String) { return getStringConverter().convert((String)value, c); } return null; } public void invalidateFeature(EObject eObject, String featureName) { while (eObject != null) { IBinder binder = getBinder(eObject, false); if (binder != null) { if (binder.validateFeature(eObject, getObject(eObject, Object.class), featureName, this)) { break; } } eObject = eObject.eContainer(); } } // private ReflectionSupport reflectionSupport = new ReflectionSupport(this); public Method getMethod(Object object, String signature) { return reflectionSupport.getMethod(object, signature); } public Object getGetterProperty(Object object, String name) { return reflectionSupport.getGetterProperty(object, name); } public Object getMethodProperty(Object object, String methodSpec, Object[] args) { return reflectionSupport.getMethodProperty(object, methodSpec, args); } public Object getFieldProperty(Object object, String name) { return reflectionSupport.getFieldProperty(object, name); } // public Exception setSetterProperty(Object object, String name, Object value) { return reflectionSupport.setSetterProperty(object, name, value); } public Exception setMethodProperty(Object object, String methodSpec, Object[] args) { return reflectionSupport.setMethodProperty(object, methodSpec, args); } public Exception setFieldProperty(Object object, String name, Object value) { return reflectionSupport.setFieldProperty(object, name, value); } public void setProperty(Object object, String name, Object value) throws Exception { reflectionSupport.setProperty(object, name, value); } }