/*************************************************************************** * 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 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 = "" + strRecom1 + ""; else strRecom1 = "" + strRecom1 + ""; 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("" + strRecom2 + ""); } else { str = strRecom1; if (!strRecom2.isEmpty()) str += "

" + strRecom2 + ""; 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ältnis zwischen RecommendedQuestion und Zufalls-Question ausgewä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 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üllt werden -> 0 zurü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;ilevel(); 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ä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ällige Frage bestimmen uRnd = afu_random (1, uCountQuestion[uLevel]); for (i=0; ilevel() == 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 = "

Schummel-Modus
Richtige Antwort: " + CAnswerClicked::answerText (m_pQuestion->correctAnswerMask()) + "
"; strCheat += "
Empfohlene Wiederholung: " + m_pQuestion->repeatDateText(); strCheat += QString("
isLearningNew(): %1").arg(m_pQuestion->isLearningNew()); strCheat += "

"; } 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<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("Herzlichen Glückwunsch!

Sie haben das heutige Lernziel für dieses Kapitel erreicht.
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())); }