Initial commit from SVN.
This commit is contained in:
@@ -0,0 +1,719 @@
|
||||
/*
|
||||
* Copyright (c) 2002,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.view.swt;
|
||||
|
||||
import com.common.util.*;
|
||||
import com.common.util.optimized.*;
|
||||
|
||||
/**
|
||||
* Used as a base class for collection components that are indexed.
|
||||
* Components such as a list of strings may be indexed such that objects from which the strings are derived cannot be attached to the row since there isn't the concept of a row.
|
||||
* This class tracks the mapping between the row value and the value's index in the collection to allow selections and updates to be converted to and from values and indices.
|
||||
*/
|
||||
public abstract class IndexedCollectionComponent extends CollectionComponent {
|
||||
/** A mapping of collection values by the control assigned indexes. */
|
||||
private IIndexedCollection valueByIndexMap = new LiteList(100);
|
||||
/** A mapping of control assigned indices by the collection values. Since the item can be in the collection more than once we will either store an Integer or an IntArray. */
|
||||
private LiteHashMap indexByValueMap = new LiteHashMap(100, com.common.comparison.Comparator.getLogicalComparator(), null);
|
||||
/**
|
||||
* IndexedCollectionComponent constructor.
|
||||
* @param parent The parent container.
|
||||
* @param name The name of the component.
|
||||
* @param style The style for the control.
|
||||
*/
|
||||
public IndexedCollectionComponent(Container parent, String name, int style) {
|
||||
super(parent, name, style);
|
||||
}//IndexedCollectionComponent()//
|
||||
/**
|
||||
* Gets the control specific data for a collection item.
|
||||
* @param item The item data which will eventually make it to the visual control.
|
||||
* @return The data for the item. This can be an array of values if necessary.
|
||||
*/
|
||||
protected abstract Object getItemData(Object item);
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.view.swt.CollectionComponent#updateHiddenData(java.lang.Object, int, java.lang.Object)
|
||||
*/
|
||||
protected void updateHiddenData(Object item, int hiddenDataIndex, Object value) {
|
||||
if(getAllowMultiSelection()) {
|
||||
boolean updateSelectionLinks = false;
|
||||
int[] selectedIndices = controlGetSelections();
|
||||
Object[] selectedValues = new Object[selectedIndices.length];
|
||||
|
||||
if((selectedIndices != null) && (selectedIndices.length > 0)) {
|
||||
//Determine whether any of the selections match with the hidden data's item to see whether we need to update any hidden data linkages.//
|
||||
for(int selectionIndex = 0; (!updateSelectionLinks) && (selectionIndex < selectedIndices.length); selectionIndex++) {
|
||||
Object selectionValue = valueByIndexMap.get(selectedIndices[selectionIndex]);
|
||||
|
||||
updateSelectionLinks = selectionValue == item;
|
||||
selectedValues[selectionIndex] = selectionValue;
|
||||
}//for//
|
||||
}//if//
|
||||
|
||||
if(updateSelectionLinks) {
|
||||
getHiddenData(hiddenDataIndex).invokeLinkage(selectedValues);
|
||||
}//if//
|
||||
}//if//
|
||||
else {
|
||||
int selectedIndex = controlGetSelection();
|
||||
|
||||
if(selectedIndex != -1) {
|
||||
Object selectedValue = valueByIndexMap.get(selectedIndex);
|
||||
|
||||
if(selectedValue == item) {
|
||||
getHiddenData(hiddenDataIndex).invokeLinkage(selectedValue);
|
||||
}//if//
|
||||
}//if//
|
||||
}//else//
|
||||
}//updateHiddenData()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.view.swt.CollectionComponent#updateSelectionLinks()
|
||||
*/
|
||||
protected void updateSelectionLinks() {
|
||||
super.updateSelectionLinks();
|
||||
|
||||
if(getHiddenDataCount() > 0) {
|
||||
if(getAllowMultiSelection()) {
|
||||
int[] selectedIndices = controlGetSelections();
|
||||
Object[] selectedValues = selectedIndices != null && selectedIndices.length > 0 ? new Object[selectedIndices.length] : null;
|
||||
|
||||
if(selectedValues != null) {
|
||||
//Collect the selected values.//
|
||||
for(int selectionIndex = 0; selectionIndex < selectedIndices.length; selectionIndex++) {
|
||||
selectedValues[selectionIndex] = valueByIndexMap.get(selectedIndices[selectionIndex]);
|
||||
}//for//
|
||||
}//if//
|
||||
|
||||
//Update the hidden data linkages.//
|
||||
for(int hiddenDataIndex = 0; hiddenDataIndex < getHiddenDataCount(); hiddenDataIndex++) {
|
||||
getHiddenData(hiddenDataIndex).invokeLinkage(selectedValues);
|
||||
}//for//
|
||||
}//if//
|
||||
else {
|
||||
int selectedIndex = controlGetSelection();
|
||||
Object selectedValue = selectedIndex != -1 ? valueByIndexMap.get(selectedIndex) : null;
|
||||
|
||||
//Update the hidden data linkages.//
|
||||
for(int hiddenDataIndex = 0; hiddenDataIndex < getHiddenDataCount(); hiddenDataIndex++) {
|
||||
getHiddenData(hiddenDataIndex).invokeLinkage(selectedValue);
|
||||
}//for//
|
||||
}//else//
|
||||
}//if//
|
||||
}//updateSelectionLinks()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.view.swt.CollectionComponent#internalViewRefreshCollection(com.common.util.ICollection, com.common.util.ICollection)
|
||||
*/
|
||||
protected void internalViewRefreshCollection(ICollection newCollection, ICollection oldCollection) {
|
||||
//TODO: Make this simpler - this is not at all as easy as the tcv code & is less useful.//
|
||||
if((newCollection != null) && (newCollection.getSize() > 0)) {
|
||||
Object[] items = new Object[newCollection.getSize()];
|
||||
IIterator iterator = newCollection.iterator();
|
||||
int removedCount = 0;
|
||||
|
||||
//Remove all index mappings so we reflect the latest collection ordering (in case the user wants the order to reflect a new collection order).//
|
||||
valueByIndexMap.removeAll();
|
||||
indexByValueMap.removeAll();
|
||||
|
||||
//Get the array of strings representing the list contents.//
|
||||
while(iterator.hasNext()) {
|
||||
Object value = iterator.next();
|
||||
|
||||
//Prevent two objects that are exactly the same from being added to the collection control.//
|
||||
if(indexByValueMap.containsKey(value)) {
|
||||
//Do nothing.//
|
||||
removedCount++;
|
||||
}//if//
|
||||
else {
|
||||
int valueIndex = addValueToMappings(value);
|
||||
|
||||
//Add the value to the item array.//
|
||||
items[valueIndex] = getItemData(value);
|
||||
}//else//
|
||||
}//while//
|
||||
|
||||
//Truncate the array so we don't have nulls at the end.//
|
||||
if(removedCount > 0) {
|
||||
Object[] newItems = new Object[items.length - removedCount];
|
||||
|
||||
System.arraycopy(items, 0, newItems, 0, newItems.length);
|
||||
items = newItems;
|
||||
}//if//
|
||||
|
||||
//Set the collection contents.//
|
||||
controlSetItems(items);
|
||||
}//if//
|
||||
else {
|
||||
//Remove all existing items.//
|
||||
controlRemoveAll();
|
||||
}//else//
|
||||
}//internalViewRefreshCollection()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.view.swt.CollectionComponent#internalViewRefreshSelection(java.lang.Object)
|
||||
*/
|
||||
protected void internalViewRefreshSelection(Object selectedItem) {
|
||||
//TODO: Make this simpler - this is not at all as easy as the tcv code & is less useful.//
|
||||
int selectionIndex = controlGetSelection();
|
||||
int modelSelectionIndex = -1;
|
||||
Object controlSelection = selectionIndex != -1 ? valueByIndexMap.get(selectionIndex) : null;
|
||||
Object indexData = selectedItem != null ? indexByValueMap.get(selectedItem) : null;
|
||||
|
||||
if(indexData == null) {
|
||||
modelSelectionIndex = -1;
|
||||
}//if//
|
||||
else if(indexData instanceof Integer) {
|
||||
modelSelectionIndex = ((Integer) indexData).intValue();
|
||||
}//else if//
|
||||
else {
|
||||
//Select the first one if the selection is not one of the possible ones.//
|
||||
if(!((IntArray) indexData).containsValue(modelSelectionIndex)) {
|
||||
modelSelectionIndex = ((IntArray) indexData).get(0); //Use the first occurance of the object.//
|
||||
}//if//
|
||||
}//else//
|
||||
|
||||
if((getAllowUserItems()) && (selectedItem != null) && (indexData == null)) {
|
||||
//Set a custom selection for the control (currently only supported for string values).//
|
||||
controlSetCustomItem(selectedItem);
|
||||
selectionIndex = -1;
|
||||
}//if//
|
||||
else if(controlSelection != selectedItem) {
|
||||
//Set the control selection.//
|
||||
controlSetSelection(modelSelectionIndex);
|
||||
}//else if//
|
||||
}//internalViewRefreshSelection()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.view.swt.CollectionComponent#internalViewRefreshSelections(com.common.util.ICollection, com.common.util.ICollection)
|
||||
*/
|
||||
protected void internalViewRefreshSelections(ICollection newSelections, ICollection oldSelections) {
|
||||
//TODO: Make this simpler - this is not at all as easy as the tcv code & is less useful.//
|
||||
if(newSelections != null) {
|
||||
int[] controlSelections = controlGetSelections();
|
||||
boolean[] markedSelections = new boolean[controlSelections.length];
|
||||
IIterator selectionIterator = newSelections.iterator();
|
||||
|
||||
for(int index = 0; index < markedSelections.length; index++) {
|
||||
markedSelections[index] = false;
|
||||
}//for//
|
||||
|
||||
//Apply differences between the selection collection and the control selection. Also remove all impossible selections.//
|
||||
while(selectionIterator.hasNext()) {
|
||||
Object modelSelection = selectionIterator.next();
|
||||
Object indexData = indexByValueMap.get(modelSelection);
|
||||
|
||||
if(indexData == null) {
|
||||
//An invalid selection because the selection is not in the collection of displayed values.//
|
||||
selectionIterator.remove();
|
||||
}//if//
|
||||
else if(indexData instanceof Integer) {
|
||||
int selectionIndex = ((Integer) indexData).intValue();
|
||||
|
||||
for(int index = 0; index < controlSelections.length; index++) {
|
||||
if(controlSelections[index] == selectionIndex) {
|
||||
if(!markedSelections[index]) {
|
||||
//The selection is already in the control.//
|
||||
markedSelections[index] = true;
|
||||
selectionIndex = -1;
|
||||
break;
|
||||
}//if//
|
||||
else {
|
||||
//Cannot have two of the same value selected if the value is only in the data collection once.//
|
||||
selectionIterator.remove();
|
||||
selectionIndex = -1;
|
||||
}//else//
|
||||
}//if//
|
||||
}//for//
|
||||
|
||||
//If we did not find the selected object in the array of currently selected indexes, then add it now.//
|
||||
if(selectionIndex != -1) {
|
||||
controlAddSelection(selectionIndex);
|
||||
}//if//
|
||||
}//else if//
|
||||
else {
|
||||
IntArray indices = (IntArray) indexData;
|
||||
boolean wasFound = false;
|
||||
|
||||
//This is a complex bit of code that must as best as possible identify whether the selection is already represented in the control.//
|
||||
for(int index = 0; index < controlSelections.length; index++) {
|
||||
//If the control selection is one of the indexes assigned to the selected object then check to see if we have already identified it as used.//
|
||||
if(indices.containsValue(controlSelections[index])) {
|
||||
if(!markedSelections[index]) {
|
||||
//The selection is already in the control and has not already been marked.//
|
||||
markedSelections[index] = true;
|
||||
wasFound = true;
|
||||
break;
|
||||
}//if//
|
||||
}//if//
|
||||
}//for//
|
||||
|
||||
//If we did not find the selected object in the array of currently selected indexes, then add it now.//
|
||||
if(!wasFound) {
|
||||
IIntIterator indicesIterator = indices.iterator();
|
||||
boolean wasAdded = false;
|
||||
|
||||
//Since we don't know exactly which one to add, we will have to search for one that is not selected.//
|
||||
//Note: We could seemingly do this faster by querying the control, but that would require a round trip query to the control which may be very expensive.//
|
||||
while((!wasAdded) && (indicesIterator.hasNext())) {
|
||||
int nextIndex = indicesIterator.next();
|
||||
|
||||
//Search the control selections for the next possible selection index.//
|
||||
for(int index = 0; index < controlSelections.length; index++) {
|
||||
if(nextIndex == controlSelections[index]) {
|
||||
nextIndex = -1;
|
||||
break;
|
||||
}//if//
|
||||
}//for//
|
||||
|
||||
//If the next possible selection index was not in the control's selection collection then we can add it.//
|
||||
if(nextIndex != -1) {
|
||||
controlAddSelection(nextIndex);
|
||||
wasAdded = true;
|
||||
}//if//
|
||||
}//while//
|
||||
|
||||
if(!wasAdded) {
|
||||
//Cannot have more references to a value in the selection collection than are in the data collection.//
|
||||
selectionIterator.remove();
|
||||
}//if//
|
||||
}//if//
|
||||
}//else//
|
||||
}//while//
|
||||
|
||||
//Remove all control selections that have not been marked. These selections were not represented in the model collection of selections.//
|
||||
for(int index = 0; index < markedSelections.length; index++) {
|
||||
if(!markedSelections[index]) {
|
||||
controlRemoveSelection(controlSelections[index]);
|
||||
}//if//
|
||||
}//for//
|
||||
}//if//
|
||||
else {
|
||||
//Remove all selections.//
|
||||
controlSetSelection(-1);
|
||||
}//else//
|
||||
}//internalViewRefreshSelections()//
|
||||
/**
|
||||
* Synchronizes the selection to the model from the view.
|
||||
* <p>This method has no logic to examine the auto synchronization state. It simply synchronizes the selection immediatly.</p>
|
||||
*/
|
||||
protected void synchronizeSelection() {
|
||||
if(getAllowMultiSelection()) {
|
||||
int[] controlSelectionIndices = controlGetSelections();
|
||||
ICollection modelSelections = getModelSelections();
|
||||
|
||||
//Prevent the selection additions from causing a feedback loop.//
|
||||
suspendSelectionHooks = true;
|
||||
|
||||
try {
|
||||
if(modelSelections != null) {
|
||||
Object[] controlSelectionObjects = new Object[controlSelectionIndices.length];
|
||||
boolean[] markedControlSelections = new boolean[controlSelectionObjects.length];
|
||||
IIterator modelSelectionIterator = modelSelections.iterator();
|
||||
LiteList removed = new LiteList(modelSelections.getSize());
|
||||
LiteList added = new LiteList(controlSelectionIndices.length);
|
||||
|
||||
for(int index = 0; index < controlSelectionIndices.length; index++) {
|
||||
controlSelectionObjects[index] = valueByIndexMap.get(controlSelectionIndices[index]);
|
||||
markedControlSelections[index] = false;
|
||||
}//for//
|
||||
|
||||
//Add selected items to the selection collection.//
|
||||
while(modelSelectionIterator.hasNext()) {
|
||||
Object modelSelection = modelSelectionIterator.next();
|
||||
boolean found = false;
|
||||
|
||||
for(int index = 0; (!found) && (index < markedControlSelections.length); index++) {
|
||||
if(!markedControlSelections[index]) {
|
||||
if(controlSelectionObjects[index] == modelSelection) {
|
||||
markedControlSelections[index] = true;
|
||||
found = true;
|
||||
}//if//
|
||||
}//if//
|
||||
}//for//
|
||||
|
||||
if(!found) {
|
||||
removed.add(modelSelection);
|
||||
}//if//
|
||||
}//while//
|
||||
|
||||
for(int index = 0; index < markedControlSelections.length; index++) {
|
||||
if(!markedControlSelections[index]) {
|
||||
added.add(controlSelectionObjects[index]);
|
||||
}//if//
|
||||
}//for//
|
||||
|
||||
modelSelections.replaceAll(removed, added);
|
||||
}//if//
|
||||
}//try//
|
||||
finally {
|
||||
suspendSelectionHooks = false;
|
||||
}//finally//
|
||||
}//if//
|
||||
else {
|
||||
int selectionIndex = controlGetSelection();
|
||||
Object controlSelection = selectionIndex != -1 ? valueByIndexMap.get(selectionIndex) : null;
|
||||
|
||||
if((getAllowUserItems()) && (selectionIndex == -1) && (controlGetText().length() > 0)) {
|
||||
setModelSelection(controlGetText());
|
||||
}//if//
|
||||
else {
|
||||
setModelSelection(controlSelection);
|
||||
}//else if//
|
||||
}//else//
|
||||
}//internalViewSynchronizeSelection()//
|
||||
/**
|
||||
* Gets the index (or indices) for the given item.
|
||||
* @param item The item whose index is required.
|
||||
* @return The index data for the item which will either be an Integer, an IntArray, or null if the item is not mapped.
|
||||
*/
|
||||
protected Object getItemIndexData(Object item) {
|
||||
return (item != null) && (indexByValueMap.containsKey(item)) ? indexByValueMap.get(item) : null;
|
||||
}//getItemIndexData()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.view.swt.CollectionComponent#itemAdded(java.lang.Object, int)
|
||||
*/
|
||||
protected void itemAdded(Object item, int index) {
|
||||
//Setup a mapping and a new index for the value.//
|
||||
index = addValueToMappings(item);
|
||||
//Add the value to the control.//
|
||||
controlAddItem(getItemData(item), index);
|
||||
|
||||
//TODO: Should this be allowed? If the user sets the selection to an object not in the collection, should we prevent it? What about controls like a combobox which allow custom input?//
|
||||
if((!getAllowMultiSelection()) && (getModelSelection() == item)) {
|
||||
controlSetSelection(index);
|
||||
}//if//
|
||||
}//itemAdded()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.view.swt.CollectionComponent#itemRemoved(java.lang.Object, int)
|
||||
*/
|
||||
protected void itemRemoved(Object item, int index) {
|
||||
if(indexByValueMap.containsKey(item)) {
|
||||
Object indexData = indexByValueMap.get(item);
|
||||
int modelIndex;
|
||||
|
||||
//Determine whether the removed object occurs more than once in the collection.//
|
||||
if(indexData instanceof Integer) {
|
||||
modelIndex = ((Integer) indexData).intValue();
|
||||
//Remove the item from the control and unregister all event handlers.//
|
||||
controlRemoveItem(modelIndex);
|
||||
}//if//
|
||||
else {
|
||||
IntArray indices = (IntArray) indexData;
|
||||
//TODO: We could make things look better by removing the selected object when there are more than one possible objects to be removed.//
|
||||
//Assume that we should remove the last occurance of the object.//
|
||||
modelIndex = indices.get(indices.getSize() - 1);
|
||||
//Remove the item from the control.//
|
||||
controlRemoveItem(modelIndex);
|
||||
}//else//
|
||||
|
||||
//Remove the object from the mappings.//
|
||||
removeValueFromMappings(item, modelIndex);
|
||||
}//if//
|
||||
}//itemRemoved()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.view.swt.CollectionComponent#itemAllRemoved()
|
||||
*/
|
||||
protected void itemAllRemoved() {
|
||||
//Remove all index mappings so we reflect the latest collection ordering (in case the user wants the order to reflect a new collection order).//
|
||||
valueByIndexMap.removeAll();
|
||||
indexByValueMap.removeAll();
|
||||
//Remove all existing items.//
|
||||
controlRemoveAll();
|
||||
}//itemAllRemoved()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.view.swt.CollectionComponent#registerItem(java.lang.Object)
|
||||
*/
|
||||
protected void registerItem(Object item) {
|
||||
internalItemAdded(item);
|
||||
}//registerItem()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.view.swt.CollectionComponent#unregisterItem(java.lang.Object)
|
||||
*/
|
||||
protected void unregisterItem(Object item) {
|
||||
internalItemRemoved(item);
|
||||
}//unregisterItem()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.view.swt.CollectionComponent#unregisterItems()
|
||||
*/
|
||||
protected void unregisterItems() {
|
||||
internalItemsRemoved();
|
||||
}//unregisterItems()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.view.swt.CollectionComponent#itemSorted(int[])
|
||||
*/
|
||||
protected void itemSorted(int[] mapping) {
|
||||
//TODO: Re-order the indicies in the control and rebuild the mappings.//
|
||||
}//itemSorted()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.view.swt.CollectionComponent#selectionAdded(java.lang.Object)
|
||||
*/
|
||||
protected void selectionAdded(Object value) {
|
||||
checkObjectSelectionCount(value);
|
||||
}//selectionAdded()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.view.swt.CollectionComponent#selectionRemoved(java.lang.Object)
|
||||
*/
|
||||
protected void selectionRemoved(Object value) {
|
||||
checkObjectSelectionCount(value);
|
||||
}//selectionRemoved()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.view.swt.CollectionComponent#selectionAllRemoved()
|
||||
*/
|
||||
protected void selectionAllRemoved() {
|
||||
controlRemoveAllSelections();
|
||||
}//selectionAllRemoved()//
|
||||
/**
|
||||
* Verifies that the correct number of selections for the given value exist in the control.
|
||||
* @param value The value that is being checked. It may be checked because a selection was added, or removed.
|
||||
*/
|
||||
protected void checkObjectSelectionCount(Object value) {
|
||||
if(!getAllowMultiSelection()) {
|
||||
throw new RuntimeException("Cannot call this method: 'checkObjectSelectionCount' if multiple selections are not allowed.");
|
||||
}//if//
|
||||
|
||||
if(indexByValueMap.containsKey(value)) {
|
||||
int[] controlSelectionIndices = controlGetSelections();
|
||||
Object indexData = indexByValueMap.get(value);
|
||||
int possibleCount = indexData == null ? 0 : indexData instanceof Integer ? 1 : ((IntArray) indexData).getSize();
|
||||
int modelCount = 0;
|
||||
IIterator iterator = getModelSelections().iterator();
|
||||
|
||||
//Count the number of times the object is in the model's selection collection. Remove impossible references.//
|
||||
while(iterator.hasNext()) {
|
||||
if(iterator.next() == value) {
|
||||
modelCount++;
|
||||
|
||||
//Fix impossible selections.//
|
||||
if(modelCount > possibleCount) {
|
||||
modelCount = possibleCount;
|
||||
iterator.remove();
|
||||
}//if//
|
||||
}//if//
|
||||
}//while//
|
||||
|
||||
//Count the number of times the object is selected in the control's selections. Remove or add selections to match the model's selection collection.//
|
||||
if(indexData instanceof Integer) {
|
||||
int valueIndex = ((Integer) indexData).intValue();
|
||||
int controlCount = 0;
|
||||
|
||||
for(int index = 0; index < controlSelectionIndices.length; index++) {
|
||||
if(controlSelectionIndices[index] == valueIndex) {
|
||||
controlCount++;
|
||||
|
||||
if(controlCount > modelCount) {
|
||||
controlRemoveSelection(valueIndex);
|
||||
}//if//
|
||||
|
||||
//Stop iterating since there can only be one selection for this object.//
|
||||
break;
|
||||
}//if//
|
||||
}//for//
|
||||
|
||||
if(controlCount < modelCount) {
|
||||
controlAddSelection(valueIndex);
|
||||
}//if//
|
||||
}//if//
|
||||
else {
|
||||
int controlCount = 0;
|
||||
IntArray valueIndices = new IntArray((IntArray) indexData); //Copy the object indices so we can remove the ones we already have used.//
|
||||
|
||||
for(int index = 0; index < controlSelectionIndices.length; index++) {
|
||||
Object controlSelectionValue = valueByIndexMap.get(controlSelectionIndices[index]);
|
||||
|
||||
if(controlSelectionValue == value) {
|
||||
controlCount++;
|
||||
|
||||
if(controlCount > modelCount) {
|
||||
//Remove the selection because there are too many.//
|
||||
controlRemoveSelection(controlSelectionIndices[index]);
|
||||
}//if//
|
||||
else {
|
||||
//Remove used object indexes so it is easy to add more references if they are required.//
|
||||
valueIndices.remove(valueIndices.getIndexOf(controlSelectionIndices[index]));
|
||||
}//else//
|
||||
}//if//
|
||||
}//for//
|
||||
|
||||
//Add selections for the object until the counts match.//
|
||||
while(controlCount < modelCount) {
|
||||
controlAddSelection(valueIndices.get(valueIndices.getSize()));
|
||||
valueIndices.remove(valueIndices.getSize());
|
||||
controlCount++;
|
||||
}//while//
|
||||
}//else//
|
||||
}//if//
|
||||
}//checkObjectCount()//
|
||||
/**
|
||||
* Removes a value from the mappings of values and internal indexes.
|
||||
* <p>Note: The current implementation is very fast, except when removing items from a very large collection of values. This performance problem is due to the need to clean the object->index mapping after each removal.</p>
|
||||
* @param removedValue The value removed from the collection being displayed.
|
||||
* @param removedIndex The index of the removed value. This is necessary because a value could be in the collection more than one time.
|
||||
*/
|
||||
protected void removeValueFromMappings(Object removedValue, int removedIndex) {
|
||||
if(indexByValueMap.containsKey(removedValue)) {
|
||||
Object indexData = indexByValueMap.get(removedValue);
|
||||
IIterator iterator = indexByValueMap.keyIterator();
|
||||
|
||||
if(indexData instanceof IntArray) {
|
||||
IntArray indices = (IntArray) indexData;
|
||||
|
||||
//Remove the specified index from the array of indices.//
|
||||
indices.remove(indices.getIndexOf(removedIndex));
|
||||
|
||||
//Optimize things by only using an IntArray when necessary.//
|
||||
if(indices.getSize() == 1) {
|
||||
indexByValueMap.put(removedValue, new Integer(indices.get(0)));
|
||||
}//if//
|
||||
}//if//
|
||||
else {
|
||||
//Since there should be no other occurances of the object in the collection we can remove the mapping altogether.//
|
||||
indexByValueMap.remove(removedValue);
|
||||
}//else//
|
||||
|
||||
valueByIndexMap.remove(removedIndex);
|
||||
|
||||
while(iterator.hasNext()) {
|
||||
Object next = iterator.next();
|
||||
|
||||
indexData = indexByValueMap.get(next);
|
||||
|
||||
if(indexData instanceof Integer) {
|
||||
if(((Integer) indexData).intValue() > removedIndex) {
|
||||
indexByValueMap.put(next, new Integer(((Integer) indexData).intValue() - 1));
|
||||
}//if//
|
||||
}//if//
|
||||
else {
|
||||
IntArray indices = (IntArray) indexData;
|
||||
|
||||
//TODO: For large collections where items may be regularly removed we may wish to create a special collection that maintains the object to index mappings. We could use the bucket approach to maintaining the index number.//
|
||||
for(int index = indices.getSize() - 1; (index >= 0) && (indices.get(index) > removedIndex); index--) {
|
||||
indices.replace(index, indices.get(index) - 1);
|
||||
}//for//
|
||||
}//else//
|
||||
}//while//
|
||||
}//if//
|
||||
}//removeValueFromMappings()//
|
||||
/**
|
||||
* Adds a value to the mappings of values and internal indexes.
|
||||
* @param addedValue The value added to the collection being displayed.
|
||||
* @return The internal index of the added value.
|
||||
*/
|
||||
protected int addValueToMappings(Object addedValue) {
|
||||
int index = valueByIndexMap.getSize();
|
||||
|
||||
//Always add the value to the indexed mapping.//
|
||||
valueByIndexMap.add(addedValue);
|
||||
|
||||
//Either add the index to the index by value map, or add it to a collection indexed by the object if the object is in the collection more than once.//
|
||||
if(!indexByValueMap.containsKey(addedValue)) {
|
||||
//Add the index to the mappings.//
|
||||
indexByValueMap.put(addedValue, new Integer(index));
|
||||
}//if//
|
||||
else {
|
||||
Object indexData = indexByValueMap.get(addedValue);
|
||||
|
||||
if(indexData instanceof Integer) {
|
||||
IntArray indices = new IntArray(10, 30);
|
||||
|
||||
//Create a collection of indices for the same object.//
|
||||
indices.add(((Integer) indexData).intValue());
|
||||
indices.add(index);
|
||||
indexByValueMap.put(addedValue, indices);
|
||||
}//if//
|
||||
else {
|
||||
//Add the new index to the collection of indices where this same object can be found in the control's list.//
|
||||
((IntArray) indexData).add(index);
|
||||
}//else//
|
||||
}//else//
|
||||
|
||||
return index;
|
||||
}//addValueToMappings()//
|
||||
/**
|
||||
* Removes all displayed items from the control.
|
||||
*/
|
||||
protected abstract void controlRemoveAll();
|
||||
/**
|
||||
* Sets the control's displayed collection values ordered by index.
|
||||
* @param items The indexed values displayed by the control.
|
||||
*/
|
||||
protected abstract void controlSetItems(Object[] items);
|
||||
/**
|
||||
* Sets an item in the control's collection display.
|
||||
* @param index The index at which the item should be set.
|
||||
* @param itemData The value displayed by the control.
|
||||
*/
|
||||
protected abstract void controlSetItem(int index, Object itemData);
|
||||
/**
|
||||
* Adds an item to the control's collection display.
|
||||
* @param itemData The value displayed by the control.
|
||||
* @param index The index at which the item should be added.
|
||||
*/
|
||||
protected abstract void controlAddItem(Object itemData, int index);
|
||||
/**
|
||||
* Adds an item to the control's collection at the end.
|
||||
* @param itemData The value displayed by the control.
|
||||
*/
|
||||
protected abstract void controlAddItem(Object itemData);
|
||||
/**
|
||||
* Removes an item from the control's collection display.
|
||||
* @param index The index of the item to be removed.
|
||||
*/
|
||||
protected abstract void controlRemoveItem(int index);
|
||||
/**
|
||||
* Gets the indices selected within the control.
|
||||
* @return The collection of indices selected.
|
||||
*/
|
||||
protected abstract int[] controlGetSelections();
|
||||
/**
|
||||
* Gets the index selected within the control.
|
||||
* @return The index currently selected.
|
||||
*/
|
||||
protected abstract int controlGetSelection();
|
||||
/**
|
||||
* Sets the selected values in the control.
|
||||
* @param indices The indices of the selected values.
|
||||
*/
|
||||
protected abstract void controlSetSelections(int[] indices);
|
||||
/**
|
||||
* Sets the selected value in the control.
|
||||
* @param index The index of the selected value.
|
||||
*/
|
||||
protected abstract void controlSetSelection(int index);
|
||||
/**
|
||||
* Adds a selected value in the control.
|
||||
* @param index The index of the selected value.
|
||||
*/
|
||||
protected abstract void controlAddSelection(int index);
|
||||
/**
|
||||
* Deselects a value in the control.
|
||||
* @param index The index of the selected value.
|
||||
*/
|
||||
protected abstract void controlRemoveSelection(int index);
|
||||
/**
|
||||
* Deselects all values in the control.
|
||||
*/
|
||||
protected abstract void controlRemoveAllSelections();
|
||||
/**
|
||||
* Checks to see if a value is selected.
|
||||
* @param index The index of the checked value.
|
||||
* @return Whether the value is currently selected.
|
||||
*/
|
||||
protected abstract boolean controlIsSelected(int index);
|
||||
/**
|
||||
* Gets the current text for the control.
|
||||
* <p>Some controls such as comboboxes have a text which may not be one of the listed items.</p>
|
||||
* @return The control's current text.
|
||||
*/
|
||||
protected abstract String controlGetText();
|
||||
/**
|
||||
* Sets the current custom selection item for the control.
|
||||
* <p>Some controls such as comboboxes have a text which may not be one of the listed items.</p>
|
||||
* @param item The controls custom selected item.
|
||||
*/
|
||||
protected abstract void controlSetCustomItem(Object item);
|
||||
/**
|
||||
* Forces the selection event handler to be called.
|
||||
*/
|
||||
protected abstract void forceSelectionEvent(); //TODO: Should call widgetSelected implemented by the subclass. This name may need to change.//
|
||||
}//IndexedCollectionComponent//
|
||||
Reference in New Issue
Block a user