| /******************************************************************************* |
| * 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); |
| } |
| |
| |
| |
| } |
| |