diff options
author | toma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2009-11-25 17:56:58 +0000 |
---|---|---|
committer | toma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2009-11-25 17:56:58 +0000 |
commit | ce599e4f9f94b4eb00c1b5edb85bce5431ab3df2 (patch) | |
tree | d3bb9f5d25a2dc09ca81adecf39621d871534297 /kbruch/src | |
download | tdeedu-ce599e4f9f94b4eb00c1b5edb85bce5431ab3df2.tar.gz tdeedu-ce599e4f9f94b4eb00c1b5edb85bce5431ab3df2.zip |
Copy the KDE 3.5 branch to branches/trinity for new KDE 3.5 features.
BUG:215923
git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/kdeedu@1054174 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'kbruch/src')
59 files changed, 7312 insertions, 0 deletions
diff --git a/kbruch/src/Makefile.am b/kbruch/src/Makefile.am new file mode 100644 index 00000000..7456866d --- /dev/null +++ b/kbruch/src/Makefile.am @@ -0,0 +1,49 @@ +bin_PROGRAMS = kbruch + +kbruch_COMPILE_FIRST = version.h +kbruch_SOURCES = exercisebase.cpp taskvieweroptionsbase.ui task.cpp ratio.cpp taskview.cpp statisticsview.cpp primenumber.cpp kbruch.cpp mainqtwidget.cpp taskwidget.cpp fractionbasewidget.cpp resultwidget.cpp exercisecompare.cpp ratiowidget.cpp rationalwidget.cpp exerciseconvert.cpp exercisefactorize.cpp factorizedwidget.cpp settingsclass.kcfgc +kbruch_LDADD = $(LIB_KDEUI) +# the library search path. +kbruch_LDFLAGS = $(all_libraries) $(KDE_RPATH) + +EXTRA_DIST = kbruch.cpp kbruch.h kbruch.desktop hi32-app-kbruch.png hi16-app-kbruch.png lo32-app-kbruch.png lo16-app-kbruch.png mainqtwidget.cpp mainqtwidget.h primenumber.cpp primenumber.h statisticsview.cpp statisticsview.h exercisebase.cpp exercisebase.h taskview.cpp taskview.h ratio.cpp ratio.h task.cpp task.h taskwidget.cpp taskwidget.h fractionbasewidget.cpp fractionbasewidget.h resultwidget.cpp resultwidget.h exercisecompare.cpp exercisecompare.h ratiowidget.cpp ratiowidget.h rationalwidget.cpp rationalwidget.h exerciseconvert.cpp exerciseconvert.h exercisefactorize.cpp exercisefactorize.h factorizedwidget.cpp factorizedwidget.h kbruch.rc taskvieweroptionsbase.ui + +xdg_apps_DATA = kbruch.desktop +kde_kcfg_DATA = kbruch.kcfg + +KDE_ICON = AUTO + +####### kdevelop will overwrite this part!!! (end)############ +# this 10 paths are KDE specific. Use them: +# kde_htmldir Where your docs should go to. (contains lang subdirs) +# kde_appsdir Where your application file (.kdelnk) should go to. +# kde_icondir Where your icon should go to. +# kde_minidir Where your mini icon should go to. +# kde_datadir Where you install application data. (Use a subdir) +# kde_locale Where translation files should go to.(contains lang subdirs) +# kde_cgidir Where cgi-bin executables should go to. +# kde_confdir Where config files should go to. +# kde_mimedir Where mimetypes should go to. +# kde_toolbardir Where general toolbar icons should go to. +# kde_wallpaperdir Where general wallpapers should go to. + +# set the include path for X, qt and KDE +INCLUDES= $(all_includes) + +METASOURCES = AUTO + +rcdir = $(kde_datadir)/kbruch +rc_DATA = kbruchui.rc + +messages: rc.cpp + LIST=`find . -name \*.h -o -name \*.hh -o -name \*.H -o -name \*.hxx -o -name \*.hpp -o -name \*.cpp -o -name \*.cc -o -name \*.cxx -o -name \*.ecpp -o -name \*.C`; \ + if test -n "$$LIST"; then \ + $(XGETTEXT) $$LIST -o $(podir)/kbruch.pot; \ + fi + +version.h: $(top_srcdir)/kbruch/VERSION + printf "#undef KBRUCH_VERSION\n#define KBRUCH_VERSION \"`cat $(top_srcdir)/kbruch/VERSION`\"\n" > version.h + +CLEANFILES = version.h + +noinst_HEADERS = version.h diff --git a/kbruch/src/cr32-action-kbruch_exercise_common.png b/kbruch/src/cr32-action-kbruch_exercise_common.png Binary files differnew file mode 100644 index 00000000..4cf33865 --- /dev/null +++ b/kbruch/src/cr32-action-kbruch_exercise_common.png diff --git a/kbruch/src/cr32-action-kbruch_exercise_compare.png b/kbruch/src/cr32-action-kbruch_exercise_compare.png Binary files differnew file mode 100644 index 00000000..251f3a99 --- /dev/null +++ b/kbruch/src/cr32-action-kbruch_exercise_compare.png diff --git a/kbruch/src/cr32-action-kbruch_exercise_conversion.png b/kbruch/src/cr32-action-kbruch_exercise_conversion.png Binary files differnew file mode 100644 index 00000000..372f6c1e --- /dev/null +++ b/kbruch/src/cr32-action-kbruch_exercise_conversion.png diff --git a/kbruch/src/cr32-action-kbruch_exercise_factorisation.png b/kbruch/src/cr32-action-kbruch_exercise_factorisation.png Binary files differnew file mode 100644 index 00000000..333dfb78 --- /dev/null +++ b/kbruch/src/cr32-action-kbruch_exercise_factorisation.png diff --git a/kbruch/src/cr64-action-kbruch_exercise_common.png b/kbruch/src/cr64-action-kbruch_exercise_common.png Binary files differnew file mode 100644 index 00000000..a10e14d9 --- /dev/null +++ b/kbruch/src/cr64-action-kbruch_exercise_common.png diff --git a/kbruch/src/cr64-action-kbruch_exercise_compare.png b/kbruch/src/cr64-action-kbruch_exercise_compare.png Binary files differnew file mode 100644 index 00000000..cd00e937 --- /dev/null +++ b/kbruch/src/cr64-action-kbruch_exercise_compare.png diff --git a/kbruch/src/cr64-action-kbruch_exercise_conversion.png b/kbruch/src/cr64-action-kbruch_exercise_conversion.png Binary files differnew file mode 100644 index 00000000..db7f81fc --- /dev/null +++ b/kbruch/src/cr64-action-kbruch_exercise_conversion.png diff --git a/kbruch/src/cr64-action-kbruch_exercise_factorisation.png b/kbruch/src/cr64-action-kbruch_exercise_factorisation.png Binary files differnew file mode 100644 index 00000000..5b949484 --- /dev/null +++ b/kbruch/src/cr64-action-kbruch_exercise_factorisation.png diff --git a/kbruch/src/exercisebase.cpp b/kbruch/src/exercisebase.cpp new file mode 100644 index 00000000..f8d376c5 --- /dev/null +++ b/kbruch/src/exercisebase.cpp @@ -0,0 +1,42 @@ +/*************************************************************************** + exercisebase.cpp + ------------------- + begin : 2004/06/03 + 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 "exercisebase.h" +#include "exercisebase.moc" + +/* these includes are needed for KDE support */ +#include <kapplication.h> +#include <klocale.h> + +/* ----- public member functions ----- */ + +/* constructor */ +ExerciseBase::ExerciseBase(QWidget * parent, const char * name): + QWidget(parent, name) +{ +#ifdef DEBUG + kdDebug() << "constructor ExerciseBase()" << endl; +#endif +} + +/* destructor */ +ExerciseBase::~ExerciseBase() +{ +#ifdef DEBUG + kdDebug() << "destructor ExerciseBase()" << endl; +#endif +} diff --git a/kbruch/src/exercisebase.h b/kbruch/src/exercisebase.h new file mode 100644 index 00000000..a43992e7 --- /dev/null +++ b/kbruch/src/exercisebase.h @@ -0,0 +1,51 @@ +/*************************************************************************** + exercisebase.h + ------------------- + begin : 2004/06/03 + 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. * + * * + ***************************************************************************/ + +#ifndef EXERCISEBASE_H +#define EXERCISEBASE_H + +#define _CHECK_TASK 0 +#define _NEXT_TASK 1 + +#ifdef DEBUG +#include <kdebug.h> +#endif + +#include <qwidget.h> + +/*! Constructs a QWidget. + * + * It is the base class for showing the different exercises. + * + * \author Sebastian Stein + * */ +class ExerciseBase : public QWidget +{ + Q_OBJECT + +public: + /** constructor */ + ExerciseBase(QWidget * parent = 0, const char * name = 0); + + /** destructor */ + ~ExerciseBase(); + + /** force the creation of a new task */ + virtual void forceNewTask() = 0; +}; + +#endif diff --git a/kbruch/src/exercisecompare.cpp b/kbruch/src/exercisecompare.cpp new file mode 100644 index 00000000..c0d6466d --- /dev/null +++ b/kbruch/src/exercisecompare.cpp @@ -0,0 +1,327 @@ +/*************************************************************************** + exercisecompare.cpp + ------------------- + begin : 2004/06/03 + 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 "exercisecompare.h" +#include "exercisecompare.moc" + +/* these includes are needed for KDE support */ +#include <kapplication.h> +#include <klocale.h> + +/* these includes are needed for Qt support */ +#include <qlabel.h> +#include <qlayout.h> +#include <qpushbutton.h> +#include <qtooltip.h> +#include <qwhatsthis.h> + +/* standard C++ library includes */ +#include <stdlib.h> + +/* ----- public member functions ----- */ + +/* constructor */ +ExerciseCompare::ExerciseCompare(QWidget * parent, const char * name): + ExerciseBase(parent, name) +{ +#ifdef DEBUG + kdDebug() << "constructor ExerciseCompare()" << endl; +#endif + + /* create a new task */ + QApplication::setOverrideCursor(waitCursor); /* show the sand clock */ + createTask(); + QApplication::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 QWidget(this, "baseWidget"); + baseGrid = new QGridLayout(this, 1, 1, 0, -1, "baseGrid"); + baseGrid->addWidget(baseWidget, 0, 0); + + // this is a VBox + realLayout = new QVBoxLayout(baseWidget, 5, 5, "realLayout"); + + // add a spacer at the top of the VBox + QSpacerItem * v_spacer = new QSpacerItem(1, 1); + realLayout->addItem(v_spacer); + + // now a line holding the task, input fields and result + QHBoxLayout * taskLineHBoxLayout = new QHBoxLayout(5, "taskLineHBoxLayout"); + realLayout->addLayout(taskLineHBoxLayout); + + // spacer + v_spacer = new QSpacerItem(1, 1); + taskLineHBoxLayout->addItem(v_spacer); + + // first the first ratio widget + m_firstRatioWidget = new RatioWidget(baseWidget, "m_firstRatioWidget", m_firstRatio); + taskLineHBoxLayout->addWidget(m_firstRatioWidget); + + // spacer + v_spacer = new QSpacerItem(1, 1); + taskLineHBoxLayout->addItem(v_spacer); + + // now the button where the user has to choose the comparison sign + m_signButton = new QPushButton(baseWidget, "m_signButton"); + + // RTL BUG, see slotSignButtonClicked() for more information + m_signButton->setText( QApplication::reverseLayout()?">":"<"); + + m_signButtonState = lessThen; + taskLineHBoxLayout->addWidget(m_signButton); + QObject::connect(m_signButton, SIGNAL(clicked()), this, SLOT(slotSignButtonClicked())); + QToolTip::add(m_signButton, i18n("Click on this button to change the comparison sign.")); + + // spacer + v_spacer = new QSpacerItem(1, 1); + taskLineHBoxLayout->addItem(v_spacer); + + // now the second ratio widget + m_secondRatioWidget = new RatioWidget(baseWidget, "m_secondRatioWidget", m_secondRatio); + taskLineHBoxLayout->addWidget(m_secondRatioWidget); + + // spacer + v_spacer = new QSpacerItem(1, 1); + taskLineHBoxLayout->addItem(v_spacer); + + // at the right end we have a label just showing CORRECT or WRONG + result_label = new QLabel(baseWidget, "result_label"); + result_label->setText(i18n("WRONG")); + taskLineHBoxLayout->addWidget(result_label); + result_label->hide(); + + // --- that is the end of the horizontal line --- + + // add another spacer in the middle of the VBox + v_spacer = new QSpacerItem(1, 1); + realLayout->addItem(v_spacer); + + // the lower part of the VBox holds just a right aligned button + QHBoxLayout * lowerHBox = new QHBoxLayout(1, "lowerHBox"); + realLayout->addLayout(lowerHBox); + lowerHBox->addStretch(100); + + // the right aligned button + m_checkButton = new QPushButton( baseWidget, "m_checkButton" ); + m_checkButton->setText(i18n("&Check Task")); + m_checkButton->setDefault(true); // is the default button of the dialog + QToolTip::add(m_checkButton, i18n("Click on this button to check your result.")); + lowerHBox->addWidget(m_checkButton, 1, Qt::AlignRight); + QObject::connect(m_checkButton, SIGNAL(clicked()), this, SLOT(slotCheckButtonClicked())); + + // that the user can start typing without moving the focus + m_signButton->setFocus(); + + // show the whole layout + baseWidget->show(); + + // add tooltip and qwhatsthis help to the widget + QToolTip::add(this, i18n("In this exercise you have to compare 2 given fractions.")); + QWhatsThis::add(this, i18n("In this exercise you have to compare 2 given fractions by choosing the correct comparison sign. You can change the comparison sign by just clicking on the button showing the sign.")); +} + +/* destructor */ +ExerciseCompare::~ExerciseCompare() +{ +#ifdef DEBUG + kdDebug() << "destructor ExerciseCompare()" << endl; +#endif + + /* no need to delete any child widgets, Qt 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 ExerciseCompare::forceNewTask() +{ +#ifdef DEBUG + kdDebug() << "forceNewTask ExerciseCompare()" << 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 ExerciseCompare::update() +{ + // call update of components + m_firstRatioWidget->updateAndRepaint(); + m_secondRatioWidget->updateAndRepaint(); + + // update for itself + ((QWidget *) this)->update(); +} + + +/* ------ private member functions ------ */ + +void ExerciseCompare::createTask() +{ + // generate the first ratio + m_firstRatio = ratio(int((double(rand()) / RAND_MAX) * 10 + 1), int((double(rand()) / RAND_MAX) * 10 + 1)); + + // now the second ratio, but make sure, the second ratio is different from + // the first one + do + { + m_secondRatio = ratio(int((double(rand()) / RAND_MAX) * 10 + 1), int((double(rand()) / RAND_MAX) * 10 + 1)); + } while (m_firstRatio == m_secondRatio); + + return; +} + +/** - checks, if the user solved the task correctly + - emits signals if task was solved correctly or wrong */ +void ExerciseCompare::showResult() +{ + QPalette pal; + QColorGroup cg; + bool result = m_firstRatio < m_secondRatio; + + // change the tooltip of the check button + QToolTip::add(m_checkButton, i18n("Click on this button to get to the next task.")); + + // disable sign button + m_signButton->setEnabled(false); + + if ((m_signButtonState == lessThen && result == true) || + (m_signButtonState == greaterThen && result == false)) + { + // 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(QColorGroup::Foreground, QColor(6, 179, 0)); + pal.setActive(cg); + cg = pal.inactive(); + cg.setColor(QColorGroup::Foreground, QColor(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(QColorGroup::Foreground, QColor(red)); + pal.setActive(cg); + cg = pal.inactive(); + cg.setColor(QColorGroup::Foreground, QColor(red)); + pal.setInactive(cg); + result_label->setPalette(pal); + + result_label->show(); /* show the result at the end of the task */ + } /* if (entered_result == result) */ + + return; +} + +/** generate the next task and show it to the user */ +void ExerciseCompare::nextTask() +{ + // change the tooltip of the check button + QToolTip::add(m_checkButton, i18n("Click on this button to check your result.")); + + // enable sign button + m_signButton->setEnabled(true); + + result_label->hide(); /* do not show the result at the end of the task */ + + // reset the signButton + // RTL BUG, see slotSignButtonClicked() for more information + m_signButton->setText( QApplication::reverseLayout()?">":"<"); + m_signButtonState = lessThen; + + /* create a new task */ + QApplication::setOverrideCursor(waitCursor); /* show the sand clock */ + createTask(); + QApplication::restoreOverrideCursor(); /* show the normal cursor */ + + // set the ratio widgets with the new ratios + m_firstRatioWidget->setRatio(m_firstRatio); + m_secondRatioWidget->setRatio(m_secondRatio); + + return; +} + +/* ------ private slots ------ */ + +void ExerciseCompare::slotCheckButtonClicked() +{ + if (m_currentState == _CHECK_TASK) + { + 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; +} + +void ExerciseCompare::slotSignButtonClicked() +{ + // in RTL desktops, we still need to allign the + // execise to the left. On Qt4, you can set the direction + // of the layout to LTR (instead of inherit), but on Qt3 + // the only way of fixing it is inserting the widgets in reversed + // order to the layout. + // + // But... as an ugly hack, we can also display the "other" operation + // thats damm ugly, but will work as well :) + // + // See also taskview.cpp for the same bug. + // + // (if you need help with this feel free to contact + // (me - Diego <elcuco@kde.org> ) + // This shuold fix parts of bug #116831, + + if (m_signButtonState == lessThen) + { + m_signButton->setText( QApplication::reverseLayout()?"<":">"); + m_signButtonState = greaterThen; + } else { + m_signButton->setText( QApplication::reverseLayout()?">":"<"); + m_signButtonState = lessThen; + } + + return; +} diff --git a/kbruch/src/exercisecompare.h b/kbruch/src/exercisecompare.h new file mode 100644 index 00000000..a1c656c2 --- /dev/null +++ b/kbruch/src/exercisecompare.h @@ -0,0 +1,102 @@ +/*************************************************************************** + exercisecompare.h + ------------------- + begin : 2004/06/03 + 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. * + * * + ***************************************************************************/ + +#ifndef EXERCISECOMPARE_H +#define EXERCISECOMPARE_H + +#define DEBUG + +#ifdef DEBUG +#include <kdebug.h> +#endif + +#include "exercisebase.h" +#include "ratio.h" +#include "ratiowidget.h" + +class QGridLayout; +class QLabel; +class QPushButton; +class QVBoxLayout; + + +#include <qwidget.h> + +/*! Constructs a QWidget, which shows the task to the user. + * The class also provides input fields, so that the user can enter the result. + * It also controls the interaction, so that the entered result gets checked + * and a new task can be generated. + * \author Sebastian Stein + * */ +class ExerciseCompare : public ExerciseBase +{ + Q_OBJECT + +public: + /** constructor */ + ExerciseCompare(QWidget * parent = 0, const char * name = 0); + + /** destructor */ + ~ExerciseCompare(); + + /** force the creation of a new task */ + void forceNewTask(); + +public slots: + void update(); + +signals: + /** class emits this signal, if the task was solved correctly by the user */ + void signalExerciseSolvedCorrect(); + + /** class emits this signal, if the task was solved not correctly by the user + * */ + void signalExerciseSolvedWrong(); + +private: + short m_currentState; + + RatioWidget* m_firstRatioWidget; + RatioWidget* m_secondRatioWidget; + QPushButton* m_checkButton; + QPushButton* m_signButton; + QLabel* result_label; + + QGridLayout* baseGrid; + QWidget* baseWidget; + QVBoxLayout* realLayout; + + ratio m_firstRatio; + ratio m_secondRatio; + + enum SignButtonState + { + lessThen, + greaterThen + }; + SignButtonState m_signButtonState; + + void createTask(); + void showResult(); + void nextTask(); + +private slots: + void slotCheckButtonClicked(); + void slotSignButtonClicked(); +}; + +#endif diff --git a/kbruch/src/exerciseconvert.cpp b/kbruch/src/exerciseconvert.cpp new file mode 100644 index 00000000..1207ecbf --- /dev/null +++ b/kbruch/src/exerciseconvert.cpp @@ -0,0 +1,467 @@ +/*************************************************************************** + 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 Qt support */ +#include <qlabel.h> +#include <qlayout.h> +#include <qlineedit.h> +#include <qpushbutton.h> +#include <qtooltip.h> +#include <qwhatsthis.h> + +/* standard C++ library includes */ +#include <stdlib.h> + +#include "rationalwidget.h" +#include "resultwidget.h" + +/* ----- public member functions ----- */ + +/* constructor */ +ExerciseConvert::ExerciseConvert(QWidget * parent, const char * name): + ExerciseBase(parent, name) +{ +#ifdef DEBUG + kdDebug() << "constructor ExerciseConvert()" << endl; +#endif + + /* create a new task */ + QApplication::setOverrideCursor(waitCursor); /* show the sand clock */ + createTask(); + QApplication::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 QWidget(this, "baseWidget"); + baseGrid = new QGridLayout(this, 1, 1, 0, -1, "baseGrid"); + baseGrid->addWidget(baseWidget, 0, 0); + + // this is a VBox + realLayout = new QVBoxLayout(baseWidget, 5, 5, "realLayout"); + + // add a spacer at the top of the VBox + QSpacerItem * v_spacer = new QSpacerItem(1, 1); + realLayout->addItem(v_spacer); + + // now a line holding the task, input fields and result + QHBoxLayout * taskLineHBoxLayout = new QHBoxLayout(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 + QVBoxLayout * inputLayout = new QVBoxLayout(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 QLineEdit(baseWidget, "numer_edit"); + numer_edit->setValidator( valnum ); // use the int validator + QToolTip::add(numer_edit, i18n("Enter the numerator of your result")); + inputLayout->addWidget(numer_edit); + + /* add a line between the edit boxes */ + edit_line = new QFrame(baseWidget, "edit_line"); + edit_line->setGeometry(QRect(100, 100, 20, 20)); + edit_line->setFrameStyle(QFrame::HLine | QFrame::Sunken); + inputLayout->addWidget(edit_line); + + /* add input box so the user can enter denominator */ + deno_edit = new QLineEdit(baseWidget, "deno_edit"); + deno_edit->setValidator( valnum ); // use the int validator + QToolTip::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 QLabel(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 QSpacerItem(1, 1, QSizePolicy::Expanding, QSizePolicy::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 Qt4, you can set the direction + // of the layout to LTR (instead of inherit), but on Qt3 + // 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 (QApplication::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 QSpacerItem(1, 1); + realLayout->addItem(v_spacer); + + // the lower part of the VBox holds just a right aligned button + QHBoxLayout * lowerHBox = new QHBoxLayout(1, "lowerHBox"); + realLayout->addLayout(lowerHBox); + lowerHBox->addStretch(100); + + // the right aligned button + m_checkButton = new QPushButton( baseWidget, "m_checkButton" ); + m_checkButton->setText(i18n("&Check Task")); + m_checkButton->setDefault(true); // is the default button of the dialog + 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.")); + lowerHBox->addWidget(m_checkButton, 1, Qt::AlignRight); + QObject::connect(m_checkButton, SIGNAL(clicked()), this, 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 + QToolTip::add(this, i18n("In this exercise you have to convert a number into a fraction.")); + 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!")); +} + +/* destructor */ +ExerciseConvert::~ExerciseConvert() +{ +#ifdef DEBUG + kdDebug() << "destructor ExerciseConvert()" << endl; +#endif + + /* no need to delete any child widgets, Qt 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 + ((QWidget *) 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() +{ + QString tmp_str; /* to build a string for a label */ + QPalette pal; + QColorGroup cg; + ratio entered_result; + + // change the tooltip of the check button + QToolTip::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(QColorGroup::Foreground, QColor(6, 179, 0)); + pal.setActive(cg); + cg = pal.inactive(); + cg.setColor(QColorGroup::Foreground, QColor(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(QColorGroup::Foreground, QColor(red)); + pal.setActive(cg); + cg = pal.inactive(); + cg.setColor(QColorGroup::Foreground, QColor(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 + 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.")); + + 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 */ + QApplication::setOverrideCursor(waitCursor); /* show the sand clock */ + createTask(); + QApplication::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; +} diff --git a/kbruch/src/exerciseconvert.h b/kbruch/src/exerciseconvert.h new file mode 100644 index 00000000..cfbb3e0c --- /dev/null +++ b/kbruch/src/exerciseconvert.h @@ -0,0 +1,97 @@ +/*************************************************************************** + 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. * + * * + ***************************************************************************/ + +#ifndef EXERCISECONVERT_H +#define EXERCISECONVERT_H + +#ifdef DEBUG +#include <kdebug.h> +#endif + +#include "exercisebase.h" +#include "ratio.h" + +class RationalWidget; +class ResultWidget; + +class QFrame; +class QGridLayout; +class QLabel; +class QLineEdit; +class QPushButton; +class QString; +class QVBoxLayout; + +/*! Construct the exercise widget to convert rational numbers into fractions + * + * \author Sebastian Stein + * */ +class ExerciseConvert : public ExerciseBase +{ + Q_OBJECT + +public: + /** constructor */ + ExerciseConvert(QWidget * parent = 0, const char * name = 0); + + /** destructor */ + ~ExerciseConvert(); + + /** force the creation of a new task */ + void forceNewTask(); + +public slots: + void update(); + +signals: + /** class emits this signal, if the task was solved correctly by the user */ + void signalExerciseSolvedCorrect(); + + /** class emits this signal, if the task was solved not correctly by the user + * */ + void signalExerciseSolvedWrong(); + +private: + short m_currentState; + + QString m_number; + uint m_periodStart; + uint m_periodLength; + ratio m_result; + + RationalWidget* m_rationalWidget; + ResultWidget* m_resultWidget; + QLineEdit* numer_edit; + QFrame* edit_line; + QLineEdit* deno_edit; + + QPushButton* m_checkButton; + QLabel* result_label; + + QGridLayout* baseGrid; + QWidget* baseWidget; + QVBoxLayout* realLayout; + + void createTask(); + void showResult(); + void nextTask(); + +private slots: + void slotCheckButtonClicked(); +}; + +#endif diff --git a/kbruch/src/exercisefactorize.cpp b/kbruch/src/exercisefactorize.cpp new file mode 100644 index 00000000..b411e032 --- /dev/null +++ b/kbruch/src/exercisefactorize.cpp @@ -0,0 +1,652 @@ +/*************************************************************************** + 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 "exercisefactorize.h" +#include "exercisefactorize.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 Qt support */ +#include <qlabel.h> +#include <qlayout.h> +#include <qlineedit.h> +#include <qpushbutton.h> +#include <qtooltip.h> +#include <qwhatsthis.h> + +/* standard C++ library includes */ +#include <stdlib.h> + +#include "factorizedwidget.h" +#include "primenumber.h" +#include "rationalwidget.h" +#include "resultwidget.h" +#include "settingsclass.h" + +/* ----- public member functions ----- */ + +/* constructor */ +ExerciseFactorize::ExerciseFactorize(QWidget * parent, const char * name): + ExerciseBase(parent, name) +{ + QPalette pal; + QColorGroup cg; +#ifdef DEBUG + kdDebug() << "constructor ExerciseFactorize()" << endl; +#endif + + /* create a new task */ + QApplication::setOverrideCursor(waitCursor); /* show the sand clock */ + createTask(); + QApplication::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; + + Form1Layout = new QVBoxLayout( this, 11, 6, "Form1Layout"); + + layout9 = new QVBoxLayout( 0, 0, 6, "layout9"); + + // The following method fix the problem in + // bug #116831, reverse order in RTL desktops. + // Amit Ramon amit.ramon@kdemail.net + layout4 = createFactorsLayout(); + layout9->addLayout(layout4); + + spacer2 = new QSpacerItem( 20, 21, QSizePolicy::Minimum, QSizePolicy::Expanding ); + layout9->addItem( spacer2 ); + + layout2 = new QVBoxLayout( 0, 0, 6, "layout2"); + + // The following method fix the problem in + // bug #116831, reverse order in RTL desktops. + // Amit Ramon amit.ramon@kdemail.net + layout1 = createButtonsLayout(); + layout2->addLayout(layout1); + + m_removeLastFactorButton = new QPushButton( this, "m_removeLastFactorButton" ); + layout2->addWidget( m_removeLastFactorButton ); + layout9->addLayout( layout2 ); + + spacer4 = new QSpacerItem( 20, 21, QSizePolicy::Minimum, QSizePolicy::Expanding ); + layout9->addItem( spacer4 ); + + layout7 = new QHBoxLayout( 0, 0, 6, "layout7"); + spacer3 = new QSpacerItem( 361, 20, QSizePolicy::Expanding, QSizePolicy::Minimum ); + layout7->addItem( spacer3 ); + + m_checkButton = new QPushButton( this, "m_checkButton" ); + layout7->addWidget( m_checkButton ); + layout9->addLayout( layout7 ); + Form1Layout->addLayout( layout9 ); + + // the current task + QString tmp_str; + tmp_str.setNum(m_taskNumber); + m_taskLabel->setText(tmp_str); + + // now set the color for the task label + m_taskLabel->setPaletteForegroundColor(SettingsClass::numberColor()); + + // the equal sign + m_equalSignLabel->setText("="); + + // now set the color for the equal sign + m_equalSignLabel->setPaletteForegroundColor(SettingsClass::operationColor()); + + // the wrong/correct label, we hide it + result_label->setText(i18n("WRONG")); + result_label->hide(); + + // the prime factor buttons + m_factor2Button->setText( i18n( "2" ) ); + m_factor3Button->setText( i18n( "3" ) ); + m_factor5Button->setText( i18n( "5" ) ); + m_factor7Button->setText( i18n( "7" ) ); + m_factor11Button->setText( i18n( "11" ) ); + m_factor13Button->setText( i18n( "13" ) ); + m_factor17Button->setText( i18n( "17" ) ); + m_factor19Button->setText( i18n( "19" ) ); + QObject::connect(m_factor2Button, SIGNAL(clicked()), this, SLOT(slotFactor2ButtonClicked())); + QObject::connect(m_factor3Button, SIGNAL(clicked()), this, SLOT(slotFactor3ButtonClicked())); + QObject::connect(m_factor5Button, SIGNAL(clicked()), this, SLOT(slotFactor5ButtonClicked())); + QObject::connect(m_factor7Button, SIGNAL(clicked()), this, SLOT(slotFactor7ButtonClicked())); + QObject::connect(m_factor11Button, SIGNAL(clicked()), this, SLOT(slotFactor11ButtonClicked())); + QObject::connect(m_factor13Button, SIGNAL(clicked()), this, SLOT(slotFactor13ButtonClicked())); + QObject::connect(m_factor17Button, SIGNAL(clicked()), this, SLOT(slotFactor17ButtonClicked())); + QObject::connect(m_factor19Button, SIGNAL(clicked()), this, SLOT(slotFactor19ButtonClicked())); + + // add tooltips to the factor buttons + QToolTip::add(m_factor2Button, i18n("Add prime factor 2.")); + QToolTip::add(m_factor3Button, i18n("Add prime factor 3.")); + QToolTip::add(m_factor5Button, i18n("Add prime factor 5.")); + QToolTip::add(m_factor7Button, i18n("Add prime factor 7.")); + QToolTip::add(m_factor11Button, i18n("Add prime factor 11.")); + QToolTip::add(m_factor13Button, i18n("Add prime factor 13.")); + QToolTip::add(m_factor17Button, i18n("Add prime factor 17.")); + QToolTip::add(m_factor19Button, i18n("Add prime factor 19.")); + + // the remove last factor button + m_removeLastFactorButton->setText( i18n( "&Remove Last Factor" ) ); + m_removeLastFactorButton->setEnabled(false); + QObject::connect(m_removeLastFactorButton, SIGNAL(clicked()), this, SLOT(slotRemoveLastFactorButtonClicked())); + QToolTip::add(m_removeLastFactorButton, i18n("Removes the last entered prime factor.")); + + // the check task button + m_checkButton->setText( i18n( "&Check Task" ) ); + 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.")); + QObject::connect(m_checkButton, SIGNAL(clicked()), this, SLOT(slotCheckButtonClicked())); + m_checkButton->setDefault(true); // is the default button of the dialog + + // that the user can start choosing the prime factors + m_factor2Button->setFocus(); + + // set the tab order + setTabOrder(m_factor2Button, m_factor3Button); + setTabOrder(m_factor3Button, m_factor5Button); + setTabOrder(m_factor5Button, m_factor7Button); + setTabOrder(m_factor7Button, m_factor11Button); + setTabOrder(m_factor13Button, m_factor17Button); + setTabOrder(m_factor17Button, m_factor19Button); + setTabOrder(m_factor19Button, m_removeLastFactorButton); + + // add tooltip and qwhatsthis help to the widget + QToolTip::add(this, i18n("In this exercise you have to factorize a given number.")); + QWhatsThis::add(this, i18n("In this exercise you have to factorize a given number. You have to enter all prime factors of the number. You can add a prime factor by clicking on the corresponding button. The chosen prime factors will be shown in the input field. Do not forget to enter all prime factors, even when a prime factor repeats several times!")); +} + +/* destructor */ +ExerciseFactorize::~ExerciseFactorize() +{ +#ifdef DEBUG + kdDebug() << "destructor ExerciseFactorize()" << endl; +#endif + + /* no need to delete any child widgets, Qt 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 ExerciseFactorize::forceNewTask() +{ +#ifdef DEBUG + kdDebug() << "forceNewTask ExerciseFactorize()" << 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 ExerciseFactorize::update() +{ + // now set the color for the task label + m_taskLabel->setPaletteForegroundColor(SettingsClass::numberColor()); + + // now set the color for the equal sign + m_equalSignLabel->setPaletteForegroundColor(SettingsClass::operationColor()); + + // and the factors + m_factorsWidget->updateAndRepaint(); + + // update for itself + ((QWidget *) this)->update(); +} + + +/* ------ private member functions ------ */ + +// +// The following method was added to fix +// bug #116831 (reverse layout in RTL desktops) +// Amit Ramon amit.ramon@kdemail.net +// + +/** Create the layout that hold the exercise widgets + */ +QHBoxLayout* ExerciseFactorize::createFactorsLayout() +{ + // first create all widgets + QHBoxLayout* layout = new QHBoxLayout( 0, 0, 6, "layout4"); + + m_taskLabel = new QLabel( this, "m_taskLabel" ); + + m_equalSignLabel = new QLabel( this, "m_equalSignLabel" ); + + m_factorsEnteredEdit = new QLineEdit( this, "m_factorsEnteredEdit" ); + m_factorsEnteredEdit->setReadOnly(true); + m_factorsEnteredEdit->setEnabled(false); + m_factorsEnteredEdit->setPaletteForegroundColor(QColor(0, 0, 0)); + + m_factorsWidget = + new FactorizedWidget( this, "m_factorsWidget", m_factorsResult); + + m_factorsWidget->hide(); + + result_label = new QLabel( this, "result_label" ); + + spacer1 = new QSpacerItem( 25, 20, QSizePolicy::Expanding, + QSizePolicy::Minimum ); + + // now add the widgets to the layout. + // if we are in a RTL desktop, add them + // in a reverse order + if (QApplication::reverseLayout()) + { + layout->addItem( spacer1 ); + layout->addWidget( result_label ); + layout->addWidget( m_factorsWidget ); + layout->addWidget( m_factorsEnteredEdit ); + layout->addWidget( m_equalSignLabel ); + layout->addWidget( m_taskLabel ); + } + else + { + layout->addWidget( m_taskLabel ); + layout->addWidget( m_equalSignLabel ); + layout->addWidget( m_factorsEnteredEdit ); + layout->addWidget( m_factorsWidget ); + layout->addWidget( result_label ); + layout->addItem( spacer1 ); + } + + return layout; +} + + +// +// The following method was added to fix +// bug #116831 (reverse layout in RTL desktops) +// Amit Ramon amit.ramon@kdemail.net +// + +/** Create the layout that hold the exercise widgets + */ +QGridLayout* ExerciseFactorize::createButtonsLayout() +{ + const int _COLS = 4; // number of buttons in each row + const int _ROWS = 2; // number of rows + + QGridLayout* layout = new QGridLayout( 0, 1, 1, 0, 6, "layout1"); + + // first row buttons + m_factor2Button = new QPushButton( this, "m_factor2Button" ); + m_factor3Button = new QPushButton( this, "m_factor3Button" ); + m_factor5Button = new QPushButton( this, "m_factor5Button" ); + m_factor7Button = new QPushButton( this, "m_factor7Button" ); + + // second row buttons + m_factor11Button = new QPushButton( this, "m_factor11Button" ); + m_factor13Button = new QPushButton( this, "m_factor13Button" ); + m_factor17Button = new QPushButton( this, "m_factor17Button" ); + m_factor19Button = new QPushButton( this, "m_factor19Button" ); + + // temp array to help with adding the buttons + // to the grid + QPushButton* buttons[_ROWS][_COLS] = + { + { + m_factor2Button, + m_factor3Button, + m_factor5Button, + m_factor7Button + }, + { + m_factor11Button, + m_factor13Button, + m_factor17Button, + m_factor19Button + } + }; + + + int buttonIdxStart = 0; + int step = 1; + + // if we are in a RTL desktop, this helps adding the + // buttons in a reverse order + if (QApplication::reverseLayout()) + { + buttonIdxStart = _COLS - 1; + step = -1; + } + + // now add the buttons to the grid + for (int row = 0; row < _ROWS; row++) + { + int buttonIdx = buttonIdxStart; + + for (int col = 0; col < _COLS; col++) + { + layout->addWidget(buttons[row][buttonIdx], row, col ); + buttonIdx += step; + } + } + + return layout; +} + + +void ExerciseFactorize::createTask() +{ + uint uint_number; + primenumber tmp_primenumber; + + // just pick one number out of the possible numbers to factorize + m_taskNumber = possibleTasks[uint((double(rand()) / RAND_MAX) * numberPossibleTasks)]; + + // now get the primefactors of the taskNumber + m_factorsResult.clear(); + uint_number = m_taskNumber; + tmp_primenumber.move_first(); + do + { + // check if the current primenumber is a divisor + if (uint_number % tmp_primenumber.get_current() != 0) + { + // no, it is not a divisor, go on with next primenumber + tmp_primenumber.move_forward(); + } else { + // current primenumber is a divisor + m_factorsResult.append(tmp_primenumber.get_current()); + uint_number = uint(uint_number / tmp_primenumber.get_current()); + } + } while (uint_number != 1); + + return; +} + +/** - checks, if the user solved the task correctly + - emits signals if task was solved correctly or wrong */ +void ExerciseFactorize::showResult() +{ + QString tmp_str, tmp_str2; /* to build a string for a label */ + QPalette pal; + QColorGroup cg; + uint uint_result = 0; + + // change the tooltip of the check button + QToolTip::add(m_checkButton, i18n("Click on this button to get to the next task.")); + + // disable prime factor buttons + m_factor2Button->setEnabled(false); + m_factor3Button->setEnabled(false); + m_factor5Button->setEnabled(false); + m_factor7Button->setEnabled(false); + m_factor11Button->setEnabled(false); + m_factor13Button->setEnabled(false); + m_factor17Button->setEnabled(false); + m_factor19Button->setEnabled(false); + + // disable factor removal button as well + m_removeLastFactorButton->setEnabled(false); + + // show the result + m_factorsWidget->setFactors(m_factorsResult); + m_factorsWidget->show(); + + // now calculate the product of the prime factors entered by the user + for (uint tmp_uint = 0; tmp_uint < m_factorsEntered.count(); tmp_uint++) + { + if (tmp_uint == 0) + { + uint_result = m_factorsEntered[0]; + } else { + uint_result *= m_factorsEntered[tmp_uint]; + } + } + + if (uint_result == m_taskNumber) + { + // 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(QColorGroup::Foreground, QColor(6, 179, 0)); + pal.setActive(cg); + cg = pal.inactive(); + cg.setColor(QColorGroup::Foreground, QColor(6, 179, 0)); + pal.setInactive(cg); + result_label->setPalette(pal); + } 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(QColorGroup::Foreground, QColor(red)); + pal.setActive(cg); + cg = pal.inactive(); + cg.setColor(QColorGroup::Foreground, QColor(red)); + pal.setInactive(cg); + result_label->setPalette(pal); + + } /* if (entered_result == result) */ + + result_label->show(); /* show the result at the end of the task */ + + return; +} + +/** generate the next task and show it to the user */ +void ExerciseFactorize::nextTask() +{ + // change the tooltip of the check button + 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.")); + + // enable prime factor buttons + m_factor2Button->setEnabled(true); + m_factor3Button->setEnabled(true); + m_factor5Button->setEnabled(true); + m_factor7Button->setEnabled(true); + m_factor11Button->setEnabled(true); + m_factor13Button->setEnabled(true); + m_factor17Button->setEnabled(true); + m_factor19Button->setEnabled(true); + + // disable the factor removal button, there are no factors to be removed yet + m_removeLastFactorButton->setEnabled(false); + + result_label->hide(); /* do not show the result at the end of the task */ + m_factorsWidget->hide(); + + /* clear user input */ + m_factorsEntered.clear(); + m_factorsResult.clear(); + m_factorsEnteredEdit->setText(""); + + m_factor2Button->setFocus(); + + /* create a new task */ + QApplication::setOverrideCursor(waitCursor); /* show the sand clock */ + createTask(); + QApplication::restoreOverrideCursor(); /* show the normal cursor */ + + // update the task widget + QString tmp_str; + tmp_str.setNum(m_taskNumber); + m_taskLabel->setText(tmp_str); + + return; +} + +void ExerciseFactorize::addFactor(uint factor) +{ + // add the new entered factor + m_factorsEntered.append(factor); + + // a factor was added, so the user can can remove one again + m_removeLastFactorButton->setEnabled(true); + + // update the line edit + updateEnteredEdit(); + + return; +} + +void ExerciseFactorize::updateEnteredEdit() +{ + // the string to be shown in the entered edit + QString str_output = ""; + QString str_tmp; + + // find the end of the list + uintList::iterator it; + + + for (it = m_factorsEntered.begin(); it != m_factorsEntered.end(); ++it) + { + // convert the factor into a string + str_tmp.setNum(*it); + + // add the factor with a * + if (it == m_factorsEntered.begin()) + { + str_output = str_tmp; + } else { + str_output += " * " + str_tmp; + } + } + + // set the text into the line edit + m_factorsEnteredEdit->setText(str_output); + + return; +} + +/* ------ private slots ------ */ + +void ExerciseFactorize::slotCheckButtonClicked() +{ + if (m_currentState == _CHECK_TASK) + { + // if nothing has been entered by the user, we don't check the result yet + if (m_factorsEntered.count() == 0) + 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(); + } + + // update the line edit + updateEnteredEdit(); + + return; +} + +void ExerciseFactorize::slotFactor2ButtonClicked() +{ + addFactor(2); + + return; +} + +void ExerciseFactorize::slotFactor3ButtonClicked() +{ + addFactor(3); + + return; +} + +void ExerciseFactorize::slotFactor5ButtonClicked() +{ + addFactor(5); + + return; +} + +void ExerciseFactorize::slotFactor7ButtonClicked() +{ + addFactor(7); + + return; +} + +void ExerciseFactorize::slotFactor11ButtonClicked() +{ + addFactor(11); + + return; +} + +void ExerciseFactorize::slotFactor13ButtonClicked() +{ + addFactor(13); + + return; +} + +void ExerciseFactorize::slotFactor17ButtonClicked() +{ + addFactor(17); + + return; +} + +void ExerciseFactorize::slotFactor19ButtonClicked() +{ + addFactor(19); + + return; +} + +void ExerciseFactorize::slotRemoveLastFactorButtonClicked() +{ + if (m_factorsEntered.count() > 0) + { + // find the end of the list + uintList::iterator it = m_factorsEntered.end(); + --it; + + // remove last item + m_factorsEntered.remove(it); + } + + // if the list is empty, we have to disable the delete button + if (m_factorsEntered.count() == 0) + m_removeLastFactorButton->setEnabled(false); + + // update the line edit + updateEnteredEdit(); + + return; +} diff --git a/kbruch/src/exercisefactorize.h b/kbruch/src/exercisefactorize.h new file mode 100644 index 00000000..30cc2d8d --- /dev/null +++ b/kbruch/src/exercisefactorize.h @@ -0,0 +1,162 @@ +/*************************************************************************** + exercisefactorize.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. * + * * + ***************************************************************************/ + +#ifndef EXERCISEFACTORIZE_H +#define EXERCISEFACTORIZE_H + +#define DEBUG + +#ifdef DEBUG +#include <kdebug.h> +#endif + +#include <qvaluelist.h> +#include <qvariant.h> +#include <qwidget.h> + +#include "exercisebase.h" +#include "ratio.h" + +class ResultWidget; +class FactorizedWidget; + +class QVBoxLayout; +class QHBoxLayout; +class QGridLayout; +class QSpacerItem; +class QLabel; +class QLineEdit; +class QPushButton; + +// a list containing uints +typedef QValueList<uint> uintList; + +// set a macro how much numbers are given to factorize +#define numberPossibleTasks 45 + +// set all possible numbers to factorize +const uint possibleTasks[numberPossibleTasks] = {4, 6, 8, 9, 10, 12, 14, 15, 16, +18, 20, 21, 22, 24, 25, 26, 27, 30, 32, 33, 34, 35, 38, 39, 49, 50, 51, 54, 55, +57, 60, 65, 70, 77, 75, 85, 95, 98, 121, 125, 169, 242, 250, 289, 361}; + +/*! Construct the exercise widget to factorize a given number + * + * \author Sebastian Stein + * */ +class ExerciseFactorize : public ExerciseBase +{ + Q_OBJECT + +public: + /** constructor */ + ExerciseFactorize(QWidget * parent = 0, const char * name = 0); + + /** destructor */ + ~ExerciseFactorize(); + + + /** force the creation of a new task */ + void forceNewTask(); + +public slots: + void update(); + +signals: + /** class emits this signal, if the task was solved correctly by the user */ + void signalExerciseSolvedCorrect(); + + /** class emits this signal, if the task was solved not correctly by the user + * */ + void signalExerciseSolvedWrong(); + +private: + short m_currentState; + + uint m_taskNumber; + uintList m_factorsEntered; + uintList m_factorsResult; + + QLabel* m_taskLabel; + QLabel* m_equalSignLabel; + QLineEdit* m_factorsEnteredEdit; + FactorizedWidget* m_factorsWidget; + QLabel* result_label; + + + + // buttons for the different prime factors + QPushButton* m_factor2Button; + QPushButton* m_factor3Button; + QPushButton* m_factor5Button; + QPushButton* m_factor7Button; + QPushButton* m_factor11Button; + QPushButton* m_factor13Button; + QPushButton* m_factor17Button; + QPushButton* m_factor19Button; + + // button to remove the last entered factor + QPushButton* m_removeLastFactorButton; + QPushButton* m_checkButton; + + + // + // the following two methods were added to fix + // bug #116831 (reverse layout in RTL desktops) + // Amit Ramon amit.ramon@kdemail.net + // + + /** create the factor widgets layout */ + QHBoxLayout* createFactorsLayout(); + + /** create the (answer) buttons layout */ + QGridLayout* createButtonsLayout(); + + + void createTask(); + void showResult(); + void nextTask(); + + void addFactor(uint factor); + void updateEnteredEdit(); + +protected: + QVBoxLayout* Form1Layout; + QVBoxLayout* layout9; + QSpacerItem* spacer4; + QHBoxLayout* layout4; + QSpacerItem* spacer1; + QSpacerItem* spacer2; + QVBoxLayout* layout2; + QGridLayout* layout1; + QHBoxLayout* layout7; + QSpacerItem* spacer3; + +private slots: + void slotCheckButtonClicked(); + + void slotFactor2ButtonClicked(); + void slotFactor3ButtonClicked(); + void slotFactor5ButtonClicked(); + void slotFactor7ButtonClicked(); + void slotFactor11ButtonClicked(); + void slotFactor13ButtonClicked(); + void slotFactor17ButtonClicked(); + void slotFactor19ButtonClicked(); + void slotRemoveLastFactorButtonClicked(); +}; + +#endif diff --git a/kbruch/src/factorizedwidget.cpp b/kbruch/src/factorizedwidget.cpp new file mode 100644 index 00000000..6baabc3e --- /dev/null +++ b/kbruch/src/factorizedwidget.cpp @@ -0,0 +1,112 @@ +/*************************************************************************** + factorizedwidget.h - paint a factorization + ------------------- + begin : 2004/07/11 + 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 "factorizedwidget.h" +#include "factorizedwidget.moc" + +/* these includes are needed for Qt support */ +#include <qpainter.h> + +FactorizedWidget::FactorizedWidget(QWidget * parent, const char * name, const uintList para_factors) : + FractionBaseWidget(parent, name), m_factors(para_factors) +{ +#ifdef DEBUG + kdDebug() << "constructor FactorizedWidget" << endl; +#endif +} + +FactorizedWidget::~FactorizedWidget() +{ +#ifdef DEBUG + kdDebug() << "destructor FactorizedWidget" << endl; +#endif +} + +void FactorizedWidget::setFactors(const uintList para_factors) +{ + m_factors = para_factors; + update(); +} + +void FactorizedWidget::paintEvent(QPaintEvent* /* p_paintEvent */) +{ + // our x position, we paint from left to right; + // we don't want to start directly on the border, so add the margin + int x_pos = _MARGIN_X; + + int fontWidth; // to store the width of the last thing painted + + // start the painter + QPainter paint(this); + + // ratios and operation signs are painted with the same font + paint.setFont(m_font); + + // set the pen for painting + QPen pen(Qt::SolidLine); + pen.setWidth(0); + paint.setPen(pen); + + // get the font height; the font height doesn't change while painting + QFontMetrics fm(paint.fontMetrics()); + + // now we can correctly set the height of the widget + setMinimumHeight(fm.lineSpacing()); + setMaximumHeight(fm.lineSpacing()); + + QString tmpStr; + int fontHeight = fm.lineSpacing(); // get the font height + + for (uint tmpInt = 0; tmpInt < m_factors.count(); tmpInt++) + { + // set color for operation sign + pen.setColor(m_colorOperation); + paint.setPen(pen); + + if (tmpInt == 0) + { + fontWidth = fm.width("="); + paint.drawText(x_pos, 0, fontWidth, fontHeight, AlignCenter, "="); + x_pos += fontWidth; + x_pos += _MARGIN_X; + } else { + fontWidth = fm.width("*"); + paint.drawText(x_pos, 0, fontWidth, fontHeight, AlignCenter, "*"); + x_pos += fontWidth; + x_pos += _MARGIN_X; + } + + // set color for number + pen.setColor(m_colorNumber); + paint.setPen(pen); + + tmpStr.setNum(m_factors[tmpInt]); + + fontWidth = fm.width(tmpStr); + paint.drawText(x_pos, 0, fontWidth, fontHeight, AlignCenter, tmpStr); + x_pos += fontWidth; + x_pos += _MARGIN_X; + } + + // stop the painter + paint.end(); + + // the space we needed for painting is the minimum width of the widget + setMinimumWidth(x_pos); + + return; +} diff --git a/kbruch/src/factorizedwidget.h b/kbruch/src/factorizedwidget.h new file mode 100644 index 00000000..2626d445 --- /dev/null +++ b/kbruch/src/factorizedwidget.h @@ -0,0 +1,58 @@ +/*************************************************************************** + factorizedwidget.h - paint a factorization + ------------------- + begin : 2004/07/11 + 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. * + * * + ***************************************************************************/ + +#ifndef FACTORIZEDWIDGET_H +#define FACTORIZEDWIDGET_H + +#ifdef DEBUG +#include <kdebug.h> +#endif + +#include "fractionbasewidget.h" + +#include <qwidget.h> + +// a list containing uints +typedef QValueList<uint> uintList; + +/*! class to paint the factorization of a number + * + * \author Sebastian Stein */ +class FactorizedWidget : public FractionBaseWidget +{ + Q_OBJECT + +public: + /** constructor */ + FactorizedWidget(QWidget * parent, const char * name, const uintList para_factors); + + /** destructor */ + ~FactorizedWidget(); + + /** set the task to be displayed */ + void setFactors(const uintList para_factors); + +private: + + /** the prime factors of the number */ + uintList m_factors; + + /** overrideing the paint event of FractionBaseWidget */ + void paintEvent(QPaintEvent*); +}; + +#endif diff --git a/kbruch/src/fractionbasewidget.cpp b/kbruch/src/fractionbasewidget.cpp new file mode 100644 index 00000000..77ff3056 --- /dev/null +++ b/kbruch/src/fractionbasewidget.cpp @@ -0,0 +1,168 @@ +/*************************************************************************** + fractionbasewidget.cpp - base fraction painting + ------------------- + begin : 2004/05/30 + 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 "fractionbasewidget.h" +#include "fractionbasewidget.moc" + +/* these includes are needed for KDE support */ +#include <kglobalsettings.h> + +/* these includes are needed for Qt support */ +#include <qpainter.h> + +#include "settingsclass.h" + +FractionBaseWidget::FractionBaseWidget(QWidget * parent = 0, const char * name = 0) : + QWidget(parent, name) +{ +#ifdef DEBUG + kdDebug() << "constructor FractionBaseWidget" << endl; +#endif + + // set colors and font used for task displaying + setColorAndFont(); +} + +FractionBaseWidget::~FractionBaseWidget() +{ +#ifdef DEBUG + kdDebug() << "destructor FractionBaseWidget" << endl; +#endif +} + +void FractionBaseWidget::updateAndRepaint() +{ + setColorAndFont(); + update(); +} + +void FractionBaseWidget::paintRatio(QPainter & paint, ratio tmp_ratio, int & x_pos, QFontMetrics & fm, bool show_mixed, bool addMargin) +{ + QPen pen = paint.pen(); // get the pen + int fontHeight = fm.lineSpacing(); // get the font height + + int int_numerator, int_denominator, int_mixed; + QString str_numerator, str_denominator; + QString str_mixed; + + int fontWidth; // to store the width of the last thing painted + int tmp_int; + + // check if we have to show the ratio as mixed number + // 11 1 + // if yes, -- becomes 2 - + // 5 5 + int_numerator = tmp_ratio.numerator(); + int_denominator = tmp_ratio.denominator(); + if (show_mixed == true && QABS(int_numerator) >= QABS(int_denominator)) + { + // calculate the mixed number + int_mixed = int(int_numerator / int_denominator); + + // the negative sign is in front of the mixed number + int_numerator = QABS(int_numerator); + int_denominator = QABS(int_denominator); + + // we have to reduce the numerator by the mixed number * denominator + int_numerator = int_numerator % int_denominator; + + // now we can convert the numbers into strings for painting + str_mixed.setNum(int_mixed); + str_numerator.setNum(int_numerator); + str_denominator.setNum(int_denominator); + + // paint the front part of the mixed number + paintMiddle(paint, str_mixed, x_pos, fm, m_colorNumber); + } else { + + // don't show the ratio as mixed number + str_numerator.setNum(int_numerator); + str_denominator.setNum(int_denominator); + } // if (show_mixed == true && QABS(int_numerator) > QABS(int_denominator)) + + // get the text width of the current ratio + fontWidth = fm.width(str_numerator); + tmp_int = fm.width(str_denominator); + if (tmp_int > fontWidth) + fontWidth = tmp_int; + + // show numerator and denominator in m_colorNumber + pen.setColor(m_colorNumber); + paint.setPen(pen); + + // make sure we don't display something like: 0 + // 7 - + // 3 + if (! (int_numerator == 0 && show_mixed == true) ) + { + // paint the numerator + paint.drawText(x_pos, 0, fontWidth, fontHeight, AlignCenter, str_numerator); + + // paint the fraction line between numerator and denominator + paint.fillRect(x_pos, fontHeight + 4, fontWidth, 2, m_colorLine); + + // paint the denominator + paint.drawText(x_pos, fontHeight + 10, fontWidth, fontHeight, AlignCenter, str_denominator); + + // move the x position to the right by adding the width used for painting + // the ratio and a margin + x_pos += fontWidth; + + if (addMargin == true) + x_pos += _MARGIN_X; + } + + return; +} + +void FractionBaseWidget::paintMiddle(QPainter & paint, const QString& paint_str, int & x_pos, QFontMetrics & fm, QColor color, bool addMargin) +{ + // get the pen, font height and font width + QPen pen = paint.pen(); + int fontHeight = fm.lineSpacing(); + int fontWidth = fm.width(paint_str); + + // paint the string + pen.setColor(color); + paint.setPen(pen); + paint.drawText(x_pos, fontHeight + 5 - fontHeight / 2, fontWidth, fontHeight, AlignCenter, paint_str); + + // move the x position to the right by adding the width used for + // painting the string and a margin + x_pos += fontWidth; + + if (addMargin == true) + x_pos += _MARGIN_X; + + return; +} + +void FractionBaseWidget::setColorAndFont() +{ + /* set colors */ + m_colorNumber = SettingsClass::numberColor(); + m_colorLine = SettingsClass::fractionBarColor(); + m_colorOperation = SettingsClass::operationColor(); + + /* set font */ + m_font = SettingsClass::taskFont(); + + // repaint + update(); + + return; +} diff --git a/kbruch/src/fractionbasewidget.h b/kbruch/src/fractionbasewidget.h new file mode 100644 index 00000000..4472ade3 --- /dev/null +++ b/kbruch/src/fractionbasewidget.h @@ -0,0 +1,74 @@ +/*************************************************************************** + fractionbasewidget.h - base fraction painting + ------------------- + begin : 2004/05/30 + 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. * + * * + ***************************************************************************/ + +#ifndef FRACTIONBASEWIDGET_H +#define FRACTIONBASEWIDGET_H + +/** the space between a ratio and an operation */ +#define _MARGIN_X 5 + +#ifdef DEBUG +#include <kdebug.h> +#endif + +#include "ratio.h" + +#include <qwidget.h> + + +/*! base class for painting fractions + * + * \author Sebastian Stein */ +class FractionBaseWidget : public QWidget +{ + Q_OBJECT + +public: + /** constructor */ + FractionBaseWidget(QWidget * parent, const char * name); + + /** destructor */ + ~FractionBaseWidget(); + + /** updates the widget by first getting the settings and then repainting */ + void updateAndRepaint(); + +protected: + + /* store the different colors */ + QColor m_colorNumber; + QColor m_colorLine; + QColor m_colorOperation; + + /* the font to paint with */ + QFont m_font; + + /** overrideing the paint event of QWidget */ + virtual void paintEvent(QPaintEvent*) = 0; + + /** paints a ratio at the given position */ + void paintRatio(QPainter & paint, ratio tmp_ratio, int & x_pos, QFontMetrics & fm, bool show_mixed, bool addMargin = true); + + /** paints a string in the vertical middle (aligned to the operation signs) */ + void paintMiddle(QPainter & paint, const QString& paint_str, int & x_pos, QFontMetrics & fm, QColor color, bool addMargin = true); + +private: + /** sets the font and color; values taken from settingsclass */ + void setColorAndFont(); +}; + +#endif diff --git a/kbruch/src/hi128-app-kbruch.png b/kbruch/src/hi128-app-kbruch.png Binary files differnew file mode 100644 index 00000000..dae0ed94 --- /dev/null +++ b/kbruch/src/hi128-app-kbruch.png diff --git a/kbruch/src/hi16-app-kbruch.png b/kbruch/src/hi16-app-kbruch.png Binary files differnew file mode 100644 index 00000000..0ddaebc8 --- /dev/null +++ b/kbruch/src/hi16-app-kbruch.png diff --git a/kbruch/src/hi22-app-kbruch.png b/kbruch/src/hi22-app-kbruch.png Binary files differnew file mode 100644 index 00000000..ce1b6d6a --- /dev/null +++ b/kbruch/src/hi22-app-kbruch.png diff --git a/kbruch/src/hi32-app-kbruch.png b/kbruch/src/hi32-app-kbruch.png Binary files differnew file mode 100644 index 00000000..40d9d2ec --- /dev/null +++ b/kbruch/src/hi32-app-kbruch.png diff --git a/kbruch/src/hi48-app-kbruch.png b/kbruch/src/hi48-app-kbruch.png Binary files differnew file mode 100644 index 00000000..2bcfc87d --- /dev/null +++ b/kbruch/src/hi48-app-kbruch.png diff --git a/kbruch/src/hi64-app-kbruch.png b/kbruch/src/hi64-app-kbruch.png Binary files differnew file mode 100644 index 00000000..88d935b2 --- /dev/null +++ b/kbruch/src/hi64-app-kbruch.png diff --git a/kbruch/src/hisc-app-kbruch.svgz b/kbruch/src/hisc-app-kbruch.svgz Binary files differnew file mode 100644 index 00000000..2b550080 --- /dev/null +++ b/kbruch/src/hisc-app-kbruch.svgz diff --git a/kbruch/src/kbruch.cpp b/kbruch/src/kbruch.cpp new file mode 100644 index 00000000..df74101e --- /dev/null +++ b/kbruch/src/kbruch.cpp @@ -0,0 +1,57 @@ +/*************************************************************************** + kbruch.cpp - Main File of KBruch + ------------------- + begin : Tue Nov 27 16:40:42 CET 2001 + copyright : (C) 2001 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 "kbruch.h" + +#include "version.h" + +/* standard C++ library includes */ +#include <time.h> +#include <stdlib.h> + +/* these includes are needed for Qt support */ +#include <kapplication.h> +#include <kcmdlineargs.h> +#include <kaboutdata.h> + +/* the main program */ +int main(int argc, char * argv[]) +{ + // init random generator + srand(time(NULL)); + + /* fill the about data; the common KDE about dialog will show it to the + * user */ + KAboutData aboutData( "kbruch", + description, + KBRUCH_VERSION, + I18N_NOOP("Learn calculating with fractions"), + KAboutData::License_GPL, + "(c) 2002-2005, Sebastian Stein", 0, "http://edu.kde.org/kbruch/", + "seb.kde@hpfsc.de"); + aboutData.addAuthor("Sebastian Stein",0, "seb.kde@hpfsc.de"); + KCmdLineArgs::init( argc, argv, &aboutData ); + + KApplication kbruch; + + MainQtWidget * kbruchApp = new MainQtWidget(); + kbruch.setMainWidget(kbruchApp); + kbruchApp->show(); + + /* lets execute the Qt GUI; it will handle all cmd options which are left */ + return kbruch.exec(); +} diff --git a/kbruch/src/kbruch.desktop b/kbruch/src/kbruch.desktop new file mode 100644 index 00000000..3d8575ab --- /dev/null +++ b/kbruch/src/kbruch.desktop @@ -0,0 +1,128 @@ +# KDE Config File +[Desktop Entry] +Type=Application +Exec=kbruch -caption "%c" %i %m +Icon=kbruch +DocPath=kbruch/index.html +GenericName=Exercise Fractions +GenericName[af]=Oefen Breuke +GenericName[ar]=تمرين على الكسور +GenericName[be]=Практыкаванні з дробамі +GenericName[bg]=Упражнения с дроби +GenericName[bn]=ভগ্নাংশের অংক অনুশীলন করুন +GenericName[bs]=Vježbajte razlomke +GenericName[ca]=Exercita les fraccions +GenericName[cs]=Cvičení se zlomky +GenericName[csb]=Cwiczënczi z kawelków +GenericName[cy]=Ymarfer Ffracsiynnau +GenericName[da]=Øvelsesopgaver med brøker +GenericName[de]=Bruchrechnen üben +GenericName[el]=Εξάσκηση με κλάσματα +GenericName[eo]=Ekzercilo por frakcioj +GenericName[es]=Ejercitar fracciones +GenericName[et]=Harjutused murdudega +GenericName[eu]=Zatiki ariketak +GenericName[fa]=تمرین کسرها +GenericName[fi]=Harjoittele murtolukulaskuja +GenericName[fr]=Exercices pratiques avec des fractions +GenericName[ga]=Cleachtadh le Codáin +GenericName[gl]=Exercicios con Fraccións +GenericName[he]=תרגילי בשברים +GenericName[hi]=अभ्यास अंश +GenericName[hr]=Vježbajte s razlomcima +GenericName[hu]=Törtszámítás-gyakorló +GenericName[is]=Tugabrotaæfingar +GenericName[it]=Esercizi con le frazioni +GenericName[ja]=分数の練習 +GenericName[ka]=ვარჯიში წილადებთან +GenericName[km]=លំហាត់ប្រភាគ +GenericName[mk]=Вежбајте дропки +GenericName[ms]=Latih Pecahan +GenericName[nb]=Brøk-øvelser +GenericName[nds]=Brookreken öven +GenericName[ne]=अभ्यास खण्ड +GenericName[nl]=Breuken oefenen +GenericName[nn]=Brøkøvingar +GenericName[pa]=ਭਿੰਨ ਅਭਿਆਸ +GenericName[pl]=Ćwiczenia z ułamków +GenericName[pt]=Exercícios com Fracções +GenericName[pt_BR]=Exercícios com frações +GenericName[ru]=Упражнения с дробями +GenericName[sk]=Cvičenie zlomkov +GenericName[sl]=Vaje z ulomki +GenericName[sr]=Вежбајте задатке са разломцима +GenericName[sr@Latn]=Vežbajte zadatke sa razlomcima +GenericName[sv]=Övningar med bråk +GenericName[ta]=பின்னங்களில் பயிற்சிகள் +GenericName[tg]=Машқҳо барои ададҳои касрӣ +GenericName[tr]=Parçalara Çalış +GenericName[uk]=Вправи з дробами +GenericName[vi]=Bài tập Phân số +GenericName[zh_CN]=分数练习 +GenericName[zh_TW]=練習分數 +Comment=Practice exercises with fractions +Comment[af]=Doen oefeninge met breuke +Comment[ar]=تمارين عمليّة على الكسور +Comment[be]=Практычныя заняткі з дробамі +Comment[bg]=Практически упражнения с дроби +Comment[bn]=ভগ্নাংশের অংকের অনুশীলনী চর্চা করুন +Comment[bs]=Vježbajte rad sa razlomcima +Comment[ca]=Practica exercicis amb fraccions +Comment[cs]=Praktická cvičení se zlomky +Comment[csb]=Cwiczënczi z kawelków +Comment[cy]=Ymarfer ymarferion efo ffracsiynnau +Comment[da]=Øvelsesopgaver med brøker +Comment[de]=Übungen mit Brüchen +Comment[el]=Εξάσκηση με ασκήσεις κλασμάτων +Comment[eo]=Ekzerci kun frakcioj +Comment[es]=Práctica de ejercicios con fracciones +Comment[et]=Harjutused murdudega +Comment[eu]=Entrenatu zatikidun ariketekin +Comment[fa]=انجام تمرین با کسرها +Comment[fi]=Harjoittele murtolukulaskuja +Comment[fr]=Exercices pratiques avec des fractions +Comment[ga]=Ceachtanna le codáin +Comment[gl]=Exercicios Práticos con Fraccións +Comment[he]=התאמנות בתרגילי שברים +Comment[hi]=अंश के साथ अभ्यास प्रश्नोत्तर +Comment[hr]=Vježbajte zadatke s razlomcima +Comment[hu]=Gyakorlási példák törtszámításhoz +Comment[is]=Gera æfingar með tugabrotum +Comment[it]=Esercizi con le frazioni +Comment[ja]=分数の実践練習 +Comment[ka]=პრაქტიკული სავარჯიშოები წილადებთან +Comment[km]=លំហាត់អនុវត្តប្រភាគ +Comment[lv]=Praktiskie uzdevumi ar daļām +Comment[mk]=Вежбајте задачи со дропки +Comment[ms]=Buat latihan pecahan +Comment[nb]=Treningsøvelser med brøker +Comment[nds]=Brookreken öven +Comment[ne]=खण्डसँग प्रयास अभ्यास +Comment[nl]=Praktische oefeningen met breuken +Comment[nn]=Øvingar i brøkrekning +Comment[pa]=ਭਿੰਨਾਂ ਲਈ ਅਭਿਆਸ ਕਰੋ +Comment[pl]=Ćwiczenia z ułamków +Comment[pt]=Faça exercícios com fracções +Comment[pt_BR]=Exercícios práticos com frações +Comment[ru]=Практические упражнения с дробями +Comment[sk]=Cvičenie operácií so zlomkami +Comment[sl]=Vaje računanja z ulomki +Comment[sr]=Вежбајте задатке са разломцима +Comment[sr@Latn]=Vežbajte zadatke sa razlomcima +Comment[sv]=Övningar med bråk +Comment[ta]=பின்னங்களில் செயல்முறை பயிற்சிகள் +Comment[tg]=Машқҳои таҷрибавӣ барои ададҳои касрӣ +Comment[tr]=Parçalarla alıştırmalara çalış +Comment[uk]=Практичні вправи з дробами +Comment[vi]=Bài luyện tập tính toán với phân số +Comment[zh_CN]=练习分数 +Comment[zh_TW]=練習計算分數題 +Terminal=false +Name=KBruch +Name[bn]=কে-ব্রুচ +Name[hi]=के-ब्रच +Name[ne]=केडीई ब्रच +Name[pa]=ਕੇ-ਭਿੰਨ +Name[sv]=Kbruch +Name[ta]=கேபிரயுச் +Categories=Qt;KDE;Education;Math; diff --git a/kbruch/src/kbruch.h b/kbruch/src/kbruch.h new file mode 100644 index 00000000..e0f5ca0e --- /dev/null +++ b/kbruch/src/kbruch.h @@ -0,0 +1,39 @@ +/*************************************************************************** + kbruch.h - Header File + ------------------- + begin : Tue Nov 27 16:40:42 CET 2001 + copyright : (C) 2001 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. * + * * + ***************************************************************************/ + +/*#define DEBUG*/ + +#ifndef BRUCH_H +#define BRUCH_H + +#include <config.h> + +/* for the I18N_NOOP macro */ +#include <klocale.h> + +#include "task.h" +#include "mainqtwidget.h" + +static const char description[] = + I18N_NOOP("KBruch"); + +class MainQtWidget; +class task; +class ratio; +class primzahl; + +#endif /* ifndef BRUCH_H */ diff --git a/kbruch/src/kbruch.kcfg b/kbruch/src/kbruch.kcfg new file mode 100644 index 00000000..98103a2a --- /dev/null +++ b/kbruch/src/kbruch.kcfg @@ -0,0 +1,79 @@ +<?xml version="1.0" encoding="UTF-8"?> +<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://www.kde.org/standards/kcfg/1.0 + http://www.kde.org/standards/kcfg/1.0/kcfg.xsd" > +<kcfgfile name="kbruchrc"/> + + <group name="General"> + <entry type="Int" key="activeExercise"> + <label>Active exercise.</label> + <whatsthis>Saves the active exercise's type.</whatsthis> + <default>0</default> + </entry> + </group> + + <group name="Task"> + <entry type="Bool" key="addsub"> + <label>Enable Addition/Subtraction</label> + <whatsthis>Enable Addition/Subtraction for task generation.</whatsthis> + <default>true</default> + </entry> + <entry type="Bool" key="muldiv"> + <label>Enable Multiplication/Division</label> + <whatsthis>Enable Multiplication/Division for task generation.</whatsthis> + <default>false</default> + </entry> + <entry type="UInt" key="number_ratios"> + <label>Number of fractions</label> + <whatsthis>Set the number of fractions for task generation.</whatsthis> + <default>2</default> + </entry> + <entry type="UInt" key="max_main_denominator"> + <label>Max. main denominator</label> + <whatsthis>Set the maximum value of the main denominator.</whatsthis> + <default>10</default> + </entry> + </group> + + <group name="Statistics"> + <entry type="Int" key="correct"> + <label>Number of correctly solved tasks</label> + <whatsthis>Number of correctly solved tasks</whatsthis> + <default>0</default> + </entry> + <entry type="Int" key="count"> + <label>Number of solved tasks</label> + <whatsthis>Total number of solved tasks</whatsthis> + <default>0</default> + </entry> + </group> + + <group name="TaskViewer"> + <entry name="numberColor" type="Color"> + <label>Color of the numbers in the task view</label> + <whatsthis>Color of the numbers in the task view</whatsthis> + <default code="true">Qt::darkGreen</default> + </entry> + <entry name="operationColor" type="Color"> + <label>Color of the operation signs in the task view</label> + <whatsthis>Color of the operation signs in the task view</whatsthis> + <default code="true">Qt::blue</default> + </entry> + <entry name="fractionBarColor" type="Color"> + <label>Color of the fraction bars in the task view</label> + <whatsthis>Color of the fraction bars in the task view</whatsthis> + <default code="true">Qt::red</default> + </entry> + <entry type="Font" key="taskFont"> + <label>Font used for the task view</label> + <whatsthis>Font used for the task view</whatsthis> + <default code="true">KGlobalSettings::generalFont()</default> + </entry> + <entry type="Bool" key="showSpecialRatioNotation"> + <label>Enable showing the result also as a mixed number</label> + <whatsthis>Enables/disables showing the result also in the special mixed-number notation.</whatsthis> + <default>true</default> + </entry> + </group> +</kcfg> diff --git a/kbruch/src/kbruchui.rc b/kbruch/src/kbruchui.rc new file mode 100644 index 00000000..e9e8747d --- /dev/null +++ b/kbruch/src/kbruchui.rc @@ -0,0 +1,31 @@ +<!DOCTYPE kpartgui SYSTEM "kpartgui.dtd"> +<kpartgui name="kbruch" version="1"> +<MenuBar> + <Menu noMerge="1" name="file"><text>&Task</text> + <Action name="NewTask"/> + <Merge/> + <Separator/> + <Action name="file_quit"/> + </Menu> +</MenuBar> +<ToolBar noMerge="1" name="mainToolBar" fullWidth="true"> + <text>Main Toolbar</text> + <Action name="NewTask"/> + <Separator/> + + <Action name="NrOfTermsLabelAction"/> + <Action name="NrOfTermsBoxAction"/> + + <Separator/> + + <Action name="MaxMainDenominatorLabelAction"/> + <Action name="MaxMainDenominatorBoxAction"/> + + <Separator/> + + <Action name="OperationLabelAction"/> + <Action name="OperationBoxAction"/> + + <Action name="help"/> +</ToolBar> +</kpartgui> diff --git a/kbruch/src/mainqtwidget.cpp b/kbruch/src/mainqtwidget.cpp new file mode 100644 index 00000000..069a4d83 --- /dev/null +++ b/kbruch/src/mainqtwidget.cpp @@ -0,0 +1,489 @@ +/*************************************************************************** + mainqtwidget.cpp - The main Qt/KDE window + ------------------- + begin : Tue Mar 16 00:00:00 CET 2003 + copyright : (C) 2003-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 "mainqtwidget.h" + +#include <config.h> + +#include <kaccel.h> +#include <kapplication.h> +#include <kaction.h> +#include <kdebug.h> +#include <kiconloader.h> +#include <kjanuswidget.h> +#include <kconfigdialog.h> +#include <klocale.h> + +#include <qsplitter.h> +#include <qlabel.h> +#include <qtooltip.h> +#include <qwhatsthis.h> +#include <qwidget.h> + +#include <math.h> + +#include "exercisecompare.h" +#include "exerciseconvert.h" +#include "exercisefactorize.h" +#include "taskview.h" +#include "taskvieweroptionsbase.h" +#include "statisticsview.h" + +#include "settingsclass.h" + +/* ------ public member functions ------ */ + +MainQtWidget::MainQtWidget() +{ +#ifdef DEBUG + kdDebug() << "constructor MainQtWidget" << endl; +#endif + + // get the settings + readOptions(); + + // creating KActions, used by the kbruchui.rc file + setupActions(); + + createGUI(0L); + + // we split the main view into 2 parts, one for the tasks, one for the + // statistics + QSplitter* splitter = new QSplitter(QSplitter::Horizontal, this,"QSplitter"); + setCentralWidget(splitter); + + // the iconlist, where the user can choose the different exercises + m_exercises = new KJanusWidget(splitter, "KJanusWidget", KJanusWidget::IconList); + QToolTip::add(m_exercises, i18n("Choose another exercise by clicking on an icon.")); + QWhatsThis::add(m_exercises, i18n("Click on the different icons to choose another exercise. The exercises help you to practice different aspects of calculating with fractions.")); + + // create the statistic view + m_statview = new StatisticsView(splitter, "StatisticsView"); + + // add the pages + // + // we have the exercise to solve fraction tasks + QVBox * page = m_exercises->addVBoxPage(i18n("Fraction Task"), "", DesktopIcon("kbruch_exercise_common")); + m_taskview = new TaskView((QWidget *) page, "TaskView", m_addSub, m_mulDiv, m_nrRatios, m_maxMainDenominator); + + // we have the exercise to compare ratios + page = m_exercises->addVBoxPage(i18n("Comparison"), "", DesktopIcon("kbruch_exercise_compare")); + m_exerciseCompare = new ExerciseCompare((QWidget *) page, "ExerciseCompare"); + + // we have the exercise to convert rational numbers into ratios + page = m_exercises->addVBoxPage(i18n("Conversion"), "", DesktopIcon("kbruch_exercise_conversion")); + m_exerciseConvert = new ExerciseConvert((QWidget *) page, "ExerciseConvert"); + + // we have the exercise to factorize a given number into prime factors + page = m_exercises->addVBoxPage(i18n("Factorization"), "", DesktopIcon("kbruch_exercise_factorisation")); + m_exerciseFactorize = new ExerciseFactorize((QWidget *) page, "ExerciseFactorize"); + + splitter->setResizeMode(m_statview, QSplitter::FollowSizeHint); + + // we must change the status of the menubar before another page is shown + QObject::connect(m_exercises, SIGNAL(aboutToShowPage(QWidget *)), this, SLOT(slotAboutToShowPage(QWidget *))); + + // connect signals of the exercises and StatisticView, so that StatisticView + // gets informed about how the user solved a given task (wrong or correct) + QObject::connect(m_taskview, SIGNAL(signalTaskSolvedCorrect()), m_statview, SLOT(addCorrect())); + QObject::connect(m_taskview, SIGNAL(signalTaskSolvedWrong()), m_statview, SLOT(addWrong())); + QObject::connect(m_exerciseCompare, SIGNAL(signalExerciseSolvedCorrect()), m_statview, SLOT(addCorrect())); + QObject::connect(m_exerciseCompare, SIGNAL(signalExerciseSolvedWrong()), m_statview, SLOT(addWrong())); + QObject::connect(m_exerciseConvert, SIGNAL(signalExerciseSolvedCorrect()), m_statview, SLOT(addCorrect())); + QObject::connect(m_exerciseConvert, SIGNAL(signalExerciseSolvedWrong()), m_statview, SLOT(addWrong())); + QObject::connect(m_exerciseFactorize, SIGNAL(signalExerciseSolvedCorrect()), m_statview, SLOT(addCorrect())); + QObject::connect(m_exerciseFactorize, SIGNAL(signalExerciseSolvedWrong()), m_statview, SLOT(addWrong())); + +#if (KDE_VERSION_MINOR>=3) && (KDE_VERSION_MAJOR>=3) +#else + resize(QSize(QMAX(toolBar()->sizeHint().width(), sizeHint().width()), sizeHint().height())); +#endif + // now show the last exercise + m_exercises->showPage(SettingsClass::activeExercise()); + slotAboutToShowPage(m_exercises->pageWidget(m_exercises->activePageIndex())); +} + +MainQtWidget::~MainQtWidget() +{ +} + + +/* ------ private member functions ------ */ + +void MainQtWidget::readOptions() +{ + m_addSub = SettingsClass::addsub(); + m_mulDiv = SettingsClass::muldiv(); + m_nrRatios = SettingsClass::number_ratios(); + m_maxMainDenominator = SettingsClass::max_main_denominator(); + + /* make sure that we can load config files with corrupted values */ + if (m_mulDiv == true && pow(2, m_nrRatios) > m_maxMainDenominator) + { + m_nrRatios = 2; + m_maxMainDenominator = 10; + } +} + +void MainQtWidget::writeOptions() +{ + SettingsClass::setActiveExercise(m_exercises->activePageIndex()); + + // save settings for exercise solve task with fractions + SettingsClass::setAddsub(m_addSub); + SettingsClass::setMuldiv(m_mulDiv); + SettingsClass::setNumber_ratios(m_nrRatios); + SettingsClass::setMax_main_denominator(m_maxMainDenominator); + + SettingsClass::writeConfig(); +} + +void MainQtWidget::setupActions() +{ + // new task action + m_NewTaskAction = new KAction(i18n("&New"), "filenew", KStdAccel::shortcut(KStdAccel::New), + this, SLOT(NewTask()), + actionCollection(), "NewTask"); + + // quit action + KStdAction::quit(kapp, SLOT(quit()), actionCollection()); + + // + KStdAction::preferences(this, SLOT( slotPrefs() ), actionCollection()); + + // a label just describing the Number of terms ComboBox + m_NrOfTermsLabel = new QLabel(i18n("Terms:"), 0, "kde toolbar widget"); + m_NrOfTermsLabelAction = new KWidgetAction(m_NrOfTermsLabel, i18n("Terms:"), ALT+Key_E, + this, SLOT(NrOfTermsBoxSlot()), + actionCollection(), "NrOfTermsLabelAction"); + + // the ComboBox holding possible values for term number + m_NrOfTermsBox = new QComboBox(); + m_NrOfTermsBox->insertItem("2"); + m_NrOfTermsBox->insertItem("3"); + m_NrOfTermsBox->insertItem("4"); + m_NrOfTermsBox->insertItem("5"); + m_NrOfTermsBox->setCurrentItem(m_nrRatios - 2); + QToolTip::add( m_NrOfTermsBox, i18n( "The number of terms you want" ) ); + QWhatsThis::add( m_NrOfTermsBox, i18n( "Choose the number of terms (2, 3, 4 or 5) you want for calculating fractions." ) ); + m_NrOfTermsBoxAction = new KWidgetAction(m_NrOfTermsBox, i18n("Number of Terms"), ALT+Key_E, this, SLOT(NrOfTermsBoxSlot()), actionCollection(), "NrOfTermsBoxAction"); + + // now connect the ComboBox's signal textChanged() to the slot function + QObject::connect(m_NrOfTermsBox, SIGNAL(activated(int)), this, SLOT(NrOfTermsBoxSlot())); + + // a label just describing the max. main denominator ComboBox + m_MaxMainDenominatorLabel = new QLabel(i18n("Max. main denominator:"), 0, "kde toolbar widget"); + m_MaxMainDenominatorLabelAction = new KWidgetAction(m_MaxMainDenominatorLabel, i18n("Max. main denominator:"), ALT+Key_D, + this, SLOT(MaxMainDenominatorBoxSlot()), + actionCollection(), "MaxMainDenominatorLabelAction"); + + // the ComboBox holding possible values for the max. main denominator + m_MaxMainDenominatorBox = new QComboBox(this); + m_MaxMainDenominatorBox->insertItem("10"); + m_MaxMainDenominatorBox->insertItem("20"); + m_MaxMainDenominatorBox->insertItem("30"); + m_MaxMainDenominatorBox->insertItem("50"); + QToolTip::add( m_MaxMainDenominatorBox, i18n( "The maximum number you can have as main denominator" ) ); + QWhatsThis::add( m_MaxMainDenominatorBox, i18n( "Choose the number which will be the maximum for the main denominator: 10, 20, 30, 40 or 50." ) ); + switch (m_maxMainDenominator) + { + case 10 : m_MaxMainDenominatorBox->setCurrentItem(0); + break; + case 20 : m_MaxMainDenominatorBox->setCurrentItem(1); + break; + case 30 : m_MaxMainDenominatorBox->setCurrentItem(2); + break; + case 50 : m_MaxMainDenominatorBox->setCurrentItem(3); + break; + } + m_MaxMainDenominatorBoxAction = new KWidgetAction(m_MaxMainDenominatorBox, i18n("Maximal Main Denominator"), ALT+Key_D, this, SLOT(MaxMainDenominatorBoxSlot()), actionCollection(), "MaxMainDenominatorBoxAction"); + + // now connect the ComboBox's signal textChanged() to the slot function + QObject::connect(m_MaxMainDenominatorBox, SIGNAL(activated(int)), + this, SLOT(MaxMainDenominatorBoxSlot())); + + // a label just describing the operation ComboBox + m_OperationLabel = new QLabel(i18n("Operations:"), 0, "kde toolbar widget"); + m_OperationLabelAction = new KWidgetAction(m_OperationLabel, i18n("Operations:"), ALT+Key_O, + this, SLOT(OperationBoxSlot()), + actionCollection(), "OperationLabelAction"); + + // the ComboBox holding possible combinations for operations + m_OperationBox = new QComboBox(this); + m_OperationBox->insertItem(i18n("Addition/Subtraction")); + m_OperationBox->insertItem(i18n("Multiplication/Division")); + m_OperationBox->insertItem(i18n("All Operations Mixed")); + if (m_addSub == true && m_mulDiv == false) + { + m_OperationBox->setCurrentItem(0); + } else if (m_addSub == false && m_mulDiv == true) { + m_OperationBox->setCurrentItem(1); + } else if (m_addSub == true && m_mulDiv == true) { + m_OperationBox->setCurrentItem(2); + } + QToolTip::add( m_OperationBox, i18n( "The operations you want" ) ); + QWhatsThis::add( m_OperationBox, i18n( "Choose the type of operations you want for calculating fractions: Addition/Substraction, Multiplication/Division or All Operations Mixed. If you choose All Operations Mixed, the program will randomly choose addition, substraction, multiplication and/or division." ) ); + m_OperationBoxAction = new KWidgetAction(m_OperationBox, i18n("Operations:"), ALT+Key_O, this, SLOT(OperationBoxSlot()), actionCollection(), "OperationBoxAction"); + + // now connect the ComboBox's signal textChanged() to the slot function + QObject::connect(m_OperationBox, SIGNAL(activated(int)), this, SLOT(OperationBoxSlot())); + +#if (KDE_VERSION_MINOR>=3) && (KDE_VERSION_MAJOR>=3) + if (!initialGeometrySet()) + resize( QSize(725, 330).expandedTo(minimumSizeHint())); + setupGUI(ToolBar | Keys | StatusBar | Create); + setAutoSaveSettings(); +#endif +} + + +/* ------ private slots ------ */ + +void MainQtWidget::NewTask() +{ +#ifdef DEBUG + kdDebug() << "NewTask MainQtWidget" << endl; + kdDebug() << "pageIndex(m_taskview): " << m_exercises->pageIndex(m_taskview) << endl; + kdDebug() << "pageIndex(m_exerciseCompare): " << m_exercises->pageIndex(m_exerciseCompare) << endl; + kdDebug() << "pageIndex(m_exerciseConvert): " << m_exercises->pageIndex(m_exerciseConvert) << endl; +#endif + + // check which page should generate a new task + switch (m_exercises->activePageIndex()) + { + case 0 : + m_taskview->forceNewTask(); + break; + case 1 : + m_exerciseCompare->forceNewTask(); + break; + case 2 : + m_exerciseConvert->forceNewTask(); + break; + case 3 : + m_exerciseFactorize->forceNewTask(); + break; + } + +/* this doesn't seem to work, because pageIndex always returns 0 + + if (m_exercises->activePageIndex() == m_exercises->pageIndex(m_taskview)) + { + m_taskview->forceNewTask(); + return; + } + if (m_exercises->activePageIndex() == m_exercises->pageIndex(m_exerciseCompare)) + { + m_exerciseCompare->forceNewTask(); + return; + } +*/ + +/* this even do not compile, but I don't know why + + switch (m_exercises->activePageIndex()) + { + case m_exercises->pageIndex(m_taskview): + break; + case m_exercises->pageIndex(m_exerciseCompare): + m_exerciseCompare->forceNewTask(); + break; + } +*/ + + return; +} + +void MainQtWidget::NrOfTermsBoxSlot() +{ +#ifdef DEBUG + kdDebug() << "MainQtWidget::NrOfTermsBoxSlot()" << endl; +#endif + QString curr_nr = m_NrOfTermsBox->currentText(); + m_MaxMainDenominatorBox->clear(); + + if (m_mulDiv == true) + { + if (curr_nr == "2") + { + m_MaxMainDenominatorBox->insertItem("10"); + m_MaxMainDenominatorBox->insertItem("20"); + m_MaxMainDenominatorBox->insertItem("30"); + m_MaxMainDenominatorBox->insertItem("50"); + m_nrRatios = 2; + m_maxMainDenominator = 10; + } else if (curr_nr == "3") { + m_MaxMainDenominatorBox->insertItem("20"); + m_MaxMainDenominatorBox->insertItem("30"); + m_MaxMainDenominatorBox->insertItem("50"); + m_nrRatios = 3; + m_maxMainDenominator = 20; + } else if (curr_nr == "4") { + m_MaxMainDenominatorBox->insertItem("20"); + m_MaxMainDenominatorBox->insertItem("30"); + m_MaxMainDenominatorBox->insertItem("50"); + m_nrRatios = 4; + m_maxMainDenominator = 20; + } else { + m_MaxMainDenominatorBox->insertItem("50"); + m_nrRatios = 5; + m_maxMainDenominator = 50; + } + m_MaxMainDenominatorBox->setCurrentItem(0); + } else { + /* no multiplication or division allowed, so we add the default values */ + m_MaxMainDenominatorBox->insertItem("10"); + m_MaxMainDenominatorBox->insertItem("20"); + m_MaxMainDenominatorBox->insertItem("30"); + m_MaxMainDenominatorBox->insertItem("50"); + if (curr_nr == "2") + m_nrRatios = 2; + else if (curr_nr == "3") + m_nrRatios = 3; + else if (curr_nr == "4") + m_nrRatios = 4; + else + m_nrRatios = 5; + } // if (m_mulDiv == true) + + // set the new task parameters + (void) m_taskview->setTaskParameters(m_addSub, m_mulDiv, m_nrRatios, m_maxMainDenominator); +} + +void MainQtWidget::MaxMainDenominatorBoxSlot() +{ +#ifdef DEBUG + kdDebug() << "MainQtWidget::MaxMainDenominatorBoxSlot()" << endl; +#endif + + // get the max. size from the ComboBox, convert it to a number and store + // it in the private member + QString curr_md = m_MaxMainDenominatorBox->currentText(); + m_maxMainDenominator = curr_md.toUInt(); + + // set the new task parameters + (void) m_taskview->setTaskParameters(m_addSub, m_mulDiv, m_nrRatios, m_maxMainDenominator); +} + +void MainQtWidget::OperationBoxSlot() +{ +#ifdef DEBUG + kdDebug() << "MainQtWidget::OperationBoxSlot()" << endl; +#endif + + int index = m_OperationBox->currentItem(); // get selected item + + // user has selected the operations for the next task, so store it in the + // private members + if (index == 0) + { + m_addSub = true; + m_mulDiv = false; + + /* set the number of terms box and max main denominator box correctly */ + NrOfTermsBoxSlot(); + } else if (index == 1) { + m_addSub = false; + m_mulDiv = true; + + /* set the number of terms box and max main denominator box correctly */ + NrOfTermsBoxSlot(); + } else { + m_addSub = true; + m_mulDiv = true; + + /* set the number of terms box and max main denominator box correctly */ + NrOfTermsBoxSlot(); + } + + // set the new task parameters + (void) m_taskview->setTaskParameters(m_addSub, m_mulDiv, m_nrRatios, m_maxMainDenominator); +} + +void MainQtWidget::slotPrefs() +{ + // do not show dialog twice + if (KConfigDialog::showDialog("settings")) + return; + + //KConfigDialog didn't find an instance of this dialog, so lets create it : + KConfigDialog* configDialog = new KConfigDialog( this, "settings", SettingsClass::self() ); + + + TaskViewerOptionsBase * taskViewerOptions = new TaskViewerOptionsBase(0, "TaskViewerOptionsBase"); + configDialog->addPage(taskViewerOptions, i18n("Task Viewer Settings"), "colorize"); + + // User edited the configuration - update your local copies of the + // configuration data + connect(configDialog, SIGNAL(settingsChanged()), this, SLOT(slotApplySettings()) ); + + configDialog->show(); +/* + SettingsDialog * dlg = new SettingsDialog(this); + connect(dlg, SIGNAL(configChanged()), this, SLOT(slotApplySettings())); + + dlg->exec(); + + delete dlg; + dlg = NULL; + +*/ + return; +} + +void MainQtWidget::slotApplySettings() +{ + // update the task view + m_taskview->update(); + m_exerciseCompare->update(); + m_exerciseConvert->update(); + m_exerciseFactorize->update(); + + return; +} + +void MainQtWidget::slotAboutToShowPage(QWidget * page) +{ +#ifdef DEBUG + kdDebug() << "slotAboutToShowPage MainQtWidget" << endl; + kdDebug() << "pageIndex(m_taskview): " << m_exercises->pageIndex(m_taskview) << endl; + kdDebug() << "pageIndex(m_exerciseCompare): " << m_exercises->pageIndex(m_exerciseCompare) << endl; + kdDebug() << "pageIndex(m_exerciseConvert): " << m_exercises->pageIndex(m_exerciseConvert) << endl; +#endif + + // check which page to show + if (m_exercises->pageIndex(page) == m_exercises->pageIndex(m_taskview)) + { + // exercise solve task with fraction (taskview.h) + m_NrOfTermsBox->setEnabled(true); + m_MaxMainDenominatorBox->setEnabled(true); + m_OperationBox->setEnabled(true); + } else { + m_NrOfTermsBox->setEnabled(false); + m_MaxMainDenominatorBox->setEnabled(false); + m_OperationBox->setEnabled(false); + } + + return; +} + +bool MainQtWidget::queryExit() +{ + writeOptions(); + return true; +} + +#include "mainqtwidget.moc" diff --git a/kbruch/src/mainqtwidget.h b/kbruch/src/mainqtwidget.h new file mode 100644 index 00000000..33c1f2e5 --- /dev/null +++ b/kbruch/src/mainqtwidget.h @@ -0,0 +1,145 @@ +/*************************************************************************** + mainqtwidget.h - The main Qt/KDE window + ------------------- + begin : Tue Mar 16 00:00:00 CET 2003 + copyright : (C) 2003-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. * + * * + ***************************************************************************/ +#ifndef MAINQTWIDGET_H +#define MAINQTWIDGET_H + +#include <kmainwindow.h> + + +class KJanusWidget; +class KWidgetAction; + +class QLabel; + +class ExerciseCompare; +class ExerciseConvert; +class ExerciseFactorize; +class StatisticsView; +class TaskView; + +/** Constructs the main window and presents the user interface. + * The window is seperated into 2 sections. In the left section is the + * statistic view and in the right section the task view. + * \author Sebastian Stein + * \author Eva Brucherseifer + **/ +class MainQtWidget : public KMainWindow +{ + Q_OBJECT + + public: + /** constructor */ + MainQtWidget(); + + /** destructor */ + ~MainQtWidget(); + + private: + /** read the config file */ + void readOptions(); + + /** read the config file */ + void writeOptions(); + + /** pointing to the statistics view */ + StatisticsView * m_statview; + + /** the iconlist for the different exercises */ + KJanusWidget * m_exercises; + + /** pointing to the exercise solving a task with fractions; added as page + * to the iconlist */ + TaskView * m_taskview; + + /** pointing to the exercise comparing ratios; added as page to the + * iconlist */ + ExerciseCompare * m_exerciseCompare; + + /** pointing to the exercise convert rational number; added as page to the + * iconlist */ + ExerciseConvert * m_exerciseConvert; + + /** pointing to the exercise factorize a given number; added as page to + * the iconlist */ + ExerciseFactorize * m_exerciseFactorize; + + bool m_addSub; + bool m_mulDiv; + unsigned int m_nrRatios; + unsigned int m_maxMainDenominator; + + void setupActions(); + + QComboBox * m_NrOfTermsBox; + QLabel * m_NrOfTermsLabel; + KWidgetAction * m_NrOfTermsBoxAction; + KWidgetAction * m_NrOfTermsLabelAction; + + QComboBox * m_MaxMainDenominatorBox; + QLabel * m_MaxMainDenominatorLabel; + KWidgetAction * m_MaxMainDenominatorBoxAction; + KWidgetAction * m_MaxMainDenominatorLabelAction; + + QComboBox * m_OperationBox; + QLabel * m_OperationLabel; + KWidgetAction * m_OperationBoxAction; + KWidgetAction * m_OperationLabelAction; + + KAction * m_NewTaskAction; + + private slots: + /** + * called to force generation of a new task + */ + void NewTask(); + /** + * called when the user changes the number of terms in the ComboBox + */ + void NrOfTermsBoxSlot(); + /** + *called, when the user changes the max. size of the main denominator in + * the ComboBox + */ + void MaxMainDenominatorBoxSlot(); + /** + * called, when the user changes the wished task's operations + */ + void OperationBoxSlot(); + + /** + * calls the settings dialog + */ + void slotPrefs(); + + /** + * makes sure, all parts of the UI update to new settings + */ + void slotApplySettings(); + + /** + * called just before another page is shown + */ + void slotAboutToShowPage(QWidget * page); + + protected: + /** Function is called when user calls termination. + * Used to save the current statistics and settings before exiting. + **/ + bool queryExit(); +}; + +#endif // MainQtWidget diff --git a/kbruch/src/primenumber.cpp b/kbruch/src/primenumber.cpp new file mode 100644 index 00000000..7eb3c700 --- /dev/null +++ b/kbruch/src/primenumber.cpp @@ -0,0 +1,202 @@ +/*************************************************************************** + primenumber.cpp - source code of class primenumber + ------------------- + begin : Tue Nov 27 16:40:42 CET 2001 + copyright : (C) 2001 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 <kdebug.h> +#include "primenumber.h" + +/* ----- the global prime number vector ----- */ +UnsignedIntArray primenumber::prim_vector; + +/* ----- public member functions ----- */ + +/* constructor for class primenumber */ +primenumber::primenumber() +{ + /* if the vector is empty, we will add the first 2 prime numbers */ + if (prim_vector.empty()) + { +#ifdef DEBUG + kdDebug() << "prim_vector is still empty" << endl; +#endif + + prim_vector.push_back(2); + prim_vector.push_back(3); + } + current_pos = prim_vector.begin(); +#ifdef DEBUG + kdDebug() << "constructor primenumber" << endl; +#endif +} + +/* destructor for class primenumber */ +primenumber::~primenumber() +{ +#ifdef DEBUG + kdDebug() << "destructor primenumber" << endl; +#endif +} + +/* check, if the given number is a prime number; + * return 0 if no, 1 if yes */ +short primenumber::isPrimeNumber(uint number) +{ +#ifdef DEBUG + kdDebug() << "primenumber::isPrimeNumber(" << number << ")" << endl; +#endif + /* 0 is not a prime number */ + if (number == 0) + return 0; + + /* jump to the start of the vector */ + move_first(); + + /* check, if we can find a divisor */ + for (unsigned int dummy = get_first(); dummy < number; dummy = get_next()) + { + if ((number % dummy == 0) && (dummy != number)) + return 0; // the number is not a prime number + + /* we found a prime number, because we only have to test the given + * number against all known prime numbers smaller square root of the + * number */ + if (dummy * dummy > number) + return 1; + } + + return 1; // the given number is a prime number +} + +/* returns next prime number */ +unsigned int primenumber::get_next() +{ + /* if we do not know the next number, we have to find it first */ + if (current_pos == prim_vector.end() || + ++current_pos == prim_vector.end()) + { + /* we do not know the next prime number, so we have to find it */ + find_next(); + move_last(); + return get_last(); /* return it */ + } + else + { + /* we know the next prime number, set the pointer on it */ + return *current_pos; /* return it */ + } +} + +/* returns the first prime number of the vector */ +unsigned int primenumber::get_first() const +{ + return *prim_vector.begin(); +} + +/* returns the last prime number in the vector */ +unsigned int primenumber::get_last() const +{ + return *(prim_vector.end() - 1); +} + +/* returns currently selected prime number */ +unsigned int primenumber::get_current() const +{ + if (current_pos == prim_vector.end() + 1) + return get_last(); + return *current_pos; +} + +/* set current_pos to the first prime number */ +void primenumber::move_first() +{ + current_pos = prim_vector.begin(); +} + +/* set current_pos to the last prime number */ +void primenumber::move_last() +{ + current_pos = prim_vector.end() - 1; +} + +/* move to the next prime number */ +void primenumber::move_forward() +{ + /* if we are at the end of prim_vector, we have to find a new number */ + if (current_pos == prim_vector.end() || + ++current_pos == prim_vector.end()) + { + find_next(); + move_last(); + } +} + +/* move one prime number back */ +void primenumber::move_back() +{ + /* current_pos must be at least pointing to the first element + * of our vector after this function */ + if (current_pos != prim_vector.begin()) + --current_pos; +} + +/* displays the whole prim_vector on stdout; just for debugging */ +void primenumber::display_all() +{ + unsigned int dummy = 0; // count the numbers + + /* looping through the complete vector */ + for (current_pos = prim_vector.begin(); current_pos != prim_vector.end(); + current_pos++, dummy++) + kdDebug() << dummy << ": " << *current_pos << endl; + + current_pos = prim_vector.end() - 1; +} + +/* ----- private member functions ----- */ + +/* finds next prime number and adds it to the vector */ +void primenumber::find_next() +{ + /* our new prime number, must be bigger then the last one */ + unsigned int new_prim = *(prim_vector.end() - 1); + + do + { + /* new prime number must be bigger as biggest known one */ + new_prim += 2; + /* loop as long as we find a divisor for the new number */ + for (current_pos = prim_vector.begin(); current_pos != prim_vector.end(); + current_pos++) + if ((new_prim % *current_pos == 0) || (new_prim < *current_pos)) + break; + + /* if we tried all known numbers and found no divisor, well, + * we are happy to have found a new prime number + * + * we found a prime number, because we only have to test the given + * number against all known prime numbers smaller square root of the + * number */ + if ((current_pos == prim_vector.end()) + || (*current_pos * *current_pos > new_prim)) + break; + } + while(1); + + /* add the new prime number to the vector */ + prim_vector.push_back(new_prim); + + current_pos = prim_vector.end() - 1; +} diff --git a/kbruch/src/primenumber.h b/kbruch/src/primenumber.h new file mode 100644 index 00000000..8f135b26 --- /dev/null +++ b/kbruch/src/primenumber.h @@ -0,0 +1,83 @@ +/*************************************************************************** + primenumber.h - class primenumber + ------------------- + begin : Tue Nov 27 16:40:42 CET 2001 + copyright : (C) 2001 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. * + * * + ***************************************************************************/ + +#ifndef PRIMZAHL_H +#define PRIMZAHL_H + +#include <qvaluevector.h> + +typedef QValueVector<uint> UnsignedIntArray; + +/** Class to handle prime numbers. + * The prime numbers are stored in a static vector, so that different instances + * can use them. Each time a higher prime number is needed, the new found prime + * number is stored in the vector. To check if a given number is a prime number + * this vector is scanned and if needed new prime numbers are generated. This + * algorithm should reduce calculation time and speed up every program using + * this prime number class. + * \author Sebastian Stein */ +class primenumber +{ +public: + /** constructor */ + primenumber(); + + /** destructor */ + ~primenumber(); + + /** returns wether the given number is a prime number */ + short isPrimeNumber(uint number); + + /** returns the next prime number */ + unsigned int get_next(); + + /** returns the first prime number */ + unsigned int get_first() const; + + /** return the last known prime number */ + unsigned int get_last() const; + + /** returns the current prime number */ + unsigned int get_current() const; + + /** moves the internal pointer to the first prime number */ + void move_first(); + + /** moves the internal pointer to the last prime number */ + void move_last(); + + /** moves the internal pointer to the next prime number */ + void move_forward(); + + /** moves the internal pointer to the previous prime number */ + void move_back(); + + /** Displays all known prime numbers, mainly used for debugging. */ + void display_all(); +private: + /** a vector storing all known prime numbers, access for all objects; + * we are using the vector<T> template; so we do not have to think + * about dynamic mem manipulation */ + static UnsignedIntArray prim_vector; + + /** current selected prime number */ + UnsignedIntArray::iterator current_pos; + + /** finds next prime number and adds it to the vector */ + void find_next(); +}; +#endif diff --git a/kbruch/src/ratio.cpp b/kbruch/src/ratio.cpp new file mode 100644 index 00000000..289e79f9 --- /dev/null +++ b/kbruch/src/ratio.cpp @@ -0,0 +1,368 @@ +/*************************************************************************** + ratio.cpp - source code of class ratio + ------------------- + begin : Tue Nov 27 16:40:42 CET 2001 + copyright : (C) 2001-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 <kdebug.h> + +#include "ratio.h" +#include "primenumber.h" + +/* ----- public member functions ----- */ + +/* constructor */ +ratio::ratio(int pnumerator, int pdenominator):m_numerator(pnumerator), m_denominator(pdenominator) +{ +#ifdef DEBUG + kdDebug() << "constructor ratio" << endl; +#endif + + // denominator is never allowed to be 0 + if (!m_denominator) + m_denominator = 1; + + // reduce the new ratio + reduce(); +} + +/* copy constructor */ +ratio::ratio(const ratio & copy_ratio) +{ +#ifdef DEBUG + kdDebug() << "copy constructor ratio" << endl; +#endif + + setNumerator(copy_ratio.numerator(), false); + setDenominator(copy_ratio.denominator(), false); +} + +/* destructor */ +ratio::~ratio() +{ +#ifdef DEBUG + kdDebug() << "destructor ratio" << endl; +#endif +} + +/* displays the ratio on stdout; just for debugging */ +QTextStream & ratio::display(QTextStream & str) const +{ + int tmp_width = str.width(); + str << qSetW(5) << " "; + str << qSetW(5) << m_numerator << endl; + str << qSetW(tmp_width) << " "; + str << " ----- " << endl; + str << qSetW(tmp_width) << " "; + return str << qSetW(5) << m_denominator; +} + +/* return the numerator */ +int ratio::numerator() const +{ + return m_numerator; +} + +/* return the denominator */ +int ratio::denominator() const +{ + return m_denominator; +} + +/* set the numerator */ +void ratio::setNumerator(int pnumerator, bool reduce_it) +{ + m_numerator = pnumerator; + + // check, if we have to reduce the ratio + if (reduce_it == true) + reduce(); + + return; +} + +/* set the denominator */ +void ratio::setDenominator(int pdenominator, bool reduce_it) +{ + /* denominator is not allowed to be 0 */ + if (!pdenominator) + pdenominator = 1; + + m_denominator = pdenominator; + + // check, if we have to reduce the ratio + if (reduce_it == true) + reduce(); + + return; +} + +/* add a ratio to a ratio like c = a + b */ +ratio ratio::operator+(ratio addend) +{ + // this object will be returned as the sum + ratio sum(0, 1); + + // calculate and set the numerator without reducing + sum.setNumerator(m_numerator * addend.denominator() + + addend.numerator() * m_denominator, false); + + // calculate and set the denominator without reducing + sum.setDenominator(m_denominator * addend.denominator(), false); + + // reduce the sum + sum.reduce(); + + return sum; +} + +/* sub a ratio from a ratio like c = a - b */ +ratio ratio::operator-(ratio subtrahend) +{ + /* this object will be returned as the difference */ + ratio diff(0, 1); + + /* change the sign of the subtrahend, so we can handle it as an addition */ + subtrahend.change_sign(); + diff = operator+(subtrahend); + + /* we have to change the sign back, so everything will be as before */ + subtrahend.change_sign(); + + /* return the difference */ + return diff; +} + +/* mul a ratio with a ratio like c = a * b */ +ratio ratio::operator*(ratio factor) +{ + // this object will be returned as the product + ratio product(0, 1); + + // calculate and set numerator and denominator without reducing + product.setNumerator(m_numerator * factor.numerator(), false); + product.setDenominator(m_denominator * factor.denominator(), false); + + // reduce the product + product.reduce(); + + return product; +} + +/* div a ratio with a ratio like c = a / b */ +ratio ratio::operator/(ratio divisor) +{ + /* this object will be returned as the quotient */ + ratio quotient(0, 1); + + /* exchange numerator and denominator so we can handle as multiplication */ + divisor.reziproc(); + quotient = operator*(divisor); + + /* go back to the original state */ + divisor.reziproc(); + + return quotient; +} + +/* we need this for initialization during a function prototyp; + * ratio fraction = 0 */ +ratio ratio::operator=(int dummy) +{ + m_numerator = dummy; + m_denominator = 1; + + return *this; +} + +/* check, if the ratios are equivalent; -1/2 == 1/-2 -> TRUE */ +bool ratio::operator==(ratio right) +{ + signed short orig_sign = 1, right_sign = 1; + + /* we do not check the presign at this point */ + if (QABS(m_numerator) != QABS(right.numerator())) + return false; + if (QABS(m_denominator) != QABS(right.denominator())) + return false; + + /* check if the signs of the ratios are equivalent */ + if (m_numerator < 0) + orig_sign = -1; + if (m_denominator < 0) + orig_sign *= -1; + if (right.numerator() < 0) + right_sign = -1; + if (right.denominator() < 0) + right_sign *= -1; + + if (orig_sign != right_sign) + return false; + + return true; +} + +bool ratio::operator<(ratio right) +{ + signed short sign = 1; + ratio tmp_ratio = ratio(m_numerator, m_denominator) - right; + + // check for this == right + if (tmp_ratio == ratio(0, 1)) + return false; + + // get the presign of the diff + if (tmp_ratio.numerator() < 0) + sign = -1; + if (tmp_ratio.denominator() < 0) + sign *= -1; + + // if the diff is negative, this is smaller then right + if (sign > 0) + { + return false; + } else { + return true; + } +} + +bool ratio::operator>(ratio right) +{ + signed short sign = 1; + ratio tmp_ratio = ratio(m_numerator, m_denominator) - right; + + // check for this == right + if (tmp_ratio == ratio(0, 1)) + return false; + + // get the presign of the diff + if (tmp_ratio.numerator() < 0) + sign = -1; + if (tmp_ratio.denominator() < 0) + sign *= -1; + + // if the diff is positive, this is smaller then right + if (sign < 0) + { + return false; + } else { + return true; + } +} + +/* ----- private member functions ----- */ + +/* reduce the ratio */ +void ratio::reduce() +{ + /* we try prime numbers as divisors; I think it is the fastet way to do */ + primenumber number; + short sign_numerator = 0, sign_denominator = 0; + + /* make the whole ratio positive; save the signs; it is easier to reduce + * the ratio, if it is positive */ + if (m_numerator < 0) // save numerator sign + { + sign_numerator = 1; + m_numerator *= -1; + } + if (m_denominator < 0) // save denominator sign + { + sign_denominator = 1; + m_denominator *= -1; + } + + for (int divisor = number.get_first(); + divisor <= m_numerator && divisor <= m_denominator; divisor = number.get_next()) + { + if (divisor == 0) + { +#ifdef DEBUG + kdDebug() << "ratio::reduce() -> divisor == 0 !!!" << endl; + kdDebug() << "m_numerator: " << m_numerator << endl; + kdDebug() << "m_denominator: " << m_denominator << endl; + // cin.get(); +#endif + /* so that the application does not crash with a floating + * point exception; the error should not appear, but in some + * cases it does and I do not know why */ + continue; + } + + /* is the prime number a divisor of numerator and denominator? */ + if ((m_numerator % divisor == 0) && (m_denominator % divisor == 0)) + { + /* reduce the ratio by the divisor */ + m_numerator /= divisor; + m_denominator /= divisor; + + /* we have to go recursive, if the 2 is a divisor, because there + * is no way to step one number before 2 -> there is no prime + * number smaller than 2 */ + if (divisor == 2) + reduce(); + else + number.move_back(); // the prime number could be a divisor again + } // if ((zaehler % divisor == 0) && (nenner % divisor == 0)) + } // for (unsigned int divisor = number.get_first(); ... + + /* restore the correct signs */ + if (sign_numerator) + m_numerator *= -1; + if (sign_denominator) + m_denominator *= -1; + if (m_numerator == 0) + m_denominator = 1; + + return; +} + +/* exchange numerator and denominator */ +void ratio::reziproc() +{ + int temp = m_numerator; + m_numerator = m_denominator; + m_denominator = temp; + + return; +} + + +/* ------ private member functions ------ */ + +/* change the sign of the ratio; ratio = ratio * -1 */ +void ratio::change_sign() +{ + /* this would be enough to change the sign of the ratio */ + m_numerator *= -1; + + /* if numerator and denominator both are negative, make them positive; + * if denominator is negative and numerator positive, exchange the sign */ + if ((m_numerator < 0 && m_denominator < 0) || (m_numerator > 0 && m_denominator < 0)) + { + m_numerator *= -1; + m_denominator *= -1; + } + + return; +} + + +/* ------ some prototyps of non class functions ------ */ + +// it is possible to stram ratio_object +QTextStream & operator<<(QTextStream & str, const ratio & pratio) +{ + return pratio.display(str); +} diff --git a/kbruch/src/ratio.h b/kbruch/src/ratio.h new file mode 100644 index 00000000..3e3ca44a --- /dev/null +++ b/kbruch/src/ratio.h @@ -0,0 +1,102 @@ +/*************************************************************************** + ratio.h - class ratio + ------------------- + begin : Tue Nov 27 16:40:42 CET 2001 + copyright : (C) 2001-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. * + * * + ***************************************************************************/ + +#ifndef RATIO_H +#define RATIO_H + +#include <qtextstream.h> + +/** Represents a ratio + * This class represents 1 ratio. There are several functions provided to + * modify the numerator and denominator. It is also possible to calculate with + * objects of the class ratio. Overloaded operation functions are provided for + * this task. + * \author Sebastian Stein */ +class ratio +{ +public: + /** constructor */ + ratio(int pnumerator = 0, int pdenominator = 1); + + /** copy constructor */ + ratio(const ratio & copy_ratio); + + /** destructor */ + ~ratio(); + + /** returns the ratio as QTextStream object */ + QTextStream & display(QTextStream & str) const; + + /** returns the numerator */ + int numerator() const; + + /** returns the denominator */ + int denominator() const; + + /** set numerator and reduce the ratio */ + void setNumerator(int pnumerator = 0, bool reduce = true); + + /** set denominator and reduce the ratio */ + void setDenominator(int pdenominator = 1, bool reduce = true); + + /** operator overloading for: c = object + summand */ + ratio operator+(ratio addend); + + /** operator overloading for: c = object - subtrahend */ + ratio operator-(ratio subtrahend); + + /** operator overloading for: c = object * factor */ + ratio operator*(ratio factor); + + /** operator overloading for: c = object / divisor */ + ratio operator/(ratio divisor); + + /** set numerator with dummy and denominator = 1 */ + ratio operator=(int dummy); + + /** compares the current ratio with a given one */ + bool operator==(ratio right); + + /** compares the current ratio with a given one */ + bool operator<(ratio right); + + /** compares the current ratio with a given one */ + bool operator>(ratio right); + + /** exchange numerator and denominator */ + void reziproc(); + + /** reduce the ratio */ + void reduce(); +private: + /** numerator */ + int m_numerator; + + /** denominator */ + int m_denominator; + + /** change sign of the ratio */ + void change_sign(); +} +; + +/* ------ some prototyps of non class functions ------ */ + +/** it is possible to code: cout << ratio_object << endl; */ +QTextStream & operator<<(QTextStream & str, const ratio & pratio); + +#endif diff --git a/kbruch/src/rationalwidget.cpp b/kbruch/src/rationalwidget.cpp new file mode 100644 index 00000000..7184cafd --- /dev/null +++ b/kbruch/src/rationalwidget.cpp @@ -0,0 +1,114 @@ +/*************************************************************************** + rationalwidget.h - paint a rational number + ------------------- + 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 "rationalwidget.h" +#include "rationalwidget.moc" + +/* these includes are needed for Qt support */ +#include <qpainter.h> +#include <qstring.h> + +RationalWidget::RationalWidget(QWidget * parent, const char * name, const QString pnumber, const uint pperiodStart, const uint pperiodLength): + FractionBaseWidget(parent, name), m_number(pnumber), + m_periodStart(pperiodStart), m_periodLength(pperiodLength) +{ +#ifdef DEBUG + kdDebug() << "constructor RationalWidget" << endl; +#endif +} + +RationalWidget::~RationalWidget() +{ +#ifdef DEBUG + kdDebug() << "destructor RationalWidget" << endl; +#endif +} + +void RationalWidget::setRational(const QString pnumber, const uint pperiodStart, const uint pperiodLength) +{ + m_number = pnumber; + m_periodStart = pperiodStart; + m_periodLength = pperiodLength; + + update(); + + return; +} + +void RationalWidget::paintEvent(QPaintEvent* /* p_paintEvent */) +{ + // our x position, we paint from left to right; + // we don't want to start directly on the border, so add the margin + int x_pos = _MARGIN_X; + int x_startPos = _MARGIN_X; + bool tmp_painting = false; + + // start the painter + QPainter paint(this); + + // ratios and operation signs are painted with the same font + paint.setFont(m_font); + + // set the pen for painting + QPen pen(Qt::SolidLine); + pen.setWidth(0); + paint.setPen(pen); + + // get the font height; the font height doesn't change while painting + QFontMetrics fm(paint.fontMetrics()); + int fontHeight = fm.lineSpacing(); // get the font height + + // now we can correctly set the height of the widget + setMinimumHeight(2 * fontHeight + 10); + setMaximumHeight(2 * fontHeight + 10); + + // paint each char one by one + for (uint stringPos = 0; stringPos < m_number.length(); stringPos++) + { + // check if the period line starts over the current number + if (m_periodLength > 0 && stringPos == m_periodStart && tmp_painting == false) + { + x_startPos = x_pos; + tmp_painting = true; + } + + // paint the current number (or comma) + paintMiddle(paint, QString(m_number[stringPos]), x_pos, fm, m_colorNumber, false); + + // check if the period line ends over the current number; in this case + // draw the period line + if (tmp_painting == true && m_periodStart + m_periodLength - 1 == stringPos) + { + tmp_painting = false; + + // paint the period line above the numbers + paint.fillRect(x_startPos, fontHeight - 3, x_pos - x_startPos, 1, m_colorNumber); + } + } + + // paint a = at the end + x_pos += _MARGIN_X; + paintMiddle(paint, "=", x_pos, fm, m_colorOperation); + + // stop the painter + paint.end(); + + // the space we needed for painting is the minimum width of the widget + setMinimumWidth(x_pos); + + return; +} diff --git a/kbruch/src/rationalwidget.h b/kbruch/src/rationalwidget.h new file mode 100644 index 00000000..bb668bcd --- /dev/null +++ b/kbruch/src/rationalwidget.h @@ -0,0 +1,63 @@ +/*************************************************************************** + rationalwidget.h - paint a rational number + ------------------- + 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. * + * * + ***************************************************************************/ + +#ifndef RATIONALWIDGET_H +#define RATIONALWIDGET_H + +#define DEBUG + +#ifdef DEBUG +#include <kdebug.h> +#endif + +#include "fractionbasewidget.h" + +class QString; + +/*! class to paint a rational number + * + * \author Sebastian Stein */ +class RationalWidget : public FractionBaseWidget +{ + Q_OBJECT + +public: + /** constructor */ + RationalWidget(QWidget * parent, const char * name, const QString pnumber, const uint pperiodStart = 1, const uint pperiodLength = 0); + + /** destructor */ + ~RationalWidget(); + + /** set the task to be displayed */ + void setRational(const QString pnumber, const uint pperiodStart = 1, const uint pperiodLength = 0); + +private: + + /** the rational number to be displayed */ + QString m_number; + + /** starting of the period */ + uint m_periodStart; + + /** length of the period */ + uint m_periodLength; + + /** overrideing the paint event of FractionBaseWidget */ + void paintEvent(QPaintEvent*); +}; + +#endif diff --git a/kbruch/src/ratiowidget.cpp b/kbruch/src/ratiowidget.cpp new file mode 100644 index 00000000..43d4d317 --- /dev/null +++ b/kbruch/src/ratiowidget.cpp @@ -0,0 +1,80 @@ +/*************************************************************************** + ratiowidget.h - paint a ratio + ------------------- + begin : 2004/06/03 + 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 "ratiowidget.h" +#include "ratiowidget.moc" + +/* these includes are needed for Qt support */ +#include <qpainter.h> + +RatioWidget::RatioWidget(QWidget * parent = 0, const char * name = 0, + const ratio para_ratio = *new ratio()) : + FractionBaseWidget(parent, name), m_ratio(para_ratio) +{ +#ifdef DEBUG + kdDebug() << "constructor RatioWidget" << endl; +#endif +} + +RatioWidget::~RatioWidget() +{ +#ifdef DEBUG + kdDebug() << "destructor RatioWidget" << endl; +#endif +} + +void RatioWidget::setRatio(const ratio para_ratio) +{ + m_ratio = para_ratio; + update(); +} + +void RatioWidget::paintEvent(QPaintEvent* /* p_paintEvent */) +{ + // our x position, we paint from left to right; + // we don't want to start directly on the border, so add the margin + int x_pos = _MARGIN_X; + + // start the painter + QPainter paint(this); + + // ratios and operation signs are painted with the same font + paint.setFont(m_font); + + // set the pen for painting + QPen pen(Qt::SolidLine); + pen.setWidth(0); + paint.setPen(pen); + + // get the font height; the font height doesn't change while painting + QFontMetrics fm(paint.fontMetrics()); + + // now we can correctly set the height of the widget + setMinimumHeight(2 * fm.lineSpacing() + 10); + setMaximumHeight(2 * fm.lineSpacing() + 10); + + // result as normal ratio + paintRatio(paint, m_ratio, x_pos, fm, false); + + // stop the painter + paint.end(); + + // the space we needed for painting is the minimum width of the widget + setMinimumWidth(x_pos); + + return; +} diff --git a/kbruch/src/ratiowidget.h b/kbruch/src/ratiowidget.h new file mode 100644 index 00000000..f2422043 --- /dev/null +++ b/kbruch/src/ratiowidget.h @@ -0,0 +1,56 @@ +/*************************************************************************** + ratiowidget.h - paint a ratio + ------------------- + begin : 2004/06/03 + 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. * + * * + ***************************************************************************/ + +#ifndef RATIOWIDGET_H +#define RATIOWIDGET_H + +#ifdef DEBUG +#include <kdebug.h> +#endif + +#include "fractionbasewidget.h" +#include "ratio.h" + +#include <qwidget.h> + +/*! class to paint the ratio + * + * \author Sebastian Stein */ +class RatioWidget : public FractionBaseWidget +{ + Q_OBJECT + +public: + /** constructor */ + RatioWidget(QWidget * parent, const char * name, const ratio para_ratio); + + /** destructor */ + ~RatioWidget(); + + /** set the task to be displayed */ + void setRatio(const ratio para_ratio); + +private: + + /** the ratio to be displayed */ + ratio m_ratio; + + /** overrideing the paint event of FractionBaseWidget */ + void paintEvent(QPaintEvent*); +}; + +#endif diff --git a/kbruch/src/resultwidget.cpp b/kbruch/src/resultwidget.cpp new file mode 100644 index 00000000..bc9fb285 --- /dev/null +++ b/kbruch/src/resultwidget.cpp @@ -0,0 +1,90 @@ +/*************************************************************************** + resultwidget.h - paint the result + ------------------- + begin : 2004/05/30 + 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 "resultwidget.h" +#include "resultwidget.moc" + +/* these includes are needed for Qt support */ +#include <qpainter.h> + +#include "settingsclass.h" + +ResultWidget::ResultWidget(QWidget * parent = 0, const char * name = 0, + const ratio para_result = *new ratio()) : + FractionBaseWidget(parent, name), m_result(para_result) +{ +#ifdef DEBUG + kdDebug() << "constructor ResultWidget" << endl; +#endif +} + +ResultWidget::~ResultWidget() +{ +#ifdef DEBUG + kdDebug() << "destructor ResultWidget" << endl; +#endif +} + +void ResultWidget::setResult(const ratio para_result) +{ + m_result = para_result; + update(); +} + +void ResultWidget::paintEvent(QPaintEvent* /* p_paintEvent */) +{ + // our x position, we paint from left to right; + // we don't want to start directly on the border, so add the margin + int old_x = _MARGIN_X; + + // start the painter + QPainter paint(this); + + // ratios and operation signs are painted with the same font + paint.setFont(m_font); + + // set the pen for painting + QPen pen(Qt::SolidLine); + pen.setWidth(0); + paint.setPen(pen); + + // get the font height; the font height doesn't change while painting + QFontMetrics fm(paint.fontMetrics()); + + // now we can correctly set the height of the widget + setMinimumHeight(2 * fm.lineSpacing() + 10); + setMaximumHeight(2 * fm.lineSpacing() + 10); + + // result as normal ratio + paintMiddle(paint, QString("="), old_x, fm, m_colorOperation); + paintRatio(paint, m_result, old_x, fm, false); + + if (SettingsClass::showSpecialRatioNotation() == true && QABS(m_result.numerator()) >= QABS(m_result.denominator())) + { + // result as mixed number + paintMiddle(paint, QString("="), old_x, fm, m_colorOperation); + paintRatio(paint, m_result, old_x, fm, true); + } + + // stop the painter + paint.end(); + + // the space we needed for painting is the minimum width of the widget + setMinimumWidth(old_x); + + return; +} diff --git a/kbruch/src/resultwidget.h b/kbruch/src/resultwidget.h new file mode 100644 index 00000000..4570df1d --- /dev/null +++ b/kbruch/src/resultwidget.h @@ -0,0 +1,56 @@ +/*************************************************************************** + resultwidget.h - paint the result + ------------------- + begin : 2004/05/30 + 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. * + * * + ***************************************************************************/ + +#ifndef RESULTWIDGET_H +#define RESULTWIDGET_H + +#ifdef DEBUG +#include <kdebug.h> +#endif + +#include "fractionbasewidget.h" +#include "ratio.h" + +#include <qwidget.h> + +/*! class to paint the result + * + * \author Sebastian Stein */ +class ResultWidget : public FractionBaseWidget +{ + Q_OBJECT + +public: + /** constructor */ + ResultWidget(QWidget * parent, const char * name, const ratio para_result); + + /** destructor */ + ~ResultWidget(); + + /** set the task to be displayed */ + void setResult(const ratio para_result); + +private: + + /** the ratio to be displayed */ + ratio m_result; + + /** overrideing the paint event of FractionBaseWidget */ + void paintEvent(QPaintEvent*); +}; + +#endif diff --git a/kbruch/src/settingsclass.kcfgc b/kbruch/src/settingsclass.kcfgc new file mode 100644 index 00000000..3cc5424b --- /dev/null +++ b/kbruch/src/settingsclass.kcfgc @@ -0,0 +1,4 @@ +File=kbruch.kcfg +ClassName=SettingsClass +Singleton=true +Mutators=true diff --git a/kbruch/src/statisticsview.cpp b/kbruch/src/statisticsview.cpp new file mode 100644 index 00000000..b19779f6 --- /dev/null +++ b/kbruch/src/statisticsview.cpp @@ -0,0 +1,199 @@ +/*************************************************************************** + statisticsview.cpp - the statistic window + ------------------- + begin : Tue Mar 08 17:20:00 CET 2002 + copyright : (C) 2001 - 2004 by Sebastian Stein, Eva Brucherseifer + 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 "statisticsview.h" +#include "statisticsview.moc" + +/* the includes are needed for Qt support */ +#include <qlabel.h> +#include <qlayout.h> +#include <qpushbutton.h> +#include <qtooltip.h> +#include <qwhatsthis.h> + +#include <klocale.h> +#include <kdebug.h> + +#include "settingsclass.h" + +/* constructor */ +StatisticsView::StatisticsView(QWidget * parent, const char * name): + QWidget(parent, name), m_count(0), m_correct(0) +{ +#ifdef DEBUG + kdDebug() << "constructor StatisticsView()" << endl; +#endif + + // load statistics from config file + m_count = SettingsClass::count(); + m_correct = SettingsClass::correct(); + + QPalette pal; + QColorGroup cg; + + /* set the caption of the window */ + // setCaption(i18n("Statistics")); + + /* add a layout as a base */ + layout1 = new QVBoxLayout(this); + layout1->setSpacing(6); + layout1->setMargin(6); + + /* now add a v-spacer */ + QSpacerItem * v_spacer = new QSpacerItem(1, 1); + layout1->addItem(v_spacer); + + /* create a grid to show the labels */ + labelGrid = new QGridLayout(layout1, 3, 2); + + /* add 6 labels to the grid */ + info1Label = new QLabel(this); + info1Label->setText(i18n("Tasks so far:")); + labelGrid->addWidget(info1Label, 1, 0); + + result1Label = new QLabel(this); + labelGrid->addWidget(result1Label, 1, 1); + QToolTip::add(result1Label, + i18n("This is the current total number of solved tasks.")); + + info2Label = new QLabel(this); + info2Label->setText(i18n("Correct:")); + labelGrid->addWidget(info2Label, 2, 0); + + result2Label = new QLabel(this); + + /* set green text color for this label */ + pal = result2Label->palette(); + cg = pal.active(); + cg.setColor(QColorGroup::Foreground, QColor(6, 179, 0)); + pal.setActive(cg); + cg = pal.inactive(); + cg.setColor(QColorGroup::Foreground, QColor(6, 179, 0)); + pal.setInactive(cg); + result2Label->setPalette(pal); + + labelGrid->addWidget(result2Label, 2, 1); + QToolTip::add(result2Label, + i18n("This is the current total number of correctly solved tasks.")); + + info3Label = new QLabel(this); + info3Label->setText(i18n("Incorrect:")); + labelGrid->addWidget(info3Label, 3, 0); + + result3Label = new QLabel(this); + + /* set red text color for this label */ + pal = result3Label->palette(); + cg = pal.active(); + cg.setColor(QColorGroup::Foreground, QColor(red)); + pal.setActive(cg); + cg = pal.inactive(); + cg.setColor(QColorGroup::Foreground, QColor(red)); + pal.setInactive(cg); + result3Label->setPalette(pal); + + labelGrid->addWidget(result3Label, 3, 1); + QToolTip::add(result3Label, + i18n("This is the current total number of unsolved tasks.")); + + /* now add a v-spacer */ + v_spacer = new QSpacerItem(1, 1); + layout1->addItem(v_spacer); + + /* the Reset button */ + buttonLayout = new QHBoxLayout(layout1); + resetBtn = new QPushButton(i18n("&Reset"), this); + QObject::connect(resetBtn, SIGNAL(clicked()), this, SLOT(resetStatistics())); + buttonLayout->addWidget(resetBtn); + QToolTip::add(resetBtn, i18n("Press the button to reset the statistics.")); + QSpacerItem* spacer = new QSpacerItem(0,0); + buttonLayout->addItem(spacer); + + /* calculate the statistics */ + (void) calc(); + + // add tooltip and qwhatsthis help to the widget + QToolTip::add(this, i18n("This part of the window shows the statistics.")); + QWhatsThis::add(this, i18n("This part of the window shows the statistics. Each exercise you do is counted. You can reset the statistics by clicking on the button below. Also, if you do not want to see the statistics, use the vertical bar on the left to reduce the size of this window part.")); +} + +/* destructor */ +StatisticsView::~StatisticsView() +{ +#ifdef DEBUG + kdDebug() << "destructor StatisticsView()" << endl; +#endif + // save statistics for next run + SettingsClass::setCount(m_count); + SettingsClass::setCorrect(m_correct); + SettingsClass::writeConfig(); + + /* no need to delete any child widgets, Qt does it by itself */ +} + +/* called, if a task solved correctly */ +void StatisticsView::addCorrect() +{ + ++m_count; + ++m_correct; + (void) calc(); /* repaint the statistics */ +} + +/* called, if a task was solved wrong */ +void StatisticsView::addWrong() +{ + ++m_count; + (void) calc(); /* repaint the statistics */ +} + + +/* ------ private member functions ------ */ + +/* recalculates the statistics and changes the corresponding labels */ +void StatisticsView::calc() +{ + QString new_text; + QString number; + + new_text = QString("<b>%1</b>").arg(m_count); + result1Label->setText(new_text); + + /* we have to be careful with division by 0 */ + if (m_count == 0) + { + result2Label->setText("- (- %)"); + result3Label->setText("- (- %)"); + } else { + /* set the correct label */ + new_text = QString("%1 (%2 %)").arg(m_correct).arg(int(double(m_correct) / m_count * 100)); + result2Label->setText(new_text); + + /* set the incorrect label */ + new_text = QString("%1 (%2 %)").arg(m_count - m_correct).arg(int(double(m_count - m_correct) / m_count * 100)); + result3Label->setText(new_text); + } +} + +/* ------ private slots ------ */ + +/* called by the reset button */ +void StatisticsView::resetStatistics() +{ + m_count = 0; + m_correct = 0; + (void) calc(); +} diff --git a/kbruch/src/statisticsview.h b/kbruch/src/statisticsview.h new file mode 100644 index 00000000..9de0c24d --- /dev/null +++ b/kbruch/src/statisticsview.h @@ -0,0 +1,78 @@ +/*************************************************************************** + statisticsview.cpp - Header File + ------------------- + begin : Tue Mar 08 17:20:00 CET 2002 + copyright : (C) 2001 - 2004 by Sebastian Stein, Eva Brucherseifer + 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. * + * * + ***************************************************************************/ + +#ifndef STATISTICSVIEW_H +#define STATISTICSVIEW_H + +class QLabel; +class QPushButton; +class QVBoxLayout; +class QHBoxLayout; +class QGridLayout; + +#include <qwidget.h> + +/*! + * StatisticsView takes care of the statistics of a test. + * It saves the number of correct and wrong answers and + * displays this data to the user. + * \author Sebastian Stein + * \author Eva Brucherseifer + */ + +class StatisticsView : public QWidget +{ + Q_OBJECT + +public: + /** constructor */ + StatisticsView(QWidget * parent = 0, const char * name = 0); + + /** destructor */ + ~StatisticsView(); + +public slots: + /** increment number of correct answers */ + void addCorrect(); + + /** increment number of wrong answers */ + void addWrong(); + + /** set statistics to zero. + * Triggered by internal button or when a new test is started + */ + void resetStatistics(); +private: + /** calculate percentages and update view */ + void calc(); + + unsigned int m_count; + unsigned int m_correct; + + QPushButton * resetBtn; + QHBoxLayout * buttonLayout; + QVBoxLayout * layout1; + QGridLayout * labelGrid; + QLabel * result1Label; + QLabel * result2Label; + QLabel * result3Label; + QLabel * info1Label; + QLabel * info2Label; + QLabel * info3Label; +}; + +#endif diff --git a/kbruch/src/svg-source/cr-action-kbruch_exercise_common.svg b/kbruch/src/svg-source/cr-action-kbruch_exercise_common.svg new file mode 100644 index 00000000..8ebfc7f8 --- /dev/null +++ b/kbruch/src/svg-source/cr-action-kbruch_exercise_common.svg @@ -0,0 +1,171 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN" +"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd"> +<!-- Created with Inkscape (http://www.inkscape.org/) --> +<svg + id="svg1" + sodipodi:version="0.32" + inkscape:version="0.38.1" + width="16.000000pt" + height="16.000000pt" + sodipodi:docbase="/home/sstein/programmierung/cvs/kde/kdeedu/kbruch/src/svg-source" + sodipodi:docname="cr-action-kbruch-exercise-common.svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:xml="http://www.w3.org/XML/1998/namespace" + xmlns:xlink="http://www.w3.org/1999/xlink"> + <defs + id="defs3"> + <linearGradient + id="linearGradient868"> + <stop + style="stop-color:#ffffff;stop-opacity:0.0000000;" + offset="0.0000000" + id="stop869" /> + <stop + style="stop-color:#fff;stop-opacity:1;" + offset="1" + id="stop870" /> + </linearGradient> + <linearGradient + id="linearGradient893"> + <stop + style="stop-color:#19839a;stop-opacity:0.0000000;" + offset="0.0000000" + id="stop894" /> + <stop + style="stop-color:#fff;stop-opacity:1;" + offset="1" + id="stop895" /> + </linearGradient> + <linearGradient + id="linearGradient830"> + <stop + style="stop-color:#ebffff;stop-opacity:0.0000000;" + offset="0.0000000" + id="stop831" /> + <stop + style="stop-color:#fff;stop-opacity:1;" + offset="1" + id="stop832" /> + </linearGradient> + <linearGradient + id="linearGradient826"> + <stop + style="stop-color:#000;stop-opacity:1;" + offset="0" + id="stop827" /> + <stop + style="stop-color:#fff;stop-opacity:1;" + offset="1" + id="stop828" /> + </linearGradient> + <linearGradient + xlink:href="#linearGradient830" + id="linearGradient829" /> + <linearGradient + xlink:href="#linearGradient830" + id="linearGradient834" + x1="-0.31159419" + y1="0.19531250" + x2="0.77536231" + y2="0.94531250" /> + <linearGradient + xlink:href="#linearGradient830" + id="linearGradient836" /> + <linearGradient + xlink:href="#linearGradient868" + id="linearGradient892" + x1="-0.49264705" + y1="0.43750000" + x2="0.022058824" + y2="0.92187500" /> + <radialGradient + xlink:href="#linearGradient830" + id="radialGradient869" + cx="0.50000000" + cy="0.50000000" + r="0.50000000" + fx="0.50000000" + fy="0.50000000" + spreadMethod="reflect" /> + </defs> + <sodipodi:namedview + id="base" + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1.0" + inkscape:pageopacity="0.0" + inkscape:pageshadow="2" + inkscape:zoom="24.280000" + inkscape:cx="12.500000" + inkscape:cy="5.9102142" + inkscape:window-width="1024" + inkscape:window-height="742" + gridspacingy="1.0000000pt" + gridspacingx="1.0000000pt" + gridtolerance="1.0000000px" + inkscape:window-x="0" + inkscape:window-y="0" + showgrid="true" /> + <text + xml:space="preserve" + style="fill:#00ff00;fill-opacity:1.0000000;stroke:none;font-family:Verdana;font-style:normal;font-weight:normal;font-size:10.000000;font-stretch:normal;font-variant:normal;text-anchor:start;writing-mode:lr;stroke-opacity:1;stroke-width:1pt;stroke-linejoin:miter;stroke-linecap:butt;" + x="0.097586758" + y="19.209157" + id="text850" + sodipodi:linespacing="100%"><tspan + id="tspan851" + style="fill:#00ff00;fill-opacity:1.0000000;">7</tspan></text> + <text + xml:space="preserve" + style="fill:#ff7700;fill-opacity:1.0000000;stroke:none;font-family:Verdana;font-style:normal;font-weight:normal;font-size:10.000000;font-stretch:normal;font-variant:normal;text-anchor:start;writing-mode:lr;stroke-opacity:1;stroke-width:1pt;stroke-linejoin:miter;stroke-linecap:butt;" + x="13.697060" + y="19.360525" + id="text856" + sodipodi:linespacing="100%"><tspan + id="tspan857" + style="fill:#ff7700;fill-opacity:1.0000000;">3</tspan></text> + <text + xml:space="preserve" + style="fill:#ff009e;fill-opacity:1.0000000;stroke:none;font-family:Verdana;font-style:normal;font-weight:normal;font-size:10.000000;font-stretch:normal;font-variant:normal;text-anchor:start;writing-mode:lr;stroke-opacity:1.0000000;stroke-width:1pt;stroke-linejoin:miter;stroke-linecap:butt;" + x="5.8638921" + y="13.346795" + id="text865" + sodipodi:linespacing="100%"><tspan + id="tspan866" + style="stroke:none;stroke-opacity:1.0000000;fill:#ff009e;fill-opacity:1.0000000;">+</tspan></text> + <text + xml:space="preserve" + style="fill:#ff0000;fill-opacity:1.0000000;stroke:none;font-family:Verdana;font-style:normal;font-weight:normal;font-size:10.000000;font-stretch:normal;font-variant:normal;text-anchor:start;writing-mode:lr;stroke-opacity:1;stroke-width:1pt;stroke-linejoin:miter;stroke-linecap:butt;" + x="0.063407071" + y="8.3877524" + id="text847" + sodipodi:linespacing="100%"><tspan + id="tspan848" + style="fill:#ff0000;fill-opacity:1.0000000;">2</tspan></text> + <text + xml:space="preserve" + style="fill:#ff0072;fill-opacity:1.0000000;stroke:none;font-family:Verdana;font-style:normal;font-weight:normal;font-size:10.000000;font-stretch:normal;font-variant:normal;text-anchor:start;writing-mode:lr;stroke-opacity:1;stroke-width:1pt;stroke-linejoin:miter;stroke-linecap:butt;" + x="13.653116" + y="8.2363851" + id="text853" + sodipodi:linespacing="100%"><tspan + id="tspan854" + style="fill:#ff0072;fill-opacity:1.0000000;">5</tspan></text> + <rect + style="fill-rule:evenodd;stroke:#0000ff;stroke-width:0.62263856pt;fill:#0000ff;fill-opacity:1.0000000;stroke-opacity:1.0000000;" + id="rect868" + width="4.1720033" + height="0.40835696" + x="1.2302562" + y="9.9590223" /> + <rect + style="fill-rule:evenodd;stroke:#00ffff;stroke-width:0.62263856pt;stroke-opacity:1.0000000;" + id="rect871" + width="4.1720033" + height="0.40835696" + x="14.771190" + y="9.9590228" /> +</svg> diff --git a/kbruch/src/svg-source/cr-action-kbruch_exercise_compare.svg b/kbruch/src/svg-source/cr-action-kbruch_exercise_compare.svg new file mode 100644 index 00000000..ba4c1da9 --- /dev/null +++ b/kbruch/src/svg-source/cr-action-kbruch_exercise_compare.svg @@ -0,0 +1,173 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN" +"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd"> +<!-- Created with Inkscape (http://www.inkscape.org/) --> +<svg + id="svg1" + sodipodi:version="0.32" + inkscape:version="0.38.1" + width="16.000000pt" + height="16.000000pt" + sodipodi:docbase="/home/sstein/programmierung/cvs/kde/kdeedu/kbruch/src/svg-source" + sodipodi:docname="cr-action-kbruch-exercise-compare.svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:xml="http://www.w3.org/XML/1998/namespace" + xmlns:xlink="http://www.w3.org/1999/xlink"> + <defs + id="defs3"> + <linearGradient + id="linearGradient868"> + <stop + style="stop-color:#ffffff;stop-opacity:0.0000000;" + offset="0.0000000" + id="stop869" /> + <stop + style="stop-color:#fff;stop-opacity:1;" + offset="1" + id="stop870" /> + </linearGradient> + <linearGradient + id="linearGradient893"> + <stop + style="stop-color:#19839a;stop-opacity:0.0000000;" + offset="0.0000000" + id="stop894" /> + <stop + style="stop-color:#fff;stop-opacity:1;" + offset="1" + id="stop895" /> + </linearGradient> + <linearGradient + id="linearGradient830"> + <stop + style="stop-color:#ebffff;stop-opacity:0.0000000;" + offset="0.0000000" + id="stop831" /> + <stop + style="stop-color:#fff;stop-opacity:1;" + offset="1" + id="stop832" /> + </linearGradient> + <linearGradient + id="linearGradient826"> + <stop + style="stop-color:#000;stop-opacity:1;" + offset="0" + id="stop827" /> + <stop + style="stop-color:#fff;stop-opacity:1;" + offset="1" + id="stop828" /> + </linearGradient> + <linearGradient + xlink:href="#linearGradient830" + id="linearGradient829" /> + <linearGradient + xlink:href="#linearGradient830" + id="linearGradient834" + x1="-0.31159419" + y1="0.19531250" + x2="0.77536231" + y2="0.94531250" /> + <linearGradient + xlink:href="#linearGradient830" + id="linearGradient836" /> + <linearGradient + xlink:href="#linearGradient868" + id="linearGradient892" + x1="-0.49264705" + y1="0.43750000" + x2="0.022058824" + y2="0.92187500" /> + <radialGradient + xlink:href="#linearGradient830" + id="radialGradient869" + cx="0.50000000" + cy="0.50000000" + r="0.50000000" + fx="0.50000000" + fy="0.50000000" + spreadMethod="reflect" /> + </defs> + <sodipodi:namedview + id="base" + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1.0" + inkscape:pageopacity="0.0" + inkscape:pageshadow="2" + inkscape:zoom="24.280000" + inkscape:cx="12.500000" + inkscape:cy="5.9102142" + inkscape:window-width="1017" + inkscape:window-height="731" + gridspacingy="1.0000000pt" + gridspacingx="1.0000000pt" + gridtolerance="1.0000000px" + inkscape:window-x="0" + inkscape:window-y="0" + showgrid="true" /> + <text + xml:space="preserve" + style="fill:#00ff00;fill-opacity:1.0000000;stroke:none;font-family:Verdana;font-style:normal;font-weight:normal;font-size:10.000000;font-stretch:normal;font-variant:normal;text-anchor:start;writing-mode:lr;stroke-opacity:1;stroke-width:1pt;stroke-linejoin:miter;stroke-linecap:butt;" + x="0.097586758" + y="19.209157" + id="text850" + sodipodi:linespacing="100%"><tspan + id="tspan851" + style="fill:#00ff00;fill-opacity:1.0000000;">7</tspan></text> + <text + xml:space="preserve" + style="fill:#ff7700;fill-opacity:1.0000000;stroke:none;font-family:Verdana;font-style:normal;font-weight:normal;font-size:10.000000;font-stretch:normal;font-variant:normal;text-anchor:start;writing-mode:lr;stroke-opacity:1;stroke-width:1pt;stroke-linejoin:miter;stroke-linecap:butt;" + x="13.697060" + y="19.360525" + id="text856" + sodipodi:linespacing="100%"><tspan + id="tspan857" + style="fill:#ff7700;fill-opacity:1.0000000;">3</tspan></text> + <text + xml:space="preserve" + style="fill:#ff009e;fill-opacity:1.0000000;stroke:none;font-family:Verdana;font-style:normal;font-weight:normal;font-size:10.000000;font-stretch:normal;font-variant:normal;text-anchor:start;writing-mode:lr;stroke-opacity:1.0000000;stroke-width:1pt;stroke-linejoin:miter;stroke-linecap:butt;" + x="5.8638921" + y="13.346795" + id="text865" + sodipodi:linespacing="100%"><tspan + x="5.8638921" + y="13.346795" + sodipodi:role="line" + id="tspan863"><</tspan></text> + <text + xml:space="preserve" + style="fill:#ff0000;fill-opacity:1.0000000;stroke:none;font-family:Verdana;font-style:normal;font-weight:normal;font-size:10.000000;font-stretch:normal;font-variant:normal;text-anchor:start;writing-mode:lr;stroke-opacity:1;stroke-width:1pt;stroke-linejoin:miter;stroke-linecap:butt;" + x="0.063407071" + y="8.3877524" + id="text855" + sodipodi:linespacing="100%"><tspan + id="tspan848" + style="fill:#ff0000;fill-opacity:1.0000000;">2</tspan></text> + <text + xml:space="preserve" + style="fill:#ff0072;fill-opacity:1.0000000;stroke:none;font-family:Verdana;font-style:normal;font-weight:normal;font-size:10.000000;font-stretch:normal;font-variant:normal;text-anchor:start;writing-mode:lr;stroke-opacity:1;stroke-width:1pt;stroke-linejoin:miter;stroke-linecap:butt;" + x="13.653116" + y="8.2363851" + id="text853" + sodipodi:linespacing="100%"><tspan + id="tspan854" + style="fill:#ff0072;fill-opacity:1.0000000;">5</tspan></text> + <rect + style="fill-rule:evenodd;stroke:#0000ff;stroke-width:0.62263856pt;fill:#0000ff;fill-opacity:1.0000000;stroke-opacity:1.0000000;" + id="rect868" + width="4.1720033" + height="0.40835696" + x="1.2302562" + y="9.9590223" /> + <rect + style="fill-rule:evenodd;stroke:#00ffff;stroke-width:0.62263856pt;stroke-opacity:1.0000000;" + id="rect871" + width="4.1720033" + height="0.40835696" + x="14.771190" + y="9.9590228" /> +</svg> diff --git a/kbruch/src/svg-source/cr-action-kbruch_exercise_conversion.svg b/kbruch/src/svg-source/cr-action-kbruch_exercise_conversion.svg new file mode 100644 index 00000000..3a52d5a8 --- /dev/null +++ b/kbruch/src/svg-source/cr-action-kbruch_exercise_conversion.svg @@ -0,0 +1,198 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN" +"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd"> +<!-- Created with Inkscape (http://www.inkscape.org/) --> +<svg + id="svg1" + sodipodi:version="0.32" + inkscape:version="0.38.1" + width="22.000000pt" + height="22.000000pt" + sodipodi:docbase="/home/sstein/programmierung/cvs/kde/kdeedu/kbruch/src/svg-source" + sodipodi:docname="cr-action-kbruch-exercise-conversion.svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:xml="http://www.w3.org/XML/1998/namespace" + xmlns:xlink="http://www.w3.org/1999/xlink"> + <defs + id="defs3"> + <linearGradient + id="linearGradient868"> + <stop + style="stop-color:#ffffff;stop-opacity:0.0000000;" + offset="0.0000000" + id="stop869" /> + <stop + style="stop-color:#fff;stop-opacity:1;" + offset="1" + id="stop870" /> + </linearGradient> + <linearGradient + id="linearGradient893"> + <stop + style="stop-color:#19839a;stop-opacity:0.0000000;" + offset="0.0000000" + id="stop894" /> + <stop + style="stop-color:#fff;stop-opacity:1;" + offset="1" + id="stop895" /> + </linearGradient> + <linearGradient + id="linearGradient830"> + <stop + style="stop-color:#ebffff;stop-opacity:0.0000000;" + offset="0.0000000" + id="stop831" /> + <stop + style="stop-color:#fff;stop-opacity:1;" + offset="1" + id="stop832" /> + </linearGradient> + <linearGradient + id="linearGradient826"> + <stop + style="stop-color:#000;stop-opacity:1;" + offset="0" + id="stop827" /> + <stop + style="stop-color:#fff;stop-opacity:1;" + offset="1" + id="stop828" /> + </linearGradient> + <linearGradient + xlink:href="#linearGradient868" + id="linearGradient829" /> + <linearGradient + xlink:href="#linearGradient830" + id="linearGradient834" + x1="-0.31159419" + y1="0.19531250" + x2="0.77536231" + y2="0.94531250" /> + <linearGradient + xlink:href="#linearGradient830" + id="linearGradient836" /> + <linearGradient + xlink:href="#linearGradient868" + id="linearGradient892" + x1="-0.49264705" + y1="0.43750000" + x2="0.022058824" + y2="0.92187500" /> + <radialGradient + xlink:href="#linearGradient830" + id="radialGradient869" + cx="0.50000000" + cy="0.50000000" + r="0.50000000" + fx="0.50000000" + fy="0.50000000" + spreadMethod="reflect" /> + </defs> + <sodipodi:namedview + id="base" + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1.0" + inkscape:pageopacity="0.0" + inkscape:pageshadow="2" + inkscape:zoom="27.090909" + inkscape:cx="11.000000" + inkscape:cy="11.000000" + inkscape:window-width="1017" + inkscape:window-height="731" + gridspacingy="1.0000000pt" + gridspacingx="1.0000000pt" + gridtolerance="1.0000000px" + inkscape:window-x="0" + inkscape:window-y="0" + showgrid="true" /> + <text + xml:space="preserve" + style="font-size:10.000000;fill:#ff7700;stroke-width:1.0000000pt;font-family:Verdana;" + x="13.697060" + y="19.360525" + id="text856" + sodipodi:linespacing="100%" + transform="translate(6.641269,2.831549)"><tspan + id="tspan857" + style="fill:#ff7700;fill-opacity:1.0000000;">3</tspan></text> + <text + xml:space="preserve" + style="font-size:10.000000;fill:#ff009e;stroke-width:1.0000000pt;font-family:Verdana;" + x="15.667000" + y="16.178345" + id="text865" + sodipodi:linespacing="100%" + transform="scale(0.839978,1.000000)"><tspan + x="15.667000" + y="16.178345" + sodipodi:role="line" + id="tspan902">=</tspan></text> + <text + xml:space="preserve" + style="font-size:10.000000;fill:#ff0072;stroke-width:1.0000000pt;font-family:Verdana;" + x="13.653116" + y="8.2363851" + id="text853" + sodipodi:linespacing="100%" + transform="translate(6.641269,2.831549)"><tspan + x="13.653116" + y="8.2363853" + sodipodi:role="line" + id="tspan904">1</tspan></text> + <rect + style="fill-rule:evenodd;stroke:#00ffff;stroke-width:0.62263856pt;" + id="rect871" + width="4.1720033" + height="0.40835696" + x="14.771190" + y="9.9590228" + transform="translate(6.641269,2.831549)" /> + <text + xml:space="preserve" + style="font-size:10.000000;fill:#ff0000;stroke-width:1.0000000pt;font-family:Verdana;fill-opacity:1.0000000;" + x="-0.28028948" + y="16.894014" + id="text857" + sodipodi:linespacing="100%"><tspan + x="-0.28028947" + y="16.894014" + sodipodi:role="line" + id="tspan908" + style="fill:#ff0000;fill-opacity:1.0000000;">0</tspan></text> + <text + xml:space="preserve" + style="font-size:10.000000;fill:#ff0000;stroke-width:1.0000000pt;font-family:Verdana;fill-opacity:1.0000000;" + x="-0.24907962" + y="14.057030" + id="text910" + sodipodi:linespacing="100%" + transform="translate(7.104613,2.841867)"><tspan + x="-0.24907961" + y="14.057030" + sodipodi:role="line" + id="tspan918" + style="fill:#ff0000;fill-opacity:1.0000000;">3</tspan></text> + <text + xml:space="preserve" + style="font-size:10.000000;fill:#ff0000;stroke-width:1.0000000pt;font-family:Verdana;fill-opacity:1.0000000;" + x="4.5033544" + y="16.995065" + id="text913" + sodipodi:linespacing="100%"><tspan + x="4.5033545" + y="16.995066" + sodipodi:role="line" + id="tspan916" + style="fill:#ff0000;fill-opacity:1.0000000;">,</tspan></text> + <rect + style="fill:none;fill-opacity:1.0000000;fill-rule:evenodd;stroke:#ff0000;stroke-width:0.51292586pt;stroke-opacity:1.0000000;" + id="rect951" + width="4.0542931" + height="0.31371954" + x="8.1664283" + y="8.0371272" /> +</svg> diff --git a/kbruch/src/svg-source/cr-action-kbruch_exercise_factorisation.svg b/kbruch/src/svg-source/cr-action-kbruch_exercise_factorisation.svg new file mode 100644 index 00000000..53972b4f --- /dev/null +++ b/kbruch/src/svg-source/cr-action-kbruch_exercise_factorisation.svg @@ -0,0 +1,147 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN" +"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd"> +<!-- Created with Inkscape (http://www.inkscape.org/) --> +<svg + id="svg1" + sodipodi:version="0.32" + inkscape:version="0.38.1" + width="20.000000pt" + height="20.000000pt" + sodipodi:docbase="/home/sstein/programmierung/cvs/kde/kdeedu/kbruch/src/svg-source" + sodipodi:docname="cr-action-kbruch-exercise-factorisation.svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:xml="http://www.w3.org/XML/1998/namespace" + xmlns:xlink="http://www.w3.org/1999/xlink"> + <defs + id="defs3"> + <linearGradient + id="linearGradient868"> + <stop + style="stop-color:#ffffff;stop-opacity:0.0000000;" + offset="0.0000000" + id="stop869" /> + <stop + style="stop-color:#fff;stop-opacity:1;" + offset="1" + id="stop870" /> + </linearGradient> + <linearGradient + id="linearGradient893"> + <stop + style="stop-color:#19839a;stop-opacity:0.0000000;" + offset="0.0000000" + id="stop894" /> + <stop + style="stop-color:#fff;stop-opacity:1;" + offset="1" + id="stop895" /> + </linearGradient> + <linearGradient + id="linearGradient830"> + <stop + style="stop-color:#ebffff;stop-opacity:0.0000000;" + offset="0.0000000" + id="stop831" /> + <stop + style="stop-color:#fff;stop-opacity:1;" + offset="1" + id="stop832" /> + </linearGradient> + <linearGradient + id="linearGradient826"> + <stop + style="stop-color:#000;stop-opacity:1;" + offset="0" + id="stop827" /> + <stop + style="stop-color:#fff;stop-opacity:1;" + offset="1" + id="stop828" /> + </linearGradient> + <linearGradient + xlink:href="#linearGradient830" + id="linearGradient829" /> + <linearGradient + xlink:href="#linearGradient830" + id="linearGradient834" + x1="-0.31159419" + y1="0.19531250" + x2="0.77536231" + y2="0.94531250" /> + <linearGradient + xlink:href="#linearGradient830" + id="linearGradient836" /> + <linearGradient + xlink:href="#linearGradient868" + id="linearGradient892" + x1="-0.49264705" + y1="0.43750000" + x2="0.022058824" + y2="0.92187500" /> + <radialGradient + xlink:href="#linearGradient830" + id="radialGradient869" + cx="0.50000000" + cy="0.50000000" + r="0.50000000" + fx="0.50000000" + fy="0.50000000" + spreadMethod="reflect" /> + </defs> + <sodipodi:namedview + id="base" + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1.0" + inkscape:pageopacity="0.0" + inkscape:pageshadow="2" + inkscape:zoom="29.800000" + inkscape:cx="10.000000" + inkscape:cy="10.000000" + inkscape:window-width="1017" + inkscape:window-height="731" + gridspacingy="1.0000000pt" + gridspacingx="1.0000000pt" + gridtolerance="1.0000000px" + inkscape:window-x="0" + inkscape:window-y="0" + showgrid="true" /> + <text + xml:space="preserve" + style="font-size:10.000000;fill:#ff7700;stroke-width:1.0000000pt;font-family:Verdana;font-weight:normal;font-style:normal;font-stretch:normal;font-variant:normal;text-anchor:start;writing-mode:lr;" + x="18.712952" + y="16.106063" + id="text856" + sodipodi:linespacing="100%"><tspan + x="18.712952" + y="16.106064" + sodipodi:role="line" + id="tspan981">?</tspan></text> + <text + xml:space="preserve" + style="font-size:10.000000;fill:#ff009e;stroke-width:1.0000000pt;font-family:Verdana;" + x="14.769678" + y="15.654403" + id="text865" + sodipodi:linespacing="100%" + transform="scale(0.839978,1.000000)"><tspan + x="14.769678" + y="15.654403" + sodipodi:role="line" + id="tspan902">=</tspan></text> + <text + xml:space="preserve" + style="font-size:10.000000;fill:#ff0000;stroke-width:1.0000000pt;font-family:Verdana;font-weight:normal;font-style:normal;font-stretch:normal;font-variant:normal;text-anchor:start;writing-mode:lr;fill-opacity:1.0000000;" + x="0.54185826" + y="16.181745" + id="text850" + sodipodi:linespacing="100%"><tspan + x="0.54185826" + y="16.181746" + sodipodi:role="line" + id="tspan979" + style="fill:#ff0000;fill-opacity:1.0000000;">21</tspan></text> +</svg> diff --git a/kbruch/src/task.cpp b/kbruch/src/task.cpp new file mode 100644 index 00000000..4c3748a3 --- /dev/null +++ b/kbruch/src/task.cpp @@ -0,0 +1,712 @@ +/*************************************************************************** + task.cpp - source code of class task + ------------------- + begin : Tue Nov 27 16:40:42 CET 2001 + copyright : (C) 2001 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 <math.h> +#include <stdlib.h> + +#include <kdebug.h> + +#include <time.h> + +#include "task.h" + +/** constructor of class task */ +task::task() +{ + srand(time(NULL)); +#ifdef DEBUG + kdDebug() << "constructor task" << endl; +#endif +} + +/** destructor of class task */ +task::~task() +{ +#ifdef DEBUG + kdDebug() << "destructor task" << endl; +#endif +} + +/** create a task with random ratios and operations; the generated task + * can be customized by the given parameters: + * pmax_md: maximum main denominator + * pnr_ratios: number of ratios -> pnr_ratios - 1 operations + * padd_sub: if TRUE + and - are allowed operations + * pmul_div: if TRUE * and / are allowed operations */ +void task::create_task(unsigned int pmax_md, short pnr_ratios, + short padd_sub, short pmul_div) +{ + unsigned short max_product_length = 0; + int main_denominator = 1; + + /* we say that if add/sub and mul/div are not allowed we want a task + * for add/sub only */ + if (padd_sub == NO && pmul_div == NO) + padd_sub = YES; + + do + { + /* delete a maybe given task */ + ratio_vector.clear(); + + /* generate the operations and count the max. mul/div in one block */ + max_product_length = make_operation(padd_sub, pmul_div, pnr_ratios); + +#ifdef DEBUG + kdDebug() << "1: max_product_length: " << max_product_length << endl; +#endif + /* later we must be able to find a main denominator; + * so 2 ^ max_product_length couldn't be bigger than the max. denominator */ + } + while ((unsigned int) pow(2, max_product_length) > pmax_md); + +#ifdef DEBUG + kdDebug() << "2: max_product_length: " << max_product_length << endl; +#endif + + /* find a main denominator */ + main_denominator = make_main_dn(pmax_md, max_product_length); + +#ifdef DEBUG + kdDebug() << "after make_main_dn()" << endl; +#endif + + /* create the ratios' numerators */ + make_numerators(main_denominator, pnr_ratios); + +#ifdef DEBUG + kdDebug() << "after make_numerators()" << endl; +#endif + + /* create the ratios' denominators */ + make_denominators(main_denominator, pmax_md, pmul_div); + +#ifdef DEBUG + kdDebug() << "main deno: " << main_denominator << endl; + kdDebug() << "prim fakt: " << prim_fac_vector.size() << endl; +#endif + + return; +} + +/** set ratio n in the ratio_vector */ +void task::set_ratio_n(unsigned short number, int numerator, int denominator) +{ + /* do not set something outside our vector */ + if (number > ratio_vector.size() - 1) + number = 0; + ratio_vector[number].setNumerator(numerator); // set numerator + ratio_vector[number].setDenominator(denominator); // set denominator + return; +} + +/** set ratio n in the ratio_vector */ +void task::set_ratio_n(unsigned short number, ratio fraction) +{ + /* do not set something outside our vector */ + if (number > ratio_vector.size() - 1) + number = 0; + ratio_vector[number].setNumerator(fraction.numerator()); // set numerator + ratio_vector[number].setDenominator(fraction.denominator()); // set denominator + return; +} + +/** returns the ratio given by number from the ratio_vector */ +ratio task::get_ratio_n(unsigned short number) const +{ + /* do not set something outside our vector */ + if (number > ratio_vector.size() - 1) + number = 0; + return ratio_vector[number]; +} + +/** set operation given by the number in the op_vector */ +void task::set_op_n(unsigned short number, short operation) +{ + /* do not set something outside our vector */ + if (number > op_vector.size() - 1) + number = 0; + op_vector[number] = operation; + return; +} + +/** returns the operation given by number from the op_vector */ +short task::get_op_n(unsigned short number) const +{ + /* do not set something outside our vector */ + if (number > op_vector.size() - 1) + number = 0; + return op_vector[number]; +} + +/** add a new ratio at the end of the ratio vector */ +void task::add_ratio(ratio new_ratio) +{ + ratio_vector.push_back(new_ratio); + return; +} + +/** add a new ratio at the end of the ratio vector */ +void task::add_ratio(int numerator, int denominator) +{ + ratio new_ratio(numerator, denominator); + ratio_vector.push_back(new_ratio); + return; +} + +/** add a new operation at the end of the operation vector */ +void task::add_operation(short operation) +{ + op_vector.push_back(operation); + return; +} + +/** just outputs the whole given task to stdout; for debugging */ +QTextStream & task::display(QTextStream & str) +{ + /* this is our pointer on the ratio_vector, set it to the beginning */ + RatioArray::iterator ratio_pointer = ratio_vector.begin(); + + /* this is our pointer on the op_vector, set it to the beginning */ + ShortArray::iterator op_pointer = op_vector.begin(); + + /* we need this array to look up the fitting chars for the operations */ + const char a[] = "+-*/"; + + /* check, if a qSetW() was given to the stream */ + int weite = str.width(); + int pweite = weite; + str << qSetW(0); + + /* check, if ratio number and operation number fit together */ + if (ratio_vector.size() != op_vector.size() + 1) + { + kdDebug() << "Number of ratios and operations do not fit." << endl; + return str; + } + + while (pweite-- > 0) + str << " "; + + /* display all numerators */ + for (ratio_pointer = ratio_vector.begin(); + ratio_pointer != ratio_vector.end(); ratio_pointer++) + { + str << qSetW(5) << ratio_pointer->numerator() << " "; + } + str << endl; + + pweite = weite; + while (pweite-- > 0) + str << " "; + + /* display all operations */ + for (op_pointer = op_vector.begin(); + op_pointer != op_vector.end(); op_pointer++) + { + str << " ----- " << a[*op_pointer]; + } + str << " ----- = " << endl; + + pweite = weite; + while (pweite-- > 0) + str << " "; + + /* display all denominators */ + for (ratio_pointer = ratio_vector.begin(); + ratio_pointer != ratio_vector.end(); ratio_pointer++) + { + if (ratio_pointer == ratio_vector.end() - 1) + return str << qSetW(5) << ratio_pointer->denominator() << " "; + str << qSetW(5) << ratio_pointer->denominator() << " "; + } + return str; +} + +/** solves the given task and returns the result as a ratio */ +ratio task::solve() +{ + ratio ergebnis(0, 1); /* that is the starting point */ + + /* this is our pointer on the ratio_vector, set it to the beginning */ + RatioArray::iterator ratio_pointer = ratio_vector.begin(); + + /* add a temp operation at the beginning */ + op_vector.insert(op_vector.begin(), ADD); + + /* this is our pointer on the op_vector, set it to the beginning */ + ShortArray::iterator op_pointer = op_vector.begin() + 1; + + /* check, if ratio number and operation number fit together */ + if (ratio_vector.size() != op_vector.size()) + { + kdDebug() << "Number of ratios and operations do not fit." << endl; + return ergebnis; + } + + do + { + /* we have to decide our next action by the given operation */ + switch (*op_pointer) + { + case ADD : + case SUB : + switch(*(op_pointer - 1)) + { + /* we only have to add/sub the next ratio */ + case ADD : + ergebnis = ergebnis + *ratio_pointer++; + break; + case SUB : + ergebnis = ergebnis - *ratio_pointer++; + break; + } + break; + case MUL : + case DIV : + switch (*(op_pointer - 1)) + { + /* the next ratio is a product, so we have to + * compute this product first and than add/sub it */ + case ADD : + ergebnis = ergebnis + + product(ratio_pointer, op_pointer); + break; + case SUB : + ergebnis = ergebnis - + product(ratio_pointer, op_pointer); + break; + } + break; + } + /* check if we reached the and of the task */ + if (ratio_pointer == ratio_vector.end()) + break; + +#ifdef DEBUG + kdDebug() << "Schleifenende" << endl; +#endif + + } + while (++op_pointer != op_vector.end()); + +#ifdef DEBUG + + kdDebug() << "after do while in solve()" << endl; +#endif + + /* if the last operation was an add/sub we haven't add/subed it until now */ + --op_pointer; + switch (*op_pointer) + { + case ADD : + ergebnis = ergebnis + *ratio_pointer; + break; + case SUB : + ergebnis = ergebnis - *ratio_pointer; + break; + } + + /* erase the temp operation */ + op_vector.erase(op_vector.begin()); + + /* before we return the result we have to reduce it */ + ergebnis.reduce(); + + return ergebnis; /* return the solution */ +} + +/* returns the number of ratios in the vector */ +int task::getNumberOfRatios() const +{ + return ratio_vector.count(); +} + +/* returns the number of operations in the vector */ +int task::getNumberOfOperations() const +{ + return op_vector.count(); +} + +/** this function is called by the solving function to compute a given + * product (or div) and return the solution */ +ratio task::product(RatioArray::iterator & ratio_pointer, + ShortArray::iterator & op_pointer) +{ + /* the function's parameters are pointing to the next ratio; + * to the starting point of the product */ + ratio product(ratio_pointer->numerator(), ratio_pointer->denominator()); + +#ifdef DEBUG + + kdDebug() << "in product()" << endl; +#endif + + ++ratio_pointer; + do + { + switch (*op_pointer) + { + case ADD : + case SUB : + return product; /* finished */ + + /* compute the next step of the product (or div) */ + case MUL : + product = product * *ratio_pointer++; + ++op_pointer; + break; + case DIV : + product = product / *ratio_pointer++; + ++op_pointer; + break; + } + } + while (op_pointer != op_vector.end()); + + /* we get here if the product consists of the whole given task starting + * at the point given by the function's parameters */ + return product; +} + +/** generate the operations randomly; return how many mul or div + * are in one block */ +unsigned short task::make_operation(short padd_sub, short pmul_div, + short pnr_ratios) +{ + unsigned short max_product_length = 0; + unsigned short operations = 0; + + /* this is our pointer on the op_vector, set it to the beginning */ + ShortArray::iterator op_pointer; + + /* we need this to generate the fitting operations */ + if (padd_sub == YES) + operations += 2; + if (pmul_div == YES) + operations += 2; + + /* clear the old operations */ + op_vector.clear(); + + /* generate the operations */ + for (short counter = 0; counter < pnr_ratios - 1; counter++) + op_vector.push_back(short((double(rand()) / RAND_MAX) * operations)); + + /* if we only wanted mul/div, operations was 2; but we want values + * for the operations with 2 and 3 so we have to add 2 */ + if (padd_sub == NO && pmul_div == YES) + { + /* loop through all operations and add 2, so that the operations + * are interpreted as mul/div and not add/sub */ + for (op_pointer = op_vector.begin(); + op_pointer != op_vector.end(); op_pointer++) + *op_pointer += 2; + } + + if (pmul_div == YES) + { + short flag_counter = 0; + + /* loop through all operations */ + for (op_pointer = op_vector.begin(); + op_pointer != op_vector.end(); op_pointer++) + { + /* look if we got a mul/div or add/sub */ + if (*op_pointer == DIV || *op_pointer == MUL) + { + flag_counter++; + } + else + { + /* we have to decide, if this was the end of a mul/div block or + * just another add/sub */ + if (flag_counter > 0) + { + /* it was the end of a mul/div block; lets look if it was + * longer than the blocks before and save it; than restart */ + if (flag_counter > max_product_length) + max_product_length = flag_counter; + flag_counter = 0; + } /* if (flag_counter > 0) */ + } /* if (*op_pointer == DIV || *op_pointer == MUL) */ + } /* for (op_pointer = op_vector.begin(); ...) */ + + /* just to correct the things a little bit if the last operation was a + * mul/div as well */ + if (flag_counter > max_product_length) + max_product_length = flag_counter; + max_product_length++; + } + else + { /* if (pmul_div == YES) */ + /* a task is given only with add/sub ops; so we want a max. + * of pnr_ratios / 2 + 1 prime factors, but at least */ + max_product_length = (unsigned short) (float(pnr_ratios) / 2) + 1; + if (max_product_length < 2) + max_product_length = 2; + } /* if (pmul_div == YES) */ + + return max_product_length; +} + +/** find a denominator for the task */ +int task::make_main_dn(unsigned int pmax_md, unsigned short max_product_length) +{ + int denominator; + + /* find a main denominator in the given limits by pmax_md and check + * if the main denominator has enough prime factors */ + do + { + denominator = int(((double(rand()) / RAND_MAX) * pmax_md) + 1); + } + while ((pmax_md < 1) || + (prim_factor_nr(denominator) < max_product_length)); + + return denominator; +} + +/** returns the count number's prime factors and stores the prime factors + * in the prim_fac_vektor vektor */ +unsigned short task::prim_factor_nr(int number) +{ + unsigned int tmp_number = number; + primenumber primenumber; + Tprime_factor prim_fac_struct; + + /* delete all the prime factors of the old main denominator */ + prim_fac_vector.clear(); + + /* test if we can find prime factors */ + for (primenumber.move_first(); primenumber.get_current() <= tmp_number; ) + { + /* if the current selected prime number is a divisor */ + if (tmp_number % primenumber.get_current() != 0) + { + primenumber.move_forward(); /* no, test next one */ + } + else + { + /* yes, we found a new prime factor; so first we use the divisor */ + tmp_number = int(tmp_number / primenumber.get_current()); + + /* now we add the prime factor to our prime factor vector */ + prim_fac_struct.factor = primenumber.get_current(); + prim_fac_struct.flag = UNUSED; + prim_fac_vector.push_back(prim_fac_struct); + } + } +#ifdef DEBUG + PrimeFactorArray::iterator prim_fac_pointer = prim_fac_vector.begin(); + kdDebug() << "Primfaktoren von: " << number << endl; + for (prim_fac_pointer = prim_fac_vector.begin(); + prim_fac_pointer != prim_fac_vector.end(); + prim_fac_pointer++) + kdDebug() << (*prim_fac_pointer).factor << endl; + kdDebug() << "Anzahl: " << prim_fac_vector.size() << endl; +#endif + + return prim_fac_vector.size(); +} + +/** set the numerators randomly */ +void task::make_numerators(int main_denominator, short pnr_ratios) +{ + /* I think it is to easy to deal with ratios like 1/1 or 4/4; so + * I limit the maximum of a numerator */ + int max_numerator = int(main_denominator * float(0.7)); + + /* add a new ratio to the task and compute the numerator randomly */ + for (short tmpcounter = 0; tmpcounter < pnr_ratios; tmpcounter++) + { + (*this).add_ratio(int((double(rand()) / RAND_MAX) + * max_numerator) + 1, 1); + } + return; +} + +/** create the ratios' denominators */ +void task::make_denominators(int main_denominator, short pmax_md, + short pmul_div) +{ + /* this is our pointer on the ratio_vector, set it to the beginning */ + RatioArray::iterator ratio_pointer = ratio_vector.begin(); + + /* this is our pointer on the op_vector, set it to the beginning */ + ShortArray::iterator op_pointer = op_vector.begin() + 1; + + /* this is a pointer on the array with the prime factors of the main + * denominator */ + PrimeFactorArray::iterator prim_fac_pointer; + + unsigned short unused_fac = prim_fac_vector.size(); + unsigned short next_fac; + unsigned short tmp_counter; + int tmp_deno; + + /* check, if ratio number and operation number fit together */ + if (ratio_vector.size() != op_vector.size() + 1) + { + kdDebug() << "Number of ratios and operations do not fit." << endl; + return; + } + + /* first make all denominators */ + for (ratio_pointer = ratio_vector.begin(); + ratio_pointer != ratio_vector.end(); ratio_pointer++) + { + do + { + tmp_deno = int((double(rand()) / RAND_MAX) * pmax_md) + 1; + } + while (main_denominator % tmp_deno != 0); + (*ratio_pointer).setDenominator(tmp_deno); + } + + /* if the ratio is connected to a mul or div operation, we have to do some + * extra work and regenerate the denominators */ + if (pmul_div == YES) + { + /* lets loop through all ratios and check, if there is a mul/div + * after the ratio */ + ratio_pointer = ratio_vector.begin(); + op_pointer = op_vector.begin(); + do + { + if (*op_pointer == MUL || *op_pointer == DIV) + { + /* yes, there is a mul/div after the ratio; + * reset the prime number structure */ + for (prim_fac_pointer = prim_fac_vector.begin(); + prim_fac_pointer != prim_fac_vector.end(); + prim_fac_pointer++) + (*prim_fac_pointer).flag = UNUSED; + + /* how many prime factors are avaible? */ + unused_fac = prim_fac_vector.size() - 1; + + /* now loop through this mul/div section until we find a add/sub */ + do + { + /* the prim_fac_vector is sorted, but we do not want the + * factors in this sorted way as our denominators; + * so we choose one randomly */ + next_fac = (unsigned short)((double(rand()) / RAND_MAX) + * unused_fac); + tmp_counter = 0; + + /* check the prime factors, if they are unused */ + for (prim_fac_pointer = prim_fac_vector.begin(); + prim_fac_pointer != prim_fac_vector.end(); + prim_fac_pointer++) + { + if ((*prim_fac_pointer).flag == UNUSED) + { + tmp_counter++; /* we found a unused factor */ + } + /* we found the factor, which we have chosen randomly */ + if (tmp_counter > next_fac) + break; + } + /* mark the factor as used, so we can not use it again in + * this mul/div section */ + (*prim_fac_pointer).flag = USED; + + /* store the factor as our new denominator for this ratio */ + (*ratio_pointer).setDenominator((*prim_fac_pointer).factor, false); + unused_fac--; /* now there is one factor less avaible */ + + /* move to the next ratio */ + ratio_pointer++; + op_pointer++; + } + while ((op_pointer != op_vector.end()) && + (*op_pointer == MUL || *op_pointer == DIV)); + + /* we always miss to set the last ratio in a mul/div section; + * so we have to fix this here */ + if (ratio_pointer != ratio_vector.end()) + { + /* the prim_fac_vector is sorted, but we do not want the + * factors in this sorted way as our denominators; + * so we choose one randomly */ + next_fac = (unsigned short)((double(rand()) / RAND_MAX) + * unused_fac); + tmp_counter = 0; + + /* check the prime factors, if they are unused */ + for (prim_fac_pointer = prim_fac_vector.begin(); + prim_fac_pointer != prim_fac_vector.end(); + prim_fac_pointer++) + { + if ((*prim_fac_pointer).flag == UNUSED) + { + tmp_counter++; /* we found a unused factor */ + } + /* we found the factor, which we have chosen randomly */ + if (tmp_counter > next_fac) + break; + } + /* mark the factor as used, so we can not use it again in + * this mul/div section */ + (*prim_fac_pointer).flag = USED; + + /* store the factor as our new denominator for this ratio */ + (*ratio_pointer).setDenominator((*prim_fac_pointer).factor, false); + unused_fac--; /* now there is one factor less avaible */ + + /* move to the next ratio */ + ratio_pointer++; + op_pointer++; + } + } + else + { /* if (*op_pointer == MUL || ...) */ + ratio_pointer++; + op_pointer++; + } + } + while (ratio_pointer != ratio_vector.end() && + op_pointer != op_vector.end()); + + /* now we will swap all ratios, if there is a div in front of */ + ratio_pointer = ratio_vector.begin(); + ratio_pointer++; + + for (op_pointer = op_vector.begin(); op_pointer != op_vector.end(); + op_pointer++) + { + if (*op_pointer == DIV) + { + (*ratio_pointer).reziproc(); + } + ratio_pointer++; + } + } /* if (pmul_div == YES) */ + + return; +} + + +/* ------ some prototyps of non class functions ------ */ + +/** it is possible to code: cout << task_object << endl; */ +QTextStream & operator<<(QTextStream & str, task & ptask) +{ + return ptask.display(str); +} diff --git a/kbruch/src/task.h b/kbruch/src/task.h new file mode 100644 index 00000000..3e4c15b6 --- /dev/null +++ b/kbruch/src/task.h @@ -0,0 +1,167 @@ +/*************************************************************************** + task.h - class task + ------------------- + begin : Tue Nov 27 16:40:42 CET 2001 + copyright : (C) 2001 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. * + * * + ***************************************************************************/ + +#ifndef TASK_H +#define TASK_H + +#include "ratio.h" +#include "primenumber.h" + +#include <vector> + +/** important for add_sub and mul_div */ +#define YES 1 +#define NO 0 + +/** important for op_vector */ +#define ADD 0 +#define SUB 1 +#define MUL 2 +#define DIV 3 + +/** to mark a prime factor as used or unused */ +#define UNUSED 0 +#define USED 1 + +/** Structure represents a prime factor. + * Structure stores a prime factor and its usage status. The factor is marked + * as used or unused. + **/ +typedef struct PRIME_FACTOR +{ + /** the prime factor */ + int factor; + + /** the status of the prime factor (used or unused) */ + short flag; +} +Tprime_factor; + +/** we use the vector template class to create 3 dynamic types */ +typedef QValueVector<ratio> RatioArray; +typedef QValueVector<short> ShortArray; +typedef QValueVector<Tprime_factor> PrimeFactorArray; + +/*! class to handle mathematical tasks with ratios + * naming: + * - a task has at least 2 ratios + * - a task has at least 1 operation + * + * \author Sebastian Stein */ +class task +{ +public: + /** constructor */ + task(); + + /** destructor */ + ~task(); + + /** automatically generate a new task with the given parameters */ + void create_task(unsigned int pmax_md = 10, short pnr_ratios = 2, + short padd_sub = YES, short pmul_div = NO); + + /** set ratio n */ + void set_ratio_n(unsigned short number = 0, int numerator = 0, + int denominator = 1); + + /** set ratio n */ + void set_ratio_n(unsigned short number = 0, ratio fraction = 0); + + /** returns ration n */ + ratio get_ratio_n(unsigned short number = 0) const; + + /** set operation n */ + void set_op_n(unsigned short number = 0, short operation = ADD); + + /** return operation n */ + short get_op_n(unsigned short number = 0) const; + + /** add a ratio to the end of the task */ + void add_ratio(ratio new_ratio = 0); + + /** add a ratio to the end of the task */ + void add_ratio(int numerator = 0, int denominator = 1); + + /** add an operation at the end of the task */ + void add_operation(short operation = ADD); + + /** display the whole task, mainly for debug */ + QTextStream & display(QTextStream & str); + + /** solves the task and returns the result as ratio */ + ratio solve(); + + /** returns the number of ratios in the vector */ + int getNumberOfRatios() const; + + /** returns the number of operations in the vector */ + int getNumberOfOperations() const; + +private: + /** max. size of main denominator */ + int max_md; + + /** how many ratios should the task have */ + short nr_ratios; + + /** are add/sub operations allowed */ + short add_sub; + + /** are mul/div operations allowed */ + short mul_div; + + /** the ratio vector */ + RatioArray ratio_vector; + + /** the operation vector, smaller by one than ratio_vector */ + ShortArray op_vector; + + /** the prime factor vector is used to store all prime factors of the + * main denominator */ + PrimeFactorArray prim_fac_vector; + + /** this function is needed by solve() */ + ratio product(RatioArray::iterator & ratio_pointer, + ShortArray::iterator & op_pointer); + + /** generate the operations randomly; return how many mul or div + * are in one block */ + unsigned short make_operation(short padd_sub, short pmul_div, + short pnr_ratios); + + /** find a denominator for the task */ + int make_main_dn(unsigned int pmax_md, unsigned short max_product_length); + + /** returns the count number's prime factors */ + unsigned short prim_factor_nr(int number = 1); + + /** set the numerators randomly */ + void make_numerators(int main_denominator, short pnr_ratios); + + /** create the ratios' denominators */ + void make_denominators(int main_denominator, short pmax_md, + short pmul_div); +}; + + +/* ------ some prototypes of non class functions ------ */ + +/** it is possible to code: cout << task_object << endl; */ +QTextStream & operator<<(QTextStream & str, task & ptask); + +#endif diff --git a/kbruch/src/taskview.cpp b/kbruch/src/taskview.cpp new file mode 100644 index 00000000..aba064a1 --- /dev/null +++ b/kbruch/src/taskview.cpp @@ -0,0 +1,387 @@ +/*************************************************************************** + taskview.cpp - The task window + ------------------- + begin : Tue Feb 08 13:41:00 CET 2002 + copyright : (C) 2001 - 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 "taskview.h" +#include "taskview.moc" + +/* these includes are needed for KDE support */ +#include <klocale.h> +#include <kmessagebox.h> +#include <kapplication.h> +#include <knumvalidator.h> + +/* these includes are needed for Qt support */ +#include <qlabel.h> +#include <qlayout.h> +#include <qlineedit.h> +#include <qpushbutton.h> +#include <qtooltip.h> +#include <qwhatsthis.h> + +/* standard C++ library includes */ +#include <math.h> + +/* ----- public member functions ----- */ + +/* constructor */ +TaskView::TaskView(QWidget * parent, const char * name, bool padd_sub, + bool pmul_div, unsigned int pnr_ratios, unsigned int pmax_md): + ExerciseBase(parent, name), add_sub(padd_sub), mul_div(pmul_div), + nr_ratios(pnr_ratios), max_md(pmax_md) +{ +#ifdef DEBUG + kdDebug() << "constructor TaskView()" << endl; +#endif + + curr_nr_ratios = nr_ratios; + + /* create a new task */ + QApplication::setOverrideCursor(waitCursor); /* show the sand clock */ + current_task.create_task(max_md, nr_ratios, add_sub, mul_div); + QApplication::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 QWidget(this, "baseWidget"); + baseGrid = new QGridLayout(this, 1, 1, 0, -1, "baseGrid"); + baseGrid->addWidget(baseWidget, 0, 0); + + // this is a VBox + realLayout = new QVBoxLayout(baseWidget, 5, 5, "realLayout"); + + // add a spacer at the top of the VBox + QSpacerItem * v_spacer = new QSpacerItem(1, 1); + realLayout->addItem(v_spacer); + + // now a line holding the task, input fields and result + QHBoxLayout * taskLineHBoxLayout = new QHBoxLayout(5, "taskLineHBoxLayout"); + realLayout->addLayout(taskLineHBoxLayout); + + // first left is the task widget + m_taskWidget = new TaskWidget(baseWidget, "m_taskWidget", current_task); + + // now we have the input fields aligned in a VBox + QVBoxLayout * inputLayout = new QVBoxLayout(5, "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 QLineEdit(baseWidget, "numer_edit"); + numer_edit->setValidator( valnum ); // use the int validator + QToolTip::add(numer_edit, i18n("Enter the numerator of your result")); + inputLayout->addWidget(numer_edit); + + /* add a line between the edit boxes */ + edit_line = new QFrame(baseWidget, "edit_line"); + edit_line->setGeometry(QRect(100, 100, 20, 20)); + edit_line->setFrameStyle(QFrame::HLine | QFrame::Sunken); + inputLayout->addWidget(edit_line); + + /* add input box so the user can enter denominator */ + deno_edit = new QLineEdit(baseWidget, "deno_edit"); + deno_edit->setValidator( valnum ); // use the int validator + QToolTip::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", *new ratio()); + + // at the right end we have a label just showing CORRECT or WRONG + result_label = new QLabel(baseWidget, "result_label"); + result_label->setText(i18n("WRONG")); + result_label->hide(); + + // add another spacer in the middle of the VBox + v_spacer = new QSpacerItem(1, 1, QSizePolicy::Expanding, QSizePolicy::Minimum); + + // --- that is the end of the horizontal line --- + // in RTL desktops, we still need to allign the + // execise to the left. On Qt4, you can set the direction + // of the layout to LTR (instead of inherit), but on Qt3 + // 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 (QApplication::reverseLayout()) + { + taskLineHBoxLayout->addItem(v_spacer); + taskLineHBoxLayout->addWidget(result_label); + taskLineHBoxLayout->addWidget(m_resultWidget); + taskLineHBoxLayout->addLayout(inputLayout); + taskLineHBoxLayout->addWidget(m_taskWidget); + } + else + { + taskLineHBoxLayout->addWidget(m_taskWidget); + 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 QSpacerItem(1, 1); + realLayout->addItem(v_spacer); + + + // the lower part of the VBox holds just a right aligned button + QHBoxLayout * lowerHBox = new QHBoxLayout(1, "lowerHBox"); + realLayout->addLayout(lowerHBox); + lowerHBox->addStretch(100); + + // the right aligned button + m_checkButton = new QPushButton( baseWidget, "m_checkButton" ); + m_checkButton->setText(i18n("&Check Task")); + m_checkButton->setDefault(true); // is the default button of the dialog + 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.")); + lowerHBox->addWidget(m_checkButton, 1, Qt::AlignRight); + QObject::connect(m_checkButton, SIGNAL(clicked()), this, SLOT(slotCheckButtonClicked())); + + // that the user can start typing without moving the focus + numer_edit->setFocus(); + + // show the whole layout + baseWidget->show(); + + // show the whole layout + m_taskWidget->show(); + m_resultWidget->hide(); + + // add tooltip and qwhatsthis help to the widget + QToolTip::add(this, i18n("In this exercise you have to solve a given task with fractions.")); + 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!")); +} + +/* destructor */ +TaskView::~TaskView() +{ +#ifdef DEBUG + kdDebug() << "destructor TaskView()" << endl; +#endif + + /* no need to delete any child widgets, Qt does it by itself */ +} + +/** the parameters of task generation can be set with this function */ +void TaskView::setTaskParameters(bool padd_sub, bool pmul_div, unsigned int pnr_ratios, unsigned int pmax_md) +{ + // at least one operation must be enabled + if ((padd_sub == false) && (pmul_div == false)) + padd_sub = true; + + // we need at least 2 ratios + if (pnr_ratios < 2) + pnr_ratios = 2; + + // we can only visualize 5 ratios, so we have to limit it + if (pnr_ratios > 5) + pnr_ratios = 5; + + // the main denominator must be at least 2^pnr_ratios + if (pow(2, pnr_ratios) > pmax_md) + pmax_md = (unsigned int) pow(2, pnr_ratios); + + // so everything seems to be fine, lets set the internal values to the given + // ones + add_sub = padd_sub; + mul_div = pmul_div; + max_md = pmax_md; + + nr_ratios = pnr_ratios; + + return; +} + +/** 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 TaskView::forceNewTask() +{ +#ifdef DEBUG + kdDebug() << "forceNewTask TaskView()" << endl; +#endif + + if (m_currentState == _CHECK_TASK) + { + // emit the signal for wrong + signalTaskSolvedWrong(); + } + m_currentState = _CHECK_TASK; + m_checkButton->setText(i18n("&Check Task")); + + // generate next task + (void) nextTask(); +} + + +/* ------ public slots ------ */ + +void TaskView::update() +{ + // call update of components + m_taskWidget->updateAndRepaint(); + m_resultWidget->updateAndRepaint(); + + // update for itself + ((QWidget *) this)->update(); +} + + +/* ------ private member functions ------ */ + +/** - checks the entered result and compares it to the task's result + - shows the correct result and informs the user if he was right or wrong + - if the user entered the result unreduced, he will be informed about it + - if the user entered a 0 for the denominator, he will be informed about + it (division by zero) + - emits signals if task was solved right or wrong */ +void TaskView::showResult() +{ + QString tmp_str; /* to build a string for a label */ + QPalette pal; + QColorGroup cg; + + // change the tooltip of the check button + QToolTip::add(m_checkButton, i18n("Click on this button to get to the next task.")); + + numer_edit->setEnabled(false); + deno_edit->setEnabled(false); + + result = current_task.solve(); + m_resultWidget->setResult(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 == result) || + (result.numerator() == 0 && entered_result.numerator() == 0)) ) + { + // emit the signal for correct + signalTaskSolvedCorrect(); + + /* 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(QColorGroup::Foreground, QColor(6, 179, 0)); + pal.setActive(cg); + cg = pal.inactive(); + cg.setColor(QColorGroup::Foreground, QColor(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 + signalTaskSolvedWrong(); + + /* 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(QColorGroup::Foreground, QColor(red)); + pal.setActive(cg); + cg = pal.inactive(); + cg.setColor(QColorGroup::Foreground, QColor(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 == 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) */ +} + +/** generate the next task and show it to the user */ +void TaskView::nextTask() +{ + // change the tooltip of the check button + 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.")); + + 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 */ + QApplication::setOverrideCursor(waitCursor); /* show the sand clock */ + current_task.create_task(max_md, nr_ratios, add_sub, mul_div); + QApplication::restoreOverrideCursor(); /* show the normal cursor */ + + // update the task widget + m_taskWidget->setTask((const task) (current_task)); +} + +/* ------ private slots ------ */ + +void TaskView::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(); + } +} diff --git a/kbruch/src/taskview.h b/kbruch/src/taskview.h new file mode 100644 index 00000000..60c3e75c --- /dev/null +++ b/kbruch/src/taskview.h @@ -0,0 +1,113 @@ +/*************************************************************************** + taskview.cpp - Header File + ------------------- + begin : Tue Feb 08 13:42:00 CET 2002 + copyright : (C) 2001 - 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. * + * * + ***************************************************************************/ + +#ifndef TASKVIEW_H +#define TASKVIEW_H + +#define _CHECK_TASK 0 +#define _NEXT_TASK 1 + +#include "exercisebase.h" +#include "resultwidget.h" +#include "task.h" +#include "taskwidget.h" + +#ifdef DEBUG +#include <kdebug.h> +#endif + +#include <qwidget.h> + + +class QVBoxLayout; +class QHBoxLayout; +class QGridLayout; +class QSpacerItem; +class QLabel; +class QPushButton; +class QLineEdit; +class QFrame; + +/*! Constructs a QWidget, which shows the task to the user. + * The class also provides input fields, so that the user can enter the result. + * It also controls the interaction, so that the entered result gets checked + * and a new task can be generated. + * \author Sebastian Stein + * */ +class TaskView : public ExerciseBase +{ + Q_OBJECT + +public: + /** constructor */ + TaskView(QWidget * parent = 0, const char * name = 0, + bool padd_sub = true, bool pmul_div = false, + unsigned int pnr_ratios = 2, unsigned int pmax_md = 10); + + /** destructor */ + ~TaskView(); + + /** set new task parameters, which will be used for the next task to be + * generated */ + void setTaskParameters(bool padd_sub, bool pmul_div, unsigned int pnr_ratios, unsigned int pmax_md); + + /** force the creation of a new task */ + void forceNewTask(); + +public slots: + void update(); + +signals: + /** class emits this signal, if the task was solved correctly by the user */ + void signalTaskSolvedCorrect(); + + /** class emits this signal, if the task was solved not correctly by the user + * */ + void signalTaskSolvedWrong(); + +private: + bool add_sub; + bool mul_div; + unsigned int nr_ratios; + unsigned int curr_nr_ratios; + unsigned int max_md; + short m_currentState; + + ResultWidget* m_resultWidget; + QPushButton* m_checkButton; + QLabel* result_label; + TaskWidget* m_taskWidget; + QLineEdit* numer_edit; + QFrame* edit_line; + QLineEdit* deno_edit; + + QGridLayout* baseGrid; + QWidget* baseWidget; + QVBoxLayout* realLayout; + + task current_task; + ratio result; + ratio entered_result; + + void showResult(); + void nextTask(); + +private slots: + void slotCheckButtonClicked(); +}; + +#endif diff --git a/kbruch/src/taskvieweroptionsbase.ui b/kbruch/src/taskvieweroptionsbase.ui new file mode 100644 index 00000000..97cba6ed --- /dev/null +++ b/kbruch/src/taskvieweroptionsbase.ui @@ -0,0 +1,224 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>TaskViewerOptionsBase</class> +<widget class="QWidget"> + <property name="name"> + <cstring>TaskViewerOptionsBase</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>414</width> + <height>550</height> + </rect> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLayoutWidget" row="0" column="0"> + <property name="name"> + <cstring>layout2</cstring> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="KFontChooser"> + <property name="name"> + <cstring>kcfg_taskFont</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>1</hsizetype> + <vsizetype>3</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="toolTip" stdset="0"> + <string>Change the font of the numbers</string> + </property> + </widget> + <widget class="QGroupBox"> + <property name="name"> + <cstring>colorGroupBox</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>5</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="title"> + <string>Colors</string> + </property> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout7</cstring> + </property> + <property name="geometry"> + <rect> + <x>10</x> + <y>20</y> + <width>230</width> + <height>110</height> + </rect> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="KColorButton" row="1" column="1"> + <property name="name"> + <cstring>kcfg_operationColor</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>1</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string></string> + </property> + <property name="color"> + <color> + <red>0</red> + <green>0</green> + <blue>255</blue> + </color> + </property> + <property name="toolTip" stdset="0"> + <string>Change the color of the operation signs</string> + </property> + </widget> + <widget class="KColorButton" row="2" column="1"> + <property name="name"> + <cstring>kcfg_fractionBarColor</cstring> + </property> + <property name="text"> + <string></string> + </property> + <property name="color"> + <color> + <red>255</red> + <green>0</green> + <blue>0</blue> + </color> + </property> + <property name="toolTip" stdset="0"> + <string>Change the color of the fraction bar</string> + </property> + </widget> + <widget class="QLabel" row="2" column="0"> + <property name="name"> + <cstring>fractionBarLabel</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>1</hsizetype> + <vsizetype>5</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Fraction bar:</string> + </property> + </widget> + <widget class="QLabel" row="1" column="0"> + <property name="name"> + <cstring>operationLabel</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>1</hsizetype> + <vsizetype>5</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Operation sign:</string> + </property> + </widget> + <widget class="KColorButton" row="0" column="1"> + <property name="name"> + <cstring>kcfg_numberColor</cstring> + </property> + <property name="text"> + <string></string> + </property> + <property name="color"> + <color> + <red>0</red> + <green>255</green> + <blue>0</blue> + </color> + </property> + <property name="toolTip" stdset="0"> + <string>Change the color of the numbers</string> + </property> + </widget> + <widget class="QLabel" row="0" column="0"> + <property name="name"> + <cstring>numberLabel</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>1</hsizetype> + <vsizetype>5</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Number:</string> + </property> + </widget> + </grid> + </widget> + </widget> + <widget class="QGroupBox"> + <property name="name"> + <cstring>groupBox2</cstring> + </property> + <property name="title"> + <string>General</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QCheckBox" row="0" column="0"> + <property name="name"> + <cstring>kcfg_showSpecialRatioNotation</cstring> + </property> + <property name="text"> + <string>Show result also as a mixed number, like 1 2/3.</string> + </property> + <property name="toolTip" stdset="0"> + <string>Here you can enable/disable showing the result in mixed-number notation.</string> + </property> + </widget> + </grid> + </widget> + </vbox> + </widget> + </grid> +</widget> +<customwidgets> +</customwidgets> +<layoutdefaults spacing="6" margin="11"/> +<includehints> + <includehint>kfontdialog.h</includehint> + <includehint>kcolorbutton.h</includehint> + <includehint>kcolorbutton.h</includehint> + <includehint>kcolorbutton.h</includehint> +</includehints> +</UI> diff --git a/kbruch/src/taskwidget.cpp b/kbruch/src/taskwidget.cpp new file mode 100644 index 00000000..378b7afb --- /dev/null +++ b/kbruch/src/taskwidget.cpp @@ -0,0 +1,130 @@ +/*************************************************************************** + taskwidget.cpp - paint a task + ------------------- + begin : 2004/05/30 + 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 "taskwidget.h" +#include "taskwidget.moc" + +/* these includes are needed for KDE support */ +#include <klocale.h> + +/* these includes are needed for Qt support */ +#include <qpainter.h> + +TaskWidget::TaskWidget(QWidget * parent = 0, const char * name = 0, + const task para_task = *new task()) : + FractionBaseWidget(parent, name), m_task(para_task) +{ +#ifdef DEBUG + kdDebug() << "constructor TaskWidget" << endl; +#endif +} + +TaskWidget::~TaskWidget() +{ +#ifdef DEBUG + kdDebug() << "destructor TaskWidget" << endl; +#endif +} + +void TaskWidget::setTask(const task para_task) +{ + m_task = para_task; + update(); +} + +void TaskWidget::paintEvent(QPaintEvent* /* p_paintEvent */) +{ + // our x position, we paint from left to right; + // we don't want to start directly on the border, so add the margin + int old_x = _MARGIN_X; + + // strings holding numerator, denominator and the operation sign + QString str_numerator, str_denominator, str_operation; + + // operation sign as number + short tmp_operation; + + // start the painter + QPainter paint(this); + + // ratios and operation signs are painted with the same font + paint.setFont(m_font); + + // set the pen for painting + QPen pen(Qt::SolidLine); + pen.setWidth(0); + paint.setPen(pen); + + // get the font height; the font height doesn't change while painting + QFontMetrics fm(paint.fontMetrics()); + + // now we can correctly set the height of the widget + setMinimumHeight(2 * fm.lineSpacing() + 10); + setMaximumHeight(2 * fm.lineSpacing() + 10); + + // loop through all ratios and paint them + for (unsigned short tmp_counter = 0; tmp_counter < m_task.getNumberOfRatios(); tmp_counter++) + { + // get the current ratio and paint it + paintRatio(paint, m_task.get_ratio_n(tmp_counter), old_x, fm, false); + + // now check if we have another operation to show + // if not we will stop showing ratios as well + if (tmp_counter < m_task.getNumberOfOperations()) + { + // get the operation sign + tmp_operation = m_task.get_op_n(tmp_counter); + + // we have to convert the operation sign into a string + switch (tmp_operation) + { + case ADD : + str_operation = "+"; + break; + case SUB : + str_operation = "-"; + break; + case MUL : + str_operation = "x"; + break; + case DIV : + // there seems to be different division signs around the world + // so please translate it to the right one for your country + str_operation = i18n("division symbol", "/"); + break; + } /* switch (operation) */ + + // paint the operation + paintMiddle(paint, str_operation, old_x, fm, m_colorOperation); + + } else { + // no further operations to show, so we always show the = sign at the + // end of a task + paintMiddle(paint, "=", old_x, fm, m_colorOperation); + + break; + } // if (tmp_counter < m_task.getNumberOfOperations()) + } + + // stop the painter + paint.end(); + + // the space we needed for painting is the minimum width of the widget + setMinimumWidth(old_x); + + return; +} diff --git a/kbruch/src/taskwidget.h b/kbruch/src/taskwidget.h new file mode 100644 index 00000000..e25ef3d3 --- /dev/null +++ b/kbruch/src/taskwidget.h @@ -0,0 +1,66 @@ +/*************************************************************************** + taskwidget.h - paint a task + ------------------- + begin : 2004/05/30 + 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. * + * * + ***************************************************************************/ + +#ifndef TASKWIDGET_H +#define TASKWIDGET_H + +#ifdef DEBUG +#include <kdebug.h> +#endif + +#include "fractionbasewidget.h" +#include "task.h" + +#include <qwidget.h> + +/** important for add_sub and mul_div */ +#define YES 1 +#define NO 0 + +/** important for op_vector */ +#define ADD 0 +#define SUB 1 +#define MUL 2 +#define DIV 3 + +/*! class to paint task with fractions + * + * \author Sebastian Stein */ +class TaskWidget : public FractionBaseWidget +{ + Q_OBJECT + +public: + /** constructor */ + TaskWidget(QWidget * parent, const char * name, const task para_task); + + /** destructor */ + ~TaskWidget(); + + /** set the task to be displayed */ + void setTask(const task para_task); + +private: + + /** the task to be displayed */ + task m_task; + + /** overrideing the paint event of FractionBaseWidget */ + void paintEvent(QPaintEvent*); +}; + +#endif |