2590 lines
98 KiB
Java
2590 lines
98 KiB
Java
/*
|
|
* Copyright (c) 2005,2009 Declarative Engineering LLC.
|
|
* All rights reserved. This program and the accompanying materials
|
|
* are made available under the terms of the Declarative Engineering LLC
|
|
* verson 1 which accompanies this distribution, and is available at
|
|
* http://declarativeengineering.com/legal/DE_Developer_License_v1.txt
|
|
*/
|
|
package com.foundation.view.swt;
|
|
|
|
import org.eclipse.swt.SWT;
|
|
import org.eclipse.swt.custom.TableEditor;
|
|
import org.eclipse.swt.events.ControlEvent;
|
|
import org.eclipse.swt.events.ControlListener;
|
|
import org.eclipse.swt.events.SelectionEvent;
|
|
import org.eclipse.swt.events.SelectionListener;
|
|
import org.eclipse.swt.graphics.GC;
|
|
import org.eclipse.swt.graphics.Point;
|
|
import org.eclipse.swt.graphics.Rectangle;
|
|
import org.eclipse.swt.widgets.Control;
|
|
import org.eclipse.swt.widgets.Event;
|
|
import org.eclipse.swt.widgets.Listener;
|
|
import org.eclipse.swt.widgets.Shell;
|
|
import org.eclipse.swt.widgets.Table;
|
|
import org.eclipse.swt.widgets.TableColumn;
|
|
import org.eclipse.swt.widgets.TableItem;
|
|
|
|
import com.common.debug.Debug;
|
|
import com.common.exception.InvalidArgumentException;
|
|
import com.common.util.ICollection;
|
|
import com.common.util.IHashSet;
|
|
import com.common.util.IIterator;
|
|
import com.common.util.IList;
|
|
import com.common.util.LiteHashMap;
|
|
import com.common.util.LiteHashSet;
|
|
import com.common.util.LiteList;
|
|
import com.foundation.controller.DecorationManager;
|
|
import com.foundation.view.*;
|
|
import com.foundation.view.resource.AbstractResourceService;
|
|
import com.foundation.view.resource.ResourceReference;
|
|
import com.foundation.view.swt.cell.CellComponent;
|
|
import com.foundation.view.swt.util.SwtUtilities;
|
|
|
|
/*
|
|
* What started out as a simple table control has turned out to be not so simple. This table control does almost everything one would want from a table control with possibly the exception of multi line rows.
|
|
* <p>TODO:
|
|
* <ul>
|
|
* <li>Allow custom controls in the headers - finally added to SWT and should now be possible here.</li>
|
|
* <li>Improve rendering of cells that custom draw their contents. There are a number of graphical artifacts that are not pleasing. Current work around is to do the drawing in a heavy control in the cell.</li>
|
|
* <li>Optimize the thick client table by removing the getCellData() and getHeaderData() which create a data bundle for each cell and for the row. On the thick client this isn't necessary since the data doesn't need to be serailized to a client and it is all easily accessable by the rendering engine.</li>
|
|
* <li>Allow custom renderers for the selection. Currently allowing gradient and solid color renderers, but it would be nice to offer fully customized rendering somehow.</li>
|
|
* <li>Not sure if this is done or not: Add option for a auto numbered header column.</li>
|
|
* <li>Optimize the startup of the table - can add rows in a sudo-mutli-threaded system - can identify speed bottlenecks and inefficiencies via profiling - can allow options for automating chunking the data (providing N rows at a time and sorting on the server instead of in the control {already doable}).</li>
|
|
* <li>Modify cell editors to allow the editor control to only appear when the cell is selected. Also modify the cell editor focus gain code to select the row if it isn't already selected.</li>
|
|
* </ul>
|
|
* </p>
|
|
*/
|
|
public class SimpleTable extends TableComponent implements SelectionListener, ControlListener {
|
|
public static final int STYLE_SINGLE = SWT.SINGLE;
|
|
public static final int STYLE_MULTI = SWT.MULTI;
|
|
public static final int STYLE_CHECK = SWT.CHECK;
|
|
public static final int STYLE_FULL_SELECTION = SWT.FULL_SELECTION;
|
|
public static final int STYLE_HIDE_SELECTION = SWT.HIDE_SELECTION;
|
|
public static final int STYLE_VIRTUAL = SWT.VIRTUAL;
|
|
|
|
public static final int ALIGNMENT_LEFT = 0;
|
|
public static final int ALIGNMENT_CENTER = 1;
|
|
public static final int ALIGNMENT_RIGHT = 2;
|
|
|
|
public static final int AUTO_FIT_NEVER = 0;
|
|
public static final int AUTO_FIT_MANUAL = 1;
|
|
public static final int AUTO_FIT_AUTO = 2;
|
|
|
|
public static final int LINK_TARGET_FIT = TableComponent.LAST_LINK_TARGET + 1;
|
|
public static final int LINK_TARGET_FILL = TableComponent.LAST_LINK_TARGET + 2;
|
|
public static final int LAST_LINK_TARGET = TableComponent.LAST_LINK_TARGET + 2;
|
|
|
|
/** 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 sorting is managed by the view versus the model. */
|
|
private boolean inViewSorting = true;
|
|
/** A flag to temporarily disable the delay when synchronizing the selection before sending the double click message. */
|
|
private boolean disableAutoSynchronizeDelay = false;
|
|
/** The last column to be locally sorted. This allows the user to reverse sort a column. */
|
|
private int lastSortedColumnIndex = -1;
|
|
/** Whether the last sorted column was reverse sorted. */
|
|
private boolean isSortReversed = false;
|
|
/** Fixes a bug in the table where by a double click event gets fired twice. */
|
|
private int lastDoubleClickTime = 0;
|
|
/** The set of currently visible table items. */
|
|
private LiteHashSet currentlyVisibleTableItems = null;
|
|
/** Allows us to ignore resize events while creating items during initialization. */
|
|
private boolean suspendResizeEvents = false;
|
|
/** Allows us to ignore table editor updates while adding, removing, or moving large numbers of items. */
|
|
private int suspendUpdateTableEditorsCount = 0;
|
|
/** Suspends the laying out of the renderers while adding, removing, or moving large numbers of items. */
|
|
private boolean suspendLayoutRenderers = false;
|
|
/** Allows us to ignore resize events for the column while resizing the columns. */
|
|
private boolean suspendColumnResizeEvents = false;
|
|
/** The last known width for the control's client area. This is used to avoid filling or fitting the columns unless the width of the control is altered. */
|
|
private int lastControlWidth = 0;
|
|
/** The minimum table editor height for all tested table editors. */
|
|
private int minimumTableEditorHeight = -1;
|
|
/** A flag indicating whether the control's selection events should be ignored temporarily. */
|
|
protected boolean suspendSelectionEvents = false;
|
|
|
|
/**
|
|
* A customized row object.
|
|
*/
|
|
protected class SimpleTableRowObject extends TableRowObject {
|
|
public SimpleTableRowObject(Object value) {
|
|
super(value);
|
|
}//SimpleTableRowObject()//
|
|
}//SimpleTableRowObject//
|
|
|
|
public static class Renderer {
|
|
public CellComponent component = null;
|
|
public Class type;
|
|
|
|
public Renderer(Class type, CellComponent component) {
|
|
if(type == null || component == null) {
|
|
throw new InvalidArgumentException();
|
|
}//if//
|
|
|
|
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 implements IResourceHolderComponent {
|
|
/** 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);
|
|
/** A holder for the value of the cell background color. */
|
|
private MultiResourceHolder backgroundColorHolder = new MultiResourceHolder(this);
|
|
/** A holder for the value of the cell foreground color. */
|
|
private MultiResourceHolder foregroundColorHolder = new MultiResourceHolder(this);
|
|
/** A holder for the value of the cell foreground color. */
|
|
private MultiResourceHolder fontHolder = new MultiResourceHolder(this);
|
|
/** A holder for the value of the cell image. */
|
|
private MultiResourceHolder cellImageHolder = new MultiResourceHolder(this);
|
|
/** A holder for the value of the column's tool tip text. */
|
|
private ResourceHolder toolTipTextHolder = new ResourceHolder(this);
|
|
/** A holder for the value of the column's header text. */
|
|
private ResourceHolder headerTextHolder = new ResourceHolder(this);
|
|
/** A holder for the value of the column's header image. */
|
|
private ResourceHolder headerImageHolder = new ResourceHolder(this);
|
|
/** The alginment of the column data. */
|
|
private int alignment = ALIGNMENT_LEFT;
|
|
/** The width of the column. */
|
|
private int width = 100;
|
|
/** The minimum width of the column. */
|
|
private int minimumWidth = 20;
|
|
/** 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 set of TableEditor instances mapped by the TableItem they are serving. This is used primarily to release the editors when the are out of view. */
|
|
private LiteHashMap editorByTableItem = new LiteHashMap(50);
|
|
/** A counter for the number of renderers that will paint their data. */
|
|
private int paintRendererCounter = 0;
|
|
/** A counter for the number of renderers that will generate a component to display their data. */
|
|
private int componentRendererCounter = 0;
|
|
/** The table column being served. */
|
|
private TableColumn column;
|
|
|
|
/**
|
|
* ColumnData constructor.
|
|
*/
|
|
public ColumnData(int index) {
|
|
this.index = index;
|
|
}//ColumnData()//
|
|
/* (non-Javadoc)
|
|
* @see com.foundation.view.IAbstractComponent#verifyThread()
|
|
*/
|
|
public void verifyThread() {
|
|
SimpleTable.this.verifyThread();
|
|
}//verifyThread()//
|
|
/**
|
|
* Sets the swt table column reference.
|
|
* @param column The actual column.
|
|
*/
|
|
public void setTableColumn(TableColumn column) {
|
|
this.column = column;
|
|
}//setTableColumn()//
|
|
/* (non-Javadoc)
|
|
* @see com.foundation.view.IAbstractComponent#getName()
|
|
*/
|
|
public String getName() {
|
|
return "__Column__";
|
|
}//getName()//
|
|
/**
|
|
* Forces the renderers to layout or reposition.
|
|
*/
|
|
public void layoutRenderers() {
|
|
IIterator iterator = editorByTableItem.valueIterator();
|
|
|
|
while(iterator.hasNext()) {
|
|
((TableEditor) iterator.next()).layout();
|
|
}//while//
|
|
}//layoutRenderers()//
|
|
/**
|
|
* Gets the table editor associated with the given row object.
|
|
* @param tableItem The table item whose editor should be retrieved.
|
|
* @return The editor, or null if the row does not have an editor for this column.
|
|
*/
|
|
public TableEditor getTableEditor(TableItem tableItem) {
|
|
return (TableEditor) editorByTableItem.get(tableItem);
|
|
}//getTableEditor()//
|
|
/**
|
|
* Sets the table editor associated with the given row object.
|
|
* @param tableItem The table item whose editor should be set.
|
|
* @param tableEditor The editor, or null if the row does not have an editor for this column.
|
|
*/
|
|
public void setTableEditor(TableItem tableItem, TableEditor tableEditor) {
|
|
editorByTableItem.put(tableItem, tableEditor);
|
|
}//setTableEditor()//
|
|
/**
|
|
* Removes and returns the table editor associated with the given row object.
|
|
* @param tableItem The table item whose editor should be removed.
|
|
* @return The editor, or null if the row does not have an editor for this column.
|
|
*/
|
|
public TableEditor removeTableEditor(TableItem tableItem) {
|
|
return (TableEditor) editorByTableItem.remove(tableItem);
|
|
}//getTableEditor()//
|
|
/* (non-Javadoc)
|
|
* @see com.foundation.tcv.swt.server.TableComponent.AbstractColumn#registerItem(java.lang.Object)
|
|
*/
|
|
protected void registerItem(Object item, TableRowObject rowObject) {
|
|
cellText.registerItem(item, rowObject);
|
|
cellText.refresh(item);
|
|
cellImage.registerItem(item, rowObject);
|
|
|
|
if(cellImage.refresh(item)) {
|
|
cellImageHolder.setValue(rowObject, cellImage.getValue(item), false);
|
|
}//if//
|
|
|
|
backgroundColor.registerItem(item, rowObject);
|
|
|
|
if(backgroundColor.refresh(item)) {
|
|
backgroundColorHolder.setValue(rowObject, backgroundColor.getValue(item), false);
|
|
}//if//
|
|
|
|
foregroundColor.registerItem(item, rowObject);
|
|
|
|
if(foregroundColor.refresh(item)) {
|
|
foregroundColorHolder.setValue(rowObject, foregroundColor.getValue(item), false);
|
|
}//if//
|
|
|
|
font.registerItem(item, rowObject);
|
|
|
|
if(font.refresh(item)) {
|
|
fontHolder.setValue(rowObject, font.getValue(item), false);
|
|
}//if//
|
|
|
|
if(renderers != null) {
|
|
for(int index = 0; index < renderers.getSize(); index++) {
|
|
((Renderer) renderers.get(index)).component.registerRowItem(item, null);
|
|
}//for//
|
|
}//if//
|
|
}//registerItem()//
|
|
/* (non-Javadoc)
|
|
* @see com.foundation.tcv.swt.server.TableComponent.AbstractColumn#unregisterItem(java.lang.Object)
|
|
*/
|
|
protected void unregisterItem(Object item) {
|
|
cellText.unregisterItem(item);
|
|
cellImage.unregisterItem(item);
|
|
backgroundColor.unregisterItem(item);
|
|
backgroundColorHolder.remove(item);
|
|
foregroundColor.unregisterItem(item);
|
|
foregroundColorHolder.remove(item);
|
|
font.unregisterItem(item);
|
|
fontHolder.remove(item);
|
|
|
|
if(renderers != null) {
|
|
for(int index = 0; index < renderers.getSize(); index++) {
|
|
((Renderer) renderers.get(index)).component.unregisterRowItem(item);
|
|
}//for//
|
|
}//if//
|
|
}//unregisterItem()//
|
|
/* (non-Javadoc)
|
|
* @see com.foundation.tcv.swt.server.TableComponent.AbstractColumn#unregisterAllItems()
|
|
*/
|
|
protected void unregisterAllItems() {
|
|
cellText.unregisterAllItems();
|
|
cellImage.unregisterAllItems();
|
|
backgroundColor.unregisterAllItems();
|
|
backgroundColorHolder.removeAll();
|
|
foregroundColor.unregisterAllItems();
|
|
foregroundColorHolder.removeAll();
|
|
font.unregisterAllItems();
|
|
fontHolder.removeAll();
|
|
|
|
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.TableComponent.AbstractColumn#getIndex()
|
|
*/
|
|
protected int getIndex() {
|
|
return index;
|
|
}//getIndex()//
|
|
/* (non-Javadoc)
|
|
* @see com.foundation.tcv.swt.server.TableComponent.AbstractColumn#setIndex(int)
|
|
*/
|
|
protected void setIndex(int index) {
|
|
this.index = index;
|
|
}//setIndex()//
|
|
/* (non-Javadoc)
|
|
* @see com.foundation.view.IAbstractComponent#getContainer()
|
|
*/
|
|
public IAbstractContainer getContainer() {
|
|
return SimpleTable.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() {
|
|
}//addMessageHold()//
|
|
/* (non-Javadoc)
|
|
* @see com.foundation.view.ISingleResourceAssociationChangeListener#removeMessageHold()
|
|
*/
|
|
public void 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, 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) {
|
|
if(isInitialized()) {
|
|
verifyThread();
|
|
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) {
|
|
if(isInitialized()) {
|
|
verifyThread();
|
|
internalOnModelExternallyChanged((MultiResourceAssociation) resourceAssociation, alteredItem, data, isCleared, originalValue);
|
|
}//if//
|
|
}//onModelExternallyChanged()//
|
|
/* (non-Javadoc)
|
|
* @see com.foundation.view.IResourceHolderComponent#resourceHolderChanged(com.foundation.view.ResourceHolder, java.lang.Object, java.lang.Object, int)
|
|
*/
|
|
public void resourceHolderChanged(com.foundation.view.AbstractResourceHolder resourceHolder, Object oldValue, Object newValue, int flags) {
|
|
verifyThread();
|
|
internalResourceHolderChanged((ResourceHolder) resourceHolder, oldValue, newValue, flags);
|
|
}//resourceHolderChanged()//
|
|
/* (non-Javadoc)
|
|
* @see com.foundation.view.IResourceHolderComponent#resourceHolderChanged(com.foundation.view.AbstractMultiResourceHolder, com.common.util.IHashSet, java.lang.Object, java.lang.Object)
|
|
*/
|
|
public void resourceHolderChanged(AbstractMultiResourceHolder resourceHolder, IHashSet rows, Object oldValue, Object newValue) {
|
|
//Not used.//
|
|
}//resourceHolderChanged()//
|
|
/* (non-Javadoc)
|
|
* @see com.foundation.view.IResourceHolderComponent#resourceHolderChanged(com.foundation.view.AbstractMultiResourceHolder, java.lang.Object, java.lang.Object, java.lang.Object)
|
|
*/
|
|
public void resourceHolderChanged(AbstractMultiResourceHolder resourceHolder, Object row, Object oldValue, Object newValue) {
|
|
//Not used.//
|
|
}//resourceHolderChanged()//
|
|
/**
|
|
* Called by the resource association when a resource changes value.
|
|
* <p>The change in value will be because the resource context altered its set of current resources and the associated resources was in the set that was altered.</p>
|
|
* @param resourceAssociation The resource association used to register with the resource.
|
|
*/
|
|
protected void internalOnValueChanged(SingleResourceAssociation resourceAssociation) {
|
|
if(resourceAssociation == headerText) {
|
|
if(headerText.refresh()) {
|
|
headerTextHolder.setValue(headerText.getValue());
|
|
}//if//
|
|
}//if//
|
|
else if(resourceAssociation == headerImage) {
|
|
if(headerImage.refresh()) {
|
|
headerImageHolder.setValue(headerImage.getValue());
|
|
}//if//
|
|
}//else if//
|
|
}//internalOnValueChanged()//
|
|
/**
|
|
* Called by the resource association when a resource changes value.
|
|
* <p>The change in value will be because the resource context altered its set of current resources and the associated resources was in the set that was altered.</p>
|
|
* @param resourceAssociation The resource association used to register with the resource.
|
|
* @param item The item whose value has been altered.
|
|
* @param isUpdate Whether the change is an update from the reflected object.
|
|
*/
|
|
protected void internalOnValueChanged(MultiResourceAssociation resourceAssociation, Object item, Object data, boolean isUpdate) {
|
|
if(isInitialized()) {
|
|
if(resourceAssociation == cellText) {
|
|
//Refresh the item cell data.//
|
|
if(cellText.refresh(item)) {
|
|
int columnIndex = getColumnIndex();
|
|
String text = (String) cellText.getValue(item);
|
|
|
|
text = text == null ? "" : text;
|
|
|
|
if(item != null) {
|
|
SimpleTableRowObject rowObject = (SimpleTableRowObject) data;
|
|
|
|
if(rowObject.controlItem == null) {
|
|
for(int index = 0; index < (rowObject.controlItems != null ? rowObject.controlItems.getSize() : 0); index++) {
|
|
((TableItem) rowObject.controlItems.get(index)).setText(columnIndex, text);
|
|
}//for//
|
|
}//if//
|
|
else {
|
|
((TableItem) rowObject.controlItem).setText(columnIndex, text);
|
|
}//else//
|
|
}//if//
|
|
//TODO: Does this ever happen?
|
|
else {
|
|
IIterator iterator = getRowObjects();
|
|
|
|
while(iterator.hasNext()) {
|
|
SimpleTableRowObject rowObject = (SimpleTableRowObject) iterator.next();
|
|
|
|
if(rowObject.controlItem == null) {
|
|
for(int index = 0; index < rowObject.controlItems.getSize(); index++) {
|
|
((TableItem) rowObject.controlItems.get(index)).setText(columnIndex, text);
|
|
}//for//
|
|
}//if//
|
|
else {
|
|
((TableItem) rowObject.controlItem).setText(columnIndex, text);
|
|
}//else//
|
|
}//while//
|
|
}//else//
|
|
}//if//
|
|
}//if//
|
|
else if(resourceAssociation == cellImage) {
|
|
//Refresh the item cell data.//
|
|
if(cellImage.refresh(item)) {
|
|
if(item != null) {
|
|
cellImageHolder.setValue((SimpleTableRowObject) data, cellImage.getValue(item));
|
|
}//if//
|
|
//TODO: Does this ever happen?
|
|
else {
|
|
Object value = cellImage.getValue(null);
|
|
IIterator iterator = getRowObjects();
|
|
|
|
while(iterator.hasNext()) {
|
|
cellImageHolder.setValue(iterator.next(), value);
|
|
}//while//
|
|
}//else//
|
|
}//if//
|
|
}//else if//
|
|
else if(resourceAssociation == backgroundColor) {
|
|
//Refresh the item cell data.//
|
|
if(backgroundColor.refresh(item)) {
|
|
if(item != null) {
|
|
backgroundColorHolder.setValue((SimpleTableRowObject) data, backgroundColor.getValue(item));
|
|
}//if//
|
|
//TODO: Does this ever happen?
|
|
else {
|
|
Object value = backgroundColor.getValue(null);
|
|
IIterator iterator = getRowObjects();
|
|
|
|
while(iterator.hasNext()) {
|
|
backgroundColorHolder.setValue(iterator.next(), value);
|
|
}//while//
|
|
}//else//
|
|
}//if//
|
|
}//else if//
|
|
else if(resourceAssociation == foregroundColor) {
|
|
//Refresh the item cell data.//
|
|
if(foregroundColor.refresh(item)) {
|
|
if(item != null) {
|
|
foregroundColorHolder.setValue((SimpleTableRowObject) data, foregroundColor.getValue(item));
|
|
}//if//
|
|
//TODO: Does this ever happen?
|
|
else {
|
|
Object value = foregroundColor.getValue(null);
|
|
IIterator iterator = getRowObjects();
|
|
|
|
while(iterator.hasNext()) {
|
|
foregroundColorHolder.setValue(iterator.next(), value);
|
|
}//while//
|
|
}//else//
|
|
}//if//
|
|
}//else if//
|
|
else if(resourceAssociation == font) {
|
|
//Refresh the item cell data.//
|
|
if(font.refresh(item)) {
|
|
if(item != null) {
|
|
fontHolder.setValue((SimpleTableRowObject) data, font.getValue(item));
|
|
}//if//
|
|
//TODO: Does this ever happen?
|
|
else {
|
|
Object value = font.getValue(null);
|
|
IIterator iterator = getRowObjects();
|
|
|
|
while(iterator.hasNext()) {
|
|
fontHolder.setValue(iterator.next(), value);
|
|
}//while//
|
|
}//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 internalOnModelValueChanged(ResourceAssociation resourceAssociation, Object alteredItem, Object originalValue) {
|
|
}//internalOnModelValueChanged()//
|
|
/**
|
|
* 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 internalOnModelValueChanged(ResourceAssociation resourceAssociation, Object originalValue) {
|
|
}//internalOnModelValueChanged()//
|
|
/**
|
|
* Called when a resource holder's value has been altered.
|
|
* Subclasses must override this to handle change to resource holders they define.
|
|
* @param resourceHolder The resource holder whose value changed.
|
|
* @param oldValue The old value.
|
|
* @param newValue The new value.
|
|
*/
|
|
protected void internalResourceHolderChanged(ResourceHolder resourceHolder, Object oldValue, Object newValue, int flags) {
|
|
if(resourceHolder == toolTipTextHolder) {
|
|
getSwtTable().getColumn(index).setToolTipText((String) toolTipTextHolder.getValue());
|
|
}//if//
|
|
else if(resourceHolder == headerTextHolder) {
|
|
column.setText((String) headerTextHolder.getValue());
|
|
}//else if//
|
|
else if(resourceHolder == headerImageHolder) {
|
|
if(oldValue != null) {
|
|
destroyImage((JefImage) oldValue);
|
|
}//if//
|
|
|
|
column.setImage(createImage((JefImage) headerImageHolder.getValue()));
|
|
}//else if//
|
|
else {
|
|
Debug.log("Error: Unhandled resource holder change event found. ResourceHolder: " + resourceHolder);
|
|
}//else//
|
|
}//internalResourceHolderChanged()//
|
|
/**
|
|
* Called by a resource holder when the held value changes either due to a new value being set, or due to a resource being changed.
|
|
* @param resourceHolder The resource holder that is sending the notification.
|
|
* @param row The row whose value has changed.
|
|
* @param oldValue The old value for the resource.
|
|
* @param newValue The new value for the resource.
|
|
*/
|
|
protected void internalResourceHolderChanged(MultiResourceHolder resourceHolder, Object row, Object oldValue, Object newValue) {
|
|
int columnIndex = getColumnIndex();
|
|
|
|
if(resourceHolder == cellImageHolder) {
|
|
SimpleTableRowObject rowObject = (SimpleTableRowObject) row;
|
|
|
|
if(rowObject.controlItem == null) {
|
|
for(int index = 0; index < rowObject.controlItems.getSize(); index++) {
|
|
TableItem tableItem = (TableItem) rowObject.controlItems.get(index);
|
|
|
|
destroyImage(tableItem.getImage(columnIndex));
|
|
tableItem.setImage(columnIndex, createImage((JefImage) newValue));
|
|
}//for//
|
|
}//if//
|
|
else {
|
|
TableItem tableItem = (TableItem) rowObject.controlItem;
|
|
|
|
destroyImage(tableItem.getImage(columnIndex));
|
|
tableItem.setImage(columnIndex, createImage((JefImage) newValue));
|
|
}//else//
|
|
}//if//
|
|
else if(resourceHolder == backgroundColorHolder) {
|
|
SimpleTableRowObject rowObject = (SimpleTableRowObject) row;
|
|
|
|
if(rowObject.controlItem == null) {
|
|
for(int index = 0; index < rowObject.controlItems.getSize(); index++) {
|
|
TableItem tableItem = (TableItem) rowObject.controlItems.get(index);
|
|
|
|
destroyColor(tableItem.getBackground(columnIndex));
|
|
tableItem.setBackground(columnIndex, createColor((JefColor) newValue));
|
|
}//for//
|
|
}//if//
|
|
else {
|
|
TableItem tableItem = (TableItem) rowObject.controlItem;
|
|
|
|
destroyColor(tableItem.getBackground(columnIndex));
|
|
tableItem.setBackground(columnIndex, createColor((JefColor) newValue));
|
|
}//else//
|
|
}//else if//
|
|
else if(resourceHolder == foregroundColorHolder) {
|
|
SimpleTableRowObject rowObject = (SimpleTableRowObject) row;
|
|
|
|
if(rowObject.controlItem == null) {
|
|
for(int index = 0; index < rowObject.controlItems.getSize(); index++) {
|
|
TableItem tableItem = (TableItem) rowObject.controlItems.get(index);
|
|
|
|
destroyColor(tableItem.getForeground(columnIndex));
|
|
tableItem.setForeground(columnIndex, createColor((JefColor) newValue));
|
|
}//for//
|
|
}//if//
|
|
else {
|
|
TableItem tableItem = (TableItem) rowObject.controlItem;
|
|
|
|
destroyColor(tableItem.getForeground(columnIndex));
|
|
tableItem.setForeground(columnIndex, createColor((JefColor) newValue));
|
|
}//else//
|
|
}//else if//
|
|
else if(resourceHolder == fontHolder) {
|
|
SimpleTableRowObject rowObject = (SimpleTableRowObject) row;
|
|
|
|
if(rowObject.controlItem == null) {
|
|
for(int index = 0; index < rowObject.controlItems.getSize(); index++) {
|
|
TableItem tableItem = (TableItem) rowObject.controlItems.get(index);
|
|
|
|
destroyFont(tableItem.getFont(columnIndex));
|
|
tableItem.setFont(columnIndex, createFont((JefFont[]) newValue));
|
|
}//for//
|
|
}//if//
|
|
else {
|
|
TableItem tableItem = (TableItem) rowObject.controlItem;
|
|
|
|
destroyFont(tableItem.getFont(columnIndex));
|
|
tableItem.setFont(columnIndex, createFont((JefFont[]) newValue));
|
|
}//else//
|
|
}//else if//
|
|
else {
|
|
Debug.log("Error: Unhandled resource holder change event found. ResourceHolder: " + resourceHolder);
|
|
}//else//
|
|
}//internalResourceHolderChanged()//
|
|
/**
|
|
* Called by a resource holder when the held value changes either due to a new value being set, or due to a resource being changed.
|
|
* @param resourceHolder The resource holder that is sending the notification.
|
|
* @param rows The rows whose values have changed.
|
|
* @param oldValue The old value for the resource.
|
|
* @param newValue The new value for the resource.
|
|
*/
|
|
protected void internalResourceHolderChanged(MultiResourceHolder resourceHolder, IHashSet rows, Object oldValue, Object newValue) {
|
|
int columnIndex = getColumnIndex();
|
|
|
|
if(resourceHolder == cellImageHolder) {
|
|
IIterator iterator = rows.iterator();
|
|
|
|
while(iterator.hasNext()) {
|
|
SimpleTableRowObject rowObject = (SimpleTableRowObject) iterator.next();
|
|
|
|
if(rowObject.controlItem == null) {
|
|
for(int index = 0; index < rowObject.controlItems.getSize(); index++) {
|
|
TableItem tableItem = (TableItem) rowObject.controlItems.get(index);
|
|
|
|
destroyImage(tableItem.getImage(columnIndex));
|
|
tableItem.setImage(columnIndex, createImage((JefImage) newValue));
|
|
}//for//
|
|
}//if//
|
|
else {
|
|
TableItem tableItem = (TableItem) rowObject.controlItem;
|
|
|
|
destroyImage(tableItem.getImage(columnIndex));
|
|
tableItem.setImage(columnIndex, createImage((JefImage) newValue));
|
|
}//else//
|
|
}//while//
|
|
}//if//
|
|
else if(resourceHolder == backgroundColorHolder) {
|
|
IIterator iterator = rows.iterator();
|
|
|
|
while(iterator.hasNext()) {
|
|
SimpleTableRowObject rowObject = (SimpleTableRowObject) iterator.next();
|
|
|
|
if(rowObject.controlItem == null) {
|
|
for(int index = 0; index < rowObject.controlItems.getSize(); index++) {
|
|
TableItem tableItem = (TableItem) rowObject.controlItems.get(index);
|
|
|
|
destroyColor(tableItem.getBackground(columnIndex));
|
|
tableItem.setBackground(columnIndex, createColor((JefColor) newValue));
|
|
}//for//
|
|
}//if//
|
|
else {
|
|
TableItem tableItem = (TableItem) rowObject.controlItem;
|
|
|
|
destroyColor(tableItem.getBackground(columnIndex));
|
|
tableItem.setBackground(columnIndex, createColor((JefColor) newValue));
|
|
}//else//
|
|
}//while//
|
|
}//else if//
|
|
else if(resourceHolder == foregroundColorHolder) {
|
|
IIterator iterator = rows.iterator();
|
|
|
|
while(iterator.hasNext()) {
|
|
SimpleTableRowObject rowObject = (SimpleTableRowObject) iterator.next();
|
|
|
|
if(rowObject.controlItem == null) {
|
|
for(int index = 0; index < rowObject.controlItems.getSize(); index++) {
|
|
TableItem tableItem = (TableItem) rowObject.controlItems.get(index);
|
|
|
|
destroyColor(tableItem.getForeground(columnIndex));
|
|
tableItem.setForeground(columnIndex, createColor((JefColor) newValue));
|
|
}//for//
|
|
}//if//
|
|
else {
|
|
TableItem tableItem = (TableItem) rowObject.controlItem;
|
|
|
|
destroyColor(tableItem.getForeground(columnIndex));
|
|
tableItem.setForeground(columnIndex, createColor((JefColor) newValue));
|
|
}//else//
|
|
}//while//
|
|
}//else if//
|
|
else if(resourceHolder == fontHolder) {
|
|
IIterator iterator = rows.iterator();
|
|
|
|
while(iterator.hasNext()) {
|
|
SimpleTableRowObject rowObject = (SimpleTableRowObject) iterator.next();
|
|
|
|
if(rowObject.controlItem == null) {
|
|
for(int index = 0; index < rowObject.controlItems.getSize(); index++) {
|
|
TableItem tableItem = (TableItem) rowObject.controlItems.get(index);
|
|
|
|
destroyFont(tableItem.getFont(columnIndex));
|
|
tableItem.setFont(columnIndex, createFont((JefFont[]) newValue));
|
|
}//for//
|
|
}//if//
|
|
else {
|
|
TableItem tableItem = (TableItem) rowObject.controlItem;
|
|
|
|
destroyFont(tableItem.getFont(columnIndex));
|
|
tableItem.setFont(columnIndex, createFont((JefFont[]) newValue));
|
|
}//else//
|
|
}//while//
|
|
}//else if//
|
|
else {
|
|
Debug.log("Error: Unhandled resource holder change event found. ResourceHolder: " + resourceHolder);
|
|
}//else//
|
|
}//internalResourceHolderChanged()//
|
|
/**
|
|
* Gets the index of this column.
|
|
* @return The column's zero based index.
|
|
*/
|
|
public int getColumnIndex() {
|
|
int result = -1;
|
|
|
|
for(int index = 0; (result == -1) && (index < getSwtTable().getColumnCount()); index++) {
|
|
if(getSwtTable().getColumn(index) == column) {
|
|
result = index;
|
|
}//if//
|
|
}//for//
|
|
|
|
return result;
|
|
}//getColumnIndex()//
|
|
/* (non-Javadoc)
|
|
* @see com.foundation.tcv.swt.server.TableComponent.AbstractColumn#initialize()
|
|
*/
|
|
protected void initialize() {
|
|
headerText.initialize();
|
|
headerImage.initialize();
|
|
cellText.initialize();
|
|
cellImage.initialize();
|
|
backgroundColor.initialize();
|
|
foregroundColor.initialize();
|
|
font.initialize();
|
|
|
|
//Force the header data to refresh since it gets set after sending the new header message to the client.//
|
|
if(headerText.refresh()) {
|
|
headerTextHolder.setValue(headerText.getValue());
|
|
}//if//
|
|
|
|
if(headerImage.refresh()) {
|
|
headerImageHolder.setValue(headerImage.getValue());
|
|
}//if//
|
|
}//initialize()//
|
|
/* (non-Javadoc)
|
|
* @see com.foundation.view.swt.TableComponent.AbstractColumn#refresh()
|
|
*/
|
|
protected void refresh() {
|
|
}//refresh()//
|
|
/* (non-Javadoc)
|
|
* @see com.foundation.tcv.swt.server.TableComponent.AbstractColumn#release()
|
|
*/
|
|
protected void release() {
|
|
unregisterAllItems();
|
|
headerText.release();
|
|
headerTextHolder.release();
|
|
headerImage.release();
|
|
headerImageHolder.release();
|
|
cellText.release();
|
|
cellImage.release();
|
|
cellImageHolder.release();
|
|
backgroundColor.release();
|
|
backgroundColorHolder.release();
|
|
foregroundColor.release();
|
|
foregroundColorHolder.release();
|
|
font.release();
|
|
fontHolder.release();
|
|
}//release()//
|
|
/**
|
|
* Determines whether the column header is resizable by the user.
|
|
* @param headerResizable Whether the header is resizable.
|
|
*/
|
|
public void setHeaderResizeable(boolean headerResizable) {
|
|
getSwtTable().getColumn(index).setResizable(headerResizable);
|
|
}//setHeadersResizeable()//
|
|
/**
|
|
* Sets the columns alignment.
|
|
* @param alignment The column's alignment
|
|
*/
|
|
public void setAlignment(int alignment) {
|
|
if(this.alignment != alignment) {
|
|
this.alignment = alignment;
|
|
getSwtTable().getColumn(index).setAlignment(alignment == ALIGNMENT_RIGHT ? SWT.RIGHT : alignment == ALIGNMENT_CENTER ? SWT.CENTER : SWT.LEFT);
|
|
}//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;
|
|
getSwtTable().getColumn(index).setWidth(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;
|
|
|
|
if(getSwtTable().getColumn(index).getWidth() < minimumWidth) {
|
|
getSwtTable().getColumn(index).setWidth(minimumWidth);
|
|
}//if//
|
|
}//if//
|
|
}//setMinimumWidth()//
|
|
/**
|
|
* Sets the column's tool tip text.
|
|
* @param toolTipText The tool tip for the column.
|
|
*/
|
|
public void setToolTipText(String toolTipText) {
|
|
toolTipTextHolder.setValue(toolTipText);
|
|
}//setToolTipText()//
|
|
/**
|
|
* Sets the column's tool tip text.
|
|
* @param toolTipText The tool tip for the column.
|
|
*/
|
|
public void setToolTipText(ResourceReference toolTipText) {
|
|
toolTipTextHolder.setValue(toolTipText);
|
|
}//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;
|
|
getSwtTable().getColumn(index).setResizable(moveable);
|
|
}//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 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 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 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()//
|
|
/**
|
|
* Determines whether there are renderers capable of painting their data.
|
|
* @return Whether one or more renderers, that support painting a cell, were defined for this column.
|
|
*/
|
|
public boolean hasPaintCapableRenderers() {
|
|
return paintRendererCounter != 0;
|
|
}//hasPaintCapableRenderers()//
|
|
/**
|
|
* Determines whether there are renderers capable of creating a component.
|
|
* @return Whether one or more renderers, that support creating a component, were defined for this column.
|
|
*/
|
|
public boolean hasComponentCapableRenderers() {
|
|
return componentRendererCounter != 0;
|
|
}//hasComponentCapableRenderers()//
|
|
/**
|
|
* 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));
|
|
|
|
if(component.usePaint()) {
|
|
paintRendererCounter++;
|
|
}//if//
|
|
|
|
if(component.useControl() != CellComponent.USE_CONTROL_NEVER) {
|
|
componentRendererCounter++;
|
|
}//if//
|
|
}//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 cellDisplay = (Renderer) renderers.get(index);
|
|
|
|
if((cellDisplay instanceof Renderer) && (cellDisplay.type.isAssignableFrom(rowType))) {
|
|
result = ((Renderer) cellDisplay).component;
|
|
}//if//
|
|
}//for//
|
|
}//if//
|
|
|
|
return result;
|
|
}//getCellComponent()//
|
|
/* (non-Javadoc)
|
|
* @see com.foundation.view.swt.IInternalAbstractComponent#getShell()
|
|
*/
|
|
public Shell getShell() {
|
|
return SimpleTable.this.getSwtControl().getShell();
|
|
}//getShell()//
|
|
/* (non-Javadoc)
|
|
* @see com.foundation.view.IMultiResourceAssociationChangeListener#getResourceService()
|
|
*/
|
|
public AbstractResourceService getResourceService() {
|
|
return SimpleTable.this.getResourceService();
|
|
}//getResourceService()//
|
|
/* (non-Javadoc)
|
|
* @see com.foundation.view.ISingleResourceAssociationChangeListener#getDecorationManager()
|
|
*/
|
|
public DecorationManager getDecorationManager() {
|
|
return SimpleTable.this.getDecorationManager();
|
|
}//getDecorationManager()//
|
|
/* (non-Javadoc)
|
|
* @see com.foundation.view.ISingleResourceAssociationChangeListener#addDecoration(com.foundation.view.AbstractDecoration)
|
|
*/
|
|
public void addDecoration(AbstractDecoration decoration) {
|
|
//Never used.//
|
|
}//addDecoration()//
|
|
/* (non-Javadoc)
|
|
* @see com.foundation.view.ISingleResourceAssociationChangeListener#removeDecoration(com.foundation.view.AbstractDecoration)
|
|
*/
|
|
public void removeDecoration(AbstractDecoration decoration) {
|
|
//Never used.//
|
|
}//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: Implement?
|
|
}//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: Implement?
|
|
}//removeDecoration()//
|
|
}//ColumnData//
|
|
|
|
/**
|
|
* SimpleTable 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 SimpleTable(Container parent, String name, int style) {
|
|
super(parent, name, style);
|
|
}//SimpleTable()//
|
|
/* (non-Javadoc)
|
|
* @see com.foundation.view.swt.AbstractComponent#initializeControl(int)
|
|
*/
|
|
protected void initializeControl(int style, Object data) {
|
|
//Create the SWT widget.//
|
|
setSwtWidget(new org.eclipse.swt.widgets.Table(((Container) getContainer()).getSwtParent(), style | SWT.FULL_SELECTION));
|
|
getSwtWidget().setData(this);
|
|
//Set the allows multiple selections flag.//
|
|
setAllowMultiSelection((style & SWT.MULTI) > 0);
|
|
//Make sure the headers are visible by default.//
|
|
getSwtTable().setHeaderVisible(true);
|
|
|
|
//If the container has already been initialized then force the parent to re-layout so that this component will appear.//
|
|
if(((Container) getContainer()).isInitialized()) {
|
|
((Container) getContainer()).getSwtComposite().layout(true, true);
|
|
}//if//
|
|
}//initializeControl()//
|
|
/**
|
|
* Adjusts the visible range of items to show some or all of the selections.
|
|
*/
|
|
public void showSelection() {
|
|
getSwtTable().showSelection();
|
|
}//showSelection()//
|
|
/**
|
|
* Determines whether the view manages the sorting of data.
|
|
* <p><b>Warning: This is only settable when creating the control since once the user sorts things we don't have code to put the humpty dumpty back together again.</b></p>
|
|
* @param inViewSorting Whether the view should handle data sorting, otherwise the model will handle it.
|
|
*/
|
|
public void setInViewSorting(boolean inViewSorting) {
|
|
this.inViewSorting = inViewSorting;
|
|
}//setInViewSorting()//
|
|
/**
|
|
* Determines whether to show the header.
|
|
* @param showHeader Whether the header is visible.
|
|
*/
|
|
public void showHeaders(boolean showHeader) {
|
|
getSwtTable().setHeaderVisible(showHeader);
|
|
}//showHeaders()//
|
|
/**
|
|
* Determines whether to show the grid lines.
|
|
* @param showGridLines Whether the grid lines are visible.
|
|
*/
|
|
public void showGridLines(boolean showGridLines) {
|
|
getSwtTable().setLinesVisible(showGridLines);
|
|
}//showGridLines()//
|
|
/**
|
|
* Gets the index of the top most visible item.
|
|
* @return The top most visible item's index.
|
|
*/
|
|
public Integer getTopIndex() {
|
|
return new Integer(getSwtTable().getTopIndex());
|
|
}//getTopIndex()//
|
|
/**
|
|
* Sets the index of the top most visible item.
|
|
* @parma topIndex The top most visible item's index.
|
|
*/
|
|
public void setTopIndex(Integer topIndex) {
|
|
//Tell the list to update.//
|
|
getSwtTable().setTopIndex(topIndex.intValue());
|
|
}//setTopIndex()//
|
|
/**
|
|
* 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;
|
|
}//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;
|
|
}//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;
|
|
}//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()//
|
|
/**
|
|
* 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.view.swt.CollectionComponent#itemSorted(int[])
|
|
*/
|
|
protected void itemSorted(int[] mapping) {
|
|
if(!inViewSorting) {
|
|
super.itemSorted(mapping);
|
|
}//if//
|
|
}//itemSorted()//
|
|
/* (non-Javadoc)
|
|
* @see com.foundation.view.swt.TableComponent#createRowObject(java.lang.Object)
|
|
*/
|
|
protected TableRowObject createRowObject(Object value) {
|
|
return new SimpleTableRowObject(value);
|
|
}//createRowObject()//
|
|
/* (non-Javadoc)
|
|
* @see com.foundation.view.swt.AbstractComponent#internalViewInitialize()
|
|
*/
|
|
protected void internalViewInitialize() {
|
|
getSwtTable().addSelectionListener(this);
|
|
getSwtTable().addControlListener(this);
|
|
getSwtTable().getVerticalBar().addSelectionListener(this);
|
|
|
|
// getSwtTable().addListener(SWT.Resize, new Listener() {
|
|
// public void handleEvent(Event event) {
|
|
// if(getAutoFit()) {
|
|
// int controlWidth = getSwtTable().getClientArea().width;
|
|
//
|
|
// if(controlWidth != lastControlWidth) {
|
|
// lastControlWidth = controlWidth;
|
|
// fit();
|
|
// }//if//
|
|
// }//if//
|
|
// }//handleEvent()//
|
|
// });
|
|
|
|
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//
|
|
|
|
super.internalViewInitialize();
|
|
|
|
if((!getAutoFit()) && (getFillOnInitialize())) {
|
|
//TODO: The problem with this is the control's size is zero at this time.
|
|
fill();
|
|
}//else if//
|
|
}//internalViewInitialize()//
|
|
/* (non-Javadoc)
|
|
* @see com.foundation.view.swt.TableComponent#initializePaintItemListener()
|
|
*/
|
|
protected void initializePaintItemListener() {
|
|
super.initializePaintItemListener();
|
|
|
|
getSwtTable().addListener(SWT.PaintItem, new Listener() {
|
|
public void handleEvent(Event event) {
|
|
SimpleTableRowObject rowObject = (SimpleTableRowObject) ((TableItem) event.item).getData();
|
|
TableColumn column = getSwtTable().getColumn(event.index);
|
|
ColumnData columnData = (ColumnData) column.getData();
|
|
|
|
if(columnData.hasPaintCapableRenderers()) {
|
|
CellComponent cellComponent = columnData.getCellComponent(rowObject.value.getClass());
|
|
|
|
//Only paint the cell if there is a cell component and it supports painting the cell.//
|
|
if((cellComponent != null) && (cellComponent.supportsPaint()) && (cellComponent.usePaint())) {
|
|
GC gc = event.gc;
|
|
Rectangle rectangle = gc.getClipping();
|
|
|
|
//Set the clip area so the component knows where to draw.//
|
|
gc.setClipping(event.x, event.y, column.getWidth(), event.height);
|
|
//Send GC to the column's cell component.//
|
|
cellComponent.paintCell(rowObject.value, gc);
|
|
//Reset the clipping area.//
|
|
gc.setClipping(rectangle);
|
|
}//if//
|
|
}//if//
|
|
}//handleEvent()//
|
|
});
|
|
}//initializePaintItemListener()//
|
|
/**
|
|
* Initializes the measure item listener.
|
|
*/
|
|
protected void initializeMeasureItemListener() {
|
|
getSwtTable().addListener(SWT.MeasureItem, new Listener() {
|
|
public void handleEvent(Event event) {
|
|
switch(event.type) {
|
|
case SWT.MeasureItem: {
|
|
if(rowHeightValue > 0) {
|
|
event.height = rowHeightValue;
|
|
}//if//
|
|
else {
|
|
TableItem item = (TableItem) event.item;
|
|
//TableRowObject rowObject = (TableRowObject) item.getData();
|
|
ColumnData column = (ColumnData) getColumn(event.index);
|
|
TableEditor editor = column.getTableEditor(item);
|
|
|
|
if(minimumTableEditorHeight > event.height) {
|
|
event.height = minimumTableEditorHeight;
|
|
}//if//
|
|
|
|
//Note: minimumTableEditorHeight should suffice, but are we properly updating it as the editors change content?
|
|
//TODO: Cache the editor's control's preferred height? It is unlikely to change (but I suppose it is possible for things like multi line text controls without scroll bars?).
|
|
if(editor != null) {
|
|
if(event.height < editor.minimumHeight) {
|
|
event.height = editor.minimumHeight;
|
|
}//if//
|
|
|
|
Control control = editor.getEditor();
|
|
Point point = control.computeSize(event.width, event.height);
|
|
|
|
if(point.y > event.height) {
|
|
event.height = point.y;
|
|
}//if//
|
|
}//if//
|
|
}//else//
|
|
|
|
//Note: Commented out this next line because calling getItemHeight() is a recursive call.//
|
|
//if(((rowHeightValue > 0) && (getSwtTable().getItemHeight() != rowHeightValue)) || (minimumTableEditorHeight > 0 && getSwtTable().getItemHeight() < minimumTableEditorHeight)) {
|
|
// if(rowHeightValue > 0 || minimumTableEditorHeight > 0) {
|
|
// event.height = rowHeightValue > 0 ? rowHeightValue : minimumTableEditorHeight;
|
|
/* Note: Commented this block because it causes recursive redrawing in certain cases. It should also be unnecessary since the column width has nothing to do with the height.
|
|
SwtUtilities.setRedraw(getSwtTable(), false);
|
|
|
|
getSwtTable().getDisplay().asyncExec(new Runnable() {
|
|
public void run() {
|
|
try {
|
|
if(getAutoFit()) {
|
|
int controlWidth = getSwtTable().getClientArea().width;
|
|
|
|
if(controlWidth != lastControlWidth) {
|
|
lastControlWidth = controlWidth;
|
|
fit();
|
|
}//if//
|
|
}//if//
|
|
|
|
for(int columnIndex = getColumnCount() - 1; columnIndex >= 0; columnIndex--) {
|
|
((ColumnData) getColumn(columnIndex)).layoutRenderers();
|
|
}//for//
|
|
}//try//
|
|
finally {
|
|
SwtUtilities.setRedraw(getSwtTable(), true);
|
|
getSwtTable().redraw();
|
|
}//finally//
|
|
}//run()//
|
|
});
|
|
*/
|
|
// }//if//
|
|
break;
|
|
}//case//
|
|
}//switch//
|
|
}//handleEvent()//
|
|
});
|
|
}//initializeMeasureItemListener()//
|
|
/* (non-Javadoc)
|
|
* @see com.foundation.view.swt.AbstractComponent#internalViewRelease()
|
|
*/
|
|
protected void internalViewRelease() {
|
|
if(!getSwtTable().isDisposed()) {
|
|
getSwtTable().removeSelectionListener(this);
|
|
getSwtTable().removeControlListener(this);
|
|
}//if//
|
|
|
|
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.view.swt.TableComponent#internalViewRefresh()
|
|
*/
|
|
protected void internalViewRefresh() {
|
|
super.internalViewRefresh();
|
|
}//internalViewRefresh()//
|
|
/* (non-Javadoc)
|
|
* @see com.foundation.view.swt.AbstractComponent#internalOnEventFired(com.foundation.view.IEventAssociation, java.lang.Object[])
|
|
*/
|
|
protected void internalOnEventFired(IEventAssociation eventAssociation, Object[] eventArguments) {
|
|
if((fillEventAssociations != null) && (fillEventAssociations.containsValue(eventAssociation))) {
|
|
lastControlWidth = getSwtTable().getClientArea().width;
|
|
fill();
|
|
}//if//
|
|
else if((fitEventAssociations != null) && (fitEventAssociations.containsValue(eventAssociation))) {
|
|
lastControlWidth = getSwtTable().getClientArea().width;
|
|
fit();
|
|
}//else if//
|
|
else {
|
|
super.internalOnEventFired(eventAssociation, eventArguments);
|
|
}//else//
|
|
}//internalOnEventFired()//
|
|
/* (non-Javadoc)
|
|
* @see com.foundation.view.swt.AbstractComponent#internalOnLinkInvoked(int, java.lang.Object)
|
|
*/
|
|
protected void internalOnLinkInvoked(int linkTarget, Object data) {
|
|
switch(linkTarget) {
|
|
case LINK_TARGET_FILL: {
|
|
lastControlWidth = getSwtTable().getClientArea().width;
|
|
fill();
|
|
break;
|
|
}//case//
|
|
case LINK_TARGET_FIT: {
|
|
lastControlWidth = getSwtTable().getClientArea().width;
|
|
fit();
|
|
break;
|
|
}//case//
|
|
default: {
|
|
super.internalOnLinkInvoked(linkTarget, data);
|
|
break;
|
|
}//default//
|
|
}//switch//
|
|
}//internalOnLinkInvoked()//
|
|
/**
|
|
* Fills the available space by expanding all resizeable columns.
|
|
*/
|
|
protected void fill() {
|
|
int width = lastControlWidth;
|
|
TableColumn[] columns = getSwtTable().getColumns();
|
|
int totalColumnWidth = 0;
|
|
int increaseWidth = 0;
|
|
int extraIncreaseWidth = 0;
|
|
int resizeableColumnCount = 0;
|
|
|
|
for(int index = 0; index < columns.length; index++) {
|
|
totalColumnWidth += columns[index].getWidth();
|
|
|
|
if(columns[index].getResizable()) {
|
|
resizeableColumnCount++;
|
|
}//if//
|
|
}//for//
|
|
|
|
if(width > totalColumnWidth) {
|
|
if(resizeableColumnCount > 0) {
|
|
stopRendering();
|
|
suspendColumnResizeEvents = true;
|
|
|
|
try {
|
|
increaseWidth = (int) Math.floor((width - totalColumnWidth) / (double) resizeableColumnCount);
|
|
extraIncreaseWidth = (width - totalColumnWidth) % resizeableColumnCount;
|
|
|
|
for(int index = 0; index < columns.length; index++) {
|
|
if(columns[index].getResizable()) {
|
|
int newWidth = columns[index].getWidth() + increaseWidth;
|
|
|
|
//Add one to the new width for the extra pixels.//
|
|
if(resizeableColumnCount <= extraIncreaseWidth) {
|
|
newWidth++;
|
|
}//if//
|
|
|
|
//Set the new width and decrement the resizeable column count so we track how many columns to add the extra pixel to.//
|
|
columns[index].setWidth(newWidth);
|
|
resizeableColumnCount--;
|
|
}//if//
|
|
}//for//
|
|
}//try//
|
|
finally {
|
|
suspendColumnResizeEvents = false;
|
|
startRendering();
|
|
redraw();
|
|
}//finally//
|
|
}//if//
|
|
}//if//
|
|
}//fill()//
|
|
/**
|
|
* Fits the resizeable columns to fill all available table space without needing a horizontal scroll bar.
|
|
*/
|
|
protected void fit() {
|
|
fit(null);
|
|
}//fit()//
|
|
/**
|
|
* Fits the resizeable columns to fill all available table space without needing a horizontal scroll bar.
|
|
* @param ignoredColumn The column to be ignored in the fit operation. Note that there must be at least 2 resizeable columns for this algorithm to work, and no column should be resized less than the minimum size.
|
|
*/
|
|
protected void fit(TableColumn ignoredColumn) {
|
|
int controlWidth = lastControlWidth;
|
|
TableColumn[] columns = getSwtTable().getColumns();
|
|
int extraWidth = 0;
|
|
LiteList resizeableColumns = new LiteList(columns.length);
|
|
int totalMinimumWidth = 0;
|
|
int availableWidth = controlWidth - extraWidth;
|
|
int currentColumnWidthTotal = 0;
|
|
int fixedWidth = 0;
|
|
|
|
for(int index = 0; index < columns.length; index++) {
|
|
if((columns[index] != ignoredColumn) && (columns[index].getResizable())) {
|
|
resizeableColumns.add(columns[index]);
|
|
totalMinimumWidth += ((ColumnData) columns[index].getData()).getMinimumWidth();
|
|
}//if//
|
|
else {
|
|
if(!columns[index].getResizable()) {
|
|
fixedWidth += columns[index].getWidth();
|
|
}//if//
|
|
|
|
availableWidth -= columns[index].getWidth();
|
|
}//else//
|
|
|
|
currentColumnWidthTotal += columns[index].getWidth();
|
|
}//for//
|
|
|
|
//The width of the control which can be divied up between the resizable columns.//
|
|
availableWidth -= totalMinimumWidth;
|
|
|
|
//Detect formatting errors that cannot be worked around.//
|
|
if((controlWidth > 0) && (resizeableColumns.getSize() > 0) && (availableWidth > 0) && (currentColumnWidthTotal != controlWidth)) {
|
|
int[] columnSizes = new int[resizeableColumns.getSize()];
|
|
int totalColumnSizes = 0;
|
|
int newTotalColumnSizes = 0;
|
|
|
|
//Record the previous sizes (minus the minimum width to make the equation simpler).//
|
|
for(int index = 0; index < resizeableColumns.getSize(); index++) {
|
|
TableColumn next = (TableColumn) resizeableColumns.get(index);
|
|
|
|
totalColumnSizes += (columnSizes[index] = (next.getWidth() - ((ColumnData) next.getData()).getMinimumWidth()));
|
|
}//for//
|
|
|
|
//Resize the columns relative to their previous sizes.//
|
|
for(int index = 0; index < columnSizes.length; index++) {
|
|
TableColumn next = (TableColumn) resizeableColumns.get(index);
|
|
|
|
newTotalColumnSizes += (columnSizes[index] = ((int) Math.round((columnSizes[index] / (double) totalColumnSizes) * availableWidth)) + ((ColumnData) next.getData()).getMinimumWidth());
|
|
}//for//
|
|
|
|
availableWidth += totalMinimumWidth;
|
|
//Debug.log("New Total Column Sizes: " + newTotalColumnSizes + " Control Width - Fixed Width: " + availableWidth);
|
|
|
|
//Adjust the column sizes to take up the exact right amount of space.//
|
|
for(int index = 0; (index < columnSizes.length) && (newTotalColumnSizes != availableWidth); index++) {
|
|
if(newTotalColumnSizes < availableWidth) {
|
|
//Debug.log("Adding");
|
|
columnSizes[index]++;
|
|
newTotalColumnSizes++;
|
|
}//if//
|
|
else {
|
|
//Debug.log("Removing");
|
|
columnSizes[index]--;
|
|
newTotalColumnSizes--;
|
|
}//else//
|
|
}//for//
|
|
|
|
stopRendering();
|
|
suspendColumnResizeEvents = true;
|
|
|
|
try {
|
|
for(int index = 0; index < resizeableColumns.getSize(); index++) {
|
|
((TableColumn) resizeableColumns.get(index)).setWidth(columnSizes[index]);
|
|
}//for//
|
|
}//try//
|
|
finally {
|
|
suspendColumnResizeEvents = false;
|
|
startRendering();
|
|
redraw();
|
|
}//finally//
|
|
}//if//
|
|
else if((availableWidth < 0) && (ignoredColumn != null)) {
|
|
int minimumWidth = ((ColumnData) ignoredColumn.getData()).getMinimumWidth();
|
|
|
|
stopRendering();
|
|
suspendColumnResizeEvents = true;
|
|
|
|
try {
|
|
//Ensure all columns that can be resized are set to their minimum width.//
|
|
for(int index = 0; index < resizeableColumns.getSize(); index++) {
|
|
TableColumn column = (TableColumn) resizeableColumns.get(index);
|
|
|
|
column.setWidth(((ColumnData) column.getData()).getMinimumWidth());
|
|
}//for//
|
|
|
|
//Adjust the ignored column to either its minimum width, or to fill available space.//
|
|
if((ignoredColumn.getWidth() - minimumWidth + availableWidth) > 0) {
|
|
ignoredColumn.setWidth(controlWidth - extraWidth - fixedWidth - totalMinimumWidth);
|
|
}//if//
|
|
else {
|
|
ignoredColumn.setWidth(minimumWidth);
|
|
}//else//
|
|
}//try//
|
|
finally {
|
|
suspendColumnResizeEvents = false;
|
|
startRendering();
|
|
redraw();
|
|
}//finally//
|
|
}//else if//
|
|
|
|
//Test Code//
|
|
//int newColumnWidthTotal = 0;
|
|
//for(int index = 0; index < columns.length; index++) {
|
|
// newColumnWidthTotal += columns[index].getWidth();
|
|
//}//for//
|
|
|
|
//Debug.log("Total column width: " + newColumnWidthTotal + " Control client width: " + getSwtTable().getClientArea().width + "\n");
|
|
}//fit()//
|
|
/* (non-Javadoc)
|
|
* @see com.foundation.view.swt.TableComponent#registerItem(java.lang.Object, com.foundation.view.swt.TableComponent.TableRowObject)
|
|
*/
|
|
protected void registerItem(Object item, TableRowObject rowObject) {
|
|
super.registerItem(item, rowObject);
|
|
}//registerItem()//
|
|
/* (non-Javadoc)
|
|
* @see com.foundation.view.swt.CollectionComponent#unregisterItem(java.lang.Object)
|
|
*/
|
|
protected void unregisterItem(Object item) {
|
|
super.unregisterItem(item);
|
|
}//unregisterItem()//
|
|
/* (non-Javadoc)
|
|
* @see com.foundation.view.swt.CollectionComponent#unregisterItems()
|
|
*/
|
|
protected void unregisterItems() {
|
|
super.unregisterItems();
|
|
}//unregisterItems()//
|
|
/**
|
|
* Processes a double click on a table item.
|
|
*/
|
|
protected void doDoubleClick() {
|
|
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(getAllowMultiSelection()) {
|
|
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//
|
|
}//doDoubleClick()//
|
|
/**
|
|
* Called when a column is added to the table.
|
|
* @param columnData The metadata for the column. This should be associated with the table column.
|
|
* @param column The column added.
|
|
*/
|
|
protected void internalColumnAdded(ColumnData columnData, final TableColumn column) {
|
|
columnData.setTableColumn(column);
|
|
column.setData(columnData);
|
|
//Set the initial width.//
|
|
column.setWidth(100);
|
|
//TODO: Make the moveable feature be configurable.
|
|
column.setMoveable(true);
|
|
//Add a listener to resize the columns to fit the space if we are performing auto-fit.//
|
|
column.addControlListener(new ControlListener() {
|
|
public void controlResized(ControlEvent event) {
|
|
if(isInitialized() && !suspendColumnResizeEvents) {
|
|
if(((ColumnData) column.getData()).getMinimumWidth() > column.getWidth()) {
|
|
//Enforce the minimum width.//
|
|
column.setWidth(((ColumnData) column.getData()).getMinimumWidth());
|
|
}//if//
|
|
else if(autoFit) {
|
|
fit(column);
|
|
}//else if//
|
|
}//if//
|
|
}//controlResized()//
|
|
public void controlMoved(ControlEvent event) {
|
|
}//controlMoved()//
|
|
});
|
|
//Add a sorting handler to the column.//
|
|
column.addSelectionListener(new SelectionListener() {
|
|
public void widgetDefaultSelected(SelectionEvent e) {
|
|
widgetSelected(e);
|
|
}//widgetDefaultSelected()//
|
|
public void widgetSelected(SelectionEvent e) {
|
|
if((inViewSorting) && (getSwtTable().getColumnCount() > 1)) {
|
|
int columnCount = getSwtTable().getColumnCount();
|
|
int columnIndex = getSwtTable().indexOf(column);
|
|
boolean reverse = isSortReversed = (columnIndex == lastSortedColumnIndex ? !isSortReversed : false);
|
|
TableItem[] mapping = getSwtTable().getItems();
|
|
TableItem[] selected = getSwtTable().getSelection();
|
|
|
|
if(getSwtTable().getItemCount() > 0) {
|
|
boolean done = false;
|
|
|
|
//TODO: Replace this for large tables.
|
|
//Perform a bubble sort on the table items.//
|
|
while(!done) {
|
|
String text1 = mapping[0].getText(columnIndex);
|
|
|
|
done = true;
|
|
|
|
for(int index = 1; index < mapping.length; index++) {
|
|
String text2 = mapping[index].getText(columnIndex);
|
|
|
|
if(requiresSwap(text1, text2, reverse)) {
|
|
TableItem temp = mapping[index];
|
|
|
|
mapping[index] = mapping[index - 1];
|
|
mapping[index - 1] = temp;
|
|
done = false;
|
|
}//if//
|
|
|
|
text1 = text2;
|
|
}//for//
|
|
}//while//
|
|
|
|
stopRendering();
|
|
|
|
try {
|
|
//Rebuild the table items since we can't reuse them.//
|
|
for(int index = 0; index < mapping.length; index++) {
|
|
TableItem tableItem = (TableItem) mapping[index];
|
|
TableItem newTableItem = new TableItem(getSwtTable(), tableItem.getStyle(), index);
|
|
|
|
newTableItem.setChecked(tableItem.getChecked());
|
|
newTableItem.setGrayed(tableItem.getGrayed());
|
|
newTableItem.setText(tableItem.getText());
|
|
newTableItem.setImage(tableItem.getImage());
|
|
newTableItem.setBackground(tableItem.getBackground());
|
|
newTableItem.setForeground(tableItem.getForeground());
|
|
newTableItem.setFont(tableItem.getFont());
|
|
newTableItem.setData(tableItem.getData());
|
|
|
|
for(int column = 0; column < columnCount; column++) {
|
|
newTableItem.setText(column, tableItem.getText(column));
|
|
newTableItem.setImage(column, tableItem.getImage(column));
|
|
newTableItem.setBackground(column, tableItem.getBackground(column));
|
|
newTableItem.setForeground(column, tableItem.getForeground(column));
|
|
newTableItem.setFont(column, tableItem.getFont(column));
|
|
}//for//
|
|
|
|
((SimpleTableRowObject) tableItem.getData()).replaceControlItem(tableItem, newTableItem);
|
|
|
|
//TODO: Replace this for large selections.
|
|
for(int selectedIndex = 0; selectedIndex < selected.length; selectedIndex++) {
|
|
if(selected[selectedIndex] == tableItem) {
|
|
selected[selectedIndex] = newTableItem;
|
|
}//if//
|
|
}//for//
|
|
|
|
tableItem.dispose();
|
|
}//for//
|
|
|
|
updateRowColors(0);
|
|
updateTableEditors();
|
|
}//try//
|
|
finally {
|
|
startRendering();
|
|
}//finally//
|
|
}//if//
|
|
|
|
//Save the last sorted column index so we know when to reverse the order of the sort.//
|
|
lastSortedColumnIndex = columnIndex;
|
|
//Set the new selection.//
|
|
getSwtTable().setSelection(selected); //TODO: Should this be inside the try block above?
|
|
getSwtTable().setSortColumn(column);
|
|
getSwtTable().setSortDirection(reverse ? SWT.UP : SWT.DOWN);
|
|
}//if//
|
|
}//widgetSelected()//
|
|
});
|
|
}//internalColumnAdded()//
|
|
/**
|
|
* Gets the top row index.
|
|
* @return The top most visible row index.
|
|
*/
|
|
protected Integer internalGetTopIndex() {
|
|
return new Integer(getSwtTable().getTopIndex());
|
|
}//internalGetTopIndex()//
|
|
/**
|
|
* Sets the top row index.
|
|
* @param topIndex The top most visible row index.
|
|
*/
|
|
protected void internalSetTopIndex(Integer topIndex) {
|
|
getSwtTable().setTopIndex(topIndex.intValue());
|
|
}//internalSetTopIndex()//
|
|
/* (non-Javadoc)
|
|
* @see com.foundation.view.swt.TableComponent#controlOrderRows(int[])
|
|
*/
|
|
protected void controlOrderRows(int[] mapping) {
|
|
if(!inViewSorting) {
|
|
int columnCount = getSwtTable().getColumnCount();
|
|
TableItem[] tableItems = getSwtTable().getItems();
|
|
int tableItemCount = tableItems.length;
|
|
IList newTableItems = new LiteList(tableItemCount + 100);
|
|
int selectionIndex = getAllowMultiSelection() ? 0 : getSwtTable().getSelectionIndex();
|
|
int[] selectionIndices = getAllowMultiSelection() ? getSwtTable().getSelectionIndices() : null;
|
|
|
|
stopRendering();
|
|
suspendSelectionEvents = true;
|
|
|
|
try {
|
|
for(int index = 0; index < tableItemCount; index++) {
|
|
TableItem tableItem = (TableItem) tableItems[mapping[index]];
|
|
TableItem newTableItem = new TableItem(getSwtTable(), tableItem.getStyle(), index);
|
|
|
|
newTableItem.setChecked(tableItem.getChecked());
|
|
newTableItem.setGrayed(tableItem.getGrayed());
|
|
newTableItem.setText(tableItem.getText());
|
|
newTableItem.setImage(tableItem.getImage());
|
|
newTableItem.setBackground(tableItem.getBackground());
|
|
newTableItem.setForeground(tableItem.getForeground());
|
|
newTableItem.setFont(tableItem.getFont());
|
|
newTableItem.setData(tableItem.getData());
|
|
|
|
for(int column = 0; column < columnCount; column++) {
|
|
newTableItem.setText(column, tableItem.getText(column));
|
|
newTableItem.setImage(column, tableItem.getImage(column));
|
|
newTableItem.setBackground(column, tableItem.getBackground(column));
|
|
newTableItem.setForeground(column, tableItem.getForeground(column));
|
|
newTableItem.setFont(column, tableItem.getFont(column));
|
|
}//for//
|
|
|
|
newTableItems.add(newTableItem);
|
|
((SimpleTableRowObject) tableItem.getData()).replaceControlItem(tableItem, newTableItem);
|
|
tableItem.dispose();
|
|
}//for//
|
|
|
|
//Refresh the selection.//
|
|
if(getAllowMultiSelection()) {
|
|
if(selectionIndices != null && selectionIndices.length > 0) {
|
|
for(int index = 0; index < selectionIndices.length; index++) {
|
|
selectionIndices[index] = mapping[selectionIndices[index]];
|
|
}//for//
|
|
|
|
getSwtTable().setSelection(selectionIndices);
|
|
}//if//
|
|
}//if//
|
|
else {
|
|
if(selectionIndex >= 0) {
|
|
selectionIndex = mapping[selectionIndex];
|
|
getSwtTable().setSelection(selectionIndex);
|
|
}//if//
|
|
}//else//
|
|
}//try//
|
|
finally {
|
|
startRendering();
|
|
suspendSelectionEvents = false;
|
|
}//finally//
|
|
|
|
updateRowColors(0);
|
|
}//if//
|
|
}//controlOrderRows()//
|
|
/* (non-Javadoc)
|
|
* @see com.foundation.view.swt.TableComponent#controlRemoveAll()
|
|
*/
|
|
protected void controlRemoveAll() {
|
|
suspendUpdateTableEditors(true);
|
|
|
|
//Dispose of any color, font, or image resources used.//
|
|
for(int itemIndex = 0; itemIndex < getSwtTable().getItemCount(); itemIndex++) {
|
|
TableItem tableItem = getSwtTable().getItem(itemIndex);
|
|
|
|
destroyImage(tableItem.getImage());
|
|
destroyColor(tableItem.getBackground());
|
|
destroyColor(tableItem.getForeground());
|
|
destroyFont(tableItem.getFont());
|
|
|
|
for(int columnIndex = 0; columnIndex < getSwtTable().getColumnCount(); columnIndex++) {
|
|
destroyImage(tableItem.getImage(columnIndex));
|
|
destroyColor(tableItem.getBackground(columnIndex));
|
|
destroyColor(tableItem.getForeground(columnIndex));
|
|
destroyFont(tableItem.getFont(columnIndex));
|
|
}//for//
|
|
}//for//
|
|
|
|
try {
|
|
getSwtTable().removeAll();
|
|
}//try//
|
|
finally {
|
|
suspendUpdateTableEditors(false);
|
|
}//finally//
|
|
|
|
updateTableEditors();
|
|
}//controlRemoveAll()//
|
|
/* (non-Javadoc)
|
|
* @see com.foundation.view.swt.TableComponent#controlAddRow(com.foundation.view.swt.TableComponent.TableRowObject, java.lang.Object[], int)
|
|
*/
|
|
protected Object controlAddRow(TableRowObject rowObject, int index) {
|
|
TableItem tableItem = null;
|
|
Table table = getSwtTable();
|
|
Object item = rowObject.getValue();
|
|
|
|
suspendResizeEvents = true;
|
|
suspendUpdateTableEditors(true);
|
|
|
|
try {
|
|
int columnCount = table.getColumnCount();
|
|
JefColor rowForegroundColor = rowObject.rowForegroundColorCustomHolder != null ? (JefColor) rowObject.rowForegroundColorCustomHolder.getValue() : null;
|
|
JefColor rowBackgroundColor = rowObject.rowBackgroundColorCustomHolder != null ? (JefColor) rowObject.rowBackgroundColorCustomHolder.getValue() : null;
|
|
|
|
//Sort the item if necessary.//
|
|
if(lastSortedColumnIndex == -1) {
|
|
tableItem = index == -1 ? new TableItem(table, 0, index = table.getItemCount()) : new TableItem(table, 0, index);
|
|
}//if//
|
|
else {
|
|
TableItem[] rows = table.getItems();
|
|
ColumnData columnData = (ColumnData) getColumn(lastSortedColumnIndex);
|
|
String newText = (String) columnData.cellText.getValue(item);
|
|
|
|
for(int rowIndex = 0; (tableItem == null) && (rowIndex < rows.length); rowIndex++) {
|
|
String nextText = rows[rowIndex].getText(lastSortedColumnIndex);
|
|
|
|
if(!requiresSwap(newText, nextText, isSortReversed)) {
|
|
index = rowIndex;
|
|
tableItem = new TableItem(table, 0, index);
|
|
}//if//
|
|
}//for//
|
|
|
|
if(tableItem == null) {
|
|
index = rows.length;
|
|
tableItem = new TableItem(table, 0, index);
|
|
}//if//
|
|
}//else//
|
|
|
|
//Determine the correct foreground color.//
|
|
if(rowForegroundColor == null) {
|
|
//If odd use the alt color if available, otherwise the primary, otherwise null.//
|
|
if((index % 2) == 1) {
|
|
if(rowForegroundColorAltHolder != null) {
|
|
rowForegroundColor = (JefColor) rowForegroundColorAltHolder.getValue();
|
|
}//if//
|
|
else if(rowForegroundColorHolder != null) {
|
|
rowForegroundColor = (JefColor) rowForegroundColorHolder.getValue();
|
|
}//else if//
|
|
}//if//
|
|
else if(rowForegroundColorHolder != null) {
|
|
rowForegroundColor = (JefColor) rowForegroundColorHolder.getValue();
|
|
}//else if//
|
|
}//if//
|
|
|
|
//Determine the correct background color.//
|
|
if(rowBackgroundColor == null) {
|
|
//If odd use the alt color if available, otherwise the primary, otherwise null.//
|
|
if((index % 2) == 1) {
|
|
if(rowBackgroundColorAltHolder != null) {
|
|
rowBackgroundColor = (JefColor) rowBackgroundColorAltHolder.getValue();
|
|
}//if//
|
|
else if(rowBackgroundColorHolder != null) {
|
|
rowBackgroundColor = (JefColor) rowBackgroundColorHolder.getValue();
|
|
}//else if//
|
|
}//if//
|
|
else if(rowBackgroundColorHolder != null) {
|
|
rowBackgroundColor = (JefColor) rowBackgroundColorHolder.getValue();
|
|
}//else if//
|
|
}//if//
|
|
|
|
//Set the row coloring.//
|
|
tableItem.setBackground(createColor(rowBackgroundColor));
|
|
tableItem.setForeground(createColor(rowForegroundColor));
|
|
|
|
//Set the row font.//
|
|
if(rowObject.rowFontHolder != null) {
|
|
tableItem.setFont(createFont((JefFont[]) rowObject.rowFontHolder.getValue()));
|
|
}//if//
|
|
|
|
//Set the column data for each column.//
|
|
for(int columnIndex = 0; columnIndex < columnCount; columnIndex++) {
|
|
ColumnData columnData = (ColumnData) getColumn(columnIndex);
|
|
String cellText = (String) columnData.cellText.getValue(item);
|
|
|
|
tableItem.setText(columnIndex, cellText == null ? "" : cellText);
|
|
tableItem.setImage(columnIndex, createImage((JefImage) columnData.cellImageHolder.getValue(item)));
|
|
tableItem.setBackground(columnIndex, createColor((JefColor) columnData.backgroundColorHolder.getValue(item)));
|
|
tableItem.setForeground(columnIndex, createColor((JefColor) columnData.foregroundColorHolder.getValue(item)));
|
|
tableItem.setFont(columnIndex, createFont((JefFont[]) columnData.fontHolder.getValue(item)));
|
|
}//for//
|
|
|
|
//Save a reference to the row object from the table item.//
|
|
tableItem.setData(rowObject);
|
|
|
|
//If this wasn't the last row and alternate colors are provided then we must update the coloring of the subsiquent rows.//
|
|
if((rowBackgroundColorAltHolder != null || rowForegroundColorAltHolder != null) && index < table.getItemCount() + 1) {
|
|
updateRowColors(index + 1);
|
|
}//if//
|
|
}//try//
|
|
finally {
|
|
suspendResizeEvents = false;
|
|
suspendUpdateTableEditors(false);
|
|
}//finally//
|
|
|
|
if(getAutoFit()) {
|
|
int controlWidth = table.getClientArea().width;
|
|
|
|
if(controlWidth != lastControlWidth) {
|
|
lastControlWidth = controlWidth;
|
|
fit();
|
|
}//if//
|
|
}//if//
|
|
|
|
updateTableEditors();
|
|
layoutRenderers();
|
|
|
|
return tableItem;
|
|
}//controlAddRow()//
|
|
/* (non-Javadoc)
|
|
* @see com.foundation.view.swt.TableComponent#controlRemoveRow(java.lang.Object)
|
|
*/
|
|
protected void controlRemoveRow(Object tableItemData) {
|
|
suspendUpdateTableEditors(true);
|
|
|
|
try {
|
|
TableItem tableItem = (TableItem) tableItemData;
|
|
|
|
//Dispose of any color, font, or image resources used.//
|
|
destroyImage(tableItem.getImage());
|
|
destroyColor(tableItem.getBackground());
|
|
destroyColor(tableItem.getForeground());
|
|
destroyFont(tableItem.getFont());
|
|
|
|
for(int columnIndex = 0; columnIndex < getSwtTable().getColumnCount(); columnIndex++) {
|
|
destroyImage(tableItem.getImage(columnIndex));
|
|
destroyColor(tableItem.getBackground(columnIndex));
|
|
destroyColor(tableItem.getForeground(columnIndex));
|
|
destroyFont(tableItem.getFont(columnIndex));
|
|
}//for//
|
|
|
|
tableItem.dispose();
|
|
}//try//
|
|
finally {
|
|
suspendUpdateTableEditors(false);
|
|
}//finally//
|
|
|
|
if(getAutoFit()) {
|
|
int controlWidth = getSwtTable().getClientArea().width;
|
|
|
|
if(controlWidth != lastControlWidth) {
|
|
lastControlWidth = controlWidth;
|
|
fit();
|
|
}//if//
|
|
}//if//
|
|
|
|
updateTableEditors();
|
|
layoutRenderers();
|
|
updateRowColors(0); //TODO: Is it easier to update all, or figure out what the index of the item was?
|
|
}//controlRemoveRow()//
|
|
/* (non-Javadoc)
|
|
* @see com.foundation.view.swt.TableComponent#controlAddColumn(com.foundation.view.swt.TableComponent.AbstractColumn)
|
|
*/
|
|
protected void controlAddColumn(AbstractColumn columnData) {
|
|
if(!getSwtTable().isDisposed()) {
|
|
internalColumnAdded((ColumnData) columnData, new TableColumn(getSwtTable(), 0));
|
|
}//if//
|
|
}//controlAddColumn()//
|
|
/* (non-Javadoc)
|
|
* @see com.foundation.view.swt.TableComponent#controlAddColumn(com.foundation.view.swt.TableComponent.AbstractColumn, int)
|
|
*/
|
|
protected void controlAddColumn(AbstractColumn columnData, int columnIndex) {
|
|
if(!getSwtTable().isDisposed()) {
|
|
internalColumnAdded((ColumnData) columnData, new TableColumn(getSwtTable(), 0, columnIndex));
|
|
}//if//
|
|
}//controlAddColumn()//
|
|
/* (non-Javadoc)
|
|
* @see com.foundation.view.swt.TableComponent#controlRemoveColumn(int)
|
|
*/
|
|
protected void controlRemoveColumn(int columnIndex) {
|
|
if(!getSwtTable().getColumn(columnIndex).isDisposed()) {
|
|
getSwtTable().getColumn(columnIndex).dispose();
|
|
}//if//
|
|
}//controlRemoveColumn()//
|
|
/* (non-Javadoc)
|
|
* @see com.foundation.view.swt.TableComponent#controlAddSelection(java.lang.Object)
|
|
*/
|
|
protected void controlAddSelection(Object tableItemData) {
|
|
if(!getSwtTable().isDisposed()) {
|
|
TableItem tableItem = (TableItem) tableItemData;
|
|
int count = getSwtTable().getSelectionCount();
|
|
|
|
getSwtTable().select(getSwtTable().indexOf(tableItem));
|
|
|
|
if(count == 0) {
|
|
getSwtTable().showItem(tableItem);
|
|
}//if//
|
|
}//if//
|
|
}//controlAddSelection()//
|
|
/* (non-Javadoc)
|
|
* @see com.foundation.view.swt.TableComponent#controlRemoveSelection(java.lang.Object)
|
|
*/
|
|
protected void controlRemoveSelection(Object tableItemData) {
|
|
if(!getSwtTable().isDisposed()) {
|
|
TableItem tableItem = (TableItem) tableItemData;
|
|
|
|
getSwtTable().deselect(getSwtTable().indexOf(tableItem));
|
|
}//if//
|
|
}//controlRemoveSelection()//
|
|
/* (non-Javadoc)
|
|
* @see com.foundation.view.swt.TableComponent#controlRemoveAllSelections()
|
|
*/
|
|
protected void controlRemoveAllSelections() {
|
|
if(!getSwtTable().isDisposed()) {
|
|
getSwtTable().deselectAll();
|
|
}//if//
|
|
}//controlRemoveAllSelections()//
|
|
/* (non-Javadoc)
|
|
* @see com.foundation.view.swt.TableComponent#controlSetSelection(java.lang.Object)
|
|
*/
|
|
protected void controlSetSelection(Object tableItemData) {
|
|
if(!getSwtTable().isDisposed()) {
|
|
TableItem tableItem = (TableItem) tableItemData;
|
|
|
|
getSwtTable().setSelection(getSwtTable().indexOf(tableItem));
|
|
getSwtTable().showItem(tableItem);
|
|
}//if//
|
|
}//controlSetSelection()//
|
|
/* (non-Javadoc)
|
|
* @see com.foundation.view.swt.TableComponent#controlSetSelections(com.common.util.IList)
|
|
*/
|
|
protected void controlSetSelections(IList tableItemData) {
|
|
if(!getSwtTable().isDisposed()) {
|
|
TableItem[] tableItems = new TableItem[tableItemData.getSize()];
|
|
|
|
//Collect the table items for the selected rows.//
|
|
for(int index = 0; index < tableItems.length; index++) {
|
|
tableItems[index] = (TableItem) tableItemData.get(index);
|
|
}//for//
|
|
|
|
getSwtTable().setSelection(tableItems);
|
|
|
|
if(tableItems.length > 0) {
|
|
getSwtTable().showItem(tableItems[0]);
|
|
}//if//
|
|
}//if//
|
|
}//controlSetSelections()//
|
|
/* (non-Javadoc)
|
|
* @see com.foundation.view.swt.TableComponent#controlGetSelection()
|
|
*/
|
|
protected TableRowObject controlGetSelection() {
|
|
int selectionIndex = getSwtTable().getSelectionIndex();
|
|
|
|
return selectionIndex == -1 ? null : (SimpleTableRowObject) getSwtTable().getItem(selectionIndex).getData();
|
|
}//controlGetSelection()//
|
|
/* (non-Javadoc)
|
|
* @see com.foundation.view.swt.TableComponent#controlGetSelections()
|
|
*/
|
|
protected TableRowObject[] controlGetSelections() {
|
|
TableRowObject[] results = null;
|
|
|
|
if(getSwtTable().getSelectionCount() > 0) {
|
|
TableItem[] tableItems = getSwtTable().getSelection();
|
|
|
|
results = new TableRowObject[tableItems.length];
|
|
|
|
for(int index = 0; index < tableItems.length; index++) {
|
|
results[index] = (SimpleTableRowObject) tableItems[index].getData();
|
|
}//for//
|
|
}//if//
|
|
|
|
return results;
|
|
}//controlGetSelections()//
|
|
/* (non-Javadoc)
|
|
* @see com.foundation.view.swt.TableComponent#controlIsSelected(java.lang.Object)
|
|
*/
|
|
protected boolean controlIsSelected(Object tableItemData) {
|
|
TableItem tableItem = (TableItem) tableItemData;
|
|
|
|
return getSwtTable().isSelected(getSwtTable().indexOf(tableItem));
|
|
}//controlIsSelected()//
|
|
/* (non-Javadoc)
|
|
* @see com.foundation.view.swt.CollectionComponent#controlGetSelectionCount()
|
|
*/
|
|
protected int controlGetSelectionCount() {
|
|
return getSwtTable().getSelectionCount();
|
|
}//controlGetSelectionCount()//
|
|
/* (non-Javadoc)
|
|
* @see com.foundation.view.swt.TableComponent#forceSelectionEvent()
|
|
*/
|
|
protected void forceSelectionEvent() {
|
|
if(!getSwtTable().isDisposed()) {
|
|
widgetSelected(null);
|
|
}//if//
|
|
}//forceSelectionEvent()//
|
|
/* (non-Javadoc)
|
|
* @see com.foundation.view.swt.CollectionComponent#getAutoSynchronizeSelectionDelay()
|
|
*/
|
|
protected long getAutoSynchronizeSelectionDelay() {
|
|
return disableAutoSynchronizeDelay ? 0 : super.getAutoSynchronizeSelectionDelay();
|
|
}//getAutoSynchronizeSelectionDelay()//
|
|
/* (non-Javadoc)
|
|
* @see com.foundation.view.swt.CollectionComponent#internalPreChangeCollection()
|
|
*/
|
|
protected void internalPreChangeCollection() {
|
|
super.internalPreChangeCollection();
|
|
suspendUpdateTableEditors(true);
|
|
suspendLayoutRenderers = true;
|
|
}//internalPreChangeCollection()//
|
|
/* (non-Javadoc)
|
|
* @see com.foundation.view.swt.CollectionComponent#internalPostChangeCollection()
|
|
*/
|
|
protected void internalPostChangeCollection() {
|
|
super.internalPostChangeCollection();
|
|
suspendUpdateTableEditors(false);
|
|
suspendLayoutRenderers = false;
|
|
//Update the editors and renderers after large scale changes to the collection.//
|
|
updateTableEditors();
|
|
layoutRenderers();
|
|
}//internalPostChangeCollection()//
|
|
/**
|
|
* Determines whether to suspend the table editor updating.
|
|
* @return Whether to suspend table editor updating.
|
|
*/
|
|
protected boolean suspendUpdateTableEditors() {
|
|
return suspendUpdateTableEditorsCount > 0;
|
|
}//suspendUpdateTableEditors()//
|
|
/**
|
|
* Suspends or un-suspends the table editor updating.
|
|
* @param suspend Whether to suspend the updating, or restart updating. There must be a call to un-suspend for each call to suspend.
|
|
*/
|
|
protected void suspendUpdateTableEditors(boolean suspend) {
|
|
if(suspend) {
|
|
suspendUpdateTableEditorsCount++;
|
|
}//if//
|
|
else {
|
|
suspendUpdateTableEditorsCount--;
|
|
}//else//
|
|
}//suspendUpdateTableEditors()//
|
|
/**
|
|
* Releases the table editors for the given item.
|
|
* @param tableItem The table item whose editors will be released.
|
|
*/
|
|
protected void releaseTableEditors(TableItem tableItem) {
|
|
int columnCount = getColumnCount();
|
|
|
|
//Release the editors for the row and each column.//
|
|
for(int columnIndex = 0; columnIndex < columnCount; columnIndex++) {
|
|
TableColumn tableColumn = getSwtTable().getColumn(columnIndex);
|
|
ColumnData columnData = (ColumnData) tableColumn.getData();
|
|
TableEditor tableEditor = columnData.removeTableEditor(tableItem);
|
|
|
|
if(tableEditor != null) {
|
|
CellComponent cellComponent = ((CellComponent.CellControl) tableEditor.getEditor().getData()).getCellComponent();
|
|
|
|
cellComponent.destroyCellControl(tableEditor.getEditor());
|
|
tableEditor.dispose();
|
|
}//if//
|
|
}//for//
|
|
}//releaseTableEditors()//
|
|
/**
|
|
* Creates the table editors for the given item.
|
|
* @param tableItem The table item whose editors will be created.
|
|
*/
|
|
protected void createTableEditors(TableItem tableItem) {
|
|
int columnCount = getColumnCount();
|
|
SimpleTableRowObject rowObject = (SimpleTableRowObject) tableItem.getData();
|
|
|
|
//Check for a null row object indicating that the update is due to a resize due to the creation of a table item which has not yet been initialized.//
|
|
if(rowObject != null) {
|
|
//Release the editors for the row and each column.//
|
|
for(int columnIndex = 0; columnIndex < columnCount; columnIndex++) {
|
|
TableColumn tableColumn = getSwtTable().getColumn(columnIndex);
|
|
ColumnData columnData = (ColumnData) tableColumn.getData();
|
|
|
|
if(columnData.hasComponentCapableRenderers()) {
|
|
CellComponent cellComponent = columnData.getCellComponent(rowObject.value != null ? rowObject.value.getClass() : null);
|
|
|
|
//If there is a cell component and it allows us to use a control for this row, then set up a new control and table editor.//
|
|
if((cellComponent != null) && (cellComponent.supportsControl()) && ((cellComponent.useControl() == CellComponent.USE_CONTROL_ALWAYS) || ((cellComponent.useControl() == CellComponent.USE_CONTROL_ON_SELECTION) && ((getSwtTable().getSelectionCount() == 1) && (getSwtTable().getItem(getSwtTable().getSelectionIndex()) == tableItem))))) {
|
|
Control control = cellComponent.createCellControl(rowObject.value);
|
|
TableEditor tableEditor = new TableEditor(getSwtTable());
|
|
Point size;
|
|
|
|
tableEditor.setEditor(control, tableItem, columnIndex);
|
|
columnData.setTableEditor(tableItem, tableEditor);
|
|
tableEditor.grabHorizontal = cellComponent.grabHorizontalSpace();
|
|
tableEditor.grabVertical = cellComponent.grabVerticalSpace();
|
|
tableEditor.horizontalAlignment = cellComponent.getHorizontalAlignment();
|
|
tableEditor.verticalAlignment = cellComponent.getVerticalAlignment();
|
|
size = tableEditor.getEditor().computeSize(SWT.DEFAULT, SWT.DEFAULT);
|
|
|
|
if(size.y > minimumTableEditorHeight) {
|
|
minimumTableEditorHeight = size.y;
|
|
}//if//
|
|
}//if//
|
|
}//if//
|
|
}//for//
|
|
}//if//
|
|
}//createTableEditors()//
|
|
/**
|
|
* Updates the table editors so that all visible rows have appropriate table editors when the table scrolls.
|
|
*/
|
|
protected void updateTableEditors() {
|
|
if(!suspendUpdateTableEditors()) {
|
|
int topIndex = getSwtTable().getTopIndex();
|
|
TableItem item = (topIndex >= 0 && topIndex < getSwtTable().getItemCount()) ? getSwtTable().getItem(topIndex) : null;
|
|
IIterator iterator;
|
|
|
|
if(item != null) {
|
|
Rectangle clientArea = getSwtTable().getClientArea();
|
|
int visibleRowCount = (int) Math.ceil(clientArea.height / (double) getSwtTable().getItemHeight());
|
|
LiteHashSet visibleTableItems = new LiteHashSet(visibleRowCount);
|
|
|
|
//Collect the visible table items.//
|
|
for(int index = topIndex + visibleRowCount < getSwtTable().getItemCount() ? topIndex + visibleRowCount : getSwtTable().getItemCount() - 1; index >= topIndex; index--) {
|
|
visibleTableItems.add(getSwtTable().getItem(index));
|
|
}//for//
|
|
|
|
if(currentlyVisibleTableItems != null) {
|
|
iterator = currentlyVisibleTableItems.iterator();
|
|
|
|
//Release the editors for items no longer visible.//
|
|
while(iterator.hasNext()) {
|
|
TableItem next = (TableItem) iterator.next();
|
|
|
|
if(!visibleTableItems.containsValue(next)) {
|
|
releaseTableEditors(next);
|
|
}//if//
|
|
}//while//
|
|
|
|
iterator = visibleTableItems.iterator();
|
|
|
|
//Setup the editors for newly visible items.//
|
|
while(iterator.hasNext()) {
|
|
TableItem next = (TableItem) iterator.next();
|
|
|
|
if(!currentlyVisibleTableItems.containsValue(next)) {
|
|
createTableEditors(next);
|
|
}//if//
|
|
}//while//
|
|
}//if//
|
|
else {
|
|
iterator = visibleTableItems.iterator();
|
|
|
|
//Setup the editors for newly visible items.//
|
|
while(iterator.hasNext()) {
|
|
TableItem next = (TableItem) iterator.next();
|
|
|
|
createTableEditors(next);
|
|
}//while//
|
|
}//else//
|
|
|
|
currentlyVisibleTableItems = visibleTableItems;
|
|
}//if//
|
|
else if(currentlyVisibleTableItems != null) {
|
|
iterator = currentlyVisibleTableItems.iterator();
|
|
|
|
//Setup the editors for newly visible items.//
|
|
while(iterator.hasNext()) {
|
|
TableItem next = (TableItem) iterator.next();
|
|
|
|
releaseTableEditors(next);
|
|
}//while//
|
|
|
|
currentlyVisibleTableItems = null;
|
|
}//else if//
|
|
}//if//
|
|
}//updateTableEditors()//
|
|
/**
|
|
* Forces the renderers to reposition themselves since SWT has a bug where by the renderers are not updated on table adds, removes, or row height resizing.
|
|
*/
|
|
protected void layoutRenderers() {
|
|
if(!suspendLayoutRenderers) {
|
|
stopRendering();
|
|
|
|
try {
|
|
for(int columnIndex = getColumnCount() - 1; columnIndex >= 0; columnIndex--) {
|
|
((ColumnData) getColumn(columnIndex)).layoutRenderers();
|
|
}//for//
|
|
}//try//
|
|
finally {
|
|
startRendering();
|
|
redraw();
|
|
}//finally//
|
|
}//if//
|
|
}//layoutRenderers()//
|
|
/* (non-Javadoc)
|
|
* @see org.eclipse.swt.events.SelectionListener#widgetDefaultSelected(org.eclipse.swt.events.SelectionEvent)
|
|
*/
|
|
public void widgetDefaultSelected(SelectionEvent event) {
|
|
if(event.widget == getSwtTable()) {
|
|
//Fix a bug in the table where a double click event is fired twice.//
|
|
if(lastDoubleClickTime != event.time) {
|
|
if(getDoubleClickMethod() != null) {
|
|
//Set the synchronize delay to zero so the synchronize occurs immediatly.//
|
|
disableAutoSynchronizeDelay = true;
|
|
|
|
try {
|
|
//Synchronize the selection.//
|
|
synchronizeSelection();
|
|
|
|
//Force any selection task to complete prior to sending the double click.//
|
|
synchronized(this) {
|
|
if(autoSynchronizeSelectionTask != null) {
|
|
autoSynchronizeSelectionTask.run();
|
|
}//if//
|
|
}//synchronized//
|
|
|
|
//Send the double click message.//
|
|
doDoubleClick();
|
|
}//try//
|
|
finally {
|
|
//Reset the delay and send the messages.//
|
|
disableAutoSynchronizeDelay = false;
|
|
}//finally//
|
|
|
|
lastDoubleClickTime = event.time;
|
|
}//if//
|
|
else {
|
|
widgetSelected(event);
|
|
}//else//
|
|
}//if//
|
|
}//if//
|
|
else if(event.widget == getSwtTable().getVerticalBar()) {
|
|
updateTableEditors();
|
|
}//else//
|
|
}//widgetDefaultSelected()//
|
|
/* (non-Javadoc)
|
|
* @see org.eclipse.swt.events.SelectionListener#widgetSelected(org.eclipse.swt.events.SelectionEvent)
|
|
*/
|
|
public void widgetSelected(SelectionEvent event) {
|
|
if(!suspendSelectionEvents && ((event == null) || (event.widget == getSwtTable()))) {
|
|
synchronizeSelection();
|
|
}//if//
|
|
else if(event.widget == getSwtTable().getVerticalBar()) {
|
|
updateTableEditors();
|
|
}//else//
|
|
}//widgetSelected()//
|
|
/* (non-Javadoc)
|
|
* @see org.eclipse.swt.events.ControlListener#controlMoved(org.eclipse.swt.events.ControlEvent)
|
|
*/
|
|
public void controlMoved(ControlEvent event) {
|
|
//Ignore this.//
|
|
}//controlMoved()//
|
|
/* (non-Javadoc)
|
|
* @see org.eclipse.swt.events.ControlListener#controlResized(org.eclipse.swt.events.ControlEvent)
|
|
*/
|
|
public void controlResized(ControlEvent event) {
|
|
if(!suspendResizeEvents) {
|
|
int controlWidth = getSwtTable().getClientArea().width;
|
|
|
|
if(controlWidth != lastControlWidth) {
|
|
lastControlWidth = controlWidth;
|
|
|
|
if(getAutoFit()) {
|
|
fit();
|
|
}//if//
|
|
else if(getFillOnResize()) {
|
|
fill();
|
|
}//else if//
|
|
}//if//
|
|
|
|
updateTableEditors();
|
|
}//if//
|
|
}//controlResized()//
|
|
}//SimpleTable// |