001 package data.filters; 002 003 import data.*; 004 import data.events.*; 005 006 import util.*; 007 008 import java.util.*; 009 import java.beans.*; 010 011 /** 012 * A filter for Catalogs. 013 * 014 * <p>CatalogFilters can be used to present partial views of a Catalog to parts of your application, e.g., 015 * GUI elements. However, you cannot use a CatalogFilter as a replacement for a 'real' Catalog, e.g., as an 016 * item in another Catalog.</p> 017 * 018 * <p>The actual filter condition is defined by overriding method {@link #match}.</p> 019 * 020 * @author Steffen Zschaler 021 * @version 2.0 19/08/1999 022 * @since v2.0 023 */ 024 public abstract class CatalogFilter<T extends CatalogItem> extends Object implements Catalog<T>, CatalogChangeListener<T>, 025 ListenableCatalog<T>, HelpableListener { 026 027 /** 028 * The Catalog that is being filtered. 029 * 030 * @serial 031 */ 032 protected Catalog<T> m_cOrg; 033 034 /** 035 * The listeners that listen for events from this Catalog. 036 * 037 * @serial 038 */ 039 protected ListenerHelper m_lhListeners = new ListenerHelper(this); 040 041 /** 042 * Create a new CatalogFilter. 043 * 044 * @param cOrg the Catalog to be filtered. 045 */ 046 public CatalogFilter(Catalog<T> cOrg) { 047 super(); 048 049 m_cOrg = cOrg; 050 } 051 052 /** 053 * Compare the source Catalog to the given object. 054 * 055 * @override Never 056 */ 057 public int compareTo(Object o) { 058 return m_cOrg.compareTo(o); 059 } 060 061 /** 062 * Detach the current name context from the source Catalog. 063 * 064 * @override Never 065 */ 066 public NameContext detachNC() { 067 return m_cOrg.detachNC(); 068 } 069 070 /** 071 * Attach the given name context to the source Catalog. 072 * 073 * @override Never 074 */ 075 public NameContext attach(NameContext nc) { 076 return m_cOrg.attach(nc); 077 } 078 079 /** 080 * Get the source Catalog's name. 081 * 082 * @override Never 083 */ 084 public String getName() { 085 return m_cOrg.getName(); 086 } 087 088 /** 089 * Set the source Catalog's name. 090 * 091 * @override Never 092 */ 093 public void setName(String sName, DataBasket db) throws NameContextException { 094 m_cOrg.setName(sName, db); 095 } 096 097 /** 098 * Get the source Catalog's value. 099 * 100 * @override Never 101 */ 102 public Value getValue() { 103 return m_cOrg.getValue(); 104 } 105 106 /** 107 * Register the listener with the source Catalog. 108 * 109 * @override Never 110 */ 111 public void addPropertyChangeListener(PropertyChangeListener pcl) { 112 m_cOrg.addPropertyChangeListener(pcl); 113 } 114 115 /** 116 * Un-Register the listener with the source Catalog. 117 * 118 * @override Never 119 */ 120 public void removePropertyChangeListener(PropertyChangeListener pcl) { 121 m_cOrg.removePropertyChangeListener(pcl); 122 } 123 124 /** 125 * Register the listener with the source Catalog. 126 * 127 * @override Never 128 */ 129 public void addNameListener(PropertyChangeListener pcl) { 130 m_cOrg.addNameListener(pcl); 131 } 132 133 /** 134 * Un-Register the listener with the source Catalog. 135 * 136 * @override Never 137 */ 138 public void removeNameListener(PropertyChangeListener pcl) { 139 m_cOrg.removeNameListener(pcl); 140 } 141 142 /** 143 * Register the listener with the source Catalog. 144 * 145 * @override Never 146 */ 147 public void addValueListener(PropertyChangeListener pcl) { 148 m_cOrg.addValueListener(pcl); 149 } 150 151 /** 152 * Un-Register the listener with the source Catalog. 153 * 154 * @override Never 155 */ 156 public void removeValueListener(PropertyChangeListener pcl) { 157 m_cOrg.removeValueListener(pcl); 158 } 159 160 /** 161 * Get the source Catalog's Catalog. 162 * 163 * @override Never 164 */ 165 public Catalog getCatalog() { 166 return m_cOrg.getCatalog(); 167 } 168 169 /** 170 * Get the source catalog. If the source catalog is a CatalogFilter again, 171 * return this Catalog's MainCatalog. 172 * 173 * @override Never 174 */ 175 public Catalog getMainCatalog() { 176 if (m_cOrg instanceof CatalogFilter) { 177 return ((CatalogFilter)m_cOrg).getMainCatalog(); 178 } 179 180 return m_cOrg; 181 } 182 183 /** 184 * Add the given item to the source Catalog. 185 * 186 * @override Never 187 */ 188 public void add(T ci, DataBasket db) { 189 m_cOrg.add(ci, db); 190 } 191 192 /** 193 * Remove the given item from the source Catalog if it is contained in the filtered Catalog. 194 * 195 * @override Never 196 */ 197 public T remove(T ci, DataBasket db) throws VetoException { 198 if (match(ci)) { 199 return m_cOrg.remove(ci, db); 200 } else { 201 return null; 202 } 203 } 204 205 /** 206 * Remove the given item from the source Catalog if it is contained in the filtered Catalog. 207 * 208 * @override Never 209 */ 210 public T remove(String sKey, DataBasket db) throws VetoException { 211 if (get(sKey, db, false) != null) { 212 return m_cOrg.remove(sKey, db); 213 } else { 214 return null; 215 } 216 } 217 218 /** 219 * Get the indicated item from the source Catalog if it is contained in the filtered Catalog. 220 * 221 * @override Never 222 */ 223 public T get(String sKey, DataBasket db, boolean fForEdit) throws VetoException { 224 T ci = m_cOrg.get(sKey, db, fForEdit); 225 226 if (match(ci)) { 227 return ci; 228 } else { 229 return null; 230 } 231 } 232 233 /** 234 * Check whether the indicated item is contained in the filtered Catalog. 235 * 236 * @override Never 237 */ 238 public boolean contains(String sKey, DataBasket db) { 239 if (m_cOrg.contains(sKey, db)) { 240 try { 241 CatalogItem ci = get(sKey, db, false); 242 243 return (ci != null); 244 } 245 catch (VetoException e) { 246 return false; 247 } 248 } else { 249 return false; 250 } 251 } 252 253 /** 254 * An iterator that returns only items that are contained in the filtered Catalog. 255 * 256 * @author Steffen Zschaler 257 * @version 2.0 19/08/1999 258 * @since v2.0 259 */ 260 private class FilteredIterator implements Iterator<T> { 261 private Iterator<T> m_i; 262 private T m_ciCurrent; 263 264 public FilteredIterator(Iterator<T> i) { 265 m_i = i; 266 } 267 268 public boolean hasNext() { 269 return findNext(); 270 } 271 272 public T next() { 273 if (!findNext()) { 274 throw new NoSuchElementException(); 275 } 276 277 T ciReturn = m_ciCurrent; 278 m_ciCurrent = null; 279 return ciReturn; 280 } 281 282 public void remove() { 283 m_i.remove(); // may have to be more sophisticated ! 284 } 285 286 /** 287 * Find the next item that matches the condition. Helper function. 288 * 289 * @return true if there was still a next item 290 */ 291 private boolean findNext() { 292 if (m_ciCurrent != null) { 293 return true; 294 } 295 296 while (m_i.hasNext()) { 297 m_ciCurrent = m_i.next(); 298 299 if (match(m_ciCurrent)) { 300 return true; 301 } 302 } 303 304 m_ciCurrent = null; 305 return false; 306 } 307 } 308 309 /** 310 * Get an iterator of all items that are contained in the filtered Catalog. 311 * 312 * @override Never 313 */ 314 public Iterator<T> iterator(DataBasket db, boolean fForEdit) { 315 return new FilteredIterator(m_cOrg.iterator(db, fForEdit)); 316 } 317 318 /** 319 * Return a set that contains all keys for which a CatalogItem is contained in the filtered Catalog. 320 * 321 * @override Never 322 */ 323 public Set<String> keySet(final DataBasket db) { 324 AbstractSet<String> m_set = new HashSet<String>(); 325 Iterator<T> it = new FilteredIterator(m_cOrg.iterator(db, false)); 326 while(it.hasNext()) 327 { 328 m_set.add(it.next().getName()); 329 } 330 return m_set; 331 } 332 333 /** 334 * Calculate the size of the filtered Catalog. 335 * 336 * @override Never 337 */ 338 public int size(DataBasket db) { 339 if (m_cOrg.size(db) > 0) { 340 int nReturn = 0; 341 342 for (Iterator<T> i = m_cOrg.iterator(db, false); i.hasNext(); ) { 343 if (match(i.next())) { 344 nReturn++; 345 } 346 } 347 348 return nReturn; 349 } else { 350 return 0; 351 } 352 } 353 354 /** 355 * Filter condition. 356 * 357 * @param ci the item to be tested 358 * 359 * @return true if the given item shall be an item of the filtered Catalog. 360 * 361 * @override Always 362 */ 363 protected abstract boolean match(T ci); 364 365 // CatalogChangeListener interface methods 366 367 /** 368 * Translate and propagate the event to all listeners of this Catalog. 369 * 370 * @override Never 371 */ 372 public void addedCatalogItem(CatalogChangeEvent<T> e) { 373 fireCatalogItemAdded(e.getAffectedItem(), e.getBasket()); 374 } 375 376 /** 377 * Translate and propagate the event to all listeners of this Catalog. 378 * 379 * @override Never 380 */ 381 public void commitedAddCatalogItem(CatalogChangeEvent<T> e) { 382 fireCatalogItemAddCommit(e.getAffectedItem(), e.getBasket()); 383 } 384 385 /** 386 * Translate and propagate the event to all listeners of this Catalog. 387 * 388 * @override Never 389 */ 390 public void rolledbackAddCatalogItem(CatalogChangeEvent<T> e) { 391 fireCatalogItemAddRollback(e.getAffectedItem(), e.getBasket()); 392 } 393 394 /** 395 * Translate and propagate the event to all listeners of this Catalog. 396 * 397 * @override Never 398 */ 399 public void canRemoveCatalogItem(CatalogChangeEvent<T> e) throws VetoException { 400 fireCanRemoveCatalogItem(e.getAffectedItem(), e.getBasket()); 401 } 402 403 /** 404 * Translate and propagate the event to all listeners of this Catalog. 405 * 406 * @override Never 407 */ 408 public void noRemoveCatalogItem(CatalogChangeEvent<T> e) { 409 fireNoRemoveCatalogItem(e.getAffectedItem(), e.getBasket()); 410 } 411 412 /** 413 * Translate and propagate the event to all listeners of this Catalog. 414 * 415 * @override Never 416 */ 417 public void removedCatalogItem(CatalogChangeEvent<T> e) { 418 fireCatalogItemRemoved(e.getAffectedItem(), e.getBasket()); 419 } 420 421 /** 422 * Translate and propagate the event to all listeners of this Catalog. 423 * 424 * @override Never 425 */ 426 public void commitedRemoveCatalogItem(CatalogChangeEvent<T> e) { 427 fireCatalogItemRemoveCommit(e.getAffectedItem(), e.getBasket()); 428 } 429 430 /** 431 * Translate and propagate the event to all listeners of this Catalog. 432 * 433 * @override Never 434 */ 435 public void rolledbackRemoveCatalogItem(CatalogChangeEvent<T> e) { 436 fireCatalogItemRemoveRollback(e.getAffectedItem(), e.getBasket()); 437 } 438 439 /** 440 * Translate and propagate the event to all listeners of this Catalog. 441 * 442 * @override Never 443 */ 444 public void canEditCatalogItem(CatalogChangeEvent<T> e) throws VetoException { 445 fireCanEditCatalogItem(e.getAffectedItem(), e.getBasket()); 446 } 447 448 /** 449 * Translate and propagate the event to all listeners of this Catalog. 450 * 451 * @override Never 452 */ 453 public void noEditCatalogItem(CatalogChangeEvent<T> e) { 454 fireNoEditCatalogItem(e.getAffectedItem(), e.getBasket()); 455 } 456 457 /** 458 * Translate and propagate the event to all listeners of this Catalog. 459 * 460 * @override Never 461 */ 462 public void editingCatalogItem(CatalogChangeEvent<T> e) { 463 fireEditingCatalogItem(e.getAffectedItem(), e.getBasket()); 464 } 465 466 /** 467 * Translate and propagate the event to all listeners of this Catalog. 468 * 469 * @override Never 470 */ 471 public void commitEditCatalogItem(CatalogChangeEvent<T> e) { 472 fireCommitEditCatalogItem(e.getAffectedItem(), e.getBasket()); 473 } 474 475 /** 476 * Translate and propagate the event to all listeners of this Catalog. 477 * 478 * @override Never 479 */ 480 public void rollbackEditCatalogItem(CatalogChangeEvent<T> e) { 481 fireRollbackEditCatalogItem(e.getAffectedItem(), e.getBasket()); 482 } 483 484 // ListenableCatalog interface methods 485 486 /** 487 * Add a listener that wishes to receive events when the filtered Catalog changes. 488 * 489 * @override Never 490 */ 491 public void addCatalogChangeListener(CatalogChangeListener ccl) { 492 m_lhListeners.add(CatalogChangeListener.class, ccl); 493 } 494 495 /** 496 * Remove a listener that received events when the filtered Catalog changed. 497 * 498 * @override Never 499 */ 500 public void removeCatalogChangeListener(CatalogChangeListener ccl) { 501 m_lhListeners.remove(CatalogChangeListener.class, ccl); 502 } 503 504 /** 505 * Fire the event to all listeners of this Catalog. 506 * 507 * @override Never 508 */ 509 @SuppressWarnings("unchecked") 510 protected void fireCatalogItemAdded(T ci, DataBasket db) { 511 Object[] listeners = m_lhListeners.getListenerList(); 512 CatalogChangeEvent cce = null; 513 514 for (int i = listeners.length - 2; i >= 0; i -= 2) { 515 if (listeners[i] == CatalogChangeListener.class) { 516 if (cce == null) { 517 cce = new CatalogChangeEvent<T>(this, ci, db); 518 } 519 520 ((CatalogChangeListener)listeners[i + 1]).addedCatalogItem(cce); 521 } 522 } 523 } 524 525 /** 526 * Fire the event to all listeners of this Catalog. 527 * 528 * @override Never 529 */ 530 @SuppressWarnings("unchecked") 531 protected void fireCatalogItemAddCommit(T ci, DataBasket db) { 532 Object[] listeners = m_lhListeners.getListenerList(); 533 CatalogChangeEvent cce = null; 534 535 for (int i = listeners.length - 2; i >= 0; i -= 2) { 536 if (listeners[i] == CatalogChangeListener.class) { 537 if (cce == null) { 538 cce = new CatalogChangeEvent<T>(this, ci, db); 539 } 540 541 ((CatalogChangeListener)listeners[i + 1]).commitedAddCatalogItem(cce); 542 } 543 } 544 } 545 546 /** 547 * Fire the event to all listeners of this Catalog. 548 * 549 * @override Never 550 */ 551 @SuppressWarnings("unchecked") 552 protected void fireCatalogItemAddRollback(T ci, DataBasket db) { 553 Object[] listeners = m_lhListeners.getListenerList(); 554 CatalogChangeEvent cce = null; 555 556 for (int i = listeners.length - 2; i >= 0; i -= 2) { 557 if (listeners[i] == CatalogChangeListener.class) { 558 if (cce == null) { 559 cce = new CatalogChangeEvent<T>(this, ci, db); 560 } 561 562 ((CatalogChangeListener)listeners[i + 1]).rolledbackAddCatalogItem(cce); 563 } 564 } 565 } 566 567 /** 568 * Fire the event to all listeners of this Catalog. 569 * 570 * @override Never 571 */ 572 @SuppressWarnings("unchecked") 573 protected void fireCatalogItemRemoved(T ci, DataBasket db) { 574 Object[] listeners = m_lhListeners.getListenerList(); 575 CatalogChangeEvent cce = null; 576 577 for (int i = listeners.length - 2; i >= 0; i -= 2) { 578 if (listeners[i] == CatalogChangeListener.class) { 579 if (cce == null) { 580 cce = new CatalogChangeEvent<T>(this, ci, db); 581 } 582 583 ((CatalogChangeListener)listeners[i + 1]).removedCatalogItem(cce); 584 } 585 } 586 } 587 588 /** 589 * Fire the event to all listeners of this Catalog. 590 * 591 * @override Never 592 */ 593 @SuppressWarnings("unchecked") 594 protected void fireCatalogItemRemoveCommit(T ci, DataBasket db) { 595 Object[] listeners = m_lhListeners.getListenerList(); 596 CatalogChangeEvent cce = null; 597 598 for (int i = listeners.length - 2; i >= 0; i -= 2) { 599 if (listeners[i] == CatalogChangeListener.class) { 600 if (cce == null) { 601 cce = new CatalogChangeEvent<T>(this, ci, db); 602 } 603 604 ((CatalogChangeListener)listeners[i + 1]).commitedRemoveCatalogItem(cce); 605 } 606 } 607 } 608 609 /** 610 * Fire the event to all listeners of this Catalog. 611 * 612 * @override Never 613 */ 614 @SuppressWarnings("unchecked") 615 protected void fireCatalogItemRemoveRollback(T ci, DataBasket db) { 616 Object[] listeners = m_lhListeners.getListenerList(); 617 CatalogChangeEvent cce = null; 618 619 for (int i = listeners.length - 2; i >= 0; i -= 2) { 620 if (listeners[i] == CatalogChangeListener.class) { 621 if (cce == null) { 622 cce = new CatalogChangeEvent<T>(this, ci, db); 623 } 624 625 ((CatalogChangeListener)listeners[i + 1]).rolledbackRemoveCatalogItem(cce); 626 } 627 } 628 } 629 630 /** 631 * Fire the event to all listeners of this Catalog. 632 * 633 * @override Never 634 */ 635 @SuppressWarnings("unchecked") 636 protected void fireCanRemoveCatalogItem(T ci, DataBasket db) throws VetoException { 637 Object[] temp = m_lhListeners.getListenerList(); 638 Object[] listeners = new Object[temp.length]; 639 System.arraycopy(temp, 0, listeners, 0, temp.length); 640 641 CatalogChangeEvent cce = null; 642 643 for (int i = listeners.length - 2; i >= 0; i -= 2) { 644 if (listeners[i] == CatalogChangeListener.class) { 645 if (cce == null) { 646 cce = new CatalogChangeEvent<T>(this, ci, db); 647 } 648 649 ((CatalogChangeListener)listeners[i + 1]).canRemoveCatalogItem(cce); 650 } 651 } 652 } 653 654 /** 655 * Fire the event to all listeners of this Catalog. 656 * 657 * @override Never 658 */ 659 @SuppressWarnings("unchecked") 660 protected void fireNoRemoveCatalogItem(T ci, DataBasket db) { 661 Object[] listeners = m_lhListeners.getListenerList(); 662 CatalogChangeEvent cce = null; 663 664 for (int i = listeners.length - 2; i >= 0; i -= 2) { 665 if (listeners[i] == CatalogChangeListener.class) { 666 if (cce == null) { 667 cce = new CatalogChangeEvent<T>(this, ci, db); 668 } 669 670 ((CatalogChangeListener)listeners[i + 1]).noRemoveCatalogItem(cce); 671 } 672 } 673 } 674 675 /** 676 * Fire the event to all listeners of this Catalog. 677 * 678 * @override Never 679 */ 680 @SuppressWarnings("unchecked") 681 protected void fireCanEditCatalogItem(T ci, DataBasket db) throws VetoException { 682 Object[] temp = m_lhListeners.getListenerList(); 683 Object[] listeners = new Object[temp.length]; 684 System.arraycopy(temp, 0, listeners, 0, temp.length); 685 686 CatalogChangeEvent cce = null; 687 688 for (int i = listeners.length - 2; i >= 0; i -= 2) { 689 if (listeners[i] == CatalogChangeListener.class) { 690 if (cce == null) { 691 cce = new CatalogChangeEvent<T>(this, ci, db); 692 } 693 694 ((CatalogChangeListener)listeners[i + 1]).canEditCatalogItem(cce); 695 } 696 } 697 } 698 699 /** 700 * Fire the event to all listeners of this Catalog. 701 * 702 * @override Never 703 */ 704 @SuppressWarnings("unchecked") 705 protected void fireNoEditCatalogItem(T ci, DataBasket db) { 706 Object[] listeners = m_lhListeners.getListenerList(); 707 CatalogChangeEvent cce = null; 708 709 for (int i = listeners.length - 2; i >= 0; i -= 2) { 710 if (listeners[i] == CatalogChangeListener.class) { 711 if (cce == null) { 712 cce = new CatalogChangeEvent<T>(this, ci, db); 713 } 714 715 ((CatalogChangeListener)listeners[i + 1]).noEditCatalogItem(cce); 716 } 717 } 718 } 719 720 /** 721 * Fire the event to all listeners of this Catalog. 722 * 723 * @override Never 724 */ 725 @SuppressWarnings("unchecked") 726 protected void fireEditingCatalogItem(T ci, DataBasket db) { 727 Object[] listeners = m_lhListeners.getListenerList(); 728 729 CatalogChangeEvent cce = null; 730 731 for (int i = listeners.length - 2; i >= 0; i -= 2) { 732 if (listeners[i] == CatalogChangeListener.class) { 733 if (cce == null) { 734 cce = new CatalogChangeEvent<T>(this, ci, db); 735 } 736 737 ((CatalogChangeListener)listeners[i + 1]).editingCatalogItem(cce); 738 } 739 } 740 } 741 742 /** 743 * Fire the event to all listeners of this Catalog. 744 * 745 * @override Never 746 */ 747 @SuppressWarnings("unchecked") 748 protected void fireCommitEditCatalogItem(T ci, DataBasket db) { 749 Object[] listeners = m_lhListeners.getListenerList(); 750 751 CatalogChangeEvent cce = null; 752 753 for (int i = listeners.length - 2; i >= 0; i -= 2) { 754 if (listeners[i] == CatalogChangeListener.class) { 755 if (cce == null) { 756 cce = new CatalogChangeEvent<T>(this, ci, db); 757 } 758 759 ((CatalogChangeListener)listeners[i + 1]).commitEditCatalogItem(cce); 760 } 761 } 762 } 763 764 /** 765 * Fire the event to all listeners of this Catalog. 766 * 767 * @override Never 768 */ 769 @SuppressWarnings("unchecked") 770 protected void fireRollbackEditCatalogItem(T ci, DataBasket db) { 771 Object[] listeners = m_lhListeners.getListenerList(); 772 773 CatalogChangeEvent cce = null; 774 775 for (int i = listeners.length - 2; i >= 0; i -= 2) { 776 if (listeners[i] == CatalogChangeListener.class) { 777 if (cce == null) { 778 cce = new CatalogChangeEvent<T>(this, ci, db); 779 } 780 781 ((CatalogChangeListener)listeners[i + 1]).rollbackEditCatalogItem(cce); 782 } 783 } 784 } 785 786 // HelpableListener interface methods 787 /** 788 * Subscribe as a listener to the source Catalog if that is a {@link ListenableCatalog}. 789 * 790 * @override Never 791 */ 792 @SuppressWarnings("unchecked") 793 public void subscribe() { 794 if (m_cOrg instanceof ListenableCatalog) { 795 ((ListenableCatalog)m_cOrg).addCatalogChangeListener(this); 796 } 797 } 798 799 /** 800 * Un-Subscribe as a listener from the source Catalog if that is a {@link ListenableCatalog}. 801 * 802 * @override Never 803 */ 804 @SuppressWarnings("unchecked") 805 public void unsubscribe() { 806 if (m_cOrg instanceof ListenableCatalog) { 807 ((ListenableCatalog)m_cOrg).removeCatalogChangeListener(this); 808 } 809 } 810 811 /** 812 * Empty method body. 813 * 814 * @override Never 815 */ 816 public void updateModel() {} 817 }