File indexing completed on 2024-10-06 03:31:32

0001 // SPDX-FileCopyrightText: 2007-2010 Peter Hedlund <peter.hedlund@kdemail.net>
0002 // SPDX-License-Identifier: GPL-2.0-or-later
0003 
0004 #include "kwqrandomsortmodel.h"
0005 #include "kwqcardmodel.h"
0006 #include "prefs.h"
0007 
0008 #include <KRandom>
0009 #include <QRandomGenerator>
0010 
0011 KWQRandomSortModel::KWQRandomSortModel(QObject *parent)
0012     : QSortFilterProxyModel(parent)
0013 {
0014     m_sourceModel = nullptr;
0015     setSortCaseSensitivity(Qt::CaseInsensitive);
0016     setFilterCaseSensitivity(Qt::CaseInsensitive);
0017     setFilterKeyColumn(-1);
0018     m_restoreNativeOrder = false;
0019     m_shuffle = false;
0020 
0021     auto reset = [this] {
0022         this->reset();
0023         Prefs::self()->save();
0024     };
0025 
0026     connect(Prefs::self(), &Prefs::RandomizeChanged, this, reset);
0027     connect(Prefs::self(), &Prefs::QuestionInLeftColumnChanged, this, reset);
0028     connect(Prefs::self(), &Prefs::QuestionInRightColumnChanged, this, reset);
0029 }
0030 
0031 QVariant KWQRandomSortModel::data(const QModelIndex &idx, int role) const
0032 {
0033     auto mode = idx.row() >= m_modes.count() ? QuestionInLeftColumn : m_modes[idx.row()];
0034 
0035     if (role == MultipleChoiceRole) {
0036         if (rowCount() < 4) {
0037             return QStringList();
0038         }
0039 
0040         const auto rowRole = mode == QuestionInRightColumn
0041             ? KWQCardModel::QuestionRole
0042             : KWQCardModel::AnswerRole;
0043 
0044         QList<int> possibleIndex;
0045         for (int i = 0; i < rowCount(); i++) {
0046             possibleIndex << i;
0047         }
0048         possibleIndex.removeAll(idx.row());
0049 
0050         KRandom::shuffle(possibleIndex, QRandomGenerator::global());
0051 
0052         QStringList possibleAnswer;
0053         possibleAnswer << QSortFilterProxyModel::data(index(possibleIndex[0], 0), rowRole).toString();
0054         possibleAnswer << QSortFilterProxyModel::data(index(possibleIndex[1], 0), rowRole).toString();
0055         possibleAnswer << QSortFilterProxyModel::data(index(possibleIndex[3], 0), rowRole).toString();
0056         possibleAnswer << QSortFilterProxyModel::data(index(idx.row(), 0), rowRole).toString();
0057 
0058         KRandom::shuffle(possibleAnswer, QRandomGenerator::global());
0059 
0060         return QVariant::fromValue(possibleAnswer);
0061     }
0062 
0063     if (mode == QuestionInRightColumn) {
0064         switch (role) {
0065         case KWQCardModel::AnswerRole:
0066             role = KWQCardModel::QuestionRole;
0067             break;
0068         case KWQCardModel::AnswerSoundRole:
0069             role = KWQCardModel::QuestionSoundRole;
0070             break;
0071         case KWQCardModel::AnswerImageRole:
0072             role = KWQCardModel::QuestionImageRole;
0073             break;
0074         case KWQCardModel::QuestionRole:
0075             role = KWQCardModel::AnswerRole;
0076             break;
0077         case KWQCardModel::QuestionSoundRole:
0078             role = KWQCardModel::AnswerSoundRole;
0079             break;
0080         case KWQCardModel::QuestionImageRole:
0081             role = KWQCardModel::AnswerImageRole;
0082             break;
0083         }
0084     }
0085 
0086     return QSortFilterProxyModel::data(idx, role);
0087 }
0088 
0089 QHash<int, QByteArray> KWQRandomSortModel::roleNames() const
0090 {
0091     auto roles = QSortFilterProxyModel::roleNames();
0092     roles[MultipleChoiceRole] = "multipleChoice";
0093     return roles;
0094 }
0095 
0096 void KWQRandomSortModel::setCardModel(KWQCardModel *sourceModel)
0097 {
0098     if (m_sourceModel == sourceModel) {
0099         return;
0100     }
0101     if (m_sourceModel) {
0102         disconnect(m_sourceModel, &KWQCardModel::modelReset, this, &KWQRandomSortModel::reset);
0103     }
0104     m_sourceModel = sourceModel;
0105     QSortFilterProxyModel::setSourceModel(sourceModel);
0106     Q_EMIT cardModelChanged();
0107 
0108     if (m_sourceModel) {
0109         connect(m_sourceModel, &KWQCardModel::modelReset, this, &KWQRandomSortModel::reset);
0110     }
0111     reset();
0112 }
0113 
0114 KWQCardModel *KWQRandomSortModel::cardModel() const
0115 {
0116     return m_sourceModel;
0117 }
0118 
0119 bool KWQRandomSortModel::lessThan(const QModelIndex &left, const QModelIndex &right) const
0120 {
0121     if (m_shuffle) {
0122         return m_shuffleList.at(right.row()) < m_shuffleList.at(left.row());
0123     } else if (m_restoreNativeOrder) {
0124         return sourceModel()->index(right.row(), right.column()).row() <
0125                sourceModel()->index(left.row(), left.column()).row();
0126     } else {
0127         return QSortFilterProxyModel::lessThan(left, right);
0128     }
0129 }
0130 
0131 bool KWQRandomSortModel::filterAcceptsRow(const int sourceRow, const QModelIndex &sourceParent) const
0132 {
0133     if (!m_showErrorsOnly) {
0134         return true;
0135     }
0136 
0137     return m_errors.contains(sourceRow);
0138 }
0139 
0140 void KWQRandomSortModel::setRandomModes()
0141 {
0142     m_modes.clear();
0143     if (Prefs::questionInLeftColumn() && !Prefs::questionInRightColumn()) {
0144         for (int i = 0; i < rowCount({}); ++i) {
0145             m_modes.append(QuestionInLeftColumn);
0146         }
0147     } else if (!Prefs::questionInLeftColumn() && Prefs::questionInRightColumn()) {
0148         for (int i = 0; i < rowCount({}); ++i) {
0149             m_modes.append(QuestionInRightColumn);
0150         }
0151     } else {
0152         auto generator = QRandomGenerator::global();
0153         for (int i = 0; i < rowCount({}); ++i) {
0154             if (generator->bounded(2) == 1) {
0155                 m_modes.append(QuestionInLeftColumn);
0156             } else {
0157                 m_modes.append(QuestionInRightColumn);
0158             }
0159         }
0160     }
0161 }
0162 
0163 void KWQRandomSortModel::reset()
0164 {
0165     if (Prefs::randomize()) {
0166         shuffle();
0167     } else {
0168         restoreNativeOrder();
0169     }
0170 }
0171 
0172 void KWQRandomSortModel::restoreNativeOrder()
0173 {
0174     m_errors.clear();
0175     m_restoreNativeOrder = true;
0176     setRandomModes();
0177     sort(-1, Qt::AscendingOrder);
0178     invalidate();
0179     m_restoreNativeOrder = false;
0180     m_modes.clear();
0181 }
0182 
0183 void KWQRandomSortModel::shuffle()
0184 {
0185     m_errors.clear();
0186     m_shuffleList.clear();
0187     setRandomModes();
0188     for (int i = 0; i < rowCount({}); ++i)
0189         m_shuffleList.append(i);
0190 
0191     KRandom::shuffle(m_shuffleList, QRandomGenerator::global());
0192     m_shuffle = true;
0193     sort(0, Qt::AscendingOrder);
0194     invalidate();
0195     m_shuffle = false;
0196 }
0197 
0198 void KWQRandomSortModel::markAsError(const int row)
0199 {
0200     m_errors << sourceModel()->index(row, 0).row();
0201 }
0202 
0203 void KWQRandomSortModel::unMarkAsError(const int row)
0204 {
0205     m_errors.removeAll(sourceModel()->index(row, 0).row());
0206 }
0207 
0208 bool KWQRandomSortModel::showErrorsOnly() const
0209 {
0210     return m_showErrorsOnly;
0211 }
0212 
0213 void KWQRandomSortModel::setShowErrorsOnly(const bool showErrorsOnly)
0214 {
0215     if (m_showErrorsOnly == showErrorsOnly) {
0216         return;
0217     }
0218     m_showErrorsOnly = showErrorsOnly;
0219     Q_EMIT showErrorsOnlyChanged();
0220     invalidateFilter();
0221 }
0222 
0223 #include "moc_kwqrandomsortmodel.cpp"