blob: b8fbf964aa200c41a011b5d91146495dd50dad33 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2009, 2015 Nokia 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:
* Nokia Corporation - initial API and implementation
* Wind River Systems - Added support for advanced expression hover
*******************************************************************************/
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.IDsfStatusConstants;
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.IExpressions.IExpressionDMContext;
import org.eclipse.cdt.dsf.debug.service.IFormattedValues;
import org.eclipse.cdt.dsf.debug.service.IFormattedValues.FormattedValueDMContext;
import org.eclipse.cdt.dsf.debug.service.IFormattedValues.FormattedValueDMData;
import org.eclipse.cdt.dsf.debug.service.IStack.IFrameDMContext;
import org.eclipse.cdt.dsf.internal.ui.DsfUIPlugin;
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
*
* @since 2.1
*/
abstract public class AbstractDsfDebugTextHover extends AbstractDebugTextHover implements ITextHoverExtension2 {
/**
* Returns the debug model ID that this debug text hover is to be used for.
*/
abstract protected String getModelId();
/**
* Returns the type of format that should be used for the hover.
*/
protected String getHoverFormat() {
return IFormattedValues.NATURAL_FORMAT;
}
private class GetExpressionValueQuery extends Query<FormattedValueDMData> {
private final IFrameDMContext frame;
private final String expression;
private DsfServicesTracker dsfServicesTracker;
public GetExpressionValueQuery(IFrameDMContext frame, String expression,
DsfServicesTracker dsfServicesTracker) {
this.frame = frame;
this.expression = expression;
this.dsfServicesTracker = dsfServicesTracker;
}
@Override
protected void execute(final DataRequestMonitor<FormattedValueDMData> rm) {
DsfSession session = DsfSession.getSession(frame.getSessionId());
IExpressions expressions = dsfServicesTracker.getService(IExpressions.class);
if (expressions == null) {
rm.setStatus(
DsfUIPlugin.newErrorStatus(IDsfStatusConstants.REQUEST_FAILED, "No expression service", null)); //$NON-NLS-1$
rm.done();
return;
}
IExpressionDMContext expressionDMC = expressions.createExpression(frame, expression);
FormattedValueDMContext formattedValueContext = expressions.getFormattedValueContext(expressionDMC,
getHoverFormat());
expressions.getFormattedExpressionValue(formattedValueContext,
new DataRequestMonitor<FormattedValueDMData>(session.getExecutor(), rm) {
@Override
protected void handleSuccess() {
rm.setData(getData());
rm.done();
}
@Override
protected void handleFailure() {
rm.done();
}
});
}
}
protected IFrameDMContext getFrame() {
IAdaptable adaptable = getSelectionAdaptable();
if (adaptable != null) {
return adaptable.getAdapter(IFrameDMContext.class);
}
return null;
}
@Override
protected boolean canEvaluate() {
if (getFrame() == null) {
return false;
}
IAdaptable adaptable = getSelectionAdaptable();
if (adaptable != null) {
IDebugModelProvider modelProvider = adaptable.getAdapter(IDebugModelProvider.class);
if (modelProvider != null) {
String[] models = modelProvider.getModelIdentifiers();
String myModel = getModelId();
for (int i = 0; i < models.length; i++) {
if (models[i].equals(myModel)) {
return true;
}
}
}
}
return false;
}
@Override
protected String evaluateExpression(String expression) {
IFrameDMContext frame = getFrame();
if (frame == null) {
return null;
}
String sessionId = frame.getSessionId();
DsfServicesTracker dsfServicesTracker = new DsfServicesTracker(DsfUIPlugin.getBundleContext(), sessionId);
try {
GetExpressionValueQuery query = new GetExpressionValueQuery(frame, expression, dsfServicesTracker);
DsfSession session = DsfSession.getSession(sessionId);
if (session != null) {
session.getExecutor().execute(query);
try {
FormattedValueDMData data = query.get();
if (data != null)
return data.getFormattedValue();
} catch (Exception e) {
}
}
} finally {
dsfServicesTracker.dispose();
}
return null;
}
/**
* Returns whether the "advanced" expression information control should be used.
* The default implementation returns <code>false</code>.
*/
protected boolean useExpressionExplorer() {
return false;
}
/**
* Create an information control creator for the "advanced" hover.
* <p>
* Clients can call this method to create an information control creator
* with custom options.
* </p>
* @param showDetailPane whether the detail pane should be visible
* @param defaultExpansionLevel automatically expand the expression to this level
* @return the information control creator
*/
protected final IInformationControlCreator createExpressionInformationControlCreator(boolean showDetailPane,
int defaultExpansionLevel) {
return new ExpressionInformationControlCreator(showDetailPane, defaultExpansionLevel);
}
/**
* Create an information control creator for the "advanced" hover.
* Called by {@link #getHoverControlCreator()} when {@link #useExpressionExplorer()}
* returns <code>true</code>.
* <p>
* The default implementation returns an information control creator with
* details pane enabled and default expansion level = 1.
* Clients may override this method to return an instance with different options.
* </p>
* @return the information control creator
* @see {@link #createExpressionInformationControlCreator(boolean, int)}
*/
protected IInformationControlCreator createExpressionInformationControlCreator() {
return createExpressionInformationControlCreator(true, 1);
}
@Override
public IInformationControlCreator getHoverControlCreator() {
if (useExpressionExplorer()) {
return createExpressionInformationControlCreator();
}
return new IInformationControlCreator() {
@Override
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)
*/
@Override
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.isEmpty()) {
final IFrameDMContext frameDmc = getFrame();
if (frameDmc != null) {
final DsfSession dsfSession = DsfSession.getSession(frameDmc.getSessionId());
if (dsfSession != null) {
Callable<IExpressionDMContext> callable = new Callable<IExpressionDMContext>() {
@Override
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;
}
}