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<CatalogItem> { 261 private Iterator<CatalogItem> m_i; 262 private CatalogItem m_ciCurrent; 263 264 public FilteredIterator(Iterator<CatalogItem> i) { 265 m_i = i; 266 } 267 268 public boolean hasNext() { 269 return findNext(); 270 } 271 272 public CatalogItem next() { 273 if (!findNext()) { 274 throw new NoSuchElementException(); 275 } 276 277 CatalogItem 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((CatalogItem)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<CatalogItem> 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<CatalogItem> 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<CatalogItem> 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(CatalogItem 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 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 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 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 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 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 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 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 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 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 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 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 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 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 protected void fireCatalogItemAdded(CatalogItem ci, DataBasket db) { 510 Object[] listeners = m_lhListeners.getListenerList(); 511 CatalogChangeEvent cce = null; 512 513 for (int i = listeners.length - 2; i >= 0; i -= 2) { 514 if (listeners[i] == CatalogChangeListener.class) { 515 if (cce == null) { 516 cce = new CatalogChangeEvent(this, ci, db); 517 } 518 519 ((CatalogChangeListener)listeners[i + 1]).addedCatalogItem(cce); 520 } 521 } 522 } 523 524 /** 525 * Fire the event to all listeners of this Catalog. 526 * 527 * @override Never 528 */ 529 protected void fireCatalogItemAddCommit(CatalogItem ci, DataBasket db) { 530 Object[] listeners = m_lhListeners.getListenerList(); 531 CatalogChangeEvent cce = null; 532 533 for (int i = listeners.length - 2; i >= 0; i -= 2) { 534 if (listeners[i] == CatalogChangeListener.class) { 535 if (cce == null) { 536 cce = new CatalogChangeEvent(this, ci, db); 537 } 538 539 ((CatalogChangeListener)listeners[i + 1]).commitedAddCatalogItem(cce); 540 } 541 } 542 } 543 544 /** 545 * Fire the event to all listeners of this Catalog. 546 * 547 * @override Never 548 */ 549 protected void fireCatalogItemAddRollback(CatalogItem ci, DataBasket db) { 550 Object[] listeners = m_lhListeners.getListenerList(); 551 CatalogChangeEvent cce = null; 552 553 for (int i = listeners.length - 2; i >= 0; i -= 2) { 554 if (listeners[i] == CatalogChangeListener.class) { 555 if (cce == null) { 556 cce = new CatalogChangeEvent(this, ci, db); 557 } 558 559 ((CatalogChangeListener)listeners[i + 1]).rolledbackAddCatalogItem(cce); 560 } 561 } 562 } 563 564 /** 565 * Fire the event to all listeners of this Catalog. 566 * 567 * @override Never 568 */ 569 protected void fireCatalogItemRemoved(CatalogItem ci, DataBasket db) { 570 Object[] listeners = m_lhListeners.getListenerList(); 571 CatalogChangeEvent cce = null; 572 573 for (int i = listeners.length - 2; i >= 0; i -= 2) { 574 if (listeners[i] == CatalogChangeListener.class) { 575 if (cce == null) { 576 cce = new CatalogChangeEvent(this, ci, db); 577 } 578 579 ((CatalogChangeListener)listeners[i + 1]).removedCatalogItem(cce); 580 } 581 } 582 } 583 584 /** 585 * Fire the event to all listeners of this Catalog. 586 * 587 * @override Never 588 */ 589 protected void fireCatalogItemRemoveCommit(CatalogItem ci, DataBasket db) { 590 Object[] listeners = m_lhListeners.getListenerList(); 591 CatalogChangeEvent cce = null; 592 593 for (int i = listeners.length - 2; i >= 0; i -= 2) { 594 if (listeners[i] == CatalogChangeListener.class) { 595 if (cce == null) { 596 cce = new CatalogChangeEvent(this, ci, db); 597 } 598 599 ((CatalogChangeListener)listeners[i + 1]).commitedRemoveCatalogItem(cce); 600 } 601 } 602 } 603 604 /** 605 * Fire the event to all listeners of this Catalog. 606 * 607 * @override Never 608 */ 609 protected void fireCatalogItemRemoveRollback(CatalogItem ci, DataBasket db) { 610 Object[] listeners = m_lhListeners.getListenerList(); 611 CatalogChangeEvent cce = null; 612 613 for (int i = listeners.length - 2; i >= 0; i -= 2) { 614 if (listeners[i] == CatalogChangeListener.class) { 615 if (cce == null) { 616 cce = new CatalogChangeEvent(this, ci, db); 617 } 618 619 ((CatalogChangeListener)listeners[i + 1]).rolledbackRemoveCatalogItem(cce); 620 } 621 } 622 } 623 624 /** 625 * Fire the event to all listeners of this Catalog. 626 * 627 * @override Never 628 */ 629 protected void fireCanRemoveCatalogItem(CatalogItem ci, DataBasket db) throws VetoException { 630 Object[] temp = m_lhListeners.getListenerList(); 631 Object[] listeners = new Object[temp.length]; 632 System.arraycopy(temp, 0, listeners, 0, temp.length); 633 634 CatalogChangeEvent cce = null; 635 636 for (int i = listeners.length - 2; i >= 0; i -= 2) { 637 if (listeners[i] == CatalogChangeListener.class) { 638 if (cce == null) { 639 cce = new CatalogChangeEvent(this, ci, db); 640 } 641 642 ((CatalogChangeListener)listeners[i + 1]).canRemoveCatalogItem(cce); 643 } 644 } 645 } 646 647 /** 648 * Fire the event to all listeners of this Catalog. 649 * 650 * @override Never 651 */ 652 protected void fireNoRemoveCatalogItem(CatalogItem ci, DataBasket db) { 653 Object[] listeners = m_lhListeners.getListenerList(); 654 CatalogChangeEvent cce = null; 655 656 for (int i = listeners.length - 2; i >= 0; i -= 2) { 657 if (listeners[i] == CatalogChangeListener.class) { 658 if (cce == null) { 659 cce = new CatalogChangeEvent(this, ci, db); 660 } 661 662 ((CatalogChangeListener)listeners[i + 1]).noRemoveCatalogItem(cce); 663 } 664 } 665 } 666 667 /** 668 * Fire the event to all listeners of this Catalog. 669 * 670 * @override Never 671 */ 672 protected void fireCanEditCatalogItem(CatalogItem ci, DataBasket db) throws VetoException { 673 Object[] temp = m_lhListeners.getListenerList(); 674 Object[] listeners = new Object[temp.length]; 675 System.arraycopy(temp, 0, listeners, 0, temp.length); 676 677 CatalogChangeEvent cce = null; 678 679 for (int i = listeners.length - 2; i >= 0; i -= 2) { 680 if (listeners[i] == CatalogChangeListener.class) { 681 if (cce == null) { 682 cce = new CatalogChangeEvent(this, ci, db); 683 } 684 685 ((CatalogChangeListener)listeners[i + 1]).canEditCatalogItem(cce); 686 } 687 } 688 } 689 690 /** 691 * Fire the event to all listeners of this Catalog. 692 * 693 * @override Never 694 */ 695 protected void fireNoEditCatalogItem(CatalogItem ci, DataBasket db) { 696 Object[] listeners = m_lhListeners.getListenerList(); 697 CatalogChangeEvent cce = null; 698 699 for (int i = listeners.length - 2; i >= 0; i -= 2) { 700 if (listeners[i] == CatalogChangeListener.class) { 701 if (cce == null) { 702 cce = new CatalogChangeEvent(this, ci, db); 703 } 704 705 ((CatalogChangeListener)listeners[i + 1]).noEditCatalogItem(cce); 706 } 707 } 708 } 709 710 /** 711 * Fire the event to all listeners of this Catalog. 712 * 713 * @override Never 714 */ 715 protected void fireEditingCatalogItem(CatalogItem ci, DataBasket db) { 716 Object[] listeners = m_lhListeners.getListenerList(); 717 718 CatalogChangeEvent cce = null; 719 720 for (int i = listeners.length - 2; i >= 0; i -= 2) { 721 if (listeners[i] == CatalogChangeListener.class) { 722 if (cce == null) { 723 cce = new CatalogChangeEvent(this, ci, db); 724 } 725 726 ((CatalogChangeListener)listeners[i + 1]).editingCatalogItem(cce); 727 } 728 } 729 } 730 731 /** 732 * Fire the event to all listeners of this Catalog. 733 * 734 * @override Never 735 */ 736 protected void fireCommitEditCatalogItem(CatalogItem ci, DataBasket db) { 737 Object[] listeners = m_lhListeners.getListenerList(); 738 739 CatalogChangeEvent cce = null; 740 741 for (int i = listeners.length - 2; i >= 0; i -= 2) { 742 if (listeners[i] == CatalogChangeListener.class) { 743 if (cce == null) { 744 cce = new CatalogChangeEvent(this, ci, db); 745 } 746 747 ((CatalogChangeListener)listeners[i + 1]).commitEditCatalogItem(cce); 748 } 749 } 750 } 751 752 /** 753 * Fire the event to all listeners of this Catalog. 754 * 755 * @override Never 756 */ 757 protected void fireRollbackEditCatalogItem(CatalogItem ci, DataBasket db) { 758 Object[] listeners = m_lhListeners.getListenerList(); 759 760 CatalogChangeEvent cce = null; 761 762 for (int i = listeners.length - 2; i >= 0; i -= 2) { 763 if (listeners[i] == CatalogChangeListener.class) { 764 if (cce == null) { 765 cce = new CatalogChangeEvent(this, ci, db); 766 } 767 768 ((CatalogChangeListener)listeners[i + 1]).rollbackEditCatalogItem(cce); 769 } 770 } 771 } 772 773 // HelpableListener interface methods 774 /** 775 * Subscribe as a listener to the source Catalog if that is a {@link ListenableCatalog}. 776 * 777 * @override Never 778 */ 779 public void subscribe() { 780 if (m_cOrg instanceof ListenableCatalog) { 781 ((ListenableCatalog)m_cOrg).addCatalogChangeListener(this); 782 } 783 } 784 785 /** 786 * Un-Subscribe as a listener from the source Catalog if that is a {@link ListenableCatalog}. 787 * 788 * @override Never 789 */ 790 public void unsubscribe() { 791 if (m_cOrg instanceof ListenableCatalog) { 792 ((ListenableCatalog)m_cOrg).removeCatalogChangeListener(this); 793 } 794 } 795 796 /** 797 * Empty method body. 798 * 799 * @override Never 800 */ 801 public void updateModel() {} 802 }