Add a QPropertyAlias
A property alias is the equivalent of the "alias" keyword in QML. It provides the same API as QProperty, but redirects any access to the QProperty it was initialized with. When the original property is destroyed the binding becomes invalid and ignores any further acccess. Task-number: QTBUG-84370 Change-Id: I0aef8d50e73a2aa9e7703d51194d4c5480573578 Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io> Reviewed-by: Lars Knoll <lars.knoll@qt.io>
This commit is contained in:
parent
0a07f9528c
commit
a64a0ce331
@ -254,6 +254,12 @@ QPropertyObserver::QPropertyObserver(void (*callback)(QPropertyObserver *, void
|
||||
d.setChangeHandler(callback);
|
||||
}
|
||||
|
||||
QPropertyObserver::QPropertyObserver(void *aliasedPropertyPtr)
|
||||
{
|
||||
QPropertyObserverPointer d{this};
|
||||
d.setAliasedProperty(aliasedPropertyPtr);
|
||||
}
|
||||
|
||||
void QPropertyObserver::setSource(QPropertyBase &property)
|
||||
{
|
||||
QPropertyObserverPointer d{this};
|
||||
@ -303,6 +309,8 @@ QPropertyObserver &QPropertyObserver::operator=(QPropertyObserver &&other)
|
||||
|
||||
void QPropertyObserverPointer::unlink()
|
||||
{
|
||||
if (ptr->next.tag() & QPropertyObserver::ObserverNotifiesAlias)
|
||||
ptr->aliasedPropertyPtr = 0;
|
||||
if (ptr->next)
|
||||
ptr->next->prev = ptr->prev;
|
||||
if (ptr->prev)
|
||||
@ -317,6 +325,12 @@ void QPropertyObserverPointer::setChangeHandler(void (*changeHandler)(QPropertyO
|
||||
ptr->next.setTag(QPropertyObserver::ObserverNotifiesChangeHandler);
|
||||
}
|
||||
|
||||
void QPropertyObserverPointer::setAliasedProperty(void *propertyPtr)
|
||||
{
|
||||
ptr->aliasedPropertyPtr = quintptr(propertyPtr);
|
||||
ptr->next.setTag(QPropertyObserver::ObserverNotifiesAlias);
|
||||
}
|
||||
|
||||
void QPropertyObserverPointer::setBindingToMarkDirty(QPropertyBindingPrivate *binding)
|
||||
{
|
||||
ptr->bindingToMarkDirty = binding;
|
||||
@ -331,7 +345,8 @@ void QPropertyObserverPointer::notify(QPropertyBindingPrivate *triggeringBinding
|
||||
auto observer = const_cast<QPropertyObserver*>(ptr);
|
||||
while (observer) {
|
||||
auto * const next = observer->next.data();
|
||||
if (observer->next.tag() == QPropertyObserver::ObserverNotifiesChangeHandler) {
|
||||
switch (observer->next.tag()) {
|
||||
case QPropertyObserver::ObserverNotifiesChangeHandler:
|
||||
if (!knownIfPropertyChanged && triggeringBinding) {
|
||||
knownIfPropertyChanged = true;
|
||||
|
||||
@ -344,9 +359,13 @@ void QPropertyObserverPointer::notify(QPropertyBindingPrivate *triggeringBinding
|
||||
handlerToCall(observer, propertyDataPtr);
|
||||
observer->changeHandler = handlerToCall;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
case QPropertyObserver::ObserverNotifiesBinding:
|
||||
if (observer->bindingToMarkDirty)
|
||||
observer->bindingToMarkDirty->markDirtyAndNotifyObservers();
|
||||
break;
|
||||
case QPropertyObserver::ObserverNotifiesAlias:
|
||||
break;
|
||||
}
|
||||
observer = next;
|
||||
}
|
||||
@ -354,7 +373,8 @@ void QPropertyObserverPointer::notify(QPropertyBindingPrivate *triggeringBinding
|
||||
|
||||
void QPropertyObserverPointer::observeProperty(QPropertyBasePointer property)
|
||||
{
|
||||
unlink();
|
||||
if (ptr->prev)
|
||||
unlink();
|
||||
property.addObserver(ptr);
|
||||
}
|
||||
|
||||
@ -697,4 +717,227 @@ QPropertyBindingSourceLocation QPropertyBindingError::location() const
|
||||
A handler instance can be transferred between C++ scopes using move semantics.
|
||||
*/
|
||||
|
||||
/*!
|
||||
\class QPropertyAlias
|
||||
\inmodule QtCore
|
||||
\brief The QPropertyAlias class is a safe alias for a QProperty with same template parameter.
|
||||
|
||||
\ingroup tools
|
||||
|
||||
QPropertyAlias\<T\> wraps a pointer to a QProperty\<T\> and automatically
|
||||
invalidates itself when the QProperty\<T\> is destroyed. It forwards all
|
||||
method invocations to the wrapped property. For example:
|
||||
|
||||
\code
|
||||
QProperty<QString> *name = new QProperty<QString>("John");
|
||||
QProperty<int> age(41);
|
||||
|
||||
QPropertyAlias<QString> nameAlias(name);
|
||||
QPropertyAlias<int> ageAlias(&age);
|
||||
|
||||
QPropertyAlias<QString> fullname;
|
||||
fullname.setBinding([&]() { return nameAlias.value() + " age:" + QString::number(ageAlias.value()); });
|
||||
|
||||
qDebug() << fullname.value(); // Prints "Smith age: 41"
|
||||
|
||||
*name = "Emma"; // Marks binding expression as dirty
|
||||
|
||||
qDebug() << fullname.value(); // Re-evaluates the binding expression and prints "Emma age: 41"
|
||||
|
||||
// Birthday is coming up
|
||||
ageAlias.setValue(age.value() + 1); // Writes the age property through the alias
|
||||
|
||||
qDebug() << fullname.value(); // Re-evaluates the binding expression and prints "Emma age: 42"
|
||||
|
||||
delete name; // Leaves the alias in an invalid, but accessible state
|
||||
nameAlias.setValue("Eve"); // Ignored: nameAlias carries a default-constructed QString now
|
||||
|
||||
ageAlias.setValue(92);
|
||||
qDebug() << fullname.value(); // Re-evaluates the binding expression and prints " age: 92"
|
||||
\endcode
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn template <typename T> QPropertyAlias<T>::QPropertyAlias(QProperty<T> *property)
|
||||
|
||||
Constructs a property alias for the given \a property.
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn template <typename T> explicit QPropertyAlias<T>::QPropertyAlias(QPropertyAlias<T> *alias)
|
||||
|
||||
Constructs a property alias for the property aliased by \a alias.
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn template <typename T> T QPropertyAlias<T>::value() const
|
||||
|
||||
Returns the value of the aliased property. This may evaluate a binding
|
||||
expression that is tied to the property, before returning the value.
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn template <typename T> QPropertyAlias<T>::operator T() const
|
||||
|
||||
Returns the value of the aliased property. This may evaluate a binding
|
||||
expression that is tied to the property, before returning the value.
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn template <typename T> void QPropertyAlias<T>::setValue(const T &newValue)
|
||||
|
||||
Assigns \a newValue to the aliased property and removes the property's
|
||||
associated binding, if present.
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn template <typename T> void QPropertyAlias<T>::setValue(T &&newValue)
|
||||
\overload
|
||||
|
||||
Assigns \a newValue to the aliased property and removes the property's
|
||||
associated binding, if present.
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn template <typename T> QPropertyAlias<T> &QPropertyAlias<T>::operator=(const T &newValue)
|
||||
|
||||
Assigns \a newValue to the aliased property and returns a reference to this
|
||||
QPropertyAlias.
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn template <typename T> QPropertyAlias<T> &QPropertyAlias<T>::operator=(T &&newValue)
|
||||
\overload
|
||||
|
||||
Assigns \a newValue to the aliased property and returns a reference to this
|
||||
QPropertyAlias.
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn template <typename T> QPropertyAlias<T> &QPropertyAlias<T>::operator=(const QPropertyBinding<T> &newBinding)
|
||||
\overload
|
||||
|
||||
Associates the value of the aliased property with the provided \a newBinding
|
||||
expression and returns a reference to this alias. The first time the
|
||||
property value is read, either from the property itself or from any alias, the
|
||||
binding is evaluated. Whenever a dependency of the binding changes, the
|
||||
binding will be re-evaluated the next time the value of this property is read.
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn template <typename T> QPropertyBinding<T> QPropertyAlias<T>::setBinding(const QPropertyBinding<T> &newBinding)
|
||||
|
||||
Associates the value of the aliased property with the provided \a newBinding
|
||||
expression and returns any previous binding the associated with the aliased
|
||||
property. The first time the property value is read, either from the property
|
||||
itself or from any alias, the binding is evaluated. Whenever a dependency of
|
||||
the binding changes, the binding will be re-evaluated the next time the value
|
||||
of this property is read.
|
||||
|
||||
Returns any previous binding associated with the property, or a
|
||||
default-constructed QPropertyBinding<T>.
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn template <typename T> QPropertyBinding<T> QPropertyAlias<T>::setBinding(QPropertyBinding<T> &&newBinding)
|
||||
\overload
|
||||
|
||||
Associates the value of the aliased property with the provided \a newBinding
|
||||
expression and returns any previous binding the associated with the aliased
|
||||
property. The first time the property value is read, either from the property
|
||||
itself or from any alias, the binding is evaluated. Whenever a dependency of
|
||||
the binding changes, the binding will be re-evaluated the next time the value
|
||||
of this property is read.
|
||||
|
||||
Returns any previous binding associated with the property, or a
|
||||
default-constructed QPropertyBinding<T>.
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn template <typename T> QPropertyBinding<T> bool QPropertyAlias<T>::setBinding(const QUntypedPropertyBinding &newBinding)
|
||||
\overload
|
||||
|
||||
Associates the value of the aliased property with the provided \a newBinding
|
||||
expression. The first time the property value is read, either from the
|
||||
property itself or from any alias, the binding is evaluated. Whenever a
|
||||
dependency of the binding changes, the binding will be re-evaluated the next
|
||||
time the value of this property is read.
|
||||
|
||||
Returns true if the type of this property is the same as the type the binding
|
||||
function returns; false otherwise.
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn template <typename T> template <typename Functor> QPropertyBinding<T> setBinding(Functor f)
|
||||
\overload
|
||||
|
||||
Associates the value of the aliased property with the provided functor \a f
|
||||
expression. The first time the property value is read, either from the
|
||||
property itself or from any alias, the binding is evaluated. Whenever a
|
||||
dependency of the binding changes, the binding will be re-evaluated the next
|
||||
time the value of this property is read.
|
||||
|
||||
Returns any previous binding associated with the property, or a
|
||||
default-constructed QPropertyBinding<T>.
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn template <typename T> bool QPropertyAlias<T>::hasBinding() const
|
||||
|
||||
Returns true if the aliased property is associated with a binding; false
|
||||
otherwise.
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn template <typename T> QPropertyBinding<T> QPropertyAlias<T>::binding() const
|
||||
|
||||
Returns the binding expression that is associated with the aliased property. A
|
||||
default constructed QPropertyBinding<T> will be returned if no such
|
||||
association exists.
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn template <typename T> QPropertyBinding<T> QPropertyAlias<T>::takeBinding()
|
||||
|
||||
Disassociates the binding expression from the aliased property and returns it.
|
||||
After calling this function, the value of the property will only change if
|
||||
you assign a new value to it, or when a new binding is set.
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn template <typename T> template <typename Functor> QPropertyChangeHandler<T, Functor> QPropertyAlias<T>::onValueChanged(Functor f)
|
||||
|
||||
Registers the given functor \a f as a callback that shall be called whenever
|
||||
the value of the aliased property changes.
|
||||
|
||||
The callback \a f is expected to be a type that has a plain call operator () without any
|
||||
parameters. This means that you can provide a C++ lambda expression, an std::function
|
||||
or even a custom struct with a call operator.
|
||||
|
||||
The returned property change handler object keeps track of the registration. When it
|
||||
goes out of scope, the callback is de-registered.
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn template <typename T> template <typename Functor> QPropertyChangeHandler<T, Functor> QPropertyAlias<T>::subscribe(Functor f)
|
||||
|
||||
Subscribes the given functor \a f as a callback that is called immediately and whenever
|
||||
the value of the aliased property changes in the future.
|
||||
|
||||
The callback \a f is expected to be a type that has a plain call operator () without any
|
||||
parameters. This means that you can provide a C++ lambda expression, an std::function
|
||||
or even a custom struct with a call operator.
|
||||
|
||||
The returned property change handler object keeps track of the subscription. When it
|
||||
goes out of scope, the callback is unsubscribed.
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn template <typename T> bool QPropertyAlias<T>::isValid() const
|
||||
|
||||
Returns true if the aliased property still exists; false otherwise.
|
||||
|
||||
If the aliased property doesn't exist, all other method calls are ignored.
|
||||
*/
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
@ -378,10 +378,10 @@ class Q_CORE_EXPORT QPropertyObserver
|
||||
public:
|
||||
// Internal
|
||||
enum ObserverTag {
|
||||
ObserverNotifiesBinding = 0x0,
|
||||
ObserverNotifiesChangeHandler = 0x1,
|
||||
ObserverNotifiesBinding,
|
||||
ObserverNotifiesChangeHandler,
|
||||
ObserverNotifiesAlias,
|
||||
};
|
||||
Q_DECLARE_FLAGS(ObserverTags, ObserverTag)
|
||||
|
||||
QPropertyObserver();
|
||||
QPropertyObserver(QPropertyObserver &&other);
|
||||
@ -394,18 +394,26 @@ public:
|
||||
|
||||
protected:
|
||||
QPropertyObserver(void (*callback)(QPropertyObserver*, void *));
|
||||
QPropertyObserver(void *aliasedPropertyPtr);
|
||||
|
||||
template<typename PropertyType>
|
||||
QProperty<PropertyType> *aliasedProperty() const
|
||||
{
|
||||
return reinterpret_cast<QProperty<PropertyType> *>(aliasedPropertyPtr);
|
||||
}
|
||||
|
||||
private:
|
||||
void setSource(QtPrivate::QPropertyBase &property);
|
||||
|
||||
QTaggedPointer<QPropertyObserver, ObserverTags> next;
|
||||
QTaggedPointer<QPropertyObserver, ObserverTag> next;
|
||||
// prev is a pointer to the "next" element within the previous node, or to the "firstObserverPtr" if it is the
|
||||
// first node.
|
||||
QtPrivate::QTagPreservingPointerToPointer<QPropertyObserver, ObserverTags> prev;
|
||||
QtPrivate::QTagPreservingPointerToPointer<QPropertyObserver, ObserverTag> prev;
|
||||
|
||||
union {
|
||||
QPropertyBindingPrivate *bindingToMarkDirty = nullptr;
|
||||
void (*changeHandler)(QPropertyObserver*, void *);
|
||||
quintptr aliasedPropertyPtr;
|
||||
};
|
||||
|
||||
QPropertyObserver(const QPropertyObserver &) = delete;
|
||||
@ -416,8 +424,6 @@ private:
|
||||
friend class QPropertyBindingPrivate;
|
||||
};
|
||||
|
||||
Q_DECLARE_OPERATORS_FOR_FLAGS(QPropertyObserver::ObserverTags)
|
||||
|
||||
template <typename Functor>
|
||||
class QPropertyChangeHandler : public QPropertyObserver
|
||||
{
|
||||
@ -487,6 +493,145 @@ struct QPropertyMemberChangeHandler<PropertyMember, Callback> : public QProperty
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class QPropertyAlias : public QPropertyObserver
|
||||
{
|
||||
Q_DISABLE_COPY_MOVE(QPropertyAlias)
|
||||
public:
|
||||
QPropertyAlias(QProperty<T> *property)
|
||||
: QPropertyObserver(property)
|
||||
{
|
||||
if (property)
|
||||
setSource(*property);
|
||||
}
|
||||
|
||||
QPropertyAlias(QPropertyAlias<T> *alias)
|
||||
: QPropertyAlias(alias->aliasedProperty<T>())
|
||||
{}
|
||||
|
||||
T value() const
|
||||
{
|
||||
if (auto *p = aliasedProperty<T>())
|
||||
return p->value();
|
||||
return T();
|
||||
}
|
||||
|
||||
operator T() const { return value(); }
|
||||
|
||||
void setValue(T &&newValue)
|
||||
{
|
||||
if (auto *p = aliasedProperty<T>())
|
||||
p->setValue(std::move(newValue));
|
||||
}
|
||||
|
||||
void setValue(const T &newValue)
|
||||
{
|
||||
if (auto *p = aliasedProperty<T>())
|
||||
p->setValue(newValue);
|
||||
}
|
||||
|
||||
QPropertyAlias<T> &operator=(T &&newValue)
|
||||
{
|
||||
if (auto *p = aliasedProperty<T>())
|
||||
*p = std::move(newValue);
|
||||
return *this;
|
||||
}
|
||||
|
||||
QPropertyAlias<T> &operator=(const T &newValue)
|
||||
{
|
||||
if (auto *p = aliasedProperty<T>())
|
||||
*p = newValue;
|
||||
return *this;
|
||||
}
|
||||
|
||||
QPropertyAlias<T> &operator=(const QPropertyBinding<T> &newBinding)
|
||||
{
|
||||
setBinding(newBinding);
|
||||
return *this;
|
||||
}
|
||||
|
||||
QPropertyAlias<T> &operator=(QPropertyBinding<T> &&newBinding)
|
||||
{
|
||||
setBinding(std::move(newBinding));
|
||||
return *this;
|
||||
}
|
||||
|
||||
QPropertyBinding<T> setBinding(const QPropertyBinding<T> &newBinding)
|
||||
{
|
||||
if (auto *p = aliasedProperty<T>())
|
||||
return p->setBinding(newBinding);
|
||||
return QPropertyBinding<T>();
|
||||
}
|
||||
|
||||
QPropertyBinding<T> setBinding(QPropertyBinding<T> &&newBinding)
|
||||
{
|
||||
if (auto *p = aliasedProperty<T>())
|
||||
return p->setBinding(std::move(newBinding));
|
||||
return QPropertyBinding<T>();
|
||||
}
|
||||
|
||||
bool setBinding(const QUntypedPropertyBinding &newBinding)
|
||||
{
|
||||
if (auto *p = aliasedProperty<T>())
|
||||
return p->setBinding(newBinding);
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifndef Q_CLANG_QDOC
|
||||
template <typename Functor>
|
||||
QPropertyBinding<T> setBinding(Functor &&f,
|
||||
const QPropertyBindingSourceLocation &location = QT_PROPERTY_DEFAULT_BINDING_LOCATION,
|
||||
std::enable_if_t<std::is_invocable_v<Functor>> * = nullptr)
|
||||
{
|
||||
return setBinding(Qt::makePropertyBinding(std::forward<Functor>(f), location));
|
||||
}
|
||||
#else
|
||||
template <typename Functor>
|
||||
QPropertyBinding<T> setBinding(Functor f);
|
||||
#endif
|
||||
|
||||
bool hasBinding() const
|
||||
{
|
||||
if (auto *p = aliasedProperty<T>())
|
||||
return p->hasBinding();
|
||||
return false;
|
||||
}
|
||||
|
||||
QPropertyBinding<T> binding() const
|
||||
{
|
||||
if (auto *p = aliasedProperty<T>())
|
||||
return p->binding();
|
||||
return QPropertyBinding<T>();
|
||||
}
|
||||
|
||||
QPropertyBinding<T> takeBinding()
|
||||
{
|
||||
if (auto *p = aliasedProperty<T>())
|
||||
return p->takeBinding();
|
||||
return QPropertyBinding<T>();
|
||||
}
|
||||
|
||||
template<typename Functor>
|
||||
QPropertyChangeHandler<Functor> onValueChanged(Functor f)
|
||||
{
|
||||
if (auto *p = aliasedProperty<T>())
|
||||
return p->onValueChanged(f);
|
||||
return QPropertyChangeHandler<Functor>(f);
|
||||
}
|
||||
|
||||
template<typename Functor>
|
||||
QPropertyChangeHandler<Functor> subscribe(Functor f)
|
||||
{
|
||||
if (auto *p = aliasedProperty<T>())
|
||||
return p->subscribe(f);
|
||||
return QPropertyChangeHandler<Functor>(f);
|
||||
}
|
||||
|
||||
bool isValid() const
|
||||
{
|
||||
return aliasedProperty<T>() != nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
|
@ -88,6 +88,7 @@ struct QPropertyObserverPointer
|
||||
|
||||
void setBindingToMarkDirty(QPropertyBindingPrivate *binding);
|
||||
void setChangeHandler(void (*changeHandler)(QPropertyObserver *, void *));
|
||||
void setAliasedProperty(void *propertyPtr);
|
||||
|
||||
void notify(QPropertyBindingPrivate *triggeringBinding, void *propertyDataPtr);
|
||||
void observeProperty(QPropertyBasePointer property);
|
||||
|
@ -70,6 +70,7 @@ private slots:
|
||||
void staticChangeHandler();
|
||||
void setBindingFunctor();
|
||||
void multipleObservers();
|
||||
void propertyAlias();
|
||||
};
|
||||
|
||||
void tst_QProperty::functorBinding()
|
||||
@ -722,6 +723,52 @@ void tst_QProperty::multipleObservers()
|
||||
QCOMPARE(property.value(), 22);
|
||||
}
|
||||
|
||||
void tst_QProperty::propertyAlias()
|
||||
{
|
||||
QScopedPointer<QProperty<int>> property(new QProperty<int>);
|
||||
property->setValue(5);
|
||||
QPropertyAlias alias(property.get());
|
||||
QVERIFY(alias.isValid());
|
||||
QCOMPARE(alias.value(), 5);
|
||||
|
||||
int value1 = 1;
|
||||
auto changeHandler = alias.onValueChanged([&]() { value1 = alias.value(); });
|
||||
QCOMPARE(value1, 1);
|
||||
|
||||
int value2 = 2;
|
||||
auto subscribeHandler = alias.subscribe([&]() { value2 = alias.value(); });
|
||||
QCOMPARE(value2, 5);
|
||||
|
||||
alias.setValue(6);
|
||||
QVERIFY(alias.isValid());
|
||||
QCOMPARE(alias.value(), 6);
|
||||
QCOMPARE(value1, 6);
|
||||
QCOMPARE(value2, 6);
|
||||
|
||||
alias.setBinding([]() { return 12; });
|
||||
QCOMPARE(value1, 12);
|
||||
QCOMPARE(value2, 12);
|
||||
QCOMPARE(alias.value(), 12);
|
||||
|
||||
alias.setValue(22);
|
||||
QCOMPARE(value1, 22);
|
||||
QCOMPARE(value2, 22);
|
||||
QCOMPARE(alias.value(), 22);
|
||||
|
||||
property.reset();
|
||||
|
||||
QVERIFY(!alias.isValid());
|
||||
QCOMPARE(alias.value(), int());
|
||||
QCOMPARE(value1, 22);
|
||||
QCOMPARE(value2, 22);
|
||||
|
||||
// Does not crash
|
||||
alias.setValue(25);
|
||||
QCOMPARE(alias.value(), int());
|
||||
QCOMPARE(value1, 22);
|
||||
QCOMPARE(value2, 22);
|
||||
}
|
||||
|
||||
QTEST_MAIN(tst_QProperty);
|
||||
|
||||
#include "tst_qproperty.moc"
|
||||
|
Loading…
Reference in New Issue
Block a user