blob: 3b955959e0c07b4739a6c96c067111eaa7dcb1be [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2005 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.jface.viewers;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import org.eclipse.jface.util.Assert;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.TableEditor;
import org.eclipse.swt.events.MouseAdapter;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Item;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.swt.widgets.Widget;
/**
* A concrete viewer based on a SWT <code>Table</code> control.
* <p>
* This class is not intended to be subclassed outside the viewer framework. It
* is designed to be instantiated with a pre-existing SWT table control and
* configured with a domain-specific content provider, table label provider,
* element filter (optional), and element sorter (optional).
* </p>
* <p>
* Label providers for table viewers must implement either the
* <code>ITableLabelProvider</code> or the <code>ILabelProvider</code>
* interface (see <code>TableViewer.setLabelProvider</code> for more details).
* </p>
* <p>
* As of 3.1 the TableViewer now supports the SWT.VIRTUAL
* flag. It is important to note that if SWT.VIRTUAL is in use
* that the Widget based APIs will return null in both the
* cases where either the element is not specified or not
* created yet.
* </p>
* <p>
* Users of SWT.VIRTUAL should also avoid using getItems()
* from the Table within the TreeViewer as this does not
* necessarily generate a callback for the TreeViewer
* to populate the items. It also has the side effect of
* creating all of the items thereby eliminating the
* performance improvements of SWT.VIRTUAL.
* </p>
* @see SWT#VIRTUAL
* @see #doFindItem(Object)
* @see #internalRefresh(Object, boolean)
*/
public class TableViewer extends StructuredViewer {
private class VirtualManager{
/**
* The currently invisible elements as provided
* by the content provider or by addition.
* This will not be populated by an ILazyStructuredContentProvider
* as an ILazyStructuredContentProvider is only queried
* on the virtual callabck.
*/
private Object[] cachedElements = new Object[0];
/**
* Create a new instance of the receiver.
*
*/
public VirtualManager(){
addTableListener();
}
/**
* Add the listener for SetData on the table
*/
private void addTableListener() {
table.addListener(SWT.SetData,new Listener(){
/* (non-Javadoc)
* @see org.eclipse.swt.widgets.Listener#handleEvent(org.eclipse.swt.widgets.Event)
*/
public void handleEvent(Event event) {
TableItem item = (TableItem) event.item;
final int index = table.indexOf(item);
Object element = resolveElement(index);
if(element == null){
//Didn't find it so make a request
//Keep looking if it is not in the cache.
IContentProvider contentProvider = getContentProvider();
//If we are building lazily then request lookup now
if(contentProvider instanceof ILazyContentProvider){
((ILazyContentProvider) contentProvider).
updateElement(index);
return;
}
}
associate(element,item);
updateItem(item,element);
}
});
}
/**
* Get the element at index.Resolve it lazily if this
* is available.
* @param index
* @return Object or <code>null</code> if it could
* not be found
*/
protected Object resolveElement(int index) {
Object element = null;
if(index < cachedElements.length)
element = cachedElements[index];
return element;
}
/**
* A non visible item has been added.
* @param element
* @param index
*/
public void notVisibleAdded(Object element, int index) {
int requiredCount = index + 1;
if(requiredCount > getTable().getItemCount()){
getTable().setItemCount(requiredCount);
Object[] newCache = new Object[requiredCount];
System.arraycopy(cachedElements, 0, newCache, 0, cachedElements.length);
cachedElements = newCache;
}
cachedElements[index] = element;
}
}
private VirtualManager virtualManager;
/**
* TableColorAndFontNoOp is an optimization for tables without
* color and font support.
* @see ITableColorProvider
* @see ITableFontProvider
*/
private class TableColorAndFontNoOp{
/**
* Create a new instance of the receiver.
*
*/
TableColorAndFontNoOp(){
}
/**
* Set the fonts and colors for the tableItem if there is a color
* and font provider available.
* @param tableItem The item to update.
* @param element The element being represented
* @param column The column index
*/
public void setFontsAndColors(TableItem tableItem, Object element, int column){
}
}
/**
* TableColorAndFontCollector is an helper class for color and font
* support for tables that support the ITableFontProvider and
* the ITableColorProvider.
* @see ITableColorProvider
* @see ITableFontProvider
*/
private class TableColorAndFontCollector extends TableColorAndFontNoOp{
ITableFontProvider fontProvider = null;
ITableColorProvider colorProvider = null;
/**
* Create an instance of the receiver. Set the color and font
* providers if provider can be cast to the correct type.
* @param provider IBaseLabelProvider
*/
public TableColorAndFontCollector(IBaseLabelProvider provider){
if(provider instanceof ITableFontProvider)
fontProvider = (ITableFontProvider) provider;
if(provider instanceof ITableColorProvider)
colorProvider = (ITableColorProvider) provider;
}
/**
* Set the fonts and colors for the tableItem if there is a color
* and font provider available.
* @param tableItem The item to update.
* @param element The element being represented
* @param column The column index
*/
public void setFontsAndColors(TableItem tableItem, Object element, int column){
if (colorProvider != null) {
tableItem.setBackground(column, colorProvider.getBackground(element,
column));
tableItem.setForeground(column, colorProvider.getForeground(element,
column));
}
if(fontProvider != null)
tableItem.setFont(column,fontProvider.getFont(element,column));
}
}
/**
* Internal table viewer implementation.
*/
private TableEditorImpl tableViewerImpl;
/**
* This viewer's table control.
*/
private Table table;
/**
* This viewer's table editor.
*/
private TableEditor tableEditor;
/**
* The color and font collector for the cells.
*/
private TableColorAndFontNoOp tableColorAndFont = new TableColorAndFontNoOp();
/**
* Creates a table viewer on a newly-created table control under the given
* parent. The table control is created using the SWT style bits
* <code>MULTI, H_SCROLL, V_SCROLL,</code> and <code>BORDER</code>. The
* viewer has no input, no content provider, a default label provider, no
* sorter, and no filters. The table has no columns.
*
* @param parent
* the parent control
*/
public TableViewer(Composite parent) {
this(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER);
}
/**
* Creates a table viewer on a newly-created table control under the given
* parent. The table control is created using the given style bits. The
* viewer has no input, no content provider, a default label provider, no
* sorter, and no filters. The table has no columns.
*
* @param parent
* the parent control
* @param style
* SWT style bits
*/
public TableViewer(Composite parent, int style) {
this(new Table(parent, style));
}
/**
* Creates a table viewer on the given table control. The viewer has no
* input, no content provider, a default label provider, no sorter, and no
* filters.
*
* @param table
* the table control
*/
public TableViewer(Table table) {
this.table = table;
hookControl(table);
tableEditor = new TableEditor(table);
initTableViewerImpl();
initializeVirtualManager(table.getStyle());
}
/**
* Initialize the virtual manager to manage the virtual state
* if the table is VIRTUAL. If not use the default no-op
* version.
* @param style
*/
private void initializeVirtualManager(int style) {
if((style & SWT.VIRTUAL) == 0)
return;
virtualManager = new VirtualManager();
}
/**
* Adds the given elements to this table viewer. If this viewer does not
* have a sorter, the elements are added at the end in the order given;
* otherwise the elements are inserted at appropriate positions.
* <p>
* This method should be called (by the content provider) when elements have
* been added to the model, in order to cause the viewer to accurately
* reflect the model. This method only affects the viewer, not the model.
* </p>
*
* @param elements
* the elements to add
*/
public void add(Object[] elements) {
assertElementsNotNull(elements);
Object[] filtered = filter(elements);
for (int i = 0; i < filtered.length; i++) {
Object element = filtered[i];
int index = indexForElement(element);
createItem(element, index);
}
}
/**
* Create a new TableItem at index if required.
* @param element
* @param index
*
* @since 3.1
*/
private void createItem(Object element, int index) {
if(virtualManager == null)
updateItem(new TableItem(getTable(), SWT.NONE, index), element);
else{
virtualManager.notVisibleAdded(element,index);
}
}
/**
* Adds the given element to this table viewer. If this viewer does not have
* a sorter, the element is added at the end; otherwise the element is
* inserted at the appropriate position.
* <p>
* This method should be called (by the content provider) when a single
* element has been added to the model, in order to cause the viewer to
* accurately reflect the model. This method only affects the viewer, not
* the model. Note that there is another method for efficiently processing
* the simultaneous addition of multiple elements.
* </p>
*
* @param element
* the element to add
*/
public void add(Object element) {
add(new Object[] { element });
}
/**
* Cancels a currently active cell editor. All changes already done in the
* cell editor are lost.
*/
public void cancelEditing() {
tableViewerImpl.cancelEditing();
}
/*
* (non-Javadoc)
* @see org.eclipse.jface.viewers.StructuredViewer#doFindInputItem(java.lang.Object)
*/
protected Widget doFindInputItem(Object element) {
if (equals(element, getRoot()))
return getTable();
return null;
}
/*
* (non-Javadoc)
* @see org.eclipse.jface.viewers.StructuredViewer#doFindItem(java.lang.Object)
*/
protected Widget doFindItem(Object element) {
TableItem[] children = table.getItems();
for (int i = 0; i < children.length; i++) {
TableItem item = children[i];
Object data = item.getData();
if (data != null && equals(data, element))
return item;
}
return null;
}
/*
* (non-Javadoc)
* @see org.eclipse.jface.viewers.StructuredViewer#doUpdateItem(org.eclipse.swt.widgets.Widget, java.lang.Object, boolean)
*/
protected void doUpdateItem(Widget widget, Object element, boolean fullMap) {
if (widget instanceof TableItem) {
final TableItem item = (TableItem) widget;
// remember element we are showing
if (fullMap) {
associate(element, item);
} else {
Object data = item.getData();
if (data != null) {
unmapElement(data, item);
}
item.setData(element);
mapElement(element, item);
}
IBaseLabelProvider prov = getLabelProvider();
ITableLabelProvider tprov = null;
ILabelProvider lprov = null;
IViewerLabelProvider vprov = null;
if(prov instanceof ILabelProvider)
lprov = (ILabelProvider) prov;
if (prov instanceof IViewerLabelProvider) {
vprov = (IViewerLabelProvider) prov;
}
if (prov instanceof ITableLabelProvider) {
tprov = (ITableLabelProvider) prov;
}
int columnCount = table.getColumnCount();
TableItem ti = item;
getColorAndFontCollector().setFontsAndColors(element);
// Also enter loop if no columns added. See 1G9WWGZ: JFUIF:WINNT -
// TableViewer with 0 columns does not work
for (int column = 0; column < columnCount || column == 0; column++) {
// Similar code in TreeViewer.doUpdateItem()
String text = "";//$NON-NLS-1$
Image image = null;
tableColorAndFont.setFontsAndColors(ti,element,column);
if (tprov == null) {
if (column == 0) {
ViewerLabel updateLabel = new ViewerLabel(item
.getText(), item.getImage());
if(vprov != null)
buildLabel(updateLabel,element,vprov);
else{
if(lprov != null)
buildLabel(updateLabel,element,lprov);
}
// As it is possible for user code to run the event
//loop check here.
if (item.isDisposed()) {
unmapElement(element, item);
return;
}
text = updateLabel.getText();
image = updateLabel.getImage();
}
} else {
text = tprov.getColumnText(element, column);
image = tprov.getColumnImage(element, column);
}
//Avoid setting text to null
if (text == null)
text = ""; //$NON-NLS-1$
ti.setText(column, text);
if (ti.getImage(column) != image) {
ti.setImage(column, image);
}
}
getColorAndFontCollector().applyFontsAndColors(ti);
}
}
/**
* Starts editing the given element.
*
* @param element
* the element
* @param column
* the column number
*/
public void editElement(Object element, int column) {
tableViewerImpl.editElement(element, column);
}
/**
* Returns the cell editors of this table viewer.
*
* @return the list of cell editors
*/
public CellEditor[] getCellEditors() {
return tableViewerImpl.getCellEditors();
}
/**
* Returns the cell modifier of this table viewer.
*
* @return the cell modifier
*/
public ICellModifier getCellModifier() {
return tableViewerImpl.getCellModifier();
}
/**
* Returns the column properties of this table viewer. The properties must
* correspond with the columns of the table control. They are used to
* identify the column in a cell modifier.
*
* @return the list of column properties
*/
public Object[] getColumnProperties() {
return tableViewerImpl.getColumnProperties();
}
/*
* (non-Javadoc)
* @see org.eclipse.jface.viewers.Viewer#getControl()
*/
public Control getControl() {
return table;
}
/**
* Returns the element with the given index from this table viewer. Returns
* <code>null</code> if the index is out of range.
* <p>
* This method is internal to the framework.
* </p>
*
* @param index
* the zero-based index
* @return the element at the given index, or <code>null</code> if the
* index is out of range
*/
public Object getElementAt(int index) {
if (index >= 0 && index < table.getItemCount()) {
TableItem i = table.getItem(index);
if (i != null)
return i.getData();
}
return null;
}
/**
* The table viewer implementation of this <code>Viewer</code> framework
* method returns the label provider, which in the case of table viewers
* will be an instance of either <code>ITableLabelProvider</code> or
* <code>ILabelProvider</code>. If it is an
* <code>ITableLabelProvider</code>, then it provides a separate label
* text and image for each column. If it is an <code>ILabelProvider</code>,
* then it provides only the label text and image for the first column, and
* any remaining columns are blank.
*/
public IBaseLabelProvider getLabelProvider() {
return super.getLabelProvider();
}
/*
* (non-Javadoc)
* @see org.eclipse.jface.viewers.StructuredViewer#getSelectionFromWidget()
*/
protected List getSelectionFromWidget() {
if(virtualManager != null)
return getVirtualSelection();
Widget[] items = table.getSelection();
ArrayList list = new ArrayList(items.length);
for (int i = 0; i < items.length; i++) {
Widget item = items[i];
Object e = item.getData();
if (e != null)
list.add(e);
}
return list;
}
/**
* Get the virtual selection. Avoid calling SWT whenever possible
* to prevent extra widget creation.
* @return List of Object
*/
private List getVirtualSelection() {
List result = new ArrayList();
int[] selectionIndices = getTable().getSelectionIndices();
if(getContentProvider() instanceof ILazyContentProvider){
ILazyContentProvider lazy = (ILazyContentProvider) getContentProvider();
for (int i = 0; i < selectionIndices.length; i++) {
int selectionIndex = selectionIndices[i];
lazy.updateElement(selectionIndex);//Start the update
Object element = getTable().getItem(selectionIndex).getData();
//Only add the element if it got updated.
//If this is done deferred the selection will
//be incomplete until selection is finished.
if (element != null)
result.add(element);
}
}
else{
for (int i = 0; i < selectionIndices.length; i++) {
Object element = null;
//See if it is cached
int selectionIndex = selectionIndices[i];
if (selectionIndex < virtualManager.cachedElements.length){
element = virtualManager.cachedElements[selectionIndex];
}
if (element == null){
// Not cached so try the item's data
TableItem item = getTable().getItem(selectionIndex);
element = item.getData();
}
if (element != null)
result.add(element);
}
}
return result;
}
/**
* Returns this table viewer's table control.
*
* @return the table control
*/
public Table getTable() {
return table;
}
/*
* (non-Javadoc)
* @see org.eclipse.jface.viewers.ContentViewer#hookControl(org.eclipse.swt.widgets.Control)
*/
protected void hookControl(Control control) {
super.hookControl(control);
Table tableControl = (Table) control;
tableControl.addMouseListener(new MouseAdapter() {
public void mouseDown(MouseEvent e) {
tableViewerImpl.handleMouseDown(e);
}
});
}
/*
* Returns the index where the item should be inserted.
*/
protected int indexForElement(Object element) {
ViewerSorter sorter = getSorter();
if (sorter == null)
return table.getItemCount();
int count = table.getItemCount();
int min = 0, max = count - 1;
while (min <= max) {
int mid = (min + max) / 2;
Object data = table.getItem(mid).getData();
int compare = sorter.compare(this, data, element);
if (compare == 0) {
// find first item > element
while (compare == 0) {
++mid;
if (mid >= count) {
break;
}
data = table.getItem(mid).getData();
compare = sorter.compare(this, data, element);
}
return mid;
}
if (compare < 0)
min = mid + 1;
else
max = mid - 1;
}
return min;
}
/**
* Initializes the table viewer implementation.
*/
private void initTableViewerImpl() {
tableViewerImpl = new TableEditorImpl(this) {
Rectangle getBounds(Item item, int columnNumber) {
return ((TableItem) item).getBounds(columnNumber);
}
int getColumnCount() {
return getTable().getColumnCount();
}
Item[] getSelection() {
return getTable().getSelection();
}
void setEditor(Control w, Item item, int columnNumber) {
tableEditor.setEditor(w, (TableItem) item, columnNumber);
}
void setSelection(StructuredSelection selection, boolean b) {
TableViewer.this.setSelection(selection, b);
}
void showSelection() {
getTable().showSelection();
}
void setLayoutData(CellEditor.LayoutData layoutData) {
tableEditor.grabHorizontal = layoutData.grabHorizontal;
tableEditor.horizontalAlignment = layoutData.horizontalAlignment;
tableEditor.minimumWidth = layoutData.minimumWidth;
}
void handleDoubleClickEvent() {
Viewer viewer = getViewer();
fireDoubleClick(new DoubleClickEvent(viewer, viewer
.getSelection()));
fireOpen(new OpenEvent(viewer, viewer.getSelection()));
}
};
}
/*
* (non-Javadoc)
* @see org.eclipse.jface.viewers.Viewer#inputChanged(java.lang.Object, java.lang.Object)
*/
protected void inputChanged(Object input, Object oldInput) {
getControl().setRedraw(false);
try {
// refresh() attempts to preserve selection, which we want here
refresh();
} finally {
getControl().setRedraw(true);
}
}
/**
* Inserts the given element into this table viewer at the given position.
* If this viewer has a sorter, the position is ignored and the element is
* inserted at the correct position in the sort order.
* <p>
* This method should be called (by the content provider) when elements have
* been added to the model, in order to cause the viewer to accurately
* reflect the model. This method only affects the viewer, not the model.
* </p>
*
* @param element
* the element
* @param position
* a 0-based position relative to the model, or -1 to indicate
* the last position
*/
public void insert(Object element, int position) {
tableViewerImpl.applyEditorValue();
if (getSorter() != null || hasFilters()) {
add(element);
return;
}
if (position == -1)
position = table.getItemCount();
createItem(element,position);
}
/*
* (non-Javadoc)
* @see org.eclipse.jface.viewers.StructuredViewer#internalRefresh(java.lang.Object)
*/
protected void internalRefresh(Object element) {
internalRefresh(element, true);
}
/*
* (non-Javadoc)
* @see org.eclipse.jface.viewers.StructuredViewer#internalRefresh(java.lang.Object, boolean)
*/
protected void internalRefresh(Object element, boolean updateLabels) {
tableViewerImpl.applyEditorValue();
if (element == null || equals(element, getRoot())) {
if(virtualManager == null)
internalRefreshAll(updateLabels);
else{
internalVirtualRefreshAll();
}
} else {
Widget w = findItem(element);
if (w != null) {
updateItem(w, element);
}
}
}
/**
* Refresh all with virtual elements.
*
* @since 3.1
*/
private void internalVirtualRefreshAll() {
Object root = getRoot();
IContentProvider contentProvider = getContentProvider();
//Invalidate for lazy
if(!(contentProvider instanceof ILazyContentProvider)
&& (contentProvider instanceof IStructuredContentProvider)) {
//Don't cache if the root is null but cache if it is not lazy.
if(root != null){
virtualManager.cachedElements =
((IStructuredContentProvider) getContentProvider()).getElements(root);
getTable().setItemCount(virtualManager.cachedElements.length);
}
}
getTable().clearAll();
}
/**
* Refresh all of the elements of the table. update the
* labels if updatLabels is true;
* @param updateLabels
*
* @since 3.1
*/
private void internalRefreshAll(boolean updateLabels) {
// the parent
// in the code below, it is important to do all disassociates
// before any associates, since a later disassociate can undo an
// earlier associate
// e.g. if (a, b) is replaced by (b, a), the disassociate of b to
// item 1 could undo
// the associate of b to item 0.
Object[] children = getSortedChildren(getRoot());
TableItem[] items = getTable().getItems();
int min = Math.min(children.length, items.length);
for (int i = 0; i < min; ++i) {
TableItem item = items[i];
// if the element is unchanged, update its label if appropriate
if (equals(children[i], item.getData())) {
if (updateLabels) {
updateItem(item, children[i]);
} else {
// associate the new element, even if equal to the old
// one,
// to remove stale references (see bug 31314)
associate(children[i], item);
}
} else {
// updateItem does an associate(...), which can mess up
// the associations if the order of elements has changed.
// E.g. (a, b) -> (b, a) first replaces a->0 with b->0, then
// replaces b->1 with a->1, but this actually removes b->0.
// So, if the object associated with this item has changed,
// just disassociate it for now, and update it below.
item.setText(""); //$NON-NLS-1$
item.setImage(new Image[Math.max(1,table.getColumnCount())]);//Clear all images
disassociate(item);
}
}
// dispose of all items beyond the end of the current elements
if (min < items.length) {
for (int i = items.length; --i >= min;) {
disassociate(items[i]);
}
table.remove(min, items.length - 1);
}
// Workaround for 1GDGN4Q: ITPUI:WIN2000 - TableViewer icons get
// scrunched
if (table.getItemCount() == 0) {
table.removeAll();
}
// Update items which were removed above
for (int i = 0; i < min; ++i) {
TableItem item = items[i];
if (item.getData() == null)
updateItem(item, children[i]);
}
// add any remaining elements
for (int i = min; i < children.length; ++i) {
createItem(children[i],i);
}
}
/**
* Removes the given elements from this table viewer.
*
* @param elements
* the elements to remove
*/
private void internalRemove(final Object[] elements) {
Object input = getInput();
for (int i = 0; i < elements.length; ++i) {
if (equals(elements[i], input)) {
setInput(null);
return;
}
}
// use remove(int[]) rather than repeated TableItem.dispose() calls
// to allow SWT to optimize multiple removals
int[] indices = new int[elements.length];
int count = 0;
for (int i = 0; i < elements.length; ++i) {
Widget w = findItem(elements[i]);
if (w instanceof TableItem) {
TableItem item = (TableItem) w;
disassociate(item);
indices[count++] = table.indexOf(item);
}
}
if (count < indices.length) {
System.arraycopy(indices, 0, indices = new int[count], 0, count);
}
table.remove(indices);
// Workaround for 1GDGN4Q: ITPUI:WIN2000 - TableViewer icons get
// scrunched
if (table.getItemCount() == 0) {
table.removeAll();
}
}
/**
* Returns whether there is an active cell editor.
*
* @return <code>true</code> if there is an active cell editor, and
* <code>false</code> otherwise
*/
public boolean isCellEditorActive() {
return tableViewerImpl.isCellEditorActive();
}
/**
* Removes the given elements from this table viewer. The selection is
* updated if required.
* <p>
* This method should be called (by the content provider) when elements have
* been removed from the model, in order to cause the viewer to accurately
* reflect the model. This method only affects the viewer, not the model.
* </p>
*
* @param elements
* the elements to remove
*/
public void remove(final Object[] elements) {
assertElementsNotNull(elements);
if (elements.length == 0) {
return;
}
preservingSelection(new Runnable() {
public void run() {
internalRemove(elements);
}
});
}
/**
* Removes the given element from this table viewer. The selection is
* updated if necessary.
* <p>
* This method should be called (by the content provider) when a single
* element has been removed from the model, in order to cause the viewer to
* accurately reflect the model. This method only affects the viewer, not
* the model. Note that there is another method for efficiently processing
* the simultaneous removal of multiple elements.
* </p>
* <strong>NOTE:</strong> removing an object from a virtual
* table will decrement the itemCount.
*
* @param element
* the element
*/
public void remove(Object element) {
remove(new Object[] { element });
}
/*
* (non-Javadoc)
* @see org.eclipse.jface.viewers.StructuredViewer#reveal(java.lang.Object)
*/
public void reveal(Object element) {
Assert.isNotNull(element);
Widget w = findItem(element);
if (w instanceof TableItem)
getTable().showItem((TableItem) w);
}
/**
* Sets the cell editors of this table viewer.
*
* @param editors
* the list of cell editors
*/
public void setCellEditors(CellEditor[] editors) {
tableViewerImpl.setCellEditors(editors);
}
/**
* Sets the cell modifier of this table viewer.
*
* @param modifier
* the cell modifier
*/
public void setCellModifier(ICellModifier modifier) {
tableViewerImpl.setCellModifier(modifier);
}
/**
* Sets the column properties of this table viewer. The properties must
* correspond with the columns of the table control. They are used to
* identify the column in a cell modifier.
*
* @param columnProperties
* the list of column properties
*/
public void setColumnProperties(String[] columnProperties) {
tableViewerImpl.setColumnProperties(columnProperties);
}
/**
* The table viewer implementation of this <code>Viewer</code> framework
* method ensures that the given label provider is an instance of either
* <code>ITableLabelProvider</code> or <code>ILabelProvider</code>. If
* it is an <code>ITableLabelProvider</code>, then it provides a separate
* label text and image for each column. If it is an
* <code>ILabelProvider</code>, then it provides only the label text and
* image for the first column, and any remaining columns are blank.
*/
public void setLabelProvider(IBaseLabelProvider labelProvider) {
Assert.isTrue(labelProvider instanceof ITableLabelProvider
|| labelProvider instanceof ILabelProvider);
super.setLabelProvider(labelProvider);
if(labelProvider instanceof ITableFontProvider || labelProvider instanceof ITableColorProvider)
tableColorAndFont = new TableColorAndFontCollector(labelProvider);
else
tableColorAndFont = new TableColorAndFontNoOp();
}
/**
* <p>
* Sets a new selection for this viewer and optionally makes it visible.
* The TableViewer implmentation of this method is ineffecient for the
* ILazyContentProvider as lookup is done by indices rather than elements
* and may require population of the entire table in worse case.
* </p>
* <p>
* Use Table#setSelection(int[] indices) and Table#showSelection() if
* you wish to set selection more effeciently when using a ILazyContentProvider.
* </p>
*
* @param selection the new selection
* @param reveal <code>true</code> if the selection is to be made
* visible, and <code>false</code> otherwise
* @see Table#setSelection(int[])
* @see Table#showSelection()
*/
public void setSelection(ISelection selection, boolean reveal) {
super.setSelection(selection, reveal);
}
/*
* (non-Javadoc)
* @see org.eclipse.jface.viewers.StructuredViewer#setSelectionToWidget(java.util.List, boolean)
*/
protected void setSelectionToWidget(List list, boolean reveal) {
if (list == null) {
table.deselectAll();
return;
}
if(virtualManager != null){
virtualSetSelectionToWidget(list, reveal);
return;
}
int size = list.size();
TableItem[] items = new TableItem[size];
int count = 0;
for (int i = 0; i < size; ++i) {
Object o = list.get(i);
Widget w = findItem(o);
if (w instanceof TableItem) {
TableItem item = (TableItem) w;
items[count++] = item;
}
}
if (count < size) {
System.arraycopy(items, 0, items = new TableItem[count], 0, count);
}
table.setSelection(items);
if (reveal) {
table.showSelection();
}
}
/**
* Set the selection on a virtual table
* @param list The elements to set
* @param reveal Whether or not reveal the first item.
*/
private void virtualSetSelectionToWidget(List list, boolean reveal) {
int size = list.size();
int[] indices = new int[list.size()];
TableItem firstItem = null;
int count = 0;
HashSet virtualElements = new HashSet();
for (int i = 0; i < size; ++i) {
Object o = list.get(i);
Widget w = findItem(o);
if (w instanceof TableItem) {
TableItem item = (TableItem) w;
indices[count++] = getTable().indexOf(item);
if (firstItem == null)
firstItem = item;
}
else
virtualElements.add(o);
}
if(getContentProvider() instanceof ILazyContentProvider){
ILazyContentProvider provider =
(ILazyContentProvider) getContentProvider();
//Now go through it again until all is done or we are no longer virtual
//This may create all items so it is not a good
//idea in general.
//Use #setSelection (int [] indices,boolean reveal) instead
for (int i = 0; virtualElements.size() > 0 && i < getTable().getItemCount(); i++) {
provider.updateElement(i);
TableItem item = getTable().getItem(i);
if(virtualElements.contains(item.getData())){
indices[count++] = i;
virtualElements.remove(item.getData());
if (firstItem == null)
firstItem = item;
}
}
}
else{
if(count != list.size()){//As this is expensive skip it if all have been found
//If it is not lazy we can use the cache
for (int i = 0; i < virtualManager.cachedElements.length; i++) {
Object element = virtualManager.cachedElements[i];
if(virtualElements.contains(element)){
TableItem item = getTable().getItem(i);
item.getText();//Be sure to fire the update
indices[count++] = i;
virtualElements.remove(element);
if (firstItem == null)
firstItem = item;
}
}
}
}
if (count < size) {
System.arraycopy(indices, 0, indices = new int[count], 0, count);
}
table.setSelection(indices);
if (reveal && firstItem != null) {
table.showItem(firstItem);
}
}
/**
* Set the item count of the receiver.
* @param count the new table size.
*
* @since 3.1
*/
public void setItemCount(int count){
getTable().setItemCount(count);
getTable().redraw();
}
/**
* Replace the entries starting at index with elements.
* This method assumes all of these values are correct
* and will not call the content provider to verify.
* <strong>Note that this method will create a TableItem
* for all of the elements provided</strong>.
* @param element
* @param index
* @see ILazyContentProvider
*
* @since 3.1
*/
public void replace(Object element, int index){
TableItem item = getTable().getItem(index);
refreshItem(item, element);
}
/**
* Clear the table item at the specified index
* @param index the index of the table item to be cleared
*
* @since 3.1
*/
public void clear(int index) {
TableItem item = getTable().getItem(index);
if (item.getData() != null) {
disassociate(item);
}
table.clear(index);
}
/* (non-Javadoc)
* @see org.eclipse.jface.viewers.StructuredViewer#getRawChildren(java.lang.Object)
*/
protected Object[] getRawChildren(Object parent) {
Assert.isTrue(!(getContentProvider() instanceof ILazyContentProvider),"Cannot get raw children with an ILazyContentProvider");//$NON-NLS-1$
return super.getRawChildren(parent);
}
/* (non-Javadoc)
* @see org.eclipse.jface.viewers.StructuredViewer#assertContentProviderType(org.eclipse.jface.viewers.IContentProvider)
*/
protected void assertContentProviderType(IContentProvider provider) {
Assert.isTrue(provider instanceof IStructuredContentProvider ||
provider instanceof ILazyContentProvider);
}
}