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