aboutsummaryrefslogtreecommitdiffstats
path: root/src/com/itmill/toolkit/data/util/ObjectProperty.java
blob: c8b8abef4d262c8fc23a37723c4bbb7584fa3da2 (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
/* *************************************************************************
 
                               IT Mill Toolkit 

               Development of Browser User Interfaces Made Easy

                    Copyright (C) 2000-2006 IT Mill Ltd
                     
   *************************************************************************

   This product is distributed under commercial license that can be found
   from the product package on license.pdf. Use of this product might 
   require purchasing a commercial license from IT Mill Ltd. For guidelines 
   on usage, see licensing-guidelines.html

   *************************************************************************
   
   For more information, contact:
   
   IT Mill Ltd                           phone: +358 2 4802 7180
   Ruukinkatu 2-4                        fax:   +358 2 4802 7181
   20540, Turku                          email:  info@itmill.com
   Finland                               company www: www.itmill.com
   
   Primary source for information and releases: www.itmill.com

   ********************************************************************** */

package com.itmill.toolkit.data.util;

import com.itmill.toolkit.data.Property;

import java.lang.reflect.Constructor;
import java.util.LinkedList;

/** A simple data object containing one typed value. This class is a
 * straightforward implementation of the the
 * {@link com.itmill.toolkit.data.Property} interface.
 *
 * @author IT Mill Ltd.
 * @version @VERSION@
 * @since 3.0
 */
public class ObjectProperty implements Property, Property.ValueChangeNotifier,
Property.ReadOnlyStatusChangeNotifier {
  
  	/** A boolean value storing the Property's read-only status
  	 * information.
  	 */  
    private boolean readOnly = false;
  
  	/** The value contained by the Property. */  
    private Object value;
  
  	/** Data type of the Property's value */  
    private Class type;
  
  	/** Internal list of registered value change listeners. */  
    private LinkedList valueChangeListeners = null;
  
  	/** Internal list of registered read-only status change listeners. */
    private LinkedList readOnlyStatusChangeListeners = null;
    
    /** Creates a new instance of ObjectProperty with the given value.
     * The type of the property is automatically initialized to be
     * the type of the given value.
     *
     * @param value Initial value of the Property
     */
    public ObjectProperty(Object value) {
        this(value,value.getClass());
    }
    
    /** Creates a new instance of ObjectProperty with the given value and
     * type.
     * 
     * @param value Initial value of the Property
     * @param type The type of the value. The value must be assignable to
     * given type
     */
    public ObjectProperty(Object value, Class type) {
        
        // Set the values
        this.type = type;
        setValue(value);
    }
    
    /** Creates a new instance of ObjectProperty with the given value, type
     * and read-only mode status.
     * 
     * @param value Initial value of the property.
     * @param type The type of the value. <code>value</code> must be
     * assignable to this type.
     * @param readOnly Sets the read-only mode.
     */
    public ObjectProperty(Object value, Class type, boolean readOnly) {
        this(value,type);
        setReadOnly(readOnly);
    }
    
    /** Returns the type of the ObjectProperty. The methods
     * <code>getValue</code> and <code>setValue</code> must be compatible
     * with this type: one must be able to safely cast the value returned
     * from <code>getValue</code> to the given type and pass any variable
     * assignable to this type as an argument to <code>setValue</code>.
     * 
     * @return type of the Property
     */
    public final Class getType() {
        return type;
    }
    
    /** Gets the value stored in the Property.
     * 
     * @return the value stored in the Property
     */
    public Object getValue() {
        return value;
    }
    
    /** Returns the value of the ObjectProperty in human readable textual
     * format. The return value should be assignable to the
     * <code>setValue</code> method if the Property is not in read-only
     * mode.
     * 
     * @return <code>String</code> representation of the value stored in the
     * ObjectProperty
     */
    public String toString() {
    	Object value = getValue();
    	if (value != null) 
        	return value.toString();
        else 
        	return null;
    }
    
    /** Tests if the Property is in read-only mode. In read-only mode calls
     * to the method <code>setValue</code> will throw
     * <code>ReadOnlyException</code>s and will not modify the value of the
     * Property.
     *
     * @return <code>true</code> if the Property is in read-only mode,
     * <code>false</code> if it's not
     */
    public boolean isReadOnly() {
        return readOnly;
    }
    
    /** Sets the Property's read-only mode to the specified status.
     * 
     * @param newStatus new read-only status of the Property
     */	
    public void setReadOnly(boolean newStatus) {
    	if (newStatus != readOnly) {
    		readOnly = newStatus;
    		fireReadOnlyStatusChange();
    	}
    }
    
    /** Set the value of the property. This method supports setting from
     * <code>String</code>s if either <code>String</code> is directly
     * assignable to property type, or the type class contains a string
     * constructor.
     *
     * @param newValue New value of the property.
     * @throws <code>Property.ReadOnlyException</code> if the object is in
     * read-only mode
     * @throws <code>Property.ConversionException</code> if
     * <code>newValue</code> can't be converted into the Property's native
     * type directly or through <code>String</code>
     */
    public void setValue(Object newValue)
    throws Property.ReadOnlyException, Property.ConversionException {
        
        // Check the mode
        if (isReadOnly()) throw new Property.ReadOnlyException();
        
        // Try to assign the compatible value directly
        if (newValue == null || type.isAssignableFrom(newValue.getClass()))
            value = newValue;
        
        // Otherwise try to convert the value trough string constructor
        else try {
            
            // Get the string constructor
            Constructor constr =
            getType().getConstructor(new Class[] { String.class });
            
            // Create new object from the string
            value = constr.newInstance(new Object[] {newValue.toString()});
            
        } catch (java.lang.Exception e) {
            throw new Property.ConversionException(e);
        }

        fireValueChange();
    }

    /* Events *************************************************************** */
    
    /** An <code>Event</code> object specifying the ObjectProperty whose value
     * has changed.
     * @author IT Mill Ltd.
     * @version @VERSION@
     * @since 3.0
     */
    private class ValueChangeEvent extends java.util.EventObject
    implements Property.ValueChangeEvent {
        
        /**
         * Serial generated by eclipse.
         */
        private static final long serialVersionUID = 3256718468479725873L;

        /** Constructs a new value change event for this object.
         * 
         * @param source source object of the event
         */
        protected ValueChangeEvent(ObjectProperty source) {
            super(source);
        }
        
        /** Gets the Property whose read-only state has changed.
         * 
         * @return source Property of the event.
         */
        public Property getProperty() {
            return (Property) getSource();
        }
    }
    
   /** An <code>Event</code> object specifying the Property whose read-only
     * status has been changed.
     * @author IT Mill Ltd.
     * @version @VERSION@
     * @since 3.0
     */
	private class ReadOnlyStatusChangeEvent extends java.util.EventObject
    implements Property.ReadOnlyStatusChangeEvent {
        
        /**
         * Serial generated by eclipse.
         */
        private static final long serialVersionUID = 3907208273529616696L;

        /** Constructs a new read-only status change event for this object.
         * 
         * @param source source object of the event
         */
        protected ReadOnlyStatusChangeEvent(ObjectProperty source) {
            super(source);
        }
        
        /** Gets the Property whose read-only state has changed.
         * 
         * @return source Property of the event.
         */
        public Property getProperty() {
            return (Property) getSource();
        }
    }
    
    /** Remove a previously registered value change listener.
     * 
     * @param listener listener to be removed
     */
    public void removeListener(Property.ValueChangeListener listener) {
        if (valueChangeListeners != null) 
            valueChangeListeners.remove(listener);
    }
    
    /** Registers a new value change listener for this ObjectProperty.
     * 
     * @param listener the new Listener to be registered
     */
    public void addListener(Property.ValueChangeListener listener) {
        if (valueChangeListeners == null) 
            valueChangeListeners = new LinkedList();
        valueChangeListeners.add(listener);
    }
    
    /** Registers a new read-only status change listener for this Property.
     * 
     * @param listener the new Listener to be registered
     */
    public void addListener(Property.ReadOnlyStatusChangeListener listener) {
        if (readOnlyStatusChangeListeners == null)
            readOnlyStatusChangeListeners = new LinkedList();
        readOnlyStatusChangeListeners.add(listener);
    }
    
    /** Remove a previously registered read-only status change listener.
     * 
     * @param listener listener to be removed
     */
    public void removeListener(Property.ReadOnlyStatusChangeListener listener) {
        if (readOnlyStatusChangeListeners != null)
            readOnlyStatusChangeListeners.remove(listener);
    }
    
    /** Send a value change event to all registered listeners.
     */
    private void fireValueChange() {
        if (valueChangeListeners != null) {
            Object[] l = valueChangeListeners.toArray();
            Property.ValueChangeEvent event =
            new ObjectProperty.ValueChangeEvent(this);
            for (int i=0; i<l.length; i++)
                ((Property.ValueChangeListener)l[i]).valueChange(event);
        }
    }

    /** Send a read only status change event to all registered listeners.
     */
    private void fireReadOnlyStatusChange() {
        if (readOnlyStatusChangeListeners != null) {
            Object[] l = readOnlyStatusChangeListeners.toArray();
            Property.ReadOnlyStatusChangeEvent event =
            new ObjectProperty.ReadOnlyStatusChangeEvent(this);
            for (int i=0; i<l.length; i++)
                ((Property.ReadOnlyStatusChangeListener)l[i]).
                readOnlyStatusChange(event);
        }
    }
}