blob: 9aef723ea94f71b9e3248c1e8efd93d6ff752c52 [file] [log] [blame]
/**************************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*************************************************************/
package com.sun.star.wizards.ui.event;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import com.sun.star.wizards.common.PropertyNames;
/**
* @author rpiterman
* DataAware objects are used to live-synchronize UI and DataModel/DataObject.
* It is used as listener on UI events, to keep the DataObject up to date.
* This class, as a base abstract class, sets a frame of functionality,
* delegating the data Object get/set methods to a Value object,
* and leaving the UI get/set methods abstract.
* Note that event listenning is *not* a part of this model.
* the updateData() or updateUI() methods should be porogramatically called.
* in child classes, the updateData() will be binded to UI event calls.
* <br><br>
* This class holds references to a Data Object and a Value object.
* The Value object "knows" how to get and set a value from the
* Data Object.
*/
public abstract class DataAware {
/**
* this is the data object.
*/
protected Object dataObject;
//protected Method setMethod;
//protected Method getMethod;
/**
* A Value Object knows how to get/set a value
* from/to the data object.
*/
protected Value value;
/**
* creates a DataAware object for the given data object and Value object.
* @param dataObject_
* @param value_
*/
protected DataAware(Object dataObject_, Value value_) {
dataObject = dataObject_;
value = value_;
//getMethod = createGetMethod(dataPropName, dataObject);
//setMethod = createSetMethod(dataPropName, dataObject, getMethod.getReturnType());
}
/**
* returns the data object.
* @return
*/
public Object getDataObject() {
return dataObject;
}
/**
* sets a new data object. Optionally
* update the UI.
* @param obj the new data object.
* @param updateUI if true updateUI() will be called.
*/
public void setDataObject(Object obj, boolean updateUI) {
if (obj != null && !value.isAssignable(obj.getClass()))
throw new ClassCastException("can not cast new DataObject to original Class");
dataObject = obj;
if (updateUI)
updateUI();
}
/**
* Sets the given value to the data object.
* this method delegates the job to the
* Value object, but can be overwritten if
* another kind of Data is needed.
* @param newValue the new value to set to the DataObject.
*/
protected void setToData(Object newValue) {
value.set(newValue,getDataObject());
}
/**
* gets the current value from the data obejct.
* this method delegates the job to
* the value object.
* @return the current value of the data object.
*/
protected Object getFromData() {
return value.get(getDataObject());
}
/**
* sets the given value to the UI control
* @param newValue the value to set to the ui control.
*/
protected abstract void setToUI(Object newValue);
/**
* gets the current value from the UI control.
* @return the current value from the UI control.
*/
protected abstract Object getFromUI();
/**
* updates the UI control according to the
* current state of the data object.
*/
public void updateUI() {
Object data = getFromData();
Object ui = getFromUI();
if (!equals(data, ui))
try {
setToUI(data);
} catch (Exception ex) {
ex.printStackTrace();
//TODO tell user...
}
enableControls(data);
}
/**
* enables
* @param currentValue
*/
protected void enableControls(Object currentValue) {
}
/**
* updates the DataObject according to
* the current state of the UI control.
*/
public void updateData() {
Object data = getFromData();
Object ui = getFromUI();
if (!equals(data, ui))
setToData(ui);
enableControls(ui);
}
public interface Listener {
public void eventPerformed(Object event);
}
/**
* compares the two given objects.
* This method is null safe and returns true also if both are null...
* If both are arrays, treats them as array of short and compares them.
* @param a first object to compare
* @param b second object to compare.
* @return true if both are null or both are equal.
*/
protected boolean equals(Object a, Object b) {
if (a == null && b == null)
return true;
if (a == null || b == null)
return false;
if (a.getClass().isArray()) {
if (b.getClass().isArray())
return Arrays.equals((short[]) a, (short[]) b);
else
return false;
}
return a.equals(b);
}
/**
* given a collection containing DataAware objects,
* calls updateUI() on each memebr of the collection.
* @param dataAwares a collection containing DataAware objects.
*/
public static void updateUI(Collection dataAwares) {
for (Iterator i = dataAwares.iterator(); i.hasNext();)
((DataAware) i.next()).updateUI();
}
public static void updateData(Collection dataAwares) {
for (Iterator i = dataAwares.iterator(); i.hasNext();)
((DataAware) i.next()).updateData();
}
/**
* /**
* Given a collection containing DataAware objects,
* sets the given DataObject to each DataAware object
* in the given collection
* @param dataAwares a collection of DataAware objects.
* @param dataObject new data object to set to the DataAware objects in the given collection.
* @param updateUI if true, calls updateUI() on each DataAware object.
*/public static void setDataObject(Collection dataAwares, Object dataObject, boolean updateUI) {
for (Iterator i = dataAwares.iterator(); i.hasNext();)
((DataAware) i.next()).setDataObject(dataObject, updateUI);
}
/**
* Value objects read and write a value from and
* to an object. Typically using reflection and JavaBeans properties
* or directly using memeber reflection API.
* DataAware delegates the handling of the DataObject
* to a Value object.
* 2 implementations currently exist: PropertyValue,
* using JavaBeans properties reflection, and DataAwareFields classes
* which implement different memeber types.
*/
public interface Value {
/**
* gets a value from the given object.
* @param target the object to get the value from.
* @return the value from the given object.
*/
public Object get(Object target);
/**
* sets a value to the given object.
* @param value the value to set to the object.
* @param target the object to set the value to.
*/
public void set(Object value, Object target);
/**
* checks if this Value object can handle
* the given object type as a target.
* @param type the type of a target to check
* @return true if the given class is acceptible for
* the Value object. False if not.
*/
public boolean isAssignable(Class type);
}
/**
* implementation of Value, handling JavaBeans properties through
* reflection.
* This Object gets and sets a value a specific
* (JavaBean-style) property on a given object.
* @author rp143992
*/
public static class PropertyValue implements Value {
/**
* the get method of the JavaBean-style property
*/
private Method getMethod;
/**
* the set method of the JavaBean-style property
*/
private Method setMethod;
/**
* creates a PropertyValue for the property with
* the given name, of the given JavaBean object.
* @param propertyName the property to access. Must be a Cup letter (e.g. PropertyNames.PROPERTY_NAME for getName() and setName("..."). )
* @param propertyOwner the object which "own" or "contains" the property.
*/
public PropertyValue(String propertyName, Object propertyOwner) {
getMethod = createGetMethod(propertyName, propertyOwner);
setMethod = createSetMethod(propertyName, propertyOwner, getMethod.getReturnType());
}
/**
* called from the constructor, and creates a get method reflection object
* for the given property and object.
* @param propName the property name0
* @param obj the object which contains the property.
* @return the get method reflection object.
*/
private static Class[] EMPTY_ARRAY = new Class[0];
protected Method createGetMethod(String propName, Object obj)
{
Method m = null;
try
{ //try to get a "get" method.
m = obj.getClass().getMethod("get" + propName, EMPTY_ARRAY);
}
catch (NoSuchMethodException ex1)
{
throw new IllegalArgumentException("get" + propName + "() method does not exist on " + obj.getClass().getName());
}
return m;
}
/* (non-Javadoc)
* @see com.sun.star.wizards.ui.event.DataAware.Value#get(java.lang.Object)
*/
public Object get(Object target) {
try {
return getMethod.invoke(target, EMPTY_ARRAY);
} catch (IllegalAccessException ex1) {
ex1.printStackTrace();
} catch (InvocationTargetException ex2) {
ex2.printStackTrace();
} catch (NullPointerException npe) {
if (getMethod.getReturnType().equals(String.class))
return PropertyNames.EMPTY_STRING;
if (getMethod.getReturnType().equals(Short.class))
return new Short((short) 0);
if (getMethod.getReturnType().equals(Integer.class))
return 0;
if (getMethod.getReturnType().equals(short[].class))
return new short[0];
}
return null;
}
protected Method createSetMethod(String propName, Object obj, Class paramClass) {
Method m = null;
try {
m = obj.getClass().getMethod("set" + propName, new Class[] { paramClass });
} catch (NoSuchMethodException ex1) {
throw new IllegalArgumentException("set" + propName + "(" + getMethod.getReturnType().getName() + ") method does not exist on " + obj.getClass().getName());
}
return m;
}
/* (non-Javadoc)
* @see com.sun.star.wizards.ui.event.DataAware.Value#set(java.lang.Object, java.lang.Object)
*/
public void set(Object value, Object target) {
try {
setMethod.invoke(target, value);
} catch (IllegalAccessException ex1) {
ex1.printStackTrace();
} catch (InvocationTargetException ex2) {
ex2.printStackTrace();
}
}
/* (non-Javadoc)
* @see com.sun.star.wizards.ui.event.DataAware.Value#isAssignable(java.lang.Class)
*/
public boolean isAssignable(Class type) {
return getMethod.getDeclaringClass().isAssignableFrom(type) &&
setMethod.getDeclaringClass().isAssignableFrom(type);
}
}
}