diff --git a/discover/PaginateModel.h b/discover/PaginateModel.h --- a/discover/PaginateModel.h +++ b/discover/PaginateModel.h @@ -33,10 +33,19 @@ class PaginateModel : public QAbstractListModel { Q_OBJECT + /** Holds the number of elements that will fit in a page */ Q_PROPERTY(int pageSize READ pageSize WRITE setPageSize NOTIFY pageSizeChanged) + + /** Tells what is the first row shown in the model */ Q_PROPERTY(int firstItem READ firstItem WRITE setFirstItem NOTIFY firstItemChanged) + + /** The model we will be proxying */ Q_PROPERTY(QAbstractItemModel* sourceModel READ sourceModel WRITE setSourceModel NOTIFY sourceModelChanged) + + /** Among the totality of elements, indicates the one we're currently offering */ Q_PROPERTY(int currentPage READ currentPage NOTIFY firstItemChanged) + + /** Provides the number of pages available, given the sourceModel size */ Q_PROPERTY(int pageCount READ pageCount NOTIFY pageCountChanged) /** If enabled, ensures that pageCount and pageSize are the same. */ @@ -74,9 +83,16 @@ void setStaticRowCount(bool src); bool hasStaticRowCount() const; + /** Display the first rows of the model */ Q_SCRIPTABLE void firstPage(); + + /** Display the rows right after the ones that are currently being served */ Q_SCRIPTABLE void nextPage(); + + /** Display the rows right before the ones that are currently being served */ Q_SCRIPTABLE void previousPage(); + + /** Display the last set of rows of the source model */ Q_SCRIPTABLE void lastPage(); private Q_SLOTS: @@ -110,12 +126,10 @@ private: bool canSizeChange() const; bool isIntervalValid(const QModelIndex& parent, int start, int end) const; - int rowsByPageSize(int size) const; - int m_firstItem; - int m_pageSize; - QAbstractItemModel* m_sourceModel; - bool m_hasStaticRowCount; + + class PaginateModelPrivate; + QScopedPointer d; }; #endif diff --git a/discover/PaginateModel.cpp b/discover/PaginateModel.cpp --- a/discover/PaginateModel.cpp +++ b/discover/PaginateModel.cpp @@ -21,140 +21,144 @@ #include #include "discover_debug.h" +class PaginateModel::PaginateModelPrivate +{ +public: + int m_firstItem = 0; + int m_pageSize = 0; + QAbstractItemModel* m_sourceModel = nullptr; + bool m_hasStaticRowCount = false; +}; + PaginateModel::PaginateModel(QObject* object) : QAbstractListModel(object) - , m_firstItem(0) - , m_pageSize(10) - , m_sourceModel(nullptr) - , m_hasStaticRowCount(false) + , d(new PaginateModelPrivate) { } -PaginateModel::~PaginateModel() -{ -} +PaginateModel::~PaginateModel() = default; int PaginateModel::firstItem() const { - return m_firstItem; + return d->m_firstItem; } void PaginateModel::setFirstItem(int row) { - Q_ASSERT(row>=0 && rowrowCount()); - if (row!=m_firstItem) { + Q_ASSERT(row >= 0 && row < d->m_sourceModel->rowCount()); + if (row != d->m_firstItem) { beginResetModel(); - m_firstItem = row; + d->m_firstItem = row; endResetModel(); emit firstItemChanged(); } } int PaginateModel::pageSize() const { - return m_pageSize; + return d->m_pageSize; } void PaginateModel::setPageSize(int count) { - if (count != m_pageSize) { - const int oldSize = rowsByPageSize(m_pageSize); + if (count != d->m_pageSize) { + const int oldSize = rowsByPageSize(d->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; + d->m_pageSize = count; + } else if (difference>0) { + beginInsertRows(QModelIndex(), d->m_pageSize, d->m_pageSize + difference - 1); + d->m_pageSize = count; endInsertRows(); } else { - beginRemoveRows(QModelIndex(), m_pageSize+difference, m_pageSize-1); - m_pageSize = count; + beginRemoveRows(QModelIndex(), d->m_pageSize + difference, d->m_pageSize - 1); + d->m_pageSize = count; endRemoveRows(); } emit pageSizeChanged(); } } QAbstractItemModel* PaginateModel::sourceModel() const { - return m_sourceModel; + return d->m_sourceModel; } void PaginateModel::setSourceModel(QAbstractItemModel* model) { - if(m_sourceModel) { - disconnect(m_sourceModel, nullptr, this, nullptr); + if (d->m_sourceModel) { + disconnect(d->m_sourceModel, nullptr, this, nullptr); } - if(model!=m_sourceModel) { + if (model != d->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); + d->m_sourceModel = model; + if (model) { + connect(d->m_sourceModel, &QAbstractItemModel::rowsAboutToBeInserted, this, &PaginateModel::_k_sourceRowsAboutToBeInserted); + connect(d->m_sourceModel, &QAbstractItemModel::rowsInserted, this, &PaginateModel::_k_sourceRowsInserted); + connect(d->m_sourceModel, &QAbstractItemModel::rowsAboutToBeRemoved, this, &PaginateModel::_k_sourceRowsAboutToBeRemoved); + connect(d->m_sourceModel, &QAbstractItemModel::rowsRemoved, this, &PaginateModel::_k_sourceRowsRemoved); + connect(d->m_sourceModel, &QAbstractItemModel::rowsAboutToBeMoved, this, &PaginateModel::_k_sourceRowsAboutToBeMoved); + connect(d->m_sourceModel, &QAbstractItemModel::rowsMoved, this, &PaginateModel::_k_sourceRowsMoved); + + connect(d->m_sourceModel, &QAbstractItemModel::columnsAboutToBeInserted, this, &PaginateModel::_k_sourceColumnsAboutToBeInserted); + connect(d->m_sourceModel, &QAbstractItemModel::columnsInserted, this, &PaginateModel::_k_sourceColumnsInserted); + connect(d->m_sourceModel, &QAbstractItemModel::columnsAboutToBeRemoved, this, &PaginateModel::_k_sourceColumnsAboutToBeRemoved); + connect(d->m_sourceModel, &QAbstractItemModel::columnsRemoved, this, &PaginateModel::_k_sourceColumnsRemoved); + connect(d->m_sourceModel, &QAbstractItemModel::columnsAboutToBeMoved, this, &PaginateModel::_k_sourceColumnsAboutToBeMoved); + connect(d->m_sourceModel, &QAbstractItemModel::columnsMoved, this, &PaginateModel::_k_sourceColumnsMoved); + + connect(d->m_sourceModel, &QAbstractItemModel::dataChanged, this, &PaginateModel::_k_sourceDataChanged); + connect(d->m_sourceModel, &QAbstractItemModel::headerDataChanged, this, &PaginateModel::_k_sourceHeaderDataChanged); + + connect(d->m_sourceModel, &QAbstractItemModel::modelAboutToBeReset, this, &PaginateModel::_k_sourceModelAboutToBeReset); + connect(d->m_sourceModel, &QAbstractItemModel::modelReset, this, &PaginateModel::_k_sourceModelReset); + + connect(d->m_sourceModel, &QAbstractItemModel::rowsInserted, this, &PaginateModel::pageCountChanged); + connect(d->m_sourceModel, &QAbstractItemModel::rowsRemoved, this, &PaginateModel::pageCountChanged); + connect(d->m_sourceModel, &QAbstractItemModel::modelReset, this, &PaginateModel::pageCountChanged); } endResetModel(); emit sourceModelChanged(); } } QHash< int, QByteArray > PaginateModel::roleNames() const { - return m_sourceModel ? m_sourceModel->roleNames() : QAbstractItemModel::roleNames(); + return d->m_sourceModel ? d->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); + return d->m_hasStaticRowCount ? size + : !d->m_sourceModel ? 0 + : qMin(d->m_sourceModel->rowCount() - d->m_firstItem, size); } int PaginateModel::rowCount(const QModelIndex& parent) const { - return parent.isValid() ? 0 : rowsByPageSize(m_pageSize); + return parent.isValid() ? 0 : rowsByPageSize(d->m_pageSize); } QModelIndex PaginateModel::mapToSource(const QModelIndex& idx) const { - if(!m_sourceModel) + if (!d->m_sourceModel) return QModelIndex(); - return m_sourceModel->index(idx.row()+m_firstItem, idx.column()); + return d->m_sourceModel->index(idx.row() + d->m_firstItem, idx.column()); } QModelIndex PaginateModel::mapFromSource(const QModelIndex& idx) const { - Q_ASSERT(idx.model() == m_sourceModel); - if(!m_sourceModel) + Q_ASSERT(idx.model() == d->m_sourceModel); + if (!d->m_sourceModel) return QModelIndex(); - return index(idx.row()-m_firstItem, idx.column()); + return index(idx.row() - d->m_firstItem, idx.column()); } QVariant PaginateModel::data(const QModelIndex& index, int role) const { - if(!m_sourceModel) + if (!d->m_sourceModel) return QVariant(); QModelIndex idx = mapToSource(index); return idx.data(role); @@ -167,46 +171,46 @@ void PaginateModel::lastPage() { - setFirstItem((pageCount() - 1)*m_pageSize); + setFirstItem((pageCount() - 1) * d->m_pageSize); } void PaginateModel::nextPage() { - setFirstItem(m_firstItem + m_pageSize); + setFirstItem(d->m_firstItem + d->m_pageSize); } void PaginateModel::previousPage() { - setFirstItem(m_firstItem - m_pageSize); + setFirstItem(d->m_firstItem - d->m_pageSize); } int PaginateModel::currentPage() const { - return m_firstItem/m_pageSize; + return d->m_firstItem / d->m_pageSize; } int PaginateModel::pageCount() const { - if(!m_sourceModel) + if (!d->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); + const int rc = d->m_sourceModel->rowCount(); + const int r = (rc % d->m_pageSize == 0) ? 1 : 0; + return qMax(qCeil(float(rc) / d->m_pageSize) - r, 1); } bool PaginateModel::hasStaticRowCount() const { - return m_hasStaticRowCount; + return d->m_hasStaticRowCount; } void PaginateModel::setStaticRowCount(bool src) { - if (src == m_hasStaticRowCount) { + if (src == d->m_hasStaticRowCount) { return; } beginResetModel(); - m_hasStaticRowCount = src; + d->m_hasStaticRowCount = src; endResetModel(); Q_EMIT staticRowCountChanged(); @@ -217,7 +221,7 @@ void PaginateModel::_k_sourceColumnsAboutToBeInserted(const QModelIndex& parent, int start, int end) { Q_UNUSED(end) - if(parent.isValid() || start!=0) { + if (parent.isValid() || start!=0) { return; } beginResetModel(); @@ -236,16 +240,16 @@ void PaginateModel::_k_sourceColumnsAboutToBeRemoved(const QModelIndex& parent, int start, int end) { Q_UNUSED(end) - if(parent.isValid() || start!=0) { + 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) { + if (parent.isValid() || start!=0) { return; } endResetModel(); @@ -264,32 +268,32 @@ void PaginateModel::_k_sourceColumnsRemoved(const QModelIndex& parent, int start, int end) { Q_UNUSED(end) - if(parent.isValid() || start!=0) { + 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()) { + if (topLeft.parent().isValid() || bottomRight.row() < d->m_firstItem || topLeft.row()>lastItem()) { return; } QModelIndex idxTop = mapFromSource(topLeft); QModelIndex idxBottom = mapFromSource(bottomRight); - if(!idxTop.isValid()) + if (!idxTop.isValid()) idxTop = index(0); - if(!idxBottom.isValid()) + 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) + if (first == 0) emit headerDataChanged(orientation, 0, 0); } @@ -310,31 +314,31 @@ bool PaginateModel::canSizeChange() const { - return !m_hasStaticRowCount && currentPage() == pageCount()-1; + return !d->m_hasStaticRowCount && currentPage() == pageCount()-1; } void PaginateModel::_k_sourceRowsAboutToBeInserted(const QModelIndex& parent, int start, int end) { - if(!isIntervalValid(parent, start, end)) { + if (!isIntervalValid(parent, start, end)) { return; } - if(canSizeChange()) { - const int newStart = qMax(start-m_firstItem, 0); - const int insertedCount = qMin(end-start, pageSize() - newStart -1); + if (canSizeChange()) { + const int newStart = qMax(start - d->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)) { + if (!isIntervalValid(parent, start, end)) { return; } - if(canSizeChange()) { + if (canSizeChange()) { endInsertRows(); } else { endResetModel(); @@ -364,33 +368,33 @@ void PaginateModel::_k_sourceRowsAboutToBeRemoved(const QModelIndex& parent, int start, int end) { - if(!isIntervalValid(parent, start, end)) { + if (!isIntervalValid(parent, start, end)) { return; } - if(canSizeChange()) { + if (canSizeChange()) { const int removedCount = end-start; - const int newStart = qMax(start-m_firstItem, 0); - beginRemoveRows(QModelIndex(), newStart, newStart+removedCount); + const int newStart = qMax(start - d->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)) { + if (!isIntervalValid(parent, start, end)) { return; } - if(canSizeChange()) { + if (canSizeChange()) { endRemoveRows(); } else { beginResetModel(); } } int PaginateModel::lastItem() const { - return m_firstItem + rowCount(); + return d->m_firstItem + rowCount(); }