/* Wotonomy: OpenStep design patterns for pure Java applications. Copyright (C) 2001 Michael Powers This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, see http://www.gnu.org */ package net.wotonomy.ui; import java.util.Collection; import java.util.Iterator; import java.util.List; import net.wotonomy.control.EOObserverCenter; import net.wotonomy.control.EOObserving; import net.wotonomy.foundation.NSMutableArray; import net.wotonomy.foundation.NSRange; /** * A package class that extends NSMutableArray but makes use * of the fact that wotonomy's implementation extends ArrayList * to intercept insertions and deletion and register and * unregister objects for change notifications as appropriate. * Since we can't be sure of ArrayList's implementation, we're * forced to override each and every add and remove method, * some of which probably call each other. However, * EOObserverCenter will only register us once per object. */ class ObservableArray extends NSMutableArray { EOObserving observer; ObservableArray( EOObserving anObserver ) { observer = anObserver; } /** * Removes the last object from the array. */ public void removeLastObject () { remove( count() - 1 ); } /** * Removes the object at the specified index. */ public void removeObjectAtIndex (int index) { remove( index ); } /** * Adds all objects in the specified collection. */ public void addObjectsFromArray (Collection aCollection) { addAll( aCollection ); } /** * Removes all objects from the array. */ public void removeAllObjects () { clear(); } /** * Removes all objects equivalent to the specified object * within the range of specified indices. */ public void removeObject (Object anObject, NSRange aRange) { if ( ( anObject == null ) || ( aRange == null ) ) return; int loc = aRange.location(); int max = aRange.maxRange(); for ( int i = loc; i < max; i++ ) { if ( anObject.equals( get( i ) ) ) { remove( i ); i = i - 1; max = max - 1; } } } /** * Removes all instances of the specified object within the * range of specified indices, comparing by reference. */ public void removeIdenticalObject (Object anObject, NSRange aRange) { if ( ( anObject == null ) || ( aRange == null ) ) return; int loc = aRange.location(); int max = aRange.maxRange(); for ( int i = loc; i < max; i++ ) { if ( anObject == get( i ) ) { remove( i ); i = i - 1; max = max - 1; } } } /** * Removes all objects in the specified collection from the array. */ public void removeObjectsInArray (Collection aCollection) { removeAll( aCollection ); } /** * Removes all objects in the indices within the specified range * from the array. */ public void removeObjectsInRange (NSRange aRange) { if ( aRange == null ) return; for ( int i = 0; i < aRange.length(); i++ ) { remove( aRange.location() ); } } /** * Replaces objects in the current range with objects from * the specified range of the specified array. If currentRange * is larger than otherRange, the extra objects are removed. * If otherRange is larger than currentRange, the extra objects * are added. */ public void replaceObjectsInRange (NSRange currentRange, List otherArray, NSRange otherRange) { if ( ( currentRange == null ) || ( otherArray == null ) || ( otherRange == null ) ) return; // transform otherRange if out of bounds for array if ( otherRange.maxRange() > otherArray.size() ) { // TODO: Test this logic. int loc = Math.min( otherRange.location(), otherArray.size() - 1 ); otherRange = new NSRange( loc, otherArray.size() - loc ); } Object o; List subList = subList( currentRange.location(), currentRange.maxRange() ); int otherIndex = otherRange.location(); // TODO: Test this logic. for ( int i = 0; i < subList.size(); i++ ) { if ( otherIndex < otherRange.maxRange() ) { // set object subList.set( i, otherArray.get( otherIndex ) ); } else { // remove extra elements from currentRange subList.remove( i ); i--; } otherIndex++; } // TODO: Test this logic. for ( int i = otherIndex; i < otherRange.maxRange(); i++ ) { add( otherArray.get( i ) ); } } /** * Clears the current array and then populates it with the * contents of the specified collection. */ public void setArray (Collection aCollection) { clear(); addAll( aCollection ); } /** * Removes all objects equivalent to the specified object. */ public void removeObject (Object anObject) { remove( anObject ); } /** * Removes all occurences of the specified object, * comparing by reference. */ public void removeIdenticalObject (Object anObject) { EOObserverCenter.removeObserver( observer, anObject ); super.removeIdenticalObject( anObject ); } /** * Inserts the specified object into this array at the * specified index. */ public void insertObjectAtIndex (Object anObject, int anIndex) { add( anIndex, anObject ); } /** * Replaces the object at the specified index with the * specified object. */ public void replaceObjectAtIndex (int anIndex, Object anObject) { set( anIndex, anObject ); } /** * Adds the specified object to the end of this array. */ public void addObject (Object anObject) { add( anObject ); } // interface List: mutators public void add(int index, Object element) { EOObserverCenter.addObserver( observer, element ); super.add( index, element ); } public boolean add(Object o) { EOObserverCenter.addObserver( observer, o ); return super.add(o); } public boolean addAll(Collection coll) { Iterator it = coll.iterator(); while ( it.hasNext() ) { EOObserverCenter.addObserver( observer, it.next() ); } return super.addAll(coll); } public boolean addAll(int index, Collection c) { Iterator it = c.iterator(); while ( it.hasNext() ) { EOObserverCenter.addObserver( observer, it.next() ); } return super.addAll( index, c ); } public void clear() { Iterator it = iterator(); while ( it.hasNext() ) { EOObserverCenter.removeObserver( observer, it.next() ); } super.clear(); } public Object remove(int index) { EOObserverCenter.removeObserver( observer, get(index) ); return super.remove( index ); } public boolean remove(Object o) { EOObserverCenter.removeObserver( observer, o ); return super.remove(o); } public boolean removeAll(Collection coll) { Iterator it = coll.iterator(); while ( it.hasNext() ) { EOObserverCenter.removeObserver( observer, it.next() ); } return super.removeAll(coll); } public boolean retainAll(Collection coll) { throw new UnsupportedOperationException(); } public Object set(int index, Object element) { EOObserverCenter.removeObserver( observer, get(index) ); EOObserverCenter.addObserver( observer, element ); return super.set( index, element ); } } /* * $Log$ * Revision 1.2 2006/02/18 23:14:35 cgruber * Update imports and maven dependencies. * * Revision 1.1 2006/02/16 13:22:22 cgruber * Check in all sources in eclipse-friendly maven-enabled packages. * * Revision 1.3 2003/08/06 23:07:52 chochos * general code cleanup (mostly, removing unused imports) * * Revision 1.2 2002/10/24 21:15:36 mpowers * New implementations of NSArray and subclasses. * * Revision 1.1 2001/02/20 16:38:55 mpowers * MasterDetailAssociations now observe their controlled display group's * objects for changes to that the parent object will be marked as updated. * Before, only inserts and deletes to an object's items are registered. * Also, moved ObservableArray to package access. * * Revision 1.1 2001/01/24 14:37:24 mpowers * Contributing a delegate useful for debugging. * * */