/******************************************************************************* * Copyright (c) 2006, 2016 Wind River Systems, Inc. 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: * Ted R Williams (Wind River Systems, Inc.) - initial implementation * Alvaro Sanchez-Leon (Ericsson AB) - [Memory] Support 16 bit addressable size (Bug 426730) *******************************************************************************/ package org.eclipse.cdt.debug.ui.memory.traditional; import java.lang.reflect.Method; import java.math.BigInteger; import java.util.HashMap; import java.util.Map; import org.eclipse.cdt.debug.core.model.provisional.IMemoryRenderingViewportProvider; import org.eclipse.cdt.debug.core.model.provisional.IMemorySpaceAwareMemoryBlock; import org.eclipse.cdt.debug.core.model.provisional.IMemorySpaceAwareMemoryBlockRetrieval; import org.eclipse.cdt.debug.internal.core.CRequest; import org.eclipse.core.commands.AbstractHandler; import org.eclipse.core.commands.Command; import org.eclipse.core.commands.ExecutionEvent; import org.eclipse.core.commands.ExecutionException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.debug.core.DebugException; import org.eclipse.debug.core.DebugPlugin; import org.eclipse.debug.core.model.IMemoryBlock; import org.eclipse.debug.core.model.IMemoryBlockExtension; import org.eclipse.debug.core.model.IMemoryBlockRetrieval; import org.eclipse.debug.core.model.MemoryByte; import org.eclipse.debug.internal.ui.DebugUIPlugin; import org.eclipse.debug.internal.ui.IInternalDebugUIConstants; import org.eclipse.debug.internal.ui.memory.IMemoryBlockConnection; import org.eclipse.debug.internal.ui.memory.provisional.MemoryViewPresentationContext; import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelChangedListener; import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta; import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelProxy; import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelProxyFactory; import org.eclipse.debug.internal.ui.views.memory.renderings.GoToAddressAction; import org.eclipse.debug.ui.IDebugUIConstants; import org.eclipse.debug.ui.memory.AbstractMemoryRendering; import org.eclipse.debug.ui.memory.AbstractTableRendering; import org.eclipse.debug.ui.memory.IMemoryRendering; import org.eclipse.debug.ui.memory.IMemoryRenderingContainer; import org.eclipse.debug.ui.memory.IMemoryRenderingSite; import org.eclipse.debug.ui.memory.IRepositionableMemoryRendering; import org.eclipse.debug.ui.memory.IResettableMemoryRendering; import org.eclipse.jface.action.Action; import org.eclipse.jface.action.IAction; import org.eclipse.jface.action.IMenuListener; import org.eclipse.jface.action.IMenuManager; import org.eclipse.jface.action.MenuManager; import org.eclipse.jface.action.Separator; import org.eclipse.jface.dialogs.IInputValidator; import org.eclipse.jface.dialogs.InputDialog; import org.eclipse.jface.preference.IPreferenceStore; import org.eclipse.jface.preference.PreferenceConverter; import org.eclipse.jface.resource.ImageDescriptor; import org.eclipse.jface.resource.JFaceResources; import org.eclipse.jface.util.IPropertyChangeListener; import org.eclipse.jface.util.PropertyChangeEvent; import org.eclipse.jface.viewers.IBasicPropertyConstants; import org.eclipse.jface.window.Window; import org.eclipse.swt.SWT; import org.eclipse.swt.dnd.Clipboard; import org.eclipse.swt.dnd.DND; import org.eclipse.swt.dnd.TextTransfer; import org.eclipse.swt.dnd.Transfer; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.graphics.Font; import org.eclipse.swt.graphics.FontData; import org.eclipse.swt.graphics.RGB; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Display; import org.eclipse.ui.IActionBars; import org.eclipse.ui.IViewSite; import org.eclipse.ui.IWorkbench; import org.eclipse.ui.IWorkbenchActionConstants; import org.eclipse.ui.IWorkbenchPartSite; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.actions.ActionFactory; import org.eclipse.ui.commands.ICommandService; import org.eclipse.ui.model.IWorkbenchAdapter; import org.eclipse.ui.progress.UIJob; /** * A memory rendering displaying memory in a traditional * memory view look and feel, optimized for minimal IO traffic. * <p> * requirements of the debug model implementation: * - An IMemoryBlockExtension is required. * * Since it is not possible to size the memory block to match * the size of the viewport, memory block change notification * is not useful. Such events are ignored by this rendering. */ @SuppressWarnings("restriction") public class TraditionalRendering extends AbstractMemoryRendering implements IRepositionableMemoryRendering, IResettableMemoryRendering, IMemoryRenderingViewportProvider, IModelChangedListener { protected Rendering fRendering; protected Action displayEndianBigAction; protected Action displayEndianLittleAction; private IWorkbenchAdapter fWorkbenchAdapter; private IMemoryBlockConnection fConnection; private String fMemorySpaceId; private final static int MAX_MENU_COLUMN_COUNT = 8; private IMemorySpacePreferencesHelper fMemSpacePreferenceHelper; private class GetMemorySpacesRequest extends CRequest implements IMemorySpaceAwareMemoryBlockRetrieval.GetMemorySpacesRequest { String [] fMemorySpaces; public String[] getMemorySpaces() { return fMemorySpaces; } public void setMemorySpaces(String[] memorySpaceIds) { fMemorySpaces = memorySpaceIds; } } public TraditionalRendering(String id) { super(id); JFaceResources.getFontRegistry().addListener( new IPropertyChangeListener() { public void propertyChange(PropertyChangeEvent event) { if(event.getProperty().equals( IInternalDebugUIConstants.FONT_NAME)) { TraditionalRendering.this.fRendering .handleFontPreferenceChange(JFaceResources .getFont(IInternalDebugUIConstants.FONT_NAME)); } } }); this.addPropertyChangeListener(new IPropertyChangeListener() { public void propertyChange(PropertyChangeEvent event) { IMemoryRendering sourceRendering = (IMemoryRendering) event .getSource(); if(!sourceRendering.getMemoryBlock().equals(getMemoryBlock())) return; Object address = event.getNewValue(); if(event.getProperty().equals( AbstractTableRendering.PROPERTY_SELECTED_ADDRESS) && address instanceof BigInteger) { TraditionalRendering.this.fRendering .ensureVisible((BigInteger) address); } } }); TraditionalRenderingPlugin.getDefault().getPreferenceStore().addPropertyChangeListener( new IPropertyChangeListener() { public void propertyChange(PropertyChangeEvent event) { disposeColors(); allocateColors(); applyPreferences(); } }); DebugUIPlugin.getDefault().getPreferenceStore().addPropertyChangeListener( new IPropertyChangeListener() { public void propertyChange(PropertyChangeEvent event) { if(event.getProperty().equals(IDebugUIConstants.PREF_PADDED_STR)) { if(TraditionalRendering.this.fRendering != null) { setRenderingPadding((String) event.getNewValue()); TraditionalRendering.this.fRendering.redrawPanes(); } } } }); } private void setRenderingPadding(String padding) { if(padding == null || padding.length() == 0) padding = "?"; //$NON-NLS-1$ TraditionalRendering.this.fRendering.setPaddingString(padding); } protected void logError(String message, Exception e) { Status status = new Status(IStatus.ERROR, getRenderingId(), DebugException.INTERNAL_ERROR, message, e); TraditionalRenderingPlugin.getDefault().getLog().log(status); } private BigInteger fBigBaseAddress; private BigInteger fStartAddress; private BigInteger fEndAddress; private int fAddressableSize; private int fAddressSize; /* * @see org.eclipse.debug.internal.ui.viewers.model.provisional.IModelChangedListener#modelChanged(org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta, org.eclipse.debug.internal.ui.viewers.model.provisional.IModelProxy) */ public void modelChanged(IModelDelta delta, IModelProxy proxy) { /* * The event model in the traditional renderer is written to expect a suspend first * which will cause it to save its current data set away in an archive. Then when * the state change comes through it will compare and refresh showing a difference. */ int flags = delta.getFlags(); if ( ( flags & IModelDelta.STATE ) != 0 ) { fRendering.handleSuspend(false); } fRendering.handleChange(); } /* * We use the model proxy which is supplied by the TCF implementation to provide the knowledge of memory * change notifications. The older backends ( the reference model, Wind River Systems Inc. ) are written * to generate the Debug Model events. TCF follows the "ModelDelta/IModelProxy" implementation that the * platform renderers use. So this implementation acts as a shim. If the older Debug Events come in then * fine. If the newer model deltas come in fine also. */ private IModelProxy fModel; @Override public void dispose() { /* * We use the UI dispatch thread to protect the proxy information. Even though I believe the * dispose routine is always called in the UI dispatch thread. I am going to make sure. */ Display.getDefault().asyncExec(new Runnable() { public void run() { if ( fModel != null ) { fModel.removeModelChangedListener(TraditionalRendering.this); fModel.dispose(); } }}); if(this.fRendering != null) this.fRendering.dispose(); disposeColors(); disposeFonts(); super.dispose(); } @Override public void init(final IMemoryRenderingContainer container, final IMemoryBlock block) { super.init(container, block); fMemSpacePreferenceHelper = TraditionalMemoryRenderingFactory.getMemorySpacesPreferencesHelper(); // resolve memory space, if any if (block instanceof IMemorySpaceAwareMemoryBlock) { IMemorySpaceAwareMemoryBlock memBlock = (IMemorySpaceAwareMemoryBlock) block; String id = memBlock.getMemorySpaceID(); fMemorySpaceId = id; } // extract memory space info, if applicable if (block instanceof IMemorySpaceAwareMemoryBlock) { IMemoryBlockRetrieval retrieval = ((IMemorySpaceAwareMemoryBlock) block).getMemoryBlockRetrieval(); ((IMemorySpaceAwareMemoryBlockRetrieval)retrieval).getMemorySpaces(block, new GetMemorySpacesRequest(){ @Override public void done() { final String[] spaces = isSuccess() ? getMemorySpaces() : new String[0]; // remember memory spaces Display.getDefault().asyncExec(new Runnable() { @Override public void run() { fMemSpacePreferenceHelper.updateMemorySpaces(spaces); } }); } }); } /* * Working with the model proxy must be done on the UI dispatch thread. */ final IModelProxyFactory factory = (IModelProxyFactory) DebugPlugin.getAdapter(block, IModelProxyFactory.class ); if ( factory != null ) { Display.getDefault().asyncExec(new Runnable() { public void run() { /* * The asynchronous model assumes we have an asynchronous viewer that has an IPresentationContext * to represent it. The Platform memory subsystem provides a way to create one without a viewewr. */ IMemoryRenderingSite site = container.getMemoryRenderingSite(); MemoryViewPresentationContext context = new MemoryViewPresentationContext(site, container, TraditionalRendering.this); /* * Get a new proxy and perform the initialization sequence so we are known the * the model provider. */ fModel = factory.createModelProxy(block, context); if ( fModel != null ) { fModel.installed(null); fModel.addModelChangedListener(TraditionalRendering.this); } }}); } try { fBigBaseAddress = ((IMemoryBlockExtension) block).getBigBaseAddress(); } catch(DebugException de) { logError(TraditionalRenderingMessages .getString("TraditionalRendering.FAILURE_RETRIEVE_BASE_ADDRESS"), de); //$NON-NLS-1$ // FIXME } try { fAddressableSize = ((IMemoryBlockExtension) block).getAddressableSize(); } catch(DebugException de) { fAddressableSize = 1; } try { fStartAddress = ((IMemoryBlockExtension)block).getMemoryBlockStartAddress(); } catch (DebugException de) { fStartAddress = null; logError(TraditionalRenderingMessages .getString("TraditionalRendering.FAILURE_RETRIEVE_START_ADDRESS"), de); //$NON-NLS-1$ } try { fAddressSize = ((IMemoryBlockExtension) block).getAddressSize(); } catch(DebugException e) { fAddressSize = 0; } BigInteger endAddress; try { endAddress = ((IMemoryBlockExtension) block).getMemoryBlockEndAddress(); if (endAddress != null) fEndAddress = endAddress; } catch (DebugException e) { fEndAddress = null; } if (fEndAddress == null) { int addressSize; try { addressSize = ((IMemoryBlockExtension) block).getAddressSize(); } catch (DebugException e) { addressSize = 4; } endAddress = BigInteger.valueOf(2); endAddress = endAddress.pow(addressSize*8); endAddress = endAddress.subtract(BigInteger.valueOf(1)); fEndAddress = endAddress; } // default to MAX_VALUE if we have trouble getting the end address if (fEndAddress == null) fEndAddress = BigInteger.valueOf(Integer.MAX_VALUE); } public BigInteger getBigBaseAddress() { return fBigBaseAddress; } public BigInteger getMemoryBlockStartAddress() { return fStartAddress; } public BigInteger getMemoryBlockEndAddress() { return fEndAddress; } public int getAddressableSize() { return fAddressableSize; } public int getAddressSize() { return fAddressSize; } public Control createControl(Composite parent) { allocateColors(); this.fRendering = new RenderingAddressInfo(parent, this); applyPreferences(); createMenus(); return this.fRendering; } // FIXME private static final String ID_GO_TO_ADDRESS_COMMAND = "org.eclipse.debug.ui.command.gotoaddress"; //$NON-NLS-1$ private AbstractHandler fGoToAddressHandler; private IAction fSavedActionHandler; // When we set the global copy action handler we save off the existing so we can restore it. @Override public void activated() { super.activated(); IWorkbench workbench = PlatformUI.getWorkbench(); ICommandService commandSupport = (ICommandService)workbench.getAdapter(ICommandService.class); if(commandSupport != null) { Command gotoCommand = commandSupport.getCommand(ID_GO_TO_ADDRESS_COMMAND); if(fGoToAddressHandler == null) { fGoToAddressHandler = new AbstractHandler() { public Object execute(ExecutionEvent event) throws ExecutionException { // TODO return null; } }; } gotoCommand.setHandler(fGoToAddressHandler); } // Set the action handler for the global copy action final Action defaultAction = new CopyDefaultAction(this.fRendering, DND.CLIPBOARD); IWorkbenchPartSite site = getMemoryRenderingContainer().getMemoryRenderingSite().getSite(); if (site instanceof IViewSite) { IActionBars actionBars = ((IViewSite) site).getActionBars(); if (actionBars != null) { fSavedActionHandler = actionBars.getGlobalActionHandler(ActionFactory.COPY.getId()); actionBars.setGlobalActionHandler(ActionFactory.COPY.getId(), defaultAction); } } } @Override public void deactivated() { IWorkbench workbench = PlatformUI.getWorkbench(); ICommandService commandSupport = (ICommandService) workbench.getAdapter(ICommandService.class); if(commandSupport != null) { // remove handler Command command = commandSupport.getCommand(ID_GO_TO_ADDRESS_COMMAND); command.setHandler(null); } // Restore the saved action handler for the memory view. IWorkbenchPartSite site = getMemoryRenderingContainer().getMemoryRenderingSite().getSite(); if (site instanceof IViewSite) { IActionBars actionBars = ((IViewSite) site).getActionBars(); if (actionBars != null) { actionBars.setGlobalActionHandler(ActionFactory.COPY.getId(), fSavedActionHandler); } } super.deactivated(); } public void setSelection(BigInteger start, BigInteger end) { fRendering.getSelection().setStart(start, start); fRendering.getSelection().setEnd(end, end); } public void gotoAddress(final BigInteger address) { this.fRendering.gotoAddress(address); } public void updateRenderingLabels() { UIJob job = new UIJob("updateLabels"){ //$NON-NLS-1$ @Override public IStatus runInUIThread(IProgressMonitor monitor) { // update tab labels String fLabel = getLabel(); firePropertyChangedEvent(new PropertyChangeEvent(TraditionalRendering.this, IBasicPropertyConstants.P_TEXT, null, fLabel)); return Status.OK_STATUS; }}; job.setSystem(true); job.schedule(); } private Color colorBackground; private Color colorChanged; private Color colorsChanged[] = null; private Color colorEdit; private Color colorSelection; private Color colorText; private Color colorTextAlternate; private Map<Integer,Font> fonts = new HashMap<Integer,Font>(3); public void allocateColors() { IPreferenceStore store = TraditionalRenderingPlugin.getDefault().getPreferenceStore(); colorBackground = null; // has a memory-space-specific background color been set for the associated memory space? if (fMemorySpaceId != null) { String key = fMemSpacePreferenceHelper.getMemorySpaceKey(fMemorySpaceId); if (store.getString(key) != "") { colorBackground = new Color(Display.getDefault(), PreferenceConverter.getColor(store, key)); } } // no - then use default if (colorBackground == null) { colorBackground = new Color(Display.getDefault(), PreferenceConverter.getColor(store, TraditionalRenderingPreferenceConstants.MEM_COLOR_BACKGROUND)); } colorChanged = new Color(Display.getDefault(), PreferenceConverter.getColor(store, TraditionalRenderingPreferenceConstants.MEM_COLOR_CHANGED)); colorEdit = new Color(Display.getDefault(), PreferenceConverter.getColor(store, TraditionalRenderingPreferenceConstants.MEM_COLOR_EDIT)); colorSelection = new Color(Display.getDefault(), PreferenceConverter.getColor(store, TraditionalRenderingPreferenceConstants.MEM_COLOR_SELECTION)); colorText = new Color(Display.getDefault(), PreferenceConverter.getColor(store, TraditionalRenderingPreferenceConstants.MEM_COLOR_TEXT)); // alternate cell color Color textColor = getColorText(); int red = textColor.getRed(); int green = textColor.getGreen(); int blue = textColor.getBlue(); float scale = store.getInt( TraditionalRenderingPreferenceConstants.MEM_LIGHTEN_DARKEN_ALTERNATE_CELLS); red = (int) Math.min(red + ((255 - red) / 10) * scale, 255); green = (int) Math.min(green + ((255 - green) / 10) * scale, 255); blue = (int) Math.min(blue + ((255 - blue) / 10) * scale, 255); colorTextAlternate = new Color(Display.getDefault(), new RGB(red, green, blue)); } public void disposeColors() { if(colorBackground != null) colorBackground.dispose(); colorBackground = null; if(colorChanged != null) colorChanged.dispose(); colorChanged = null; if(colorEdit != null) colorEdit.dispose(); colorEdit = null; if(colorSelection != null) colorSelection.dispose(); colorSelection = null; if(colorText != null) colorText.dispose(); colorText = null; if(colorTextAlternate != null) colorTextAlternate.dispose(); colorTextAlternate = null; disposeChangedColors(); } public void disposeFonts() { for (Font font : fonts.values()) font.dispose(); } public void applyPreferences() { if(fRendering != null && !fRendering.isDisposed()) { IPreferenceStore store = TraditionalRenderingPlugin.getDefault().getPreferenceStore(); fRendering.setHistoryDepth(store.getInt(TraditionalRenderingPreferenceConstants.MEM_HISTORY_TRAILS_COUNT)); fRendering.setBackground(getColorBackground()); AbstractPane panes[] = fRendering.getRenderingPanes(); for(int i = 0; i < panes.length; i++) panes[i].setBackground(getColorBackground()); setRenderingPadding(TraditionalRenderingPlugin.getDefault().getPreferenceStore().getString(IDebugUIConstants.PREF_PADDED_STR)); if (store.getBoolean(TraditionalRenderingPreferenceConstants.MEM_CROSS_REFERENCE_INFO)) { fRendering.resolveAddressInfoForCurrentSelection(); } fRendering.redrawPanes(); } } private Font makeFont(Font font, String boldKey, String italicKey) { IPreferenceStore store = TraditionalRenderingPlugin.getDefault().getPreferenceStore(); int style = SWT.NONE; if (store.getBoolean(boldKey)) style |= SWT.BOLD; if (store.getBoolean(italicKey)) style |= SWT.ITALIC; if (style == SWT.NONE) return font; Font modified = fonts.get(style); if (modified == null) { FontData fontData = font.getFontData()[0]; modified = new Font(font.getDevice(), fontData.getName(), fontData.getHeight(), fontData.getStyle() | style); fonts.put(style, modified); } return modified; } public Font getFontChanged(Font font) { return makeFont(font, TraditionalRenderingPreferenceConstants.MEM_COLOR_CHANGED_BOLD, TraditionalRenderingPreferenceConstants.MEM_COLOR_CHANGED_ITALIC); } public Font getFontEdit(Font font) { return makeFont(font, TraditionalRenderingPreferenceConstants.MEM_COLOR_EDIT_BOLD, TraditionalRenderingPreferenceConstants.MEM_COLOR_EDIT_ITALIC); } public boolean getBoxChanged() { IPreferenceStore store = TraditionalRenderingPlugin.getDefault().getPreferenceStore(); return store.getBoolean(TraditionalRenderingPreferenceConstants.MEM_COLOR_CHANGED_BOX); } public boolean getBoxEdit() { IPreferenceStore store = TraditionalRenderingPlugin.getDefault().getPreferenceStore(); return store.getBoolean(TraditionalRenderingPreferenceConstants.MEM_COLOR_EDIT_BOX); } public Color getColorBackground() { IPreferenceStore store = TraditionalRenderingPlugin.getDefault().getPreferenceStore(); if(store.getBoolean(TraditionalRenderingPreferenceConstants.MEM_USE_GLOBAL_BACKGROUND)) return Display.getDefault().getSystemColor(SWT.COLOR_LIST_BACKGROUND); else return colorBackground; } public Color getColorChanged() { return colorChanged; } private void disposeChangedColors() { if(colorsChanged != null) for(int i = 0; i < colorsChanged.length; i++) colorsChanged[i].dispose(); colorsChanged = null; } public Color[] getColorsChanged() { if(colorsChanged != null && colorsChanged.length != fRendering.getHistoryDepth()) { disposeChangedColors(); } if(colorsChanged == null) { colorsChanged = new Color[fRendering.getHistoryDepth()]; colorsChanged[0] = colorChanged; int shades = fRendering.getHistoryDepth() + 4; int red = (255 - colorChanged.getRed()) / shades; int green = (255 - colorChanged.getGreen()) / shades; int blue = (255 - colorChanged.getBlue()) / shades; for(int i = 1; i < fRendering.getHistoryDepth(); i++) { colorsChanged[i] = new Color(colorChanged.getDevice(), colorChanged.getRed() + ((shades - i) * red), colorChanged.getGreen() + ((shades - i) * green), colorChanged.getBlue() + ((shades - i) * blue)); } } return colorsChanged; } public Color getColorEdit() { return colorEdit; } public Color getColorSelection() { IPreferenceStore store = TraditionalRenderingPlugin.getDefault().getPreferenceStore(); if(store.getBoolean(TraditionalRenderingPreferenceConstants.MEM_USE_GLOBAL_SELECTION)) return Display.getDefault().getSystemColor(SWT.COLOR_LIST_SELECTION); else return colorSelection; } public Color getColorText() { IPreferenceStore store = TraditionalRenderingPlugin.getDefault().getPreferenceStore(); if(store.getBoolean(TraditionalRenderingPreferenceConstants.MEM_USE_GLOBAL_TEXT)) return Display.getDefault().getSystemColor(SWT.COLOR_LIST_FOREGROUND); else return colorText; } public Color getColorTextAlternate() { return colorTextAlternate; } /** * @since 1.4 */ public boolean isShowCrossRefInfoGlobalPref() { IPreferenceStore store = TraditionalRenderingPlugin.getDefault().getPreferenceStore(); return store.getBoolean(TraditionalRenderingPreferenceConstants.MEM_CROSS_REFERENCE_INFO); } public void createMenus() { // add the menu to each of the rendering panes Control[] renderingControls = this.fRendering.getRenderingPanes(); for(int i = 0; i < renderingControls.length; i++) super.createPopupMenu(renderingControls[i]); super.createPopupMenu(this.fRendering); // Create the copy actions final CopyAction copyBinaryAction = new CopyBinaryAction(this.fRendering); final CopyAction copyTextAction = new CopyTextAction(this.fRendering); final CopyAction copyAddressAction = new CopyAddressAction(this.fRendering); final CopyAction copyAllAction = new CopyAllAction(this.fRendering); // go-to address action final IAction goToAddressAction = new GoToAddressAction(getMemoryRenderingContainer(), this); // reset to base address final Action gotoBaseAddressAction = new Action( TraditionalRenderingMessages .getString("TraditionalRendering.RESET_TO_BASE_ADDRESS")) //$NON-NLS-1$ { @Override public void run() { Display.getDefault().asyncExec(new Runnable() { public void run() { TraditionalRendering.this.fRendering .gotoAddress(TraditionalRendering.this.fRendering.fBaseAddress); } }); } }; // refresh final Action refreshAction = new Action( TraditionalRenderingMessages .getString("TraditionalRendering.REFRESH")) //$NON-NLS-1$ { @Override public void run() { Display.getDefault().asyncExec(new Runnable() { public void run() { // For compatibility with DSF update modes (hopefully this will either be replaced by an enhanced // platform interface or the caching will move out of the data layer try { Method m = fRendering.getMemoryBlock().getClass().getMethod("clearCache", new Class[0]); //$NON-NLS-1$ if(m != null) m.invoke(fRendering.getMemoryBlock(), new Object[0]); } catch (Exception e) { } TraditionalRendering.this.fRendering.refresh(); } }); } }; // display address final Action displayAddressPaneAction = new Action( TraditionalRenderingMessages .getString("TraditionalRendering.ADDRESS"), //$NON-NLS-1$ IAction.AS_CHECK_BOX) { @Override public void run() { TraditionalRendering.this.fRendering.setPaneVisible( Rendering.PANE_ADDRESS, isChecked()); } }; displayAddressPaneAction.setChecked(this.fRendering .getPaneVisible(Rendering.PANE_ADDRESS)); // display hex final Action displayBinaryPaneAction = new Action( TraditionalRenderingMessages .getString("TraditionalRendering.BINARY"), //$NON-NLS-1$ IAction.AS_CHECK_BOX) { @Override public void run() { TraditionalRendering.this.fRendering.setPaneVisible( Rendering.PANE_BINARY, isChecked()); } }; displayBinaryPaneAction.setChecked(this.fRendering .getPaneVisible(Rendering.PANE_BINARY)); // display text final Action displayTextPaneAction = new Action( TraditionalRenderingMessages .getString("TraditionalRendering.TEXT"), //$NON-NLS-1$ IAction.AS_CHECK_BOX) { @Override public void run() { TraditionalRendering.this.fRendering.setPaneVisible( Rendering.PANE_TEXT, isChecked()); } }; displayTextPaneAction.setChecked(this.fRendering .getPaneVisible(Rendering.PANE_TEXT)); // display size final Action displaySize1BytesAction = new Action( TraditionalRenderingMessages .getString("TraditionalRendering.1_BYTE"), //$NON-NLS-1$ IAction.AS_RADIO_BUTTON) { @Override public void run() { TraditionalRendering.this.fRendering.setBytesPerColumn(1); } }; displaySize1BytesAction .setChecked(this.fRendering.getBytesPerColumn() == 1); final Action displaySize2BytesAction = new Action( TraditionalRenderingMessages .getString("TraditionalRendering.2_BYTES"), IAction.AS_RADIO_BUTTON) //$NON-NLS-1$ { @Override public void run() { TraditionalRendering.this.fRendering.setBytesPerColumn(2); } }; displaySize2BytesAction .setChecked(this.fRendering.getBytesPerColumn() == 2); final Action displaySize4BytesAction = new Action( TraditionalRenderingMessages .getString("TraditionalRendering.4_BYTES"), IAction.AS_RADIO_BUTTON) //$NON-NLS-1$ { @Override public void run() { TraditionalRendering.this.fRendering.setBytesPerColumn(4); } }; displaySize4BytesAction .setChecked(this.fRendering.getBytesPerColumn() == 4); final Action displaySize8BytesAction = new Action( TraditionalRenderingMessages .getString("TraditionalRendering.8_BYTES"), IAction.AS_RADIO_BUTTON) //$NON-NLS-1$ { @Override public void run() { TraditionalRendering.this.fRendering.setBytesPerColumn(8); } }; displaySize8BytesAction .setChecked(this.fRendering.getBytesPerColumn() == 8); // text / unicode ? final Action displayCharactersISO8859Action = new Action( TraditionalRenderingMessages .getString("TraditionalRendering.ISO-8859-1"), //$NON-NLS-1$ IAction.AS_RADIO_BUTTON) { @Override public void run() { TraditionalRendering.this.fRendering .setTextMode(Rendering.TEXT_ISO_8859_1); } }; displayCharactersISO8859Action.setChecked(this.fRendering .getTextMode() == Rendering.TEXT_ISO_8859_1); final Action displayCharactersUSASCIIAction = new Action( TraditionalRenderingMessages .getString("TraditionalRendering.USASCII"), //$NON-NLS-1$ IAction.AS_RADIO_BUTTON) { @Override public void run() { TraditionalRendering.this.fRendering .setTextMode(Rendering.TEXT_USASCII); } }; displayCharactersUSASCIIAction.setChecked(this.fRendering .getTextMode() == Rendering.TEXT_USASCII); final Action displayCharactersUTF8Action = new Action( TraditionalRenderingMessages .getString("TraditionalRendering.UTF8"), IAction.AS_RADIO_BUTTON) //$NON-NLS-1$ { @Override public void run() { TraditionalRendering.this.fRendering .setTextMode(Rendering.TEXT_UTF8); } }; displayCharactersUTF8Action.setChecked(this.fRendering .getTextMode() == Rendering.TEXT_UTF8); // final Action displayCharactersUTF16Action = new Action( // TraditionalRenderingMessages // .getString("TraditionalRendering.UTF16"), IAction.AS_RADIO_BUTTON) //$NON-NLS-1$ // { // @Override // public void run() // { // TraditionalRendering.this.fRendering // .setTextMode(Rendering.TEXT_UTF16); // } // }; // displayCharactersUTF16Action.setChecked(this.fRendering // .getTextMode() == Rendering.TEXT_UTF16); // endian displayEndianBigAction = new Action( TraditionalRenderingMessages .getString("TraditionalRendering.BIG"), //$NON-NLS-1$ IAction.AS_RADIO_BUTTON) { @Override public void run() { TraditionalRendering.this.fRendering .setDisplayLittleEndian(false); } }; displayEndianBigAction.setChecked(!this.fRendering.isTargetLittleEndian()); displayEndianLittleAction = new Action( TraditionalRenderingMessages .getString("TraditionalRendering.LITTLE"), //$NON-NLS-1$ IAction.AS_RADIO_BUTTON) { @Override public void run() { TraditionalRendering.this.fRendering .setDisplayLittleEndian(true); } }; displayEndianLittleAction.setChecked(this.fRendering.isTargetLittleEndian()); // radix final Action displayRadixHexAction = new Action( TraditionalRenderingMessages .getString("TraditionalRendering.HEX"), //$NON-NLS-1$ IAction.AS_RADIO_BUTTON) { @Override public void run() { TraditionalRendering.this.fRendering .setRadix(Rendering.RADIX_HEX); } }; displayRadixHexAction .setChecked(this.fRendering.getRadix() == Rendering.RADIX_HEX); final Action displayRadixDecSignedAction = new Action( TraditionalRenderingMessages .getString("TraditionalRendering.DECIMAL_SIGNED"), IAction.AS_RADIO_BUTTON) //$NON-NLS-1$ { @Override public void run() { TraditionalRendering.this.fRendering .setRadix(Rendering.RADIX_DECIMAL_SIGNED); } }; displayRadixDecSignedAction .setChecked(this.fRendering.getRadix() == Rendering.RADIX_DECIMAL_SIGNED); final Action displayRadixDecUnsignedAction = new Action( TraditionalRenderingMessages .getString("TraditionalRendering.DECIMAL_UNSIGNED"), IAction.AS_RADIO_BUTTON) //$NON-NLS-1$ { @Override public void run() { TraditionalRendering.this.fRendering .setRadix(Rendering.RADIX_DECIMAL_UNSIGNED); } }; displayRadixDecUnsignedAction .setChecked(this.fRendering.getRadix() == Rendering.RADIX_DECIMAL_UNSIGNED); final Action displayRadixOctAction = new Action( TraditionalRenderingMessages .getString("TraditionalRendering.OCTAL"), //$NON-NLS-1$ IAction.AS_RADIO_BUTTON) { @Override public void run() { TraditionalRendering.this.fRendering .setRadix(Rendering.RADIX_OCTAL); } }; displayRadixOctAction .setChecked(this.fRendering.getRadix() == Rendering.RADIX_OCTAL); final Action displayRadixBinAction = new Action( TraditionalRenderingMessages .getString("TraditionalRendering.BINARY"), //$NON-NLS-1$ IAction.AS_RADIO_BUTTON) { @Override public void run() { TraditionalRendering.this.fRendering .setRadix(Rendering.RADIX_BINARY); } }; displayRadixBinAction .setChecked(this.fRendering.getRadix() == Rendering.RADIX_BINARY); final Action displayColumnCountAuto = new Action( TraditionalRenderingMessages .getString("TraditionalRendering.COLUMN_COUNT_AUTO"), //$NON-NLS-1$ IAction.AS_RADIO_BUTTON) { @Override public void run() { TraditionalRendering.this.fRendering.setColumnsSetting(Rendering.COLUMNS_AUTO_SIZE_TO_FIT); } }; displayColumnCountAuto.setChecked(fRendering.getColumnsSetting() == Rendering.COLUMNS_AUTO_SIZE_TO_FIT); final Action[] displayColumnCounts = new Action[MAX_MENU_COLUMN_COUNT]; for(int i = 0, j = 1; i < MAX_MENU_COLUMN_COUNT; i++, j*=2) { final int finali = j; displayColumnCounts[i] = new Action( TraditionalRenderingMessages .getString("TraditionalRendering.COLUMN_COUNT_" + finali), //$NON-NLS-1$ IAction.AS_RADIO_BUTTON) { @Override public void run() { TraditionalRendering.this.fRendering.setColumnsSetting(finali); } }; displayColumnCounts[i].setChecked(fRendering.getColumnsSetting() == finali); } final Action displayColumnCountCustomValue = new Action("", IAction.AS_RADIO_BUTTON) //$NON-NLS-1$ { @Override public void run() { } }; final Action displayColumnCountCustom = new Action( TraditionalRenderingMessages .getString("TraditionalRendering.COLUMN_COUNT_CUSTOM"), //$NON-NLS-1$ IAction.AS_RADIO_BUTTON) { @Override public void run() { InputDialog inputDialog = new InputDialog( fRendering.getShell(), "Set Column Count", //$NON-NLS-1$ "Please enter column count", //$NON-NLS-1$ "", //$NON-NLS-1$ new IInputValidator() { public String isValid(String input) { try { int i= Integer.parseInt(input); if (i <= 0) return "Please enter a positive integer"; //$NON-NLS-1$ if (i > 200) return "Please enter a positive integer not greater than 200"; //$NON-NLS-1$ } catch (NumberFormatException x) { return "Please enter a positive integer"; //$NON-NLS-1$ } return null; } } ); if (inputDialog.open() != Window.OK) { this.setChecked(false); int currentColumnSetting = TraditionalRendering.this.fRendering.getColumnsSetting(); if(currentColumnSetting == Rendering.COLUMNS_AUTO_SIZE_TO_FIT) displayColumnCountAuto.setChecked(true); else { boolean currentCountIsCustom = true; for(int i = 0, j = 1; i < MAX_MENU_COLUMN_COUNT && currentCountIsCustom; i++, j*=2) { currentCountIsCustom = (j != fRendering.getColumnsSetting()); if(j == fRendering.getColumnsSetting()) displayColumnCounts[i].setChecked(true); } if(currentCountIsCustom) displayColumnCountCustomValue.setChecked(true); } return; } int newColumnCount = -1; try { newColumnCount = Integer.parseInt(inputDialog.getValue()); } catch (NumberFormatException x) { assert false; } boolean customIsOneOfStandardListChoices = false; for(int i = 0, j = 1; i < MAX_MENU_COLUMN_COUNT; i++, j*=2) { if ( newColumnCount == j ) { customIsOneOfStandardListChoices = true; TraditionalRendering.this.fRendering.setColumnsSetting(newColumnCount); this.setChecked(false); displayColumnCountCustomValue.setChecked(false); displayColumnCounts[i].setChecked(true); break; } } if ( ! customIsOneOfStandardListChoices ) { TraditionalRendering.this.fRendering.setColumnsSetting(newColumnCount); this.setChecked(false); displayColumnCountCustomValue.setChecked(true); displayColumnCountCustomValue.setText(Integer.valueOf( fRendering.getColumnsSetting()).toString()); } } }; getPopupMenuManager().addMenuListener(new IMenuListener() { public void menuAboutToShow(IMenuManager manager) { manager.add(new Separator()); MenuManager sub = new MenuManager( TraditionalRenderingMessages .getString("TraditionalRendering.PANES")); //$NON-NLS-1$ sub.add(displayAddressPaneAction); sub.add(displayBinaryPaneAction); sub.add(displayTextPaneAction); manager.add(sub); // if there is cross reference info types available // add Actions to allow the user to toggle the visibility for each of them if (isShowCrossRefInfoGlobalPref()) { Action[] dynamicActions = fRendering.getDynamicActions(); if (dynamicActions != null) { sub = new MenuManager(TraditionalRenderingMessages .getString("TraditionalRenderingPreferencePage_ShowCrossRefInfo_Label")); //$NON-NLS-1$ for (Action action : dynamicActions) { sub.add(action); } manager.add(sub); } } sub = new MenuManager(TraditionalRenderingMessages .getString("TraditionalRendering.ENDIAN")); //$NON-NLS-1$ sub.add(displayEndianBigAction); sub.add(displayEndianLittleAction); manager.add(sub); sub = new MenuManager(TraditionalRenderingMessages .getString("TraditionalRendering.TEXT")); //$NON-NLS-1$ sub.add(displayCharactersISO8859Action); sub.add(displayCharactersUSASCIIAction); sub.add(displayCharactersUTF8Action); //sub.add(displayCharactersUTF16Action); manager.add(sub); sub = new MenuManager(TraditionalRenderingMessages .getString("TraditionalRendering.CELL_SIZE")); //$NON-NLS-1$ sub.add(displaySize1BytesAction); sub.add(displaySize2BytesAction); sub.add(displaySize4BytesAction); sub.add(displaySize8BytesAction); manager.add(sub); sub = new MenuManager(TraditionalRenderingMessages .getString("TraditionalRendering.RADIX")); //$NON-NLS-1$ sub.add(displayRadixHexAction); sub.add(displayRadixDecSignedAction); sub.add(displayRadixDecUnsignedAction); sub.add(displayRadixOctAction); sub.add(displayRadixBinAction); manager.add(sub); sub = new MenuManager(TraditionalRenderingMessages .getString("TraditionalRendering.COLUMN_COUNT")); //$NON-NLS-1$ sub.add(displayColumnCountAuto); for(int i = 0; i < displayColumnCounts.length; i++) sub.add(displayColumnCounts[i]); boolean currentCountIsCustom = fRendering.getColumnsSetting() != 0; for(int i = 0, j = 1; i < MAX_MENU_COLUMN_COUNT && currentCountIsCustom; i++, j*=2) currentCountIsCustom = (j != fRendering.getColumnsSetting()); if(currentCountIsCustom) sub.add(displayColumnCountCustomValue); sub.add(displayColumnCountCustom); manager.add(sub); final Action updateAlwaysAction = new Action( TraditionalRenderingMessages .getString("TraditionalRendering.UPDATE_ALWAYS"), //$NON-NLS-1$ IAction.AS_RADIO_BUTTON) { @Override public void run() { fRendering.setUpdateMode(Rendering.UPDATE_ALWAYS); } }; updateAlwaysAction.setChecked(fRendering.getUpdateMode() == Rendering.UPDATE_ALWAYS); final Action updateOnBreakpointAction = new Action( TraditionalRenderingMessages .getString("TraditionalRendering.UPDATE_ON_BREAKPOINT"), //$NON-NLS-1$ IAction.AS_RADIO_BUTTON) { @Override public void run() { fRendering.setUpdateMode(Rendering.UPDATE_ON_BREAKPOINT); } }; updateOnBreakpointAction.setChecked(fRendering.getUpdateMode() == Rendering.UPDATE_ON_BREAKPOINT); final Action updateManualAction = new Action( TraditionalRenderingMessages .getString("TraditionalRendering.UPDATE_MANUAL"), //$NON-NLS-1$ IAction.AS_RADIO_BUTTON) { @Override public void run() { fRendering.setUpdateMode(Rendering.UPDATE_MANUAL); } }; updateManualAction.setChecked(fRendering.getUpdateMode() == Rendering.UPDATE_MANUAL); sub = new MenuManager(TraditionalRenderingMessages .getString("TraditionalRendering.UPDATEMODE")); //$NON-NLS-1$ sub.add(updateAlwaysAction); sub.add(updateOnBreakpointAction); sub.add(updateManualAction); manager.add(sub); manager.add(new Separator()); BigInteger start = fRendering.getSelection().getStart(); BigInteger end = fRendering.getSelection().getEnd(); copyBinaryAction.setEnabled(start != null && end != null); copyTextAction.setEnabled(start != null && end != null); sub = new MenuManager(TraditionalRenderingMessages.getString("TraditionalRendering.COPY")); //$NON-NLS-1$ sub.add(copyBinaryAction); sub.add(copyTextAction); sub.add(copyAddressAction); sub.add(copyAllAction); manager.add(sub); copyBinaryAction.checkStatus(); copyTextAction.checkStatus(); copyAddressAction.checkStatus(); copyAllAction.checkStatus(); manager.add(gotoBaseAddressAction); manager.add(goToAddressAction); manager.add(refreshAction); manager.add(new Separator()); manager.add(new Separator( IWorkbenchActionConstants.MB_ADDITIONS)); } }); } public Control getControl() { return this.fRendering; } // selection is terminology for caret position public BigInteger getSelectedAddress() { IMemorySelection selection = fRendering.getSelection(); if (selection == null || selection.getStart() == null) return fRendering.getCaretAddress(); return selection.getStartLow(); } public MemoryByte[] getSelectedAsBytes() { try { // default to the caret address and the cell count size BigInteger startAddr = fRendering.getCaretAddress(); int byteCount = fRendering.getBytesPerColumn(); // Now see if there's a selection IMemorySelection selection = fRendering.getSelection(); if (selection != null && selection.getStart() != null) { // The implementation is such that just having a caret somewhere // (without multiple cells being selected) constitutes a selection, // except for when the rendering is in its initial state. I.e., // just because we get here doesn't mean the user has selected more // than one cell. startAddr = getSelectedAddress(); if (selection.getHigh() != null) { byteCount = selection.getHigh().subtract(selection.getLow()).intValue() * fRendering.getAddressableSize(); } } return fRendering.getViewportCache().getBytes(startAddr, byteCount); } catch(DebugException de) { // FIXME log? return null; } } public void goToAddress(final BigInteger address) throws DebugException { Display.getDefault().asyncExec(new Runnable(){ public void run() { fRendering.gotoAddress(address); } }); } protected void setTargetMemoryLittleEndian(boolean littleEndian) { // once we actually read memory we can determine the // endianess and need to set these actions accordingly. displayEndianBigAction.setChecked(!littleEndian); displayEndianLittleAction.setChecked(littleEndian); // when target endian changes, force display endian to track. // user can then change display endian if desired. fRendering.setDisplayLittleEndian(littleEndian); } /* (non-Javadoc) * @see org.eclipse.core.runtime.PlatformObject#getAdapter(java.lang.Class) */ @Override @SuppressWarnings({ "unchecked" }) public <T> T getAdapter(Class<T> adapter) { if(adapter == IWorkbenchAdapter.class) { if(this.fWorkbenchAdapter == null) { this.fWorkbenchAdapter = new IWorkbenchAdapter() { public Object[] getChildren(Object o) { return new Object[0]; } public ImageDescriptor getImageDescriptor(Object object) { return null; } public String getLabel(Object o) { return TraditionalRenderingMessages .getString("TraditionalRendering.RENDERING_NAME"); //$NON-NLS-1$ } public Object getParent(Object o) { return null; } }; } return (T) this.fWorkbenchAdapter; } if (adapter == IMemoryBlockConnection.class) { if (fConnection == null) { fConnection = new IMemoryBlockConnection() { public void update() { // update UI asynchronously Display display = TraditionalRenderingPlugin.getDefault().getWorkbench().getDisplay(); display.asyncExec(new Runnable() { public void run() { try { if(fBigBaseAddress != TraditionalRendering.this.fRendering.getMemoryBlock().getBigBaseAddress()) { fBigBaseAddress = TraditionalRendering.this.fRendering.getMemoryBlock().getBigBaseAddress(); TraditionalRendering.this.fRendering.gotoAddress(fBigBaseAddress); } TraditionalRendering.this.fRendering.refresh(); } catch (DebugException e) { } } }); } }; } return (T) fConnection; } return super.getAdapter(adapter); } public void resetRendering() throws DebugException { fRendering.gotoAddress(fRendering.fBaseAddress); } /* (non-Javadoc) * @see org.eclipse.cdt.debug.internal.core.model.provisional.IMemoryRenderingViewportProvider#getViewportAddress() */ public BigInteger getViewportAddress() { return fRendering.getViewportStartAddress(); } } class CopyBinaryAction extends CopyAction { public CopyBinaryAction(Rendering rendering) { super(rendering, CopyType.BINARY, DND.CLIPBOARD); setText(TraditionalRenderingMessages.getString("TraditionalRendering.BINARY")); //$NON-NLS-1$ setToolTipText(TraditionalRenderingMessages.getString("TraditionalRendering.COPY_SELECTED_DATA")); //$NON-NLS-1$ } } class CopyTextAction extends CopyAction { public CopyTextAction(Rendering rendering) { super(rendering, CopyType.TEXT, DND.CLIPBOARD); setText(TraditionalRenderingMessages.getString("TraditionalRendering.TEXT")); //$NON-NLS-1$ setToolTipText(TraditionalRenderingMessages.getString("TraditionalRendering.COPY_SELECTED_DATA_TEXT")); //$NON-NLS-1$ } } class CopyAddressAction extends CopyAction { public CopyAddressAction(Rendering rendering) { super(rendering, CopyType.ADDRESS, DND.CLIPBOARD); setText(TraditionalRenderingMessages.getString("TraditionalRendering.ADDRESS")); //$NON-NLS-1$ setToolTipText(TraditionalRenderingMessages.getString("TraditionalRendering.COPY_SELECTED_ADDDESS")); //$NON-NLS-1$ } } class CopyAllAction extends CopyAction { public CopyAllAction(Rendering rendering) { super(rendering, CopyType.ALL, DND.CLIPBOARD); setText(TraditionalRenderingMessages.getString("TraditionalRendering.ALL")); //$NON-NLS-1$ setToolTipText(TraditionalRenderingMessages.getString("TraditionalRendering.COPY_ALL")); //$NON-NLS-1$ } } class CopyDefaultAction extends CopyAction { public CopyDefaultAction(Rendering rendering, int clipType) { super(rendering, CopyType.DEFAULT, clipType); setText(TraditionalRenderingMessages.getString("TraditionalRendering.DEFAULT")); //$NON-NLS-1$ } } abstract class CopyAction extends Action { // TODO for the sake of large copies, this action should probably read in // blocks on a Job. public enum CopyType {UNDEFINED, BINARY, TEXT, ADDRESS, ALL, DEFAULT}; private Rendering fRendering; private int fClipboardType = DND.CLIPBOARD; private CopyType fCopyType = CopyType.ALL; static private CopyType fDefaultCopyType = CopyType.UNDEFINED; public CopyAction(Rendering rendering, CopyType copyType, int clipboardType) { super(); fCopyType = copyType; fClipboardType = clipboardType; fRendering = rendering; if (fDefaultCopyType == CopyType.UNDEFINED) { IPreferenceStore store = TraditionalRenderingPlugin.getDefault().getPreferenceStore(); String defaultString = store.getString(TraditionalRenderingPreferenceConstants.MEM_DEFAULT_COPY_ACTION); if (defaultString.length() > 0) { try { fDefaultCopyType = Enum.valueOf(CopyType.class, defaultString); } catch (Exception e) { fDefaultCopyType = CopyType.ALL; } } else fDefaultCopyType = CopyType.ALL; } } public void checkStatus() { setChecked(fDefaultCopyType == fCopyType); } @Override public void run() { final String PANE_SPACING = " "; //$NON-NLS-1$ Clipboard clip = null; try { if (fCopyType == CopyType.DEFAULT) fCopyType = fDefaultCopyType; if (fCopyType != fDefaultCopyType) { IPreferenceStore store = TraditionalRenderingPlugin.getDefault().getPreferenceStore(); store.putValue(TraditionalRenderingPreferenceConstants.MEM_DEFAULT_COPY_ACTION, fCopyType.name()); } fDefaultCopyType = fCopyType; boolean copyAddress = fRendering.getPaneVisible(Rendering.PANE_ADDRESS) && (fCopyType == CopyType.ADDRESS || fCopyType == CopyType.ALL); boolean copyBinary = fRendering.getPaneVisible(Rendering.PANE_BINARY) && (fCopyType == CopyType.BINARY || fCopyType == CopyType.ALL); boolean copyText = fRendering.getPaneVisible(Rendering.PANE_TEXT) && (fCopyType == CopyType.TEXT || fCopyType == CopyType.ALL); clip = new Clipboard(fRendering.getDisplay()); BigInteger start = fRendering.getSelection().getStart(); BigInteger end = fRendering.getSelection().getEnd(); // end will be null when there is nothing selected if (end == null) { if (fCopyType == CopyType.ADDRESS) fRendering.copyAddressToClipboard(); return; } if(start.compareTo(end) > 0) { // swap start and end BigInteger bigI = end; end = start; start = bigI; } final int radix = fRendering.getRadix(); final int bytesPerColumn = fRendering.getBytesPerColumn(); final boolean isLittleEndian = fRendering.isTargetLittleEndian(); // final int binaryCellWidth = fRendering.getRadixCharacterCount( // radix, bytesPerColumn) + 1; // // final int asciiCellWidth = fRendering.getBytesPerColumn() // / fRendering.getBytesPerCharacter(); // final int combindCellWidths = (fRendering // .getPaneVisible(Rendering.PANE_BINARY) ? binaryCellWidth : 0) // + (fRendering.getPaneVisible(Rendering.PANE_TEXT) ? asciiCellWidth // : 0); final int columns = fRendering.getColumnCount(); int addressableSize = fRendering.getAddressableSize(); assert(addressableSize != 0); int addressesPerColumn = bytesPerColumn/addressableSize; BigInteger lengthToRead = end.subtract(start).multiply(BigInteger.valueOf(addressableSize)); int rows = lengthToRead.divide( BigInteger.valueOf(columns * bytesPerColumn)).intValue(); if(rows * columns * bytesPerColumn < lengthToRead.intValue()) rows++; StringBuilder buffer = new StringBuilder(); for(int row = 0; row < rows; row++) { BigInteger rowAddress = start.add(BigInteger.valueOf(row * columns * addressesPerColumn)); if(copyAddress) { buffer.append(fRendering.getAddressString(rowAddress)); buffer.append(PANE_SPACING); } if(copyBinary) { for(int col = 0; col < columns; col++) { BigInteger cellAddress = rowAddress.add(BigInteger .valueOf(col * addressesPerColumn)); if(cellAddress.compareTo(end) < 0) { try { MemoryByte bytes[] = fRendering.getBytes( cellAddress, bytesPerColumn); buffer.append(fRendering.getRadixText(bytes, radix, isLittleEndian)); } catch(DebugException de) { fRendering .logError( TraditionalRenderingMessages .getString("TraditionalRendering.FAILURE_COPY_OPERATION"), de); //$NON-NLS-1$ return; } } else { for(int i = fRendering.getRadixCharacterCount( radix, bytesPerColumn); i > 0; i--) buffer.append(' '); } if(col != columns - 1) buffer.append(' '); } } if(copyBinary && copyText) { buffer.append(PANE_SPACING); } if(copyText) { for(int col = 0; col < columns; col++) { BigInteger cellAddress = rowAddress.add(BigInteger .valueOf(col * addressesPerColumn)); if(cellAddress.compareTo(end) < 0) { try { MemoryByte bytes[] = fRendering .getBytes(cellAddress, fRendering .getBytesPerColumn()); buffer.append(fRendering.formatText(bytes, isLittleEndian, fRendering.getTextMode())); } catch(DebugException de) { fRendering .logError( TraditionalRenderingMessages .getString("TraditionalRendering.FAILURE_COPY_OPERATION"), de); //$NON-NLS-1$ return; } } else { } } } buffer.append("\n"); //$NON-NLS-1$ } if(buffer.length() > 0) { TextTransfer plainTextTransfer = TextTransfer.getInstance(); clip.setContents(new Object[] { buffer.toString() }, new Transfer[] { plainTextTransfer }, fClipboardType); } } finally { checkStatus(); if(clip != null) { clip.dispose(); } } } }