Initial commit from SVN.
This commit is contained in:
@@ -0,0 +1,460 @@
|
||||
/*
|
||||
* Copyright (c) 2004,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.server;
|
||||
|
||||
import com.common.util.ICollection;
|
||||
import com.common.util.IIterator;
|
||||
import com.common.util.IList;
|
||||
import com.common.util.LiteList;
|
||||
import com.common.util.optimized.IntArray;
|
||||
import com.foundation.tcv.swt.ITreeComponent;
|
||||
import com.foundation.tcv.swt.server.SimpleTreeTable.SimpleNodeData;
|
||||
import com.foundation.tcv.view.IAbstractRemoteViewComponent;
|
||||
import com.foundation.tcv.view.ViewMessage;
|
||||
import com.foundation.view.IAbstractComponent;
|
||||
|
||||
/*
|
||||
* Tries to push as much common tree component code down to a reusable base class.
|
||||
*/
|
||||
public abstract class TreeComponent extends CollectionComponent implements ITreeComponent {
|
||||
/** The collection of columns (AbstractColumn) in server order. */
|
||||
private IList tableColumns = new LiteList(16);
|
||||
|
||||
/**
|
||||
* Encapsulates all the data pertaining to a single column in the table component.
|
||||
*/
|
||||
public static abstract class AbstractColumn implements IAbstractComponent, IAbstractRemoteViewComponent {
|
||||
/**
|
||||
* Registers an item in the collection with this column.
|
||||
* <p>An item can be registered more than once, but must be unregistered just as many times.</p>
|
||||
* @param rowObject The row to be registered.
|
||||
*/
|
||||
protected void registerItem(RowObject rowObject) {
|
||||
}//registerItem()//
|
||||
/**
|
||||
* Unregisters an item that had been previously registered.
|
||||
* @param rowObject The row to be unregistered.
|
||||
*/
|
||||
protected void unregisterItem(RowObject rowObject) {
|
||||
}//unregisterItem()//
|
||||
/**
|
||||
* Unregisters all items that had been previously registered.
|
||||
*/
|
||||
protected void unregisterAllItems() {
|
||||
}//unregisterAllItems()//
|
||||
/**
|
||||
* Refreshes the value for the cell(s) denoted by the item representing the row(s) and this column.
|
||||
* @param item The item that represents the row(s).
|
||||
* @return Whether the cell data was altered by the refresh.
|
||||
*/
|
||||
protected abstract boolean refreshCellData(Object item);
|
||||
/**
|
||||
* Gets the value for the cell(s) denoted by the item representing the row(s) and this column.
|
||||
* @param item The item that represents the row(s).
|
||||
* @return The cell value.
|
||||
*/
|
||||
protected abstract Object getCellData(Object item);
|
||||
/**
|
||||
* Gets the column's creation index.
|
||||
* @return The index assigned to this column and used to facilitate communication with the actual column resource in the display.
|
||||
*/
|
||||
protected abstract int getIndex();
|
||||
/**
|
||||
* Sets the column's creation index.
|
||||
* @param index The index assigned to this column and used to facilitate communication with the actual column resource in the display.
|
||||
*/
|
||||
protected abstract void setIndex(int index);
|
||||
/**
|
||||
* Initializes the column before the table component is initialized.
|
||||
*/
|
||||
protected abstract void initialize();
|
||||
/**
|
||||
* Refreshes the column.
|
||||
*/
|
||||
protected abstract void refresh();
|
||||
/**
|
||||
* Initializes the column before the table component is released.
|
||||
*/
|
||||
protected abstract void release();
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.tcv.view.IAbstractViewComponent#processMessage(com.foundation.tcv.view.ViewMessage)
|
||||
*/
|
||||
public Object processMessage(ViewMessage viewMessage) {
|
||||
return null;
|
||||
}//processMessage()//
|
||||
}//AbstractColumn//
|
||||
/**
|
||||
* TreeComponent constructor.
|
||||
* @param parent The parent container for this component.
|
||||
* @param name The name of the component.
|
||||
*/
|
||||
public TreeComponent(Container parent, String name, int style) {
|
||||
super(parent, name, style);
|
||||
}//TreeComponent()//
|
||||
/**
|
||||
* Adds a column to the component.
|
||||
* @param column The column to be added.
|
||||
*/
|
||||
protected void addColumn(AbstractColumn column) {
|
||||
tableColumns.add(column.getIndex(), column);
|
||||
|
||||
//Update the other column indices.//
|
||||
for(int index = column.getIndex() + 1; index < tableColumns.getSize(); index++) {
|
||||
((AbstractColumn) tableColumns.get(index)).setIndex(index);
|
||||
}//for//
|
||||
|
||||
//Notify the client.//
|
||||
sendMessage(MESSAGE_ADD_COLUMN, new Integer(column.getIndex()));
|
||||
|
||||
//TODO: Support columns added after the display is showing.//
|
||||
if(isInitialized()) {
|
||||
//Note: While it would be nice to send the header and cell data, we can't because the column hasn't been setup yet.//
|
||||
//TODO: Send the initial header data.//
|
||||
//TODO: Need to send the initial cell data.//
|
||||
}//if//
|
||||
}//addColumn()//
|
||||
/**
|
||||
* Gets the number of columns in the table.
|
||||
* @return The count of columns.
|
||||
*/
|
||||
protected int getColumnCount() {
|
||||
return tableColumns.getSize();
|
||||
}//getColumnCount()//
|
||||
/**
|
||||
* Gets the column at the given index.
|
||||
* @param index The zero based column index.
|
||||
* @return The column at the given index.
|
||||
*/
|
||||
protected AbstractColumn getColumn(int index) {
|
||||
return (AbstractColumn) tableColumns.get(index);
|
||||
}//getColumn()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.tcv.swt.server.CollectionComponent#internalViewRefreshCollection(com.common.util.ICollection, com.common.util.ICollection)
|
||||
*/
|
||||
protected void internalViewRefreshCollection(ICollection newCollection, ICollection oldCollection) {
|
||||
sendMessage(MESSAGE_SAVE_VIEW_STATE, null);
|
||||
//Clear the old data.//
|
||||
primaryCollectionItemsRemoved();
|
||||
|
||||
//Rebuild the tree.//
|
||||
if(newCollection != null) {
|
||||
IIterator itemIterator = newCollection.iterator();
|
||||
|
||||
//Get the array of strings representing the list contents.//
|
||||
while(itemIterator.hasNext()) {
|
||||
Object item = itemIterator.next();
|
||||
|
||||
placeItem(null, item);
|
||||
}//while//
|
||||
}//if//
|
||||
|
||||
//If the selection was invalid previously then refresh the selection since it may no longer be invalid.//
|
||||
if(isSelectionInvalid) {
|
||||
internalViewRefreshSelection();
|
||||
}//if//
|
||||
|
||||
sendMessage(MESSAGE_RESTORE_VIEW_STATE, null);
|
||||
}//internalViewRefreshCollection()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.tcv.swt.server.CollectionComponent#internalViewRefreshSelection(java.lang.Object)
|
||||
*/
|
||||
protected void internalViewRefreshSelection(Object selectedItem) {
|
||||
if(selectedItem != null) {
|
||||
RowObject rowObject = (RowObject) getRowObject(selectedItem);
|
||||
|
||||
if(rowObject == null) {
|
||||
isSelectionInvalid = true;
|
||||
sendMessage(MESSAGE_SET_SELECTION, null);
|
||||
}//if//
|
||||
else {
|
||||
isSelectionInvalid = false;
|
||||
sendMessage(MESSAGE_SET_SELECTION, new int[] {rowObject.objectId});
|
||||
}//else//
|
||||
}//if//
|
||||
else {
|
||||
//No selection.//
|
||||
sendMessage(MESSAGE_SET_SELECTION, null);
|
||||
}//else//
|
||||
}//internalViewRefreshSelection()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.tcv.swt.server.CollectionComponent#internalViewRefreshSelections(com.common.util.ICollection, com.common.util.ICollection)
|
||||
*/
|
||||
protected void internalViewRefreshSelections(ICollection newSelections, ICollection oldSelections) {
|
||||
if(newSelections != null) {
|
||||
IntArray selectionObjectIds = new IntArray(newSelections.getSize());
|
||||
IIterator selectionIterator = newSelections.iterator();
|
||||
|
||||
//Apply differences between the selection collection and the control selection. Also remove all impossible selections.//
|
||||
while(selectionIterator.hasNext()) {
|
||||
Object selection = selectionIterator.next();
|
||||
RowObject rowObject = (RowObject) getRowObject(selection);
|
||||
|
||||
if(rowObject == null) {
|
||||
//An invalid selection because the selection is not in the collection of displayed values.//
|
||||
selectionIterator.remove();
|
||||
}//if//
|
||||
else {
|
||||
selectionObjectIds.add(rowObject.objectId);
|
||||
}//else//
|
||||
}//while//
|
||||
|
||||
sendMessage(MESSAGE_SET_SELECTION, selectionObjectIds.toArray());
|
||||
}//if//
|
||||
else {
|
||||
//Remove all selections.//
|
||||
sendMessage(MESSAGE_REMOVE_SELECTIONS, null);
|
||||
}//else//
|
||||
}//internalViewRefreshSelections()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.tcv.swt.server.CollectionComponent#internalViewInitialize()
|
||||
*/
|
||||
protected void internalViewInitialize() {
|
||||
//Initialize all the columns.//
|
||||
for(int columnIndex = 0; columnIndex < tableColumns.getSize(); columnIndex++) {
|
||||
((AbstractColumn) tableColumns.get(columnIndex)).initialize();
|
||||
}//for//
|
||||
|
||||
super.internalViewInitialize();
|
||||
}//internalViewInitialize()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.tcv.swt.server.CollectionComponent#internalViewRefresh()
|
||||
*/
|
||||
protected void internalViewRefresh() {
|
||||
super.internalViewRefresh();
|
||||
|
||||
//Refresh all the columns.//
|
||||
for(int columnIndex = 0; columnIndex < tableColumns.getSize(); columnIndex++) {
|
||||
((AbstractColumn) tableColumns.get(columnIndex)).refresh();
|
||||
}//for//
|
||||
}//internalViewRefresh()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.view.swt.AbstractComponent#internalViewRelease()
|
||||
*/
|
||||
protected void internalViewRelease() {
|
||||
//Release all the columns.//
|
||||
for(int columnIndex = 0; columnIndex < tableColumns.getSize(); columnIndex++) {
|
||||
((AbstractColumn) tableColumns.get(columnIndex)).release();
|
||||
}//for//
|
||||
|
||||
super.internalViewRelease();
|
||||
}//internalViewRelease()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.tcv.swt.server.CollectionComponent#itemSorted(int[])
|
||||
*/
|
||||
protected void itemSorted(int[] mapping) {
|
||||
//TODO: Should this be implemented?
|
||||
//sendMessage(MESSAGE_ORDER_ROWS, mapping);
|
||||
}//itemSorted()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.tcv.swt.server.CollectionComponent#selectionAdded(java.lang.Object)
|
||||
*/
|
||||
protected void selectionAdded(Object value) {
|
||||
RowObject rowObject = getRowObject(value);
|
||||
|
||||
if(rowObject != null) {
|
||||
sendMessage(MESSAGE_ADD_SELECTION, null, null, rowObject.objectId, -1);
|
||||
}//if//
|
||||
}//selectionAdded()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.tcv.swt.server.CollectionComponent#selectionRemoved(java.lang.Object)
|
||||
*/
|
||||
protected void selectionRemoved(Object value) {
|
||||
RowObject rowObject = getRowObject(value);
|
||||
|
||||
if(rowObject != null) {
|
||||
sendMessage(MESSAGE_REMOVE_SELECTION, null, null, rowObject.objectId, -1);
|
||||
}//if//
|
||||
}//selectionRemoved()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.tcv.swt.server.CollectionComponent#selectionAllRemoved()
|
||||
*/
|
||||
protected void selectionAllRemoved() {
|
||||
sendMessage(MESSAGE_REMOVE_ALL_SELECTIONS, null);
|
||||
}//selectionAllRemoved()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.tcv.swt.server.CollectionComponent#registerItem(com.foundation.tcv.swt.server.RowObject)
|
||||
*/
|
||||
protected void registerItem(RowObject rowObject) {
|
||||
super.registerItem(rowObject);
|
||||
|
||||
//Add the item to each of the columns so we receive updates.//
|
||||
for(int index = 0; index < tableColumns.getSize(); index++) {
|
||||
((AbstractColumn) tableColumns.get(index)).registerItem(rowObject);
|
||||
}//for//
|
||||
}//registerItem()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.tcv.swt.server.CollectionComponent#unregisterItem(com.foundation.tcv.swt.server.RowObject)
|
||||
*/
|
||||
protected void unregisterItem(RowObject rowObject) {
|
||||
super.unregisterItem(rowObject);
|
||||
|
||||
//Unregister the value with the columns so we stop receiving updates.//
|
||||
for(int index = 0; index < tableColumns.getSize(); index++) {
|
||||
((AbstractColumn) tableColumns.get(index)).unregisterItem(rowObject);
|
||||
}//for//
|
||||
}//unregisterItem()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.tcv.swt.server.CollectionComponent#unregisterItems()
|
||||
*/
|
||||
protected void unregisterItems() {
|
||||
super.unregisterItems();
|
||||
|
||||
//Unregister the items from the columns so we stop recieving updates.//
|
||||
for(int index = 0; index < tableColumns.getSize(); index++) {
|
||||
((AbstractColumn) tableColumns.get(index)).unregisterAllItems();
|
||||
}//for//
|
||||
}//unregisterItems()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.tcv.swt.server.CollectionComponent#getItemData(com.foundation.tcv.swt.server.RowObject)
|
||||
*/
|
||||
protected Object getItemData(RowObject rowObject) {
|
||||
Object[] result = new Object[tableColumns.getSize() + 1];
|
||||
|
||||
refreshRowHeaderCellData(rowObject.value);
|
||||
result[0] = getRowHeaderCellData(rowObject.value);
|
||||
|
||||
for(int index = 0; index < result.length; index++) {
|
||||
AbstractColumn column = (AbstractColumn) tableColumns.get(index);
|
||||
|
||||
if(column != null) {
|
||||
column.refreshCellData(rowObject.value);
|
||||
result[index + 1] = column.getCellData(rowObject.value);
|
||||
}//if//
|
||||
}//for//
|
||||
|
||||
return result;
|
||||
}//getItemData()//
|
||||
protected void sendAddItemMessage(RowObject rowObject, int itemIndex) {
|
||||
//Don't send duplicate messages since the client doesn't care.//
|
||||
if(rowObject.isFirstReference()) {
|
||||
//TODO: Figure out how to get whether the value can have children from the row object. Send 0 if no children, 1 if can have children.
|
||||
sendMessage(MESSAGE_ADD_ITEM, getItemData(rowObject), getItemHiddenData(rowObject.value), rowObject.objectId, canHaveChildren(rowObject.value) ? 1 : 0);
|
||||
}//if//
|
||||
}//sendAddItemMessage()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.tcv.swt.server.CollectionComponent#sendRemoveItemMessage(com.foundation.tcv.swt.server.CollectionComponent.RowObject, int, boolean)
|
||||
*/
|
||||
protected void sendRemoveItemMessage(RowObject rowObject, int itemIndex, boolean isRemovedEntirely) {
|
||||
if(isRemovedEntirely) {
|
||||
sendMessage(MESSAGE_REMOVE_ITEM, null, null, rowObject.objectId, itemIndex);
|
||||
}//if//
|
||||
}//sendRemoveItemMessage()//
|
||||
/**
|
||||
* Refreshes the row header cell data and determines whether there were substantial alterations.
|
||||
* @param item The row item.
|
||||
* @return Whether the cell data was changed.
|
||||
*/
|
||||
protected abstract boolean refreshRowHeaderCellData(Object item);
|
||||
/**
|
||||
* Gets the row header cell data.
|
||||
* @param item The row item.
|
||||
* @return The cell data for the row's row header.
|
||||
*/
|
||||
protected abstract Object getRowHeaderCellData(Object item);
|
||||
/**
|
||||
* Determines whether the passed item might have children.
|
||||
* @param item The item to check.
|
||||
* @return Whether the item could have children.
|
||||
*/
|
||||
protected abstract boolean canHaveChildren(Object item);
|
||||
/**
|
||||
* Places the item as a child of the given node. It may be grouped so that it is an indirect child of the given node.
|
||||
* @param node The node that will have the item as a child. This may be null if the item is at the root of the tree.
|
||||
* @param item The non-grouping item that is placed under the node.
|
||||
*/
|
||||
protected abstract void placeItem(SimpleNodeData node, Object item);
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.tcv.view.IViewComponent#processMessage(com.foundation.tcv.model.ViewMessage)
|
||||
*/
|
||||
public Object processMessage(ViewMessage viewMessage) {
|
||||
Object retVal = null;
|
||||
|
||||
switch(viewMessage.getMessageNumber()) {
|
||||
case MESSAGE_VIEW_SYNCHRONIZE_SELECTION: { //Receive the selection information from the client.//
|
||||
Object messageData = viewMessage.getMessageData();
|
||||
|
||||
if(getAllowMultiSelection()) {
|
||||
int[] selectionObjectIds = (int[]) messageData;
|
||||
boolean[] selectionMarks = new boolean[selectionObjectIds.length];
|
||||
ICollection modelSelections = getModelSelections();
|
||||
|
||||
//Prevent the selection additions from causing a feedback loop.//
|
||||
suspendSelectionHooks = true;
|
||||
|
||||
try {
|
||||
if(modelSelections != null) {
|
||||
IIterator iterator = modelSelections.iterator();
|
||||
LiteList removed = new LiteList(modelSelections.getSize());
|
||||
LiteList added = new LiteList(selectionObjectIds.length);
|
||||
|
||||
//Initialize the bit field.//
|
||||
for(int index = 0; index < selectionMarks.length; index++) {
|
||||
selectionMarks[index] = false;
|
||||
}//for//
|
||||
|
||||
//For each previous selection, try to find a matching current selection, otherwise remove it. Mark all used current selections.//
|
||||
while(iterator.hasNext()) {
|
||||
Object next = iterator.next();
|
||||
RowObject rowObject = getRowObject(next);
|
||||
|
||||
if(rowObject != null) {
|
||||
int nextObjectId = rowObject.objectId;
|
||||
boolean found = false;
|
||||
|
||||
for(int index = 0; (!found) && (index < selectionObjectIds.length); index++) {
|
||||
if((selectionObjectIds[index] == nextObjectId) && (!selectionMarks[index])) {
|
||||
selectionMarks[index] = true;
|
||||
found = true;
|
||||
}//if//
|
||||
}//for//
|
||||
|
||||
//If the selection wasn't found in the view then remove it from the model.//
|
||||
if(!found) {
|
||||
removed.add(next);
|
||||
}//if//
|
||||
|
||||
//Add the selections that were in the view but not in the model.//
|
||||
for(int index = 0; index < selectionMarks.length; index++) {
|
||||
if(!selectionMarks[index]) {
|
||||
RowObject wrapper = (RowObject) getRowObject(selectionObjectIds[index]);
|
||||
|
||||
if(wrapper != null) {
|
||||
added.add(wrapper.value);
|
||||
}//if//
|
||||
}//if//
|
||||
}//for//
|
||||
}//if//
|
||||
}//while//
|
||||
|
||||
modelSelections.replaceAll(removed, added);
|
||||
}//if//
|
||||
}//try//
|
||||
finally {
|
||||
suspendSelectionHooks = false;
|
||||
}//finally//
|
||||
}//if//
|
||||
else {
|
||||
int selectedObjectId = messageData != null ? ((Integer) messageData).intValue() : -1;
|
||||
RowObject selectedRowObject = (RowObject) (selectedObjectId >= 0 ? getRowObject(selectedObjectId) : null);
|
||||
|
||||
setModelSelection(selectedRowObject == null ? null : selectedRowObject.value);
|
||||
}//else//
|
||||
|
||||
if(getAutoValidate()) {
|
||||
postSynchronizeValidate();
|
||||
}//if//
|
||||
break;
|
||||
}//case//
|
||||
default: {
|
||||
retVal = super.processMessage(viewMessage);
|
||||
}//default//
|
||||
}//switch//
|
||||
|
||||
return retVal;
|
||||
}//processMessage()//
|
||||
}//TreeComponent//
|
||||
Reference in New Issue
Block a user