debugger: implement a dumper for QAbstractItemModel

This also squashes a namespace related bug introduced by the watchutils
refactoring.
This commit is contained in:
hjk
2009-06-03 12:46:55 +02:00
parent 311ca7a074
commit d7af85a097
6 changed files with 143 additions and 12 deletions

View File

@@ -851,6 +851,102 @@ static void qDumpInnerValueOrPointer(QDumper &d,
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
struct ModelIndex { int r; int c; void *p; void *m; };
static void qDumpQAbstractItem(QDumper &d)
{
ModelIndex mm;
mm.r = mm.c = 0;
mm.p = mm.m = 0;
sscanf(d.templateParameters[0], "%d,%d,%p,%p", &mm.r, &mm.c, &mm.p, &mm.m);
const QModelIndex &mi(*reinterpret_cast<QModelIndex *>(&mm));
const QAbstractItemModel *m = mi.model();
const int rowCount = m->rowCount(mi);
if (rowCount < 0)
return;
const int columnCount = m->columnCount(mi);
if (columnCount < 0)
return;
P(d, "type", NS"QAbstractItem");
P(d, "addr", "$" << mm.r << "," << mm.c << "," << mm.p << "," << mm.m);
//P(d, "value", "(" << rowCount << "," << columnCount << ")");
P(d, "value", m->data(mi, Qt::DisplayRole).toString());
P(d, "valueencoded", "2");
P(d, "numchild", "1");
if (d.dumpChildren) {
d << ",children=[";
for (int row = 0; row < rowCount; ++row) {
for (int column = 0; column < columnCount; ++column) {
QModelIndex child = m->index(row, column, mi);
d.beginHash();
P(d, "name", "[" << row << "," << column << "]");
//P(d, "numchild", (m->hasChildren(child) ? "1" : "0"));
P(d, "numchild", "1");
P(d, "addr", "$" << child.row() << "," << child.column() << ","
<< child.internalPointer() << "," << child.model());
P(d, "type", NS"QAbstractItem");
P(d, "value", m->data(mi, Qt::DisplayRole).toString());
P(d, "valueencoded", "2");
d.endHash();
}
}
d.beginHash();
P(d, "name", "DisplayRole");
P(d, "numchild", 0);
P(d, "value", m->data(mi, Qt::DisplayRole).toString());
P(d, "valueencoded", 2);
P(d, "type", NS"QString");
d.endHash();
d << "]";
}
d.disarm();
}
static void qDumpQAbstractItemModel(QDumper &d)
{
const QAbstractItemModel &m = *reinterpret_cast<const QAbstractItemModel *>(d.data);
const int rowCount = m.rowCount();
if (rowCount < 0)
return;
const int columnCount = m.columnCount();
if (columnCount < 0)
return;
P(d, "type", NS"QAbstractItemModel");
P(d, "value", "(" << rowCount << "," << columnCount << ")");
P(d, "numchild", "1");
if (d.dumpChildren) {
d << ",children=[";
d.beginHash();
P(d, "numchild", "1");
P(d, "name", NS"QObject");
P(d, "addr", d.data);
P(d, "value", m.objectName());
P(d, "valueencoded", "2");
P(d, "type", NS"QObject");
P(d, "displayedtype", m.metaObject()->className());
d.endHash();
for (int row = 0; row < rowCount; ++row) {
for (int column = 0; column < columnCount; ++column) {
QModelIndex mi = m.index(row, column);
d.beginHash();
P(d, "name", "[" << row << "," << column << "]");
P(d, "value", m.data(mi, Qt::DisplayRole).toString());
P(d, "valueencoded", "2");
//P(d, "numchild", (m.hasChildren(mi) ? "1" : "0"));
P(d, "numchild", "1");
P(d, "addr", "$" << mi.row() << "," << mi.column() << ","
<< mi.internalPointer() << "," << mi.model());
P(d, "type", NS"QAbstractItem");
d.endHash();
}
}
d << "]";
}
d.disarm();
}
static void qDumpQByteArray(QDumper &d) static void qDumpQByteArray(QDumper &d)
{ {
const QByteArray &ba = *reinterpret_cast<const QByteArray *>(d.data); const QByteArray &ba = *reinterpret_cast<const QByteArray *>(d.data);
@@ -1210,7 +1306,7 @@ static void qDumpQImage(QDumper &d)
if (d.dumpChildren) { if (d.dumpChildren) {
d << ",children=["; d << ",children=[";
d.beginHash(); d.beginHash();
P(d, "name", "key"); P(d, "name", "data");
P(d, "type", NS "QImageData"); P(d, "type", NS "QImageData");
P(d, "addr", d.data); P(d, "addr", d.data);
d.endHash(); d.endHash();
@@ -2533,7 +2629,8 @@ static void handleProtocolVersion2and3(QDumper & d)
d.setupTemplateParameters(); d.setupTemplateParameters();
P(d, "iname", d.iname); P(d, "iname", d.iname);
P(d, "addr", d.data); if (d.data)
P(d, "addr", d.data);
#ifdef QT_NO_QDATASTREAM #ifdef QT_NO_QDATASTREAM
if (d.protocolVersion == 3) { if (d.protocolVersion == 3) {
@@ -2555,6 +2652,12 @@ static void handleProtocolVersion2and3(QDumper & d)
if (isEqual(type, "map")) if (isEqual(type, "map"))
qDumpStdMap(d); qDumpStdMap(d);
break; break;
case 'A':
if (isEqual(type, "QAbstractItemModel"))
qDumpQAbstractItemModel(d);
else if (isEqual(type, "QAbstractItem"))
qDumpQAbstractItem(d);
break;
case 'B': case 'B':
if (isEqual(type, "QByteArray")) if (isEqual(type, "QByteArray"))
qDumpQByteArray(d); qDumpQByteArray(d);
@@ -2715,6 +2818,8 @@ void *qDumpObjectData440(
// They are mentioned here nevertheless. For types that are not listed // They are mentioned here nevertheless. For types that are not listed
// here, dumpers won't be used. // here, dumpers won't be used.
d << "dumpers=[" d << "dumpers=["
"\""NS"QAbstractItem\","
"\""NS"QAbstractItemModel\","
"\""NS"QByteArray\"," "\""NS"QByteArray\","
"\""NS"QDateTime\"," "\""NS"QDateTime\","
"\""NS"QDir\"," "\""NS"QDir\","
@@ -2810,7 +2915,6 @@ void *qDumpObjectData440(
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;
handleProtocolVersion2and3(d); handleProtocolVersion2and3(d);
} }

View File

@@ -252,8 +252,8 @@ void DebuggerOutputWindow::showOutput(const QString &prefix, const QString &outp
foreach (QString line, output.split("\n")) { foreach (QString line, output.split("\n")) {
// FIXME: QTextEdit asserts on really long lines... // FIXME: QTextEdit asserts on really long lines...
const int n = 3000; const int n = 3000;
//if (line.size() > n) if (line.size() > n)
// line = line.left(n) + " [...] <cut off>"; line = line.left(n) + " [...] <cut off>";
m_combinedText->appendPlainText(prefix + line); m_combinedText->appendPlainText(prefix + line);
} }
QTextCursor cursor = m_combinedText->textCursor(); QTextCursor cursor = m_combinedText->textCursor();

View File

@@ -2813,7 +2813,7 @@ static void setWatchDataAddress(WatchData &data, const GdbMi &mi)
{ {
if (mi.isValid()) { if (mi.isValid()) {
data.addr = _(mi.data()); data.addr = _(mi.data());
if (data.exp.isEmpty()) if (data.exp.isEmpty() && !data.addr.startsWith(_("$")))
data.exp = _("(*(") + gdbQuoteTypes(data.type) + _("*)") + data.addr + _c(')'); data.exp = _("(*(") + gdbQuoteTypes(data.type) + _("*)") + data.addr + _c(')');
} }
} }
@@ -2885,7 +2885,6 @@ void GdbEngine::runDebuggingHelper(const WatchData &data0, bool dumpChildren)
return; return;
} }
WatchData data = data0; WatchData data = data0;
QTC_ASSERT(!data.exp.isEmpty(), return);
QByteArray params; QByteArray params;
QStringList extraArgs; QStringList extraArgs;
@@ -2900,6 +2899,8 @@ void GdbEngine::runDebuggingHelper(const WatchData &data0, bool dumpChildren)
QString addr; QString addr;
if (data.addr.startsWith(__("0x"))) if (data.addr.startsWith(__("0x")))
addr = _("(void*)") + data.addr; addr = _("(void*)") + data.addr;
else if (data.exp.isEmpty()) // happens e.g. for QAbstractItem
addr = _("0");
else else
addr = _("&(") + data.exp + _c(')'); addr = _("&(") + data.exp + _c(')');

View File

@@ -658,6 +658,7 @@ QtDumperHelper::Type QtDumperHelper::specialType(QString s)
if (s.startsWith(QLatin1String("std::"))) if (s.startsWith(QLatin1String("std::")))
return stdType(s.mid(5)); return stdType(s.mid(5));
// Strip namespace // Strip namespace
// FIXME: that's not a good idea as it makes all namespaces equal.
const int namespaceIndex = s.lastIndexOf(QLatin1String("::")); const int namespaceIndex = s.lastIndexOf(QLatin1String("::"));
if (namespaceIndex == -1) { if (namespaceIndex == -1) {
// None ... check for std.. // None ... check for std..
@@ -665,7 +666,7 @@ QtDumperHelper::Type QtDumperHelper::specialType(QString s)
if (sType != UnknownType) if (sType != UnknownType)
return sType; return sType;
} else { } else {
s.remove(namespaceIndex + 2); s = s.mid(namespaceIndex + 2);
} }
if (s == QLatin1String("QObject")) if (s == QLatin1String("QObject"))
return QObjectType; return QObjectType;
@@ -677,6 +678,8 @@ QtDumperHelper::Type QtDumperHelper::specialType(QString s)
return QObjectSignalType; return QObjectSignalType;
if (s == QLatin1String("QVector")) if (s == QLatin1String("QVector"))
return QVectorType; return QVectorType;
if (s == QLatin1String("QAbstractItem"))
return QAbstractItemType;
if (s == QLatin1String("QMap")) if (s == QLatin1String("QMap"))
return QMapType; return QMapType;
if (s == QLatin1String("QMultiMap")) if (s == QLatin1String("QMultiMap"))
@@ -689,6 +692,7 @@ QtDumperHelper::Type QtDumperHelper::specialType(QString s)
bool QtDumperHelper::needsExpressionSyntax(Type t) bool QtDumperHelper::needsExpressionSyntax(Type t)
{ {
switch (t) { switch (t) {
case QAbstractItemType:
case QObjectSlotType: case QObjectSlotType:
case QObjectSignalType: case QObjectSignalType:
case QMapType: case QMapType:
@@ -1058,6 +1062,7 @@ void QtDumperHelper::addSize(const QString &name, int size)
break; break;
} }
if (name == QLatin1String("std::wstring")) { if (name == QLatin1String("std::wstring")) {
// FIXME: check space between > > below?
m_sizeCache.insert(QLatin1String("std::basic_string<unsigned short,std::char_traits<unsignedshort>,std::allocator<unsignedshort> >"), size); m_sizeCache.insert(QLatin1String("std::basic_string<unsigned short,std::char_traits<unsignedshort>,std::allocator<unsignedshort> >"), size);
break; break;
} }
@@ -1078,7 +1083,7 @@ QtDumperHelper::TypeData QtDumperHelper::typeData(const QString &typeName) const
const Type st = simpleType(typeName); const Type st = simpleType(typeName);
if (st != UnknownType) { if (st != UnknownType) {
td.isTemplate = false; td.isTemplate = false;
td.type =st; td.type = st;
return td; return td;
} }
// Try template // Try template
@@ -1129,6 +1134,8 @@ void QtDumperHelper::evaluationParameters(const WatchData &data,
if (outertype == m_qtNamespace + QLatin1String("QWidget")) if (outertype == m_qtNamespace + QLatin1String("QWidget"))
outertype = m_qtNamespace + QLatin1String("QObject"); outertype = m_qtNamespace + QLatin1String("QObject");
QString inner = td.inner;
extraArgs.clear(); extraArgs.clear();
if (!inners.empty()) { if (!inners.empty()) {
@@ -1147,6 +1154,9 @@ void QtDumperHelper::evaluationParameters(const WatchData &data,
// in rare cases we need more or less: // in rare cases we need more or less:
switch (td.type) { switch (td.type) {
case QAbstractItemType:
inner = data.addr.mid(1);
break;
case QObjectType: case QObjectType:
case QWidgetType: case QWidgetType:
if (debugger == GdbDebugger) { if (debugger == GdbDebugger) {
@@ -1258,9 +1268,7 @@ void QtDumperHelper::evaluationParameters(const WatchData &data,
inBuffer->append('\0'); inBuffer->append('\0');
inBuffer->append(data.exp.toUtf8()); inBuffer->append(data.exp.toUtf8());
inBuffer->append('\0'); inBuffer->append('\0');
inBuffer->append(td.inner.toUtf8()); inBuffer->append(inner.toUtf8());
inBuffer->append('\0');
inBuffer->append(data.iname.toUtf8());
inBuffer->append('\0'); inBuffer->append('\0');
if (debug) if (debug)

View File

@@ -145,6 +145,7 @@ public:
UnknownType, UnknownType,
SupportedType, // A type that requires no special handling by the dumper SupportedType, // A type that requires no special handling by the dumper
// Below types require special handling // Below types require special handling
QAbstractItemType,
QObjectType, QWidgetType, QObjectSlotType, QObjectSignalType, QObjectType, QWidgetType, QObjectSlotType, QObjectSignalType,
QVectorType, QMapType, QMultiMapType, QMapNodeType, QVectorType, QMapType, QMultiMapType, QMapNodeType,
StdVectorType, StdDequeType, StdSetType, StdMapType, StdStackType, StdVectorType, StdDequeType, StdSetType, StdMapType, StdStackType,

View File

@@ -48,6 +48,7 @@
#include <QtGui/QLabel> #include <QtGui/QLabel>
#include <QtGui/QPainter> #include <QtGui/QPainter>
#include <QtGui/QPainterPath> #include <QtGui/QPainterPath>
#include <QtGui/QStandardItemModel>
#include <QtNetwork/QHostAddress> #include <QtNetwork/QHostAddress>
@@ -787,6 +788,21 @@ void testStdVector()
vec.push_back(false); vec.push_back(false);
} }
void testQStandardItemModel()
{
QStandardItemModel m;
QStandardItem *i1, *i2, *i11;
m.appendRow(QList<QStandardItem *>()
<< (i1 = new QStandardItem("1")) << (new QStandardItem("a")));
m.appendRow(QList<QStandardItem *>()
<< (i2 = new QStandardItem("2")) << (new QStandardItem("b")));
i1->appendRow(QList<QStandardItem *>()
<< (i11 = new QStandardItem("11")) << (new QStandardItem("aa")));
int i = 1;
++i;
++i;
}
void testQString() void testQString()
{ {
QString str = "Hello "; QString str = "Hello ";
@@ -1090,6 +1106,7 @@ int main(int argc, char *argv[])
QStringList list; QStringList list;
list << "aaa" << "bbb" << "cc"; list << "aaa" << "bbb" << "cc";
testQStandardItemModel();
testQImage(); testQImage();
testNoArgumentName(1, 2, 3); testNoArgumentName(1, 2, 3);
testIO(); testIO();