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 extends Object implements Catalog, CatalogChangeListener, 025 ListenableCatalog, HelpableListener { 026 027 /** 028 * The Catalog that is being filtered. 029 * 030 * @serial 031 */ 032 protected Catalog 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 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(CatalogItem 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 CatalogItem remove(CatalogItem 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 CatalogItem 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 CatalogItem get(String sKey, DataBasket db, boolean fForEdit) throws VetoException { 224 CatalogItem 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 { 261 private Iterator m_i; 262 private Object m_oCurrent; 263 264 public FilteredIterator(Iterator i) { 265 m_i = i; 266 } 267 268 public boolean hasNext() { 269 return findNext(); 270 } 271 272 public Object next() { 273 if (!findNext()) { 274 throw new NoSuchElementException(); 275 } 276 277 Object oReturn = m_oCurrent; 278 m_oCurrent = null; 279 return oReturn; 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_oCurrent != null) { 293 return true; 294 } 295 296 while (m_i.hasNext()) { 297 m_oCurrent = m_i.next(); 298 299 if (match((CatalogItem)m_oCurrent)) { 300 return true; 301 } 302 } 303 304 m_oCurrent = 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 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 keySet(final DataBasket db) { 324 // return filtered set 325 class S extends AbstractSet { 326 public Iterator iterator() { 327 return new FilteredIterator(m_cOrg.iterator(db, false)) { 328 public Object next() { 329 CatalogItem ci = (CatalogItem)super.next(); 330 return ci.getName(); 331 } 332 333 public void remove() { 334 throw new UnsupportedOperationException(); 335 } 336 }; 337 } 338 339 public int size() { 340 return CatalogFilter.this.size(db); 341 } 342 } 343 344 return new S(); 345 } 346 347 /** 348 * Calculate the size of the filtered Catalog. 349 * 350 * @override Never 351 */ 352 public int size(DataBasket db) { 353 if (m_cOrg.size(db) > 0) { 354 int nReturn = 0; 355 356 for (Iterator i = m_cOrg.iterator(db, false); i.hasNext(); ) { 357 if (match((CatalogItem)i.next())) { 358 nReturn++; 359 } 360 } 361 362 return nReturn; 363 } else { 364 return 0; 365 } 366 } 367 368 /** 369 * Filter condition. 370 * 371 * @param ci the item to be tested 372 * 373 * @return true if the given item shall be an item of the filtered Catalog. 374 * 375 * @override Always 376 */ 377 protected abstract boolean match(CatalogItem ci); 378 379 // CatalogChangeListener interface methods 380 381 /** 382 * Translate and propagate the event to all listeners of this Catalog. 383 * 384 * @override Never 385 */ 386 public void addedCatalogItem(CatalogChangeEvent e) { 387 fireCatalogItemAdded(e.getAffectedItem(), e.getBasket()); 388 } 389 390 /** 391 * Translate and propagate the event to all listeners of this Catalog. 392 * 393 * @override Never 394 */ 395 public void commitedAddCatalogItem(CatalogChangeEvent e) { 396 fireCatalogItemAddCommit(e.getAffectedItem(), e.getBasket()); 397 } 398 399 /** 400 * Translate and propagate the event to all listeners of this Catalog. 401 * 402 * @override Never 403 */ 404 public void rolledbackAddCatalogItem(CatalogChangeEvent e) { 405 fireCatalogItemAddRollback(e.getAffectedItem(), e.getBasket()); 406 } 407 408 /** 409 * Translate and propagate the event to all listeners of this Catalog. 410 * 411 * @override Never 412 */ 413 public void canRemoveCatalogItem(CatalogChangeEvent e) throws VetoException { 414 fireCanRemoveCatalogItem(e.getAffectedItem(), e.getBasket()); 415 } 416 417 /** 418 * Translate and propagate the event to all listeners of this Catalog. 419 * 420 * @override Never 421 */ 422 public void noRemoveCatalogItem(CatalogChangeEvent e) { 423 fireNoRemoveCatalogItem(e.getAffectedItem(), e.getBasket()); 424 } 425 426 /** 427 * Translate and propagate the event to all listeners of this Catalog. 428 * 429 * @override Never 430 */ 431 public void removedCatalogItem(CatalogChangeEvent e) { 432 fireCatalogItemRemoved(e.getAffectedItem(), e.getBasket()); 433 } 434 435 /** 436 * Translate and propagate the event to all listeners of this Catalog. 437 * 438 * @override Never 439 */ 440 public void commitedRemoveCatalogItem(CatalogChangeEvent e) { 441 fireCatalogItemRemoveCommit(e.getAffectedItem(), e.getBasket()); 442 } 443 444 /** 445 * Translate and propagate the event to all listeners of this Catalog. 446 * 447 * @override Never 448 */ 449 public void rolledbackRemoveCatalogItem(CatalogChangeEvent e) { 450 fireCatalogItemRemoveRollback(e.getAffectedItem(), e.getBasket()); 451 } 452 453 /** 454 * Translate and propagate the event to all listeners of this Catalog. 455 * 456 * @override Never 457 */ 458 public void canEditCatalogItem(CatalogChangeEvent e) throws VetoException { 459 fireCanEditCatalogItem(e.getAffectedItem(), e.getBasket()); 460 } 461 462 /** 463 * Translate and propagate the event to all listeners of this Catalog. 464 * 465 * @override Never 466 */ 467 public void noEditCatalogItem(CatalogChangeEvent e) { 468 fireNoEditCatalogItem(e.getAffectedItem(), e.getBasket()); 469 } 470 471 /** 472 * Translate and propagate the event to all listeners of this Catalog. 473 * 474 * @override Never 475 */ 476 public void editingCatalogItem(CatalogChangeEvent e) { 477 fireEditingCatalogItem(e.getAffectedItem(), e.getBasket()); 478 } 479 480 /** 481 * Translate and propagate the event to all listeners of this Catalog. 482 * 483 * @override Never 484 */ 485 public void commitEditCatalogItem(CatalogChangeEvent e) { 486 fireCommitEditCatalogItem(e.getAffectedItem(), e.getBasket()); 487 } 488 489 /** 490 * Translate and propagate the event to all listeners of this Catalog. 491 * 492 * @override Never 493 */ 494 public void rollbackEditCatalogItem(CatalogChangeEvent e) { 495 fireRollbackEditCatalogItem(e.getAffectedItem(), e.getBasket()); 496 } 497 498 // ListenableCatalog interface methods 499 500 /** 501 * Add a listener that wishes to receive events when the filtered Catalog changes. 502 * 503 * @override Never 504 */ 505 public void addCatalogChangeListener(CatalogChangeListener ccl) { 506 m_lhListeners.add(CatalogChangeListener.class, ccl); 507 } 508 509 /** 510 * Remove a listener that received events when the filtered Catalog changed. 511 * 512 * @override Never 513 */ 514 public void removeCatalogChangeListener(CatalogChangeListener ccl) { 515 m_lhListeners.remove(CatalogChangeListener.class, ccl); 516 } 517 518 /** 519 * Fire the event to all listeners of this Catalog. 520 * 521 * @override Never 522 */ 523 protected void fireCatalogItemAdded(CatalogItem ci, DataBasket db) { 524 Object[] listeners = m_lhListeners.getListenerList(); 525 CatalogChangeEvent cce = null; 526 527 for (int i = listeners.length - 2; i >= 0; i -= 2) { 528 if (listeners[i] == CatalogChangeListener.class) { 529 if (cce == null) { 530 cce = new CatalogChangeEvent(this, ci, db); 531 } 532 533 ((CatalogChangeListener)listeners[i + 1]).addedCatalogItem(cce); 534 } 535 } 536 } 537 538 /** 539 * Fire the event to all listeners of this Catalog. 540 * 541 * @override Never 542 */ 543 protected void fireCatalogItemAddCommit(CatalogItem ci, DataBasket db) { 544 Object[] listeners = m_lhListeners.getListenerList(); 545 CatalogChangeEvent cce = null; 546 547 for (int i = listeners.length - 2; i >= 0; i -= 2) { 548 if (listeners[i] == CatalogChangeListener.class) { 549 if (cce == null) { 550 cce = new CatalogChangeEvent(this, ci, db); 551 } 552 553 ((CatalogChangeListener)listeners[i + 1]).commitedAddCatalogItem(cce); 554 } 555 } 556 } 557 558 /** 559 * Fire the event to all listeners of this Catalog. 560 * 561 * @override Never 562 */ 563 protected void fireCatalogItemAddRollback(CatalogItem ci, DataBasket db) { 564 Object[] listeners = m_lhListeners.getListenerList(); 565 CatalogChangeEvent cce = null; 566 567 for (int i = listeners.length - 2; i >= 0; i -= 2) { 568 if (listeners[i] == CatalogChangeListener.class) { 569 if (cce == null) { 570 cce = new CatalogChangeEvent(this, ci, db); 571 } 572 573 ((CatalogChangeListener)listeners[i + 1]).rolledbackAddCatalogItem(cce); 574 } 575 } 576 } 577 578 /** 579 * Fire the event to all listeners of this Catalog. 580 * 581 * @override Never 582 */ 583 protected void fireCatalogItemRemoved(CatalogItem ci, DataBasket db) { 584 Object[] listeners = m_lhListeners.getListenerList(); 585 CatalogChangeEvent cce = null; 586 587 for (int i = listeners.length - 2; i >= 0; i -= 2) { 588 if (listeners[i] == CatalogChangeListener.class) { 589 if (cce == null) { 590 cce = new CatalogChangeEvent(this, ci, db); 591 } 592 593 ((CatalogChangeListener)listeners[i + 1]).removedCatalogItem(cce); 594 } 595 } 596 } 597 598 /** 599 * Fire the event to all listeners of this Catalog. 600 * 601 * @override Never 602 */ 603 protected void fireCatalogItemRemoveCommit(CatalogItem ci, DataBasket db) { 604 Object[] listeners = m_lhListeners.getListenerList(); 605 CatalogChangeEvent cce = null; 606 607 for (int i = listeners.length - 2; i >= 0; i -= 2) { 608 if (listeners[i] == CatalogChangeListener.class) { 609 if (cce == null) { 610 cce = new CatalogChangeEvent(this, ci, db); 611 } 612 613 ((CatalogChangeListener)listeners[i + 1]).commitedRemoveCatalogItem(cce); 614 } 615 } 616 } 617 618 /** 619 * Fire the event to all listeners of this Catalog. 620 * 621 * @override Never 622 */ 623 protected void fireCatalogItemRemoveRollback(CatalogItem ci, DataBasket db) { 624 Object[] listeners = m_lhListeners.getListenerList(); 625 CatalogChangeEvent cce = null; 626 627 for (int i = listeners.length - 2; i >= 0; i -= 2) { 628 if (listeners[i] == CatalogChangeListener.class) { 629 if (cce == null) { 630 cce = new CatalogChangeEvent(this, ci, db); 631 } 632 633 ((CatalogChangeListener)listeners[i + 1]).rolledbackRemoveCatalogItem(cce); 634 } 635 } 636 } 637 638 /** 639 * Fire the event to all listeners of this Catalog. 640 * 641 * @override Never 642 */ 643 protected void fireCanRemoveCatalogItem(CatalogItem ci, DataBasket db) throws VetoException { 644 Object[] temp = m_lhListeners.getListenerList(); 645 Object[] listeners = new Object[temp.length]; 646 System.arraycopy(temp, 0, listeners, 0, temp.length); 647 648 CatalogChangeEvent cce = null; 649 650 for (int i = listeners.length - 2; i >= 0; i -= 2) { 651 if (listeners[i] == CatalogChangeListener.class) { 652 if (cce == null) { 653 cce = new CatalogChangeEvent(this, ci, db); 654 } 655 656 ((CatalogChangeListener)listeners[i + 1]).canRemoveCatalogItem(cce); 657 } 658 } 659 } 660 661 /** 662 * Fire the event to all listeners of this Catalog. 663 * 664 * @override Never 665 */ 666 protected void fireNoRemoveCatalogItem(CatalogItem ci, DataBasket db) { 667 Object[] listeners = m_lhListeners.getListenerList(); 668 CatalogChangeEvent cce = null; 669 670 for (int i = listeners.length - 2; i >= 0; i -= 2) { 671 if (listeners[i] == CatalogChangeListener.class) { 672 if (cce == null) { 673 cce = new CatalogChangeEvent(this, ci, db); 674 } 675 676 ((CatalogChangeListener)listeners[i + 1]).noRemoveCatalogItem(cce); 677 } 678 } 679 } 680 681 /** 682 * Fire the event to all listeners of this Catalog. 683 * 684 * @override Never 685 */ 686 protected void fireCanEditCatalogItem(CatalogItem ci, DataBasket db) throws VetoException { 687 Object[] temp = m_lhListeners.getListenerList(); 688 Object[] listeners = new Object[temp.length]; 689 System.arraycopy(temp, 0, listeners, 0, temp.length); 690 691 CatalogChangeEvent cce = null; 692 693 for (int i = listeners.length - 2; i >= 0; i -= 2) { 694 if (listeners[i] == CatalogChangeListener.class) { 695 if (cce == null) { 696 cce = new CatalogChangeEvent(this, ci, db); 697 } 698 699 ((CatalogChangeListener)listeners[i + 1]).canEditCatalogItem(cce); 700 } 701 } 702 } 703 704 /** 705 * Fire the event to all listeners of this Catalog. 706 * 707 * @override Never 708 */ 709 protected void fireNoEditCatalogItem(CatalogItem ci, DataBasket db) { 710 Object[] listeners = m_lhListeners.getListenerList(); 711 CatalogChangeEvent cce = null; 712 713 for (int i = listeners.length - 2; i >= 0; i -= 2) { 714 if (listeners[i] == CatalogChangeListener.class) { 715 if (cce == null) { 716 cce = new CatalogChangeEvent(this, ci, db); 717 } 718 719 ((CatalogChangeListener)listeners[i + 1]).noEditCatalogItem(cce); 720 } 721 } 722 } 723 724 /** 725 * Fire the event to all listeners of this Catalog. 726 * 727 * @override Never 728 */ 729 protected void fireEditingCatalogItem(CatalogItem ci, DataBasket db) { 730 Object[] listeners = m_lhListeners.getListenerList(); 731 732 CatalogChangeEvent cce = null; 733 734 for (int i = listeners.length - 2; i >= 0; i -= 2) { 735 if (listeners[i] == CatalogChangeListener.class) { 736 if (cce == null) { 737 cce = new CatalogChangeEvent(this, ci, db); 738 } 739 740 ((CatalogChangeListener)listeners[i + 1]).editingCatalogItem(cce); 741 } 742 } 743 } 744 745 /** 746 * Fire the event to all listeners of this Catalog. 747 * 748 * @override Never 749 */ 750 protected void fireCommitEditCatalogItem(CatalogItem ci, DataBasket db) { 751 Object[] listeners = m_lhListeners.getListenerList(); 752 753 CatalogChangeEvent cce = null; 754 755 for (int i = listeners.length - 2; i >= 0; i -= 2) { 756 if (listeners[i] == CatalogChangeListener.class) { 757 if (cce == null) { 758 cce = new CatalogChangeEvent(this, ci, db); 759 } 760 761 ((CatalogChangeListener)listeners[i + 1]).commitEditCatalogItem(cce); 762 } 763 } 764 } 765 766 /** 767 * Fire the event to all listeners of this Catalog. 768 * 769 * @override Never 770 */ 771 protected void fireRollbackEditCatalogItem(CatalogItem ci, DataBasket db) { 772 Object[] listeners = m_lhListeners.getListenerList(); 773 774 CatalogChangeEvent cce = null; 775 776 for (int i = listeners.length - 2; i >= 0; i -= 2) { 777 if (listeners[i] == CatalogChangeListener.class) { 778 if (cce == null) { 779 cce = new CatalogChangeEvent(this, ci, db); 780 } 781 782 ((CatalogChangeListener)listeners[i + 1]).rollbackEditCatalogItem(cce); 783 } 784 } 785 } 786 787 // HelpableListener interface methods 788 /** 789 * Subscribe as a listener to the source Catalog if that is a {@link ListenableCatalog}. 790 * 791 * @override Never 792 */ 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 public void unsubscribe() { 805 if (m_cOrg instanceof ListenableCatalog) { 806 ((ListenableCatalog)m_cOrg).removeCatalogChangeListener(this); 807 } 808 } 809 810 /** 811 * Empty method body. 812 * 813 * @override Never 814 */ 815 public void updateModel() {} 816 }