debugger: rework WatchModel

It's one model for all locals, watch, return, tooltip and inspector
data. This allows more streamlined code paths and better isolation
of the model data from the WatchHandler. WatchItems are now registered
in a hash indexed by iname, so inames can be used as the primary
handle to watch data in the WatchHandler interface.

Change-Id: Idac0a808b5d785307496d1de4198a1f2e9ce3880
Reviewed-by: Aurindam Jana <aurindam.jana@nokia.com>
This commit is contained in:
hjk
2012-05-18 02:28:41 +02:00
parent c14c1248ed
commit e11a3a7697
27 changed files with 909 additions and 948 deletions

View File

@@ -2397,6 +2397,14 @@ def qdump__Debugger__Internal__GdbMi(d, value):
d.putByteArrayValue(value["m_data"]) d.putByteArrayValue(value["m_data"])
d.putPlainChildren(value) d.putPlainChildren(value)
def qdump__Debugger__Internal__WatchData(d, value):
d.putByteArrayValue(value["iname"])
d.putPlainChildren(value)
def qdump__Debugger__Internal__WatchItem(d, value):
d.putByteArrayValue(value["iname"])
d.putPlainChildren(value)
def qdump__CPlusPlus__ByteArrayRef(d, value): def qdump__CPlusPlus__ByteArrayRef(d, value):
d.putValue(encodeCharArray(value["m_start"], 100, value["m_length"]), d.putValue(encodeCharArray(value["m_start"], 100, value["m_length"]),
Hex2EncodedLatin1) Hex2EncodedLatin1)

View File

@@ -98,6 +98,12 @@ enum { debugSourceMapping = 0 };
enum { debugWatches = 0 }; enum { debugWatches = 0 };
enum { debugBreakpoints = 0 }; enum { debugBreakpoints = 0 };
enum HandleLocalsFlags
{
PartialLocalsUpdate = 0x1,
LocalsUpdateForNewFrame = 0x2
};
#if 0 #if 0
# define STATE_DEBUG(state, func, line, notifyFunc) qDebug("%s in %s at %s:%d", notifyFunc, stateName(state), func, line); # define STATE_DEBUG(state, func, line, notifyFunc) qDebug("%s in %s at %s:%d", notifyFunc, stateName(state), func, line);
#else #else
@@ -550,18 +556,16 @@ bool CdbEngine::setToolTipExpression(const QPoint &mousePos,
// Can this be found as a local variable? // Can this be found as a local variable?
const QByteArray localsPrefix(localsPrefixC); const QByteArray localsPrefix(localsPrefixC);
QByteArray iname = localsPrefix + exp.toAscii(); QByteArray iname = localsPrefix + exp.toAscii();
QModelIndex index = watchHandler()->itemIndex(iname); if (!watchHandler()->hasItem(iname)) {
if (!index.isValid()) {
// Nope, try a 'local.this.m_foo'. // Nope, try a 'local.this.m_foo'.
exp.prepend(QLatin1String("this.")); exp.prepend(QLatin1String("this."));
iname.insert(localsPrefix.size(), "this."); iname.insert(localsPrefix.size(), "this.");
index = watchHandler()->itemIndex(iname); if (!watchHandler()->hasItem(iname))
if (!index.isValid())
return false; return false;
} }
DebuggerToolTipWidget *tw = new DebuggerToolTipWidget; DebuggerToolTipWidget *tw = new DebuggerToolTipWidget;
tw->setContext(context); tw->setContext(context);
tw->setDebuggerModel(LocalsWatch); tw->setDebuggerModel(LocalsType);
tw->setExpression(exp); tw->setExpression(exp);
tw->acquireEngine(this); tw->acquireEngine(this);
DebuggerToolTipManager::instance()->showToolTip(mousePos, editor, tw); DebuggerToolTipManager::instance()->showToolTip(mousePos, editor, tw);
@@ -1048,7 +1052,7 @@ void CdbEngine::handleAddWatch(const CdbExtensionCommandPtr &reply)
updateLocalVariable(item.iname); updateLocalVariable(item.iname);
} else { } else {
item.setError(tr("Unable to add expression")); item.setError(tr("Unable to add expression"));
watchHandler()->insertData(item); watchHandler()->insertIncompleteData(item);
showMessage(QString::fromLatin1("Unable to add watch item '%1'/'%2': %3"). showMessage(QString::fromLatin1("Unable to add watch item '%1'/'%2': %3").
arg(QString::fromLatin1(item.iname), QString::fromLatin1(item.exp), arg(QString::fromLatin1(item.iname), QString::fromLatin1(item.exp),
QString::fromLocal8Bit(reply->errorMessage)), LogError); QString::fromLocal8Bit(reply->errorMessage)), LogError);
@@ -1086,7 +1090,10 @@ void CdbEngine::updateLocalVariable(const QByteArray &iname)
str << blankSeparator << stackFrame; str << blankSeparator << stackFrame;
} }
str << blankSeparator << iname; str << blankSeparator << iname;
postExtensionCommand(isWatch ? "watches" : "locals", localsArguments, 0, &CdbEngine::handleLocals); postExtensionCommand(isWatch ? "watches" : "locals",
localsArguments, 0,
&CdbEngine::handleLocals,
0, QVariant(int(PartialLocalsUpdate)));
} }
bool CdbEngine::hasCapability(unsigned cap) const bool CdbEngine::hasCapability(unsigned cap) const
@@ -1465,8 +1472,7 @@ void CdbEngine::activateFrame(int index)
stackHandler()->setCurrentIndex(index); stackHandler()->setCurrentIndex(index);
const bool showAssembler = !frames.at(index).isUsable(); const bool showAssembler = !frames.at(index).isUsable();
if (showAssembler) { // Assembly code: Clean out model and force instruction mode. if (showAssembler) { // Assembly code: Clean out model and force instruction mode.
watchHandler()->beginCycle(); watchHandler()->removeAllData();
watchHandler()->endCycle();
QAction *assemblerAction = theAssemblerAction(); QAction *assemblerAction = theAssemblerAction();
if (assemblerAction->isChecked()) { if (assemblerAction->isChecked()) {
gotoLocation(frame); gotoLocation(frame);
@@ -1485,14 +1491,12 @@ void CdbEngine::updateLocals(bool forNewStackFrame)
const int frameIndex = stackHandler()->currentIndex(); const int frameIndex = stackHandler()->currentIndex();
if (frameIndex < 0) { if (frameIndex < 0) {
watchHandler()->beginCycle(); watchHandler()->removeAllData();
watchHandler()->endCycle();
return; return;
} }
const StackFrame frame = stackHandler()->currentFrame(); const StackFrame frame = stackHandler()->currentFrame();
if (!frame.isUsable()) { if (!frame.isUsable()) {
watchHandler()->beginCycle(); watchHandler()->removeAllData();
watchHandler()->endCycle();
return; return;
} }
/* Watchers: Forcibly discard old symbol group as switching from /* Watchers: Forcibly discard old symbol group as switching from
@@ -1542,9 +1546,11 @@ void CdbEngine::updateLocals(bool forNewStackFrame)
} }
// Required arguments: frame // Required arguments: frame
const int flags = forNewStackFrame ? LocalsUpdateForNewFrame : 0;
str << blankSeparator << frameIndex; str << blankSeparator << frameIndex;
watchHandler()->beginCycle(); postExtensionCommand("locals", arguments, 0,
postExtensionCommand("locals", arguments, 0, &CdbEngine::handleLocals, 0, QVariant(forNewStackFrame)); &CdbEngine::handleLocals, 0,
QVariant(flags));
} }
void CdbEngine::selectThread(int index) void CdbEngine::selectThread(int index)
@@ -1925,6 +1931,9 @@ void CdbEngine::handleRegisters(const CdbExtensionCommandPtr &reply)
void CdbEngine::handleLocals(const CdbExtensionCommandPtr &reply) void CdbEngine::handleLocals(const CdbExtensionCommandPtr &reply)
{ {
const int flags = reply->cookie.toInt();
if (!(flags & PartialLocalsUpdate))
watchHandler()->removeAllData();
if (reply->success) { if (reply->success) {
QList<WatchData> watchData; QList<WatchData> watchData;
GdbMi root; GdbMi root;
@@ -1940,16 +1949,14 @@ 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);
} }
watchHandler()->insertBulkData(watchData); watchHandler()->insertData(watchData);
watchHandler()->endCycle();
if (debugLocals) { if (debugLocals) {
QDebug nsp = qDebug().nospace(); QDebug nsp = qDebug().nospace();
nsp << "Obtained " << watchData.size() << " items:\n"; nsp << "Obtained " << watchData.size() << " items:\n";
foreach (const WatchData &wd, watchData) foreach (const WatchData &wd, watchData)
nsp << wd.toString() <<'\n'; nsp << wd.toString() <<'\n';
} }
const bool forNewStackFrame = reply->cookie.toBool(); if (flags & LocalsUpdateForNewFrame)
if (forNewStackFrame)
emit stackFrameCompleted(); emit stackFrameCompleted();
} else { } else {
showMessage(QString::fromLatin1(reply->errorMessage), LogWarning); showMessage(QString::fromLatin1(reply->errorMessage), LogWarning);

View File

@@ -85,7 +85,7 @@ public:
virtual QVariant configValue(const QString &name) const = 0; virtual QVariant configValue(const QString &name) const = 0;
virtual void setConfigValue(const QString &name, const QVariant &value) = 0; virtual void setConfigValue(const QString &name, const QVariant &value) = 0;
virtual void updateState(DebuggerEngine *engine) = 0; virtual void updateState(DebuggerEngine *engine) = 0;
virtual void updateWatchersWindow() = 0; virtual void updateWatchersWindow(bool showWatch, bool showReturn) = 0;
virtual void showQtDumperLibraryWarning(const QString &details) = 0; virtual void showQtDumperLibraryWarning(const QString &details) = 0;
virtual QIcon locationMarkIcon() const = 0; virtual QIcon locationMarkIcon() const = 0;
virtual const CPlusPlus::Snapshot &cppCodeModelSnapshot() const = 0; virtual const CPlusPlus::Snapshot &cppCodeModelSnapshot() const = 0;

View File

@@ -491,42 +491,32 @@ QAbstractItemModel *DebuggerEngine::threadsModel() const
QAbstractItemModel *DebuggerEngine::localsModel() const QAbstractItemModel *DebuggerEngine::localsModel() const
{ {
QAbstractItemModel *model = watchHandler()->model(LocalsWatch); return watchHandler()->model();
if (model->objectName().isEmpty()) // Make debugging easier.
model->setObjectName(objectName() + QLatin1String("LocalsModel"));
return model;
} }
QAbstractItemModel *DebuggerEngine::watchersModel() const QAbstractItemModel *DebuggerEngine::watchersModel() const
{ {
QAbstractItemModel *model = watchHandler()->model(WatchersWatch); return watchHandler()->model();
if (model->objectName().isEmpty()) // Make debugging easier.
model->setObjectName(objectName() + QLatin1String("WatchersModel"));
return model;
} }
QAbstractItemModel *DebuggerEngine::returnModel() const QAbstractItemModel *DebuggerEngine::returnModel() const
{ {
QAbstractItemModel *model = watchHandler()->model(ReturnWatch); return watchHandler()->model();
if (model->objectName().isEmpty()) // Make debugging easier.
model->setObjectName(objectName() + QLatin1String("ReturnModel"));
return model;
} }
QAbstractItemModel *DebuggerEngine::inspectorModel() const QAbstractItemModel *DebuggerEngine::inspectorModel() const
{ {
QAbstractItemModel *model = watchHandler()->model(InspectWatch); return watchHandler()->model();
if (model->objectName().isEmpty()) // Make debugging easier.
model->setObjectName(objectName() + QLatin1String("InspectorModel"));
return model;
} }
QAbstractItemModel *DebuggerEngine::toolTipsModel() const QAbstractItemModel *DebuggerEngine::toolTipsModel() const
{ {
QAbstractItemModel *model = watchHandler()->model(TooltipsWatch); return watchHandler()->model();
if (model->objectName().isEmpty()) // Make debugging easier. }
model->setObjectName(objectName() + QLatin1String("TooltipsModel"));
return model; QAbstractItemModel *DebuggerEngine::watchModel() const
{
return watchHandler()->model();
} }
QAbstractItemModel *DebuggerEngine::sourceFilesModel() const QAbstractItemModel *DebuggerEngine::sourceFilesModel() const

View File

@@ -229,11 +229,12 @@ public:
virtual QAbstractItemModel *registerModel() const; virtual QAbstractItemModel *registerModel() const;
virtual QAbstractItemModel *stackModel() const; virtual QAbstractItemModel *stackModel() const;
virtual QAbstractItemModel *threadsModel() const; virtual QAbstractItemModel *threadsModel() const;
virtual QAbstractItemModel *localsModel() const; virtual QAbstractItemModel *localsModel() const; // Deprecated, FIXME: use watchModel
virtual QAbstractItemModel *watchersModel() const; virtual QAbstractItemModel *watchersModel() const; // Deprecated, FIXME: use watchModel
virtual QAbstractItemModel *returnModel() const; virtual QAbstractItemModel *returnModel() const; // Deprecated, FIXME: use watchModel
virtual QAbstractItemModel *inspectorModel() const; virtual QAbstractItemModel *inspectorModel() const; // Deprecated, FIXME: use watchModel
virtual QAbstractItemModel *toolTipsModel() const; virtual QAbstractItemModel *toolTipsModel() const; // Deprecated, FIXME: use watchModel
virtual QAbstractItemModel *watchModel() const;
virtual QAbstractItemModel *sourceFilesModel() const; virtual QAbstractItemModel *sourceFilesModel() const;
virtual QAbstractItemModel *qtMessageLogModel() const; virtual QAbstractItemModel *qtMessageLogModel() const;

View File

@@ -815,7 +815,7 @@ public slots:
void fontSettingsChanged(const TextEditor::FontSettings &settings); void fontSettingsChanged(const TextEditor::FontSettings &settings);
void updateState(DebuggerEngine *engine); void updateState(DebuggerEngine *engine);
void updateWatchersWindow(); void updateWatchersWindow(bool showWatch, bool showReturn);
void onCurrentProjectChanged(ProjectExplorer::Project *project); void onCurrentProjectChanged(ProjectExplorer::Project *project);
void sessionLoaded(); void sessionLoaded();
@@ -2238,12 +2238,10 @@ void DebuggerPluginPrivate::setInitialState()
m_qtMessageLogWindow->setEnabled(true); m_qtMessageLogWindow->setEnabled(true);
} }
void DebuggerPluginPrivate::updateWatchersWindow() void DebuggerPluginPrivate::updateWatchersWindow(bool showWatch, bool showReturn)
{ {
m_watchersWindow->setVisible( m_watchersWindow->setVisible(showWatch);
m_watchersWindow->model()->rowCount(QModelIndex()) > 0); m_returnWindow->setVisible(showReturn);
m_returnWindow->setVisible(
m_returnWindow->model()->rowCount(QModelIndex()) > 0);
} }
void DebuggerPluginPrivate::updateState(DebuggerEngine *engine) void DebuggerPluginPrivate::updateState(DebuggerEngine *engine)
@@ -2254,8 +2252,7 @@ void DebuggerPluginPrivate::updateState(DebuggerEngine *engine)
QTC_ASSERT(!engine->isSlaveEngine(), return); QTC_ASSERT(!engine->isSlaveEngine(), return);
m_threadBox->setCurrentIndex(engine->threadsHandler()->currentThread()); m_threadBox->setCurrentIndex(engine->threadsHandler()->currentThread());
engine->watchHandler()->updateWatchersWindow();
updateWatchersWindow();
const DebuggerState state = engine->state(); const DebuggerState state = engine->state();
//showMessage(QString("PLUGIN SET STATE: ") //showMessage(QString("PLUGIN SET STATE: ")

View File

@@ -230,7 +230,6 @@ QDataStream &operator<<(QDataStream &stream, const WatchData &wd)
stream << wd.address; stream << wd.address;
stream << wd.size; stream << wd.size;
stream << wd.hasChildren; stream << wd.hasChildren;
stream << wd.generation;
stream << wd.valueEnabled; stream << wd.valueEnabled;
stream << wd.valueEditable; stream << wd.valueEditable;
stream << wd.error; stream << wd.error;
@@ -256,7 +255,6 @@ QDataStream &operator>>(QDataStream &stream, WatchData &wd)
stream >> wd.address; stream >> wd.address;
stream >> wd.size; stream >> wd.size;
stream >> wd.hasChildren; stream >> wd.hasChildren;
stream >> wd.generation;
stream >> wd.valueEnabled; stream >> wd.valueEnabled;
stream >> wd.valueEditable; stream >> wd.valueEditable;
stream >> wd.error; stream >> wd.error;

View File

@@ -31,6 +31,7 @@
**************************************************************************/ **************************************************************************/
#include "debuggertooltipmanager.h" #include "debuggertooltipmanager.h"
#include "debuggerinternalconstants.h"
#include "watchutils.h" #include "watchutils.h"
#include "debuggerengine.h" #include "debuggerengine.h"
#include "debuggeractions.h" #include "debuggeractions.h"
@@ -617,7 +618,7 @@ 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(TooltipsWatch), m_debuggerModel(TooltipType),
m_treeView(new DebuggerToolTipTreeView), m_treeView(new DebuggerToolTipTreeView),
m_defaultModel(new QStandardItemModel(this)) m_defaultModel(new QStandardItemModel(this))
{ {
@@ -664,7 +665,7 @@ bool DebuggerToolTipWidget::matches(const QString &fileName,
return function == m_context.function; return function == m_context.function;
} }
void DebuggerToolTipWidget::acquireEngine(Debugger::DebuggerEngine *engine) void DebuggerToolTipWidget::acquireEngine(DebuggerEngine *engine)
{ {
QTC_ASSERT(engine, return); QTC_ASSERT(engine, return);
@@ -836,7 +837,7 @@ void DebuggerToolTipWidget::saveSessionData(QXmlStreamWriter &w) const
} }
/*! /*!
\class Debugger::Internal::DebuggerToolTipExpressionFilterModel \class Debugger::Internal::TooltipFilterModel
\brief Model for tooltips filtering a local variable using the locals or tooltip model, \brief Model for tooltips filtering a local variable using the locals or tooltip model,
matching on the name. matching on the name.
@@ -847,50 +848,46 @@ void DebuggerToolTipWidget::saveSessionData(QXmlStreamWriter &w) const
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.
*/ */
class DebuggerToolTipExpressionFilterModel : public QSortFilterProxyModel class TooltipFilterModel : public QSortFilterProxyModel
{ {
public: public:
explicit DebuggerToolTipExpressionFilterModel(QAbstractItemModel *model, const QString &exp, QObject *parent = 0); TooltipFilterModel(QAbstractItemModel *model, const QString &exp, int debuggerModel) :
virtual bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const; m_expressions(exp.split(QLatin1Char('.'))),
m_debuggerModel(debuggerModel)
virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
private:
const QStringList m_expressions;
};
DebuggerToolTipExpressionFilterModel::DebuggerToolTipExpressionFilterModel(QAbstractItemModel *model,
const QString &exp,
QObject *parent) :
QSortFilterProxyModel(parent),
m_expressions(exp.split(QLatin1Char('.')))
{ {
setSourceModel(model); setSourceModel(model);
} }
QVariant DebuggerToolTipExpressionFilterModel::data(const QModelIndex &index, int role) const QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const
{ {
return role != Qt::ToolTipRole ? return role == Qt::ToolTipRole
QSortFilterProxyModel::data(index, role) : QVariant(); ? QVariant() : QSortFilterProxyModel::data(index, role);
} }
// Return depth of a model index, that is, 0 for root index, 1 for level-1 children, etc. bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const;
static inline int indexDepth(QModelIndex index)
{
int depth = 0;
for ( ; index.isValid() ; index = index.parent())
depth++;
return depth;
}
bool DebuggerToolTipExpressionFilterModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const private:
const QStringList m_expressions;
int m_debuggerModel;
};
bool TooltipFilterModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const
{ {
// Match on expression for top level, else pass through.
const int depth = indexDepth(sourceParent);
if (depth >= m_expressions.size()) // No filters at this level
return true;
const QModelIndex nameIndex = sourceModel()->index(sourceRow, 0, sourceParent); const QModelIndex nameIndex = sourceModel()->index(sourceRow, 0, sourceParent);
return nameIndex.data().toString() == m_expressions.at(depth); QByteArray iname = nameIndex.data(LocalsINameRole).toByteArray();
if (m_debuggerModel == LocalsType && !iname.startsWith("local"))
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);
} }
/*! /*!
@@ -924,6 +921,7 @@ QAbstractItemModel *DebuggerToolTipTreeView::swapModel(QAbstractItemModel *newMo
if (previousModel) if (previousModel)
previousModel->disconnect(SIGNAL(rowsInserted(QModelIndex,int,int)), this); previousModel->disconnect(SIGNAL(rowsInserted(QModelIndex,int,int)), this);
setModel(newModel); setModel(newModel);
//setRootIndex(newModel->index(0, 0));
connect(newModel, SIGNAL(rowsInserted(QModelIndex,int,int)), connect(newModel, SIGNAL(rowsInserted(QModelIndex,int,int)),
this, SLOT(computeSize()), Qt::QueuedConnection); this, SLOT(computeSize()), Qt::QueuedConnection);
computeSize(); computeSize();
@@ -991,24 +989,12 @@ void DebuggerToolTipTreeView::computeSize()
setRootIsDecorated(rootDecorated); setRootIsDecorated(rootDecorated);
} }
void DebuggerToolTipWidget::doAcquireEngine(Debugger::DebuggerEngine *engine) 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 = 0; QAbstractItemModel *model = engine->watchModel();
switch (m_debuggerModel) { TooltipFilterModel *filterModel =
case LocalsWatch: new TooltipFilterModel(model, m_expression, m_debuggerModel);
model = engine->localsModel();
break;
case WatchersWatch:
model = engine->watchersModel();
break;
case TooltipsWatch:
model = engine->toolTipsModel();
break;
}
QTC_ASSERT(model, return);
DebuggerToolTipExpressionFilterModel *filterModel =
new DebuggerToolTipExpressionFilterModel(model, m_expression);
swapModel(filterModel); swapModel(filterModel);
} }
@@ -1311,7 +1297,7 @@ void DebuggerToolTipManager::slotUpdateVisibleToolTips()
} }
} }
void DebuggerToolTipManager::slotDebuggerStateChanged(Debugger::DebuggerState state) void DebuggerToolTipManager::slotDebuggerStateChanged(DebuggerState state)
{ {
const QObject *engine = sender(); const QObject *engine = sender();
QTC_ASSERT(engine, return); QTC_ASSERT(engine, return);
@@ -1319,7 +1305,7 @@ void DebuggerToolTipManager::slotDebuggerStateChanged(Debugger::DebuggerState st
const QString name = engine->objectName(); const QString name = engine->objectName();
if (debugToolTips) if (debugToolTips)
qDebug() << "DebuggerToolTipWidget::debuggerStateChanged" qDebug() << "DebuggerToolTipWidget::debuggerStateChanged"
<< engine << Debugger::DebuggerEngine::stateName(state); << engine << DebuggerEngine::stateName(state);
// Release at earliest possible convenience. // Release at earliest possible convenience.
switch (state) { switch (state) {

View File

@@ -63,8 +63,11 @@ void AbstractPlainGdbAdapter::setupInferior()
QString args = startParameters().processArgs; QString args = startParameters().processArgs;
m_engine->postCommand("-exec-arguments " + toLocalEncoding(args)); m_engine->postCommand("-exec-arguments " + toLocalEncoding(args));
} }
if (m_engine->gdbVersion() > 70000)
m_engine->postCommand("-file-exec-and-symbols \"" + execFilePath() + '"', m_engine->postCommand("-file-exec-and-symbols \"" + execFilePath() + '"',
CB(handleFileExecAndSymbols)); CB(handleFileExecAndSymbols));
else
m_engine->postCommand("file " + execFilePath(), CB(handleFileExecAndSymbols));
} }
void AbstractPlainGdbAdapter::handleFileExecAndSymbols(const GdbResponse &response) void AbstractPlainGdbAdapter::handleFileExecAndSymbols(const GdbResponse &response)

View File

@@ -716,7 +716,7 @@ static bool parseConsoleStream(const GdbResponse &response, GdbMi *contents)
void GdbEngine::updateLocalsClassic() void GdbEngine::updateLocalsClassic()
{ {
PRECONDITION; PRECONDITION;
m_pendingWatchRequests = 0; //m_pendingWatchRequests = 0;
m_pendingBreakpointRequests = 0; m_pendingBreakpointRequests = 0;
m_processedNames.clear(); m_processedNames.clear();
@@ -724,15 +724,14 @@ void GdbEngine::updateLocalsClassic()
qDebug() << "\nRESET PENDING"; qDebug() << "\nRESET PENDING";
//m_toolTipCache.clear(); //m_toolTipCache.clear();
clearToolTip(); clearToolTip();
watchHandler()->beginCycle();
QByteArray level = QByteArray::number(currentFrame()); QByteArray level = QByteArray::number(currentFrame());
// '2' is 'list with type and value' // '2' is 'list with type and value'
QByteArray cmd = "-stack-list-arguments 2 " + level + ' ' + level; QByteArray cmd = "-stack-list-arguments 2 " + level + ' ' + level;
postCommand(cmd, WatchUpdate, postCommand(cmd, Discardable,
CB(handleStackListArgumentsClassic)); CB(handleStackListArgumentsClassic));
// '2' is 'list with type and value' // '2' is 'list with type and value'
postCommand("-stack-list-locals 2", WatchUpdate, postCommand("-stack-list-locals 2", Discardable,
CB(handleStackListLocalsClassic)); // stage 2/2 CB(handleStackListLocalsClassic)); // stage 2/2
} }
@@ -754,9 +753,9 @@ void GdbEngine::runDirectDebuggingHelperClassic(const WatchData &data, bool dump
QVariant var; QVariant var;
var.setValue(data); var.setValue(data);
postCommand(cmd, WatchUpdate, CB(handleDebuggingHelperValue3Classic), var); postCommand(cmd, Discardable, CB(handleDebuggingHelperValue3Classic), var);
showStatusMessage(msgRetrievingWatchData(m_pendingWatchRequests + 1), 10000); showStatusMessage(msgRetrievingWatchData(m_uncompleted.size()), 10000);
} }
void GdbEngine::runDebuggingHelperClassic(const WatchData &data0, bool dumpChildren) void GdbEngine::runDebuggingHelperClassic(const WatchData &data0, bool dumpChildren)
@@ -811,25 +810,25 @@ void GdbEngine::runDebuggingHelperClassic(const WatchData &data0, bool dumpChild
cmd += ',' + ex; cmd += ',' + ex;
cmd += ')'; cmd += ')';
postCommand(cmd, WatchUpdate | NonCriticalResponse); postCommand(cmd, Discardable | NonCriticalResponse);
showStatusMessage(msgRetrievingWatchData(m_pendingWatchRequests + 1), 10000); showStatusMessage(msgRetrievingWatchData(m_uncompleted.size()), 10000);
// retrieve response // retrieve response
postCommand("p (char*)&qDumpOutBuffer", WatchUpdate, postCommand("p (char*)&qDumpOutBuffer", Discardable,
CB(handleDebuggingHelperValue2Classic), qVariantFromValue(data)); CB(handleDebuggingHelperValue2Classic), qVariantFromValue(data));
} }
void GdbEngine::createGdbVariableClassic(const WatchData &data) void GdbEngine::createGdbVariableClassic(const WatchData &data)
{ {
PRECONDITION; PRECONDITION;
postCommand("-var-delete \"" + data.iname + '"', WatchUpdate); postCommand("-var-delete \"" + data.iname + '"', Discardable);
QByteArray exp = data.exp; QByteArray exp = data.exp;
if (exp.isEmpty() && data.address) if (exp.isEmpty() && data.address)
exp = "*(" + gdbQuoteTypes(data.type) + "*)" + data.hexAddress(); exp = "*(" + gdbQuoteTypes(data.type) + "*)" + data.hexAddress();
QVariant val = QVariant::fromValue<WatchData>(data); QVariant val = QVariant::fromValue<WatchData>(data);
postCommand("-var-create \"" + data.iname + "\" * \"" + exp + '"', postCommand("-var-create \"" + data.iname + "\" * \"" + exp + '"',
WatchUpdate, CB(handleVarCreate), val); Discardable, CB(handleVarCreate), val);
} }
void GdbEngine::updateSubItemClassic(const WatchData &data0) void GdbEngine::updateSubItemClassic(const WatchData &data0)
@@ -929,7 +928,7 @@ void GdbEngine::updateSubItemClassic(const WatchData &data0)
if (debugSubItem) if (debugSubItem)
qDebug() << "UPDATE SUBITEM: VALUE"; qDebug() << "UPDATE SUBITEM: VALUE";
QByteArray cmd = "-var-evaluate-expression \"" + data.iname + '"'; QByteArray cmd = "-var-evaluate-expression \"" + data.iname + '"';
postCommand(cmd, WatchUpdate, postCommand(cmd, Discardable,
CB(handleEvaluateExpressionClassic), QVariant::fromValue(data)); CB(handleEvaluateExpressionClassic), QVariant::fromValue(data));
return; return;
} }
@@ -953,7 +952,7 @@ void GdbEngine::updateSubItemClassic(const WatchData &data0)
if (data.isChildrenNeeded()) { if (data.isChildrenNeeded()) {
QTC_ASSERT(!data.variable.isEmpty(), return); // tested above QTC_ASSERT(!data.variable.isEmpty(), return); // tested above
QByteArray cmd = "-var-list-children --all-values \"" + data.variable + '"'; QByteArray cmd = "-var-list-children --all-values \"" + data.variable + '"';
postCommand(cmd, WatchUpdate, postCommand(cmd, Discardable,
CB(handleVarListChildrenClassic), QVariant::fromValue(data)); CB(handleVarListChildrenClassic), QVariant::fromValue(data));
return; return;
} }
@@ -999,7 +998,7 @@ void GdbEngine::handleDebuggingHelperValue2Classic(const GdbResponse &response)
if (m_cookieForToken.contains(response.token - 1)) { if (m_cookieForToken.contains(response.token - 1)) {
m_cookieForToken.remove(response.token - 1); m_cookieForToken.remove(response.token - 1);
showMessage(_("DETECTING LOST COMMAND %1").arg(response.token - 1)); showMessage(_("DETECTING LOST COMMAND %1").arg(response.token - 1));
--m_pendingWatchRequests; // --m_pendingWatchRequests;
data.setError(WatchData::msgNotInScope()); data.setError(WatchData::msgNotInScope());
insertData(data); insertData(data);
return; return;
@@ -1025,7 +1024,7 @@ void GdbEngine::handleDebuggingHelperValue2Classic(const GdbResponse &response)
parseWatchData(watchHandler()->expandedINames(), data, contents, &list); parseWatchData(watchHandler()->expandedINames(), data, contents, &list);
//for (int i = 0; i != list.size(); ++i) //for (int i = 0; i != list.size(); ++i)
// qDebug() << "READ: " << list.at(i).toString(); // qDebug() << "READ: " << list.at(i).toString();
watchHandler()->insertBulkData(list); watchHandler()->insertData(list);
} }
void GdbEngine::handleDebuggingHelperValue3Classic(const GdbResponse &response) void GdbEngine::handleDebuggingHelperValue3Classic(const GdbResponse &response)
@@ -1082,7 +1081,7 @@ void GdbEngine::handleDebuggingHelperValue3Classic(const GdbResponse &response)
QByteArray cmd = "qdumpqstring (" + data1.exp + ')'; QByteArray cmd = "qdumpqstring (" + data1.exp + ')';
QVariant var; QVariant var;
var.setValue(data1); var.setValue(data1);
postCommand(cmd, WatchUpdate, postCommand(cmd, Discardable,
CB(handleDebuggingHelperValue3Classic), var); CB(handleDebuggingHelperValue3Classic), var);
} }
} }
@@ -1101,6 +1100,9 @@ void GdbEngine::handleDebuggingHelperValue3Classic(const GdbResponse &response)
void GdbEngine::tryLoadDebuggingHelpersClassic() void GdbEngine::tryLoadDebuggingHelpersClassic()
{ {
if (m_forceAsyncModel)
return;
PRECONDITION; PRECONDITION;
if (m_gdbAdapter->dumperHandling() == AbstractGdbAdapter::DumperNotAvailable) { if (m_gdbAdapter->dumperHandling() == AbstractGdbAdapter::DumperNotAvailable) {
// Load at least gdb macro based dumpers. // Load at least gdb macro based dumpers.
@@ -1171,12 +1173,12 @@ void GdbEngine::updateAllClassic()
qDebug() << state()); qDebug() << state());
tryLoadDebuggingHelpersClassic(); tryLoadDebuggingHelpersClassic();
reloadModulesInternal(); reloadModulesInternal();
postCommand("-stack-list-frames", WatchUpdate, postCommand("-stack-list-frames", Discardable,
CB(handleStackListFrames), CB(handleStackListFrames),
QVariant::fromValue<StackCookie>(StackCookie(false, true))); QVariant::fromValue<StackCookie>(StackCookie(false, true)));
stackHandler()->setCurrentIndex(0); stackHandler()->setCurrentIndex(0);
if (supportsThreads()) if (supportsThreads())
postCommand("-thread-list-ids", WatchUpdate, CB(handleThreadListIds), 0); postCommand("-thread-list-ids", Discardable, CB(handleThreadListIds), 0);
reloadRegisters(); reloadRegisters();
updateLocals(); updateLocals();
} }
@@ -1248,11 +1250,10 @@ void GdbEngine::handleStackListLocalsClassic(const GdbResponse &response)
frame.function, frame.file, frame.line, frame.function, frame.file, frame.line,
&uninitializedVariables); &uninitializedVariables);
} }
QList<WatchData> list;
foreach (const GdbMi &item, locals) { foreach (const GdbMi &item, locals) {
const WatchData data = localVariable(item, uninitializedVariables, &seen); const WatchData data = localVariable(item, uninitializedVariables, &seen);
if (data.isValid()) if (data.isValid())
list.push_back(data); insertData(data);
} }
if (!m_resultVarName.isEmpty()) { if (!m_resultVarName.isEmpty()) {
@@ -1260,10 +1261,9 @@ void GdbEngine::handleStackListLocalsClassic(const GdbResponse &response)
rd.iname = "return.0"; rd.iname = "return.0";
rd.name = QLatin1String("return"); rd.name = QLatin1String("return");
rd.exp = m_resultVarName; rd.exp = m_resultVarName;
list.append(rd); insertData(rd);
} }
watchHandler()->insertBulkData(list);
watchHandler()->updateWatchers(); watchHandler()->updateWatchers();
} }
@@ -1371,7 +1371,7 @@ void GdbEngine::handleVarListChildrenHelperClassic(const GdbMi &item,
data.setChildrenUnneeded(); data.setChildrenUnneeded();
QByteArray cmd = "-var-list-children --all-values \"" + data.variable + '"'; QByteArray cmd = "-var-list-children --all-values \"" + data.variable + '"';
//iname += '.' + exp; //iname += '.' + exp;
postCommand(cmd, WatchUpdate, postCommand(cmd, Discardable,
CB(handleVarListChildrenClassic), QVariant::fromValue(data)); CB(handleVarListChildrenClassic), QVariant::fromValue(data));
} else if (!startsWithDigit(QLatin1String(exp)) } else if (!startsWithDigit(QLatin1String(exp))
&& item.findChild("numchild").data() == "0") { && item.findChild("numchild").data() == "0") {
@@ -1390,7 +1390,7 @@ void GdbEngine::handleVarListChildrenHelperClassic(const GdbMi &item,
WatchData data; WatchData data;
data.iname = name; data.iname = name;
QByteArray cmd = "-var-list-children --all-values \"" + data.variable + '"'; QByteArray cmd = "-var-list-children --all-values \"" + data.variable + '"';
postCommand(cmd, WatchUpdate, postCommand(cmd, Discardable,
CB(handleVarListChildrenClassic), QVariant::fromValue(data)); CB(handleVarListChildrenClassic), QVariant::fromValue(data));
} else if (exp == "staticMetaObject") { } else if (exp == "staticMetaObject") {
// && item.findChild("type").data() == "const QMetaObject") // && item.findChild("type").data() == "const QMetaObject")
@@ -1464,9 +1464,6 @@ void GdbEngine::handleVarListChildrenClassic(const GdbResponse &response)
//qDebug() << "VAR_LIST_CHILDREN: PARENT" << data.toString(); //qDebug() << "VAR_LIST_CHILDREN: PARENT" << data.toString();
QList<GdbMi> children = response.data.findChild("children").children(); QList<GdbMi> children = response.data.findChild("children").children();
for (int i = 0; i != children.size(); ++i)
handleVarListChildrenHelperClassic(children.at(i), data, i);
if (children.isEmpty()) { if (children.isEmpty()) {
// happens e.g. if no debug information is present or // happens e.g. if no debug information is present or
// if the class really has no children // if the class really has no children
@@ -1479,7 +1476,8 @@ void GdbEngine::handleVarListChildrenClassic(const GdbResponse &response)
insertData(data1); insertData(data1);
data.setAllUnneeded(); data.setAllUnneeded();
insertData(data); insertData(data);
} else if (data.variable.endsWith("private") } else {
if (data.variable.endsWith("private")
|| data.variable.endsWith("protected") || data.variable.endsWith("protected")
|| data.variable.endsWith("public")) { || data.variable.endsWith("public")) {
// this skips the spurious "public", "private" etc levels // this skips the spurious "public", "private" etc levels
@@ -1488,6 +1486,9 @@ void GdbEngine::handleVarListChildrenClassic(const GdbResponse &response)
data.setChildrenUnneeded(); data.setChildrenUnneeded();
insertData(data); insertData(data);
} }
for (int i = 0; i != children.size(); ++i)
handleVarListChildrenHelperClassic(children.at(i), data, i);
}
} else { } else {
data.setError(QString::fromLocal8Bit(response.data.findChild("msg").data())); data.setError(QString::fromLocal8Bit(response.data.findChild("msg").data()));
} }

View File

@@ -255,7 +255,6 @@ GdbEngine::GdbEngine(const DebuggerStartParameters &startParameters,
m_oldestAcceptableToken = -1; m_oldestAcceptableToken = -1;
m_nonDiscardableCount = 0; m_nonDiscardableCount = 0;
m_outputCodec = QTextCodec::codecForLocale(); m_outputCodec = QTextCodec::codecForLocale();
m_pendingWatchRequests = 0;
m_pendingBreakpointRequests = 0; m_pendingBreakpointRequests = 0;
m_commandsDoneCallback = 0; m_commandsDoneCallback = 0;
m_stackNeeded = false; m_stackNeeded = false;
@@ -263,6 +262,7 @@ GdbEngine::GdbEngine(const DebuggerStartParameters &startParameters,
m_disassembleUsesComma = false; m_disassembleUsesComma = false;
m_actingOnExpectedStop = false; m_actingOnExpectedStop = false;
m_fullStartDone = false; m_fullStartDone = false;
m_forceAsyncModel = false;
invalidateSourcesList(); invalidateSourcesList();
@@ -788,7 +788,8 @@ void GdbEngine::readGdbStandardOutput()
int newstart = 0; int newstart = 0;
int scan = m_inbuffer.size(); int scan = m_inbuffer.size();
m_inbuffer.append(gdbProc()->readAllStandardOutput()); QByteArray out = gdbProc()->readAllStandardOutput();
m_inbuffer.append(out);
// This can trigger when a dialog starts a nested event loop. // This can trigger when a dialog starts a nested event loop.
if (m_busy) if (m_busy)
@@ -811,7 +812,8 @@ void GdbEngine::readGdbStandardOutput()
continue; continue;
} }
m_busy = true; m_busy = true;
handleResponse(QByteArray::fromRawData(m_inbuffer.constData() + start, end - start)); QByteArray ba = QByteArray::fromRawData(m_inbuffer.constData() + start, end - start);
handleResponse(ba);
m_busy = false; m_busy = false;
} }
m_inbuffer.clear(); m_inbuffer.clear();
@@ -903,17 +905,13 @@ void GdbEngine::postCommandHelper(const GdbCommand &cmd)
return; return;
} }
if (cmd.flags & RebuildWatchModel) { if (cmd.flags & RebuildBreakpointModel) {
++m_pendingWatchRequests;
PENDING_DEBUG(" WATCH MODEL:" << cmd.command << "=>" << cmd.callbackName
<< "INCREMENTS PENDING TO" << m_pendingWatchRequests);
} else if (cmd.flags & RebuildBreakpointModel) {
++m_pendingBreakpointRequests; ++m_pendingBreakpointRequests;
PENDING_DEBUG(" BRWAKPOINT MODEL:" << cmd.command << "=>" << cmd.callbackName PENDING_DEBUG(" BRWAKPOINT MODEL:" << cmd.command << "=>" << cmd.callbackName
<< "INCREMENTS PENDING TO" << m_pendingBreakpointRequests); << "INCREMENTS PENDING TO" << m_pendingBreakpointRequests);
} else { } else {
PENDING_DEBUG(" OTHER (IN):" << cmd.command << "=>" << cmd.callbackName PENDING_DEBUG(" OTHER (IN):" << cmd.command << "=>" << cmd.callbackName
<< "LEAVES PENDING WATCH AT" << m_pendingWatchRequests << "LEAVES PENDING WATCH AT" << m_uncompleted.size()
<< "LEAVES PENDING BREAKPOINT AT" << m_pendingBreakpointRequests); << "LEAVES PENDING BREAKPOINT AT" << m_pendingBreakpointRequests);
} }
@@ -1055,7 +1053,6 @@ void GdbEngine::commandTimeout()
if (mb->exec() == QMessageBox::Ok) { if (mb->exec() == QMessageBox::Ok) {
showMessage(_("KILLING DEBUGGER AS REQUESTED BY USER")); showMessage(_("KILLING DEBUGGER AS REQUESTED BY USER"));
// This is an undefined state, so we just pull the emergency brake. // This is an undefined state, so we just pull the emergency brake.
watchHandler()->endCycle();
gdbProc()->kill(); gdbProc()->kill();
} else { } else {
showMessage(_("CONTINUE DEBUGGER AS REQUESTED BY USER")); showMessage(_("CONTINUE DEBUGGER AS REQUESTED BY USER"));
@@ -1205,25 +1202,17 @@ void GdbEngine::handleResultRecord(GdbResponse *response)
else if (cmd.adapterCallback) else if (cmd.adapterCallback)
(m_gdbAdapter->*cmd.adapterCallback)(*response); (m_gdbAdapter->*cmd.adapterCallback)(*response);
if (cmd.flags & RebuildWatchModel) { if (cmd.flags & RebuildBreakpointModel) {
--m_pendingWatchRequests;
PENDING_DEBUG(" WATCH" << cmd.command << "=>" << cmd.callbackName
<< "DECREMENTS PENDING WATCH TO" << m_pendingWatchRequests);
if (m_pendingWatchRequests <= 0) {
PENDING_DEBUG("\n\n ... AND TRIGGERS WATCH MODEL UPDATE\n");
rebuildWatchModel();
}
} else if (cmd.flags & RebuildBreakpointModel) {
--m_pendingBreakpointRequests; --m_pendingBreakpointRequests;
PENDING_DEBUG(" BREAKPOINT" << cmd.command << "=>" << cmd.callbackName PENDING_DEBUG(" BREAKPOINT" << cmd.command << "=>" << cmd.callbackName
<< "DECREMENTS PENDING TO" << m_pendingWatchRequests); << "DECREMENTS PENDING TO" << m_uncompleted.size());
if (m_pendingBreakpointRequests <= 0) { if (m_pendingBreakpointRequests <= 0) {
PENDING_DEBUG("\n\n ... AND TRIGGERS BREAKPOINT MODEL UPDATE\n"); PENDING_DEBUG("\n\n ... AND TRIGGERS BREAKPOINT MODEL UPDATE\n");
attemptBreakpointSynchronization(); attemptBreakpointSynchronization();
} }
} else { } else {
PENDING_DEBUG(" OTHER (OUT):" << cmd.command << "=>" << cmd.callbackName PENDING_DEBUG(" OTHER (OUT):" << cmd.command << "=>" << cmd.callbackName
<< "LEAVES PENDING WATCH AT" << m_pendingWatchRequests << "LEAVES PENDING WATCH AT" << m_uncompleted.size()
<< "LEAVES PENDING BREAKPOINT AT" << m_pendingBreakpointRequests); << "LEAVES PENDING BREAKPOINT AT" << m_pendingBreakpointRequests);
} }
@@ -3918,10 +3907,10 @@ bool GdbEngine::supportsThreads() const
// //
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
bool GdbEngine::showToolTip() void GdbEngine::showToolTip()
{ {
if (m_toolTipContext.isNull()) if (m_toolTipContext.isNull())
return false; return;
const QString expression = m_toolTipContext->expression; const QString expression = m_toolTipContext->expression;
const QByteArray iname = tooltipIName(m_toolTipContext->expression); const QByteArray iname = tooltipIName(m_toolTipContext->expression);
if (DebuggerToolTipManager::debug()) if (DebuggerToolTipManager::debug())
@@ -3929,15 +3918,15 @@ bool GdbEngine::showToolTip()
if (!debuggerCore()->boolSetting(UseToolTipsInMainEditor)) { if (!debuggerCore()->boolSetting(UseToolTipsInMainEditor)) {
watchHandler()->removeData(iname); watchHandler()->removeData(iname);
return true; return;
} }
if (!watchHandler()->isValidToolTip(iname)) { if (!watchHandler()->isValidToolTip(iname)) {
watchHandler()->removeData(iname); watchHandler()->removeData(iname);
return true; return;
} }
DebuggerToolTipWidget *tw = new DebuggerToolTipWidget; DebuggerToolTipWidget *tw = new DebuggerToolTipWidget;
tw->setDebuggerModel(TooltipsWatch); tw->setDebuggerModel(TooltipType);
tw->setExpression(expression); tw->setExpression(expression);
tw->setContext(*m_toolTipContext); tw->setContext(*m_toolTipContext);
tw->acquireEngine(this); tw->acquireEngine(this);
@@ -3945,7 +3934,6 @@ bool GdbEngine::showToolTip()
m_toolTipContext->editor, tw); m_toolTipContext->editor, tw);
// Prevent tooltip from re-occurring (classic GDB, QTCREATORBUG-4711). // Prevent tooltip from re-occurring (classic GDB, QTCREATORBUG-4711).
m_toolTipContext.reset(); m_toolTipContext.reset();
return true;
} }
QString GdbEngine::tooltipExpression() const QString GdbEngine::tooltipExpression() const
@@ -4034,7 +4022,6 @@ bool GdbEngine::setToolTipExpression(const QPoint &mousePos,
toolTip.exp = exp.toLatin1(); toolTip.exp = exp.toLatin1();
toolTip.name = exp; toolTip.name = exp;
toolTip.iname = tooltipIName(exp); toolTip.iname = tooltipIName(exp);
watchHandler()->removeData(toolTip.iname);
watchHandler()->insertData(toolTip); watchHandler()->insertData(toolTip);
} }
return true; return true;
@@ -4071,19 +4058,12 @@ bool GdbEngine::hasDebuggingHelperForType(const QByteArray &type) const
return m_dumperHelper.type(type) != DumperHelper::UnknownType; return m_dumperHelper.type(type) != DumperHelper::UnknownType;
} }
void GdbEngine::updateWatchData(const WatchData &data, const WatchUpdateFlags &flags) void GdbEngine::updateWatchData(const WatchData &data, const WatchUpdateFlags &flags)
{ {
if (isSynchronous()) { if (isSynchronous()) {
// This should only be called for fresh expanded items, not for // This should only be called for fresh expanded items, not for
// items that had their children retrieved earlier. // items that had their children retrieved earlier.
//qDebug() << "\nUPDATE WATCH DATA: " << data.toString() << "\n"; //qDebug() << "\nUPDATE WATCH DATA: " << data.toString() << "\n";
#if 0
WatchData data1 = data;
data1.setAllUnneeded();
insertData(data1);
rebuildModel();
#else
if (data.iname.endsWith(".")) if (data.iname.endsWith("."))
return; return;
@@ -4106,53 +4086,26 @@ void GdbEngine::updateWatchData(const WatchData &data, const WatchUpdateFlags &f
// triggered e.g. by manually entered command in the gdb console? // triggered e.g. by manually entered command in the gdb console?
//qDebug() << "TRY PARTIAL: " << flags.tryIncremental //qDebug() << "TRY PARTIAL: " << flags.tryIncremental
// << hasPython() // << hasPython()
// << (m_pendingWatchRequests == 0)
// << (m_pendingBreakpointRequests == 0); // << (m_pendingBreakpointRequests == 0);
UpdateParameters params; UpdateParameters params;
params.tooltipOnly = data.iname.startsWith("tooltip"); params.tooltipOnly = data.iname.startsWith("tooltip");
params.tryPartial = flags.tryIncremental params.tryPartial = flags.tryIncremental
&& hasPython() && hasPython()
&& m_pendingWatchRequests == 0
&& m_pendingBreakpointRequests == 0; && m_pendingBreakpointRequests == 0;
params.varList = data.iname; params.varList = data.iname;
updateLocalsPython(params); updateLocalsPython(params);
#endif
} else { } else {
// Bump requests to avoid model rebuilding during the nested PENDING_DEBUG("UPDATE WATCH BUMPS PENDING UP TO " << m_uncompleted.size());
// updateWatchModel runs.
++m_pendingWatchRequests;
PENDING_DEBUG("UPDATE WATCH BUMPS PENDING UP TO " << m_pendingWatchRequests);
#if 1
QMetaObject::invokeMethod(this, "updateWatchDataHelper",
Qt::QueuedConnection, Q_ARG(WatchData, data));
#else
updateWatchDataHelper(data);
#endif
}
}
void GdbEngine::updateWatchDataHelper(const WatchData &data)
{
//m_pendingRequests = 0;
PENDING_DEBUG("UPDATE WATCH DATA");
# if DEBUG_PENDING
//qDebug() << "##############################################";
qDebug() << "UPDATE MODEL, FOUND INCOMPLETE:";
//qDebug() << data.toString();
# endif
updateSubItemClassic(data); updateSubItemClassic(data);
//PENDING_DEBUG("INTERNAL TRIGGERING UPDATE WATCH MODEL"); }
--m_pendingWatchRequests;
PENDING_DEBUG("UPDATE WATCH DONE BUMPS PENDING DOWN TO " << m_pendingWatchRequests);
if (m_pendingWatchRequests <= 0)
rebuildWatchModel();
} }
void GdbEngine::rebuildWatchModel() void GdbEngine::rebuildWatchModel()
{ {
QTC_CHECK(m_completed.isEmpty());
QTC_CHECK(m_uncompleted.isEmpty());
static int count = 0; static int count = 0;
++count; ++count;
if (!isSynchronous()) if (!isSynchronous())
@@ -4162,7 +4115,6 @@ void GdbEngine::rebuildWatchModel()
showMessage(LogWindow::logTimeStamp(), LogMiscInput); showMessage(LogWindow::logTimeStamp(), LogMiscInput);
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);
watchHandler()->endCycle();
showToolTip(); showToolTip();
handleAutoTests(); handleAutoTests();
} }
@@ -4332,15 +4284,23 @@ WatchData GdbEngine::localVariable(const GdbMi &item,
return data; return data;
} }
void GdbEngine::insertData(const WatchData &data0) void GdbEngine::insertData(const WatchData &data)
{ {
PENDING_DEBUG("INSERT DATA" << data0.toString()); PENDING_DEBUG("INSERT DATA" << data.toString());
WatchData data = data0; if (data.isSomethingNeeded()) {
if (data.value.startsWith(QLatin1String("mi_cmd_var_create:"))) { m_uncompleted.insert(data.iname);
qDebug() << "BOGUS VALUE:" << data.toString(); WatchUpdateFlags flags;
return; flags.tryIncremental = true;
updateWatchData(data, flags);
} else {
m_completed.append(data);
m_uncompleted.remove(data.iname);
if (m_uncompleted.isEmpty()) {
watchHandler()->insertData(m_completed);
m_completed.clear();
rebuildWatchModel();
}
} }
watchHandler()->insertData(data);
} }
void GdbEngine::assignValueInDebugger(const WatchData *data, void GdbEngine::assignValueInDebugger(const WatchData *data,
@@ -4901,12 +4861,6 @@ bool GdbEngine::startGdb(const QStringList &args, const QString &settingsIdHint)
postCommand("disassemble 0 0", ConsoleCommand, CB(handleDisassemblerCheck)); postCommand("disassemble 0 0", ConsoleCommand, CB(handleDisassemblerCheck));
if (sp.breakOnMain) {
QByteArray cmd = "tbreak ";
cmd += sp.toolChainAbi.os() == Abi::WindowsOS ? "qMain" : "main";
postCommand(cmd);
}
if (attemptQuickStart()) { if (attemptQuickStart()) {
postCommand("set auto-solib-add off", ConsoleCommand); postCommand("set auto-solib-add off", ConsoleCommand);
} else { } else {
@@ -4941,6 +4895,9 @@ void GdbEngine::loadInitScript()
void GdbEngine::loadPythonDumpers() void GdbEngine::loadPythonDumpers()
{ {
if (m_forceAsyncModel)
return;
const QByteArray dumperSourcePath = const QByteArray dumperSourcePath =
Core::ICore::resourcePath().toLocal8Bit() + "/dumper/"; Core::ICore::resourcePath().toLocal8Bit() + "/dumper/";
@@ -5091,6 +5048,12 @@ void GdbEngine::handleInferiorPrepared()
QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << state()); QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << state());
if (sp.breakOnMain) {
QByteArray cmd = "tbreak ";
cmd += sp.toolChainAbi.os() == Abi::WindowsOS ? "qMain" : "main";
postCommand(cmd);
}
// Initial attempt to set breakpoints. // Initial attempt to set breakpoints.
if (sp.startMode != AttachCore) { if (sp.startMode != AttachCore) {
showStatusMessage(tr("Setting breakpoints...")); showStatusMessage(tr("Setting breakpoints..."));
@@ -5361,6 +5324,9 @@ void GdbEngine::requestDebugInformation(const DebugInfoTask &task)
bool GdbEngine::attemptQuickStart() const bool GdbEngine::attemptQuickStart() const
{ {
if (m_forceAsyncModel)
return false;
// Don't try if the user does not ask for it. // Don't try if the user does not ask for it.
if (!debuggerCore()->boolSetting(AttemptQuickStart)) if (!debuggerCore()->boolSetting(AttemptQuickStart))
return false; return false;

View File

@@ -36,6 +36,7 @@
#include "debuggerengine.h" #include "debuggerengine.h"
#include "stackframe.h" #include "stackframe.h"
#include "watchhandler.h"
#include "watchutils.h" #include "watchutils.h"
#include <QByteArray> #include <QByteArray>
@@ -80,16 +81,6 @@ enum DebuggingHelperState
DebuggingHelperUnavailable DebuggingHelperUnavailable
}; };
class UpdateParameters
{
public:
UpdateParameters() { tryPartial = tooltipOnly = false; }
bool tryPartial;
bool tooltipOnly;
QByteArray varList;
};
/* This is only used with Mac gdb since 2.2 /* This is only used with Mac gdb since 2.2
* *
* "Custom dumper" is a library compiled against the current * "Custom dumper" is a library compiled against the current
@@ -322,9 +313,6 @@ private: ////////// Gdb Command Management //////////
NeedsStop = 1, NeedsStop = 1,
// No need to wait for the reply before continuing inferior. // No need to wait for the reply before continuing inferior.
Discardable = 2, Discardable = 2,
// Trigger watch model rebuild when no such commands are pending anymore.
RebuildWatchModel = 4,
WatchUpdate = Discardable | RebuildWatchModel,
// We can live without receiving an answer. // We can live without receiving an answer.
NonCriticalResponse = 8, NonCriticalResponse = 8,
// Callback expects GdbResultRunning instead of GdbResultDone. // Callback expects GdbResultRunning instead of GdbResultDone.
@@ -407,7 +395,6 @@ private: ////////// Gdb Command Management //////////
int m_oldestAcceptableToken; int m_oldestAcceptableToken;
int m_nonDiscardableCount; int m_nonDiscardableCount;
int m_pendingWatchRequests; // Watch updating commands in flight
int m_pendingBreakpointRequests; // Watch updating commands in flight int m_pendingBreakpointRequests; // Watch updating commands in flight
typedef void (GdbEngine::*CommandsDoneCallback)(); typedef void (GdbEngine::*CommandsDoneCallback)();
@@ -630,13 +617,11 @@ private: ////////// View & Data Stuff //////////
virtual void watchPoint(const QPoint &); virtual void watchPoint(const QPoint &);
void handleWatchPoint(const GdbResponse &response); void handleWatchPoint(const GdbResponse &response);
// FIXME: BaseClass. called to improve situation for a watch item
void updateSubItemClassic(const WatchData &data); void updateSubItemClassic(const WatchData &data);
void virtual updateWatchData(const WatchData &data, const WatchUpdateFlags &flags); void updateWatchData(const WatchData &data, const WatchUpdateFlags &flags);
Q_SLOT void updateWatchDataHelper(const WatchData &data);
void rebuildWatchModel(); void rebuildWatchModel();
bool showToolTip(); void showToolTip();
void insertData(const WatchData &data); void insertData(const WatchData &data);
void sendWatchParameters(const QByteArray &params0); void sendWatchParameters(const QByteArray &params0);
@@ -753,6 +738,11 @@ private: ////////// View & Data Stuff //////////
// debug information. // debug information.
bool attemptQuickStart() const; bool attemptQuickStart() const;
bool m_fullStartDone; bool m_fullStartDone;
// Test
bool m_forceAsyncModel;
QList<WatchData> m_completed;
QSet<QByteArray> m_uncompleted;
}; };
} // namespace Internal } // namespace Internal

View File

@@ -54,12 +54,11 @@ namespace Internal {
void GdbEngine::updateLocalsPython(const UpdateParameters &params) void GdbEngine::updateLocalsPython(const UpdateParameters &params)
{ {
PRECONDITION; PRECONDITION;
m_pendingWatchRequests = 0; //m_pendingWatchRequests = 0;
m_pendingBreakpointRequests = 0; m_pendingBreakpointRequests = 0;
m_processedNames.clear(); m_processedNames.clear();
WatchHandler *handler = watchHandler();
handler->beginCycle(!params.tryPartial);
WatchHandler *handler = watchHandler();
QByteArray expanded = "expanded:" + handler->expansionRequests() + ' '; QByteArray expanded = "expanded:" + handler->expansionRequests() + ' ';
expanded += "typeformats:" + handler->typeFormatRequests() + ' '; expanded += "typeformats:" + handler->typeFormatRequests() + ' ';
expanded += "formats:" + handler->individualFormatRequests(); expanded += "formats:" + handler->individualFormatRequests();
@@ -117,7 +116,7 @@ void GdbEngine::updateLocalsPython(const UpdateParameters &params)
postCommand("bb options:" + options + " vars:" + params.varList + ' ' postCommand("bb options:" + options + " vars:" + params.varList + ' '
+ resultVar + expanded + " watchers:" + watchers.toHex(), + resultVar + expanded + " watchers:" + watchers.toHex(),
WatchUpdate, CB(handleStackFramePython), QVariant(params.tryPartial)); Discardable, CB(handleStackFramePython), QVariant(params.tryPartial));
} }
void GdbEngine::handleStackFramePython(const GdbResponse &response) void GdbEngine::handleStackFramePython(const GdbResponse &response)
@@ -136,9 +135,11 @@ void GdbEngine::handleStackFramePython(const GdbResponse &response)
} }
GdbMi all; GdbMi all;
all.fromStringMultiple(out); all.fromStringMultiple(out);
GdbMi data = all.findChild("data"); GdbMi data = all.findChild("data");
WatchHandler *handler = watchHandler();
QList<WatchData> list; QList<WatchData> list;
foreach (const GdbMi &child, data.children()) { foreach (const GdbMi &child, data.children()) {
WatchData dummy; WatchData dummy;
dummy.iname = child.findChild("iname").data(); dummy.iname = child.findChild("iname").data();
@@ -151,7 +152,7 @@ void GdbEngine::handleStackFramePython(const GdbResponse &response)
} else { } else {
dummy.name = _(child.findChild("name").data()); dummy.name = _(child.findChild("name").data());
} }
parseWatchData(watchHandler()->expandedINames(), dummy, child, &list); parseWatchData(handler->expandedINames(), dummy, child, &list);
} }
const GdbMi typeInfo = all.findChild("typeinfo"); const GdbMi typeInfo = all.findChild("typeinfo");
if (typeInfo.type() == GdbMi::List) { if (typeInfo.type() == GdbMi::List) {
@@ -169,15 +170,20 @@ void GdbEngine::handleStackFramePython(const GdbResponse &response)
list[i].size = ti.size; list[i].size = ti.size;
} }
watchHandler()->insertBulkData(list); if (!partial) {
handler->removeChildren("local");
handler->removeChildren("watch");
}
handler->insertData(list);
//PENDING_DEBUG("AFTER handleStackFrame()"); //PENDING_DEBUG("AFTER handleStackFrame()");
// FIXME: This should only be used when updateLocals() was // FIXME: This should only be used when updateLocals() was
// triggered by expanding an item in the view. // triggered by expanding an item in the view.
if (m_pendingWatchRequests <= 0) { //if (m_pendingWatchRequests <= 0) {
//PENDING_DEBUG("\n\n .... AND TRIGGERS MODEL UPDATE\n"); //PENDING_DEBUG("\n\n .... AND TRIGGERS MODEL UPDATE\n");
rebuildWatchModel(); rebuildWatchModel();
} //}
if (!partial) if (!partial)
emit stackFrameCompleted(); emit stackFrameCompleted();
} else { } else {

View File

@@ -496,9 +496,7 @@ void IPCEngineHost::rpcCallback(quint64 f, QByteArray payload)
WatchHandler *wh = watchHandler(); WatchHandler *wh = watchHandler();
if (!wh) if (!wh)
break; break;
wh->beginCycle(fullCycle); wh->insertData(wd);
wh->insertBulkData(wd);
wh->endCycle();
} }
break; break;
case IPCEngineGuest::NotifyAddBreakpointOk: case IPCEngineGuest::NotifyAddBreakpointOk:

View File

@@ -720,14 +720,12 @@ void PdbEngine::updateAll()
void PdbEngine::updateLocals() void PdbEngine::updateLocals()
{ {
WatchHandler *handler = watchHandler();
handler->beginCycle(true);
QByteArray watchers; QByteArray watchers;
//if (!m_toolTipExpression.isEmpty()) //if (!m_toolTipExpression.isEmpty())
// watchers += m_toolTipExpression.toLatin1() // watchers += m_toolTipExpression.toLatin1()
// + '#' + tooltipINameForExpression(m_toolTipExpression.toLatin1()); // + '#' + tooltipINameForExpression(m_toolTipExpression.toLatin1());
WatchHandler *handler = watchHandler();
QHash<QByteArray, int> watcherNames = handler->watcherNames(); QHash<QByteArray, int> watcherNames = handler->watcherNames();
QHashIterator<QByteArray, int> it(watcherNames); QHashIterator<QByteArray, int> it(watcherNames);
while (it.hasNext()) { while (it.hasNext()) {
@@ -831,8 +829,7 @@ void PdbEngine::handleListLocals(const PdbResponse &response)
//qDebug() << "CHILD: " << child.toString(); //qDebug() << "CHILD: " << child.toString();
parseWatchData(handler->expandedINames(), dummy, child, &list); parseWatchData(handler->expandedINames(), dummy, child, &list);
} }
handler->insertBulkData(list); handler->insertData(list);
handler->endCycle();
} }
bool PdbEngine::hasCapability(unsigned cap) const bool PdbEngine::hasCapability(unsigned cap) const

View File

@@ -1000,7 +1000,6 @@ void QmlEngine::updateWatchData(const WatchData &data,
const WatchUpdateFlags &) const WatchUpdateFlags &)
{ {
// qDebug() << "UPDATE WATCH DATA" << data.toString(); // qDebug() << "UPDATE WATCH DATA" << data.toString();
//watchHandler()->rebuildModel();
//showStatusMessage(tr("Stopped."), 5000); //showStatusMessage(tr("Stopped."), 5000);
if (data.isInspect()) { if (data.isInspect()) {
@@ -1020,7 +1019,7 @@ void QmlEngine::updateWatchData(const WatchData &data,
if (!data.isSomethingNeeded()) if (!data.isSomethingNeeded())
watchHandler()->insertData(data); watchHandler()->insertIncompleteData(data);
} }
void QmlEngine::synchronizeWatchers() void QmlEngine::synchronizeWatchers()

View File

@@ -103,15 +103,11 @@ void QmlInspectorAgent::updateWatchData(const WatchData &data)
if (debug) if (debug)
qDebug() << __FUNCTION__ << "(" << data.id << ")"; qDebug() << __FUNCTION__ << "(" << data.id << ")";
if (data.id) { if (data.id && !m_fetchDataIds.contains(data.id)) {
// objects // objects
m_fetchDataIds << data.id;
ObjectReference ref(data.id); ObjectReference ref(data.id);
m_fetchCurrentObjectsQueryIds << fetchContextObject(ref); m_fetchCurrentObjectsQueryIds << fetchContextObject(ref);
WatchData d = data;
d.setAllUnneeded();
m_engine->watchHandler()->beginCycle(InspectWatch, false);
m_engine->watchHandler()->insertData(d);
m_engine->watchHandler()->endCycle(InspectWatch);
} }
} }
@@ -126,12 +122,9 @@ void QmlInspectorAgent::selectObjectInTree(int debugId)
if (m_debugIdToIname.contains(debugId)) { if (m_debugIdToIname.contains(debugId)) {
QByteArray iname = m_debugIdToIname.value(debugId); QByteArray iname = m_debugIdToIname.value(debugId);
QTC_ASSERT(iname.startsWith("inspect."), qDebug() << iname); QTC_ASSERT(iname.startsWith("inspect."), qDebug() << iname);
QModelIndex itemIndex = m_engine->watchHandler()->itemIndex(iname);
QTC_ASSERT(itemIndex.isValid(),
qDebug() << "No for " << debugId << ", iname " << iname; return;);
if (debug) if (debug)
qDebug() << " selecting" << iname << "in tree"; qDebug() << " selecting" << iname << "in tree";
m_engine->watchHandler()->setCurrentModelIndex(InspectWatch, itemIndex); m_engine->watchHandler()->setCurrentItem(iname);
m_objectToSelect = 0; m_objectToSelect = 0;
} else { } else {
// we've to fetch it // we've to fetch it
@@ -370,9 +363,8 @@ void QmlInspectorAgent::updateStatus()
&& debuggerCore()->boolSetting(ShowQmlObjectTree)) { && debuggerCore()->boolSetting(ShowQmlObjectTree)) {
reloadEngines(); reloadEngines();
} else { } else {
// clear view // Clear view.
m_engine->watchHandler()->beginCycle(InspectWatch, true); m_engine->watchHandler()->removeChildren("inspect");
m_engine->watchHandler()->endCycle(InspectWatch);
} }
} }
@@ -588,10 +580,7 @@ void QmlInspectorAgent::objectTreeFetched(const ObjectReference &object)
<< "entries into watch handler ..."; << "entries into watch handler ...";
} }
WatchHandler *watchHandler = m_engine->watchHandler(); m_engine->watchHandler()->insertData(watchData);
watchHandler->beginCycle(InspectWatch, true);
watchHandler->insertBulkData(watchData);
watchHandler->endCycle(InspectWatch);
if (debug) if (debug)
qDebug() << "inserting entries took" << t.elapsed() << "ms"; qDebug() << "inserting entries took" << t.elapsed() << "ms";
@@ -615,15 +604,16 @@ void QmlInspectorAgent::onCurrentObjectsFetched(const ObjectReference &obj)
ObjectReference last = m_fetchCurrentObjects.last(); ObjectReference last = m_fetchCurrentObjects.last();
m_fetchCurrentObjects.clear(); m_fetchCurrentObjects.clear();
m_fetchDataIds.clear();
if (m_objectToSelect == last.debugId()) { if (m_objectToSelect == last.debugId()) {
// select item in view // select item in view
QByteArray iname = m_debugIdToIname.value(last.debugId()); QByteArray iname = m_debugIdToIname.value(last.debugId());
QModelIndex itemIndex = m_engine->watchHandler()->itemIndex(iname); WatchHandler *handler = m_engine->watchHandler();
QTC_ASSERT(itemIndex.isValid(), return); QTC_ASSERT(handler->hasItem(iname), return);
if (debug) if (debug)
qDebug() << " selecting" << iname << "in tree"; qDebug() << " selecting" << iname << "in tree";
m_engine->watchHandler()->setCurrentModelIndex(InspectWatch, itemIndex); handler->setCurrentItem(iname);
m_objectToSelect = -1; m_objectToSelect = -1;
} }
@@ -780,12 +770,11 @@ void QmlInspectorAgent::addObjectToTree(const ObjectReference &obj,
// find parent // find parent
QTC_ASSERT(m_debugIdToIname.contains(parentId), break); QTC_ASSERT(m_debugIdToIname.contains(parentId), break);
QByteArray iname = m_debugIdToIname.value(parentId); QByteArray iname = m_debugIdToIname.value(parentId);
const WatchData *parent = m_engine->watchHandler()->findItem(iname); WatchHandler *handler = m_engine->watchHandler();
const WatchData *parent = handler->findData(iname);
if (parent) { if (parent) {
QList<WatchData> watches = buildWatchData(obj, *parent); QList<WatchData> watches = buildWatchData(obj, *parent);
m_engine->watchHandler()->beginCycle(false); handler->insertData(watches);
m_engine->watchHandler()->insertBulkData(watches);
m_engine->watchHandler()->endCycle();
break; break;
} }
} }

View File

@@ -153,6 +153,7 @@ private:
DebugIdHash m_debugIdHash; DebugIdHash m_debugIdHash;
QList<int> m_objectWatches; QList<int> m_objectWatches;
QList<int> m_fetchDataIds;
}; };
} // Internal } // Internal

View File

@@ -272,7 +272,7 @@ void QmlV8DebuggerClientPrivate::evaluate(const QString expr, bool global,
QScriptValue ctxtList = parser.call(QScriptValue(), QScriptValueList() << _(ARRAY )); QScriptValue ctxtList = parser.call(QScriptValue(), QScriptValueList() << _(ARRAY ));
while (rowCount) { while (rowCount) {
QModelIndex index = localsModel->index(--rowCount, 0); QModelIndex index = localsModel->index(--rowCount, 0);
const WatchData *data = engine->watchHandler()->watchData(LocalsWatch, index); const WatchData *data = engine->watchHandler()->watchData(index);
QScriptValue ctxt = parser.call(QScriptValue(), QScriptValueList() << QScriptValue(_(OBJECT))); QScriptValue ctxt = parser.call(QScriptValue(), QScriptValueList() << QScriptValue(_(OBJECT)));
ctxt.setProperty(_(NAME), QScriptValue(data->name)); ctxt.setProperty(_(NAME), QScriptValue(data->name));
ctxt.setProperty(_(HANDLE), QScriptValue(int(data->id))); ctxt.setProperty(_(HANDLE), QScriptValue(int(data->id)));
@@ -1173,7 +1173,7 @@ void QmlV8DebuggerClient::expandObject(const QByteArray &iname, quint64 objectId
{ {
if (objectId == 0) { if (objectId == 0) {
//We may have got the global object //We may have got the global object
const WatchData *watch = d->engine->watchHandler()->findItem(iname); const WatchData *watch = d->engine->watchHandler()->findData(iname);
if (watch->value == QLatin1String("global")) { if (watch->value == QLatin1String("global")) {
StackHandler *stackHandler = d->engine->stackHandler(); StackHandler *stackHandler = d->engine->stackHandler();
if (stackHandler->isContentsValid() && stackHandler->currentFrame().isUsable()) { if (stackHandler->isContentsValid() && stackHandler->currentFrame().isUsable()) {
@@ -1706,9 +1706,7 @@ void QmlV8DebuggerClient::setCurrentFrameDetails(const QVariant &bodyVal, const
data.setHasChildren(true); data.setHasChildren(true);
data.id = 0; data.id = 0;
} }
d->engine->watchHandler()->beginCycle();
d->engine->watchHandler()->insertData(data); d->engine->watchHandler()->insertData(data);
d->engine->watchHandler()->endCycle();
} }
const QVariantList currentFrameScopes = currentFrame.value(_("scopes")).toList(); const QVariantList currentFrameScopes = currentFrame.value(_("scopes")).toList();
@@ -1785,11 +1783,8 @@ void QmlV8DebuggerClient::updateScope(const QVariant &bodyVal, const QVariant &r
if (!handlesToLookup.isEmpty()) if (!handlesToLookup.isEmpty())
d->lookup(handlesToLookup); d->lookup(handlesToLookup);
if (!locals.isEmpty()) { if (!locals.isEmpty())
d->engine->watchHandler()->beginCycle(false); d->engine->watchHandler()->insertData(locals);
d->engine->watchHandler()->insertBulkData(locals);
d->engine->watchHandler()->endCycle();
}
} }
void QmlV8DebuggerClient::updateEvaluationResult(int sequence, bool success, const QVariant &bodyVal, void QmlV8DebuggerClient::updateEvaluationResult(int sequence, bool success, const QVariant &bodyVal,
@@ -1810,7 +1805,7 @@ void QmlV8DebuggerClient::updateEvaluationResult(int sequence, bool success, con
d->scope(index); d->scope(index);
//Also update "this" //Also update "this"
QByteArray iname("local.this"); QByteArray iname("local.this");
const WatchData *parent = d->engine->watchHandler()->findItem(iname); const WatchData *parent = d->engine->watchHandler()->findData(iname);
d->localsAndWatchers.insertMulti(parent->id, iname); d->localsAndWatchers.insertMulti(parent->id, iname);
d->lookup(QList<int>() << parent->id); d->lookup(QList<int>() << parent->id);
@@ -1833,7 +1828,7 @@ void QmlV8DebuggerClient::updateEvaluationResult(int sequence, bool success, con
WatchData data; WatchData data;
//Do we have request to evaluate a local? //Do we have request to evaluate a local?
if (exp.startsWith("local.")) { if (exp.startsWith("local.")) {
const WatchData *watch = d->engine->watchHandler()->findItem(exp.toLatin1()); const WatchData *watch = d->engine->watchHandler()->findData(exp.toLatin1());
watchDataList << createWatchDataList(watch, body.properties, refsVal); watchDataList << createWatchDataList(watch, body.properties, refsVal);
} else { } else {
QByteArray iname = d->engine->watchHandler()->watcherName(exp.toLatin1()); QByteArray iname = d->engine->watchHandler()->watcherName(exp.toLatin1());
@@ -1854,9 +1849,7 @@ void QmlV8DebuggerClient::updateEvaluationResult(int sequence, bool success, con
watchDataList << data << createWatchDataList(&data, body.properties, refsVal); watchDataList << data << createWatchDataList(&data, body.properties, refsVal);
} }
//Insert the newly evaluated expression to the Watchers Window //Insert the newly evaluated expression to the Watchers Window
d->engine->watchHandler()->beginCycle(false); d->engine->watchHandler()->insertData(watchDataList);
d->engine->watchHandler()->insertBulkData(watchDataList);
d->engine->watchHandler()->endCycle();
} }
} }
} }
@@ -1933,7 +1926,7 @@ void QmlV8DebuggerClient::expandLocalsAndWatchers(const QVariant &bodyVal, const
if (prepend.startsWith("local.") || prepend.startsWith("watch.")) { if (prepend.startsWith("local.") || prepend.startsWith("watch.")) {
//Data for expanded local/watch //Data for expanded local/watch
//Could be an object or function //Could be an object or function
const WatchData *parent = d->engine->watchHandler()->findItem(prepend); const WatchData *parent = d->engine->watchHandler()->findData(prepend);
watchDataList << createWatchDataList(parent, bodyObjectData.properties, refsVal); watchDataList << createWatchDataList(parent, bodyObjectData.properties, refsVal);
} else { } else {
//rest //rest
@@ -1952,9 +1945,7 @@ void QmlV8DebuggerClient::expandLocalsAndWatchers(const QVariant &bodyVal, const
} }
} }
d->engine->watchHandler()->beginCycle(false); d->engine->watchHandler()->insertData(watchDataList);
d->engine->watchHandler()->insertBulkData(watchDataList);
d->engine->watchHandler()->endCycle();
} }
QList<WatchData> QmlV8DebuggerClient::createWatchDataList(const WatchData *parent, QList<WatchData> QmlV8DebuggerClient::createWatchDataList(const WatchData *parent,

View File

@@ -403,6 +403,8 @@ void QScriptDebuggerClient::messageReceived(const QByteArray &data)
QByteArray command; QByteArray command;
stream >> command; stream >> command;
WatchHandler *watchHandler = d->engine->watchHandler();
if (command == "STOPPED") { if (command == "STOPPED") {
d->engine->inferiorSpontaneousStop(); d->engine->inferiorSpontaneousStop();
@@ -432,15 +434,13 @@ void QScriptDebuggerClient::messageReceived(const QByteArray &data)
d->engine->stackHandler()->setFrames(ideStackFrames); d->engine->stackHandler()->setFrames(ideStackFrames);
d->engine->watchHandler()->beginCycle();
bool needPing = false; bool needPing = false;
foreach (WatchData data, watches) { foreach (WatchData data, watches) {
data.iname = d->engine->watchHandler()->watcherName(data.exp); data.iname = watchHandler->watcherName(data.exp);
d->engine->watchHandler()->insertData(data); watchHandler->insertIncompleteData(data);
if (d->engine->watchHandler()->expandedINames().contains(data.iname) && if (watchHandler->isExpandedIName(data.iname) && qint64(data.id) != -1) {
qint64(data.id) != -1) {
needPing = true; needPing = true;
expandObject(data.iname,data.id); expandObject(data.iname,data.id);
} }
@@ -448,20 +448,16 @@ void QScriptDebuggerClient::messageReceived(const QByteArray &data)
foreach (WatchData data, locals) { foreach (WatchData data, locals) {
data.iname = "local." + data.exp; data.iname = "local." + data.exp;
d->engine->watchHandler()->insertData(data); watchHandler->insertIncompleteData(data);
if (d->engine->watchHandler()->expandedINames().contains(data.iname) && if (watchHandler->isExpandedIName(data.iname) && qint64(data.id) != -1) {
qint64(data.id) != -1) {
needPing = true; needPing = true;
expandObject(data.iname,data.id); expandObject(data.iname,data.id);
} }
} }
if (needPing) { if (needPing)
sendPing(); sendPing();
} else {
d->engine->watchHandler()->endCycle();
}
bool becauseOfException; bool becauseOfException;
stream >> becauseOfException; stream >> becauseOfException;
@@ -518,12 +514,12 @@ void QScriptDebuggerClient::messageReceived(const QByteArray &data)
+ QLatin1String(iname) + QLatin1Char(' ') + data.value); + QLatin1String(iname) + QLatin1Char(' ') + data.value);
data.iname = iname; data.iname = iname;
if (iname.startsWith("watch.")) { if (iname.startsWith("watch.")) {
d->engine->watchHandler()->insertData(data); watchHandler->insertIncompleteData(data);
} else if (iname == "console") { } else if (iname == "console") {
d->engine->showMessage(data.value, QtMessageLogOutput); d->engine->showMessage(data.value, QtMessageLogOutput);
} else if (iname.startsWith("local.")) { } else if (iname.startsWith("local.")) {
data.name = data.name.left(data.name.indexOf(QLatin1Char(' '))); data.name = data.name.left(data.name.indexOf(QLatin1Char(' ')));
d->engine->watchHandler()->insertData(data); watchHandler->insertIncompleteData(data);
} else { } else {
qWarning() << "QmlEngine: Unexcpected result: " << iname << data.value; qWarning() << "QmlEngine: Unexcpected result: " << iname << data.value;
} }
@@ -538,10 +534,9 @@ void QScriptDebuggerClient::messageReceived(const QByteArray &data)
foreach (WatchData data, result) { foreach (WatchData data, result) {
data.iname = iname + '.' + data.exp; data.iname = iname + '.' + data.exp;
d->engine->watchHandler()->insertData(data); watchHandler->insertIncompleteData(data);
if (d->engine->watchHandler()->expandedINames().contains(data.iname) && if (watchHandler->isExpandedIName(data.iname) && qint64(data.id) != -1) {
qint64(data.id) != -1) {
needPing = true; needPing = true;
expandObject(data.iname, data.id); expandObject(data.iname, data.id);
} }
@@ -560,14 +555,12 @@ void QScriptDebuggerClient::messageReceived(const QByteArray &data)
d->logReceiveMessage(QString::fromLatin1("%1 %2 (%3 x locals) (%4 x watchdata)").arg( d->logReceiveMessage(QString::fromLatin1("%1 %2 (%3 x locals) (%4 x watchdata)").arg(
QLatin1String(command), QString::number(frameId), QLatin1String(command), QString::number(frameId),
QString::number(locals.size()), QString::number(watches.size()))); QString::number(locals.size()), QString::number(watches.size())));
d->engine->watchHandler()->beginCycle();
bool needPing = false; bool needPing = false;
foreach (WatchData data, watches) { foreach (WatchData data, watches) {
data.iname = d->engine->watchHandler()->watcherName(data.exp); data.iname = watchHandler->watcherName(data.exp);
d->engine->watchHandler()->insertData(data); watchHandler->insertIncompleteData(data);
if (d->engine->watchHandler()->expandedINames().contains(data.iname) && if (watchHandler->isExpandedIName(data.iname) && qint64(data.id) != -1) {
qint64(data.id) != -1) {
needPing = true; needPing = true;
expandObject(data.iname, data.id); expandObject(data.iname, data.id);
} }
@@ -575,26 +568,19 @@ void QScriptDebuggerClient::messageReceived(const QByteArray &data)
foreach (WatchData data, locals) { foreach (WatchData data, locals) {
data.iname = "local." + data.exp; data.iname = "local." + data.exp;
d->engine->watchHandler()->insertData(data); watchHandler->insertIncompleteData(data);
if (d->engine->watchHandler()->expandedINames().contains(data.iname) && if (watchHandler->isExpandedIName(data.iname) && qint64(data.id) != -1) {
qint64(data.id) != -1) {
needPing = true; needPing = true;
expandObject(data.iname, data.id); expandObject(data.iname, data.id);
} }
} }
if (needPing) if (needPing)
sendPing(); sendPing();
else
d->engine->watchHandler()->endCycle();
} else if (command == "PONG") { } else if (command == "PONG") {
int ping; int ping;
stream >> ping; stream >> ping;
d->logReceiveMessage(QLatin1String(command) + QLatin1Char(' ') + QString::number(ping)); d->logReceiveMessage(QLatin1String(command) + QLatin1Char(' ') + QString::number(ping));
if (ping == d->ping)
d->engine->watchHandler()->endCycle();
} else { } else {
qDebug() << Q_FUNC_INFO << "Unknown command: " << command; qDebug() << Q_FUNC_INFO << "Unknown command: " << command;
d->logReceiveMessage(QLatin1String(command) + QLatin1String(" UNKNOWN COMMAND!!")); d->logReceiveMessage(QLatin1String(command) + QLatin1String(" UNKNOWN COMMAND!!"));

View File

@@ -651,7 +651,6 @@ bool ScriptEngine::checkForBreakCondition(bool byFunction)
void ScriptEngine::updateLocals() void ScriptEngine::updateLocals()
{ {
QScriptContext *context = m_scriptEngine->currentContext(); QScriptContext *context = m_scriptEngine->currentContext();
watchHandler()->beginCycle();
SDEBUG(Q_FUNC_INFO); SDEBUG(Q_FUNC_INFO);
// //
@@ -686,9 +685,7 @@ void ScriptEngine::updateLocals()
data.iname = "local"; data.iname = "local";
data.name = _(data.iname); data.name = _(data.iname);
watchHandler()->beginCycle();
updateSubItem(data); updateSubItem(data);
watchHandler()->endCycle();
// FIXME: Use an extra thread. This here is evil. // FIXME: Use an extra thread. This here is evil.
m_stopped = true; m_stopped = true;
showStatusMessage(tr("Stopped."), 5000); showStatusMessage(tr("Stopped."), 5000);
@@ -809,9 +806,9 @@ void ScriptEngine::updateSubItem(const WatchData &data0)
} }
SDEBUG(msgDebugInsert(data, children)); SDEBUG(msgDebugInsert(data, children));
watchHandler()->insertData(data); watchHandler()->insertIncompleteData(data);
if (!children.isEmpty()) if (!children.isEmpty())
watchHandler()->insertBulkData(children); watchHandler()->insertData(children);
} }
DebuggerEngine *createScriptEngine(const DebuggerStartParameters &sp) DebuggerEngine *createScriptEngine(const DebuggerStartParameters &sp)

View File

@@ -143,7 +143,6 @@ WatchData::WatchData() :
size(0), size(0),
bitpos(0), bitpos(0),
bitsize(0), bitsize(0),
generation(-1),
hasChildren(false), hasChildren(false),
valueEnabled(true), valueEnabled(true),
valueEditable(true), valueEditable(true),
@@ -399,8 +398,6 @@ QString WatchData::toToolTip() const
if (size) if (size)
formatToolTipRow(str, tr("Static Object Size"), tr("%1 bytes").arg(size)); formatToolTipRow(str, tr("Static Object Size"), tr("%1 bytes").arg(size));
formatToolTipRow(str, tr("Internal ID"), QLatin1String(iname)); formatToolTipRow(str, tr("Internal ID"), QLatin1String(iname));
formatToolTipRow(str, tr("Generation"),
QString::number(generation));
str << "</table></body></html>"; str << "</table></body></html>";
return res; return res;
} }

View File

@@ -135,7 +135,6 @@ public:
uint size; // Size uint size; // Size
uint bitpos; // Position within bit fields uint bitpos; // Position within bit fields
uint bitsize; // Size in case of bit fields uint bitsize; // Size in case of bit fields
qint32 generation; // When updated?
bool hasChildren; bool hasChildren;
bool valueEnabled; // Value will be enabled or not bool valueEnabled; // Value will be enabled or not
bool valueEditable; // Value will be editable bool valueEditable; // Value will be editable

File diff suppressed because it is too large Load Diff

View File

@@ -35,28 +35,38 @@
#include "watchdata.h" #include "watchdata.h"
#include <QPointer>
#include <QHash> #include <QHash>
#include <QSet> #include <QSet>
#include <QStringList> #include <QStringList>
#include <QAbstractItemModel> #include <QAbstractItemModel>
namespace Debugger { namespace Debugger {
class DebuggerEngine; class DebuggerEngine;
namespace Internal { namespace Internal {
class WatchItem; class WatchModel;
class WatchHandler;
class UpdateParameters
{
public:
UpdateParameters() { tryPartial = tooltipOnly = false; }
bool tryPartial;
bool tooltipOnly;
QByteArray varList;
};
typedef QHash<QString, QStringList> TypeFormats; typedef QHash<QString, QStringList> TypeFormats;
enum WatchType enum WatchType
{ {
ReturnWatch, LocalsType,
LocalsWatch, InspectType,
WatchersWatch, WatchersType,
TooltipsWatch, ReturnType,
InspectWatch TooltipType
}; };
enum IntegerFormat enum IntegerFormat
@@ -67,126 +77,38 @@ enum IntegerFormat
OctalFormat OctalFormat
}; };
class WatchModel : public QAbstractItemModel
{
Q_OBJECT
private:
explicit WatchModel(WatchHandler *handler, WatchType type);
virtual ~WatchModel();
public:
virtual int rowCount(const QModelIndex &idx = QModelIndex()) const;
virtual int columnCount(const QModelIndex &idx) const;
signals:
void setCurrentIndex(const QModelIndex &index);
private:
QVariant data(const QModelIndex &index, int role) const;
bool setData(const QModelIndex &index, const QVariant &value, int role);
QModelIndex index(int, int, const QModelIndex &idx) const;
QModelIndex parent(const QModelIndex &idx) const;
bool hasChildren(const QModelIndex &idx) const;
Qt::ItemFlags flags(const QModelIndex &idx) const;
QVariant headerData(int section, Qt::Orientation orientation,
int role = Qt::DisplayRole) const;
bool canFetchMore(const QModelIndex &parent) const;
void fetchMore(const QModelIndex &parent);
void invalidateAll(const QModelIndex &parentIndex = QModelIndex());
friend class WatchHandler;
WatchItem *watchItem(const QModelIndex &) const;
QModelIndex watchIndex(const WatchItem *needle) const;
QModelIndex watchIndexHelper(const WatchItem *needle,
const WatchItem *parentItem, const QModelIndex &parentIndex) const;
void insertData(const WatchData &data);
void reinsertAllData();
void reinsertAllDataHelper(WatchItem *item, QList<WatchData> *data);
void insertBulkData(const QList<WatchData> &data);
WatchItem *findItem(const QByteArray &iname, WatchItem *root) const;
QString displayForAutoTest(const QByteArray &iname) const;
void reinitialize();
void removeOutdated();
void removeOutdatedHelper(WatchItem *item);
WatchItem *rootItem() const;
void destroyItem(WatchItem *item);
void emitDataChanged(int column,
const QModelIndex &parentIndex = QModelIndex());
void beginCycle(bool fullCycle); // Called at begin of updateLocals() cycle.
void endCycle(); // Called after all results have been received.
friend QDebug operator<<(QDebug d, const WatchModel &m);
void dump();
void dumpHelper(WatchItem *item);
void emitAllChanged();
private:
QString displayType(const WatchData &typeIn) const;
QString formattedValue(const WatchData &data) const;
QString removeInitialNamespace(QString str) const;
QString removeNamespaces(QString str) const;
void formatRequests(QByteArray *out, const WatchItem *item) const;
DebuggerEngine *engine() const;
QString display(const WatchItem *item, int col) const;
int itemFormat(const WatchData &data) const;
bool contentIsValid() const;
int m_generationCounter;
WatchHandler *m_handler;
WatchType m_type;
WatchItem *m_root;
QSet<QByteArray> m_fetchTriggered;
};
class WatchHandler : public QObject class WatchHandler : public QObject
{ {
Q_OBJECT Q_OBJECT
public: public:
explicit WatchHandler(DebuggerEngine *engine); explicit WatchHandler(DebuggerEngine *engine);
WatchModel *model(WatchType type) const; ~WatchHandler();
WatchModel *modelForIName(const QByteArray &iname) const;
QAbstractItemModel *model() const;
void cleanup(); void cleanup();
void watchExpression(const QString &exp); void watchExpression(const QString &exp);
void removeWatchExpression(const QString &exp); void removeWatchExpression(const QString &exp);
Q_SLOT void clearWatches(); Q_SLOT void clearWatches();
Q_SLOT void emitAllChanged();
void beginCycle(bool fullCycle = true); // Called at begin of updateLocals() cycle
void updateWatchers(); // Called after locals are fetched void updateWatchers(); // Called after locals are fetched
void endCycle(); // Called after all results have been received
void beginCycle(WatchType type, bool fullCycle = true);
void endCycle(WatchType type);
void showEditValue(const WatchData &data); void showEditValue(const WatchData &data);
void insertData(const WatchData &data); const WatchData *watchData(const QModelIndex &) const;
void insertBulkData(const QList<WatchData> &data); const WatchData *findData(const QByteArray &iname) const;
void removeData(const QByteArray &iname);
Q_SLOT void reinsertAllData();
const WatchData *watchData(WatchType type, const QModelIndex &) const;
const WatchData *findItem(const QByteArray &iname) const;
QString displayForAutoTest(const QByteArray &iname) const; QString displayForAutoTest(const QByteArray &iname) const;
QModelIndex itemIndex(const QByteArray &iname) const; bool hasItem(const QByteArray &iname) const;
void loadSessionData(); void loadSessionData();
void saveSessionData(); void saveSessionData();
void removeTooltip(); void removeTooltip();
void rebuildModel(); void rebuildModel();
bool isExpandedIName(const QByteArray &iname) const bool isExpandedIName(const QByteArray &iname) const;
{ return m_expandedINames.contains(iname); } QSet<QByteArray> expandedINames() const;
QSet<QByteArray> expandedINames() const
{ return m_expandedINames; }
static QStringList watchedExpressions(); static QStringList watchedExpressions();
static QHash<QByteArray, int> watcherNames(); static QHash<QByteArray, int> watcherNames();
@@ -199,7 +121,6 @@ public:
void addTypeFormats(const QByteArray &type, const QStringList &formats); void addTypeFormats(const QByteArray &type, const QStringList &formats);
void setTypeFormats(const TypeFormats &typeFormats); void setTypeFormats(const TypeFormats &typeFormats);
TypeFormats typeFormats() const; TypeFormats typeFormats() const;
QStringList typeFormatList(const WatchData &data) const;
void setUnprintableBase(int base); void setUnprintableBase(int base);
static int unprintableBase(); static int unprintableBase();
@@ -213,7 +134,15 @@ public:
void resetLocation(); void resetLocation();
bool isValidToolTip(const QByteArray &iname) const; bool isValidToolTip(const QByteArray &iname) const;
void setCurrentModelIndex(WatchType modelType, const QModelIndex &index); void setCurrentItem(const QByteArray &iname);
void updateWatchersWindow();
void insertData(const WatchData &data); // Convenience.
void insertData(const QList<WatchData> &list);
void insertIncompleteData(const WatchData &data);
void removeData(const QByteArray &iname);
void removeChildren(const QByteArray &iname);
void removeAllData();
private: private:
friend class WatchModel; friend class WatchModel;
@@ -223,25 +152,8 @@ private:
static void saveTypeFormats(); static void saveTypeFormats();
void setFormat(const QByteArray &type, int format); void setFormat(const QByteArray &type, int format);
void updateWatchersWindow();
void showInEditorHelper(QString *contents, WatchItem *item, int level);
bool m_inChange; WatchModel *m_model;
// QWidgets and QProcesses taking care of special displays.
typedef QMap<QByteArray, QPointer<QObject> > EditHandlers;
EditHandlers m_editHandlers;
TypeFormats m_reportedTypeFormats;
// Items expanded in the Locals & Watchers view.
QSet<QByteArray> m_expandedINames;
WatchModel *m_return;
WatchModel *m_locals;
WatchModel *m_watchers;
WatchModel *m_tooltips;
WatchModel *m_inspect;
DebuggerEngine *m_engine; DebuggerEngine *m_engine;
int m_watcherCounter; int m_watcherCounter;
@@ -253,4 +165,6 @@ private:
} // namespace Internal } // namespace Internal
} // namespace Debugger } // namespace Debugger
Q_DECLARE_METATYPE(Debugger::Internal::UpdateParameters)
#endif // DEBUGGER_WATCHHANDLER_H #endif // DEBUGGER_WATCHHANDLER_H

View File

@@ -530,12 +530,12 @@ void WatchTreeView::keyPressEvent(QKeyEvent *ev)
QString exp = model()->data(idx1).toString(); QString exp = model()->data(idx1).toString();
watchExpression(exp); watchExpression(exp);
} }
QTreeView::keyPressEvent(ev); BaseTreeView::keyPressEvent(ev);
} }
void WatchTreeView::dragEnterEvent(QDragEnterEvent *ev) void WatchTreeView::dragEnterEvent(QDragEnterEvent *ev)
{ {
//QTreeView::dragEnterEvent(ev); //BaseTreeView::dragEnterEvent(ev);
if (ev->mimeData()->hasText()) { if (ev->mimeData()->hasText()) {
ev->setDropAction(Qt::CopyAction); ev->setDropAction(Qt::CopyAction);
ev->accept(); ev->accept();
@@ -544,7 +544,7 @@ void WatchTreeView::dragEnterEvent(QDragEnterEvent *ev)
void WatchTreeView::dragMoveEvent(QDragMoveEvent *ev) void WatchTreeView::dragMoveEvent(QDragMoveEvent *ev)
{ {
//QTreeView::dragMoveEvent(ev); //BaseTreeView::dragMoveEvent(ev);
if (ev->mimeData()->hasText()) { if (ev->mimeData()->hasText()) {
ev->setDropAction(Qt::CopyAction); ev->setDropAction(Qt::CopyAction);
ev->accept(); ev->accept();
@@ -559,7 +559,7 @@ void WatchTreeView::dropEvent(QDropEvent *ev)
ev->setDropAction(Qt::CopyAction); ev->setDropAction(Qt::CopyAction);
ev->accept(); ev->accept();
} }
//QTreeView::dropEvent(ev); //BaseTreeView::dropEvent(ev);
} }
void WatchTreeView::mouseDoubleClickEvent(QMouseEvent *ev) void WatchTreeView::mouseDoubleClickEvent(QMouseEvent *ev)
@@ -570,7 +570,7 @@ void WatchTreeView::mouseDoubleClickEvent(QMouseEvent *ev)
watchExpression(QString()); watchExpression(QString());
return; return;
} }
QTreeView::mouseDoubleClickEvent(ev); BaseTreeView::mouseDoubleClickEvent(ev);
} }
// Text for add watch action with truncated expression. // Text for add watch action with truncated expression.
@@ -971,7 +971,7 @@ bool WatchTreeView::event(QEvent *ev)
releaseMouse(); releaseMouse();
currentEngine()->watchPoint(mapToGlobal(mev->pos())); currentEngine()->watchPoint(mapToGlobal(mev->pos()));
} }
return QTreeView::event(ev); return BaseTreeView::event(ev);
} }
void WatchTreeView::editItem(const QModelIndex &idx) void WatchTreeView::editItem(const QModelIndex &idx)
@@ -982,6 +982,7 @@ void WatchTreeView::editItem(const QModelIndex &idx)
void WatchTreeView::setModel(QAbstractItemModel *model) void WatchTreeView::setModel(QAbstractItemModel *model)
{ {
BaseTreeView::setModel(model); BaseTreeView::setModel(model);
setRootIndex(model->index(m_type, 0, QModelIndex()));
setRootIsDecorated(true); setRootIsDecorated(true);
if (header()) { if (header()) {
header()->setDefaultAlignment(Qt::AlignLeft); header()->setDefaultAlignment(Qt::AlignLeft);
@@ -990,15 +991,25 @@ void WatchTreeView::setModel(QAbstractItemModel *model)
} }
connect(model, SIGNAL(layoutChanged()), SLOT(resetHelper())); connect(model, SIGNAL(layoutChanged()), SLOT(resetHelper()));
connect(model, SIGNAL(currentIndexRequested(QModelIndex)),
QTC_ASSERT(qobject_cast<WatchModel*>(model), return);
connect(model, SIGNAL(setCurrentIndex(QModelIndex)),
SLOT(setCurrentIndex(QModelIndex))); SLOT(setCurrentIndex(QModelIndex)));
connect(model, SIGNAL(itemIsExpanded(QModelIndex)),
SLOT(handleItemIsExpanded(QModelIndex)));
}
void WatchTreeView::handleItemIsExpanded(const QModelIndex &idx)
{
bool on = idx.data(LocalsExpandedRole).toBool();
QTC_ASSERT(on, return);
if (!isExpanded(idx))
expand(idx);
} }
void WatchTreeView::resetHelper() void WatchTreeView::resetHelper()
{ {
resetHelper(model()->index(0, 0)); QModelIndex idx = model()->index(m_type, 0);
resetHelper(idx);
expand(idx);
} }
void WatchTreeView::resetHelper(const QModelIndex &idx) void WatchTreeView::resetHelper(const QModelIndex &idx)
@@ -1019,6 +1030,13 @@ void WatchTreeView::resetHelper(const QModelIndex &idx)
} }
} }
void WatchTreeView::reset()
{
BaseTreeView::reset();
setRootIndex(model()->index(m_type, 0));
resetHelper();
}
void WatchTreeView::watchExpression(const QString &exp) void WatchTreeView::watchExpression(const QString &exp)
{ {
currentEngine()->watchHandler()->watchExpression(exp); currentEngine()->watchHandler()->watchExpression(exp);
@@ -1063,7 +1081,5 @@ void WatchTreeView::setWatchpointAtExpression(const QString &exp)
breakHandler()->appendBreakpoint(data); breakHandler()->appendBreakpoint(data);
} }
} // namespace Internal } // namespace Internal
} // namespace Debugger } // namespace Debugger

View File

@@ -49,15 +49,17 @@ class WatchTreeView : public BaseTreeView
Q_OBJECT Q_OBJECT
public: public:
enum Type { ReturnType, LocalsType, TooltipType, WatchersType, InspectType }; enum Type { LocalsType, InspectType, WatchersType, ReturnType, TooltipType };
explicit WatchTreeView(Type type, QWidget *parent = 0); explicit WatchTreeView(Type type, QWidget *parent = 0);
Type type() const { return m_type; } Type type() const { return m_type; }
void setModel(QAbstractItemModel *model); void setModel(QAbstractItemModel *model);
void reset();
public slots: public slots:
void watchExpression(const QString &exp); void watchExpression(const QString &exp);
void removeWatchExpression(const QString &exp); void removeWatchExpression(const QString &exp);
void handleItemIsExpanded(const QModelIndex &idx);
private: private:
Q_SLOT void resetHelper(); Q_SLOT void resetHelper();