diff --git a/memory/org.eclipse.cdt.debug.ui.memory.memorybrowser/src/org/eclipse/cdt/debug/ui/memory/memorybrowser/MemoryBrowser.java b/memory/org.eclipse.cdt.debug.ui.memory.memorybrowser/src/org/eclipse/cdt/debug/ui/memory/memorybrowser/MemoryBrowser.java index 9f3eaf7e0a9..9dfdd2dff11 100644 --- a/memory/org.eclipse.cdt.debug.ui.memory.memorybrowser/src/org/eclipse/cdt/debug/ui/memory/memorybrowser/MemoryBrowser.java +++ b/memory/org.eclipse.cdt.debug.ui.memory.memorybrowser/src/org/eclipse/cdt/debug/ui/memory/memorybrowser/MemoryBrowser.java @@ -1,1395 +1,1395 @@ -/******************************************************************************* - * Copyright (c) 2009, 2015 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 - * Ted R Williams (Mentor Graphics, Inc.) - address space enhancements - * Patrick Chuong (Texas Instruments) - Pin and Clone Supports (331781) - *******************************************************************************/ - -package org.eclipse.cdt.debug.ui.memory.memorybrowser; - -import java.lang.reflect.Type; -import java.math.BigInteger; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import org.eclipse.cdt.debug.core.model.provisional.IMemoryRenderingViewportProvider; -import org.eclipse.cdt.debug.core.model.provisional.IMemorySpaceAwareMemoryBlockRetrieval; -import org.eclipse.cdt.debug.internal.core.CRequest; -import org.eclipse.cdt.debug.ui.memory.memorybrowser.api.IMemoryBrowser; -import org.eclipse.cdt.debug.ui.provisional.IRepositionableMemoryRendering2; -import org.eclipse.core.runtime.CoreException; -import org.eclipse.core.runtime.IAdaptable; -import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.core.runtime.IStatus; -import org.eclipse.core.runtime.SafeRunner; -import org.eclipse.core.runtime.Status; -import org.eclipse.debug.core.DebugEvent; -import org.eclipse.debug.core.DebugException; -import org.eclipse.debug.core.DebugPlugin; -import org.eclipse.debug.core.IDebugEventSetListener; -import org.eclipse.debug.core.ILaunch; -import org.eclipse.debug.core.model.IDebugTarget; -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.IMemoryBlockRetrievalExtension; -import org.eclipse.debug.core.model.MemoryByte; -import org.eclipse.debug.internal.ui.memory.MemoryRenderingManager; -import org.eclipse.debug.ui.DebugUITools; -import org.eclipse.debug.ui.contexts.DebugContextEvent; -import org.eclipse.debug.ui.contexts.IDebugContextListener; -import org.eclipse.debug.ui.contexts.IDebugContextService; -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.IMemoryRenderingSynchronizationService; -import org.eclipse.debug.ui.memory.IMemoryRenderingType; -import org.eclipse.debug.ui.memory.IRepositionableMemoryRendering; -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.IToolBarManager; -import org.eclipse.jface.action.MenuManager; -import org.eclipse.jface.action.Separator; -import org.eclipse.jface.dialogs.IDialogConstants; -import org.eclipse.jface.preference.IPreferenceStore; -import org.eclipse.jface.resource.ColorRegistry; -import org.eclipse.jface.resource.JFaceResources; -import org.eclipse.jface.util.IPropertyChangeListener; -import org.eclipse.jface.util.PropertyChangeEvent; -import org.eclipse.jface.util.SafeRunnable; -import org.eclipse.jface.viewers.IBasicPropertyConstants; -import org.eclipse.jface.viewers.ILabelDecorator; -import org.eclipse.jface.viewers.ISelection; -import org.eclipse.jface.viewers.ISelectionChangedListener; -import org.eclipse.jface.viewers.ISelectionProvider; -import org.eclipse.jface.viewers.SelectionChangedEvent; -import org.eclipse.jface.viewers.StructuredSelection; -import org.eclipse.swt.SWT; -import org.eclipse.swt.custom.CTabFolder; -import org.eclipse.swt.custom.CTabFolder2Adapter; -import org.eclipse.swt.custom.CTabFolderEvent; -import org.eclipse.swt.custom.CTabItem; -import org.eclipse.swt.custom.StackLayout; -import org.eclipse.swt.dnd.DND; -import org.eclipse.swt.dnd.DropTarget; -import org.eclipse.swt.dnd.DropTargetAdapter; -import org.eclipse.swt.dnd.DropTargetEvent; -import org.eclipse.swt.dnd.TextTransfer; -import org.eclipse.swt.dnd.Transfer; -import org.eclipse.swt.events.DisposeEvent; -import org.eclipse.swt.events.DisposeListener; -import org.eclipse.swt.events.SelectionAdapter; -import org.eclipse.swt.events.SelectionEvent; -import org.eclipse.swt.events.SelectionListener; -import org.eclipse.swt.graphics.Color; -import org.eclipse.swt.layout.FormAttachment; -import org.eclipse.swt.layout.FormData; -import org.eclipse.swt.layout.FormLayout; -import org.eclipse.swt.widgets.Combo; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Control; -import org.eclipse.swt.widgets.Display; -import org.eclipse.swt.widgets.Label; -import org.eclipse.swt.widgets.Menu; -import org.eclipse.ui.IActionBars; -import org.eclipse.ui.IViewSite; -import org.eclipse.ui.IWorkbenchActionConstants; -import org.eclipse.ui.IWorkbenchPreferenceConstants; -import org.eclipse.ui.PlatformUI; -import org.eclipse.ui.part.ViewPart; -import org.eclipse.ui.progress.UIJob; -import org.eclipse.ui.progress.WorkbenchJob; - -/** - * A lightweight rendering container. - * - * Debug model requirements: - * IMemoryBlockExtension (IMemoryBlock not supported) - * IMemoryBlockRetrievalExtension - *

- * Rendering requirements: - * IRepositionableMemoryRendering - * - */ - -@SuppressWarnings("restriction") /* Debug Platform's Flexible hierarchy is still provisional */ - -public class MemoryBrowser extends ViewPart implements IDebugContextListener, IMemoryRenderingSite, IDebugEventSetListener, IMemoryBrowser -{ - public static final String ID = "org.eclipse.cdt.debug.ui.memory.memorybrowser.MemoryBrowser"; //$NON-NLS-1$ - - protected StackLayout fStackLayout; - private Composite fRenderingsComposite; - private GoToAddressBarWidget fGotoAddressBar; - private DropTarget fDropTarget; - private Control fGotoAddressBarControl; - private Combo fGotoMemorySpaceControl; - private Label fUnsupportedLabel; - private Composite fMainComposite; - private String defaultRenderingTypeId = null; - private IMemoryRendering fActiveRendering; - - /** - * Every memory retrieval object is given its own tab folder. Typically all - * elements of a "process" (process, threads, frames) have the same - * retrieval object. - */ - private Map fContextFolders = new HashMap (); - - private List fCurrentContainers = new ArrayList(); - - private final static String KEY_CONTEXT = "CONTEXT"; //$NON-NLS-1$ - private final static String KEY_CONTAINER = "CONTAINER"; //$NON-NLS-1$ - private final static String KEY_RENDERING_TYPE = "RENDERING_TYPE"; //$NON-NLS-1$ - - /** - * Property we attach to a CTabItem to track the retrieval object we use to - * create memory blocks on the tab's behalf. Value is an - * {@link IMemoryBlockRetrieval} - */ - private final static String KEY_RETRIEVAL = "RETRIEVAL"; //$NON-NLS-1$ - - /** - * Property we attach to a CTabItem to track the memory space it's - * associated with. Value is a memory space ID (String), or null if n/a - */ - private final static String KEY_MEMORY_SPACE = "MEMORY_SPACE"; //$NON-NLS-1$ - - /** - * Property we attach to a CTabItem to track what renderings have been - * created on its behalf. There will be more than one rendering if the - * backend supports memory spaces, there is more than one such space, and - * the user has viewed memory in multiple memory spaces within that tab. - * The value is a map of memory-space-ID==>IMemoryRendering. - */ - private final static String KEY_RENDERINGS = "RENDERINGS"; //$NON-NLS-1$ - - /** - * Property we attach to a CTabItem to track the active rendering in the - * tab. The value is an IMemoryRendering. - */ - private final static String KEY_RENDERING = "RENDERING"; //$NON-NLS-1$ - - /** - * Property we attach to a CTabItem to track what memory blocks have been - * created on its behalf. There can be multiple when dealing with memory - * spaces, for the same reasons there can be multiple renderings. There is a - * 1:1:1 association between rendering, block and memory space. The value is - * a list of IMemoryBlockExtension - */ - private final static String KEY_MEMORY_BLOCKS = "MEMORY_BLOCKS"; //$NON-NLS-1$ - - /** - * Property we attach to a CTabItem to track the expression we used to - * create memory blocks on the tab's behalf. Value is a String. - */ - private final static String KEY_EXPRESSION = "EXPRESSION"; //$NON-NLS-1$ - - /** - * Property we attach to a CTabItem to track the address associated with - * KEY_EXPRESSION. Value is a BigInteger - */ - private final static String KEY_EXPRESSION_ADDRESS = "EXPRESSION_ADDRESS"; //$NON-NLS-1$ - - public static final String PREF_DEFAULT_RENDERING = "org.eclipse.cdt.debug.ui.memory.memorybrowser.defaultRendering"; //$NON-NLS-1$ - - /** - * The text we use in the combobox to represent no memory space specification - */ - private static final String NA_MEMORY_SPACE_ID = " -----"; //$NON-NLS-1$ - - public MemoryBrowser() { - } - - public Control getControl() { - return fMainComposite; - } - - /* - * Handles DnD from other views. - */ - private class MemoryDropAdapter extends DropTargetAdapter { - /* - * @see org.eclipse.swt.dnd.DropTargetListener#drop(org.eclipse.swt.dnd.DropTargetEvent) - */ - @Override - public void drop(final DropTargetEvent event) { - if (TextTransfer.getInstance().isSupportedType( event.currentDataType )) { - if ( event.data instanceof String ) { - fGotoAddressBar.setExpressionText( (String) event.data ); - performGo(false); - } - } - } - - /* - * @see org.eclipse.swt.dnd.DropTargetListener#dragEnter(org.eclipse.swt.dnd.DropTargetEvent) - */ - @Override - public void dragEnter(DropTargetEvent event) { - event.detail = DND.DROP_COPY; - event.feedback = DND.FEEDBACK_NONE; - } - } - - @Override - public void createPartControl(Composite parent) { - // set default rendering type. use the traditional rendering if available. fallback on first registered type. - // this should eventually be configurable via a preference page. - boolean isDefaultRenderingAvailable = false; - IPreferenceStore store = MemoryBrowserPlugin.getDefault().getPreferenceStore(); - String defaultRendering = store.getString(PREF_DEFAULT_RENDERING); - if(defaultRendering == null || defaultRendering.trim().length() == 0) - { - defaultRendering = "org.eclipse.cdt.debug.ui.memory.traditional.TraditionalRendering"; //$NON-NLS-1$ - } - - IMemoryRenderingType[] types = getRenderingTypes(); - for(final IMemoryRenderingType type : types) - { - if(type.getId().equals(defaultRendering)) - { - isDefaultRenderingAvailable = true; - break; - } - } - if(isDefaultRenderingAvailable) - defaultRenderingTypeId = defaultRendering; - else if(types.length > 0) - defaultRenderingTypeId = types[0].getId(); - - getSite().setSelectionProvider(new SelectionProviderAdapter()); - - fMainComposite = new Composite(parent, SWT.NONE); - - FormLayout layout = new FormLayout(); - layout.spacing = 0; - fMainComposite.setLayout(layout); - - fGotoMemorySpaceControl = new Combo(fMainComposite, SWT.DROP_DOWN | SWT.READ_ONLY); - fGotoAddressBar = new GoToAddressBarWidget(); - fGotoAddressBarControl = fGotoAddressBar.createControl(fMainComposite); - - if (fDropTarget == null) { - fDropTarget = new DropTarget(fGotoAddressBarControl, DND.DROP_COPY | DND.DROP_DEFAULT); - fDropTarget.setTransfer( new Transfer[] { TextTransfer.getInstance() }); - fDropTarget.addDropListener(new MemoryDropAdapter()); - } - - fGotoAddressBar.getButton(IDialogConstants.OK_ID).addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - performGo(false); - } - }); - - fGotoAddressBar.getButton(GoToAddressBarWidget.ID_GO_NEW_TAB).addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - performGo(true); - } - }); - - fGotoAddressBar.getExpressionWidget().addSelectionListener(new SelectionAdapter() { - @Override - public void widgetDefaultSelected(SelectionEvent e) { - performGo(false); - } - @Override - public void widgetSelected(SelectionEvent e) { - performGo(false); - } - }); - - fGotoMemorySpaceControl.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - if(fGotoMemorySpaceControl.getItemCount() >= 2) { - final CTabFolder activeFolder = (CTabFolder) fStackLayout.topControl; - if (activeFolder != null) { - final Object context = activeFolder.getData(KEY_CONTEXT); - fGotoAddressBar.loadSavedExpressions(context, fGotoMemorySpaceControl.getText()); - performGo(false); - } - } - } - }); - - - FormData data = new FormData(); - data.top = new FormAttachment(0); - data.left = new FormAttachment(fGotoMemorySpaceControl); - data.right = new FormAttachment(100); - fGotoAddressBarControl.setLayoutData(data); - - fRenderingsComposite = new Composite(fMainComposite, SWT.NONE); - data = new FormData(); - data.top = new FormAttachment(fGotoAddressBarControl); - data.left = new FormAttachment(0); - data.right = new FormAttachment(100); - data.bottom = new FormAttachment(100); - fRenderingsComposite.setLayoutData(data); - - fStackLayout = new StackLayout(); - - fRenderingsComposite.setLayout(fStackLayout); - - fUnsupportedLabel = new Label(fRenderingsComposite, SWT.NONE); - fUnsupportedLabel.setText(""); //$NON-NLS-1$ - - handleUnsupportedSelection(); - - PlatformUI.getWorkbench().getHelpSystem().setHelp(fMainComposite, MemoryBrowserPlugin.PLUGIN_ID); - makeActions(); - hookContextMenu(); - contributeToActionBars(); - - Object selection = null; - IDebugContextService contextService = - DebugUITools.getDebugContextManager().getContextService(getSite().getWorkbenchWindow()); - if (isBug145635Patched()) { - String presentationContextId = getPresentationContextId(); - contextService.addDebugContextListener(this, presentationContextId); - selection = contextService.getActiveContext(presentationContextId); - } else { - DebugUITools.addPartDebugContextListener(getSite(), this); - selection = contextService.getActiveContext(getSite().getId(), ((IViewSite)getSite()).getSecondaryId()); - } - - DebugPlugin.getDefault().addDebugEventListener(this); - - if(selection instanceof StructuredSelection) - handleDebugContextChanged(((StructuredSelection) selection).getFirstElement()); - } - - private boolean isBug145635Patched() { - Type[] managerTypes = DebugUITools.getDebugContextManager().getClass().getGenericInterfaces(); - for (int i = 0; i < managerTypes.length; i++) { - if (managerTypes[i] instanceof Class) { - Class clazz = (Class)managerTypes[i]; - if ("org.eclipse.debug.ui.contexts.IBug145635Marker".equals(clazz.getName()) ) { //$NON-NLS-1$ - return true; - } - } - } - return false; - } - - /** - * Clears the expression history for the active tab - */ - public void clearExpressionHistoryForActiveTab() { - final CTabFolder activeFolder = (CTabFolder) fStackLayout.topControl; - if (activeFolder != null) { - final Object context = activeFolder.getData(KEY_CONTEXT); - fGotoAddressBar.clearExpressionHistory(context); - } - } - - /** - * Returns the presentation context id for this view. Used to support the - * pin and clone feature patch from bug 145635. - * - * @return context id - */ - private String getPresentationContextId() { - IViewSite site = (IViewSite)getSite(); - return site.getId() + (site.getSecondaryId() != null ? (":" + site.getSecondaryId()) : ""); //$NON-NLS-1$ //$NON-NLS-2$ - } - - @Override - public void dispose() { - if (fDropTarget != null) { - fDropTarget.dispose(); - fDropTarget = null; - } - DebugPlugin.getDefault().removeDebugEventListener(this); - IDebugContextService contextService = - DebugUITools.getDebugContextManager().getContextService(getSite().getWorkbenchWindow()); - if (isBug145635Patched()) { - String presentationContextId = getPresentationContextId(); - contextService.removeDebugContextListener(this, presentationContextId); - } else { - DebugUITools.removePartDebugContextListener(getSite(), this); - } - super.dispose(); - } - - /* (non-Javadoc) - * @see org.eclipse.debug.core.IDebugEventSetListener#handleDebugEvents(org.eclipse.debug.core.DebugEvent[]) - */ - public void handleDebugEvents(DebugEvent[] events) { - for (DebugEvent event: events) { - Object source = event.getSource(); - if (event.getKind() == DebugEvent.TERMINATE && source instanceof IMemoryBlockRetrieval) { - releaseTabFolder((IMemoryBlockRetrieval)source); - } - } - } - - public IMemoryRenderingContainer getContainer(String id) { - return null; - } - - public IMemoryRenderingContainer[] getMemoryRenderingContainers() { - IMemoryRenderingContainer[] containerList = new IMemoryRenderingContainer[fCurrentContainers.size()]; - for ( int idx = 0 ; idx < fCurrentContainers.size() ; idx ++ ) { - containerList[ idx ] = fCurrentContainers.get( idx ); - } - return containerList; - } - - public IMemoryRenderingSynchronizationService getSynchronizationService() { - return null; - } - - private void handleUnsupportedSelection() { - fStackLayout.topControl = fUnsupportedLabel; - if(!fGotoAddressBarControl.isDisposed()) { - fGotoAddressBarControl.setVisible(false); - } - if(!fGotoMemorySpaceControl.isDisposed()) { - fGotoMemorySpaceControl.setVisible(false); - } - } - - private void performGo(boolean inNewTab) { - // Index zero is the 'auto' (n/a) memory space entry, unless the backend - // said we need to force a memory space selection - String memorySpace = null; - if (fGotoMemorySpaceControl.isVisible()) { - memorySpace = fGotoMemorySpaceControl.getText(); - if (memorySpace.equals(NA_MEMORY_SPACE_ID)) { - memorySpace = null; - } - assert (memorySpace == null) || (memorySpace.length() > 0); - } - - String expression = fGotoAddressBar.getExpressionText(); - if (expression.length() > 0) { - final CTabFolder activeFolder = (CTabFolder) fStackLayout.topControl; - Object context = null; - if (activeFolder != null) { - context = activeFolder.getData(KEY_CONTEXT); - } - fGotoAddressBar.addExpressionToHistory(context, expression, memorySpace); - performGo(inNewTab, expression, memorySpace); - } - } - - /* (non-Javadoc) - * @see org.eclipse.cdt.debug.ui.memory.memorybrowser.api.IMemoryBrowser#getActiveRetrieval() - */ - public IMemoryBlockRetrieval getActiveRetrieval() { - final CTabFolder activeFolder = (CTabFolder) fStackLayout.topControl; - if (activeFolder == null) - return null; - - return (IMemoryBlockRetrieval) activeFolder.getData(KEY_RETRIEVAL); - } - - public void performGo(boolean inNewTab, final String expression, final String memorySpaceId) { - final CTabFolder activeFolder = (CTabFolder) fStackLayout.topControl; - if (activeFolder != null) { - final IMemoryBlockRetrieval retrieval = (IMemoryBlockRetrieval) activeFolder.getData(KEY_RETRIEVAL); - final Object context = activeFolder.getData(KEY_CONTEXT); - IMemoryRendering rendering = null; - - CTabItem item = activeFolder.getSelection(); - if (inNewTab || item == null) - { - try { - item = createTab(activeFolder, activeFolder.getSelectionIndex() + 1); - rendering = populateTabWithRendering(item, retrieval, context, memorySpaceId, expression); - fContextFolders.put(retrieval, activeFolder); - activeFolder.setSelection(item); - getSite().getSelectionProvider().setSelection(new StructuredSelection(item.getData(KEY_RENDERING))); - handleTabActivated(item); - } catch (DebugException e1) { - fGotoAddressBar.handleExpressionStatus(new Status(Status.ERROR, MemoryBrowserPlugin.PLUGIN_ID, - Messages.getString("MemoryBrowser.FailedToGoToAddressTitle"), e1)); //$NON-NLS-1$ - if (item != null) { - item.dispose(); - } - return; - } - } else { - // Tab is already in place. However, the user may have selected - // a different memory space. If so, that requires us to switch - // out the rendering in the tab with either a new one or an - // existing one already associated with that memory space. - String oldMemorySpaceId = (String)activeFolder.getSelection().getData(KEY_MEMORY_SPACE); - assert oldMemorySpaceId == null || !oldMemorySpaceId.equals(NA_MEMORY_SPACE_ID) : "should be null reference or an explicit, valid memory space ID (not including '----')"; //$NON-NLS-1$ - if ((oldMemorySpaceId != null && !oldMemorySpaceId.equals(memorySpaceId)) - || (oldMemorySpaceId == null && memorySpaceId != null)) { - try { - rendering = populateTabWithRendering(item, retrieval, context, memorySpaceId, expression); - activeFolder.setSelection(item); - getSite().getSelectionProvider().setSelection(new StructuredSelection(item.getData(KEY_RENDERING))); - handleTabActivated(item); - } catch (DebugException e) { - fGotoAddressBar.handleExpressionStatus(new Status(Status.ERROR, MemoryBrowserPlugin.PLUGIN_ID, - Messages.getString("MemoryBrowser.FailedToGoToAddressTitle"), e)); //$NON-NLS-1$ - return; - } - } - } - - if (rendering == null) { - rendering = (IRepositionableMemoryRendering) activeFolder.getSelection().getData(KEY_RENDERING); - } - - if (retrieval instanceof IMemoryBlockRetrievalExtension && - rendering instanceof IRepositionableMemoryRendering) { - final IRepositionableMemoryRendering renderingFinal = (IRepositionableMemoryRendering) rendering; - new Thread() { - @Override - public void run() { - try { - final BigInteger newBase = getExpressionAddress(retrieval, expression, context, memorySpaceId); - IMemoryBlockExtension block = (IMemoryBlockExtension) renderingFinal.getMemoryBlock(); - if (block.supportBaseAddressModification()) { - block.setBaseAddress(newBase); - } - if(renderingFinal instanceof IRepositionableMemoryRendering2) { - ((IRepositionableMemoryRendering2)renderingFinal).goToAddress(newBase, expression); - } - else { - renderingFinal.goToAddress(newBase); - } - - runOnUIThread(new Runnable(){ - public void run() { - CTabItem selection = activeFolder.getSelection(); - selection.setData(KEY_EXPRESSION, expression); - selection.setData(KEY_EXPRESSION_ADDRESS, newBase); - fGotoAddressBar.handleExpressionStatus(Status.OK_STATUS); - updateLabel(selection, renderingFinal); - } - }); - } catch (final DebugException e1) { - // widgets update require Display - runOnUIThread(new Runnable(){ - public void run() { - fGotoAddressBar.handleExpressionStatus(new Status(Status.ERROR, MemoryBrowserPlugin.PLUGIN_ID, - Messages.getString("MemoryBrowser.FailedToGoToAddressTitle"), e1)); //$NON-NLS-1$ - } - }); - } - } - }.start(); - } - } - } - - private void updateLabel(CTabItem tab, IMemoryRendering rendering) { - // The default is to use the label provided by the base rendering - // interface. - String label = rendering.getLabel(); - - // If the rendering provides access to its viewport address (the first - // address shown in the rendering, subject to scrolling), display that - // in the tab rather than the expression that was used when the tab was - // first created. - if (rendering instanceof IMemoryRenderingViewportProvider) { - BigInteger viewportAddress = ((IMemoryRenderingViewportProvider)rendering).getViewportAddress(); - - // The base label generation puts the rendering type name in "<>" and - // appends it to the label. Fish that out - String renderingType = null; - int i = label.indexOf('<'); - if (i >= 0) { - renderingType = label.substring(i); - } - - label = null; - - // If a memory space is involved, we want to include its ID in the label - String memorySpaceID = (String)tab.getData(KEY_MEMORY_SPACE); - if (memorySpaceID != null) { - IMemoryBlockRetrieval retrieval = (IMemoryBlockRetrieval) tab.getParent().getData(KEY_RETRIEVAL); - if (retrieval instanceof IMemorySpaceAwareMemoryBlockRetrieval) { - label = ((IMemorySpaceAwareMemoryBlockRetrieval)retrieval).encodeAddress("0x" + viewportAddress.toString(16), memorySpaceID); - } - } - if (label == null) { - label = "0x" + viewportAddress.toString(16); - } - - // If the expression that was went to ("Go") is not a hex address, - // or it is but the user has scrolled/paged, then show the - // expression after the viewport hex address. Additionally, if some - // scrolling/paging has moved the viewport, also show the relative - // displacement. E.g., - // "0x10020 - gSomeVar(+20) " - // (for a tab where the user did a "Go" to "gSomeVar" then paged - // down, and where gSomeVar is at 0x10000) - // - String expression = (String)tab.getData(KEY_EXPRESSION); - BigInteger evaluatedAddress = (BigInteger)tab.getData(KEY_EXPRESSION_ADDRESS); - if(expression != null && !expression.equals("0x" + viewportAddress.toString(16))) { - label += " - " + expression; - BigInteger delta = evaluatedAddress.subtract(viewportAddress); - if (!delta.equals(BigInteger.ZERO)) { - label += "("; - label += delta.signum() < 0 ? '+' : '-'; - label += "0x" + delta.abs().toString(16) +")"; - } - } - - label += ' ' + renderingType;; - - // Allow the memory block to customize the label. The platform's - // Memory view support this (it was done in the call to - // rendering.getLabel() above) - IMemoryBlock block = rendering.getMemoryBlock(); - ILabelDecorator labelDec = (ILabelDecorator)block.getAdapter(ILabelDecorator.class); - if (labelDec != null) { - String newLabel = labelDec.decorateText(label, rendering); - if (newLabel != null) { - label = newLabel; - } - } - } - - tab.setText(label); - } - - private CTabFolder createTabFolder(Composite parent) - { - final CTabFolder folder = new CTabFolder(parent, SWT.NO_REDRAW_RESIZE | SWT.NO_TRIM | SWT.FLAT); - - ColorRegistry reg = JFaceResources.getColorRegistry(); - Color c1 = reg.get("org.eclipse.ui.workbench.ACTIVE_TAB_BG_START"), //$NON-NLS-1$ - c2 = reg.get("org.eclipse.ui.workbench.ACTIVE_TAB_BG_END"); //$NON-NLS-1$ - folder.setSelectionBackground(new Color[] {c1, c2}, new int[] {100}, true); - folder.setSelectionForeground(reg.get("org.eclipse.ui.workbench.ACTIVE_TAB_TEXT_COLOR")); //$NON-NLS-1$ - folder.setSimple(PlatformUI.getPreferenceStore().getBoolean(IWorkbenchPreferenceConstants.SHOW_TRADITIONAL_STYLE_TABS)); - folder.setBorderVisible(true); - - // listener to dispose rendering resources for each closed tab - folder.addCTabFolder2Listener(new CTabFolder2Adapter() { - @Override - public void close(CTabFolderEvent event) { - event.doit = true; - CTabItem item = (CTabItem) event.item; - disposeTab(item); - } - }); - - // listener to dispose rendering resources for all tab items when view part is closed - folder.addDisposeListener(new DisposeListener() { - public void widgetDisposed(DisposeEvent e) { - for(CTabItem tab : folder.getItems()) { - disposeTab(tab); - } - folder.removeDisposeListener(this); - } - }); - return folder; - } - - // these utility methods allow us restrict the scope of the unavoidable @SuppressWarnings - - @SuppressWarnings("unchecked") - private static Map getRenderings(CTabItem tabItem) { - return (Map)tabItem.getData(KEY_RENDERINGS); - } - - @SuppressWarnings("unchecked") - private static List getMemoryBlocks(CTabItem tabItem) { - return (List)tabItem.getData(KEY_MEMORY_BLOCKS); - } - - - /** - * dispose rendering resources associated with the tab item - * @param item - */ - private void disposeTab(CTabItem item ) { - if (item.isDisposed()) - return; - - IMemoryRenderingContainer container = (IMemoryRenderingContainer) item.getData(KEY_CONTAINER); - fCurrentContainers.remove( container ); - Map map = getRenderings(item); - Collection renderings = map.values(); - for (IMemoryRendering rendering : renderings) { - // always deactivate rendering before disposing it. - rendering.deactivated(); - rendering.dispose(); - if (rendering == fActiveRendering) { - fActiveRendering = null; - getSite().getSelectionProvider().setSelection(new StructuredSelection()); - } - } - map.clear(); - - List blocks = getMemoryBlocks(item); - for (IMemoryBlockExtension block : blocks) { - try { - block.dispose(); - } catch (DebugException e) { - MemoryBrowserPlugin.getDefault().getLog().log(new Status(Status.ERROR, MemoryBrowserPlugin.PLUGIN_ID, "Could not dispose memory block", e)); //$NON-NLS-1$ - } - } - blocks.clear(); - } - - private CTabItem createTab(CTabFolder tabFolder, int index) { - int swtStyle = SWT.CLOSE; - CTabItem tab = new CTabItem(tabFolder, swtStyle, index); - tab.setData(KEY_RENDERINGS, new HashMap()); - tab.setData(KEY_MEMORY_BLOCKS, new ArrayList()); - return tab; - } - - private void hookContextMenu() { - MenuManager menuMgr = new MenuManager("#PopupMenu"); //$NON-NLS-1$ - menuMgr.setRemoveAllWhenShown(true); - menuMgr.addMenuListener(new IMenuListener() { - public void menuAboutToShow(IMenuManager manager) { - MemoryBrowser.this.fillContextMenu(manager); - } - }); - Menu menu = menuMgr.createContextMenu(getControl()); - getControl().setMenu(menu); - } - - private void contributeToActionBars() { - IActionBars bars = getViewSite().getActionBars(); - fillLocalPullDown(bars.getMenuManager()); - fillLocalToolBar(bars.getToolBarManager()); - } - - private void fillLocalPullDown(IMenuManager manager) { - - - MenuManager sub = new MenuManager(Messages.getString("MemoryBrowser.DefaultRendering")); //$NON-NLS-1$ - - for(final IMemoryRenderingType type : getRenderingTypes()) - { - final Action action = new Action( - type.getLabel(), IAction.AS_RADIO_BUTTON) - { - @Override - public void run() - { - setDefaultRenderingTypeId(type.getId()); - } - }; - action.setChecked(type.getId().equals(getDefaultRenderingTypeId())); - sub.add(action); - } - - manager.add(sub); - manager.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS)); - } - - private void fillContextMenu(IMenuManager manager) { - manager.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS)); - } - - private void fillLocalToolBar(IToolBarManager manager) { - manager.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS)); - } - - private void makeActions() { - - } - - private IMemoryRenderingType[] getRenderingTypes() - { - return MemoryRenderingManager.getDefault().getRenderingTypes(new IMemoryBlockExtension(){ - public void connect(Object client) {} - public void disconnect(Object client) {} - public void dispose() throws DebugException {} - public int getAddressSize() throws DebugException { return 0; } - public int getAddressableSize() throws DebugException { return 0; } - public BigInteger getBigBaseAddress() throws DebugException { return null; } - public BigInteger getBigLength() throws DebugException { return null; } - public MemoryByte[] getBytesFromAddress(BigInteger address, long units) throws DebugException { return null; } - public MemoryByte[] getBytesFromOffset(BigInteger unitOffset, long addressableUnits) throws DebugException { return null; } - public Object[] getConnections() { return null; } - public String getExpression() { return null; } - public BigInteger getMemoryBlockEndAddress() throws DebugException { return null; } - public IMemoryBlockRetrieval getMemoryBlockRetrieval() { return null; } - public BigInteger getMemoryBlockStartAddress() throws DebugException { return null; } - public void setBaseAddress(BigInteger address) throws DebugException {} - public void setValue(BigInteger offset, byte[] bytes) throws DebugException {} - public boolean supportBaseAddressModification() throws DebugException { return false; } - public boolean supportsChangeManagement() { return false; } - public byte[] getBytes() throws DebugException { return null; } - public long getLength() { return 0; } - public long getStartAddress() { return 0; } - public void setValue(long offset, byte[] bytes) throws DebugException {} - public boolean supportsValueModification() { return false; } - public IDebugTarget getDebugTarget() { return null; } - public ILaunch getLaunch() { return null; } - public String getModelIdentifier() { return null; } - @SuppressWarnings({ "rawtypes", "unchecked" }) - public Object getAdapter(Class adapter) { return null; } - }); - } - - @Override - public void setFocus() { - getControl().setFocus(); - } - - public void debugContextChanged(DebugContextEvent event) { - handleDebugContextChanged(((StructuredSelection) event.getContext()).getFirstElement()); - } - - private final class MemoryBrowserRenderingContainer implements - IMemoryRenderingContainer { - private final List renderings = new ArrayList(); - - private MemoryBrowserRenderingContainer() { - } - - public void addMemoryRendering(IMemoryRendering rendering) { - // do not allow duplicated objects - if (!renderings.contains(rendering)) { - renderings.add(rendering); - } - } - - public IMemoryRendering getActiveRendering() { - return renderings.isEmpty() ? null : renderings.get(renderings.size() -1); - } - - public String getId() { - return ID; - } - - public String getLabel() { - IMemoryRendering rendering = getActiveRendering(); - return rendering != null ? rendering.getLabel() : null; - } - - public IMemoryRenderingSite getMemoryRenderingSite() { - return MemoryBrowser.this; - } - - public IMemoryRendering[] getRenderings() { - return renderings.toArray(new IMemoryRendering[renderings.size()]); - } - - public void removeMemoryRendering(IMemoryRendering rendering) { - renderings.remove(rendering); - } - } - - private final class RenderingPropertyChangeListener implements - IPropertyChangeListener { - private final CTabItem tab; - private final IMemoryRendering newRendering; - - private RenderingPropertyChangeListener(CTabItem tab, - IMemoryRendering newRendering) { - this.tab = tab; - this.newRendering = newRendering; - } - - public void propertyChange(final PropertyChangeEvent event) { - WorkbenchJob job = new WorkbenchJob("MemoryBrowser PropertyChanged") { //$NON-NLS-1$ - @Override - public IStatus runInUIThread(IProgressMonitor monitor) { - if(tab.isDisposed()) - return Status.OK_STATUS; - - if (event.getProperty().equals(IBasicPropertyConstants.P_TEXT)) - updateLabel(tab, newRendering); - return Status.OK_STATUS; - } - }; - job.setSystem(true); - job.schedule(); - } - } - - private class GetMemorySpacesRequest extends CRequest implements IMemorySpaceAwareMemoryBlockRetrieval.GetMemorySpacesRequest { - String [] fMemorySpaces; - public String[] getMemorySpaces() { - return fMemorySpaces; - } - public void setMemorySpaces(String[] memorySpaceIds) { - fMemorySpaces = memorySpaceIds; - } - } - - public void handleDebugContextChanged(final Object context) { - if(defaultRenderingTypeId == null) - return; - - IAdaptable adaptable = null; - IMemoryBlockRetrieval retrieval = null; - ILaunch launch = null; - - if(context instanceof IAdaptable) - { - adaptable = (IAdaptable) context; - retrieval = ((IMemoryBlockRetrieval) adaptable.getAdapter(IMemoryBlockRetrieval.class)); - launch = ((ILaunch) adaptable.getAdapter(ILaunch.class)); - } - - if(retrieval != null && launch != null && !launch.isTerminated()) { - if (retrieval instanceof IMemorySpaceAwareMemoryBlockRetrieval) { - final IMemoryBlockRetrieval _retrieval = retrieval; - ((IMemorySpaceAwareMemoryBlockRetrieval)retrieval).getMemorySpaces(context, new GetMemorySpacesRequest(){ - @Override - public void done() { - updateTab(_retrieval, context, isSuccess() ? getMemorySpaces() : new String[0]); - } - }); - } - else { - updateTab(retrieval, context, new String[0]); - } - } - else { - handleUnsupportedSelection(); - } - - fGotoMemorySpaceControl.pack(true); - fStackLayout.topControl.getParent().layout(true); - } - - /** - * Called to update the tab once the asynchronous query for memory spaces - * has returned a result. - * - * @param retrieval - * the retrieval object associated with the newly active debug - * context - * @param context - * the newly active context - * @param memorySpaces - * the memory spaces, if applicable. Otherwise an empty array. - */ - private void updateTab(final IMemoryBlockRetrieval retrieval, final Object context, final String[] memorySpaces) { - // GUI activity must be on the main thread - runOnUIThread(new Runnable(){ - public void run() { - if (fGotoAddressBarControl.isDisposed() || fGotoMemorySpaceControl.isDisposed()) { - return; - } - - fGotoAddressBarControl.setVisible(true); - - // If we've already created a tab folder for this retrieval - // object, bring it to the forefront. Otherwise create the - // folder. - CTabFolder tabFolder = fContextFolders.get(retrieval); - if(tabFolder != null) { - fStackLayout.topControl = tabFolder; - CTabItem tabItem = (CTabItem) tabFolder.getSelection(); - if ( tabItem != null ) { - getSite().getSelectionProvider().setSelection(new StructuredSelection(tabItem.getData(KEY_RENDERING))); - } - handleTabActivated(tabItem); - } - else { - tabFolder = createTabFolder(fRenderingsComposite); - tabFolder.addSelectionListener(new SelectionListener() { - public void widgetDefaultSelected(SelectionEvent e) {} - public void widgetSelected(SelectionEvent e) { - CTabItem tabItem = (CTabItem)e.item; - updateMemorySpaceControlSelection(tabItem); - fGotoAddressBar.loadSavedExpressions(context, fGotoMemorySpaceControl.isVisible() ? fGotoMemorySpaceControl.getText() : null); - getSite().getSelectionProvider().setSelection(new StructuredSelection(tabItem.getData(KEY_RENDERING))); - handleTabActivated(tabItem); - } - }); - - tabFolder.setData(KEY_RETRIEVAL, retrieval); - fContextFolders.put(retrieval, tabFolder); - fStackLayout.topControl = tabFolder; - } - // update debug context to the new selection - tabFolder.setData(KEY_CONTEXT, context); - - - final CTabFolder activeFolder = tabFolder; - if (!activeFolder.equals(tabFolder)) { - return; - } - - // Don't expose the memory spaces widget if there are none or - // only one memory space involved. - // https://bugs.eclipse.org/bugs/show_bug.cgi?id=309032#c50 - if (memorySpaces.length >= 2) { - fGotoMemorySpaceControl.setItems(memorySpaces); - - // Add the '----' (N/A) entry unless the retrieval object - // says it requires a memory space ID in all cases - boolean addNA = true; - if (retrieval instanceof IMemorySpaceAwareMemoryBlockRetrieval) { - addNA = !((IMemorySpaceAwareMemoryBlockRetrieval)retrieval).creatingBlockRequiresMemorySpaceID(); - } - if (addNA) { - fGotoMemorySpaceControl.add(NA_MEMORY_SPACE_ID, 0); - } - setMemorySpaceControlVisible(true); - } - else { - fGotoMemorySpaceControl.setItems(new String[0]); - setMemorySpaceControlVisible(false); - } - - updateMemorySpaceControlSelection(activeFolder.getSelection()); - fGotoAddressBar.loadSavedExpressions(context, fGotoMemorySpaceControl.isVisible() ? fGotoMemorySpaceControl.getText() : null); - - fStackLayout.topControl.getParent().layout(true); - } - }); - } - - /** - * Update the expression text in goto address widget to reflect the memory - * rendering expression - * - * @param item - * the active tab; may be null if in a "fresh" memory browser instance - */ - protected void updateExpression(CTabItem activeFolder) { - String expression = (activeFolder != null) ? (String) activeFolder.getData(KEY_EXPRESSION) : null; - if (expression != null) { - fGotoAddressBar.setExpressionText(expression); - } - } - - protected final void handleTabActivated(CTabItem item) { - if (item != null) { - updateActiveRendering((IMemoryRendering) item.getData(KEY_RENDERING)); - } - } - - private void updateActiveRendering(IMemoryRendering rendering) { - if (fActiveRendering == rendering) { - return; - } - if (fActiveRendering != null) { - fActiveRendering.deactivated(); - fActiveRendering.becomesHidden(); - } - if (rendering != null) { - rendering.activated(); - rendering.becomesVisible(); - } - fActiveRendering = rendering; - } - - private void setMemorySpaceControlVisible(boolean visible) { - FormData data = (FormData)fGotoAddressBarControl.getLayoutData(); - if (visible) { - data.left = new FormAttachment(fGotoMemorySpaceControl); - } - else { - data.left = new FormAttachment(0); - } - fGotoMemorySpaceControl.setVisible(visible); - - } - - /** - * Update the selection in the memory space combobox to reflect the memory - * space being shown in the given tab - * - * @param item - * the active tab; may be null if in a "fresh" memory browser instance - */ - private void updateMemorySpaceControlSelection(CTabItem item) { - String[] memorySpaces = fGotoMemorySpaceControl.getItems(); - if (memorySpaces.length > 0 ) { - // Don't assume that the memory space previously set in the tab - // is one of the ones now available. If it isn't, then select - // the first available one and update the tab data - boolean foundIt = false; - if (item != null) { - String currentMemorySpace = (String) item.getData(KEY_MEMORY_SPACE); - if (currentMemorySpace != null) { - assert currentMemorySpace.length() > 0; - for (String memorySpace : memorySpaces) { - if (memorySpace.equals(currentMemorySpace)) { - foundIt = true; - fGotoMemorySpaceControl.setText(currentMemorySpace); - break; - } - } - } - } - if (!foundIt) { - fGotoMemorySpaceControl.select(0); - if (item != null) { - item.setData(KEY_MEMORY_SPACE, null); - } - } - fGotoMemorySpaceControl.setVisible(true); - } - else { - fGotoMemorySpaceControl.setVisible(false); - } - fGotoMemorySpaceControl.getParent().layout(true); - - } - - private String getDefaultRenderingTypeId() - { - return defaultRenderingTypeId; - } - - public void setDefaultRenderingTypeId(String id) - { - defaultRenderingTypeId = id; - IPreferenceStore store = MemoryBrowserPlugin.getDefault().getPreferenceStore(); - store.setValue(PREF_DEFAULT_RENDERING, defaultRenderingTypeId); - } - - /** - * Populate given tab with a rendering positioned at specified expression and memory space. - * Will create a new rendering if one does not exist for the given memory space - * - * @param tab item to populate - * @param retrieval memory service to retrieve memory block from - * @param context memory block would be retrieved - * @param memorySpaceId of the expression or null if not supported - * @param expression from where to retrieve the memory block - * @return return the memory rendering or null if could not be created - * - * @throws DebugException if could not retrieve memory block (e.g. invalid expression) - */ - private IMemoryRendering populateTabWithRendering(final CTabItem tab, final IMemoryBlockRetrieval retrieval, Object context, String memorySpaceId, String expression) throws DebugException { - IMemoryRenderingType type = DebugUITools.getMemoryRenderingManager().getRenderingType(getDefaultRenderingTypeId()); - IMemoryRenderingContainer container = (IMemoryRenderingContainer)tab.getData(KEY_CONTAINER); - if (container == null) { - container = new MemoryBrowserRenderingContainer(); - fCurrentContainers.add(container); - } - - IMemoryRendering rendering = getRenderings(tab).get(memorySpaceId); - if (rendering == null) { - // No rendering yet. Create rendering and associated memory block. - // createMemoryBlock will throw if expression cannot be resolved - IMemoryBlockExtension block = createMemoryBlock(retrieval, expression, context, memorySpaceId); - try { - rendering = type.createRendering(); - } catch (CoreException e) { - MemoryBrowserPlugin.getDefault().getLog().log(new Status(Status.ERROR, MemoryBrowserPlugin.PLUGIN_ID, "", e)); //$NON-NLS-1$ - return null; - } - - rendering.init(container, block); - container.addMemoryRendering(rendering); - rendering.createControl(tab.getParent()); - getRenderings(tab).put(memorySpaceId, rendering); - getMemoryBlocks(tab).add(block); - rendering.addPropertyChangeListener(new RenderingPropertyChangeListener(tab, rendering)); - } - - tab.setControl(rendering.getControl()); - tab.getParent().setSelection(0); - tab.setData(KEY_RENDERING, rendering); - tab.setData(KEY_MEMORY_SPACE, memorySpaceId); - tab.setData(KEY_CONTAINER, container); - tab.setData(KEY_RENDERING_TYPE, type); - tab.setData(KEY_EXPRESSION, expression); - tab.setData(KEY_EXPRESSION_ADDRESS, ((IMemoryBlockExtension)rendering.getMemoryBlock()).getBigBaseAddress()); - getSite().getSelectionProvider().setSelection(new StructuredSelection(tab.getData(KEY_RENDERING))); - - return rendering; - } - - - private void releaseTabFolder(final IMemoryBlockRetrieval retrieval) - { - final CTabFolder folder = fContextFolders.get(retrieval); - if(folder != null) - { - Runnable run = new Runnable() { - public void run() { - for(CTabItem tab : folder.getItems()) { - disposeTab(tab); - } - fContextFolders.remove(retrieval); - folder.dispose(); - - if (fStackLayout.topControl.equals(folder)) { - handleUnsupportedSelection(); - } - } - }; - runOnUIThread(run); - } - } - - class SelectionProviderAdapter implements ISelectionProvider { - - List listeners = new ArrayList(); - - ISelection theSelection = StructuredSelection.EMPTY; - - public void addSelectionChangedListener(ISelectionChangedListener listener) { - listeners.add(listener); - } - - public ISelection getSelection() { - return theSelection; - } - - public void removeSelectionChangedListener( - ISelectionChangedListener listener) { - listeners.remove(listener); - } - - public void setSelection(ISelection selection) { - theSelection = selection; - final SelectionChangedEvent e = new SelectionChangedEvent(this, selection); - Object[] listenersArray = listeners.toArray(); - - for (int i = 0; i < listenersArray.length; i++) { - final ISelectionChangedListener l = (ISelectionChangedListener) listenersArray[i]; - SafeRunner.run(new SafeRunnable() { - public void run() { - l.selectionChanged(e); - } - }); - } - } - } - - /** - * create a memory block - * @param retrieval memory block retrieval. - * @param expression expression to be evaluated to an addressL - * @param context context for evaluating the expression. This is typically - * a debug element. - * @param memorySpaceID a memory space identifier, or null if n/a - * @return a memory block based on the given expression and context - * @throws DebugException if unable to retrieve the specified memory - */ - private IMemoryBlockExtension createMemoryBlock(IMemoryBlockRetrieval retrieval, String expression, Object context, String memorySpaceID) throws DebugException { - IMemoryBlockExtension block = null; - IMemoryBlockRetrievalExtension retrievalExtension = null; - if (retrieval instanceof IMemoryBlockRetrievalExtension) { - retrievalExtension = (IMemoryBlockRetrievalExtension) retrieval; - } else if(retrieval instanceof IAdaptable) { - retrievalExtension = (IMemoryBlockRetrievalExtension)((IAdaptable) retrieval).getAdapter(IMemoryBlockRetrievalExtension.class); - } - if (retrievalExtension != null) { - if (retrievalExtension instanceof IMemorySpaceAwareMemoryBlockRetrieval) { - block = ((IMemorySpaceAwareMemoryBlockRetrieval)retrievalExtension).getMemoryBlock(expression, context, memorySpaceID); - } - else { - block = retrievalExtension.getExtendedMemoryBlock(expression, context); - } - } - if ( block == null ) { - throw new DebugException(new Status(Status.ERROR, MemoryBrowserPlugin.PLUGIN_ID, "Extended Memory Block could not be obtained")); //$NON-NLS-1$ - } - return block; - } - - /** - * Get a memory address for an expression in a given context. - * @param retrieval - * @param expression - * @param context - * @return BigInteger address of the expression - * @throws DebugException - */ - private BigInteger getExpressionAddress(IMemoryBlockRetrieval retrieval, String expression, Object context, String memorySpaceId) throws DebugException { - // Until 257842 issue is solved this is done via IMemoryBlockRetrievalExtension API. - IMemoryBlockExtension newBlock = createMemoryBlock(retrieval, expression, context, memorySpaceId); - BigInteger address = newBlock.getBigBaseAddress(); - newBlock.dispose(); - return address; - } - - /** - * Execute runnable on UI thread if the current thread is not an UI thread. - * Otherwise execute it directly. - * - * @param runnable - * the runnable to execute - */ - private void runOnUIThread(final Runnable runnable) { - if (Display.getCurrent() != null) { - runnable.run(); - } - else { - UIJob job = new UIJob("Memory Browser UI Job"){ //$NON-NLS-1$ - @Override - public IStatus runInUIThread(IProgressMonitor monitor) { - runnable.run(); - return Status.OK_STATUS; - }}; - job.setSystem(true); - job.schedule(); - } - } - - /* (non-Javadoc) - * @see org.eclipse.cdt.debug.ui.memory.memorybrowser.api.IMemoryBrowser#go(java.lang.String, java.lang.String, boolean) - */ - public void go(String expression, String memorySpaceId, boolean inNewTab) - throws CoreException { - if (expression == null) { - throw new IllegalArgumentException("expression cannot be null"); - } - expression = expression.trim(); - if (expression.length() == 0) { - throw new IllegalArgumentException("expression cannot be empty"); - } - if (!fGotoMemorySpaceControl.isDisposed() && fGotoMemorySpaceControl.isVisible()) { - if (memorySpaceId == null) { - // if caller passed null, use whatever memory space is selected in the control - memorySpaceId = fGotoMemorySpaceControl.getText(); - if (memorySpaceId.equals(NA_MEMORY_SPACE_ID)) { - memorySpaceId = null; - } - } - else { - // if caller passed empty string, it means n/a (same as "----" in the selector) - memorySpaceId = memorySpaceId.trim(); - if (memorySpaceId.length() == 0) { - memorySpaceId = null; - } - else { - // Check that the ID requested by the user is a valid one - if (fGotoMemorySpaceControl.indexOf(memorySpaceId) == -1) { - throw new IllegalArgumentException("unrecognized memory space ID"); - } - } - - fGotoMemorySpaceControl.setText(memorySpaceId == null ? NA_MEMORY_SPACE_ID : memorySpaceId); - } - } - - fGotoAddressBar.setExpressionText(expression); - performGo(inNewTab, expression, memorySpaceId); - } - - /* (non-Javadoc) - * @see org.eclipse.cdt.debug.ui.memory.memorybrowser.api.IMemoryBrowser#getSelectedMemorySpace() - */ - public String getSelectedMemorySpace() { - if (!fGotoMemorySpaceControl.isDisposed() && fGotoMemorySpaceControl.isVisible()) { - String id = fGotoMemorySpaceControl.getText(); - return id.equals(NA_MEMORY_SPACE_ID) ? null : id; - } - return null; - } -} +/******************************************************************************* + * Copyright (c) 2009, 2015 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 + * Ted R Williams (Mentor Graphics, Inc.) - address space enhancements + * Patrick Chuong (Texas Instruments) - Pin and Clone Supports (331781) + *******************************************************************************/ + +package org.eclipse.cdt.debug.ui.memory.memorybrowser; + +import java.lang.reflect.Type; +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.eclipse.cdt.debug.core.model.provisional.IMemoryRenderingViewportProvider; +import org.eclipse.cdt.debug.core.model.provisional.IMemorySpaceAwareMemoryBlockRetrieval; +import org.eclipse.cdt.debug.internal.core.CRequest; +import org.eclipse.cdt.debug.ui.memory.memorybrowser.api.IMemoryBrowser; +import org.eclipse.cdt.debug.ui.provisional.IRepositionableMemoryRendering2; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IAdaptable; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.SafeRunner; +import org.eclipse.core.runtime.Status; +import org.eclipse.debug.core.DebugEvent; +import org.eclipse.debug.core.DebugException; +import org.eclipse.debug.core.DebugPlugin; +import org.eclipse.debug.core.IDebugEventSetListener; +import org.eclipse.debug.core.ILaunch; +import org.eclipse.debug.core.model.IDebugTarget; +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.IMemoryBlockRetrievalExtension; +import org.eclipse.debug.core.model.MemoryByte; +import org.eclipse.debug.internal.ui.memory.MemoryRenderingManager; +import org.eclipse.debug.ui.DebugUITools; +import org.eclipse.debug.ui.contexts.DebugContextEvent; +import org.eclipse.debug.ui.contexts.IDebugContextListener; +import org.eclipse.debug.ui.contexts.IDebugContextService; +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.IMemoryRenderingSynchronizationService; +import org.eclipse.debug.ui.memory.IMemoryRenderingType; +import org.eclipse.debug.ui.memory.IRepositionableMemoryRendering; +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.IToolBarManager; +import org.eclipse.jface.action.MenuManager; +import org.eclipse.jface.action.Separator; +import org.eclipse.jface.dialogs.IDialogConstants; +import org.eclipse.jface.preference.IPreferenceStore; +import org.eclipse.jface.resource.ColorRegistry; +import org.eclipse.jface.resource.JFaceResources; +import org.eclipse.jface.util.IPropertyChangeListener; +import org.eclipse.jface.util.PropertyChangeEvent; +import org.eclipse.jface.util.SafeRunnable; +import org.eclipse.jface.viewers.IBasicPropertyConstants; +import org.eclipse.jface.viewers.ILabelDecorator; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.ISelectionChangedListener; +import org.eclipse.jface.viewers.ISelectionProvider; +import org.eclipse.jface.viewers.SelectionChangedEvent; +import org.eclipse.jface.viewers.StructuredSelection; +import org.eclipse.swt.SWT; +import org.eclipse.swt.custom.CTabFolder; +import org.eclipse.swt.custom.CTabFolder2Adapter; +import org.eclipse.swt.custom.CTabFolderEvent; +import org.eclipse.swt.custom.CTabItem; +import org.eclipse.swt.custom.StackLayout; +import org.eclipse.swt.dnd.DND; +import org.eclipse.swt.dnd.DropTarget; +import org.eclipse.swt.dnd.DropTargetAdapter; +import org.eclipse.swt.dnd.DropTargetEvent; +import org.eclipse.swt.dnd.TextTransfer; +import org.eclipse.swt.dnd.Transfer; +import org.eclipse.swt.events.DisposeEvent; +import org.eclipse.swt.events.DisposeListener; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.events.SelectionListener; +import org.eclipse.swt.graphics.Color; +import org.eclipse.swt.layout.FormAttachment; +import org.eclipse.swt.layout.FormData; +import org.eclipse.swt.layout.FormLayout; +import org.eclipse.swt.widgets.Combo; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Menu; +import org.eclipse.ui.IActionBars; +import org.eclipse.ui.IViewSite; +import org.eclipse.ui.IWorkbenchActionConstants; +import org.eclipse.ui.IWorkbenchPreferenceConstants; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.part.ViewPart; +import org.eclipse.ui.progress.UIJob; +import org.eclipse.ui.progress.WorkbenchJob; + +/** + * A lightweight rendering container. + * + * Debug model requirements: + * IMemoryBlockExtension (IMemoryBlock not supported) + * IMemoryBlockRetrievalExtension + *

+ * Rendering requirements: + * IRepositionableMemoryRendering + * + */ + +@SuppressWarnings("restriction") /* Debug Platform's Flexible hierarchy is still provisional */ + +public class MemoryBrowser extends ViewPart implements IDebugContextListener, IMemoryRenderingSite, IDebugEventSetListener, IMemoryBrowser +{ + public static final String ID = "org.eclipse.cdt.debug.ui.memory.memorybrowser.MemoryBrowser"; //$NON-NLS-1$ + + protected StackLayout fStackLayout; + private Composite fRenderingsComposite; + private GoToAddressBarWidget fGotoAddressBar; + private DropTarget fDropTarget; + private Control fGotoAddressBarControl; + private Combo fGotoMemorySpaceControl; + private Label fUnsupportedLabel; + private Composite fMainComposite; + private String defaultRenderingTypeId = null; + private IMemoryRendering fActiveRendering; + + /** + * Every memory retrieval object is given its own tab folder. Typically all + * elements of a "process" (process, threads, frames) have the same + * retrieval object. + */ + private Map fContextFolders = new HashMap (); + + private List fCurrentContainers = new ArrayList(); + + private final static String KEY_CONTEXT = "CONTEXT"; //$NON-NLS-1$ + private final static String KEY_CONTAINER = "CONTAINER"; //$NON-NLS-1$ + private final static String KEY_RENDERING_TYPE = "RENDERING_TYPE"; //$NON-NLS-1$ + + /** + * Property we attach to a CTabItem to track the retrieval object we use to + * create memory blocks on the tab's behalf. Value is an + * {@link IMemoryBlockRetrieval} + */ + private final static String KEY_RETRIEVAL = "RETRIEVAL"; //$NON-NLS-1$ + + /** + * Property we attach to a CTabItem to track the memory space it's + * associated with. Value is a memory space ID (String), or null if n/a + */ + private final static String KEY_MEMORY_SPACE = "MEMORY_SPACE"; //$NON-NLS-1$ + + /** + * Property we attach to a CTabItem to track what renderings have been + * created on its behalf. There will be more than one rendering if the + * backend supports memory spaces, there is more than one such space, and + * the user has viewed memory in multiple memory spaces within that tab. + * The value is a map of memory-space-ID==>IMemoryRendering. + */ + private final static String KEY_RENDERINGS = "RENDERINGS"; //$NON-NLS-1$ + + /** + * Property we attach to a CTabItem to track the active rendering in the + * tab. The value is an IMemoryRendering. + */ + private final static String KEY_RENDERING = "RENDERING"; //$NON-NLS-1$ + + /** + * Property we attach to a CTabItem to track what memory blocks have been + * created on its behalf. There can be multiple when dealing with memory + * spaces, for the same reasons there can be multiple renderings. There is a + * 1:1:1 association between rendering, block and memory space. The value is + * a list of IMemoryBlockExtension + */ + private final static String KEY_MEMORY_BLOCKS = "MEMORY_BLOCKS"; //$NON-NLS-1$ + + /** + * Property we attach to a CTabItem to track the expression we used to + * create memory blocks on the tab's behalf. Value is a String. + */ + private final static String KEY_EXPRESSION = "EXPRESSION"; //$NON-NLS-1$ + + /** + * Property we attach to a CTabItem to track the address associated with + * KEY_EXPRESSION. Value is a BigInteger + */ + private final static String KEY_EXPRESSION_ADDRESS = "EXPRESSION_ADDRESS"; //$NON-NLS-1$ + + public static final String PREF_DEFAULT_RENDERING = "org.eclipse.cdt.debug.ui.memory.memorybrowser.defaultRendering"; //$NON-NLS-1$ + + /** + * The text we use in the combobox to represent no memory space specification + */ + private static final String NA_MEMORY_SPACE_ID = " -----"; //$NON-NLS-1$ + + public MemoryBrowser() { + } + + public Control getControl() { + return fMainComposite; + } + + /* + * Handles DnD from other views. + */ + private class MemoryDropAdapter extends DropTargetAdapter { + /* + * @see org.eclipse.swt.dnd.DropTargetListener#drop(org.eclipse.swt.dnd.DropTargetEvent) + */ + @Override + public void drop(final DropTargetEvent event) { + if (TextTransfer.getInstance().isSupportedType( event.currentDataType )) { + if ( event.data instanceof String ) { + fGotoAddressBar.setExpressionText( (String) event.data ); + performGo(false); + } + } + } + + /* + * @see org.eclipse.swt.dnd.DropTargetListener#dragEnter(org.eclipse.swt.dnd.DropTargetEvent) + */ + @Override + public void dragEnter(DropTargetEvent event) { + event.detail = DND.DROP_COPY; + event.feedback = DND.FEEDBACK_NONE; + } + } + + @Override + public void createPartControl(Composite parent) { + // set default rendering type. use the traditional rendering if available. fallback on first registered type. + // this should eventually be configurable via a preference page. + boolean isDefaultRenderingAvailable = false; + IPreferenceStore store = MemoryBrowserPlugin.getDefault().getPreferenceStore(); + String defaultRendering = store.getString(PREF_DEFAULT_RENDERING); + if(defaultRendering == null || defaultRendering.trim().length() == 0) + { + defaultRendering = "org.eclipse.cdt.debug.ui.memory.traditional.TraditionalRendering"; //$NON-NLS-1$ + } + + IMemoryRenderingType[] types = getRenderingTypes(); + for(final IMemoryRenderingType type : types) + { + if(type.getId().equals(defaultRendering)) + { + isDefaultRenderingAvailable = true; + break; + } + } + if(isDefaultRenderingAvailable) + defaultRenderingTypeId = defaultRendering; + else if(types.length > 0) + defaultRenderingTypeId = types[0].getId(); + + getSite().setSelectionProvider(new SelectionProviderAdapter()); + + fMainComposite = new Composite(parent, SWT.NONE); + + FormLayout layout = new FormLayout(); + layout.spacing = 0; + fMainComposite.setLayout(layout); + + fGotoMemorySpaceControl = new Combo(fMainComposite, SWT.DROP_DOWN | SWT.READ_ONLY); + fGotoAddressBar = new GoToAddressBarWidget(); + fGotoAddressBarControl = fGotoAddressBar.createControl(fMainComposite); + + if (fDropTarget == null) { + fDropTarget = new DropTarget(fGotoAddressBarControl, DND.DROP_COPY | DND.DROP_DEFAULT); + fDropTarget.setTransfer( new Transfer[] { TextTransfer.getInstance() }); + fDropTarget.addDropListener(new MemoryDropAdapter()); + } + + fGotoAddressBar.getButton(IDialogConstants.OK_ID).addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + performGo(false); + } + }); + + fGotoAddressBar.getButton(GoToAddressBarWidget.ID_GO_NEW_TAB).addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + performGo(true); + } + }); + + fGotoAddressBar.getExpressionWidget().addSelectionListener(new SelectionAdapter() { + @Override + public void widgetDefaultSelected(SelectionEvent e) { + performGo(false); + } + @Override + public void widgetSelected(SelectionEvent e) { + performGo(false); + } + }); + + fGotoMemorySpaceControl.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + if(fGotoMemorySpaceControl.getItemCount() >= 2) { + final CTabFolder activeFolder = (CTabFolder) fStackLayout.topControl; + if (activeFolder != null) { + final Object context = activeFolder.getData(KEY_CONTEXT); + fGotoAddressBar.loadSavedExpressions(context, fGotoMemorySpaceControl.getText()); + performGo(false); + } + } + } + }); + + + FormData data = new FormData(); + data.top = new FormAttachment(0); + data.left = new FormAttachment(fGotoMemorySpaceControl); + data.right = new FormAttachment(100); + fGotoAddressBarControl.setLayoutData(data); + + fRenderingsComposite = new Composite(fMainComposite, SWT.NONE); + data = new FormData(); + data.top = new FormAttachment(fGotoAddressBarControl); + data.left = new FormAttachment(0); + data.right = new FormAttachment(100); + data.bottom = new FormAttachment(100); + fRenderingsComposite.setLayoutData(data); + + fStackLayout = new StackLayout(); + + fRenderingsComposite.setLayout(fStackLayout); + + fUnsupportedLabel = new Label(fRenderingsComposite, SWT.NONE); + fUnsupportedLabel.setText(""); //$NON-NLS-1$ + + handleUnsupportedSelection(); + + PlatformUI.getWorkbench().getHelpSystem().setHelp(fMainComposite, MemoryBrowserPlugin.PLUGIN_ID); + makeActions(); + hookContextMenu(); + contributeToActionBars(); + + Object selection = null; + IDebugContextService contextService = + DebugUITools.getDebugContextManager().getContextService(getSite().getWorkbenchWindow()); + if (isBug145635Patched()) { + String presentationContextId = getPresentationContextId(); + contextService.addDebugContextListener(this, presentationContextId); + selection = contextService.getActiveContext(presentationContextId); + } else { + DebugUITools.addPartDebugContextListener(getSite(), this); + selection = contextService.getActiveContext(getSite().getId(), ((IViewSite)getSite()).getSecondaryId()); + } + + DebugPlugin.getDefault().addDebugEventListener(this); + + if(selection instanceof StructuredSelection) + handleDebugContextChanged(((StructuredSelection) selection).getFirstElement()); + } + + private boolean isBug145635Patched() { + Type[] managerTypes = DebugUITools.getDebugContextManager().getClass().getGenericInterfaces(); + for (int i = 0; i < managerTypes.length; i++) { + if (managerTypes[i] instanceof Class) { + Class clazz = (Class)managerTypes[i]; + if ("org.eclipse.debug.ui.contexts.IBug145635Marker".equals(clazz.getName()) ) { //$NON-NLS-1$ + return true; + } + } + } + return false; + } + + /** + * Clears the expression history for the active tab + */ + public void clearExpressionHistoryForActiveTab() { + final CTabFolder activeFolder = (CTabFolder) fStackLayout.topControl; + if (activeFolder != null) { + final Object context = activeFolder.getData(KEY_CONTEXT); + fGotoAddressBar.clearExpressionHistory(context); + } + } + + /** + * Returns the presentation context id for this view. Used to support the + * pin and clone feature patch from bug 145635. + * + * @return context id + */ + private String getPresentationContextId() { + IViewSite site = (IViewSite)getSite(); + return site.getId() + (site.getSecondaryId() != null ? (":" + site.getSecondaryId()) : ""); //$NON-NLS-1$ //$NON-NLS-2$ + } + + @Override + public void dispose() { + if (fDropTarget != null) { + fDropTarget.dispose(); + fDropTarget = null; + } + DebugPlugin.getDefault().removeDebugEventListener(this); + IDebugContextService contextService = + DebugUITools.getDebugContextManager().getContextService(getSite().getWorkbenchWindow()); + if (isBug145635Patched()) { + String presentationContextId = getPresentationContextId(); + contextService.removeDebugContextListener(this, presentationContextId); + } else { + DebugUITools.removePartDebugContextListener(getSite(), this); + } + super.dispose(); + } + + /* (non-Javadoc) + * @see org.eclipse.debug.core.IDebugEventSetListener#handleDebugEvents(org.eclipse.debug.core.DebugEvent[]) + */ + public void handleDebugEvents(DebugEvent[] events) { + for (DebugEvent event: events) { + Object source = event.getSource(); + if (event.getKind() == DebugEvent.TERMINATE && source instanceof IMemoryBlockRetrieval) { + releaseTabFolder((IMemoryBlockRetrieval)source); + } + } + } + + public IMemoryRenderingContainer getContainer(String id) { + return null; + } + + public IMemoryRenderingContainer[] getMemoryRenderingContainers() { + IMemoryRenderingContainer[] containerList = new IMemoryRenderingContainer[fCurrentContainers.size()]; + for ( int idx = 0 ; idx < fCurrentContainers.size() ; idx ++ ) { + containerList[ idx ] = fCurrentContainers.get( idx ); + } + return containerList; + } + + public IMemoryRenderingSynchronizationService getSynchronizationService() { + return null; + } + + private void handleUnsupportedSelection() { + fStackLayout.topControl = fUnsupportedLabel; + if(!fGotoAddressBarControl.isDisposed()) { + fGotoAddressBarControl.setVisible(false); + } + if(!fGotoMemorySpaceControl.isDisposed()) { + fGotoMemorySpaceControl.setVisible(false); + } + } + + private void performGo(boolean inNewTab) { + // Index zero is the 'auto' (n/a) memory space entry, unless the backend + // said we need to force a memory space selection + String memorySpace = null; + if (fGotoMemorySpaceControl.isVisible()) { + memorySpace = fGotoMemorySpaceControl.getText(); + if (memorySpace.equals(NA_MEMORY_SPACE_ID)) { + memorySpace = null; + } + assert (memorySpace == null) || (memorySpace.length() > 0); + } + + String expression = fGotoAddressBar.getExpressionText(); + if (expression.length() > 0) { + final CTabFolder activeFolder = (CTabFolder) fStackLayout.topControl; + Object context = null; + if (activeFolder != null) { + context = activeFolder.getData(KEY_CONTEXT); + } + fGotoAddressBar.addExpressionToHistory(context, expression, memorySpace); + performGo(inNewTab, expression, memorySpace); + } + } + + /* (non-Javadoc) + * @see org.eclipse.cdt.debug.ui.memory.memorybrowser.api.IMemoryBrowser#getActiveRetrieval() + */ + public IMemoryBlockRetrieval getActiveRetrieval() { + final CTabFolder activeFolder = (CTabFolder) fStackLayout.topControl; + if (activeFolder == null) + return null; + + return (IMemoryBlockRetrieval) activeFolder.getData(KEY_RETRIEVAL); + } + + public void performGo(boolean inNewTab, final String expression, final String memorySpaceId) { + final CTabFolder activeFolder = (CTabFolder) fStackLayout.topControl; + if (activeFolder != null) { + final IMemoryBlockRetrieval retrieval = (IMemoryBlockRetrieval) activeFolder.getData(KEY_RETRIEVAL); + final Object context = activeFolder.getData(KEY_CONTEXT); + IMemoryRendering rendering = null; + + CTabItem item = activeFolder.getSelection(); + if (inNewTab || item == null) + { + try { + item = createTab(activeFolder, activeFolder.getSelectionIndex() + 1); + rendering = populateTabWithRendering(item, retrieval, context, memorySpaceId, expression); + fContextFolders.put(retrieval, activeFolder); + activeFolder.setSelection(item); + getSite().getSelectionProvider().setSelection(new StructuredSelection(item.getData(KEY_RENDERING))); + handleTabActivated(item); + } catch (DebugException e1) { + fGotoAddressBar.handleExpressionStatus(new Status(Status.ERROR, MemoryBrowserPlugin.PLUGIN_ID, + Messages.getString("MemoryBrowser.FailedToGoToAddressTitle"), e1)); //$NON-NLS-1$ + if (item != null) { + item.dispose(); + } + return; + } + } else { + // Tab is already in place. However, the user may have selected + // a different memory space. If so, that requires us to switch + // out the rendering in the tab with either a new one or an + // existing one already associated with that memory space. + String oldMemorySpaceId = (String)activeFolder.getSelection().getData(KEY_MEMORY_SPACE); + assert oldMemorySpaceId == null || !oldMemorySpaceId.equals(NA_MEMORY_SPACE_ID) : "should be null reference or an explicit, valid memory space ID (not including '----')"; //$NON-NLS-1$ + if ((oldMemorySpaceId != null && !oldMemorySpaceId.equals(memorySpaceId)) + || (oldMemorySpaceId == null && memorySpaceId != null)) { + try { + rendering = populateTabWithRendering(item, retrieval, context, memorySpaceId, expression); + activeFolder.setSelection(item); + getSite().getSelectionProvider().setSelection(new StructuredSelection(item.getData(KEY_RENDERING))); + handleTabActivated(item); + } catch (DebugException e) { + fGotoAddressBar.handleExpressionStatus(new Status(Status.ERROR, MemoryBrowserPlugin.PLUGIN_ID, + Messages.getString("MemoryBrowser.FailedToGoToAddressTitle"), e)); //$NON-NLS-1$ + return; + } + } + } + + if (rendering == null) { + rendering = (IRepositionableMemoryRendering) activeFolder.getSelection().getData(KEY_RENDERING); + } + + if (retrieval instanceof IMemoryBlockRetrievalExtension && + rendering instanceof IRepositionableMemoryRendering) { + final IRepositionableMemoryRendering renderingFinal = (IRepositionableMemoryRendering) rendering; + new Thread() { + @Override + public void run() { + try { + final BigInteger newBase = getExpressionAddress(retrieval, expression, context, memorySpaceId); + IMemoryBlockExtension block = (IMemoryBlockExtension) renderingFinal.getMemoryBlock(); + if (block.supportBaseAddressModification()) { + block.setBaseAddress(newBase); + } + if(renderingFinal instanceof IRepositionableMemoryRendering2) { + ((IRepositionableMemoryRendering2)renderingFinal).goToAddress(newBase, expression); + } + else { + renderingFinal.goToAddress(newBase); + } + + runOnUIThread(new Runnable(){ + public void run() { + CTabItem selection = activeFolder.getSelection(); + selection.setData(KEY_EXPRESSION, expression); + selection.setData(KEY_EXPRESSION_ADDRESS, newBase); + fGotoAddressBar.handleExpressionStatus(Status.OK_STATUS); + updateLabel(selection, renderingFinal); + } + }); + } catch (final DebugException e1) { + // widgets update require Display + runOnUIThread(new Runnable(){ + public void run() { + fGotoAddressBar.handleExpressionStatus(new Status(Status.ERROR, MemoryBrowserPlugin.PLUGIN_ID, + Messages.getString("MemoryBrowser.FailedToGoToAddressTitle"), e1)); //$NON-NLS-1$ + } + }); + } + } + }.start(); + } + } + } + + private void updateLabel(CTabItem tab, IMemoryRendering rendering) { + // The default is to use the label provided by the base rendering + // interface. + String label = rendering.getLabel(); + + // If the rendering provides access to its viewport address (the first + // address shown in the rendering, subject to scrolling), display that + // in the tab rather than the expression that was used when the tab was + // first created. + if (rendering instanceof IMemoryRenderingViewportProvider) { + BigInteger viewportAddress = ((IMemoryRenderingViewportProvider)rendering).getViewportAddress(); + + // The base label generation puts the rendering type name in "<>" and + // appends it to the label. Fish that out + String renderingType = null; + int i = label.indexOf('<'); + if (i >= 0) { + renderingType = label.substring(i); + } + + label = null; + + // If a memory space is involved, we want to include its ID in the label + String memorySpaceID = (String)tab.getData(KEY_MEMORY_SPACE); + if (memorySpaceID != null) { + IMemoryBlockRetrieval retrieval = (IMemoryBlockRetrieval) tab.getParent().getData(KEY_RETRIEVAL); + if (retrieval instanceof IMemorySpaceAwareMemoryBlockRetrieval) { + label = ((IMemorySpaceAwareMemoryBlockRetrieval)retrieval).encodeAddress("0x" + viewportAddress.toString(16), memorySpaceID); + } + } + if (label == null) { + label = "0x" + viewportAddress.toString(16); + } + + // If the expression that was went to ("Go") is not a hex address, + // or it is but the user has scrolled/paged, then show the + // expression after the viewport hex address. Additionally, if some + // scrolling/paging has moved the viewport, also show the relative + // displacement. E.g., + // "0x10020 - gSomeVar(+20) " + // (for a tab where the user did a "Go" to "gSomeVar" then paged + // down, and where gSomeVar is at 0x10000) + // + String expression = (String)tab.getData(KEY_EXPRESSION); + BigInteger evaluatedAddress = (BigInteger)tab.getData(KEY_EXPRESSION_ADDRESS); + if(expression != null && !expression.equals("0x" + viewportAddress.toString(16))) { + label += " - " + expression; + BigInteger delta = evaluatedAddress.subtract(viewportAddress); + if (!delta.equals(BigInteger.ZERO)) { + label += "("; + label += delta.signum() < 0 ? '+' : '-'; + label += "0x" + delta.abs().toString(16) +")"; + } + } + + label += ' ' + renderingType;; + + // Allow the memory block to customize the label. The platform's + // Memory view support this (it was done in the call to + // rendering.getLabel() above) + IMemoryBlock block = rendering.getMemoryBlock(); + ILabelDecorator labelDec = (ILabelDecorator)block.getAdapter(ILabelDecorator.class); + if (labelDec != null) { + String newLabel = labelDec.decorateText(label, rendering); + if (newLabel != null) { + label = newLabel; + } + } + } + + tab.setText(label); + } + + private CTabFolder createTabFolder(Composite parent) + { + final CTabFolder folder = new CTabFolder(parent, SWT.NO_REDRAW_RESIZE | SWT.NO_TRIM | SWT.FLAT); + + ColorRegistry reg = JFaceResources.getColorRegistry(); + Color c1 = reg.get("org.eclipse.ui.workbench.ACTIVE_TAB_BG_START"), //$NON-NLS-1$ + c2 = reg.get("org.eclipse.ui.workbench.ACTIVE_TAB_BG_END"); //$NON-NLS-1$ + folder.setSelectionBackground(new Color[] {c1, c2}, new int[] {100}, true); + folder.setSelectionForeground(reg.get("org.eclipse.ui.workbench.ACTIVE_TAB_TEXT_COLOR")); //$NON-NLS-1$ + folder.setSimple(PlatformUI.getPreferenceStore().getBoolean(IWorkbenchPreferenceConstants.SHOW_TRADITIONAL_STYLE_TABS)); + folder.setBorderVisible(true); + + // listener to dispose rendering resources for each closed tab + folder.addCTabFolder2Listener(new CTabFolder2Adapter() { + @Override + public void close(CTabFolderEvent event) { + event.doit = true; + CTabItem item = (CTabItem) event.item; + disposeTab(item); + } + }); + + // listener to dispose rendering resources for all tab items when view part is closed + folder.addDisposeListener(new DisposeListener() { + public void widgetDisposed(DisposeEvent e) { + for(CTabItem tab : folder.getItems()) { + disposeTab(tab); + } + folder.removeDisposeListener(this); + } + }); + return folder; + } + + // these utility methods allow us restrict the scope of the unavoidable @SuppressWarnings + + @SuppressWarnings("unchecked") + private static Map getRenderings(CTabItem tabItem) { + return (Map)tabItem.getData(KEY_RENDERINGS); + } + + @SuppressWarnings("unchecked") + private static List getMemoryBlocks(CTabItem tabItem) { + return (List)tabItem.getData(KEY_MEMORY_BLOCKS); + } + + + /** + * dispose rendering resources associated with the tab item + * @param item + */ + private void disposeTab(CTabItem item ) { + if (item.isDisposed()) + return; + + IMemoryRenderingContainer container = (IMemoryRenderingContainer) item.getData(KEY_CONTAINER); + fCurrentContainers.remove( container ); + Map map = getRenderings(item); + Collection renderings = map.values(); + for (IMemoryRendering rendering : renderings) { + // always deactivate rendering before disposing it. + rendering.deactivated(); + rendering.dispose(); + if (rendering == fActiveRendering) { + fActiveRendering = null; + getSite().getSelectionProvider().setSelection(new StructuredSelection()); + } + } + map.clear(); + + List blocks = getMemoryBlocks(item); + for (IMemoryBlockExtension block : blocks) { + try { + block.dispose(); + } catch (DebugException e) { + MemoryBrowserPlugin.getDefault().getLog().log(new Status(Status.ERROR, MemoryBrowserPlugin.PLUGIN_ID, "Could not dispose memory block", e)); //$NON-NLS-1$ + } + } + blocks.clear(); + } + + private CTabItem createTab(CTabFolder tabFolder, int index) { + int swtStyle = SWT.CLOSE; + CTabItem tab = new CTabItem(tabFolder, swtStyle, index); + tab.setData(KEY_RENDERINGS, new HashMap()); + tab.setData(KEY_MEMORY_BLOCKS, new ArrayList()); + return tab; + } + + private void hookContextMenu() { + MenuManager menuMgr = new MenuManager("#PopupMenu"); //$NON-NLS-1$ + menuMgr.setRemoveAllWhenShown(true); + menuMgr.addMenuListener(new IMenuListener() { + public void menuAboutToShow(IMenuManager manager) { + MemoryBrowser.this.fillContextMenu(manager); + } + }); + Menu menu = menuMgr.createContextMenu(getControl()); + getControl().setMenu(menu); + } + + private void contributeToActionBars() { + IActionBars bars = getViewSite().getActionBars(); + fillLocalPullDown(bars.getMenuManager()); + fillLocalToolBar(bars.getToolBarManager()); + } + + private void fillLocalPullDown(IMenuManager manager) { + + + MenuManager sub = new MenuManager(Messages.getString("MemoryBrowser.DefaultRendering")); //$NON-NLS-1$ + + for(final IMemoryRenderingType type : getRenderingTypes()) + { + final Action action = new Action( + type.getLabel(), IAction.AS_RADIO_BUTTON) + { + @Override + public void run() + { + setDefaultRenderingTypeId(type.getId()); + } + }; + action.setChecked(type.getId().equals(getDefaultRenderingTypeId())); + sub.add(action); + } + + manager.add(sub); + manager.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS)); + } + + private void fillContextMenu(IMenuManager manager) { + manager.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS)); + } + + private void fillLocalToolBar(IToolBarManager manager) { + manager.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS)); + } + + private void makeActions() { + + } + + private IMemoryRenderingType[] getRenderingTypes() + { + return MemoryRenderingManager.getDefault().getRenderingTypes(new IMemoryBlockExtension(){ + public void connect(Object client) {} + public void disconnect(Object client) {} + public void dispose() throws DebugException {} + public int getAddressSize() throws DebugException { return 0; } + public int getAddressableSize() throws DebugException { return 0; } + public BigInteger getBigBaseAddress() throws DebugException { return null; } + public BigInteger getBigLength() throws DebugException { return null; } + public MemoryByte[] getBytesFromAddress(BigInteger address, long units) throws DebugException { return null; } + public MemoryByte[] getBytesFromOffset(BigInteger unitOffset, long addressableUnits) throws DebugException { return null; } + public Object[] getConnections() { return null; } + public String getExpression() { return null; } + public BigInteger getMemoryBlockEndAddress() throws DebugException { return null; } + public IMemoryBlockRetrieval getMemoryBlockRetrieval() { return null; } + public BigInteger getMemoryBlockStartAddress() throws DebugException { return null; } + public void setBaseAddress(BigInteger address) throws DebugException {} + public void setValue(BigInteger offset, byte[] bytes) throws DebugException {} + public boolean supportBaseAddressModification() throws DebugException { return false; } + public boolean supportsChangeManagement() { return false; } + public byte[] getBytes() throws DebugException { return null; } + public long getLength() { return 0; } + public long getStartAddress() { return 0; } + public void setValue(long offset, byte[] bytes) throws DebugException {} + public boolean supportsValueModification() { return false; } + public IDebugTarget getDebugTarget() { return null; } + public ILaunch getLaunch() { return null; } + public String getModelIdentifier() { return null; } + @SuppressWarnings({ "rawtypes", "unchecked" }) + public Object getAdapter(Class adapter) { return null; } + }); + } + + @Override + public void setFocus() { + getControl().setFocus(); + } + + public void debugContextChanged(DebugContextEvent event) { + handleDebugContextChanged(((StructuredSelection) event.getContext()).getFirstElement()); + } + + private final class MemoryBrowserRenderingContainer implements + IMemoryRenderingContainer { + private final List renderings = new ArrayList(); + + private MemoryBrowserRenderingContainer() { + } + + public void addMemoryRendering(IMemoryRendering rendering) { + // do not allow duplicated objects + if (!renderings.contains(rendering)) { + renderings.add(rendering); + } + } + + public IMemoryRendering getActiveRendering() { + return renderings.isEmpty() ? null : renderings.get(renderings.size() -1); + } + + public String getId() { + return ID; + } + + public String getLabel() { + IMemoryRendering rendering = getActiveRendering(); + return rendering != null ? rendering.getLabel() : null; + } + + public IMemoryRenderingSite getMemoryRenderingSite() { + return MemoryBrowser.this; + } + + public IMemoryRendering[] getRenderings() { + return renderings.toArray(new IMemoryRendering[renderings.size()]); + } + + public void removeMemoryRendering(IMemoryRendering rendering) { + renderings.remove(rendering); + } + } + + private final class RenderingPropertyChangeListener implements + IPropertyChangeListener { + private final CTabItem tab; + private final IMemoryRendering newRendering; + + private RenderingPropertyChangeListener(CTabItem tab, + IMemoryRendering newRendering) { + this.tab = tab; + this.newRendering = newRendering; + } + + public void propertyChange(final PropertyChangeEvent event) { + WorkbenchJob job = new WorkbenchJob("MemoryBrowser PropertyChanged") { //$NON-NLS-1$ + @Override + public IStatus runInUIThread(IProgressMonitor monitor) { + if(tab.isDisposed()) + return Status.OK_STATUS; + + if (event.getProperty().equals(IBasicPropertyConstants.P_TEXT)) + updateLabel(tab, newRendering); + return Status.OK_STATUS; + } + }; + job.setSystem(true); + job.schedule(); + } + } + + private class GetMemorySpacesRequest extends CRequest implements IMemorySpaceAwareMemoryBlockRetrieval.GetMemorySpacesRequest { + String [] fMemorySpaces; + public String[] getMemorySpaces() { + return fMemorySpaces; + } + public void setMemorySpaces(String[] memorySpaceIds) { + fMemorySpaces = memorySpaceIds; + } + } + + public void handleDebugContextChanged(final Object context) { + if(defaultRenderingTypeId == null) + return; + + IAdaptable adaptable = null; + IMemoryBlockRetrieval retrieval = null; + ILaunch launch = null; + + if(context instanceof IAdaptable) + { + adaptable = (IAdaptable) context; + retrieval = ((IMemoryBlockRetrieval) adaptable.getAdapter(IMemoryBlockRetrieval.class)); + launch = ((ILaunch) adaptable.getAdapter(ILaunch.class)); + } + + if(retrieval != null && launch != null && !launch.isTerminated()) { + if (retrieval instanceof IMemorySpaceAwareMemoryBlockRetrieval) { + final IMemoryBlockRetrieval _retrieval = retrieval; + ((IMemorySpaceAwareMemoryBlockRetrieval)retrieval).getMemorySpaces(context, new GetMemorySpacesRequest(){ + @Override + public void done() { + updateTab(_retrieval, context, isSuccess() ? getMemorySpaces() : new String[0]); + } + }); + } + else { + updateTab(retrieval, context, new String[0]); + } + } + else { + handleUnsupportedSelection(); + } + + fGotoMemorySpaceControl.pack(true); + fStackLayout.topControl.getParent().layout(true); + } + + /** + * Called to update the tab once the asynchronous query for memory spaces + * has returned a result. + * + * @param retrieval + * the retrieval object associated with the newly active debug + * context + * @param context + * the newly active context + * @param memorySpaces + * the memory spaces, if applicable. Otherwise an empty array. + */ + private void updateTab(final IMemoryBlockRetrieval retrieval, final Object context, final String[] memorySpaces) { + // GUI activity must be on the main thread + runOnUIThread(new Runnable(){ + public void run() { + if (fGotoAddressBarControl.isDisposed() || fGotoMemorySpaceControl.isDisposed()) { + return; + } + + fGotoAddressBarControl.setVisible(true); + + // If we've already created a tab folder for this retrieval + // object, bring it to the forefront. Otherwise create the + // folder. + CTabFolder tabFolder = fContextFolders.get(retrieval); + if(tabFolder != null) { + fStackLayout.topControl = tabFolder; + CTabItem tabItem = (CTabItem) tabFolder.getSelection(); + if ( tabItem != null ) { + getSite().getSelectionProvider().setSelection(new StructuredSelection(tabItem.getData(KEY_RENDERING))); + } + handleTabActivated(tabItem); + } + else { + tabFolder = createTabFolder(fRenderingsComposite); + tabFolder.addSelectionListener(new SelectionListener() { + public void widgetDefaultSelected(SelectionEvent e) {} + public void widgetSelected(SelectionEvent e) { + CTabItem tabItem = (CTabItem)e.item; + updateMemorySpaceControlSelection(tabItem); + fGotoAddressBar.loadSavedExpressions(context, fGotoMemorySpaceControl.isVisible() ? fGotoMemorySpaceControl.getText() : null); + getSite().getSelectionProvider().setSelection(new StructuredSelection(tabItem.getData(KEY_RENDERING))); + handleTabActivated(tabItem); + } + }); + + tabFolder.setData(KEY_RETRIEVAL, retrieval); + fContextFolders.put(retrieval, tabFolder); + fStackLayout.topControl = tabFolder; + } + // update debug context to the new selection + tabFolder.setData(KEY_CONTEXT, context); + + + final CTabFolder activeFolder = tabFolder; + if (!activeFolder.equals(tabFolder)) { + return; + } + + // Don't expose the memory spaces widget if there are none or + // only one memory space involved. + // https://bugs.eclipse.org/bugs/show_bug.cgi?id=309032#c50 + if (memorySpaces.length >= 2) { + fGotoMemorySpaceControl.setItems(memorySpaces); + + // Add the '----' (N/A) entry unless the retrieval object + // says it requires a memory space ID in all cases + boolean addNA = true; + if (retrieval instanceof IMemorySpaceAwareMemoryBlockRetrieval) { + addNA = !((IMemorySpaceAwareMemoryBlockRetrieval)retrieval).creatingBlockRequiresMemorySpaceID(); + } + if (addNA) { + fGotoMemorySpaceControl.add(NA_MEMORY_SPACE_ID, 0); + } + setMemorySpaceControlVisible(true); + } + else { + fGotoMemorySpaceControl.setItems(new String[0]); + setMemorySpaceControlVisible(false); + } + + updateMemorySpaceControlSelection(activeFolder.getSelection()); + fGotoAddressBar.loadSavedExpressions(context, fGotoMemorySpaceControl.isVisible() ? fGotoMemorySpaceControl.getText() : null); + + fStackLayout.topControl.getParent().layout(true); + } + }); + } + + /** + * Update the expression text in goto address widget to reflect the memory + * rendering expression + * + * @param item + * the active tab; may be null if in a "fresh" memory browser instance + */ + protected void updateExpression(CTabItem activeFolder) { + String expression = (activeFolder != null) ? (String) activeFolder.getData(KEY_EXPRESSION) : null; + if (expression != null) { + fGotoAddressBar.setExpressionText(expression); + } + } + + protected final void handleTabActivated(CTabItem item) { + if (item != null) { + updateActiveRendering((IMemoryRendering) item.getData(KEY_RENDERING)); + } + } + + private void updateActiveRendering(IMemoryRendering rendering) { + if (fActiveRendering == rendering) { + return; + } + if (fActiveRendering != null) { + fActiveRendering.deactivated(); + fActiveRendering.becomesHidden(); + } + if (rendering != null) { + rendering.activated(); + rendering.becomesVisible(); + } + fActiveRendering = rendering; + } + + private void setMemorySpaceControlVisible(boolean visible) { + FormData data = (FormData)fGotoAddressBarControl.getLayoutData(); + if (visible) { + data.left = new FormAttachment(fGotoMemorySpaceControl); + } + else { + data.left = new FormAttachment(0); + } + fGotoMemorySpaceControl.setVisible(visible); + + } + + /** + * Update the selection in the memory space combobox to reflect the memory + * space being shown in the given tab + * + * @param item + * the active tab; may be null if in a "fresh" memory browser instance + */ + private void updateMemorySpaceControlSelection(CTabItem item) { + String[] memorySpaces = fGotoMemorySpaceControl.getItems(); + if (memorySpaces.length > 0 ) { + // Don't assume that the memory space previously set in the tab + // is one of the ones now available. If it isn't, then select + // the first available one and update the tab data + boolean foundIt = false; + if (item != null) { + String currentMemorySpace = (String) item.getData(KEY_MEMORY_SPACE); + if (currentMemorySpace != null) { + assert currentMemorySpace.length() > 0; + for (String memorySpace : memorySpaces) { + if (memorySpace.equals(currentMemorySpace)) { + foundIt = true; + fGotoMemorySpaceControl.setText(currentMemorySpace); + break; + } + } + } + } + if (!foundIt) { + fGotoMemorySpaceControl.select(0); + if (item != null) { + item.setData(KEY_MEMORY_SPACE, null); + } + } + fGotoMemorySpaceControl.setVisible(true); + } + else { + fGotoMemorySpaceControl.setVisible(false); + } + fGotoMemorySpaceControl.getParent().layout(true); + + } + + private String getDefaultRenderingTypeId() + { + return defaultRenderingTypeId; + } + + public void setDefaultRenderingTypeId(String id) + { + defaultRenderingTypeId = id; + IPreferenceStore store = MemoryBrowserPlugin.getDefault().getPreferenceStore(); + store.setValue(PREF_DEFAULT_RENDERING, defaultRenderingTypeId); + } + + /** + * Populate given tab with a rendering positioned at specified expression and memory space. + * Will create a new rendering if one does not exist for the given memory space + * + * @param tab item to populate + * @param retrieval memory service to retrieve memory block from + * @param context memory block would be retrieved + * @param memorySpaceId of the expression or null if not supported + * @param expression from where to retrieve the memory block + * @return return the memory rendering or null if could not be created + * + * @throws DebugException if could not retrieve memory block (e.g. invalid expression) + */ + private IMemoryRendering populateTabWithRendering(final CTabItem tab, final IMemoryBlockRetrieval retrieval, Object context, String memorySpaceId, String expression) throws DebugException { + IMemoryRenderingType type = DebugUITools.getMemoryRenderingManager().getRenderingType(getDefaultRenderingTypeId()); + IMemoryRenderingContainer container = (IMemoryRenderingContainer)tab.getData(KEY_CONTAINER); + if (container == null) { + container = new MemoryBrowserRenderingContainer(); + fCurrentContainers.add(container); + } + + IMemoryRendering rendering = getRenderings(tab).get(memorySpaceId); + if (rendering == null) { + // No rendering yet. Create rendering and associated memory block. + // createMemoryBlock will throw if expression cannot be resolved + IMemoryBlockExtension block = createMemoryBlock(retrieval, expression, context, memorySpaceId); + try { + rendering = type.createRendering(); + } catch (CoreException e) { + MemoryBrowserPlugin.getDefault().getLog().log(new Status(Status.ERROR, MemoryBrowserPlugin.PLUGIN_ID, "", e)); //$NON-NLS-1$ + return null; + } + + rendering.init(container, block); + container.addMemoryRendering(rendering); + rendering.createControl(tab.getParent()); + getRenderings(tab).put(memorySpaceId, rendering); + getMemoryBlocks(tab).add(block); + rendering.addPropertyChangeListener(new RenderingPropertyChangeListener(tab, rendering)); + } + + tab.setControl(rendering.getControl()); + tab.getParent().setSelection(0); + tab.setData(KEY_RENDERING, rendering); + tab.setData(KEY_MEMORY_SPACE, memorySpaceId); + tab.setData(KEY_CONTAINER, container); + tab.setData(KEY_RENDERING_TYPE, type); + tab.setData(KEY_EXPRESSION, expression); + tab.setData(KEY_EXPRESSION_ADDRESS, ((IMemoryBlockExtension)rendering.getMemoryBlock()).getBigBaseAddress()); + getSite().getSelectionProvider().setSelection(new StructuredSelection(tab.getData(KEY_RENDERING))); + + return rendering; + } + + + private void releaseTabFolder(final IMemoryBlockRetrieval retrieval) + { + final CTabFolder folder = fContextFolders.get(retrieval); + if(folder != null) + { + Runnable run = new Runnable() { + public void run() { + for(CTabItem tab : folder.getItems()) { + disposeTab(tab); + } + fContextFolders.remove(retrieval); + folder.dispose(); + + if (fStackLayout.topControl.equals(folder)) { + handleUnsupportedSelection(); + } + } + }; + runOnUIThread(run); + } + } + + class SelectionProviderAdapter implements ISelectionProvider { + + List listeners = new ArrayList(); + + ISelection theSelection = StructuredSelection.EMPTY; + + public void addSelectionChangedListener(ISelectionChangedListener listener) { + listeners.add(listener); + } + + public ISelection getSelection() { + return theSelection; + } + + public void removeSelectionChangedListener( + ISelectionChangedListener listener) { + listeners.remove(listener); + } + + public void setSelection(ISelection selection) { + theSelection = selection; + final SelectionChangedEvent e = new SelectionChangedEvent(this, selection); + Object[] listenersArray = listeners.toArray(); + + for (int i = 0; i < listenersArray.length; i++) { + final ISelectionChangedListener l = (ISelectionChangedListener) listenersArray[i]; + SafeRunner.run(new SafeRunnable() { + public void run() { + l.selectionChanged(e); + } + }); + } + } + } + + /** + * create a memory block + * @param retrieval memory block retrieval. + * @param expression expression to be evaluated to an addressL + * @param context context for evaluating the expression. This is typically + * a debug element. + * @param memorySpaceID a memory space identifier, or null if n/a + * @return a memory block based on the given expression and context + * @throws DebugException if unable to retrieve the specified memory + */ + private IMemoryBlockExtension createMemoryBlock(IMemoryBlockRetrieval retrieval, String expression, Object context, String memorySpaceID) throws DebugException { + IMemoryBlockExtension block = null; + IMemoryBlockRetrievalExtension retrievalExtension = null; + if (retrieval instanceof IMemoryBlockRetrievalExtension) { + retrievalExtension = (IMemoryBlockRetrievalExtension) retrieval; + } else if(retrieval instanceof IAdaptable) { + retrievalExtension = (IMemoryBlockRetrievalExtension)((IAdaptable) retrieval).getAdapter(IMemoryBlockRetrievalExtension.class); + } + if (retrievalExtension != null) { + if (retrievalExtension instanceof IMemorySpaceAwareMemoryBlockRetrieval) { + block = ((IMemorySpaceAwareMemoryBlockRetrieval)retrievalExtension).getMemoryBlock(expression, context, memorySpaceID); + } + else { + block = retrievalExtension.getExtendedMemoryBlock(expression, context); + } + } + if ( block == null ) { + throw new DebugException(new Status(Status.ERROR, MemoryBrowserPlugin.PLUGIN_ID, "Extended Memory Block could not be obtained")); //$NON-NLS-1$ + } + return block; + } + + /** + * Get a memory address for an expression in a given context. + * @param retrieval + * @param expression + * @param context + * @return BigInteger address of the expression + * @throws DebugException + */ + private BigInteger getExpressionAddress(IMemoryBlockRetrieval retrieval, String expression, Object context, String memorySpaceId) throws DebugException { + // Until 257842 issue is solved this is done via IMemoryBlockRetrievalExtension API. + IMemoryBlockExtension newBlock = createMemoryBlock(retrieval, expression, context, memorySpaceId); + BigInteger address = newBlock.getBigBaseAddress(); + newBlock.dispose(); + return address; + } + + /** + * Execute runnable on UI thread if the current thread is not an UI thread. + * Otherwise execute it directly. + * + * @param runnable + * the runnable to execute + */ + private void runOnUIThread(final Runnable runnable) { + if (Display.getCurrent() != null) { + runnable.run(); + } + else { + UIJob job = new UIJob("Memory Browser UI Job"){ //$NON-NLS-1$ + @Override + public IStatus runInUIThread(IProgressMonitor monitor) { + runnable.run(); + return Status.OK_STATUS; + }}; + job.setSystem(true); + job.schedule(); + } + } + + /* (non-Javadoc) + * @see org.eclipse.cdt.debug.ui.memory.memorybrowser.api.IMemoryBrowser#go(java.lang.String, java.lang.String, boolean) + */ + public void go(String expression, String memorySpaceId, boolean inNewTab) + throws CoreException { + if (expression == null) { + throw new IllegalArgumentException("expression cannot be null"); + } + expression = expression.trim(); + if (expression.length() == 0) { + throw new IllegalArgumentException("expression cannot be empty"); + } + if (!fGotoMemorySpaceControl.isDisposed() && fGotoMemorySpaceControl.isVisible()) { + if (memorySpaceId == null) { + // if caller passed null, use whatever memory space is selected in the control + memorySpaceId = fGotoMemorySpaceControl.getText(); + if (memorySpaceId.equals(NA_MEMORY_SPACE_ID)) { + memorySpaceId = null; + } + } + else { + // if caller passed empty string, it means n/a (same as "----" in the selector) + memorySpaceId = memorySpaceId.trim(); + if (memorySpaceId.length() == 0) { + memorySpaceId = null; + } + else { + // Check that the ID requested by the user is a valid one + if (fGotoMemorySpaceControl.indexOf(memorySpaceId) == -1) { + throw new IllegalArgumentException("unrecognized memory space ID"); + } + } + + fGotoMemorySpaceControl.setText(memorySpaceId == null ? NA_MEMORY_SPACE_ID : memorySpaceId); + } + } + + fGotoAddressBar.setExpressionText(expression); + performGo(inNewTab, expression, memorySpaceId); + } + + /* (non-Javadoc) + * @see org.eclipse.cdt.debug.ui.memory.memorybrowser.api.IMemoryBrowser#getSelectedMemorySpace() + */ + public String getSelectedMemorySpace() { + if (!fGotoMemorySpaceControl.isDisposed() && fGotoMemorySpaceControl.isVisible()) { + String id = fGotoMemorySpaceControl.getText(); + return id.equals(NA_MEMORY_SPACE_ID) ? null : id; + } + return null; + } +} diff --git a/memory/org.eclipse.cdt.debug.ui.memory.traditional/src/org/eclipse/cdt/debug/ui/memory/traditional/ColorAndEffectFieldEditor.java b/memory/org.eclipse.cdt.debug.ui.memory.traditional/src/org/eclipse/cdt/debug/ui/memory/traditional/ColorAndEffectFieldEditor.java index be63a48eeea..328e5fd926e 100644 --- a/memory/org.eclipse.cdt.debug.ui.memory.traditional/src/org/eclipse/cdt/debug/ui/memory/traditional/ColorAndEffectFieldEditor.java +++ b/memory/org.eclipse.cdt.debug.ui.memory.traditional/src/org/eclipse/cdt/debug/ui/memory/traditional/ColorAndEffectFieldEditor.java @@ -1,99 +1,99 @@ -/******************************************************************************* - * Copyright (c) 2013 IBM Corporation and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * IBM - Initial API and implementation - *******************************************************************************/ -package org.eclipse.cdt.debug.ui.memory.traditional; - -import org.eclipse.jface.preference.ColorSelector; -import org.eclipse.jface.preference.FieldEditor; -import org.eclipse.jface.preference.IPreferenceStore; -import org.eclipse.jface.preference.PreferenceConverter; -import org.eclipse.swt.SWT; -import org.eclipse.swt.layout.GridData; -import org.eclipse.swt.widgets.Button; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Control; - -public class ColorAndEffectFieldEditor extends FieldEditor { - - private final String nameBold; - private final String nameItalic; - private final String nameBox; - - private ColorSelector colorSelector; - private Button checkBold; - private Button checkItalic; - private Button checkBox; // :) - - public ColorAndEffectFieldEditor(String name, String nameBold, String nameItalic, String nameBox, String labelText, Composite parent) { - super(name, labelText, parent); - this.nameBold = nameBold; - this.nameItalic = nameItalic; - this.nameBox = nameBox; - } - - @Override - protected void adjustForNumColumns(int numColumns) { - ((GridData) checkItalic.getLayoutData()).horizontalSpan = numColumns - 4; - } - - @Override - protected void doFillIntoGrid(Composite parent, int numColumns) { - Control control = getLabelControl(parent); - control.setLayoutData(new GridData()); - - colorSelector = new ColorSelector(parent); - colorSelector.getButton().setLayoutData(new GridData()); - - checkBold = new Button(parent, SWT.CHECK); - checkBold.setText(TraditionalRenderingMessages.getString("ColorAndEffectFieldEditor.bold")); - checkBold.setLayoutData(new GridData()); - - checkItalic = new Button(parent, SWT.CHECK); - checkItalic.setText(TraditionalRenderingMessages.getString("ColorAndEffectFieldEditor.italic")); - checkItalic.setLayoutData(new GridData()); - - checkBox = new Button(parent, SWT.CHECK); - checkBox.setText(TraditionalRenderingMessages.getString("ColorAndEffectFieldEditor.box")); - checkBox.setLayoutData(new GridData()); - } - - @Override - protected void doLoad() { - IPreferenceStore store = getPreferenceStore(); - colorSelector.setColorValue(PreferenceConverter.getColor(store, getPreferenceName())); - checkBold.setSelection(store.getBoolean(nameBold)); - checkItalic.setSelection(store.getBoolean(nameItalic)); - checkBox.setSelection(store.getBoolean(nameBox)); - } - - @Override - protected void doLoadDefault() { - IPreferenceStore store = getPreferenceStore(); - colorSelector.setColorValue(PreferenceConverter.getDefaultColor(store, getPreferenceName())); - checkBold.setSelection(store.getDefaultBoolean(nameBold)); - checkItalic.setSelection(store.getDefaultBoolean(nameItalic)); - checkBox.setSelection(store.getDefaultBoolean(nameBox)); - } - - @Override - protected void doStore() { - IPreferenceStore store = getPreferenceStore(); - PreferenceConverter.setValue(store, getPreferenceName(), colorSelector.getColorValue()); - store.setValue(nameBold, checkBold.getSelection()); - store.setValue(nameItalic, checkItalic.getSelection()); - store.setValue(nameBox, checkBox.getSelection()); - } - - @Override - public int getNumberOfControls() { - return 5; - } - -} +/******************************************************************************* + * Copyright (c) 2013 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM - Initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.debug.ui.memory.traditional; + +import org.eclipse.jface.preference.ColorSelector; +import org.eclipse.jface.preference.FieldEditor; +import org.eclipse.jface.preference.IPreferenceStore; +import org.eclipse.jface.preference.PreferenceConverter; +import org.eclipse.swt.SWT; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; + +public class ColorAndEffectFieldEditor extends FieldEditor { + + private final String nameBold; + private final String nameItalic; + private final String nameBox; + + private ColorSelector colorSelector; + private Button checkBold; + private Button checkItalic; + private Button checkBox; // :) + + public ColorAndEffectFieldEditor(String name, String nameBold, String nameItalic, String nameBox, String labelText, Composite parent) { + super(name, labelText, parent); + this.nameBold = nameBold; + this.nameItalic = nameItalic; + this.nameBox = nameBox; + } + + @Override + protected void adjustForNumColumns(int numColumns) { + ((GridData) checkItalic.getLayoutData()).horizontalSpan = numColumns - 4; + } + + @Override + protected void doFillIntoGrid(Composite parent, int numColumns) { + Control control = getLabelControl(parent); + control.setLayoutData(new GridData()); + + colorSelector = new ColorSelector(parent); + colorSelector.getButton().setLayoutData(new GridData()); + + checkBold = new Button(parent, SWT.CHECK); + checkBold.setText(TraditionalRenderingMessages.getString("ColorAndEffectFieldEditor.bold")); + checkBold.setLayoutData(new GridData()); + + checkItalic = new Button(parent, SWT.CHECK); + checkItalic.setText(TraditionalRenderingMessages.getString("ColorAndEffectFieldEditor.italic")); + checkItalic.setLayoutData(new GridData()); + + checkBox = new Button(parent, SWT.CHECK); + checkBox.setText(TraditionalRenderingMessages.getString("ColorAndEffectFieldEditor.box")); + checkBox.setLayoutData(new GridData()); + } + + @Override + protected void doLoad() { + IPreferenceStore store = getPreferenceStore(); + colorSelector.setColorValue(PreferenceConverter.getColor(store, getPreferenceName())); + checkBold.setSelection(store.getBoolean(nameBold)); + checkItalic.setSelection(store.getBoolean(nameItalic)); + checkBox.setSelection(store.getBoolean(nameBox)); + } + + @Override + protected void doLoadDefault() { + IPreferenceStore store = getPreferenceStore(); + colorSelector.setColorValue(PreferenceConverter.getDefaultColor(store, getPreferenceName())); + checkBold.setSelection(store.getDefaultBoolean(nameBold)); + checkItalic.setSelection(store.getDefaultBoolean(nameItalic)); + checkBox.setSelection(store.getDefaultBoolean(nameBox)); + } + + @Override + protected void doStore() { + IPreferenceStore store = getPreferenceStore(); + PreferenceConverter.setValue(store, getPreferenceName(), colorSelector.getColorValue()); + store.setValue(nameBold, checkBold.getSelection()); + store.setValue(nameItalic, checkItalic.getSelection()); + store.setValue(nameBox, checkBox.getSelection()); + } + + @Override + public int getNumberOfControls() { + return 5; + } + +}