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"