blob: 37b641e1042ef0f4472a84ec52726edb1d460188 [file] [log] [blame]
/*
* Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.xdebugger.impl.evaluate.quick;
import com.intellij.codeInsight.hint.HintUtil;
import com.intellij.execution.console.LanguageConsoleImpl;
import com.intellij.execution.console.LanguageConsoleView;
import com.intellij.execution.impl.ConsoleViewImpl;
import com.intellij.execution.ui.ConsoleView;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.actionSystem.ActionManager;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.ShortcutSet;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.keymap.KeymapUtil;
import com.intellij.openapi.project.DumbAwareAction;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.vcs.changes.issueLinks.LinkMouseListenerBase;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.ui.SimpleColoredComponent;
import com.intellij.ui.SimpleColoredText;
import com.intellij.ui.SimpleTextAttributes;
import com.intellij.util.Consumer;
import com.intellij.xdebugger.XDebugSession;
import com.intellij.xdebugger.XDebuggerUtil;
import com.intellij.xdebugger.XSourcePosition;
import com.intellij.xdebugger.evaluation.ExpressionInfo;
import com.intellij.xdebugger.evaluation.XDebuggerEvaluator;
import com.intellij.xdebugger.frame.XDebuggerTreeNodeHyperlink;
import com.intellij.xdebugger.frame.XFullValueEvaluator;
import com.intellij.xdebugger.frame.XValue;
import com.intellij.xdebugger.frame.XValuePlace;
import com.intellij.xdebugger.frame.presentation.XValuePresentation;
import com.intellij.xdebugger.impl.XDebugSessionImpl;
import com.intellij.xdebugger.impl.actions.handlers.XDebuggerEvaluateActionHandler;
import com.intellij.xdebugger.impl.evaluate.quick.common.AbstractValueHint;
import com.intellij.xdebugger.impl.evaluate.quick.common.ValueHintType;
import com.intellij.xdebugger.impl.frame.XValueMarkers;
import com.intellij.xdebugger.impl.ui.DebuggerUIUtil;
import com.intellij.xdebugger.impl.ui.XDebuggerUIConstants;
import com.intellij.xdebugger.impl.ui.tree.nodes.XEvaluationCallbackBase;
import com.intellij.xdebugger.impl.ui.tree.nodes.XValueNodeImpl;
import com.intellij.xdebugger.impl.ui.tree.nodes.XValueNodePresentationConfigurator;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseEvent;
/**
* @author nik
*/
public class XValueHint extends AbstractValueHint {
private static final Logger LOG = Logger.getInstance(XValueHint.class);
private final XDebuggerEvaluator myEvaluator;
private final XDebugSession myDebugSession;
private final String myExpression;
private final String myValueName;
private final @Nullable XSourcePosition myExpressionPosition;
private final ExpressionInfo myExpressionInfo;
private Disposable myDisposable;
public XValueHint(@NotNull Project project, @NotNull Editor editor, @NotNull Point point, @NotNull ValueHintType type,
@NotNull ExpressionInfo expressionInfo, @NotNull XDebuggerEvaluator evaluator,
@NotNull XDebugSession session) {
super(project, editor, point, type, expressionInfo.getTextRange());
myEvaluator = evaluator;
myDebugSession = session;
myExpression = XDebuggerEvaluateActionHandler.getExpressionText(expressionInfo, editor.getDocument());
myValueName = XDebuggerEvaluateActionHandler.getDisplayText(expressionInfo, editor.getDocument());
myExpressionInfo = expressionInfo;
VirtualFile file;
ConsoleView consoleView = ConsoleViewImpl.CONSOLE_VIEW_IN_EDITOR_VIEW.get(editor);
if (consoleView instanceof LanguageConsoleView) {
LanguageConsoleImpl console = ((LanguageConsoleView)consoleView).getConsole();
file = console.getHistoryViewer() == editor ? console.getVirtualFile() : null;
}
else {
file = FileDocumentManager.getInstance().getFile(editor.getDocument());
}
myExpressionPosition = file != null ? XDebuggerUtil.getInstance().createPositionByOffset(file, expressionInfo.getTextRange().getStartOffset()) : null;
}
@Override
protected boolean canShowHint() {
return true;
}
@Override
protected boolean showHint(final JComponent component) {
boolean result = super.showHint(component);
if (result && getType() == ValueHintType.MOUSE_OVER_HINT) {
myDisposable = Disposer.newDisposable();
ShortcutSet shortcut = ActionManager.getInstance().getAction("ShowErrorDescription").getShortcutSet();
new DumbAwareAction() {
@Override
public void actionPerformed(@NotNull AnActionEvent e) {
hideHint();
final Point point = new Point(myPoint.x, myPoint.y + getEditor().getLineHeight());
new XValueHint(getProject(), getEditor(), point, ValueHintType.MOUSE_CLICK_HINT, myExpressionInfo, myEvaluator, myDebugSession).invokeHint();
}
}.registerCustomShortcutSet(shortcut, getEditor().getContentComponent(), myDisposable);
}
return result;
}
@Override
public void hideHint() {
super.hideHint();
if (myDisposable != null) {
Disposer.dispose(myDisposable);
}
}
@Override
protected void evaluateAndShowHint() {
myEvaluator.evaluate(myExpression, new XEvaluationCallbackBase() {
@Override
public void evaluated(@NotNull final XValue result) {
result.computePresentation(new XValueNodePresentationConfigurator.ConfigurableXValueNodeImpl() {
private XFullValueEvaluator myFullValueEvaluator;
private boolean myShown = false;
@Override
public void applyPresentation(@Nullable Icon icon,
@NotNull XValuePresentation valuePresenter,
boolean hasChildren) {
if (isHintHidden()) {
return;
}
SimpleColoredText text = new SimpleColoredText();
text.append(myValueName, XDebuggerUIConstants.VALUE_NAME_ATTRIBUTES);
XValueNodeImpl.buildText(valuePresenter, text);
if (!hasChildren) {
SimpleColoredComponent component = HintUtil.createInformationComponent();
text.appendToComponent(component);
if (myFullValueEvaluator != null) {
component.append(myFullValueEvaluator.getLinkText(), XDebuggerTreeNodeHyperlink.TEXT_ATTRIBUTES, new Consumer<MouseEvent>() {
@Override
public void consume(MouseEvent event) {
DebuggerUIUtil.showValuePopup(myFullValueEvaluator, event, getProject(), getEditor());
}
});
LinkMouseListenerBase.installSingleTagOn(component);
}
showHint(component);
}
else if (getType() == ValueHintType.MOUSE_CLICK_HINT && !myShown) {
showTree(result);
}
else {
if (getType() == ValueHintType.MOUSE_OVER_HINT) {
text.insert(0, "(" + KeymapUtil.getFirstKeyboardShortcutText("ShowErrorDescription") + ") ",
SimpleTextAttributes.GRAYED_ATTRIBUTES);
}
JComponent component = createExpandableHintComponent(text, new Runnable() {
@Override
public void run() {
showTree(result);
}
});
showHint(component);
}
myShown = true;
}
@Override
public void setFullValueEvaluator(@NotNull XFullValueEvaluator fullValueEvaluator) {
myFullValueEvaluator = fullValueEvaluator;
}
@Override
public boolean isObsolete() {
return isHintHidden();
}
}, XValuePlace.TOOLTIP);
}
@Override
public void errorOccurred(@NotNull final String errorMessage) {
LOG.debug("Cannot evaluate '" + myExpression + "':" + errorMessage);
}
}, myExpressionPosition);
}
private void showTree(@NotNull XValue value) {
XValueMarkers<?,?> valueMarkers = ((XDebugSessionImpl)myDebugSession).getValueMarkers();
XDebuggerTreeCreator creator = new XDebuggerTreeCreator(myDebugSession.getProject(), myDebugSession.getDebugProcess().getEditorsProvider(),
myDebugSession.getCurrentPosition(), valueMarkers);
showTreePopup(creator, Pair.create(value, myValueName));
}
}