moved kdeaccessibility kdeaddons kdeadmin kdeartwork kdebindings kdeedu kdegames...
[kdeedu.git] / kbruch / src / taskview.cpp
blob9c08dc699d9d202a8774916cbf618d0367db65cd
1 /***************************************************************************
2 taskview.cpp - The task window
3 -------------------
4 begin : Tue Feb 08 13:41:00 CET 2002
5 copyright : (C) 2001 - 2004 by Sebastian Stein
6 email : seb.kde@hpfsc.de
7 ***************************************************************************/
9 /***************************************************************************
10 * *
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. *
15 * *
16 ***************************************************************************/
18 #include "taskview.h"
19 #include "taskview.moc"
21 /* these includes are needed for KDE support */
22 #include <klocale.h>
23 #include <kmessagebox.h>
24 #include <kapplication.h>
25 #include <knumvalidator.h>
27 /* these includes are needed for Qt support */
28 #include <qlabel.h>
29 #include <qlayout.h>
30 #include <qlineedit.h>
31 #include <qpushbutton.h>
32 #include <qtooltip.h>
33 #include <qwhatsthis.h>
35 /* standard C++ library includes */
36 #include <math.h>
38 /* ----- public member functions ----- */
40 /* constructor */
41 TaskView::TaskView(QWidget * parent, const char * name, bool padd_sub,
42 bool pmul_div, unsigned int pnr_ratios, unsigned int pmax_md):
43 ExerciseBase(parent, name), add_sub(padd_sub), mul_div(pmul_div),
44 nr_ratios(pnr_ratios), max_md(pmax_md)
46 #ifdef DEBUG
47 kdDebug() << "constructor TaskView()" << endl;
48 #endif
50 curr_nr_ratios = nr_ratios;
52 /* create a new task */
53 QApplication::setOverrideCursor(waitCursor); /* show the sand clock */
54 current_task.create_task(max_md, nr_ratios, add_sub, mul_div);
55 QApplication::restoreOverrideCursor(); /* show the normal cursor */
57 // the next thing to do on a button click would be to check the entered
58 // result
59 m_currentState = _CHECK_TASK;
61 baseWidget = new QWidget(this, "baseWidget");
62 baseGrid = new QGridLayout(this, 1, 1, 0, -1, "baseGrid");
63 baseGrid->addWidget(baseWidget, 0, 0);
65 // this is a VBox
66 realLayout = new QVBoxLayout(baseWidget, 5, 5, "realLayout");
68 // add a spacer at the top of the VBox
69 QSpacerItem * v_spacer = new QSpacerItem(1, 1);
70 realLayout->addItem(v_spacer);
72 // now a line holding the task, input fields and result
73 QHBoxLayout * taskLineHBoxLayout = new QHBoxLayout(5, "taskLineHBoxLayout");
74 realLayout->addLayout(taskLineHBoxLayout);
76 // first left is the task widget
77 m_taskWidget = new TaskWidget(baseWidget, "m_taskWidget", current_task);
78 taskLineHBoxLayout->addWidget(m_taskWidget);
80 // now we have the input fields aligned in a VBox
81 QVBoxLayout * inputLayout = new QVBoxLayout(5, "inputLayout");
82 taskLineHBoxLayout->addLayout(inputLayout);
84 // to validate, that the input is an int
85 KIntValidator *valnum = new KIntValidator( this );
87 /* add input box so the user can enter numerator */
88 numer_edit = new QLineEdit(baseWidget, "numer_edit");
89 numer_edit->setValidator( valnum ); // use the int validator
90 QToolTip::add(numer_edit, i18n("Enter the numerator of your result"));
91 inputLayout->addWidget(numer_edit);
93 /* add a line between the edit boxes */
94 edit_line = new QFrame(baseWidget, "edit_line");
95 edit_line->setGeometry(QRect(100, 100, 20, 20));
96 edit_line->setFrameStyle(QFrame::HLine | QFrame::Sunken);
97 inputLayout->addWidget(edit_line);
99 /* add input box so the user can enter denominator */
100 deno_edit = new QLineEdit(baseWidget, "deno_edit");
101 deno_edit->setValidator( valnum ); // use the int validator
102 QToolTip::add(deno_edit, i18n("Enter the denominator of your result"));
103 inputLayout->addWidget(deno_edit);
105 // next is the result widget
106 m_resultWidget = new ResultWidget(baseWidget, "m_resultWidget", *new ratio());
107 taskLineHBoxLayout->addWidget(m_resultWidget);
109 // at the right end we have a label just showing CORRECT or WRONG
110 result_label = new QLabel(baseWidget, "result_label");
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
142 baseWidget->show();
144 // show the whole layout
145 m_taskWidget->show();
146 m_resultWidget->hide();
148 // add tooltip and qwhatsthis help to the widget
149 QToolTip::add(this, i18n("In this exercise you have to solve a given task with fractions."));
150 QWhatsThis::add(this, i18n("In this exercise you have to solve the generated task. You have to enter numerator and denominator. You can adjust the difficulty of the task with the boxes in the toolbar. Do not forget to reduce the result!"));
153 /* destructor */
154 TaskView::~TaskView()
156 #ifdef DEBUG
157 kdDebug() << "destructor TaskView()" << endl;
158 #endif
160 /* no need to delete any child widgets, Qt does it by itself */
163 /** the parameters of task generation can be set with this function */
164 void TaskView::setTaskParameters(bool padd_sub, bool pmul_div, unsigned int pnr_ratios, unsigned int pmax_md)
166 // at least one operation must be enabled
167 if ((padd_sub == false) && (pmul_div == false))
168 padd_sub = true;
170 // we need at least 2 ratios
171 if (pnr_ratios < 2)
172 pnr_ratios = 2;
174 // we can only visualize 5 ratios, so we have to limit it
175 if (pnr_ratios > 5)
176 pnr_ratios = 5;
178 // the main denominator must be at least 2^pnr_ratios
179 if (pow(2, pnr_ratios) > pmax_md)
180 pmax_md = (unsigned int) pow(2, pnr_ratios);
182 // so everything seems to be fine, lets set the internal values to the given
183 // ones
184 add_sub = padd_sub;
185 mul_div = pmul_div;
186 max_md = pmax_md;
188 nr_ratios = pnr_ratios;
190 return;
193 /** resets the current state, creates a new task and count the last task as
194 * wrong, if it wasn't solved (in _NEXT_TASK state) yet
195 * mainly used after changing the task parameters */
196 void TaskView::forceNewTask()
198 #ifdef DEBUG
199 kdDebug() << "forceNewTask TaskView()" << endl;
200 #endif
202 if (m_currentState == _CHECK_TASK)
204 // emit the signal for wrong
205 signalTaskSolvedWrong();
207 m_currentState = _CHECK_TASK;
208 m_checkButton->setText(i18n("&Check Task"));
210 // generate next task
211 (void) nextTask();
215 /* ------ public slots ------ */
217 void TaskView::update()
219 // call update of components
220 m_taskWidget->updateAndRepaint();
221 m_resultWidget->updateAndRepaint();
223 // update for itself
224 ((QWidget *) this)->update();
228 /* ------ private member functions ------ */
230 /** - checks the entered result and compares it to the task's result
231 - shows the correct result and informs the user if he was right or wrong
232 - if the user entered the result unreduced, he will be informed about it
233 - if the user entered a 0 for the denominator, he will be informed about
234 it (division by zero)
235 - emits signals if task was solved right or wrong */
236 void TaskView::showResult()
238 QString tmp_str; /* to build a string for a label */
239 QPalette pal;
240 QColorGroup cg;
242 // change the tooltip of the check button
243 QToolTip::add(m_checkButton, i18n("Click on this button to get to the next task."));
245 numer_edit->setEnabled(false);
246 deno_edit->setEnabled(false);
248 result = current_task.solve();
249 m_resultWidget->setResult(result);
250 m_resultWidget->show();
252 // an empty numerator field will be interpreted as 0
253 if (numer_edit->text().isEmpty() == true)
254 numer_edit->setText("0");
256 // an empty denominator field will be interpreted as 1
257 if (deno_edit->text().isEmpty() == true)
258 deno_edit->setText("1");
260 /* store the entered result to check it, but without reducing */
261 entered_result.setNumerator(numer_edit->text().toInt(), false);
262 entered_result.setDenominator(deno_edit->text().toInt(), false);
264 // check the entered result; 0/1 == 0/5 -> true,
265 // but 0/1 == 0/0 -> false
266 // a 0 for denominator is never allowed (always counted as wrong)
268 // we have to get the 0 directly from the input field, because
269 // Ratio::setDenominator(0, false) will set the denominator to 1 to ensure
270 // the Ratio is valid
271 if ( (deno_edit->text().toInt() != 0) && ((entered_result == result) ||
272 (result.numerator() == 0 && entered_result.numerator() == 0)) )
274 // emit the signal for correct
275 signalTaskSolvedCorrect();
277 /* yes, the user entered the correct result */
278 result_label->setText(i18n("CORRECT"));
279 pal = result_label->palette(); /* set green font color */
280 cg = pal.active();
281 cg.setColor(QColorGroup::Foreground, QColor(6, 179, 0));
282 pal.setActive(cg);
283 cg = pal.inactive();
284 cg.setColor(QColorGroup::Foreground, QColor(6, 179, 0));
285 pal.setInactive(cg);
286 result_label->setPalette(pal);
287 result_label->show(); /* show the result at the end of the task */
288 } else {
289 // emit the signal for wrong
290 signalTaskSolvedWrong();
292 /* no, the user entered the wrong result */
293 result_label->setText(i18n("WRONG"));
294 pal = result_label->palette(); /* set red font color */
295 cg = pal.active();
296 cg.setColor(QColorGroup::Foreground, QColor(red));
297 pal.setActive(cg);
298 cg = pal.inactive();
299 cg.setColor(QColorGroup::Foreground, QColor(red));
300 pal.setInactive(cg);
301 result_label->setPalette(pal);
303 result_label->show(); /* show the result at the end of the task */
305 // if the user entered a 0 for the denominator (division by 0) we have to
306 // get the 0 directly from the input field, because
307 // Ratio::setDenominator(0, true) will set the denominator to 1 to ensure
308 // the Ratio is valid
309 if (deno_edit->text().toInt() == 0)
311 KMessageBox::information(this,
312 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."));
313 } else {
314 /* maybe the entered ratio was not reduced */
315 entered_result.reduce();
316 if (entered_result == result)
317 KMessageBox::information(this,
318 i18n("You entered the correct result, but not reduced.\nAlways enter your results as reduced. This task will be counted as not correctly solved."));
320 } /* if (entered_result == result) */
323 /** generate the next task and show it to the user */
324 void TaskView::nextTask()
326 // change the tooltip of the check button
327 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."));
329 numer_edit->setEnabled(true);
330 deno_edit->setEnabled(true);
332 result_label->hide(); /* do not show the result at the end of the task */
333 m_resultWidget->hide();
335 /* clear user input */
336 deno_edit->setText("");
337 numer_edit->setText("");
338 numer_edit->setFocus();
340 /* create a new task */
341 QApplication::setOverrideCursor(waitCursor); /* show the sand clock */
342 current_task.create_task(max_md, nr_ratios, add_sub, mul_div);
343 QApplication::restoreOverrideCursor(); /* show the normal cursor */
345 // update the task widget
346 m_taskWidget->setTask((const task) (current_task));
349 /* ------ private slots ------ */
351 void TaskView::slotCheckButtonClicked()
353 if (m_currentState == _CHECK_TASK)
355 // if nothing has been entered by the user, we don't check the result yet
356 if (numer_edit->text().isEmpty() == true && deno_edit->text().isEmpty() ==
357 true)
358 return;
359 m_currentState = _NEXT_TASK;
360 m_checkButton->setText(i18n("N&ext Task"));
361 (void) showResult();
362 } else {
363 m_currentState = _CHECK_TASK;
364 m_checkButton->setText(i18n("&Check Task"));
365 (void) nextTask();