aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSimon Hausmann <simon.hausmann@qt.io>2018-03-19 10:18:57 +0100
committerSimon Hausmann <simon.hausmann@qt.io>2018-03-21 08:45:28 +0000
commitaceeec0a85cc50fec70e3142936332a3b09e7061 (patch)
tree059990158695a886d72bf18e25b5b30c489e2103
parentce5b33c350cb7aa4a649088d85e48be08b632b69 (diff)
Fix crash with StackView::initialItem
The following binding initialView: Qt.createComponent("blah.qml") works with QQC1 but crashes with QQC2 as soon as the garbage collector kicks in. In QQC1 StackView was implemented in a .qml file and the property was declared as property var initialItem For such declared properties the QML engine takes care of ensuring that the reference assigned is a strong reference towards the GC and it also tracks the life-time of the QObject in case it's explicitly deleted by somebody else. In QQC2 the property continues to be documented as "var" property, however it is implemented in C++ as QVariant property. The QVariant is not known to the GC at all and it also doesn't do life-cycle tracking. The C++ equivalent to "var" in QML is QJSValue, which is a strong reference and also ends up using a QPointer internally when holding a QObject. Task-number: QTBUG-67118 Change-Id: I43e473c7bf2c40f9843e9d50fe4fd805b54fd256 Reviewed-by: Mitch Curtis <mitch.curtis@qt.io>
-rw-r--r--src/quicktemplates2/qquickstackview.cpp8
-rw-r--r--src/quicktemplates2/qquickstackview_p.h6
-rw-r--r--src/quicktemplates2/qquickstackview_p_p.h2
-rw-r--r--tests/auto/controls/data/tst_stackview.qml15
4 files changed, 23 insertions, 8 deletions
diff --git a/src/quicktemplates2/qquickstackview.cpp b/src/quicktemplates2/qquickstackview.cpp
index 1abc506b..6dae65c8 100644
--- a/src/quicktemplates2/qquickstackview.cpp
+++ b/src/quicktemplates2/qquickstackview.cpp
@@ -898,13 +898,13 @@ void QQuickStackView::clear(Operation operation)
\sa push()
*/
-QVariant QQuickStackView::initialItem() const
+QJSValue QQuickStackView::initialItem() const
{
Q_D(const QQuickStackView);
return d->initialItem;
}
-void QQuickStackView::setInitialItem(const QVariant &item)
+void QQuickStackView::setInitialItem(const QJSValue &item)
{
Q_D(QQuickStackView);
d->initialItem = item;
@@ -1081,9 +1081,9 @@ void QQuickStackView::componentComplete()
QQuickStackElement *element = nullptr;
QString error;
int oldDepth = d->elements.count();
- if (QObject *o = d->initialItem.value<QObject *>())
+ if (QObject *o = d->initialItem.toQObject())
element = QQuickStackElement::fromObject(o, this, &error);
- else if (d->initialItem.canConvert<QString>())
+ else if (d->initialItem.isString())
element = QQuickStackElement::fromString(d->initialItem.toString(), this, &error);
if (!error.isEmpty()) {
d->warn(error);
diff --git a/src/quicktemplates2/qquickstackview_p.h b/src/quicktemplates2/qquickstackview_p.h
index e347ba9d..ba6fe106 100644
--- a/src/quicktemplates2/qquickstackview_p.h
+++ b/src/quicktemplates2/qquickstackview_p.h
@@ -65,7 +65,7 @@ class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickStackView : public QQuickControl
Q_PROPERTY(bool busy READ isBusy NOTIFY busyChanged FINAL)
Q_PROPERTY(int depth READ depth NOTIFY depthChanged FINAL)
Q_PROPERTY(QQuickItem *currentItem READ currentItem NOTIFY currentItemChanged FINAL)
- Q_PROPERTY(QVariant initialItem READ initialItem WRITE setInitialItem FINAL)
+ Q_PROPERTY(QJSValue initialItem READ initialItem WRITE setInitialItem FINAL)
Q_PROPERTY(QQuickTransition *popEnter READ popEnter WRITE setPopEnter NOTIFY popEnterChanged FINAL)
Q_PROPERTY(QQuickTransition *popExit READ popExit WRITE setPopExit NOTIFY popExitChanged FINAL)
Q_PROPERTY(QQuickTransition *pushEnter READ pushEnter WRITE setPushEnter NOTIFY pushEnterChanged FINAL)
@@ -93,8 +93,8 @@ public:
};
Q_ENUM(Status)
- QVariant initialItem() const;
- void setInitialItem(const QVariant &item);
+ QJSValue initialItem() const;
+ void setInitialItem(const QJSValue &item);
QQuickTransition *popEnter() const;
void setPopEnter(QQuickTransition *enter);
diff --git a/src/quicktemplates2/qquickstackview_p_p.h b/src/quicktemplates2/qquickstackview_p_p.h
index d86f35cd..7f1b77b1 100644
--- a/src/quicktemplates2/qquickstackview_p_p.h
+++ b/src/quicktemplates2/qquickstackview_p_p.h
@@ -96,7 +96,7 @@ public:
bool busy;
QString operation;
- QVariant initialItem;
+ QJSValue initialItem;
QQuickItem *currentItem;
QSet<QQuickStackElement*> removing;
QList<QQuickStackElement*> removed;
diff --git a/tests/auto/controls/data/tst_stackview.qml b/tests/auto/controls/data/tst_stackview.qml
index 3c0f0273..3827354b 100644
--- a/tests/auto/controls/data/tst_stackview.qml
+++ b/tests/auto/controls/data/tst_stackview.qml
@@ -1230,4 +1230,19 @@ TestCase {
touch.release(0, control).commit()
verify(!ma.pressed)
}
+
+ // Separate function to ensure that the temporary value created to hold the return value of the Qt.createComponent()
+ // call is out of scope when the caller calls gc().
+ function stackViewFactory()
+ {
+ return createTemporaryObject(stackView, testCase, {initialItem: Qt.createComponent("TestItem.qml")})
+ }
+
+ function test_initalItemOwnership()
+ {
+ var control = stackViewFactory()
+ verify(control)
+ gc()
+ verify(control.initialItem)
+ }
}