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

source code of qtquickcontrols2/src/quicktemplates2/qquickcontainer.cpp