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
617
618
619
620
621
622QItemViewPaintPairs QListViewPrivate::draggablePaintPairs(
const QModelIndexList &indexes, QRect *r)
const
625 Q_Q(
const QListView);
627 const QRect viewportRect = viewport->rect();
628 QItemViewPaintPairs ret;
629 QList<QModelIndex> visibleIndexes =
630 intersectingSet(viewportRect.translated(q->horizontalOffset(), q->verticalOffset()));
631 std::sort(visibleIndexes.begin(), visibleIndexes.end());
632 for (
const auto &index : indexes) {
633 if (std::binary_search(visibleIndexes.cbegin(), visibleIndexes.cend(), index)) {
634 const QRect current = q->visualRect(index);
635 ret.append({current, index});
639 QRect clipped = rect & viewportRect;
640 rect.setLeft(clipped.left());
641 rect.setRight(clipped.right());
646
647
648void QListView::reset()
652 d->hiddenRows.clear();
653 QAbstractItemView::reset();
657
658
659void QListView::setRootIndex(
const QModelIndex &index)
662 d->column = qMax(0, qMin(d->column, d->model->columnCount(index) - 1));
663 QAbstractItemView::setRootIndex(index);
666 d->hiddenRows.clear();
670
671
672
673
675void QListView::scrollContentsBy(
int dx,
int dy)
678 d->delayedAutoScroll.stop();
679 d->commonListView->scrollContentsBy(dx, dy, d->state == QListView::DragSelectingState);
683
684
685
686
687
688void QListView::resizeContents(
int width,
int height)
691 d->setContentsSize(width, height);
695
696
697QSize QListView::contentsSize()
const
699 Q_D(
const QListView);
700 return d->contentsSize();
704
705
706void QListView::dataChanged(
const QModelIndex &topLeft,
const QModelIndex &bottomRight,
707 const QList<
int> &roles)
709 d_func()->commonListView->dataChanged(topLeft, bottomRight);
710 QAbstractItemView::dataChanged(topLeft, bottomRight, roles);
714
715
716void QListView::rowsInserted(
const QModelIndex &parent,
int start,
int end)
721 d->doDelayedItemsLayout();
722 QAbstractItemView::rowsInserted(parent, start, end);
726
727
728void QListView::rowsAboutToBeRemoved(
const QModelIndex &parent,
int start,
int end)
732 QAbstractItemView::rowsAboutToBeRemoved(parent, start, end);
733 if (parent == d->root) {
734 QSet<QPersistentModelIndex>::iterator it = d->hiddenRows.begin();
735 while (it != d->hiddenRows.end()) {
736 int hiddenRow = it->row();
737 if (hiddenRow >= start && hiddenRow <= end) {
738 it = d->hiddenRows.erase(it);
745 d->doDelayedItemsLayout();
749
750
751void QListView::mouseMoveEvent(QMouseEvent *e)
756 QAbstractItemView::mouseMoveEvent(e);
757 if (state() == DragSelectingState
758 && d->showElasticBand
759 && d->selectionMode != SingleSelection
760 && d->selectionMode != NoSelection) {
761 QRect rect(d->pressedPosition, e->position().toPoint() + QPoint(horizontalOffset(), verticalOffset()));
762 rect = rect.normalized();
763 const int margin = 2 * style()->pixelMetric(QStyle::PM_DefaultFrameWidth);
764 const QRect viewPortRect = rect.united(d->elasticBand)
765 .adjusted(-margin, -margin, margin, margin);
766 d->viewport->update(d->mapToViewport(viewPortRect));
767 d->elasticBand = rect;
772
773
774void QListView::mouseReleaseEvent(QMouseEvent *e)
777 QAbstractItemView::mouseReleaseEvent(e);
779 if (d->showElasticBand && d->elasticBand.isValid()) {
780 const int margin = 2 * style()->pixelMetric(QStyle::PM_DefaultFrameWidth);
781 const QRect viewPortRect = d->elasticBand.adjusted(-margin, -margin, margin, margin);
782 d->viewport->update(d->mapToViewport(viewPortRect));
783 d->elasticBand = QRect();
787#if QT_CONFIG(wheelevent)
789
790
791void QListView::wheelEvent(QWheelEvent *e)
794 if (qAbs(e->angleDelta().y()) > qAbs(e->angleDelta().x())) {
795 if (e->angleDelta().x() == 0
796 && ((d->flow == TopToBottom && d->wrap) || (d->flow == LeftToRight && !d->wrap))
797 && d->vbar->minimum() == 0 && d->vbar->maximum() == 0) {
798 QPoint pixelDelta(e->pixelDelta().y(), e->pixelDelta().x());
799 QPoint angleDelta(e->angleDelta().y(), e->angleDelta().x());
800 QWheelEvent hwe(e->position(), e->globalPosition(), pixelDelta, angleDelta,
801 e->buttons(), e->modifiers(), e->phase(), e->inverted(), e->source());
802 if (e->spontaneous())
803 qt_sendSpontaneousEvent(d->hbar, &hwe);
805 QCoreApplication::sendEvent(d->hbar, &hwe);
806 e->setAccepted(hwe.isAccepted());
808 QCoreApplication::sendEvent(d->vbar, e);
811 QCoreApplication::sendEvent(d->hbar, e);
817
818
819void QListView::timerEvent(QTimerEvent *e)
822 if (e->timerId() == d->batchLayoutTimer.timerId()) {
823 if (d->doItemsLayout(d->batchSize)) {
824 d->batchLayoutTimer.stop();
826 d->viewport->update();
829 QAbstractItemView::timerEvent(e);
833
834
835void QListView::resizeEvent(QResizeEvent *e)
838 if (d->delayedPendingLayout)
841 QSize delta = e->size() - e->oldSize();
846 bool listWrap = (d->viewMode == ListMode) && d->wrapItemText;
847 bool flowDimensionChanged = (d->flow == LeftToRight && delta.width() != 0)
848 || (d->flow == TopToBottom && delta.height() != 0);
854 || (state() == NoState && d->resizeMode == Adjust && flowDimensionChanged)) {
855 d->doDelayedItemsLayout(100);
857 QAbstractItemView::resizeEvent(e);
861#if QT_CONFIG(draganddrop)
864
865
866void QListView::dragMoveEvent(QDragMoveEvent *e)
869 if (!d->commonListView->filterDragMoveEvent(e)) {
870 if (viewMode() == QListView::ListMode && flow() == QListView::LeftToRight)
871 static_cast<QListModeViewBase *>(d->commonListView)->dragMoveEvent(e);
873 QAbstractItemView::dragMoveEvent(e);
879
880
881void QListView::dragLeaveEvent(QDragLeaveEvent *e)
883 if (!d_func()->commonListView->filterDragLeaveEvent(e))
884 QAbstractItemView::dragLeaveEvent(e);
888
889
890void QListView::dropEvent(QDropEvent *event)
894 const bool moveAction = event->dropAction() == Qt::MoveAction
895 || dragDropMode() == QAbstractItemView::InternalMove;
896 if (event->source() ==
this && moveAction) {
897 QModelIndex topIndex;
898 bool topIndexDropped =
false;
902 if (!event->isAccepted() && d->dropOn(event, &row, &col, &topIndex)) {
903 const QList<QModelIndex> selIndexes = selectedIndexes();
904 QList<QPersistentModelIndex> persIndexes;
905 persIndexes.reserve(selIndexes.size());
907 for (
const auto &index : selIndexes) {
908 persIndexes.append(index);
909 if (index == topIndex) {
910 topIndexDropped =
true;
915 if (!topIndexDropped && !topIndex.isValid()) {
916 std::sort(persIndexes.begin(), persIndexes.end());
918 QPersistentModelIndex dropRow = model()->index(row, col, topIndex);
920 int r = row == -1 ? model()->rowCount() : (dropRow.row() >= 0 ? dropRow.row() : row);
921 bool dataMoved =
false;
922 for (
const QPersistentModelIndex &pIndex : std::as_const(persIndexes)) {
924 if (r != pIndex.row() && r != pIndex.row() + 1) {
926 const bool moved = model()->moveRow(QModelIndex(), pIndex.row(), QModelIndex(), r);
934 r = pIndex.row() + 1;
943 if (event->isAccepted())
944 d->dropEventMoved =
true;
947 if (!d->commonListView->filterDropEvent(event) || !d->dropEventMoved) {
949 if (!d->dropEventMoved && moveAction)
951 QAbstractItemView::dropEvent(event);
956
957
958void QListView::startDrag(Qt::DropActions supportedActions)
960 if (!d_func()->commonListView->filterStartDrag(supportedActions))
961 QAbstractItemView::startDrag(supportedActions);
967
968
969void QListView::initViewItemOption(QStyleOptionViewItem *option)
const
971 Q_D(
const QListView);
972 QAbstractItemView::initViewItemOption(option);
973 if (!d->iconSize.isValid()) {
974 int pm = (d->viewMode == QListView::ListMode
975 ? style()->pixelMetric(QStyle::PM_ListViewIconSize,
nullptr,
this)
976 : style()->pixelMetric(QStyle::PM_IconViewIconSize,
nullptr,
this));
977 option->decorationSize = QSize(pm, pm);
979 if (d->viewMode == QListView::IconMode) {
980 option->showDecorationSelected =
false;
981 option->decorationPosition = QStyleOptionViewItem::Top;
982 option->displayAlignment = Qt::AlignCenter;
984 option->decorationPosition = QStyleOptionViewItem::Left;
987 if (d->gridSize().isValid()) {
988 option->rect.setSize(d->gridSize());
990 option->viewItemPosition = QStyleOptionViewItem::OnlyOne;
995
996
997void QListView::paintEvent(QPaintEvent *e)
1000 if (!d->itemDelegate)
1002 QStyleOptionViewItem option;
1003 initViewItemOption(&option);
1004 QStylePainter painter(d->viewport);
1006 const QList<QModelIndex> toBeRendered =
1007 d->intersectingSet(e->rect().translated(horizontalOffset(), verticalOffset()),
false);
1009 const QModelIndex current = currentIndex();
1010 const QModelIndex hover = d->hover;
1011 const QItemSelectionModel *selections = d->selectionModel;
1012 const bool focus = (hasFocus() || d->viewport->hasFocus()) && current.isValid();
1013 const bool alternate = d->alternatingColors;
1014 const QStyle::State state = option.state;
1015 const bool enabled = (state & QStyle::State_Enabled) != 0;
1017 bool alternateBase =
false;
1018 int previousRow = -2;
1020 int maxSize = (flow() == TopToBottom)
1021 ? qMax(viewport()->size().width(), d->contentsSize().width()) - 2 * d->spacing()
1022 : qMax(viewport()->size().height(), d->contentsSize().height()) - 2 * d->spacing();
1024 for (
const QModelIndex &index : toBeRendered) {
1025 Q_ASSERT(index.isValid());
1026 option.rect = visualRect(index);
1028 if (flow() == TopToBottom)
1029 option.rect.setWidth(qMin(maxSize, option.rect.width()));
1031 option.rect.setHeight(qMin(maxSize, option.rect.height()));
1033 const bool itemIsEnabled = enabled && index.flags().testFlag(Qt::ItemIsEnabled);
1034 option.state = state;
1035 option.state.setFlag(QStyle::State_Selected, selections && selections->isSelected(index));
1036 option.state.setFlag(QStyle::State_Enabled, itemIsEnabled);
1037 option.state.setFlag(QStyle::State_HasFocus, focus && current == index);
1038 option.state.setFlag(QStyle::State_MouseOver, index == hover);
1039 option.palette.setCurrentColorGroup(itemIsEnabled ? QPalette::Normal : QPalette::Disabled);
1042 int row = index.row();
1043 if (row != previousRow + 1) {
1045 if (!d->hiddenRows.isEmpty()) {
1046 for (
int r = qMax(previousRow + 1, 0); r < row; ++r) {
1047 if (!d->isHidden(r))
1048 alternateBase = !alternateBase;
1051 alternateBase = (row & 1) != 0;
1054 option.features.setFlag(QStyleOptionViewItem::Alternate, alternateBase);
1058 QStyle::State oldState = option.state;
1059 option.state &= ~QStyle::State_Selected;
1060 painter.drawPrimitive(QStyle::PE_PanelItemViewRow, option);
1061 option.state = oldState;
1063 alternateBase = !alternateBase;
1067 itemDelegateForIndex(index)->paint(&painter, option, index);
1070#if QT_CONFIG(draganddrop)
1071 d->commonListView->paintDragDrop(&painter);
1074#if QT_CONFIG(rubberband)
1076 if (d->showElasticBand && d->elasticBand.isValid()) {
1077 QStyleOptionRubberBand opt;
1079 opt.shape = QRubberBand::Rectangle;
1081 opt.rect = d->mapToViewport(d->elasticBand,
false).intersected(
1082 d->viewport->rect().adjusted(-16, -16, 16, 16));
1084 painter.drawControl(QStyle::CE_RubberBand, opt);
1091
1092
1093QModelIndex QListView::indexAt(
const QPoint &p)
const
1095 Q_D(
const QListView);
1096 QRect rect(p.x() + horizontalOffset(), p.y() + verticalOffset(), 1, 1);
1097 const QList<QModelIndex> intersectVector = d->intersectingSet(rect);
1098 QModelIndex index = intersectVector.size() > 0
1099 ? intersectVector.last() : QModelIndex();
1100 if (index.isValid() && visualRect(index).contains(p))
1102 return QModelIndex();
1106
1107
1108int QListView::horizontalOffset()
const
1110 return d_func()->commonListView->horizontalOffset();
1114
1115
1116int QListView::verticalOffset()
const
1118 return d_func()->commonListView->verticalOffset();
1122
1123
1124QModelIndex QListView::moveCursor(CursorAction cursorAction, Qt::KeyboardModifiers modifiers)
1127 Q_UNUSED(modifiers);
1129 auto findAvailableRowBackward = [d](
int row) {
1130 while (row >= 0 && d->isHiddenOrDisabled(row))
1135 auto findAvailableRowForward = [d](
int row) {
1136 int rowCount = d->model->rowCount(d->root);
1139 while (row < rowCount && d->isHiddenOrDisabled(row))
1141 if (row >= rowCount)
1146 QModelIndex current = currentIndex();
1147 if (!current.isValid()) {
1148 int row = findAvailableRowForward(0);
1150 return QModelIndex();
1151 return d->model->index(row, d->column, d->root);
1154 if ((d->flow == LeftToRight && cursorAction == MoveLeft) ||
1155 (d->flow == TopToBottom && (cursorAction == MoveUp || cursorAction == MovePrevious))) {
1156 const int row = findAvailableRowBackward(current.row() - 1);
1159 return d->model->index(row, d->column, d->root);
1160 }
else if ((d->flow == LeftToRight && cursorAction == MoveRight) ||
1161 (d->flow == TopToBottom && (cursorAction == MoveDown || cursorAction == MoveNext))) {
1162 const int row = findAvailableRowForward(current.row() + 1);
1165 return d->model->index(row, d->column, d->root);
1168 const QRect initialRect = rectForIndex(current);
1169 QRect rect = initialRect;
1170 if (rect.isEmpty()) {
1171 return d->model->index(0, d->column, d->root);
1173 if (d->gridSize().isValid()) rect.setSize(d->gridSize());
1175 QSize contents = d->contentsSize();
1176 QList<QModelIndex> intersectVector;
1178 switch (cursorAction) {
1180 while (intersectVector.isEmpty()) {
1181 rect.translate(-rect.width(), 0);
1182 if (rect.right() <= 0)
1184 if (rect.left() < 0)
1186 intersectVector = d->intersectingSet(rect);
1187 d->removeCurrentAndDisabled(&intersectVector, current);
1189 return d->closestIndex(initialRect, intersectVector);
1191 while (intersectVector.isEmpty()) {
1192 rect.translate(rect.width(), 0);
1193 if (rect.left() >= contents.width())
1195 if (rect.right() > contents.width())
1196 rect.setRight(contents.width());
1197 intersectVector = d->intersectingSet(rect);
1198 d->removeCurrentAndDisabled(&intersectVector, current);
1200 return d->closestIndex(initialRect, intersectVector);
1202 if (rect.height() >= d->viewport->height())
1203 return moveCursor(QAbstractItemView::MoveUp, modifiers);
1205 rect.moveTop(rect.top() - d->viewport->height() + 1);
1206 if (rect.top() < rect.height()) {
1210 QModelIndex findindex = current;
1211 while (intersectVector.isEmpty()
1212 || rectForIndex(findindex).top() <= (rectForIndex(current).bottom() - d->viewport->rect().height())
1213 || rect.top() <= 0) {
1214 rect.translate(0, 1);
1215 if (rect.bottom() <= 0) {
1218 intersectVector = d->intersectingSet(rect);
1219 findindex = d->closestIndex(initialRect, intersectVector);
1225 while (intersectVector.isEmpty()) {
1226 rect.translate(0, -rect.height());
1227 if (rect.bottom() <= 0) {
1228#ifdef QT_KEYPAD_NAVIGATION
1229 if (QApplicationPrivate::keypadNavigationEnabled()) {
1230 int row = d->batchStartRow() - 1;
1231 while (row >= 0 && d->isHiddenOrDisabled(row))
1234 return d->model->index(row, d->column, d->root);
1241 intersectVector = d->intersectingSet(rect);
1242 d->removeCurrentAndDisabled(&intersectVector, current);
1244 return d->closestIndex(initialRect, intersectVector);
1245 case MovePageDown: {
1246 if (rect.height() >= d->viewport->height())
1247 return moveCursor(QAbstractItemView::MoveDown, modifiers);
1249 rect.moveTop(rect.top() + d->viewport->height() - 1);
1250 if (rect.bottom() > contents.height() - rect.height()) {
1251 rect.setTop(contents.height() - 1);
1252 rect.setBottom(contents.height());
1254 QModelIndex index = current;
1256 while (intersectVector.isEmpty()
1257 || rectForIndex(index).bottom() >= (d->viewport->rect().height() + rectForIndex(current).top())
1258 || rect.bottom() > contents.height()) {
1259 rect.translate(0, -1);
1260 if (rect.top() >= contents.height()) {
1263 intersectVector = d->intersectingSet(rect);
1264 index = d->closestIndex(initialRect, intersectVector);
1270 while (intersectVector.isEmpty()) {
1271 rect.translate(0, rect.height());
1272 if (rect.top() >= contents.height()) {
1273#ifdef QT_KEYPAD_NAVIGATION
1274 if (QApplicationPrivate::keypadNavigationEnabled()) {
1275 int rowCount = d->model->rowCount(d->root);
1277 while (row < rowCount && d->isHiddenOrDisabled(row))
1280 return d->model->index(row, d->column, d->root);
1285 if (rect.bottom() > contents.height())
1286 rect.setBottom(contents.height());
1287 intersectVector = d->intersectingSet(rect);
1288 d->removeCurrentAndDisabled(&intersectVector, current);
1290 return d->closestIndex(initialRect, intersectVector);
1292 return d->model->index(0, d->column, d->root);
1294 return d->model->index(d->batchStartRow() - 1, d->column, d->root);}
1300
1301
1302
1303
1304
1305QRect QListView::rectForIndex(
const QModelIndex &index)
const
1307 return d_func()->rectForIndex(index);
1311
1312
1313
1314
1315
1316void QListView::setPositionForIndex(
const QPoint &position,
const QModelIndex &index)
1319 if (d->movement == Static
1320 || !d->isIndexValid(index)
1321 || index.parent() != d->root
1322 || index.column() != d->column)
1325 d->executePostedLayout();
1326 d->commonListView->setPositionForIndex(position, index);
1330
1331
1332void QListView::setSelection(
const QRect &rect, QItemSelectionModel::SelectionFlags command)
1335 if (!d->selectionModel)
1339 int w = qMax(d->contentsSize().width(), d->viewport->width());
1340 int h = qMax(d->contentsSize().height(), d->viewport->height());
1341 if (d->wrap && !QRect(0, 0, w, h).intersects(rect))
1344 QItemSelection selection;
1346 if (rect.width() == 1 && rect.height() == 1) {
1347 const QList<QModelIndex> intersectVector =
1348 d->intersectingSet(rect.translated(horizontalOffset(), verticalOffset()));
1350 if (!intersectVector.isEmpty())
1351 tl = intersectVector.last();
1352 if (tl.isValid() && d->isIndexEnabled(tl))
1353 selection.select(tl, tl);
1355 if (state() == DragSelectingState) {
1356 selection = d->selection(rect.translated(horizontalOffset(), verticalOffset()));
1360 const QRect topLeft(rect.left() + horizontalOffset(), rect.top() + verticalOffset(), 1, 1);
1361 QList<QModelIndex> intersectVector = d->intersectingSet(topLeft);
1362 if (!intersectVector.isEmpty())
1363 tl = intersectVector.last();
1365 const QRect bottomRight(rect.right() + horizontalOffset(), rect.bottom() + verticalOffset(), 1, 1);
1366 intersectVector = d->intersectingSet(bottomRight);
1367 if (!intersectVector.isEmpty())
1368 br = intersectVector.last();
1371 if (tl.isValid() && br.isValid()
1372 && d->isIndexEnabled(tl)
1373 && d->isIndexEnabled(br)) {
1374 QRect first = d->cellRectForIndex(tl);
1375 QRect last = d->cellRectForIndex(br);
1377 if (d->flow == LeftToRight) {
1379 QRect &bottom = last;
1381 if (top.center().y() > bottom.center().y()) {
1387 if (top.top() != bottom.top()) {
1389 if (isRightToLeft())
1392 top.setRight(contentsSize().width());
1394 if (isRightToLeft())
1395 bottom.setRight(contentsSize().width());
1398 }
else if (top.left() > bottom.right()) {
1399 if (isRightToLeft())
1400 bottom.setLeft(top.right());
1402 bottom.setRight(top.left());
1404 if (isRightToLeft())
1405 top.setLeft(bottom.right());
1407 top.setRight(bottom.left());
1410 if (top.bottom() < bottom.top()) {
1411 if (gridSize().isValid() && !gridSize().isNull())
1412 middle.setTop(top.top() + gridSize().height());
1414 middle.setTop(top.bottom() + 1);
1415 middle.setLeft(qMin(top.left(), bottom.left()));
1416 middle.setBottom(bottom.top() - 1);
1417 middle.setRight(qMax(top.right(), bottom.right()));
1420 QRect &left = first;
1421 QRect &right = last;
1422 if (left.center().x() > right.center().x())
1425 int ch = contentsSize().height();
1426 if (left.left() != right.left()) {
1428 if (isRightToLeft())
1434 if (isRightToLeft())
1435 right.setBottom(ch);
1440 middle.setBottom(ch);
1441 if (gridSize().isValid() && !gridSize().isNull())
1442 middle.setLeft(left.left() + gridSize().width());
1444 middle.setLeft(left.right() + 1);
1445 middle.setRight(right.left() - 1);
1446 }
else if (left.bottom() < right.top()) {
1447 left.setBottom(right.top() - 1);
1449 right.setBottom(left.top() - 1);
1454 QItemSelection topSelection = d->selection(first);
1455 QItemSelection middleSelection = d->selection(middle);
1456 QItemSelection bottomSelection = d->selection(last);
1458 selection.merge(topSelection, QItemSelectionModel::Select);
1459 selection.merge(middleSelection, QItemSelectionModel::Select);
1460 selection.merge(bottomSelection, QItemSelectionModel::Select);
1465 d->selectionModel->select(selection, command);
1469
1470
1471
1472
1473
1474QRegion QListView::visualRegionForSelection(
const QItemSelection &selection)
const
1476 Q_D(
const QListView);
1479 QRegion selectionRegion;
1480 const QRect &viewportRect = d->viewport->rect();
1481 for (
const auto &elem : selection) {
1482 if (!elem.isValid())
1484 QModelIndex parent = elem.topLeft().parent();
1487 if (parent != d->root)
1489 int t = elem.topLeft().row();
1490 int b = elem.bottomRight().row();
1491 if (d->viewMode == IconMode || d->isWrapping()) {
1492 for (
int r = t; r <= b; ++r) {
1493 const QRect &rect = visualRect(d->model->index(r, c, parent));
1494 if (viewportRect.intersects(rect))
1495 selectionRegion += rect;
1498 while (t <= b && d->isHidden(t)) ++t;
1499 while (b >= t && d->isHidden(b)) --b;
1500 const QModelIndex top = d->model->index(t, c, parent);
1501 const QModelIndex bottom = d->model->index(b, c, parent);
1502 QRect rect(visualRect(top).topLeft(),
1503 visualRect(bottom).bottomRight());
1504 if (viewportRect.intersects(rect))
1505 selectionRegion += rect;
1509 return selectionRegion;
1513
1514
1515QModelIndexList QListView::selectedIndexes()
const
1517 Q_D(
const QListView);
1518 if (!d->selectionModel)
1519 return QModelIndexList();
1521 QModelIndexList viewSelected = d->selectionModel->selectedIndexes();
1522 auto ignorable = [
this, d](
const QModelIndex &index) {
1523 return index.column() != d->column || index.parent() != d->root || isIndexHidden(index);
1525 viewSelected.removeIf(ignorable);
1526 return viewSelected;
1530
1531
1532
1533
1534void QListView::doItemsLayout()
1540 QAbstractItemView::State oldState = state();
1541 setState(ExpandingState);
1542 if (d->model->columnCount(d->root) > 0) {
1543 d->resetBatchStartRow();
1544 if (layoutMode() == SinglePass) {
1545 d->doItemsLayout(d->model->rowCount(d->root));
1546 }
else if (!d->batchLayoutTimer.isActive()) {
1547 if (!d->doItemsLayout(d->batchSize))
1548 d->batchLayoutTimer.start(0,
this);
1553 QAbstractItemView::doItemsLayout();
1558
1559
1560void QListView::updateGeometries()
1563 if (geometry().isEmpty() || d->model->rowCount(d->root) <= 0 || d->model->columnCount(d->root) <= 0) {
1564 horizontalScrollBar()->setRange(0, 0);
1565 verticalScrollBar()->setRange(0, 0);
1567 QModelIndex index = d->model->index(0, d->column, d->root);
1568 QStyleOptionViewItem option;
1569 initViewItemOption(&option);
1570 QSize step = d->itemSize(option, index);
1571 d->commonListView->updateHorizontalScrollBar(step);
1572 d->commonListView->updateVerticalScrollBar(step);
1575 QAbstractItemView::updateGeometries();
1578 if (d->movement == Static && !d->isWrapping()) {
1579 d->layoutChildren();
1580 if (d->flow == TopToBottom) {
1581 if (horizontalScrollBarPolicy() == Qt::ScrollBarAlwaysOff) {
1582 d->setContentsSize(viewport()->width(), contentsSize().height());
1583 horizontalScrollBar()->setRange(0, 0);
1586 if (verticalScrollBarPolicy() == Qt::ScrollBarAlwaysOff) {
1587 d->setContentsSize(contentsSize().width(), viewport()->height());
1588 verticalScrollBar()->setRange(0, 0);
1596
1597
1598bool QListView::isIndexHidden(
const QModelIndex &index)
const
1600 Q_D(
const QListView);
1601 return (d->isHidden(index.row())
1602 && (index.parent() == d->root)
1603 && index.column() == d->column);
1607
1608
1609
1610
1611
1612
1613void QListView::setModelColumn(
int column)
1616 if (column < 0 || column >= d->model->columnCount(d->root))
1619 d->doDelayedItemsLayout();
1620#if QT_CONFIG(accessibility)
1621 if (QAccessible::isActive()) {
1622 QAccessibleTableModelChangeEvent event(
this, QAccessibleTableModelChangeEvent::ModelReset);
1623 QAccessible::updateAccessibility(&event);
1628int QListView::modelColumn()
const
1630 Q_D(
const QListView);
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644void QListView::setUniformItemSizes(
bool enable)
1647 d->uniformItemSizes = enable;
1650bool QListView::uniformItemSizes()
const
1652 Q_D(
const QListView);
1653 return d->uniformItemSizes;
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669void QListView::setWordWrap(
bool on)
1672 if (d->wrapItemText == on)
1674 d->wrapItemText = on;
1675 d->doDelayedItemsLayout();
1678bool QListView::wordWrap()
const
1680 Q_D(
const QListView);
1681 return d->wrapItemText;
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698void QListView::setSelectionRectVisible(
bool show)
1701 d->modeProperties |= uint(QListViewPrivate::SelectionRectVisible);
1702 d->setSelectionRectVisible(show);
1705bool QListView::isSelectionRectVisible()
const
1707 Q_D(
const QListView);
1708 return d->isSelectionRectVisible();
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721void QListView::setItemAlignment(Qt::Alignment alignment)
1724 if (d->itemAlignment == alignment)
1726 d->itemAlignment = alignment;
1727 if (viewMode() == ListMode && flow() == QListView::TopToBottom && isWrapping())
1728 d->doDelayedItemsLayout();
1731Qt::Alignment QListView::itemAlignment()
const
1733 Q_D(
const QListView);
1734 return d->itemAlignment;
1738
1739
1740bool QListView::event(QEvent *e)
1742 return QAbstractItemView::event(e);
1746
1747
1749QListViewPrivate::QListViewPrivate()
1750 : QAbstractItemViewPrivate(),
1751 commonListView(
nullptr),
1754 flow(QListView::TopToBottom),
1755 movement(QListView::Static),
1756 resizeMode(QListView::Fixed),
1757 layoutMode(QListView::SinglePass),
1758 viewMode(QListView::ListMode),
1761 uniformItemSizes(
false),
1763 showElasticBand(
false),
1764 itemAlignment(Qt::Alignment())
1768QListViewPrivate::~QListViewPrivate()
1770 delete commonListView;
1773void QListViewPrivate::clear()
1776 cachedItemSize = QSize();
1777 commonListView->clear();
1780void QListViewPrivate::prepareItemsLayout()
1786 layoutBounds = QRect(QPoint(), q->maximumViewportSize());
1788 int frameAroundContents = 0;
1789 if (q->style()->styleHint(QStyle::SH_ScrollView_FrameOnlyAroundContents,
nullptr, q)) {
1790 QStyleOption option;
1792 frameAroundContents = q->style()->pixelMetric(QStyle::PM_DefaultFrameWidth, &option, q) * 2;
1798 int verticalMargin = (vbarpolicy == Qt::ScrollBarAsNeeded) && (flow == QListView::LeftToRight || vbar->isVisible())
1799 && !q->style()->pixelMetric(QStyle::PM_ScrollView_ScrollBarOverlap,
nullptr, vbar)
1800 ? q->style()->pixelMetric(QStyle::PM_ScrollBarExtent,
nullptr, vbar) + frameAroundContents
1802 int horizontalMargin = hbarpolicy==Qt::ScrollBarAsNeeded
1803 ? q->style()->pixelMetric(QStyle::PM_ScrollBarExtent,
nullptr, hbar) + frameAroundContents
1806 layoutBounds.adjust(0, 0, -verticalMargin, -horizontalMargin);
1808 int rowCount = model->columnCount(root) <= 0 ? 0 : model->rowCount(root);
1809 commonListView->setRowCount(rowCount);
1813
1814
1815bool QListViewPrivate::doItemsLayout(
int delta)
1817 int max = model->rowCount(root) - 1;
1818 int first = batchStartRow();
1819 int last = qMin(first + delta - 1, max);
1823 prepareItemsLayout();
1826 if (max < 0 || last < first) {
1830 QListViewLayoutInfo info;
1831 info.bounds = layoutBounds;
1832 info.grid = gridSize();
1833 info.spacing = (info.grid.isValid() ? 0 : spacing());
1836 info.wrap = isWrapping();
1840 return commonListView->doBatchedItemLayout(info, max);
1843QListViewItem QListViewPrivate::indexToListViewItem(
const QModelIndex &index)
const
1845 if (!index.isValid() || isHidden(index.row()))
1846 return QListViewItem();
1848 return commonListView->indexToListViewItem(index);
1851QRect QListViewPrivate::mapToViewport(
const QRect &rect,
bool extend)
const
1853 Q_Q(
const QListView);
1854 if (!rect.isValid())
1857 QRect result = extend ? commonListView->mapToViewport(rect) : rect;
1858 int dx = -q->horizontalOffset();
1859 int dy = -q->verticalOffset();
1860 return result.adjusted(dx, dy, dx, dy);
1863QModelIndex QListViewPrivate::closestIndex(
const QRect &target,
1864 const QList<QModelIndex> &candidates)
const
1867 int shortest = INT_MAX;
1868 QModelIndex closest;
1869 QList<QModelIndex>::const_iterator it = candidates.begin();
1871 for (; it != candidates.end(); ++it) {
1872 if (!(*it).isValid())
1875 const QRect indexRect = indexToListViewItem(*it).rect();
1880 if ((target.center().x() >= indexRect.x() && target.center().x() < indexRect.right())
1881 || (indexRect.center().x() >= target.x() && indexRect.center().x() < target.right())) {
1883 distance = qAbs(indexRect.center().y() - target.center().y());
1884 }
else if ((target.center().y() >= indexRect.y() && target.center().y() < indexRect.bottom())
1885 || (indexRect.center().y() >= target.y() && indexRect.center().y() < target.bottom())) {
1887 distance = qAbs(indexRect.center().x() - target.center().x());
1889 distance = (indexRect.center() - target.center()).manhattanLength();
1891 if (distance < shortest) {
1892 shortest = distance;
1899QSize QListViewPrivate::itemSize(
const QStyleOptionViewItem &option,
const QModelIndex &index)
const
1901 Q_Q(
const QListView);
1902 if (!uniformItemSizes) {
1903 const QAbstractItemDelegate *delegate = q->itemDelegateForIndex(index);
1904 return delegate ? delegate->sizeHint(option, index) : QSize();
1906 if (!cachedItemSize.isValid()) {
1907 int row = model->rowCount(root) - 1;
1908 QModelIndex sample = model->index(row, column, root);
1909 const QAbstractItemDelegate *delegate = q->itemDelegateForIndex(sample);
1910 cachedItemSize = delegate ? delegate->sizeHint(option, sample) : QSize();
1912 return cachedItemSize;
1915QItemSelection QListViewPrivate::selection(
const QRect &rect)
const
1917 QItemSelection selection;
1919 const QList<QModelIndex> intersectVector = intersectingSet(rect);
1920 QList<QModelIndex>::const_iterator it = intersectVector.begin();
1921 for (; it != intersectVector.end(); ++it) {
1922 if (!tl.isValid() && !br.isValid()) {
1924 }
else if ((*it).row() == (tl.row() - 1)) {
1926 }
else if ((*it).row() == (br.row() + 1)) {
1929 selection.select(tl, br);
1934 if (tl.isValid() && br.isValid())
1935 selection.select(tl, br);
1936 else if (tl.isValid())
1937 selection.select(tl, tl);
1938 else if (br.isValid())
1939 selection.select(br, br);
1944#if QT_CONFIG(draganddrop)
1945QAbstractItemView::DropIndicatorPosition QListViewPrivate::position(
const QPoint &pos,
const QRect &rect,
const QModelIndex &idx)
const
1947 if (viewMode == QListView::ListMode && flow == QListView::LeftToRight)
1948 return static_cast<QListModeViewBase *>(commonListView)->position(pos, rect, idx);
1950 return QAbstractItemViewPrivate::position(pos, rect, idx);
1953bool QListViewPrivate::dropOn(QDropEvent *event,
int *dropRow,
int *dropCol, QModelIndex *dropIndex)
1955 if (viewMode == QListView::ListMode && flow == QListView::LeftToRight)
1956 return static_cast<QListModeViewBase *>(commonListView)->dropOn(event, dropRow, dropCol, dropIndex);
1958 return QAbstractItemViewPrivate::dropOn(event, dropRow, dropCol, dropIndex);
1962#if QT_CONFIG(accessibility)
1963int QListViewPrivate::accessibleChildIndex(
const QModelIndex &index)
const
1965 Q_Q(
const QListView);
1966 return q->visualIndex(index);
1970void QListViewPrivate::removeCurrentAndDisabled(QList<QModelIndex> *indexes,
1971 const QModelIndex ¤t)
const
1973 auto isCurrentOrDisabled = [
this, current](
const QModelIndex &index) {
1974 return !isIndexEnabled(index) || index == current;
1976 indexes->removeIf(isCurrentOrDisabled);
1980
1981
1983void QCommonListViewBase::appendHiddenRow(
int row)
1985 dd->hiddenRows.insert(dd->model->index(row, 0, qq->rootIndex()));
1988void QCommonListViewBase::removeHiddenRow(
int row)
1990 dd->hiddenRows.remove(dd->model->index(row, 0, qq->rootIndex()));
1993#if QT_CONFIG(draganddrop)
1994void QCommonListViewBase::paintDragDrop(QPainter *painter)
1998 dd->paintDropIndicator(painter);
2002QSize QListModeViewBase::viewportSize(
const QAbstractItemView *v)
2004 return v->contentsRect().marginsRemoved(v->viewportMargins()).size();
2007void QCommonListViewBase::updateHorizontalScrollBar(
const QSize &step)
2009 horizontalScrollBar()->d_func()->itemviewChangeSingleStep(step.width() + spacing());
2010 horizontalScrollBar()->setPageStep(viewport()->width());
2016 const bool bothScrollBarsAuto = qq->verticalScrollBarPolicy() == Qt::ScrollBarAsNeeded &&
2017 qq->horizontalScrollBarPolicy() == Qt::ScrollBarAsNeeded;
2019 const QSize viewportSize = QListModeViewBase::viewportSize(qq);
2021 bool verticalWantsToShow = contentsSize.height() > viewportSize.height();
2022 bool horizontalWantsToShow;
2023 if (verticalWantsToShow)
2024 horizontalWantsToShow = contentsSize.width() > viewportSize.width() - qq->verticalScrollBar()->width();
2026 horizontalWantsToShow = contentsSize.width() > viewportSize.width();
2028 if (bothScrollBarsAuto && !horizontalWantsToShow) {
2031 horizontalScrollBar()->setRange(0, 0);
2033 horizontalScrollBar()->setRange(0, contentsSize.width() - viewport()->width());
2037void QCommonListViewBase::updateVerticalScrollBar(
const QSize &step)
2039 verticalScrollBar()->d_func()->itemviewChangeSingleStep(step.height() + spacing());
2040 verticalScrollBar()->setPageStep(viewport()->height());
2046 const bool bothScrollBarsAuto = qq->verticalScrollBarPolicy() == Qt::ScrollBarAsNeeded &&
2047 qq->horizontalScrollBarPolicy() == Qt::ScrollBarAsNeeded;
2049 const QSize viewportSize = QListModeViewBase::viewportSize(qq);
2051 bool horizontalWantsToShow = contentsSize.width() > viewportSize.width();
2052 bool verticalWantsToShow;
2053 if (horizontalWantsToShow)
2054 verticalWantsToShow = contentsSize.height() > viewportSize.height() - qq->horizontalScrollBar()->height();
2056 verticalWantsToShow = contentsSize.height() > viewportSize.height();
2058 if (bothScrollBarsAuto && !verticalWantsToShow) {
2061 verticalScrollBar()->setRange(0, 0);
2063 verticalScrollBar()->setRange(0, contentsSize.height() - viewport()->height());
2067void QCommonListViewBase::scrollContentsBy(
int dx,
int dy,
bool )
2069 dd->scrollContentsBy(isRightToLeft() ? -dx : dx, dy);
2072int QCommonListViewBase::verticalScrollToValue(
int , QListView::ScrollHint hint,
2073 bool above,
bool below,
const QRect &area,
const QRect &rect)
const
2075 int verticalValue = verticalScrollBar()->value();
2076 QRect adjusted = rect.adjusted(-spacing(), -spacing(), spacing(), spacing());
2077 if (hint == QListView::PositionAtTop || above)
2078 verticalValue += adjusted.top();
2079 else if (hint == QListView::PositionAtBottom || below)
2080 verticalValue += qMin(adjusted.top(), adjusted.bottom() - area.height() + 1);
2081 else if (hint == QListView::PositionAtCenter)
2082 verticalValue += adjusted.top() - ((area.height() - adjusted.height()) / 2);
2083 return verticalValue;
2086int QCommonListViewBase::horizontalOffset()
const
2088 return (isRightToLeft() ? horizontalScrollBar()->maximum() - horizontalScrollBar()->value() : horizontalScrollBar()->value());
2091int QCommonListViewBase::horizontalScrollToValue(
const int , QListView::ScrollHint hint,
2092 bool leftOf,
bool rightOf,
const QRect &area,
const QRect &rect)
const
2094 int horizontalValue = horizontalScrollBar()->value();
2095 if (isRightToLeft()) {
2096 if (hint == QListView::PositionAtCenter) {
2097 horizontalValue += ((area.width() - rect.width()) / 2) - rect.left();
2100 horizontalValue -= rect.left();
2102 horizontalValue += qMin(rect.left(), area.width() - rect.right());
2105 if (hint == QListView::PositionAtCenter) {
2106 horizontalValue += rect.left() - ((area.width()- rect.width()) / 2);
2109 horizontalValue += rect.left();
2111 horizontalValue += qMin(rect.left(), rect.right() - area.width());
2114 return horizontalValue;
2118
2119
2120QListModeViewBase::QListModeViewBase(QListView *q, QListViewPrivate *d)
2121 : QCommonListViewBase(q, d)
2123#if QT_CONFIG(draganddrop)
2124 dd->defaultDropAction = Qt::CopyAction;
2128#if QT_CONFIG(draganddrop)
2129QAbstractItemView::DropIndicatorPosition QListModeViewBase::position(
const QPoint &pos,
const QRect &rect,
const QModelIndex &index)
const
2131 QAbstractItemView::DropIndicatorPosition r = QAbstractItemView::OnViewport;
2132 if (!dd->overwrite) {
2133 const int margin = 2;
2134 if (pos.x() - rect.left() < margin) {
2135 r = QAbstractItemView::AboveItem;
2136 }
else if (rect.right() - pos.x() < margin) {
2137 r = QAbstractItemView::BelowItem;
2138 }
else if (rect.contains(pos,
true)) {
2139 r = QAbstractItemView::OnItem;
2142 QRect touchingRect = rect;
2143 touchingRect.adjust(-1, -1, 1, 1);
2144 if (touchingRect.contains(pos,
false)) {
2145 r = QAbstractItemView::OnItem;
2149 if (r == QAbstractItemView::OnItem && (!(dd->model->flags(index) & Qt::ItemIsDropEnabled)))
2150 r = pos.x() < rect.center().x() ? QAbstractItemView::AboveItem : QAbstractItemView::BelowItem;
2155void QListModeViewBase::dragMoveEvent(QDragMoveEvent *event)
2157 if (qq->dragDropMode() == QAbstractItemView::InternalMove
2158 && (event->source() != qq || !(event->possibleActions() & Qt::MoveAction)))
2165 QPoint p = event->position().toPoint();
2166 QRect rect(p.x() + horizontalOffset(), p.y() + verticalOffset(), 1, 1);
2167 rect.adjust(-dd->spacing(), -dd->spacing(), dd->spacing(), dd->spacing());
2168 const QList<QModelIndex> intersectVector = dd->intersectingSet(rect);
2169 QModelIndex index = intersectVector.size() > 0
2170 ? intersectVector.last() : QModelIndex();
2172 if (!dd->droppingOnItself(event, index)
2173 && dd->canDrop(event)) {
2175 if (index.isValid() && dd->showDropIndicator) {
2176 QRect rect = qq->visualRect(index);
2177 dd->dropIndicatorPosition = position(event->position().toPoint(), rect, index);
2179 switch (dd->dropIndicatorPosition) {
2180 case QAbstractItemView::AboveItem:
2181 if (dd->isIndexDropEnabled(index.parent())) {
2182 dd->dropIndicatorRect = QRect(rect.left()-dd->spacing(), rect.top(), 0, rect.height());
2185 dd->dropIndicatorRect = QRect();
2188 case QAbstractItemView::BelowItem:
2189 if (dd->isIndexDropEnabled(index.parent())) {
2190 dd->dropIndicatorRect = QRect(rect.right()+dd->spacing(), rect.top(), 0, rect.height());
2193 dd->dropIndicatorRect = QRect();
2196 case QAbstractItemView::OnItem:
2197 if (dd->isIndexDropEnabled(index)) {
2198 dd->dropIndicatorRect = rect;
2201 dd->dropIndicatorRect = QRect();
2204 case QAbstractItemView::OnViewport:
2205 dd->dropIndicatorRect = QRect();
2206 if (dd->isIndexDropEnabled(qq->rootIndex())) {
2212 dd->dropIndicatorRect = QRect();
2213 dd->dropIndicatorPosition = QAbstractItemView::OnViewport;
2214 if (dd->isIndexDropEnabled(qq->rootIndex())) {
2218 dd->viewport->update();
2221 if (dd->shouldAutoScroll(event->position().toPoint()))
2222 qq->startAutoScroll();
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236bool QListModeViewBase::dropOn(QDropEvent *event,
int *dropRow,
int *dropCol, QModelIndex *dropIndex)
2238 if (event->isAccepted())
2242 if (dd->viewport->rect().contains(event->position().toPoint())) {
2244 QPoint p = event->position().toPoint();
2245 QRect rect(p.x() + horizontalOffset(), p.y() + verticalOffset(), 1, 1);
2246 rect.adjust(-dd->spacing(), -dd->spacing(), dd->spacing(), dd->spacing());
2247 const QList<QModelIndex> intersectVector = dd->intersectingSet(rect);
2248 index = intersectVector.size() > 0
2249 ? intersectVector.last() : QModelIndex();
2250 if (!index.isValid())
2255 if (dd->model->supportedDropActions() & event->dropAction()) {
2258 if (index != dd->root) {
2259 dd->dropIndicatorPosition = position(event->position().toPoint(), qq->visualRect(index), index);
2260 switch (dd->dropIndicatorPosition) {
2261 case QAbstractItemView::AboveItem:
2263 col = index.column();
2264 index = index.parent();
2266 case QAbstractItemView::BelowItem:
2267 row = index.row() + 1;
2268 col = index.column();
2269 index = index.parent();
2271 case QAbstractItemView::OnItem:
2272 case QAbstractItemView::OnViewport:
2276 dd->dropIndicatorPosition = QAbstractItemView::OnViewport;
2281 if (!dd->droppingOnItself(event, index))
2289void QListModeViewBase::updateVerticalScrollBar(
const QSize &step)
2291 if (verticalScrollMode() == QAbstractItemView::ScrollPerItem
2292 && ((flow() == QListView::TopToBottom && !isWrapping())
2293 || (flow() == QListView::LeftToRight && isWrapping()))) {
2294 const int steps = (flow() == QListView::TopToBottom ? scrollValueMap : segmentPositions).size() - 1;
2296 const int pageSteps = perItemScrollingPageSteps(viewport()->height(), contentsSize.height(), isWrapping());
2297 verticalScrollBar()->setSingleStep(1);
2298 verticalScrollBar()->setPageStep(pageSteps);
2299 verticalScrollBar()->setRange(0, steps - pageSteps);
2301 verticalScrollBar()->setRange(0, 0);
2306 QCommonListViewBase::updateVerticalScrollBar(step);
2310void QListModeViewBase::updateHorizontalScrollBar(
const QSize &step)
2312 if (horizontalScrollMode() == QAbstractItemView::ScrollPerItem
2313 && ((flow() == QListView::TopToBottom && isWrapping())
2314 || (flow() == QListView::LeftToRight && !isWrapping()))) {
2315 int steps = (flow() == QListView::TopToBottom ? segmentPositions : scrollValueMap).size() - 1;
2317 const int pageSteps = perItemScrollingPageSteps(viewport()->width(), contentsSize.width(), isWrapping());
2318 horizontalScrollBar()->setSingleStep(1);
2319 horizontalScrollBar()->setPageStep(pageSteps);
2320 horizontalScrollBar()->setRange(0, steps - pageSteps);
2322 horizontalScrollBar()->setRange(0, 0);
2325 QCommonListViewBase::updateHorizontalScrollBar(step);
2329int QListModeViewBase::verticalScrollToValue(
int index, QListView::ScrollHint hint,
2330 bool above,
bool below,
const QRect &area,
const QRect &rect)
const
2332 if (verticalScrollMode() == QAbstractItemView::ScrollPerItem) {
2334 if (scrollValueMap.isEmpty()) {
2337 int scrollBarValue = verticalScrollBar()->value();
2339 for (
const auto &idx : std::as_const(dd->hiddenRows))
2340 if (idx.row() <= scrollBarValue)
2342 value = qBound(0, scrollValueMap.at(verticalScrollBar()->value()) - numHidden, flowPositions.size() - 1);
2345 hint = QListView::PositionAtTop;
2347 hint = QListView::PositionAtBottom;
2348 if (hint == QListView::EnsureVisible)
2351 return perItemScrollToValue(index, value, area.height(), hint, Qt::Vertical, isWrapping(), rect.height());
2354 return QCommonListViewBase::verticalScrollToValue(index, hint, above, below, area, rect);
2357int QListModeViewBase::horizontalOffset()
const
2359 if (horizontalScrollMode() == QAbstractItemView::ScrollPerItem) {
2361 if (flow() == QListView::TopToBottom && !segmentPositions.isEmpty()) {
2362 const int max = segmentPositions.size() - 1;
2363 int currentValue = qBound(0, horizontalScrollBar()->value(), max);
2364 int position = segmentPositions.at(currentValue);
2365 int maximumValue = qBound(0, horizontalScrollBar()->maximum(), max);
2366 int maximum = segmentPositions.at(maximumValue);
2367 return (isRightToLeft() ? maximum - position : position);
2369 }
else if (flow() == QListView::LeftToRight && !flowPositions.isEmpty()) {
2370 int position = flowPositions.at(scrollValueMap.at(horizontalScrollBar()->value()));
2371 int maximum = flowPositions.at(scrollValueMap.at(horizontalScrollBar()->maximum()));
2372 return (isRightToLeft() ? maximum - position : position);
2375 return QCommonListViewBase::horizontalOffset();
2378int QListModeViewBase::verticalOffset()
const
2380 if (verticalScrollMode() == QAbstractItemView::ScrollPerItem) {
2382 if (flow() == QListView::LeftToRight && !segmentPositions.isEmpty()) {
2383 int value = verticalScrollBar()->value();
2384 if (value >= segmentPositions.size())
2386 return segmentPositions.at(value) - spacing();
2388 }
else if (flow() == QListView::TopToBottom && !flowPositions.isEmpty()) {
2389 int value = verticalScrollBar()->value();
2390 if (value > scrollValueMap.size())
2392 return flowPositions.at(scrollValueMap.at(value)) - spacing();
2395 return QCommonListViewBase::verticalOffset();
2398int QListModeViewBase::horizontalScrollToValue(
int index, QListView::ScrollHint hint,
2399 bool leftOf,
bool rightOf,
const QRect &area,
const QRect &rect)
const
2401 if (horizontalScrollMode() != QAbstractItemView::ScrollPerItem)
2402 return QCommonListViewBase::horizontalScrollToValue(index, hint, leftOf, rightOf, area, rect);
2405 if (scrollValueMap.isEmpty())
2408 value = qBound(0, scrollValueMap.at(horizontalScrollBar()->value()), flowPositions.size() - 1);
2410 hint = QListView::PositionAtTop;
2412 hint = QListView::PositionAtBottom;
2413 if (hint == QListView::EnsureVisible)
2416 return perItemScrollToValue(index, value, area.width(), hint, Qt::Horizontal, isWrapping(), rect.width());
2419void QListModeViewBase::scrollContentsBy(
int dx,
int dy,
bool scrollElasticBand)
2422 const int verticalValue = verticalScrollBar()->value();
2423 const int horizontalValue = horizontalScrollBar()->value();
2424 const bool vertical = (verticalScrollMode() == QAbstractItemView::ScrollPerItem);
2425 const bool horizontal = (horizontalScrollMode() == QAbstractItemView::ScrollPerItem);
2428 if (segmentPositions.isEmpty())
2430 const int max = segmentPositions.size() - 1;
2431 if (horizontal && flow() == QListView::TopToBottom && dx != 0) {
2432 int currentValue = qBound(0, horizontalValue, max);
2433 int previousValue = qBound(0, currentValue + dx, max);
2434 int currentCoordinate = segmentPositions.at(currentValue) - spacing();
2435 int previousCoordinate = segmentPositions.at(previousValue) - spacing();
2436 dx = previousCoordinate - currentCoordinate;
2437 }
else if (vertical && flow() == QListView::LeftToRight && dy != 0) {
2438 int currentValue = qBound(0, verticalValue, max);
2439 int previousValue = qBound(0, currentValue + dy, max);
2440 int currentCoordinate = segmentPositions.at(currentValue) - spacing();
2441 int previousCoordinate = segmentPositions.at(previousValue) - spacing();
2442 dy = previousCoordinate - currentCoordinate;
2445 if (flowPositions.isEmpty())
2447 const int max = scrollValueMap.size() - 1;
2448 if (vertical && flow() == QListView::TopToBottom && dy != 0) {
2449 int currentValue = qBound(0, verticalValue, max);
2450 int previousValue = qBound(0, currentValue + dy, max);
2451 int currentCoordinate = flowPositions.at(scrollValueMap.at(currentValue));
2452 int previousCoordinate = flowPositions.at(scrollValueMap.at(previousValue));
2453 dy = previousCoordinate - currentCoordinate;
2454 }
else if (horizontal && flow() == QListView::LeftToRight && dx != 0) {
2455 int currentValue = qBound(0, horizontalValue, max);
2456 int previousValue = qBound(0, currentValue + dx, max);
2457 int currentCoordinate = flowPositions.at(scrollValueMap.at(currentValue));
2458 int previousCoordinate = flowPositions.at(scrollValueMap.at(previousValue));
2459 dx = previousCoordinate - currentCoordinate;
2462 QCommonListViewBase::scrollContentsBy(dx, dy, scrollElasticBand);
2465bool QListModeViewBase::doBatchedItemLayout(
const QListViewLayoutInfo &info,
int max)
2467 doStaticLayout(info);
2468 return batchStartRow > max;
2471QListViewItem QListModeViewBase::indexToListViewItem(
const QModelIndex &index)
const
2473 if (flowPositions.isEmpty()
2474 || segmentPositions.isEmpty()
2475 || index.row() >= flowPositions.size() - 1)
2476 return QListViewItem();
2478 const int segment = qBinarySearch<
int>(segmentStartRows, index.row(),
2479 0, segmentStartRows.size() - 1);
2482 QStyleOptionViewItem options;
2483 initViewItemOption(&options);
2484 options.rect.setSize(contentsSize);
2485 QSize size = (uniformItemSizes() && cachedItemSize().isValid())
2486 ? cachedItemSize() : itemSize(options, index);
2487 QSize cellSize = size;
2490 if (flow() == QListView::LeftToRight) {
2491 pos.setX(flowPositions.at(index.row()));
2492 pos.setY(segmentPositions.at(segment));
2494 pos.setY(flowPositions.at(index.row()));
2495 pos.setX(segmentPositions.at(segment));
2497 int right = (segment + 1 >= segmentPositions.size()
2498 ? contentsSize.width()
2499 : segmentPositions.at(segment + 1));
2500 cellSize.setWidth(right - pos.x());
2502 cellSize.setWidth(qMax(size.width(), viewport()->width() - 2 * spacing()));
2506 if (dd->itemAlignment & Qt::AlignHorizontal_Mask) {
2507 size.setWidth(qMin(size.width(), cellSize.width()));
2508 if (dd->itemAlignment & Qt::AlignRight)
2509 pos.setX(pos.x() + cellSize.width() - size.width());
2510 if (dd->itemAlignment & Qt::AlignHCenter)
2511 pos.setX(pos.x() + (cellSize.width() - size.width()) / 2);
2513 size.setWidth(cellSize.width());
2516 return QListViewItem(QRect(pos, size), index.row());
2519QPoint QListModeViewBase::initStaticLayout(
const QListViewLayoutInfo &info)
2522 if (info.first == 0) {
2523 flowPositions.clear();
2524 segmentPositions.clear();
2525 segmentStartRows.clear();
2526 segmentExtents.clear();
2527 scrollValueMap.clear();
2528 x = info.bounds.left() + info.spacing;
2529 y = info.bounds.top() + info.spacing;
2530 segmentPositions.append(info.flow == QListView::LeftToRight ? y : x);
2531 segmentStartRows.append(0);
2532 }
else if (info.wrap) {
2533 if (info.flow == QListView::LeftToRight) {
2534 x = batchSavedPosition;
2535 y = segmentPositions.constLast();
2537 x = segmentPositions.constLast();
2538 y = batchSavedPosition;
2541 if (info.flow == QListView::LeftToRight) {
2542 x = batchSavedPosition;
2543 y = info.bounds.top() + info.spacing;
2545 x = info.bounds.left() + info.spacing;
2546 y = batchSavedPosition;
2549 return QPoint(x, y);
2553
2554
2555void QListModeViewBase::doStaticLayout(
const QListViewLayoutInfo &info)
2557 const bool useItemSize = !info.grid.isValid();
2558 const QPoint topLeft = initStaticLayout(info);
2559 QStyleOptionViewItem option;
2560 initViewItemOption(&option);
2561 option.rect = info.bounds;
2562 option.rect.adjust(info.spacing, info.spacing, -info.spacing, -info.spacing);
2570 int segStartPosition;
2572 int deltaFlowPosition;
2573 int deltaSegPosition;
2578 if (info.flow == QListView::LeftToRight) {
2579 segStartPosition = info.bounds.left();
2580 segEndPosition = info.bounds.width();
2581 flowPosition = topLeft.x();
2582 segPosition = topLeft.y();
2583 deltaFlowPosition = info.grid.width();
2584 deltaSegPosition = useItemSize ? batchSavedDeltaSeg : info.grid.height();
2585 deltaSegHint = info.grid.height();
2587 segStartPosition = info.bounds.top();
2588 segEndPosition = info.bounds.height();
2589 flowPosition = topLeft.y();
2590 segPosition = topLeft.x();
2591 deltaFlowPosition = info.grid.height();
2592 deltaSegPosition = useItemSize ? batchSavedDeltaSeg : info.grid.width();
2593 deltaSegHint = info.grid.width();
2596 for (
int row = info.first; row <= info.last; ++row) {
2597 if (isHidden(row)) {
2598 flowPositions.append(flowPosition);
2602 QSize hint = itemSize(option, modelIndex(row));
2603 if (info.flow == QListView::LeftToRight) {
2604 deltaFlowPosition = hint.width() + info.spacing;
2605 deltaSegHint = hint.height() + info.spacing;
2607 deltaFlowPosition = hint.height() + info.spacing;
2608 deltaSegHint = hint.width() + info.spacing;
2612 if (info.wrap && (flowPosition + deltaFlowPosition >= segEndPosition)) {
2613 segmentExtents.append(flowPosition);
2614 flowPosition = info.spacing + segStartPosition;
2615 segPosition += info.spacing + deltaSegPosition;
2616 segmentPositions.append(segPosition);
2617 segmentStartRows.append(row);
2618 deltaSegPosition = 0;
2621 scrollValueMap.append(flowPositions.size());
2622 flowPositions.append(flowPosition);
2624 deltaSegPosition = qMax(deltaSegHint, deltaSegPosition);
2625 flowPosition += info.spacing + deltaFlowPosition;
2629 batchSavedPosition = flowPosition;
2630 batchSavedDeltaSeg = deltaSegPosition;
2631 batchStartRow = info.last + 1;
2632 if (info.last == info.max)
2633 flowPosition -= info.spacing;
2635 QRect rect = info.bounds;
2636 if (info.flow == QListView::LeftToRight) {
2637 rect.setRight(segmentPositions.size() == 1 ? flowPosition : info.bounds.right());
2638 rect.setBottom(segPosition + deltaSegPosition);
2640 rect.setRight(segPosition + deltaSegPosition);
2641 rect.setBottom(segmentPositions.size() == 1 ? flowPosition : info.bounds.bottom());
2643 contentsSize = QSize(rect.right(), rect.bottom());
2645 if (info.last == info.max) {
2646 segmentExtents.append(flowPosition);
2647 scrollValueMap.append(flowPositions.size());
2648 flowPositions.append(flowPosition);
2649 segmentPositions.append(info.wrap ? segPosition + deltaSegPosition : INT_MAX);
2652 QRect changedRect(topLeft, rect.bottomRight());
2653 if (clipRect().intersects(changedRect))
2654 viewport()->update();
2658
2659
2660
2661
2662QList<QModelIndex> QListModeViewBase::intersectingSet(
const QRect &area)
const
2664 QList<QModelIndex> ret;
2665 int segStartPosition;
2667 int flowStartPosition;
2668 int flowEndPosition;
2669 if (flow() == QListView::LeftToRight) {
2670 segStartPosition = area.top();
2671 segEndPosition = area.bottom();
2672 flowStartPosition = area.left();
2673 flowEndPosition = area.right();
2675 segStartPosition = area.left();
2676 segEndPosition = area.right();
2677 flowStartPosition = area.top();
2678 flowEndPosition = area.bottom();
2680 if (segmentPositions.size() < 2 || flowPositions.isEmpty())
2683 const int segLast = segmentPositions.size() - 2;
2684 int seg = qBinarySearch<
int>(segmentPositions, segStartPosition, 0, segLast + 1);
2685 for (; seg <= segLast && segmentPositions.at(seg) <= segEndPosition; ++seg) {
2686 int first = segmentStartRows.at(seg);
2687 int last = (seg < segLast ? segmentStartRows.at(seg + 1) : batchStartRow) - 1;
2688 if (segmentExtents.at(seg) < flowStartPosition)
2690 int row = qBinarySearch<
int>(flowPositions, flowStartPosition, first, last);
2691 for (; row <= last && flowPositions.at(row) <= flowEndPosition; ++row) {
2694 QModelIndex index = modelIndex(row);
2695 if (index.isValid()) {
2696 if (flow() == QListView::LeftToRight || dd->itemAlignment == Qt::Alignment()) {
2699 const auto viewItem = indexToListViewItem(index);
2700 const int iw = viewItem.width();
2701 const int startPos = qMax(segStartPosition, segmentPositions.at(seg));
2702 const int endPos = qMin(segmentPositions.at(seg + 1), segEndPosition);
2703 if (endPos >= viewItem.x && startPos < viewItem.x + iw)
2709 qWarning(
"intersectingSet: row %d was invalid", row);
2716void QListModeViewBase::dataChanged(
const QModelIndex &,
const QModelIndex &)
2718 dd->doDelayedItemsLayout();
2722QRect QListModeViewBase::mapToViewport(
const QRect &rect)
const
2728 QRect result = rect;
2729 if (flow() == QListView::TopToBottom) {
2730 result.setLeft(spacing());
2731 result.setWidth(qMax(rect.width(), qMax(contentsSize.width(), viewport()->width()) - 2 * spacing()));
2733 result.setTop(spacing());
2734 result.setHeight(qMax(rect.height(), qMax(contentsSize.height(), viewport()->height()) - 2 * spacing()));
2739int QListModeViewBase::perItemScrollingPageSteps(
int length,
int bounds,
bool wrap)
const
2741 QList<
int> positions;
2743 positions = segmentPositions;
2744 else if (!flowPositions.isEmpty()) {
2745 positions.reserve(scrollValueMap.size());
2746 for (
int itemShown : scrollValueMap)
2747 positions.append(flowPositions.at(itemShown));
2749 if (positions.isEmpty() || bounds <= length)
2750 return positions.size();
2751 if (uniformItemSizes()) {
2752 for (
int i = 1; i < positions.size(); ++i)
2753 if (positions.at(i) > 0)
2754 return length / positions.at(i);
2758 int steps = positions.size() - 1;
2759 int max = qMax(length, bounds);
2760 int min = qMin(length, bounds);
2761 int pos = min - (max - positions.constLast());
2763 while (pos >= 0 && steps > 0) {
2764 pos -= (positions.at(steps) - positions.at(steps - 1));
2771 return qMax(pageSteps, 1);
2774int QListModeViewBase::perItemScrollToValue(
int index,
int scrollValue,
int viewportSize,
2775 QAbstractItemView::ScrollHint hint,
2776 Qt::Orientation orientation,
bool wrap,
int itemExtent)
const
2781 itemExtent += spacing();
2782 QList<
int> hiddenRows = dd->hiddenRowIds();
2783 std::sort(hiddenRows.begin(), hiddenRows.end());
2784 int hiddenRowsBefore = 0;
2785 for (
int i = 0; i < hiddenRows.size() - 1; ++i)
2786 if (hiddenRows.at(i) > index + hiddenRowsBefore)
2791 int topIndex = index;
2792 const int bottomIndex = topIndex;
2793 const int bottomCoordinate = flowPositions.at(index + hiddenRowsBefore);
2794 while (topIndex > 0 &&
2795 (bottomCoordinate - flowPositions.at(topIndex + hiddenRowsBefore - 1) + itemExtent) <= (viewportSize)) {
2798 while (hiddenRowsBefore > 0 && hiddenRows.at(hiddenRowsBefore - 1) >= topIndex + hiddenRowsBefore - 1)
2802 const int itemCount = bottomIndex - topIndex + 1;
2804 case QAbstractItemView::PositionAtTop:
2806 case QAbstractItemView::PositionAtBottom:
2807 return index - itemCount + 1;
2808 case QAbstractItemView::PositionAtCenter:
2809 return index - (itemCount / 2);
2814 Qt::Orientation flowOrientation = (flow() == QListView::LeftToRight
2815 ? Qt::Horizontal : Qt::Vertical);
2816 if (flowOrientation == orientation) {
2818 return flowPositions.at(index + hiddenRowsBefore);
2819 }
else if (!segmentStartRows.isEmpty()) {
2820 int segment = qBinarySearch<
int>(segmentStartRows, index, 0, segmentStartRows.size() - 1);
2821 int leftSegment = segment;
2822 const int rightSegment = leftSegment;
2823 const int bottomCoordinate = segmentPositions.at(segment);
2825 while (leftSegment > scrollValue &&
2826 (bottomCoordinate - segmentPositions.at(leftSegment-1) + itemExtent) <= (viewportSize)) {
2830 const int segmentCount = rightSegment - leftSegment + 1;
2832 case QAbstractItemView::PositionAtTop:
2834 case QAbstractItemView::PositionAtBottom:
2835 return segment - segmentCount + 1;
2836 case QAbstractItemView::PositionAtCenter:
2837 return segment - (segmentCount / 2);
2846void QListModeViewBase::clear()
2848 flowPositions.clear();
2849 segmentPositions.clear();
2850 segmentStartRows.clear();
2851 segmentExtents.clear();
2852 batchSavedPosition = 0;
2854 batchSavedDeltaSeg = 0;
2858
2859
2861void QIconModeViewBase::setPositionForIndex(
const QPoint &position,
const QModelIndex &index)
2863 if (index.row() >= items.size())
2865 const QSize oldContents = contentsSize;
2867 moveItem(index.row(), position);
2870 if (contentsSize != oldContents)
2871 dd->viewUpdateGeometries();
2874void QIconModeViewBase::appendHiddenRow(
int row)
2876 if (row >= 0 && row < items.size())
2877 tree.removeLeaf(items.at(row).rect(), row);
2878 QCommonListViewBase::appendHiddenRow(row);
2881void QIconModeViewBase::removeHiddenRow(
int row)
2883 QCommonListViewBase::removeHiddenRow(row);
2884 if (row >= 0 && row < items.size())
2885 tree.insertLeaf(items.at(row).rect(), row);
2888#if QT_CONFIG(draganddrop)
2889bool QIconModeViewBase::filterStartDrag(Qt::DropActions supportedActions)
2894 QModelIndexList indexes = dd->selectionModel->selectedIndexes();
2895 if (indexes.size() > 0 ) {
2896 if (viewport()->acceptDrops()) {
2897 QModelIndexList::ConstIterator it = indexes.constBegin();
2898 for (; it != indexes.constEnd(); ++it)
2899 if (dd->model->flags(*it) & Qt::ItemIsDragEnabled
2900 && (*it).column() == dd->column)
2901 draggedItems.push_back(*it);
2905 QPixmap pixmap = dd->renderToPixmap(indexes, &rect);
2906 rect.adjust(horizontalOffset(), verticalOffset(), 0, 0);
2907 QDrag *drag =
new QDrag(qq);
2908 drag->setMimeData(dd->model->mimeData(indexes));
2909 drag->setPixmap(pixmap);
2910 drag->setHotSpot(dd->pressedPosition - rect.topLeft());
2911 dd->dropEventMoved =
false;
2912 Qt::DropAction action = drag->exec(supportedActions, dd->defaultDropAction);
2913 draggedItems.clear();
2915 if (action == Qt::MoveAction && !dd->dropEventMoved) {
2916 if (dd->dragDropMode != QAbstractItemView::InternalMove || drag->target() == qq->viewport())
2917 dd->clearOrRemove();
2919 dd->dropEventMoved =
false;
2924bool QIconModeViewBase::filterDropEvent(QDropEvent *e)
2926 if (e->source() != qq)
2929 const QSize contents = contentsSize;
2930 QPoint offset(horizontalOffset(), verticalOffset());
2931 QPoint end = e->position().toPoint() + offset;
2932 if (qq->acceptDrops()) {
2933 const Qt::ItemFlags dropableFlags = Qt::ItemIsDropEnabled|Qt::ItemIsEnabled;
2934 const QList<QModelIndex> &dropIndices = intersectingSet(QRect(end, QSize(1, 1)));
2935 for (
const QModelIndex &index : dropIndices)
2936 if ((index.flags() & dropableFlags) == dropableFlags)
2939 QPoint start = dd->pressedPosition;
2940 QPoint delta = (dd->movement == QListView::Snap ? snapToGrid(end) - snapToGrid(start) : end - start);
2941 const QList<QModelIndex> indexes = dd->selectionModel->selectedIndexes();
2942 for (
const auto &index : indexes) {
2943 QRect rect = dd->rectForIndex(index);
2944 viewport()->update(dd->mapToViewport(rect,
false));
2945 QPoint dest = rect.topLeft() + delta;
2946 if (qq->isRightToLeft())
2947 dest.setX(dd->flipX(dest.x()) - rect.width());
2948 moveItem(index.row(), dest);
2951 dd->stopAutoScroll();
2952 draggedItems.clear();
2953 dd->emitIndexesMoved(indexes);
2955 dd->dropEventMoved =
true;
2958 if (contentsSize != contents) {
2959 if ((contentsSize.width() <= contents.width()
2960 || contentsSize.height() <= contents.height())) {
2961 updateContentsSize();
2963 dd->viewUpdateGeometries();
2968bool QIconModeViewBase::filterDragLeaveEvent(QDragLeaveEvent *e)
2970 viewport()->update(draggedItemsRect());
2971 draggedItemsPos = QPoint(-1, -1);
2972 return QCommonListViewBase::filterDragLeaveEvent(e);
2975bool QIconModeViewBase::filterDragMoveEvent(QDragMoveEvent *e)
2977 const bool wasAccepted = e->isAccepted();
2982 if (e->source() != qq || !dd->canDrop(e)) {
2984 e->setAccepted(wasAccepted);
2989 QRect itemsRect =
this->itemsRect(draggedItems);
2990 viewport()->update(itemsRect.translated(draggedItemsDelta()));
2992 draggedItemsPos = e->position().toPoint();
2994 viewport()->update(itemsRect.translated(draggedItemsDelta()));
2997 if (movement() == QListView::Snap) {
2998 QRect rect(snapToGrid(e->position().toPoint() + offset()), gridSize());
2999 const QList<QModelIndex> intersectVector = intersectingSet(rect);
3000 index = intersectVector.size() > 0 ? intersectVector.last() : QModelIndex();
3002 index = qq->indexAt(e->position().toPoint());
3005 if (draggedItems.contains(index))
3007 else if (dd->model->flags(index) & Qt::ItemIsDropEnabled)
3009 else if (!index.isValid())
3013 if (dd->shouldAutoScroll(e->position().toPoint()))
3014 dd->startAutoScroll();
3019void QIconModeViewBase::setRowCount(
int rowCount)
3021 tree.create(qMax(rowCount - hiddenCount(), 0));
3024void QIconModeViewBase::scrollContentsBy(
int dx,
int dy,
bool scrollElasticBand)
3026 if (scrollElasticBand)
3027 dd->scrollElasticBandBy(isRightToLeft() ? -dx : dx, dy);
3029 QCommonListViewBase::scrollContentsBy(dx, dy, scrollElasticBand);
3030 if (!draggedItems.isEmpty())
3031 viewport()->update(draggedItemsRect().translated(dx, dy));
3034void QIconModeViewBase::dataChanged(
const QModelIndex &topLeft,
const QModelIndex &bottomRight)
3036 if (column() >= topLeft.column() && column() <= bottomRight.column()) {
3037 QStyleOptionViewItem option;
3038 initViewItemOption(&option);
3039 const int bottom = qMin(items.size(), bottomRight.row() + 1);
3040 const bool useItemSize = !dd->grid.isValid();
3041 for (
int row = topLeft.row(); row < bottom; ++row)
3043 QSize s = itemSize(option, modelIndex(row));
3046 s.setWidth(qMin(dd->grid.width(), s.width()));
3047 s.setHeight(qMin(dd->grid.height(), s.height()));
3049 items[row].resize(s);
3054bool QIconModeViewBase::doBatchedItemLayout(
const QListViewLayoutInfo &info,
int max)
3056 if (info.last >= items.size()) {
3058 QStyleOptionViewItem option;
3059 initViewItemOption(&option);
3060 for (
int row = items.size(); row <= info.last; ++row) {
3061 QSize size = itemSize(option, modelIndex(row));
3062 QListViewItem item(QRect(0, 0, size.width(), size.height()), row);
3065 doDynamicLayout(info);
3067 return (batchStartRow > max);
3070QListViewItem QIconModeViewBase::indexToListViewItem(
const QModelIndex &index)
const
3072 if (index.isValid() && index.row() < items.size())
3073 return items.at(index.row());
3074 return QListViewItem();
3077void QIconModeViewBase::initBspTree(
const QSize &contents)
3080 int leafCount = tree.leafCount();
3081 for (
int l = 0; l < leafCount; ++l)
3082 tree.leaf(l).clear();
3084 QBspTree::Node::Type type = QBspTree::Node::Both;
3086 if (contents.height() / contents.width() >= 3)
3087 type = QBspTree::Node::HorizontalPlane;
3088 else if (contents.width() / contents.height() >= 3)
3089 type = QBspTree::Node::VerticalPlane;
3091 tree.init(QRect(0, 0, contents.width(), contents.height()), type);
3094QPoint QIconModeViewBase::initDynamicLayout(
const QListViewLayoutInfo &info)
3097 if (info.first == 0) {
3098 x = info.bounds.x() + info.spacing;
3099 y = info.bounds.y() + info.spacing;
3100 items.reserve(rowCount() - hiddenCount());
3102 int idx = info.first - 1;
3103 while (idx > 0 && !items.at(idx).isValid())
3105 const QListViewItem &item = items.at(idx);
3108 if (info.flow == QListView::LeftToRight)
3109 x += (info.grid.isValid() ? info.grid.width() : item.w) + info.spacing;
3111 y += (info.grid.isValid() ? info.grid.height() : item.h) + info.spacing;
3113 return QPoint(x, y);
3117
3118
3119void QIconModeViewBase::doDynamicLayout(
const QListViewLayoutInfo &info)
3121 const bool useItemSize = !info.grid.isValid();
3122 const QPoint topLeft = initDynamicLayout(info);
3124 int segStartPosition;
3126 int deltaFlowPosition;
3127 int deltaSegPosition;
3132 if (info.flow == QListView::LeftToRight) {
3133 segStartPosition = info.bounds.left() + info.spacing;
3134 segEndPosition = info.bounds.right();
3135 deltaFlowPosition = info.grid.width();
3136 deltaSegPosition = (useItemSize ? batchSavedDeltaSeg : info.grid.height());
3137 deltaSegHint = info.grid.height();
3138 flowPosition = topLeft.x();
3139 segPosition = topLeft.y();
3141 segStartPosition = info.bounds.top() + info.spacing;
3142 segEndPosition = info.bounds.bottom();
3143 deltaFlowPosition = info.grid.height();
3144 deltaSegPosition = (useItemSize ? batchSavedDeltaSeg : info.grid.width());
3145 deltaSegHint = info.grid.width();
3146 flowPosition = topLeft.y();
3147 segPosition = topLeft.x();
3150 if (moved.size() != items.size())
3151 moved.resize(items.size());
3153 QRect rect(QPoint(), topLeft);
3154 QListViewItem *item =
nullptr;
3155 Q_ASSERT(info.first <= info.last);
3156 for (
int row = info.first; row <= info.last; ++row) {
3158 if (isHidden(row)) {
3163 if (info.flow == QListView::LeftToRight)
3164 deltaFlowPosition = item->w + info.spacing;
3166 deltaFlowPosition = item->h + info.spacing;
3168 item->w = qMin<
int>(info.grid.width(), item->w);
3169 item->h = qMin<
int>(info.grid.height(), item->h);
3174 && flowPosition + deltaFlowPosition > segEndPosition
3175 && flowPosition > segStartPosition) {
3176 flowPosition = segStartPosition;
3177 segPosition += deltaSegPosition;
3179 deltaSegPosition = 0;
3184 if (info.flow == QListView::LeftToRight)
3185 deltaSegHint = item->h + info.spacing;
3187 deltaSegHint = item->w + info.spacing;
3188 deltaSegPosition = qMax(deltaSegPosition, deltaSegHint);
3194 if (!moved.testBit(row)) {
3195 if (info.flow == QListView::LeftToRight) {
3197 item->x = flowPosition;
3198 item->y = segPosition;
3200 item->x = flowPosition + ((deltaFlowPosition - item->w) / 2);
3201 item->y = segPosition;
3205 item->y = flowPosition;
3206 item->x = segPosition;
3208 item->y = flowPosition + ((deltaFlowPosition - item->h) / 2);
3209 item->x = segPosition;
3216 rect |= item->rect();
3217 else if (info.flow == QListView::LeftToRight)
3218 rect |= QRect(flowPosition, segPosition, deltaFlowPosition, deltaSegPosition);
3220 rect |= QRect(segPosition, flowPosition, deltaSegPosition, deltaFlowPosition);
3223 flowPosition += deltaFlowPosition;
3227 batchSavedDeltaSeg = deltaSegPosition;
3228 batchStartRow = info.last + 1;
3229 bool done = (info.last >= rowCount() - 1);
3231 if (done || !info.bounds.contains(item->rect())) {
3232 contentsSize = rect.size();
3233 if (info.flow == QListView::LeftToRight)
3234 contentsSize.rheight() += info.spacing;
3236 contentsSize.rwidth() += info.spacing;
3238 if (rect.size().isEmpty())
3241 int insertFrom = info.first;
3242 if (done || info.first == 0) {
3243 initBspTree(rect.size());
3247 for (
int row = insertFrom; row <= info.last; ++row)
3248 tree.insertLeaf(items.at(row).rect(), row);
3250 QRect changedRect(topLeft, rect.bottomRight());
3251 if (clipRect().intersects(changedRect))
3252 viewport()->update();
3255QList<QModelIndex> QIconModeViewBase::intersectingSet(
const QRect &area)
const
3257 QIconModeViewBase *that =
const_cast<QIconModeViewBase*>(
this);
3258 QBspTree::Data data(
static_cast<
void*>(that));
3259 QList<QModelIndex> res;
3260 that->interSectingVector = &res;
3261 that->tree.climbTree(area, &QIconModeViewBase::addLeaf, data);
3262 that->interSectingVector =
nullptr;
3266QRect QIconModeViewBase::itemsRect(
const QList<QModelIndex> &indexes)
const
3269 for (
const auto &index : indexes)
3270 rect |= viewItemRect(indexToListViewItem(index));
3274int QIconModeViewBase::itemIndex(
const QListViewItem &item)
const
3276 if (!item.isValid())
3278 int i = item.indexHint;
3279 if (i < items.size()) {
3280 if (items.at(i) == item)
3283 i = items.size() - 1;
3287 int c = items.size();
3293 if (items.at(i) == item) {
3294 items.at(i).indexHint = i;
3300 if (items.at(j) == item) {
3301 items.at(j).indexHint = j;
3310void QIconModeViewBase::addLeaf(QList<
int> &leaf,
const QRect &area, uint visited,
3311 QBspTree::Data data)
3314 QIconModeViewBase *_this =
static_cast<QIconModeViewBase *>(data.ptr);
3315 for (
int i = 0; i < leaf.size(); ++i) {
3316 int idx = leaf.at(i);
3317 if (idx < 0 || idx >= _this->items.size())
3319 vi = &_this->items[idx];
3321 if (vi->isValid() && vi->rect().intersects(area) && vi->visited != visited) {
3322 QModelIndex index = _this->dd->listViewItemToIndex(*vi);
3323 Q_ASSERT(index.isValid());
3324 _this->interSectingVector->append(index);
3325 vi->visited = visited;
3330void QIconModeViewBase::moveItem(
int index,
const QPoint &dest)
3333 QListViewItem *item = &items[index];
3334 QRect rect = item->rect();
3337 tree.removeLeaf(rect, index);
3339 tree.insertLeaf(QRect(dest, rect.size()), index);
3342 contentsSize = (QRect(QPoint(0, 0), contentsSize)|QRect(dest, rect.size())).size();
3345 if (moved.size() != items.size())
3346 moved.resize(items.size());
3347 moved.setBit(index,
true);
3350QPoint QIconModeViewBase::snapToGrid(
const QPoint &pos)
const
3352 int x = pos.x() - (pos.x() % gridSize().width());
3353 int y = pos.y() - (pos.y() % gridSize().height());
3354 return QPoint(x, y);
3357QPoint QIconModeViewBase::draggedItemsDelta()
const
3359 if (movement() == QListView::Snap) {
3360 QPoint snapdelta = QPoint((offset().x() % gridSize().width()),
3361 (offset().y() % gridSize().height()));
3362 return snapToGrid(draggedItemsPos + snapdelta) - snapToGrid(pressedPosition()) - snapdelta;
3364 return draggedItemsPos - pressedPosition();
3367QRect QIconModeViewBase::draggedItemsRect()
const
3369 QRect rect = itemsRect(draggedItems);
3370 rect.translate(draggedItemsDelta());
3374void QListViewPrivate::scrollElasticBandBy(
int dx,
int dy)
3377 elasticBand.moveRight(elasticBand.right() + dx);
3379 elasticBand.moveLeft(elasticBand.left() - dx);
3381 elasticBand.moveBottom(elasticBand.bottom() + dy);
3383 elasticBand.moveTop(elasticBand.top() - dy);
3386void QIconModeViewBase::clear()
3392 batchSavedDeltaSeg = 0;
3395void QIconModeViewBase::updateContentsSize()
3398 for (
int i = 0; i < items.size(); ++i)
3399 bounding |= items.at(i).rect();
3400 contentsSize = bounding.size();
3404
3405
3406void QListView::currentChanged(
const QModelIndex ¤t,
const QModelIndex &previous)
3408 Q_D(
const QListView);
3409 QAbstractItemView::currentChanged(current, previous);
3410#if QT_CONFIG(accessibility)
3411 if (QAccessible::isActive()) {
3412 if (current.isValid() && hasFocus()) {
3413 int entry = d->accessibleChildIndex(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 Q_D(
const QListView);
3430 if (QAccessible::isActive()) {
3432 QModelIndex sel = selected.indexes().value(0);
3433 if (sel.isValid()) {
3434 int entry = d->accessibleChildIndex(sel);
3435 QAccessibleEvent event(
this, QAccessible::SelectionAdd);
3436 event.setChild(entry);
3437 QAccessible::updateAccessibility(&event);
3439 QModelIndex desel = deselected.indexes().value(0);
3440 if (desel.isValid()) {
3441 int entry = d->accessibleChildIndex(desel);
3442 QAccessibleEvent event(
this, QAccessible::SelectionRemove);
3443 event.setChild(entry);
3444 QAccessible::updateAccessibility(&event);
3448 QAbstractItemView::selectionChanged(selected, deselected);
3451int QListView::visualIndex(
const QModelIndex &index)
const
3453 Q_D(
const QListView);
3454 d->executePostedLayout();
3455 QListViewItem itm = d->indexToListViewItem(index);
3456 int visualIndex = d->commonListView->itemIndex(itm);
3457 for (
const auto &idx : std::as_const(d->hiddenRows)) {
3458 if (idx.row() <= index.row())
3466
3467
3468
3469QSize QListView::viewportSizeHint()
const
3471 Q_D(
const QListView);
3474 return QAbstractItemView::viewportSizeHint();
3475 const int rc = d->model->rowCount();
3476 if (rc == 0 || isWrapping())
3477 return QAbstractItemView::viewportSizeHint();
3479 QStyleOptionViewItem option;
3480 initViewItemOption(&option);
3482 if (uniformItemSizes()) {
3483 QSize sz = d->cachedItemSize;
3484 if (!sz.isValid()) {
3485 QModelIndex idx = d->model->index(0, d->column, d->root);
3486 sz = d->itemSize(option, idx);
3488 sz.setHeight(rc * sz.height());
3495 int maximumRows = 1000;
3496 const QVariant userOverrideValue = property(
"_q_resizeContentPrecision");
3497 if (userOverrideValue.isValid() && userOverrideValue.toInt() > 0) {
3498 maximumRows = userOverrideValue.toInt();
3500 const int rowCount = qMin(rc, maximumRows);
3505 for (
int row = 0; row < rowCount; ++row) {
3506 QModelIndex idx = d->model->index(row, d->column, d->root);
3507 QSize itemSize = d->itemSize(option, idx);
3508 h += itemSize.height();
3509 w = qMax(w, itemSize.width());
3516#include "moc_qlistview.cpp"