You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

ObjectProperty.java 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358
  1. /*
  2. @ITMillApache2LicenseForJavaFiles@
  3. */
  4. package com.itmill.toolkit.data.util;
  5. import java.lang.reflect.Constructor;
  6. import java.util.LinkedList;
  7. import com.itmill.toolkit.data.Property;
  8. /**
  9. * A simple data object containing one typed value. This class is a
  10. * straightforward implementation of the the
  11. * {@link com.itmill.toolkit.data.Property} interface.
  12. *
  13. * @author IT Mill Ltd.
  14. * @version
  15. * @VERSION@
  16. * @since 3.0
  17. */
  18. public class ObjectProperty implements Property, Property.ValueChangeNotifier,
  19. Property.ReadOnlyStatusChangeNotifier {
  20. /**
  21. * A boolean value storing the Property's read-only status information.
  22. */
  23. private boolean readOnly = false;
  24. /**
  25. * The value contained by the Property.
  26. */
  27. private Object value;
  28. /**
  29. * Data type of the Property's value.
  30. */
  31. private final Class type;
  32. /**
  33. * Internal list of registered value change listeners.
  34. */
  35. private LinkedList valueChangeListeners = null;
  36. /**
  37. * Internal list of registered read-only status change listeners.
  38. */
  39. private LinkedList readOnlyStatusChangeListeners = null;
  40. /**
  41. * Creates a new instance of ObjectProperty with the given value. The type
  42. * of the property is automatically initialized to be the type of the given
  43. * value.
  44. *
  45. * @param value
  46. * the Initial value of the Property.
  47. */
  48. public ObjectProperty(Object value) {
  49. this(value, value.getClass());
  50. }
  51. /**
  52. * Creates a new instance of ObjectProperty with the given value and type.
  53. *
  54. * @param value
  55. * the Initial value of the Property.
  56. * @param type
  57. * the type of the value. The value must be assignable to
  58. * given type.
  59. */
  60. public ObjectProperty(Object value, Class type) {
  61. // Set the values
  62. this.type = type;
  63. setValue(value);
  64. }
  65. /**
  66. * Creates a new instance of ObjectProperty with the given value, type and
  67. * read-only mode status.
  68. *
  69. * @param value
  70. * the Initial value of the property.
  71. * @param type
  72. * the type of the value. <code>value</code> must be
  73. * assignable to this type.
  74. * @param readOnly
  75. * Sets the read-only mode.
  76. */
  77. public ObjectProperty(Object value, Class type, boolean readOnly) {
  78. this(value, type);
  79. setReadOnly(readOnly);
  80. }
  81. /**
  82. * Returns the type of the ObjectProperty. The methods <code>getValue</code>
  83. * and <code>setValue</code> must be compatible with this type: one must
  84. * be able to safely cast the value returned from <code>getValue</code> to
  85. * the given type and pass any variable assignable to this type as an
  86. * argument to <code>setValue</code>.
  87. *
  88. * @return type of the Property
  89. */
  90. public final Class getType() {
  91. return type;
  92. }
  93. /**
  94. * Gets the value stored in the Property.
  95. *
  96. * @return the value stored in the Property
  97. */
  98. public Object getValue() {
  99. return value;
  100. }
  101. /**
  102. * Returns the value of the ObjectProperty in human readable textual format.
  103. * The return value should be assignable to the <code>setValue</code>
  104. * method if the Property is not in read-only mode.
  105. *
  106. * @return <code>String</code> representation of the value stored in the
  107. * ObjectProperty
  108. */
  109. public String toString() {
  110. final Object value = getValue();
  111. if (value != null) {
  112. return value.toString();
  113. } else {
  114. return null;
  115. }
  116. }
  117. /**
  118. * Tests if the Property is in read-only mode. In read-only mode calls to
  119. * the method <code>setValue</code> will throw
  120. * <code>ReadOnlyException</code>s and will not modify the value of the
  121. * Property.
  122. *
  123. * @return <code>true</code> if the Property is in read-only mode,
  124. * <code>false</code> if it's not
  125. */
  126. public boolean isReadOnly() {
  127. return readOnly;
  128. }
  129. /**
  130. * Sets the Property's read-only mode to the specified status.
  131. *
  132. * @param newStatus
  133. * the new read-only status of the Property.
  134. */
  135. public void setReadOnly(boolean newStatus) {
  136. if (newStatus != readOnly) {
  137. readOnly = newStatus;
  138. fireReadOnlyStatusChange();
  139. }
  140. }
  141. /**
  142. * Sets the value of the property. This method supports setting from
  143. * <code>String</code> if either <code>String</code> is directly
  144. * assignable to property type, or the type class contains a string
  145. * constructor.
  146. *
  147. * @param newValue
  148. * the New value of the property.
  149. * @throws <code>Property.ReadOnlyException</code> if the object is in
  150. * read-only mode
  151. * @throws <code>Property.ConversionException</code> if the newValue
  152. * can't be converted into the Property's native type
  153. * directly or through <code>String</code>
  154. */
  155. public void setValue(Object newValue) throws Property.ReadOnlyException,
  156. Property.ConversionException {
  157. // Checks the mode
  158. if (isReadOnly()) {
  159. throw new Property.ReadOnlyException();
  160. }
  161. // Tries to assign the compatible value directly
  162. if (newValue == null || type.isAssignableFrom(newValue.getClass())) {
  163. value = newValue;
  164. } else {
  165. try {
  166. // Gets the string constructor
  167. final Constructor constr = getType().getConstructor(
  168. new Class[] { String.class });
  169. // Creates new object from the string
  170. value = constr
  171. .newInstance(new Object[] { newValue.toString() });
  172. } catch (final java.lang.Exception e) {
  173. throw new Property.ConversionException(e);
  174. }
  175. }
  176. fireValueChange();
  177. }
  178. /* Events *************************************************************** */
  179. /**
  180. * An <code>Event</code> object specifying the ObjectProperty whose value
  181. * has changed.
  182. *
  183. * @author IT Mill Ltd.
  184. * @version
  185. * @VERSION@
  186. * @since 3.0
  187. */
  188. private class ValueChangeEvent extends java.util.EventObject implements
  189. Property.ValueChangeEvent {
  190. /**
  191. * Serial generated by eclipse.
  192. */
  193. private static final long serialVersionUID = 3256718468479725873L;
  194. /**
  195. * Constructs a new value change event for this object.
  196. *
  197. * @param source
  198. * the source object of the event.
  199. */
  200. protected ValueChangeEvent(ObjectProperty source) {
  201. super(source);
  202. }
  203. /**
  204. * Gets the Property whose read-only state has changed.
  205. *
  206. * @return source the Property of the event.
  207. */
  208. public Property getProperty() {
  209. return (Property) getSource();
  210. }
  211. }
  212. /**
  213. * An <code>Event</code> object specifying the Property whose read-only
  214. * status has been changed.
  215. *
  216. * @author IT Mill Ltd.
  217. * @version
  218. * @VERSION@
  219. * @since 3.0
  220. */
  221. private class ReadOnlyStatusChangeEvent extends java.util.EventObject
  222. implements Property.ReadOnlyStatusChangeEvent {
  223. /**
  224. * Serial generated by eclipse.
  225. */
  226. private static final long serialVersionUID = 3907208273529616696L;
  227. /**
  228. * Constructs a new read-only status change event for this object.
  229. *
  230. * @param source
  231. * source object of the event
  232. */
  233. protected ReadOnlyStatusChangeEvent(ObjectProperty source) {
  234. super(source);
  235. }
  236. /**
  237. * Gets the Property whose read-only state has changed.
  238. *
  239. * @return source Property of the event.
  240. */
  241. public Property getProperty() {
  242. return (Property) getSource();
  243. }
  244. }
  245. /**
  246. * Removes a previously registered value change listener.
  247. *
  248. * @param listener
  249. * the listener to be removed.
  250. */
  251. public void removeListener(Property.ValueChangeListener listener) {
  252. if (valueChangeListeners != null) {
  253. valueChangeListeners.remove(listener);
  254. }
  255. }
  256. /**
  257. * Registers a new value change listener for this ObjectProperty.
  258. *
  259. * @param listener
  260. * the new Listener to be registered
  261. */
  262. public void addListener(Property.ValueChangeListener listener) {
  263. if (valueChangeListeners == null) {
  264. valueChangeListeners = new LinkedList();
  265. }
  266. valueChangeListeners.add(listener);
  267. }
  268. /**
  269. * Registers a new read-only status change listener for this Property.
  270. *
  271. * @param listener
  272. * the new Listener to be registered
  273. */
  274. public void addListener(Property.ReadOnlyStatusChangeListener listener) {
  275. if (readOnlyStatusChangeListeners == null) {
  276. readOnlyStatusChangeListeners = new LinkedList();
  277. }
  278. readOnlyStatusChangeListeners.add(listener);
  279. }
  280. /**
  281. * Removes a previously registered read-only status change listener.
  282. *
  283. * @param listener
  284. * the listener to be removed.
  285. */
  286. public void removeListener(Property.ReadOnlyStatusChangeListener listener) {
  287. if (readOnlyStatusChangeListeners != null) {
  288. readOnlyStatusChangeListeners.remove(listener);
  289. }
  290. }
  291. /**
  292. * Sends a value change event to all registered listeners.
  293. */
  294. private void fireValueChange() {
  295. if (valueChangeListeners != null) {
  296. final Object[] l = valueChangeListeners.toArray();
  297. final Property.ValueChangeEvent event = new ObjectProperty.ValueChangeEvent(
  298. this);
  299. for (int i = 0; i < l.length; i++) {
  300. ((Property.ValueChangeListener) l[i]).valueChange(event);
  301. }
  302. }
  303. }
  304. /**
  305. * Sends a read only status change event to all registered listeners.
  306. */
  307. private void fireReadOnlyStatusChange() {
  308. if (readOnlyStatusChangeListeners != null) {
  309. final Object[] l = readOnlyStatusChangeListeners.toArray();
  310. final Property.ReadOnlyStatusChangeEvent event = new ObjectProperty.ReadOnlyStatusChangeEvent(
  311. this);
  312. for (int i = 0; i < l.length; i++) {
  313. ((Property.ReadOnlyStatusChangeListener) l[i])
  314. .readOnlyStatusChange(event);
  315. }
  316. }
  317. }
  318. }