[app] Corrected page stack behaviour

It couldn't push the same position that was just popped.

Also, some countChanged signals were not being deferred - it
was probably not intentional, at least I couldn't remember why
it was done like that. Let all countChanged signals be deferred.
This commit is contained in:
Slava Monich 2018-01-20 13:35:35 +02:00
parent 7a7067869d
commit feffa61273

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2016-2017 Jolla Ltd. * Copyright (C) 2016-2018 Jolla Ltd.
* Contact: Slava Monich <slava.monich@jolla.com> * Contact: Slava Monich <slava.monich@jolla.com>
* *
* You may use this file under the terms of the BSD license as follows: * You may use this file under the terms of the BSD license as follows:
@ -89,12 +89,12 @@ public:
private: private:
BooksPos::List iPageMarks; BooksPos::List iPageMarks;
BooksPageStack* iModel;
public: public:
Private(BooksPageStack* aModel); Private(BooksPageStack* aModel);
BooksPos::Stack getStack() const; BooksPos::Stack getStack() const;
bool atEnd() const;
bool isValidIndex(int aIndex) const; bool isValidIndex(int aIndex) const;
void setCurrentIndex(int aIndex); void setCurrentIndex(int aIndex);
int currentPage() const; int currentPage() const;
@ -103,7 +103,6 @@ public:
void setPageAt(int aIndex, int aPage); void setPageAt(int aIndex, int aPage);
void setStack(BooksPos::List aStack, int aCurrentPos); void setStack(BooksPos::List aStack, int aCurrentPos);
void setPageMarks(BooksPos::List aPageMarks); void setPageMarks(BooksPos::List aPageMarks);
void push(BooksPos aPos, int aPage);
void push(BooksPos); void push(BooksPos);
void push(int aPage); void push(int aPage);
void pop(); void pop();
@ -114,6 +113,8 @@ private Q_SLOTS:
void onModelChanged(); void onModelChanged();
private: private:
BooksPageStack* parentModel() const;
void push(BooksPos aPos, int aPage);
BooksPos getPosAt(int aIndex) const; BooksPos getPosAt(int aIndex) const;
int findPage(BooksPos aPos) const; int findPage(BooksPos aPos) const;
int makeIndexValid(int aIndex) const; int makeIndexValid(int aIndex) const;
@ -128,8 +129,7 @@ private:
BooksPageStack::Private::Private(BooksPageStack* aModel) : BooksPageStack::Private::Private(BooksPageStack* aModel) :
QObject(aModel), QObject(aModel),
iCurrentIndex(0), iCurrentIndex(0),
iQueuedSignals(0), iQueuedSignals(0)
iModel(aModel)
{ {
iEntries.append(Entry()); iEntries.append(Entry());
connect(aModel, connect(aModel,
@ -146,6 +146,11 @@ BooksPageStack::Private::Private(BooksPageStack* aModel) :
SLOT(onModelChanged())); SLOT(onModelChanged()));
} }
inline BooksPageStack* BooksPageStack::Private::parentModel() const
{
return qobject_cast<BooksPageStack*>(parent());
}
void BooksPageStack::Private::emitQueuedSignals() void BooksPageStack::Private::emitQueuedSignals()
{ {
static const struct SignalInfo { static const struct SignalInfo {
@ -158,10 +163,13 @@ void BooksPageStack::Private::emitQueuedSignals()
{ SignalCurrentPageChanged, &BooksPageStack::currentPageChanged} { SignalCurrentPageChanged, &BooksPageStack::currentPageChanged}
}; };
const uint n = sizeof(signalInfo)/sizeof(signalInfo[0]); const uint n = sizeof(signalInfo)/sizeof(signalInfo[0]);
for (uint i=0; i<n && iQueuedSignals; i++) { if (iQueuedSignals) {
if (iQueuedSignals & signalInfo[i].signal) { BooksPageStack* model = parentModel();
iQueuedSignals &= ~signalInfo[i].signal; for (uint i=0; i<n && iQueuedSignals; i++) {
Q_EMIT (iModel->*(signalInfo[i].fn))(); if (iQueuedSignals & signalInfo[i].signal) {
iQueuedSignals &= ~signalInfo[i].signal;
Q_EMIT (model->*(signalInfo[i].fn))();
}
} }
} }
} }
@ -191,6 +199,11 @@ inline bool BooksPageStack::Private::isValidIndex(int aIndex) const
return aIndex >= 0 && aIndex < iEntries.count(); return aIndex >= 0 && aIndex < iEntries.count();
} }
inline bool BooksPageStack::Private::atEnd() const
{
return (iCurrentIndex + 1) >= iEntries.count();
}
inline void BooksPageStack::Private::checkCurrentIndex(int aLastIndex) inline void BooksPageStack::Private::checkCurrentIndex(int aLastIndex)
{ {
if (validateCurrentIndex() != aLastIndex) { if (validateCurrentIndex() != aLastIndex) {
@ -274,8 +287,9 @@ void BooksPageStack::Private::pageChanged(int aIndex)
{ {
QVector<int> roles; QVector<int> roles;
roles.append(PageRole); roles.append(PageRole);
QModelIndex modelIndex(iModel->createIndex(aIndex, 0)); BooksPageStack* model = parentModel();
Q_EMIT iModel->dataChanged(modelIndex, modelIndex, roles); QModelIndex modelIndex(model->createIndex(aIndex, 0));
Q_EMIT model->dataChanged(modelIndex, modelIndex, roles);
} }
void BooksPageStack::Private::setStack(BooksPos::List aStack, int aStackPos) void BooksPageStack::Private::setStack(BooksPos::List aStack, int aStackPos)
@ -313,12 +327,13 @@ void BooksPageStack::Private::setStack(BooksPos::List aStack, int aStackPos)
if (entryIndex < oldEntryCount) { if (entryIndex < oldEntryCount) {
// We have run out of stack entries, remove remainig rows // We have run out of stack entries, remove remainig rows
iModel->beginRemoveRows(QModelIndex(), entryIndex, oldEntryCount-1); BooksPageStack* model = parentModel();
model->beginRemoveRows(QModelIndex(), entryIndex, oldEntryCount-1);
while (iEntries.count() > entryIndex) { while (iEntries.count() > entryIndex) {
iEntries.removeLast(); iEntries.removeLast();
} }
iModel->endRemoveRows(); model->endRemoveRows();
Q_EMIT iModel->countChanged(); queueSignals(SignalCountChanged);
} else { } else {
// Add new entries if necessary // Add new entries if necessary
while (stackIndex < aStack.count()) { while (stackIndex < aStack.count()) {
@ -332,9 +347,10 @@ void BooksPageStack::Private::setStack(BooksPos::List aStack, int aStackPos)
const int n = iEntries.count(); const int n = iEntries.count();
if (n > oldEntryCount) { if (n > oldEntryCount) {
// We have added some entries, update the model // We have added some entries, update the model
iModel->beginInsertRows(QModelIndex(), oldEntryCount, n-1); BooksPageStack* model = parentModel();
iModel->endInsertRows(); model->beginInsertRows(QModelIndex(), oldEntryCount, n-1);
Q_EMIT iModel->countChanged(); model->endInsertRows();
queueSignals(SignalCountChanged);
} }
} }
@ -395,55 +411,56 @@ BooksPos BooksPageStack::Private::getPosAt(int aIndex) const
void BooksPageStack::Private::push(BooksPos aPos, int aPage) void BooksPageStack::Private::push(BooksPos aPos, int aPage)
{ {
Entry last = iEntries.last(); Entry last = iEntries.last();
if (last.iPos != aPos || last.iPage != aPage) { const int n = iEntries.count();
const int n = iEntries.count(); // The caller makes sure that the operation makes sense
if (n >= iCurrentIndex+2) { HASSERT(!atEnd() || last.iPos != aPos || last.iPage != aPage);
// Push on top of the current position. if (n >= iCurrentIndex+2) {
if (n > iCurrentIndex+2) { // Push on top of the current position.
// Drop unnecessary entries if (n > iCurrentIndex+2) {
iModel->beginRemoveRows(QModelIndex(), iCurrentIndex+2, n-1); // Drop unnecessary entries
while (iEntries.count() > iCurrentIndex+2) { BooksPageStack* model = parentModel();
iEntries.removeLast(); model->beginRemoveRows(QModelIndex(), iCurrentIndex+2, n-1);
} while (iEntries.count() > iCurrentIndex+2) {
iModel->endRemoveRows(); iEntries.removeLast();
Q_EMIT iModel->countChanged();
queueSignals(SignalCountChanged);
} }
// And replace the next one model->endRemoveRows();
setPageAt(iCurrentIndex+1, aPage);
setCurrentIndex(iCurrentIndex+1);
} else if (n >= MAX_DEPTH) {
// We have reached the depth limit, push the entire stack down
const int oldCurrentPage = currentPage();
for (int i=1; i<n; i++) {
iEntries[i-1] = iEntries[i];
pageChanged(i-1);
}
iEntries[n-1] = Entry(aPos, aPage);
pageChanged(n-1);
checkCurrentPage(oldCurrentPage);
} else {
// Just push the new one
const int i = iCurrentIndex+1;
iModel->beginInsertRows(QModelIndex(), i, i);
iEntries.append(Entry(aPos, aPage));
iModel->endInsertRows();
queueSignals(SignalCountChanged); queueSignals(SignalCountChanged);
setCurrentIndex(i);
} }
// And replace the next one
setPageAt(iCurrentIndex+1, aPage);
setCurrentIndex(iCurrentIndex+1);
} else if (n >= MAX_DEPTH) {
// We have reached the depth limit, push the entire stack down
const int oldCurrentPage = currentPage();
for (int i=1; i<n; i++) {
iEntries[i-1] = iEntries[i];
pageChanged(i-1);
}
iEntries[n-1] = Entry(aPos, aPage);
pageChanged(n-1);
checkCurrentPage(oldCurrentPage);
} else {
// Just push the new one
const int i = iCurrentIndex+1;
BooksPageStack* model = parentModel();
model->beginInsertRows(QModelIndex(), i, i);
iEntries.append(Entry(aPos, aPage));
model->endInsertRows();
queueSignals(SignalCountChanged);
setCurrentIndex(i);
} }
} }
void BooksPageStack::Private::push(BooksPos aPos) void BooksPageStack::Private::push(BooksPos aPos)
{ {
if (iEntries.last().iPos != aPos) { if (!atEnd() || iEntries.last().iPos != aPos) {
push(aPos, findPage(aPos)); push(aPos, findPage(aPos));
} }
} }
void BooksPageStack::Private::push(int aPage) void BooksPageStack::Private::push(int aPage)
{ {
if (iEntries.last().iPage != aPage) { if (!atEnd() || iEntries.last().iPage != aPage) {
push(getPosAt(aPage), aPage); push(getPosAt(aPage), aPage);
} }
} }
@ -452,10 +469,11 @@ void BooksPageStack::Private::pop()
{ {
const int n = iEntries.count(); const int n = iEntries.count();
if (n > 1) { if (n > 1) {
iModel->beginRemoveRows(QModelIndex(), n-1, n-1); BooksPageStack* model = parentModel();
model->beginRemoveRows(QModelIndex(), n-1, n-1);
iEntries.removeLast(); iEntries.removeLast();
validateCurrentIndex(); validateCurrentIndex();
iModel->endRemoveRows(); model->endRemoveRows();
queueSignals(SignalCountChanged); queueSignals(SignalCountChanged);
} }
} }
@ -464,13 +482,14 @@ void BooksPageStack::Private::clear()
{ {
const int n = iEntries.count(); const int n = iEntries.count();
if (n > 1) { if (n > 1) {
BooksPageStack* model = parentModel();
Entry currentEntry = iEntries.at(iCurrentIndex); Entry currentEntry = iEntries.at(iCurrentIndex);
iModel->beginRemoveRows(QModelIndex(), 1, n-1); model->beginRemoveRows(QModelIndex(), 1, n-1);
while (iEntries.count() > 1) { while (iEntries.count() > 1) {
iEntries.removeLast(); iEntries.removeLast();
} }
validateCurrentIndex(); validateCurrentIndex();
iModel->endRemoveRows(); model->endRemoveRows();
if (iEntries.at(0) != currentEntry) { if (iEntries.at(0) != currentEntry) {
iEntries[0] = currentEntry; iEntries[0] = currentEntry;
pageChanged(0); pageChanged(0);