summaryrefslogtreecommitdiff
path: root/src/dictionary/Dictionary.h
blob: 5cbeaa218bc995d75798cb9525af5dd87122e6e3 (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
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
#ifndef DICTIONARY_H
#define DICTIONARY_H

#include <QObject>
#include <QList>
#include <QString>
#include <QFileInfo>
#include <QFile>
#include <QPair>
#include <QUuid>

#include "../export-import/CsvData.h"
#include "IDictionary.h"
#include "Card.h"
#include "Field.h"
#include "TreeItem.h"

class DicRecord;
class CardPack;
class AppModel;

/** \brief The dictionary
 *
 * The dictionary consists of entries #iEntries.
 * The property #iIsContentModified shows if the dictionary contents are modified and not saved. Different modifications are possible:
 * \li A single card was modified. Means contents of a card were modified. Signal CardModified(int) is emitted.
 * \li The Content Modified state is changed. Means that iIsContentModified has changed. Signal ContentModifiedChanged(bool) is emitted.
 * \li Some cards were inserted or removed. Independently of whether the cards are valid, signal
 * CardsInserted(int, int) or CardsRemoved(int,int) is emitted.
 * \li The file path is modified. Means that the dictionary file was renamed, e.g. after "Save as" operation.
 * Signal filePathChanged() is emitted.
 *
 * All card-modifying functions and signals call SetModified().
 */

class Dictionary: public TreeItem, public IDictionary
{
Q_OBJECT

friend class DictionaryReader;

public:
    
    // Methods
    Dictionary( const QString& aFilePath = "", bool aNameIsTemp = false, const AppModel* aAppModel = NULL );
    ~Dictionary();
    
    const TreeItem* parent() const { return NULL; }
    const TreeItem* child( int aRow ) const;
    int childCount() const { return cardPacksNum(); }
    int columnCount() const { return 1; }
    QVariant data( int aColumn ) const;
    int row() const;
    int topParentRow() const { return row(); }
    
    void clearFieldPackConfig();
    void setDictConfig( const Dictionary* aOtherDic );
    void setDefaultFields();
    bool load(const QString aFilePath);
    QFile::FileError save(const QString aFilePath, bool aChangeFilePath = true );
    QFile::FileError save() { return save( filePath ); }
    QFile::FileError saveContent( const QString aFilePath );
    QFile::FileError saveStudy();

    QString getFilePath() const { return filePath; }
    QString shortName( bool aMarkModified = true ) const;
    QString getStudyFilePath() const;
    QString getErrorMessage() const { return errorMessage; }
    bool contentModified() const { return m_contentModified; }
    bool studyModified() const { return m_studyModified; }
    bool nameIsTemp() const { return m_nameIsTemp; }
    bool empty() const { return records.isEmpty(); }
    
    QList<Field*> fields() const { return m_fields; }
    const Field* field( int aIx ) const { return m_fields.value( aIx ); }
    const Field* field( const QString aFieldName ) const;
    QString getFieldValue(int recordNum, int fieldNum) const;
    int fieldsNum() const { return m_fields.size(); }
    QStringList fieldNames() const;
    
    int cardPacksNum() const { return m_cardPacks.size(); }
    QList<CardPack*> cardPacks() const { return m_cardPacks; }
    CardPack* cardPack( int aIx ) const {return m_cardPacks.value(aIx);}
    CardPack* cardPack( QString aId ) const;
    int indexOfCardPack( CardPack* aPack ) const { return m_cardPacks.indexOf( aPack ); }
    
    int fieldId04ToIx( const QString aId ) const;   // Obsolete        
    const DicRecord* getRecord( int aIndex ) const;
    const DicRecord* entry04( const QString aId04 ) const;   // Obsolete
    const DicRecord* operator[]( int aIndex ) const { return getRecord(aIndex); }
    int entriesNum() const { return records.size(); }
    int indexOfRecord( DicRecord* aRecord ) const { return records.indexOf( aRecord ); }
    
    void setAppModel( const AppModel* aModel ) { Q_ASSERT( !m_appModel ); m_appModel = aModel; }

    // Modify fields
    
    void setFieldName( int aField, QString aName );
    void setFieldStyle( int aField, QString aStyle );
    void insertField( int aPos, QString aName );
    void insertField( int aPos, Field* aFieldPtr );
    void addField( QString aName, QString aStyle = "" );
    void addFields( QStringList aFieldNames );
    void removeField( int aPos );
    void destroyField( int aPos );
    
    // Modify card packs
    
    void insertPack( int aPos, CardPack* aPack );
    void removePack( int aPos );
    void destroyPack( int aPos );
    void addCardPack( CardPack* aCardPack );
    
    // Modify records
    
    void setFieldValue( int aEntryIx, int aFieldIx, QString aValue );
    void setRecord( int aIndex, const DicRecord& aRecord );
    void insertEntry(int aIndex, DicRecord* aEntry);
    void insertEntries(int aIndex, int aNum);
    void insertEntries( int aIndex, QList<DicRecord*> aEntries );    
    void removeEntry(int aIndex) { removeRecords( aIndex, 1 ); }
    void cleanRecords();
    void removeRecords(int aIndex, int aNum);
    void removeRecord(QString aQuestion);
    void disableRecordUpdates();
    void enableRecordUpdates();

    QString shortenImagePaths(QString text) const;    
    
signals:
    void entryChanged( int aEntryIx, int aFieldIx );
    void entriesRemoved( int aIndex, int aNum );
    void entriesInserted( int aIndex, int aNum );
    
    void fieldChanged( int aField );
    void fieldInserted( int aField );
    void fieldRemoved( int aField );
    void fieldDestroyed( Field* aField );
    
    void packInserted( int aPack );
    void packRemoved( int aPack );
    void packDestroyed( CardPack* aPack );
    void contentModifiedChanged( bool aModified );
    void studyModifiedChanged( bool aModified );
    
    void filePathChanged();    
    void cardsGenerated();
    
public slots:
    void setContentModified( bool aModified = true );    
    void setContentClean( bool aClean = true ) { setContentModified( !aClean ); }
    void setStudyModified( bool aModified = true );
    void generateCards();

private:
    bool loadDictFile(const QString filePath);
    bool loadStudyFile(const QString filePath);
    void cleanObsoleteId();

protected:
    void notifyRecordsInserted(int index, int num);

public:
    static const char* NoName;
    static const QString DictFileExtension;
    static const QString StudyFileExtension;

private:
    const AppModel* m_appModel;
    QUuid obsoleteId;  // Obsolete starting from 1.0
    QList<Field*> m_fields;

    bool m_contentModified;
    bool m_studyModified;

    /**
       The current file name is temporary and must be changed at the next save.
       Use cases:
       \li the dictionary has just been imported from a CSV file
       \li the dictionary of obsolete format was converted to the modern format
     */
    bool m_nameIsTemp;

    QString errorMessage;
};

#endif