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