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