summaryrefslogtreecommitdiffstats
path: root/src/widgets/itemviews/qlistview.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/widgets/itemviews/qlistview.cpp')
-rw-r--r--src/widgets/itemviews/qlistview.cpp614
1 files changed, 370 insertions, 244 deletions
diff --git a/src/widgets/itemviews/qlistview.cpp b/src/widgets/itemviews/qlistview.cpp
index 1c01bba771..a7f1931947 100644
--- a/src/widgets/itemviews/qlistview.cpp
+++ b/src/widgets/itemviews/qlistview.cpp
@@ -1,65 +1,30 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Copyright (C) 2013 Samuel Gaist <samuel.gaist@deltech.ch>
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtWidgets module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// Copyright (C) 2013 Samuel Gaist <samuel.gaist@deltech.ch>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qlistview.h"
#include <qabstractitemdelegate.h>
+#if QT_CONFIG(accessibility)
+#include <qaccessible.h>
+#endif
#include <qapplication.h>
-#include <qpainter.h>
+#include <qstylepainter.h>
#include <qbitmap.h>
+#include <qdebug.h>
#if QT_CONFIG(draganddrop)
#include <qdrag.h>
#endif
-#include <qvector.h>
-#include <qstyle.h>
#include <qevent.h>
-#include <qscrollbar.h>
+#include <qlist.h>
#if QT_CONFIG(rubberband)
#include <qrubberband.h>
#endif
+#include <qscrollbar.h>
+#include <qstyle.h>
+#include <private/qapplication_p.h>
#include <private/qlistview_p.h>
#include <private/qscrollbar_p.h>
-#include <qdebug.h>
-#ifndef QT_NO_ACCESSIBILITY
-#include <qaccessible.h>
-#endif
#include <algorithm>
@@ -123,7 +88,7 @@ extern bool qt_sendSpontaneousEvent(QObject *receiver, QEvent *event);
that can be taken for views that are intended to display items with equal sizes
is to set the \l uniformItemSizes property to true.
- \sa {View Classes}, {Item Views Puzzle Example}, QTreeView, QTableView, QListWidget
+ \sa {View Classes}, QTreeView, QTableView, QListWidget
*/
/*!
@@ -213,8 +178,8 @@ QListView::~QListView()
grid, or cannot be moved at all.
This property determines how the user can move the items in the
- view. \l Static means that the items can't be moved the user. \l
- Free means that the user can drag and drop the items to any
+ view. \l Static means that the items can't be moved by the user.
+ \l Free means that the user can drag and drop the items to any
position in the view. \l Snap means that the user can drag and
drop the items, but only to the positions in a notional grid
signified by the gridSize property.
@@ -387,7 +352,7 @@ int QListView::spacing() const
/*!
\property QListView::batchSize
\brief the number of items laid out in each batch if \l layoutMode is
- set to \l Batched
+ set to \l Batched.
The default value is 100.
@@ -571,6 +536,8 @@ void QListView::scrollTo(const QModelIndex &index, ScrollHint hint)
return;
const QRect rect = visualRect(index);
+ if (!rect.isValid())
+ return;
if (hint == EnsureVisible && d->viewport->rect().contains(rect)) {
d->viewport->update(rect);
return;
@@ -654,7 +621,8 @@ QItemViewPaintPairs QListViewPrivate::draggablePaintPairs(const QModelIndexList
QRect &rect = *r;
const QRect viewportRect = viewport->rect();
QItemViewPaintPairs ret;
- QVector<QModelIndex> visibleIndexes = intersectingSet(viewportRect.translated(q->horizontalOffset(), q->verticalOffset()));
+ QList<QModelIndex> visibleIndexes =
+ intersectingSet(viewportRect.translated(q->horizontalOffset(), q->verticalOffset()));
std::sort(visibleIndexes.begin(), visibleIndexes.end());
for (const auto &index : indexes) {
if (std::binary_search(visibleIndexes.cbegin(), visibleIndexes.cend(), index)) {
@@ -663,7 +631,9 @@ QItemViewPaintPairs QListViewPrivate::draggablePaintPairs(const QModelIndexList
rect |= current;
}
}
- rect &= viewportRect;
+ QRect clipped = rect & viewportRect;
+ rect.setLeft(clipped.left());
+ rect.setRight(clipped.right());
return ret;
}
@@ -679,12 +649,12 @@ void QListView::reset()
}
/*!
- \internal
+ \reimp
*/
void QListView::setRootIndex(const QModelIndex &index)
{
Q_D(QListView);
- d->column = qBound(0, d->column, d->model->columnCount(index) - 1);
+ d->column = qMax(0, qMin(d->column, d->model->columnCount(index) - 1));
QAbstractItemView::setRootIndex(index);
// sometimes we get an update before reset() is called
d->clear();
@@ -692,7 +662,7 @@ void QListView::setRootIndex(const QModelIndex &index)
}
/*!
- \internal
+ \reimp
Scroll the view contents by \a dx and \a dy.
*/
@@ -728,7 +698,8 @@ QSize QListView::contentsSize() const
/*!
\reimp
*/
-void QListView::dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector<int> &roles)
+void QListView::dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight,
+ const QList<int> &roles)
{
d_func()->commonListView->dataChanged(topLeft, bottomRight);
QAbstractItemView::dataChanged(topLeft, bottomRight, roles);
@@ -782,9 +753,12 @@ void QListView::mouseMoveEvent(QMouseEvent *e)
&& d->showElasticBand
&& d->selectionMode != SingleSelection
&& d->selectionMode != NoSelection) {
- QRect rect(d->pressedPosition, e->pos() + QPoint(horizontalOffset(), verticalOffset()));
+ QRect rect(d->pressedPosition, e->position().toPoint() + QPoint(horizontalOffset(), verticalOffset()));
rect = rect.normalized();
- d->viewport->update(d->mapToViewport(rect.united(d->elasticBand)));
+ const int margin = 2 * style()->pixelMetric(QStyle::PM_DefaultFrameWidth);
+ const QRect viewPortRect = rect.united(d->elasticBand)
+ .adjusted(-margin, -margin, margin, margin);
+ d->viewport->update(d->mapToViewport(viewPortRect));
d->elasticBand = rect;
}
}
@@ -798,7 +772,9 @@ void QListView::mouseReleaseEvent(QMouseEvent *e)
QAbstractItemView::mouseReleaseEvent(e);
// #### move this implementation into a dynamic class
if (d->showElasticBand && d->elasticBand.isValid()) {
- d->viewport->update(d->mapToViewport(d->elasticBand));
+ const int margin = 2 * style()->pixelMetric(QStyle::PM_DefaultFrameWidth);
+ const QRect viewPortRect = d->elasticBand.adjusted(-margin, -margin, margin, margin);
+ d->viewport->update(d->mapToViewport(viewPortRect));
d->elasticBand = QRect();
}
}
@@ -810,24 +786,24 @@ void QListView::mouseReleaseEvent(QMouseEvent *e)
void QListView::wheelEvent(QWheelEvent *e)
{
Q_D(QListView);
- if (e->orientation() == Qt::Vertical) {
+ if (qAbs(e->angleDelta().y()) > qAbs(e->angleDelta().x())) {
if (e->angleDelta().x() == 0
- && ((d->flow == TopToBottom && d->wrap) || (d->flow == LeftToRight && !d->wrap))
- && d->vbar->minimum() == 0 && d->vbar->maximum() == 0) {
+ && ((d->flow == TopToBottom && d->wrap) || (d->flow == LeftToRight && !d->wrap))
+ && d->vbar->minimum() == 0 && d->vbar->maximum() == 0) {
QPoint pixelDelta(e->pixelDelta().y(), e->pixelDelta().x());
QPoint angleDelta(e->angleDelta().y(), e->angleDelta().x());
- QWheelEvent hwe(e->pos(), e->globalPos(), pixelDelta, angleDelta, e->delta(),
- Qt::Horizontal, e->buttons(), e->modifiers(), e->phase(), e->source(), e->inverted());
+ QWheelEvent hwe(e->position(), e->globalPosition(), pixelDelta, angleDelta,
+ e->buttons(), e->modifiers(), e->phase(), e->inverted(), e->source());
if (e->spontaneous())
qt_sendSpontaneousEvent(d->hbar, &hwe);
else
- QApplication::sendEvent(d->hbar, &hwe);
+ QCoreApplication::sendEvent(d->hbar, &hwe);
e->setAccepted(hwe.isAccepted());
} else {
- QApplication::sendEvent(d->vbar, e);
+ QCoreApplication::sendEvent(d->vbar, e);
}
} else {
- QApplication::sendEvent(d->hbar, e);
+ QCoreApplication::sendEvent(d->hbar, e);
}
}
#endif // QT_CONFIG(wheelevent)
@@ -906,10 +882,68 @@ void QListView::dragLeaveEvent(QDragLeaveEvent *e)
/*!
\reimp
*/
-void QListView::dropEvent(QDropEvent *e)
+void QListView::dropEvent(QDropEvent *event)
{
- if (!d_func()->commonListView->filterDropEvent(e))
- QAbstractItemView::dropEvent(e);
+ Q_D(QListView);
+
+ if (event->source() == this && (event->dropAction() == Qt::MoveAction ||
+ dragDropMode() == QAbstractItemView::InternalMove)) {
+ QModelIndex topIndex;
+ bool topIndexDropped = false;
+ int col = -1;
+ int row = -1;
+ // check whether a subclass has already accepted the event, ie. moved the data
+ if (!event->isAccepted() && d->dropOn(event, &row, &col, &topIndex)) {
+ const QList<QModelIndex> selIndexes = selectedIndexes();
+ QList<QPersistentModelIndex> persIndexes;
+ persIndexes.reserve(selIndexes.size());
+
+ for (const auto &index : selIndexes) {
+ persIndexes.append(index);
+ if (index == topIndex) {
+ topIndexDropped = true;
+ break;
+ }
+ }
+
+ if (!topIndexDropped && !topIndex.isValid()) {
+ std::sort(persIndexes.begin(), persIndexes.end()); // The dropped items will remain in the same visual order.
+
+ QPersistentModelIndex dropRow = model()->index(row, col, topIndex);
+
+ int r = row == -1 ? model()->rowCount() : (dropRow.row() >= 0 ? dropRow.row() : row);
+ bool dataMoved = false;
+ for (int i = 0; i < persIndexes.size(); ++i) {
+ const QPersistentModelIndex &pIndex = persIndexes.at(i);
+ // only generate a move when not same row or behind itself
+ if (r != pIndex.row() && r != pIndex.row() + 1) {
+ // try to move (preserves selection)
+ dataMoved |= model()->moveRow(QModelIndex(), pIndex.row(), QModelIndex(), r);
+ if (!dataMoved) // can't move - abort and let QAbstractItemView handle this
+ break;
+ } else {
+ // move onto itself is blocked, don't delete anything
+ dataMoved = true;
+ }
+ r = pIndex.row() + 1; // Dropped items are inserted contiguously and in the right order.
+ }
+ if (dataMoved)
+ event->accept();
+ }
+ }
+
+ // either we or a subclass accepted the move event, so assume that the data was
+ // moved and that QAbstractItemView shouldn't remove the source when QDrag::exec returns
+ if (event->isAccepted())
+ d->dropEventMoved = true;
+ }
+
+ if (!d->commonListView->filterDropEvent(event) || !d->dropEventMoved) {
+ // icon view didn't move the data, and moveRows not implemented, so fall back to default
+ if (!d->dropEventMoved)
+ event->ignore();
+ QAbstractItemView::dropEvent(event);
+ }
}
/*!
@@ -926,29 +960,27 @@ void QListView::startDrag(Qt::DropActions supportedActions)
/*!
\reimp
*/
-QStyleOptionViewItem QListView::viewOptions() const
+void QListView::initViewItemOption(QStyleOptionViewItem *option) const
{
Q_D(const QListView);
- QStyleOptionViewItem option = QAbstractItemView::viewOptions();
+ QAbstractItemView::initViewItemOption(option);
if (!d->iconSize.isValid()) { // otherwise it was already set in abstractitemview
int pm = (d->viewMode == QListView::ListMode
- ? style()->pixelMetric(QStyle::PM_ListViewIconSize, 0, this)
- : style()->pixelMetric(QStyle::PM_IconViewIconSize, 0, this));
- option.decorationSize = QSize(pm, pm);
+ ? style()->pixelMetric(QStyle::PM_ListViewIconSize, nullptr, this)
+ : style()->pixelMetric(QStyle::PM_IconViewIconSize, nullptr, this));
+ option->decorationSize = QSize(pm, pm);
}
if (d->viewMode == QListView::IconMode) {
- option.showDecorationSelected = false;
- option.decorationPosition = QStyleOptionViewItem::Top;
- option.displayAlignment = Qt::AlignCenter;
+ option->showDecorationSelected = false;
+ option->decorationPosition = QStyleOptionViewItem::Top;
+ option->displayAlignment = Qt::AlignCenter;
} else {
- option.decorationPosition = QStyleOptionViewItem::Left;
+ option->decorationPosition = QStyleOptionViewItem::Left;
}
if (d->gridSize().isValid()) {
- option.rect.setSize(d->gridSize());
+ option->rect.setSize(d->gridSize());
}
-
- return option;
}
@@ -960,10 +992,12 @@ void QListView::paintEvent(QPaintEvent *e)
Q_D(QListView);
if (!d->itemDelegate)
return;
- QStyleOptionViewItem option = d->viewOptionsV1();
- QPainter painter(d->viewport);
+ QStyleOptionViewItem option;
+ initViewItemOption(&option);
+ QStylePainter painter(d->viewport);
- const QVector<QModelIndex> toBeRendered = d->intersectingSet(e->rect().translated(horizontalOffset(), verticalOffset()), false);
+ const QList<QModelIndex> toBeRendered =
+ d->intersectingSet(e->rect().translated(horizontalOffset(), verticalOffset()), false);
const QModelIndex current = currentIndex();
const QModelIndex hover = d->hover;
@@ -982,8 +1016,8 @@ void QListView::paintEvent(QPaintEvent *e)
? qMax(viewport()->size().width(), d->contentsSize().width()) - 2 * d->spacing()
: qMax(viewport()->size().height(), d->contentsSize().height()) - 2 * d->spacing();
- QVector<QModelIndex>::const_iterator end = toBeRendered.constEnd();
- for (QVector<QModelIndex>::const_iterator it = toBeRendered.constBegin(); it != end; ++it) {
+ QList<QModelIndex>::const_iterator end = toBeRendered.constEnd();
+ for (QList<QModelIndex>::const_iterator it = toBeRendered.constBegin(); it != end; ++it) {
Q_ASSERT((*it).isValid());
option.rect = visualRect(*it);
@@ -1031,14 +1065,14 @@ void QListView::paintEvent(QPaintEvent *e)
// is provided by the delegate
QStyle::State oldState = option.state;
option.state &= ~QStyle::State_Selected;
- style()->drawPrimitive(QStyle::PE_PanelItemViewRow, &option, &painter, this);
+ painter.drawPrimitive(QStyle::PE_PanelItemViewRow, option);
option.state = oldState;
alternateBase = !alternateBase;
previousRow = row;
}
- d->delegateForIndex(*it)->paint(&painter, option, *it);
+ itemDelegateForIndex(*it)->paint(&painter, option, *it);
}
#if QT_CONFIG(draganddrop)
@@ -1055,7 +1089,7 @@ void QListView::paintEvent(QPaintEvent *e)
opt.rect = d->mapToViewport(d->elasticBand, false).intersected(
d->viewport->rect().adjusted(-16, -16, 16, 16));
painter.save();
- style()->drawControl(QStyle::CE_RubberBand, &opt, &painter);
+ painter.drawControl(QStyle::CE_RubberBand, opt);
painter.restore();
}
#endif
@@ -1068,8 +1102,8 @@ QModelIndex QListView::indexAt(const QPoint &p) const
{
Q_D(const QListView);
QRect rect(p.x() + horizontalOffset(), p.y() + verticalOffset(), 1, 1);
- const QVector<QModelIndex> intersectVector = d->intersectingSet(rect);
- QModelIndex index = intersectVector.count() > 0
+ const QList<QModelIndex> intersectVector = d->intersectingSet(rect);
+ QModelIndex index = intersectVector.size() > 0
? intersectVector.last() : QModelIndex();
if (index.isValid() && visualRect(index).contains(p))
return index;
@@ -1147,7 +1181,7 @@ QModelIndex QListView::moveCursor(CursorAction cursorAction, Qt::KeyboardModifie
if (d->gridSize().isValid()) rect.setSize(d->gridSize());
QSize contents = d->contentsSize();
- QVector<QModelIndex> intersectVector;
+ QList<QModelIndex> intersectVector;
switch (cursorAction) {
case MoveLeft:
@@ -1172,20 +1206,35 @@ QModelIndex QListView::moveCursor(CursorAction cursorAction, Qt::KeyboardModifie
d->removeCurrentAndDisabled(&intersectVector, current);
}
return d->closestIndex(initialRect, intersectVector);
- case MovePageUp:
- // move current by (visibileRowCount - 1) items.
- // rect.translate(0, -rect.height()); will happen in the switch fallthrough for MoveUp.
- rect.moveTop(rect.top() - d->viewport->height() + 2 * rect.height());
- if (rect.top() < rect.height())
- rect.moveTop(rect.height());
- Q_FALLTHROUGH();
+ case MovePageUp: {
+ if (rect.height() >= d->viewport->height())
+ return moveCursor(QAbstractItemView::MoveUp, modifiers);
+
+ rect.moveTop(rect.top() - d->viewport->height() + 1);
+ if (rect.top() < rect.height()) {
+ rect.setTop(0);
+ rect.setBottom(1);
+ }
+ QModelIndex findindex = current;
+ while (intersectVector.isEmpty()
+ || rectForIndex(findindex).top() <= (rectForIndex(current).bottom() - d->viewport->rect().height())
+ || rect.top() <= 0) {
+ rect.translate(0, 1);
+ if (rect.bottom() <= 0) {
+ return current;
+ }
+ intersectVector = d->intersectingSet(rect);
+ findindex = d->closestIndex(initialRect, intersectVector);
+ }
+ return findindex;
+ }
case MovePrevious:
case MoveUp:
while (intersectVector.isEmpty()) {
rect.translate(0, -rect.height());
if (rect.bottom() <= 0) {
#ifdef QT_KEYPAD_NAVIGATION
- if (QApplication::keypadNavigationEnabled()) {
+ if (QApplicationPrivate::keypadNavigationEnabled()) {
int row = d->batchStartRow() - 1;
while (row >= 0 && d->isHiddenOrDisabled(row))
--row;
@@ -1201,20 +1250,36 @@ QModelIndex QListView::moveCursor(CursorAction cursorAction, Qt::KeyboardModifie
d->removeCurrentAndDisabled(&intersectVector, current);
}
return d->closestIndex(initialRect, intersectVector);
- case MovePageDown:
- // move current by (visibileRowCount - 1) items.
- // rect.translate(0, rect.height()); will happen in the switch fallthrough for MoveDown.
- rect.moveTop(rect.top() + d->viewport->height() - 2 * rect.height());
- if (rect.bottom() > contents.height() - rect.height())
- rect.moveBottom(contents.height() - rect.height());
- Q_FALLTHROUGH();
+ case MovePageDown: {
+ if (rect.height() >= d->viewport->height())
+ return moveCursor(QAbstractItemView::MoveDown, modifiers);
+
+ rect.moveTop(rect.top() + d->viewport->height() - 1);
+ if (rect.bottom() > contents.height() - rect.height()) {
+ rect.setTop(contents.height() - 1);
+ rect.setBottom(contents.height());
+ }
+ QModelIndex index = current;
+ // index's bottom() - current's top() always <= (d->viewport->rect().height()
+ while (intersectVector.isEmpty()
+ || rectForIndex(index).bottom() >= (d->viewport->rect().height() + rectForIndex(current).top())
+ || rect.bottom() > contents.height()) {
+ rect.translate(0, -1);
+ if (rect.top() >= contents.height()) {
+ return current;
+ }
+ intersectVector = d->intersectingSet(rect);
+ index = d->closestIndex(initialRect, intersectVector);
+ }
+ return index;
+ }
case MoveNext:
case MoveDown:
while (intersectVector.isEmpty()) {
rect.translate(0, rect.height());
if (rect.top() >= contents.height()) {
#ifdef QT_KEYPAD_NAVIGATION
- if (QApplication::keypadNavigationEnabled()) {
+ if (QApplicationPrivate::keypadNavigationEnabled()) {
int rowCount = d->model->rowCount(d->root);
int row = 0;
while (row < rowCount && d->isHiddenOrDisabled(row))
@@ -1280,7 +1345,7 @@ void QListView::setSelection(const QRect &rect, QItemSelectionModel::SelectionFl
if (!d->selectionModel)
return;
- // if we are wrapping, we can only selecte inside the contents rectangle
+ // if we are wrapping, we can only select inside the contents rectangle
int w = qMax(d->contentsSize().width(), d->viewport->width());
int h = qMax(d->contentsSize().height(), d->viewport->height());
if (d->wrap && !QRect(0, 0, w, h).intersects(rect))
@@ -1289,7 +1354,8 @@ void QListView::setSelection(const QRect &rect, QItemSelectionModel::SelectionFl
QItemSelection selection;
if (rect.width() == 1 && rect.height() == 1) {
- const QVector<QModelIndex> intersectVector = d->intersectingSet(rect.translated(horizontalOffset(), verticalOffset()));
+ const QList<QModelIndex> intersectVector =
+ d->intersectingSet(rect.translated(horizontalOffset(), verticalOffset()));
QModelIndex tl;
if (!intersectVector.isEmpty())
tl = intersectVector.last(); // special case for mouse press; only select the top item
@@ -1302,7 +1368,7 @@ void QListView::setSelection(const QRect &rect, QItemSelectionModel::SelectionFl
QModelIndex tl, br;
// get the first item
const QRect topLeft(rect.left() + horizontalOffset(), rect.top() + verticalOffset(), 1, 1);
- QVector<QModelIndex> intersectVector = d->intersectingSet(topLeft);
+ QList<QModelIndex> intersectVector = d->intersectingSet(topLeft);
if (!intersectVector.isEmpty())
tl = intersectVector.last();
// get the last item
@@ -1327,7 +1393,7 @@ void QListView::setSelection(const QRect &rect, QItemSelectionModel::SelectionFl
top = bottom;
bottom = tmp;
}
- // if the rect are on differnet lines, expand
+ // if the rect are on different lines, expand
if (top.top() != bottom.top()) {
// top rectangle
if (isRightToLeft())
@@ -1466,8 +1532,7 @@ QModelIndexList QListView::selectedIndexes() const
auto ignorable = [this, d](const QModelIndex &index) {
return index.column() != d->column || index.parent() != d->root || isIndexHidden(index);
};
- viewSelected.erase(std::remove_if(viewSelected.begin(), viewSelected.end(), ignorable),
- viewSelected.end());
+ viewSelected.removeIf(ignorable);
return viewSelected;
}
@@ -1486,12 +1551,14 @@ void QListView::doItemsLayout()
setState(ExpandingState);
if (d->model->columnCount(d->root) > 0) { // no columns means no contents
d->resetBatchStartRow();
- if (layoutMode() == SinglePass)
+ if (layoutMode() == SinglePass) {
d->doItemsLayout(d->model->rowCount(d->root)); // layout everything
- else if (!d->batchLayoutTimer.isActive()) {
+ } else if (!d->batchLayoutTimer.isActive()) {
if (!d->doItemsLayout(d->batchSize)) // layout is done
d->batchLayoutTimer.start(0, this); // do a new batch as fast as possible
}
+ } else { // clear the QBspTree generated by the last layout
+ d->clear();
}
QAbstractItemView::doItemsLayout();
setState(oldState); // restoring the oldState
@@ -1508,7 +1575,8 @@ void QListView::updateGeometries()
verticalScrollBar()->setRange(0, 0);
} else {
QModelIndex index = d->model->index(0, d->column, d->root);
- QStyleOptionViewItem option = d->viewOptionsV1();
+ QStyleOptionViewItem option;
+ initViewItemOption(&option);
QSize step = d->itemSize(option, index);
d->commonListView->updateHorizontalScrollBar(step);
d->commonListView->updateVerticalScrollBar(step);
@@ -1559,6 +1627,12 @@ void QListView::setModelColumn(int column)
return;
d->column = column;
d->doDelayedItemsLayout();
+#if QT_CONFIG(accessibility)
+ if (QAccessible::isActive()) {
+ QAccessibleTableModelChangeEvent event(this, QAccessibleTableModelChangeEvent::ModelReset);
+ QAccessible::updateAccessibility(&event);
+ }
+#endif
}
int QListView::modelColumn() const
@@ -1687,7 +1761,7 @@ bool QListView::event(QEvent *e)
QListViewPrivate::QListViewPrivate()
: QAbstractItemViewPrivate(),
- commonListView(0),
+ commonListView(nullptr),
wrap(false),
space(0),
flow(QListView::TopToBottom),
@@ -1725,17 +1799,21 @@ void QListViewPrivate::prepareItemsLayout()
layoutBounds = QRect(QPoint(), q->maximumViewportSize());
int frameAroundContents = 0;
- if (q->style()->styleHint(QStyle::SH_ScrollView_FrameOnlyAroundContents))
- frameAroundContents = q->style()->pixelMetric(QStyle::PM_DefaultFrameWidth) * 2;
+ if (q->style()->styleHint(QStyle::SH_ScrollView_FrameOnlyAroundContents)) {
+ QStyleOption option;
+ option.initFrom(q);
+ frameAroundContents = q->style()->pixelMetric(QStyle::PM_DefaultFrameWidth, &option, q) * 2;
+ }
// maximumViewportSize() already takes scrollbar into account if policy is
// Qt::ScrollBarAlwaysOn but scrollbar extent must be deduced if policy
// is Qt::ScrollBarAsNeeded
- int verticalMargin = vbarpolicy==Qt::ScrollBarAsNeeded
- ? q->style()->pixelMetric(QStyle::PM_ScrollBarExtent, 0, vbar) + frameAroundContents
+ int verticalMargin = (vbarpolicy == Qt::ScrollBarAsNeeded) && (flow == QListView::LeftToRight || vbar->isVisible())
+ && !q->style()->pixelMetric(QStyle::PM_ScrollView_ScrollBarOverlap, nullptr, vbar)
+ ? q->style()->pixelMetric(QStyle::PM_ScrollBarExtent, nullptr, vbar) + frameAroundContents
: 0;
int horizontalMargin = hbarpolicy==Qt::ScrollBarAsNeeded
- ? q->style()->pixelMetric(QStyle::PM_ScrollBarExtent, 0, hbar) + frameAroundContents
+ ? q->style()->pixelMetric(QStyle::PM_ScrollBarExtent, nullptr, hbar) + frameAroundContents
: 0;
layoutBounds.adjust(0, 0, -verticalMargin, -horizontalMargin);
@@ -1796,12 +1874,12 @@ QRect QListViewPrivate::mapToViewport(const QRect &rect, bool extend) const
}
QModelIndex QListViewPrivate::closestIndex(const QRect &target,
- const QVector<QModelIndex> &candidates) const
+ const QList<QModelIndex> &candidates) const
{
int distance = 0;
int shortest = INT_MAX;
QModelIndex closest;
- QVector<QModelIndex>::const_iterator it = candidates.begin();
+ QList<QModelIndex>::const_iterator it = candidates.begin();
for (; it != candidates.end(); ++it) {
if (!(*it).isValid())
@@ -1833,14 +1911,15 @@ QModelIndex QListViewPrivate::closestIndex(const QRect &target,
QSize QListViewPrivate::itemSize(const QStyleOptionViewItem &option, const QModelIndex &index) const
{
+ Q_Q(const QListView);
if (!uniformItemSizes) {
- const QAbstractItemDelegate *delegate = delegateForIndex(index);
+ const QAbstractItemDelegate *delegate = q->itemDelegateForIndex(index);
return delegate ? delegate->sizeHint(option, index) : QSize();
}
- if (!cachedItemSize.isValid()) { // the last item is probaly the largest, so we use its size
+ if (!cachedItemSize.isValid()) { // the last item is probably the largest, so we use its size
int row = model->rowCount(root) - 1;
QModelIndex sample = model->index(row, column, root);
- const QAbstractItemDelegate *delegate = delegateForIndex(sample);
+ const QAbstractItemDelegate *delegate = q->itemDelegateForIndex(sample);
cachedItemSize = delegate ? delegate->sizeHint(option, sample) : QSize();
}
return cachedItemSize;
@@ -1850,8 +1929,8 @@ QItemSelection QListViewPrivate::selection(const QRect &rect) const
{
QItemSelection selection;
QModelIndex tl, br;
- const QVector<QModelIndex> intersectVector = intersectingSet(rect);
- QVector<QModelIndex>::const_iterator it = intersectVector.begin();
+ const QList<QModelIndex> intersectVector = intersectingSet(rect);
+ QList<QModelIndex>::const_iterator it = intersectVector.begin();
for (; it != intersectVector.end(); ++it) {
if (!tl.isValid() && !br.isValid()) {
tl = br = *it;
@@ -1893,14 +1972,13 @@ bool QListViewPrivate::dropOn(QDropEvent *event, int *dropRow, int *dropCol, QMo
}
#endif
-void QListViewPrivate::removeCurrentAndDisabled(QVector<QModelIndex> *indexes, const QModelIndex &current) const
+void QListViewPrivate::removeCurrentAndDisabled(QList<QModelIndex> *indexes,
+ const QModelIndex &current) const
{
auto isCurrentOrDisabled = [this, current](const QModelIndex &index) {
return !isIndexEnabled(index) || index == current;
};
- indexes->erase(std::remove_if(indexes->begin(), indexes->end(),
- isCurrentOrDisabled),
- indexes->end());
+ indexes->removeIf(isCurrentOrDisabled);
}
/*
@@ -2089,11 +2167,11 @@ void QListModeViewBase::dragMoveEvent(QDragMoveEvent *event)
event->ignore();
// can't use indexAt, doesn't account for spacing.
- QPoint p = event->pos();
+ QPoint p = event->position().toPoint();
QRect rect(p.x() + horizontalOffset(), p.y() + verticalOffset(), 1, 1);
rect.adjust(-dd->spacing(), -dd->spacing(), dd->spacing(), dd->spacing());
- const QVector<QModelIndex> intersectVector = dd->intersectingSet(rect);
- QModelIndex index = intersectVector.count() > 0
+ const QList<QModelIndex> intersectVector = dd->intersectingSet(rect);
+ QModelIndex index = intersectVector.size() > 0
? intersectVector.last() : QModelIndex();
dd->hover = index;
if (!dd->droppingOnItself(event, index)
@@ -2101,7 +2179,7 @@ void QListModeViewBase::dragMoveEvent(QDragMoveEvent *event)
if (index.isValid() && dd->showDropIndicator) {
QRect rect = qq->visualRect(index);
- dd->dropIndicatorPosition = position(event->pos(), rect, index);
+ dd->dropIndicatorPosition = position(event->position().toPoint(), rect, index);
// if spacing, should try to draw between items, not just next to item.
switch (dd->dropIndicatorPosition) {
case QAbstractItemView::AboveItem:
@@ -2145,7 +2223,7 @@ void QListModeViewBase::dragMoveEvent(QDragMoveEvent *event)
dd->viewport->update();
} // can drop
- if (dd->shouldAutoScroll(event->pos()))
+ if (dd->shouldAutoScroll(event->position().toPoint()))
qq->startAutoScroll();
}
@@ -2166,13 +2244,13 @@ bool QListModeViewBase::dropOn(QDropEvent *event, int *dropRow, int *dropCol, QM
return false;
QModelIndex index;
- if (dd->viewport->rect().contains(event->pos())) {
+ if (dd->viewport->rect().contains(event->position().toPoint())) {
// can't use indexAt, doesn't account for spacing.
- QPoint p = event->pos();
+ QPoint p = event->position().toPoint();
QRect rect(p.x() + horizontalOffset(), p.y() + verticalOffset(), 1, 1);
rect.adjust(-dd->spacing(), -dd->spacing(), dd->spacing(), dd->spacing());
- const QVector<QModelIndex> intersectVector = dd->intersectingSet(rect);
- index = intersectVector.count() > 0
+ const QList<QModelIndex> intersectVector = dd->intersectingSet(rect);
+ index = intersectVector.size() > 0
? intersectVector.last() : QModelIndex();
if (!index.isValid())
index = dd->root;
@@ -2183,7 +2261,7 @@ bool QListModeViewBase::dropOn(QDropEvent *event, int *dropRow, int *dropCol, QM
int row = -1;
int col = -1;
if (index != dd->root) {
- dd->dropIndicatorPosition = position(event->pos(), qq->visualRect(index), index);
+ dd->dropIndicatorPosition = position(event->position().toPoint(), qq->visualRect(index), index);
switch (dd->dropIndicatorPosition) {
case QAbstractItemView::AboveItem:
row = index.row();
@@ -2218,7 +2296,7 @@ void QListModeViewBase::updateVerticalScrollBar(const QSize &step)
if (verticalScrollMode() == QAbstractItemView::ScrollPerItem
&& ((flow() == QListView::TopToBottom && !isWrapping())
|| (flow() == QListView::LeftToRight && isWrapping()))) {
- const int steps = (flow() == QListView::TopToBottom ? scrollValueMap : segmentPositions).count() - 1;
+ const int steps = (flow() == QListView::TopToBottom ? scrollValueMap : segmentPositions).size() - 1;
if (steps > 0) {
const int pageSteps = perItemScrollingPageSteps(viewport()->height(), contentsSize.height(), isWrapping());
verticalScrollBar()->setSingleStep(1);
@@ -2239,7 +2317,7 @@ void QListModeViewBase::updateHorizontalScrollBar(const QSize &step)
if (horizontalScrollMode() == QAbstractItemView::ScrollPerItem
&& ((flow() == QListView::TopToBottom && isWrapping())
|| (flow() == QListView::LeftToRight && !isWrapping()))) {
- int steps = (flow() == QListView::TopToBottom ? segmentPositions : scrollValueMap).count() - 1;
+ int steps = (flow() == QListView::TopToBottom ? segmentPositions : scrollValueMap).size() - 1;
if (steps > 0) {
const int pageSteps = perItemScrollingPageSteps(viewport()->width(), contentsSize.width(), isWrapping());
horizontalScrollBar()->setSingleStep(1);
@@ -2263,10 +2341,10 @@ int QListModeViewBase::verticalScrollToValue(int index, QListView::ScrollHint hi
} else {
int scrollBarValue = verticalScrollBar()->value();
int numHidden = 0;
- for (int i = 0; i < flowPositions.count() - 1 && i <= scrollBarValue; ++i)
- if (isHidden(i))
+ for (const auto &idx : std::as_const(dd->hiddenRows))
+ if (idx.row() <= scrollBarValue)
++numHidden;
- value = qBound(0, scrollValueMap.at(verticalScrollBar()->value()) - numHidden, flowPositions.count() - 1);
+ value = qBound(0, scrollValueMap.at(verticalScrollBar()->value()) - numHidden, flowPositions.size() - 1);
}
if (above)
hint = QListView::PositionAtTop;
@@ -2286,7 +2364,7 @@ int QListModeViewBase::horizontalOffset() const
if (horizontalScrollMode() == QAbstractItemView::ScrollPerItem) {
if (isWrapping()) {
if (flow() == QListView::TopToBottom && !segmentPositions.isEmpty()) {
- const int max = segmentPositions.count() - 1;
+ const int max = segmentPositions.size() - 1;
int currentValue = qBound(0, horizontalScrollBar()->value(), max);
int position = segmentPositions.at(currentValue);
int maximumValue = qBound(0, horizontalScrollBar()->maximum(), max);
@@ -2308,13 +2386,13 @@ int QListModeViewBase::verticalOffset() const
if (isWrapping()) {
if (flow() == QListView::LeftToRight && !segmentPositions.isEmpty()) {
int value = verticalScrollBar()->value();
- if (value >= segmentPositions.count())
+ if (value >= segmentPositions.size())
return 0;
return segmentPositions.at(value) - spacing();
}
} else if (flow() == QListView::TopToBottom && !flowPositions.isEmpty()) {
int value = verticalScrollBar()->value();
- if (value > scrollValueMap.count())
+ if (value > scrollValueMap.size())
return 0;
return flowPositions.at(scrollValueMap.at(value)) - spacing();
}
@@ -2332,7 +2410,7 @@ int QListModeViewBase::horizontalScrollToValue(int index, QListView::ScrollHint
if (scrollValueMap.isEmpty())
value = 0;
else
- value = qBound(0, scrollValueMap.at(horizontalScrollBar()->value()), flowPositions.count() - 1);
+ value = qBound(0, scrollValueMap.at(horizontalScrollBar()->value()), flowPositions.size() - 1);
if (leftOf)
hint = QListView::PositionAtTop;
else if (rightOf)
@@ -2354,7 +2432,7 @@ void QListModeViewBase::scrollContentsBy(int dx, int dy, bool scrollElasticBand)
if (isWrapping()) {
if (segmentPositions.isEmpty())
return;
- const int max = segmentPositions.count() - 1;
+ const int max = segmentPositions.size() - 1;
if (horizontal && flow() == QListView::TopToBottom && dx != 0) {
int currentValue = qBound(0, horizontalValue, max);
int previousValue = qBound(0, currentValue + dx, max);
@@ -2371,7 +2449,7 @@ void QListModeViewBase::scrollContentsBy(int dx, int dy, bool scrollElasticBand)
} else {
if (flowPositions.isEmpty())
return;
- const int max = scrollValueMap.count() - 1;
+ const int max = scrollValueMap.size() - 1;
if (vertical && flow() == QListView::TopToBottom && dy != 0) {
int currentValue = qBound(0, verticalValue, max);
int previousValue = qBound(0, currentValue + dy, max);
@@ -2399,14 +2477,15 @@ QListViewItem QListModeViewBase::indexToListViewItem(const QModelIndex &index) c
{
if (flowPositions.isEmpty()
|| segmentPositions.isEmpty()
- || index.row() >= flowPositions.count() - 1)
+ || index.row() >= flowPositions.size() - 1)
return QListViewItem();
const int segment = qBinarySearch<int>(segmentStartRows, index.row(),
- 0, segmentStartRows.count() - 1);
+ 0, segmentStartRows.size() - 1);
- QStyleOptionViewItem options = viewOptions();
+ QStyleOptionViewItem options;
+ initViewItemOption(&options);
options.rect.setSize(contentsSize);
QSize size = (uniformItemSizes() && cachedItemSize().isValid())
? cachedItemSize() : itemSize(options, index);
@@ -2420,7 +2499,7 @@ QListViewItem QListModeViewBase::indexToListViewItem(const QModelIndex &index) c
pos.setY(flowPositions.at(index.row()));
pos.setX(segmentPositions.at(segment));
if (isWrapping()) { // make the items as wide as the segment
- int right = (segment + 1 >= segmentPositions.count()
+ int right = (segment + 1 >= segmentPositions.size()
? contentsSize.width()
: segmentPositions.at(segment + 1));
cellSize.setWidth(right - pos.x());
@@ -2482,7 +2561,8 @@ void QListModeViewBase::doStaticLayout(const QListViewLayoutInfo &info)
{
const bool useItemSize = !info.grid.isValid();
const QPoint topLeft = initStaticLayout(info);
- QStyleOptionViewItem option = viewOptions();
+ QStyleOptionViewItem option;
+ initViewItemOption(&option);
option.rect = info.bounds;
option.rect.adjust(info.spacing, info.spacing, -info.spacing, -info.spacing);
@@ -2543,7 +2623,7 @@ void QListModeViewBase::doStaticLayout(const QListViewLayoutInfo &info)
deltaSegPosition = 0;
}
// save the flow position of this item
- scrollValueMap.append(flowPositions.count());
+ scrollValueMap.append(flowPositions.size());
flowPositions.append(flowPosition);
// prepare for the next item
deltaSegPosition = qMax(deltaSegHint, deltaSegPosition);
@@ -2559,21 +2639,21 @@ void QListModeViewBase::doStaticLayout(const QListViewLayoutInfo &info)
// set the contents size
QRect rect = info.bounds;
if (info.flow == QListView::LeftToRight) {
- rect.setRight(segmentPositions.count() == 1 ? flowPosition : info.bounds.right());
+ rect.setRight(segmentPositions.size() == 1 ? flowPosition : info.bounds.right());
rect.setBottom(segPosition + deltaSegPosition);
} else { // TopToBottom
rect.setRight(segPosition + deltaSegPosition);
- rect.setBottom(segmentPositions.count() == 1 ? flowPosition : info.bounds.bottom());
+ rect.setBottom(segmentPositions.size() == 1 ? flowPosition : info.bounds.bottom());
}
contentsSize = QSize(rect.right(), rect.bottom());
// if it is the last batch, save the end of the segments
if (info.last == info.max) {
segmentExtents.append(flowPosition);
- scrollValueMap.append(flowPositions.count());
+ scrollValueMap.append(flowPositions.size());
flowPositions.append(flowPosition);
segmentPositions.append(info.wrap ? segPosition + deltaSegPosition : INT_MAX);
}
- // if the new items are visble, update the viewport
+ // if the new items are visible, update the viewport
QRect changedRect(topLeft, rect.bottomRight());
if (clipRect().intersects(changedRect))
viewport()->update();
@@ -2584,9 +2664,9 @@ void QListModeViewBase::doStaticLayout(const QListViewLayoutInfo &info)
Finds the set of items intersecting with \a area.
In this function, itemsize is counted from topleft to the start of the next item.
*/
-QVector<QModelIndex> QListModeViewBase::intersectingSet(const QRect &area) const
+QList<QModelIndex> QListModeViewBase::intersectingSet(const QRect &area) const
{
- QVector<QModelIndex> ret;
+ QList<QModelIndex> ret;
int segStartPosition;
int segEndPosition;
int flowStartPosition;
@@ -2602,10 +2682,10 @@ QVector<QModelIndex> QListModeViewBase::intersectingSet(const QRect &area) const
flowStartPosition = area.top();
flowEndPosition = area.bottom();
}
- if (segmentPositions.count() < 2 || flowPositions.isEmpty())
+ if (segmentPositions.size() < 2 || flowPositions.isEmpty())
return ret;
// the last segment position is actually the edge of the last segment
- const int segLast = segmentPositions.count() - 2;
+ const int segLast = segmentPositions.size() - 2;
int seg = qBinarySearch<int>(segmentPositions, segStartPosition, 0, segLast + 1);
for (; seg <= segLast && segmentPositions.at(seg) <= segEndPosition; ++seg) {
int first = segmentStartRows.at(seg);
@@ -2663,7 +2743,7 @@ QRect QListModeViewBase::mapToViewport(const QRect &rect) const
int QListModeViewBase::perItemScrollingPageSteps(int length, int bounds, bool wrap) const
{
- QVector<int> positions;
+ QList<int> positions;
if (wrap)
positions = segmentPositions;
else if (!flowPositions.isEmpty()) {
@@ -2672,15 +2752,15 @@ int QListModeViewBase::perItemScrollingPageSteps(int length, int bounds, bool wr
positions.append(flowPositions.at(itemShown));
}
if (positions.isEmpty() || bounds <= length)
- return positions.count();
+ return positions.size();
if (uniformItemSizes()) {
- for (int i = 1; i < positions.count(); ++i)
+ for (int i = 1; i < positions.size(); ++i)
if (positions.at(i) > 0)
return length / positions.at(i);
return 0; // all items had height 0
}
int pageSteps = 0;
- int steps = positions.count() - 1;
+ int steps = positions.size() - 1;
int max = qMax(length, bounds);
int min = qMin(length, bounds);
int pos = min - (max - positions.constLast());
@@ -2704,21 +2784,24 @@ int QListModeViewBase::perItemScrollToValue(int index, int scrollValue, int view
return scrollValue;
itemExtent += spacing();
- QVector<int> visibleFlowPositions;
- visibleFlowPositions.reserve(flowPositions.count() - 1);
- for (int i = 0; i < flowPositions.count() - 1; i++) { // flowPositions count is +1 larger than actual row count
- if (!isHidden(i))
- visibleFlowPositions.append(flowPositions.at(i));
- }
-
+ QList<int> hiddenRows = dd->hiddenRowIds();
+ std::sort(hiddenRows.begin(), hiddenRows.end());
+ int hiddenRowsBefore = 0;
+ for (int i = 0; i < hiddenRows.size() - 1; ++i)
+ if (hiddenRows.at(i) > index + hiddenRowsBefore)
+ break;
+ else
+ ++hiddenRowsBefore;
if (!wrap) {
int topIndex = index;
const int bottomIndex = topIndex;
- const int bottomCoordinate = visibleFlowPositions.at(index);
-
+ const int bottomCoordinate = flowPositions.at(index + hiddenRowsBefore);
while (topIndex > 0 &&
- (bottomCoordinate - visibleFlowPositions.at(topIndex - 1) + itemExtent) <= (viewportSize)) {
+ (bottomCoordinate - flowPositions.at(topIndex + hiddenRowsBefore - 1) + itemExtent) <= (viewportSize)) {
topIndex--;
+ // will the next one be a hidden row -> skip
+ while (hiddenRowsBefore > 0 && hiddenRows.at(hiddenRowsBefore - 1) >= topIndex + hiddenRowsBefore - 1)
+ hiddenRowsBefore--;
}
const int itemCount = bottomIndex - topIndex + 1;
@@ -2737,9 +2820,9 @@ int QListModeViewBase::perItemScrollToValue(int index, int scrollValue, int view
? Qt::Horizontal : Qt::Vertical);
if (flowOrientation == orientation) { // scrolling in the "flow" direction
// ### wrapped scrolling in the flow direction
- return visibleFlowPositions.at(index); // ### always pixel based for now
+ return flowPositions.at(index + hiddenRowsBefore); // ### always pixel based for now
} else if (!segmentStartRows.isEmpty()) { // we are scrolling in the "segment" direction
- int segment = qBinarySearch<int>(segmentStartRows, index, 0, segmentStartRows.count() - 1);
+ int segment = qBinarySearch<int>(segmentStartRows, index, 0, segmentStartRows.size() - 1);
int leftSegment = segment;
const int rightSegment = leftSegment;
const int bottomCoordinate = segmentPositions.at(segment);
@@ -2782,7 +2865,7 @@ void QListModeViewBase::clear()
void QIconModeViewBase::setPositionForIndex(const QPoint &position, const QModelIndex &index)
{
- if (index.row() >= items.count())
+ if (index.row() >= items.size())
return;
const QSize oldContents = contentsSize;
qq->update(index); // update old position
@@ -2795,7 +2878,7 @@ void QIconModeViewBase::setPositionForIndex(const QPoint &position, const QModel
void QIconModeViewBase::appendHiddenRow(int row)
{
- if (row >= 0 && row < items.count()) //remove item
+ if (row >= 0 && row < items.size()) //remove item
tree.removeLeaf(items.at(row).rect(), row);
QCommonListViewBase::appendHiddenRow(row);
}
@@ -2803,7 +2886,7 @@ void QIconModeViewBase::appendHiddenRow(int row)
void QIconModeViewBase::removeHiddenRow(int row)
{
QCommonListViewBase::removeHiddenRow(row);
- if (row >= 0 && row < items.count()) //insert item
+ if (row >= 0 && row < items.size()) //insert item
tree.insertLeaf(items.at(row).rect(), row);
}
@@ -2814,7 +2897,7 @@ bool QIconModeViewBase::filterStartDrag(Qt::DropActions supportedActions)
// plus adding viewitems to the draggedItems list.
// We need these items to draw the drag items
QModelIndexList indexes = dd->selectionModel->selectedIndexes();
- if (indexes.count() > 0 ) {
+ if (indexes.size() > 0 ) {
if (viewport()->acceptDrops()) {
QModelIndexList::ConstIterator it = indexes.constBegin();
for (; it != indexes.constEnd(); ++it)
@@ -2830,12 +2913,15 @@ bool QIconModeViewBase::filterStartDrag(Qt::DropActions supportedActions)
drag->setMimeData(dd->model->mimeData(indexes));
drag->setPixmap(pixmap);
drag->setHotSpot(dd->pressedPosition - rect.topLeft());
+ dd->dropEventMoved = false;
Qt::DropAction action = drag->exec(supportedActions, dd->defaultDropAction);
draggedItems.clear();
- // for internal moves the action was set to Qt::CopyAction in
- // filterDropEvent() to avoid the deletion here
- if (action == Qt::MoveAction)
- dd->clearOrRemove();
+ // delete item, unless it has already been moved internally (see filterDropEvent)
+ if (action == Qt::MoveAction && !dd->dropEventMoved) {
+ if (dd->dragDropMode != QAbstractItemView::InternalMove || drag->target() == qq->viewport())
+ dd->clearOrRemove();
+ }
+ dd->dropEventMoved = false;
}
return true;
}
@@ -2847,10 +2933,10 @@ bool QIconModeViewBase::filterDropEvent(QDropEvent *e)
const QSize contents = contentsSize;
QPoint offset(horizontalOffset(), verticalOffset());
- QPoint end = e->pos() + offset;
+ QPoint end = e->position().toPoint() + offset;
if (qq->acceptDrops()) {
const Qt::ItemFlags dropableFlags = Qt::ItemIsDropEnabled|Qt::ItemIsEnabled;
- const QVector<QModelIndex> &dropIndices = intersectingSet(QRect(end, QSize(1, 1)));
+ const QList<QModelIndex> &dropIndices = intersectingSet(QRect(end, QSize(1, 1)));
for (const QModelIndex &index : dropIndices)
if ((index.flags() & dropableFlags) == dropableFlags)
return false;
@@ -2871,9 +2957,9 @@ bool QIconModeViewBase::filterDropEvent(QDropEvent *e)
draggedItems.clear();
dd->emitIndexesMoved(indexes);
// do not delete item on internal move, see filterStartDrag()
- e->setDropAction(Qt::CopyAction);
+ dd->dropEventMoved = true;
e->accept(); // we have handled the event
- // if the size has not grown, we need to check if it has shrinked
+ // if the size has not grown, we need to check if it has shrunk
if (contentsSize != contents) {
if ((contentsSize.width() <= contents.width()
|| contentsSize.height() <= contents.height())) {
@@ -2908,17 +2994,17 @@ bool QIconModeViewBase::filterDragMoveEvent(QDragMoveEvent *e)
QRect itemsRect = this->itemsRect(draggedItems);
viewport()->update(itemsRect.translated(draggedItemsDelta()));
// update position
- draggedItemsPos = e->pos();
+ draggedItemsPos = e->position().toPoint();
// get new items rect
viewport()->update(itemsRect.translated(draggedItemsDelta()));
// set the item under the cursor to current
QModelIndex index;
if (movement() == QListView::Snap) {
- QRect rect(snapToGrid(e->pos() + offset()), gridSize());
- const QVector<QModelIndex> intersectVector = intersectingSet(rect);
- index = intersectVector.count() > 0 ? intersectVector.last() : QModelIndex();
+ QRect rect(snapToGrid(e->position().toPoint() + offset()), gridSize());
+ const QList<QModelIndex> intersectVector = intersectingSet(rect);
+ index = intersectVector.size() > 0 ? intersectVector.last() : QModelIndex();
} else {
- index = qq->indexAt(e->pos());
+ index = qq->indexAt(e->position().toPoint());
}
// check if we allow drops here
if (draggedItems.contains(index))
@@ -2929,7 +3015,7 @@ bool QIconModeViewBase::filterDragMoveEvent(QDragMoveEvent *e)
e->accept(); // allow dropping in empty areas
// the event was treated. do autoscrolling
- if (dd->shouldAutoScroll(e->pos()))
+ if (dd->shouldAutoScroll(e->position().toPoint()))
dd->startAutoScroll();
return true;
}
@@ -2953,8 +3039,9 @@ void QIconModeViewBase::scrollContentsBy(int dx, int dy, bool scrollElasticBand)
void QIconModeViewBase::dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight)
{
if (column() >= topLeft.column() && column() <= bottomRight.column()) {
- const QStyleOptionViewItem option = viewOptions();
- const int bottom = qMin(items.count(), bottomRight.row() + 1);
+ QStyleOptionViewItem option;
+ initViewItemOption(&option);
+ const int bottom = qMin(items.size(), bottomRight.row() + 1);
const bool useItemSize = !dd->grid.isValid();
for (int row = topLeft.row(); row < bottom; ++row)
{
@@ -2971,10 +3058,11 @@ void QIconModeViewBase::dataChanged(const QModelIndex &topLeft, const QModelInde
bool QIconModeViewBase::doBatchedItemLayout(const QListViewLayoutInfo &info, int max)
{
- if (info.last >= items.count()) {
+ if (info.last >= items.size()) {
//first we create the items
- QStyleOptionViewItem option = viewOptions();
- for (int row = items.count(); row <= info.last; ++row) {
+ QStyleOptionViewItem option;
+ initViewItemOption(&option);
+ for (int row = items.size(); row <= info.last; ++row) {
QSize size = itemSize(option, modelIndex(row));
QListViewItem item(QRect(0, 0, size.width(), size.height()), row); // default pos
items.append(item);
@@ -2986,7 +3074,7 @@ bool QIconModeViewBase::doBatchedItemLayout(const QListViewLayoutInfo &info, int
QListViewItem QIconModeViewBase::indexToListViewItem(const QModelIndex &index) const
{
- if (index.isValid() && index.row() < items.count())
+ if (index.isValid() && index.row() < items.size())
return items.at(index.row());
return QListViewItem();
}
@@ -3064,11 +3152,12 @@ void QIconModeViewBase::doDynamicLayout(const QListViewLayoutInfo &info)
segPosition = topLeft.x();
}
- if (moved.count() != items.count())
- moved.resize(items.count());
+ if (moved.size() != items.size())
+ moved.resize(items.size());
QRect rect(QPoint(), topLeft);
- QListViewItem *item = 0;
+ QListViewItem *item = nullptr;
+ Q_ASSERT(info.first <= info.last);
for (int row = info.first; row <= info.last; ++row) {
item = &items[row];
if (isHidden(row)) {
@@ -3139,6 +3228,7 @@ void QIconModeViewBase::doDynamicLayout(const QListViewLayoutInfo &info)
flowPosition += deltaFlowPosition; // current position + item width + gap
}
}
+ Q_ASSERT(item);
batchSavedDeltaSeg = deltaSegPosition;
batchStartRow = info.last + 1;
bool done = (info.last >= rowCount() - 1);
@@ -3161,32 +3251,28 @@ void QIconModeViewBase::doDynamicLayout(const QListViewLayoutInfo &info)
// insert items in tree
for (int row = insertFrom; row <= info.last; ++row)
tree.insertLeaf(items.at(row).rect(), row);
- // if the new items are visble, update the viewport
+ // if the new items are visible, update the viewport
QRect changedRect(topLeft, rect.bottomRight());
if (clipRect().intersects(changedRect))
viewport()->update();
}
-QVector<QModelIndex> QIconModeViewBase::intersectingSet(const QRect &area) const
+QList<QModelIndex> QIconModeViewBase::intersectingSet(const QRect &area) const
{
QIconModeViewBase *that = const_cast<QIconModeViewBase*>(this);
QBspTree::Data data(static_cast<void*>(that));
- QVector<QModelIndex> res;
+ QList<QModelIndex> res;
that->interSectingVector = &res;
that->tree.climbTree(area, &QIconModeViewBase::addLeaf, data);
- that->interSectingVector = 0;
+ that->interSectingVector = nullptr;
return res;
}
-QRect QIconModeViewBase::itemsRect(const QVector<QModelIndex> &indexes) const
+QRect QIconModeViewBase::itemsRect(const QList<QModelIndex> &indexes) const
{
- QVector<QModelIndex>::const_iterator it = indexes.begin();
- QListViewItem item = indexToListViewItem(*it);
- QRect rect(item.x, item.y, item.w, item.h);
- for (; it != indexes.end(); ++it) {
- item = indexToListViewItem(*it);
- rect |= viewItemRect(item);
- }
+ QRect rect;
+ for (const auto &index : indexes)
+ rect |= viewItemRect(indexToListViewItem(index));
return rect;
}
@@ -3195,15 +3281,15 @@ int QIconModeViewBase::itemIndex(const QListViewItem &item) const
if (!item.isValid())
return -1;
int i = item.indexHint;
- if (i < items.count()) {
+ if (i < items.size()) {
if (items.at(i) == item)
return i;
} else {
- i = items.count() - 1;
+ i = items.size() - 1;
}
int j = i;
- int c = items.count();
+ int c = items.size();
bool a = true;
bool b = true;
@@ -3226,14 +3312,14 @@ int QIconModeViewBase::itemIndex(const QListViewItem &item) const
return -1;
}
-void QIconModeViewBase::addLeaf(QVector<int> &leaf, const QRect &area,
- uint visited, QBspTree::Data data)
+void QIconModeViewBase::addLeaf(QList<int> &leaf, const QRect &area, uint visited,
+ QBspTree::Data data)
{
QListViewItem *vi;
QIconModeViewBase *_this = static_cast<QIconModeViewBase *>(data.ptr);
- for (int i = 0; i < leaf.count(); ++i) {
+ for (int i = 0; i < leaf.size(); ++i) {
int idx = leaf.at(i);
- if (idx < 0 || idx >= _this->items.count())
+ if (idx < 0 || idx >= _this->items.size())
continue;
vi = &_this->items[idx];
Q_ASSERT(vi);
@@ -3261,8 +3347,8 @@ void QIconModeViewBase::moveItem(int index, const QPoint &dest)
contentsSize = (QRect(QPoint(0, 0), contentsSize)|QRect(dest, rect.size())).size();
// mark the item as moved
- if (moved.count() != items.count())
- moved.resize(items.count());
+ if (moved.size() != items.size())
+ moved.resize(items.size());
moved.setBit(index, true);
}
@@ -3314,7 +3400,7 @@ void QIconModeViewBase::clear()
void QIconModeViewBase::updateContentsSize()
{
QRect bounding;
- for (int i = 0; i < items.count(); ++i)
+ for (int i = 0; i < items.size(); ++i)
bounding |= items.at(i).rect();
contentsSize = bounding.size();
}
@@ -3324,9 +3410,10 @@ void QIconModeViewBase::updateContentsSize()
*/
void QListView::currentChanged(const QModelIndex &current, const QModelIndex &previous)
{
-#ifndef QT_NO_ACCESSIBILITY
+ QAbstractItemView::currentChanged(current, previous);
+#if QT_CONFIG(accessibility)
if (QAccessible::isActive()) {
- if (current.isValid()) {
+ if (current.isValid() && hasFocus()) {
int entry = visualIndex(current);
QAccessibleEvent event(this, QAccessible::Focus);
event.setChild(entry);
@@ -3334,7 +3421,6 @@ void QListView::currentChanged(const QModelIndex &current, const QModelIndex &pr
}
}
#endif
- QAbstractItemView::currentChanged(current, previous);
}
/*!
@@ -3343,7 +3429,7 @@ void QListView::currentChanged(const QModelIndex &current, const QModelIndex &pr
void QListView::selectionChanged(const QItemSelection &selected,
const QItemSelection &deselected)
{
-#ifndef QT_NO_ACCESSIBILITY
+#if QT_CONFIG(accessibility)
if (QAccessible::isActive()) {
// ### does not work properly for selection ranges.
QModelIndex sel = selected.indexes().value(0);
@@ -3371,9 +3457,9 @@ int QListView::visualIndex(const QModelIndex &index) const
d->executePostedLayout();
QListViewItem itm = d->indexToListViewItem(index);
int visualIndex = d->commonListView->itemIndex(itm);
- for (int row = 0; row <= index.row() && visualIndex >= 0; row++) {
- if (d->isHidden(row))
- visualIndex--;
+ for (const auto &idx : std::as_const(d->hiddenRows)) {
+ if (idx.row() <= index.row())
+ --visualIndex;
}
return visualIndex;
}
@@ -3385,7 +3471,47 @@ int QListView::visualIndex(const QModelIndex &index) const
*/
QSize QListView::viewportSizeHint() const
{
- return QAbstractItemView::viewportSizeHint();
+ Q_D(const QListView);
+ // We don't have a nice simple size hint for invalid or wrapping list views.
+ if (!d->model)
+ return QAbstractItemView::viewportSizeHint();
+ const int rc = d->model->rowCount();
+ if (rc == 0 || isWrapping())
+ return QAbstractItemView::viewportSizeHint();
+
+ QStyleOptionViewItem option;
+ initViewItemOption(&option);
+
+ if (uniformItemSizes()) {
+ QSize sz = d->cachedItemSize;
+ if (!sz.isValid()) {
+ QModelIndex idx = d->model->index(0, d->column, d->root);
+ sz = d->itemSize(option, idx);
+ }
+ sz.setHeight(rc * sz.height());
+ return sz;
+ }
+
+ // Using AdjustToContents with a high number of rows will normally not make sense, so we limit
+ // this to default 1000 (that is btw the default for QHeaderView::resizeContentsPrecision())
+ // (By setting the property _q_resizeContentPrecision the user can however override this).
+ int maximumRows = 1000;
+ const QVariant userOverrideValue = property("_q_resizeContentPrecision");
+ if (userOverrideValue.isValid() && userOverrideValue.toInt() > 0) {
+ maximumRows = userOverrideValue.toInt();
+ }
+ const int rowCount = qMin(rc, maximumRows);
+
+ int h = 0;
+ int w = 0;
+
+ for (int row = 0; row < rowCount; ++row) {
+ QModelIndex idx = d->model->index(row, d->column, d->root);
+ QSize itemSize = d->itemSize(option, idx);
+ h += itemSize.height();
+ w = qMax(w, itemSize.width());
+ }
+ return QSize(w, h);
}
QT_END_NAMESPACE