1 /***************************************************************************
5 copyright : (C) 2004 by Sebastian Stein
6 email : seb.kde@hpfsc.de
7 ***************************************************************************/
9 /***************************************************************************
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
16 ***************************************************************************/
18 #include "exerciseconvert.h"
19 #include "exerciseconvert.moc"
21 /* these includes are needed for KDE support */
22 #include <kapplication.h>
24 #include <kmessagebox.h>
25 #include <knumvalidator.h>
27 /* these includes are needed for Qt support */
30 #include <qlineedit.h>
31 #include <qpushbutton.h>
33 #include <qwhatsthis.h>
35 /* standard C++ library includes */
38 #include "rationalwidget.h"
39 #include "resultwidget.h"
41 /* ----- public member functions ----- */
44 ExerciseConvert::ExerciseConvert(QWidget
* parent
, const char * name
):
45 ExerciseBase(parent
, name
)
48 kdDebug() << "constructor ExerciseConvert()" << endl
;
51 /* create a new task */
52 QApplication::setOverrideCursor(waitCursor
); /* show the sand clock */
54 QApplication::restoreOverrideCursor(); /* show the normal cursor */
56 // the next thing to do on a button click would be to check the entered
58 m_currentState
= _CHECK_TASK
;
60 baseWidget
= new QWidget(this, "baseWidget");
61 baseGrid
= new QGridLayout(this, 1, 1, 0, -1, "baseGrid");
62 baseGrid
->addWidget(baseWidget
, 0, 0);
65 realLayout
= new QVBoxLayout(baseWidget
, 5, 5, "realLayout");
67 // add a spacer at the top of the VBox
68 QSpacerItem
* v_spacer
= new QSpacerItem(1, 1);
69 realLayout
->addItem(v_spacer
);
71 // now a line holding the task, input fields and result
72 QHBoxLayout
* taskLineHBoxLayout
= new QHBoxLayout(5, "taskLineHBoxLayout");
73 realLayout
->addLayout(taskLineHBoxLayout
);
75 // first left is the rational widget
76 m_rationalWidget
= new RationalWidget(baseWidget
, "m_rationalWidget", m_number
, m_periodStart
, m_periodLength
);
77 taskLineHBoxLayout
->addWidget(m_rationalWidget
);
79 // now we have the input fields aligned in a VBox
80 QVBoxLayout
* inputLayout
= new QVBoxLayout(5, "inputLayout");
81 taskLineHBoxLayout
->addLayout(inputLayout
);
83 // to validate, that the input is an int
84 KIntValidator
*valnum
= new KIntValidator( this );
86 /* add input box so the user can enter numerator */
87 numer_edit
= new QLineEdit(baseWidget
, "numer_edit");
88 numer_edit
->setValidator( valnum
); // use the int validator
89 QToolTip::add(numer_edit
, i18n("Enter the numerator of your result"));
90 inputLayout
->addWidget(numer_edit
);
92 /* add a line between the edit boxes */
93 edit_line
= new QFrame(baseWidget
, "edit_line");
94 edit_line
->setGeometry(QRect(100, 100, 20, 20));
95 edit_line
->setFrameStyle(QFrame::HLine
| QFrame::Sunken
);
96 inputLayout
->addWidget(edit_line
);
98 /* add input box so the user can enter denominator */
99 deno_edit
= new QLineEdit(baseWidget
, "deno_edit");
100 deno_edit
->setValidator( valnum
); // use the int validator
101 QToolTip::add(deno_edit
, i18n("Enter the denominator of your result"));
102 inputLayout
->addWidget(deno_edit
);
104 // next is the result widget
105 m_resultWidget
= new ResultWidget(baseWidget
, "m_resultWidget", m_result
);
106 taskLineHBoxLayout
->addWidget(m_resultWidget
);
107 m_resultWidget
->hide();
109 // at the right end we have a label just showing CORRECT or WRONG
110 result_label
= new QLabel(baseWidget
, "result_lable");
111 result_label
->setText(i18n("WRONG"));
112 taskLineHBoxLayout
->addWidget(result_label
);
113 result_label
->hide();
115 // add another spacer in the middle of the VBox
116 v_spacer
= new QSpacerItem(1, 1, QSizePolicy::Expanding
, QSizePolicy::Minimum
);
117 taskLineHBoxLayout
->addItem(v_spacer
);
119 // --- that is the end of the horizontal line ---
121 // add another spacer in the middle of the VBox
122 v_spacer
= new QSpacerItem(1, 1);
123 realLayout
->addItem(v_spacer
);
125 // the lower part of the VBox holds just a right aligned button
126 QHBoxLayout
* lowerHBox
= new QHBoxLayout(1, "lowerHBox");
127 realLayout
->addLayout(lowerHBox
);
128 lowerHBox
->addStretch(100);
130 // the right aligned button
131 m_checkButton
= new QPushButton( baseWidget
, "m_checkButton" );
132 m_checkButton
->setText(i18n("&Check Task"));
133 m_checkButton
->setDefault(true); // is the default button of the dialog
134 QToolTip::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."));
135 lowerHBox
->addWidget(m_checkButton
, 1, Qt::AlignRight
);
136 QObject::connect(m_checkButton
, SIGNAL(clicked()), this, SLOT(slotCheckButtonClicked()));
138 // that the user can start typing without moving the focus
139 numer_edit
->setFocus();
141 // show the whole layout
144 // add tooltip and qwhatsthis help to the widget
145 QToolTip::add(this, i18n("In this exercise you have to convert a number into a fraction."));
146 QWhatsThis::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!"));
150 ExerciseConvert::~ExerciseConvert()
153 kdDebug() << "destructor ExerciseConvert()" << endl
;
156 /* no need to delete any child widgets, Qt does it by itself */
159 /** resets the current state, creates a new task and count the last task as
160 * wrong, if it wasn't solved (in _NEXT_TASK state) yet
161 * mainly used after changing the task parameters */
162 void ExerciseConvert::forceNewTask()
165 kdDebug() << "forceNewTask ExerciseConvert()" << endl
;
168 if (m_currentState
== _CHECK_TASK
)
170 // emit the signal for wrong
171 signalExerciseSolvedWrong();
173 m_currentState
= _CHECK_TASK
;
174 m_checkButton
->setText(i18n("&Check Task"));
176 // generate next task
181 /* ------ public slots ------ */
183 void ExerciseConvert::update()
185 // call update of components
186 m_rationalWidget
->updateAndRepaint();
187 m_resultWidget
->updateAndRepaint();
190 ((QWidget
*) this)->update();
194 /* ------ private member functions ------ */
196 void ExerciseConvert::createTask()
198 // the tasks are hardcoded here; there are some algorithms to convert
199 // rational numbers to fractions, but it is not worth the effort here
200 switch(int((double(rand()) / RAND_MAX
) * 18 + 1))
202 case 0 : m_number
= KGlobal::locale()->formatNumber(0.5, 1);
205 m_result
= ratio(1, 2);
207 case 1 : m_number
= KGlobal::locale()->formatNumber(0.3, 1);
210 m_result
= ratio(1, 3);
212 case 2 : m_number
= KGlobal::locale()->formatNumber(0.6, 1);
215 m_result
= ratio(2, 3);
217 case 3 : m_number
= KGlobal::locale()->formatNumber(0.25, 2);
220 m_result
= ratio(1, 4);
222 case 4 : m_number
= KGlobal::locale()->formatNumber(0.75, 2);
225 m_result
= ratio(3, 4);
227 case 5 : m_number
= KGlobal::locale()->formatNumber(0.2, 1);
230 m_result
= ratio(1, 5);
232 case 6 : m_number
= KGlobal::locale()->formatNumber(0.4, 1);
235 m_result
= ratio(2, 5);
237 case 7 : m_number
= KGlobal::locale()->formatNumber(0.6, 1);
240 m_result
= ratio(3, 5);
242 case 8 : m_number
= KGlobal::locale()->formatNumber(0.8, 1);
245 m_result
= ratio(4, 5);
247 case 9 : m_number
= KGlobal::locale()->formatNumber(0.16, 2);
250 m_result
= ratio(1, 6);
252 case 10 : m_number
= KGlobal::locale()->formatNumber(0.142857, 6);
255 m_result
= ratio(1, 7);
257 case 11 : m_number
= KGlobal::locale()->formatNumber(0.125, 3);
260 m_result
= ratio(1, 8);
262 case 12 : m_number
= KGlobal::locale()->formatNumber(0.375, 3);
265 m_result
= ratio(3, 8);
267 case 13 : m_number
= KGlobal::locale()->formatNumber(0.1, 1);
270 m_result
= ratio(1, 9);
272 case 14 : m_number
= KGlobal::locale()->formatNumber(0.1, 1);
275 m_result
= ratio(1, 10);
277 case 15 : m_number
= KGlobal::locale()->formatNumber(0.05, 2);
280 m_result
= ratio(1, 20);
282 case 16 : m_number
= KGlobal::locale()->formatNumber(0.01, 2);
285 m_result
= ratio(1, 100);
287 case 17 : m_number
= KGlobal::locale()->formatNumber(0.83, 2);
290 m_result
= ratio(5, 6);
293 case 18 : m_number
= KGlobal::locale()->formatNumber(0.001, 3);
296 m_result
= ratio(1, 1000);
303 /** - checks, if the user solved the task correctly
304 - emits signals if task was solved correctly or wrong */
305 void ExerciseConvert::showResult()
307 QString tmp_str
; /* to build a string for a label */
310 ratio entered_result
;
312 // change the tooltip of the check button
313 QToolTip::add(m_checkButton
, i18n("Click on this button to get to the next task."));
315 numer_edit
->setEnabled(false);
316 deno_edit
->setEnabled(false);
318 m_resultWidget
->setResult(m_result
);
319 m_resultWidget
->show();
321 // an empty numerator field will be interpreted as 0
322 if (numer_edit
->text().isEmpty() == true)
323 numer_edit
->setText("0");
325 // an empty denominator field will be interpreted as 1
326 if (deno_edit
->text().isEmpty() == true)
327 deno_edit
->setText("1");
329 /* store the entered result to check it, but without reducing */
330 entered_result
.setNumerator(numer_edit
->text().toInt(), false);
331 entered_result
.setDenominator(deno_edit
->text().toInt(), false);
333 // check the entered result; 0/1 == 0/5 -> true,
334 // but 0/1 == 0/0 -> false
335 // a 0 for denominator is never allowed (always counted as wrong)
337 // we have to get the 0 directly from the input field, because
338 // Ratio::setDenominator(0, false) will set the denominator to 1 to ensure
339 // the Ratio is valid
340 if ( (deno_edit
->text().toInt() != 0) && ((entered_result
== m_result
) ||
341 (m_result
.numerator() == 0 && entered_result
.numerator() == 0)) )
343 // emit the signal for correct
344 signalExerciseSolvedCorrect();
346 /* yes, the user entered the correct result */
347 result_label
->setText(i18n("CORRECT"));
348 pal
= result_label
->palette(); /* set green font color */
350 cg
.setColor(QColorGroup::Foreground
, QColor(6, 179, 0));
353 cg
.setColor(QColorGroup::Foreground
, QColor(6, 179, 0));
355 result_label
->setPalette(pal
);
356 result_label
->show(); /* show the result at the end of the task */
358 // emit the signal for wrong
359 signalExerciseSolvedWrong();
361 /* no, the user entered the wrong result */
362 result_label
->setText(i18n("WRONG"));
363 pal
= result_label
->palette(); /* set red font color */
365 cg
.setColor(QColorGroup::Foreground
, QColor(red
));
368 cg
.setColor(QColorGroup::Foreground
, QColor(red
));
370 result_label
->setPalette(pal
);
372 result_label
->show(); /* show the result at the end of the task */
374 // if the user entered a 0 for the denominator (division by 0) we have to
375 // get the 0 directly from the input field, because
376 // Ratio::setDenominator(0, true) will set the denominator to 1 to ensure
377 // the Ratio is valid
378 if (deno_edit
->text().toInt() == 0)
380 KMessageBox::information(this,
381 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."));
383 /* maybe the entered ratio was not reduced */
384 entered_result
.reduce();
385 if (entered_result
== m_result
)
386 KMessageBox::information(this,
387 i18n("You entered the correct result, but not reduced.\nAlways enter your results as reduced. This task will be counted as not correctly solved."));
389 } /* if (entered_result == result) */
394 /** generate the next task and show it to the user */
395 void ExerciseConvert::nextTask()
397 // change the tooltip of the check button
398 QToolTip::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."));
400 numer_edit
->setEnabled(true);
401 deno_edit
->setEnabled(true);
403 result_label
->hide(); /* do not show the result at the end of the task */
404 m_resultWidget
->hide();
406 /* clear user input */
407 deno_edit
->setText("");
408 numer_edit
->setText("");
409 numer_edit
->setFocus();
411 /* create a new task */
412 QApplication::setOverrideCursor(waitCursor
); /* show the sand clock */
414 QApplication::restoreOverrideCursor(); /* show the normal cursor */
416 // update the task widget
417 m_rationalWidget
->setRational(m_number
, m_periodStart
, m_periodLength
);
422 /* ------ private slots ------ */
424 void ExerciseConvert::slotCheckButtonClicked()
426 if (m_currentState
== _CHECK_TASK
)
428 // if nothing has been entered by the user, we don't check the result yet
429 if (numer_edit
->text().isEmpty() == true && deno_edit
->text().isEmpty() ==
432 m_currentState
= _NEXT_TASK
;
433 m_checkButton
->setText(i18n("N&ext Task"));
436 m_currentState
= _CHECK_TASK
;
437 m_checkButton
->setText(i18n("&Check Task"));