mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-08-07 00:05:53 +02:00
[255026] [expressions][cdi] Support for advanced expression hover
This commit is contained in:
parent
d15ff47ef8
commit
ab53de8c4f
5 changed files with 875 additions and 6 deletions
|
@ -0,0 +1,441 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2008, 2009 IBM Corporation and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* IBM Corporation - initial API and implementation
|
||||
* Wind River Systems - adapted for DSF
|
||||
*******************************************************************************/
|
||||
package org.eclipse.cdt.dsf.debug.internal.ui;
|
||||
|
||||
import org.eclipse.cdt.dsf.debug.service.IExpressions.IExpressionDMContext;
|
||||
import org.eclipse.cdt.dsf.debug.ui.IDsfDebugUIConstants;
|
||||
import org.eclipse.cdt.dsf.internal.ui.DsfUIPlugin;
|
||||
import org.eclipse.core.runtime.CoreException;
|
||||
import org.eclipse.debug.core.model.IVariable;
|
||||
import org.eclipse.debug.internal.ui.SWTFactory;
|
||||
import org.eclipse.debug.internal.ui.model.elements.ElementContentProvider;
|
||||
import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate;
|
||||
import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
|
||||
import org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerInputRequestor;
|
||||
import org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerInputUpdate;
|
||||
import org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerUpdate;
|
||||
import org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerUpdateListener;
|
||||
import org.eclipse.debug.internal.ui.viewers.model.provisional.PresentationContext;
|
||||
import org.eclipse.debug.internal.ui.viewers.model.provisional.TreeModelViewer;
|
||||
import org.eclipse.debug.internal.ui.viewers.model.provisional.ViewerInputService;
|
||||
import org.eclipse.debug.internal.ui.views.variables.details.DefaultDetailPane;
|
||||
import org.eclipse.debug.internal.ui.views.variables.details.DetailPaneProxy;
|
||||
import org.eclipse.debug.internal.ui.views.variables.details.IDetailPaneContainer;
|
||||
import org.eclipse.debug.ui.AbstractDebugView;
|
||||
import org.eclipse.debug.ui.IDebugUIConstants;
|
||||
import org.eclipse.jface.dialogs.IDialogSettings;
|
||||
import org.eclipse.jface.text.AbstractInformationControl;
|
||||
import org.eclipse.jface.text.IInformationControl;
|
||||
import org.eclipse.jface.text.IInformationControlCreator;
|
||||
import org.eclipse.jface.text.IInformationControlExtension2;
|
||||
import org.eclipse.jface.viewers.IStructuredSelection;
|
||||
import org.eclipse.jface.viewers.StructuredViewer;
|
||||
import org.eclipse.jface.viewers.TreeSelection;
|
||||
import org.eclipse.jface.viewers.ViewerFilter;
|
||||
import org.eclipse.swt.SWT;
|
||||
import org.eclipse.swt.custom.SashForm;
|
||||
import org.eclipse.swt.events.SelectionEvent;
|
||||
import org.eclipse.swt.events.SelectionListener;
|
||||
import org.eclipse.swt.graphics.Color;
|
||||
import org.eclipse.swt.graphics.Point;
|
||||
import org.eclipse.swt.layout.GridData;
|
||||
import org.eclipse.swt.layout.GridLayout;
|
||||
import org.eclipse.swt.widgets.Composite;
|
||||
import org.eclipse.swt.widgets.Layout;
|
||||
import org.eclipse.swt.widgets.Shell;
|
||||
import org.eclipse.swt.widgets.Tree;
|
||||
import org.eclipse.ui.IWorkbenchPage;
|
||||
import org.eclipse.ui.IWorkbenchPartSite;
|
||||
|
||||
/**
|
||||
* Creates an information control to display an expression in a hover control.
|
||||
* <br/> This class is derivative work from JDT's <code>ExpressionInformationControlCreator</code>.
|
||||
*
|
||||
* @noextend This class is not intended to be subclassed by clients.
|
||||
*
|
||||
* @since 2.1
|
||||
*/
|
||||
@SuppressWarnings("restriction")
|
||||
public class ExpressionInformationControlCreator implements IInformationControlCreator {
|
||||
|
||||
class ExpressionInformationControl extends AbstractInformationControl implements IInformationControlExtension2, IViewerInputRequestor {
|
||||
|
||||
/**
|
||||
* Dialog setting key for height
|
||||
*/
|
||||
private static final String HEIGHT = "HEIGHT"; //$NON-NLS-1$
|
||||
|
||||
/**
|
||||
* Dialog setting key for width.
|
||||
*/
|
||||
private static final String WIDTH = "WIDTH"; //$NON-NLS-1$
|
||||
|
||||
/**
|
||||
* Dialog setting key for tree sash weight
|
||||
*/
|
||||
private static final String SASH_WEIGHT_TREE = "SashWeightTree"; //$NON-NLS-1$
|
||||
|
||||
/**
|
||||
* Dialog setting key for details sash weight
|
||||
*/
|
||||
private static final String SASH_WEIGHT_DETAILS = "SashWeightDetails"; //$NON-NLS-1$
|
||||
|
||||
/**
|
||||
* Variable to display.
|
||||
*/
|
||||
private Object fVariable;
|
||||
|
||||
private TreeModelViewer fViewer;
|
||||
private SashForm fSashForm;
|
||||
private Composite fDetailPaneComposite;
|
||||
private DetailPaneProxy fDetailPane;
|
||||
private Tree fTree;
|
||||
|
||||
private ViewerInputService fInputService;
|
||||
|
||||
/**
|
||||
* Creates the content for the root element of the tree viewer in the hover
|
||||
*/
|
||||
private class TreeRoot extends ElementContentProvider {
|
||||
@Override
|
||||
protected int getChildCount(Object element, IPresentationContext context, IViewerUpdate monitor) throws CoreException {
|
||||
return 1;
|
||||
}
|
||||
@Override
|
||||
protected Object[] getChildren(Object parent, int index, int length, IPresentationContext context, IViewerUpdate monitor) throws CoreException {
|
||||
return new Object[] { fVariable };
|
||||
}
|
||||
@Override
|
||||
protected boolean supportsContextId(String id) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Inner class implementing IDetailPaneContainer methods. Handles changes to detail
|
||||
* pane and provides limited access to the detail pane proxy.
|
||||
*/
|
||||
private class DetailPaneContainer implements IDetailPaneContainer {
|
||||
|
||||
/*
|
||||
* @see org.eclipse.debug.internal.ui.views.variables.details.IDetailPaneContainer#getCurrentPaneID()
|
||||
*/
|
||||
public String getCurrentPaneID() {
|
||||
return fDetailPane.getCurrentPaneID();
|
||||
}
|
||||
|
||||
/*
|
||||
* @see org.eclipse.debug.internal.ui.views.variables.details.IDetailPaneContainer#getCurrentSelection()
|
||||
*/
|
||||
public IStructuredSelection getCurrentSelection() {
|
||||
return (IStructuredSelection)fViewer.getSelection();
|
||||
}
|
||||
|
||||
/*
|
||||
* @see org.eclipse.debug.internal.ui.views.variables.details.IDetailPaneContainer#refreshDetailPaneContents()
|
||||
*/
|
||||
public void refreshDetailPaneContents() {
|
||||
fDetailPane.display(getCurrentSelection());
|
||||
}
|
||||
|
||||
/*
|
||||
* @see org.eclipse.debug.internal.ui.views.variables.details.IDetailPaneContainer#getParentComposite()
|
||||
*/
|
||||
public Composite getParentComposite() {
|
||||
return fDetailPaneComposite;
|
||||
}
|
||||
|
||||
/*
|
||||
* @see org.eclipse.debug.internal.ui.views.variables.details.IDetailPaneContainer#getWorkbenchPartSite()
|
||||
*/
|
||||
public IWorkbenchPartSite getWorkbenchPartSite() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/*
|
||||
* @see org.eclipse.debug.internal.ui.views.variables.details.IDetailPaneContainer#paneChanged(java.lang.String)
|
||||
*/
|
||||
public void paneChanged(String newPaneID) {
|
||||
if (DefaultDetailPane.ID.equals(newPaneID)){
|
||||
fDetailPane.getCurrentControl().setBackground(getShell().getDisplay().getSystemColor(SWT.COLOR_INFO_BACKGROUND));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new control in the given shell.
|
||||
*
|
||||
* @param parentShell shell
|
||||
* @param resize whether resize is supported
|
||||
*/
|
||||
ExpressionInformationControl(Shell parentShell, boolean resize) {
|
||||
super(parentShell, resize);
|
||||
create();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Point computeSizeHint() {
|
||||
IDialogSettings settings = getDialogSettings(false);
|
||||
if (settings != null) {
|
||||
int x = getIntSetting(settings, WIDTH);
|
||||
if (x > 0) {
|
||||
int y = getIntSetting(settings, HEIGHT);
|
||||
if (y > 0) {
|
||||
return new Point(x,y);
|
||||
}
|
||||
}
|
||||
}
|
||||
return super.computeSizeHint();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the dialog settings for this hover or <code>null</code> if none
|
||||
*
|
||||
* @param create whether to create the settings
|
||||
*/
|
||||
private IDialogSettings getDialogSettings(boolean create) {
|
||||
IDialogSettings settings = DsfUIPlugin.getDefault().getDialogSettings();
|
||||
IDialogSettings section = settings.getSection(this.getClass().getName());
|
||||
if (section == null & create) {
|
||||
section = settings.addNewSection(this.getClass().getName());
|
||||
}
|
||||
return section;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an integer value in the given dialog settings or -1 if none.
|
||||
*
|
||||
* @param settings dialog settings
|
||||
* @param key key
|
||||
* @return value or -1 if not present
|
||||
*/
|
||||
private int getIntSetting(IDialogSettings settings, String key) {
|
||||
try {
|
||||
return settings.getInt(key);
|
||||
} catch (NumberFormatException e) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
persistSettings(getShell());
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
/**
|
||||
* Persists dialog settings.
|
||||
*
|
||||
* @param shell
|
||||
*/
|
||||
private void persistSettings(Shell shell) {
|
||||
if (shell != null && !shell.isDisposed()) {
|
||||
if (isResizable()) {
|
||||
IDialogSettings settings = getDialogSettings(true);
|
||||
Point size = shell.getSize();
|
||||
settings.put(WIDTH, size.x);
|
||||
settings.put(HEIGHT, size.y);
|
||||
int[] weights = fSashForm.getWeights();
|
||||
settings.put(SASH_WEIGHT_TREE, weights[0]);
|
||||
settings.put(SASH_WEIGHT_DETAILS, weights[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setVisible(boolean visible) {
|
||||
if (!visible) {
|
||||
persistSettings(getShell());
|
||||
}
|
||||
super.setVisible(visible);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void createContent(Composite parent) {
|
||||
|
||||
fSashForm = new SashForm(parent, parent.getStyle());
|
||||
fSashForm.setOrientation(SWT.VERTICAL);
|
||||
|
||||
// update presentation context
|
||||
AbstractDebugView view = getViewToEmulate();
|
||||
IPresentationContext context = new PresentationContext(IDsfDebugUIConstants.ID_EXPRESSION_HOVER);
|
||||
if (view != null) {
|
||||
// copy over properties
|
||||
IPresentationContext copy = ((TreeModelViewer)view.getViewer()).getPresentationContext();
|
||||
try {
|
||||
String[] properties = copy.getProperties();
|
||||
for (int i = 0; i < properties.length; i++) {
|
||||
String key = properties[i];
|
||||
context.setProperty(key, copy.getProperty(key));
|
||||
}
|
||||
} catch (NoSuchMethodError e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
|
||||
fViewer = new TreeModelViewer(fSashForm, SWT.NO_TRIM | SWT.MULTI | SWT.VIRTUAL, context);
|
||||
fViewer.setAutoExpandLevel(1);
|
||||
|
||||
if (view != null) {
|
||||
// copy over filters
|
||||
StructuredViewer structuredViewer = (StructuredViewer) view.getViewer();
|
||||
if (structuredViewer != null) {
|
||||
ViewerFilter[] filters = structuredViewer.getFilters();
|
||||
for (int i = 0; i < filters.length; i++) {
|
||||
fViewer.addFilter(filters[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
fInputService = new ViewerInputService(fViewer, this);
|
||||
|
||||
fDetailPaneComposite = SWTFactory.createComposite(fSashForm, 1, 1, GridData.FILL_BOTH);
|
||||
Layout layout = fDetailPaneComposite.getLayout();
|
||||
if (layout instanceof GridLayout) {
|
||||
GridLayout gl = (GridLayout) layout;
|
||||
gl.marginHeight = 0;
|
||||
gl.marginWidth = 0;
|
||||
}
|
||||
|
||||
fDetailPane = new DetailPaneProxy(new DetailPaneContainer());
|
||||
fDetailPane.display(null); // Bring up the default pane so the user doesn't see an empty composite
|
||||
|
||||
fTree = fViewer.getTree();
|
||||
fTree.addSelectionListener(new SelectionListener() {
|
||||
public void widgetSelected(SelectionEvent e) {
|
||||
fDetailPane.display((IStructuredSelection)fViewer.getSelection());
|
||||
}
|
||||
public void widgetDefaultSelected(SelectionEvent e) {}
|
||||
});
|
||||
|
||||
initSashWeights();
|
||||
|
||||
// add update listener to auto-select and display details of root expression
|
||||
fViewer.addViewerUpdateListener(new IViewerUpdateListener() {
|
||||
public void viewerUpdatesComplete() {
|
||||
}
|
||||
public void viewerUpdatesBegin() {
|
||||
}
|
||||
public void updateStarted(IViewerUpdate update) {
|
||||
}
|
||||
public void updateComplete(IViewerUpdate update) {
|
||||
if (update instanceof IChildrenUpdate) {
|
||||
fViewer.removeViewerUpdateListener(this);
|
||||
fViewer.getDisplay().timerExec(100, new Runnable() {
|
||||
public void run() {
|
||||
TreeSelection selection = new TreeSelection(fViewer.getTopElementPath());
|
||||
fViewer.setSelection(selection);
|
||||
fDetailPane.display(selection);
|
||||
}});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
setBackgroundColor(getShell().getDisplay().getSystemColor(SWT.COLOR_INFO_BACKGROUND));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Attempts to find an appropriate view to emulate, this will either be the
|
||||
* variables view or the expressions view.
|
||||
* @return a view to emulate or <code>null</code>
|
||||
*/
|
||||
private AbstractDebugView getViewToEmulate() {
|
||||
IWorkbenchPage page = DsfUIPlugin.getDefault().getWorkbench().getActiveWorkbenchWindow().getActivePage();
|
||||
AbstractDebugView expressionsView = (AbstractDebugView) page.findView(IDebugUIConstants.ID_EXPRESSION_VIEW);
|
||||
if (expressionsView != null && expressionsView.isVisible()) {
|
||||
return expressionsView;
|
||||
}
|
||||
AbstractDebugView variablesView = (AbstractDebugView) page.findView(IDebugUIConstants.ID_VARIABLE_VIEW);
|
||||
if (variablesView != null && variablesView.isVisible()) {
|
||||
return variablesView;
|
||||
}
|
||||
if (expressionsView != null) {
|
||||
return expressionsView;
|
||||
}
|
||||
return variablesView;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the sash form weights from the preference store (using default values if
|
||||
* no sash weights were stored previously).
|
||||
*/
|
||||
protected void initSashWeights(){
|
||||
IDialogSettings settings = getDialogSettings(false);
|
||||
if (settings != null) {
|
||||
int tree = getIntSetting(settings, SASH_WEIGHT_TREE);
|
||||
if (tree > 0) {
|
||||
int details = getIntSetting(settings, SASH_WEIGHT_DETAILS);
|
||||
if (details > 0) {
|
||||
fSashForm.setWeights(new int[]{tree, details});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBackgroundColor(Color background) {
|
||||
super.setBackgroundColor(background);
|
||||
fDetailPaneComposite.setBackground(background);
|
||||
fTree.setBackground(background);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFocus() {
|
||||
super.setFocus();
|
||||
fTree.setFocus();
|
||||
}
|
||||
|
||||
/*
|
||||
* @see org.eclipse.jface.text.IInformationControlExtension#hasContents()
|
||||
*/
|
||||
public boolean hasContents() {
|
||||
return fVariable != null;
|
||||
}
|
||||
|
||||
/*
|
||||
* @see org.eclipse.jface.text.IInformationControlExtension2#setInput(java.lang.Object)
|
||||
*/
|
||||
public void setInput(Object input) {
|
||||
if (input instanceof IExpressionDMContext) {
|
||||
fVariable = input;
|
||||
fInputService.resolveViewerInput(input);
|
||||
} else if (input instanceof IVariable) {
|
||||
fVariable = input;
|
||||
fViewer.setInput(new TreeRoot());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public IInformationControlCreator getInformationPresenterControlCreator() {
|
||||
return new ExpressionInformationControlCreator() {
|
||||
@Override
|
||||
public IInformationControl createInformationControl(Shell shell) {
|
||||
return new ExpressionInformationControl(shell, true);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public void viewerInputComplete(IViewerInputUpdate update) {
|
||||
fViewer.setInput(fVariable = update.getInputElement());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* @see org.eclipse.jface.text.IInformationControlCreator#createInformationControl(org.eclipse.swt.widgets.Shell)
|
||||
*/
|
||||
public IInformationControl createInformationControl(Shell parent) {
|
||||
return new ExpressionInformationControl(parent, false);
|
||||
}
|
||||
|
||||
}
|
|
@ -10,9 +10,13 @@
|
|||
*******************************************************************************/
|
||||
package org.eclipse.cdt.dsf.debug.ui;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
import org.eclipse.cdt.debug.ui.editors.AbstractDebugTextHover;
|
||||
import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
|
||||
import org.eclipse.cdt.dsf.concurrent.Query;
|
||||
import org.eclipse.cdt.dsf.debug.internal.ui.ExpressionInformationControlCreator;
|
||||
import org.eclipse.cdt.dsf.debug.service.IExpressions;
|
||||
import org.eclipse.cdt.dsf.debug.service.IFormattedValues;
|
||||
import org.eclipse.cdt.dsf.debug.service.IExpressions.IExpressionDMContext;
|
||||
|
@ -24,13 +28,21 @@ import org.eclipse.cdt.dsf.service.DsfServicesTracker;
|
|||
import org.eclipse.cdt.dsf.service.DsfSession;
|
||||
import org.eclipse.core.runtime.IAdaptable;
|
||||
import org.eclipse.debug.core.model.IDebugModelProvider;
|
||||
import org.eclipse.jface.text.DefaultInformationControl;
|
||||
import org.eclipse.jface.text.IInformationControl;
|
||||
import org.eclipse.jface.text.IInformationControlCreator;
|
||||
import org.eclipse.jface.text.IRegion;
|
||||
import org.eclipse.jface.text.ITextHoverExtension2;
|
||||
import org.eclipse.jface.text.ITextViewer;
|
||||
import org.eclipse.swt.widgets.Shell;
|
||||
import org.eclipse.ui.editors.text.EditorsUI;
|
||||
|
||||
/**
|
||||
* An implementation of AbstractDebugTextHover using DSF services.
|
||||
* An implementation of AbstractDebugTextHover using DSF services
|
||||
*
|
||||
* @since 2.1
|
||||
*/
|
||||
abstract public class AbstractDsfDebugTextHover extends AbstractDebugTextHover {
|
||||
abstract public class AbstractDsfDebugTextHover extends AbstractDebugTextHover implements ITextHoverExtension2 {
|
||||
|
||||
/**
|
||||
* Returns the debug model ID that this debug text hover is to be used for.
|
||||
|
@ -121,4 +133,63 @@ abstract public class AbstractDsfDebugTextHover extends AbstractDebugTextHover {
|
|||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the expression explorer information control should be used.
|
||||
* The default implementation returns <code>false</code>.
|
||||
*/
|
||||
protected boolean useExpressionExplorer() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IInformationControlCreator getHoverControlCreator() {
|
||||
if (useExpressionExplorer()) {
|
||||
return new ExpressionInformationControlCreator();
|
||||
} else {
|
||||
return new IInformationControlCreator() {
|
||||
public IInformationControl createInformationControl(Shell parent) {
|
||||
return new DefaultInformationControl(parent, EditorsUI.getTooltipAffordanceString());
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* @see org.eclipse.jface.text.ITextHoverExtension2#getHoverInfo2(org.eclipse.jface.text.ITextViewer, org.eclipse.jface.text.IRegion)
|
||||
*/
|
||||
public Object getHoverInfo2(ITextViewer textViewer, IRegion hoverRegion) {
|
||||
final String simpleInfo = getHoverInfo(textViewer, hoverRegion);
|
||||
if (!useExpressionExplorer() || simpleInfo == null) {
|
||||
return simpleInfo;
|
||||
}
|
||||
// improved version using ExpressionInformationControlCreator
|
||||
// see also getHoverControlCreator()
|
||||
final String text;
|
||||
text= getExpressionText(textViewer, hoverRegion);
|
||||
if (text != null && text.length() > 0) {
|
||||
final IFrameDMContext frameDmc = getFrame();
|
||||
final DsfSession dsfSession = DsfSession.getSession(frameDmc.getSessionId());
|
||||
Callable<IExpressionDMContext> callable = new Callable<IExpressionDMContext>() {
|
||||
public IExpressionDMContext call() throws Exception {
|
||||
DsfServicesTracker tracker = new DsfServicesTracker(DsfUIPlugin.getBundleContext(), frameDmc.getSessionId());
|
||||
try {
|
||||
IExpressions expressions = tracker.getService(IExpressions.class);
|
||||
if (expressions != null) {
|
||||
return expressions.createExpression(frameDmc, text);
|
||||
}
|
||||
return null;
|
||||
} finally {
|
||||
tracker.dispose();
|
||||
}
|
||||
}
|
||||
};
|
||||
try {
|
||||
return dsfSession.getExecutor().submit(callable).get();
|
||||
} catch (InterruptedException e) {
|
||||
} catch (ExecutionException e) {
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2006, 2008 Wind River Systems and others.
|
||||
* Copyright (c) 2006, 2009 Wind River Systems 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
|
||||
|
@ -79,4 +79,11 @@ public interface IDsfDebugUIConstants {
|
|||
* @since 2.0
|
||||
*/
|
||||
public static final String PREF_COLOR_STALE_DATA_BACKGROUND= PLUGIN_ID + ".staledata.background"; //$NON-NLS-1$
|
||||
|
||||
/**
|
||||
* Presentation context id for the expression hover.
|
||||
*
|
||||
* @since 2.1
|
||||
*/
|
||||
public static final String ID_EXPRESSION_HOVER= PLUGIN_ID + ".expression_hover"; //$NON-NLS-1$
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2006, 2008 Wind River Systems and others.
|
||||
* Copyright (c) 2006, 2009 Wind River Systems 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
|
||||
|
@ -19,6 +19,7 @@ import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
|
|||
import org.eclipse.cdt.dsf.debug.service.ICachingService;
|
||||
import org.eclipse.cdt.dsf.debug.service.IExpressions;
|
||||
import org.eclipse.cdt.dsf.debug.service.IRegisters;
|
||||
import org.eclipse.cdt.dsf.debug.service.IExpressions.IExpressionDMContext;
|
||||
import org.eclipse.cdt.dsf.debug.service.IRunControl.ISuspendedDMEvent;
|
||||
import org.eclipse.cdt.dsf.debug.ui.DsfDebugUITools;
|
||||
import org.eclipse.cdt.dsf.debug.ui.IDsfDebugUIConstants;
|
||||
|
@ -46,6 +47,7 @@ import org.eclipse.debug.core.model.IExpression;
|
|||
import org.eclipse.debug.internal.core.IExpressionsListener2;
|
||||
import org.eclipse.debug.internal.ui.viewers.model.provisional.IColumnPresentation;
|
||||
import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
|
||||
import org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerInputUpdate;
|
||||
import org.eclipse.debug.internal.ui.viewers.model.provisional.ModelDelta;
|
||||
import org.eclipse.jface.preference.IPreferenceStore;
|
||||
import org.eclipse.jface.util.IPropertyChangeListener;
|
||||
|
@ -210,8 +212,13 @@ public class ExpressionVMProvider extends AbstractDMVMProvider
|
|||
/*
|
||||
* Now the Over-arching management node.
|
||||
*/
|
||||
ExpressionManagerVMNode expressionManagerNode = new ExpressionManagerVMNode(this);
|
||||
addChildNodes(rootNode, new IVMNode[] {expressionManagerNode});
|
||||
if (IDsfDebugUIConstants.ID_EXPRESSION_HOVER.equals(getPresentationContext().getId())) {
|
||||
SingleExpressionVMNode expressionManagerNode = new SingleExpressionVMNode(this);
|
||||
addChildNodes(rootNode, new IVMNode[] { expressionManagerNode });
|
||||
} else {
|
||||
ExpressionManagerVMNode expressionManagerNode = new ExpressionManagerVMNode(this);
|
||||
addChildNodes(rootNode, new IVMNode[] {expressionManagerNode});
|
||||
}
|
||||
|
||||
/*
|
||||
* The expression view wants to support fully all of the components of the register view.
|
||||
|
@ -372,4 +379,20 @@ public class ExpressionVMProvider extends AbstractDMVMProvider
|
|||
// Session disposed, ignore.
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(IViewerInputUpdate update) {
|
||||
if (IDsfDebugUIConstants.ID_EXPRESSION_HOVER.equals(getPresentationContext().getId())) {
|
||||
Object input = update.getElement();
|
||||
if (input instanceof IExpressionDMContext) {
|
||||
IExpressionDMContext dmc = (IExpressionDMContext) input;
|
||||
SingleExpressionVMNode vmNode = (SingleExpressionVMNode) getChildVMNodes(getRootVMNode())[0];
|
||||
vmNode.setExpression(dmc);
|
||||
update.setInputElement(vmNode.createVMContext(dmc));
|
||||
update.done();
|
||||
return;
|
||||
}
|
||||
}
|
||||
super.update(update);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,327 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2009 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:
|
||||
* Wind River Systems - initial API and implementation
|
||||
*******************************************************************************/
|
||||
|
||||
package org.eclipse.cdt.dsf.debug.ui.viewmodel.expression;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.cdt.dsf.concurrent.CountingRequestMonitor;
|
||||
import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
|
||||
import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
|
||||
import org.eclipse.cdt.dsf.datamodel.IDMContext;
|
||||
import org.eclipse.cdt.dsf.debug.service.IExpressions.IExpressionDMContext;
|
||||
import org.eclipse.cdt.dsf.debug.ui.viewmodel.expression.ExpressionVMProvider;
|
||||
import org.eclipse.cdt.dsf.debug.ui.viewmodel.expression.ExpressionsChangedEvent;
|
||||
import org.eclipse.cdt.dsf.debug.ui.viewmodel.expression.InvalidExpressionVMContext;
|
||||
import org.eclipse.cdt.dsf.ui.concurrent.ViewerCountingRequestMonitor;
|
||||
import org.eclipse.cdt.dsf.ui.viewmodel.AbstractVMContext;
|
||||
import org.eclipse.cdt.dsf.ui.viewmodel.IVMNode;
|
||||
import org.eclipse.cdt.dsf.ui.viewmodel.VMDelta;
|
||||
import org.eclipse.cdt.dsf.ui.viewmodel.datamodel.AbstractDMVMNode;
|
||||
import org.eclipse.cdt.dsf.ui.viewmodel.datamodel.IDMVMContext;
|
||||
import org.eclipse.debug.core.ILaunch;
|
||||
import org.eclipse.debug.core.model.IDebugTarget;
|
||||
import org.eclipse.debug.core.model.IExpression;
|
||||
import org.eclipse.debug.core.model.IValue;
|
||||
import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenCountUpdate;
|
||||
import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate;
|
||||
import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementLabelProvider;
|
||||
import org.eclipse.debug.internal.ui.viewers.model.provisional.IHasChildrenUpdate;
|
||||
import org.eclipse.debug.internal.ui.viewers.model.provisional.ILabelUpdate;
|
||||
import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta;
|
||||
import org.eclipse.jface.viewers.TreePath;
|
||||
|
||||
/**
|
||||
* A VM node for displaying a single expression in the expression hover.
|
||||
*/
|
||||
public class SingleExpressionVMNode extends AbstractDMVMNode implements IElementLabelProvider {
|
||||
|
||||
private static class RootDMVMContext extends AbstractVMContext implements IDMVMContext {
|
||||
private final IDMContext fDmc;
|
||||
public RootDMVMContext(IVMNode node, IDMContext dmc) {
|
||||
super(node);
|
||||
fDmc = dmc;
|
||||
}
|
||||
public IDMContext getDMContext() {
|
||||
return fDmc;
|
||||
}
|
||||
@SuppressWarnings("rawtypes")
|
||||
@Override
|
||||
public Object getAdapter(Class adapter) {
|
||||
Object superAdapter = super.getAdapter(adapter);
|
||||
if (superAdapter != null) {
|
||||
return superAdapter;
|
||||
} else {
|
||||
// Delegate to the Data Model to find the context.
|
||||
if (adapter.isInstance(fDmc)) {
|
||||
return fDmc;
|
||||
} else {
|
||||
return fDmc.getAdapter(adapter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (!(other instanceof RootDMVMContext)) return false;
|
||||
RootDMVMContext otherVmc = (RootDMVMContext)other;
|
||||
return getVMNode().equals(otherVmc.getVMNode()) &&
|
||||
fDmc.equals(otherVmc.fDmc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return getVMNode().hashCode() + fDmc.hashCode();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class SimpleExpression implements IExpression {
|
||||
private String fExpressionText;
|
||||
SimpleExpression(String text) {
|
||||
fExpressionText = text;
|
||||
}
|
||||
public void dispose() {
|
||||
}
|
||||
public IDebugTarget getDebugTarget() {
|
||||
return null;
|
||||
}
|
||||
public String getExpressionText() {
|
||||
return fExpressionText;
|
||||
}
|
||||
public IValue getValue() {
|
||||
return null;
|
||||
}
|
||||
public ILaunch getLaunch() {
|
||||
return null;
|
||||
}
|
||||
public String getModelIdentifier() {
|
||||
return null;
|
||||
}
|
||||
@SuppressWarnings("rawtypes")
|
||||
public Object getAdapter(Class adapter) {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class SingleExpressionManager {
|
||||
private static final IExpression[] NO_EXPRESSIONS = {};
|
||||
IExpression fExpression;
|
||||
public IExpression[] getExpressions() {
|
||||
if (fExpression != null) {
|
||||
return new IExpression[] { fExpression };
|
||||
}
|
||||
return NO_EXPRESSIONS;
|
||||
}
|
||||
public void setExpression(IExpression expression) {
|
||||
fExpression = expression;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/** Local reference to the expression manager */
|
||||
private final SingleExpressionManager fManager;
|
||||
|
||||
public SingleExpressionVMNode(ExpressionVMProvider provider) {
|
||||
super(provider, provider.getSession(), IExpressionDMContext.class);
|
||||
fManager = new SingleExpressionManager();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "SingleExpressionVMNode"; //$NON-NLS-1$
|
||||
}
|
||||
|
||||
private ExpressionVMProvider getExpressionVMProvider() {
|
||||
return (ExpressionVMProvider)getVMProvider();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(IHasChildrenUpdate[] updates) {
|
||||
// Test availability of children based on whether there are any expressions
|
||||
// in the manager. We assume that the getExpressions() will just read
|
||||
// local state data, so we don't bother using a job to perform this
|
||||
// operation.
|
||||
for (int i = 0; i < updates.length; i++) {
|
||||
updates[i].setHasChilren(fManager.getExpressions().length != 0);
|
||||
updates[i].done();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(IChildrenCountUpdate[] updates) {
|
||||
for (IChildrenCountUpdate update : updates) {
|
||||
if (!checkUpdate(update)) continue;
|
||||
|
||||
// We assume that the getExpressions() will just read local state data,
|
||||
// so we don't bother using a job to perform this operation.
|
||||
update.setChildCount(fManager.getExpressions().length);
|
||||
update.done();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(final IChildrenUpdate[] updates) {
|
||||
for (IChildrenUpdate update : updates) {
|
||||
doUpdateChildren(update);
|
||||
}
|
||||
}
|
||||
|
||||
public void doUpdateChildren(final IChildrenUpdate update) {
|
||||
final IExpression[] expressions = fManager.getExpressions();
|
||||
|
||||
// For each (expression) element in update, find the layout node that can
|
||||
// parse it. And for each expression that has a corresponding layout node,
|
||||
// call IExpressionLayoutNode#getElementForExpression to generate a VMC.
|
||||
// Since the last is an async call, we need to create a multi-RM to wait
|
||||
// for all the calls to complete.
|
||||
final CountingRequestMonitor multiRm = new ViewerCountingRequestMonitor(getVMProvider().getExecutor(), update);
|
||||
int multiRmCount = 0;
|
||||
|
||||
int lowOffset= update.getOffset();
|
||||
if (lowOffset < 0) {
|
||||
lowOffset = 0;
|
||||
}
|
||||
int length= update.getLength();
|
||||
if (length <= 0) {
|
||||
length = expressions.length;
|
||||
}
|
||||
final int highOffset= lowOffset + length;
|
||||
for (int i = lowOffset; i < highOffset && i < expressions.length + 1; i++) {
|
||||
if (i < expressions.length) {
|
||||
multiRmCount++;
|
||||
final int childIndex = i;
|
||||
final IExpression expression = expressions[i];
|
||||
// getElementForExpression() accepts a IElementsUpdate as an argument.
|
||||
// Construct an instance of VMElementsUpdate which will call a
|
||||
// the request monitor when it is finished. The request monitor
|
||||
// will in turn set the element in the update argument in this method.
|
||||
((ExpressionVMProvider)getVMProvider()).update(
|
||||
new VMExpressionUpdate(
|
||||
update, expression,
|
||||
new DataRequestMonitor<Object>(getVMProvider().getExecutor(), multiRm) {
|
||||
@Override
|
||||
protected void handleSuccess() {
|
||||
update.setChild(getData(), childIndex);
|
||||
multiRm.done();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void handleError() {
|
||||
update.setChild(new InvalidExpressionVMContext(SingleExpressionVMNode.this, expression), childIndex);
|
||||
multiRm.done();
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// If no expressions were parsed, we're finished.
|
||||
// Set the count to the counting RM.
|
||||
multiRm.setDoneCount(multiRmCount);
|
||||
}
|
||||
|
||||
public void update(ILabelUpdate[] updates) {
|
||||
// The label update handler only handles labels for the invalid expression VMCs.
|
||||
// The expression layout nodes are responsible for supplying label providers
|
||||
// for their VMCs.
|
||||
for (ILabelUpdate update : updates) {
|
||||
update.done();
|
||||
}
|
||||
}
|
||||
|
||||
public int getDeltaFlags(Object event) {
|
||||
int retVal = 0;
|
||||
|
||||
// Add a flag if the list of expressions in the global expression manager has changed.
|
||||
if (event instanceof ExpressionsChangedEvent) {
|
||||
retVal |= IModelDelta.ADDED | IModelDelta.REMOVED | IModelDelta.INSERTED | IModelDelta.CONTENT ;
|
||||
}
|
||||
|
||||
for (IExpression expression : fManager.getExpressions()) {
|
||||
retVal |= getExpressionVMProvider().getDeltaFlagsForExpression(expression, event);
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
public void buildDelta(final Object event, final VMDelta parentDelta, final int nodeOffset, final RequestMonitor requestMonitor) {
|
||||
if (event instanceof ExpressionsChangedEvent) {
|
||||
buildDeltaForExpressionsChangedEvent((ExpressionsChangedEvent)event, parentDelta, nodeOffset, requestMonitor);
|
||||
} else {
|
||||
|
||||
// For each expression, find its corresponding node and ask that
|
||||
// layout node for its delta flags for given event. If there are delta flags to be
|
||||
// generated, call the asynchronous method to do so.
|
||||
CountingRequestMonitor multiRm = new CountingRequestMonitor(getExecutor(), requestMonitor);
|
||||
|
||||
int buildDeltaForExpressionCallCount = 0;
|
||||
|
||||
IExpression[] expressions = fManager.getExpressions();
|
||||
for (int i = 0; i < expressions.length; i++ ) {
|
||||
int flags = getExpressionVMProvider().getDeltaFlagsForExpression(expressions[i], event);
|
||||
// If the given expression has no delta flags, skip it.
|
||||
if (flags == IModelDelta.NO_CHANGE) continue;
|
||||
|
||||
int elementOffset = nodeOffset >= 0 ? nodeOffset + i : -1;
|
||||
getExpressionVMProvider().buildDeltaForExpression(
|
||||
expressions[i], elementOffset, event, parentDelta, getTreePathFromDelta(parentDelta),
|
||||
new RequestMonitor(getExecutor(), multiRm));
|
||||
buildDeltaForExpressionCallCount++;
|
||||
}
|
||||
|
||||
multiRm.setDoneCount(buildDeltaForExpressionCallCount);
|
||||
}
|
||||
}
|
||||
|
||||
private void buildDeltaForExpressionsChangedEvent(ExpressionsChangedEvent event, VMDelta parentDelta,
|
||||
int nodeOffset, RequestMonitor requestMonitor)
|
||||
{
|
||||
CountingRequestMonitor multiRm = new CountingRequestMonitor(getExecutor(), requestMonitor);
|
||||
for (int i = 0; i < event.getExpressions().length; i++) {
|
||||
int expIndex = event.getIndex() != -1
|
||||
? nodeOffset + event.getIndex() + i
|
||||
: -1;
|
||||
getExpressionVMProvider().buildDeltaForExpression(
|
||||
event.getExpressions()[i], expIndex, event, parentDelta, getTreePathFromDelta(parentDelta),
|
||||
new RequestMonitor(getExecutor(), multiRm));
|
||||
}
|
||||
multiRm.setDoneCount(event.getExpressions().length);
|
||||
}
|
||||
|
||||
private TreePath getTreePathFromDelta(IModelDelta delta) {
|
||||
List<Object> elementList = new LinkedList<Object>();
|
||||
IModelDelta listDelta = delta;
|
||||
elementList.add(0, listDelta.getElement());
|
||||
while (listDelta.getParentDelta() != null) {
|
||||
elementList.add(0, listDelta.getElement());
|
||||
listDelta = listDelta.getParentDelta();
|
||||
}
|
||||
return new TreePath(elementList.toArray());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateElementsInSessionThread(IChildrenUpdate update) {
|
||||
doUpdateChildren(update);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IDMVMContext createVMContext(IDMContext dmc) {
|
||||
return new RootDMVMContext(getVMProvider().getRootVMNode(), dmc);
|
||||
}
|
||||
|
||||
void setExpression(IExpressionDMContext dmc) {
|
||||
String text = dmc.getExpression();
|
||||
fManager.setExpression(new SimpleExpression(text));
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue