Fix naming: book parts vs. chapters.
[dorian] / model / library.cpp
1 #include <QSettings>
2 #include <QDebug>
3 #include <QFileInfo>
4
5 #include "library.h"
6 #include "book.h"
7 #include "trace.h"
8
9 Library *Library::mInstance = 0;
10
11 Library::Library(QObject *parent): QAbstractListModel(parent)
12 {
13     load();
14 }
15
16 Library::~Library()
17 {
18     clear();
19 }
20
21 Library *Library::instance()
22 {
23     if (!mInstance) {
24         mInstance = new Library();
25     }
26     return mInstance;
27 }
28
29 int Library::rowCount(const QModelIndex &parent) const
30 {
31     if (parent.isValid()) {
32         return 0;
33     } else {
34         return mBooks.size();
35     }
36 }
37
38 QVariant Library::data(const QModelIndex &index, int role) const
39 {
40     if (!index.isValid()) {
41         return QVariant();
42     }
43
44     switch (role) {
45     case Qt::DisplayRole:
46         return mBooks[index.row()]->name();
47     case Qt::DecorationRole:
48         return QPixmap::fromImage(mBooks[index.row()]->cover);
49     default:
50         return QVariant();
51     }
52 }
53
54 Book *Library::book(const QModelIndex &index)
55 {
56     if (index.isValid()) {
57         if ((index.row() >= 0) && (index.row() < mBooks.size())) {
58             return mBooks[index.row()];
59         } else {
60             qCritical() << "Library::book: Bad index" << index.row();
61         }
62     }
63     return 0;
64 }
65
66 void Library::close()
67 {
68     delete mInstance;
69     mInstance = 0;
70 }
71
72 void Library::load()
73 {
74     QSettings settings;
75     clear();
76     int size = settings.value("lib/size").toInt();
77     for (int i = 0; i < size; i++) {
78         QString key = "lib/book" + QString::number(i);
79         QString path = settings.value(key).toString();
80         Book *book = new Book(path);
81         connect(book, SIGNAL(opened(const QString &)),
82                 this, SLOT(onBookOpened(const QString &)));
83         book->load();
84         mBooks.append(book);
85     }
86     QString currentPath = settings.value("lib/nowreading").toString();
87     mNowReading = find(currentPath);
88     mFolders = settings.value("lib/folders").toStringList();
89 }
90
91 void Library::save()
92 {
93     QSettings settings;
94     settings.setValue("lib/size", mBooks.size());
95     for (int i = 0; i < mBooks.size(); i++) {
96         QString key = "lib/book" + QString::number(i);
97         settings.setValue(key, mBooks[i]->path());
98     }
99     Book *currentBook = book(mNowReading);
100     settings.setValue("lib/nowreading",
101                       currentBook? currentBook->path(): QString());
102     settings.setValue("lib/folders", mFolders);
103 }
104
105 bool Library::add(const QString &path)
106 {
107     Trace t("Library::add " + path);
108     if (path == "") {
109         qCritical() << "Library::add: Empty path";
110         return false;
111     }
112     if (find(path).isValid()) {
113         t.trace("Book already exists in library");
114         return false;
115     }
116     int size = mBooks.size();
117     Book *book = new Book(path);
118     beginInsertRows(QModelIndex(), size, size);
119     mBooks.append(book);
120     save();
121     endInsertRows();
122     return true;
123 }
124
125 void Library::remove(const QModelIndex &index)
126 {
127     Book *toRemove = book(index);
128     if (!toRemove) {
129         return;
130     }
131     int row = index.row();
132     beginRemoveRows(QModelIndex(), row, row);
133     mBooks.removeAt(row);
134     save();
135     endRemoveRows();
136     if (index == mNowReading) {
137         mNowReading = QModelIndex();
138         emit nowReadingChanged();
139     }
140     delete toRemove;
141 }
142
143 void Library::remove(const QString &path)
144 {
145     remove(find(path));
146 }
147
148 QModelIndex Library::nowReading() const
149 {
150     return mNowReading;
151 }
152
153 void Library::setNowReading(const QModelIndex &index)
154 {
155     mNowReading = index;
156     save();
157     emit nowReadingChanged();
158 }
159
160 void Library::clear()
161 {
162     for (int i = 0; i < mBooks.size(); i++) {
163         delete mBooks[i];
164     }
165     mBooks.clear();
166     mNowReading = QModelIndex();
167 }
168
169 QModelIndex Library::find(QString path) const
170 {
171     if (path != "") {
172         QString absolutePath = QFileInfo(path).absoluteFilePath();
173         for (int i = 0; i < mBooks.size(); i++) {
174             if (absolutePath == mBooks[i]->path()) {
175                 return index(i);
176             }
177         }
178     }
179     return QModelIndex();
180 }
181
182 QModelIndex Library::find(const Book *book) const
183 {
184     if (book) {
185         for (int i = 0; i < mBooks.size(); i++) {
186             if (book == mBooks[i]) {
187                 return index(i);
188             }
189         }
190     }
191     return QModelIndex();
192 }
193
194 void Library::onBookOpened(const QString &path)
195 {
196     Trace t("Library::onBookOpened " + path);
197     QModelIndex index = find(path);
198     if (index.isValid()) {
199         emit dataChanged(index, index);
200     }
201 }
202
203 QStringList Library::bookPaths()
204 {
205     QStringList ret;
206     foreach (Book *book, mBooks) {
207         ret.append(book->path());
208     }
209     return ret;
210 }
211
212 QStringList Library::folders() const
213 {
214     return mFolders;
215 }
216
217 bool Library::addFolder(const QString &folder)
218 {
219     if (!mFolders.contains(folder)) {
220         mFolders.append(folder);
221         save();
222         return true;
223     } else {
224         return false;
225     }
226 }
227
228 bool Library::removeFolder(const QString &folder)
229 {
230     if (mFolders.contains(folder)) {
231         mFolders.removeOne(folder);
232         save();
233         return true;
234     } else {
235         return false;
236     }
237 }
238
239 void Library::scanFolders()
240 {
241 }