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)
1231 intersectVector = d->intersectingSet(rect);
1232 d->removeCurrentAndDisabled(&intersectVector, current);
1234 return d->closestIndex(initialRect, intersectVector);
1235 case MovePageDown: {
1236 if (rect.height() >= d->viewport->height())
1237 return moveCursor(QAbstractItemView::MoveDown, modifiers);
1239 rect.moveTop(rect.top() + d->viewport->height() - 1);
1240 if (rect.bottom() > contents.height() - rect.height()) {
1241 rect.setTop(contents.height() - 1);
1242 rect.setBottom(contents.height());
1244 QModelIndex index = current;
1246 while (intersectVector.isEmpty()
1247 || rectForIndex(index).bottom() >= (d->viewport->rect().height() + rectForIndex(current).top())
1248 || rect.bottom() > contents.height()) {
1249 rect.translate(0, -1);
1250 if (rect.top() >= contents.height()) {
1253 intersectVector = d->intersectingSet(rect);
1254 index = d->closestIndex(initialRect, intersectVector);
1260 while (intersectVector.isEmpty()) {
1261 rect.translate(0, rect.height());
1262 if (rect.top() >= contents.height())
1264 if (rect.bottom() > contents.height())
1265 rect.setBottom(contents.height());
1266 intersectVector = d->intersectingSet(rect);
1267 d->removeCurrentAndDisabled(&intersectVector, current);
1269 return d->closestIndex(initialRect, intersectVector);
1271 return d->model->index(0, d->column, d->root);
1273 return d->model->index(d->batchStartRow() - 1, d->column, d->root);}
1279
1280
1281
1282
1283
1284QRect QListView::rectForIndex(
const QModelIndex &index)
const
1286 return d_func()->rectForIndex(index);
1290
1291
1292
1293
1294
1295void QListView::setPositionForIndex(
const QPoint &position,
const QModelIndex &index)
1298 if (d->movement == Static
1299 || !d->isIndexValid(index)
1300 || index.parent() != d->root
1301 || index.column() != d->column)
1304 d->executePostedLayout();
1305 d->commonListView->setPositionForIndex(position, index);
1309
1310
1311void QListView::setSelection(
const QRect &rect, QItemSelectionModel::SelectionFlags command)
1314 if (!d->selectionModel)
1318 int w = qMax(d->contentsSize().width(), d->viewport->width());
1319 int h = qMax(d->contentsSize().height(), d->viewport->height());
1320 if (d->wrap && !QRect(0, 0, w, h).intersects(rect))
1323 QItemSelection selection;
1325 if (rect.width() == 1 && rect.height() == 1) {
1326 const QList<QModelIndex> intersectVector =
1327 d->intersectingSet(rect.translated(horizontalOffset(), verticalOffset()));
1329 if (!intersectVector.isEmpty())
1330 tl = intersectVector.last();
1331 if (tl.isValid() && d->isIndexEnabled(tl))
1332 selection.select(tl, tl);
1334 if (state() == DragSelectingState) {
1335 selection = d->selection(rect.translated(horizontalOffset(), verticalOffset()));
1339 const QRect topLeft(rect.left() + horizontalOffset(), rect.top() + verticalOffset(), 1, 1);
1340 QList<QModelIndex> intersectVector = d->intersectingSet(topLeft);
1341 if (!intersectVector.isEmpty())
1342 tl = intersectVector.last();
1344 const QRect bottomRight(rect.right() + horizontalOffset(), rect.bottom() + verticalOffset(), 1, 1);
1345 intersectVector = d->intersectingSet(bottomRight);
1346 if (!intersectVector.isEmpty())
1347 br = intersectVector.last();
1350 if (tl.isValid() && br.isValid()
1351 && d->isIndexEnabled(tl)
1352 && d->isIndexEnabled(br)) {
1353 QRect first = d->cellRectForIndex(tl);
1354 QRect last = d->cellRectForIndex(br);
1356 if (d->flow == LeftToRight) {
1358 QRect &bottom = last;
1360 if (top.center().y() > bottom.center().y()) {
1366 if (top.top() != bottom.top()) {
1368 if (isRightToLeft())
1371 top.setRight(contentsSize().width());
1373 if (isRightToLeft())
1374 bottom.setRight(contentsSize().width());
1377 }
else if (top.left() > bottom.right()) {
1378 if (isRightToLeft())
1379 bottom.setLeft(top.right());
1381 bottom.setRight(top.left());
1383 if (isRightToLeft())
1384 top.setLeft(bottom.right());
1386 top.setRight(bottom.left());
1389 if (top.bottom() < bottom.top()) {
1390 if (gridSize().isValid() && !gridSize().isNull())
1391 middle.setTop(top.top() + gridSize().height());
1393 middle.setTop(top.bottom() + 1);
1394 middle.setLeft(qMin(top.left(), bottom.left()));
1395 middle.setBottom(bottom.top() - 1);
1396 middle.setRight(qMax(top.right(), bottom.right()));
1399 QRect &left = first;
1400 QRect &right = last;
1401 if (left.center().x() > right.center().x())
1404 int ch = contentsSize().height();
1405 if (left.left() != right.left()) {
1407 if (isRightToLeft())
1413 if (isRightToLeft())
1414 right.setBottom(ch);
1419 middle.setBottom(ch);
1420 if (gridSize().isValid() && !gridSize().isNull())
1421 middle.setLeft(left.left() + gridSize().width());
1423 middle.setLeft(left.right() + 1);
1424 middle.setRight(right.left() - 1);
1425 }
else if (left.bottom() < right.top()) {
1426 left.setBottom(right.top() - 1);
1428 right.setBottom(left.top() - 1);
1433 QItemSelection topSelection = d->selection(first);
1434 QItemSelection middleSelection = d->selection(middle);
1435 QItemSelection bottomSelection = d->selection(last);
1437 selection.merge(topSelection, QItemSelectionModel::Select);
1438 selection.merge(middleSelection, QItemSelectionModel::Select);
1439 selection.merge(bottomSelection, QItemSelectionModel::Select);
1444 d->selectionModel->select(selection, command);
1448
1449
1450
1451
1452
1453QRegion QListView::visualRegionForSelection(
const QItemSelection &selection)
const
1455 Q_D(
const QListView);
1458 QRegion selectionRegion;
1459 const QRect &viewportRect = d->viewport->rect();
1460 for (
const auto &elem : selection) {
1461 if (!elem.isValid())
1463 QModelIndex parent = elem.topLeft().parent();
1466 if (parent != d->root)
1468 int t = elem.topLeft().row();
1469 int b = elem.bottomRight().row();
1470 if (d->viewMode == IconMode || d->isWrapping()) {
1471 for (
int r = t; r <= b; ++r) {
1472 const QRect &rect = visualRect(d->model->index(r, c, parent));
1473 if (viewportRect.intersects(rect))
1474 selectionRegion += rect;
1477 while (t <= b && d->isHidden(t)) ++t;
1478 while (b >= t && d->isHidden(b)) --b;
1479 const QModelIndex top = d->model->index(t, c, parent);
1480 const QModelIndex bottom = d->model->index(b, c, parent);
1481 QRect rect(visualRect(top).topLeft(),
1482 visualRect(bottom).bottomRight());
1483 if (viewportRect.intersects(rect))
1484 selectionRegion += rect;
1488 return selectionRegion;
1492
1493
1494QModelIndexList QListView::selectedIndexes()
const
1496 Q_D(
const QListView);
1497 if (!d->selectionModel)
1498 return QModelIndexList();
1500 QModelIndexList viewSelected = d->selectionModel->selectedIndexes();
1501 auto ignorable = [
this, d](
const QModelIndex &index) {
1502 return index.column() != d->column || index.parent() != d->root || isIndexHidden(index);
1504 viewSelected.removeIf(ignorable);
1505 return viewSelected;
1509
1510
1511
1512
1513void QListView::doItemsLayout()
1519 QAbstractItemView::State oldState = state();
1520 setState(ExpandingState);
1521 if (d->model->columnCount(d->root) > 0) {
1522 d->resetBatchStartRow();
1523 if (layoutMode() == SinglePass) {
1524 d->doItemsLayout(d->model->rowCount(d->root));
1525 }
else if (!d->batchLayoutTimer.isActive()) {
1526 if (!d->doItemsLayout(d->batchSize))
1527 d->batchLayoutTimer.start(0,
this);
1532 QAbstractItemView::doItemsLayout();
1537
1538
1539void QListView::updateGeometries()
1542 if (geometry().isEmpty() || d->model->rowCount(d->root) <= 0 || d->model->columnCount(d->root) <= 0) {
1543 horizontalScrollBar()->setRange(0, 0);
1544 verticalScrollBar()->setRange(0, 0);
1546 QModelIndex index = d->model->index(0, d->column, d->root);
1547 QStyleOptionViewItem option;
1548 initViewItemOption(&option);
1549 QSize step = d->itemSize(option, index);
1550 d->commonListView->updateHorizontalScrollBar(step);
1551 d->commonListView->updateVerticalScrollBar(step);
1554 QAbstractItemView::updateGeometries();
1557 if (d->movement == Static && !d->isWrapping()) {
1558 d->layoutChildren();
1559 if (d->flow == TopToBottom) {
1560 if (horizontalScrollBarPolicy() == Qt::ScrollBarAlwaysOff) {
1561 d->setContentsSize(viewport()->width(), contentsSize().height());
1562 horizontalScrollBar()->setRange(0, 0);
1565 if (verticalScrollBarPolicy() == Qt::ScrollBarAlwaysOff) {
1566 d->setContentsSize(contentsSize().width(), viewport()->height());
1567 verticalScrollBar()->setRange(0, 0);
1575
1576
1577bool QListView::isIndexHidden(
const QModelIndex &index)
const
1579 Q_D(
const QListView);
1580 return (d->isHidden(index.row())
1581 && (index.parent() == d->root)
1582 && index.column() == d->column);
1586
1587
1588
1589
1590
1591
1592void QListView::setModelColumn(
int column)
1595 if (column < 0 || column >= d->model->columnCount(d->root))
1598 d->doDelayedItemsLayout();
1599#if QT_CONFIG(accessibility)
1600 if (QAccessible::isActive()) {
1601 QAccessibleTableModelChangeEvent event(
this, QAccessibleTableModelChangeEvent::ModelReset);
1602 QAccessible::updateAccessibility(&event);
1607int QListView::modelColumn()
const
1609 Q_D(
const QListView);
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623void QListView::setUniformItemSizes(
bool enable)
1626 d->uniformItemSizes = enable;
1629bool QListView::uniformItemSizes()
const
1631 Q_D(
const QListView);
1632 return d->uniformItemSizes;
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648void QListView::setWordWrap(
bool on)
1651 if (d->wrapItemText == on)
1653 d->wrapItemText = on;
1654 d->doDelayedItemsLayout();
1657bool QListView::wordWrap()
const
1659 Q_D(
const QListView);
1660 return d->wrapItemText;
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677void QListView::setSelectionRectVisible(
bool show)
1680 d->modeProperties |= uint(QListViewPrivate::SelectionRectVisible);
1681 d->setSelectionRectVisible(show);
1684bool QListView::isSelectionRectVisible()
const
1686 Q_D(
const QListView);
1687 return d->isSelectionRectVisible();
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700void QListView::setItemAlignment(Qt::Alignment alignment)
1703 if (d->itemAlignment == alignment)
1705 d->itemAlignment = alignment;
1706 if (viewMode() == ListMode && flow() == QListView::TopToBottom && isWrapping())
1707 d->doDelayedItemsLayout();
1710Qt::Alignment QListView::itemAlignment()
const
1712 Q_D(
const QListView);
1713 return d->itemAlignment;
1717
1718
1719bool QListView::event(QEvent *e)
1721 return QAbstractItemView::event(e);
1725
1726
1728QListViewPrivate::QListViewPrivate()
1729 : QAbstractItemViewPrivate(),
1730 commonListView(
nullptr),
1733 flow(QListView::TopToBottom),
1734 movement(QListView::Static),
1735 resizeMode(QListView::Fixed),
1736 layoutMode(QListView::SinglePass),
1737 viewMode(QListView::ListMode),
1740 uniformItemSizes(
false),
1742 showElasticBand(
false),
1743 itemAlignment(Qt::Alignment())
1747QListViewPrivate::~QListViewPrivate()
1749 delete commonListView;
1752void QListViewPrivate::clear()
1755 cachedItemSize = QSize();
1756 commonListView->clear();
1759void QListViewPrivate::prepareItemsLayout()
1765 layoutBounds = QRect(QPoint(), q->maximumViewportSize());
1767 int frameAroundContents = 0;
1768 if (q->style()->styleHint(QStyle::SH_ScrollView_FrameOnlyAroundContents,
nullptr, q)) {
1769 QStyleOption option;
1771 frameAroundContents = q->style()->pixelMetric(QStyle::PM_DefaultFrameWidth, &option, q) * 2;
1777 int verticalMargin = (vbarpolicy == Qt::ScrollBarAsNeeded) && (flow == QListView::LeftToRight || vbar->isVisible())
1778 && !q->style()->pixelMetric(QStyle::PM_ScrollView_ScrollBarOverlap,
nullptr, vbar)
1779 ? q->style()->pixelMetric(QStyle::PM_ScrollBarExtent,
nullptr, vbar) + frameAroundContents
1781 int horizontalMargin = hbarpolicy==Qt::ScrollBarAsNeeded
1782 ? q->style()->pixelMetric(QStyle::PM_ScrollBarExtent,
nullptr, hbar) + frameAroundContents
1785 layoutBounds.adjust(0, 0, -verticalMargin, -horizontalMargin);
1787 int rowCount = model->columnCount(root) <= 0 ? 0 : model->rowCount(root);
1788 commonListView->setRowCount(rowCount);
1792
1793
1794bool QListViewPrivate::doItemsLayout(
int delta)
1796 int max = model->rowCount(root) - 1;
1797 int first = batchStartRow();
1798 int last = qMin(first + delta - 1, max);
1802 prepareItemsLayout();
1805 if (max < 0 || last < first) {
1809 QListViewLayoutInfo info;
1810 info.bounds = layoutBounds;
1811 info.grid = gridSize();
1812 info.spacing = (info.grid.isValid() ? 0 : spacing());
1815 info.wrap = isWrapping();
1819 return commonListView->doBatchedItemLayout(info, max);
1822QListViewItem QListViewPrivate::indexToListViewItem(
const QModelIndex &index)
const
1824 if (!index.isValid() || isHidden(index.row()))
1825 return QListViewItem();
1827 return commonListView->indexToListViewItem(index);
1830QRect QListViewPrivate::mapToViewport(
const QRect &rect,
bool extend)
const
1832 Q_Q(
const QListView);
1833 if (!rect.isValid())
1836 QRect result = extend ? commonListView->mapToViewport(rect) : rect;
1837 int dx = -q->horizontalOffset();
1838 int dy = -q->verticalOffset();
1839 return result.adjusted(dx, dy, dx, dy);
1842QModelIndex QListViewPrivate::closestIndex(
const QRect &target,
1843 const QList<QModelIndex> &candidates)
const
1846 int shortest = INT_MAX;
1847 QModelIndex closest;
1848 QList<QModelIndex>::const_iterator it = candidates.begin();
1850 for (; it != candidates.end(); ++it) {
1851 if (!(*it).isValid())
1854 const QRect indexRect = indexToListViewItem(*it).rect();
1859 if ((target.center().x() >= indexRect.x() && target.center().x() < indexRect.right())
1860 || (indexRect.center().x() >= target.x() && indexRect.center().x() < target.right())) {
1862 distance = qAbs(indexRect.center().y() - target.center().y());
1863 }
else if ((target.center().y() >= indexRect.y() && target.center().y() < indexRect.bottom())
1864 || (indexRect.center().y() >= target.y() && indexRect.center().y() < target.bottom())) {
1866 distance = qAbs(indexRect.center().x() - target.center().x());
1868 distance = (indexRect.center() - target.center()).manhattanLength();
1870 if (distance < shortest) {
1871 shortest = distance;
1878QSize QListViewPrivate::itemSize(
const QStyleOptionViewItem &option,
const QModelIndex &index)
const
1880 Q_Q(
const QListView);
1881 if (!uniformItemSizes) {
1882 const QAbstractItemDelegate *delegate = q->itemDelegateForIndex(index);
1883 return delegate ? delegate->sizeHint(option, index) : QSize();
1885 if (!cachedItemSize.isValid()) {
1886 int row = model->rowCount(root) - 1;
1887 QModelIndex sample = model->index(row, column, root);
1888 const QAbstractItemDelegate *delegate = q->itemDelegateForIndex(sample);
1889 cachedItemSize = delegate ? delegate->sizeHint(option, sample) : QSize();
1891 return cachedItemSize;
1894QItemSelection QListViewPrivate::selection(
const QRect &rect)
const
1896 QItemSelection selection;
1898 const QList<QModelIndex> intersectVector = intersectingSet(rect);
1899 QList<QModelIndex>::const_iterator it = intersectVector.begin();
1900 for (; it != intersectVector.end(); ++it) {
1901 if (!tl.isValid() && !br.isValid()) {
1903 }
else if ((*it).row() == (tl.row() - 1)) {
1905 }
else if ((*it).row() == (br.row() + 1)) {
1908 selection.select(tl, br);
1913 if (tl.isValid() && br.isValid())
1914 selection.select(tl, br);
1915 else if (tl.isValid())
1916 selection.select(tl, tl);
1917 else if (br.isValid())
1918 selection.select(br, br);
1923#if QT_CONFIG(draganddrop)
1924QAbstractItemView::DropIndicatorPosition QListViewPrivate::position(
const QPoint &pos,
const QRect &rect,
const QModelIndex &idx)
const
1926 if (viewMode == QListView::ListMode && flow == QListView::LeftToRight)
1927 return static_cast<QListModeViewBase *>(commonListView)->position(pos, rect, idx);
1929 return QAbstractItemViewPrivate::position(pos, rect, idx);
1932bool QListViewPrivate::dropOn(QDropEvent *event,
int *dropRow,
int *dropCol, QModelIndex *dropIndex)
1934 if (viewMode == QListView::ListMode && flow == QListView::LeftToRight)
1935 return static_cast<QListModeViewBase *>(commonListView)->dropOn(event, dropRow, dropCol, dropIndex);
1937 return QAbstractItemViewPrivate::dropOn(event, dropRow, dropCol, dropIndex);
1941#if QT_CONFIG(accessibility)
1942int QListViewPrivate::accessibleChildIndex(
const QModelIndex &index)
const
1944 Q_Q(
const QListView);
1945 Q_ASSERT(index.isValid());
1946 return q->visualIndex(index);
1950void QListViewPrivate::removeCurrentAndDisabled(QList<QModelIndex> *indexes,
1951 const QModelIndex ¤t)
const
1953 auto isCurrentOrDisabled = [
this, current](
const QModelIndex &index) {
1954 return !isIndexEnabled(index) || index == current;
1956 indexes->removeIf(isCurrentOrDisabled);
1960
1961
1963void QCommonListViewBase::appendHiddenRow(
int row)
1965 dd->hiddenRows.insert(dd->model->index(row, 0, qq->rootIndex()));
1968void QCommonListViewBase::removeHiddenRow(
int row)
1970 dd->hiddenRows.remove(dd->model->index(row, 0, qq->rootIndex()));
1973#if QT_CONFIG(draganddrop)
1974void QCommonListViewBase::paintDragDrop(QPainter *painter)
1978 dd->paintDropIndicator(painter);
1982QSize QListModeViewBase::viewportSize(
const QAbstractItemView *v)
1984 return v->contentsRect().marginsRemoved(v->viewportMargins()).size();
1987void QCommonListViewBase::updateHorizontalScrollBar(
const QSize &step)
1989 horizontalScrollBar()->d_func()->itemviewChangeSingleStep(step.width() + spacing());
1990 horizontalScrollBar()->setPageStep(viewport()->width());
1996 const bool bothScrollBarsAuto = qq->verticalScrollBarPolicy() == Qt::ScrollBarAsNeeded &&
1997 qq->horizontalScrollBarPolicy() == Qt::ScrollBarAsNeeded;
1999 const QSize viewportSize = QListModeViewBase::viewportSize(qq);
2001 bool verticalWantsToShow = contentsSize.height() > viewportSize.height();
2002 bool horizontalWantsToShow;
2003 if (verticalWantsToShow)
2004 horizontalWantsToShow = contentsSize.width() > viewportSize.width() - qq->verticalScrollBar()->width();
2006 horizontalWantsToShow = contentsSize.width() > viewportSize.width();
2008 if (bothScrollBarsAuto && !horizontalWantsToShow) {
2011 horizontalScrollBar()->setRange(0, 0);
2013 horizontalScrollBar()->setRange(0, contentsSize.width() - viewport()->width());
2017void QCommonListViewBase::updateVerticalScrollBar(
const QSize &step)
2019 verticalScrollBar()->d_func()->itemviewChangeSingleStep(step.height() + spacing());
2020 verticalScrollBar()->setPageStep(viewport()->height());
2026 const bool bothScrollBarsAuto = qq->verticalScrollBarPolicy() == Qt::ScrollBarAsNeeded &&
2027 qq->horizontalScrollBarPolicy() == Qt::ScrollBarAsNeeded;
2029 const QSize viewportSize = QListModeViewBase::viewportSize(qq);
2031 bool horizontalWantsToShow = contentsSize.width() > viewportSize.width();
2032 bool verticalWantsToShow;
2033 if (horizontalWantsToShow)
2034 verticalWantsToShow = contentsSize.height() > viewportSize.height() - qq->horizontalScrollBar()->height();
2036 verticalWantsToShow = contentsSize.height() > viewportSize.height();
2038 if (bothScrollBarsAuto && !verticalWantsToShow) {
2041 verticalScrollBar()->setRange(0, 0);
2043 verticalScrollBar()->setRange(0, contentsSize.height() - viewport()->height());
2047void QCommonListViewBase::scrollContentsBy(
int dx,
int dy,
bool )
2049 dd->scrollContentsBy(isRightToLeft() ? -dx : dx, dy);
2052int QCommonListViewBase::verticalScrollToValue(
int , QListView::ScrollHint hint,
2053 bool above,
bool below,
const QRect &area,
const QRect &rect)
const
2055 int verticalValue = verticalScrollBar()->value();
2056 QRect adjusted = rect.adjusted(-spacing(), -spacing(), spacing(), spacing());
2057 if (hint == QListView::PositionAtTop || above)
2058 verticalValue += adjusted.top();
2059 else if (hint == QListView::PositionAtBottom || below)
2060 verticalValue += qMin(adjusted.top(), adjusted.bottom() - area.height() + 1);
2061 else if (hint == QListView::PositionAtCenter)
2062 verticalValue += adjusted.top() - ((area.height() - adjusted.height()) / 2);
2063 return verticalValue;
2066int QCommonListViewBase::horizontalOffset()
const
2068 return (isRightToLeft() ? horizontalScrollBar()->maximum() - horizontalScrollBar()->value() : horizontalScrollBar()->value());
2071int QCommonListViewBase::horizontalScrollToValue(
const int , QListView::ScrollHint hint,
2072 bool leftOf,
bool rightOf,
const QRect &area,
const QRect &rect)
const
2074 int horizontalValue = horizontalScrollBar()->value();
2075 if (isRightToLeft()) {
2076 if (hint == QListView::PositionAtCenter) {
2077 horizontalValue += ((area.width() - rect.width()) / 2) - rect.left();
2080 horizontalValue -= rect.left();
2082 horizontalValue += qMin(rect.left(), area.width() - rect.right());
2085 if (hint == QListView::PositionAtCenter) {
2086 horizontalValue += rect.left() - ((area.width()- rect.width()) / 2);
2089 horizontalValue += rect.left();
2091 horizontalValue += qMin(rect.left(), rect.right() - area.width());
2094 return horizontalValue;
2098
2099
2100QListModeViewBase::QListModeViewBase(QListView *q, QListViewPrivate *d)
2101 : QCommonListViewBase(q, d)
2103#if QT_CONFIG(draganddrop)
2104 dd->defaultDropAction = Qt::CopyAction;
2108#if QT_CONFIG(draganddrop)
2109QAbstractItemView::DropIndicatorPosition QListModeViewBase::position(
const QPoint &pos,
const QRect &rect,
const QModelIndex &index)
const
2111 QAbstractItemView::DropIndicatorPosition r = QAbstractItemView::OnViewport;
2112 if (!dd->overwrite) {
2113 const int margin = 2;
2114 if (pos.x() - rect.left() < margin) {
2115 r = QAbstractItemView::AboveItem;
2116 }
else if (rect.right() - pos.x() < margin) {
2117 r = QAbstractItemView::BelowItem;
2118 }
else if (rect.contains(pos,
true)) {
2119 r = QAbstractItemView::OnItem;
2122 QRect touchingRect = rect;
2123 touchingRect.adjust(-1, -1, 1, 1);
2124 if (touchingRect.contains(pos,
false)) {
2125 r = QAbstractItemView::OnItem;
2129 if (r == QAbstractItemView::OnItem && (!(dd->model->flags(index) & Qt::ItemIsDropEnabled)))
2130 r = pos.x() < rect.center().x() ? QAbstractItemView::AboveItem : QAbstractItemView::BelowItem;
2135void QListModeViewBase::dragMoveEvent(QDragMoveEvent *event)
2137 if (qq->dragDropMode() == QAbstractItemView::InternalMove
2138 && (event->source() != qq || !(event->possibleActions() & Qt::MoveAction)))
2145 QPoint p = event->position().toPoint();
2146 QRect rect(p.x() + horizontalOffset(), p.y() + verticalOffset(), 1, 1);
2147 rect.adjust(-dd->spacing(), -dd->spacing(), dd->spacing(), dd->spacing());
2148 const QList<QModelIndex> intersectVector = dd->intersectingSet(rect);
2149 QModelIndex index = intersectVector.size() > 0
2150 ? intersectVector.last() : QModelIndex();
2152 if (!dd->droppingOnItself(event, index)
2153 && dd->canDrop(event)) {
2155 if (index.isValid() && dd->showDropIndicator) {
2156 QRect rect = qq->visualRect(index);
2157 dd->dropIndicatorPosition = position(event->position().toPoint(), rect, index);
2159 switch (dd->dropIndicatorPosition) {
2160 case QAbstractItemView::AboveItem:
2161 if (dd->isIndexDropEnabled(index.parent())) {
2162 dd->dropIndicatorRect = QRect(rect.left()-dd->spacing(), rect.top(), 0, rect.height());
2165 dd->dropIndicatorRect = QRect();
2168 case QAbstractItemView::BelowItem:
2169 if (dd->isIndexDropEnabled(index.parent())) {
2170 dd->dropIndicatorRect = QRect(rect.right()+dd->spacing(), rect.top(), 0, rect.height());
2173 dd->dropIndicatorRect = QRect();
2176 case QAbstractItemView::OnItem:
2177 if (dd->isIndexDropEnabled(index)) {
2178 dd->dropIndicatorRect = rect;
2181 dd->dropIndicatorRect = QRect();
2184 case QAbstractItemView::OnViewport:
2185 dd->dropIndicatorRect = QRect();
2186 if (dd->isIndexDropEnabled(qq->rootIndex())) {
2192 dd->dropIndicatorRect = QRect();
2193 dd->dropIndicatorPosition = QAbstractItemView::OnViewport;
2194 if (dd->isIndexDropEnabled(qq->rootIndex())) {
2198 dd->viewport->update();
2201 if (dd->shouldAutoScroll(event->position().toPoint()))
2202 qq->startAutoScroll();
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216bool QListModeViewBase::dropOn(QDropEvent *event,
int *dropRow,
int *dropCol, QModelIndex *dropIndex)
2218 if (event->isAccepted())
2222 if (dd->viewport->rect().contains(event->position().toPoint())) {
2224 QPoint p = event->position().toPoint();
2225 QRect rect(p.x() + horizontalOffset(), p.y() + verticalOffset(), 1, 1);
2226 rect.adjust(-dd->spacing(), -dd->spacing(), dd->spacing(), dd->spacing());
2227 const QList<QModelIndex> intersectVector = dd->intersectingSet(rect);
2228 index = intersectVector.size() > 0
2229 ? intersectVector.last() : QModelIndex();
2230 if (!index.isValid())
2235 if (dd->model->supportedDropActions() & event->dropAction()) {
2238 if (index != dd->root) {
2239 dd->dropIndicatorPosition = position(event->position().toPoint(), qq->visualRect(index), index);
2240 switch (dd->dropIndicatorPosition) {
2241 case QAbstractItemView::AboveItem:
2243 col = index.column();
2244 index = index.parent();
2246 case QAbstractItemView::BelowItem:
2247 row = index.row() + 1;
2248 col = index.column();
2249 index = index.parent();
2251 case QAbstractItemView::OnItem:
2252 case QAbstractItemView::OnViewport:
2256 dd->dropIndicatorPosition = QAbstractItemView::OnViewport;
2261 if (!dd->droppingOnItself(event, index))
2269void QListModeViewBase::updateVerticalScrollBar(
const QSize &step)
2271 if (verticalScrollMode() == QAbstractItemView::ScrollPerItem
2272 && ((flow() == QListView::TopToBottom && !isWrapping())
2273 || (flow() == QListView::LeftToRight && isWrapping()))) {
2274 const int steps = (flow() == QListView::TopToBottom ? scrollValueMap : segmentPositions).size() - 1;
2276 const int pageSteps = perItemScrollingPageSteps(viewport()->height(), contentsSize.height(), isWrapping());
2277 verticalScrollBar()->setSingleStep(1);
2278 verticalScrollBar()->setPageStep(pageSteps);
2279 verticalScrollBar()->setRange(0, steps - pageSteps);
2281 verticalScrollBar()->setRange(0, 0);
2286 QCommonListViewBase::updateVerticalScrollBar(step);
2290void QListModeViewBase::updateHorizontalScrollBar(
const QSize &step)
2292 if (horizontalScrollMode() == QAbstractItemView::ScrollPerItem
2293 && ((flow() == QListView::TopToBottom && isWrapping())
2294 || (flow() == QListView::LeftToRight && !isWrapping()))) {
2295 int steps = (flow() == QListView::TopToBottom ? segmentPositions : scrollValueMap).size() - 1;
2297 const int pageSteps = perItemScrollingPageSteps(viewport()->width(), contentsSize.width(), isWrapping());
2298 horizontalScrollBar()->setSingleStep(1);
2299 horizontalScrollBar()->setPageStep(pageSteps);
2300 horizontalScrollBar()->setRange(0, steps - pageSteps);
2302 horizontalScrollBar()->setRange(0, 0);
2305 QCommonListViewBase::updateHorizontalScrollBar(step);
2309int QListModeViewBase::verticalScrollToValue(
int index, QListView::ScrollHint hint,
2310 bool above,
bool below,
const QRect &area,
const QRect &rect)
const
2312 if (verticalScrollMode() == QAbstractItemView::ScrollPerItem) {
2314 if (scrollValueMap.isEmpty()) {
2317 int scrollBarValue = verticalScrollBar()->value();
2319 for (
const auto &idx : std::as_const(dd->hiddenRows))
2320 if (idx.row() <= scrollBarValue)
2322 value = qBound(0, scrollValueMap.at(verticalScrollBar()->value()) - numHidden, flowPositions.size() - 1);
2325 hint = QListView::PositionAtTop;
2327 hint = QListView::PositionAtBottom;
2328 if (hint == QListView::EnsureVisible)
2331 return perItemScrollToValue(index, value, area.height(), hint, Qt::Vertical, isWrapping(), rect.height());
2334 return QCommonListViewBase::verticalScrollToValue(index, hint, above, below, area, rect);
2337int QListModeViewBase::horizontalOffset()
const
2339 if (horizontalScrollMode() == QAbstractItemView::ScrollPerItem) {
2341 if (flow() == QListView::TopToBottom && !segmentPositions.isEmpty()) {
2342 const int max = segmentPositions.size() - 1;
2343 int currentValue = qBound(0, horizontalScrollBar()->value(), max);
2344 int position = segmentPositions.at(currentValue);
2345 int maximumValue = qBound(0, horizontalScrollBar()->maximum(), max);
2346 int maximum = segmentPositions.at(maximumValue);
2347 return (isRightToLeft() ? maximum - position : position);
2349 }
else if (flow() == QListView::LeftToRight && !flowPositions.isEmpty()) {
2350 int position = flowPositions.at(scrollValueMap.at(horizontalScrollBar()->value()));
2351 int maximum = flowPositions.at(scrollValueMap.at(horizontalScrollBar()->maximum()));
2352 return (isRightToLeft() ? maximum - position : position);
2355 return QCommonListViewBase::horizontalOffset();
2358int QListModeViewBase::verticalOffset()
const
2360 if (verticalScrollMode() == QAbstractItemView::ScrollPerItem) {
2362 if (flow() == QListView::LeftToRight && !segmentPositions.isEmpty()) {
2363 int value = verticalScrollBar()->value();
2364 if (value >= segmentPositions.size())
2366 return segmentPositions.at(value) - spacing();
2368 }
else if (flow() == QListView::TopToBottom && !flowPositions.isEmpty()) {
2369 int value = verticalScrollBar()->value();
2370 if (value > scrollValueMap.size())
2372 return flowPositions.at(scrollValueMap.at(value)) - spacing();
2375 return QCommonListViewBase::verticalOffset();
2378int QListModeViewBase::horizontalScrollToValue(
int index, QListView::ScrollHint hint,
2379 bool leftOf,
bool rightOf,
const QRect &area,
const QRect &rect)
const
2381 if (horizontalScrollMode() != QAbstractItemView::ScrollPerItem)
2382 return QCommonListViewBase::horizontalScrollToValue(index, hint, leftOf, rightOf, area, rect);
2385 if (scrollValueMap.isEmpty())
2388 value = qBound(0, scrollValueMap.at(horizontalScrollBar()->value()), flowPositions.size() - 1);
2390 hint = QListView::PositionAtTop;
2392 hint = QListView::PositionAtBottom;
2393 if (hint == QListView::EnsureVisible)
2396 return perItemScrollToValue(index, value, area.width(), hint, Qt::Horizontal, isWrapping(), rect.width());
2399void QListModeViewBase::scrollContentsBy(
int dx,
int dy,
bool scrollElasticBand)
2402 const int verticalValue = verticalScrollBar()->value();
2403 const int horizontalValue = horizontalScrollBar()->value();
2404 const bool vertical = (verticalScrollMode() == QAbstractItemView::ScrollPerItem);
2405 const bool horizontal = (horizontalScrollMode() == QAbstractItemView::ScrollPerItem);
2408 if (segmentPositions.isEmpty())
2410 const int max = segmentPositions.size() - 1;
2411 if (horizontal && flow() == QListView::TopToBottom && dx != 0) {
2412 int currentValue = qBound(0, horizontalValue, max);
2413 int previousValue = qBound(0, currentValue + dx, max);
2414 int currentCoordinate = segmentPositions.at(currentValue) - spacing();
2415 int previousCoordinate = segmentPositions.at(previousValue) - spacing();
2416 dx = previousCoordinate - currentCoordinate;
2417 }
else if (vertical && flow() == QListView::LeftToRight && dy != 0) {
2418 int currentValue = qBound(0, verticalValue, max);
2419 int previousValue = qBound(0, currentValue + dy, max);
2420 int currentCoordinate = segmentPositions.at(currentValue) - spacing();
2421 int previousCoordinate = segmentPositions.at(previousValue) - spacing();
2422 dy = previousCoordinate - currentCoordinate;
2425 if (flowPositions.isEmpty())
2427 const int max = scrollValueMap.size() - 1;
2428 if (vertical && flow() == QListView::TopToBottom && dy != 0) {
2429 int currentValue = qBound(0, verticalValue, max);
2430 int previousValue = qBound(0, currentValue + dy, max);
2431 int currentCoordinate = flowPositions.at(scrollValueMap.at(currentValue));
2432 int previousCoordinate = flowPositions.at(scrollValueMap.at(previousValue));
2433 dy = previousCoordinate - currentCoordinate;
2434 }
else if (horizontal && flow() == QListView::LeftToRight && dx != 0) {
2435 int currentValue = qBound(0, horizontalValue, max);
2436 int previousValue = qBound(0, currentValue + dx, max);
2437 int currentCoordinate = flowPositions.at(scrollValueMap.at(currentValue));
2438 int previousCoordinate = flowPositions.at(scrollValueMap.at(previousValue));
2439 dx = previousCoordinate - currentCoordinate;
2442 QCommonListViewBase::scrollContentsBy(dx, dy, scrollElasticBand);
2445bool QListModeViewBase::doBatchedItemLayout(
const QListViewLayoutInfo &info,
int max)
2447 doStaticLayout(info);
2448 return batchStartRow > max;
2451QListViewItem QListModeViewBase::indexToListViewItem(
const QModelIndex &index)
const
2453 if (flowPositions.isEmpty()
2454 || segmentPositions.isEmpty()
2455 || index.row() >= flowPositions.size() - 1)
2456 return QListViewItem();
2458 const int segment = qBinarySearch<
int>(segmentStartRows, index.row(),
2459 0, segmentStartRows.size() - 1);
2462 QStyleOptionViewItem options;
2463 initViewItemOption(&options);
2464 options.rect.setSize(contentsSize);
2465 QSize size = (uniformItemSizes() && cachedItemSize().isValid())
2466 ? cachedItemSize() : itemSize(options, index);
2467 QSize cellSize = size;
2470 if (flow() == QListView::LeftToRight) {
2471 pos.setX(flowPositions.at(index.row()));
2472 pos.setY(segmentPositions.at(segment));
2474 pos.setY(flowPositions.at(index.row()));
2475 pos.setX(segmentPositions.at(segment));
2477 int right = (segment + 1 >= segmentPositions.size()
2478 ? contentsSize.width()
2479 : segmentPositions.at(segment + 1));
2480 cellSize.setWidth(right - pos.x());
2482 cellSize.setWidth(qMax(size.width(), viewport()->width() - 2 * spacing()));
2486 if (dd->itemAlignment & Qt::AlignHorizontal_Mask) {
2487 size.setWidth(qMin(size.width(), cellSize.width()));
2488 if (dd->itemAlignment & Qt::AlignRight)
2489 pos.setX(pos.x() + cellSize.width() - size.width());
2490 if (dd->itemAlignment & Qt::AlignHCenter)
2491 pos.setX(pos.x() + (cellSize.width() - size.width()) / 2);
2493 size.setWidth(cellSize.width());
2496 return QListViewItem(QRect(pos, size), index.row());
2499QPoint QListModeViewBase::initStaticLayout(
const QListViewLayoutInfo &info)
2502 if (info.first == 0) {
2503 flowPositions.clear();
2504 segmentPositions.clear();
2505 segmentStartRows.clear();
2506 segmentExtents.clear();
2507 scrollValueMap.clear();
2508 x = info.bounds.left() + info.spacing;
2509 y = info.bounds.top() + info.spacing;
2510 segmentPositions.append(info.flow == QListView::LeftToRight ? y : x);
2511 segmentStartRows.append(0);
2512 }
else if (info.wrap) {
2513 if (info.flow == QListView::LeftToRight) {
2514 x = batchSavedPosition;
2515 y = segmentPositions.constLast();
2517 x = segmentPositions.constLast();
2518 y = batchSavedPosition;
2521 if (info.flow == QListView::LeftToRight) {
2522 x = batchSavedPosition;
2523 y = info.bounds.top() + info.spacing;
2525 x = info.bounds.left() + info.spacing;
2526 y = batchSavedPosition;
2529 return QPoint(x, y);
2533
2534
2535void QListModeViewBase::doStaticLayout(
const QListViewLayoutInfo &info)
2537 const bool useItemSize = !info.grid.isValid();
2538 const QPoint topLeft = initStaticLayout(info);
2539 QStyleOptionViewItem option;
2540 initViewItemOption(&option);
2541 option.rect = info.bounds;
2542 option.rect.adjust(info.spacing, info.spacing, -info.spacing, -info.spacing);
2550 int segStartPosition;
2552 int deltaFlowPosition;
2553 int deltaSegPosition;
2558 if (info.flow == QListView::LeftToRight) {
2559 segStartPosition = info.bounds.left();
2560 segEndPosition = info.bounds.width();
2561 flowPosition = topLeft.x();
2562 segPosition = topLeft.y();
2563 deltaFlowPosition = info.grid.width();
2564 deltaSegPosition = useItemSize ? batchSavedDeltaSeg : info.grid.height();
2565 deltaSegHint = info.grid.height();
2567 segStartPosition = info.bounds.top();
2568 segEndPosition = info.bounds.height();
2569 flowPosition = topLeft.y();
2570 segPosition = topLeft.x();
2571 deltaFlowPosition = info.grid.height();
2572 deltaSegPosition = useItemSize ? batchSavedDeltaSeg : info.grid.width();
2573 deltaSegHint = info.grid.width();
2576 for (
int row = info.first; row <= info.last; ++row) {
2577 if (isHidden(row)) {
2578 flowPositions.append(flowPosition);
2582 QSize hint = itemSize(option, modelIndex(row));
2583 if (info.flow == QListView::LeftToRight) {
2584 deltaFlowPosition = hint.width() + info.spacing;
2585 deltaSegHint = hint.height() + info.spacing;
2587 deltaFlowPosition = hint.height() + info.spacing;
2588 deltaSegHint = hint.width() + info.spacing;
2592 if (info.wrap && (flowPosition + deltaFlowPosition >= segEndPosition)) {
2593 segmentExtents.append(flowPosition);
2594 flowPosition = info.spacing + segStartPosition;
2595 segPosition += info.spacing + deltaSegPosition;
2596 segmentPositions.append(segPosition);
2597 segmentStartRows.append(row);
2598 deltaSegPosition = 0;
2601 scrollValueMap.append(flowPositions.size());
2602 flowPositions.append(flowPosition);
2604 deltaSegPosition = qMax(deltaSegHint, deltaSegPosition);
2605 flowPosition += info.spacing + deltaFlowPosition;
2609 batchSavedPosition = flowPosition;
2610 batchSavedDeltaSeg = deltaSegPosition;
2611 batchStartRow = info.last + 1;
2612 if (info.last == info.max)
2613 flowPosition -= info.spacing;
2615 QRect rect = info.bounds;
2616 if (info.flow == QListView::LeftToRight) {
2617 rect.setRight(segmentPositions.size() == 1 ? flowPosition : info.bounds.right());
2618 rect.setBottom(segPosition + deltaSegPosition);
2620 rect.setRight(segPosition + deltaSegPosition);
2621 rect.setBottom(segmentPositions.size() == 1 ? flowPosition : info.bounds.bottom());
2623 contentsSize = QSize(rect.right(), rect.bottom());
2625 if (info.last == info.max) {
2626 segmentExtents.append(flowPosition);
2627 scrollValueMap.append(flowPositions.size());
2628 flowPositions.append(flowPosition);
2629 segmentPositions.append(info.wrap ? segPosition + deltaSegPosition : INT_MAX);
2632 QRect changedRect(topLeft, rect.bottomRight());
2633 if (clipRect().intersects(changedRect))
2634 viewport()->update();
2638
2639
2640
2641
2642QList<QModelIndex> QListModeViewBase::intersectingSet(
const QRect &area)
const
2644 QList<QModelIndex> ret;
2645 int segStartPosition;
2647 int flowStartPosition;
2648 int flowEndPosition;
2649 if (flow() == QListView::LeftToRight) {
2650 segStartPosition = area.top();
2651 segEndPosition = area.bottom();
2652 flowStartPosition = area.left();
2653 flowEndPosition = area.right();
2655 segStartPosition = area.left();
2656 segEndPosition = area.right();
2657 flowStartPosition = area.top();
2658 flowEndPosition = area.bottom();
2660 if (segmentPositions.size() < 2 || flowPositions.isEmpty())
2663 const int segLast = segmentPositions.size() - 2;
2664 int seg = qBinarySearch<
int>(segmentPositions, segStartPosition, 0, segLast + 1);
2665 for (; seg <= segLast && segmentPositions.at(seg) <= segEndPosition; ++seg) {
2666 int first = segmentStartRows.at(seg);
2667 int last = (seg < segLast ? segmentStartRows.at(seg + 1) : batchStartRow) - 1;
2668 if (segmentExtents.at(seg) < flowStartPosition)
2670 int row = qBinarySearch<
int>(flowPositions, flowStartPosition, first, last);
2671 for (; row <= last && flowPositions.at(row) <= flowEndPosition; ++row) {
2674 QModelIndex index = modelIndex(row);
2675 if (index.isValid()) {
2676 if (flow() == QListView::LeftToRight || dd->itemAlignment == Qt::Alignment()) {
2679 const auto viewItem = indexToListViewItem(index);
2680 const int iw = viewItem.width();
2681 const int startPos = qMax(segStartPosition, segmentPositions.at(seg));
2682 const int endPos = qMin(segmentPositions.at(seg + 1), segEndPosition);
2683 if (endPos >= viewItem.x && startPos < viewItem.x + iw)
2689 qWarning(
"intersectingSet: row %d was invalid", row);
2696void QListModeViewBase::dataChanged(
const QModelIndex &,
const QModelIndex &)
2698 dd->doDelayedItemsLayout();
2702QRect QListModeViewBase::mapToViewport(
const QRect &rect)
const
2708 QRect result = rect;
2709 if (flow() == QListView::TopToBottom) {
2710 result.setLeft(spacing());
2711 result.setWidth(qMax(rect.width(), qMax(contentsSize.width(), viewport()->width()) - 2 * spacing()));
2713 result.setTop(spacing());
2714 result.setHeight(qMax(rect.height(), qMax(contentsSize.height(), viewport()->height()) - 2 * spacing()));
2719int QListModeViewBase::perItemScrollingPageSteps(
int length,
int bounds,
bool wrap)
const
2721 QList<
int> positions;
2723 positions = segmentPositions;
2724 else if (!flowPositions.isEmpty()) {
2725 positions.reserve(scrollValueMap.size());
2726 for (
int itemShown : scrollValueMap)
2727 positions.append(flowPositions.at(itemShown));
2729 if (positions.isEmpty() || bounds <= length)
2730 return positions.size();
2731 if (uniformItemSizes()) {
2732 for (
int i = 1; i < positions.size(); ++i)
2733 if (positions.at(i) > 0)
2734 return length / positions.at(i);
2738 int steps = positions.size() - 1;
2739 int max = qMax(length, bounds);
2740 int min = qMin(length, bounds);
2741 int pos = min - (max - positions.constLast());
2743 while (pos >= 0 && steps > 0) {
2744 pos -= (positions.at(steps) - positions.at(steps - 1));
2751 return qMax(pageSteps, 1);
2754int QListModeViewBase::perItemScrollToValue(
int index,
int scrollValue,
int viewportSize,
2755 QAbstractItemView::ScrollHint hint,
2756 Qt::Orientation orientation,
bool wrap,
int itemExtent)
const
2761 itemExtent += spacing();
2762 QList<
int> hiddenRows = dd->hiddenRowIds();
2763 std::sort(hiddenRows.begin(), hiddenRows.end());
2764 int hiddenRowsBefore = 0;
2765 for (
int i = 0; i < hiddenRows.size() - 1; ++i)
2766 if (hiddenRows.at(i) > index + hiddenRowsBefore)
2771 int topIndex = index;
2772 const int bottomIndex = topIndex;
2773 const int bottomCoordinate = flowPositions.at(index + hiddenRowsBefore);
2774 while (topIndex > 0 &&
2775 (bottomCoordinate - flowPositions.at(topIndex + hiddenRowsBefore - 1) + itemExtent) <= (viewportSize)) {
2778 while (hiddenRowsBefore > 0 && hiddenRows.at(hiddenRowsBefore - 1) >= topIndex + hiddenRowsBefore - 1)
2782 const int itemCount = bottomIndex - topIndex + 1;
2784 case QAbstractItemView::PositionAtTop:
2786 case QAbstractItemView::PositionAtBottom:
2787 return index - itemCount + 1;
2788 case QAbstractItemView::PositionAtCenter:
2789 return index - (itemCount / 2);
2794 Qt::Orientation flowOrientation = (flow() == QListView::LeftToRight
2795 ? Qt::Horizontal : Qt::Vertical);
2796 if (flowOrientation == orientation) {
2798 return flowPositions.at(index + hiddenRowsBefore);
2799 }
else if (!segmentStartRows.isEmpty()) {
2800 int segment = qBinarySearch<
int>(segmentStartRows, index, 0, segmentStartRows.size() - 1);
2801 int leftSegment = segment;
2802 const int rightSegment = leftSegment;
2803 const int bottomCoordinate = segmentPositions.at(segment);
2805 while (leftSegment > scrollValue &&
2806 (bottomCoordinate - segmentPositions.at(leftSegment-1) + itemExtent) <= (viewportSize)) {
2810 const int segmentCount = rightSegment - leftSegment + 1;
2812 case QAbstractItemView::PositionAtTop:
2814 case QAbstractItemView::PositionAtBottom:
2815 return segment - segmentCount + 1;
2816 case QAbstractItemView::PositionAtCenter:
2817 return segment - (segmentCount / 2);
2826void QListModeViewBase::clear()
2828 flowPositions.clear();
2829 segmentPositions.clear();
2830 segmentStartRows.clear();
2831 segmentExtents.clear();
2832 batchSavedPosition = 0;
2834 batchSavedDeltaSeg = 0;
2838
2839
2841void QIconModeViewBase::setPositionForIndex(
const QPoint &position,
const QModelIndex &index)
2843 if (index.row() >= items.size())
2845 const QSize oldContents = contentsSize;
2847 moveItem(index.row(), position);
2850 if (contentsSize != oldContents)
2851 dd->viewUpdateGeometries();
2854void QIconModeViewBase::appendHiddenRow(
int row)
2856 if (row >= 0 && row < items.size())
2857 tree.removeLeaf(items.at(row).rect(), row);
2858 QCommonListViewBase::appendHiddenRow(row);
2861void QIconModeViewBase::removeHiddenRow(
int row)
2863 QCommonListViewBase::removeHiddenRow(row);
2864 if (row >= 0 && row < items.size())
2865 tree.insertLeaf(items.at(row).rect(), row);
2868#if QT_CONFIG(draganddrop)
2869bool QIconModeViewBase::filterStartDrag(Qt::DropActions supportedActions)
2874 QModelIndexList indexes = dd->selectionModel->selectedIndexes();
2875 if (indexes.size() > 0 ) {
2876 if (viewport()->acceptDrops()) {
2877 QModelIndexList::ConstIterator it = indexes.constBegin();
2878 for (; it != indexes.constEnd(); ++it)
2879 if (dd->model->flags(*it) & Qt::ItemIsDragEnabled
2880 && (*it).column() == dd->column)
2881 draggedItems.push_back(*it);
2885 QPixmap pixmap = dd->renderToPixmap(indexes, &rect);
2886 rect.adjust(horizontalOffset(), verticalOffset(), 0, 0);
2887 QDrag *drag =
new QDrag(qq);
2888 drag->setMimeData(dd->model->mimeData(indexes));
2889 drag->setPixmap(pixmap);
2890 drag->setHotSpot(dd->pressedPosition - rect.topLeft());
2891 dd->dropEventMoved =
false;
2892 Qt::DropAction action = drag->exec(supportedActions, dd->defaultDropAction);
2893 draggedItems.clear();
2895 if (action == Qt::MoveAction && !dd->dropEventMoved) {
2896 if (dd->dragDropMode != QAbstractItemView::InternalMove || drag->target() == qq->viewport())
2897 dd->clearOrRemove();
2899 dd->dropEventMoved =
false;
2904bool QIconModeViewBase::filterDropEvent(QDropEvent *e)
2906 if (e->source() != qq)
2909 const QSize contents = contentsSize;
2910 QPoint offset(horizontalOffset(), verticalOffset());
2911 QPoint end = e->position().toPoint() + offset;
2912 if (qq->acceptDrops()) {
2913 const Qt::ItemFlags dropableFlags = Qt::ItemIsDropEnabled|Qt::ItemIsEnabled;
2914 const QList<QModelIndex> &dropIndices = intersectingSet(QRect(end, QSize(1, 1)));
2915 for (
const QModelIndex &index : dropIndices)
2916 if ((index.flags() & dropableFlags) == dropableFlags)
2919 QPoint start = dd->pressedPosition;
2920 QPoint delta = (dd->movement == QListView::Snap ? snapToGrid(end) - snapToGrid(start) : end - start);
2921 const QList<QModelIndex> indexes = dd->selectionModel->selectedIndexes();
2922 for (
const auto &index : indexes) {
2923 QRect rect = dd->rectForIndex(index);
2924 viewport()->update(dd->mapToViewport(rect,
false));
2925 QPoint dest = rect.topLeft() + delta;
2926 if (qq->isRightToLeft())
2927 dest.setX(dd->flipX(dest.x()) - rect.width());
2928 moveItem(index.row(), dest);
2931 dd->stopAutoScroll();
2932 draggedItems.clear();
2933 dd->emitIndexesMoved(indexes);
2935 dd->dropEventMoved =
true;
2938 if (contentsSize != contents) {
2939 if ((contentsSize.width() <= contents.width()
2940 || contentsSize.height() <= contents.height())) {
2941 updateContentsSize();
2943 dd->viewUpdateGeometries();
2948bool QIconModeViewBase::filterDragLeaveEvent(QDragLeaveEvent *e)
2950 viewport()->update(draggedItemsRect());
2951 draggedItemsPos = QPoint(-1, -1);
2952 return QCommonListViewBase::filterDragLeaveEvent(e);
2955bool QIconModeViewBase::filterDragMoveEvent(QDragMoveEvent *e)
2957 const bool wasAccepted = e->isAccepted();
2962 if (e->source() != qq || !dd->canDrop(e)) {
2964 e->setAccepted(wasAccepted);
2969 QRect itemsRect =
this->itemsRect(draggedItems);
2970 viewport()->update(itemsRect.translated(draggedItemsDelta()));
2972 draggedItemsPos = e->position().toPoint();
2974 viewport()->update(itemsRect.translated(draggedItemsDelta()));
2977 if (movement() == QListView::Snap) {
2978 QRect rect(snapToGrid(e->position().toPoint() + offset()), gridSize());
2979 const QList<QModelIndex> intersectVector = intersectingSet(rect);
2980 index = intersectVector.size() > 0 ? intersectVector.last() : QModelIndex();
2982 index = qq->indexAt(e->position().toPoint());
2985 if (draggedItems.contains(index))
2987 else if (dd->model->flags(index) & Qt::ItemIsDropEnabled)
2989 else if (!index.isValid())
2993 if (dd->shouldAutoScroll(e->position().toPoint()))
2994 dd->startAutoScroll();
2999void QIconModeViewBase::setRowCount(
int rowCount)
3001 tree.create(qMax(rowCount - hiddenCount(), 0));
3004void QIconModeViewBase::scrollContentsBy(
int dx,
int dy,
bool scrollElasticBand)
3006 if (scrollElasticBand)
3007 dd->scrollElasticBandBy(isRightToLeft() ? -dx : dx, dy);
3009 QCommonListViewBase::scrollContentsBy(dx, dy, scrollElasticBand);
3010 if (!draggedItems.isEmpty())
3011 viewport()->update(draggedItemsRect().translated(dx, dy));
3014void QIconModeViewBase::dataChanged(
const QModelIndex &topLeft,
const QModelIndex &bottomRight)
3016 if (column() >= topLeft.column() && column() <= bottomRight.column()) {
3017 QStyleOptionViewItem option;
3018 initViewItemOption(&option);
3019 const int bottom = qMin(items.size(), bottomRight.row() + 1);
3020 const bool useItemSize = !dd->grid.isValid();
3021 for (
int row = topLeft.row(); row < bottom; ++row)
3023 QSize s = itemSize(option, modelIndex(row));
3026 s.setWidth(qMin(dd->grid.width(), s.width()));
3027 s.setHeight(qMin(dd->grid.height(), s.height()));
3029 items[row].resize(s);
3034bool QIconModeViewBase::doBatchedItemLayout(
const QListViewLayoutInfo &info,
int max)
3036 if (info.last >= items.size()) {
3038 QStyleOptionViewItem option;
3039 initViewItemOption(&option);
3040 for (
int row = items.size(); row <= info.last; ++row) {
3041 QSize size = itemSize(option, modelIndex(row));
3042 QListViewItem item(QRect(0, 0, size.width(), size.height()), row);
3045 doDynamicLayout(info);
3047 return (batchStartRow > max);
3050QListViewItem QIconModeViewBase::indexToListViewItem(
const QModelIndex &index)
const
3052 if (index.isValid() && index.row() < items.size())
3053 return items.at(index.row());
3054 return QListViewItem();
3057void QIconModeViewBase::initBspTree(
const QSize &contents)
3060 int leafCount = tree.leafCount();
3061 for (
int l = 0; l < leafCount; ++l)
3062 tree.leaf(l).clear();
3064 QBspTree::Node::Type type = QBspTree::Node::Both;
3066 if (contents.height() / contents.width() >= 3)
3067 type = QBspTree::Node::HorizontalPlane;
3068 else if (contents.width() / contents.height() >= 3)
3069 type = QBspTree::Node::VerticalPlane;
3071 tree.init(QRect(0, 0, contents.width(), contents.height()), type);
3074QPoint QIconModeViewBase::initDynamicLayout(
const QListViewLayoutInfo &info)
3077 if (info.first == 0) {
3078 x = info.bounds.x() + info.spacing;
3079 y = info.bounds.y() + info.spacing;
3080 items.reserve(rowCount() - hiddenCount());
3082 int idx = info.first - 1;
3083 while (idx > 0 && !items.at(idx).isValid())
3085 const QListViewItem &item = items.at(idx);
3088 if (info.flow == QListView::LeftToRight)
3089 x += (info.grid.isValid() ? info.grid.width() : item.w) + info.spacing;
3091 y += (info.grid.isValid() ? info.grid.height() : item.h) + info.spacing;
3093 return QPoint(x, y);
3097
3098
3099void QIconModeViewBase::doDynamicLayout(
const QListViewLayoutInfo &info)
3101 const bool useItemSize = !info.grid.isValid();
3102 const QPoint topLeft = initDynamicLayout(info);
3104 int segStartPosition;
3106 int deltaFlowPosition;
3107 int deltaSegPosition;
3112 if (info.flow == QListView::LeftToRight) {
3113 segStartPosition = info.bounds.left() + info.spacing;
3114 segEndPosition = info.bounds.right();
3115 deltaFlowPosition = info.grid.width();
3116 deltaSegPosition = (useItemSize ? batchSavedDeltaSeg : info.grid.height());
3117 deltaSegHint = info.grid.height();
3118 flowPosition = topLeft.x();
3119 segPosition = topLeft.y();
3121 segStartPosition = info.bounds.top() + info.spacing;
3122 segEndPosition = info.bounds.bottom();
3123 deltaFlowPosition = info.grid.height();
3124 deltaSegPosition = (useItemSize ? batchSavedDeltaSeg : info.grid.width());
3125 deltaSegHint = info.grid.width();
3126 flowPosition = topLeft.y();
3127 segPosition = topLeft.x();
3130 if (moved.size() != items.size())
3131 moved.resize(items.size());
3133 QRect rect(QPoint(), topLeft);
3134 QListViewItem *item =
nullptr;
3135 Q_ASSERT(info.first <= info.last);
3136 for (
int row = info.first; row <= info.last; ++row) {
3138 if (isHidden(row)) {
3143 if (info.flow == QListView::LeftToRight)
3144 deltaFlowPosition = item->w + info.spacing;
3146 deltaFlowPosition = item->h + info.spacing;
3148 item->w = qMin<
int>(info.grid.width(), item->w);
3149 item->h = qMin<
int>(info.grid.height(), item->h);
3154 && flowPosition + deltaFlowPosition > segEndPosition
3155 && flowPosition > segStartPosition) {
3156 flowPosition = segStartPosition;
3157 segPosition += deltaSegPosition;
3159 deltaSegPosition = 0;
3164 if (info.flow == QListView::LeftToRight)
3165 deltaSegHint = item->h + info.spacing;
3167 deltaSegHint = item->w + info.spacing;
3168 deltaSegPosition = qMax(deltaSegPosition, deltaSegHint);
3174 if (!moved.testBit(row)) {
3175 if (info.flow == QListView::LeftToRight) {
3177 item->x = flowPosition;
3178 item->y = segPosition;
3180 item->x = flowPosition + ((deltaFlowPosition - item->w) / 2);
3181 item->y = segPosition;
3185 item->y = flowPosition;
3186 item->x = segPosition;
3188 item->y = flowPosition + ((deltaFlowPosition - item->h) / 2);
3189 item->x = segPosition;
3196 rect |= item->rect();
3197 else if (info.flow == QListView::LeftToRight)
3198 rect |= QRect(flowPosition, segPosition, deltaFlowPosition, deltaSegPosition);
3200 rect |= QRect(segPosition, flowPosition, deltaSegPosition, deltaFlowPosition);
3203 flowPosition += deltaFlowPosition;
3207 batchSavedDeltaSeg = deltaSegPosition;
3208 batchStartRow = info.last + 1;
3209 bool done = (info.last >= rowCount() - 1);
3211 if (done || !info.bounds.contains(item->rect())) {
3212 contentsSize = rect.size();
3213 if (info.flow == QListView::LeftToRight)
3214 contentsSize.rheight() += info.spacing;
3216 contentsSize.rwidth() += info.spacing;
3218 if (rect.size().isEmpty())
3221 int insertFrom = info.first;
3222 if (done || info.first == 0) {
3223 initBspTree(rect.size());
3227 for (
int row = insertFrom; row <= info.last; ++row)
3228 tree.insertLeaf(items.at(row).rect(), row);
3230 QRect changedRect(topLeft, rect.bottomRight());
3231 if (clipRect().intersects(changedRect))
3232 viewport()->update();
3235QList<QModelIndex> QIconModeViewBase::intersectingSet(
const QRect &area)
const
3237 QIconModeViewBase *that =
const_cast<QIconModeViewBase*>(
this);
3238 QBspTree::Data data(
static_cast<
void*>(that));
3239 QList<QModelIndex> res;
3240 that->interSectingVector = &res;
3241 that->tree.climbTree(area, &QIconModeViewBase::addLeaf, data);
3242 that->interSectingVector =
nullptr;
3246QRect QIconModeViewBase::itemsRect(
const QList<QModelIndex> &indexes)
const
3249 for (
const auto &index : indexes)
3250 rect |= viewItemRect(indexToListViewItem(index));
3254int QIconModeViewBase::itemIndex(
const QListViewItem &item)
const
3256 if (!item.isValid())
3258 int i = item.indexHint;
3259 if (i < items.size()) {
3260 if (items.at(i) == item)
3263 i = items.size() - 1;
3267 int c = items.size();
3273 if (items.at(i) == item) {
3274 items.at(i).indexHint = i;
3280 if (items.at(j) == item) {
3281 items.at(j).indexHint = j;
3290void QIconModeViewBase::addLeaf(QList<
int> &leaf,
const QRect &area, uint visited,
3291 QBspTree::Data data)
3294 QIconModeViewBase *_this =
static_cast<QIconModeViewBase *>(data.ptr);
3295 for (
int i = 0; i < leaf.size(); ++i) {
3296 int idx = leaf.at(i);
3297 if (idx < 0 || idx >= _this->items.size())
3299 vi = &_this->items[idx];
3301 if (vi->isValid() && vi->rect().intersects(area) && vi->visited != visited) {
3302 QModelIndex index = _this->dd->listViewItemToIndex(*vi);
3303 Q_ASSERT(index.isValid());
3304 _this->interSectingVector->append(index);
3305 vi->visited = visited;
3310void QIconModeViewBase::moveItem(
int index,
const QPoint &dest)
3313 QListViewItem *item = &items[index];
3314 QRect rect = item->rect();
3317 tree.removeLeaf(rect, index);
3319 tree.insertLeaf(QRect(dest, rect.size()), index);
3322 contentsSize = (QRect(QPoint(0, 0), contentsSize)|QRect(dest, rect.size())).size();
3325 if (moved.size() != items.size())
3326 moved.resize(items.size());
3327 moved.setBit(index,
true);
3330QPoint QIconModeViewBase::snapToGrid(
const QPoint &pos)
const
3332 int x = pos.x() - (pos.x() % gridSize().width());
3333 int y = pos.y() - (pos.y() % gridSize().height());
3334 return QPoint(x, y);
3337QPoint QIconModeViewBase::draggedItemsDelta()
const
3339 if (movement() == QListView::Snap) {
3340 QPoint snapdelta = QPoint((offset().x() % gridSize().width()),
3341 (offset().y() % gridSize().height()));
3342 return snapToGrid(draggedItemsPos + snapdelta) - snapToGrid(pressedPosition()) - snapdelta;
3344 return draggedItemsPos - pressedPosition();
3347QRect QIconModeViewBase::draggedItemsRect()
const
3349 QRect rect = itemsRect(draggedItems);
3350 rect.translate(draggedItemsDelta());
3354void QListViewPrivate::scrollElasticBandBy(
int dx,
int dy)
3357 elasticBand.moveRight(elasticBand.right() + dx);
3359 elasticBand.moveLeft(elasticBand.left() - dx);
3361 elasticBand.moveBottom(elasticBand.bottom() + dy);
3363 elasticBand.moveTop(elasticBand.top() - dy);
3366void QIconModeViewBase::clear()
3372 batchSavedDeltaSeg = 0;
3375void QIconModeViewBase::updateContentsSize()
3378 for (
int i = 0; i < items.size(); ++i)
3379 bounding |= items.at(i).rect();
3380 contentsSize = bounding.size();
3384
3385
3386void QListView::currentChanged(
const QModelIndex ¤t,
const QModelIndex &previous)
3388 Q_D(
const QListView);
3389 QAbstractItemView::currentChanged(current, previous);
3390#if QT_CONFIG(accessibility)
3391 if (QAccessible::isActive()) {
3392 if (current.isValid() && hasFocus()) {
3393 int entry = d->accessibleChildIndex(current);
3394 QAccessibleEvent event(
this, QAccessible::Focus);
3395 event.setChild(entry);
3396 QAccessible::updateAccessibility(&event);
3403
3404
3405void QListView::selectionChanged(
const QItemSelection &selected,
3406 const QItemSelection &deselected)
3408#if QT_CONFIG(accessibility)
3409 Q_D(
const QListView);
3410 if (QAccessible::isActive()) {
3412 QModelIndex sel = selected.indexes().value(0);
3413 if (sel.isValid()) {
3414 int entry = d->accessibleChildIndex(sel);
3415 QAccessibleEvent event(
this, QAccessible::SelectionAdd);
3416 event.setChild(entry);
3417 QAccessible::updateAccessibility(&event);
3419 QModelIndex desel = deselected.indexes().value(0);
3420 if (desel.isValid()) {
3421 int entry = d->accessibleChildIndex(desel);
3422 QAccessibleEvent event(
this, QAccessible::SelectionRemove);
3423 event.setChild(entry);
3424 QAccessible::updateAccessibility(&event);
3428 QAbstractItemView::selectionChanged(selected, deselected);
3431int QListView::visualIndex(
const QModelIndex &index)
const
3433 Q_D(
const QListView);
3434 d->executePostedLayout();
3435 QListViewItem itm = d->indexToListViewItem(index);
3436 int visualIndex = d->commonListView->itemIndex(itm);
3437 for (
const auto &idx : std::as_const(d->hiddenRows)) {
3438 if (idx.row() <= index.row())
3446
3447
3448
3449QSize QListView::viewportSizeHint()
const
3451 Q_D(
const QListView);
3454 return QAbstractItemView::viewportSizeHint();
3455 const int rc = d->model->rowCount();
3456 if (rc == 0 || isWrapping())
3457 return QAbstractItemView::viewportSizeHint();
3459 QStyleOptionViewItem option;
3460 initViewItemOption(&option);
3462 if (uniformItemSizes()) {
3463 QSize sz = d->cachedItemSize;
3464 if (!sz.isValid()) {
3465 QModelIndex idx = d->model->index(0, d->column, d->root);
3466 sz = d->itemSize(option, idx);
3468 sz.setHeight(rc * sz.height());
3475 int maximumRows = 1000;
3476 const QVariant userOverrideValue = property(
"_q_resizeContentPrecision");
3477 if (userOverrideValue.isValid() && userOverrideValue.toInt() > 0) {
3478 maximumRows = userOverrideValue.toInt();
3480 const int rowCount = qMin(rc, maximumRows);
3485 for (
int row = 0; row < rowCount; ++row) {
3486 QModelIndex idx = d->model->index(row, d->column, d->root);
3487 QSize itemSize = d->itemSize(option, idx);
3488 h += itemSize.height();
3489 w = qMax(w, itemSize.width());
3496#include "moc_qlistview.cpp"