forked from qt-creator/qt-creator
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:
@@ -119,7 +119,7 @@ void GdbEngine::updateLocalsClassic(const QVariant &cookie)
|
||||
|
||||
//PENDING_DEBUG("\nRESET PENDING");
|
||||
//m_toolTipCache.clear();
|
||||
m_toolTipExpression.clear();
|
||||
clearToolTip();
|
||||
watchHandler()->beginCycle();
|
||||
|
||||
QByteArray level = QByteArray::number(currentFrame());
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -60,6 +60,7 @@ class AbstractGdbAdapter;
|
||||
class AbstractGdbProcess;
|
||||
class GdbResponse;
|
||||
class GdbMi;
|
||||
class GdbToolTipContext;
|
||||
|
||||
class WatchData;
|
||||
class DisassemblerAgentCookie;
|
||||
@@ -325,6 +326,7 @@ private: ////////// Inferior Management //////////
|
||||
void executeNextI();
|
||||
|
||||
void continueInferiorInternal();
|
||||
void doNotifyInferiorRunOk();
|
||||
void autoContinueInferior();
|
||||
void continueInferior();
|
||||
void interruptInferior();
|
||||
@@ -474,8 +476,7 @@ private: ////////// View & Data Stuff //////////
|
||||
// Watch specific stuff
|
||||
//
|
||||
virtual void setToolTipExpression(const QPoint &mousePos,
|
||||
TextEditor::ITextEditor *editor, int cursorPos);
|
||||
|
||||
TextEditor::ITextEditor *editor, const DebuggerToolTipContext &);
|
||||
virtual void assignValueInDebugger(const WatchData *data,
|
||||
const QString &expr, const QVariant &value);
|
||||
|
||||
@@ -555,10 +556,11 @@ private: ////////// View & Data Stuff //////////
|
||||
AbstractGdbProcess *gdbProc() const;
|
||||
void showExecutionError(const QString &message);
|
||||
|
||||
void removeTooltip();
|
||||
static QByteArray tooltipIName(const QString &exp);
|
||||
QString m_toolTipExpression;
|
||||
QPoint m_toolTipPos;
|
||||
QString tooltipExpression() const;
|
||||
void clearToolTip();
|
||||
QScopedPointer<GdbToolTipContext> m_toolTipContext;
|
||||
|
||||
|
||||
// For short-circuiting stack and thread list evaluation.
|
||||
bool m_stackNeeded;
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
#include "debuggeractions.h"
|
||||
#include "debuggercore.h"
|
||||
#include "debuggerstringutils.h"
|
||||
#include "debuggertooltipmanager.h"
|
||||
|
||||
#include "breakhandler.h"
|
||||
#include "watchhandler.h"
|
||||
@@ -64,10 +65,21 @@ void GdbEngine::updateLocalsPython(bool tryPartial, const QByteArray &varList)
|
||||
expanded += "formats:" + handler->individualFormatRequests();
|
||||
|
||||
QByteArray watchers;
|
||||
if (!m_toolTipExpression.isEmpty()) {
|
||||
watchers += m_toolTipExpression.toLatin1();
|
||||
watchers += '#';
|
||||
watchers += tooltipIName(m_toolTipExpression);
|
||||
const QString fileName = stackHandler()->currentFrame().file;
|
||||
const QString function = stackHandler()->currentFrame().function;
|
||||
if (!fileName.isEmpty()) {
|
||||
QStringList expressions =
|
||||
DebuggerToolTipManager::instance()->treeWidgetExpressions(fileName, objectName(), function);
|
||||
const QString currentExpression = tooltipExpression();
|
||||
if (!currentExpression.isEmpty() && !expressions.contains(currentExpression))
|
||||
expressions.push_back(currentExpression);
|
||||
foreach (const QString &te, expressions) {
|
||||
if (!watchers.isEmpty())
|
||||
watchers += "##";
|
||||
watchers += te.toLatin1();
|
||||
watchers += '#';
|
||||
watchers += tooltipIName(te);
|
||||
}
|
||||
}
|
||||
|
||||
QHash<QByteArray, int> watcherNames = handler->watcherNames();
|
||||
@@ -120,7 +132,6 @@ void GdbEngine::handleStackFramePython(const GdbResponse &response)
|
||||
PRECONDITION;
|
||||
if (response.resultClass == GdbResultDone) {
|
||||
const bool partial = response.cookie.toBool();
|
||||
Q_UNUSED(partial);
|
||||
//qDebug() << "READING " << (partial ? "PARTIAL" : "FULL");
|
||||
QByteArray out = response.data.findChild("consolestreamoutput").data();
|
||||
while (out.endsWith(' ') || out.endsWith('\n'))
|
||||
@@ -192,6 +203,8 @@ void GdbEngine::handleStackFramePython(const GdbResponse &response)
|
||||
//PENDING_DEBUG("\n\n .... AND TRIGGERS MODEL UPDATE\n");
|
||||
rebuildWatchModel();
|
||||
}
|
||||
if (!partial)
|
||||
emit stackFrameCompleted();
|
||||
} else {
|
||||
showMessage(_("DUMPER FAILED: " + response.toString()));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user