blob: 05013b0cc9ddda73224c69c8f94594faadb8c89e [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2004, 2017 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* IBM Corporation - initial API and implementation
* WindRiver - Bug 192028 [Memory View] Memory view does not
* display memory blocks that do not reference IDebugTarget
*
*******************************************************************************/
package org.eclipse.debug.internal.ui.views.memory;
import java.util.ArrayList;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.debug.core.DebugEvent;
import org.eclipse.debug.core.DebugPlugin;
import org.eclipse.debug.core.IDebugEventSetListener;
import org.eclipse.debug.core.IMemoryBlockListener;
import org.eclipse.debug.core.model.IDebugTarget;
import org.eclipse.debug.core.model.IMemoryBlock;
import org.eclipse.debug.core.model.IMemoryBlockRetrieval;
import org.eclipse.debug.internal.ui.DebugPluginImages;
import org.eclipse.debug.internal.ui.DebugUIMessages;
import org.eclipse.debug.internal.ui.DebugUIPlugin;
import org.eclipse.debug.internal.ui.IInternalDebugUIConstants;
import org.eclipse.debug.internal.ui.memory.provisional.MemoryViewPresentationContext;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
import org.eclipse.debug.ui.DebugUITools;
import org.eclipse.debug.ui.IDebugUIConstants;
import org.eclipse.debug.ui.contexts.DebugContextEvent;
import org.eclipse.debug.ui.contexts.IDebugContextListener;
import org.eclipse.debug.ui.memory.IMemoryRendering;
import org.eclipse.debug.ui.memory.IMemoryRenderingContainer;
import org.eclipse.debug.ui.memory.IMemoryRenderingSite;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.action.IMenuListener;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.action.Separator;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.ISelectionProvider;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.StructuredViewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.ui.ISelectionListener;
import org.eclipse.ui.IViewPart;
import org.eclipse.ui.IWorkbenchActionConstants;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.progress.UIJob;
/**
* Tree viewer for memory blocks
*/
public class MemoryBlocksTreeViewPane implements ISelectionListener, ISelectionChangedListener, IMemoryViewPane, IMemoryRenderingContainer {
public static final String PANE_ID = DebugUIPlugin.getUniqueIdentifier() + ".MemoryView.MemoryBlocksTreeViewPane"; //$NON-NLS-1$
private IViewPart fParent;
private IPresentationContext fPresentationContext;
private MemoryViewTreeViewer fTreeViewer;
protected IMemoryBlockRetrieval fRetrieval;
private ViewPaneSelectionProvider fSelectionProvider;
private AddMemoryBlockAction fAddMemoryBlockAction;
private IAction fRemoveMemoryBlockAction;
private IAction fRemoveAllMemoryBlocksAction;
private String fPaneId;
private boolean fVisible = true;
private TreeViewPaneContextListener fDebugContextListener;
private ViewPaneEventHandler fEvtHandler;
private String fLabel;
class TreeViewerRemoveMemoryBlocksAction extends Action {
TreeViewerRemoveMemoryBlocksAction() {
super();
setText(DebugUIMessages.RemoveMemoryBlockAction_title);
setToolTipText(DebugUIMessages.RemoveMemoryBlockAction_tooltip);
setImageDescriptor(DebugPluginImages.getImageDescriptor(IInternalDebugUIConstants.IMG_ELCL_REMOVE_MEMORY));
setHoverImageDescriptor(DebugPluginImages.getImageDescriptor(IInternalDebugUIConstants.IMG_LCL_REMOVE_MEMORY));
setDisabledImageDescriptor(DebugPluginImages.getImageDescriptor(IInternalDebugUIConstants.IMG_DLCL_REMOVE_MEMORY));
PlatformUI.getWorkbench().getHelpSystem().setHelp(this, IDebugUIConstants.PLUGIN_ID + ".RemoveMemoryBlockAction_context"); //$NON-NLS-1$
setEnabled(true);
}
/*
* (non-Javadoc)
* @see org.eclipse.jface.action.IAction#run()
*/
@Override
public void run() {
ISelection selected = fTreeViewer.getSelection();
if (selected != null && selected instanceof IStructuredSelection) {
Object[] selectedMemBlks = ((IStructuredSelection) selected).toArray();
ArrayList<Object> memoryBlocks = new ArrayList<>();
for (int i = 0; i < selectedMemBlks.length; i++) {
if (selectedMemBlks[i] instanceof IMemoryBlock) {
memoryBlocks.add(selectedMemBlks[i]);
}
}
DebugPlugin.getDefault().getMemoryBlockManager().removeMemoryBlocks(memoryBlocks.toArray(new IMemoryBlock[memoryBlocks.size()]));
}
}
}
class TreeViewerRemoveAllMemoryBlocksAction extends Action {
TreeViewerRemoveAllMemoryBlocksAction() {
super();
setText(DebugUIMessages.MemoryBlocksTreeViewPane_2);
setToolTipText(DebugUIMessages.MemoryBlocksTreeViewPane_2);
setImageDescriptor(DebugPluginImages.getImageDescriptor(IInternalDebugUIConstants.IMG_ELCL_REMOVE_ALL));
setHoverImageDescriptor(DebugPluginImages.getImageDescriptor(IInternalDebugUIConstants.IMG_ELCL_REMOVE_ALL));
setDisabledImageDescriptor(DebugPluginImages.getImageDescriptor(IInternalDebugUIConstants.IMG_DLCL_REMOVE_ALL));
PlatformUI.getWorkbench().getHelpSystem().setHelp(this, IDebugUIConstants.PLUGIN_ID + ".RemoveAllMemoryBlocksAction_context"); //$NON-NLS-1$
}
/*
* (non-Javadoc)
* @see org.eclipse.jface.action.IAction#run()
*/
@Override
public void run() {
IWorkbenchWindow window = DebugUIPlugin.getActiveWorkbenchWindow();
if (window == null) {
return;
}
boolean proceed = MessageDialog.openQuestion(window.getShell(), DebugUIMessages.MemoryBlocksTreeViewPane_0, DebugUIMessages.MemoryBlocksTreeViewPane_1); //
if (proceed) {
IMemoryBlock[] memoryBlocks = DebugPlugin.getDefault().getMemoryBlockManager().getMemoryBlocks(fRetrieval);
DebugPlugin.getDefault().getMemoryBlockManager().removeMemoryBlocks(memoryBlocks);
}
}
}
class ViewPaneEventHandler implements IMemoryBlockListener, IDebugEventSetListener {
private boolean fDisposed = false;
public ViewPaneEventHandler() {
DebugPlugin.getDefault().getMemoryBlockManager().addListener(this);
DebugPlugin.getDefault().addDebugEventListener(this);
}
/*
* (non-Javadoc)
* @see org.eclipse.jface.viewers.IContentProvider#dispose()
*/
public void dispose() {
fDisposed = true;
DebugPlugin.getDefault().getMemoryBlockManager().removeListener(this);
DebugPlugin.getDefault().removeDebugEventListener(this);
}
/*
* (non-Javadoc)
* @see org.eclipse.debug.internal.core.memory.IMemoryBlockListener#
* MemoryBlockAdded(org.eclipse.debug.core.model.IMemoryBlock)
*/
@Override
public void memoryBlocksAdded(final IMemoryBlock[] memory) {
// if the content provider is disposed, do not handle event
if (fDisposed) {
return;
}
updateActionsEnablement();
}
/*
* (non-Javadoc)
* @see org.eclipse.debug.internal.core.memory.IMemoryBlockListener#
* MemoryBlockRemoved(org.eclipse.debug.core.model.IMemoryBlock)
*/
@Override
public void memoryBlocksRemoved(final IMemoryBlock[] memory) {
if (fDisposed) {
return;
}
updateActionsEnablement();
}
/*
* (non-Javadoc)
* @see
* org.eclipse.debug.internal.ui.views.memory.BasicDebugViewContentProvider
* #doHandleDebugEvent(org.eclipse.debug.core.DebugEvent)
*/
protected void doHandleDebugEvent(DebugEvent event) {
// if the view is disposed, do not handle event
if (fDisposed) {
return;
}
if (event.getKind() == DebugEvent.TERMINATE) {
// should only handle the terminate event if the target is
// terminated
if (event.getSource() instanceof IDebugTarget) {
IMemoryBlockRetrieval srcRetrieval = MemoryViewUtil.getMemoryBlockRetrieval(event.getSource());
if (srcRetrieval == fRetrieval) {
// #setInput must be done on the UI thread
UIJob job = new UIJob("setInput") { //$NON-NLS-1$
@Override
public IStatus runInUIThread(IProgressMonitor monitor) {
// if viewpane is disposed, do not handle event
if (fTreeViewer.getContentProvider() == null) {
return Status.OK_STATUS;
}
fTreeViewer.setInput(null);
return Status.OK_STATUS;
}
};
job.setSystem(true);
job.schedule();
}
}
}
}
@Override
public void handleDebugEvents(DebugEvent[] events) {
for (int i = 0; i < events.length; i++) {
doHandleDebugEvent(events[i]);
}
}
}
class TreeViewPaneContextListener implements IDebugContextListener {
public void contextActivated(ISelection selection) {
if (selection.isEmpty() && fRetrieval != null) {
fRetrieval = null;
if (fTreeViewer != null && fTreeViewer.getContentProvider() != null) {
fTreeViewer.setInput(fRetrieval);
}
updateActionsEnablement();
return;
}
if (selection instanceof IStructuredSelection) {
Object obj = ((IStructuredSelection) selection).getFirstElement();
if (obj instanceof IAdaptable) {
IAdaptable context = (IAdaptable) obj;
IMemoryBlockRetrieval retrieval = MemoryViewUtil.getMemoryBlockRetrieval(context);
if (retrieval != null && fTreeViewer != null && (retrieval != fRetrieval || retrieval != fTreeViewer.getInput()) && fTreeViewer.getContentProvider() != null) {
// set new setting
fRetrieval = retrieval;
fTreeViewer.setInput(fRetrieval);
}
updateActionsEnablement();
}
}
}
/*
* (non-Javadoc)
* @see
* org.eclipse.debug.internal.ui.contexts.provisional.IDebugContextListener
* #contextEvent(org.eclipse.debug.internal.ui.contexts.provisional.
* DebugContextEvent)
*/
@Override
public void debugContextChanged(DebugContextEvent event) {
if ((event.getFlags() & DebugContextEvent.ACTIVATED) > 0) {
contextActivated(event.getContext());
}
}
}
public MemoryBlocksTreeViewPane(IViewPart parent) {
fParent = parent;
fSelectionProvider = new ViewPaneSelectionProvider();
}
@Override
public Control createViewPane(Composite parent, String paneId, String label) {
fPaneId = paneId;
int style = SWT.MULTI | SWT.V_SCROLL | SWT.H_SCROLL | SWT.VIRTUAL;
fLabel = label;
IMemoryRenderingSite site = getMemoryRenderingSite();
fPresentationContext = new MemoryViewPresentationContext(site, this, null);
fTreeViewer = new MemoryViewTreeViewer(parent, style, fPresentationContext);
IAdaptable context = DebugUITools.getPartDebugContext(fParent.getSite());
IMemoryBlockRetrieval retrieval = MemoryViewUtil.getMemoryBlockRetrieval(context);
if (retrieval != null) {
fTreeViewer.setInput(retrieval);
}
fRetrieval = retrieval;
fParent.getViewSite().getSelectionProvider().addSelectionChangedListener(this);
fParent.getViewSite().getPage().addSelectionListener(this);
fDebugContextListener = new TreeViewPaneContextListener();
DebugUITools.addPartDebugContextListener(fParent.getSite(), fDebugContextListener);
fTreeViewer.addSelectionChangedListener(new ISelectionChangedListener() {
@Override
public void selectionChanged(SelectionChangedEvent event) {
ISelection treeSelected = event.getSelection();
fSelectionProvider.setSelection(treeSelected);
}
});
updateRetrieval();
fEvtHandler = new ViewPaneEventHandler();
// create context menu
MenuManager mgr = createContextMenuManager();
Menu menu = mgr.createContextMenu(fTreeViewer.getControl());
fTreeViewer.getControl().setMenu(menu);
GridData data = new GridData();
data.grabExcessHorizontalSpace = true;
data.grabExcessVerticalSpace = true;
data.horizontalAlignment = SWT.FILL;
data.verticalAlignment = SWT.FILL;
fTreeViewer.getControl().setLayoutData(data);
updateActionsEnablement();
return fTreeViewer.getControl();
}
/**
*
*/
private void updateRetrieval() {
Object context = DebugUITools.getPartDebugContext(fParent.getSite());
fRetrieval = MemoryViewUtil.getMemoryBlockRetrieval(context);
}
protected MenuManager createContextMenuManager() {
MenuManager menuMgr = new MenuManager("#PopupMenu"); //$NON-NLS-1$
menuMgr.setRemoveAllWhenShown(true);
menuMgr.addMenuListener(new IMenuListener() {
@Override
public void menuAboutToShow(IMenuManager manager) {
manager.add(fAddMemoryBlockAction);
manager.add(fRemoveMemoryBlockAction);
manager.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS));
}
});
// register a context menu manager, use its pane id as the menu id
fParent.getSite().registerContextMenu(getId(), menuMgr, fSelectionProvider);
return menuMgr;
}
@Override
public void dispose() {
fParent.getViewSite().getSelectionProvider().removeSelectionChangedListener(this);
fParent.getViewSite().getPage().removeSelectionListener(this);
fAddMemoryBlockAction.dispose();
DebugUITools.removePartDebugContextListener(fParent.getSite(), fDebugContextListener);
fEvtHandler.dispose();
fPresentationContext.dispose();
}
/*
* (non-Javadoc)
* @see org.eclipse.ui.ISelectionListener#selectionChanged(org.eclipse.ui.
* IWorkbenchPart, org.eclipse.jface.viewers.ISelection)
*/
@Override
public void selectionChanged(IWorkbenchPart part, ISelection selection) {
if (selection instanceof IStructuredSelection) {
Object obj = ((IStructuredSelection) selection).getFirstElement();
if (obj instanceof IMemoryBlock) {
// if the selection event comes from this view
if (part == fParent) {
// do not change selection if the selection is already
// correct
ISelection treeSel = fTreeViewer.getSelection();
if (treeSel instanceof IStructuredSelection) {
if (((IStructuredSelection) treeSel).getFirstElement() == obj) {
return;
}
}
// remove itself as selection listener when handling
// selection changed event
removeSelctionListener(this);
fTreeViewer.setSelection(selection);
// remove itself as selection listener when handling
// selection changed event
addSelectionListener(this);
}
}
}
}
@Override
public String getId() {
return fPaneId;
}
/*
* (non-Javadoc)
* @see
* org.eclipse.debug.internal.ui.views.memory.IMemoryViewPane#getActions()
*/
@Override
public IAction[] getActions() {
if (fAddMemoryBlockAction == null) {
fAddMemoryBlockAction = new RetargetAddMemoryBlockAction((IMemoryRenderingSite) fParent);
}
if (fRemoveMemoryBlockAction == null) {
fRemoveMemoryBlockAction = new TreeViewerRemoveMemoryBlocksAction();
}
if (fRemoveAllMemoryBlocksAction == null) {
fRemoveAllMemoryBlocksAction = new TreeViewerRemoveAllMemoryBlocksAction();
}
updateActionsEnablement();
return new IAction[] {
fAddMemoryBlockAction, fRemoveMemoryBlockAction,
fRemoveAllMemoryBlocksAction };
}
/*
* (non-Javadoc)
* @see org.eclipse.debug.internal.ui.views.memory.IMemoryViewPane#
* addSelectionListener(org.eclipse.jface.viewers.ISelectionChangedListener)
*/
@Override
public void addSelectionListener(ISelectionChangedListener listener) {
if (fSelectionProvider == null) {
fSelectionProvider = new ViewPaneSelectionProvider();
}
fSelectionProvider.addSelectionChangedListener(listener);
}
/*
* (non-Javadoc)
* @see org.eclipse.debug.internal.ui.views.memory.IMemoryViewPane#
* removeSelctionListener
* (org.eclipse.jface.viewers.ISelectionChangedListener)
*/
@Override
public void removeSelctionListener(ISelectionChangedListener listener) {
if (fSelectionProvider == null) {
return;
}
fSelectionProvider.removeSelectionChangedListener(listener);
}
/*
* (non-Javadoc)
* @see org.eclipse.debug.internal.ui.views.memory.IMemoryViewPane#
* getSelectionProvider()
*/
@Override
public ISelectionProvider getSelectionProvider() {
return fSelectionProvider;
}
/*
* (non-Javadoc)
* @see
* org.eclipse.debug.internal.ui.views.memory.IMemoryViewPane#restoreViewPane
* ()
*/
@Override
public void restoreViewPane() {
updateRetrieval();
updateActionsEnablement();
}
/*
* (non-Javadoc)
* @see
* org.eclipse.debug.internal.ui.views.memory.IMemoryViewPane#getControl()
*/
@Override
public Control getControl() {
return fTreeViewer.getControl();
}
/*
* (non-Javadoc)
* @see
* org.eclipse.debug.internal.ui.views.memory.IMemoryViewPane#setVisible
* (boolean)
*/
@Override
public void setVisible(boolean visible) {
if (fVisible != visible) {
fVisible = visible;
if (fVisible) {
fTreeViewer.refresh();
fTreeViewer.getControl().setFocus();
}
}
}
/*
* (non-Javadoc)
* @see
* org.eclipse.debug.internal.ui.views.memory.IMemoryViewPane#isVisible()
*/
@Override
public boolean isVisible() {
return fVisible;
}
private void updateActionsEnablement() {
if (fRemoveMemoryBlockAction == null) {
return;
}
if (fRemoveAllMemoryBlocksAction == null) {
return;
}
if (fRetrieval != null) {
IMemoryBlock[] memBlocks = DebugPlugin.getDefault().getMemoryBlockManager().getMemoryBlocks(fRetrieval);
if (memBlocks.length > 0) {
fRemoveMemoryBlockAction.setEnabled(true);
fRemoveAllMemoryBlocksAction.setEnabled(true);
} else {
fRemoveMemoryBlockAction.setEnabled(false);
fRemoveAllMemoryBlocksAction.setEnabled(false);
}
} else {
fRemoveMemoryBlockAction.setEnabled(false);
fRemoveAllMemoryBlocksAction.setEnabled(false);
}
}
@Override
public void selectionChanged(SelectionChangedEvent event) {
// only handle selection changed from parent's selection provider
if (event.getSource() == fParent.getSite().getSelectionProvider()) {
MemoryBlocksTreeViewPane.this.selectionChanged(fParent, event.getSelection());
}
}
public StructuredViewer getViewer() {
return fTreeViewer;
}
@Override
public IMemoryRenderingSite getMemoryRenderingSite() {
if (fParent instanceof IMemoryRenderingSite) {
return (IMemoryRenderingSite) fParent;
}
return null;
}
@Override
public void addMemoryRendering(IMemoryRendering rendering) {
// do nothing
}
@Override
public void removeMemoryRendering(IMemoryRendering rendering) {
// do nothing
}
@Override
public IMemoryRendering[] getRenderings() {
return new IMemoryRendering[0];
}
@Override
public IMemoryRendering getActiveRendering() {
return null;
}
@Override
public String getLabel() {
return fLabel;
}
}