Avoid complex types as statics.
[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     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 theInstance;
69     theInstance = 0;
70 }
71
72 void Library::load()
73 {
74     TRACE;
75
76     clear();
77     QStringList books = BookDb::instance()->books();
78     emit beginLoad(books.size());
79
80     foreach(QString path, books) {
81         emit loading(path);
82         Book *book = new Book(path);
83         connect(book, SIGNAL(opened(const QString &)),
84                 this, SLOT(onBookOpened(const QString &)));
85         // book->load();
86         mBooks.append(book);
87     }
88
89     QSettings settings;
90     QString currentPath = settings.value("lib/nowreading").toString();
91     mNowReading = find(currentPath);
92     emit endLoad();
93 }
94
95 void Library::save()
96 {
97     TRACE;
98     QSettings settings;
99     Book *currentBook = book(mNowReading);
100     settings.setValue("lib/nowreading",
101                       currentBook? currentBook->path(): QString());
102 }
103
104 bool Library::add(const QString &path)
105 {
106     TRACE;
107     if (path == "") {
108         qCritical() << "Library::add: Empty path";
109         return false;
110     }
111     if (find(path).isValid()) {
112         qDebug() << "Book already exists in library";
113         return false;
114     }
115     int size = mBooks.size();
116     beginInsertRows(QModelIndex(), size, size);
117     Book *book = new Book(path);
118     book->peek();
119     mBooks.append(book);
120     save();
121     endInsertRows();
122     return true;
123 }
124
125 void Library::remove(const QModelIndex &index)
126 {
127     TRACE;
128     Book *toRemove = book(index);
129     if (!toRemove) {
130         return;
131     }
132     toRemove->remove();
133     int row = index.row();
134     beginRemoveRows(QModelIndex(), row, row);
135     mBooks.removeAt(row);
136     save();
137     endRemoveRows();
138     if (index == mNowReading) {
139         mNowReading = QModelIndex();
140         emit nowReadingChanged();
141     }
142     delete toRemove;
143 }
144
145 void Library::remove(const QString &path)
146 {
147     remove(find(path));
148 }
149
150 QModelIndex Library::nowReading() const
151 {
152     return mNowReading;
153 }
154
155 void Library::setNowReading(const QModelIndex &index)
156 {
157     mNowReading = index;
158     save();
159     emit nowReadingChanged();
160 }
161
162 void Library::clear()
163 {
164     for (int i = 0; i < mBooks.size(); i++) {
165         delete mBooks[i];
166     }
167     mBooks.clear();
168     mNowReading = QModelIndex();
169 }
170
171 QModelIndex Library::find(QString path) const
172 {
173     if (path != "") {
174         QString absolutePath = QFileInfo(path).absoluteFilePath();
175         for (int i = 0; i < mBooks.size(); i++) {
176             if (absolutePath == mBooks[i]->path()) {
177                 return index(i);
178             }
179         }
180     }
181     return QModelIndex();
182 }
183
184 QModelIndex Library::find(const Book *book) const
185 {
186     if (book) {
187         for (int i = 0; i < mBooks.size(); i++) {
188             if (book == mBooks[i]) {
189                 return index(i);
190             }
191         }
192     }
193     return QModelIndex();
194 }
195
196 void Library::onBookOpened(const QString &path)
197 {
198     TRACE;
199     QModelIndex index = find(path);
200     if (index.isValid()) {
201         emit dataChanged(index, index);
202     }
203 }
204
205 QStringList Library::bookPaths()
206 {
207     QStringList ret;
208     foreach (Book *book, mBooks) {
209         ret.append(book->path());
210     }
211     return ret;
212 }
213
214 void Library::upgrade()
215 {
216     TRACE;
217     QSettings settings;
218     QString oldVersion = settings.value("lib/version").toString();
219     if (oldVersion.isEmpty()) {
220         int size = settings.value("lib/size").toInt();
221         emit beginUpgrade(size);
222         for (int i = 0; i < size; i++) {
223             QString key = "lib/book" + QString::number(i);
224             QString path = settings.value(key).toString();
225             emit upgrading(path);
226             Book *book = new Book(path);
227             book->upgrade();
228         }
229     } else {
230         emit beginUpgrade(0);
231     }
232     settings.setValue("lib/version", QString(DORIAN_VERSION));
233     emit endUpgrade();
234 }