package org.eclipse.iee.editor.properties; import java.beans.Introspector; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.HashSet; import java.util.List; import java.util.Set; import org.eclipse.iee.core.document.PropertiesContainer; import org.eclipse.iee.core.document.Property; import org.eclipse.jface.viewers.CellEditor; import org.eclipse.jface.viewers.TextCellEditor; import org.eclipse.swt.widgets.Composite; import org.eclipse.ui.views.properties.IPropertyDescriptor; import org.eclipse.ui.views.properties.IPropertySource2; import org.eclipse.ui.views.properties.PropertyDescriptor; import com.google.common.base.Converter; import com.google.common.base.Strings; import com.google.common.primitives.Doubles; import com.google.common.primitives.Ints; public class ContainerPropertySource implements IPropertySource2 { private Object fObject; private IPropertyDescriptor[] fDescriptors; private PropertiesInfo root; public ContainerPropertySource(Object adaptableObject) { super(); fObject = adaptableObject; root = calculateInfo(fObject.getClass()); fDescriptors = calculateDescriptors(root, null, ""); } private PropertiesInfo calculateInfo(Class<?> clz) { PropertiesInfo info = new PropertiesInfo(); Field[] declaredFields = clz.getDeclaredFields(); for (Field field : declaredFields) { if (isProperty(field)) { info.getPropertyFields().put(getPropertyNameFromField(field), field); } } Method[] declaredMethods = clz.getDeclaredMethods(); for (Method method : declaredMethods) { if (isGetter(method)) { info.getPropertyGetters().put(getPropertyNameFromGetter(method), method); } else if (isSetter(method)) { String name = getPropertyNameFromSetter(method); Collection<Method> methods = info.getPropertySetters().get(name); if (methods == null) { methods = new HashSet<>(); info.getPropertySetters().put(name, methods); } methods.add(method); } } return info; } private IPropertyDescriptor[] calculateDescriptors(PropertiesInfo info, String category, String parentPath) { List<IPropertyDescriptor> descriptors = new ArrayList<>(); Set<String> properties = new HashSet<>(); properties.addAll(info.getPropertyFields().keySet()); properties.addAll(info.getPropertyGetters().keySet()); properties.addAll(info.getPropertySetters().keySet()); for (String string : properties) { PropertiesContainer propertiesContainer = info.getPropertyAnnotation(string, PropertiesContainer.class); String propertyPath = parentPath.length() > 0 ? parentPath + "." + string : string; if (propertiesContainer != null) { Class<?> propertyType = info.getPropertyType(string); PropertiesInfo subInfo = calculateInfo(propertyType); IPropertyDescriptor[] calculatedDescriptors = calculateDescriptors(subInfo, propertiesContainer.name(), propertyPath); List<IPropertyDescriptor> asList = Arrays.asList(calculatedDescriptors); descriptors.addAll(asList); } Property property = info.getPropertyAnnotation(string, Property.class); if (property != null) { final Class<?> propertyType = info.getPropertyType(string); String description = property.description(); PropertyDescriptor descriptor = new PropertyDescriptor(propertyPath, property.name()) { @Override public CellEditor createPropertyEditor(Composite parent) { final Converter<String, ?> converter; if (int.class.equals(propertyType) || Integer.class.equals(propertyType)) { converter = Ints.stringConverter(); } else if (double.class.equals(propertyType) || Double.class.equals(propertyType)) { converter = Doubles.stringConverter(); } else { converter = Converter.identity(); } return new TextCellEditor(parent) { @Override protected void doSetValue(Object value) { String str; if (value != null) { @SuppressWarnings("unchecked") Converter<Object, String> reverse = (Converter<Object, String>) converter.reverse(); str = reverse.convert(value); } else { str = ""; } super.doSetValue(str); } @Override protected Object doGetValue() { String value = (String) super.doGetValue(); if (Strings.isNullOrEmpty(value)) { return null; } return converter.convert(value); } }; } }; if (category != null) { descriptor.setCategory(category); } if (description != null) { descriptor.setDescription(description); } descriptors.add(descriptor); } } return (IPropertyDescriptor[]) descriptors.toArray(new IPropertyDescriptor[descriptors.size()]); } private String getPropertyNameFromField(Field field) { String name = field.getName(); if (name.length() > 1 && name.startsWith("f") && Character.isUpperCase(name.charAt(1))) { name = Introspector.decapitalize(name.substring(1)); } return name; } private String getPropertyNameFromSetter(Method method) { String name = method.getName(); if (name.startsWith("set")) { return Introspector.decapitalize(name.substring(3)); } throw new IllegalArgumentException("Method is not setter:" + method); } private String getPropertyNameFromGetter(Method method) { String name = method.getName(); if (name.startsWith("get")) { return Introspector.decapitalize(name.substring(3)); } else if (name.startsWith("is")) { return Introspector.decapitalize(name.substring(2)); } throw new IllegalArgumentException("Method is not getter:" + method); } private boolean isSetter(Method method) { String name = method.getName(); return method.getParameterTypes().length == 1 && name.length() > 3 && name.startsWith("set"); } private boolean isGetter(Method method) { String name = method.getName(); return method.getParameterTypes().length == 0 && name.length() > 3 && (name.startsWith("get") || name.startsWith("is")); } private boolean isProperty(Field field) { return !Modifier.isStatic(field.getModifiers()); } @Override public void setPropertyValue(Object id, Object value) { String strId = (String) id; String[] pathElements = strId.split("\\."); Object bean = fObject; if (pathElements.length > 1) { for (String string : Arrays.copyOf(pathElements, pathElements.length - 1)) { Method propertyGetter = calculateInfo(bean.getClass()).getPropertyGetter(string); if (propertyGetter != null) { try { bean = propertyGetter.invoke(bean); } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { e.printStackTrace(); } } } } Method propertySetter = calculateInfo(bean.getClass()).getPropertySetter(pathElements[pathElements.length - 1]); if (propertySetter != null) { try { propertySetter.invoke(bean, value); } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { e.printStackTrace(); } } } @Override public void resetPropertyValue(Object id) { } @Override public Object getPropertyValue(Object id) { String strId = (String) id; String[] pathElements = strId.split("\\."); Object result = fObject; for (String string : pathElements) { Method propertyGetter = calculateInfo(result.getClass()).getPropertyGetter(string); if (propertyGetter != null) { try { result = propertyGetter.invoke(result); if (result == null) { return null; } } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { e.printStackTrace(); } } else { return null; } } return convertResult(result); } private Object convertResult(Object result) { return result; } @Override public IPropertyDescriptor[] getPropertyDescriptors() { return fDescriptors; } @Override public Object getEditableValue() { return this; } @Override public boolean isPropertySet(Object id) { return false; } @Override public boolean isPropertyResettable(Object id) { return false; } }