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 10KB

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