001 /*
002 * Copyright 2003-2004 The Apache Software Foundation
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016 package org.apache.commons.events.observable.standard;
017
018 import java.util.Collection;
019 import java.util.Collections;
020 import java.util.List;
021 import java.util.Map;
022 import java.util.Set;
023
024 import org.apache.commons.collections.Bag;
025 import org.apache.commons.events.observable.ModificationEvent;
026 import org.apache.commons.events.observable.ModificationEventType;
027 import org.apache.commons.events.observable.ModificationHandler;
028 import org.apache.commons.events.observable.ObservableCollection;
029
030 /**
031 * Event class that encapsulates the event information for a
032 * standard collection event. Two subclasses are provided, one for
033 * pre and one for post events.
034 * <p>
035 * The information stored in this event is all that is available as
036 * parameters or return values.
037 * In addition, the <code>size</code> method is used on the collection.
038 * All objects used are the real objects from the method calls, not clones.
039 *
040 * @since Commons Events 1.0
041 * @version $Revision: 155443 $ $Date: 2005-02-26 13:19:51 +0000 (Sat, 26 Feb 2005) $
042 *
043 * @author Stephen Colebourne
044 */
045 public class StandardModificationEvent extends ModificationEvent {
046
047 /** The size before the event */
048 protected final int preSize;
049 /** The index of the change */
050 protected final int index;
051 /** The object of the change */
052 protected final Object object;
053 /** The number of changes */
054 protected final int repeat;
055 /** The result of the method call */
056 protected final Object previous;
057 /** The view that the event came from, null if none */
058 protected final ObservableCollection view;
059 /** The offset index within the main collection of the view, -1 if none */
060 protected final int viewOffset;
061
062 // Constructor
063 //-----------------------------------------------------------------------
064 /**
065 * Constructor.
066 *
067 * @param obsCollection the event source
068 * @param handler the handler
069 * @param type the event type
070 * @param preSize the size before the change
071 * @param index the index that changed
072 * @param object the value that changed
073 * @param repeat the number of repeats
074 * @param previous the previous value being removed/replaced
075 * @param view the view collection, null if event from main collection
076 * @param viewOffset the offset within the main collection of the view, -1 if unknown
077 */
078 public StandardModificationEvent(
079 final ObservableCollection obsCollection,
080 final ModificationHandler handler,
081 final int type,
082 final int preSize,
083 final int index,
084 final Object object,
085 final int repeat,
086 final Object previous,
087 final ObservableCollection view,
088 final int viewOffset) {
089
090 super(obsCollection, handler, type);
091 this.preSize = preSize;
092 this.index = index;
093 this.object = object;
094 this.repeat = repeat;
095 this.previous = previous;
096 this.view = view;
097 this.viewOffset = viewOffset;
098 }
099
100 // Change info
101 //-----------------------------------------------------------------------
102 /**
103 * Gets the index of the change.
104 * <p>
105 * This is <code>-1</code> when not applicable. Typically only used
106 * for {@link java.util.List} events.
107 *
108 * @return the change index
109 */
110 public int getChangeIndex() {
111 return index;
112 }
113
114 /**
115 * Gets the object that was added/removed/set.
116 * <p>
117 * This is <code>null</code> when not applicable, such as for clear().
118 *
119 * @return the changing object
120 */
121 public Object getChangeObject() {
122 return object;
123 }
124
125 /**
126 * Gets the collection of changed objects.
127 * <p>
128 * For clear, it is an empty list.
129 * For bulk operations, it is the collection.
130 * For non-bulk operations, it is a size one list.
131 *
132 * @return the changing collection, never null
133 */
134 public Collection getChangeCollection() {
135 if (object == null) {
136 return Collections.EMPTY_LIST;
137 } else if (isType(ModificationEventType.GROUP_BULK)) {
138 if (object instanceof Collection) {
139 return (Collection) object;
140 } else {
141 throw new IllegalStateException(
142 "Bulk operations must involve a Collection, but was " + object.getClass().getName());
143 }
144 } else {
145 return Collections.singletonList(object);
146 }
147 }
148
149 /**
150 * Gets the number of times the object was added/removed.
151 * <p>
152 * This is normally <code>1</code>, but will be used for
153 * {@link org.apache.commons.collections.Bag Bag} events.
154 *
155 * @return the repeat
156 */
157 public int getChangeRepeat() {
158 return repeat;
159 }
160
161 /**
162 * Gets the previous value that is being replaced or removed.
163 * <p>
164 * This is only returned if the value definitely was previously in the
165 * collection. Bulk operatons will not return this.
166 *
167 * @return the previous value that was removed/replaced
168 */
169 public Object getPrevious() {
170 return previous;
171 }
172
173 // Size info
174 //-----------------------------------------------------------------------
175 /**
176 * Gets the size before the change.
177 *
178 * @return the size before the change
179 */
180 public int getPreSize() {
181 return preSize;
182 }
183
184 // View info
185 //-----------------------------------------------------------------------
186 /**
187 * Gets the view, <code>null</code> if none.
188 * <p>
189 * A view is a subSet, headSet, tailSet, subList and so on.
190 *
191 * @return the view
192 */
193 public ObservableCollection getView() {
194 return view;
195 }
196
197 /**
198 * Checks whether the event originated from a view.
199 *
200 * @return true if event came from a view
201 */
202 public boolean isView() {
203 return (view != null);
204 }
205
206 /**
207 * Gets the view offset, <code>-1</code> if no view or unknown offset.
208 * <p>
209 * This refers to the index of the start of the view within the main collection.
210 *
211 * @return the view offset
212 */
213 public int getViewOffset() {
214 return viewOffset;
215 }
216
217 // Event type
218 //-----------------------------------------------------------------------
219 /**
220 * Checks to see if the event is an add event (add/addAll).
221 *
222 * @return true if of the specified type
223 */
224 public boolean isTypeAdd() {
225 return (type & ModificationEventType.GROUP_ADD) > 0;
226 }
227
228 /**
229 * Checks to see if the event is a remove event (remove/removeAll/retainAll/clear).
230 *
231 * @return true if of the specified type
232 */
233 public boolean isTypeReduce() {
234 return (type & ModificationEventType.GROUP_REDUCE) > 0;
235 }
236
237 /**
238 * Checks to see if the event is a change event (set).
239 *
240 * @return true if of the specified type
241 */
242 public boolean isTypeChange() {
243 return (type & ModificationEventType.GROUP_CHANGE) > 0;
244 }
245
246 /**
247 * Checks to see if the event is a bulk event (addAll/removeAll/retainAll/clear).
248 *
249 * @return true if of the specified type
250 */
251 public boolean isTypeBulk() {
252 return (type & ModificationEventType.GROUP_BULK) > 0;
253 }
254
255 /**
256 * Checks to see if the event is of the specified type.
257 * <p>
258 * This is any combination of constants from {@link ModificationEventType}.
259 *
260 * @param eventType an event type constant
261 * @return true if of the specified type
262 */
263 public boolean isType(final int eventType) {
264 return (type & eventType) > 0;
265 }
266
267 // toString
268 //-----------------------------------------------------------------------
269 /**
270 * Gets a debugging string version of the event.
271 *
272 * @return a debugging string
273 */
274 public String toString() {
275 StringBuffer buf = new StringBuffer(64);
276 buf.append("ModificationEvent[type=");
277 buf.append(ModificationEventType.toString(type));
278 if (index >= 0) {
279 buf.append(",index=");
280 buf.append(index);
281 }
282 if (type != ModificationEventType.CLEAR) {
283 buf.append(",object=");
284 if (object instanceof List) {
285 buf.append("List:size:");
286 buf.append(((List) object).size());
287 } else if (object instanceof Set) {
288 buf.append("Set:size:");
289 buf.append(((Set) object).size());
290 } else if (object instanceof Bag) {
291 buf.append("Bag:size:");
292 buf.append(((Bag) object).size());
293 } else if (object instanceof Collection) {
294 buf.append("Collection:size:");
295 buf.append(((Collection) object).size());
296 } else if (object instanceof Map) {
297 buf.append("Map:size:");
298 buf.append(((Map) object).size());
299 } else if (object instanceof Object[]) {
300 buf.append("Array:size:");
301 buf.append(((Object[]) object).length);
302 } else if (object == null) {
303 buf.append("null");
304 } else {
305 buf.append(object.toString());
306 }
307 }
308 buf.append(']');
309 return buf.toString();
310 }
311
312 }