| /******************************************************************************* |
| * Copyright (c) 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.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.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.provisional.IAsynchronousRequestMonitor; |
| import org.eclipse.debug.internal.ui.views.memory.MemoryViewUtil; |
| import org.eclipse.jface.resource.JFaceResources; |
| import org.eclipse.jface.viewers.IBaseLabelProvider; |
| 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.DisposeEvent; |
| import org.eclipse.swt.events.DisposeListener; |
| import org.eclipse.swt.events.FocusAdapter; |
| import org.eclipse.swt.events.FocusEvent; |
| 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.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 FocusAdapter fEditorFocusListener; |
| private KeyAdapter fEditorKeyListener; |
| |
| private boolean fPendingFormatViewer; |
| |
| public AsyncTableRenderingViewer(AbstractAsyncTableRendering rendering, Composite parent, int style) { |
| super(parent, style); |
| fRendering = rendering; |
| |
| getTable().addMouseListener(new MouseAdapter() { |
| public void mouseDown(MouseEvent e) { |
| handleTableMouseEvent(e); |
| }}); |
| |
| createCursor(getTable()); |
| } |
| |
| 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() { |
| public void keyPressed(KeyEvent e) |
| { |
| handleCursorKeyPressed(e); |
| } |
| }; |
| |
| fTableCursor.addKeyListener(fCursorKeyAdapter); |
| |
| fCursorTraverseListener = new TraverseListener() { |
| public void keyTraversed(TraverseEvent e) { |
| handleCursorTraverseEvt(e); |
| }}; |
| |
| fTableCursor.addTraverseListener(fCursorTraverseListener); |
| |
| fCursorMouseListener = new MouseAdapter() { |
| 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(new DisposeListener() { |
| public void widgetDisposed(DisposeEvent e) { |
| if (fTableCursor == null) |
| return; |
| fTableCursor.removeTraverseListener(fCursorTraverseListener); |
| fTableCursor.removeKeyListener(fCursorKeyAdapter); |
| fTableCursor.removeMouseListener(fCursorMouseListener); |
| fTableCursor.removeSelectionListener(fCursorSelectionListener); |
| }}); |
| |
| fCursorSelectionListener = new SelectionAdapter() { |
| 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) |
| { |
| String initialValue = String.valueOf(event.character); |
| activateCellEditor(initialValue); |
| return; |
| } |
| } |
| } |
| |
| 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 (AsyncVirtualContentTableViewer.DEBUG_DYNAMIC_LOADING) |
| System.out.println(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$ |
| |
| public IStatus runInUIThread(IProgressMonitor monitor) { |
| try { |
| if (AsyncVirtualContentTableViewer.DEBUG_DYNAMIC_LOADING) |
| System.out.println(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 (AsyncVirtualContentTableViewer.DEBUG_DYNAMIC_LOADING) |
| { |
| System.out.println(getRendering() + " set cursor selection, row is " + getTable().getItem(newLocation[0]).getData()); //$NON-NLS-1$ |
| System.out.println(getRendering() + " set cursor selection, model is " + getVirtualContentModel().getElement(newLocation[0])); //$NON-NLS-1$ |
| } |
| |
| fTableCursor.setSelection(newLocation[0], newLocation[1]); |
| showTableCursor(true); |
| |
| 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 |
| * @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; |
| } |
| |
| |
| protected synchronized void preservingSelection(Runnable updateCode) { |
| Object oldTopIndexKey = null; |
| |
| if (getPendingSetTopIndexKey() == null) { |
| // preserve selection |
| oldTopIndexKey = getTopIndexKey(); |
| } |
| else |
| { |
| oldTopIndexKey = getPendingSetTopIndexKey(); |
| } |
| Object oldSelectionKey = null; |
| try { |
| if (AsyncVirtualContentTableViewer.DEBUG_DYNAMIC_LOADING) |
| { |
| if (oldTopIndexKey != null) |
| System.out.println(getRendering() + " preserve top index: " + ((BigInteger)oldTopIndexKey).toString(16)); //$NON-NLS-1$ |
| else |
| System.out.println("top index key is null, nothing to preserve"); //$NON-NLS-1$ |
| } |
| |
| if (fPendingSelection != null) |
| oldSelectionKey = fPendingSelection; |
| else |
| oldSelectionKey = getSelectionKey(); |
| |
| if (AsyncVirtualContentTableViewer.DEBUG_DYNAMIC_LOADING) |
| { |
| if (oldTopIndexKey != null) |
| System.out.println(getRendering() + " preserve selection: " + ((BigInteger)oldSelectionKey).toString(16)); //$NON-NLS-1$ |
| else |
| System.out.println("selection key is null, nothing to preserve"); //$NON-NLS-1$ |
| } |
| |
| // perform the update |
| updateCode.run(); |
| |
| } finally { |
| |
| if (oldSelectionKey != null) |
| { |
| if (AsyncVirtualContentTableViewer.DEBUG_DYNAMIC_LOADING) |
| System.out.println(getRendering() + " preserved selection " + ((BigInteger)oldSelectionKey).toString(16)); //$NON-NLS-1$ |
| setSelection(oldSelectionKey); |
| } |
| |
| if (getPendingSetTopIndexKey() != null) |
| { |
| if (AsyncVirtualContentTableViewer.DEBUG_DYNAMIC_LOADING) |
| System.out.println(getRendering() + " finished top index: " + ((BigInteger)oldTopIndexKey).toString(16)); //$NON-NLS-1$ |
| setTopIndex(getPendingSetTopIndexKey()); |
| } |
| else if (oldTopIndexKey != null) |
| { |
| setTopIndex(oldTopIndexKey); |
| |
| if (AsyncVirtualContentTableViewer.DEBUG_DYNAMIC_LOADING) |
| System.out.println(getRendering() + " finished top index: " + ((BigInteger)oldTopIndexKey).toString(16)); //$NON-NLS-1$ |
| } |
| } |
| } |
| |
| 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$ |
| |
| 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 prefill it with initial value. |
| * If initialValue is null, use cell content as initial value |
| * @param initialValue |
| */ |
| private void activateCellEditor(String initialValue) { |
| |
| int col = fTableCursor.getColumn(); |
| 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); |
| |
| // The cell modifier canModify function always returns false if the edit action |
| // is not invoked from here. This is to prevent data to be modified when |
| // the table cursor loses focus from a cell. By default, data will |
| // be changed in a table when the cell loses focus. This is to workaround |
| // this default behaviour and only change data when the cell editor |
| // is activated. |
| ((AsyncTableRenderingCellModifier)cellModifier).setEditActionInvoked(true); |
| boolean canEdit = cellModifier.canModify(element, (String)property); |
| ((AsyncTableRenderingCellModifier)cellModifier).setEditActionInvoked(false); |
| |
| if (!canEdit) |
| return; |
| |
| // activate based on current cursor position |
| TextCellEditor selectedEditor = (TextCellEditor)getCellEditors()[col]; |
| |
| if (selectedEditor != null) |
| { |
| // The control that will be the editor must be a child of the Table |
| Text text = (Text)selectedEditor.getControl(); |
| |
| String cellValue = null; |
| |
| if (initialValue != null) |
| { |
| cellValue = initialValue; |
| } |
| else |
| { |
| cellValue = ((String)value); |
| } |
| |
| text.setText(cellValue); |
| |
| fCursorEditor.horizontalAlignment = SWT.LEFT; |
| fCursorEditor.grabHorizontal = true; |
| |
| // Open the text editor in selected column of the selected row. |
| fCursorEditor.setEditor (text, tableItem, col); |
| |
| // Assign focus to the text control |
| selectedEditor.setFocus(); |
| |
| if (initialValue != null) |
| { |
| text.clearSelection(); |
| } |
| |
| text.setFont(JFaceResources.getFont(IInternalDebugUIConstants.FONT_NAME)); |
| |
| // add listeners for the text control |
| addListeners(text); |
| |
| // move cursor below text control |
| fTableCursor.moveBelow(text); |
| } |
| } |
| } |
| |
| /* |
| * @param text |
| */ |
| private void addListeners(Text text) { |
| fEditorFocusListener = new FocusAdapter() { |
| public void focusLost(FocusEvent e) |
| { |
| handleTableEditorFocusLost(e); |
| } |
| }; |
| text.addFocusListener(fEditorFocusListener); |
| |
| fEditorKeyListener = new KeyAdapter() { |
| public void keyPressed(KeyEvent e) { |
| handleKeyEventInEditor(e); |
| } |
| }; |
| |
| text.addKeyListener(fEditorKeyListener); |
| } |
| |
| private void handleTableEditorFocusLost(FocusEvent event) |
| { |
| final FocusEvent e = event; |
| |
| Display.getDefault().syncExec(new Runnable() { |
| |
| public void run() |
| { |
| try |
| { |
| int row = indexOf(fSelectionKey); |
| int col = fTableCursor.getColumn(); |
| |
| Text text = (Text)e.getSource(); |
| removeListeners(text); |
| |
| // get new value |
| String newValue = text.getText(); |
| |
| // modify memory at fRow and fCol |
| modifyValue(row, col, newValue); |
| |
| // show cursor after modification is completed |
| setSelection(fSelectionKey); |
| fTableCursor.moveAbove(text); |
| showTableCursor(true); |
| } |
| catch (NumberFormatException e1) |
| { |
| MemoryViewUtil.openError(DebugUIMessages.MemoryViewCellModifier_failure_title, |
| DebugUIMessages.MemoryViewCellModifier_data_is_invalid, null); |
| } |
| } |
| }); |
| } |
| |
| /** |
| * @param event |
| */ |
| private void handleKeyEventInEditor(KeyEvent event) { |
| |
| final KeyEvent e = event; |
| Display.getDefault().asyncExec(new Runnable() |
| { |
| public void run() |
| { |
| Text text = (Text)e.getSource(); |
| int row = indexOf(fSelectionKey); |
| int col = fTableCursor.getColumn(); |
| |
| try |
| { |
| switch (e.keyCode) |
| { |
| case SWT.ARROW_UP : |
| |
| // move text editor box up one row |
| if (row-1 < 0) |
| return; |
| |
| // modify value for current cell |
| modifyValue(row, col, text.getText()); |
| |
| row--; |
| |
| // update cursor location and selection in table |
| fTableCursor.setSelection(row, col); |
| handleCursorMoved(); |
| |
| // remove listeners when focus is lost |
| removeListeners(text); |
| activateCellEditor(null); |
| break; |
| case SWT.ARROW_DOWN : |
| |
| // move text editor box down one row |
| |
| if (row+1 >= getTable().getItemCount()) |
| return; |
| |
| // modify value for current cell |
| modifyValue(row, col, text.getText()); |
| |
| row++; |
| |
| // update cursor location and selection in table |
| fTableCursor.setSelection(row, col); |
| handleCursorMoved(); |
| |
| // remove traverse listener when focus is lost |
| removeListeners(text); |
| activateCellEditor(null); |
| break; |
| case 0: |
| |
| // if user has entered the max number of characters allowed in a cell, move to next cell |
| // Extra changes will be used as initial value for the next cell |
| int numCharsPerByte = fRendering.getNumCharsPerByte(); |
| if (numCharsPerByte > 0) |
| { |
| if (text.getText().length() > fRendering.getBytesPerColumn()*numCharsPerByte) |
| { |
| String newValue = text.getText(); |
| text.setText(newValue.substring(0, fRendering.getBytesPerColumn()*numCharsPerByte)); |
| |
| modifyValue(row, col, text.getText()); |
| |
| // if cursor is at the end of a line, move to next line |
| if (col >= getNumCol()) |
| { |
| col = 1; |
| row++; |
| } |
| else |
| { |
| // move to next column |
| row++; |
| } |
| |
| // update cursor position and selected address |
| fTableCursor.setSelection(row, col); |
| handleCursorMoved(); |
| |
| removeListeners(text); |
| |
| // activate text editor at next cell |
| activateCellEditor(newValue.substring(fRendering.getBytesPerColumn()*numCharsPerByte)); |
| } |
| } |
| break; |
| case SWT.ESC: |
| |
| // if user has pressed escape, do not commit the changes |
| // that's why "modifyValue" is not called |
| fTableCursor.setSelection(row, col); |
| handleCursorMoved(); |
| |
| removeListeners(text); |
| |
| // cursor needs to have focus to remove focus from cell editor |
| fTableCursor.setFocus(); |
| break; |
| default : |
| numCharsPerByte = fRendering.getNumCharsPerByte(); |
| if (numCharsPerByte > 0) |
| { |
| if (text.getText().length()> fRendering.getBytesPerColumn()* numCharsPerByte) |
| { |
| String newValue = text.getText(); |
| text.setText(newValue.substring(0,fRendering.getBytesPerColumn()* numCharsPerByte)); |
| modifyValue(row, col, text.getText()); |
| // 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(); |
| |
| removeListeners(text); |
| |
| activateCellEditor(newValue.substring(fRendering.getBytesPerColumn()*numCharsPerByte)); |
| } |
| } |
| break; |
| } |
| } |
| catch (NumberFormatException e1) |
| { |
| MemoryViewUtil.openError(DebugUIMessages.MemoryViewCellModifier_failure_title, |
| DebugUIMessages.MemoryViewCellModifier_data_is_invalid, null); |
| |
| fTableCursor.setSelection(row, col); |
| handleCursorMoved(); |
| |
| removeListeners(text); |
| } |
| } |
| }); |
| } |
| |
| /** |
| * @param text |
| */ |
| private void removeListeners(Text text) { |
| |
| text.removeFocusListener(fEditorFocusListener); |
| text.removeKeyListener(fEditorKeyListener); |
| } |
| |
| /** |
| * Modify value and send new value to debug adapter |
| * @param row |
| * @param col |
| * @param newValue |
| * @throws NumberFormatException |
| */ |
| private void modifyValue(int row, int col, String newValue) throws NumberFormatException |
| { |
| if (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. |
| */ |
| public IBaseLabelProvider getLabelProvider() { |
| return new ITableLabelProvider() { |
| |
| public Image getColumnImage(Object element, int columnIndex) { |
| return null; |
| } |
| |
| 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 ""; //$NON-NLS-1$ |
| } |
| |
| public void addListener(ILabelProviderListener listener) { |
| } |
| |
| public void dispose() { |
| } |
| |
| public boolean isLabelProperty(Object element, String property) { |
| return false; |
| } |
| |
| 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(new Runnable() { |
| |
| public void run() { |
| // 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); |
| } |
| } |
| |
| public void handlePresentationFailure(IAsynchronousRequestMonitor monitor, IStatus status) { |
| super.handlePresentationFailure(monitor, status); |
| } |
| |
| public void refresh(boolean getContent) |
| { |
| if (getContent) |
| refresh(); |
| else |
| { |
| preservingSelection(new Runnable() { |
| |
| public void run() { |
| AbstractVirtualContentTableModel model = getVirtualContentModel(); |
| if (model != null) |
| { |
| Object[] elements = model.getElements(); |
| model.remove(elements); |
| model.add(elements); |
| } |
| }}); |
| } |
| } |
| |
| 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.model.viewers.AsynchronousViewer#getModel() |
| */ |
| public AsynchronousModel getModel() { |
| return super.getModel(); |
| } |
| |
| // TODO: need pluggable model to be truly flexible |
| protected AbstractVirtualContentTableModel createVirtualContentTableModel() { |
| return new TableRenderingModel(this); |
| } |
| |
| protected void updateComplete(IAsynchronousRequestMonitor 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(new Runnable() { |
| |
| public void run() { |
| |
| int[] coordinates = getCoordinatesFromKey(getSelectionKey()); |
| if (coordinates.length > 0) |
| fTableCursor.setVisible(true); |
| else |
| fTableCursor.setVisible(false); |
| }}); |
| } |
| } |
| |
| if (!hasPendingUpdates() && fPendingFormatViewer) |
| { |
| formatViewer(); |
| resizeColumnsToPreferredSize(); |
| } |
| } |
| |
| 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); |
| } |
| } |
| } |