void recurseObjectIdList(const QDeclarativeDebugObjectReference &ref, QList<int> &debugIds, QList<QString> &objectIds) { debugIds << ref.debugId(); objectIds << ref.idString(); foreach (const QDeclarativeDebugObjectReference &child, ref.children()) recurseObjectIdList(child, debugIds, objectIds); }
void QmlJSLiveTextPreview::changeSelectedElements(QList<int> offsets, const QString &wordAtCursor) { if (m_editors.isEmpty() || !m_previousDoc || !m_clientProxy) return; QDeclarativeDebugObjectReference objectRefUnderCursor; objectRefUnderCursor = m_clientProxy.data()->objectReferenceForId(wordAtCursor); QList<int> selectedReferences; bool containsReferenceUnderCursor = false; foreach(int offset, offsets) { if (offset >= 0) { QList<int> list = objectReferencesForOffset(offset); if (!containsReferenceUnderCursor && objectRefUnderCursor.debugId() != -1) { foreach(int id, list) { if (id == objectRefUnderCursor.debugId()) { containsReferenceUnderCursor = true; break; } } } selectedReferences << list; }
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 tst_QDeclarativeDebug::setMethodBody() { QDeclarativeDebugObjectReference obj = findRootObject(2); QObject *root = m_components.at(2); // Without args { QVariant rv; QVERIFY(QMetaObject::invokeMethod(root, "myMethodNoArgs", Qt::DirectConnection, Q_RETURN_ARG(QVariant, rv))); QVERIFY(rv == QVariant(qreal(3))); QVERIFY(m_dbg->setMethodBody(obj.debugId(), "myMethodNoArgs", "return 7")); QTest::qWait(100); QVERIFY(QMetaObject::invokeMethod(root, "myMethodNoArgs", Qt::DirectConnection, Q_RETURN_ARG(QVariant, rv))); QVERIFY(rv == QVariant(qreal(7))); } // With args { QVariant rv; QVERIFY(QMetaObject::invokeMethod(root, "myMethod", Qt::DirectConnection, Q_RETURN_ARG(QVariant, rv), Q_ARG(QVariant, QVariant(19)))); QVERIFY(rv == QVariant(qreal(28))); QVERIFY(m_dbg->setMethodBody(obj.debugId(), "myMethod", "return a + 7")); QTest::qWait(100); QVERIFY(QMetaObject::invokeMethod(root, "myMethod", Qt::DirectConnection, Q_RETURN_ARG(QVariant, rv), Q_ARG(QVariant, QVariant(19)))); QVERIFY(rv == QVariant(qreal(26))); } }
QString ObjectPropertiesView::propertyBaseClass(const QDeclarativeDebugObjectReference &object, const QDeclarativeDebugPropertyReference &property, int &depth) { ExtensionSystem::PluginManager *pluginManager = ExtensionSystem::PluginManager::instance(); QmlJSEditor::ModelManagerInterface *modelManager = pluginManager->getObject<QmlJSEditor::ModelManagerInterface>(); QmlJS::Snapshot snapshot = modelManager->snapshot(); QmlJS::Document::Ptr document = snapshot.document(object.source().url().path()); if (document.isNull()) { QFile inFile(object.source().url().path()); QString contents; if (inFile.open(QIODevice::ReadOnly)) { QTextStream ins(&inFile); contents = ins.readAll(); inFile.close(); } document = QmlJS::Document::create(object.source().url().path()); document->setSource(contents); if (!document->parse()) return QString(); snapshot.insert(document); } PropertyTypeFinder find(document, snapshot, modelManager->importPaths()); QString baseClassName = find(object.source().lineNumber(), object.source().columnNumber(), property.name()); if (baseClassName.isEmpty()) { if (!object.idString().isEmpty()) baseClassName = object.idString(); else baseClassName = QString("<%1>").arg(object.className()); } depth = find.depth(); return baseClassName; }
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::watch_expression() { QFETCH(QString, expr); QFETCH(int, increment); QFETCH(int, incrementCount); int origWidth = m_rootItem->property("width").toInt(); QDeclarativeDebugObjectReference obj = findRootObject(); QDeclarativeDebugObjectExpressionWatch *watch; QDeclarativeEngineDebug *unconnected = new QDeclarativeEngineDebug(0); watch = unconnected->addWatch(obj, expr, this); QCOMPARE(watch->state(), QDeclarativeDebugWatch::Dead); delete watch; delete unconnected; watch = m_dbg->addWatch(QDeclarativeDebugObjectReference(), expr, this); QVERIFY(QDeclarativeDebugTest::waitForSignal(watch, SIGNAL(stateChanged(QDeclarativeDebugWatch::State)))); QCOMPARE(watch->state(), QDeclarativeDebugWatch::Inactive); delete watch; watch = m_dbg->addWatch(obj, expr, this); QCOMPARE(watch->state(), QDeclarativeDebugWatch::Waiting); QCOMPARE(watch->objectDebugId(), obj.debugId()); QCOMPARE(watch->expression(), expr); QSignalSpy spyState(watch, SIGNAL(stateChanged(QDeclarativeDebugWatch::State))); QSignalSpy spy(watch, SIGNAL(valueChanged(QByteArray,QVariant))); int expectedSpyCount = incrementCount + 1; // should also get signal with expression's initial value int width = origWidth; for (int i=0; i<incrementCount+1; i++) { if (i > 0) { width += increment; m_rootItem->setProperty("width", width); } if (!QDeclarativeDebugTest::waitForSignal(watch, SIGNAL(valueChanged(QByteArray,QVariant)))) QFAIL("Did not receive valueChanged() for expression"); } if (spyState.count() == 0) QVERIFY(QDeclarativeDebugTest::waitForSignal(watch, SIGNAL(stateChanged(QDeclarativeDebugWatch::State)))); QCOMPARE(spyState.count(), 1); QCOMPARE(watch->state(), QDeclarativeDebugWatch::Active); m_dbg->removeWatch(watch); delete watch; // restore original value and verify spy doesn't get a signal since watch has been removed m_rootItem->setProperty("width", origWidth); QTest::qWait(100); QCOMPARE(spy.count(), expectedSpyCount); width = origWidth + increment; for (int i=0; i<spy.count(); i++) { QCOMPARE(spy.at(i).at(1).value<QVariant>().toInt(), width); width += increment; } }
void tst_QDeclarativeDebug::watch_object() { QDeclarativeDebugEnginesQuery *q_engines = m_dbg->queryAvailableEngines(this); waitForQuery(q_engines); QVERIFY(q_engines->engines().count() > 0); QDeclarativeDebugRootContextQuery *q_context = m_dbg->queryRootContexts(q_engines->engines()[0].debugId(), this); waitForQuery(q_context); QVERIFY(q_context->rootContext().objects().count() > 0); QDeclarativeDebugObjectQuery *q_obj = m_dbg->queryObject(q_context->rootContext().objects()[0], this); waitForQuery(q_obj); QDeclarativeDebugObjectReference obj = q_obj->object(); delete q_engines; delete q_context; delete q_obj; QDeclarativeDebugWatch *watch; QDeclarativeEngineDebug *unconnected = new QDeclarativeEngineDebug(0); watch = unconnected->addWatch(obj, this); QCOMPARE(watch->state(), QDeclarativeDebugWatch::Dead); delete watch; delete unconnected; watch = m_dbg->addWatch(QDeclarativeDebugObjectReference(), this); QVERIFY(QDeclarativeDebugTest::waitForSignal(watch, SIGNAL(stateChanged(QDeclarativeDebugWatch::State)))); QCOMPARE(watch->state(), QDeclarativeDebugWatch::Inactive); delete watch; watch = m_dbg->addWatch(obj, this); QCOMPARE(watch->state(), QDeclarativeDebugWatch::Waiting); QCOMPARE(watch->objectDebugId(), obj.debugId()); QSignalSpy spy(watch, SIGNAL(valueChanged(QByteArray,QVariant))); int origWidth = m_rootItem->property("width").toInt(); int origHeight = m_rootItem->property("height").toInt(); m_rootItem->setProperty("width", origWidth*2); m_rootItem->setProperty("height", origHeight*2); // stateChanged() is received before any valueChanged() signals QVERIFY(QDeclarativeDebugTest::waitForSignal(watch, SIGNAL(stateChanged(QDeclarativeDebugWatch::State)))); QCOMPARE(watch->state(), QDeclarativeDebugWatch::Active); QVERIFY(spy.count() > 0); int newWidth = -1; int newHeight = -1; for (int i=0; i<spy.count(); i++) { const QVariantList &values = spy[i]; if (values[0].value<QByteArray>() == "width") newWidth = values[1].value<QVariant>().toInt(); else if (values[0].value<QByteArray>() == "height") newHeight = values[1].value<QVariant>().toInt(); } m_dbg->removeWatch(watch); delete watch; // since watch has been removed, restoring the original values should not trigger a valueChanged() spy.clear(); m_rootItem->setProperty("width", origWidth); m_rootItem->setProperty("height", origHeight); QTest::qWait(100); QCOMPARE(spy.count(), 0); QCOMPARE(newWidth, origWidth * 2); QCOMPARE(newHeight, origHeight * 2); }
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::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()); } }