| /******************************************************************************* |
| * Copyright (c) 2004 IBM Corporation and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Common Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/cpl-v10.html |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| *******************************************************************************/ |
| |
| package org.eclipse.debug.internal.ui.views.memory; |
| |
| import java.math.BigInteger; |
| import java.util.ArrayList; |
| |
| import org.eclipse.core.runtime.IConfigurationElement; |
| import org.eclipse.core.runtime.IExtension; |
| import org.eclipse.core.runtime.IExtensionPoint; |
| import org.eclipse.core.runtime.IStatus; |
| import org.eclipse.core.runtime.Platform; |
| import org.eclipse.core.runtime.Status; |
| import org.eclipse.debug.core.DebugException; |
| import org.eclipse.debug.core.model.IMemoryBlock; |
| import org.eclipse.debug.internal.core.memory.IExtendedMemoryBlock; |
| import org.eclipse.debug.internal.core.memory.IMemoryRendering; |
| import org.eclipse.debug.internal.core.memory.MemoryBlockManager; |
| import org.eclipse.debug.internal.ui.DebugUIMessages; |
| import org.eclipse.debug.internal.ui.DebugUIPlugin; |
| import org.eclipse.debug.internal.ui.DelegatingModelPresentation; |
| import org.eclipse.debug.internal.ui.IInternalDebugUIConstants; |
| import org.eclipse.debug.internal.ui.LazyModelPresentation; |
| import org.eclipse.debug.internal.ui.preferences.IDebugPreferenceConstants; |
| import org.eclipse.debug.ui.IDebugModelPresentation; |
| import org.eclipse.debug.ui.IDebugUIConstants; |
| import org.eclipse.jface.action.Action; |
| import org.eclipse.jface.action.IMenuManager; |
| import org.eclipse.jface.action.MenuManager; |
| import org.eclipse.jface.action.Separator; |
| import org.eclipse.jface.preference.IPreferenceStore; |
| import org.eclipse.jface.resource.JFaceResources; |
| import org.eclipse.jface.text.Document; |
| import org.eclipse.jface.text.TextViewer; |
| import org.eclipse.jface.util.IPropertyChangeListener; |
| import org.eclipse.jface.util.PropertyChangeEvent; |
| import org.eclipse.jface.viewers.CellEditor; |
| import org.eclipse.jface.viewers.ICellModifier; |
| import org.eclipse.jface.viewers.TableViewer; |
| import org.eclipse.jface.viewers.TextCellEditor; |
| import org.eclipse.swt.SWT; |
| import org.eclipse.swt.custom.StyledText; |
| import org.eclipse.swt.custom.TableCursor; |
| import org.eclipse.swt.events.ControlEvent; |
| import org.eclipse.swt.events.ControlListener; |
| import org.eclipse.swt.events.DisposeEvent; |
| import org.eclipse.swt.events.DisposeListener; |
| import org.eclipse.swt.events.KeyEvent; |
| import org.eclipse.swt.events.KeyListener; |
| import org.eclipse.swt.events.SelectionEvent; |
| import org.eclipse.swt.events.SelectionListener; |
| import org.eclipse.swt.graphics.Font; |
| import org.eclipse.swt.widgets.Control; |
| import org.eclipse.swt.widgets.Display; |
| import org.eclipse.swt.widgets.ScrollBar; |
| import org.eclipse.swt.widgets.TabItem; |
| import org.eclipse.swt.widgets.Table; |
| import org.eclipse.swt.widgets.TableColumn; |
| import org.eclipse.swt.widgets.TableItem; |
| import org.eclipse.swt.widgets.Text; |
| |
| /** |
| * @since 3.0 |
| */ |
| public class MemoryViewTab extends AbstractMemoryViewTab implements SelectionListener, ControlListener, KeyListener, ITableMemoryViewTab, ISynchronizedMemoryBlockView{ |
| |
| private static final String PREFIX = "MemoryViewTab."; //$NON-NLS-1$ |
| private static final String ADDRESS = PREFIX + "Address"; //$NON-NLS-1$ |
| private static final String ERROR = PREFIX + "Error"; //$NON-NLS-1$ |
| private static final String FORMAT_IS_INVALID = PREFIX + "Format_is_invalid"; //$NON-NLS-1$ |
| private static final String ADDRESS_IS_OUT_OF_RANGE = PREFIX + "Address_is_out_of_range"; //$NON-NLS-1$ |
| private static final String COLUMN_SIZE = PREFIX + "Column_size"; //$NON-NLS-1$ |
| //private static final String ADD_RENDERING = PREFIX + "Add_rendering"; //$NON-NLS-1$ |
| private static final String UNABLE_TO_GET_BASE_ADDRESS = PREFIX +"Unable_to_retrieve_base_address"; //$NON-NLS-1$ |
| private static final String UNKNOWN = PREFIX + "Unknown"; //$NON-NLS-1$ |
| |
| // menu group names |
| private static final String MEMORY_ACTIONS_GROUP = IDebugUIConstants.PLUGIN_ID + ".MemoryViewActionsGroup"; //$NON-NLS-1$ |
| private static final String MEMORY_ACTIONS_FORMAT_GROUP = IDebugUIConstants.PLUGIN_ID + ".MemoryViewActionsGroup.format"; //$NON-NLS-1$ |
| //private static final String MEMORY_ACTIONS_RENDERING_GROUP = IDebugUIConstants.PLUGIN_ID + ".MemoryViewActionsGroup.rendering"; //$NON-NLS-1$ |
| |
| private MemoryViewContentProvider contentProvider; |
| private TableViewer fTableViewer = null; |
| private boolean fEnabled; |
| private ViewTabCursorManager fCursorManager; |
| |
| private IMemoryBlockModelPresentation fMemoryBlockPresentation; |
| private boolean fNoPresentation = false; |
| |
| public int TABLE_PREBUFFER = 20; |
| public int TABLE_POSTBUFFER = 20; |
| public int TABLE_DEFAULTBUFFER = 20; |
| |
| private TextViewer fTextViewer = null; |
| private boolean errorOccurred = false; |
| |
| protected BigInteger fSelectedAddress = null; |
| |
| private boolean fTabCreated = false; |
| |
| private CellEditor fEditors[]; |
| private ICellModifier fCellModifier; |
| |
| private CopyViewTabToClipboardAction fCopyToClipboardAction; |
| private GoToAddressAction fGoToAddressAction; |
| private ResetMemoryBlockAction fResetMemoryBlockAction; |
| private PrintViewTabAction fPrintViewTabAction; |
| private Action[] fFormatColumnActions; |
| private ReformatAction fReformatAction; |
| |
| private boolean fIsDisposed = false; |
| |
| private int fBytePerLine; // number of bytes per line: 16 |
| private int fColumnSize; // number of bytes per column: 1,2,4,8 |
| |
| // font change listener |
| private FontChangeListener fFontChangeListener; |
| private TabFolderDisposeListener fTabFolderDisposeListener; |
| |
| private static final int[] ignoreEvents = |
| { |
| SWT.ARROW_UP, |
| SWT.ARROW_DOWN, |
| SWT.ARROW_LEFT, |
| SWT.ARROW_RIGHT, |
| SWT.PAGE_UP, |
| SWT.PAGE_DOWN, |
| SWT.HOME, |
| SWT.END, |
| SWT.INSERT, |
| SWT.F1, |
| SWT.F2, |
| SWT.F3, |
| SWT.F4, |
| SWT.F5, |
| SWT.F6, |
| SWT.F7, |
| SWT.F8, |
| SWT.F9, |
| SWT.F10, |
| SWT.F11, |
| SWT.F12, |
| SWT.F13, |
| SWT.F14, |
| SWT.F15, |
| SWT.HELP, |
| SWT.CAPS_LOCK, |
| SWT.NUM_LOCK, |
| SWT.SCROLL_LOCK, |
| SWT.PAUSE, |
| SWT.BREAK, |
| SWT.PRINT_SCREEN, |
| SWT.ESC, |
| SWT.CTRL, |
| SWT.ALT |
| }; |
| |
| private final class TabFolderDisposeListener implements DisposeListener |
| { |
| MemoryViewTab fViewTab; |
| TabFolderDisposeListener(MemoryViewTab viewTab) |
| { |
| fViewTab = viewTab; |
| } |
| |
| public void widgetDisposed(DisposeEvent e) |
| { |
| if (!fViewTab.fIsDisposed) |
| { |
| // remove listeners |
| JFaceResources.getFontRegistry().removeListener(fFontChangeListener); |
| removeReferenceFromSynchronizer(); |
| getMemoryBlockViewSynchronizer().removeView(fViewTab); |
| } |
| } |
| } |
| |
| class FontChangeListener implements IPropertyChangeListener |
| { |
| /* (non-Javadoc) |
| * @see org.eclipse.jface.util.IPropertyChangeListener#propertyChange(org.eclipse.jface.util.PropertyChangeEvent) |
| */ |
| public void propertyChange(PropertyChangeEvent event) |
| { |
| // if memory view table font has changed |
| if (event.getProperty().equals(IInternalDebugUIConstants.FONT_NAME)) |
| { |
| if (!fIsDisposed) |
| { |
| Font memoryViewFont = JFaceResources.getFont(IInternalDebugUIConstants.FONT_NAME); |
| setFont(memoryViewFont); |
| } |
| } |
| } |
| } |
| |
| // ** Referring to internal class: DelegatingModelPresentation and LazyModelPresentation |
| // ** This should be ok when Memory View is contributed to Eclipse platform? |
| class MemoryViewDelegatingModelPresentation extends DelegatingModelPresentation |
| { |
| |
| MemoryViewDelegatingModelPresentation() |
| { |
| IExtensionPoint point= Platform.getExtensionRegistry().getExtensionPoint(DebugUIPlugin.getUniqueIdentifier(), IDebugUIConstants.ID_DEBUG_MODEL_PRESENTATION); |
| if (point != null) { |
| IExtension[] extensions= point.getExtensions(); |
| for (int i= 0; i < extensions.length; i++) { |
| IExtension extension= extensions[i]; |
| IConfigurationElement[] configElements= extension.getConfigurationElements(); |
| for (int j= 0; j < configElements.length; j++) { |
| IConfigurationElement elt= configElements[j]; |
| String id= elt.getAttribute("id"); //$NON-NLS-1$ |
| if (id != null) { |
| IDebugModelPresentation lp= new MemoryViewLazyModelPresentation(elt); |
| getLabelProviders().put(id, lp); |
| } |
| } |
| } |
| } |
| } |
| |
| } |
| |
| class MemoryViewLazyModelPresentation extends LazyModelPresentation implements IMemoryBlockModelPresentation |
| { |
| |
| MemoryViewLazyModelPresentation(IConfigurationElement element) |
| { |
| super(element); |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.debug.ui.IMemoryBlockModelPresentation#getTabLabel(org.eclipse.debug.core.model.IMemoryBlock) |
| */ |
| public String getTabLabel(IMemoryBlock blk, String renderingId) |
| { |
| IDebugModelPresentation presentation = getPresentation(); |
| |
| if (presentation instanceof IMemoryBlockModelPresentation) |
| { |
| return ((IMemoryBlockModelPresentation)presentation).getTabLabel(blk, getRenderingId()); |
| } |
| else |
| { |
| return null; |
| } |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.debug.ui.IMemoryBlockModelPresentation#getColumnLabels(org.eclipse.debug.core.model.IMemoryBlock, int, int) |
| */ |
| public String[] getColumnLabels(IMemoryBlock blk, int bytesPerLine, int columnSize) |
| { |
| IDebugModelPresentation presentation = getPresentation(); |
| |
| if (presentation instanceof IMemoryBlockModelPresentation) |
| { |
| return ((IMemoryBlockModelPresentation)presentation).getColumnLabels(blk, bytesPerLine, columnSize); |
| } |
| else |
| { |
| return new String[0]; |
| } |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.debug.ui.IMemoryBlockModelPresentation#getAddressPresentation(org.eclipse.debug.core.model.IMemoryBlock, java.math.BigInteger) |
| */ |
| public String getAddressPresentation(IMemoryBlock blk, BigInteger address) |
| { |
| IDebugModelPresentation presentation = getPresentation(); |
| |
| if (presentation instanceof IMemoryBlockModelPresentation) |
| { |
| return ((IMemoryBlockModelPresentation)presentation).getAddressPresentation(blk, address); |
| } |
| else |
| { |
| return null; |
| } |
| } |
| } |
| |
| public MemoryViewTab(IMemoryBlock newMemory, TabItem newTab, MenuManager menuMgr, IMemoryRendering rendering, AbstractMemoryRenderer renderer) { |
| super(newMemory, newTab, menuMgr, rendering); |
| |
| setTabName(newMemory, true); |
| |
| fTabItem.setControl(createFolderPage(renderer)); |
| |
| if (!(newMemory instanceof IExtendedMemoryBlock)) |
| { |
| // If not extended memory block, do not create any buffer |
| // no scrolling |
| TABLE_PREBUFFER=0; |
| TABLE_POSTBUFFER=0; |
| TABLE_DEFAULTBUFFER=0; |
| } |
| |
| if (fTableViewer != null) |
| { |
| fTableViewer.getTable().setTopIndex(TABLE_PREBUFFER); |
| } |
| |
| addViewTabToSynchronizer(); |
| |
| // otherwise, this is a totally new synchronize info |
| |
| fEnabled = true; |
| fTabCreated = true; |
| |
| //synchronize |
| synchronize(); |
| |
| createActions(); |
| |
| // Need to resize column after content is filled in |
| // Pack function does not work unless content is not filled in |
| // since the table is not able to compute the preferred size. |
| packColumns(); |
| |
| // add listeners in the end to make sure that the resize event |
| // does not affect synchronization |
| if (fTableViewer != null){ |
| fTableViewer.getTable().addSelectionListener(this); |
| fTabFolderDisposeListener = new TabFolderDisposeListener(this); |
| fTabItem.addDisposeListener(fTabFolderDisposeListener); |
| } |
| |
| if (fMemoryBlock instanceof IExtendedMemoryBlock) |
| { |
| if(((IExtendedMemoryBlock)fMemoryBlock).getBigBaseAddress() == null) |
| { |
| DebugException e = new DebugException(DebugUIPlugin.newErrorStatus(DebugUIMessages.getString(UNABLE_TO_GET_BASE_ADDRESS), null)); |
| displayError(e); |
| } |
| } |
| } |
| |
| private void addViewTabToSynchronizer() |
| { |
| getMemoryBlockViewSynchronizer().addView(this, null); |
| |
| // check if there is already synchronization info available |
| Object selectedAddress =getSynchronizedProperty( IMemoryViewConstants.PROPERTY_SELECTED_ADDRESS); |
| Object size =getSynchronizedProperty( IMemoryViewConstants.PROPERTY_COL_SIZE); |
| Object topAddress =getSynchronizedProperty( IMemoryViewConstants.PROPERTY_TOP_ADDRESS); |
| |
| // if info is available, some other view tab has already been created |
| // do not overwirte info int he synchronizer if that's the case |
| if (selectedAddress == null) |
| { |
| updateSyncSelectedAddress(true); |
| } |
| |
| if (size == null) |
| { |
| updateSyncColSize(); |
| } |
| if (topAddress == null) |
| { |
| updateSyncTopAddress(true); |
| } |
| |
| } |
| |
| /** |
| * update selected address in synchronizer if update is true. |
| */ |
| private void updateSyncSelectedAddress(boolean update) { |
| |
| if (update) |
| getMemoryBlockViewSynchronizer().setSynchronizedProperty(getMemoryBlock(), IMemoryViewConstants.PROPERTY_SELECTED_ADDRESS, fSelectedAddress); |
| } |
| |
| /** |
| * update column size in synchronizer |
| */ |
| private void updateSyncColSize() { |
| getMemoryBlockViewSynchronizer().setSynchronizedProperty(getMemoryBlock(), IMemoryViewConstants.PROPERTY_COL_SIZE, new Integer(fColumnSize)); |
| } |
| |
| /** |
| * update top visible address in synchronizer |
| */ |
| protected void updateSyncTopAddress(boolean updateToSynchronizer) { |
| |
| if (updateToSynchronizer) |
| { |
| getMemoryBlockViewSynchronizer().setSynchronizedProperty(getMemoryBlock(), IMemoryViewConstants.PROPERTY_TOP_ADDRESS, getTopVisibleAddress()); |
| } |
| } |
| |
| protected void setTabName(IMemoryBlock newMemory, boolean showAddress) |
| { |
| String tabName = null; |
| |
| if (getMemoryBlockPresentation() != null) |
| tabName = getMemoryBlockPresentation().getTabLabel(newMemory, getRenderingId()); |
| |
| if (tabName == null) |
| { |
| |
| tabName = ""; //$NON-NLS-1$ |
| try { |
| if (newMemory instanceof IExtendedMemoryBlock) |
| { |
| tabName = ((IExtendedMemoryBlock)newMemory).getExpression(); |
| |
| if (tabName.startsWith("&")) //$NON-NLS-1$ |
| tabName = "&" + tabName; //$NON-NLS-1$ |
| |
| if (tabName == null) |
| { |
| tabName = DebugUIMessages.getString(UNKNOWN); |
| } |
| |
| if (showAddress && ((IExtendedMemoryBlock)newMemory).getBigBaseAddress() != null) |
| { |
| tabName += " : 0x"; //$NON-NLS-1$ |
| tabName += ((IExtendedMemoryBlock)newMemory).getBigBaseAddress().toString(16); |
| } |
| } |
| else |
| { |
| long address = newMemory.getStartAddress(); |
| tabName = Long.toHexString(address); |
| } |
| } catch (DebugException e) { |
| tabName = DebugUIMessages.getString(UNKNOWN); |
| DebugUIPlugin.log(e.getStatus()); |
| } |
| |
| String preName = MemoryBlockManager.getMemoryRenderingManager().getRenderingInfo(getRenderingId()).getName(); |
| |
| if (preName != null) |
| tabName += " <" + preName + ">"; //$NON-NLS-1$ //$NON-NLS-2$ |
| |
| } |
| fTabItem.setText(tabName); |
| } |
| |
| |
| /** |
| * Create actions for the view tab |
| */ |
| protected void createActions() { |
| fCopyToClipboardAction = new CopyViewTabToClipboardContextAction(this); |
| fGoToAddressAction = new GoToAddressAction(this); |
| fResetMemoryBlockAction = new ResetMemoryBlockContextAction(this); |
| fPrintViewTabAction = new PrintViewTabContextAction(this); |
| |
| fFormatColumnActions = new Action[6]; |
| fFormatColumnActions[0] = new FormatColumnAction(1, this); |
| fFormatColumnActions[1] = new FormatColumnAction(2, this); |
| fFormatColumnActions[2] = new FormatColumnAction(4, this); |
| fFormatColumnActions[3] = new FormatColumnAction(8, this); |
| fFormatColumnActions[4] = new FormatColumnAction(16, this); |
| fFormatColumnActions[5] = new SetColumnSizeDefaultAction(this); |
| |
| fReformatAction = new ReformatAction(this); |
| } |
| |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.debug.ui.IMemoryViewTab#fillContextMenu(org.eclipse.jface.action.IMenuManager) |
| */ |
| public void fillContextMenu(IMenuManager menu) { |
| |
| menu.add(new Separator(MEMORY_ACTIONS_GROUP)); |
| menu.add(fResetMemoryBlockAction); |
| menu.add(fGoToAddressAction); |
| |
| menu.add(new Separator()); |
| |
| if (fFormatColumnActions.length > 0) |
| { |
| // Format view tab actions |
| IMenuManager formatMenu = new MenuManager(DebugUIMessages.getString(COLUMN_SIZE), |
| MEMORY_ACTIONS_FORMAT_GROUP); |
| |
| menu.appendToGroup(MEMORY_ACTIONS_GROUP, formatMenu); |
| |
| for (int i=0; i<fFormatColumnActions.length; i++) |
| { |
| formatMenu.add(fFormatColumnActions[i]); |
| |
| // add check mark to the action to reflect current format of the view tab |
| if (fFormatColumnActions[i] instanceof FormatColumnAction) |
| { |
| if (((FormatColumnAction)fFormatColumnActions[i]).getColumnSize() == getColumnSize()) |
| { |
| fFormatColumnActions[i].setChecked(true); |
| } |
| else |
| { |
| fFormatColumnActions[i].setChecked(false); |
| } |
| } |
| } |
| } |
| |
| menu.add(new Separator()); |
| menu.add(fReformatAction); |
| menu.add(fCopyToClipboardAction); |
| menu.add(fPrintViewTabAction); |
| } |
| |
| private Control createFolderPage(AbstractMemoryRenderer renderer) { |
| |
| contentProvider = new MemoryViewContentProvider(fMemoryBlock, fTabItem); |
| fTableViewer= new TableViewer(fTabItem.getParent(), SWT.FULL_SELECTION | SWT.SINGLE | SWT.H_SCROLL | SWT.V_SCROLL | SWT.HIDE_SELECTION | SWT.BORDER); |
| fTableViewer.setContentProvider(contentProvider); |
| |
| if (renderer != null) |
| { |
| renderer.setRenderingId(fRenderingId); |
| MemoryViewTabLabelProvider labelProvider = new MemoryViewTabLabelProvider(this, renderer); |
| fTableViewer.setLabelProvider(labelProvider); |
| ((AbstractTableViewTabLabelProvider)labelProvider).setViewTab(this); |
| } |
| else |
| { |
| renderer = new EmptyRenderer(); |
| renderer.setRenderingId(fRenderingId); |
| renderer.setViewTab(this); |
| |
| MemoryViewTabLabelProvider labelProvider = new MemoryViewTabLabelProvider(this, renderer); |
| fTableViewer.setLabelProvider(labelProvider); |
| |
| DebugUIPlugin.log(DebugUIPlugin.newErrorStatus("Renderer property is not defined for: " + fRenderingId, null)); //$NON-NLS-1$ |
| } |
| |
| contentProvider.setViewer(fTableViewer); |
| |
| ScrollBar scroll = ((Table)fTableViewer.getControl()).getVerticalBar(); |
| scroll.addSelectionListener(this); |
| scroll.setMinimum(-100); |
| scroll.setMaximum(200); |
| |
| fTableViewer.getControl().addControlListener(this); |
| fTableViewer.getControl().addKeyListener(this); |
| |
| fTableViewer.getTable().setHeaderVisible(true); |
| fTableViewer.getTable().setLinesVisible(true); |
| |
| int bytePerLine = IInternalDebugUIConstants.BYTES_PER_LINE; |
| |
| // get default column size from preference store |
| IPreferenceStore prefStore = DebugUIPlugin.getDefault().getPreferenceStore(); |
| int columnSize = prefStore.getInt(IDebugPreferenceConstants.PREF_COLUMN_SIZE); |
| |
| // check synchronized col size |
| Integer colSize = (Integer)getSynchronizedProperty(IMemoryViewConstants.PROPERTY_COL_SIZE); |
| |
| if (colSize != null) |
| { |
| int syncColSize = colSize.intValue(); |
| if (syncColSize > 0) |
| { |
| columnSize = syncColSize; |
| } |
| } |
| |
| // format memory block with specified "bytesPerLine" and "columnSize" |
| boolean ok = format(bytePerLine, columnSize); |
| |
| if (!ok) |
| { |
| DebugException e = new DebugException(DebugUIPlugin.newErrorStatus(DebugUIMessages.getString(FORMAT_IS_INVALID), null)); |
| displayError(e); |
| return fTextViewer.getControl(); |
| } |
| |
| fTableViewer.setInput(fMemoryBlock); |
| |
| fCellModifier = new MemoryViewCellModifier(this); |
| fTableViewer.setCellModifier(fCellModifier); |
| |
| // set to a non-proportional font |
| fTableViewer.getTable().setFont(JFaceResources.getFont(IInternalDebugUIConstants.FONT_NAME)); |
| |
| int row = 0; |
| int col = 1; |
| |
| // set up cursor manager |
| // manager sets up initial position of the cursor |
| fCursorManager = new ViewTabCursorManager(this, row, col, fMenuMgr); |
| |
| if (fMemoryBlock instanceof IExtendedMemoryBlock) |
| { |
| BigInteger address = ((IExtendedMemoryBlock)fMemoryBlock).getBigBaseAddress(); |
| |
| if (address == null) |
| { |
| address = new BigInteger("0"); //$NON-NLS-1$ |
| } |
| |
| BigInteger syncAddress = (BigInteger)getSynchronizedProperty(IMemoryViewConstants.PROPERTY_SELECTED_ADDRESS); |
| |
| // set initial selected address |
| if (syncAddress != null) |
| { |
| setSelectedAddress(syncAddress, false); |
| } |
| else |
| { |
| setSelectedAddress(address, true); |
| } |
| updateCursorPosition(); |
| } |
| else |
| { |
| long address = fMemoryBlock.getStartAddress(); |
| BigInteger syncAddress = (BigInteger)getSynchronizedProperty(IMemoryViewConstants.PROPERTY_SELECTED_ADDRESS); |
| |
| if (syncAddress != null) |
| { |
| // set initial selected address |
| setSelectedAddress(syncAddress, false); |
| } |
| else |
| { |
| setSelectedAddress(BigInteger.valueOf(address), true); |
| } |
| updateCursorPosition(); |
| } |
| |
| // add font change listener and update font when the font has been changed |
| fFontChangeListener = new FontChangeListener(); |
| JFaceResources.getFontRegistry().addListener(fFontChangeListener); |
| |
| // finish initialization and return text viewer as the control |
| if (errorOccurred) |
| { |
| return fTextViewer.getControl(); |
| } |
| |
| return fTableViewer.getControl(); |
| } |
| |
| |
| /** |
| * Format view tab based on parameters. |
| * @param bytesPerLine - number of bytes per line, possible values: 16 |
| * @param columnSize - number of bytes per column, possible values: 1, 2, 4, 8 |
| * @return true if format is successful, false, otherwise |
| */ |
| public boolean format(int bytesPerLine, int columnSize) |
| { |
| // check parameter, bytesPerLine be 16 |
| if (bytesPerLine != IInternalDebugUIConstants.BYTES_PER_LINE) |
| { |
| return false; |
| } |
| // bytes per cell must be divisible to bytesPerLine |
| if (bytesPerLine % columnSize != 0) |
| { |
| return false; |
| } |
| |
| // do not format if the view tab is already in that format |
| if(fBytePerLine == bytesPerLine && fColumnSize == columnSize){ |
| return false; |
| } |
| |
| fBytePerLine = bytesPerLine; |
| fColumnSize = columnSize; |
| |
| // if the tab is already created and is being reformated |
| if (fTabCreated) |
| { |
| getTopVisibleAddress(); |
| |
| if (fTableViewer == null) |
| return false; |
| |
| if (fTableViewer.getTable() == null) |
| return false; |
| |
| // clean up old columns |
| TableColumn[] oldColumns = fTableViewer.getTable().getColumns(); |
| |
| for (int i=0; i<oldColumns.length; i++) |
| { |
| oldColumns[i].dispose(); |
| } |
| |
| // clean up old cell editors |
| CellEditor[] oldCellEditors = fTableViewer.getCellEditors(); |
| |
| for (int i=0; i<oldCellEditors.length; i++) |
| { |
| oldCellEditors[i].dispose(); |
| } |
| } |
| |
| TableColumn column0 = new TableColumn(fTableViewer.getTable(),SWT.LEFT,0); |
| column0.setText(DebugUIMessages.getString(ADDRESS)); |
| |
| // create new byte columns |
| TableColumn [] byteColumns = new TableColumn[bytesPerLine/columnSize]; |
| |
| String[] columnLabels = new String[0]; |
| if (getMemoryBlockPresentation() != null) |
| columnLabels = getMemoryBlockPresentation().getColumnLabels(getMemoryBlock(), bytesPerLine, columnSize); |
| |
| for (int i=0;i<byteColumns.length; i++) |
| { |
| TableColumn column = new TableColumn(fTableViewer.getTable(), SWT.LEFT, i+1); |
| |
| // if the number of column labels returned is correct |
| // use supplied column labels |
| if (columnLabels.length == byteColumns.length) |
| { |
| column.setText(columnLabels[i]); |
| } |
| else |
| { |
| // otherwise, use default |
| if (getColumnSize() >= 4) |
| { |
| column.setText(Integer.toHexString(i*columnSize).toUpperCase() + |
| " - " + Integer.toHexString(i*columnSize+columnSize-1).toUpperCase()); //$NON-NLS-1$ |
| } |
| else |
| { |
| column.setText(Integer.toHexString(i*columnSize).toUpperCase()); |
| } |
| } |
| } |
| |
| //Empty column for cursor navigation |
| TableColumn emptyCol = new TableColumn(fTableViewer.getTable(),SWT.LEFT,byteColumns.length+1); |
| emptyCol.setText(" "); //$NON-NLS-1$ |
| emptyCol.setWidth(1); |
| emptyCol.setResizable(false); |
| |
| // +2 to include properties for address and navigation column |
| String[] columnProperties = new String[byteColumns.length+2]; |
| columnProperties[0] = MemoryViewLine.P_ADDRESS; |
| |
| // use column beginning offset to the row address as properties |
| for (int i=1; i<columnProperties.length-1; i++) |
| { |
| columnProperties[i] = Integer.toHexString((i-1)*columnSize); |
| } |
| |
| // Empty column for cursor navigation |
| columnProperties[columnProperties.length-1] = " "; //$NON-NLS-1$ |
| |
| fTableViewer.setColumnProperties(columnProperties); |
| |
| // create and set cell editors |
| fTableViewer.setCellEditors(getCellEditors()); |
| |
| if (fTabCreated) |
| { |
| refreshTableViewer(); |
| |
| // after refresh, make sure cursor position is up-to-date |
| if (isAddressVisible(fSelectedAddress)) |
| updateCursorPosition(); |
| } |
| |
| packColumns(); |
| |
| updateSyncColSize(); |
| |
| return true; |
| } |
| |
| /** |
| * |
| */ |
| private void refreshTableViewer() { |
| |
| int i = fTableViewer.getTable().getTopIndex(); |
| |
| // refresh if the view is already created |
| fTableViewer.refresh(); |
| |
| // if top index has changed, restore it |
| if (i != fTableViewer.getTable().getTopIndex()) |
| fTableViewer.getTable().setTopIndex(i); |
| } |
| |
| private void setColumnHeadings() |
| { |
| String[] columnLabels = new String[0]; |
| |
| if (getMemoryBlockPresentation() != null) |
| columnLabels = getMemoryBlockPresentation().getColumnLabels(getMemoryBlock(), fBytePerLine, fColumnSize); |
| |
| int numByteColumns = fBytePerLine/fColumnSize; |
| |
| TableColumn[] columns = fTableViewer.getTable().getColumns(); |
| |
| int j=0; |
| for (int i=1; i<columns.length-1; i++) |
| { |
| // if the number of column labels returned is correct |
| // use supplied column labels |
| if (columnLabels.length == numByteColumns) |
| { |
| columns[i].setText(columnLabels[j]); |
| j++; |
| } |
| else |
| { |
| // otherwise, use default |
| if (fColumnSize >= 4) |
| { |
| columns[i].setText(Integer.toHexString(i*fColumnSize).toUpperCase() + |
| " - " + Integer.toHexString(i*fColumnSize+fColumnSize-1).toUpperCase()); //$NON-NLS-1$ |
| } |
| else |
| { |
| columns[i].setText(Integer.toHexString(i*fColumnSize).toUpperCase()); |
| } |
| } |
| } |
| } |
| |
| /** |
| * Resize column to the preferred size |
| */ |
| public void packColumns() { |
| // pack columns |
| Table table = fTableViewer.getTable(); |
| TableColumn[] columns = table.getColumns(); |
| |
| for (int i=0 ;i<columns.length-1; i++) |
| { |
| columns[i].pack(); |
| } |
| |
| if (fCursorManager != null) |
| { |
| if (isAddressVisible(fSelectedAddress)) |
| fCursorManager.redrawCursors(); |
| } |
| } |
| |
| /** |
| * @return tab item for the view tab |
| */ |
| protected TabItem getTab() |
| { |
| return fTabItem; |
| } |
| |
| /** |
| * Force focus on th ecursor if the selected address is not out of range |
| * Cursor cannot be shown if it's out of range. Otherwise, it messes up |
| * the top index of the table and affects scrolling. |
| */ |
| protected void setCursorFocus() |
| { |
| if (!isAddressOutOfRange(fSelectedAddress) && fCursorManager != null) |
| fCursorManager.setCursorFocus(); |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.debug.ui.IMemoryViewTab#getMemoryBlock() |
| */ |
| public IMemoryBlock getMemoryBlock() |
| { |
| IMemoryBlock mem = fMemoryBlock; |
| return mem; |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.ui.IWorkbenchPart#dispose() |
| */ |
| public void dispose() { |
| try { |
| fIsDisposed = true; |
| |
| // clean up listeners |
| if (fTableViewer != null) |
| { |
| fTableViewer.getControl().removeControlListener(this); |
| fTableViewer.getControl().removeKeyListener(this); |
| fTableViewer.getTable().removeSelectionListener(this); |
| } |
| |
| if (contentProvider != null) |
| contentProvider.dispose(); |
| |
| ScrollBar scroll = ((Table)fTableViewer.getControl()).getVerticalBar(); |
| |
| if (scroll != null) |
| scroll.removeSelectionListener(this); |
| |
| // dispose cursor |
| if (fCursorManager != null) |
| fCursorManager.dispose(); |
| |
| // remove selection listener for tab folder |
| fTabItem.removeDisposeListener(fTabFolderDisposeListener); |
| fTabItem.dispose(); |
| |
| fTextViewer = null; |
| fTableViewer = null; |
| |
| // clean up cell editors |
| for (int i=0; i<fEditors.length; i++) |
| { |
| fEditors[i].dispose(); |
| } |
| |
| // remove font change listener when the view tab is disposed |
| JFaceResources.getFontRegistry().removeListener(fFontChangeListener); |
| |
| // remove the view tab from the synchronizer |
| getMemoryBlockViewSynchronizer().removeView(this); |
| |
| super.dispose(); |
| |
| } catch (Exception e) {} |
| } |
| |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.swt.events.SelectionListener#widgetSelected(org.eclipse.swt.events.SelectionEvent) |
| */ |
| public void widgetSelected(SelectionEvent event) { |
| |
| if (event.getSource() instanceof ScrollBar) |
| { |
| handleScrollBarSelection(event); |
| } |
| } |
| |
| /** |
| * Based on cursor position, update table selection. |
| * If a lead cursor is not available, the cursor is not visible. |
| * Update will not be performed if the cursor is not visible. |
| */ |
| protected void updateTableSelection() |
| { |
| // do not update selection if address is out of range |
| // otherwise, screws up top index |
| if (isAddressOutOfRange(fSelectedAddress)) |
| return; |
| |
| int index = findAddressIndex(getTopVisibleAddress()); |
| |
| // update table selection |
| fTableViewer.getTable().setSelection(fCursorManager.fRow); |
| |
| // if top index has changed, restore |
| if (fTableViewer.getTable().getTopIndex() != index) |
| fTableViewer.getTable().setTopIndex(index); |
| } |
| |
| /** |
| * Calculate and set selected address based on provided row and column |
| */ |
| protected void updateSelectedAddress(TableItem row, int col) |
| { |
| |
| // get row address |
| String temp = ((MemoryViewLine)row.getData()).getAddress(); |
| BigInteger rowAddress = new BigInteger(temp, 16); |
| |
| int offset; |
| if (col > 0) |
| { |
| // get address offset |
| offset = (col-1) * getColumnSize(); |
| } |
| else |
| { |
| offset = 0; |
| } |
| |
| // update selected address |
| setSelectedAddress(rowAddress.add(BigInteger.valueOf(offset)), true); |
| } |
| |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.swt.events.SelectionListener#widgetDefaultSelected(org.eclipse.swt.events.SelectionEvent) |
| */ |
| public void widgetDefaultSelected(SelectionEvent e) { |
| |
| |
| } |
| |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.swt.events.ControlListener#controlMoved(org.eclipse.swt.events.ControlEvent) |
| */ |
| public void controlMoved(ControlEvent e) { |
| |
| |
| } |
| |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.swt.events.ControlListener#controlResized(org.eclipse.swt.events.ControlEvent) |
| */ |
| public void controlResized(ControlEvent e) { |
| //this method gets called many times as the user drags the window to a new size |
| //TODO: only refresh the data at the end of the resize, if possible |
| |
| // do not handle resize if the tab is not yet created completely |
| if (fTabCreated) |
| resizeTable(); |
| |
| } |
| |
| /** |
| * Handles key events in viewer. |
| */ |
| protected void handleKeyPressed(KeyEvent evt) { |
| |
| final KeyEvent event = evt; |
| |
| // Must run on UI Thread asynchronously |
| // Otherwise, another event could have been recevied before the reload is completed |
| Display.getDefault().syncExec(new Runnable() |
| { |
| public void run() |
| { |
| if (event.stateMask != 0) |
| { |
| return; |
| } |
| |
| if (event.getSource() instanceof Text) |
| return; |
| |
| // allow edit if user hits return |
| if (event.character == '\r' && event.getSource() instanceof TableCursor) |
| { |
| fCursorManager.activateCellEditor(null); |
| return; |
| } |
| |
| try |
| { |
| switch (event.keyCode) |
| { |
| case SWT.HOME : |
| case SWT.PAGE_UP : |
| case SWT.ARROW_UP : |
| case SWT.ARROW_LEFT: |
| case SWT.END : |
| case SWT.PAGE_DOWN : |
| case SWT.ARROW_DOWN : |
| case SWT.ARROW_RIGHT: |
| // If blocking an extended memory block, |
| // check to see if additional memory needs to be obtained. |
| if (fMemoryBlock instanceof IExtendedMemoryBlock) |
| { |
| // User could have used scroll bar to scroll away |
| // from the highlighted address. |
| // When user hits arrow keys or page up/down keys |
| // we should go back to the selected address and moves the cursor |
| // based on the key pressed. |
| if (isAddressOutOfRange(fSelectedAddress)) |
| { |
| reloadTable(fSelectedAddress, false); |
| |
| updateSyncTopAddress(true); |
| updateSyncSelectedAddress(true); |
| |
| fCursorManager.setCursorFocus(); |
| break; |
| } |
| //if we are approaching the limits of the currently loaded memory, reload the table |
| if (needMoreLines()) |
| { |
| BigInteger topAddress = getTopVisibleAddress(); |
| //if we're near 0, just go there immediately (hard stop at 0, don't try to scroll/wrap) |
| if (topAddress.compareTo(BigInteger.valueOf(96)) <= 0) |
| { |
| if (topAddress.equals(BigInteger.valueOf(0))) |
| { |
| // do not reload if we are already at zero |
| break; |
| } |
| reloadTable(BigInteger.valueOf(0), false); |
| fCursorManager.setCursorFocus(); |
| } |
| else |
| { |
| //otherwise, just load the next portion of the memory |
| reloadTable(topAddress, false); |
| fCursorManager.setCursorFocus(); |
| } |
| } |
| else if (!isAddressVisible(fSelectedAddress)) |
| { |
| // address is in range, but not visible |
| // just go to the address and make sure |
| // that the cursor is in focus |
| |
| goToAddress(fSelectedAddress); |
| fCursorManager.setCursorFocus(); |
| updateSyncTopAddress(true); |
| |
| } |
| else |
| { |
| // in place of the commented lines |
| updateCursorPosition(); |
| fCursorManager.setCursorFocus(); |
| // since cursor is going to be visible |
| // synchronization event will be fired by the cursor |
| // when it is selected |
| } |
| } |
| |
| break; |
| default : |
| |
| // if it's a valid key for edit |
| if (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); |
| fCursorManager.activateCellEditor(initialValue); |
| } |
| } |
| break; |
| } |
| } |
| catch (DebugException e) |
| { |
| displayError(e); |
| DebugUIPlugin.log(e.getStatus()); |
| } |
| } |
| }); |
| } |
| |
| /** |
| * @return top visible address of this view tab |
| */ |
| public BigInteger getTopVisibleAddress() { |
| |
| if (fTableViewer == null) |
| return BigInteger.valueOf(0); |
| |
| Table table = fTableViewer.getTable(); |
| int topIndex = table.getTopIndex(); |
| |
| if (topIndex < 1) { topIndex = 0; } |
| |
| if (table.getItemCount() > topIndex) |
| { |
| MemoryViewLine topItem = (MemoryViewLine)table.getItem(topIndex).getData(); |
| |
| String calculatedAddress = null; |
| if (topItem == null) |
| { |
| calculatedAddress = table.getItem(topIndex).getText(); |
| } |
| else |
| { |
| calculatedAddress = topItem.getAddress(); |
| } |
| |
| BigInteger bigInt = new BigInteger(calculatedAddress, 16); |
| |
| return bigInt; |
| } |
| else |
| { |
| return BigInteger.valueOf(0); |
| } |
| } |
| |
| /** |
| * Reload table at the topAddress. |
| * Delta will be re-computed if updateDelta is true. |
| * @param topAddress |
| * @param updateDelta |
| * @throws DebugException |
| */ |
| synchronized protected void reloadTable(BigInteger topAddress, boolean updateDelta) throws DebugException{ |
| |
| if (fTableViewer == null) |
| return; |
| |
| Table table = (Table)fTableViewer.getControl(); |
| |
| // Calculate top buffer address |
| // This is where we will start asking for memory from debug adapter. |
| BigInteger topBufferAddress = topAddress; |
| if (topBufferAddress.compareTo(BigInteger.valueOf(32)) <= 0) { |
| TABLE_PREBUFFER = 0; |
| } else { |
| TABLE_PREBUFFER = topBufferAddress.divide(BigInteger.valueOf(32)).min(BigInteger.valueOf(TABLE_DEFAULTBUFFER)).intValue(); |
| } |
| |
| topBufferAddress = topAddress.subtract(BigInteger.valueOf(getBytesPerLine()*TABLE_PREBUFFER)); |
| |
| // calculate number of lines needed |
| long numLines = 0; |
| if (fMemoryBlock instanceof IExtendedMemoryBlock) |
| { |
| // number of lines is number of visible lines + buffered lines |
| numLines = getNumberOfVisibleLines()+TABLE_PREBUFFER+TABLE_POSTBUFFER; |
| } |
| |
| |
| // tell content provider to get memory and refresh |
| contentProvider.getMemoryToFitTable(topBufferAddress, numLines, updateDelta); |
| contentProvider.forceRefresh(); |
| |
| |
| if (fMemoryBlock instanceof IExtendedMemoryBlock) |
| { |
| int topIdx = findAddressIndex(topAddress); |
| |
| if (topIdx != -1) |
| { |
| table.setTopIndex(topIdx); |
| } |
| |
| // TODO: Revisit this part again |
| // if allow cursor update when the cursor is |
| // not visible, causes flashing on the screen |
| // if not updated... then cursor may not |
| // show properly (table selection not hidden) |
| // if selected address is not out of range |
| // restore cursor |
| if (isAddressVisible(fSelectedAddress) && findAddressIndex(fSelectedAddress) != -1) |
| { |
| getTopVisibleAddress(); |
| getTopVisibleAddress().add(BigInteger.valueOf(getBytesPerLine()*getNumberOfVisibleLines())); |
| |
| // if the cursor is not visible but in buffered range |
| // updating and showing the cursor will move the top index of the table |
| updateCursorPosition(); |
| |
| int newIdx = findAddressIndex(getTopVisibleAddress()); |
| |
| if (newIdx != topIdx && topIdx != -1) |
| { |
| table.setTopIndex(topIdx); |
| } |
| |
| if (isAddressVisible(fSelectedAddress)) |
| { |
| fCursorManager.showCursor(); |
| } |
| else |
| { |
| fCursorManager.hideCursor(); |
| } |
| } |
| else |
| { |
| fCursorManager.hideCursor(); |
| } |
| } |
| |
| // try to display the table every time it's reloaded |
| displayTable(); |
| } |
| |
| private int findAddressIndex(BigInteger address) |
| { |
| TableItem items[] = fTableViewer.getTable().getItems(); |
| |
| for (int i=0; i<items.length; i++){ |
| |
| // Again, when the table resizes, the table may have a null item |
| // at then end. This is to handle that. |
| if (items[i] != null) |
| { |
| MemoryViewLine line = (MemoryViewLine)items[i].getData(); |
| BigInteger lineAddress = new BigInteger(line.getAddress(), 16); |
| BigInteger endLineAddress = lineAddress.add(BigInteger.valueOf(getBytesPerLine())); |
| |
| if (lineAddress.compareTo(address) <= 0 && endLineAddress.compareTo(address) > 0) |
| { |
| return i; |
| } |
| } |
| } |
| |
| return -1; |
| } |
| |
| /** |
| * Update cursor position based on selected address. |
| * @return true if cursor is visible, false otherwise |
| */ |
| private boolean updateCursorPosition() |
| { |
| // selected address is out of range, simply return false |
| if (fSelectedAddress.compareTo(contentProvider.getBufferTopAddress()) < 0) |
| return false; |
| |
| // calculate selected row address |
| int numOfRows = fSelectedAddress.subtract(contentProvider.getBufferTopAddress()).intValue()/getBytesPerLine(); |
| BigInteger rowAddress = contentProvider.getBufferTopAddress().add(BigInteger.valueOf(numOfRows * getBytesPerLine())); |
| |
| // try to find the row of the selected address |
| int row = findAddressIndex(fSelectedAddress); |
| |
| if (row == -1) |
| { |
| return false; |
| } |
| |
| // calculate offset to the row address |
| BigInteger offset = fSelectedAddress.subtract(rowAddress); |
| |
| // locate column |
| int col = ((offset.intValue()/getColumnSize())+1); |
| |
| // setting cursor selection or table selection changes |
| // the top index of the table... and may mess up top index in the talbe |
| // save up old top index |
| int oldTop = fTableViewer.getTable().getTopIndex(); |
| |
| // update cursor position and table selection |
| fCursorManager.updateCursorPosition(row, col, isAddressVisible(fSelectedAddress)); |
| updateTableSelection(); |
| |
| // reset top index to make sure the table is not moved |
| fTableViewer.getTable().setTopIndex(oldTop); |
| |
| if (isAddressVisible(fSelectedAddress)) |
| { |
| fCursorManager.showCursor(); |
| fTableViewer.getTable().deselectAll(); |
| } |
| else |
| fCursorManager.hideCursor(); |
| |
| return true; |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.debug.ui.ITableMemoryViewTab#getNumberOfVisibleLines() |
| */ |
| public int getNumberOfVisibleLines() |
| { |
| if(fTableViewer == null) |
| return -1; |
| |
| Table table = fTableViewer.getTable(); |
| int height = fTableViewer.getTable().getSize().y; |
| |
| // when table is not yet created, height is zero |
| if (height == 0) |
| { |
| // make use of the table viewer to estimate table size |
| height = fTableViewer.getTable().getParent().getSize().y; |
| } |
| |
| // height of border |
| int border = fTableViewer.getTable().getHeaderHeight(); |
| |
| // height of scroll bar |
| int scroll = fTableViewer.getTable().getHorizontalBar().getSize().y; |
| |
| // height of table is table's area minus border and scroll bar height |
| height = height-border-scroll; |
| |
| // calculate number of visible lines |
| int lineHeight = table.getItemHeight(); |
| |
| int numberOfLines = height/lineHeight; |
| |
| return numberOfLines; |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.debug.ui.IMemoryViewTab#refresh() |
| */ |
| public void refresh() |
| { |
| try { |
| |
| // refresh at start address of this memory block |
| // address may change if expression is evaluated to a different value |
| IMemoryBlock mem = fMemoryBlock; |
| BigInteger address; |
| |
| if (mem instanceof IExtendedMemoryBlock) |
| { |
| address = ((IExtendedMemoryBlock)mem).getBigBaseAddress(); |
| |
| if (address == null) |
| { |
| DebugException e = new DebugException(DebugUIPlugin.newErrorStatus(DebugUIMessages.getString(UNABLE_TO_GET_BASE_ADDRESS), null)); |
| displayError(e); |
| return; |
| } |
| |
| setTabName(mem, true); |
| |
| // base address has changed |
| if (address.compareTo(contentProvider.getContentBaseAddress()) != 0) |
| { |
| // get to new address |
| reloadTable(address, true); |
| } |
| else |
| { |
| // reload at top of table |
| // address = contentProvider.getBufferTopAddress().add(BigInteger.valueOf(getBytesPerLine()*TABLE_PREBUFFER)); |
| address = getTopVisibleAddress(); |
| reloadTable(address, true); |
| } |
| } |
| else |
| { |
| address = BigInteger.valueOf(mem.getStartAddress()); |
| reloadTable(address, true); |
| } |
| |
| if (isAddressVisible(fSelectedAddress)) |
| { |
| // redraw cursors if cursor is visible |
| getCursorManager().redrawCursors(); |
| } |
| |
| } catch (DebugException e) { |
| displayError(e); |
| DebugUIPlugin.log(e.getStatus()); |
| } |
| } |
| |
| /** |
| * Handle resize of the table. |
| */ |
| private void resizeTable() { |
| |
| if (!(fMemoryBlock instanceof IExtendedMemoryBlock)) |
| return; |
| |
| if (!isEnabled()) |
| return; |
| |
| Display.getDefault().syncExec(new Runnable() |
| { |
| public void run() |
| { |
| boolean reloaded = false; |
| |
| // this code is is running on the UI thread with a delay |
| // The view tab may have been disposed when this actually gets executed. |
| if (fTableViewer == null) |
| return; |
| |
| Table table = fTableViewer.getTable(); |
| |
| // make sure table is still valid |
| if (table.isDisposed()) |
| return; |
| |
| int topIndex = table.getTopIndex(); |
| if (topIndex < 0) |
| { |
| return; |
| } |
| BigInteger oldTopAddress = getTopVisibleAddress(); |
| if (oldTopAddress.compareTo(BigInteger.valueOf(32)) <= 0) |
| { |
| TABLE_PREBUFFER = 0; |
| } |
| else |
| { |
| TABLE_PREBUFFER = |
| oldTopAddress.divide(BigInteger.valueOf(32)).min(BigInteger.valueOf(TABLE_DEFAULTBUFFER)).intValue(); |
| } |
| |
| // check pre-condition before we can check on number of lines left in the table |
| if (table.getItemCount() > topIndex) |
| { |
| try |
| { |
| //if new window size exceeds the number of lines available in the table, reload the table |
| if (needMoreLines()) |
| { |
| reloadTable(oldTopAddress, false); |
| reloaded = true; |
| } |
| if (oldTopAddress.compareTo(BigInteger.valueOf(96)) <= 0) |
| { |
| reloadTable(BigInteger.valueOf(0), false); |
| reloaded = true; |
| } |
| } |
| catch (DebugException e) |
| { |
| displayError(e); |
| DebugUIPlugin.log(e.getStatus()); |
| } |
| } |
| |
| if (!reloaded){ |
| // if not reload, still need to update the cursor position |
| // since the position may change |
| |
| updateCursorPosition(); |
| fTableViewer.getTable().deselectAll(); |
| |
| if (!getTopVisibleAddress().equals(oldTopAddress)) |
| { |
| int i = findAddressIndex(oldTopAddress); |
| |
| if (i != -1) |
| fTableViewer.getTable().setTopIndex(i); |
| } |
| } |
| |
| updateSyncTopAddress(true); |
| } |
| }); |
| } |
| |
| /** |
| * Handle scrollling and reload table if necessary |
| * @param event |
| */ |
| private void handleScrollBarSelection(SelectionEvent event) |
| { |
| if (!(fMemoryBlock instanceof IExtendedMemoryBlock)) |
| { |
| // if not instance of extended memory block |
| // just get current top visible address and fire event |
| |
| updateSyncTopAddress(true); |
| |
| } |
| |
| final SelectionEvent evt = event; |
| |
| // Must run on UI Thread asynchronously |
| // Otherwise, another event could have been recevied before the reload is completed |
| Display.getDefault().asyncExec(new Runnable() |
| { |
| public void run() |
| { |
| try |
| { |
| switch (evt.detail) |
| { |
| case 0 : //the end of a drag |
| case SWT.END : |
| case SWT.PAGE_DOWN : |
| case SWT.ARROW_DOWN : |
| case SWT.HOME : |
| case SWT.PAGE_UP : |
| case SWT.ARROW_UP : |
| if (fMemoryBlock instanceof IExtendedMemoryBlock) |
| { |
| updateSyncTopAddress(true); |
| //if we are approaching the limits of the currently loaded memory, reload the table |
| if (needMoreLines()) |
| { |
| BigInteger topAddress = getTopVisibleAddress(); |
| //if we're near 0, just go there immediately (hard stop at 0, don't try to scroll/wrap) |
| if (topAddress.compareTo(BigInteger.valueOf(96)) <= 0) |
| { |
| if (topAddress.equals(BigInteger.valueOf(0))) |
| { |
| // do not reload if we are already at zero |
| break; |
| } |
| reloadTable(BigInteger.valueOf(0), false); |
| } |
| else |
| { |
| |
| //otherwise, just load the next portion of the memory |
| reloadTable(topAddress, false); |
| } |
| } |
| } |
| if (isAddressVisible(fSelectedAddress)) |
| { |
| updateCursorPosition(); |
| fCursorManager.setCursorFocus(); |
| } |
| break; |
| default: |
| break; |
| } |
| } |
| catch (DebugException e) |
| { |
| displayError(e); |
| DebugUIPlugin.log(e.getStatus()); |
| } |
| } |
| }); |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.debug.ui.IMemoryViewTab#setEnabled(boolean) |
| */ |
| public void setEnabled(boolean enable) |
| { |
| super.setEnabled(enable); |
| |
| fEnabled = enable; |
| IMemoryBlock mem = fMemoryBlock; |
| |
| if (fEnabled) |
| { |
| BigInteger oldBase = contentProvider.getContentBaseAddress(); |
| |
| // debug adapter may ignore the enable request |
| // some adapter does not block memory and may not do anything |
| // with the enable/disable request |
| // As a result, we need to force a refresh |
| // and to make sure content is updated |
| refresh(); |
| |
| if (mem instanceof IExtendedMemoryBlock) |
| { |
| BigInteger baseAddress = ((IExtendedMemoryBlock)mem).getBigBaseAddress(); |
| |
| if (baseAddress == null) |
| { |
| baseAddress = new BigInteger("0"); //$NON-NLS-1$ |
| } |
| |
| ArrayList references = (ArrayList)getSynchronizedProperty(IMemoryViewConstants.PROPERTY_ENABLED_REFERENCES); |
| |
| // if the base address has changed, update cursor |
| // and this is the first time this memory block is enabled |
| if (!baseAddress.equals(oldBase) && references.size() == 1) |
| { |
| setSelectedAddress(baseAddress, true); |
| updateCursorPosition(); |
| |
| updateSyncTopAddress(true); |
| updateSyncSelectedAddress(true); |
| } |
| else |
| { |
| // otherwise, take synchronized settings |
| synchronize(); |
| } |
| } |
| else |
| { |
| synchronize(); |
| } |
| } |
| else |
| { |
| if (mem instanceof IExtendedMemoryBlock) |
| { |
| setTabName(mem, false); |
| } |
| |
| // once the view tab is disabled, all deltas information becomes invalid. |
| // reset changed information and recompute if data has really changed when |
| // user revisits the same tab. |
| contentProvider.resetDeltas(); |
| } |
| } |
| public boolean isEnabled() |
| { |
| return fEnabled; |
| } |
| |
| /** |
| * Display an error in the view tab. |
| * Make use of the text viewer instead of the table viewer. |
| * @param e |
| */ |
| protected void displayError(DebugException e) |
| { |
| StyledText styleText = null; |
| errorOccurred = true; |
| |
| if (fTextViewer == null) |
| { |
| // create text viewer |
| fTextViewer = new TextViewer(fTabItem.getParent(), SWT.NONE); |
| fTabItem.setControl(fTextViewer.getControl()); |
| fTextViewer.setDocument(new Document()); |
| styleText = fTextViewer.getTextWidget(); |
| styleText.setEditable(false); |
| styleText.setEnabled(false); |
| } |
| else if (fTextViewer.getControl() != fTabItem.getControl()) |
| { |
| // switch to text viewer |
| fTabItem.setControl(fTextViewer.getControl()); |
| } |
| |
| styleText = fTextViewer.getTextWidget(); |
| |
| if (styleText != null) |
| styleText.setText(DebugUIMessages.getString(ERROR) + e); |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.debug.ui.IMemoryViewTab#isDisplayingError() |
| */ |
| public boolean isDisplayingError() |
| { |
| if(fTextViewer == null) |
| return false; |
| |
| if (fTabItem.getControl() == fTextViewer.getControl()) |
| return true; |
| else |
| return false; |
| } |
| |
| public void displayTable() |
| { |
| |
| if (fTableViewer!= null && fTabItem.getControl() != fTableViewer.getControl()) |
| { |
| errorOccurred = false; |
| fTabItem.setControl(fTableViewer.getControl()); |
| } |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.swt.events.KeyListener#keyPressed(org.eclipse.swt.events.KeyEvent) |
| */ |
| public void keyPressed(KeyEvent e) |
| { |
| handleKeyPressed(e); |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.swt.events.KeyListener#keyReleased(org.eclipse.swt.events.KeyEvent) |
| */ |
| public void keyReleased(KeyEvent e) |
| { |
| } |
| |
| /** |
| * @return cell editors for the table |
| */ |
| private CellEditor[] getCellEditors() { |
| Table table = fTableViewer.getTable(); |
| fEditors = new CellEditor[table.getColumnCount()]; |
| |
| for (int i=0; i<fEditors.length; i++) |
| { |
| fEditors[i] = new TextCellEditor(table); |
| } |
| |
| // combine the listener/validator interfaces so we can handle |
| // "editing" an address, which really skips the table to that address |
| // class CellValidatorListener implements ICellEditorValidator { |
| // TextCellEditor textEditor; |
| // boolean isAddressValidator; |
| // |
| // public CellValidatorListener(CellEditor cellEditor, boolean isAddress) { |
| // textEditor = (TextCellEditor)cellEditor; |
| // isAddressValidator = isAddress; |
| // } |
| // |
| // public String isValid(Object value) { |
| // if ((value instanceof String)) { |
| // if (((String)value).length() == 0) |
| // return null; //allow empty strings so hitting "delete" doesn't immediately pop up an error |
| // |
| // // make sure the character is 0-9ABCDEF only |
| // try { |
| // if (!isAddressValidator) { // don't validate address to allow input of variable in the address field |
| // BigInteger bigInt = new BigInteger((String)value, 16); |
| // } |
| // } catch (NumberFormatException ne) { |
| // return "not valid"; |
| // } |
| // } |
| // return null; |
| // } |
| // |
| // } |
| // |
| // //"editing" an address skips the table to that address |
| // |
| // for (int i=0; i<fEditors.length; i++) |
| // { |
| // fEditors[i].setValidator(new CellValidatorListener(fEditors[i], true)); |
| // } |
| |
| return fEditors; |
| } |
| |
| public TableViewer getTableViewer() |
| { |
| return fTableViewer; |
| } |
| |
| protected ViewTabCursorManager getCursorManager() |
| { |
| return fCursorManager; |
| } |
| |
| /** |
| * This function must be made synchronized. |
| * Otherwise, another thread could modify the selected address while it is being updated. |
| * It is the case when user scrolls up/down the table using arrow key. |
| * When the table reaches its limit, it is being reloaded. However, cursor receives a selection |
| * event and update the selected address at the same time. It messes up the selected address |
| * and causes cursor selection to behave unexpectedly. |
| * @param address |
| */ |
| synchronized protected void setSelectedAddress(BigInteger address, boolean updateSynchronizer) |
| { |
| fSelectedAddress = address; |
| |
| updateSyncSelectedAddress(updateSynchronizer); |
| } |
| |
| /** |
| * Return the offset from the base address of the memory block. |
| * @param memory |
| * @param lineAddress |
| * @param lineOffset |
| * @return |
| * TODO: this method is never called |
| */ |
| protected long getOffset(IMemoryBlock memory, String lineAddress, int lineOffset) { |
| |
| BigInteger lineAddr = new BigInteger(lineAddress, 16); |
| BigInteger memoryAddr; |
| |
| if (memory instanceof IExtendedMemoryBlock) |
| { |
| memoryAddr = ((IExtendedMemoryBlock)memory).getBigBaseAddress(); |
| } |
| else |
| { |
| memoryAddr = BigInteger.valueOf(memory.getStartAddress()); |
| } |
| |
| if (memoryAddr == null) |
| memoryAddr = new BigInteger("0"); //$NON-NLS-1$ |
| |
| long offset = lineAddr.subtract(memoryAddr).longValue(); |
| |
| return offset + lineOffset; |
| } |
| |
| /** |
| * Reset this view tab to the base address of the memory block |
| */ |
| public void resetAtBaseAddress() throws DebugException |
| { |
| try |
| { |
| IMemoryBlock mem = getMemoryBlock(); |
| if (mem instanceof IExtendedMemoryBlock) |
| { |
| // if text editor is activated, removes its focus and commit |
| // any changes made |
| setCursorFocus(); |
| |
| // reload table at base address |
| BigInteger address = ((IExtendedMemoryBlock)mem).getBigBaseAddress(); |
| |
| if (address == null) |
| { |
| address = new BigInteger("0"); //$NON-NLS-1$ |
| } |
| |
| setSelectedAddress(address, true); |
| reloadTable(address, false); |
| |
| // make sure cursor has focus when the user chooses to reset |
| setCursorFocus(); |
| } |
| else |
| { |
| // go to top of the table |
| BigInteger address = BigInteger.valueOf(mem.getStartAddress()); |
| setSelectedAddress(address, true); |
| getTableViewer().getTable().setTopIndex(0); |
| updateCursorPosition(); |
| updateTableSelection(); |
| setCursorFocus(); |
| } |
| |
| updateSyncTopAddress(true); |
| } |
| catch (DebugException e) |
| { |
| throw e; |
| } |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.debug.ui.IMemoryViewTab#goToAddress(java.math.BigInteger) |
| */ |
| public void goToAddress(BigInteger address) throws DebugException |
| { |
| goToAddress(address, true); |
| fCursorManager.setCursorFocus(); |
| } |
| |
| /** |
| * @param address |
| * @throws DebugException |
| */ |
| private void goToAddress(BigInteger address, boolean updateSynchronizer) throws DebugException { |
| try |
| { |
| // if address is within the range, highlight |
| if (!isAddressOutOfRange(address)) |
| { |
| // Defer update so that top visible address is updated before |
| // the selected address |
| // This is to ensure that the other view tabs get the top |
| // visible address change events first in case the selected |
| // address is not already visible. |
| // If this is not done, the other view tab may not show selected address. |
| setSelectedAddress(address, false); |
| updateCursorPosition(); |
| updateTableSelection(); |
| |
| // force the cursor to be shown |
| if (!isAddressVisible(fSelectedAddress)) |
| { |
| int i = findAddressIndex(fSelectedAddress); |
| |
| fTableViewer.getTable().showItem(fTableViewer.getTable().getItem(i)); |
| getCursorManager().showCursor(); |
| |
| updateSyncTopAddress(updateSynchronizer); |
| } |
| |
| // update selected address in synchronizer |
| updateSyncSelectedAddress(updateSynchronizer); |
| } |
| else |
| { |
| // if not extended memory block |
| // do not allow user to go to an address that's out of range |
| if (!(fMemoryBlock instanceof IExtendedMemoryBlock)) |
| { |
| Status stat = new Status( |
| IStatus.ERROR, DebugUIPlugin.getUniqueIdentifier(), |
| DebugException.NOT_SUPPORTED, DebugUIMessages.getString(ADDRESS_IS_OUT_OF_RANGE), null |
| ); |
| DebugException e = new DebugException(stat); |
| throw e; |
| } |
| |
| setSelectedAddress(address, updateSynchronizer); |
| |
| //otherwise, reload at the address |
| reloadTable(address, false); |
| updateSyncTopAddress(updateSynchronizer); |
| } |
| } |
| catch (DebugException e) |
| { |
| throw e; |
| } |
| } |
| |
| /** |
| * @return |
| */ |
| public int getColumnSize() |
| { |
| return fColumnSize; |
| } |
| |
| /** |
| * @return |
| */ |
| public int getBytesPerLine() |
| { |
| return fBytePerLine; |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.debug.ui.IMemoryViewTab#setFont(org.eclipse.swt.graphics.Font) |
| */ |
| public void setFont(Font font) |
| { |
| int oldIdx = fTableViewer.getTable().getTopIndex(); |
| |
| // BUG in table, if font is changed when table is not starting |
| // from the top, causes table gridline to be misaligned. |
| fTableViewer.getTable().setTopIndex(0); |
| |
| // set font |
| fTableViewer.getTable().setFont(font); |
| fCursorManager.setFont(font); |
| |
| fTableViewer.getTable().setTopIndex(oldIdx); |
| |
| packColumns(); |
| |
| // update table cursor and force redraw |
| updateCursorPosition(); |
| } |
| |
| /** |
| * @return memory block presentation to allow for customization |
| */ |
| protected IMemoryBlockModelPresentation getMemoryBlockPresentation() |
| { |
| // only try to create a model presentation once |
| if (fMemoryBlockPresentation == null && !fNoPresentation) |
| { |
| // create model presentation for memory block |
| DelegatingModelPresentation presentation = new MemoryViewDelegatingModelPresentation(); |
| String id = fMemoryBlock.getModelIdentifier(); |
| fMemoryBlockPresentation = (MemoryViewLazyModelPresentation)presentation.getPresentation(id); |
| |
| // if a memory block presentation cannot be retrieved |
| if (fMemoryBlockPresentation == null) |
| fNoPresentation = true; |
| } |
| return fMemoryBlockPresentation; |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.debug.ui.IMemoryViewTab#setTabLabel(java.lang.String) |
| */ |
| public void setTabLabel(String label) |
| { |
| if (label != null) |
| fTabItem.setText(label); |
| |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.debug.ui.IMemoryViewTab#getTabLabel() |
| */ |
| public String getTabLabel() |
| { |
| if (fTabItem != null) |
| return fTabItem.getText(); |
| else |
| return null; |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.debug.ui.IMemoryViewTab#getRenderingId() |
| */ |
| public String getRenderingId() |
| { |
| return fRenderingId; |
| } |
| |
| /** |
| * Handle column size changed event from synchronizer |
| * @param newColumnSize |
| */ |
| private void columnSizeChanged(final int newColumnSize) |
| { |
| // ignore event if view tab is disabled |
| if (!isEnabled()) |
| return; |
| |
| Display.getDefault().asyncExec(new Runnable() |
| { |
| public void run() |
| { |
| format(16, newColumnSize); |
| } |
| }); |
| |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.debug.ui.ISynchronizedMemoryBlockView#scrollBarSelectionChanged(int) |
| */ |
| public void scrollBarSelectionChanged(int newSelection) |
| { |
| |
| |
| } |
| |
| /** |
| * Handle selected address change event from synchronizer |
| * @param address |
| */ |
| private void selectedAddressChanged(final BigInteger address) |
| { |
| // ignore event if view tab is disabled |
| if (!isEnabled()) |
| { |
| return; |
| } |
| |
| try |
| { |
| if (!fSelectedAddress.equals(address)) |
| { |
| if (getMemoryBlock() instanceof IExtendedMemoryBlock) |
| { |
| goToAddress(address, false); |
| } |
| else |
| { |
| if (!isAddressOutOfRange(address)) |
| { |
| goToAddress(address, false); |
| } |
| } |
| } |
| |
| } |
| catch (DebugException e) |
| { |
| displayError(e); |
| } |
| } |
| |
| /** |
| * Handle top visible address change event from synchronizer |
| * @param address |
| */ |
| private void topVisibleAddressChanged(final BigInteger address) |
| { |
| try |
| { |
| // do not handle event if view tab is disabled |
| if (!isEnabled()) |
| return; |
| |
| if (!address.equals(getTopVisibleAddress())) |
| { |
| if (getMemoryBlock() instanceof IExtendedMemoryBlock) |
| { |
| |
| if (!isAddressOutOfRange(address)) |
| { |
| int index = -1; |
| // within buffer range, just set top index |
| Table table = getTableViewer().getTable(); |
| for (int i = 0; i < table.getItemCount(); i++) |
| { |
| MemoryViewLine line = (MemoryViewLine) table.getItem(i).getData(); |
| if (line != null) |
| { |
| BigInteger lineAddress = new BigInteger(line.getAddress(), 16); |
| if (lineAddress.equals(address)) |
| { |
| index = i; |
| break; |
| } |
| } |
| } |
| if (index >= 3 && table.getItemCount() - (index+getNumberOfVisibleLines()) >= 3) |
| { |
| // update cursor position |
| table.setTopIndex(index); |
| |
| if (!isAddressVisible(fSelectedAddress)) |
| { |
| fCursorManager.hideCursor(); |
| } |
| else |
| { |
| updateCursorPosition(); |
| updateTableSelection(); |
| table.setTopIndex(index); |
| |
| // BUG 64831: to get around SWT problem with |
| // the table cursor not painted properly after |
| // table.setTopIndex is called |
| fCursorManager.getLeadCursor().setVisible(false); |
| fCursorManager.getLeadCursor().setVisible(true); |
| } |
| } |
| else |
| { |
| // approaching limit, reload table |
| reloadTable(address, false); |
| } |
| } |
| else |
| { |
| // approaching limit, reload table |
| reloadTable(address, false); |
| } |
| } |
| else |
| { |
| // IMemoryBlock support |
| int index = -1; |
| // within buffer range, just set top index |
| Table table = getTableViewer().getTable(); |
| for (int i = 0; i < table.getItemCount(); i++) |
| { |
| MemoryViewLine line = (MemoryViewLine) table.getItem(i).getData(); |
| if (line != null) |
| { |
| BigInteger lineAddress = new BigInteger(line.getAddress(), 16); |
| if (lineAddress.equals(address)) |
| { |
| index = i; |
| break; |
| } |
| } |
| } |
| |
| if (index >= 0) |
| { |
| table.setTopIndex(index); |
| |
| if (!isAddressVisible(fSelectedAddress)) |
| { |
| fCursorManager.hideCursor(); |
| } |
| else |
| { |
| updateCursorPosition(); |
| updateTableSelection(); |
| table.setTopIndex(index); |
| |
| // BUG 64831: to get around SWT problem with |
| // the table cursor not painted properly after |
| // table.setTopIndex is called |
| fCursorManager.getLeadCursor().setVisible(false); |
| fCursorManager.getLeadCursor().setVisible(true); |
| } |
| } |
| } |
| } |
| } |
| catch (DebugException e) |
| { |
| displayError(e); |
| } |
| } |
| |
| /** |
| * Check if address provided is out of buffered range |
| * @param address |
| * @return |
| */ |
| private boolean isAddressOutOfRange(BigInteger address) |
| { |
| return contentProvider.isAddressOutOfRange(address); |
| } |
| |
| /** |
| * Check if address is visible |
| * @param address |
| * @return |
| */ |
| protected boolean isAddressVisible(BigInteger address) |
| { |
| // if view tab is not yet created |
| // cursor should always be visible |
| if (!fTabCreated) |
| return true; |
| |
| BigInteger topVisible = getTopVisibleAddress(); |
| BigInteger lastVisible = getTopVisibleAddress().add(BigInteger.valueOf((getNumberOfVisibleLines()) * getBytesPerLine() + getBytesPerLine())); |
| |
| if (topVisible.compareTo(address) <= 0 && lastVisible.compareTo(address) > 0) |
| { |
| return true; |
| } |
| else |
| { |
| return false; |
| } |
| } |
| |
| /** |
| * Get properties from synchronizer and synchronize settings |
| */ |
| private void synchronize() |
| { |
| Integer columnSize = (Integer) getSynchronizedProperty(IMemoryViewConstants.PROPERTY_COL_SIZE); |
| BigInteger selectedAddress = (BigInteger)getSynchronizedProperty(IMemoryViewConstants.PROPERTY_SELECTED_ADDRESS); |
| BigInteger topAddress = (BigInteger)getSynchronizedProperty(IMemoryViewConstants.PROPERTY_TOP_ADDRESS); |
| |
| if (columnSize != null) |
| { |
| int colSize = columnSize.intValue(); |
| |
| if (colSize > 0 && colSize != fColumnSize) |
| { |
| columnSizeChanged(colSize); |
| } |
| } |
| |
| if (topAddress != null) |
| { |
| if (!topAddress.equals(getTopVisibleAddress())) |
| { |
| if (!fSelectedAddress.equals(selectedAddress)) |
| { |
| setSelectedAddress(selectedAddress, true); |
| } |
| |
| topVisibleAddressChanged(topAddress); |
| } |
| } |
| |
| if (selectedAddress != null) |
| { |
| if (selectedAddress.compareTo(fSelectedAddress) != 0) |
| { |
| selectedAddressChanged(selectedAddress); |
| } |
| } |
| |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.debug.ui.ISynchronizedMemoryBlockView#propertyChanged(java.lang.String, java.lang.Object) |
| */ |
| public void propertyChanged(String propertyName, Object value) |
| { |
| if (isDisplayingError()) |
| return; |
| |
| if (propertyName.equals(IMemoryViewConstants.PROPERTY_SELECTED_ADDRESS) && value instanceof BigInteger) |
| { |
| try { |
| if (needMoreLines()) |
| { |
| reloadTable(getTopVisibleAddress(), false); |
| } |
| } catch (DebugException e) { |
| displayError(e); |
| } |
| |
| selectedAddressChanged((BigInteger)value); |
| } |
| else if (propertyName.equals(IMemoryViewConstants.PROPERTY_COL_SIZE) && value instanceof Integer) |
| { |
| columnSizeChanged(((Integer)value).intValue()); |
| } |
| else if (propertyName.equals(IMemoryViewConstants.PROPERTY_TOP_ADDRESS) && value instanceof BigInteger) |
| { |
| try { |
| if (needMoreLines()) |
| { |
| reloadTable(getTopVisibleAddress(), false); |
| } |
| } catch (DebugException e) { |
| displayError(e); |
| } |
| topVisibleAddressChanged((BigInteger)value); |
| return; |
| } |
| } |
| /* (non-Javadoc) |
| * @see org.eclipse.debug.ui.ISynchronizedMemoryBlockView#getProperty(java.lang.String) |
| */ |
| public Object getProperty(String propertyId) |
| { |
| if (propertyId.equals(IMemoryViewConstants.PROPERTY_SELECTED_ADDRESS)) |
| { |
| return fSelectedAddress; |
| } |
| else if (propertyId.equals(IMemoryViewConstants.PROPERTY_COL_SIZE)) |
| { |
| return new Integer(fColumnSize); |
| } |
| else if (propertyId.equals(IMemoryViewConstants.PROPERTY_TOP_ADDRESS)) |
| { |
| return getTopVisibleAddress(); |
| } |
| return null; |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.debug.ui.IMemoryViewTab#getSelectedAddress() |
| */ |
| public BigInteger getSelectedAddress() { |
| return fSelectedAddress; |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.debug.ui.IMemoryViewTab#getSelectedContent() |
| */ |
| public String getSelectedContent() { |
| |
| // check precondition |
| if (fCursorManager.fCol == 0 || fCursorManager.fCol > getBytesPerLine()/getColumnSize()) |
| { |
| return ""; //$NON-NLS-1$ |
| } |
| |
| TableItem tableItem = getTableViewer().getTable().getItem(fCursorManager.fRow); |
| |
| return tableItem.getText(fCursorManager.fCol); |
| } |
| |
| /** |
| * Update labels in the view tab |
| */ |
| protected void updateLabels() |
| { |
| // update tab labels |
| setTabName(getMemoryBlock(), true); |
| |
| if (fTableViewer != null) |
| { |
| // update column labels |
| setColumnHeadings(); |
| |
| refreshTableViewer(); |
| } |
| } |
| |
| protected boolean needMoreLines() |
| { |
| if (getMemoryBlock() instanceof IExtendedMemoryBlock) |
| { |
| Table table = fTableViewer.getTable(); |
| TableItem firstItem = table.getItem(0); |
| TableItem lastItem = table.getItem(table.getItemCount()-1); |
| |
| if (firstItem == null || lastItem == null) |
| return true; |
| |
| MemoryViewLine first = (MemoryViewLine)firstItem.getData(); |
| MemoryViewLine last = (MemoryViewLine) lastItem.getData(); |
| |
| if (first == null ||last == null) |
| { |
| // For some reason, the table does not return the correct number |
| // of table items in table.getItemCount(), causing last to be null. |
| // This check is to ensure that we don't get a null pointer exception. |
| return true; |
| } |
| |
| BigInteger startAddress = new BigInteger(first.getAddress(), 16); |
| BigInteger lastAddress = new BigInteger(last.getAddress(), 16); |
| lastAddress = lastAddress.add(BigInteger.valueOf(getBytesPerLine())); |
| |
| BigInteger topVisibleAddress = getTopVisibleAddress(); |
| long numVisibleLines = getNumberOfVisibleLines(); |
| long numOfBytes = numVisibleLines * getBytesPerLine(); |
| |
| BigInteger lastVisibleAddrss = topVisibleAddress.add(BigInteger.valueOf(numOfBytes)); |
| |
| // if there are only 3 lines left at the top, refresh |
| BigInteger numTopLine = topVisibleAddress.subtract(startAddress).divide(BigInteger.valueOf(getBytesPerLine())); |
| if (numTopLine.compareTo(BigInteger.valueOf(3)) <= 0) |
| return true; |
| |
| // if there are only 3 lines left at the bottom, refresh |
| BigInteger numBottomLine = lastAddress.subtract(lastVisibleAddrss).divide(BigInteger.valueOf(getBytesPerLine())); |
| if (numBottomLine.compareTo(BigInteger.valueOf(3)) <= 0) |
| { |
| return true; |
| } |
| |
| return false; |
| } |
| else |
| { |
| return false; |
| } |
| } |
| |
| private Object getSynchronizedProperty(String propertyId) |
| { |
| return getMemoryBlockViewSynchronizer().getSynchronizedProperty(getMemoryBlock(), propertyId); |
| } |
| |
| /** |
| * Checks to see if the event is valid for activating |
| * cell editing in a view tab |
| * @param event |
| * @return |
| */ |
| public boolean isValidEditEvent(int event) { |
| for (int i = 0; i < MemoryViewTab.ignoreEvents.length; i++) { |
| if (event == MemoryViewTab.ignoreEvents[i]) |
| return false; |
| } |
| return true; |
| } |
| |
| private IMemoryBlockViewSynchronizer getMemoryBlockViewSynchronizer() { |
| return DebugUIPlugin.getDefault().getMemoryBlockViewSynchronizer(); |
| } |
| } |
| |