Improve identification if bookmark's chapter. Add some AppAward
[dorian] / model / book.cpp
index c28af23..d209816 100644 (file)
@@ -1,4 +1,5 @@
 #include <qtextdocument.h>  // Qt::escape is currently defined here...
+#include <QtGui>
 
 #include "book.h"
 #include "opshandler.h"
 
 const int COVER_WIDTH = 53;
 const int COVER_HEIGHT = 59;
+const int COVER_MAX = 512 * 1024;
 
-static QImage makeCover(const QString &path)
-{
-    return QImage(path).scaled(COVER_WIDTH, COVER_HEIGHT,
-        Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation).
-        scaled(COVER_WIDTH, COVER_HEIGHT, Qt::KeepAspectRatio);
-}
-
-Book::Book(const QString &p, QObject *parent): QObject(parent)
+Book::Book(const QString &p, QObject *parent): QObject(parent), loaded(false)
 {
     mPath = "";
     if (p.size()) {
         QFileInfo info(p);
         mPath = info.absoluteFilePath();
         title = info.baseName();
-        cover = makeCover(":/icons/book.png");
         mTempFile.open();
     }
 }
 
-QString Book::path() const
+Book::~Book()
+{
+    close();
+}
+
+QString Book::path()
 {
     return mPath;
 }
@@ -43,6 +42,7 @@ bool Book::open()
     qDebug() << path();
     close();
     clear();
+    load();
     if (path().isEmpty()) {
         title = "No book";
         return false;
@@ -64,6 +64,7 @@ void Book::peek()
     qDebug() << path();
     close();
     clear();
+    load();
     if (path().isEmpty()) {
         title = "No book";
         return;
@@ -101,6 +102,7 @@ bool Book::extract(const QStringList &excludedExtensions)
     QString tmp = tmpDir();
     qDebug() << "Extracting" << mPath << "to" << tmp;
 
+    load();
     QDir::setCurrent(QDir::rootPath());
     if (!clearDir(tmp)) {
         qCritical() << "Book::extract: Failed to remove" << tmp;
@@ -144,6 +146,8 @@ bool Book::parse()
 {
     TRACE;
 
+    load();
+
     // Parse OPS file
     bool ret = false;
     QString opsFileName = opsPath();
@@ -268,7 +272,12 @@ void Book::clear()
 
 void Book::load()
 {
+    if (loaded) {
+        return;
+    }
+
     TRACE;
+    loaded = true;
     qDebug() << "path" << path();
 
     QVariantHash data = BookDb::instance()->load(path());
@@ -283,8 +292,7 @@ void Book::load()
     rights = data["rights"].toString();
     mLastBookmark.part = data["lastpart"].toInt();
     mLastBookmark.pos = data["lastpos"].toReal();
-    cover = data["cover"].value<QImage>().scaled(COVER_WIDTH,
-        COVER_HEIGHT, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
+    cover = data["cover"].value<QImage>();
     if (cover.isNull()) {
         cover = makeCover(":/icons/book.png");
     }
@@ -301,6 +309,7 @@ void Book::save()
 {
     TRACE;
 
+    load();
     QVariantHash data;
     data["title"] = title;
     data["creators"] = creators;
@@ -325,19 +334,21 @@ void Book::save()
 void Book::setLastBookmark(int part, qreal position)
 {
     TRACE;
-    qDebug() << "part" << part << "position" << position;
+    load();
     mLastBookmark.part = part;
     mLastBookmark.pos = position;
     save();
 }
 
-Book::Bookmark Book::lastBookmark() const
+Book::Bookmark Book::lastBookmark()
 {
+    load();
     return Book::Bookmark(mLastBookmark);
 }
 
 void Book::addBookmark(int part, qreal position, const QString &note)
 {
+    load();
     mBookmarks.append(Bookmark(part, position, note));
     qSort(mBookmarks.begin(), mBookmarks.end());
     save();
@@ -345,18 +356,21 @@ void Book::addBookmark(int part, qreal position, const QString &note)
 
 void Book::deleteBookmark(int index)
 {
+    load();
     mBookmarks.removeAt(index);
     save();
 }
 
-QList<Book::Bookmark> Book::bookmarks() const
+QList<Book::Bookmark> Book::bookmarks()
 {
+    load();
     return mBookmarks;
 }
 
 QString Book::opsPath()
 {
     TRACE;
+    load();
     QString ret;
 
     QFile container(tmpDir() + "/META-INF/container.xml");
@@ -378,34 +392,41 @@ QString Book::opsPath()
     return ret;
 }
 
-QString Book::rootPath() const
+QString Book::rootPath()
 {
+    load();
     return mRootPath;
 }
 
-QString Book::name() const
+QString Book::name()
 {
+    load();
     if (title.size()) {
         QString ret = title;
         if (creators.length()) {
-            ret += "\nBy " + creators[0];
-            for (int i = 1; i < creators.length(); i++) {
-                ret += ", " + creators[i];
-            }
+            ret += "\nBy " + creators.join(", ");
         }
         return ret;
-    } else {
-        return path();
     }
+    return path();
 }
 
-QString Book::shortName() const
+QString Book::shortName()
 {
+    load();
     return (title.isEmpty())? QFileInfo(path()).baseName(): title;
 }
 
+QImage Book::coverImage()
+{
+    load();
+    return cover;
+}
+
 int Book::chapterFromPart(int index)
 {
+    TRACE;
+    load();
     int ret = -1;
 
     QString partId = parts[index];
@@ -414,24 +435,24 @@ int Book::chapterFromPart(int index)
     for (int i = 0; i < chapters.size(); i++) {
         QString id = chapters[i];
         QString href = content[id].href;
-        QString baseRef(href);
-        QUrl url(QString("file://") + href);
-        if (url.hasFragment()) {
-            QString fragment = url.fragment();
-            baseRef.chop(fragment.length() + 1);
+        int hashPos = href.indexOf("#");
+        if (hashPos != -1) {
+            href = href.left(hashPos);
         }
-        if (baseRef == partHref) {
+        if (href == partHref) {
             ret = i;
             // Don't break, keep looking
         }
     }
 
+    qDebug() << "Part" << index << partId << partHref << ":" << ret;
     return ret;
 }
 
 int Book::partFromChapter(int index, QString &fragment)
 {
-    Trace t("Book::partFromChapter");
+    TRACE;
+    load();
     fragment.clear();
     QString id = chapters[index];
     QString href = content[id].href;
@@ -461,6 +482,7 @@ int Book::partFromChapter(int index, QString &fragment)
 
 qreal Book::getProgress(int part, qreal position)
 {
+    load();
     Q_ASSERT(part < parts.size());
     QString key;
     qreal partSize = 0;
@@ -476,7 +498,8 @@ qreal Book::getProgress(int part, qreal position)
 bool Book::extractMetaData()
 {
     QStringList excludedExtensions;
-    excludedExtensions << ".html" << ".xhtml" << ".xht" << ".htm";
+    excludedExtensions << ".html" << ".xhtml" << ".xht" << ".htm" << ".gif"
+            << ".css" << "*.ttf" << "mimetype";
     return extract(excludedExtensions);
 }
 
@@ -484,10 +507,7 @@ void Book::upgrade()
 {
     TRACE;
 
-    qDebug() << path();
-
     // Load book from old database (QSettings)
-
     QSettings settings;
     QString key = "book/" + path() + "/";
     title = settings.value(key + "title").toString();
@@ -501,10 +521,11 @@ void Book::upgrade()
     rights = settings.value(key + "rights").toString();
     mLastBookmark.part = settings.value(key + "lastpart").toInt();
     mLastBookmark.pos = settings.value(key + "lastpos").toReal();
-    cover = settings.value(key + "cover").value<QImage>().scaled(COVER_WIDTH,
-        COVER_HEIGHT, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
+    cover = settings.value(key + "cover").value<QImage>();
     if (cover.isNull()) {
         cover = makeCover(":/icons/book.png");
+    } else {
+        cover = makeCover(QPixmap::fromImage(cover));
     }
     int size = settings.value(key + "bookmarks").toInt();
     for (int i = 0; i < size; i++) {
@@ -517,13 +538,47 @@ void Book::upgrade()
         mBookmarks.append(Bookmark(part, pos));
     }
 
-    // Save book to new database
+    // Remove QSettings
+    settings.remove("book/" + path());
 
+    // Save book to new database
     save();
 }
 
 void Book::remove()
 {
     TRACE;
+    close();
     BookDb::instance()->remove(path());
 }
+
+QImage Book::makeCover(const QString &fileName)
+{
+    TRACE;
+    qDebug() << fileName;
+    QFileInfo info(fileName);
+    if (info.isReadable() && (info.size() < COVER_MAX)) {
+        return makeCover(QPixmap(fileName));
+    }
+    return makeCover(QPixmap(":/icons/book.png"));
+}
+
+QImage Book::makeCover(const QPixmap &pixmap)
+{
+    TRACE;
+    QPixmap src = pixmap.scaled(COVER_WIDTH, COVER_HEIGHT,
+        Qt::KeepAspectRatio, Qt::SmoothTransformation);
+    QPixmap transparent(COVER_WIDTH, COVER_HEIGHT);
+    transparent.fill(Qt::transparent);
+
+    QPainter p;
+    p.begin(&transparent);
+    p.setCompositionMode(QPainter::CompositionMode_Source);
+    p.drawPixmap((COVER_WIDTH - src.width()) / 2,
+                 (COVER_HEIGHT - src.height()) / 2, src);
+    p.end();
+
+    return transparent.toImage();
+}
+
+