You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
468 lines
15 KiB
468 lines
15 KiB
/***************************************************************************
|
|
exerciseconvert.h
|
|
-------------------
|
|
begin : 2004/06/04
|
|
copyright : (C) 2004 by Sebastian Stein
|
|
email : seb.kde@hpfsc.de
|
|
***************************************************************************/
|
|
|
|
/***************************************************************************
|
|
* *
|
|
* This program is free software; you can redistribute it and/or modify *
|
|
* it under the terms of the GNU General Public License as published by *
|
|
* the Free Software Foundation; either version 2 of the License, or *
|
|
* (at your option) any later version. *
|
|
* *
|
|
***************************************************************************/
|
|
|
|
#include "exerciseconvert.h"
|
|
#include "exerciseconvert.moc"
|
|
|
|
/* these includes are needed for KDE support */
|
|
#include <kapplication.h>
|
|
#include <klocale.h>
|
|
#include <kmessagebox.h>
|
|
#include <knumvalidator.h>
|
|
|
|
/* these includes are needed for TQt support */
|
|
#include <tqlabel.h>
|
|
#include <tqlayout.h>
|
|
#include <tqlineedit.h>
|
|
#include <tqpushbutton.h>
|
|
#include <tqtooltip.h>
|
|
#include <tqwhatsthis.h>
|
|
|
|
/* standard C++ library includes */
|
|
#include <stdlib.h>
|
|
|
|
#include "rationalwidget.h"
|
|
#include "resultwidget.h"
|
|
|
|
/* ----- public member functions ----- */
|
|
|
|
/* constructor */
|
|
ExerciseConvert::ExerciseConvert(TQWidget * parent, const char * name):
|
|
ExerciseBase(parent, name)
|
|
{
|
|
#ifdef DEBUG
|
|
kdDebug() << "constructor ExerciseConvert()" << endl;
|
|
#endif
|
|
|
|
/* create a new task */
|
|
TQApplication::setOverrideCursor(waitCursor); /* show the sand clock */
|
|
createTask();
|
|
TQApplication::restoreOverrideCursor(); /* show the normal cursor */
|
|
|
|
// the next thing to do on a button click would be to check the entered
|
|
// result
|
|
m_currentState = _CHECK_TASK;
|
|
|
|
baseWidget = new TQWidget(this, "baseWidget");
|
|
baseGrid = new TQGridLayout(this, 1, 1, 0, -1, "baseGrid");
|
|
baseGrid->addWidget(baseWidget, 0, 0);
|
|
|
|
// this is a VBox
|
|
realLayout = new TQVBoxLayout(baseWidget, 5, 5, "realLayout");
|
|
|
|
// add a spacer at the top of the VBox
|
|
TQSpacerItem * v_spacer = new TQSpacerItem(1, 1);
|
|
realLayout->addItem(v_spacer);
|
|
|
|
// now a line holding the task, input fields and result
|
|
TQHBoxLayout * taskLineHBoxLayout = new TQHBoxLayout(5, "taskLineHBoxLayout");
|
|
realLayout->addLayout(taskLineHBoxLayout);
|
|
|
|
// first left is the rational widget
|
|
m_rationalWidget = new RationalWidget(baseWidget, "m_rationalWidget", m_number, m_periodStart, m_periodLength);
|
|
// taskLineHBoxLayout->addWidget(m_rationalWidget);
|
|
|
|
// now we have the input fields aligned in a VBox
|
|
TQVBoxLayout * inputLayout = new TQVBoxLayout(5, "inputLayout");
|
|
// taskLineHBoxLayout->addLayout(inputLayout);
|
|
|
|
// to validate, that the input is an int
|
|
KIntValidator *valnum = new KIntValidator( this );
|
|
|
|
/* add input box so the user can enter numerator */
|
|
numer_edit = new TQLineEdit(baseWidget, "numer_edit");
|
|
numer_edit->setValidator( valnum ); // use the int validator
|
|
TQToolTip::add(numer_edit, i18n("Enter the numerator of your result"));
|
|
inputLayout->addWidget(numer_edit);
|
|
|
|
/* add a line between the edit boxes */
|
|
edit_line = new TQFrame(baseWidget, "edit_line");
|
|
edit_line->setGeometry(TQRect(100, 100, 20, 20));
|
|
edit_line->setFrameStyle(TQFrame::HLine | TQFrame::Sunken);
|
|
inputLayout->addWidget(edit_line);
|
|
|
|
/* add input box so the user can enter denominator */
|
|
deno_edit = new TQLineEdit(baseWidget, "deno_edit");
|
|
deno_edit->setValidator( valnum ); // use the int validator
|
|
TQToolTip::add(deno_edit, i18n("Enter the denominator of your result"));
|
|
inputLayout->addWidget(deno_edit);
|
|
|
|
// next is the result widget
|
|
m_resultWidget = new ResultWidget(baseWidget, "m_resultWidget", m_result);
|
|
// taskLineHBoxLayout->addWidget(m_resultWidget);
|
|
m_resultWidget->hide();
|
|
|
|
// at the right end we have a label just showing CORRECT or WRONG
|
|
result_label = new TQLabel(baseWidget, "result_lable");
|
|
result_label->setText(i18n("WRONG"));
|
|
// taskLineHBoxLayout->addWidget(result_label);
|
|
result_label->hide();
|
|
|
|
// add another spacer in the middle of the VBox
|
|
v_spacer = new TQSpacerItem(1, 1, TQSizePolicy::Expanding, TQSizePolicy::Minimum);
|
|
// taskLineHBoxLayout->addItem(v_spacer);
|
|
|
|
// --- that is the end of the horizontal line ---
|
|
|
|
// in RTL desktops, we still need to allign the
|
|
// execise to the left. On TQt4, you can set the direction
|
|
// of the layout to LTR (instead of inherit), but on TQt3
|
|
// the only way of fixing it is inserting the widgets in reversed
|
|
// order to the layout.
|
|
//
|
|
// if you need help with this feel free to contact me - Diego <elcuco@kde.org> )
|
|
// This should fix parts of bug #116831
|
|
if (TQApplication::reverseLayout())
|
|
{
|
|
taskLineHBoxLayout->addItem(v_spacer);
|
|
taskLineHBoxLayout->addWidget(result_label);
|
|
taskLineHBoxLayout->addWidget(m_resultWidget);
|
|
taskLineHBoxLayout->addLayout(inputLayout);
|
|
taskLineHBoxLayout->addWidget(m_rationalWidget);
|
|
}
|
|
else
|
|
{
|
|
taskLineHBoxLayout->addWidget(m_rationalWidget);
|
|
taskLineHBoxLayout->addLayout(inputLayout);
|
|
taskLineHBoxLayout->addWidget(m_resultWidget);
|
|
taskLineHBoxLayout->addWidget(result_label);
|
|
taskLineHBoxLayout->addItem(v_spacer);
|
|
}
|
|
|
|
// add another spacer in the middle of the VBox
|
|
v_spacer = new TQSpacerItem(1, 1);
|
|
realLayout->addItem(v_spacer);
|
|
|
|
// the lower part of the VBox holds just a right aligned button
|
|
TQHBoxLayout * lowerHBox = new TQHBoxLayout(1, "lowerHBox");
|
|
realLayout->addLayout(lowerHBox);
|
|
lowerHBox->addStretch(100);
|
|
|
|
// the right aligned button
|
|
m_checkButton = new TQPushButton( baseWidget, "m_checkButton" );
|
|
m_checkButton->setText(i18n("&Check Task"));
|
|
m_checkButton->setDefault(true); // is the default button of the dialog
|
|
TQToolTip::add(m_checkButton, i18n("Click on this button to check your result. The button will not work if you have not entered a result yet."));
|
|
lowerHBox->addWidget(m_checkButton, 1, TQt::AlignRight);
|
|
TQObject::connect(m_checkButton, TQT_SIGNAL(clicked()), this, TQT_SLOT(slotCheckButtonClicked()));
|
|
|
|
// that the user can start typing without moving the focus
|
|
numer_edit->setFocus();
|
|
|
|
// show the whole layout
|
|
baseWidget->show();
|
|
|
|
// add tooltip and qwhatsthis help to the widget
|
|
TQToolTip::add(this, i18n("In this exercise you have to convert a number into a fraction."));
|
|
TQWhatsThis::add(this, i18n("In this exercise you have to convert a given number into a fraction by entering numerator and denominator. Do not forget to reduce the result!"));
|
|
}
|
|
|
|
/* destructor */
|
|
ExerciseConvert::~ExerciseConvert()
|
|
{
|
|
#ifdef DEBUG
|
|
kdDebug() << "destructor ExerciseConvert()" << endl;
|
|
#endif
|
|
|
|
/* no need to delete any child widgets, TQt does it by itself */
|
|
}
|
|
|
|
/** resets the current state, creates a new task and count the last task as
|
|
* wrong, if it wasn't solved (in _NEXT_TASK state) yet
|
|
* mainly used after changing the task parameters */
|
|
void ExerciseConvert::forceNewTask()
|
|
{
|
|
#ifdef DEBUG
|
|
kdDebug() << "forceNewTask ExerciseConvert()" << endl;
|
|
#endif
|
|
|
|
if (m_currentState == _CHECK_TASK)
|
|
{
|
|
// emit the signal for wrong
|
|
signalExerciseSolvedWrong();
|
|
}
|
|
m_currentState = _CHECK_TASK;
|
|
m_checkButton->setText(i18n("&Check Task"));
|
|
|
|
// generate next task
|
|
(void) nextTask();
|
|
}
|
|
|
|
|
|
/* ------ public slots ------ */
|
|
|
|
void ExerciseConvert::update()
|
|
{
|
|
// call update of components
|
|
m_rationalWidget->updateAndRepaint();
|
|
m_resultWidget->updateAndRepaint();
|
|
|
|
// update for itself
|
|
((TQWidget *) this)->update();
|
|
}
|
|
|
|
|
|
/* ------ private member functions ------ */
|
|
|
|
void ExerciseConvert::createTask()
|
|
{
|
|
// the tasks are hardcoded here; there are some algorithms to convert
|
|
// rational numbers to fractions, but it is not worth the effort here
|
|
switch(int((double(rand()) / RAND_MAX) * 18 + 1))
|
|
{
|
|
case 0 : m_number = KGlobal::locale()->formatNumber(0.5, 1);
|
|
m_periodStart = 2;
|
|
m_periodLength = 0;
|
|
m_result = ratio(1, 2);
|
|
break;
|
|
case 1 : m_number = KGlobal::locale()->formatNumber(0.3, 1);
|
|
m_periodStart = 2;
|
|
m_periodLength = 1;
|
|
m_result = ratio(1, 3);
|
|
break;
|
|
case 2 : m_number = KGlobal::locale()->formatNumber(0.6, 1);
|
|
m_periodStart = 2;
|
|
m_periodLength = 1;
|
|
m_result = ratio(2, 3);
|
|
break;
|
|
case 3 : m_number = KGlobal::locale()->formatNumber(0.25, 2);
|
|
m_periodStart = 2;
|
|
m_periodLength = 0;
|
|
m_result = ratio(1, 4);
|
|
break;
|
|
case 4 : m_number = KGlobal::locale()->formatNumber(0.75, 2);
|
|
m_periodStart = 2;
|
|
m_periodLength = 0;
|
|
m_result = ratio(3, 4);
|
|
break;
|
|
case 5 : m_number = KGlobal::locale()->formatNumber(0.2, 1);
|
|
m_periodStart = 2;
|
|
m_periodLength = 0;
|
|
m_result = ratio(1, 5);
|
|
break;
|
|
case 6 : m_number = KGlobal::locale()->formatNumber(0.4, 1);
|
|
m_periodStart = 2;
|
|
m_periodLength = 0;
|
|
m_result = ratio(2, 5);
|
|
break;
|
|
case 7 : m_number = KGlobal::locale()->formatNumber(0.6, 1);
|
|
m_periodStart = 2;
|
|
m_periodLength = 0;
|
|
m_result = ratio(3, 5);
|
|
break;
|
|
case 8 : m_number = KGlobal::locale()->formatNumber(0.8, 1);
|
|
m_periodStart = 2;
|
|
m_periodLength = 0;
|
|
m_result = ratio(4, 5);
|
|
break;
|
|
case 9 : m_number = KGlobal::locale()->formatNumber(0.16, 2);
|
|
m_periodStart = 3;
|
|
m_periodLength = 1;
|
|
m_result = ratio(1, 6);
|
|
break;
|
|
case 10 : m_number = KGlobal::locale()->formatNumber(0.142857, 6);
|
|
m_periodStart = 2;
|
|
m_periodLength = 6;
|
|
m_result = ratio(1, 7);
|
|
break;
|
|
case 11 : m_number = KGlobal::locale()->formatNumber(0.125, 3);
|
|
m_periodStart = 2;
|
|
m_periodLength = 0;
|
|
m_result = ratio(1, 8);
|
|
break;
|
|
case 12 : m_number = KGlobal::locale()->formatNumber(0.375, 3);
|
|
m_periodStart = 2;
|
|
m_periodLength = 0;
|
|
m_result = ratio(3, 8);
|
|
break;
|
|
case 13 : m_number = KGlobal::locale()->formatNumber(0.1, 1);
|
|
m_periodStart = 2;
|
|
m_periodLength = 1;
|
|
m_result = ratio(1, 9);
|
|
break;
|
|
case 14 : m_number = KGlobal::locale()->formatNumber(0.1, 1);
|
|
m_periodStart = 2;
|
|
m_periodLength = 0;
|
|
m_result = ratio(1, 10);
|
|
break;
|
|
case 15 : m_number = KGlobal::locale()->formatNumber(0.05, 2);
|
|
m_periodStart = 2;
|
|
m_periodLength = 0;
|
|
m_result = ratio(1, 20);
|
|
break;
|
|
case 16 : m_number = KGlobal::locale()->formatNumber(0.01, 2);
|
|
m_periodStart = 2;
|
|
m_periodLength = 0;
|
|
m_result = ratio(1, 100);
|
|
break;
|
|
case 17 : m_number = KGlobal::locale()->formatNumber(0.83, 2);
|
|
m_periodStart = 3;
|
|
m_periodLength = 1;
|
|
m_result = ratio(5, 6);
|
|
break;
|
|
default :
|
|
case 18 : m_number = KGlobal::locale()->formatNumber(0.001, 3);
|
|
m_periodStart = 2;
|
|
m_periodLength = 0;
|
|
m_result = ratio(1, 1000);
|
|
break;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
/** - checks, if the user solved the task correctly
|
|
- emits signals if task was solved correctly or wrong */
|
|
void ExerciseConvert::showResult()
|
|
{
|
|
TQString tmp_str; /* to build a string for a label */
|
|
TQPalette pal;
|
|
TQColorGroup cg;
|
|
ratio entered_result;
|
|
|
|
// change the tooltip of the check button
|
|
TQToolTip::add(m_checkButton, i18n("Click on this button to get to the next task."));
|
|
|
|
numer_edit->setEnabled(false);
|
|
deno_edit->setEnabled(false);
|
|
|
|
m_resultWidget->setResult(m_result);
|
|
m_resultWidget->show();
|
|
|
|
// an empty numerator field will be interpreted as 0
|
|
if (numer_edit->text().isEmpty() == true)
|
|
numer_edit->setText("0");
|
|
|
|
// an empty denominator field will be interpreted as 1
|
|
if (deno_edit->text().isEmpty() == true)
|
|
deno_edit->setText("1");
|
|
|
|
/* store the entered result to check it, but without reducing */
|
|
entered_result.setNumerator(numer_edit->text().toInt(), false);
|
|
entered_result.setDenominator(deno_edit->text().toInt(), false);
|
|
|
|
// check the entered result; 0/1 == 0/5 -> true,
|
|
// but 0/1 == 0/0 -> false
|
|
// a 0 for denominator is never allowed (always counted as wrong)
|
|
//
|
|
// we have to get the 0 directly from the input field, because
|
|
// Ratio::setDenominator(0, false) will set the denominator to 1 to ensure
|
|
// the Ratio is valid
|
|
if ( (deno_edit->text().toInt() != 0) && ((entered_result == m_result) ||
|
|
(m_result.numerator() == 0 && entered_result.numerator() == 0)) )
|
|
{
|
|
// emit the signal for correct
|
|
signalExerciseSolvedCorrect();
|
|
|
|
/* yes, the user entered the correct result */
|
|
result_label->setText(i18n("CORRECT"));
|
|
pal = result_label->palette(); /* set green font color */
|
|
cg = pal.active();
|
|
cg.setColor(TQColorGroup::Foreground, TQColor(6, 179, 0));
|
|
pal.setActive(cg);
|
|
cg = pal.inactive();
|
|
cg.setColor(TQColorGroup::Foreground, TQColor(6, 179, 0));
|
|
pal.setInactive(cg);
|
|
result_label->setPalette(pal);
|
|
result_label->show(); /* show the result at the end of the task */
|
|
} else {
|
|
// emit the signal for wrong
|
|
signalExerciseSolvedWrong();
|
|
|
|
/* no, the user entered the wrong result */
|
|
result_label->setText(i18n("WRONG"));
|
|
pal = result_label->palette(); /* set red font color */
|
|
cg = pal.active();
|
|
cg.setColor(TQColorGroup::Foreground, TQColor(red));
|
|
pal.setActive(cg);
|
|
cg = pal.inactive();
|
|
cg.setColor(TQColorGroup::Foreground, TQColor(red));
|
|
pal.setInactive(cg);
|
|
result_label->setPalette(pal);
|
|
|
|
result_label->show(); /* show the result at the end of the task */
|
|
|
|
// if the user entered a 0 for the denominator (division by 0) we have to
|
|
// get the 0 directly from the input field, because
|
|
// Ratio::setDenominator(0, true) will set the denominator to 1 to ensure
|
|
// the Ratio is valid
|
|
if (deno_edit->text().toInt() == 0)
|
|
{
|
|
KMessageBox::information(this,
|
|
i18n("You entered a 0 as the denominator. This means division by zero, which is not allowed. This task will be counted as not correctly solved."));
|
|
} else {
|
|
/* maybe the entered ratio was not reduced */
|
|
entered_result.reduce();
|
|
if (entered_result == m_result)
|
|
KMessageBox::information(this,
|
|
i18n("You entered the correct result, but not reduced.\nAlways enter your results as reduced. This task will be counted as not correctly solved."));
|
|
}
|
|
} /* if (entered_result == result) */
|
|
|
|
return;
|
|
}
|
|
|
|
/** generate the next task and show it to the user */
|
|
void ExerciseConvert::nextTask()
|
|
{
|
|
// change the tooltip of the check button
|
|
TQToolTip::add(m_checkButton, i18n("Click on this button to check your result. The button will not work if you have not entered a result yet."));
|
|
|
|
numer_edit->setEnabled(true);
|
|
deno_edit->setEnabled(true);
|
|
|
|
result_label->hide(); /* do not show the result at the end of the task */
|
|
m_resultWidget->hide();
|
|
|
|
/* clear user input */
|
|
deno_edit->setText("");
|
|
numer_edit->setText("");
|
|
numer_edit->setFocus();
|
|
|
|
/* create a new task */
|
|
TQApplication::setOverrideCursor(waitCursor); /* show the sand clock */
|
|
createTask();
|
|
TQApplication::restoreOverrideCursor(); /* show the normal cursor */
|
|
|
|
// update the task widget
|
|
m_rationalWidget->setRational(m_number, m_periodStart, m_periodLength);
|
|
|
|
return;
|
|
}
|
|
|
|
/* ------ private slots ------ */
|
|
|
|
void ExerciseConvert::slotCheckButtonClicked()
|
|
{
|
|
if (m_currentState == _CHECK_TASK)
|
|
{
|
|
// if nothing has been entered by the user, we don't check the result yet
|
|
if (numer_edit->text().isEmpty() == true && deno_edit->text().isEmpty() ==
|
|
true)
|
|
return;
|
|
m_currentState = _NEXT_TASK;
|
|
m_checkButton->setText(i18n("N&ext Task"));
|
|
(void) showResult();
|
|
} else {
|
|
m_currentState = _CHECK_TASK;
|
|
m_checkButton->setText(i18n("&Check Task"));
|
|
(void) nextTask();
|
|
}
|
|
|
|
return;
|
|
}
|