diff --git a/changes b/changes index 3128ad69c246879f145f1f0908eff3113d263ab9..a447b27779368d9d9d58b0fc8c81bed558039291 100644 --- a/changes +++ b/changes @@ -1,3 +1,7 @@ +1.7.3 git + - exam melodies can be played in order from melody set + - user can define repeats number of melodies from the set + 1.7.2 beta2 - improved rhythm detection - bug fixes diff --git a/src/dialogs/tlevelcreatoritem.cpp b/src/dialogs/tlevelcreatoritem.cpp index 436a8780780d051eb64bb7520dc6bfefb2891160..ec0f84170366cd9f10b945ba591ad5ecae1faea8 100644 --- a/src/dialogs/tlevelcreatoritem.cpp +++ b/src/dialogs/tlevelcreatoritem.cpp @@ -344,6 +344,18 @@ void TlevelCreatorItem::setKeyOfRandList(int key) { levelParamChanged(); } +bool TlevelCreatorItem::randomOrder() const { return m_level->randOrderInSet; } +void TlevelCreatorItem::setRandomOrder(bool randO) { + m_level->randOrderInSet = randO; + levelParamChanged(); +} + +int TlevelCreatorItem::repeatsNumber() const { return m_level->repeatNrInSet; } +void TlevelCreatorItem::setRepeatsNumber(int rNr) { + m_level->repeatNrInSet = static_cast<quint8>(rNr); + levelParamChanged(); +} + // Range page int TlevelCreatorItem::loFret() const { return static_cast<int>(m_level->loFret); } diff --git a/src/dialogs/tlevelcreatoritem.h b/src/dialogs/tlevelcreatoritem.h index 58a61b6f913a76996b8f4ff656515951f3051633..5b23d6c43be0539ef07186dabfbd1b90d927db93 100644 --- a/src/dialogs/tlevelcreatoritem.h +++ b/src/dialogs/tlevelcreatoritem.h @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2017-2018 by Tomasz Bojczuk * + * Copyright (C) 2017-2020 by Tomasz Bojczuk * * seelook@gmail.com * * * * This program is free software; you can redistribute it and/or modify * @@ -65,6 +65,8 @@ class TlevelCreatorItem : public QQuickItem Q_PROPERTY(bool endsOnTonic READ endsOnTonic WRITE setEndsOnTonic NOTIFY updateLevel) Q_PROPERTY(int randMelody READ randMelody WRITE setRandMelody NOTIFY updateLevel) Q_PROPERTY(int keyOfRandList READ keyOfRandList WRITE setKeyOfRandList NOTIFY updateLevel) + Q_PROPERTY(bool randomOrder READ randomOrder WRITE setRandomOrder NOTIFY updateLevel) + Q_PROPERTY(qreal repeatsNumber READ repeatsNumber WRITE setRepeatsNumber NOTIFY updateLevel) // Range Q_PROPERTY(int loFret READ loFret WRITE setLoFret NOTIFY updateLevel) Q_PROPERTY(int hiFret READ hiFret WRITE setHiFret NOTIFY updateLevel) @@ -165,6 +167,12 @@ public: int keyOfRandList() const; void setKeyOfRandList(int key); + bool randomOrder() const; + void setRandomOrder(bool randO); + + int repeatsNumber() const; + void setRepeatsNumber(int rNr); + // Range page int loFret() const; void setLoFret(int lf); diff --git a/src/libs/core/exam/texam.cpp b/src/libs/core/exam/texam.cpp index cc787e1f51129d5487936693e5340b6e3101d3c1..a522d37cd2f4f1cebb3404a414de0d88fa518083 100644 --- a/src/libs/core/exam/texam.cpp +++ b/src/libs/core/exam/texam.cpp @@ -510,18 +510,18 @@ void Texam::sumarizeAnswer() { void Texam::addPenalties() { if (!curQ()->isCorrect()) { - if (melodies()) - m_blackNumbers.append(-1); // one more random melody + if (melodies()) // for any kind of mistake add one more random melody or mistaken one if not random and melody set + m_blackNumbers.append(m_level->isMelodySet() && !m_level->randOrderInSet ? count() - 1 : -1); if (curQ()->isNotSoBad()) { - if (!isExercise() /*&& !melodies() */&& !isFinished()) - m_penaltysNr++; + if (!isExercise() && !isFinished()) + m_penaltysNr++; if (!melodies()) m_halfMistNr++; } else { if (melodies()) m_blackNumbers.append(count() - 1); // repeat current melody in some further question - if (!isExercise() /*&& !melodies() */&& !isFinished()) - m_penaltysNr += 2; + if (!isExercise() && !isFinished()) + m_penaltysNr += 2; if (!melodies()) m_mistNr++; } diff --git a/src/main/texamexecutor.cpp b/src/main/texamexecutor.cpp index 6e469a9d288304b215ecd9a271e78ba34d0bda18..e2c56647332b11f9522027262cff2f4428c71256 100644 --- a/src/main/texamexecutor.cpp +++ b/src/main/texamexecutor.cpp @@ -172,8 +172,29 @@ bool TexamExecutor::continueInit() { m_supp = new TexecutorSupply(&m_level, this); // TODO: when level has its own list of notes for melodies - it is wasting energy! m_supp->createQuestionsList(m_questList); - if (m_exam->melodies()) + + if (m_exam->melodies()) { m_melody = new TexamMelody(this); + if (m_level.randMelody == Tlevel::e_randFromList && !m_level.randOrderInSet) { + // Determine id of melody in the set and initialize appropriate variables + auto lastQ = m_exam->count() ? nullptr : m_exam->curQ(); + if (lastQ) { // exam is continued, so find latest melody id and how many times it was asked already + int q = m_exam->count() - 1; + int repeatNr = 1; + while (q >= 0 && lastQ->idOfMelody() == m_exam->question(q)->idOfMelody()) { + q--; + repeatNr++; + } + m_melody->setLastMelodyId(lastQ->idOfMelody() + (repeatNr >= m_level.repeatNrInSet ? 1 : 0)); + if (m_melody->lastMelodyId() >= m_level.melodySet.count()) { + qDebug() << "[TexamExecutor] FIXME! Melody ID in the set is greater than melodies number there!"; + m_melody->setLastMelodyId(m_level.melodySet.count() - 1); + } + m_melody->setRepeat(repeatNr); + } + // for newly started exam, above variables are initialized by default + } + } if (m_questList.isEmpty() && !m_level.isMelodySet()) { QMessageBox::critical(nullptr, QString(), tr("Level <b>%1</b><br>makes no sense because there are no questions to ask.<br>It can be re-adjusted.<br>Repair it in Level Creator and try again.").arg(m_level.name)); return false; @@ -245,7 +266,7 @@ void TexamExecutor::askQuestion(bool isAttempt) { if (!isAttempt) { // add new question to the list m_penalty->setMelodyPenalties(); if (m_exam->count() && m_exercise) // Check answer only after summarize - m_exercise->checkAnswer(); + m_exercise->checkAnswer(); TQAunit Q(m_exam); m_exam->addQuestion(Q); } @@ -298,35 +319,62 @@ void TexamExecutor::askQuestion(bool isAttempt) { disconnect(MAIN_SCORE, &TmainScoreObject::readOnlyNoteClicked, this, &TexamExecutor::correctNoteOfMelody); int melodyLength = qBound(qMax(2, qRound(m_level.melodyLen * 0.7)), //at least 70% of length but not less than 2 qRound(((6.0 + (qrand() % 5)) / 10.0) * (qreal)m_level.melodyLen), (int)m_level.melodyLen); + qDebug() << "========== Asking melody" << m_exam->count(); if (m_penalty->isNot()) { - TrhythmList rhythms; - if (!m_level.isMelodySet()) { - curQ->addMelody(QString("%1").arg(m_exam->count())); - curQ->melody()->setKey(curQ->key); - if (m_level.useRhythms()) { - curQ->melody()->setMeter(m_supp->randomMeter()); - int barsNr = m_supp->getBarNumber(m_exam->count(), m_exam->penalty()); - rhythms = getRandomRhythm(curQ->melody()->meter()->meter(), barsNr, m_level.basicRhythms, m_level.dotsRhythms, m_level.rhythmDiversity); - melodyLength = rhythms.count(); + TrhythmList rhythms; + if (!m_level.isMelodySet()) { + curQ->addMelody(QString("%1").arg(m_exam->count())); + curQ->melody()->setKey(curQ->key); + if (m_level.useRhythms()) { + curQ->melody()->setMeter(m_supp->randomMeter()); + int barsNr = m_supp->getBarNumber(m_exam->count(), m_exam->penalty()); + rhythms = getRandomRhythm(curQ->melody()->meter()->meter(), barsNr, m_level.basicRhythms, m_level.dotsRhythms, m_level.rhythmDiversity); + melodyLength = rhythms.count(); + } } - } - if (m_level.randMelody == Tlevel::e_randFromList) { - QList<TQAgroup> qaList; - m_supp->listForRandomNotes(curQ->key, qaList); - // ignore in key (4th param) of level, notes from list are already in key (if required) - getRandomMelodyNG(qaList, curQ->melody(), melodyLength, false, false); - } else if (m_level.randMelody == Tlevel::e_melodyFromSet) { - int melodyId = m_rand->get(); - curQ->addMelody(&m_level.melodySet[melodyId], TQAunit::e_srcLevelSet, melodyId); - if (!m_level.useKeySign) // respect melody key to avoid transposition - curQ->key = curQ->melody()->key(); - melodyLength = curQ->melody()->length(); - } else { // Tlevel::e_melodyFromRange - getRandomMelodyNG(m_questList, curQ->melody(), melodyLength, m_level.onlyCurrKey, m_level.endsOnTonic); - } - if (!m_level.isMelodySet() && m_level.useRhythms()) { - mergeRhythmAndMelody(rhythms, curQ->melody()); - } + if (m_level.randMelody == Tlevel::e_randFromList) { + QList<TQAgroup> qaList; + m_supp->listForRandomNotes(curQ->key, qaList); + // ignore in key (4th param) of level, notes from list are already in key (if required) + getRandomMelodyNG(qaList, curQ->melody(), melodyLength, false, false); + } else if (m_level.randMelody == Tlevel::e_melodyFromSet) { + // Randomize melody number or get it in order of the melody set + int melodyId = m_melody->lastMelodyId(); + if (m_level.randOrderInSet) { + melodyId = m_rand->get(); + } else { + // Set the next melody ID: + // It may be the same ID when repetition number is not fulfilled + // or the next melody when repeated enough or this is exercise + qDebug() << "[MELODY SET] ID" << m_melody->lastMelodyId() << "repeat" << m_melody->repeatCounter() << "of" << m_level.repeatNrInSet; + m_melody->nextRepeat(); + if (m_exercise || m_melody->repeatCounter() > m_level.repeatNrInSet) { + m_melody->setRepeat(1); + m_melody->setLastMelodyId(melodyId + 1); + if (m_melody->lastMelodyId() >= m_level.melodySet.count()) { + if (m_exercise) { + m_melody->setLastMelodyId(0); // start from the first melody + qDebug() << "[TexamExecutor] All melodies were exercised, starting again."; + } else { // TODO It should never happen, delete when tested + if (m_exam->count() < m_supp->obligQuestions() + m_exam->penalty()) + qDebug() << "[TexamExecutor] FIXME! Trying to get melody out of the list!"; + m_melody->setLastMelodyId(m_level.melodySet.count() - 1); + } + } + } + } + curQ->addMelody(&m_level.melodySet[melodyId], TQAunit::e_srcLevelSet, melodyId); + if (!m_level.useKeySign) // respect melody key to avoid transposition + curQ->key = curQ->melody()->key(); + melodyLength = curQ->melody()->length(); + } else { // Tlevel::e_melodyFromRange + getRandomMelodyNG(m_questList, curQ->melody(), melodyLength, m_level.onlyCurrKey, m_level.endsOnTonic); + } + if (!m_level.isMelodySet() && m_level.useRhythms()) { + mergeRhythmAndMelody(rhythms, curQ->melody()); + } + } else { + melodyLength = curQ->melody()->length(); } m_melody->newMelody(curQ->answerAsSound() ? curQ->melody()->length() : 0); // prepare list to store notes played by user or clear it m_exam->newAttempt(); diff --git a/src/main/texammelody.h b/src/main/texammelody.h index f7352e08138f7818c993d2d34075e9ed4ef5a4b8..e42131cf6fa0f8a35192b47808aed6d9b46cb170 100644 --- a/src/main/texammelody.h +++ b/src/main/texammelody.h @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2014-2018 by Tomasz Bojczuk * + * Copyright (C) 2014-2020 by Tomasz Bojczuk * * seelook@gmail.com * * * * This program is free software; you can redistribute it and/or modify * @@ -35,7 +35,7 @@ class TnoteStruct; * then @p wasIndexChenged() returns @p TRUE but invoking @p noteStarted() * will reset it to @p FALSE again. * This way can be counted how many times user started to play a melody. - * + * * It also manages of a list of fixed melody notes during correction. * List is stored in @p attemptFix() and can be reset by @p clearToFix(). * Then @p setFixed() sets given note to @p TRUE and @p fixed() returns its state. @@ -100,6 +100,20 @@ public: */ bool wasLatestNoteSet() const { return m_indexOfSaved == m_currentIndex; } + /** + * Counts how many times the same melody was asked + */ + int repeatCounter() const { return m_repeatCounter; } + void setRepeat(int r) { m_repeatCounter = r; } + + /** + * Increases repeat counter + */ + void nextRepeat() { m_repeatCounter++; } + + int lastMelodyId() const { return m_lastMelodyId; } + void setLastMelodyId(int li) { m_lastMelodyId = li; } + private: QList<TnoteStruct> m_listened; @@ -109,6 +123,8 @@ private: int m_numberOfFixed; QList<bool> m_attemptFix; + int m_repeatCounter = 1; + int m_lastMelodyId = 0; }; #endif // TEXAMMELODY_H diff --git a/src/main/tpenalty.cpp b/src/main/tpenalty.cpp index 8e0e2032f2f434272625969fa78f2375aba9e949..048c89add823951326c2388c07559bcb7e7c9d1d 100644 --- a/src/main/tpenalty.cpp +++ b/src/main/tpenalty.cpp @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2014-2017 by Tomasz Bojczuk * + * Copyright (C) 2014-2020 by Tomasz Bojczuk * * seelook@gmail.com * * * * This program is free software; you can redistribute it and/or modify * @@ -20,6 +20,7 @@ #include "texecutorsupply.h" #include "texamview.h" #include <exam/texam.h> +#include <exam/tlevel.h> #include <QtCore/qdebug.h> @@ -39,19 +40,18 @@ Tpenalty::Tpenalty(Texam* exam, TexecutorSupply* supply) : if (m_exam->isFinished()) { m_supply->setFinished(); qDebug() << "Exam was finished"; - } else { - int remained = (m_supply->obligQuestions() + m_exam->penalty()) - m_exam->count(); - remained = qMax(0, remained); - if (remained < m_exam->blackCount()) { - m_exam->increasePenaltys(m_exam->blackCount() - remained); - qDebug() << "penalties number adjusted:" << m_exam->blackCount() - remained; -// RESULTS->startExam(m_exam, m_supply->obligQuestions()); - } - if (remained == 0 && m_exam->blackCount() == 0) { - m_supply->setFinished(); - m_exam->setFinished(); - qDebug() << "Finished exam was detected"; - } + } else { + int remained = (m_supply->obligQuestions() + m_exam->penalty()) - m_exam->count(); + remained = qMax(0, remained); + if (remained < m_exam->blackCount()) { + m_exam->increasePenaltys(m_exam->blackCount() - remained); + qDebug() << "[Tpenalty] penalties number adjusted:" << m_exam->blackCount() - remained; + } + if (remained == 0 && m_exam->blackCount() == 0) { + m_supply->setFinished(); + m_exam->setFinished(); + qDebug() << "[Tpenalty] Finished exam was detected"; + } } RESULTS->displayTime(); } @@ -69,32 +69,32 @@ void Tpenalty::nextQuestion() { bool Tpenalty::ask() { if (m_exam->melodies()) { - if (m_exam->blackNumbers()->size() && m_penalCount > m_penalStep) { - m_penalCount = 0; - int idInList = qrand() % m_exam->blackNumbers()->size(); - m_blackNumber = m_exam->blackNumbers()->at(idInList); - m_exam->blackNumbers()->removeAt(idInList); -// qDebug() << "penalty melody" << m_blackNumber; - if (m_blackNumber != -1) { - m_exam->curQ()->copy(*m_exam->answList()->operator[](m_blackNumber)); // copy black question into last unit + if (m_exam->blackNumbers()->size() && m_penalCount > m_penalStep) { + m_penalCount = 0; + int idInList = qrand() % m_exam->blackNumbers()->size(); + m_blackNumber = m_exam->blackNumbers()->at(idInList); + qDebug() << "[Tpenalty]" << "penalty melody"; + m_exam->blackNumbers()->removeAt(idInList); + if (m_blackNumber != -1) { + m_exam->curQ()->copy(*m_exam->answList()->operator[](m_blackNumber)); // copy black question into last unit + m_exam->curQ()->unsetAnswered(); + m_exam->curQ()->addMelody(m_exam->answList()->operator[](m_blackNumber)->melody(), TQAunit::e_srcOtherUnit, m_blackNumber); + m_exam->curQ()->time = 0; + m_exam->curQ()->setMistake(TQAunit::e_correct); + return true; + } + } + } else { + if (m_exam->blackCount() && m_penalCount > m_penalStep) { + qDebug() << "[Tpenalty]" << "penalty question"; + m_penalCount = 0; + m_blackQuestNr = qrand() % m_exam->blacList()->size(); + m_exam->curQ()->copy(m_exam->blacList()->operator[](m_blackQuestNr)); m_exam->curQ()->unsetAnswered(); - m_exam->curQ()->addMelody(m_exam->answList()->operator[](m_blackNumber)->melody(), TQAunit::e_srcOtherUnit, m_blackNumber); m_exam->curQ()->time = 0; m_exam->curQ()->setMistake(TQAunit::e_correct); return true; } - } - } else { - if (m_exam->blackCount() && m_penalCount > m_penalStep) { -// qDebug("penalty"); - m_penalCount = 0; - m_blackQuestNr = qrand() % m_exam->blacList()->size(); - m_exam->curQ()->copy(m_exam->blacList()->operator[](m_blackQuestNr)); - m_exam->curQ()->unsetAnswered(); - m_exam->curQ()->time = 0; - m_exam->curQ()->setMistake(TQAunit::e_correct); - return true; - } } return false; } @@ -104,10 +104,7 @@ void Tpenalty::checkAnswer() { if (!m_exam->isExercise() && !m_exam->melodies()) { if (!m_exam->curQ()->isCorrect() && !m_exam->isFinished()) { // finished exam hasn't got black list m_exam->blacList()->append(*m_exam->curQ()); - if (m_exam->curQ()->isNotSoBad()) - m_exam->blacList()->last().time = 65501; - else - m_exam->blacList()->last().time = 65502; + m_exam->blacList()->last().time = m_exam->curQ()->isNotSoBad() ? 65501 : 65502; } } if (!m_exam->melodies()) // we don't know is melody question answered here - user will decide... @@ -121,7 +118,7 @@ void Tpenalty::checkAnswer() { releaseBlackList(); RESULTS->progress(); if (!m_exam->curQ()->isCorrect()) - updatePenalStep(); + updatePenalStep(); checkForCert(); } } @@ -136,13 +133,17 @@ void Tpenalty::newAttempt() { void Tpenalty::setMelodyPenalties() { if (m_exam->count() == 0) return; - if (m_exam->curQ()->answered()) { + + if (m_exam->curQ()->answered()) return; // It happens when continued exam starts - last question has been answered already - } + m_exam->curQ()->setAnswered(); if (m_exam->melodies()) { if (!m_exam->curQ()->isCorrect() && !m_exam->isFinished()) { - m_exam->addPenalties(); + m_exam->addPenalties(); + if (m_exam->level()->isMelodySet() && !m_exam->level()->randOrderInSet) + m_penalStep = -1; + else updatePenalStep(); } if (!m_exam->isExercise()) { @@ -176,7 +177,7 @@ void Tpenalty::checkForCert() { if (!m_supply->wasFinished() && m_exam->count() >= (m_supply->obligQuestions() + m_exam->penalty()) ) { // maybe enough if (m_exam->blackCount()) { m_exam->increasePenaltys(m_exam->blackCount()); - qDebug() << "penalties increased. Can't finish this exam yet."; + qDebug() << "[Tpenalty] penalties increased. Can't finish this exam yet."; } else { m_exam->setFinished(); emit certificate(); @@ -188,15 +189,16 @@ void Tpenalty::checkForCert() { void Tpenalty::updatePenalStep() { if (m_supply->wasFinished()) - return; + return; + if ((m_exam->melodies() && m_exam->blackNumbers()->isEmpty()) || (!m_exam->melodies() && m_exam->blacList()->isEmpty())) m_penalStep = 65535; else { - if ((m_supply->obligQuestions() + m_exam->penalty() - m_exam->count()) > 0) - m_penalStep = (m_supply->obligQuestions() + m_exam->penalty() - m_exam->count()) - / (m_exam->melodies() ? m_exam->blackNumbers()->size() : m_exam->blackCount()); - else - m_penalStep = 0; // only penalties questions remained to ask in this exam + if ((m_supply->obligQuestions() + m_exam->penalty() - m_exam->count()) > 0) + m_penalStep = (m_supply->obligQuestions() + m_exam->penalty() - m_exam->count()) + / (m_exam->melodies() ? m_exam->blackNumbers()->size() : m_exam->blackCount()); + else + m_penalStep = 0; // only penalties questions remained to ask in this exam } } diff --git a/src/main/tpenalty.h b/src/main/tpenalty.h index a959cc04de781c3403c6bf2620db0987688d9cd4..fb1398e1212d9ec9f92bfd124a0608578cd95a1b 100644 --- a/src/main/tpenalty.h +++ b/src/main/tpenalty.h @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2014-2017 by Tomasz Bojczuk * + * Copyright (C) 2014-2020 by Tomasz Bojczuk * * seelook@gmail.com * * * * This program is free software; you can redistribute it and/or modify * @@ -58,7 +58,10 @@ class Tpenalty : public QObject public: Tpenalty(Texam* exam, TexecutorSupply* supply); - bool isNot() { return m_blackQuestNr == -1 && m_blackNumber == -1; } /** @p TRUE when a question is not a penalty */ + /** + * @p TRUE when a question is not a penalty + */ + bool isNot() { return m_blackQuestNr == -1 && m_blackNumber == -1; } /** * Check state of counters and if it is time for penalty @@ -68,12 +71,33 @@ public: bool ask(); void updatePenalStep(); - void nextQuestion(); /**< Increases counter of question, resets m_blackQuestNr. Starts timer */ - void checkAnswer(); /**< Checks last answer and when not valid adds penalty(s) to black list. */ - void newAttempt(); /**< Prepares @p Texam to continue answering and updates counters. */ + + /** + * Increases counter of question, resets @p m_blackQuestNr. Starts timer + */ + void nextQuestion(); + + /** + * Checks last answer and when not valid adds penalty(s) to black list. + */ + void checkAnswer(); + + /** + * Prepares @p Texam to continue answering and updates counters. + */ + void newAttempt(); + void setMelodyPenalties(); - void releaseBlackList(); /**< If asked question was penalty and answer was correct it removes penalty from black list. */ - void checkForCert(); /**< Checks could be exam finished and emits @p certificate() when it can. */ + + /** + * If asked question was penalty and answer was correct it removes penalty from black list. + */ + void releaseBlackList(); + + /** + * Checks could be exam finished and emits @p certificate() when it can. + */ + void checkForCert(); /** * Sets @p m_blackQuestNr to the last question from the black list @@ -82,17 +106,53 @@ public: */ void setBlackQuestion(); - // Methods only forwarding functionality of TexamView and TprogressWidget classes - void pauseTime(); /**< Pauses exam view timers. */ - void continueTime(); /**< Continues exam view timers. */ - void updateExamTimes(); /**< Updates exam variables with already elapsed times. */ - void stopTimeView(); /**< Stops refreshing elapsing time on the exam view labels. */ - void startQuestionTime(); /**< Initializes counting time for a new question. */ - void stopQuestionTime(); /**< Stops counting time of the current question and updates counters and labels. */ - quint32 elapsedTime(); /**< Elapsed time of current question. */ + /** + * Pauses exam view timers. + * Forwarded functionality of @p TexamView and @p TprogressWidget classes + */ + void pauseTime(); + + /** + * Continues exam view timers. + * Forwarded functionality of @p TexamView and @p TprogressWidget classes + */ + void continueTime(); + + /** + * Updates exam variables with already elapsed times. + * Forwarded functionality of @p TexamView and @p TprogressWidget classes + */ + void updateExamTimes(); + + /** + * Stops refreshing elapsing time on the exam view labels. + * Forwarded functionality of @p TexamView and @p TprogressWidget classes + */ + void stopTimeView(); + + /** + * Initializes counting time for a new question. + * Forwarded functionality of @p TexamView and @p TprogressWidget classes + */ + void startQuestionTime(); + + /** + * Stops counting time of the current question and updates counters and labels. + * Forwarded functionality of @p TexamView and @p TprogressWidget classes + */ + void stopQuestionTime(); + + /** + * Elapsed time of current question. + * Forwarded functionality of @p TexamView and @p TprogressWidget classes + */ + quint32 elapsedTime(); signals: - void certificate(); /**< Emitted when last mandatory question was correct, so certificate can be displayed. */ + /** + * Emitted when last mandatory question was correct, so certificate can be displayed. + */ + void certificate(); private: Texam *m_exam;