7#include <qabstractitemdelegate.h>
8#if QT_CONFIG(accessibility)
9#include <qaccessible.h>
11#include <qapplication.h>
12#include <qstylepainter.h>
15#if QT_CONFIG(draganddrop)
20#if QT_CONFIG(rubberband)
21#include <qrubberband.h>
23#include <qscrollbar.h>
25#include <private/qapplication_p.h>
26#include <private/qlistview_p.h>
27#include <private/qscrollbar_p.h>
36
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
95
96
97
98
99
102
103
104
105
106
107
108
111
112
113
114
116
117
120
121
122
123
124
127
128
129
130
131
132
135
136
137
138
141
142
143
144QListView::QListView(QWidget *parent)
145 : QAbstractItemView(*
new QListViewPrivate, parent)
147 setViewMode(ListMode);
148 setSelectionMode(SingleSelection);
149 setAttribute(Qt::WA_MacShowFocusRect);
151 d->updateStyledFrameWidths();
155
156
157QListView::QListView(QListViewPrivate &dd, QWidget *parent)
158 : QAbstractItemView(dd, parent)
160 setViewMode(ListMode);
161 setSelectionMode(SingleSelection);
162 setAttribute(Qt::WA_MacShowFocusRect);
164 d->updateStyledFrameWidths();
168
169
170QListView::~QListView()
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193void QListView::setMovement(Movement movement)
196 d->modeProperties |= uint(QListViewPrivate::Movement);
197 d->movement = movement;
199#if QT_CONFIG(draganddrop)
200 bool movable = (movement != Static);
201 setDragEnabled(movable);
202 d->viewport->setAcceptDrops(movable);
204 d->doDelayedItemsLayout();
207QListView::Movement QListView::movement()
const
209 Q_D(
const QListView);
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230void QListView::setFlow(Flow flow)
233 d->modeProperties |= uint(QListViewPrivate::Flow);
235 d->doDelayedItemsLayout();
238QListView::Flow QListView::flow()
const
240 Q_D(
const QListView);
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259void QListView::setWrapping(
bool enable)
262 d->modeProperties |= uint(QListViewPrivate::Wrap);
263 d->setWrapping(enable);
264 d->doDelayedItemsLayout();
267bool QListView::isWrapping()
const
269 Q_D(
const QListView);
270 return d->isWrapping();
274
275
276
277
278
279
280
281
282
283
284
285void QListView::setResizeMode(ResizeMode mode)
288 d->modeProperties |= uint(QListViewPrivate::ResizeMode);
289 d->resizeMode = mode;
292QListView::ResizeMode QListView::resizeMode()
const
294 Q_D(
const QListView);
295 return d->resizeMode;
299
300
301
302
303
304
305
306
307
308
309
310
311void QListView::setLayoutMode(LayoutMode mode)
314 d->layoutMode = mode;
317QListView::LayoutMode QListView::layoutMode()
const
319 Q_D(
const QListView);
320 return d->layoutMode;
324
325
326
327
328
329
330
331
332
333
334
335
336
337void QListView::setSpacing(
int space)
340 d->modeProperties |= uint(QListViewPrivate::Spacing);
341 d->setSpacing(space);
342 d->doDelayedItemsLayout();
345int QListView::spacing()
const
347 Q_D(
const QListView);
352
353
354
355
356
357
359void QListView::setBatchSize(
int batchSize)
362 if (Q_UNLIKELY(batchSize <= 0)) {
363 qWarning(
"Invalid batchSize (%d)", batchSize);
366 d->batchSize = batchSize;
369int QListView::batchSize()
const
371 Q_D(
const QListView);
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390void QListView::setGridSize(
const QSize &size)
393 d->modeProperties |= uint(QListViewPrivate::GridSize);
394 d->setGridSize(size);
395 d->doDelayedItemsLayout();
398QSize QListView::gridSize()
const
400 Q_D(
const QListView);
401 return d->gridSize();
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419void QListView::setViewMode(ViewMode mode)
422 if (d->commonListView && d->viewMode == mode)
426 delete d->commonListView;
427 if (mode == ListMode) {
428 d->commonListView =
new QListModeViewBase(
this, d);
429 if (!(d->modeProperties & QListViewPrivate::Wrap))
430 d->setWrapping(
false);
431 if (!(d->modeProperties & QListViewPrivate::Spacing))
433 if (!(d->modeProperties & QListViewPrivate::GridSize))
434 d->setGridSize(QSize());
435 if (!(d->modeProperties & QListViewPrivate::Flow))
436 d->flow = TopToBottom;
437 if (!(d->modeProperties & QListViewPrivate::Movement))
438 d->movement = Static;
439 if (!(d->modeProperties & QListViewPrivate::ResizeMode))
440 d->resizeMode = Fixed;
441 if (!(d->modeProperties & QListViewPrivate::SelectionRectVisible))
442 d->showElasticBand =
false;
444 d->commonListView =
new QIconModeViewBase(
this, d);
445 if (!(d->modeProperties & QListViewPrivate::Wrap))
446 d->setWrapping(
true);
447 if (!(d->modeProperties & QListViewPrivate::Spacing))
449 if (!(d->modeProperties & QListViewPrivate::GridSize))
450 d->setGridSize(QSize());
451 if (!(d->modeProperties & QListViewPrivate::Flow))
452 d->flow = LeftToRight;
453 if (!(d->modeProperties & QListViewPrivate::Movement))
455 if (!(d->modeProperties & QListViewPrivate::ResizeMode))
456 d->resizeMode = Fixed;
457 if (!(d->modeProperties & QListViewPrivate::SelectionRectVisible))
458 d->showElasticBand =
true;
461#if QT_CONFIG(draganddrop)
462 bool movable = (d->movement != Static);
463 setDragEnabled(movable);
464 setAcceptDrops(movable);
467 d->doDelayedItemsLayout();
470QListView::ViewMode QListView::viewMode()
const
472 Q_D(
const QListView);
477
478
479
480
481
482
483
484
485void QListView::clearPropertyFlags()
488 d->modeProperties = 0;
492
493
494bool QListView::isRowHidden(
int row)
const
496 Q_D(
const QListView);
497 return d->isHidden(row);
501
502
503
504void QListView::setRowHidden(
int row,
bool hide)
507 const bool hidden = d->isHidden(row);
509 d->commonListView->appendHiddenRow(row);
510 else if (!hide && hidden)
511 d->commonListView->removeHiddenRow(row);
512 d->doDelayedItemsLayout();
513 d->viewport->update();
517
518
519QRect QListView::visualRect(
const QModelIndex &index)
const
521 Q_D(
const QListView);
522 return d->mapToViewport(rectForIndex(index));
526
527
528void QListView::scrollTo(
const QModelIndex &index, ScrollHint hint)
532 if (index.parent() != d->root || index.column() != d->column)
535 const QRect rect = visualRect(index);
538 if (hint == EnsureVisible && d->viewport->rect().contains(rect)) {
539 d->viewport->update(rect);
543 if (d->flow == QListView::TopToBottom || d->isWrapping())
544 verticalScrollBar()->setValue(d->verticalScrollToValue(index, rect, hint));
546 if (d->flow == QListView::LeftToRight || d->isWrapping())
547 horizontalScrollBar()->setValue(d->horizontalScrollToValue(index, rect, hint));
550int QListViewPrivate::horizontalScrollToValue(
const QModelIndex &index,
const QRect &rect,
551 QListView::ScrollHint hint)
const
553 Q_Q(
const QListView);
554 const QRect area = viewport->rect();
555 const bool leftOf = q->isRightToLeft()
556 ? (rect.left() < area.left()) && (rect.right() < area.right())
557 : rect.left() < area.left();
558 const bool rightOf = q->isRightToLeft()
559 ? rect.right() > area.right()
560 : (rect.right() > area.right()) && (rect.left() > area.left());
561 return commonListView->horizontalScrollToValue(q->visualIndex(index), hint, leftOf, rightOf, area, rect);
564int QListViewPrivate::verticalScrollToValue(
const QModelIndex &index,
const QRect &rect,
565 QListView::ScrollHint hint)
const
567 Q_Q(
const QListView);
568 const QRect area = viewport->rect();
569 const bool above = (hint == QListView::EnsureVisible && rect.top() < area.top());
570 const bool below = (hint == QListView::EnsureVisible && rect.bottom() > area.bottom());
571 return commonListView->verticalScrollToValue(q->visualIndex(index), hint, above, below, area, rect);
574void QListViewPrivate::selectAll(QItemSelectionModel::SelectionFlags command)
579 QItemSelection selection;
582 const int colCount = model->columnCount(root);
583 const int rowCount = model->rowCount(root);
584 for ( ; row < rowCount; ++row) {
587 if (topLeft.isValid()) {
588 QModelIndex bottomRight = model->index(row - 1, colCount - 1, root);
589 selection.append(QItemSelectionRange(topLeft, bottomRight));
590 topLeft = QModelIndex();
595 if (!topLeft.isValid())
596 topLeft = model->index(row, 0, root);
599 if (topLeft.isValid()) {
601 QModelIndex bottomRight = model->index(row - 1, colCount - 1, root);
602 selection.append(QItemSelectionRange(topLeft, bottomRight));
605 if (!selection.isEmpty())
606 selectionModel->select(selection, command);
610
611
612
613
614
615QItemViewPaintPairs QListViewPrivate::draggablePaintPairs(
const QModelIndexList &indexes, QRect *r)
const
618 Q_Q(
const QListView);
620 const QRect viewportRect = viewport->rect();
621 QItemViewPaintPairs ret;
622 QList<QModelIndex> visibleIndexes =
623 intersectingSet(viewportRect.translated(q->horizontalOffset(), q->verticalOffset()));
624 std::sort(visibleIndexes.begin(), visibleIndexes.end());
625 for (
const auto &index : indexes) {
626 if (std::binary_search(visibleIndexes.cbegin(), visibleIndexes.cend(), index)) {
627 const QRect current = q->visualRect(index);
628 ret.append({current, index});
632 QRect clipped = rect & viewportRect;
633 rect.setLeft(clipped.left());
634 rect.setRight(clipped.right());
639
640
641void QListView::reset()
645 d->hiddenRows.clear();
646 QAbstractItemView::reset();
650
651
652void QListView::setRootIndex(
const QModelIndex &index)
655 d->column = qMax(0, qMin(d->column, d->model->columnCount(index) - 1));
656 QAbstractItemView::setRootIndex(index);
659 d->hiddenRows.clear();
663
664
665
666
668void QListView::scrollContentsBy(
int dx,
int dy)
671 d->delayedAutoScroll.stop();
672 d->commonListView->scrollContentsBy(dx, dy, d->state == QListView::DragSelectingState);
676
677
678
679
680
681void QListView::resizeContents(
int width,
int height)
684 d->setContentsSize(width, height);
688
689
690QSize QListView::contentsSize()
const
692 Q_D(
const QListView);
693 return d->contentsSize();
697
698
699void QListView::dataChanged(
const QModelIndex &topLeft,
const QModelIndex &bottomRight,
700 const QList<
int> &roles)
702 d_func()->commonListView->dataChanged(topLeft, bottomRight);
703 QAbstractItemView::dataChanged(topLeft, bottomRight, roles);
707
708
709void QListView::rowsInserted(
const QModelIndex &parent,
int start,
int end)
714 d->doDelayedItemsLayout();
715 QAbstractItemView::rowsInserted(parent, start, end);
719
720
721void QListView::rowsAboutToBeRemoved(
const QModelIndex &parent,
int start,
int end)
725 QAbstractItemView::rowsAboutToBeRemoved(parent, start, end);
726 if (parent == d->root) {
727 QSet<QPersistentModelIndex>::iterator it = d->hiddenRows.begin();
728 while (it != d->hiddenRows.end()) {
729 int hiddenRow = it->row();
730 if (hiddenRow >= start && hiddenRow <= end) {
731 it = d->hiddenRows.erase(it);
738 d->doDelayedItemsLayout();
742
743
744void QListView::mouseMoveEvent(QMouseEvent *e)
749 QAbstractItemView::mouseMoveEvent(e);
750 if (state() == DragSelectingState
751 && d->showElasticBand
752 && d->selectionMode != SingleSelection
753 && d->selectionMode != NoSelection) {
754 QRect rect(d->pressedPosition, e->position().toPoint() + QPoint(horizontalOffset(), verticalOffset()));
755 rect = rect.normalized();
756 const int margin = 2 * style()->pixelMetric(QStyle::PM_DefaultFrameWidth);
757 const QRect viewPortRect = rect.united(d->elasticBand)
758 .adjusted(-margin, -margin, margin, margin);
759 d->viewport->update(d->mapToViewport(viewPortRect));
760 d->elasticBand = rect;
765
766
767void QListView::mouseReleaseEvent(QMouseEvent *e)
770 QAbstractItemView::mouseReleaseEvent(e);
772 if (d->showElasticBand && d->elasticBand.isValid()) {
773 const int margin = 2 * style()->pixelMetric(QStyle::PM_DefaultFrameWidth);
774 const QRect viewPortRect = d->elasticBand.adjusted(-margin, -margin, margin, margin);
775 d->viewport->update(d->mapToViewport(viewPortRect));
776 d->elasticBand = QRect();
780#if QT_CONFIG(wheelevent)
782
783
784void QListView::wheelEvent(QWheelEvent *e)
787 if (qAbs(e->angleDelta().y()) > qAbs(e->angleDelta().x())) {
788 if (e->angleDelta().x() == 0
789 && ((d->flow == TopToBottom && d->wrap) || (d->flow == LeftToRight && !d->wrap))
790 && d->vbar->minimum() == 0 && d->vbar->maximum() == 0) {
791 QPoint pixelDelta(e->pixelDelta().y(), e->pixelDelta().x());
792 QPoint angleDelta(e->angleDelta().y(), e->angleDelta().x());
793 QWheelEvent hwe(e->position(), e->globalPosition(), pixelDelta, angleDelta,
794 e->buttons(), e->modifiers(), e->phase(), e->inverted(), e->source());
795 if (e->spontaneous())
796 qt_sendSpontaneousEvent(d->hbar, &hwe);
798 QCoreApplication::sendEvent(d->hbar, &hwe);
799 e->setAccepted(hwe.isAccepted());
801 QCoreApplication::sendEvent(d->vbar, e);
804 QCoreApplication::sendEvent(d->hbar, e);
810
811
812void QListView::timerEvent(QTimerEvent *e)
815 if (e->timerId() == d->batchLayoutTimer.timerId()) {
816 if (d->doItemsLayout(d->batchSize)) {
817 d->batchLayoutTimer.stop();
819 d->viewport->update();
822 QAbstractItemView::timerEvent(e);
826
827
828void QListView::resizeEvent(QResizeEvent *e)
831 if (d->delayedPendingLayout)
834 QSize delta = e->size() - e->oldSize();
839 bool listWrap = (d->viewMode == ListMode) && d->wrapItemText;
840 bool flowDimensionChanged = (d->flow == LeftToRight && delta.width() != 0)
841 || (d->flow == TopToBottom && delta.height() != 0);
847 || (state() == NoState && d->resizeMode == Adjust && flowDimensionChanged)) {
848 d->doDelayedItemsLayout(100);
850 QAbstractItemView::resizeEvent(e);
854#if QT_CONFIG(draganddrop)
857
858
859void QListView::dragMoveEvent(QDragMoveEvent *e)
862 if (!d->commonListView->filterDragMoveEvent(e)) {
863 if (viewMode() == QListView::ListMode && flow() == QListView::LeftToRight)
864 static_cast<QListModeViewBase *>(d->commonListView)->dragMoveEvent(e);
866 QAbstractItemView::dragMoveEvent(e);
872
873
874void QListView::dragLeaveEvent(QDragLeaveEvent *e)
876 if (!d_func()->commonListView->filterDragLeaveEvent(e))
877 QAbstractItemView::dragLeaveEvent(e);
881
882
883void QListView::dropEvent(QDropEvent *event)
887 const bool moveAction = event->dropAction() == Qt::MoveAction
888 || dragDropMode() == QAbstractItemView::InternalMove;
889 if (event->source() ==
this && moveAction) {
890 QModelIndex topIndex;
891 bool topIndexDropped =
false;
895 if (!event->isAccepted() && d->dropOn(event, &row, &col, &topIndex)) {
896 const QList<QModelIndex> selIndexes = selectedIndexes();
897 QList<QPersistentModelIndex> persIndexes;
898 persIndexes.reserve(selIndexes.size());
900 for (
const auto &index : selIndexes) {
901 persIndexes.append(index);
902 if (index == topIndex) {
903 topIndexDropped =
true;
908 if (!topIndexDropped && !topIndex.isValid()) {
909 std::sort(persIndexes.begin(), persIndexes.end());
911 QPersistentModelIndex dropRow = model()->index(row, col, topIndex);
913 int r = row == -1 ? model()->rowCount() : (dropRow.row() >= 0 ? dropRow.row() : row);
914 bool dataMoved =
false;
915 for (
const QPersistentModelIndex &pIndex : std::as_const(persIndexes)) {
917 if (r != pIndex.row() && r != pIndex.row() + 1) {
919 const bool moved = model()->moveRow(QModelIndex(), pIndex.row(), QModelIndex(), r);
927 r = pIndex.row() + 1;
936 if (event->isAccepted())
937 d->dropEventMoved =
true;
940 if (!d->commonListView->filterDropEvent(event) || !d->dropEventMoved) {
942 if (!d->dropEventMoved && moveAction)
944 QAbstractItemView::dropEvent(event);
949
950
951void QListView::startDrag(Qt::DropActions supportedActions)
953 if (!d_func()->commonListView->filterStartDrag(supportedActions))
954 QAbstractItemView::startDrag(supportedActions);
960
961
962void QListView::initViewItemOption(QStyleOptionViewItem *option)
const
964 Q_D(
const QListView);
965 QAbstractItemView::initViewItemOption(option);
966 if (!d->iconSize.isValid()) {
967 int pm = (d->viewMode == QListView::ListMode
968 ? style()->pixelMetric(QStyle::PM_ListViewIconSize,
nullptr,
this)
969 : style()->pixelMetric(QStyle::PM_IconViewIconSize,
nullptr,
this));
970 option->decorationSize = QSize(pm, pm);
972 if (d->viewMode == QListView::IconMode) {
973 option->showDecorationSelected =
false;
974 option->decorationPosition = QStyleOptionViewItem::Top;
975 option->displayAlignment = Qt::AlignCenter;
977 option->decorationPosition = QStyleOptionViewItem::Left;
980 if (d->gridSize().isValid()) {
981 option->rect.setSize(d->gridSize());
987
988
989void QListView::paintEvent(QPaintEvent *e)
992 if (!d->itemDelegate)
994 QStyleOptionViewItem option;
995 initViewItemOption(&option);
996 QStylePainter painter(d->viewport);
998 const QList<QModelIndex> toBeRendered =
999 d->intersectingSet(e->rect().translated(horizontalOffset(), verticalOffset()),
false);
1001 const QModelIndex current = currentIndex();
1002 const QModelIndex hover = d->hover;
1003 const QAbstractItemModel *itemModel = d->model;
1004 const QItemSelectionModel *selections = d->selectionModel;
1005 const bool focus = (hasFocus() || d->viewport->hasFocus()) && current.isValid();
1006 const bool alternate = d->alternatingColors;
1007 const QStyle::State state = option.state;
1008 const QAbstractItemView::State viewState =
this->state();
1009 const bool enabled = (state & QStyle::State_Enabled) != 0;
1011 bool alternateBase =
false;
1012 int previousRow = -2;
1014 int maxSize = (flow() == TopToBottom)
1015 ? qMax(viewport()->size().width(), d->contentsSize().width()) - 2 * d->spacing()
1016 : qMax(viewport()->size().height(), d->contentsSize().height()) - 2 * d->spacing();
1018 QList<QModelIndex>::const_iterator end = toBeRendered.constEnd();
1019 for (QList<QModelIndex>::const_iterator it = toBeRendered.constBegin(); it != end; ++it) {
1020 Q_ASSERT((*it).isValid());
1021 option.rect = visualRect(*it);
1023 if (flow() == TopToBottom)
1024 option.rect.setWidth(qMin(maxSize, option.rect.width()));
1026 option.rect.setHeight(qMin(maxSize, option.rect.height()));
1028 option.state = state;
1029 if (selections && selections->isSelected(*it))
1030 option.state |= QStyle::State_Selected;
1032 QPalette::ColorGroup cg;
1033 if ((itemModel->flags(*it) & Qt::ItemIsEnabled) == 0) {
1034 option.state &= ~QStyle::State_Enabled;
1035 cg = QPalette::Disabled;
1037 cg = QPalette::Normal;
1039 option.palette.setCurrentColorGroup(cg);
1041 if (focus && current == *it) {
1042 option.state |= QStyle::State_HasFocus;
1043 if (viewState == EditingState)
1044 option.state |= QStyle::State_Editing;
1046 option.state.setFlag(QStyle::State_MouseOver, *it == hover);
1049 int row = (*it).row();
1050 if (row != previousRow + 1) {
1052 if (!d->hiddenRows.isEmpty()) {
1053 for (
int r = qMax(previousRow + 1, 0); r < row; ++r) {
1054 if (!d->isHidden(r))
1055 alternateBase = !alternateBase;
1058 alternateBase = (row & 1) != 0;
1061 option.features.setFlag(QStyleOptionViewItem::Alternate, alternateBase);
1065 QStyle::State oldState = option.state;
1066 option.state &= ~QStyle::State_Selected;
1067 painter.drawPrimitive(QStyle::PE_PanelItemViewRow, option);
1068 option.state = oldState;
1070 alternateBase = !alternateBase;
1074 itemDelegateForIndex(*it)->paint(&painter, option, *it);
1077#if QT_CONFIG(draganddrop)
1078 d->commonListView->paintDragDrop(&painter);
1081#if QT_CONFIG(rubberband)
1083 if (d->showElasticBand && d->elasticBand.isValid()) {
1084 QStyleOptionRubberBand opt;
1086 opt.shape = QRubberBand::Rectangle;
1088 opt.rect = d->mapToViewport(d->elasticBand,
false).intersected(
1089 d->viewport->rect().adjusted(-16, -16, 16, 16));
1091 painter.drawControl(QStyle::CE_RubberBand, opt);
1098
1099
1100QModelIndex QListView::indexAt(
const QPoint &p)
const
1102 Q_D(
const QListView);
1103 QRect rect(p.x() + horizontalOffset(), p.y() + verticalOffset(), 1, 1);
1104 const QList<QModelIndex> intersectVector = d->intersectingSet(rect);
1105 QModelIndex index = intersectVector.size() > 0
1106 ? intersectVector.last() : QModelIndex();
1107 if (index.isValid() && visualRect(index).contains(p))
1109 return QModelIndex();
1113
1114
1115int QListView::horizontalOffset()
const
1117 return d_func()->commonListView->horizontalOffset();
1121
1122
1123int QListView::verticalOffset()
const
1125 return d_func()->commonListView->verticalOffset();
1129
1130
1131QModelIndex QListView::moveCursor(CursorAction cursorAction, Qt::KeyboardModifiers modifiers)
1134 Q_UNUSED(modifiers);
1136 auto findAvailableRowBackward = [d](
int row) {
1137 while (row >= 0 && d->isHiddenOrDisabled(row))
1142 auto findAvailableRowForward = [d](
int row) {
1143 int rowCount = d->model->rowCount(d->root);
1146 while (row < rowCount && d->isHiddenOrDisabled(row))
1148 if (row >= rowCount)
1153 QModelIndex current = currentIndex();
1154 if (!current.isValid()) {
1155 int row = findAvailableRowForward(0);
1157 return QModelIndex();
1158 return d->model->index(row, d->column, d->root);
1161 if ((d->flow == LeftToRight && cursorAction == MoveLeft) ||
1162 (d->flow == TopToBottom && (cursorAction == MoveUp || cursorAction == MovePrevious))) {
1163 const int row = findAvailableRowBackward(current.row() - 1);
1166 return d->model->index(row, d->column, d->root);
1167 }
else if ((d->flow == LeftToRight && cursorAction == MoveRight) ||
1168 (d->flow == TopToBottom && (cursorAction == MoveDown || cursorAction == MoveNext))) {
1169 const int row = findAvailableRowForward(current.row() + 1);
1172 return d->model->index(row, d->column, d->root);
1175 const QRect initialRect = rectForIndex(current);
1176 QRect rect = initialRect;
1177 if (rect.isEmpty()) {
1178 return d->model->index(0, d->column, d->root);
1180 if (d->gridSize().isValid()) rect.setSize(d->gridSize());
1182 QSize contents = d->contentsSize();
1183 QList<QModelIndex> intersectVector;
1185 switch (cursorAction) {
1187 while (intersectVector.isEmpty()) {
1188 rect.translate(-rect.width(), 0);
1189 if (rect.right() <= 0)
1191 if (rect.left() < 0)
1193 intersectVector = d->intersectingSet(rect);
1194 d->removeCurrentAndDisabled(&intersectVector, current);
1196 return d->closestIndex(initialRect, intersectVector);
1198 while (intersectVector.isEmpty()) {
1199 rect.translate(rect.width(), 0);
1200 if (rect.left() >= contents.width())
1202 if (rect.right() > contents.width())
1203 rect.setRight(contents.width());
1204 intersectVector = d->intersectingSet(rect);
1205 d->removeCurrentAndDisabled(&intersectVector, current);
1207 return d->closestIndex(initialRect, intersectVector);
1209 if (rect.height() >= d->viewport->height())
1210 return moveCursor(QAbstractItemView::MoveUp, modifiers);
1212 rect.moveTop(rect.top() - d->viewport->height() + 1);
1213 if (rect.top() < rect.height()) {
1217 QModelIndex findindex = current;
1218 while (intersectVector.isEmpty()
1219 || rectForIndex(findindex).top() <= (rectForIndex(current).bottom() - d->viewport->rect().height())
1220 || rect.top() <= 0) {
1221 rect.translate(0, 1);
1222 if (rect.bottom() <= 0) {
1225 intersectVector = d->intersectingSet(rect);
1226 findindex = d->closestIndex(initialRect, intersectVector);
1232 while (intersectVector.isEmpty()) {
1233 rect.translate(0, -rect.height());
1234 if (rect.bottom() <= 0) {
1235#ifdef QT_KEYPAD_NAVIGATION
1236 if (QApplicationPrivate::keypadNavigationEnabled()) {
1237 int row = d->batchStartRow() - 1;
1238 while (row >= 0 && d->isHiddenOrDisabled(row))
1241 return d->model->index(row, d->column, d->root);
1248 intersectVector = d->intersectingSet(rect);
1249 d->removeCurrentAndDisabled(&intersectVector, current);
1251 return d->closestIndex(initialRect, intersectVector);
1252 case MovePageDown: {
1253 if (rect.height() >= d->viewport->height())
1254 return moveCursor(QAbstractItemView::MoveDown, modifiers);
1256 rect.moveTop(rect.top() + d->viewport->height() - 1);
1257 if (rect.bottom() > contents.height() - rect.height()) {
1258 rect.setTop(contents.height() - 1);
1259 rect.setBottom(contents.height());
1261 QModelIndex index = current;
1263 while (intersectVector.isEmpty()
1264 || rectForIndex(index).bottom() >= (d->viewport->rect().height() + rectForIndex(current).top())
1265 || rect.bottom() > contents.height()) {
1266 rect.translate(0, -1);
1267 if (rect.top() >= contents.height()) {
1270 intersectVector = d->intersectingSet(rect);
1271 index = d->closestIndex(initialRect, intersectVector);
1277 while (intersectVector.isEmpty()) {
1278 rect.translate(0, rect.height());
1279 if (rect.top() >= contents.height()) {
1280#ifdef QT_KEYPAD_NAVIGATION
1281 if (QApplicationPrivate::keypadNavigationEnabled()) {
1282 int rowCount = d->model->rowCount(d->root);
1284 while (row < rowCount && d->isHiddenOrDisabled(row))
1287 return d->model->index(row, d->column, d->root);
1292 if (rect.bottom() > contents.height())
1293 rect.setBottom(contents.height());
1294 intersectVector = d->intersectingSet(rect);
1295 d->removeCurrentAndDisabled(&intersectVector, current);
1297 return d->closestIndex(initialRect, intersectVector);
1299 return d->model->index(0, d->column, d->root);
1301 return d->model->index(d->batchStartRow() - 1, d->column, d->root);}
1307
1308
1309
1310
1311
1312QRect QListView::rectForIndex(
const QModelIndex &index)
const
1314 return d_func()->rectForIndex(index);
1318
1319
1320
1321
1322
1323void QListView::setPositionForIndex(
const QPoint &position,
const QModelIndex &index)
1326 if (d->movement == Static
1327 || !d->isIndexValid(index)
1328 || index.parent() != d->root
1329 || index.column() != d->column)
1332 d->executePostedLayout();
1333 d->commonListView->setPositionForIndex(position, index);
1337
1338
1339void QListView::setSelection(
const QRect &rect, QItemSelectionModel::SelectionFlags command)
1342 if (!d->selectionModel)
1346 int w = qMax(d->contentsSize().width(), d->viewport->width());
1347 int h = qMax(d->contentsSize().height(), d->viewport->height());
1348 if (d->wrap && !QRect(0, 0, w, h).intersects(rect))
1351 QItemSelection selection;
1353 if (rect.width() == 1 && rect.height() == 1) {
1354 const QList<QModelIndex> intersectVector =
1355 d->intersectingSet(rect.translated(horizontalOffset(), verticalOffset()));
1357 if (!intersectVector.isEmpty())
1358 tl = intersectVector.last();
1359 if (tl.isValid() && d->isIndexEnabled(tl))
1360 selection.select(tl, tl);
1362 if (state() == DragSelectingState) {
1363 selection = d->selection(rect.translated(horizontalOffset(), verticalOffset()));
1367 const QRect topLeft(rect.left() + horizontalOffset(), rect.top() + verticalOffset(), 1, 1);
1368 QList<QModelIndex> intersectVector = d->intersectingSet(topLeft);
1369 if (!intersectVector.isEmpty())
1370 tl = intersectVector.last();
1372 const QRect bottomRight(rect.right() + horizontalOffset(), rect.bottom() + verticalOffset(), 1, 1);
1373 intersectVector = d->intersectingSet(bottomRight);
1374 if (!intersectVector.isEmpty())
1375 br = intersectVector.last();
1378 if (tl.isValid() && br.isValid()
1379 && d->isIndexEnabled(tl)
1380 && d->isIndexEnabled(br)) {
1381 QRect first = d->cellRectForIndex(tl);
1382 QRect last = d->cellRectForIndex(br);
1384 if (d->flow == LeftToRight) {
1386 QRect &bottom = last;
1388 if (top.center().y() > bottom.center().y()) {
1394 if (top.top() != bottom.top()) {
1396 if (isRightToLeft())
1399 top.setRight(contentsSize().width());
1401 if (isRightToLeft())
1402 bottom.setRight(contentsSize().width());
1405 }
else if (top.left() > bottom.right()) {
1406 if (isRightToLeft())
1407 bottom.setLeft(top.right());
1409 bottom.setRight(top.left());
1411 if (isRightToLeft())
1412 top.setLeft(bottom.right());
1414 top.setRight(bottom.left());
1417 if (top.bottom() < bottom.top()) {
1418 if (gridSize().isValid() && !gridSize().isNull())
1419 middle.setTop(top.top() + gridSize().height());
1421 middle.setTop(top.bottom() + 1);
1422 middle.setLeft(qMin(top.left(), bottom.left()));
1423 middle.setBottom(bottom.top() - 1);
1424 middle.setRight(qMax(top.right(), bottom.right()));
1427 QRect &left = first;
1428 QRect &right = last;
1429 if (left.center().x() > right.center().x())
1432 int ch = contentsSize().height();
1433 if (left.left() != right.left()) {
1435 if (isRightToLeft())
1441 if (isRightToLeft())
1442 right.setBottom(ch);
1447 middle.setBottom(ch);
1448 if (gridSize().isValid() && !gridSize().isNull())
1449 middle.setLeft(left.left() + gridSize().width());
1451 middle.setLeft(left.right() + 1);
1452 middle.setRight(right.left() - 1);
1453 }
else if (left.bottom() < right.top()) {
1454 left.setBottom(right.top() - 1);
1456 right.setBottom(left.top() - 1);
1461 QItemSelection topSelection = d->selection(first);
1462 QItemSelection middleSelection = d->selection(middle);
1463 QItemSelection bottomSelection = d->selection(last);
1465 selection.merge(topSelection, QItemSelectionModel::Select);
1466 selection.merge(middleSelection, QItemSelectionModel::Select);
1467 selection.merge(bottomSelection, QItemSelectionModel::Select);
1472 d->selectionModel->select(selection, command);
1476
1477
1478
1479
1480
1481QRegion QListView::visualRegionForSelection(
const QItemSelection &selection)
const
1483 Q_D(
const QListView);
1486 QRegion selectionRegion;
1487 const QRect &viewportRect = d->viewport->rect();
1488 for (
const auto &elem : selection) {
1489 if (!elem.isValid())
1491 QModelIndex parent = elem.topLeft().parent();
1494 if (parent != d->root)
1496 int t = elem.topLeft().row();
1497 int b = elem.bottomRight().row();
1498 if (d->viewMode == IconMode || d->isWrapping()) {
1499 for (
int r = t; r <= b; ++r) {
1500 const QRect &rect = visualRect(d->model->index(r, c, parent));
1501 if (viewportRect.intersects(rect))
1502 selectionRegion += rect;
1505 while (t <= b && d->isHidden(t)) ++t;
1506 while (b >= t && d->isHidden(b)) --b;
1507 const QModelIndex top = d->model->index(t, c, parent);
1508 const QModelIndex bottom = d->model->index(b, c, parent);
1509 QRect rect(visualRect(top).topLeft(),
1510 visualRect(bottom).bottomRight());
1511 if (viewportRect.intersects(rect))
1512 selectionRegion += rect;
1516 return selectionRegion;
1520
1521
1522QModelIndexList QListView::selectedIndexes()
const
1524 Q_D(
const QListView);
1525 if (!d->selectionModel)
1526 return QModelIndexList();
1528 QModelIndexList viewSelected = d->selectionModel->selectedIndexes();
1529 auto ignorable = [
this, d](
const QModelIndex &index) {
1530 return index.column() != d->column || index.parent() != d->root || isIndexHidden(index);
1532 viewSelected.removeIf(ignorable);
1533 return viewSelected;
1537
1538
1539
1540
1541void QListView::doItemsLayout()
1547 QAbstractItemView::State oldState = state();
1548 setState(ExpandingState);
1549 if (d->model->columnCount(d->root) > 0) {
1550 d->resetBatchStartRow();
1551 if (layoutMode() == SinglePass) {
1552 d->doItemsLayout(d->model->rowCount(d->root));
1553 }
else if (!d->batchLayoutTimer.isActive()) {
1554 if (!d->doItemsLayout(d->batchSize))
1555 d->batchLayoutTimer.start(0,
this);
1560 QAbstractItemView::doItemsLayout();
1565
1566
1567void QListView::updateGeometries()
1570 if (geometry().isEmpty() || d->model->rowCount(d->root) <= 0 || d->model->columnCount(d->root) <= 0) {
1571 horizontalScrollBar()->setRange(0, 0);
1572 verticalScrollBar()->setRange(0, 0);
1574 QModelIndex index = d->model->index(0, d->column, d->root);
1575 QStyleOptionViewItem option;
1576 initViewItemOption(&option);
1577 QSize step = d->itemSize(option, index);
1578 d->commonListView->updateHorizontalScrollBar(step);
1579 d->commonListView->updateVerticalScrollBar(step);
1582 QAbstractItemView::updateGeometries();
1585 if (d->movement == Static && !d->isWrapping()) {
1586 d->layoutChildren();
1587 if (d->flow == TopToBottom) {
1588 if (horizontalScrollBarPolicy() == Qt::ScrollBarAlwaysOff) {
1589 d->setContentsSize(viewport()->width(), contentsSize().height());
1590 horizontalScrollBar()->setRange(0, 0);
1593 if (verticalScrollBarPolicy() == Qt::ScrollBarAlwaysOff) {
1594 d->setContentsSize(contentsSize().width(), viewport()->height());
1595 verticalScrollBar()->setRange(0, 0);
1603
1604
1605bool QListView::isIndexHidden(
const QModelIndex &index)
const
1607 Q_D(
const QListView);
1608 return (d->isHidden(index.row())
1609 && (index.parent() == d->root)
1610 && index.column() == d->column);
1614
1615
1616
1617
1618
1619
1620void QListView::setModelColumn(
int column)
1623 if (column < 0 || column >= d->model->columnCount(d->root))
1626 d->doDelayedItemsLayout();
1627#if QT_CONFIG(accessibility)
1628 if (QAccessible::isActive()) {
1629 QAccessibleTableModelChangeEvent event(
this, QAccessibleTableModelChangeEvent::ModelReset);
1630 QAccessible::updateAccessibility(&event);
1635int QListView::modelColumn()
const
1637 Q_D(
const QListView);
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651void QListView::setUniformItemSizes(
bool enable)
1654 d->uniformItemSizes = enable;
1657bool QListView::uniformItemSizes()
const
1659 Q_D(
const QListView);
1660 return d->uniformItemSizes;
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676void QListView::setWordWrap(
bool on)
1679 if (d->wrapItemText == on)
1681 d->wrapItemText = on;
1682 d->doDelayedItemsLayout();
1685bool QListView::wordWrap()
const
1687 Q_D(
const QListView);
1688 return d->wrapItemText;
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705void QListView::setSelectionRectVisible(
bool show)
1708 d->modeProperties |= uint(QListViewPrivate::SelectionRectVisible);
1709 d->setSelectionRectVisible(show);
1712bool QListView::isSelectionRectVisible()
const
1714 Q_D(
const QListView);
1715 return d->isSelectionRectVisible();
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728void QListView::setItemAlignment(Qt::Alignment alignment)
1731 if (d->itemAlignment == alignment)
1733 d->itemAlignment = alignment;
1734 if (viewMode() == ListMode && flow() == QListView::TopToBottom && isWrapping())
1735 d->doDelayedItemsLayout();
1738Qt::Alignment QListView::itemAlignment()
const
1740 Q_D(
const QListView);
1741 return d->itemAlignment;
1745
1746
1747bool QListView::event(QEvent *e)
1749 return QAbstractItemView::event(e);
1753
1754
1756QListViewPrivate::QListViewPrivate()
1757 : QAbstractItemViewPrivate(),
1758 commonListView(
nullptr),
1761 flow(QListView::TopToBottom),
1762 movement(QListView::Static),
1763 resizeMode(QListView::Fixed),
1764 layoutMode(QListView::SinglePass),
1765 viewMode(QListView::ListMode),
1768 uniformItemSizes(
false),
1770 showElasticBand(
false),
1771 itemAlignment(Qt::Alignment())
1775QListViewPrivate::~QListViewPrivate()
1777 delete commonListView;
1780void QListViewPrivate::clear()
1783 cachedItemSize = QSize();
1784 commonListView->clear();
1787void QListViewPrivate::prepareItemsLayout()
1793 layoutBounds = QRect(QPoint(), q->maximumViewportSize());
1795 int frameAroundContents = 0;
1796 if (q->style()->styleHint(QStyle::SH_ScrollView_FrameOnlyAroundContents,
nullptr, q)) {
1797 QStyleOption option;
1799 frameAroundContents = q->style()->pixelMetric(QStyle::PM_DefaultFrameWidth, &option, q) * 2;
1805 int verticalMargin = (vbarpolicy == Qt::ScrollBarAsNeeded) && (flow == QListView::LeftToRight || vbar->isVisible())
1806 && !q->style()->pixelMetric(QStyle::PM_ScrollView_ScrollBarOverlap,
nullptr, vbar)
1807 ? q->style()->pixelMetric(QStyle::PM_ScrollBarExtent,
nullptr, vbar) + frameAroundContents
1809 int horizontalMargin = hbarpolicy==Qt::ScrollBarAsNeeded
1810 ? q->style()->pixelMetric(QStyle::PM_ScrollBarExtent,
nullptr, hbar) + frameAroundContents
1813 layoutBounds.adjust(0, 0, -verticalMargin, -horizontalMargin);
1815 int rowCount = model->columnCount(root) <= 0 ? 0 : model->rowCount(root);
1816 commonListView->setRowCount(rowCount);
1820
1821
1822bool QListViewPrivate::doItemsLayout(
int delta)
1824 int max = model->rowCount(root) - 1;
1825 int first = batchStartRow();
1826 int last = qMin(first + delta - 1, max);
1830 prepareItemsLayout();
1833 if (max < 0 || last < first) {
1837 QListViewLayoutInfo info;
1838 info.bounds = layoutBounds;
1839 info.grid = gridSize();
1840 info.spacing = (info.grid.isValid() ? 0 : spacing());
1843 info.wrap = isWrapping();
1847 return commonListView->doBatchedItemLayout(info, max);
1850QListViewItem QListViewPrivate::indexToListViewItem(
const QModelIndex &index)
const
1852 if (!index.isValid() || isHidden(index.row()))
1853 return QListViewItem();
1855 return commonListView->indexToListViewItem(index);
1858QRect QListViewPrivate::mapToViewport(
const QRect &rect,
bool extend)
const
1860 Q_Q(
const QListView);
1861 if (!rect.isValid())
1864 QRect result = extend ? commonListView->mapToViewport(rect) : rect;
1865 int dx = -q->horizontalOffset();
1866 int dy = -q->verticalOffset();
1867 return result.adjusted(dx, dy, dx, dy);
1870QModelIndex QListViewPrivate::closestIndex(
const QRect &target,
1871 const QList<QModelIndex> &candidates)
const
1874 int shortest = INT_MAX;
1875 QModelIndex closest;
1876 QList<QModelIndex>::const_iterator it = candidates.begin();
1878 for (; it != candidates.end(); ++it) {
1879 if (!(*it).isValid())
1882 const QRect indexRect = indexToListViewItem(*it).rect();
1887 if ((target.center().x() >= indexRect.x() && target.center().x() < indexRect.right())
1888 || (indexRect.center().x() >= target.x() && indexRect.center().x() < target.right())) {
1890 distance = qAbs(indexRect.center().y() - target.center().y());
1891 }
else if ((target.center().y() >= indexRect.y() && target.center().y() < indexRect.bottom())
1892 || (indexRect.center().y() >= target.y() && indexRect.center().y() < target.bottom())) {
1894 distance = qAbs(indexRect.center().x() - target.center().x());
1896 distance = (indexRect.center() - target.center()).manhattanLength();
1898 if (distance < shortest) {
1899 shortest = distance;
1906QSize QListViewPrivate::itemSize(
const QStyleOptionViewItem &option,
const QModelIndex &index)
const
1908 Q_Q(
const QListView);
1909 if (!uniformItemSizes) {
1910 const QAbstractItemDelegate *delegate = q->itemDelegateForIndex(index);
1911 return delegate ? delegate->sizeHint(option, index) : QSize();
1913 if (!cachedItemSize.isValid()) {
1914 int row = model->rowCount(root) - 1;
1915 QModelIndex sample = model->index(row, column, root);
1916 const QAbstractItemDelegate *delegate = q->itemDelegateForIndex(sample);
1917 cachedItemSize = delegate ? delegate->sizeHint(option, sample) : QSize();
1919 return cachedItemSize;
1922QItemSelection QListViewPrivate::selection(
const QRect &rect)
const
1924 QItemSelection selection;
1926 const QList<QModelIndex> intersectVector = intersectingSet(rect);
1927 QList<QModelIndex>::const_iterator it = intersectVector.begin();
1928 for (; it != intersectVector.end(); ++it) {
1929 if (!tl.isValid() && !br.isValid()) {
1931 }
else if ((*it).row() == (tl.row() - 1)) {
1933 }
else if ((*it).row() == (br.row() + 1)) {
1936 selection.select(tl, br);
1941 if (tl.isValid() && br.isValid())
1942 selection.select(tl, br);
1943 else if (tl.isValid())
1944 selection.select(tl, tl);
1945 else if (br.isValid())
1946 selection.select(br, br);
1951#if QT_CONFIG(draganddrop)
1952QAbstractItemView::DropIndicatorPosition QListViewPrivate::position(
const QPoint &pos,
const QRect &rect,
const QModelIndex &idx)
const
1954 if (viewMode == QListView::ListMode && flow == QListView::LeftToRight)
1955 return static_cast<QListModeViewBase *>(commonListView)->position(pos, rect, idx);
1957 return QAbstractItemViewPrivate::position(pos, rect, idx);
1960bool QListViewPrivate::dropOn(QDropEvent *event,
int *dropRow,
int *dropCol, QModelIndex *dropIndex)
1962 if (viewMode == QListView::ListMode && flow == QListView::LeftToRight)
1963 return static_cast<QListModeViewBase *>(commonListView)->dropOn(event, dropRow, dropCol, dropIndex);
1965 return QAbstractItemViewPrivate::dropOn(event, dropRow, dropCol, dropIndex);
1969void QListViewPrivate::removeCurrentAndDisabled(QList<QModelIndex> *indexes,
1970 const QModelIndex ¤t)
const
1972 auto isCurrentOrDisabled = [
this, current](
const QModelIndex &index) {
1973 return !isIndexEnabled(index) || index == current;
1975 indexes->removeIf(isCurrentOrDisabled);
1979
1980
1982void QCommonListViewBase::appendHiddenRow(
int row)
1984 dd->hiddenRows.insert(dd->model->index(row, 0, qq->rootIndex()));
1987void QCommonListViewBase::removeHiddenRow(
int row)
1989 dd->hiddenRows.remove(dd->model->index(row, 0, qq->rootIndex()));
1992#if QT_CONFIG(draganddrop)
1993void QCommonListViewBase::paintDragDrop(QPainter *painter)
1997 dd->paintDropIndicator(painter);
2001QSize QListModeViewBase::viewportSize(
const QAbstractItemView *v)
2003 return v->contentsRect().marginsRemoved(v->viewportMargins()).size();
2006void QCommonListViewBase::updateHorizontalScrollBar(
const QSize &step)
2008 horizontalScrollBar()->d_func()->itemviewChangeSingleStep(step.width() + spacing());
2009 horizontalScrollBar()->setPageStep(viewport()->width());
2015 const bool bothScrollBarsAuto = qq->verticalScrollBarPolicy() == Qt::ScrollBarAsNeeded &&
2016 qq->horizontalScrollBarPolicy() == Qt::ScrollBarAsNeeded;
2018 const QSize viewportSize = QListModeViewBase::viewportSize(qq);
2020 bool verticalWantsToShow = contentsSize.height() > viewportSize.height();
2021 bool horizontalWantsToShow;
2022 if (verticalWantsToShow)
2023 horizontalWantsToShow = contentsSize.width() > viewportSize.width() - qq->verticalScrollBar()->width();
2025 horizontalWantsToShow = contentsSize.width() > viewportSize.width();
2027 if (bothScrollBarsAuto && !horizontalWantsToShow) {
2030 horizontalScrollBar()->setRange(0, 0);
2032 horizontalScrollBar()->setRange(0, contentsSize.width() - viewport()->width());
2036void QCommonListViewBase::updateVerticalScrollBar(
const QSize &step)
2038 verticalScrollBar()->d_func()->itemviewChangeSingleStep(step.height() + spacing());
2039 verticalScrollBar()->setPageStep(viewport()->height());
2045 const bool bothScrollBarsAuto = qq->verticalScrollBarPolicy() == Qt::ScrollBarAsNeeded &&
2046 qq->horizontalScrollBarPolicy() == Qt::ScrollBarAsNeeded;
2048 const QSize viewportSize = QListModeViewBase::viewportSize(qq);
2050 bool horizontalWantsToShow = contentsSize.width() > viewportSize.width();
2051 bool verticalWantsToShow;
2052 if (horizontalWantsToShow)
2053 verticalWantsToShow = contentsSize.height() > viewportSize.height() - qq->horizontalScrollBar()->height();
2055 verticalWantsToShow = contentsSize.height() > viewportSize.height();
2057 if (bothScrollBarsAuto && !verticalWantsToShow) {
2060 verticalScrollBar()->setRange(0, 0);
2062 verticalScrollBar()->setRange(0, contentsSize.height() - viewport()->height());
2066void QCommonListViewBase::scrollContentsBy(
int dx,
int dy,
bool )
2068 dd->scrollContentsBy(isRightToLeft() ? -dx : dx, dy);
2071int QCommonListViewBase::verticalScrollToValue(
int , QListView::ScrollHint hint,
2072 bool above,
bool below,
const QRect &area,
const QRect &rect)
const
2074 int verticalValue = verticalScrollBar()->value();
2075 QRect adjusted = rect.adjusted(-spacing(), -spacing(), spacing(), spacing());
2076 if (hint == QListView::PositionAtTop || above)
2077 verticalValue += adjusted.top();
2078 else if (hint == QListView::PositionAtBottom || below)
2079 verticalValue += qMin(adjusted.top(), adjusted.bottom() - area.height() + 1);
2080 else if (hint == QListView::PositionAtCenter)
2081 verticalValue += adjusted.top() - ((area.height() - adjusted.height()) / 2);
2082 return verticalValue;
2085int QCommonListViewBase::horizontalOffset()
const
2087 return (isRightToLeft() ? horizontalScrollBar()->maximum() - horizontalScrollBar()->value() : horizontalScrollBar()->value());
2090int QCommonListViewBase::horizontalScrollToValue(
const int , QListView::ScrollHint hint,
2091 bool leftOf,
bool rightOf,
const QRect &area,
const QRect &rect)
const
2093 int horizontalValue = horizontalScrollBar()->value();
2094 if (isRightToLeft()) {
2095 if (hint == QListView::PositionAtCenter) {
2096 horizontalValue += ((area.width() - rect.width()) / 2) - rect.left();
2099 horizontalValue -= rect.left();
2101 horizontalValue += qMin(rect.left(), area.width() - rect.right());
2104 if (hint == QListView::PositionAtCenter) {
2105 horizontalValue += rect.left() - ((area.width()- rect.width()) / 2);
2108 horizontalValue += rect.left();
2110 horizontalValue += qMin(rect.left(), rect.right() - area.width());
2113 return horizontalValue;
2117
2118
2119QListModeViewBase::QListModeViewBase(QListView *q, QListViewPrivate *d)
2120 : QCommonListViewBase(q, d)
2122#if QT_CONFIG(draganddrop)
2123 dd->defaultDropAction = Qt::CopyAction;
2127#if QT_CONFIG(draganddrop)
2128QAbstractItemView::DropIndicatorPosition QListModeViewBase::position(
const QPoint &pos,
const QRect &rect,
const QModelIndex &index)
const
2130 QAbstractItemView::DropIndicatorPosition r = QAbstractItemView::OnViewport;
2131 if (!dd->overwrite) {
2132 const int margin = 2;
2133 if (pos.x() - rect.left() < margin) {
2134 r = QAbstractItemView::AboveItem;
2135 }
else if (rect.right() - pos.x() < margin) {
2136 r = QAbstractItemView::BelowItem;
2137 }
else if (rect.contains(pos,
true)) {
2138 r = QAbstractItemView::OnItem;
2141 QRect touchingRect = rect;
2142 touchingRect.adjust(-1, -1, 1, 1);
2143 if (touchingRect.contains(pos,
false)) {
2144 r = QAbstractItemView::OnItem;
2148 if (r == QAbstractItemView::OnItem && (!(dd->model->flags(index) & Qt::ItemIsDropEnabled)))
2149 r = pos.x() < rect.center().x() ? QAbstractItemView::AboveItem : QAbstractItemView::BelowItem;
2154void QListModeViewBase::dragMoveEvent(QDragMoveEvent *event)
2156 if (qq->dragDropMode() == QAbstractItemView::InternalMove
2157 && (event->source() != qq || !(event->possibleActions() & Qt::MoveAction)))
2164 QPoint p = event->position().toPoint();
2165 QRect rect(p.x() + horizontalOffset(), p.y() + verticalOffset(), 1, 1);
2166 rect.adjust(-dd->spacing(), -dd->spacing(), dd->spacing(), dd->spacing());
2167 const QList<QModelIndex> intersectVector = dd->intersectingSet(rect);
2168 QModelIndex index = intersectVector.size() > 0
2169 ? intersectVector.last() : QModelIndex();
2171 if (!dd->droppingOnItself(event, index)
2172 && dd->canDrop(event)) {
2174 if (index.isValid() && dd->showDropIndicator) {
2175 QRect rect = qq->visualRect(index);
2176 dd->dropIndicatorPosition = position(event->position().toPoint(), rect, index);
2178 switch (dd->dropIndicatorPosition) {
2179 case QAbstractItemView::AboveItem:
2180 if (dd->isIndexDropEnabled(index.parent())) {
2181 dd->dropIndicatorRect = QRect(rect.left()-dd->spacing(), rect.top(), 0, rect.height());
2184 dd->dropIndicatorRect = QRect();
2187 case QAbstractItemView::BelowItem:
2188 if (dd->isIndexDropEnabled(index.parent())) {
2189 dd->dropIndicatorRect = QRect(rect.right()+dd->spacing(), rect.top(), 0, rect.height());
2192 dd->dropIndicatorRect = QRect();
2195 case QAbstractItemView::OnItem:
2196 if (dd->isIndexDropEnabled(index)) {
2197 dd->dropIndicatorRect = rect;
2200 dd->dropIndicatorRect = QRect();
2203 case QAbstractItemView::OnViewport:
2204 dd->dropIndicatorRect = QRect();
2205 if (dd->isIndexDropEnabled(qq->rootIndex())) {
2211 dd->dropIndicatorRect = QRect();
2212 dd->dropIndicatorPosition = QAbstractItemView::OnViewport;
2213 if (dd->isIndexDropEnabled(qq->rootIndex())) {
2217 dd->viewport->update();
2220 if (dd->shouldAutoScroll(event->position().toPoint()))
2221 qq->startAutoScroll();
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235bool QListModeViewBase::dropOn(QDropEvent *event,
int *dropRow,
int *dropCol, QModelIndex *dropIndex)
2237 if (event->isAccepted())
2241 if (dd->viewport->rect().contains(event->position().toPoint())) {
2243 QPoint p = event->position().toPoint();
2244 QRect rect(p.x() + horizontalOffset(), p.y() + verticalOffset(), 1, 1);
2245 rect.adjust(-dd->spacing(), -dd->spacing(), dd->spacing(), dd->spacing());
2246 const QList<QModelIndex> intersectVector = dd->intersectingSet(rect);
2247 index = intersectVector.size() > 0
2248 ? intersectVector.last() : QModelIndex();
2249 if (!index.isValid())
2254 if (dd->model->supportedDropActions() & event->dropAction()) {
2257 if (index != dd->root) {
2258 dd->dropIndicatorPosition = position(event->position().toPoint(), qq->visualRect(index), index);
2259 switch (dd->dropIndicatorPosition) {
2260 case QAbstractItemView::AboveItem:
2262 col = index.column();
2263 index = index.parent();
2265 case QAbstractItemView::BelowItem:
2266 row = index.row() + 1;
2267 col = index.column();
2268 index = index.parent();
2270 case QAbstractItemView::OnItem:
2271 case QAbstractItemView::OnViewport:
2275 dd->dropIndicatorPosition = QAbstractItemView::OnViewport;
2280 if (!dd->droppingOnItself(event, index))
2288void QListModeViewBase::updateVerticalScrollBar(
const QSize &step)
2290 if (verticalScrollMode() == QAbstractItemView::ScrollPerItem
2291 && ((flow() == QListView::TopToBottom && !isWrapping())
2292 || (flow() == QListView::LeftToRight && isWrapping()))) {
2293 const int steps = (flow() == QListView::TopToBottom ? scrollValueMap : segmentPositions).size() - 1;
2295 const int pageSteps = perItemScrollingPageSteps(viewport()->height(), contentsSize.height(), isWrapping());
2296 verticalScrollBar()->setSingleStep(1);
2297 verticalScrollBar()->setPageStep(pageSteps);
2298 verticalScrollBar()->setRange(0, steps - pageSteps);
2300 verticalScrollBar()->setRange(0, 0);
2305 QCommonListViewBase::updateVerticalScrollBar(step);
2309void QListModeViewBase::updateHorizontalScrollBar(
const QSize &step)
2311 if (horizontalScrollMode() == QAbstractItemView::ScrollPerItem
2312 && ((flow() == QListView::TopToBottom && isWrapping())
2313 || (flow() == QListView::LeftToRight && !isWrapping()))) {
2314 int steps = (flow() == QListView::TopToBottom ? segmentPositions : scrollValueMap).size() - 1;
2316 const int pageSteps = perItemScrollingPageSteps(viewport()->width(), contentsSize.width(), isWrapping());
2317 horizontalScrollBar()->setSingleStep(1);
2318 horizontalScrollBar()->setPageStep(pageSteps);
2319 horizontalScrollBar()->setRange(0, steps - pageSteps);
2321 horizontalScrollBar()->setRange(0, 0);
2324 QCommonListViewBase::updateHorizontalScrollBar(step);
2328int QListModeViewBase::verticalScrollToValue(
int index, QListView::ScrollHint hint,
2329 bool above,
bool below,
const QRect &area,
const QRect &rect)
const
2331 if (verticalScrollMode() == QAbstractItemView::ScrollPerItem) {
2333 if (scrollValueMap.isEmpty()) {
2336 int scrollBarValue = verticalScrollBar()->value();
2338 for (
const auto &idx : std::as_const(dd->hiddenRows))
2339 if (idx.row() <= scrollBarValue)
2341 value = qBound(0, scrollValueMap.at(verticalScrollBar()->value()) - numHidden, flowPositions.size() - 1);
2344 hint = QListView::PositionAtTop;
2346 hint = QListView::PositionAtBottom;
2347 if (hint == QListView::EnsureVisible)
2350 return perItemScrollToValue(index, value, area.height(), hint, Qt::Vertical, isWrapping(), rect.height());
2353 return QCommonListViewBase::verticalScrollToValue(index, hint, above, below, area, rect);
2356int QListModeViewBase::horizontalOffset()
const
2358 if (horizontalScrollMode() == QAbstractItemView::ScrollPerItem) {
2360 if (flow() == QListView::TopToBottom && !segmentPositions.isEmpty()) {
2361 const int max = segmentPositions.size() - 1;
2362 int currentValue = qBound(0, horizontalScrollBar()->value(), max);
2363 int position = segmentPositions.at(currentValue);
2364 int maximumValue = qBound(0, horizontalScrollBar()->maximum(), max);
2365 int maximum = segmentPositions.at(maximumValue);
2366 return (isRightToLeft() ? maximum - position : position);
2368 }
else if (flow() == QListView::LeftToRight && !flowPositions.isEmpty()) {
2369 int position = flowPositions.at(scrollValueMap.at(horizontalScrollBar()->value()));
2370 int maximum = flowPositions.at(scrollValueMap.at(horizontalScrollBar()->maximum()));
2371 return (isRightToLeft() ? maximum - position : position);
2374 return QCommonListViewBase::horizontalOffset();
2377int QListModeViewBase::verticalOffset()
const
2379 if (verticalScrollMode() == QAbstractItemView::ScrollPerItem) {
2381 if (flow() == QListView::LeftToRight && !segmentPositions.isEmpty()) {
2382 int value = verticalScrollBar()->value();
2383 if (value >= segmentPositions.size())
2385 return segmentPositions.at(value) - spacing();
2387 }
else if (flow() == QListView::TopToBottom && !flowPositions.isEmpty()) {
2388 int value = verticalScrollBar()->value();
2389 if (value > scrollValueMap.size())
2391 return flowPositions.at(scrollValueMap.at(value)) - spacing();
2394 return QCommonListViewBase::verticalOffset();
2397int QListModeViewBase::horizontalScrollToValue(
int index, QListView::ScrollHint hint,
2398 bool leftOf,
bool rightOf,
const QRect &area,
const QRect &rect)
const
2400 if (horizontalScrollMode() != QAbstractItemView::ScrollPerItem)
2401 return QCommonListViewBase::horizontalScrollToValue(index, hint, leftOf, rightOf, area, rect);
2404 if (scrollValueMap.isEmpty())
2407 value = qBound(0, scrollValueMap.at(horizontalScrollBar()->value()), flowPositions.size() - 1);
2409 hint = QListView::PositionAtTop;
2411 hint = QListView::PositionAtBottom;
2412 if (hint == QListView::EnsureVisible)
2415 return perItemScrollToValue(index, value, area.width(), hint, Qt::Horizontal, isWrapping(), rect.width());
2418void QListModeViewBase::scrollContentsBy(
int dx,
int dy,
bool scrollElasticBand)
2421 const int verticalValue = verticalScrollBar()->value();
2422 const int horizontalValue = horizontalScrollBar()->value();
2423 const bool vertical = (verticalScrollMode() == QAbstractItemView::ScrollPerItem);
2424 const bool horizontal = (horizontalScrollMode() == QAbstractItemView::ScrollPerItem);
2427 if (segmentPositions.isEmpty())
2429 const int max = segmentPositions.size() - 1;
2430 if (horizontal && flow() == QListView::TopToBottom && dx != 0) {
2431 int currentValue = qBound(0, horizontalValue, max);
2432 int previousValue = qBound(0, currentValue + dx, max);
2433 int currentCoordinate = segmentPositions.at(currentValue) - spacing();
2434 int previousCoordinate = segmentPositions.at(previousValue) - spacing();
2435 dx = previousCoordinate - currentCoordinate;
2436 }
else if (vertical && flow() == QListView::LeftToRight && dy != 0) {
2437 int currentValue = qBound(0, verticalValue, max);
2438 int previousValue = qBound(0, currentValue + dy, max);
2439 int currentCoordinate = segmentPositions.at(currentValue) - spacing();
2440 int previousCoordinate = segmentPositions.at(previousValue) - spacing();
2441 dy = previousCoordinate - currentCoordinate;
2444 if (flowPositions.isEmpty())
2446 const int max = scrollValueMap.size() - 1;
2447 if (vertical && flow() == QListView::TopToBottom && dy != 0) {
2448 int currentValue = qBound(0, verticalValue, max);
2449 int previousValue = qBound(0, currentValue + dy, max);
2450 int currentCoordinate = flowPositions.at(scrollValueMap.at(currentValue));
2451 int previousCoordinate = flowPositions.at(scrollValueMap.at(previousValue));
2452 dy = previousCoordinate - currentCoordinate;
2453 }
else if (horizontal && flow() == QListView::LeftToRight && dx != 0) {
2454 int currentValue = qBound(0, horizontalValue, max);
2455 int previousValue = qBound(0, currentValue + dx, max);
2456 int currentCoordinate = flowPositions.at(scrollValueMap.at(currentValue));
2457 int previousCoordinate = flowPositions.at(scrollValueMap.at(previousValue));
2458 dx = previousCoordinate - currentCoordinate;
2461 QCommonListViewBase::scrollContentsBy(dx, dy, scrollElasticBand);
2464bool QListModeViewBase::doBatchedItemLayout(
const QListViewLayoutInfo &info,
int max)
2466 doStaticLayout(info);
2467 return batchStartRow > max;
2470QListViewItem QListModeViewBase::indexToListViewItem(
const QModelIndex &index)
const
2472 if (flowPositions.isEmpty()
2473 || segmentPositions.isEmpty()
2474 || index.row() >= flowPositions.size() - 1)
2475 return QListViewItem();
2477 const int segment = qBinarySearch<
int>(segmentStartRows, index.row(),
2478 0, segmentStartRows.size() - 1);
2481 QStyleOptionViewItem options;
2482 initViewItemOption(&options);
2483 options.rect.setSize(contentsSize);
2484 QSize size = (uniformItemSizes() && cachedItemSize().isValid())
2485 ? cachedItemSize() : itemSize(options, index);
2486 QSize cellSize = size;
2489 if (flow() == QListView::LeftToRight) {
2490 pos.setX(flowPositions.at(index.row()));
2491 pos.setY(segmentPositions.at(segment));
2493 pos.setY(flowPositions.at(index.row()));
2494 pos.setX(segmentPositions.at(segment));
2496 int right = (segment + 1 >= segmentPositions.size()
2497 ? contentsSize.width()
2498 : segmentPositions.at(segment + 1));
2499 cellSize.setWidth(right - pos.x());
2501 cellSize.setWidth(qMax(size.width(), viewport()->width() - 2 * spacing()));
2505 if (dd->itemAlignment & Qt::AlignHorizontal_Mask) {
2506 size.setWidth(qMin(size.width(), cellSize.width()));
2507 if (dd->itemAlignment & Qt::AlignRight)
2508 pos.setX(pos.x() + cellSize.width() - size.width());
2509 if (dd->itemAlignment & Qt::AlignHCenter)
2510 pos.setX(pos.x() + (cellSize.width() - size.width()) / 2);
2512 size.setWidth(cellSize.width());
2515 return QListViewItem(QRect(pos, size), index.row());
2518QPoint QListModeViewBase::initStaticLayout(
const QListViewLayoutInfo &info)
2521 if (info.first == 0) {
2522 flowPositions.clear();
2523 segmentPositions.clear();
2524 segmentStartRows.clear();
2525 segmentExtents.clear();
2526 scrollValueMap.clear();
2527 x = info.bounds.left() + info.spacing;
2528 y = info.bounds.top() + info.spacing;
2529 segmentPositions.append(info.flow == QListView::LeftToRight ? y : x);
2530 segmentStartRows.append(0);
2531 }
else if (info.wrap) {
2532 if (info.flow == QListView::LeftToRight) {
2533 x = batchSavedPosition;
2534 y = segmentPositions.constLast();
2536 x = segmentPositions.constLast();
2537 y = batchSavedPosition;
2540 if (info.flow == QListView::LeftToRight) {
2541 x = batchSavedPosition;
2542 y = info.bounds.top() + info.spacing;
2544 x = info.bounds.left() + info.spacing;
2545 y = batchSavedPosition;
2548 return QPoint(x, y);
2552
2553
2554void QListModeViewBase::doStaticLayout(
const QListViewLayoutInfo &info)
2556 const bool useItemSize = !info.grid.isValid();
2557 const QPoint topLeft = initStaticLayout(info);
2558 QStyleOptionViewItem option;
2559 initViewItemOption(&option);
2560 option.rect = info.bounds;
2561 option.rect.adjust(info.spacing, info.spacing, -info.spacing, -info.spacing);
2569 int segStartPosition;
2571 int deltaFlowPosition;
2572 int deltaSegPosition;
2577 if (info.flow == QListView::LeftToRight) {
2578 segStartPosition = info.bounds.left();
2579 segEndPosition = info.bounds.width();
2580 flowPosition = topLeft.x();
2581 segPosition = topLeft.y();
2582 deltaFlowPosition = info.grid.width();
2583 deltaSegPosition = useItemSize ? batchSavedDeltaSeg : info.grid.height();
2584 deltaSegHint = info.grid.height();
2586 segStartPosition = info.bounds.top();
2587 segEndPosition = info.bounds.height();
2588 flowPosition = topLeft.y();
2589 segPosition = topLeft.x();
2590 deltaFlowPosition = info.grid.height();
2591 deltaSegPosition = useItemSize ? batchSavedDeltaSeg : info.grid.width();
2592 deltaSegHint = info.grid.width();
2595 for (
int row = info.first; row <= info.last; ++row) {
2596 if (isHidden(row)) {
2597 flowPositions.append(flowPosition);
2601 QSize hint = itemSize(option, modelIndex(row));
2602 if (info.flow == QListView::LeftToRight) {
2603 deltaFlowPosition = hint.width() + info.spacing;
2604 deltaSegHint = hint.height() + info.spacing;
2606 deltaFlowPosition = hint.height() + info.spacing;
2607 deltaSegHint = hint.width() + info.spacing;
2611 if (info.wrap && (flowPosition + deltaFlowPosition >= segEndPosition)) {
2612 segmentExtents.append(flowPosition);
2613 flowPosition = info.spacing + segStartPosition;
2614 segPosition += info.spacing + deltaSegPosition;
2615 segmentPositions.append(segPosition);
2616 segmentStartRows.append(row);
2617 deltaSegPosition = 0;
2620 scrollValueMap.append(flowPositions.size());
2621 flowPositions.append(flowPosition);
2623 deltaSegPosition = qMax(deltaSegHint, deltaSegPosition);
2624 flowPosition += info.spacing + deltaFlowPosition;
2628 batchSavedPosition = flowPosition;
2629 batchSavedDeltaSeg = deltaSegPosition;
2630 batchStartRow = info.last + 1;
2631 if (info.last == info.max)
2632 flowPosition -= info.spacing;
2634 QRect rect = info.bounds;
2635 if (info.flow == QListView::LeftToRight) {
2636 rect.setRight(segmentPositions.size() == 1 ? flowPosition : info.bounds.right());
2637 rect.setBottom(segPosition + deltaSegPosition);
2639 rect.setRight(segPosition + deltaSegPosition);
2640 rect.setBottom(segmentPositions.size() == 1 ? flowPosition : info.bounds.bottom());
2642 contentsSize = QSize(rect.right(), rect.bottom());
2644 if (info.last == info.max) {
2645 segmentExtents.append(flowPosition);
2646 scrollValueMap.append(flowPositions.size());
2647 flowPositions.append(flowPosition);
2648 segmentPositions.append(info.wrap ? segPosition + deltaSegPosition : INT_MAX);
2651 QRect changedRect(topLeft, rect.bottomRight());
2652 if (clipRect().intersects(changedRect))
2653 viewport()->update();
2657
2658
2659
2660
2661QList<QModelIndex> QListModeViewBase::intersectingSet(
const QRect &area)
const
2663 QList<QModelIndex> ret;
2664 int segStartPosition;
2666 int flowStartPosition;
2667 int flowEndPosition;
2668 if (flow() == QListView::LeftToRight) {
2669 segStartPosition = area.top();
2670 segEndPosition = area.bottom();
2671 flowStartPosition = area.left();
2672 flowEndPosition = area.right();
2674 segStartPosition = area.left();
2675 segEndPosition = area.right();
2676 flowStartPosition = area.top();
2677 flowEndPosition = area.bottom();
2679 if (segmentPositions.size() < 2 || flowPositions.isEmpty())
2682 const int segLast = segmentPositions.size() - 2;
2683 int seg = qBinarySearch<
int>(segmentPositions, segStartPosition, 0, segLast + 1);
2684 for (; seg <= segLast && segmentPositions.at(seg) <= segEndPosition; ++seg) {
2685 int first = segmentStartRows.at(seg);
2686 int last = (seg < segLast ? segmentStartRows.at(seg + 1) : batchStartRow) - 1;
2687 if (segmentExtents.at(seg) < flowStartPosition)
2689 int row = qBinarySearch<
int>(flowPositions, flowStartPosition, first, last);
2690 for (; row <= last && flowPositions.at(row) <= flowEndPosition; ++row) {
2693 QModelIndex index = modelIndex(row);
2694 if (index.isValid()) {
2695 if (flow() == QListView::LeftToRight || dd->itemAlignment == Qt::Alignment()) {
2698 const auto viewItem = indexToListViewItem(index);
2699 const int iw = viewItem.width();
2700 const int startPos = qMax(segStartPosition, segmentPositions.at(seg));
2701 const int endPos = qMin(segmentPositions.at(seg + 1), segEndPosition);
2702 if (endPos >= viewItem.x && startPos < viewItem.x + iw)
2708 qWarning(
"intersectingSet: row %d was invalid", row);
2715void QListModeViewBase::dataChanged(
const QModelIndex &,
const QModelIndex &)
2717 dd->doDelayedItemsLayout();
2721QRect QListModeViewBase::mapToViewport(
const QRect &rect)
const
2727 QRect result = rect;
2728 if (flow() == QListView::TopToBottom) {
2729 result.setLeft(spacing());
2730 result.setWidth(qMax(rect.width(), qMax(contentsSize.width(), viewport()->width()) - 2 * spacing()));
2732 result.setTop(spacing());
2733 result.setHeight(qMax(rect.height(), qMax(contentsSize.height(), viewport()->height()) - 2 * spacing()));
2738int QListModeViewBase::perItemScrollingPageSteps(
int length,
int bounds,
bool wrap)
const
2740 QList<
int> positions;
2742 positions = segmentPositions;
2743 else if (!flowPositions.isEmpty()) {
2744 positions.reserve(scrollValueMap.size());
2745 for (
int itemShown : scrollValueMap)
2746 positions.append(flowPositions.at(itemShown));
2748 if (positions.isEmpty() || bounds <= length)
2749 return positions.size();
2750 if (uniformItemSizes()) {
2751 for (
int i = 1; i < positions.size(); ++i)
2752 if (positions.at(i) > 0)
2753 return length / positions.at(i);
2757 int steps = positions.size() - 1;
2758 int max = qMax(length, bounds);
2759 int min = qMin(length, bounds);
2760 int pos = min - (max - positions.constLast());
2762 while (pos >= 0 && steps > 0) {
2763 pos -= (positions.at(steps) - positions.at(steps - 1));
2770 return qMax(pageSteps, 1);
2773int QListModeViewBase::perItemScrollToValue(
int index,
int scrollValue,
int viewportSize,
2774 QAbstractItemView::ScrollHint hint,
2775 Qt::Orientation orientation,
bool wrap,
int itemExtent)
const
2780 itemExtent += spacing();
2781 QList<
int> hiddenRows = dd->hiddenRowIds();
2782 std::sort(hiddenRows.begin(), hiddenRows.end());
2783 int hiddenRowsBefore = 0;
2784 for (
int i = 0; i < hiddenRows.size() - 1; ++i)
2785 if (hiddenRows.at(i) > index + hiddenRowsBefore)
2790 int topIndex = index;
2791 const int bottomIndex = topIndex;
2792 const int bottomCoordinate = flowPositions.at(index + hiddenRowsBefore);
2793 while (topIndex > 0 &&
2794 (bottomCoordinate - flowPositions.at(topIndex + hiddenRowsBefore - 1) + itemExtent) <= (viewportSize)) {
2797 while (hiddenRowsBefore > 0 && hiddenRows.at(hiddenRowsBefore - 1) >= topIndex + hiddenRowsBefore - 1)
2801 const int itemCount = bottomIndex - topIndex + 1;
2803 case QAbstractItemView::PositionAtTop:
2805 case QAbstractItemView::PositionAtBottom:
2806 return index - itemCount + 1;
2807 case QAbstractItemView::PositionAtCenter:
2808 return index - (itemCount / 2);
2813 Qt::Orientation flowOrientation = (flow() == QListView::LeftToRight
2814 ? Qt::Horizontal : Qt::Vertical);
2815 if (flowOrientation == orientation) {
2817 return flowPositions.at(index + hiddenRowsBefore);
2818 }
else if (!segmentStartRows.isEmpty()) {
2819 int segment = qBinarySearch<
int>(segmentStartRows, index, 0, segmentStartRows.size() - 1);
2820 int leftSegment = segment;
2821 const int rightSegment = leftSegment;
2822 const int bottomCoordinate = segmentPositions.at(segment);
2824 while (leftSegment > scrollValue &&
2825 (bottomCoordinate - segmentPositions.at(leftSegment-1) + itemExtent) <= (viewportSize)) {
2829 const int segmentCount = rightSegment - leftSegment + 1;
2831 case QAbstractItemView::PositionAtTop:
2833 case QAbstractItemView::PositionAtBottom:
2834 return segment - segmentCount + 1;
2835 case QAbstractItemView::PositionAtCenter:
2836 return segment - (segmentCount / 2);
2845void QListModeViewBase::clear()
2847 flowPositions.clear();
2848 segmentPositions.clear();
2849 segmentStartRows.clear();
2850 segmentExtents.clear();
2851 batchSavedPosition = 0;
2853 batchSavedDeltaSeg = 0;
2857
2858
2860void QIconModeViewBase::setPositionForIndex(
const QPoint &position,
const QModelIndex &index)
2862 if (index.row() >= items.size())
2864 const QSize oldContents = contentsSize;
2866 moveItem(index.row(), position);
2869 if (contentsSize != oldContents)
2870 dd->viewUpdateGeometries();
2873void QIconModeViewBase::appendHiddenRow(
int row)
2875 if (row >= 0 && row < items.size())
2876 tree.removeLeaf(items.at(row).rect(), row);
2877 QCommonListViewBase::appendHiddenRow(row);
2880void QIconModeViewBase::removeHiddenRow(
int row)
2882 QCommonListViewBase::removeHiddenRow(row);
2883 if (row >= 0 && row < items.size())
2884 tree.insertLeaf(items.at(row).rect(), row);
2887#if QT_CONFIG(draganddrop)
2888bool QIconModeViewBase::filterStartDrag(Qt::DropActions supportedActions)
2893 QModelIndexList indexes = dd->selectionModel->selectedIndexes();
2894 if (indexes.size() > 0 ) {
2895 if (viewport()->acceptDrops()) {
2896 QModelIndexList::ConstIterator it = indexes.constBegin();
2897 for (; it != indexes.constEnd(); ++it)
2898 if (dd->model->flags(*it) & Qt::ItemIsDragEnabled
2899 && (*it).column() == dd->column)
2900 draggedItems.push_back(*it);
2904 QPixmap pixmap = dd->renderToPixmap(indexes, &rect);
2905 rect.adjust(horizontalOffset(), verticalOffset(), 0, 0);
2906 QDrag *drag =
new QDrag(qq);
2907 drag->setMimeData(dd->model->mimeData(indexes));
2908 drag->setPixmap(pixmap);
2909 drag->setHotSpot(dd->pressedPosition - rect.topLeft());
2910 dd->dropEventMoved =
false;
2911 Qt::DropAction action = drag->exec(supportedActions, dd->defaultDropAction);
2912 draggedItems.clear();
2914 if (action == Qt::MoveAction && !dd->dropEventMoved) {
2915 if (dd->dragDropMode != QAbstractItemView::InternalMove || drag->target() == qq->viewport())
2916 dd->clearOrRemove();
2918 dd->dropEventMoved =
false;
2923bool QIconModeViewBase::filterDropEvent(QDropEvent *e)
2925 if (e->source() != qq)
2928 const QSize contents = contentsSize;
2929 QPoint offset(horizontalOffset(), verticalOffset());
2930 QPoint end = e->position().toPoint() + offset;
2931 if (qq->acceptDrops()) {
2932 const Qt::ItemFlags dropableFlags = Qt::ItemIsDropEnabled|Qt::ItemIsEnabled;
2933 const QList<QModelIndex> &dropIndices = intersectingSet(QRect(end, QSize(1, 1)));
2934 for (
const QModelIndex &index : dropIndices)
2935 if ((index.flags() & dropableFlags) == dropableFlags)
2938 QPoint start = dd->pressedPosition;
2939 QPoint delta = (dd->movement == QListView::Snap ? snapToGrid(end) - snapToGrid(start) : end - start);
2940 const QList<QModelIndex> indexes = dd->selectionModel->selectedIndexes();
2941 for (
const auto &index : indexes) {
2942 QRect rect = dd->rectForIndex(index);
2943 viewport()->update(dd->mapToViewport(rect,
false));
2944 QPoint dest = rect.topLeft() + delta;
2945 if (qq->isRightToLeft())
2946 dest.setX(dd->flipX(dest.x()) - rect.width());
2947 moveItem(index.row(), dest);
2950 dd->stopAutoScroll();
2951 draggedItems.clear();
2952 dd->emitIndexesMoved(indexes);
2954 dd->dropEventMoved =
true;
2957 if (contentsSize != contents) {
2958 if ((contentsSize.width() <= contents.width()
2959 || contentsSize.height() <= contents.height())) {
2960 updateContentsSize();
2962 dd->viewUpdateGeometries();
2967bool QIconModeViewBase::filterDragLeaveEvent(QDragLeaveEvent *e)
2969 viewport()->update(draggedItemsRect());
2970 draggedItemsPos = QPoint(-1, -1);
2971 return QCommonListViewBase::filterDragLeaveEvent(e);
2974bool QIconModeViewBase::filterDragMoveEvent(QDragMoveEvent *e)
2976 const bool wasAccepted = e->isAccepted();
2981 if (e->source() != qq || !dd->canDrop(e)) {
2983 e->setAccepted(wasAccepted);
2988 QRect itemsRect =
this->itemsRect(draggedItems);
2989 viewport()->update(itemsRect.translated(draggedItemsDelta()));
2991 draggedItemsPos = e->position().toPoint();
2993 viewport()->update(itemsRect.translated(draggedItemsDelta()));
2996 if (movement() == QListView::Snap) {
2997 QRect rect(snapToGrid(e->position().toPoint() + offset()), gridSize());
2998 const QList<QModelIndex> intersectVector = intersectingSet(rect);
2999 index = intersectVector.size() > 0 ? intersectVector.last() : QModelIndex();
3001 index = qq->indexAt(e->position().toPoint());
3004 if (draggedItems.contains(index))
3006 else if (dd->model->flags(index) & Qt::ItemIsDropEnabled)
3008 else if (!index.isValid())
3012 if (dd->shouldAutoScroll(e->position().toPoint()))
3013 dd->startAutoScroll();
3018void QIconModeViewBase::setRowCount(
int rowCount)
3020 tree.create(qMax(rowCount - hiddenCount(), 0));
3023void QIconModeViewBase::scrollContentsBy(
int dx,
int dy,
bool scrollElasticBand)
3025 if (scrollElasticBand)
3026 dd->scrollElasticBandBy(isRightToLeft() ? -dx : dx, dy);
3028 QCommonListViewBase::scrollContentsBy(dx, dy, scrollElasticBand);
3029 if (!draggedItems.isEmpty())
3030 viewport()->update(draggedItemsRect().translated(dx, dy));
3033void QIconModeViewBase::dataChanged(
const QModelIndex &topLeft,
const QModelIndex &bottomRight)
3035 if (column() >= topLeft.column() && column() <= bottomRight.column()) {
3036 QStyleOptionViewItem option;
3037 initViewItemOption(&option);
3038 const int bottom = qMin(items.size(), bottomRight.row() + 1);
3039 const bool useItemSize = !dd->grid.isValid();
3040 for (
int row = topLeft.row(); row < bottom; ++row)
3042 QSize s = itemSize(option, modelIndex(row));
3045 s.setWidth(qMin(dd->grid.width(), s.width()));
3046 s.setHeight(qMin(dd->grid.height(), s.height()));
3048 items[row].resize(s);
3053bool QIconModeViewBase::doBatchedItemLayout(
const QListViewLayoutInfo &info,
int max)
3055 if (info.last >= items.size()) {
3057 QStyleOptionViewItem option;
3058 initViewItemOption(&option);
3059 for (
int row = items.size(); row <= info.last; ++row) {
3060 QSize size = itemSize(option, modelIndex(row));
3061 QListViewItem item(QRect(0, 0, size.width(), size.height()), row);
3064 doDynamicLayout(info);
3066 return (batchStartRow > max);
3069QListViewItem QIconModeViewBase::indexToListViewItem(
const QModelIndex &index)
const
3071 if (index.isValid() && index.row() < items.size())
3072 return items.at(index.row());
3073 return QListViewItem();
3076void QIconModeViewBase::initBspTree(
const QSize &contents)
3079 int leafCount = tree.leafCount();
3080 for (
int l = 0; l < leafCount; ++l)
3081 tree.leaf(l).clear();
3083 QBspTree::Node::Type type = QBspTree::Node::Both;
3085 if (contents.height() / contents.width() >= 3)
3086 type = QBspTree::Node::HorizontalPlane;
3087 else if (contents.width() / contents.height() >= 3)
3088 type = QBspTree::Node::VerticalPlane;
3090 tree.init(QRect(0, 0, contents.width(), contents.height()), type);
3093QPoint QIconModeViewBase::initDynamicLayout(
const QListViewLayoutInfo &info)
3096 if (info.first == 0) {
3097 x = info.bounds.x() + info.spacing;
3098 y = info.bounds.y() + info.spacing;
3099 items.reserve(rowCount() - hiddenCount());
3101 int idx = info.first - 1;
3102 while (idx > 0 && !items.at(idx).isValid())
3104 const QListViewItem &item = items.at(idx);
3107 if (info.flow == QListView::LeftToRight)
3108 x += (info.grid.isValid() ? info.grid.width() : item.w) + info.spacing;
3110 y += (info.grid.isValid() ? info.grid.height() : item.h) + info.spacing;
3112 return QPoint(x, y);
3116
3117
3118void QIconModeViewBase::doDynamicLayout(
const QListViewLayoutInfo &info)
3120 const bool useItemSize = !info.grid.isValid();
3121 const QPoint topLeft = initDynamicLayout(info);
3123 int segStartPosition;
3125 int deltaFlowPosition;
3126 int deltaSegPosition;
3131 if (info.flow == QListView::LeftToRight) {
3132 segStartPosition = info.bounds.left() + info.spacing;
3133 segEndPosition = info.bounds.right();
3134 deltaFlowPosition = info.grid.width();
3135 deltaSegPosition = (useItemSize ? batchSavedDeltaSeg : info.grid.height());
3136 deltaSegHint = info.grid.height();
3137 flowPosition = topLeft.x();
3138 segPosition = topLeft.y();
3140 segStartPosition = info.bounds.top() + info.spacing;
3141 segEndPosition = info.bounds.bottom();
3142 deltaFlowPosition = info.grid.height();
3143 deltaSegPosition = (useItemSize ? batchSavedDeltaSeg : info.grid.width());
3144 deltaSegHint = info.grid.width();
3145 flowPosition = topLeft.y();
3146 segPosition = topLeft.x();
3149 if (moved.size() != items.size())
3150 moved.resize(items.size());
3152 QRect rect(QPoint(), topLeft);
3153 QListViewItem *item =
nullptr;
3154 Q_ASSERT(info.first <= info.last);
3155 for (
int row = info.first; row <= info.last; ++row) {
3157 if (isHidden(row)) {
3162 if (info.flow == QListView::LeftToRight)
3163 deltaFlowPosition = item->w + info.spacing;
3165 deltaFlowPosition = item->h + info.spacing;
3167 item->w = qMin<
int>(info.grid.width(), item->w);
3168 item->h = qMin<
int>(info.grid.height(), item->h);
3173 && flowPosition + deltaFlowPosition > segEndPosition
3174 && flowPosition > segStartPosition) {
3175 flowPosition = segStartPosition;
3176 segPosition += deltaSegPosition;
3178 deltaSegPosition = 0;
3183 if (info.flow == QListView::LeftToRight)
3184 deltaSegHint = item->h + info.spacing;
3186 deltaSegHint = item->w + info.spacing;
3187 deltaSegPosition = qMax(deltaSegPosition, deltaSegHint);
3193 if (!moved.testBit(row)) {
3194 if (info.flow == QListView::LeftToRight) {
3196 item->x = flowPosition;
3197 item->y = segPosition;
3199 item->x = flowPosition + ((deltaFlowPosition - item->w) / 2);
3200 item->y = segPosition;
3204 item->y = flowPosition;
3205 item->x = segPosition;
3207 item->y = flowPosition + ((deltaFlowPosition - item->h) / 2);
3208 item->x = segPosition;
3215 rect |= item->rect();
3216 else if (info.flow == QListView::LeftToRight)
3217 rect |= QRect(flowPosition, segPosition, deltaFlowPosition, deltaSegPosition);
3219 rect |= QRect(segPosition, flowPosition, deltaSegPosition, deltaFlowPosition);
3222 flowPosition += deltaFlowPosition;
3226 batchSavedDeltaSeg = deltaSegPosition;
3227 batchStartRow = info.last + 1;
3228 bool done = (info.last >= rowCount() - 1);
3230 if (done || !info.bounds.contains(item->rect())) {
3231 contentsSize = rect.size();
3232 if (info.flow == QListView::LeftToRight)
3233 contentsSize.rheight() += info.spacing;
3235 contentsSize.rwidth() += info.spacing;
3237 if (rect.size().isEmpty())
3240 int insertFrom = info.first;
3241 if (done || info.first == 0) {
3242 initBspTree(rect.size());
3246 for (
int row = insertFrom; row <= info.last; ++row)
3247 tree.insertLeaf(items.at(row).rect(), row);
3249 QRect changedRect(topLeft, rect.bottomRight());
3250 if (clipRect().intersects(changedRect))
3251 viewport()->update();
3254QList<QModelIndex> QIconModeViewBase::intersectingSet(
const QRect &area)
const
3256 QIconModeViewBase *that =
const_cast<QIconModeViewBase*>(
this);
3257 QBspTree::Data data(
static_cast<
void*>(that));
3258 QList<QModelIndex> res;
3259 that->interSectingVector = &res;
3260 that->tree.climbTree(area, &QIconModeViewBase::addLeaf, data);
3261 that->interSectingVector =
nullptr;
3265QRect QIconModeViewBase::itemsRect(
const QList<QModelIndex> &indexes)
const
3268 for (
const auto &index : indexes)
3269 rect |= viewItemRect(indexToListViewItem(index));
3273int QIconModeViewBase::itemIndex(
const QListViewItem &item)
const
3275 if (!item.isValid())
3277 int i = item.indexHint;
3278 if (i < items.size()) {
3279 if (items.at(i) == item)
3282 i = items.size() - 1;
3286 int c = items.size();
3292 if (items.at(i) == item) {
3293 items.at(i).indexHint = i;
3299 if (items.at(j) == item) {
3300 items.at(j).indexHint = j;
3309void QIconModeViewBase::addLeaf(QList<
int> &leaf,
const QRect &area, uint visited,
3310 QBspTree::Data data)
3313 QIconModeViewBase *_this =
static_cast<QIconModeViewBase *>(data.ptr);
3314 for (
int i = 0; i < leaf.size(); ++i) {
3315 int idx = leaf.at(i);
3316 if (idx < 0 || idx >= _this->items.size())
3318 vi = &_this->items[idx];
3320 if (vi->isValid() && vi->rect().intersects(area) && vi->visited != visited) {
3321 QModelIndex index = _this->dd->listViewItemToIndex(*vi);
3322 Q_ASSERT(index.isValid());
3323 _this->interSectingVector->append(index);
3324 vi->visited = visited;
3329void QIconModeViewBase::moveItem(
int index,
const QPoint &dest)
3332 QListViewItem *item = &items[index];
3333 QRect rect = item->rect();
3336 tree.removeLeaf(rect, index);
3338 tree.insertLeaf(QRect(dest, rect.size()), index);
3341 contentsSize = (QRect(QPoint(0, 0), contentsSize)|QRect(dest, rect.size())).size();
3344 if (moved.size() != items.size())
3345 moved.resize(items.size());
3346 moved.setBit(index,
true);
3349QPoint QIconModeViewBase::snapToGrid(
const QPoint &pos)
const
3351 int x = pos.x() - (pos.x() % gridSize().width());
3352 int y = pos.y() - (pos.y() % gridSize().height());
3353 return QPoint(x, y);
3356QPoint QIconModeViewBase::draggedItemsDelta()
const
3358 if (movement() == QListView::Snap) {
3359 QPoint snapdelta = QPoint((offset().x() % gridSize().width()),
3360 (offset().y() % gridSize().height()));
3361 return snapToGrid(draggedItemsPos + snapdelta) - snapToGrid(pressedPosition()) - snapdelta;
3363 return draggedItemsPos - pressedPosition();
3366QRect QIconModeViewBase::draggedItemsRect()
const
3368 QRect rect = itemsRect(draggedItems);
3369 rect.translate(draggedItemsDelta());
3373void QListViewPrivate::scrollElasticBandBy(
int dx,
int dy)
3376 elasticBand.moveRight(elasticBand.right() + dx);
3378 elasticBand.moveLeft(elasticBand.left() - dx);
3380 elasticBand.moveBottom(elasticBand.bottom() + dy);
3382 elasticBand.moveTop(elasticBand.top() - dy);
3385void QIconModeViewBase::clear()
3391 batchSavedDeltaSeg = 0;
3394void QIconModeViewBase::updateContentsSize()
3397 for (
int i = 0; i < items.size(); ++i)
3398 bounding |= items.at(i).rect();
3399 contentsSize = bounding.size();
3403
3404
3405void QListView::currentChanged(
const QModelIndex ¤t,
const QModelIndex &previous)
3407 QAbstractItemView::currentChanged(current, previous);
3408#if QT_CONFIG(accessibility)
3409 if (QAccessible::isActive()) {
3410 if (current.isValid() && hasFocus()) {
3411 int entry = visualIndex(current);
3412 QAccessibleEvent event(
this, QAccessible::Focus);
3413 event.setChild(entry);
3414 QAccessible::updateAccessibility(&event);
3421
3422
3423void QListView::selectionChanged(
const QItemSelection &selected,
3424 const QItemSelection &deselected)
3426#if QT_CONFIG(accessibility)
3427 if (QAccessible::isActive()) {
3429 QModelIndex sel = selected.indexes().value(0);
3430 if (sel.isValid()) {
3431 int entry = visualIndex(sel);
3432 QAccessibleEvent event(
this, QAccessible::SelectionAdd);
3433 event.setChild(entry);
3434 QAccessible::updateAccessibility(&event);
3436 QModelIndex desel = deselected.indexes().value(0);
3437 if (desel.isValid()) {
3438 int entry = visualIndex(desel);
3439 QAccessibleEvent event(
this, QAccessible::SelectionRemove);
3440 event.setChild(entry);
3441 QAccessible::updateAccessibility(&event);
3445 QAbstractItemView::selectionChanged(selected, deselected);
3448int QListView::visualIndex(
const QModelIndex &index)
const
3450 Q_D(
const QListView);
3451 d->executePostedLayout();
3452 QListViewItem itm = d->indexToListViewItem(index);
3453 int visualIndex = d->commonListView->itemIndex(itm);
3454 for (
const auto &idx : std::as_const(d->hiddenRows)) {
3455 if (idx.row() <= index.row())
3463
3464
3465
3466QSize QListView::viewportSizeHint()
const
3468 Q_D(
const QListView);
3471 return QAbstractItemView::viewportSizeHint();
3472 const int rc = d->model->rowCount();
3473 if (rc == 0 || isWrapping())
3474 return QAbstractItemView::viewportSizeHint();
3476 QStyleOptionViewItem option;
3477 initViewItemOption(&option);
3479 if (uniformItemSizes()) {
3480 QSize sz = d->cachedItemSize;
3481 if (!sz.isValid()) {
3482 QModelIndex idx = d->model->index(0, d->column, d->root);
3483 sz = d->itemSize(option, idx);
3485 sz.setHeight(rc * sz.height());
3492 int maximumRows = 1000;
3493 const QVariant userOverrideValue = property(
"_q_resizeContentPrecision");
3494 if (userOverrideValue.isValid() && userOverrideValue.toInt() > 0) {
3495 maximumRows = userOverrideValue.toInt();
3497 const int rowCount = qMin(rc, maximumRows);
3502 for (
int row = 0; row < rowCount; ++row) {
3503 QModelIndex idx = d->model->index(row, d->column, d->root);
3504 QSize itemSize = d->itemSize(option, idx);
3505 h += itemSize.height();
3506 w = qMax(w, itemSize.width());
3513#include "moc_qlistview.cpp"