#include "WordDrillModel.h" #include "../dictionary/Card.h" #include "../dictionary/CardPack.h" #include "StudySettings.h" #include #include WordDrillModel::WordDrillModel( CardPack* aCardPack ): IStudyModel( aCardPack ), m_historyCurPackStart(0) { curCardNum = NoCardIndex; srand( time(NULL) ); connect( aCardPack, SIGNAL(cardsGenerated()), SLOT(updateStudyState()) ); generateFreshPack(); pickNextCard(); } /** Get current card. * If the current card doesn't exist any more, find the next valid card. */ Card* WordDrillModel::getCurCard() const { if( m_cardHistory.isEmpty() || curCardNum < 0 ) // No cards in the pack return NULL; if( curCardNum >= m_cardHistory.size() ) return NULL; QString cardName = m_cardHistory.at(curCardNum); return cardPack->getCard( cardName ); } void WordDrillModel::updateStudyState() { generateFreshPack(); cleanHistoryFromRemovedCards(); if( getCurCard() ) emit curCardUpdated(); else pickNextCard(); } void WordDrillModel::generateFreshPack() { m_freshPack = cardPack->getCardQuestions(); // Remove already reviewed cards if( m_historyCurPackStart >= m_cardHistory.size() ) return; foreach( QString reviewedCard, m_cardHistory.mid( m_historyCurPackStart ) ) m_freshPack.removeAll( reviewedCard ); } void WordDrillModel::cleanHistoryFromRemovedCards() { if( m_cardHistory.isEmpty() ) return; bool cardsRemoved = false; QMutableStringListIterator it( m_cardHistory ); int i = 0; while( it.hasNext() ) { QString cardName = it.next(); if( !cardPack->containsQuestion( cardName ) ) { it.remove(); cardsRemoved = true; if( i < curCardNum ) curCardNum--; } i++; } if( cardsRemoved ) { if( curCardNum >= m_cardHistory.size() ) curCardNum = m_cardHistory.size() - 1; emit nextCardSelected(); } } /** Picks a random card. Removes the selected card from the fresh pack and adds it to the history. * Thus, the new card is the last entry in the history. * This function guarantees that the new card's question will be different from the previous one, unless there is no choice. * * Updates #m_curCardNum. */ void WordDrillModel::pickNextCard() { QString selectedCardName; const Card* selectedCard = NULL; do { if( m_freshPack.isEmpty() ) // No fresh cards { m_historyCurPackStart = m_cardHistory.size(); // Refers beyond the history pack generateFreshPack(); if( m_freshPack.isEmpty() ) // Still no any cards available - no useful cards in the dictionary or it's empty { curCardNum = NoCardIndex; emit nextCardSelected(); return; } } if( m_freshPack.size() == 1 ) // Only 1 fresh card, no choice selectedCardName = m_freshPack.takeFirst(); else { int selectedCardNum; if( StudySettings::inst()->showRandomly ) selectedCardNum = rand() % m_freshPack.size(); else selectedCardNum = 0; if( !m_cardHistory.isEmpty() ) while( m_freshPack[ selectedCardNum ] == m_cardHistory.last() ) // The new question must be different from the current one { selectedCardNum++; selectedCardNum %= m_freshPack.size(); } selectedCardName = m_freshPack.takeAt( selectedCardNum ); } selectedCard = cardPack->getCard( selectedCardName ); } while( !selectedCard ); m_cardHistory << selectedCardName; curCardNum = m_cardHistory.size() - 1; emit nextCardSelected(); } /** Go back along the history line. * @return true, if the transition was successful */ bool WordDrillModel::goBack() { if( !canGoBack() ) return false; curCardNum--; emit nextCardSelected(); return true; } /** Go forward along the history line. * @return true, if the transition was successful */ bool WordDrillModel::goForward() { if( !canGoForward() ) return false; curCardNum++; emit nextCardSelected(); return true; } bool WordDrillModel::canGoBack() { return curCardNum > 0; } bool WordDrillModel::canGoForward() { return curCardNum < m_cardHistory.size() - 1; }