Convert CRLF to Unix newlines

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

View File

@ -1,119 +1,119 @@
/***************************************************************************
* Copyright (C) 2003-2007 by Oliver Saal *
* osaal@gmx.de *
* http://www.oliver-saal.de/software/afutrainer/ *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include "answer.h"
#include <qcoreapplication.h>
CAnswer::CAnswer(const QString& strText, const bool bCorrect)
{
m_strText = strText;
m_bIsCorrect = bCorrect;
}
void CAnswer::clear()
{
m_strText.clear();
m_bIsCorrect = false;
}
QString CAnswerClicked::tr (const char *sourceText, const char *comment)
{
return QCoreApplication::translate("CAnswerClicked", sourceText, comment);
}
void CAnswerClicked::clear()
{
m_dt = QDateTime::currentDateTime();
m_uAnswer=0;
m_uNeededTime=0;
}
bool CAnswerClicked::operator < (const CAnswerClicked& ac) const
{
return m_dt < ac.m_dt;
}
QString CAnswerClicked::answerText(const unsigned uAnswer)
{
QString strRet;
for (int i=0; i<32; i++)
{
if (uAnswer & (1<<i))
{
if (!strRet.isEmpty())
strRet += ", ";
strRet += QChar('A' + i);
}
}
return strRet;
}
QString CAnswerClicked::answerText() const
{
return answerText(m_uAnswer);
}
QString CAnswerClicked::neededTimeText() const
{
if (m_uNeededTime < 1000)
return tr("&lt; 1 sec");
else if (m_uNeededTime < 60000)
return tr("%1 sec").arg(m_uNeededTime / 1000);
else
return tr("%1:%2 min").arg(m_uNeededTime / 60000).arg((m_uNeededTime / 1000) % 60, 2, 10, QChar('0'));
}
bool CAnswerClicked::isCorrect(const QList<CAnswer>& listAnswer) const
{
unsigned uMask=0;
for (int i=0; i<listAnswer.size(); i++)
{
if (listAnswer.at(i).isCorrect())
uMask |= (1<<i);
}
return (m_uAnswer == uMask);
}
bool CAnswerClicked::load (QDomElement elem)
{
bool bOk=false;
if (elem.tagName() != "answer_clicked") return false;
m_dt = QDateTime::fromString (elem.attribute("datetime"), Qt::ISODate);
if (!m_dt.isValid()) return false;
m_uAnswer = elem.attribute("answer_code").toUInt(&bOk);
if (!bOk) return false;
m_uNeededTime = elem.attribute("needed_time").toUInt(&bOk);
if (!bOk) return false;
return true;
}
void CAnswerClicked::save (QDomElement& parent, QDomDocument& doc) const
{
QDomElement elem = doc.createElement("answer_clicked");
elem.setAttribute("datetime", m_dt.toString(Qt::ISODate));
elem.setAttribute("answer_code", QString("%1").arg(m_uAnswer));
elem.setAttribute("needed_time", QString("%1").arg(m_uNeededTime));
parent.appendChild(elem);
}
/***************************************************************************
* Copyright (C) 2003-2007 by Oliver Saal *
* osaal@gmx.de *
* http://www.oliver-saal.de/software/afutrainer/ *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include "answer.h"
#include <qcoreapplication.h>
CAnswer::CAnswer(const QString& strText, const bool bCorrect)
{
m_strText = strText;
m_bIsCorrect = bCorrect;
}
void CAnswer::clear()
{
m_strText.clear();
m_bIsCorrect = false;
}
QString CAnswerClicked::tr (const char *sourceText, const char *comment)
{
return QCoreApplication::translate("CAnswerClicked", sourceText, comment);
}
void CAnswerClicked::clear()
{
m_dt = QDateTime::currentDateTime();
m_uAnswer=0;
m_uNeededTime=0;
}
bool CAnswerClicked::operator < (const CAnswerClicked& ac) const
{
return m_dt < ac.m_dt;
}
QString CAnswerClicked::answerText(const unsigned uAnswer)
{
QString strRet;
for (int i=0; i<32; i++)
{
if (uAnswer & (1<<i))
{
if (!strRet.isEmpty())
strRet += ", ";
strRet += QChar('A' + i);
}
}
return strRet;
}
QString CAnswerClicked::answerText() const
{
return answerText(m_uAnswer);
}
QString CAnswerClicked::neededTimeText() const
{
if (m_uNeededTime < 1000)
return tr("&lt; 1 sec");
else if (m_uNeededTime < 60000)
return tr("%1 sec").arg(m_uNeededTime / 1000);
else
return tr("%1:%2 min").arg(m_uNeededTime / 60000).arg((m_uNeededTime / 1000) % 60, 2, 10, QChar('0'));
}
bool CAnswerClicked::isCorrect(const QList<CAnswer>& listAnswer) const
{
unsigned uMask=0;
for (int i=0; i<listAnswer.size(); i++)
{
if (listAnswer.at(i).isCorrect())
uMask |= (1<<i);
}
return (m_uAnswer == uMask);
}
bool CAnswerClicked::load (QDomElement elem)
{
bool bOk=false;
if (elem.tagName() != "answer_clicked") return false;
m_dt = QDateTime::fromString (elem.attribute("datetime"), Qt::ISODate);
if (!m_dt.isValid()) return false;
m_uAnswer = elem.attribute("answer_code").toUInt(&bOk);
if (!bOk) return false;
m_uNeededTime = elem.attribute("needed_time").toUInt(&bOk);
if (!bOk) return false;
return true;
}
void CAnswerClicked::save (QDomElement& parent, QDomDocument& doc) const
{
QDomElement elem = doc.createElement("answer_clicked");
elem.setAttribute("datetime", m_dt.toString(Qt::ISODate));
elem.setAttribute("answer_code", QString("%1").arg(m_uAnswer));
elem.setAttribute("needed_time", QString("%1").arg(m_uNeededTime));
parent.appendChild(elem);
}

284
answer.h
View File

@ -1,142 +1,142 @@
/***************************************************************************
* Copyright (C) 2003-2007 by Oliver Saal *
* osaal@gmx.de *
* http://www.oliver-saal.de/software/afutrainer/ *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#ifndef ANSWER_H
#define ANSWER_H
#include <qstring.h>
#include <qdom.h>
#include <qlist.h>
#include <qdatetime.h>
//! Die Klasse CAnswer speichert eine einzelne Antwort auf eine Frage
/*!
Das Schreiben und Lesen von XML-Daten wird von der Klasse CQuestion übernommen
*/
class CAnswer
{
public:
//! Standard-Konstruktor
/*! Initialisiert die Klasse, indem die Funktion clear() aufgerufen wird. */
CAnswer() { clear(); }
//! Konstruktor inkl. setzen eines Textes und ob die Antwort richtig ist
/*!
\param strText Antworttext
\param bCorrect true: Die Antwort ist korrekt
\sa m_strText, m_bIsCorrect
*/
CAnswer(const QString& strText, const bool bCorrect);
//! Standard-Destruktor
/*! In der Standard-Implementierung tut der Destruktor nichts. */
~CAnswer() {}
//! Zurücksetzen aller Werte
/*! Es werden alle Daten der Antwort gelöscht. */
void clear();
//! Überprüfen, ob die Klasse eine Antwort enthält
/*! \return true: Die Klasse ist leer und enthält keine Antwort */
inline bool isEmpty() const { return m_strText.isEmpty(); }
//! Auslesen, ob diese Antwort richtig ist
/*! \return true: Die Antwort ist richtig */
inline bool isCorrect() const { return m_bIsCorrect; }
//! Auslesen des Antworttextes
/*! \return Antworttext */
inline QString text() const { return m_strText; }
//! Setzen, ob diese Antwort richtig ist
/*!
\param bCorrect true: Die Antwort ist korrekt
\sa m_bIsCorrect
*/
inline void setCorrect (const bool bCorrect) { m_bIsCorrect = bCorrect; }
//! Setzen des Antworttextes
/*!
\param strText Antworttext
\sa m_strText
*/
inline void setText(const QString& strText) { m_strText = strText; }
//! Anhängen eines Textes an den Antworttext
/*!
\param strText Anzuhängender Text
\sa m_strText
*/
inline void appendText(const QString& strText) { m_strText += strText; }
protected:
//! Antworttext
/*!
Der Antworttext darf HTML-Code und HTML-Verweise auf Grafiken/Bilder enthalten. Bei Verweisen ist zu achten, dass kein Verzeichnis angegeben werden darf!
Default: leer
*/
QString m_strText;
//! Richtige oder falsche Antwort
/*! Default: false */
bool m_bIsCorrect;
};
//! Die Klasse CAnswerClicked speichert eine einzelne Beantwortung des Benutzers
/*!
*/
class CAnswerClicked
{
public:
//! Standard-Konstruktor
/*! Initialisiert die Klasse, indem die Funktion clear() aufgerufen wird. */
CAnswerClicked () { clear(); }
CAnswerClicked (const unsigned uAnswer, const unsigned uNeededTime)
{ m_uAnswer = uAnswer; m_dt = QDateTime::currentDateTime(); m_uNeededTime = uNeededTime; }
//! Standard-Destruktor
/*! In der Standard-Implementierung tut der Destruktor nichts. */
~CAnswerClicked () {}
//! Zurücksetzen aller Werte
/*! Es werden alle Daten auf Default-Werte zurückgesetzt. */
void clear();
inline QDateTime dateTime() const { return m_dt; }
inline unsigned neededTime() const { return m_uNeededTime; }
inline unsigned answer() const { return m_uAnswer; }
static QString answerText(const unsigned uAnswer);
QString answerText() const;
QString neededTimeText() const;
bool isCorrect(const QList<CAnswer>& listAnswer) const;
bool load (QDomElement elem);
void save (QDomElement& parent, QDomDocument& doc) const;
static QString tr (const char *sourceText, const char *comment=0);
bool operator < (const CAnswerClicked& ac) const;
protected:
QDateTime m_dt; //!< Zeitstempel der Antwort
unsigned m_uAnswer; //!< Antwort-Bitmaske
unsigned m_uNeededTime; //!< Benötigte Zeit in ms
};
#endif
/***************************************************************************
* Copyright (C) 2003-2007 by Oliver Saal *
* osaal@gmx.de *
* http://www.oliver-saal.de/software/afutrainer/ *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#ifndef ANSWER_H
#define ANSWER_H
#include <qstring.h>
#include <qdom.h>
#include <qlist.h>
#include <qdatetime.h>
//! Die Klasse CAnswer speichert eine einzelne Antwort auf eine Frage
/*!
Das Schreiben und Lesen von XML-Daten wird von der Klasse CQuestion übernommen
*/
class CAnswer
{
public:
//! Standard-Konstruktor
/*! Initialisiert die Klasse, indem die Funktion clear() aufgerufen wird. */
CAnswer() { clear(); }
//! Konstruktor inkl. setzen eines Textes und ob die Antwort richtig ist
/*!
\param strText Antworttext
\param bCorrect true: Die Antwort ist korrekt
\sa m_strText, m_bIsCorrect
*/
CAnswer(const QString& strText, const bool bCorrect);
//! Standard-Destruktor
/*! In der Standard-Implementierung tut der Destruktor nichts. */
~CAnswer() {}
//! Zurücksetzen aller Werte
/*! Es werden alle Daten der Antwort gelöscht. */
void clear();
//! Überprüfen, ob die Klasse eine Antwort enthält
/*! \return true: Die Klasse ist leer und enthält keine Antwort */
inline bool isEmpty() const { return m_strText.isEmpty(); }
//! Auslesen, ob diese Antwort richtig ist
/*! \return true: Die Antwort ist richtig */
inline bool isCorrect() const { return m_bIsCorrect; }
//! Auslesen des Antworttextes
/*! \return Antworttext */
inline QString text() const { return m_strText; }
//! Setzen, ob diese Antwort richtig ist
/*!
\param bCorrect true: Die Antwort ist korrekt
\sa m_bIsCorrect
*/
inline void setCorrect (const bool bCorrect) { m_bIsCorrect = bCorrect; }
//! Setzen des Antworttextes
/*!
\param strText Antworttext
\sa m_strText
*/
inline void setText(const QString& strText) { m_strText = strText; }
//! Anhängen eines Textes an den Antworttext
/*!
\param strText Anzuhängender Text
\sa m_strText
*/
inline void appendText(const QString& strText) { m_strText += strText; }
protected:
//! Antworttext
/*!
Der Antworttext darf HTML-Code und HTML-Verweise auf Grafiken/Bilder enthalten. Bei Verweisen ist zu achten, dass kein Verzeichnis angegeben werden darf!
Default: leer
*/
QString m_strText;
//! Richtige oder falsche Antwort
/*! Default: false */
bool m_bIsCorrect;
};
//! Die Klasse CAnswerClicked speichert eine einzelne Beantwortung des Benutzers
/*!
*/
class CAnswerClicked
{
public:
//! Standard-Konstruktor
/*! Initialisiert die Klasse, indem die Funktion clear() aufgerufen wird. */
CAnswerClicked () { clear(); }
CAnswerClicked (const unsigned uAnswer, const unsigned uNeededTime)
{ m_uAnswer = uAnswer; m_dt = QDateTime::currentDateTime(); m_uNeededTime = uNeededTime; }
//! Standard-Destruktor
/*! In der Standard-Implementierung tut der Destruktor nichts. */
~CAnswerClicked () {}
//! Zurücksetzen aller Werte
/*! Es werden alle Daten auf Default-Werte zurückgesetzt. */
void clear();
inline QDateTime dateTime() const { return m_dt; }
inline unsigned neededTime() const { return m_uNeededTime; }
inline unsigned answer() const { return m_uAnswer; }
static QString answerText(const unsigned uAnswer);
QString answerText() const;
QString neededTimeText() const;
bool isCorrect(const QList<CAnswer>& listAnswer) const;
bool load (QDomElement elem);
void save (QDomElement& parent, QDomDocument& doc) const;
static QString tr (const char *sourceText, const char *comment=0);
bool operator < (const CAnswerClicked& ac) const;
protected:
QDateTime m_dt; //!< Zeitstempel der Antwort
unsigned m_uAnswer; //!< Antwort-Bitmaske
unsigned m_uNeededTime; //!< Benötigte Zeit in ms
};
#endif

View File

@ -1,433 +1,433 @@
/***************************************************************************
* Copyright (C) 2003-2007 by Oliver Saal *
* osaal@gmx.de *
* http://www.oliver-saal.de/software/afutrainer/ *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include "catalog.h"
#include "osziparchive.h"
#include "tools.h"
#include <qdir.h>
#include <qfile.h>
#include <qmessagebox.h>
#include <qtextstream.h>
#include <qvariant.h>
CCatalog::~CCatalog()
{
qDeleteAll(m_listFiles);
}
void CCatalog::clear()
{
CChapter::clear();
m_bMixAnswers = true;
m_bSort = false;
m_strFileName.clear();
m_listHint.clear();
m_strUniqueName.clear();
qDeleteAll(m_listFiles);
m_strPublisher.clear();
m_strContact.clear();
m_dateValidFrom = QDate();
m_dateValidUntil = QDate();
m_dateCreated = QDate();
m_datePublished = QDate();
m_strVersion.clear();
m_listExam.clear();
m_listExamStat.clear();
}
bool CCatalog::isEmpty()
{
return m_strText.isEmpty();
}
bool CCatalog::isValid() const
{
if (m_dateValidFrom.isValid() && QDate::currentDate() < m_dateValidFrom) return false;
if (m_dateValidUntil.isValid() && QDate::currentDate() > m_dateValidUntil) return false;
return true;
}
bool CCatalog::hasHints (const QString& strQuestionId) const
{
for (int i=0; i<m_listHint.size(); i++)
{
if (m_listHint.at(i).hasQuestion(strQuestionId)) return true;
}
return false;
}
QString CCatalog::hintText (const QString& strQuestionId) const
{
QString str;
if (strQuestionId.isEmpty()) return QString();
for (int i=0; i<m_listHint.size(); i++)
{
if (m_listHint.at(i).hasQuestion(strQuestionId))
str += m_listHint[i].showText();
}
return str;
}
bool CCatalog::load (const QString& strFileName, QWidget *pParent)
{
QDomDocument doc;
QDomElement elemRoot, e;
QDomNode n;
QString str, strXML;
int iErrLine, iErrCol;
double dVersion=0.0;
CChapter *pChapter=0;
if (strFileName.right(3).toLower() != "aqz") return false;
CZipArchive zip;
if (!zip.open(strFileName, CZipArchive::OpenReadOnly))
{
QMessageBox::critical(pParent, pParent->tr("Datei-Fehler"), pParent->tr("Konnte folgende Datei nicht zum Lesen öffnen:\n%1").arg(strFileName));
return false;
}
// Fragen entpacken
CZipFile *pzfQuestions = zip.findFile("questions.xml");
if (pzfQuestions == 0)
{
QMessageBox::critical(pParent, pParent->tr("Datei-Fehler"), pParent->tr("Konnte in der Datei '%1' keine Fragen finden.").arg(strFileName));
return false;
}
strXML = QString::fromUtf8(pzfQuestions->deflateToByteArray());
clear();
// Alle Grafiken in temp. Dateien entpacken
// pParent->setCursor(Qt::WaitCursor);
for (int i=0; i<zip.fileCount(); i++)
{
CZipFile *pzf = zip.fileAt(i);
str = pzf->fileName().right(3);
if (str == "png" || str == "jpg" || str == "gif" || str == "bmp")
{ // Datei entpacken und Pfade im XML anpassen
str = QDir::temp().absoluteFilePath(pzf->fileName()+".XXXXXX");
QTemporaryFile *ptf = new QTemporaryFile(str);
ptf->open();
str = ptf->fileName();
pzf->deflateToFile(*ptf);
ptf->close();
m_listFiles.append(ptf);
strXML.replace(pzf->fileName(), str);
//qDebug ("Deflating %s to %s", qPrintable(pzf->fileName()), qPrintable(str));
}
}
// pParent->setCursor(Qt::ArrowCursor);
if (!doc.setContent(strXML, true, &str, &iErrLine, &iErrCol))
{
QMessageBox::critical(pParent, pParent->tr("XML-Fehler"), pParent->tr("Fragenkatalog: ") + strFileName + "\n" + str + "\n" + QString (pParent->tr("Zeile: %1 Spalte %2")).arg(iErrLine).arg(iErrCol));
return false;
}
elemRoot = doc.documentElement ();
if (elemRoot.tagName() != "aqdf")
{
QMessageBox::critical(pParent, pParent->tr("Datei-Fehler"), pParent->tr("Unbekanntes XML-Datenformat '%1'.").arg(elemRoot.tagName()));
return false;
}
//m_strText = elemRoot.attribute ("name");
m_dateCreated = QDate::fromString(elemRoot.attribute("created"), Qt::ISODate);
dVersion = elemRoot.attribute("version").toDouble();
if (dVersion != 1.0)
{
QMessageBox::information(pParent, pParent->tr("Information"), pParent->tr("Kann die Dateiversion %1 des Fragenkatalogs '%2' nicht lesen.").arg(dVersion).arg(strFileName));
return false;
}
n = elemRoot.firstChild();
while (!n.isNull())
{
if (n.isElement ())
{
e = n.toElement ();
if (e.tagName() == QString ("chapter"))
{
pChapter = new CChapter();
if (pChapter->load (e))
appendChapter(pChapter);
else
delete pChapter;
}
else if (e.tagName() == QString ("exam"))
{
CExam exam;
if (exam.load(e)) m_listExam.append(exam);
}
else if (e.tagName () == "hint")
{
CHint hint;
if (hint.load (e))
m_listHint.append (hint);
}
else if (e.tagName () == "title")
{
m_strText = e.text();
m_strUniqueName = e.attribute("unique");
}
else if (e.tagName () == "comment")
m_strComment = e.text();
else if (e.tagName () == "contact")
m_strContact = e.text();
else if (e.tagName () == "publisher")
m_strPublisher = e.text();
else if (e.tagName() == "valid")
{
m_dateValidFrom = QDate::fromString(e.attribute("from"), Qt::ISODate);
m_dateValidUntil = QDate::fromString(e.attribute("until"), Qt::ISODate);
}
else if (e.tagName() == "version")
{
m_datePublished = QDate::fromString(e.attribute("published"), Qt::ISODate);
m_strVersion = e.text();
}
else if (e.tagName() == "options")
{
m_bMixAnswers = QVariant(e.attribute("mixanswers", "true")).toBool();
m_bSort = QVariant(e.attribute("sort", "false")).toBool();
}
}
n = n.nextSibling();
}
if (m_strUniqueName.isEmpty())
m_strUniqueName = QDir(strFileName).dirName();
if (m_bSort) sortAll();
loadStatistic (pParent);
updateStatistic();
m_strFileName = strFileName;
return true;
}
bool CCatalog::save (const QString& strFileName, QWidget *pParent)
{
QFile file (strFileName);
if (strFileName.isEmpty()) return false;
if (!file.open(QIODevice::WriteOnly))
{
QMessageBox::critical(pParent, QString(pParent->tr("Datei-Fehler")), pParent->tr("Konnte folgende Datei nicht zum Schreiben öffnen:\n")+strFileName);
return false;
}
QTextStream out(&file);
QDomDocument doc("afutrainer");
QDomElement elemRoot = doc.createElement("afutrainer");
//elemRoot.setAttribute("name", name());
elemRoot.setAttribute("version", 3.0);
elemRoot.setAttribute("created", QDate::currentDate().toString(Qt::ISODate));
doc.appendChild(elemRoot);
// save unique name
QDomElement elemTitle = createXmlTextElement("title", name(), doc);
elemTitle.setAttribute("unique", m_strUniqueName);
elemRoot.appendChild (elemTitle);
// save comment
if (!m_strComment.isEmpty())
elemRoot.appendChild (createXmlTextElement("comment", m_strComment, doc));
// save contact
if (!m_strContact.isEmpty())
elemRoot.appendChild (createXmlTextElement("contact", m_strContact, doc));
// save publisher
if (!m_strPublisher.isEmpty())
elemRoot.appendChild (createXmlTextElement("publisher", m_strPublisher, doc));
// save version
QDomElement elemVersion = createXmlTextElement("version", m_strVersion, doc);
elemVersion.setAttribute("published", m_datePublished.toString(Qt::ISODate));
elemRoot.appendChild(elemVersion);
// save dates
if (m_dateValidFrom.isValid() || m_dateValidUntil.isValid())
{
QDomElement elemValid = doc.createElement("valid");
elemValid.setAttribute("from", m_dateValidFrom.toString(Qt::ISODate));
elemValid.setAttribute("until", m_dateValidUntil.toString(Qt::ISODate));
elemRoot.appendChild(elemValid);
}
// TODO: save tests
// save chapters
for (int i=0; i<m_listChapter.size(); i++)
m_listChapter[i]->save(elemRoot, doc);
// save helpers
for (int i=0; i<m_listHint.size(); i++)
m_listHint[i].save(elemRoot, doc);
out << doc.toString();
m_strFileName = strFileName;
return true;
}
QString CCatalog::statisticFileName() const
{
QDir dir;
QString str = dir.homePath()+QString("/.afutrainer/") + m_strUniqueName + QString(".stat.xml");
Q_ASSERT(!m_strUniqueName.isEmpty());
return (str);
}
bool CCatalog::loadStatistic(QWidget *pParent)
{
QDomDocument doc;
QDomElement elemRoot, e;
QDomNode n;
QFile file (statisticFileName());
QString strVerzeichnis, str, strXML;
int iErrLine, iErrCol;
if (!file.exists()) return true;
if (!file.open (QIODevice::ReadOnly))
{
QMessageBox::critical(pParent, QString(pParent->tr("Datei-Fehler")), pParent->tr("Konnte folgende Datei nicht zum Lesen öffnen:\n")+statisticFileName());
return false;
}
QTextStream in (&file);
strXML = in.readAll();
if (!doc.setContent(strXML, true, &str, &iErrLine, &iErrCol))
{
QMessageBox::critical(pParent, pParent->tr("XML-Fehler"), pParent->tr("Statistik zum Fragenkatalog: ") + statisticFileName() + "\n" + str + "\n" + QString (pParent->tr("Zeile: %1 Spalte %2")).arg(iErrLine).arg(iErrCol));
return false;
}
file.close ();
elemRoot = doc.documentElement ();
if (doc.doctype().name() != "AFUTrainerStatistics") return false;
if (elemRoot.tagName() != "statistic") return false;
n = elemRoot.firstChild();
while (!n.isNull())
{
if (n.isElement ())
{
e = n.toElement ();
if (e.tagName() == QString ("learning"))
{
loadLearnStatistic(e);
}
else if (e.tagName() == QString("exams"))
loadExamStatistic(e);
}
n = n.nextSibling();
}
return true;
}
bool CCatalog::saveStatistic(QWidget *pParent)
{
QDomDocument doc ("AFUTrainerStatistics");
QString strFileName = statisticFileName();
QFile file (strFileName);
if (m_strUniqueName.isEmpty()) return false;
QDomElement elemRoot = doc.createElement ("statistic");
elemRoot.setAttribute ("name", name());
elemRoot.setAttribute("version", 2);
elemRoot.setAttribute("date", QDate::currentDate().toString(Qt::ISODate));
doc.appendChild (elemRoot);
QDomElement elemLearn = doc.createElement ("learning");
elemRoot.appendChild (elemLearn);
saveLearnStatistic(elemLearn, doc);
QDomElement elemExams = doc.createElement ("exams");
elemRoot.appendChild (elemExams);
saveExamStatistic(elemExams, doc);
if (!file.open (QIODevice::WriteOnly))
{
QMessageBox::critical (pParent, pParent->tr("Fehler"), pParent->tr("Konnte folgende Datei nicht zum Schreiben öffnen.\n")+strFileName);
return false;
}
QTextStream out(&file);
out << doc.toString ();
return true;
}
bool CCatalog::loadExamStatistic (QDomElement& elemRoot)
{
QDomNode n;
QDomElement e;
n = elemRoot.firstChild();
while (!n.isNull())
{
if (n.isElement ())
{
e = n.toElement ();
if (e.tagName() == QString ("exam"))
{
CExamStat es;
if (es.load(e)) m_listExamStat.append(es);
}
}
n = n.nextSibling();
}
return true;
}
void CCatalog::saveExamStatistic (QDomElement& parent, QDomDocument& doc)
{
for (int i=0; i<m_listExamStat.size(); i++)
{
m_listExamStat.at(i).save (parent, doc);
}
}
QList<CChapter*> CCatalog::chapters()
{
QList<CChapter*> list;
list.append(this);
list << subChapters();
return list;
}
CExam CCatalog::examById(const QString& strId) const
{
for (int i=0; i<m_listExam.size(); i++)
{
if (m_listExam.at(i).id() == strId)
return m_listExam.at(i);
}
return CExam();
}
/***************************************************************************
* Copyright (C) 2003-2007 by Oliver Saal *
* osaal@gmx.de *
* http://www.oliver-saal.de/software/afutrainer/ *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include "catalog.h"
#include "osziparchive.h"
#include "tools.h"
#include <qdir.h>
#include <qfile.h>
#include <qmessagebox.h>
#include <qtextstream.h>
#include <qvariant.h>
CCatalog::~CCatalog()
{
qDeleteAll(m_listFiles);
}
void CCatalog::clear()
{
CChapter::clear();
m_bMixAnswers = true;
m_bSort = false;
m_strFileName.clear();
m_listHint.clear();
m_strUniqueName.clear();
qDeleteAll(m_listFiles);
m_strPublisher.clear();
m_strContact.clear();
m_dateValidFrom = QDate();
m_dateValidUntil = QDate();
m_dateCreated = QDate();
m_datePublished = QDate();
m_strVersion.clear();
m_listExam.clear();
m_listExamStat.clear();
}
bool CCatalog::isEmpty()
{
return m_strText.isEmpty();
}
bool CCatalog::isValid() const
{
if (m_dateValidFrom.isValid() && QDate::currentDate() < m_dateValidFrom) return false;
if (m_dateValidUntil.isValid() && QDate::currentDate() > m_dateValidUntil) return false;
return true;
}
bool CCatalog::hasHints (const QString& strQuestionId) const
{
for (int i=0; i<m_listHint.size(); i++)
{
if (m_listHint.at(i).hasQuestion(strQuestionId)) return true;
}
return false;
}
QString CCatalog::hintText (const QString& strQuestionId) const
{
QString str;
if (strQuestionId.isEmpty()) return QString();
for (int i=0; i<m_listHint.size(); i++)
{
if (m_listHint.at(i).hasQuestion(strQuestionId))
str += m_listHint[i].showText();
}
return str;
}
bool CCatalog::load (const QString& strFileName, QWidget *pParent)
{
QDomDocument doc;
QDomElement elemRoot, e;
QDomNode n;
QString str, strXML;
int iErrLine, iErrCol;
double dVersion=0.0;
CChapter *pChapter=0;
if (strFileName.right(3).toLower() != "aqz") return false;
CZipArchive zip;
if (!zip.open(strFileName, CZipArchive::OpenReadOnly))
{
QMessageBox::critical(pParent, pParent->tr("Datei-Fehler"), pParent->tr("Konnte folgende Datei nicht zum Lesen öffnen:\n%1").arg(strFileName));
return false;
}
// Fragen entpacken
CZipFile *pzfQuestions = zip.findFile("questions.xml");
if (pzfQuestions == 0)
{
QMessageBox::critical(pParent, pParent->tr("Datei-Fehler"), pParent->tr("Konnte in der Datei '%1' keine Fragen finden.").arg(strFileName));
return false;
}
strXML = QString::fromUtf8(pzfQuestions->deflateToByteArray());
clear();
// Alle Grafiken in temp. Dateien entpacken
// pParent->setCursor(Qt::WaitCursor);
for (int i=0; i<zip.fileCount(); i++)
{
CZipFile *pzf = zip.fileAt(i);
str = pzf->fileName().right(3);
if (str == "png" || str == "jpg" || str == "gif" || str == "bmp")
{ // Datei entpacken und Pfade im XML anpassen
str = QDir::temp().absoluteFilePath(pzf->fileName()+".XXXXXX");
QTemporaryFile *ptf = new QTemporaryFile(str);
ptf->open();
str = ptf->fileName();
pzf->deflateToFile(*ptf);
ptf->close();
m_listFiles.append(ptf);
strXML.replace(pzf->fileName(), str);
//qDebug ("Deflating %s to %s", qPrintable(pzf->fileName()), qPrintable(str));
}
}
// pParent->setCursor(Qt::ArrowCursor);
if (!doc.setContent(strXML, true, &str, &iErrLine, &iErrCol))
{
QMessageBox::critical(pParent, pParent->tr("XML-Fehler"), pParent->tr("Fragenkatalog: ") + strFileName + "\n" + str + "\n" + QString (pParent->tr("Zeile: %1 Spalte %2")).arg(iErrLine).arg(iErrCol));
return false;
}
elemRoot = doc.documentElement ();
if (elemRoot.tagName() != "aqdf")
{
QMessageBox::critical(pParent, pParent->tr("Datei-Fehler"), pParent->tr("Unbekanntes XML-Datenformat '%1'.").arg(elemRoot.tagName()));
return false;
}
//m_strText = elemRoot.attribute ("name");
m_dateCreated = QDate::fromString(elemRoot.attribute("created"), Qt::ISODate);
dVersion = elemRoot.attribute("version").toDouble();
if (dVersion != 1.0)
{
QMessageBox::information(pParent, pParent->tr("Information"), pParent->tr("Kann die Dateiversion %1 des Fragenkatalogs '%2' nicht lesen.").arg(dVersion).arg(strFileName));
return false;
}
n = elemRoot.firstChild();
while (!n.isNull())
{
if (n.isElement ())
{
e = n.toElement ();
if (e.tagName() == QString ("chapter"))
{
pChapter = new CChapter();
if (pChapter->load (e))
appendChapter(pChapter);
else
delete pChapter;
}
else if (e.tagName() == QString ("exam"))
{
CExam exam;
if (exam.load(e)) m_listExam.append(exam);
}
else if (e.tagName () == "hint")
{
CHint hint;
if (hint.load (e))
m_listHint.append (hint);
}
else if (e.tagName () == "title")
{
m_strText = e.text();
m_strUniqueName = e.attribute("unique");
}
else if (e.tagName () == "comment")
m_strComment = e.text();
else if (e.tagName () == "contact")
m_strContact = e.text();
else if (e.tagName () == "publisher")
m_strPublisher = e.text();
else if (e.tagName() == "valid")
{
m_dateValidFrom = QDate::fromString(e.attribute("from"), Qt::ISODate);
m_dateValidUntil = QDate::fromString(e.attribute("until"), Qt::ISODate);
}
else if (e.tagName() == "version")
{
m_datePublished = QDate::fromString(e.attribute("published"), Qt::ISODate);
m_strVersion = e.text();
}
else if (e.tagName() == "options")
{
m_bMixAnswers = QVariant(e.attribute("mixanswers", "true")).toBool();
m_bSort = QVariant(e.attribute("sort", "false")).toBool();
}
}
n = n.nextSibling();
}
if (m_strUniqueName.isEmpty())
m_strUniqueName = QDir(strFileName).dirName();
if (m_bSort) sortAll();
loadStatistic (pParent);
updateStatistic();
m_strFileName = strFileName;
return true;
}
bool CCatalog::save (const QString& strFileName, QWidget *pParent)
{
QFile file (strFileName);
if (strFileName.isEmpty()) return false;
if (!file.open(QIODevice::WriteOnly))
{
QMessageBox::critical(pParent, QString(pParent->tr("Datei-Fehler")), pParent->tr("Konnte folgende Datei nicht zum Schreiben öffnen:\n")+strFileName);
return false;
}
QTextStream out(&file);
QDomDocument doc("afutrainer");
QDomElement elemRoot = doc.createElement("afutrainer");
//elemRoot.setAttribute("name", name());
elemRoot.setAttribute("version", 3.0);
elemRoot.setAttribute("created", QDate::currentDate().toString(Qt::ISODate));
doc.appendChild(elemRoot);
// save unique name
QDomElement elemTitle = createXmlTextElement("title", name(), doc);
elemTitle.setAttribute("unique", m_strUniqueName);
elemRoot.appendChild (elemTitle);
// save comment
if (!m_strComment.isEmpty())
elemRoot.appendChild (createXmlTextElement("comment", m_strComment, doc));
// save contact
if (!m_strContact.isEmpty())
elemRoot.appendChild (createXmlTextElement("contact", m_strContact, doc));
// save publisher
if (!m_strPublisher.isEmpty())
elemRoot.appendChild (createXmlTextElement("publisher", m_strPublisher, doc));
// save version
QDomElement elemVersion = createXmlTextElement("version", m_strVersion, doc);
elemVersion.setAttribute("published", m_datePublished.toString(Qt::ISODate));
elemRoot.appendChild(elemVersion);
// save dates
if (m_dateValidFrom.isValid() || m_dateValidUntil.isValid())
{
QDomElement elemValid = doc.createElement("valid");
elemValid.setAttribute("from", m_dateValidFrom.toString(Qt::ISODate));
elemValid.setAttribute("until", m_dateValidUntil.toString(Qt::ISODate));
elemRoot.appendChild(elemValid);
}
// TODO: save tests
// save chapters
for (int i=0; i<m_listChapter.size(); i++)
m_listChapter[i]->save(elemRoot, doc);
// save helpers
for (int i=0; i<m_listHint.size(); i++)
m_listHint[i].save(elemRoot, doc);
out << doc.toString();
m_strFileName = strFileName;
return true;
}
QString CCatalog::statisticFileName() const
{
QDir dir;
QString str = dir.homePath()+QString("/.afutrainer/") + m_strUniqueName + QString(".stat.xml");
Q_ASSERT(!m_strUniqueName.isEmpty());
return (str);
}
bool CCatalog::loadStatistic(QWidget *pParent)
{
QDomDocument doc;
QDomElement elemRoot, e;
QDomNode n;
QFile file (statisticFileName());
QString strVerzeichnis, str, strXML;
int iErrLine, iErrCol;
if (!file.exists()) return true;
if (!file.open (QIODevice::ReadOnly))
{
QMessageBox::critical(pParent, QString(pParent->tr("Datei-Fehler")), pParent->tr("Konnte folgende Datei nicht zum Lesen öffnen:\n")+statisticFileName());
return false;
}
QTextStream in (&file);
strXML = in.readAll();
if (!doc.setContent(strXML, true, &str, &iErrLine, &iErrCol))
{
QMessageBox::critical(pParent, pParent->tr("XML-Fehler"), pParent->tr("Statistik zum Fragenkatalog: ") + statisticFileName() + "\n" + str + "\n" + QString (pParent->tr("Zeile: %1 Spalte %2")).arg(iErrLine).arg(iErrCol));
return false;
}
file.close ();
elemRoot = doc.documentElement ();
if (doc.doctype().name() != "AFUTrainerStatistics") return false;
if (elemRoot.tagName() != "statistic") return false;
n = elemRoot.firstChild();
while (!n.isNull())
{
if (n.isElement ())
{
e = n.toElement ();
if (e.tagName() == QString ("learning"))
{
loadLearnStatistic(e);
}
else if (e.tagName() == QString("exams"))
loadExamStatistic(e);
}
n = n.nextSibling();
}
return true;
}
bool CCatalog::saveStatistic(QWidget *pParent)
{
QDomDocument doc ("AFUTrainerStatistics");
QString strFileName = statisticFileName();
QFile file (strFileName);
if (m_strUniqueName.isEmpty()) return false;
QDomElement elemRoot = doc.createElement ("statistic");
elemRoot.setAttribute ("name", name());
elemRoot.setAttribute("version", 2);
elemRoot.setAttribute("date", QDate::currentDate().toString(Qt::ISODate));
doc.appendChild (elemRoot);
QDomElement elemLearn = doc.createElement ("learning");
elemRoot.appendChild (elemLearn);
saveLearnStatistic(elemLearn, doc);
QDomElement elemExams = doc.createElement ("exams");
elemRoot.appendChild (elemExams);
saveExamStatistic(elemExams, doc);
if (!file.open (QIODevice::WriteOnly))
{
QMessageBox::critical (pParent, pParent->tr("Fehler"), pParent->tr("Konnte folgende Datei nicht zum Schreiben öffnen.\n")+strFileName);
return false;
}
QTextStream out(&file);
out << doc.toString ();
return true;
}
bool CCatalog::loadExamStatistic (QDomElement& elemRoot)
{
QDomNode n;
QDomElement e;
n = elemRoot.firstChild();
while (!n.isNull())
{
if (n.isElement ())
{
e = n.toElement ();
if (e.tagName() == QString ("exam"))
{
CExamStat es;
if (es.load(e)) m_listExamStat.append(es);
}
}
n = n.nextSibling();
}
return true;
}
void CCatalog::saveExamStatistic (QDomElement& parent, QDomDocument& doc)
{
for (int i=0; i<m_listExamStat.size(); i++)
{
m_listExamStat.at(i).save (parent, doc);
}
}
QList<CChapter*> CCatalog::chapters()
{
QList<CChapter*> list;
list.append(this);
list << subChapters();
return list;
}
CExam CCatalog::examById(const QString& strId) const
{
for (int i=0; i<m_listExam.size(); i++)
{
if (m_listExam.at(i).id() == strId)
return m_listExam.at(i);
}
return CExam();
}

240
catalog.h
View File

@ -1,120 +1,120 @@
/***************************************************************************
* Copyright (C) 2003-2007 by Oliver Saal *
* osaal@gmx.de *
* http://www.oliver-saal.de/software/afutrainer/ *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#ifndef CATALOG_H
#define CATALOG_H
#include "chapter.h"
#include "exam.h"
#include <qlist.h>
#include <qtemporaryfile.h>
class CCatalog : public CChapter
{
public:
CCatalog() : CChapter() { clear(); }
~CCatalog();
void clear();
bool isEmpty();
inline QString name() const { return m_strText; }
inline void setName(const QString& strName) { m_strText = strName; }