summaryrefslogtreecommitdiff
path: root/src/dictionary/CardPack.h
blob: fc7d3357e19d94a313132278859cb14cd6b2bba3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
#ifndef CARDPACK_H
#define CARDPACK_H

#include <QtCore>
#include <QtDebug>

#include "ICardPack.h"
#include "../study/StudyRecord.h"
#include "IDictionary.h"
#include "Field.h"
#include "TreeItem.h"

class DicRecord;
class Card;

/**
  @brief Pack of cards

  A card pack consists of cards of certain card pattern.
  A card pattern is a combination of fields: question field and answer fields.
*/

class CardPack: public TreeItem, public ICardPack
{
    Q_OBJECT

public:
    static const QString SynonymDelimiter;
    static const QString HomonymDelimiter;

public:
    CardPack(IDictionary* dict);
    CardPack(IDictionary* dict, const CardPack* otherPack);
    ~CardPack();
    
    // Getters

    QString id() const;
    QString name() const { return m_name; } // See also id()
    QString curCardName() const { return m_curCardName; }
    IDictionary* dictionary() const { return m_dictionary; }
    QList<DicRecord*> getRecords() const;
    
    // Tree view
    const TreeItem* parent() const;
    const TreeItem* child( int /*aRow*/ ) const { return NULL; }
    int childCount() const { return 0; }
    int columnCount() const { return 3; }
    QVariant data( int aColumn ) const;
    int row() const;
    int topParentRow() const;
    
    // Fields
    QList<const Field*> getFields() const { return fields; }
    const Field* getQuestionField() const;
    QList<const Field*> getAnswerFields() const;
    bool getUsesExactAnswer() const { return usesExactAnswer; }
    
    // Cards
    QStringList getCardQuestions() const { return cardQuestions; }
    bool containsQuestion(const QString& question) const
        { return cardQuestions.contains(question); }
    int cardsNum() const { return cardQuestions.size(); }
    Card* getCard(const QString& cardName);
    
    // Study records
    QList<StudyRecord> getStudyRecords() const { return studyRecords.values(); }
    QList<QDateTime> getScheduledDates() const;
    QList<StudyRecord> getStudyRecords(QString cardId) const
        { return studyRecords.values(cardId); }
    int studyRecordsNum() const { return studyRecords.uniqueKeys().size(); }
    bool containsReviewedCards() const;
    StudyRecord getStudyRecord(QString cardId) const;
    QString findLastReviewedCard() const;
    
    // Study statistics
    QStringList getNewCards() const;
    QStringList getActiveCards() const;
    int getActiveRepeatingCardsNum() const;
    int countScheduledForTodayCards() const;
    QStringList getPriorityActiveCards() const;
    QStringList getLearningCards() const;
    int getLearningReviewsNum() const;
    int getTimeToNextLearning() const;
    int getInactiveLearningReviewsNum() const;
    QStringList getSmallestIntervalCards(const QStringList& priorityCards);
    int getTodayReviewedCardsNum() const;
    int getTodayNewCardsNum() const;
    
public:
    // Setters
    void setName( QString aName ) { m_name = aName; }
    void setCurCard( const QString aCardId );
    
    // Fields
    void setFields( QList<const Field*> aFields ) { fields = aFields; }
    void setField( int aPos, const Field* aField );
    void addField( const Field* aField ) { fields << aField; }
    void removeField( int aPos ) { fields.removeAt(aPos); }
    void removeField( const Field* aField ) { fields.removeAll( aField ); }
    void insertField( int aPos, const Field* aField ) { fields.insert( aPos, aField ); }
    void setQstField( const Field* aField );
    void setAnsFields( QList<const Field*> aFields );
    void setUsesExactAnswer(bool uses) { usesExactAnswer = uses; }

    void setReadingStudyFile(bool reading) { isReadingStudyFile = reading; }
    void addStudyRecord( const QString aCardId, const StudyRecord& aStudyRecord );

public:
    void generateQuestions();
    void disableDictRecordUpdates();
    void enableDictRecordUpdates();

private:
    void destroyCards();
    void addQuestionElementsForRecord(const DicRecord* record);
    void removeAbsentCards(QStringList& cardQuestions);
    void removeDelayedCard(const QString& cardName);

signals:
    void studyRecordAdded();
    void cardsGenerated();

private slots:
    void processEntryChangedEvent( int aEntryIx, int aFieldIx = IDictionary::AllFields );

private:
    static const int MinRequiredFieldsNum = 2;

private:
    QString m_name; // Not used
    IDictionary* m_dictionary;

        // The first field is the question, others are answers.
    QList<const Field*> fields;

    QStringList cardQuestions;   ///< Original order of questions
    QHash<QString, Card*> cards;   ///< Card name -> card (own)
    QString m_curCardName;
    QMultiHash<QString, StudyRecord> studyRecords;  // Card ID -> Study record
    bool isReadingStudyFile;
    bool usesExactAnswer;
};
#endif