summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMathias Hasselmann <mathias.hasselmann@kdab.com>2013-11-13 22:53:35 +0100
committerMathias Hasselmann <mathias.hasselmann@kdab.com>2013-11-13 23:02:16 +0100
commit30f9bd3d57b673b9962264d14f8087c5381abb75 (patch)
tree0a19a96182691147164ff61c09212407a935835a
parenta0e901691b91eaf293a50f01cf9eaaf08f6c963a (diff)
downloadqtquickstreamer-30f9bd3d57b673b9962264d14f8087c5381abb75.tar.gz
qtquickstreamer-30f9bd3d57b673b9962264d14f8087c5381abb75.tar.xz
Make properties resetable
-rw-r--r--src/QuickStreamer/item.cpp121
-rw-r--r--src/QuickStreamer/item.h2
-rw-r--r--tests/tst_metaobject/tst_metaobjecttest.cpp13
-rw-r--r--tests/tst_qml/tst_quickstreamer.qml37
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()