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.

PropertysetItem.java 9.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338
  1. /*
  2. @VaadinApache2LicenseForJavaFiles@
  3. */
  4. package com.vaadin.data.util;
  5. import java.util.Collection;
  6. import java.util.Collections;
  7. import java.util.EventObject;
  8. import java.util.HashMap;
  9. import java.util.Iterator;
  10. import java.util.LinkedList;
  11. import com.vaadin.data.Item;
  12. import com.vaadin.data.Property;
  13. /**
  14. * Class for handling a set of identified Properties. The elements contained in
  15. * a </code>MapItem</code> can be referenced using locally unique identifiers.
  16. * The class supports listeners who are interested in changes to the Property
  17. * set managed by the class.
  18. *
  19. * @author Vaadin Ltd.
  20. * @since 3.0
  21. */
  22. @SuppressWarnings("serial")
  23. public class PropertysetItem implements Item, Item.PropertySetChangeNotifier,
  24. Cloneable {
  25. /* Private representation of the item */
  26. /**
  27. * Mapping from property id to property.
  28. */
  29. private HashMap<Object, Property<?>> map = new HashMap<Object, Property<?>>();
  30. /**
  31. * List of all property ids to maintain the order.
  32. */
  33. private LinkedList<Object> list = new LinkedList<Object>();
  34. /**
  35. * List of property set modification listeners.
  36. */
  37. private LinkedList<Item.PropertySetChangeListener> propertySetChangeListeners = null;
  38. /* Item methods */
  39. /**
  40. * Gets the Property corresponding to the given Property ID stored in the
  41. * Item. If the Item does not contain the Property, <code>null</code> is
  42. * returned.
  43. *
  44. * @param id
  45. * the identifier of the Property to get.
  46. * @return the Property with the given ID or <code>null</code>
  47. */
  48. @Override
  49. public Property<?> getItemProperty(Object id) {
  50. return map.get(id);
  51. }
  52. /**
  53. * Gets the collection of IDs of all Properties stored in the Item.
  54. *
  55. * @return unmodifiable collection containing IDs of the Properties stored
  56. * the Item
  57. */
  58. @Override
  59. public Collection<?> getItemPropertyIds() {
  60. return Collections.unmodifiableCollection(list);
  61. }
  62. /* Item.Managed methods */
  63. /**
  64. * Removes the Property identified by ID from the Item. This functionality
  65. * is optional. If the method is not implemented, the method always returns
  66. * <code>false</code>.
  67. *
  68. * @param id
  69. * the ID of the Property to be removed.
  70. * @return <code>true</code> if the operation succeeded <code>false</code>
  71. * if not
  72. */
  73. @Override
  74. public boolean removeItemProperty(Object id) {
  75. // Cant remove missing properties
  76. if (map.remove(id) == null) {
  77. return false;
  78. }
  79. list.remove(id);
  80. // Send change events
  81. fireItemPropertySetChange();
  82. return true;
  83. }
  84. /**
  85. * Tries to add a new Property into the Item.
  86. *
  87. * @param id
  88. * the ID of the new Property.
  89. * @param property
  90. * the Property to be added and associated with the id.
  91. * @return <code>true</code> if the operation succeeded, <code>false</code>
  92. * if not
  93. */
  94. @Override
  95. public boolean addItemProperty(Object id, Property property) {
  96. // Null ids are not accepted
  97. if (id == null) {
  98. throw new NullPointerException("Item property id can not be null");
  99. }
  100. // Cant add a property twice
  101. if (map.containsKey(id)) {
  102. return false;
  103. }
  104. // Put the property to map
  105. map.put(id, property);
  106. list.add(id);
  107. // Send event
  108. fireItemPropertySetChange();
  109. return true;
  110. }
  111. /**
  112. * Gets the <code>String</code> representation of the contents of the Item.
  113. * The format of the string is a space separated catenation of the
  114. * <code>String</code> representations of the Properties contained by the
  115. * Item.
  116. *
  117. * @return <code>String</code> representation of the Item contents
  118. */
  119. @Override
  120. public String toString() {
  121. String retValue = "";
  122. for (final Iterator<?> i = getItemPropertyIds().iterator(); i.hasNext();) {
  123. final Object propertyId = i.next();
  124. retValue += getItemProperty(propertyId).getValue();
  125. if (i.hasNext()) {
  126. retValue += " ";
  127. }
  128. }
  129. return retValue;
  130. }
  131. /* Notifiers */
  132. /**
  133. * An <code>event</code> object specifying an Item whose Property set has
  134. * changed.
  135. *
  136. * @author Vaadin Ltd.
  137. * @version
  138. * @VERSION@
  139. * @since 3.0
  140. */
  141. private static class PropertySetChangeEvent extends EventObject implements
  142. Item.PropertySetChangeEvent {
  143. private PropertySetChangeEvent(Item source) {
  144. super(source);
  145. }
  146. /**
  147. * Gets the Item whose Property set has changed.
  148. *
  149. * @return source object of the event as an <code>Item</code>
  150. */
  151. @Override
  152. public Item getItem() {
  153. return (Item) getSource();
  154. }
  155. }
  156. /**
  157. * Registers a new property set change listener for this Item.
  158. *
  159. * @param listener
  160. * the new Listener to be registered.
  161. */
  162. @Override
  163. public void addListener(Item.PropertySetChangeListener listener) {
  164. if (propertySetChangeListeners == null) {
  165. propertySetChangeListeners = new LinkedList<PropertySetChangeListener>();
  166. }
  167. propertySetChangeListeners.add(listener);
  168. }
  169. /**
  170. * Removes a previously registered property set change listener.
  171. *
  172. * @param listener
  173. * the Listener to be removed.
  174. */
  175. @Override
  176. public void removeListener(Item.PropertySetChangeListener listener) {
  177. if (propertySetChangeListeners != null) {
  178. propertySetChangeListeners.remove(listener);
  179. }
  180. }
  181. /**
  182. * Sends a Property set change event to all interested listeners.
  183. */
  184. private void fireItemPropertySetChange() {
  185. if (propertySetChangeListeners != null) {
  186. final Object[] l = propertySetChangeListeners.toArray();
  187. final Item.PropertySetChangeEvent event = new PropertysetItem.PropertySetChangeEvent(
  188. this);
  189. for (int i = 0; i < l.length; i++) {
  190. ((Item.PropertySetChangeListener) l[i])
  191. .itemPropertySetChange(event);
  192. }
  193. }
  194. }
  195. public Collection<?> getListeners(Class<?> eventType) {
  196. if (Item.PropertySetChangeEvent.class.isAssignableFrom(eventType)) {
  197. if (propertySetChangeListeners == null) {
  198. return Collections.EMPTY_LIST;
  199. } else {
  200. return Collections
  201. .unmodifiableCollection(propertySetChangeListeners);
  202. }
  203. }
  204. return Collections.EMPTY_LIST;
  205. }
  206. /**
  207. * Creates and returns a copy of this object.
  208. * <p>
  209. * The method <code>clone</code> performs a shallow copy of the
  210. * <code>PropertysetItem</code>.
  211. * </p>
  212. * <p>
  213. * Note : All arrays are considered to implement the interface Cloneable.
  214. * Otherwise, this method creates a new instance of the class of this object
  215. * and initializes all its fields with exactly the contents of the
  216. * corresponding fields of this object, as if by assignment, the contents of
  217. * the fields are not themselves cloned. Thus, this method performs a
  218. * "shallow copy" of this object, not a "deep copy" operation.
  219. * </p>
  220. *
  221. * @throws CloneNotSupportedException
  222. * if the object's class does not support the Cloneable
  223. * interface.
  224. *
  225. * @see java.lang.Object#clone()
  226. */
  227. @Override
  228. public Object clone() throws CloneNotSupportedException {
  229. final PropertysetItem npsi = new PropertysetItem();
  230. npsi.list = list != null ? (LinkedList<Object>) list.clone() : null;
  231. npsi.propertySetChangeListeners = propertySetChangeListeners != null ? (LinkedList<PropertySetChangeListener>) propertySetChangeListeners
  232. .clone() : null;
  233. npsi.map = (HashMap<Object, Property<?>>) map.clone();
  234. return npsi;
  235. }
  236. /*
  237. * (non-Javadoc)
  238. *
  239. * @see java.lang.Object#equals(java.lang.Object)
  240. */
  241. @Override
  242. public boolean equals(Object obj) {
  243. if (obj == null || !(obj instanceof PropertysetItem)) {
  244. return false;
  245. }
  246. final PropertysetItem other = (PropertysetItem) obj;
  247. if (other.list != list) {
  248. if (other.list == null) {
  249. return false;
  250. }
  251. if (!other.list.equals(list)) {
  252. return false;
  253. }
  254. }
  255. if (other.map != map) {
  256. if (other.map == null) {
  257. return false;
  258. }
  259. if (!other.map.equals(map)) {
  260. return false;
  261. }
  262. }
  263. if (other.propertySetChangeListeners != propertySetChangeListeners) {
  264. boolean thisEmpty = (propertySetChangeListeners == null || propertySetChangeListeners
  265. .isEmpty());
  266. boolean otherEmpty = (other.propertySetChangeListeners == null || other.propertySetChangeListeners
  267. .isEmpty());
  268. if (thisEmpty && otherEmpty) {
  269. return true;
  270. }
  271. if (otherEmpty) {
  272. return false;
  273. }
  274. if (!other.propertySetChangeListeners
  275. .equals(propertySetChangeListeners)) {
  276. return false;
  277. }
  278. }
  279. return true;
  280. }
  281. /*
  282. * (non-Javadoc)
  283. *
  284. * @see java.lang.Object#hashCode()
  285. */
  286. @Override
  287. public int hashCode() {
  288. return (list == null ? 0 : list.hashCode())
  289. ^ (map == null ? 0 : map.hashCode())
  290. ^ ((propertySetChangeListeners == null || propertySetChangeListeners
  291. .isEmpty()) ? 0 : propertySetChangeListeners.hashCode());
  292. }
  293. }