diff options
author | J-P Nurmi <jpnurmi@theqtcompany.com> | 2015-06-12 00:17:35 +0200 |
---|---|---|
committer | J-P Nurmi <jpnurmi@theqtcompany.com> | 2015-06-15 08:21:37 +0000 |
commit | 73f931a771e3576a9dd1daf6d13a6ef11eeee5a9 (patch) | |
tree | a05ff94f1e6be0b886b84842ac2b5e2ef2357beb | |
parent | c4f50fa96d22f1cecbe5abef6ebc5b6d55d3dfbf (diff) |
TabBar: implement contentData & contentChildren
Change-Id: I61d077758c83027cbfc1b99d32cb68efc0829ffd
Reviewed-by: J-P Nurmi <jpnurmi@theqtcompany.com>
-rw-r--r-- | src/controls/qquicktabbar.cpp | 260 | ||||
-rw-r--r-- | src/controls/qquicktabbar_p.h | 12 | ||||
-rw-r--r-- | src/imports/controls/TabBar.qml | 2 | ||||
-rw-r--r-- | tests/auto/controls/data/tst_tabbar.qml | 420 |
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() + } +} |