File indexing completed on 2024-04-14 03:49:11

0001 /*
0002     SPDX-FileCopyrightText: 2009-2010 Frederik Gladhorn <gladhorn@kde.org>
0003     SPDX-FileCopyrightText: 2009 Daniel Laidig <d.laidig@gmx.de>
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #include "practicestatemachine.h"
0008 
0009 #include "parleydocument.h"
0010 
0011 #include "comparisonbackendmode.h"
0012 #include "conjugationbackendmode.h"
0013 #include "examplesentencebackendmode.h"
0014 #include "flashcardbackendmode.h"
0015 #include "genderbackendmode.h"
0016 #include "multiplechoicebackendmode.h"
0017 #include "prefs.h"
0018 #include "writtenbackendmode.h"
0019 
0020 using namespace Practice;
0021 
0022 PracticeStateMachine::PracticeStateMachine(AbstractFrontend *frontend, ParleyDocument *doc, SessionManagerBase *sessionManager, QObject *parent)
0023     : QObject(parent)
0024     , m_frontend(frontend)
0025     , m_document(doc)
0026     , m_sessionManager(sessionManager)
0027 {
0028     createPracticeMode();
0029 
0030     // To allow to skip an an entry
0031     connect(m_frontend, &AbstractFrontend::skipAction, this, &PracticeStateMachine::nextEntry);
0032     connect(m_frontend, &AbstractFrontend::stopPractice, this, &PracticeStateMachine::slotPracticeFinished);
0033     connect(m_frontend, &AbstractFrontend::hintAction, m_mode, &AbstractBackendMode::hintAction);
0034 
0035     connect(m_frontend, &AbstractFrontend::continueAction, this, &PracticeStateMachine::continueAction);
0036 
0037     connect(m_mode, &AbstractBackendMode::answerRight, this, &PracticeStateMachine::answerRight);
0038     connect(m_mode, &AbstractBackendMode::answerWrongRetry, this, &PracticeStateMachine::answerWrongRetry);
0039     connect(m_mode, &AbstractBackendMode::answerWrongShowSolution, this, &PracticeStateMachine::answerWrongShowSolution);
0040     connect(m_mode, &AbstractBackendMode::showSolution, this, &PracticeStateMachine::showSolution);
0041 }
0042 
0043 void PracticeStateMachine::createPracticeMode()
0044 {
0045     switch (Prefs::practiceMode()) {
0046     case Prefs::EnumPracticeMode::FlashCardsPractice:
0047         qDebug() << "Create Flash Card Practice backend";
0048         m_frontend->setMode(AbstractFrontend::FlashCard);
0049         m_mode = new FlashCardBackendMode(m_frontend, this);
0050         break;
0051     case Prefs::EnumPracticeMode::MultipleChoicePractice:
0052         qDebug() << "Create MultipleChoice Practice backend";
0053         m_frontend->setMode(AbstractFrontend::MultipleChoice);
0054         m_mode = new MultipleChoiceBackendMode(m_frontend, this, m_sessionManager);
0055         break;
0056     case Prefs::EnumPracticeMode::MixedLettersPractice:
0057         qDebug() << "Create Mixed Letters Practice backend";
0058         m_frontend->setMode(AbstractFrontend::MixedLetters);
0059         m_mode = new WrittenBackendMode(m_frontend, this, m_sessionManager, m_document->document().get());
0060         break;
0061     case Prefs::EnumPracticeMode::WrittenPractice:
0062         qDebug() << "Create Written Practice backend";
0063         m_frontend->setMode(AbstractFrontend::Written);
0064         m_mode = new WrittenBackendMode(m_frontend, this, m_sessionManager, m_document->document().get());
0065         break;
0066     case Prefs::EnumPracticeMode::ExampleSentencesPractice:
0067         qDebug() << "Create Written Practice backend";
0068         m_frontend->setMode(AbstractFrontend::ExampleSentence);
0069         m_mode = new ExampleSentenceBackendMode(m_frontend, this, m_sessionManager, m_document->document().get());
0070         break;
0071     case Prefs::EnumPracticeMode::GenderPractice:
0072         m_frontend->setMode(AbstractFrontend::MultipleChoice);
0073         m_mode = new GenderBackendMode(m_frontend, this, m_sessionManager, m_document->document().get());
0074         break;
0075     case Prefs::EnumPracticeMode::ConjugationPractice:
0076         m_frontend->setMode(AbstractFrontend::Conjugation);
0077         m_mode = new ConjugationBackendMode(m_frontend, this, m_sessionManager, m_document->document().get());
0078         break;
0079     case Prefs::EnumPracticeMode::ComparisonPractice:
0080         m_frontend->setMode(AbstractFrontend::Comparison);
0081         m_mode = new ComparisonBackendMode(m_frontend, this, m_sessionManager, m_document->document().get());
0082         break;
0083 
0084     default:
0085         Q_ASSERT("Implement selected practice mode" == nullptr);
0086     }
0087 }
0088 
0089 void Practice::PracticeStateMachine::start()
0090 {
0091     qDebug() << "Start practice";
0092     m_sessionManager->practiceStarted();
0093     nextEntry();
0094 }
0095 
0096 void PracticeStateMachine::nextEntry()
0097 {
0098     m_state = NotAnswered;
0099     m_current = m_sessionManager->nextTrainingEntry();
0100 
0101     // qDebug() << "GETTING ENTRY - " << m_current;
0102 
0103     // after going through all words, or at the start of practice
0104     if (m_current == nullptr) {
0105         slotPracticeFinished();
0106         return;
0107     }
0108     if (!m_mode->setTestEntry(m_current)) {
0109         // this is just a fall back, if an invalid entry slipped through
0110         currentEntryFinished();
0111         nextEntry();
0112     }
0113     updateFrontend();
0114 }
0115 
0116 void PracticeStateMachine::slotPracticeFinished()
0117 {
0118     qDebug() << "Stop practice";
0119     m_sessionManager->practiceFinished();
0120     Q_EMIT practiceFinished();
0121 }
0122 
0123 void PracticeStateMachine::currentEntryFinished()
0124 {
0125     m_sessionManager->removeCurrentEntryFromPractice();
0126 }
0127 
0128 void PracticeStateMachine::continueAction()
0129 {
0130     // qDebug() << "continue" << m_state;
0131     switch (m_state) {
0132         // on continue, we check the answer, if in NotAnsweredState or AnswerWasWrongState
0133     case NotAnswered:
0134     case AnswerWasWrong:
0135         m_mode->checkAnswer();
0136         break;
0137 
0138     case SolutionShown:
0139         gradeEntryAndContinue();
0140         break;
0141     }
0142 }
0143 
0144 void PracticeStateMachine::answerRight()
0145 {
0146     // qDebug() << "ans right";
0147 
0148     m_frontend->setFeedbackState(AbstractFrontend::AnswerCorrect);
0149     if (m_state == NotAnswered) {
0150         m_frontend->setResultState(AbstractFrontend::AnswerCorrect);
0151     } else {
0152         m_frontend->setResultState(AbstractFrontend::AnswerWrong);
0153     }
0154 
0155     m_state = SolutionShown;
0156     m_frontend->showSolution();
0157 }
0158 
0159 void PracticeStateMachine::answerWrongRetry()
0160 {
0161     // qDebug() << "wrong retr";
0162     m_frontend->setFeedbackState(AbstractFrontend::AnswerWrong);
0163     m_state = AnswerWasWrong;
0164 }
0165 
0166 void PracticeStateMachine::answerWrongShowSolution()
0167 {
0168     // qDebug() << "wrong sol";
0169     m_frontend->setFeedbackState(AbstractFrontend::AnswerWrong);
0170     // User gave an empty answer or the same answer for a second time so we want to drop out.
0171     m_frontend->setResultState(AbstractFrontend::AnswerWrong);
0172     m_state = SolutionShown;
0173     m_frontend->showSolution();
0174 }
0175 
0176 void PracticeStateMachine::showSolution()
0177 {
0178     // qDebug() << "show solution";
0179     m_state = SolutionShown;
0180     m_frontend->showSolution();
0181 }
0182 
0183 void PracticeStateMachine::updateFrontend()
0184 {
0185     m_frontend->setFeedbackState(AbstractFrontend::QuestionState);
0186     m_frontend->setResultState(AbstractFrontend::QuestionState);
0187     m_frontend->setLessonName(m_current->entry()->lesson()->name());
0188     grade_t grade = m_mode->currentGradeForEntry();
0189     m_frontend->showGrade(m_mode->currentPreGradeForEntry(), grade);
0190 
0191     // show the word that is currently practiced in the progress bar
0192     m_frontend->setFinishedWordsTotalWords(m_sessionManager->allEntryCount() - m_sessionManager->activeEntryCount(), m_sessionManager->allEntryCount());
0193 
0194     // Set fonts
0195     m_frontend->setQuestionFont((m_current->languageFrom() == Prefs::learningLanguage()) ? m_frontend->learningLangFont() : m_frontend->knownLangFont());
0196     m_frontend->setSolutionFont((m_current->languageTo() == Prefs::learningLanguage()) ? m_frontend->learningLangFont() : m_frontend->knownLangFont());
0197 
0198     grade_t goodGrade = qMax(grade, grade_t(KV_LEV1_GRADE)); // if the word hasn't been practiced yet, use grade 1 as a base
0199 
0200     if (m_current->statisticBadCount() == 0) {
0201         goodGrade = qMax(KV_LEV2_GRADE, qMin(grade + 1, KV_MAX_GRADE));
0202     }
0203 
0204     m_frontend->setBoxes(grade, goodGrade, KV_LEV1_GRADE);
0205 
0206     QUrl imgFrom = m_current->entry()->translation(m_current->languageFrom())->imageUrl();
0207     QUrl imgTo = m_current->entry()->translation(m_current->languageTo())->imageUrl();
0208     if (imgFrom.isEmpty()) {
0209         imgFrom = imgTo;
0210     }
0211     if (imgTo.isEmpty()) {
0212         imgTo = imgFrom;
0213     }
0214     if (Prefs::flashcardsFrontImage()) {
0215         m_frontend->setQuestionImage(imgFrom);
0216     } else {
0217         m_frontend->setQuestionImage(QUrl());
0218     }
0219     if (Prefs::flashcardsBackImage()) {
0220         m_frontend->setSolutionImage(imgTo);
0221     } else {
0222         m_frontend->setSolutionImage(QUrl());
0223     }
0224     m_frontend->showQuestion();
0225 }
0226 
0227 void PracticeStateMachine::gradeEntryAndContinue()
0228 {
0229     grade_t currentPreGrade = m_mode->currentPreGradeForEntry();
0230     grade_t currentGrade = m_mode->currentGradeForEntry();
0231 
0232     if (m_frontend->resultState() == AbstractFrontend::AnswerCorrect) {
0233         m_current->updateStatisticsRightAnswer(currentPreGrade, currentGrade);
0234     } else {
0235         m_current->updateStatisticsWrongAnswer(currentPreGrade, currentGrade);
0236     }
0237 
0238     if (m_current->shouldChangeGrades()) {
0239         m_mode->updateGrades();
0240         if (m_frontend->resultState() == AbstractFrontend::AnswerCorrect) {
0241             currentEntryFinished();
0242         }
0243     }
0244     nextEntry();
0245 }
0246 
0247 #include "moc_practicestatemachine.cpp"