From d24f813f3f2a05c112e803e4256b53535895fc98 Mon Sep 17 00:00:00 2001 From: Jedidiah Barber Date: Wed, 14 Jul 2021 11:49:10 +1200 Subject: Initial mirror commit --- src/study/StudyFileReader.cpp | 238 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 238 insertions(+) create mode 100644 src/study/StudyFileReader.cpp (limited to 'src/study/StudyFileReader.cpp') 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 + +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; +} -- cgit