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

Provided by KDAB

Privacy Policy
Start learning QML with our Intro Training
Find out more

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