248 lines
9.5 KiB
C++
248 lines
9.5 KiB
C++
/***************************************************************************
|
||
* Copyright (C) 2003-2007 by Oliver Saal *
|
||
* osaal@gmx.de *
|
||
* http://www.oliver-saal.de/software/afutrainer/ *
|
||
* *
|
||
* 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. *
|
||
* *
|
||
* This program is distributed in the hope that it will be useful, *
|
||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||
* GNU General Public License for more details. *
|
||
* *
|
||
* You should have received a copy of the GNU General Public License *
|
||
* along with this program; if not, write to the *
|
||
* Free Software Foundation, Inc., *
|
||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||
***************************************************************************/
|
||
|
||
#ifndef QUESTION_H
|
||
#define QUESTION_H
|
||
|
||
#include <qstring.h>
|
||
#include <qdom.h>
|
||
#include <qlist.h>
|
||
#include <qdatetime.h>
|
||
#include <qstringlist.h>
|
||
#include <qicon.h>
|
||
#include <qpixmap.h>
|
||
|
||
#include "answer.h"
|
||
#include "helper.h"
|
||
|
||
unsigned afu_random (const unsigned uMin, const unsigned uMax);
|
||
|
||
class CChapter;
|
||
|
||
#define LEVEL_VERYOFTEN 0
|
||
#define LEVEL_OFTEN 1
|
||
#define LEVEL_NORMAL 2
|
||
#define LEVEL_RARE 3
|
||
#define LEVEL_VERYRARE 4
|
||
#define LEVEL_EXTREMERARE 5
|
||
#define LEVEL_MAX 5
|
||
|
||
class CDayStatistic
|
||
{
|
||
public:
|
||
CDayStatistic() { clear(); }
|
||
~CDayStatistic() {}
|
||
|
||
void clear();
|
||
|
||
inline QDate date() const { return m_date; }
|
||
|
||
inline unsigned clickedCount() const { return m_uClickedWrong + m_uClickedCorrect; }
|
||
inline unsigned clickedCorrect() const { return m_uClickedCorrect; }
|
||
inline unsigned clickedWrong() const { return m_uClickedWrong; }
|
||
inline unsigned timeExpediture() const { return m_uTimeExpeditureCorrect + m_uTimeExpeditureWrong; }
|
||
inline unsigned timeExpeditureCorrect() const { return m_uTimeExpeditureCorrect; }
|
||
inline unsigned timeExpeditureWrong() const { return m_uTimeExpeditureWrong; }
|
||
|
||
inline unsigned levelRounded() const { return (unsigned) (m_dLevel + 0.5); }
|
||
inline double level() const { return m_dLevel; }
|
||
|
||
CDayStatistic& operator += (const CDayStatistic& ds);
|
||
|
||
void debug() const;
|
||
|
||
protected:
|
||
QDate m_date;
|
||
unsigned m_uClickedWrong;
|
||
unsigned m_uClickedCorrect;
|
||
unsigned m_uTimeExpeditureCorrect;
|
||
unsigned m_uTimeExpeditureWrong;
|
||
double m_dLevel;
|
||
|
||
friend class CQuestion;
|
||
friend class CChapter;
|
||
};
|
||
|
||
//! CQuestion speichert eine Frage mit allen Antworten und der Klick-Statistik.
|
||
|
||
class CQuestion
|
||
{
|
||
public:
|
||
//! Standard-Konstruktor
|
||
/*! Initialisiert die Klasse, indem die Funktion clear() aufgerufen wird. */
|
||
CQuestion() { clear(); }
|
||
//! Standard-Destruktor
|
||
/*! In der Standard-Implementierung tut der Destruktor nichts. */
|
||
~CQuestion() {}
|
||
|
||
/** @name Basisdaten
|
||
* Auslesen und setzen der Basisdaten einer Frage
|
||
*/
|
||
//@{
|
||
//! Zur<75>cksetzen aller Werte
|
||
/*! Es werden alle Daten der Frage gel<65>scht. */
|
||
void clear();
|
||
|
||
//! Elternkapitel abfragen
|
||
/*!
|
||
\return Elternkapitel m_pParentChapter
|
||
\sa CChapter, setParentChapter(), m_pParentChapter
|
||
*/
|
||
inline CChapter* parentChapter() const { return m_pParentChapter; }
|
||
|
||
//! Elternkapitel setzen
|
||
/*!
|
||
Durch diese Funktion wird lediglich die Variable m_pParentChapter gesetzt, jedoch nicht die Statistiken
|
||
des Eltern-Kapitels aktualisiert.
|
||
|
||
\param pChapter Das zu setzende Elternkapitel der Frage
|
||
\sa CChapter, parentChapter(), m_pParentChapter
|
||
*/
|
||
inline void setParentChapter(CChapter *pChapter) { m_pParentChapter = pChapter; }
|
||
//! ID abfragen
|
||
inline QString id() const { return m_strId; }
|
||
//! Text abfragen
|
||
inline QString text() const { return m_strText; }
|
||
|
||
//! ID setzen
|
||
inline void setId(const QString& strId) { m_strId = strId; }
|
||
//! Text setzen
|
||
inline void setText(const QString& strText) { m_strText = strText; }
|
||
|
||
//! Anh<6E>ngen eines Textes an den Fragentext
|
||
/*!
|
||
\param strText Anzuh<75>ngender Text
|
||
\sa m_strText
|
||
*/
|
||
inline void appendText(const QString& strText) { m_strText += strText; }
|
||
//@}
|
||
|
||
QString plainText() const;
|
||
QString firstTextLine() const;
|
||
|
||
QString showText(CCatalog *pCatalog) const;
|
||
QString learnText(CCatalog *pCatalog, const bool bShowId=true, const bool bShowHints=false);
|
||
|
||
inline unsigned errorPoints() const { return m_uErrorPoints; }
|
||
inline void setErrorPoints (const unsigned u) { m_uErrorPoints = u; }
|
||
|
||
QStringList groups() const { return m_strlGroups; }
|
||
|
||
bool load (QDomElement elem);
|
||
void save (QDomElement& parent, QDomDocument& doc);
|
||
static QString removeTempPath(const QString& strText);
|
||
bool loadLearnStatistic (QDomElement elem);
|
||
bool saveLearnStatistic (QDomElement& parent, QDomDocument& doc);
|
||
QString checkForErrors() const;
|
||
|
||
// answers
|
||
inline int countAnswer() const { return m_listAnswer.size(); }
|
||
inline const CAnswer& answerAt(int i) const { return m_listAnswer.at(i); }
|
||
inline CAnswer& answerAt(int i) { return m_listAnswer[i]; }
|
||
inline void appendAnswer(const CAnswer& a) { m_listAnswer.append(a); }
|
||
int countCorrectAnswer() const;
|
||
|
||
// helpers
|
||
// inline bool hasHints() const { return !m_listHint.isEmpty(); }
|
||
|
||
// learning
|
||
void mixAnswers(const bool bMix=true);
|
||
const CAnswer& learnAnswerAt(int i) const;
|
||
unsigned correctAnswerMask() const;
|
||
inline bool isCorrectAnswer (const unsigned uAnswerMask) const { return uAnswerMask == correctAnswerMask(); }
|
||
unsigned orderedAnswerMask(const unsigned uMixedAnswerMask);
|
||
void registerAnswerClicked (const unsigned uAnswerMask, const unsigned uNeededTime);
|
||
static QString answerMaskToString(const unsigned uAnswerMask);
|
||
QString correctionText(const unsigned uAnswerMask);
|
||
|
||
// statistics
|
||
//! Abfrageh<65>ufigkeit der Frage
|
||
inline unsigned level() const { return m_uLevel; }
|
||
inline QString levelIconName() const { return levelIconName (m_uLevel); }
|
||
inline QIcon levelIcon() const { return levelIcon (m_uLevel); }
|
||
inline QPixmap levelPixmap() const { return QPixmap(levelIconName (m_uLevel)); }
|
||
inline QString levelText() const { return levelText (m_uLevel); }
|
||
inline int clickedCount() const { return m_listAnswerClicked.size(); }
|
||
inline unsigned clickedCorrect() const { return m_uCorrectAnswers; }
|
||
inline unsigned clickedWrong() const { return m_uWrongAnswers; }
|
||
inline unsigned clickedCorrectSuccessive() const { return m_uCorrectSuccessive; }
|
||
inline unsigned clickedWrongSuccessive() const { return m_uWrongSuccessive; }
|
||
inline bool isNeverAsked() const { return m_listAnswerClicked.isEmpty(); }
|
||
|
||
unsigned levelAtEndOfDay(const QDate& date) const; //!< Lernfortschritt am Ende eines bestimmten Tages
|
||
CDayStatistic dayStatistic(const QDate& date) const;
|
||
|
||
QDateTime firstClicked() const;
|
||
QDateTime lastClicked() const;
|
||
QString lastClickedText() const;
|
||
QString lastClickedTextExtended() const;
|
||
QDate repeatDate() const; //!< Wiederhol-Datum der Frage bestimmen
|
||
QString repeatDateText() const;
|
||
QString repeatDateTextExtended() const;
|
||
bool isRepeatToday() const; //!< Frage sollte heute wiederholt werden
|
||
|
||
bool isLearningNew() const; //!< Ist dies eine neue Frage, die gerade gelernt wird?
|
||
bool isKnownQuestion() const; //!< Ist die Frage schon (l<>nger) bekannt?
|
||
|
||
//! Name des Icons einer bestimmten Abfrageh<65>ufigkeit ermitteln
|
||
static QString levelIconName(const unsigned uLevel);
|
||
//! Icon einer bestimmten Abfrageh<65>ufigkeit
|
||
static QIcon levelIcon(const unsigned uLevel);
|
||
//! Name einer bestimmten Abfrageh<65>ufigkeit
|
||
static QString levelText(const unsigned uLevel);
|
||
static QString tr (const char *sourceText, const char *comment=0);
|
||
//! Berechnung der Wartezeit f<>r eine bestimmte Abfrageh<65>ufigkeit
|
||
static unsigned waitDaysForRepeat (const unsigned uLevel);
|
||
|
||
protected:
|
||
|
||
CChapter *m_pParentChapter; //!< Zeiger auf das (Eltern-) Kapitel, zu dem die Frage geh<65>rt.
|
||
// masterdata
|
||
QString m_strId; //!< ID der Frage
|
||
QString m_strText; //!< Fragentext
|
||
QList<CAnswer> m_listAnswer; //!< Liste mit Antworten
|
||
unsigned m_uErrorPoints; //!< Fehlerpunkte bei Falschantwort in Pr<50>fung
|
||
QStringList m_strlGroups; //!< Liste der Klassen/Gruppen, zu denen diese Frage geh<65>rt
|
||
|
||
// learning
|
||
//! Durchmischte Antworten
|
||
/*! Die Liste enth<74>lt die Positionen der Liste m_listAnswer */
|
||
QList<int> m_listMixedAnswer;
|
||
|
||
// Statistics
|
||
QList<CAnswerClicked> m_listAnswerClicked; //!< Liste mit s<>mtlichen Antwort-Klicks
|
||
unsigned m_uCorrectAnswers; //!< Anzahl der richtigen Antworten
|
||
unsigned m_uCorrectSuccessive; //!< Anzahl der richtigen Antworten zuletzt hintereinander
|
||
unsigned m_uWrongAnswers; //!< Anzahl der falschen Antworten
|
||
unsigned m_uWrongSuccessive; //!< Anzahl der falschen Antworten zuletzt hintereinander
|
||
|
||
//! Aktuelle Stufe der Abfrageh<65>ufigkeit
|
||
/*!
|
||
Stufe 0: sehr h<>ufige ... Stufe 5: sehr seltene Abfrage
|
||
|
||
Die Abfrageh<65>ufigkeit wird nicht in der Statistik-Datei gespeichert, sondern bei jedem Laden der
|
||
Datei anhand der Beantwortungen in der Vergangenheit neu berechnet.
|
||
*/
|
||
unsigned m_uLevel;
|
||
};
|
||
|
||
#endif
|