Source code
Revision control
Copy as Markdown
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include "testtypes.h"
#ifndef QT_NO_WIDGETS
# include <QWidget>
# include <QPlainTextEdit>
#endif
#include <QQmlEngine>
#include <QJSEngine>
#include <QThread>
#include <QtQuickTestUtils/private/qmlutils_p.h>
class BaseExtensionObject : public QObject
{
Q_OBJECT
Q_PROPERTY(int baseExtendedProperty READ extendedProperty WRITE setExtendedProperty NOTIFY extendedPropertyChanged)
public:
BaseExtensionObject(QObject *parent) : QObject(parent), m_value(0) {}
int extendedProperty() const { return m_value; }
void setExtendedProperty(int v) { m_value = v; emit extendedPropertyChanged(); }
signals:
void extendedPropertyChanged();
private:
int m_value;
};
class AbstractExtensionObject : public QObject
{
Q_OBJECT
Q_PROPERTY(int abstractProperty READ abstractProperty WRITE setAbstractProperty NOTIFY abstractPropertyChanged)
public:
AbstractExtensionObject(QObject *parent = nullptr) : QObject(parent), m_abstractProperty(-1) {}
void setAbstractProperty(int abstractProperty) { m_abstractProperty = abstractProperty; emit abstractPropertyChanged(); }
int abstractProperty() const { return m_abstractProperty; }
virtual void shouldBeImplemented() = 0;
signals:
void abstractPropertyChanged();
private:
int m_abstractProperty;
};
class ImplementedExtensionObject : public AbstractExtensionObject
{
Q_OBJECT
Q_PROPERTY(int implementedProperty READ implementedProperty WRITE setImplementedProperty NOTIFY implementedPropertyChanged)
public:
ImplementedExtensionObject(QObject *parent = nullptr) : AbstractExtensionObject(parent), m_implementedProperty(883) {}
void shouldBeImplemented() override {}
void setImplementedProperty(int implementedProperty) { m_implementedProperty = implementedProperty; emit implementedPropertyChanged(); }
int implementedProperty() const { return m_implementedProperty; }
signals:
void implementedPropertyChanged();
private:
int m_implementedProperty;
};
class ExtensionObject : public QObject
{
Q_OBJECT
Q_PROPERTY(int extendedProperty READ extendedProperty WRITE setExtendedProperty NOTIFY extendedPropertyChanged)
public:
ExtensionObject(QObject *parent) : QObject(parent), m_value(0) {}
int extendedProperty() const { return m_value; }
void setExtendedProperty(int v) { m_value = v; emit extendedPropertyChanged(); }
signals:
void extendedPropertyChanged();
private:
int m_value;
};
class DefaultPropertyExtensionObject : public QObject
{
Q_OBJECT
Q_CLASSINFO("DefaultProperty", "firstProperty")
public:
DefaultPropertyExtensionObject(QObject *parent) : QObject(parent) {}
};
class QWidgetDeclarativeUI : public QObject
{
Q_OBJECT
Q_PROPERTY(int width READ width WRITE setWidth NOTIFY widthChanged)
signals:
void widthChanged();
public:
QWidgetDeclarativeUI(QObject *other) : QObject(other) { }
public:
int width() const { return 0; }
void setWidth(int) { }
};
void MyQmlObject::v8function(QQmlV4FunctionPtr function)
{
function->v4engine()->throwError(QStringLiteral("Exception thrown from within QObject slot"));
}
static QJSValue script_api(QQmlEngine *engine, QJSEngine *scriptEngine)
{
Q_UNUSED(engine);
static int testProperty = 13;
QJSValue v = scriptEngine->newObject();
v.setProperty("scriptTestProperty", testProperty++);
return v;
}
static QJSValue readonly_script_api(QQmlEngine *engine, QJSEngine *scriptEngine)
{
Q_UNUSED(engine);
static int testProperty = 42;
QJSValue v = scriptEngine->newObject();
v.setProperty("scriptTestProperty", testProperty++);
// now freeze it so that it's read-only
QJSValue freezeFunction = scriptEngine->evaluate("(function(obj) { return Object.freeze(obj); })");
v = freezeFunction.call(QJSValueList() << v);
return v;
}
static QObject *testImportOrder_api(QQmlEngine *engine, QJSEngine *scriptEngine)
{
Q_UNUSED(engine);
Q_UNUSED(scriptEngine);
testImportOrderApi *o = new testImportOrderApi(37);
return o;
}
static QObject *testImportOrder_api1(QQmlEngine *engine, QJSEngine *scriptEngine)
{
Q_UNUSED(engine);
Q_UNUSED(scriptEngine);
testImportOrderApi *o = new testImportOrderApi(1);
return o;
}
static QObject *testImportOrder_api2(QQmlEngine *engine, QJSEngine *scriptEngine)
{
Q_UNUSED(engine);
Q_UNUSED(scriptEngine);
testImportOrderApi *o = new testImportOrderApi(2);
return o;
}
static QObject *qobject_api(QQmlEngine *engine, QJSEngine *scriptEngine)
{
Q_UNUSED(engine);
Q_UNUSED(scriptEngine);
testQObjectApi *o = new testQObjectApi();
o->setQObjectTestProperty(20);
o->setQObjectTestWritableProperty(50);
o->setQObjectTestWritableFinalProperty(10);
return o;
}
static QObject *qobject_api_two(QQmlEngine *engine, QJSEngine *scriptEngine)
{
Q_UNUSED(engine);
Q_UNUSED(scriptEngine);
testQObjectApiTwo *o = new testQObjectApiTwo;
return o;
}
static QObject *qobject_api_engine_parent(QQmlEngine *engine, QJSEngine *scriptEngine)
{
Q_UNUSED(scriptEngine);
static int testProperty = 26;
testQObjectApi *o = new testQObjectApi(engine);
o->setQObjectTestProperty(testProperty++);
return o;
}
static QObject *fallback_bindings_object(QQmlEngine *engine, QJSEngine *scriptEngine)
{
Q_UNUSED(engine);
Q_UNUSED(scriptEngine);
return new FallbackBindingsObject();
}
static QObject *fallback_bindings_derived(QQmlEngine *engine, QJSEngine *scriptEngine)
{
Q_UNUSED(engine);
Q_UNUSED(scriptEngine);
return new FallbackBindingsDerived();
}
class MyWorkerObjectThread : public QThread
{
public:
MyWorkerObjectThread(MyWorkerObject *o) : QThread(o), o(o) { start(); }
void run() override {
emit o->done(QLatin1String("good"));
}
MyWorkerObject *o;
};
MyWorkerObject::~MyWorkerObject()
{
if (m_thread)
m_thread->wait();
}
void MyWorkerObject::doIt()
{
Q_ASSERT(!m_thread);
m_thread = new MyWorkerObjectThread(this);
}
class MyDateClass : public QObject
{
Q_OBJECT
public:
Q_INVOKABLE QDateTime invalidDate()
{
return QDateTime();
}
};
class MiscTypeTestClass : public QObject
{
Q_OBJECT
public:
Q_INVOKABLE QUrl invalidUrl()
{
return QUrl();
}
}
};
class MyStringClass : public QObject
{
Q_OBJECT
public:
Q_INVOKABLE QStringList strings(QStringList stringList) const
{
return stringList;
}
Q_INVOKABLE QList<QString> stringsVector(const QStringList& stringList) const
{
return stringList.toVector();
}
Q_INVOKABLE
std::vector<QString> stringsStdVector(const QStringList& stringList) const
{
return std::vector<QString>(stringList.begin(), stringList.end());
}
Q_INVOKABLE QList<int> integers(QList<int> v) const
{
return v;
}
Q_INVOKABLE QList<qreal> reals(QList<qreal> v) const
{
return v;
}
Q_INVOKABLE QList<bool> bools(QList<bool> v) const
{
return v;
}
Q_INVOKABLE QList<int> integerVector(QList<int> v) const
{
return v;
}
Q_INVOKABLE
std::vector<int> integerStdVector(std::vector<int> v) const
{
return v;
}
Q_INVOKABLE QList<qreal> realVector(QList<qreal> v) const
{
return v;
}
Q_INVOKABLE
std::vector<qreal> realStdVector(std::vector<qreal> v) const
{
return v;
}
Q_INVOKABLE QList<bool> boolVector(QList<bool> v) const
{
return v;
}
Q_INVOKABLE
std::vector<bool> boolStdVector(std::vector<bool> v) const
{
return v;
}
};
static MyInheritedQmlObject *theSingletonObject = nullptr;
static QObject *inheritedQmlObject_provider(QQmlEngine* /* engine */, QJSEngine* /* scriptEngine */)
{
theSingletonObject = new MyInheritedQmlObject();
return theSingletonObject;
}
bool MyInheritedQmlObject::isItYouQObject(QObject *o)
{
return o && o == theSingletonObject;
}
bool MyInheritedQmlObject::isItYouMyQmlObject(MyQmlObject *o)
{
return o && o == theSingletonObject;
}
bool MyInheritedQmlObject::isItYouMyInheritedQmlObject(MyInheritedQmlObject *o)
{
return o && o == theSingletonObject;
}
class TestTypeCppSingleton : public QObject
{
Q_OBJECT
Q_PROPERTY(int foo READ foo)
Q_CLASSINFO("DefaultProperty", "foo")
public:
int foo() { return 0; }
static TestTypeCppSingleton *instance() {
static TestTypeCppSingleton cppSingleton;
return &cppSingleton;
}
private:
TestTypeCppSingleton(){}
~TestTypeCppSingleton() {
// just to make sure it crashes on double delete
static int a = 0;
static int *ptr = &a;
*ptr = 1;
ptr = nullptr;
}
};
QObject *testTypeCppProvider(QQmlEngine *engine, QJSEngine *scriptEngine)
{
Q_UNUSED(engine);
Q_UNUSED(scriptEngine);
TestTypeCppSingleton *o = TestTypeCppSingleton::instance();
QQmlEngine::setObjectOwnership(o, QQmlEngine::CppOwnership);
return o;
}
static QObject *create_singletonWithEnum(QQmlEngine *, QJSEngine *)
{
return new SingletonWithEnum;
}
QObjectContainer::QObjectContainer()
: widgetParent(nullptr)
, gcOnAppend(false)
{}
QQmlListProperty<QObject> QObjectContainer::data()
{
return QQmlListProperty<QObject>(this, nullptr, children_append, children_count, children_at, children_clear);
}
void QObjectContainer::children_append(QQmlListProperty<QObject> *prop, QObject *o)
{
QObjectContainer *that = static_cast<QObjectContainer*>(prop->object);
that->dataChildren.append(o);
QObject::connect(o, SIGNAL(destroyed(QObject*)), prop->object, SLOT(childDestroyed(QObject*)));
if (that->gcOnAppend) {
QQmlEngine *engine = qmlEngine(that);
gc(*engine);
}
}
qsizetype QObjectContainer::children_count(QQmlListProperty<QObject> *prop)
{
return static_cast<QObjectContainer*>(prop->object)->dataChildren.size();
}
QObject *QObjectContainer::children_at(QQmlListProperty<QObject> *prop, qsizetype index)
{
return static_cast<QObjectContainer*>(prop->object)->dataChildren.at(index);
}
void QObjectContainer::children_clear(QQmlListProperty<QObject> *prop)
{
QObjectContainer *that = static_cast<QObjectContainer*>(prop->object);
for (QObject *c : std::as_const(that->dataChildren))
QObject::disconnect(c, SIGNAL(destroyed(QObject*)), that, SLOT(childDestroyed(QObject*)));
that->dataChildren.clear();
}
void QObjectContainer::childDestroyed(QObject *child) {
dataChildren.removeAll(child);
}
void FloatingQObject::classBegin()
{
setParent(nullptr);
}
void FloatingQObject::componentComplete()
{
Q_ASSERT(!parent());
}
void ClassWithQProperty2::callback()
{
// Q_UNUSED(this->value.value()); // force evaluation
}
ListPropertyAssignment_Gadget::ListPropertyAssignment_Gadget() { }
QStringList ListPropertyAssignment_Gadget::gadgetStringList() const
{
return m_gadgetStringList;
}
void ListPropertyAssignment_Gadget::setGadgetStringList(const QStringList &list)
{
if (m_gadgetStringList == list)
return;
m_gadgetStringList = list;
}
QVariantList ListPropertyAssignment_Gadget::gadgetVariantList() const
{
return m_gadgetVariantList;
}
void ListPropertyAssignment_Gadget::setGadgetVariantList(const QVariantList &list)
{
if (m_gadgetVariantList == list)
return;
m_gadgetVariantList = list;
}
ListPropertyAssignment_Object::ListPropertyAssignment_Object(QObject *parent)
: QObject{ parent } { }
void ListPropertyAssignment_Object::setQobjectStringList(const QStringList &newList)
{
if (m_qobjectStringList == newList)
return;
m_qobjectStringList = newList;
}
bool MetaCallInterceptor::didGetObjectDestroyedCallback = false;
void registerTypes()
{
qmlRegisterType<MyQmlObject>("Qt.test", 1,0, "MyQmlObjectAlias");
qmlRegisterType<MyQmlObject>("Qt.test", 1,0, "MyQmlObject");
qmlRegisterSingletonType<MyInheritedQmlObject>("Test", 1, 0, "MyInheritedQmlObjectSingleton", inheritedQmlObject_provider);
qmlRegisterSingletonType<TestTypeCppSingleton>("Test", 1, 0, "TestTypeCppSingleton", testTypeCppProvider);
qmlRegisterType<MyDeferredObject>("Qt.test", 1,0, "MyDeferredObject");
qmlRegisterType<MyImmediateObject>("Qt.test", 1,0, "MyImmediateObject");
qmlRegisterType<DerivedFromImmediate>("Qt.test", 1,0, "DerivedFromImmediate");
qmlRegisterType<BrokenImmediateDeferred>("Qt.test", 1,0, "BrokenImmediateDeferred");
qmlRegisterType<DeferredChild>("Qt.test", 1,0, "DeferredChild");
qmlRegisterType<DeferredChildOverwrite>("Qt.test", 1, 0, "DeferredChildOverwrite");
qmlRegisterType<DeferredByParentChild>("Qt.test", 1,0, "DeferredByParentChild");
qmlRegisterType<MyVeryDeferredObject>("Qt.test", 1,0, "MyVeryDeferredObject");
qmlRegisterType<MyQmlContainer>("Qt.test", 1,0, "MyQmlContainer");
qmlRegisterExtendedType<MyBaseExtendedObject, BaseExtensionObject>("Qt.test", 1,0, "MyBaseExtendedObject");
qmlRegisterExtendedType<MyExtendedObject, ExtensionObject>("Qt.test", 1,0, "MyExtendedObject");
qmlRegisterType<MyTypeObject>("Qt.test", 1,0, "MyTypeObject");
qmlRegisterType<MyDerivedObject>("Qt.test", 1,0, "MyDerivedObject");
qmlRegisterType<NumberAssignment>("Qt.test", 1,0, "NumberAssignment");
qmlRegisterExtendedType<DefaultPropertyExtendedObject, DefaultPropertyExtensionObject>("Qt.test", 1,0, "DefaultPropertyExtendedObject");
qmlRegisterType<OverrideDefaultPropertyObject>("Qt.test", 1,0, "OverrideDefaultPropertyObject");
qmlRegisterType<MyRevisionedClass>("Qt.test",1,0,"MyRevisionedClass");
qmlRegisterType<MyDeleteObject>("Qt.test", 1,0, "MyDeleteObject");
qmlRegisterType<MyRevisionedClass,1>("Qt.test",1,1,"MyRevisionedClass");
qmlRegisterType<MyWorkerObject>("Qt.test", 1,0, "MyWorkerObject");
qmlRegisterExtendedUncreatableType<AbstractExtensionObject, ExtensionObject>("Qt.test", 1,0, "AbstractExtensionObject", QStringLiteral("Abstracts are uncreatable"));
qmlRegisterType<ImplementedExtensionObject>("Qt.test", 1,0, "ImplementedExtensionObject");
// test scarce resource property binding post-evaluation optimization
// and for testing memory usage in property var circular reference test
qmlRegisterType<ScarceResourceObject>("Qt.test", 1,0, "MyScarceResourceObject");
// Register the uncreatable base class
qmlRegisterRevision<MyRevisionedBaseClassRegistered,1>("Qt.test",1,1);
// MyRevisionedSubclass 1.0 uses MyRevisionedClass revision 0
qmlRegisterType<MyRevisionedSubclass>("Qt.test",1,0,"MyRevisionedSubclass");
// MyRevisionedSubclass 1.1 uses MyRevisionedClass revision 1
qmlRegisterType<MyRevisionedSubclass,1>("Qt.test",1,1,"MyRevisionedSubclass");
qmlRegisterType<MyItemUsingRevisionedObject>("Qt.test", 1, 0, "MyItemUsingRevisionedObject");
#ifndef QT_NO_WIDGETS
qmlRegisterExtendedType<QWidget,QWidgetDeclarativeUI>("Qt.test",1,0,"QWidget");
qmlRegisterType<QPlainTextEdit>("Qt.test",1,0,"QPlainTextEdit");
#endif
qRegisterMetaType<MyQmlObject::MyType>("MyQmlObject::MyType");
qmlRegisterSingletonType("Qt.test",1,0,"Script",script_api); // register (script) singleton Type for an existing uri which contains elements
qmlRegisterSingletonType<testQObjectApi>("Qt.test",1,0,"QObject",qobject_api); // register (qobject) for an existing uri for which another singleton Type was previously regd. Should replace!
qmlRegisterSingletonType("Qt.test.scriptApi",1,0,"Script",script_api); // register (script) singleton Type for a uri which doesn't contain elements
qmlRegisterSingletonType("Qt.test.scriptApi",2,0,"Script",readonly_script_api); // register (script) singleton Type for a uri which doesn't contain elements - will be made read-only
qmlRegisterSingletonType<testQObjectApi>("Qt.test.qobjectApi",1,0,"QObject",qobject_api); // register (qobject) singleton Type for a uri which doesn't contain elements
qmlRegisterSingletonType<testQObjectApi>("Qt.test.qobjectApi",1,3,"QObject",qobject_api); // register (qobject) singleton Type for a uri which doesn't contain elements, minor version set
qmlRegisterSingletonType<testQObjectApi>("Qt.test.qobjectApi",2,0,"QObject",qobject_api); // register (qobject) singleton Type for a uri which doesn't contain elements, major version set
qmlRegisterSingletonType<testQObjectApi>("Qt.test.qobjectApiParented",1,0,"QObject",qobject_api_engine_parent); // register (parented qobject) singleton Type for a uri which doesn't contain elements
qmlRegisterSingletonType<testQObjectApi>("Qt.test.qobjectApis",1,0,"One",qobject_api); // register multiple qobject singleton types in a single namespace
qmlRegisterSingletonType<testQObjectApiTwo>("Qt.test.qobjectApis",1,0,"Two",qobject_api_two); // register multiple qobject singleton types in a single namespace
qRegisterMetaType<MyQmlObject::MyEnum2>("MyEnum2");
qRegisterMetaType<Qt::MouseButtons>("Qt::MouseButtons");
qmlRegisterType<CircularReferenceObject>("Qt.test", 1, 0, "CircularReferenceObject");
qmlRegisterType<MyDynamicCreationDestructionObject>("Qt.test", 1, 0, "MyDynamicCreationDestructionObject");
qmlRegisterType<WriteCounter>("Qt.test", 1, 0, "WriteCounter");
qmlRegisterType<MySequenceConversionObject>("Qt.test", 1, 0, "MySequenceConversionObject");
qmlRegisterType<MyUnregisteredEnumTypeObject>("Qt.test", 1, 0, "MyUnregisteredEnumTypeObject");
qmlRegisterSingletonType<FallbackBindingsObject>("Qt.test.fallbackBindingsObject", 1, 0, "Fallback", fallback_bindings_object);
qmlRegisterSingletonType<FallbackBindingsObject>("Qt.test.fallbackBindingsDerived", 1, 0, "Fallback", fallback_bindings_derived);
qmlRegisterType<FallbackBindingsObject>("Qt.test.fallbackBindingsItem", 1, 0, "FallbackBindingsType");
qmlRegisterType<FallbackBindingsDerived>("Qt.test.fallbackBindingsItem", 1, 0, "FallbackBindingsDerivedType");
qmlRegisterType<FallbackBindingsTypeObject>("Qt.test.fallbackBindingsObject", 1, 0, "FallbackBindingsType");
qmlRegisterType<FallbackBindingsTypeDerived>("Qt.test.fallbackBindingsDerived", 1, 0, "FallbackBindingsType");
qmlRegisterType<MyDateClass>("Qt.test", 1, 0, "MyDateClass");
qmlRegisterType<MyStringClass>("Qt.test", 1, 0, "MyStringClass");
qmlRegisterType<MiscTypeTestClass>("Qt.test", 1, 0, "MiscTypeTest");
qmlRegisterSingletonType<testImportOrderApi>("Qt.test.importOrderApi",1,0,"Data",testImportOrder_api);
qmlRegisterSingletonType<testImportOrderApi>("NamespaceAndType",1,0,"NamespaceAndType",testImportOrder_api);
qmlRegisterSingletonType<testImportOrderApi>("Qt.test.importOrderApi1",1,0,"Data",testImportOrder_api1);
qmlRegisterSingletonType<testImportOrderApi>("Qt.test.importOrderApi2",1,0,"Data",testImportOrder_api2);
qmlRegisterSingletonType<SingletonWithEnum>("Qt.test.singletonWithEnum", 1, 0, "SingletonWithEnum", create_singletonWithEnum);
qmlRegisterType<QObjectContainer>("Qt.test", 1, 0, "QObjectContainer");
qmlRegisterType<QObjectContainerWithGCOnAppend>("Qt.test", 1, 0, "QObjectContainerWithGCOnAppend");
qmlRegisterType<FloatingQObject>("Qt.test", 1, 0, "FloatingQObject");
qmlRegisterType<ClashingNames>("Qt.test", 1, 0, "ClashingNames");
qmlRegisterType<ClassWithQProperty>("Qt.test", 1, 0, "ClassWithQProperty");
qmlRegisterType<ClassWithQObjectProperty>("Qt.test", 1, 0, "ClassWithQObjectProperty");
qmlRegisterType<ClassWithQProperty2>("Qt.test", 1, 0, "ClassWithQProperty2");
qmlRegisterType<Receiver>("Qt.test", 1,0, "Receiver");
qmlRegisterType<Sender>("Qt.test", 1,0, "Sender");
qmlRegisterTypesAndRevisions<ReadOnlyBindable>("Qt.test", 1);
qmlRegisterTypesAndRevisions<ResettableGadgetHolder>("Qt.test", 1);
qmlRegisterTypesAndRevisions<ListPropertyAssignment_Gadget>("Qt.test", 1);
qmlRegisterTypesAndRevisions<ListPropertyAssignment_Object>("Qt.test", 1);
qmlRegisterTypesAndRevisions<SingletonRegistrationWrapper>("Qt.test", 1);
qmlRegisterExtendedType<TypeWithCustomMetaObject, TypeToTriggerProxyMetaObject>(
"Qt.test", 1,0, "TypeWithCustomMetaObject");
}
#include "testtypes.moc"