diff --git a/discover/PaginateModel.cpp b/discover/PaginateModel.cpp index 31437b9a..2ddf49bd 100644 --- a/discover/PaginateModel.cpp +++ b/discover/PaginateModel.cpp @@ -1,394 +1,394 @@ /* * Copyright (C) 2014 Aleix Pol Gonzalez * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library/Lesser General Public License * version 2, or (at your option) any later version, as published by the * Free Software Foundation * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details * * You should have received a copy of the GNU Library/Lesser General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "PaginateModel.h" #include #include PaginateModel::PaginateModel(QObject* object) : QAbstractListModel(object) , m_firstItem(0) , m_pageSize(10) , m_sourceModel(nullptr) , m_hasStaticRowCount(false) { } PaginateModel::~PaginateModel() { } int PaginateModel::firstItem() const { return m_firstItem; } void PaginateModel::setFirstItem(int row) { Q_ASSERT(row>=0 && rowrowCount()); if (row!=m_firstItem) { beginResetModel(); m_firstItem = row; endResetModel(); emit firstItemChanged(); } } int PaginateModel::pageSize() const { return m_pageSize; } void PaginateModel::setPageSize(int count) { if (count != m_pageSize) { const int oldSize = rowsByPageSize(m_pageSize); const int newSize = rowsByPageSize(count); const int difference = newSize - oldSize; if (difference==0) { m_pageSize = count; } else if(difference>0) { beginInsertRows(QModelIndex(), m_pageSize, m_pageSize+difference-1); m_pageSize = count; endInsertRows(); } else { beginRemoveRows(QModelIndex(), m_pageSize+difference, m_pageSize-1); m_pageSize = count; endRemoveRows(); } emit pageSizeChanged(); } } QAbstractItemModel* PaginateModel::sourceModel() const { return m_sourceModel; } void PaginateModel::setSourceModel(QAbstractItemModel* model) { if(m_sourceModel) { disconnect(m_sourceModel, nullptr, this, nullptr); } if(model!=m_sourceModel) { beginResetModel(); m_sourceModel = model; if(model) { connect(m_sourceModel, &QAbstractItemModel::rowsAboutToBeInserted, this, &PaginateModel::_k_sourceRowsAboutToBeInserted); connect(m_sourceModel, &QAbstractItemModel::rowsInserted, this, &PaginateModel::_k_sourceRowsInserted); connect(m_sourceModel, &QAbstractItemModel::rowsAboutToBeRemoved, this, &PaginateModel::_k_sourceRowsAboutToBeRemoved); connect(m_sourceModel, &QAbstractItemModel::rowsRemoved, this, &PaginateModel::_k_sourceRowsRemoved); connect(m_sourceModel, &QAbstractItemModel::rowsAboutToBeMoved, this, &PaginateModel::_k_sourceRowsAboutToBeMoved); connect(m_sourceModel, &QAbstractItemModel::rowsMoved, this, &PaginateModel::_k_sourceRowsMoved); connect(m_sourceModel, &QAbstractItemModel::columnsAboutToBeInserted, this, &PaginateModel::_k_sourceColumnsAboutToBeInserted); connect(m_sourceModel, &QAbstractItemModel::columnsInserted, this, &PaginateModel::_k_sourceColumnsInserted); connect(m_sourceModel, &QAbstractItemModel::columnsAboutToBeRemoved, this, &PaginateModel::_k_sourceColumnsAboutToBeRemoved); connect(m_sourceModel, &QAbstractItemModel::columnsRemoved, this, &PaginateModel::_k_sourceColumnsRemoved); connect(m_sourceModel, &QAbstractItemModel::columnsAboutToBeMoved, this, &PaginateModel::_k_sourceColumnsAboutToBeMoved); connect(m_sourceModel, &QAbstractItemModel::columnsMoved, this, &PaginateModel::_k_sourceColumnsMoved); connect(m_sourceModel, &QAbstractItemModel::dataChanged, this, &PaginateModel::_k_sourceDataChanged); connect(m_sourceModel, &QAbstractItemModel::headerDataChanged, this, &PaginateModel::_k_sourceHeaderDataChanged); connect(m_sourceModel, &QAbstractItemModel::modelAboutToBeReset, this, &PaginateModel::_k_sourceModelAboutToBeReset); connect(m_sourceModel, &QAbstractItemModel::modelReset, this, &PaginateModel::_k_sourceModelReset); connect(m_sourceModel, &QAbstractItemModel::rowsInserted, this, &PaginateModel::pageCountChanged); connect(m_sourceModel, &QAbstractItemModel::rowsRemoved, this, &PaginateModel::pageCountChanged); connect(m_sourceModel, &QAbstractItemModel::modelReset, this, &PaginateModel::pageCountChanged); } endResetModel(); emit sourceModelChanged(); } } QHash< int, QByteArray > PaginateModel::roleNames() const { return m_sourceModel ? m_sourceModel->roleNames() : QAbstractItemModel::roleNames(); } int PaginateModel::rowsByPageSize(int size) const { return m_hasStaticRowCount ? size : !m_sourceModel ? 0 : qMin(m_sourceModel->rowCount()-m_firstItem, size); } int PaginateModel::rowCount(const QModelIndex& parent) const { return parent.isValid() ? 0 : rowsByPageSize(m_pageSize); } QModelIndex PaginateModel::mapToSource(const QModelIndex& idx) const { if(!m_sourceModel) return QModelIndex(); return m_sourceModel->index(idx.row()+m_firstItem, idx.column()); } QModelIndex PaginateModel::mapFromSource(const QModelIndex& idx) const { Q_ASSERT(idx.model() == m_sourceModel); if(!m_sourceModel) return QModelIndex(); return index(idx.row()-m_firstItem, idx.column()); } QVariant PaginateModel::data(const QModelIndex& index, int role) const { if(!m_sourceModel) return QVariant(); QModelIndex idx = mapToSource(index); return idx.data(role); } void PaginateModel::firstPage() { setFirstItem(0); } void PaginateModel::lastPage() { setFirstItem((pageCount() - 1)*m_pageSize); } void PaginateModel::nextPage() { setFirstItem(m_firstItem + m_pageSize); } void PaginateModel::previousPage() { setFirstItem(m_firstItem - m_pageSize); } int PaginateModel::currentPage() const { return m_firstItem/m_pageSize; } int PaginateModel::pageCount() const { if(!m_sourceModel) return 0; const int rc = m_sourceModel->rowCount(); const int r = (rc%m_pageSize == 0) ? 1 : 0; return qMax(qCeil(float(rc)/m_pageSize) - r, 1); } bool PaginateModel::hasStaticRowCount() const { return m_hasStaticRowCount; } void PaginateModel::setStaticRowCount(bool src) { if (src == m_hasStaticRowCount) { return; } beginResetModel(); m_hasStaticRowCount = src; endResetModel(); } ////////////////////////////// void PaginateModel::_k_sourceColumnsAboutToBeInserted(const QModelIndex& parent, int start, int end) { Q_UNUSED(end) if(parent.isValid() || start!=0) { return; } beginResetModel(); } void PaginateModel::_k_sourceColumnsAboutToBeMoved(const QModelIndex& sourceParent, int sourceStart, int sourceEnd, const QModelIndex& destParent, int dest) { Q_UNUSED(sourceParent) Q_UNUSED(sourceStart) Q_UNUSED(sourceEnd) Q_UNUSED(destParent) Q_UNUSED(dest) beginResetModel(); } void PaginateModel::_k_sourceColumnsAboutToBeRemoved(const QModelIndex& parent, int start, int end) { Q_UNUSED(end) if(parent.isValid() || start!=0) { return; } beginResetModel(); } void PaginateModel::_k_sourceColumnsInserted(const QModelIndex& parent, int start, int end) { Q_UNUSED(end) if(parent.isValid() || start!=0) { return; } endResetModel(); } void PaginateModel::_k_sourceColumnsMoved(const QModelIndex& sourceParent, int sourceStart, int sourceEnd, const QModelIndex& destParent, int dest) { Q_UNUSED(sourceParent) Q_UNUSED(sourceStart) Q_UNUSED(sourceEnd) Q_UNUSED(destParent) Q_UNUSED(dest) endResetModel(); } void PaginateModel::_k_sourceColumnsRemoved(const QModelIndex& parent, int start, int end) { Q_UNUSED(end) if(parent.isValid() || start!=0) { return; } endResetModel(); } void PaginateModel::_k_sourceDataChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight, const QVector &roles) { if(topLeft.parent().isValid() || bottomRight.row()lastItem()) { return; } QModelIndex idxTop = mapFromSource(topLeft); QModelIndex idxBottom = mapFromSource(bottomRight); if(!idxTop.isValid()) idxTop = index(0); if(!idxBottom.isValid()) idxBottom = index(rowCount()-1); emit dataChanged(idxTop, idxBottom, roles); } void PaginateModel::_k_sourceHeaderDataChanged(Qt::Orientation orientation, int first, int last) { Q_UNUSED(last) if(first==0) emit headerDataChanged(orientation, 0, 0); } void PaginateModel::_k_sourceModelAboutToBeReset() { beginResetModel(); } void PaginateModel::_k_sourceModelReset() { endResetModel(); } bool PaginateModel::isIntervalValid(const QModelIndex& parent, int start, int /*end*/) const { return !parent.isValid() && start<=lastItem(); } bool PaginateModel::canSizeChange() const { return !m_hasStaticRowCount && currentPage() == pageCount()-1; } void PaginateModel::_k_sourceRowsAboutToBeInserted(const QModelIndex& parent, int start, int end) { if(!isIntervalValid(parent, start, end)) { return; } if(canSizeChange()) { - const int insertedCount = end-start; const int newStart = qMax(start-m_firstItem, 0); + const int insertedCount = qMin(end-start, pageSize() - newStart -1); beginInsertRows(QModelIndex(), newStart, newStart+insertedCount); } else { beginResetModel(); } } void PaginateModel::_k_sourceRowsInserted(const QModelIndex& parent, int start, int end) { if(!isIntervalValid(parent, start, end)) { return; } if(canSizeChange()) { endInsertRows(); } else { endResetModel(); } } void PaginateModel::_k_sourceRowsAboutToBeMoved(const QModelIndex& sourceParent, int sourceStart, int sourceEnd, const QModelIndex& destParent, int dest) { Q_UNUSED(sourceParent) Q_UNUSED(sourceStart) Q_UNUSED(sourceEnd) Q_UNUSED(destParent) Q_UNUSED(dest) //NOTE could optimize, unsure if it makes sense beginResetModel(); } void PaginateModel::_k_sourceRowsMoved(const QModelIndex& sourceParent, int sourceStart, int sourceEnd, const QModelIndex& destParent, int dest) { Q_UNUSED(sourceParent) Q_UNUSED(sourceStart) Q_UNUSED(sourceEnd) Q_UNUSED(destParent) Q_UNUSED(dest) endResetModel(); } void PaginateModel::_k_sourceRowsAboutToBeRemoved(const QModelIndex& parent, int start, int end) { if(!isIntervalValid(parent, start, end)) { return; } if(canSizeChange()) { const int removedCount = end-start; const int newStart = qMax(start-m_firstItem, 0); beginRemoveRows(QModelIndex(), newStart, newStart+removedCount); } else { beginResetModel(); } } void PaginateModel::_k_sourceRowsRemoved(const QModelIndex& parent, int start, int end) { if(!isIntervalValid(parent, start, end)) { return; } if(canSizeChange()) { endRemoveRows(); } else { beginResetModel(); } } int PaginateModel::lastItem() const { return m_firstItem + rowCount(); }