Commit 6886e485 authored by Friedemann Kleint's avatar Friedemann Kleint Committed by hjk

Handle watching/tooltips of C++ editor tokens consistently.

For editor tooltips and the editor context menu
'Watch expression', always try to find a local variable first
and use its expression.

Change the tooltip manager/widgets not to rely on the debugger
model enum and obscure expression, filter by complete iname
instead. Remove obsolete enumeration.

Change gdb's handling of tooltips such that local variables
are displayed immediately without creating additional tooltip
items.

Change-Id: I9b55823428029ba50d84d3a8cab55eb58942e72b
Reviewed-by: default avatarhjk <qthjk@ovi.com>
parent a37eca63
...@@ -404,6 +404,7 @@ void CdbEngine::init() ...@@ -404,6 +404,7 @@ void CdbEngine::init()
m_sourceStepInto = false; m_sourceStepInto = false;
m_watchPointX = m_watchPointY = 0; m_watchPointX = m_watchPointY = 0;
m_ignoreCdbOutput = false; m_ignoreCdbOutput = false;
m_watchInameToName.clear();
m_outputBuffer.clear(); m_outputBuffer.clear();
m_builtinCommandQueue.clear(); m_builtinCommandQueue.clear();
...@@ -470,23 +471,13 @@ bool CdbEngine::setToolTipExpression(const QPoint &mousePos, ...@@ -470,23 +471,13 @@ bool CdbEngine::setToolTipExpression(const QPoint &mousePos,
// Are we in the current stack frame // Are we in the current stack frame
if (context.function.isEmpty() || exp.isEmpty() || context.function != stackHandler()->currentFrame().function) if (context.function.isEmpty() || exp.isEmpty() || context.function != stackHandler()->currentFrame().function)
return false; return false;
// No numerical or any other expressions [yet] // Show tooltips of local variables only. Anything else can slow debugging down.
if (!(exp.at(0).isLetter() || exp.at(0) == QLatin1Char('_'))) const WatchData *localVariable = watchHandler()->findCppLocalVariable(exp);
if (!localVariable)
return false; return false;
// Can this be found as a local variable?
const QByteArray localsPrefix(localsPrefixC);
QByteArray iname = localsPrefix + exp.toAscii();
if (!watchHandler()->hasItem(iname)) {
// Nope, try a 'local.this.m_foo'.
exp.prepend(QLatin1String("this."));
iname.insert(localsPrefix.size(), "this.");
if (!watchHandler()->hasItem(iname))
return false;
}
DebuggerToolTipWidget *tw = new DebuggerToolTipWidget; DebuggerToolTipWidget *tw = new DebuggerToolTipWidget;
tw->setContext(context); tw->setContext(context);
tw->setDebuggerModel(LocalsType); tw->setIname(localVariable->iname);
tw->setExpression(exp);
tw->acquireEngine(this); tw->acquireEngine(this);
DebuggerToolTipManager::instance()->showToolTip(mousePos, editor, tw); DebuggerToolTipManager::instance()->showToolTip(mousePos, editor, tw);
return true; return true;
...@@ -995,6 +986,10 @@ void CdbEngine::updateWatchData(const WatchData &dataIn, ...@@ -995,6 +986,10 @@ void CdbEngine::updateWatchData(const WatchData &dataIn,
QByteArray args; QByteArray args;
ByteArrayInputStream str(args); ByteArrayInputStream str(args);
str << dataIn.iname << " \"" << dataIn.exp << '"'; str << dataIn.iname << " \"" << dataIn.exp << '"';
// Store the name since the CDB extension library
// does not maintain the names of watches.
if (!dataIn.name.isEmpty() && dataIn.name != QLatin1String(dataIn.exp))
m_watchInameToName.insert(dataIn.iname, dataIn.name);
postExtensionCommand("addwatch", args, 0, postExtensionCommand("addwatch", args, 0,
&CdbEngine::handleAddWatch, 0, &CdbEngine::handleAddWatch, 0,
qVariantFromValue(dataIn)); qVariantFromValue(dataIn));
...@@ -1916,6 +1911,15 @@ void CdbEngine::handleLocals(const CdbExtensionCommandPtr &reply) ...@@ -1916,6 +1911,15 @@ void CdbEngine::handleLocals(const CdbExtensionCommandPtr &reply)
dummy.name = QLatin1String(child.findChild("name").data()); dummy.name = QLatin1String(child.findChild("name").data());
parseWatchData(watchHandler()->expandedINames(), dummy, child, &watchData); parseWatchData(watchHandler()->expandedINames(), dummy, child, &watchData);
} }
// Fix the names of watch data.
for (int i =0; i < watchData.size(); ++i) {
if (watchData.at(i).iname.startsWith('w')) {
const QHash<QByteArray, QString>::const_iterator it
= m_watchInameToName.find(watchData.at(i).iname);
if (it != m_watchInameToName.constEnd())
watchData[i].name = it.value();
}
}
watchHandler()->insertData(watchData); watchHandler()->insertData(watchData);
if (debugLocals) { if (debugLocals) {
QDebug nsp = qDebug().nospace(); QDebug nsp = qDebug().nospace();
......
...@@ -275,6 +275,7 @@ private: ...@@ -275,6 +275,7 @@ private:
PendingBreakPointMap m_pendingBreakpointMap; PendingBreakPointMap m_pendingBreakpointMap;
QHash<QString, QString> m_fileNameModuleHash; QHash<QString, QString> m_fileNameModuleHash;
QMultiHash<QString, quint64> m_symbolAddressCache; QMultiHash<QString, quint64> m_symbolAddressCache;
QHash<QByteArray, QString> m_watchInameToName;
bool m_ignoreCdbOutput; bool m_ignoreCdbOutput;
QVariantList m_customSpecialStopData; QVariantList m_customSpecialStopData;
QList<SourcePathMapping> m_sourcePathMappings; QList<SourcePathMapping> m_sourcePathMappings;
......
...@@ -1143,7 +1143,12 @@ public slots: ...@@ -1143,7 +1143,12 @@ public slots:
exp = fixCppExpression(exp); exp = fixCppExpression(exp);
if (exp.isEmpty()) if (exp.isEmpty())
return; return;
currentEngine()->watchHandler()->watchExpression(exp); const QString name = exp;
// Prefer to watch an existing local variable by its expression (address) if it can be found.
WatchHandler *watchHandler = currentEngine()->watchHandler();
if (const WatchData *localVariable = watchHandler->findCppLocalVariable(exp))
exp = QLatin1String(localVariable->exp);
watchHandler->watchExpression(exp, name);
} }
void handleExecExit() void handleExecExit()
......
...@@ -98,8 +98,8 @@ static const char offsetYAttributeC[] = "offset_y"; ...@@ -98,8 +98,8 @@ static const char offsetYAttributeC[] = "offset_y";
static const char engineTypeAttributeC[] = "engine"; static const char engineTypeAttributeC[] = "engine";
static const char dateAttributeC[] = "date"; static const char dateAttributeC[] = "date";
static const char treeElementC[] = "tree"; static const char treeElementC[] = "tree";
static const char treeModelAttributeC[] = "model"; // Locals/Watches static const char treeExpressionAttributeC[] = "expression";
static const char treeExpressionAttributeC[] = "expression"; // Locals/Watches static const char treeInameAttributeC[] = "iname";
static const char modelElementC[] = "model"; static const char modelElementC[] = "model";
static const char modelColumnCountAttributeC[] = "columncount"; static const char modelColumnCountAttributeC[] = "columncount";
static const char modelRowElementC[] = "row"; static const char modelRowElementC[] = "row";
...@@ -615,7 +615,6 @@ DebuggerToolTipWidget::DebuggerToolTipWidget(QWidget *parent) : ...@@ -615,7 +615,6 @@ DebuggerToolTipWidget::DebuggerToolTipWidget(QWidget *parent) :
m_titleLabel(new DraggableLabel), m_titleLabel(new DraggableLabel),
m_engineAcquired(false), m_engineAcquired(false),
m_creationDate(QDate::currentDate()), m_creationDate(QDate::currentDate()),
m_debuggerModel(TooltipType),
m_treeView(new DebuggerToolTipTreeView), m_treeView(new DebuggerToolTipTreeView),
m_defaultModel(new QStandardItemModel(this)) m_defaultModel(new QStandardItemModel(this))
{ {
...@@ -836,11 +835,7 @@ void DebuggerToolTipWidget::saveSessionData(QXmlStreamWriter &w) const ...@@ -836,11 +835,7 @@ void DebuggerToolTipWidget::saveSessionData(QXmlStreamWriter &w) const
/*! /*!
\class Debugger::Internal::TooltipFilterModel \class Debugger::Internal::TooltipFilterModel
\brief Model for tooltips filtering a local variable using the locals or tooltip model, \brief Model for tooltips filtering an item on the watchhandler matching its tree on the iname.
matching on the name.
Expressions/names can either be flat ('foo' will match at the root level)
or nested ('this.m_foo' will match 'this' at root level and 'm_foo' at level 1).
In addition, suppress the model's tooltip data to avoid a tooltip on a tooltip. In addition, suppress the model's tooltip data to avoid a tooltip on a tooltip.
*/ */
...@@ -848,9 +843,8 @@ void DebuggerToolTipWidget::saveSessionData(QXmlStreamWriter &w) const ...@@ -848,9 +843,8 @@ void DebuggerToolTipWidget::saveSessionData(QXmlStreamWriter &w) const
class TooltipFilterModel : public QSortFilterProxyModel class TooltipFilterModel : public QSortFilterProxyModel
{ {
public: public:
TooltipFilterModel(QAbstractItemModel *model, const QString &exp, int debuggerModel) : TooltipFilterModel(QAbstractItemModel *model, const QByteArray &iname)
m_expressions(exp.split(QLatin1Char('.'))), : m_iname(iname)
m_debuggerModel(debuggerModel)
{ {
setSourceModel(model); setSourceModel(model);
} }
...@@ -864,27 +858,21 @@ public: ...@@ -864,27 +858,21 @@ public:
bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const; bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const;
private: private:
const QStringList m_expressions; const QByteArray m_iname;
int m_debuggerModel;
}; };
static bool isSubIname(const QByteArray &haystack, const QByteArray &needle)
{
return haystack.size() > needle.size()
&& haystack.startsWith(needle)
&& haystack.at(needle.size()) == '.';
}
bool TooltipFilterModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const bool TooltipFilterModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const
{ {
const QModelIndex nameIndex = sourceModel()->index(sourceRow, 0, sourceParent); const QModelIndex nameIndex = sourceModel()->index(sourceRow, 0, sourceParent);
QByteArray iname = nameIndex.data(LocalsINameRole).toByteArray(); const QByteArray iname = nameIndex.data(LocalsINameRole).toByteArray();
if (m_debuggerModel == LocalsType && !iname.startsWith("local")) return iname == m_iname || isSubIname(iname, m_iname) || isSubIname(m_iname, iname);
return false;
if (m_debuggerModel == TooltipType && !iname.startsWith("tooltip"))
return false;
// Match on expression for top level, else pass through.
const int depth = iname.count('.');
if (depth == 0)
return true;
if (depth > m_expressions.size())
return true;
const QString name = nameIndex.data().toString();
//const QString exp = nameIndex.data(LocalsExpressionRole).toString();
return name == m_expressions.at(depth - 1);
} }
/*! /*!
...@@ -991,7 +979,7 @@ void DebuggerToolTipWidget::doAcquireEngine(DebuggerEngine *engine) ...@@ -991,7 +979,7 @@ void DebuggerToolTipWidget::doAcquireEngine(DebuggerEngine *engine)
// Create a filter model on the debugger's model and switch to it. // Create a filter model on the debugger's model and switch to it.
QAbstractItemModel *model = engine->watchModel(); QAbstractItemModel *model = engine->watchModel();
TooltipFilterModel *filterModel = TooltipFilterModel *filterModel =
new TooltipFilterModel(model, m_expression, m_debuggerModel); new TooltipFilterModel(model, m_iname);
swapModel(filterModel); swapModel(filterModel);
} }
...@@ -1000,7 +988,7 @@ QAbstractItemModel *DebuggerToolTipWidget::swapModel(QAbstractItemModel *newMode ...@@ -1000,7 +988,7 @@ QAbstractItemModel *DebuggerToolTipWidget::swapModel(QAbstractItemModel *newMode
QAbstractItemModel *oldModel = m_treeView->swapModel(newModel); QAbstractItemModel *oldModel = m_treeView->swapModel(newModel);
// When looking at some 'this.m_foo.x', expand all items // When looking at some 'this.m_foo.x', expand all items
if (newModel) { if (newModel) {
if (const int level = m_expression.count(QLatin1Char('.')) + 1) { if (const int level = m_iname.count('.')) {
QModelIndex index = newModel->index(0, 0); QModelIndex index = newModel->index(0, 0);
for (int i = 0; i < level && index.isValid(); i++, index = index.child(0, 0)) for (int i = 0; i < level && index.isValid(); i++, index = index.child(0, 0))
m_treeView->setExpanded(index, true); m_treeView->setExpanded(index, true);
...@@ -1062,8 +1050,9 @@ void DebuggerToolTipWidget::doSaveSessionData(QXmlStreamWriter &w) const ...@@ -1062,8 +1050,9 @@ void DebuggerToolTipWidget::doSaveSessionData(QXmlStreamWriter &w) const
{ {
w.writeStartElement(QLatin1String(treeElementC)); w.writeStartElement(QLatin1String(treeElementC));
QXmlStreamAttributes attributes; QXmlStreamAttributes attributes;
attributes.append(QLatin1String(treeModelAttributeC), QString::number(m_debuggerModel)); if (!m_expression.isEmpty())
attributes.append(QLatin1String(treeExpressionAttributeC), m_expression); attributes.append(QLatin1String(treeExpressionAttributeC), m_expression);
attributes.append(QLatin1String(treeInameAttributeC), QLatin1String(m_iname));
w.writeAttributes(attributes); w.writeAttributes(attributes);
if (QAbstractItemModel *model = m_treeView->model()) { if (QAbstractItemModel *model = m_treeView->model()) {
XmlWriterTreeModelVisitor v(model, w); XmlWriterTreeModelVisitor v(model, w);
...@@ -1078,11 +1067,11 @@ void DebuggerToolTipWidget::doLoadSessionData(QXmlStreamReader &r) ...@@ -1078,11 +1067,11 @@ void DebuggerToolTipWidget::doLoadSessionData(QXmlStreamReader &r)
return; return;
// Restore data to default model and show that. // Restore data to default model and show that.
const QXmlStreamAttributes attributes = r.attributes(); const QXmlStreamAttributes attributes = r.attributes();
m_debuggerModel = attributes.value(QLatin1String(treeModelAttributeC)).toString().toInt(); m_iname = attributes.value(QLatin1String(treeInameAttributeC)).toString().toLatin1();
m_expression = attributes.value(QLatin1String(treeExpressionAttributeC)).toString(); m_expression = attributes.value(QLatin1String(treeExpressionAttributeC)).toString();
if (debugToolTips) if (debugToolTips)
qDebug() << "DebuggerTreeViewToolTipWidget::doLoadSessionData() " << m_debuggerModel << m_expression; qDebug() << "DebuggerTreeViewToolTipWidget::doLoadSessionData() " << m_debuggerModel << m_iname;
setObjectName(QLatin1String("DebuggerTreeViewToolTipWidget: ") + m_expression); setObjectName(QLatin1String("DebuggerTreeViewToolTipWidget: ") + QLatin1String(m_iname));
restoreTreeModel(r, m_defaultModel); restoreTreeModel(r, m_defaultModel);
r.readNext(); // Skip </tree> r.readNext(); // Skip </tree>
m_treeView->swapModel(m_defaultModel); m_treeView->swapModel(m_defaultModel);
...@@ -1480,14 +1469,16 @@ void DebuggerToolTipManager::slotTooltipOverrideRequested(ITextEditor *editor, ...@@ -1480,14 +1469,16 @@ void DebuggerToolTipManager::slotTooltipOverrideRequested(ITextEditor *editor,
qDebug() << "<slotTooltipOverrideRequested() " << currentEngine << *handled; qDebug() << "<slotTooltipOverrideRequested() " << currentEngine << *handled;
} }
QStringList DebuggerToolTipManager::treeWidgetExpressions(const QString &fileName,
const QString &engineType, DebuggerToolTipManager::ExpressionInamePairs
const QString &function) const DebuggerToolTipManager::treeWidgetExpressions(const QString &fileName,
const QString &engineType,
const QString &function) const
{ {
QStringList rc; ExpressionInamePairs rc;
foreach (const QPointer<DebuggerToolTipWidget> &tw, m_tooltips) { foreach (const QPointer<DebuggerToolTipWidget> &tw, m_tooltips) {
if (!tw.isNull() && tw->matches(fileName, engineType, function)) if (!tw.isNull() && tw->matches(fileName, engineType, function))
rc.push_back(tw->expression()); rc.push_back(ExpressionInamePair(tw->expression(), tw->iname()));
} }
if (debugToolTips) if (debugToolTips)
qDebug() << "DebuggerToolTipManager::treeWidgetExpressions" qDebug() << "DebuggerToolTipManager::treeWidgetExpressions"
......
...@@ -119,8 +119,9 @@ public: ...@@ -119,8 +119,9 @@ public:
static DebuggerToolTipWidget *loadSessionData(QXmlStreamReader &r); static DebuggerToolTipWidget *loadSessionData(QXmlStreamReader &r);
int debuggerModel() const { return m_debuggerModel; } QByteArray iname() const { return m_iname; }
void setDebuggerModel(int m) { m_debuggerModel = m; } void setIname(const QByteArray &e) { m_iname = e; }
QString expression() const { return m_expression; } QString expression() const { return m_expression; }
void setExpression(const QString &e) { m_expression = e; } void setExpression(const QString &e) { m_expression = e; }
...@@ -166,6 +167,7 @@ private: ...@@ -166,6 +167,7 @@ private:
int m_debuggerModel; int m_debuggerModel;
QString m_expression; QString m_expression;
QByteArray m_iname;
DebuggerToolTipTreeView *m_treeView; DebuggerToolTipTreeView *m_treeView;
QStandardItemModel *m_defaultModel; QStandardItemModel *m_defaultModel;
...@@ -196,6 +198,9 @@ class DebuggerToolTipManager : public QObject ...@@ -196,6 +198,9 @@ class DebuggerToolTipManager : public QObject
Q_OBJECT Q_OBJECT
public: public:
typedef QPair<QString, QByteArray> ExpressionInamePair;
typedef QList<ExpressionInamePair> ExpressionInamePairs;
explicit DebuggerToolTipManager(QObject *parent = 0); explicit DebuggerToolTipManager(QObject *parent = 0);
virtual ~DebuggerToolTipManager(); virtual ~DebuggerToolTipManager();
...@@ -204,9 +209,9 @@ public: ...@@ -204,9 +209,9 @@ public:
bool hasToolTips() const { return !m_tooltips.isEmpty(); } bool hasToolTips() const { return !m_tooltips.isEmpty(); }
// Collect all expressions of DebuggerTreeViewToolTipWidget // Collect all expressions of DebuggerTreeViewToolTipWidget
QStringList treeWidgetExpressions(const QString &fileName, ExpressionInamePairs treeWidgetExpressions(const QString &fileName,
const QString &engineType = QString(), const QString &engineType = QString(),
const QString &function= QString()) const; const QString &function= QString()) const;
void showToolTip(const QPoint &p, Core::IEditor *editor, DebuggerToolTipWidget *); void showToolTip(const QPoint &p, Core::IEditor *editor, DebuggerToolTipWidget *);
......
...@@ -117,6 +117,7 @@ public: ...@@ -117,6 +117,7 @@ public:
QPoint mousePosition; QPoint mousePosition;
QString expression; QString expression;
QByteArray iname;
Core::IEditor *editor; Core::IEditor *editor;
}; };
...@@ -3844,22 +3845,19 @@ void GdbEngine::showToolTip() ...@@ -3844,22 +3845,19 @@ void GdbEngine::showToolTip()
if (m_toolTipContext.isNull()) if (m_toolTipContext.isNull())
return; return;
const QString expression = m_toolTipContext->expression; const QString expression = m_toolTipContext->expression;
const QByteArray iname = tooltipIName(m_toolTipContext->expression);
if (DebuggerToolTipManager::debug()) if (DebuggerToolTipManager::debug())
qDebug() << "GdbEngine::showToolTip " << expression << iname << (*m_toolTipContext); qDebug() << "GdbEngine::showToolTip " << expression << m_toolTipContext->iname << (*m_toolTipContext);
if (!debuggerCore()->boolSetting(UseToolTipsInMainEditor)) { if (m_toolTipContext->iname.startsWith("tooltip")
watchHandler()->removeData(iname); && (!debuggerCore()->boolSetting(UseToolTipsInMainEditor)
|| !watchHandler()->isValidToolTip(m_toolTipContext->iname))) {
watchHandler()->removeData(m_toolTipContext->iname);
return; return;
} }
if (!watchHandler()->isValidToolTip(iname)) {
watchHandler()->removeData(iname);
return;
}
DebuggerToolTipWidget *tw = new DebuggerToolTipWidget; DebuggerToolTipWidget *tw = new DebuggerToolTipWidget;
tw->setDebuggerModel(TooltipType); tw->setIname(m_toolTipContext->iname);
tw->setExpression(expression); tw->setExpression(m_toolTipContext->expression);
tw->setContext(*m_toolTipContext); tw->setContext(*m_toolTipContext);
tw->acquireEngine(this); tw->acquireEngine(this);
DebuggerToolTipManager::instance()->showToolTip(m_toolTipContext->mousePosition, DebuggerToolTipManager::instance()->showToolTip(m_toolTipContext->mousePosition,
...@@ -3890,12 +3888,22 @@ bool GdbEngine::setToolTipExpression(const QPoint &mousePos, ...@@ -3890,12 +3888,22 @@ bool GdbEngine::setToolTipExpression(const QPoint &mousePos,
DebuggerToolTipContext context = contextIn; DebuggerToolTipContext context = contextIn;
int line, column; int line, column;
const QString exp = fixCppExpression(cppExpressionAt(editor, context.position, &line, &column, &context.function)); QString exp = fixCppExpression(cppExpressionAt(editor, context.position, &line, &column, &context.function));
if (DebuggerToolTipManager::debug())
qDebug() << "GdbEngine::setToolTipExpression1 " << exp << context;
if (exp.isEmpty()) if (exp.isEmpty())
return false; return false;
// Prefer a filter on an existing local variable if it can be found.
QByteArray iname;
if (const WatchData *localVariable = watchHandler()->findCppLocalVariable(exp)) {
exp = QLatin1String(localVariable->exp);
iname = localVariable->iname;
} else {
iname = tooltipIName(exp);
}
if (DebuggerToolTipManager::debug())
qDebug() << "GdbEngine::setToolTipExpression1 " << exp << iname << context;
// Same expression: Display synchronously.
if (!m_toolTipContext.isNull() && m_toolTipContext->expression == exp) { if (!m_toolTipContext.isNull() && m_toolTipContext->expression == exp) {
showToolTip(); showToolTip();
return true; return true;
...@@ -3904,7 +3912,14 @@ bool GdbEngine::setToolTipExpression(const QPoint &mousePos, ...@@ -3904,7 +3912,14 @@ bool GdbEngine::setToolTipExpression(const QPoint &mousePos,
m_toolTipContext.reset(new GdbToolTipContext(context)); m_toolTipContext.reset(new GdbToolTipContext(context));
m_toolTipContext->mousePosition = mousePos; m_toolTipContext->mousePosition = mousePos;
m_toolTipContext->expression = exp; m_toolTipContext->expression = exp;
m_toolTipContext->iname = iname;
m_toolTipContext->editor = editor; m_toolTipContext->editor = editor;
// Local variable: Display synchronously.
if (iname.startsWith("local")) {
showToolTip();
return true;
}
if (DebuggerToolTipManager::debug()) if (DebuggerToolTipManager::debug())
qDebug() << "GdbEngine::setToolTipExpression2 " << exp << (*m_toolTipContext); qDebug() << "GdbEngine::setToolTipExpression2 " << exp << (*m_toolTipContext);
...@@ -3912,13 +3927,13 @@ bool GdbEngine::setToolTipExpression(const QPoint &mousePos, ...@@ -3912,13 +3927,13 @@ bool GdbEngine::setToolTipExpression(const QPoint &mousePos,
UpdateParameters params; UpdateParameters params;
params.tryPartial = true; params.tryPartial = true;
params.tooltipOnly = true; params.tooltipOnly = true;
params.varList = tooltipIName(exp); params.varList = iname;
updateLocalsPython(params); updateLocalsPython(params);
} else { } else {
WatchData toolTip; WatchData toolTip;
toolTip.exp = exp.toLatin1(); toolTip.exp = exp.toLatin1();
toolTip.name = exp; toolTip.name = exp;
toolTip.iname = tooltipIName(exp); toolTip.iname = iname;
watchHandler()->insertData(toolTip); watchHandler()->insertData(toolTip);
} }
return true; return true;
......
...@@ -64,17 +64,35 @@ void GdbEngine::updateLocalsPython(const UpdateParameters &params) ...@@ -64,17 +64,35 @@ void GdbEngine::updateLocalsPython(const UpdateParameters &params)
const QString fileName = stackHandler()->currentFrame().file; const QString fileName = stackHandler()->currentFrame().file;
const QString function = stackHandler()->currentFrame().function; const QString function = stackHandler()->currentFrame().function;
if (!fileName.isEmpty()) { if (!fileName.isEmpty()) {
QStringList expressions = DebuggerToolTipManager::instance() typedef DebuggerToolTipManager::ExpressionInamePair ExpressionInamePair;
typedef DebuggerToolTipManager::ExpressionInamePairs ExpressionInamePairs;
// Re-create tooltip items that are not filters on existing local variables in
// the tooltip model.
ExpressionInamePairs toolTips = DebuggerToolTipManager::instance()
->treeWidgetExpressions(fileName, objectName(), function); ->treeWidgetExpressions(fileName, objectName(), function);
const QString currentExpression = tooltipExpression(); const QString currentExpression = tooltipExpression();
if (!currentExpression.isEmpty() && !expressions.contains(currentExpression)) if (!currentExpression.isEmpty()) {
expressions.push_back(currentExpression); int currentIndex = -1;
foreach (const QString &te, expressions) { for (int i = 0; i < toolTips.size(); ++i) {
if (!watchers.isEmpty()) if (toolTips.at(i).first == currentExpression) {
watchers += "##"; currentIndex = i;
watchers += te.toLatin1(); break;
watchers += '#'; }
watchers += tooltipIName(te); }
if (currentIndex < 0)
toolTips.push_back(ExpressionInamePair(currentExpression, tooltipIName(currentExpression)));
}
foreach (const ExpressionInamePair &p, toolTips) {
if (p.second.startsWith("tooltip")) {
if (!watchers.isEmpty())
watchers += "##";
watchers += p.first.toLatin1();
watchers += '#';
watchers += p.second;
}
} }
} }
......
...@@ -1550,7 +1550,7 @@ QByteArray WatchHandler::watcherName(const QByteArray &exp) ...@@ -1550,7 +1550,7 @@ QByteArray WatchHandler::watcherName(const QByteArray &exp)
return "watch." + QByteArray::number(theWatcherNames[exp]); return "watch." + QByteArray::number(theWatcherNames[exp]);
} }
void WatchHandler::watchExpression(const QString &exp) void WatchHandler::watchExpression(const QString &exp, const QString &name)
{ {
QTC_ASSERT(m_engine, return); QTC_ASSERT(m_engine, return);
// Do not insert the same entry more then once. // Do not insert the same entry more then once.
...@@ -1560,7 +1560,7 @@ void WatchHandler::watchExpression(const QString &exp) ...@@ -1560,7 +1560,7 @@ void WatchHandler::watchExpression(const QString &exp)
// FIXME: 'exp' can contain illegal characters // FIXME: 'exp' can contain illegal characters
WatchData data; WatchData data;
data.exp = exp.toLatin1(); data.exp = exp.toLatin1();
data.name = exp; data.name = name.isEmpty() ? exp : name;
theWatcherNames[data.exp] = m_watcherCounter++; theWatcherNames[data.exp] = m_watcherCounter++;
saveWatchers(); saveWatchers();