435 lines
14 KiB
C++
435 lines
14 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 "dlglearn.h"
|
||
#include "dlgviewquestion.h"
|
||
#include "dlglearnassistant.h"
|
||
#include "tools.h"
|
||
|
||
#include <qmessagebox.h>
|
||
|
||
CDlgLearn::CDlgLearn (QWidget *pParent) : QDialog (pParent, Qt::WindowMaximizeButtonHint)
|
||
{
|
||
m_pCatalog = 0;
|
||
m_pChapter = 0;
|
||
m_pQuestion=0;
|
||
m_pLastQuestion=0;
|
||
m_uLastAnswerMask=0;
|
||
m_bHintsUsed=false;
|
||
m_uElapsedBeforeBreak=0;
|
||
#ifdef _DEBUG
|
||
m_bCheatEnable=true;
|
||
#else
|
||
m_bCheatEnable=false;
|
||
#endif
|
||
m_bAssistantEnable=true;
|
||
setupUi(this);
|
||
|
||
if (!m_bAssistantEnable)
|
||
gbAssistant->hide();
|
||
}
|
||
|
||
CDlgLearn::~CDlgLearn()
|
||
{
|
||
}
|
||
|
||
void CDlgLearn::go (CCatalog *pCatalog, CChapter *pChapter)
|
||
{
|
||
Q_ASSERT (pChapter != 0);
|
||
m_pCatalog = pCatalog;
|
||
setNewChapter(pChapter);
|
||
|
||
m_ds = pCatalog->dayStatistic(QDate::currentDate());
|
||
onUpdateDS();
|
||
|
||
exec();
|
||
}
|
||
|
||
void CDlgLearn::setNewChapter(CChapter *pChapter)
|
||
{
|
||
m_pQuestion=0;
|
||
m_bHintsUsed=false;
|
||
m_pChapter = pChapter;
|
||
m_listQuestion = m_pChapter->questionPool();
|
||
nextQuestion();
|
||
}
|
||
|
||
void CDlgLearn::updateStatistic()
|
||
{
|
||
const int w=60, h=16;
|
||
|
||
// CHAPTER STATISTICS
|
||
labChapter->setText (m_pChapter->text());
|
||
labChapterCount->setText(QString("%1").arg(m_listQuestion.size()));
|
||
labChapterVeryOften->setText(QString("%1").arg(m_pChapter->countQuestion(0)));
|
||
labChapterOften->setText(QString("%1").arg(m_pChapter->countQuestion(1)));
|
||
labChapterNormal->setText(QString("%1").arg(m_pChapter->countQuestion(2)));
|
||
labChapterRare->setText(QString("%1").arg(m_pChapter->countQuestion(3)));
|
||
labChapterVeryRare->setText(QString("%1").arg(m_pChapter->countQuestion(4)));
|
||
labChapterExtremeRare->setText(QString("%1").arg(m_pChapter->countQuestion(5)));
|
||
labChapterAvgText->setText(m_pChapter->levelAvgText());
|
||
labChapterAvgIcon->setPixmap(m_pChapter->levelAvgPixmap());
|
||
labChapterAvgIcon->setToolTip(QString("Kennzahl: %1").arg(m_pChapter->levelAvg(), 4, 'g', 2));
|
||
|
||
double dQuestionCount = m_listQuestion.size(), dPercent;
|
||
// dPercent = (double)m_listQuestion.size()/(double)m_pCatalog->countSubQuestion();
|
||
// labChapterCountBar->setPixmap(createProgressBar(w, h, dPercent));
|
||
// labChapterCountBar->setToolTip(QString("%1 %").arg(dPercent * 100, 0, 'f', 1));
|
||
dPercent = (double)m_pChapter->countQuestion(0)/dQuestionCount;
|
||
labChapterVeryOftenBar->setPixmap(createProgressBar(w, h, dPercent));
|
||
labChapterVeryOftenBar->setToolTip(QString("%1 %").arg(dPercent * 100, 0, 'f', 1));
|
||
dPercent = (double)m_pChapter->countQuestion(1)/dQuestionCount;
|
||
labChapterOftenBar->setPixmap(createProgressBar(w, h, dPercent));
|
||
labChapterOftenBar->setToolTip(QString("%1 %").arg(dPercent * 100, 0, 'f', 1));
|
||
dPercent = (double)m_pChapter->countQuestion(2)/dQuestionCount;
|
||
labChapterNormalBar->setPixmap(createProgressBar(w, h, dPercent));
|
||
labChapterNormalBar->setToolTip(QString("%1 %").arg(dPercent * 100, 0, 'f', 1));
|
||
dPercent = (double)m_pChapter->countQuestion(3)/dQuestionCount;
|
||
labChapterRareBar->setPixmap(createProgressBar(w, h, dPercent));
|
||
labChapterRareBar->setToolTip(QString("%1 %").arg(dPercent * 100, 0, 'f', 1));
|
||
dPercent = (double)m_pChapter->countQuestion(4)/dQuestionCount;
|
||
labChapterVeryRareBar->setPixmap(createProgressBar(w, h, dPercent));
|
||
labChapterVeryRareBar->setToolTip(QString("%1 %").arg(dPercent * 100, 0, 'f', 1));
|
||
dPercent = (double)m_pChapter->countQuestion(5)/dQuestionCount;
|
||
labChapterExtremeRareBar->setPixmap(createProgressBar(w, h, dPercent));
|
||
labChapterExtremeRareBar->setToolTip(QString("%1 %").arg(dPercent * 100, 0, 'f', 1));
|
||
|
||
// QUESTION STATISTICS
|
||
labQuestion->setText (tr("Frage %1").arg(m_pQuestion->id()));
|
||
labQuestionLevelIcon->setPixmap(m_pQuestion->levelPixmap());
|
||
labQuestionLevelText->setText(m_pQuestion->levelText());
|
||
if (m_pQuestion->clickedCorrectSuccessive() != 0)
|
||
labQuestionSuccessive->setText(tr("%1x richtig").arg(m_pQuestion->clickedCorrectSuccessive()));
|
||
else if (m_pQuestion->clickedWrongSuccessive() != 0)
|
||
labQuestionSuccessive->setText(tr("%1x falsch").arg(m_pQuestion->clickedWrongSuccessive()));
|
||
else
|
||
labQuestionSuccessive->setText(tr("--"));
|
||
|
||
labQuestionCount->setText(QString("%1").arg(m_pQuestion->clickedCount()));
|
||
labQuestionCorrect->setText(QString("%1").arg(m_pQuestion->clickedCorrect()));
|
||
labQuestionWrong->setText(QString("%1").arg(m_pQuestion->clickedWrong()));
|
||
QDateTime dtLastClicked = m_pQuestion->lastClicked();
|
||
if (!dtLastClicked.isValid())
|
||
labQuestionDate->setText("--");
|
||
else
|
||
{
|
||
labQuestionDate->setText(m_pQuestion->lastClickedText());
|
||
}
|
||
|
||
onUpdateDS();
|
||
}
|
||
|
||
void CDlgLearn::updateLearnAssistant()
|
||
{
|
||
QString strRecom1, strRecom2, str;
|
||
QPixmap pixRecom1, pixRecom2, pix;
|
||
|
||
// first recommendation
|
||
strRecom1 = m_pChapter->recommendationTextExtended(m_pCatalog);
|
||
if (m_pChapter->isRecommendedNow(m_pCatalog))
|
||
strRecom1 = "<font color='green'>" + strRecom1 + "</font>";
|
||
else
|
||
strRecom1 = "<font color='red'>" + strRecom1 + "</font>";
|
||
pixRecom1 = QPixmap (m_pChapter->recommendationIconName (m_pCatalog));
|
||
|
||
// second recommendation
|
||
strRecom2 = m_pChapter->recommendationTextExtended2(m_pCatalog);
|
||
pixRecom2 = QPixmap (m_pChapter->recommendationIconName (m_pChapter->recommendation2(), m_pCatalog));
|
||
|
||
|
||
if (m_pChapter->recommendation() == CChapter::RecommendationSubChapter && m_pChapter->recommendation2() == CChapter::RecommendationRepeatToday)
|
||
{
|
||
labRecommendationIcon->setPixmap (pixRecom2);
|
||
labRecommendation->setText("<font color='green'>" + strRecom2 + "</font>");
|
||
}
|
||
else
|
||
{
|
||
str = strRecom1;
|
||
if (!strRecom2.isEmpty())
|
||
str += "<p><font color='green'>" + strRecom2 + "</font>";
|
||
labRecommendationIcon->setPixmap (pixRecom1);
|
||
labRecommendation->setText(str);
|
||
}
|
||
}
|
||
|
||
CQuestion *CDlgLearn::findNextQuestion()
|
||
{
|
||
CQuestion *p = 0;
|
||
|
||
if (m_bAssistantEnable && m_pChapter->hasRecommendedQuestions())
|
||
{
|
||
// if (afu_random (0, 99) >= 0) // hier kann ggf. das Verh<72>ltnis zwischen RecommendedQuestion und Zufalls-Question ausgew<65>hlt werden
|
||
// {
|
||
p = findNextTargetQuestion();
|
||
// Wichtig: p kann hier immernoch 0 sein! Dies bedeutet, dass keine passende Frage im TargetPool gefunden wurde.
|
||
// }
|
||
}
|
||
|
||
if (p == 0)
|
||
p = findNextPoolQuestion();
|
||
|
||
return p;
|
||
}
|
||
|
||
CQuestion *CDlgLearn::findNextTargetQuestion()
|
||
{
|
||
CQuestion *pQuestion=0;
|
||
QList<CQuestion*> list = m_pChapter->recommendedQuestions();
|
||
int iSize = list.size();
|
||
unsigned uRnd=0;
|
||
|
||
if (iSize == 0) return 0;
|
||
if (iSize == 1)
|
||
{
|
||
if (list.at(0) == m_pQuestion)
|
||
// Regel: Niemals die gleiche Frage mehrfach hintereinander
|
||
// -> kann hier nicht erf<72>llt werden -> 0 zur<75>ckgeben -> hole Frage aus allg. Pool (siehe findNextQuestion)
|
||
return 0;
|
||
else
|
||
return list.at(0);
|
||
}
|
||
|
||
do
|
||
{
|
||
uRnd = afu_random (0, iSize-1);
|
||
pQuestion = list.at(uRnd);
|
||
}
|
||
while (m_pQuestion == pQuestion);
|
||
|
||
return pQuestion;
|
||
}
|
||
|
||
CQuestion *CDlgLearn::findNextPoolQuestion()
|
||
{
|
||
CQuestion *pQuestion=0;
|
||
unsigned uCountQuestion[LEVEL_MAX+1];
|
||
unsigned uRnd=0, uLevel=0;
|
||
int i=0;
|
||
unsigned uGewichtung[LEVEL_MAX+1], uEdge[LEVEL_MAX+1];
|
||
unsigned uRndMax = 0;
|
||
|
||
memset (uCountQuestion, 0, sizeof(unsigned)*(LEVEL_MAX+1));
|
||
for (i=0;i<m_listQuestion.size(); i++)
|
||
{
|
||
uLevel = m_listQuestion[i]->level();
|
||
Q_ASSERT(uLevel < LEVEL_MAX+1);
|
||
if (uLevel > LEVEL_MAX) continue;
|
||
uCountQuestion[uLevel]++;
|
||
}
|
||
|
||
uGewichtung[LEVEL_MAX] = 1;
|
||
uRndMax = 1;
|
||
for (i=LEVEL_MAX-1; i>=0; i--)
|
||
{
|
||
uRndMax += uGewichtung[i+1];
|
||
uGewichtung[i] = uRndMax;
|
||
}
|
||
|
||
for (i=0; i<=LEVEL_MAX; i++)
|
||
uGewichtung[i] *= uCountQuestion[i];
|
||
|
||
uRndMax=0;
|
||
for (i=0; i<=LEVEL_MAX; i++)
|
||
{
|
||
uLevel = LEVEL_MAX-i;
|
||
uRndMax += uGewichtung[uLevel];
|
||
uEdge[uLevel] = uRndMax;
|
||
}
|
||
|
||
do /* diese Schleife verhindert, dass eine Frage zweimal hintereinander kommt */
|
||
{
|
||
do /* diese Schleife w<>hlt die Abfrageh<65>ufigkeit aus */
|
||
{
|
||
uRnd = afu_random (1, uRndMax);
|
||
uLevel = LEVEL_MAX;
|
||
while (uLevel != LEVEL_VERYOFTEN && uRnd > uEdge[uLevel])
|
||
uLevel--;
|
||
|
||
Q_ASSERT(uCountQuestion[uLevel] != 0); // Wenn hier assertion failed => algorithmus falsch
|
||
}
|
||
while (uCountQuestion[uLevel] == 0);
|
||
|
||
// Zuf<75>llige Frage bestimmen
|
||
uRnd = afu_random (1, uCountQuestion[uLevel]);
|
||
for (i=0; i<m_listQuestion.size()-1; i++)
|
||
if (m_listQuestion[i]->level() == uLevel && --uRnd == 0) break;
|
||
}
|
||
while (m_pQuestion == m_listQuestion[i] && m_listQuestion.size() > 1);
|
||
pQuestion = m_listQuestion[i];
|
||
return pQuestion;
|
||
}
|
||
|
||
void CDlgLearn::nextQuestion()
|
||
{
|
||
QString str, strCheat;
|
||
|
||
if (m_listQuestion.size() == 0)
|
||
{
|
||
QMessageBox::critical (this, "Fehler", "Es gibt keine Fragen, die gelernt werden k<>nnten!");
|
||
accept();
|
||
return;
|
||
}
|
||
|
||
if (m_pQuestion)
|
||
{ // Save current question as new last question
|
||
pbLastQuestion->setEnabled(true);
|
||
m_pLastQuestion = m_pQuestion;
|
||
}
|
||
|
||
m_pQuestion = findNextQuestion();
|
||
|
||
// show answer
|
||
m_pQuestion->mixAnswers();
|
||
|
||
str = m_pQuestion->learnText(m_pCatalog, true, false);
|
||
if (m_bCheatEnable)
|
||
{
|
||
strCheat = "<p><font size=-1><i><b>Schummel-Modus</b><br>Richtige Antwort: " + CAnswerClicked::answerText (m_pQuestion->correctAnswerMask()) + "</i>";
|
||
strCheat += "<br>Empfohlene Wiederholung: " + m_pQuestion->repeatDateText();
|
||
strCheat += QString("<br>isLearningNew(): %1").arg(m_pQuestion->isLearningNew());
|
||
|
||
strCheat += "</font><p>";
|
||
}
|
||
teQuestion->setHtml(strCheat + str);
|
||
|
||
pbShowHelper->setEnabled (m_pCatalog->hasHints(m_pQuestion->id()));
|
||
m_bHintsUsed = false;
|
||
m_timeElapsed.restart();
|
||
updateStatistic();
|
||
updateLearnAssistant();
|
||
}
|
||
|
||
void CDlgLearn::on_pbAnswerA_clicked()
|
||
{
|
||
handleAnswer(0);
|
||
}
|
||
|
||
void CDlgLearn::on_pbAnswerB_clicked()
|
||
{
|
||
handleAnswer(1);
|
||
}
|
||
|
||
void CDlgLearn::on_pbAnswerC_clicked()
|
||
{
|
||
handleAnswer(2);
|
||
}
|
||
|
||
void CDlgLearn::on_pbAnswerD_clicked()
|
||
{
|
||
handleAnswer(3);
|
||
}
|
||
|
||
void CDlgLearn::handleAnswer(const int i)
|
||
{
|
||
unsigned uAnswerMask = 1<<i;
|
||
|
||
if (!m_pQuestion->isCorrectAnswer(uAnswerMask))
|
||
{
|
||
QMessageBox::information(this, tr("Hinweis"), m_pQuestion->correctionText(uAnswerMask));
|
||
}
|
||
m_uLastAnswerMask=uAnswerMask;
|
||
|
||
if (!m_bHintsUsed)
|
||
{
|
||
m_pQuestion->registerAnswerClicked(uAnswerMask, m_timeElapsed.elapsed() + m_uElapsedBeforeBreak);
|
||
|
||
bool bIsRecommendedOld = m_pChapter->isRecommendedNow(m_pCatalog) ;
|
||
|
||
m_pCatalog->updateStatistic();
|
||
m_ds = m_pCatalog->dayStatistic(QDate::currentDate());
|
||
|
||
if (bIsRecommendedOld && !m_pChapter->isRecommendedNow(m_pCatalog))
|
||
{
|
||
QMessageBox msgBox(this);
|
||
QPushButton *pbAssistant = msgBox.addButton(tr("Assistent"), QMessageBox::AcceptRole);
|
||
QPushButton *pbIgnore = msgBox.addButton(QMessageBox::Ignore);
|
||
QPushButton *pbExit = msgBox.addButton(QMessageBox::Cancel);
|
||
pbAssistant->setIcon(QIcon(":/icons/16x16/idea_info.png"));
|
||
pbAssistant->setToolTip(tr("Lern-Assistent aufrufen"));
|
||
pbIgnore->setToolTip(tr("Meldung ignorieren, dieses Kapitel weiterlernen"));
|
||
pbExit->setToolTip(tr("Lernmodus beenden"));
|
||
msgBox.setText(tr("<b>Herzlichen Gl<47>ckwunsch!</b><p>Sie haben das heutige Lernziel f<>r dieses Kapitel erreicht.<br>Bitte folgen Sie den weiteren Empfehlungen des Lernassistents."));
|
||
msgBox.setWindowTitle(tr("Ziel erreicht"));
|
||
|
||
msgBox.exec();
|
||
if (msgBox.clickedButton() == pbExit)
|
||
{
|
||
reject();
|
||
return;
|
||
}
|
||
else if (msgBox.clickedButton() == pbAssistant)
|
||
{
|
||
on_pbLearnAssistant_clicked();
|
||
return;
|
||
}
|
||
}
|
||
}
|
||
nextQuestion();
|
||
}
|
||
|
||
void CDlgLearn::on_pbShowHelper_clicked()
|
||
{
|
||
m_bHintsUsed = true;
|
||
QString str = m_pQuestion->learnText(m_pCatalog, true, true);
|
||
teQuestion->setHtml(str);
|
||
}
|
||
|
||
void CDlgLearn::on_pbLastQuestion_clicked()
|
||
{
|
||
CDlgViewQuestion dlg(this);
|
||
dlg.go(m_pCatalog, m_pLastQuestion, m_uLastAnswerMask);
|
||
}
|
||
|
||
void CDlgLearn::on_pbSkip_clicked()
|
||
{
|
||
m_uLastAnswerMask=0;
|
||
nextQuestion();
|
||
}
|
||
|
||
void CDlgLearn::on_pbQuit_clicked()
|
||
{
|
||
m_pCatalog->updateStatistic();
|
||
accept();
|
||
}
|
||
|
||
void CDlgLearn::on_pbLearnAssistant_clicked()
|
||
{
|
||
CDlgLearnAssistant dlg(this);
|
||
CChapter *pChapter=0;
|
||
if (!dlg.setup(m_pCatalog))
|
||
{
|
||
QMessageBox::information(this, tr("Information"), tr("Derzeit gibt es keine Empfehlung des Lernassistentes."));
|
||
return;
|
||
}
|
||
if (dlg.exec() != QDialog::Accepted) return;
|
||
pChapter = dlg.selectedChapter();
|
||
if (pChapter == 0) return;
|
||
setNewChapter(pChapter);
|
||
}
|
||
|
||
void CDlgLearn::onUpdateDS()
|
||
{
|
||
labDSTime->setText(QString("%1 h %2 m").arg(m_ds.timeExpediture()/1000/3600).arg(m_ds.timeExpediture()/1000/60 % 60, 2, 10, QChar('0')));
|
||
labDSCount->setText(QString::number(m_ds.clickedCount()));
|
||
labDSCorrect->setText(QString::number(m_ds.clickedCorrect()));
|
||
labDSWrong->setText(QString::number(m_ds.clickedWrong()));
|
||
}
|