Q(Untyped)Bindable: Print warnings when operations fail
Instead of silently failing, we now print an explanatory warning to aid with debugging. Task-number: QTBUG-89512 Change-Id: I36dd2ce452af12d0523c19286919095e366bd390 Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>bb10
parent
d225c6afe7
commit
98b4f4bc4d
|
|
@ -42,9 +42,12 @@
|
|||
|
||||
#include <qscopedvaluerollback.h>
|
||||
#include <QScopeGuard>
|
||||
#include <QtCore/qloggingcategory.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
Q_LOGGING_CATEGORY(lcQPropertyBinding, "qt.qproperty.binding");
|
||||
|
||||
using namespace QtPrivate;
|
||||
|
||||
void QPropertyBindingPrivatePtr::destroyAndFreeMemory()
|
||||
|
|
@ -2131,6 +2134,36 @@ bool isPropertyInBindingWrapper(const QUntypedPropertyData *property)
|
|||
bindingStatus.currentCompatProperty->property == property;
|
||||
}
|
||||
|
||||
namespace BindableWarnings {
|
||||
|
||||
void printUnsuitableBindableWarning(QAnyStringView prefix, BindableWarnings::Reason reason)
|
||||
{
|
||||
switch (reason) {
|
||||
case QtPrivate::BindableWarnings::NonBindableInterface:
|
||||
qCWarning(lcQPropertyBinding).noquote() << prefix.toString()
|
||||
<< "The QBindable does not allow interaction with the binding.";
|
||||
break;
|
||||
case QtPrivate::BindableWarnings::ReadOnlyInterface:
|
||||
qCWarning(lcQPropertyBinding).noquote() << prefix.toString()
|
||||
<< "The QBindable is read-only.";
|
||||
break;
|
||||
default:
|
||||
case QtPrivate::BindableWarnings::InvalidInterface:
|
||||
qCWarning(lcQPropertyBinding).noquote() << prefix.toString()
|
||||
<< "The QBindable is invalid.";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void printMetaTypeMismatch(QMetaType actual, QMetaType expected)
|
||||
{
|
||||
qCWarning(lcQPropertyBinding) << "setBinding: Could not set binding as the property expects it to be of type"
|
||||
<< actual.name()
|
||||
<< "but got" << expected.name() << "instead.";
|
||||
}
|
||||
|
||||
} // namespace BindableWarnings end
|
||||
|
||||
} // namespace QtPrivate end
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
|
|
|||
|
|
@ -43,9 +43,7 @@
|
|||
#include <QtCore/qglobal.h>
|
||||
#include <QtCore/qshareddata.h>
|
||||
#include <QtCore/qstring.h>
|
||||
#include <functional>
|
||||
#include <type_traits>
|
||||
#include <variant>
|
||||
|
||||
#include <QtCore/qpropertyprivate.h>
|
||||
|
||||
|
|
@ -555,6 +553,15 @@ public:
|
|||
|
||||
}
|
||||
|
||||
namespace QtPrivate {
|
||||
// used in Q(Untyped)Bindable to print warnings about various binding errors
|
||||
namespace BindableWarnings {
|
||||
enum Reason { InvalidInterface, NonBindableInterface, ReadOnlyInterface };
|
||||
Q_CORE_EXPORT void printUnsuitableBindableWarning(QAnyStringView prefix, Reason reason);
|
||||
Q_CORE_EXPORT void printMetaTypeMismatch(QMetaType actual, QMetaType expected);
|
||||
}
|
||||
}
|
||||
|
||||
class QUntypedBindable
|
||||
{
|
||||
protected:
|
||||
|
|
@ -600,6 +607,11 @@ public:
|
|||
{
|
||||
if (iface)
|
||||
iface->setObserver(data, observer);
|
||||
#ifndef QT_NO_DEBUG
|
||||
else
|
||||
QtPrivate::BindableWarnings::printUnsuitableBindableWarning("observe:",
|
||||
QtPrivate::BindableWarnings::InvalidInterface);
|
||||
#endif
|
||||
}
|
||||
|
||||
template<typename Functor>
|
||||
|
|
@ -619,16 +631,31 @@ public:
|
|||
|
||||
QUntypedPropertyBinding binding() const
|
||||
{
|
||||
if (!iface->getBinding)
|
||||
if (!isBindable()) {
|
||||
#ifndef QT_NO_DEBUG
|
||||
QtPrivate::BindableWarnings::printUnsuitableBindableWarning("binding: ",
|
||||
QtPrivate::BindableWarnings::NonBindableInterface);
|
||||
#endif
|
||||
return QUntypedPropertyBinding();
|
||||
}
|
||||
return iface->getBinding(data);
|
||||
}
|
||||
bool setBinding(const QUntypedPropertyBinding &binding)
|
||||
{
|
||||
if (!iface->setBinding)
|
||||
if (isReadOnly()) {
|
||||
#ifndef QT_NO_DEBUG
|
||||
const auto errorType = iface ? QtPrivate::BindableWarnings::ReadOnlyInterface :
|
||||
QtPrivate::BindableWarnings::InvalidInterface;
|
||||
QtPrivate::BindableWarnings::printUnsuitableBindableWarning("setBinding: Could not set binding via bindable interface.", errorType);
|
||||
#endif
|
||||
return false;
|
||||
if (!binding.isNull() && binding.valueMetaType() != iface->metaType())
|
||||
}
|
||||
if (!binding.isNull() && binding.valueMetaType() != iface->metaType()) {
|
||||
#ifndef QT_NO_DEBUG
|
||||
QtPrivate::BindableWarnings::printMetaTypeMismatch(iface->metaType(), binding.valueMetaType());
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
iface->setBinding(data, binding);
|
||||
return true;
|
||||
}
|
||||
|
|
@ -675,7 +702,16 @@ public:
|
|||
QPropertyBinding<T> setBinding(const QPropertyBinding<T> &binding)
|
||||
{
|
||||
Q_ASSERT(!iface || binding.isNull() || binding.valueMetaType() == iface->metaType());
|
||||
return (iface && iface->setBinding) ? static_cast<QPropertyBinding<T> &&>(iface->setBinding(data, binding)) : QPropertyBinding<T>();
|
||||
|
||||
if (iface && iface->setBinding)
|
||||
return static_cast<QPropertyBinding<T> &&>(iface->setBinding(data, binding));
|
||||
#ifndef QT_NO_DEBUG
|
||||
if (!iface)
|
||||
QtPrivate::BindableWarnings::printUnsuitableBindableWarning("setBinding", QtPrivate::BindableWarnings::InvalidInterface);
|
||||
else
|
||||
QtPrivate::BindableWarnings::printUnsuitableBindableWarning("setBinding: Could not set binding via bindable interface.", QtPrivate::BindableWarnings::ReadOnlyInterface);
|
||||
#endif
|
||||
return QPropertyBinding<T>();
|
||||
}
|
||||
#ifndef Q_CLANG_QDOC
|
||||
template <typename Functor>
|
||||
|
|
|
|||
|
|
@ -1065,6 +1065,25 @@ void tst_QProperty::quntypedBindableApi()
|
|||
QCOMPARE(iprop.value(), 42);
|
||||
QUntypedBindable propLess;
|
||||
QVERIFY(propLess.takeBinding().isNull());
|
||||
|
||||
QUntypedBindable invalidBindable;
|
||||
#ifndef QT_NO_DEBUG
|
||||
QTest::ignoreMessage(QtMsgType::QtWarningMsg, "setBinding: Could not set binding via bindable interface. The QBindable is invalid.");
|
||||
#endif
|
||||
invalidBindable.setBinding(Qt::makePropertyBinding(iprop));
|
||||
|
||||
QUntypedBindable readOnlyBindable(static_cast<const QProperty<int> *>(&iprop) );
|
||||
QVERIFY(readOnlyBindable.isReadOnly());
|
||||
#ifndef QT_NO_DEBUG
|
||||
QTest::ignoreMessage(QtMsgType::QtWarningMsg, "setBinding: Could not set binding via bindable interface. The QBindable is read-only.");
|
||||
#endif
|
||||
readOnlyBindable.setBinding(Qt::makePropertyBinding(iprop));
|
||||
|
||||
QProperty<float> fprop;
|
||||
#ifndef QT_NO_DEBUG
|
||||
QTest::ignoreMessage(QtMsgType::QtWarningMsg, "setBinding: Could not set binding as the property expects it to be of type int but got float instead.");
|
||||
#endif
|
||||
bindable.setBinding(Qt::makePropertyBinding(fprop));
|
||||
}
|
||||
|
||||
void tst_QProperty::readonlyConstQBindable()
|
||||
|
|
@ -1216,6 +1235,9 @@ void tst_QProperty::qobjectBindableSignalTakingNewValue()
|
|||
void tst_QProperty::testNewStuff()
|
||||
{
|
||||
MyQObject testReadOnly;
|
||||
#ifndef QT_NO_DEBUG
|
||||
QTest::ignoreMessage(QtMsgType::QtWarningMsg, "setBinding: Could not set binding via bindable interface. The QBindable is read-only.");
|
||||
#endif
|
||||
testReadOnly.bindableFoo().setBinding([](){return 42;});
|
||||
auto bindable = const_cast<const MyQObject&>(testReadOnly).bindableFoo();
|
||||
QVERIFY(bindable.hasBinding());
|
||||
|
|
|
|||
Loading…
Reference in New Issue