void tst_QDeclarativeDebug::recursiveCompareObjects(const QDeclarativeDebugObjectReference &a, const QDeclarativeDebugObjectReference &b) const { QCOMPARE(a.debugId(), b.debugId()); QCOMPARE(a.className(), b.className()); QCOMPARE(a.name(), b.name()); QCOMPARE(a.contextDebugId(), b.contextDebugId()); QCOMPARE(a.source().url(), b.source().url()); QCOMPARE(a.source().lineNumber(), b.source().lineNumber()); QCOMPARE(a.source().columnNumber(), b.source().columnNumber()); QCOMPARE(a.properties().count(), b.properties().count()); QCOMPARE(a.children().count(), b.children().count()); QList<QDeclarativeDebugPropertyReference> aprops = a.properties(); QList<QDeclarativeDebugPropertyReference> bprops = b.properties(); for (int i=0; i<aprops.count(); i++) compareProperties(aprops[i], bprops[i]); for (int i=0; i<a.children().count(); i++) recursiveCompareObjects(a.children()[i], b.children()[i]); }
void tst_QDeclarativeDebug::watch_property() { QDeclarativeDebugObjectReference obj = findRootObject(); QDeclarativeDebugPropertyReference prop = findProperty(obj.properties(), "width"); QDeclarativeDebugPropertyWatch *watch; QDeclarativeEngineDebug *unconnected = new QDeclarativeEngineDebug(0); watch = unconnected->addWatch(prop, this); QCOMPARE(watch->state(), QDeclarativeDebugWatch::Dead); delete watch; delete unconnected; watch = m_dbg->addWatch(QDeclarativeDebugPropertyReference(), this); QVERIFY(QDeclarativeDebugTest::waitForSignal(watch, SIGNAL(stateChanged(QDeclarativeDebugWatch::State)))); QCOMPARE(watch->state(), QDeclarativeDebugWatch::Inactive); delete watch; watch = m_dbg->addWatch(prop, this); QCOMPARE(watch->state(), QDeclarativeDebugWatch::Waiting); QCOMPARE(watch->objectDebugId(), obj.debugId()); QCOMPARE(watch->name(), prop.name()); QSignalSpy spy(watch, SIGNAL(valueChanged(QByteArray,QVariant))); int origWidth = m_rootItem->property("width").toInt(); m_rootItem->setProperty("width", origWidth*2); // stateChanged() is received before valueChanged() QVERIFY(QDeclarativeDebugTest::waitForSignal(watch, SIGNAL(stateChanged(QDeclarativeDebugWatch::State)))); QCOMPARE(watch->state(), QDeclarativeDebugWatch::Active); QCOMPARE(spy.count(), 1); m_dbg->removeWatch(watch); delete watch; // restore original value and verify spy doesn't get additional signal since watch has been removed m_rootItem->setProperty("width", origWidth); QTest::qWait(100); QCOMPARE(spy.count(), 1); QCOMPARE(spy.at(0).at(0).value<QByteArray>(), prop.name().toUtf8()); QCOMPARE(spy.at(0).at(1).value<QVariant>(), qVariantFromValue(origWidth*2)); }
void ObjectPropertiesView::setObject(const QDeclarativeDebugObjectReference &object) { m_object = object; m_tree->clear(); QHash<QString, PropertiesViewItem*> baseClassItems; PropertiesViewItem* currentParentItem = 0; QList<QString> insertedPropertyNames; QList<QDeclarativeDebugPropertyReference> properties = object.properties(); for (int i=0; i<properties.count(); ++i) { const QDeclarativeDebugPropertyReference &p = properties[i]; // ignore overridden/redefined/shadowed properties; and do special ignore for QGraphicsObject* parent, // which is useless while debugging. if (insertedPropertyNames.contains(p.name()) || (p.name() == "parent" && p.valueTypeName() == "QGraphicsObject*")) { continue; } insertedPropertyNames.append(p.name()); if (m_showUnwatchableProperties || p.hasNotifySignal()) { PropertiesViewItem *item = 0; if (m_groupByItemType) { int depth = 0; QString baseClassName = propertyBaseClass(object, p, depth); if (!baseClassItems.contains(baseClassName)) { PropertiesViewItem *baseClassItem = new PropertiesViewItem(m_tree, PropertiesViewItem::ClassType); baseClassItem->setData(0, PropertiesViewItem::CanEditRole, false); baseClassItem->setData(0, PropertiesViewItem::ClassDepthRole, depth); baseClassItem->setText(0, baseClassName); QFont font = m_tree->font(); font.setBold(true); baseClassItem->setFont(0, font); baseClassItems.insert(baseClassName, baseClassItem); } currentParentItem = baseClassItems.value(baseClassName); item = new PropertiesViewItem(currentParentItem); } else item = new PropertiesViewItem(m_tree); item->property = p; item->setData(0, PropertiesViewItem::ObjectIdStringRole, object.idString()); item->setText(0, p.name()); Qt::ItemFlags itemFlags = Qt::ItemIsSelectable | Qt::ItemIsEnabled; bool canEdit = object.idString().length() && QmlInspector::instance()->canEditProperty(item->property.valueTypeName()); item->setData(0, PropertiesViewItem::CanEditRole, canEdit); if (canEdit) itemFlags |= Qt::ItemIsEditable; item->setFlags(itemFlags); if (m_watchTableModel.data() && m_watchTableModel.data()->isWatchingProperty(p)) { QFont font = m_tree->font(); font.setBold(true); item->setFont(0, font); } setPropertyValue(item, p.value(), !p.hasNotifySignal()); item->setText(2, p.valueTypeName()); // binding is set after property value to ensure it is added to the end of the // list, if the value is a list if (!p.binding().isEmpty()) { PropertiesViewItem *binding = new PropertiesViewItem(item, PropertiesViewItem::BindingType); binding->setText(1, p.binding()); binding->setForeground(1, Qt::darkGreen); } } } if (m_groupByItemType) sortBaseClassItems(); m_tree->expandAll(); }
void tst_QDeclarativeDebug::recursiveObjectTest(QObject *o, const QDeclarativeDebugObjectReference &oref, bool recursive) const { const QMetaObject *meta = o->metaObject(); QDeclarativeType *type = QDeclarativeMetaType::qmlType(meta); QString className = type ? QString(type->qmlTypeName()) : QString(meta->className()); className = className.mid(className.lastIndexOf(QLatin1Char('/'))+1); QCOMPARE(oref.debugId(), QDeclarativeDebugService::idForObject(o)); QCOMPARE(oref.name(), o->objectName()); QCOMPARE(oref.className(), className); QCOMPARE(oref.contextDebugId(), QDeclarativeDebugService::idForObject(qmlContext(o))); const QObjectList &children = o->children(); for (int i=0; i<children.count(); i++) { QObject *child = children[i]; if (!qmlContext(child)) continue; int debugId = QDeclarativeDebugService::idForObject(child); QVERIFY(debugId >= 0); QDeclarativeDebugObjectReference cref; foreach (const QDeclarativeDebugObjectReference &ref, oref.children()) { if (ref.debugId() == debugId) { cref = ref; break; } } QVERIFY(cref.debugId() >= 0); if (recursive) recursiveObjectTest(child, cref, true); } foreach (const QDeclarativeDebugPropertyReference &p, oref.properties()) { QCOMPARE(p.objectDebugId(), QDeclarativeDebugService::idForObject(o)); // signal properties are fake - they are generated from QDeclarativeBoundSignal children if (p.name().startsWith("on") && p.name().length() > 2 && p.name()[2].isUpper()) { QVERIFY(p.value().toString().startsWith('{') && p.value().toString().endsWith('}')); QVERIFY(p.valueTypeName().isEmpty()); QVERIFY(p.binding().isEmpty()); QVERIFY(!p.hasNotifySignal()); continue; } QMetaProperty pmeta = meta->property(meta->indexOfProperty(p.name().toUtf8().constData())); QCOMPARE(p.name(), QString::fromUtf8(pmeta.name())); if (pmeta.type() > 0 && pmeta.type() < QVariant::UserType) // TODO test complex types QCOMPARE(p.value(), pmeta.read(o)); if (p.name() == "parent") QVERIFY(p.valueTypeName() == "QGraphicsObject*" || p.valueTypeName() == "QDeclarativeItem*"); else QCOMPARE(p.valueTypeName(), QString::fromUtf8(pmeta.typeName())); QDeclarativeAbstractBinding *binding = QDeclarativePropertyPrivate::binding(QDeclarativeProperty(o, p.name())); if (binding) QCOMPARE(binding->expression(), p.binding()); QCOMPARE(p.hasNotifySignal(), pmeta.hasNotifySignal()); QVERIFY(pmeta.isValid()); } }