debugger: fixes and improvements related to the Locals display

Split the concepts 'enabled' and 'editable' in the dumper output
Disable "<not in scope>" entries, also fix their type.
Fix glitch in type beautification for display
Find reason for failing bulk updates.
This commit is contained in:
hjk
2009-08-31 09:14:04 +02:00
parent 7503d1bcf6
commit 452f108ac7
15 changed files with 428 additions and 159 deletions

View File

@@ -500,10 +500,10 @@ struct QDumper
// the dumper arguments // the dumper arguments
int protocolVersion; // dumper protocol version int protocolVersion; // dumper protocol version
int token; // some token to show on success int token; // some token to show on success
const char *outertype; // object type const char *outerType; // object type
const char *iname; // object name used for display const char *iname; // object name used for display
const char *exp; // object expression const char *exp; // object expression
const char *innertype; // 'inner type' for class templates const char *innerType; // 'inner type' for class templates
const void *data; // pointer to raw data const void *data; // pointer to raw data
bool dumpChildren; // do we want to see children? bool dumpChildren; // do we want to see children?
@@ -543,7 +543,7 @@ QDumper::~QDumper()
void QDumper::setupTemplateParameters() void QDumper::setupTemplateParameters()
{ {
char *s = const_cast<char *>(innertype); char *s = const_cast<char *>(innerType);
int templateParametersCount = 1; int templateParametersCount = 1;
templateParameters[0] = s; templateParameters[0] = s;
@@ -734,7 +734,7 @@ void QDumper::endHash()
void QDumper::putEllipsis() void QDumper::putEllipsis()
{ {
putCommaIfNeeded(); putCommaIfNeeded();
put("{name=\"<incomplete>\",value=\"\",type=\"").put(innertype).put("\"}"); put("{name=\"<incomplete>\",value=\"\",type=\"").put(innerType).put("\"}");
} }
void QDumper::putItemCount(const char *name, int count) void QDumper::putItemCount(const char *name, int count)
@@ -875,13 +875,11 @@ void QDumper::putHash(const char *name, QChar value)
#define DUMPUNKNOWN_MESSAGE "<not in scope>" #define DUMPUNKNOWN_MESSAGE "<not in scope>"
static void qDumpUnknown(QDumper &d, const char *why = 0) static void qDumpUnknown(QDumper &d, const char *why = 0)
{ {
//d.putItem("iname", d.iname);
//d.putItem("addr", d.data);
if (!why) if (!why)
why = DUMPUNKNOWN_MESSAGE; why = DUMPUNKNOWN_MESSAGE;
d.putItem("value", why); d.putItem("value", why);
d.putItem("type", d.outertype); d.putItem("valueeditable", "false");
d.putItem("valuedisabled", "true"); d.putItem("valueenabled", "false");
d.putItem("numchild", "0", d.currentChildNumChild); d.putItem("numchild", "0", d.currentChildNumChild);
d.disarm(); d.disarm();
} }
@@ -983,7 +981,7 @@ void qDumpInnerValueHelper(QDumper &d, const char *type, const void *addr,
if (startsWith(type, "QList<")) { if (startsWith(type, "QList<")) {
const QListData *ldata = reinterpret_cast<const QListData*>(addr); const QListData *ldata = reinterpret_cast<const QListData*>(addr);
d.putItemCount("value", ldata->size()); d.putItemCount("value", ldata->size());
d.putItem("valuedisabled", "true"); d.putItem("valueeditable", "false");
d.putItem("numchild", ldata->size()); d.putItem("numchild", ldata->size());
} }
break; break;
@@ -1638,12 +1636,12 @@ static void qDumpQList(QDumper &d)
int n = nn; int n = nn;
d.putItemCount("value", n); d.putItemCount("value", n);
d.putItem("valuedisabled", "true"); d.putItem("valueeditable", "false");
d.putItem("numchild", n); d.putItem("numchild", n);
if (d.dumpChildren) { if (d.dumpChildren) {
unsigned innerSize = d.extraInt[0]; unsigned innerSize = d.extraInt[0];
bool innerTypeIsPointer = isPointerType(d.innertype); bool innerTypeIsPointer = isPointerType(d.innerType);
QByteArray strippedInnerType = stripPointerType(d.innertype); QByteArray strippedInnerType = stripPointerType(d.innerType);
// The exact condition here is: // The exact condition here is:
// QTypeInfo<T>::isLarge || QTypeInfo<T>::isStatic // QTypeInfo<T>::isLarge || QTypeInfo<T>::isStatic
@@ -1651,11 +1649,11 @@ static void qDumpQList(QDumper &d)
// in the frontend. // in the frontend.
// So as first approximation only do the 'isLarge' check: // So as first approximation only do the 'isLarge' check:
bool isInternal = innerSize <= int(sizeof(void*)) bool isInternal = innerSize <= int(sizeof(void*))
&& isMovableType(d.innertype); && isMovableType(d.innerType);
d.putItem("internal", (int)isInternal); d.putItem("internal", (int)isInternal);
if (n > 1000) if (n > 1000)
n = 1000; n = 1000;
d.beginChildren(n ? d.innertype : 0); d.beginChildren(n ? d.innerType : 0);
for (int i = 0; i != n; ++i) { for (int i = 0; i != n; ++i) {
d.beginHash(); d.beginHash();
if (innerTypeIsPointer) { if (innerTypeIsPointer) {
@@ -1671,13 +1669,13 @@ static void qDumpQList(QDumper &d)
} else { } else {
void *p = ldata.d->array + i + pdata->begin; void *p = ldata.d->array + i + pdata->begin;
if (isInternal) { if (isInternal) {
//qDumpInnerValue(d, d.innertype, p); //qDumpInnerValue(d, d.innerType, p);
d.putItem("addr", p); d.putItem("addr", p);
qDumpInnerValueHelper(d, d.innertype, p); qDumpInnerValueHelper(d, d.innerType, p);
} else { } else {
//qDumpInnerValue(d, d.innertype, deref(p)); //qDumpInnerValue(d, d.innerType, deref(p));
d.putItem("addr", deref(p)); d.putItem("addr", deref(p));
qDumpInnerValueHelper(d, d.innertype, deref(p)); qDumpInnerValueHelper(d, d.innerType, deref(p));
} }
} }
d.endHash(); d.endHash();
@@ -1702,23 +1700,23 @@ static void qDumpQLinkedList(QDumper &d)
int n = nn; int n = nn;
d.putItemCount("value", n); d.putItemCount("value", n);
d.putItem("valuedisabled", "true"); d.putItem("valueeditable", "false");
d.putItem("numchild", n); d.putItem("numchild", n);
if (d.dumpChildren) { if (d.dumpChildren) {
//unsigned innerSize = d.extraInt[0]; //unsigned innerSize = d.extraInt[0];
//bool innerTypeIsPointer = isPointerType(d.innertype); //bool innerTypeIsPointer = isPointerType(d.innerType);
QByteArray strippedInnerType = stripPointerType(d.innertype); QByteArray strippedInnerType = stripPointerType(d.innerType);
const char *stripped = const char *stripped =
isPointerType(d.innertype) ? strippedInnerType.data() : 0; isPointerType(d.innerType) ? strippedInnerType.data() : 0;
if (n > 1000) if (n > 1000)
n = 1000; n = 1000;
d.beginChildren(d.innertype); d.beginChildren(d.innerType);
const void *p = deref(ldata); const void *p = deref(ldata);
for (int i = 0; i != n; ++i) { for (int i = 0; i != n; ++i) {
d.beginHash(); d.beginHash();
const void *addr = addOffset(p, 2 * sizeof(void*)); const void *addr = addOffset(p, 2 * sizeof(void*));
qDumpInnerValueOrPointer(d, d.innertype, stripped, addr); qDumpInnerValueOrPointer(d, d.innerType, stripped, addr);
p = deref(p); p = deref(p);
d.endHash(); d.endHash();
} }
@@ -2750,7 +2748,7 @@ static void qDumpQSet(QDumper &d)
} }
d.putItemCount("value", n); d.putItemCount("value", n);
d.putItem("valuedisabled", "true"); d.putItem("valueeditable", "false");
d.putItem("numchild", 2 * n); d.putItem("numchild", 2 * n);
if (d.dumpChildren) { if (d.dumpChildren) {
if (n > 100) if (n > 100)
@@ -2760,9 +2758,9 @@ static void qDumpQSet(QDumper &d)
for (int bucket = 0; bucket != hd->numBuckets && i <= 10000; ++bucket) { for (int bucket = 0; bucket != hd->numBuckets && i <= 10000; ++bucket) {
for (node = hd->buckets[bucket]; node->next; node = node->next) { for (node = hd->buckets[bucket]; node->next; node = node->next) {
d.beginHash(); d.beginHash();
d.putItem("type", d.innertype); d.putItem("type", d.innerType);
d.beginItem("exp"); d.beginItem("exp");
d.put("(('"NS"QHashNode<").put(d.innertype d.put("(('"NS"QHashNode<").put(d.innerType
).put(","NS"QHashDummyValue>'*)" ).put(","NS"QHashDummyValue>'*)"
).put(static_cast<const void*>(node)).put(")->key"); ).put(static_cast<const void*>(node)).put(")->key");
d.endItem(); d.endItem();
@@ -2788,23 +2786,23 @@ static void qDumpQSharedPointer(QDumper &d)
if (ptr.isNull()) { if (ptr.isNull()) {
d.putItem("value", "<null>"); d.putItem("value", "<null>");
d.putItem("valuedisabled", "true"); d.putItem("valueeditable", "false");
d.putItem("numchild", 0); d.putItem("numchild", 0);
d.disarm(); d.disarm();
return; return;
} }
if (isSimpleType(d.innertype)) if (isSimpleType(d.innerType))
qDumpInnerValueHelper(d, d.innertype, ptr.data()); qDumpInnerValueHelper(d, d.innerType, ptr.data());
else else
d.putItem("value", ""); d.putItem("value", "");
d.putItem("valuedisabled", "true"); d.putItem("valueeditable", "false");
d.putItem("numchild", 1); d.putItem("numchild", 1);
if (d.dumpChildren) { if (d.dumpChildren) {
d.beginChildren(); d.beginChildren();
d.beginHash(); d.beginHash();
d.putItem("name", "data"); d.putItem("name", "data");
qDumpInnerValue(d, d.innertype, ptr.data()); qDumpInnerValue(d, d.innerType, ptr.data());
d.endHash(); d.endHash();
const int v = sizeof(void *); const int v = sizeof(void *);
d.beginHash(); d.beginHash();
@@ -2868,7 +2866,7 @@ static void qDumpQStringList(QDumper &d)
} }
d.putItemCount("value", n); d.putItemCount("value", n);
d.putItem("valuedisabled", "true"); d.putItem("valueeditable", "false");
d.putItem("numchild", n); d.putItem("numchild", n);
if (d.dumpChildren) { if (d.dumpChildren) {
if (n > 1000) if (n > 1000)
@@ -2926,18 +2924,18 @@ static void qDumpQVector(QDumper &d)
int n = nn; int n = nn;
d.putItemCount("value", n); d.putItemCount("value", n);
d.putItem("valuedisabled", "true"); d.putItem("valueeditable", "false");
d.putItem("numchild", n); d.putItem("numchild", n);
if (d.dumpChildren) { if (d.dumpChildren) {
QByteArray strippedInnerType = stripPointerType(d.innertype); QByteArray strippedInnerType = stripPointerType(d.innerType);
const char *stripped = const char *stripped =
isPointerType(d.innertype) ? strippedInnerType.data() : 0; isPointerType(d.innerType) ? strippedInnerType.data() : 0;
if (n > 1000) if (n > 1000)
n = 1000; n = 1000;
d.beginChildren(d.innertype); d.beginChildren(d.innerType);
for (int i = 0; i != n; ++i) { for (int i = 0; i != n; ++i) {
d.beginHash(); d.beginHash();
qDumpInnerValueOrPointer(d, d.innertype, stripped, qDumpInnerValueOrPointer(d, d.innerType, stripped,
addOffset(v, i * innersize + typeddatasize)); addOffset(v, i * innersize + typeddatasize));
d.endHash(); d.endHash();
} }
@@ -2958,23 +2956,23 @@ static void qDumpQWeakPointer(QDumper &d)
if (value == 0 || data == 0) { if (value == 0 || data == 0) {
d.putItem("value", "<null>"); d.putItem("value", "<null>");
d.putItem("valuedisabled", "true"); d.putItem("valueeditable", "false");
d.putItem("numchild", 0); d.putItem("numchild", 0);
d.disarm(); d.disarm();
return; return;
} }
if (isSimpleType(d.innertype)) if (isSimpleType(d.innerType))
qDumpInnerValueHelper(d, d.innertype, value); qDumpInnerValueHelper(d, d.innerType, value);
else else
d.putItem("value", ""); d.putItem("value", "");
d.putItem("valuedisabled", "true"); d.putItem("valueeditable", "false");
d.putItem("numchild", 1); d.putItem("numchild", 1);
if (d.dumpChildren) { if (d.dumpChildren) {
d.beginChildren(); d.beginChildren();
d.beginHash(); d.beginHash();
d.putItem("name", "data"); d.putItem("name", "data");
qDumpInnerValue(d, d.innertype, value); qDumpInnerValue(d, d.innerType, value);
d.endHash(); d.endHash();
d.beginHash(); d.beginHash();
const void *weak = addOffset(deref(d.data), v); const void *weak = addOffset(deref(d.data), v);
@@ -3034,16 +3032,16 @@ static void qDumpStdList(QDumper &d)
d.putItemCount("value", nn); d.putItemCount("value", nn);
d.putItem("numchild", nn); d.putItem("numchild", nn);
d.putItem("valuedisabled", "true"); d.putItem("valueeditable", "false");
if (d.dumpChildren) { if (d.dumpChildren) {
QByteArray strippedInnerType = stripPointerType(d.innertype); QByteArray strippedInnerType = stripPointerType(d.innerType);
const char *stripped = const char *stripped =
isPointerType(d.innertype) ? strippedInnerType.data() : 0; isPointerType(d.innerType) ? strippedInnerType.data() : 0;
d.beginChildren(d.innertype); d.beginChildren(d.innerType);
it = list.begin(); it = list.begin();
for (int i = 0; i < 1000 && it != cend; ++i, ++it) { for (int i = 0; i < 1000 && it != cend; ++i, ++it) {
d.beginHash(); d.beginHash();
qDumpInnerValueOrPointer(d, d.innertype, stripped, it.operator->()); qDumpInnerValueOrPointer(d, d.innerType, stripped, it.operator->());
d.endHash(); d.endHash();
} }
if (it != list.end()) if (it != list.end())
@@ -3078,10 +3076,10 @@ static void qDumpStdMapHelper(QDumper &d)
for (int i = 0; i < nn && i < 10 && it != cend; ++i, ++it) for (int i = 0; i < nn && i < 10 && it != cend; ++i, ++it)
qCheckAccess(it.operator->()); qCheckAccess(it.operator->());
const QByteArray strippedInnerType = stripPointerType(d.innertype); const QByteArray strippedInnerType = stripPointerType(d.innerType);
d.putItem("numchild", nn); d.putItem("numchild", nn);
d.putItemCount("value", nn); d.putItemCount("value", nn);
d.putItem("valuedisabled", "true"); d.putItem("valueeditable", "false");
d.putItem("valueoffset", d.extraInt[2]); d.putItem("valueoffset", d.extraInt[2]);
// HACK: we need a properly const qualified version of the // HACK: we need a properly const qualified version of the
@@ -3105,7 +3103,7 @@ static void qDumpStdMapHelper(QDumper &d)
d.put(" valueOffset: ").put(valueOffset); d.put(" valueOffset: ").put(valueOffset);
d.endItem(); d.endItem();
d.beginChildren(d.innertype); d.beginChildren(d.innerType);
it = map.begin(); it = map.begin();
for (int i = 0; i < 1000 && it != cend; ++i, ++it) { for (int i = 0; i < 1000 && it != cend; ++i, ++it) {
d.beginHash(); d.beginHash();
@@ -3185,26 +3183,26 @@ static void qDumpStdSetHelper(QDumper &d)
qCheckAccess(it.operator->()); qCheckAccess(it.operator->());
d.putItemCount("value", nn); d.putItemCount("value", nn);
d.putItem("valuedisabled", "true"); d.putItem("valueeditable", "false");
d.putItem("numchild", nn); d.putItem("numchild", nn);
d.putItem("valueoffset", d.extraInt[0]); d.putItem("valueoffset", d.extraInt[0]);
if (d.dumpChildren) { if (d.dumpChildren) {
int valueOffset = 0; // d.extraInt[0]; int valueOffset = 0; // d.extraInt[0];
QByteArray strippedInnerType = stripPointerType(d.innertype); QByteArray strippedInnerType = stripPointerType(d.innerType);
const char *stripped = const char *stripped =
isPointerType(d.innertype) ? strippedInnerType.data() : 0; isPointerType(d.innerType) ? strippedInnerType.data() : 0;
d.beginItem("extra"); d.beginItem("extra");
d.put("valueOffset: ").put(valueOffset); d.put("valueOffset: ").put(valueOffset);
d.endItem(); d.endItem();
d.beginChildren(d.innertype); d.beginChildren(d.innerType);
it = set.begin(); it = set.begin();
for (int i = 0; i < 1000 && it != cend; ++i, ++it) { for (int i = 0; i < 1000 && it != cend; ++i, ++it) {
const void *node = it.operator->(); const void *node = it.operator->();
d.beginHash(); d.beginHash();
qDumpInnerValueOrPointer(d, d.innertype, stripped, node); qDumpInnerValueOrPointer(d, d.innerType, stripped, node);
d.endHash(); d.endHash();
} }
if (it != set.end()) if (it != set.end())
@@ -3295,19 +3293,19 @@ static void qDumpStdVector(QDumper &d)
int n = nn; int n = nn;
d.putItemCount("value", n); d.putItemCount("value", n);
d.putItem("valuedisabled", "true"); d.putItem("valueeditable", "false");
d.putItem("numchild", n); d.putItem("numchild", n);
if (d.dumpChildren) { if (d.dumpChildren) {
unsigned innersize = d.extraInt[0]; unsigned innersize = d.extraInt[0];
QByteArray strippedInnerType = stripPointerType(d.innertype); QByteArray strippedInnerType = stripPointerType(d.innerType);
const char *stripped = const char *stripped =
isPointerType(d.innertype) ? strippedInnerType.data() : 0; isPointerType(d.innerType) ? strippedInnerType.data() : 0;
if (n > 1000) if (n > 1000)
n = 1000; n = 1000;
d.beginChildren(n ? d.innertype : 0); d.beginChildren(n ? d.innerType : 0);
for (int i = 0; i != n; ++i) { for (int i = 0; i != n; ++i) {
d.beginHash(); d.beginHash();
qDumpInnerValueOrPointer(d, d.innertype, stripped, qDumpInnerValueOrPointer(d, d.innerType, stripped,
addOffset(v->start, i * innersize)); addOffset(v->start, i * innersize));
d.endHash(); d.endHash();
} }
@@ -3326,7 +3324,7 @@ static void qDumpStdVectorBool(QDumper &d)
static void handleProtocolVersion2and3(QDumper &d) static void handleProtocolVersion2and3(QDumper &d)
{ {
if (!d.outertype[0]) { if (!d.outerType[0]) {
qDumpUnknown(d); qDumpUnknown(d);
return; return;
} }
@@ -3341,7 +3339,7 @@ static void handleProtocolVersion2and3(QDumper &d)
#ifdef QT_NO_QDATASTREAM #ifdef QT_NO_QDATASTREAM
if (d.protocolVersion == 3) { if (d.protocolVersion == 3) {
QVariant::Type type = QVariant::nameToType(d.outertype); QVariant::Type type = QVariant::nameToType(d.outerType);
if (type != QVariant::Invalid) { if (type != QVariant::Invalid) {
QVariant v(type, d.data); QVariant v(type, d.data);
QByteArray ba; QByteArray ba;
@@ -3352,7 +3350,7 @@ static void handleProtocolVersion2and3(QDumper &d)
} }
#endif #endif
const char *type = stripNamespace(d.outertype); const char *type = stripNamespace(d.outerType);
// type[0] is usally 'Q', so don't use it // type[0] is usally 'Q', so don't use it
switch (type[1]) { switch (type[1]) {
case 'a': case 'a':
@@ -3774,10 +3772,10 @@ void *qDumpObjectData440(
d.extraInt[3] = extraInt3; d.extraInt[3] = extraInt3;
const char *inbuffer = inBuffer; const char *inbuffer = inBuffer;
d.outertype = inbuffer; while (*inbuffer) ++inbuffer; ++inbuffer; d.outerType = inbuffer; while (*inbuffer) ++inbuffer; ++inbuffer;
d.iname = inbuffer; while (*inbuffer) ++inbuffer; ++inbuffer; d.iname = inbuffer; while (*inbuffer) ++inbuffer; ++inbuffer;
d.exp = inbuffer; while (*inbuffer) ++inbuffer; ++inbuffer; d.exp = inbuffer; while (*inbuffer) ++inbuffer; ++inbuffer;
d.innertype = inbuffer; while (*inbuffer) ++inbuffer; ++inbuffer; d.innerType = inbuffer; while (*inbuffer) ++inbuffer; ++inbuffer;
d.iname = inbuffer; while (*inbuffer) ++inbuffer; ++inbuffer; d.iname = inbuffer; while (*inbuffer) ++inbuffer; ++inbuffer;
handleProtocolVersion2and3(d); handleProtocolVersion2and3(d);

View File

@@ -319,9 +319,7 @@ void DebuggerManager::init()
//qRegisterMetaType<WatchData>("Debugger::Internal::WatchData"); //qRegisterMetaType<WatchData>("Debugger::Internal::WatchData");
qRegisterMetaType<WatchData>("WatchData"); qRegisterMetaType<WatchData>("WatchData");
connect(m_watchHandler, SIGNAL(watchDataUpdateNeeded(WatchData)), connect(m_watchHandler, SIGNAL(watchDataUpdateNeeded(WatchData)),
this, SLOT(updateWatchDataAnnounce())); this, SLOT(updateWatchData(WatchData)));
connect(m_watchHandler, SIGNAL(watchDataUpdateNeeded(WatchData)),
this, SLOT(updateWatchData(WatchData)), Qt::QueuedConnection);
m_continueAction = new QAction(this); m_continueAction = new QAction(this);
m_continueAction->setText(tr("Continue")); m_continueAction->setText(tr("Continue"));
@@ -695,12 +693,6 @@ void DebuggerManager::updateWatchData(const WatchData &data)
m_engine->updateWatchData(data); m_engine->updateWatchData(data);
} }
void DebuggerManager::updateWatchDataAnnounce()
{
if (m_engine)
m_engine->updateWatchDataAnnounce();
}
static inline QString msgEngineNotAvailable(const char *engine) static inline QString msgEngineNotAvailable(const char *engine)
{ {
return DebuggerManager::tr("The application requires the debugger engine '%1', which is disabled.").arg(QLatin1String(engine)); return DebuggerManager::tr("The application requires the debugger engine '%1', which is disabled.").arg(QLatin1String(engine));

View File

@@ -57,6 +57,7 @@
#include <QtCore/QDebug> #include <QtCore/QDebug>
#include <QtCore/QDir> #include <QtCore/QDir>
#include <QtCore/QFileInfo> #include <QtCore/QFileInfo>
#include <QtCore/QMetaObject>
#include <QtCore/QTime> #include <QtCore/QTime>
#include <QtCore/QTimer> #include <QtCore/QTimer>
#include <QtCore/QTextStream> #include <QtCore/QTextStream>
@@ -2814,12 +2815,20 @@ static void setWatchDataChildCount(WatchData &data, const GdbMi &mi)
data.setHasChildren(mi.data().toInt() > 0); data.setHasChildren(mi.data().toInt() > 0);
} }
static void setWatchDataValueDisabled(WatchData &data, const GdbMi &mi) static void setWatchDataValueEnabled(WatchData &data, const GdbMi &mi)
{ {
if (mi.data() == "true") if (mi.data() == "true")
data.valuedisabled = true; data.valueEnabled = true;
else if (mi.data() == "false") else if (mi.data() == "false")
data.valuedisabled = false; data.valueEnabled = false;
}
static void setWatchDataValueEditable(WatchData &data, const GdbMi &mi)
{
if (mi.data() == "true")
data.valueEditable = true;
else if (mi.data() == "false")
data.valueEditable = false;
} }
static void setWatchDataExpression(WatchData &data, const GdbMi &mi) static void setWatchDataExpression(WatchData &data, const GdbMi &mi)
@@ -3127,20 +3136,26 @@ void GdbEngine::updateSubItem(const WatchData &data0)
QTC_ASSERT(false, return); QTC_ASSERT(false, return);
} }
void GdbEngine::updateWatchDataAnnounce() void GdbEngine::updateWatchData(const WatchData &data)
{ {
// Bump requests to avoid model rebuilding during the nested // Bump requests to avoid model rebuilding during the nested
// updateWatchModel runs. // updateWatchModel runs.
++m_pendingRequests; ++m_pendingRequests;
#if 1
QMetaObject::invokeMethod(this, "updateWatchDataHelper",
Qt::QueuedConnection, Q_ARG(WatchData, data));
#else
updateWatchDataHelper(data);
#endif
} }
void GdbEngine::updateWatchData(const WatchData &data) void GdbEngine::updateWatchDataHelper(const WatchData &data)
{ {
//m_pendingRequests = 0; //m_pendingRequests = 0;
PENDING_DEBUG("UPDATE WATCH DATA"); PENDING_DEBUG("UPDATE WATCH DATA");
#if DEBUG_PENDING #if DEBUG_PENDING
//qDebug() << "##############################################"; //qDebug() << "##############################################";
//qDebug() << "UPDATE MODEL, FOUND INCOMPLETE:"; qDebug() << "UPDATE MODEL, FOUND INCOMPLETE:";
//qDebug() << data.toString(); //qDebug() << data.toString();
#endif #endif
@@ -3153,9 +3168,11 @@ void GdbEngine::updateWatchData(const WatchData &data)
void GdbEngine::rebuildModel() void GdbEngine::rebuildModel()
{ {
static int count = 0;
++count;
m_processedNames.clear(); m_processedNames.clear();
PENDING_DEBUG("REBUILDING MODEL"); PENDING_DEBUG("REBUILDING MODEL" << count);
emit gdbInputAvailable(LogStatus, _("<Rebuild Watchmodel>")); emit gdbInputAvailable(LogStatus, _("<Rebuild Watchmodel %1>").arg(count));
q->showStatusMessage(tr("Finished retrieving data."), 400); q->showStatusMessage(tr("Finished retrieving data."), 400);
qq->watchHandler()->endCycle(); qq->watchHandler()->endCycle();
showToolTip(); showToolTip();
@@ -3330,7 +3347,8 @@ void GdbEngine::handleVarCreate(const GdbResultRecord &record,
data.type = _(" "); data.type = _(" ");
data.setAllUnneeded(); data.setAllUnneeded();
data.setHasChildren(false); data.setHasChildren(false);
data.valuedisabled = true; data.valueEnabled = false;
data.valueEditable = false;
insertData(data); insertData(data);
} }
} }
@@ -3445,7 +3463,8 @@ void GdbEngine::handleChildren(const WatchData &data0, const GdbMi &item,
setWatchDataSAddress(data, item.findChild("saddr")); setWatchDataSAddress(data, item.findChild("saddr"));
setWatchDataValueToolTip(data, item.findChild("valuetooltip"), setWatchDataValueToolTip(data, item.findChild("valuetooltip"),
item.findChild("valuetooltipencoded").data().toInt()); item.findChild("valuetooltipencoded").data().toInt());
setWatchDataValueDisabled(data, item.findChild("valuedisabled")); setWatchDataValueEnabled(data, item.findChild("valueenabled"));
setWatchDataValueEditable(data, item.findChild("valueeditable"));
//qDebug() << "HANDLE CHILDREN: " << data.toString(); //qDebug() << "HANDLE CHILDREN: " << data.toString();
list->append(data); list->append(data);
@@ -3495,7 +3514,7 @@ void GdbEngine::handleDebuggingHelperValue3(const GdbResultRecord &record,
// << " STREAM:" << out; // << " STREAM:" << out;
if (list.isEmpty()) { if (list.isEmpty()) {
//: Value for variable //: Value for variable
data.setValue(strNotInScope); data.setError(strNotInScope);
data.setAllUnneeded(); data.setAllUnneeded();
insertData(data); insertData(data);
} else if (data.type == __("QString") } else if (data.type == __("QString")
@@ -3540,13 +3559,13 @@ void GdbEngine::handleDebuggingHelperValue3(const GdbResultRecord &record,
} }
} else { } else {
//: Value for variable //: Value for variable
data.setValue(strNotInScope); data.setError(strNotInScope);
data.setAllUnneeded(); data.setAllUnneeded();
insertData(data); insertData(data);
} }
} else if (record.resultClass == GdbResultError) { } else if (record.resultClass == GdbResultError) {
WatchData data = cookie.value<WatchData>(); WatchData data = cookie.value<WatchData>();
data.setValue(strNotInScope); data.setError(strNotInScope);
data.setAllUnneeded(); data.setAllUnneeded();
insertData(data); insertData(data);
} }
@@ -3628,6 +3647,7 @@ void GdbEngine::setLocals(const QList<GdbMi> &locals)
//qDebug() << m_varToType; //qDebug() << m_varToType;
QMap<QByteArray, int> seen; QMap<QByteArray, int> seen;
QList<WatchData> list;
foreach (const GdbMi &item, locals) { foreach (const GdbMi &item, locals) {
// Local variables of inlined code are reported as // Local variables of inlined code are reported as
// 26^done,locals={varobj={exp="this",value="",name="var4",exp="this", // 26^done,locals={varobj={exp="this",value="",name="var4",exp="this",
@@ -3657,7 +3677,7 @@ void GdbEngine::setLocals(const QList<GdbMi> &locals)
//variable of the same name in a nested block //variable of the same name in a nested block
data.setType(tr("<shadowed>")); data.setType(tr("<shadowed>"));
data.setHasChildren(false); data.setHasChildren(false);
insertData(data); list.append(data);
} else { } else {
seen[name] = 1; seen[name] = 1;
WatchData data; WatchData data;
@@ -3679,9 +3699,10 @@ void GdbEngine::setLocals(const QList<GdbMi> &locals)
qDebug() << "RE-USING" << m_varToType.value(data.framekey); qDebug() << "RE-USING" << m_varToType.value(data.framekey);
data.setType(m_varToType.value(data.framekey)); data.setType(m_varToType.value(data.framekey));
} }
insertData(data); list.append(data);
} }
} }
qq->watchHandler()->insertBulkData(list);
} }
void GdbEngine::insertData(const WatchData &data0) void GdbEngine::insertData(const WatchData &data0)
@@ -3698,7 +3719,6 @@ void GdbEngine::insertData(const WatchData &data0)
void GdbEngine::handleVarListChildrenHelper(const GdbMi &item, void GdbEngine::handleVarListChildrenHelper(const GdbMi &item,
const WatchData &parent) const WatchData &parent)
{ {
//qDebug() << "VAR_LIST_CHILDREN: PARENT 2" << parent.toString();
//qDebug() << "VAR_LIST_CHILDREN: APPENDEE" << data.toString(); //qDebug() << "VAR_LIST_CHILDREN: APPENDEE" << data.toString();
QByteArray exp = item.findChild("exp").data(); QByteArray exp = item.findChild("exp").data();
QByteArray name = item.findChild("name").data(); QByteArray name = item.findChild("name").data();

View File

@@ -332,7 +332,7 @@ private:
void updateSubItem(const WatchData &data); void updateSubItem(const WatchData &data);
void updateWatchData(const WatchData &data); void updateWatchData(const WatchData &data);
void updateWatchDataAnnounce(); Q_SLOT void updateWatchDataHelper(const WatchData &data);
void rebuildModel(); void rebuildModel();
void insertData(const WatchData &data); void insertData(const WatchData &data);

View File

@@ -63,7 +63,6 @@ public:
virtual bool startDebugger(const QSharedPointer<DebuggerStartParameters> &startParameters) = 0; virtual bool startDebugger(const QSharedPointer<DebuggerStartParameters> &startParameters) = 0;
virtual void exitDebugger() = 0; virtual void exitDebugger() = 0;
virtual void detachDebugger() {} virtual void detachDebugger() {}
virtual void updateWatchDataAnnounce() {}
virtual void updateWatchData(const WatchData &data) = 0; virtual void updateWatchData(const WatchData &data) = 0;
virtual void stepExec() = 0; virtual void stepExec() = 0;

View File

@@ -0,0 +1,87 @@
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** GNU Lesser General Public License Usage
**
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at http://qt.nokia.com/contact.
**
**************************************************************************/
#include <QtCore/QCoreApplication>
#include <QtCore/QDebug>
#include <QtCore/QProcess>
#if defined(Q_OS_LINUX)
#include <stdio.h>
#include <signal.h>
#include <execinfo.h>
#endif
namespace Debugger {
namespace Internal {
void dumpBacktrace(int maxdepth)
{
if (maxdepth == -1)
maxdepth = 200;
#if defined(Q_OS_LINUX)
void *bt[200] = {0};
qDebug() << "BACKTRACE:";
int size = backtrace(bt, sizeof(bt) / sizeof(bt[0]));
for (int i = 0; i < qMin(size, maxdepth); i++)
qDebug() << "0x" + QByteArray::number(quintptr(bt[i]), 16);
QProcess proc;
QStringList args;
args.append("-e");
args.append(QCoreApplication::arguments().at(0));
proc.start("addr2line", args);
proc.waitForStarted();
for (int i = 0; i < qMin(size, maxdepth); i++)
proc.write("0x" + QByteArray::number(quintptr(bt[i]), 16) + "\n");
proc.closeWriteChannel();
QByteArray out = proc.readAllStandardOutput();
qDebug() << QCoreApplication::arguments().at(0);
qDebug() << out;
proc.waitForFinished();
out = proc.readAllStandardOutput();
qDebug() << out;
#endif
}
/*
void installSignalHandlers()
{
#if defined(Q_OS_LINUX)
struct sigaction SignalAction;
SignalAction.sa_sigaction = handler;
sigemptyset(&SignalAction.sa_mask);
SignalAction.sa_flags = SA_SIGINFO;
sigaction(SIGSEGV, &SignalAction, NULL);
sigaction(SIGABRT, &SignalAction, NULL);
#endif
}
*/
} // namespace Internal
} // namespace Debugger

View File

@@ -0,0 +1,43 @@
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** GNU Lesser General Public License Usage
**
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at http://qt.nokia.com/contact.
**
**************************************************************************/
#ifndef DEBUGGER_BACKTRACE_H
#define DEBUGGER_BACKTRACE_H
#include <QtCore/qglobal.h>
namespace Debugger {
namespace Internal {
void dumpBacktrace(int maxdepth = -1);
} // namespace Internal
} // namespace Debugger
#endif // DEBUGGER_BACKTRACE_H

View File

@@ -1,4 +1,8 @@
SOURCES += $$PWD/backtrace.cpp
HEADERS += $$PWD/backtrace.h
win32 { win32 {
INCLUDEPATH+=$$PWD INCLUDEPATH+=$$PWD

View File

@@ -102,19 +102,40 @@ public:
WatchData::WatchData() : WatchData::WatchData() :
hasChildren(false), hasChildren(false),
generation(-1), generation(-1),
valuedisabled(false), valueEnabled(true),
valueEditable(true),
source(0), source(0),
state(InitialState), state(InitialState),
changed(false) changed(false)
{ {
} }
bool WatchData::isEqual(const WatchData &other) const
{
return iname == other.iname
&& exp == other.exp
&& name == other.name
&& value == other.value
&& editvalue == other.editvalue
&& valuetooltip == other.valuetooltip
&& type == other.type
&& displayedType == other.displayedType
&& variable == other.variable
&& addr == other.addr
&& saddr == other.saddr
&& framekey == other.framekey
&& hasChildren == other.hasChildren
&& valueEnabled == other.valueEnabled
&& valueEditable == other.valueEditable;
}
void WatchData::setError(const QString &msg) void WatchData::setError(const QString &msg)
{ {
setAllUnneeded(); setAllUnneeded();
value = msg; value = msg;
setHasChildren(false); setHasChildren(false);
valuedisabled = true; valueEnabled = false;
valueEditable = false;
} }
void WatchData::setValue(const QString &value0) void WatchData::setValue(const QString &value0)
@@ -276,6 +297,8 @@ QString WatchData::toToolTip() const
formatToolTipRow(str, WatchHandler::tr("Object Address"), addr); formatToolTipRow(str, WatchHandler::tr("Object Address"), addr);
formatToolTipRow(str, WatchHandler::tr("Stored Address"), saddr); formatToolTipRow(str, WatchHandler::tr("Stored Address"), saddr);
formatToolTipRow(str, WatchHandler::tr("Internal ID"), iname); formatToolTipRow(str, WatchHandler::tr("Internal ID"), iname);
formatToolTipRow(str, WatchHandler::tr("Generation"),
QString::number(generation));
str << "</table></body></html>"; str << "</table></body></html>";
return res; return res;
} }
@@ -330,6 +353,33 @@ void WatchModel::reinitialize()
endRemoveRows(); endRemoveRows();
} }
void WatchModel::beginCycle()
{
emit enableUpdates(false);
}
void WatchModel::endCycle()
{
removeOutdated();
emit enableUpdates(true);
}
void WatchModel::dump()
{
qDebug() << "\n";
foreach (WatchItem *child, m_root->children)
dumpHelper(child);
}
void WatchModel::dumpHelper(WatchItem *item)
{
qDebug() << "ITEM: " << item->iname
<< (item->parent ? item->parent->iname : "<none>")
<< item->generation;
foreach (WatchItem *child, item->children)
dumpHelper(child);
}
void WatchModel::removeOutdated() void WatchModel::removeOutdated()
{ {
foreach (WatchItem *child, m_root->children) foreach (WatchItem *child, m_root->children)
@@ -343,9 +393,9 @@ void WatchModel::removeOutdated()
void WatchModel::removeOutdatedHelper(WatchItem *item) void WatchModel::removeOutdatedHelper(WatchItem *item)
{ {
if (item->generation < generationCounter) if (item->generation < generationCounter) {
removeItem(item); removeItem(item);
else { } else {
foreach (WatchItem *child, item->children) foreach (WatchItem *child, item->children)
removeOutdatedHelper(child); removeOutdatedHelper(child);
item->fetchTriggered = false; item->fetchTriggered = false;
@@ -407,9 +457,9 @@ QString niceType(const QString typeIn)
{ {
static QMap<QString, QString> cache; static QMap<QString, QString> cache;
const QMap<QString, QString>::const_iterator it = cache.constFind(typeIn); const QMap<QString, QString>::const_iterator it = cache.constFind(typeIn);
if (it != cache.constEnd()) { if (it != cache.constEnd())
return it.value(); return it.value();
}
QString type = typeIn; QString type = typeIn;
type.replace(QLatin1Char('*'), QLatin1Char('@')); type.replace(QLatin1Char('*'), QLatin1Char('@'));
@@ -434,23 +484,23 @@ QString niceType(const QString typeIn)
QString inner = alloc.mid(15, alloc.size() - 16).trimmed(); QString inner = alloc.mid(15, alloc.size() - 16).trimmed();
if (inner == QLatin1String("char")) { // std::string if (inner == QLatin1String("char")) { // std::string
static const QRegExp stringRegexp = stdStringRegExp(inner); const QRegExp stringRegexp = stdStringRegExp(inner);
type.replace(stringRegexp, QLatin1String("string")); type.replace(stringRegexp, QLatin1String("string"));
} else if (inner == QLatin1String("wchar_t")) { // std::wstring } else if (inner == QLatin1String("wchar_t")) { // std::wstring
static const QRegExp wchartStringRegexp = stdStringRegExp(inner); const QRegExp wchartStringRegexp = stdStringRegExp(inner);
type.replace(wchartStringRegexp, QLatin1String("wstring")); type.replace(wchartStringRegexp, QLatin1String("wstring"));
} else if (inner == QLatin1String("unsigned short")) { // std::wstring/MSVC } else if (inner == QLatin1String("unsigned short")) { // std::wstring/MSVC
static const QRegExp usStringRegexp = stdStringRegExp(inner); const QRegExp usStringRegexp = stdStringRegExp(inner);
type.replace(usStringRegexp, QLatin1String("wstring")); type.replace(usStringRegexp, QLatin1String("wstring"));
} }
// std::vector, std::deque, std::list // std::vector, std::deque, std::list
static const QRegExp re1(QString::fromLatin1("(vector|list|deque)<%1,[ ]?%2\\s*>").arg(inner, alloc)); const QRegExp re1(QString::fromLatin1("(vector|list|deque)<%1, ?%2\\s*>").arg(inner, alloc));
Q_ASSERT(re1.isValid()); Q_ASSERT(re1.isValid());
if (re1.indexIn(type) != -1) if (re1.indexIn(type) != -1)
type.replace(re1.cap(0), QString::fromLatin1("%1<%2>").arg(re1.cap(1), inner)); type.replace(re1.cap(0), QString::fromLatin1("%1<%2>").arg(re1.cap(1), inner));
// std::stack // std::stack
static QRegExp re6(QString::fromLatin1("stack<%1,[ ]?std::deque<%2> >").arg(inner, inner)); QRegExp re6(QString::fromLatin1("stack<%1, ?std::deque<%2> >").arg(inner, inner));
if (!re6.isMinimal()) if (!re6.isMinimal())
re6.setMinimal(true); re6.setMinimal(true);
Q_ASSERT(re6.isValid()); Q_ASSERT(re6.isValid());
@@ -458,7 +508,7 @@ QString niceType(const QString typeIn)
type.replace(re6.cap(0), QString::fromLatin1("stack<%1>").arg(inner)); type.replace(re6.cap(0), QString::fromLatin1("stack<%1>").arg(inner));
// std::set // std::set
static QRegExp re4(QString::fromLatin1("set<%1,[ ]?std::less<%2>,[ ]?%3\\s*>").arg(inner, inner, alloc)); QRegExp re4(QString::fromLatin1("set<%1, ?std::less<%2>, ?%3\\s*>").arg(inner, inner, alloc));
if (!re4.isMinimal()) if (!re4.isMinimal())
re4.setMinimal(true); re4.setMinimal(true);
Q_ASSERT(re4.isValid()); Q_ASSERT(re4.isValid());
@@ -481,17 +531,16 @@ QString niceType(const QString typeIn)
} }
QString ckey = inner.mid(10, pos - 10); QString ckey = inner.mid(10, pos - 10);
QString key = chopConst(ckey); QString key = chopConst(ckey);
QString value = inner.mid(pos + 2, inner.size() - 3 - pos); QString value = inner.mid(pos + 2, inner.size() - 3 - pos).trimmed();
QRegExp re5(QString("map<%1, ?%2, ?std::less<%3 ?>, ?%4\\s*>")
static QRegExp re5(QString("map<%1,[ ]?%2,[ ]?std::less<%3>,[ ]?%4\\s*>")
.arg(key, value, key, alloc)); .arg(key, value, key, alloc));
if (!re5.isMinimal()) if (!re5.isMinimal())
re5.setMinimal(true); re5.setMinimal(true);
Q_ASSERT(re5.isValid()); Q_ASSERT(re5.isValid());
if (re5.indexIn(type) != -1) if (re5.indexIn(type) != -1) {
type.replace(re5.cap(0), QString("map<%1, %2>").arg(key, value)); type.replace(re5.cap(0), QString("map<%1, %2>").arg(key, value));
else { } else {
static QRegExp re7(QString("map<const %1,[ ]?%2,[ ]?std::less<const %3>,[ ]?%4\\s*>") QRegExp re7(QString("map<const %1, ?%2, ?std::less<const %3>, ?%4\\s*>")
.arg(key, value, key, alloc)); .arg(key, value, key, alloc));
if (!re7.isMinimal()) if (!re7.isMinimal())
re7.setMinimal(true); re7.setMinimal(true);
@@ -657,7 +706,7 @@ QVariant WatchModel::data(const QModelIndex &idx, int role) const
static const QVariant red(QColor(200, 0, 0)); static const QVariant red(QColor(200, 0, 0));
static const QVariant gray(QColor(140, 140, 140)); static const QVariant gray(QColor(140, 140, 140));
switch (idx.column()) { switch (idx.column()) {
case 1: return data.valuedisabled ? gray : data.changed ? red : QVariant(); case 1: return !data.valueEnabled ? gray : data.changed ? red : QVariant();
} }
break; break;
} }
@@ -751,9 +800,9 @@ Qt::ItemFlags WatchModel::flags(const QModelIndex &idx) const
return editable; // watcher names are editable return editable; // watcher names are editable
if (data.isWatcher() && idx.column() == 2) if (data.isWatcher() && idx.column() == 2)
return editable; // watcher types are return editable; // watcher types are
if (idx.column() == 1) if (idx.column() == 1 && data.valueEditable)
return editable; // locals and watcher values are editable return editable; // locals and watcher values are sometimes editable
return notEditable; return notEditable;
} }
QVariant WatchModel::headerData(int section, Qt::Orientation orientation, int role) const QVariant WatchModel::headerData(int section, Qt::Orientation orientation, int role) const
@@ -775,7 +824,7 @@ struct IName : public QString
IName(const QString &iname) : QString(iname) {} IName(const QString &iname) : QString(iname) {}
}; };
bool operator<(const IName &iname1, const IName &iname2) bool iNameLess(const QString &iname1, const QString &iname2)
{ {
QString name1 = iname1.section('.', -1); QString name1 = iname1.section('.', -1);
QString name2 = iname2.section('.', -1); QString name2 = iname2.section('.', -1);
@@ -790,10 +839,14 @@ bool operator<(const IName &iname1, const IName &iname2)
return name1 < name2; return name1 < name2;
} }
bool operator<(const IName &iname1, const IName &iname2)
{
return iNameLess(iname1, iname2);
}
static bool iNameSorter(const WatchItem *item1, const WatchItem *item2) static bool iNameSorter(const WatchItem *item1, const WatchItem *item2)
{ {
return IName(item1->iname) < IName(item2->iname); return iNameLess(item1->iname, item2->iname);
} }
static int findInsertPosition(const QList<WatchItem *> &list, const WatchItem *item) static int findInsertPosition(const QList<WatchItem *> &list, const WatchItem *item)
@@ -806,7 +859,7 @@ static int findInsertPosition(const QList<WatchItem *> &list, const WatchItem *i
void WatchModel::insertData(const WatchData &data) void WatchModel::insertData(const WatchData &data)
{ {
// qDebug() << "WMI:" << data.toString(); // qDebug() << "WMI:" << data.toString();
static int bulk = 0; //static int bulk = 0;
//qDebug() << "SINGLE: " << ++bulk << data.toString(); //qDebug() << "SINGLE: " << ++bulk << data.toString();
QTC_ASSERT(!data.iname.isEmpty(), return); QTC_ASSERT(!data.iname.isEmpty(), return);
WatchItem *parent = findItem(parentName(data.iname), m_root); WatchItem *parent = findItem(parentName(data.iname), m_root);
@@ -845,8 +898,16 @@ void WatchModel::insertData(const WatchData &data)
void WatchModel::insertBulkData(const QList<WatchData> &list) void WatchModel::insertBulkData(const QList<WatchData> &list)
{ {
#if 1
for (int i = 0; i != list.size(); ++i)
insertData(list.at(i));
return;
#endif
// This method does not properly insert items in proper "iname sort
// order", leading to random removal of items in removeOutDated();
//qDebug() << "WMI:" << list.toString(); //qDebug() << "WMI:" << list.toString();
static int bulk = 0; //static int bulk = 0;
//foreach (const WatchItem &data, list) //foreach (const WatchItem &data, list)
// qDebug() << "BULK: " << ++bulk << data.toString(); // qDebug() << "BULK: " << ++bulk << data.toString();
QTC_ASSERT(!list.isEmpty(), return); QTC_ASSERT(!list.isEmpty(), return);
@@ -885,22 +946,39 @@ void WatchModel::insertBulkData(const QList<WatchData> &list)
foreach (WatchItem *oldItem, parent->children) { foreach (WatchItem *oldItem, parent->children) {
Iterator it = newList.find(oldItem->iname); Iterator it = newList.find(oldItem->iname);
if (it == newList.end()) { if (it == newList.end()) {
newList[oldItem->iname] = *oldItem; WatchData data = *oldItem;
data.generation = generationCounter;
newList[oldItem->iname] = data;
} else { } else {
bool changed = !it->value.isEmpty() bool changed = !it->value.isEmpty()
&& it->value != oldItem->value && it->value != oldItem->value
&& it->value != strNotInScope; && it->value != strNotInScope;
it->changed = changed; it->changed = changed;
it->generation = generationCounter; if (it->generation == -1)
it->generation = generationCounter;
} }
} }
for (Iterator it = newList.begin(); it != newList.end(); ++it) {
qDebug() << " NEW: " << it->iname;
}
// overwrite existing items // overwrite existing items
Iterator it = newList.begin(); Iterator it = newList.begin();
const int oldCount = parent->children.size();
for (int i = 0; i < oldCount; ++i, ++it)
parent->children[i]->setData(*it);
QModelIndex idx = watchIndex(parent); QModelIndex idx = watchIndex(parent);
const int oldCount = parent->children.size();
for (int i = 0; i < oldCount; ++i, ++it) {
if (!parent->children[i]->isEqual(*it)) {
qDebug() << "REPLACING" << parent->children.at(i)->iname
<< " WITH " << it->iname << it->generation;
parent->children[i]->setData(*it);
if (parent->children[i]->generation == -1)
parent->children[i]->generation = generationCounter;
//emit dataChanged(idx.sibling(i, 0), idx.sibling(i, 2));
} else {
//qDebug() << "SKIPPING REPLACEMENT" << parent->children.at(i)->iname;
}
}
emit dataChanged(idx.sibling(0, 0), idx.sibling(oldCount - 1, 2)); emit dataChanged(idx.sibling(0, 0), idx.sibling(oldCount - 1, 2));
// add new items // add new items
@@ -909,13 +987,17 @@ void WatchModel::insertBulkData(const QList<WatchData> &list)
//MODEL_DEBUG("INSERT : " << data.iname << data.value); //MODEL_DEBUG("INSERT : " << data.iname << data.value);
for (int i = oldCount; i < newList.size(); ++i, ++it) { for (int i = oldCount; i < newList.size(); ++i, ++it) {
WatchItem *item = new WatchItem(*it); WatchItem *item = new WatchItem(*it);
qDebug() << "ADDING" << it->iname;
item->parent = parent; item->parent = parent;
item->generation = generationCounter; if (item->generation == -1)
item->generation = generationCounter;
item->changed = true; item->changed = true;
parent->children.append(item); parent->children.append(item);
} }
endInsertRows(); endInsertRows();
} }
//qDebug() << "ITEMS: " << parent->children.size();
dump();
} }
WatchItem *WatchModel::findItem(const QString &iname, WatchItem *root) const WatchItem *WatchModel::findItem(const QString &iname, WatchItem *root) const
@@ -965,11 +1047,20 @@ WatchHandler::WatchHandler()
SIGNAL(triggered()), this, SLOT(removeWatchExpression())); SIGNAL(triggered()), this, SLOT(removeWatchExpression()));
} }
void WatchHandler::beginCycle()
{
++generationCounter;
m_locals->beginCycle();
m_watchers->beginCycle();
m_tooltips->beginCycle();
}
void WatchHandler::endCycle() void WatchHandler::endCycle()
{ {
m_locals->removeOutdated(); //qDebug() << "END CYCLE";
m_watchers->removeOutdated(); m_locals->endCycle();
m_tooltips->removeOutdated(); m_watchers->endCycle();
m_tooltips->endCycle();
} }
void WatchHandler::cleanup() void WatchHandler::cleanup()
@@ -1004,7 +1095,7 @@ void WatchHandler::insertData(const WatchData &data)
// bulk-insertion // bulk-insertion
void WatchHandler::insertBulkData(const QList<WatchData> &list) void WatchHandler::insertBulkData(const QList<WatchData> &list)
{ {
#if 1 #if 0
foreach (const WatchItem &data, list) foreach (const WatchItem &data, list)
insertData(data); insertData(data);
return; return;
@@ -1015,16 +1106,20 @@ void WatchHandler::insertBulkData(const QList<WatchData> &list)
QMap<QString, QList<WatchData> > hash; QMap<QString, QList<WatchData> > hash;
foreach (const WatchData &data, list) { foreach (const WatchData &data, list) {
if (data.isSomethingNeeded()) // we insert everything, including incomplete stuff
emit watchDataUpdateNeeded(data); // to reduce the number of row add operations in the model.
else hash[parentName(data.iname)].append(data);
hash[parentName(data.iname)].append(data);
} }
foreach (const QString &parentIName, hash.keys()) { foreach (const QString &parentIName, hash.keys()) {
WatchModel *model = modelForIName(parentIName); WatchModel *model = modelForIName(parentIName);
QTC_ASSERT(model, return); QTC_ASSERT(model, return);
model->insertBulkData(hash[parentIName]); model->insertBulkData(hash[parentIName]);
} }
foreach (const WatchData &data, list) {
if (data.isSomethingNeeded())
emit watchDataUpdateNeeded(data);
}
} }
void WatchHandler::removeData(const QString &iname) void WatchHandler::removeData(const QString &iname)
@@ -1157,12 +1252,6 @@ void WatchHandler::removeWatchExpression(const QString &exp)
} }
} }
void WatchHandler::beginCycle()
{
++generationCounter;
//m_locals->beginCycle();
}
void WatchHandler::updateWatchers() void WatchHandler::updateWatchers()
{ {
//qDebug() << "UPDATE WATCHERS"; //qDebug() << "UPDATE WATCHERS";

View File

@@ -112,6 +112,8 @@ public:
bool isWatcher() const { return iname.startsWith(QLatin1String("watch.")); } bool isWatcher() const { return iname.startsWith(QLatin1String("watch.")); }
bool isValid() const { return !iname.isEmpty(); } bool isValid() const { return !iname.isEmpty(); }
bool isEqual(const WatchData &other) const;
public: public:
QString iname; // internal name sth like 'local.baz.public.a' QString iname; // internal name sth like 'local.baz.public.a'
QString exp; // the expression QString exp; // the expression
@@ -128,7 +130,8 @@ public:
QScriptValue scriptValue; // if needed... QScriptValue scriptValue; // if needed...
bool hasChildren; bool hasChildren;
int generation; // when updated? int generation; // when updated?
bool valuedisabled; // value will be greyed out bool valueEnabled; // value will be greyed out or not
bool valueEditable; // value will be editable
private: private:
@@ -204,8 +207,16 @@ private:
void emitDataChanged(int column, void emitDataChanged(int column,
const QModelIndex &parentIndex = QModelIndex()); const QModelIndex &parentIndex = QModelIndex());
void beginCycle(); // called at begin of updateLocals() cycle
void endCycle(); // called after all results have been received
friend QDebug operator<<(QDebug d, const WatchModel &m); friend QDebug operator<<(QDebug d, const WatchModel &m);
void dump();
void dumpHelper(WatchItem *item);
signals:
void enableUpdates(bool);
private: private:
WatchHandler *m_handler; WatchHandler *m_handler;
WatchType m_type; WatchType m_type;

View File

@@ -491,7 +491,7 @@ QtDumperResult::Child::Child() :
keyEncoded(0), keyEncoded(0),
valueEncoded(0), valueEncoded(0),
childCount(-1), childCount(-1),
valuedisabled(false), valueEnabled(true),
valueEncountered(false) valueEncountered(false)
{ {
} }
@@ -499,7 +499,7 @@ QtDumperResult::Child::Child() :
QtDumperResult::QtDumperResult() : QtDumperResult::QtDumperResult() :
valueEncountered(false), valueEncountered(false),
valueEncoded(0), valueEncoded(0),
valuedisabled(false), valueEnabled(true),
childCount(-1), childCount(-1),
internal(false), internal(false),
childChildCount(-1) childChildCount(-1)
@@ -516,7 +516,8 @@ void QtDumperResult::clear()
extra.clear(); extra.clear();
displayedType.clear(); displayedType.clear();
valueEncoded = 0; valueEncoded = 0;
valueEncountered = valuedisabled = false; valueEncountered = false;
valueEnabled = false;
childCount = -1; childCount = -1;
internal = false; internal = false;
childType.clear(); childType.clear();
@@ -535,7 +536,7 @@ QList<WatchData> QtDumperResult::toWatchData(int source) const
root.exp = root.name = lastDotIndex == -1 ? iname : iname.mid(lastDotIndex + 1); root.exp = root.name = lastDotIndex == -1 ? iname : iname.mid(lastDotIndex + 1);
if (valueEncountered) { if (valueEncountered) {
root.setValue(decodeData(value, valueEncoded)); root.setValue(decodeData(value, valueEncoded));
root.valuedisabled = valuedisabled; root.valueEnabled = valueEnabled;
} }
root.setType(type); root.setType(type);
if (!displayedType.isEmpty()) if (!displayedType.isEmpty())
@@ -575,7 +576,7 @@ QList<WatchData> QtDumperResult::toWatchData(int source) const
wchild.iname += iname; wchild.iname += iname;
wchild.exp = dchild.exp; wchild.exp = dchild.exp;
if (dchild.valueEncountered) { if (dchild.valueEncountered) {
wchild.valuedisabled = dchild.valuedisabled; wchild.valueEnabled = dchild.valueEnabled;
wchild.setValue(decodeData(dchild.value, dchild.valueEncoded)); wchild.setValue(decodeData(dchild.value, dchild.valueEncoded));
} }
wchild.setAddress(dchild.address); wchild.setAddress(dchild.address);
@@ -611,14 +612,15 @@ QList<WatchData> QtDumperResult::toWatchData(int source) const
QDebug operator<<(QDebug in, const QtDumperResult &d) QDebug operator<<(QDebug in, const QtDumperResult &d)
{ {
QDebug nospace = in.nospace(); QDebug nospace = in.nospace();
nospace << " iname=" << d.iname << " type=" << d.type << " displayed=" << d.displayedType nospace << " iname=" << d.iname << " type=" << d.type
<< " displayed=" << d.displayedType
<< " address=" << d.address; << " address=" << d.address;
if (!d.addressInfo.isEmpty()) if (!d.addressInfo.isEmpty())
nospace << " addressInfo=" << d.addressInfo; nospace << " addressInfo=" << d.addressInfo;
if (d.valueEncountered) { if (d.valueEncountered) {
nospace << " encoded=" << d.valueEncoded nospace << " encoded=" << d.valueEncoded
<< " value=" << d.value << " value=" << d.value
<< " disabled=" << d.valuedisabled; << " enabled=" << d.valueEnabled;
} else { } else {
nospace << " <no value>"; nospace << " <no value>";
} }
@@ -633,7 +635,7 @@ QDebug operator<<(QDebug in, const QtDumperResult &d)
for (int i = 0; i < realChildCount; i++) { for (int i = 0; i < realChildCount; i++) {
const QtDumperResult::Child &c = d.children.at(i); const QtDumperResult::Child &c = d.children.at(i);
nospace << " #" << i << " addr=" << c.address nospace << " #" << i << " addr=" << c.address
<< " disabled=" << c.valuedisabled << " enabled=" << c.valueEnabled
<< " type=" << c.type << " exp=" << c.exp << " type=" << c.type << " exp=" << c.exp
<< " name=" << c.name; << " name=" << c.name;
if (!c.key.isEmpty()) if (!c.key.isEmpty())
@@ -1518,7 +1520,7 @@ protected:
private: private:
enum Mode { None, ExpectingIName, ExpectingAddress, ExpectingValue, enum Mode { None, ExpectingIName, ExpectingAddress, ExpectingValue,
ExpectingType, ExpectingDisplayedType, ExpectingInternal, ExpectingType, ExpectingDisplayedType, ExpectingInternal,
ExpectingValueDisabled, ExpectingValueEncoded, ExpectingValueEnabled, ExpectingValueEncoded,
ExpectingCommonChildType, ExpectingChildCount, ExpectingCommonChildType, ExpectingChildCount,
ExpectingChildChildOverrideCount, ExpectingChildChildOverrideCount,
ExpectingExtra, ExpectingExtra,
@@ -1529,7 +1531,7 @@ private:
ExpectingChildDisplayedType, ExpectingChildDisplayedType,
ExpectingChildKey, ExpectingChildKeyEncoded, ExpectingChildKey, ExpectingChildKeyEncoded,
ExpectingChildValue, ExpectingChildValueEncoded, ExpectingChildValue, ExpectingChildValueEncoded,
ExpectingChildValueDisabled, ExpectingChildChildCount, ExpectingChildValueEnabled, ExpectingChildChildCount,
IgnoreNextChildMode IgnoreNextChildMode
}; };
@@ -1593,8 +1595,8 @@ ValueDumperParser::Mode ValueDumperParser::nextMode(Mode in, const char *keyword
return in > ChildModeStart ? ExpectingChildValueEncoded : ExpectingValueEncoded; return in > ChildModeStart ? ExpectingChildValueEncoded : ExpectingValueEncoded;
break; break;
case 13: case 13:
if (!qstrncmp(keyword, "valuedisabled", size)) if (!qstrncmp(keyword, "valueenabled", size))
return in > ChildModeStart ? ExpectingChildValueDisabled : ExpectingValueDisabled; return in > ChildModeStart ? ExpectingChildValueEnabled : ExpectingValueEnabled;
if (!qstrncmp(keyword, "displayedtype", size)) if (!qstrncmp(keyword, "displayedtype", size))
return in > ChildModeStart ? ExpectingChildDisplayedType : ExpectingDisplayedType; return in > ChildModeStart ? ExpectingChildDisplayedType : ExpectingDisplayedType;
if (!qstrncmp(keyword, "childnumchild", size)) if (!qstrncmp(keyword, "childnumchild", size))
@@ -1642,8 +1644,8 @@ bool ValueDumperParser::handleValue(const char *k, int size)
m_result.valueEncountered = true; m_result.valueEncountered = true;
m_result.value = valueBA; m_result.value = valueBA;
break; break;
case ExpectingValueDisabled: case ExpectingValueEnabled:
m_result.valuedisabled = valueBA == "true"; m_result.valueEnabled = valueBA == "true";
break; break;
case ExpectingValueEncoded: case ExpectingValueEncoded:
m_result.valueEncoded = QString::fromLatin1(valueBA).toInt(); m_result.valueEncoded = QString::fromLatin1(valueBA).toInt();
@@ -1695,8 +1697,8 @@ bool ValueDumperParser::handleValue(const char *k, int size)
case ExpectingChildValueEncoded: case ExpectingChildValueEncoded:
m_result.children.back().valueEncoded = QString::fromLatin1(valueBA).toInt(); m_result.children.back().valueEncoded = QString::fromLatin1(valueBA).toInt();
break; break;
case ExpectingChildValueDisabled: case ExpectingChildValueEnabled:
m_result.children.back().valuedisabled = valueBA == "true"; m_result.children.back().valueEnabled = valueBA == "true";
break; break;
case ExpectingChildType: case ExpectingChildType:
m_result.children.back().type = QString::fromLatin1(valueBA); m_result.children.back().type = QString::fromLatin1(valueBA);

View File

@@ -97,7 +97,7 @@ struct QtDumperResult
int keyEncoded; int keyEncoded;
int valueEncoded; int valueEncoded;
int childCount; int childCount;
bool valuedisabled; bool valueEnabled;
QString name; QString name;
QString address; QString address;
QString exp; QString exp;
@@ -121,7 +121,7 @@ struct QtDumperResult
bool valueEncountered; bool valueEncountered;
QByteArray value; QByteArray value;
int valueEncoded; int valueEncoded;
bool valuedisabled; bool valueEnabled;
int childCount; int childCount;
bool internal; bool internal;
QString childType; QString childType;

View File

@@ -353,7 +353,16 @@ void WatchWindow::setModel(QAbstractItemModel *model)
if (m_type != LocalsType) if (m_type != LocalsType)
header()->hide(); header()->hide();
connect(model, SIGNAL(layoutChanged()), this, SLOT(resetHelper())); connect(model, SIGNAL(layoutChanged()),
this, SLOT(resetHelper()));
connect(model, SIGNAL(enableUpdates(bool)),
this, SLOT(setUpdatesEnabled(bool)));
}
void WatchWindow::setUpdatesEnabled(bool enable)
{
//qDebug() << "ENABLING UPDATES: " << enable;
QTreeView::setUpdatesEnabled(enable);
} }
void WatchWindow::resetHelper() void WatchWindow::resetHelper()

View File

@@ -64,6 +64,7 @@ private:
Q_SLOT void resetHelper(); Q_SLOT void resetHelper();
Q_SLOT void expandNode(const QModelIndex &idx); Q_SLOT void expandNode(const QModelIndex &idx);
Q_SLOT void collapseNode(const QModelIndex &idx); Q_SLOT void collapseNode(const QModelIndex &idx);
Q_SLOT void setUpdatesEnabled(bool enable);
void keyPressEvent(QKeyEvent *ev); void keyPressEvent(QKeyEvent *ev);
void contextMenuEvent(QContextMenuEvent *ev); void contextMenuEvent(QContextMenuEvent *ev);

View File

@@ -90,6 +90,20 @@ public:
int t = 2; int t = 2;
b = 2 + s + t; b = 2 + s + t;
a += 1; a += 1;
a += 1;
a += 1;
a += 1;
a += 1;
a += 1;
a += 1;
a += 1;
a += 1;
a += 1;
a += 1;
a += 1;
a += 1;
a += 1;
a += 1;
} }
~Foo() ~Foo()