/* 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 { private static final long serialVersionUID = 9098414040194393263L; 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(T anObject) { EOObserverCenter.removeObserver(observer, anObject); super.removeIdenticalObject(anObject); } /** * Inserts the specified object into this array at the specified index. */ public void insertObjectAtIndex(T anObject, int anIndex) { add(anIndex, anObject); } /** * Replaces the object at the specified index with the specified object. */ public void replaceObjectAtIndex(int anIndex, T anObject) { set(anIndex, anObject); } /** * Adds the specified object to the end of this array. */ public void addObject(T anObject) { add(anObject); } // interface List: mutators public void add(int index, T element) { EOObserverCenter.addObserver(observer, element); super.add(index, element); } public boolean add(T 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 T 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 T set(int index, T 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. * * */