Debugger: Make tooltips pinnable.

Replace old debugger tooltip by a new ToolTipManager which
has a list of AbstractDebuggerToolTipWidget with the functionality
to 'acquire' an engine (display its data) and 'release' it
(store engine data and display them as 'previous') and serialization
to XML session data.
DebuggerTreeViewToolTipWidget implements AbstractDebuggerToolTipWidget
for tree model acting as  a filter on watch models.

Rubber-stamped-by: hjk
This commit is contained in:
Friedemann Kleint
2011-02-11 15:00:13 +01:00
parent 80b2b71a5b
commit 0ac879e39f
29 changed files with 1717 additions and 409 deletions

View File

@@ -52,7 +52,7 @@
#include "debuggerplugin.h"
#include "debuggerrunner.h"
#include "debuggerstringutils.h"
#include "debuggertooltip.h"
#include "debuggertooltipmanager.h"
#include "disassembleragent.h"
#include "gdbmi.h"
#include "gdboptionspage.h"
@@ -74,6 +74,7 @@
#include "logwindow.h"
#include <coreplugin/icore.h>
#include <coreplugin/ifile.h>
#include <projectexplorer/toolchain.h>
#include <texteditor/itexteditor.h>
#include <utils/qtcassert.h>
@@ -101,10 +102,18 @@
#endif
#include <ctype.h>
namespace Debugger {
namespace Internal {
class GdbToolTipContext : public DebuggerToolTipContext
{
public:
GdbToolTipContext(const DebuggerToolTipContext &c) : DebuggerToolTipContext(c) {}
QPoint mousePosition;
QString expression;
};
static const char winPythonVersionC[] = "python2.5";
enum { debugPending = 0 };
@@ -1103,7 +1112,7 @@ void GdbEngine::handleQuerySources(const GdbResponse &response)
void GdbEngine::handleExecuteJumpToLine(const GdbResponse &response)
{
if (response.resultClass == GdbResultRunning) {
notifyInferiorRunOk();
doNotifyInferiorRunOk();
// All is fine. Waiting for the temporary breakpoint to be hit.
} else if (response.resultClass == GdbResultDone) {
// This happens on old gdb. Trigger the effect of a '*stopped'.
@@ -1116,7 +1125,7 @@ void GdbEngine::handleExecuteJumpToLine(const GdbResponse &response)
void GdbEngine::handleExecuteRunToLine(const GdbResponse &response)
{
if (response.resultClass == GdbResultRunning) {
notifyInferiorRunOk();
doNotifyInferiorRunOk();
// All is fine. Waiting for the temporary breakpoint to be hit.
} else if (response.resultClass == GdbResultDone) {
// This happens on old gdb. Trigger the effect of a '*stopped'.
@@ -1275,7 +1284,7 @@ void GdbEngine::handleStopResponse(const GdbMi &data)
// be handled in the result handler.
// -- or --
// *stopped arriving earlier than ^done response to an -exec-step
notifyInferiorRunOk();
doNotifyInferiorRunOk();
notifyInferiorSpontaneousStop();
} else if (state() == InferiorStopOk && isQmlStepBreakpoint2(bkptno)) {
// That's expected.
@@ -1630,7 +1639,7 @@ void GdbEngine::handleExecuteContinue(const GdbResponse &response)
{
QTC_ASSERT(state() == InferiorRunRequested, qDebug() << state());
if (response.resultClass == GdbResultRunning) {
notifyInferiorRunOk();
doNotifyInferiorRunOk();
return;
}
QByteArray msg = response.data.findChild("msg").data();
@@ -1871,6 +1880,12 @@ void GdbEngine::continueInferiorInternal()
postCommand("-exec-continue", RunRequest, CB(handleExecuteContinue));
}
void GdbEngine::doNotifyInferiorRunOk()
{
clearToolTip();
notifyInferiorRunOk();
}
void GdbEngine::autoContinueInferior()
{
resetLocation();
@@ -1909,7 +1924,7 @@ void GdbEngine::handleExecuteStep(const GdbResponse &response)
}
QTC_ASSERT(state() == InferiorRunRequested, qDebug() << state());
if (response.resultClass == GdbResultRunning) {
notifyInferiorRunOk();
doNotifyInferiorRunOk();
return;
}
QByteArray msg = response.data.findChild("msg").data();
@@ -1972,7 +1987,7 @@ void GdbEngine::handleExecuteNext(const GdbResponse &response)
}
QTC_ASSERT(state() == InferiorRunRequested, qDebug() << state());
if (response.resultClass == GdbResultRunning) {
notifyInferiorRunOk();
doNotifyInferiorRunOk();
return;
}
QTC_ASSERT(state() == InferiorStopOk, qDebug() << state());
@@ -3366,7 +3381,12 @@ bool GdbEngine::supportsThreads() const
bool GdbEngine::showToolTip()
{
const QByteArray iname = tooltipIName(m_toolTipExpression);
if (m_toolTipContext.isNull())
return false;
const QString expression = m_toolTipContext->expression;
const QByteArray iname = tooltipIName(m_toolTipContext->expression);
if (DebuggerToolTipManager::debug())
qDebug() << "GdbEngine::showToolTip " << expression << iname << (*m_toolTipContext);
if (!debuggerCore()->boolSetting(UseToolTipsInMainEditor)) {
watchHandler()->removeData(iname);
@@ -3376,15 +3396,29 @@ bool GdbEngine::showToolTip()
const QModelIndex index = watchHandler()->itemIndex(iname);
if (!index.isValid()) {
watchHandler()->removeData(iname);
hideDebuggerToolTip();
return false;
}
showDebuggerToolTip(m_toolTipPos, index);
DebuggerTreeViewToolTipWidget *tw = new DebuggerTreeViewToolTipWidget;
tw->setDebuggerModel(TooltipsWatch);
tw->setExpression(expression);
tw->setContext(*m_toolTipContext);
tw->acquireEngine(this);
DebuggerToolTipManager::instance()->add(m_toolTipContext->mousePosition, tw);
return true;
}
QString GdbEngine::tooltipExpression() const
{
return m_toolTipContext.isNull() ? QString() : m_toolTipContext->expression;
}
void GdbEngine::clearToolTip()
{
m_toolTipContext.reset();
}
void GdbEngine::setToolTipExpression(const QPoint &mousePos,
TextEditor::ITextEditor *editor, int cursorPos)
TextEditor::ITextEditor *editor, const DebuggerToolTipContext &contextIn)
{
if (state() != InferiorStopOk || !isCppEditor(editor)) {
//qDebug() << "SUPPRESSING DEBUGGER TOOLTIP, INFERIOR NOT STOPPED "
@@ -3392,9 +3426,13 @@ void GdbEngine::setToolTipExpression(const QPoint &mousePos,
return;
}
m_toolTipPos = mousePos;
DebuggerToolTipContext context = contextIn;
int line, column;
QString exp = cppExpressionAt(editor, cursorPos, &line, &column);
QString exp = cppExpressionAt(editor, context.position, &line, &column, &context.function);
if (DebuggerToolTipManager::debug())
qDebug() << "GdbEngine::setToolTipExpression1 " << exp << context;
if (exp.isEmpty())
return;
// Extract the first identifier, everything else is considered
// too dangerous.
@@ -3414,35 +3452,11 @@ void GdbEngine::setToolTipExpression(const QPoint &mousePos,
}
exp = exp.mid(pos1, pos2 - pos1);
if (!exp.isEmpty() && exp == m_toolTipExpression) {
showToolTip();
return;
}
m_toolTipExpression = exp;
// FIXME: enable caching
//if (showToolTip())
// return;
if (exp.isEmpty() || exp.startsWith(_c('#'))) {
//QToolTip::hideText();
return;
}
if (!hasLetterOrNumber(exp)) {
//QToolTip::showText(m_toolTipPos,
// tr("'%1' contains no identifier").arg(exp));
return;
}
if (isKeyWord(exp))
if (exp.isEmpty() || exp.startsWith(_c('#')) || !hasLetterOrNumber(exp) || isKeyWord(exp))
return;
if (exp.startsWith(_c('"')) && exp.endsWith(_c('"'))) {
//QToolTip::showText(m_toolTipPos, tr("String literal %1").arg(exp));
if (exp.startsWith(_c('"')) && exp.endsWith(_c('"')))
return;
}
if (exp.startsWith(__("++")) || exp.startsWith(__("--")))
exp = exp.mid(2);
@@ -3453,29 +3467,19 @@ void GdbEngine::setToolTipExpression(const QPoint &mousePos,
if (exp.startsWith(_c('<')) || exp.startsWith(_c('[')))
return;
if (hasSideEffects(exp)) {
//QToolTip::showText(m_toolTipPos,
// tr("Cowardly refusing to evaluate expression '%1' "
// "with potential side effects").arg(exp));
if (hasSideEffects(exp) || exp.isEmpty())
return;
if (!m_toolTipContext.isNull() && m_toolTipContext->expression == exp) {
showToolTip();
return;
}
// Gdb crashes when creating a variable object with the name
// of the type of 'this'
/*
for (int i = 0; i != m_currentLocals.childCount(); ++i) {
if (m_currentLocals.childAt(i).exp == "this") {
qDebug() << "THIS IN ROW" << i;
if (m_currentLocals.childAt(i).type.startsWith(exp)) {
QToolTip::showText(m_toolTipPos,
tr("%1: type of current 'this'").arg(exp));
qDebug() << " TOOLTIP CRASH SUPPRESSED";
return;
}
break;
}
}
*/
m_toolTipContext.reset(new GdbToolTipContext(context));
m_toolTipContext->mousePosition = mousePos;
m_toolTipContext->expression = exp;
if (DebuggerToolTipManager::debug())
qDebug() << "GdbEngine::setToolTipExpression2 " << exp << (*m_toolTipContext);
if (isSynchronous()) {
updateLocals(QVariant());
@@ -4587,13 +4591,6 @@ void GdbEngine::resetCommandQueue()
}
}
void GdbEngine::removeTooltip()
{
m_toolTipExpression.clear();
m_toolTipPos = QPoint();
DebuggerEngine::removeTooltip();
}
void GdbEngine::handleRemoteSetupDone(int gdbServerPort, int qmlPort)
{
m_gdbAdapter->handleRemoteSetupDone(gdbServerPort, qmlPort);