package org.goko.common.preferences.fieldeditor.ui; import java.lang.reflect.Method; import org.apache.commons.lang3.StringUtils; import org.eclipse.core.databinding.Binding; import org.eclipse.core.databinding.DataBindingContext; import org.eclipse.core.databinding.validation.IValidator; import org.eclipse.jface.util.IPropertyChangeListener; import org.eclipse.jface.util.PropertyChangeEvent; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.goko.common.bindings.AbstractModelObject; import org.goko.common.preferences.fieldeditor.IFieldEditor; import org.goko.core.common.exception.GkException; import org.goko.core.common.exception.GkTechnicalException; public abstract class UiFieldEditor<C extends Control> extends Composite implements IFieldEditor<C>, IValidator{ /** * Property name constant (value <code>"field_editor_is_valid"</code>) * to signal a change in the validity of the value of this field editor. */ public static final String IS_VALID = "field_editor_is_valid"; /** * Property name constant (value <code>"field_editor_value"</code>) * to signal a change in the value of this field editor. */ public static final String VALUE = "field_editor_value"; /** The name of the preference displayed in this field editor. */ protected String propertyName; /** The label's text. */ private String label; /** The associated control */ protected C control; /** Listener, or <code>null</code> if none */ private IPropertyChangeListener propertyChangeListener; /** * Constructor * @param parent * @param style */ public UiFieldEditor(Composite parent, int style){ super(parent, style); label = "Default"; } protected void createLayout(Composite parent){ GridLayout layout = new GridLayout(2, false); layout.marginHeight = 2; layout.marginWidth = 2; setLayout(layout); } protected void createControls(Composite parent, int style){ createLayout(parent); } @Override public void setEnabled(boolean enabled) { boolean wasEnabled = isEnabled(); super.setEnabled(enabled); if(!wasEnabled && enabled){ // try { // loadValue(); // } catch (GkException e) { // // TODO Auto-generated catch block // e.printStackTrace(); // } } } public boolean isValid(){ return true; } /** * Informs this field editor's listener, if it has one, about a change to * one of this field editor's boolean-valued properties. Does nothing * if the old and new values are the same. * * @param property the field editor property name, * such as <code>VALUE</code> or <code>IS_VALID</code> * @param oldValue the old value * @param newValue the new value */ protected void fireStateChanged(String property, boolean oldValue, boolean newValue) { if (oldValue == newValue) { return; } fireValueChanged(property, oldValue ? Boolean.TRUE : Boolean.FALSE, newValue ? Boolean.TRUE : Boolean.FALSE); } /** * Informs this field editor's listener, if it has one, about a change to * one of this field editor's properties. * * @param property the field editor property name, * such as <code>VALUE</code> or <code>IS_VALID</code> * @param oldValue the old value object, or <code>null</code> * @param newValue the new value, or <code>null</code> */ protected void fireValueChanged(String property, Object oldValue, Object newValue) { if (propertyChangeListener == null) { return; } propertyChangeListener.propertyChange(new PropertyChangeEvent(this, property, oldValue, newValue)); } /** * @return the propertyChangeListener */ public IPropertyChangeListener getPropertyChangeListener() { return propertyChangeListener; } /** * @param propertyChangeListener the propertyChangeListener to set */ public void setPropertyChangeListener(IPropertyChangeListener propertyChangeListener) { this.propertyChangeListener = propertyChangeListener; } /** * @return the control */ public C getControl() { return control; } /** * @return the label */ public String getLabel() { return label; } /** * @param label the label to set */ public void setLabel(String label) { this.label = label; } public Binding getBinding(DataBindingContext bindingContext, AbstractModelObject modelObject) throws GkException{ verifyGetter(modelObject,propertyName); verifySetter(modelObject,propertyName); return getFieldEditorBinding(bindingContext, modelObject); } protected abstract Binding getFieldEditorBinding(DataBindingContext bindingContext, AbstractModelObject modelObject) throws GkException; /** * Make sure the getter for the given property exists * @param source the source object * @param property the property to search for * @return the {@link Method} * @throws GkException GkException */ private Method verifyGetter(Object source, String property) throws GkException{ String firstLetter = StringUtils.substring(property, 0,1); String otherLetters = StringUtils.substring(property, 1); String getGetterName = "^get"+ StringUtils.upperCase(firstLetter)+otherLetters+"$"; String isGetterName = "^is"+ StringUtils.upperCase(firstLetter)+otherLetters+"$"; Method[] methodArray = source.getClass().getMethods(); for (Method method : methodArray) { //if(StringUtils.equals(getterName, method.getName())){ if(method.getName().matches(getGetterName) || method.getName().matches(isGetterName)){ return method; } } String getterNameDisplay = "get"+ StringUtils.upperCase(firstLetter)+otherLetters+"/is"+ StringUtils.upperCase(firstLetter)+otherLetters; throw new GkTechnicalException("Cannot find getter (looking for '"+getterNameDisplay+"') for property '"+property+"' on object "+source.getClass()+". Make sure it's public and correctly spelled"); } /** * Make sure the setter for the given property exists * @param source the source object * @param property the property to search for * @throws GkException GkException */ private void verifySetter(Object source, String property) throws GkException{ String firstLetter = StringUtils.substring(property, 0,1); String otherLetters = StringUtils.substring(property, 1); String setterName = "set"+ StringUtils.upperCase(firstLetter)+otherLetters; boolean found = false; Method getMethod = verifyGetter(source, property); Method[] methodArray = source.getClass().getMethods(); for (Method method : methodArray) { if(StringUtils.equals(setterName, method.getName())){ Class<?>[] paramsArray = method.getParameterTypes(); if(paramsArray != null && paramsArray.length == 1 && paramsArray[0] == getMethod.getReturnType()){ found = true; break; } } } //source.getClass().getDeclaredMethod(setterName, getMethod.getReturnType()); if(!found){ throw new GkTechnicalException("Cannot find setter (looking for '"+setterName+"') for property '"+property+"' on object "+source.getClass()+". Make sure it's public and correctly spelled"); } } /** * @return the propertyName */ public String getPropertyName() { return propertyName; } /** * @param propertyName the propertyName to set */ public void setPropertyName(String propertyName) { this.propertyName = propertyName; } }