summaryrefslogtreecommitdiff
path: root/src/study/StudyFileReader.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/study/StudyFileReader.cpp')
-rw-r--r--src/study/StudyFileReader.cpp238
1 files changed, 238 insertions, 0 deletions
diff --git a/src/study/StudyFileReader.cpp b/src/study/StudyFileReader.cpp
new file mode 100644
index 0000000..ecc4dbf
--- /dev/null
+++ b/src/study/StudyFileReader.cpp
@@ -0,0 +1,238 @@
+#include "StudyFileReader.h"
+#include "../dictionary/Dictionary.h"
+#include "../version.h"
+#include "../dictionary/CardPack.h"
+#include "../dictionary/DicRecord.h"
+
+#include <QMessageBox>
+
+const QString StudyFileReader::MinSupportedStudyVersion = "1.0";
+
+StudyFileReader::StudyFileReader( Dictionary* aDict ):
+ m_dict( aDict ), m_cardPack( NULL )
+ {
+ settings = StudySettings::inst();
+ }
+
+bool StudyFileReader::read( QIODevice* aDevice )
+ {
+ setDevice( aDevice );
+ while( !atEnd() )
+ {
+ readNext();
+ if( isStartElement() )
+ {
+ if( name() == "study" )
+ {
+ readStudy();
+ return !error(); // readStudy() processes all situations
+ }
+ else
+ raiseError( Dictionary::tr("The file is not a study file.") );
+ }
+ }
+ return !error();
+ }
+
+void StudyFileReader::readStudy()
+ {
+ Q_ASSERT( isStartElement() && name() == "study" );
+
+ m_studyVersion = attributes().value( "version" ).toString();
+ if(m_studyVersion >= MinSupportedStudyVersion)
+ readStudyCurrentVersion();
+ else
+ QMessageBox::warning( NULL, Dictionary::tr("Unsupported format"),
+ Dictionary::tr("The study file uses unsupported format %1.\n"
+ "The minimum supported version is %2" )
+ .arg( m_studyVersion )
+ .arg( MinSupportedStudyVersion ) );
+ }
+
+void StudyFileReader::readUnknownElement()
+ {
+ Q_ASSERT( isStartElement() );
+ while( !atEnd() )
+ {
+ readNext();
+ if( isEndElement() )
+ break;
+ if( isStartElement() )
+ readUnknownElement();
+ }
+ }
+
+void StudyFileReader::readStudyCurrentVersion()
+ {
+ Q_ASSERT( isStartElement() && name() == "study" );
+
+ while( !atEnd() )
+ {
+ readNext();
+ if( isEndElement() )
+ break;
+ if( isStartElement() )
+ {
+ if( name() == "pack" )
+ readPack();
+ else
+ readUnknownElement();
+ }
+ }
+ if(m_studyVersion != STUDY_VERSION)
+ m_dict->setStudyModified();
+ }
+
+void StudyFileReader::readPack()
+ {
+ Q_ASSERT( isStartElement() && name() == "pack" );
+
+ QString id = attributes().value( "id" ).toString();
+ m_cardPack = m_dict->cardPack( id );
+ if( !m_cardPack )
+ {
+ skipCurrentElement();
+ return;
+ }
+ m_cardPack->setReadingStudyFile(true);
+
+ while( !atEnd() )
+ {
+ readNext();
+ if( isEndElement() )
+ break;
+ if( isStartElement() )
+ {
+ if( name() == "cur-card" )
+ {
+ Q_ASSERT( m_cardPack->curCardName().isEmpty() );
+ QString curCard = attributes().value( "id" ).toString();
+ if( !curCard.isEmpty() )
+ m_cardPack->setCurCard( curCard );
+ readNext(); // read end of 'cur-card' element
+ Q_ASSERT( isEndElement() );
+ }
+ else if( name() == "c" )
+ readC();
+ else
+ readUnknownElement();
+ }
+ }
+
+ m_cardPack->setReadingStudyFile(false);
+ }
+
+void StudyFileReader::readC()
+ {
+ Q_ASSERT( isStartElement() && name() == "c" && m_cardPack );
+
+ m_cardId = attributes().value( "id" ).toString();
+
+ while( !atEnd() )
+ {
+ readNext();
+ if( isEndElement() )
+ break;
+ if( isStartElement() )
+ {
+ if( name() == "r" )
+ readR();
+ else
+ readUnknownElement();
+ }
+ }
+ }
+
+void StudyFileReader::readR()
+ {
+ Q_ASSERT( isStartElement() && name() == "r" );
+
+ StudyRecord study;
+ bool ok; // for number conversions
+
+ QString date = attributes().value( "d" ).toString();
+ study.date = QDateTime::fromString( date, Qt::ISODate );
+
+ QString grade = attributes().value( "g" ).toString();
+ study.grade = grade.toInt( &ok );
+ if(m_studyVersion < "1.4" && study.grade < 3)
+ study.grade++;
+
+ QString easiness = attributes().value( "e" ).toString();
+ study.easiness = easiness.toFloat( &ok );
+
+ QString time;
+ time = attributes().value( "t" ).toString(); // obsolete parameter
+ if(!time.isEmpty())
+ {
+ study.recallTime = time.toFloat( &ok );
+ Q_ASSERT( ok );
+ }
+
+ time = attributes().value( "rt" ).toString();
+ if(!time.isEmpty())
+ {
+ study.recallTime = time.toFloat( &ok );
+ if( study.recallTime > StudyRecord::MaxAnswerTime )
+ study.recallTime = StudyRecord::MaxAnswerTime;
+ Q_ASSERT( ok );
+ }
+
+ time = attributes().value( "at" ).toString();
+ if(!time.isEmpty())
+ {
+ study.answerTime = time.toFloat( &ok );
+ if( study.answerTime > StudyRecord::MaxAnswerTime )
+ study.answerTime = StudyRecord::MaxAnswerTime;
+ Q_ASSERT( ok );
+ }
+
+ QString interval = attributes().value( "i" ).toString();
+ QString level = attributes().value( "l" ).toString();
+ if(!interval.isEmpty() && interval != "0")
+ {
+ study.interval = interval.toFloat();
+ if(!level.isEmpty())
+ study.level = level.toInt();
+ else
+ study.level = StudyRecord::Repeating;
+ if(m_studyVersion == "1.4")
+ fixupIncorrectGradeIn1_4(study);
+ }
+ else // delayed card
+ {
+ QString cardsStr = attributes().value( "c" ).toString();
+ if( !cardsStr.isEmpty() )
+ {
+ int cardInterval = cardsStr.toInt();
+ if(cardInterval <= 7)
+ study.interval = settings->unknownInterval;
+ else
+ study.interval = settings->incorrectInterval;
+ }
+ else
+ study.interval = 0;
+ study.level = StudyRecord::ShortLearning;
+ }
+
+ m_cardPack->addStudyRecord( m_cardId, study );
+
+ readElementText(); // read until element end
+ }
+
+void StudyFileReader::fixupIncorrectGradeIn1_4(StudyRecord& study)
+{
+ if(!(study.level == StudyRecord::ShortLearning &&
+ study.grade <= 3))
+ return;
+ if(equalDouble(study.interval, settings->unknownInterval))
+ study.grade = StudyRecord::Unknown;
+ else if(equalDouble(study.interval, settings->incorrectInterval))
+ study.grade = StudyRecord::Incorrect;
+}
+
+bool StudyFileReader::equalDouble(double a, double b)
+{
+ static const double Dif = 0.0001;
+ return fabs(a - b) < Dif;
+}