blob: 398296ccf13467015269eaf029858c9b76ab4d33 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2006, 2018 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.debug.internal.ui.views.memory.renderings;
import java.math.BigInteger;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.debug.internal.core.IInternalDebugCoreConstants;
import org.eclipse.debug.internal.ui.DebugUIMessages;
import org.eclipse.debug.internal.ui.DebugUIPlugin;
import org.eclipse.debug.internal.ui.IInternalDebugUIConstants;
import org.eclipse.debug.internal.ui.memory.provisional.AbstractAsyncTableRendering;
import org.eclipse.debug.internal.ui.viewers.AbstractUpdatePolicy;
import org.eclipse.debug.internal.ui.viewers.AsynchronousModel;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IStatusMonitor;
import org.eclipse.debug.internal.ui.views.memory.MemoryViewUtil;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.viewers.CellEditor;
import org.eclipse.jface.viewers.IBaseLabelProvider;
import org.eclipse.jface.viewers.ICellEditorListener;
import org.eclipse.jface.viewers.ICellModifier;
import org.eclipse.jface.viewers.ILabelProviderListener;
import org.eclipse.jface.viewers.ITableLabelProvider;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.TextCellEditor;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.TableCursor;
import org.eclipse.swt.custom.TableEditor;
import org.eclipse.swt.events.KeyAdapter;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.MouseAdapter;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.TraverseEvent;
import org.eclipse.swt.events.TraverseListener;
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.Display;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.swt.widgets.Text;
import org.eclipse.swt.widgets.Widget;
import org.eclipse.ui.progress.UIJob;
public class AsyncTableRenderingViewer extends AsyncVirtualContentTableViewer {
private AbstractAsyncTableRendering fRendering;
// selection keys
private Object fPendingSelection;
private Object fSelectionKey;
// cursor and associated listeners
private TableCursor fTableCursor;
private KeyAdapter fCursorKeyAdapter;
private TraverseListener fCursorTraverseListener;
private MouseAdapter fCursorMouseListener;
private SelectionAdapter fCursorSelectionListener;
// cursor editor and associated listeners
private TableEditor fCursorEditor;
private KeyAdapter fEditorKeyListener;
private CellEditorListener fCellEditorListener;
private class CellEditorListener implements ICellEditorListener {
private CellEditor fEditor;
private int fRow;
private int fCol;
public CellEditorListener(int row, int col, CellEditor editor) {
fEditor = editor;
fRow = row;
fCol = col;
}
@Override
public void applyEditorValue() {
fEditor.removeListener(this);
modifyValue(fRow, fCol, fEditor.getValue());
}
@Override
public void cancelEditor() {
fEditor.removeListener(this);
}
@Override
public void editorValueChanged(boolean oldValidState,
boolean newValidState) {
}
public int getRow()
{
return fRow;
}
public int getCol()
{
return fCol;
}
}
private boolean fPendingFormatViewer;
public AsyncTableRenderingViewer(AbstractAsyncTableRendering rendering, Composite parent, int style) {
super(parent, style);
fRendering = rendering;
getTable().addMouseListener(new MouseAdapter() {
@Override
public void mouseDown(MouseEvent e) {
handleTableMouseEvent(e);
}});
createCursor(getTable());
}
@Override
public AbstractUpdatePolicy createUpdatePolicy() {
return new AsyncTableRenderingUpdatePolicy();
}
public AbstractAsyncTableRendering getRendering()
{
return fRendering;
}
private void createCursor(Table table)
{
fTableCursor = new TableCursor(table, SWT.NONE);
Display display = fTableCursor.getDisplay();
// set up cursor color
fTableCursor.setBackground(display.getSystemColor(SWT.COLOR_LIST_SELECTION));
fTableCursor.setForeground(display.getSystemColor(SWT.COLOR_LIST_SELECTION_TEXT));
fTableCursor.setFont(JFaceResources.getFont(IInternalDebugUIConstants.FONT_NAME));
fCursorKeyAdapter = new KeyAdapter() {
@Override
public void keyPressed(KeyEvent e)
{
handleCursorKeyPressed(e);
}
};
fTableCursor.addKeyListener(fCursorKeyAdapter);
fCursorTraverseListener = e -> handleCursorTraverseEvt(e);
fTableCursor.addTraverseListener(fCursorTraverseListener);
fCursorMouseListener = new MouseAdapter() {
@Override
public void mouseDown(MouseEvent e) {
handleCursorMouseEvent(e);
}};
fTableCursor.addMouseListener(fCursorMouseListener);
// cursor may be disposed before disposed is called
// remove listeners whenever the cursor is disposed
fTableCursor.addDisposeListener(e -> {
if (fTableCursor == null) {
return;
}
fTableCursor.removeTraverseListener(fCursorTraverseListener);
fTableCursor.removeKeyListener(fCursorKeyAdapter);
fTableCursor.removeMouseListener(fCursorMouseListener);
fTableCursor.removeSelectionListener(fCursorSelectionListener);
});
fCursorSelectionListener = new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
handleCursorMoved();
}
};
fTableCursor.addSelectionListener(fCursorSelectionListener);
fCursorEditor = new TableEditor (getTable());
}
private void handleCursorKeyPressed(KeyEvent event)
{
if (event.character == '\r' && event.getSource() instanceof TableCursor)
{
activateCellEditor(null);
return;
}
if (MemoryViewUtil.isValidEditEvent(event.keyCode))
{
// activate edit as soon as user types something at the cursor
if (event.getSource() instanceof TableCursor)
{
int col = fTableCursor.getColumn();
if (getCellEditors()[col] instanceof TextCellEditor)
{
String initialValue = String.valueOf(event.character);
activateCellEditor(initialValue);
}
}
}
}
private void handleCursorMouseEvent(MouseEvent e){
if (e.button == 1)
{
int col = fTableCursor.getColumn();
if (col > 0 && col <= (getNumCol())) {
activateCellEditor(null);
}
}
}
private void handleCursorTraverseEvt(TraverseEvent e){
if (fTableCursor.getRow() == null) {
return;
}
Table table = (Table)fTableCursor.getParent();
int row = table.indexOf(fTableCursor.getRow());
int col = fTableCursor.getColumn();
if (col == getNumCol() && e.keyCode == SWT.ARROW_RIGHT)
{
if (row + 1>= table.getItemCount())
{
return;
}
row = row +1;
col = 0;
fTableCursor.setSelection(row, col);
}
if (col <= 1 && e.keyCode == SWT.ARROW_LEFT)
{
if (row-1 < 0)
{
return;
}
row = row - 1;
col = getNumCol()+1;
fTableCursor.setSelection(row, col);
}
handleCursorMoved();
}
/**
* Update selected address.
* Load more memory if required.
*/
private void handleCursorMoved()
{
fSelectionKey = getSelectionKeyFromCursor();
fPendingSelection = null;
if (DebugUIPlugin.DEBUG_DYNAMIC_LOADING) {
DebugUIPlugin.trace(Thread.currentThread().getName() + " cursor moved selection is: " + ((BigInteger)fSelectionKey).toString(16)); //$NON-NLS-1$
}
// now check to see if the cursor is approaching buffer limit
handleScrollBarSelection();
fireSelectionChanged(fSelectionKey);
}
private int getNumCol() {
int bytesPerLine = fRendering.getBytesPerLine();
int columnSize = fRendering.getBytesPerColumn();
return bytesPerLine/columnSize;
}
/**
* Sets the cursor at the specified address
* @param key selection key
*/
public void setSelection(Object key)
{
fPendingSelection = key;
attemptSetKeySelection();
}
public Object getSelectionKey()
{
return fSelectionKey;
}
private synchronized void attemptSetKeySelection()
{
if (fPendingSelection != null) {
doAttemptSetKeySelection(fPendingSelection);
}
}
synchronized private Object doAttemptSetKeySelection(final Object key)
{
if (getBufferTopKey() == null || getBufferEndKey() == null) {
return key;
}
// calculate selected row address
int[] location = getCoordinatesFromKey(key);
if(location.length == 0)
{
return key;
}
UIJob uiJob = new UIJob("Set Cursor Selection"){ //$NON-NLS-1$
@Override
public IStatus runInUIThread(IProgressMonitor monitor) {
try {
if (DebugUIPlugin.DEBUG_DYNAMIC_LOADING) {
DebugUIPlugin.trace(getRendering() + " set cursor selection " + ((BigInteger)key).toString(16)); //$NON-NLS-1$
}
if (fPendingSelection != null && fPendingSelection != key) {
return Status.OK_STATUS;
}
if (fTableCursor.isDisposed()) {
return Status.OK_STATUS;
}
// by the time this is called, the location may not be valid anymore
int[] newLocation = getCoordinatesFromKey(key);
if (newLocation.length == 0)
{
Object selectionKey = getSelectionKey();
fPendingSelection = selectionKey;
return Status.OK_STATUS;
}
fSelectionKey = key;
fPendingSelection = null;
if (DebugUIPlugin.DEBUG_DYNAMIC_LOADING) {
DebugUIPlugin.trace(getRendering() + " set cursor selection, row is " + getTable().getItem(newLocation[0]).getData()); //$NON-NLS-1$
DebugUIPlugin.trace(getRendering() + " set cursor selection, model is " + getVirtualContentModel().getElement(newLocation[0])); //$NON-NLS-1$
}
fTableCursor.setSelection(newLocation[0], newLocation[1]);
showTableCursor(true);
// show the column for the selection
getTable().showColumn(getTable().getColumn(newLocation[1]));
int topIndex = getTable().getTopIndex();
Object topKey = getVirtualContentModel().getKey(topIndex);
setTopIndexKey(topKey);
} catch (RuntimeException e) {
// by the time this is called, the selection may no longer
// get the latest selection and try to set selection again
Object selectionKey = getSelectionKey();
fPendingSelection = selectionKey;
doAttemptSetKeySelection(selectionKey);
}
return Status.OK_STATUS;
}};
uiJob.setSystem(true);
uiJob.schedule();
return null;
}
/**
*
* @param key the element
* @return the coordinates of the key
* Element[0] is the row index
* Element[1] is the column index
*/
private int[] getCoordinatesFromKey(Object key)
{
final int row = indexOf(key);
if (row == -1)
{
return new int[0];
}
Object element = getVirtualContentModel().getElement(row);
final int col = columnOf(element, key);
if (col == -1)
{
return new int[0];
}
return new int[]{row, col};
}
private Object getSelectionKeyFromCursor()
{
int idx = getTable().indexOf(fTableCursor.getRow());
int col = fTableCursor.getColumn();
return getVirtualContentModel().getKey(idx, col);
}
private Object getBufferTopKey()
{
return getKey(0);
}
private Object getBufferEndKey()
{
AbstractVirtualContentTableModel model = getVirtualContentModel();
if (model != null) {
return getKey(model.getElements().length-1);
}
return null;
}
public int indexOf(Object key)
{
int idx = -1;
AbstractVirtualContentTableModel model = getVirtualContentModel();
if (model != null) {
idx = model.indexOfKey(key);
}
return idx;
}
private int columnOf(Object element, Object key)
{
int idx = -1;
AbstractVirtualContentTableModel model = getVirtualContentModel();
if (model != null)
{
idx = model.columnOf(element, key);
}
return idx;
}
public Object getKey(int index)
{
AbstractVirtualContentTableModel model = getVirtualContentModel();
if (model != null)
{
Object key = model.getKey(index);
return key;
}
return null;
}
public Object getKey(int row, int col)
{
AbstractVirtualContentTableModel model = getVirtualContentModel();
if (model != null) {
return model.getKey(row, col);
}
return null;
}
@Override
protected synchronized void preservingSelection(Runnable updateCode) {
Object oldTopIndexKey = null;
if (getPendingSetTopIndexKey() == null) {
// preserve selection
oldTopIndexKey = getTopIndexKey();
}
else
{
oldTopIndexKey = getPendingSetTopIndexKey();
}
Object oldSelectionKey = null;
try {
if (DebugUIPlugin.DEBUG_DYNAMIC_LOADING)
{
if (oldTopIndexKey != null) {
DebugUIPlugin.trace(getRendering() + " preserve top index: " + ((BigInteger)oldTopIndexKey).toString(16)); //$NON-NLS-1$
}
else {
DebugUIPlugin.trace("top index key is null, nothing to preserve"); //$NON-NLS-1$
}
}
if (fPendingSelection != null) {
oldSelectionKey = fPendingSelection;
} else {
oldSelectionKey = getSelectionKey();
}
if (DebugUIPlugin.DEBUG_DYNAMIC_LOADING)
{
if (oldTopIndexKey != null) {
DebugUIPlugin.trace(getRendering() + " preserve selection: " + ((BigInteger)oldSelectionKey).toString(16)); //$NON-NLS-1$
}
else {
DebugUIPlugin.trace("selection key is null, nothing to preserve"); //$NON-NLS-1$
}
}
// perform the update
updateCode.run();
} finally {
if (oldSelectionKey != null)
{
if (DebugUIPlugin.DEBUG_DYNAMIC_LOADING) {
DebugUIPlugin.trace(getRendering() + " preserved selection " + ((BigInteger)oldSelectionKey).toString(16)); //$NON-NLS-1$
}
setSelection(oldSelectionKey);
}
if (getPendingSetTopIndexKey() != null)
{
if (DebugUIPlugin.DEBUG_DYNAMIC_LOADING) {
if (oldTopIndexKey != null) {
DebugUIPlugin.trace(getRendering() + " finished top index: " + ((BigInteger)oldTopIndexKey).toString(16)); //$NON-NLS-1$
}
}
setTopIndex(getPendingSetTopIndexKey());
}
else if (oldTopIndexKey != null)
{
setTopIndex(oldTopIndexKey);
if (DebugUIPlugin.DEBUG_DYNAMIC_LOADING) {
DebugUIPlugin.trace(getRendering() + " finished top index: " + ((BigInteger)oldTopIndexKey).toString(16)); //$NON-NLS-1$
}
}
}
}
@Override
public void dispose()
{
super.dispose();
if (fTableCursor != null && !fTableCursor.isDisposed())
{
fCursorEditor.dispose();
fCursorEditor = null;
fTableCursor.removeTraverseListener(fCursorTraverseListener);
fTableCursor.removeKeyListener(fCursorKeyAdapter);
fTableCursor.removeMouseListener(fCursorMouseListener);
fTableCursor.removeSelectionListener(fCursorSelectionListener);
fTableCursor.dispose();
fTableCursor = null;
}
}
public void showTableCursor(final boolean show)
{
Display display = DebugUIPlugin.getDefault().getWorkbench().getDisplay();
if (Thread.currentThread() == display.getThread())
{
if (!fTableCursor.isDisposed())
{
if (fTableCursor.isVisible() != show) {
fTableCursor.setVisible(show);
}
}
}
else
{
UIJob job = new UIJob("show table cursor"){ //$NON-NLS-1$
@Override
public IStatus runInUIThread(IProgressMonitor monitor) {
if (!fTableCursor.isDisposed())
{
if (fTableCursor.isVisible() != show) {
fTableCursor.setVisible(show);
}
}
return Status.OK_STATUS;
}};
job.setSystem(true);
job.schedule();
}
}
private void handleTableMouseEvent(MouseEvent e) {
// figure out new cursor position based on here the mouse is pointing
TableItem[] tableItems = getTable().getItems();
TableItem selectedRow = null;
int colNum = -1;
int numCol = getColumnProperties().length;
for (int j=0; j<tableItems.length; j++)
{
TableItem item = tableItems[j];
if (item.getData() != null)
{
for (int i=0; i<numCol; i++)
{
Rectangle bound = item.getBounds(i);
if (bound.contains(e.x, e.y))
{
colNum = i;
selectedRow = item;
break;
}
}
}
if (colNum >= 0) {
break;
}
}
// if column position cannot be determined, return
if (colNum < 1) {
return;
}
// handle user mouse click onto table
// move cursor to new position
if (selectedRow != null)
{
int row = getTable().indexOf(selectedRow);
showTableCursor(true);
fTableCursor.setSelection(row, colNum);
// manually call this since we don't get an event when
// the table cursor changes selection.
handleCursorMoved();
fTableCursor.setFocus();
}
}
/**
* Activate cell editor and pre-fill it with initial value.
* If initialValue is null, use cell content as initial value
* @param initialValue the initial value for the cell editor
*/
private void activateCellEditor(String initialValue) {
final int col = fTableCursor.getColumn();
final int row = indexOf(fSelectionKey);
if (row < 0) {
return;
}
// do not allow user to edit address column
if (col == 0 || col > getNumCol()) {
return;
}
ICellModifier cellModifier = null;
cellModifier = getCellModifier();
TableItem tableItem = getTable().getItem(row);
Object element = tableItem.getData();
if (element != null) {
Object property = getColumnProperties()[col];
Object value = cellModifier.getValue(element, (String) property);
boolean canEdit = cellModifier
.canModify(element, (String) property);
if (!canEdit) {
return;
}
CellEditor editor = getCellEditors()[col];
if (editor != null) {
// The control that will be the editor must be a child of the
// Table
Control control = editor.getControl();
Object cellValue = null;
if (initialValue != null) {
cellValue = initialValue;
} else {
cellValue = value;
}
editor.setValue(cellValue);
fCursorEditor.horizontalAlignment = SWT.LEFT;
fCursorEditor.grabHorizontal = true;
// Open the editor editor in selected column of the selected
// row.
fCursorEditor.setEditor(control, tableItem, col);
// Assign focus to the editor control
editor.setFocus();
if (initialValue != null && control instanceof Text) {
((Text) control).clearSelection();
}
control.setFont(JFaceResources
.getFont(IInternalDebugUIConstants.FONT_NAME));
// add listeners for the editor control
addListeners(control);
fCellEditorListener = new CellEditorListener(row, col, editor);
editor.addListener(fCellEditorListener);
// move cursor below editor control
fTableCursor.moveBelow(control);
}
}
}
private void deactivateEditor(CellEditor editor)
{
removeListeners(editor.getControl());
fTableCursor.moveAbove(editor.getControl());
fTableCursor.setFocus();
}
/*
* @param editor
*/
private void addListeners(Control control) {
fEditorKeyListener = new KeyAdapter() {
@Override
public void keyPressed(KeyEvent e) {
handleKeyEventInEditor(e);
}
};
control.addKeyListener(fEditorKeyListener);
}
/**
* @param event the key event
*/
private void handleKeyEventInEditor(KeyEvent event) {
final KeyEvent e = event;
Display.getDefault().asyncExec(() -> {
Object obj = e.getSource();
if (obj instanceof Control)
{
Control control = (Control) obj;
int row = fCellEditorListener.getRow();
int col = fCellEditorListener.getCol();
try
{
switch (e.keyCode)
{
case 0:
doHandleKeyEvent(row, col);
break;
case SWT.ESC:
cancelEditing(row, col);
break;
default:
doHandleKeyEvent(row, col);
break;
}
} catch (NumberFormatException e1) {
MemoryViewUtil.openError(DebugUIMessages.MemoryViewCellModifier_failure_title,
DebugUIMessages.MemoryViewCellModifier_data_is_invalid, null);
fTableCursor.setSelection(row, col);
handleCursorMoved();
removeListeners(control);
}
}
});
}
private void doHandleKeyEvent(int row, int col)
{
int numCharsPerByte = fRendering.getNumCharsPerByte();
if (numCharsPerByte > 0)
{
Object value = getCellEditors()[col].getValue();
if (getCellEditors()[col] instanceof TextCellEditor && value instanceof String)
{
String str = (String)value;
if (str.length() > fRendering.getBytesPerColumn()*numCharsPerByte)
{
String newValue = str;
CellEditor editor = getCellEditors()[col];
editor.setValue(newValue.substring(0,fRendering.getBytesPerColumn()* numCharsPerByte));
// We want to call modify value here to avoid race condition.
// Relying on the editor event to modify the cell may introduce a race condition since
// we try to activate another cell editor in this method. If we happen to use same cell
// editor in the next activation, the value of the editor may be incorrect when the listener gets the event.
// We may write the wrong value in that case. Calling modify here allows us to capture the value
// now and send that to the model.
fCellEditorListener.cancelEditor();
deactivateEditor(editor);
modifyValue(fCellEditorListener.getRow(), fCellEditorListener.getCol(), editor.getValue());
// if cursor is at the end of a line, move to next line
if (col >= getNumCol())
{
col = 1;
row++;
}
else
{
col++;
}
fTableCursor.setSelection(row, col);
handleCursorMoved();
activateCellEditor(newValue.substring(fRendering.getBytesPerColumn()*numCharsPerByte));
}
}
}
}
private void cancelEditing(int row, int col)
{
// if user has pressed escape, do not commit the changes
// remove listener to avoid getting notified on the modify value
fCellEditorListener.cancelEditor();
deactivateEditor(getCellEditors()[col]);
fTableCursor.setSelection(row, col);
handleCursorMoved();
// cursor needs to have focus to remove focus from cell editor
fTableCursor.setFocus();
}
/**
* @param control the control to remove the default key listener from
*/
private void removeListeners(Control control) {
control.removeKeyListener(fEditorKeyListener);
}
/**
* Modify value and send new value to debug adapter
* @param row the row
* @param col the column
* @param newValue the new value
* @throws NumberFormatException if trying to set a number value fails
*/
private void modifyValue(int row, int col, Object newValue) throws NumberFormatException
{
if (newValue instanceof String && ((String)newValue).length() == 0)
{
// do not do anything if user has not entered anything
return;
}
if (row >= 0 && row < getTable().getItemCount())
{
TableItem tableItem = getTable().getItem(row);
Object property = getColumnProperties()[col];
getCellModifier().modify(tableItem, (String)property, newValue);
}
}
public TableCursor getCursor()
{
return fTableCursor;
}
/* (non-Javadoc)
* @see org.eclipse.jface.viewers.ContentViewer#getLabelProvider()
* Implemented minimum to work with PrintTableRendering action.
* This is not a real table labe provider, only goes to the table
* to get the text at the specified row and column.
*/
@Override
public IBaseLabelProvider getLabelProvider() {
return new ITableLabelProvider() {
@Override
public Image getColumnImage(Object element, int columnIndex) {
return null;
}
@Override
public String getColumnText(Object element, int columnIndex) {
int idx = getVirtualContentModel().indexOfElement(element);
if (idx >= 0 )
{
TableItem item = getTable().getItem(idx);
return item.getText(columnIndex);
}
return IInternalDebugCoreConstants.EMPTY_STRING;
}
@Override
public void addListener(ILabelProviderListener listener) {
}
@Override
public void dispose() {
}
@Override
public boolean isLabelProperty(Object element, String property) {
return false;
}
@Override
public void removeListener(ILabelProviderListener listener) {
}};
}
public void formatViewer()
{
if (getModel() == null || !hasPendingUpdates()) {
doFormatViewer();
} else {
// do not format in the middle of an update
// set pending update and will format when update is completed
fPendingFormatViewer = true;
}
}
/**
*
*/
private void doFormatViewer() {
fPendingFormatViewer = false;
preservingSelection(() -> {
// causes the content of the table viewer to be replaced
// without asking content adapter for content
AbstractVirtualContentTableModel model = getVirtualContentModel();
if (model != null) {
model.handleViewerChanged();
}
});
}
private void fireSelectionChanged(Object selectionKey)
{
if (selectionKey != null)
{
SelectionChangedEvent evt = new SelectionChangedEvent(this, new StructuredSelection(selectionKey));
fireSelectionChanged(evt);
}
}
@Override
public void handlePresentationFailure(IStatusMonitor monitor, IStatus status) {
super.handlePresentationFailure(monitor, status);
}
@Override
public void refresh(boolean getContent)
{
if (getContent) {
refresh();
} else
{
preservingSelection(() -> {
AbstractVirtualContentTableModel model = getVirtualContentModel();
if (model != null) {
Object[] elements = model.getElements();
model.remove(elements);
model.add(elements);
}
});
}
}
@Override
protected void tableTopIndexSetComplete() {
if (!fTableCursor.isDisposed())
{
// TODO: work around swt bug, must force a table cursor redraw after top index is changed
// BUG 130130
int[] coordinates = getCoordinatesFromKey(getSelectionKey());
if (coordinates.length > 0) {
fTableCursor.setVisible(true);
} else {
fTableCursor.setVisible(false);
}
}
}
/* (non-Javadoc)
* @see org.eclipse.debug.internal.ui.viewers.model.provisional.viewers.AsynchronousViewer#getModel()
*/
@Override
public AsynchronousModel getModel() {
return super.getModel();
}
// TODO: need pluggable model to be truly flexible
@Override
protected AbstractVirtualContentTableModel createVirtualContentTableModel() {
return new TableRenderingModel(this);
}
@Override
protected void updateComplete(IStatusMonitor monitor) {
super.updateComplete(monitor);
if (!hasPendingUpdates() && !fTableCursor.isDisposed())
{
attemptSetKeySelection();
fTableCursor.redraw();
// if the viewer has pending top index, then more updates will come in
// and the cursor should not be redrawn yet.
if (!hasPendingSetTopIndex())
{
preservingSelection(() -> {
int[] coordinates = getCoordinatesFromKey(getSelectionKey());
if (coordinates.length > 0) {
fTableCursor.setVisible(true);
} else {
fTableCursor.setVisible(false);
}
});
}
}
if (!hasPendingUpdates() && fPendingFormatViewer)
{
formatViewer();
resizeColumnsToPreferredSize();
}
}
@Override
protected void clear(Widget item) {
super.clear(item);
// this table viewer assumes that #getData will return null
// set data to null when clearing an item.
// only visible item will get SET DATA event again and at that time
// the viewer would set the data back.
if (item instanceof TableItem)
{
item.setData(null);
}
}
}