View Javadoc

1   package cz.cuni.amis.utils.collections;
2   
3   import java.util.ArrayList;
4   import java.util.Collection;
5   import java.util.Collections;
6   import java.util.Iterator;
7   import java.util.LinkedList;
8   
9   import cz.cuni.amis.utils.listener.Listeners;
10  
11  /**
12   * Wrapper for collections. It raises events when elements are added/removed 
13   * from the collection.
14   * @author Ik
15   * @param <E>
16   */
17  public class ObservableCollection<E> implements Collection<E> {
18  
19      protected Collection<E> col = null;
20      protected Listeners<CollectionEventListener> eventListeners = new Listeners<CollectionEventListener>();
21      
22      private abstract class ListenerNotifier implements Listeners.ListenerNotifier<CollectionEventListener> {
23  
24      	public Collection what;
25      	public Collection where;
26      	
27      	public ListenerNotifier() {    		
28      	}
29      	
30  		@Override
31  		public Object getEvent() {
32  			return what;
33  		}
34  
35  		@Override
36  		public abstract void notify(CollectionEventListener listener);
37      	
38      }
39      
40      private ListenerNotifier preAddNotifier = new ListenerNotifier() {
41  		
42  		@Override
43  		public void notify(CollectionEventListener listener) {
44  			listener.preAddEvent(what, where);
45  		}
46  		
47  	};
48  	
49  	private ListenerNotifier postAddNotifier = new ListenerNotifier() {
50  		
51  		@Override
52  		public void notify(CollectionEventListener listener) {
53  			listener.postAddEvent(what, where);
54  		}
55  		
56  	};
57  	
58  	 private ListenerNotifier preRemoveNotifier = new ListenerNotifier() {
59  			
60  		@Override
61  		public void notify(CollectionEventListener listener) {
62  			listener.preRemoveEvent(what, where);
63  		}
64  		
65  	};
66  	
67  	private ListenerNotifier postRemoveNotifier = new ListenerNotifier() {
68  		
69  		@Override
70  		public void notify(CollectionEventListener listener) {
71  			listener.postRemoveEvent(what, where);
72  		}
73  		
74  	};
75  
76      public void addCollectionListener(CollectionEventListener listener) {
77          eventListeners.addStrongListener(listener);
78      }
79  
80      public boolean removeCollectionListener(CollectionEventListener listener) {
81          return eventListeners.removeListener(listener) > 0;
82      }
83  
84      public ObservableCollection(Collection c) {
85          col = c;
86      }
87  
88      @Override
89      public int size() {
90          return col.size();
91      }
92  
93      @Override
94      public boolean isEmpty() {
95          return col.isEmpty();
96      }
97  
98      @Override
99      public boolean contains(Object o) {
100         return col.contains(o);
101     }
102 
103     @Override
104     public Iterator<E> iterator() {
105         return col.iterator();
106     }
107 
108     @Override
109     public Object[] toArray() {
110         return col.toArray();
111     }
112 
113     @Override
114     public <T> T[] toArray(T[] a) {
115         return col.toArray(a);
116     }
117 
118     @Override
119     public boolean add(E e) {
120         Collection add = Collections.singletonList(e);
121         notifyPreAdd(add);
122         boolean ret = col.add(e);
123         notifyPostAdd(add);
124         return ret;
125     }
126 
127     @Override
128     public boolean remove(Object o) {
129         Collection rem = Collections.singletonList(o);
130         notifyPreRemove(rem);
131         boolean ret = col.remove(o);
132         notifyPostRemove(rem);
133         return ret;
134     }
135 
136     @Override
137     public boolean containsAll(Collection<?> c) {
138         return col.containsAll(c);
139     }
140 
141     @Override
142     public boolean addAll(Collection<? extends E> c) {
143         notifyPreAdd(c);
144         boolean ret = col.addAll(c);
145         notifyPostAdd(c);
146         return ret;
147 
148     }
149 
150     @Override
151     public boolean removeAll(Collection<?> c) {
152         notifyPreRemove(c);
153         boolean ret = col.removeAll(c);
154         notifyPostRemove(c);
155         return ret;
156     }
157 
158     @Override
159     public boolean retainAll(Collection<?> c) {
160     	// Compute difference
161     	Collection<Object> toRemove = new LinkedList<Object>();
162     	for (Object o : col) {
163     		if (!c.contains(o)) {
164     			toRemove.add(o);
165     		}
166     	}
167     	notifyPreRemove(toRemove);
168     	boolean ret = col.retainAll(c);
169     	notifyPostRemove(toRemove);
170     	 
171     	return ret;
172     }
173 
174     @Override
175     public void clear() {
176     	Collection<Object> copy = new ArrayList<Object>(col);
177     	notifyPreRemove(copy);
178     	col.clear();
179     	notifyPostRemove(copy);
180     }
181 
182     protected synchronized void notifyPreAdd(Collection<? extends E> add) {
183     	preAddNotifier.what = add;
184     	preAddNotifier.where = this;
185     	eventListeners.notify(preAddNotifier);
186     }
187 
188     protected synchronized void notifyPostAdd(Collection<? extends E> add) {
189     	postAddNotifier.what = add;
190     	postAddNotifier.where = this;
191     	eventListeners.notify(postAddNotifier);
192     }
193 
194     protected synchronized void notifyPreRemove(Collection<?> remove) {
195     	preRemoveNotifier.what = remove;
196     	preRemoveNotifier.where = this;
197     	eventListeners.notify(preRemoveNotifier);
198     }
199 
200     protected synchronized void notifyPostRemove(Collection<?> remove) {
201     	postRemoveNotifier.what = remove;
202     	postRemoveNotifier.where = this;
203     	eventListeners.notify(postRemoveNotifier);
204     }
205 }