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 }