Convert CRLF to Unix newlines
This commit is contained in:
parent
9898b3404a
commit
1010914f41
238
answer.cpp
238
answer.cpp
|
@ -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("< 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("< 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
284
answer.h
|
@ -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
|
||||
|
|
866
catalog.cpp
866
catalog.cpp
|
@ -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
240
catalog.h
|
@ -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
|
||||
|
|
410
catalogmodel.cpp
410
catalogmodel.cpp
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
110
catalogmodel.h
110
catalogmodel.h
|
@ -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
|
||||
|
||||
|
|
1616
chapter.cpp
1616
chapter.cpp
File diff suppressed because it is too large
Load Diff
484
chapter.h
484
chapter.h
|
@ -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
|
||||
|
|
368
chaptermodel.cpp
368
chaptermodel.cpp
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
120
chaptermodel.h
120
chaptermodel.h
|
@ -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
|
||||
|
|
600
dlgexam.cpp
600
dlgexam.cpp
|
@ -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
162
dlgexam.h
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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')) : "--");
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
870
dlglearn.cpp
870
dlglearn.cpp
|
@ -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()));
|
||||
}
|
||||
|
|
168
dlglearn.h
168
dlglearn.h
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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
196
error.cpp
|
@ -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
156
error.h
|
@ -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
612
exam.cpp
|
@ -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
284
exam.h
|
@ -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
|
||||
|
||||
|
|
168
helper.cpp
168
helper.cpp
|
@ -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'> </td></tr>";
|
||||
str += "</table></p>";
|
||||
*/
|
||||
|
||||
str += "<p>" + text() + "</p>"; //"<p><i><font size=-1>" + author() + " " + 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'> </td></tr>";
|
||||
str += "</table></p>";
|
||||
*/
|
||||
|
||||
str += "<p>" + text() + "</p>"; //"<p><i><font size=-1>" + author() + " " + date() + "</font></i></p>";
|
||||
return (str);
|
||||
}
|
||||
|
|
142
helper.h
142
helper.h
|
@ -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
|
||||
|
|
84
main.cpp
84
main.cpp
|
@ -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();
|
||||
}
|
||||
|
|
1638
mainwindow.cpp
1638
mainwindow.cpp
File diff suppressed because it is too large
Load Diff
182
mainwindow.h
182
mainwindow.h
|
@ -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
|
||||
|
||||
|
|
934
osziparchive.cpp
934
osziparchive.cpp
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
310
osziparchive.h
310
osziparchive.h
|
@ -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
|
||||
|
||||
|
|
852
plotwidget.cpp
852
plotwidget.cpp
|
@ -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());
|
||||
}
|
||||
|
|
430
plotwidget.h
430
plotwidget.h
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
1418
question.cpp
1418
question.cpp
File diff suppressed because it is too large
Load Diff
494
question.h
494
question.h
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
116
questionmodel.h
116
questionmodel.h
|
@ -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
|
||||
|
|
356
recentfiles.cpp
356
recentfiles.cpp
|
@ -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);
|
||||
}
|
||||
|
|
164
recentfiles.h
164
recentfiles.h
|
@ -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
106
tools.cpp
|
@ -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
64
tools.h
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue