diff options
Diffstat (limited to 'jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/CompositeListValueModel.java')
-rw-r--r-- | jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/CompositeListValueModel.java | 574 |
1 files changed, 0 insertions, 574 deletions
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/CompositeListValueModel.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/CompositeListValueModel.java deleted file mode 100644 index 3609d5a4dd..0000000000 --- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/CompositeListValueModel.java +++ /dev/null @@ -1,574 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2008 Oracle. All rights reserved. - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v1.0, which accompanies this distribution - * and is available at http://www.eclipse.org/legal/epl-v10.html. - * - * Contributors: - * Oracle - initial API and implementation - ******************************************************************************/ -package org.eclipse.jpt.utility.internal.model.value; - -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; -import java.util.ListIterator; -import org.eclipse.jpt.utility.internal.CollectionTools; -import org.eclipse.jpt.utility.internal.Transformer; -import org.eclipse.jpt.utility.internal.iterators.ReadOnlyCompositeListIterator; -import org.eclipse.jpt.utility.internal.iterators.TransformationListIterator; -import org.eclipse.jpt.utility.model.event.ListChangeEvent; -import org.eclipse.jpt.utility.model.listener.ListChangeListener; -import org.eclipse.jpt.utility.model.value.ListValueModel; - -/** - * A <code>CompositeListValueModel</code> wraps another - * <code>ListValueModel</code> and uses a <code>Transformer</code> - * to convert each item in the wrapped list to yet another - * <code>ListValueModel</code>. This composite list contains - * the combined items from all these component lists. - * - * Terminology: - * - sources - the items in the wrapped list value model; these - * are converted into component LVMs by the transformer - * - componentLVMs - the component list value models that are combined - * by this composite list value model - * - items - the items held by the component LVMs - */ -public class CompositeListValueModel<E1, E2> - extends ListValueModelWrapper<E1> - implements ListValueModel<E2> -{ - /** - * This is the (optional) user-supplied object that transforms - * the items in the wrapped list to list value models. - */ - private final Transformer<E1, ListValueModel<E2>> transformer; - - /** - * Cache of the sources, component LVMs, lists. - */ - private final ArrayList<Info> infoList; - protected class Info { - // the object passed to the transformer - final E1 source; - // the list value model generated by the transformer - final ListValueModel<E2> componentLVM; - // cache of the items held by the component LVM - final ArrayList<E2> items; - // the component LVM's beginning index within the composite LVM - int begin; - Info(E1 source, ListValueModel<E2> componentLVM, ArrayList<E2> items, int begin) { - super(); - this.source = source; - this.componentLVM = componentLVM; - this.items = items; - this.begin = begin; - } - } - - /** Listener that listens to all the component list value models. */ - private final ListChangeListener componentLVMListener; - - /** Cache the size of the composite list. */ - private int size; - - - // ********** constructors ********** - - /** - * Construct a list value model with the specified wrapped - * list value model. Use this constructor if - * - the wrapped list value model already contains other - * list value models or - * - you want to override the <code>transform(E1)</code> method - * instead of building a <code>Transformer</code> - */ - public CompositeListValueModel(ListValueModel<? extends E1> listHolder) { - this(listHolder, Transformer.Null.<E1, ListValueModel<E2>>instance()); - } - - /** - * Construct a list value model with the specified wrapped - * list value model and transformer. - */ - public CompositeListValueModel(ListValueModel<? extends E1> listHolder, Transformer<E1, ListValueModel<E2>> transformer) { - super(listHolder); - this.transformer = transformer; - this.infoList = new ArrayList<Info>(); - this.componentLVMListener = this.buildComponentLVMListener(); - this.size = 0; - } - - /** - * Construct a list value model with the specified, unchanging, wrapped - * list. Use this constructor if - * - the wrapped list already contains list value models or - * - you want to override the <code>transform(E1)</code> method - * instead of building a <code>Transformer</code> - */ - public CompositeListValueModel(List<? extends E1> list) { - this(new StaticListValueModel<E1>(list)); - } - - /** - * Construct a list value model with the specified, unchanging, wrapped - * list and transformer. - */ - public CompositeListValueModel(List<? extends E1> list, Transformer<E1, ListValueModel<E2>> transformer) { - this(new StaticListValueModel<E1>(list), transformer); - } - - - // ********** initialization ********** - - protected ListChangeListener buildComponentLVMListener() { - return new ListChangeListener() { - public void itemsAdded(ListChangeEvent event) { - CompositeListValueModel.this.componentItemsAdded(event); - } - public void itemsRemoved(ListChangeEvent event) { - CompositeListValueModel.this.componentItemsRemoved(event); - } - public void itemsReplaced(ListChangeEvent event) { - CompositeListValueModel.this.componentItemsReplaced(event); - } - public void itemsMoved(ListChangeEvent event) { - CompositeListValueModel.this.componentItemsMoved(event); - } - public void listCleared(ListChangeEvent event) { - CompositeListValueModel.this.componentListCleared(event); - } - public void listChanged(ListChangeEvent event) { - CompositeListValueModel.this.componentListChanged(event); - } - @Override - public String toString() { - return "component LVM listener"; - } - }; - } - - - // ********** ListValueModel implementation ********** - - public E2 get(int index) { - if ((index < 0) || (index >= this.size)) { - throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + this.size); - } - // move backwards through the info list - for (int i = this.infoList.size(); i-- > 0; ) { - Info info = this.infoList.get(i); - if (index >= info.begin) { - return info.items.get(index - info.begin); - } - } - throw new IllegalStateException(); // something is wack - } - - public Iterator<E2> iterator() { - return this.listIterator(); - } - - public ListIterator<E2> listIterator() { - return new ReadOnlyCompositeListIterator<E2>(this.buildListsIterators()); - } - - protected ListIterator<ListIterator<E2>> buildListsIterators() { - return new TransformationListIterator<Info, ListIterator<E2>>(this.infoList.listIterator()) { - @Override - protected ListIterator<E2> transform(Info info) { - return info.items.listIterator(); - } - }; - } - - public int size() { - return this.size; - } - - public Object[] toArray() { - return CollectionTools.array(this.listIterator(), this.size); - } - - - // ********** ListValueModelWrapper overrides/implementation ********** - - @Override - protected void engageModel() { - super.engageModel(); - // synch our cache *after* we start listening to the wrapped list, - // since its value might change when a listener is added - this.addComponentSources(0, this.listHolder.listIterator(), this.listHolder.size()); - } - - @Override - protected void disengageModel() { - super.disengageModel(); - // stop listening to the component LVMs... - for (Info info : this.infoList) { - info.componentLVM.removeListChangeListener(LIST_VALUES, this.componentLVMListener); - } - // ...and clear the cache - this.infoList.clear(); - this.size = 0; - } - - /** - * Some component sources were added; update our cache. - */ - @Override - protected void itemsAdded(ListChangeEvent event) { - this.addComponentSources(event.getIndex(), this.items(event), event.itemsSize(), true); // true = fire event - } - - /** - * Do not fire an event. - */ - protected void addComponentSources(int addedSourcesIndex, ListIterator<? extends E1> addedSources, int addedSourcesSize) { - this.addComponentSources(addedSourcesIndex, addedSources, addedSourcesSize, false); // false = do not fire event - } - - /** - * Add infos corresponding to the specified sources to our cache. - * Fire the appropriate event if requested. - */ - protected void addComponentSources(int addedSourcesIndex, ListIterator<? extends E1> addedSources, int addedSourcesSize, boolean fireEvent) { - ArrayList<Info> newInfoList = new ArrayList<Info>(addedSourcesSize); - // the 'items' are either tacked on to the end or - // at the 'begin' index of the first 'info' that is being pushed back - int newItemsIndex = (addedSourcesIndex == this.infoList.size()) ? this.size : this.infoList.get(addedSourcesIndex).begin; - - int begin = newItemsIndex; - while (addedSources.hasNext()) { - E1 source = addedSources.next(); - ListValueModel<E2> componentLVM = this.transform(source); - componentLVM.addListChangeListener(LIST_VALUES, this.componentLVMListener); - ArrayList<E2> items = new ArrayList<E2>(componentLVM.size()); - CollectionTools.addAll(items, componentLVM.listIterator()); - newInfoList.add(new Info(source, componentLVM, items, begin)); - begin += items.size(); - } - this.infoList.addAll(addedSourcesIndex, newInfoList); - int newItemsSize = begin - newItemsIndex; - this.size += newItemsSize; - - // bump the 'begin' index for all the infos that were pushed back by the insert - int movedInfosIndex = addedSourcesIndex + addedSourcesSize; - for (int i = movedInfosIndex; i < this.infoList.size(); i++) { - this.infoList.get(i).begin += newItemsSize; - } - - if (fireEvent) { - ArrayList<E2> newItems = new ArrayList<E2>(newItemsSize); - for (int i = addedSourcesIndex; i < movedInfosIndex; i++) { - newItems.addAll(this.infoList.get(i).items); - } - this.fireItemsAdded(LIST_VALUES, newItemsIndex, newItems); - } - } - - /** - * Some component sources were removed; update our cache. - */ - @Override - protected void itemsRemoved(ListChangeEvent event) { - this.removeComponentSources(event.getIndex(), event.itemsSize(), true); // true = fire event - } - - /** - * Do not fire an event. - */ - protected void removeComponentSources(int removedSourcesIndex, int removedSourcesSize) { - this.removeComponentSources(removedSourcesIndex, removedSourcesSize, false); // false = do not fire event - } - - /** - * Remove the infos corresponding to the specified sources from our cache. - */ - protected void removeComponentSources(int removedSourcesIndex, int removedSourcesSize, boolean fireEvent) { - int removedItemsIndex = this.infoList.get(removedSourcesIndex).begin; - int movedSourcesIndex = removedSourcesIndex + removedSourcesSize; - int movedItemsIndex = (movedSourcesIndex == this.infoList.size()) ? this.size : this.infoList.get(movedSourcesIndex).begin; - int removedItemsSize = movedItemsIndex - removedItemsIndex; - this.size -= removedItemsSize; - - List<Info> subList = this.infoList.subList(removedSourcesIndex, removedSourcesIndex + removedSourcesSize); - ArrayList<Info> removedInfoList = new ArrayList<Info>(subList); // make a copy - subList.clear(); - - // decrement the 'begin' index for all the infos that were moved forward by the deletes - for (int i = removedSourcesIndex; i < this.infoList.size(); i++) { - this.infoList.get(i).begin -= removedItemsSize; - } - - for (Info removedInfo : removedInfoList) { - removedInfo.componentLVM.removeListChangeListener(LIST_VALUES, this.componentLVMListener); - } - - if (fireEvent) { - ArrayList<E2> removedItems = new ArrayList<E2>(removedItemsSize); - for (Info removedInfo : removedInfoList) { - removedItems.addAll(removedInfo.items); - } - this.fireItemsRemoved(LIST_VALUES, removedItemsIndex, removedItems); - } - } - - /** - * Some component sources were replaced; update our cache. - */ - @Override - protected void itemsReplaced(ListChangeEvent event) { - this.replaceComponentSources(event.getIndex(), this.items(event), event.itemsSize(), true); // true = fire event - } - - /** - * Replaced component sources will not (typically) map to a set of replaced - * items, so we remove and add the corresponding lists of items, resulting in - * two events. - */ - protected void replaceComponentSources(int replacedSourcesIndex, ListIterator<? extends E1> newSources, int replacedSourcesSize, boolean fireEvent) { - this.removeComponentSources(replacedSourcesIndex, replacedSourcesSize, fireEvent); - this.addComponentSources(replacedSourcesIndex, newSources, replacedSourcesSize, fireEvent); - } - - /** - * Some component sources were moved; update our cache. - */ - @Override - protected void itemsMoved(ListChangeEvent event) { - this.moveComponentSources(event.getTargetIndex(), event.getSourceIndex(), event.getMoveLength(), true); // true = fire event - } - - protected void moveComponentSources(int targetSourcesIndex, int sourceSourcesIndex, int movedSourcesLength, boolean fireEvent) { - int sourceItemsIndex = this.infoList.get(sourceSourcesIndex).begin; - - int nextSourceSourceIndex = sourceSourcesIndex + movedSourcesLength; - int nextSourceItemIndex = (nextSourceSourceIndex == this.infoList.size()) ? this.size : this.infoList.get(nextSourceSourceIndex).begin; - int moveItemsLength = nextSourceItemIndex - sourceItemsIndex; - - int targetItemsIndex = -1; - if (sourceSourcesIndex > targetSourcesIndex) { - // move from high to low index - targetItemsIndex = this.infoList.get(targetSourcesIndex).begin; - } else { - // move from low to high index (higher items move down during move) - int nextTargetSourceIndex = targetSourcesIndex + movedSourcesLength; - targetItemsIndex = (nextTargetSourceIndex == this.infoList.size()) ? this.size : this.infoList.get(nextTargetSourceIndex).begin; - targetItemsIndex = targetItemsIndex - moveItemsLength; - } - - CollectionTools.move(this.infoList, targetSourcesIndex, sourceSourcesIndex, movedSourcesLength); - - // update the 'begin' indexes of all the affected 'infos' - int min = Math.min(targetSourcesIndex, sourceSourcesIndex); - int max = Math.max(targetSourcesIndex, sourceSourcesIndex) + movedSourcesLength; - int begin = Math.min(targetItemsIndex, sourceItemsIndex); - for (int i = min; i < max; i++) { - Info info = this.infoList.get(i); - info.begin = begin; - begin += info.componentLVM.size(); - } - - if (fireEvent) { - this.fireItemsMoved(LIST_VALUES, targetItemsIndex, sourceItemsIndex, moveItemsLength); - } - } - - /** - * The component sources were cleared; clear our cache. - */ - @Override - protected void listCleared(ListChangeEvent event) { - this.removeComponentSources(0, this.infoList.size()); - this.fireListCleared(LIST_VALUES); - } - - /** - * The component sources changed; rebuild our cache. - */ - @Override - protected void listChanged(ListChangeEvent event) { - this.removeComponentSources(0, this.infoList.size()); - this.addComponentSources(0, this.listHolder.listIterator(), this.listHolder.size()); - this.fireListChanged(LIST_VALUES); - } - - @Override - public void toString(StringBuilder sb) { - sb.append(CollectionTools.list(this.listIterator(), this.size)); - } - - - // ********** internal methods ********** - - /** - * Transform the specified object into a list value model. - * <p> - * This method can be overridden by a subclass as an - * alternative to building a <code>Transformer</code>. - */ - protected ListValueModel<E2> transform(E1 value) { - return this.transformer.transform(value); - } - - /** - * Return the index of the specified component LVM. - */ - protected int indexOf(ListValueModel<E2> componentLVM) { - for (int i = 0; i < this.infoList.size(); i++) { - if (this.infoList.get(i).componentLVM == componentLVM) { - return i; - } - } - throw new IllegalArgumentException("invalid component LVM: " + componentLVM); - } - - /** - * Return the index of the specified event's component LVM. - */ - protected int indexFor(ListChangeEvent event) { - return this.indexOf(this.componentLVM(event)); - } - - /** - * Items were added to one of the component lists; - * synchronize our cache. - */ - protected void componentItemsAdded(ListChangeEvent event) { - // update the affected 'begin' indices - int componentLVMIndex = this.indexFor(event); - int newItemsSize = event.itemsSize(); - for (int i = componentLVMIndex + 1; i < this.infoList.size(); i++) { - this.infoList.get(i).begin += newItemsSize; - } - this.size += newItemsSize; - - // synchronize the cached list - Info info = this.infoList.get(componentLVMIndex); - CollectionTools.addAll(info.items, event.getIndex(), this.componentItems(event), event.itemsSize()); - - // translate the event - this.fireItemsAdded(event.cloneWithSource(this, LIST_VALUES, info.begin)); - } - - /** - * Items were removed from one of the component lists; - * synchronize our cache. - */ - protected void componentItemsRemoved(ListChangeEvent event) { - // update the affected 'begin' indices - int componentLVMIndex = this.indexFor(event); - int removedItemsSize = event.itemsSize(); - for (int i = componentLVMIndex + 1; i < this.infoList.size(); i++) { - this.infoList.get(i).begin -= removedItemsSize; - } - this.size -= removedItemsSize; - - // synchronize the cached list - Info info = this.infoList.get(componentLVMIndex); - int itemIndex = event.getIndex(); - info.items.subList(itemIndex, itemIndex + event.itemsSize()).clear(); - - // translate the event - this.fireItemsRemoved(event.cloneWithSource(this, LIST_VALUES, info.begin)); - } - - /** - * Items were replaced in one of the component lists; - * synchronize our cache. - */ - protected void componentItemsReplaced(ListChangeEvent event) { - // no changes to the 'begin' indices or size - - // synchronize the cached list - int componentLVMIndex = this.indexFor(event); - Info info = this.infoList.get(componentLVMIndex); - int i = event.getIndex(); - for (Iterator<E2> stream = this.componentItems(event); stream.hasNext(); ) { - info.items.set(i++, stream.next()); - } - - // translate the event - this.fireItemsReplaced(event.cloneWithSource(this, LIST_VALUES, info.begin)); - } - - /** - * Items were moved in one of the component lists; - * synchronize our cache. - */ - protected void componentItemsMoved(ListChangeEvent event) { - // no changes to the 'begin' indices or size - - // synchronize the cached list - int componentLVMIndex = this.indexFor(event); - Info info = this.infoList.get(componentLVMIndex); - CollectionTools.move(info.items, event.getTargetIndex(), event.getSourceIndex(), event.getMoveLength()); - - // translate the event - this.fireItemsMoved(event.cloneWithSource(this, LIST_VALUES, info.begin)); - } - - /** - * One of the component lists was cleared; - * synchronize our cache. - */ - protected void componentListCleared(ListChangeEvent event) { - int componentLVMIndex = this.indexFor(event); - this.clearComponentList(componentLVMIndex, this.infoList.get(componentLVMIndex)); - } - - protected void clearComponentList(int componentLVMIndex, Info info) { - // update the affected 'begin' indices - int removedItemsSize = info.items.size(); - for (int i = componentLVMIndex + 1; i < this.infoList.size(); i++) { - this.infoList.get(i).begin -= removedItemsSize; - } - this.size -= removedItemsSize; - - // synchronize the cached list - ArrayList<E2> items = new ArrayList<E2>(info.items); - info.items.clear(); - - // translate the event - this.fireItemsRemoved(LIST_VALUES, info.begin, items); - } - - /** - * One of the component lists changed; - * synchronize our cache by clearing out the appropriate - * list and rebuilding it. - */ - protected void componentListChanged(ListChangeEvent event) { - int componentLVMIndex = this.indexFor(event); - Info info = this.infoList.get(componentLVMIndex); - this.clearComponentList(componentLVMIndex, info); - - // update the affected 'begin' indices - int newItemsSize = info.componentLVM.size(); - for (int i = componentLVMIndex + 1; i < this.infoList.size(); i++) { - this.infoList.get(i).begin += newItemsSize; - } - this.size += newItemsSize; - - // synchronize the cached list - CollectionTools.addAll(info.items, info.componentLVM.listIterator(), newItemsSize); - - // translate the event - this.fireItemsAdded(LIST_VALUES, info.begin, info.items); - } - - // minimize scope of suppressed warnings - @SuppressWarnings("unchecked") - protected ListIterator<E2> componentItems(ListChangeEvent event) { - return (ListIterator<E2>) event.items(); - } - - // minimize scope of suppressed warnings - @SuppressWarnings("unchecked") - protected ListValueModel<E2> componentLVM(ListChangeEvent event) { - return (ListValueModel<E2>) event.getSource(); - } - -} |