8#include <qabstractitemdelegate.h>
9#if QT_CONFIG(accessibility)
10#include <qaccessible.h>
12#include <qapplication.h>
13#include <qstylepainter.h>
16#if QT_CONFIG(draganddrop)
21#if QT_CONFIG(rubberband)
22#include <qrubberband.h>
24#include <qscrollbar.h>
26#include <private/qapplication_p.h>
27#include <private/qlistview_p.h>
28#include <private/qscrollbar_p.h>
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
96
97
98
99
100
103
104
105
106
107
108
109
112
113
114
115
117
118
121
122
123
124
125
128
129
130
131
132
133
136
137
138
139
142
143
144
145QListView::QListView(QWidget *parent)
146 : QAbstractItemView(*
new QListViewPrivate, parent)
148 setViewMode(ListMode);
149 setSelectionMode(SingleSelection);
150 setAttribute(Qt::WA_MacShowFocusRect);
152 d->updateStyledFrameWidths();
156
157
158QListView::QListView(QListViewPrivate &dd, QWidget *parent)
159 : QAbstractItemView(dd, parent)
161 setViewMode(ListMode);
162 setSelectionMode(SingleSelection);
163 setAttribute(Qt::WA_MacShowFocusRect);
165 d->updateStyledFrameWidths();
169
170
171QListView::~QListView()
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194void QListView::setMovement(Movement movement)
197 d->modeProperties |= uint(QListViewPrivate::Movement);
198 d->movement = movement;
200#if QT_CONFIG(draganddrop)
201 bool movable = (movement != Static);
202 setDragEnabled(movable);
203 d->viewport->setAcceptDrops(movable);
205 d->doDelayedItemsLayout();
208QListView::Movement QListView::movement()
const
210 Q_D(
const QListView);
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231void QListView::setFlow(Flow flow)
234 d->modeProperties |= uint(QListViewPrivate::Flow);
236 d->doDelayedItemsLayout();
239QListView::Flow QListView::flow()
const
241 Q_D(
const QListView);
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260void QListView::setWrapping(
bool enable)
263 d->modeProperties |= uint(QListViewPrivate::Wrap);
264 d->setWrapping(enable);
265 d->doDelayedItemsLayout();
268bool QListView::isWrapping()
const
270 Q_D(
const QListView);
271 return d->isWrapping();
275
276
277
278
279
280
281
282
283
284
285
286void QListView::setResizeMode(ResizeMode mode)
289 d->modeProperties |= uint(QListViewPrivate::ResizeMode);
290 d->resizeMode = mode;
293QListView::ResizeMode QListView::resizeMode()
const
295 Q_D(
const QListView);
296 return d->resizeMode;
300
301
302
303
304
305
306
307
308
309
310
311
312void QListView::setLayoutMode(LayoutMode mode)
315 d->layoutMode = mode;
318QListView::LayoutMode QListView::layoutMode()
const
320 Q_D(
const QListView);
321 return d->layoutMode;
325
326
327
328
329
330
331
332
333
334
335
336
337
338void QListView::setSpacing(
int space)
341 d->modeProperties |= uint(QListViewPrivate::Spacing);
342 d->setSpacing(space);
343 d->doDelayedItemsLayout();
346int QListView::spacing()
const
348 Q_D(
const QListView);
353
354
355
356
357
358
360void QListView::setBatchSize(
int batchSize)
363 if (Q_UNLIKELY(batchSize <= 0)) {
364 qWarning(
"Invalid batchSize (%d)", batchSize);
367 d->batchSize = batchSize;
370int QListView::batchSize()
const
372 Q_D(
const QListView);
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391void QListView::setGridSize(
const QSize &size)
394 d->modeProperties |= uint(QListViewPrivate::GridSize);
395 d->setGridSize(size);
396 d->doDelayedItemsLayout();
399QSize QListView::gridSize()
const
401 Q_D(
const QListView);
402 return d->gridSize();
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420void QListView::setViewMode(ViewMode mode)
423 if (d->commonListView && d->viewMode == mode)
427 delete d->commonListView;
428 if (mode == ListMode) {
429 d->commonListView =
new QListModeViewBase(
this, d);
430 if (!(d->modeProperties & QListViewPrivate::Wrap))
431 d->setWrapping(
false);
432 if (!(d->modeProperties & QListViewPrivate::Spacing))
434 if (!(d->modeProperties & QListViewPrivate::GridSize))
435 d->setGridSize(QSize());
436 if (!(d->modeProperties & QListViewPrivate::Flow))
437 d->flow = TopToBottom;
438 if (!(d->modeProperties & QListViewPrivate::Movement))
439 d->movement = Static;
440 if (!(d->modeProperties & QListViewPrivate::ResizeMode))
441 d->resizeMode = Fixed;
442 if (!(d->modeProperties & QListViewPrivate::SelectionRectVisible))
443 d->showElasticBand =
false;
445 d->commonListView =
new QIconModeViewBase(
this, d);
446 if (!(d->modeProperties & QListViewPrivate::Wrap))
447 d->setWrapping(
true);
448 if (!(d->modeProperties & QListViewPrivate::Spacing))
450 if (!(d->modeProperties & QListViewPrivate::GridSize))
451 d->setGridSize(QSize());
452 if (!(d->modeProperties & QListViewPrivate::Flow))
453 d->flow = LeftToRight;
454 if (!(d->modeProperties & QListViewPrivate::Movement))
456 if (!(d->modeProperties & QListViewPrivate::ResizeMode))
457 d->resizeMode = Fixed;
458 if (!(d->modeProperties & QListViewPrivate::SelectionRectVisible))
459 d->showElasticBand =
true;
462#if QT_CONFIG(draganddrop)
463 bool movable = (d->movement != Static);
464 setDragEnabled(movable);
465 setAcceptDrops(movable);
468 d->doDelayedItemsLayout();
471QListView::ViewMode QListView::viewMode()
const
473 Q_D(
const QListView);
478
479
480
481
482
483
484
485
486void QListView::clearPropertyFlags()
489 d->modeProperties = 0;
493
494
495bool QListView::isRowHidden(
int row)
const
497 Q_D(
const QListView);
498 return d->isHidden(row);
502
503
504
505void QListView::setRowHidden(
int row,
bool hide)
508 const bool hidden = d->isHidden(row);
510 d->commonListView->appendHiddenRow(row);
511 else if (!hide && hidden)
512 d->commonListView->removeHiddenRow(row);
513 d->doDelayedItemsLayout();
514 d->viewport->update();
518
519
520QRect QListView::visualRect(
const QModelIndex &index)
const
522 Q_D(
const QListView);
523 return d->mapToViewport(rectForIndex(index));
527
528
529void QListView::scrollTo(
const QModelIndex &index, ScrollHint hint)
533 if (index.parent() != d->root || index.column() != d->column)
536 const QRect rect = visualRect(index);
539 if (hint == EnsureVisible && d->viewport->rect().contains(rect)) {
540 d->viewport->update(rect);
544 if (d->flow == QListView::TopToBottom || d->isWrapping())
545 verticalScrollBar()->setValue(d->verticalScrollToValue(index, rect, hint));
547 if (d->flow == QListView::LeftToRight || d->isWrapping())
548 horizontalScrollBar()->setValue(d->horizontalScrollToValue(index, rect, hint));
551int QListViewPrivate::horizontalScrollToValue(
const QModelIndex &index,
const QRect &rect,
552 QListView::ScrollHint hint)
const
554 Q_Q(
const QListView);
555 const QRect area = viewport->rect();
556 const bool leftOf = q->isRightToLeft()
557 ? (rect.left() < area.left()) && (rect.right() < area.right())
558 : rect.left() < area.left();
559 const bool rightOf = q->isRightToLeft()
560 ? rect.right() > area.right()
561 : (rect.right() > area.right()) && (rect.left() > area.left());
562 return commonListView->horizontalScrollToValue(q->visualIndex(index), hint, leftOf, rightOf, area, rect);
565int QListViewPrivate::verticalScrollToValue(
const QModelIndex &index,
const QRect &rect,
566 QListView::ScrollHint hint)
const
568 Q_Q(
const QListView);
569 const QRect area = viewport->rect();
570 const bool above = (hint == QListView::EnsureVisible && rect.top() < area.top());
571 const bool below = (hint == QListView::EnsureVisible && rect.bottom() > area.bottom());
572 return commonListView->verticalScrollToValue(q->visualIndex(index), hint, above, below, area, rect);
575void QListViewPrivate::selectAll(QItemSelectionModel::SelectionFlags command)
580 QItemSelection selection;
583 const int colCount = model->columnCount(root);
584 const int rowCount = model->rowCount(root);
585 for ( ; row < rowCount; ++row) {
588 if (topLeft.isValid()) {
589 QModelIndex bottomRight = model->index(row - 1, colCount - 1, root);
590 selection.append(QItemSelectionRange(topLeft, bottomRight));
591 topLeft = QModelIndex();
596 if (!topLeft.isValid())
597 topLeft = model->index(row, 0, root);
600 if (topLeft.isValid()) {
602 QModelIndex bottomRight = model->index(row - 1, colCount - 1, root);
603 selection.append(QItemSelectionRange(topLeft, bottomRight));
606 if (!selection.isEmpty())
607 selectionModel->select(selection, command);
611
612
613
614
615
616QItemViewPaintPairs QListViewPrivate::draggablePaintPairs(
const QModelIndexList &indexes, QRect *r)
const
619 Q_Q(
const QListView);
621 const QRect viewportRect = viewport->rect();
622 QItemViewPaintPairs ret;
623 QList<QModelIndex> visibleIndexes =
624 intersectingSet(viewportRect.translated(q->horizontalOffset(), q->verticalOffset()));
625 std::sort(visibleIndexes.begin(), visibleIndexes.end());
626 for (
const auto &index : indexes) {
627 if (std::binary_search(visibleIndexes.cbegin(), visibleIndexes.cend(), index)) {
628 const QRect current = q->visualRect(index);
629 ret.append({current, index});
633 QRect clipped = rect & viewportRect;
634 rect.setLeft(clipped.left());
635 rect.setRight(clipped.right());
640
641
642void QListView::reset()
646 d->hiddenRows.clear();
647 QAbstractItemView::reset();
651
652
653void QListView::setRootIndex(
const QModelIndex &index)
656 d->column = qMax(0, qMin(d->column, d->model->columnCount(index) - 1));
657 QAbstractItemView::setRootIndex(index);
660 d->hiddenRows.clear();
664
665
666
667
669void QListView::scrollContentsBy(
int dx,
int dy)
672 d->delayedAutoScroll.stop();
673 d->commonListView->scrollContentsBy(dx, dy, d->state == QListView::DragSelectingState);
677
678
679
680
681
682void QListView::resizeContents(
int width,
int height)
685 d->setContentsSize(width, height);
689
690
691QSize QListView::contentsSize()
const
693 Q_D(
const QListView);
694 return d->contentsSize();
698
699
700void QListView::dataChanged(
const QModelIndex &topLeft,
const QModelIndex &bottomRight,
701 const QList<
int> &roles)
703 d_func()->commonListView->dataChanged(topLeft, bottomRight);
704 QAbstractItemView::dataChanged(topLeft, bottomRight, roles);
708
709
710void QListView::rowsInserted(
const QModelIndex &parent,
int start,
int end)
715 d->doDelayedItemsLayout();
716 QAbstractItemView::rowsInserted(parent, start, end);
720
721
722void QListView::rowsAboutToBeRemoved(
const QModelIndex &parent,
int start,
int end)
726 QAbstractItemView::rowsAboutToBeRemoved(parent, start, end);
727 if (parent == d->root) {
728 QSet<QPersistentModelIndex>::iterator it = d->hiddenRows.begin();
729 while (it != d->hiddenRows.end()) {
730 int hiddenRow = it->row();
731 if (hiddenRow >= start && hiddenRow <= end) {
732 it = d->hiddenRows.erase(it);
739 d->doDelayedItemsLayout();
743
744
745void QListView::mouseMoveEvent(QMouseEvent *e)
750 QAbstractItemView::mouseMoveEvent(e);
751 if (state() == DragSelectingState
752 && d->showElasticBand
753 && d->selectionMode != SingleSelection
754 && d->selectionMode != NoSelection) {
755 QRect rect(d->pressedPosition, e->position().toPoint() + QPoint(horizontalOffset(), verticalOffset()));
756 rect = rect.normalized();
757 const int margin = 2 * style()->pixelMetric(QStyle::PM_DefaultFrameWidth);
758 const QRect viewPortRect = rect.united(d->elasticBand)
759 .adjusted(-margin, -margin, margin, margin);
760 d->viewport->update(d->mapToViewport(viewPortRect));
761 d->elasticBand = rect;
766
767
768void QListView::mouseReleaseEvent(QMouseEvent *e)
771 QAbstractItemView::mouseReleaseEvent(e);
773 if (d->showElasticBand && d->elasticBand.isValid()) {
774 const int margin = 2 * style()->pixelMetric(QStyle::PM_DefaultFrameWidth);
775 const QRect viewPortRect = d->elasticBand.adjusted(-margin, -margin, margin, margin);
776 d->viewport->update(d->mapToViewport(viewPortRect));
777 d->elasticBand = QRect();
781#if QT_CONFIG(wheelevent)
783
784
785void QListView::wheelEvent(QWheelEvent *e)
788 if (qAbs(e->angleDelta().y()) > qAbs(e->angleDelta().x())) {
789 if (e->angleDelta().x() == 0
790 && ((d->flow == TopToBottom && d->wrap) || (d->flow == LeftToRight && !d->wrap))
791 && d->vbar->minimum() == 0 && d->vbar->maximum() == 0) {
792 QPoint pixelDelta(e->pixelDelta().y(), e->pixelDelta().x());
793 QPoint angleDelta(e->angleDelta().y(), e->angleDelta().x());
794 QWheelEvent hwe(e->position(), e->globalPosition(), pixelDelta, angleDelta,
795 e->buttons(), e->modifiers(), e->phase(), e->inverted(), e->source());
796 if (e->spontaneous())
797 qt_sendSpontaneousEvent(d->hbar, &hwe);
799 QCoreApplication::sendEvent(d->hbar, &hwe);
800 e->setAccepted(hwe.isAccepted());
802 QCoreApplication::sendEvent(d->vbar, e);
805 QCoreApplication::sendEvent(d->hbar, e);
811
812
813void QListView::timerEvent(QTimerEvent *e)
816 if (e->timerId() == d->batchLayoutTimer.timerId()) {
817 if (d->doItemsLayout(d->batchSize)) {
818 d->batchLayoutTimer.stop();
820 d->viewport->update();
823 QAbstractItemView::timerEvent(e);
827
828
829void QListView::resizeEvent(QResizeEvent *e)
832 if (d->delayedPendingLayout)
835 QSize delta = e->size() - e->oldSize();
840 bool listWrap = (d->viewMode == ListMode) && d->wrapItemText;
841 bool flowDimensionChanged = (d->flow == LeftToRight && delta.width() != 0)
842 || (d->flow == TopToBottom && delta.height() != 0);
848 || (state() == NoState && d->resizeMode == Adjust && flowDimensionChanged)) {
849 d->doDelayedItemsLayout(100);
851 QAbstractItemView::resizeEvent(e);
855#if QT_CONFIG(draganddrop)
858
859
860void QListView::dragMoveEvent(QDragMoveEvent *e)
863 if (!d->commonListView->filterDragMoveEvent(e)) {
864 if (viewMode() == QListView::ListMode && flow() == QListView::LeftToRight)
865 static_cast<QListModeViewBase *>(d->commonListView)->dragMoveEvent(e);
867 QAbstractItemView::dragMoveEvent(e);
873
874
875void QListView::dragLeaveEvent(QDragLeaveEvent *e)
877 if (!d_func()->commonListView->filterDragLeaveEvent(e))
878 QAbstractItemView::dragLeaveEvent(e);
882
883
884void QListView::dropEvent(QDropEvent *event)
888 const bool moveAction = event->dropAction() == Qt::MoveAction
889 || dragDropMode() == QAbstractItemView::InternalMove;
890 if (event->source() ==
this && moveAction) {
891 QModelIndex topIndex;
892 bool topIndexDropped =
false;
896 if (!event->isAccepted() && d->dropOn(event, &row, &col, &topIndex)) {
897 const QList<QModelIndex> selIndexes = selectedIndexes();
898 QList<QPersistentModelIndex> persIndexes;
899 persIndexes.reserve(selIndexes.size());
901 for (
const auto &index : selIndexes) {
902 persIndexes.append(index);
903 if (index == topIndex) {
904 topIndexDropped =
true;
909 if (!topIndexDropped && !topIndex.isValid()) {
910 std::sort(persIndexes.begin(), persIndexes.end());
912 QPersistentModelIndex dropRow = model()->index(row, col, topIndex);
914 int r = row == -1 ? model()->rowCount() : (dropRow.row() >= 0 ? dropRow.row() : row);
915 bool dataMoved =
false;
916 for (
const QPersistentModelIndex &pIndex : std::as_const(persIndexes)) {
918 if (r != pIndex.row() && r != pIndex.row() + 1) {
920 const bool moved = model()->moveRow(QModelIndex(), pIndex.row(), QModelIndex(), r);
928 r = pIndex.row() + 1;
937 if (event->isAccepted())
938 d->dropEventMoved =
true;
941 if (!d->commonListView->filterDropEvent(event) || !d->dropEventMoved) {
943 if (!d->dropEventMoved && moveAction)
945 QAbstractItemView::dropEvent(event);
950
951
952void QListView::startDrag(Qt::DropActions supportedActions)
954 if (!d_func()->commonListView->filterStartDrag(supportedActions))
955 QAbstractItemView::startDrag(supportedActions);
961
962
963void QListView::initViewItemOption(QStyleOptionViewItem *option)
const
965 Q_D(
const QListView);
966 QAbstractItemView::initViewItemOption(option);
967 if (!d->iconSize.isValid()) {
968 int pm = (d->viewMode == QListView::ListMode
969 ? style()->pixelMetric(QStyle::PM_ListViewIconSize,
nullptr,
this)
970 : style()->pixelMetric(QStyle::PM_IconViewIconSize,
nullptr,
this));
971 option->decorationSize = QSize(pm, pm);
973 if (d->viewMode == QListView::IconMode) {
974 option->showDecorationSelected =
false;
975 option->decorationPosition = QStyleOptionViewItem::Top;
976 option->displayAlignment = Qt::AlignCenter;
978 option->decorationPosition = QStyleOptionViewItem::Left;
981 if (d->gridSize().isValid()) {
982 option->rect.setSize(d->gridSize());
984 option->viewItemPosition = QStyleOptionViewItem::OnlyOne;
989
990
991void QListView::paintEvent(QPaintEvent *e)
994 if (!d->itemDelegate)
996 QStyleOptionViewItem option;
997 initViewItemOption(&option);
998 QStylePainter painter(d->viewport);
1000 const QList<QModelIndex> toBeRendered =
1001 d->intersectingSet(e->rect().translated(horizontalOffset(), verticalOffset()),
false);
1003 const QModelIndex current = currentIndex();
1004 const QModelIndex hover = d->hover;
1005 const QAbstractItemModel *itemModel = d->model;
1006 const QItemSelectionModel *selections = d->selectionModel;
1007 const bool focus = (hasFocus() || d->viewport->hasFocus()) && current.isValid();
1008 const bool alternate = d->alternatingColors;
1009 const QStyle::State state = option.state;
1010 const QAbstractItemView::State viewState =
this->state();
1011 const bool enabled = (state & QStyle::State_Enabled) != 0;
1013 bool alternateBase =
false;
1014 int previousRow = -2;
1016 int maxSize = (flow() == TopToBottom)
1017 ? qMax(viewport()->size().width(), d->contentsSize().width()) - 2 * d->spacing()
1018 : qMax(viewport()->size().height(), d->contentsSize().height()) - 2 * d->spacing();
1020 QList<QModelIndex>::const_iterator end = toBeRendered.constEnd();
1021 for (QList<QModelIndex>::const_iterator it = toBeRendered.constBegin(); it != end; ++it) {
1022 Q_ASSERT((*it).isValid());
1023 option.rect = visualRect(*it);
1025 if (flow() == TopToBottom)
1026 option.rect.setWidth(qMin(maxSize, option.rect.width()));
1028 option.rect.setHeight(qMin(maxSize, option.rect.height()));
1030 option.state = state;
1031 if (selections && selections->isSelected(*it))
1032 option.state |= QStyle::State_Selected;
1034 QPalette::ColorGroup cg;
1035 if ((itemModel->flags(*it) & Qt::ItemIsEnabled) == 0) {
1036 option.state &= ~QStyle::State_Enabled;
1037 cg = QPalette::Disabled;
1039 cg = QPalette::Normal;
1041 option.palette.setCurrentColorGroup(cg);
1043 if (focus && current == *it) {
1044 option.state |= QStyle::State_HasFocus;
1045 if (viewState == EditingState)
1046 option.state |= QStyle::State_Editing;
1048 option.state.setFlag(QStyle::State_MouseOver, *it == hover);
1051 int row = (*it).row();
1052 if (row != previousRow + 1) {
1054 if (!d->hiddenRows.isEmpty()) {
1055 for (
int r = qMax(previousRow + 1, 0); r < row; ++r) {
1056 if (!d->isHidden(r))
1057 alternateBase = !alternateBase;
1060 alternateBase = (row & 1) != 0;
1063 option.features.setFlag(QStyleOptionViewItem::Alternate, alternateBase);
1067 QStyle::State oldState = option.state;
1068 option.state &= ~QStyle::State_Selected;
1069 painter.drawPrimitive(QStyle::PE_PanelItemViewRow, option);
1070 option.state = oldState;
1072 alternateBase = !alternateBase;
1076 itemDelegateForIndex(*it)->paint(&painter, option, *it);
1079#if QT_CONFIG(draganddrop)
1080 d->commonListView->paintDragDrop(&painter);
1083#if QT_CONFIG(rubberband)
1085 if (d->showElasticBand && d->elasticBand.isValid()) {
1086 QStyleOptionRubberBand opt;
1088 opt.shape = QRubberBand::Rectangle;
1090 opt.rect = d->mapToViewport(d->elasticBand,
false).intersected(
1091 d->viewport->rect().adjusted(-16, -16, 16, 16));
1093 painter.drawControl(QStyle::CE_RubberBand, opt);
1100
1101
1102QModelIndex QListView::indexAt(
const QPoint &p)
const
1104 Q_D(
const QListView);
1105 QRect rect(p.x() + horizontalOffset(), p.y() + verticalOffset(), 1, 1);
1106 const QList<QModelIndex> intersectVector = d->intersectingSet(rect);
1107 QModelIndex index = intersectVector.size() > 0
1108 ? intersectVector.last() : QModelIndex();
1109 if (index.isValid() && visualRect(index).contains(p))
1111 return QModelIndex();
1115
1116
1117int QListView::horizontalOffset()
const
1119 return d_func()->commonListView->horizontalOffset();
1123
1124
1125int QListView::verticalOffset()
const
1127 return d_func()->commonListView->verticalOffset();
1131
1132
1133QModelIndex QListView::moveCursor(CursorAction cursorAction, Qt::KeyboardModifiers modifiers)
1136 Q_UNUSED(modifiers);
1138 auto findAvailableRowBackward = [d](
int row) {
1139 while (row >= 0 && d->isHiddenOrDisabled(row))
1144 auto findAvailableRowForward = [d](
int row) {
1145 int rowCount = d->model->rowCount(d->root);
1148 while (row < rowCount && d->isHiddenOrDisabled(row))
1150 if (row >= rowCount)
1155 QModelIndex current = currentIndex();
1156 if (!current.isValid()) {
1157 int row = findAvailableRowForward(0);
1159 return QModelIndex();
1160 return d->model->index(row, d->column, d->root);
1163 if ((d->flow == LeftToRight && cursorAction == MoveLeft) ||
1164 (d->flow == TopToBottom && (cursorAction == MoveUp || cursorAction == MovePrevious))) {
1165 const int row = findAvailableRowBackward(current.row() - 1);
1168 return d->model->index(row, d->column, d->root);
1169 }
else if ((d->flow == LeftToRight && cursorAction == MoveRight) ||
1170 (d->flow == TopToBottom && (cursorAction == MoveDown || cursorAction == MoveNext))) {
1171 const int row = findAvailableRowForward(current.row() + 1);
1174 return d->model->index(row, d->column, d->root);
1177 const QRect initialRect = rectForIndex(current);
1178 QRect rect = initialRect;
1179 if (rect.isEmpty()) {
1180 return d->model->index(0, d->column, d->root);
1182 if (d->gridSize().isValid()) rect.setSize(d->gridSize());
1184 QSize contents = d->contentsSize();
1185 QList<QModelIndex> intersectVector;
1187 switch (cursorAction) {
1189 while (intersectVector.isEmpty()) {
1190 rect.translate(-rect.width(), 0);
1191 if (rect.right() <= 0)
1193 if (rect.left() < 0)
1195 intersectVector = d->intersectingSet(rect);
1196 d->removeCurrentAndDisabled(&intersectVector, current);
1198 return d->closestIndex(initialRect, intersectVector);
1200 while (intersectVector.isEmpty()) {
1201 rect.translate(rect.width(), 0);
1202 if (rect.left() >= contents.width())
1204 if (rect.right() > contents.width())
1205 rect.setRight(contents.width());
1206 intersectVector = d->intersectingSet(rect);
1207 d->removeCurrentAndDisabled(&intersectVector, current);
1209 return d->closestIndex(initialRect, intersectVector);
1211 if (rect.height() >= d->viewport->height())
1212 return moveCursor(QAbstractItemView::MoveUp, modifiers);
1214 rect.moveTop(rect.top() - d->viewport->height() + 1);
1215 if (rect.top() < rect.height()) {
1219 QModelIndex findindex = current;
1220 while (intersectVector.isEmpty()
1221 || rectForIndex(findindex).top() <= (rectForIndex(current).bottom() - d->viewport->rect().height())
1222 || rect.top() <= 0) {
1223 rect.translate(0, 1);
1224 if (rect.bottom() <= 0) {
1227 intersectVector = d->intersectingSet(rect);
1228 findindex = d->closestIndex(initialRect, intersectVector);
1234 while (intersectVector.isEmpty()) {
1235 rect.translate(0, -rect.height());
1236 if (rect.bottom() <= 0) {
1237#ifdef QT_KEYPAD_NAVIGATION
1238 if (QApplicationPrivate::keypadNavigationEnabled()) {
1239 int row = d->batchStartRow() - 1;
1240 while (row >= 0 && d->isHiddenOrDisabled(row))
1243 return d->model->index(row, d->column, d->root);
1250 intersectVector = d->intersectingSet(rect);
1251 d->removeCurrentAndDisabled(&intersectVector, current);
1253 return d->closestIndex(initialRect, intersectVector);
1254 case MovePageDown: {
1255 if (rect.height() >= d->viewport->height())
1256 return moveCursor(QAbstractItemView::MoveDown, modifiers);
1258 rect.moveTop(rect.top() + d->viewport->height() - 1);
1259 if (rect.bottom() > contents.height() - rect.height()) {
1260 rect.setTop(contents.height() - 1);
1261 rect.setBottom(contents.height());
1263 QModelIndex index = current;
1265 while (intersectVector.isEmpty()
1266 || rectForIndex(index).bottom() >= (d->viewport->rect().height() + rectForIndex(current).top())
1267 || rect.bottom() > contents.height()) {
1268 rect.translate(0, -1);
1269 if (rect.top() >= contents.height()) {
1272 intersectVector = d->intersectingSet(rect);
1273 index = d->closestIndex(initialRect, intersectVector);
1279 while (intersectVector.isEmpty()) {
1280 rect.translate(0, rect.height());
1281 if (rect.top() >= contents.height()) {
1282#ifdef QT_KEYPAD_NAVIGATION
1283 if (QApplicationPrivate::keypadNavigationEnabled()) {
1284 int rowCount = d->model->rowCount(d->root);
1286 while (row < rowCount && d->isHiddenOrDisabled(row))
1289 return d->model->index(row, d->column, d->root);
1294 if (rect.bottom() > contents.height())
1295 rect.setBottom(contents.height());
1296 intersectVector = d->intersectingSet(rect);
1297 d->removeCurrentAndDisabled(&intersectVector, current);
1299 return d->closestIndex(initialRect, intersectVector);
1301 return d->model->index(0, d->column, d->root);
1303 return d->model->index(d->batchStartRow() - 1, d->column, d->root);}
1309
1310
1311
1312
1313
1314QRect QListView::rectForIndex(
const QModelIndex &index)
const
1316 return d_func()->rectForIndex(index);
1320
1321
1322
1323
1324
1325void QListView::setPositionForIndex(
const QPoint &position,
const QModelIndex &index)
1328 if (d->movement == Static
1329 || !d->isIndexValid(index)
1330 || index.parent() != d->root
1331 || index.column() != d->column)
1334 d->executePostedLayout();
1335 d->commonListView->setPositionForIndex(position, index);
1339
1340
1341void QListView::setSelection(
const QRect &rect, QItemSelectionModel::SelectionFlags command)
1344 if (!d->selectionModel)
1348 int w = qMax(d->contentsSize().width(), d->viewport->width());
1349 int h = qMax(d->contentsSize().height(), d->viewport->height());
1350 if (d->wrap && !QRect(0, 0, w, h).intersects(rect))
1353 QItemSelection selection;
1355 if (rect.width() == 1 && rect.height() == 1) {
1356 const QList<QModelIndex> intersectVector =
1357 d->intersectingSet(rect.translated(horizontalOffset(), verticalOffset()));
1359 if (!intersectVector.isEmpty())
1360 tl = intersectVector.last();
1361 if (tl.isValid() && d->isIndexEnabled(tl))
1362 selection.select(tl, tl);
1364 if (state() == DragSelectingState) {
1365 selection = d->selection(rect.translated(horizontalOffset(), verticalOffset()));
1369 const QRect topLeft(rect.left() + horizontalOffset(), rect.top() + verticalOffset(), 1, 1);
1370 QList<QModelIndex> intersectVector = d->intersectingSet(topLeft);
1371 if (!intersectVector.isEmpty())
1372 tl = intersectVector.last();
1374 const QRect bottomRight(rect.right() + horizontalOffset(), rect.bottom() + verticalOffset(), 1, 1);
1375 intersectVector = d->intersectingSet(bottomRight);
1376 if (!intersectVector.isEmpty())
1377 br = intersectVector.last();
1380 if (tl.isValid() && br.isValid()
1381 && d->isIndexEnabled(tl)
1382 && d->isIndexEnabled(br)) {
1383 QRect first = d->cellRectForIndex(tl);
1384 QRect last = d->cellRectForIndex(br);
1386 if (d->flow == LeftToRight) {
1388 QRect &bottom = last;
1390 if (top.center().y() > bottom.center().y()) {
1396 if (top.top() != bottom.top()) {
1398 if (isRightToLeft())
1401 top.setRight(contentsSize().width());
1403 if (isRightToLeft())
1404 bottom.setRight(contentsSize().width());
1407 }
else if (top.left() > bottom.right()) {
1408 if (isRightToLeft())
1409 bottom.setLeft(top.right());
1411 bottom.setRight(top.left());
1413 if (isRightToLeft())
1414 top.setLeft(bottom.right());
1416 top.setRight(bottom.left());
1419 if (top.bottom() < bottom.top()) {
1420 if (gridSize().isValid() && !gridSize().isNull())
1421 middle.setTop(top.top() + gridSize().height());
1423 middle.setTop(top.bottom() + 1);
1424 middle.setLeft(qMin(top.left(), bottom.left()));
1425 middle.setBottom(bottom.top() - 1);
1426 middle.setRight(qMax(top.right(), bottom.right()));
1429 QRect &left = first;
1430 QRect &right = last;
1431 if (left.center().x() > right.center().x())
1434 int ch = contentsSize().height();
1435 if (left.left() != right.left()) {
1437 if (isRightToLeft())
1443 if (isRightToLeft())
1444 right.setBottom(ch);
1449 middle.setBottom(ch);
1450 if (gridSize().isValid() && !gridSize().isNull())
1451 middle.setLeft(left.left() + gridSize().width());
1453 middle.setLeft(left.right() + 1);
1454 middle.setRight(right.left() - 1);
1455 }
else if (left.bottom() < right.top()) {
1456 left.setBottom(right.top() - 1);
1458 right.setBottom(left.top() - 1);
1463 QItemSelection topSelection = d->selection(first);
1464 QItemSelection middleSelection = d->selection(middle);
1465 QItemSelection bottomSelection = d->selection(last);
1467 selection.merge(topSelection, QItemSelectionModel::Select);
1468 selection.merge(middleSelection, QItemSelectionModel::Select);
1469 selection.merge(bottomSelection, QItemSelectionModel::Select);
1474 d->selectionModel->select(selection, command);
1478
1479
1480
1481
1482
1483QRegion QListView::visualRegionForSelection(
const QItemSelection &selection)
const
1485 Q_D(
const QListView);
1488 QRegion selectionRegion;
1489 const QRect &viewportRect = d->viewport->rect();
1490 for (
const auto &elem : selection) {
1491 if (!elem.isValid())
1493 QModelIndex parent = elem.topLeft().parent();
1496 if (parent != d->root)
1498 int t = elem.topLeft().row();
1499 int b = elem.bottomRight().row();
1500 if (d->viewMode == IconMode || d->isWrapping()) {
1501 for (
int r = t; r <= b; ++r) {
1502 const QRect &rect = visualRect(d->model->index(r, c, parent));
1503 if (viewportRect.intersects(rect))
1504 selectionRegion += rect;
1507 while (t <= b && d->isHidden(t)) ++t;
1508 while (b >= t && d->isHidden(b)) --b;
1509 const QModelIndex top = d->model->index(t, c, parent);
1510 const QModelIndex bottom = d->model->index(b, c, parent);
1511 QRect rect(visualRect(top).topLeft(),
1512 visualRect(bottom).bottomRight());
1513 if (viewportRect.intersects(rect))
1514 selectionRegion += rect;
1518 return selectionRegion;
1522
1523
1524QModelIndexList QListView::selectedIndexes()
const
1526 Q_D(
const QListView);
1527 if (!d->selectionModel)
1528 return QModelIndexList();
1530 QModelIndexList viewSelected = d->selectionModel->selectedIndexes();
1531 auto ignorable = [
this, d](
const QModelIndex &index) {
1532 return index.column() != d->column || index.parent() != d->root || isIndexHidden(index);
1534 viewSelected.removeIf(ignorable);
1535 return viewSelected;
1539
1540
1541
1542
1543void QListView::doItemsLayout()
1549 QAbstractItemView::State oldState = state();
1550 setState(ExpandingState);
1551 if (d->model->columnCount(d->root) > 0) {
1552 d->resetBatchStartRow();
1553 if (layoutMode() == SinglePass) {
1554 d->doItemsLayout(d->model->rowCount(d->root));
1555 }
else if (!d->batchLayoutTimer.isActive()) {
1556 if (!d->doItemsLayout(d->batchSize))
1557 d->batchLayoutTimer.start(0,
this);
1562 QAbstractItemView::doItemsLayout();
1567
1568
1569void QListView::updateGeometries()
1572 if (geometry().isEmpty() || d->model->rowCount(d->root) <= 0 || d->model->columnCount(d->root) <= 0) {
1573 horizontalScrollBar()->setRange(0, 0);
1574 verticalScrollBar()->setRange(0, 0);
1576 QModelIndex index = d->model->index(0, d->column, d->root);
1577 QStyleOptionViewItem option;
1578 initViewItemOption(&option);
1579 QSize step = d->itemSize(option, index);
1580 d->commonListView->updateHorizontalScrollBar(step);
1581 d->commonListView->updateVerticalScrollBar(step);
1584 QAbstractItemView::updateGeometries();
1587 if (d->movement == Static && !d->isWrapping()) {
1588 d->layoutChildren();
1589 if (d->flow == TopToBottom) {
1590 if (horizontalScrollBarPolicy() == Qt::ScrollBarAlwaysOff) {
1591 d->setContentsSize(viewport()->width(), contentsSize().height());
1592 horizontalScrollBar()->setRange(0, 0);
1595 if (verticalScrollBarPolicy() == Qt::ScrollBarAlwaysOff) {
1596 d->setContentsSize(contentsSize().width(), viewport()->height());
1597 verticalScrollBar()->setRange(0, 0);
1605
1606
1607bool QListView::isIndexHidden(
const QModelIndex &index)
const
1609 Q_D(
const QListView);
1610 return (d->isHidden(index.row())
1611 && (index.parent() == d->root)
1612 && index.column() == d->column);
1616
1617
1618
1619
1620
1621
1622void QListView::setModelColumn(
int column)
1625 if (column < 0 || column >= d->model->columnCount(d->root))
1628 d->doDelayedItemsLayout();
1629#if QT_CONFIG(accessibility)
1630 if (QAccessible::isActive()) {
1631 QAccessibleTableModelChangeEvent event(
this, QAccessibleTableModelChangeEvent::ModelReset);
1632 QAccessible::updateAccessibility(&event);
1637int QListView::modelColumn()
const
1639 Q_D(
const QListView);
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653void QListView::setUniformItemSizes(
bool enable)
1656 d->uniformItemSizes = enable;
1659bool QListView::uniformItemSizes()
const
1661 Q_D(
const QListView);
1662 return d->uniformItemSizes;
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678void QListView::setWordWrap(
bool on)
1681 if (d->wrapItemText == on)
1683 d->wrapItemText = on;
1684 d->doDelayedItemsLayout();
1687bool QListView::wordWrap()
const
1689 Q_D(
const QListView);
1690 return d->wrapItemText;
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707void QListView::setSelectionRectVisible(
bool show)
1710 d->modeProperties |= uint(QListViewPrivate::SelectionRectVisible);
1711 d->setSelectionRectVisible(show);
1714bool QListView::isSelectionRectVisible()
const
1716 Q_D(
const QListView);
1717 return d->isSelectionRectVisible();
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730void QListView::setItemAlignment(Qt::Alignment alignment)
1733 if (d->itemAlignment == alignment)
1735 d->itemAlignment = alignment;
1736 if (viewMode() == ListMode && flow() == QListView::TopToBottom && isWrapping())
1737 d->doDelayedItemsLayout();
1740Qt::Alignment QListView::itemAlignment()
const
1742 Q_D(
const QListView);
1743 return d->itemAlignment;
1747
1748
1749bool QListView::event(QEvent *e)
1751 return QAbstractItemView::event(e);
1755
1756
1758QListViewPrivate::QListViewPrivate()
1759 : QAbstractItemViewPrivate(),
1760 commonListView(
nullptr),
1763 flow(QListView::TopToBottom),
1764 movement(QListView::Static),
1765 resizeMode(QListView::Fixed),
1766 layoutMode(QListView::SinglePass),
1767 viewMode(QListView::ListMode),
1770 uniformItemSizes(
false),
1772 showElasticBand(
false),
1773 itemAlignment(Qt::Alignment())
1777QListViewPrivate::~QListViewPrivate()
1779 delete commonListView;
1782void QListViewPrivate::clear()
1785 cachedItemSize = QSize();
1786 commonListView->clear();
1789void QListViewPrivate::prepareItemsLayout()
1795 layoutBounds = QRect(QPoint(), q->maximumViewportSize());
1797 int frameAroundContents = 0;
1798 if (q->style()->styleHint(QStyle::SH_ScrollView_FrameOnlyAroundContents,
nullptr, q)) {
1799 QStyleOption option;
1801 frameAroundContents = q->style()->pixelMetric(QStyle::PM_DefaultFrameWidth, &option, q) * 2;
1807 int verticalMargin = (vbarpolicy == Qt::ScrollBarAsNeeded) && (flow == QListView::LeftToRight || vbar->isVisible())
1808 && !q->style()->pixelMetric(QStyle::PM_ScrollView_ScrollBarOverlap,
nullptr, vbar)
1809 ? q->style()->pixelMetric(QStyle::PM_ScrollBarExtent,
nullptr, vbar) + frameAroundContents
1811 int horizontalMargin = hbarpolicy==Qt::ScrollBarAsNeeded
1812 ? q->style()->pixelMetric(QStyle::PM_ScrollBarExtent,
nullptr, hbar) + frameAroundContents
1815 layoutBounds.adjust(0, 0, -verticalMargin, -horizontalMargin);
1817 int rowCount = model->columnCount(root) <= 0 ? 0 : model->rowCount(root);
1818 commonListView->setRowCount(rowCount);
1822
1823
1824bool QListViewPrivate::doItemsLayout(
int delta)
1826 int max = model->rowCount(root) - 1;
1827 int first = batchStartRow();
1828 int last = qMin(first + delta - 1, max);
1832 prepareItemsLayout();
1835 if (max < 0 || last < first) {
1839 QListViewLayoutInfo info;
1840 info.bounds = layoutBounds;
1841 info.grid = gridSize();
1842 info.spacing = (info.grid.isValid() ? 0 : spacing());
1845 info.wrap = isWrapping();
1849 return commonListView->doBatchedItemLayout(info, max);
1852QListViewItem QListViewPrivate::indexToListViewItem(
const QModelIndex &index)
const
1854 if (!index.isValid() || isHidden(index.row()))
1855 return QListViewItem();
1857 return commonListView->indexToListViewItem(index);
1860QRect QListViewPrivate::mapToViewport(
const QRect &rect,
bool extend)
const
1862 Q_Q(
const QListView);
1863 if (!rect.isValid())
1866 QRect result = extend ? commonListView->mapToViewport(rect) : rect;
1867 int dx = -q->horizontalOffset();
1868 int dy = -q->verticalOffset();
1869 return result.adjusted(dx, dy, dx, dy);
1872QModelIndex QListViewPrivate::closestIndex(
const QRect &target,
1873 const QList<QModelIndex> &candidates)
const
1876 int shortest = INT_MAX;
1877 QModelIndex closest;
1878 QList<QModelIndex>::const_iterator it = candidates.begin();
1880 for (; it != candidates.end(); ++it) {
1881 if (!(*it).isValid())
1884 const QRect indexRect = indexToListViewItem(*it).rect();
1889 if ((target.center().x() >= indexRect.x() && target.center().x() < indexRect.right())
1890 || (indexRect.center().x() >= target.x() && indexRect.center().x() < target.right())) {
1892 distance = qAbs(indexRect.center().y() - target.center().y());
1893 }
else if ((target.center().y() >= indexRect.y() && target.center().y() < indexRect.bottom())
1894 || (indexRect.center().y() >= target.y() && indexRect.center().y() < target.bottom())) {
1896 distance = qAbs(indexRect.center().x() - target.center().x());
1898 distance = (indexRect.center() - target.center()).manhattanLength();
1900 if (distance < shortest) {
1901 shortest = distance;
1908QSize QListViewPrivate::itemSize(
const QStyleOptionViewItem &option,
const QModelIndex &index)
const
1910 Q_Q(
const QListView);
1911 if (!uniformItemSizes) {
1912 const QAbstractItemDelegate *delegate = q->itemDelegateForIndex(index);
1913 return delegate ? delegate->sizeHint(option, index) : QSize();
1915 if (!cachedItemSize.isValid()) {
1916 int row = model->rowCount(root) - 1;
1917 QModelIndex sample = model->index(row, column, root);
1918 const QAbstractItemDelegate *delegate = q->itemDelegateForIndex(sample);
1919 cachedItemSize = delegate ? delegate->sizeHint(option, sample) : QSize();
1921 return cachedItemSize;
1924QItemSelection QListViewPrivate::selection(
const QRect &rect)
const
1926 QItemSelection selection;
1928 const QList<QModelIndex> intersectVector = intersectingSet(rect);
1929 QList<QModelIndex>::const_iterator it = intersectVector.begin();
1930 for (; it != intersectVector.end(); ++it) {
1931 if (!tl.isValid() && !br.isValid()) {
1933 }
else if ((*it).row() == (tl.row() - 1)) {
1935 }
else if ((*it).row() == (br.row() + 1)) {
1938 selection.select(tl, br);
1943 if (tl.isValid() && br.isValid())
1944 selection.select(tl, br);
1945 else if (tl.isValid())
1946 selection.select(tl, tl);
1947 else if (br.isValid())
1948 selection.select(br, br);
1953#if QT_CONFIG(draganddrop)
1954QAbstractItemView::DropIndicatorPosition QListViewPrivate::position(
const QPoint &pos,
const QRect &rect,
const QModelIndex &idx)
const
1956 if (viewMode == QListView::ListMode && flow == QListView::LeftToRight)
1957 return static_cast<QListModeViewBase *>(commonListView)->position(pos, rect, idx);
1959 return QAbstractItemViewPrivate::position(pos, rect, idx);
1962bool QListViewPrivate::dropOn(QDropEvent *event,
int *dropRow,
int *dropCol, QModelIndex *dropIndex)
1964 if (viewMode == QListView::ListMode && flow == QListView::LeftToRight)
1965 return static_cast<QListModeViewBase *>(commonListView)->dropOn(event, dropRow, dropCol, dropIndex);
1967 return QAbstractItemViewPrivate::dropOn(event, dropRow, dropCol, dropIndex);
1971void QListViewPrivate::removeCurrentAndDisabled(QList<QModelIndex> *indexes,
1972 const QModelIndex ¤t)
const
1974 auto isCurrentOrDisabled = [
this, current](
const QModelIndex &index) {
1975 return !isIndexEnabled(index) || index == current;
1977 indexes->removeIf(isCurrentOrDisabled);
1981
1982
1984void QCommonListViewBase::appendHiddenRow(
int row)
1986 dd->hiddenRows.insert(dd->model->index(row, 0, qq->rootIndex()));
1989void QCommonListViewBase::removeHiddenRow(
int row)
1991 dd->hiddenRows.remove(dd->model->index(row, 0, qq->rootIndex()));
1994#if QT_CONFIG(draganddrop)
1995void QCommonListViewBase::paintDragDrop(QPainter *painter)
1999 dd->paintDropIndicator(painter);
2003QSize QListModeViewBase::viewportSize(
const QAbstractItemView *v)
2005 return v->contentsRect().marginsRemoved(v->viewportMargins()).size();
2008void QCommonListViewBase::updateHorizontalScrollBar(
const QSize &step)
2010 horizontalScrollBar()->d_func()->itemviewChangeSingleStep(step.width() + spacing());
2011 horizontalScrollBar()->setPageStep(viewport()->width());
2017 const bool bothScrollBarsAuto = qq->verticalScrollBarPolicy() == Qt::ScrollBarAsNeeded &&
2018 qq->horizontalScrollBarPolicy() == Qt::ScrollBarAsNeeded;
2020 const QSize viewportSize = QListModeViewBase::viewportSize(qq);
2022 bool verticalWantsToShow = contentsSize.height() > viewportSize.height();
2023 bool horizontalWantsToShow;
2024 if (verticalWantsToShow)
2025 horizontalWantsToShow = contentsSize.width() > viewportSize.width() - qq->verticalScrollBar()->width();
2027 horizontalWantsToShow = contentsSize.width() > viewportSize.width();
2029 if (bothScrollBarsAuto && !horizontalWantsToShow) {
2032 horizontalScrollBar()->setRange(0, 0);
2034 horizontalScrollBar()->setRange(0, contentsSize.width() - viewport()->width());
2038void QCommonListViewBase::updateVerticalScrollBar(
const QSize &step)
2040 verticalScrollBar()->d_func()->itemviewChangeSingleStep(step.height() + spacing());
2041 verticalScrollBar()->setPageStep(viewport()->height());
2047 const bool bothScrollBarsAuto = qq->verticalScrollBarPolicy() == Qt::ScrollBarAsNeeded &&
2048 qq->horizontalScrollBarPolicy() == Qt::ScrollBarAsNeeded;
2050 const QSize viewportSize = QListModeViewBase::viewportSize(qq);
2052 bool horizontalWantsToShow = contentsSize.width() > viewportSize.width();
2053 bool verticalWantsToShow;
2054 if (horizontalWantsToShow)
2055 verticalWantsToShow = contentsSize.height() > viewportSize.height() - qq->horizontalScrollBar()->height();
2057 verticalWantsToShow = contentsSize.height() > viewportSize.height();
2059 if (bothScrollBarsAuto && !verticalWantsToShow) {
2062 verticalScrollBar()->setRange(0, 0);
2064 verticalScrollBar()->setRange(0, contentsSize.height() - viewport()->height());
2068void QCommonListViewBase::scrollContentsBy(
int dx,
int dy,
bool )
2070 dd->scrollContentsBy(isRightToLeft() ? -dx : dx, dy);
2073int QCommonListViewBase::verticalScrollToValue(
int , QListView::ScrollHint hint,
2074 bool above,
bool below,
const QRect &area,
const QRect &rect)
const
2076 int verticalValue = verticalScrollBar()->value();
2077 QRect adjusted = rect.adjusted(-spacing(), -spacing(), spacing(), spacing());
2078 if (hint == QListView::PositionAtTop || above)
2079 verticalValue += adjusted.top();
2080 else if (hint == QListView::PositionAtBottom || below)
2081 verticalValue += qMin(adjusted.top(), adjusted.bottom() - area.height() + 1);
2082 else if (hint == QListView::PositionAtCenter)
2083 verticalValue += adjusted.top() - ((area.height() - adjusted.height()) / 2);
2084 return verticalValue;
2087int QCommonListViewBase::horizontalOffset()
const
2089 return (isRightToLeft() ? horizontalScrollBar()->maximum() - horizontalScrollBar()->value() : horizontalScrollBar()->value());
2092int QCommonListViewBase::horizontalScrollToValue(
const int , QListView::ScrollHint hint,
2093 bool leftOf,
bool rightOf,
const QRect &area,
const QRect &rect)
const
2095 int horizontalValue = horizontalScrollBar()->value();
2096 if (isRightToLeft()) {
2097 if (hint == QListView::PositionAtCenter) {
2098 horizontalValue += ((area.width() - rect.width()) / 2) - rect.left();
2101 horizontalValue -= rect.left();
2103 horizontalValue += qMin(rect.left(), area.width() - rect.right());
2106 if (hint == QListView::PositionAtCenter) {
2107 horizontalValue += rect.left() - ((area.width()- rect.width()) / 2);
2110 horizontalValue += rect.left();
2112 horizontalValue += qMin(rect.left(), rect.right() - area.width());
2115 return horizontalValue;
2119
2120
2121QListModeViewBase::QListModeViewBase(QListView *q, QListViewPrivate *d)
2122 : QCommonListViewBase(q, d)
2124#if QT_CONFIG(draganddrop)
2125 dd->defaultDropAction = Qt::CopyAction;
2129#if QT_CONFIG(draganddrop)
2130QAbstractItemView::DropIndicatorPosition QListModeViewBase::position(
const QPoint &pos,
const QRect &rect,
const QModelIndex &index)
const
2132 QAbstractItemView::DropIndicatorPosition r = QAbstractItemView::OnViewport;
2133 if (!dd->overwrite) {
2134 const int margin = 2;
2135 if (pos.x() - rect.left() < margin) {
2136 r = QAbstractItemView::AboveItem;
2137 }
else if (rect.right() - pos.x() < margin) {
2138 r = QAbstractItemView::BelowItem;
2139 }
else if (rect.contains(pos,
true)) {
2140 r = QAbstractItemView::OnItem;
2143 QRect touchingRect = rect;
2144 touchingRect.adjust(-1, -1, 1, 1);
2145 if (touchingRect.contains(pos,
false)) {
2146 r = QAbstractItemView::OnItem;
2150 if (r == QAbstractItemView::OnItem && (!(dd->model->flags(index) & Qt::ItemIsDropEnabled)))
2151 r = pos.x() < rect.center().x() ? QAbstractItemView::AboveItem : QAbstractItemView::BelowItem;
2156void QListModeViewBase::dragMoveEvent(QDragMoveEvent *event)
2158 if (qq->dragDropMode() == QAbstractItemView::InternalMove
2159 && (event->source() != qq || !(event->possibleActions() & Qt::MoveAction)))
2166 QPoint p = event->position().toPoint();
2167 QRect rect(p.x() + horizontalOffset(), p.y() + verticalOffset(), 1, 1);
2168 rect.adjust(-dd->spacing(), -dd->spacing(), dd->spacing(), dd->spacing());
2169 const QList<QModelIndex> intersectVector = dd->intersectingSet(rect);
2170 QModelIndex index = intersectVector.size() > 0
2171 ? intersectVector.last() : QModelIndex();
2173 if (!dd->droppingOnItself(event, index)
2174 && dd->canDrop(event)) {
2176 if (index.isValid() && dd->showDropIndicator) {
2177 QRect rect = qq->visualRect(index);
2178 dd->dropIndicatorPosition = position(event->position().toPoint(), rect, index);
2180 switch (dd->dropIndicatorPosition) {
2181 case QAbstractItemView::AboveItem:
2182 if (dd->isIndexDropEnabled(index.parent())) {
2183 dd->dropIndicatorRect = QRect(rect.left()-dd->spacing(), rect.top(), 0, rect.height());
2186 dd->dropIndicatorRect = QRect();
2189 case QAbstractItemView::BelowItem:
2190 if (dd->isIndexDropEnabled(index.parent())) {
2191 dd->dropIndicatorRect = QRect(rect.right()+dd->spacing(), rect.top(), 0, rect.height());
2194 dd->dropIndicatorRect = QRect();
2197 case QAbstractItemView::OnItem:
2198 if (dd->isIndexDropEnabled(index)) {
2199 dd->dropIndicatorRect = rect;
2202 dd->dropIndicatorRect = QRect();
2205 case QAbstractItemView::OnViewport:
2206 dd->dropIndicatorRect = QRect();
2207 if (dd->isIndexDropEnabled(qq->rootIndex())) {
2213 dd->dropIndicatorRect = QRect();
2214 dd->dropIndicatorPosition = QAbstractItemView::OnViewport;
2215 if (dd->isIndexDropEnabled(qq->rootIndex())) {
2219 dd->viewport->update();
2222 if (dd->shouldAutoScroll(event->position().toPoint()))
2223 qq->startAutoScroll();
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237bool QListModeViewBase::dropOn(QDropEvent *event,
int *dropRow,
int *dropCol, QModelIndex *dropIndex)
2239 if (event->isAccepted())
2243 if (dd->viewport->rect().contains(event->position().toPoint())) {
2245 QPoint p = event->position().toPoint();
2246 QRect rect(p.x() + horizontalOffset(), p.y() + verticalOffset(), 1, 1);
2247 rect.adjust(-dd->spacing(), -dd->spacing(), dd->spacing(), dd->spacing());
2248 const QList<QModelIndex> intersectVector = dd->intersectingSet(rect);
2249 index = intersectVector.size() > 0
2250 ? intersectVector.last() : QModelIndex();
2251 if (!index.isValid())
2256 if (dd->model->supportedDropActions() & event->dropAction()) {
2259 if (index != dd->root) {
2260 dd->dropIndicatorPosition = position(event->position().toPoint(), qq->visualRect(index), index);
2261 switch (dd->dropIndicatorPosition) {
2262 case QAbstractItemView::AboveItem:
2264 col = index.column();
2265 index = index.parent();
2267 case QAbstractItemView::BelowItem:
2268 row = index.row() + 1;
2269 col = index.column();
2270 index = index.parent();
2272 case QAbstractItemView::OnItem:
2273 case QAbstractItemView::OnViewport:
2277 dd->dropIndicatorPosition = QAbstractItemView::OnViewport;
2282 if (!dd->droppingOnItself(event, index))
2290void QListModeViewBase::updateVerticalScrollBar(
const QSize &step)
2292 if (verticalScrollMode() == QAbstractItemView::ScrollPerItem
2293 && ((flow() == QListView::TopToBottom && !isWrapping())
2294 || (flow() == QListView::LeftToRight && isWrapping()))) {
2295 const int steps = (flow() == QListView::TopToBottom ? scrollValueMap : segmentPositions).size() - 1;
2297 const int pageSteps = perItemScrollingPageSteps(viewport()->height(), contentsSize.height(), isWrapping());
2298 verticalScrollBar()->setSingleStep(1);
2299 verticalScrollBar()->setPageStep(pageSteps);
2300 verticalScrollBar()->setRange(0, steps - pageSteps);
2302 verticalScrollBar()->setRange(0, 0);
2307 QCommonListViewBase::updateVerticalScrollBar(step);
2311void QListModeViewBase::updateHorizontalScrollBar(
const QSize &step)
2313 if (horizontalScrollMode() == QAbstractItemView::ScrollPerItem
2314 && ((flow() == QListView::TopToBottom && isWrapping())
2315 || (flow() == QListView::LeftToRight && !isWrapping()))) {
2316 int steps = (flow() == QListView::TopToBottom ? segmentPositions : scrollValueMap).size() - 1;
2318 const int pageSteps = perItemScrollingPageSteps(viewport()->width(), contentsSize.width(), isWrapping());
2319 horizontalScrollBar()->setSingleStep(1);
2320 horizontalScrollBar()->setPageStep(pageSteps);
2321 horizontalScrollBar()->setRange(0, steps - pageSteps);
2323 horizontalScrollBar()->setRange(0, 0);
2326 QCommonListViewBase::updateHorizontalScrollBar(step);
2330int QListModeViewBase::verticalScrollToValue(
int index, QListView::ScrollHint hint,
2331 bool above,
bool below,
const QRect &area,
const QRect &rect)
const
2333 if (verticalScrollMode() == QAbstractItemView::ScrollPerItem) {
2335 if (scrollValueMap.isEmpty()) {
2338 int scrollBarValue = verticalScrollBar()->value();
2340 for (
const auto &idx : std::as_const(dd->hiddenRows))
2341 if (idx.row() <= scrollBarValue)
2343 value = qBound(0, scrollValueMap.at(verticalScrollBar()->value()) - numHidden, flowPositions.size() - 1);
2346 hint = QListView::PositionAtTop;
2348 hint = QListView::PositionAtBottom;
2349 if (hint == QListView::EnsureVisible)
2352 return perItemScrollToValue(index, value, area.height(), hint, Qt::Vertical, isWrapping(), rect.height());
2355 return QCommonListViewBase::verticalScrollToValue(index, hint, above, below, area, rect);
2358int QListModeViewBase::horizontalOffset()
const
2360 if (horizontalScrollMode() == QAbstractItemView::ScrollPerItem) {
2362 if (flow() == QListView::TopToBottom && !segmentPositions.isEmpty()) {
2363 const int max = segmentPositions.size() - 1;
2364 int currentValue = qBound(0, horizontalScrollBar()->value(), max);
2365 int position = segmentPositions.at(currentValue);
2366 int maximumValue = qBound(0, horizontalScrollBar()->maximum(), max);
2367 int maximum = segmentPositions.at(maximumValue);
2368 return (isRightToLeft() ? maximum - position : position);
2370 }
else if (flow() == QListView::LeftToRight && !flowPositions.isEmpty()) {
2371 int position = flowPositions.at(scrollValueMap.at(horizontalScrollBar()->value()));
2372 int maximum = flowPositions.at(scrollValueMap.at(horizontalScrollBar()->maximum()));
2373 return (isRightToLeft() ? maximum - position : position);
2376 return QCommonListViewBase::horizontalOffset();
2379int QListModeViewBase::verticalOffset()
const
2381 if (verticalScrollMode() == QAbstractItemView::ScrollPerItem) {
2383 if (flow() == QListView::LeftToRight && !segmentPositions.isEmpty()) {
2384 int value = verticalScrollBar()->value();
2385 if (value >= segmentPositions.size())
2387 return segmentPositions.at(value) - spacing();
2389 }
else if (flow() == QListView::TopToBottom && !flowPositions.isEmpty()) {
2390 int value = verticalScrollBar()->value();
2391 if (value > scrollValueMap.size())
2393 return flowPositions.at(scrollValueMap.at(value)) - spacing();
2396 return QCommonListViewBase::verticalOffset();
2399int QListModeViewBase::horizontalScrollToValue(
int index, QListView::ScrollHint hint,
2400 bool leftOf,
bool rightOf,
const QRect &area,
const QRect &rect)
const
2402 if (horizontalScrollMode() != QAbstractItemView::ScrollPerItem)
2403 return QCommonListViewBase::horizontalScrollToValue(index, hint, leftOf, rightOf, area, rect);
2406 if (scrollValueMap.isEmpty())
2409 value = qBound(0, scrollValueMap.at(horizontalScrollBar()->value()), flowPositions.size() - 1);
2411 hint = QListView::PositionAtTop;
2413 hint = QListView::PositionAtBottom;
2414 if (hint == QListView::EnsureVisible)
2417 return perItemScrollToValue(index, value, area.width(), hint, Qt::Horizontal, isWrapping(), rect.width());
2420void QListModeViewBase::scrollContentsBy(
int dx,
int dy,
bool scrollElasticBand)
2423 const int verticalValue = verticalScrollBar()->value();
2424 const int horizontalValue = horizontalScrollBar()->value();
2425 const bool vertical = (verticalScrollMode() == QAbstractItemView::ScrollPerItem);
2426 const bool horizontal = (horizontalScrollMode() == QAbstractItemView::ScrollPerItem);
2429 if (segmentPositions.isEmpty())
2431 const int max = segmentPositions.size() - 1;
2432 if (horizontal && flow() == QListView::TopToBottom && dx != 0) {
2433 int currentValue = qBound(0, horizontalValue, max);
2434 int previousValue = qBound(0, currentValue + dx, max);
2435 int currentCoordinate = segmentPositions.at(currentValue) - spacing();
2436 int previousCoordinate = segmentPositions.at(previousValue) - spacing();
2437 dx = previousCoordinate - currentCoordinate;
2438 }
else if (vertical && flow() == QListView::LeftToRight && dy != 0) {
2439 int currentValue = qBound(0, verticalValue, max);
2440 int previousValue = qBound(0, currentValue + dy, max);
2441 int currentCoordinate = segmentPositions.at(currentValue) - spacing();
2442 int previousCoordinate = segmentPositions.at(previousValue) - spacing();
2443 dy = previousCoordinate - currentCoordinate;
2446 if (flowPositions.isEmpty())
2448 const int max = scrollValueMap.size() - 1;
2449 if (vertical && flow() == QListView::TopToBottom && dy != 0) {
2450 int currentValue = qBound(0, verticalValue, max);
2451 int previousValue = qBound(0, currentValue + dy, max);
2452 int currentCoordinate = flowPositions.at(scrollValueMap.at(currentValue));
2453 int previousCoordinate = flowPositions.at(scrollValueMap.at(previousValue));
2454 dy = previousCoordinate - currentCoordinate;
2455 }
else if (horizontal && flow() == QListView::LeftToRight && dx != 0) {
2456 int currentValue = qBound(0, horizontalValue, max);
2457 int previousValue = qBound(0, currentValue + dx, max);
2458 int currentCoordinate = flowPositions.at(scrollValueMap.at(currentValue));
2459 int previousCoordinate = flowPositions.at(scrollValueMap.at(previousValue));
2460 dx = previousCoordinate - currentCoordinate;
2463 QCommonListViewBase::scrollContentsBy(dx, dy, scrollElasticBand);
2466bool QListModeViewBase::doBatchedItemLayout(
const QListViewLayoutInfo &info,
int max)
2468 doStaticLayout(info);
2469 return batchStartRow > max;
2472QListViewItem QListModeViewBase::indexToListViewItem(
const QModelIndex &index)
const
2474 if (flowPositions.isEmpty()
2475 || segmentPositions.isEmpty()
2476 || index.row() >= flowPositions.size() - 1)
2477 return QListViewItem();
2479 const int segment = qBinarySearch<
int>(segmentStartRows, index.row(),
2480 0, segmentStartRows.size() - 1);
2483 QStyleOptionViewItem options;
2484 initViewItemOption(&options);
2485 options.rect.setSize(contentsSize);
2486 QSize size = (uniformItemSizes() && cachedItemSize().isValid())
2487 ? cachedItemSize() : itemSize(options, index);
2488 QSize cellSize = size;
2491 if (flow() == QListView::LeftToRight) {
2492 pos.setX(flowPositions.at(index.row()));
2493 pos.setY(segmentPositions.at(segment));
2495 pos.setY(flowPositions.at(index.row()));
2496 pos.setX(segmentPositions.at(segment));
2498 int right = (segment + 1 >= segmentPositions.size()
2499 ? contentsSize.width()
2500 : segmentPositions.at(segment + 1));
2501 cellSize.setWidth(right - pos.x());
2503 cellSize.setWidth(qMax(size.width(), viewport()->width() - 2 * spacing()));
2507 if (dd->itemAlignment & Qt::AlignHorizontal_Mask) {
2508 size.setWidth(qMin(size.width(), cellSize.width()));
2509 if (dd->itemAlignment & Qt::AlignRight)
2510 pos.setX(pos.x() + cellSize.width() - size.width());
2511 if (dd->itemAlignment & Qt::AlignHCenter)
2512 pos.setX(pos.x() + (cellSize.width() - size.width()) / 2);
2514 size.setWidth(cellSize.width());
2517 return QListViewItem(QRect(pos, size), index.row());
2520QPoint QListModeViewBase::initStaticLayout(
const QListViewLayoutInfo &info)
2523 if (info.first == 0) {
2524 flowPositions.clear();
2525 segmentPositions.clear();
2526 segmentStartRows.clear();
2527 segmentExtents.clear();
2528 scrollValueMap.clear();
2529 x = info.bounds.left() + info.spacing;
2530 y = info.bounds.top() + info.spacing;
2531 segmentPositions.append(info.flow == QListView::LeftToRight ? y : x);
2532 segmentStartRows.append(0);
2533 }
else if (info.wrap) {
2534 if (info.flow == QListView::LeftToRight) {
2535 x = batchSavedPosition;
2536 y = segmentPositions.constLast();
2538 x = segmentPositions.constLast();
2539 y = batchSavedPosition;
2542 if (info.flow == QListView::LeftToRight) {
2543 x = batchSavedPosition;
2544 y = info.bounds.top() + info.spacing;
2546 x = info.bounds.left() + info.spacing;
2547 y = batchSavedPosition;
2550 return QPoint(x, y);
2554
2555
2556void QListModeViewBase::doStaticLayout(
const QListViewLayoutInfo &info)
2558 const bool useItemSize = !info.grid.isValid();
2559 const QPoint topLeft = initStaticLayout(info);
2560 QStyleOptionViewItem option;
2561 initViewItemOption(&option);
2562 option.rect = info.bounds;
2563 option.rect.adjust(info.spacing, info.spacing, -info.spacing, -info.spacing);
2571 int segStartPosition;
2573 int deltaFlowPosition;
2574 int deltaSegPosition;
2579 if (info.flow == QListView::LeftToRight) {
2580 segStartPosition = info.bounds.left();
2581 segEndPosition = info.bounds.width();
2582 flowPosition = topLeft.x();
2583 segPosition = topLeft.y();
2584 deltaFlowPosition = info.grid.width();
2585 deltaSegPosition = useItemSize ? batchSavedDeltaSeg : info.grid.height();
2586 deltaSegHint = info.grid.height();
2588 segStartPosition = info.bounds.top();
2589 segEndPosition = info.bounds.height();
2590 flowPosition = topLeft.y();
2591 segPosition = topLeft.x();
2592 deltaFlowPosition = info.grid.height();
2593 deltaSegPosition = useItemSize ? batchSavedDeltaSeg : info.grid.width();
2594 deltaSegHint = info.grid.width();
2597 for (
int row = info.first; row <= info.last; ++row) {
2598 if (isHidden(row)) {
2599 flowPositions.append(flowPosition);
2603 QSize hint = itemSize(option, modelIndex(row));
2604 if (info.flow == QListView::LeftToRight) {
2605 deltaFlowPosition = hint.width() + info.spacing;
2606 deltaSegHint = hint.height() + info.spacing;
2608 deltaFlowPosition = hint.height() + info.spacing;
2609 deltaSegHint = hint.width() + info.spacing;
2613 if (info.wrap && (flowPosition + deltaFlowPosition >= segEndPosition)) {
2614 segmentExtents.append(flowPosition);
2615 flowPosition = info.spacing + segStartPosition;
2616 segPosition += info.spacing + deltaSegPosition;
2617 segmentPositions.append(segPosition);
2618 segmentStartRows.append(row);
2619 deltaSegPosition = 0;
2622 scrollValueMap.append(flowPositions.size());
2623 flowPositions.append(flowPosition);
2625 deltaSegPosition = qMax(deltaSegHint, deltaSegPosition);
2626 flowPosition += info.spacing + deltaFlowPosition;
2630 batchSavedPosition = flowPosition;
2631 batchSavedDeltaSeg = deltaSegPosition;
2632 batchStartRow = info.last + 1;
2633 if (info.last == info.max)
2634 flowPosition -= info.spacing;
2636 QRect rect = info.bounds;
2637 if (info.flow == QListView::LeftToRight) {
2638 rect.setRight(segmentPositions.size() == 1 ? flowPosition : info.bounds.right());
2639 rect.setBottom(segPosition + deltaSegPosition);
2641 rect.setRight(segPosition + deltaSegPosition);
2642 rect.setBottom(segmentPositions.size() == 1 ? flowPosition : info.bounds.bottom());
2644 contentsSize = QSize(rect.right(), rect.bottom());
2646 if (info.last == info.max) {
2647 segmentExtents.append(flowPosition);
2648 scrollValueMap.append(flowPositions.size());
2649 flowPositions.append(flowPosition);
2650 segmentPositions.append(info.wrap ? segPosition + deltaSegPosition : INT_MAX);
2653 QRect changedRect(topLeft, rect.bottomRight());
2654 if (clipRect().intersects(changedRect))
2655 viewport()->update();
2659
2660
2661
2662
2663QList<QModelIndex> QListModeViewBase::intersectingSet(
const QRect &area)
const
2665 QList<QModelIndex> ret;
2666 int segStartPosition;
2668 int flowStartPosition;
2669 int flowEndPosition;
2670 if (flow() == QListView::LeftToRight) {
2671 segStartPosition = area.top();
2672 segEndPosition = area.bottom();
2673 flowStartPosition = area.left();
2674 flowEndPosition = area.right();
2676 segStartPosition = area.left();
2677 segEndPosition = area.right();
2678 flowStartPosition = area.top();
2679 flowEndPosition = area.bottom();
2681 if (segmentPositions.size() < 2 || flowPositions.isEmpty())
2684 const int segLast = segmentPositions.size() - 2;
2685 int seg = qBinarySearch<
int>(segmentPositions, segStartPosition, 0, segLast + 1);
2686 for (; seg <= segLast && segmentPositions.at(seg) <= segEndPosition; ++seg) {
2687 int first = segmentStartRows.at(seg);
2688 int last = (seg < segLast ? segmentStartRows.at(seg + 1) : batchStartRow) - 1;
2689 if (segmentExtents.at(seg) < flowStartPosition)
2691 int row = qBinarySearch<
int>(flowPositions, flowStartPosition, first, last);
2692 for (; row <= last && flowPositions.at(row) <= flowEndPosition; ++row) {
2695 QModelIndex index = modelIndex(row);
2696 if (index.isValid()) {
2697 if (flow() == QListView::LeftToRight || dd->itemAlignment == Qt::Alignment()) {
2700 const auto viewItem = indexToListViewItem(index);
2701 const int iw = viewItem.width();
2702 const int startPos = qMax(segStartPosition, segmentPositions.at(seg));
2703 const int endPos = qMin(segmentPositions.at(seg + 1), segEndPosition);
2704 if (endPos >= viewItem.x && startPos < viewItem.x + iw)
2710 qWarning(
"intersectingSet: row %d was invalid", row);
2717void QListModeViewBase::dataChanged(
const QModelIndex &,
const QModelIndex &)
2719 dd->doDelayedItemsLayout();
2723QRect QListModeViewBase::mapToViewport(
const QRect &rect)
const
2729 QRect result = rect;
2730 if (flow() == QListView::TopToBottom) {
2731 result.setLeft(spacing());
2732 result.setWidth(qMax(rect.width(), qMax(contentsSize.width(), viewport()->width()) - 2 * spacing()));
2734 result.setTop(spacing());
2735 result.setHeight(qMax(rect.height(), qMax(contentsSize.height(), viewport()->height()) - 2 * spacing()));
2740int QListModeViewBase::perItemScrollingPageSteps(
int length,
int bounds,
bool wrap)
const
2742 QList<
int> positions;
2744 positions = segmentPositions;
2745 else if (!flowPositions.isEmpty()) {
2746 positions.reserve(scrollValueMap.size());
2747 for (
int itemShown : scrollValueMap)
2748 positions.append(flowPositions.at(itemShown));
2750 if (positions.isEmpty() || bounds <= length)
2751 return positions.size();
2752 if (uniformItemSizes()) {
2753 for (
int i = 1; i < positions.size(); ++i)
2754 if (positions.at(i) > 0)
2755 return length / positions.at(i);
2759 int steps = positions.size() - 1;
2760 int max = qMax(length, bounds);
2761 int min = qMin(length, bounds);
2762 int pos = min - (max - positions.constLast());
2764 while (pos >= 0 && steps > 0) {
2765 pos -= (positions.at(steps) - positions.at(steps - 1));
2772 return qMax(pageSteps, 1);
2775int QListModeViewBase::perItemScrollToValue(
int index,
int scrollValue,
int viewportSize,
2776 QAbstractItemView::ScrollHint hint,
2777 Qt::Orientation orientation,
bool wrap,
int itemExtent)
const
2782 itemExtent += spacing();
2783 QList<
int> hiddenRows = dd->hiddenRowIds();
2784 std::sort(hiddenRows.begin(), hiddenRows.end());
2785 int hiddenRowsBefore = 0;
2786 for (
int i = 0; i < hiddenRows.size() - 1; ++i)
2787 if (hiddenRows.at(i) > index + hiddenRowsBefore)
2792 int topIndex = index;
2793 const int bottomIndex = topIndex;
2794 const int bottomCoordinate = flowPositions.at(index + hiddenRowsBefore);
2795 while (topIndex > 0 &&
2796 (bottomCoordinate - flowPositions.at(topIndex + hiddenRowsBefore - 1) + itemExtent) <= (viewportSize)) {
2799 while (hiddenRowsBefore > 0 && hiddenRows.at(hiddenRowsBefore - 1) >= topIndex + hiddenRowsBefore - 1)
2803 const int itemCount = bottomIndex - topIndex + 1;
2805 case QAbstractItemView::PositionAtTop:
2807 case QAbstractItemView::PositionAtBottom:
2808 return index - itemCount + 1;
2809 case QAbstractItemView::PositionAtCenter:
2810 return index - (itemCount / 2);
2815 Qt::Orientation flowOrientation = (flow() == QListView::LeftToRight
2816 ? Qt::Horizontal : Qt::Vertical);
2817 if (flowOrientation == orientation) {
2819 return flowPositions.at(index + hiddenRowsBefore);
2820 }
else if (!segmentStartRows.isEmpty()) {
2821 int segment = qBinarySearch<
int>(segmentStartRows, index, 0, segmentStartRows.size() - 1);
2822 int leftSegment = segment;
2823 const int rightSegment = leftSegment;
2824 const int bottomCoordinate = segmentPositions.at(segment);
2826 while (leftSegment > scrollValue &&
2827 (bottomCoordinate - segmentPositions.at(leftSegment-1) + itemExtent) <= (viewportSize)) {
2831 const int segmentCount = rightSegment - leftSegment + 1;
2833 case QAbstractItemView::PositionAtTop:
2835 case QAbstractItemView::PositionAtBottom:
2836 return segment - segmentCount + 1;
2837 case QAbstractItemView::PositionAtCenter:
2838 return segment - (segmentCount / 2);
2847void QListModeViewBase::clear()
2849 flowPositions.clear();
2850 segmentPositions.clear();
2851 segmentStartRows.clear();
2852 segmentExtents.clear();
2853 batchSavedPosition = 0;
2855 batchSavedDeltaSeg = 0;
2859
2860
2862void QIconModeViewBase::setPositionForIndex(
const QPoint &position,
const QModelIndex &index)
2864 if (index.row() >= items.size())
2866 const QSize oldContents = contentsSize;
2868 moveItem(index.row(), position);
2871 if (contentsSize != oldContents)
2872 dd->viewUpdateGeometries();
2875void QIconModeViewBase::appendHiddenRow(
int row)
2877 if (row >= 0 && row < items.size())
2878 tree.removeLeaf(items.at(row).rect(), row);
2879 QCommonListViewBase::appendHiddenRow(row);
2882void QIconModeViewBase::removeHiddenRow(
int row)
2884 QCommonListViewBase::removeHiddenRow(row);
2885 if (row >= 0 && row < items.size())
2886 tree.insertLeaf(items.at(row).rect(), row);
2889#if QT_CONFIG(draganddrop)
2890bool QIconModeViewBase::filterStartDrag(Qt::DropActions supportedActions)
2895 QModelIndexList indexes = dd->selectionModel->selectedIndexes();
2896 if (indexes.size() > 0 ) {
2897 if (viewport()->acceptDrops()) {
2898 QModelIndexList::ConstIterator it = indexes.constBegin();
2899 for (; it != indexes.constEnd(); ++it)
2900 if (dd->model->flags(*it) & Qt::ItemIsDragEnabled
2901 && (*it).column() == dd->column)
2902 draggedItems.push_back(*it);
2906 QPixmap pixmap = dd->renderToPixmap(indexes, &rect);
2907 rect.adjust(horizontalOffset(), verticalOffset(), 0, 0);
2908 QDrag *drag =
new QDrag(qq);
2909 drag->setMimeData(dd->model->mimeData(indexes));
2910 drag->setPixmap(pixmap);
2911 drag->setHotSpot(dd->pressedPosition - rect.topLeft());
2912 dd->dropEventMoved =
false;
2913 Qt::DropAction action = drag->exec(supportedActions, dd->defaultDropAction);
2914 draggedItems.clear();
2916 if (action == Qt::MoveAction && !dd->dropEventMoved) {
2917 if (dd->dragDropMode != QAbstractItemView::InternalMove || drag->target() == qq->viewport())
2918 dd->clearOrRemove();
2920 dd->dropEventMoved =
false;
2925bool QIconModeViewBase::filterDropEvent(QDropEvent *e)
2927 if (e->source() != qq)
2930 const QSize contents = contentsSize;
2931 QPoint offset(horizontalOffset(), verticalOffset());
2932 QPoint end = e->position().toPoint() + offset;
2933 if (qq->acceptDrops()) {
2934 const Qt::ItemFlags dropableFlags = Qt::ItemIsDropEnabled|Qt::ItemIsEnabled;
2935 const QList<QModelIndex> &dropIndices = intersectingSet(QRect(end, QSize(1, 1)));
2936 for (
const QModelIndex &index : dropIndices)
2937 if ((index.flags() & dropableFlags) == dropableFlags)
2940 QPoint start = dd->pressedPosition;
2941 QPoint delta = (dd->movement == QListView::Snap ? snapToGrid(end) - snapToGrid(start) : end - start);
2942 const QList<QModelIndex> indexes = dd->selectionModel->selectedIndexes();
2943 for (
const auto &index : indexes) {
2944 QRect rect = dd->rectForIndex(index);
2945 viewport()->update(dd->mapToViewport(rect,
false));
2946 QPoint dest = rect.topLeft() + delta;
2947 if (qq->isRightToLeft())
2948 dest.setX(dd->flipX(dest.x()) - rect.width());
2949 moveItem(index.row(), dest);
2952 dd->stopAutoScroll();
2953 draggedItems.clear();
2954 dd->emitIndexesMoved(indexes);
2956 dd->dropEventMoved =
true;
2959 if (contentsSize != contents) {
2960 if ((contentsSize.width() <= contents.width()
2961 || contentsSize.height() <= contents.height())) {
2962 updateContentsSize();
2964 dd->viewUpdateGeometries();
2969bool QIconModeViewBase::filterDragLeaveEvent(QDragLeaveEvent *e)
2971 viewport()->update(draggedItemsRect());
2972 draggedItemsPos = QPoint(-1, -1);
2973 return QCommonListViewBase::filterDragLeaveEvent(e);
2976bool QIconModeViewBase::filterDragMoveEvent(QDragMoveEvent *e)
2978 const bool wasAccepted = e->isAccepted();
2983 if (e->source() != qq || !dd->canDrop(e)) {
2985 e->setAccepted(wasAccepted);
2990 QRect itemsRect =
this->itemsRect(draggedItems);
2991 viewport()->update(itemsRect.translated(draggedItemsDelta()));
2993 draggedItemsPos = e->position().toPoint();
2995 viewport()->update(itemsRect.translated(draggedItemsDelta()));
2998 if (movement() == QListView::Snap) {
2999 QRect rect(snapToGrid(e->position().toPoint() + offset()), gridSize());
3000 const QList<QModelIndex> intersectVector = intersectingSet(rect);
3001 index = intersectVector.size() > 0 ? intersectVector.last() : QModelIndex();
3003 index = qq->indexAt(e->position().toPoint());
3006 if (draggedItems.contains(index))
3008 else if (dd->model->flags(index) & Qt::ItemIsDropEnabled)
3010 else if (!index.isValid())
3014 if (dd->shouldAutoScroll(e->position().toPoint()))
3015 dd->startAutoScroll();
3020void QIconModeViewBase::setRowCount(
int rowCount)
3022 tree.create(qMax(rowCount - hiddenCount(), 0));
3025void QIconModeViewBase::scrollContentsBy(
int dx,
int dy,
bool scrollElasticBand)
3027 if (scrollElasticBand)
3028 dd->scrollElasticBandBy(isRightToLeft() ? -dx : dx, dy);
3030 QCommonListViewBase::scrollContentsBy(dx, dy, scrollElasticBand);
3031 if (!draggedItems.isEmpty())
3032 viewport()->update(draggedItemsRect().translated(dx, dy));
3035void QIconModeViewBase::dataChanged(
const QModelIndex &topLeft,
const QModelIndex &bottomRight)
3037 if (column() >= topLeft.column() && column() <= bottomRight.column()) {
3038 QStyleOptionViewItem option;
3039 initViewItemOption(&option);
3040 const int bottom = qMin(items.size(), bottomRight.row() + 1);
3041 const bool useItemSize = !dd->grid.isValid();
3042 for (
int row = topLeft.row(); row < bottom; ++row)
3044 QSize s = itemSize(option, modelIndex(row));
3047 s.setWidth(qMin(dd->grid.width(), s.width()));
3048 s.setHeight(qMin(dd->grid.height(), s.height()));
3050 items[row].resize(s);
3055bool QIconModeViewBase::doBatchedItemLayout(
const QListViewLayoutInfo &info,
int max)
3057 if (info.last >= items.size()) {
3059 QStyleOptionViewItem option;
3060 initViewItemOption(&option);
3061 for (
int row = items.size(); row <= info.last; ++row) {
3062 QSize size = itemSize(option, modelIndex(row));
3063 QListViewItem item(QRect(0, 0, size.width(), size.height()), row);
3066 doDynamicLayout(info);
3068 return (batchStartRow > max);
3071QListViewItem QIconModeViewBase::indexToListViewItem(
const QModelIndex &index)
const
3073 if (index.isValid() && index.row() < items.size())
3074 return items.at(index.row());
3075 return QListViewItem();
3078void QIconModeViewBase::initBspTree(
const QSize &contents)
3081 int leafCount = tree.leafCount();
3082 for (
int l = 0; l < leafCount; ++l)
3083 tree.leaf(l).clear();
3085 QBspTree::Node::Type type = QBspTree::Node::Both;
3087 if (contents.height() / contents.width() >= 3)
3088 type = QBspTree::Node::HorizontalPlane;
3089 else if (contents.width() / contents.height() >= 3)
3090 type = QBspTree::Node::VerticalPlane;
3092 tree.init(QRect(0, 0, contents.width(), contents.height()), type);
3095QPoint QIconModeViewBase::initDynamicLayout(
const QListViewLayoutInfo &info)
3098 if (info.first == 0) {
3099 x = info.bounds.x() + info.spacing;
3100 y = info.bounds.y() + info.spacing;
3101 items.reserve(rowCount() - hiddenCount());
3103 int idx = info.first - 1;
3104 while (idx > 0 && !items.at(idx).isValid())
3106 const QListViewItem &item = items.at(idx);
3109 if (info.flow == QListView::LeftToRight)
3110 x += (info.grid.isValid() ? info.grid.width() : item.w) + info.spacing;
3112 y += (info.grid.isValid() ? info.grid.height() : item.h) + info.spacing;
3114 return QPoint(x, y);
3118
3119
3120void QIconModeViewBase::doDynamicLayout(
const QListViewLayoutInfo &info)
3122 const bool useItemSize = !info.grid.isValid();
3123 const QPoint topLeft = initDynamicLayout(info);
3125 int segStartPosition;
3127 int deltaFlowPosition;
3128 int deltaSegPosition;
3133 if (info.flow == QListView::LeftToRight) {
3134 segStartPosition = info.bounds.left() + info.spacing;
3135 segEndPosition = info.bounds.right();
3136 deltaFlowPosition = info.grid.width();
3137 deltaSegPosition = (useItemSize ? batchSavedDeltaSeg : info.grid.height());
3138 deltaSegHint = info.grid.height();
3139 flowPosition = topLeft.x();
3140 segPosition = topLeft.y();
3142 segStartPosition = info.bounds.top() + info.spacing;
3143 segEndPosition = info.bounds.bottom();
3144 deltaFlowPosition = info.grid.height();
3145 deltaSegPosition = (useItemSize ? batchSavedDeltaSeg : info.grid.width());
3146 deltaSegHint = info.grid.width();
3147 flowPosition = topLeft.y();
3148 segPosition = topLeft.x();
3151 if (moved.size() != items.size())
3152 moved.resize(items.size());
3154 QRect rect(QPoint(), topLeft);
3155 QListViewItem *item =
nullptr;
3156 Q_ASSERT(info.first <= info.last);
3157 for (
int row = info.first; row <= info.last; ++row) {
3159 if (isHidden(row)) {
3164 if (info.flow == QListView::LeftToRight)
3165 deltaFlowPosition = item->w + info.spacing;
3167 deltaFlowPosition = item->h + info.spacing;
3169 item->w = qMin<
int>(info.grid.width(), item->w);
3170 item->h = qMin<
int>(info.grid.height(), item->h);
3175 && flowPosition + deltaFlowPosition > segEndPosition
3176 && flowPosition > segStartPosition) {
3177 flowPosition = segStartPosition;
3178 segPosition += deltaSegPosition;
3180 deltaSegPosition = 0;
3185 if (info.flow == QListView::LeftToRight)
3186 deltaSegHint = item->h + info.spacing;
3188 deltaSegHint = item->w + info.spacing;
3189 deltaSegPosition = qMax(deltaSegPosition, deltaSegHint);
3195 if (!moved.testBit(row)) {
3196 if (info.flow == QListView::LeftToRight) {
3198 item->x = flowPosition;
3199 item->y = segPosition;
3201 item->x = flowPosition + ((deltaFlowPosition - item->w) / 2);
3202 item->y = segPosition;
3206 item->y = flowPosition;
3207 item->x = segPosition;
3209 item->y = flowPosition + ((deltaFlowPosition - item->h) / 2);
3210 item->x = segPosition;
3217 rect |= item->rect();
3218 else if (info.flow == QListView::LeftToRight)
3219 rect |= QRect(flowPosition, segPosition, deltaFlowPosition, deltaSegPosition);
3221 rect |= QRect(segPosition, flowPosition, deltaSegPosition, deltaFlowPosition);
3224 flowPosition += deltaFlowPosition;
3228 batchSavedDeltaSeg = deltaSegPosition;
3229 batchStartRow = info.last + 1;
3230 bool done = (info.last >= rowCount() - 1);
3232 if (done || !info.bounds.contains(item->rect())) {
3233 contentsSize = rect.size();
3234 if (info.flow == QListView::LeftToRight)
3235 contentsSize.rheight() += info.spacing;
3237 contentsSize.rwidth() += info.spacing;
3239 if (rect.size().isEmpty())
3242 int insertFrom = info.first;
3243 if (done || info.first == 0) {
3244 initBspTree(rect.size());
3248 for (
int row = insertFrom; row <= info.last; ++row)
3249 tree.insertLeaf(items.at(row).rect(), row);
3251 QRect changedRect(topLeft, rect.bottomRight());
3252 if (clipRect().intersects(changedRect))
3253 viewport()->update();
3256QList<QModelIndex> QIconModeViewBase::intersectingSet(
const QRect &area)
const
3258 QIconModeViewBase *that =
const_cast<QIconModeViewBase*>(
this);
3259 QBspTree::Data data(
static_cast<
void*>(that));
3260 QList<QModelIndex> res;
3261 that->interSectingVector = &res;
3262 that->tree.climbTree(area, &QIconModeViewBase::addLeaf, data);
3263 that->interSectingVector =
nullptr;
3267QRect QIconModeViewBase::itemsRect(
const QList<QModelIndex> &indexes)
const
3270 for (
const auto &index : indexes)
3271 rect |= viewItemRect(indexToListViewItem(index));
3275int QIconModeViewBase::itemIndex(
const QListViewItem &item)
const
3277 if (!item.isValid())
3279 int i = item.indexHint;
3280 if (i < items.size()) {
3281 if (items.at(i) == item)
3284 i = items.size() - 1;
3288 int c = items.size();
3294 if (items.at(i) == item) {
3295 items.at(i).indexHint = i;
3301 if (items.at(j) == item) {
3302 items.at(j).indexHint = j;
3311void QIconModeViewBase::addLeaf(QList<
int> &leaf,
const QRect &area, uint visited,
3312 QBspTree::Data data)
3315 QIconModeViewBase *_this =
static_cast<QIconModeViewBase *>(data.ptr);
3316 for (
int i = 0; i < leaf.size(); ++i) {
3317 int idx = leaf.at(i);
3318 if (idx < 0 || idx >= _this->items.size())
3320 vi = &_this->items[idx];
3322 if (vi->isValid() && vi->rect().intersects(area) && vi->visited != visited) {
3323 QModelIndex index = _this->dd->listViewItemToIndex(*vi);
3324 Q_ASSERT(index.isValid());
3325 _this->interSectingVector->append(index);
3326 vi->visited = visited;
3331void QIconModeViewBase::moveItem(
int index,
const QPoint &dest)
3334 QListViewItem *item = &items[index];
3335 QRect rect = item->rect();
3338 tree.removeLeaf(rect, index);
3340 tree.insertLeaf(QRect(dest, rect.size()), index);
3343 contentsSize = (QRect(QPoint(0, 0), contentsSize)|QRect(dest, rect.size())).size();
3346 if (moved.size() != items.size())
3347 moved.resize(items.size());
3348 moved.setBit(index,
true);
3351QPoint QIconModeViewBase::snapToGrid(
const QPoint &pos)
const
3353 int x = pos.x() - (pos.x() % gridSize().width());
3354 int y = pos.y() - (pos.y() % gridSize().height());
3355 return QPoint(x, y);
3358QPoint QIconModeViewBase::draggedItemsDelta()
const
3360 if (movement() == QListView::Snap) {
3361 QPoint snapdelta = QPoint((offset().x() % gridSize().width()),
3362 (offset().y() % gridSize().height()));
3363 return snapToGrid(draggedItemsPos + snapdelta) - snapToGrid(pressedPosition()) - snapdelta;
3365 return draggedItemsPos - pressedPosition();
3368QRect QIconModeViewBase::draggedItemsRect()
const
3370 QRect rect = itemsRect(draggedItems);
3371 rect.translate(draggedItemsDelta());
3375void QListViewPrivate::scrollElasticBandBy(
int dx,
int dy)
3378 elasticBand.moveRight(elasticBand.right() + dx);
3380 elasticBand.moveLeft(elasticBand.left() - dx);
3382 elasticBand.moveBottom(elasticBand.bottom() + dy);
3384 elasticBand.moveTop(elasticBand.top() - dy);
3387void QIconModeViewBase::clear()
3393 batchSavedDeltaSeg = 0;
3396void QIconModeViewBase::updateContentsSize()
3399 for (
int i = 0; i < items.size(); ++i)
3400 bounding |= items.at(i).rect();
3401 contentsSize = bounding.size();
3405
3406
3407void QListView::currentChanged(
const QModelIndex ¤t,
const QModelIndex &previous)
3409 QAbstractItemView::currentChanged(current, previous);
3410#if QT_CONFIG(accessibility)
3411 if (QAccessible::isActive()) {
3412 if (current.isValid() && hasFocus()) {
3413 int entry = visualIndex(current);
3414 QAccessibleEvent event(
this, QAccessible::Focus);
3415 event.setChild(entry);
3416 QAccessible::updateAccessibility(&event);
3423
3424
3425void QListView::selectionChanged(
const QItemSelection &selected,
3426 const QItemSelection &deselected)
3428#if QT_CONFIG(accessibility)
3429 if (QAccessible::isActive()) {
3431 QModelIndex sel = selected.indexes().value(0);
3432 if (sel.isValid()) {
3433 int entry = visualIndex(sel);
3434 QAccessibleEvent event(
this, QAccessible::SelectionAdd);
3435 event.setChild(entry);
3436 QAccessible::updateAccessibility(&event);
3438 QModelIndex desel = deselected.indexes().value(0);
3439 if (desel.isValid()) {
3440 int entry = visualIndex(desel);
3441 QAccessibleEvent event(
this, QAccessible::SelectionRemove);
3442 event.setChild(entry);
3443 QAccessible::updateAccessibility(&event);
3447 QAbstractItemView::selectionChanged(selected, deselected);
3450int QListView::visualIndex(
const QModelIndex &index)
const
3452 Q_D(
const QListView);
3453 d->executePostedLayout();
3454 QListViewItem itm = d->indexToListViewItem(index);
3455 int visualIndex = d->commonListView->itemIndex(itm);
3456 for (
const auto &idx : std::as_const(d->hiddenRows)) {
3457 if (idx.row() <= index.row())
3465
3466
3467
3468QSize QListView::viewportSizeHint()
const
3470 Q_D(
const QListView);
3473 return QAbstractItemView::viewportSizeHint();
3474 const int rc = d->model->rowCount();
3475 if (rc == 0 || isWrapping())
3476 return QAbstractItemView::viewportSizeHint();
3478 QStyleOptionViewItem option;
3479 initViewItemOption(&option);
3481 if (uniformItemSizes()) {
3482 QSize sz = d->cachedItemSize;
3483 if (!sz.isValid()) {
3484 QModelIndex idx = d->model->index(0, d->column, d->root);
3485 sz = d->itemSize(option, idx);
3487 sz.setHeight(rc * sz.height());
3494 int maximumRows = 1000;
3495 const QVariant userOverrideValue = property(
"_q_resizeContentPrecision");
3496 if (userOverrideValue.isValid() && userOverrideValue.toInt() > 0) {
3497 maximumRows = userOverrideValue.toInt();
3499 const int rowCount = qMin(rc, maximumRows);
3504 for (
int row = 0; row < rowCount; ++row) {
3505 QModelIndex idx = d->model->index(row, d->column, d->root);
3506 QSize itemSize = d->itemSize(option, idx);
3507 h += itemSize.height();
3508 w = qMax(w, itemSize.width());
3515#include "moc_qlistview.cpp"