2022-06-30 23:13:43 +02:00
|
|
|
|
/***************************************************************************
|
|
|
|
|
* 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<EFBFBD>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<EFBFBD>ufige ... Stufe 5: sehr seltene Abfrage
|
|
|
|
|
|
|
|
|
|
Die Abfrageh<EFBFBD>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
|