blob: a07c59c3e12ebeb3fb3482cc2b71e0db759f381e [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2005, 2006 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.debug.internal.ui.viewers;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.util.Assert;
import org.eclipse.jface.viewers.CellEditor;
import org.eclipse.jface.viewers.DoubleClickEvent;
import org.eclipse.jface.viewers.ICellModifier;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.OpenEvent;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerSorter;
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.Color;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.FontData;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.RGB;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
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;
import org.eclipse.ui.progress.WorkbenchJob;
/**
* @since 3.2
*/
public class AsynchronousTableViewer extends AsynchronousViewer implements Listener {
private Table fTable;
private TableEditor fTableEditor;
private TableEditorImpl fTableEditorImpl;
public AsynchronousTableViewer(Composite parent) {
this(parent, SWT.VIRTUAL);
}
public AsynchronousTableViewer(Composite parent, int style) {
this(new Table(parent, style));
}
/**
* Table must be SWT.VIRTUAL. This is intentional. Labels will never be
* retrieved for non-visible items.
*
* @see SWT.VIRTUAL
* @param table
*/
public AsynchronousTableViewer(Table table) {
Assert.isTrue((table.getStyle() & SWT.VIRTUAL) != 0);
fTable = table;
hookControl(fTable);
fTableEditor = new TableEditor(fTable);
fTableEditorImpl = createTableEditorImpl();
}
protected void hookControl(Control control) {
super.hookControl(control);
control.addMouseListener(new MouseAdapter() {
public void mouseDown(MouseEvent e) {
fTableEditorImpl.handleMouseDown(e);
}
});
}
public synchronized void dispose() {
fTable.dispose();
fTableEditor.dispose();
super.dispose();
}
protected ISelection doAttemptSelectionToWidget(ISelection selection, boolean reveal) {
if (acceptsSelection(selection)) {
List list = ((IStructuredSelection) selection).toList();
if (list == null) {
fTable.deselectAll();
return StructuredSelection.EMPTY;
}
int[] indices = new int[list.size()];
ModelNode[] nodes = getModel().getRootNode().getChildrenNodes();
if (nodes != null) {
int index = 0;
// I'm not sure if it would be faster to check TableItems first...
for (int i = 0; i < nodes.length; i++) {
Object element = nodes[i].getElement();
if (list.contains(element)) {
indices[index] = i;
index++;
}
}
fTable.setSelection(indices);
if (reveal && indices.length > 0) {
TableItem item = fTable.getItem(indices[0]);
fTable.showItem(item);
}
}
}
return StructuredSelection.EMPTY;
}
protected boolean acceptsSelection(ISelection selection) {
return selection instanceof IStructuredSelection;
}
protected ISelection getEmptySelection() {
return StructuredSelection.EMPTY;
}
protected Widget getParent(Widget widget) {
if (widget instanceof TableItem) {
return fTable;
}
return null;
}
protected List getSelectionFromWidget() {
TableItem[] selection = fTable.getSelection();
List datas = new ArrayList(selection.length);
for (int i = 0; i < selection.length; i++) {
datas.add(selection[i].getData());
}
return datas;
}
public Control getControl() {
return fTable;
}
public Table getTable() {
return (Table) getControl();
}
/* (non-Javadoc)
* @see org.eclipse.debug.internal.ui.model.viewers.AsynchronousViewer#internalRefresh(org.eclipse.debug.internal.ui.model.viewers.ModelNode)
*/
protected void internalRefresh(ModelNode node) {
super.internalRefresh(node);
if (node.getElement().equals(getInput())) {
updateChildren(node);
}
}
protected void restoreLabels(Item item) {
TableItem tableItem = (TableItem) item;
String[] values = (String[]) tableItem.getData(OLD_LABEL);
Image[] images = (Image[]) tableItem.getData(OLD_IMAGE);
if (values != null) {
tableItem.setText(values);
tableItem.setImage(images);
}
}
public void setLabels(Widget widget, String[] labels, ImageDescriptor[] imageDescriptors) {
TableItem item = (TableItem) widget;
item.setText(labels);
item.setData(OLD_LABEL, labels);
Image[] images = new Image[labels.length];
item.setData(OLD_IMAGE, images);
if (imageDescriptors != null) {
for (int i = 0; i < images.length; i++) {
if (i < imageDescriptors.length)
images[i] = getImage(imageDescriptors[i]);
}
}
item.setImage(images);
}
public void setColors(Widget widget, RGB[] foregrounds, RGB[] backgrounds) {
TableItem item = (TableItem) widget;
if (foregrounds == null) {
foregrounds = new RGB[fTable.getColumnCount()];
}
if (backgrounds == null) {
backgrounds = new RGB[fTable.getColumnCount()];
}
for (int i = 0; i < foregrounds.length; i++) {
Color fg = getColor(foregrounds[i]);
item.setForeground(i, fg);
}
for (int i = 0; i < backgrounds.length; i++) {
Color bg = getColor(backgrounds[i]);
item.setBackground(i, bg);
}
}
public void setFonts(Widget widget, FontData[] fontDatas) {
TableItem item = (TableItem) widget;
if (fontDatas != null) {
for (int i = 0; i < fontDatas.length; i++) {
Font font = getFont(fontDatas[i]);
item.setFont(i, font);
}
}
}
public void setColumnHeaders(final String[] headers) {
fTableEditorImpl.setColumnProperties(headers);
}
public Object[] getColumnProperties() {
return fTableEditorImpl.getColumnProperties();
}
public void showColumnHeader(final boolean showHeaders) {
WorkbenchJob job = new WorkbenchJob("Set Header Visibility") { //$NON-NLS-1$
public IStatus runInUIThread(IProgressMonitor monitor) {
if (!fTable.isDisposed())
{
fTable.setHeaderVisible(showHeaders);
}
return Status.OK_STATUS;
}
};
job.setPriority(Job.INTERACTIVE);
job.setSystem(true);
job.schedule();
}
/*
* (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) {
fTableEditorImpl.setCellEditors(editors);
}
/**
* Sets the cell modifier of this table viewer.
*
* @param modifier
* the cell modifier
*/
public void setCellModifier(ICellModifier modifier) {
fTableEditorImpl.setCellModifier(modifier);
}
protected TableEditorImpl createTableEditorImpl() {
return 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) {
fTableEditor.setEditor(w, (TableItem) item, columnNumber);
}
void setSelection(StructuredSelection selection, boolean b) {
AsynchronousTableViewer.this.setSelection(selection, b);
}
void showSelection() {
getTable().showSelection();
}
void setLayoutData(CellEditor.LayoutData layoutData) {
fTableEditor.grabHorizontal = layoutData.grabHorizontal;
fTableEditor.horizontalAlignment = layoutData.horizontalAlignment;
fTableEditor.minimumWidth = layoutData.minimumWidth;
}
void handleDoubleClickEvent() {
Viewer viewer = getViewer();
fireDoubleClick(new DoubleClickEvent(viewer, viewer.getSelection()));
fireOpen(new OpenEvent(viewer, viewer.getSelection()));
}
};
}
protected ISelection newSelectionFromWidget() {
Control control = getControl();
if (control == null || control.isDisposed()) {
return StructuredSelection.EMPTY;
}
List list = getSelectionFromWidget();
return new StructuredSelection(list);
}
public CellEditor[] getCellEditors() {
return fTableEditorImpl.getCellEditors();
}
public ICellModifier getCellModifier() {
return fTableEditorImpl.getCellModifier();
}
public boolean isCellEditorActive() {
return fTableEditorImpl.isCellEditorActive();
}
/**
* This is not asynchronous. This method must be called in the UI Thread.
*/
public void cancelEditing() {
fTableEditorImpl.cancelEditing();
}
/**
* This is not asynchronous. This method must be called in the UI Thread.
*
* @param element
* The element to edit. Each element maps to a row in the Table.
* @param column
* The column to edit
*/
public void editElement(Object element, int column) {
fTableEditorImpl.editElement(element, column);
}
protected int indexForElement(Object element) {
ViewerSorter sorter = getSorter();
if (sorter == null)
return fTable.getItemCount();
int count = fTable.getItemCount();
int min = 0, max = count - 1;
while (min <= max) {
int mid = (min + max) / 2;
Object data = fTable.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 = fTable.getItem(mid).getData();
compare = sorter.compare(this, data, element);
}
return mid;
}
if (compare < 0)
min = mid + 1;
else
max = mid - 1;
}
return min;
}
public void add(Object element) {
if (element != null)
add(new Object[] { element });
}
public void add(Object[] elements) {
if (elements == null || elements.length == 0)
return; // done
((AsynchronousTableModel)getModel()).add(elements);
}
public void remove(Object element) {
if (element != null)
remove(new Object[] { element });
}
public void remove(final Object[] elements) {
if (elements == null || elements.length == 0)
return; // done
((AsynchronousTableModel)getModel()).remove(elements);
}
public void insert(Object element, int position) {
if (element != null)
insert(new Object[] { element }, position);
}
public void insert(Object[] elements, int position) {
if (elements == null || elements.length == 0)
return;
((AsynchronousTableModel)getModel()).insert(elements, position);
}
public void replace(Object element, Object replacement) {
if (element == null || replacement == null)
throw new IllegalArgumentException("unexpected null parameter"); //$NON-NLS-1$
((AsynchronousTableModel)getModel()).replace(element, replacement);
}
/* (non-Javadoc)
* @see org.eclipse.debug.internal.ui.model.viewers.AsynchronousViewer#createModel()
*/
protected AsynchronousModel createModel() {
return new AsynchronousTableModel(this);
}
/* (non-Javadoc)
* @see org.eclipse.debug.internal.ui.model.viewers.AsynchronousViewer#setItemCount(org.eclipse.swt.widgets.Widget, int)
*/
protected void setItemCount(Widget parent, int itemCount) {
fTable.setItemCount(itemCount);
}
protected int getVisibleItemCount(int top) {
int itemCount = fTable.getItemCount();
return Math.min((fTable.getBounds().height / fTable.getItemHeight()) + 2, itemCount - top);
}
/* (non-Javadoc)
* @see org.eclipse.debug.internal.ui.model.viewers.AsynchronousViewer#createUpdatePolicy()
*/
public AbstractUpdatePolicy createUpdatePolicy() {
return new TableUpdatePolicy();
}
/* (non-Javadoc)
* @see org.eclipse.debug.internal.ui.model.viewers.AsynchronousViewer#getParentWidget(org.eclipse.swt.widgets.Widget)
*/
protected Widget getParentWidget(Widget widget) {
if (widget instanceof TableItem) {
return ((TableItem)widget).getParent();
}
return null;
}
/* (non-Javadoc)
* @see org.eclipse.debug.internal.ui.model.viewers.AsynchronousViewer#getChildWidget(org.eclipse.swt.widgets.Widget, int)
*/
protected Widget getChildWidget(Widget parent, int index) {
if (index < fTable.getItemCount()) {
return fTable.getItem(index);
}
return null;
}
/* (non-Javadoc)
* @see org.eclipse.debug.internal.ui.model.viewers.AsynchronousViewer#clear(org.eclipse.swt.widgets.Widget)
*/
protected void clear(Widget item) {
if (item instanceof TableItem) {
int i = fTable.indexOf((TableItem)item);
if (i >= 0) {
fTable.clear(i);
}
}
}
/* (non-Javadoc)
* @see org.eclipse.debug.internal.ui.viewers.AsynchronousViewer#clearChild(org.eclipse.swt.widgets.Widget, int)
*/
protected void clearChild(Widget parent, int childIndex) {
if (parent instanceof Table) {
fTable.clear(childIndex);
}
}
/* (non-Javadoc)
* @see org.eclipse.debug.internal.ui.viewers.AsynchronousViewer#clearChildren(org.eclipse.swt.widgets.Widget)
*/
protected void clearChildren(Widget item) {
if (item instanceof Table) {
fTable.clearAll();
}
}
/* (non-Javadoc)
* @see org.eclipse.debug.internal.ui.viewers.AsynchronousViewer#indexOf(org.eclipse.swt.widgets.Widget, org.eclipse.swt.widgets.Widget)
*/
protected int indexOf(Widget parent, Widget child) {
if (parent instanceof Table) {
return ((Table)parent).indexOf((TableItem)child);
}
return -1;
}
}