File indexing completed on 2022-12-06 18:52:30

0001 /*
0002     SPDX-FileCopyrightText: 2008 Tiago Porangaba <tiago.porangaba@ltia.fc.unesp.br>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #include "ExercisePercentage.h"
0008 
0009 /* these includes are needed for KDE support */
0010 #include <KLocalizedString>
0011 
0012 /* these includes are needed for Qt support */
0013 #include <QApplication>
0014 #include <QGridLayout>
0015 #include <QIntValidator>
0016 #include <QLineEdit>
0017 #include <QPushButton>
0018 #include <QRandomGenerator>
0019 
0020 #ifdef DEBUG
0021 #include <QDebug>
0022 #endif
0023 
0024 /* standard C++ library includes */
0025 #include <cstdlib>
0026 
0027 #include "RationalWidget.h"
0028 #include "ResultWidget.h"
0029 #include "settingsclass.h"
0030 
0031 /* ----- public member functions ----- */
0032 
0033 /* constructor */
0034 ExercisePercentage::ExercisePercentage(QWidget * parent) :
0035     ExerciseBase(parent)
0036 {
0037 #ifdef DEBUG
0038     qDebug() << QStringLiteral("constructor ExercisePercentage()");
0039 #endif
0040 
0041     /* create a new task */
0042     QApplication::setOverrideCursor(Qt::WaitCursor);  /* show the sand clock */
0043     createTask();
0044     QApplication::restoreOverrideCursor(); /* show the normal cursor */
0045 
0046     // to validate, that the input is an int
0047     QIntValidator *valnum = new QIntValidator(this);
0048 
0049     QFont defaultFont = SettingsClass::taskFont();
0050     defaultFont.setBold(true);
0051     defaultFont.setPointSize(10);
0052 
0053     // the next thing to do on a button click would be to check the entered
0054     // result
0055     m_currentState = _CHECK_TASK;
0056 
0057     taskWidget = new QWidget(this);
0058     taskWidget->setObjectName(QStringLiteral("taskWidget"));
0059     checkWidget = new QWidget(this);
0060     checkWidget->setObjectName(QStringLiteral("checkWidget"));
0061 
0062     baseGrid = new QGridLayout(this);
0063     baseGrid->setObjectName(QStringLiteral("baseGrid"));
0064     baseGrid->setColumnStretch(0, 1);
0065 
0066     baseGrid->addWidget(taskWidget, 0, 0);
0067     baseGrid->addWidget(checkWidget, 0, 1);
0068 
0069     taskLayout = new QGridLayout(taskWidget);
0070     taskLayout->setObjectName(QStringLiteral("taskLayout"));
0071     taskLayout->setRowStretch(0, 1);
0072     taskLayout->setRowStretch(4, 1);
0073     taskLayout->setColumnStretch(0, 1);
0074     taskLayout->setColumnStretch(3, 1);
0075 
0076     checkLayout = new QGridLayout(checkWidget);
0077     checkLayout->setObjectName(QStringLiteral("checkLayout"));
0078 
0079     /* Task: percentage question */
0080     defaultFont.setPointSize(16);
0081     m_taskLabel = new QLabel(this);
0082     m_taskLabel->setObjectName(QStringLiteral("m_taskLabel"));
0083     m_taskLabel->setFont(defaultFont);
0084     m_taskLabel->setText(i18nc("%1 percentage of %2", "%1% of %2 = ", m_numberPercentage ,  m_numberPercentageOf));
0085     taskLayout->addWidget(m_taskLabel, 1, 1, 2, 1);
0086 
0087     /* Input question: result of question */
0088     answer_edit = new QLineEdit(taskWidget);
0089     answer_edit->setObjectName(QStringLiteral("answer_edit"));
0090     answer_edit->setValidator(valnum);   // use the int validator
0091     answer_edit->setToolTip(i18n("Enter the result of percentage question"));
0092     answer_edit->setFixedSize(85, 42);
0093     answer_edit->setAlignment(Qt::AlignHCenter);
0094     answer_edit->setFont(defaultFont);
0095     QObject::connect(answer_edit, &QLineEdit::returnPressed, this, &ExercisePercentage::answerReturnPressed);
0096     taskLayout->addWidget(answer_edit, 1, 2, 2, 1);
0097 
0098     // next is the result widget
0099     m_resultWidget = new ResultWidget(checkWidget, m_result);
0100     m_resultWidget->setObjectName(QStringLiteral("m_resultWidget"));
0101     checkLayout->addWidget(m_resultWidget, 0, 0, 1, 2);
0102 
0103     // the right aligned button
0104     defaultFont.setPointSize(10);
0105     m_checkButton = new QPushButton(checkWidget);
0106     m_checkButton->setObjectName(QStringLiteral("m_checkButton"));
0107     m_checkButton->setText(i18n("&Check"));
0108     m_checkButton->setDefault(true);  // is the default button of the dialog
0109     m_checkButton->setToolTip(i18n("Click on this button to check your result. The button will not work if you have not entered a result yet."));
0110     m_checkButton->setFont(defaultFont);
0111     QObject::connect(m_checkButton, &QPushButton::clicked, this, &ExercisePercentage::slotCheckButtonClicked);
0112     checkLayout->addWidget(m_checkButton, 2, 0);
0113 
0114     // the right aligned button
0115     m_skipButton = new QPushButton(checkWidget);
0116     m_skipButton->setObjectName(QStringLiteral("m_skipButton"));
0117     m_skipButton->setText(i18n("&Skip"));
0118     m_skipButton->setToolTip(i18n("Click on this button to skip this question."));
0119     m_skipButton->setFont(defaultFont);
0120     QObject::connect(m_skipButton, &QPushButton::clicked, this, &ExercisePercentage::slotSkipButtonClicked);
0121     checkLayout->addWidget(m_skipButton, 2, 1);
0122 
0123     // that the user can start typing without moving the focus
0124     //numer_edit->setFocus();
0125     answer_edit->setFocus();
0126 
0127     setLayout(baseGrid);
0128     taskWidget->setLayout(taskLayout);
0129     checkWidget->setLayout(checkLayout);
0130 
0131     // add tooltip and qwhatsthis help to the widget
0132     setToolTip(i18n("In this exercise you have to work with percentage questions."));
0133     setWhatsThis(i18n("In this exercise you have to enter the fraction of the given number."));
0134 
0135 }
0136 
0137 /* destructor */
0138 ExercisePercentage::~ExercisePercentage()
0139 {
0140 #ifdef DEBUG
0141     qDebug() << QStringLiteral("destructor ExercisePercentage()");
0142 #endif
0143 
0144     /* no need to delete any child widgets, Qt does it by itself */
0145 }
0146 
0147 /** resets the current state, creates a new task and count the last task as
0148  * wrong, if it wasn't solved (in _NEXT_TASK state) yet
0149  * mainly used after changing the task parameters */
0150 void ExercisePercentage::forceNewTask()
0151 {
0152 #ifdef DEBUG
0153     qDebug() << QStringLiteral("forceNewTask ExercisePercentage()");
0154 #endif
0155 
0156     if (m_currentState == _CHECK_TASK) {
0157         // emit the signal for skipped
0158         Q_EMIT signalExerciseSkipped();
0159     }
0160     m_currentState = _CHECK_TASK;
0161     m_checkButton->setText(i18n("&Check"));
0162 
0163     // generate next task
0164     (void) nextTask();
0165 }
0166 
0167 
0168 /* ------ public slots ------ */
0169 
0170 void ExercisePercentage::update()
0171 {
0172     // call update of components
0173     //m_rationalWidget->updateAndRepaint();
0174     m_resultWidget->updateAndRepaint();
0175 
0176     // update for itself
0177     ((QWidget *) this)->update();
0178 }
0179 
0180 
0181 /* ------ private member functions ------ */
0182 
0183 void ExercisePercentage::createTask()
0184 {
0185     // the tasks are hardcoded here; there are some algorithms to convert
0186     // rational numbers to fractions, but it is not worth the effort here
0187     switch (QRandomGenerator::global()->bounded(19)) {
0188     case  0 :
0189         //m_number = QLocale().toString(0.5, 'f', 1);
0190         m_numberPercentage = QStringLiteral("75");
0191         m_numberPercentageOf = QStringLiteral("1900");
0192         m_resultPercentage = QStringLiteral("1425");
0193         break;
0194     case  1 :
0195         //m_number = QLocale().toString(0.3, 'f', 1);
0196         m_numberPercentage = QStringLiteral("50");
0197         m_numberPercentageOf = QStringLiteral("1800");
0198         m_resultPercentage = QStringLiteral("900");
0199         break;
0200     case  2 :
0201         //m_number = QLocale().toString(0.6, 'f', 1);
0202         m_numberPercentage = QStringLiteral("1");
0203         m_numberPercentageOf = QStringLiteral("1200");
0204         m_resultPercentage = QStringLiteral("12");
0205         break;
0206     case  3 :
0207         //m_number = QLocale().toString(0.25, 'f', 2);
0208         m_numberPercentage = QStringLiteral("10");
0209         m_numberPercentageOf = QStringLiteral("900");
0210         m_resultPercentage = QStringLiteral("90");
0211         break;
0212     case  4 :
0213         //m_number = QLocale().toString(0.75, 'f', 2);
0214         m_numberPercentage = QStringLiteral("100");
0215         m_numberPercentageOf = QStringLiteral("800");
0216         m_resultPercentage = QStringLiteral("800");
0217         break;
0218     case  5 :
0219         //m_number = QLocale().toString(0.2, 'f', 1);
0220         m_numberPercentage = QStringLiteral("75");
0221         m_numberPercentageOf = QStringLiteral("300");
0222         m_resultPercentage = QStringLiteral("225");
0223         break;
0224     case  6 :
0225         //m_number = QLocale().toString(0.4, 'f', 1);
0226         m_numberPercentage = QStringLiteral("10");
0227         m_numberPercentageOf = QStringLiteral("1500");
0228         m_resultPercentage = QStringLiteral("150");
0229         break;
0230     case  7 :
0231         //m_number = QLocale().toString(0.6, 'f', 1);
0232         m_numberPercentage = QStringLiteral("10");
0233         m_numberPercentageOf = QStringLiteral("100");
0234         m_resultPercentage = QStringLiteral("10");
0235         break;
0236     case  8 :
0237         //m_number = QLocale().toString(0.8, 'f', 1);
0238         m_numberPercentage = QStringLiteral("25");
0239         m_numberPercentageOf = QStringLiteral("400");
0240         m_resultPercentage = QStringLiteral("100");
0241         break;
0242     case  9 :
0243         //m_number = QLocale().toString(0.16, 'f', 2);
0244         m_numberPercentage = QStringLiteral("50");
0245         m_numberPercentageOf = QStringLiteral("800");
0246         m_resultPercentage = QStringLiteral("400");
0247         break;
0248     case 10 :
0249         //m_number = QLocale().toString(0.142857, 'f', 6);
0250         m_numberPercentage = QStringLiteral("1");
0251         m_numberPercentageOf = QStringLiteral("400");
0252         m_resultPercentage = QStringLiteral("4");
0253         break;
0254     case 11 :
0255         //m_number = QLocale().toString(0.125, 'f', 3);
0256         m_numberPercentage = QStringLiteral("50");
0257         m_numberPercentageOf = QStringLiteral("600");
0258         m_resultPercentage = QStringLiteral("300");
0259         break;
0260     case 12 :
0261         //m_number = QLocale().toString(0.375, 'f', 3);
0262         m_numberPercentage = QStringLiteral("100");
0263         m_numberPercentageOf = QStringLiteral("1300");
0264         m_resultPercentage = QStringLiteral("1300");
0265         break;
0266     case 13 :
0267         //m_number = QLocale().toString(0.1, 'f', 1);
0268         m_numberPercentage = QStringLiteral("100");
0269         m_numberPercentageOf = QStringLiteral("800");
0270         m_resultPercentage = QStringLiteral("800");
0271         break;
0272     case 14 :
0273         //m_number = QLocale().toString(0.1, 'f', 1);
0274         m_numberPercentage = QStringLiteral("25");
0275         m_numberPercentageOf = QStringLiteral("1400");
0276         m_resultPercentage = QStringLiteral("350");
0277         break;
0278     case 15 :
0279         //m_number = QLocale().toString(0.05, 'f', 2);
0280         m_numberPercentage = QStringLiteral("10");
0281         m_numberPercentageOf = QStringLiteral("1400");
0282         m_resultPercentage = QStringLiteral("140");
0283         break;
0284     case 16 :
0285         //m_number = QLocale().toString(0.01, 'f', 2);
0286         m_numberPercentage = QStringLiteral("1");
0287         m_numberPercentageOf = QStringLiteral("2000");
0288         m_resultPercentage = QStringLiteral("20");
0289         break;
0290     case 17 :
0291         //m_number = QLocale().toString(0.83, 'f', 2);
0292         m_numberPercentage = QStringLiteral("75");
0293         m_numberPercentageOf = QStringLiteral("1000");
0294         m_resultPercentage = QStringLiteral("750");
0295         break;
0296     default :
0297     case 18 :
0298         //m_number = QLocale().toString(0.001, 'f', 3);
0299         m_numberPercentage = QStringLiteral("75");
0300         m_numberPercentageOf = QStringLiteral("1100");
0301         m_resultPercentage = QStringLiteral("825");
0302         break;
0303     }
0304 
0305     return;
0306 }
0307 
0308 /** - checks, if the user solved the task correctly
0309         - emits signals if task was solved correctly or wrong */
0310 void ExercisePercentage::showResult()
0311 {
0312     int tmp_result;
0313     Ratio entered_result;
0314     Ratio correct_result;
0315 
0316     // change the tooltip of the check button
0317     m_checkButton->setToolTip(i18n("Click on this button to get to the next question."));
0318 
0319     answer_edit->setEnabled(false);
0320     m_skipButton->setEnabled(false);
0321 
0322     //an empty answer field will be interpreted as 0
0323     if (answer_edit->text().isEmpty() == true)
0324         answer_edit->setText(QStringLiteral("0"));
0325 
0326 
0327     tmp_result = answer_edit->text().toInt();
0328     entered_result.setNumerator(tmp_result, false);
0329     entered_result.setDenominator(1, false);
0330     correct_result.setNumerator(m_resultPercentage.toInt());
0331     correct_result.setDenominator(1, false);
0332     if (tmp_result == m_resultPercentage.toInt()) {
0333         // emit the signal for correct
0334         Q_EMIT signalExerciseSolvedCorrect();
0335         /* yes, the user entered the correct result */
0336         m_resultWidget->setResult(entered_result, 1);
0337     } else {
0338         // emit the signal for incorrect
0339         Q_EMIT signalExerciseSolvedWrong();
0340         /* no, the user entered the wrong result */
0341         m_resultWidget->setResult(correct_result, 0);
0342     }
0343 
0344     return;
0345 }
0346 
0347 /** generate the next task and show it to the user */
0348 void ExercisePercentage::nextTask()
0349 {
0350     // change the tooltip of the check button
0351     m_checkButton->setToolTip(i18n("Click on this button to check your result. The button will not work if you have not entered a result yet."));
0352 
0353     answer_edit->setEnabled(true);
0354     m_skipButton->setEnabled(true);
0355 
0356     m_resultWidget->setResult(m_result, -1);
0357 
0358     /* clear user input */
0359     answer_edit->clear();
0360     answer_edit->setFocus();
0361 
0362     /* create a new task */
0363     QApplication::setOverrideCursor(Qt::WaitCursor);  /* show the sand clock */
0364     createTask();
0365     QApplication::restoreOverrideCursor(); /* show the normal cursor */
0366 
0367     // update the task widget
0368     QString tempTask = i18nc("%1 percentage of %2", "%1% of %2 = ", m_numberPercentage, m_numberPercentageOf);
0369     m_taskLabel->setText(tempTask);
0370 
0371     return;
0372 }
0373 
0374 /* ------ private slots ------ */
0375 
0376 void ExercisePercentage::slotCheckButtonClicked()
0377 {
0378     if (m_currentState == _CHECK_TASK) {
0379         // if nothing has been entered by the user, we don't check the result yet
0380         if (answer_edit->text().isEmpty() == true)
0381             return;
0382         m_currentState = _NEXT_TASK;
0383         m_checkButton->setText(i18n("N&ext"));
0384         (void) showResult();
0385     } else {
0386         m_currentState = _CHECK_TASK;
0387         m_checkButton->setText(i18n("&Check"));
0388         (void) nextTask();
0389     }
0390 
0391     return;
0392 }
0393 
0394 void ExercisePercentage::slotSkipButtonClicked()
0395 {
0396     forceNewTask();
0397 }
0398 
0399 void ExercisePercentage::answerReturnPressed()
0400 {
0401     slotCheckButtonClicked();
0402 }