diff --git a/share/qtcreator/gdbmacros/gdbmacros.cpp b/share/qtcreator/gdbmacros/gdbmacros.cpp index 5f75cc8997e7ba5380f677e7830794fedda0ea2b..1bf767002b0bcaef5135bdfa468f7cdf31199c73 100644 --- a/share/qtcreator/gdbmacros/gdbmacros.cpp +++ b/share/qtcreator/gdbmacros/gdbmacros.cpp @@ -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) { const QByteArray &ba = *reinterpret_cast<const QByteArray *>(d.data); @@ -1210,7 +1306,7 @@ static void qDumpQImage(QDumper &d) if (d.dumpChildren) { d << ",children=["; d.beginHash(); - P(d, "name", "key"); + P(d, "name", "data"); P(d, "type", NS "QImageData"); P(d, "addr", d.data); d.endHash(); @@ -2533,7 +2629,8 @@ static void handleProtocolVersion2and3(QDumper & d) d.setupTemplateParameters(); P(d, "iname", d.iname); - P(d, "addr", d.data); + if (d.data) + P(d, "addr", d.data); #ifdef QT_NO_QDATASTREAM if (d.protocolVersion == 3) { @@ -2555,6 +2652,12 @@ static void handleProtocolVersion2and3(QDumper & d) if (isEqual(type, "map")) qDumpStdMap(d); break; + case 'A': + if (isEqual(type, "QAbstractItemModel")) + qDumpQAbstractItemModel(d); + else if (isEqual(type, "QAbstractItem")) + qDumpQAbstractItem(d); + break; case 'B': if (isEqual(type, "QByteArray")) qDumpQByteArray(d); @@ -2715,6 +2818,8 @@ void *qDumpObjectData440( // They are mentioned here nevertheless. For types that are not listed // here, dumpers won't be used. d << "dumpers=[" + "\""NS"QAbstractItem\"," + "\""NS"QAbstractItemModel\"," "\""NS"QByteArray\"," "\""NS"QDateTime\"," "\""NS"QDir\"," @@ -2810,7 +2915,6 @@ void *qDumpObjectData440( d.iname = inbuffer; while (*inbuffer) ++inbuffer; ++inbuffer; d.exp = inbuffer; while (*inbuffer) ++inbuffer; ++inbuffer; d.innertype = inbuffer; while (*inbuffer) ++inbuffer; ++inbuffer; - d.iname = inbuffer; while (*inbuffer) ++inbuffer; ++inbuffer; handleProtocolVersion2and3(d); } diff --git a/src/plugins/debugger/debuggeroutputwindow.cpp b/src/plugins/debugger/debuggeroutputwindow.cpp index d50536e7ca5bff496c338c8da6564b1045245af3..9c51a5300c78785dd3117ac4c8e89b01736428bc 100644 --- a/src/plugins/debugger/debuggeroutputwindow.cpp +++ b/src/plugins/debugger/debuggeroutputwindow.cpp @@ -252,8 +252,8 @@ void DebuggerOutputWindow::showOutput(const QString &prefix, const QString &outp foreach (QString line, output.split("\n")) { // FIXME: QTextEdit asserts on really long lines... const int n = 3000; - //if (line.size() > n) - // line = line.left(n) + " [...] <cut off>"; + if (line.size() > n) + line = line.left(n) + " [...] <cut off>"; m_combinedText->appendPlainText(prefix + line); } QTextCursor cursor = m_combinedText->textCursor(); diff --git a/src/plugins/debugger/gdb/gdbengine.cpp b/src/plugins/debugger/gdb/gdbengine.cpp index b0a62981b5a44b7e6eb50fd7c8e80ebc06228826..770586af681142590cd6eccfb8cc14281397065f 100644 --- a/src/plugins/debugger/gdb/gdbengine.cpp +++ b/src/plugins/debugger/gdb/gdbengine.cpp @@ -2813,7 +2813,7 @@ static void setWatchDataAddress(WatchData &data, const GdbMi &mi) { if (mi.isValid()) { data.addr = _(mi.data()); - if (data.exp.isEmpty()) + if (data.exp.isEmpty() && !data.addr.startsWith(_("$"))) data.exp = _("(*(") + gdbQuoteTypes(data.type) + _("*)") + data.addr + _c(')'); } } @@ -2885,7 +2885,6 @@ void GdbEngine::runDebuggingHelper(const WatchData &data0, bool dumpChildren) return; } WatchData data = data0; - QTC_ASSERT(!data.exp.isEmpty(), return); QByteArray params; QStringList extraArgs; @@ -2900,6 +2899,8 @@ void GdbEngine::runDebuggingHelper(const WatchData &data0, bool dumpChildren) QString addr; if (data.addr.startsWith(__("0x"))) addr = _("(void*)") + data.addr; + else if (data.exp.isEmpty()) // happens e.g. for QAbstractItem + addr = _("0"); else addr = _("&(") + data.exp + _c(')'); diff --git a/src/plugins/debugger/watchutils.cpp b/src/plugins/debugger/watchutils.cpp index f074ee2ddc1a121cb62495944cc562042ce71666..887d0c7fa894c98cc870a3521a78fe0ef31373c5 100644 --- a/src/plugins/debugger/watchutils.cpp +++ b/src/plugins/debugger/watchutils.cpp @@ -658,6 +658,7 @@ QtDumperHelper::Type QtDumperHelper::specialType(QString s) if (s.startsWith(QLatin1String("std::"))) return stdType(s.mid(5)); // Strip namespace + // FIXME: that's not a good idea as it makes all namespaces equal. const int namespaceIndex = s.lastIndexOf(QLatin1String("::")); if (namespaceIndex == -1) { // None ... check for std.. @@ -665,7 +666,7 @@ QtDumperHelper::Type QtDumperHelper::specialType(QString s) if (sType != UnknownType) return sType; } else { - s.remove(namespaceIndex + 2); + s = s.mid(namespaceIndex + 2); } if (s == QLatin1String("QObject")) return QObjectType; @@ -677,6 +678,8 @@ QtDumperHelper::Type QtDumperHelper::specialType(QString s) return QObjectSignalType; if (s == QLatin1String("QVector")) return QVectorType; + if (s == QLatin1String("QAbstractItem")) + return QAbstractItemType; if (s == QLatin1String("QMap")) return QMapType; if (s == QLatin1String("QMultiMap")) @@ -689,6 +692,7 @@ QtDumperHelper::Type QtDumperHelper::specialType(QString s) bool QtDumperHelper::needsExpressionSyntax(Type t) { switch (t) { + case QAbstractItemType: case QObjectSlotType: case QObjectSignalType: case QMapType: @@ -1058,6 +1062,7 @@ void QtDumperHelper::addSize(const QString &name, int size) break; } 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); break; } @@ -1078,7 +1083,7 @@ QtDumperHelper::TypeData QtDumperHelper::typeData(const QString &typeName) const const Type st = simpleType(typeName); if (st != UnknownType) { td.isTemplate = false; - td.type =st; + td.type = st; return td; } // Try template @@ -1129,6 +1134,8 @@ void QtDumperHelper::evaluationParameters(const WatchData &data, if (outertype == m_qtNamespace + QLatin1String("QWidget")) outertype = m_qtNamespace + QLatin1String("QObject"); + QString inner = td.inner; + extraArgs.clear(); if (!inners.empty()) { @@ -1147,6 +1154,9 @@ void QtDumperHelper::evaluationParameters(const WatchData &data, // in rare cases we need more or less: switch (td.type) { + case QAbstractItemType: + inner = data.addr.mid(1); + break; case QObjectType: case QWidgetType: if (debugger == GdbDebugger) { @@ -1258,9 +1268,7 @@ void QtDumperHelper::evaluationParameters(const WatchData &data, inBuffer->append('\0'); inBuffer->append(data.exp.toUtf8()); inBuffer->append('\0'); - inBuffer->append(td.inner.toUtf8()); - inBuffer->append('\0'); - inBuffer->append(data.iname.toUtf8()); + inBuffer->append(inner.toUtf8()); inBuffer->append('\0'); if (debug) diff --git a/src/plugins/debugger/watchutils.h b/src/plugins/debugger/watchutils.h index e87b3cd8221bc0391f88b1f26f083c6f63363fe8..2b8ef865baf2e7d1d5f5de1abe33d9884bb4fecf 100644 --- a/src/plugins/debugger/watchutils.h +++ b/src/plugins/debugger/watchutils.h @@ -145,6 +145,7 @@ public: UnknownType, SupportedType, // A type that requires no special handling by the dumper // Below types require special handling + QAbstractItemType, QObjectType, QWidgetType, QObjectSlotType, QObjectSignalType, QVectorType, QMapType, QMultiMapType, QMapNodeType, StdVectorType, StdDequeType, StdSetType, StdMapType, StdStackType, diff --git a/tests/manual/gdbdebugger/simple/app.cpp b/tests/manual/gdbdebugger/simple/app.cpp index de12a5474c71976bb5a4245934095eacf5f51372..349055c3b2ada198326b3e2d7e9b8d4f5f6de9b3 100644 --- a/tests/manual/gdbdebugger/simple/app.cpp +++ b/tests/manual/gdbdebugger/simple/app.cpp @@ -48,6 +48,7 @@ #include <QtGui/QLabel> #include <QtGui/QPainter> #include <QtGui/QPainterPath> +#include <QtGui/QStandardItemModel> #include <QtNetwork/QHostAddress> @@ -787,6 +788,21 @@ void testStdVector() 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() { QString str = "Hello "; @@ -1090,6 +1106,7 @@ int main(int argc, char *argv[]) QStringList list; list << "aaa" << "bbb" << "cc"; + testQStandardItemModel(); testQImage(); testNoArgumentName(1, 2, 3); testIO();