2149 lines
84 KiB
Java
2149 lines
84 KiB
Java
/*
|
|
* 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.comparison.Comparator;
|
|
import com.common.debug.Debug;
|
|
import com.common.util.ICollection;
|
|
import com.common.util.IHashSet;
|
|
import com.common.util.IIterator;
|
|
import com.common.util.IList;
|
|
import com.common.util.LiteHashSet;
|
|
import com.common.util.LiteList;
|
|
import com.common.util.optimized.IntArray;
|
|
import com.foundation.controller.DecorationManager;
|
|
import com.foundation.tcv.swt.ISimpleTreeTable;
|
|
import com.foundation.tcv.swt.SimpleTreeTableCellData;
|
|
import com.foundation.tcv.swt.server.SimpleTable.Renderer;
|
|
import com.foundation.tcv.swt.server.cell.CellComponent;
|
|
import com.foundation.tcv.view.ViewMessage;
|
|
import com.foundation.util.IInlineCollectionObservable;
|
|
import com.foundation.util.IInlineCollectionObserver;
|
|
import com.foundation.util.IInlineIndexedCollectionObservable;
|
|
import com.foundation.util.IInlineIndexedCollectionObserver;
|
|
import com.foundation.view.*;
|
|
import com.foundation.view.resource.AbstractResourceService;
|
|
import com.foundation.view.resource.ResourceReference;
|
|
|
|
/**
|
|
* A base class for table or table like controls which have multiple columns or categories of data and a list or collection of model objects representing rows.
|
|
* <p>TODO: Enable more usage patterns:
|
|
* <ol>
|
|
* <li>The current usage pattern is that the client doesn't know of node's children until the user tries to open the node, then the client always knows of the node's children from then on.
|
|
* <li>The client could lose the node's children knowledge when it is closed, thus releasing the server side listeners and reducing messaging. This would require the client send a lose node data message to the server which would then prune the tree which would send the remove linkage and remove data messages. This would also have to update the client node to show that it may have children.
|
|
* <li>The client could know of each visible and unopened node's children and the linkages such that when a node is opened, the children are immediatly displayed, and a message is sent to fetch each child's children nodes. The view would have to display the children as potentially having children where necessary until the children data arrives.
|
|
* <li>The client could know of all nodes in the tree up front and there would be no adding or removing of linkages except as the model changes. This would be most efficient for small fairly static trees.
|
|
* </ol>
|
|
* </p>
|
|
*/
|
|
public class SimpleTreeTable extends TreeComponent implements ISimpleTreeTable {
|
|
/** The background color resource for the column. */
|
|
private MultiResourceAssociation rowBackgroundColor = new MultiResourceAssociation(this, this, getViewContext(), ResourceAssociation.TYPE_COLOR, false, null);
|
|
/** The foreground color resource for the column. */
|
|
private MultiResourceAssociation rowForegroundColor = new MultiResourceAssociation(this, this, getViewContext(), ResourceAssociation.TYPE_COLOR, false, null);
|
|
/** The font resource for the column. */
|
|
private MultiResourceAssociation rowFont = new MultiResourceAssociation(this, this, getViewContext(), ResourceAssociation.TYPE_FONT, false, null);
|
|
/** The row height used. */
|
|
private SingleResourceAssociation rowHeight = new SingleResourceAssociation(this, this, getViewContext(), ResourceAssociation.TYPE_INTEGER, false, null);
|
|
/** The events associations that resize all non-auto-fit columns to fit the size of the data in the column. */
|
|
private IHashSet fitEventAssociations = null;
|
|
/** The event associations resize all auto-fill columns to fill empty space in the control. This never makes columns smaller. */
|
|
private IHashSet fillEventAssociations = null;
|
|
/** Whether resizeable columns will be called upon to fit the control's client space when the control resizes or a column resizes. */
|
|
private boolean autoFit = false;
|
|
/** Whether resizeable columns will be streched to fill available space during the control's initialization. */
|
|
private boolean fillOnInitialize = false;
|
|
/** Whether resizeable columns will be streched to fill available space after the control is resized. */
|
|
private boolean fillOnResize = false;
|
|
/** Whether the user is allowed to make more than one item selection. */
|
|
private final boolean allowMultiSelection;
|
|
/** Whether the sorting is managed by the view versus the model. */
|
|
//private boolean inViewSorting = true;
|
|
/** Whether to show the header. */
|
|
private boolean showHeader = true;
|
|
/** Whether to show the grid lines. */
|
|
private boolean showGridLines = false;
|
|
/** The association that returns the children for any row in the tree. */
|
|
private CollectingMultiResourceAssociation children = new CollectingMultiResourceAssociation(this, this, getViewContext(), ResourceAssociation.TYPE_OBJECT, false);
|
|
/** The association that returns the groupings for any row in the tree. */
|
|
private CollectingMultiResourceAssociation groupings = new CollectingMultiResourceAssociation(this, this, getViewContext(), ResourceAssociation.TYPE_OBJECT, false);
|
|
/** The root node for our tree. */
|
|
private SimpleNodeData rootNode = new SimpleNodeData(null, -1);
|
|
/** Sets whether or not the opening of a node causes the selection even to occur for that row. */
|
|
private boolean selectOnOpen = false;
|
|
/** The set of all group nodes. This allows the group nodes to be retrieved when refreshing a column or the whole tree. */
|
|
private LiteHashSet groupNodes = new LiteHashSet(100);
|
|
|
|
public class CollectionListener implements IInlineIndexedCollectionObserver, IInlineCollectionObserver {
|
|
/** The node to be notified when the collection changes. */
|
|
private SimpleNodeData node;
|
|
/** Whether this is a grouping collection (versus a children collection). */
|
|
//private boolean isGrouping;
|
|
/** The collection to be listened to. */
|
|
private ICollection collection;
|
|
|
|
/**
|
|
* CollectionListener constructor.
|
|
* <p>Note: Also registers for the event on the collection.</p>
|
|
* @param node The node to be notified when the collection changes.
|
|
* @param isGrouping Whether this is a grouping collection (versus a children collection).
|
|
* @param collection The collection to be listened to.
|
|
*/
|
|
public CollectionListener(SimpleNodeData node, boolean isGrouping, ICollection collection) {
|
|
this.node = node;
|
|
//this.isGrouping = isGrouping;
|
|
this.collection = collection;
|
|
|
|
if(collection instanceof IInlineIndexedCollectionObservable) {
|
|
((IInlineIndexedCollectionObservable) collection).addCollectionObserver((IInlineIndexedCollectionObserver) this);
|
|
}//if//
|
|
else if(collection instanceof IInlineCollectionObservable) {
|
|
((IInlineCollectionObservable) collection).addCollectionObserver((IInlineCollectionObserver) this);
|
|
}//else if//
|
|
}//CollectionListener()//
|
|
/**
|
|
* Releases the listener when it is no longer needed.
|
|
*/
|
|
public void release() {
|
|
if(collection instanceof IInlineIndexedCollectionObservable) {
|
|
((IInlineIndexedCollectionObservable) collection).removeCollectionObserver((IInlineIndexedCollectionObserver) this);
|
|
}//if//
|
|
else if(collection instanceof IInlineCollectionObservable) {
|
|
((IInlineCollectionObservable) collection).removeCollectionObserver((IInlineCollectionObserver) this);
|
|
}//else if//
|
|
}//release()//
|
|
/**
|
|
* Gets the collection being listened to.
|
|
* @return The collection whose adds and removes are to be used to update the tree.
|
|
*/
|
|
public ICollection getCollection() {
|
|
return collection;
|
|
}//getCollection()//
|
|
/* (non-Javadoc)
|
|
* @see com.foundation.util.IInlineCollectionObserver#valueAdded(java.lang.Object)
|
|
*/
|
|
public void valueAdded(Object value) {
|
|
placeItem(node, value);
|
|
}//valueAdded()//
|
|
/* (non-Javadoc)
|
|
* @see com.foundation.util.IInlineCollectionObserver#valueRemoved(java.lang.Object)
|
|
*/
|
|
public void valueRemoved(Object value) {
|
|
SimpleNodeData child = node.getChildNode(value, false);
|
|
|
|
if(child != null) {
|
|
pruneNode(node, child);
|
|
}//if//
|
|
else {
|
|
Debug.log(new RuntimeException("Internal Error: failed to locate the child node."));
|
|
}//else//
|
|
}//valueRemoved()//
|
|
/* (non-Javadoc)
|
|
* @see com.foundation.util.IInlineCollectionObserver#removingAll()
|
|
*/
|
|
public void removingAll() {
|
|
IList children = new LiteList(node.getChildNodes());
|
|
|
|
try {
|
|
startChanges(children.getSize());
|
|
|
|
for(int index = 0; index < children.getSize(); index++) {
|
|
SimpleNodeData child = (SimpleNodeData) children.get(index);
|
|
|
|
if(!child.isGrouping()) {
|
|
pruneNode(node, child);
|
|
}//if//
|
|
}//for//
|
|
}//try//
|
|
finally {
|
|
stopChanges();
|
|
}//finally//
|
|
}//removingAll()//
|
|
/* (non-Javadoc)
|
|
* @see com.foundation.util.IInlineIndexedCollectionObserver#startChanges(int)
|
|
*/
|
|
public void startChanges(int changeCount) {
|
|
SimpleTreeTable.this.addMessageHold();
|
|
}//startChanges()//
|
|
/* (non-Javadoc)
|
|
* @see com.foundation.util.IInlineIndexedCollectionObserver#stopChanges()
|
|
*/
|
|
public void stopChanges() {
|
|
SimpleTreeTable.this.removeMessageHold();
|
|
}//stopChanges()//
|
|
/* (non-Javadoc)
|
|
* @see com.foundation.util.IInlineIndexedCollectionObserver#valueAdded(java.lang.Object, int)
|
|
*/
|
|
public void valueAdded(Object value, int index) {
|
|
valueAdded(value);
|
|
}//valueAdded()//
|
|
/* (non-Javadoc)
|
|
* @see com.foundation.util.IInlineIndexedCollectionObserver#valueRemoved(java.lang.Object, int)
|
|
*/
|
|
public void valueRemoved(Object value, int index) {
|
|
valueRemoved(value);
|
|
}//valueRemoved()//
|
|
/* (non-Javadoc)
|
|
* @see com.foundation.util.IInlineIndexedCollectionObserver#valuesSorted(int[])
|
|
*/
|
|
public void valuesSorted(int[] mapping) {
|
|
//TODO: Should this be implemented?
|
|
//Ignored//
|
|
}//valuesSorted()//
|
|
}//CollectionListener//
|
|
|
|
/**
|
|
* The node in the virtual tree. This node can have multiple parents because it can appear in more than one place in the tree display.
|
|
* A virtual tree is used because it is much more flexable than the underlying tree component.
|
|
* There is only one TreeNode for each model value even if the model value appears in the tree in multiple places at multiple levels of the tree.
|
|
*/
|
|
protected class SimpleNodeData extends RowObject {
|
|
/** The child TreeNode instances. This will be null if the children are unkown. */
|
|
private IList childNodes = null;
|
|
/** The parent tree nodes (the non-grouping parent), or null if this is a root node, this is a grouping node, or has no groupings. This is used to update the groupings when a node's groupings change. It is possible for a node to be referenced by more than one parent. */
|
|
private IList parentNodes = null;
|
|
/** Whether this is a grouping node. */
|
|
private boolean isGrouping = false;
|
|
/** The reference to a CollectionListener or an IList of CollectionListeners which will provide us with adds and removes of the node's children. This will be null if there are no listeners yet. */
|
|
private Object childListener = null;
|
|
/** Whether the node has been opened. Opened nodes must release from the children association. */
|
|
private boolean isOpened = false;
|
|
|
|
/**
|
|
* SimpleNodeData constructor.
|
|
* <p>Note: The caller should not increment the usage counter as it already starts at one.</p>
|
|
* <p>Warning: Callers must initialize the node after creating it. There also must be a release call to allow for unregistering event hooks.</p>
|
|
* @param item The data for the node. This is often the row value, but for groupings is the grouping value.
|
|
* @param objectId The value's object identifier.
|
|
*/
|
|
public SimpleNodeData(Object value, int objectId) {
|
|
super(value, objectId);
|
|
}//SimpleNodeData()//
|
|
/**
|
|
* Determines whether changes to the children collection for this node must send changes to the client.
|
|
* @return Whether the client knows of the children for this node (whether the node has been opened and not specifically closed by the client).
|
|
*/
|
|
public boolean sendChildUpdates() {
|
|
return childNodes != null;
|
|
}//sendChildUpdates()//
|
|
/**
|
|
* Determines whether this is a grouping node.
|
|
* @return Whether this node was created from a grouping value.
|
|
*/
|
|
public boolean isGrouping() {
|
|
return isGrouping;
|
|
}//isGrouping()//
|
|
/**
|
|
* Determines whether this is a grouping node.
|
|
* @param isGrouping Whether this node was created from a grouping value.
|
|
*/
|
|
public void isGrouping(boolean isGrouping) {
|
|
this.isGrouping = isGrouping;
|
|
}//isGrouping()//
|
|
/**
|
|
* Gets the node's child node count.
|
|
* @return The number of child TreeNode instances.
|
|
*/
|
|
public int getChildNodeCount() {
|
|
return childNodes == null ? 0 : childNodes.getSize();
|
|
}//getChildNodeCount()//
|
|
/**
|
|
* Gets the indexed child node.
|
|
* @param index The zero based index of the child to be retrieved.
|
|
* @return The child tree node at the given index.
|
|
*/
|
|
public SimpleNodeData getChildNode(int index) {
|
|
return (SimpleNodeData) childNodes.get(index);
|
|
}//getChildNode()//
|
|
/**
|
|
* Gets the child nodes.
|
|
* @return The collection of all child nodes.
|
|
*/
|
|
public IList getChildNodes() {
|
|
return childNodes;
|
|
}//getChildNodes()//
|
|
/**
|
|
* Gets the child node association with the given item.
|
|
* @param item The item associated with the node we are searching for.
|
|
* @param isGrouping Whether we are searching for a grouping node.
|
|
* @return The found tree node, or null.
|
|
*/
|
|
public SimpleNodeData getChildNode(Object item, boolean isGrouping) {
|
|
SimpleNodeData result = null;
|
|
|
|
for(int index = 0; (result == null) && (index < childNodes.getSize()); index++) {
|
|
SimpleNodeData next = (SimpleNodeData) childNodes.get(index);
|
|
|
|
if((next.isGrouping() == isGrouping) && (Comparator.equals(next.value, item))) {
|
|
result = next;
|
|
}//if//
|
|
}//for//
|
|
|
|
return result;
|
|
}//getChildNode()//
|
|
/**
|
|
* Adds a child node to this node.
|
|
* <p>Warning: This method should be called in order to allow future indexing of the child nodes.</p>
|
|
* @param childNode The child node to be added.
|
|
*/
|
|
public void addChildNode(SimpleNodeData childNode) {
|
|
if(childNodes == null) {
|
|
childNodes = new LiteList(20, 100);
|
|
}//if//
|
|
|
|
childNodes.add(childNode);
|
|
//Notify the client.//
|
|
sendMessage(MESSAGE_ADD_NODE_LINK, null, null, objectId, childNode.objectId);
|
|
}//addChildNode()//
|
|
/**
|
|
* Removes a child node from this node.
|
|
* <p>Warning: This method should be called in order to allow future indexing of the child nodes.</p>
|
|
* @param childNode The child node to be removed.
|
|
*/
|
|
public void removeChildNode(SimpleNodeData childNode) {
|
|
childNodes.remove(childNode);
|
|
//Notify the client.//
|
|
sendMessage(MESSAGE_REMOVE_NODE_LINK, null, null, objectId, childNode.objectId);
|
|
}//removeChildNode()//
|
|
/**
|
|
* Removes all child nodes from this node.
|
|
* <p>Warning: This method should be called in order to allow future indexing of the child nodes.</p>
|
|
*/
|
|
public void removeChildNodes() {
|
|
if(childNodes != null) {
|
|
childNodes.removeAll();
|
|
}//if//
|
|
}//removeChildNodes()//
|
|
/**
|
|
* Sets the node's child nodes. This method will index the list of child nodes.
|
|
* @param childNodes The child TreeNode instances. This will be null if the children are unkown.
|
|
*/
|
|
public void setChildNodes(IList childNodes) {
|
|
this.childNodes = childNodes;
|
|
}//setChildNodes()//
|
|
/**
|
|
* Gets the parents of this node.
|
|
* <p>The parent tree nodes (the non-grouping parent), or null if this is a root node, the is a grouping node, or has no groupings.
|
|
* This is used to update the groupings when a node's groupings change.
|
|
* It is possible for a node to be referenced by more than one parent.</p>
|
|
* @return The parent (non-grouping) tree nodes, or null.
|
|
*/
|
|
public IList getParentNodes() {
|
|
return parentNodes;
|
|
}//getParentNodes()//
|
|
/**
|
|
* Sets the parents of this node.
|
|
* <p>The parent tree nodes (the non-grouping parent), or null if this is a root node, the is a grouping node, or has no groupings.
|
|
* This is used to update the groupings when a node's groupings change.
|
|
* It is possible for a node to be referenced by more than one parent.</p>
|
|
* @param parentNodes The parent (non-grouping) tree nodes, or null.
|
|
*/
|
|
public void setParentNodes(IList parentNodes) {
|
|
this.parentNodes = parentNodes;
|
|
}//setParentNodes()//
|
|
/**
|
|
* Adds a child collection listener to pickup adds and removes from the collection of child items.
|
|
* @param collection The collection to be listened to.
|
|
*/
|
|
public void addChildListener(ICollection collection) {
|
|
CollectionListener listener = new CollectionListener(this, false, collection);
|
|
|
|
if(childListener != null) {
|
|
if(childListener instanceof IList) {
|
|
((IList) childListener).add(listener);
|
|
}//if//
|
|
else {
|
|
IList list = new LiteList(5, 20);
|
|
|
|
list.add(childListener);
|
|
list.add(listener);
|
|
childListener = list;
|
|
}//else//
|
|
}//if//
|
|
else {
|
|
childListener = listener;
|
|
}//else//
|
|
}//addChildListener()//
|
|
/**
|
|
* Removes a child collection listener given the collection it was created with.
|
|
* @param collection The collection that the listener is listening to.
|
|
*/
|
|
public void removeChildListener(ICollection collection) {
|
|
CollectionListener result = null;
|
|
|
|
if(childListener instanceof IList) {
|
|
IList listeners = (IList) childListener;
|
|
|
|
for(int index = 0; (result == null) && (index < listeners.getSize()); index++) {
|
|
CollectionListener listener = (CollectionListener) listeners.get(index);
|
|
|
|
if(listener.getCollection() == collection) {
|
|
listeners.remove(index);
|
|
result = listener;
|
|
}//if//
|
|
}//for//
|
|
}//if//
|
|
else if(childListener instanceof CollectionListener) {
|
|
if(((CollectionListener) childListener).getCollection() == collection) {
|
|
result = (CollectionListener) childListener;
|
|
}//if//
|
|
}//else if//
|
|
|
|
if(result != null) {
|
|
result.release();
|
|
}//if//
|
|
}//removeChildListener()//
|
|
/**
|
|
* Removes all child collection listeners.
|
|
*/
|
|
public void removeChildListeners() {
|
|
CollectionListener result = null;
|
|
|
|
if(childListener instanceof IList) {
|
|
IList listeners = (IList) childListener;
|
|
|
|
for(int index = 0; (result == null) && (index < listeners.getSize()); index++) {
|
|
((CollectionListener) listeners.get(index)).release();
|
|
}//for//
|
|
|
|
listeners.removeAll();
|
|
}//if//
|
|
else if(childListener instanceof CollectionListener) {
|
|
((CollectionListener) childListener).release();
|
|
}//else if//
|
|
|
|
if(result != null) {
|
|
result.release();
|
|
}//if//
|
|
}//removeChildListeners()//
|
|
/**
|
|
* Initializes the node by placing it in all mappings.
|
|
*/
|
|
public void initialize() {
|
|
if((this != rootNode) && (!isGrouping)) {
|
|
groupings.registerItem(value);
|
|
//Moved into initializeOnOpen() which is called when the row is opened, not when loaded.//
|
|
// children.registerItem(value);
|
|
}//if//
|
|
}//initialize()//
|
|
/**
|
|
* Initializes the node by placing it in all mappings.
|
|
*/
|
|
public void initializeOnOpen() {
|
|
if((this != rootNode) && (!isGrouping)) {
|
|
isOpened = true;
|
|
children.registerItem(value);
|
|
}//if//
|
|
}//initialize()//
|
|
/**
|
|
* Removes the node from all mappings.
|
|
*/
|
|
public void release() {
|
|
if((this != rootNode) && (!isGrouping)) {
|
|
groupings.unregisterItem(value);
|
|
|
|
if(isOpened) {
|
|
children.unregisterItem(value);
|
|
}//if//
|
|
}//if//
|
|
|
|
removeChildListeners();
|
|
}//release()//
|
|
}//SimpleNodeData//
|
|
|
|
public static class Renderer {
|
|
public Class type = null;
|
|
public CellComponent component = null;
|
|
|
|
public Renderer(Class type, CellComponent component) {
|
|
this.type = type;
|
|
this.component = component;
|
|
}//Renderer()//
|
|
}//Renderer//
|
|
|
|
/**
|
|
* Encapsulates all the data pertaining to a single column in the table component.
|
|
*/
|
|
public class ColumnData extends AbstractColumn {
|
|
/** The zero based index of this column in the set of columns. Note that this is not display order, just an identifier. */
|
|
private int index = 0;
|
|
/** The text resource for the column. */
|
|
private SingleResourceAssociation headerText = new SingleResourceAssociation(this, this, getViewContext(), ResourceAssociation.TYPE_TEXT, false, "");
|
|
/** The image resource for the column. */
|
|
private SingleResourceAssociation headerImage = new SingleResourceAssociation(this, this, getViewContext(), ResourceAssociation.TYPE_IMAGE, false, null);
|
|
/** The text resource for the cell. */
|
|
private MultiResourceAssociation cellText = new MultiResourceAssociation(this, this, getViewContext(), ResourceAssociation.TYPE_TEXT, false, null);
|
|
/** The image resource for the cell. */
|
|
private MultiResourceAssociation cellImage = new MultiResourceAssociation(this, this, getViewContext(), ResourceAssociation.TYPE_IMAGE, false, null);
|
|
/** The background color resource for the cell. */
|
|
private MultiResourceAssociation backgroundColor = new MultiResourceAssociation(this, this, getViewContext(), ResourceAssociation.TYPE_COLOR, false, null);
|
|
/** The foreground color resource for the cell. */
|
|
private MultiResourceAssociation foregroundColor = new MultiResourceAssociation(this, this, getViewContext(), ResourceAssociation.TYPE_COLOR, false, null);
|
|
/** The font resource for the cell. */
|
|
private MultiResourceAssociation font = new MultiResourceAssociation(this, this, getViewContext(), ResourceAssociation.TYPE_FONT, false, null);
|
|
/** Whether the column header is resizable. */
|
|
private boolean headerResizable = false;
|
|
/** The alginment of the column data. */
|
|
private int alignment = ALIGNMENT_LEFT;
|
|
/** The width of the column. */
|
|
private int width = 100;
|
|
/** The tool tip text for the column (String or ResourceReference). */
|
|
private Object toolTipText = null;
|
|
/** Whether the column is moveable. */
|
|
private boolean moveable = true;
|
|
/** The collection of Renderer instances in the order they were specified. */
|
|
private IList renderers = null;
|
|
/** The minimum width of the column. */
|
|
private int minimumWidth = 20;
|
|
|
|
/**
|
|
* Column constructor.
|
|
*/
|
|
public ColumnData(int index) {
|
|
this.index = index;
|
|
}//ColumnData()//
|
|
/* (non-Javadoc)
|
|
* @see com.foundation.view.IAbstractComponent#verifyThread()
|
|
*/
|
|
public void verifyThread() {
|
|
SimpleTreeTable.this.verifyThread();
|
|
}//verifyThread()//
|
|
/* (non-Javadoc)
|
|
* @see com.foundation.view.IAbstractComponent#getName()
|
|
*/
|
|
public String getName() {
|
|
return "__Column__";
|
|
}//getName()//
|
|
/* (non-Javadoc)
|
|
* @see com.foundation.tcv.swt.server.TreeComponent.AbstractColumn#registerItem(com.foundation.tcv.swt.server.RowObject)
|
|
*/
|
|
protected void registerItem(RowObject rowObject) {
|
|
super.registerItem(rowObject);
|
|
cellText.registerItem(rowObject.value, rowObject);
|
|
cellImage.registerItem(rowObject.value, rowObject);
|
|
backgroundColor.registerItem(rowObject.value, rowObject);
|
|
foregroundColor.registerItem(rowObject.value, rowObject);
|
|
font.registerItem(rowObject.value, rowObject);
|
|
|
|
if(renderers != null) {
|
|
for(int index = 0; index < renderers.getSize(); index++) {
|
|
((Renderer) renderers.get(index)).component.registerRowItem(rowObject);
|
|
((Renderer) renderers.get(index)).component.viewRefresh(rowObject);
|
|
}//for//
|
|
}//if//
|
|
}//registerItem()//
|
|
/* (non-Javadoc)
|
|
* @see com.foundation.tcv.swt.server.TreeComponent.AbstractColumn#unregisterItem(com.foundation.tcv.swt.server.RowObject)
|
|
*/
|
|
protected void unregisterItem(RowObject rowObject) {
|
|
super.unregisterItem(rowObject);
|
|
cellText.unregisterItem(rowObject.value);
|
|
cellImage.unregisterItem(rowObject.value);
|
|
backgroundColor.unregisterItem(rowObject.value);
|
|
foregroundColor.unregisterItem(rowObject.value);
|
|
font.unregisterItem(rowObject.value);
|
|
|
|
if(renderers != null) {
|
|
for(int index = 0; index < renderers.getSize(); index++) {
|
|
((Renderer) renderers.get(index)).component.unregisterRowItem(rowObject);
|
|
}//for//
|
|
}//if//
|
|
}//unregisterItem()//
|
|
/* (non-Javadoc)
|
|
* @see com.foundation.tcv.swt.server.TreeComponent.AbstractColumn#unregisterAllItems()
|
|
*/
|
|
protected void unregisterAllItems() {
|
|
super.unregisterAllItems();
|
|
cellText.unregisterAllItems();
|
|
cellImage.unregisterAllItems();
|
|
backgroundColor.unregisterAllItems();
|
|
foregroundColor.unregisterAllItems();
|
|
font.unregisterAllItems();
|
|
|
|
if(renderers != null) {
|
|
for(int index = 0; index < renderers.getSize(); index++) {
|
|
((Renderer) renderers.get(index)).component.unregisterRowItems();
|
|
}//for//
|
|
}//if//
|
|
}//unregisterAllItems()//
|
|
/* (non-Javadoc)
|
|
* @see com.foundation.tcv.swt.server.TreeComponent.AbstractColumn#refreshCellData(java.lang.Object)
|
|
*/
|
|
protected boolean refreshCellData(Object item) {
|
|
boolean result = false;
|
|
|
|
result |= cellText.refresh(item);
|
|
result |= cellImage.refresh(item);
|
|
result |= backgroundColor.refresh(item);
|
|
result |= foregroundColor.refresh(item);
|
|
result |= font.refresh(item);
|
|
|
|
return result;
|
|
}//refreshCellData()//
|
|
/* (non-Javadoc)
|
|
* @see com.foundation.tcv.swt.server.TreeComponent.AbstractColumn#getCellData(java.lang.Object)
|
|
*/
|
|
protected Object getCellData(Object item) {
|
|
CellComponent cellComponent = getCellComponent(item != null ? item.getClass() : null);
|
|
|
|
return new SimpleTreeTableCellData(cellText.getValue(item), cellImage.getValue(item), backgroundColor.getValue(item), foregroundColor.getValue(item), font.getValue(item), cellComponent != null ? cellComponent.getNumber() : -1);
|
|
}//getCellValue()//
|
|
/* (non-Javadoc)
|
|
* @see com.foundation.tcv.swt.server.TreeComponent.AbstractColumn#getIndex()
|
|
*/
|
|
protected int getIndex() {
|
|
return index;
|
|
}//getIndex()//
|
|
/* (non-Javadoc)
|
|
* @see com.foundation.tcv.swt.server.TreeComponent.AbstractColumn#setIndex(int)
|
|
*/
|
|
protected void setIndex(int index) {
|
|
this.index = index;
|
|
}//setIndex()//
|
|
/* (non-Javadoc)
|
|
* @see com.foundation.view.IAbstractComponent#getContainer()
|
|
*/
|
|
public IAbstractContainer getContainer() {
|
|
return SimpleTreeTable.this.getContainer();
|
|
}//getContainer()//
|
|
/* (non-Javadoc)
|
|
* @see com.foundation.view.IAbstractComponent#onEventFired(com.foundation.view.IEventAssociation, java.lang.Object[])
|
|
*/
|
|
public void onEventFired(IEventAssociation eventAssociation, Object[] eventArguments) {
|
|
}//onEventFired()//
|
|
/* (non-Javadoc)
|
|
* @see com.foundation.view.IAbstractComponent#onValueChanged(com.foundation.view.IAttributeAssociation)
|
|
*/
|
|
public void onValueChanged(IAttributeAssociation attributeAssociation) {
|
|
}//onValueChanged()//
|
|
/* (non-Javadoc)
|
|
* @see com.foundation.view.ISingleResourceAssociationChangeListener#addMessageHold()
|
|
*/
|
|
public void addMessageHold() {
|
|
SimpleTreeTable.this.addMessageHold();
|
|
}//addMessageHold()//
|
|
/* (non-Javadoc)
|
|
* @see com.foundation.view.ISingleResourceAssociationChangeListener#removeMessageHold()
|
|
*/
|
|
public void removeMessageHold() {
|
|
SimpleTreeTable.this.removeMessageHold();
|
|
}//removeMessageHold()//
|
|
/* (non-Javadoc)
|
|
* @see com.foundation.view.ISingleResourceAssociationChangeListener#onValueChanged(com.foundation.view.ResourceAssociation, int)
|
|
*/
|
|
public void onValueChanged(ResourceAssociation resourceAssociation, int flags) {
|
|
if(resourceAssociation instanceof SingleResourceAssociation) {
|
|
//TODO:Remove me once we verify it isn't necessary.
|
|
verifyThread();
|
|
internalOnValueChanged((SingleResourceAssociation) resourceAssociation);
|
|
}//if//
|
|
}//onValueChanged()//
|
|
/* (non-Javadoc)
|
|
* @see com.foundation.view.IMultiResourceAssociationChangeListener#onValueChanged(com.foundation.view.ResourceAssociation, java.lang.Object, java.lang.Object, boolean)
|
|
*/
|
|
public void onValueChanged(ResourceAssociation resourceAssociation, Object item, Object data, boolean isUpdate) {
|
|
if(resourceAssociation instanceof MultiResourceAssociation) {
|
|
//TODO:Remove me once we verify it isn't necessary.
|
|
verifyThread();
|
|
internalOnValueChanged((MultiResourceAssociation) resourceAssociation, item, data, isUpdate);
|
|
}//if//
|
|
}//onValueChanged()//
|
|
/* (non-Javadoc)
|
|
* @see com.foundation.view.ISingleResourceAssociationChangeListener#onModelExternallyChanged(com.foundation.view.ResourceAssociation, boolean, java.lang.Object)
|
|
*/
|
|
public void onModelExternallyChanged(ResourceAssociation resourceAssociation, boolean isCleared, Object originalValue) {
|
|
verifyThread();
|
|
|
|
if(isInitialized()) {
|
|
internalOnModelExternallyChanged((SingleResourceAssociation) resourceAssociation, isCleared, originalValue);
|
|
}//if//
|
|
}//onModelExternallyChanged()//
|
|
/* (non-Javadoc)
|
|
* @see com.foundation.view.IMultiResourceAssociationChangeListener#onModelExternallyChanged(com.foundation.view.ResourceAssociation, java.lang.Object, java.lang.Object, boolean, java.lang.Object)
|
|
*/
|
|
public void onModelExternallyChanged(ResourceAssociation resourceAssociation, Object alteredItem, Object data, boolean isCleared, Object originalValue) {
|
|
verifyThread();
|
|
|
|
if(isInitialized()) {
|
|
internalOnModelExternallyChanged((MultiResourceAssociation) resourceAssociation, alteredItem, data, isCleared, originalValue);
|
|
}//if//
|
|
}//onModelExternallyChanged()//
|
|
/* (non-Javadoc)
|
|
* @see com.foundation.view.ISingleResourceAssociationChangeListener#onValueChanged(com.foundation.view.ResourceAssociation)
|
|
*/
|
|
protected void internalOnValueChanged(ResourceAssociation resourceAssociation) {
|
|
if(resourceAssociation == headerText) {
|
|
if(headerText.refresh()) {
|
|
sendMessage(MESSAGE_SET_COLUMN_HEADER_TEXT, headerText.getValue(), null, getIndex(), -1);
|
|
}//if//
|
|
}//if//
|
|
else if(resourceAssociation == headerImage) {
|
|
if(headerImage.refresh()) {
|
|
sendMessage(MESSAGE_SET_COLUMN_HEADER_IMAGE, headerImage.getValue(), null, getIndex(), -1);
|
|
}//if//
|
|
}//else if//
|
|
}//internalOnValueChanged()//
|
|
protected void internalOnValueChanged(ResourceAssociation resourceAssociation, Object item, Object data, boolean isUpdate) {
|
|
if(isInitialized()) {
|
|
if(resourceAssociation == cellText) {
|
|
if(cellText.refresh(item)) {
|
|
if(item != null) {
|
|
sendMessage(MESSAGE_SET_CELL_TEXT, cellText.getValue(item), null, getIndex(), getRowObject(item).objectId);
|
|
}//if//
|
|
else {
|
|
//Update all cells since the association has a single value for all rows in the column.//
|
|
sendMessage(MESSAGE_SET_CELL_TEXT, cellText.getValue(null), null, getIndex(), -1);
|
|
}//else//
|
|
}//if//
|
|
}//if//
|
|
else if(resourceAssociation == cellImage) {
|
|
if(cellImage.refresh(item)) {
|
|
if(item != null) {
|
|
sendMessage(MESSAGE_SET_CELL_IMAGE, cellImage.getValue(item), null, getIndex(), getRowObject(item).objectId);
|
|
}//if//
|
|
else {
|
|
//Update all cells since the association has a single value for all rows in the column.//
|
|
sendMessage(MESSAGE_SET_CELL_IMAGE, cellImage.getValue(null), null, getIndex(), -1);
|
|
}//else//
|
|
}//if//
|
|
}//else if//
|
|
else if(resourceAssociation == backgroundColor) {
|
|
if(backgroundColor.refresh(item)) {
|
|
if(item != null) {
|
|
sendMessage(MESSAGE_SET_CELL_BACKGROUND_COLOR, backgroundColor.getValue(item), null, getIndex(), getRowObject(item).objectId);
|
|
}//if//
|
|
else {
|
|
//Update all cells since the association has a single value for all rows in the column.//
|
|
sendMessage(MESSAGE_SET_CELL_BACKGROUND_COLOR, backgroundColor.getValue(null), null, getIndex(), -1);
|
|
}//else//
|
|
}//if//
|
|
}//else if//
|
|
else if(resourceAssociation == foregroundColor) {
|
|
if(foregroundColor.refresh(item)) {
|
|
if(item != null) {
|
|
sendMessage(MESSAGE_SET_CELL_FOREGROUND_COLOR, foregroundColor.getValue(item), null, getIndex(), getRowObject(item).objectId);
|
|
}//if//
|
|
else {
|
|
//Update all cells since the association has a single value for all rows in the column.//
|
|
sendMessage(MESSAGE_SET_CELL_FOREGROUND_COLOR, foregroundColor.getValue(null), null, getIndex(), -1);
|
|
}//else//
|
|
}//if//
|
|
}//else if//
|
|
else if(resourceAssociation == font) {
|
|
if(font.refresh(item)) {
|
|
if(item != null) {
|
|
sendMessage(MESSAGE_SET_CELL_FONT, font.getValue(item), null, getIndex(), getRowObject(item).objectId);
|
|
}//if//
|
|
else {
|
|
//Update all cells since the association has a single value for all rows in the column.//
|
|
sendMessage(MESSAGE_SET_CELL_FONT, font.getValue(null), null, getIndex(), -1);
|
|
}//else//
|
|
}//if//
|
|
}//else if//
|
|
}//if//
|
|
}//internalOnValueChanged()//
|
|
/**
|
|
* Called by the resource association (target ONLY) when the underlying model has changed, but a user's change is overriding it.
|
|
* @param resourceAssociation The resource association used to register with the resource.
|
|
* @param alteredItem The row item for the row being altered.
|
|
* @param originalValue The original value.
|
|
*/
|
|
protected void internalOnModelExternallyChanged(MultiResourceAssociation resourceAssociation, Object alteredItem, Object data, boolean isCleared, Object originalValue) {
|
|
}//internalOnModelExternallyChanged()//
|
|
/**
|
|
* Called by the resource association (target ONLY) when the underlying model has changed, but a user's change is overriding it.
|
|
* @param resourceAssociation The resource association used to register with the resource.
|
|
* @param originalValue The original value.
|
|
*/
|
|
protected void internalOnModelExternallyChanged(SingleResourceAssociation resourceAssociation, boolean isCleared, Object originalValue) {
|
|
}//internalOnModelValueChanged()//
|
|
/* (non-Javadoc)
|
|
* @see com.foundation.tcv.swt.server.TreeComponent.AbstractColumn#initialize()
|
|
*/
|
|
protected void initialize() {
|
|
headerText.initialize();
|
|
headerImage.initialize();
|
|
cellText.initialize();
|
|
cellImage.initialize();
|
|
backgroundColor.initialize();
|
|
foregroundColor.initialize();
|
|
font.initialize();
|
|
}//initialize()//
|
|
/* (non-Javadoc)
|
|
* @see com.foundation.tcv.swt.server.TreeComponent.AbstractColumn#refresh()
|
|
*/
|
|
protected void refresh() {
|
|
//Force the header data to refresh since it gets set after sending the new header message to the client.//
|
|
if(headerText.refresh()) {
|
|
sendMessage(MESSAGE_SET_COLUMN_HEADER_TEXT, headerText.getValue(), null, getIndex(), -1);
|
|
}//if//
|
|
|
|
if(headerImage.refresh()) {
|
|
sendMessage(MESSAGE_SET_COLUMN_HEADER_IMAGE, headerImage.getValue(), null, getIndex(), -1);
|
|
}//if//
|
|
}//refresh()//
|
|
/* (non-Javadoc)
|
|
* @see com.foundation.tcv.swt.server.TreeComponent.AbstractColumn#release()
|
|
*/
|
|
protected void release() {
|
|
unregisterAllItems();
|
|
headerText.release();
|
|
headerImage.release();
|
|
cellText.release();
|
|
cellImage.release();
|
|
backgroundColor.release();
|
|
foregroundColor.release();
|
|
font.release();
|
|
}//release()//
|
|
/**
|
|
* Determines whether the column header is resizable by the user.
|
|
* @param headerResizable Whether the header is resizable.
|
|
*/
|
|
public void setHeaderResizeable(boolean headerResizable) {
|
|
if(this.headerResizable != headerResizable) {
|
|
this.headerResizable = headerResizable;
|
|
sendMessage(MESSAGE_SET_HEADER_RESIZEABLE, new Object[] {new Integer(index), headerResizable ? Boolean.TRUE : Boolean.FALSE});
|
|
}//if//
|
|
}//setHeadersResizeable()//
|
|
/**
|
|
* Sets the columns alignment.
|
|
* @param alignment The column's alignment
|
|
*/
|
|
public void setAlignment(int alignment) {
|
|
if(this.alignment != alignment) {
|
|
this.alignment = alignment;
|
|
sendMessage(MESSAGE_SET_COLUMN_ALIGNMENT, new int[] {index, alignment});
|
|
}//if//
|
|
}//setAlignment()//
|
|
/**
|
|
* Sets the column's width.
|
|
* @param width The number of pixels of width for the column.
|
|
*/
|
|
public void setWidth(int width) {
|
|
if(this.width != width) {
|
|
this.width = width;
|
|
sendMessage(MESSAGE_SET_COLUMN_WIDTH, new int[] {index, width});
|
|
}//if//
|
|
}//setWidth()//
|
|
/**
|
|
* Gets the column's minimum width.
|
|
* @return The minimum number of pixels of width for the column.
|
|
*/
|
|
public int getMinimumWidth() {
|
|
return minimumWidth;
|
|
}//getMinimumWidth()//
|
|
/**
|
|
* Sets the column's minimum width.
|
|
* @param width The minimum number of pixels of width for the column.
|
|
*/
|
|
public void setMinimumWidth(int minimumWidth) {
|
|
if(this.minimumWidth != minimumWidth) {
|
|
this.minimumWidth = minimumWidth;
|
|
|
|
sendMessage(MESSAGE_SET_COLUMN_MINIMUM_WIDTH, null, null, index, minimumWidth);
|
|
}//if//
|
|
}//setMinimumWidth()//
|
|
/**
|
|
* Sets the column's tool tip text.
|
|
* @param toolTipText The tool tip for the column.
|
|
*/
|
|
public void setToolTipText(String toolTipText) {
|
|
if(this.toolTipText != toolTipText) {
|
|
this.toolTipText = toolTipText;
|
|
sendMessage(MESSAGE_SET_COLUMN_TOOL_TIP, toolTipText, null, index, -1);
|
|
}//if//
|
|
}//setToolTipText()//
|
|
/**
|
|
* Sets the column's tool tip text.
|
|
* @param toolTipText The tool tip for the column.
|
|
*/
|
|
public void setToolTipText(ResourceReference toolTipText) {
|
|
if(this.toolTipText != toolTipText) {
|
|
this.toolTipText = toolTipText;
|
|
sendMessage(MESSAGE_SET_COLUMN_TOOL_TIP, toolTipText, null, index, -1);
|
|
}//if//
|
|
}//setToolTipText()//
|
|
/**
|
|
* Sets whether the column is moveable by the user.
|
|
* @param moveable Whether the column can be moved.
|
|
*/
|
|
public void setMoveable(boolean moveable) {
|
|
if(this.moveable != moveable) {
|
|
this.moveable = moveable;
|
|
sendMessage(MESSAGE_SET_COLUMN_MOVEABLE, new Object[] {new Integer(index), moveable ? Boolean.TRUE : Boolean.FALSE});
|
|
}//if//
|
|
}//setMoveable()//
|
|
/**
|
|
* Sets the column's default header text which is used when no other text is available.
|
|
* @param headerText The column's default header text.
|
|
*/
|
|
public void setHeaderText(String headerText) {
|
|
verifyThread();
|
|
this.headerText.setDefaultValue(headerText);
|
|
}//setHeaderText()//
|
|
/**
|
|
* Sets the column's default header text which is used when no other text is available.
|
|
* @param headerText The column's default header text.
|
|
*/
|
|
public void setHeaderText(ResourceReference headerText) {
|
|
verifyThread();
|
|
this.headerText.setDefaultValue(headerText);
|
|
}//setHeaderText()//
|
|
/**
|
|
* Sets the column's default header image which is used when no other image is available.
|
|
* @param headerImage The column's default header image.
|
|
*/
|
|
public void setHeaderImage(JefImage headerImage) {
|
|
verifyThread();
|
|
this.headerImage.setDefaultValue(headerImage);
|
|
}//setHeaderImage()//
|
|
/**
|
|
* Sets the column's default header image which is used when no other image is available.
|
|
* @param headerImage The column's default header image.
|
|
*/
|
|
public void setHeaderImage(ResourceReference headerImage) {
|
|
verifyThread();
|
|
this.headerImage.setDefaultValue(headerImage);
|
|
}//setHeaderImage()//
|
|
/**
|
|
* Sets the column's default cell text which is used when no other text is available.
|
|
* @param cellText The column's default cell text.
|
|
*/
|
|
public void setCellText(String cellText) {
|
|
verifyThread();
|
|
this.cellText.setDefaultValue(cellText);
|
|
}//setCellText()//
|
|
/**
|
|
* Sets the column's default cell image which is used when no other image is available.
|
|
* @param cellImage The column's default cell image.
|
|
*/
|
|
public void setCellImage(JefImage cellImage) {
|
|
verifyThread();
|
|
this.cellImage.setDefaultValue(cellImage);
|
|
}//setCellImage()//
|
|
/**
|
|
* Sets the column's default cell image which is used when no other image is available.
|
|
* @param cellImage The column's default cell image.
|
|
*/
|
|
public void setCellImage(ResourceReference cellImage) {
|
|
verifyThread();
|
|
this.cellImage.setDefaultValue(cellImage);
|
|
}//setCellImage()//
|
|
/**
|
|
* Sets the column's default background color which is used when no other background color is available.
|
|
* @param backgroundColor The column's default background color.
|
|
*/
|
|
public void setBackgroundColor(JefColor backgroundColor) {
|
|
verifyThread();
|
|
this.backgroundColor.setDefaultValue(backgroundColor);
|
|
}//setBackgroundColor()//
|
|
/**
|
|
* Sets the column's default background color which is used when no other background color is available.
|
|
* @param backgroundColor The column's default background color.
|
|
*/
|
|
public void setBackgroundColor(ResourceReference backgroundColor) {
|
|
verifyThread();
|
|
this.backgroundColor.setDefaultValue(backgroundColor);
|
|
}//setBackgroundColor()//
|
|
/**
|
|
* Sets the column's default background color which is used when no other font is available.
|
|
* @param font The column's default font.
|
|
*/
|
|
public void setFont(JefFont[] font) {
|
|
verifyThread();
|
|
this.font.setDefaultValue(font);
|
|
}//setFont()//
|
|
/**
|
|
* Sets the column's default background color which is used when no other font is available.
|
|
* @param font The column's default font.
|
|
*/
|
|
public void setFont(ResourceReference font) {
|
|
verifyThread();
|
|
this.font.setDefaultValue(font);
|
|
}//setFont()//
|
|
/**
|
|
* Sets the column's default background color which is used when no other foreground color is available.
|
|
* @param foregroundColor The column's default foreground color.
|
|
*/
|
|
public void setForegroundColor(JefColor foregroundColor) {
|
|
verifyThread();
|
|
this.foregroundColor.setDefaultValue(foregroundColor);
|
|
}//setForegroundColor()//
|
|
/**
|
|
* Sets the column's default background color which is used when no other foreground color is available.
|
|
* @param foregroundColor The column's default foreground color.
|
|
*/
|
|
public void setForegroundColor(ResourceReference foregroundColor) {
|
|
verifyThread();
|
|
this.foregroundColor.setDefaultValue(foregroundColor);
|
|
}//setForegroundColor()//
|
|
/**
|
|
* Sets the association container used to access the header text.
|
|
* @param container The header text association metadata.
|
|
*/
|
|
public void setHeaderTextAssociation(SingleAssociationContainer container) {
|
|
verifyThread();
|
|
this.headerText.setAssociations(container);
|
|
}//setHeaderTextAssociation()//
|
|
/**
|
|
* Sets the association container used to access the header image.
|
|
* @param container The header image association metadata.
|
|
*/
|
|
public void setHeaderImageAssociation(SingleAssociationContainer container) {
|
|
verifyThread();
|
|
this.headerImage.setAssociations(container);
|
|
}//setHeaderImageAssociation()//
|
|
/**
|
|
* Sets the association container used to access the cell text.
|
|
* @param container The cell text association metadata.
|
|
*/
|
|
public void setCellTextAssociation(MultiAssociationContainer container) {
|
|
verifyThread();
|
|
this.cellText.setAssociations(container);
|
|
}//setCellTextAssociation()//
|
|
/**
|
|
* Sets the association container used to access the cell image.
|
|
* @param container The cell image association metadata.
|
|
*/
|
|
public void setCellImageAssociation(MultiAssociationContainer container) {
|
|
verifyThread();
|
|
this.cellImage.setAssociations(container);
|
|
}//setCellImageAssociation()//
|
|
/**
|
|
* Sets the association container used to access the background color.
|
|
* @param container The background color association metadata.
|
|
*/
|
|
public void setBackgroundColorAssociation(MultiAssociationContainer container) {
|
|
verifyThread();
|
|
this.backgroundColor.setAssociations(container);
|
|
}//setBackgroundColorAssociation()//
|
|
/**
|
|
* Sets the association container used to access the foreground color.
|
|
* @param container The foreground color association metadata.
|
|
*/
|
|
public void setForegroundColorAssociation(MultiAssociationContainer container) {
|
|
verifyThread();
|
|
this.foregroundColor.setAssociations(container);
|
|
}//setForegroundColorAssociation()//
|
|
/**
|
|
* Sets the association container used to access the font.
|
|
* @param container The font association metadata.
|
|
*/
|
|
public void setFontAssociation(MultiAssociationContainer container) {
|
|
verifyThread();
|
|
this.font.setAssociations(container);
|
|
}//setFontAssociation()//
|
|
/**
|
|
* Adds a cell component to the column for use with rows that match the given type name.
|
|
* @param typeName The name of the class associated with the rows that will use the component to display cell data.
|
|
* @param component The component that lets the user view and optionally interact with cell data.
|
|
*/
|
|
public void addCellComponent(Class type, CellComponent component) {
|
|
if(renderers == null) {
|
|
renderers = new LiteList(5, 20);
|
|
}//if//
|
|
|
|
renderers.add(new Renderer(type, component));
|
|
}//addCellComponent()//
|
|
/**
|
|
* Gets the cell component for the given row type.
|
|
* @param rowType The type of data displayed on the row for which the cell component will be used.
|
|
* @return The cell component used to render and optionally interact with the cell data. This may be null in which case the default rendering will be used.
|
|
*/
|
|
public CellComponent getCellComponent(Class rowType) {
|
|
CellComponent result = null;
|
|
|
|
if(renderers != null) {
|
|
for(int index = 0; (result == null) && (index < renderers.getSize()); index++) {
|
|
Renderer renderer = (Renderer) renderers.get(index);
|
|
|
|
if(renderer.type.isAssignableFrom(rowType)) {
|
|
result = renderer.component;
|
|
}//if//
|
|
}//for//
|
|
}//if//
|
|
|
|
return result;
|
|
}//getCellComponent()//
|
|
/* (non-Javadoc)
|
|
* @see com.foundation.view.IMultiResourceAssociationChangeListener#getResourceService()
|
|
*/
|
|
public AbstractResourceService getResourceService() {
|
|
return SimpleTreeTable.this.getResourceService();
|
|
}//getResourceService()//
|
|
/* (non-Javadoc)
|
|
* @see com.foundation.view.ISingleResourceAssociationChangeListener#getDecorationManager()
|
|
*/
|
|
public DecorationManager getDecorationManager() {
|
|
return SimpleTreeTable.this.getDecorationManager();
|
|
}//getDecorationManager()//
|
|
/* (non-Javadoc)
|
|
* @see com.foundation.view.ISingleResourceAssociationChangeListener#addDecoration(com.foundation.view.AbstractDecoration)
|
|
*/
|
|
public void addDecoration(AbstractDecoration decoration) {
|
|
}//addDecoration()//
|
|
/* (non-Javadoc)
|
|
* @see com.foundation.view.ISingleResourceAssociationChangeListener#removeDecoration(com.foundation.view.AbstractDecoration)
|
|
*/
|
|
public void removeDecoration(AbstractDecoration decoration) {
|
|
}//removeDecoration()//
|
|
/* (non-Javadoc)
|
|
* @see com.foundation.view.IMultiResourceAssociationChangeListener#addDecoration(com.foundation.view.ResourceAssociation, java.lang.Object, java.lang.Object, com.foundation.view.AbstractDecoration)
|
|
*/
|
|
public void addDecoration(ResourceAssociation association, Object row, Object data, AbstractDecoration decoration) {
|
|
//TODO: Finish.
|
|
}//addDecoration()//
|
|
/* (non-Javadoc)
|
|
* @see com.foundation.view.IMultiResourceAssociationChangeListener#removeDecoration(com.foundation.view.ResourceAssociation, java.lang.Object, java.lang.Object, com.foundation.view.AbstractDecoration)
|
|
*/
|
|
public void removeDecoration(ResourceAssociation association, Object row, Object data, AbstractDecoration decoration) {
|
|
//TODO: Finish.
|
|
}//removeDecoration()//
|
|
}//ColumnData//
|
|
/**
|
|
* SimpleTreeTable constructor.
|
|
* <p>Not Supported Styles (Yet): STYLE_CHECK, STYLE_VIRTUAL</p>
|
|
* @param parent The parent container for this component.
|
|
* @param name The name of the component.
|
|
* @param style The style of control to construct.
|
|
* @see #STYLE_MULTI
|
|
* @see #STYLE_SINGLE
|
|
* @see #STYLE_FULL_SELECTION
|
|
* @see #STYLE_HIDE_SELECTION
|
|
*/
|
|
public SimpleTreeTable(Container parent, String name, int style) {
|
|
super(parent, name, style);
|
|
allowMultiSelection = ((style & STYLE_MULTI) > 0);
|
|
sendMessage(MESSAGE_INITIALIZE, new int[] {parent.getNumber(), style});
|
|
}//SimpleTreeTable()//
|
|
/**
|
|
* Adjusts the visible range of items to show some or all of the selections.
|
|
*/
|
|
public void showSelection() {
|
|
sendMessage(MESSAGE_SHOW_SELECTION, null);
|
|
}//showSelection()//
|
|
/**
|
|
* Sets the component's default background color.
|
|
* @param backgroundColor The default background color.
|
|
*/
|
|
public void setRowBackgroundColor(JefColor backgroundColor) {
|
|
verifyThread();
|
|
this.rowBackgroundColor.setDefaultValue(backgroundColor);
|
|
}//setRowHeaderBackgroundColor()//
|
|
/**
|
|
* Sets the component's default background color.
|
|
* @param backgroundColor The default background color.
|
|
*/
|
|
public void setRowBackgroundColor(ResourceReference backgroundColor) {
|
|
verifyThread();
|
|
this.rowBackgroundColor.setDefaultValue(backgroundColor);
|
|
}//setRowHeaderBackgroundColor()//
|
|
/**
|
|
* Sets the component's default foreground color.
|
|
* @param foregroundColor The default foreground color.
|
|
*/
|
|
public void setRowForegroundColor(JefColor foregroundColor) {
|
|
verifyThread();
|
|
this.rowForegroundColor.setDefaultValue(foregroundColor);
|
|
}//setRowHeaderForegroundColor()//
|
|
/**
|
|
* Sets the component's default foreground color.
|
|
* @param foregroundColor The default foreground color.
|
|
*/
|
|
public void setRowForegroundColor(ResourceReference foregroundColor) {
|
|
verifyThread();
|
|
this.rowForegroundColor.setDefaultValue(foregroundColor);
|
|
}//setRowHeaderForegroundColor()//
|
|
/**
|
|
* Sets the font for the row header. This will be the default font if there is a font attribute associated with this component.
|
|
* @param font The default font metadata.
|
|
*/
|
|
public void setRowFont(JefFont[] font) {
|
|
verifyThread();
|
|
this.rowFont.setDefaultValue(font);
|
|
}//setRowHeaderFont()//
|
|
/**
|
|
* Sets the font for the row header. This will be the default font if there is a font attribute associated with this component.
|
|
* @param font The default font metadata.
|
|
*/
|
|
public void setRowFont(ResourceReference font) {
|
|
verifyThread();
|
|
this.rowFont.setDefaultValue(font);
|
|
}//setRowHeaderFont()//
|
|
/**
|
|
* Sets the height for the rows.
|
|
* @param height The row height in pixels.
|
|
*/
|
|
public void setRowHeight(Integer height) {
|
|
verifyThread();
|
|
this.rowHeight.setDefaultValue(height);
|
|
}//setRowHeight()//
|
|
/**
|
|
* Sets the association container used to access the row background color.
|
|
* @param container The row background color association metadata.
|
|
*/
|
|
public void setRowBackgroundColorAssociation(MultiAssociationContainer container) {
|
|
verifyThread();
|
|
this.rowBackgroundColor.setAssociations(container);
|
|
}//setRowBackgroundColorAssociation()//
|
|
/**
|
|
* Sets the association container used to access the row foreground color.
|
|
* @param container The row foreground color association metadata.
|
|
*/
|
|
public void setRowForegroundColorAssociation(MultiAssociationContainer container) {
|
|
verifyThread();
|
|
this.rowForegroundColor.setAssociations(container);
|
|
}//setRowForegroundColorAssociation()//
|
|
/**
|
|
* Sets the association container used to access the row font.
|
|
* @param container The row font association metadata.
|
|
*/
|
|
public void setRowFontAssociation(MultiAssociationContainer container) {
|
|
verifyThread();
|
|
this.rowFont.setAssociations(container);
|
|
}//setRowFontAssociation()//
|
|
/**
|
|
* Sets the association container used to access the row height.
|
|
* @param container The row font association metadata.
|
|
*/
|
|
public void setRowHeightAssociation(SingleAssociationContainer container) {
|
|
verifyThread();
|
|
this.rowHeight.setAssociations(container);
|
|
}//setRowHeightAssociation()//
|
|
/**
|
|
* Sets the association container used to access the row's groupings.
|
|
* @param container The grouping association metadata.
|
|
*/
|
|
public void setGroupAssociation(CollectingMultiAssociationContainer container) {
|
|
verifyThread();
|
|
this.groupings.setAssociations(container);
|
|
}//setGroupAssociation()//
|
|
/**
|
|
* Sets the association container used to access the row's children.
|
|
* @param container The children association metadata.
|
|
*/
|
|
public void setChildAssociation(CollectingMultiAssociationContainer container) {
|
|
verifyThread();
|
|
this.children.setAssociations(container);
|
|
}//setChildAssociation()//
|
|
/**
|
|
* Gets whether resizeable columns will be called upon to fit the control's client space when the control resizes or a column resizes.
|
|
* @return Whether resizeable columns will be told to fit available space.
|
|
*/
|
|
public boolean getAutoFit() {
|
|
return autoFit;
|
|
}//getAutoFill()//
|
|
/**
|
|
* Sets whether resizeable columns will be called upon to fit the control's client space when the control resizes or a column resizes.
|
|
* @param autoFit Whether resizeable columns will be told to fit available space.
|
|
*/
|
|
public void setAutoFit(boolean autoFit) {
|
|
this.autoFit = autoFit;
|
|
sendMessage(MESSAGE_SET_AUTO_FIT, autoFit ? Boolean.TRUE : Boolean.FALSE);
|
|
}//setAutoFit()//
|
|
/**
|
|
* Gets whether resizeable columns will be streched to fill available space during the control's initialization.
|
|
* @return Whether resizeable columns will be expanded to fill in empty space.
|
|
*/
|
|
public boolean getFillOnInitialize() {
|
|
return fillOnInitialize;
|
|
}//getFillOnInitialize()//
|
|
/**
|
|
* Sets whether resizeable columns will be streched to fill available space during the control's initialization.
|
|
* @param fillOnInitialize Whether resizeable columns will be expanded to fill in empty space.
|
|
*/
|
|
public void setFillOnInitialize(boolean fillOnInitialize) {
|
|
this.fillOnInitialize = fillOnInitialize;
|
|
sendMessage(MESSAGE_SET_FILL_ON_INITIALIZE, fillOnInitialize ? Boolean.TRUE : Boolean.FALSE);
|
|
}//setFillOnInitialize()//
|
|
/**
|
|
* Gets whether resizeable columns will be streched to fill available space when resizing the control.
|
|
* @return Whether resizeable columns will be expanded to fill in empty space.
|
|
*/
|
|
public boolean getFillOnResize() {
|
|
return fillOnResize;
|
|
}//getFillOnResize()//
|
|
/**
|
|
* Sets whether resizeable columns will be streched to fill available space when resizing the control.
|
|
* @param fillOnResize Whether resizeable columns will be expanded to fill in empty space.
|
|
*/
|
|
public void setFillOnResize(boolean fillOnResize) {
|
|
this.fillOnResize = fillOnResize;
|
|
sendMessage(MESSAGE_SET_FILL_ON_RESIZE, fillOnResize ? Boolean.TRUE : Boolean.FALSE);
|
|
}//setFillOnResize()//
|
|
/**
|
|
* Adds an association for the fit event.
|
|
* @param association The association.
|
|
*/
|
|
public void addFitEventAssociation(IEventAssociation association) {
|
|
if(fitEventAssociations == null) {
|
|
fitEventAssociations = new LiteHashSet(4);
|
|
}//if//
|
|
|
|
association.setChangeListener(this);
|
|
fitEventAssociations.add(association);
|
|
|
|
if(isInitialized()) {
|
|
association.register();
|
|
}//if//
|
|
}//setFitEventAssociation()//
|
|
/**
|
|
* Adds an association for the fill event.
|
|
* @param association The association.
|
|
*/
|
|
public void addFillEventAssociation(IEventAssociation association) {
|
|
if(fillEventAssociations == null) {
|
|
fillEventAssociations = new LiteHashSet(4);
|
|
}//if//
|
|
|
|
association.setChangeListener(this);
|
|
fillEventAssociations.add(association);
|
|
|
|
if(isInitialized()) {
|
|
association.register();
|
|
}//if//
|
|
}//setFillEventAssociation()//
|
|
/**
|
|
* Determines whether the view manages the sorting of data.
|
|
* <p>TODO: Enable this again if we allow server side sorting.</p>
|
|
* @param inViewSorting Whether the view should handle data sorting, otherwise the model will handle it.
|
|
*/
|
|
public void setInViewSorting(boolean inViewSorting) {
|
|
//this.inViewSorting = inViewSorting;
|
|
//Tell the client to update.//
|
|
sendMessage(MESSAGE_IN_VIEW_SORTING, inViewSorting ? Boolean.TRUE : Boolean.FALSE);
|
|
}//setInViewSorting()//
|
|
/**
|
|
* Determines whether multiple selections are allowed.
|
|
* @return Whether the user may make multiple collection selections.
|
|
*/
|
|
protected boolean allowMultiSelection() {
|
|
return allowMultiSelection;
|
|
}//allowMultiSelection()//
|
|
/**
|
|
* Determines whether to show the header.
|
|
* @param showHeader Whether the header is visible.
|
|
*/
|
|
public void showHeaders(boolean showHeader) {
|
|
if(this.showHeader != showHeader) {
|
|
this.showHeader = showHeader;
|
|
sendMessage(MESSAGE_SHOW_HEADERS, showHeader ? Boolean.TRUE : Boolean.FALSE);
|
|
}//if//
|
|
}//showHeaders()//
|
|
/**
|
|
* Determines whether to show the grid lines.
|
|
* @param showGridLines Whether the grid lines are visible.
|
|
*/
|
|
public void showGridLines(boolean showGridLines) {
|
|
if(this.showGridLines != showGridLines) {
|
|
this.showGridLines = showGridLines;
|
|
sendMessage(MESSAGE_SHOW_GRID_LINES, showGridLines ? Boolean.TRUE : Boolean.FALSE);
|
|
}//if//
|
|
}//showGridLines()//
|
|
/**
|
|
* Adds a new column to the right of the existing columns.
|
|
* <p>Note: I have not yet allowed the removal of columns or addition of columns at specific indices.</p>
|
|
* @return The column that was added. This can be used to setup the column's display properties.
|
|
*/
|
|
public ColumnData addColumn() {
|
|
ColumnData result = new ColumnData(getColumnCount());
|
|
|
|
addColumn(result);
|
|
|
|
return result;
|
|
}//addColumn()//
|
|
/* (non-Javadoc)
|
|
* @see com.foundation.tcv.swt.server.AbstractComponent#internalViewInitialize()
|
|
*/
|
|
protected void internalViewInitialize() {
|
|
children.initialize();
|
|
groupings.initialize();
|
|
rowBackgroundColor.initialize();
|
|
rowFont.initialize();
|
|
rowForegroundColor.initialize();
|
|
rowHeight.initialize();
|
|
super.internalViewInitialize();
|
|
|
|
if(fillEventAssociations != null) {
|
|
IIterator iterator = fillEventAssociations.iterator();
|
|
|
|
while(iterator.hasNext()) {
|
|
((IEventAssociation) iterator.next()).register();
|
|
}//while//
|
|
}//if//
|
|
|
|
if(fitEventAssociations != null) {
|
|
IIterator iterator = fitEventAssociations.iterator();
|
|
|
|
while(iterator.hasNext()) {
|
|
((IEventAssociation) iterator.next()).register();
|
|
}//while//
|
|
}//if//
|
|
}//internalViewInitialize()//
|
|
/* (non-Javadoc)
|
|
* @see com.foundation.tcv.swt.server.AbstractComponent#internalViewRelease()
|
|
*/
|
|
protected void internalViewRelease() {
|
|
children.release();
|
|
groupings.release();
|
|
rowBackgroundColor.release();
|
|
rowFont.release();
|
|
rowForegroundColor.release();
|
|
rowHeight.release();
|
|
|
|
if(fillEventAssociations != null) {
|
|
IIterator iterator = fillEventAssociations.iterator();
|
|
|
|
while(iterator.hasNext()) {
|
|
((IEventAssociation) iterator.next()).unregister();
|
|
}//while//
|
|
}//if//
|
|
|
|
if(fitEventAssociations != null) {
|
|
IIterator iterator = fitEventAssociations.iterator();
|
|
|
|
while(iterator.hasNext()) {
|
|
((IEventAssociation) iterator.next()).unregister();
|
|
}//while//
|
|
}//if//
|
|
|
|
super.internalViewRelease();
|
|
}//internalViewRelease()//
|
|
/* (non-Javadoc)
|
|
* @see com.foundation.tcv.swt.server.TreeComponent#internalViewRefresh()
|
|
*/
|
|
protected void internalViewRefresh() {
|
|
internalViewRefreshRowHeight();
|
|
super.internalViewRefresh();
|
|
}//internalViewRefresh()//
|
|
/**
|
|
* Refreshes the component's row height.
|
|
*/
|
|
protected void internalViewRefreshRowHeight() {
|
|
if(rowHeight.refresh()) {
|
|
Integer height = (Integer) rowHeight.getValue();
|
|
|
|
if(height != null) {
|
|
//TODO: Reset to the default height if null but was previously non-null.//
|
|
sendMessage(MESSAGE_SET_ROW_HEIGHT, height, null, -1, -1);
|
|
}//if//
|
|
}//if//
|
|
}//internalViewRefreshRowHeight()//
|
|
/* (non-Javadoc)
|
|
* @see com.foundation.tcv.swt.server.Component#internalOnEventFired(com.foundation.view.IEventAssociation, java.lang.Object[])
|
|
*/
|
|
protected void internalOnEventFired(IEventAssociation eventAssociation, Object[] eventArguments) {
|
|
if((fillEventAssociations != null) && (fillEventAssociations.containsValue(eventAssociation))) {
|
|
sendMessage(MESSAGE_FILL, null);
|
|
}//if//
|
|
else if((fitEventAssociations != null) && (fitEventAssociations.containsValue(eventAssociation))) {
|
|
sendMessage(MESSAGE_FIT, null);
|
|
}//else if//
|
|
else {
|
|
super.internalOnEventFired(eventAssociation, eventArguments);
|
|
}//else//
|
|
}//internalOnEventFired()//
|
|
/* (non-Javadoc)
|
|
* @see com.foundation.tcv.swt.server.CollectionComponent#internalOnValueChanged(com.foundation.view.SingleResourceAssociation)
|
|
*/
|
|
protected void internalOnValueChanged(SingleResourceAssociation resourceAssociation, int flags) {
|
|
if(resourceAssociation == rowHeight) {
|
|
internalViewRefreshRowHeight();
|
|
}//if//
|
|
else {
|
|
super.internalOnValueChanged(resourceAssociation, flags);
|
|
}//else//
|
|
}//internalOnValueChanged()//
|
|
/* (non-Javadoc)
|
|
* @see com.foundation.tcv.swt.server.AbstractComponent#internalOnValueChanged(com.foundation.view.CollectingMultiResourceAssociation, java.lang.Object)
|
|
*/
|
|
protected void internalOnValueChanged(CollectingMultiResourceAssociation resourceAssociation, Object item, Object data) {
|
|
if(isInitialized()) {
|
|
if(resourceAssociation == children) {
|
|
//Verify that the item cell data has actually been altered.//
|
|
if(children.refresh(item)) {
|
|
SimpleNodeData node = (SimpleNodeData) getRowObject(item);
|
|
|
|
if(node != null) {
|
|
if(node.sendChildUpdates()) {
|
|
//TODO: Should the client or server retain any open node state?
|
|
//TODO: Place a message hold.
|
|
pruneAllChildren(node, false);
|
|
openNode(node);
|
|
}//if//
|
|
}//if//
|
|
else {
|
|
Debug.log("Internal Error: Failed to locate a node by its item.");
|
|
}//else//
|
|
}//if//
|
|
}//if//
|
|
else if(resourceAssociation == groupings) {
|
|
IList oldGroupings = groupings.getValues(item, null); //TODO: Reuse list.
|
|
|
|
//Verify that the item cell data has actually been altered.//
|
|
if(groupings.refresh(item)) {
|
|
SimpleNodeData node = (SimpleNodeData) getRowObject(item);
|
|
|
|
regroupItem(node, oldGroupings, groupings.getValues(item, null)); //TODO: Reuse list.
|
|
}//if//
|
|
}//else if//
|
|
else {
|
|
super.internalOnValueChanged(resourceAssociation, item, data);
|
|
}//else//
|
|
}//if//
|
|
}//internalOnValueChanged()//
|
|
/* (non-Javadoc)
|
|
* @see com.foundation.tcv.swt.server.AbstractComponent#internalOnValueChanged(com.foundation.view.MultiResourceAssociation, java.lang.Object)
|
|
*/
|
|
protected void internalOnValueChanged(MultiResourceAssociation resourceAssociation, Object item, Object data, boolean isUpdate) {
|
|
if(isInitialized()) {
|
|
if(resourceAssociation == rowBackgroundColor) {
|
|
//Verify that the item cell data has actually been altered.//
|
|
if(rowBackgroundColor.refresh(item)) {
|
|
SimpleNodeData node = (SimpleNodeData) getRowObject(item);
|
|
|
|
sendMessage(MESSAGE_SET_ROW_BACKGROUND_COLOR, rowBackgroundColor.getValue(item), null, node.objectId, -1);
|
|
}//if//
|
|
}//if//
|
|
else if(resourceAssociation == rowForegroundColor) {
|
|
//Verify that the item cell data has actually been altered.//
|
|
if(rowForegroundColor.refresh(item)) {
|
|
SimpleNodeData node = (SimpleNodeData) getRowObject(item);
|
|
|
|
sendMessage(MESSAGE_SET_ROW_FOREGROUND_COLOR, rowForegroundColor.getValue(item), null, node.objectId, -1);
|
|
}//if//
|
|
}//else if//
|
|
else if(resourceAssociation == rowFont) {
|
|
//Verify that the item cell data has actually been altered.//
|
|
if(rowFont.refresh(item)) {
|
|
SimpleNodeData node = (SimpleNodeData) getRowObject(item);
|
|
|
|
sendMessage(MESSAGE_SET_ROW_FONT, rowFont.getValue(item), null, node.objectId, -1);
|
|
}//if//
|
|
}//else if//
|
|
else {
|
|
super.internalOnValueChanged(resourceAssociation, item, data, isUpdate);
|
|
}//else//
|
|
}//if//
|
|
}//internalOnValueChanged()//
|
|
/* (non-Javadoc)
|
|
* @see com.foundation.tcv.swt.server.CollectionComponent#internalViewRefreshSelection(java.lang.Object)
|
|
*/
|
|
protected void internalViewRefreshSelection(Object selectedItem) {
|
|
if(selectedItem != null) {
|
|
SimpleNodeData treeNode = (SimpleNodeData) getRowObject(selectedItem);
|
|
|
|
if(treeNode == null) {
|
|
isSelectionInvalid = true;
|
|
sendMessage(MESSAGE_SET_SELECTION, null);
|
|
}//if//
|
|
else {
|
|
isSelectionInvalid = false;
|
|
sendMessage(MESSAGE_SET_SELECTION, new int[] {treeNode.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();
|
|
SimpleNodeData treeNode = (SimpleNodeData) getRowObject(selection);
|
|
|
|
if(treeNode == null) {
|
|
//TODO: Check the currently selected node's children if they haven't been loaded yet.
|
|
//TODO: Search the entire tree of closed nodes for the node - ensure we don't encounter recursion in the tree.
|
|
|
|
//An invalid selection because the selection is not in the collection of displayed values.//
|
|
selectionIterator.remove();
|
|
}//if//
|
|
else {
|
|
selectionObjectIds.add(treeNode.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#createRowObject(java.lang.Object, int)
|
|
*/
|
|
protected RowObject createRowObject(Object item, int objectId) {
|
|
return new SimpleNodeData(item, objectId);
|
|
}//createRowObject()//
|
|
/* (non-Javadoc)
|
|
* @see com.foundation.tcv.swt.server.CollectionComponent#primaryCollectionItemAdded(java.lang.Object, int)
|
|
*/
|
|
protected void primaryCollectionItemAdded(Object item, int itemIndex) {
|
|
placeItem(rootNode, item);
|
|
}//primaryCollectionItemAdded()//
|
|
/* (non-Javadoc)
|
|
* @see com.foundation.tcv.swt.server.CollectionComponent#primaryCollectionItemRemoved(java.lang.Object, int)
|
|
*/
|
|
protected void primaryCollectionItemRemoved(Object item, int index) {
|
|
SimpleNodeData node = (SimpleNodeData) getRowObject(item);
|
|
|
|
if(node != null) {
|
|
pruneNode(rootNode, node);
|
|
}//if//
|
|
else {
|
|
Debug.log(new RuntimeException("Internal Tree Error: Couldn't find the requested node."));
|
|
}//else//
|
|
}//primaryCollectionItemRemoved()//
|
|
/* (non-Javadoc)
|
|
* @see com.foundation.tcv.swt.server.CollectionComponent#primaryCollectionItemsRemoved()
|
|
*/
|
|
protected void primaryCollectionItemsRemoved() {
|
|
//Not certain this will work - it should release all mappings, listeners and remove all but the root node on both the client and server.//
|
|
itemAllRemoved();
|
|
rootNode.removeChildNodes();
|
|
groupNodes.removeAll();
|
|
children.unregisterAllItems();
|
|
groupings.unregisterAllItems();
|
|
|
|
//TODO: This would work fine if we didn't send a remove message and an unlink message for every node in the tree.
|
|
//pruneAllChildren(rootNode);
|
|
}//primaryCollectionItemsRemoved()//
|
|
/* (non-Javadoc)
|
|
* @see com.foundation.tcv.swt.server.CollectionComponent#itemSorted(int[])
|
|
*/
|
|
protected void itemSorted(int[] mapping) {
|
|
//Do nothing.//
|
|
}//itemSorted()//
|
|
/* (non-Javadoc)
|
|
* @see com.foundation.tcv.swt.server.TreeComponent#refreshRowHeaderCellData(java.lang.Object)
|
|
*/
|
|
protected boolean refreshRowHeaderCellData(Object item) {
|
|
boolean result = false;
|
|
|
|
result |= rowBackgroundColor.refresh(item);
|
|
result |= rowForegroundColor.refresh(item);
|
|
result |= rowFont.refresh(item);
|
|
|
|
return result;
|
|
}//refreshRowHeaderCellData()//
|
|
/* (non-Javadoc)
|
|
* @see com.foundation.tcv.swt.server.TreeComponent#getRowHeaderCellData(java.lang.Object)
|
|
*/
|
|
protected Object getRowHeaderCellData(Object item) {
|
|
return new SimpleTreeTableCellData(null, null, rowBackgroundColor.getValue(item), rowForegroundColor.getValue(item), rowFont.getValue(item), -1);
|
|
}//getCellValue()//
|
|
/* (non-Javadoc)
|
|
* @see com.foundation.tcv.swt.server.CollectionComponent#registerItem(java.lang.Object)
|
|
*/
|
|
protected void registerItem(RowObject rowObject) {
|
|
super.registerItem(rowObject);
|
|
rowBackgroundColor.registerItem(rowObject);
|
|
rowForegroundColor.registerItem(rowObject);
|
|
rowFont.registerItem(rowObject);
|
|
}//registerItem()//
|
|
/* (non-Javadoc)
|
|
* @see com.foundation.tcv.swt.server.CollectionComponent#unregisterItem(java.lang.Object)
|
|
*/
|
|
protected void unregisterItem(RowObject rowObject) {
|
|
super.unregisterItem(rowObject);
|
|
rowBackgroundColor.unregisterItem(rowObject);
|
|
rowForegroundColor.unregisterItem(rowObject);
|
|
rowFont.unregisterItem(rowObject);
|
|
}//unregisterItem()//
|
|
/* (non-Javadoc)
|
|
* @see com.foundation.tcv.swt.server.TreeComponent#unregisterItems()
|
|
*/
|
|
protected void unregisterItems() {
|
|
super.unregisterItems();
|
|
rowBackgroundColor.unregisterAllItems();
|
|
rowForegroundColor.unregisterAllItems();
|
|
rowFont.unregisterAllItems();
|
|
}//unregisterItems()//
|
|
/* (non-Javadoc)
|
|
* @see com.foundation.tcv.swt.server.TreeComponent#canHaveChildren(java.lang.Object)
|
|
*/
|
|
protected boolean canHaveChildren(Object item) {
|
|
return children.hasAssociations(item);
|
|
}//canHaveChildren()//
|
|
/* (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(allowMultiSelection()) {
|
|
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();
|
|
|
|
//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();
|
|
SimpleNodeData treeNode = (SimpleNodeData) getRowObject(next);
|
|
|
|
if(treeNode != null) {
|
|
int nextObjectId = treeNode.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(!found) {
|
|
//Add the new selection to the model's collection of selections.//
|
|
modelSelections.add(next);
|
|
}//if//
|
|
}//if//
|
|
}//while//
|
|
}//if//
|
|
}//try//
|
|
finally {
|
|
suspendSelectionHooks = false;
|
|
}//finally//
|
|
}//if//
|
|
else {
|
|
int selectedObjectId = messageData != null ? ((Integer) messageData).intValue() : -1;
|
|
SimpleNodeData treeNode = selectedObjectId >= 0 ? (SimpleNodeData) getRowObject(selectedObjectId) : null;
|
|
|
|
setModelSelection(treeNode == null ? null : treeNode.value);
|
|
}//else//
|
|
break;
|
|
}//case//
|
|
case MESSAGE_SEND_DOUBLE_CLICK: {
|
|
if(getDoubleClickMethod() != null) {
|
|
if(getDoubleClickMethod().getIsValueHolderAssociated()) {
|
|
getDoubleClickMethod().invoke(null, true); //For now we will assume no parameters. It would be nice to pass the selection perhaps.//
|
|
}//if//
|
|
else {
|
|
Object selection = null;
|
|
|
|
//Determine which selection to invoke the method on.//
|
|
if(allowMultiSelection()) {
|
|
ICollection selections = getModelSelections();
|
|
|
|
if((selections != null) && (selections.getSize() > 0)) {
|
|
selection = selections.iterator().next();
|
|
}//if//
|
|
}//if//
|
|
else {
|
|
selection = getModelSelection();
|
|
}//else//
|
|
|
|
if(selection != null) {
|
|
//Invoke the method on the selection object if there is one.//
|
|
getDoubleClickMethod().invoke(selection, null, true);
|
|
}//if//
|
|
}//else//
|
|
}//if//
|
|
break;
|
|
}//case//
|
|
case MESSAGE_OPEN_NODE: {
|
|
int objectId = viewMessage.getMessageInteger();
|
|
SimpleNodeData node = (SimpleNodeData) getRowObject(objectId);
|
|
|
|
addMessageHold();
|
|
|
|
try {
|
|
openNode(node);
|
|
sendMessage(MESSAGE_NODE_OPENED, null, null, objectId, 0);
|
|
}//try//
|
|
finally {
|
|
removeMessageHold();
|
|
}//finally//
|
|
break;
|
|
}//case//
|
|
default: {
|
|
retVal = super.processMessage(viewMessage);
|
|
}//default//
|
|
}//switch//
|
|
|
|
return retVal;
|
|
}//processMessage()//
|
|
/**
|
|
* Opens a node in the tree which will populate its children.
|
|
* <p>Note: A call to closeNode must be made for each call to open node. Open node does register for node data change events.</p>
|
|
* @param node The node whose children are currently unkown.
|
|
*/
|
|
protected void openNode(SimpleNodeData node) {
|
|
IList childItemCollections = null; //TODO: Use a reusable collection.
|
|
|
|
addMessageHold();
|
|
|
|
try {
|
|
int childCount = 0;
|
|
|
|
node.initializeOnOpen();
|
|
children.refresh(node.value);
|
|
childItemCollections = children.getValues(node.value, childItemCollections);
|
|
|
|
//Iterate over the items or collections of child items and figure a total.//
|
|
for(int index = 0; index < childItemCollections.getSize(); index++) {
|
|
Object childItemCollection = childItemCollections.get(index);
|
|
|
|
if(childItemCollection instanceof Object[]) {
|
|
childCount += ((Object[]) childItemCollection).length;
|
|
}//else//
|
|
else if(childItemCollection instanceof ICollection) {
|
|
childCount += ((ICollection) childItemCollection).getSize();
|
|
}//else if//
|
|
else {
|
|
childCount++;
|
|
}//else//
|
|
}//for//
|
|
|
|
node.setChildNodes(new LiteList(childCount, 20));
|
|
|
|
//Iterate over the items or collections of child items and place them in the tree.//
|
|
for(int index = 0; index < childItemCollections.getSize(); index++) {
|
|
Object childItemCollection = childItemCollections.get(index);
|
|
|
|
if((childItemCollection instanceof IInlineIndexedCollectionObservable) || (childItemCollection instanceof IInlineCollectionObservable)) {
|
|
node.addChildListener((ICollection) childItemCollection);
|
|
//TODO: Is this the only instance that needs the child listener?//
|
|
}//if//
|
|
else if(childItemCollection instanceof Object[]) {
|
|
for(int i = 0; i < ((Object[]) childItemCollection).length; i++) {
|
|
placeItem(node, ((Object[]) childItemCollection)[i]);
|
|
}//for//
|
|
}//else//
|
|
else if(childItemCollection instanceof IList) {
|
|
for(int i = 0; i < ((IList) childItemCollection).getSize(); i++) {
|
|
placeItem(node, ((IList) childItemCollection).get(i));
|
|
}//for//
|
|
}//else if//
|
|
else if(childItemCollection instanceof ICollection) {
|
|
IIterator iterator = ((ICollection) childItemCollection).iterator();
|
|
|
|
while(iterator.hasNext()) {
|
|
placeItem(node, iterator.next());
|
|
}//while//
|
|
}//else if//
|
|
else {
|
|
placeItem(node, childItemCollection);
|
|
}//else//
|
|
}//for//
|
|
}//try//
|
|
finally {
|
|
removeMessageHold();
|
|
}//finally//
|
|
}//openNode()//
|
|
/* (non-Javadoc)
|
|
* @see com.foundation.tcv.swt.server.TreeComponent#placeItem(com.foundation.tcv.swt.server.SimpleTreeTable.TreeNode, java.lang.Object)
|
|
*/
|
|
protected void placeItem(SimpleNodeData node, Object item) {
|
|
IList groupingItems = null; //TODO: Use a reusable collection.
|
|
SimpleNodeData nextNode;
|
|
SimpleNodeData newNode = (SimpleNodeData) itemAdded(item, -1, false);
|
|
|
|
if(node == null) {
|
|
node = rootNode;
|
|
}//if//
|
|
|
|
if(newNode.isFirstReference()) {
|
|
newNode.initialize();
|
|
sendAddItemMessage(newNode, -1);
|
|
}//if//
|
|
|
|
groupings.refresh(item);
|
|
groupingItems = groupings.getValues(item, null);
|
|
nextNode = node;
|
|
|
|
//Iterate over the grouping items.//
|
|
for(int groupingItemsIndex = 0; groupingItemsIndex < groupingItems.getSize(); groupingItemsIndex++) {
|
|
Object grouping = groupingItems.get(groupingItemsIndex);
|
|
|
|
//Ignore null groupings.//
|
|
//TODO: Allow the developer to replace null with a value via the vml.
|
|
if(grouping != null) {
|
|
nextNode = groupItem(nextNode, grouping);
|
|
}//if//
|
|
}//for//
|
|
|
|
nextNode.addChildNode(newNode);
|
|
|
|
//If there were groupings then we must link the new node with its parent so that if the groupings change, it can find its parent(s) to alter the grouping nodes it falls under.//
|
|
if(groupingItems.getSize() > 0) {
|
|
if(newNode.getParentNodes() == null) {
|
|
newNode.setParentNodes(new LiteList((Object) node, 10));
|
|
}//if//
|
|
else {
|
|
newNode.getParentNodes().add(node);
|
|
}//else//
|
|
}//if//
|
|
}//placeItem()//
|
|
/**
|
|
* Creates the tree nodes necessary for the given group item and returns the tree node for the grouping.
|
|
* @param node The node that the grouping belongs under.
|
|
* @param groupItem The group item data used to create the grouping or find the existing grouping.
|
|
* @return The grouping tree node.
|
|
*/
|
|
protected SimpleNodeData groupItem(SimpleNodeData node, Object groupItem) {
|
|
int nextNodeChildrenSize = node.getChildNodeCount();
|
|
boolean found = false;
|
|
|
|
//Search for an existing grouping of the same or equivalent value.//
|
|
for(int nextNodeChildIndex = 0; (!found) && (nextNodeChildIndex < nextNodeChildrenSize); nextNodeChildIndex++) {
|
|
SimpleNodeData nodeChild = node.getChildNode(nextNodeChildIndex);
|
|
|
|
//If we found an existing grouping then use it.//
|
|
if((nodeChild.isGrouping()) && (Comparator.equals(nodeChild.value, groupItem))) {
|
|
node = nodeChild;
|
|
found = true;
|
|
}//if//
|
|
}//for//
|
|
|
|
//We didn't find an existing grouping, so create one.//
|
|
if(!found) {
|
|
SimpleNodeData newNode = (SimpleNodeData) itemAdded(groupItem, -1, false);
|
|
|
|
newNode.isGrouping(true);
|
|
newNode.initialize();
|
|
groupNodes.add(newNode);
|
|
sendAddItemMessage(newNode, -1);
|
|
node.addChildNode(newNode);
|
|
node = newNode;
|
|
}//if//
|
|
|
|
return node;
|
|
}//groupItem()//
|
|
/**
|
|
* Changes the groupings that the given node falls under.
|
|
* @param childNode The node that is grouped.
|
|
* @param oldGroupings The old list of groupings.
|
|
* @param newGroupings The new list of groupings.
|
|
*/
|
|
protected void regroupItem(SimpleNodeData childNode, IList oldGroupings, IList newGroupings) {
|
|
IList parentNodes = childNode.getParentNodes();
|
|
int changeIndex;
|
|
int size = Math.min(oldGroupings.getSize(), newGroupings.getSize());
|
|
SimpleNodeData[] oldGroupingStack = null;
|
|
|
|
/*
|
|
The number of groupings shouldn't change unless we count null group values as non-groupings (Note: we are not counting on this though).
|
|
If we assume static group counts, then we need to find the first changed grouping between the old and new list.
|
|
Next we must for each parent of the node, iterate through the groupings in reverse order to remove the item and unused groupings.
|
|
Then for each parent of the node we must iterate through the groupings in forward order to add the item under the new groupings (creating as necessary).
|
|
|
|
Note that we must then build a stack of TreeNodes, starting with the first unchanged grouping, or the parent node, and going to the end.
|
|
To remove we can then iterate up the stack toward the unchanged node, and then we can iterate from the unchanged node down to where we add the node back to the tree.
|
|
*/
|
|
|
|
//Determine the index first grouping that has changed from the top (the parent) towards the bottom (the child).
|
|
for(changeIndex = 0; changeIndex < size; changeIndex++) {
|
|
if(!oldGroupings.get(changeIndex).equals(newGroupings.get(changeIndex))) {
|
|
break;
|
|
}//if//
|
|
}//for//
|
|
|
|
oldGroupingStack = new SimpleNodeData[oldGroupings.getSize() - changeIndex];
|
|
|
|
//Iterate over the parents (which if null indicate a root) to regroup the node in all parents.//
|
|
for(int parentIndex = 0; parentIndex < parentNodes.getSize(); parentIndex++) {
|
|
SimpleNodeData unchangedNode = (SimpleNodeData) parentNodes.get(parentIndex);
|
|
SimpleNodeData indexNode = null;
|
|
|
|
//Find the last unchanged node.//
|
|
for(int index = 0; index < changeIndex; index++) {
|
|
unchangedNode = unchangedNode.getChildNode(newGroupings.get(index), true);
|
|
}//for//
|
|
|
|
indexNode = unchangedNode;
|
|
|
|
//Build a stack of changed nodes so we can reverse iterate over them to cleanup.//
|
|
for(int index = changeIndex, stackIndex = 0; index < oldGroupings.getSize(); index++, stackIndex++) {
|
|
indexNode = oldGroupingStack[stackIndex] = indexNode.getChildNode(oldGroupings.get(index), true);
|
|
}//for//
|
|
|
|
//Remove the child node from the last grouping node.//
|
|
oldGroupingStack[oldGroupingStack.length - 1].removeChildNode(childNode);
|
|
indexNode = oldGroupingStack[oldGroupingStack.length - 1];
|
|
|
|
//Reverse iterate over the changed tree nodes to clean them up.//
|
|
//Exit the loop if one of the grouping nodes has more than the removed node as its child.//
|
|
for(int index = oldGroupingStack.length - 1; (oldGroupingStack[index].getChildNodeCount() == 0) && (index >= 0); index--) {
|
|
SimpleNodeData parentNode = index == 0 ? unchangedNode : oldGroupingStack[index - 1];
|
|
|
|
parentNode.removeChildNode(oldGroupingStack[index]);
|
|
oldGroupingStack[index].release();
|
|
groupNodes.remove(oldGroupingStack[index]);
|
|
}//for//
|
|
|
|
indexNode = unchangedNode;
|
|
|
|
//Place the child node under the new groupings.//
|
|
for(int index = changeIndex; index < newGroupings.getSize(); index++) {
|
|
SimpleNodeData groupingNode = indexNode.getChildNode(newGroupings.get(index), true);
|
|
|
|
if(groupingNode == null) {
|
|
groupingNode = (SimpleNodeData) itemAdded(newGroupings.get(index), -1, true);
|
|
groupingNode.isGrouping(true);
|
|
groupingNode.initialize();
|
|
groupNodes.add(groupingNode);
|
|
indexNode.addChildNode(groupingNode);
|
|
}//if//
|
|
|
|
indexNode = groupingNode;
|
|
}//for//
|
|
}//for//
|
|
}//regroupItem()//
|
|
/**
|
|
* Removes a node and all children from the tree.
|
|
* This is called when the parent no longer references the given node.
|
|
* @param parent The node's parent node, or null if the node is a root node.
|
|
* @param node The non-grouping node to be removed, along with any groupings it defines.
|
|
*/
|
|
protected void pruneNode(SimpleNodeData parent, SimpleNodeData node) {
|
|
if(!node.isGrouping()) {
|
|
IList nodeGroups = groupings.getValues(node.value, null);
|
|
|
|
//Remove this item from the tree.//
|
|
//Prune all the children so that the nodes furthor down the tree branches get removed first.//
|
|
pruneAllChildren(node, true);
|
|
|
|
//If the node was grouped, then cleanup the groupings which are no longer required by disconnecting them from their parents.//
|
|
if(nodeGroups.getSize() > 0) {
|
|
SimpleNodeData childNode = node;
|
|
SimpleNodeData groupingParent = parent;
|
|
|
|
//Build a stack of grouping nodes from closest to the parent to furthest.//
|
|
for(int groupingIndex = 0; groupingIndex < nodeGroups.getSize(); groupingIndex++) {
|
|
Object group = nodeGroups.get(groupingIndex);
|
|
|
|
//Ignore null groupings.//
|
|
//TODO: Allow null groupings to be converted to a fixed value.
|
|
if(group != null) {
|
|
SimpleNodeData groupNode = groupingParent.getChildNode(group, true);
|
|
|
|
//Replace the grouping item with the actual grouping node in our list.//
|
|
nodeGroups.set(groupingIndex, groupNode);
|
|
groupingParent = groupNode;
|
|
}//if//
|
|
else {
|
|
nodeGroups.set(groupingIndex, null);
|
|
}//else//
|
|
}//for//
|
|
|
|
//Reverse iterate over the groupings to remove any that are no longer required.//
|
|
for(int groupingIndex = nodeGroups.getSize() - 1; (childNode != null) && (groupingIndex >= 0); groupingIndex--) {
|
|
SimpleNodeData groupNode = (SimpleNodeData) nodeGroups.get(groupingIndex);
|
|
|
|
if(groupNode != null) {
|
|
groupNode.removeChildNode(childNode);
|
|
|
|
if(groupNode.getChildNodeCount() == 0) {
|
|
itemRemoved(childNode, -1, true);
|
|
childNode = groupNode;
|
|
}//if//
|
|
else {
|
|
childNode = null;
|
|
}//else//
|
|
}//if//
|
|
}//for//
|
|
}//if//
|
|
else {
|
|
//This method sends a message to the client to remove the node linkage which will also free any node data no longer linked.//
|
|
parent.removeChildNode(node);
|
|
}//else//
|
|
|
|
//Note: Doing this outside the pruneAllChildren so that disconnecting the node from its groupings doesn't encounter a missing node on the client.//
|
|
//Send the remove item message after removing the children so the client receives them in the correct order.//
|
|
sendRemoveItemMessage(node, -1, true);
|
|
//Release the node (after the above two lines so the client can find the child/parent node when removing linkage).//
|
|
node.release();
|
|
}//if//
|
|
}//pruneNode()//
|
|
/**
|
|
* Recursively prunes all the children of the given node.
|
|
* @param node The node whose children will recursively be pruned from the tree.
|
|
* @return Whether the passed node was removed entirely (false if the node still exists elsewhere in the tree).
|
|
*/
|
|
private boolean pruneAllChildren(SimpleNodeData node, boolean isFirst) {
|
|
boolean removedEntirely = true;
|
|
|
|
//TODO: We should send one message to the client to remove all children instead of one per child node.
|
|
if(node != rootNode) {
|
|
removedEntirely = itemRemoved(node.value, -1, false);
|
|
}//if//
|
|
else {
|
|
removedEntirely = false;
|
|
}//else//
|
|
|
|
//Prune the children if the node was released, or is the root node (which is never released).//
|
|
if(!node.isGrouping && removedEntirely) {
|
|
//Recursively prune all children.//
|
|
while(node.getChildNodeCount() > 0) {
|
|
SimpleNodeData child = node.getChildNode(node.getChildNodeCount() - 1);
|
|
|
|
//First remove the linkage to the child.//
|
|
node.removeChildNode(child);
|
|
//Recursively prune the child's children.//
|
|
pruneAllChildren(child, false);
|
|
}//for//
|
|
|
|
if(node != rootNode) {
|
|
if(!isFirst) {
|
|
//Send the remove item message after removing the children so the client receives them in the correct order.//
|
|
sendRemoveItemMessage(node, -1, true);
|
|
//Release the node (after the above two lines so the client can find the child/parent node when removing linkage).//
|
|
node.release();
|
|
}//if//
|
|
|
|
if(node.isGrouping) {
|
|
groupNodes.remove(node);
|
|
}//if//
|
|
}//if//
|
|
}//if//
|
|
|
|
return removedEntirely;
|
|
}//pruneAllChildren()//
|
|
/* (non-Javadoc)
|
|
* @see com.foundation.tcv.swt.server.AbstractComponent#getClientClassName()
|
|
*/
|
|
protected String getClientClassName() {
|
|
return "com.foundation.tcv.swt.client.SimpleTreeTable";
|
|
}//getClientClassName()//
|
|
/**
|
|
* Determines whether the selection event is forced on a row when a node is opened by the user.
|
|
* @param selectOnOpen Whether the selection even is forced.
|
|
*/
|
|
public void setSelectOnOpen(boolean selectOnOpen) {
|
|
if(this.selectOnOpen != selectOnOpen) {
|
|
this.selectOnOpen = selectOnOpen;
|
|
sendMessage(MESSAGE_SET_SELECT_ON_OPEN, selectOnOpen ? Boolean.TRUE : Boolean.FALSE);
|
|
}//if//
|
|
}//selectOnOpen()//
|
|
}//SimpleTreeTable// |