forked from qt-creator/qt-creator
debugger: implement a dumper for QAbstractItemModel
This also squashes a namespace related bug introduced by the watchutils refactoring.
This commit is contained in:
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
@@ -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(')');
|
||||||
|
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
Reference in New Issue
Block a user