5 #include <qtextdocument.h> // Qt::escape is currently defined here...
6 #include <QDirIterator>
8 #include <QtAlgorithms>
11 #include "opshandler.h"
12 #include "xmlerrorhandler.h"
13 #include "extractzip.h"
15 #include "containerhandler.h"
16 #include "ncxhandler.h"
22 Book::Book(const QString &path_)
26 QFileInfo info(path_);
27 mPath = info.absoluteFilePath();
28 title = info.baseName();
29 cover = QIcon(":/icons/book.png");
33 QString Book::path() const
40 qDebug() << "Book::open" << path();
47 else if (!extract()) {
48 fail("Could not extract content of " + path() + ".");
51 fail("Could not parse content of " + path() + ".");
60 qDebug() << "Book::close";
63 QDir::setCurrent(QDir::rootPath());
67 QString Book::tmpDir() const
69 return QDir::tempPath() + "/dorian/book";
72 void Book::fail(const QString &details, const QString &error)
77 QString errorPage = "<html><head><title>" + Qt::escape(error) +
78 "</title></head><body><h1>" + Qt::escape(error) + "</h1><p>" +
79 Qt::escape(details) + "</p></body></html>";
80 content["error"].href = errorPage;
81 content["error"].name = "Error";
87 QString tmp = tmpDir();
88 qDebug() << "Book::extract: Extracting" << mPath << "to" << tmp;
90 QDir::setCurrent(QDir::rootPath());
92 qCritical() << "*** Book::extract: Failed to remove" << tmp;
97 qCritical() << "*** Book::extract: Could not create" << tmp;
101 // If book comes from resource, copy it to the temporary directory first
102 QString bookPath = path();
103 if (bookPath.startsWith(":/books/")) {
105 QString dst(tmp + "/book.epub");
106 if (!src.copy(dst)) {
107 qCritical() << "*** Book::extract: Failed to copy built-in book to"
114 QString oldDir = QDir::currentPath();
115 if (!QDir::setCurrent(tmp)) {
116 qCritical() << "*** Book::extract: Could not change to" << tmp;
119 ret = extractZip(bookPath);
121 qCritical() << "*** Book::extract: Extracting ZIP failed";
123 QDir::setCurrent(oldDir);
129 qDebug() << "Book::parse";
132 QString opsFileName = opsPath();
133 qDebug() << " Parsing OPS file" << opsFileName;
134 QFile opsFile(opsFileName);
135 QXmlSimpleReader reader;
136 QXmlInputSource *source = new QXmlInputSource(&opsFile);
137 OpsHandler *opsHandler = new OpsHandler(*this);
138 XmlErrorHandler *errorHandler = new XmlErrorHandler();
139 reader.setContentHandler(opsHandler);
140 reader.setErrorHandler(errorHandler);
141 ret = reader.parse(source);
146 // If there is an "ncx" item in content, parse it: That's the real table of
148 if (content.contains("ncx")) {
149 QString ncxFileName = content["ncx"].href;
150 qDebug() << " Parsing NCX file" << ncxFileName;
151 QFile ncxFile(ncxFileName);
152 source = new QXmlInputSource(&ncxFile);
153 NcxHandler *ncxHandler = new NcxHandler(*this);
154 errorHandler = new XmlErrorHandler();
155 reader.setContentHandler(ncxHandler);
156 reader.setErrorHandler(errorHandler);
157 ret = reader.parse(source);
166 bool Book::clearDir(const QString &dir)
172 QDirIterator i(dir, QDirIterator::Subdirectories);
173 while (i.hasNext()) {
174 QString entry = i.next();
175 if (entry.endsWith("/.") || entry.endsWith("/..")) {
178 QFileInfo info(entry);
180 if (!clearDir(entry)) {
185 if (!QFile::remove(entry)) {
186 qCritical() << "*** Book::clearDir: Could not remove" << entry;
187 // FIXME: To be investigated: This is happening too often
211 qDebug() << "Book::load" << path();
213 QString key = "book/" + path() + "/";
214 qDebug() << " key" << key;
217 title = settings.value(key + "title").toString();
218 qDebug() << " title" << title;
219 creators = settings.value(key + "creators").toStringList();
220 date = settings.value(key + "date").toString();
221 publisher = settings.value(key + "publisher").toString();
222 datePublished = settings.value(key + "datepublished").toString();
223 subject = settings.value(key + "subject").toString();
224 source = settings.value(key + "source").toString();
225 rights = settings.value(key + "rights").toString();
226 mLastBookmark.chapter = settings.value(key + "lastchapter").toInt();
227 mLastBookmark.pos = settings.value(key + "lastpos").toReal();
230 int size = settings.value(key + "bookmarks").toInt();
231 for (int i = 0; i < size; i++) {
232 int chapter = settings.value(key + "bookmark" + QString::number(i) +
234 qreal pos = settings.value(key + "bookmark" + QString::number(i) +
236 qDebug() << " Bookmark" << i << "at" << chapter << "," << pos;
237 mBookmarks.append(Bookmark(chapter, pos));
243 qDebug() << "Book::save";
245 QString key = "book/" + path() + "/";
246 qDebug() << " key" << key;
249 settings.setValue(key + "title", title);
250 qDebug() << " title" << title;
251 settings.setValue(key + "creators", creators);
252 settings.setValue(key + "date", date);
253 settings.setValue(key + "publisher", publisher);
254 settings.setValue(key + "datepublished", datePublished);
255 settings.setValue(key + "subject", subject);
256 settings.setValue(key + "source", source);
257 settings.setValue(key + "rights", rights);
258 settings.setValue(key + "lastchapter", mLastBookmark.chapter);
259 settings.setValue(key + "lastpos", mLastBookmark.pos);
262 settings.setValue(key + "bookmarks", mBookmarks.size());
263 for (int i = 0; i < mBookmarks.size(); i++) {
264 qDebug() << " Bookmark" << i << "at" << mBookmarks[i].chapter << ","
265 << mBookmarks[i].pos;
266 settings.setValue(key + "bookmark" + QString::number(i) + "/chapter",
267 mBookmarks[i].chapter);
268 settings.setValue(key + "bookmark" + QString::number(i) + "/pos",
273 void Book::setLastBookmark(int chapter, qreal position)
275 mLastBookmark.chapter = chapter;
276 mLastBookmark.pos = position;
280 Book::Bookmark Book::lastBookmark() const
282 return Book::Bookmark(mLastBookmark);
285 void Book::addBookmark(int chapter, qreal position)
287 mBookmarks.append(Bookmark(chapter, position));
288 qSort(mBookmarks.begin(), mBookmarks.end());
292 void Book::deleteBookmark(int index)
294 mBookmarks.removeAt(index);
298 QList<Book::Bookmark> Book::bookmarks() const
303 QString Book::opsPath()
307 QFile container(tmpDir() + "/META-INF/container.xml");
308 qDebug() << "Book::opsPath" << container.fileName();
309 QXmlSimpleReader reader;
310 QXmlInputSource *source = new QXmlInputSource(&container);
311 ContainerHandler *containerHandler = new ContainerHandler();
312 XmlErrorHandler *errorHandler = new XmlErrorHandler();
313 reader.setContentHandler(containerHandler);
314 reader.setErrorHandler(errorHandler);
315 if (reader.parse(source)) {
316 ret = tmpDir() + "/" + containerHandler->rootFile;
317 mRootPath = QFileInfo(ret).absoluteDir().absolutePath();
318 qDebug() << " OSP path" << ret;
319 qDebug() << " Root dir" << mRootPath;
322 delete containerHandler;
327 QString Book::rootPath() const
332 QString Book::name() const