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"
19 const int COVER_WIDTH = 53;
20 const int COVER_HEIGHT = 59;
22 Book::Book(const QString &p, QObject *parent): QObject(parent)
27 mPath = info.absoluteFilePath();
28 title = info.baseName();
29 cover = QImage(":/icons/book.png").scaled(COVER_WIDTH, COVER_HEIGHT,
30 Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
34 QString Book::path() const
41 Trace t("Book::open");
62 Trace t("Book::close");
65 QDir::setCurrent(QDir::rootPath());
69 QString Book::tmpDir() const
71 return QDir::tempPath() + "/dorian/book";
76 Trace t("Book::extract");
78 QString tmp = tmpDir();
79 t.trace("Extracting " + mPath + " to " + tmp);
81 QDir::setCurrent(QDir::rootPath());
83 qCritical() << "Book::extract: Failed to remove" << tmp;
88 qCritical() << "Book::extract: Could not create" << tmp;
92 // If book comes from resource, copy it to the temporary directory first
93 QString bookPath = path();
94 if (bookPath.startsWith(":/books/")) {
96 QString dst(tmp + "/book.epub");
98 qCritical() << "Book::extract: Failed to copy built-in book to"
105 QString oldDir = QDir::currentPath();
106 if (!QDir::setCurrent(tmp)) {
107 qCritical() << "Book::extract: Could not change to" << tmp;
110 ret = extractZip(bookPath);
112 qCritical() << "Book::extract: Extracting ZIP failed";
114 QDir::setCurrent(oldDir);
120 Trace t("Book::parse");
124 QString opsFileName = opsPath();
125 t.trace("Parsing OPS file" + opsFileName);
126 QFile opsFile(opsFileName);
127 QXmlSimpleReader reader;
128 QXmlInputSource *source = new QXmlInputSource(&opsFile);
129 OpsHandler *opsHandler = new OpsHandler(*this);
130 XmlErrorHandler *errorHandler = new XmlErrorHandler();
131 reader.setContentHandler(opsHandler);
132 reader.setErrorHandler(errorHandler);
133 ret = reader.parse(source);
139 if (content.contains("cover-image")) {
140 t.trace("Loading cover image from " + content["cover-image"].href);
141 cover = QImage(content["cover-image"].href).scaled(COVER_WIDTH,
142 COVER_HEIGHT, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
143 } else if (content.contains("img-cover-jpeg")) {
144 t.trace("Loading cover image from " + content["img-cover-jpeg"].href);
145 cover = QImage(content["img-cover-jpeg"].href).scaled(COVER_WIDTH,
146 COVER_HEIGHT, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
149 // If there is an "ncx" item in content, parse it: That's the real table of
151 if (content.contains("ncx")) {
152 QString ncxFileName = content["ncx"].href;
153 t.trace("Parsing NCX file " + ncxFileName);
154 QFile ncxFile(ncxFileName);
155 source = new QXmlInputSource(&ncxFile);
156 NcxHandler *ncxHandler = new NcxHandler(*this);
157 errorHandler = new XmlErrorHandler();
158 reader.setContentHandler(ncxHandler);
159 reader.setErrorHandler(errorHandler);
160 ret = reader.parse(source);
169 bool Book::clearDir(const QString &dir)
175 QDirIterator i(dir, QDirIterator::Subdirectories);
176 while (i.hasNext()) {
177 QString entry = i.next();
178 if (entry.endsWith("/.") || entry.endsWith("/..")) {
181 QFileInfo info(entry);
183 if (!clearDir(entry)) {
188 if (!QFile::remove(entry)) {
189 qCritical() << "Book::clearDir: Could not remove" << entry;
190 // FIXME: To be investigated: This is happening too often
214 Trace t("Book::load");
215 t.trace("path: " + path());
217 QString key = "book/" + path() + "/";
218 t.trace("key: " + key);
221 title = settings.value(key + "title").toString();
223 creators = settings.value(key + "creators").toStringList();
224 date = settings.value(key + "date").toString();
225 publisher = settings.value(key + "publisher").toString();
226 datePublished = settings.value(key + "datepublished").toString();
227 subject = settings.value(key + "subject").toString();
228 source = settings.value(key + "source").toString();
229 rights = settings.value(key + "rights").toString();
230 mLastBookmark.chapter = settings.value(key + "lastchapter").toInt();
231 mLastBookmark.pos = settings.value(key + "lastpos").toReal();
232 cover = settings.value(key + "cover").value<QImage>().scaled(COVER_WIDTH,
233 COVER_HEIGHT, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
234 if (cover.isNull()) {
235 cover = QImage(":/icons/book.png").scaled(COVER_WIDTH, COVER_HEIGHT,
236 Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
240 int size = settings.value(key + "bookmarks").toInt();
241 for (int i = 0; i < size; i++) {
242 int chapter = settings.value(key + "bookmark" + QString::number(i) +
244 qreal pos = settings.value(key + "bookmark" + QString::number(i) +
246 t.trace(QString("Bookmark %1 at chapter %2, %3").
247 arg(i).arg(chapter).arg(pos));
248 mBookmarks.append(Bookmark(chapter, pos));
254 Trace t("Book::save");
256 QString key = "book/" + path() + "/";
257 t.trace("key: " + key);
260 settings.setValue(key + "title", title);
261 t.trace("title: " + title);
262 settings.setValue(key + "creators", creators);
263 settings.setValue(key + "date", date);
264 settings.setValue(key + "publisher", publisher);
265 settings.setValue(key + "datepublished", datePublished);
266 settings.setValue(key + "subject", subject);
267 settings.setValue(key + "source", source);
268 settings.setValue(key + "rights", rights);
269 settings.setValue(key + "lastchapter", mLastBookmark.chapter);
270 settings.setValue(key + "lastpos", mLastBookmark.pos);
271 settings.setValue(key + "cover", cover);
274 settings.setValue(key + "bookmarks", mBookmarks.size());
275 for (int i = 0; i < mBookmarks.size(); i++) {
276 t.trace(QString("Bookmark %1 at %2, %3").
277 arg(i).arg(mBookmarks[i].chapter).arg(mBookmarks[i].pos));
278 settings.setValue(key + "bookmark" + QString::number(i) + "/chapter",
279 mBookmarks[i].chapter);
280 settings.setValue(key + "bookmark" + QString::number(i) + "/pos",
285 void Book::setLastBookmark(int chapter, qreal position)
287 mLastBookmark.chapter = chapter;
288 mLastBookmark.pos = position;
292 Book::Bookmark Book::lastBookmark() const
294 return Book::Bookmark(mLastBookmark);
297 void Book::addBookmark(int chapter, qreal position)
299 mBookmarks.append(Bookmark(chapter, position));
300 qSort(mBookmarks.begin(), mBookmarks.end());
304 void Book::deleteBookmark(int index)
306 mBookmarks.removeAt(index);
310 QList<Book::Bookmark> Book::bookmarks() const
315 QString Book::opsPath()
317 Trace t("Book::opsPath");
320 QFile container(tmpDir() + "/META-INF/container.xml");
321 t.trace(container.fileName());
322 QXmlSimpleReader reader;
323 QXmlInputSource *source = new QXmlInputSource(&container);
324 ContainerHandler *containerHandler = new ContainerHandler();
325 XmlErrorHandler *errorHandler = new XmlErrorHandler();
326 reader.setContentHandler(containerHandler);
327 reader.setErrorHandler(errorHandler);
328 if (reader.parse(source)) {
329 ret = tmpDir() + "/" + containerHandler->rootFile;
330 mRootPath = QFileInfo(ret).absoluteDir().absolutePath();
331 t.trace("OSP path: " + ret);
332 t.trace("Root dir: " + mRootPath);
335 delete containerHandler;
340 QString Book::rootPath() const
345 QString Book::name() const
349 if (creators.length()) {
350 ret += "\nBy " + creators[0];
351 for (int i = 1; i < creators.length(); i++) {
352 ret += ", " + creators[i];
361 QString Book::shortName() const
364 return QFileInfo(path()).baseName();