/*
* Copyright (C) 2006-2016 DLR, Germany
*
* All rights reserved
*
* http://www.rcenvironment.de/
*/
package de.rcenvironment.core.gui.utils.common.configuration;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import org.eclipse.core.runtime.IAdapterFactory;
import org.eclipse.core.runtime.Platform;
import org.eclipse.jface.viewers.ILabelProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.ui.views.properties.IPropertyDescriptor;
import org.eclipse.ui.views.properties.IPropertySource;
import org.eclipse.ui.views.properties.IPropertySource2;
import org.eclipse.ui.views.properties.PropertyDescriptor;
import de.rcenvironment.core.gui.utils.common.configuration.ConfigurationViewerContentProvider.ArraySource;
import de.rcenvironment.core.utils.common.StringUtils;
import de.rcenvironment.core.utils.incubator.configuration.ConfigurationInfo;
import de.rcenvironment.core.utils.incubator.configuration.ConfigurationIntrospector;
import de.rcenvironment.core.utils.incubator.configuration.annotation.Configurable;
import de.rcenvironment.core.utils.incubator.configuration.annotation.Configuration;
/**
* A {@link IConfigurationSource} to wrap configuration beans to be displayed in a
* {@link ConfigurationViewer}.
*
* @author Christian Weiss
*/
public class BeanConfigurationSourceAdapter extends BeanPropertySourceAdapter
implements IConfigurationSource {
/**
* The {@link IAdapterFactory} responsible for generating the
* {@link BeanConfigurationSourceAdapter}s.
*
* @author Christian Weiss
*/
public static final class Factory implements IAdapterFactory {
/** The adapter classes provided through {@link BeanConfigurationSourceAdapter}. */
private static final Class<?>[] ADAPTER_CLASSES = new Class[] { IPropertySource.class, IPropertySource2.class,
IConfigurationSource.class };
/** The Constant applicable. */
private static final ThreadLocal<Boolean> APPLICABLE = new ThreadLocal<Boolean>();
/**
* {@inheritDoc}
*
* @see org.eclipse.core.runtime.IAdapterFactory#getAdapterList()
*/
@SuppressWarnings("rawtypes")
@Override
public Class[] getAdapterList() {
return ADAPTER_CLASSES;
}
/**
* {@inheritDoc}
*
* @see org.eclipse.core.runtime.IAdapterFactory#getAdapter(java.lang.Object,
* java.lang.Class)
*/
@SuppressWarnings("rawtypes")
@Override
public Object getAdapter(final Object adaptableObject,
final Class adapterType) {
boolean configuration = false;
Class<?> clazz = adaptableObject.getClass();
while (clazz.getSuperclass() != null) {
if (clazz.isAnnotationPresent(Configuration.class)) {
configuration = true;
break;
}
clazz = clazz.getSuperclass();
}
if (!configuration //
|| (APPLICABLE.get() != null && !APPLICABLE.get())) {
return null;
}
APPLICABLE.set(false);
try {
final Object adapter = AdapterManager.getInstance().getAdapter(
adaptableObject, adapterType);
if (adapter != null) {
return adapter;
}
} finally {
APPLICABLE.set(true);
}
return new BeanConfigurationSourceAdapter(adaptableObject);
}
}
static {
AdapterManager.getInstance().registerAdapters(new Factory(),
Object.class);
AdapterManager.getInstance().registerAdapters(
new ArrayConfigurationSourceAdapter.Factory(), ArraySource.class);
AdapterManager.getInstance().registerAdapters(
new ListConfigurationSourceAdapter.Factory(), List.class);
}
/** The {@link ConfigurationInfo} instance describing the configuration bean. */
private final ConfigurationInfo configurationInfo;
/** The mapping from property names to {@link IPropertyDescriptor}s. */
private final Map<String, IPropertyDescriptor> configurationPropertyDescriptors = new HashMap<String, IPropertyDescriptor>();
/** The {@link IPropertyDescriptor} representing the configuration properties. */
private IPropertyDescriptor[] configurationPropertyDescriptorsArray;
/**
* The constructor.
*
* @param source the configuration bean
*/
public BeanConfigurationSourceAdapter(final Object source) {
super(source);
configurationInfo = ConfigurationIntrospector
.getConfigurationInfo(source.getClass());
parse();
}
/**
* Initializes the {@link AdapterManager} with the generic {@link IAdapterFactory}s.
*/
public static void initialize() {
//
}
/**
* Parses the backing configuration bean.
*/
private void parse() {
final List<IPropertyDescriptor> configurationDescriptors = new LinkedList<IPropertyDescriptor>();
configurationPropertyDescriptors.clear();
for (final String propertyName : configurationInfo.getPropertyNames()) {
// if the property is managed by the BeanPropertySourceAdapter use its
// PropertyDescriptor, otherwise it is a complex configuration property which has to be
// handled appropriately
if (super.isManaged(propertyName)) {
configurationDescriptors.add(getPropertyDescriptor(propertyName));
} else {
final PropertyDescriptor descriptor;
// get a ValueProvider, if present to determine whether its supposed to be a fixed
// set of select options displayed in a select widget
final Configurable.ValueProvider valueProvider = configurationInfo
.getProperty(propertyName).getValueProvider();
// if there is no ValueProvider, it is an ordinary property,
// otherwise it is a property which shall be manipulated through a select widget
if (valueProvider == null) {
descriptor = new PropertyDescriptor(propertyName, propertyName);
} else {
SelectionPropertyDescriptor.ValueProvider valueProvider2 = null;
if (valueProvider != null) {
valueProvider.setObject(getBean());
valueProvider2 = new SelectionPropertyDescriptor.ValueProvider() {
@Override
public Object[] getValues() {
return valueProvider.getValues();
}
};
}
descriptor = new SelectionPropertyDescriptor(propertyName, propertyName, valueProvider2);
}
// prepare the LabelProvider for the property
final Configurable.LabelProvider labelProvider = configurationInfo
.getProperty(propertyName).getLabelProvider();
final ILabelProvider propertyLabelProvider = new LabelProvider() {
@Override
public String getText(final Object element) {
return labelProvider.getLabel(element);
}
};
descriptor.setLabelProvider(propertyLabelProvider);
configurationDescriptors.add(descriptor);
configurationPropertyDescriptors.put(propertyName, descriptor);
}
}
configurationPropertyDescriptorsArray = configurationDescriptors
.toArray(new IPropertyDescriptor[configurationDescriptors
.size()]);
}
/**
* {@inheritDoc}
*
* @see de.rcenvironment.core.gui.utils.common.configuration.IConfigurationSource#getConfigurationPropertyDescriptors()
*/
@Override
public IPropertyDescriptor[] getConfigurationPropertyDescriptors() {
return configurationPropertyDescriptorsArray;
}
/**
* {@inheritDoc}
*
* @see de.rcenvironment.core.gui.utils.common.configuration.BeanPropertySourceAdapter#isManaged(java.lang.Object)
*/
@Override
protected boolean isManaged(final Object id) {
if (super.isManaged(id)) {
return true;
}
final String key = id.toString();
return configurationInfo.getProperty(key) != null;
}
/**
* {@inheritDoc}
*
* @see de.rcenvironment.core.gui.utils.common.configuration.BeanPropertySourceAdapter#setPropertyValue(java.lang.Object,
* java.lang.Object)
*/
@Override
public void setPropertyValue(Object id, Object value) {
if (super.isManaged(id)) {
super.setPropertyValue(id, value);
return;
}
final String propertyName = id.toString();
configurationInfo.getProperty(propertyName).setValue(getBean(), value);
}
/**
* {@inheritDoc}
*
* @see de.rcenvironment.core.gui.utils.common.configuration.BeanPropertySourceAdapter#getPropertyValue(java.lang.Object)
*/
@Override
public Object getPropertyValue(Object id) {
if (super.isManaged(id)) {
return super.getPropertyValue(id);
}
final String propertyName = id.toString();
Object result = configurationInfo.getProperty(propertyName).getValue(
getBean());
return result;
}
/**
* An {@link IConfigurationSource} to adapt arrays of values to the {@link ConfigurationViewer}.
*/
public static final class ArrayConfigurationSourceAdapter implements
IConfigurationSource {
/**
* The {@link IAdapterFactory} class to generate instances of
* {@link ArrayConfigurationSourceAdapter} out of arrays.
*/
public static final class Factory implements IAdapterFactory {
/** The Constant ADAPTER_CLASSES. */
private static final Class<?>[] ADAPTER_CLASSES = new Class[] { IPropertySource.class, IPropertySource2.class,
IConfigurationSource.class };
/** The Constant applicable. */
private static final ThreadLocal<Boolean> APPLICABLE = new ThreadLocal<Boolean>();
/**
* {@inheritDoc}
*
* @see org.eclipse.core.runtime.IAdapterFactory#getAdapterList()
*/
@SuppressWarnings("rawtypes")
@Override
public Class[] getAdapterList() {
return ADAPTER_CLASSES;
}
/**
* {@inheritDoc}
*
* @see org.eclipse.core.runtime.IAdapterFactory#getAdapter(java.lang.Object,
* java.lang.Class)
*/
@SuppressWarnings("rawtypes")
@Override
public Object getAdapter(final Object adaptableObject,
final Class adapterType) {
boolean applicable = true;
if ((APPLICABLE.get() != null && !APPLICABLE.get())) {
applicable = false;
}
if (adaptableObject.getClass().getComponentType() == null //
&& !(adaptableObject instanceof ArraySource)) {
applicable = false;
}
Object result = null;
if (applicable) {
APPLICABLE.set(false);
try {
final Object adapter = Platform.getAdapterManager()
.getAdapter(adaptableObject, adapterType);
if (adapter != null) {
return adapter;
}
} finally {
APPLICABLE.set(true);
}
if (adaptableObject.getClass().getComponentType() != null) {
final Object[] array = (Object[]) adaptableObject;
result = new ArrayConfigurationSourceAdapter(array);
} else if (adaptableObject instanceof ArraySource) {
final ArraySource<?> arraySource = (ArraySource<?>) adaptableObject;
result = new ArrayConfigurationSourceAdapter(arraySource);
} else {
throw new AssertionError();
}
}
return result;
}
}
/** The base array. */
private final Object[] array;
/** The {@link ArraySource}. */
private final ArraySource<?> arraySource;
/**
* Instantiates a new {@link ArrayConfigurationSourceAdapter}.
*
* @param array the array
*/
public ArrayConfigurationSourceAdapter(final Object[] array) {
this.array = array;
this.arraySource = null;
}
/**
* Instantiates a new {@link ArrayConfigurationSourceAdapter}.
*
* @param array the array
*/
public ArrayConfigurationSourceAdapter(final ArraySource<?> arraySource) {
this.array = null;
this.arraySource = arraySource;
}
private Object[] getArray() {
if (array != null) {
return array;
} else {
return arraySource.getValue();
}
}
/**
* {@inheritDoc}
*
* @see org.eclipse.ui.views.properties.IPropertySource#getEditableValue()
*/
@Override
public Object getEditableValue() {
final Object[] arrayRef = getArray();
return StringUtils.format("%s [%d]", arrayRef.getClass().getComponentType()
.getSimpleName(), arrayRef.length);
}
/**
* {@inheritDoc}
*
* @see org.eclipse.ui.views.properties.IPropertySource2#isPropertySet(java.lang.Object)
*/
@Override
public boolean isPropertySet(Object id) {
return true;
}
/**
* {@inheritDoc}
*
* @see org.eclipse.ui.views.properties.IPropertySource#getPropertyValue(java.lang.Object)
*/
@Override
public Object getPropertyValue(Object id) {
final Object[] arrayRef = getArray();
final Integer index = (Integer) id;
return arrayRef[index];
}
/**
* {@inheritDoc}
*
* @see org.eclipse.ui.views.properties.IPropertySource2#isPropertyResettable(java.lang.Object)
*/
@Override
public boolean isPropertyResettable(Object id) {
return false;
}
/**
* {@inheritDoc}
*
* @see org.eclipse.ui.views.properties.IPropertySource#resetPropertyValue(java.lang.Object)
*/
@Override
public void resetPropertyValue(Object id) {
//
}
/**
* {@inheritDoc}
*
* @see org.eclipse.ui.views.properties.IPropertySource#getPropertyDescriptors()
*/
@Override
public IPropertyDescriptor[] getPropertyDescriptors() {
final Object[] arrayRef = getArray();
IPropertyDescriptor[] descriptors = new IPropertyDescriptor[arrayRef.length];
for (int index = 0; index < descriptors.length; ++index) {
descriptors[index] = new PropertyDescriptor(new Integer(
index), StringUtils.format("[%d]", index));
}
return descriptors;
}
/**
* {@inheritDoc}
*
* @see de.rcenvironment.core.gui.utils.common.configuration.IConfigurationSource#getConfigurationPropertyDescriptors()
*/
@Override
public IPropertyDescriptor[] getConfigurationPropertyDescriptors() {
return getPropertyDescriptors();
}
/**
* {@inheritDoc}
*
* @see org.eclipse.ui.views.properties.IPropertySource#setPropertyValue(java.lang.Object,
* java.lang.Object)
*/
@Override
public void setPropertyValue(Object id, Object value) {
final Object[] arrayRef = getArray();
final Integer index = (Integer) id;
arrayRef[index] = value;
}
}
/**
* An {@link IConfigurationSource} to adapt {@link List}s of values to the
* {@link ConfigurationViewer}.
*/
public static final class ListConfigurationSourceAdapter implements
IConfigurationSource {
/**
* The {@link IAdapterFactory} class to generate instances of
* {@link ArrayConfigurationSourceAdapter} out of arrays.
*/
public static final class Factory implements IAdapterFactory {
/** The Constant ADAPTER_CLASSES. */
private static final Class<?>[] ADAPTER_CLASSES = new Class[] { IPropertySource.class, IPropertySource2.class,
IConfigurationSource.class };
/** The Constant applicable. */
private static final ThreadLocal<Boolean> APPLICABLE = new ThreadLocal<Boolean>();
/**
* {@inheritDoc}
*
* @see org.eclipse.core.runtime.IAdapterFactory#getAdapterList()
*/
@SuppressWarnings("rawtypes")
@Override
public Class[] getAdapterList() {
return ADAPTER_CLASSES;
}
/**
* {@inheritDoc}
*
* @see org.eclipse.core.runtime.IAdapterFactory#getAdapter(java.lang.Object,
* java.lang.Class)
*/
@SuppressWarnings("rawtypes")
@Override
public Object getAdapter(final Object adaptableObject,
final Class adapterType) {
if ((APPLICABLE.get() != null && !APPLICABLE.get())) {
return null;
}
APPLICABLE.set(false);
try {
final Object adapter = Platform.getAdapterManager()
.getAdapter(adaptableObject, adapterType);
if (adapter != null) {
return adapter;
}
} finally {
APPLICABLE.set(true);
}
final List<?> list = (List<?>) adaptableObject;
return new ListConfigurationSourceAdapter(list);
}
}
/** The base list. */
private final List<?> list;
/**
* Instantiates a new {@link ListConfigurationSourceAdapter}.
*
* @param list the list
*/
public ListConfigurationSourceAdapter(final List<?> list) {
this.list = list;
}
/**
* {@inheritDoc}
*
* @see org.eclipse.ui.views.properties.IPropertySource#getEditableValue()
*/
@Override
public Object getEditableValue() {
return StringUtils.format("? [%d]", list.size());
}
/**
* {@inheritDoc}
*
* @see org.eclipse.ui.views.properties.IPropertySource2#isPropertySet(java.lang.Object)
*/
@Override
public boolean isPropertySet(Object id) {
return true;
}
/**
* {@inheritDoc}
*
* @see org.eclipse.ui.views.properties.IPropertySource#getPropertyValue(java.lang.Object)
*/
@Override
public Object getPropertyValue(Object id) {
final Integer index = (Integer) id;
return list.get(index);
}
/**
* {@inheritDoc}
*
* @see org.eclipse.ui.views.properties.IPropertySource2#isPropertyResettable(java.lang.Object)
*/
@Override
public boolean isPropertyResettable(Object id) {
return false;
}
/**
* {@inheritDoc}
*
* @see org.eclipse.ui.views.properties.IPropertySource#resetPropertyValue(java.lang.Object)
*/
@Override
public void resetPropertyValue(Object id) {
//
}
/**
* {@inheritDoc}
*
* @see org.eclipse.ui.views.properties.IPropertySource#getPropertyDescriptors()
*/
@Override
public IPropertyDescriptor[] getPropertyDescriptors() {
final IPropertyDescriptor[] descriptors = new IPropertyDescriptor[list.size()];
for (int index = 0; index < descriptors.length; ++index) {
descriptors[index] = new PropertyDescriptor(new Integer(
index), StringUtils.format("[%d]", index));
}
return descriptors;
}
/**
* {@inheritDoc}
*
* @see de.rcenvironment.core.gui.utils.common.configuration.IConfigurationSource#getConfigurationPropertyDescriptors()
*/
@Override
public IPropertyDescriptor[] getConfigurationPropertyDescriptors() {
return getPropertyDescriptors();
}
/**
* {@inheritDoc}
*
* @see org.eclipse.ui.views.properties.IPropertySource#setPropertyValue(java.lang.Object,
* java.lang.Object)
*/
@Override
public void setPropertyValue(Object id, Object value) {
throw new UnsupportedOperationException();
}
}
}