/************************************************************************* * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * Copyright 2008 by Sun Microsystems, Inc. * * OpenOffice.org - a multi-platform office productivity suite * * $RCSfile: DataAware.java,v $ * $Revision: 1.7 $ * * This file is part of OpenOffice.org. * * OpenOffice.org is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version 3 * only, as published by the Free Software Foundation. * * OpenOffice.org is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License version 3 for more details * (a copy is included in the LICENSE file that accompanied this code). * * You should have received a copy of the GNU Lesser General Public License * version 3 along with OpenOffice.org. If not, see * * for a copy of the LGPLv3 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; /** * @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. *

* 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. "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 ""; if (getMethod.getReturnType().equals(Short.class)) return new Short((short) 0); if (getMethod.getReturnType().equals(Integer.class)) return new Integer(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, new Object[] {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); } } }