#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; }