aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/types
diff options
context:
space:
mode:
Diffstat (limited to 'src/qml/types')
-rw-r--r--src/qml/types/qqmlbind.cpp909
-rw-r--r--src/qml/types/qqmlbind_p.h60
-rw-r--r--src/qml/types/qqmlconnections.cpp299
-rw-r--r--src/qml/types/qqmlconnections_p.h63
-rw-r--r--src/qml/types/qqmllocaleenums_p.h48
-rw-r--r--src/qml/types/qqmlloggingcategory.cpp146
-rw-r--r--src/qml/types/qqmlloggingcategory_p.h71
-rw-r--r--src/qml/types/qqmlmodelindexvaluetype.cpp68
-rw-r--r--src/qml/types/qqmlmodelindexvaluetype_p.h164
-rw-r--r--src/qml/types/qqmltimer.cpp42
-rw-r--r--src/qml/types/qqmltimer_p.h52
-rw-r--r--src/qml/types/types.pri22
12 files changed, 1258 insertions, 686 deletions
diff --git a/src/qml/types/qqmlbind.cpp b/src/qml/types/qqmlbind.cpp
index 6d762401d0..6991d642f5 100644
--- a/src/qml/types/qqmlbind.cpp
+++ b/src/qml/types/qqmlbind.cpp
@@ -1,117 +1,331 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmlbind_p.h"
-#include <private/qqmlnullablevalue_p.h>
-#include <private/qqmlproperty_p.h>
+#include <private/qqmlanybinding_p.h>
#include <private/qqmlbinding_p.h>
+#include <private/qqmlcomponent_p.h>
#include <private/qqmlmetatype_p.h>
+#include <private/qqmlnullablevalue_p.h>
+#include <private/qqmlproperty_p.h>
#include <private/qqmlvmemetaobject_p.h>
#include <private/qv4persistent_p.h>
+#include <private/qv4qmlcontext_p.h>
+#include <private/qv4resolvedtypereference_p.h>
-#include <qqmlengine.h>
-#include <qqmlcontext.h>
-#include <qqmlproperty.h>
-#include <qqmlinfo.h>
+#include <QtQml/qqmlcontext.h>
+#include <QtQml/qqmlengine.h>
+#include <QtQml/qqmlinfo.h>
+#include <QtQml/qqmlproperty.h>
+#include <QtQml/qqmlpropertymap.h>
+
+#include <QtCore/private/qobject_p.h>
-#include <QtCore/qfile.h>
#include <QtCore/qdebug.h>
-#include <QtCore/qtimer.h>
+#include <QtCore/qfile.h>
#include <QtCore/qloggingcategory.h>
-
-#include <private/qobject_p.h>
+#include <QtCore/qpointer.h>
+#include <QtCore/qtimer.h>
QT_BEGIN_NAMESPACE
-Q_DECLARE_LOGGING_CATEGORY(lcBindingRemoval)
+Q_STATIC_LOGGING_CATEGORY(lcQtQmlBindingRemoval, "qt.qml.binding.removal", QtWarningMsg)
+
+enum class QQmlBindEntryKind: quint8 {
+ V4Value,
+ Variant,
+ Binding,
+ None
+};
+
+/*!
+ * \internal
+ * QQmlBindEntryContent can store one of QV4::Value, QVariant, QQmlAnyBinding, or nothing,
+ * as denoted by QQmlBindEntryKind. It expects the calling code to know what is stored at
+ * any time. On each method invocation, the current kind has to be passed as last parameter
+ * and the new kind is returned.
+ */
+union QQmlBindEntryContent {
+ Q_DISABLE_COPY_MOVE(QQmlBindEntryContent)
+public:
+ QQmlBindEntryContent() {}
+ ~QQmlBindEntryContent() {}
+
+ [[nodiscard]] QQmlBindEntryKind set(
+ QQmlBindEntryContent &&other, QQmlBindEntryKind newKind, QQmlBindEntryKind oldKind)
+ {
+ silentDestroy(oldKind);
+ switch (newKind) {
+ case QQmlBindEntryKind::V4Value:
+ new (&v4Value) QV4::PersistentValue(std::move(other.v4Value));
+ break;
+ case QQmlBindEntryKind::Variant:
+ new (&variant) QVariant(std::move(other.variant));
+ break;
+ case QQmlBindEntryKind::Binding:
+ new (&binding) QQmlAnyBinding(std::move(other.binding));
+ break;
+ case QQmlBindEntryKind::None:
+ break;
+ }
+ return newKind;
+ }
+
+ [[nodiscard]] QQmlBindEntryKind set(
+ const QQmlBindEntryContent &other, QQmlBindEntryKind newKind, QQmlBindEntryKind oldKind)
+ {
+ silentDestroy(oldKind);
+ switch (newKind) {
+ case QQmlBindEntryKind::V4Value:
+ new (&v4Value) QV4::PersistentValue(other.v4Value);
+ break;
+ case QQmlBindEntryKind::Variant:
+ new (&variant) QVariant(other.variant);
+ break;
+ case QQmlBindEntryKind::Binding:
+ new (&binding) QQmlAnyBinding(other.binding);
+ break;
+ case QQmlBindEntryKind::None:
+ break;
+ }
+ return newKind;
+ }
+
+ [[nodiscard]] QQmlBindEntryKind destroy(QQmlBindEntryKind kind)
+ {
+ switch (kind) {
+ case QQmlBindEntryKind::V4Value:
+ v4Value.~PersistentValue();
+ break;
+ case QQmlBindEntryKind::Variant:
+ variant.~QVariant();
+ break;
+ case QQmlBindEntryKind::Binding:
+ binding.~QQmlAnyBinding();
+ break;
+ case QQmlBindEntryKind::None:
+ break;
+ }
+ return QQmlBindEntryKind::None;
+ }
+
+ [[nodiscard]] QQmlBindEntryKind set(QVariant v, QQmlBindEntryKind oldKind)
+ {
+ silentDestroy(oldKind);
+ new (&variant) QVariant(std::move(v));
+ return QQmlBindEntryKind::Variant;
+ }
+
+ [[nodiscard]] QQmlBindEntryKind set(QV4::PersistentValue v, QQmlBindEntryKind oldKind)
+ {
+ silentDestroy(oldKind);
+ new (&v4Value) QV4::PersistentValue(std::move(v));
+ return QQmlBindEntryKind::V4Value;
+ }
+
+ [[nodiscard]] QQmlBindEntryKind set(QQmlAnyBinding v, QQmlBindEntryKind oldKind)
+ {
+ silentDestroy(oldKind);
+ new (&binding) QQmlAnyBinding(std::move(v));
+ return QQmlBindEntryKind::Binding;
+ }
+
+ QV4::PersistentValue v4Value;
+ QVariant variant;
+ QQmlAnyBinding binding;
+
+private:
+ void silentDestroy(QQmlBindEntryKind oldKind)
+ {
+ const QQmlBindEntryKind dead = destroy(oldKind);
+ Q_ASSERT(dead == QQmlBindEntryKind::None);
+ Q_UNUSED(dead);
+ }
+};
+
+/*!
+ * \internal
+ * QQmlBindEntry holds two QQmlBindEntryContent members, along with their kinds.
+ * The \l current content is the value or binding the Binding element installs on
+ * the target if enabled (that is, if \l{when}). The \l previous content is what
+ * the target holds before the Binding element installs its binding or value. It
+ * is restored if !\l{when}. The \l prop member holds the target property.
+ */
+struct QQmlBindEntry
+{
+ QQmlBindEntry() = default;
+ QQmlBindEntry(QQmlBindEntry &&other) noexcept : prop(std::move(other.prop))
+ {
+ currentKind = current.set(std::move(other.current), other.currentKind, currentKind);
+ previousKind = previous.set(std::move(other.previous), other.previousKind, previousKind);
+ }
+
+ QQmlBindEntry(const QQmlBindEntry &other)
+ : prop(other.prop)
+ {
+ currentKind = current.set(other.current, other.currentKind, currentKind);
+ previousKind = previous.set(other.previous, other.previousKind, previousKind);
+ }
+
+ ~QQmlBindEntry()
+ {
+ currentKind = current.destroy(currentKind);
+ previousKind = previous.destroy(previousKind);
+ }
+
+ QQmlBindEntry &operator=(QQmlBindEntry &&other) noexcept
+ {
+ if (this == &other)
+ return *this;
+ prop = std::move(other.prop);
+ currentKind = current.set(std::move(other.current), other.currentKind, currentKind);
+ previousKind = previous.set(std::move(other.previous), other.previousKind, previousKind);
+ return *this;
+ }
+
+ QQmlBindEntry &operator=(const QQmlBindEntry &other)
+ {
+ if (this == &other)
+ return *this;
+ prop = other.prop;
+ currentKind = current.set(other.current, other.currentKind, currentKind);
+ previousKind = previous.set(other.previous, other.previousKind, previousKind);
+ return *this;
+ }
+
+
+ QQmlBindEntryContent current;
+ QQmlBindEntryContent previous;
+ QQmlProperty prop;
+ QQmlBindEntryKind currentKind = QQmlBindEntryKind::None;
+ QQmlBindEntryKind previousKind = QQmlBindEntryKind::None;
+
+ void validate(QQmlBind *q) const;
+ void clearPrev();
+ void setTarget(QQmlBind *q, const QQmlProperty &p);
+};
class QQmlBindPrivate : public QObjectPrivate
{
public:
QQmlBindPrivate()
- : obj(nullptr)
- , prevBind(QQmlAbstractBinding::Ptr())
- , prevIsVariant(false)
+ : when(true)
, componentComplete(true)
, delayed(false)
, pendingEval(false)
, restoreBinding(true)
, restoreValue(true)
, writingProperty(false)
- {}
+ , lastIsTarget(false)
+ {
+ }
~QQmlBindPrivate() { }
- QQmlNullableValue<bool> when;
+ // There can be multiple entries when using the generalized grouped
+ // property syntax. One is used for target/property/value.
+ QVarLengthArray<QQmlBindEntry, 1> entries;
+
+ // The target object if using the \l target property
QPointer<QObject> obj;
+
+ // Any values we need to create a proxy for. This is necessary when
+ // using the \l delayed member on generalized grouped properties. See
+ // the note on \l delayed.
+ std::unique_ptr<QQmlPropertyMap> delayedValues;
+
+ // The property name if using the \l property property.
QString propName;
- QQmlNullableValue<QJSValue> value;
- QQmlProperty prop;
- QQmlAbstractBinding::Ptr prevBind;
- QV4::PersistentValue v4Value;
- QVariant prevValue;
- bool prevIsVariant:1;
+
+ // Whether the binding is enabled.
+ bool when: 1;
+
+ // Whether we have already parsed any generalized grouped properties
+ // we might need.
bool componentComplete:1;
+
+ // Whether we should run in "delayed" mode and proxy all values before
+ // applying them to the target.
bool delayed:1;
+
+ // In delayed mode, when using the target/property mode, the \l value
+ // is the proxy. Then pendingEval denotes that a timer is active to
+ // apply the value. We should not start another timer then.
bool pendingEval:1;
+
+ // Whether we should restore bindings on !when.
+ // TODO: Deprecate this and always do.
bool restoreBinding:1;
+
+ // Whether we should restore values on !when.
+ // TODO: Deprecate this and always do.
bool restoreValue:1;
- bool writingProperty: 1;
- void validate(QObject *binding) const;
- void clearPrev();
+ // writingProperty tracks whether we are updating the target property
+ // when using target/property/value. We use this information to warn about
+ // binding removal if we detect the target property to be updated while we
+ // are not writing it. This doesn't remove the Binding after all.
+ // For generalized grouped properties, we don't have to do this as writing
+ // the target property does remove the binding, just like it removes any
+ // other binding.
+ bool writingProperty:1;
+
+ // Whether the last entry is the the target property referred to by the
+ // \l target object and the \l property property. This will generally be
+ // the case when using \l target and \l property.
+ bool lastIsTarget:1;
+
+ QQmlBindEntry *targetEntry();
+ void validate(QQmlBind *binding) const;
+ void decodeBinding(
+ QQmlBind *q, const QString &propertyPrefix, QQmlData::DeferredData *deferredData,
+ const QV4::CompiledData::Binding *binding,
+ QQmlComponentPrivate::ConstructionState *immediateState);
+ void createDelayedValues();
+ void onDelayedValueChanged(QString delayedName);
+ void evalDelayed();
+ void buildBindEntries(QQmlBind *q, QQmlComponentPrivate::DeferredState *deferredState);
};
-void QQmlBindPrivate::validate(QObject *binding) const
+void QQmlBindEntry::validate(QQmlBind *q) const
{
- if (!obj || (when.isValid() && !when))
- return;
+ if (!prop.isWritable()) {
+ qmlWarning(q) << "Property '" << prop.name() << "' on "
+ << QQmlMetaType::prettyTypeName(prop.object()) << " is read-only.";
+ }
+}
- if (!prop.isValid()) {
- qmlWarning(binding) << "Property '" << propName << "' does not exist on " << QQmlMetaType::prettyTypeName(obj) << ".";
- return;
+QQmlBindEntry *QQmlBindPrivate::targetEntry()
+{
+ if (!lastIsTarget) {
+ entries.append(QQmlBindEntry());
+ lastIsTarget = true;
}
+ return &entries.last();
+}
- if (!prop.isWritable()) {
- qmlWarning(binding) << "Property '" << propName << "' on " << QQmlMetaType::prettyTypeName(obj) << " is read-only.";
+void QQmlBindPrivate::validate(QQmlBind *q) const
+{
+ if (!when)
return;
+
+ qsizetype iterationEnd = entries.size();
+ if (lastIsTarget) {
+ if (obj) {
+ Q_ASSERT(!entries.isEmpty());
+ const QQmlBindEntry &last = entries.last();
+ if (!last.prop.isValid()) {
+ qmlWarning(q) << "Property '" << propName << "' does not exist on "
+ << QQmlMetaType::prettyTypeName(obj) << ".";
+ --iterationEnd;
+ }
+ } else {
+ --iterationEnd;
+ }
}
+
+ for (qsizetype i = 0; i < iterationEnd; ++i)
+ entries[i].validate(q);
}
/*!
@@ -134,10 +348,10 @@ void QQmlBindPrivate::validate(QObject *binding) const
For example, in a C++ application that maps an "app.enteredText" property
into QML, you can use Binding to update the enteredText property.
- \code
+ \qml
TextEdit { id: myTextField; text: "Please type here..." }
- Binding { target: app; property: "enteredText"; value: myTextField.text }
- \endcode
+ Binding { app.enteredText: myTextField.text }
+ \endqml
When \c{text} changes, the C++ property \c{enteredText} will update
automatically.
@@ -170,29 +384,25 @@ void QQmlBindPrivate::validate(QObject *binding) const
The Binding type restores any previously set direct bindings on the
property.
- \sa {Qt QML}
+ \sa {Qt Qml}
*/
QQmlBind::QQmlBind(QObject *parent)
: QObject(*(new QQmlBindPrivate), parent)
{
}
-QQmlBind::~QQmlBind()
-{
-}
-
/*!
\qmlproperty bool QtQml::Binding::when
This property holds when the binding is active.
This should be set to an expression that evaluates to true when you want the binding to be active.
- \code
+ \qml
Binding {
- target: contactName; property: 'text'
- value: name; when: list.ListView.isCurrentItem
+ contactName.text: name
+ when: list.ListView.isCurrentItem
}
- \endcode
+ \endqml
By default, any binding or value that was set perviously is restored when the binding becomes
inactive. You can customize the restoration behavior using the \l restoreMode property.
@@ -208,7 +418,7 @@ bool QQmlBind::when() const
void QQmlBind::setWhen(bool v)
{
Q_D(QQmlBind);
- if (!d->when.isNull && d->when == v)
+ if (d->when == v)
return;
d->when = v;
@@ -218,9 +428,26 @@ void QQmlBind::setWhen(bool v)
}
/*!
- \qmlproperty Object QtQml::Binding::target
+ \qmlproperty QtObject QtQml::Binding::target
- The object to be updated.
+ The object to be updated. You need to use this property if the binding target
+ does not have an \c id attribute (for example, when the target is a singleton).
+ Otherwise, the following two pieces of code are equivalent:
+
+ \qml
+ Binding { contactName.text: name }
+ \endqml
+
+ \qml
+ Binding {
+ target: contactName
+ property: "text"
+ value: name
+ }
+ \endqml
+
+ The former one is much more compact, but you cannot replace the target
+ object or property at run time. With the latter one you can.
*/
QObject *QQmlBind::object()
{
@@ -231,17 +458,33 @@ QObject *QQmlBind::object()
void QQmlBind::setObject(QObject *obj)
{
Q_D(QQmlBind);
- if (d->obj && d->when.isValid() && d->when) {
+ if (d->obj && d->when) {
/* if we switch the object at runtime, we need to restore the
previous binding on the old object before continuing */
d->when = false;
eval();
d->when = true;
}
+ /* if "when" and "target" depend on the same property, we might
+ end up here before we could have updated "when". So reevaluate
+ when manually here.
+ */
+ const QQmlProperty whenProp(this, QLatin1StringView("when"));
+ const auto potentialWhenBinding = QQmlAnyBinding::ofProperty(whenProp);
+ if (auto abstractBinding = potentialWhenBinding.asAbstractBinding()) {
+ QQmlBinding *binding = static_cast<QQmlBinding *>(abstractBinding);
+ if (binding->hasValidContext()) {
+ const auto boolType = QMetaType::fromType<bool>();
+ bool when;
+ binding->evaluate(&when, boolType);
+ d->when = when;
+ }
+ }
d->obj = obj;
if (d->componentComplete) {
setTarget(QQmlProperty(d->obj, d->propName, qmlContext(this)));
- d->validate(this);
+ if (d->when)
+ d->validate(this);
}
eval();
}
@@ -252,7 +495,7 @@ void QQmlBind::setObject(QObject *obj)
The property to be updated.
This can be a group property if the expression results in accessing a
- property of a \l {QML Basic Types}{value type}. For example:
+ property of a \l {QML Value Types}{value type}. For example:
\qml
Item {
@@ -267,6 +510,14 @@ void QQmlBind::setObject(QObject *obj)
value: 100
}
\endqml
+
+ You only need to use this property if you can't supply the binding target
+ declaratively. The following snippet of code is equivalent to the above
+ binding, but more compact:
+
+ \qml
+ Binding { item.rectangle.x: 100 }
+ \endqml
*/
QString QQmlBind::property() const
{
@@ -277,7 +528,7 @@ QString QQmlBind::property() const
void QQmlBind::setProperty(const QString &p)
{
Q_D(QQmlBind);
- if (!d->propName.isEmpty() && d->when.isValid() && d->when) {
+ if (!d->propName.isEmpty() && d->when) {
/* if we switch the property name at runtime, we need to restore the
previous binding on the old object before continuing */
d->when = false;
@@ -287,27 +538,35 @@ void QQmlBind::setProperty(const QString &p)
d->propName = p;
if (d->componentComplete) {
setTarget(QQmlProperty(d->obj, d->propName, qmlContext(this)));
- d->validate(this);
+ if (d->when)
+ d->validate(this);
}
eval();
}
/*!
- \qmlproperty any QtQml::Binding::value
+ \qmlproperty var QtQml::Binding::value
The value to be set on the target object and property. This can be a
constant (which isn't very useful), or a bound expression.
+
+ You only need to use this property if you can't supply the binding target
+ declaratively. Otherwise you can directly bind to the target.
*/
-QJSValue QQmlBind::value() const
+QVariant QQmlBind::value() const
{
Q_D(const QQmlBind);
- return d->value.value;
+ if (!d->lastIsTarget)
+ return QVariant();
+ Q_ASSERT(d->entries.last().currentKind == QQmlBindEntryKind::Variant);
+ return d->entries.last().current.variant;
}
-void QQmlBind::setValue(const QJSValue &v)
+void QQmlBind::setValue(const QVariant &v)
{
Q_D(QQmlBind);
- d->value = v;
+ QQmlBindEntry *targetEntry = d->targetEntry();
+ targetEntry->currentKind = targetEntry->current.set(v, targetEntry->currentKind);
prepareEval();
}
@@ -323,11 +582,19 @@ void QQmlBind::setValue(const QJSValue &v)
\code
Binding {
- target: contactName; property: 'text'
- value: givenName + " " + familyName; when: list.ListView.isCurrentItem
+ contactName.text.value: givenName + " " + familyName
+ when: list.ListView.isCurrentItem
delayed: true
}
\endcode
+
+ \note Using the \l delayed property incurs a run time cost as the Binding
+ element has to create a proxy for the value, so that it can delay its
+ application to the actual target. When using the \l target and
+ \l property properties, this cost is lower because the \l value
+ property can be re-used as proxy. When using the form shown above,
+ Binding will allocate a separate object with a dynamic meta-object to
+ hold the proxy values.
*/
bool QQmlBind::delayed() const
{
@@ -342,6 +609,28 @@ void QQmlBind::setDelayed(bool delayed)
return;
d->delayed = delayed;
+ if (!d->componentComplete)
+ return;
+
+ d->delayedValues.reset();
+
+ QVarLengthArray<QQmlBindEntry, 1> oldEntries = std::move(d->entries);
+ d->entries.clear();
+ d->buildBindEntries(this, nullptr);
+
+ if (d->lastIsTarget) {
+ d->entries.append(std::move(oldEntries.last()));
+ oldEntries.pop_back();
+ }
+
+ for (qsizetype i = 0, end = oldEntries.size(); i < end; ++i) {
+ QQmlBindEntry &newEntry = d->entries[i];
+ QQmlBindEntry &oldEntry = oldEntries[i];
+ newEntry.previousKind = newEntry.previous.set(
+ std::move(oldEntry.previous), oldEntry.previousKind, newEntry.previousKind);
+ if (d->delayed && oldEntry.currentKind == QQmlBindEntryKind::Binding)
+ QQmlAnyBinding::removeBindingFrom(oldEntry.prop);
+ }
if (!d->delayed)
eval();
@@ -355,23 +644,18 @@ void QQmlBind::setDelayed(bool delayed)
be restored when the binding is disabled.
The possible values are:
- \list
- \li Binding.RestoreNone The original value is not restored at all
- \li Binding.RestoreBinding The original value is restored if it was another
- binding. In that case the old binding is in effect again.
- \li Binding.RestoreValue The original value is restored if it was a plain
- value rather than a binding.
- \li Binding.RestoreBindingOrValue The original value is always restored.
- \endlist
- The default value is \c Binding.RestoreBindingOrValue.
+ \value Binding.RestoreNone The original value is not restored at all
+ \value Binding.RestoreBinding The original value is restored if it was another binding.
+ In that case the old binding is in effect again.
+ \value Binding.RestoreValue The original value is restored if it was a plain
+ value rather than a binding.
+ \value Binding.RestoreBindingOrValue The original value is always restored.
- If you rely on any specific behavior regarding the restoration of plain
- values when bindings get disabled you should migrate to explicitly set the
- restoreMode.
+ The default value is \c Binding.RestoreBindingOrValue.
- Reliance on a restoreMode that doesn't restore the previous binding or value
- for a specific property results in a run-time warning.
+ \note This property exists for backwards compatibility with earlier versions
+ of Qt. Don't use it in new code.
*/
QQmlBind::RestorationMode QQmlBind::restoreMode() const
{
@@ -397,20 +681,24 @@ void QQmlBind::setRestoreMode(RestorationMode newMode)
void QQmlBind::setTarget(const QQmlProperty &p)
{
Q_D(QQmlBind);
+ d->targetEntry()->setTarget(this, p);
+}
- if (Q_UNLIKELY(lcBindingRemoval().isInfoEnabled())) {
- if (QObject *oldObject = d->prop.object()) {
- QMetaProperty prop = oldObject->metaObject()->property(d->prop.index());
- if (prop.hasNotifySignal()) {
- QByteArray signal('2' + prop.notifySignal().methodSignature());
+void QQmlBindEntry::setTarget(QQmlBind *q, const QQmlProperty &p)
+{
+ if (Q_UNLIKELY(lcQtQmlBindingRemoval().isInfoEnabled())) {
+ if (QObject *oldObject = prop.object()) {
+ QMetaProperty metaProp = oldObject->metaObject()->property(prop.index());
+ if (metaProp.hasNotifySignal()) {
+ QByteArray signal('2' + metaProp.notifySignal().methodSignature());
QObject::disconnect(oldObject, signal.constData(),
- this, SLOT(targetValueChanged()));
+ q, SLOT(targetValueChanged()));
}
}
- p.connectNotifySignal(this, SLOT(targetValueChanged()));
+ p.connectNotifySignal(q, SLOT(targetValueChanged()));
}
- d->prop = p;
+ prop = p;
}
void QQmlBind::classBegin()
@@ -419,14 +707,285 @@ void QQmlBind::classBegin()
d->componentComplete = false;
}
+static QQmlAnyBinding createBinding(
+ const QQmlProperty &prop, const QV4::CompiledData::Binding *binding,
+ const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit,
+ const QQmlRefPointer<QQmlContextData> &contextData,
+ QObject *scopeObject)
+{
+ switch (binding->type()) {
+ case QV4::CompiledData::Binding::Type_Translation:
+ case QV4::CompiledData::Binding::Type_TranslationById:
+ return QQmlAnyBinding::createTranslationBinding(prop, compilationUnit, binding, scopeObject);
+ case QV4::CompiledData::Binding::Type_Script: {
+ const QQmlBinding::Identifier id = binding->value.compiledScriptIndex;
+ if (id == QQmlBinding::Invalid) {
+ return QQmlAnyBinding::createFromCodeString(
+ prop, compilationUnit->bindingValueAsString(binding), scopeObject,
+ contextData, compilationUnit->finalUrlString(), binding->location.line());
+ }
+ QV4::Scope scope(contextData->engine()->handle());
+ QV4::Scoped<QV4::QmlContext> qmlCtxt(
+ scope, QV4::QmlContext::create(
+ scope.engine->rootContext(), contextData, scopeObject));
+ return QQmlAnyBinding::createFromFunction(
+ prop, compilationUnit->runtimeFunctions.at(id), scopeObject, contextData,
+ qmlCtxt);
+ }
+ default:
+ break;
+ }
+ return QQmlAnyBinding();
+}
+
+static void initCreator(
+ QQmlData::DeferredData *deferredData,
+ const QQmlRefPointer<QQmlContextData> &contextData,
+ QQmlComponentPrivate::ConstructionState *immediateState)
+{
+ if (!immediateState->hasCreator()) {
+ immediateState->setCompletePending(true);
+ immediateState->initCreator(
+ deferredData->context->parent(), deferredData->compilationUnit,
+ contextData);
+ immediateState->creator()->beginPopulateDeferred(deferredData->context);
+ }
+}
+
+void QQmlBindPrivate::decodeBinding(
+ QQmlBind *q, const QString &propertyPrefix,
+ QQmlData::DeferredData *deferredData,
+ const QV4::CompiledData::Binding *binding,
+ QQmlComponentPrivate::ConstructionState *immediateState)
+{
+ const QQmlRefPointer<QV4::ExecutableCompilationUnit> compilationUnit
+ = deferredData->compilationUnit;
+ const QString propertySuffix = compilationUnit->stringAt(binding->propertyNameIndex);
+ const QString propertyName = propertyPrefix + propertySuffix;
+
+ switch (binding->type()) {
+ case QV4::CompiledData::Binding::Type_AttachedProperty:
+ if (propertyPrefix.isEmpty()) {
+ // Top-level attached properties cannot be generalized grouped properties.
+ // Treat them as regular properties.
+ // ... unless we're not supposed to handle regular properties. Then ignore them.
+ if (!immediateState)
+ return;
+
+ Q_ASSERT(compilationUnit->stringAt(compilationUnit->objectAt(binding->value.objectIndex)
+ ->inheritedTypeNameIndex).isEmpty());
+
+ const QV4::ResolvedTypeReference *typeReference
+ = compilationUnit->resolvedType(binding->propertyNameIndex);
+ Q_ASSERT(typeReference);
+ QQmlType attachedType = typeReference->type();
+ if (!attachedType.isValid()) {
+ if (QQmlTypeLoader *typeLoader = compilationUnit->engine->typeLoader()) {
+ const QQmlTypeNameCache::Result result
+ = deferredData->context->imports()->query(propertySuffix, typeLoader);
+ if (!result.isValid()) {
+ qmlWarning(q).nospace()
+ << "Unknown name " << propertySuffix << ". The binding is ignored.";
+ return;
+ }
+ attachedType = result.type;
+ }
+ }
+
+ QQmlContext *context = qmlContext(q);
+ QObject *attachedObject = qmlAttachedPropertiesObject(
+ q, attachedType.attachedPropertiesFunction(
+ QQmlEnginePrivate::get(context->engine())));
+ if (!attachedObject) {
+ qmlWarning(q).nospace() <<"Could not create attached properties object '"
+ << attachedType.typeName() << "'";
+ return;
+ }
+
+ initCreator(deferredData, QQmlContextData::get(context), immediateState);
+ immediateState->creator()->populateDeferredInstance(
+ q, deferredData->deferredIdx, binding->value.objectIndex, attachedObject,
+ attachedObject, /*value type property*/ nullptr, binding);
+ return;
+ }
+ Q_FALLTHROUGH();
+ case QV4::CompiledData::Binding::Type_GroupProperty: {
+ const QString pre = propertyName + u'.';
+ const QV4::CompiledData::Object *subObj
+ = compilationUnit->objectAt(binding->value.objectIndex);
+ const QV4::CompiledData::Binding *subBinding = subObj->bindingTable();
+ for (quint32 i = 0; i < subObj->nBindings; ++i, ++subBinding)
+ decodeBinding(q, pre, deferredData, subBinding, immediateState);
+ return;
+ }
+ default:
+ break;
+ }
+
+ QQmlBindEntry entry;
+ QQmlContext *context = qmlContext(q);
+ const QQmlRefPointer<QQmlContextData> contextData = QQmlContextData::get(context);
+ entry.prop = QQmlPropertyPrivate::create(nullptr, propertyName, contextData,
+ QQmlPropertyPrivate::InitFlag::AllowId);
+ if (!entry.prop.isValid()) {
+ // Try again in the context of this object. If that works, it's a regular property.
+ // ... unless we're not supposed to handle regular properties. Then ignore it.
+ if (!immediateState)
+ return;
+
+ QQmlProperty property = QQmlPropertyPrivate::create(
+ q, propertyName, contextData, QQmlPropertyPrivate::InitFlag::AllowSignal);
+ if (property.isValid()) {
+ initCreator(deferredData, contextData, immediateState);
+ immediateState->creator()->populateDeferredBinding(
+ property, deferredData->deferredIdx, binding);
+ } else {
+ qmlWarning(q).nospace() << "Unknown name " << propertyName
+ << ". The binding is ignored.";
+ }
+ return;
+ }
+
+ const auto setVariant = [&entry](QVariant var) {
+ entry.currentKind = entry.current.set(std::move(var), entry.currentKind);
+ };
+
+ const auto setBinding = [&entry](QQmlAnyBinding binding) {
+ entry.currentKind = entry.current.set(binding, entry.currentKind);
+ };
+
+ switch (binding->type()) {
+ case QV4::CompiledData::Binding::Type_AttachedProperty:
+ case QV4::CompiledData::Binding::Type_GroupProperty:
+ Q_UNREACHABLE(); // Handled above
+ break;
+ case QV4::CompiledData::Binding::Type_Translation:
+ case QV4::CompiledData::Binding::Type_TranslationById:
+ case QV4::CompiledData::Binding::Type_Script:
+ if (delayed) {
+ if (!delayedValues)
+ createDelayedValues();
+ const QString delayedName = QString::number(entries.size());
+ delayedValues->insert(delayedName, QVariant());
+ QQmlProperty bindingTarget = QQmlProperty(delayedValues.get(), delayedName);
+ Q_ASSERT(bindingTarget.isValid());
+ QQmlAnyBinding anyBinding = createBinding(
+ bindingTarget, binding, compilationUnit, contextData, q);
+ anyBinding.installOn(bindingTarget);
+ } else {
+ setBinding(createBinding(entry.prop, binding, compilationUnit, contextData, q));
+ }
+ break;
+ case QV4::CompiledData::Binding::Type_String:
+ setVariant(compilationUnit->bindingValueAsString(binding));
+ break;
+ case QV4::CompiledData::Binding::Type_Number:
+ setVariant(compilationUnit->bindingValueAsNumber(binding));
+ break;
+ case QV4::CompiledData::Binding::Type_Boolean:
+ setVariant(binding->valueAsBoolean());
+ break;
+ case QV4::CompiledData::Binding::Type_Null:
+ setVariant(QVariant::fromValue(nullptr));
+ break;
+ case QV4::CompiledData::Binding::Type_Object:
+ case QV4::CompiledData::Binding::Type_Invalid:
+ break;
+ }
+
+ entries.append(std::move(entry));
+}
+
+void QQmlBindPrivate::createDelayedValues()
+{
+ delayedValues = std::make_unique<QQmlPropertyMap>();
+ QObject::connect(
+ delayedValues.get(), &QQmlPropertyMap::valueChanged,
+ delayedValues.get(), [this](QString delayedName, const QVariant &value) {
+ Q_UNUSED(value);
+ onDelayedValueChanged(std::move(delayedName));
+ }
+ );
+}
+
+void QQmlBindPrivate::onDelayedValueChanged(QString delayedName)
+{
+ Q_ASSERT(delayed);
+ Q_ASSERT(delayedValues);
+ const QString pendingName = QStringLiteral("pending");
+ QStringList pending = qvariant_cast<QStringList>((*delayedValues)[pendingName]);
+ if (componentComplete && pending.size() == 0)
+ QTimer::singleShot(0, delayedValues.get(), [this]() { evalDelayed(); });
+ else if (pending.contains(delayedName))
+ return;
+
+ pending.append(std::move(delayedName));
+ (*delayedValues)[pendingName].setValue(std::move(pending));
+}
+
+void QQmlBindPrivate::evalDelayed()
+{
+ if (!when || !delayedValues)
+ return;
+
+ const QString pendingName = QStringLiteral("pending");
+ const QStringList pending = qvariant_cast<QStringList>((*delayedValues)[pendingName]);
+ for (const QString &delayedName : pending) {
+ bool ok;
+ const int delayedIndex = delayedName.toInt(&ok);
+ Q_ASSERT(ok);
+ Q_ASSERT(delayedIndex >= 0 && delayedIndex < entries.size());
+ entries[delayedIndex].prop.write((*delayedValues)[delayedName]);
+ }
+ (*delayedValues)[pendingName].setValue(QStringList());
+}
+
+void QQmlBindPrivate::buildBindEntries(QQmlBind *q, QQmlComponentPrivate::DeferredState *deferredState)
+{
+ QQmlData *data = QQmlData::get(q);
+ if (data && !data->deferredData.isEmpty()) {
+ QQmlEnginePrivate *ep = QQmlEnginePrivate::get(data->context->engine());
+ for (QQmlData::DeferredData *deferredData : data->deferredData) {
+ QMultiHash<int, const QV4::CompiledData::Binding *> *bindings = &deferredData->bindings;
+ if (deferredState) {
+ QQmlComponentPrivate::ConstructionState constructionState;
+ for (auto it = bindings->cbegin(); it != bindings->cend(); ++it)
+ decodeBinding(q, QString(), deferredData, *it, &constructionState);
+
+
+ if (constructionState.hasCreator()) {
+ ++ep->inProgressCreations;
+ constructionState.creator()->finalizePopulateDeferred();
+ constructionState.appendCreatorErrors();
+ deferredState->push_back(std::move(constructionState));
+ }
+ } else {
+ for (auto it = bindings->cbegin(); it != bindings->cend(); ++it)
+ decodeBinding(q, QString(), deferredData, *it, nullptr);
+ }
+ }
+
+ if (deferredState) {
+ data->releaseDeferredData();
+ if (!deferredState->empty())
+ QQmlComponentPrivate::completeDeferred(ep, deferredState);
+ }
+ }
+}
+
void QQmlBind::componentComplete()
{
Q_D(QQmlBind);
+ QQmlComponentPrivate::DeferredState deferredState;
+ d->buildBindEntries(this, &deferredState);
d->componentComplete = true;
- if (!d->prop.isValid()) {
- setTarget(QQmlProperty(d->obj, d->propName, qmlContext(this)));
- d->validate(this);
+ if (!d->propName.isEmpty() || d->obj) {
+ QQmlBindEntry *target = d->targetEntry();
+ if (!target->prop.isValid())
+ target->setTarget(this, QQmlProperty(d->obj, d->propName, qmlContext(this)));
}
+ d->validate(this);
+ d->evalDelayed();
eval();
}
@@ -442,72 +1001,110 @@ void QQmlBind::prepareEval()
}
}
-void QQmlBindPrivate::clearPrev()
+void QQmlBindEntry::clearPrev()
{
- prevBind = nullptr;
- v4Value.clear();
- prevValue.clear();
- prevIsVariant = false;
+ previousKind = previous.destroy(previousKind);
}
void QQmlBind::eval()
{
Q_D(QQmlBind);
d->pendingEval = false;
- if (!d->prop.isValid() || d->value.isNull || !d->componentComplete)
+ if (!d->componentComplete)
return;
- if (d->when.isValid()) {
+ for (QQmlBindEntry &entry : d->entries) {
+ if (!entry.prop.isValid() || (entry.currentKind == QQmlBindEntryKind::None))
+ continue;
+
if (!d->when) {
//restore any previous binding
- if (d->prevBind) {
+ switch (entry.previousKind) {
+ case QQmlBindEntryKind::Binding:
if (d->restoreBinding) {
- QQmlAbstractBinding::Ptr p = d->prevBind;
- d->clearPrev(); // Do that before setBinding(), as setBinding() may recurse.
- QQmlPropertyPrivate::setBinding(p.data());
+ QQmlAnyBinding p = std::move(entry.previous.binding);
+ entry.clearPrev(); // Do that before setBinding(), as setBinding() may recurse.
+ p.installOn(entry.prop);
}
- } else if (!d->v4Value.isEmpty()) {
+ break;
+ case QQmlBindEntryKind::V4Value:
if (d->restoreValue) {
- auto propPriv = QQmlPropertyPrivate::get(d->prop);
+ QQmlAnyBinding::takeFrom(entry.prop); // we don't want to have a binding active
+ auto propPriv = QQmlPropertyPrivate::get(entry.prop);
QQmlVMEMetaObject *vmemo = QQmlVMEMetaObject::get(propPriv->object);
Q_ASSERT(vmemo);
- vmemo->setVMEProperty(propPriv->core.coreIndex(), *d->v4Value.valueRef());
- d->clearPrev();
+ vmemo->setVMEProperty(propPriv->core.coreIndex(),
+ *entry.previous.v4Value.valueRef());
+ entry.clearPrev();
}
- } else if (d->prevIsVariant) {
+ break;
+ case QQmlBindEntryKind::Variant:
if (d->restoreValue) {
- d->prop.write(d->prevValue);
- d->clearPrev();
+ QQmlAnyBinding::takeFrom(entry.prop); // we don't want to have a binding active
+ entry.prop.write(entry.previous.variant);
+ entry.clearPrev();
}
+ break;
+ case QQmlBindEntryKind::None:
+ break;
}
- return;
+ continue;
}
//save any set binding for restoration
- if (!d->prevBind && d->v4Value.isEmpty() && !d->prevIsVariant) {
- // try binding first
- d->prevBind = QQmlPropertyPrivate::binding(d->prop);
-
- if (!d->prevBind) { // nope, try a V4 value next
- auto propPriv = QQmlPropertyPrivate::get(d->prop);
+ if (entry.previousKind == QQmlBindEntryKind::None) {
+ // try binding first; we need to use takeFrom to properly unlink the binding
+ QQmlAnyBinding prevBind = QQmlAnyBinding::takeFrom(entry.prop);
+ if (prevBind) {
+ entry.previousKind = entry.previous.set(std::move(prevBind), entry.previousKind);
+ } else {
+ // nope, try a V4 value next
+ auto propPriv = QQmlPropertyPrivate::get(entry.prop);
auto propData = propPriv->core;
if (!propPriv->valueTypeData.isValid() && propData.isVarProperty()) {
QQmlVMEMetaObject *vmemo = QQmlVMEMetaObject::get(propPriv->object);
Q_ASSERT(vmemo);
auto retVal = vmemo->vmeProperty(propData.coreIndex());
- d->v4Value = QV4::PersistentValue(vmemo->engine, retVal);
- } else { // nope, use the meta object to get a QVariant
- d->prevValue = d->prop.read();
- d->prevIsVariant = true;
+ entry.previousKind = entry.previous.set(
+ QV4::PersistentValue(vmemo->engine, retVal), entry.previousKind);
+ } else {
+ // nope, use the meta object to get a QVariant
+ entry.previousKind = entry.previous.set(entry.prop.read(), entry.previousKind);
}
}
}
- QQmlPropertyPrivate::removeBinding(d->prop);
+ // NOTE: removeBinding has no effect on QProperty classes, but
+ // we already used takeBinding to remove it
+ QQmlPropertyPrivate::removeBinding(entry.prop);
}
+ if (!d->when)
+ return;
+
d->writingProperty = true;
- d->prop.write(d->value.value.toVariant());
+ for (qsizetype i = 0, end = d->entries.size(); i != end; ++i) {
+ QQmlBindEntry &entry = d->entries[i];
+ if (!entry.prop.isValid())
+ continue;
+ switch (entry.currentKind) {
+ case QQmlBindEntryKind::Variant:
+ entry.prop.write(entry.current.variant);
+ break;
+ case QQmlBindEntryKind::Binding:
+ Q_ASSERT(!d->delayed);
+ entry.current.binding.installOn(entry.prop);
+ break;
+ case QQmlBindEntryKind::V4Value: {
+ auto propPriv = QQmlPropertyPrivate::get(entry.prop);
+ QQmlVMEMetaObject::get(propPriv->object)->setVMEProperty(
+ propPriv->core.coreIndex(), *entry.current.v4Value.valueRef());
+ break;
+ }
+ case QQmlBindEntryKind::None:
+ break;
+ }
+ }
d->writingProperty = false;
}
@@ -517,7 +1114,7 @@ void QQmlBind::targetValueChanged()
if (d->writingProperty)
return;
- if (d->when.isValid() && !d->when)
+ if (!d->when)
return;
QUrl url;
@@ -529,7 +1126,7 @@ void QQmlBind::targetValueChanged()
line = ddata->lineNumber;
}
- qCInfo(lcBindingRemoval,
+ qCInfo(lcQtQmlBindingRemoval,
"The target property of the Binding element created at %s:%d was changed from "
"elsewhere. This does not overwrite the binding. The target property will still be "
"updated when the value of the Binding element changes.",
diff --git a/src/qml/types/qqmlbind_p.h b/src/qml/types/qqmlbind_p.h
index c709224c23..d4c93ebe0a 100644
--- a/src/qml/types/qqmlbind_p.h
+++ b/src/qml/types/qqmlbind_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLBIND_H
#define QQMLBIND_H
@@ -51,14 +15,15 @@
// We mean it.
//
-#include <qqml.h>
+#include <QtQmlMeta/qtqmlmetaexports.h>
+#include <QtQml/qqml.h>
#include <QtCore/qobject.h>
QT_BEGIN_NAMESPACE
class QQmlBindPrivate;
-class Q_AUTOTEST_EXPORT QQmlBind : public QObject, public QQmlPropertyValueSource, public QQmlParserStatus
+class Q_QMLMETA_EXPORT QQmlBind : public QObject, public QQmlPropertyValueSource, public QQmlParserStatus
{
public:
enum RestorationMode {
@@ -75,17 +40,18 @@ private:
Q_INTERFACES(QQmlPropertyValueSource)
Q_PROPERTY(QObject *target READ object WRITE setObject)
Q_PROPERTY(QString property READ property WRITE setProperty)
- Q_PROPERTY(QJSValue value READ value WRITE setValue)
+ Q_PROPERTY(QVariant value READ value WRITE setValue)
Q_PROPERTY(bool when READ when WRITE setWhen)
- Q_PROPERTY(bool delayed READ delayed WRITE setDelayed REVISION 8)
+ Q_PROPERTY(bool delayed READ delayed WRITE setDelayed REVISION(2, 8))
Q_PROPERTY(RestorationMode restoreMode READ restoreMode WRITE setRestoreMode
- NOTIFY restoreModeChanged REVISION 14)
+ NOTIFY restoreModeChanged REVISION(2, 14))
Q_ENUM(RestorationMode)
QML_NAMED_ELEMENT(Binding)
+ QML_ADDED_IN_VERSION(2, 0)
+ Q_CLASSINFO("ImmediatePropertyNames", "objectName,target,property,value,when,delayed,restoreMode");
public:
QQmlBind(QObject *parent=nullptr);
- ~QQmlBind();
bool when() const;
void setWhen(bool);
@@ -96,8 +62,8 @@ public:
QString property() const;
void setProperty(const QString &);
- QJSValue value() const;
- void setValue(const QJSValue &);
+ QVariant value() const;
+ void setValue(const QVariant &);
bool delayed() const;
void setDelayed(bool);
@@ -123,6 +89,4 @@ private Q_SLOTS:
QT_END_NAMESPACE
-QML_DECLARE_TYPE(QQmlBind)
-
#endif
diff --git a/src/qml/types/qqmlconnections.cpp b/src/qml/types/qqmlconnections.cpp
index 1e801641e5..710adc3efa 100644
--- a/src/qml/types/qqmlconnections.cpp
+++ b/src/qml/types/qqmlconnections.cpp
@@ -1,71 +1,140 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmlconnections_p.h"
-#include <private/qqmlexpression_p.h>
-#include <private/qqmlproperty_p.h>
#include <private/qqmlboundsignal_p.h>
-#include <qqmlcontext.h>
#include <private/qqmlcontext_p.h>
+#include <private/qqmlexpression_p.h>
+#include <private/qqmlproperty_p.h>
+#include <private/qqmlsignalnames_p.h>
#include <private/qqmlvmemetaobject_p.h>
-#include <qqmlinfo.h>
+#include <private/qv4jscall_p.h>
+#include <private/qv4qobjectwrapper_p.h>
+
+#include <QtQml/qqmlcontext.h>
+#include <QtQml/qqmlinfo.h>
#include <QtCore/qdebug.h>
+#include <QtCore/qloggingcategory.h>
#include <QtCore/qstringlist.h>
#include <private/qobject_p.h>
QT_BEGIN_NAMESPACE
+Q_STATIC_LOGGING_CATEGORY(lcQmlConnections, "qt.qml.connections")
+
+// This is the equivalent of QQmlBoundSignal for C++ methods as as slots.
+// If a type derived from QQmlConnnections is compiled using qmltc, the
+// JavaScript functions it contains are turned into C++ methods and we cannot
+// use QQmlBoundSignal to connect to those.
+struct QQmlConnectionSlotDispatcher : public QtPrivate::QSlotObjectBase
+{
+ QV4::ExecutionEngine *v4 = nullptr;
+ QObject *receiver = nullptr;
+
+ // Signals rarely have more than one argument.
+ QQmlMetaObject::ArgTypeStorage<2> signalMetaTypes;
+ QQmlMetaObject::ArgTypeStorage<2> slotMetaTypes;
+
+ QMetaObject::Connection connection;
+
+ int slotIndex = -1;
+ bool enabled = true;
+
+ QQmlConnectionSlotDispatcher(
+ QV4::ExecutionEngine *v4, QObject *sender, int signalIndex,
+ QObject *receiver, int slotIndex, bool enabled)
+ : QtPrivate::QSlotObjectBase(&impl)
+ , v4(v4)
+ , receiver(receiver)
+ , slotIndex(slotIndex)
+ , enabled(enabled)
+ {
+ QMetaMethod signal = sender->metaObject()->method(signalIndex);
+ QQmlMetaObject::methodReturnAndParameterTypes(signal, &signalMetaTypes, nullptr);
+
+ QMetaMethod slot = receiver->metaObject()->method(slotIndex);
+ QQmlMetaObject::methodReturnAndParameterTypes(slot, &slotMetaTypes, nullptr);
+ }
+
+ template<typename ArgTypeStorage>
+ struct TypedFunction
+ {
+ Q_DISABLE_COPY_MOVE(TypedFunction)
+ public:
+ TypedFunction(const ArgTypeStorage *storage) : storage(storage) {}
+
+ QMetaType returnMetaType() const { return storage->at(0); }
+ qsizetype parameterCount() const { return storage->size() - 1; }
+ QMetaType parameterMetaType(qsizetype i) const { return storage->at(i + 1); }
+
+ private:
+ const ArgTypeStorage *storage;
+ };
+
+ static void impl(int which, QSlotObjectBase *base, QObject *, void **metaArgs, bool *ret)
+ {
+ switch (which) {
+ case Destroy: {
+ delete static_cast<QQmlConnectionSlotDispatcher *>(base);
+ break;
+ }
+ case Call: {
+ QQmlConnectionSlotDispatcher *self = static_cast<QQmlConnectionSlotDispatcher *>(base);
+ QV4::ExecutionEngine *v4 = self->v4;
+ if (!v4)
+ break;
+
+ if (!self->enabled)
+ break;
+
+ TypedFunction typedFunction(&self->slotMetaTypes);
+ QV4::coerceAndCall(
+ v4, &typedFunction, metaArgs,
+ self->signalMetaTypes.data(), self->signalMetaTypes.size() - 1,
+ [&](void **argv, int) {
+ self->receiver->metaObject()->metacall(
+ self->receiver, QMetaObject::InvokeMetaMethod,
+ self->slotIndex, argv);
+ });
+
+ if (v4->hasException) {
+ QQmlError error = v4->catchExceptionAsQmlError();
+ if (QQmlEngine *qmlEngine = v4->qmlEngine()) {
+ QQmlEnginePrivate::get(qmlEngine)->warning(error);
+ } else {
+ QMessageLogger(
+ qPrintable(error.url().toString()), error.line(), nullptr)
+ .warning().noquote()
+ << error.toString();
+ }
+ }
+ break;
+ }
+ case Compare:
+ // We're not implementing the Compare protocol here. It's insane.
+ // QQmlConnectionSlotDispatcher compares false to anything. We use
+ // the regular QObject::disconnect with QMetaObject::Connection.
+ *ret = false;
+ break;
+ case NumOperations:
+ break;
+ }
+ };
+};
+
class QQmlConnectionsPrivate : public QObjectPrivate
{
public:
- QQmlConnectionsPrivate() : target(nullptr), enabled(true), targetSet(false), ignoreUnknownSignals(false), componentcomplete(true) {}
+ QList<QBiPointer<QQmlBoundSignal, QQmlConnectionSlotDispatcher>> boundsignals;
+ QQmlGuard<QObject> target;
- QList<QQmlBoundSignal*> boundsignals;
- QObject *target;
-
- bool enabled;
- bool targetSet;
- bool ignoreUnknownSignals;
- bool componentcomplete;
+ bool enabled = true;
+ bool targetSet = false;
+ bool ignoreUnknownSignals = false;
+ bool componentcomplete = true;
QQmlRefPointer<QV4::ExecutableCompilationUnit> compilationUnit;
QList<const QV4::CompiledData::Binding *> bindings;
@@ -85,7 +154,7 @@ public:
\qml
MouseArea {
- onClicked: { foo(parameters) }
+ onClicked: (mouse)=> { foo(mouse) }
}
\endqml
@@ -127,7 +196,13 @@ public:
}
\endqml
- \sa {Qt QML}
+ \note For backwards compatibility you can also specify the signal handlers
+ without \c{function}, like you would specify them directly in the target
+ object. This is not recommended. If you specify one signal handler this way,
+ then all signal handlers specified as \c{function} in the same Connections
+ object are ignored.
+
+ \sa {Qt Qml}
*/
QQmlConnections::QQmlConnections(QObject *parent) :
QObject(*(new QQmlConnectionsPrivate), parent)
@@ -136,10 +211,22 @@ QQmlConnections::QQmlConnections(QObject *parent) :
QQmlConnections::~QQmlConnections()
{
+ Q_D(QQmlConnections);
+
+ // The slot dispatchers hold cyclic references to their connections. Clear them.
+ for (const auto &bound : std::as_const(d->boundsignals)) {
+ if (QQmlConnectionSlotDispatcher *dispatcher = bound.isT2() ? bound.asT2() : nullptr) {
+ // No need to explicitly disconnect anymore since 'this' is the receiver.
+ // But to be safe, explicitly break any cyclic references between the connection
+ // and the slot object.
+ dispatcher->connection = {};
+ dispatcher->destroyIfLastRef();
+ }
+ }
}
/*!
- \qmlproperty Object QtQml::Connections::target
+ \qmlproperty QtObject QtQml::Connections::target
This property holds the object that sends the signal.
If this property is not set, the \c target defaults to the parent of the Connection.
@@ -150,7 +237,7 @@ QQmlConnections::~QQmlConnections()
QObject *QQmlConnections::target() const
{
Q_D(const QQmlConnections);
- return d->targetSet ? d->target : parent();
+ return d->targetSet ? d->target.data() : parent();
}
class QQmlBoundSignalDeleter : public QObject
@@ -169,13 +256,19 @@ void QQmlConnections::setTarget(QObject *obj)
if (d->targetSet && d->target == obj)
return;
d->targetSet = true; // even if setting to 0, it is *set*
- for (QQmlBoundSignal *s : qAsConst(d->boundsignals)) {
+ for (const auto &bound : std::as_const(d->boundsignals)) {
// It is possible that target is being changed due to one of our signal
// handlers -> use deleteLater().
- if (s->isNotifying())
- (new QQmlBoundSignalDeleter(s))->deleteLater();
- else
- delete s;
+ if (QQmlBoundSignal *signal = bound.isT1() ? bound.asT1() : nullptr) {
+ if (signal->isNotifying())
+ (new QQmlBoundSignalDeleter(signal))->deleteLater();
+ else
+ delete signal;
+ } else {
+ QQmlConnectionSlotDispatcher *dispatcher = bound.asT2();
+ QObject::disconnect(std::exchange(dispatcher->connection, {}));
+ dispatcher->destroyIfLastRef();
+ }
}
d->boundsignals.clear();
d->target = obj;
@@ -205,8 +298,12 @@ void QQmlConnections::setEnabled(bool enabled)
d->enabled = enabled;
- for (QQmlBoundSignal *s : qAsConst(d->boundsignals))
- s->setEnabled(d->enabled);
+ for (const auto &bound : std::as_const(d->boundsignals)) {
+ if (QQmlBoundSignal *signal = bound.isT1() ? bound.asT1() : nullptr)
+ signal->setEnabled(d->enabled);
+ else
+ bound.asT2()->enabled = enabled;
+ }
emit enabledChanged();
}
@@ -234,26 +331,29 @@ void QQmlConnections::setIgnoreUnknownSignals(bool ignore)
void QQmlConnectionsParser::verifyBindings(const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit, const QList<const QV4::CompiledData::Binding *> &props)
{
- for (int ii = 0; ii < props.count(); ++ii) {
+ for (int ii = 0; ii < props.size(); ++ii) {
const QV4::CompiledData::Binding *binding = props.at(ii);
const QString &propName = compilationUnit->stringAt(binding->propertyNameIndex);
- if (!propName.startsWith(QLatin1String("on")) || (propName.length() < 3 || !propName.at(2).isUpper())) {
+ if (!QQmlSignalNames::isHandlerName(propName)) {
error(props.at(ii), QQmlConnections::tr("Cannot assign to non-existent property \"%1\"").arg(propName));
return;
}
- if (binding->type >= QV4::CompiledData::Binding::Type_Object) {
+ if (binding->type() == QV4::CompiledData::Binding::Type_Script)
+ continue;
+
+ if (binding->type() >= QV4::CompiledData::Binding::Type_Object) {
const QV4::CompiledData::Object *target = compilationUnit->objectAt(binding->value.objectIndex);
if (!compilationUnit->stringAt(target->inheritedTypeNameIndex).isEmpty())
error(binding, QQmlConnections::tr("Connections: nested objects not allowed"));
else
error(binding, QQmlConnections::tr("Connections: syntax error"));
return;
- } if (binding->type != QV4::CompiledData::Binding::Type_Script) {
- error(binding, QQmlConnections::tr("Connections: script expected"));
- return;
}
+
+ error(binding, QQmlConnections::tr("Connections: script expected"));
+ return;
}
}
@@ -274,10 +374,10 @@ void QQmlConnections::connectSignals()
if (d->bindings.isEmpty()) {
connectSignalsToMethods();
} else {
-#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
- qmlWarning(this) << tr("Implicitly defined onFoo properties in Connections are deprecated. "
- "Use this syntax instead: function onFoo(<arguments>) { ... }");
-#endif
+ if (lcQmlConnections().isWarningEnabled()) {
+ qmlWarning(this) << tr("Implicitly defined onFoo properties in Connections are deprecated. "
+ "Use this syntax instead: function onFoo(<arguments>) { ... }");
+ }
connectSignalsToBindings();
}
}
@@ -291,44 +391,51 @@ void QQmlConnections::connectSignalsToMethods()
if (!ddata)
return;
- QV4::ExecutionEngine *engine = ddata->context->engine->handle();
+ QV4::ExecutionEngine *engine = ddata->context->engine()->handle();
- QQmlContextData *ctxtdata = ddata->outerContext;
+ QQmlRefPointer<QQmlContextData> ctxtdata = ddata->outerContext;
for (int i = ddata->propertyCache->methodOffset(),
end = ddata->propertyCache->methodOffset() + ddata->propertyCache->methodCount();
i < end;
++i) {
- QQmlPropertyData *handler = ddata->propertyCache->method(i);
- if (!handler || !handler->isVMEFunction())
+ const QQmlPropertyData *handler = ddata->propertyCache->method(i);
+ if (!handler)
continue;
const QString propName = handler->name(this);
QQmlProperty prop(target, propName);
if (prop.isValid() && (prop.type() & QQmlProperty::SignalProperty)) {
- int signalIndex = QQmlPropertyPrivate::get(prop)->signalIndex();
- auto *signal = new QQmlBoundSignal(target, signalIndex, this, qmlEngine(this));
- signal->setEnabled(d->enabled);
-
QV4::Scope scope(engine);
QV4::ScopedContext global(scope, engine->rootContext());
- QQmlVMEMetaObject *vmeMetaObject = QQmlVMEMetaObject::get(this);
- Q_ASSERT(vmeMetaObject); // the fact we found the property above should guarentee this
-
- QV4::ScopedFunctionObject method(scope, vmeMetaObject->vmeMethod(handler->coreIndex()));
-
- QQmlBoundSignalExpression *expression =
- ctxtdata ? new QQmlBoundSignalExpression(
- target, signalIndex, ctxtdata, this,
- method->as<QV4::FunctionObject>()->function())
- : nullptr;
-
- signal->takeExpression(expression);
- d->boundsignals += signal;
+ if (QQmlVMEMetaObject *vmeMetaObject = QQmlVMEMetaObject::get(this)) {
+ int signalIndex = QQmlPropertyPrivate::get(prop)->signalIndex();
+ auto *signal = new QQmlBoundSignal(target, signalIndex, this, qmlEngine(this));
+ signal->setEnabled(d->enabled);
+
+ QV4::Scoped<QV4::JavaScriptFunctionObject> method(
+ scope, vmeMetaObject->vmeMethod(handler->coreIndex()));
+
+ QQmlBoundSignalExpression *expression = ctxtdata
+ ? new QQmlBoundSignalExpression(
+ target, signalIndex, ctxtdata, this, method->function())
+ : nullptr;
+
+ signal->takeExpression(expression);
+ d->boundsignals += signal;
+ } else {
+ QQmlConnectionSlotDispatcher *slot = new QQmlConnectionSlotDispatcher(
+ scope.engine, target, prop.index(),
+ this, handler->coreIndex(), d->enabled);
+ slot->connection = QObjectPrivate::connect(
+ target, prop.index(), slot, Qt::AutoConnection);
+ slot->ref();
+ d->boundsignals += slot;
+ }
} else if (!d->ignoreUnknownSignals
- && propName.startsWith(QLatin1String("on")) && propName.length() > 2
+ && propName.startsWith(QLatin1String("on")) && propName.size() > 2
&& propName.at(2).isUpper()) {
qmlWarning(this) << tr("Detected function \"%1\" in Connections element. "
"This is probably intended to be a signal handler but no "
@@ -343,10 +450,10 @@ void QQmlConnections::connectSignalsToBindings()
Q_D(QQmlConnections);
QObject *target = this->target();
QQmlData *ddata = QQmlData::get(this);
- QQmlContextData *ctxtdata = ddata ? ddata->outerContext : nullptr;
+ QQmlRefPointer<QQmlContextData> ctxtdata = ddata ? ddata->outerContext : nullptr;
- for (const QV4::CompiledData::Binding *binding : qAsConst(d->bindings)) {
- Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_Script);
+ for (const QV4::CompiledData::Binding *binding : std::as_const(d->bindings)) {
+ Q_ASSERT(binding->type() == QV4::CompiledData::Binding::Type_Script);
QString propName = d->compilationUnit->stringAt(binding->propertyNameIndex);
QQmlProperty prop(target, propName);
diff --git a/src/qml/types/qqmlconnections_p.h b/src/qml/types/qqmlconnections_p.h
index 7bf688cf75..f0852cda73 100644
--- a/src/qml/types/qqmlconnections_p.h
+++ b/src/qml/types/qqmlconnections_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLCONNECTIONS_H
#define QQMLCONNECTIONS_H
@@ -51,9 +15,11 @@
// We mean it.
//
-#include <qqml.h>
#include <private/qqmlcustomparser_p.h>
+#include <QtQmlMeta/qtqmlmetaexports.h>
+#include <QtQml/qqml.h>
+
#include <QtCore/qobject.h>
#include <QtCore/qstring.h>
@@ -62,19 +28,21 @@ QT_BEGIN_NAMESPACE
class QQmlBoundSignal;
class QQmlContext;
class QQmlConnectionsPrivate;
-class Q_AUTOTEST_EXPORT QQmlConnections : public QObject, public QQmlParserStatus
+class Q_QMLMETA_EXPORT QQmlConnections : public QObject, public QQmlParserStatus
{
Q_OBJECT
Q_DECLARE_PRIVATE(QQmlConnections)
Q_INTERFACES(QQmlParserStatus)
Q_PROPERTY(QObject *target READ target WRITE setTarget NOTIFY targetChanged)
- Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled NOTIFY enabledChanged REVISION 3)
+ Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled NOTIFY enabledChanged REVISION(2, 3))
Q_PROPERTY(bool ignoreUnknownSignals READ ignoreUnknownSignals WRITE setIgnoreUnknownSignals)
QML_NAMED_ELEMENT(Connections)
+ QML_ADDED_IN_VERSION(2, 0)
+ QML_CUSTOMPARSER
public:
- QQmlConnections(QObject *parent=nullptr);
+ QQmlConnections(QObject *parent = nullptr);
~QQmlConnections();
QObject *target() const;
@@ -86,17 +54,18 @@ public:
bool ignoreUnknownSignals() const;
void setIgnoreUnknownSignals(bool ignore);
+protected:
+ void classBegin() override;
+ void componentComplete() override;
+
Q_SIGNALS:
void targetChanged();
- Q_REVISION(3) void enabledChanged();
+ Q_REVISION(2, 3) void enabledChanged();
private:
void connectSignals();
void connectSignalsToMethods();
void connectSignalsToBindings();
-
- void classBegin() override;
- void componentComplete() override;
};
// TODO: Drop this class as soon as we can
@@ -117,6 +86,4 @@ inline QQmlCustomParser *qmlCreateCustomParser<QQmlConnections>()
QT_END_NAMESPACE
-QML_DECLARE_TYPE(QQmlConnections)
-
#endif
diff --git a/src/qml/types/qqmllocaleenums_p.h b/src/qml/types/qqmllocaleenums_p.h
new file mode 100644
index 0000000000..771b74e5fb
--- /dev/null
+++ b/src/qml/types/qqmllocaleenums_p.h
@@ -0,0 +1,48 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QQMLLOCALEENUMS_H
+#define QQMLLOCALEENUMS_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <private/qtqmlglobal_p.h>
+#include <private/qqmllocale_p.h>
+
+#include <QtQmlMeta/qtqmlmetaexports.h>
+#include <QtQml/qqml.h>
+
+QT_REQUIRE_CONFIG(qml_locale);
+
+QT_BEGIN_NAMESPACE
+
+// Derive again so that we don't expose QQmlLocale as two different QML types
+// as that would be bad style.
+struct Q_QMLMETA_EXPORT QQmlLocaleEnums : public QQmlLocale
+{
+ Q_GADGET
+};
+
+// Use QML_FOREIGN_NAMESPACE so that we can expose QQmlLocaleEnums as a namespace
+// rather than a value type.
+namespace QQmlLocaleEnumsForeign
+{
+Q_NAMESPACE_EXPORT(Q_QMLMETA_EXPORT)
+QML_NAMED_ELEMENT(Locale)
+QML_ADDED_IN_VERSION(2, 2)
+QML_FOREIGN_NAMESPACE(QQmlLocaleEnums)
+};
+
+QT_END_NAMESPACE
+
+#endif // QQMLLOCALEENUMS_H
+
diff --git a/src/qml/types/qqmlloggingcategory.cpp b/src/qml/types/qqmlloggingcategory.cpp
new file mode 100644
index 0000000000..c18be74525
--- /dev/null
+++ b/src/qml/types/qqmlloggingcategory.cpp
@@ -0,0 +1,146 @@
+// Copyright (C) 2016 Pelagicore AG
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qqmlloggingcategory_p.h"
+
+#include <QtQml/qqmlinfo.h>
+
+#include <memory>
+
+/*!
+ \qmltype LoggingCategory
+ \ingroup qml-utility-elements
+ \inqmlmodule QtQml
+ \brief Defines a logging category in QML.
+ \since 5.8
+
+ A logging category can be passed to console.log() and friends as the first argument.
+ If supplied to the logger the LoggingCategory's name will be used as logging category.
+ Otherwise the default logging category will be used.
+
+ \qml
+ import QtQuick
+
+ Item {
+ LoggingCategory {
+ id: category
+ name: "com.qt.category"
+ defaultLogLevel: LoggingCategory.Warning
+ }
+
+ Component.onCompleted: {
+ console.log(category, "log message");
+ console.warn(category, "warning message");
+ }
+ }
+ \endqml
+
+ By default this outputs only \c{com.qt.category: warning message}. The
+ \c{log message} is suppressed due to the \l{defaultLogLevel}. You can,
+ however, configure log levels for QML logging categories the same way
+ you can configure them for
+ \l{QLoggingCategory#configuring-categories}{QLoggingCategory}.
+
+ \note As the creation of objects is expensive, it is encouraged to put the needed
+ LoggingCategory definitions into a singleton and import this where needed.
+
+ \sa QLoggingCategory
+*/
+
+/*!
+ \qmlproperty string QtQml::LoggingCategory::name
+
+ Holds the name of the logging category.
+
+ \note This property needs to be set when declaring the LoggingCategory
+ and cannot be changed later.
+
+ \sa QLoggingCategory::categoryName()
+*/
+
+/*!
+ \qmlproperty enumeration QtQml::LoggingCategory::defaultLogLevel
+ \since 5.12
+
+ Holds the default log level of the logging category. By default it is
+ created with the LoggingCategory.Debug log level.
+
+ The following enumeration values are available:
+ \list
+ \li LoggingCategory.Debug
+ \li LoggingCategory.Info
+ \li LoggingCategory.Warning
+ \li LoggingCategory.Critical
+ \li LoggingCategory.Fatal
+ \endlist
+
+ They mirror the values of the \l{QtMsgType} enumeration.
+
+ \note This property needs to be set when declaring the LoggingCategory
+ and cannot be changed later.
+
+ \sa QtMsgType
+*/
+
+QQmlLoggingCategory::QQmlLoggingCategory(QObject *parent)
+ : QQmlLoggingCategoryBase(parent)
+ , m_initialized(false)
+{
+}
+
+QQmlLoggingCategory::~QQmlLoggingCategory()
+{
+}
+
+QString QQmlLoggingCategory::name() const
+{
+ return QString::fromUtf8(m_name);
+}
+
+QQmlLoggingCategory::DefaultLogLevel QQmlLoggingCategory::defaultLogLevel() const
+{
+ return m_defaultLogLevel;
+}
+
+void QQmlLoggingCategory::classBegin()
+{
+}
+
+void QQmlLoggingCategory::componentComplete()
+{
+ m_initialized = true;
+ if (m_name.isNull())
+ qmlWarning(this) << QLatin1String("Declaring the name of a LoggingCategory is mandatory and cannot be changed later");
+ else
+ setCategory(m_name.constData(), QtMsgType(m_defaultLogLevel));
+}
+
+void QQmlLoggingCategory::setDefaultLogLevel(DefaultLogLevel defaultLogLevel)
+{
+ if (m_defaultLogLevel == defaultLogLevel)
+ return;
+
+ if (m_initialized) {
+ qmlWarning(this) << QLatin1String("The defaultLogLevel of a LoggingCategory cannot be changed after the component is completed");
+ return;
+ }
+
+ m_defaultLogLevel = defaultLogLevel;
+}
+
+void QQmlLoggingCategory::setName(const QString &name)
+{
+ const QByteArray newName = name.toUtf8();
+
+ if (m_name == newName)
+ return;
+
+ if (m_initialized) {
+ qmlWarning(this) << QLatin1String("The name of a LoggingCategory cannot be changed after the component is completed");
+ return;
+ }
+
+ m_name = newName;
+}
+
+#include "moc_qqmlloggingcategory_p.cpp"
diff --git a/src/qml/types/qqmlloggingcategory_p.h b/src/qml/types/qqmlloggingcategory_p.h
new file mode 100644
index 0000000000..1f1f9abb63
--- /dev/null
+++ b/src/qml/types/qqmlloggingcategory_p.h
@@ -0,0 +1,71 @@
+// Copyright (C) 2016 Pelagicore AG
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QQMLLOGGINGCATEGORY_P_H
+#define QQMLLOGGINGCATEGORY_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <private/qqmlloggingcategorybase_p.h>
+
+#include <QtQmlMeta/qtqmlmetaexports.h>
+
+#include <QtQml/qqml.h>
+#include <QtQml/qqmlparserstatus.h>
+
+#include <QtCore/private/qglobal_p.h>
+#include <QtCore/qloggingcategory.h>
+#include <QtCore/qobject.h>
+#include <QtCore/qstring.h>
+
+QT_BEGIN_NAMESPACE
+
+class Q_QMLMETA_EXPORT QQmlLoggingCategory : public QQmlLoggingCategoryBase, public QQmlParserStatus
+{
+ Q_OBJECT
+ Q_INTERFACES(QQmlParserStatus)
+
+ Q_PROPERTY(QString name READ name WRITE setName)
+ Q_PROPERTY(DefaultLogLevel defaultLogLevel READ defaultLogLevel WRITE setDefaultLogLevel REVISION(2, 12))
+ QML_NAMED_ELEMENT(LoggingCategory)
+ QML_ADDED_IN_VERSION(2, 8)
+
+public:
+ enum DefaultLogLevel {
+ Debug = QtDebugMsg,
+ Info = QtInfoMsg,
+ Warning = QtWarningMsg,
+ Critical = QtCriticalMsg,
+ Fatal = QtFatalMsg
+ };
+ Q_ENUM(DefaultLogLevel);
+
+ QQmlLoggingCategory(QObject *parent = nullptr);
+ virtual ~QQmlLoggingCategory();
+
+ DefaultLogLevel defaultLogLevel() const;
+ void setDefaultLogLevel(DefaultLogLevel defaultLogLevel);
+ QString name() const;
+ void setName(const QString &name);
+
+ void classBegin() override;
+ void componentComplete() override;
+
+private:
+ QByteArray m_name;
+ DefaultLogLevel m_defaultLogLevel = Debug;
+ bool m_initialized;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQMLLOGGINGCATEGORY_H
diff --git a/src/qml/types/qqmlmodelindexvaluetype.cpp b/src/qml/types/qqmlmodelindexvaluetype.cpp
deleted file mode 100644
index cbf2fef348..0000000000
--- a/src/qml/types/qqmlmodelindexvaluetype.cpp
+++ /dev/null
@@ -1,68 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qqmlmodelindexvaluetype_p.h"
-
-QT_BEGIN_NAMESPACE
-
-/*!
- \internal
-*/
-QString QQmlModelIndexValueType::propertiesString(const QModelIndex &idx)
-{
- if (!idx.isValid())
- return QLatin1String("()");
- return QString(QLatin1String("(%1,%2,0x%3,%4(0x%5))"))
- .arg(idx.row()).arg(idx.column()).arg(idx.internalId(), 0, 16)
- .arg(QLatin1String(idx.model()->metaObject()->className())).arg(quintptr(idx.model()), 0, 16);
-}
-
-/*!
- \internal
-*/
-QString QQmlItemSelectionRangeValueType::toString() const
-{
- return QString(QLatin1String("QItemSelectionRange(%1,%2)"))
- .arg(reinterpret_cast<const QQmlPersistentModelIndexValueType *>(&v.topLeft())->toString())
- .arg(reinterpret_cast<const QQmlPersistentModelIndexValueType *>(&v.bottomRight())->toString());
-}
-
-QT_END_NAMESPACE
-
-#include "moc_qqmlmodelindexvaluetype_p.cpp"
diff --git a/src/qml/types/qqmlmodelindexvaluetype_p.h b/src/qml/types/qqmlmodelindexvaluetype_p.h
deleted file mode 100644
index f5b1699574..0000000000
--- a/src/qml/types/qqmlmodelindexvaluetype_p.h
+++ /dev/null
@@ -1,164 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QQMLMODELINDEXVALUETYPE_P_H
-#define QQMLMODELINDEXVALUETYPE_P_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <QtCore/qabstractitemmodel.h>
-#include <QtCore/qitemselectionmodel.h>
-
-QT_BEGIN_NAMESPACE
-
-struct QQmlModelIndexValueType
-{
- QModelIndex v;
-
- Q_PROPERTY(int row READ row CONSTANT FINAL)
- Q_PROPERTY(int column READ column CONSTANT FINAL)
- Q_PROPERTY(QModelIndex parent READ parent FINAL)
- Q_PROPERTY(bool valid READ isValid CONSTANT FINAL)
- Q_PROPERTY(QAbstractItemModel *model READ model CONSTANT FINAL)
- Q_PROPERTY(quint64 internalId READ internalId CONSTANT FINAL)
- Q_GADGET
-
-public:
- Q_INVOKABLE QString toString() const
- { return QLatin1String("QModelIndex") + propertiesString(v); }
-
- inline int row() const Q_DECL_NOTHROW { return v.row(); }
- inline int column() const Q_DECL_NOTHROW { return v.column(); }
- inline QModelIndex parent() const { return v.parent(); }
- inline bool isValid() const Q_DECL_NOTHROW { return v.isValid(); }
- inline QAbstractItemModel *model() const Q_DECL_NOTHROW
- { return const_cast<QAbstractItemModel *>(v.model()); }
- quint64 internalId() const { return v.internalId(); }
-
- static QString propertiesString(const QModelIndex &idx);
-
- static QPersistentModelIndex toPersistentModelIndex(const QModelIndex &index)
- { return QPersistentModelIndex(index); }
-};
-
-struct QQmlPersistentModelIndexValueType
-{
- QPersistentModelIndex v;
-
- Q_PROPERTY(int row READ row FINAL)
- Q_PROPERTY(int column READ column FINAL)
- Q_PROPERTY(QModelIndex parent READ parent FINAL)
- Q_PROPERTY(bool valid READ isValid FINAL)
- Q_PROPERTY(QAbstractItemModel *model READ model FINAL)
- Q_PROPERTY(quint64 internalId READ internalId FINAL)
- Q_GADGET
-
-public:
- Q_INVOKABLE QString toString() const
- { return QLatin1String("QPersistentModelIndex") + QQmlModelIndexValueType::propertiesString(v); }
-
- inline int row() const { return v.row(); }
- inline int column() const { return v.column(); }
- inline QModelIndex parent() const { return v.parent(); }
- inline bool isValid() const { return v.isValid(); }
- inline QAbstractItemModel *model() const { return const_cast<QAbstractItemModel *>(v.model()); }
- inline quint64 internalId() const { return v.internalId(); }
-
- static const QModelIndex &toModelIndex(const QPersistentModelIndex &index)
- { return index; }
-};
-
-struct QQmlItemSelectionRangeValueType
-{
- QItemSelectionRange v;
-
- Q_PROPERTY(int top READ top FINAL)
- Q_PROPERTY(int left READ left FINAL)
- Q_PROPERTY(int bottom READ bottom FINAL)
- Q_PROPERTY(int right READ right FINAL)
- Q_PROPERTY(int width READ width FINAL)
- Q_PROPERTY(int height READ height FINAL)
- Q_PROPERTY(QPersistentModelIndex topLeft READ topLeft FINAL)
- Q_PROPERTY(QPersistentModelIndex bottomRight READ bottomRight FINAL)
- Q_PROPERTY(QModelIndex parent READ parent FINAL)
- Q_PROPERTY(bool valid READ isValid FINAL)
- Q_PROPERTY(bool empty READ isEmpty FINAL)
- Q_PROPERTY(QAbstractItemModel *model READ model FINAL)
- Q_GADGET
-
-public:
- Q_INVOKABLE QString toString() const;
- Q_INVOKABLE inline bool contains(const QModelIndex &index) const
- { return v.contains(index); }
- Q_INVOKABLE inline bool contains(int row, int column, const QModelIndex &parentIndex) const
- { return v.contains(row, column, parentIndex); }
- Q_INVOKABLE inline bool intersects(const QItemSelectionRange &other) const
- { return v.intersects(other); }
- Q_INVOKABLE QItemSelectionRange intersected(const QItemSelectionRange &other) const
- { return v.intersected(other); }
-
- inline int top() const { return v.top(); }
- inline int left() const { return v.left(); }
- inline int bottom() const { return v.bottom(); }
- inline int right() const { return v.right(); }
- inline int width() const { return v.width(); }
- inline int height() const { return v.height(); }
- inline QPersistentModelIndex &topLeft() const { return const_cast<QPersistentModelIndex &>(v.topLeft()); }
- inline QPersistentModelIndex &bottomRight() const { return const_cast<QPersistentModelIndex &>(v.bottomRight()); }
- inline QModelIndex parent() const { return v.parent(); }
- inline QAbstractItemModel *model() const { return const_cast<QAbstractItemModel *>(v.model()); }
- inline bool isValid() const { return v.isValid(); }
- inline bool isEmpty() const { return v.isEmpty(); }
-};
-
-#undef QLISTVALUETYPE_INVOKABLE_API
-
-QT_END_NAMESPACE
-
-#endif // QQMLMODELINDEXVALUETYPE_P_H
-
diff --git a/src/qml/types/qqmltimer.cpp b/src/qml/types/qqmltimer.cpp
index af2ff56f2a..fb3c53e880 100644
--- a/src/qml/types/qqmltimer.cpp
+++ b/src/qml/types/qqmltimer.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmltimer_p.h"
@@ -313,8 +277,6 @@ void QQmlTimer::componentComplete()
\qmlsignal QtQml::Timer::triggered()
This signal is emitted when the Timer times out.
-
- The corresponding handler is \c onTriggered.
*/
void QQmlTimer::ticked()
{
diff --git a/src/qml/types/qqmltimer_p.h b/src/qml/types/qqmltimer_p.h
index 0cd93e4659..f926262952 100644
--- a/src/qml/types/qqmltimer_p.h
+++ b/src/qml/types/qqmltimer_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLTIMER_H
#define QQMLTIMER_H
@@ -51,18 +15,18 @@
// We mean it.
//
-#include <qqml.h>
+#include <private/qtqmlglobal_p.h>
+#include <QtQmlMeta/qtqmlmetaexports.h>
+#include <QtQml/qqml.h>
#include <QtCore/qobject.h>
-#include <private/qtqmlglobal_p.h>
-
QT_REQUIRE_CONFIG(qml_animation);
QT_BEGIN_NAMESPACE
class QQmlTimerPrivate;
-class Q_QML_PRIVATE_EXPORT QQmlTimer : public QObject, public QQmlParserStatus
+class Q_QMLMETA_EXPORT QQmlTimer : public QObject, public QQmlParserStatus
{
Q_OBJECT
Q_DECLARE_PRIVATE(QQmlTimer)
@@ -72,7 +36,9 @@ class Q_QML_PRIVATE_EXPORT QQmlTimer : public QObject, public QQmlParserStatus
Q_PROPERTY(bool repeat READ isRepeating WRITE setRepeating NOTIFY repeatChanged)
Q_PROPERTY(bool triggeredOnStart READ triggeredOnStart WRITE setTriggeredOnStart NOTIFY triggeredOnStartChanged)
Q_PROPERTY(QObject *parent READ parent CONSTANT)
+ Q_CLASSINFO("ParentProperty", "parent")
QML_NAMED_ELEMENT(Timer)
+ QML_ADDED_IN_VERSION(2, 0)
public:
QQmlTimer(QObject *parent=nullptr);
@@ -116,6 +82,4 @@ private Q_SLOTS:
QT_END_NAMESPACE
-QML_DECLARE_TYPE(QQmlTimer)
-
#endif
diff --git a/src/qml/types/types.pri b/src/qml/types/types.pri
deleted file mode 100644
index 54cd8710b6..0000000000
--- a/src/qml/types/types.pri
+++ /dev/null
@@ -1,22 +0,0 @@
-SOURCES += \
- $$PWD/qqmlbind.cpp \
- $$PWD/qqmlconnections.cpp
-
-HEADERS += \
- $$PWD/qqmlbind_p.h \
- $$PWD/qqmlconnections_p.h
-
-qtConfig(qml-itemmodel) {
- SOURCES += \
- $$PWD/qqmlmodelindexvaluetype.cpp
- HEADERS += \
- $$PWD/qqmlmodelindexvaluetype_p.h
-}
-
-qtConfig(qml-animation) {
- SOURCES += \
- $$PWD/qqmltimer.cpp
-
- HEADERS += \
- $$PWD/qqmltimer_p.h
-}