From a60c8e60d508117ddf48876b44d31e6d5ab98da6 Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Wed, 13 Apr 2016 15:59:53 +0200 Subject: Templates: rename the C++ module to qtquicktemplates2 Change-Id: I146da903b46f5c2caf865e37291c25376b49021a Reviewed-by: J-P Nurmi --- src/quicktemplates2/qquickcontainer.cpp | 527 ++++++++++++++++++++++++++++++++ 1 file changed, 527 insertions(+) create mode 100644 src/quicktemplates2/qquickcontainer.cpp (limited to 'src/quicktemplates2/qquickcontainer.cpp') diff --git a/src/quicktemplates2/qquickcontainer.cpp b/src/quicktemplates2/qquickcontainer.cpp new file mode 100644 index 00000000..9d39182f --- /dev/null +++ b/src/quicktemplates2/qquickcontainer.cpp @@ -0,0 +1,527 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Labs Templates module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qquickcontainer_p.h" +#include "qquickcontainer_p_p.h" + +#include + +QT_BEGIN_NAMESPACE + +/*! + \qmltype Container + \inherits Control + \instantiates QQuickContainer + \inqmlmodule Qt.labs.controls + \ingroup qtquickcontrols2-containers + \brief A container control base type. + + Container is the base type of container-like user interface controls. + + \labs + + \sa {Container Controls} +*/ + +static QQuickItem *effectiveContentItem(QQuickItem *item) +{ + QQuickFlickable *flickable = qobject_cast(item); + if (flickable) + return flickable->contentItem(); + return item; +} + +QQuickContainerPrivate::QQuickContainerPrivate() : contentModel(nullptr), currentIndex(-1), updatingCurrent(false) +{ +} + +void QQuickContainerPrivate::init() +{ + Q_Q(QQuickContainer); + contentModel = new QQmlObjectModel(q); + QObject::connect(contentModel, &QQmlObjectModel::countChanged, q, &QQuickContainer::countChanged); + QObject::connect(contentModel, &QQmlObjectModel::childrenChanged, q, &QQuickContainer::contentChildrenChanged); +} + +void QQuickContainerPrivate::cleanup() +{ + // ensure correct destruction order (QTBUG-46798) + delete contentItem; + const int count = contentModel->count(); + for (int i = 0; i < count; ++i) { + QQuickItem *item = itemAt(i); + if (item) { + QQuickItemPrivate::get(item)->removeItemChangeListener(this, QQuickItemPrivate::Destroyed | QQuickItemPrivate::Parent); + delete item; + } + } + delete contentModel; +} + +QQuickItem *QQuickContainerPrivate::itemAt(int index) const +{ + return qobject_cast(contentModel->get(index)); +} + +void QQuickContainerPrivate::insertItem(int index, QQuickItem *item) +{ + Q_Q(QQuickContainer); + if (!q->isContent(item)) + return; + contentData.append(item); + + updatingCurrent = true; + + item->setParentItem(effectiveContentItem(contentItem)); + QQuickItemPrivate::get(item)->addItemChangeListener(this, QQuickItemPrivate::Destroyed | QQuickItemPrivate::Parent); + contentModel->insert(index, item); + + q->itemAdded(index, item); + + if (contentModel->count() == 1 && currentIndex == -1) + q->setCurrentIndex(index); + + updatingCurrent = false; +} + +void QQuickContainerPrivate::moveItem(int from, int to) +{ + Q_Q(QQuickContainer); + int oldCurrent = currentIndex; + contentModel->move(from, to); + + updatingCurrent = true; + + if (from == oldCurrent) + q->setCurrentIndex(to); + else if (from < oldCurrent && to >= oldCurrent) + q->setCurrentIndex(oldCurrent - 1); + else if (from > oldCurrent && to <= oldCurrent) + q->setCurrentIndex(oldCurrent + 1); + + updatingCurrent = false; +} + +void QQuickContainerPrivate::removeItem(int index, QQuickItem *item) +{ + Q_Q(QQuickContainer); + if (!q->isContent(item)) + return; + contentData.removeOne(item); + + updatingCurrent = true; + + bool currentChanged = false; + if (index == currentIndex) { + q->setCurrentIndex(currentIndex - 1); + } else if (index < currentIndex) { + --currentIndex; + currentChanged = true; + } + + QQuickItemPrivate::get(item)->removeItemChangeListener(this, QQuickItemPrivate::Destroyed | QQuickItemPrivate::Parent); + item->setParentItem(nullptr); + contentModel->remove(index); + + q->itemRemoved(index, item); + + if (currentChanged) + emit q->currentIndexChanged(); + + updatingCurrent = false; +} + +void QQuickContainerPrivate::_q_currentIndexChanged() +{ + Q_Q(QQuickContainer); + if (!updatingCurrent) + q->setCurrentIndex(contentItem ? contentItem->property("currentIndex").toInt() : -1); +} + +void QQuickContainerPrivate::itemChildAdded(QQuickItem *, QQuickItem *child) +{ + // add dynamically reparented items (eg. by a Repeater) + if (!QQuickItemPrivate::get(child)->isTransparentForPositioner() && !contentData.contains(child)) + insertItem(contentModel->count(), child); +} + +void QQuickContainerPrivate::itemParentChanged(QQuickItem *item, QQuickItem *parent) +{ + // remove dynamically unparented items (eg. by a Repeater) + if (!parent) + removeItem(contentModel->indexOf(item, nullptr), item); +} + +void QQuickContainerPrivate::itemSiblingOrderChanged(QQuickItem *) +{ + // reorder the restacked items (eg. by a Repeater) + Q_Q(QQuickContainer); + QList siblings = effectiveContentItem(contentItem)->childItems(); + for (int i = 0; i < siblings.count(); ++i) { + QQuickItem* sibling = siblings.at(i); + int index = contentModel->indexOf(sibling, nullptr); + q->moveItem(index, i); + } +} + +void QQuickContainerPrivate::itemDestroyed(QQuickItem *item) +{ + int index = contentModel->indexOf(item, nullptr); + if (index != -1) + removeItem(index, item); +} + +void QQuickContainerPrivate::contentData_append(QQmlListProperty *prop, QObject *obj) +{ + QQuickContainerPrivate *p = static_cast(prop->data); + QQuickContainer *q = static_cast(prop->object); + QQuickItem *item = qobject_cast(obj); + if (item) { + if (QQuickItemPrivate::get(item)->isTransparentForPositioner()) { + QQuickItemPrivate::get(item)->addItemChangeListener(p, QQuickItemPrivate::SiblingOrder); + item->setParentItem(effectiveContentItem(p->contentItem)); + } else if (p->contentModel->indexOf(item, nullptr) == -1) { + q->addItem(item); + } + } else { + p->contentData.append(obj); + } +} + +int QQuickContainerPrivate::contentData_count(QQmlListProperty *prop) +{ + QQuickContainerPrivate *p = static_cast(prop->data); + return p->contentData.count(); +} + +QObject *QQuickContainerPrivate::contentData_at(QQmlListProperty *prop, int index) +{ + QQuickContainerPrivate *p = static_cast(prop->data); + return p->contentData.value(index); +} + +void QQuickContainerPrivate::contentData_clear(QQmlListProperty *prop) +{ + QQuickContainerPrivate *p = static_cast(prop->data); + p->contentData.clear(); +} + +void QQuickContainerPrivate::contentChildren_append(QQmlListProperty *prop, QQuickItem *item) +{ + QQuickContainer *q = static_cast(prop->object); + q->addItem(item); +} + +int QQuickContainerPrivate::contentChildren_count(QQmlListProperty *prop) +{ + QQuickContainerPrivate *p = static_cast(prop->data); + return p->contentModel->count(); +} + +QQuickItem *QQuickContainerPrivate::contentChildren_at(QQmlListProperty *prop, int index) +{ + QQuickContainer *q = static_cast(prop->object); + return q->itemAt(index); +} + +void QQuickContainerPrivate::contentChildren_clear(QQmlListProperty *prop) +{ + QQuickContainerPrivate *p = static_cast(prop->data); + p->contentModel->clear(); +} + +QQuickContainer::QQuickContainer(QQuickItem *parent) : + QQuickControl(*(new QQuickContainerPrivate), parent) +{ + Q_D(QQuickContainer); + d->init(); +} + +QQuickContainer::QQuickContainer(QQuickContainerPrivate &dd, QQuickItem *parent) : + QQuickControl(dd, parent) +{ + Q_D(QQuickContainer); + d->init(); +} + +QQuickContainer::~QQuickContainer() +{ + Q_D(QQuickContainer); + d->cleanup(); +} + +/*! + \qmlproperty int Qt.labs.controls::Container::count + \readonly + + This property holds the number of items. +*/ +int QQuickContainer::count() const +{ + Q_D(const QQuickContainer); + return d->contentModel->count(); +} + +/*! + \qmlmethod Item Qt.labs.controls::Container::itemAt(int index) + + Returns the item at \a index, or \c null if it does not exist. +*/ +QQuickItem *QQuickContainer::itemAt(int index) const +{ + Q_D(const QQuickContainer); + return d->itemAt(index); +} + +/*! + \qmlmethod void Qt.labs.controls::Container::addItem(Item item) + + Adds an \a item. +*/ +void QQuickContainer::addItem(QQuickItem *item) +{ + Q_D(QQuickContainer); + insertItem(d->contentModel->count(), item); +} + +/*! + \qmlmethod void Qt.labs.controls::Container::insertItem(int index, Item item) + + Inserts an \a item at \a index. +*/ +void QQuickContainer::insertItem(int index, QQuickItem *item) +{ + Q_D(QQuickContainer); + if (!item) + return; + const int count = d->contentModel->count(); + if (index < 0 || index > count) + index = count; + + int oldIndex = d->contentModel->indexOf(item, nullptr); + if (oldIndex != -1) { + if (oldIndex < index) + --index; + if (oldIndex != index) + d->moveItem(oldIndex, index); + } else { + d->insertItem(index, item); + } +} + +/*! + \qmlmethod void Qt.labs.controls::Container::moveItem(int from, int to) + + Moves an item \a from one index \a to another. +*/ +void QQuickContainer::moveItem(int from, int to) +{ + Q_D(QQuickContainer); + 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->moveItem(from, to); +} + +/*! + \qmlmethod void Qt.labs.controls::Container::removeItem(int index) + + Removes an item at \a index. + + \note The ownership of the item is transferred to the caller. +*/ +void QQuickContainer::removeItem(int index) +{ + Q_D(QQuickContainer); + const int count = d->contentModel->count(); + if (index < 0 || index >= count) + return; + + QQuickItem *item = itemAt(index); + if (item) + d->removeItem(index, item); +} + +/*! + \qmlproperty model Qt.labs.controls::Container::contentModel + \readonly + + This property holds the content model of items. +*/ +QVariant QQuickContainer::contentModel() const +{ + Q_D(const QQuickContainer); + return QVariant::fromValue(d->contentModel); +} + +/*! + \qmlproperty list Qt.labs.controls::Container::contentData + \default + + This property holds the list of content data. + + \sa Item::data +*/ +QQmlListProperty QQuickContainer::contentData() +{ + Q_D(QQuickContainer); + return QQmlListProperty(this, d, + QQuickContainerPrivate::contentData_append, + QQuickContainerPrivate::contentData_count, + QQuickContainerPrivate::contentData_at, + QQuickContainerPrivate::contentData_clear); +} + +/*! + \qmlproperty list Qt.labs.controls::Container::contentChildren + + This property holds the list of content children. + + \sa Item::children +*/ +QQmlListProperty QQuickContainer::contentChildren() +{ + Q_D(QQuickContainer); + return QQmlListProperty(this, d, + QQuickContainerPrivate::contentChildren_append, + QQuickContainerPrivate::contentChildren_count, + QQuickContainerPrivate::contentChildren_at, + QQuickContainerPrivate::contentChildren_clear); +} + +/*! + \qmlproperty int Qt.labs.controls::Container::currentIndex + + This property holds the index of the current item in the container. +*/ +int QQuickContainer::currentIndex() const +{ + Q_D(const QQuickContainer); + return d->currentIndex; +} + +void QQuickContainer::setCurrentIndex(int index) +{ + Q_D(QQuickContainer); + if (d->currentIndex == index) + return; + + d->currentIndex = index; + emit currentIndexChanged(); + emit currentItemChanged(); +} + +/*! + \qmlproperty Item Qt.labs.controls::Container::currentItem + + This property holds the current item. +*/ +QQuickItem *QQuickContainer::currentItem() const +{ + Q_D(const QQuickContainer); + return itemAt(d->currentIndex); +} + +void QQuickContainer::itemChange(ItemChange change, const ItemChangeData &data) +{ + Q_D(QQuickContainer); + QQuickControl::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, nullptr) == -1) + addItem(data.item); + } +} + +void QQuickContainer::contentItemChange(QQuickItem *newItem, QQuickItem *oldItem) +{ + Q_D(QQuickContainer); + QQuickControl::contentItemChange(newItem, oldItem); + + static const int slotIndex = metaObject()->indexOfSlot("_q_currentIndexChanged()"); + + if (oldItem) { + QQuickItemPrivate::get(oldItem)->removeItemChangeListener(d, QQuickItemPrivate::Children); + QQuickItem *oldContentItem = effectiveContentItem(oldItem); + if (oldContentItem != oldItem) + QQuickItemPrivate::get(oldContentItem)->removeItemChangeListener(d, QQuickItemPrivate::Children); + + int signalIndex = oldItem->metaObject()->indexOfSignal("currentIndexChanged()"); + if (signalIndex != -1) + QMetaObject::disconnect(oldItem, signalIndex, this, slotIndex); + } + + if (newItem) { + QQuickItemPrivate::get(newItem)->addItemChangeListener(d, QQuickItemPrivate::Children); + QQuickItem *newContentItem = effectiveContentItem(newItem); + if (newContentItem != newItem) + QQuickItemPrivate::get(newContentItem)->addItemChangeListener(d, QQuickItemPrivate::Children); + + int signalIndex = newItem->metaObject()->indexOfSignal("currentIndexChanged()"); + if (signalIndex != -1) + QMetaObject::connect(newItem, signalIndex, this, slotIndex); + } +} + +bool QQuickContainer::isContent(QQuickItem *item) const +{ + // If the item has a QML context associated to it (it was created in QML), + // we add it to the content model. Otherwise, it's probably the default + // highlight item that is always created by the item views, which we need + // to exclude. + // + // TODO: Find a better way to identify/exclude the highlight item... + return qmlContext(item); +} + +void QQuickContainer::itemAdded(int index, QQuickItem *item) +{ + Q_UNUSED(index); + Q_UNUSED(item); +} + +void QQuickContainer::itemRemoved(int index, QQuickItem *item) +{ + Q_UNUSED(index); + Q_UNUSED(item); +} + +QT_END_NAMESPACE + +#include "moc_qquickcontainer_p.cpp" -- cgit v1.2.3