Currently, I'm trying to get five items from a QSortFilterProxyModel
after I sort the model.
I tried to do this:
void setSourceModel(QAbstractItemModel* source) override
{
QSortFilterProxyModel::setSourceModel(source);
auto* model{sourceModel()};
model->sort(1);
}
and then:
bool filterAcceptsRow(int sourceRow, const QModelIndex& sourceParent) const override
{
return sourceRow < 5;
}
But that didn't work. I get the first 5 items in the unsorted source model, instead of the first 5 items of the sorted model.
Can someone help me out?
As was stated in the comments, not all models support sorting (The base implementation QAbstractItemModel::sort
is documented to do nothing).
Of course, you can override sort
for your source model. Hopefully, there are at least 2 solutions to solve your problem without bothering with it.
1. Using more than 1 level of proxy model:
Instances of QSortFilterProxyModel
can sort data regardless of what their source model is.
setSourceModel
so that instead of attaching source
directly to this
, we place another QSortFilterProxyModel
in between.this->sourceModel()
supports sorting.void setSourceModel(QAbstractItemModel* source) override
{
QSortFilterProxyModel* sortModel = new QSortFilterProxyModel(this);
sortModel->setSourceModel(source);
setSourceModel(sortModel);
sortModel->sort(1);
}
bool filterAcceptsRow(int sourceRow, const QModelIndex& sourceParent) const override
{
return sourceRow < 5;
}
2. With a QIdentityProxyModel
:
The above solution builds 3 layers of models:QSortFilterProxyModel
subclass (filter) > QSortFilterProxyModel
(sort) > QAbstractItemModel
.
Your filter criterion is a little bit special in the sense it does not use the data
method from its source. Since this is the case, you may as well extend the definition of what we call filtering and implement the layers as:QIdentityProxyModel
subclass (filter) > QSortFilterProxyModel
(sort) > QAbstractItemModel
.
Inheriting QIdentityProxyModel
with the below methods should make your model a little bit faster, although the difference may not be visible at all:
void setSourceModel(QAbstractItemModel* source) override
{
QSortFilterProxyModel* sortModel = new QSortFilterProxyModel(this);
sortModel->setSourceModel(source);
setSourceModel(sortModel);
sortModel->sort(1);
}
int rowCount(const QModelIndex &parent = QModelIndex()) const override
{
//Should parent be tested?
//if (!parent.isValid())
return 5;
}
This is probably all you need. To be safe, you may choose to add the mapFromSource
/ mapSelectionFromSource
methods (and as a bonus, I also include mapToSource
/ mapSelectionToSource
even though I really think those last 2 are not needed):
QModelIndex mapFromSource(const QModelIndex &sourceIndex) const override
{
if (sourceIndex.row() >= 5)
return QModelIndex();
return QIdentityProxyModel::mapFromSource(sourceIndex);
}
QItemSelection mapSelectionFromSource(const QItemSelection& selection) const
{
QItemSelection proxySelection;
for (auto selRange : selection) {
QModelIndex topLeftIndex = selRange.topLeft();
if (topLeftIndex.row() < 5) {
QModelIndex bottomRightIndex = it->bottomRight();
if (bottomRightIndex.row() < 5) {
const QItemSelectionRange range(
QIdentityProxyModel::mapFromSource(topLeftIndex),
QIdentityProxyModel::mapFromSource(bottomRightIndex)
);
proxySelection.append(range);
}
else {
const QItemSelectionRange range(
QIdentityProxyModel::mapFromSource(topLeftIndex),
QIdentityProxyModel::mapFromSource(bottomRightIndex.siblingAtRow(4))
);
proxySelection.append(range);
}
}
}
return proxySelection;
}
QModelIndex mapToSource(const QModelIndex &proxyIndex) const override
{
if (proxyIndex.row() >= 5)
return QModelIndex();
return QIdentityProxyModel::mapToSource(proxyIndex);
}
QItemSelection mapSelectionToSource(const QItemSelection& selection) const
{
QItemSelection sourceSelection;
for (auto selRange : selection) {
QModelIndex topLeftIndex = selRange.topLeft();
if (topLeftIndex.row() < 5) {
QModelIndex bottomRightIndex = it->bottomRight();
if (bottomRightIndex.row() < 5) {
const QItemSelectionRange range(
QIdentityProxyModel::mapToSource(topLeftIndex),
QIdentityProxyModel::mapToSource(bottomRightIndex)
);
sourceSelection.append(range);
}
else {
const QItemSelectionRange range(
QIdentityProxyModel::mapToSource(topLeftIndex),
QIdentityProxyModel::mapToSource(bottomRightIndex.siblingAtRow(4))
);
sourceSelection.append(range);
}
}
}
return sourceSelection;
}