809 lines
21 KiB
C++
809 lines
21 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. *
|
|||
|
***************************************************************************/
|
|||
|
|
|||
|
#include "catalog.h"
|
|||
|
#include <qcoreapplication.h>
|
|||
|
|
|||
|
|
|||
|
QString CChapter::tr (const char *sourceText, const char *comment)
|
|||
|
{
|
|||
|
return QCoreApplication::translate("CChapter", sourceText, comment);
|
|||
|
}
|
|||
|
|
|||
|
void CChapter::clear()
|
|||
|
{
|
|||
|
m_pParentChapter=0;
|
|||
|
m_strId.clear();
|
|||
|
m_strText.clear();
|
|||
|
m_strComment.clear();
|
|||
|
m_recom = RecommendationNone;
|
|||
|
m_recom2 = RecommendationNone;
|
|||
|
qDeleteAll(m_listChapter);
|
|||
|
qDeleteAll(m_listQuestion);
|
|||
|
m_bHasLearningNew = false;
|
|||
|
m_bHasKnownQuestions = false;
|
|||
|
m_bHasKnownQuestionsRepeatToday = false;
|
|||
|
m_uNeverAskedCount = 0;
|
|||
|
for (int i=0; i<=LEVEL_MAX; i++) m_uLevelCount[i] = 0;
|
|||
|
for (int i=0; i<=RecommendationMax; i++) m_uRecomCount[i] = 0;
|
|||
|
// m_mapExam.clear();
|
|||
|
}
|
|||
|
|
|||
|
int CChapter::countSubQuestion() const
|
|||
|
{
|
|||
|
int i=0, iRet=0;
|
|||
|
for (i=0; i<m_listChapter.size(); i++)
|
|||
|
iRet += m_listChapter.at(i)->countSubQuestion();
|
|||
|
return (iRet + m_listQuestion.size());
|
|||
|
}
|
|||
|
|
|||
|
bool CChapter::load (QDomElement elem)
|
|||
|
{
|
|||
|
CChapter *pChapter=0;
|
|||
|
|
|||
|
if (elem.tagName () != QString ("chapter")) return false;
|
|||
|
if (!elem.hasAttribute ("name")) return false;
|
|||
|
// if (pParent != NULL && !elem.hasAttribute ("id")) return false;
|
|||
|
m_strId = elem.attribute ("id");
|
|||
|
m_strText = elem.attribute ("name");
|
|||
|
QDomNode n = elem.firstChild();
|
|||
|
while (!n.isNull())
|
|||
|
{
|
|||
|
if (n.isElement ())
|
|||
|
{
|
|||
|
QDomElement e = n.toElement ();
|
|||
|
if (e.tagName() == "comment")
|
|||
|
m_strComment = e.text();
|
|||
|
else if (e.tagName() == QString ("chapter"))
|
|||
|
{
|
|||
|
pChapter = new CChapter();
|
|||
|
if (pChapter->load (e))
|
|||
|
appendChapter(pChapter);
|
|||
|
else
|
|||
|
delete pChapter;
|
|||
|
}
|
|||
|
else if (e.tagName() == QString ("question"))
|
|||
|
{
|
|||
|
CQuestion *pQuestion = new CQuestion();
|
|||
|
if (pQuestion->load (e))
|
|||
|
appendQuestion(pQuestion);
|
|||
|
else
|
|||
|
delete pQuestion;
|
|||
|
}
|
|||
|
}
|
|||
|
n = n.nextSibling();
|
|||
|
}
|
|||
|
updateStatistic();
|
|||
|
return true;
|
|||
|
}
|
|||
|
|
|||
|
void CChapter::save (QDomElement& parent, QDomDocument& doc)
|
|||
|
{
|
|||
|
QDomElement elem = doc.createElement("chapter");
|
|||
|
|
|||
|
elem.setAttribute("name", text());
|
|||
|
elem.setAttribute("id", id());
|
|||
|
|
|||
|
if (!m_strComment.isEmpty())
|
|||
|
{
|
|||
|
QDomElement elemComment = doc.createElement("comment");
|
|||
|
QDomText textComment = doc.createTextNode(text());
|
|||
|
elemComment.appendChild(textComment);
|
|||
|
elem.appendChild(elemComment);
|
|||
|
}
|
|||
|
|
|||
|
parent.appendChild(elem);
|
|||
|
|
|||
|
// save exams
|
|||
|
/* QStringList strl = m_mapExam.keys();
|
|||
|
for (int i=0; i<strl.size(); i++)
|
|||
|
{
|
|||
|
QDomElement e = doc.createElement("exam");
|
|||
|
e.setAttribute("id", strl.at(i));
|
|||
|
e.setAttribute("questions", QString("%1").arg(m_mapExam[strl.at(i)]));
|
|||
|
elem.appendChild(e);
|
|||
|
}
|
|||
|
*/
|
|||
|
// save chapters
|
|||
|
for (int i=0; i<m_listChapter.size(); i++)
|
|||
|
{
|
|||
|
m_listChapter[i]->save(elem, doc);
|
|||
|
}
|
|||
|
|
|||
|
// save questions
|
|||
|
for (int i=0; i<m_listQuestion.size(); i++)
|
|||
|
{
|
|||
|
m_listQuestion[i]->save(elem, doc);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
bool CChapter::loadLearnStatistic (QDomElement elem)
|
|||
|
{
|
|||
|
QList<CQuestion*> listQuestionPool = questionPool();
|
|||
|
|
|||
|
if (elem.tagName () != QString ("learning")) return false;
|
|||
|
|
|||
|
QDomNode n = elem.firstChild();
|
|||
|
while (!n.isNull())
|
|||
|
{
|
|||
|
if (n.isElement ())
|
|||
|
{
|
|||
|
QDomElement e = n.toElement ();
|
|||
|
if (e.tagName() == QString ("question"))
|
|||
|
{
|
|||
|
QString strId = e.attribute("id");
|
|||
|
for (int i=0; i<listQuestionPool.size(); i++)
|
|||
|
{
|
|||
|
if (listQuestionPool.at(i)->id() == strId)
|
|||
|
listQuestionPool[i]->loadLearnStatistic(e);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
n = n.nextSibling();
|
|||
|
}
|
|||
|
updateRecommendation();
|
|||
|
return true;
|
|||
|
}
|
|||
|
|
|||
|
bool CChapter::saveLearnStatistic (QDomElement& parent, QDomDocument& doc)
|
|||
|
{
|
|||
|
// questions from sub-chapters
|
|||
|
for (int i=0; i<m_listChapter.size(); i++)
|
|||
|
{
|
|||
|
m_listChapter[i]->saveLearnStatistic(parent, doc);
|
|||
|
}
|
|||
|
|
|||
|
// save questions
|
|||
|
for (int i=0; i<m_listQuestion.size(); i++)
|
|||
|
{
|
|||
|
m_listQuestion[i]->saveLearnStatistic(parent, doc);
|
|||
|
}
|
|||
|
return true;
|
|||
|
}
|
|||
|
|
|||
|
QString CChapter::checkForErrors() const
|
|||
|
{
|
|||
|
QString str;
|
|||
|
|
|||
|
// check chapters
|
|||
|
for (int i=0; i<m_listChapter.size(); i++)
|
|||
|
{
|
|||
|
str += m_listChapter[i]->checkForErrors();
|
|||
|
}
|
|||
|
|
|||
|
// check questions
|
|||
|
for (int i=0; i<m_listQuestion.size(); i++)
|
|||
|
{
|
|||
|
str += m_listQuestion[i]->checkForErrors();
|
|||
|
}
|
|||
|
return str;
|
|||
|
}
|
|||
|
|
|||
|
QList<CChapter*> CChapter::subChapters() const
|
|||
|
{
|
|||
|
QList<CChapter*> list;
|
|||
|
|
|||
|
for (int i=0; i<m_listChapter.size(); i++)
|
|||
|
{
|
|||
|
list << m_listChapter.at(i);
|
|||
|
list << m_listChapter[i]->subChapters();
|
|||
|
}
|
|||
|
return list;
|
|||
|
}
|
|||
|
|
|||
|
QList<CQuestion*> CChapter::questionPool() const
|
|||
|
{
|
|||
|
QList<CQuestion*> list;
|
|||
|
for (int i=0; i<m_listChapter.size(); i++)
|
|||
|
{
|
|||
|
list << m_listChapter[i]->questionPool();
|
|||
|
}
|
|||
|
list << m_listQuestion;
|
|||
|
return list;
|
|||
|
}
|
|||
|
|
|||
|
QList<CQuestion*> CChapter::questionPoolLevel(const unsigned uLevel) const
|
|||
|
{
|
|||
|
QList<CQuestion*> list;
|
|||
|
int i;
|
|||
|
for (i=0; i<m_listChapter.size(); i++)
|
|||
|
list << m_listChapter[i]->questionPoolLevel(uLevel);
|
|||
|
for (i=0; i<m_listQuestion.size(); i++)
|
|||
|
{
|
|||
|
if (m_listQuestion.at(i)->level() == uLevel)
|
|||
|
list.append (m_listQuestion.at(i));
|
|||
|
}
|
|||
|
return list;
|
|||
|
}
|
|||
|
|
|||
|
QList<CQuestion*> CChapter::questionPoolDeepen() const
|
|||
|
{
|
|||
|
QList<CQuestion*> list;
|
|||
|
int i;
|
|||
|
for (i=0; i<m_listChapter.size(); i++)
|
|||
|
list << m_listChapter[i]->questionPoolDeepen();
|
|||
|
for (i=0; i<m_listQuestion.size(); i++)
|
|||
|
{
|
|||
|
CQuestion *q = m_listQuestion.at(i);
|
|||
|
if (q->level() == LEVEL_VERYOFTEN && !q->isNeverAsked())
|
|||
|
list.append (q);
|
|||
|
}
|
|||
|
return list;
|
|||
|
}
|
|||
|
|
|||
|
QList<CQuestion*> CChapter::questionPoolRepeat(const QDate d) const
|
|||
|
{
|
|||
|
QList<CQuestion*> list;
|
|||
|
int i;
|
|||
|
for (i=0; i<m_listChapter.size(); i++)
|
|||
|
list << m_listChapter[i]->questionPoolRepeat(d);
|
|||
|
for (i=0; i<m_listQuestion.size(); i++)
|
|||
|
{
|
|||
|
CQuestion *q = m_listQuestion.at(i);
|
|||
|
if (q->repeatDate() <= d)
|
|||
|
list.append (q);
|
|||
|
}
|
|||
|
return list;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
void CChapter::updateStatisticCount()
|
|||
|
{
|
|||
|
/* for (int i=0; i<m_listQuestion.size(); i++)
|
|||
|
if (m_listQuestion.at(i)->isLearningNew()) return true;
|
|||
|
|
|||
|
for (int i=0; i<m_listChapter.size(); i++)
|
|||
|
if (m_listChapter.at(i)->isLearningNew()) return true;
|
|||
|
|
|||
|
return false;
|
|||
|
*/
|
|||
|
// Alle Statistiken zur<75>cksetzen
|
|||
|
m_uNeverAskedCount = 0;
|
|||
|
m_bHasLearningNew = false;
|
|||
|
m_bHasKnownQuestions = false;
|
|||
|
m_bHasKnownQuestionsRepeatToday = false;
|
|||
|
for (int i=0; i<=LEVEL_MAX; i++) m_uLevelCount[i] = 0;
|
|||
|
|
|||
|
// Zuerst Statistiken f<>r Unterkapitel berechnen und integrieren
|
|||
|
for (int i=0; i<m_listChapter.size(); i++)
|
|||
|
{
|
|||
|
CChapter *p = m_listChapter.at(i);
|
|||
|
p->updateStatisticCount();
|
|||
|
for (int j=0; j<=LEVEL_MAX; j++)
|
|||
|
m_uLevelCount[j] += p->m_uLevelCount[j];
|
|||
|
m_uNeverAskedCount += p->m_uNeverAskedCount;
|
|||
|
if (p->hasLearningNewQuestions()) m_bHasLearningNew = true;
|
|||
|
if (p->hasKnownQuestions()) m_bHasKnownQuestions = true;
|
|||
|
if (p->hasKnownQuestionsRepeatToday()) m_bHasKnownQuestionsRepeatToday = true;
|
|||
|
}
|
|||
|
|
|||
|
// Anschlie<69>end Statistiken f<>r eigene Fragen neu berechnen und hinzuf<75>gen
|
|||
|
for (int i=0; i<m_listQuestion.size(); i++)
|
|||
|
{
|
|||
|
CQuestion *q = m_listQuestion.at(i);
|
|||
|
if (q->isNeverAsked()) m_uNeverAskedCount++;
|
|||
|
m_uLevelCount[q->level()]++;
|
|||
|
if (q->isLearningNew()) m_bHasLearningNew = true;
|
|||
|
if (q->isKnownQuestion()) m_bHasKnownQuestions = true;
|
|||
|
if (q->isKnownQuestion() && q->isRepeatToday()) m_bHasKnownQuestionsRepeatToday = true;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
void CChapter::updateRecommendationStatistic()
|
|||
|
{
|
|||
|
for (int i=0; i<RecommendationMax; i++) m_uRecomCount[i] = 0;
|
|||
|
m_uRecomCount[recommendation()]=1;
|
|||
|
|
|||
|
for (int i=0; i<m_listChapter.size(); i++)
|
|||
|
{
|
|||
|
CChapter *p = m_listChapter.at(i);
|
|||
|
p->updateRecommendationStatistic();
|
|||
|
for (int j=0; j<RecommendationMax; j++)
|
|||
|
m_uRecomCount[j] += p->m_uRecomCount[j];
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/*
|
|||
|
Berechnet die Statistik f<EFBFBD>r das Kapitel inkl. aller Unterkapitel neu.
|
|||
|
*/
|
|||
|
void CChapter::updateStatistic()
|
|||
|
{
|
|||
|
updateStatisticCount();
|
|||
|
updateRecommendation();
|
|||
|
updateRecommendationStatistic();
|
|||
|
}
|
|||
|
|
|||
|
/*
|
|||
|
CRecommendation CChapter::recommendation() const
|
|||
|
{
|
|||
|
CRecommendation r;
|
|||
|
r.create(this);
|
|||
|
return r;
|
|||
|
}
|
|||
|
*/
|
|||
|
/*
|
|||
|
CRecommendationStatistic CChapter::recommendationStatistic() const
|
|||
|
{
|
|||
|
CRecommendationStatistic rs;
|
|||
|
|
|||
|
for (int i=0; i<m_listChapter.size(); i++)
|
|||
|
{
|
|||
|
rs.append(m_listChapter.at(i)->recommendationStatistic());
|
|||
|
}
|
|||
|
//TODO
|
|||
|
// rs.append(recommendation());
|
|||
|
return rs;
|
|||
|
}
|
|||
|
*/
|
|||
|
|
|||
|
QString CChapter::idWithParents() const
|
|||
|
{
|
|||
|
CChapter *pParent=m_pParentChapter;
|
|||
|
QString str;
|
|||
|
str = id();
|
|||
|
while (pParent != 0)
|
|||
|
{
|
|||
|
str = pParent->id() + str;
|
|||
|
pParent = pParent->m_pParentChapter;
|
|||
|
}
|
|||
|
|
|||
|
return str;
|
|||
|
}
|
|||
|
|
|||
|
/*!
|
|||
|
Das empfohlene Wiederholdatum eines Kapitels das fr<EFBFBD>hestete Datum,
|
|||
|
an dem eine Frage des Kapitels oder Unterkapitels wiederholt werden sollte.
|
|||
|
\return Datum, wann das Kapitel wiederholt werden soll.
|
|||
|
Gibt es kein solches Datum, so wird ein ung<EFBFBD>ltiges Datum (QDate::isValid()) zur<EFBFBD>ckgegeben.
|
|||
|
Hinweis: Das Datum kann auch in der Vergangenheit liegen!
|
|||
|
*/
|
|||
|
QDate CChapter::repeatDate() const
|
|||
|
{
|
|||
|
QDate d;
|
|||
|
QList<CQuestion*> list = questionPool();
|
|||
|
|
|||
|
for (int i=0; i<list.size(); i++)
|
|||
|
{
|
|||
|
QDate dq = list.at(i)->repeatDate();
|
|||
|
if (!dq.isValid()) continue;
|
|||
|
if (!d.isValid() || dq < d) d = dq;
|
|||
|
}
|
|||
|
return d;
|
|||
|
}
|
|||
|
|
|||
|
/*!
|
|||
|
Die Variable m_recomRepeatDate muss up to date sein!
|
|||
|
|
|||
|
\return Lernempfehlung dieses Kapitels ohne Ber<EFBFBD>cksichtigung evt. vorhandener <EFBFBD>nter- oder <EFBFBD>bergeordneter Kapitel.
|
|||
|
|
|||
|
\sa m_recomRepeatDate
|
|||
|
*/
|
|||
|
CChapter::Recommendation CChapter::recommendationIndividual() const
|
|||
|
{
|
|||
|
if (!m_recomRepeatDate.isValid())
|
|||
|
return RecommendationLearnNew;
|
|||
|
else if (m_recomRepeatDate <= QDate::currentDate())
|
|||
|
{
|
|||
|
if (hasLearningNewQuestions() && !hasKnownQuestionsRepeatToday())
|
|||
|
return RecommendationLearnNew;
|
|||
|
else
|
|||
|
return RecommendationRepeatToday;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
if (countNeverAsked() > 0)
|
|||
|
return RecommendationLearnNew;
|
|||
|
else
|
|||
|
return RecommendationRepeatLater;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/*!
|
|||
|
Aktualisiert die Lernempfehlung f<EFBFBD>r dieses Kapitel und alle Unterkapitel
|
|||
|
\sa m_recom
|
|||
|
*/
|
|||
|
void CChapter::updateRecommendation()
|
|||
|
{
|
|||
|
m_recom = RecommendationNone;
|
|||
|
m_recom2 = RecommendationNone;
|
|||
|
|
|||
|
m_recomRepeatDate = repeatDate(); /*QDate();*/
|
|||
|
if (m_listChapter.isEmpty() && m_listQuestion.isEmpty()) return;
|
|||
|
|
|||
|
if (m_pParentChapter && m_pParentChapter->recommendation() != RecommendationSubChapter)
|
|||
|
m_recom = RecommendationParentChapter;
|
|||
|
else
|
|||
|
{
|
|||
|
if (countSubQuestion() > 20)
|
|||
|
{ // Nur wenn in den Unterkapiteln zusammen mehr als x Fragen sind, zuerst die Unterkapitel einzeln lernen lassen
|
|||
|
for (int i=0; i<m_listChapter.size(); i++)
|
|||
|
{
|
|||
|
CChapter *p = m_listChapter.at(i);
|
|||
|
if (p->levelAvg() < LEVEL_NORMAL || p->countNeverAsked() > 0)
|
|||
|
m_recom = RecommendationSubChapter;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (m_recom == RecommendationNone)
|
|||
|
{
|
|||
|
//m_recomRepeatDate = repeatDate();
|
|||
|
m_recom = recommendationIndividual();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// Alternative Empfehlung
|
|||
|
if (m_recom == RecommendationParentChapter || m_recom == RecommendationSubChapter)
|
|||
|
{
|
|||
|
m_recom2 = recommendationIndividual();
|
|||
|
if (m_recom2 != RecommendationLearnNew && m_recom2 != RecommendationRepeatToday)
|
|||
|
m_recom2 = RecommendationNone;
|
|||
|
}
|
|||
|
|
|||
|
// find recommended questions
|
|||
|
m_listQuestionRecommended.clear();
|
|||
|
QList<CQuestion*> list = questionPool();
|
|||
|
for (int i=0; i<list.size(); i++)
|
|||
|
{
|
|||
|
CQuestion *q = list.at(i);
|
|||
|
if (m_recom == RecommendationLearnNew || m_recom2 == RecommendationLearnNew)
|
|||
|
{
|
|||
|
if (q->isNeverAsked() || q->isLearningNew())
|
|||
|
m_listQuestionRecommended.append(q);
|
|||
|
}
|
|||
|
else if (m_recom == RecommendationRepeatToday || m_recom2 == RecommendationRepeatToday)
|
|||
|
{
|
|||
|
if (q->isRepeatToday())
|
|||
|
m_listQuestionRecommended.append(q);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// update child chapters
|
|||
|
for (int i=0; i<m_listChapter.size(); i++)
|
|||
|
{
|
|||
|
CChapter *p = m_listChapter.at(i);
|
|||
|
p->updateRecommendation();
|
|||
|
//m_listQuestionRecommended << p->m_listQuestionRecommended;
|
|||
|
}
|
|||
|
}
|
|||
|
/*
|
|||
|
bool CChapter::hasRecommendedQuestions() const
|
|||
|
{
|
|||
|
return (m_recom == RecommendationLearnNew || m_recom == RecommendationRepeatToday);
|
|||
|
}
|
|||
|
|
|||
|
QList<CQuestion*> CChapter::recommendedQuestions() const
|
|||
|
{
|
|||
|
QList<CQuestion*> listRet, list = questionPool();
|
|||
|
|
|||
|
if (m_recom != RecommendationLearnNew && m_recom != RecommendationRepeatToday) return listRet;
|
|||
|
|
|||
|
for (int i=0; i<list.size(); i++)
|
|||
|
{
|
|||
|
CQuestion *q = list.at(i);
|
|||
|
switch (m_recom)
|
|||
|
{
|
|||
|
case RecommendationLearnNew:
|
|||
|
if (q->isNeverAsked() || q->isLearningNew())
|
|||
|
listRet.append(q);
|
|||
|
break;
|
|||
|
case RecommendationRepeatToday:
|
|||
|
if (q->isRepeatToday())
|
|||
|
listRet.append(q);
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
return listRet;
|
|||
|
}
|
|||
|
*/
|
|||
|
|
|||
|
QString CChapter::recommendationText(const Recommendation r, const QDate dRepeat)
|
|||
|
{
|
|||
|
unsigned uDays=0;
|
|||
|
switch (r)
|
|||
|
{
|
|||
|
default:
|
|||
|
case RecommendationNone:
|
|||
|
return tr("Keine Lernempfehlung");
|
|||
|
case RecommendationSubChapter:
|
|||
|
return tr("Zuerst Unterkapitel lernen");
|
|||
|
case RecommendationParentChapter:
|
|||
|
return tr("<EFBFBD>bergeordnetes Kapitel lernen");
|
|||
|
case RecommendationLearnNew:
|
|||
|
return tr("Neue Fragen lernen");
|
|||
|
case RecommendationRepeatToday:
|
|||
|
return tr("Heute wiederholen");
|
|||
|
case RecommendationRepeatLater:
|
|||
|
uDays = QDate::currentDate().daysTo(dRepeat);
|
|||
|
if (uDays == 1)
|
|||
|
return tr("Morgen wiederholen");
|
|||
|
else
|
|||
|
return tr("In %1 Tagen wiederholen").arg(uDays);
|
|||
|
}
|
|||
|
return QString();
|
|||
|
}
|
|||
|
|
|||
|
QString CChapter::recommendationText() const
|
|||
|
{
|
|||
|
return recommendationText(m_recom, m_recomRepeatDate);
|
|||
|
}
|
|||
|
|
|||
|
QString CChapter::recommendationToolTip() const
|
|||
|
{
|
|||
|
QString str = recommendationText();
|
|||
|
unsigned uCount = recommendedQuestionCount();
|
|||
|
if (hasRecommendedQuestions() && m_recom2 == RecommendationNone)
|
|||
|
{
|
|||
|
str += " ";
|
|||
|
if (uCount == 1)
|
|||
|
str += tr("(1 Frage)");
|
|||
|
else
|
|||
|
str += tr("(%1 Fragen)").arg(uCount);
|
|||
|
}
|
|||
|
if (m_recom2 != RecommendationNone)
|
|||
|
{
|
|||
|
str += "\n" + tr("Alternativ: ");
|
|||
|
if (m_recom2 == RecommendationLearnNew)
|
|||
|
{
|
|||
|
if (uCount == 1)
|
|||
|
str += tr("1 neue Frage lernen");
|
|||
|
else
|
|||
|
str += tr("%1 neue Fragen lernen").arg(uCount);
|
|||
|
}
|
|||
|
else if (m_recom2 == RecommendationRepeatToday)
|
|||
|
{
|
|||
|
if (uCount == 1)
|
|||
|
str += tr("1 Frage wiederholen");
|
|||
|
else
|
|||
|
str += tr("%1 Fragen wiederholen").arg(uCount);
|
|||
|
}
|
|||
|
else
|
|||
|
str += recommendationText (m_recom2, m_recomRepeatDate);
|
|||
|
}
|
|||
|
return str;
|
|||
|
}
|
|||
|
|
|||
|
QString CChapter::recommendationTextExtended(const CCatalog *pCatalog) const
|
|||
|
{
|
|||
|
unsigned uDays=0;
|
|||
|
QString str;
|
|||
|
|
|||
|
switch (m_recom)
|
|||
|
{
|
|||
|
default:
|
|||
|
case RecommendationNone:
|
|||
|
str = tr("Keine Lernempfehlung");
|
|||
|
break;
|
|||
|
case RecommendationSubChapter:
|
|||
|
str = tr("Dieses Kapitel enth<74>lt Unterkapitel, dessen Fragen Sie noch nicht ausreichend gelernt haben.\nEs wird empohlen in kleinen Etappen zu lernen und damit zuerst die Unterkapitel zu vertiefen.");
|
|||
|
break;
|
|||
|
case RecommendationParentChapter:
|
|||
|
if (levelAvgRounded() >= LEVEL_NORMAL)
|
|||
|
str = tr("Sie k<>nnen die Fragen dieses Kapitels gut beantworten.\n");
|
|||
|
str += tr("Es wird empfohlen, alle Fragen des <20>bergeordneten Kapitels gemischt zusammen zu lernen.");
|
|||
|
break;
|
|||
|
case RecommendationLearnNew:
|
|||
|
if (!isRecommendedNow(pCatalog))
|
|||
|
str = tr("Es gibt andere Kapitel, deren Fragen heute wiederholt werden sollten. Bitte lernen Sie diese Kapitel zuerst.");
|
|||
|
else
|
|||
|
str = tr("Bitte beantworten Sie alle neuen Fragen mindestens einmal richtig.");
|
|||
|
break;
|
|||
|
case RecommendationRepeatToday:
|
|||
|
str = tr("Bitte lernen Sie alle heute zu wiederholenden Fragen, bis sie eine Lernfortschritts-Stufe h<>her eingestuft sind.");
|
|||
|
break;
|
|||
|
case RecommendationRepeatLater:
|
|||
|
uDays = QDate::currentDate().daysTo(m_recomRepeatDate);
|
|||
|
if (uDays > 1)
|
|||
|
str = tr("Die Wiederholung dieses Kapitels ist erst in %1 Tagen geplant.\n").arg(uDays);
|
|||
|
else
|
|||
|
str = tr("Die Wiederholung dieses Kapitels ist erst f<>r morgen geplant.\n");
|
|||
|
if (pCatalog->m_uRecomCount[RecommendationRepeatToday] > 0)
|
|||
|
str += tr("Es gibt andere Kapitel, deren Fragen heute wiederholt werden m<>ssen. Bitte lernen Sie diese Kapitel zuerst.");
|
|||
|
else if (pCatalog->m_uRecomCount[RecommendationLearnNew] > 0)
|
|||
|
str += tr("Bitte lernen Sie zuerst Kapitel mit neuen Fragen.");
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
if (hasRecommendedQuestions() && isRecommendedNow(pCatalog))
|
|||
|
str += tr("<p>Daf<61>r sind noch %1 Fragen zu lernen.").arg(recommendedQuestionCount());
|
|||
|
|
|||
|
return str;
|
|||
|
}
|
|||
|
|
|||
|
QString CChapter::recommendationTextExtended2(const CCatalog *pCatalog) const
|
|||
|
{
|
|||
|
QString str;
|
|||
|
|
|||
|
if (m_recom2 == RecommendationLearnNew || (m_recom == RecommendationLearnNew && !isRecommendedNow(pCatalog)))
|
|||
|
{
|
|||
|
//str = tr("Bitte beantworten Sie alle neuen Fragen mindestens einmal richtig.");
|
|||
|
str = tr("Alternativ k<>nnen Sie jetzt die neuen Fragen dieses Kapitels lernen (%1 Fragen).").arg(recommendedQuestionCount());
|
|||
|
}
|
|||
|
else if (m_recom2 == RecommendationRepeatToday)
|
|||
|
{
|
|||
|
if (m_recom == RecommendationSubChapter)
|
|||
|
str = tr("Bitte lernen Sie alle heute zu wiederholenden Fragen, bis sie eine Lernfortschritts-Stufe h<>her eingestuft sind (%1 Fragen).").arg(recommendedQuestionCount());
|
|||
|
else
|
|||
|
str = tr("Alternativ k<>nnen Sie jetzt die heute zu wiederholenden Fragen dieses Kapitels lernen (%1 Fragen).").arg(recommendedQuestionCount());
|
|||
|
}
|
|||
|
|
|||
|
return str;
|
|||
|
}
|
|||
|
|
|||
|
QString CChapter::recommendationIconName(const Recommendation r, const CCatalog *pCatalog)
|
|||
|
{
|
|||
|
switch (r)
|
|||
|
{
|
|||
|
case RecommendationSubChapter:
|
|||
|
return QString(":/icons/16x16/button_cancel.png");
|
|||
|
case RecommendationParentChapter:
|
|||
|
return QString(":/icons/16x16/button_ok.png");
|
|||
|
case RecommendationLearnNew:
|
|||
|
if (pCatalog->m_uRecomCount[RecommendationRepeatToday] > 0)
|
|||
|
return QString(":/icons/16x16/idea_gray.png");
|
|||
|
else
|
|||
|
return QString(":/icons/16x16/idea.png");
|
|||
|
case RecommendationRepeatToday:
|
|||
|
return QString(":/icons/16x16/idea.png");
|
|||
|
case RecommendationRepeatLater:
|
|||
|
return QString(":/icons/16x16/idea_gray.png");
|
|||
|
default:
|
|||
|
return QString();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
QString CChapter::recommendationIconName(const CCatalog *pCatalog) const
|
|||
|
{
|
|||
|
return recommendationIconName(m_recom, pCatalog);
|
|||
|
}
|
|||
|
|
|||
|
/*!
|
|||
|
\return true: Kapitel kann jetzt gelernt werden,
|
|||
|
false: Kapitel sollte <EFBFBD>berhaupt nicht oder erst sp<EFBFBD>ter gelernt werden
|
|||
|
*/
|
|||
|
|
|||
|
bool CChapter::isRecommendedNow(const CCatalog *pCatalog) const
|
|||
|
{
|
|||
|
switch (m_recom)
|
|||
|
{
|
|||
|
case RecommendationSubChapter:
|
|||
|
if (pCatalog->m_uRecomCount[RecommendationRepeatToday] > 0)
|
|||
|
return true;
|
|||
|
break;
|
|||
|
case RecommendationRepeatToday:
|
|||
|
return true;
|
|||
|
case RecommendationLearnNew:
|
|||
|
if (pCatalog->m_uRecomCount[RecommendationRepeatToday] == 0)
|
|||
|
return true;
|
|||
|
break;
|
|||
|
default:
|
|||
|
break;
|
|||
|
}
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
/*
|
|||
|
\return true: Das Kapitel enth<EFBFBD>lt noch neue Fragen, die gerade (="heute") gelernt werden
|
|||
|
bool CChapter::isLearningNew() const
|
|||
|
{
|
|||
|
for (int i=0; i<m_listQuestion.size(); i++)
|
|||
|
if (m_listQuestion.at(i)->isLearningNew()) return true;
|
|||
|
|
|||
|
for (int i=0; i<m_listChapter.size(); i++)
|
|||
|
if (m_listChapter.at(i)->isLearningNew()) return true;
|
|||
|
|
|||
|
return false;
|
|||
|
}
|
|||
|
*/
|
|||
|
|
|||
|
CDayStatistic CChapter::dayStatistic (const QDate& date) const
|
|||
|
{
|
|||
|
CDayStatistic dsRet, ds;
|
|||
|
QList<CQuestion*> listPool = questionPool();
|
|||
|
|
|||
|
for (int i=0; i<listPool.size(); i++)
|
|||
|
{
|
|||
|
ds = listPool.at(i)->dayStatistic(date);
|
|||
|
dsRet += ds;
|
|||
|
}
|
|||
|
if (listPool.size() != 0) dsRet.m_dLevel /= listPool.size();
|
|||
|
return dsRet;
|
|||
|
}
|
|||
|
|
|||
|
CDayStatistic CChapter::completeStatistic() const
|
|||
|
{
|
|||
|
return dayStatistic(QDate());
|
|||
|
}
|
|||
|
|
|||
|
QDateTime CChapter::firstAnswerClicked() const
|
|||
|
{
|
|||
|
QList<CQuestion*> listPool = questionPool();
|
|||
|
QDateTime dtRet, dt;
|
|||
|
|
|||
|
for (int i=0; i<listPool.size(); i++)
|
|||
|
{
|
|||
|
dt = listPool.at(i)->firstClicked();
|
|||
|
if (dt.isNull()) continue;
|
|||
|
if (dtRet.isNull() || dt < dtRet) dtRet = dt;
|
|||
|
}
|
|||
|
return dtRet;
|
|||
|
}
|
|||
|
|
|||
|
double CChapter::levelAvg() const
|
|||
|
{
|
|||
|
double d=0.0;
|
|||
|
double dCount=0.0;
|
|||
|
|
|||
|
for (int i=0; i<=LEVEL_MAX; i++)
|
|||
|
{
|
|||
|
d += m_uLevelCount[i] * i;
|
|||
|
dCount += m_uLevelCount[i];
|
|||
|
}
|
|||
|
if (dCount != 0.0) d /= dCount;
|
|||
|
return d;
|
|||
|
}
|
|||
|
|
|||
|
unsigned CChapter::levelAvgRounded() const
|
|||
|
{
|
|||
|
return ((unsigned) (levelAvg()+0.5));
|
|||
|
}
|
|||
|
|
|||
|
QString CChapter::levelAvgText() const
|
|||
|
{
|
|||
|
return QString("%1").arg(CQuestion::levelText(levelAvgRounded()));
|
|||
|
}
|
|||
|
|
|||
|
QIcon CChapter::levelAvgIcon() const
|
|||
|
{
|
|||
|
return QIcon(CQuestion::levelIconName(levelAvgRounded()));
|
|||
|
}
|
|||
|
|
|||
|
QPixmap CChapter::levelAvgPixmap() const
|
|||
|
{
|
|||
|
return QPixmap(CQuestion::levelIconName(levelAvgRounded()));
|
|||
|
}
|
|||
|
|
|||
|
static bool chapterLessThan(const CChapter *c1, const CChapter *c2)
|
|||
|
{
|
|||
|
return c1->id() < c2->id();
|
|||
|
}
|
|||
|
|
|||
|
void CChapter::sortSubChapters(bool bSortQuestions)
|
|||
|
{
|
|||
|
if (bSortQuestions) sortQuestions();
|
|||
|
qSort (m_listChapter.begin(), m_listChapter.end(), chapterLessThan);
|
|||
|
|
|||
|
for (int i=0; i<m_listChapter.size(); i++)
|
|||
|
{
|
|||
|
m_listChapter.at(i)->sortSubChapters(bSortQuestions);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
static bool questionLessThan(const CQuestion *q1, const CQuestion *q2)
|
|||
|
{
|
|||
|
return q1->id() < q2->id();
|
|||
|
}
|
|||
|
|
|||
|
void CChapter::sortQuestions()
|
|||
|
{
|
|||
|
qSort (m_listQuestion.begin(), m_listQuestion.end(), questionLessThan);
|
|||
|
}
|
|||
|
|