Add attached properties to the positioners.
authorGlenn Watson <glenn.watson@nokia.com>
Tue, 16 Aug 2011 01:48:14 +0000 (11:48 +1000)
committerQt by Nokia <qt-info@nokia.com>
Wed, 17 Aug 2011 22:24:09 +0000 (00:24 +0200)
Added an attached property type to the base positioner class.
This allows items within a positioner (Row, Column, Grid, Flow) to
determine their index inside the positioner, as well as whether
they are the first or last items. Non-visible items are ignored,
as in the positioner layout objects themselves. It may be useful
to expand this in the future to contain more information specific
to the positioner, for example row/column for Grid.

Task-number: QTBUG-19211
Change-Id: I10a8c9ca5528dd12811125cae8a9b4d2e3747972
Reviewed-on: http://codereview.qt.nokia.com/2983
Reviewed-by: Qt Sanity Bot <qt_sanity_bot@ovi.com>
Reviewed-by: Alan Alpert <alan.alpert@nokia.com>
12 files changed:
doc/src/declarative/whatsnew.qdoc
examples/declarative/positioners/positioners-attachedproperties.qml [new file with mode: 0644]
src/declarative/items/qsgitemsmodule.cpp
src/declarative/items/qsgpositioners.cpp
src/declarative/items/qsgpositioners_p.h
tests/auto/declarative/qsgpositioners/data/attachedproperties-column.qml [new file with mode: 0644]
tests/auto/declarative/qsgpositioners/data/attachedproperties-dynamic.qml [new file with mode: 0644]
tests/auto/declarative/qsgpositioners/data/attachedproperties-flow.qml [new file with mode: 0644]
tests/auto/declarative/qsgpositioners/data/attachedproperties-grid.qml [new file with mode: 0644]
tests/auto/declarative/qsgpositioners/data/attachedproperties-row.qml [new file with mode: 0644]
tests/auto/declarative/qsgpositioners/data/rectangleComponent.qml [new file with mode: 0644]
tests/auto/declarative/qsgpositioners/tst_qsgpositioners.cpp

index 3707d41..9bac55e 100644 (file)
@@ -54,6 +54,9 @@ of the properties was changed.
 
 Grid now has rowSpacing and columnSpacing properties.
 
+Positioner now has an attached property that can be used to determine a subitem's location within a
+container such as Column or Row.
+
 \section2 QtQuick 1 is now a separate library and module
 
 Writing C++ applications using QtQuick 1 specific API, i.e. QDeclarativeView or QDeclarativeItem
diff --git a/examples/declarative/positioners/positioners-attachedproperties.qml b/examples/declarative/positioners/positioners-attachedproperties.qml
new file mode 100644 (file)
index 0000000..4963868
--- /dev/null
@@ -0,0 +1,66 @@
+import QtQuick 2.0
+
+Rectangle {
+  width: 400
+  height: 100
+
+  // Create row with four rectangles, the fourth one is hidden
+  Row {
+    id: row
+
+    Rectangle {
+      id: red
+      color: "red"
+      width: 100
+      height: 100
+
+      // When mouse is clicked, display the values of the positioner
+      MouseArea {
+        anchors.fill: parent
+        onClicked: row.showInfo(red.Positioner)
+      }
+    }
+
+    Rectangle {
+      id: green
+      color: "green"
+      width: 100
+      height: 100
+
+      // When mouse is clicked, display the values of the positioner
+      MouseArea {
+        anchors.fill: parent
+        onClicked: row.showInfo(green.Positioner)
+      }
+    }
+
+    Rectangle {
+      id: blue
+      color: "blue"
+      width: 100
+      height: 100
+
+      // When mouse is clicked, display the values of the positioner
+      MouseArea {
+        anchors.fill: parent
+        onClicked: row.showInfo(blue.Positioner)
+      }
+    }
+
+    // This rectangle is not visible, so it doesn't have a positioner value
+    Rectangle {
+      color: "black"
+      width: 100
+      height: 100
+      visible: false
+    }
+
+    // Print the index of the child item in the positioner and convenience
+    // properties showing if it's the first or last item.
+    function showInfo(positioner) {
+      console.log("Item Index = " + positioner.index)
+      console.log("  isFirstItem = " + positioner.isFirstItem)
+      console.log("  isLastItem = " + positioner.isLastItem)
+    }
+  }
+}
index 62a4bd0..9359906 100644 (file)
@@ -126,6 +126,7 @@ static void qt_sgitems_defineModule(const char *uri, int major, int minor)
     qmlRegisterType<QDeclarativePathPercent>(uri,major,minor,"PathPercent");
     qmlRegisterType<QDeclarativePathQuad>(uri,major,minor,"PathQuad");
     qmlRegisterType<QSGPathView>(uri,major,minor,"PathView");
+    qmlRegisterUncreatableType<QSGBasePositioner>(uri,major,minor,"Positioner","Positioner is an abstract type that is only available as an attached property.");
 #ifndef QT_NO_VALIDATOR
     qmlRegisterType<QIntValidator>(uri,major,minor,"IntValidator");
     qmlRegisterType<QDoubleValidator>(uri,major,minor,"DoubleValidator");
index d500afd..df3450e 100644 (file)
@@ -230,6 +230,7 @@ void QSGBasePositioner::prePositioning()
     }
     QSizeF contentSize(0,0);
     doPositioning(&contentSize);
+    updateAttachedProperties();
     if (!d->addActions.isEmpty() || !d->moveActions.isEmpty())
         finishApplyTransitions();
     d->doingPositioning = false;
@@ -285,6 +286,119 @@ void QSGBasePositioner::finishApplyTransitions()
     d->moveActions.clear();
 }
 
+QSGPositionerAttached *QSGBasePositioner::qmlAttachedProperties(QObject *obj)
+{
+    return new QSGPositionerAttached(obj);
+}
+
+void QSGBasePositioner::updateAttachedProperties(QSGPositionerAttached *specificProperty, QSGItem *specificPropertyOwner) const
+{
+    // If this function is deemed too expensive or shows up in profiles, it could
+    // be changed to run only when there are attached properties present. This
+    // could be a flag in the positioner that is set by the attached property
+    // constructor.
+    QSGPositionerAttached *prevLastProperty = 0;
+    QSGPositionerAttached *lastProperty = 0;
+
+    int visibleItemIndex = 0;
+    for (int ii = 0; ii < positionedItems.count(); ++ii) {
+        const PositionedItem &child = positionedItems.at(ii);
+        if (!child.item)
+            continue;
+
+        QSGPositionerAttached *property = 0;
+
+        if (specificProperty) {
+            if (specificPropertyOwner == child.item) {
+                property = specificProperty;
+            }
+        } else {
+            property = static_cast<QSGPositionerAttached *>(qmlAttachedPropertiesObject<QSGBasePositioner>(child.item, false));
+        }
+
+        if (child.isVisible) {
+            if (property) {
+              property->setIndex(visibleItemIndex);
+              property->setIsFirstItem(visibleItemIndex == 0);
+
+              if (property->isLastItem())
+                prevLastProperty = property;
+            }
+
+            lastProperty = property;
+            ++visibleItemIndex;
+        } else if (property) {
+            property->setIndex(-1);
+            property->setIsFirstItem(false);
+            property->setIsLastItem(false);
+        }
+    }
+
+    if (prevLastProperty && prevLastProperty != lastProperty)
+        prevLastProperty->setIsLastItem(false);
+    if (lastProperty)
+      lastProperty->setIsLastItem(true);
+}
+
+/*!
+    \qmlclass Positioner QSGPositionerAttached
+    \inqmlmodule QtQuick 2
+    \ingroup qml-positioning-elements
+    \brief The Positioner type provides attached properties that contain details on where an item exists in a positioner.
+
+    Positioner items (such as Column, Row, Flow and Grid) provide automatic layout
+    for child items. Attaching this property allows a child item to determine
+    where it exists within the positioner.
+*/
+
+QSGPositionerAttached::QSGPositionerAttached(QObject *parent) : QObject(parent), m_index(-1), m_isFirstItem(false), m_isLastItem(false)
+{
+    QSGItem *attachedItem = qobject_cast<QSGItem *>(parent);
+    if (attachedItem) {
+        QSGBasePositioner *positioner = qobject_cast<QSGBasePositioner *>(attachedItem->parent());
+        if (positioner) {
+            positioner->updateAttachedProperties(this, attachedItem);
+        }
+    }
+}
+
+/*!
+    \qmlattachedproperty Item QtQuick2::Positioner::index
+
+    This property allows the item to determine
+    its index within the positioner.
+*/
+void QSGPositionerAttached::setIndex(int index)
+{
+    if (m_index == index)
+        return;
+    m_index = index;
+    emit indexChanged();
+}
+
+/*!
+    \qmlattachedproperty Item QtQuick2::Positioner::isFirstItem
+    \qmlattachedproperty Item QtQuick2::Positioner::isLastItem
+
+    These properties allow the item to determine if it
+    is the first or last item in the positioner, respectively.
+*/
+void QSGPositionerAttached::setIsFirstItem(bool isFirstItem)
+{
+    if (m_isFirstItem == isFirstItem)
+        return;
+    m_isFirstItem = isFirstItem;
+    emit isFirstItemChanged();
+}
+
+void QSGPositionerAttached::setIsLastItem(bool isLastItem)
+{
+    if (m_isLastItem == isLastItem)
+        return;
+    m_isLastItem = isLastItem;
+    emit isLastItemChanged();
+}
+
 /*!
   \qmlclass Column QSGColumn
     \inqmlmodule QtQuick 2
@@ -349,7 +463,7 @@ void QSGBasePositioner::finishApplyTransitions()
 
   Items with a width or height of 0 will not be positioned.
 
-  \sa Row, Grid, Flow, {declarative/positioners}{Positioners example}
+  \sa Row, Grid, Flow, Positioner, {declarative/positioners}{Positioners example}
 */
 /*!
     \qmlproperty Transition QtQuick2::Column::add
@@ -492,7 +606,7 @@ void QSGColumn::reportConflictingAnchors()
 
   Items with a width or height of 0 will not be positioned.
 
-  \sa Column, Grid, Flow, {declarative/positioners}{Positioners example}
+  \sa Column, Grid, Flow, Positioner, {declarative/positioners}{Positioners example}
 */
 /*!
     \qmlproperty Transition QtQuick2::Row::add
@@ -722,7 +836,7 @@ void QSGRow::reportConflictingAnchors()
 
   Items with a width or height of 0 will not be positioned.
 
-  \sa Flow, Row, Column, {declarative/positioners}{Positioners example}
+  \sa Flow, Row, Column, Positioner, {declarative/positioners}{Positioners example}
 */
 /*!
     \qmlproperty Transition QtQuick2::Grid::add
@@ -1149,7 +1263,7 @@ void QSGGrid::reportConflictingAnchors()
 
   Items with a width or height of 0 will not be positioned.
 
-  \sa Column, Row, Grid, {declarative/positioners}{Positioners example}
+  \sa Column, Row, Grid, Positioner, {declarative/positioners}{Positioners example}
 */
 /*!
     \qmlproperty Transition QtQuick2::Flow::add
index 8f9d3eb..7200b6d 100644 (file)
@@ -59,6 +59,37 @@ QT_MODULE(Declarative)
 
 class QSGBasePositionerPrivate;
 
+class QSGPositionerAttached : public QObject
+{
+    Q_OBJECT
+
+public:
+    QSGPositionerAttached(QObject *parent);
+
+    Q_PROPERTY(int index READ index NOTIFY indexChanged)
+    Q_PROPERTY(bool isFirstItem READ isFirstItem NOTIFY isFirstItemChanged)
+    Q_PROPERTY(bool isLastItem READ isLastItem NOTIFY isLastItemChanged)
+
+    int index() const { return m_index; }
+    void setIndex(int index);
+
+    bool isFirstItem() const { return m_isFirstItem; }
+    void setIsFirstItem(bool isFirstItem);
+
+    bool isLastItem() const { return m_isLastItem; }
+    void setIsLastItem(bool isLastItem);
+
+Q_SIGNALS:
+    void indexChanged();
+    void isFirstItemChanged();
+    void isLastItemChanged();
+
+private:
+    int m_index;
+    bool m_isFirstItem;
+    bool m_isLastItem;
+};
+
 class Q_DECLARATIVE_PRIVATE_EXPORT QSGBasePositioner : public QSGImplicitSizeItem
 {
     Q_OBJECT
@@ -80,6 +111,10 @@ public:
     QDeclarativeTransition *add() const;
     void setAdd(QDeclarativeTransition *);
 
+    static QSGPositionerAttached *qmlAttachedProperties(QObject *obj);
+
+    void updateAttachedProperties(QSGPositionerAttached *specificProperty = 0, QSGItem *specificPropertyOwner = 0) const;
+
 protected:
     QSGBasePositioner(QSGBasePositionerPrivate &dd, PositionerType at, QSGItem *parent);
     virtual void componentComplete();
@@ -120,6 +155,7 @@ class Q_AUTOTEST_EXPORT QSGColumn : public QSGBasePositioner
     Q_OBJECT
 public:
     QSGColumn(QSGItem *parent=0);
+
 protected:
     virtual void doPositioning(QSizeF *contentSize);
     virtual void reportConflictingAnchors();
@@ -249,6 +285,9 @@ QML_DECLARE_TYPE(QSGRow)
 QML_DECLARE_TYPE(QSGGrid)
 QML_DECLARE_TYPE(QSGFlow)
 
+QML_DECLARE_TYPE(QSGBasePositioner)
+QML_DECLARE_TYPEINFO(QSGBasePositioner, QML_HAS_ATTACHED_PROPERTIES)
+
 QT_END_HEADER
 
 #endif // QSGPOSITIONERS_P_H
diff --git a/tests/auto/declarative/qsgpositioners/data/attachedproperties-column.qml b/tests/auto/declarative/qsgpositioners/data/attachedproperties-column.qml
new file mode 100644 (file)
index 0000000..4c667aa
--- /dev/null
@@ -0,0 +1,50 @@
+import QtQuick 2.0
+
+Rectangle {
+  width: 100
+  height: 200
+
+  Column {
+
+    Rectangle {
+      width: 100
+      height: 100
+      color: 'red'
+      visible: false
+    }
+
+    Rectangle {
+      objectName: "greenRect"
+      width: 100
+      height: 100
+      color: 'green'
+      property int posIndex: Positioner.index
+      property bool isFirstItem: Positioner.isFirstItem
+      property bool isLastItem: Positioner.isLastItem
+    }
+
+    Rectangle {
+      width: 100
+      height: 100
+      color: 'blue'
+      visible: false
+    }
+
+    Rectangle {
+      objectName: "yellowRect"
+      width: 100
+      height: 100
+      color: 'yellow'
+
+      property int posIndex: -1
+      property bool isFirstItem: false
+      property bool isLastItem: false
+
+      function onDemandPositioner() {
+        posIndex = Positioner.index;
+        isFirstItem = Positioner.isFirstItem
+        isLastItem = Positioner.isLastItem
+      }
+    }
+  }
+}
diff --git a/tests/auto/declarative/qsgpositioners/data/attachedproperties-dynamic.qml b/tests/auto/declarative/qsgpositioners/data/attachedproperties-dynamic.qml
new file mode 100644 (file)
index 0000000..894749d
--- /dev/null
@@ -0,0 +1,44 @@
+import QtQuick 2.0
+
+Rectangle
+{
+  width: 300
+  height: 100
+
+  Row {
+    id: pos
+    objectName: "pos"
+    anchors.fill: parent
+
+    Rectangle {
+      objectName: "rect0"
+      width: 100
+      height: 100
+      color: 'red'
+      property int index: Positioner.index
+      property bool firstItem: Positioner.isFirstItem
+      property bool lastItem: Positioner.isLastItem
+    }
+
+    Rectangle {
+      objectName: "rect1"
+      width: 100
+      height: 100
+      color: 'green'
+      property int index: Positioner.index
+      property bool firstItem: Positioner.isFirstItem
+      property bool lastItem: Positioner.isLastItem
+    }
+
+    property QtObject subRect;
+
+    function createSubRect() {
+      var component = Qt.createComponent("rectangleComponent.qml");
+      subRect = component.createObject(pos, {});
+    }
+
+    function destroySubRect() {
+      subRect.destroy();
+    }
+  }
+}
diff --git a/tests/auto/declarative/qsgpositioners/data/attachedproperties-flow.qml b/tests/auto/declarative/qsgpositioners/data/attachedproperties-flow.qml
new file mode 100644 (file)
index 0000000..e7f9a63
--- /dev/null
@@ -0,0 +1,50 @@
+import QtQuick 2.0
+
+Rectangle {
+  width: 200
+  height: 100
+
+  Flow {
+
+    Rectangle {
+      width: 100
+      height: 100
+      color: 'red'
+      visible: false
+    }
+
+    Rectangle {
+      objectName: "greenRect"
+      width: 100
+      height: 100
+      color: 'green'
+      property int posIndex: Positioner.index
+      property bool isFirstItem: Positioner.isFirstItem
+      property bool isLastItem: Positioner.isLastItem
+    }
+
+    Rectangle {
+      width: 100
+      height: 100
+      color: 'blue'
+      visible: false
+    }
+
+    Rectangle {
+      objectName: "yellowRect"
+      width: 100
+      height: 100
+      color: 'yellow'
+
+      property int posIndex: -1
+      property bool isFirstItem: false
+      property bool isLastItem: false
+
+      function onDemandPositioner() {
+        posIndex = Positioner.index;
+        isFirstItem = Positioner.isFirstItem
+        isLastItem = Positioner.isLastItem
+      }
+    }
+  }
+}
diff --git a/tests/auto/declarative/qsgpositioners/data/attachedproperties-grid.qml b/tests/auto/declarative/qsgpositioners/data/attachedproperties-grid.qml
new file mode 100644 (file)
index 0000000..2094309
--- /dev/null
@@ -0,0 +1,50 @@
+import QtQuick 2.0
+
+Rectangle {
+  width: 200
+  height: 100
+
+  Grid {
+
+    Rectangle {
+      width: 100
+      height: 100
+      color: 'red'
+      visible: false
+    }
+
+    Rectangle {
+      objectName: "greenRect"
+      width: 100
+      height: 100
+      color: 'green'
+      property int posIndex: Positioner.index
+      property bool isFirstItem: Positioner.isFirstItem
+      property bool isLastItem: Positioner.isLastItem
+    }
+
+    Rectangle {
+      width: 100
+      height: 100
+      color: 'blue'
+      visible: false
+    }
+
+    Rectangle {
+      objectName: "yellowRect"
+      width: 100
+      height: 100
+      color: 'yellow'
+
+      property int posIndex: -1
+      property bool isFirstItem: false
+      property bool isLastItem: false
+
+      function onDemandPositioner() {
+        posIndex = Positioner.index;
+        isFirstItem = Positioner.isFirstItem
+        isLastItem = Positioner.isLastItem
+      }
+    }
+  }
+}
diff --git a/tests/auto/declarative/qsgpositioners/data/attachedproperties-row.qml b/tests/auto/declarative/qsgpositioners/data/attachedproperties-row.qml
new file mode 100644 (file)
index 0000000..212a26b
--- /dev/null
@@ -0,0 +1,50 @@
+import QtQuick 2.0
+
+Rectangle {
+  width: 200
+  height: 100
+
+  Row {
+
+    Rectangle {
+      width: 100
+      height: 100
+      color: 'red'
+      visible: false
+    }
+
+    Rectangle {
+      objectName: "greenRect"
+      width: 100
+      height: 100
+      color: 'green'
+      property int posIndex: Positioner.index
+      property bool isFirstItem: Positioner.isFirstItem
+      property bool isLastItem: Positioner.isLastItem
+    }
+
+    Rectangle {
+      width: 100
+      height: 100
+      color: 'blue'
+      visible: false
+    }
+
+    Rectangle {
+      objectName: "yellowRect"
+      width: 100
+      height: 100
+      color: 'yellow'
+
+      property int posIndex: -1
+      property bool isFirstItem: false
+      property bool isLastItem: false
+
+      function onDemandPositioner() {
+        posIndex = Positioner.index;
+        isFirstItem = Positioner.isFirstItem
+        isLastItem = Positioner.isLastItem
+      }
+    }
+  }
+}
diff --git a/tests/auto/declarative/qsgpositioners/data/rectangleComponent.qml b/tests/auto/declarative/qsgpositioners/data/rectangleComponent.qml
new file mode 100644 (file)
index 0000000..de1bb99
--- /dev/null
@@ -0,0 +1,11 @@
+import QtQuick 2.0;
+
+Rectangle {
+  objectName: "rect2"
+  color: "blue"
+  width: 100
+  height: 100
+  property int index: Positioner.index
+  property bool firstItem: Positioner.isFirstItem
+  property bool lastItem: Positioner.isLastItem
+}
index 497f511..137e6ac 100644 (file)
@@ -91,6 +91,10 @@ private slots:
     void test_conflictinganchors();
     void test_mirroring();
     void test_allInvisible();
+    void test_attachedproperties();
+    void test_attachedproperties_data();
+    void test_attachedproperties_dynamic();
+
 private:
     QSGView *createView(const QString &filename);
 };
@@ -1345,6 +1349,116 @@ void tst_qsgpositioners::test_allInvisible()
     QVERIFY(column->height() == 0);
 }
 
+void tst_qsgpositioners::test_attachedproperties()
+{
+    QFETCH(QString, filename);
+
+    QSGView *canvas = createView(filename);
+    QVERIFY(canvas->rootObject() != 0);
+
+    QSGRectangle *greenRect = canvas->rootObject()->findChild<QSGRectangle *>("greenRect");
+    QVERIFY(greenRect != 0);
+
+    int posIndex = greenRect->property("posIndex").toInt();
+    QVERIFY(posIndex == 0);
+    bool isFirst = greenRect->property("isFirstItem").toBool();
+    QVERIFY(isFirst == true);
+    bool isLast = greenRect->property("isLastItem").toBool();
+    QVERIFY(isLast == false);
+
+    QSGRectangle *yellowRect = canvas->rootObject()->findChild<QSGRectangle *>("yellowRect");
+    QVERIFY(yellowRect != 0);
+
+    posIndex = yellowRect->property("posIndex").toInt();
+    QVERIFY(posIndex == -1);
+    isFirst = yellowRect->property("isFirstItem").toBool();
+    QVERIFY(isFirst == false);
+    isLast = yellowRect->property("isLastItem").toBool();
+    QVERIFY(isLast == false);
+
+    yellowRect->metaObject()->invokeMethod(yellowRect, "onDemandPositioner");
+
+    posIndex = yellowRect->property("posIndex").toInt();
+    QVERIFY(posIndex == 1);
+    isFirst = yellowRect->property("isFirstItem").toBool();
+    QVERIFY(isFirst == false);
+    isLast = yellowRect->property("isLastItem").toBool();
+    QVERIFY(isLast == true);
+
+    delete canvas;
+}
+
+void tst_qsgpositioners::test_attachedproperties_data()
+{
+    QTest::addColumn<QString>("filename");
+
+    QTest::newRow("column") << SRCDIR "/data/attachedproperties-column.qml";
+    QTest::newRow("row") << SRCDIR "/data/attachedproperties-row.qml";
+    QTest::newRow("grid") << SRCDIR "/data/attachedproperties-grid.qml";
+    QTest::newRow("flow") << SRCDIR "/data/attachedproperties-flow.qml";
+}
+
+void tst_qsgpositioners::test_attachedproperties_dynamic()
+{
+    QSGView *canvas = createView(SRCDIR "/data/attachedproperties-dynamic.qml");
+    QVERIFY(canvas->rootObject() != 0);
+
+    QSGRow *row = canvas->rootObject()->findChild<QSGRow *>("pos");
+    QVERIFY(row != 0);
+
+    QSGRectangle *rect0 = canvas->rootObject()->findChild<QSGRectangle *>("rect0");
+    QVERIFY(rect0 != 0);
+
+    int posIndex = rect0->property("index").toInt();
+    QVERIFY(posIndex == 0);
+    bool isFirst = rect0->property("firstItem").toBool();
+    QVERIFY(isFirst == true);
+    bool isLast = rect0->property("lastItem").toBool();
+    QVERIFY(isLast == false);
+
+    QSGRectangle *rect1 = canvas->rootObject()->findChild<QSGRectangle *>("rect1");
+    QVERIFY(rect1 != 0);
+
+    posIndex = rect1->property("index").toInt();
+    QVERIFY(posIndex == 1);
+    isFirst = rect1->property("firstItem").toBool();
+    QVERIFY(isFirst == false);
+    isLast = rect1->property("lastItem").toBool();
+    QVERIFY(isLast == true);
+
+    row->metaObject()->invokeMethod(row, "createSubRect");
+
+    posIndex = rect1->property("index").toInt();
+    QVERIFY(posIndex == 1);
+    isFirst = rect1->property("firstItem").toBool();
+    QVERIFY(isFirst == false);
+    isLast = rect1->property("lastItem").toBool();
+    QVERIFY(isLast == false);
+
+    QSGRectangle *rect2 = canvas->rootObject()->findChild<QSGRectangle *>("rect2");
+    QVERIFY(rect2 != 0);
+
+    posIndex = rect2->property("index").toInt();
+    QVERIFY(posIndex == 2);
+    isFirst = rect2->property("firstItem").toBool();
+    QVERIFY(isFirst == false);
+    isLast = rect2->property("lastItem").toBool();
+    QVERIFY(isLast == true);
+
+    row->metaObject()->invokeMethod(row, "destroySubRect");
+
+    qApp->processEvents(QEventLoop::DeferredDeletion);
+
+    posIndex = rect1->property("index").toInt();
+    QVERIFY(posIndex == 1);
+    isFirst = rect1->property("firstItem").toBool();
+    QVERIFY(isFirst == false);
+    isLast = rect1->property("lastItem").toBool();
+    QVERIFY(isLast == true);
+
+    delete canvas;
+}
+
 QSGView *tst_qsgpositioners::createView(const QString &filename)
 {
     QSGView *canvas = new QSGView(0);