558 lines
21 KiB
Java
558 lines
21 KiB
Java
|
|
/*
|
||
|
|
* Copyright (c) 2003,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.tcv.swt.client;
|
||
|
|
|
||
|
|
import com.common.comparison.Comparator;
|
||
|
|
import com.common.util.IIterator;
|
||
|
|
import com.common.util.IList;
|
||
|
|
import com.common.util.LiteList;
|
||
|
|
import com.common.util.optimized.IIntIterator;
|
||
|
|
import com.common.util.optimized.IntObjectHashMap;
|
||
|
|
import com.foundation.tcv.model.LinkInfo;
|
||
|
|
import com.foundation.tcv.swt.*;
|
||
|
|
import com.foundation.tcv.swt.client.cell.CellComponent;
|
||
|
|
import com.foundation.tcv.view.*;
|
||
|
|
import com.foundation.view.LinkData;
|
||
|
|
|
||
|
|
public abstract class CollectionComponent extends ScrollableComponent implements ICollectionComponent, ICellContainer {
|
||
|
|
/** The only invalid value for an object identifier. */
|
||
|
|
protected static final int INVALID_OBJECT_ID = -1;
|
||
|
|
/** Used by the hidden data to identify when the previous value has not yet been assigned a value. */
|
||
|
|
protected static final Object UNSET_VALUE = new Object();
|
||
|
|
|
||
|
|
/** Whether the user can type a custom selection. If this is true and the selection attribute is not a String type then the user input must match a list item's text. */
|
||
|
|
private boolean allowUserItems = false;
|
||
|
|
/** Whether the user is allowed to make multiple selections. */
|
||
|
|
private boolean allowMultiSelection = false;
|
||
|
|
/** Whether the selection should be automatically sent to the model. */
|
||
|
|
private boolean autoSynchronizeSelection = false;
|
||
|
|
/** The number of milliseconds of delay before auto synchronizing the selection. */
|
||
|
|
private long autoSynchronizeSelectionDelay = 500;
|
||
|
|
/** The task that auto synchronizes the selection after a short delay. */
|
||
|
|
protected Task autoSynchronizeSelectionTask = null;
|
||
|
|
/** Whether to send the double click events to the server for processing. */
|
||
|
|
private boolean sendDoubleClick = false;
|
||
|
|
/** The collection of HiddenData instances, one for each hidden data holder. */
|
||
|
|
private IList hiddenDataSets = new LiteList(10, 20);
|
||
|
|
/** Maps the row objects by their unique object identifiers. */
|
||
|
|
private IntObjectHashMap rowObjectByObjectIdMap = new IntObjectHashMap(100, 200);
|
||
|
|
/** The linkage for the selection related value. */
|
||
|
|
private Linkage selectionLinkage = new Linkage();
|
||
|
|
/** The collection of cell components. */
|
||
|
|
private LiteList cellComponents = null;
|
||
|
|
/** The count of calls to preChangeCollection(). Incremented for each call to preChangeCollection(), decremented for each call to postChangeCollection(). This counter determines when to call internalPostChangeCollection(). */
|
||
|
|
private int preChangeCollectionCounter = 0;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* The base class for the different types of hidden data.
|
||
|
|
* Hidden data is used by the collection to activate linkages without going through the controllers or models.
|
||
|
|
* Each object in the collection will then be assigned a value for each hidden data and the selection determines the value assigned to the linkages.
|
||
|
|
*/
|
||
|
|
protected class HiddenData {
|
||
|
|
/** The zero based index of the hidden data. This identifies the hidden data that generates events. */
|
||
|
|
private int hiddenDataIndex;
|
||
|
|
/** The previous selection related value for this hidden data. This allows linkages to be activated only when the value is altered. */
|
||
|
|
private Object previousValue = UNSET_VALUE;
|
||
|
|
/** The linkage for the selection related value. */
|
||
|
|
private Linkage linkage = new Linkage();
|
||
|
|
/** The multi-selection options for the hidden data. */
|
||
|
|
private int multiSelectionOption = MULTI_SELECTION_OPTION_DEFAULT;
|
||
|
|
/** The default value for the hidden data. */
|
||
|
|
private Object defaultValue = null;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* HiddenData constructor.
|
||
|
|
* @param hiddenDataIndex The index in the hidden data set.
|
||
|
|
*/
|
||
|
|
protected HiddenData(int hiddenDataIndex) {
|
||
|
|
this.hiddenDataIndex = hiddenDataIndex;
|
||
|
|
}//HiddenData()//
|
||
|
|
/**
|
||
|
|
* Adds a link associated with the collection's selection's hidden data value.
|
||
|
|
* @param link The local linkage for the selection related data.
|
||
|
|
*/
|
||
|
|
public void addLink(LinkData link) {
|
||
|
|
linkage.add(link);
|
||
|
|
}//addLink()//
|
||
|
|
/**
|
||
|
|
* Invokes the linkage with the given value.
|
||
|
|
* @param value The last value for the selection and this hidden data.
|
||
|
|
*/
|
||
|
|
public void invokeLinkage(RowObject[] selections) {
|
||
|
|
Object value = null;
|
||
|
|
|
||
|
|
if((selections == null) || (selections.length == 0) || (multiSelectionOption == MULTI_SELECTION_OPTION_DEFAULT)) {
|
||
|
|
value = defaultValue;
|
||
|
|
}//if//
|
||
|
|
else {
|
||
|
|
value = selections[0].hiddenData[hiddenDataIndex];
|
||
|
|
|
||
|
|
for(int index = 1; index < selections.length; index++) {
|
||
|
|
Object next = selections[index].hiddenData[hiddenDataIndex];
|
||
|
|
|
||
|
|
switch(multiSelectionOption) {
|
||
|
|
case MULTI_SELECTION_OPTION_COMMON: {
|
||
|
|
//If the values are not comparable then use the default value for the linkage and exit the loop.//
|
||
|
|
if(!Comparator.equals(next, value)) {
|
||
|
|
value = defaultValue;
|
||
|
|
index = selections.length;
|
||
|
|
}//if//
|
||
|
|
break;
|
||
|
|
}//case//
|
||
|
|
case MULTI_SELECTION_OPTION_AND: {
|
||
|
|
if((next instanceof Boolean) && (value instanceof Boolean)) {
|
||
|
|
value = ((Boolean) next).booleanValue() && ((Boolean) value).booleanValue() ? Boolean.TRUE : Boolean.FALSE;
|
||
|
|
}//if//
|
||
|
|
//TODO: What should we do if they are not booleans? For now we will ignore this since a view building tool would prevent the possibility.
|
||
|
|
break;
|
||
|
|
}//case//
|
||
|
|
case MULTI_SELECTION_OPTION_OR: {
|
||
|
|
if((next instanceof Boolean) && (value instanceof Boolean)) {
|
||
|
|
value = ((Boolean) next).booleanValue() || ((Boolean) value).booleanValue() ? Boolean.TRUE : Boolean.FALSE;
|
||
|
|
}//if//
|
||
|
|
//TODO: What should we do if they are not booleans? For now we will ignore this since a view building tool would prevent the possibility.
|
||
|
|
break;
|
||
|
|
}//case//
|
||
|
|
}//switch//
|
||
|
|
}//for//
|
||
|
|
}//else//
|
||
|
|
|
||
|
|
if(!Comparator.equals(value, previousValue)) {
|
||
|
|
previousValue = value;
|
||
|
|
linkage.invoke(value);
|
||
|
|
}//if//
|
||
|
|
}//invokeLinkage()//
|
||
|
|
/**
|
||
|
|
* Invokes the linkage with the given value.
|
||
|
|
* @param value The last value for the selection and this hidden data.
|
||
|
|
*/
|
||
|
|
public void invokeLinkage(RowObject selection) {
|
||
|
|
Object value = selection != null ? selection.hiddenData[hiddenDataIndex] : defaultValue;
|
||
|
|
|
||
|
|
if(!Comparator.equals(value, previousValue)) {
|
||
|
|
previousValue = value;
|
||
|
|
linkage.invoke(value);
|
||
|
|
}//if//
|
||
|
|
}//invokeLinkage()//
|
||
|
|
/**
|
||
|
|
* Gets the index for the hidden data.
|
||
|
|
* @return The zero based index identifying the hidden data.
|
||
|
|
*/
|
||
|
|
public int getHiddenDataIndex() {
|
||
|
|
return hiddenDataIndex;
|
||
|
|
}//getHiddenDataIndex()//
|
||
|
|
}//HiddenData//
|
||
|
|
/**
|
||
|
|
* CollectionComponent constructor.
|
||
|
|
*/
|
||
|
|
public CollectionComponent() {
|
||
|
|
super();
|
||
|
|
}//CollectionComponent()//
|
||
|
|
/* (non-Javadoc)
|
||
|
|
* @see com.foundation.tcv.swt.client.ICellContainer#addCellComponent(com.foundation.tcv.swt.client.cell.CellComponent)
|
||
|
|
*/
|
||
|
|
public void addCellComponent(CellComponent component) {
|
||
|
|
if(cellComponents == null) {
|
||
|
|
cellComponents = new LiteList(10, 20);
|
||
|
|
}//if//
|
||
|
|
|
||
|
|
cellComponents.add(component);
|
||
|
|
|
||
|
|
if(isInitialized()) {
|
||
|
|
((AbstractComponent) component).internalViewInitializeAll();
|
||
|
|
}//if//
|
||
|
|
}//addCellComponent()//
|
||
|
|
/**
|
||
|
|
* Gets the collection of cell components for this container.
|
||
|
|
* @return The cell components contained within this container.
|
||
|
|
*/
|
||
|
|
public IList getCellComponents() {
|
||
|
|
return cellComponents == null ? LiteList.EMPTY_LIST : cellComponents;
|
||
|
|
}//getCellComponents()//
|
||
|
|
/**
|
||
|
|
* Gets the SWT composite that represents this collection component.
|
||
|
|
* @return The SWT composite providing visualization for this collection component.
|
||
|
|
*/
|
||
|
|
public org.eclipse.swt.widgets.Composite getSwtComposite() {
|
||
|
|
return (org.eclipse.swt.widgets.Composite) getSwtWidget();
|
||
|
|
}//getSwtComposite()//
|
||
|
|
/* (non-Javadoc)
|
||
|
|
* @see com.foundation.tcv.swt.client.ICellContainer#getSwtComposite(com.foundation.tcv.swt.client.RowObject)
|
||
|
|
*/
|
||
|
|
public org.eclipse.swt.widgets.Composite getSwtComposite(RowObject rowObject) {
|
||
|
|
return getSwtComposite();
|
||
|
|
}//getSwtComposite()//
|
||
|
|
/* (non-Javadoc)
|
||
|
|
* @see com.foundation.tcv.swt.client.Component#internalViewInitializeAll()
|
||
|
|
*/
|
||
|
|
protected void internalViewInitializeAll() {
|
||
|
|
super.internalViewInitializeAll();
|
||
|
|
|
||
|
|
if(cellComponents != null) {
|
||
|
|
for(int index = 0; index < cellComponents.getSize(); index++) {
|
||
|
|
((AbstractComponent) cellComponents.get(index)).internalViewInitializeAll();
|
||
|
|
}//for//
|
||
|
|
}//if//
|
||
|
|
}//internalViewInitializeAll()//
|
||
|
|
/* (non-Javadoc)
|
||
|
|
* @see com.foundation.tcv.swt.client.Component#internalViewReleaseAll()
|
||
|
|
*/
|
||
|
|
protected void internalViewReleaseAll() {
|
||
|
|
super.internalViewReleaseAll();
|
||
|
|
|
||
|
|
if(cellComponents != null) {
|
||
|
|
for(int index = 0; index < cellComponents.getSize(); index++) {
|
||
|
|
((AbstractComponent) cellComponents.get(index)).internalViewReleaseAll();
|
||
|
|
}//for//
|
||
|
|
}//if//
|
||
|
|
}//internalViewReleaseAll()//
|
||
|
|
/* (non-Javadoc)
|
||
|
|
* @see com.foundation.tcv.swt.client.Component#internalViewSynchronizeAll()
|
||
|
|
*/
|
||
|
|
protected void internalViewSynchronizeAll() {
|
||
|
|
super.internalViewSynchronizeAll();
|
||
|
|
|
||
|
|
if(cellComponents != null) {
|
||
|
|
for(int index = 0; index < cellComponents.getSize(); index++) {
|
||
|
|
((AbstractComponent) cellComponents.get(index)).internalViewSynchronizeAll();
|
||
|
|
}//for//
|
||
|
|
}//if//
|
||
|
|
}//internalViewSynchronizeAll()//
|
||
|
|
/* (non-Javadoc)
|
||
|
|
* @see com.foundation.tcv.swt.client.AbstractComponent#internalViewSynchronize()
|
||
|
|
*/
|
||
|
|
protected void internalViewSynchronize() {
|
||
|
|
super.internalViewSynchronize();
|
||
|
|
internalViewSynchronizeSelection();
|
||
|
|
}//internalViewSynchronize()//
|
||
|
|
/**
|
||
|
|
* Synchronizes the selection when requested by the view controller.
|
||
|
|
*/
|
||
|
|
protected void internalViewSynchronizeSelection() {
|
||
|
|
if(!getAutoSynchronizeSelection()) {
|
||
|
|
synchronizeSelection();
|
||
|
|
}//if//
|
||
|
|
else {
|
||
|
|
synchronized(this) {
|
||
|
|
if(autoSynchronizeSelectionTask != null) {
|
||
|
|
removeTask(autoSynchronizeSelectionTask);
|
||
|
|
autoSynchronizeSelectionTask.execute();
|
||
|
|
}//if//
|
||
|
|
}//synchronized//
|
||
|
|
}//else//
|
||
|
|
}//internalViewSynchronizeSelection()//
|
||
|
|
/**
|
||
|
|
* Synchronizes the selection when the user interacts with the collection.
|
||
|
|
*/
|
||
|
|
protected abstract void synchronizeSelection();
|
||
|
|
/* (non-Javadoc)
|
||
|
|
* @see com.foundation.tcv.swt.client.Component#internalViewInitialize()
|
||
|
|
*/
|
||
|
|
protected void internalViewInitialize() {
|
||
|
|
super.internalViewInitialize();
|
||
|
|
}//internalViewInitialize()//
|
||
|
|
/* (non-Javadoc)
|
||
|
|
* @see com.foundation.tcv.swt.client.AbstractComponent#internalViewRelease()
|
||
|
|
*/
|
||
|
|
protected void internalViewRelease() {
|
||
|
|
synchronized(this) {
|
||
|
|
if(autoSynchronizeSelectionTask != null) {
|
||
|
|
removeTask(autoSynchronizeSelectionTask);
|
||
|
|
autoSynchronizeSelectionTask = null;
|
||
|
|
}//if//
|
||
|
|
}//synchronized//
|
||
|
|
|
||
|
|
super.internalViewRelease();
|
||
|
|
}//internalViewRelease()//
|
||
|
|
/* (non-Javadoc)
|
||
|
|
* @see com.foundation.tcv.swt.client.AbstractComponent#internalProcessMessage(com.foundation.tcv.model.ViewMessage)
|
||
|
|
*/
|
||
|
|
public Object internalProcessMessage(ViewMessage viewMessage) {
|
||
|
|
Object result = null;
|
||
|
|
|
||
|
|
switch(viewMessage.getMessageNumber()) {
|
||
|
|
case MESSAGE_SET_AUTO_SYNCHRONIZE_SELECTION: {
|
||
|
|
autoSynchronizeSelection = ((Boolean) viewMessage.getMessageData()).booleanValue();
|
||
|
|
break;
|
||
|
|
}//case//
|
||
|
|
case MESSAGE_SET_AUTO_SYNCHRONIZE_SELECTION_DELAY: {
|
||
|
|
autoSynchronizeSelectionDelay = ((Long) viewMessage.getMessageData()).longValue();
|
||
|
|
break;
|
||
|
|
}//case//
|
||
|
|
case MESSAGE_SEND_DOUBLE_CLICK: {
|
||
|
|
sendDoubleClick = ((Boolean) viewMessage.getMessageData()).booleanValue();
|
||
|
|
break;
|
||
|
|
}//case//
|
||
|
|
case MESSAGE_ADD_HIDDEN_DATA: {
|
||
|
|
hiddenDataSets.add(createHiddenData(hiddenDataSets.getSize()));
|
||
|
|
break;
|
||
|
|
}//case//
|
||
|
|
case MESSAGE_ADD_HIDDEN_DATA_LINK: {
|
||
|
|
HiddenData hiddenData = (HiddenData) hiddenDataSets.get(viewMessage.getMessageInteger());
|
||
|
|
LinkInfo info = (LinkInfo) viewMessage.getMessageData();
|
||
|
|
|
||
|
|
hiddenData.linkage.add(new LinkData(getComponent(info.getComponent()), info.getTarget(), info.getData(), info.isBoolean(), info.invertLogic(), info.nullValue()));
|
||
|
|
break;
|
||
|
|
}//case//
|
||
|
|
case MESSAGE_UPDATE_HIDDEN_DATA_DEFAULT_VALUE: {
|
||
|
|
HiddenData hiddenData = (HiddenData) hiddenDataSets.get(viewMessage.getMessageInteger());
|
||
|
|
Object defaultValue = viewMessage.getMessageData();
|
||
|
|
|
||
|
|
hiddenData.defaultValue = defaultValue;
|
||
|
|
|
||
|
|
if(isInitialized()) {
|
||
|
|
updateSelectionLinks();
|
||
|
|
}//if//
|
||
|
|
break;
|
||
|
|
}//case//
|
||
|
|
case MESSAGE_UPDATE_HIDDEN_DATA: {
|
||
|
|
Object[] data = (Object[]) viewMessage.getMessageData();
|
||
|
|
int objectId = ((Integer) data[0]).intValue();
|
||
|
|
int hiddenDataIndex = ((Integer) data[1]).intValue();
|
||
|
|
Object hiddenData = data[2];
|
||
|
|
|
||
|
|
updateHiddenData(getRowObject(objectId), hiddenDataIndex, hiddenData);
|
||
|
|
break;
|
||
|
|
}//case//
|
||
|
|
case MESSAGE_ADD_SELECTION_LINK: {
|
||
|
|
LinkInfo info = (LinkInfo) viewMessage.getMessageData();
|
||
|
|
|
||
|
|
selectionLinkage.add(new LinkData(getComponent(info.getComponent()), info.getTarget(), info.getData(), info.invertLogic()));
|
||
|
|
break;
|
||
|
|
}//case//
|
||
|
|
case MESSAGE_PRE_CHANGE_COLLECTION: {
|
||
|
|
preChangeCollection();
|
||
|
|
break;
|
||
|
|
}//case//
|
||
|
|
case MESSAGE_POST_CHANGE_COLLECTION: {
|
||
|
|
postChangeCollection();
|
||
|
|
break;
|
||
|
|
}//case//
|
||
|
|
default: {
|
||
|
|
result = super.internalProcessMessage(viewMessage);
|
||
|
|
}//default//
|
||
|
|
}//switch//
|
||
|
|
|
||
|
|
return result;
|
||
|
|
}//internalProcessMessage()//
|
||
|
|
/**
|
||
|
|
* Determines whether the control allows the user to type in custom items (combobox).
|
||
|
|
* @return Whether users will be allowed to type in a custom value.
|
||
|
|
*/
|
||
|
|
protected boolean getAllowUserItems() {
|
||
|
|
return allowUserItems;
|
||
|
|
}//getAllowUserItems()//
|
||
|
|
/**
|
||
|
|
* Determines whether the control allows the user to type in custom items (combobox).
|
||
|
|
* @param allowUserItems Whether users will be allowed to type in a custom value.
|
||
|
|
*/
|
||
|
|
protected void setAllowUserItems(boolean allowUserItems) {
|
||
|
|
this.allowUserItems = allowUserItems;
|
||
|
|
}//setAllowUserItems()//
|
||
|
|
/**
|
||
|
|
* Determines whether the control should automatically synchronize all selections.
|
||
|
|
* @return Whether selections should automatically get sent to the server.
|
||
|
|
*/
|
||
|
|
protected boolean getAutoSynchronizeSelection() {
|
||
|
|
return autoSynchronizeSelection;
|
||
|
|
}//getAutoSynchronizeSelection()//
|
||
|
|
/**
|
||
|
|
* Gets the delay in milliseconds between the selection event and updating the model.
|
||
|
|
* @return The number of milliseconds to wait before updating the model.
|
||
|
|
*/
|
||
|
|
protected long getAutoSynchronizeSelectionDelay() {
|
||
|
|
return autoSynchronizeSelectionDelay;
|
||
|
|
}//getAutoSynchronizeSelectionDelay()//
|
||
|
|
/**
|
||
|
|
* Sets the delay in milliseconds between the selection event and updating the model.
|
||
|
|
* @param autoSynchronizeSelectionDelay The number of milliseconds to wait before updating the model.
|
||
|
|
*/
|
||
|
|
protected void setAutoSynchronizeSelectionDelay(long autoSynchronizeSelectionDelay) {
|
||
|
|
this.autoSynchronizeSelectionDelay = autoSynchronizeSelectionDelay;
|
||
|
|
}//setAutoSynchronizeSelectionDelay()//
|
||
|
|
/**
|
||
|
|
* Gets the linkage for the selection state.
|
||
|
|
* @return The linkage used to notify listeners when there is or is not a selection.
|
||
|
|
*/
|
||
|
|
protected Linkage getSelectionLinkage() {
|
||
|
|
return selectionLinkage;
|
||
|
|
}//getSelectionLinkage()//
|
||
|
|
/**
|
||
|
|
* Determines whether the control allows the user to make multiple selections at one time.
|
||
|
|
* @return Whether more than one value can be selected at a time.
|
||
|
|
*/
|
||
|
|
protected boolean getAllowMultiSelection() {
|
||
|
|
return allowMultiSelection;
|
||
|
|
}//getAllowMultiSelection()//
|
||
|
|
/**
|
||
|
|
* Determines whether the control allows the user to make multiple selections at one time.
|
||
|
|
* @param allowMultiSelection Whether more than one value can be selected at a time.
|
||
|
|
*/
|
||
|
|
protected void setAllowMultiSelection(boolean allowMultiSelection) {
|
||
|
|
this.allowMultiSelection = allowMultiSelection;
|
||
|
|
}//setAllowMultiSelection()//
|
||
|
|
/**
|
||
|
|
* Determines whether the control should send double click events to the server.
|
||
|
|
* @return Whether double click events need to be forwarded to the server for processing.
|
||
|
|
*/
|
||
|
|
protected boolean getSendDoubleClick() {
|
||
|
|
return sendDoubleClick;
|
||
|
|
}//getSendDoubleClick()//
|
||
|
|
/* (non-Javadoc)
|
||
|
|
* @see com.foundation.tcv.swt.client.ICellContainer#getSwtComposites()
|
||
|
|
*/
|
||
|
|
public IIterator getSwtComposites() {
|
||
|
|
return LiteList.EMPTY_LIST.iterator();
|
||
|
|
}//getSwtComposites()//
|
||
|
|
/* (non-Javadoc)
|
||
|
|
* @see com.foundation.tcv.swt.client.ICellContainer#setLayout(com.foundation.tcv.swt.client.Layout)
|
||
|
|
*/
|
||
|
|
public void setLayout(Layout layout) {
|
||
|
|
//Not supported.//
|
||
|
|
}//setLayout()//
|
||
|
|
/**
|
||
|
|
* Determines whether the two texts require swapping.
|
||
|
|
* This is used by the sorting code to determine whether rows should be swapped.
|
||
|
|
* @param text1 The first text.
|
||
|
|
* @param text2 The second text (following the first text).
|
||
|
|
* @param reverse Whether the logic should be reversed.
|
||
|
|
* @return Whether text1 and text2 require swapping.
|
||
|
|
*/
|
||
|
|
protected boolean requiresSwap(String text1, String text2, boolean reverse) {
|
||
|
|
int compare = Comparator.getNumericStringComparator().compare(text1, text2);
|
||
|
|
|
||
|
|
return reverse ? compare < 0 : compare > 0;
|
||
|
|
}//requiresSwap()//
|
||
|
|
/**
|
||
|
|
* Creates a new hidden data object at the given index in the collection.
|
||
|
|
* This can be overloaded to use subclasses which can hold the data associated with the hidden data and the rows of data in the component.
|
||
|
|
* @param hiddenDataIndex The index at for the hidden data which will serve to identify it on the server and client.
|
||
|
|
*/
|
||
|
|
protected HiddenData createHiddenData(int hiddenDataIndex) {
|
||
|
|
return new HiddenData(hiddenDataIndex);
|
||
|
|
}//createHiddenData()//
|
||
|
|
/**
|
||
|
|
* Gets the hidden data set for the given index.
|
||
|
|
* @param hiddenDataIndex The zero based index for the desired hidden data metadata.
|
||
|
|
* @return The metadata describing the hidden data and providing access to the current value for any collection item.
|
||
|
|
*/
|
||
|
|
protected HiddenData getHiddenData(int hiddenDataIndex) {
|
||
|
|
return (HiddenData) hiddenDataSets.get(hiddenDataIndex);
|
||
|
|
}//getHiddenData()//
|
||
|
|
/**
|
||
|
|
* Creates a new row object.
|
||
|
|
* @param objectId The identifier for the object that is represented by the row.
|
||
|
|
* @return An empty row object.
|
||
|
|
*/
|
||
|
|
protected RowObject createRowObject(int objectId) {
|
||
|
|
return new RowObject(objectId, getHiddenDataCount());
|
||
|
|
}//createRowObject()//
|
||
|
|
/**
|
||
|
|
* Gets the row object containing the data for the object with the given identifier.
|
||
|
|
* @param objectId Identifies the object that the row object represents.
|
||
|
|
* @return The row object that is the avatar for the object identified by the object id.
|
||
|
|
*/
|
||
|
|
public RowObject getRowObject(int objectId) {
|
||
|
|
return (RowObject) rowObjectByObjectIdMap.get(objectId);
|
||
|
|
}//getRowObject()//
|
||
|
|
/**
|
||
|
|
* Adds a new row object to the collection.
|
||
|
|
* @param rowObject The row object to be added.
|
||
|
|
*/
|
||
|
|
protected void addRowObject(RowObject rowObject) {
|
||
|
|
rowObjectByObjectIdMap.put(rowObject.getObjectId(), rowObject);
|
||
|
|
}//addRowObject()//
|
||
|
|
/**
|
||
|
|
* Removes a row object from the collection.
|
||
|
|
* @param rowObject The row object to be removed.
|
||
|
|
*/
|
||
|
|
protected void removeRowObject(int rowObjectId) {
|
||
|
|
((RowObject) rowObjectByObjectIdMap.remove(rowObjectId)).dispose();
|
||
|
|
}//removeRowObject()//
|
||
|
|
/**
|
||
|
|
* Removes all row objects from the collection.
|
||
|
|
*/
|
||
|
|
protected void removeRowObjects() {
|
||
|
|
IIterator iterator = rowObjectByObjectIdMap.valueIterator();
|
||
|
|
|
||
|
|
while(iterator.hasNext()) {
|
||
|
|
((RowObject) iterator.next()).dispose();
|
||
|
|
}//while//
|
||
|
|
|
||
|
|
rowObjectByObjectIdMap.removeAll();
|
||
|
|
}//removeRowObjects()//
|
||
|
|
/**
|
||
|
|
* Gets an iterator over all the row objects.
|
||
|
|
* @return The RowObject iterator.
|
||
|
|
*/
|
||
|
|
public IIterator getRowObjects() {
|
||
|
|
return rowObjectByObjectIdMap.valueIterator();
|
||
|
|
}//getRowObjects()//
|
||
|
|
/**
|
||
|
|
* Gets an iterator over all the row object identifiers.
|
||
|
|
* @return The row object identifier iterator.
|
||
|
|
*/
|
||
|
|
protected IIntIterator getRowObjectIds() {
|
||
|
|
return rowObjectByObjectIdMap.keyIterator();
|
||
|
|
}//getRowObjectIds()//
|
||
|
|
/**
|
||
|
|
* Gets the number of hidden data sets used by the collection component.
|
||
|
|
* @return The count of hidden data 'columns'.
|
||
|
|
*/
|
||
|
|
protected int getHiddenDataCount() {
|
||
|
|
return hiddenDataSets.getSize();
|
||
|
|
}//getHiddenDataCount()//
|
||
|
|
/**
|
||
|
|
* Gets the number of selections in the component.
|
||
|
|
* @return The count of selections.
|
||
|
|
*/
|
||
|
|
protected abstract int controlGetSelectionCount();
|
||
|
|
/**
|
||
|
|
* Updates selection linkages associated with the hidden data 'columns' based on the current selection settings.
|
||
|
|
*/
|
||
|
|
protected void updateSelectionLinks() {
|
||
|
|
selectionLinkage.invoke(controlGetSelectionCount() > 0 ? Boolean.TRUE : Boolean.FALSE);
|
||
|
|
}//updateSelectionLinks()//
|
||
|
|
/**
|
||
|
|
* Sets the hidden data for an object displayed in the collection and the hidden data column.
|
||
|
|
* @param object The row object representing the object whose hidden data is being set.
|
||
|
|
* @param hiddenDataIndex The zero based index of the hidden data column.
|
||
|
|
* @param value The new value for the hidden data for the object.
|
||
|
|
*/
|
||
|
|
protected abstract void updateHiddenData(RowObject object, int hiddenDataIndex, Object value);
|
||
|
|
/**
|
||
|
|
* Called before the collection of displayed values is modified.
|
||
|
|
* This method, in combination with postChangeCollection(), allows the control to be more efficient about its adding of items.
|
||
|
|
*/
|
||
|
|
protected final void preChangeCollection() {
|
||
|
|
if(preChangeCollectionCounter++ == 0) {
|
||
|
|
internalPreChangeCollection();
|
||
|
|
}//if//
|
||
|
|
}//preChangeCollection()//
|
||
|
|
/**
|
||
|
|
* Called after the collection of displayed values is modified.
|
||
|
|
*/
|
||
|
|
protected final void postChangeCollection() {
|
||
|
|
if(--preChangeCollectionCounter == 0) {
|
||
|
|
internalPostChangeCollection();
|
||
|
|
}//if//
|
||
|
|
}//postChangeCollection()//
|
||
|
|
/**
|
||
|
|
* Called before the collection of displayed values is modified.
|
||
|
|
* This method, in combination with postChangeCollection(), allows the control to be more efficient about its adding of items.
|
||
|
|
*/
|
||
|
|
protected void internalPreChangeCollection() {
|
||
|
|
//Subclasses should override as required.//
|
||
|
|
}//preChangeCollection()//
|
||
|
|
/**
|
||
|
|
* Called after the collection of displayed values is modified.
|
||
|
|
*/
|
||
|
|
protected void internalPostChangeCollection() {
|
||
|
|
//Subclasses should override as required.//
|
||
|
|
}//postChangeCollection()//
|
||
|
|
}//CollectionComponent//
|