Coverage Report - org.apache.commons.events.observable.ModificationHandler
 
Classes in this File Line Coverage Branch Coverage Complexity
ModificationHandler
0%
0/89
0%
0/18
1.254
ModificationHandler$Factory
0%
0/4
0%
0/2
1.254
ModificationHandler$SetViewHandler
0%
0/5
N/A
1.254
ModificationHandler$SubListHandler
0%
0/5
N/A
1.254
 
 1  
 /*
 2  
  * Copyright 2003-2004 The Apache Software Foundation
 3  
  *
 4  
  * Licensed under the Apache License, Version 2.0 (the "License");
 5  
  * you may not use this file except in compliance with the License.
 6  
  * You may obtain a copy of the License at
 7  
  *
 8  
  *     http://www.apache.org/licenses/LICENSE-2.0
 9  
  *
 10  
  * Unless required by applicable law or agreed to in writing, software
 11  
  * distributed under the License is distributed on an "AS IS" BASIS,
 12  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 13  
  * See the License for the specific language governing permissions and
 14  
  * limitations under the License.
 15  
  */
 16  
 package org.apache.commons.events.observable;
 17  
 
 18  
 import java.util.Collection;
 19  
 
 20  
 /**
 21  
  * Defines a handler for collection modification events.
 22  
  * <p>
 23  
  * This class defines the event handling methods, following the 
 24  
  * <code>preXxx</code> and <code>postXxx</code> naming convention.
 25  
  * It also provides a default implementation that forwards to single methods.
 26  
  * <p>
 27  
  * To write your own handler, you will normally subclass and override the
 28  
  * <code>preEvent</code> and <code>postEvent</code> methods. However, you
 29  
  * could choose to override any individual event method.
 30  
  * <p>
 31  
  * This class could have been implemented as an interface, however to do so
 32  
  * would prevent the addition of extra events in the future. It does mean
 33  
  * that if you subclass this class, you must check it when you upgrade to a
 34  
  * later release.
 35  
  *
 36  
  * @since Commons Events 1.0
 37  
  * @version $Revision: 155443 $ $Date: 2005-02-26 13:19:51 +0000 (Sat, 26 Feb 2005) $
 38  
  * 
 39  
  * @author Stephen Colebourne
 40  
  */
 41  
 public class ModificationHandler {
 42  
     
 43  
     /** Singleton factory */
 44  0
     static final ModificationHandlerFactory FACTORY = new Factory();
 45  
     
 46  
     /** The collection being observed */
 47  0
     private ObservableCollection obsCollection = null;
 48  
     /** The underlying base collection being decorated */
 49  0
     private Collection baseCollection = null;
 50  
     /** The root handler */
 51  
     private final ModificationHandler rootHandler;
 52  
     /** The view offset, 0 if not a view */
 53  
     private final int viewOffset;
 54  
     
 55  
     // Constructors
 56  
     //-----------------------------------------------------------------------
 57  
     /**
 58  
      * Constructor.
 59  
      */
 60  
     protected ModificationHandler() {
 61  0
         super();
 62  0
         this.rootHandler = this;
 63  0
         this.viewOffset = 0;
 64  0
     }
 65  
 
 66  
     /**
 67  
      * Constructor.
 68  
      * 
 69  
      * @param rootHandler  the base underlying handler
 70  
      * @param viewOffset  the offset on the base collection
 71  
      */
 72  
     protected ModificationHandler(ModificationHandler rootHandler, int viewOffset) {
 73  0
         super();
 74  0
         this.rootHandler = rootHandler;
 75  0
         this.viewOffset = viewOffset;
 76  0
     }
 77  
 
 78  
     /**
 79  
      * Initialize the handler.
 80  
      * <p>
 81  
      * The handler cannot be used until this method is called.
 82  
      * However, the handler's setup methods can be called.
 83  
      * All other methods will throw NullPointerException until then.
 84  
      * 
 85  
      * @param coll  the observed collection, must not be null
 86  
      * @param baseColl  the base collection, must not be null
 87  
      * @throws IllegalArgumentException if the collection is null
 88  
      * @throws IllegalStateException if init has already been called
 89  
      */
 90  
     void init(final ObservableCollection coll, Collection baseColl) {
 91  0
         if (coll == null) {
 92  0
             throw new IllegalArgumentException("Collection must not be null");
 93  
         }
 94  0
         if (baseColl == null) {
 95  0
             throw new IllegalArgumentException("Base Collection must not be null");
 96  
         }
 97  0
         if (this.obsCollection != null) {
 98  0
             throw new IllegalArgumentException("init() has already been called");
 99  
         }
 100  0
         this.obsCollection = coll;
 101  0
         this.baseCollection = baseColl;
 102  0
     }
 103  
 
 104  
     // Field access
 105  
     //-----------------------------------------------------------------------
 106  
     /**
 107  
      * Gets the observed collection.
 108  
      * 
 109  
      * @return the observed collection
 110  
      */
 111  
     public ObservableCollection getObservedCollection() {
 112  0
         return obsCollection;
 113  
     }
 114  
     
 115  
     /**
 116  
      * Gets the base collection.
 117  
      * 
 118  
      * @return the base collection
 119  
      */
 120  
     protected Collection getBaseCollection() {
 121  0
         return baseCollection;
 122  
     }
 123  
     
 124  
     /**
 125  
      * Gets the root handler.
 126  
      * 
 127  
      * @return the root handler
 128  
      */
 129  
     protected ModificationHandler getRootHandler() {
 130  0
         return rootHandler;
 131  
     }
 132  
     
 133  
     /**
 134  
      * Gets the view offset.
 135  
      * 
 136  
      * @return the view offset
 137  
      */
 138  
     protected int getViewOffset() {
 139  0
         return viewOffset;
 140  
     }
 141  
     
 142  
     // PreListeners
 143  
     //----------------------------------------------------------------------
 144  
     /**
 145  
      * Gets an array of all the pre listeners active in the handler.
 146  
      * <p>
 147  
      * This implementation throws UnsupportedOperationException.
 148  
      * 
 149  
      * @return the listeners
 150  
      * @throws UnsupportedOperationException if the handler does not support listeners
 151  
      */
 152  
     public Object[] getPreModificationListeners() {
 153  0
         throw new UnsupportedOperationException("Listeners not supported by " + getClass().getName());
 154  
     }
 155  
     
 156  
     /**
 157  
      * Adds a pre listener to the list held in the handler.
 158  
      * <p>
 159  
      * No error occurs if the listener is <code>null</code>.
 160  
      * <p>
 161  
      * The listener does not necessarily have to be a listener in the classic
 162  
      * JavaBean sense. It is entirely up to the handler as to how it interprets
 163  
      * the listener parameter. A ClassCastException is thrown if the handler
 164  
      * cannot interpret the parameter.
 165  
      * <p>
 166  
      * This implementation throws UnsupportedOperationException.
 167  
      * 
 168  
      * @param listener  the listener to add, may be null (ignored)
 169  
      * @throws ClassCastException if the listener is not of the correct type
 170  
      * @throws UnsupportedOperationException if the handler does not support listeners
 171  
      */
 172  
     public void addPreModificationListener(Object listener) {
 173  0
         throw new UnsupportedOperationException("Listeners not supported by " + getClass().getName());
 174  
     }
 175  
     
 176  
     /**
 177  
      * Removes a pre listener to the list held in the handler.
 178  
      * <p>
 179  
      * No error occurs if the listener is not in the list or the type
 180  
      * of the listener is incorrect.
 181  
      * <p>
 182  
      * This implementation throws UnsupportedOperationException.
 183  
      * 
 184  
      * @param listener  the listener to remove, may be null (ignored)
 185  
      * @throws UnsupportedOperationException if the handler does not support listeners
 186  
      */
 187  
     public void removePreModificationListener(Object listener) {
 188  0
         throw new UnsupportedOperationException("Listeners not supported by " + getClass().getName());
 189  
     }
 190  
     
 191  
     // PostListeners
 192  
     //----------------------------------------------------------------------
 193  
     /**
 194  
      * Gets an array of all the post listeners active in the handler.
 195  
      * <p>
 196  
      * This implementation throws UnsupportedOperationException.
 197  
      * 
 198  
      * @return the listeners
 199  
      * @throws UnsupportedOperationException if the handler does not support listeners
 200  
      */
 201  
     public Object[] getPostModificationListeners() {
 202  0
         throw new UnsupportedOperationException("Listeners not supported by " + getClass().getName());
 203  
     }
 204  
     
 205  
     /**
 206  
      * Adds a post listener to the list held in the handler.
 207  
      * <p>
 208  
      * No error occurs if the listener is <code>null</code>.
 209  
      * <p>
 210  
      * The listener does not necessarily have to be a listener in the classic
 211  
      * JavaBean sense. It is entirely up to the handler as to how it interprets
 212  
      * the listener parameter. A ClassCastException is thrown if the handler
 213  
      * cannot interpret the parameter.
 214  
      * <p>
 215  
      * This implementation throws UnsupportedOperationException.
 216  
      * 
 217  
      * @param listener  the listener to add, may be null (ignored)
 218  
      * @throws ClassCastException if the listener is not of the correct type
 219  
      * @throws UnsupportedOperationException if the handler does not support listeners
 220  
      */
 221  
     public void addPostModificationListener(Object listener) {
 222  0
         throw new UnsupportedOperationException("Listeners not supported by " + getClass().getName());
 223  
     }
 224  
     
 225  
     /**
 226  
      * Removes a post listener to the list held in the handler.
 227  
      * <p>
 228  
      * No error occurs if the listener is not in the list or the type
 229  
      * of the listener is incorrect.
 230  
      * <p>
 231  
      * This implementation throws UnsupportedOperationException.
 232  
      * 
 233  
      * @param listener  the listener to remove, may be null (ignored)
 234  
      * @throws UnsupportedOperationException if the handler does not support listeners
 235  
      */
 236  
     public void removePostModificationListener(Object listener) {
 237  0
         throw new UnsupportedOperationException("Listeners not supported by " + getClass().getName());
 238  
     }
 239  
     
 240  
     // Event sending
 241  
     //-----------------------------------------------------------------------
 242  
     /**
 243  
      * Handles the pre event.
 244  
      * <p>
 245  
      * This implementation does nothing.
 246  
      * 
 247  
      * @param type  the event type to send
 248  
      * @param index  the index where the change starts, the method param or derived
 249  
      * @param object  the object that will be added/removed/set, the method param or derived
 250  
      * @param repeat  the number of repeats of the add/remove, the method param or derived
 251  
      * @param previous  the previous value that will be removed/replaced, must exist in coll
 252  
      * @param view  the view collection that the change was actioned on, null if no view
 253  
      * @param viewOffset  the offset of the subList view, -1 if unknown
 254  
      */
 255  
     protected boolean preEvent(
 256  
             int type, int index, Object object, int repeat,
 257  
             Object previous, ObservableCollection view, int viewOffset) {
 258  0
         return true;
 259  
     }
 260  
 
 261  
     /**
 262  
      * Handles the post event.
 263  
      * <p>
 264  
      * This implementation does nothing.
 265  
      * 
 266  
      * @param modified  true if the method succeeded in changing the collection
 267  
      * @param type  the event type to send
 268  
      * @param index  the index where the change starts, the method param or derived
 269  
      * @param object  the object that was added/removed/set, the method param or derived
 270  
      * @param repeat  the number of repeats of the add/remove, the method param or derived
 271  
      * @param previous  the previous value that was removed/replace, must have existed in coll
 272  
      * @param view  the view collection that the change was actioned on, null if no view
 273  
      * @param viewOffset  the offset of the subList view, -1 if unknown
 274  
      */
 275  
     protected void postEvent(
 276  
             boolean modified, int type, int index, Object object, int repeat,
 277  
             Object previous, ObservableCollection view, int viewOffset) {
 278  0
     }
 279  
 
 280  
     // Event handling
 281  
     //-----------------------------------------------------------------------
 282  
     /**
 283  
      * Store data and send event before add(obj) is called.
 284  
      * <p>
 285  
      * This implementation forwards to {@link #preEvent}.
 286  
      * It does not set the index for List implementations.
 287  
      * 
 288  
      * @param object  the object being added
 289  
      * @return true to process modification
 290  
      */
 291  
     protected boolean preAdd(Object object) {
 292  0
         return preEvent(ModificationEventType.ADD, -1, object, 1, null, null, -1);
 293  
     }
 294  
 
 295  
     /**
 296  
      * Send an event after add(obj) is called.
 297  
      * <p>
 298  
      * This implementation forwards to {@link #postEvent}.
 299  
      * It does not set the index for List implementations.
 300  
      * 
 301  
      * @param object  the object being added
 302  
      * @param result  the result from the add method
 303  
      */
 304  
     protected void postAdd(Object object, boolean result) {
 305  0
         postEvent(result, ModificationEventType.ADD, -1, object, 1, null, null, -1);
 306  0
     }
 307  
 
 308  
     //-----------------------------------------------------------------------
 309  
     /**
 310  
      * Store data and send event before add(int,obj) is called on a List.
 311  
      * <p>
 312  
      * This implementation forwards to {@link #preEvent}.
 313  
      * 
 314  
      * @param index  the index to add at
 315  
      * @param object  the object being added
 316  
      * @return true to process modification
 317  
      */
 318  
     protected boolean preAddIndexed(int index, Object object) {
 319  0
         return preEvent(ModificationEventType.ADD_INDEXED, index + viewOffset, object, 1, null, null, -1);
 320  
     }
 321  
 
 322  
     /**
 323  
      * Send an event after add(int,obj) is called on a List.
 324  
      * <p>
 325  
      * This implementation forwards to {@link #postEvent}.
 326  
      * 
 327  
      * @param index  the index to add at
 328  
      * @param object  the object being added
 329  
      */
 330  
     protected void postAddIndexed(int index, Object object) {
 331  0
         postEvent(true, ModificationEventType.ADD_INDEXED, index + viewOffset, object, 1, null, null, -1);
 332  0
     }
 333  
 
 334  
     //-----------------------------------------------------------------------
 335  
     /**
 336  
      * Store data and send event before add(obj,int) is called on a Bag.
 337  
      * <p>
 338  
      * This implementation forwards to {@link #preEvent}.
 339  
      * 
 340  
      * @param object  the object being added
 341  
      * @param nCopies  the number of copies being added
 342  
      * @return true to process modification
 343  
      */
 344  
     protected boolean preAddNCopies(Object object, int nCopies) {
 345  0
         return preEvent(ModificationEventType.ADD_NCOPIES, -1, object, nCopies, null, null, -1);
 346  
     }
 347  
 
 348  
     /**
 349  
      * Send an event after add(obj,int) is called on a Bag.
 350  
      * <p>
 351  
      * This implementation forwards to {@link #postEvent}.
 352  
      * The method result is not used by this implementation (Bag violates the
 353  
      * Collection contract)
 354  
      * 
 355  
      * @param object  the object being added
 356  
      * @param nCopies  the number of copies being added
 357  
      * @param result  the method result
 358  
      */
 359  
     protected void postAddNCopies(Object object, int nCopies, boolean result) {
 360  0
         postEvent(true, ModificationEventType.ADD_NCOPIES, -1, object, nCopies, null, null, -1);
 361  0
     }
 362  
 
 363  
     //-----------------------------------------------------------------------
 364  
     /**
 365  
      * Store data and send event before add(obj) is called on a ListIterator.
 366  
      * <p>
 367  
      * This implementation forwards to {@link #preEvent}.
 368  
      * 
 369  
      * @param index  the index of the iterator
 370  
      * @param object  the object being added
 371  
      * @return true to process modification
 372  
      */
 373  
     protected boolean preAddIterated(int index, Object object) {
 374  0
         return preEvent(ModificationEventType.ADD_ITERATED, index + viewOffset, object, 1, null, null, -1);
 375  
     }
 376  
 
 377  
     /**
 378  
      * Send an event after add(obj) is called on a ListIterator.
 379  
      * <p>
 380  
      * This implementation forwards to {@link #postEvent}.
 381  
      * 
 382  
      * @param index  the index of the iterator
 383  
      * @param object  the object being added
 384  
      */
 385  
     protected void postAddIterated(int index, Object object) {
 386  
         // assume collection changed
 387  0
         postEvent(true, ModificationEventType.ADD_ITERATED, index + viewOffset, object, 1, null, null, -1);
 388  0
     }
 389  
 
 390  
     //-----------------------------------------------------------------------
 391  
     /**
 392  
      * Store data and send event before addAll(coll) is called.
 393  
      * <p>
 394  
      * This implementation forwards to {@link #preEvent}.
 395  
      * 
 396  
      * @param coll  the collection being added
 397  
      * @return true to process modification
 398  
      */
 399  
     protected boolean preAddAll(Collection coll) {
 400  0
         return preEvent(ModificationEventType.ADD_ALL, -1, coll, 1, null, null, -1);
 401  
     }
 402  
 
 403  
     /**
 404  
      * Send an event after addAll(coll) is called.
 405  
      * <p>
 406  
      * This implementation forwards to {@link #postEvent}.
 407  
      * 
 408  
      * @param coll  the collection being added
 409  
      * @param collChanged  the result from the addAll method
 410  
      */
 411  
     protected void postAddAll(Collection coll, boolean collChanged) {
 412  0
         postEvent(collChanged, ModificationEventType.ADD_ALL, -1, coll, 1, null, null, -1);
 413  0
     }
 414  
 
 415  
     //-----------------------------------------------------------------------
 416  
     /**
 417  
      * Store data and send event before addAll(int,coll) is called on a List.
 418  
      * <p>
 419  
      * This implementation forwards to {@link #preEvent}.
 420  
      * 
 421  
      * @param index  the index to addAll at
 422  
      * @param coll  the collection being added
 423  
      * @return true to process modification
 424  
      */
 425  
     protected boolean preAddAllIndexed(int index, Collection coll) {
 426  0
         return preEvent(ModificationEventType.ADD_ALL_INDEXED, index + viewOffset, coll, 1, null, null, -1);
 427  
     }
 428  
 
 429  
     /**
 430  
      * Send an event after addAll(int,coll) is called on a List.
 431  
      * <p>
 432  
      * This implementation forwards to {@link #postEvent}.
 433  
      * 
 434  
      * @param index  the index to addAll at
 435  
      * @param coll  the collection being added
 436  
      * @param collChanged  the result from the addAll method
 437  
      */
 438  
     protected void postAddAllIndexed(int index, Collection coll, boolean collChanged) {
 439  0
         postEvent(collChanged, ModificationEventType.ADD_ALL_INDEXED, index + viewOffset, coll, 1, null, null, -1);
 440  0
     }
 441  
 
 442  
     //-----------------------------------------------------------------------
 443  
     /**
 444  
      * Store data and send event before clear() is called.
 445  
      * <p>
 446  
      * This implementation forwards to {@link #preEvent}.
 447  
      * 
 448  
      * @return true to process modification
 449  
      */
 450  
     protected boolean preClear() {
 451  0
         return preEvent(ModificationEventType.CLEAR, -1, null, 1, null, null, -1);
 452  
     }
 453  
 
 454  
     /**
 455  
      * Send an event after clear() is called.
 456  
      * <p>
 457  
      * This implementation forwards to {@link #postEvent}.
 458  
      */
 459  
     protected void postClear() {
 460  
         // assumes a modification occurred
 461  0
         postEvent(true, ModificationEventType.CLEAR, -1, null, 1, null, null, -1);
 462  0
     }
 463  
 
 464  
     //-----------------------------------------------------------------------
 465  
     /**
 466  
      * Store data and send event before remove(obj) is called.
 467  
      * <p>
 468  
      * This implementation forwards to {@link #preEvent}.
 469  
      * 
 470  
      * @param object  the object being removed
 471  
      * @return true to process modification
 472  
      */
 473  
     protected boolean preRemove(Object object) {
 474  0
         return preEvent(ModificationEventType.REMOVE, -1, object, 1, null, null, -1);
 475  
     }
 476  
 
 477  
     /**
 478  
      * Send an event after remove(obj) is called.
 479  
      * <p>
 480  
      * This implementation forwards to {@link #postEvent}.
 481  
      * 
 482  
      * @param object  the object being removed
 483  
      * @param collChanged  the result from the remove method
 484  
      */
 485  
     protected void postRemove(Object object, boolean collChanged) {
 486  0
         postEvent(collChanged, ModificationEventType.REMOVE, -1, object, 1, (collChanged ? object : null), null, -1);
 487  0
     }
 488  
 
 489  
     //-----------------------------------------------------------------------
 490  
     /**
 491  
      * Store data and send event before remove(int) is called on a List.
 492  
      * <p>
 493  
      * This implementation forwards to {@link #preEvent}.
 494  
      * 
 495  
      * @param index  the index to remove at
 496  
      * @return true to process modification
 497  
      */
 498  
     protected boolean preRemoveIndexed(int index) {
 499  
         // could do a get(index) to determine previousValue
 500  
         // we don't for performance, but subclass may override
 501  0
         return preEvent(ModificationEventType.REMOVE_INDEXED, index + viewOffset, null, 1, null, null, -1);
 502  
     }
 503  
 
 504  
     /**
 505  
      * Send an event after remove(int) is called on a List.
 506  
      * <p>
 507  
      * This implementation forwards to {@link #postEvent}.
 508  
      * 
 509  
      * @param index  the index to remove at
 510  
      * @param previousValue  the result from the remove method
 511  
      */
 512  
     protected void postRemoveIndexed(int index, Object previousValue) {
 513  0
         postEvent(true, ModificationEventType.REMOVE_INDEXED, index + viewOffset, null, 1, previousValue, null, -1);
 514  0
     }
 515  
 
 516  
     //-----------------------------------------------------------------------
 517  
     /**
 518  
      * Store data and send event before remove(obj,int) is called on a Bag.
 519  
      * <p>
 520  
      * This implementation forwards to {@link #preEvent}.
 521  
      * 
 522  
      * @param object  the object being removed
 523  
      * @param nCopies  the number of copies being removed
 524  
      * @return true to process modification
 525  
      */
 526  
     protected boolean preRemoveNCopies(Object object, int nCopies) {
 527  0
         return preEvent(ModificationEventType.REMOVE_NCOPIES, -1, object, nCopies, null, null, -1);
 528  
     }
 529  
 
 530  
     /**
 531  
      * Send an event after remove(obj,int) is called on a Bag.
 532  
      * <p>
 533  
      * This implementation forwards to {@link #postEvent}.
 534  
      * 
 535  
      * @param object  the object being removed
 536  
      * @param nCopies  the number of copies being removed
 537  
      * @param collChanged  the result from the remove method
 538  
      */
 539  
     protected void postRemoveNCopies(Object object, int nCopies, boolean collChanged) {
 540  0
         postEvent(collChanged, ModificationEventType.REMOVE_NCOPIES, -1, object, nCopies, (collChanged ? object : null), null, -1);
 541  0
     }
 542  
 
 543  
     //-----------------------------------------------------------------------
 544  
     /**
 545  
      * Store data and send event before remove() is called on a Buffer.
 546  
      * <p>
 547  
      * This implementation forwards to {@link #preEvent}.
 548  
      * 
 549  
      * @return true to process modification
 550  
      */
 551  
     protected boolean preRemoveNext() {
 552  0
         return preEvent(ModificationEventType.REMOVE_NEXT, -1, null, 1, null, null, -1);
 553  
     }
 554  
 
 555  
     /**
 556  
      * Send an event after remove() is called on a Buffer.
 557  
      * <p>
 558  
      * This implementation forwards to {@link #postEvent}.
 559  
      * 
 560  
      * @param removedValue  the previous value at this index
 561  
      */
 562  
     protected void postRemoveNext(Object removedValue) {
 563  
         // assume collection changed
 564  0
         postEvent(true, ModificationEventType.REMOVE_NEXT, -1, removedValue, 1, removedValue, null, -1);
 565  0
     }
 566  
 
 567  
     //-----------------------------------------------------------------------
 568  
     /**
 569  
      * Store data and send event before remove(obj) is called on an Iterator.
 570  
      * <p>
 571  
      * This implementation forwards to {@link #preEvent}.
 572  
      * 
 573  
      * @param index  the index of the iterator
 574  
      * @param removedValue  the object being removed
 575  
      * @return true to process modification
 576  
      */
 577  
     protected boolean preRemoveIterated(int index, Object removedValue) {
 578  0
         return preEvent(ModificationEventType.REMOVE_ITERATED, index + viewOffset, removedValue, 1, removedValue, null, -1);
 579  
     }
 580  
 
 581  
     /**
 582  
      * Send an event after remove(obj) is called on an Iterator.
 583  
      * <p>
 584  
      * This implementation forwards to {@link #postEvent}.
 585  
      * 
 586  
      * @param index  the index of the iterator
 587  
      * @param removedValue  the previous value at this index
 588  
      */
 589  
     protected void postRemoveIterated(int index, Object removedValue) {
 590  
         // assume collection changed
 591  0
         postEvent(true, ModificationEventType.REMOVE_ITERATED, index + viewOffset, removedValue, 1, removedValue, null, -1);
 592  0
     }
 593  
 
 594  
     //-----------------------------------------------------------------------
 595  
     /**
 596  
      * Store data and send event before removeAll(coll) is called.
 597  
      * <p>
 598  
      * This implementation forwards to {@link #preEvent}.
 599  
      * 
 600  
      * @param coll  the collection being removed
 601  
      * @return true to process modification
 602  
      */
 603  
     protected boolean preRemoveAll(Collection coll) {
 604  0
         return preEvent(ModificationEventType.REMOVE_ALL, -1, coll, 1, null, null, -1);
 605  
     }
 606  
 
 607  
     /**
 608  
      * Send an event after removeAll(coll) is called.
 609  
      * <p>
 610  
      * This implementation forwards to {@link #postEvent}.
 611  
      * 
 612  
      * @param coll  the collection being removed
 613  
      * @param collChanged  the result from the removeAll method
 614  
      */
 615  
     protected void postRemoveAll(Collection coll, boolean collChanged) {
 616  0
         postEvent(collChanged, ModificationEventType.REMOVE_ALL, -1, coll, 1, null, null, -1);
 617  0
     }
 618  
 
 619  
     //-----------------------------------------------------------------------
 620  
     /**
 621  
      * Store data and send event before retainAll(coll) is called.
 622  
      * <p>
 623  
      * This implementation forwards to {@link #preEvent}.
 624  
      * 
 625  
      * @param coll  the collection being retained
 626  
      * @return true to process modification
 627  
      */
 628  
     protected boolean preRetainAll(Collection coll) {
 629  0
         return preEvent(ModificationEventType.RETAIN_ALL, -1, coll, 1, null, null, -1);
 630  
     }
 631  
 
 632  
     /**
 633  
      * Send an event after retainAll(coll) is called.
 634  
      * <p>
 635  
      * This implementation forwards to {@link #postEvent}.
 636  
      * 
 637  
      * @param coll  the collection being retained
 638  
      * @param collChanged  the result from the retainAll method
 639  
      */
 640  
     protected void postRetainAll(Collection coll, boolean collChanged) {
 641  0
         postEvent(collChanged, ModificationEventType.RETAIN_ALL, -1, coll, 1, null, null, -1);
 642  0
     }
 643  
 
 644  
     //-----------------------------------------------------------------------
 645  
     /**
 646  
      * Store data and send event before set(int,obj) is called on a List.
 647  
      * <p>
 648  
      * This implementation forwards to {@link #preEvent}.
 649  
      * 
 650  
      * @param index  the index to add at
 651  
      * @param object  the object being added
 652  
      * @return true to process modification
 653  
      */
 654  
     protected boolean preSetIndexed(int index, Object object) {
 655  
         // could do a get(index) to determine previousValue
 656  
         // we don't for performance, but subclass may override
 657  0
         return preEvent(ModificationEventType.SET_INDEXED, index + viewOffset, object, 1, null, null, -1);
 658  
     }
 659  
 
 660  
     /**
 661  
      * Send an event after set(int,obj) is called on a List.
 662  
      * <p>
 663  
      * This implementation forwards to {@link #postEvent}.
 664  
      * 
 665  
      * @param index  the index to add at
 666  
      * @param object  the object being added
 667  
      * @param previousValue  the result from the set method
 668  
      */
 669  
     protected void postSetIndexed(int index, Object object, Object previousValue) {
 670  
         // reference check for modification, in case equals() has issues (eg. performance)
 671  0
         postEvent((object != previousValue), ModificationEventType.SET_INDEXED, index + viewOffset, object, 1, previousValue, null, -1);
 672  0
     }
 673  
 
 674  
     //-----------------------------------------------------------------------
 675  
     /**
 676  
      * Store data and send event before set(obj) is called on a ListIterator.
 677  
      * <p>
 678  
      * This implementation forwards to {@link #preEvent}.
 679  
      * 
 680  
      * @param index  the index to set at
 681  
      * @param object  the object being added
 682  
      * @param previousValue  the previous value at this index
 683  
      * @return true to process modification
 684  
      */
 685  
     protected boolean preSetIterated(int index, Object object, Object previousValue) {
 686  0
         return preEvent(ModificationEventType.SET_ITERATED, index + viewOffset, object, 1, previousValue, null, -1);
 687  
     }
 688  
 
 689  
     /**
 690  
      * Send an event after set(obj) is called on a ListIterator.
 691  
      * <p>
 692  
      * This implementation forwards to {@link #postEvent}.
 693  
      * 
 694  
      * @param index  the index to set at
 695  
      * @param object  the object being added
 696  
      * @param previousValue  the previous value at this index
 697  
      */
 698  
     protected void postSetIterated(int index, Object object, Object previousValue) {
 699  
         // reference check for modification, in case equals() has issues (eg. performance)
 700  0
         postEvent((object != previousValue), ModificationEventType.SET_ITERATED, index + viewOffset, object, 1, previousValue, null, -1);
 701  0
     }
 702  
 
 703  
     // SortedSet Views
 704  
     //-----------------------------------------------------------------------
 705  
     /**
 706  
      * Creates a new handler for SortedSet subSet.
 707  
      * 
 708  
      * @param fromElement  the from element
 709  
      * @param toElement  the to element
 710  
      */
 711  
     protected ModificationHandler createSubSetHandler(Object fromElement, Object toElement) {
 712  0
         return new SetViewHandler(rootHandler);
 713  
     }
 714  
     
 715  
     /**
 716  
      * Creates a new handler for SortedSet headSet.
 717  
      * 
 718  
      * @param toElement  the to element
 719  
      */
 720  
     protected ModificationHandler createHeadSetHandler(Object toElement) {
 721  0
         return new SetViewHandler(rootHandler);
 722  
     }
 723  
     
 724  
     /**
 725  
      * Creates a new handler for SortedSet tailSet.
 726  
      * 
 727  
      * @param fromElement  the from element
 728  
      */
 729  
     protected ModificationHandler createTailSetHandler(Object fromElement) {
 730  0
         return new SetViewHandler(rootHandler);
 731  
     }
 732  
     
 733  
     /**
 734  
      * Inner class for views.
 735  
      */    
 736  
     protected static class SetViewHandler extends ModificationHandler {
 737  
         
 738  
         /**
 739  
          * Constructor.
 740  
          * 
 741  
          * @param rootHandler  the base underlying handler
 742  
          */
 743  
         protected SetViewHandler(ModificationHandler rootHandler) {
 744  0
             super(rootHandler, 0);
 745  0
         }
 746  
 
 747  
         /**
 748  
          * Override the preEvent method to forward all events to the 
 749  
          * underlying handler. This method also inserts details of the view
 750  
          * that caused the event.
 751  
          */
 752  
         protected boolean preEvent(
 753  
                 int type, int index, Object object, int repeat,
 754  
                 Object previous, ObservableCollection ignoredView, int offset) {
 755  
 
 756  0
             return getRootHandler().preEvent(
 757  
                 type, index, object, repeat,
 758  
                 previous, getObservedCollection(), offset);
 759  
         }
 760  
 
 761  
         /**
 762  
          * Override the postEvent method to forward all events to the 
 763  
          * underlying handler. This method also inserts details of the view
 764  
          * that caused the event.
 765  
          */
 766  
         protected void postEvent(
 767  
                 boolean modified, int type, int index, Object object, int repeat,
 768  
                 Object previous, ObservableCollection ignoredView, int offset) {
 769  
 
 770  0
             getRootHandler().postEvent(
 771  
                 modified, type, index, object, repeat,
 772  
                 previous, getObservedCollection(), offset);
 773  0
         }
 774  
     }
 775  
     
 776  
     // List View
 777  
     //-----------------------------------------------------------------------
 778  
     /**
 779  
      * Creates a new handler for subLists that is aware of the offset.
 780  
      * 
 781  
      * @param fromIndex  the sublist fromIndex (inclusive)
 782  
      * @param toIndex  the sublist toIndex (exclusive)
 783  
      */
 784  
     protected ModificationHandler createSubListHandler(int fromIndex, int toIndex) {
 785  0
         return new SubListHandler(rootHandler, fromIndex + viewOffset);
 786  
     }
 787  
 
 788  
     /**
 789  
      * Inner class for subLists.
 790  
      */    
 791  
     protected static class SubListHandler extends ModificationHandler {
 792  
         
 793  
         /**
 794  
          * Constructor.
 795  
          * 
 796  
          * @param rootHandler  the base underlying handler
 797  
          * @param viewOffset  the offset on the base collection
 798  
          */
 799  
         protected SubListHandler(ModificationHandler rootHandler, int viewOffset) {
 800  0
             super(rootHandler, viewOffset);
 801  0
         }
 802  
 
 803  
         /**
 804  
          * Override the preEvent method to forward all events to the 
 805  
          * underlying handler. This method also inserts details of the view
 806  
          * that caused the event.
 807  
          */
 808  
         protected boolean preEvent(
 809  
                 int type, int index, Object object, int repeat,
 810  
                 Object previous, ObservableCollection ignoredView, int ignoredOffset) {
 811  
 
 812  0
             return getRootHandler().preEvent(
 813  
                 type, index, object, repeat,
 814  
                 previous, getObservedCollection(), getViewOffset());
 815  
         }
 816  
 
 817  
         /**
 818  
          * Override the postEvent method to forward all events to the 
 819  
          * underlying handler. This method also inserts details of the view
 820  
          * that caused the event.
 821  
          */
 822  
         protected void postEvent(
 823  
                 boolean modified, int type, int index, Object object, int repeat,
 824  
                 Object previous, ObservableCollection ignoredView, int ignoredOffset) {
 825  
 
 826  0
             getRootHandler().postEvent(
 827  
                 modified, type, index, object, repeat,
 828  
                 previous, getObservedCollection(), getViewOffset());
 829  0
         }
 830  
     }
 831  
     
 832  
     // toString
 833  
     //-----------------------------------------------------------------------
 834  
     /**
 835  
      * Gets a debugging string version of this object.
 836  
      * 
 837  
      * @return a debugging string
 838  
      */
 839  
     public String toString() {
 840  0
         String name = getClass().getName();
 841  0
         int pos = name.lastIndexOf('.');
 842  0
         if (pos != -1) {
 843  0
             name = name.substring(pos + 1);
 844  
         }
 845  0
         return name + '[' + (obsCollection == null ? "" : "initialised") + ']';
 846  
     }
 847  
 
 848  
     // Factory to create handler from handler
 849  
     //-----------------------------------------------------------------------
 850  
     /**
 851  
      * Factory that casts the listener to a handler.
 852  
      */
 853  0
     static class Factory implements ModificationHandlerFactory {
 854  
         public ModificationHandler createHandler(Collection coll, Object listener) {
 855  0
             if (listener instanceof ModificationHandler) {
 856  0
                 return (ModificationHandler) listener;
 857  
             }
 858  0
             return null;
 859  
         }
 860  
     }
 861  
 
 862  
 }