1// Copyright (C) 2020 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qquickcontainer_p.h"
5#include "qquickcontainer_p_p.h"
6
7#include <QtQuick/private/qquickflickable_p.h>
8
9QT_BEGIN_NAMESPACE
10
11/*!
12 \qmltype Container
13 \inherits Control
14//! \instantiates QQuickContainer
15 \inqmlmodule QtQuick.Controls
16 \since 5.7
17 \ingroup qtquickcontrols-containers
18 \brief Abstract base type providing functionality common to containers.
19
20 Container is the base type of container-like user interface controls that
21 allow dynamic insertion and removal of items.
22
23 \section2 Using Containers
24
25 Typically, items are statically declared as children of Container, but it
26 is also possible to \l {addItem}{add}, \l {insertItem}{insert},
27 \l {moveItem}{move} and \l {removeItem}{remove} items dynamically. The
28 items in a container can be accessed using \l itemAt() or
29 \l contentChildren.
30
31 Most containers have the concept of a "current" item. The current item is
32 specified via the \l currentIndex property, and can be accessed using the
33 read-only \l currentItem property.
34
35 The following example illustrates dynamic insertion of items to a \l TabBar,
36 which is one of the concrete implementations of Container.
37
38 \code
39 Row {
40 TabBar {
41 id: tabBar
42
43 currentIndex: 0
44 width: parent.width - addButton.width
45
46 TabButton { text: "TabButton" }
47 }
48
49 Component {
50 id: tabButton
51 TabButton { text: "TabButton" }
52 }
53
54 Button {
55 id: addButton
56 text: "+"
57 flat: true
58 onClicked: {
59 tabBar.addItem(tabButton.createObject(tabBar))
60 console.log("added:", tabBar.itemAt(tabBar.count - 1))
61 }
62 }
63 }
64 \endcode
65
66 \section2 Managing the Current Index
67
68 When using multiple containers, such as \l TabBar and \l SwipeView, together,
69 their \l currentIndex properties can be bound to each other to keep them in
70 sync. When the user interacts with either container, its current index changes
71 automatically propagate to the other container.
72
73 Notice, however, that assigning a \c currentIndex value in JavaScript removes
74 the respective binding. In order to retain the bindings, use the following
75 methods to alter the current index:
76
77 \list
78 \li \l incrementCurrentIndex()
79 \li \l decrementCurrentIndex()
80 \li \l setCurrentIndex()
81 \endlist
82
83 \code
84 TabBar {
85 id: tabBar
86 currentIndex: swipeView.currentIndex
87 }
88
89 SwipeView {
90 id: swipeView
91 currentIndex: tabBar.currentIndex
92 }
93
94 Button {
95 text: qsTr("Home")
96 onClicked: swipeView.setCurrentIndex(0)
97 enabled: swipeView.currentIndex != 0
98 }
99
100 Button {
101 text: qsTr("Previous")
102 onClicked: swipeView.decrementCurrentIndex()
103 enabled: swipeView.currentIndex > 0
104 }
105
106 Button {
107 text: qsTr("Next")
108 onClicked: swipeView.incrementCurrentIndex()
109 enabled: swipeView.currentIndex < swipeView.count - 1
110 }
111 \endcode
112
113
114 \section2 Implementing Containers
115
116 Container does not provide any default visualization. It is used to implement
117 such containers as \l SwipeView and \l TabBar. When implementing a custom
118 container, the most important part of the API is \l contentModel, which provides
119 the contained items in a way that it can be used as an object model for item
120 views and repeaters.
121
122 \code
123 Container {
124 id: container
125
126 contentItem: ListView {
127 model: container.contentModel
128 snapMode: ListView.SnapOneItem
129 orientation: ListView.Horizontal
130 }
131
132 Text {
133 text: "Page 1"
134 width: container.width
135 height: container.height
136 }
137
138 Text {
139 text: "Page 2"
140 width: container.width
141 height: container.height
142 }
143 }
144 \endcode
145
146 Notice how the sizes of the page items are set by hand. This is because the
147 example uses a plain Container, which does not make any assumptions on the
148 visual layout. It is typically not necessary to specify sizes for items in
149 concrete Container implementations, such as \l SwipeView and \l TabBar.
150
151 \sa {Container Controls}
152*/
153
154static QQuickItem *effectiveContentItem(QQuickItem *item)
155{
156 QQuickFlickable *flickable = qobject_cast<QQuickFlickable *>(object: item);
157 if (flickable)
158 return flickable->contentItem();
159 return item;
160}
161
162void QQuickContainerPrivate::init()
163{
164 Q_Q(QQuickContainer);
165 contentModel = new QQmlObjectModel(q);
166 QObject::connect(sender: contentModel, signal: &QQmlObjectModel::countChanged, context: q, slot: &QQuickContainer::countChanged);
167 QObject::connect(sender: contentModel, signal: &QQmlObjectModel::childrenChanged, context: q, slot: &QQuickContainer::contentChildrenChanged);
168 connect(sender: q, signal: &QQuickControl::implicitContentWidthChanged, receiverPrivate: this, slot: &QQuickContainerPrivate::updateContentWidth);
169 connect(sender: q, signal: &QQuickControl::implicitContentHeightChanged, receiverPrivate: this, slot: &QQuickContainerPrivate::updateContentHeight);
170}
171
172void QQuickContainerPrivate::cleanup()
173{
174 Q_Q(QQuickContainer);
175 // ensure correct destruction order (QTBUG-46798)
176 const int count = contentModel->count();
177 for (int i = 0; i < count; ++i) {
178 QQuickItem *item = itemAt(index: i);
179 if (item)
180 QQuickItemPrivate::get(item)->removeItemChangeListener(this, types: changeTypes);
181 }
182
183 if (contentItem) {
184 QQuickItem *focusItem = QQuickItemPrivate::get(item: contentItem)->subFocusItem;
185 if (focusItem && window)
186 QQuickWindowPrivate::get(c: window)->clearFocusInScope(scope: contentItem, item: focusItem, reason: Qt::OtherFocusReason);
187
188 q->contentItemChange(newItem: nullptr, oldItem: contentItem);
189 QQuickControlPrivate::hideOldItem(item: contentItem);
190 }
191
192 QObject::disconnect(sender: contentModel, signal: &QQmlObjectModel::countChanged, receiver: q, slot: &QQuickContainer::countChanged);
193 QObject::disconnect(sender: contentModel, signal: &QQmlObjectModel::childrenChanged, receiver: q, slot: &QQuickContainer::contentChildrenChanged);
194 delete contentModel;
195 contentModel = nullptr;
196}
197
198QQuickItem *QQuickContainerPrivate::itemAt(int index) const
199{
200 return qobject_cast<QQuickItem *>(o: contentModel->get(index));
201}
202
203void QQuickContainerPrivate::insertItem(int index, QQuickItem *item)
204{
205 Q_Q(QQuickContainer);
206 if (!q->isContent(item))
207 return;
208 contentData.append(t: item);
209
210 updatingCurrent = true;
211
212 item->setParentItem(effectiveContentItem(item: q->contentItem()));
213 QQuickItemPrivate::get(item)->addItemChangeListener(listener: this, types: changeTypes);
214 contentModel->insert(index, object: item);
215
216 q->itemAdded(index, item);
217
218 int count = contentModel->count();
219 for (int i = index + 1; i < count; ++i)
220 q->itemMoved(index: i, item: itemAt(index: i));
221
222 if (count == 1 && currentIndex == -1)
223 q->setCurrentIndex(index);
224
225 updatingCurrent = false;
226}
227
228void QQuickContainerPrivate::moveItem(int from, int to, QQuickItem *item)
229{
230 Q_Q(QQuickContainer);
231 int oldCurrent = currentIndex;
232 contentModel->move(from, to);
233
234 updatingCurrent = true;
235
236 q->itemMoved(index: to, item);
237
238 if (from < to) {
239 for (int i = from; i < to; ++i)
240 q->itemMoved(index: i, item: itemAt(index: i));
241 } else {
242 for (int i = from; i > to; --i)
243 q->itemMoved(index: i, item: itemAt(index: i));
244 }
245
246 if (from == oldCurrent)
247 q->setCurrentIndex(to);
248 else if (from < oldCurrent && to >= oldCurrent)
249 q->setCurrentIndex(oldCurrent - 1);
250 else if (from > oldCurrent && to <= oldCurrent)
251 q->setCurrentIndex(oldCurrent + 1);
252
253 updatingCurrent = false;
254}
255
256void QQuickContainerPrivate::removeItem(int index, QQuickItem *item)
257{
258 Q_Q(QQuickContainer);
259 if (!q->isContent(item))
260 return;
261 contentData.removeOne(t: item);
262
263 updatingCurrent = true;
264
265 int count = contentModel->count();
266 bool currentChanged = false;
267 if (index == currentIndex && (index != 0 || count == 1)) {
268 q->setCurrentIndex(currentIndex - 1);
269 } else if (index < currentIndex) {
270 --currentIndex;
271 currentChanged = true;
272 }
273
274 QQuickItemPrivate::get(item)->removeItemChangeListener(this, types: changeTypes);
275 item->setParentItem(nullptr);
276 contentModel->remove(index);
277 --count;
278
279 q->itemRemoved(index, item);
280
281 for (int i = index; i < count; ++i)
282 q->itemMoved(index: i, item: itemAt(index: i));
283
284 if (currentChanged)
285 emit q->currentIndexChanged();
286
287 updatingCurrent = false;
288}
289
290void QQuickContainerPrivate::reorderItems()
291{
292 Q_Q(QQuickContainer);
293 if (!contentItem)
294 return;
295
296 QList<QQuickItem *> siblings = effectiveContentItem(item: contentItem)->childItems();
297
298 int to = 0;
299 for (int i = 0; i < siblings.size(); ++i) {
300 QQuickItem* sibling = siblings.at(i);
301 if (QQuickItemPrivate::get(item: sibling)->isTransparentForPositioner())
302 continue;
303 int index = contentModel->indexOf(object: sibling, objectContext: nullptr);
304 q->moveItem(from: index, to: to++);
305 }
306}
307
308void QQuickContainerPrivate::_q_currentIndexChanged()
309{
310 Q_Q(QQuickContainer);
311 if (!updatingCurrent)
312 q->setCurrentIndex(contentItem ? contentItem->property(name: "currentIndex").toInt() : -1);
313}
314
315void QQuickContainerPrivate::itemChildAdded(QQuickItem *, QQuickItem *child)
316{
317 // add dynamically reparented items (eg. by a Repeater)
318 if (!QQuickItemPrivate::get(item: child)->isTransparentForPositioner() && !contentData.contains(t: child))
319 insertItem(index: contentModel->count(), item: child);
320}
321
322void QQuickContainerPrivate::itemParentChanged(QQuickItem *item, QQuickItem *parent)
323{
324 // remove dynamically unparented items (eg. by a Repeater)
325 if (!parent)
326 removeItem(index: contentModel->indexOf(object: item, objectContext: nullptr), item);
327}
328
329void QQuickContainerPrivate::itemSiblingOrderChanged(QQuickItem *)
330{
331 if (!componentComplete)
332 return;
333
334 // reorder the restacked items (eg. by a Repeater)
335 reorderItems();
336}
337
338void QQuickContainerPrivate::itemDestroyed(QQuickItem *item)
339{
340 int index = contentModel->indexOf(object: item, objectContext: nullptr);
341 if (index != -1)
342 removeItem(index, item);
343 else
344 QQuickControlPrivate::itemDestroyed(item);
345}
346
347void QQuickContainerPrivate::contentData_append(QQmlListProperty<QObject> *prop, QObject *obj)
348{
349 QQuickContainer *q = static_cast<QQuickContainer *>(prop->object);
350 QQuickContainerPrivate *p = QQuickContainerPrivate::get(container: q);
351 QQuickItem *item = qobject_cast<QQuickItem *>(o: obj);
352 if (item) {
353 if (QQuickItemPrivate::get(item)->isTransparentForPositioner())
354 item->setParentItem(effectiveContentItem(item: q->contentItem()));
355 else if (p->contentModel->indexOf(object: item, objectContext: nullptr) == -1)
356 q->addItem(item);
357 } else {
358 p->contentData.append(t: obj);
359 }
360}
361
362qsizetype QQuickContainerPrivate::contentData_count(QQmlListProperty<QObject> *prop)
363{
364 QQuickContainer *q = static_cast<QQuickContainer *>(prop->object);
365 return QQuickContainerPrivate::get(container: q)->contentData.size();
366}
367
368QObject *QQuickContainerPrivate::contentData_at(QQmlListProperty<QObject> *prop, qsizetype index)
369{
370 QQuickContainer *q = static_cast<QQuickContainer *>(prop->object);
371 return QQuickContainerPrivate::get(container: q)->contentData.value(i: index);
372}
373
374void QQuickContainerPrivate::contentData_clear(QQmlListProperty<QObject> *prop)
375{
376 QQuickContainer *q = static_cast<QQuickContainer *>(prop->object);
377 return QQuickContainerPrivate::get(container: q)->contentData.clear();
378}
379
380void QQuickContainerPrivate::contentChildren_append(QQmlListProperty<QQuickItem> *prop, QQuickItem *item)
381{
382 QQuickContainer *q = static_cast<QQuickContainer *>(prop->object);
383 q->addItem(item);
384}
385
386qsizetype QQuickContainerPrivate::contentChildren_count(QQmlListProperty<QQuickItem> *prop)
387{
388 QQuickContainer *q = static_cast<QQuickContainer *>(prop->object);
389 return QQuickContainerPrivate::get(container: q)->contentModel->count();
390}
391
392QQuickItem *QQuickContainerPrivate::contentChildren_at(QQmlListProperty<QQuickItem> *prop, qsizetype index)
393{
394 QQuickContainer *q = static_cast<QQuickContainer *>(prop->object);
395 return q->itemAt(index);
396}
397
398void QQuickContainerPrivate::contentChildren_clear(QQmlListProperty<QQuickItem> *prop)
399{
400 QQuickContainer *q = static_cast<QQuickContainer *>(prop->object);
401 return QQuickContainerPrivate::get(container: q)->contentModel->clear();
402}
403
404void QQuickContainerPrivate::updateContentWidth()
405{
406 Q_Q(QQuickContainer);
407 if (hasContentWidth || qFuzzyCompare(p1: contentWidth, p2: implicitContentWidth) || !contentModel)
408 return;
409
410 contentWidth = implicitContentWidth;
411 emit q->contentWidthChanged();
412}
413
414void QQuickContainerPrivate::updateContentHeight()
415{
416 Q_Q(QQuickContainer);
417 if (hasContentHeight || qFuzzyCompare(p1: contentHeight, p2: implicitContentHeight) || !contentModel)
418 return;
419
420 contentHeight = implicitContentHeight;
421 emit q->contentHeightChanged();
422}
423
424QQuickContainer::QQuickContainer(QQuickItem *parent)
425 : QQuickControl(*(new QQuickContainerPrivate), parent)
426{
427 Q_D(QQuickContainer);
428 d->init();
429}
430
431QQuickContainer::QQuickContainer(QQuickContainerPrivate &dd, QQuickItem *parent)
432 : QQuickControl(dd, parent)
433{
434 Q_D(QQuickContainer);
435 d->init();
436}
437
438QQuickContainer::~QQuickContainer()
439{
440 Q_D(QQuickContainer);
441 d->cleanup();
442}
443
444/*!
445 \qmlproperty int QtQuick.Controls::Container::count
446 \readonly
447
448 This property holds the number of items.
449*/
450int QQuickContainer::count() const
451{
452 Q_D(const QQuickContainer);
453 return d->contentModel->count();
454}
455
456/*!
457 \qmlmethod Item QtQuick.Controls::Container::itemAt(int index)
458
459 Returns the item at \a index, or \c null if it does not exist.
460*/
461QQuickItem *QQuickContainer::itemAt(int index) const
462{
463 Q_D(const QQuickContainer);
464 return d->itemAt(index);
465}
466
467/*!
468 \qmlmethod void QtQuick.Controls::Container::addItem(Item item)
469
470 Adds an \a item.
471*/
472void QQuickContainer::addItem(QQuickItem *item)
473{
474 Q_D(QQuickContainer);
475 insertItem(index: d->contentModel->count(), item);
476}
477
478/*!
479 \qmlmethod void QtQuick.Controls::Container::insertItem(int index, Item item)
480
481 Inserts an \a item at \a index.
482*/
483void QQuickContainer::insertItem(int index, QQuickItem *item)
484{
485 Q_D(QQuickContainer);
486 if (!item)
487 return;
488 const int count = d->contentModel->count();
489 if (index < 0 || index > count)
490 index = count;
491
492 int oldIndex = d->contentModel->indexOf(object: item, objectContext: nullptr);
493 if (oldIndex != -1) {
494 if (oldIndex < index)
495 --index;
496 if (oldIndex != index)
497 d->moveItem(from: oldIndex, to: index, item);
498 } else {
499 d->insertItem(index, item);
500 }
501}
502
503/*!
504 \qmlmethod void QtQuick.Controls::Container::moveItem(int from, int to)
505
506 Moves an item \a from one index \a to another.
507*/
508void QQuickContainer::moveItem(int from, int to)
509{
510 Q_D(QQuickContainer);
511 const int count = d->contentModel->count();
512 if (from < 0 || from > count - 1)
513 return;
514 if (to < 0 || to > count - 1)
515 to = count - 1;
516
517 if (from != to)
518 d->moveItem(from, to, item: d->itemAt(index: from));
519}
520
521/*!
522 \since QtQuick.Controls 2.3 (Qt 5.10)
523 \qmlmethod void QtQuick.Controls::Container::removeItem(Item item)
524
525 Removes and destroys the specified \a item.
526*/
527void QQuickContainer::removeItem(QQuickItem *item)
528{
529 Q_D(QQuickContainer);
530 if (!item)
531 return;
532
533 const int index = d->contentModel->indexOf(object: item, objectContext: nullptr);
534 if (index == -1)
535 return;
536
537 d->removeItem(index, item);
538 item->deleteLater();
539}
540
541/*!
542 \since QtQuick.Controls 2.3 (Qt 5.10)
543 \qmlmethod Item QtQuick.Controls::Container::takeItem(int index)
544
545 Removes and returns the item at \a index.
546
547 \note The ownership of the item is transferred to the caller.
548*/
549QQuickItem *QQuickContainer::takeItem(int index)
550{
551 Q_D(QQuickContainer);
552 const int count = d->contentModel->count();
553 if (index < 0 || index >= count)
554 return nullptr;
555
556 QQuickItem *item = itemAt(index);
557 if (item)
558 d->removeItem(index, item);
559 return item;
560}
561
562/*!
563 \qmlproperty model QtQuick.Controls::Container::contentModel
564 \readonly
565
566 This property holds the content model of items.
567
568 The content model is provided for visualization purposes. It can be assigned
569 as a model to a content item that presents the contents of the container.
570
571 \code
572 Container {
573 id: container
574 contentItem: ListView {
575 model: container.contentModel
576 }
577 }
578 \endcode
579
580 \sa contentData, contentChildren
581*/
582QVariant QQuickContainer::contentModel() const
583{
584 Q_D(const QQuickContainer);
585 return QVariant::fromValue(value: d->contentModel);
586}
587
588/*!
589 \qmlproperty list<QtObject> QtQuick.Controls::Container::contentData
590 \qmldefault
591
592 This property holds the list of content data.
593
594 The list contains all objects that have been declared in QML as children
595 of the container, and also items that have been dynamically added or
596 inserted using the \l addItem() and \l insertItem() methods, respectively.
597
598 \note Unlike \c contentChildren, \c contentData does include non-visual QML
599 objects. It is not re-ordered when items are inserted or moved.
600
601 \sa Item::data, contentChildren
602*/
603QQmlListProperty<QObject> QQuickContainer::contentData()
604{
605 Q_D(QQuickContainer);
606 if (!d->contentItem)
607 d->executeContentItem();
608 return QQmlListProperty<QObject>(this, nullptr,
609 QQuickContainerPrivate::contentData_append,
610 QQuickContainerPrivate::contentData_count,
611 QQuickContainerPrivate::contentData_at,
612 QQuickContainerPrivate::contentData_clear);
613}
614
615/*!
616 \qmlproperty list<Item> QtQuick.Controls::Container::contentChildren
617
618 This property holds the list of content children.
619
620 The list contains all items that have been declared in QML as children
621 of the container, and also items that have been dynamically added or
622 inserted using the \l addItem() and \l insertItem() methods, respectively.
623
624 \note Unlike \c contentData, \c contentChildren does not include non-visual
625 QML objects. It is re-ordered when items are inserted or moved.
626
627 \sa Item::children, contentData
628*/
629QQmlListProperty<QQuickItem> QQuickContainer::contentChildren()
630{
631 return QQmlListProperty<QQuickItem>(this, nullptr,
632 QQuickContainerPrivate::contentChildren_append,
633 QQuickContainerPrivate::contentChildren_count,
634 QQuickContainerPrivate::contentChildren_at,
635 QQuickContainerPrivate::contentChildren_clear);
636}
637
638/*!
639 \qmlproperty int QtQuick.Controls::Container::currentIndex
640
641 This property holds the index of the current item.
642
643 \sa currentItem, {Managing the Current Index}
644*/
645int QQuickContainer::currentIndex() const
646{
647 Q_D(const QQuickContainer);
648 return d->currentIndex;
649}
650
651/*!
652 \qmlmethod void QtQuick.Controls::Container::setCurrentIndex(int index)
653
654 Sets the current \a index of the container.
655
656 This method can be called to set a specific current index without breaking
657 existing \c currentIndex bindings.
658
659 \sa currentIndex, {Managing the Current Index}
660*/
661void QQuickContainer::setCurrentIndex(int index)
662{
663 Q_D(QQuickContainer);
664 if (d->currentIndex == index)
665 return;
666
667 d->currentIndex = index;
668 emit currentIndexChanged();
669 emit currentItemChanged();
670}
671
672/*!
673 \qmlmethod void QtQuick.Controls::Container::incrementCurrentIndex()
674 \since QtQuick.Controls 2.1 (Qt 5.8)
675
676 Increments the current index of the container.
677
678 This method can be called to alter the current index without breaking
679 existing \c currentIndex bindings.
680
681 \sa currentIndex, {Managing the Current Index}
682*/
683void QQuickContainer::incrementCurrentIndex()
684{
685 Q_D(QQuickContainer);
686 if (d->currentIndex < count() - 1)
687 setCurrentIndex(d->currentIndex + 1);
688}
689
690/*!
691 \qmlmethod void QtQuick.Controls::Container::decrementCurrentIndex()
692 \since QtQuick.Controls 2.1 (Qt 5.8)
693
694 Decrements the current index of the container.
695
696 This method can be called to alter the current index without breaking
697 existing \c currentIndex bindings.
698
699 \sa currentIndex, {Managing the Current Index}
700*/
701void QQuickContainer::decrementCurrentIndex()
702{
703 Q_D(QQuickContainer);
704 if (d->currentIndex > 0)
705 setCurrentIndex(d->currentIndex - 1);
706}
707
708/*!
709 \qmlproperty Item QtQuick.Controls::Container::currentItem
710 \readonly
711
712 This property holds the current item.
713
714 \sa currentIndex
715*/
716QQuickItem *QQuickContainer::currentItem() const
717{
718 Q_D(const QQuickContainer);
719 return itemAt(index: d->currentIndex);
720}
721
722/*!
723 \since QtQuick.Controls 2.5 (Qt 5.12)
724 \qmlproperty real QtQuick.Controls::Container::contentWidth
725
726 This property holds the content width. It is used for calculating the total
727 implicit width of the container.
728
729 Unless explicitly overridden, the content width is automatically calculated
730 based on the implicit width of the items in the container.
731
732 \sa contentHeight
733*/
734qreal QQuickContainer::contentWidth() const
735{
736 Q_D(const QQuickContainer);
737 return d->contentWidth;
738}
739
740void QQuickContainer::setContentWidth(qreal width)
741{
742 Q_D(QQuickContainer);
743 d->hasContentWidth = true;
744 if (qFuzzyCompare(p1: d->contentWidth, p2: width))
745 return;
746
747 d->contentWidth = width;
748 d->resizeContent();
749 emit contentWidthChanged();
750}
751
752void QQuickContainer::resetContentWidth()
753{
754 Q_D(QQuickContainer);
755 if (!d->hasContentWidth)
756 return;
757
758 d->hasContentWidth = false;
759 d->updateContentWidth();
760}
761
762/*!
763 \since QtQuick.Controls 2.5 (Qt 5.12)
764 \qmlproperty real QtQuick.Controls::Container::contentHeight
765
766 This property holds the content height. It is used for calculating the total
767 implicit height of the container.
768
769 Unless explicitly overridden, the content height is automatically calculated
770 based on the implicit height of the items in the container.
771
772 \sa contentWidth
773*/
774qreal QQuickContainer::contentHeight() const
775{
776 Q_D(const QQuickContainer);
777 return d->contentHeight;
778}
779
780void QQuickContainer::setContentHeight(qreal height)
781{
782 Q_D(QQuickContainer);
783 d->hasContentHeight = true;
784 if (qFuzzyCompare(p1: d->contentHeight, p2: height))
785 return;
786
787 d->contentHeight = height;
788 d->resizeContent();
789 emit contentHeightChanged();
790}
791
792void QQuickContainer::resetContentHeight()
793{
794 Q_D(QQuickContainer);
795 if (!d->hasContentHeight)
796 return;
797
798 d->hasContentHeight = false;
799 d->updateContentHeight();
800}
801
802void QQuickContainer::componentComplete()
803{
804 Q_D(QQuickContainer);
805 QQuickControl::componentComplete();
806 d->reorderItems();
807}
808
809void QQuickContainer::itemChange(ItemChange change, const ItemChangeData &data)
810{
811 Q_D(QQuickContainer);
812 QQuickControl::itemChange(change, value: data);
813 if (change == QQuickItem::ItemChildAddedChange && isComponentComplete() && data.item != d->background && data.item != d->contentItem) {
814 if (!QQuickItemPrivate::get(item: data.item)->isTransparentForPositioner() && d->contentModel->indexOf(object: data.item, objectContext: nullptr) == -1)
815 addItem(item: data.item);
816 }
817}
818
819void QQuickContainer::contentItemChange(QQuickItem *newItem, QQuickItem *oldItem)
820{
821 Q_D(QQuickContainer);
822 QQuickControl::contentItemChange(newItem, oldItem);
823
824 static const int slotIndex = metaObject()->indexOfSlot(slot: "_q_currentIndexChanged()");
825
826 if (oldItem) {
827 QQuickItemPrivate::get(item: oldItem)->removeItemChangeListener(d, types: QQuickItemPrivate::Children | QQuickItemPrivate::ImplicitWidth | QQuickItemPrivate::ImplicitHeight);
828 QQuickItem *oldContentItem = effectiveContentItem(item: oldItem);
829 if (oldContentItem != oldItem)
830 QQuickItemPrivate::get(item: oldContentItem)->removeItemChangeListener(d, types: QQuickItemPrivate::Children);
831
832 int signalIndex = oldItem->metaObject()->indexOfSignal(signal: "currentIndexChanged()");
833 if (signalIndex != -1)
834 QMetaObject::disconnect(sender: oldItem, signal_index: signalIndex, receiver: this, method_index: slotIndex);
835 }
836
837 if (newItem) {
838 QQuickItemPrivate::get(item: newItem)->addItemChangeListener(listener: d, types: QQuickItemPrivate::Children | QQuickItemPrivate::ImplicitWidth | QQuickItemPrivate::ImplicitHeight);
839 QQuickItem *newContentItem = effectiveContentItem(item: newItem);
840 if (newContentItem != newItem)
841 QQuickItemPrivate::get(item: newContentItem)->addItemChangeListener(listener: d, types: QQuickItemPrivate::Children);
842
843 int signalIndex = newItem->metaObject()->indexOfSignal(signal: "currentIndexChanged()");
844 if (signalIndex != -1)
845 QMetaObject::connect(sender: newItem, signal_index: signalIndex, receiver: this, method_index: slotIndex);
846 }
847}
848
849bool QQuickContainer::isContent(QQuickItem *item) const
850{
851 // If the item has a QML context associated to it (it was created in QML),
852 // we add it to the content model. Otherwise, it's probably the default
853 // highlight item that is always created by the item views, which we need
854 // to exclude.
855 //
856 // TODO: Find a better way to identify/exclude the highlight item...
857 return qmlContext(item);
858}
859
860void QQuickContainer::itemAdded(int index, QQuickItem *item)
861{
862 Q_UNUSED(index);
863 Q_UNUSED(item);
864}
865
866void QQuickContainer::itemMoved(int index, QQuickItem *item)
867{
868 Q_UNUSED(index);
869 Q_UNUSED(item);
870}
871
872void QQuickContainer::itemRemoved(int index, QQuickItem *item)
873{
874 Q_UNUSED(index);
875 Q_UNUSED(item);
876}
877
878QT_END_NAMESPACE
879
880#include "moc_qquickcontainer_p.cpp"
881

source code of qtdeclarative/src/quicktemplates/qquickcontainer.cpp