001: /* *************************************************************************
002:
003: Millstone(TM)
004: Open Sourced User Interface Library for
005: Internet Development with Java
006:
007: Millstone is a registered trademark of IT Mill Ltd
008: Copyright (C) 2000-2005 IT Mill Ltd
009:
010: *************************************************************************
011:
012: This library is free software; you can redistribute it and/or
013: modify it under the terms of the GNU Lesser General Public
014: license version 2.1 as published by the Free Software Foundation.
015:
016: This library is distributed in the hope that it will be useful,
017: but WITHOUT ANY WARRANTY; without even the implied warranty of
018: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
019: Lesser General Public License for more details.
020:
021: You should have received a copy of the GNU Lesser General Public
022: License along with this library; if not, write to the Free Software
023: Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
024:
025: *************************************************************************
026:
027: For more information, contact:
028:
029: IT Mill Ltd phone: +358 2 4802 7180
030: Ruukinkatu 2-4 fax: +358 2 4802 7181
031: 20540, Turku email: info@itmill.com
032: Finland company www: www.itmill.com
033:
034: Primary source for MillStone information and releases: www.millstone.org
035:
036: ********************************************************************** */
037:
038: package org.millstone.base.data.util;
039:
040: import org.millstone.base.data.Property;
041: import java.lang.reflect.Constructor;
042: import java.util.LinkedList;
043:
044: /** A simple data object containing one typed value. This class is a
045: * straightforward implementation of the the
046: * {@link org.millstone.base.data.Property} interface.
047: *
048: * @author IT Mill Ltd.
049: * @version 3.1.1
050: * @since 3.0
051: */
052: public class ObjectProperty implements Property,
053: Property.ValueChangeNotifier,
054: Property.ReadOnlyStatusChangeNotifier {
055:
056: /** A boolean value storing the Property's read-only status
057: * information.
058: */
059: private boolean readOnly = false;
060:
061: /** The value contained by the Property. */
062: private Object value;
063:
064: /** Data type of the Property's value */
065: private Class type;
066:
067: /** Internal list of registered value change listeners. */
068: private LinkedList valueChangeListeners = null;
069:
070: /** Internal list of registered read-only status change listeners. */
071: private LinkedList readOnlyStatusChangeListeners = null;
072:
073: /** Creates a new instance of ObjectProperty with the given value.
074: * The type of the property is automatically initialized to be
075: * the type of the given value.
076: *
077: * @param value Initial value of the Property
078: */
079: public ObjectProperty(Object value) {
080: this (value, value.getClass());
081: }
082:
083: /** Creates a new instance of ObjectProperty with the given value and
084: * type.
085: *
086: * @param value Initial value of the Property
087: * @param type The type of the value. The value must be assignable to
088: * given type
089: */
090: public ObjectProperty(Object value, Class type) {
091:
092: // Set the values
093: this .type = type;
094: setValue(value);
095: }
096:
097: /** Creates a new instance of ObjectProperty with the given value, type
098: * and read-only mode status.
099: *
100: * @param value Initial value of the property.
101: * @param type The type of the value. <code>value</code> must be
102: * assignable to this type.
103: * @param readOnly Sets the read-only mode.
104: */
105: public ObjectProperty(Object value, Class type, boolean readOnly) {
106: this (value, type);
107: setReadOnly(readOnly);
108: }
109:
110: /** Returns the type of the ObjectProperty. The methods
111: * <code>getValue</code> and <code>setValue</code> must be compatible
112: * with this type: one must be able to safely cast the value returned
113: * from <code>getValue</code> to the given type and pass any variable
114: * assignable to this type as an argument to <code>setValue</code>.
115: *
116: * @return type of the Property
117: */
118: public final Class getType() {
119: return type;
120: }
121:
122: /** Gets the value stored in the Property.
123: *
124: * @return the value stored in the Property
125: */
126: public Object getValue() {
127: return value;
128: }
129:
130: /** Returns the value of the ObjectProperty in human readable textual
131: * format. The return value should be assignable to the
132: * <code>setValue</code> method if the Property is not in read-only
133: * mode.
134: *
135: * @return <code>String</code> representation of the value stored in the
136: * ObjectProperty
137: */
138: public String toString() {
139: Object value = getValue();
140: if (value != null)
141: return value.toString();
142: else
143: return null;
144: }
145:
146: /** Tests if the Property is in read-only mode. In read-only mode calls
147: * to the method <code>setValue</code> will throw
148: * <code>ReadOnlyException</code>s and will not modify the value of the
149: * Property.
150: *
151: * @return <code>true</code> if the Property is in read-only mode,
152: * <code>false</code> if it's not
153: */
154: public boolean isReadOnly() {
155: return readOnly;
156: }
157:
158: /** Sets the Property's read-only mode to the specified status.
159: *
160: * @param newStatus new read-only status of the Property
161: */
162: public void setReadOnly(boolean newStatus) {
163: readOnly = newStatus;
164: }
165:
166: /** Set the value of the property. This method supports setting from
167: * <code>String</code>s if either <code>String</code> is directly
168: * assignable to property type, or the type class contains a string
169: * constructor.
170: *
171: * @param newValue New value of the property.
172: * @throws <code>Property.ReadOnlyException</code> if the object is in
173: * read-only mode
174: * @throws <code>Property.ConversionException</code> if
175: * <code>newValue</code> can't be converted into the Property's native
176: * type directly or through <code>String</code>
177: */
178: public void setValue(Object newValue)
179: throws Property.ReadOnlyException,
180: Property.ConversionException {
181:
182: // Check the mode
183: if (isReadOnly())
184: throw new Property.ReadOnlyException();
185:
186: // Try to assign the compatible value directly
187: if (newValue == null
188: || type.isAssignableFrom(newValue.getClass()))
189: value = newValue;
190:
191: // Otherwise try to convert the value trough string constructor
192: else
193: try {
194:
195: // Get the string constructor
196: Constructor constr = getType().getConstructor(
197: new Class[] { String.class });
198:
199: // Create new object from the string
200: value = constr.newInstance(new Object[] { newValue
201: .toString() });
202:
203: } catch (java.lang.Exception e) {
204: throw new Property.ConversionException(e);
205: }
206:
207: fireValueChange();
208: }
209:
210: /* Events *************************************************************** */
211:
212: /** An <code>Event</code> object specifying the ObjectProperty whose value
213: * has changed.
214: * @author IT Mill Ltd.
215: * @version 3.1.1
216: * @since 3.0
217: */
218: private class ValueChangeEvent extends java.util.EventObject
219: implements Property.ValueChangeEvent {
220:
221: /**
222: * Serial generated by eclipse.
223: */
224: private static final long serialVersionUID = 3256718468479725873L;
225:
226: /** Constructs a new value change event for this object.
227: *
228: * @param source source object of the event
229: */
230: protected ValueChangeEvent(ObjectProperty source) {
231: super (source);
232: }
233:
234: /** Gets the Property whose read-only state has changed.
235: *
236: * @return source Property of the event.
237: */
238: public Property getProperty() {
239: return (Property) getSource();
240: }
241: }
242:
243: /** An <code>Event</code> object specifying the Property whose read-only
244: * status has been changed.
245: * @author IT Mill Ltd.
246: * @version 3.1.1
247: * @since 3.0
248: */
249: private class ReadOnlyStatusChangeEvent extends
250: java.util.EventObject implements
251: Property.ReadOnlyStatusChangeEvent {
252:
253: /**
254: * Serial generated by eclipse.
255: */
256: private static final long serialVersionUID = 3907208273529616696L;
257:
258: /** Constructs a new read-only status change event for this object.
259: *
260: * @param source source object of the event
261: */
262: protected ReadOnlyStatusChangeEvent(ObjectProperty source) {
263: super (source);
264: }
265:
266: /** Gets the Property whose read-only state has changed.
267: *
268: * @return source Property of the event.
269: */
270: public Property getProperty() {
271: return (Property) getSource();
272: }
273: }
274:
275: /** Remove a previously registered value change listener.
276: *
277: * @param listener listener to be removed
278: */
279: public void removeListener(Property.ValueChangeListener listener) {
280: if (valueChangeListeners != null)
281: valueChangeListeners.remove(listener);
282: }
283:
284: /** Registers a new value change listener for this ObjectProperty.
285: *
286: * @param listener the new Listener to be registered
287: */
288: public void addListener(Property.ValueChangeListener listener) {
289: if (valueChangeListeners == null)
290: valueChangeListeners = new LinkedList();
291: valueChangeListeners.add(listener);
292: }
293:
294: /** Registers a new read-only status change listener for this Property.
295: *
296: * @param listener the new Listener to be registered
297: */
298: public void addListener(
299: Property.ReadOnlyStatusChangeListener listener) {
300: if (readOnlyStatusChangeListeners == null)
301: readOnlyStatusChangeListeners = new LinkedList();
302: readOnlyStatusChangeListeners.add(listener);
303: }
304:
305: /** Remove a previously registered read-only status change listener.
306: *
307: * @param listener listener to be removed
308: */
309: public void removeListener(
310: Property.ReadOnlyStatusChangeListener listener) {
311: if (readOnlyStatusChangeListeners != null)
312: readOnlyStatusChangeListeners.remove(listener);
313: }
314:
315: /** Send a value change event to all registered listeners.
316: */
317: private void fireValueChange() {
318: if (valueChangeListeners != null) {
319: Object[] l = valueChangeListeners.toArray();
320: Property.ValueChangeEvent event = new ObjectProperty.ValueChangeEvent(
321: this );
322: for (int i = 0; i < l.length; i++)
323: ((Property.ValueChangeListener) l[i])
324: .valueChange(event);
325: }
326: }
327:
328: /** Send a read only status change event to all registered listeners.
329: */
330: private void fireReadOnlyStatusChange() {
331: if (readOnlyStatusChangeListeners != null) {
332: Object[] l = readOnlyStatusChangeListeners.toArray();
333: Property.ReadOnlyStatusChangeEvent event = new ObjectProperty.ReadOnlyStatusChangeEvent(
334: this );
335: for (int i = 0; i < l.length; i++)
336: ((Property.ReadOnlyStatusChangeListener) l[i])
337: .readOnlyStatusChange(event);
338: }
339: }
340: }
|