#include "testingWidget.h" TestingWidget::TestingWidget(QWidget *pWidget) : QWidget(pWidget), m_currentComplexityName("everything"), m_currentTopicName("everything"), m_file("./QuestionsXML/questions.xml") { setupUi(dynamic_cast(this)); connect(m_pbConfirm, &QPushButton::clicked, this, &TestingWidget::slotClickedConfirm); connect(m_pbStart, &QPushButton::clicked, this, &TestingWidget::slotClickedStart); connect(m_pbStop, &QPushButton::clicked, this, &TestingWidget::slotResetTesting); connect(m_rbAllDifficulties, &QRadioButton::clicked, this, &TestingWidget::slotSwitchedComplexity); connect(m_rbEasy, &QRadioButton::clicked, this, &TestingWidget::slotSwitchedComplexity); connect(m_rbMedium, &QRadioButton::clicked, this, &TestingWidget::slotSwitchedComplexity); connect(m_rbHard, &QRadioButton::clicked, this, &TestingWidget::slotSwitchedComplexity); connect(m_rbAllTopics, &QRadioButton::clicked, this, &TestingWidget::slotSwitchedTopics); connect(m_rbDiscreteMathematics, &QRadioButton::clicked, this, &TestingWidget::slotSwitchedTopics); connect(m_rbHashFunction, &QRadioButton::clicked, this, &TestingWidget::slotSwitchedTopics); connect(m_rbHashTable, &QRadioButton::clicked, this, &TestingWidget::slotSwitchedTopics); connect(m_rbAlgorithm, &QRadioButton::clicked, this, &TestingWidget::slotSwitchedTopics); m_frmConfirm->hide(); } inline void TestingWidget::hideCheckBoxes() { QCheckBox *currentCheckBox; for (unsigned i = 0; i < 9; ++i) { currentCheckBox = findChild(QString("m_cbIndex%1").arg(i)); currentCheckBox->hide(); } } inline void TestingWidget::showCheckBoxes() { QCheckBox *currentCheckBox; for (unsigned i = 0, size = m_answers.size(); i < size; ++i) { currentCheckBox = findChild(QString("m_cbIndex%1").arg(i)); currentCheckBox->show(); currentCheckBox->setText(m_answers[i].first); } } inline QString TestingWidget::getHTMLQuestion(QDomElement element) { QString currentQuestion; element = element.firstChildElement(); do { switch (getTagsEnumFromQString(element.tagName())) { case TagXML::Caption: { currentQuestion.append(QString("

%1

").arg(element.text())); } break; case TagXML::Text: { currentQuestion.append(QString(R"(

%2

)") .arg(element.text())); } break; case TagXML::Answer: { m_answers.append(std::make_pair( element.text(), element.hasAttribute("type") ? (element.attribute("type") == "correct") : false)); } break; case TagXML::Question: { throw std::invalid_argument( "the question cannot be nested within the question"); } break; case TagXML::Undefined: { throw std::invalid_argument("tag undefined"); } break; } element = element.nextSiblingElement(); } while (not element.isNull()); return currentQuestion; } inline void TestingWidget::configureInput(const QString &value) { hideCheckBoxes(); resetInput(); if (value == "choice") { m_swInputData->setCurrentIndex(0); unsigned seed = std::chrono::system_clock::now().time_since_epoch().count(); std::shuffle(m_answers.begin(), m_answers.end(), std::default_random_engine(seed)); showCheckBoxes(); } else if (value == "integer") { m_swInputData->setCurrentIndex(1); } else if (value == "floatingPoint") { m_swInputData->setCurrentIndex(2); } else { throw std::invalid_argument("the type of the input option is undefined"); } } inline bool TestingWidget::showNextQuestion() { bool continueFlag = true; auto checkType = [](const QString &value) -> bool { return bool{value == "choice" || value == "integer" || value == "floatingPoint"}; }; while (not m_currentQuestion.isNull() && continueFlag) { m_currentTypeName = m_currentQuestion.attribute("type"); if ((m_currentTopicName == "everything" || m_currentQuestion.attribute("category") .split('|') .contains(m_currentTopicName)) && (m_currentComplexityName == "everything" || m_currentComplexityName == m_currentQuestion.attribute("complexity")) && checkType(m_currentTypeName)) { m_answers.clear(); m_testingTextBrowser->setHtml(getHTMLQuestion(m_currentQuestion)); configureInput(m_currentTypeName); continueFlag = false; } m_currentQuestion = m_currentQuestion.nextSiblingElement("question"); } return (not continueFlag); } inline void TestingWidget::setEnabledGUIStartTesting(bool flag) { m_gbTopics->setEnabled(flag); m_gbDifficulty->setEnabled(flag); m_pbStart->setEnabled(flag); m_pbStop->setDisabled(flag); m_frmConfirm->setVisible(not flag); } inline TestingWidget::TagXML TestingWidget::getTagsEnumFromQString(const QString &value) { TagXML result = {value == "question" ? TagXML::Question : value == "caption" ? TagXML::Caption : value == "text" ? TagXML::Text : value == "answer" ? TagXML::Answer : TagXML::Undefined}; return result; } /* * Slots */ inline void TestingWidget::slotSwitchedTopics() { QString result = {m_rbAllTopics->isChecked() ? QString("everything") : m_rbDiscreteMathematics->isChecked() ? QString("discreteMathematics") : m_rbHashFunction->isChecked() ? QString("hashFunction") : m_rbHashTable->isChecked() ? QString("hashTable") : m_rbAlgorithm->isChecked() ? QString("algorithm") : QString()}; if (result.isNull()) { throw std::invalid_argument("topic undefined"); } m_currentTopicName = result; } inline void TestingWidget::slotSwitchedComplexity() { QString result = {m_rbAllDifficulties->isChecked() ? QString("everything") : m_rbEasy->isChecked() ? QString("easy") : m_rbMedium->isChecked() ? QString("medium") : m_rbHard->isChecked() ? QString("hard") : QString()}; if (result.isNull()) { throw std::invalid_argument("complexity undefined"); } m_currentComplexityName = result; } inline bool TestingWidget::checkAnswer(const QString &value) { if (m_answers.size() <= 0) { return false; } bool result = true; if (value == "choice") { QCheckBox *currentCheckBox; for (unsigned i = 0, size = m_answers.size(); i < size; ++i) { currentCheckBox = findChild(QString("m_cbIndex%1").arg(i)); if (m_answers[i].second) { result &= currentCheckBox->isChecked(); } else { result &= not currentCheckBox->isChecked(); } } } else if (value == "integer" || value == "floatingPoint") { QString answer = {value == "integer" ? m_sbInteger->text() : m_sbDouble->text()}; auto iter = std::find_if(m_answers.begin(), m_answers.end(), [answer](const std::pair &value) -> bool { return (value.second == true && value.first == answer); }); return (iter not_eq m_answers.end()); } else { throw std::invalid_argument("input not defined"); } return result; } inline void TestingWidget::slotClickedConfirm() { bool result = checkAnswer(m_currentTypeName); emit signalReplyGiven(result); if (not showNextQuestion()) { setEnabledGUIStartTesting(true); slotResetTesting(); } } inline void TestingWidget::slotClickedStart() { bool isOpened = m_file.open(QIODevice::ReadOnly); emit signalFileOpened(isOpened); if (isOpened) { bool isSet = m_document.setContent(&m_file); m_file.close(); emit signalContentIsSet(isSet); if (isSet) { QDomNode questions = m_document.firstChild().nextSiblingElement("questions"); if (questions.isNull()) { return; } QDomNode firstQuestion = questions.firstChild().nextSiblingElement("question"); if (firstQuestion.isNull()) { return; } m_currentQuestion = firstQuestion.toElement(); if (showNextQuestion()) { setEnabledGUIStartTesting(false); emit signalStartOfTesting(); } } } return; } inline void TestingWidget::resetInput() { QCheckBox *currentCheckBox; for (unsigned i = 0; i < 9; ++i) { currentCheckBox = findChild(QString("m_cbIndex%1").arg(i)); currentCheckBox->setChecked(false); } m_sbInteger->clear(); m_sbDouble->clear(); } inline void TestingWidget::slotResetTesting() { m_testingTextBrowser->clear(); setEnabledGUIStartTesting(true); resetInput(); emit signalEndOfTesting(); }