diff options
Diffstat (limited to 'src/widgets/itemviews/qlistwidget.cpp')
-rw-r--r-- | src/widgets/itemviews/qlistwidget.cpp | 285 |
1 files changed, 126 insertions, 159 deletions
diff --git a/src/widgets/itemviews/qlistwidget.cpp b/src/widgets/itemviews/qlistwidget.cpp index ca7439b08c..a91902813a 100644 --- a/src/widgets/itemviews/qlistwidget.cpp +++ b/src/widgets/itemviews/qlistwidget.cpp @@ -1,45 +1,8 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** 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. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #include "qlistwidget.h" -#include <qitemdelegate.h> #include <private/qlistview_p.h> #include <private/qwidgetitemdata_p.h> #include <private/qlistwidget_p.h> @@ -72,7 +35,7 @@ QListModel::~QListModel() void QListModel::clear() { beginResetModel(); - for (int i = 0; i < items.count(); ++i) { + for (int i = 0; i < items.size(); ++i) { if (items.at(i)) { items.at(i)->d->theid = -1; items.at(i)->view = nullptr; @@ -116,8 +79,8 @@ void QListModel::insert(int row, QListWidgetItem *item) } else { if (row < 0) row = 0; - else if (row > items.count()) - row = items.count(); + else if (row > items.size()) + row = items.size(); } beginInsertRows(QModelIndex(), row, row); items.insert(row, item); @@ -127,7 +90,7 @@ void QListModel::insert(int row, QListWidgetItem *item) void QListModel::insert(int row, const QStringList &labels) { - const int count = labels.count(); + const int count = labels.size(); if (count <= 0) return; QListWidget *view = qobject_cast<QListWidget*>(QObject::parent()); @@ -140,8 +103,8 @@ void QListModel::insert(int row, const QStringList &labels) } else { if (row < 0) row = 0; - else if (row > items.count()) - row = items.count(); + else if (row > items.size()) + row = items.size(); beginInsertRows(QModelIndex(), row, row + count - 1); for (int i = 0; i < count; ++i) { QListWidgetItem *item = new QListWidgetItem(labels.at(i)); @@ -155,7 +118,7 @@ void QListModel::insert(int row, const QStringList &labels) QListWidgetItem *QListModel::take(int row) { - if (row < 0 || row >= items.count()) + if (row < 0 || row >= items.size()) return nullptr; beginRemoveRows(QModelIndex(), row, row); @@ -169,8 +132,8 @@ QListWidgetItem *QListModel::take(int row) void QListModel::move(int srcRow, int dstRow) { if (srcRow == dstRow - || srcRow < 0 || srcRow >= items.count() - || dstRow < 0 || dstRow > items.count()) + || srcRow < 0 || srcRow >= items.size() + || dstRow < 0 || dstRow > items.size()) return; if (!beginMoveRows(QModelIndex(), srcRow, srcRow, QModelIndex(), dstRow)) @@ -183,7 +146,7 @@ void QListModel::move(int srcRow, int dstRow) int QListModel::rowCount(const QModelIndex &parent) const { - return parent.isValid() ? 0 : items.count(); + return parent.isValid() ? 0 : items.size(); } QModelIndex QListModel::index(const QListWidgetItem *item_) const @@ -194,7 +157,7 @@ QModelIndex QListModel::index(const QListWidgetItem *item_) const return QModelIndex(); int row; const int theid = item->d->theid; - if (theid >= 0 && theid < items.count() && items.at(theid) == item) { + if (theid >= 0 && theid < items.size() && items.at(theid) == item) { row = theid; } else { // we need to search for the item row = items.lastIndexOf(item); // lastIndexOf is an optimization in favor of indexOf @@ -214,14 +177,14 @@ QModelIndex QListModel::index(int row, int column, const QModelIndex &parent) co QVariant QListModel::data(const QModelIndex &index, int role) const { - if (!index.isValid() || index.row() >= items.count()) + if (!index.isValid() || index.row() >= items.size()) return QVariant(); return items.at(index.row())->data(role); } bool QListModel::setData(const QModelIndex &index, const QVariant &value, int role) { - if (!index.isValid() || index.row() >= items.count()) + if (!index.isValid() || index.row() >= items.size()) return false; items.at(index.row())->setData(role, value); return true; @@ -244,10 +207,10 @@ bool QListModel::clearItemData(const QModelIndex &index) QMap<int, QVariant> QListModel::itemData(const QModelIndex &index) const { QMap<int, QVariant> roles; - if (!index.isValid() || index.row() >= items.count()) + if (!index.isValid() || index.row() >= items.size()) return roles; QListWidgetItem *itm = items.at(index.row()); - for (int i = 0; i < itm->d->values.count(); ++i) { + for (int i = 0; i < itm->d->values.size(); ++i) { roles.insert(itm->d->values.at(i).role, itm->d->values.at(i).value); } @@ -324,7 +287,7 @@ bool QListModel::moveRows(const QModelIndex &sourceParent, int sourceRow, int co Qt::ItemFlags QListModel::flags(const QModelIndex &index) const { - if (!index.isValid() || index.row() >= items.count() || index.model() != this) + if (!index.isValid() || index.row() >= items.size() || index.model() != this) return Qt::ItemIsDropEnabled; // we allow drops outside the items return items.at(index.row())->flags(); } @@ -336,18 +299,18 @@ void QListModel::sort(int column, Qt::SortOrder order) emit layoutAboutToBeChanged({}, QAbstractItemModel::VerticalSortHint); - QList<QPair<QListWidgetItem *, int>> sorting(items.count()); - for (int i = 0; i < items.count(); ++i) { + QList<QPair<QListWidgetItem *, int>> sorting(items.size()); + for (int i = 0; i < items.size(); ++i) { QListWidgetItem *item = items.at(i); sorting[i].first = item; sorting[i].second = i; } const auto compare = (order == Qt::AscendingOrder ? &itemLessThan : &itemGreaterThan); - std::sort(sorting.begin(), sorting.end(), compare); + std::stable_sort(sorting.begin(), sorting.end(), compare); QModelIndexList fromIndexes; QModelIndexList toIndexes; - const int sortingCount = sorting.count(); + const int sortingCount = sorting.size(); fromIndexes.reserve(sortingCount); toIndexes.reserve(sortingCount); for (int r = 0; r < sortingCount; ++r) { @@ -364,72 +327,34 @@ void QListModel::sort(int column, Qt::SortOrder order) /** * This function assumes that all items in the model except the items that are between * (inclusive) start and end are sorted. - * With these assumptions, this function can ensure that the model is sorted in a - * much more efficient way than doing a naive 'sort everything'. - * (provided that the range is relatively small compared to the total number of items) */ void QListModel::ensureSorted(int column, Qt::SortOrder order, int start, int end) { if (column != 0) return; - int count = end - start + 1; - QList<QPair<QListWidgetItem *, int>> sorting(count); - for (int i = 0; i < count; ++i) { - sorting[i].first = items.at(start + i); - sorting[i].second = start + i; - } + const auto compareLt = [](const QListWidgetItem *left, const QListWidgetItem *right) -> bool { + return *left < *right; + }; - const auto compare = (order == Qt::AscendingOrder ? &itemLessThan : &itemGreaterThan); - std::sort(sorting.begin(), sorting.end(), compare); - - QModelIndexList oldPersistentIndexes = persistentIndexList(); - QModelIndexList newPersistentIndexes = oldPersistentIndexes; - QList<QListWidgetItem*> tmp = items; - QList<QListWidgetItem*>::iterator lit = tmp.begin(); - bool changed = false; - for (int i = 0; i < count; ++i) { - int oldRow = sorting.at(i).second; - int tmpitepos = lit - tmp.begin(); - QListWidgetItem *item = tmp.takeAt(oldRow); - if (tmpitepos > tmp.size()) - --tmpitepos; - lit = tmp.begin() + tmpitepos; - lit = sortedInsertionIterator(lit, tmp.end(), order, item); - int newRow = qMax<qsizetype>(lit - tmp.begin(), 0); - lit = tmp.insert(lit, item); - if (newRow != oldRow) { - changed = true; - for (int j = i + 1; j < count; ++j) { - int otherRow = sorting.at(j).second; - if (oldRow < otherRow && newRow >= otherRow) - --sorting[j].second; - else if (oldRow > otherRow && newRow <= otherRow) - ++sorting[j].second; - } - for (int k = 0; k < newPersistentIndexes.count(); ++k) { - QModelIndex pi = newPersistentIndexes.at(k); - int oldPersistentRow = pi.row(); - int newPersistentRow = oldPersistentRow; - if (oldPersistentRow == oldRow) - newPersistentRow = newRow; - else if (oldRow < oldPersistentRow && newRow >= oldPersistentRow) - newPersistentRow = oldPersistentRow - 1; - else if (oldRow > oldPersistentRow && newRow <= oldPersistentRow) - newPersistentRow = oldPersistentRow + 1; - if (newPersistentRow != oldPersistentRow) - newPersistentIndexes[k] = createIndex(newPersistentRow, - pi.column(), pi.internalPointer()); - } - } - } + const auto compareGt = [](const QListWidgetItem *left, const QListWidgetItem *right) -> bool { + return *right < *left; + }; - if (changed) { - emit layoutAboutToBeChanged(); - items = tmp; - changePersistentIndexList(oldPersistentIndexes, newPersistentIndexes); - emit layoutChanged(); - } + /** Check if range [start,end] is already in sorted position in list. + * Take for this the assumption, that outside [start,end] the list + * is already sorted. Therefore the sorted check has to be extended + * to the first element that is known to be sorted before the range + * [start, end], which is (start-1) and the first element after the + * range [start, end], which is (end+2) due to end being included. + */ + const auto beginChangedIterator = items.constBegin() + qMax(start - 1, 0); + const auto endChangedIterator = items.constBegin() + qMin(end + 2, items.size()); + const bool needsSorting = !std::is_sorted(beginChangedIterator, endChangedIterator, + order == Qt::AscendingOrder ? compareLt : compareGt); + + if (needsSorting) + sort(column, order); } bool QListModel::itemLessThan(const QPair<QListWidgetItem*,int> &left, @@ -476,7 +401,7 @@ QMimeData *QListModel::internalMimeData() const QMimeData *QListModel::mimeData(const QModelIndexList &indexes) const { QList<QListWidgetItem*> itemlist; - const int indexesCount = indexes.count(); + const int indexesCount = indexes.size(); itemlist.reserve(indexesCount); for (int i = 0; i < indexesCount; ++i) itemlist << at(indexes.at(i).row()); @@ -497,7 +422,7 @@ bool QListModel::dropMimeData(const QMimeData *data, Qt::DropAction action, if (index.isValid()) row = index.row(); else if (row == -1) - row = items.count(); + row = items.size(); return view->dropMimeData(row, data, action); } @@ -734,7 +659,7 @@ void QListWidgetItem::setData(int role, const QVariant &value) { bool found = false; role = (role == Qt::EditRole ? Qt::DisplayRole : role); - for (int i = 0; i < d->values.count(); ++i) { + for (int i = 0; i < d->values.size(); ++i) { if (d->values.at(i).role == role) { if (d->values.at(i).value == value) return; @@ -762,7 +687,7 @@ void QListWidgetItem::setData(int role, const QVariant &value) QVariant QListWidgetItem::data(int role) const { role = (role == Qt::EditRole ? Qt::DisplayRole : role); - for (int i = 0; i < d->values.count(); ++i) + for (int i = 0; i < d->values.size(); ++i) if (d->values.at(i).role == role) return d->values.at(i).value; return QVariant(); @@ -930,11 +855,24 @@ QDataStream &operator>>(QDataStream &in, QListWidgetItem &item) */ /*! + \if defined(qt7) + + \fn Qt::Alignment QListWidgetItem::textAlignment() const + + Returns the text alignment for the list item. + + \else + \fn int QListWidgetItem::textAlignment() const Returns the text alignment for the list item. - \sa Qt::AlignmentFlag + \note This function returns an int for historical reasons. It will + be corrected to return Qt::Alignment in Qt 7. + + \sa Qt::Alignment + + \endif */ /*! @@ -1088,11 +1026,26 @@ void QListWidgetItem::setFlags(Qt::ItemFlags aflags) */ /*! + \obsolete [6.4] Use the overload that takes a Qt::Alignment argument. + \fn void QListWidgetItem::setTextAlignment(int alignment) Sets the list item's text alignment to \a alignment. - \sa Qt::AlignmentFlag + \sa Qt::Alignment +*/ + +/*! + \since 6.4 + + \fn void QListWidgetItem::setTextAlignment(Qt::Alignment alignment) + + Sets the list item's text alignment to \a alignment. +*/ + +/*! + \fn void QListWidgetItem::setTextAlignment(Qt::AlignmentFlag alignment) + \internal */ /*! @@ -1130,57 +1083,71 @@ void QListWidgetPrivate::setup() Q_Q(QListWidget); q->QListView::setModel(new QListModel(q)); // view signals - QObject::connect(q, SIGNAL(pressed(QModelIndex)), q, SLOT(_q_emitItemPressed(QModelIndex))); - QObject::connect(q, SIGNAL(clicked(QModelIndex)), q, SLOT(_q_emitItemClicked(QModelIndex))); - QObject::connect(q, SIGNAL(doubleClicked(QModelIndex)), - q, SLOT(_q_emitItemDoubleClicked(QModelIndex))); - QObject::connect(q, SIGNAL(activated(QModelIndex)), - q, SLOT(_q_emitItemActivated(QModelIndex))); - QObject::connect(q, SIGNAL(entered(QModelIndex)), q, SLOT(_q_emitItemEntered(QModelIndex))); - QObject::connect(model, SIGNAL(dataChanged(QModelIndex,QModelIndex)), - q, SLOT(_q_emitItemChanged(QModelIndex))); - QObject::connect(model, SIGNAL(dataChanged(QModelIndex,QModelIndex)), - q, SLOT(_q_dataChanged(QModelIndex,QModelIndex))); - QObject::connect(model, SIGNAL(columnsRemoved(QModelIndex,int,int)), q, SLOT(_q_sort())); -} - -void QListWidgetPrivate::_q_emitItemPressed(const QModelIndex &index) + connections = { + QObjectPrivate::connect(q, &QListWidget::pressed, + this, &QListWidgetPrivate::emitItemPressed), + QObjectPrivate::connect(q, &QListWidget::clicked, + this, &QListWidgetPrivate::emitItemClicked), + QObjectPrivate::connect(q, &QListWidget::doubleClicked, + this, &QListWidgetPrivate::emitItemDoubleClicked), + QObjectPrivate::connect(q, &QListWidget::activated, + this, &QListWidgetPrivate::emitItemActivated), + QObjectPrivate::connect(q, &QListWidget::entered, + this, &QListWidgetPrivate::emitItemEntered), + QObjectPrivate::connect(model, &QAbstractItemModel::dataChanged, + this, &QListWidgetPrivate::emitItemChanged), + QObjectPrivate::connect(model, &QAbstractItemModel::dataChanged, + this, &QListWidgetPrivate::dataChanged), + QObjectPrivate::connect(model, &QAbstractItemModel::columnsRemoved, + this, &QListWidgetPrivate::sort) + }; +} + +void QListWidgetPrivate::clearConnections() +{ + for (const QMetaObject::Connection &connection : connections) + QObject::disconnect(connection); + for (const QMetaObject::Connection &connection : selectionModelConnections) + QObject::disconnect(connection); +} + +void QListWidgetPrivate::emitItemPressed(const QModelIndex &index) { Q_Q(QListWidget); emit q->itemPressed(listModel()->at(index.row())); } -void QListWidgetPrivate::_q_emitItemClicked(const QModelIndex &index) +void QListWidgetPrivate::emitItemClicked(const QModelIndex &index) { Q_Q(QListWidget); emit q->itemClicked(listModel()->at(index.row())); } -void QListWidgetPrivate::_q_emitItemDoubleClicked(const QModelIndex &index) +void QListWidgetPrivate::emitItemDoubleClicked(const QModelIndex &index) { Q_Q(QListWidget); emit q->itemDoubleClicked(listModel()->at(index.row())); } -void QListWidgetPrivate::_q_emitItemActivated(const QModelIndex &index) +void QListWidgetPrivate::emitItemActivated(const QModelIndex &index) { Q_Q(QListWidget); emit q->itemActivated(listModel()->at(index.row())); } -void QListWidgetPrivate::_q_emitItemEntered(const QModelIndex &index) +void QListWidgetPrivate::emitItemEntered(const QModelIndex &index) { Q_Q(QListWidget); emit q->itemEntered(listModel()->at(index.row())); } -void QListWidgetPrivate::_q_emitItemChanged(const QModelIndex &index) +void QListWidgetPrivate::emitItemChanged(const QModelIndex &index) { Q_Q(QListWidget); emit q->itemChanged(listModel()->at(index.row())); } -void QListWidgetPrivate::_q_emitCurrentItemChanged(const QModelIndex ¤t, +void QListWidgetPrivate::emitCurrentItemChanged(const QModelIndex ¤t, const QModelIndex &previous) { Q_Q(QListWidget); @@ -1198,14 +1165,14 @@ void QListWidgetPrivate::_q_emitCurrentItemChanged(const QModelIndex ¤t, emit q->currentRowChanged(persistentCurrent.row()); } -void QListWidgetPrivate::_q_sort() +void QListWidgetPrivate::sort() { if (sortingEnabled) model->sort(0, sortOrder); } -void QListWidgetPrivate::_q_dataChanged(const QModelIndex &topLeft, - const QModelIndex &bottomRight) +void QListWidgetPrivate::dataChanged(const QModelIndex &topLeft, + const QModelIndex &bottomRight) { if (sortingEnabled && topLeft.isValid() && bottomRight.isValid()) listModel()->ensureSorted(topLeft.column(), sortOrder, @@ -1411,6 +1378,8 @@ QListWidget::QListWidget(QWidget *parent) QListWidget::~QListWidget() { + Q_D(QListWidget); + d->clearConnections(); } /*! @@ -1421,20 +1390,18 @@ void QListWidget::setSelectionModel(QItemSelectionModel *selectionModel) { Q_D(QListWidget); - if (d->selectionModel) { - QObject::disconnect(d->selectionModel, SIGNAL(currentChanged(QModelIndex,QModelIndex)), - this, SLOT(_q_emitCurrentItemChanged(QModelIndex,QModelIndex))); - QObject::disconnect(d->selectionModel, SIGNAL(selectionChanged(QItemSelection,QItemSelection)), - this, SIGNAL(itemSelectionChanged())); - } + for (const QMetaObject::Connection &connection : d->selectionModelConnections) + disconnect(connection); QListView::setSelectionModel(selectionModel); if (d->selectionModel) { - QObject::connect(d->selectionModel, SIGNAL(currentChanged(QModelIndex,QModelIndex)), - this, SLOT(_q_emitCurrentItemChanged(QModelIndex,QModelIndex))); - QObject::connect(d->selectionModel, SIGNAL(selectionChanged(QItemSelection,QItemSelection)), - this, SIGNAL(itemSelectionChanged())); + d->selectionModelConnections = { + QObjectPrivate::connect(d->selectionModel, &QItemSelectionModel::currentChanged, + d, &QListWidgetPrivate::emitCurrentItemChanged), + QObject::connect(d->selectionModel, &QItemSelectionModel::selectionChanged, + this, &QListWidget::itemSelectionChanged) + }; } } @@ -1764,7 +1731,7 @@ QList<QListWidgetItem*> QListWidget::selectedItems() const Q_D(const QListWidget); QModelIndexList indexes = selectionModel()->selectedIndexes(); QList<QListWidgetItem*> items; - const int numIndexes = indexes.count(); + const int numIndexes = indexes.size(); items.reserve(numIndexes); for (int i = 0; i < numIndexes; ++i) items.append(d->listModel()->at(indexes.at(i).row())); @@ -1841,7 +1808,7 @@ QMimeData *QListWidget::mimeData(const QList<QListWidgetItem *> &items) const // if non empty, it's called from the model's own mimeData if (cachedIndexes.isEmpty()) { - cachedIndexes.reserve(items.count()); + cachedIndexes.reserve(items.size()); for (QListWidgetItem *item : items) cachedIndexes << indexFromItem(item); |