1741 lines
65 KiB
Java
1741 lines
65 KiB
Java
|
|
/*
|
||
|
|
* Copyright (c) 2005,2009 Declarative Engineering LLC.
|
||
|
|
* All rights reserved. This program and the accompanying materials
|
||
|
|
* are made available under the terms of the Declarative Engineering LLC
|
||
|
|
* verson 1 which accompanies this distribution, and is available at
|
||
|
|
* http://declarativeengineering.com/legal/DE_Developer_License_v1.txt
|
||
|
|
*/
|
||
|
|
package com.foundation.util;
|
||
|
|
|
||
|
|
import com.common.debug.Debug;
|
||
|
|
import com.common.util.*;
|
||
|
|
import com.common.util.optimized.IntArray;
|
||
|
|
import com.foundation.attribute.IReflectable;
|
||
|
|
import com.foundation.attribute.ReflectCollectionData;
|
||
|
|
import com.foundation.attribute.ReflectIndexedCollectionData;
|
||
|
|
import com.foundation.attribute.ReflectionContext;
|
||
|
|
import com.foundation.common.IEntity;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* The managed indexed collection adds the ability to manage the items in the collection.
|
||
|
|
* @see com.common.util.IndexedCollection
|
||
|
|
*/
|
||
|
|
public abstract class ManagedIndexedCollection extends ManagedCollection implements IManagedIndexedCollection {
|
||
|
|
/** A collection of IInlinedIndexedCollectionObserver instances which will be provided immediate inline change notification. */
|
||
|
|
private LiteList indexedCollectionObservers = null;
|
||
|
|
/** Whether the collection's order is managed by the application. If this is true then the orderComparator must be null. */
|
||
|
|
private boolean isExternallyOrdered = false;
|
||
|
|
/**
|
||
|
|
* ManagedIndexedCollection constructor.
|
||
|
|
* @param collectionManager The manager instance that will govern the collection changes.
|
||
|
|
* @param collectionMapping The optional mapping handler that retreives a mapped collection for a given collection value. This allows two collections to be tied together such that adds to one causes adds to the other. For example if Project has a collection of Contacts and Contacts has a collection of Projects (bidirectional references) then a mapping can be defined such that when Project is given another Contact, the Contact's projects collection is updated automatically in such a way that the mapping is not marked as new in both collections (the repository doesn't get updated twice).
|
||
|
|
* @param trackChanges Whether the collection changes should be recorded. This should default to true.
|
||
|
|
* @param protectCollectionManager Whether the collection manager should be kept private, or should be accessable. This should default to true.
|
||
|
|
*/
|
||
|
|
protected ManagedIndexedCollection(IndexedCollectionManager collectionManager, IManagedCollectionMapping collectionMapping, boolean trackChanges, boolean protectCollectionManager, boolean isReadOnly) {
|
||
|
|
super(collectionManager, collectionMapping, trackChanges, protectCollectionManager, isReadOnly);
|
||
|
|
}//ManagedIndexedCollection()//
|
||
|
|
/* (non-Javadoc)
|
||
|
|
* @see java.lang.Object#clone()
|
||
|
|
*/
|
||
|
|
protected Object clone() {
|
||
|
|
ManagedIndexedCollection clone = (ManagedIndexedCollection) super.clone();
|
||
|
|
|
||
|
|
clone.indexedCollectionObservers = null;
|
||
|
|
|
||
|
|
return clone;
|
||
|
|
}//clone()//
|
||
|
|
/* (non-Javadoc)
|
||
|
|
* @see com.common.util.IIndexedCollection#add(int, java.lang.Object)
|
||
|
|
*/
|
||
|
|
public int add(int index, Object value) {
|
||
|
|
return add(index, value, CONTEXT_UNTRUSTED);
|
||
|
|
}//add()//
|
||
|
|
/**
|
||
|
|
* Adds the given value to the indexed collection at the given index.
|
||
|
|
* @param index The index to add the item in the collection. Sorted collections will ignore this value.
|
||
|
|
* @param value A value to add to this collection.
|
||
|
|
* @param context The context for the operation.
|
||
|
|
* @return The index of the addition, or -1 if the operation failed.
|
||
|
|
* @throws IndexOutOfBoundsException When the index is not within the indexed collection's valid range.
|
||
|
|
*/
|
||
|
|
public int add(int index, Object value, byte context) {
|
||
|
|
int result = -1;
|
||
|
|
IndexedCollectionManager collectionManager = (IndexedCollectionManager) internalGetCollectionManager();
|
||
|
|
|
||
|
|
//Clear the error information prior to running the operation.//
|
||
|
|
setErrorInfo(null);
|
||
|
|
//Verify that the collection can be modified.//
|
||
|
|
verifyIsChangeable(context);
|
||
|
|
|
||
|
|
//Make sure the manager allows the add.//
|
||
|
|
if((!collectionManager.checkOnAdd()) || (collectionManager.canAdd(this, index, value, context))) {
|
||
|
|
boolean trackChanges = trackChanges(context);
|
||
|
|
|
||
|
|
//Notify the manager.//
|
||
|
|
if(collectionManager.notifyOnPreAdd()) {
|
||
|
|
collectionManager.preAdd(this, index, value, context);
|
||
|
|
}//if//
|
||
|
|
|
||
|
|
//Perform the add opertion.//
|
||
|
|
result = internalAdd(index, value, context);
|
||
|
|
|
||
|
|
//Fire an event and notify listeners if successful.//
|
||
|
|
if(result != -1) {
|
||
|
|
//Provide the manager an opportunity to act.//
|
||
|
|
if(collectionManager.notifyOnPostAdd()) {
|
||
|
|
collectionManager.postAdd(this, result, value, context);
|
||
|
|
}//if//
|
||
|
|
|
||
|
|
//Update reflections.//
|
||
|
|
if(hasReflections()) {
|
||
|
|
reflectSupportAddNotify(value, result);
|
||
|
|
}//if//
|
||
|
|
|
||
|
|
//Track changes.//
|
||
|
|
if(trackChanges) {
|
||
|
|
trackChange(value, context == CONTEXT_TRUSTED ? index : result, context, true);
|
||
|
|
}//if//
|
||
|
|
|
||
|
|
//Notify the parent object in the logical object of our changed state.//
|
||
|
|
collectionStateChanged();
|
||
|
|
//Fire an event to any event listeners.//
|
||
|
|
fireEvent(true, value, false, null);
|
||
|
|
}//if//
|
||
|
|
}//if//
|
||
|
|
|
||
|
|
return result;
|
||
|
|
}//add()//
|
||
|
|
/* (non-Javadoc)
|
||
|
|
* @see com.common.util.IIndexedCollection#addAll(int, java.lang.Object[])
|
||
|
|
*/
|
||
|
|
public boolean addAll(int index, Object[] values) {
|
||
|
|
return addAll(index, values, 0, values.length, CONTEXT_UNTRUSTED);
|
||
|
|
}//addAll()//
|
||
|
|
/* (non-Javadoc)
|
||
|
|
* @see com.common.util.IIndexedCollection#addAll(int, java.lang.Object[], int, int)
|
||
|
|
*/
|
||
|
|
public boolean addAll(int index, Object[] values, int offset, int length) {
|
||
|
|
return addAll(index, values, offset, length, CONTEXT_UNTRUSTED);
|
||
|
|
}//addAll()//
|
||
|
|
/**
|
||
|
|
* Adds the given values to the indexed collection at the given index.
|
||
|
|
* @param index The index to add the items in the collection. Sorted collections will ignore this value.
|
||
|
|
* @param values The values to add to this collection.
|
||
|
|
* @param context The context for the operation.
|
||
|
|
* @return Whether the items were all added.
|
||
|
|
* @throws IndexOutOfBoundsException When the index is not within the indexed collection's valid range.
|
||
|
|
*/
|
||
|
|
public boolean addAll(int index, Object[] values, byte context) {
|
||
|
|
return addAll(index, values, 0, values.length, context);
|
||
|
|
}//addAll()//
|
||
|
|
/**
|
||
|
|
* Adds the given values to the indexed collection at the given index.
|
||
|
|
* @param index The index to add the items in the collection. Sorted collections will ignore this value.
|
||
|
|
* @param values The values to add to this collection.
|
||
|
|
* @param offset The offset of the first value to add.
|
||
|
|
* @param length The count of values to add.
|
||
|
|
* @param context The context for the operation.
|
||
|
|
* @return Whether the items were all added.
|
||
|
|
* @throws IndexOutOfBoundsException When the index is not within the indexed collection's valid range.
|
||
|
|
*/
|
||
|
|
public boolean addAll(int index, Object[] values, int offset, int length, byte context) {
|
||
|
|
boolean result = true;
|
||
|
|
IndexedCollectionManager collectionManager = (IndexedCollectionManager) internalGetCollectionManager();
|
||
|
|
|
||
|
|
//Clear the error information prior to running the operation.//
|
||
|
|
setErrorInfo(null);
|
||
|
|
//Verify that the collection can be modified.//
|
||
|
|
verifyIsChangeable(context);
|
||
|
|
//Ensure there is enough capacity to handle the additions.//
|
||
|
|
ensureCapacity(length);
|
||
|
|
|
||
|
|
//Make sure that the collection has values.//
|
||
|
|
if((values != null) && (length > 0)) {
|
||
|
|
//Make sure the manager allows the add.//
|
||
|
|
if((!collectionManager.checkOnAdd()) || (collectionManager.canAdd(this, index, values, context))) {
|
||
|
|
LiteList addedValues = null;
|
||
|
|
boolean trackChanges = trackChanges(context);
|
||
|
|
IntArray indices = hasReflections() || trackChanges ? new IntArray(length) : null;
|
||
|
|
|
||
|
|
//Notify the collection manager.//
|
||
|
|
if(collectionManager.notifyOnPreAdd()) {
|
||
|
|
collectionManager.preAddAll(this, index, values, context);
|
||
|
|
}//if//
|
||
|
|
|
||
|
|
//Saved added values if necessary.//
|
||
|
|
if(trackChanges || hasEventListeners() || collectionManager.notifyOnPostAdd() || hasReflections()) {
|
||
|
|
addedValues = new LiteList(length);
|
||
|
|
}//if//
|
||
|
|
|
||
|
|
notifyCollectionObserversOnStart(length);
|
||
|
|
|
||
|
|
//Iterate over the items to be added and add them one at a time.//
|
||
|
|
for(int valueIndex = offset; valueIndex < length; valueIndex++) {
|
||
|
|
int nextIndex = internalAdd(index++, values[valueIndex], context);
|
||
|
|
|
||
|
|
if(nextIndex == -1) {
|
||
|
|
result = false;
|
||
|
|
index--;
|
||
|
|
}//if//
|
||
|
|
else {
|
||
|
|
if(addedValues != null) {
|
||
|
|
addedValues.add(values[valueIndex]);
|
||
|
|
}//if//
|
||
|
|
|
||
|
|
if(indices != null) {
|
||
|
|
indices.add(nextIndex);
|
||
|
|
}//if//
|
||
|
|
}//else//
|
||
|
|
}//for//
|
||
|
|
|
||
|
|
notifyCollectionObserversOnStop();
|
||
|
|
|
||
|
|
//Notify listeners and fire events if necessary.//
|
||
|
|
if((addedValues != null) && (addedValues.getSize() > 0)) {
|
||
|
|
addedValues.isChangeable(false);
|
||
|
|
|
||
|
|
//Provide the manager an opportunity to act.//
|
||
|
|
if(collectionManager.notifyOnPostAdd()) {
|
||
|
|
collectionManager.postAddAll(this, index, addedValues, context);
|
||
|
|
}//if//
|
||
|
|
|
||
|
|
//Update reflections.//
|
||
|
|
if(hasReflections()) {
|
||
|
|
reflectSupportAddNotify(addedValues, indices);
|
||
|
|
}//if//
|
||
|
|
|
||
|
|
//Track changes.//
|
||
|
|
if(trackChanges) {
|
||
|
|
trackChange(addedValues, indices, context, true);
|
||
|
|
}//if//
|
||
|
|
|
||
|
|
//Fire an event to any event listeners.//
|
||
|
|
fireEvent(true, addedValues, false, null, context);
|
||
|
|
}//if//
|
||
|
|
|
||
|
|
//Notify the parent object in the logical object of our changed state.//
|
||
|
|
collectionStateChanged();
|
||
|
|
}//if//
|
||
|
|
}//if//
|
||
|
|
|
||
|
|
return result;
|
||
|
|
}//addAll()//
|
||
|
|
/* (non-Javadoc)
|
||
|
|
* @see com.common.util.IIndexedCollection#addAll(int, com.common.util.ICollection)
|
||
|
|
*/
|
||
|
|
public boolean addAll(int index, ICollection values) {
|
||
|
|
return values instanceof IIndexedCollection ? addAll(index, (IIndexedCollection) values, 0, values.getSize(), CONTEXT_UNTRUSTED) : addAll(index, values, CONTEXT_UNTRUSTED);
|
||
|
|
}//addAll()//
|
||
|
|
/* (non-Javadoc)
|
||
|
|
* @see com.common.util.IIndexedCollection#addAll(int, com.common.util.IIndexedCollection, int, int)
|
||
|
|
*/
|
||
|
|
public boolean addAll(int index, IIndexedCollection values, int offset, int length) {
|
||
|
|
return addAll(index, values, offset, length, CONTEXT_UNTRUSTED);
|
||
|
|
}//addAll()//
|
||
|
|
/**
|
||
|
|
* Adds the given values to the indexed collection at the given index.
|
||
|
|
* @param index The index to add the items in the collection. Sorted collections will ignore this value.
|
||
|
|
* @param values The values to add to this collection.
|
||
|
|
* @param context The context for the operation.
|
||
|
|
* @return Whether the items were all added.
|
||
|
|
* @throws IndexOutOfBoundsException When the index is not within the indexed collection's valid range.
|
||
|
|
*/
|
||
|
|
public boolean addAll(int index, ICollection values, byte context) {
|
||
|
|
boolean result = true;
|
||
|
|
|
||
|
|
if(values instanceof IIndexedCollection) {
|
||
|
|
result = addAll(index, (IIndexedCollection) values, 0, values.getSize());
|
||
|
|
}//if//
|
||
|
|
else {
|
||
|
|
IndexedCollectionManager collectionManager = (IndexedCollectionManager) internalGetCollectionManager();
|
||
|
|
|
||
|
|
//Clear the error information prior to running the operation.//
|
||
|
|
setErrorInfo(null);
|
||
|
|
//Verify that the collection can be modified.//
|
||
|
|
verifyIsChangeable(context);
|
||
|
|
//Ensure there is enough capacity to handle the additions.//
|
||
|
|
ensureCapacity(values.getSize());
|
||
|
|
|
||
|
|
//Make sure that the collection has values.//
|
||
|
|
if((values != null) && (values.getSize() > 0)) {
|
||
|
|
//Make sure the manager allows the add.//
|
||
|
|
if((!collectionManager.checkOnAdd()) || (collectionManager.canAdd(this, index, values, context))) {
|
||
|
|
LiteList addedValues = null;
|
||
|
|
Object next = null;
|
||
|
|
boolean trackChanges = trackChanges(context);
|
||
|
|
IntArray indices = hasReflections() || trackChanges ? new IntArray(values.getSize()) : null;
|
||
|
|
|
||
|
|
//Notify the collection manager.//
|
||
|
|
if(collectionManager.notifyOnPreAdd()) {
|
||
|
|
collectionManager.preAddAll(this, index, values, context);
|
||
|
|
}//if//
|
||
|
|
|
||
|
|
//Saved added values if necessary.//
|
||
|
|
if(trackChanges || hasEventListeners() || collectionManager.notifyOnPostAdd() || hasReflections()) {
|
||
|
|
addedValues = new LiteList(values.getSize());
|
||
|
|
}//if//
|
||
|
|
|
||
|
|
notifyCollectionObserversOnStart(values.getSize());
|
||
|
|
|
||
|
|
//Iterate over the items to be added and add them one at a time.//
|
||
|
|
for(IIterator iterator = values.iterator(); iterator.hasNext(); ) {
|
||
|
|
int nextIndex;
|
||
|
|
|
||
|
|
next = iterator.next();
|
||
|
|
nextIndex = internalAdd(index++, next, context);
|
||
|
|
|
||
|
|
if(nextIndex == -1) {
|
||
|
|
result = false;
|
||
|
|
index--;
|
||
|
|
}//if//
|
||
|
|
else {
|
||
|
|
if(addedValues != null) {
|
||
|
|
addedValues.add(next);
|
||
|
|
}//if//
|
||
|
|
|
||
|
|
if(indices != null) {
|
||
|
|
indices.add(nextIndex);
|
||
|
|
}//if//
|
||
|
|
}//else//
|
||
|
|
}//for//
|
||
|
|
|
||
|
|
notifyCollectionObserversOnStop();
|
||
|
|
|
||
|
|
//Notify listeners and fire events if necessary.//
|
||
|
|
if((addedValues != null) && (addedValues.getSize() > 0)) {
|
||
|
|
addedValues.isChangeable(false);
|
||
|
|
|
||
|
|
//Provide the manager an opportunity to act.//
|
||
|
|
if(collectionManager.notifyOnPostAdd()) {
|
||
|
|
collectionManager.postAddAll(this, index, addedValues, context);
|
||
|
|
}//if//
|
||
|
|
|
||
|
|
//Update reflections.//
|
||
|
|
if(hasReflections()) {
|
||
|
|
reflectSupportAddNotify(addedValues, indices);
|
||
|
|
}//if//
|
||
|
|
|
||
|
|
//Track changes.//
|
||
|
|
if(trackChanges) {
|
||
|
|
trackChange(addedValues, indices, context, true);
|
||
|
|
}//if//
|
||
|
|
|
||
|
|
//Fire an event to any event listeners.//
|
||
|
|
fireEvent(true, addedValues, false, null, context);
|
||
|
|
}//if//
|
||
|
|
|
||
|
|
//Notify the parent object in the logical object of our changed state.//
|
||
|
|
collectionStateChanged();
|
||
|
|
}//if//
|
||
|
|
}//if//
|
||
|
|
}//else//
|
||
|
|
|
||
|
|
return result;
|
||
|
|
}//addAll()//
|
||
|
|
/**
|
||
|
|
* Adds the given values to the indexed collection at the given index.
|
||
|
|
* @param index The index to add the items in the collection. Sorted collections will ignore this value.
|
||
|
|
* @param values The values to add to this collection.
|
||
|
|
* @param offset The offset of the first value to add.
|
||
|
|
* @param length The count of values to add.
|
||
|
|
* @param context The context for the operation.
|
||
|
|
* @return Whether the items were all added.
|
||
|
|
* @throws IndexOutOfBoundsException When the index is not within the indexed collection's valid range.
|
||
|
|
*/
|
||
|
|
public boolean addAll(int index, IIndexedCollection values, int offset, int length, byte context) {
|
||
|
|
boolean result = true;
|
||
|
|
IndexedCollectionManager collectionManager = (IndexedCollectionManager) internalGetCollectionManager();
|
||
|
|
|
||
|
|
//Clear the error information prior to running the operation.//
|
||
|
|
setErrorInfo(null);
|
||
|
|
//Verify that the collection can be modified.//
|
||
|
|
verifyIsChangeable(context);
|
||
|
|
//Ensure there is enough capacity to handle the additions.//
|
||
|
|
ensureCapacity(length);
|
||
|
|
|
||
|
|
//Make sure that the collection has values.//
|
||
|
|
if((values != null) && (length > 0)) {
|
||
|
|
//Make sure the manager allows the add.//
|
||
|
|
if((!collectionManager.checkOnAdd()) || (collectionManager.canAdd(this, index, values, context))) {
|
||
|
|
LiteList addedValues = null;
|
||
|
|
Object next = null;
|
||
|
|
boolean trackChanges = trackChanges(context);
|
||
|
|
IntArray indices = hasReflections() || trackChanges ? new IntArray(length) : null;
|
||
|
|
|
||
|
|
//Notify the collection manager.//
|
||
|
|
if(collectionManager.notifyOnPreAdd()) {
|
||
|
|
collectionManager.preAddAll(this, index, values, context);
|
||
|
|
}//if//
|
||
|
|
|
||
|
|
//Saved added values if necessary.//
|
||
|
|
if(trackChanges || hasEventListeners() || collectionManager.notifyOnPostAdd() || hasReflections()) {
|
||
|
|
addedValues = new LiteList(length);
|
||
|
|
}//if//
|
||
|
|
|
||
|
|
notifyCollectionObserversOnStart(length);
|
||
|
|
|
||
|
|
//Iterate over the items to be added and add them one at a time.//
|
||
|
|
for(int valuesIndex = offset, count = offset + length; valuesIndex < count; valuesIndex++) {
|
||
|
|
int nextIndex;
|
||
|
|
|
||
|
|
next = values.get(valuesIndex);
|
||
|
|
nextIndex = internalAdd(index++, next, context);
|
||
|
|
|
||
|
|
if(nextIndex == -1) {
|
||
|
|
result = false;
|
||
|
|
index--;
|
||
|
|
}//if//
|
||
|
|
else {
|
||
|
|
if(addedValues != null) {
|
||
|
|
addedValues.add(next);
|
||
|
|
}//if//
|
||
|
|
|
||
|
|
if(indices != null) {
|
||
|
|
indices.add(nextIndex);
|
||
|
|
}//if//
|
||
|
|
}//else//
|
||
|
|
}//for//
|
||
|
|
|
||
|
|
notifyCollectionObserversOnStop();
|
||
|
|
|
||
|
|
//Notify listeners and fire events if necessary.//
|
||
|
|
if((addedValues != null) && (addedValues.getSize() > 0)) {
|
||
|
|
addedValues.isChangeable(false);
|
||
|
|
|
||
|
|
//Provide the manager an opportunity to act.//
|
||
|
|
if(collectionManager.notifyOnPostAdd()) {
|
||
|
|
collectionManager.postAddAll(this, index, addedValues, context);
|
||
|
|
}//if//
|
||
|
|
|
||
|
|
//Update reflections.//
|
||
|
|
if(hasReflections()) {
|
||
|
|
reflectSupportAddNotify(addedValues, indices);
|
||
|
|
}//if//
|
||
|
|
|
||
|
|
//Track changes.//
|
||
|
|
if(trackChanges) {
|
||
|
|
trackChange(addedValues, indices, context, true);
|
||
|
|
}//if//
|
||
|
|
|
||
|
|
//Fire an event to any event listeners.//
|
||
|
|
fireEvent(true, addedValues, false, null, context);
|
||
|
|
}//if//
|
||
|
|
|
||
|
|
//Notify the parent object in the logical object of our changed state.//
|
||
|
|
collectionStateChanged();
|
||
|
|
}//if//
|
||
|
|
}//if//
|
||
|
|
|
||
|
|
return result;
|
||
|
|
}//addAll()//
|
||
|
|
/**
|
||
|
|
* Notifies the collection that a change has occured with a given context and determines whether the caller has to report each change.
|
||
|
|
* @param context The context for the changes.
|
||
|
|
* @return Whether the changes must be reported.
|
||
|
|
*/
|
||
|
|
protected abstract boolean trackChanges(byte context);
|
||
|
|
/**
|
||
|
|
* Tracks a single change to the collection.
|
||
|
|
* @param value The value added or removed. This may be null if a remove and an index is provided.
|
||
|
|
* @param index The index of the value added or removed. The index must be the original index (the index it was intended to be inserted at) if the context is TRUSTED, otherwise it must be the actual index it was inserted at locally.
|
||
|
|
* @param context The context for the change.
|
||
|
|
* @param isAdd Whether the change is an add (versus a remove).
|
||
|
|
*/
|
||
|
|
protected abstract void trackChange(Object value, int index, byte context, boolean isAdd);
|
||
|
|
/**
|
||
|
|
* Tracks a single change to the collection.
|
||
|
|
* @param values The value added or removed. This may be null if a remove and indices are provided.
|
||
|
|
* @param indices The index of the values added or removed. This must be null if all values are removed. The index must be the original index (the index it was intended to be inserted at) if the context is TRUSTED, otherwise it must be the actual index it was inserted at locally.
|
||
|
|
* @param context The context for the change.
|
||
|
|
* @param isAdd Whether the change is an add (versus a remove).
|
||
|
|
*/
|
||
|
|
protected abstract void trackChange(IList values, IntArray indices, byte context, boolean isAdd);
|
||
|
|
/* (non-Javadoc)
|
||
|
|
* @see com.foundation.util.ManagedCollection#containsValue(java.lang.Object)
|
||
|
|
*/
|
||
|
|
public boolean containsValue(Object value) {
|
||
|
|
return getIndexOf(value) != VALUE_NOT_FOUND;
|
||
|
|
}//containsValue()//
|
||
|
|
/* (non-Javadoc)
|
||
|
|
* @see com.common.util.IIndexedCollection#get(int)
|
||
|
|
*/
|
||
|
|
public abstract Object get(int index);
|
||
|
|
/* (non-Javadoc)
|
||
|
|
* @see com.common.util.ICollection#getFirst()
|
||
|
|
*/
|
||
|
|
public Object getFirst() {
|
||
|
|
return get(0);
|
||
|
|
}//getFirst()//
|
||
|
|
/* (non-Javadoc)
|
||
|
|
* @see com.common.util.IIndexedCollection#getIndexOf(java.lang.Object)
|
||
|
|
*/
|
||
|
|
public abstract int getIndexOf(Object value);
|
||
|
|
/* (non-Javadoc)
|
||
|
|
* @see com.common.util.IIndexedCollection#getLast()
|
||
|
|
*/
|
||
|
|
public Object getLast() {
|
||
|
|
return get(getSize() - 1);
|
||
|
|
}//getLast()//
|
||
|
|
/**
|
||
|
|
* Fires a sort event for the indexed collection.
|
||
|
|
* @param mapping A mapping of new positions to old positions. The index is the new position and the value is the old position.
|
||
|
|
*/
|
||
|
|
protected void fireSortEvent(int[] mapping) {
|
||
|
|
if(getEventSupport().hasListeners(SORT_EVENT.getNumber())) {
|
||
|
|
getEventSupport().fireEvent(SORT_EVENT.getNumber(), mapping);
|
||
|
|
}//if//
|
||
|
|
}//fireSortEvent()//
|
||
|
|
/* (non-Javadoc)
|
||
|
|
* @see com.foundation.util.ManagedCollection#getSize()
|
||
|
|
*/
|
||
|
|
public abstract int getSize();
|
||
|
|
/**
|
||
|
|
* Will retrieve the collection specific iterator for this object.
|
||
|
|
* The iterator may be used to iterate over the items in the collection starting with the first item and ending with the last item.
|
||
|
|
* <p><bold>NOTE: The iterator is only guaranteed to iterate over all of the items in the collection if the collection does not change except through the iterator.</bold>
|
||
|
|
* @return An indexed iterator object starting at the beginning of the collection.
|
||
|
|
*/
|
||
|
|
public IReversableIterator indexedIterator() {
|
||
|
|
return new IndexedIterator(this);
|
||
|
|
}//indexedIterator()//
|
||
|
|
/**
|
||
|
|
* Adds a value at a given index.
|
||
|
|
* @param index Where to add the new value.
|
||
|
|
* @param value The value to add to the collection.
|
||
|
|
* @param context The context under which the object is being added.
|
||
|
|
* @return The success of the operation.
|
||
|
|
*/
|
||
|
|
protected abstract int internalAdd(int index, Object object, byte context);
|
||
|
|
/**
|
||
|
|
* Removes a value specified by the given index.
|
||
|
|
* @param index Which value to remove.
|
||
|
|
* @param context The context under which the object is being removed.
|
||
|
|
* @return The value removed from the collection.
|
||
|
|
*/
|
||
|
|
protected abstract Object internalRemove(int index, byte context);
|
||
|
|
/**
|
||
|
|
* Removes a value from the collection.
|
||
|
|
* @param value The value to remove.
|
||
|
|
* @param context The context under which the object is being removed.
|
||
|
|
* @return The index of the value removed, 0 if the collection is not indexed, or -1 of no value was removed.
|
||
|
|
*/
|
||
|
|
protected abstract int internalRemove(Object value, byte context);
|
||
|
|
/**
|
||
|
|
* Replaces a value specified by the given index with another value.
|
||
|
|
* @param index Which value to replace.
|
||
|
|
* @param newValue The value to replace the old value with.
|
||
|
|
* @param context The context under which the object is being replaced.
|
||
|
|
* @return The value that was replaced.
|
||
|
|
*/
|
||
|
|
protected abstract Object internalReplace(int index, Object newValue, byte context);
|
||
|
|
/**
|
||
|
|
* Sets a given value at a given index, replacing what was previously at that index, or expanding the list if necessary.
|
||
|
|
* @param index The index where the value will be stored.
|
||
|
|
* @param value The value to place in the collection.
|
||
|
|
* @param context The context under which the object is being set.
|
||
|
|
* @return The value that was replaced, or null if no value was replaced.
|
||
|
|
*/
|
||
|
|
protected abstract Object internalSet(int index, Object value, byte context);
|
||
|
|
/* (non-Javadoc)
|
||
|
|
* @see com.foundation.util.ManagedCollection#iterator()
|
||
|
|
*/
|
||
|
|
public abstract IIterator iterator();
|
||
|
|
/* (non-Javadoc)
|
||
|
|
* @see com.foundation.util.ManagedCollection#add(java.lang.Object, byte)
|
||
|
|
*/
|
||
|
|
public int add(Object value, byte context) {
|
||
|
|
int result = -1;
|
||
|
|
IndexedCollectionManager collectionManager = (IndexedCollectionManager) internalGetCollectionManager();
|
||
|
|
|
||
|
|
//Clear the error information prior to running the operation.//
|
||
|
|
setErrorInfo(null);
|
||
|
|
//Verify that the collection can be modified.//
|
||
|
|
verifyIsChangeable(context);
|
||
|
|
|
||
|
|
if((!collectionManager.checkOnAdd()) || (collectionManager.canAdd(this, value, context))) {
|
||
|
|
boolean trackChanges = trackChanges(context);
|
||
|
|
int index = getSize();
|
||
|
|
|
||
|
|
if(collectionManager.notifyOnPreAdd()) {
|
||
|
|
collectionManager.preAdd(this, value, context);
|
||
|
|
}//if//
|
||
|
|
|
||
|
|
//Perform the add operation.//
|
||
|
|
result = internalAdd(value, context);
|
||
|
|
|
||
|
|
//Fire an event and notify listeners if successful.//
|
||
|
|
if(result != -1) {
|
||
|
|
//Provide the manager an opportunity to act.//
|
||
|
|
if(collectionManager.notifyOnPostAdd()) {
|
||
|
|
collectionManager.postAdd(this, value, context);
|
||
|
|
}//if//
|
||
|
|
|
||
|
|
//Update reflections.//
|
||
|
|
if(hasReflections()) {
|
||
|
|
reflectSupportAddNotify(value, result);
|
||
|
|
}//if//
|
||
|
|
|
||
|
|
//Track changes.//
|
||
|
|
if(trackChanges) {
|
||
|
|
trackChange(value, context == CONTEXT_TRUSTED ? index : result, context, true);
|
||
|
|
}//if//
|
||
|
|
|
||
|
|
//Notify the parent object in the logical object of our changed state.//
|
||
|
|
collectionStateChanged();
|
||
|
|
//Fire an event to any event listeners.//
|
||
|
|
fireEvent(true, value, false, null);
|
||
|
|
}//if//
|
||
|
|
}//if//
|
||
|
|
|
||
|
|
return result;
|
||
|
|
}//add()//
|
||
|
|
/* (non-Javadoc)
|
||
|
|
* @see com.foundation.util.ManagedCollection#addAll(com.common.util.ICollection, byte)
|
||
|
|
*/
|
||
|
|
public boolean addAll(ICollection values, byte context) {
|
||
|
|
boolean result = true;
|
||
|
|
IndexedCollectionManager collectionManager = (IndexedCollectionManager) internalGetCollectionManager();
|
||
|
|
|
||
|
|
//Clear the error information prior to running the operation.//
|
||
|
|
setErrorInfo(null);
|
||
|
|
//Verify that the collection can be modified.//
|
||
|
|
verifyIsChangeable(context);
|
||
|
|
//Ensure there is enough capacity to handle the additions.//
|
||
|
|
ensureCapacity(values.getSize());
|
||
|
|
|
||
|
|
//Make sure that the collection has values.//
|
||
|
|
if((values != null) && (values.getSize() > 0)) {
|
||
|
|
//Verify that we can add the items.//
|
||
|
|
if((!collectionManager.checkOnAdd()) || (collectionManager.canAddAll(this, values, context))) {
|
||
|
|
LiteList addedValues = null;
|
||
|
|
Object next = null;
|
||
|
|
boolean trackChanges = trackChanges(context);
|
||
|
|
IntArray indices = hasReflections() || trackChanges ? new IntArray(values.getSize()) : null;
|
||
|
|
|
||
|
|
//Notify the manager before adding.//
|
||
|
|
if(collectionManager.notifyOnPreAdd()) {
|
||
|
|
collectionManager.preAddAll(this, values, context);
|
||
|
|
}//if//
|
||
|
|
|
||
|
|
//Save the added values if necessary.//
|
||
|
|
if(trackChanges || hasEventListeners() || collectionManager.notifyOnPostAdd() || hasReflections()) {
|
||
|
|
addedValues = new LiteList(values.getSize());
|
||
|
|
}//if//
|
||
|
|
|
||
|
|
notifyCollectionObserversOnStart(values.getSize());
|
||
|
|
|
||
|
|
//Iterate over the items to be added and add them one at a time.//
|
||
|
|
for(IIterator iterator = values.iterator(); iterator.hasNext(); ) {
|
||
|
|
int nextIndex;
|
||
|
|
|
||
|
|
next = iterator.next();
|
||
|
|
nextIndex = internalAdd(next, context);
|
||
|
|
|
||
|
|
if(nextIndex == -1) {
|
||
|
|
result = false;
|
||
|
|
}//if//
|
||
|
|
else {
|
||
|
|
if(addedValues != null) {
|
||
|
|
addedValues.add(next);
|
||
|
|
}//if//
|
||
|
|
|
||
|
|
if(indices != null) {
|
||
|
|
indices.add(nextIndex);
|
||
|
|
}//if//
|
||
|
|
}//else//
|
||
|
|
}//for//
|
||
|
|
|
||
|
|
notifyCollectionObserversOnStop();
|
||
|
|
|
||
|
|
//Notify listeners and fire events if necessary.//
|
||
|
|
if((addedValues != null) && (addedValues.getSize() > 0)) {
|
||
|
|
addedValues.isChangeable(false);
|
||
|
|
|
||
|
|
//Provide the manager an opportunity to act.//
|
||
|
|
if(collectionManager.notifyOnPostAdd()) {
|
||
|
|
collectionManager.postAddAll(this, addedValues, context);
|
||
|
|
}//if//
|
||
|
|
|
||
|
|
//Update reflections.//
|
||
|
|
if(hasReflections()) {
|
||
|
|
reflectSupportAddNotify(addedValues, indices);
|
||
|
|
}//if//
|
||
|
|
|
||
|
|
//Track changes.//
|
||
|
|
if(trackChanges) {
|
||
|
|
trackChange(addedValues, indices, context, true);
|
||
|
|
}//if//
|
||
|
|
|
||
|
|
//Fire an event to any event listeners.//
|
||
|
|
fireEvent(true, addedValues, false, null, context);
|
||
|
|
}//if//
|
||
|
|
|
||
|
|
//Notify the parent object in the logical object of our changed state.//
|
||
|
|
collectionStateChanged();
|
||
|
|
}//if//
|
||
|
|
}//if//
|
||
|
|
|
||
|
|
return result;
|
||
|
|
}//addAll()//
|
||
|
|
/* (non-Javadoc)
|
||
|
|
* @see com.foundation.util.ManagedCollection#addAll(com.common.util.IIndexedCollection, int, int, byte)
|
||
|
|
*/
|
||
|
|
public boolean addAll(IIndexedCollection values, int offset, int length, byte context) {
|
||
|
|
boolean result = true;
|
||
|
|
IndexedCollectionManager collectionManager = (IndexedCollectionManager) internalGetCollectionManager();
|
||
|
|
|
||
|
|
//Clear the error information prior to running the operation.//
|
||
|
|
setErrorInfo(null);
|
||
|
|
//Verify that the collection can be modified.//
|
||
|
|
verifyIsChangeable(context);
|
||
|
|
//Ensure there is enough capacity to handle the additions.//
|
||
|
|
ensureCapacity(length);
|
||
|
|
|
||
|
|
//Make sure that the collection has values.//
|
||
|
|
if((values != null) && (length > 0)) {
|
||
|
|
//Verify that we can add the items.//
|
||
|
|
if((!collectionManager.checkOnAdd()) || (collectionManager.canAddAll(this, values, context))) {
|
||
|
|
LiteList addedValues = null;
|
||
|
|
Object next = null;
|
||
|
|
boolean trackChanges = trackChanges(context);
|
||
|
|
IntArray indices = hasReflections() || trackChanges ? new IntArray(length) : null;
|
||
|
|
|
||
|
|
//Notify the manager before adding.//
|
||
|
|
if(collectionManager.notifyOnPreAdd()) {
|
||
|
|
collectionManager.preAddAll(this, values, context);
|
||
|
|
}//if//
|
||
|
|
|
||
|
|
//Save the added values if necessary.//
|
||
|
|
if(trackChanges || hasEventListeners() || collectionManager.notifyOnPostAdd() || hasReflections()) {
|
||
|
|
addedValues = new LiteList(length);
|
||
|
|
}//if//
|
||
|
|
|
||
|
|
notifyCollectionObserversOnStart(length);
|
||
|
|
|
||
|
|
//Iterate over the items to be added and add them one at a time.//
|
||
|
|
for(int valuesIndex = offset, count = offset + length; valuesIndex < count; valuesIndex++) {
|
||
|
|
int nextIndex;
|
||
|
|
|
||
|
|
next = values.get(valuesIndex);
|
||
|
|
nextIndex = internalAdd(next, context);
|
||
|
|
|
||
|
|
if(nextIndex == -1) {
|
||
|
|
result = false;
|
||
|
|
}//if//
|
||
|
|
else {
|
||
|
|
if(addedValues != null) {
|
||
|
|
addedValues.add(next);
|
||
|
|
}//if//
|
||
|
|
|
||
|
|
if(indices != null) {
|
||
|
|
indices.add(nextIndex);
|
||
|
|
}//if//
|
||
|
|
}//else//
|
||
|
|
}//for//
|
||
|
|
|
||
|
|
notifyCollectionObserversOnStop();
|
||
|
|
|
||
|
|
//Notify listeners and fire events if necessary.//
|
||
|
|
if((addedValues != null) && (addedValues.getSize() > 0)) {
|
||
|
|
addedValues.isChangeable(false);
|
||
|
|
|
||
|
|
//Provide the manager an opportunity to act.//
|
||
|
|
if(collectionManager.notifyOnPostAdd()) {
|
||
|
|
collectionManager.postAddAll(this, addedValues, context);
|
||
|
|
}//if//
|
||
|
|
|
||
|
|
//Update reflections.//
|
||
|
|
if(hasReflections()) {
|
||
|
|
reflectSupportAddNotify(addedValues, indices);
|
||
|
|
}//if//
|
||
|
|
|
||
|
|
//Track changes.//
|
||
|
|
if(trackChanges) {
|
||
|
|
trackChange(addedValues, indices, context, true);
|
||
|
|
}//if//
|
||
|
|
|
||
|
|
//Fire an event to any event listeners.//
|
||
|
|
fireEvent(true, addedValues, false, null, context);
|
||
|
|
}//if//
|
||
|
|
|
||
|
|
//Notify the parent object in the logical object of our changed state.//
|
||
|
|
collectionStateChanged();
|
||
|
|
}//if//
|
||
|
|
}//if//
|
||
|
|
|
||
|
|
return result;
|
||
|
|
}//addAll()//
|
||
|
|
/* (non-Javadoc)
|
||
|
|
* @see com.foundation.util.ManagedCollection#addAll(java.lang.Object[], int, int, byte)
|
||
|
|
*/
|
||
|
|
public boolean addAll(Object[] values, int offset, int length, byte context) {
|
||
|
|
boolean result = true;
|
||
|
|
IndexedCollectionManager collectionManager = (IndexedCollectionManager) internalGetCollectionManager();
|
||
|
|
|
||
|
|
//Clear the error information prior to running the operation.//
|
||
|
|
setErrorInfo(null);
|
||
|
|
//Verify that the collection can be modified.//
|
||
|
|
verifyIsChangeable(context);
|
||
|
|
//Ensure there is enough capacity to handle the additions.//
|
||
|
|
ensureCapacity(length);
|
||
|
|
|
||
|
|
//Make sure that the collection has values.//
|
||
|
|
if((values != null) && (length > 0) && offset >= 0 && offset + length <= values.length) {
|
||
|
|
//Verify that we can add the items.//
|
||
|
|
if((!collectionManager.checkOnAdd()) || (collectionManager.canAddAll(this, values, offset, length, context))) {
|
||
|
|
LiteList addedValues = null;
|
||
|
|
boolean trackChanges = trackChanges(context);
|
||
|
|
IntArray indices = hasReflections() || trackChanges ? new IntArray(length) : null;
|
||
|
|
|
||
|
|
//Notify the manager before adding.//
|
||
|
|
if(collectionManager.notifyOnPreAdd()) {
|
||
|
|
collectionManager.preAddAll(this, values, offset, length, context);
|
||
|
|
}//if//
|
||
|
|
|
||
|
|
//Save the added items if necessary.//
|
||
|
|
if(trackChanges || hasEventListeners() || collectionManager.notifyOnPostAdd() || hasReflections()) {
|
||
|
|
addedValues = new LiteList(length);
|
||
|
|
}//if//
|
||
|
|
|
||
|
|
notifyCollectionObserversOnStart(length);
|
||
|
|
|
||
|
|
//Iterate over the items to be added and add them one at a time.//
|
||
|
|
for(int index = offset; index < length; index++) {
|
||
|
|
int nextIndex = internalAdd(values[index], context);
|
||
|
|
|
||
|
|
if(nextIndex == -1) {
|
||
|
|
result = false;
|
||
|
|
}//if//
|
||
|
|
else {
|
||
|
|
if(addedValues != null) {
|
||
|
|
addedValues.add(values[index]);
|
||
|
|
}//if//
|
||
|
|
|
||
|
|
if(indices != null) {
|
||
|
|
indices.add(nextIndex);
|
||
|
|
}//if//
|
||
|
|
}//else//
|
||
|
|
}//for//
|
||
|
|
|
||
|
|
notifyCollectionObserversOnStop();
|
||
|
|
|
||
|
|
//Notify listeners and fire events if necessary.//
|
||
|
|
if((addedValues != null) && (addedValues.getSize() > 0)) {
|
||
|
|
addedValues.isChangeable(false);
|
||
|
|
|
||
|
|
//Provide the manager an opportunity to act.//
|
||
|
|
if(collectionManager.notifyOnPostAdd()) {
|
||
|
|
collectionManager.postAddAll(this, addedValues, context);
|
||
|
|
}//if//
|
||
|
|
|
||
|
|
//Update reflections.//
|
||
|
|
if(hasReflections()) {
|
||
|
|
reflectSupportAddNotify(addedValues, indices);
|
||
|
|
}//if//
|
||
|
|
|
||
|
|
//Track changes.//
|
||
|
|
if(trackChanges) {
|
||
|
|
trackChange(addedValues, indices, context, true);
|
||
|
|
}//if//
|
||
|
|
|
||
|
|
//Fire an event to any event listeners.//
|
||
|
|
fireEvent(true, addedValues, false, null, context);
|
||
|
|
}//if//
|
||
|
|
|
||
|
|
//Notify the parent object in the logical object of our changed state.//
|
||
|
|
collectionStateChanged();
|
||
|
|
}//if//
|
||
|
|
}//if//
|
||
|
|
else {
|
||
|
|
result = false;
|
||
|
|
}//else//
|
||
|
|
|
||
|
|
return result;
|
||
|
|
}//addAll()//
|
||
|
|
/* (non-Javadoc)
|
||
|
|
* @see com.foundation.util.ManagedCollection#internalReplace(java.lang.Object, java.lang.Object, byte)
|
||
|
|
*/
|
||
|
|
protected final boolean internalReplace(Object oldValue, Object newValue, byte context) {
|
||
|
|
//Never called.//
|
||
|
|
return false;
|
||
|
|
}//internalReplace()//
|
||
|
|
/* (non-Javadoc)
|
||
|
|
* @see com.foundation.util.ManagedCollection#replace(java.lang.Object, java.lang.Object, byte)
|
||
|
|
*/
|
||
|
|
public boolean replace(Object oldValue, Object newValue, byte context) {
|
||
|
|
int index = getIndexOf(oldValue);
|
||
|
|
|
||
|
|
if(index >= 0) {
|
||
|
|
replace(getIndexOf(oldValue), newValue, context);
|
||
|
|
}//if//
|
||
|
|
|
||
|
|
return index >= 0;
|
||
|
|
}//replace()//
|
||
|
|
/* (non-Javadoc)
|
||
|
|
* @see com.foundation.util.ManagedCollection#remove(java.lang.Object, byte)
|
||
|
|
*/
|
||
|
|
public boolean remove(Object value, byte context) {
|
||
|
|
int result = -1;
|
||
|
|
IndexedCollectionManager collectionManager = (IndexedCollectionManager) internalGetCollectionManager();
|
||
|
|
|
||
|
|
//Clear the error information prior to running the operation.//
|
||
|
|
setErrorInfo(null);
|
||
|
|
//Verify that the collection can be modified.//
|
||
|
|
verifyIsChangeable(context);
|
||
|
|
|
||
|
|
if((!collectionManager.checkOnRemove()) || (collectionManager.canRemove(this, value, context))) {
|
||
|
|
boolean trackChanges = trackChanges(context);
|
||
|
|
|
||
|
|
if(collectionManager.notifyOnPreRemove()) {
|
||
|
|
collectionManager.preRemove(this, value, context);
|
||
|
|
}//if//
|
||
|
|
|
||
|
|
//Performs the remove operation.//
|
||
|
|
result = internalRemove(value, context);
|
||
|
|
|
||
|
|
if(result != -1) {
|
||
|
|
//Provide the manager an opportunity to act.//
|
||
|
|
if(collectionManager.notifyOnPostRemove()) {
|
||
|
|
collectionManager.postRemove(this, value, context);
|
||
|
|
}//if//
|
||
|
|
|
||
|
|
//Update reflections.//
|
||
|
|
if(hasReflections()) {
|
||
|
|
reflectSupportRemoveNotify(result);
|
||
|
|
}//if//
|
||
|
|
|
||
|
|
//Track changes.//
|
||
|
|
if(trackChanges) {
|
||
|
|
trackChange(value, result, context, false);
|
||
|
|
}//if//
|
||
|
|
|
||
|
|
//Notify the parent object in the logical object of our changed state.//
|
||
|
|
collectionStateChanged();
|
||
|
|
//Fire an event to any event listeners.//
|
||
|
|
fireEvent(false, null, true, value);
|
||
|
|
}//if//
|
||
|
|
}//if//
|
||
|
|
|
||
|
|
return result != -1;
|
||
|
|
}//remove()//
|
||
|
|
/* (non-Javadoc)
|
||
|
|
* @see com.foundation.util.ManagedCollection#removeAll(byte)
|
||
|
|
*/
|
||
|
|
public void removeAll(byte context) {
|
||
|
|
if(getSize() > 0) {
|
||
|
|
IndexedCollectionManager collectionManager = (IndexedCollectionManager) internalGetCollectionManager();
|
||
|
|
|
||
|
|
//Clear the error information prior to running the operation.//
|
||
|
|
setErrorInfo(null);
|
||
|
|
//Verify that the collection can be modified.//
|
||
|
|
verifyIsChangeable(context);
|
||
|
|
|
||
|
|
//Check with the manager before allowing the remove.//
|
||
|
|
if((!collectionManager.checkOnRemove()) || (collectionManager.canRemoveAll(this, context))) {
|
||
|
|
IList removedValues = null;
|
||
|
|
boolean trackChanges = trackChanges(context);
|
||
|
|
|
||
|
|
if(hasEventListeners() || collectionManager.notifyOnPostRemove() || hasReflections()) {
|
||
|
|
removedValues = new LiteList(this);
|
||
|
|
removedValues.isChangeable(false);
|
||
|
|
}//if//
|
||
|
|
|
||
|
|
//Notify the manager before removing.//
|
||
|
|
if(collectionManager.notifyOnPreRemove()) {
|
||
|
|
collectionManager.preRemoveAll(this, context);
|
||
|
|
}//if//
|
||
|
|
|
||
|
|
internalRemoveAll(context);
|
||
|
|
|
||
|
|
//Notify listeners and fire events if necessary.//
|
||
|
|
if((removedValues != null) && (removedValues.getSize() > 0)) {
|
||
|
|
removedValues.isChangeable(false);
|
||
|
|
|
||
|
|
//Provide the manager an opportunity to act.//
|
||
|
|
if(collectionManager.notifyOnPostRemove()) {
|
||
|
|
collectionManager.postRemoveAll(this, removedValues, context);
|
||
|
|
}//if//
|
||
|
|
|
||
|
|
//Update reflections.//
|
||
|
|
if(hasReflections()) {
|
||
|
|
reflectSupportRemoveAllNotify();
|
||
|
|
}//if//
|
||
|
|
|
||
|
|
//Track changes.//
|
||
|
|
if(trackChanges) {
|
||
|
|
trackChange(null, null, context, false);
|
||
|
|
}//if//
|
||
|
|
|
||
|
|
//Fire an event to any event listeners.//
|
||
|
|
fireEvent(false, null, true, removedValues, context);
|
||
|
|
}//if//
|
||
|
|
|
||
|
|
//Notify the parent object in the logical object of our changed state.//
|
||
|
|
collectionStateChanged();
|
||
|
|
}//if//
|
||
|
|
}//if//
|
||
|
|
}//removeAll()//
|
||
|
|
/* (non-Javadoc)
|
||
|
|
* @see com.foundation.util.ManagedCollection#removeAll(com.common.util.ICollection, byte)
|
||
|
|
*/
|
||
|
|
public boolean removeAll(ICollection values, byte context) {
|
||
|
|
boolean result = true;
|
||
|
|
|
||
|
|
//Clear the error information prior to running the operation.//
|
||
|
|
setErrorInfo(null);
|
||
|
|
//Verify that this collection can be modified.//
|
||
|
|
verifyIsChangeable(context);
|
||
|
|
|
||
|
|
//Make sure that there are values to remove.//
|
||
|
|
if((values != null) && (values.getSize() > 0)) {
|
||
|
|
IndexedCollectionManager collectionManager = (IndexedCollectionManager) internalGetCollectionManager();
|
||
|
|
|
||
|
|
//Make sure that we are allowed to remove the values.//
|
||
|
|
if((!collectionManager.checkOnRemove()) || (collectionManager.canRemoveAll(this, values, context))) {
|
||
|
|
LiteList removedValues = null;
|
||
|
|
Object next = null;
|
||
|
|
boolean trackChanges = trackChanges(context);
|
||
|
|
IntArray indices = hasReflections() || trackChanges ? new IntArray(values.getSize()) : null;
|
||
|
|
|
||
|
|
//Save the removed values if necessary.//
|
||
|
|
if(hasEventListeners() || collectionManager.notifyOnPostRemove()) {
|
||
|
|
removedValues = new LiteList(values.getSize());
|
||
|
|
}//if//
|
||
|
|
|
||
|
|
//Notify the manager before removing.//
|
||
|
|
if(collectionManager.notifyOnPreRemove()) {
|
||
|
|
collectionManager.preRemoveAll(this, values, context);
|
||
|
|
}//if//
|
||
|
|
|
||
|
|
notifyCollectionObserversOnStart(values.getSize());
|
||
|
|
|
||
|
|
//Remove the values one at a time.//
|
||
|
|
for(IIterator iterator = values.iterator(); iterator.hasNext(); ) {
|
||
|
|
int nextIndex;
|
||
|
|
|
||
|
|
next = iterator.next();
|
||
|
|
nextIndex = internalRemove(next, context);
|
||
|
|
|
||
|
|
if(nextIndex == -1) {
|
||
|
|
result = false;
|
||
|
|
}//if//
|
||
|
|
else {
|
||
|
|
if(removedValues != null) {
|
||
|
|
removedValues.add(next);
|
||
|
|
}//if//
|
||
|
|
|
||
|
|
if(indices != null) {
|
||
|
|
indices.add(nextIndex);
|
||
|
|
}//if//
|
||
|
|
}//else//
|
||
|
|
}//for//
|
||
|
|
|
||
|
|
notifyCollectionObserversOnStop();
|
||
|
|
|
||
|
|
//Notify listeners and fire events if necessary.//
|
||
|
|
if((removedValues != null) && (removedValues.getSize() > 0)) {
|
||
|
|
removedValues.isChangeable(false);
|
||
|
|
|
||
|
|
//Provide the manager an opportunity to act.//
|
||
|
|
if(collectionManager.notifyOnPostRemove()) {
|
||
|
|
collectionManager.postRemoveAll(this, removedValues, context);
|
||
|
|
}//if//
|
||
|
|
|
||
|
|
//Update reflections.//
|
||
|
|
if(hasReflections()) {
|
||
|
|
reflectSupportRemoveNotify(indices);
|
||
|
|
}//if//
|
||
|
|
|
||
|
|
//Track changes.//
|
||
|
|
if(trackChanges) {
|
||
|
|
trackChange(null, indices, context, false);
|
||
|
|
}//if//
|
||
|
|
|
||
|
|
//Fire an event to any event listeners.//
|
||
|
|
fireEvent(false, null, true, removedValues, context);
|
||
|
|
}//if//
|
||
|
|
|
||
|
|
//Notify the parent object in the logical object of our changed state.//
|
||
|
|
collectionStateChanged();
|
||
|
|
}//if//
|
||
|
|
}//if//
|
||
|
|
|
||
|
|
return result;
|
||
|
|
}//removeAll()//
|
||
|
|
/* (non-Javadoc)
|
||
|
|
* @see com.foundation.util.ManagedCollection#removeAll(java.lang.Object[], int, int, byte)
|
||
|
|
*/
|
||
|
|
public boolean removeAll(Object[] values, int offset, int length, byte context) {
|
||
|
|
boolean result = true;
|
||
|
|
|
||
|
|
//Clear the error information prior to running the operation.//
|
||
|
|
setErrorInfo(null);
|
||
|
|
//Verify that this collection can be modified.//
|
||
|
|
verifyIsChangeable(context);
|
||
|
|
|
||
|
|
//Make sure that there are values to remove.//
|
||
|
|
if((values != null) && (values.length > 0)) {
|
||
|
|
IndexedCollectionManager collectionManager = (IndexedCollectionManager) internalGetCollectionManager();
|
||
|
|
|
||
|
|
//Make sure that we are allowed to remove the values.//
|
||
|
|
if((!collectionManager.checkOnRemove()) || (collectionManager.canRemoveAll(this, values, offset, length, context))) {
|
||
|
|
LiteList removedValues = null;
|
||
|
|
boolean trackChanges = trackChanges(context);
|
||
|
|
IntArray indices = hasReflections() || trackChanges ? new IntArray(values.length) : null;
|
||
|
|
|
||
|
|
//Save the removed values if necessary.//
|
||
|
|
if(hasEventListeners() || collectionManager.notifyOnPostRemove()) {
|
||
|
|
removedValues = new LiteList(values.length);
|
||
|
|
}//if//
|
||
|
|
|
||
|
|
//Notify the manager before removing.//
|
||
|
|
if(collectionManager.notifyOnPreRemove()) {
|
||
|
|
collectionManager.preRemoveAll(this, values, offset, length, context);
|
||
|
|
}//if//
|
||
|
|
|
||
|
|
notifyCollectionObserversOnStart(values.length);
|
||
|
|
|
||
|
|
//Remove the values one at a time.//
|
||
|
|
for(int index = offset; index < length; index++) {
|
||
|
|
int nextIndex = internalRemove(values[index], context);
|
||
|
|
|
||
|
|
if(nextIndex == -1) {
|
||
|
|
result = false;
|
||
|
|
}//if//
|
||
|
|
else {
|
||
|
|
if(removedValues != null) {
|
||
|
|
removedValues.add(values[index]);
|
||
|
|
}//if//
|
||
|
|
|
||
|
|
if(indices != null) {
|
||
|
|
indices.add(nextIndex);
|
||
|
|
}//if//
|
||
|
|
}//else//
|
||
|
|
}//for//
|
||
|
|
|
||
|
|
notifyCollectionObserversOnStop();
|
||
|
|
|
||
|
|
//Notify listeners and fire events if necessary.//
|
||
|
|
if((removedValues != null) && (removedValues.getSize() > 0)) {
|
||
|
|
removedValues.isChangeable(false);
|
||
|
|
|
||
|
|
//Provide the manager an opportunity to act.//
|
||
|
|
if(collectionManager.notifyOnPostRemove()) {
|
||
|
|
collectionManager.postRemoveAll(this, removedValues, context);
|
||
|
|
}//if//
|
||
|
|
|
||
|
|
//Update reflections.//
|
||
|
|
if(hasReflections()) {
|
||
|
|
reflectSupportRemoveNotify(indices);
|
||
|
|
}//if//
|
||
|
|
|
||
|
|
//Track changes.//
|
||
|
|
if(trackChanges) {
|
||
|
|
trackChange(null, indices, context, false);
|
||
|
|
}//if//
|
||
|
|
|
||
|
|
//Fire an event to any event listeners.//
|
||
|
|
fireEvent(false, null, true, removedValues, context);
|
||
|
|
}//if//
|
||
|
|
|
||
|
|
//Notify the parent object in the logical object of our changed state.//
|
||
|
|
collectionStateChanged();
|
||
|
|
}//if//
|
||
|
|
}//if//
|
||
|
|
|
||
|
|
return result;
|
||
|
|
}//removeAll()//
|
||
|
|
/* (non-Javadoc)
|
||
|
|
* @see com.common.util.IIndexedCollection#remove(int)
|
||
|
|
*/
|
||
|
|
public Object remove(int index) {
|
||
|
|
return remove(index, CONTEXT_UNTRUSTED);
|
||
|
|
}//remove()//
|
||
|
|
/**
|
||
|
|
* Removes the value from the collection.
|
||
|
|
* @param index The index of the value to remove.
|
||
|
|
* @param context The context for the operation.
|
||
|
|
* @return The value that was removed.
|
||
|
|
*/
|
||
|
|
public Object remove(int index, byte context) {
|
||
|
|
Object result = null;
|
||
|
|
IndexedCollectionManager collectionManager = (IndexedCollectionManager) internalGetCollectionManager();
|
||
|
|
|
||
|
|
//Clear the error information prior to running the operation.//
|
||
|
|
setErrorInfo(null);
|
||
|
|
//Verify that the collection can be modified.//
|
||
|
|
verifyIsChangeable(context);
|
||
|
|
|
||
|
|
//Make sure the manager allows the add.//
|
||
|
|
if((!collectionManager.checkOnRemove()) || (collectionManager.canRemove(this, index, context))) {
|
||
|
|
boolean trackChanges = trackChanges(context);
|
||
|
|
|
||
|
|
//Notify the manager.//
|
||
|
|
if(collectionManager.notifyOnPreRemove()) {
|
||
|
|
collectionManager.preRemove(this, index, context);
|
||
|
|
}//if//
|
||
|
|
|
||
|
|
//Perform the remove opertion.//
|
||
|
|
result = internalRemove(index, context);
|
||
|
|
|
||
|
|
//Notify the manager.//
|
||
|
|
if(collectionManager.notifyOnPostRemove()) {
|
||
|
|
collectionManager.postRemove(this, index, result, context);
|
||
|
|
}//if//
|
||
|
|
|
||
|
|
//Update reflections.//
|
||
|
|
if(hasReflections()) {
|
||
|
|
reflectSupportRemoveNotify(index);
|
||
|
|
}//if//
|
||
|
|
|
||
|
|
//Track changes.//
|
||
|
|
if(trackChanges) {
|
||
|
|
trackChange(result, index, context, false);
|
||
|
|
}//if//
|
||
|
|
|
||
|
|
//Notify the parent object in the logical object of our changed state.//
|
||
|
|
collectionStateChanged();
|
||
|
|
//Fire an event.//
|
||
|
|
fireEvent(false, null, true, result);
|
||
|
|
}//if//
|
||
|
|
|
||
|
|
return result;
|
||
|
|
}//remove()//
|
||
|
|
/* (non-Javadoc)
|
||
|
|
* @see com.common.util.IIndexedCollection#replace(int, java.lang.Object)
|
||
|
|
*/
|
||
|
|
public Object replace(int index, Object value) {
|
||
|
|
return replace(index, value, CONTEXT_UNTRUSTED);
|
||
|
|
}//replace()//
|
||
|
|
/**
|
||
|
|
* Replaces the value at the index with the given value.
|
||
|
|
* @param index The index of the value to be removed.
|
||
|
|
* @param value The value to put in place of the removed value. This may not be placed in the same index if the collection is sorted.
|
||
|
|
* @param context The context for the operation.
|
||
|
|
* @return The replaced value.
|
||
|
|
*/
|
||
|
|
public Object replace(int index, Object value, byte context) {
|
||
|
|
Object result = null;
|
||
|
|
IndexedCollectionManager collectionManager = (IndexedCollectionManager) internalGetCollectionManager();
|
||
|
|
|
||
|
|
//Clear the error information prior to running the operation.//
|
||
|
|
setErrorInfo(null);
|
||
|
|
//Verify that the collection can be changed.//
|
||
|
|
verifyIsChangeable(context);
|
||
|
|
|
||
|
|
//Make sure the manager allows the add.//
|
||
|
|
if((!collectionManager.checkOnReplace()) || (collectionManager.canReplace(this, index, value, context))) {
|
||
|
|
boolean trackChanges = trackChanges(context);
|
||
|
|
int addedIndex;
|
||
|
|
|
||
|
|
//Notify the manager.//
|
||
|
|
if(collectionManager.notifyOnPreReplace()) {
|
||
|
|
collectionManager.preReplace(this, index, value, context);
|
||
|
|
}//if//
|
||
|
|
|
||
|
|
result = internalRemove(index, context);
|
||
|
|
addedIndex = internalAdd(index, value, context);
|
||
|
|
|
||
|
|
//Notify the manager.//
|
||
|
|
if(collectionManager.notifyOnPostReplace()) {
|
||
|
|
collectionManager.postReplace(this, index, result, value, context);
|
||
|
|
}//if//
|
||
|
|
|
||
|
|
//Update reflections.//
|
||
|
|
if(hasReflections()) {
|
||
|
|
reflectSupportRemoveNotify(index);
|
||
|
|
reflectSupportAddNotify(value, addedIndex);
|
||
|
|
}//if//
|
||
|
|
|
||
|
|
//Track changes.//
|
||
|
|
if(trackChanges) {
|
||
|
|
trackChange(null, index, context, false);
|
||
|
|
trackChange(value, context == CONTEXT_TRUSTED ? index : addedIndex, context, true);
|
||
|
|
}//if//
|
||
|
|
|
||
|
|
//Notify the parent object in the logical object of our changed state.//
|
||
|
|
collectionStateChanged();
|
||
|
|
//Fire event.//
|
||
|
|
fireEvent(true, value, true, result);
|
||
|
|
}//if//
|
||
|
|
|
||
|
|
return result;
|
||
|
|
}//replace()//
|
||
|
|
/* (non-Javadoc)
|
||
|
|
* @see com.common.util.IIndexedCollection#set(int, java.lang.Object)
|
||
|
|
*/
|
||
|
|
public Object set(int index, Object value) {
|
||
|
|
return set(index, value, CONTEXT_UNTRUSTED);
|
||
|
|
}//set()//
|
||
|
|
/**
|
||
|
|
* Sets the value at the given index. This operation is not valid if the collection is sorted and should never be called.
|
||
|
|
* @param index The index whose value is going to be replaced with the given value.
|
||
|
|
* @param value The value to assign to the index.
|
||
|
|
* @param context The context for the operation.
|
||
|
|
* @return The value previously at the index.
|
||
|
|
*/
|
||
|
|
public Object set(int index, Object value, byte context) {
|
||
|
|
Object result = null;
|
||
|
|
boolean isReplace = index < getSize();
|
||
|
|
IndexedCollectionManager collectionManager = (IndexedCollectionManager) internalGetCollectionManager();
|
||
|
|
|
||
|
|
//Clear the error information prior to running the operation.//
|
||
|
|
setErrorInfo(null);
|
||
|
|
//Verify that the collection can be changed.//
|
||
|
|
verifyIsChangeable(context);
|
||
|
|
|
||
|
|
if(isLocallySorted()) {
|
||
|
|
throw new IllegalAccessError("Cannot call set in a sorted collection.");
|
||
|
|
}//if//
|
||
|
|
|
||
|
|
//Make sure the manager allows the replace.//
|
||
|
|
if((!collectionManager.checkOnReplace()) || (collectionManager.canReplace(this, index, value, context))) {
|
||
|
|
boolean hasRemove = index < getSize();
|
||
|
|
boolean trackChanges = trackChanges(context);
|
||
|
|
|
||
|
|
//Notify the manager.//
|
||
|
|
if(collectionManager.notifyOnPreReplace()) {
|
||
|
|
collectionManager.preReplace(this, index, value, context);
|
||
|
|
}//if//
|
||
|
|
|
||
|
|
result = internalSet(index, value, context);
|
||
|
|
|
||
|
|
//Notify the manager.//
|
||
|
|
if(isReplace) {
|
||
|
|
if(collectionManager.notifyOnPostReplace()) {
|
||
|
|
collectionManager.postReplace(this, index, result, value, context);
|
||
|
|
}//if//
|
||
|
|
}//if//
|
||
|
|
else {
|
||
|
|
if(collectionManager.notifyOnPostAdd()) {
|
||
|
|
collectionManager.postAdd(this, index, value, context);
|
||
|
|
}//if//
|
||
|
|
}//else//
|
||
|
|
|
||
|
|
//Update reflections.//
|
||
|
|
if(hasReflections()) {
|
||
|
|
if(hasRemove) {
|
||
|
|
reflectSupportRemoveNotify(index);
|
||
|
|
}//if//
|
||
|
|
|
||
|
|
reflectSupportAddNotify(value, index);
|
||
|
|
}//if//
|
||
|
|
|
||
|
|
//Track changes.//
|
||
|
|
if(trackChanges) {
|
||
|
|
if(hasRemove) {
|
||
|
|
trackChange(null, index, context, false);
|
||
|
|
}//if//
|
||
|
|
|
||
|
|
trackChange(value, index, context, true);
|
||
|
|
}//if//
|
||
|
|
|
||
|
|
//Notify the parent object in the logical object of our changed state.//
|
||
|
|
collectionStateChanged();
|
||
|
|
//Fire event.//
|
||
|
|
fireEvent(true, value, true, result);
|
||
|
|
}//if//
|
||
|
|
|
||
|
|
return result;
|
||
|
|
}//set()//
|
||
|
|
/**
|
||
|
|
* Determines whether the collection is sorted internally (versus externally, or no dicernable sorting).
|
||
|
|
* @return Whether this collection has a sort applied to it.
|
||
|
|
*/
|
||
|
|
public abstract boolean isLocallySorted();
|
||
|
|
/**
|
||
|
|
* Recursively prepares the reflectable (non-reflection) prior to being part of a synchronize action via the current reflection context.
|
||
|
|
* <p>For example, if a view creates a new model object and makes it part of an existing reflection of a logical model, then this method will be called on the new model object prior to synchronizing the changes.</p>
|
||
|
|
* <p>Note: This method only gets called if this object is not a reflection in the current context (in which case it is never going to be a reflection at all), but is referenced by a reflection that is being synchronized.
|
||
|
|
* This method should prepare a non-reflection for being moved to a different reflection context (or no reflection context) by replacing any references to reflections in the current context.</p>
|
||
|
|
* <p>This method does not copy this object, but does make permenant changes.</p>
|
||
|
|
* @param currentContext The current reflection context that is preparing to synchronize this object. This object might not be a reflection in the current context if this object is newly created.
|
||
|
|
* @param destinationContext The reflection context that this object is being synchronized to, if known. This may be null if the context is remote, or if not synchronizing to another reflection context. This is primarily used to make coding views more flexable since one view may base some but not all its data on the previous view's reflections.
|
||
|
|
* @param newPartOfEntity The part of entity reference that should be set during a recursive call. Initial callers should ALWAYS pass null.
|
||
|
|
* @param cloned The reflectable that this reflectable is a clone of. All non-reflections are cloned prior to synchronization so that the new shared objects will not have any ties to old proxies. Proxies to the non-clone will continue to work since the synchronization will either fail (in which case the proxied non-clone object doesn't change), or will succeed and pass the reflection data back to the reflection context which will utilize the non-clone object as the reflection object.
|
||
|
|
* @param synchronizingContext The reflection context that is performing the synchronization operation.
|
||
|
|
*/
|
||
|
|
protected void reflectionPreSynchronize(ReflectionContext currentContext, ReflectionContext destinationContext, IEntity newPartOfEntity, IReflectable cloned, ReflectionContext synchronizingContext) {
|
||
|
|
//Set the new part-of entity (should be null always I think - to prep it for being added to the shared model).//
|
||
|
|
internalSetPartOfEntity(newPartOfEntity);
|
||
|
|
//Link this model to the cloned model via a unique number within the context of the Reflection Context.//
|
||
|
|
createModelMapping(cloned, currentContext);
|
||
|
|
|
||
|
|
//Copy the cloned object's hash since its hash must be the same as the hash of the object it reflects (and it will reflect this object once it has been succesfully synchronized).//
|
||
|
|
//Note: Since the cloned object is being reused as a reflection upon successful synchronization, its hash must not change, otherwise hashmap lookups (as are often used in the view components) will fail.//
|
||
|
|
if(cloned != null) {
|
||
|
|
setHash(((ManagedCollection) cloned).getHash());
|
||
|
|
}//if//
|
||
|
|
|
||
|
|
//Iterate over the contents to dereflect reflections in this context, and to fix the objects if they are part of the list.//
|
||
|
|
for(int index = 0; index < getSize(); index++) {
|
||
|
|
Object value = get(index);
|
||
|
|
|
||
|
|
if(value instanceof IReflectable) {
|
||
|
|
//If the value is a reflection in this context then de-reflect it.//
|
||
|
|
if(((IReflectable) value).zzrIsReflection(value, currentContext)) {
|
||
|
|
//
|
||
|
|
// Note:
|
||
|
|
//Don't worry about the value being part-of since that is impossible.
|
||
|
|
//It isn't possible because this object isn't a reflection in the current context (it is new which is why this is being called).
|
||
|
|
//So that means this value must be a reference to something else in this logical object that already exists in the reflected logical object.
|
||
|
|
//Or it is a reference to something not in the logical object that already exists in the destination context, or will soon.
|
||
|
|
//
|
||
|
|
value = ((IReflectable) value).getReflected();
|
||
|
|
|
||
|
|
//If the value is not a reflection in the destination context then make it one.//
|
||
|
|
if((destinationContext != null) && (!((IReflectable) value).zzrIsReflection(value, destinationContext))) {
|
||
|
|
value = destinationContext.createReflection((IReflectable) value);
|
||
|
|
}//if//
|
||
|
|
|
||
|
|
//If the value has changed then update this object.//
|
||
|
|
replace(index, value, CONTEXT_UNTRUSTED);
|
||
|
|
}//if//
|
||
|
|
else if(((IReflectable) value).isReflection()) {
|
||
|
|
Debug.log(new RuntimeException("Error: Detected a reflection in the wrong context."));
|
||
|
|
}//else if//
|
||
|
|
else if(isPartOf()) {
|
||
|
|
Object clonedValue = ((ManagedIndexedCollection) cloned).get(index);
|
||
|
|
|
||
|
|
//If the value is part of this object then pre-synchronize the value.//
|
||
|
|
((IReflectable) value).zzrReflectionPreSynchronize(value, currentContext, destinationContext, newPartOfEntity, (IReflectable) clonedValue, synchronizingContext);
|
||
|
|
}//else if//
|
||
|
|
}//if//
|
||
|
|
}//for//
|
||
|
|
}//reflectionPreSynchronize()//
|
||
|
|
/* (non-Javadoc)
|
||
|
|
* @see com.foundation.util.ManagedCollection#reflectionCreateSafeCopy(com.foundation.attribute.ReflectionContext)
|
||
|
|
*/
|
||
|
|
protected IReflectable reflectionCreateSafeCopy(com.foundation.attribute.ReflectionContext reflectionContext) {
|
||
|
|
/* This code created a copy of this reflectable object. The problem with a copy (besides being inefficient, is that multiple references create multiple copies to the same object. This could be fixed by tracking the copies in the context, but it might be better to just modify the original object.
|
||
|
|
IReflectable result = null;
|
||
|
|
|
||
|
|
if(isReflection(reflectionContext)) {
|
||
|
|
result = getReflectedObject();
|
||
|
|
}//if//
|
||
|
|
else {
|
||
|
|
try {
|
||
|
|
ManagedIndexedCollection clone = (ManagedIndexedCollection) clone();
|
||
|
|
|
||
|
|
result = clone;
|
||
|
|
|
||
|
|
//Iterate over the values to convert them where necessary.//
|
||
|
|
for(int index = 0; index < clone.getSize(); index++) {
|
||
|
|
Object value = clone.get(index);
|
||
|
|
|
||
|
|
if(value instanceof IReflectable) {
|
||
|
|
IReflectable reflectable = (IReflectable) value;
|
||
|
|
|
||
|
|
if(reflectable.isReflection(reflectionContext)) {
|
||
|
|
//Dereference the reflection.//
|
||
|
|
clone.set(index, reflectable.getReflected());
|
||
|
|
}//if//
|
||
|
|
else if(reflectable.isReflection()) {
|
||
|
|
if(isPartOf()) {
|
||
|
|
Debug.log(new RuntimeException(), "Error: Invalid data structure: Cannot have a reflection in a non-reflection collection with the wrong reflection context.");
|
||
|
|
}//if//
|
||
|
|
|
||
|
|
//Leave it alone - this may be an error.//
|
||
|
|
}//else if//
|
||
|
|
else if(isPartOf()) {
|
||
|
|
//Create a copy of the value.//
|
||
|
|
clone.set(index, reflectable.reflectionCreateSafeCopy(reflectionContext));
|
||
|
|
}//else if//
|
||
|
|
else {
|
||
|
|
//Do nothing - pass the reference as is.//
|
||
|
|
}//else//
|
||
|
|
}//if//
|
||
|
|
}//for//
|
||
|
|
}//try//
|
||
|
|
catch(CloneNotSupportedException e) {
|
||
|
|
Debug.log(e, "Failed to create a clone of the collection durring a synchronization of a reflection.");
|
||
|
|
}//catch//
|
||
|
|
}//else//
|
||
|
|
|
||
|
|
return result;
|
||
|
|
*/
|
||
|
|
return this;
|
||
|
|
}//reflectionCreateSafeCopy()//
|
||
|
|
/* (non-Javadoc)
|
||
|
|
* @see com.foundation.util.ManagedCollection#hasCollectionObservers()
|
||
|
|
*/
|
||
|
|
protected boolean hasCollectionObservers() {
|
||
|
|
return super.hasCollectionObservers() || ((indexedCollectionObservers != null) && (indexedCollectionObservers.getSize() > 0));
|
||
|
|
}//hasCollectionObservers()//
|
||
|
|
/**
|
||
|
|
* Notifies any collection listeners of a change in the collection values.
|
||
|
|
* @param value The value added.
|
||
|
|
* @param valueIndex The index of the value added, or -1 if not known.
|
||
|
|
*/
|
||
|
|
protected void notifyCollectionObserversOnAdd(Object value, int valueIndex) {
|
||
|
|
super.notifyCollectionObserversOnAdd(value);
|
||
|
|
|
||
|
|
if((indexedCollectionObservers != null) && (indexedCollectionObservers.getSize() > 0)) {
|
||
|
|
for(int index = 0; index < indexedCollectionObservers.getSize(); index++) {
|
||
|
|
((IInlineIndexedCollectionObserver) indexedCollectionObservers.get(index)).valueAdded(value, valueIndex);
|
||
|
|
}//for//
|
||
|
|
}//if//
|
||
|
|
}//notifyCollectionObserversOnAdd()//
|
||
|
|
/**
|
||
|
|
* Notifies any collection listeners of a change in the collection values.
|
||
|
|
* @param value The value removed.
|
||
|
|
* @param valueIndex The index of the value removed, or -1 if not known.
|
||
|
|
*/
|
||
|
|
protected void notifyCollectionObserversOnRemove(Object value, int valueIndex) {
|
||
|
|
super.notifyCollectionObserversOnRemove(value);
|
||
|
|
|
||
|
|
if((indexedCollectionObservers != null) && (indexedCollectionObservers.getSize() > 0)) {
|
||
|
|
for(int index = 0; index < indexedCollectionObservers.getSize(); index++) {
|
||
|
|
((IInlineIndexedCollectionObserver) indexedCollectionObservers.get(index)).valueRemoved(value, valueIndex);
|
||
|
|
}//for//
|
||
|
|
}//if//
|
||
|
|
}//notifyCollectionObserversOnRemove()//
|
||
|
|
/* (non-Javadoc)
|
||
|
|
* @see com.foundation.util.ManagedCollection#notifyCollectionObserversOnRemovingAll()
|
||
|
|
*/
|
||
|
|
protected void notifyCollectionObserversOnRemovingAll() {
|
||
|
|
super.notifyCollectionObserversOnRemovingAll();
|
||
|
|
|
||
|
|
if((indexedCollectionObservers != null) && (indexedCollectionObservers.getSize() > 0)) {
|
||
|
|
for(int index = 0; index < indexedCollectionObservers.getSize(); index++) {
|
||
|
|
((IInlineIndexedCollectionObserver) indexedCollectionObservers.get(index)).removingAll();
|
||
|
|
}//for//
|
||
|
|
}//if//
|
||
|
|
}//notifyCollectionObserversOnRemovingAll()//
|
||
|
|
/* (non-Javadoc)
|
||
|
|
* @see com.foundation.util.ManagedCollection#notifyCollectionObserversOnStart(int)
|
||
|
|
*/
|
||
|
|
protected void notifyCollectionObserversOnStart(int changeCount) {
|
||
|
|
super.notifyCollectionObserversOnStart(changeCount);
|
||
|
|
|
||
|
|
if(startChangeCount == 1) {
|
||
|
|
if((indexedCollectionObservers != null) && (indexedCollectionObservers.getSize() > 0)) {
|
||
|
|
for(int index = 0; index < indexedCollectionObservers.getSize(); index++) {
|
||
|
|
((IInlineIndexedCollectionObserver) indexedCollectionObservers.get(index)).startChanges(changeCount);
|
||
|
|
}//for//
|
||
|
|
}//if//
|
||
|
|
}//if//
|
||
|
|
}//notifyCollectionObserversOnStart()//
|
||
|
|
/* (non-Javadoc)
|
||
|
|
* @see com.foundation.util.ManagedCollection#notifyCollectionObserversOnStop()
|
||
|
|
*/
|
||
|
|
protected void notifyCollectionObserversOnStop() {
|
||
|
|
super.notifyCollectionObserversOnStop();
|
||
|
|
|
||
|
|
if(startChangeCount == 0) {
|
||
|
|
if((indexedCollectionObservers != null) && (indexedCollectionObservers.getSize() > 0)) {
|
||
|
|
for(int index = 0; index < indexedCollectionObservers.getSize(); index++) {
|
||
|
|
((IInlineIndexedCollectionObserver) indexedCollectionObservers.get(index)).stopChanges();
|
||
|
|
}//for//
|
||
|
|
}//if//
|
||
|
|
}//if//
|
||
|
|
}//notifyCollectionObserversOnStop()//
|
||
|
|
/**
|
||
|
|
* Notifies any collection listeners of a change in the collection values.
|
||
|
|
* @param indexMap The mapping of indices. The number in array position N is the current N'th item's new index.
|
||
|
|
*/
|
||
|
|
protected void notifyCollectionObserversOnSort(int[] indexMap) {
|
||
|
|
if((indexedCollectionObservers != null) && (indexedCollectionObservers.getSize() > 0)) {
|
||
|
|
for(int index = 0; index < indexedCollectionObservers.getSize(); index++) {
|
||
|
|
((IInlineIndexedCollectionObserver) indexedCollectionObservers.get(index)).valuesSorted(indexMap);
|
||
|
|
}//for//
|
||
|
|
}//if//
|
||
|
|
}//notifyCollectionObservers()//
|
||
|
|
/* (non-Javadoc)
|
||
|
|
* @see com.foundation.util.IInlineIndexedCollectionObservable#addCollectionObserver(com.foundation.util.IInlineIndexedCollectionObserver)
|
||
|
|
*/
|
||
|
|
public void addCollectionObserver(IInlineIndexedCollectionObserver observer) {
|
||
|
|
if(indexedCollectionObservers == null) {
|
||
|
|
indexedCollectionObservers = new LiteList(2, 4);
|
||
|
|
}//if//
|
||
|
|
|
||
|
|
indexedCollectionObservers.add(observer);
|
||
|
|
observer.startChanges(getSize());
|
||
|
|
|
||
|
|
//Pass all existing values to the observer.//
|
||
|
|
for(int index = 0; index < getSize(); index++) {
|
||
|
|
observer.valueAdded(get(index), index);
|
||
|
|
}//for//
|
||
|
|
|
||
|
|
observer.stopChanges();
|
||
|
|
}//addCollectionObserver()//
|
||
|
|
/* (non-Javadoc)
|
||
|
|
* @see com.foundation.util.IInlineIndexedCollectionObservable#removeCollectionObserver(com.foundation.util.IInlineIndexedCollectionObserver)
|
||
|
|
*/
|
||
|
|
public void removeCollectionObserver(IInlineIndexedCollectionObserver observer) {
|
||
|
|
indexedCollectionObservers.remove(observer);
|
||
|
|
}//removeCollectionObserver()//
|
||
|
|
/**
|
||
|
|
* Reads the collection from the stream.
|
||
|
|
* @param in java.io.ObjectInput The stream that the object data can be read from.
|
||
|
|
*/
|
||
|
|
public void readExternal(java.io.ObjectInput in) throws java.io.IOException, ClassNotFoundException {
|
||
|
|
/*byte version = */in.readByte();
|
||
|
|
|
||
|
|
super.readExternal(in);
|
||
|
|
}//readExternal()//
|
||
|
|
/**
|
||
|
|
* Writes the collection to the stream.
|
||
|
|
* @param out java.io.ObjectOutput The stream that the object data can be written to.
|
||
|
|
*/
|
||
|
|
public void writeExternal(java.io.ObjectOutput out) throws java.io.IOException {
|
||
|
|
out.writeByte(0); //Version number.//
|
||
|
|
super.writeExternal(out);
|
||
|
|
}//writeExternal()//
|
||
|
|
/**
|
||
|
|
* Determines whether order matters for the collection and the order is managed by the application (versus an order comparator and the contained value data).
|
||
|
|
* @return Whether the ordering of the collection is important information that must be retained since it may not be stored anywhere else.
|
||
|
|
*/
|
||
|
|
public boolean isExternallyOrdered() {
|
||
|
|
return isExternallyOrdered;
|
||
|
|
}//isExternallyOrdered()//
|
||
|
|
/**
|
||
|
|
* Whether the collection is ordered manually (or externally) by the code.
|
||
|
|
* If true then the collection ordering is going to be synchronized with the collection contents when reflected.
|
||
|
|
*/
|
||
|
|
public void setManuallyOrdered() {
|
||
|
|
this.isExternallyOrdered = true;
|
||
|
|
}//setManuallyOrdered()//
|
||
|
|
/* (non-Javadoc)
|
||
|
|
* @see com.foundation.attribute.ReflectCollectionSupport#createReflectCollectionData()
|
||
|
|
*/
|
||
|
|
protected ReflectCollectionData createReflectCollectionData() {
|
||
|
|
return new ReflectIndexedCollectionData();
|
||
|
|
}//createReflectCollectionData()//
|
||
|
|
/* (non-Javadoc)
|
||
|
|
* @see com.foundation.attribute.ReflectCollectionSupport#initializeReflectCollectionData(com.foundation.attribute.ReflectCollectionData)
|
||
|
|
*/
|
||
|
|
protected void initializeReflectCollectionData(ReflectCollectionData reflectionData) {
|
||
|
|
ReflectIndexedCollectionData data = (ReflectIndexedCollectionData) reflectionData;
|
||
|
|
|
||
|
|
super.initializeReflectCollectionData(reflectionData);
|
||
|
|
data.retainOrdering = isExternallyOrdered();
|
||
|
|
}//registerReflection()//
|
||
|
|
/* (non-Javadoc)
|
||
|
|
* @see com.foundation.attribute.ReflectCollectionSupport#reflectionInitialize(com.foundation.attribute.ReflectCollectionData)
|
||
|
|
*/
|
||
|
|
protected Object reflectionInitialize(ReflectCollectionData reflectionData) {
|
||
|
|
//Note: It is assumed that externally ordered collections will send their data in the correct order.//
|
||
|
|
isExternallyOrdered = ((ReflectIndexedCollectionData) reflectionData).retainOrdering;
|
||
|
|
|
||
|
|
return super.reflectionInitialize(reflectionData);
|
||
|
|
}//reflectionInitialize()//
|
||
|
|
/**
|
||
|
|
* Notifies the reflection support of a value added to the supported collection.
|
||
|
|
* This method is called by the supported collection when it adds a value locally, or as part of an update.
|
||
|
|
* @param values The values added by the supported collection.
|
||
|
|
* @param indices The indices at which the values were added.
|
||
|
|
*/
|
||
|
|
public void reflectSupportAddNotify(IList values, IntArray indices) {
|
||
|
|
if(getEventData() == null) {
|
||
|
|
if(hasReflections()) {
|
||
|
|
ReflectIndexedCollectionData eventData = (ReflectIndexedCollectionData) createReflectCollectionData();
|
||
|
|
|
||
|
|
eventData.addAddOperation(values, indices);
|
||
|
|
sendUpdate(eventData, null);
|
||
|
|
}//if//
|
||
|
|
}//if//
|
||
|
|
else {
|
||
|
|
ReflectIndexedCollectionData eventData = (ReflectIndexedCollectionData) getEventData();
|
||
|
|
|
||
|
|
eventData.addAddOperation(values, indices);
|
||
|
|
}//else//
|
||
|
|
}//reflectSupportAddNotify()//
|
||
|
|
/**
|
||
|
|
* Notifies the reflection support of a value removed from the supported collection.
|
||
|
|
* This method is called by the supported collection when it removes a value locally, or as part of an update.
|
||
|
|
* @param indices The indices at which the values were removed.
|
||
|
|
*/
|
||
|
|
public void reflectSupportRemoveNotify(IntArray indices) {
|
||
|
|
if(getEventData() == null) {
|
||
|
|
if(hasReflections()) {
|
||
|
|
ReflectIndexedCollectionData eventData = (ReflectIndexedCollectionData) createReflectCollectionData();
|
||
|
|
|
||
|
|
eventData.addRemoveOperation(indices);
|
||
|
|
sendUpdate(eventData, null);
|
||
|
|
}//if//
|
||
|
|
}//if//
|
||
|
|
else {
|
||
|
|
ReflectIndexedCollectionData eventData = (ReflectIndexedCollectionData) getEventData();
|
||
|
|
|
||
|
|
eventData.addRemoveOperation(indices);
|
||
|
|
}//else//
|
||
|
|
}//reflectSupportRemoveNotify()//
|
||
|
|
/**
|
||
|
|
* Notifies the reflection support of a value added to the supported collection.
|
||
|
|
* This method is called by the supported collection when it adds a value locally, or as part of an update.
|
||
|
|
* @param value The value added by the supported collection.
|
||
|
|
* @param index The index at which the value was added.
|
||
|
|
*/
|
||
|
|
public void reflectSupportAddNotify(Object value, int index) {
|
||
|
|
if(getEventData() == null) {
|
||
|
|
if(hasReflections()) {
|
||
|
|
ReflectIndexedCollectionData eventData = (ReflectIndexedCollectionData) createReflectCollectionData();
|
||
|
|
|
||
|
|
eventData.addAddOperation(value, index);
|
||
|
|
sendUpdate(eventData, null);
|
||
|
|
}//if//
|
||
|
|
}//if//
|
||
|
|
else {
|
||
|
|
ReflectIndexedCollectionData eventData = (ReflectIndexedCollectionData) getEventData();
|
||
|
|
|
||
|
|
eventData.addAddOperation(value, index);
|
||
|
|
}//else//
|
||
|
|
}//reflectSupportAddNotify()//
|
||
|
|
/**
|
||
|
|
* Notifies the reflection support of a value removed from the supported collection.
|
||
|
|
* This method is called by the supported collection when it removes a value locally, or as part of an update.
|
||
|
|
* @param index The index at which the value was removed.
|
||
|
|
*/
|
||
|
|
public void reflectSupportRemoveNotify(int index) {
|
||
|
|
if(getEventData() == null) {
|
||
|
|
if(hasReflections()) {
|
||
|
|
ReflectIndexedCollectionData eventData = (ReflectIndexedCollectionData) createReflectCollectionData();
|
||
|
|
|
||
|
|
eventData.addRemoveOperation(index);
|
||
|
|
sendUpdate(eventData, null);
|
||
|
|
}//if//
|
||
|
|
}//if//
|
||
|
|
else {
|
||
|
|
ReflectIndexedCollectionData eventData = (ReflectIndexedCollectionData) getEventData();
|
||
|
|
|
||
|
|
eventData.addRemoveOperation(index);
|
||
|
|
}//else//
|
||
|
|
}//reflectSupportRemoveNotify()//
|
||
|
|
/**
|
||
|
|
* Notifies the reflection support that all values were removed from the supported collection.
|
||
|
|
* This method is called by the supported collection when it removes a value locally, or as part of an update.
|
||
|
|
*/
|
||
|
|
public void reflectSupportRemoveAllNotify() {
|
||
|
|
if(getEventData() == null) {
|
||
|
|
if(hasReflections()) {
|
||
|
|
ReflectIndexedCollectionData eventData = (ReflectIndexedCollectionData) createReflectCollectionData();
|
||
|
|
|
||
|
|
eventData.operations = new IntArray(1);
|
||
|
|
eventData.operations.add(ReflectIndexedCollectionData.OPERATION_REMOVE_ALL);
|
||
|
|
|
||
|
|
sendUpdate(eventData, null);
|
||
|
|
}//if//
|
||
|
|
}//if//
|
||
|
|
else {
|
||
|
|
ReflectIndexedCollectionData eventData = (ReflectIndexedCollectionData) getEventData();
|
||
|
|
|
||
|
|
if(eventData.operations == null) {
|
||
|
|
eventData.operations = new IntArray(1, 100);
|
||
|
|
}//if//
|
||
|
|
else {
|
||
|
|
eventData.operations.ensureCapacity(1);
|
||
|
|
}//else//
|
||
|
|
|
||
|
|
eventData.operations.add(ReflectIndexedCollectionData.OPERATION_REMOVE_ALL);
|
||
|
|
}//else//
|
||
|
|
}//reflectSupportRemoveAllNotify()//
|
||
|
|
/**
|
||
|
|
* Creates the collection of adds and removes since the change flags were last reset.
|
||
|
|
* @param added The collection to be filled with added values.
|
||
|
|
* @param addedIndices The indices of the adds. Note that indices are in ascending order and N+1 will always be greater than N.
|
||
|
|
* @param removedIndices The indices in the original collection of the values to be removed. These should be applied before applying any adds. This can be null if the caller doesn't care about removes. Note that indices are in ascending order and N+1 will always be greater than N.
|
||
|
|
*/
|
||
|
|
protected abstract void getCollectionChanges(ICollection added, IntArray addedIndices, IntArray removedIndices);
|
||
|
|
}//ManagedIndexedCollection//
|