aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJ-P Nurmi <jpnurmi@theqtcompany.com>2015-06-12 00:17:35 +0200
committerJ-P Nurmi <jpnurmi@theqtcompany.com>2015-06-15 08:21:37 +0000
commit73f931a771e3576a9dd1daf6d13a6ef11eeee5a9 (patch)
treea05ff94f1e6be0b886b84842ac2b5e2ef2357beb
parentc4f50fa96d22f1cecbe5abef6ebc5b6d55d3dfbf (diff)
TabBar: implement contentData & contentChildren
Change-Id: I61d077758c83027cbfc1b99d32cb68efc0829ffd Reviewed-by: J-P Nurmi <jpnurmi@theqtcompany.com>
-rw-r--r--src/controls/qquicktabbar.cpp260
-rw-r--r--src/controls/qquicktabbar_p.h12
-rw-r--r--src/imports/controls/TabBar.qml2
-rw-r--r--tests/auto/controls/data/tst_tabbar.qml420
4 files changed, 659 insertions, 35 deletions
diff --git a/src/controls/qquicktabbar.cpp b/src/controls/qquicktabbar.cpp
index 74766d1b..7e240726 100644
--- a/src/controls/qquicktabbar.cpp
+++ b/src/controls/qquicktabbar.cpp
@@ -39,6 +39,7 @@
#include "qquickexclusivegroup_p.h"
#include <QtQuick/private/qquickitem_p.h>
+#include <QtQuick/private/qquickitemchangelistener_p.h>
#include <QtQml/private/qqmlobjectmodel_p.h>
QT_BEGIN_NAMESPACE
@@ -54,33 +55,47 @@ QT_BEGIN_NAMESPACE
TODO
*/
-class QQuickTabBarPrivate : public QQuickContainerPrivate
+class QQuickTabBarPrivate : public QQuickContainerPrivate, public QQuickItemChangeListener
{
Q_DECLARE_PUBLIC(QQuickTabBar)
public:
- QQuickTabBarPrivate() : currentIndex(0), model(Q_NULLPTR), group(Q_NULLPTR) { }
+ QQuickTabBarPrivate() : currentIndex(0), contentModel(Q_NULLPTR), group(Q_NULLPTR) { }
void updateLayout();
void updateCurrent();
- // TODO: implement the whole list property
+ void itemChildAdded(QQuickItem *item, QQuickItem *child) Q_DECL_OVERRIDE;
+ void itemSiblingOrderChanged(QQuickItem *item) Q_DECL_OVERRIDE;
+ void itemParentChanged(QQuickItem *item, QQuickItem *parent) Q_DECL_OVERRIDE;
+ void itemDestroyed(QQuickItem *item) Q_DECL_OVERRIDE;
+
static void contentData_append(QQmlListProperty<QObject> *prop, QObject *obj);
+ static int contentData_count(QQmlListProperty<QObject> *prop);
+ static QObject *contentData_at(QQmlListProperty<QObject> *prop, int index);
+ static void contentData_clear(QQmlListProperty<QObject> *prop);
+
+ static void contentChildren_append(QQmlListProperty<QQuickItem> *prop, QQuickItem *obj);
+ static int contentChildren_count(QQmlListProperty<QQuickItem> *prop);
+ static QQuickItem *contentChildren_at(QQmlListProperty<QQuickItem> *prop, int index);
+ static void contentChildren_clear(QQmlListProperty<QQuickItem> *prop);
int currentIndex;
- QQmlObjectModel *model;
+ QObjectList contentData;
+ QQmlObjectModel *contentModel;
QQuickExclusiveGroup *group;
};
void QQuickTabBarPrivate::updateLayout()
{
- const int count = model->count();
+ Q_Q(QQuickTabBar);
+ const int count = contentModel->count();
if (count > 0 && contentItem) {
const qreal spacing = contentItem->property("spacing").toReal();
const qreal itemWidth = (contentItem->width() - qMax(0, count - 1) * spacing) / count;
for (int i = 0; i < count; ++i) {
- QQuickItem *item = qobject_cast<QQuickItem *>(model->get(i));
+ QQuickItem *item = q->itemAt(i);
if (item) {
QQuickItemPrivate *p = QQuickItemPrivate::get(item);
if (!p->widthValid) {
@@ -95,17 +110,102 @@ void QQuickTabBarPrivate::updateLayout()
void QQuickTabBarPrivate::updateCurrent()
{
Q_Q(QQuickTabBar);
- q->setCurrentIndex(model->indexOf(group->current(), Q_NULLPTR));
+ q->setCurrentIndex(contentModel->indexOf(group->current(), Q_NULLPTR));
+}
+
+void QQuickTabBarPrivate::itemChildAdded(QQuickItem *, QQuickItem *child)
+{
+ // add dynamically reparented items (eg. by a Repeater)
+ Q_Q(QQuickTabBar);
+ if (!QQuickItemPrivate::get(child)->isTransparentForPositioner() && contentModel->indexOf(child, Q_NULLPTR) == -1)
+ q->addItem(child);
+}
+
+void QQuickTabBarPrivate::itemParentChanged(QQuickItem *item, QQuickItem *parent)
+{
+ // remove dynamically unparented items (eg. by a Repeater)
+ Q_Q(QQuickTabBar);
+ if (!parent)
+ q->removeItem(contentModel->indexOf(item, Q_NULLPTR));
+}
+
+void QQuickTabBarPrivate::itemSiblingOrderChanged(QQuickItem *)
+{
+ // reorder the restacked items (eg. by a Repeater)
+ Q_Q(QQuickTabBar);
+ QList<QQuickItem *> siblings = contentItem->childItems();
+ for (int i = 0; i < siblings.count(); ++i) {
+ QQuickItem* sibling = siblings.at(i);
+ int index = contentModel->indexOf(sibling, Q_NULLPTR);
+ q->moveItem(index, i);
+ }
+}
+
+void QQuickTabBarPrivate::itemDestroyed(QQuickItem *item)
+{
+ Q_Q(QQuickTabBar);
+ int index = contentModel->indexOf(item, Q_NULLPTR);
+ if (index != -1)
+ q->removeItem(index);
}
void QQuickTabBarPrivate::contentData_append(QQmlListProperty<QObject> *prop, QObject *obj)
{
+ QQuickTabBarPrivate *p = static_cast<QQuickTabBarPrivate *>(prop->data);
QQuickTabBar *bar = static_cast<QQuickTabBar *>(prop->object);
QQuickItem *item = qobject_cast<QQuickItem *>(obj);
- if (item)
- bar->addItem(item);
- else
- QQuickItemPrivate::data_append(prop, obj);
+ if (item) {
+ if (QQuickItemPrivate::get(item)->isTransparentForPositioner()) {
+ QQuickItemPrivate::get(item)->addItemChangeListener(p, QQuickItemPrivate::SiblingOrder);
+ item->setParentItem(p->contentItem);
+ } else if (p->contentModel->indexOf(item, Q_NULLPTR) == -1) {
+ bar->addItem(item);
+ }
+ } else {
+ p->contentData.append(obj);
+ }
+}
+
+int QQuickTabBarPrivate::contentData_count(QQmlListProperty<QObject> *prop)
+{
+ QQuickTabBarPrivate *p = static_cast<QQuickTabBarPrivate *>(prop->data);
+ return p->contentData.count();
+}
+
+QObject *QQuickTabBarPrivate::contentData_at(QQmlListProperty<QObject> *prop, int index)
+{
+ QQuickTabBarPrivate *p = static_cast<QQuickTabBarPrivate *>(prop->data);
+ return p->contentData.value(index);
+}
+
+void QQuickTabBarPrivate::contentData_clear(QQmlListProperty<QObject> *prop)
+{
+ QQuickTabBarPrivate *p = static_cast<QQuickTabBarPrivate *>(prop->data);
+ p->contentData.clear();
+}
+
+void QQuickTabBarPrivate::contentChildren_append(QQmlListProperty<QQuickItem> *prop, QQuickItem *item)
+{
+ QQuickTabBar *bar = static_cast<QQuickTabBar *>(prop->object);
+ bar->addItem(item);
+}
+
+int QQuickTabBarPrivate::contentChildren_count(QQmlListProperty<QQuickItem> *prop)
+{
+ QQuickTabBarPrivate *p = static_cast<QQuickTabBarPrivate *>(prop->data);
+ return p->contentModel->count();
+}
+
+QQuickItem *QQuickTabBarPrivate::contentChildren_at(QQmlListProperty<QQuickItem> *prop, int index)
+{
+ QQuickTabBar *bar = static_cast<QQuickTabBar *>(prop->object);
+ return bar->itemAt(index);
+}
+
+void QQuickTabBarPrivate::contentChildren_clear(QQmlListProperty<QQuickItem> *prop)
+{
+ QQuickTabBarPrivate *p = static_cast<QQuickTabBarPrivate *>(prop->data);
+ p->contentModel->clear();
}
QQuickTabBar::QQuickTabBar(QQuickItem *parent) :
@@ -115,15 +215,26 @@ QQuickTabBar::QQuickTabBar(QQuickItem *parent) :
setFlag(ItemIsFocusScope);
setActiveFocusOnTab(true);
- d->model = new QQmlObjectModel(this);
- connect(d->model, &QQmlObjectModel::countChanged, this, &QQuickTabBar::countChanged);
- QObjectPrivate::connect(d->model, &QQmlObjectModel::countChanged, d, &QQuickTabBarPrivate::updateLayout);
+ d->contentModel = new QQmlObjectModel(this);
+ connect(d->contentModel, &QQmlObjectModel::countChanged, this, &QQuickTabBar::countChanged);
+ connect(d->contentModel, &QQmlObjectModel::modelUpdated, this, &QQuickTabBar::polish);
d->group = new QQuickExclusiveGroup(this);
connect(d->group, &QQuickExclusiveGroup::currentChanged, this, &QQuickTabBar::currentItemChanged);
QObjectPrivate::connect(d->group, &QQuickExclusiveGroup::currentChanged, d, &QQuickTabBarPrivate::updateCurrent);
}
+QQuickTabBar::~QQuickTabBar()
+{
+ Q_D(QQuickTabBar);
+ const int count = d->contentModel->count();
+ for (int i = 0; i < count; ++i) {
+ QQuickItem *item = itemAt(i);
+ if (item)
+ QQuickItemPrivate::get(item)->removeItemChangeListener(d, QQuickItemPrivate::Destroyed | QQuickItemPrivate::Parent);
+ }
+}
+
/*!
\qmlproperty int QtQuickControls2::TabBar::count
\readonly
@@ -133,7 +244,7 @@ QQuickTabBar::QQuickTabBar(QQuickItem *parent) :
int QQuickTabBar::count() const
{
Q_D(const QQuickTabBar);
- return d->model->count();
+ return d->contentModel->count();
}
/*!
@@ -153,6 +264,8 @@ void QQuickTabBar::setCurrentIndex(int index)
if (d->currentIndex != index) {
d->currentIndex = index;
emit currentIndexChanged();
+ if (isComponentComplete())
+ d->group->setCurrent(d->contentModel->get(index));
}
}
@@ -168,26 +281,35 @@ QQuickItem *QQuickTabBar::currentItem() const
}
/*!
- \qmlproperty model QtQuickControls2::TabBar::model
+ \qmlproperty model QtQuickControls2::TabBar::contentModel
\readonly
TODO
*/
-QVariant QQuickTabBar::model() const
+QVariant QQuickTabBar::contentModel() const
{
Q_D(const QQuickTabBar);
- return QVariant::fromValue(d->model);
+ return QVariant::fromValue(d->contentModel);
}
QQmlListProperty<QObject> QQuickTabBar::contentData()
{
Q_D(QQuickTabBar);
- // TODO: implement the whole list property
return QQmlListProperty<QObject>(this, d,
QQuickTabBarPrivate::contentData_append,
- QQuickItemPrivate::data_count,
- QQuickItemPrivate::data_at,
- QQuickItemPrivate::data_clear);
+ QQuickTabBarPrivate::contentData_count,
+ QQuickTabBarPrivate::contentData_at,
+ QQuickTabBarPrivate::contentData_clear);
+}
+
+QQmlListProperty<QQuickItem> QQuickTabBar::contentChildren()
+{
+ Q_D(QQuickTabBar);
+ return QQmlListProperty<QQuickItem>(this, d,
+ QQuickTabBarPrivate::contentChildren_append,
+ QQuickTabBarPrivate::contentChildren_count,
+ QQuickTabBarPrivate::contentChildren_at,
+ QQuickTabBarPrivate::contentChildren_clear);
}
/*!
@@ -198,7 +320,7 @@ QQmlListProperty<QObject> QQuickTabBar::contentData()
QQuickItem *QQuickTabBar::itemAt(int index) const
{
Q_D(const QQuickTabBar);
- return qobject_cast<QQuickItem *>(d->model->get(index));
+ return qobject_cast<QQuickItem *>(d->contentModel->get(index));
}
/*!
@@ -209,7 +331,7 @@ QQuickItem *QQuickTabBar::itemAt(int index) const
void QQuickTabBar::addItem(QQuickItem *item)
{
Q_D(QQuickTabBar);
- insertItem(d->model->count(), item);
+ insertItem(d->contentModel->count(), item);
}
/*!
@@ -220,10 +342,29 @@ void QQuickTabBar::addItem(QQuickItem *item)
void QQuickTabBar::insertItem(int index, QQuickItem *item)
{
Q_D(QQuickTabBar);
- d->model->insert(index, item);
- d->group->addCheckable(item);
- if (d->currentIndex == index)
- d->group->setCurrent(item);
+ if (!item)
+ return;
+ const int count = d->contentModel->count();
+ if (index < 0 || index > count)
+ index = count;
+
+ int oldIndex = d->contentModel->indexOf(item, Q_NULLPTR);
+ if (oldIndex != -1) {
+ if (oldIndex < index)
+ --index;
+ if (oldIndex != index)
+ moveItem(oldIndex, index);
+ } else {
+ QQuickItemPrivate::get(item)->addItemChangeListener(d, QQuickItemPrivate::Destroyed | QQuickItemPrivate::Parent);
+ d->contentData.append(item);
+ d->contentModel->insert(index, item);
+ d->group->addCheckable(item);
+
+ if (count == 0 || d->currentIndex == index)
+ d->group->setCurrent(item);
+ else
+ d->updateCurrent();
+ }
}
/*!
@@ -234,7 +375,16 @@ void QQuickTabBar::insertItem(int index, QQuickItem *item)
void QQuickTabBar::moveItem(int from, int to)
{
Q_D(QQuickTabBar);
- d->model->move(from, to);
+ const int count = d->contentModel->count();
+ if (from < 0 || from > count - 1)
+ return;
+ if (to < 0 || to > count - 1)
+ to = count - 1;
+
+ if (from != to) {
+ d->contentModel->move(from, to);
+ d->updateCurrent();
+ }
}
/*!
@@ -245,8 +395,35 @@ void QQuickTabBar::moveItem(int from, int to)
void QQuickTabBar::removeItem(int index)
{
Q_D(QQuickTabBar);
- d->group->removeCheckable(d->model->get(index));
- d->model->remove(index);
+ const int count = d->contentModel->count();
+ if (index < 0 || index >= count)
+ return;
+
+ QQuickItem *item = itemAt(index);
+ if (item) {
+ bool currentChanged = false;
+ if (index == d->currentIndex) {
+ d->group->setCurrent(d->contentModel->get(index - 1));
+ } else if (index < d->currentIndex) {
+ --d->currentIndex;
+ currentChanged = true;
+ }
+
+ QQuickItemPrivate::get(item)->removeItemChangeListener(d, QQuickItemPrivate::Destroyed | QQuickItemPrivate::Parent);
+ d->group->removeCheckable(item);
+ d->contentData.removeOne(item);
+ d->contentModel->remove(index);
+
+ if (currentChanged)
+ emit currentIndexChanged();
+ }
+}
+
+void QQuickTabBar::updatePolish()
+{
+ Q_D(QQuickTabBar);
+ QQuickContainer::updatePolish();
+ d->updateLayout();
}
void QQuickTabBar::componentComplete()
@@ -254,6 +431,27 @@ void QQuickTabBar::componentComplete()
Q_D(QQuickTabBar);
QQuickContainer::componentComplete();
d->updateCurrent();
+ d->updateLayout();
+}
+
+void QQuickTabBar::itemChange(ItemChange change, const ItemChangeData &data)
+{
+ Q_D(QQuickTabBar);
+ QQuickContainer::itemChange(change, data);
+ if (change == QQuickItem::ItemChildAddedChange && isComponentComplete() && data.item != d->background && data.item != d->contentItem) {
+ if (!QQuickItemPrivate::get(data.item)->isTransparentForPositioner() && d->contentModel->indexOf(data.item, Q_NULLPTR) == -1)
+ addItem(data.item);
+ }
+}
+
+void QQuickTabBar::contentItemChange(QQuickItem *newItem, QQuickItem *oldItem)
+{
+ Q_D(QQuickTabBar);
+ QQuickContainer::contentItemChange(newItem, oldItem);
+ if (oldItem)
+ QQuickItemPrivate::get(oldItem)->removeItemChangeListener(d, QQuickItemPrivate::Children);
+ if (newItem)
+ QQuickItemPrivate::get(newItem)->addItemChangeListener(d, QQuickItemPrivate::Children);
}
void QQuickTabBar::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
diff --git a/src/controls/qquicktabbar_p.h b/src/controls/qquicktabbar_p.h
index 7d43e24e..ac6e29cf 100644
--- a/src/controls/qquicktabbar_p.h
+++ b/src/controls/qquicktabbar_p.h
@@ -61,19 +61,22 @@ class Q_QUICKCONTROLS_EXPORT QQuickTabBar : public QQuickContainer
Q_PROPERTY(int count READ count NOTIFY countChanged FINAL)
Q_PROPERTY(int currentIndex READ currentIndex WRITE setCurrentIndex NOTIFY currentIndexChanged FINAL)
Q_PROPERTY(QQuickItem *currentItem READ currentItem NOTIFY currentItemChanged FINAL)
- Q_PROPERTY(QVariant model READ model CONSTANT FINAL)
- Q_PROPERTY(QQmlListProperty<QObject> contentData READ contentData)
+ Q_PROPERTY(QVariant contentModel READ contentModel CONSTANT FINAL)
+ Q_PROPERTY(QQmlListProperty<QObject> contentData READ contentData FINAL)
+ Q_PROPERTY(QQmlListProperty<QQuickItem> contentChildren READ contentChildren FINAL)
Q_CLASSINFO("DefaultProperty", "contentData")
public:
explicit QQuickTabBar(QQuickItem *parent = Q_NULLPTR);
+ ~QQuickTabBar();
int count() const;
int currentIndex() const;
QQuickItem *currentItem() const;
- QVariant model() const;
+ QVariant contentModel() const;
QQmlListProperty<QObject> contentData();
+ QQmlListProperty<QQuickItem> contentChildren();
Q_INVOKABLE QQuickItem *itemAt(int index) const;
Q_INVOKABLE void addItem(QQuickItem *item);
@@ -90,7 +93,10 @@ Q_SIGNALS:
void currentItemChanged();
protected:
+ void updatePolish() Q_DECL_OVERRIDE;
void componentComplete() Q_DECL_OVERRIDE;
+ void itemChange(ItemChange change, const ItemChangeData &data) Q_DECL_OVERRIDE;
+ void contentItemChange(QQuickItem *newItem, QQuickItem *oldItem) Q_DECL_OVERRIDE;
void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) Q_DECL_OVERRIDE;
private:
diff --git a/src/imports/controls/TabBar.qml b/src/imports/controls/TabBar.qml
index 6d4f11c9..3b0f7bfd 100644
--- a/src/imports/controls/TabBar.qml
+++ b/src/imports/controls/TabBar.qml
@@ -57,7 +57,7 @@ AbstractTabBar {
boundsBehavior: Flickable.StopAtBounds
snapMode: ListView.SnapToItem
- model: control.model
+ model: control.contentModel
currentIndex: control.currentIndex
highlightMoveDuration: 250
diff --git a/tests/auto/controls/data/tst_tabbar.qml b/tests/auto/controls/data/tst_tabbar.qml
new file mode 100644
index 00000000..1383431c
--- /dev/null
+++ b/tests/auto/controls/data/tst_tabbar.qml
@@ -0,0 +1,420 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.2
+import QtTest 1.0
+import QtQuick.Controls 2.0
+
+TestCase {
+ id: testCase
+ width: 200
+ height: 200
+ visible: true
+ when: windowShown
+ name: "TabBar"
+
+ Component {
+ id: tabButton
+ TabButton { }
+ }
+
+ Component {
+ id: tabBar
+ TabBar { }
+ }
+
+ function test_defaults() {
+ var control = tabBar.createObject(testCase)
+ verify(control)
+ compare(control.count, 0)
+ compare(control.currentIndex, -1)
+ compare(control.currentItem, null)
+ control.destroy()
+ }
+
+ function test_current() {
+ var control = tabBar.createObject(testCase)
+
+ compare(control.count, 0)
+ compare(control.currentIndex, -1)
+ compare(control.currentItem, null)
+
+ control.addItem(tabButton.createObject(control, {text: "0"}))
+ compare(control.count, 1)
+ compare(control.currentIndex, 0)
+ compare(control.currentItem.text, "0")
+
+ control.addItem(tabButton.createObject(control, {text: "1"}))
+ compare(control.count, 2)
+ compare(control.currentIndex, 0)
+ compare(control.currentItem.text, "0")
+
+ control.addItem(tabButton.createObject(control, {text: "2"}))
+ compare(control.count, 3)
+ compare(control.currentIndex, 0)
+ compare(control.currentItem.text, "0")
+
+ control.currentIndex = 1
+ compare(control.currentIndex, 1)
+ compare(control.currentItem.text, "1")
+
+ control.currentIndex = 2
+ compare(control.currentIndex, 2)
+ compare(control.currentItem.text, "2")
+
+ control.destroy()
+ }
+
+ function test_addRemove() {
+ var control = tabBar.createObject(testCase)
+
+ function verifyCurrentIndexCountDiff() {
+ verify(control.currentIndex < control.count)
+ }
+ control.currentIndexChanged.connect(verifyCurrentIndexCountDiff)
+ control.countChanged.connect(verifyCurrentIndexCountDiff)
+
+ compare(control.count, 0)
+ compare(control.currentIndex, -1)
+ control.addItem(tabButton.createObject(control, {text: "1"}))
+ compare(control.count, 1)
+ compare(control.currentIndex, 0)
+ compare(control.currentItem.text, "1")
+ control.addItem(tabButton.createObject(control, {text: "2"}))
+ compare(control.count, 2)
+ compare(control.currentIndex, 0)
+ compare(control.currentItem.text, "1")
+ compare(control.itemAt(0).text, "1")
+ compare(control.itemAt(1).text, "2")
+
+ control.currentIndex = 1
+
+ control.insertItem(1, tabButton.createObject(control, {text: "3"}))
+ compare(control.count, 3)
+ compare(control.currentIndex, 2)
+ compare(control.currentItem.text, "2")
+ compare(control.itemAt(0).text, "1")
+ compare(control.itemAt(1).text, "3")
+ compare(control.itemAt(2).text, "2")
+
+ control.insertItem(0, tabButton.createObject(control, {text: "4"}))
+ compare(control.count, 4)
+ compare(control.currentIndex, 3)
+ compare(control.currentItem.text, "2")
+ compare(control.itemAt(0).text, "4")
+ compare(control.itemAt(1).text, "1")
+ compare(control.itemAt(2).text, "3")
+ compare(control.itemAt(3).text, "2")
+
+ control.insertItem(control.count, tabButton.createObject(control, {text: "5"}))
+ compare(control.count, 5)
+ compare(control.currentIndex, 3)
+ compare(control.currentItem.text, "2")
+ compare(control.itemAt(0).text, "4")
+ compare(control.itemAt(1).text, "1")
+ compare(control.itemAt(2).text, "3")
+ compare(control.itemAt(3).text, "2")
+ compare(control.itemAt(4).text, "5")
+
+ control.removeItem(control.count - 1)
+ compare(control.count, 4)
+ compare(control.currentIndex, 3)
+ compare(control.currentItem.text, "2")
+ compare(control.itemAt(0).text, "4")
+ compare(control.itemAt(1).text, "1")
+ compare(control.itemAt(2).text, "3")
+ compare(control.itemAt(3).text, "2")
+
+ control.removeItem(0)
+ compare(control.count, 3)
+ compare(control.currentIndex, 2)
+ compare(control.currentItem.text, "2")
+ compare(control.itemAt(0).text, "1")
+ compare(control.itemAt(1).text, "3")
+ compare(control.itemAt(2).text, "2")
+
+ control.removeItem(1)
+ compare(control.count, 2)
+ compare(control.currentIndex, 1)
+ compare(control.currentItem.text, "2")
+ compare(control.itemAt(0).text, "1")
+ compare(control.itemAt(1).text, "2")
+
+ control.removeItem(1)
+ compare(control.count, 1)
+ compare(control.currentIndex, 0)
+ compare(control.currentItem.text, "1")
+ compare(control.itemAt(0).text, "1")
+
+ control.removeItem(0)
+ compare(control.count, 0)
+ compare(control.currentIndex, -1)
+
+ control.destroy()
+ }
+
+ Component {
+ id: contentBar
+ TabBar {
+ QtObject { objectName: "object" }
+ TabButton { objectName: "button1" }
+ Timer { objectName: "timer" }
+ TabButton { objectName: "button2" }
+ Component { TabButton { } }
+ }
+ }
+
+ function test_content() {
+ var control = contentBar.createObject(testCase)
+
+ function compareObjectNames(content, names) {
+ if (content.length !== names.length)
+ return false
+ for (var i = 0; i < names.length; ++i) {
+ if (content[i].objectName !== names[i])
+ return false
+ }
+ return true
+ }
+
+ verify(compareObjectNames(control.contentData, ["object", "button1", "timer", "button2", ""]))
+ verify(compareObjectNames(control.contentChildren, ["button1", "button2"]))
+
+ control.addItem(tabButton.createObject(control, {objectName: "button3"}))
+ verify(compareObjectNames(control.contentData, ["object", "button1", "timer", "button2", "", "button3"]))
+ verify(compareObjectNames(control.contentChildren, ["button1", "button2", "button3"]))
+
+ control.insertItem(0, tabButton.createObject(control, {objectName: "button4"}))
+ verify(compareObjectNames(control.contentData, ["object", "button1", "timer", "button2", "", "button3", "button4"]))
+ verify(compareObjectNames(control.contentChildren, ["button4", "button1", "button2", "button3"]))
+
+ control.moveItem(1, 2)
+ verify(compareObjectNames(control.contentData, ["object", "button1", "timer", "button2", "", "button3", "button4"]))
+ verify(compareObjectNames(control.contentChildren, ["button4", "button2", "button1", "button3"]))
+
+ control.removeItem(0)
+ verify(compareObjectNames(control.contentData, ["object", "button1", "timer", "button2", "", "button3"]))
+ verify(compareObjectNames(control.contentChildren, ["button2", "button1", "button3"]))
+
+ control.destroy()
+ }
+
+ Component {
+ id: repeated
+ TabBar {
+ property alias repeater: repeater
+ Repeater {
+ id: repeater
+ model: 5
+ TabButton { property int idx: index }
+ }
+ }
+ }
+
+ function test_repeater() {
+ var control = repeated.createObject(testCase)
+ verify(control)
+
+ var model = control.contentModel
+ verify(model)
+
+ var repeater = control.repeater
+ verify(repeater)
+
+ compare(repeater.count, 5)
+ compare(model.count, 5)
+
+ for (var i = 0; i < 5; ++i) {
+ var item1 = control.itemAt(i)
+ verify(item1)
+ compare(item1.idx, i)
+ compare(model.get(i), item1)
+ compare(repeater.itemAt(i), item1)
+ }
+
+ repeater.model = 3
+ compare(repeater.count, 3)
+ compare(model.count, 3)
+
+ for (var j = 0; j < 3; ++j) {
+ var item2 = control.itemAt(j)
+ verify(item2)
+ compare(item2.idx, j)
+ compare(model.get(j), item2)
+ compare(repeater.itemAt(j), item2)
+ }
+
+ control.destroy()
+ }
+
+ Component {
+ id: ordered
+ TabBar {
+ id: obar
+ property alias repeater: repeater
+ TabButton { text: "static_1" }
+ Repeater {
+ id: repeater
+ model: 2
+ TabButton { text: "repeated_" + (index + 2) }
+ }
+ TabButton { text: "static_4" }
+ Component.onCompleted: {
+ addItem(tabButton.createObject(obar, {text: "dynamic_5"}))
+ addItem(tabButton.createObject(obar.contentItem, {text: "dynamic_6"}))
+ insertItem(0, tabButton.createObject(obar, {text: "dynamic_0"}))
+ }
+ }
+ }
+
+ function test_order() {
+ var control = ordered.createObject(testCase)
+ verify(control)
+
+ compare(control.count, 7)
+ compare(control.itemAt(0).text, "dynamic_0")
+ compare(control.itemAt(1).text, "static_1")
+ compare(control.itemAt(2).text, "repeated_2")
+ compare(control.itemAt(3).text, "repeated_3")
+ compare(control.itemAt(4).text, "static_4")
+ compare(control.itemAt(5).text, "dynamic_5")
+ compare(control.itemAt(6).text, "dynamic_6")
+
+ control.destroy()
+ }
+
+ function test_move_data() {
+ return [
+ {tag:"0->1 (0)", from: 0, to: 1, currentBefore: 0, currentAfter: 1},
+ {tag:"0->1 (1)", from: 0, to: 1, currentBefore: 1, currentAfter: 0},
+ {tag:"0->1 (2)", from: 0, to: 1, currentBefore: 2, currentAfter: 2},
+
+ {tag:"0->2 (0)", from: 0, to: 2, currentBefore: 0, currentAfter: 2},
+ {tag:"0->2 (1)", from: 0, to: 2, currentBefore: 1, currentAfter: 0},
+ {tag:"0->2 (2)", from: 0, to: 2, currentBefore: 2, currentAfter: 1},
+
+ {tag:"1->0 (0)", from: 1, to: 0, currentBefore: 0, currentAfter: 1},
+ {tag:"1->0 (1)", from: 1, to: 0, currentBefore: 1, currentAfter: 0},
+ {tag:"1->0 (2)", from: 1, to: 0, currentBefore: 2, currentAfter: 2},
+
+ {tag:"1->2 (0)", from: 1, to: 2, currentBefore: 0, currentAfter: 0},
+ {tag:"1->2 (1)", from: 1, to: 2, currentBefore: 1, currentAfter: 2},
+ {tag:"1->2 (2)", from: 1, to: 2, currentBefore: 2, currentAfter: 1},
+
+ {tag:"2->0 (0)", from: 2, to: 0, currentBefore: 0, currentAfter: 1},
+ {tag:"2->0 (1)", from: 2, to: 0, currentBefore: 1, currentAfter: 2},
+ {tag:"2->0 (2)", from: 2, to: 0, currentBefore: 2, currentAfter: 0},
+
+ {tag:"2->1 (0)", from: 2, to: 1, currentBefore: 0, currentAfter: 0},
+ {tag:"2->1 (1)", from: 2, to: 1, currentBefore: 1, currentAfter: 2},
+ {tag:"2->1 (2)", from: 2, to: 1, currentBefore: 2, currentAfter: 1},
+
+ {tag:"0->0", from: 0, to: 0, currentBefore: 0, currentAfter: 0},
+ {tag:"-1->0", from: 0, to: 0, currentBefore: 1, currentAfter: 1},
+ {tag:"0->-1", from: 0, to: 0, currentBefore: 2, currentAfter: 2},
+ {tag:"1->10", from: 0, to: 0, currentBefore: 0, currentAfter: 0},
+ {tag:"10->2", from: 0, to: 0, currentBefore: 1, currentAfter: 1},
+ {tag:"10->-1", from: 0, to: 0, currentBefore: 2, currentAfter: 2}
+ ]
+ }
+
+ function test_move(data) {
+ var control = tabBar.createObject(testCase)
+
+ compare(control.count, 0)
+ var titles = ["1", "2", "3"]
+
+ var i = 0;
+ for (i = 0; i < titles.length; ++i)
+ control.addItem(tabButton.createObject(control, {text: titles[i]}))
+
+ compare(control.count, titles.length)
+ for (i = 0; i < control.count; ++i)
+ compare(control.itemAt(i).text, titles[i])
+
+ control.currentIndex = data.currentBefore
+ control.moveItem(data.from, data.to)
+
+ compare(control.count, titles.length)
+ compare(control.currentIndex, data.currentAfter)
+
+ var title = titles[data.from]
+ titles.splice(data.from, 1)
+ titles.splice(data.to, 0, title)
+
+ compare(control.count, titles.length)
+ for (i = 0; i < control.count; ++i)
+ compare(control.itemAt(i).text, titles[i])
+
+ control.destroy()
+ }
+
+ Component {
+ id: dynamicBar
+ TabBar {
+ id: dbar
+ TabButton { text: "static" }
+ Component.onCompleted: {
+ addItem(tabButton.createObject(dbar, {text: "added"}))
+ insertItem(0, tabButton.createObject(dbar, {text: "inserted"}))
+ tabButton.createObject(dbar, {text: "dynamic"})
+ }
+ }
+ }
+
+ function test_dynamic() {
+ var control = dynamicBar.createObject(testCase)
+
+ // insertItem(), addItem(), createObject() and static TabButton {}
+ compare(control.count, 4)
+ compare(control.itemAt(0).text, "inserted")
+
+ var tab = tabButton.createObject(control, {text: "dying"})
+ compare(control.count, 5)
+ compare(control.itemAt(4).text, "dying")
+
+ // TODO: fix crash in QQuickItemView
+// tab.destroy()
+// wait(0)
+// compare(control.count, 4)
+
+ control.destroy()
+ }
+}