Convert CRLF to Unix newlines

This commit is contained in:
Sebastian Lohff 2022-06-30 23:13:43 +02:00
parent 9898b3404a
commit 1010914f41
47 changed files with 8916 additions and 8916 deletions

View File

@ -1,119 +1,119 @@
/***************************************************************************
* 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 "answer.h"
#include <qcoreapplication.h>
CAnswer::CAnswer(const QString& strText, const bool bCorrect)
{
m_strText = strText;
m_bIsCorrect = bCorrect;
}
void CAnswer::clear()
{
m_strText.clear();
m_bIsCorrect = false;
}
QString CAnswerClicked::tr (const char *sourceText, const char *comment)
{
return QCoreApplication::translate("CAnswerClicked", sourceText, comment);
}
void CAnswerClicked::clear()
{
m_dt = QDateTime::currentDateTime();
m_uAnswer=0;
m_uNeededTime=0;
}
bool CAnswerClicked::operator < (const CAnswerClicked& ac) const
{
return m_dt < ac.m_dt;
}
QString CAnswerClicked::answerText(const unsigned uAnswer)
{
QString strRet;
for (int i=0; i<32; i++)
{
if (uAnswer & (1<<i))
{
if (!strRet.isEmpty())
strRet += ", ";
strRet += QChar('A' + i);
}
}
return strRet;
}
QString CAnswerClicked::answerText() const
{
return answerText(m_uAnswer);
}
QString CAnswerClicked::neededTimeText() const
{
if (m_uNeededTime < 1000)
return tr("&lt; 1 sec");
else if (m_uNeededTime < 60000)
return tr("%1 sec").arg(m_uNeededTime / 1000);
else
return tr("%1:%2 min").arg(m_uNeededTime / 60000).arg((m_uNeededTime / 1000) % 60, 2, 10, QChar('0'));
}
bool CAnswerClicked::isCorrect(const QList<CAnswer>& listAnswer) const
{
unsigned uMask=0;
for (int i=0; i<listAnswer.size(); i++)
{
if (listAnswer.at(i).isCorrect())
uMask |= (1<<i);
}
return (m_uAnswer == uMask);
}
bool CAnswerClicked::load (QDomElement elem)
{
bool bOk=false;
if (elem.tagName() != "answer_clicked") return false;
m_dt = QDateTime::fromString (elem.attribute("datetime"), Qt::ISODate);
if (!m_dt.isValid()) return false;
m_uAnswer = elem.attribute("answer_code").toUInt(&bOk);
if (!bOk) return false;
m_uNeededTime = elem.attribute("needed_time").toUInt(&bOk);
if (!bOk) return false;
return true;
}
void CAnswerClicked::save (QDomElement& parent, QDomDocument& doc) const
{
QDomElement elem = doc.createElement("answer_clicked");
elem.setAttribute("datetime", m_dt.toString(Qt::ISODate));
elem.setAttribute("answer_code", QString("%1").arg(m_uAnswer));
elem.setAttribute("needed_time", QString("%1").arg(m_uNeededTime));
parent.appendChild(elem);
}
/***************************************************************************
* 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 "answer.h"
#include <qcoreapplication.h>
CAnswer::CAnswer(const QString& strText, const bool bCorrect)
{
m_strText = strText;
m_bIsCorrect = bCorrect;
}
void CAnswer::clear()
{
m_strText.clear();
m_bIsCorrect = false;
}
QString CAnswerClicked::tr (const char *sourceText, const char *comment)
{
return QCoreApplication::translate("CAnswerClicked", sourceText, comment);
}
void CAnswerClicked::clear()
{
m_dt = QDateTime::currentDateTime();
m_uAnswer=0;
m_uNeededTime=0;
}
bool CAnswerClicked::operator < (const CAnswerClicked& ac) const
{
return m_dt < ac.m_dt;
}
QString CAnswerClicked::answerText(const unsigned uAnswer)
{
QString strRet;
for (int i=0; i<32; i++)
{
if (uAnswer & (1<<i))
{
if (!strRet.isEmpty())
strRet += ", ";
strRet += QChar('A' + i);
}
}
return strRet;
}
QString CAnswerClicked::answerText() const
{
return answerText(m_uAnswer);
}
QString CAnswerClicked::neededTimeText() const
{
if (m_uNeededTime < 1000)
return tr("&lt; 1 sec");
else if (m_uNeededTime < 60000)
return tr("%1 sec").arg(m_uNeededTime / 1000);
else
return tr("%1:%2 min").arg(m_uNeededTime / 60000).arg((m_uNeededTime / 1000) % 60, 2, 10, QChar('0'));
}
bool CAnswerClicked::isCorrect(const QList<CAnswer>& listAnswer) const
{
unsigned uMask=0;
for (int i=0; i<listAnswer.size(); i++)
{
if (listAnswer.at(i).isCorrect())
uMask |= (1<<i);
}
return (m_uAnswer == uMask);
}
bool CAnswerClicked::load (QDomElement elem)
{
bool bOk=false;
if (elem.tagName() != "answer_clicked") return false;
m_dt = QDateTime::fromString (elem.attribute("datetime"), Qt::ISODate);
if (!m_dt.isValid()) return false;
m_uAnswer = elem.attribute("answer_code").toUInt(&bOk);
if (!bOk) return false;
m_uNeededTime = elem.attribute("needed_time").toUInt(&bOk);
if (!bOk) return false;
return true;
}
void CAnswerClicked::save (QDomElement& parent, QDomDocument& doc) const
{
QDomElement elem = doc.createElement("answer_clicked");
elem.setAttribute("datetime", m_dt.toString(Qt::ISODate));
elem.setAttribute("answer_code", QString("%1").arg(m_uAnswer));
elem.setAttribute("needed_time", QString("%1").arg(m_uNeededTime));
parent.appendChild(elem);
}

284
answer.h
View File

@ -1,142 +1,142 @@
/***************************************************************************
* 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 ANSWER_H
#define ANSWER_H
#include <qstring.h>
#include <qdom.h>
#include <qlist.h>
#include <qdatetime.h>
//! Die Klasse CAnswer speichert eine einzelne Antwort auf eine Frage
/*!
Das Schreiben und Lesen von XML-Daten wird von der Klasse CQuestion übernommen
*/
class CAnswer
{
public:
//! Standard-Konstruktor
/*! Initialisiert die Klasse, indem die Funktion clear() aufgerufen wird. */
CAnswer() { clear(); }
//! Konstruktor inkl. setzen eines Textes und ob die Antwort richtig ist
/*!
\param strText Antworttext
\param bCorrect true: Die Antwort ist korrekt
\sa m_strText, m_bIsCorrect
*/
CAnswer(const QString& strText, const bool bCorrect);
//! Standard-Destruktor
/*! In der Standard-Implementierung tut der Destruktor nichts. */
~CAnswer() {}
//! Zurücksetzen aller Werte
/*! Es werden alle Daten der Antwort gelöscht. */
void clear();
//! Überprüfen, ob die Klasse eine Antwort enthält
/*! \return true: Die Klasse ist leer und enthält keine Antwort */
inline bool isEmpty() const { return m_strText.isEmpty(); }
//! Auslesen, ob diese Antwort richtig ist
/*! \return true: Die Antwort ist richtig */
inline bool isCorrect() const { return m_bIsCorrect; }
//! Auslesen des Antworttextes
/*! \return Antworttext */
inline QString text() const { return m_strText; }
//! Setzen, ob diese Antwort richtig ist
/*!
\param bCorrect true: Die Antwort ist korrekt
\sa m_bIsCorrect
*/
inline void setCorrect (const bool bCorrect) { m_bIsCorrect = bCorrect; }
//! Setzen des Antworttextes
/*!
\param strText Antworttext
\sa m_strText
*/
inline void setText(const QString& strText) { m_strText = strText; }
//! Anhängen eines Textes an den Antworttext
/*!
\param strText Anzuhängender Text
\sa m_strText
*/
inline void appendText(const QString& strText) { m_strText += strText; }
protected:
//! Antworttext
/*!
Der Antworttext darf HTML-Code und HTML-Verweise auf Grafiken/Bilder enthalten. Bei Verweisen ist zu achten, dass kein Verzeichnis angegeben werden darf!
Default: leer
*/
QString m_strText;
//! Richtige oder falsche Antwort
/*! Default: false */
bool m_bIsCorrect;
};
//! Die Klasse CAnswerClicked speichert eine einzelne Beantwortung des Benutzers
/*!
*/
class CAnswerClicked
{
public:
//! Standard-Konstruktor
/*! Initialisiert die Klasse, indem die Funktion clear() aufgerufen wird. */
CAnswerClicked () { clear(); }
CAnswerClicked (const unsigned uAnswer, const unsigned uNeededTime)
{ m_uAnswer = uAnswer; m_dt = QDateTime::currentDateTime(); m_uNeededTime = uNeededTime; }
//! Standard-Destruktor
/*! In der Standard-Implementierung tut der Destruktor nichts. */
~CAnswerClicked () {}
//! Zurücksetzen aller Werte
/*! Es werden alle Daten auf Default-Werte zurückgesetzt. */
void clear();
inline QDateTime dateTime() const { return m_dt; }
inline unsigned neededTime() const { return m_uNeededTime; }
inline unsigned answer() const { return m_uAnswer; }
static QString answerText(const unsigned uAnswer);
QString answerText() const;
QString neededTimeText() const;
bool isCorrect(const QList<CAnswer>& listAnswer) const;
bool load (QDomElement elem);
void save (QDomElement& parent, QDomDocument& doc) const;
static QString tr (const char *sourceText, const char *comment=0);
bool operator < (const CAnswerClicked& ac) const;
protected:
QDateTime m_dt; //!< Zeitstempel der Antwort
unsigned m_uAnswer; //!< Antwort-Bitmaske
unsigned m_uNeededTime; //!< Benötigte Zeit in ms
};
#endif
/***************************************************************************
* 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 ANSWER_H
#define ANSWER_H
#include <qstring.h>
#include <qdom.h>
#include <qlist.h>
#include <qdatetime.h>
//! Die Klasse CAnswer speichert eine einzelne Antwort auf eine Frage
/*!
Das Schreiben und Lesen von XML-Daten wird von der Klasse CQuestion übernommen
*/
class CAnswer
{
public:
//! Standard-Konstruktor
/*! Initialisiert die Klasse, indem die Funktion clear() aufgerufen wird. */
CAnswer() { clear(); }
//! Konstruktor inkl. setzen eines Textes und ob die Antwort richtig ist
/*!
\param strText Antworttext
\param bCorrect true: Die Antwort ist korrekt
\sa m_strText, m_bIsCorrect
*/
CAnswer(const QString& strText, const bool bCorrect);
//! Standard-Destruktor
/*! In der Standard-Implementierung tut der Destruktor nichts. */
~CAnswer() {}
//! Zurücksetzen aller Werte
/*! Es werden alle Daten der Antwort gelöscht. */
void clear();
//! Überprüfen, ob die Klasse eine Antwort enthält
/*! \return true: Die Klasse ist leer und enthält keine Antwort */
inline bool isEmpty() const { return m_strText.isEmpty(); }
//! Auslesen, ob diese Antwort richtig ist
/*! \return true: Die Antwort ist richtig */
inline bool isCorrect() const { return m_bIsCorrect; }
//! Auslesen des Antworttextes
/*! \return Antworttext */
inline QString text() const { return m_strText; }
//! Setzen, ob diese Antwort richtig ist
/*!
\param bCorrect true: Die Antwort ist korrekt
\sa m_bIsCorrect
*/
inline void setCorrect (const bool bCorrect) { m_bIsCorrect = bCorrect; }
//! Setzen des Antworttextes
/*!
\param strText Antworttext
\sa m_strText
*/
inline void setText(const QString& strText) { m_strText = strText; }
//! Anhängen eines Textes an den Antworttext
/*!
\param strText Anzuhängender Text
\sa m_strText
*/
inline void appendText(const QString& strText) { m_strText += strText; }
protected:
//! Antworttext
/*!
Der Antworttext darf HTML-Code und HTML-Verweise auf Grafiken/Bilder enthalten. Bei Verweisen ist zu achten, dass kein Verzeichnis angegeben werden darf!
Default: leer
*/
QString m_strText;
//! Richtige oder falsche Antwort
/*! Default: false */
bool m_bIsCorrect;
};
//! Die Klasse CAnswerClicked speichert eine einzelne Beantwortung des Benutzers
/*!
*/
class CAnswerClicked
{
public:
//! Standard-Konstruktor
/*! Initialisiert die Klasse, indem die Funktion clear() aufgerufen wird. */
CAnswerClicked () { clear(); }
CAnswerClicked (const unsigned uAnswer, const unsigned uNeededTime)
{ m_uAnswer = uAnswer; m_dt = QDateTime::currentDateTime(); m_uNeededTime = uNeededTime; }
//! Standard-Destruktor
/*! In der Standard-Implementierung tut der Destruktor nichts. */
~CAnswerClicked () {}
//! Zurücksetzen aller Werte
/*! Es werden alle Daten auf Default-Werte zurückgesetzt. */
void clear();
inline QDateTime dateTime() const { return m_dt; }
inline unsigned neededTime() const { return m_uNeededTime; }
inline unsigned answer() const { return m_uAnswer; }
static QString answerText(const unsigned uAnswer);
QString answerText() const;
QString neededTimeText() const;
bool isCorrect(const QList<CAnswer>& listAnswer) const;
bool load (QDomElement elem);
void save (QDomElement& parent, QDomDocument& doc) const;
static QString tr (const char *sourceText, const char *comment=0);
bool operator < (const CAnswerClicked& ac) const;
protected:
QDateTime m_dt; //!< Zeitstempel der Antwort
unsigned m_uAnswer; //!< Antwort-Bitmaske
unsigned m_uNeededTime; //!< Benötigte Zeit in ms
};
#endif

View File

@ -1,433 +1,433 @@
/***************************************************************************
* 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 "osziparchive.h"
#include "tools.h"
#include <qdir.h>
#include <qfile.h>
#include <qmessagebox.h>
#include <qtextstream.h>
#include <qvariant.h>
CCatalog::~CCatalog()
{
qDeleteAll(m_listFiles);
}
void CCatalog::clear()
{
CChapter::clear();
m_bMixAnswers = true;
m_bSort = false;
m_strFileName.clear();
m_listHint.clear();
m_strUniqueName.clear();
qDeleteAll(m_listFiles);
m_strPublisher.clear();
m_strContact.clear();
m_dateValidFrom = QDate();
m_dateValidUntil = QDate();
m_dateCreated = QDate();
m_datePublished = QDate();
m_strVersion.clear();
m_listExam.clear();
m_listExamStat.clear();
}
bool CCatalog::isEmpty()
{
return m_strText.isEmpty();
}
bool CCatalog::isValid() const
{
if (m_dateValidFrom.isValid() && QDate::currentDate() < m_dateValidFrom) return false;
if (m_dateValidUntil.isValid() && QDate::currentDate() > m_dateValidUntil) return false;
return true;
}
bool CCatalog::hasHints (const QString& strQuestionId) const
{
for (int i=0; i<m_listHint.size(); i++)
{
if (m_listHint.at(i).hasQuestion(strQuestionId)) return true;
}
return false;
}
QString CCatalog::hintText (const QString& strQuestionId) const
{
QString str;
if (strQuestionId.isEmpty()) return QString();
for (int i=0; i<m_listHint.size(); i++)
{
if (m_listHint.at(i).hasQuestion(strQuestionId))
str += m_listHint[i].showText();
}
return str;
}
bool CCatalog::load (const QString& strFileName, QWidget *pParent)
{
QDomDocument doc;
QDomElement elemRoot, e;
QDomNode n;
QString str, strXML;
int iErrLine, iErrCol;
double dVersion=0.0;
CChapter *pChapter=0;
if (strFileName.right(3).toLower() != "aqz") return false;
CZipArchive zip;
if (!zip.open(strFileName, CZipArchive::OpenReadOnly))
{
QMessageBox::critical(pParent, pParent->tr("Datei-Fehler"), pParent->tr("Konnte folgende Datei nicht zum Lesen öffnen:\n%1").arg(strFileName));
return false;
}
// Fragen entpacken
CZipFile *pzfQuestions = zip.findFile("questions.xml");
if (pzfQuestions == 0)
{
QMessageBox::critical(pParent, pParent->tr("Datei-Fehler"), pParent->tr("Konnte in der Datei '%1' keine Fragen finden.").arg(strFileName));
return false;
}
strXML = QString::fromUtf8(pzfQuestions->deflateToByteArray());
clear();
// Alle Grafiken in temp. Dateien entpacken
// pParent->setCursor(Qt::WaitCursor);
for (int i=0; i<zip.fileCount(); i++)
{
CZipFile *pzf = zip.fileAt(i);
str = pzf->fileName().right(3);
if (str == "png" || str == "jpg" || str == "gif" || str == "bmp")
{ // Datei entpacken und Pfade im XML anpassen
str = QDir::temp().absoluteFilePath(pzf->fileName()+".XXXXXX");
QTemporaryFile *ptf = new QTemporaryFile(str);
ptf->open();
str = ptf->fileName();
pzf->deflateToFile(*ptf);
ptf->close();
m_listFiles.append(ptf);
strXML.replace(pzf->fileName(), str);
//qDebug ("Deflating %s to %s", qPrintable(pzf->fileName()), qPrintable(str));
}
}
// pParent->setCursor(Qt::ArrowCursor);
if (!doc.setContent(strXML, true, &str, &iErrLine, &iErrCol))
{
QMessageBox::critical(pParent, pParent->tr("XML-Fehler"), pParent->tr("Fragenkatalog: ") + strFileName + "\n" + str + "\n" + QString (pParent->tr("Zeile: %1 Spalte %2")).arg(iErrLine).arg(iErrCol));
return false;
}
elemRoot = doc.documentElement ();
if (elemRoot.tagName() != "aqdf")
{
QMessageBox::critical(pParent, pParent->tr("Datei-Fehler"), pParent->tr("Unbekanntes XML-Datenformat '%1'.").arg(elemRoot.tagName()));
return false;
}
//m_strText = elemRoot.attribute ("name");
m_dateCreated = QDate::fromString(elemRoot.attribute("created"), Qt::ISODate);
dVersion = elemRoot.attribute("version").toDouble();
if (dVersion != 1.0)
{
QMessageBox::information(pParent, pParent->tr("Information"), pParent->tr("Kann die Dateiversion %1 des Fragenkatalogs '%2' nicht lesen.").arg(dVersion).arg(strFileName));
return false;
}
n = elemRoot.firstChild();
while (!n.isNull())
{
if (n.isElement ())
{
e = n.toElement ();
if (e.tagName() == QString ("chapter"))
{
pChapter = new CChapter();
if (pChapter->load (e))
appendChapter(pChapter);
else
delete pChapter;
}
else if (e.tagName() == QString ("exam"))
{
CExam exam;
if (exam.load(e)) m_listExam.append(exam);
}
else if (e.tagName () == "hint")
{
CHint hint;
if (hint.load (e))
m_listHint.append (hint);
}
else if (e.tagName () == "title")
{
m_strText = e.text();
m_strUniqueName = e.attribute("unique");
}
else if (e.tagName () == "comment")
m_strComment = e.text();
else if (e.tagName () == "contact")
m_strContact = e.text();
else if (e.tagName () == "publisher")
m_strPublisher = e.text();
else if (e.tagName() == "valid")
{
m_dateValidFrom = QDate::fromString(e.attribute("from"), Qt::ISODate);
m_dateValidUntil = QDate::fromString(e.attribute("until"), Qt::ISODate);
}
else if (e.tagName() == "version")
{
m_datePublished = QDate::fromString(e.attribute("published"), Qt::ISODate);
m_strVersion = e.text();
}
else if (e.tagName() == "options")
{
m_bMixAnswers = QVariant(e.attribute("mixanswers", "true")).toBool();
m_bSort = QVariant(e.attribute("sort", "false")).toBool();
}
}
n = n.nextSibling();
}
if (m_strUniqueName.isEmpty())
m_strUniqueName = QDir(strFileName).dirName();
if (m_bSort) sortAll();
loadStatistic (pParent);
updateStatistic();
m_strFileName = strFileName;
return true;
}
bool CCatalog::save (const QString& strFileName, QWidget *pParent)
{
QFile file (strFileName);
if (strFileName.isEmpty()) return false;
if (!file.open(QIODevice::WriteOnly))
{
QMessageBox::critical(pParent, QString(pParent->tr("Datei-Fehler")), pParent->tr("Konnte folgende Datei nicht zum Schreiben öffnen:\n")+strFileName);
return false;
}
QTextStream out(&file);
QDomDocument doc("afutrainer");
QDomElement elemRoot = doc.createElement("afutrainer");
//elemRoot.setAttribute("name", name());
elemRoot.setAttribute("version", 3.0);
elemRoot.setAttribute("created", QDate::currentDate().toString(Qt::ISODate));
doc.appendChild(elemRoot);
// save unique name
QDomElement elemTitle = createXmlTextElement("title", name(), doc);
elemTitle.setAttribute("unique", m_strUniqueName);
elemRoot.appendChild (elemTitle);
// save comment
if (!m_strComment.isEmpty())
elemRoot.appendChild (createXmlTextElement("comment", m_strComment, doc));
// save contact
if (!m_strContact.isEmpty())
elemRoot.appendChild (createXmlTextElement("contact", m_strContact, doc));
// save publisher
if (!m_strPublisher.isEmpty())
elemRoot.appendChild (createXmlTextElement("publisher", m_strPublisher, doc));
// save version
QDomElement elemVersion = createXmlTextElement("version", m_strVersion, doc);
elemVersion.setAttribute("published", m_datePublished.toString(Qt::ISODate));
elemRoot.appendChild(elemVersion);
// save dates
if (m_dateValidFrom.isValid() || m_dateValidUntil.isValid())
{
QDomElement elemValid = doc.createElement("valid");
elemValid.setAttribute("from", m_dateValidFrom.toString(Qt::ISODate));
elemValid.setAttribute("until", m_dateValidUntil.toString(Qt::ISODate));
elemRoot.appendChild(elemValid);
}
// TODO: save tests
// save chapters
for (int i=0; i<m_listChapter.size(); i++)
m_listChapter[i]->save(elemRoot, doc);
// save helpers
for (int i=0; i<m_listHint.size(); i++)
m_listHint[i].save(elemRoot, doc);
out << doc.toString();
m_strFileName = strFileName;
return true;
}
QString CCatalog::statisticFileName() const
{
QDir dir;
QString str = dir.homePath()+QString("/.afutrainer/") + m_strUniqueName + QString(".stat.xml");
Q_ASSERT(!m_strUniqueName.isEmpty());
return (str);
}
bool CCatalog::loadStatistic(QWidget *pParent)
{
QDomDocument doc;
QDomElement elemRoot, e;
QDomNode n;
QFile file (statisticFileName());
QString strVerzeichnis, str, strXML;
int iErrLine, iErrCol;
if (!file.exists()) return true;
if (!file.open (QIODevice::ReadOnly))
{
QMessageBox::critical(pParent, QString(pParent->tr("Datei-Fehler")), pParent->tr("Konnte folgende Datei nicht zum Lesen öffnen:\n")+statisticFileName());
return false;
}
QTextStream in (&file);
strXML = in.readAll();
if (!doc.setContent(strXML, true, &str, &iErrLine, &iErrCol))
{
QMessageBox::critical(pParent, pParent->tr("XML-Fehler"), pParent->tr("Statistik zum Fragenkatalog: ") + statisticFileName() + "\n" + str + "\n" + QString (pParent->tr("Zeile: %1 Spalte %2")).arg(iErrLine).arg(iErrCol));
return false;
}
file.close ();
elemRoot = doc.documentElement ();
if (doc.doctype().name() != "AFUTrainerStatistics") return false;
if (elemRoot.tagName() != "statistic") return false;
n = elemRoot.firstChild();
while (!n.isNull())
{
if (n.isElement ())
{
e = n.toElement ();
if (e.tagName() == QString ("learning"))
{
loadLearnStatistic(e);
}
else if (e.tagName() == QString("exams"))
loadExamStatistic(e);
}
n = n.nextSibling();
}
return true;
}
bool CCatalog::saveStatistic(QWidget *pParent)
{
QDomDocument doc ("AFUTrainerStatistics");
QString strFileName = statisticFileName();
QFile file (strFileName);
if (m_strUniqueName.isEmpty()) return false;
QDomElement elemRoot = doc.createElement ("statistic");
elemRoot.setAttribute ("name", name());
elemRoot.setAttribute("version", 2);
elemRoot.setAttribute("date", QDate::currentDate().toString(Qt::ISODate));
doc.appendChild (elemRoot);
QDomElement elemLearn = doc.createElement ("learning");
elemRoot.appendChild (elemLearn);
saveLearnStatistic(elemLearn, doc);
QDomElement elemExams = doc.createElement ("exams");
elemRoot.appendChild (elemExams);
saveExamStatistic(elemExams, doc);
if (!file.open (QIODevice::WriteOnly))
{
QMessageBox::critical (pParent, pParent->tr("Fehler"), pParent->tr("Konnte folgende Datei nicht zum Schreiben öffnen.\n")+strFileName);
return false;
}
QTextStream out(&file);
out << doc.toString ();
return true;
}
bool CCatalog::loadExamStatistic (QDomElement& elemRoot)
{
QDomNode n;
QDomElement e;
n = elemRoot.firstChild();
while (!n.isNull())
{
if (n.isElement ())
{
e = n.toElement ();
if (e.tagName() == QString ("exam"))
{
CExamStat es;
if (es.load(e)) m_listExamStat.append(es);
}
}
n = n.nextSibling();
}
return true;
}
void CCatalog::saveExamStatistic (QDomElement& parent, QDomDocument& doc)
{
for (int i=0; i<m_listExamStat.size(); i++)
{
m_listExamStat.at(i).save (parent, doc);
}
}
QList<CChapter*> CCatalog::chapters()
{
QList<CChapter*> list;
list.append(this);
list << subChapters();
return list;
}
CExam CCatalog::examById(const QString& strId) const
{
for (int i=0; i<m_listExam.size(); i++)
{
if (m_listExam.at(i).id() == strId)
return m_listExam.at(i);
}
return CExam();
}
/***************************************************************************
* 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 "osziparchive.h"
#include "tools.h"
#include <qdir.h>
#include <qfile.h>
#include <qmessagebox.h>
#include <qtextstream.h>
#include <qvariant.h>
CCatalog::~CCatalog()
{
qDeleteAll(m_listFiles);
}
void CCatalog::clear()
{
CChapter::clear();
m_bMixAnswers = true;
m_bSort = false;
m_strFileName.clear();
m_listHint.clear();
m_strUniqueName.clear();
qDeleteAll(m_listFiles);
m_strPublisher.clear();
m_strContact.clear();
m_dateValidFrom = QDate();
m_dateValidUntil = QDate();
m_dateCreated = QDate();
m_datePublished = QDate();
m_strVersion.clear();
m_listExam.clear();
m_listExamStat.clear();
}
bool CCatalog::isEmpty()
{
return m_strText.isEmpty();
}
bool CCatalog::isValid() const
{
if (m_dateValidFrom.isValid() && QDate::currentDate() < m_dateValidFrom) return false;
if (m_dateValidUntil.isValid() && QDate::currentDate() > m_dateValidUntil) return false;
return true;
}
bool CCatalog::hasHints (const QString& strQuestionId) const
{
for (int i=0; i<m_listHint.size(); i++)
{
if (m_listHint.at(i).hasQuestion(strQuestionId)) return true;
}
return false;
}
QString CCatalog::hintText (const QString& strQuestionId) const
{
QString str;
if (strQuestionId.isEmpty()) return QString();
for (int i=0; i<m_listHint.size(); i++)
{
if (m_listHint.at(i).hasQuestion(strQuestionId))
str += m_listHint[i].showText();
}
return str;
}
bool CCatalog::load (const QString& strFileName, QWidget *pParent)
{
QDomDocument doc;
QDomElement elemRoot, e;
QDomNode n;
QString str, strXML;
int iErrLine, iErrCol;
double dVersion=0.0;
CChapter *pChapter=0;
if (strFileName.right(3).toLower() != "aqz") return false;
CZipArchive zip;
if (!zip.open(strFileName, CZipArchive::OpenReadOnly))
{
QMessageBox::critical(pParent, pParent->tr("Datei-Fehler"), pParent->tr("Konnte folgende Datei nicht zum Lesen öffnen:\n%1").arg(strFileName));
return false;
}
// Fragen entpacken
CZipFile *pzfQuestions = zip.findFile("questions.xml");
if (pzfQuestions == 0)
{
QMessageBox::critical(pParent, pParent->tr("Datei-Fehler"), pParent->tr("Konnte in der Datei '%1' keine Fragen finden.").arg(strFileName));
return false;
}
strXML = QString::fromUtf8(pzfQuestions->deflateToByteArray());
clear();
// Alle Grafiken in temp. Dateien entpacken
// pParent->setCursor(Qt::WaitCursor);
for (int i=0; i<zip.fileCount(); i++)
{
CZipFile *pzf = zip.fileAt(i);
str = pzf->fileName().right(3);
if (str == "png" || str == "jpg" || str == "gif" || str == "bmp")
{ // Datei entpacken und Pfade im XML anpassen
str = QDir::temp().absoluteFilePath(pzf->fileName()+".XXXXXX");
QTemporaryFile *ptf = new QTemporaryFile(str);
ptf->open();
str = ptf->fileName();
pzf->deflateToFile(*ptf);
ptf->close();
m_listFiles.append(ptf);
strXML.replace(pzf->fileName(), str);
//qDebug ("Deflating %s to %s", qPrintable(pzf->fileName()), qPrintable(str));
}
}
// pParent->setCursor(Qt::ArrowCursor);
if (!doc.setContent(strXML, true, &str, &iErrLine, &iErrCol))
{
QMessageBox::critical(pParent, pParent->tr("XML-Fehler"), pParent->tr("Fragenkatalog: ") + strFileName + "\n" + str + "\n" + QString (pParent->tr("Zeile: %1 Spalte %2")).arg(iErrLine).arg(iErrCol));
return false;
}
elemRoot = doc.documentElement ();
if (elemRoot.tagName() != "aqdf")
{
QMessageBox::critical(pParent, pParent->tr("Datei-Fehler"), pParent->tr("Unbekanntes XML-Datenformat '%1'.").arg(elemRoot.tagName()));
return false;
}
//m_strText = elemRoot.attribute ("name");
m_dateCreated = QDate::fromString(elemRoot.attribute("created"), Qt::ISODate);
dVersion = elemRoot.attribute("version").toDouble();
if (dVersion != 1.0)
{
QMessageBox::information(pParent, pParent->tr("Information"), pParent->tr("Kann die Dateiversion %1 des Fragenkatalogs '%2' nicht lesen.").arg(dVersion).arg(strFileName));
return false;
}
n = elemRoot.firstChild();
while (!n.isNull())
{
if (n.isElement ())
{
e = n.toElement ();
if (e.tagName() == QString ("chapter"))
{
pChapter = new CChapter();
if (pChapter->load (e))
appendChapter(pChapter);
else
delete pChapter;
}
else if (e.tagName() == QString ("exam"))
{
CExam exam;
if (exam.load(e)) m_listExam.append(exam);
}
else if (e.tagName () == "hint")
{
CHint hint;
if (hint.load (e))
m_listHint.append (hint);
}
else if (e.tagName () == "title")
{
m_strText = e.text();
m_strUniqueName = e.attribute("unique");
}
else if (e.tagName () == "comment")
m_strComment = e.text();
else if (e.tagName () == "contact")
m_strContact = e.text();
else if (e.tagName () == "publisher")
m_strPublisher = e.text();
else if (e.tagName() == "valid")
{
m_dateValidFrom = QDate::fromString(e.attribute("from"), Qt::ISODate);
m_dateValidUntil = QDate::fromString(e.attribute("until"), Qt::ISODate);
}
else if (e.tagName() == "version")
{
m_datePublished = QDate::fromString(e.attribute("published"), Qt::ISODate);
m_strVersion = e.text();
}
else if (e.tagName() == "options")
{
m_bMixAnswers = QVariant(e.attribute("mixanswers", "true")).toBool();
m_bSort = QVariant(e.attribute("sort", "false")).toBool();
}
}
n = n.nextSibling();
}
if (m_strUniqueName.isEmpty())
m_strUniqueName = QDir(strFileName).dirName();
if (m_bSort) sortAll();
loadStatistic (pParent);
updateStatistic();
m_strFileName = strFileName;
return true;
}
bool CCatalog::save (const QString& strFileName, QWidget *pParent)
{
QFile file (strFileName);
if (strFileName.isEmpty()) return false;
if (!file.open(QIODevice::WriteOnly))
{
QMessageBox::critical(pParent, QString(pParent->tr("Datei-Fehler")), pParent->tr("Konnte folgende Datei nicht zum Schreiben öffnen:\n")+strFileName);
return false;
}
QTextStream out(&file);
QDomDocument doc("afutrainer");
QDomElement elemRoot = doc.createElement("afutrainer");
//elemRoot.setAttribute("name", name());
elemRoot.setAttribute("version", 3.0);
elemRoot.setAttribute("created", QDate::currentDate().toString(Qt::ISODate));
doc.appendChild(elemRoot);
// save unique name
QDomElement elemTitle = createXmlTextElement("title", name(), doc);
elemTitle.setAttribute("unique", m_strUniqueName);
elemRoot.appendChild (elemTitle);
// save comment
if (!m_strComment.isEmpty())
elemRoot.appendChild (createXmlTextElement("comment", m_strComment, doc));
// save contact
if (!m_strContact.isEmpty())
elemRoot.appendChild (createXmlTextElement("contact", m_strContact, doc));
// save publisher
if (!m_strPublisher.isEmpty())
elemRoot.appendChild (createXmlTextElement("publisher", m_strPublisher, doc));
// save version
QDomElement elemVersion = createXmlTextElement("version", m_strVersion, doc);
elemVersion.setAttribute("published", m_datePublished.toString(Qt::ISODate));
elemRoot.appendChild(elemVersion);
// save dates
if (m_dateValidFrom.isValid() || m_dateValidUntil.isValid())
{
QDomElement elemValid = doc.createElement("valid");
elemValid.setAttribute("from", m_dateValidFrom.toString(Qt::ISODate));
elemValid.setAttribute("until", m_dateValidUntil.toString(Qt::ISODate));
elemRoot.appendChild(elemValid);
}
// TODO: save tests
// save chapters
for (int i=0; i<m_listChapter.size(); i++)
m_listChapter[i]->save(elemRoot, doc);
// save helpers
for (int i=0; i<m_listHint.size(); i++)
m_listHint[i].save(elemRoot, doc);
out << doc.toString();
m_strFileName = strFileName;
return true;
}
QString CCatalog::statisticFileName() const
{
QDir dir;
QString str = dir.homePath()+QString("/.afutrainer/") + m_strUniqueName + QString(".stat.xml");
Q_ASSERT(!m_strUniqueName.isEmpty());
return (str);
}
bool CCatalog::loadStatistic(QWidget *pParent)
{
QDomDocument doc;
QDomElement elemRoot, e;
QDomNode n;
QFile file (statisticFileName());
QString strVerzeichnis, str, strXML;
int iErrLine, iErrCol;
if (!file.exists()) return true;
if (!file.open (QIODevice::ReadOnly))
{
QMessageBox::critical(pParent, QString(pParent->tr("Datei-Fehler")), pParent->tr("Konnte folgende Datei nicht zum Lesen öffnen:\n")+statisticFileName());
return false;
}
QTextStream in (&file);
strXML = in.readAll();
if (!doc.setContent(strXML, true, &str, &iErrLine, &iErrCol))
{
QMessageBox::critical(pParent, pParent->tr("XML-Fehler"), pParent->tr("Statistik zum Fragenkatalog: ") + statisticFileName() + "\n" + str + "\n" + QString (pParent->tr("Zeile: %1 Spalte %2")).arg(iErrLine).arg(iErrCol));
return false;
}
file.close ();
elemRoot = doc.documentElement ();
if (doc.doctype().name() != "AFUTrainerStatistics") return false;
if (elemRoot.tagName() != "statistic") return false;
n = elemRoot.firstChild();
while (!n.isNull())
{
if (n.isElement ())
{
e = n.toElement ();
if (e.tagName() == QString ("learning"))
{
loadLearnStatistic(e);
}
else if (e.tagName() == QString("exams"))
loadExamStatistic(e);
}
n = n.nextSibling();
}
return true;
}
bool CCatalog::saveStatistic(QWidget *pParent)
{
QDomDocument doc ("AFUTrainerStatistics");
QString strFileName = statisticFileName();
QFile file (strFileName);
if (m_strUniqueName.isEmpty()) return false;
QDomElement elemRoot = doc.createElement ("statistic");
elemRoot.setAttribute ("name", name());
elemRoot.setAttribute("version", 2);
elemRoot.setAttribute("date", QDate::currentDate().toString(Qt::ISODate));
doc.appendChild (elemRoot);
QDomElement elemLearn = doc.createElement ("learning");
elemRoot.appendChild (elemLearn);
saveLearnStatistic(elemLearn, doc);
QDomElement elemExams = doc.createElement ("exams");
elemRoot.appendChild (elemExams);
saveExamStatistic(elemExams, doc);
if (!file.open (QIODevice::WriteOnly))
{
QMessageBox::critical (pParent, pParent->tr("Fehler"), pParent->tr("Konnte folgende Datei nicht zum Schreiben öffnen.\n")+strFileName);
return false;
}
QTextStream out(&file);
out << doc.toString ();
return true;
}
bool CCatalog::loadExamStatistic (QDomElement& elemRoot)
{
QDomNode n;
QDomElement e;
n = elemRoot.firstChild();
while (!n.isNull())
{
if (n.isElement ())
{
e = n.toElement ();
if (e.tagName() == QString ("exam"))
{
CExamStat es;
if (es.load(e)) m_listExamStat.append(es);
}
}
n = n.nextSibling();
}
return true;
}
void CCatalog::saveExamStatistic (QDomElement& parent, QDomDocument& doc)
{
for (int i=0; i<m_listExamStat.size(); i++)
{
m_listExamStat.at(i).save (parent, doc);
}
}
QList<CChapter*> CCatalog::chapters()
{
QList<CChapter*> list;
list.append(this);
list << subChapters();
return list;
}
CExam CCatalog::examById(const QString& strId) const
{
for (int i=0; i<m_listExam.size(); i++)
{
if (m_listExam.at(i).id() == strId)
return m_listExam.at(i);
}
return CExam();
}

240
catalog.h
View File

@ -1,120 +1,120 @@
/***************************************************************************
* 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 CATALOG_H
#define CATALOG_H
#include "chapter.h"
#include "exam.h"
#include <qlist.h>
#include <qtemporaryfile.h>
class CCatalog : public CChapter
{
public:
CCatalog() : CChapter() { clear(); }
~CCatalog();
void clear();
bool isEmpty();
inline QString name() const { return m_strText; }
inline void setName(const QString& strName) { m_strText = strName; }
inline QString contact() const { return m_strContact; }
inline void setContact(const QString& strContact) { m_strContact = strContact; }
inline QString publisher() const { return m_strPublisher; }
inline void setPublisher(const QString& strPublisher) { m_strPublisher = strPublisher; }
// Validation
inline QDate validFrom() const { return m_dateValidFrom; }
inline void setValidFrom(const QDate& date) { m_dateValidFrom = date; }
inline QDate validUntil() const { return m_dateValidUntil; }
inline void setValidUntil(const QDate& date) { m_dateValidUntil = date; }
bool isValid() const;
inline QDate created() const { return m_dateCreated; }
inline void setCreated(const QDate& date) { m_dateCreated = date; }
inline QDate published() const { return m_datePublished; }
inline void setPublished(const QDate& date) { m_datePublished = date; }
inline QString versionText() const { return m_strVersion; }
inline void setVersionText(const QString& str) { m_strVersion = str; }
// file operations
inline QString fileName() const { return m_strFileName; }
bool load (const QString& strFileName, QWidget *pParent);
bool save (const QString& strFileName, QWidget *pParent);
bool loadStatistic(QWidget *pParent);
bool saveStatistic(QWidget *pParent);
// hints
inline int countHint() const { return m_listHint.size(); }
inline const CHint& hintAt(int i) const { return m_listHint.at(i); }
inline CHint& hintAt(int i) { return m_listHint[i]; }
inline void appendHint(const CHint& a) { m_listHint.append(a); }
bool hasHints (const QString& strQuestionId) const;
QString hintText (const QString& strQuestionId) const;
// exams
inline int countExam() const { return m_listExam.size(); }
inline const CExam& examAt(int i) const { return m_listExam.at(i); }
inline CExam& examAt(int i) { return m_listExam[i]; }
inline void appendExam(const CExam& a) { m_listExam.append(a); }
CExam examById(const QString& strId) const;
inline void appendExamStat(const CExamStat& a) { m_listExamStat.append(a); }
inline int countExamStat() const { return m_listExamStat.size(); }
inline const CExamStat& examStatAt(int i) const { return m_listExamStat.at(i); }
// options
inline bool useMixedAnswers() const { return m_bMixAnswers; }
// others
QList<CChapter*> chapters();
protected:
QString statisticFileName() const;
bool loadExamStatistic (QDomElement& elemRoot);
void saveExamStatistic (QDomElement& parent, QDomDocument& doc);
protected:
QString m_strFileName;
QString m_strUniqueName;
QList<QTemporaryFile*> m_listFiles;
QList<CHint> m_listHint;
QString m_strContact;
QString m_strPublisher;
QDate m_dateValidFrom;
QDate m_dateValidUntil;
QDate m_dateCreated;
QDate m_datePublished;
QString m_strVersion;
QList<CExam> m_listExam;
QList<CExamStat> m_listExamStat;
// Optionen
bool m_bMixAnswers;
bool m_bSort;
};
#endif
/***************************************************************************
* 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 CATALOG_H
#define CATALOG_H
#include "chapter.h"
#include "exam.h"
#include <qlist.h>
#include <qtemporaryfile.h>
class CCatalog : public CChapter
{
public:
CCatalog() : CChapter() { clear(); }
~CCatalog();
void clear();
bool isEmpty();
inline QString name() const { return m_strText; }
inline void setName(const QString& strName) { m_strText = strName; }
inline QString contact() const { return m_strContact; }
inline void setContact(const QString& strContact) { m_strContact = strContact; }
inline QString publisher() const { return m_strPublisher; }
inline void setPublisher(const QString& strPublisher) { m_strPublisher = strPublisher; }
// Validation
inline QDate validFrom() const { return m_dateValidFrom; }
inline void setValidFrom(const QDate& date) { m_dateValidFrom = date; }
inline QDate validUntil() const { return m_dateValidUntil; }
inline void setValidUntil(const QDate& date) { m_dateValidUntil = date; }
bool isValid() const;
inline QDate created() const { return m_dateCreated; }
inline void setCreated(const QDate& date) { m_dateCreated = date; }
inline QDate published() const { return m_datePublished; }
inline void setPublished(const QDate& date) { m_datePublished = date; }
inline QString versionText() const { return m_strVersion; }
inline void setVersionText(const QString& str) { m_strVersion = str; }
// file operations
inline QString fileName() const { return m_strFileName; }
bool load (const QString& strFileName, QWidget *pParent);
bool save (const QString& strFileName, QWidget *pParent);
bool loadStatistic(QWidget *pParent);
bool saveStatistic(QWidget *pParent);
// hints
inline int countHint() const { return m_listHint.size(); }
inline const CHint& hintAt(int i) const { return m_listHint.at(i); }
inline CHint& hintAt(int i) { return m_listHint[i]; }
inline void appendHint(const CHint& a) { m_listHint.append(a); }
bool hasHints (const QString& strQuestionId) const;
QString hintText (const QString& strQuestionId) const;
// exams
inline int countExam() const { return m_listExam.size(); }
inline const CExam& examAt(int i) const { return m_listExam.at(i); }
inline CExam& examAt(int i) { return m_listExam[i]; }
inline void appendExam(const CExam& a) { m_listExam.append(a); }
CExam examById(const QString& strId) const;
inline void appendExamStat(const CExamStat& a) { m_listExamStat.append(a); }
inline int countExamStat() const { return m_listExamStat.size(); }
inline const CExamStat& examStatAt(int i) const { return m_listExamStat.at(i); }
// options
inline bool useMixedAnswers() const { return m_bMixAnswers; }
// others
QList<CChapter*> chapters();
protected:
QString statisticFileName() const;
bool loadExamStatistic (QDomElement& elemRoot);
void saveExamStatistic (QDomElement& parent, QDomDocument& doc);
protected:
QString m_strFileName;
QString m_strUniqueName;
QList<QTemporaryFile*> m_listFiles;
QList<CHint> m_listHint;
QString m_strContact;
QString m_strPublisher;
QDate m_dateValidFrom;
QDate m_dateValidUntil;
QDate m_dateCreated;
QDate m_datePublished;
QString m_strVersion;
QList<CExam> m_listExam;
QList<CExamStat> m_listExamStat;
// Optionen
bool m_bMixAnswers;
bool m_bSort;
};
#endif

View File

@ -1,205 +1,205 @@
/***************************************************************************
* 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 "catalogmodel.h"
#include "catalog.h"
#define COL_CHAPTER 0
#define COL_QUESTION 1
#define COL_ASSIST 2
#define COL_AVG 3
CCatalogModel::CCatalogModel (QObject *pParent) : QAbstractItemModel (pParent)
{
m_pCatalog = 0;
}
CCatalogModel::~CCatalogModel()
{
}
void CCatalogModel::onLanguageChanged()
{
headerDataChanged(Qt::Horizontal, 0, columnCount()-1);
}
void CCatalogModel::setModelData (CCatalog *pCatalog)
{
reset();
m_pCatalog = pCatalog;
reset();
}
int CCatalogModel::columnCount (const QModelIndex& parent) const
{
Q_UNUSED(parent);
return 4;
}
QVariant CCatalogModel::headerData (int section, Qt::Orientation orientation, int role) const
{
if (orientation == Qt::Vertical) return QVariant();
if (role == Qt::DisplayRole)
{
if (section == COL_CHAPTER)
return tr("Kapitel");
else if (section == COL_QUESTION)
return tr("Fragen");
else if (section == COL_AVG)
return tr("Ø");
else if (section == COL_ASSIST)
return tr("Lernassistent");
}
else if (role == Qt::ToolTipRole)
{
if (section == COL_CHAPTER)
return tr("Kapitelname\nBitte markieren Sie das Kapitel, das Sie lernen möchten.");
else if (section == COL_QUESTION)
return tr("Anzahl d. Fragen inkl. Unterkapitel");
else if (section == COL_AVG)
return tr("Durchschnittlicher Lernfortschritt");
else if (section == COL_ASSIST)
return tr("Empfehlung des Lernassistentes");
}
else if (role == Qt::WhatsThisRole)
{
}
return QVariant();
}
QVariant CCatalogModel::data (const QModelIndex& index, int role) const
{
CChapter *p = (CChapter*) index.internalPointer();
if (m_pCatalog == 0 || !index.isValid()) return QVariant();
if (role == Qt::TextAlignmentRole && index.column() == COL_QUESTION) return Qt::AlignRight;
if (p == 0) return QVariant();
if (role == Qt::DisplayRole)
{
if (index.column() == COL_CHAPTER)
{
if (p->id().isEmpty())
return p->text();
else
return p->id() + " - " + p->text();
}
else if (index.column() == COL_QUESTION)
return QString("%1").arg(p->countSubQuestion());
else if (index.column() == COL_ASSIST)
{
return p->recommendationText();
}
}
else if (role == Qt::DecorationRole)
{
if (index.column() == COL_CHAPTER)
return QIcon(":/icons/16x16/folder.png");
else if (index.column() == COL_AVG)
{
return p->levelAvgIcon();
}
else if (index.column() == COL_ASSIST)
{
return p->recommendationIcon(m_pCatalog);
}
}
else if (role == Qt::ToolTipRole)
{
if (index.column() == COL_AVG)
{
return QString ("%1 - Kennzahl: %2").arg(p->/*statistic().*/levelAvgText()).arg(p->/*statistic().*/levelAvg(), 4, 'f', 2);
}
else if (index.column() == COL_ASSIST)
{
return p->recommendationToolTip();
}
}
return QVariant();
}
bool CCatalogModel::hasChildren (const QModelIndex& parent) const
{
CChapter *p = (CChapter*) parent.internalPointer();
if (m_pCatalog == 0) return false;
if (parent.isValid() && p)
return (p->countChapter() > 0);
else // root item
return true;
}
QModelIndex CCatalogModel::index (int row, int column, const QModelIndex& parent) const
{
CChapter *pParent = (CChapter*) parent.internalPointer();
if (!parent.isValid())
{ // root item
return createIndex (row, column, (void*) m_pCatalog);
}
else
{
// take entry from parent item
if (row > pParent->countChapter())
return QModelIndex();
return createIndex (row, column, (void*)pParent->chapterAt(row));
}
return QModelIndex();
}
QModelIndex CCatalogModel::parent (const QModelIndex& index) const
{
CChapter *pIndex = (CChapter*) index.internalPointer();
int iRow=0;
if (pIndex == 0 || pIndex->parentChapter() == 0) // root item
return QModelIndex(); // has no parent
CChapter *pParent = pIndex->parentChapter();
if (pParent->parentChapter())
iRow = pParent->parentChapter()->indexOfChapter(pParent);
else // parent is the root item (parent of the parent doesn't exist)
iRow = 0;
return createIndex (iRow, 0 /*index.column()*/, pParent);
}
int CCatalogModel::rowCount (const QModelIndex& parent) const
{
CChapter *pParent = (CChapter*) parent.internalPointer();
if (m_pCatalog == 0 || m_pCatalog->isEmpty()) return 0;
if (!parent.isValid()) // root item
return 1;
return pParent->countChapter();
}
/***************************************************************************
* 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 "catalogmodel.h"
#include "catalog.h"
#define COL_CHAPTER 0
#define COL_QUESTION 1
#define COL_ASSIST 2
#define COL_AVG 3
CCatalogModel::CCatalogModel (QObject *pParent) : QAbstractItemModel (pParent)
{
m_pCatalog = 0;
}
CCatalogModel::~CCatalogModel()
{
}
void CCatalogModel::onLanguageChanged()
{
headerDataChanged(Qt::Horizontal, 0, columnCount()-1);
}
void CCatalogModel::setModelData (CCatalog *pCatalog)
{
reset();
m_pCatalog = pCatalog;
reset();
}
int CCatalogModel::columnCount (const QModelIndex& parent) const
{
Q_UNUSED(parent);
return 4;
}
QVariant CCatalogModel::headerData (int section, Qt::Orientation orientation, int role) const
{
if (orientation == Qt::Vertical) return QVariant();
if (role == Qt::DisplayRole)
{
if (section == COL_CHAPTER)
return tr("Kapitel");
else if (section == COL_QUESTION)
return tr("Fragen");
else if (section == COL_AVG)
return tr("Ø");
else if (section == COL_ASSIST)
return tr("Lernassistent");
}
else if (role == Qt::ToolTipRole)
{
if (section == COL_CHAPTER)
return tr("Kapitelname\nBitte markieren Sie das Kapitel, das Sie lernen möchten.");
else if (section == COL_QUESTION)
return tr("Anzahl d. Fragen inkl. Unterkapitel");
else if (section == COL_AVG)
return tr("Durchschnittlicher Lernfortschritt");
else if (section == COL_ASSIST)
return tr("Empfehlung des Lernassistentes");
}
else if (role == Qt::WhatsThisRole)
{
}
return QVariant();
}
QVariant CCatalogModel::data (const QModelIndex& index, int role) const
{
CChapter *p = (CChapter*) index.internalPointer();
if (m_pCatalog == 0 || !index.isValid()) return QVariant();
if (role == Qt::TextAlignmentRole && index.column() == COL_QUESTION) return Qt::AlignRight;
if (p == 0) return QVariant();
if (role == Qt::DisplayRole)
{
if (index.column() == COL_CHAPTER)
{
if (p->id().isEmpty())
return p->text();
else
return p->id() + " - " + p->text();
}
else if (index.column() == COL_QUESTION)
return QString("%1").arg(p->countSubQuestion());
else if (index.column() == COL_ASSIST)
{
return p->recommendationText();
}
}
else if (role == Qt::DecorationRole)
{
if (index.column() == COL_CHAPTER)
return QIcon(":/icons/16x16/folder.png");
else if (index.column() == COL_AVG)
{
return p->levelAvgIcon();
}
else if (index.column() == COL_ASSIST)
{
return p->recommendationIcon(m_pCatalog);
}
}
else if (role == Qt::ToolTipRole)
{
if (index.column() == COL_AVG)
{
return QString ("%1 - Kennzahl: %2").arg(p->/*statistic().*/levelAvgText()).arg(p->/*statistic().*/levelAvg(), 4, 'f', 2);
}
else if (index.column() == COL_ASSIST)
{
return p->recommendationToolTip();
}
}
return QVariant();
}
bool CCatalogModel::hasChildren (const QModelIndex& parent) const
{
CChapter *p = (CChapter*) parent.internalPointer();
if (m_pCatalog == 0) return false;
if (parent.isValid() && p)
return (p->countChapter() > 0);
else // root item
return true;
}
QModelIndex CCatalogModel::index (int row, int column, const QModelIndex& parent) const
{
CChapter *pParent = (CChapter*) parent.internalPointer();
if (!parent.isValid())
{ // root item
return createIndex (row, column, (void*) m_pCatalog);
}
else
{
// take entry from parent item
if (row > pParent->countChapter())
return QModelIndex();
return createIndex (row, column, (void*)pParent->chapterAt(row));
}
return QModelIndex();
}
QModelIndex CCatalogModel::parent (const QModelIndex& index) const
{
CChapter *pIndex = (CChapter*) index.internalPointer();
int iRow=0;
if (pIndex == 0 || pIndex->parentChapter() == 0) // root item
return QModelIndex(); // has no parent
CChapter *pParent = pIndex->parentChapter();
if (pParent->parentChapter())
iRow = pParent->parentChapter()->indexOfChapter(pParent);
else // parent is the root item (parent of the parent doesn't exist)
iRow = 0;
return createIndex (iRow, 0 /*index.column()*/, pParent);
}
int CCatalogModel::rowCount (const QModelIndex& parent) const
{
CChapter *pParent = (CChapter*) parent.internalPointer();
if (m_pCatalog == 0 || m_pCatalog->isEmpty()) return 0;
if (!parent.isValid()) // root item
return 1;
return pParent->countChapter();
}

View File

@ -1,55 +1,55 @@
/***************************************************************************
* 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 CATALOGMODEL_H
#define CATALOGMODEL_H
#include <qabstractitemmodel.h>
class CCatalog;
class CCatalogModel : public QAbstractItemModel
{
Q_OBJECT
public:
CCatalogModel (QObject *pParent=0);
~CCatalogModel();
void setModelData (CCatalog *pCatalog);
public:
virtual int columnCount ( const QModelIndex & parent = QModelIndex() ) const;
virtual QVariant data ( const QModelIndex & index, int role = Qt::DisplayRole ) const;
virtual bool hasChildren (const QModelIndex & parent = QModelIndex()) const;
virtual QVariant headerData ( int section, Qt::Orientation orientation, int role = Qt::DisplayRole ) const;
virtual QModelIndex index (int row, int column, const QModelIndex & parent = QModelIndex()) const;
virtual QModelIndex parent ( const QModelIndex & index ) const;
virtual int rowCount ( const QModelIndex & parent = QModelIndex() ) const;
public slots:
void onLanguageChanged();
protected:
CCatalog *m_pCatalog;
};
#endif
/***************************************************************************
* 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 CATALOGMODEL_H
#define CATALOGMODEL_H
#include <qabstractitemmodel.h>
class CCatalog;
class CCatalogModel : public QAbstractItemModel
{
Q_OBJECT
public:
CCatalogModel (QObject *pParent=0);
~CCatalogModel();
void setModelData (CCatalog *pCatalog);
public:
virtual int columnCount ( const QModelIndex & parent = QModelIndex() ) const;
virtual QVariant data ( const QModelIndex & index, int role = Qt::DisplayRole ) const;
virtual bool hasChildren (const QModelIndex & parent = QModelIndex()) const;
virtual QVariant headerData ( int section, Qt::Orientation orientation, int role = Qt::DisplayRole ) const;
virtual QModelIndex index (int row, int column, const QModelIndex & parent = QModelIndex()) const;
virtual QModelIndex parent ( const QModelIndex & index ) const;
virtual int rowCount ( const QModelIndex & parent = QModelIndex() ) const;
public slots:
void onLanguageChanged();
protected:
CCatalog *m_pCatalog;
};
#endif

File diff suppressed because it is too large Load Diff

484
chapter.h
View File

@ -1,242 +1,242 @@
/***************************************************************************
* 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 CHAPTER_H
#define CHAPTER_H
#include "question.h"
//#include "recommendation.h"
//#include "chapterstatistic.h"
#include <qmap.h>
//! Die Klasse CChapter speichert ein Kapitel mit allen Unterkapiteln und Fragen
/*!
*/
class CChapter
{
public:
//! Empfehlung für Kapitel
enum Recommendation
{
RecommendationNone=0, //!< Keine Emfehlung
RecommendationSubChapter=1, //!< Untergeordnetes Kapitel lernen
RecommendationParentChapter=2, //!< Übergeordnetes Kapitel lernen
RecommendationRepeatToday=3, //!< Kapitel heute wiederholen
RecommendationLearnNew=4, //!< Neue Fragen lernen
RecommendationRepeatLater=5, //!< Kapitel später wiederholen
RecommendationMax=6 //!< Für for-Schleifen, etc.
};
//! Standard-Konstruktor
/*! Initialisiert die Klasse, indem die Funktion clear() aufgerufen wird. */
CChapter() { clear(); }
//! Standard-Destruktor
/*! Es werden alle Unterkapitel und Fragen dieses Kapitels aus dem Speicher gelöscht. */
~CChapter() { qDeleteAll(m_listChapter); qDeleteAll(m_listQuestion); }
//! Zurücksetzen aller Werte
/*! Es werden alle Unterkapitel und Fragen dieses Kapitels aus dem Speicher gelöscht und alle andere Daten auf die Default-Werte zurückgesetzt. */
void clear();
//! Elternkapitel auslesen
/*!
\return Elternkapitel m_pParentChapter
\sa 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 dieses Kapitels
\sa parentChapter(), m_pParentChapter
*/
inline void setParentChapter(CChapter *pChapter) { m_pParentChapter = pChapter; }
//! ID dieses Kapitels auslesen
inline QString id() const { return m_strId; }
//! ID dieses Kapitels zusammengesetzt mit allen IDs der Eltern-Kapitel auslesen
QString idWithParents() const;
//! Kapitelbeschreibung auslesen
inline QString text() const { return m_strText; }
//! Kommentar
inline QString comment() const { return m_strComment; }
//! ID setzen
inline void setId (const QString& strId) { m_strId = strId; }
//! Kapitelbeschreibung setzen
inline void setText (const QString& strText) { m_strText = strText; }
//! Kommentar setzen
inline void setComment (const QString& strComment) { m_strComment = strComment; }
//! Anhängen eines Textes an die Kapitelbeschreibung
/*!
\param strText Anzuhängender Text
\sa m_strText
*/
inline void appendText(const QString& strText) { m_strText += strText; }
//! Anzahl der Unterkapitel ermitteln
/*! \return Anzahl der Unterkapitel */
inline int countChapter() const { return m_listChapter.size(); }
inline const CChapter* chapterAt(int i) const { return m_listChapter.at(i); }
inline int indexOfChapter(CChapter* c) const { return m_listChapter.indexOf(c); }
inline void appendChapter(CChapter* c) { m_listChapter.append(c); c->setParentChapter(this); }
// inline void removeChapter(int i) { delete m_listChapter.takeAt(i); }
QList<CChapter*> subChapters() const;
inline void sortAll() { sortSubChapters(true); sortQuestions(); }
void sortSubChapters(bool bSortQuestions);
void sortQuestions();
//! Anzahl der Fragen dieses Kapitels und aller Unterkapitel ermitteln
/*! \return Anzahl der Fragen */
int countSubQuestion() const;
//! Anzahl der Fragen dieses Kapitels (ohne Unterkapitel) ermitteln
/*! \return Anzahl der Fragen */
inline int countQuestion() const { return m_listQuestion.size(); }
inline const CQuestion* questionAt(int i) const { return m_listQuestion.at(i); }
inline CQuestion* questionAt(int i) { return m_listQuestion.at(i); }
inline void appendQuestion(CQuestion* q) { m_listQuestion.append(q); q->setParentChapter(this); }
QList<CQuestion*> questionPool() const;
QList<CQuestion*> questionPoolLevel(const unsigned uLevel) const;
QList<CQuestion*> questionPoolDeepen() const;
QList<CQuestion*> questionPoolRepeat(const QDate d=QDate::currentDate()) const;
bool load (QDomElement elem);
void save (QDomElement& parent, QDomDocument& doc);
bool loadLearnStatistic (QDomElement elem);
bool saveLearnStatistic (QDomElement& parent, QDomDocument& doc);
QString checkForErrors() const;
// Kapitelstatistik auslesen
/*
\return Kapitelstatistik (Variable m_cs)
\sa m_cs
*/
// inline CChapterStatistic statistic() const { return m_cs; }
//! @name Funktionen zur Statistik
//@{
void updateStatistic(); //!< Kapitelstatistik aktualisieren
//! Anzahl der Fragen einer bestimmten Abfragehäufigkeit
inline unsigned countQuestion(const unsigned uLevel) const { return m_uLevelCount[uLevel]; }
double levelAvg() const; //!< Durchschnittlicher Lernfortschritt des Kapitels
unsigned levelAvgRounded() const; //!< Durchschnittlicher, gerundeter Lernfortschritt des Kapitels
QString levelAvgText() const; //!< Durchschnittlicher Lernfortschritt als Text
QIcon levelAvgIcon() const; //!< Icon zum durchschnittlichen Lernfortschritt
QPixmap levelAvgPixmap() const; //!< Pixmap zum durchschnittlichen Lernfortschritt
//! Anzahl der noch nie abgefragen Fragen
inline unsigned countNeverAsked() const { return m_uNeverAskedCount; }
//!< Kapitel inkl. Unterkapitel enthalten Fragen, die gerade gelernt werden
inline bool hasLearningNewQuestions() const { return m_bHasLearningNew; }
inline bool hasKnownQuestions() const { return m_bHasKnownQuestions; }
inline bool hasKnownQuestionsRepeatToday() const { return m_bHasKnownQuestionsRepeatToday; }
CDayStatistic dayStatistic (const QDate& date) const; //<! Statistik eines Tages
CDayStatistic completeStatistic() const; //<! Statistik des kompletten Zeitraums
QDateTime firstAnswerClicked() const; //<! Datum, zu dem zum allerersten Mal eine Frage beantwortet wurde
//@}
//! @name Funktionen zur Lernempfehlung
//@{
QDate repeatDate() const; //!< Wiederhol-Datum des Kapitels
//! Lernempfehlung für das Kapitel
/*! \return Lernempfehlung (Variable m_recom) \sa m_recom */
inline Recommendation recommendation() const { return m_recom; }
QString recommendationIconName(const CCatalog *pCatalog) const; //!< Name des Icons zur Lernempfehlung ermitteln
//! Ermittelt Icon zur Lernempfehlung
inline QIcon recommendationIcon (const CCatalog *pCatalog) const { return QIcon (recommendationIconName(pCatalog)); }
QString recommendationText() const; //!< Lernempfehlungstext (kurz)
QString recommendationTextExtended(const CCatalog *pCatalog) const; //!< Lernempfehlungstext (ausführlich)
QString recommendationToolTip() const; //!< Lernempfehlungstext für Tooltip
bool isRecommendedNow(const CCatalog *pCatalog) const; //!< Kapitel sollte jetzt gelernt werden
//! Anzahl der Unterkapitel mit einer bestimmten Lernempfehlung
inline unsigned recommendationCount(const Recommendation r) const { return m_uRecomCount[r]; }
//! Fragen, die beantwortet müssen, um die Lernempfehlung zu erfüllen
inline QList<CQuestion*> recommendedQuestions() const { return m_listQuestionRecommended; }
//! Kapitel hat Fragen, die beantwortet müssen, um die Lernempfehlung zu erfüllen
inline bool hasRecommendedQuestions() const { return m_listQuestionRecommended.size() > 0; }
//! Anzahl der Fragen, die beantwortet müssen, um die Lernempfehlung zu erfüllen
inline int recommendedQuestionCount() const { return m_listQuestionRecommended.size(); }
//! Alternative Lernempfehlung für das Kapitel
inline Recommendation recommendation2() const { return m_recom2; }
QString recommendationTextExtended2(const CCatalog *pCatalog) const; //!< Alternativer Lernempfehlungstext (ausführlich)
//@}
//! @name Funktionen zu Prüfungen
//@{
// inline void setExam(const QString& strId, const unsigned uQuestionCount) { m_mapExam.insert(strId, uQuestionCount); }
// inline unsigned examQuestionCount(const QString& strId) const { return m_mapExam[strId]; }
//@}
// static
static QString tr (const char *sourceText, const char *comment=0);
static QString recommendationText(const Recommendation r, const QDate dRepeat);
static QString recommendationIconName(const Recommendation r, const CCatalog *pCatalog);
protected:
void updateStatisticCount(); //!< Zählt alle Fragen des Kapitels (inkl. Unterkapitel) für die Statistik
void updateRecommendation(); //!< Lernempfehlung für das Kapitel (inkl. Unterkapitel) aktualisieren
void updateRecommendationStatistic(); //!< Statistik über Lernempfehlungen für das Kapitel (inkl. Unterkapitel) aktualisieren
Recommendation recommendationIndividual() const; //!< Empfehlung nur für dieses Kapitel, Unterkapitel und Elternkapitel werden ignoriert
protected:
CChapter *m_pParentChapter; //!< Übergeordnetes Kapitel
QString m_strId; //!< ID des Kapitels
QString m_strText; //!< Name des Kapitels
QString m_strComment; //!< Kommentar
QList<CChapter*> m_listChapter; //!< Liste mit Unterkapiteln
QList<CQuestion*> m_listQuestion; //!< Liste mit Fragen
// Statistik
unsigned m_uLevelCount[LEVEL_MAX+1]; //!< Anzahl der Fragen einer bestimmten Abfragehäufigkeit
unsigned m_uNeverAskedCount; //!< Anzahl der Fragen, die noch nie abgefragt wurden
unsigned m_uRecomCount[RecommendationMax]; //!< Anzahl der Unterkapitel (inkl. selbst) mit bestimmter Lernempfehlung
bool m_bHasLearningNew; //!< Kapitel enthält Fragen, die gerade neu gelernt werden
bool m_bHasKnownQuestions; //!< Kapitel enthält Fragen, die seit mind. gestern bekannt sind
bool m_bHasKnownQuestionsRepeatToday; //!< Kapitel enthält Fragen, die seit mind. gestern bekannt sind und heute wiederholt werden sollten
Recommendation m_recom; //!< Lernempfehlung
Recommendation m_recom2; //!< Alternative Lernempfehlung
//! Empfohlenes Datum zur Wiederholung der Fragen
/*! Diese Variable wird mit der Funktion updateRecommendation() aktualisiert */
QDate m_recomRepeatDate;
//! Liste mit Fragen zum Erfüllen der Lernempfehlung
/*! Diese Liste wird mit der Funktion updateRecommendation() aktualisiert */
QList<CQuestion*> m_listQuestionRecommended;
};
#endif
/***************************************************************************
* 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 CHAPTER_H
#define CHAPTER_H
#include "question.h"
//#include "recommendation.h"
//#include "chapterstatistic.h"
#include <qmap.h>
//! Die Klasse CChapter speichert ein Kapitel mit allen Unterkapiteln und Fragen
/*!
*/
class CChapter
{
public:
//! Empfehlung für Kapitel
enum Recommendation
{
RecommendationNone=0, //!< Keine Emfehlung
RecommendationSubChapter=1, //!< Untergeordnetes Kapitel lernen
RecommendationParentChapter=2, //!< Übergeordnetes Kapitel lernen
RecommendationRepeatToday=3, //!< Kapitel heute wiederholen
RecommendationLearnNew=4, //!< Neue Fragen lernen
RecommendationRepeatLater=5, //!< Kapitel später wiederholen
RecommendationMax=6 //!< Für for-Schleifen, etc.
};
//! Standard-Konstruktor
/*! Initialisiert die Klasse, indem die Funktion clear() aufgerufen wird. */
CChapter() { clear(); }
//! Standard-Destruktor
/*! Es werden alle Unterkapitel und Fragen dieses Kapitels aus dem Speicher gelöscht. */
~CChapter() { qDeleteAll(m_listChapter); qDeleteAll(m_listQuestion); }
//! Zurücksetzen aller Werte
/*! Es werden alle Unterkapitel und Fragen dieses Kapitels aus dem Speicher gelöscht und alle andere Daten auf die Default-Werte zurückgesetzt. */
void clear();
//! Elternkapitel auslesen
/*!
\return Elternkapitel m_pParentChapter
\sa 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 dieses Kapitels
\sa parentChapter(), m_pParentChapter
*/
inline void setParentChapter(CChapter *pChapter) { m_pParentChapter = pChapter; }
//! ID dieses Kapitels auslesen
inline QString id() const { return m_strId; }
//! ID dieses Kapitels zusammengesetzt mit allen IDs der Eltern-Kapitel auslesen
QString idWithParents() const;
//! Kapitelbeschreibung auslesen
inline QString text() const { return m_strText; }
//! Kommentar
inline QString comment() const { return m_strComment; }
//! ID setzen
inline void setId (const QString& strId) { m_strId = strId; }
//! Kapitelbeschreibung setzen
inline void setText (const QString& strText) { m_strText = strText; }
//! Kommentar setzen
inline void setComment (const QString& strComment) { m_strComment = strComment; }
//! Anhängen eines Textes an die Kapitelbeschreibung
/*!
\param strText Anzuhängender Text
\sa m_strText
*/
inline void appendText(const QString& strText) { m_strText += strText; }
//! Anzahl der Unterkapitel ermitteln
/*! \return Anzahl der Unterkapitel */
inline int countChapter() const { return m_listChapter.size(); }
inline const CChapter* chapterAt(int i) const { return m_listChapter.at(i); }
inline int indexOfChapter(CChapter* c) const { return m_listChapter.indexOf(c); }
inline void appendChapter(CChapter* c) { m_listChapter.append(c); c->setParentChapter(this); }
// inline void removeChapter(int i) { delete m_listChapter.takeAt(i); }
QList<CChapter*> subChapters() const;
inline void sortAll() { sortSubChapters(true); sortQuestions(); }
void sortSubChapters(bool bSortQuestions);
void sortQuestions();
//! Anzahl der Fragen dieses Kapitels und aller Unterkapitel ermitteln
/*! \return Anzahl der Fragen */
int countSubQuestion() const;
//! Anzahl der Fragen dieses Kapitels (ohne Unterkapitel) ermitteln
/*! \return Anzahl der Fragen */
inline int countQuestion() const { return m_listQuestion.size(); }
inline const CQuestion* questionAt(int i) const { return m_listQuestion.at(i); }
inline CQuestion* questionAt(int i) { return m_listQuestion.at(i); }
inline void appendQuestion(CQuestion* q) { m_listQuestion.append(q); q->setParentChapter(this); }
QList<CQuestion*> questionPool() const;
QList<CQuestion*> questionPoolLevel(const unsigned uLevel) const;
QList<CQuestion*> questionPoolDeepen() const;
QList<CQuestion*> questionPoolRepeat(const QDate d=QDate::currentDate()) const;
bool load (QDomElement elem);
void save (QDomElement& parent, QDomDocument& doc);
bool loadLearnStatistic (QDomElement elem);
bool saveLearnStatistic (QDomElement& parent, QDomDocument& doc);
QString checkForErrors() const;
// Kapitelstatistik auslesen
/*
\return Kapitelstatistik (Variable m_cs)
\sa m_cs
*/
// inline CChapterStatistic statistic() const { return m_cs; }
//! @name Funktionen zur Statistik
//@{
void updateStatistic(); //!< Kapitelstatistik aktualisieren
//! Anzahl der Fragen einer bestimmten Abfragehäufigkeit
inline unsigned countQuestion(const unsigned uLevel) const { return m_uLevelCount[uLevel]; }
double levelAvg() const; //!< Durchschnittlicher Lernfortschritt des Kapitels
unsigned levelAvgRounded() const; //!< Durchschnittlicher, gerundeter Lernfortschritt des Kapitels
QString levelAvgText() const; //!< Durchschnittlicher Lernfortschritt als Text
QIcon levelAvgIcon() const; //!< Icon zum durchschnittlichen Lernfortschritt
QPixmap levelAvgPixmap() const; //!< Pixmap zum durchschnittlichen Lernfortschritt
//! Anzahl der noch nie abgefragen Fragen
inline unsigned countNeverAsked() const { return m_uNeverAskedCount; }
//!< Kapitel inkl. Unterkapitel enthalten Fragen, die gerade gelernt werden
inline bool hasLearningNewQuestions() const { return m_bHasLearningNew; }
inline bool hasKnownQuestions() const { return m_bHasKnownQuestions; }
inline bool hasKnownQuestionsRepeatToday() const { return m_bHasKnownQuestionsRepeatToday; }
CDayStatistic dayStatistic (const QDate& date) const; //<! Statistik eines Tages
CDayStatistic completeStatistic() const; //<! Statistik des kompletten Zeitraums
QDateTime firstAnswerClicked() const; //<! Datum, zu dem zum allerersten Mal eine Frage beantwortet wurde
//@}
//! @name Funktionen zur Lernempfehlung
//@{
QDate repeatDate() const; //!< Wiederhol-Datum des Kapitels
//! Lernempfehlung für das Kapitel
/*! \return Lernempfehlung (Variable m_recom) \sa m_recom */
inline Recommendation recommendation() const { return m_recom; }
QString recommendationIconName(const CCatalog *pCatalog) const; //!< Name des Icons zur Lernempfehlung ermitteln
//! Ermittelt Icon zur Lernempfehlung
inline QIcon recommendationIcon (const CCatalog *pCatalog) const { return QIcon (recommendationIconName(pCatalog)); }
QString recommendationText() const; //!< Lernempfehlungstext (kurz)
QString recommendationTextExtended(const CCatalog *pCatalog) const; //!< Lernempfehlungstext (ausführlich)
QString recommendationToolTip() const; //!< Lernempfehlungstext für Tooltip
bool isRecommendedNow(const CCatalog *pCatalog) const; //!< Kapitel sollte jetzt gelernt werden
//! Anzahl der Unterkapitel mit einer bestimmten Lernempfehlung
inline unsigned recommendationCount(const Recommendation r) const { return m_uRecomCount[r]; }
//! Fragen, die beantwortet müssen, um die Lernempfehlung zu erfüllen
inline QList<CQuestion*> recommendedQuestions() const { return m_listQuestionRecommended; }
//! Kapitel hat Fragen, die beantwortet müssen, um die Lernempfehlung zu erfüllen
inline bool hasRecommendedQuestions() const { return m_listQuestionRecommended.size() > 0; }
//! Anzahl der Fragen, die beantwortet müssen, um die Lernempfehlung zu erfüllen
inline int recommendedQuestionCount() const { return m_listQuestionRecommended.size(); }
//! Alternative Lernempfehlung für das Kapitel
inline Recommendation recommendation2() const { return m_recom2; }
QString recommendationTextExtended2(const CCatalog *pCatalog) const; //!< Alternativer Lernempfehlungstext (ausführlich)
//@}
//! @name Funktionen zu Prüfungen
//@{
// inline void setExam(const QString& strId, const unsigned uQuestionCount) { m_mapExam.insert(strId, uQuestionCount); }
// inline unsigned examQuestionCount(const QString& strId) const { return m_mapExam[strId]; }
//@}
// static
static QString tr (const char *sourceText, const char *comment=0);
static QString recommendationText(const Recommendation r, const QDate dRepeat);
static QString recommendationIconName(const Recommendation r, const CCatalog *pCatalog);
protected:
void updateStatisticCount(); //!< Zählt alle Fragen des Kapitels (inkl. Unterkapitel) für die Statistik
void updateRecommendation(); //!< Lernempfehlung für das Kapitel (inkl. Unterkapitel) aktualisieren
void updateRecommendationStatistic(); //!< Statistik über Lernempfehlungen für das Kapitel (inkl. Unterkapitel) aktualisieren
Recommendation recommendationIndividual() const; //!< Empfehlung nur für dieses Kapitel, Unterkapitel und Elternkapitel werden ignoriert
protected:
CChapter *m_pParentChapter; //!< Übergeordnetes Kapitel
QString m_strId; //!< ID des Kapitels
QString m_strText; //!< Name des Kapitels
QString m_strComment; //!< Kommentar
QList<CChapter*> m_listChapter; //!< Liste mit Unterkapiteln
QList<CQuestion*> m_listQuestion; //!< Liste mit Fragen
// Statistik
unsigned m_uLevelCount[LEVEL_MAX+1]; //!< Anzahl der Fragen einer bestimmten Abfragehäufigkeit
unsigned m_uNeverAskedCount; //!< Anzahl der Fragen, die noch nie abgefragt wurden
unsigned m_uRecomCount[RecommendationMax]; //!< Anzahl der Unterkapitel (inkl. selbst) mit bestimmter Lernempfehlung
bool m_bHasLearningNew; //!< Kapitel enthält Fragen, die gerade neu gelernt werden
bool m_bHasKnownQuestions; //!< Kapitel enthält Fragen, die seit mind. gestern bekannt sind
bool m_bHasKnownQuestionsRepeatToday; //!< Kapitel enthält Fragen, die seit mind. gestern bekannt sind und heute wiederholt werden sollten
Recommendation m_recom; //!< Lernempfehlung
Recommendation m_recom2; //!< Alternative Lernempfehlung
//! Empfohlenes Datum zur Wiederholung der Fragen
/*! Diese Variable wird mit der Funktion updateRecommendation() aktualisiert */
QDate m_recomRepeatDate;
//! Liste mit Fragen zum Erfüllen der Lernempfehlung
/*! Diese Liste wird mit der Funktion updateRecommendation() aktualisiert */
QList<CQuestion*> m_listQuestionRecommended;
};
#endif

View File

@ -1,184 +1,184 @@
/***************************************************************************
* 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 "chaptermodel.h"
#include "catalog.h"
#include <qtextdocument.h>
#define COL_CHAPTER 0
#define COL_QUESTION 1
#define COL_ASSIST 2
#define COL_AVG 3
CChapterModel::CChapterModel(QObject *pParent) : QAbstractItemModel (pParent)
{
m_pCatalog = 0;
}
CChapterModel::~CChapterModel()
{
}
void CChapterModel::onLanguageChanged()
{
headerDataChanged(Qt::Horizontal, 0, columnCount()-1);
}
void CChapterModel::clear()
{
m_listChapter.clear();
m_pCatalog = 0;
reset();
}
void CChapterModel::setModelData (CCatalog *pCatalog, QList<CChapter*> listChapter)
{
m_listChapter = listChapter;
m_pCatalog = pCatalog;
reset();
}
int CChapterModel::columnCount (const QModelIndex & parent) const
{
Q_UNUSED(parent)
return 4;
}
QVariant CChapterModel::data (const QModelIndex & index, int role) const
{
CChapter *p = (CChapter*) index.internalPointer();
if (m_pCatalog == 0 || !index.isValid()) return QVariant();
if (role == Qt::TextAlignmentRole && index.column() == COL_QUESTION) return Qt::AlignRight;
if (p == 0) return QVariant();
if (role == Qt::DisplayRole)
{
if (index.column() == COL_CHAPTER)
{
if (p->id().isEmpty())
return p->text();
else
return p->idWithParents() + " - " + p->text();
}
else if (index.column() == COL_QUESTION)
return QString("%1").arg(p->countSubQuestion());
else if (index.column() == COL_ASSIST)
{
return p->recommendationText();
/* CRecommendation r(p);
return r.textShort();
*/
}
}
else if (role == Qt::DecorationRole)
{
if (index.column() == COL_CHAPTER)
return QIcon(":/icons/16x16/folder.png");
else if (index.column() == COL_AVG)
{
return p->levelAvgIcon();
}
else if (index.column() == COL_ASSIST)
{
return p->recommendationIcon(m_pCatalog);
//TODO return p->recommendation().icon(m_pCatalog);
}
}
else if (role == Qt::ToolTipRole)
{
if (index.column() == COL_AVG)
{
return QString ("%1 - Kennzahl: %2").arg(p->/*statistic().*/levelAvgText()).arg(p->/*statistic().*/levelAvg(), 4, 'f', 2);
}
else if (index.column() == COL_ASSIST)
{
return p->recommendationToolTip();
//TODO return p->recommendation().recommendationText(m_pCatalog);
}
}
return QVariant();
}
bool CChapterModel::hasChildren (const QModelIndex & parent) const
{
if (parent.isValid()) return false;
return (!m_listChapter.isEmpty());
}
QVariant CChapterModel::headerData (int section, Qt::Orientation orientation, int role) const
{
if (orientation == Qt::Vertical) return QVariant();
if (role == Qt::DisplayRole)
{
if (section == COL_CHAPTER)
return tr("Kapitel");
else if (section == COL_QUESTION)
return tr("Fragen");
else if (section == COL_AVG)
return tr("Ø");
else if (section == COL_ASSIST)
return tr("Lernassistent");
}
else if (role == Qt::ToolTipRole)
{
if (section == COL_CHAPTER)
return tr("Kapitelname\nBitte markieren Sie das Kapitel, das Sie lernen möchten.");
else if (section == COL_QUESTION)
return tr("Anzahl d. Fragen inkl. Unterkapitel");
else if (section == COL_AVG)
return tr("Durchschnittlicher Lernfortschritt");
else if (section == COL_ASSIST)
return tr("Empfehlung des Lernassistentes");
}
else if (role == Qt::WhatsThisRole)
{
}
return QVariant();
}
QModelIndex CChapterModel::index (int row, int column, const QModelIndex & parent) const
{
CChapter *p=0;
if (parent.isValid() || row >= m_listChapter.size()) return QModelIndex();
p = m_listChapter.at (row);
return createIndex (row, column, (void*)p);
}
QModelIndex CChapterModel::parent (const QModelIndex & index) const
{
Q_UNUSED(index);
return QModelIndex();
}
int CChapterModel::rowCount (const QModelIndex & parent) const
{
if (parent.isValid()) return 0;
return m_listChapter.size();
}
/***************************************************************************
* 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 "chaptermodel.h"
#include "catalog.h"
#include <qtextdocument.h>
#define COL_CHAPTER 0
#define COL_QUESTION 1
#define COL_ASSIST 2
#define COL_AVG 3
CChapterModel::CChapterModel(QObject *pParent) : QAbstractItemModel (pParent)
{
m_pCatalog = 0;
}
CChapterModel::~CChapterModel()
{
}
void CChapterModel::onLanguageChanged()
{
headerDataChanged(Qt::Horizontal, 0, columnCount()-1);
}
void CChapterModel::clear()
{
m_listChapter.clear();
m_pCatalog = 0;
reset();
}
void CChapterModel::setModelData (CCatalog *pCatalog, QList<CChapter*> listChapter)
{
m_listChapter = listChapter;
m_pCatalog = pCatalog;
reset();
}
int CChapterModel::columnCount (const QModelIndex & parent) const
{
Q_UNUSED(parent)
return 4;
}
QVariant CChapterModel::data (const QModelIndex & index, int role) const
{
CChapter *p = (CChapter*) index.internalPointer();
if (m_pCatalog == 0 || !index.isValid()) return QVariant();
if (role == Qt::TextAlignmentRole && index.column() == COL_QUESTION) return Qt::AlignRight;
if (p == 0) return QVariant();
if (role == Qt::DisplayRole)
{
if (index.column() == COL_CHAPTER)
{
if (p->id().isEmpty())
return p->text();
else
return p->idWithParents() + " - " + p->text();
}
else if (index.column() == COL_QUESTION)
return QString("%1").arg(p->countSubQuestion());
else if (index.column() == COL_ASSIST)
{
return p->recommendationText();
/* CRecommendation r(p);
return r.textShort();
*/
}
}
else if (role == Qt::DecorationRole)
{
if (index.column() == COL_CHAPTER)
return QIcon(":/icons/16x16/folder.png");
else if (index.column() == COL_AVG)
{
return p->levelAvgIcon();
}
else if (index.column() == COL_ASSIST)
{
return p->recommendationIcon(m_pCatalog);
//TODO return p->recommendation().icon(m_pCatalog);
}
}
else if (role == Qt::ToolTipRole)
{
if (index.column() == COL_AVG)
{
return QString ("%1 - Kennzahl: %2").arg(p->/*statistic().*/levelAvgText()).arg(p->/*statistic().*/levelAvg(), 4, 'f', 2);
}
else if (index.column() == COL_ASSIST)
{
return p->recommendationToolTip();
//TODO return p->recommendation().recommendationText(m_pCatalog);
}
}
return QVariant();
}
bool CChapterModel::hasChildren (const QModelIndex & parent) const
{
if (parent.isValid()) return false;
return (!m_listChapter.isEmpty());
}
QVariant CChapterModel::headerData (int section, Qt::Orientation orientation, int role) const
{
if (orientation == Qt::Vertical) return QVariant();
if (role == Qt::DisplayRole)
{
if (section == COL_CHAPTER)
return tr("Kapitel");
else if (section == COL_QUESTION)
return tr("Fragen");
else if (section == COL_AVG)
return tr("Ø");
else if (section == COL_ASSIST)
return tr("Lernassistent");
}
else if (role == Qt::ToolTipRole)
{
if (section == COL_CHAPTER)
return tr("Kapitelname\nBitte markieren Sie das Kapitel, das Sie lernen möchten.");
else if (section == COL_QUESTION)
return tr("Anzahl d. Fragen inkl. Unterkapitel");
else if (section == COL_AVG)
return tr("Durchschnittlicher Lernfortschritt");
else if (section == COL_ASSIST)
return tr("Empfehlung des Lernassistentes");
}
else if (role == Qt::WhatsThisRole)
{
}
return QVariant();
}
QModelIndex CChapterModel::index (int row, int column, const QModelIndex & parent) const
{
CChapter *p=0;
if (parent.isValid() || row >= m_listChapter.size()) return QModelIndex();
p = m_listChapter.at (row);
return createIndex (row, column, (void*)p);
}
QModelIndex CChapterModel::parent (const QModelIndex & index) const
{
Q_UNUSED(index);
return QModelIndex();
}
int CChapterModel::rowCount (const QModelIndex & parent) const
{
if (parent.isValid()) return 0;
return m_listChapter.size();
}

View File

@ -1,60 +1,60 @@
/***************************************************************************
* 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 CHAPTERMODEL_H
#define CHAPTERMODEL_H
#include <qabstractitemmodel.h>
class CChapter;
class CCatalog;
class CChapterModel : public QAbstractItemModel
{
Q_OBJECT
public:
CChapterModel(QObject *pParent=0);
~CChapterModel();
void clear();
void setModelData (CCatalog *pCatalog, QList<CChapter*> listChapter);
public:
virtual int columnCount ( const QModelIndex & parent = QModelIndex() ) const;
virtual QVariant data ( const QModelIndex & index, int role = Qt::DisplayRole ) const;
virtual bool hasChildren (const QModelIndex & parent = QModelIndex()) const;
virtual QVariant headerData ( int section, Qt::Orientation orientation, int role = Qt::DisplayRole ) const;
virtual QModelIndex index (int row, int column, const QModelIndex & parent = QModelIndex()) const;
virtual QModelIndex parent ( const QModelIndex & index ) const;
virtual int rowCount ( const QModelIndex & parent = QModelIndex() ) const;
public slots:
void onLanguageChanged();
protected:
void recalcColumn();
protected:
CCatalog *m_pCatalog;
QList<CChapter*> m_listChapter;
};
#endif // CHAPTERMODEL_H
/***************************************************************************
* 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 CHAPTERMODEL_H
#define CHAPTERMODEL_H
#include <qabstractitemmodel.h>
class CChapter;
class CCatalog;
class CChapterModel : public QAbstractItemModel
{
Q_OBJECT
public:
CChapterModel(QObject *pParent=0);
~CChapterModel();
void clear();
void setModelData (CCatalog *pCatalog, QList<CChapter*> listChapter);
public:
virtual int columnCount ( const QModelIndex & parent = QModelIndex() ) const;
virtual QVariant data ( const QModelIndex & index, int role = Qt::DisplayRole ) const;
virtual bool hasChildren (const QModelIndex & parent = QModelIndex()) const;
virtual QVariant headerData ( int section, Qt::Orientation orientation, int role = Qt::DisplayRole ) const;
virtual QModelIndex index (int row, int column, const QModelIndex & parent = QModelIndex()) const;
virtual QModelIndex parent ( const QModelIndex & index ) const;
virtual int rowCount ( const QModelIndex & parent = QModelIndex() ) const;
public slots:
void onLanguageChanged();
protected:
void recalcColumn();
protected:
CCatalog *m_pCatalog;
QList<CChapter*> m_listChapter;
};
#endif // CHAPTERMODEL_H

View File

@ -1,300 +1,300 @@
/***************************************************************************
* 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 "dlgexam.h"
#include "question.h"
#include "error.h"
#include "catalog.h"
#include <qmessagebox.h>
CDlgExam::CDlgExam (CCatalog *pCatalog, QWidget *pParent) : QDialog (pParent, Qt::WindowMaximizeButtonHint)
{
m_pCatalog = pCatalog;
m_iCurrentQuestion = -1;
m_bIsFinished = false;
m_bTimeout = false;
setupUi(this);
connect (&m_timer, SIGNAL(timeout()), this, SLOT(onTimer()));
}
CDlgExam::~CDlgExam ()
{
}
bool CDlgExam::setup (const CExam& exam)
{
m_exam = exam;
labHeader->setText(exam.name());
try
{
m_listQuestion = exam.createQuestionPool(m_pCatalog->questionPool());
}
catch (CError e)
{
QMessageBox::critical(this, tr("Fehler"), e.toHtml());
return false;
}
m_listAnswerMask.clear();
while (m_listAnswerMask.size() < m_listQuestion.size())
m_listAnswerMask.append(0);
// Antworten bei Bedarf durchmischen
if (m_pCatalog->useMixedAnswers())
{
for (int i=0; i<m_listQuestion.size(); i++)
m_listQuestion.at(i)->mixAnswers();
}
init();
return true;
}
void CDlgExam::init()
{
// Zeitbalken & Zeitüberwachung
m_timer.setInterval(1000);
m_timer.start();
m_dtStart = QDateTime::currentDateTime();
pgTime->setMaximum (m_exam.duration() * 60);
// Sonstiges
pgQuestions->setMaximum (m_listQuestion.size());
m_bIsFinished = false;
m_bTimeout = false;
labMaxWrong->setText(QString("%1").arg(m_exam.maxErrorPoints()));
// Navigation
spinBox->setRange (1, m_listQuestion.size());
spinBox->setValue(1);
m_iCurrentQuestion = 1;
// Alles updaten
updateNavi();
showQuestion();
updateProgressTimer();
updateProgressQuestion();
}
void CDlgExam::onTimer()
{
updateProgressTimer();
}
void CDlgExam::updateNavi()
{
pbFirst->setEnabled (spinBox->value() > spinBox->minimum());
pbPrev->setEnabled (spinBox->value() > spinBox->minimum());
pbNext->setEnabled (spinBox->value() < spinBox->maximum());
pbLast->setEnabled (spinBox->value() < spinBox->maximum());
}
unsigned CDlgExam::answeredQuestionCount()
{
unsigned u=0;
for (int i=0; i<m_listAnswerMask.size(); i++)
{
if (m_listAnswerMask.at(i) != 0) u++;
}
return u;
}
void CDlgExam::updateProgressQuestion()
{
unsigned uAnswered = answeredQuestionCount();
labProgressQuestions->setText(tr("%1 von %2").arg(uAnswered).arg(m_listAnswerMask.size()));
pgQuestions->setValue(uAnswered);
}
void CDlgExam::updateProgressTimer()
{
QDateTime dt = QDateTime::currentDateTime();
unsigned uSecs = m_dtStart.secsTo(dt);
labProgessTime->setText(tr("Abgelaufene Zeit: %1:%2 min von %3:00 min")
.arg(uSecs / 60)
.arg(uSecs % 60, 2, 10, QChar('0'))
.arg(m_exam.duration()));
pgTime->setValue (uSecs);
if (uSecs > m_exam.duration()*60)
{
m_bTimeout = true;
m_timer.stop();
QMessageBox::information(this, tr("Information"), tr("Die Zeit ist abgelaufen.\nDie Prüfung wird deswegen beendet."));
on_pbFinish_clicked();
}
}
void CDlgExam::on_pbFirst_clicked()
{
spinBox->setValue(1);
}
void CDlgExam::on_pbPrev_clicked()
{
int iNew = spinBox->value() - 1;
if (iNew < 1) iNew = 1;
spinBox->setValue(iNew);
}
void CDlgExam::on_pbNext_clicked()
{
int iNew = spinBox->value() + 1;
if (iNew > m_listQuestion.size()) iNew = m_listQuestion.size();
spinBox->setValue(iNew);
}
void CDlgExam::on_pbLast_clicked()
{
spinBox->setValue(m_listQuestion.size());
}
void CDlgExam::on_spinBox_valueChanged(int i)
{
Q_UNUSED(i);
onQuestionChanged();
}
void CDlgExam::saveCurrentAnswer()
{
unsigned uAnswerMask=0;
if (m_iCurrentQuestion >= 0)
{ // Antwort zur aktuellen Frage abspeichern
if (rbA->isChecked()) uAnswerMask |= 1;
if (rbB->isChecked()) uAnswerMask |= 2;
if (rbC->isChecked()) uAnswerMask |= 4;
if (rbD->isChecked()) uAnswerMask |= 8;
m_listAnswerMask[m_iCurrentQuestion] = uAnswerMask;
}
}
void CDlgExam::onQuestionChanged()
{
saveCurrentAnswer();
updateNavi();
updateProgressQuestion();
showQuestion(); // neue Frage anzeigen
}
void CDlgExam::showQuestion()
{
CQuestion *q=0;
unsigned uAnswerMask;
QString str;
m_iCurrentQuestion = spinBox->value()-1;
q = m_listQuestion.at(m_iCurrentQuestion);
uAnswerMask = m_listAnswerMask.at(m_iCurrentQuestion);
str = q->learnText(m_pCatalog, m_bIsFinished, false);
if (m_bIsFinished)
{
str += "<hr><p><b>";
if (!q->isCorrectAnswer(uAnswerMask))
str += "<font color='red'>";
else
str += "<font color='green'>";
str += q->correctionText(uAnswerMask) + "</font></p>";
}
textBrowser->setHtml(str);
rbA->setChecked(uAnswerMask & 1);
rbB->setChecked(uAnswerMask & 2);
rbC->setChecked(uAnswerMask & 4);
rbD->setChecked(uAnswerMask & 8);
rbNoIdea->setChecked(uAnswerMask == 0);
}
void CDlgExam::on_pbFinish_clicked()
{
unsigned uCorrect=0, uWrong=0, uAnsweredCount = answeredQuestionCount(), uErrorPoints=0;
bool bSaveStat=true, bPassed=false;
QDateTime dt = QDateTime::currentDateTime();
unsigned uSecs = m_dtStart.secsTo(dt);
saveCurrentAnswer();
if (uAnsweredCount < (unsigned)m_listQuestion.size() && !m_bTimeout)
{
if (QMessageBox::question (this,
tr("Sicherheitsabfrage"),
tr("Sie haben noch nicht alle Fragen beantwortet.\nWirklich abgeben?"),
QMessageBox::Yes | QMessageBox::No, QMessageBox::No) == QMessageBox::No) return;
}
m_timer.stop();
pbFinish->setEnabled(false);
rbA->setEnabled(false);
rbB->setEnabled(false);
rbC->setEnabled(false);
rbD->setEnabled(false);
rbNoIdea->setEnabled(false);
pbCancel->setText(tr("Beenden"));
m_bIsFinished = true;
showQuestion();
for (int i=0; i<m_listQuestion.size(); i++)
{
CQuestion *q = m_listQuestion.at(i);
unsigned uAnswerMask = m_listAnswerMask.at(i);
if (q->isCorrectAnswer(uAnswerMask))
uCorrect++;
else
{
uWrong++;
uErrorPoints+=q->errorPoints();
}
}
labCorrect->setText(QString("%1").arg(uCorrect));
labWrong->setText(QString("%1").arg(uWrong));
if (uAnsweredCount < (unsigned)m_listQuestion.size()/2)
{
bPassed = false;
bSaveStat = false;
labResult->setText(tr("Ohne Wertung\n(Nicht bestanden)"));
QMessageBox::information(this, tr("Information"), tr("Sie haben weniger als die Hälfte aller Fragen beantwortet.\nDiese Prüfung wird deswegen nicht gewertet."));
}
else if (uErrorPoints > m_exam.maxErrorPoints())
{
bPassed = false;
labResult->setText(tr("<font color='red'>Nicht bestanden</font>"));
QMessageBox::information(this, tr("Ergebnis"), tr("Sie haben die Prüfung leider nicht bestanden."));
}
else
{
bPassed = true;
labResult->setText(tr("<font color='green'>Bestanden</font>"));
QMessageBox::information(this, tr("Ergebnis"), tr("<b>Herzlichen Glückwunsch!</b><p>Sie haben die Prüfung bestanden!"));
}
if (bSaveStat)
{ // Prüfungsstatistik speichern
CExamStat es(m_exam);
es.setSecs(uSecs);
es.setQuestions(m_listQuestion, m_listAnswerMask);
es.setResult(uCorrect, uWrong, uErrorPoints, bPassed);
m_pCatalog->appendExamStat(es);
m_pCatalog->saveStatistic(this);
}
}
/***************************************************************************
* 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 "dlgexam.h"
#include "question.h"
#include "error.h"
#include "catalog.h"
#include <qmessagebox.h>
CDlgExam::CDlgExam (CCatalog *pCatalog, QWidget *pParent) : QDialog (pParent, Qt::WindowMaximizeButtonHint)
{
m_pCatalog = pCatalog;
m_iCurrentQuestion = -1;
m_bIsFinished = false;
m_bTimeout = false;
setupUi(this);
connect (&m_timer, SIGNAL(timeout()), this, SLOT(onTimer()));
}
CDlgExam::~CDlgExam ()
{
}
bool CDlgExam::setup (const CExam& exam)
{
m_exam = exam;
labHeader->setText(exam.name());
try
{
m_listQuestion = exam.createQuestionPool(m_pCatalog->questionPool());
}
catch (CError e)
{
QMessageBox::critical(this, tr("Fehler"), e.toHtml());
return false;
}
m_listAnswerMask.clear();
while (m_listAnswerMask.size() < m_listQuestion.size())
m_listAnswerMask.append(0);
// Antworten bei Bedarf durchmischen
if (m_pCatalog->useMixedAnswers())
{
for (int i=0; i<m_listQuestion.size(); i++)
m_listQuestion.at(i)->mixAnswers();
}
init();
return true;
}
void CDlgExam::init()
{
// Zeitbalken & Zeitüberwachung
m_timer.setInterval(1000);
m_timer.start();
m_dtStart = QDateTime::currentDateTime();
pgTime->setMaximum (m_exam.duration() * 60);
// Sonstiges
pgQuestions->setMaximum (m_listQuestion.size());
m_bIsFinished = false;
m_bTimeout = false;
labMaxWrong->setText(QString("%1").arg(m_exam.maxErrorPoints()));
// Navigation
spinBox->setRange (1, m_listQuestion.size());
spinBox->setValue(1);
m_iCurrentQuestion = 1;
// Alles updaten
updateNavi();
showQuestion();
updateProgressTimer();
updateProgressQuestion();
}
void CDlgExam::onTimer()
{
updateProgressTimer();
}
void CDlgExam::updateNavi()
{
pbFirst->setEnabled (spinBox->value() > spinBox->minimum());
pbPrev->setEnabled (spinBox->value() > spinBox->minimum());
pbNext->setEnabled (spinBox->value() < spinBox->maximum());
pbLast->setEnabled (spinBox->value() < spinBox->maximum());
}
unsigned CDlgExam::answeredQuestionCount()
{
unsigned u=0;
for (int i=0; i<m_listAnswerMask.size(); i++)
{
if (m_listAnswerMask.at(i) != 0) u++;
}
return u;
}
void CDlgExam::updateProgressQuestion()
{
unsigned uAnswered = answeredQuestionCount();
labProgressQuestions->setText(tr("%1 von %2").arg(uAnswered).arg(m_listAnswerMask.size()));
pgQuestions->setValue(uAnswered);
}
void CDlgExam::updateProgressTimer()
{
QDateTime dt = QDateTime::currentDateTime();
unsigned uSecs = m_dtStart.secsTo(dt);
labProgessTime->setText(tr("Abgelaufene Zeit: %1:%2 min von %3:00 min")
.arg(uSecs / 60)
.arg(uSecs % 60, 2, 10, QChar('0'))
.arg(m_exam.duration()));
pgTime->setValue (uSecs);
if (uSecs > m_exam.duration()*60)
{
m_bTimeout = true;
m_timer.stop();
QMessageBox::information(this, tr("Information"), tr("Die Zeit ist abgelaufen.\nDie Prüfung wird deswegen beendet."));
on_pbFinish_clicked();
}
}
void CDlgExam::on_pbFirst_clicked()
{
spinBox->setValue(1);
}
void CDlgExam::on_pbPrev_clicked()
{
int iNew = spinBox->value() - 1;
if (iNew < 1) iNew = 1;
spinBox->setValue(iNew);
}
void CDlgExam::on_pbNext_clicked()
{
int iNew = spinBox->value() + 1;
if (iNew > m_listQuestion.size()) iNew = m_listQuestion.size();
spinBox->setValue(iNew);
}
void CDlgExam::on_pbLast_clicked()
{
spinBox->setValue(m_listQuestion.size());
}
void CDlgExam::on_spinBox_valueChanged(int i)
{
Q_UNUSED(i);
onQuestionChanged();
}
void CDlgExam::saveCurrentAnswer()
{
unsigned uAnswerMask=0;
if (m_iCurrentQuestion >= 0)
{ // Antwort zur aktuellen Frage abspeichern
if (rbA->isChecked()) uAnswerMask |= 1;
if (rbB->isChecked()) uAnswerMask |= 2;
if (rbC->isChecked()) uAnswerMask |= 4;
if (rbD->isChecked()) uAnswerMask |= 8;
m_listAnswerMask[m_iCurrentQuestion] = uAnswerMask;
}
}
void CDlgExam::onQuestionChanged()
{
saveCurrentAnswer();
updateNavi();
updateProgressQuestion();
showQuestion(); // neue Frage anzeigen
}
void CDlgExam::showQuestion()
{
CQuestion *q=0;
unsigned uAnswerMask;
QString str;
m_iCurrentQuestion = spinBox->value()-1;
q = m_listQuestion.at(m_iCurrentQuestion);
uAnswerMask = m_listAnswerMask.at(m_iCurrentQuestion);
str = q->learnText(m_pCatalog, m_bIsFinished, false);
if (m_bIsFinished)
{
str += "<hr><p><b>";
if (!q->isCorrectAnswer(uAnswerMask))
str += "<font color='red'>";
else
str += "<font color='green'>";
str += q->correctionText(uAnswerMask) + "</font></p>";
}
textBrowser->setHtml(str);
rbA->setChecked(uAnswerMask & 1);
rbB->setChecked(uAnswerMask & 2);
rbC->setChecked(uAnswerMask & 4);
rbD->setChecked(uAnswerMask & 8);
rbNoIdea->setChecked(uAnswerMask == 0);
}
void CDlgExam::on_pbFinish_clicked()
{
unsigned uCorrect=0, uWrong=0, uAnsweredCount = answeredQuestionCount(), uErrorPoints=0;
bool bSaveStat=true, bPassed=false;
QDateTime dt = QDateTime::currentDateTime();
unsigned uSecs = m_dtStart.secsTo(dt);
saveCurrentAnswer();
if (uAnsweredCount < (unsigned)m_listQuestion.size() && !m_bTimeout)
{
if (QMessageBox::question (this,
tr("Sicherheitsabfrage"),
tr("Sie haben noch nicht alle Fragen beantwortet.\nWirklich abgeben?"),
QMessageBox::Yes | QMessageBox::No, QMessageBox::No) == QMessageBox::No) return;
}
m_timer.stop();
pbFinish->setEnabled(false);
rbA->setEnabled(false);
rbB->setEnabled(false);
rbC->setEnabled(false);
rbD->setEnabled(false);
rbNoIdea->setEnabled(false);
pbCancel->setText(tr("Beenden"));
m_bIsFinished = true;
showQuestion();
for (int i=0; i<m_listQuestion.size(); i++)
{
CQuestion *q = m_listQuestion.at(i);
unsigned uAnswerMask = m_listAnswerMask.at(i);
if (q->isCorrectAnswer(uAnswerMask))
uCorrect++;
else
{
uWrong++;
uErrorPoints+=q->errorPoints();
}
}
labCorrect->setText(QString("%1").arg(uCorrect));
labWrong->setText(QString("%1").arg(uWrong));
if (uAnsweredCount < (unsigned)m_listQuestion.size()/2)
{
bPassed = false;
bSaveStat = false;
labResult->setText(tr("Ohne Wertung\n(Nicht bestanden)"));
QMessageBox::information(this, tr("Information"), tr("Sie haben weniger als die Hälfte aller Fragen beantwortet.\nDiese Prüfung wird deswegen nicht gewertet."));
}
else if (uErrorPoints > m_exam.maxErrorPoints())
{
bPassed = false;
labResult->setText(tr("<font color='red'>Nicht bestanden</font>"));
QMessageBox::information(this, tr("Ergebnis"), tr("Sie haben die Prüfung leider nicht bestanden."));
}
else
{
bPassed = true;
labResult->setText(tr("<font color='green'>Bestanden</font>"));
QMessageBox::information(this, tr("Ergebnis"), tr("<b>Herzlichen Glückwunsch!</b><p>Sie haben die Prüfung bestanden!"));
}
if (bSaveStat)
{ // Prüfungsstatistik speichern
CExamStat es(m_exam);
es.setSecs(uSecs);
es.setQuestions(m_listQuestion, m_listAnswerMask);
es.setResult(uCorrect, uWrong, uErrorPoints, bPassed);
m_pCatalog->appendExamStat(es);
m_pCatalog->saveStatistic(this);
}
}

162
dlgexam.h
View File

@ -1,81 +1,81 @@
/***************************************************************************
* 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. *
***************************************************************************/
#pragma once
#include "exam.h"
#include "ui_dlgexam.h"
#include <qdialog.h>
#include <qtimer.h>
#include <qdatetime.h>
class CCatalog;
class CQuestion;
class CDlgExam : public QDialog, Ui::DlgExam
{
Q_OBJECT
public:
CDlgExam (CCatalog *pCatalog, QWidget *pParent=0);
~CDlgExam ();
bool setup (const CExam& exam);
protected:
void init();
void updateNavi();
void updateProgressQuestion();
void updateProgressTimer();
void showQuestion();
void onQuestionChanged();
unsigned answeredQuestionCount();
void saveCurrentAnswer();
protected slots:
void onTimer();
void on_pbFirst_clicked();
void on_pbPrev_clicked();
void on_pbNext_clicked();
void on_pbLast_clicked();
void on_spinBox_valueChanged(int i);
void on_pbFinish_clicked();
inline void on_rbA_toggled(bool bChecked) { Q_UNUSED(bChecked); saveCurrentAnswer(); updateProgressQuestion(); }
inline void on_rbB_toggled(bool bChecked) { Q_UNUSED(bChecked); saveCurrentAnswer(); updateProgressQuestion(); }
inline void on_rbC_toggled(bool bChecked) { Q_UNUSED(bChecked); saveCurrentAnswer(); updateProgressQuestion(); }
inline void on_rbD_toggled(bool bChecked) { Q_UNUSED(bChecked); saveCurrentAnswer(); updateProgressQuestion(); }
inline void on_rbNoIdea_toggled(bool bChecked) { Q_UNUSED(bChecked); saveCurrentAnswer(); updateProgressQuestion(); }
protected:
CCatalog *m_pCatalog;
CExam m_exam;
QList<CQuestion*> m_listQuestion;
QList<unsigned> m_listAnswerMask;
QTimer m_timer;
QDateTime m_dtStart;
QDateTime m_dtStop;
int m_iCurrentQuestion;
bool m_bIsFinished;
bool m_bTimeout;
};
/***************************************************************************
* 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. *
***************************************************************************/
#pragma once
#include "exam.h"
#include "ui_dlgexam.h"
#include <qdialog.h>
#include <qtimer.h>
#include <qdatetime.h>
class CCatalog;
class CQuestion;
class CDlgExam : public QDialog, Ui::DlgExam
{
Q_OBJECT
public:
CDlgExam (CCatalog *pCatalog, QWidget *pParent=0);
~CDlgExam ();
bool setup (const CExam& exam);
protected:
void init();
void updateNavi();
void updateProgressQuestion();
void updateProgressTimer();
void showQuestion();
void onQuestionChanged();
unsigned answeredQuestionCount();
void saveCurrentAnswer();
protected slots:
void onTimer();
void on_pbFirst_clicked();
void on_pbPrev_clicked();
void on_pbNext_clicked();
void on_pbLast_clicked();
void on_spinBox_valueChanged(int i);
void on_pbFinish_clicked();
inline void on_rbA_toggled(bool bChecked) { Q_UNUSED(bChecked); saveCurrentAnswer(); updateProgressQuestion(); }
inline void on_rbB_toggled(bool bChecked) { Q_UNUSED(bChecked); saveCurrentAnswer(); updateProgressQuestion(); }
inline void on_rbC_toggled(bool bChecked) { Q_UNUSED(bChecked); saveCurrentAnswer(); updateProgressQuestion(); }
inline void on_rbD_toggled(bool bChecked) { Q_UNUSED(bChecked); saveCurrentAnswer(); updateProgressQuestion(); }
inline void on_rbNoIdea_toggled(bool bChecked) { Q_UNUSED(bChecked); saveCurrentAnswer(); updateProgressQuestion(); }
protected:
CCatalog *m_pCatalog;
CExam m_exam;
QList<CQuestion*> m_listQuestion;
QList<unsigned> m_listAnswerMask;
QTimer m_timer;
QDateTime m_dtStart;
QDateTime m_dtStop;
int m_iCurrentQuestion;
bool m_bIsFinished;
bool m_bTimeout;
};

View File

@ -1,93 +1,93 @@
/***************************************************************************
* 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 "dlgexamselect.h"
#include <qmessagebox.h>
#include <qheaderview.h>
#include "catalog.h"
CDlgExamSelect::CDlgExamSelect (QWidget *pParent) : QDialog (pParent)
{
m_pCatalog = 0;
m_iSelectedExam = -1;
setupUi(this);
twList->headerItem()->setText(0, tr("Name"));
twList->headerItem()->setText(1, tr("Dauer (min)"));
//twList->header()->setStretchLastSection(false);
twList->header()->resizeSection(0, 370);
//twList->header()->resizeSection(1, 70);
}
CDlgExamSelect::~CDlgExamSelect ()
{
}
void CDlgExamSelect::setup (const CCatalog *pCatalog)
{
m_pCatalog = pCatalog;
for (int i=0; i<m_pCatalog->countExam(); i++)
{
CExam exam = m_pCatalog->examAt(i);
QTreeWidgetItem *pItem = new QTreeWidgetItem (twList);
pItem->setText(0, exam.name());
pItem->setText(1, QString("%1 min").arg(exam.duration()));
pItem->setTextAlignment(1, Qt::AlignRight);
pItem->setData(0, Qt::UserRole, i);
}
}
void CDlgExamSelect::on_twList_currentItemChanged (QTreeWidgetItem *current, QTreeWidgetItem *previous)
{
Q_UNUSED(previous);
if (current)
{
m_iSelectedExam = current->data(0, Qt::UserRole).toInt();
CExam exam = m_pCatalog->examAt(m_iSelectedExam);
labName->setText(exam.name());
labComment->setText(exam.comment());
labDuration->setText(QString("%1 min").arg(exam.duration()));
labQuestions->setText(QString("%1").arg(exam.questionCount()));
labError->setText(QString("%1").arg(exam.maxErrorPoints()));
}
else
{
m_iSelectedExam = -1;
labName->clear();
labComment->clear();
labDuration->clear();
labQuestions->clear();
labError->clear();
}
}
void CDlgExamSelect::on_buttonBox_accepted()
{
if (m_iSelectedExam == -1)
{
QMessageBox::information(this, tr("Information"), tr("Bitte eine Prüfung auswählen!"));
return;
}
accept();
}
/***************************************************************************
* 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 "dlgexamselect.h"
#include <qmessagebox.h>
#include <qheaderview.h>
#include "catalog.h"
CDlgExamSelect::CDlgExamSelect (QWidget *pParent) : QDialog (pParent)
{
m_pCatalog = 0;
m_iSelectedExam = -1;
setupUi(this);
twList->headerItem()->setText(0, tr("Name"));
twList->headerItem()->setText(1, tr("Dauer (min)"));
//twList->header()->setStretchLastSection(false);
twList->header()->resizeSection(0, 370);
//twList->header()->resizeSection(1, 70);
}
CDlgExamSelect::~CDlgExamSelect ()
{
}
void CDlgExamSelect::setup (const CCatalog *pCatalog)
{
m_pCatalog = pCatalog;
for (int i=0; i<m_pCatalog->countExam(); i++)
{
CExam exam = m_pCatalog->examAt(i);
QTreeWidgetItem *pItem = new QTreeWidgetItem (twList);
pItem->setText(0, exam.name());
pItem->setText(1, QString("%1 min").arg(exam.duration()));
pItem->setTextAlignment(1, Qt::AlignRight);
pItem->setData(0, Qt::UserRole, i);
}
}
void CDlgExamSelect::on_twList_currentItemChanged (QTreeWidgetItem *current, QTreeWidgetItem *previous)
{
Q_UNUSED(previous);
if (current)
{
m_iSelectedExam = current->data(0, Qt::UserRole).toInt();
CExam exam = m_pCatalog->examAt(m_iSelectedExam);
labName->setText(exam.name());
labComment->setText(exam.comment());
labDuration->setText(QString("%1 min").arg(exam.duration()));
labQuestions->setText(QString("%1").arg(exam.questionCount()));
labError->setText(QString("%1").arg(exam.maxErrorPoints()));
}
else
{
m_iSelectedExam = -1;
labName->clear();
labComment->clear();
labDuration->clear();
labQuestions->clear();
labError->clear();
}
}
void CDlgExamSelect::on_buttonBox_accepted()
{
if (m_iSelectedExam == -1)
{
QMessageBox::information(this, tr("Information"), tr("Bitte eine Prüfung auswählen!"));
return;
}
accept();
}

View File

@ -1,46 +1,46 @@
/***************************************************************************
* 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. *
***************************************************************************/
#pragma once
#include "ui_dlgexamselect.h"
#include <qdialog.h>
class CCatalog;
class CDlgExamSelect : public QDialog, Ui::DlgExamSelect
{
Q_OBJECT
public:
CDlgExamSelect (QWidget *pParent=0);
~CDlgExamSelect ();
void setup (const CCatalog *pCatalog);
inline int selectedExam() const { return m_iSelectedExam; }
protected slots:
void on_buttonBox_accepted();
void on_twList_currentItemChanged (QTreeWidgetItem *current, QTreeWidgetItem *previous);
protected:
const CCatalog *m_pCatalog;
int m_iSelectedExam;
};
/***************************************************************************
* 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. *
***************************************************************************/
#pragma once
#include "ui_dlgexamselect.h"
#include <qdialog.h>
class CCatalog;
class CDlgExamSelect : public QDialog, Ui::DlgExamSelect
{
Q_OBJECT
public:
CDlgExamSelect (QWidget *pParent=0);
~CDlgExamSelect ();
void setup (const CCatalog *pCatalog);
inline int selectedExam() const { return m_iSelectedExam; }
protected slots:
void on_buttonBox_accepted();
void on_twList_currentItemChanged (QTreeWidgetItem *current, QTreeWidgetItem *previous);
protected:
const CCatalog *m_pCatalog;
int m_iSelectedExam;
};

View File

@ -1,109 +1,109 @@
/***************************************************************************
* 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 "dlgexamstatistic.h"
#include "catalog.h"
#include <qmessagebox.h>
#include <qheaderview.h>
CDlgExamStatistic::CDlgExamStatistic(QWidget *pParent) : QDialog(pParent)
{
m_pCatalog = 0;
setupUi(this);
twExamStat->headerItem()->setText(0, "Datum/Uhrzeit");
twExamStat->headerItem()->setText(1, "Ergebnis");
twExamStat->headerItem()->setText(2, "Fehler");
twExamStat->headerItem()->setText(3, "Dauer");
twExamStat->headerItem()->setText(4, "Ø pro Frage");
twExamStat->header()->resizeSection(0, 130);
twExamStat->header()->resizeSection(2, 50);
twExamStat->header()->resizeSection(3, 75);
}
void CDlgExamStatistic::go (CCatalog *pCatalog)
{
m_pCatalog = pCatalog;
if (pCatalog->countExamStat() == 0)
{
QMessageBox::information(parentWidget(), tr("Information"), tr("Es wurden bisher noch keine Prüfungen durchgeführt."));
return;
}
cbExam->clear();
for (int i=0; i<pCatalog->countExam(); i++)
{
cbExam->addItem(pCatalog->examAt(i).name(), pCatalog->examAt(i).id());
}
exec();
}
void CDlgExamStatistic::on_cbExam_currentIndexChanged (int index)
{
QString strExamId = cbExam->itemData(index).toString();
CExam exam = m_pCatalog->examById(strExamId);
unsigned uExamCount=0, uPassedCount=0, uFailedCount=0, uErrorCount=0, uDuration=0, uQuestions=0;
QTreeWidgetItem *pItem=0;
twExamStat->clear();
labExamQCount->setText(QString::number(exam.questionCount()));
labExamTime->setText(QString("%1 min").arg(exam.duration()));
labExamWrong->setText(QString::number(exam.maxErrorPoints()));
for (int i=0; i<m_pCatalog->countExamStat(); i++)
{
CExamStat es = m_pCatalog->examStatAt(i);
if (es.id() != strExamId) continue;
uExamCount++;
if (es.passed()) uPassedCount++; else uFailedCount++;
uErrorCount += es.errorPoints();
uDuration += es.duration();
uQuestions += es.correctAnswers() + es.wrongAnswers();
pItem = new QTreeWidgetItem (twExamStat);
pItem->setText(0, es.datetime().toString(Qt::LocalDate));
pItem->setText(1, es.passed() ? tr("Bestanden") : tr("Nicht bestanden"));
pItem->setText(2, QString::number(es.errorPoints()));
pItem->setTextAlignment(2, Qt::AlignRight);
pItem->setText(3, QString("%1 m %2 s").arg(es.duration() / 60).arg(es.duration() % 60, 2, 10, QChar('0')));
pItem->setTextAlignment(3, Qt::AlignRight);
unsigned uQuestionCount = es.correctAnswers() + es.wrongAnswers();
if (uQuestionCount != 0)
pItem->setText(4, QString("%1 m %2 s").arg(es.duration() / uQuestionCount / 60).arg(es.duration() / uQuestionCount % 60, 2, 10, QChar('0')));
else
pItem->setText(4, "--");
pItem->setTextAlignment(4, Qt::AlignRight);
}
labExamCount->setText(QString::number(uExamCount));
labExamPassed->setText(uExamCount != 0 ? QString::number(uPassedCount) : "--");
labExamFailed->setText(uExamCount != 0 ? QString::number(uFailedCount) : "--");
labExamPassedP->setText(uExamCount != 0 ? QString("%1 %").arg((double)uPassedCount / uExamCount * 100.0, 0, 'f', 1) : "--");
labExamFailedP->setText(uExamCount != 0 ? QString("%1 %").arg((double)uFailedCount / uExamCount * 100.0, 0, 'f', 1) : "--");
labAvgWrong->setText(uExamCount != 0 ? QString::number(uErrorCount / uExamCount) : "--");
labTimeExam->setText(uExamCount != 0 ? QString("%1 m %2 s").arg(uDuration / uExamCount / 60).arg(uDuration / uExamCount % 60, 2, 10, QChar('0')) : "--");
labTimeQuestion->setText(uQuestions != 0 ? QString("%1 m %2 s").arg(uDuration / uQuestions / 60).arg(uDuration / uQuestions % 60, 2, 10, QChar('0')) : "--");
}
/***************************************************************************
* 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 "dlgexamstatistic.h"
#include "catalog.h"
#include <qmessagebox.h>
#include <qheaderview.h>
CDlgExamStatistic::CDlgExamStatistic(QWidget *pParent) : QDialog(pParent)
{
m_pCatalog = 0;
setupUi(this);
twExamStat->headerItem()->setText(0, "Datum/Uhrzeit");
twExamStat->headerItem()->setText(1, "Ergebnis");
twExamStat->headerItem()->setText(2, "Fehler");
twExamStat->headerItem()->setText(3, "Dauer");
twExamStat->headerItem()->setText(4, "Ø pro Frage");
twExamStat->header()->resizeSection(0, 130);
twExamStat->header()->resizeSection(2, 50);
twExamStat->header()->resizeSection(3, 75);
}
void CDlgExamStatistic::go (CCatalog *pCatalog)
{
m_pCatalog = pCatalog;
if (pCatalog->countExamStat() == 0)
{
QMessageBox::information(parentWidget(), tr("Information"), tr("Es wurden bisher noch keine Prüfungen durchgeführt."));
return;
}
cbExam->clear();
for (int i=0; i<pCatalog->countExam(); i++)
{
cbExam->addItem(pCatalog->examAt(i).name(), pCatalog->examAt(i).id());
}
exec();
}
void CDlgExamStatistic::on_cbExam_currentIndexChanged (int index)
{
QString strExamId = cbExam->itemData(index).toString();
CExam exam = m_pCatalog->examById(strExamId);
unsigned uExamCount=0, uPassedCount=0, uFailedCount=0, uErrorCount=0, uDuration=0, uQuestions=0;
QTreeWidgetItem *pItem=0;
twExamStat->clear();
labExamQCount->setText(QString::number(exam.questionCount()));
labExamTime->setText(QString("%1 min").arg(exam.duration()));
labExamWrong->setText(QString::number(exam.maxErrorPoints()));
for (int i=0; i<m_pCatalog->countExamStat(); i++)
{
CExamStat es = m_pCatalog->examStatAt(i);
if (es.id() != strExamId) continue;
uExamCount++;
if (es.passed()) uPassedCount++; else uFailedCount++;
uErrorCount += es.errorPoints();
uDuration += es.duration();
uQuestions += es.correctAnswers() + es.wrongAnswers();
pItem = new QTreeWidgetItem (twExamStat);
pItem->setText(0, es.datetime().toString(Qt::LocalDate));
pItem->setText(1, es.passed() ? tr("Bestanden") : tr("Nicht bestanden"));
pItem->setText(2, QString::number(es.errorPoints()));
pItem->setTextAlignment(2, Qt::AlignRight);
pItem->setText(3, QString("%1 m %2 s").arg(es.duration() / 60).arg(es.duration() % 60, 2, 10, QChar('0')));
pItem->setTextAlignment(3, Qt::AlignRight);
unsigned uQuestionCount = es.correctAnswers() + es.wrongAnswers();
if (uQuestionCount != 0)
pItem->setText(4, QString("%1 m %2 s").arg(es.duration() / uQuestionCount / 60).arg(es.duration() / uQuestionCount % 60, 2, 10, QChar('0')));
else
pItem->setText(4, "--");
pItem->setTextAlignment(4, Qt::AlignRight);
}
labExamCount->setText(QString::number(uExamCount));
labExamPassed->setText(uExamCount != 0 ? QString::number(uPassedCount) : "--");
labExamFailed->setText(uExamCount != 0 ? QString::number(uFailedCount) : "--");
labExamPassedP->setText(uExamCount != 0 ? QString("%1 %").arg((double)uPassedCount / uExamCount * 100.0, 0, 'f', 1) : "--");
labExamFailedP->setText(uExamCount != 0 ? QString("%1 %").arg((double)uFailedCount / uExamCount * 100.0, 0, 'f', 1) : "--");
labAvgWrong->setText(uExamCount != 0 ? QString::number(uErrorCount / uExamCount) : "--");
labTimeExam->setText(uExamCount != 0 ? QString("%1 m %2 s").arg(uDuration / uExamCount / 60).arg(uDuration / uExamCount % 60, 2, 10, QChar('0')) : "--");
labTimeQuestion->setText(uQuestions != 0 ? QString("%1 m %2 s").arg(uDuration / uQuestions / 60).arg(uDuration / uQuestions % 60, 2, 10, QChar('0')) : "--");
}

View File

@ -1,43 +1,43 @@
/***************************************************************************
* 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. *
***************************************************************************/
#pragma once
#include <qdialog.h>
#include "ui_dlgexamstatistic.h"
class CCatalog;
class CDlgExamStatistic : public QDialog, Ui::DlgExamStatistic
{
Q_OBJECT
public:
CDlgExamStatistic(QWidget *pParent=0);
~CDlgExamStatistic() {}
void go (CCatalog *pCatalog);
protected slots:
void on_cbExam_currentIndexChanged (int index);
protected:
CCatalog *m_pCatalog;
};
/***************************************************************************
* 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. *
***************************************************************************/
#pragma once
#include <qdialog.h>
#include "ui_dlgexamstatistic.h"
class CCatalog;
class CDlgExamStatistic : public QDialog, Ui::DlgExamStatistic
{
Q_OBJECT
public:
CDlgExamStatistic(QWidget *pParent=0);
~CDlgExamStatistic() {}
void go (CCatalog *pCatalog);
protected slots:
void on_cbExam_currentIndexChanged (int index);
protected:
CCatalog *m_pCatalog;
};

View File

@ -1,51 +1,51 @@
/***************************************************************************
* 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 "dlginformation.h"
#include <qmessagebox.h>
#include "catalog.h"
CDlgInformation::CDlgInformation (QWidget *pParent) : QDialog(pParent)
{
m_pCatalog=0;
setupUi(this);
}
bool CDlgInformation::setup(CCatalog *pCatalog)
{
labName->setText(pCatalog->name());
labVersion->setText(pCatalog->versionText());
labPublished->setText(pCatalog->published().toString(Qt::LocalDate));
labStatQuestion->setText(QString("%1").arg(pCatalog->countSubQuestion()));
labStatChapter->setText(QString("%1").arg(pCatalog->subChapters().size()));
labValidFrom->setText(pCatalog->validFrom().toString(Qt::LocalDate));
labValidUntil->setText(pCatalog->validUntil().toString(Qt::LocalDate));
labDate->setText(pCatalog->created().toString(Qt::LocalDate));
labComment->setText(pCatalog->comment());
labPublisher->setText(pCatalog->publisher());
labContact->setText(pCatalog->contact());
return true;
}
/***************************************************************************
* 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 "dlginformation.h"
#include <qmessagebox.h>
#include "catalog.h"
CDlgInformation::CDlgInformation (QWidget *pParent) : QDialog(pParent)
{
m_pCatalog=0;
setupUi(this);
}
bool CDlgInformation::setup(CCatalog *pCatalog)
{
labName->setText(pCatalog->name());
labVersion->setText(pCatalog->versionText());
labPublished->setText(pCatalog->published().toString(Qt::LocalDate));
labStatQuestion->setText(QString("%1").arg(pCatalog->countSubQuestion()));
labStatChapter->setText(QString("%1").arg(pCatalog->subChapters().size()));
labValidFrom->setText(pCatalog->validFrom().toString(Qt::LocalDate));
labValidUntil->setText(pCatalog->validUntil().toString(Qt::LocalDate));
labDate->setText(pCatalog->created().toString(Qt::LocalDate));
labComment->setText(pCatalog->comment());
labPublisher->setText(pCatalog->publisher());
labContact->setText(pCatalog->contact());
return true;
}

View File

@ -1,47 +1,47 @@
/***************************************************************************
* 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 DLGINFORMATION_H
#define DLGINFORMATION_H
#include <qdialog.h>
#include "ui_dlginformation.h"
class CCatalog;
class CDlgInformation : public QDialog, Ui::DlgInformation
{
Q_OBJECT
public:
CDlgInformation (QWidget *pParent=0);
~CDlgInformation () {}
bool setup(CCatalog *pCatalog);
protected slots:
protected:
CCatalog *m_pCatalog;
};
#endif
/***************************************************************************
* 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 DLGINFORMATION_H
#define DLGINFORMATION_H
#include <qdialog.h>
#include "ui_dlginformation.h"
class CCatalog;
class CDlgInformation : public QDialog, Ui::DlgInformation
{
Q_OBJECT
public:
CDlgInformation (QWidget *pParent=0);
~CDlgInformation () {}
bool setup(CCatalog *pCatalog);
protected slots:
protected:
CCatalog *m_pCatalog;
};
#endif

View File

@ -1,435 +1,435 @@
/***************************************************************************
* 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ä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<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ü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;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ä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; 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ü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()));
}
/***************************************************************************
* 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ä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<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ü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;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ä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; 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ü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()));
}

View File

@ -1,84 +1,84 @@
/***************************************************************************
* 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 DLGLEARN_H
#define DLGLEARN_H
#include <qdialog.h>
#include <qlist.h>
#include <qdatetime.h>
#include "question.h"
#include "ui_dlglearn.h"
class CChapter;
class CCatalog;
class CDlgLearn : public QDialog, Ui::DlgLearn
{
Q_OBJECT
public:
CDlgLearn (QWidget *pParent=0);
~CDlgLearn();
void go (CCatalog *pCatalog, CChapter *pChapter);
protected:
void setNewChapter(CChapter *pChapter);
void updateStatistic();
void updateLearnAssistant();
void nextQuestion();
CQuestion *findNextQuestion();
CQuestion *findNextPoolQuestion();
CQuestion *findNextTargetQuestion();
void handleAnswer(const int i);
protected slots:
void on_pbAnswerA_clicked();
void on_pbAnswerB_clicked();
void on_pbAnswerC_clicked();
void on_pbAnswerD_clicked();
void on_pbShowHelper_clicked();
void on_pbSkip_clicked();
void on_pbLastQuestion_clicked();
void on_pbQuit_clicked();
void on_pbLearnAssistant_clicked();
void onUpdateDS();
protected:
CCatalog *m_pCatalog;
CChapter *m_pChapter;
QList<CQuestion*> m_listQuestion;
CQuestion *m_pQuestion;
CQuestion *m_pLastQuestion;
unsigned m_uLastAnswerMask;
bool m_bHintsUsed;
QTime m_timeElapsed;
unsigned m_uElapsedBeforeBreak; // if the user makes a break
bool m_bMsgBoxTargetReachedShowed;
CDayStatistic m_ds;
bool m_bAssistantEnable;
bool m_bCheatEnable;
};
#endif
/***************************************************************************
* 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 DLGLEARN_H
#define DLGLEARN_H
#include <qdialog.h>
#include <qlist.h>
#include <qdatetime.h>
#include "question.h"
#include "ui_dlglearn.h"
class CChapter;
class CCatalog;
class CDlgLearn : public QDialog, Ui::DlgLearn
{
Q_OBJECT
public:
CDlgLearn (QWidget *pParent=0);
~CDlgLearn();
void go (CCatalog *pCatalog, CChapter *pChapter);
protected:
void setNewChapter(CChapter *pChapter);
void updateStatistic();
void updateLearnAssistant();
void nextQuestion();
CQuestion *findNextQuestion();
CQuestion *findNextPoolQuestion();
CQuestion *findNextTargetQuestion();
void handleAnswer(const int i);
protected slots:
void on_pbAnswerA_clicked();
void on_pbAnswerB_clicked();
void on_pbAnswerC_clicked();
void on_pbAnswerD_clicked();
void on_pbShowHelper_clicked();
void on_pbSkip_clicked();
void on_pbLastQuestion_clicked();
void on_pbQuit_clicked();
void on_pbLearnAssistant_clicked();
void onUpdateDS();
protected:
CCatalog *m_pCatalog;
CChapter *m_pChapter;
QList<CQuestion*> m_listQuestion;
CQuestion *m_pQuestion;
CQuestion *m_pLastQuestion;
unsigned m_uLastAnswerMask;
bool m_bHintsUsed;
QTime m_timeElapsed;
unsigned m_uElapsedBeforeBreak; // if the user makes a break
bool m_bMsgBoxTargetReachedShowed;
CDayStatistic m_ds;
bool m_bAssistantEnable;
bool m_bCheatEnable;
};
#endif

View File

@ -1,117 +1,117 @@
/***************************************************************************
* 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 "dlglearnassistant.h"
#include <qheaderview.h>
#include <qmessagebox.h>
#include "catalog.h"
CDlgLearnAssistant::CDlgLearnAssistant (QWidget *pParent) : QDialog(pParent)
{
m_pCatalog=0;
setupUi(this);
tvChapters->setModel (&m_modelChapter);
tvChapters->header()->setStretchLastSection(false);
tvChapters->header()->setResizeMode (0, QHeaderView::Stretch);
tvChapters->header()->setResizeMode (1, QHeaderView::Interactive);
tvChapters->header()->setResizeMode (3, QHeaderView::Interactive);
tvChapters->header()->resizeSection(1, 50);
tvChapters->header()->resizeSection(2, 140);
tvChapters->header()->resizeSection(3, 20);
}
bool CDlgLearnAssistant::setup(CCatalog *pCatalog)
{
bool bEnableRepeat;
QList<CChapter*> listAll, listNow, listToday, listSelected;
CChapter *c;
m_pCatalog = pCatalog;
if (pCatalog->recommendationCount (CChapter::RecommendationRepeatToday) > 0)
{
bEnableRepeat = true;
labRepeat->setText(tr("Es sind %1 Fragen vorhanden").arg(pCatalog->recommendedQuestions().count()));
rbRepeat->setChecked(true);
}
else
{
bEnableRepeat = false;
labRepeat->setText(tr("Keine Fragen vorhanden."));
rbList->setChecked(true);
}
rbRepeat->setEnabled(bEnableRepeat);
labRepeat->setEnabled(bEnableRepeat);
// update list
listAll = pCatalog->chapters();
for (int i=0; i<listAll.size(); i++)
{
c = listAll.at(i);
if (c->isRecommendedNow(pCatalog))
listNow << c;
else if (c->recommendation() == CChapter::RecommendationLearnNew)
listToday << c;
}
listSelected << listNow << listToday;
m_modelChapter.setModelData (pCatalog, listSelected);
if (!bEnableRepeat && listSelected.isEmpty()) return false;
updateEnable();
return true;
}
void CDlgLearnAssistant::updateEnable()
{
labRepeat->setEnabled(rbRepeat->isChecked());
tvChapters->setEnabled(rbList->isChecked());
}
void CDlgLearnAssistant::on_buttonBox_accepted()
{
QModelIndexList list = tvChapters->selectionModel()->selectedIndexes();
if (rbList->isChecked() && list.isEmpty())
{
QMessageBox::information(this, tr("Information"), tr("Bitte markieren Sie in der Liste ein Kapitel, das Sie lernen möchten!"));
return;
}
accept();
}
CChapter* CDlgLearnAssistant::selectedChapter()
{
QModelIndexList list = tvChapters->selectionModel()->selectedIndexes();
if (rbRepeat->isChecked())
return m_pCatalog;
if (rbList->isChecked())
{
if (list.isEmpty()) return 0;
return (CChapter*)list.first().internalPointer();
}
return 0;
}
/***************************************************************************
* 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 "dlglearnassistant.h"
#include <qheaderview.h>
#include <qmessagebox.h>
#include "catalog.h"
CDlgLearnAssistant::CDlgLearnAssistant (QWidget *pParent) : QDialog(pParent)
{
m_pCatalog=0;
setupUi(this);
tvChapters->setModel (&m_modelChapter);
tvChapters->header()->setStretchLastSection(false);
tvChapters->header()->setResizeMode (0, QHeaderView::Stretch);
tvChapters->header()->setResizeMode (1, QHeaderView::Interactive);
tvChapters->header()->setResizeMode (3, QHeaderView::Interactive);
tvChapters->header()->resizeSection(1, 50);
tvChapters->header()->resizeSection(2, 140);
tvChapters->header()->resizeSection(3, 20);
}
bool CDlgLearnAssistant::setup(CCatalog *pCatalog)
{
bool bEnableRepeat;
QList<CChapter*> listAll, listNow, listToday, listSelected;
CChapter *c;
m_pCatalog = pCatalog;
if (pCatalog->recommendationCount (CChapter::RecommendationRepeatToday) > 0)
{
bEnableRepeat = true;
labRepeat->setText(tr("Es sind %1 Fragen vorhanden").arg(pCatalog->recommendedQuestions().count()));
rbRepeat->setChecked(true);
}
else
{
bEnableRepeat = false;
labRepeat->setText(tr("Keine Fragen vorhanden."));
rbList->setChecked(true);
}
rbRepeat->setEnabled(bEnableRepeat);
labRepeat->setEnabled(bEnableRepeat);
// update list
listAll = pCatalog->chapters();
for (int i=0; i<listAll.size(); i++)
{
c = listAll.at(i);
if (c->isRecommendedNow(pCatalog))
listNow << c;
else if (c->recommendation() == CChapter::RecommendationLearnNew)
listToday << c;
}
listSelected << listNow << listToday;
m_modelChapter.setModelData (pCatalog, listSelected);
if (!bEnableRepeat && listSelected.isEmpty()) return false;
updateEnable();
return true;
}
void CDlgLearnAssistant::updateEnable()
{
labRepeat->setEnabled(rbRepeat->isChecked());
tvChapters->setEnabled(rbList->isChecked());
}
void CDlgLearnAssistant::on_buttonBox_accepted()
{
QModelIndexList list = tvChapters->selectionModel()->selectedIndexes();
if (rbList->isChecked() && list.isEmpty())
{
QMessageBox::information(this, tr("Information"), tr("Bitte markieren Sie in der Liste ein Kapitel, das Sie lernen möchten!"));
return;
}
accept();
}
CChapter* CDlgLearnAssistant::selectedChapter()
{
QModelIndexList list = tvChapters->selectionModel()->selectedIndexes();
if (rbRepeat->isChecked())
return m_pCatalog;
if (rbList->isChecked())
{
if (list.isEmpty()) return 0;
return (CChapter*)list.first().internalPointer();
}
return 0;
}

View File

@ -1,56 +1,56 @@
/***************************************************************************
* 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 DLGLEARNASSISTANT_H
#define DLGLEARNASSISTANT_H
#include <qdialog.h>
#include "ui_dlglearnassistant.h"
#include "chaptermodel.h"
class CDlgLearnAssistant : public QDialog, Ui::DlgLearnAssistant
{
Q_OBJECT
public:
CDlgLearnAssistant (QWidget *pParent=0);
~CDlgLearnAssistant () {}
bool setup(CCatalog *pCatalog);
CChapter* selectedChapter();
protected slots:
void on_buttonBox_accepted();
inline void on_rbList_toggled() { updateEnable(); }
inline void on_rbRepeat_toggled() { updateEnable(); }
protected:
void updateEnable();
protected:
CCatalog *m_pCatalog;
CChapterModel m_modelChapter;
// CRecommendation m_recomDeepen;
// CRecommendation m_recomRepeat;
};
#endif
/***************************************************************************
* 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 DLGLEARNASSISTANT_H
#define DLGLEARNASSISTANT_H
#include <qdialog.h>
#include "ui_dlglearnassistant.h"
#include "chaptermodel.h"
class CDlgLearnAssistant : public QDialog, Ui::DlgLearnAssistant
{
Q_OBJECT
public:
CDlgLearnAssistant (QWidget *pParent=0);
~CDlgLearnAssistant () {}
bool setup(CCatalog *pCatalog);
CChapter* selectedChapter();
protected slots:
void on_buttonBox_accepted();
inline void on_rbList_toggled() { updateEnable(); }
inline void on_rbRepeat_toggled() { updateEnable(); }
protected:
void updateEnable();
protected:
CCatalog *m_pCatalog;
CChapterModel m_modelChapter;
// CRecommendation m_recomDeepen;
// CRecommendation m_recomRepeat;
};
#endif

View File

@ -1,417 +1,417 @@
/***************************************************************************
* 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 "dlglearnstatistic.h"
#include "chapter.h"
#include "tools.h"
#include "plotwidget.h"
#include <qdatetime.h>
CDlgLearnStatistic::CDlgLearnStatistic(QWidget *pParent) : QDialog(pParent)
{
m_pChapter = 0;
setupUi(this);
cbPeriod->addItem(tr("2 Wochen"), 14);
cbPeriod->addItem(tr("1 Monat"), 30);
cbPeriod->addItem(tr("3 Monate"), 90);
cbPeriod->addItem(tr("6 Monate"), 30*6);
cbPeriod->addItem(tr("1 Jahr"), 365);
cbPeriod->setCurrentIndex(0);
m_pPlotLevel = new CPlotWidget(groupLevel);
m_pPlotLevel->setFrameShape(QFrame::Panel);
m_pPlotLevel->setFrameShadow(QFrame::Sunken);
groupLevel->layout()->addWidget(m_pPlotLevel);
m_pPlotLevel->setBorderDistance(25, 5, 5, 25);
m_pPlotLevel->setLimitY(0.0, 5.5);
m_pPlotLevel->setBorderPen(QPen(Qt::black));
m_pPlotLevel->setBorder(CPlotWidget::BorderLeft | CPlotWidget::BorderBottom);
m_pPlotLevel->setTicY(1.0);
QList<CPlotWidgetTic> listTics;
for (int i=0; i<=LEVEL_MAX; i++)
{
CPlotWidgetTic tic (i, QPixmap(CQuestion::levelIconName(i)));
listTics.append(tic);
}
m_pPlotLevel->setTicListY(listTics);
m_pPlotClicked = new CPlotWidget(groupClicked);
m_pPlotClicked->setFrameShape(QFrame::Panel);
m_pPlotClicked->setFrameShadow(QFrame::Sunken);
groupClicked->layout()->addWidget(m_pPlotClicked);
m_pPlotClicked->setType(CPlotWidget::PlotBarsSum);
m_pPlotClicked->setBarOffset(-0.5);
m_pPlotClicked->setBorderDistance(25, 5, 5, 25);
// Zeitaufwand
cbPeriod2->addItem(tr("2 Wochen"), 14);
cbPeriod2->addItem(tr("1 Monat"), 30);
cbPeriod2->addItem(tr("3 Monate"), 90);
cbPeriod2->addItem(tr("6 Monate"), 30*6);
cbPeriod2->addItem(tr("1 Jahr"), 365);
cbPeriod2->setCurrentIndex(0);
m_pPlotTime = new CPlotWidget(groupTimeExpediture);
m_pPlotTime->setFrameShape(QFrame::Panel);
m_pPlotTime->setFrameShadow(QFrame::Sunken);
groupTimeExpediture->layout()->addWidget(m_pPlotTime);
m_pPlotTime->setType(CPlotWidget::PlotBarsSum);
m_pPlotTime->setBarOffset(-0.5);
m_pPlotTime->setBorderDistance(25, 5, 5, 25);
/*
m_pPlotTimePerQuestion = new CPlotWidget(groupTimeExpediturePerQuestion);
m_pPlotTimePerQuestion->setFrameShape(QFrame::Panel);
m_pPlotTimePerQuestion->setFrameShadow(QFrame::Sunken);
groupTimeExpediturePerQuestion->layout()->addWidget(m_pPlotTimePerQuestion);
m_pPlotTimePerQuestion->setType(CPlotWidget::PlotLines);
m_pPlotTimePerQuestion->setBorderDistance(25, 5, 5, 25);
*/
}
void CDlgLearnStatistic::go(CChapter *pChapter)
{
m_pChapter = pChapter;
updateTable();
updateHistory();
updateTimeExpediture();
exec();
}
void CDlgLearnStatistic::updateTable()
{
const int w=60, h=16;
QList<CQuestion*> listQuestion = m_pChapter->questionPool();
CDayStatistic ds;
// CHAPTER STATISTICS
labChapter->setText (m_pChapter->text());
labChapterCount->setText(QString("%1").arg(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 = listQuestion.size(), dPercent=0.0;
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));
ds = m_pChapter->dayStatistic(QDate());
labClickCount->setText(QString::number(ds.clickedCount()));
labClickCorrect->setText(QString::number(ds.clickedCorrect()));
labClickWrong->setText(QString::number(ds.clickedWrong()));
labClickCorrectP->setText(ds.clickedCount() != 0 ? QString("%1 %").arg(100.0 * ds.clickedCorrect() / ds.clickedCount(), 0, 'f', 1) : "--");
labClickWrongP->setText(ds.clickedCount() != 0 ? QString("%1 %").arg(100.0 * ds.clickedWrong() / ds.clickedCount(), 0, 'f', 1) : "--");
labTimeExpediture->setText(QString("%1 h %2 m %3 s").arg(ds.timeExpediture() / 3600000).arg(ds.timeExpediture() / 60000 % 60, 2, 10, QChar('0')).arg(ds.timeExpediture()/1000 % 60, 2, 10, QChar('0')));
labTimeExpeditureCorrect->setText(QString("%1 h %2 m %3 s").arg(ds.timeExpeditureCorrect() / 3600000).arg(ds.timeExpeditureCorrect() / 60000 % 60, 2, 10, QChar('0')).arg(ds.timeExpeditureCorrect()/1000 % 60, 2, 10, QChar('0')));
labTimeExpeditureWrong->setText(QString("%1 h %2 m %3 s").arg(ds.timeExpeditureWrong() / 3600000).arg(ds.timeExpeditureWrong() / 60000 % 60, 2, 10, QChar('0')).arg(ds.timeExpeditureWrong()/1000 % 60, 2, 10, QChar('0')));
labTimeExpeditureCorrectP->setText(ds.timeExpediture() != 0 ? QString("%1 %").arg(100.0 * ds.timeExpeditureCorrect() / ds.timeExpediture(), 0, 'f', 1) : "--");
labTimeExpeditureWrongP->setText(ds.timeExpediture() != 0 ? QString("%1 %").arg(100.0 * ds.timeExpeditureWrong() / ds.timeExpediture(), 0, 'f', 1) : "--");
labTimePerQuestion->setText(ds.clickedCount() != 0 ? QString("%2 m %3 s").arg(ds.timeExpediture() / ds.clickedCount() / 60000).arg(ds.timeExpediture() / 1000 / ds.clickedCount() % 60, 2, 10, QChar('0')) : "--");
labTimePerQuestionCorrect->setText(ds.clickedCorrect() != 0 ? QString("%2 m %3 s").arg(ds.timeExpeditureCorrect() / ds.clickedCorrect() / 60000).arg(ds.timeExpeditureCorrect() / 1000 / ds.clickedCorrect() % 60, 2, 10, QChar('0')) : "--");
labTimePerQuestionWrong->setText(ds.clickedWrong() != 0 ? QString("%2 m %3 s").arg(ds.timeExpeditureWrong() / ds.clickedWrong() / 60000).arg(ds.timeExpeditureWrong() / 1000 / ds.clickedWrong() % 60, 2, 10, QChar('0')) : "--");
}
void CDlgLearnStatistic::on_cbPeriod_currentIndexChanged(int index)
{
Q_UNUSED(index);
updateHistory();
}
void CDlgLearnStatistic::updateHistory()
{
int iDays = cbPeriod->itemData(cbPeriod->currentIndex()).toInt(), idx=0;
CPlotWidgetCurve curveLevel, curveClickedCorrect, curveClickedWrong;
QDate date = QDate::currentDate();
CDayStatistic ds;
QList<CPlotWidgetTic> listTics;
CPlotWidgetTic tic;
bool bAddTic=false;
unsigned uMaxClicked=0;
if (m_pChapter == 0) return;
setCursor(Qt::WaitCursor);
date = date.addDays(-iDays);
tic.setLineType(CPlotWidgetTic::LineNone);
tic.setFillType(CPlotWidgetTic::FillAll);
tic.setPen(QPen(Qt::darkGray));
while (date <= QDate::currentDate())
{
if (bAddTic)
{
bAddTic=false;
tic.setPos(idx-1);
if (listTics.size() % 2)
tic.setBrush(QBrush(Qt::white));
else
tic.setBrush(QBrush(QColor(232,232,232)));
listTics.append(tic);
}
ds = m_pChapter->dayStatistic(date);
curveLevel.append(CPlotWidgetPoint(idx, ds.level()));
curveClickedCorrect.append(CPlotWidgetPoint((double)idx, ds.clickedCorrect()));
curveClickedWrong.append(CPlotWidgetPoint((double)idx, ds.clickedWrong()));
if (ds.clickedCount() > uMaxClicked) uMaxClicked = ds.clickedCount();
date = date.addDays(1);
// X-Tics
if (iDays <= 14)
{ // daily tics
tic.setText(date.toString("ddd"));
tic.setWidth(1);
if (date.dayOfWeek() == Qt::Monday)
tic.setLineType(CPlotWidgetTic::LinePlot);
else
tic.setLineType(CPlotWidgetTic::LineNone);
bAddTic=true;
}
else if (iDays <= 90 && date.dayOfWeek() == Qt::Monday)
{
tic.setText(QString("KW %1").arg(date.weekNumber()));
tic.setWidth(7);
bAddTic=true;
}
else if (iDays > 90 && date.day() == 1)
{
tic.setText(date.toString("MMM"));
tic.setWidth(date.daysInMonth());
if (date.month() == 1)
tic.setLineType(CPlotWidgetTic::LinePlot);
else
tic.setLineType(CPlotWidgetTic::LineNone);
bAddTic=true;
}
idx++;
}
m_pPlotLevel->setTicListX(listTics);
m_pPlotClicked->setTicListX(listTics);
curveLevel.setPen(QPen(Qt::darkBlue));
curveClickedCorrect.setPen(QPen(Qt::green));
curveClickedCorrect.setBrush(QBrush(Qt::green));
curveClickedWrong.setPen(QPen(Qt::red));
curveClickedWrong.setBrush(QBrush(Qt::red));
m_pPlotLevel->clearCurves();
m_pPlotLevel->appendCurve(curveLevel);
m_pPlotLevel->update();
m_pPlotClicked->clearCurves();
m_pPlotClicked->appendCurve(curveClickedCorrect);
m_pPlotClicked->appendCurve(curveClickedWrong);
m_pPlotClicked->update();
unsigned uDiffBase[] = {1, 2, 5, 10}, uDiffMulti=1, uDiff=0, uDiffCount=0;
idx = 0;
do
{
if (idx == 4) { idx = 0; uDiffMulti*=10; }
uDiff = uDiffBase[idx] * uDiffMulti;
uDiffCount = (uMaxClicked / uDiff) + 1;
idx++;
}
while (uDiffCount > 9);
m_pPlotClicked->setLimitY(0, uDiffCount * uDiff + uDiff/2);
listTics.clear();
tic.clear();
tic.setTextFlags(Qt::AlignRight | Qt::AlignVCenter);
for (unsigned u=0; u<=uDiffCount * uDiff; u+=uDiff)
{
tic.setPos(u);
tic.setText(QString("%1").arg(u));
listTics.append(tic);
}
m_pPlotClicked->setTicListY(listTics);
setCursor(Qt::ArrowCursor);
}
void CDlgLearnStatistic::on_cbPeriod2_currentIndexChanged(int index)
{
Q_UNUSED(index);
updateTimeExpediture();
}
void CDlgLearnStatistic::updateTimeExpediture()
{
int iDays = cbPeriod2->itemData(cbPeriod2->currentIndex()).toInt(), idx=0;
CPlotWidgetCurve curveTimeWrong, curveTimeCorrect,curveTimePQWrong, curveTimePQCorrect; // PQ=per question
QDate date = QDate::currentDate();
CDayStatistic ds;
QList<CPlotWidgetTic> listTics;
CPlotWidgetTic tic;
bool bAddTic=false;
unsigned uMaxTime=0;
if (m_pChapter == 0) return;
setCursor(Qt::WaitCursor);
date = date.addDays(-iDays);
tic.setLineType(CPlotWidgetTic::LineNone);
tic.setFillType(CPlotWidgetTic::FillAll);
tic.setPen(QPen(Qt::darkGray));
while (date <= QDate::currentDate())
{
if (bAddTic)
{
bAddTic=false;
tic.setPos(idx-1);
if (listTics.size() % 2)
tic.setBrush(QBrush(Qt::white));
else
tic.setBrush(QBrush(QColor(232,232,232)));
listTics.append(tic);
}
ds = m_pChapter->dayStatistic(date);
curveTimeWrong.append(CPlotWidgetPoint(idx, (double)ds.timeExpeditureWrong()/1000.0/60.0));
curveTimeCorrect.append(CPlotWidgetPoint(idx, (double)ds.timeExpeditureCorrect()/1000.0/60.0));
/* if (ds.clickedWrong() > 0)
curveTimePQWrong.append(CPlotWidgetPoint(idx, (double)ds.timeExpeditureWrong()/1000.0/60.0/(double)ds.clickedWrong()));
else
curveTimePQWrong.append(CPlotWidgetPoint(idx, 0));
if (ds.clickedCorrect() > 0)
curveTimePQCorrect.append(CPlotWidgetPoint(idx, (double)ds.timeExpeditureCorrect()/1000.0/60.0/(double)ds.clickedCorrect()));
else
curveTimePQWrong.append(CPlotWidgetPoint(idx, 0));*/
if (ds.timeExpediture()/1000/60 > uMaxTime) uMaxTime = ds.timeExpediture()/1000/60;
date = date.addDays(1);
// X-Tics
if (iDays <= 14)
{ // daily tics
tic.setText(date.toString("ddd"));
tic.setWidth(1);
if (date.dayOfWeek() == Qt::Monday)
tic.setLineType(CPlotWidgetTic::LinePlot);
else
tic.setLineType(CPlotWidgetTic::LineNone);
bAddTic=true;
}
else if (iDays <= 90 && date.dayOfWeek() == Qt::Monday)
{
tic.setText(QString("KW %1").arg(date.weekNumber()));
tic.setWidth(7);
bAddTic=true;
}
else if (iDays > 90 && date.day() == 1)
{
tic.setText(date.toString("MMM"));
tic.setWidth(date.daysInMonth());
if (date.month() == 1)
tic.setLineType(CPlotWidgetTic::LinePlot);
else
tic.setLineType(CPlotWidgetTic::LineNone);
bAddTic=true;
}
idx++;
}
m_pPlotTime->setTicListX(listTics);
//m_pPlotTimePerQuestion->setTicListX(listTics);
curveTimeCorrect.setPen(QPen(Qt::green));
curveTimeCorrect.setBrush(QBrush(Qt::green));
curveTimeWrong.setPen(QPen(Qt::red));
curveTimeWrong.setBrush(QBrush(Qt::red));
m_pPlotTime->clearCurves();
m_pPlotTime->appendCurve(curveTimeCorrect);
m_pPlotTime->appendCurve(curveTimeWrong);
m_pPlotTime->update();
/*
m_pPlotTimePerQuestion->clearCurves();
m_pPlotTimePerQuestion->appendCurve(curveTimePQCorrect);
m_pPlotTimePerQuestion->appendCurve(curveTimePQWrong);
m_pPlotTimePerQuestion->setAutoLimitRoundY(0.1);
m_pPlotTimePerQuestion->update();
*/
unsigned uDiffBase[] = {1, 2, 5, 10}, uDiffMulti=1, uDiff=0, uDiffCount=0;
idx = 0;
do
{
if (idx == 4) { idx = 0; uDiffMulti*=10; }
uDiff = uDiffBase[idx] * uDiffMulti;
uDiffCount = (uMaxTime / uDiff) + 1;
idx++;
}
while (uDiffCount > 9);
m_pPlotTime->setLimitY(0, uDiffCount * uDiff + uDiff/2);
listTics.clear();
tic.clear();
tic.setTextFlags(Qt::AlignRight | Qt::AlignVCenter);
for (unsigned u=0; u<=uDiffCount * uDiff; u+=uDiff)
{
tic.setPos(u);
tic.setText(QString("%1").arg(u));
listTics.append(tic);
}
m_pPlotTime->setTicListY(listTics);
setCursor(Qt::ArrowCursor);
}
/***************************************************************************
* 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 "dlglearnstatistic.h"
#include "chapter.h"
#include "tools.h"
#include "plotwidget.h"
#include <qdatetime.h>
CDlgLearnStatistic::CDlgLearnStatistic(QWidget *pParent) : QDialog(pParent)
{
m_pChapter = 0;
setupUi(this);
cbPeriod->addItem(tr("2 Wochen"), 14);
cbPeriod->addItem(tr("1 Monat"), 30);
cbPeriod->addItem(tr("3 Monate"), 90);
cbPeriod->addItem(tr("6 Monate"), 30*6);
cbPeriod->addItem(tr("1 Jahr"), 365);
cbPeriod->setCurrentIndex(0);
m_pPlotLevel = new CPlotWidget(groupLevel);
m_pPlotLevel->setFrameShape(QFrame::Panel);
m_pPlotLevel->setFrameShadow(QFrame::Sunken);
groupLevel->layout()->addWidget(m_pPlotLevel);
m_pPlotLevel->setBorderDistance(25, 5, 5, 25);
m_pPlotLevel->setLimitY(0.0, 5.5);
m_pPlotLevel->setBorderPen(QPen(Qt::black));
m_pPlotLevel->setBorder(CPlotWidget::BorderLeft | CPlotWidget::BorderBottom);
m_pPlotLevel->setTicY(1.0);
QList<CPlotWidgetTic> listTics;
for (int i=0; i<=LEVEL_MAX; i++)
{
CPlotWidgetTic tic (i, QPixmap(CQuestion::levelIconName(i)));
listTics.append(tic);
}
m_pPlotLevel->setTicListY(listTics);
m_pPlotClicked = new CPlotWidget(groupClicked);
m_pPlotClicked->setFrameShape(QFrame::Panel);
m_pPlotClicked->setFrameShadow(QFrame::Sunken);
groupClicked->layout()->addWidget(m_pPlotClicked);
m_pPlotClicked->setType(CPlotWidget::PlotBarsSum);
m_pPlotClicked->setBarOffset(-0.5);
m_pPlotClicked->setBorderDistance(25, 5, 5, 25);
// Zeitaufwand
cbPeriod2->addItem(tr("2 Wochen"), 14);
cbPeriod2->addItem(tr("1 Monat"), 30);
cbPeriod2->addItem(tr("3 Monate"), 90);
cbPeriod2->addItem(tr("6 Monate"), 30*6);
cbPeriod2->addItem(tr("1 Jahr"), 365);
cbPeriod2->setCurrentIndex(0);
m_pPlotTime = new CPlotWidget(groupTimeExpediture);
m_pPlotTime->setFrameShape(QFrame::Panel);
m_pPlotTime->setFrameShadow(QFrame::Sunken);
groupTimeExpediture->layout()->addWidget(m_pPlotTime);
m_pPlotTime->setType(CPlotWidget::PlotBarsSum);
m_pPlotTime->setBarOffset(-0.5);
m_pPlotTime->setBorderDistance(25, 5, 5, 25);
/*
m_pPlotTimePerQuestion = new CPlotWidget(groupTimeExpediturePerQuestion);
m_pPlotTimePerQuestion->setFrameShape(QFrame::Panel);
m_pPlotTimePerQuestion->setFrameShadow(QFrame::Sunken);
groupTimeExpediturePerQuestion->layout()->addWidget(m_pPlotTimePerQuestion);
m_pPlotTimePerQuestion->setType(CPlotWidget::PlotLines);
m_pPlotTimePerQuestion->setBorderDistance(25, 5, 5, 25);
*/
}
void CDlgLearnStatistic::go(CChapter *pChapter)
{
m_pChapter = pChapter;
updateTable();
updateHistory();
updateTimeExpediture();
exec();
}
void CDlgLearnStatistic::updateTable()
{
const int w=60, h=16;
QList<CQuestion*> listQuestion = m_pChapter->questionPool();
CDayStatistic ds;
// CHAPTER STATISTICS
labChapter->setText (m_pChapter->text());
labChapterCount->setText(QString("%1").arg(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 = listQuestion.size(), dPercent=0.0;
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));
ds = m_pChapter->dayStatistic(QDate());
labClickCount->setText(QString::number(ds.clickedCount()));
labClickCorrect->setText(QString::number(ds.clickedCorrect()));
labClickWrong->setText(QString::number(ds.clickedWrong()));
labClickCorrectP->setText(ds.clickedCount() != 0 ? QString("%1 %").arg(100.0 * ds.clickedCorrect() / ds.clickedCount(), 0, 'f', 1) : "--");
labClickWrongP->setText(ds.clickedCount() != 0 ? QString("%1 %").arg(100.0 * ds.clickedWrong() / ds.clickedCount(), 0, 'f', 1) : "--");
labTimeExpediture->setText(QString("%1 h %2 m %3 s").arg(ds.timeExpediture() / 3600000).arg(ds.timeExpediture() / 60000 % 60, 2, 10, QChar('0')).arg(ds.timeExpediture()/1000 % 60, 2, 10, QChar('0')));
labTimeExpeditureCorrect->setText(QString("%1 h %2 m %3 s").arg(ds.timeExpeditureCorrect() / 3600000).arg(ds.timeExpeditureCorrect() / 60000 % 60, 2, 10, QChar('0')).arg(ds.timeExpeditureCorrect()/1000 % 60, 2, 10, QChar('0')));
labTimeExpeditureWrong->setText(QString("%1 h %2 m %3 s").arg(ds.timeExpeditureWrong() / 3600000).arg(ds.timeExpeditureWrong() / 60000 % 60, 2, 10, QChar('0')).arg(ds.timeExpeditureWrong()/1000 % 60, 2, 10, QChar('0')));
labTimeExpeditureCorrectP->setText(ds.timeExpediture() != 0 ? QString("%1 %").arg(100.0 * ds.timeExpeditureCorrect() / ds.timeExpediture(), 0, 'f', 1) : "--");
labTimeExpeditureWrongP->setText(ds.timeExpediture() != 0 ? QString("%1 %").arg(100.0 * ds.timeExpeditureWrong() / ds.timeExpediture(), 0, 'f', 1) : "--");
labTimePerQuestion->setText(ds.clickedCount() != 0 ? QString("%2 m %3 s").arg(ds.timeExpediture() / ds.clickedCount() / 60000).arg(ds.timeExpediture() / 1000 / ds.clickedCount() % 60, 2, 10, QChar('0')) : "--");
labTimePerQuestionCorrect->setText(ds.clickedCorrect() != 0 ? QString("%2 m %3 s").arg(ds.timeExpeditureCorrect() / ds.clickedCorrect() / 60000).arg(ds.timeExpeditureCorrect() / 1000 / ds.clickedCorrect() % 60, 2, 10, QChar('0')) : "--");
labTimePerQuestionWrong->setText(ds.clickedWrong() != 0 ? QString("%2 m %3 s").arg(ds.timeExpeditureWrong() / ds.clickedWrong() / 60000).arg(ds.timeExpeditureWrong() / 1000 / ds.clickedWrong() % 60, 2, 10, QChar('0')) : "--");
}
void CDlgLearnStatistic::on_cbPeriod_currentIndexChanged(int index)
{
Q_UNUSED(index);
updateHistory();
}
void CDlgLearnStatistic::updateHistory()
{
int iDays = cbPeriod->itemData(cbPeriod->currentIndex()).toInt(), idx=0;
CPlotWidgetCurve curveLevel, curveClickedCorrect, curveClickedWrong;
QDate date = QDate::currentDate();
CDayStatistic ds;
QList<CPlotWidgetTic> listTics;
CPlotWidgetTic tic;
bool bAddTic=false;
unsigned uMaxClicked=0;
if (m_pChapter == 0) return;
setCursor(Qt::WaitCursor);
date = date.addDays(-iDays);
tic.setLineType(CPlotWidgetTic::LineNone);
tic.setFillType(CPlotWidgetTic::FillAll);
tic.setPen(QPen(Qt::darkGray));
while (date <= QDate::currentDate())
{
if (bAddTic)
{
bAddTic=false;
tic.setPos(idx-1);
if (listTics.size() % 2)
tic.setBrush(QBrush(Qt::white));
else
tic.setBrush(QBrush(QColor(232,232,232)));
listTics.append(tic);
}
ds = m_pChapter->dayStatistic(date);
curveLevel.append(CPlotWidgetPoint(idx, ds.level()));
curveClickedCorrect.append(CPlotWidgetPoint((double)idx, ds.clickedCorrect()));
curveClickedWrong.append(CPlotWidgetPoint((double)idx, ds.clickedWrong()));
if (ds.clickedCount() > uMaxClicked) uMaxClicked = ds.clickedCount();
date = date.addDays(1);
// X-Tics
if (iDays <= 14)
{ // daily tics
tic.setText(date.toString("ddd"));
tic.setWidth(1);
if (date.dayOfWeek() == Qt::Monday)
tic.setLineType(CPlotWidgetTic::LinePlot);
else
tic.setLineType(CPlotWidgetTic::LineNone);
bAddTic=true;
}
else if (iDays <= 90 && date.dayOfWeek() == Qt::Monday)
{
tic.setText(QString("KW %1").arg(date.weekNumber()));
tic.setWidth(7);
bAddTic=true;
}
else if (iDays > 90 && date.day() == 1)
{
tic.setText(date.toString("MMM"));
tic.setWidth(date.daysInMonth());
if (date.month() == 1)
tic.setLineType(CPlotWidgetTic::LinePlot);
else
tic.setLineType(CPlotWidgetTic::LineNone);
bAddTic=true;
}
idx++;
}
m_pPlotLevel->setTicListX(listTics);
m_pPlotClicked->setTicListX(listTics);
curveLevel.setPen(QPen(Qt::darkBlue));
curveClickedCorrect.setPen(QPen(Qt::green));
curveClickedCorrect.setBrush(QBrush(Qt::green));
curveClickedWrong.setPen(QPen(Qt::red));
curveClickedWrong.setBrush(QBrush(Qt::red));
m_pPlotLevel->clearCurves();
m_pPlotLevel->appendCurve(curveLevel);
m_pPlotLevel->update();
m_pPlotClicked->clearCurves();
m_pPlotClicked->appendCurve(curveClickedCorrect);
m_pPlotClicked->appendCurve(curveClickedWrong);
m_pPlotClicked->update();
unsigned uDiffBase[] = {1, 2, 5, 10}, uDiffMulti=1, uDiff=0, uDiffCount=0;
idx = 0;
do
{
if (idx == 4) { idx = 0; uDiffMulti*=10; }
uDiff = uDiffBase[idx] * uDiffMulti;
uDiffCount = (uMaxClicked / uDiff) + 1;
idx++;
}
while (uDiffCount > 9);
m_pPlotClicked->setLimitY(0, uDiffCount * uDiff + uDiff/2);
listTics.clear();
tic.clear();
tic.setTextFlags(Qt::AlignRight | Qt::AlignVCenter);
for (unsigned u=0; u<=uDiffCount * uDiff; u+=uDiff)
{
tic.setPos(u);
tic.setText(QString("%1").arg(u));
listTics.append(tic);
}
m_pPlotClicked->setTicListY(listTics);
setCursor(Qt::ArrowCursor);
}
void CDlgLearnStatistic::on_cbPeriod2_currentIndexChanged(int index)
{
Q_UNUSED(index);
updateTimeExpediture();
}
void CDlgLearnStatistic::updateTimeExpediture()
{
int iDays = cbPeriod2->itemData(cbPeriod2->currentIndex()).toInt(), idx=0;
CPlotWidgetCurve curveTimeWrong, curveTimeCorrect,curveTimePQWrong, curveTimePQCorrect; // PQ=per question
QDate date = QDate::currentDate();
CDayStatistic ds;
QList<CPlotWidgetTic> listTics;
CPlotWidgetTic tic;
bool bAddTic=false;
unsigned uMaxTime=0;
if (m_pChapter == 0) return;
setCursor(Qt::WaitCursor);
date = date.addDays(-iDays);
tic.setLineType(CPlotWidgetTic::LineNone);
tic.setFillType(CPlotWidgetTic::FillAll);
tic.setPen(QPen(Qt::darkGray));
while (date <= QDate::currentDate())
{
if (bAddTic)
{
bAddTic=false;
tic.setPos(idx-1);
if (listTics.size() % 2)
tic.setBrush(QBrush(Qt::white));
else
tic.setBrush(QBrush(QColor(232,232,232)));
listTics.append(tic);
}
ds = m_pChapter->dayStatistic(date);
curveTimeWrong.append(CPlotWidgetPoint(idx, (double)ds.timeExpeditureWrong()/1000.0/60.0));
curveTimeCorrect.append(CPlotWidgetPoint(idx, (double)ds.timeExpeditureCorrect()/1000.0/60.0));
/* if (ds.clickedWrong() > 0)
curveTimePQWrong.append(CPlotWidgetPoint(idx, (double)ds.timeExpeditureWrong()/1000.0/60.0/(double)ds.clickedWrong()));
else
curveTimePQWrong.append(CPlotWidgetPoint(idx, 0));
if (ds.clickedCorrect() > 0)
curveTimePQCorrect.append(CPlotWidgetPoint(idx, (double)ds.timeExpeditureCorrect()/1000.0/60.0/(double)ds.clickedCorrect()));
else
curveTimePQWrong.append(CPlotWidgetPoint(idx, 0));*/
if (ds.timeExpediture()/1000/60 > uMaxTime) uMaxTime = ds.timeExpediture()/1000/60;
date = date.addDays(1);
// X-Tics
if (iDays <= 14)
{ // daily tics
tic.setText(date.toString("ddd"));
tic.setWidth(1);
if (date.dayOfWeek() == Qt::Monday)
tic.setLineType(CPlotWidgetTic::LinePlot);
else
tic.setLineType(CPlotWidgetTic::LineNone);
bAddTic=true;
}
else if (iDays <= 90 && date.dayOfWeek() == Qt::Monday)
{
tic.setText(QString("KW %1").arg(date.weekNumber()));
tic.setWidth(7);
bAddTic=true;
}
else if (iDays > 90 && date.day() == 1)
{
tic.setText(date.toString("MMM"));
tic.setWidth(date.daysInMonth());
if (date.month() == 1)
tic.setLineType(CPlotWidgetTic::LinePlot);
else
tic.setLineType(CPlotWidgetTic::LineNone);
bAddTic=true;
}
idx++;
}
m_pPlotTime->setTicListX(listTics);
//m_pPlotTimePerQuestion->setTicListX(listTics);
curveTimeCorrect.setPen(QPen(Qt::green));
curveTimeCorrect.setBrush(QBrush(Qt::green));
curveTimeWrong.setPen(QPen(Qt::red));
curveTimeWrong.setBrush(QBrush(Qt::red));
m_pPlotTime->clearCurves();
m_pPlotTime->appendCurve(curveTimeCorrect);
m_pPlotTime->appendCurve(curveTimeWrong);
m_pPlotTime->update();
/*
m_pPlotTimePerQuestion->clearCurves();
m_pPlotTimePerQuestion->appendCurve(curveTimePQCorrect);
m_pPlotTimePerQuestion->appendCurve(curveTimePQWrong);
m_pPlotTimePerQuestion->setAutoLimitRoundY(0.1);
m_pPlotTimePerQuestion->update();
*/
unsigned uDiffBase[] = {1, 2, 5, 10}, uDiffMulti=1, uDiff=0, uDiffCount=0;
idx = 0;
do
{
if (idx == 4) { idx = 0; uDiffMulti*=10; }
uDiff = uDiffBase[idx] * uDiffMulti;
uDiffCount = (uMaxTime / uDiff) + 1;
idx++;
}
while (uDiffCount > 9);
m_pPlotTime->setLimitY(0, uDiffCount * uDiff + uDiff/2);
listTics.clear();
tic.clear();
tic.setTextFlags(Qt::AlignRight | Qt::AlignVCenter);
for (unsigned u=0; u<=uDiffCount * uDiff; u+=uDiff)
{
tic.setPos(u);
tic.setText(QString("%1").arg(u));
listTics.append(tic);
}
m_pPlotTime->setTicListY(listTics);
setCursor(Qt::ArrowCursor);
}

View File

@ -1,54 +1,54 @@
/***************************************************************************
* 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. *
***************************************************************************/
#pragma once
#include <qdialog.h>
#include "ui_dlglearnstatistic.h"
class CChapter;
class CPlotWidget;
class CDlgLearnStatistic : public QDialog, Ui::DlgLearnStatistic
{
Q_OBJECT
public:
CDlgLearnStatistic(QWidget *pParent=0);
~CDlgLearnStatistic() {}
void go(CChapter *pChapter);
protected slots:
void on_cbPeriod_currentIndexChanged(int index);
void on_cbPeriod2_currentIndexChanged(int index);
protected:
void updateTable();
void updateHistory();
void updateTimeExpediture();
protected:
CChapter *m_pChapter;
CPlotWidget *m_pPlotLevel;
CPlotWidget *m_pPlotClicked;
CPlotWidget *m_pPlotTime;
// CPlotWidget *m_pPlotTimePerQuestion;
};
/***************************************************************************
* 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. *
***************************************************************************/
#pragma once
#include <qdialog.h>
#include "ui_dlglearnstatistic.h"
class CChapter;
class CPlotWidget;
class CDlgLearnStatistic : public QDialog, Ui::DlgLearnStatistic
{
Q_OBJECT
public:
CDlgLearnStatistic(QWidget *pParent=0);
~CDlgLearnStatistic() {}
void go(CChapter *pChapter);
protected slots:
void on_cbPeriod_currentIndexChanged(int index);
void on_cbPeriod2_currentIndexChanged(int index);
protected:
void updateTable();
void updateHistory();
void updateTimeExpediture();
protected:
CChapter *m_pChapter;
CPlotWidget *m_pPlotLevel;
CPlotWidget *m_pPlotClicked;
CPlotWidget *m_pPlotTime;
// CPlotWidget *m_pPlotTimePerQuestion;
};

View File

@ -1,43 +1,43 @@
/***************************************************************************
* 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 "dlgviewquestion.h"
#include "catalog.h"
void CDlgViewQuestion::go (CCatalog *pCatalog, CQuestion *pQuestion, const unsigned uAnswer)
{
QString str;
Q_ASSERT (pCatalog != 0);
if (!pQuestion) return;
str = pQuestion->learnText(pCatalog, true, true);
str += "<p><b>";
if (uAnswer != 0 && pQuestion->isCorrectAnswer(uAnswer))
str += "<font color='green'>";
else if (uAnswer != 0)
str += "<font color='red'>";
str += pQuestion->correctionText(uAnswer);
str += "</font></b></p>";
textBrowser->setHtml(str);
setWindowTitle (tr("Frage") + " " + pQuestion->id());
exec();
}
/***************************************************************************
* 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 "dlgviewquestion.h"
#include "catalog.h"
void CDlgViewQuestion::go (CCatalog *pCatalog, CQuestion *pQuestion, const unsigned uAnswer)
{
QString str;
Q_ASSERT (pCatalog != 0);
if (!pQuestion) return;
str = pQuestion->learnText(pCatalog, true, true);
str += "<p><b>";
if (uAnswer != 0 && pQuestion->isCorrectAnswer(uAnswer))
str += "<font color='green'>";
else if (uAnswer != 0)
str += "<font color='red'>";
str += pQuestion->correctionText(uAnswer);
str += "</font></b></p>";
textBrowser->setHtml(str);
setWindowTitle (tr("Frage") + " " + pQuestion->id());
exec();
}

View File

@ -1,44 +1,44 @@
/***************************************************************************
* 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 DLGVIEWQUESTION_H
#define DLGVIEWQUESTION_H
#include <qdialog.h>
#include "ui_dlgviewquestion.h"
class CQuestion;
class CCatalog;
class CDlgViewQuestion : public QDialog, Ui::DlgViewQuestion
{
Q_OBJECT
public:
CDlgViewQuestion(QWidget *pParent) : QDialog(pParent) { setupUi(this); }
~CDlgViewQuestion() { }
void go (CCatalog *pCatalog, CQuestion *pQuestion, const unsigned uAnswer=0);
protected:
};
#endif // DLGVIEWQUESTION_H
/***************************************************************************
* 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 DLGVIEWQUESTION_H
#define DLGVIEWQUESTION_H
#include <qdialog.h>
#include "ui_dlgviewquestion.h"
class CQuestion;
class CCatalog;
class CDlgViewQuestion : public QDialog, Ui::DlgViewQuestion
{
Q_OBJECT
public:
CDlgViewQuestion(QWidget *pParent) : QDialog(pParent) { setupUi(this); }
~CDlgViewQuestion() { }
void go (CCatalog *pCatalog, CQuestion *pQuestion, const unsigned uAnswer=0);
protected:
};
#endif // DLGVIEWQUESTION_H

196
error.cpp
View File

@ -1,98 +1,98 @@
/***************************************************************************
* Copyright (C) 1999-2005 by Oliver Saal *
* http://www.oliver-saal.de/ *
* osaal@gmx.de *
* *
* 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 "error.h"
#include <qobject.h>
#include <qstring.h>
#ifdef ERROR_USE_SQL
#include <qsqlerror.h>
#include <qmap.h>
//#include <qmapiterator.h>
#include <qvariant.h>
#endif
CError::CError ()
{
m_uLine = 0;
}
CError::CError (const QString& strFunc, const QString& strFile, const unsigned int uLine)
{
m_strFunction = strFunc;
m_strFile = strFile;
m_uLine = uLine;
}
CError::CError (const QString& strText, const QString& strFunc, const QString& strFile, const unsigned int uLine)
{
m_strText = strText;
m_strFunction = strFunc;
m_strFile = strFile;
m_uLine = uLine;
}
#ifdef ERROR_USE_SQL
CError::CError (const QString& strText, const QSqlDatabase* pDB, const QString& strFunc, const QString& strFile, const unsigned int uLine)
{
m_strText = QString ("%1\n%3").arg (strText, pDB->lastError().text());
m_strFunction = strFunc;
m_strFile = strFile;
m_uLine = uLine;
}
CError::CError (const QString& strText, const QSqlQuery& query, const QString& strFunc, const QString& strFile, const unsigned int uLine)
{
QMap<QString, QVariant> map;
m_strText = QString ("%1\nSQL: %2\n").arg (strText, query.lastQuery());
map = query.boundValues();
if (!map.isEmpty())
{
m_strText+="Bound values:\n";
QMap<QString, QVariant>::const_iterator i = map.constBegin();
while (i != map.constEnd())
{
m_strText += QString ("%1 / %2 ==> %4\n").arg (i.key(), i.value().typeName(), i.value().isNull() ? "NULL" : i.value().toString());
++i;
}
}
m_strText += query.lastError().text();
m_strFunction = strFunc;
m_strFile = strFile;
m_uLine = uLine;
}
#endif
QString CError::toPlainText() const
{
return QObject::tr("%1\n\nFunction: %2\nFile: %3 Line: %4\n").arg(m_strText, m_strFunction, m_strFile).arg(m_uLine);
}
QString CError::toHtml() const
{
QString str = m_strText;
str.replace ('\n', "<br>");
return QObject::tr("<p><font color='red'><b>%1</b></font><br>Function: %2<br>File: %3 Line: %4</p><br>\n").arg(str, m_strFunction, m_strFile).arg(m_uLine);
}
/***************************************************************************
* Copyright (C) 1999-2005 by Oliver Saal *
* http://www.oliver-saal.de/ *
* osaal@gmx.de *
* *
* 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 "error.h"
#include <qobject.h>
#include <qstring.h>
#ifdef ERROR_USE_SQL
#include <qsqlerror.h>
#include <qmap.h>
//#include <qmapiterator.h>
#include <qvariant.h>
#endif
CError::CError ()
{
m_uLine = 0;
}
CError::CError (const QString& strFunc, const QString& strFile, const unsigned int uLine)
{
m_strFunction = strFunc;
m_strFile = strFile;
m_uLine = uLine;
}
CError::CError (const QString& strText, const QString& strFunc, const QString& strFile, const unsigned int uLine)
{
m_strText = strText;
m_strFunction = strFunc;
m_strFile = strFile;
m_uLine = uLine;
}
#ifdef ERROR_USE_SQL
CError::CError (const QString& strText, const QSqlDatabase* pDB, const QString& strFunc, const QString& strFile, const unsigned int uLine)
{
m_strText = QString ("%1\n%3").arg (strText, pDB->lastError().text());
m_strFunction = strFunc;
m_strFile = strFile;
m_uLine = uLine;
}
CError::CError (const QString& strText, const QSqlQuery& query, const QString& strFunc, const QString& strFile, const unsigned int uLine)
{
QMap<QString, QVariant> map;
m_strText = QString ("%1\nSQL: %2\n").arg (strText, query.lastQuery());
map = query.boundValues();
if (!map.isEmpty())
{
m_strText+="Bound values:\n";
QMap<QString, QVariant>::const_iterator i = map.constBegin();
while (i != map.constEnd())
{
m_strText += QString ("%1 / %2 ==> %4\n").arg (i.key(), i.value().typeName(), i.value().isNull() ? "NULL" : i.value().toString());
++i;
}
}
m_strText += query.lastError().text();
m_strFunction = strFunc;
m_strFile = strFile;
m_uLine = uLine;
}
#endif
QString CError::toPlainText() const
{
return QObject::tr("%1\n\nFunction: %2\nFile: %3 Line: %4\n").arg(m_strText, m_strFunction, m_strFile).arg(m_uLine);
}
QString CError::toHtml() const
{
QString str = m_strText;
str.replace ('\n', "<br>");
return QObject::tr("<p><font color='red'><b>%1</b></font><br>Function: %2<br>File: %3 Line: %4</p><br>\n").arg(str, m_strFunction, m_strFile).arg(m_uLine);
}

156
error.h
View File

@ -1,78 +1,78 @@
/***************************************************************************
* Copyright (C) 1999-2007 by Oliver Saal *
* http://www.oliver-saal.de/ *
* osaal@gmx.de *
* *
* 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 ERROR_H
#define ERROR_H
//#define ERROR_USE_SQL
#ifndef __PRETTY_FUNCTION__
# if defined __FUNCSIG__
# define __PRETTY_FUNCTION__ __FUNCSIG__
# elif defined __func__
# define __PRETTY_FUNCTION__ __func__
# else
# define __PRETTY_FUNCTION__ __FILE__
# endif
#endif
#include <qstring.h>
#ifdef ERROR_USE_SQL
#include <qsqlquery.h>
#define THROW_TRANSACTION(x) throw CError (tr("Could not start database transaction."), x, __PRETTY_FUNCTION__, __FILE__, __LINE__);
#define THROW_COMMIT(x) throw CError (tr("Could not commit database transaction."), x, __PRETTY_FUNCTION__, __FILE__, __LINE__);
#endif
class CError
{
public:
CError ();
CError (const QString& strFunc, const QString& strFile, const unsigned int uLine);
CError (const QString& strText, const QString& strFunc, const QString& strFile, const unsigned int uLine);
#ifdef ERROR_USE_SQL
CError (const QString& strText, const QSqlDatabase* pDB, const QString& strFunc, const QString& strFile, const unsigned int uLine);
CError (const QString& strText, const QSqlQuery& query, const QString& strFunc, const QString& strFile, const unsigned int uLine);
#endif
inline void preText (const QString& str) { m_strText = str + m_strText; }
inline void postText (const QString& str) { m_strText += str; }
inline QString text() const { return m_strText; }
inline QString function() const { return m_strFunction; }
inline QString file() const { return m_strFile; }
inline unsigned line() const { return m_uLine; }
QString toPlainText() const;
QString toHtml() const;
protected:
QString m_strText;
QString m_strFunction;
QString m_strFile;
unsigned int m_uLine;
};
#endif // ERROR_H
/***************************************************************************
* Copyright (C) 1999-2007 by Oliver Saal *
* http://www.oliver-saal.de/ *
* osaal@gmx.de *
* *
* 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 ERROR_H
#define ERROR_H
//#define ERROR_USE_SQL
#ifndef __PRETTY_FUNCTION__
# if defined __FUNCSIG__
# define __PRETTY_FUNCTION__ __FUNCSIG__
# elif defined __func__
# define __PRETTY_FUNCTION__ __func__
# else
# define __PRETTY_FUNCTION__ __FILE__
# endif
#endif
#include <qstring.h>
#ifdef ERROR_USE_SQL
#include <qsqlquery.h>
#define THROW_TRANSACTION(x) throw CError (tr("Could not start database transaction."), x, __PRETTY_FUNCTION__, __FILE__, __LINE__);
#define THROW_COMMIT(x) throw CError (tr("Could not commit database transaction."), x, __PRETTY_FUNCTION__, __FILE__, __LINE__);
#endif
class CError
{
public:
CError ();
CError (const QString& strFunc, const QString& strFile, const unsigned int uLine);
CError (const QString& strText, const QString& strFunc, const QString& strFile, const unsigned int uLine);
#ifdef ERROR_USE_SQL
CError (const QString& strText, const QSqlDatabase* pDB, const QString& strFunc, const QString& strFile, const unsigned int uLine);
CError (const QString& strText, const QSqlQuery& query, const QString& strFunc, const QString& strFile, const unsigned int uLine);
#endif
inline void preText (const QString& str) { m_strText = str + m_strText; }
inline void postText (const QString& str) { m_strText += str; }
inline QString text() const { return m_strText; }
inline QString function() const { return m_strFunction; }
inline QString file() const { return m_strFile; }
inline unsigned line() const { return m_uLine; }
QString toPlainText() const;
QString toHtml() const;
protected:
QString m_strText;
QString m_strFunction;
QString m_strFile;
unsigned int m_uLine;
};
#endif // ERROR_H

612
exam.cpp
View File

@ -1,306 +1,306 @@
/***************************************************************************
* 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);
}
/***************************************************************************
* 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);
}

284
exam.h
View File

@ -1,142 +1,142 @@
/***************************************************************************
* 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 EXAM_H
#define EXAM_H
#include <qstring.h>
#include <qlist.h>
#include <qdom.h>
#include <qdatetime.h>
#include <qstringlist.h>
class CQuestion;
class CExamPart
{
public:
CExamPart() { clear(); }
~CExamPart() {}
void clear();
inline int questionCount() const { return m_iQuestionCount; }
inline void setQuestionCount(int i) { m_iQuestionCount = i; }
inline QString group() const { return m_strGroup; }
inline void setGroup(const QString& str) { m_strGroup = str; }
inline QString regexp() const { return m_strRegExp; }
inline void setRegExp(const QString& str) { m_strRegExp = str; }
bool load (QDomElement elem);
void save (QDomElement& parent, QDomDocument& doc) const;
QList<CQuestion*> createQuestionPool(const QList<CQuestion*>& listAllQuestions) const;
protected:
int m_iQuestionCount;
QString m_strGroup;
QString m_strRegExp;
};
class CExam
{
public:
CExam() { clear(); }
~CExam() {}
//! Zurücksetzen aller Werte
/*! Es werden alle Daten der Prüfung gelöscht. */
void clear();
//! ID abfragen
inline QString id() const { return m_strId; }
//! ID setzen
inline void setId(const QString& strId) { m_strId = strId; }
inline QString name() const { return m_strName; }
inline QString comment() const { return m_strComment; }
unsigned duration() const { return m_uDuration; }
unsigned maxErrorPoints() const { return m_uMaxErrorPoints; }
unsigned questionCount() const;
bool load (QDomElement elem);
void save (QDomElement& parent, QDomDocument& doc) const;
QList<CQuestion*> createQuestionPool(const QList<CQuestion*>& listAllQuestions) const;
protected:
QString m_strId; //< ID der Prüfung
QString m_strName; //< Name / Bezeichnung
QString m_strComment; //< Kommentar / Hinweis
unsigned m_uDuration; //< Prüfungsdauer in min
unsigned m_uMaxErrorPoints; //< Max. Anzahl an erlaubten Fehlerpunkten, um die Prüfung zu bestehen
QList<CExamPart> m_listParts; //< Abschnitte, aus denen sich die Prüfung zusammensetzt.
};
class CExamStat
{
public:
CExamStat() { clear(); }
CExamStat(const CExam& exam);
~CExamStat() {}
//! Zurücksetzen aller Werte
/*! Es werden alle Daten dieser Prüfungsstatistik gelöscht. */
void clear();
bool load (QDomElement elem);
void save (QDomElement& parent, QDomDocument& doc) const;
//! ID abfragen
inline QString id() const { return m_strId; }
//! ID setzen
inline void setId(const QString& strId) { m_strId = strId; }
inline void setSecs(const unsigned uSecs) { m_uSecs = uSecs; }
void setQuestions(const QList<CQuestion*>& listQuestion, const QList<unsigned>& listAnswerMask);
void setResult (const unsigned uCorrect, const unsigned uWrong, const unsigned uErrorPoints, const bool bPassed);
inline unsigned duration() const { return m_uSecs; }
inline bool passed() const { return m_bPassed; }
inline unsigned correctAnswers() const { return m_uCorrect; }
inline unsigned wrongAnswers() const { return m_uWrong; }
inline unsigned errorPoints() const { return m_uErrorPoints; }
QDateTime datetime() const { return m_dt; }
protected:
QString m_strId; //< ID der Prüfung
QDateTime m_dt; //< Datum/Uhrzeit
unsigned m_uSecs; //< Benötigte Zeit in sec
QStringList m_strlQuestionId; //< IDs der Fragen
QList<unsigned> m_listAnswer; //< Antworten
unsigned m_uCorrect; //< Anzahl d. richtigen Fragen
unsigned m_uWrong; //< Anzahl d. falschen Fragen
unsigned m_uErrorPoints; //< Fehlerpunkte
bool m_bPassed; //< Bestanden Ja/Nein
};
#endif
/***************************************************************************
* 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 EXAM_H
#define EXAM_H
#include <qstring.h>
#include <qlist.h>
#include <qdom.h>
#include <qdatetime.h>
#include <qstringlist.h>
class CQuestion;
class CExamPart
{
public:
CExamPart() { clear(); }
~CExamPart() {}
void clear();
inline int questionCount() const { return m_iQuestionCount; }
inline void setQuestionCount(int i) { m_iQuestionCount = i; }
inline QString group() const { return m_strGroup; }
inline void setGroup(const QString& str) { m_strGroup = str; }
inline QString regexp() const { return m_strRegExp; }
inline void setRegExp(const QString& str) { m_strRegExp = str; }
bool load (QDomElement elem);
void save (QDomElement& parent, QDomDocument& doc) const;
QList<CQuestion*> createQuestionPool(const QList<CQuestion*>& listAllQuestions) const;
protected:
int m_iQuestionCount;
QString m_strGroup;
QString m_strRegExp;
};
class CExam
{
public:
CExam() { clear(); }
~CExam() {}
//! Zurücksetzen aller Werte
/*! Es werden alle Daten der Prüfung gelöscht. */
void clear();
//! ID abfragen
inline QString id() const { return m_strId; }
//! ID setzen
inline void setId(const QString& strId) { m_strId = strId; }
inline QString name() const { return m_strName; }
inline QString comment() const { return m_strComment; }
unsigned duration() const { return m_uDuration; }
unsigned maxErrorPoints() const { return m_uMaxErrorPoints; }
unsigned questionCount() const;
bool load (QDomElement elem);
void save (QDomElement& parent, QDomDocument& doc) const;
QList<CQuestion*> createQuestionPool(const QList<CQuestion*>& listAllQuestions) const;
protected:
QString m_strId; //< ID der Prüfung
QString m_strName; //< Name / Bezeichnung
QString m_strComment; //< Kommentar / Hinweis
unsigned m_uDuration; //< Prüfungsdauer in min
unsigned m_uMaxErrorPoints; //< Max. Anzahl an erlaubten Fehlerpunkten, um die Prüfung zu bestehen
QList<CExamPart> m_listParts; //< Abschnitte, aus denen sich die Prüfung zusammensetzt.
};
class CExamStat
{
public:
CExamStat() { clear(); }
CExamStat(const CExam& exam);
~CExamStat() {}
//! Zurücksetzen aller Werte
/*! Es werden alle Daten dieser Prüfungsstatistik gelöscht. */
void clear();
bool load (QDomElement elem);
void save (QDomElement& parent, QDomDocument& doc) const;
//! ID abfragen
inline QString id() const { return m_strId; }
//! ID setzen
inline void setId(const QString& strId) { m_strId = strId; }
inline void setSecs(const unsigned uSecs) { m_uSecs = uSecs; }
void setQuestions(const QList<CQuestion*>& listQuestion, const QList<unsigned>& listAnswerMask);
void setResult (const unsigned uCorrect, const unsigned uWrong, const unsigned uErrorPoints, const bool bPassed);
inline unsigned duration() const { return m_uSecs; }
inline bool passed() const { return m_bPassed; }
inline unsigned correctAnswers() const { return m_uCorrect; }
inline unsigned wrongAnswers() const { return m_uWrong; }
inline unsigned errorPoints() const { return m_uErrorPoints; }
QDateTime datetime() const { return m_dt; }
protected:
QString m_strId; //< ID der Prüfung
QDateTime m_dt; //< Datum/Uhrzeit
unsigned m_uSecs; //< Benötigte Zeit in sec
QStringList m_strlQuestionId; //< IDs der Fragen
QList<unsigned> m_listAnswer; //< Antworten
unsigned m_uCorrect; //< Anzahl d. richtigen Fragen
unsigned m_uWrong; //< Anzahl d. falschen Fragen
unsigned m_uErrorPoints; //< Fehlerpunkte
bool m_bPassed; //< Bestanden Ja/Nein
};
#endif

View File

@ -1,84 +1,84 @@
/***************************************************************************
* 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 "helper.h"
#include "catalog.h"
void CHint::clear()
{
m_strlQuestionId.clear();
m_strAuthor.clear();
m_date = QDate();
m_strText.clear();
m_strComment.clear();
}
bool CHint::load (QDomElement elem)
{
QString str;
if (elem.tagName() != QString ("hint")) return false;
m_strAuthor = elem.attribute ("author", "AFUTrainer-Hilfe");
m_date = QDate::fromString(elem.attribute ("date"), Qt::ISODate);
str = elem.attribute("question");
str = str.replace(' ', ';').replace(',', ';');
m_strlQuestionId = str.split(";", QString::SkipEmptyParts);
m_strComment = elem.attribute ("comment");
m_strText = elem.text ();
if (m_strText.isEmpty()) return false;
return true;
}
void CHint::save (QDomElement& parent, QDomDocument& doc)
{
QDomElement elemRoot = doc.createElement("hint");
if (!m_strAuthor.isEmpty()) elemRoot.setAttribute("author", m_strAuthor);
if (m_date.isValid()) elemRoot.setAttribute("date", m_date.toString(Qt::ISODate));
elemRoot.setAttribute("question", m_strlQuestionId.join(";"));
if (!m_strComment.isEmpty()) elemRoot.setAttribute("comment", m_strComment);
parent.appendChild(elemRoot);
elemRoot.appendChild(doc.createTextNode(m_strText));
}
QString CHint::showText() const
{
QString str;
/* if (text().isEmpty())
{
if (pCatalog)
return pCatalog->hintText(id());
else
return QString();
}
*/
/* str = "<p><table cellspacing='0' border='0' width='100%'>";
str += "<tr><td bgcolor='gray'><b>"+author()+"</b></td>";
str += "<td bgcolor='gray' align='right'><b>"+dateString()+"</b></td></tr>";
str += "<tr><td colspan='2'>"+text()+"</td></tr>";
str += "<tr><td colspan='2'>&nbsp;</td></tr>";
str += "</table></p>";
*/
str += "<p>" + text() + "</p>"; //"<p><i><font size=-1>" + author() + "&nbsp;" + date() + "</font></i></p>";
return (str);
}
/***************************************************************************
* 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 "helper.h"
#include "catalog.h"
void CHint::clear()
{
m_strlQuestionId.clear();
m_strAuthor.clear();
m_date = QDate();
m_strText.clear();
m_strComment.clear();
}
bool CHint::load (QDomElement elem)
{
QString str;
if (elem.tagName() != QString ("hint")) return false;
m_strAuthor = elem.attribute ("author", "AFUTrainer-Hilfe");
m_date = QDate::fromString(elem.attribute ("date"), Qt::ISODate);
str = elem.attribute("question");
str = str.replace(' ', ';').replace(',', ';');
m_strlQuestionId = str.split(";", QString::SkipEmptyParts);
m_strComment = elem.attribute ("comment");
m_strText = elem.text ();
if (m_strText.isEmpty()) return false;
return true;
}
void CHint::save (QDomElement& parent, QDomDocument& doc)
{
QDomElement elemRoot = doc.createElement("hint");
if (!m_strAuthor.isEmpty()) elemRoot.setAttribute("author", m_strAuthor);
if (m_date.isValid()) elemRoot.setAttribute("date", m_date.toString(Qt::ISODate));
elemRoot.setAttribute("question", m_strlQuestionId.join(";"));
if (!m_strComment.isEmpty()) elemRoot.setAttribute("comment", m_strComment);
parent.appendChild(elemRoot);
elemRoot.appendChild(doc.createTextNode(m_strText));
}
QString CHint::showText() const
{
QString str;
/* if (text().isEmpty())
{
if (pCatalog)
return pCatalog->hintText(id());
else
return QString();
}
*/
/* str = "<p><table cellspacing='0' border='0' width='100%'>";
str += "<tr><td bgcolor='gray'><b>"+author()+"</b></td>";
str += "<td bgcolor='gray' align='right'><b>"+dateString()+"</b></td></tr>";
str += "<tr><td colspan='2'>"+text()+"</td></tr>";
str += "<tr><td colspan='2'>&nbsp;</td></tr>";
str += "</table></p>";
*/
str += "<p>" + text() + "</p>"; //"<p><i><font size=-1>" + author() + "&nbsp;" + date() + "</font></i></p>";
return (str);
}

142
helper.h
View File

@ -1,71 +1,71 @@
/***************************************************************************
* 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 HELPER_H
#define HELPER_H
#include <qstring.h>
#include <qdom.h>
#include <qdatetime.h>
#include <qstringlist.h>
class CCatalog;
class CHint
{
public:
CHint() { clear(); }
~CHint() {}
void clear();
inline void appendQuestion(const QString& id) { if (!hasQuestion(id)) m_strlQuestionId.append(id); }
inline void removeQuestion(const QString& id) { m_strlQuestionId.removeAll(id); }
inline bool hasQuestion(const QString& id) const { return m_strlQuestionId.contains(id); }
inline QString author() const { return m_strAuthor; }
inline void setAuthor(const QString& strAuthor) { m_strAuthor = strAuthor; }
inline QDate date() const { return m_date; }
inline QString dateString() const { return m_date.toString(Qt::LocalDate); }
inline void setDate (const QDate& date) { m_date = date; }
inline QString text() const { return m_strText; }
inline void setText(const QString& strText) { m_strText = strText; }
inline QString comment() const { return m_strComment; }
inline void setComment (const QString& strComment) { m_strComment = strComment; }
QString showText() const;
bool load (QDomElement elem);
void save (QDomElement& parent, QDomDocument& doc);
protected:
QStringList m_strlQuestionId;
QString m_strAuthor;
QDate m_date;
QString m_strText;
QString m_strComment;
};
#endif
/***************************************************************************
* 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 HELPER_H
#define HELPER_H
#include <qstring.h>
#include <qdom.h>
#include <qdatetime.h>
#include <qstringlist.h>
class CCatalog;
class CHint
{
public:
CHint() { clear(); }
~CHint() {}
void clear();
inline void appendQuestion(const QString& id) { if (!hasQuestion(id)) m_strlQuestionId.append(id); }
inline void removeQuestion(const QString& id) { m_strlQuestionId.removeAll(id); }
inline bool hasQuestion(const QString& id) const { return m_strlQuestionId.contains(id); }
inline QString author() const { return m_strAuthor; }
inline void setAuthor(const QString& strAuthor) { m_strAuthor = strAuthor; }
inline QDate date() const { return m_date; }
inline QString dateString() const { return m_date.toString(Qt::LocalDate); }
inline void setDate (const QDate& date) { m_date = date; }
inline QString text() const { return m_strText; }
inline void setText(const QString& strText) { m_strText = strText; }
inline QString comment() const { return m_strComment; }
inline void setComment (const QString& strComment) { m_strComment = strComment; }
QString showText() const;
bool load (QDomElement elem);
void save (QDomElement& parent, QDomDocument& doc);
protected:
QStringList m_strlQuestionId;
QString m_strAuthor;
QDate m_date;
QString m_strText;
QString m_strComment;
};
#endif

View File

@ -1,42 +1,42 @@
/***************************************************************************
* 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 "mainwindow.h"
#include <qapplication.h>
#include <qtranslator.h>
#include <time.h>
int main (int argc, char *argv[])
{
QApplication app (argc, argv);
QTranslator translator;
app.setOrganizationName ("osaal");
app.setApplicationName ("AFUTrainer");
translator.load(":/translations/qt_de");
app.installTranslator(&translator);
srand (time (NULL));
CMainWindow mw;
mw.show();
return app.exec();
}
/***************************************************************************
* 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 "mainwindow.h"
#include <qapplication.h>
#include <qtranslator.h>
#include <time.h>
int main (int argc, char *argv[])
{
QApplication app (argc, argv);
QTranslator translator;
app.setOrganizationName ("osaal");
app.setApplicationName ("AFUTrainer");
translator.load(":/translations/qt_de");
app.installTranslator(&translator);
srand (time (NULL));
CMainWindow mw;
mw.show();
return app.exec();
}

File diff suppressed because it is too large Load Diff

View File

@ -1,91 +1,91 @@
/***************************************************************************
* 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 MAINWINDOW_H
#define MAINWINDOW_H
#include <qmainwindow.h>
#include <qsplitter.h>
#include <qtreeview.h>
#include <qtextbrowser.h>
#include "catalogmodel.h"
#include "questionmodel.h"
#include "recentfiles.h"
#include "ui_mainwindow.h"
class CMainWindow : public QMainWindow, protected Ui::MainWindow
{
Q_OBJECT
public:
CMainWindow();
~CMainWindow();
protected:
void setCatalog (CCatalog *pCatalog);
void updateWindowTitle();
bool checkForErrors();
bool checkForHomeDir();
protected slots:
void on_actFileNew_triggered();
void on_actFileOpen_triggered();
void on_actFileInformation_triggered();
void on_actFileSave_triggered();
void on_actFileSaveAs_triggered();
void on_actFileImport_triggered();
void on_actFileImportUS_triggered();
void on_actFileExit_triggered();
void on_actQuestionAssistant_triggered();
void on_actQuestionsLearn_triggered();
void on_actQuestionsLearnStatistics_triggered();
void on_actQuestionsTest_triggered();
void on_actQuestionsTestStatistics_triggered();
void on_actViewToolbar_toggled(bool bChecked);
void on_actViewStatusbar_toggled(bool bChecked);
void on_actHelpWhatsThis_triggered();
void on_actHelpAbout_triggered();
void on_actHelpAboutQt_triggered();
void onCatalogSelectionChanged (const QItemSelection& selected, const QItemSelection& deselected);
void onQuestionSelectionChanged (const QItemSelection& selected, const QItemSelection& deselected);
void onOpenFile(const QString& strFileName);
// void onAnchorClicked (const QUrl &link );
protected:
CRecentFiles m_rf;
QSplitter *m_pSplitter; // splitter widget
QTreeView *m_pViewChapter; // listview chapters
QTreeView *m_pViewQuestions; // listview questions
QSplitter *m_pSplitter2;
QTextBrowser *m_pTextQuestion;
CCatalog *m_pCatalog;
CCatalogModel m_modelCatalog;
CQuestionModel m_modelQuestion;
};
#endif // MAINWINDOW_H
/***************************************************************************
* 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 MAINWINDOW_H
#define MAINWINDOW_H
#include <qmainwindow.h>
#include <qsplitter.h>
#include <qtreeview.h>
#include <qtextbrowser.h>
#include "catalogmodel.h"
#include "questionmodel.h"
#include "recentfiles.h"
#include "ui_mainwindow.h"
class CMainWindow : public QMainWindow, protected Ui::MainWindow
{
Q_OBJECT
public:
CMainWindow();
~CMainWindow();
protected:
void setCatalog (CCatalog *pCatalog);
void updateWindowTitle();
bool checkForErrors();
bool checkForHomeDir();
protected slots:
void on_actFileNew_triggered();
void on_actFileOpen_triggered();
void on_actFileInformation_triggered();
void on_actFileSave_triggered();
void on_actFileSaveAs_triggered();
void on_actFileImport_triggered();
void on_actFileImportUS_triggered();
void on_actFileExit_triggered();
void on_actQuestionAssistant_triggered();
void on_actQuestionsLearn_triggered();
void on_actQuestionsLearnStatistics_triggered();
void on_actQuestionsTest_triggered();
void on_actQuestionsTestStatistics_triggered();
void on_actViewToolbar_toggled(bool bChecked);
void on_actViewStatusbar_toggled(bool bChecked);
void on_actHelpWhatsThis_triggered();
void on_actHelpAbout_triggered();
void on_actHelpAboutQt_triggered();
void onCatalogSelectionChanged (const QItemSelection& selected, const QItemSelection& deselected);
void onQuestionSelectionChanged (const QItemSelection& selected, const QItemSelection& deselected);
void onOpenFile(const QString& strFileName);
// void onAnchorClicked (const QUrl &link );
protected:
CRecentFiles m_rf;
QSplitter *m_pSplitter; // splitter widget
QTreeView *m_pViewChapter; // listview chapters
QTreeView *m_pViewQuestions; // listview questions
QSplitter *m_pSplitter2;
QTextBrowser *m_pTextQuestion;
CCatalog *m_pCatalog;
CCatalogModel m_modelCatalog;
CQuestionModel m_modelQuestion;
};
#endif // MAINWINDOW_H

View File

@ -1,467 +1,467 @@
#include "osziparchive.h"
#include "zlib/zlib.h"
#include <qbytearray.h>
#include <qdatastream.h>
#include <qtextstream.h>
void CZipFileHeader::clear()
{
m_uVersionMadeBy = 0;
m_uVersionNeeded = 0;
m_uFlags = 0;
m_uCompression = 0;
m_uTime = 0;
m_uDate = 0;
m_uCRC = 0;
m_uSizeCompressed = 0;
m_uSizeUncompressed = 0;
m_uDiskNumberStart = 0;
m_uInternalFileAttributes = 0;
m_uExternalFileAttributes = 0;
m_uRelativeOffsetLocalHeader = 0;
m_strFileName.clear();
m_strComment.clear();
m_baExtraField.clear();
// helpers
m_uDataPosition = 0;
m_uLocalHeaderPosition = 0;
m_uCentralHeaderPosition = 0;
}
void CZipFileHeader::integrate(const CZipFileHeader& head)
{
if (m_uVersionMadeBy == 0) m_uVersionMadeBy = head.m_uVersionMadeBy;
if (m_uVersionNeeded == 0) m_uVersionNeeded = head.m_uVersionNeeded;
if (m_uFlags == 0) m_uFlags = head.m_uFlags;
if (m_uCompression == 0) m_uCompression = head.m_uCompression;
if (m_uTime == 0) m_uTime = head.m_uTime;
if (m_uDate == 0) m_uDate = head.m_uDate;
if (m_uCRC == 0) m_uCRC = head.m_uCRC;
if (m_uSizeCompressed == 0) m_uSizeCompressed = head.m_uSizeCompressed;
if (m_uSizeUncompressed == 0) m_uSizeUncompressed = head.m_uSizeUncompressed;
if (m_uDiskNumberStart == 0) m_uDiskNumberStart = head.m_uDiskNumberStart;
if (m_uInternalFileAttributes == 0) m_uInternalFileAttributes = head.m_uInternalFileAttributes;
if (m_uExternalFileAttributes == 0) m_uExternalFileAttributes = head.m_uExternalFileAttributes;
if (m_uRelativeOffsetLocalHeader == 0) m_uRelativeOffsetLocalHeader = head.m_uRelativeOffsetLocalHeader;
if (m_strFileName.isEmpty()) m_strFileName = head.m_strFileName;
if (m_baExtraField.isEmpty()) m_baExtraField = head.m_baExtraField;
if (m_strComment.isEmpty()) m_strComment = head.m_strComment;
if (m_uDataPosition == 0) m_uDataPosition = head.m_uDataPosition;
if (m_uLocalHeaderPosition == 0) m_uLocalHeaderPosition = head.m_uLocalHeaderPosition;
if (m_uCentralHeaderPosition == 0) m_uCentralHeaderPosition = head.m_uCentralHeaderPosition;
}
bool CZipFileHeader::readLocalFileHeader(QFile& file)
{
QDataStream in(&file);
quint16 uFileNameLength=0, uExtraFieldLength=0;
clear();
in.setByteOrder(QDataStream::LittleEndian);
m_uLocalHeaderPosition = file.pos();
in >> m_uVersionNeeded;
in >> m_uFlags;
in >> m_uCompression;
in >> m_uTime;
in >> m_uDate;
in >> m_uCRC;
in >> m_uSizeCompressed;
in >> m_uSizeUncompressed;
in >> uFileNameLength;
in >> uExtraFieldLength;
if (uFileNameLength != 0)
{
QByteArray a (uFileNameLength, 0);
in.readRawData(a.data(), uFileNameLength);
m_strFileName = a;
}
if (uExtraFieldLength != 0)
{
m_baExtraField.resize(uExtraFieldLength);
in.readRawData(m_baExtraField.data(), uExtraFieldLength);
}
m_uDataPosition = file.pos();
in.skipRawData(m_uSizeCompressed);
if (hasDataDescriptor())
{
in >> m_uCRC;
in >> m_uSizeCompressed;
in >> m_uSizeUncompressed;
}
return true;
}
void CZipFileHeader::writeLocalFileHeader(QFile& file)
{
Q_UNUSED(file);
}
bool CZipFileHeader::readCentralDirectoryHeader(QFile& file)
{
QDataStream in(&file);
quint16 uFileNameLength=0, uExtraFieldLength=0, uCommentLength=0;
clear();
in.setByteOrder(QDataStream::LittleEndian);
m_uCentralHeaderPosition = file.pos();
in >> m_uVersionMadeBy;
in >> m_uVersionNeeded;
in >> m_uFlags;
in >> m_uCompression;
in >> m_uTime;
in >> m_uDate;
in >> m_uCRC;
in >> m_uSizeCompressed;
in >> m_uSizeUncompressed;
in >> uFileNameLength;
in >> uExtraFieldLength;
in >> uCommentLength;
in >> m_uDiskNumberStart;
in >> m_uInternalFileAttributes;
in >> m_uExternalFileAttributes;
in >> m_uRelativeOffsetLocalHeader;
if (uFileNameLength != 0)
{
QByteArray a (uFileNameLength, 0);
in.readRawData(a.data(), uFileNameLength);
m_strFileName = a;
}
if (uExtraFieldLength != 0)
{
m_baExtraField.resize(uExtraFieldLength);
in.readRawData(m_baExtraField.data(), uExtraFieldLength);
}
if (uCommentLength != 0)
{
QByteArray a (uCommentLength, 0);
in.readRawData(a.data(), uCommentLength);
m_strComment = a;
}
return true;
}
void CZipFileHeader::writeCentralDirectoryHeader(QFile& file)
{
Q_UNUSED(file);
}
void CZipEndRecord::clear()
{
m_uDisk = 0;
m_uDiskCentralDir = 0;
m_uEntriesCentralDirDisk = 0;
m_uEntriesCentralDir = 0;
m_uCentralDirSize = 0;
m_uCentralDirOffset = 0;
m_strComment.clear();
}
bool CZipEndRecord::read (QFile& file)
{
QDataStream in(&file);
quint16 uCommentLength=0;
clear();
in.setByteOrder(QDataStream::LittleEndian);
in >> m_uDisk;
in >> m_uDiskCentralDir;
in >> m_uEntriesCentralDirDisk;
in >> m_uEntriesCentralDir;
in >> m_uCentralDirSize;
in >> m_uCentralDirOffset;
in >> uCommentLength;
if (uCommentLength != 0)
{
QByteArray a (uCommentLength, 0);
in.readRawData(a.data(), uCommentLength);
m_strComment = a;
}
return true;
}
void CZipEndRecord::write (QFile& file)
{
Q_UNUSED(file);
}
CZipFile::CZipFile(CZipArchive *pArchive)
{
m_pArchive = pArchive;
clear();
}
CZipFile::~CZipFile()
{
}
void CZipFile::clear()
{
}
bool CZipFile::readHeader ()
{
QFile& file = m_pArchive->m_file;
return (m_head.readLocalFileHeader(file));
}
QByteArray CZipFile::deflateToByteArray()
{
/*QByteArray a, b;
if (m_head.m_uDataPosition == 0 || m_head.m_uSizeUncompressed == 0) return QByteArray();
m_pArchive->m_file.seek (m_head.m_uDataPosition);
a = m_pArchive->m_file.read (m_head.m_uSizeCompressed);
b.resize(m_head.m_uSizeUncompressed);
quint32 u = m_head.m_uSizeUncompressed;
Bytef* src = (Bytef*)a.data();
Bytef* dst = (Bytef*)b.data();
if (uncompress(dst, (uLongf*) &u, src, m_head.m_uSizeCompressed) != Z_OK)
return QByteArray();
return b;*/
QByteArray a;
z_stream strm;
char *pIn=0, *pOut=0;
int ret;
memset(&strm, 0, sizeof(z_stream));
if (m_head.m_uDataPosition == 0 || m_head.m_uSizeUncompressed == 0) return QByteArray();
// prepare zip-stream
/* windowBits is passed < 0 to tell that there is no zlib header.
* Note that in this case inflate *requires* an extra "dummy" byte
* after the compressed stream in order to complete decompression and
* return Z_STREAM_END.
*/
if (inflateInit2(&strm, -MAX_WBITS) != Z_OK) return QByteArray();
// read data
pIn = new char[m_head.m_uSizeCompressed+1];
memset (pIn, 0, m_head.m_uSizeCompressed+1);
m_pArchive->m_file.seek (m_head.m_uDataPosition);
m_pArchive->m_file.read (pIn, m_head.m_uSizeCompressed);
// prepare output
pOut = new char[m_head.m_uSizeUncompressed];
memset(pOut, 0, m_head.m_uSizeUncompressed);
/*
// DEBUG START
FILE *fpt;
fpt = fopen ("questions.xml", "rt");
fread (pOut, m_head.m_uSizeUncompressed, 1, fpt);
fclose (fpt);
unsigned u = m_head.m_uSizeCompressed;
fpt = fopen ("test2.gz", "wb");
compress2((Bytef*)pIn, (uLongf*) &u, (Bytef*)pOut, m_head.m_uSizeUncompressed, 9);
fwrite (pIn, u, 1, fpt);
fclose (fpt);
// DEBUG ENDE
*/
do
{
strm.avail_in = m_head.m_uSizeCompressed+1;
strm.next_in = (Bytef*) pIn;
do
{
strm.avail_out = m_head.m_uSizeUncompressed;
strm.next_out = (Bytef*) pOut;
ret = inflate (&strm, Z_SYNC_FLUSH);
switch (ret)
{
case Z_NEED_DICT:
ret = Z_DATA_ERROR; /* and fall through */
case Z_DATA_ERROR:
case Z_MEM_ERROR:
inflateEnd(&strm);
delete [] pIn;
delete [] pOut;
return QByteArray();
}
}
while (strm.avail_out == 0);
/* done when inflate() says it's done */
}
while (ret != Z_STREAM_END);
inflateEnd(&strm);
a = QByteArray (pOut, m_head.m_uSizeUncompressed);
delete [] pIn;
delete [] pOut;
return a;
}
/*
QString CZipFile::deflateToString()
{
QByteArray a = deflateToByteArray();
QTextStream in (a, QIODevice::ReadOnly);
//QString str;
// in >> str;
return in.readAll();
}
*/
#define CHUNK (1<<16)
bool CZipFile::deflateToFile (QIODevice& dev)
{
z_stream strm;
char cIn[CHUNK], cOut[CHUNK];
int ret;
if ((dev.openMode() & QIODevice::WriteOnly) == 0)
return false;
memset(&strm, 0, sizeof(z_stream));
if (m_head.m_uDataPosition == 0 || m_head.m_uSizeUncompressed == 0) return false;
// prepare zip-stream
/* windowBits is passed < 0 to tell that there is no zlib header.
* Note that in this case inflate *requires* an extra "dummy" byte
* after the compressed stream in order to complete decompression and
* return Z_STREAM_END.
*/
if (inflateInit2(&strm, -MAX_WBITS) != Z_OK) return false;
// prepare archive
m_pArchive->m_file.seek (m_head.m_uDataPosition);
// unzip
unsigned uRead=0, uBytes=0;
do
{
uBytes = m_pArchive->m_file.read(cIn, CHUNK);
if (uRead + uBytes > m_head.m_uSizeCompressed)
uBytes = m_head.m_uSizeCompressed - uRead + 1; // one dummy byte extra
uRead += uBytes;
strm.avail_in = uBytes;
if (strm.avail_in == 0) break;
strm.next_in = (Bytef*) cIn;
do
{
strm.avail_out = CHUNK;
strm.next_out = (Bytef*) cOut;
ret = inflate (&strm, Z_NO_FLUSH);
switch (ret)
{
case Z_NEED_DICT:
ret = Z_DATA_ERROR; /* and fall through */
case Z_DATA_ERROR:
case Z_MEM_ERROR:
inflateEnd(&strm);
return false;
}
unsigned uHave = CHUNK - strm.avail_out;
dev.write(cOut, uHave);
}
while (strm.avail_out == 0);
/* done when inflate() says it's done */
}
while (ret != Z_STREAM_END);
inflateEnd(&strm);
return true;
}
CZipArchive::CZipArchive()
{
}
CZipArchive::~CZipArchive()
{
qDeleteAll(m_listFiles);
qDeleteAll(m_listEndRecords);
}
bool CZipArchive::open (const QString& strFileName, const OpenMode om)
{
unsigned uSignature=0;
CZipFile *pzf=0;
if (strFileName.isEmpty()) return false;
if (om != OpenReadOnly) return false;
m_strFileName = strFileName;
m_file.close();
m_file.setFileName(strFileName);
if (!m_file.open(QIODevice::ReadOnly)) return false;
QDataStream in(&m_file);
in.setByteOrder(QDataStream::LittleEndian);
while (!in.atEnd())
{
uSignature = 0;
in >> uSignature;
if (uSignature == 0x04034b50)
{ // local file header with data
pzf = new CZipFile(this);
if (pzf->readHeader())
m_listFiles.append(pzf);
//qDebug("%7i %7i %s", pzf->m_head.m_uSizeUncompressed, pzf->m_head.m_uSizeCompressed, qPrintable(pzf->fileName()));
// file.deflateToFile("test.tmp");
}
else if (uSignature == 0x02014b50)
{ // central directory file header
CZipFileHeader head;
head.readCentralDirectoryHeader(m_file);
pzf = findFile(head.m_strFileName);
if (pzf) pzf->m_head.integrate(head);
}
else if (uSignature == 0x06054b50)
{ // End of central directory record
CZipEndRecord *pzer = new CZipEndRecord();
pzer->read(m_file);
m_listEndRecords.append(pzer);
}
else
{
qDebug("Unknown signature: %X", uSignature);
break;
}
}
return true;
}
CZipFile* CZipArchive::findFile (const QString& strFileName)
{
for (int i=0; i<m_listFiles.size(); i++)
{
if (m_listFiles.at(i)->fileName() == strFileName)
return m_listFiles.at(i);
}
return 0;
}
#include "osziparchive.h"
#include "zlib/zlib.h"
#include <qbytearray.h>
#include <qdatastream.h>
#include <qtextstream.h>
void CZipFileHeader::clear()
{
m_uVersionMadeBy = 0;
m_uVersionNeeded = 0;
m_uFlags = 0;
m_uCompression = 0;
m_uTime = 0;
m_uDate = 0;
m_uCRC = 0;
m_uSizeCompressed = 0;
m_uSizeUncompressed = 0;
m_uDiskNumberStart = 0;
m_uInternalFileAttributes = 0;
m_uExternalFileAttributes = 0;
m_uRelativeOffsetLocalHeader = 0;
m_strFileName.clear();
m_strComment.clear();
m_baExtraField.clear();
// helpers
m_uDataPosition = 0;
m_uLocalHeaderPosition = 0;
m_uCentralHeaderPosition = 0;
}
void CZipFileHeader::integrate(const CZipFileHeader& head)
{
if (m_uVersionMadeBy == 0) m_uVersionMadeBy = head.m_uVersionMadeBy;
if (m_uVersionNeeded == 0) m_uVersionNeeded = head.m_uVersionNeeded;
if (m_uFlags == 0) m_uFlags = head.m_uFlags;
if (m_uCompression == 0) m_uCompression = head.m_uCompression;
if (m_uTime == 0) m_uTime = head.m_uTime;
if (m_uDate == 0) m_uDate = head.m_uDate;
if (m_uCRC == 0) m_uCRC = head.m_uCRC;
if (m_uSizeCompressed == 0) m_uSizeCompressed = head.m_uSizeCompressed;
if (m_uSizeUncompressed == 0) m_uSizeUncompressed = head.m_uSizeUncompressed;
if (m_uDiskNumberStart == 0) m_uDiskNumberStart = head.m_uDiskNumberStart;
if (m_uInternalFileAttributes == 0) m_uInternalFileAttributes = head.m_uInternalFileAttributes;
if (m_uExternalFileAttributes == 0) m_uExternalFileAttributes = head.m_uExternalFileAttributes;
if (m_uRelativeOffsetLocalHeader == 0) m_uRelativeOffsetLocalHeader = head.m_uRelativeOffsetLocalHeader;
if (m_strFileName.isEmpty()) m_strFileName = head.m_strFileName;
if (m_baExtraField.isEmpty()) m_baExtraField = head.m_baExtraField;
if (m_strComment.isEmpty()) m_strComment = head.m_strComment;
if (m_uDataPosition == 0) m_uDataPosition = head.m_uDataPosition;
if (m_uLocalHeaderPosition == 0) m_uLocalHeaderPosition = head.m_uLocalHeaderPosition;
if (m_uCentralHeaderPosition == 0) m_uCentralHeaderPosition = head.m_uCentralHeaderPosition;
}
bool CZipFileHeader::readLocalFileHeader(QFile& file)
{
QDataStream in(&file);
quint16 uFileNameLength=0, uExtraFieldLength=0;
clear();
in.setByteOrder(QDataStream::LittleEndian);
m_uLocalHeaderPosition = file.pos();
in >> m_uVersionNeeded;
in >> m_uFlags;
in >> m_uCompression;
in >> m_uTime;
in >> m_uDate;
in >> m_uCRC;
in >> m_uSizeCompressed;
in >> m_uSizeUncompressed;
in >> uFileNameLength;
in >> uExtraFieldLength;
if (uFileNameLength != 0)
{
QByteArray a (uFileNameLength, 0);
in.readRawData(a.data(), uFileNameLength);
m_strFileName = a;
}
if (uExtraFieldLength != 0)
{
m_baExtraField.resize(uExtraFieldLength);
in.readRawData(m_baExtraField.data(), uExtraFieldLength);
}
m_uDataPosition = file.pos();
in.skipRawData(m_uSizeCompressed);
if (hasDataDescriptor())
{
in >> m_uCRC;
in >> m_uSizeCompressed;
in >> m_uSizeUncompressed;
}
return true;
}
void CZipFileHeader::writeLocalFileHeader(QFile& file)
{
Q_UNUSED(file);
}
bool CZipFileHeader::readCentralDirectoryHeader(QFile& file)
{
QDataStream in(&file);
quint16 uFileNameLength=0, uExtraFieldLength=0, uCommentLength=0;
clear();
in.setByteOrder(QDataStream::LittleEndian);
m_uCentralHeaderPosition = file.pos();
in >> m_uVersionMadeBy;
in >> m_uVersionNeeded;
in >> m_uFlags;
in >> m_uCompression;
in >> m_uTime;
in >> m_uDate;
in >> m_uCRC;
in >> m_uSizeCompressed;
in >> m_uSizeUncompressed;
in >> uFileNameLength;
in >> uExtraFieldLength;
in >> uCommentLength;
in >> m_uDiskNumberStart;
in >> m_uInternalFileAttributes;
in >> m_uExternalFileAttributes;
in >> m_uRelativeOffsetLocalHeader;
if (uFileNameLength != 0)
{
QByteArray a (uFileNameLength, 0);
in.readRawData(a.data(), uFileNameLength);
m_strFileName = a;
}
if (uExtraFieldLength != 0)
{
m_baExtraField.resize(uExtraFieldLength);
in.readRawData(m_baExtraField.data(), uExtraFieldLength);
}
if (uCommentLength != 0)
{
QByteArray a (uCommentLength, 0);
in.readRawData(a.data(), uCommentLength);
m_strComment = a;
}
return true;
}
void CZipFileHeader::writeCentralDirectoryHeader(QFile& file)
{
Q_UNUSED(file);
}
void CZipEndRecord::clear()
{
m_uDisk = 0;
m_uDiskCentralDir = 0;
m_uEntriesCentralDirDisk = 0;
m_uEntriesCentralDir = 0;
m_uCentralDirSize = 0;
m_uCentralDirOffset = 0;
m_strComment.clear();
}
bool CZipEndRecord::read (QFile& file)
{
QDataStream in(&file);
quint16 uCommentLength=0;
clear();
in.setByteOrder(QDataStream::LittleEndian);
in >> m_uDisk;
in >> m_uDiskCentralDir;
in >> m_uEntriesCentralDirDisk;
in >> m_uEntriesCentralDir;
in >> m_uCentralDirSize;
in >> m_uCentralDirOffset;
in >> uCommentLength;
if (uCommentLength != 0)
{
QByteArray a (uCommentLength, 0);
in.readRawData(a.data(), uCommentLength);
m_strComment = a;
}
return true;
}
void CZipEndRecord::write (QFile& file)
{
Q_UNUSED(file);
}
CZipFile::CZipFile(CZipArchive *pArchive)
{
m_pArchive = pArchive;
clear();
}
CZipFile::~CZipFile()
{
}
void CZipFile::clear()
{
}
bool CZipFile::readHeader ()
{
QFile& file = m_pArchive->m_file;
return (m_head.readLocalFileHeader(file));
}
QByteArray CZipFile::deflateToByteArray()
{
/*QByteArray a, b;
if (m_head.m_uDataPosition == 0 || m_head.m_uSizeUncompressed == 0) return QByteArray();
m_pArchive->m_file.seek (m_head.m_uDataPosition);
a = m_pArchive->m_file.read (m_head.m_uSizeCompressed);
b.resize(m_head.m_uSizeUncompressed);
quint32 u = m_head.m_uSizeUncompressed;
Bytef* src = (Bytef*)a.data();
Bytef* dst = (Bytef*)b.data();
if (uncompress(dst, (uLongf*) &u, src, m_head.m_uSizeCompressed) != Z_OK)
return QByteArray();
return b;*/
QByteArray a;
z_stream strm;
char *pIn=0, *pOut=0;
int ret;
memset(&strm, 0, sizeof(z_stream));
if (m_head.m_uDataPosition == 0 || m_head.m_uSizeUncompressed == 0) return QByteArray();
// prepare zip-stream
/* windowBits is passed < 0 to tell that there is no zlib header.
* Note that in this case inflate *requires* an extra "dummy" byte
* after the compressed stream in order to complete decompression and
* return Z_STREAM_END.
*/
if (inflateInit2(&strm, -MAX_WBITS) != Z_OK) return QByteArray();
// read data
pIn = new char[m_head.m_uSizeCompressed+1];
memset (pIn, 0, m_head.m_uSizeCompressed+1);
m_pArchive->m_file.seek (m_head.m_uDataPosition);
m_pArchive->m_file.read (pIn, m_head.m_uSizeCompressed);
// prepare output
pOut = new char[m_head.m_uSizeUncompressed];
memset(pOut, 0, m_head.m_uSizeUncompressed);
/*
// DEBUG START
FILE *fpt;
fpt = fopen ("questions.xml", "rt");
fread (pOut, m_head.m_uSizeUncompressed, 1, fpt);
fclose (fpt);
unsigned u = m_head.m_uSizeCompressed;
fpt = fopen ("test2.gz", "wb");
compress2((Bytef*)pIn, (uLongf*) &u, (Bytef*)pOut, m_head.m_uSizeUncompressed, 9);
fwrite (pIn, u, 1, fpt);
fclose (fpt);
// DEBUG ENDE
*/
do
{
strm.avail_in = m_head.m_uSizeCompressed+1;
strm.next_in = (Bytef*) pIn;
do
{
strm.avail_out = m_head.m_uSizeUncompressed;
strm.next_out = (Bytef*) pOut;
ret = inflate (&strm, Z_SYNC_FLUSH);
switch (ret)
{
case Z_NEED_DICT:
ret = Z_DATA_ERROR; /* and fall through */
case Z_DATA_ERROR:
case Z_MEM_ERROR:
inflateEnd(&strm);
delete [] pIn;
delete [] pOut;
return QByteArray();
}
}
while (strm.avail_out == 0);
/* done when inflate() says it's done */
}
while (ret != Z_STREAM_END);
inflateEnd(&strm);
a = QByteArray (pOut, m_head.m_uSizeUncompressed);
delete [] pIn;
delete [] pOut;
return a;
}
/*
QString CZipFile::deflateToString()
{
QByteArray a = deflateToByteArray();
QTextStream in (a, QIODevice::ReadOnly);
//QString str;
// in >> str;
return in.readAll();
}
*/
#define CHUNK (1<<16)
bool CZipFile::deflateToFile (QIODevice& dev)
{
z_stream strm;
char cIn[CHUNK], cOut[CHUNK];
int ret;
if ((dev.openMode() & QIODevice::WriteOnly) == 0)
return false;
memset(&strm, 0, sizeof(z_stream));
if (m_head.m_uDataPosition == 0 || m_head.m_uSizeUncompressed == 0) return false;
// prepare zip-stream
/* windowBits is passed < 0 to tell that there is no zlib header.
* Note that in this case inflate *requires* an extra "dummy" byte
* after the compressed stream in order to complete decompression and
* return Z_STREAM_END.
*/
if (inflateInit2(&strm, -MAX_WBITS) != Z_OK) return false;
// prepare archive
m_pArchive->m_file.seek (m_head.m_uDataPosition);
// unzip
unsigned uRead=0, uBytes=0;
do
{
uBytes = m_pArchive->m_file.read(cIn, CHUNK);
if (uRead + uBytes > m_head.m_uSizeCompressed)
uBytes = m_head.m_uSizeCompressed - uRead + 1; // one dummy byte extra
uRead += uBytes;
strm.avail_in = uBytes;
if (strm.avail_in == 0) break;
strm.next_in = (Bytef*) cIn;
do
{
strm.avail_out = CHUNK;
strm.next_out = (Bytef*) cOut;
ret = inflate (&strm, Z_NO_FLUSH);
switch (ret)
{
case Z_NEED_DICT:
ret = Z_DATA_ERROR; /* and fall through */
case Z_DATA_ERROR:
case Z_MEM_ERROR:
inflateEnd(&strm);
return false;
}
unsigned uHave = CHUNK - strm.avail_out;
dev.write(cOut, uHave);
}
while (strm.avail_out == 0);
/* done when inflate() says it's done */
}
while (ret != Z_STREAM_END);
inflateEnd(&strm);
return true;
}
CZipArchive::CZipArchive()
{
}
CZipArchive::~CZipArchive()
{
qDeleteAll(m_listFiles);
qDeleteAll(m_listEndRecords);
}
bool CZipArchive::open (const QString& strFileName, const OpenMode om)
{
unsigned uSignature=0;
CZipFile *pzf=0;
if (strFileName.isEmpty()) return false;
if (om != OpenReadOnly) return false;
m_strFileName = strFileName;
m_file.close();
m_file.setFileName(strFileName);
if (!m_file.open(QIODevice::ReadOnly)) return false;
QDataStream in(&m_file);
in.setByteOrder(QDataStream::LittleEndian);
while (!in.atEnd())
{
uSignature = 0;
in >> uSignature;
if (uSignature == 0x04034b50)
{ // local file header with data
pzf = new CZipFile(this);
if (pzf->readHeader())
m_listFiles.append(pzf);
//qDebug("%7i %7i %s", pzf->m_head.m_uSizeUncompressed, pzf->m_head.m_uSizeCompressed, qPrintable(pzf->fileName()));
// file.deflateToFile("test.tmp");
}
else if (uSignature == 0x02014b50)
{ // central directory file header
CZipFileHeader head;
head.readCentralDirectoryHeader(m_file);
pzf = findFile(head.m_strFileName);
if (pzf) pzf->m_head.integrate(head);
}
else if (uSignature == 0x06054b50)
{ // End of central directory record
CZipEndRecord *pzer = new CZipEndRecord();
pzer->read(m_file);
m_listEndRecords.append(pzer);
}
else
{
qDebug("Unknown signature: %X", uSignature);
break;
}
}
return true;
}
CZipFile* CZipArchive::findFile (const QString& strFileName)
{
for (int i=0; i<m_listFiles.size(); i++)
{
if (m_listFiles.at(i)->fileName() == strFileName)
return m_listFiles.at(i);
}
return 0;
}

View File

@ -1,155 +1,155 @@
/***************************************************************************
* Copyright (C) 2003-2006 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 OSZIPARCHIVE_H
#define OSZIPARCHIVE_H
#include <qfile.h>
#include <qstring.h>
#include <qlist.h>
class CZipFile;
class CZipArchive;
class CZipFileHeader
{
public:
CZipFileHeader() { clear(); }
~CZipFileHeader() {}
void clear();
void integrate(const CZipFileHeader& head);
bool readLocalFileHeader(QFile& file);
void writeLocalFileHeader(QFile& file);
bool readCentralDirectoryHeader(QFile& file);
void writeCentralDirectoryHeader(QFile& file);
inline bool hasDataDescriptor() const { return m_uFlags & (1<<3) ? true : false; }
public:
quint16 m_uVersionMadeBy; //!< version made by 2 bytes
quint16 m_uVersionNeeded; //!< version needed to extract 2 bytes
quint16 m_uFlags; //!< general purpose bit flag 2 bytes
quint16 m_uCompression; //!< compression method 2 bytes
quint16 m_uTime; //!< last mod file time 2 bytes
quint16 m_uDate; //!< last mod file date 2 bytes
quint32 m_uCRC; //!< crc-32 4 bytes
quint32 m_uSizeCompressed; //!< compressed size 4 bytes
quint32 m_uSizeUncompressed; //!< uncompressed size 4 bytes
quint16 m_uDiskNumberStart; //!< disk number start 2 bytes
quint16 m_uInternalFileAttributes; //!< internal file attributes 2 bytes
quint32 m_uExternalFileAttributes; //!< external file attributes 4 bytes
quint32 m_uRelativeOffsetLocalHeader; //!< relative offset of local header 4 bytes
QString m_strFileName; //!< file name (variable size)
QByteArray m_baExtraField; //!< extra field (variable size)
QString m_strComment; //!< file comment (variable size)
// helpers
quint64 m_uLocalHeaderPosition; //!< Position of the local file header, after the signature field
quint64 m_uDataPosition; //!< Position in the file of the data
quint64 m_uCentralHeaderPosition; //!< Position of the central directory file header, after the signature field
};
class CZipEndRecord
{
public:
CZipEndRecord() { clear(); }
~CZipEndRecord() { }
void clear();
bool read (QFile& file);
void write (QFile& file);
public:
quint16 m_uDisk; //!< number of this disk 2 bytes
quint16 m_uDiskCentralDir; //!< number of the disk with the start of the central directory 2 bytes
quint16 m_uEntriesCentralDirDisk; //!< total number of entries in the central directory on this disk 2 bytes
quint16 m_uEntriesCentralDir; //!< total number of entries in the central directory 2 bytes
quint32 m_uCentralDirSize; //!< size of the central directory 4 bytes
quint32 m_uCentralDirOffset; //!< offset of start of central directory with respect to the starting disk number 4 bytes
QString m_strComment;
};
//! Represents a file in a zip archive
class CZipFile
{
public:
CZipFile() { m_pArchive = 0; clear(); }
CZipFile(CZipArchive *pArchive);
~CZipFile();
void clear();
inline bool isValid() const { return m_pArchive != 0; }
//! Reads local file header
//! Position has to be after the signature field
//! After the operation, the current position in the file is after the file data
bool readHeader();
bool deflateToFile (QIODevice& dev);
QByteArray deflateToByteArray();
//QString deflateToString();
// bool read (FILE *fpt, unsigned uPosition);
//! this file has a data descriptor
inline QString fileName() const { return m_head.m_strFileName; }
public:
CZipArchive *m_pArchive;
CZipFileHeader m_head;
};
class CZipArchive
{
public:
CZipArchive();
~CZipArchive();
enum OpenMode { OpenReadOnly, OpenCreate, OpenModify };
bool open (const QString& strFileName, const OpenMode om);
CZipFile* findFile (const QString& strFileName);
inline int fileCount() const { return m_listFiles.size(); }
const CZipFile* fileAt(const int i) const { return m_listFiles.at(i); }
CZipFile* fileAt(const int i) { return m_listFiles.at(i); }
protected:
friend class CZipFile;
QFile m_file;
QString m_strFileName;
QList<CZipFile*> m_listFiles;
QList<CZipEndRecord*> m_listEndRecords;
};
#endif
/***************************************************************************
* Copyright (C) 2003-2006 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 OSZIPARCHIVE_H
#define OSZIPARCHIVE_H
#include <qfile.h>
#include <qstring.h>
#include <qlist.h>
class CZipFile;
class CZipArchive;
class CZipFileHeader
{
public:
CZipFileHeader() { clear(); }
~CZipFileHeader() {}
void clear();
void integrate(const CZipFileHeader& head);
bool readLocalFileHeader(QFile& file);
void writeLocalFileHeader(QFile& file);
bool readCentralDirectoryHeader(QFile& file);
void writeCentralDirectoryHeader(QFile& file);
inline bool hasDataDescriptor() const { return m_uFlags & (1<<3) ? true : false; }
public:
quint16 m_uVersionMadeBy; //!< version made by 2 bytes
quint16 m_uVersionNeeded; //!< version needed to extract 2 bytes
quint16 m_uFlags; //!< general purpose bit flag 2 bytes
quint16 m_uCompression; //!< compression method 2 bytes
quint16 m_uTime; //!< last mod file time 2 bytes
quint16 m_uDate; //!< last mod file date 2 bytes
quint32 m_uCRC; //!< crc-32 4 bytes
quint32 m_uSizeCompressed; //!< compressed size 4 bytes
quint32 m_uSizeUncompressed; //!< uncompressed size 4 bytes
quint16 m_uDiskNumberStart; //!< disk number start 2 bytes
quint16 m_uInternalFileAttributes; //!< internal file attributes 2 bytes
quint32 m_uExternalFileAttributes; //!< external file attributes 4 bytes
quint32 m_uRelativeOffsetLocalHeader; //!< relative offset of local header 4 bytes
QString m_strFileName; //!< file name (variable size)
QByteArray m_baExtraField; //!< extra field (variable size)
QString m_strComment; //!< file comment (variable size)
// helpers
quint64 m_uLocalHeaderPosition; //!< Position of the local file header, after the signature field
quint64 m_uDataPosition; //!< Position in the file of the data
quint64 m_uCentralHeaderPosition; //!< Position of the central directory file header, after the signature field
};
class CZipEndRecord
{
public:
CZipEndRecord() { clear(); }
~CZipEndRecord() { }
void clear();
bool read (QFile& file);
void write (QFile& file);
public:
quint16 m_uDisk; //!< number of this disk 2 bytes
quint16 m_uDiskCentralDir; //!< number of the disk with the start of the central directory 2 bytes
quint16 m_uEntriesCentralDirDisk; //!< total number of entries in the central directory on this disk 2 bytes
quint16 m_uEntriesCentralDir; //!< total number of entries in the central directory 2 bytes
quint32 m_uCentralDirSize; //!< size of the central directory 4 bytes
quint32 m_uCentralDirOffset; //!< offset of start of central directory with respect to the starting disk number 4 bytes
QString m_strComment;
};
//! Represents a file in a zip archive
class CZipFile
{
public:
CZipFile() { m_pArchive = 0; clear(); }
CZipFile(CZipArchive *pArchive);
~CZipFile();
void clear();
inline bool isValid() const { return m_pArchive != 0; }
//! Reads local file header
//! Position has to be after the signature field
//! After the operation, the current position in the file is after the file data
bool readHeader();
bool deflateToFile (QIODevice& dev);
QByteArray deflateToByteArray();
//QString deflateToString();
// bool read (FILE *fpt, unsigned uPosition);
//! this file has a data descriptor
inline QString fileName() const { return m_head.m_strFileName; }
public:
CZipArchive *m_pArchive;
CZipFileHeader m_head;
};
class CZipArchive
{
public:
CZipArchive();
~CZipArchive();
enum OpenMode { OpenReadOnly, OpenCreate, OpenModify };
bool open (const QString& strFileName, const OpenMode om);
CZipFile* findFile (const QString& strFileName);
inline int fileCount() const { return m_listFiles.size(); }
const CZipFile* fileAt(const int i) const { return m_listFiles.at(i); }
CZipFile* fileAt(const int i) { return m_listFiles.at(i); }
protected:
friend class CZipFile;
QFile m_file;
QString m_strFileName;
QList<CZipFile*> m_listFiles;
QList<CZipEndRecord*> m_listEndRecords;
};
#endif

View File

@ -1,426 +1,426 @@
/***************************************************************************
* 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 "plotwidget.h"
#include <qpainter.h>
void CPlotWidgetPoint::clear()
{
}
void CPlotWidgetCurve::clear()
{
QList<CPlotWidgetPoint>::clear();
}
QRectF CPlotWidgetCurve::boundaries() const
{
QRectF rect;
for (int i=0; i<size(); i++)
{
QPointF p = at(i);
if (i == 0)
{
rect.setBottomLeft(p);
rect.setTopRight(p);
}
else
{
if (p.x() < rect.left())
rect.setLeft(p.x());
else if (p.x() > rect.right())
rect.setRight(p.x());
if (p.y() > rect.bottom())
rect.setBottom(p.y());
else if (p.y() < rect.top())
rect.setTop(p.y());
}
}
return rect;
}
CPlotWidgetTic::CPlotWidgetTic(const double dPos, const QString& strText)
{
clear();
m_dPos = dPos;
m_strText = strText;
}
CPlotWidgetTic::CPlotWidgetTic(const double dPos, const double dWidth, const QString& strText)
{
clear();
m_dPos = dPos;
m_dWidth = dWidth;
m_strText = strText;
}
CPlotWidgetTic::CPlotWidgetTic(const double dPos, const QPixmap& pixmap)
{
clear();
m_dPos = dPos;
m_pixmap = pixmap;
}
void CPlotWidgetTic::clear()
{
m_dPos = 0.0;
m_dWidth = 0.0;
m_pen = QPen(Qt::DashLine);
m_pen.setColor(Qt::darkGray);
m_penFont = QPen(Qt::black);
m_pixmap = QPixmap();
m_strText.clear();
m_fillType = FillNone;
m_lineType = LinePlot;
m_iTextFlags = Qt::AlignHCenter | Qt::AlignTop;
}
void CPlotWidgetTic::paintX (QPainter *pPainter, CPlotWidget *pWidget) const
{
QPoint ptTL, ptBR; // TopLeft, BottomRight
QRect rectText;
if (m_fillType != FillNone && m_dWidth > 0.0)
{
ptTL = pWidget->mapToPlot(QPointF(m_dPos, pWidget->m_rectData.top()));
ptBR = pWidget->mapToPlot(QPointF(m_dPos+m_dWidth, pWidget->m_rectData.bottom()));
if (m_fillType == FillAll)
{
ptTL.setY(pWidget->m_rectPlot.top());
ptBR.setY(pWidget->m_rectPlot.bottom());
}
if (ptTL.x() < pWidget->m_rectPlot.left())
ptTL.setX(pWidget->m_rectPlot.left());
if (ptBR.x() > pWidget->m_rectPlot.right())
ptBR.setX(pWidget->m_rectPlot.right());
pPainter->fillRect(QRect(ptTL, ptBR), m_brush);
rectText = QRect(
QPoint(ptTL.x(), pWidget->m_rectPlot.bottom() + 5),
QPoint(ptBR.x(), pWidget->rect().bottom()));
}
else
{
rectText = QRect();
}
if (m_lineType != LineNone)
{
pPainter->setPen(m_pen);
pPainter->drawLine(
pWidget->mapToPlot(QPointF(m_dPos, pWidget->m_rectData.top())),
pWidget->mapToPlot(QPointF(m_dPos, pWidget->m_rectData.bottom())));
}
if (!m_strText.isEmpty())
{
pPainter->setPen(m_penFont);
pPainter->drawText(rectText, m_iTextFlags, m_strText);
}
}
void CPlotWidgetTic::paintY (QPainter *pPainter, CPlotWidget *pWidget) const
{
QPoint ptTL, ptBR; // TopLeft, BottomRight
QRect rectText;
if (m_fillType != FillNone && m_dWidth > 0.0)
{
ptTL = pWidget->mapToPlot(QPointF(pWidget->m_rectData.left(), m_dPos));
ptBR = pWidget->mapToPlot(QPointF(pWidget->m_rectData.right(), m_dPos+m_dWidth));
if (m_fillType == FillAll)
{
ptTL.setX(pWidget->m_rectPlot.left());
ptBR.setX(pWidget->m_rectPlot.right());
}
if (ptTL.y() < pWidget->m_rectPlot.top())
ptTL.setY(pWidget->m_rectPlot.top());
if (ptBR.y() > pWidget->m_rectPlot.bottom())
ptBR.setY(pWidget->m_rectPlot.bottom());
pPainter->fillRect(QRect(ptTL, ptBR), m_brush);
rectText = QRect(
QPoint(3, ptTL.y()),
QPoint(pWidget->m_rectPlot.left()-3, ptBR.y()));
}
else
{
QFontMetrics fm(m_font);
QPoint pt = pWidget->mapToPlot(QPointF(pWidget->m_rectData.left(), m_dPos));
rectText = QRect(
QPoint(3, pt.y()-fm.height()),
QPoint(pWidget->m_rectPlot.left()-3, pt.y()+fm.height()));
}
if (m_lineType != LineNone)
{
pPainter->setPen(m_pen);
pPainter->drawLine(
pWidget->mapToPlot(QPointF(pWidget->m_rectData.left(), m_dPos)),
pWidget->mapToPlot(QPointF(pWidget->m_rectData.right(), m_dPos)));
}
if (!m_pixmap.isNull())
{
// Ziel-Mittelpunkt errechnen
QPoint pt = pWidget->mapToPlot(QPointF(0, m_dPos));
pt.setX(pWidget->m_rectPlot.left() - m_pixmap.width()/2 - 5);
// Linke obere Ecke errechnen und malen!
pt -= QPoint (m_pixmap.width()/2, m_pixmap.height()/2);
pPainter->drawPixmap(pt, m_pixmap);
}
if (!m_strText.isEmpty())
{
pPainter->setPen(m_penFont);
pPainter->drawText(rectText, m_iTextFlags, m_strText);
}
}
CPlotWidget::CPlotWidget(QWidget *pParent) : QFrame(pParent)
{
clear();
}
void CPlotWidget::clear()
{
m_type = PlotLines;
m_bLimitAutoY = true;
m_bLimitAutoX = true;
m_dLimitXMin = 0.0;
m_dLimitXMax = 10.0;
m_dLimitYMin = 0.0;
m_dLimitYMax = 10.0;
m_dLimitXRound = 0.0;
m_dLimitYRound = 0.0;
m_dTicX = 0.0;
m_penTicX = QPen(Qt::DashLine);
m_penTicX.setColor(Qt::darkGray);
m_dTicY = 0.0;
m_penTicY = QPen(Qt::DashLine);
m_penTicY.setColor(Qt::darkGray);
m_iBorder = BorderLeft|BorderBottom;
m_iBorderDistTop = 5;
m_iBorderDistBottom = 5;
m_iBorderDistLeft = 5;
m_iBorderDistRight = 5;
m_brushPlotBkg = QBrush(Qt::white);
m_listTicX.clear();
m_listTicY.clear();
m_dBarWidth = 0.6;
m_dBarOffset = 0.0;
m_listCurves.clear();
}
void CPlotWidget::setBorderDistance(const int iLeft, const int iRight, const int iTop, const int iBottom)
{
m_iBorderDistTop = iTop;
m_iBorderDistBottom = iBottom;
m_iBorderDistLeft = iLeft;
m_iBorderDistRight = iRight;
}
void CPlotWidget::updateCache()
{
m_rectPlot = plotArea();
m_rectData = rectData();
}
QRect CPlotWidget::plotArea() const
{
QRect rect = frameRect();
rect.adjust(m_iBorderDistLeft, m_iBorderDistTop, -m_iBorderDistRight, -m_iBorderDistBottom);
return rect;
}
QRectF CPlotWidget::rectData() const
{
QRectF rect;
if (m_bLimitAutoX || m_bLimitAutoY)
{
for (int i=0; i<m_listCurves.size(); i++)
{
rect = rect.united(m_listCurves.at(i).boundaries());
}
}
if (!m_bLimitAutoX)
{
rect.setLeft(m_dLimitXMin);
rect.setRight(m_dLimitXMax);
}
else if (m_dLimitXRound > 0.0)
{
rect.setLeft((unsigned)(rect.left() / m_dLimitXRound) * m_dLimitXRound);
rect.setRight((unsigned)(rect.right() / m_dLimitXRound + 1) * m_dLimitXRound);
}
if (!m_bLimitAutoY)
{
rect.setTop(m_dLimitYMin);
rect.setBottom(m_dLimitYMax);
}
else if (m_dLimitYRound > 0.0)
{
rect.setTop((unsigned)(rect.top() / m_dLimitYRound) * m_dLimitYRound);
rect.setBottom((unsigned)(rect.bottom() / m_dLimitYRound + 1) * m_dLimitYRound);
}
return rect;
}
QPoint CPlotWidget::mapToPlot (QPointF p)
{
QPointF ret;
double m;
// Umrechung X-Koordinate
m = ((double) (m_rectPlot.left() - m_rectPlot.right())) / (m_rectData.left() - m_rectData.right());
ret.setX(m * (p.x() - m_rectData.left()) + m_rectPlot.left());
// Umrechnung Y-Koordinate (mit Spiegelung)
m = ((double) (m_rectPlot.bottom() - m_rectPlot.top())) / (m_rectData.top() - m_rectData.bottom());
ret.setY(m * (p.y() - m_rectData.top()) + m_rectPlot.bottom());
return ret.toPoint();
}
void CPlotWidget::paintEvent (QPaintEvent *e)
{
QList<QPoint> listPoints;
QList<CPlotWidgetTic> listTicsX, listTicsY;
double d=0.0;
int i=0;
QFrame::paintEvent(e);
QPainter painter(this);
updateCache();
// Draw Background
if (m_brushPlotBkg.style() != Qt::NoBrush)
{
painter.fillRect(m_rectPlot, m_brushPlotBkg);
}
// Draw Tics
listTicsX = m_listTicX;
if (listTicsX.isEmpty() && m_dTicX > 0.0)
{
d = ((unsigned)(m_rectData.left() / m_dTicX)) * m_dTicX;
if (d < m_rectData.left()) d+=m_dTicX;
while (d <= m_rectData.right())
{
CPlotWidgetTic tic(d, QString("%1").arg(d,0,'f',2));
tic.setPen(m_penTicX);
listTicsX.append(tic);
d += m_dTicX;
}
}
listTicsY = m_listTicY;
if (listTicsY.isEmpty() && m_dTicY > 0.0)
{
d = ((unsigned)(m_rectData.top() / m_dTicY)) * m_dTicY;
if (d < m_rectData.top()) d+=m_dTicY;
while (d <= m_rectData.bottom())
{
CPlotWidgetTic tic(d, QString("%1").arg(d,0,'f',2));
tic.setPen(m_penTicY);
listTicsY.append(tic);
d += m_dTicY;
}
}
for (i=0; i<listTicsX.size(); i++)
listTicsX.at(i).paintX(&painter, this);
for (i=0; i<listTicsY.size(); i++)
listTicsY.at(i).paintY(&painter, this);
// Draw Curves
if (m_type == PlotLines)
{
for (int i=0; i<m_listCurves.size(); i++)
{
CPlotWidgetCurve c = m_listCurves.at(i);
for (int j=0; j<c.size(); j++)
{
CPlotWidgetPoint p = c.at(j);
listPoints.append(mapToPlot (p));
}
painter.setPen(c.pen());
painter.drawPolyline(listPoints.toVector());
}
}
else if (m_type == PlotBarsSum && m_listCurves.size() != 0)
{
CPlotWidgetCurve c1 = m_listCurves.at(0);
//painter.setPen(c1.pen());
//painter.setBrush(c1.brush());
QPoint ptTL, ptBR;
for (int j=0; j<c1.size(); j++)
{ // Alle Punkte der ersten Kurve durchgehen
CPlotWidgetPoint p1 = c1.at(j);
ptTL = mapToPlot(QPointF(p1.x() + m_dBarOffset - m_dBarWidth/2, p1.y()));
ptBR = mapToPlot(QPointF(p1.x() + m_dBarOffset + m_dBarWidth/2, m_rectData.top()));
if (p1.y() != 0.0 && m_rectPlot.contains(ptTL) && m_rectPlot.contains(ptBR))
painter.fillRect(QRect(ptTL, ptBR), c1.brush());
double dStart = p1.y();
for (int i=1; i<m_listCurves.size(); i++)
{ // alle Weiteren Kurven durchgehen
CPlotWidgetCurve c2 = m_listCurves.at(i);
for (int jj=0; jj<c2.size(); jj++)
{ // alle Punkte der zweiten Kurve durchgehen
CPlotWidgetPoint p2 = c2.at(jj);
if (p2.x() != p1.x()) continue;
ptTL = mapToPlot(QPointF(p2.x() + m_dBarOffset - m_dBarWidth/2, dStart+p2.y()));
ptBR = mapToPlot(QPointF(p2.x() + m_dBarOffset + m_dBarWidth/2, dStart+m_rectData.top()));
if (p2.y() != 0 && m_rectPlot.contains(ptTL) && m_rectPlot.contains(ptBR))
{
dStart += p2.y();
painter.fillRect(QRect(ptTL, ptBR), c2.brush());
}
}
}
}
}
// Draw border
painter.setPen(m_penBorder);
if (m_iBorder & BorderLeft)
painter.drawLine(m_rectPlot.topLeft(), m_rectPlot.bottomLeft());
if (m_iBorder & BorderRight)
painter.drawLine(m_rectPlot.topRight(), m_rectPlot.bottomRight());
if (m_iBorder & BorderTop)
painter.drawLine(m_rectPlot.topRight(), m_rectPlot.topLeft());
if (m_iBorder & BorderBottom)
painter.drawLine(m_rectPlot.bottomRight(), m_rectPlot.bottomLeft());
}
/***************************************************************************
* 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 "plotwidget.h"
#include <qpainter.h>
void CPlotWidgetPoint::clear()
{
}
void CPlotWidgetCurve::clear()
{
QList<CPlotWidgetPoint>::clear();
}
QRectF CPlotWidgetCurve::boundaries() const
{
QRectF rect;
for (int i=0; i<size(); i++)
{
QPointF p = at(i);
if (i == 0)
{
rect.setBottomLeft(p);
rect.setTopRight(p);
}
else
{
if (p.x() < rect.left())
rect.setLeft(p.x());
else if (p.x() > rect.right())
rect.setRight(p.x());
if (p.y() > rect.bottom())
rect.setBottom(p.y());
else if (p.y() < rect.top())
rect.setTop(p.y());
}
}
return rect;
}
CPlotWidgetTic::CPlotWidgetTic(const double dPos, const QString& strText)
{
clear();
m_dPos = dPos;
m_strText = strText;
}
CPlotWidgetTic::CPlotWidgetTic(const double dPos, const double dWidth, const QString& strText)
{
clear();
m_dPos = dPos;
m_dWidth = dWidth;
m_strText = strText;
}
CPlotWidgetTic::CPlotWidgetTic(const double dPos, const QPixmap& pixmap)
{
clear();
m_dPos = dPos;
m_pixmap = pixmap;
}
void CPlotWidgetTic::clear()
{
m_dPos = 0.0;
m_dWidth = 0.0;
m_pen = QPen(Qt::DashLine);
m_pen.setColor(Qt::darkGray);
m_penFont = QPen(Qt::black);
m_pixmap = QPixmap();
m_strText.clear();
m_fillType = FillNone;
m_lineType = LinePlot;
m_iTextFlags = Qt::AlignHCenter | Qt::AlignTop;
}
void CPlotWidgetTic::paintX (QPainter *pPainter, CPlotWidget *pWidget) const
{
QPoint ptTL, ptBR; // TopLeft, BottomRight
QRect rectText;
if (m_fillType != FillNone && m_dWidth > 0.0)
{
ptTL = pWidget->mapToPlot(QPointF(m_dPos, pWidget->m_rectData.top()));
ptBR = pWidget->mapToPlot(QPointF(m_dPos+m_dWidth, pWidget->m_rectData.bottom()));
if (m_fillType == FillAll)
{
ptTL.setY(pWidget->m_rectPlot.top());
ptBR.setY(pWidget->m_rectPlot.bottom());
}
if (ptTL.x() < pWidget->m_rectPlot.left())
ptTL.setX(pWidget->m_rectPlot.left());
if (ptBR.x() > pWidget->m_rectPlot.right())
ptBR.setX(pWidget->m_rectPlot.right());
pPainter->fillRect(QRect(ptTL, ptBR), m_brush);
rectText = QRect(
QPoint(ptTL.x(), pWidget->m_rectPlot.bottom() + 5),
QPoint(ptBR.x(), pWidget->rect().bottom()));
}
else
{
rectText = QRect();
}
if (m_lineType != LineNone)
{
pPainter->setPen(m_pen);
pPainter->drawLine(
pWidget->mapToPlot(QPointF(m_dPos, pWidget->m_rectData.top())),
pWidget->mapToPlot(QPointF(m_dPos, pWidget->m_rectData.bottom())));
}
if (!m_strText.isEmpty())
{
pPainter->setPen(m_penFont);
pPainter->drawText(rectText, m_iTextFlags, m_strText);
}
}
void CPlotWidgetTic::paintY (QPainter *pPainter, CPlotWidget *pWidget) const
{
QPoint ptTL, ptBR; // TopLeft, BottomRight
QRect rectText;
if (m_fillType != FillNone && m_dWidth > 0.0)
{
ptTL = pWidget->mapToPlot(QPointF(pWidget->m_rectData.left(), m_dPos));
ptBR = pWidget->mapToPlot(QPointF(pWidget->m_rectData.right(), m_dPos+m_dWidth));
if (m_fillType == FillAll)
{
ptTL.setX(pWidget->m_rectPlot.left());
ptBR.setX(pWidget->m_rectPlot.right());
}
if (ptTL.y() < pWidget->m_rectPlot.top())
ptTL.setY(pWidget->m_rectPlot.top());
if (ptBR.y() > pWidget->m_rectPlot.bottom())
ptBR.setY(pWidget->m_rectPlot.bottom());
pPainter->fillRect(QRect(ptTL, ptBR), m_brush);
rectText = QRect(
QPoint(3, ptTL.y()),
QPoint(pWidget->m_rectPlot.left()-3, ptBR.y()));
}
else
{
QFontMetrics fm(m_font);
QPoint pt = pWidget->mapToPlot(QPointF(pWidget->m_rectData.left(), m_dPos));
rectText = QRect(
QPoint(3, pt.y()-fm.height()),
QPoint(pWidget->m_rectPlot.left()-3, pt.y()+fm.height()));
}
if (m_lineType != LineNone)
{
pPainter->setPen(m_pen);
pPainter->drawLine(
pWidget->mapToPlot(QPointF(pWidget->m_rectData.left(), m_dPos)),
pWidget->mapToPlot(QPointF(pWidget->m_rectData.right(), m_dPos)));
}
if (!m_pixmap.isNull())
{
// Ziel-Mittelpunkt errechnen
QPoint pt = pWidget->mapToPlot(QPointF(0, m_dPos));
pt.setX(pWidget->m_rectPlot.left() - m_pixmap.width()/2 - 5);
// Linke obere Ecke errechnen und malen!
pt -= QPoint (m_pixmap.width()/2, m_pixmap.height()/2);
pPainter->drawPixmap(pt, m_pixmap);
}
if (!m_strText.isEmpty())
{
pPainter->setPen(m_penFont);
pPainter->drawText(rectText, m_iTextFlags, m_strText);
}
}
CPlotWidget::CPlotWidget(QWidget *pParent) : QFrame(pParent)
{
clear();
}
void CPlotWidget::clear()
{
m_type = PlotLines;
m_bLimitAutoY = true;
m_bLimitAutoX = true;
m_dLimitXMin = 0.0;
m_dLimitXMax = 10.0;
m_dLimitYMin = 0.0;
m_dLimitYMax = 10.0;
m_dLimitXRound = 0.0;
m_dLimitYRound = 0.0;
m_dTicX = 0.0;
m_penTicX = QPen(Qt::DashLine);
m_penTicX.setColor(Qt::darkGray);
m_dTicY = 0.0;
m_penTicY = QPen(Qt::DashLine);
m_penTicY.setColor(Qt::darkGray);
m_iBorder = BorderLeft|BorderBottom;
m_iBorderDistTop = 5;
m_iBorderDistBottom = 5;
m_iBorderDistLeft = 5;
m_iBorderDistRight = 5;
m_brushPlotBkg = QBrush(Qt::white);
m_listTicX.clear();
m_listTicY.clear();
m_dBarWidth = 0.6;
m_dBarOffset = 0.0;
m_listCurves.clear();
}
void CPlotWidget::setBorderDistance(const int iLeft, const int iRight, const int iTop, const int iBottom)
{
m_iBorderDistTop = iTop;
m_iBorderDistBottom = iBottom;
m_iBorderDistLeft = iLeft;
m_iBorderDistRight = iRight;
}
void CPlotWidget::updateCache()
{
m_rectPlot = plotArea();
m_rectData = rectData();
}
QRect CPlotWidget::plotArea() const
{
QRect rect = frameRect();
rect.adjust(m_iBorderDistLeft, m_iBorderDistTop, -m_iBorderDistRight, -m_iBorderDistBottom);
return rect;
}
QRectF CPlotWidget::rectData() const
{
QRectF rect;
if (m_bLimitAutoX || m_bLimitAutoY)
{
for (int i=0; i<m_listCurves.size(); i++)
{
rect = rect.united(m_listCurves.at(i).boundaries());
}
}
if (!m_bLimitAutoX)
{
rect.setLeft(m_dLimitXMin);
rect.setRight(m_dLimitXMax);
}
else if (m_dLimitXRound > 0.0)
{
rect.setLeft((unsigned)(rect.left() / m_dLimitXRound) * m_dLimitXRound);
rect.setRight((unsigned)(rect.right() / m_dLimitXRound + 1) * m_dLimitXRound);
}
if (!m_bLimitAutoY)
{
rect.setTop(m_dLimitYMin);
rect.setBottom(m_dLimitYMax);
}
else if (m_dLimitYRound > 0.0)
{
rect.setTop((unsigned)(rect.top() / m_dLimitYRound) * m_dLimitYRound);
rect.setBottom((unsigned)(rect.bottom() / m_dLimitYRound + 1) * m_dLimitYRound);
}
return rect;
}
QPoint CPlotWidget::mapToPlot (QPointF p)
{
QPointF ret;
double m;
// Umrechung X-Koordinate
m = ((double) (m_rectPlot.left() - m_rectPlot.right())) / (m_rectData.left() - m_rectData.right());
ret.setX(m * (p.x() - m_rectData.left()) + m_rectPlot.left());
// Umrechnung Y-Koordinate (mit Spiegelung)
m = ((double) (m_rectPlot.bottom() - m_rectPlot.top())) / (m_rectData.top() - m_rectData.bottom());
ret.setY(m * (p.y() - m_rectData.top()) + m_rectPlot.bottom());
return ret.toPoint();
}
void CPlotWidget::paintEvent (QPaintEvent *e)
{
QList<QPoint> listPoints;
QList<CPlotWidgetTic> listTicsX, listTicsY;
double d=0.0;
int i=0;
QFrame::paintEvent(e);
QPainter painter(this);
updateCache();
// Draw Background
if (m_brushPlotBkg.style() != Qt::NoBrush)
{
painter.fillRect(m_rectPlot, m_brushPlotBkg);
}
// Draw Tics
listTicsX = m_listTicX;
if (listTicsX.isEmpty() && m_dTicX > 0.0)
{
d = ((unsigned)(m_rectData.left() / m_dTicX)) * m_dTicX;
if (d < m_rectData.left()) d+=m_dTicX;
while (d <= m_rectData.right())
{
CPlotWidgetTic tic(d, QString("%1").arg(d,0,'f',2));
tic.setPen(m_penTicX);
listTicsX.append(tic);
d += m_dTicX;
}
}
listTicsY = m_listTicY;
if (listTicsY.isEmpty() && m_dTicY > 0.0)
{
d = ((unsigned)(m_rectData.top() / m_dTicY)) * m_dTicY;
if (d < m_rectData.top()) d+=m_dTicY;
while (d <= m_rectData.bottom())
{
CPlotWidgetTic tic(d, QString("%1").arg(d,0,'f',2));
tic.setPen(m_penTicY);
listTicsY.append(tic);
d += m_dTicY;
}
}
for (i=0; i<listTicsX.size(); i++)
listTicsX.at(i).paintX(&painter, this);
for (i=0; i<listTicsY.size(); i++)
listTicsY.at(i).paintY(&painter, this);
// Draw Curves
if (m_type == PlotLines)
{
for (int i=0; i<m_listCurves.size(); i++)
{
CPlotWidgetCurve c = m_listCurves.at(i);
for (int j=0; j<c.size(); j++)
{
CPlotWidgetPoint p = c.at(j);
listPoints.append(mapToPlot (p));
}
painter.setPen(c.pen());
painter.drawPolyline(listPoints.toVector());
}
}
else if (m_type == PlotBarsSum && m_listCurves.size() != 0)
{
CPlotWidgetCurve c1 = m_listCurves.at(0);
//painter.setPen(c1.pen());
//painter.setBrush(c1.brush());
QPoint ptTL, ptBR;
for (int j=0; j<c1.size(); j++)
{ // Alle Punkte der ersten Kurve durchgehen
CPlotWidgetPoint p1 = c1.at(j);
ptTL = mapToPlot(QPointF(p1.x() + m_dBarOffset - m_dBarWidth/2, p1.y()));
ptBR = mapToPlot(QPointF(p1.x() + m_dBarOffset + m_dBarWidth/2, m_rectData.top()));
if (p1.y() != 0.0 && m_rectPlot.contains(ptTL) && m_rectPlot.contains(ptBR))
painter.fillRect(QRect(ptTL, ptBR), c1.brush());
double dStart = p1.y();
for (int i=1; i<m_listCurves.size(); i++)
{ // alle Weiteren Kurven durchgehen
CPlotWidgetCurve c2 = m_listCurves.at(i);
for (int jj=0; jj<c2.size(); jj++)
{ // alle Punkte der zweiten Kurve durchgehen
CPlotWidgetPoint p2 = c2.at(jj);
if (p2.x() != p1.x()) continue;
ptTL = mapToPlot(QPointF(p2.x() + m_dBarOffset - m_dBarWidth/2, dStart+p2.y()));
ptBR = mapToPlot(QPointF(p2.x() + m_dBarOffset + m_dBarWidth/2, dStart+m_rectData.top()));
if (p2.y() != 0 && m_rectPlot.contains(ptTL) && m_rectPlot.contains(ptBR))
{
dStart += p2.y();
painter.fillRect(QRect(ptTL, ptBR), c2.brush());
}
}
}
}
}
// Draw border
painter.setPen(m_penBorder);
if (m_iBorder & BorderLeft)
painter.drawLine(m_rectPlot.topLeft(), m_rectPlot.bottomLeft());
if (m_iBorder & BorderRight)
painter.drawLine(m_rectPlot.topRight(), m_rectPlot.bottomRight());
if (m_iBorder & BorderTop)
painter.drawLine(m_rectPlot.topRight(), m_rectPlot.topLeft());
if (m_iBorder & BorderBottom)
painter.drawLine(m_rectPlot.bottomRight(), m_rectPlot.bottomLeft());
}

View File

@ -1,215 +1,215 @@
/***************************************************************************
* 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. *
***************************************************************************/
#pragma once
#include <qframe.h>
#include <qpoint.h>
#include <qrect.h>
#include <qpen.h>
#include <qbrush.h>
#include <qmap.h>
#include <qfont.h>
class CPlotWidgetPoint;
class CPlotWidgetCurve;
class CPlotWidgetTic;
class CPlotWidget;
class CPlotWidgetPoint : public QPointF
{
public:
CPlotWidgetPoint() { clear(); }
CPlotWidgetPoint(const double x, const double y) : QPointF(x,y) {}
~CPlotWidgetPoint() {}
void clear();
protected:
};
class CPlotWidgetCurve : public QList<CPlotWidgetPoint>
{
public:
CPlotWidgetCurve() { clear(); }
~CPlotWidgetCurve() {}
void clear();
QRectF boundaries() const;
inline void setPen(const QPen& pen) { m_pen = pen; }
inline QPen pen() const { return m_pen; }
inline void setBrush(const QBrush& brush) { m_brush = brush; }
inline QBrush brush() const { return m_brush; }
protected:
QPen m_pen;
QBrush m_brush;
};
class CPlotWidgetTic
{
public:
enum LineType { LineNone, LineShort, LinePlot, LineFull };
enum FillType { FillNone, FillPlot, FillAll };
CPlotWidgetTic() { clear(); }
CPlotWidgetTic(const double dPos, const QString& strText);
CPlotWidgetTic(const double dPos, const double dWidth, const QString& strText);
CPlotWidgetTic(const double dPos, const QPixmap& pixmap);
~CPlotWidgetTic() {}
void clear();
inline void setPen(const QPen& pen) { m_pen = pen; }
inline QPen pen() const { return m_pen; }
inline void setBrush(const QBrush& brush) { m_brush = brush; }
inline QBrush brush() const { return m_brush; }
inline void setFont(const QFont& font) { m_font = font; }
inline QFont font() const { return m_font; }
inline void setFontPen(const QPen& pen) { m_penFont = pen; }
inline QPen fontPen() const { return m_penFont; }
inline void setPos(const double dPos) { m_dPos = dPos; }
inline double pos() const { return m_dPos; }
inline void setWidth(const double dWidth) { m_dWidth = dWidth; }
inline double width() const { return m_dWidth; }
inline void setFillType(const FillType t) { m_fillType = t; }
inline FillType fillType () const { return m_fillType; }
inline void setLineType(const LineType t) { m_lineType = t; }
inline LineType lineType () const { return m_lineType; }
inline void setText(const QString& str) { m_strText = str; }
inline QString text() const { return m_strText; }
inline void setTextFlags (const int iFlags) { m_iTextFlags = iFlags; }
inline int textFlags() const { return m_iTextFlags; }
void paintX (QPainter *pPainter, CPlotWidget *pWidget) const;
void paintY (QPainter *pPainter, CPlotWidget *pWidget) const;
protected:
double m_dPos;
// Beschriftung
QPixmap m_pixmap;
QString m_strText;
QFont m_font;
QPen m_penFont;
int m_iTextFlags;
// Line
QPen m_pen;
LineType m_lineType;
// Background
double m_dWidth;
QBrush m_brush;
FillType m_fillType;
};
class CPlotWidget : public QFrame
{
Q_OBJECT
public:
enum PlotType { PlotPoints, PlotLines, PlotBarsSum, PlotBars };
enum Border { BorderTop=0x01, BorderBottom=0x02, BorderLeft=0x04, BorderRight=0x08 };
CPlotWidget(QWidget *pParent=0);
~CPlotWidget() {}
void clear();
inline void clearCurves() { m_listCurves.clear(); }
inline void appendCurve (const CPlotWidgetCurve& c) { m_listCurves.append(c); }
QRect plotArea() const;
QRectF rectData() const;
inline void setType (const PlotType t) { m_type = t; }
inline PlotType type() const { return m_type; }
inline void setLimitX(const double min, const double max) { m_dLimitXMin = min; m_dLimitXMax = max; m_bLimitAutoX = false; }
inline void setLimitY(const double min, const double max) { m_dLimitYMin = min; m_dLimitYMax = max; m_bLimitAutoY = false; }
inline void setAutoLimitX(const bool bAutoLimit) { m_bLimitAutoX = bAutoLimit; }
inline void setAutoLimitY(const bool bAutoLimit) { m_bLimitAutoY = bAutoLimit; }
inline void setAutoLimitRoundX(const double dRound) { m_dLimitXRound = dRound; }
inline void setAutoLimitRoundY(const double dRound) { m_dLimitYRound = dRound; }
inline void setLabelX(const QString& str) { m_strLabelX = str; }
inline void setLabelY(const QString& str) { m_strLabelY = str; }
inline void setPlotBackground (const QBrush& brush) { m_brushPlotBkg = brush; }
inline void setBorderPen(const QPen& pen) { m_penBorder = pen; }
inline QPen borderPen() const { return m_penBorder; }
inline void setBorder(const int iBorder=BorderLeft|BorderBottom) { m_iBorder = iBorder; }
inline int border() const { return m_iBorder; }
void setBorderDistance(const int iLeft, const int iRight, const int iTop, const int iBottom);
inline void setTicX(const double dTic) { m_dTicX = dTic; }
inline void setTicY(const double dTic) { m_dTicY = dTic; }
inline void setTicXPen(const QPen& pen) { m_penTicX = pen; }
inline void setTicYPen(const QPen& pen) { m_penTicY = pen; }
inline void setTicListX (const QList<CPlotWidgetTic>& list) { m_listTicX = list; }
inline void setTicListY (const QList<CPlotWidgetTic>& list) { m_listTicY = list; }
inline void setBarWidth(const double d) { m_dBarWidth = d; }
inline void setBarOffset(const double d) { m_dBarOffset = d; }
protected:
virtual void paintEvent (QPaintEvent *e);
void updateCache();
QPoint mapToPlot (QPointF p);
friend class CPlotWidgetTic;
protected:
PlotType m_type;
QList<CPlotWidgetCurve> m_listCurves;
double m_dLimitXMin, m_dLimitXMax, m_dLimitYMin, m_dLimitYMax;
double m_dLimitXRound, m_dLimitYRound;
bool m_bLimitAutoX, m_bLimitAutoY;
// Border
QBrush m_brushPlotBkg;
QPen m_penBorder;
int m_iBorder; //!< Logische Verknüpfung aus BorderTop, BorderBottom, BorderLeft, BorderRight
int m_iBorderDistTop;
int m_iBorderDistBottom;
int m_iBorderDistLeft;
int m_iBorderDistRight;
// Tics & Labels
QList<CPlotWidgetTic> m_listTicX;
QList<CPlotWidgetTic> m_listTicY;
double m_dTicX;
QPen m_penTicX;
double m_dTicY;
QPen m_penTicY;
QString m_strLabelX;
QString m_strLabelY;
// Bars
double m_dBarWidth;
double m_dBarOffset;
// Cache
QRect m_rectPlot;
QRectF m_rectData;
};
/***************************************************************************
* 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. *
***************************************************************************/
#pragma once
#include <qframe.h>
#include <qpoint.h>
#include <qrect.h>
#include <qpen.h>
#include <qbrush.h>
#include <qmap.h>
#include <qfont.h>
class CPlotWidgetPoint;
class CPlotWidgetCurve;
class CPlotWidgetTic;
class CPlotWidget;
class CPlotWidgetPoint : public QPointF
{
public:
CPlotWidgetPoint() { clear(); }
CPlotWidgetPoint(const double x, const double y) : QPointF(x,y) {}
~CPlotWidgetPoint() {}
void clear();
protected:
};
class CPlotWidgetCurve : public QList<CPlotWidgetPoint>
{
public:
CPlotWidgetCurve() { clear(); }
~CPlotWidgetCurve() {}
void clear();
QRectF boundaries() const;
inline void setPen(const QPen& pen) { m_pen = pen; }
inline QPen pen() const { return m_pen; }
inline void setBrush(const QBrush& brush) { m_brush = brush; }
inline QBrush brush() const { return m_brush; }
protected:
QPen m_pen;
QBrush m_brush;
};
class CPlotWidgetTic
{
public:
enum LineType { LineNone, LineShort, LinePlot, LineFull };
enum FillType { FillNone, FillPlot, FillAll };
CPlotWidgetTic() { clear(); }
CPlotWidgetTic(const double dPos, const QString& strText);
CPlotWidgetTic(const double dPos, const double dWidth, const QString& strText);
CPlotWidgetTic(const double dPos, const QPixmap& pixmap);
~CPlotWidgetTic() {}
void clear();
inline void setPen(const QPen& pen) { m_pen = pen; }
inline QPen pen() const { return m_pen; }
inline void setBrush(const QBrush& brush) { m_brush = brush; }
inline QBrush brush() const { return m_brush; }
inline void setFont(const QFont& font) { m_font = font; }
inline QFont font() const { return m_font; }
inline void setFontPen(const QPen& pen) { m_penFont = pen; }
inline QPen fontPen() const { return m_penFont; }
inline void setPos(const double dPos) { m_dPos = dPos; }
inline double pos() const { return m_dPos; }
inline void setWidth(const double dWidth) { m_dWidth = dWidth; }
inline double width() const { return m_dWidth; }
inline void setFillType(const FillType t) { m_fillType = t; }
inline FillType fillType () const { return m_fillType; }
inline void setLineType(const LineType t) { m_lineType = t; }
inline LineType lineType () const { return m_lineType; }
inline void setText(const QString& str) { m_strText = str; }
inline QString text() const { return m_strText; }
inline void setTextFlags (const int iFlags) { m_iTextFlags = iFlags; }
inline int textFlags() const { return m_iTextFlags; }
void paintX (QPainter *pPainter, CPlotWidget *pWidget) const;
void paintY (QPainter *pPainter, CPlotWidget *pWidget) const;
protected:
double m_dPos;
// Beschriftung
QPixmap m_pixmap;
QString m_strText;
QFont m_font;
QPen m_penFont;
int m_iTextFlags;
// Line
QPen m_pen;
LineType m_lineType;
// Background
double m_dWidth;
QBrush m_brush;
FillType m_fillType;
};
class CPlotWidget : public QFrame
{
Q_OBJECT
public:
enum PlotType { PlotPoints, PlotLines, PlotBarsSum, PlotBars };
enum Border { BorderTop=0x01, BorderBottom=0x02, BorderLeft=0x04, BorderRight=0x08 };
CPlotWidget(QWidget *pParent=0);
~CPlotWidget() {}
void clear();
inline void clearCurves() { m_listCurves.clear(); }
inline void appendCurve (const CPlotWidgetCurve& c) { m_listCurves.append(c); }
QRect plotArea() const;
QRectF rectData() const;
inline void setType (const PlotType t) { m_type = t; }
inline PlotType type() const { return m_type; }
inline void setLimitX(const double min, const double max) { m_dLimitXMin = min; m_dLimitXMax = max; m_bLimitAutoX = false; }
inline void setLimitY(const double min, const double max) { m_dLimitYMin = min; m_dLimitYMax = max; m_bLimitAutoY = false; }
inline void setAutoLimitX(const bool bAutoLimit) { m_bLimitAutoX = bAutoLimit; }
inline void setAutoLimitY(const bool bAutoLimit) { m_bLimitAutoY = bAutoLimit; }
inline void setAutoLimitRoundX(const double dRound) { m_dLimitXRound = dRound; }
inline void setAutoLimitRoundY(const double dRound) { m_dLimitYRound = dRound; }
inline void setLabelX(const QString& str) { m_strLabelX = str; }
inline void setLabelY(const QString& str) { m_strLabelY = str; }
inline void setPlotBackground (const QBrush& brush) { m_brushPlotBkg = brush; }
inline void setBorderPen(const QPen& pen) { m_penBorder = pen; }
inline QPen borderPen() const { return m_penBorder; }
inline void setBorder(const int iBorder=BorderLeft|BorderBottom) { m_iBorder = iBorder; }
inline int border() const { return m_iBorder; }
void setBorderDistance(const int iLeft, const int iRight, const int iTop, const int iBottom);
inline void setTicX(const double dTic) { m_dTicX = dTic; }
inline void setTicY(const double dTic) { m_dTicY = dTic; }
inline void setTicXPen(const QPen& pen) { m_penTicX = pen; }
inline void setTicYPen(const QPen& pen) { m_penTicY = pen; }
inline void setTicListX (const QList<CPlotWidgetTic>& list) { m_listTicX = list; }
inline void setTicListY (const QList<CPlotWidgetTic>& list) { m_listTicY = list; }
inline void setBarWidth(const double d) { m_dBarWidth = d; }
inline void setBarOffset(const double d) { m_dBarOffset = d; }
protected:
virtual void paintEvent (QPaintEvent *e);
void updateCache();
QPoint mapToPlot (QPointF p);
friend class CPlotWidgetTic;
protected:
PlotType m_type;
QList<CPlotWidgetCurve> m_listCurves;
double m_dLimitXMin, m_dLimitXMax, m_dLimitYMin, m_dLimitYMax;
double m_dLimitXRound, m_dLimitYRound;
bool m_bLimitAutoX, m_bLimitAutoY;
// Border
QBrush m_brushPlotBkg;
QPen m_penBorder;
int m_iBorder; //!< Logische Verknüpfung aus BorderTop, BorderBottom, BorderLeft, BorderRight
int m_iBorderDistTop;
int m_iBorderDistBottom;
int m_iBorderDistLeft;
int m_iBorderDistRight;
// Tics & Labels
QList<CPlotWidgetTic> m_listTicX;
QList<CPlotWidgetTic> m_listTicY;
double m_dTicX;
QPen m_penTicX;
double m_dTicY;
QPen m_penTicY;
QString m_strLabelX;
QString m_strLabelY;
// Bars
double m_dBarWidth;
double m_dBarOffset;
// Cache
QRect m_rectPlot;
QRectF m_rectData;
};

File diff suppressed because it is too large Load Diff

View File

@ -1,247 +1,247 @@
/***************************************************************************
* 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ücksetzen aller Werte
/*! Es werden alle Daten der Frage gelö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ängen eines Textes an den Fragentext
/*!
\param strText Anzuhä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ä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äufigkeit ermitteln
static QString levelIconName(const unsigned uLevel);
//! Icon einer bestimmten Abfragehäufigkeit
static QIcon levelIcon(const unsigned uLevel);
//! Name einer bestimmten Abfragehä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äufigkeit
static unsigned waitDaysForRepeat (const unsigned uLevel);
protected:
CChapter *m_pParentChapter; //!< Zeiger auf das (Eltern-) Kapitel, zu dem die Frage gehö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üfung
QStringList m_strlGroups; //!< Liste der Klassen/Gruppen, zu denen diese Frage gehört
// learning
//! Durchmischte Antworten
/*! Die Liste enthä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äufigkeit
/*!
Stufe 0: sehr häufige ... Stufe 5: sehr seltene Abfrage
Die Abfragehä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
/***************************************************************************
* 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ücksetzen aller Werte
/*! Es werden alle Daten der Frage gelö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ängen eines Textes an den Fragentext
/*!
\param strText Anzuhä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ä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äufigkeit ermitteln
static QString levelIconName(const unsigned uLevel);
//! Icon einer bestimmten Abfragehäufigkeit
static QIcon levelIcon(const unsigned uLevel);
//! Name einer bestimmten Abfragehä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äufigkeit
static unsigned waitDaysForRepeat (const unsigned uLevel);
protected:
CChapter *m_pParentChapter; //!< Zeiger auf das (Eltern-) Kapitel, zu dem die Frage gehö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üfung
QStringList m_strlGroups; //!< Liste der Klassen/Gruppen, zu denen diese Frage gehört
// learning
//! Durchmischte Antworten
/*! Die Liste enthä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äufigkeit
/*!
Stufe 0: sehr häufige ... Stufe 5: sehr seltene Abfrage
Die Abfragehä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

View File

@ -1,175 +1,175 @@
/***************************************************************************
* 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 "chapter.h"
#include "questionmodel.h"
#include <qtextdocument.h>
CQuestionModel::CQuestionModel(QObject *pParent) : QAbstractItemModel (pParent)
{
m_pChapter=0;
}
CQuestionModel::~CQuestionModel()
{
}
void CQuestionModel::onLanguageChanged()
{
headerDataChanged(Qt::Horizontal, 0, columnCount()-1);
}
void CQuestionModel::clear()
{
m_pChapter=0;
reset();
}
void CQuestionModel::setModelData (CChapter *pChapter)
{
m_pChapter = pChapter;
reset();
}
int CQuestionModel::columnCount (const QModelIndex & parent) const
{
Q_UNUSED(parent)
return 7;
}
QVariant CQuestionModel::data (const QModelIndex & index, int role) const
{
CQuestion *p;
QTextDocument t;
if (!index.isValid()) return QVariant();
p = (CQuestion*) index.internalPointer();
if (p == 0) return QVariant();
if (role == Qt::DisplayRole)
{
if (index.column() == 0)
return p->id();
else if (index.column() == 1)
return p->firstTextLine();
//return p->text();
else if (index.column() == 2)
return p->clickedCorrect();
else if (index.column() == 3)
return p->clickedWrong();
else if (index.column() == 4)
return p->levelText();
else if (index.column() == 5)
{
t.setHtml(p->lastClickedText());
return t.toPlainText();
}
else if (index.column() == 6)
{
t.setHtml(p->repeatDateText());
return t.toPlainText();
}
}
else if (role == Qt::DecorationRole)
{
if (index.column() == 4)
//return QIcon (QString(":/icons/16x16/level%1.png").arg(p->level()));
return p->levelIcon();
}
else if (role == Qt::ToolTipRole)
{
if (index.column() == 5)
return p->lastClickedTextExtended();
else if (index.column() == 6)
return p->repeatDateTextExtended();
/* if (index.column() == 4)
return "<img src='" + p->levelIconName() + "'> " + p->levelText();
*/ }
/* else if (role == Qt::WhatsThisRole)
{
if (index.column() == 4)
return QString("Was ist das?");
}
*/
return QVariant();
}
bool CQuestionModel::hasChildren (const QModelIndex & parent) const
{
if (parent.isValid()) return false;
return (m_pChapter != 0);
}
QVariant CQuestionModel::headerData (int section, Qt::Orientation orientation, int role) const
{
if (orientation == Qt::Vertical) return QVariant();
if (role == Qt::DisplayRole)
{
if (section == 0)
return tr("Kennung");
else if (section == 1)
return tr("Frage");
else if (section == 2)
return tr("R");
else if (section == 3)
return tr("F");
else if (section == 4)
return tr("Lernfortschritt");
else if (section == 5)
return tr("letzte Abfrage");
else if (section == 6)
return tr("Wiederholung");
}
/* else if (role == Qt::DecorationRole)
{
if (section == m_iColBookmarkFlag)
return QIcon (":/icons/16x16/bookmark.png");
}*/
else if (role == Qt::ToolTipRole)
{
if (section == 2)
return tr("Anzahl der richtigen Antworten");
else if (section == 3)
return tr("Anzahl der falschen Antworten");
}
return QVariant();
}
QModelIndex CQuestionModel::index (int row, int column, const QModelIndex & parent) const
{
CQuestion *p=0;
if (m_pChapter == 0 || parent.isValid() || row >= m_pChapter->countQuestion()) return QModelIndex();
p = m_pChapter->questionAt (row);
return createIndex (row, column, (void*)p);
}
QModelIndex CQuestionModel::parent (const QModelIndex & index) const
{
return QModelIndex();
}
int CQuestionModel::rowCount (const QModelIndex & parent) const
{
if (m_pChapter == 0 || parent.isValid()) return 0;
return m_pChapter->countQuestion();
}
/***************************************************************************
* 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 "chapter.h"
#include "questionmodel.h"
#include <qtextdocument.h>
CQuestionModel::CQuestionModel(QObject *pParent) : QAbstractItemModel (pParent)
{
m_pChapter=0;
}
CQuestionModel::~CQuestionModel()
{
}
void CQuestionModel::onLanguageChanged()
{
headerDataChanged(Qt::Horizontal, 0, columnCount()-1);
}
void CQuestionModel::clear()
{
m_pChapter=0;
reset();
}
void CQuestionModel::setModelData (CChapter *pChapter)
{
m_pChapter = pChapter;
reset();
}
int CQuestionModel::columnCount (const QModelIndex & parent) const
{
Q_UNUSED(parent)
return 7;
}
QVariant CQuestionModel::data (const QModelIndex & index, int role) const
{
CQuestion *p;
QTextDocument t;
if (!index.isValid()) return QVariant();
p = (CQuestion*) index.internalPointer();
if (p == 0) return QVariant();
if (role == Qt::DisplayRole)
{
if (index.column() == 0)
return p->id();
else if (index.column() == 1)
return p->firstTextLine();
//return p->text();
else if (index.column() == 2)
return p->clickedCorrect();
else if (index.column() == 3)
return p->clickedWrong();
else if (index.column() == 4)
return p->levelText();
else if (index.column() == 5)
{
t.setHtml(p->lastClickedText());
return t.toPlainText();
}
else if (index.column() == 6)
{
t.setHtml(p->repeatDateText());
return t.toPlainText();
}
}
else if (role == Qt::DecorationRole)
{
if (index.column() == 4)
//return QIcon (QString(":/icons/16x16/level%1.png").arg(p->level()));
return p->levelIcon();
}
else if (role == Qt::ToolTipRole)
{
if (index.column() == 5)
return p->lastClickedTextExtended();
else if (index.column() == 6)
return p->repeatDateTextExtended();
/* if (index.column() == 4)
return "<img src='" + p->levelIconName() + "'> " + p->levelText();
*/ }
/* else if (role == Qt::WhatsThisRole)
{
if (index.column() == 4)
return QString("Was ist das?");
}
*/
return QVariant();
}
bool CQuestionModel::hasChildren (const QModelIndex & parent) const
{
if (parent.isValid()) return false;
return (m_pChapter != 0);
}
QVariant CQuestionModel::headerData (int section, Qt::Orientation orientation, int role) const
{
if (orientation == Qt::Vertical) return QVariant();
if (role == Qt::DisplayRole)
{
if (section == 0)
return tr("Kennung");
else if (section == 1)
return tr("Frage");
else if (section == 2)
return tr("R");
else if (section == 3)
return tr("F");
else if (section == 4)
return tr("Lernfortschritt");
else if (section == 5)
return tr("letzte Abfrage");
else if (section == 6)
return tr("Wiederholung");
}
/* else if (role == Qt::DecorationRole)
{
if (section == m_iColBookmarkFlag)
return QIcon (":/icons/16x16/bookmark.png");
}*/
else if (role == Qt::ToolTipRole)
{
if (section == 2)
return tr("Anzahl der richtigen Antworten");
else if (section == 3)
return tr("Anzahl der falschen Antworten");
}
return QVariant();
}
QModelIndex CQuestionModel::index (int row, int column, const QModelIndex & parent) const
{
CQuestion *p=0;
if (m_pChapter == 0 || parent.isValid() || row >= m_pChapter->countQuestion()) return QModelIndex();
p = m_pChapter->questionAt (row);
return createIndex (row, column, (void*)p);
}
QModelIndex CQuestionModel::parent (const QModelIndex & index) const
{
return QModelIndex();
}
int CQuestionModel::rowCount (const QModelIndex & parent) const
{
if (m_pChapter == 0 || parent.isValid()) return 0;
return m_pChapter->countQuestion();
}

View File

@ -1,58 +1,58 @@
/***************************************************************************
* 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 QUESTIONMODEL_H
#define QUESTIONMODEL_H
#include <qabstractitemmodel.h>
class CChapter;
class CQuestionModel : public QAbstractItemModel
{
Q_OBJECT
public:
CQuestionModel(QObject *pParent=0);
~CQuestionModel();
void clear();
void setModelData (CChapter *pChapter);
public:
virtual int columnCount ( const QModelIndex & parent = QModelIndex() ) const;
virtual QVariant data ( const QModelIndex & index, int role = Qt::DisplayRole ) const;
virtual bool hasChildren (const QModelIndex & parent = QModelIndex()) const;
virtual QVariant headerData ( int section, Qt::Orientation orientation, int role = Qt::DisplayRole ) const;
virtual QModelIndex index (int row, int column, const QModelIndex & parent = QModelIndex()) const;
virtual QModelIndex parent ( const QModelIndex & index ) const;
virtual int rowCount ( const QModelIndex & parent = QModelIndex() ) const;
public slots:
void onLanguageChanged();
protected:
void recalcColumn();
protected:
CChapter *m_pChapter;
};
#endif
/***************************************************************************
* 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 QUESTIONMODEL_H
#define QUESTIONMODEL_H
#include <qabstractitemmodel.h>
class CChapter;
class CQuestionModel : public QAbstractItemModel
{
Q_OBJECT
public:
CQuestionModel(QObject *pParent=0);
~CQuestionModel();
void clear();
void setModelData (CChapter *pChapter);
public:
virtual int columnCount ( const QModelIndex & parent = QModelIndex() ) const;
virtual QVariant data ( const QModelIndex & index, int role = Qt::DisplayRole ) const;
virtual bool hasChildren (const QModelIndex & parent = QModelIndex()) const;
virtual QVariant headerData ( int section, Qt::Orientation orientation, int role = Qt::DisplayRole ) const;
virtual QModelIndex index (int row, int column, const QModelIndex & parent = QModelIndex()) const;
virtual QModelIndex parent ( const QModelIndex & index ) const;
virtual int rowCount ( const QModelIndex & parent = QModelIndex() ) const;
public slots:
void onLanguageChanged();
protected:
void recalcColumn();
protected:
CChapter *m_pChapter;
};
#endif

View File

@ -1,178 +1,178 @@
/***************************************************************************
* 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 "recentfiles.h"
#include <qmenu.h>
#include <qstringlist.h>
#include <qsettings.h>
CRecentFiles::CRecentFiles(QObject *pParent) : QObject(pParent)
{
m_actNoEntry = new QAction(this);
m_actSepTop = new QAction(this);
m_actSepTop->setSeparator(true);
m_actSepTop->setVisible(false);
m_actSepBottom = new QAction(this);
m_actSepBottom->setSeparator(true);
m_actSepBottom->setVisible(false);
m_showSeperator = SeperatorNone;
m_actNoEntry->setEnabled(false);
m_bShowNoEntry = true;
onLanguageChanged();
}
CRecentFiles::~CRecentFiles()
{
qDeleteAll(m_listActions);
}
void CRecentFiles::clear()
{
qDeleteAll(m_listActions);
m_listActions.clear();
}
void CRecentFiles::onLanguageChanged()
{
m_actNoEntry->setText(tr("No recent files"));
}
void CRecentFiles::create (const QString& strName, const unsigned uMaxCount)
{
QAction *pAct=0;
qDeleteAll(m_listActions);
m_listActions.clear();
m_strName = strName;
m_uMaxCount = uMaxCount;
for (unsigned u=0; u<uMaxCount; u++)
{
pAct = new QAction(this);
pAct->setVisible(false);
connect(pAct, SIGNAL(triggered()), this, SLOT(onRecentFile()));
m_listActions.append(pAct);
}
updateActions();
}
void CRecentFiles::insertToMenu(QMenu *pMenu, QAction *pBefore)
{
pMenu->insertAction(pBefore, m_actSepTop);
pMenu->insertAction(pBefore, m_actNoEntry);
pMenu->insertActions(pBefore, m_listActions);
pMenu->insertAction(pBefore, m_actSepBottom);
}
QString CRecentFiles::settingName() const
{
QString str = "RecentFileList";
if (!m_strName.isEmpty()) str += "_" + m_strName;
return str;
}
void CRecentFiles::onRecentFile()
{
QAction *action = qobject_cast<QAction *>(sender());
if (action)
loadFile(action->data().toString());
}
void CRecentFiles::setRecentFile(const QString& strFileName)
{
QSettings set;
QStringList strl = set.value(settingName()).toStringList();
strl.removeAll(strFileName);
strl.prepend(strFileName);
while ((unsigned)strl.size() > m_uMaxCount)
strl.removeLast();
set.setValue(settingName(), strl);
updateActions();
}
void CRecentFiles::removeFile(const QString& strFileName)
{
QSettings set;
QStringList strl = set.value(settingName()).toStringList();
strl.removeAll(strFileName);
set.setValue(settingName(), strl);
updateActions();
}
void CRecentFiles::removeAll()
{
QSettings set;
set.setValue(settingName(), QStringList());
updateActions();
}
void CRecentFiles::updateActions()
{
QSettings set;
QStringList strl = set.value(settingName()).toStringList();
unsigned uNumRecentFiles = qMin((unsigned)strl.size(), m_uMaxCount);
QString str;
m_actNoEntry->setVisible(m_bShowNoEntry && uNumRecentFiles == 0);
m_actSepTop->setVisible((m_showSeperator == SeperatorTop || m_showSeperator == SeperatorBoth) && uNumRecentFiles != 0);
m_actSepBottom->setVisible((m_showSeperator == SeperatorBottom || m_showSeperator == SeperatorBoth) && uNumRecentFiles != 0);
for (unsigned i=0; i<uNumRecentFiles; ++i)
{
str = tr("&%1 %2").arg(i + 1).arg(strl[i]);
m_listActions[i]->setText(str);
m_listActions[i]->setData(strl[i]);
m_listActions[i]->setVisible(true);
}
for (unsigned j=uNumRecentFiles; j<m_uMaxCount; ++j)
m_listActions[j]->setVisible(false);
}
QString CRecentFiles::recentFile(const int idx) const
{
QSettings set;
QStringList strl = set.value(settingName()).toStringList();
if (idx >= strl.size()) return QString();
return strl.at(idx);
}
void CRecentFiles::setShowNoEntry (const bool bShow)
{
QSettings set;
QStringList strl = set.value(settingName()).toStringList();
unsigned uNumRecentFiles = qMin((unsigned)strl.size(), m_uMaxCount);
m_bShowNoEntry = bShow;
m_actNoEntry->setVisible(m_bShowNoEntry && uNumRecentFiles == 0);
}
void CRecentFiles::setShowSeperator(const ShowSeperator show)
{
QSettings set;
QStringList strl = set.value(settingName()).toStringList();
unsigned uNumRecentFiles = qMin((unsigned)strl.size(), m_uMaxCount);
m_showSeperator = show;
m_actSepTop->setVisible((m_showSeperator == SeperatorTop || m_showSeperator == SeperatorBoth) && uNumRecentFiles != 0);
m_actSepBottom->setVisible((m_showSeperator == SeperatorBottom || m_showSeperator == SeperatorBoth) && uNumRecentFiles != 0);
}
/***************************************************************************
* 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 "recentfiles.h"
#include <qmenu.h>
#include <qstringlist.h>
#include <qsettings.h>
CRecentFiles::CRecentFiles(QObject *pParent) : QObject(pParent)
{
m_actNoEntry = new QAction(this);
m_actSepTop = new QAction(this);
m_actSepTop->setSeparator(true);
m_actSepTop->setVisible(false);
m_actSepBottom = new QAction(this);
m_actSepBottom->setSeparator(true);
m_actSepBottom->setVisible(false);
m_showSeperator = SeperatorNone;
m_actNoEntry->setEnabled(false);
m_bShowNoEntry = true;
onLanguageChanged();
}
CRecentFiles::~CRecentFiles()
{
qDeleteAll(m_listActions);
}
void CRecentFiles::clear()
{
qDeleteAll(m_listActions);
m_listActions.clear();
}
void CRecentFiles::onLanguageChanged()
{
m_actNoEntry->setText(tr("No recent files"));
}
void CRecentFiles::create (const QString& strName, const unsigned uMaxCount)
{
QAction *pAct=0;
qDeleteAll(m_listActions);
m_listActions.clear();
m_strName = strName;
m_uMaxCount = uMaxCount;
for (unsigned u=0; u<uMaxCount; u++)
{
pAct = new QAction(this);
pAct->setVisible(false);
connect(pAct, SIGNAL(triggered()), this, SLOT(onRecentFile()));
m_listActions.append(pAct);
}
updateActions();
}
void CRecentFiles::insertToMenu(QMenu *pMenu, QAction *pBefore)
{
pMenu->insertAction(pBefore, m_actSepTop);
pMenu->insertAction(pBefore, m_actNoEntry);
pMenu->insertActions(pBefore, m_listActions);
pMenu->insertAction(pBefore, m_actSepBottom);
}
QString CRecentFiles::settingName() const
{
QString str = "RecentFileList";
if (!m_strName.isEmpty()) str += "_" + m_strName;
return str;
}
void CRecentFiles::onRecentFile()
{
QAction *action = qobject_cast<QAction *>(sender());
if (action)
loadFile(action->data().toString());
}
void CRecentFiles::setRecentFile(const QString& strFileName)
{
QSettings set;
QStringList strl = set.value(settingName()).toStringList();
strl.removeAll(strFileName);
strl.prepend(strFileName);
while ((unsigned)strl.size() > m_uMaxCount)
strl.removeLast();
set.setValue(settingName(), strl);
updateActions();
}
void CRecentFiles::removeFile(const QString& strFileName)
{
QSettings set;
QStringList strl = set.value(settingName()).toStringList();
strl.removeAll(strFileName);
set.setValue(settingName(), strl);
updateActions();
}
void CRecentFiles::removeAll()
{
QSettings set;
set.setValue(settingName(), QStringList());
updateActions();
}
void CRecentFiles::updateActions()
{
QSettings set;
QStringList strl = set.value(settingName()).toStringList();
unsigned uNumRecentFiles = qMin((unsigned)strl.size(), m_uMaxCount);
QString str;
m_actNoEntry->setVisible(m_bShowNoEntry && uNumRecentFiles == 0);
m_actSepTop->setVisible((m_showSeperator == SeperatorTop || m_showSeperator == SeperatorBoth) && uNumRecentFiles != 0);
m_actSepBottom->setVisible((m_showSeperator == SeperatorBottom || m_showSeperator == SeperatorBoth) && uNumRecentFiles != 0);
for (unsigned i=0; i<uNumRecentFiles; ++i)
{
str = tr("&%1 %2").arg(i + 1).arg(strl[i]);
m_listActions[i]->setText(str);
m_listActions[i]->setData(strl[i]);
m_listActions[i]->setVisible(true);
}
for (unsigned j=uNumRecentFiles; j<m_uMaxCount; ++j)
m_listActions[j]->setVisible(false);
}
QString CRecentFiles::recentFile(const int idx) const
{
QSettings set;
QStringList strl = set.value(settingName()).toStringList();
if (idx >= strl.size()) return QString();
return strl.at(idx);
}
void CRecentFiles::setShowNoEntry (const bool bShow)
{
QSettings set;
QStringList strl = set.value(settingName()).toStringList();
unsigned uNumRecentFiles = qMin((unsigned)strl.size(), m_uMaxCount);
m_bShowNoEntry = bShow;
m_actNoEntry->setVisible(m_bShowNoEntry && uNumRecentFiles == 0);
}
void CRecentFiles::setShowSeperator(const ShowSeperator show)
{
QSettings set;
QStringList strl = set.value(settingName()).toStringList();
unsigned uNumRecentFiles = qMin((unsigned)strl.size(), m_uMaxCount);
m_showSeperator = show;
m_actSepTop->setVisible((m_showSeperator == SeperatorTop || m_showSeperator == SeperatorBoth) && uNumRecentFiles != 0);
m_actSepBottom->setVisible((m_showSeperator == SeperatorBottom || m_showSeperator == SeperatorBoth) && uNumRecentFiles != 0);
}

View File

@ -1,82 +1,82 @@
/***************************************************************************
* 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. *
***************************************************************************/
#pragma once
#include <qlist.h>
#include <qaction.h>
#include <qstring.h>
class QMenu;
class CRecentFiles : public QObject
{
Q_OBJECT
public:
enum ShowSeperator { SeperatorNone, SeperatorTop, SeperatorBottom, SeperatorBoth };
CRecentFiles(QObject *pParent=0);
~CRecentFiles();
void clear();
void create (const QString& strName, const unsigned uMaxCount=4);
void insertToMenu(QMenu *pMenu, QAction *pBefore=0);
inline unsigned maxCount() const { return m_uMaxCount; }
inline QString name() const { return m_strName; }
void setRecentFile(const QString& strFileName);
void removeFile(const QString& strFileName);
void removeAll();
QString recentFile(const int idx) const;
void setShowNoEntry (const bool bShow);
inline bool showNoEntry() const { return m_bShowNoEntry; }
void setShowSeperator(const ShowSeperator show);
inline ShowSeperator showSeperator() const { return m_showSeperator; }
public slots:
void onLanguageChanged();
protected slots:
void onRecentFile();
signals:
void loadFile(QString strFile);
protected:
QString settingName() const;
void updateActions();
protected:
QString m_strName;
unsigned m_uMaxCount;
QList<QAction*> m_listActions;
QAction *m_actNoEntry;
QAction *m_actSepTop;
QAction *m_actSepBottom;
bool m_bShowNoEntry;
ShowSeperator m_showSeperator;
};
/***************************************************************************
* 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. *
***************************************************************************/
#pragma once
#include <qlist.h>
#include <qaction.h>
#include <qstring.h>
class QMenu;
class CRecentFiles : public QObject
{
Q_OBJECT
public:
enum ShowSeperator { SeperatorNone, SeperatorTop, SeperatorBottom, SeperatorBoth };
CRecentFiles(QObject *pParent=0);
~CRecentFiles();
void clear();
void create (const QString& strName, const unsigned uMaxCount=4);
void insertToMenu(QMenu *pMenu, QAction *pBefore=0);
inline unsigned maxCount() const { return m_uMaxCount; }
inline QString name() const { return m_strName; }
void setRecentFile(const QString& strFileName);
void removeFile(const QString& strFileName);
void removeAll();
QString recentFile(const int idx) const;
void setShowNoEntry (const bool bShow);
inline bool showNoEntry() const { return m_bShowNoEntry; }
void setShowSeperator(const ShowSeperator show);
inline ShowSeperator showSeperator() const { return m_showSeperator; }
public slots:
void onLanguageChanged();
protected slots:
void onRecentFile();
signals:
void loadFile(QString strFile);
protected:
QString settingName() const;
void updateActions();
protected:
QString m_strName;
unsigned m_uMaxCount;
QList<QAction*> m_listActions;
QAction *m_actNoEntry;
QAction *m_actSepTop;
QAction *m_actSepBottom;
bool m_bShowNoEntry;
ShowSeperator m_showSeperator;
};

106
tools.cpp
View File

@ -1,53 +1,53 @@
/***************************************************************************
* 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 "tools.h"
#include <qpainter.h>
#include <qpalette.h>
unsigned afu_random (const unsigned uMin, const unsigned uMax)
{
unsigned u=0;
float f = (float) (uMax-uMin+1) / (float) RAND_MAX;
u = (unsigned) ((float) rand () * f) + uMin;;
return (u);
}
QDomElement createXmlTextElement(const QString& strName, const QString& strText, QDomDocument& doc)
{
QDomElement elem = doc.createElement(strName);
elem.appendChild(doc.createTextNode(strText));
return elem;
}
QPixmap createProgressBar (int w, int h, double dPercent)
{
QPixmap pix(w,h);
QPainter p(&pix);
pix.fill(QPalette().color(QPalette::Dark));
p.setBrush(Qt::blue);
p.setPen(Qt::blue);
if (dPercent != 0.0)
p.drawRect(0, 0, (int)(((double)w)*dPercent), h);
return pix;
}
/***************************************************************************
* 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 "tools.h"
#include <qpainter.h>
#include <qpalette.h>
unsigned afu_random (const unsigned uMin, const unsigned uMax)
{
unsigned u=0;
float f = (float) (uMax-uMin+1) / (float) RAND_MAX;
u = (unsigned) ((float) rand () * f) + uMin;;
return (u);
}
QDomElement createXmlTextElement(const QString& strName, const QString& strText, QDomDocument& doc)
{
QDomElement elem = doc.createElement(strName);
elem.appendChild(doc.createTextNode(strText));
return elem;
}
QPixmap createProgressBar (int w, int h, double dPercent)
{
QPixmap pix(w,h);
QPainter p(&pix);
pix.fill(QPalette().color(QPalette::Dark));
p.setBrush(Qt::blue);
p.setPen(Qt::blue);
if (dPercent != 0.0)
p.drawRect(0, 0, (int)(((double)w)*dPercent), h);
return pix;
}

64
tools.h
View File

@ -1,32 +1,32 @@
/***************************************************************************
* 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 TOOLS_H
#define TOOLS_H
#include <qdom.h>
#include <qpixmap.h>
unsigned afu_random (const unsigned uMin, const unsigned uMax);
QDomElement createXmlTextElement(const QString& strName, const QString& strText, QDomDocument& doc);
QPixmap createProgressBar (int w, int h, double dPercent);
#endif
/***************************************************************************
* 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 TOOLS_H
#define TOOLS_H
#include <qdom.h>
#include <qpixmap.h>
unsigned afu_random (const unsigned uMin, const unsigned uMax);
QDomElement createXmlTextElement(const QString& strName, const QString& strText, QDomDocument& doc);
QPixmap createProgressBar (int w, int h, double dPercent);
#endif