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.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):
d.putValue(encodeCharArray(value["m_start"], 100, value["m_length"]),
Hex2EncodedLatin1)

View File

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

View File

@@ -85,7 +85,7 @@ public:
virtual QVariant configValue(const QString &name) const = 0;
virtual void setConfigValue(const QString &name, const QVariant &value) = 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 QIcon locationMarkIcon() const = 0;
virtual const CPlusPlus::Snapshot &cppCodeModelSnapshot() const = 0;

View File

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

View File

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

View File

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

View File

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

View File

@@ -31,6 +31,7 @@
**************************************************************************/
#include "debuggertooltipmanager.h"
#include "debuggerinternalconstants.h"
#include "watchutils.h"
#include "debuggerengine.h"
#include "debuggeractions.h"
@@ -617,7 +618,7 @@ DebuggerToolTipWidget::DebuggerToolTipWidget(QWidget *parent) :
m_titleLabel(new DraggableLabel),
m_engineAcquired(false),
m_creationDate(QDate::currentDate()),
m_debuggerModel(TooltipsWatch),
m_debuggerModel(TooltipType),
m_treeView(new DebuggerToolTipTreeView),
m_defaultModel(new QStandardItemModel(this))
{
@@ -664,7 +665,7 @@ bool DebuggerToolTipWidget::matches(const QString &fileName,
return function == m_context.function;
}
void DebuggerToolTipWidget::acquireEngine(Debugger::DebuggerEngine *engine)
void DebuggerToolTipWidget::acquireEngine(DebuggerEngine *engine)
{
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,
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.
*/
class DebuggerToolTipExpressionFilterModel : public QSortFilterProxyModel
class TooltipFilterModel : public QSortFilterProxyModel
{
public:
explicit DebuggerToolTipExpressionFilterModel(QAbstractItemModel *model, const QString &exp, QObject *parent = 0);
virtual bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const;
TooltipFilterModel(QAbstractItemModel *model, const QString &exp, int debuggerModel) :
m_expressions(exp.split(QLatin1Char('.'))),
m_debuggerModel(debuggerModel)
{
setSourceModel(model);
}
virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const
{
return role == Qt::ToolTipRole
? QVariant() : QSortFilterProxyModel::data(index, role);
}
bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const;
private:
const QStringList m_expressions;
int m_debuggerModel;
};
DebuggerToolTipExpressionFilterModel::DebuggerToolTipExpressionFilterModel(QAbstractItemModel *model,
const QString &exp,
QObject *parent) :
QSortFilterProxyModel(parent),
m_expressions(exp.split(QLatin1Char('.')))
bool TooltipFilterModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const
{
setSourceModel(model);
}
QVariant DebuggerToolTipExpressionFilterModel::data(const QModelIndex &index, int role) const
{
return role != Qt::ToolTipRole ?
QSortFilterProxyModel::data(index, role) : QVariant();
}
// Return depth of a model index, that is, 0 for root index, 1 for level-1 children, etc.
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
{
// 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);
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)
previousModel->disconnect(SIGNAL(rowsInserted(QModelIndex,int,int)), this);
setModel(newModel);
//setRootIndex(newModel->index(0, 0));
connect(newModel, SIGNAL(rowsInserted(QModelIndex,int,int)),
this, SLOT(computeSize()), Qt::QueuedConnection);
computeSize();
@@ -991,24 +989,12 @@ void DebuggerToolTipTreeView::computeSize()
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.
QAbstractItemModel *model = 0;
switch (m_debuggerModel) {
case LocalsWatch:
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);
QAbstractItemModel *model = engine->watchModel();
TooltipFilterModel *filterModel =
new TooltipFilterModel(model, m_expression, m_debuggerModel);
swapModel(filterModel);
}
@@ -1311,7 +1297,7 @@ void DebuggerToolTipManager::slotUpdateVisibleToolTips()
}
}
void DebuggerToolTipManager::slotDebuggerStateChanged(Debugger::DebuggerState state)
void DebuggerToolTipManager::slotDebuggerStateChanged(DebuggerState state)
{
const QObject *engine = sender();
QTC_ASSERT(engine, return);
@@ -1319,7 +1305,7 @@ void DebuggerToolTipManager::slotDebuggerStateChanged(Debugger::DebuggerState st
const QString name = engine->objectName();
if (debugToolTips)
qDebug() << "DebuggerToolTipWidget::debuggerStateChanged"
<< engine << Debugger::DebuggerEngine::stateName(state);
<< engine << DebuggerEngine::stateName(state);
// Release at earliest possible convenience.
switch (state) {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -272,7 +272,7 @@ void QmlV8DebuggerClientPrivate::evaluate(const QString expr, bool global,
QScriptValue ctxtList = parser.call(QScriptValue(), QScriptValueList() << _(ARRAY ));
while (rowCount) {
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)));
ctxt.setProperty(_(NAME), QScriptValue(data->name));
ctxt.setProperty(_(HANDLE), QScriptValue(int(data->id)));
@@ -1173,7 +1173,7 @@ void QmlV8DebuggerClient::expandObject(const QByteArray &iname, quint64 objectId
{
if (objectId == 0) {
//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")) {
StackHandler *stackHandler = d->engine->stackHandler();
if (stackHandler->isContentsValid() && stackHandler->currentFrame().isUsable()) {
@@ -1706,9 +1706,7 @@ void QmlV8DebuggerClient::setCurrentFrameDetails(const QVariant &bodyVal, const
data.setHasChildren(true);
data.id = 0;
}
d->engine->watchHandler()->beginCycle();
d->engine->watchHandler()->insertData(data);
d->engine->watchHandler()->endCycle();
}
const QVariantList currentFrameScopes = currentFrame.value(_("scopes")).toList();
@@ -1785,11 +1783,8 @@ void QmlV8DebuggerClient::updateScope(const QVariant &bodyVal, const QVariant &r
if (!handlesToLookup.isEmpty())
d->lookup(handlesToLookup);
if (!locals.isEmpty()) {
d->engine->watchHandler()->beginCycle(false);
d->engine->watchHandler()->insertBulkData(locals);
d->engine->watchHandler()->endCycle();
}
if (!locals.isEmpty())
d->engine->watchHandler()->insertData(locals);
}
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);
//Also update "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->lookup(QList<int>() << parent->id);
@@ -1833,7 +1828,7 @@ void QmlV8DebuggerClient::updateEvaluationResult(int sequence, bool success, con
WatchData data;
//Do we have request to evaluate a 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);
} else {
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);
}
//Insert the newly evaluated expression to the Watchers Window
d->engine->watchHandler()->beginCycle(false);
d->engine->watchHandler()->insertBulkData(watchDataList);
d->engine->watchHandler()->endCycle();
d->engine->watchHandler()->insertData(watchDataList);
}
}
}
@@ -1933,7 +1926,7 @@ void QmlV8DebuggerClient::expandLocalsAndWatchers(const QVariant &bodyVal, const
if (prepend.startsWith("local.") || prepend.startsWith("watch.")) {
//Data for expanded local/watch
//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);
} else {
//rest
@@ -1952,9 +1945,7 @@ void QmlV8DebuggerClient::expandLocalsAndWatchers(const QVariant &bodyVal, const
}
}
d->engine->watchHandler()->beginCycle(false);
d->engine->watchHandler()->insertBulkData(watchDataList);
d->engine->watchHandler()->endCycle();
d->engine->watchHandler()->insertData(watchDataList);
}
QList<WatchData> QmlV8DebuggerClient::createWatchDataList(const WatchData *parent,

View File

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

View File

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

View File

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

View File

@@ -135,7 +135,6 @@ public:
uint size; // Size
uint bitpos; // Position within bit fields
uint bitsize; // Size in case of bit fields
qint32 generation; // When updated?
bool hasChildren;
bool valueEnabled; // Value will be enabled or not
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 <QPointer>
#include <QHash>
#include <QSet>
#include <QStringList>
#include <QAbstractItemModel>
namespace Debugger {
class DebuggerEngine;
namespace Internal {
class WatchItem;
class WatchHandler;
class WatchModel;
class UpdateParameters
{
public:
UpdateParameters() { tryPartial = tooltipOnly = false; }
bool tryPartial;
bool tooltipOnly;
QByteArray varList;
};
typedef QHash<QString, QStringList> TypeFormats;
enum WatchType
{
ReturnWatch,
LocalsWatch,
WatchersWatch,
TooltipsWatch,
InspectWatch
LocalsType,
InspectType,
WatchersType,
ReturnType,
TooltipType
};
enum IntegerFormat
@@ -67,126 +77,38 @@ enum IntegerFormat
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
{
Q_OBJECT
public:
explicit WatchHandler(DebuggerEngine *engine);
WatchModel *model(WatchType type) const;
WatchModel *modelForIName(const QByteArray &iname) const;
~WatchHandler();
QAbstractItemModel *model() const;
void cleanup();
void watchExpression(const QString &exp);
void removeWatchExpression(const QString &exp);
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 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 insertData(const WatchData &data);
void insertBulkData(const QList<WatchData> &data);
void removeData(const QByteArray &iname);
Q_SLOT void reinsertAllData();
const WatchData *watchData(WatchType type, const QModelIndex &) const;
const WatchData *findItem(const QByteArray &iname) const;
const WatchData *watchData(const QModelIndex &) const;
const WatchData *findData(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 saveSessionData();
void removeTooltip();
void rebuildModel();
bool isExpandedIName(const QByteArray &iname) const
{ return m_expandedINames.contains(iname); }
QSet<QByteArray> expandedINames() const
{ return m_expandedINames; }
bool isExpandedIName(const QByteArray &iname) const;
QSet<QByteArray> expandedINames() const;
static QStringList watchedExpressions();
static QHash<QByteArray, int> watcherNames();
@@ -199,7 +121,6 @@ public:
void addTypeFormats(const QByteArray &type, const QStringList &formats);
void setTypeFormats(const TypeFormats &typeFormats);
TypeFormats typeFormats() const;
QStringList typeFormatList(const WatchData &data) const;
void setUnprintableBase(int base);
static int unprintableBase();
@@ -213,7 +134,15 @@ public:
void resetLocation();
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:
friend class WatchModel;
@@ -223,25 +152,8 @@ private:
static void saveTypeFormats();
void setFormat(const QByteArray &type, int format);
void updateWatchersWindow();
void showInEditorHelper(QString *contents, WatchItem *item, int level);
bool m_inChange;
// 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;
WatchModel *m_model;
DebuggerEngine *m_engine;
int m_watcherCounter;
@@ -253,4 +165,6 @@ private:
} // namespace Internal
} // namespace Debugger
Q_DECLARE_METATYPE(Debugger::Internal::UpdateParameters)
#endif // DEBUGGER_WATCHHANDLER_H

View File

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

View File

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