forked from qt-creator/qt-creator
Debugger: Fix async tooltip handling
For now, only the gdb engine can handle complex tooltips requiring async re-evaluation, cdb and lldb will show and expand only items that are available in the Locals view. This patch disables also the save/restore feature for pinned tooltips. Task-number: QTCREATORBUG-13255 Task-number: QTCREATORBUG-13052 Change-Id: Ic25616fede0f5c4343a92b631f01e60bfc5e9d81 Reviewed-by: David Schulz <david.schulz@theqtcompany.com> Reviewed-by: Christian Stenger <christian.stenger@theqtcompany.com>
This commit is contained in:
@@ -442,28 +442,14 @@ void CdbEngine::syncVerboseLog(bool verboseLog)
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool CdbEngine::setToolTipExpression(TextEditor::TextEditorWidget *editorWidget,
|
bool CdbEngine::setToolTipExpression(TextEditor::TextEditorWidget *editorWidget,
|
||||||
const DebuggerToolTipContext &contextIn)
|
const DebuggerToolTipContext &context)
|
||||||
{
|
{
|
||||||
if (debug)
|
Q_UNUSED(editorWidget);
|
||||||
qDebug() << Q_FUNC_INFO;
|
Q_UNUSED(context);
|
||||||
// Need a stopped debuggee and a cpp file in a valid frame
|
// Tooltips matching local variables are already handled in the
|
||||||
if (state() != InferiorStopOk || !isCppEditor(editorWidget) || stackHandler()->currentIndex() < 0)
|
// base class. We don't handle anything else here in CDB
|
||||||
|
// as it can slow debugging down.
|
||||||
return false;
|
return false;
|
||||||
// Determine expression and function
|
|
||||||
int line;
|
|
||||||
int column;
|
|
||||||
DebuggerToolTipContext context = contextIn;
|
|
||||||
QString exp = fixCppExpression(cppExpressionAt(editorWidget, context.position, &line, &column, &context.function));
|
|
||||||
// Are we in the current stack frame
|
|
||||||
if (context.function.isEmpty() || exp.isEmpty() || context.function != stackHandler()->currentFrame().function)
|
|
||||||
return false;
|
|
||||||
// Show tooltips of local variables only. Anything else can slow debugging down.
|
|
||||||
const WatchData *localVariable = watchHandler()->findCppLocalVariable(exp);
|
|
||||||
if (!localVariable)
|
|
||||||
return false;
|
|
||||||
context.iname = localVariable->iname;
|
|
||||||
DebuggerToolTipManager::showToolTip(context, this);
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Determine full path to the CDB extension library.
|
// Determine full path to the CDB extension library.
|
||||||
|
|||||||
@@ -78,7 +78,7 @@ public:
|
|||||||
// Factory function that returns 0 if the debug engine library cannot be found.
|
// Factory function that returns 0 if the debug engine library cannot be found.
|
||||||
|
|
||||||
virtual bool setToolTipExpression(TextEditor::TextEditorWidget *editorWidget,
|
virtual bool setToolTipExpression(TextEditor::TextEditorWidget *editorWidget,
|
||||||
const DebuggerToolTipContext &ctx);
|
const DebuggerToolTipContext &context);
|
||||||
virtual void setupEngine();
|
virtual void setupEngine();
|
||||||
virtual void setupInferior();
|
virtual void setupInferior();
|
||||||
virtual void runEngine();
|
virtual void runEngine();
|
||||||
|
|||||||
@@ -269,6 +269,7 @@ public slots:
|
|||||||
m_watchHandler.resetLocation();
|
m_watchHandler.resetLocation();
|
||||||
m_threadsHandler.resetLocation();
|
m_threadsHandler.resetLocation();
|
||||||
m_disassemblerAgent.resetLocation();
|
m_disassemblerAgent.resetLocation();
|
||||||
|
DebuggerToolTipManager::resetLocation();
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|||||||
@@ -47,6 +47,7 @@
|
|||||||
#include <utils/tooltip/tipcontents.h>
|
#include <utils/tooltip/tipcontents.h>
|
||||||
#include <utils/qtcassert.h>
|
#include <utils/qtcassert.h>
|
||||||
|
|
||||||
|
#include <QAbstractItemModel>
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
#include <QClipboard>
|
#include <QClipboard>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
@@ -68,9 +69,8 @@ using namespace TextEditor;
|
|||||||
namespace Debugger {
|
namespace Debugger {
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
|
|
||||||
class DebuggerToolTipWidget;
|
//#define DEBUG(x) qDebug() << x
|
||||||
QList<QPointer<DebuggerToolTipWidget>> m_tooltips;
|
#define DEBUG(x)
|
||||||
bool m_debugModeActive;
|
|
||||||
|
|
||||||
// Expire tooltips after n days on (no longer load them) in order
|
// Expire tooltips after n days on (no longer load them) in order
|
||||||
// to avoid them piling up.
|
// to avoid them piling up.
|
||||||
@@ -98,12 +98,11 @@ const char modelColumnCountAttributeC[] = "columncount";
|
|||||||
const char modelRowElementC[] = "row";
|
const char modelRowElementC[] = "row";
|
||||||
const char modelItemElementC[] = "item";
|
const char modelItemElementC[] = "item";
|
||||||
|
|
||||||
static void purgeClosedToolTips()
|
static void purgeClosedToolTips();
|
||||||
{
|
|
||||||
for (int i = m_tooltips.size(); --i >= 0; )
|
class DebuggerToolTipHolder;
|
||||||
if (!m_tooltips.at(i))
|
QList<QPointer<DebuggerToolTipHolder>> m_tooltips;
|
||||||
m_tooltips.removeAt(i);
|
bool m_debugModeActive;
|
||||||
}
|
|
||||||
|
|
||||||
// Forward a stream reader across end elements looking for the
|
// Forward a stream reader across end elements looking for the
|
||||||
// next start element of a desired type.
|
// next start element of a desired type.
|
||||||
@@ -407,7 +406,7 @@ static QDebug operator<<(QDebug d, const QAbstractItemModel &model)
|
|||||||
QTextStream str(&s);
|
QTextStream str(&s);
|
||||||
Debugger::Internal::DumpTreeModelVisitor v(&model, Debugger::Internal::DumpTreeModelVisitor::DebugMode, str);
|
Debugger::Internal::DumpTreeModelVisitor v(&model, Debugger::Internal::DumpTreeModelVisitor::DebugMode, str);
|
||||||
v.run();
|
v.run();
|
||||||
qDebug().nospace() << s;
|
qCDebug(tooltip).nospace() << s;
|
||||||
return d;
|
return d;
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
@@ -443,7 +442,7 @@ public:
|
|||||||
{
|
{
|
||||||
const QModelIndex nameIndex = sourceModel()->index(sourceRow, 0, sourceParent);
|
const QModelIndex nameIndex = sourceModel()->index(sourceRow, 0, sourceParent);
|
||||||
const QByteArray iname = nameIndex.data(LocalsINameRole).toByteArray();
|
const QByteArray iname = nameIndex.data(LocalsINameRole).toByteArray();
|
||||||
// qDebug() << "ACCEPTING FILTER" << iname
|
// DEBUG("ACCEPTING FILTER" << iname
|
||||||
// << (iname == m_iname || isSubIname(iname, m_iname) || isSubIname(m_iname, iname));
|
// << (iname == m_iname || isSubIname(iname, m_iname) || isSubIname(m_iname, iname));
|
||||||
return iname == m_iname || isSubIname(iname, m_iname) || isSubIname(m_iname, iname);
|
return iname == m_iname || isSubIname(iname, m_iname) || isSubIname(m_iname, iname);
|
||||||
}
|
}
|
||||||
@@ -612,58 +611,78 @@ QString DebuggerToolTipManager::treeModelClipboardContents(const QAbstractItemMo
|
|||||||
class DebuggerToolTipWidget : public QWidget
|
class DebuggerToolTipWidget : public QWidget
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
DebuggerToolTipWidget(const DebuggerToolTipContext &context);
|
DebuggerToolTipWidget()
|
||||||
|
|
||||||
bool isPinned() const { return m_isPinned; }
|
|
||||||
QString fileName() const { return m_context.fileName; }
|
|
||||||
QString function() const { return m_context.function; }
|
|
||||||
int position() const { return m_context.position; }
|
|
||||||
|
|
||||||
const DebuggerToolTipContext &context() const { return m_context; }
|
|
||||||
|
|
||||||
void acquireEngine();
|
|
||||||
void releaseEngine();
|
|
||||||
|
|
||||||
void saveSessionData(QXmlStreamWriter &w) const;
|
|
||||||
void setWatchModel(WatchModelBase *watchModel);
|
|
||||||
void handleStackFrameCompleted(const QString &frameFile, const QString &frameFunction);
|
|
||||||
|
|
||||||
void copy();
|
|
||||||
void positionShow(const TextEditorWidget *editorWidget);
|
|
||||||
void pin();
|
|
||||||
|
|
||||||
void handleItemIsExpanded(const QModelIndex &sourceIdx)
|
|
||||||
{
|
{
|
||||||
QTC_ASSERT(m_filterModel.sourceModel() == sourceIdx.model(), return);
|
setAttribute(Qt::WA_DeleteOnClose);
|
||||||
QModelIndex mappedIdx = m_filterModel.mapFromSource(sourceIdx);
|
|
||||||
if (!m_treeView->isExpanded(mappedIdx))
|
isPinned = false;
|
||||||
m_treeView->expand(mappedIdx);
|
const QIcon pinIcon(QLatin1String(":/debugger/images/pin.xpm"));
|
||||||
|
|
||||||
|
pinButton = new QToolButton;
|
||||||
|
pinButton->setIcon(pinIcon);
|
||||||
|
|
||||||
|
auto copyButton = new QToolButton;
|
||||||
|
copyButton->setIcon(QIcon(QLatin1String(Core::Constants::ICON_COPY)));
|
||||||
|
|
||||||
|
titleLabel = new DraggableLabel(this);
|
||||||
|
titleLabel->setMinimumWidth(40); // Ensure a draggable area even if text is empty.
|
||||||
|
titleLabel->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred);
|
||||||
|
|
||||||
|
auto toolBar = new QToolBar(this);
|
||||||
|
toolBar->setProperty("_q_custom_style_disabled", QVariant(true));
|
||||||
|
const QList<QSize> pinIconSizes = pinIcon.availableSizes();
|
||||||
|
if (!pinIconSizes.isEmpty())
|
||||||
|
toolBar->setIconSize(pinIconSizes.front());
|
||||||
|
toolBar->addWidget(pinButton);
|
||||||
|
toolBar->addWidget(copyButton);
|
||||||
|
toolBar->addWidget(titleLabel);
|
||||||
|
|
||||||
|
treeView = new DebuggerToolTipTreeView(this);
|
||||||
|
treeView->setFocusPolicy(Qt::NoFocus);
|
||||||
|
|
||||||
|
auto mainLayout = new QVBoxLayout(this);
|
||||||
|
mainLayout->setSizeConstraint(QLayout::SetFixedSize);
|
||||||
|
mainLayout->setContentsMargins(0, 0, 0, 0);
|
||||||
|
mainLayout->addWidget(toolBar);
|
||||||
|
mainLayout->addWidget(treeView);
|
||||||
|
|
||||||
|
connect(copyButton, &QAbstractButton::clicked, [this] {
|
||||||
|
QString clipboardText = DebuggerToolTipManager::treeModelClipboardContents(treeView->model());
|
||||||
|
QClipboard *clipboard = QApplication::clipboard();
|
||||||
|
clipboard->setText(clipboardText, QClipboard::Selection);
|
||||||
|
clipboard->setText(clipboardText, QClipboard::Clipboard);
|
||||||
|
});
|
||||||
|
DEBUG("CREATE DEBUGGERTOOLTIP WIDGET");
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
~DebuggerToolTipWidget()
|
||||||
bool m_isPinned;
|
{
|
||||||
QToolButton *m_toolButton;
|
DEBUG("DESTROY DEBUGGERTOOLTIP WIDGET");
|
||||||
DraggableLabel *m_titleLabel;
|
}
|
||||||
QDate m_creationDate;
|
|
||||||
DebuggerToolTipTreeView *m_treeView; //!< Pointing to either m_defaultModel oder m_filterModel
|
|
||||||
DebuggerToolTipContext m_context;
|
|
||||||
TooltipFilterModel m_filterModel; //!< Pointing to a valid watchModel
|
|
||||||
QStandardItemModel m_defaultModel;
|
|
||||||
};
|
|
||||||
|
|
||||||
static void hideAllToolTips()
|
void closeEvent(QCloseEvent *)
|
||||||
{
|
{
|
||||||
purgeClosedToolTips();
|
DEBUG("CLOSE DEBUGGERTOOLTIP WIDGET");
|
||||||
foreach (const QPointer<DebuggerToolTipWidget> &tw, m_tooltips)
|
}
|
||||||
tw->hide();
|
|
||||||
}
|
|
||||||
|
|
||||||
void DebuggerToolTipWidget::pin()
|
void enterEvent(QEvent *)
|
||||||
{
|
{
|
||||||
if (m_isPinned)
|
DEBUG("ENTER DEBUGGERTOOLTIP WIDGET");
|
||||||
|
}
|
||||||
|
|
||||||
|
void leaveEvent(QEvent *)
|
||||||
|
{
|
||||||
|
DEBUG("LEAVE DEBUGGERTOOLTIP WIDGET");
|
||||||
|
if (BaseTextEditor *editor = BaseTextEditor::currentTextEditor())
|
||||||
|
editor->editorWidget()->activateWindow();
|
||||||
|
}
|
||||||
|
|
||||||
|
void pin()
|
||||||
|
{
|
||||||
|
if (isPinned)
|
||||||
return;
|
return;
|
||||||
m_isPinned = true;
|
isPinned = true;
|
||||||
m_toolButton->setIcon(style()->standardIcon(QStyle::SP_DockWidgetCloseButton));
|
pinButton->setIcon(style()->standardIcon(QStyle::SP_DockWidgetCloseButton));
|
||||||
|
|
||||||
if (parentWidget()) {
|
if (parentWidget()) {
|
||||||
// We are currently within a text editor tooltip:
|
// We are currently within a text editor tooltip:
|
||||||
@@ -673,7 +692,68 @@ void DebuggerToolTipWidget::pin()
|
|||||||
// We have just be restored from session data.
|
// We have just be restored from session data.
|
||||||
setWindowFlags(Qt::ToolTip);
|
setWindowFlags(Qt::ToolTip);
|
||||||
}
|
}
|
||||||
m_titleLabel->active = true; // User can now drag
|
titleLabel->active = true; // User can now drag
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
bool isPinned;
|
||||||
|
QToolButton *pinButton;
|
||||||
|
DraggableLabel *titleLabel;
|
||||||
|
DebuggerToolTipTreeView *treeView;
|
||||||
|
};
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// DebuggerToolTipHolder
|
||||||
|
//
|
||||||
|
/////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
class DebuggerToolTipHolder : public QObject
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
DebuggerToolTipHolder(const DebuggerToolTipContext &context);
|
||||||
|
~DebuggerToolTipHolder();
|
||||||
|
|
||||||
|
enum State { New, Pending, Acquired, Released };
|
||||||
|
|
||||||
|
void acquireEngine();
|
||||||
|
void releaseEngine();
|
||||||
|
|
||||||
|
void saveSessionData(QXmlStreamWriter &w) const;
|
||||||
|
void handleStackFrameCompleted(const QString &frameFile, const QString &frameFunction);
|
||||||
|
|
||||||
|
void positionShow(const TextEditorWidget *editorWidget);
|
||||||
|
|
||||||
|
void handleItemIsExpanded(const QModelIndex &sourceIdx);
|
||||||
|
void updateTooltip(const QString &frameFile, const QString &frameFunction);
|
||||||
|
|
||||||
|
void setState(State newState);
|
||||||
|
|
||||||
|
public:
|
||||||
|
QPointer<DebuggerToolTipWidget> widget;
|
||||||
|
QPointer<DebuggerEngine> engine;
|
||||||
|
QDate creationDate;
|
||||||
|
DebuggerToolTipContext context;
|
||||||
|
TooltipFilterModel filterModel; //!< Pointing to a valid watchModel
|
||||||
|
QStandardItemModel defaultModel;
|
||||||
|
|
||||||
|
State state;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void hideAllToolTips()
|
||||||
|
{
|
||||||
|
purgeClosedToolTips();
|
||||||
|
foreach (const DebuggerToolTipHolder *tooltip, m_tooltips)
|
||||||
|
tooltip->widget->hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DebuggerToolTipHolder::handleItemIsExpanded(const QModelIndex &sourceIdx)
|
||||||
|
{
|
||||||
|
QTC_ASSERT(filterModel.sourceModel() == sourceIdx.model(), return);
|
||||||
|
QModelIndex mappedIdx = filterModel.mapFromSource(sourceIdx);
|
||||||
|
QTC_ASSERT(widget.data(), return);
|
||||||
|
if (!widget->treeView->isExpanded(mappedIdx))
|
||||||
|
widget->treeView->expand(mappedIdx);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -752,159 +832,154 @@ QDebug operator<<(QDebug d, const DebuggerToolTipContext &c)
|
|||||||
of them. On closing or session changes, the contents it saved.
|
of them. On closing or session changes, the contents it saved.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
DebuggerToolTipHolder::DebuggerToolTipHolder(const DebuggerToolTipContext &context_)
|
||||||
static QString msgReleasedText() { return DebuggerToolTipWidget::tr("Previous"); }
|
|
||||||
|
|
||||||
DebuggerToolTipWidget::DebuggerToolTipWidget(const DebuggerToolTipContext &context)
|
|
||||||
{
|
{
|
||||||
setFocusPolicy(Qt::NoFocus);
|
widget = new DebuggerToolTipWidget;
|
||||||
|
widget->setObjectName(QLatin1String("DebuggerTreeViewToolTipWidget: ") + QLatin1String(context_.iname));
|
||||||
|
|
||||||
m_isPinned = false;
|
context = context_;
|
||||||
m_context = context;
|
context.creationDate = QDate::currentDate();
|
||||||
m_filterModel.m_iname = context.iname;
|
|
||||||
|
|
||||||
const QIcon pinIcon(QLatin1String(":/debugger/images/pin.xpm"));
|
state = New;
|
||||||
|
|
||||||
m_toolButton = new QToolButton;
|
filterModel.m_iname = context.iname;
|
||||||
m_toolButton->setIcon(pinIcon);
|
|
||||||
|
|
||||||
auto copyButton = new QToolButton;
|
QObject::connect(widget->pinButton, &QAbstractButton::clicked, [this] {
|
||||||
copyButton->setIcon(QIcon(QLatin1String(Core::Constants::ICON_COPY)));
|
if (widget->isPinned) {
|
||||||
|
widget->close();
|
||||||
m_titleLabel = new DraggableLabel(this);
|
} else {
|
||||||
m_titleLabel->setText(msgReleasedText());
|
widget->pin();
|
||||||
m_titleLabel->setMinimumWidth(40); // Ensure a draggable area even if text is empty.
|
}
|
||||||
m_titleLabel->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred);
|
|
||||||
|
|
||||||
auto toolBar = new QToolBar(this);
|
|
||||||
toolBar->setProperty("_q_custom_style_disabled", QVariant(true));
|
|
||||||
const QList<QSize> pinIconSizes = pinIcon.availableSizes();
|
|
||||||
if (!pinIconSizes.isEmpty())
|
|
||||||
toolBar->setIconSize(pinIconSizes.front());
|
|
||||||
toolBar->addWidget(m_toolButton);
|
|
||||||
toolBar->addWidget(copyButton);
|
|
||||||
toolBar->addWidget(m_titleLabel);
|
|
||||||
|
|
||||||
m_treeView = new DebuggerToolTipTreeView(this);
|
|
||||||
m_treeView->setFocusPolicy(Qt::NoFocus);
|
|
||||||
|
|
||||||
auto mainLayout = new QVBoxLayout(this);
|
|
||||||
mainLayout->setSizeConstraint(QLayout::SetFixedSize);
|
|
||||||
mainLayout->setContentsMargins(0, 0, 0, 0);
|
|
||||||
mainLayout->addWidget(toolBar);
|
|
||||||
mainLayout->addWidget(m_treeView);
|
|
||||||
|
|
||||||
connect(m_toolButton, &QAbstractButton::clicked, [this]() {
|
|
||||||
if (m_isPinned)
|
|
||||||
close();
|
|
||||||
else
|
|
||||||
pin();
|
|
||||||
});
|
});
|
||||||
|
DEBUG("CREATE DEBUGGERTOOLTIPHOLDER" << context.iname);
|
||||||
connect(copyButton, &QAbstractButton::clicked, this, &DebuggerToolTipWidget::copy);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DebuggerToolTipWidget::setWatchModel(WatchModelBase *watchModel)
|
DebuggerToolTipHolder::~DebuggerToolTipHolder()
|
||||||
{
|
{
|
||||||
QTC_ASSERT(watchModel, return);
|
DEBUG("DESTROY DEBUGGERTOOLTIPHOLDER" << context.iname << " STATE: " << state);
|
||||||
m_filterModel.setSourceModel(watchModel);
|
delete widget; widget.clear();
|
||||||
connect(watchModel, &WatchModelBase::itemIsExpanded,
|
|
||||||
this, &DebuggerToolTipWidget::handleItemIsExpanded, Qt::UniqueConnection);
|
|
||||||
connect(watchModel, &WatchModelBase::columnAdjustmentRequested,
|
|
||||||
m_treeView, &DebuggerToolTipTreeView::computeSize, Qt::UniqueConnection);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DebuggerToolTipWidget::handleStackFrameCompleted(const QString &frameFile, const QString &frameFunction)
|
void DebuggerToolTipHolder::updateTooltip(const QString &frameFile, const QString &frameFunction)
|
||||||
{
|
{
|
||||||
const bool sameFrame = m_context.matchesFrame(frameFile, frameFunction);
|
const bool sameFrame = context.matchesFrame(frameFile, frameFunction);
|
||||||
const bool isAcquired = m_treeView->model() == &m_filterModel;
|
DEBUG("UPDATE TOOLTIP: STATE " << state << context.iname
|
||||||
if (isAcquired && !sameFrame)
|
<< "PINNED: " << widget->isPinned << "SAME FRAME: " << sameFrame);
|
||||||
releaseEngine();
|
|
||||||
else if (!isAcquired && sameFrame)
|
if (state == Pending) {
|
||||||
acquireEngine();
|
acquireEngine();
|
||||||
|
} else if (state == Acquired && !sameFrame) {
|
||||||
|
releaseEngine();
|
||||||
|
} else if (state == Released && sameFrame) {
|
||||||
|
acquireEngine();
|
||||||
|
}
|
||||||
|
|
||||||
if (isAcquired) {
|
if (!widget->isPinned) {
|
||||||
m_treeView->expand(m_filterModel.index(0, 0));
|
DEBUG("SHOW UNPINNED");
|
||||||
WatchTreeView::reexpand(m_treeView, m_filterModel.index(0, 0));
|
const Utils::WidgetContent widgetContent(widget, true);
|
||||||
|
Utils::ToolTip::show(context.mousePosition, widgetContent, Internal::mainWindow());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state == Acquired) {
|
||||||
|
// Save data to stream and restore to the backup m_defaultModel.
|
||||||
|
// Doing it on releaseEngine() is too later.
|
||||||
|
defaultModel.removeRows(0, defaultModel.rowCount());
|
||||||
|
TreeModelCopyVisitor v(&filterModel, &defaultModel);
|
||||||
|
v.run();
|
||||||
|
|
||||||
|
widget->treeView->expand(filterModel.index(0, 0));
|
||||||
|
WatchTreeView::reexpand(widget->treeView, filterModel.index(0, 0));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DebuggerToolTipWidget::acquireEngine()
|
void DebuggerToolTipHolder::setState(DebuggerToolTipHolder::State newState)
|
||||||
{
|
{
|
||||||
m_titleLabel->setText(m_context.expression);
|
bool ok = (state == New && newState == Pending)
|
||||||
m_treeView->setModel(&m_filterModel);
|
|| (state == Pending && (newState == Acquired || newState == Released))
|
||||||
m_treeView->setRootIndex(m_filterModel.index(0, 0));
|
|| (state == Acquired && (newState == Released))
|
||||||
m_treeView->expand(m_filterModel.index(0, 0));
|
|| (state == Released && (newState == Acquired));
|
||||||
WatchTreeView::reexpand(m_treeView, m_filterModel.index(0, 0));
|
|
||||||
|
// FIXME: These happen when a tooltip is re-used in findOrCreate.
|
||||||
|
ok = ok
|
||||||
|
|| (state == Acquired && newState == Pending)
|
||||||
|
|| (state == Released && newState == Pending);
|
||||||
|
|
||||||
|
DEBUG("TRANSITION STATE FROM " << state << " TO " << newState);
|
||||||
|
QTC_ASSERT(ok, qDebug() << "Unexpected tooltip state transition from "
|
||||||
|
<< state << " to " << newState);
|
||||||
|
|
||||||
|
state = newState;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DebuggerToolTipWidget::releaseEngine()
|
void DebuggerToolTipHolder::acquireEngine()
|
||||||
{
|
{
|
||||||
// Save data to stream and restore to the backup m_defaultModel.
|
DEBUG("ACQUIRE ENGINE: STATE " << state);
|
||||||
m_defaultModel.removeRows(0, m_defaultModel.rowCount());
|
setState(Acquired);
|
||||||
TreeModelCopyVisitor v(&m_filterModel, &m_defaultModel);
|
|
||||||
v.run();
|
|
||||||
|
|
||||||
m_titleLabel->setText(msgReleasedText());
|
QTC_ASSERT(widget, return);
|
||||||
m_treeView->setModel(&m_defaultModel);
|
widget->titleLabel->setText(context.expression);
|
||||||
m_treeView->setRootIndex(m_defaultModel.index(0, 0));
|
widget->treeView->setModel(&filterModel);
|
||||||
m_treeView->expandAll();
|
widget->treeView->setRootIndex(filterModel.index(0, 0));
|
||||||
|
widget->treeView->expand(filterModel.index(0, 0));
|
||||||
|
WatchTreeView::reexpand(widget->treeView, filterModel.index(0, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
void DebuggerToolTipWidget::copy()
|
void DebuggerToolTipHolder::releaseEngine()
|
||||||
{
|
{
|
||||||
QString clipboardText = DebuggerToolTipManager::treeModelClipboardContents(m_treeView->model());
|
DEBUG("RELEASE ENGINE: STATE " << state);
|
||||||
QClipboard *clipboard = QApplication::clipboard();
|
setState(Released);
|
||||||
clipboard->setText(clipboardText, QClipboard::Selection);
|
|
||||||
clipboard->setText(clipboardText, QClipboard::Clipboard);
|
QTC_ASSERT(widget, return);
|
||||||
|
widget->titleLabel->setText(DebuggerToolTipManager::tr("%1 (Previous)").arg(context.expression));
|
||||||
|
widget->treeView->setModel(&defaultModel);
|
||||||
|
widget->treeView->setRootIndex(defaultModel.index(0, 0));
|
||||||
|
widget->treeView->expandAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DebuggerToolTipWidget::positionShow(const TextEditorWidget *editorWidget)
|
void DebuggerToolTipHolder::positionShow(const TextEditorWidget *editorWidget)
|
||||||
{
|
{
|
||||||
// Figure out new position of tooltip using the text edit.
|
// Figure out new position of tooltip using the text edit.
|
||||||
// If the line changed too much, close this tip.
|
// If the line changed too much, close this tip.
|
||||||
QTC_ASSERT(editorWidget, return);
|
QTC_ASSERT(editorWidget, return);
|
||||||
QTextCursor cursor = editorWidget->textCursor();
|
QTextCursor cursor = editorWidget->textCursor();
|
||||||
cursor.setPosition(m_context.position);
|
cursor.setPosition(context.position);
|
||||||
const int line = cursor.blockNumber();
|
const int line = cursor.blockNumber();
|
||||||
if (qAbs(m_context.line - line) > 2) {
|
if (qAbs(context.line - line) > 2) {
|
||||||
close();
|
widget->close();
|
||||||
return ;
|
return ;
|
||||||
}
|
}
|
||||||
|
|
||||||
const QPoint screenPos = editorWidget->toolTipPosition(cursor) + m_titleLabel->m_offset;
|
const QPoint screenPos = editorWidget->toolTipPosition(cursor) + widget->titleLabel->m_offset;
|
||||||
const QRect toolTipArea = QRect(screenPos, QSize(sizeHint()));
|
const QRect toolTipArea = QRect(screenPos, QSize(widget->sizeHint()));
|
||||||
const QRect plainTextArea = QRect(editorWidget->mapToGlobal(QPoint(0, 0)), editorWidget->size());
|
const QRect plainTextArea = QRect(editorWidget->mapToGlobal(QPoint(0, 0)), editorWidget->size());
|
||||||
const bool visible = plainTextArea.intersects(toolTipArea);
|
const bool visible = plainTextArea.intersects(toolTipArea);
|
||||||
// qDebug() << "DebuggerToolTipWidget::positionShow() " << this << m_context
|
// DEBUG("DebuggerToolTipWidget::positionShow() " << this << m_context
|
||||||
// << " line: " << line << " plainTextPos " << toolTipArea
|
// << " line: " << line << " plainTextPos " << toolTipArea
|
||||||
// << " offset: " << m_titleLabel->m_offset
|
// << " offset: " << m_titleLabel->m_offset
|
||||||
// << " Area: " << plainTextArea << " Screen pos: "
|
// << " Area: " << plainTextArea << " Screen pos: "
|
||||||
// << screenPos << te.widget << " visible=" << visible;
|
// << screenPos << te.widget << " visible=" << visible);
|
||||||
|
|
||||||
if (!visible) {
|
if (visible) {
|
||||||
hide();
|
widget->move(screenPos);
|
||||||
return;
|
widget->show();
|
||||||
|
} else {
|
||||||
|
widget->hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
move(screenPos);
|
|
||||||
show();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static DebuggerToolTipWidget *findOrCreateWidget(const DebuggerToolTipContext &context)
|
static DebuggerToolTipHolder *findOrCreateTooltip(const DebuggerToolTipContext &context)
|
||||||
{
|
{
|
||||||
foreach (const QPointer<DebuggerToolTipWidget> &tw, m_tooltips)
|
purgeClosedToolTips();
|
||||||
if (tw && tw->m_context.isSame(context))
|
|
||||||
return tw;
|
|
||||||
|
|
||||||
auto tw = new DebuggerToolTipWidget(context);
|
for (int i = 0, n = m_tooltips.size(); i != n; ++i) {
|
||||||
tw->setAttribute(Qt::WA_DeleteOnClose);
|
DebuggerToolTipHolder *tooltip = m_tooltips.at(i);
|
||||||
tw->setObjectName(QLatin1String("DebuggerTreeViewToolTipWidget: ") + QLatin1String(context.iname));
|
if (tooltip->context.isSame(context))
|
||||||
tw->m_context.creationDate = QDate::currentDate();
|
return tooltip;
|
||||||
|
}
|
||||||
|
|
||||||
m_tooltips.push_back(tw);
|
auto newTooltip = new DebuggerToolTipHolder(context);
|
||||||
|
m_tooltips.push_back(newTooltip);
|
||||||
return tw;
|
return newTooltip;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void restoreTreeModel(QXmlStreamReader &r, QStandardItemModel *m)
|
static void restoreTreeModel(QXmlStreamReader &r, QStandardItemModel *m)
|
||||||
@@ -975,27 +1050,26 @@ static void loadSessionDataHelper(QXmlStreamReader &r)
|
|||||||
context.iname = attributes.value(QLatin1String(treeInameAttributeC)).toString().toLatin1();
|
context.iname = attributes.value(QLatin1String(treeInameAttributeC)).toString().toLatin1();
|
||||||
context.expression = attributes.value(QLatin1String(treeExpressionAttributeC)).toString();
|
context.expression = attributes.value(QLatin1String(treeExpressionAttributeC)).toString();
|
||||||
|
|
||||||
const QStringRef className = attributes.value(QLatin1String(toolTipClassAttributeC));
|
// const QStringRef className = attributes.value(QLatin1String(toolTipClassAttributeC));
|
||||||
context.engineType = attributes.value(QLatin1String(engineTypeAttributeC)).toString();
|
context.engineType = attributes.value(QLatin1String(engineTypeAttributeC)).toString();
|
||||||
context.creationDate = dateFromString(attributes.value(QLatin1String(dateAttributeC)).toString());
|
context.creationDate = dateFromString(attributes.value(QLatin1String(dateAttributeC)).toString());
|
||||||
bool readTree = context.isValid();
|
bool readTree = context.isValid();
|
||||||
if (!context.creationDate.isValid() || context.creationDate.daysTo(QDate::currentDate()) > toolTipsExpiryDays) {
|
if (!context.creationDate.isValid() || context.creationDate.daysTo(QDate::currentDate()) > toolTipsExpiryDays) {
|
||||||
// qDebug() << "Expiring tooltip " << context.fileName << '@' << context.position << " from " << creationDate;
|
// DEBUG("Expiring tooltip " << context.fileName << '@' << context.position << " from " << creationDate)
|
||||||
|
//readTree = false;
|
||||||
|
} else { //if (className != QLatin1String("Debugger::Internal::DebuggerToolTipWidget")) {
|
||||||
|
//qWarning("Unable to create debugger tool tip widget of class %s", qPrintable(className.toString()));
|
||||||
//readTree = false;
|
//readTree = false;
|
||||||
} else if (className != QLatin1String("Debugger::Internal::DebuggerToolTipWidget")) {
|
|
||||||
qWarning("Unable to create debugger tool tip widget of class %s", qPrintable(className.toString()));
|
|
||||||
readTree = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (readTree) {
|
if (readTree) {
|
||||||
DebuggerToolTipWidget *tw = findOrCreateWidget(context);
|
DebuggerToolTipHolder *tw = findOrCreateTooltip(context);
|
||||||
restoreTreeModel(r, &tw->m_defaultModel);
|
restoreTreeModel(r, &tw->defaultModel);
|
||||||
tw->pin();
|
tw->widget->pin();
|
||||||
tw->acquireEngine();
|
tw->widget->titleLabel->setText(DebuggerToolTipManager::tr("%1 (Restored").arg(context.expression));
|
||||||
tw->m_titleLabel->setText(DebuggerToolTipManager::tr("Restored"));
|
tw->widget->treeView->setModel(&tw->defaultModel);
|
||||||
tw->m_treeView->setModel(&tw->m_defaultModel);
|
tw->widget->treeView->setRootIndex(tw->defaultModel.index(0, 0));
|
||||||
tw->m_treeView->setRootIndex(tw->m_defaultModel.index(0, 0));
|
tw->widget->treeView->expandAll();
|
||||||
tw->m_treeView->expandAll();
|
|
||||||
} else {
|
} else {
|
||||||
r.readElementText(QXmlStreamReader::SkipChildElements); // Skip
|
r.readElementText(QXmlStreamReader::SkipChildElements); // Skip
|
||||||
}
|
}
|
||||||
@@ -1003,29 +1077,30 @@ static void loadSessionDataHelper(QXmlStreamReader &r)
|
|||||||
r.readNext(); // Skip </tree>
|
r.readNext(); // Skip </tree>
|
||||||
}
|
}
|
||||||
|
|
||||||
void DebuggerToolTipWidget::saveSessionData(QXmlStreamWriter &w) const
|
void DebuggerToolTipHolder::saveSessionData(QXmlStreamWriter &w) const
|
||||||
{
|
{
|
||||||
w.writeStartElement(QLatin1String(toolTipElementC));
|
w.writeStartElement(QLatin1String(toolTipElementC));
|
||||||
QXmlStreamAttributes attributes;
|
QXmlStreamAttributes attributes;
|
||||||
attributes.append(QLatin1String(toolTipClassAttributeC), QString::fromLatin1(metaObject()->className()));
|
// attributes.append(QLatin1String(toolTipClassAttributeC), QString::fromLatin1(metaObject()->className()));
|
||||||
attributes.append(QLatin1String(fileNameAttributeC), m_context.fileName);
|
attributes.append(QLatin1String(fileNameAttributeC), context.fileName);
|
||||||
if (!m_context.function.isEmpty())
|
if (!context.function.isEmpty())
|
||||||
attributes.append(QLatin1String(functionAttributeC), m_context.function);
|
attributes.append(QLatin1String(functionAttributeC), context.function);
|
||||||
attributes.append(QLatin1String(textPositionAttributeC), QString::number(m_context.position));
|
attributes.append(QLatin1String(textPositionAttributeC), QString::number(context.position));
|
||||||
attributes.append(QLatin1String(textLineAttributeC), QString::number(m_context.line));
|
attributes.append(QLatin1String(textLineAttributeC), QString::number(context.line));
|
||||||
attributes.append(QLatin1String(textColumnAttributeC), QString::number(m_context.column));
|
attributes.append(QLatin1String(textColumnAttributeC), QString::number(context.column));
|
||||||
attributes.append(QLatin1String(dateAttributeC), m_creationDate.toString(QLatin1String("yyyyMMdd")));
|
attributes.append(QLatin1String(dateAttributeC), creationDate.toString(QLatin1String("yyyyMMdd")));
|
||||||
if (m_titleLabel->m_offset.x())
|
QPoint offset = widget->titleLabel->m_offset;
|
||||||
attributes.append(QLatin1String(offsetXAttributeC), QString::number(m_titleLabel->m_offset.x()));
|
if (offset.x())
|
||||||
if (m_titleLabel->m_offset.y())
|
attributes.append(QLatin1String(offsetXAttributeC), QString::number(offset.x()));
|
||||||
attributes.append(QLatin1String(offsetYAttributeC), QString::number(m_titleLabel->m_offset.y()));
|
if (offset.y())
|
||||||
attributes.append(QLatin1String(engineTypeAttributeC), m_context.engineType);
|
attributes.append(QLatin1String(offsetYAttributeC), QString::number(offset.y()));
|
||||||
attributes.append(QLatin1String(treeExpressionAttributeC), m_context.expression);
|
attributes.append(QLatin1String(engineTypeAttributeC), context.engineType);
|
||||||
attributes.append(QLatin1String(treeInameAttributeC), QLatin1String(m_context.iname));
|
attributes.append(QLatin1String(treeExpressionAttributeC), context.expression);
|
||||||
|
attributes.append(QLatin1String(treeInameAttributeC), QLatin1String(context.iname));
|
||||||
w.writeAttributes(attributes);
|
w.writeAttributes(attributes);
|
||||||
|
|
||||||
w.writeStartElement(QLatin1String(treeElementC));
|
w.writeStartElement(QLatin1String(treeElementC));
|
||||||
XmlWriterTreeModelVisitor v(&m_filterModel, w);
|
XmlWriterTreeModelVisitor v(&filterModel, w);
|
||||||
v.run();
|
v.run();
|
||||||
w.writeEndElement();
|
w.writeEndElement();
|
||||||
|
|
||||||
@@ -1047,18 +1122,16 @@ void DebuggerToolTipWidget::saveSessionData(QXmlStreamWriter &w) const
|
|||||||
(by file name and function) acquire the engine, others release.
|
(by file name and function) acquire the engine, others release.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
static DebuggerToolTipManager *m_instance = 0;
|
||||||
|
|
||||||
DebuggerToolTipManager::DebuggerToolTipManager()
|
DebuggerToolTipManager::DebuggerToolTipManager()
|
||||||
{
|
{
|
||||||
|
m_instance = this;
|
||||||
}
|
}
|
||||||
|
|
||||||
DebuggerToolTipManager::~DebuggerToolTipManager()
|
DebuggerToolTipManager::~DebuggerToolTipManager()
|
||||||
{
|
{
|
||||||
}
|
m_instance = 0;
|
||||||
|
|
||||||
void DebuggerToolTipManager::registerEngine(DebuggerEngine *)
|
|
||||||
{
|
|
||||||
loadSessionData();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DebuggerToolTipManager::slotUpdateVisibleToolTips()
|
void DebuggerToolTipManager::slotUpdateVisibleToolTips()
|
||||||
@@ -1084,11 +1157,26 @@ void DebuggerToolTipManager::slotUpdateVisibleToolTips()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Reposition and show all tooltips of that file.
|
// Reposition and show all tooltips of that file.
|
||||||
foreach (const QPointer<DebuggerToolTipWidget> &tw, m_tooltips) {
|
foreach (DebuggerToolTipHolder *tooltip, m_tooltips) {
|
||||||
if (tw->fileName() == fileName)
|
if (tooltip->context.fileName == fileName)
|
||||||
tw->positionShow(toolTipEditor->editorWidget());
|
tooltip->positionShow(toolTipEditor->editorWidget());
|
||||||
else
|
else
|
||||||
tw->hide();
|
tooltip->widget->hide();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DebuggerToolTipManager::slotItemIsExpanded(const QModelIndex &idx)
|
||||||
|
{
|
||||||
|
foreach (DebuggerToolTipHolder *tooltip, m_tooltips)
|
||||||
|
tooltip->handleItemIsExpanded(idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DebuggerToolTipManager::slotColumnAdjustmentRequested()
|
||||||
|
{
|
||||||
|
foreach (DebuggerToolTipHolder *tooltip, m_tooltips) {
|
||||||
|
QTC_ASSERT(tooltip, continue);
|
||||||
|
QTC_ASSERT(tooltip->widget, continue);
|
||||||
|
tooltip->widget->treeView->computeSize();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1111,17 +1199,42 @@ void DebuggerToolTipManager::updateEngine(DebuggerEngine *engine)
|
|||||||
function = frame.function;
|
function = frame.function;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
foreach (const QPointer<DebuggerToolTipWidget> &tw, m_tooltips)
|
foreach (DebuggerToolTipHolder *tooltip, m_tooltips)
|
||||||
tw->handleStackFrameCompleted(fileName, function);
|
tooltip->updateTooltip(fileName, function);
|
||||||
slotUpdateVisibleToolTips(); // Move out when stepping in same file.
|
slotUpdateVisibleToolTips(); // Move tooltip when stepping in same file.
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void DebuggerToolTipManager::registerEngine(DebuggerEngine *engine)
|
||||||
|
{
|
||||||
|
DEBUG("REGISTER ENGINE");
|
||||||
|
WatchModelBase *watchModel = engine->watchHandler()->model();
|
||||||
|
connect(watchModel, &WatchModelBase::itemIsExpanded,
|
||||||
|
m_instance, &DebuggerToolTipManager::slotItemIsExpanded);
|
||||||
|
connect(watchModel, &WatchModelBase::columnAdjustmentRequested,
|
||||||
|
m_instance, &DebuggerToolTipManager::slotColumnAdjustmentRequested);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DebuggerToolTipManager::deregisterEngine(DebuggerEngine *engine)
|
void DebuggerToolTipManager::deregisterEngine(DebuggerEngine *engine)
|
||||||
{
|
{
|
||||||
|
DEBUG("DEREGISTER ENGINE");
|
||||||
QTC_ASSERT(engine, return);
|
QTC_ASSERT(engine, return);
|
||||||
foreach (const QPointer<DebuggerToolTipWidget> &tw, m_tooltips)
|
|
||||||
if (tw && tw->m_context.engineType == engine->objectName())
|
// FIXME: For now remove all.
|
||||||
tw->releaseEngine();
|
purgeClosedToolTips();
|
||||||
|
foreach (const DebuggerToolTipHolder *tooltip, m_tooltips)
|
||||||
|
tooltip->widget->close();
|
||||||
|
purgeClosedToolTips();
|
||||||
|
return;
|
||||||
|
|
||||||
|
WatchModelBase *watchModel = engine->watchHandler()->model();
|
||||||
|
disconnect(watchModel, &WatchModelBase::itemIsExpanded,
|
||||||
|
m_instance, &DebuggerToolTipManager::slotItemIsExpanded);
|
||||||
|
disconnect(watchModel, &WatchModelBase::columnAdjustmentRequested,
|
||||||
|
m_instance, &DebuggerToolTipManager::slotColumnAdjustmentRequested);
|
||||||
|
foreach (DebuggerToolTipHolder *tooltip, m_tooltips)
|
||||||
|
if (tooltip->context.engineType == engine->objectName())
|
||||||
|
tooltip->releaseEngine();
|
||||||
saveSessionData();
|
saveSessionData();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1130,20 +1243,6 @@ bool DebuggerToolTipManager::hasToolTips()
|
|||||||
return !m_tooltips.isEmpty();
|
return !m_tooltips.isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DebuggerToolTipManager::showToolTip
|
|
||||||
(const DebuggerToolTipContext &context, DebuggerEngine *engine)
|
|
||||||
{
|
|
||||||
QTC_ASSERT(engine, return);
|
|
||||||
QTC_ASSERT(!context.expression.isEmpty(), qDebug(" BUT EMPTY"); return);
|
|
||||||
|
|
||||||
DebuggerToolTipWidget *tw = findOrCreateWidget(context);
|
|
||||||
tw->setWatchModel(engine->watchHandler()->model());
|
|
||||||
tw->acquireEngine();
|
|
||||||
|
|
||||||
const Utils::WidgetContent widgetContent(tw, true);
|
|
||||||
Utils::ToolTip::show(context.mousePosition, widgetContent, Internal::mainWindow());
|
|
||||||
}
|
|
||||||
|
|
||||||
void DebuggerToolTipManager::sessionAboutToChange()
|
void DebuggerToolTipManager::sessionAboutToChange()
|
||||||
{
|
{
|
||||||
closeAllToolTips();
|
closeAllToolTips();
|
||||||
@@ -1151,6 +1250,8 @@ void DebuggerToolTipManager::sessionAboutToChange()
|
|||||||
|
|
||||||
void DebuggerToolTipManager::loadSessionData()
|
void DebuggerToolTipManager::loadSessionData()
|
||||||
{
|
{
|
||||||
|
return; // FIXME
|
||||||
|
|
||||||
const QString data = sessionValue(sessionSettingsKeyC).toString();
|
const QString data = sessionValue(sessionSettingsKeyC).toString();
|
||||||
QXmlStreamReader r(data);
|
QXmlStreamReader r(data);
|
||||||
r.readNextStartElement();
|
r.readNextStartElement();
|
||||||
@@ -1161,6 +1262,8 @@ void DebuggerToolTipManager::loadSessionData()
|
|||||||
|
|
||||||
void DebuggerToolTipManager::saveSessionData()
|
void DebuggerToolTipManager::saveSessionData()
|
||||||
{
|
{
|
||||||
|
return; // FIXME
|
||||||
|
|
||||||
QString data;
|
QString data;
|
||||||
purgeClosedToolTips();
|
purgeClosedToolTips();
|
||||||
|
|
||||||
@@ -1168,9 +1271,9 @@ void DebuggerToolTipManager::saveSessionData()
|
|||||||
w.writeStartDocument();
|
w.writeStartDocument();
|
||||||
w.writeStartElement(QLatin1String(sessionDocumentC));
|
w.writeStartElement(QLatin1String(sessionDocumentC));
|
||||||
w.writeAttribute(QLatin1String(sessionVersionAttributeC), QLatin1String("1.0"));
|
w.writeAttribute(QLatin1String(sessionVersionAttributeC), QLatin1String("1.0"));
|
||||||
foreach (const QPointer<DebuggerToolTipWidget> &tw, m_tooltips)
|
foreach (DebuggerToolTipHolder *tooltip, m_tooltips)
|
||||||
if (tw->isPinned())
|
if (tooltip->widget->isPinned)
|
||||||
tw->saveSessionData(w);
|
tooltip->saveSessionData(w);
|
||||||
w.writeEndDocument();
|
w.writeEndDocument();
|
||||||
|
|
||||||
setSessionValue(sessionSettingsKeyC, QVariant(data));
|
setSessionValue(sessionSettingsKeyC, QVariant(data));
|
||||||
@@ -1178,12 +1281,18 @@ void DebuggerToolTipManager::saveSessionData()
|
|||||||
|
|
||||||
void DebuggerToolTipManager::closeAllToolTips()
|
void DebuggerToolTipManager::closeAllToolTips()
|
||||||
{
|
{
|
||||||
purgeClosedToolTips();
|
foreach (DebuggerToolTipHolder *tooltip, m_tooltips)
|
||||||
foreach (const QPointer<DebuggerToolTipWidget> &tw, m_tooltips)
|
tooltip->widget->close();
|
||||||
tw->close();
|
|
||||||
m_tooltips.clear();
|
m_tooltips.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DebuggerToolTipManager::resetLocation()
|
||||||
|
{
|
||||||
|
purgeClosedToolTips();
|
||||||
|
foreach (DebuggerToolTipHolder *tooltip, m_tooltips)
|
||||||
|
tooltip->widget->pin();
|
||||||
|
}
|
||||||
|
|
||||||
static void slotTooltipOverrideRequested
|
static void slotTooltipOverrideRequested
|
||||||
(TextEditorWidget *editorWidget, const QPoint &point, int pos, bool *handled)
|
(TextEditorWidget *editorWidget, const QPoint &point, int pos, bool *handled)
|
||||||
{
|
{
|
||||||
@@ -1208,29 +1317,49 @@ static void slotTooltipOverrideRequested
|
|||||||
context.expression = fixCppExpression(raw);
|
context.expression = fixCppExpression(raw);
|
||||||
|
|
||||||
if (context.expression.isEmpty()) {
|
if (context.expression.isEmpty()) {
|
||||||
const Utils::WidgetContent widgetContent(new QLabel(DebuggerToolTipManager::tr("No valid expression")), true);
|
const Utils::TextContent text(DebuggerToolTipManager::tr("No valid expression"));
|
||||||
Utils::ToolTip::show(context.mousePosition, widgetContent, Internal::mainWindow());
|
Utils::ToolTip::show(context.mousePosition, text, Internal::mainWindow());
|
||||||
*handled = true;
|
*handled = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prefer a filter on an existing local variable if it can be found.
|
// Prefer a filter on an existing local variable if it can be found.
|
||||||
if (const WatchData *localVariable = engine->watchHandler()->findCppLocalVariable(context.expression)) {
|
const WatchData *localVariable = engine->watchHandler()->findCppLocalVariable(context.expression);
|
||||||
|
if (localVariable) {
|
||||||
context.expression = QLatin1String(localVariable->exp);
|
context.expression = QLatin1String(localVariable->exp);
|
||||||
if (context.expression.isEmpty())
|
if (context.expression.isEmpty())
|
||||||
context.expression = localVariable->name;
|
context.expression = localVariable->name;
|
||||||
context.iname = localVariable->iname;
|
context.iname = localVariable->iname;
|
||||||
DebuggerToolTipManager::showToolTip(context, engine);
|
} else {
|
||||||
|
context.iname = "tooltip." + context.expression.toLatin1().toHex();
|
||||||
|
}
|
||||||
|
|
||||||
|
DebuggerToolTipHolder *tooltip = findOrCreateTooltip(context);
|
||||||
|
if (tooltip->state == DebuggerToolTipHolder::Pending) {
|
||||||
|
DEBUG("FOUND PENDING TOOLTIP, WAITING...");
|
||||||
*handled = true;
|
*handled = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
context.iname = "tooltip." + context.expression.toLatin1().toHex();
|
tooltip->filterModel.setSourceModel(engine->watchHandler()->model());
|
||||||
|
tooltip->widget->titleLabel->setText(DebuggerToolTipManager::tr("Updating"));
|
||||||
|
tooltip->setState(DebuggerToolTipHolder::Pending);
|
||||||
|
|
||||||
|
if (localVariable) {
|
||||||
|
tooltip->acquireEngine();
|
||||||
|
DEBUG("SYNC IN STATE" << tooltip->state);
|
||||||
|
const Utils::WidgetContent widgetContent(tooltip->widget, true);
|
||||||
|
Utils::ToolTip::show(context.mousePosition, widgetContent, Internal::mainWindow());
|
||||||
|
*handled = true;
|
||||||
|
} else {
|
||||||
|
DEBUG("ASYNC TIP IN STATE" << tooltip->state);
|
||||||
*handled = engine->setToolTipExpression(editorWidget, context);
|
*handled = engine->setToolTipExpression(editorWidget, context);
|
||||||
|
if (!*handled) {
|
||||||
// Other tooltip, close all in case mouse never entered the tooltip
|
const Utils::TextContent text(DebuggerToolTipManager::tr("Expression too complex"));
|
||||||
// and no leave was triggered.
|
Utils::ToolTip::show(context.mousePosition, text, Internal::mainWindow());
|
||||||
|
tooltip->widget->close();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1284,13 +1413,14 @@ void DebuggerToolTipManager::leavingDebugMode()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DebuggerToolTipContexts DebuggerToolTipManager::treeWidgetExpressions
|
DebuggerToolTipContexts DebuggerToolTipManager::pendingTooltips(DebuggerEngine *engine)
|
||||||
(DebuggerEngine *, const QString &fileName, const QString &function)
|
|
||||||
{
|
{
|
||||||
|
StackFrame frame = engine->stackHandler()->currentFrame();
|
||||||
DebuggerToolTipContexts rc;
|
DebuggerToolTipContexts rc;
|
||||||
foreach (const QPointer<DebuggerToolTipWidget> &tw, m_tooltips) {
|
foreach (DebuggerToolTipHolder *tooltip, m_tooltips) {
|
||||||
if (tw && tw->context().matchesFrame(fileName, function))
|
if (tooltip->context.iname.startsWith("tooltip")
|
||||||
rc.push_back(tw->context());
|
&& tooltip->context.matchesFrame(frame.file, frame.function))
|
||||||
|
rc.push_back(tooltip->context);
|
||||||
}
|
}
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
@@ -1304,9 +1434,9 @@ bool DebuggerToolTipManager::eventFilter(QObject *o, QEvent *e)
|
|||||||
const QMoveEvent *me = static_cast<const QMoveEvent *>(e);
|
const QMoveEvent *me = static_cast<const QMoveEvent *>(e);
|
||||||
const QPoint dist = me->pos() - me->oldPos();
|
const QPoint dist = me->pos() - me->oldPos();
|
||||||
purgeClosedToolTips();
|
purgeClosedToolTips();
|
||||||
foreach (const QPointer<DebuggerToolTipWidget> &tw, m_tooltips)
|
foreach (DebuggerToolTipHolder *tooltip, m_tooltips)
|
||||||
if (tw->isVisible())
|
if (tooltip->widget && tooltip->widget->isVisible())
|
||||||
tw->move(tw->pos() + dist);
|
tooltip->widget->move(tooltip->widget->pos() + dist);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case QEvent::WindowStateChange: { // Hide/Show along with parent (toplevel)
|
case QEvent::WindowStateChange: { // Hide/Show along with parent (toplevel)
|
||||||
@@ -1315,8 +1445,8 @@ bool DebuggerToolTipManager::eventFilter(QObject *o, QEvent *e)
|
|||||||
const bool isMinimized = static_cast<const QWidget *>(o)->windowState() & Qt::WindowMinimized;
|
const bool isMinimized = static_cast<const QWidget *>(o)->windowState() & Qt::WindowMinimized;
|
||||||
if (wasMinimized ^ isMinimized) {
|
if (wasMinimized ^ isMinimized) {
|
||||||
purgeClosedToolTips();
|
purgeClosedToolTips();
|
||||||
foreach (const QPointer<DebuggerToolTipWidget> &tw, m_tooltips)
|
foreach (DebuggerToolTipHolder *tooltip, m_tooltips)
|
||||||
tw->setVisible(!isMinimized);
|
tooltip->widget->setVisible(!isMinimized);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -1326,5 +1456,16 @@ bool DebuggerToolTipManager::eventFilter(QObject *o, QEvent *e)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void purgeClosedToolTips()
|
||||||
|
{
|
||||||
|
for (int i = m_tooltips.size(); --i >= 0; ) {
|
||||||
|
DebuggerToolTipHolder *tooltip = m_tooltips.at(i);
|
||||||
|
if (!tooltip || !tooltip->widget) {
|
||||||
|
DEBUG("PURGE TOOLTIP, LEFT: " << m_tooltips.size());
|
||||||
|
m_tooltips.removeAt(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
} // namespace Debugger
|
} // namespace Debugger
|
||||||
|
|||||||
@@ -83,12 +83,7 @@ public:
|
|||||||
static void updateEngine(DebuggerEngine *engine);
|
static void updateEngine(DebuggerEngine *engine);
|
||||||
static bool hasToolTips();
|
static bool hasToolTips();
|
||||||
|
|
||||||
// Collect all expressions of DebuggerTreeViewToolTipWidget
|
static DebuggerToolTipContexts pendingTooltips(DebuggerEngine *engine);
|
||||||
static DebuggerToolTipContexts treeWidgetExpressions(DebuggerEngine *engine,
|
|
||||||
const QString &fileName, const QString &function = QString());
|
|
||||||
|
|
||||||
static void showToolTip(const DebuggerToolTipContext &context,
|
|
||||||
DebuggerEngine *engine);
|
|
||||||
|
|
||||||
virtual bool eventFilter(QObject *, QEvent *);
|
virtual bool eventFilter(QObject *, QEvent *);
|
||||||
|
|
||||||
@@ -100,9 +95,12 @@ public:
|
|||||||
static void loadSessionData();
|
static void loadSessionData();
|
||||||
static void saveSessionData();
|
static void saveSessionData();
|
||||||
static void closeAllToolTips();
|
static void closeAllToolTips();
|
||||||
|
static void resetLocation();
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
static void slotUpdateVisibleToolTips();
|
static void slotUpdateVisibleToolTips();
|
||||||
|
void slotItemIsExpanded(const QModelIndex &idx);
|
||||||
|
void slotColumnAdjustmentRequested();
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
|
|||||||
@@ -3632,43 +3632,16 @@ void GdbEngine::handleRegisterListValues(const GdbResponse &response)
|
|||||||
//
|
//
|
||||||
//////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
//void GdbEngine::showToolTip()
|
|
||||||
//{
|
|
||||||
// const QString expression = m_toolTipContext.expression;
|
|
||||||
// if (DebuggerToolTipManager::debug())
|
|
||||||
// qDebug() << "GdbEngine::showToolTip " << expression << m_toolTipContext.iname << m_toolTipContext;
|
|
||||||
|
|
||||||
// if (m_toolTipContext.iname.startsWith("tooltip")
|
|
||||||
// && (!boolSetting(UseToolTipsInMainEditor)
|
|
||||||
// || !watchHandler()->isValidToolTip(m_toolTipContext.iname))) {
|
|
||||||
// watchHandler()->removeData(m_toolTipContext.iname);
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// DebuggerToolTipManager::showToolTip(m_toolTipContext, this);
|
|
||||||
//}
|
|
||||||
|
|
||||||
void GdbEngine::resetLocation()
|
|
||||||
{
|
|
||||||
m_toolTipContext.expression.clear();
|
|
||||||
DebuggerEngine::resetLocation();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool GdbEngine::setToolTipExpression(TextEditor::TextEditorWidget *editor,
|
bool GdbEngine::setToolTipExpression(TextEditor::TextEditorWidget *editor,
|
||||||
const DebuggerToolTipContext &context)
|
const DebuggerToolTipContext &context)
|
||||||
{
|
{
|
||||||
if (state() != InferiorStopOk || !isCppEditor(editor)) {
|
if (state() != InferiorStopOk || !isCppEditor(editor))
|
||||||
//qDebug() << "SUPPRESSING DEBUGGER TOOLTIP, INFERIOR NOT STOPPED "
|
|
||||||
// " OR NOT A CPPEDITOR";
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
m_toolTipContext = context;
|
|
||||||
// qDebug() << "GdbEngine::setToolTipExpression2 " << exp << m_toolTipContext;
|
|
||||||
|
|
||||||
UpdateParameters params;
|
UpdateParameters params;
|
||||||
params.tryPartial = true;
|
params.tryPartial = true;
|
||||||
params.tooltipOnly = true;
|
params.tooltipOnly = true;
|
||||||
|
params.tooltipExpression = context.expression;
|
||||||
params.varList = context.iname;
|
params.varList = context.iname;
|
||||||
updateLocalsPython(params);
|
updateLocalsPython(params);
|
||||||
return true;
|
return true;
|
||||||
@@ -3736,10 +3709,6 @@ void GdbEngine::rebuildWatchModel()
|
|||||||
showMessage(_("<Rebuild Watchmodel %1>").arg(count), LogMiscInput);
|
showMessage(_("<Rebuild Watchmodel %1>").arg(count), LogMiscInput);
|
||||||
showStatusMessage(tr("Finished retrieving data"), 400);
|
showStatusMessage(tr("Finished retrieving data"), 400);
|
||||||
|
|
||||||
if (m_toolTipContext.isValid()) {
|
|
||||||
DebuggerToolTipManager::showToolTip(m_toolTipContext, this);
|
|
||||||
m_toolTipContext = DebuggerToolTipContext();
|
|
||||||
}
|
|
||||||
DebuggerToolTipManager::updateEngine(this);
|
DebuggerToolTipManager::updateEngine(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4829,43 +4798,17 @@ void GdbEngine::updateLocalsPython(const UpdateParameters ¶ms)
|
|||||||
+ " displaystringlimit:"
|
+ " displaystringlimit:"
|
||||||
+ action(DisplayStringLimit)->value().toByteArray();
|
+ action(DisplayStringLimit)->value().toByteArray();
|
||||||
|
|
||||||
|
|
||||||
QByteArray watchers;
|
|
||||||
const QString fileName = stackHandler()->currentFrame().file;
|
|
||||||
const QString function = stackHandler()->currentFrame().function;
|
|
||||||
if (!fileName.isEmpty()) {
|
|
||||||
// Re-create tooltip items that are not filters on existing local variables in
|
// Re-create tooltip items that are not filters on existing local variables in
|
||||||
// the tooltip model.
|
// the tooltip model.
|
||||||
DebuggerToolTipContexts toolTips =
|
QByteArray watchers;
|
||||||
DebuggerToolTipManager::treeWidgetExpressions(this, fileName, function);
|
DebuggerToolTipContexts toolTips = DebuggerToolTipManager::pendingTooltips(this);
|
||||||
|
|
||||||
const QString currentExpression = m_toolTipContext.expression;
|
|
||||||
if (!currentExpression.isEmpty()) {
|
|
||||||
int currentIndex = -1;
|
|
||||||
for (int i = 0; i < toolTips.size(); ++i) {
|
|
||||||
if (toolTips.at(i).expression == currentExpression) {
|
|
||||||
currentIndex = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (currentIndex < 0) {
|
|
||||||
DebuggerToolTipContext context;
|
|
||||||
context.expression = currentExpression;
|
|
||||||
context.iname = tooltipIName(currentExpression);
|
|
||||||
toolTips.push_back(context);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (const DebuggerToolTipContext &p, toolTips) {
|
foreach (const DebuggerToolTipContext &p, toolTips) {
|
||||||
if (p.iname.startsWith("tooltip")) {
|
|
||||||
if (!watchers.isEmpty())
|
if (!watchers.isEmpty())
|
||||||
watchers += "##";
|
watchers += "##";
|
||||||
watchers += p.expression.toLatin1();
|
watchers += p.expression.toLatin1();
|
||||||
watchers += '#';
|
watchers += '#';
|
||||||
watchers += p.iname;
|
watchers += p.iname;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
QHash<QByteArray, int> watcherNames = handler->watcherNames();
|
QHash<QByteArray, int> watcherNames = handler->watcherNames();
|
||||||
QHashIterator<QByteArray, int> it(watcherNames);
|
QHashIterator<QByteArray, int> it(watcherNames);
|
||||||
|
|||||||
@@ -298,7 +298,6 @@ private: ////////// View & Data Stuff //////////
|
|||||||
|
|
||||||
void selectThread(ThreadId threadId);
|
void selectThread(ThreadId threadId);
|
||||||
void activateFrame(int index);
|
void activateFrame(int index);
|
||||||
void resetLocation();
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Breakpoint specific stuff
|
// Breakpoint specific stuff
|
||||||
@@ -469,7 +468,6 @@ protected:
|
|||||||
void showExecutionError(const QString &message);
|
void showExecutionError(const QString &message);
|
||||||
|
|
||||||
static QByteArray tooltipIName(const QString &exp);
|
static QByteArray tooltipIName(const QString &exp);
|
||||||
DebuggerToolTipContext m_toolTipContext;
|
|
||||||
|
|
||||||
// For short-circuiting stack and thread list evaluation.
|
// For short-circuiting stack and thread list evaluation.
|
||||||
bool m_stackNeeded;
|
bool m_stackNeeded;
|
||||||
|
|||||||
@@ -74,11 +74,6 @@ using namespace Utils;
|
|||||||
namespace Debugger {
|
namespace Debugger {
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
|
|
||||||
static QByteArray tooltipIName(const QString &exp)
|
|
||||||
{
|
|
||||||
return "tooltip." + exp.toLatin1().toHex();
|
|
||||||
}
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
// LldbEngine
|
// LldbEngine
|
||||||
@@ -815,41 +810,25 @@ void LldbEngine::refreshSymbols(const GdbMi &symbols)
|
|||||||
//
|
//
|
||||||
//////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
static WatchData m_toolTip;
|
|
||||||
static QPoint m_toolTipPos;
|
|
||||||
static QHash<QString, WatchData> m_toolTipCache;
|
|
||||||
|
|
||||||
void LldbEngine::showToolTip()
|
|
||||||
{
|
|
||||||
if (m_toolTipContext.expression.isEmpty())
|
|
||||||
return;
|
|
||||||
//const QString expression = m_toolTipContext->expression;
|
|
||||||
// qDebug() << "LldbEngine::showToolTip " << expression << m_toolTipContext->iname << (*m_toolTipContext);
|
|
||||||
|
|
||||||
DebuggerToolTipManager::showToolTip(m_toolTipContext, this);
|
|
||||||
// Prevent tooltip from re-occurring (classic GDB, QTCREATORBUG-4711).
|
|
||||||
m_toolTipContext.expression.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
void LldbEngine::resetLocation()
|
void LldbEngine::resetLocation()
|
||||||
{
|
{
|
||||||
m_toolTipContext.expression.clear();
|
|
||||||
DebuggerEngine::resetLocation();
|
DebuggerEngine::resetLocation();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LldbEngine::setToolTipExpression(TextEditor::TextEditorWidget *editorWidget, const DebuggerToolTipContext &context)
|
bool LldbEngine::setToolTipExpression(TextEditor::TextEditorWidget *editorWidget, const DebuggerToolTipContext &context)
|
||||||
{
|
{
|
||||||
|
return false; // FIXME
|
||||||
|
|
||||||
if (state() != InferiorStopOk || !isCppEditor(editorWidget)) {
|
if (state() != InferiorStopOk || !isCppEditor(editorWidget)) {
|
||||||
//qDebug() << "SUPPRESSING DEBUGGER TOOLTIP, INFERIOR NOT STOPPED "
|
//qDebug() << "SUPPRESSING DEBUGGER TOOLTIP, INFERIOR NOT STOPPED "
|
||||||
// " OR NOT A CPPEDITOR";
|
// " OR NOT A CPPEDITOR";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_toolTipContext = context;
|
|
||||||
|
|
||||||
UpdateParameters params;
|
UpdateParameters params;
|
||||||
params.tryPartial = true;
|
params.tryPartial = true;
|
||||||
params.tooltipOnly = true;
|
params.tooltipOnly = true;
|
||||||
|
params.tooltipExpression = context.expression;
|
||||||
params.varList = context.iname;
|
params.varList = context.iname;
|
||||||
doUpdateLocals(params);
|
doUpdateLocals(params);
|
||||||
|
|
||||||
@@ -924,6 +903,7 @@ void LldbEngine::doUpdateLocals(UpdateParameters params)
|
|||||||
cmd.arg("tooltiponly", params.tooltipOnly);
|
cmd.arg("tooltiponly", params.tooltipOnly);
|
||||||
|
|
||||||
cmd.beginList("watchers");
|
cmd.beginList("watchers");
|
||||||
|
|
||||||
// Watchers
|
// Watchers
|
||||||
QHashIterator<QByteArray, int> it(WatchHandler::watcherNames());
|
QHashIterator<QByteArray, int> it(WatchHandler::watcherNames());
|
||||||
while (it.hasNext()) {
|
while (it.hasNext()) {
|
||||||
@@ -933,38 +913,16 @@ void LldbEngine::doUpdateLocals(UpdateParameters params)
|
|||||||
.arg("exp", it.key().toHex())
|
.arg("exp", it.key().toHex())
|
||||||
.endGroup();
|
.endGroup();
|
||||||
}
|
}
|
||||||
// Tooltip
|
|
||||||
const StackFrame frame = stackHandler()->currentFrame();
|
|
||||||
if (!frame.file.isEmpty()) {
|
|
||||||
// Re-create tooltip items that are not filters on existing local variables in
|
|
||||||
// the tooltip model.
|
|
||||||
DebuggerToolTipContexts toolTips =
|
|
||||||
DebuggerToolTipManager::treeWidgetExpressions(this, frame.file, frame.function);
|
|
||||||
|
|
||||||
const QString currentExpression = m_toolTipContext.expression;
|
// Tooltips
|
||||||
if (!currentExpression.isEmpty()) {
|
DebuggerToolTipContexts toolTips = DebuggerToolTipManager::pendingTooltips(this);
|
||||||
int currentIndex = -1;
|
|
||||||
for (int i = 0; i < toolTips.size(); ++i) {
|
|
||||||
if (toolTips.at(i).expression == currentExpression) {
|
|
||||||
currentIndex = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (currentIndex < 0) {
|
|
||||||
DebuggerToolTipContext context;
|
|
||||||
context.expression = currentExpression;
|
|
||||||
context.iname = tooltipIName(currentExpression);
|
|
||||||
toolTips.push_back(context);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
foreach (const DebuggerToolTipContext &p, toolTips) {
|
foreach (const DebuggerToolTipContext &p, toolTips) {
|
||||||
if (p.iname.startsWith("tooltip"))
|
|
||||||
cmd.beginGroup()
|
cmd.beginGroup()
|
||||||
.arg("iname", p.iname)
|
.arg("iname", p.iname)
|
||||||
.arg("exp", p.expression.toLatin1().toHex())
|
.arg("exp", p.expression.toLatin1().toHex())
|
||||||
.endGroup();
|
.endGroup();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
cmd.endList();
|
cmd.endList();
|
||||||
|
|
||||||
//cmd.arg("resultvarname", m_resultVarName);
|
//cmd.arg("resultvarname", m_resultVarName);
|
||||||
@@ -1083,7 +1041,7 @@ void LldbEngine::refreshLocals(const GdbMi &vars)
|
|||||||
}
|
}
|
||||||
handler->insertData(list);
|
handler->insertData(list);
|
||||||
|
|
||||||
showToolTip();
|
DebuggerToolTipManager::updateEngine(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LldbEngine::refreshStack(const GdbMi &stack)
|
void LldbEngine::refreshStack(const GdbMi &stack)
|
||||||
|
|||||||
@@ -218,9 +218,6 @@ private:
|
|||||||
QMap<QPointer<DisassemblerAgent>, int> m_disassemblerAgents;
|
QMap<QPointer<DisassemblerAgent>, int> m_disassemblerAgents;
|
||||||
QMap<QPointer<MemoryAgent>, int> m_memoryAgents;
|
QMap<QPointer<MemoryAgent>, int> m_memoryAgents;
|
||||||
QHash<int, QPointer<QObject> > m_memoryAgentTokens;
|
QHash<int, QPointer<QObject> > m_memoryAgentTokens;
|
||||||
DebuggerToolTipContext m_toolTipContext;
|
|
||||||
|
|
||||||
void showToolTip();
|
|
||||||
|
|
||||||
// Console handling.
|
// Console handling.
|
||||||
Q_SLOT void stubError(const QString &msg);
|
Q_SLOT void stubError(const QString &msg);
|
||||||
|
|||||||
@@ -2015,10 +2015,10 @@ const WatchData *WatchHandler::findCppLocalVariable(const QString &name) const
|
|||||||
QByteArray iname = localsPrefix + name.toLatin1();
|
QByteArray iname = localsPrefix + name.toLatin1();
|
||||||
if (const WatchData *wd = findData(iname))
|
if (const WatchData *wd = findData(iname))
|
||||||
return wd;
|
return wd;
|
||||||
// Nope, try a 'local.this.m_foo'.
|
// // Nope, try a 'local.this.m_foo'.
|
||||||
iname.insert(localsPrefix.size(), "this.");
|
// iname.insert(localsPrefix.size(), "this.");
|
||||||
if (const WatchData *wd = findData(iname))
|
// if (const WatchData *wd = findData(iname))
|
||||||
return wd;
|
// return wd;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -121,6 +121,7 @@ public:
|
|||||||
bool tryPartial;
|
bool tryPartial;
|
||||||
bool tooltipOnly;
|
bool tooltipOnly;
|
||||||
QByteArray varList;
|
QByteArray varList;
|
||||||
|
QString tooltipExpression;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef QHash<QString, QStringList> DumperTypeFormats; // Type name -> Dumper Formats
|
typedef QHash<QString, QStringList> DumperTypeFormats; // Type name -> Dumper Formats
|
||||||
|
|||||||
Reference in New Issue
Block a user