diff options
-rw-r--r-- | src/QuickStreamer/item.cpp | 121 | ||||
-rw-r--r-- | src/QuickStreamer/item.h | 2 | ||||
-rw-r--r-- | tests/tst_metaobject/tst_metaobjecttest.cpp | 13 | ||||
-rw-r--r-- | tests/tst_qml/tst_quickstreamer.qml | 37 |
4 files changed, 96 insertions, 77 deletions
diff --git a/src/QuickStreamer/item.cpp b/src/QuickStreamer/item.cpp index 0fcf253..fe17aae 100644 --- a/src/QuickStreamer/item.cpp +++ b/src/QuickStreamer/item.cpp @@ -65,10 +65,13 @@ struct PropertyInfo { typedef std::function<void(Item *item, void *value)> ReadDelegate; typedef std::function<void(Item *item, const void *value)> WriteDelegate; + typedef std::function<void(Item *item)> ResetDelegate; + + GParamSpec *spec; - const char *name; ReadDelegate read; WriteDelegate write; + ResetDelegate reset; }; static bool isDash(char ch) @@ -436,34 +439,31 @@ static void writeValue(const void *input, GValue *output) } } -static void readGObjectProperty(Item *item, const QByteArray &name, GType type, void *value) +static void readGObjectProperty(Item *item, GParamSpec *spec, void *value) { GValue gvalue = G_VALUE_INIT; - g_value_init(&gvalue, type); - g_object_get_property(G_OBJECT(item->target()), name.constData(), &gvalue); + g_value_init(&gvalue, spec->value_type); + g_object_get_property(G_OBJECT(item->target()), spec->name, &gvalue); readValue(&gvalue, value); g_value_unset(&gvalue); } -static void writeGObjectProperty(Item *item, const QByteArray &name, GType type, const void *value) +static void writeGObjectProperty(Item *item, GParamSpec *spec, const void *value) { GValue gvalue = G_VALUE_INIT; - g_value_init(&gvalue, type); + g_value_init(&gvalue, spec->value_type); writeValue(value, &gvalue); - g_object_set_property(G_OBJECT(item->target()), name.constData(), &gvalue); + g_object_set_property(G_OBJECT(item->target()), spec->name, &gvalue); g_value_unset(&gvalue); } -static void readNothing(Item *item, const QByteArray &name, void *) -{ - qWarning("Cannot read \"%s::%s\" which is not declared readable", - G_OBJECT_TYPE_NAME(item->target()), name.constData()); -} - -static void writeNothing(Item *item, const QByteArray &name, const void *) +static void resetGObjectProperty(Item *item, GParamSpec *spec) { - qWarning("Cannot write \"%s::%s\" which is not declared writable", - G_OBJECT_TYPE_NAME(item->target()), name.constData()); + GValue gvalue = G_VALUE_INIT; + g_value_init(&gvalue, spec->value_type); + g_param_value_set_default(spec, &gvalue); + g_object_set_property(G_OBJECT(item->target()), spec->name, &gvalue); + g_value_unset(&gvalue); } class ElementList : public QQmlListProperty<Item> @@ -535,16 +535,9 @@ static void writeState(Item *item, const void *value) gst_element_set_state(GST_ELEMENT(item->target()), *static_cast<const GstState *>(value)); } -template<typename... Args> -PropertyInfo::ReadDelegate bindReadDelegate(Args... args) -{ - return std::bind(args...); -} - -template<typename... Args> -PropertyInfo::WriteDelegate bindWriteDelegate(Args... args) +static void resetState(Item *item) { - return std::bind(args...); + gst_element_set_state(GST_ELEMENT(item->target()), GST_STATE_VOID_PENDING); } struct TypeInfo @@ -565,6 +558,7 @@ struct TypeInfo propertyBuilder.setReadable(propertyInfo.read != Q_NULLPTR); propertyBuilder.setWritable(propertyInfo.write != Q_NULLPTR); + propertyBuilder.setResettable(propertyInfo.reset != Q_NULLPTR); if (propertyType.endsWith(ENUMERATOR_TYPE_SUFFIX)) { // FIXME propertyBuilder.setEnumOrFlag(true); @@ -599,7 +593,7 @@ struct TypeInfo if (type == GST_TYPE_ELEMENT) { // FIXME: also add pendingState property? - typeInfo->addProperty({ Q_NULLPTR, readState, writeState }, + typeInfo->addProperty({ Q_NULLPTR, readState, writeState, resetState }, QByteArrayLiteral("state"), metaTypeName(GST_TYPE_STATE), &objectBuilder); @@ -607,7 +601,7 @@ struct TypeInfo if (type == GST_TYPE_BIN) { static const auto propertyName = QByteArrayLiteral("children"); - typeInfo->addProperty({ Q_NULLPTR, readChildren, Q_NULLPTR }, + typeInfo->addProperty({ Q_NULLPTR, readChildren, Q_NULLPTR, Q_NULLPTR }, propertyName, elementListTypeName, &objectBuilder); objectBuilder.addClassInfo(QByteArrayLiteral("DefaultProperty"), propertyName); } @@ -618,35 +612,40 @@ struct TypeInfo auto *const pSpecs = g_object_class_list_properties(objectClass, &nPSpecs); for (uint i = 0; i < nPSpecs; ++i) { - const auto *const pSpec = pSpecs[i]; + auto *const spec = pSpecs[i]; - if (pSpec->owner_type != type) + if (spec->owner_type != type) continue; - const auto &propertyName = toCamelCase(pSpec->name, std::tolower); - const auto &propertyType = metaTypeName(pSpec->value_type); + const auto &propertyName = toCamelCase(spec->name, std::tolower); + const auto &propertyType = metaTypeName(spec->value_type); - if (pSpec->flags & G_PARAM_DEPRECATED) { - qWarning("Ignoring deprecated property %s::%s", g_type_name(type), pSpec->name); + if (spec->flags & G_PARAM_DEPRECATED) { + qWarning("Ignoring deprecated property %s::%s", g_type_name(type), spec->name); continue; } if (propertyType.isEmpty()) { qWarning("Ignoring property %s::%s of unsupported type %s", - g_type_name(type), pSpec->name, g_type_name(pSpec->value_type)); + g_type_name(type), spec->name, g_type_name(spec->value_type)); continue; } using namespace std::placeholders; - const auto readDelegate = pSpec->flags & G_PARAM_READABLE - ? bindReadDelegate(&readGObjectProperty, _1, pSpec->name, pSpec->value_type, _2) - : bindReadDelegate(&readNothing, _1, pSpec->name, _2); - const auto writeDelegate = pSpec->flags & G_PARAM_WRITABLE - ? bindWriteDelegate(&writeGObjectProperty, _1, pSpec->name, pSpec->value_type, _2) - : bindWriteDelegate(&writeNothing, _1, pSpec->name, _2); + PropertyInfo::ReadDelegate readDelegate; + PropertyInfo::WriteDelegate writeDelegate; + PropertyInfo::ResetDelegate resetDelegate; + + if (spec->flags & G_PARAM_READABLE) + readDelegate = std::bind(&readGObjectProperty, _1, spec, _2); + if (spec->flags & G_PARAM_WRITABLE) + writeDelegate = std::bind(&writeGObjectProperty, _1, spec, _2); - typeInfo->addProperty({pSpec->name, readDelegate, writeDelegate}, + resetDelegate = std::bind(&resetGObjectProperty, _1, spec); + + typeInfo->addProperty({ g_param_spec_ref(spec), + readDelegate, writeDelegate, resetDelegate }, propertyName, propertyType, &objectBuilder); } @@ -747,7 +746,7 @@ struct TypeInfo return typeInfo; } - int readProperty(Item *item, int id, QVariant *value) const + int readProperty(Item *item, int id, void *value) const { if (parent) id = parent->readProperty(item, id, value); @@ -773,11 +772,26 @@ struct TypeInfo return id - properties.size(); } + int resetProperty(Item *item, int id) const + { + if (parent) + id = parent->resetProperty(item, id); + if (id < 0) + return id; + + if (id < properties.size()) + properties.at(id).reset(item); + + return id - properties.size(); + } + void emitPropertyChanged(Item *object, const GParamSpec *pspec) const { for (int i = 0; i < properties.size(); ++i) { + auto const &p = properties.at(i); + // can compare by pointer because GParamSpec::name is interned - if (pspec->name == properties.at(i).name) { + if (p.spec && pspec->name == p.spec->name) { QMetaObject::activate(object, metaObject, i, Q_NULLPTR); return; } @@ -872,15 +886,16 @@ int Item::qt_metacall(QMetaObject::Call call, int id, void **args) switch(call) { case QMetaObject::ReadProperty: - id = readProperty(id, static_cast<QVariant *>(args[0])); - break; + return TypeInfo::find(G_OBJECT_TYPE(m_target))->readProperty(this, id, args[0]); case QMetaObject::WriteProperty: - id = writeProperty(id, args[0]); + return TypeInfo::find(G_OBJECT_TYPE(m_target))->writeProperty(this, id, args[0]); break; - case QMetaObject::InvokeMetaMethod: case QMetaObject::ResetProperty: + return TypeInfo::find(G_OBJECT_TYPE(m_target))->resetProperty(this, id); + + case QMetaObject::InvokeMetaMethod: case QMetaObject::QueryPropertyDesignable: case QMetaObject::QueryPropertyScriptable: case QMetaObject::QueryPropertyStored: @@ -938,18 +953,6 @@ GstObject *Item::target() const return m_target; } -int Item::readProperty(int id, QVariant *value) -{ - const auto *const typeInfo = TypeInfo::find(G_OBJECT_TYPE(m_target)); - return typeInfo->readProperty(this, id, value); -} - -int Item::writeProperty(int id, const void *value) -{ - const auto *const typeInfo = TypeInfo::find(G_OBJECT_TYPE(m_target)); - return typeInfo->writeProperty(this, id, value); -} - void Item::emitPropertyChanged(Item *self, GParamSpec *pspec) { const auto *const typeInfo = TypeInfo::find(G_OBJECT_TYPE(self->m_target)); diff --git a/src/QuickStreamer/item.h b/src/QuickStreamer/item.h index 385699e..2a2830c 100644 --- a/src/QuickStreamer/item.h +++ b/src/QuickStreamer/item.h @@ -57,8 +57,6 @@ public: GstObject *target() const; protected: - int readProperty(int id, QVariant *value); - int writeProperty(int id, const void *value); static void emitPropertyChanged(Item *self, GParamSpec *pspec); private: diff --git a/tests/tst_metaobject/tst_metaobjecttest.cpp b/tests/tst_metaobject/tst_metaobjecttest.cpp index a35ce5c..485d937 100644 --- a/tests/tst_metaobject/tst_metaobjecttest.cpp +++ b/tests/tst_metaobject/tst_metaobjecttest.cpp @@ -60,31 +60,32 @@ private slots: QTest::addColumn<QByteArray>("type"); QTest::addColumn<bool>("readable"); QTest::addColumn<bool>("writable"); + QTest::addColumn<bool>("resetable"); QTest::addColumn<bool>("enumType"); QTest::newRow("name") << QByteArrayLiteral("pipeline") << QByteArrayLiteral("name") << QByteArrayLiteral("QString") - << true << true << false; + << true << true << true << false; QTest::newRow("children") << QByteArrayLiteral("pipeline") << QByteArrayLiteral("children") << QByteArrayLiteral("QQmlListProperty<GstElement>") - << true << false << false; + << true << false << false << false; QTest::newRow("state") << QByteArrayLiteral("pipeline") << QByteArrayLiteral("state") << QByteArrayLiteral("GstState::Values") - << true << true << true; + << true << true << true << true; QTest::newRow("wave") << QByteArrayLiteral("audiotestsrc") << QByteArrayLiteral("wave") << QByteArrayLiteral("GstAudioTestSrcWave::Values") - << true << true << true; + << true << true << true << true; } void testProperties() @@ -94,6 +95,7 @@ private slots: QFETCH(QByteArray, type); QFETCH(bool, readable); QFETCH(bool, writable); + QFETCH(bool, resetable); QFETCH(bool, enumType); Item item(GST_OBJECT(gst_element_factory_make(factory.constData(), Q_NULLPTR))); @@ -105,10 +107,9 @@ private slots: const auto &property = item.metaObject()->property(propertyIndex); - qDebug() << property.isEnumType() << property.isFlagType(); - QCOMPARE(property.isReadable(), readable); QCOMPARE(property.isWritable(), writable); + QCOMPARE(property.isResettable(), resetable); QCOMPARE(property.isEnumType(), enumType); QVERIFY(property.hasNotifySignal()); QCOMPARE(property.typeName(), type.constData()); diff --git a/tests/tst_qml/tst_quickstreamer.qml b/tests/tst_qml/tst_quickstreamer.qml index acf32c5..e04b6d1 100644 --- a/tests/tst_qml/tst_quickstreamer.qml +++ b/tests/tst_qml/tst_quickstreamer.qml @@ -5,16 +5,17 @@ TestCase { name: "QuickStreamer" Pipeline { - id: "pipeline" + id: pipeline + name: "brouhaha" - AppSrc { - id: appSource - name: "brouhaha" - } + AppSrc { id: appSource } + AppSink { id: appSink } + } - AppSink { - id: appSink - } + SignalSpy { + id: pipelineNameSpy + target: pipeline + signalName: "nameChanged" } AudioTestSrc { @@ -29,9 +30,25 @@ TestCase { function test_nameProperty() { - compare(pipeline.name, "pipeline0") + compare(pipeline.name, "brouhaha") + compare(appSource.name, "appsrc0") compare(appSink.name, "appsink0") - compare(appSource.name, "brouhaha") + + compare(pipelineNameSpy.count, 0) + compare(pipeline.name, "brouhaha") + compare(pipelineNameSpy.count, 0) + + pipeline.name = "silence" + + compare(pipelineNameSpy.count, 1) + compare(pipeline.name, "silence") + compare(pipelineNameSpy.count, 1) + + pipeline.name = undefined + + compare(pipelineNameSpy.count, 2) + compare(pipeline.name, "pipeline1") + compare(pipelineNameSpy.count, 2) } function test_children() |