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; 017 018 import java.util.Collection; 019 020 /** 021 * Defines a handler for collection modification events. 022 * <p> 023 * This class defines the event handling methods, following the 024 * <code>preXxx</code> and <code>postXxx</code> naming convention. 025 * It also provides a default implementation that forwards to single methods. 026 * <p> 027 * To write your own handler, you will normally subclass and override the 028 * <code>preEvent</code> and <code>postEvent</code> methods. However, you 029 * could choose to override any individual event method. 030 * <p> 031 * This class could have been implemented as an interface, however to do so 032 * would prevent the addition of extra events in the future. It does mean 033 * that if you subclass this class, you must check it when you upgrade to a 034 * later release. 035 * 036 * @since Commons Events 1.0 037 * @version $Revision: 155443 $ $Date: 2005-02-26 13:19:51 +0000 (Sat, 26 Feb 2005) $ 038 * 039 * @author Stephen Colebourne 040 */ 041 public class ModificationHandler { 042 043 /** Singleton factory */ 044 static final ModificationHandlerFactory FACTORY = new Factory(); 045 046 /** The collection being observed */ 047 private ObservableCollection obsCollection = null; 048 /** The underlying base collection being decorated */ 049 private Collection baseCollection = null; 050 /** The root handler */ 051 private final ModificationHandler rootHandler; 052 /** The view offset, 0 if not a view */ 053 private final int viewOffset; 054 055 // Constructors 056 //----------------------------------------------------------------------- 057 /** 058 * Constructor. 059 */ 060 protected ModificationHandler() { 061 super(); 062 this.rootHandler = this; 063 this.viewOffset = 0; 064 } 065 066 /** 067 * Constructor. 068 * 069 * @param rootHandler the base underlying handler 070 * @param viewOffset the offset on the base collection 071 */ 072 protected ModificationHandler(ModificationHandler rootHandler, int viewOffset) { 073 super(); 074 this.rootHandler = rootHandler; 075 this.viewOffset = viewOffset; 076 } 077 078 /** 079 * Initialize the handler. 080 * <p> 081 * The handler cannot be used until this method is called. 082 * However, the handler's setup methods can be called. 083 * All other methods will throw NullPointerException until then. 084 * 085 * @param coll the observed collection, must not be null 086 * @param baseColl the base collection, must not be null 087 * @throws IllegalArgumentException if the collection is null 088 * @throws IllegalStateException if init has already been called 089 */ 090 void init(final ObservableCollection coll, Collection baseColl) { 091 if (coll == null) { 092 throw new IllegalArgumentException("Collection must not be null"); 093 } 094 if (baseColl == null) { 095 throw new IllegalArgumentException("Base Collection must not be null"); 096 } 097 if (this.obsCollection != null) { 098 throw new IllegalArgumentException("init() has already been called"); 099 } 100 this.obsCollection = coll; 101 this.baseCollection = baseColl; 102 } 103 104 // Field access 105 //----------------------------------------------------------------------- 106 /** 107 * Gets the observed collection. 108 * 109 * @return the observed collection 110 */ 111 public ObservableCollection getObservedCollection() { 112 return obsCollection; 113 } 114 115 /** 116 * Gets the base collection. 117 * 118 * @return the base collection 119 */ 120 protected Collection getBaseCollection() { 121 return baseCollection; 122 } 123 124 /** 125 * Gets the root handler. 126 * 127 * @return the root handler 128 */ 129 protected ModificationHandler getRootHandler() { 130 return rootHandler; 131 } 132 133 /** 134 * Gets the view offset. 135 * 136 * @return the view offset 137 */ 138 protected int getViewOffset() { 139 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 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 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 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 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 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 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 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 } 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 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 postEvent(result, ModificationEventType.ADD, -1, object, 1, null, null, -1); 306 } 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 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 postEvent(true, ModificationEventType.ADD_INDEXED, index + viewOffset, object, 1, null, null, -1); 332 } 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 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 postEvent(true, ModificationEventType.ADD_NCOPIES, -1, object, nCopies, null, null, -1); 361 } 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 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 postEvent(true, ModificationEventType.ADD_ITERATED, index + viewOffset, object, 1, null, null, -1); 388 } 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 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 postEvent(collChanged, ModificationEventType.ADD_ALL, -1, coll, 1, null, null, -1); 413 } 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 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 postEvent(collChanged, ModificationEventType.ADD_ALL_INDEXED, index + viewOffset, coll, 1, null, null, -1); 440 } 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 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 postEvent(true, ModificationEventType.CLEAR, -1, null, 1, null, null, -1); 462 } 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 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 postEvent(collChanged, ModificationEventType.REMOVE, -1, object, 1, (collChanged ? object : null), null, -1); 487 } 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 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 postEvent(true, ModificationEventType.REMOVE_INDEXED, index + viewOffset, null, 1, previousValue, null, -1); 514 } 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 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 postEvent(collChanged, ModificationEventType.REMOVE_NCOPIES, -1, object, nCopies, (collChanged ? object : null), null, -1); 541 } 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 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 postEvent(true, ModificationEventType.REMOVE_NEXT, -1, removedValue, 1, removedValue, null, -1); 565 } 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 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 postEvent(true, ModificationEventType.REMOVE_ITERATED, index + viewOffset, removedValue, 1, removedValue, null, -1); 592 } 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 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 postEvent(collChanged, ModificationEventType.REMOVE_ALL, -1, coll, 1, null, null, -1); 617 } 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 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 postEvent(collChanged, ModificationEventType.RETAIN_ALL, -1, coll, 1, null, null, -1); 642 } 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 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 postEvent((object != previousValue), ModificationEventType.SET_INDEXED, index + viewOffset, object, 1, previousValue, null, -1); 672 } 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 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 postEvent((object != previousValue), ModificationEventType.SET_ITERATED, index + viewOffset, object, 1, previousValue, null, -1); 701 } 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 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 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 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 super(rootHandler, 0); 745 } 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 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 getRootHandler().postEvent( 771 modified, type, index, object, repeat, 772 previous, getObservedCollection(), offset); 773 } 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 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 super(rootHandler, viewOffset); 801 } 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 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 getRootHandler().postEvent( 827 modified, type, index, object, repeat, 828 previous, getObservedCollection(), getViewOffset()); 829 } 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 String name = getClass().getName(); 841 int pos = name.lastIndexOf('.'); 842 if (pos != -1) { 843 name = name.substring(pos + 1); 844 } 845 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 static class Factory implements ModificationHandlerFactory { 854 public ModificationHandler createHandler(Collection coll, Object listener) { 855 if (listener instanceof ModificationHandler) { 856 return (ModificationHandler) listener; 857 } 858 return null; 859 } 860 } 861 862 }