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 Q_ASSERT(index.isValid());
1967 return q->visualIndex(index);
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 Q_D(
const QListView);
3410 QAbstractItemView::currentChanged(current, previous);
3411#if QT_CONFIG(accessibility)
3412 if (QAccessible::isActive()) {
3413 if (current.isValid() && hasFocus()) {
3414 int entry = d->accessibleChildIndex(current);
3415 QAccessibleEvent event(
this, QAccessible::Focus);
3416 event.setChild(entry);
3417 QAccessible::updateAccessibility(&event);
3424
3425
3426void QListView::selectionChanged(
const QItemSelection &selected,
3427 const QItemSelection &deselected)
3429#if QT_CONFIG(accessibility)
3430 Q_D(
const QListView);
3431 if (QAccessible::isActive()) {
3433 QModelIndex sel = selected.indexes().value(0);
3434 if (sel.isValid()) {
3435 int entry = d->accessibleChildIndex(sel);
3436 QAccessibleEvent event(
this, QAccessible::SelectionAdd);
3437 event.setChild(entry);
3438 QAccessible::updateAccessibility(&event);
3440 QModelIndex desel = deselected.indexes().value(0);
3441 if (desel.isValid()) {
3442 int entry = d->accessibleChildIndex(desel);
3443 QAccessibleEvent event(
this, QAccessible::SelectionRemove);
3444 event.setChild(entry);
3445 QAccessible::updateAccessibility(&event);
3449 QAbstractItemView::selectionChanged(selected, deselected);
3452int QListView::visualIndex(
const QModelIndex &index)
const
3454 Q_D(
const QListView);
3455 d->executePostedLayout();
3456 QListViewItem itm = d->indexToListViewItem(index);
3457 int visualIndex = d->commonListView->itemIndex(itm);
3458 for (
const auto &idx : std::as_const(d->hiddenRows)) {
3459 if (idx.row() <= index.row())
3467
3468
3469
3470QSize QListView::viewportSizeHint()
const
3472 Q_D(
const QListView);
3475 return QAbstractItemView::viewportSizeHint();
3476 const int rc = d->model->rowCount();
3477 if (rc == 0 || isWrapping())
3478 return QAbstractItemView::viewportSizeHint();
3480 QStyleOptionViewItem option;
3481 initViewItemOption(&option);
3483 if (uniformItemSizes()) {
3484 QSize sz = d->cachedItemSize;
3485 if (!sz.isValid()) {
3486 QModelIndex idx = d->model->index(0, d->column, d->root);
3487 sz = d->itemSize(option, idx);
3489 sz.setHeight(rc * sz.height());
3496 int maximumRows = 1000;
3497 const QVariant userOverrideValue = property(
"_q_resizeContentPrecision");
3498 if (userOverrideValue.isValid() && userOverrideValue.toInt() > 0) {
3499 maximumRows = userOverrideValue.toInt();
3501 const int rowCount = qMin(rc, maximumRows);
3506 for (
int row = 0; row < rowCount; ++row) {
3507 QModelIndex idx = d->model->index(row, d->column, d->root);
3508 QSize itemSize = d->itemSize(option, idx);
3509 h += itemSize.height();
3510 w = qMax(w, itemSize.width());
3517#include "moc_qlistview.cpp"