afutrainer/exam.cpp

307 lines
8.4 KiB
C++
Raw Normal View History

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. *
***************************************************************************/
#include "exam.h"
#include "question.h"
#include "error.h"
#include "tools.h"
#include <qregexp.h>
#include <qvariant.h>
//#define DEBUGMSG
void CExamPart::clear()
{
m_iQuestionCount = 0;
m_strRegExp.clear();
}
bool CExamPart::load (QDomElement elem)
{
if (elem.tagName() != QString ("exam_part")) return false;
m_iQuestionCount = elem.attribute("count").toUInt();
if (m_iQuestionCount == 0) return false;
m_strGroup = elem.attribute("group");
m_strRegExp = elem.text ();
if (m_strRegExp.isEmpty()) return false;
return true;
}
void CExamPart::save (QDomElement& parent, QDomDocument& doc) const
{
QDomElement elemRoot = doc.createElement("exam_part");
elemRoot.setAttribute("count", QString("%1").arg(m_iQuestionCount));
elemRoot.setAttribute("group", m_strGroup);
elemRoot.appendChild(doc.createTextNode(m_strRegExp));
parent.appendChild(elemRoot);
}
QList<CQuestion*> CExamPart::createQuestionPool(const QList<CQuestion*>& listAllQuestions) const
{
QList<CQuestion*> listRet, listSelected;
QRegExp regexp(m_strRegExp);
int i=0;
CQuestion *q=0;
#ifdef DEBUGMSG
qDebug ("\tPart Group = '%s' RegExp '%s' mit %i Fragen", qPrintable (m_strGroup), qPrintable(m_strRegExp), m_iQuestionCount);
#endif
// Alle Fragen raussuchen, die dem RegExp entsprechen
for (i=0; i<listAllQuestions.size(); i++)
{
q = listAllQuestions.at(i);
if (!m_strGroup.isEmpty() && !q->groups().contains(m_strGroup, Qt::CaseInsensitive))
continue;
if (regexp.exactMatch(q->id()))
{
#ifdef DEBUGMSG
qDebug ("\t\tAdding Question '%s'", qPrintable (q->id()));
#endif
listSelected.append(q);
}
}
if (listSelected.size() < questionCount())
{
throw CError (
QString("Für den regulären Ausdruck '%1' wurden nur %2 Fragen gefunden - zu wenig, um daraus %3 Fragen für die Prüfung auszuwählen.")
.arg(m_strRegExp).arg(listSelected.size()).arg(questionCount()), __PRETTY_FUNCTION__, __FILE__, __LINE__);
}
#ifdef DEBUGMSG
qDebug ("\tStarte Auswahlverfahren...");
#endif
for (i=0; i < questionCount(); i++)
{
int rnd = afu_random (0, listSelected.size()-1);
q = listSelected.at(rnd);
#ifdef DEBUGMSG
qDebug ("\t\tSelected question '%s'", qPrintable (q->id()));
#endif
listRet.append (q);
listSelected.removeAt(rnd);
}
return listRet;
}
void CExam::clear()
{
m_strId.clear();
m_strName.clear();
m_strComment.clear();
m_uDuration = 0;
m_uMaxErrorPoints = 0;
m_listParts.clear();
}
bool CExam::load (QDomElement elem)
{
if (elem.tagName() != QString ("exam")) return false;
m_strId = elem.attribute("id");
m_strName = elem.attribute("name");
m_uDuration = elem.attribute("duration").toUInt();
m_uMaxErrorPoints = elem.attribute("maxerrorpoints").toUInt();
m_strComment = elem.attribute("comment");
if (m_strName.isEmpty()) return false;
if (m_uDuration == 0) return false;
QDomNode n = elem.firstChild();
while (!n.isNull())
{
if (n.isElement ())
{
QDomElement e = n.toElement ();
if (e.tagName() == QString ("exam_part"))
{
CExamPart ep;
if (ep.load(e)) m_listParts.append(ep);
}
}
n = n.nextSibling();
}
return true;
}
void CExam::save (QDomElement& parent, QDomDocument& doc) const
{
QDomElement elemRoot = doc.createElement("exam");
elemRoot.setAttribute("id", m_strId);
elemRoot.setAttribute("name", m_strName);
elemRoot.setAttribute("duration", QString("%1").arg(m_uDuration));
elemRoot.setAttribute("maxerrorpoints", QString("%1").arg(m_uMaxErrorPoints));
elemRoot.setAttribute("comment", m_strComment);
for (int i=0; i<m_listParts.size(); i++)
m_listParts.at(i).save(elemRoot, doc);
parent.appendChild(elemRoot);
}
unsigned CExam::questionCount() const
{
unsigned u=0;
for (int i=0; i<m_listParts.size(); i++)
{
u += m_listParts.at(i).questionCount();
}
return u;
}
QList<CQuestion*> CExam::createQuestionPool(const QList<CQuestion*>& listAllQuestions) const
{
QList<CQuestion*> listRet;
#ifdef DEBUGMSG
qDebug ("Erzeuge Prüfungsfragen für '%s'", qPrintable(name()));
#endif
try
{
for (int i=0; i<m_listParts.size(); i++)
{
listRet << m_listParts.at(i).createQuestionPool(listAllQuestions);
}
}
catch (CError e)
{
e.preText(QString("Konnte Prüfung '%1' nicht erzeugen.").arg(name()));
throw;
}
#ifdef DEBUGMSG
qDebug ("Insg. %i Prüfungsfragen ausgewählt", listRet.size());
for (int i=0; i<listRet.size(); i++)
qDebug ("\t%i. Frage ID '%s'", i+1, qPrintable(listRet.at(i)->id()));
#endif
return listRet;
}
CExamStat::CExamStat(const CExam& exam)
{
clear();
m_strId = exam.id();
}
void CExamStat::clear()
{
m_strId.clear();
m_dt = QDateTime::currentDateTime();
m_uSecs = 0;
m_strlQuestionId.clear();
m_listAnswer.clear();
m_uCorrect = 0;
m_uWrong = 0;
m_uErrorPoints = 0;
m_bPassed = false;
}
void CExamStat::setQuestions(const QList<CQuestion*>& listQuestion, const QList<unsigned>& listAnswerMask)
{
for (int i=0; i<listQuestion.size(); i++)
{
CQuestion *q = listQuestion.at(i);
m_strlQuestionId.append(q->id());
m_listAnswer.append(q->orderedAnswerMask(listAnswerMask.at(i)));
}
}
void CExamStat::setResult (const unsigned uCorrect, const unsigned uWrong, const unsigned uErrorPoints, const bool bPassed)
{
m_uCorrect = uCorrect;
m_uWrong = uWrong;
m_uErrorPoints = uErrorPoints;
m_bPassed = bPassed;
}
bool CExamStat::load (QDomElement elem)
{
if (elem.tagName() != QString ("exam")) return false;
m_strId = elem.attribute("id");
m_uSecs = elem.attribute("secs").toUInt();
m_dt = QDateTime::fromString(elem.attribute("datetime"), Qt::ISODate);
m_uCorrect = elem.attribute("correct").toUInt();
m_uWrong = elem.attribute("wrong").toUInt();
m_uErrorPoints = elem.attribute("errorpoints").toUInt();
m_bPassed = QVariant(elem.attribute("passed")).toBool();
if (m_strId.isEmpty()) return false;
if (m_uSecs == 0) 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");
if (!strId.isEmpty())
{
m_strlQuestionId.append (strId);
m_listAnswer.append(e.attribute("answer").toUInt());
}
}
}
n = n.nextSibling();
}
return true;
}
void CExamStat::save (QDomElement& parent, QDomDocument& doc) const
{
QDomElement elemRoot = doc.createElement("exam");
elemRoot.setAttribute("id", m_strId);
elemRoot.setAttribute("secs", QString("%1").arg(m_uSecs));
elemRoot.setAttribute("datetime", m_dt.toString(Qt::ISODate));
elemRoot.setAttribute("correct", QString("%1").arg(m_uCorrect));
elemRoot.setAttribute("wrong", QString("%1").arg(m_uWrong));
elemRoot.setAttribute("errorpoints", QString("%1").arg(m_uErrorPoints));
elemRoot.setAttribute("passed", QString("%1").arg(m_bPassed));
for (int i=0; i<m_strlQuestionId.size(); i++)
{
QDomElement elemQuestion = doc.createElement("question");
elemQuestion.setAttribute("id", m_strlQuestionId.at(i));
elemQuestion.setAttribute("answer", m_listAnswer.at(i));
elemRoot.appendChild(elemQuestion);
}
parent.appendChild(elemRoot);
}