File indexing completed on 2024-04-14 03:49:04
0001 /* 0002 SPDX-FileCopyrightText: 2008 Frederik Gladhorn <frederik.gladhorn@kdemail.net> 0003 SPDX-License-Identifier: GPL-2.0-or-later 0004 */ 0005 0006 #include "entryfilter.h" 0007 0008 #include <QDebug> 0009 #include <QRandomGenerator> 0010 0011 #include <KLocalizedString> 0012 #include <KMessageBox> 0013 0014 #include <KEduVocDocument> 0015 #include <KEduVocExpression> 0016 #include <KEduVocWordtype> 0017 0018 #include "documentsettings.h" 0019 #include "entryfilterdialog.h" 0020 #include "testentry.h" 0021 0022 // using namespace Practice; 0023 0024 // Blocking times for pregrade levels. 0025 // 0026 // It could be argued that these should be configurable but I am not 0027 // sure what that would bring us or the user. Definitely not improved 0028 // learning... 0029 // 0030 // FIXME: Find out what the optimal values are. 0031 int preGradeTimes[] = { 0032 0, 0033 3 * 60 + 30, // 1: 3.5 minutes 0034 7 * 60, // 2: 7 minutes 0035 15 * 60, // 3: 15 minutes 0036 1 * 3600, // 4: 1 hour 0037 2 * 3600, // 5: 2 hours 0038 4 * 3600, // 6: 4 hours 0039 8 * 3600, // 7: 8 hours 0040 }; 0041 0042 EntryFilter::EntryFilter(KEduVocDocument *doc, QObject *parent) 0043 : QObject(parent) 0044 , m_doc(doc) 0045 , m_numSets(0) 0046 , m_fromTranslation(Prefs::knownLanguage()) 0047 , m_toTranslation(Prefs::learningLanguage()) 0048 { 0049 if (Prefs::practiceMode() == Prefs::EnumPracticeMode::ConjugationPractice) { 0050 DocumentSettings documentSettings(m_doc->url().url() + QString::number(m_toTranslation)); 0051 documentSettings.load(); 0052 m_tenses = documentSettings.conjugationTenses(); 0053 // qDebug() << "Tenses" << m_tenses; 0054 } 0055 } 0056 /* 0057 static void debugEntry(const QString &comment, KEduVocExpression *vocexp, 0058 KEduVocTranslation *from, KEduVocTranslation *to) 0059 { 0060 Q_UNUSED(vocexp); 0061 0062 qDebug() << comment << "from" << from->text() << "to" << to->text(); 0063 } 0064 */ 0065 QList<TestEntry *> EntryFilter::entries(bool showDialog) 0066 { 0067 switch (Prefs::practiceDirection()) { 0068 case Prefs::EnumPracticeDirection::KnownToLearning: 0069 m_numSets = 1; 0070 m_fromTranslation = Prefs::knownLanguage(); 0071 m_toTranslation = Prefs::learningLanguage(); 0072 break; 0073 case Prefs::EnumPracticeDirection::LearningToKnown: 0074 m_numSets = 1; 0075 m_fromTranslation = Prefs::learningLanguage(); 0076 m_toTranslation = Prefs::knownLanguage(); 0077 break; 0078 case Prefs::EnumPracticeDirection::MixedDirectionsWordsOnly: 0079 m_numSets = 2; 0080 m_fromTranslation = Prefs::knownLanguage(); 0081 m_toTranslation = Prefs::learningLanguage(); 0082 break; 0083 case Prefs::EnumPracticeDirection::MixedDirectionsWithSound: 0084 // FIXME: Not yet supported. Use same settings as MixedModeWordsOnly 0085 m_numSets = 2; 0086 m_fromTranslation = Prefs::knownLanguage(); 0087 m_toTranslation = Prefs::learningLanguage(); 0088 break; 0089 default: 0090 // Use KnownToLearning as default. 0091 m_numSets = 1; 0092 m_fromTranslation = Prefs::knownLanguage(); 0093 m_toTranslation = Prefs::learningLanguage(); 0094 break; 0095 } 0096 0097 for (int pass = 0; pass < m_numSets; ++pass) { 0098 // If we only do one pass, then from/to translation are already set. 0099 // But in mixed mode we need to set up pass 1 and later. 0100 if (pass == 1) { 0101 m_fromTranslation = Prefs::learningLanguage(); 0102 m_toTranslation = Prefs::knownLanguage(); 0103 } 0104 0105 // qDebug() << "Filter for " << m_fromTranslation << " to " << m_toTranslation; 0106 0107 collectEntries(pass); 0108 expireEntries(pass); 0109 setupFilteredEntries(pass); 0110 } 0111 0112 static QString noEntriesError = i18n( 0113 "The vocabulary document contains no entries that can be used for the chosen type" 0114 " of practice."); 0115 0116 // qDebug() << "Document contains " << m_entries[0].count() + m_entries[1].count() << " valid entries."; 0117 if (m_entries[0].count() + m_entries[1].count() == 0) { 0118 if (showDialog) { 0119 KMessageBox::error(nullptr, noEntriesError); 0120 } 0121 return QList<TestEntry *>(); 0122 } 0123 0124 updateCurrentSelection(); 0125 0126 bool ignoreBlocked = false; 0127 int numSelected = m_currentSelection[0].count() + m_currentSelection[1].count(); 0128 if (numSelected == 0 && showDialog) { 0129 EntryFilterDialog dialog(*this); // this pointer isn't used as pointer to parent widget here! 0130 // It should provide access to the EntryFilter data. 0131 if (dialog.exec() == QDialog::Rejected) { 0132 return QList<TestEntry *>(); 0133 } 0134 ignoreBlocked = dialog.ignoreBlocked(); 0135 } 0136 0137 // Finally, create the list of test entries from the selected 0138 // lists of EduVocTranslations. 0139 if (Prefs::practiceMode() == Prefs::EnumPracticeMode::ConjugationPractice) { 0140 QList<TestEntry *> ret = conjugationTestEntries(ignoreBlocked); 0141 if ((ret.count() == 0) && showDialog) { 0142 KMessageBox::error(nullptr, noEntriesError); 0143 } 0144 return ret; 0145 } else { 0146 // FIXME: Create entries already from the beginning so we 0147 // don't have to work with kvtml translations first and 0148 // then entries later. 0149 QList<TestEntry *> testEntries; 0150 for (int setNo = 0; setNo < m_numSets; ++setNo) { 0151 int from; 0152 int to; 0153 0154 if (setNo == 0) { 0155 switch (Prefs::practiceDirection()) { 0156 case Prefs::EnumPracticeDirection::KnownToLearning: 0157 from = Prefs::knownLanguage(); 0158 to = Prefs::learningLanguage(); 0159 break; 0160 case Prefs::EnumPracticeDirection::LearningToKnown: 0161 from = Prefs::learningLanguage(); 0162 to = Prefs::knownLanguage(); 0163 break; 0164 case Prefs::EnumPracticeDirection::MixedDirectionsWordsOnly: 0165 case Prefs::EnumPracticeDirection::MixedDirectionsWithSound: 0166 default: 0167 from = Prefs::knownLanguage(); 0168 to = Prefs::learningLanguage(); 0169 break; 0170 } 0171 } else { 0172 from = Prefs::learningLanguage(); 0173 to = Prefs::knownLanguage(); 0174 } 0175 0176 for (KEduVocExpression *entry : qAsConst(m_currentSelection[setNo])) { 0177 // Set the from and to translation for the entry itself. 0178 TestEntry *testEntry = new TestEntry(entry); 0179 0180 testEntry->setLanguageFrom(from); 0181 testEntry->setLanguageTo(to); 0182 0183 randomizedInsert(testEntries, testEntry); 0184 } 0185 } 0186 return testEntries; 0187 } 0188 } 0189 0190 void EntryFilter::expireEntries(int setNo) 0191 { 0192 if (Prefs::expire()) { 0193 int counter = 0; 0194 for (KEduVocExpression *entry : qAsConst(m_entries[setNo])) { 0195 int grade = entry->translation(m_toTranslation)->grade(); 0196 0197 const QDateTime &date = entry->translation(m_toTranslation)->practiceDate(); 0198 0199 const QDateTime &expireDate = QDateTime::currentDateTime().addSecs(-Prefs::expireItem(grade)); 0200 0201 if (date < expireDate && grade > 0) { 0202 // decrease the grade 0203 entry->translation(m_toTranslation)->decGrade(); 0204 0205 // prevent from endless dropping 0206 // use blockItem() time to prevent blocking after expiring 0207 entry->translation(m_toTranslation)->setPracticeDate(QDateTime::currentDateTime().addSecs(-Prefs::blockItem(grade - 1))); 0208 counter++; 0209 } 0210 } 0211 qDebug() << "Expired words dropped their confidence: " << counter; 0212 } 0213 } 0214 0215 void EntryFilter::collectEntries(int setNo) 0216 { 0217 // Set up the lists/sets of filtered vocabulary 0218 QList<KEduVocExpression *> entries = m_doc->lesson()->entries(KEduVocLesson::Recursive); 0219 m_entries[setNo] = QSet<KEduVocExpression *>(entries.cbegin(), entries.cend()); 0220 cleanupInvalid(setNo); 0221 0222 // FIXME the filtering needs to be done for each word or the grammar modes get included with written or somesuch 0223 0224 /* FIXME 0225 if (Prefs::genderPractice()) 0226 { 0227 if (m_doc->identifier(m_toTranslation).article().isEmpty()) 0228 { 0229 KMessageBox::error(0, i18n("The vocabulary document contains no articles for the current language. Please add some in the Edit->Grammar menu.")); 0230 return QList<KEduVocExpression*>(); 0231 } 0232 } 0233 */ 0234 } 0235 0236 void EntryFilter::setupFilteredEntries(int setNo) 0237 { 0238 lessonEntries(setNo); 0239 wordTypeEntries(setNo); 0240 blockedEntries(setNo); 0241 timesWrongEntries(setNo); 0242 timesPracticedEntries(setNo); 0243 minMaxGradeEntries(setNo); 0244 } 0245 0246 void EntryFilter::lessonEntries(int setNo) 0247 { 0248 for (KEduVocExpression *entry : qAsConst(m_entries[setNo])) { 0249 if (entry->lesson()->inPractice()) { 0250 m_entriesLesson[setNo].insert(entry); 0251 } 0252 } 0253 } 0254 0255 void EntryFilter::wordTypeEntries(int setNo) 0256 { 0257 if (Prefs::wordTypesInPracticeEnabled()) { 0258 for (KEduVocExpression *entry : qAsConst(m_entries[setNo])) { 0259 if (entry->translation(m_toTranslation)->wordType()) { 0260 if (entry->translation(m_toTranslation)->wordType()->inPractice()) { 0261 m_entriesWordType[setNo].insert(entry); 0262 } 0263 } 0264 } 0265 } else { 0266 m_entriesWordType[setNo] = m_entries[setNo]; 0267 } 0268 } 0269 0270 void EntryFilter::blockedEntries(int setNo) 0271 { 0272 if (!Prefs::block()) { 0273 m_entriesNotBlocked[setNo] = m_entries[setNo]; 0274 return; 0275 } 0276 0277 switch (Prefs::practiceMode()) { 0278 case Prefs::EnumPracticeMode::ConjugationPractice: 0279 for (KEduVocExpression *entry : qAsConst(m_entries[setNo])) { 0280 if (!isConjugationBlocked(entry->translation(m_toTranslation))) { 0281 m_entriesNotBlocked[setNo].insert(entry); 0282 } 0283 } 0284 break; 0285 case Prefs::EnumPracticeMode::GenderPractice: 0286 for (KEduVocExpression *entry : qAsConst(m_entries[setNo])) { 0287 KEduVocText article = entry->translation(m_toTranslation)->article(); 0288 if (!isBlocked(&article)) { 0289 m_entriesNotBlocked[setNo].insert(entry); 0290 } 0291 } 0292 break; 0293 case Prefs::EnumPracticeMode::ComparisonPractice: 0294 for (KEduVocExpression *entry : qAsConst(m_entries[setNo])) { 0295 KEduVocTranslation *translation = entry->translation(m_toTranslation); 0296 KEduVocText comparative = translation->comparativeForm(); 0297 KEduVocText superlative = translation->superlativeForm(); 0298 if (!isBlocked(&(comparative)) || !isBlocked(&(superlative))) { 0299 m_entriesNotBlocked[setNo].insert(entry); 0300 } 0301 } 0302 break; 0303 default: 0304 for (KEduVocExpression *entry : qAsConst(m_entries[setNo])) { 0305 if (!isBlocked(entry->translation(m_toTranslation))) { 0306 m_entriesNotBlocked[setNo].insert(entry); 0307 // debugEntry("Not blocked:", entry, 0308 // entry->translation(m_fromTranslation), 0309 // entry->translation(m_toTranslation)); 0310 } else { 0311 // debugEntry("Blocked:", entry, 0312 // entry->translation(m_fromTranslation), 0313 // entry->translation(m_toTranslation)); 0314 } 0315 } 0316 break; 0317 } 0318 } 0319 0320 bool EntryFilter::isConjugationBlocked(KEduVocTranslation *translation) const 0321 { 0322 const QStringList conjugationTenses = translation->conjugationTenses(); 0323 for (const QString &tense : conjugationTenses) { 0324 if (m_tenses.contains(tense)) { 0325 const QList<KEduVocWordFlags> pronouns = translation->getConjugation(tense).keys(); 0326 for (const KEduVocWordFlags &pronoun : pronouns) { 0327 KEduVocText grade = translation->getConjugation(tense).conjugation(pronoun); 0328 if (!isBlocked(&(grade))) { 0329 // just need to find any form that is not blocked for generating test entries 0330 // exact filtering is done later in conjugationTestEntries 0331 return false; 0332 } 0333 } 0334 } 0335 } 0336 return true; 0337 } 0338 0339 bool EntryFilter::isBlocked(const KEduVocText *const text) const 0340 { 0341 grade_t grade = text->grade(); 0342 grade_t preGrade = text->preGrade(); 0343 0344 // Sanity checks. 0345 // Note that grade_t is unsigned so no need to check < 0. 0346 // 0347 // FIXME: This should be done when the prefs are first read. 0348 if (preGrade > KV_MAX_GRADE) { 0349 preGrade = KV_MAX_GRADE; 0350 } 0351 if (grade > KV_MAX_GRADE) { 0352 grade = KV_MAX_GRADE; 0353 } 0354 0355 QDateTime now = QDateTime::currentDateTime(); 0356 0357 if ((grade == KV_NORM_GRADE && preGrade == KV_NORM_GRADE) || (grade > 0 && Prefs::blockItem(grade) == 0)) { 0358 // Always include untrained words and all words when blocking is off. 0359 0360 // qDebug() << "Not blocked, test 1; word =" << text->text() << "grade =" << grade 0361 // << "blockItem(grade) =" << Prefs::blockItem(grade); 0362 0363 return false; 0364 } else if (grade == KV_NORM_GRADE) { 0365 // Test for pregrade blocking. 0366 QDateTime date = text->practiceDate(); 0367 if (date.addSecs(preGradeTimes[preGrade]) < now) { 0368 // qDebug() << "Not blocked, test 2"; 0369 return false; 0370 } 0371 } else { 0372 // Test for grade blocking. 0373 0374 QDateTime date = text->practiceDate(); 0375 if (date.addSecs(Prefs::blockItem(grade)) < now) { 0376 // qDebug() << "Not blocked, test 3"; 0377 return false; 0378 } 0379 } 0380 0381 return true; 0382 } 0383 0384 void EntryFilter::timesWrongEntries(int setNo) 0385 { 0386 for (KEduVocExpression *entry : qAsConst(m_entries[setNo])) { 0387 if (entry->translation(m_toTranslation)->badCount() >= Prefs::practiceMinimumWrongCount() 0388 && entry->translation(m_toTranslation)->badCount() <= Prefs::practiceMaximumWrongCount()) { 0389 m_entriesTimesWrong[setNo].insert(entry); 0390 } 0391 } 0392 } 0393 0394 void EntryFilter::timesPracticedEntries(int setNo) 0395 { 0396 for (KEduVocExpression *entry : qAsConst(m_entries[setNo])) { 0397 if (entry->translation(m_toTranslation)->practiceCount() >= Prefs::practiceMinimumTimesAsked() 0398 && entry->translation(m_toTranslation)->practiceCount() <= Prefs::practiceMaximumTimesAsked()) { 0399 m_entriesTimesPracticed[setNo].insert(entry); 0400 } 0401 } 0402 } 0403 0404 void EntryFilter::minMaxGradeEntries(int setNo) 0405 { 0406 for (KEduVocExpression *entry : qAsConst(m_entries[setNo])) { 0407 int grade = entry->translation(m_toTranslation)->grade(); 0408 if (grade >= Prefs::practiceMinimumGrade() && grade <= Prefs::practiceMaximumGrade()) { 0409 m_entriesMinMaxGrade[setNo].insert(entry); 0410 } 0411 } 0412 } 0413 /* 0414 if (m_testType == Prefs::EnumTestType::ArticleTest) { 0415 KMessageBox::information(0, 0416 i18n("You selected to practice the genders of nouns, but no appropriate nouns could be found. Use \"Edit Entry\" and select Noun as word type and the 0417 gender."), i18n("No valid word type found")); return; 0418 } 0419 if (m_testType == Prefs::EnumTestType::ComparisonTest) { 0420 KMessageBox::information(0, 0421 i18n("You selected to practice comparison forms, but no adjectives or adverbs containing comparison forms could be found. Use \"Edit Entry\" and select 0422 Adverb or Adjective as word type and enter the comparison forms."), i18n("No valid word type found")); return; 0423 } 0424 if (m_testType == Prefs::EnumTestType::ConjugationTest) { 0425 KMessageBox::information(0, i18n("You selected to practice conjugations, but no vocabulary containing conjugations in the tenses you selected could be found. 0426 Use \"Edit Entry\" and select Verb as word type and enter the conjugation forms."), i18n("No valid word type found")); return; 0427 } 0428 } 0429 0430 if ( removeTestEntryList.count() == m_entries.count() ) { 0431 if ( KMessageBox::questionYesNo(0, i18n("<p>The units you selected for the practice contain no entries when the threshold settings are respected.</p><p>Hint: 0432 To configure the thresholds use the \"Threshold Page\" in the \"Configure Practice\" dialog.</p><p>Would you like to ignore the threshold setting?</p>"), 0433 i18n("No Entries with Current Threshold Settings") ) == KMessageBox::No ) { return; 0434 } 0435 0436 */ 0437 0438 void EntryFilter::cleanupInvalid(int setNo) 0439 { 0440 Prefs::EnumPracticeMode::type mode = Prefs::practiceMode(); 0441 bool wordTypeNeeded = (mode == Prefs::EnumPracticeMode::GenderPractice) || (mode == Prefs::EnumPracticeMode::ComparisonPractice) 0442 || (mode == Prefs::EnumPracticeMode::ConjugationPractice); 0443 0444 QSet<KEduVocExpression *>::iterator i = m_entries[setNo].begin(); 0445 while (i != m_entries[setNo].end()) { 0446 KEduVocTranslation *fromTranslation = (*i)->translation(m_fromTranslation); 0447 KEduVocTranslation *toTranslation = (*i)->translation(m_toTranslation); 0448 0449 // Remove empty entries. 0450 bool keep = ((!fromTranslation->text().isEmpty() || (Prefs::allowImageInsteadOfWord() && !fromTranslation->imageUrl().isEmpty())) 0451 && !toTranslation->text().isEmpty()); 0452 if (!keep) { 0453 i = m_entries[setNo].erase(i); 0454 // debugEntry("Removing empty:", *i, fromTranslation, toTranslation); 0455 continue; 0456 } 0457 0458 // For grammar stuff we need the word to have its word type set, else continue 0459 if (wordTypeNeeded && !(*i)->translation(m_toTranslation)->wordType()) { 0460 i = m_entries[setNo].erase(i); 0461 continue; 0462 } 0463 0464 // Grammar modes need different things: 0465 switch (Prefs::practiceMode()) { 0466 // example sentences: need the example sentence to exist 0467 case Prefs::EnumPracticeMode::ExampleSentencesPractice: 0468 if ((*i)->translation(m_toTranslation)->example().simplified().isEmpty()) { 0469 i = m_entries[setNo].erase(i); 0470 continue; 0471 } 0472 break; 0473 0474 case Prefs::EnumPracticeMode::GenderPractice: 0475 if (!((*i)->translation(m_toTranslation)->wordType()->wordType() & KEduVocWordFlag::Noun)) { 0476 i = m_entries[setNo].erase(i); 0477 continue; 0478 } 0479 break; 0480 0481 case Prefs::EnumPracticeMode::ComparisonPractice: 0482 if ( 0483 // only adjective/adverb 0484 (((*i)->translation(m_toTranslation)->wordType()->wordType() != KEduVocWordFlag::Adjective) 0485 && ((*i)->translation(m_toTranslation)->wordType()->wordType() != KEduVocWordFlag::Adverb)) 0486 // at least one comparison forms is there 0487 || ((*i)->translation(m_toTranslation)->comparativeForm().text().isEmpty() 0488 || (*i)->translation(m_toTranslation)->superlativeForm().text().isEmpty())) { 0489 i = m_entries[setNo].erase(i); 0490 continue; 0491 } 0492 break; 0493 0494 case Prefs::EnumPracticeMode::ConjugationPractice: { 0495 KEduVocTranslation *translation = (*i)->translation(m_toTranslation); 0496 bool erase = false; 0497 0498 // Remove entries which are not verbs 0499 if (translation->wordType()->wordType() != KEduVocWordFlag::Verb) { 0500 erase = true; 0501 } 0502 0503 // Remove entries which don't have any of the tenses which are configured for practice 0504 QSet<QString> practice_tenses = QSet<QString>(m_tenses.begin(), m_tenses.end()); 0505 QSet<QString> existing_tenses; 0506 const QStringList conjugationTenses = translation->conjugationTenses(); 0507 for (const QString &tense : conjugationTenses) { 0508 if (!translation->getConjugation(tense).isEmpty()) { 0509 existing_tenses << tense; 0510 } 0511 } 0512 if (!existing_tenses.intersects(practice_tenses)) 0513 erase = true; 0514 0515 if (erase) { 0516 i = m_entries[setNo].erase(i); 0517 continue; 0518 } 0519 break; 0520 } 0521 default: 0522 break; 0523 } // switch 0524 ++i; 0525 } // while 0526 // qDebug() << "Invalid items removed. Remaining: " << m_entries[setNo].count(); 0527 } 0528 0529 QList<TestEntry *> EntryFilter::conjugationTestEntries(bool ignoreBlocked) const 0530 { 0531 // qDebug() << "Filtering conjugation entries for tenses... " << m_tenses; 0532 0533 // TODO CM make this configurable 0534 enum MODE { M_SEPARATE, M_COMPLETE }; 0535 MODE mode = M_SEPARATE; 0536 0537 QList<TestEntry *> testEntries; 0538 for (int i = 0; i < m_numSets; ++i) { 0539 for (KEduVocExpression *entry : qAsConst(m_currentSelection[i])) { 0540 const QStringList conjugationTenses = entry->translation(m_toTranslation)->conjugationTenses(); 0541 for (const QString &tense : conjugationTenses) { 0542 // Only include tenses which are both non-empty and which should be practiced 0543 if (!m_tenses.contains(tense)) { 0544 continue; 0545 } 0546 KEduVocConjugation conjugation = entry->translation(m_toTranslation)->getConjugation(tense); 0547 if (conjugation.isEmpty()) { 0548 continue; 0549 } 0550 0551 bool blocked = true; 0552 const QList<KEduVocWordFlags> pronouns = conjugation.keys(); 0553 for (const KEduVocWordFlags &pronoun : pronouns) { 0554 KEduVocText *grade = &conjugation.conjugation(pronoun); 0555 if (ignoreBlocked || !isBlocked(grade)) { 0556 blocked = false; 0557 0558 if (mode == M_SEPARATE) { 0559 TestEntry *testEntry = new TestEntry(entry); 0560 testEntry->setConjugationTense(tense); 0561 testEntry->setLanguageTo(m_toTranslation); 0562 testEntry->setLanguageFrom(m_fromTranslation); 0563 QList<KEduVocWordFlags> list; 0564 list << pronoun; 0565 testEntry->setConjugationPronouns(list); 0566 randomizedInsert(testEntries, testEntry); 0567 } 0568 } 0569 } 0570 0571 if (!blocked && mode == M_COMPLETE) { 0572 TestEntry *testEntry = new TestEntry(entry); 0573 testEntry->setConjugationTense(tense); 0574 testEntry->setConjugationPronouns(pronouns); 0575 testEntry->setLanguageTo(m_toTranslation); 0576 testEntry->setLanguageFrom(m_fromTranslation); 0577 randomizedInsert(testEntries, testEntry); 0578 } 0579 } 0580 } 0581 } 0582 return testEntries; 0583 } 0584 0585 void EntryFilter::updateCurrentSelection() 0586 { 0587 for (int i = 0; i < m_numSets; ++i) { 0588 m_currentSelection[i] = m_entries[i]; 0589 m_currentSelection[i] = m_currentSelection[i].intersect(m_entriesLesson[i]); 0590 m_currentSelection[i] = m_currentSelection[i].intersect(m_entriesWordType[i]); 0591 m_currentSelection[i] = m_currentSelection[i].intersect(m_entriesNotBlocked[i]); 0592 m_currentSelection[i] = m_currentSelection[i].intersect(m_entriesTimesWrong[i]); 0593 m_currentSelection[i] = m_currentSelection[i].intersect(m_entriesTimesPracticed[i]); 0594 m_currentSelection[i] = m_currentSelection[i].intersect(m_entriesMinMaxGrade[i]); 0595 } 0596 } 0597 0598 // ---------------------------------------------------------------- 0599 // Utilities 0600 0601 void EntryFilter::randomizedInsert(QList<TestEntry *> &list, TestEntry *entry) 0602 { 0603 list.insert(QRandomGenerator::global()->bounded(list.size() + 1), entry); 0604 } 0605 0606 #include "moc_entryfilter.cpp"