aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/qml/qml/qqmlvmemetaobject.cpp55
-rw-r--r--src/qml/qml/qqmlvmemetaobject_p.h18
-rw-r--r--src/quick/doc/src/guidelines/qtquick-bestpractices.qdoc37
-rw-r--r--src/quick/items/qquickaccessibleattached.cpp13
-rw-r--r--src/quick/items/qquickaccessibleattached_p.h5
-rw-r--r--src/quick/items/qquickitemview.cpp6
-rw-r--r--src/quick/items/qquickitemview_p_p.h6
-rw-r--r--src/quick/items/qquicklistview.cpp1
-rw-r--r--tests/auto/quick/qquickaccessible/tst_qquickaccessible.cpp34
9 files changed, 120 insertions, 55 deletions
diff --git a/src/qml/qml/qqmlvmemetaobject.cpp b/src/qml/qml/qqmlvmemetaobject.cpp
index abdc686ec2..95e99206f0 100644
--- a/src/qml/qml/qqmlvmemetaobject.cpp
+++ b/src/qml/qml/qqmlvmemetaobject.cpp
@@ -401,57 +401,20 @@ void QQmlVMEMetaObject::writeProperty(int id, double v)
void QQmlVMEMetaObject::writeProperty(int id, const QString& v)
{
QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
- if (md)
- md->set(engine, id, engine->newString(v));
-}
-
-void QQmlVMEMetaObject::writeProperty(int id, const QUrl& v)
-{
- QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
- if (md)
- md->set(engine, id, engine->newVariantObject(QVariant::fromValue(v)));
-}
-
-void QQmlVMEMetaObject::writeProperty(int id, const QDate& v)
-{
- QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
- if (md)
- md->set(engine, id, engine->newVariantObject(QVariant::fromValue(v)));
-}
-
-void QQmlVMEMetaObject::writeProperty(int id, const QDateTime& v)
-{
- QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
- if (md)
- md->set(engine, id, engine->newVariantObject(QVariant::fromValue(v)));
-}
-
-void QQmlVMEMetaObject::writeProperty(int id, const QPointF& v)
-{
- QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
- if (md)
- md->set(engine, id, engine->newVariantObject(QVariant::fromValue(v)));
-}
-
-void QQmlVMEMetaObject::writeProperty(int id, const QSizeF& v)
-{
- QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
- if (md)
- md->set(engine, id, engine->newVariantObject(QVariant::fromValue(v)));
-}
-
-void QQmlVMEMetaObject::writeProperty(int id, const QRectF& v)
-{
- QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
- if (md)
- md->set(engine, id, engine->newVariantObject(QVariant::fromValue(v)));
+ if (md) {
+ QV4::Scope scope(engine);
+ QV4::Scoped<QV4::MemberData>(scope, md)->set(engine, id, engine->newString(v));
+ }
}
void QQmlVMEMetaObject::writeProperty(int id, QObject* v)
{
QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
- if (md)
- md->set(engine, id, QV4::Value::fromReturnedValue(QV4::QObjectWrapper::wrap(engine, v)));
+ if (md) {
+ QV4::Scope scope(engine);
+ QV4::Scoped<QV4::MemberData>(scope, md)->set(engine, id, QV4::Value::fromReturnedValue(
+ QV4::QObjectWrapper::wrap(engine, v)));
+ }
QQmlVMEVariantQObjectPtr *guard = getQObjectGuardForProperty(id);
if (v && !guard) {
diff --git a/src/qml/qml/qqmlvmemetaobject_p.h b/src/qml/qml/qqmlvmemetaobject_p.h
index 5025987586..58332ff7a8 100644
--- a/src/qml/qml/qqmlvmemetaobject_p.h
+++ b/src/qml/qml/qqmlvmemetaobject_p.h
@@ -194,12 +194,18 @@ public:
void writeProperty(int id, bool v);
void writeProperty(int id, double v);
void writeProperty(int id, const QString& v);
- void writeProperty(int id, const QPointF& v);
- void writeProperty(int id, const QSizeF& v);
- void writeProperty(int id, const QUrl& v);
- void writeProperty(int id, const QDate& v);
- void writeProperty(int id, const QDateTime& v);
- void writeProperty(int id, const QRectF& v);
+
+ template<typename VariantCompatible>
+ void writeProperty(int id, const VariantCompatible &v)
+ {
+ QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
+ if (md) {
+ QV4::Scope scope(engine);
+ QV4::Scoped<QV4::MemberData>(scope, md)->set(engine, id, engine->newVariantObject(
+ QVariant::fromValue(v)));
+ }
+ }
+
void writeProperty(int id, QObject *v);
void ensureQObjectWrapper();
diff --git a/src/quick/doc/src/guidelines/qtquick-bestpractices.qdoc b/src/quick/doc/src/guidelines/qtquick-bestpractices.qdoc
index f4a1616943..abfff7cc11 100644
--- a/src/quick/doc/src/guidelines/qtquick-bestpractices.qdoc
+++ b/src/quick/doc/src/guidelines/qtquick-bestpractices.qdoc
@@ -402,6 +402,43 @@ property MyMenu optionsMenu
For information on performance in QML and Qt Quick,
see \l {Performance Considerations And Suggestions}.
+\section1 Prefer Declarative Bindings Over Imperative Assignments
+
+In QML, it's possible to use imperative JavaScript code to perform tasks
+such as responding to input events, send data over a network, and so on.
+Imperative code has an important place in QML, but it's also important
+to be aware of when not to use it.
+
+For example, consider the following imperative assignment:
+
+\code
+Rectangle {
+ Component.onCompleted: color = "red"
+}
+\endcode
+
+This has the following disadvantages:
+
+\list
+\li It's slow. The color property will first be evaluated with a
+ default-constructed value, and then again with "red" later on.
+\li It delays errors that could be found at build time to run time, slowing
+ down the development process.
+\li It overwrites any declarative binding that was in place. In most cases this
+ is intended, but sometimes it can be unintentional.
+ See \l {Debugging overwriting of bindings} for more information.
+\li It interferes with tooling; Qt Quick Designer, for example, doesn't support
+ JavaScript.
+\endlist
+
+The code can be rewritten to be a declarative binding instead:
+
+\code
+Rectangle {
+ color: "red"
+}
+\endcode
+
\section1 Tools and Utilities
For information on useful tools and utilies that make working with QML and
diff --git a/src/quick/items/qquickaccessibleattached.cpp b/src/quick/items/qquickaccessibleattached.cpp
index c150e4efa2..2da01e9151 100644
--- a/src/quick/items/qquickaccessibleattached.cpp
+++ b/src/quick/items/qquickaccessibleattached.cpp
@@ -433,6 +433,19 @@ void QQuickAccessibleAttached::setRole(QAccessible::Role role)
}
}
+bool QQuickAccessibleAttached::wasNameExplicitlySet() const
+{
+ return m_nameExplicitlySet;
+}
+
+// Allows types to attach an accessible name to an item as a convenience,
+// so long as the user hasn't done so themselves.
+void QQuickAccessibleAttached::setNameImplicitly(const QString &name)
+{
+ setName(name);
+ m_nameExplicitlySet = false;
+}
+
QQuickAccessibleAttached *QQuickAccessibleAttached::qmlAttachedProperties(QObject *obj)
{
return new QQuickAccessibleAttached(obj);
diff --git a/src/quick/items/qquickaccessibleattached_p.h b/src/quick/items/qquickaccessibleattached_p.h
index f4194ef13d..87fb79ecc9 100644
--- a/src/quick/items/qquickaccessibleattached_p.h
+++ b/src/quick/items/qquickaccessibleattached_p.h
@@ -118,7 +118,10 @@ public:
return QString();
return m_name;
}
+
+ bool wasNameExplicitlySet() const;
void setName(const QString &name) {
+ m_nameExplicitlySet = true;
if (name != m_name) {
m_name = name;
Q_EMIT nameChanged();
@@ -126,6 +129,7 @@ public:
QAccessible::updateAccessibility(&ev);
}
}
+ void setNameImplicitly(const QString &name);
QString description() const { return m_description; }
void setDescription(const QString &description)
@@ -216,6 +220,7 @@ private:
QAccessible::State m_state;
QAccessible::State m_stateExplicitlySet;
QString m_name;
+ bool m_nameExplicitlySet = false;
QString m_description;
static QMetaMethod sigPress;
diff --git a/src/quick/items/qquickitemview.cpp b/src/quick/items/qquickitemview.cpp
index 661f19509a..7c74eafd3a 100644
--- a/src/quick/items/qquickitemview.cpp
+++ b/src/quick/items/qquickitemview.cpp
@@ -1790,6 +1790,7 @@ void QQuickItemViewPrivate::refill(qreal from, qreal to)
if (prevCount != itemCount)
emit q->countChanged();
} while (currentChanges.hasPendingChanges() || bufferedChanges.hasPendingChanges());
+ storeFirstVisibleItemPosition();
}
void QQuickItemViewPrivate::regenerate(bool orientationChanged)
@@ -1876,6 +1877,7 @@ void QQuickItemViewPrivate::layout()
updateSections();
layoutVisibleItems();
+ storeFirstVisibleItemPosition();
int lastIndexInView = findLastIndexInView();
refill();
@@ -1960,7 +1962,7 @@ bool QQuickItemViewPrivate::applyModelChanges(ChangeResult *totalInsertionResult
prevFirstItemInViewPos = prevFirstItemInView->position();
prevFirstItemInViewIndex = prevFirstItemInView->index;
}
- qreal prevVisibleItemsFirstPos = visibleItems.count() ? visibleItems.constFirst()->position() : 0.0;
+ qreal prevVisibleItemsFirstPos = visibleItems.count() ? firstVisibleItemPosition : 0.0;
totalInsertionResult->visiblePos = prevFirstItemInViewPos;
totalRemovalResult->visiblePos = prevFirstItemInViewPos;
@@ -2006,6 +2008,7 @@ bool QQuickItemViewPrivate::applyModelChanges(ChangeResult *totalInsertionResult
if (!insertions.isEmpty()) {
repositionFirstItem(prevVisibleItemsFirst, prevVisibleItemsFirstPos, prevFirstItemInView, &insertionResult, &removalResult);
layoutVisibleItems(removals.first().index);
+ storeFirstVisibleItemPosition();
}
}
@@ -2026,6 +2029,7 @@ bool QQuickItemViewPrivate::applyModelChanges(ChangeResult *totalInsertionResult
if (i < insertions.count() - 1) {
repositionFirstItem(prevVisibleItemsFirst, prevVisibleItemsFirstPos, prevFirstItemInView, &insertionResult, &removalResult);
layoutVisibleItems(insertions[i].index);
+ storeFirstVisibleItemPosition();
}
itemCount += insertions[i].count;
}
diff --git a/src/quick/items/qquickitemview_p_p.h b/src/quick/items/qquickitemview_p_p.h
index 6442fee27d..b31f53b2c0 100644
--- a/src/quick/items/qquickitemview_p_p.h
+++ b/src/quick/items/qquickitemview_p_p.h
@@ -260,6 +260,12 @@ public:
MovementReason moveReason;
QList<FxViewItem *> visibleItems;
+ qreal firstVisibleItemPosition = 0;
+ void storeFirstVisibleItemPosition() {
+ if (!visibleItems.isEmpty()) {
+ firstVisibleItemPosition = visibleItems.constFirst()->position();
+ }
+ }
int visibleIndex;
int currentIndex;
FxViewItem *currentItem;
diff --git a/src/quick/items/qquicklistview.cpp b/src/quick/items/qquicklistview.cpp
index 18a9afbad8..48bb70e597 100644
--- a/src/quick/items/qquicklistview.cpp
+++ b/src/quick/items/qquicklistview.cpp
@@ -805,6 +805,7 @@ void QQuickListViewPrivate::layoutVisibleItems(int fromModelIndex)
FxViewItem *firstItem = *visibleItems.constBegin();
bool fixedCurrent = currentItem && firstItem->item == currentItem->item;
+ firstVisibleItemPosition = firstItem->position();
qreal sum = firstItem->size();
qreal pos = firstItem->position() + firstItem->size() + spacing;
firstItem->setVisible(firstItem->endPosition() >= from && firstItem->position() <= to);
diff --git a/tests/auto/quick/qquickaccessible/tst_qquickaccessible.cpp b/tests/auto/quick/qquickaccessible/tst_qquickaccessible.cpp
index d1f6d67aa1..061d5f8a1a 100644
--- a/tests/auto/quick/qquickaccessible/tst_qquickaccessible.cpp
+++ b/tests/auto/quick/qquickaccessible/tst_qquickaccessible.cpp
@@ -185,7 +185,8 @@ void tst_QQuickAccessible::quickAttachedProperties()
QObject *object = component.create();
QVERIFY(object != nullptr);
- QObject *attachedObject = QQuickAccessibleAttached::attachedProperties(object);
+ const auto attachedObject = qobject_cast<QQuickAccessibleAttached*>(
+ QQuickAccessibleAttached::attachedProperties(object));
QVERIFY(attachedObject);
if (attachedObject) {
QVariant p = attachedObject->property("role");
@@ -195,6 +196,7 @@ void tst_QQuickAccessible::quickAttachedProperties()
QCOMPARE(p.isNull(), true);
p = attachedObject->property("description");
QCOMPARE(p.isNull(), true);
+ QCOMPARE(attachedObject->wasNameExplicitlySet(), false);
}
delete object;
}
@@ -211,7 +213,8 @@ void tst_QQuickAccessible::quickAttachedProperties()
QObject *object = component.create();
QVERIFY(object != nullptr);
- QObject *attachedObject = QQuickAccessibleAttached::attachedProperties(object);
+ const auto attachedObject = qobject_cast<QQuickAccessibleAttached*>(
+ QQuickAccessibleAttached::attachedProperties(object));
QVERIFY(attachedObject);
if (attachedObject) {
QVariant p = attachedObject->property("role");
@@ -223,6 +226,7 @@ void tst_QQuickAccessible::quickAttachedProperties()
p = attachedObject->property("description");
QCOMPARE(p.isNull(), false);
QCOMPARE(p.toString(), QLatin1String("Duck"));
+ QCOMPARE(attachedObject->wasNameExplicitlySet(), true);
}
delete object;
}
@@ -292,6 +296,32 @@ void tst_QQuickAccessible::quickAttachedProperties()
}
delete object;
}
+ // Check that a name can be implicitly set.
+ {
+ QQmlEngine engine;
+ QQmlComponent component(&engine);
+ component.setData(R"(
+ import QtQuick 2.0
+ Text {
+ Accessible.role: Accessible.Button
+ Accessible.description: "Text Button"
+ })", QUrl());
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(object);
+
+ const auto attachedObject = qobject_cast<QQuickAccessibleAttached*>(
+ QQuickAccessibleAttached::attachedProperties(object.data()));
+ QVERIFY(attachedObject);
+ QVERIFY(!attachedObject->wasNameExplicitlySet());
+
+ attachedObject->setNameImplicitly(QLatin1String("Implicit"));
+ QCOMPARE(attachedObject->name(), QLatin1String("Implicit"));
+ QVERIFY(!attachedObject->wasNameExplicitlySet());
+
+ attachedObject->setName(QLatin1String("Explicit"));
+ QCOMPARE(attachedObject->name(), QLatin1String("Explicit"));
+ QVERIFY(attachedObject->wasNameExplicitlySet());
+ }
QTestAccessibility::clearEvents();
}