summaryrefslogtreecommitdiff
path: root/wizards/com/sun/star/wizards/ui/event/DataAware.java
blob: 62eaaf657447fb2065b1ecc04ff487129adcea97 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2000, 2010 Oracle and/or its affiliates.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * 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
 * <http://www.openoffice.org/license.html>
 * 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;
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 "";
                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);
        }
    }
}