X-Git-Url: http://git.maemo.org/git/?a=blobdiff_plain;f=bookview.cpp;h=d240070eb44d48b4d54e47e633b2ce12e0d626a7;hb=cdc1598c03ccbb2aabc01e93eef25798a25098fd;hp=d960e26b9bb678d8b88d4940a77f3d5389891f57;hpb=9f29e40a91e0adf35bee94726c5e8c925fed059f;p=dorian diff --git a/bookview.cpp b/bookview.cpp index d960e26..d240070 100644 --- a/bookview.cpp +++ b/bookview.cpp @@ -1,101 +1,131 @@ -#include -#include -#include -#include #include +#include +#include + +#if defined(Q_OS_SYMBIAN) +# include "mediakeysobserver.h" +# include "flickcharm.h" +#endif #include "book.h" #include "bookview.h" #include "library.h" -#include "selectionsuppressor.h" #include "settings.h" - -#ifdef Q_WS_MAC -# define ICON_PREFIX ":/icons/mac/" -#else -# define ICON_PREFIX ":/icons/" -#endif - -BookView::BookView(QWidget *parent): - QWebView(parent), contentIndex(-1), mBook(0), - restore(true), restorePos(0), loadFinished(false) +#include "trace.h" +#include "progress.h" +#include "progressdialog.h" +#include "platform.h" + +BookView::BookView(QWidget *parent): QWebView(parent), contentIndex(-1), + mBook(0), restorePositionAfterLoad(false), positionAfterLoad(0), + restoreFragmentAfterLoad(false), loaded(false), grabbingVolumeKeys(false) { + TRACE; + + // Set up web view defaults settings()->setAttribute(QWebSettings::AutoLoadImages, true); settings()->setAttribute(QWebSettings::JavascriptEnabled, true); + settings()->setAttribute(QWebSettings::JavaEnabled, false); settings()->setAttribute(QWebSettings::PluginsEnabled, false); + settings()->setAttribute(QWebSettings::PrivateBrowsingEnabled, true); + settings()->setAttribute(QWebSettings::JavascriptCanOpenWindows, false); + settings()->setAttribute(QWebSettings::JavascriptCanAccessClipboard, + false); + settings()->setAttribute(QWebSettings::OfflineStorageDatabaseEnabled, + false); + settings()->setAttribute(QWebSettings::OfflineWebApplicationCacheEnabled, + false); + settings()->setAttribute(QWebSettings::LocalStorageEnabled, false); settings()->setAttribute(QWebSettings::ZoomTextOnly, true); settings()->setAttribute(QWebSettings::LocalContentCanAccessRemoteUrls, false); + settings()->setDefaultTextEncoding("utf-8"); page()->setContentEditable(false); - -#if defined(Q_WS_MAEMO_5) - (void)new SelectionSuppressor(this); -#endif QWebFrame *frame = page()->mainFrame(); -#if defined(Q_WS_MAEMO_5) +#if defined(Q_WS_MAEMO_5) || defined(Q_OS_SYMBIAN) frame->setScrollBarPolicy(Qt::Vertical, Qt::ScrollBarAlwaysOff); #endif frame->setScrollBarPolicy(Qt::Horizontal, Qt::ScrollBarAlwaysOff); + connect(this, SIGNAL(loadFinished(bool)), + this, SLOT(onLoadFinished(bool))); + connect(frame, SIGNAL(javaScriptWindowObjectCleared()), + this, SLOT(addJavaScriptObjects())); + + // Suppress unwanted text selections on Maemo and Symbian +#if defined(Q_WS_MAEMO_5) || defined(Q_OS_SYMBIAN) + installEventFilter(this); +#endif + // Pre-load bookmark icon bookmarkImage = QImage(":/icons/bookmark.png"); - connect(this, SIGNAL(loadFinished(bool)), this, SLOT(onLoadFinished(bool))); + // Handle settings changes, force handling initial settings connect(Settings::instance(), SIGNAL(valueChanged(const QString &)), this, SLOT(onSettingsChanged(const QString &))); - Settings *s = Settings::instance(); - s->setValue("zoom", s->value("zoom", 160)); - s->setValue("font", s->value("font", -#if defined(Q_WS_MAEMO_5) || defined(Q_WS_X11) - "Serif" -#elif defined(Q_WS_MAC) - "Hoefler Text" -#else - "Times New Roman" -#endif - )); - s->setValue("scheme", s->value("scheme", "default")); setBook(0); - extractIcons(); -} + // Enable kinetic scrolling +#if defined(Q_WS_MAEMO_5) + scrollerMonitor = 0; + scroller = property("kineticScroller").value(); +#elif defined(Q_OS_SYMBIAN) + scrollerMonitor = 0; + charm = new FlickCharm(this); + charm->activateOn(this); +#endif -BookView::~BookView() -{ - removeIcons(); + // Observe media keys on Symbian +#ifdef Q_OS_SYMBIAN + MediaKeysObserver *observer = MediaKeysObserver::instance(); + connect(observer, SIGNAL(mediaKeyPressed(MediaKeysObserver::MediaKeys)), + this, SLOT(onMediaKeysPressed(MediaKeysObserver::MediaKeys))); +#endif } void BookView::loadContent(int index) { + TRACE; + if (!mBook) { return; } - if ((index < 0) || (index >= mBook->toc.size())) { + if ((index < 0) || (index >= mBook->parts.size())) { return; } - QString contentFile(mBook->content[mBook->toc[index]].href); - if (mBook->toc[index] == "error") { + QString contentFile(mBook->content[mBook->parts[index]].href); + if (mBook->parts[index] == "error") { setHtml(contentFile); - } - else { - loadFinished = false; - emit chapterLoadStart(index); - load(QUrl(contentFile)); + } else { + loaded = false; + emit partLoadStart(index); + QUrl u = QUrl::fromLocalFile(QDir(mBook->rootPath()). + absoluteFilePath(contentFile)); + qDebug() << "Loading" << u; + load(u); } contentIndex = index; } void BookView::setBook(Book *book) { - qDebug() << "Book::setBook" << (book? book->path(): ""); + TRACE; + // Save position in current book setLastBookmark(); + + // Open new book, restore last position if (book != mBook) { mBook = book; if (book) { contentIndex = -1; - book->open(); - goToBookmark(book->lastBookmark()); + if (book->open()) { + restoreLastBookmark(); + } else { + mBook = 0; + contentIndex = 0; + setHtml(tr("Failed to open book")); + } } else { contentIndex = 0; @@ -111,165 +141,232 @@ Book *BookView::book() void BookView::goPrevious() { - loadContent(contentIndex - 1); + TRACE; + if (mBook && (contentIndex > 0)) { + mBook->setLastBookmark(contentIndex - 1, 0); + loadContent(contentIndex - 1); + } } void BookView::goNext() { - loadContent(contentIndex + 1); + TRACE; + if (mBook && (contentIndex < (mBook->parts.size() - 1))) { + mBook->setLastBookmark(contentIndex + 1, 0); + loadContent(contentIndex + 1); + } } void BookView::setLastBookmark() { - qDebug() << "BookView::setLastBookmark"; + TRACE; if (mBook) { - int height = page()->mainFrame()->contentsSize().height(); - int pos = page()->mainFrame()->scrollPosition().y(); + QWebFrame *frame = page()->mainFrame(); + int height = frame->contentsSize().height(); + int pos = frame->scrollPosition().y(); + qDebug() << QString("At %1 (%2%, height %3)"). + arg(pos).arg((qreal)pos / (qreal)height * 100).arg(height); mBook->setLastBookmark(contentIndex, (qreal)pos / (qreal)height); } } +void BookView::restoreLastBookmark() +{ + TRACE; + if (mBook) { + goToBookmark(mBook->lastBookmark()); + } +} + void BookView::goToBookmark(const Book::Bookmark &bookmark) { + TRACE; if (mBook) { - restore = true; - restorePos = bookmark.pos; - if (bookmark.chapter != contentIndex) { - loadContent(bookmark.chapter); + if (bookmark.part != contentIndex) { + qDebug () << "Loading new part" << bookmark.part; + mBook->setLastBookmark(bookmark.part, bookmark.pos); + restorePositionAfterLoad = true; + positionAfterLoad = bookmark.pos; + loadContent(bookmark.part); } else { - onLoadFinished(true); + goToPosition(bookmark.pos); } } } +void BookView::goToPart(int part, const QString &fragment) +{ + TRACE; + if (mBook) { + if (fragment.isEmpty()) { + goToBookmark(Book::Bookmark(part, 0)); + } else { + if (part != contentIndex) { + qDebug() << "Loading new part" << part; + restoreFragmentAfterLoad = true; + fragmentAfterLoad = fragment; + loadContent(part); + } else { + goToFragment(fragment); + showProgress(); + } + } + } +} + +void BookView::goToFragment(const QString &fragment) +{ + TRACE; + if (!fragment.isEmpty()) { + QVariant ret = page()->mainFrame()->evaluateJavaScript( + QString("window.location='") + fragment + "'"); + qDebug() << ret; + // FIXME: setLastBookmark(); + } +} + void BookView::onLoadFinished(bool ok) { - qDebug() << "BookView::onLoadFinished" << ok; - loadFinished = true; - addNavigationBar(); + TRACE; + if (!ok) { + qDebug() << "Not OK"; + return; + } + loaded = true; onSettingsChanged("scheme"); - emit chapterLoadEnd(contentIndex); - if (restore) { - restore = false; - if (ok && mBook) { - int height = page()->mainFrame()->contentsSize().height(); - int scrollPos = (qreal)height * restorePos; - page()->mainFrame()->setScrollPosition(QPoint(0, scrollPos)); - } + onSettingsChanged("zoom"); + onSettingsChanged("font"); + + QTimer::singleShot(210, this, SLOT(restoreAfterLoad())); +} + +void BookView::restoreAfterLoad() +{ + TRACE; + if (restoreFragmentAfterLoad) { + qDebug() << "Restorint to fragment" << fragmentAfterLoad; + goToFragment(fragmentAfterLoad); + restoreFragmentAfterLoad = false; + } else if (restorePositionAfterLoad) { + qDebug() << "Restoring to position" << positionAfterLoad; + goToPosition(positionAfterLoad); + restorePositionAfterLoad = false; } + + emit partLoadEnd(contentIndex); + showProgress(); } void BookView::onSettingsChanged(const QString &key) { - qDebug() << "BookView::onSettingsChanged" << key; + Settings *s = Settings::instance(); + Platform *p = Platform::instance(); + if (key == "zoom") { - setZoomFactor(Settings::instance()->value(key).toFloat() / 100.); + int value = s->value(key, p->defaultZoom()).toInt(); + qDebug() << "BookView::onSettingsChanged: zoom" << value; + setZoomFactor(value / 100.); } else if (key == "font") { - QString face = Settings::instance()->value("font").toString(); - qDebug() << "" << face; + QString face = s->value(key, p->defaultFont()).toString(); + qDebug() << "BookView::onSettingsChanged: font" << face; settings()->setFontFamily(QWebSettings::StandardFont, face); } else if (key == "scheme") { QWebFrame *frame = page()->mainFrame(); QString scheme = Settings::instance()->value("scheme").toString(); - qDebug() << "" << scheme; if ((scheme != "day") && (scheme != "night") && (scheme != "sand") && (scheme != "default")) { scheme = "default"; } + qDebug() << "BookView::onSettingsChanged: scheme" << scheme; QFile script(":/styles/" + scheme + ".js"); script.open(QFile::ReadOnly); QString scriptText = script.readAll(); script.close(); - QVariant ret = frame->evaluateJavaScript(scriptText); - qDebug() << "" << script.fileName() << ":" << scriptText; - qDebug() << "" << ret; + (void)frame->evaluateJavaScript(scriptText); + } + else if (key == "usevolumekeys") { + bool grab = s->value(key, false).toBool(); + qDebug() << "BookView::onSettingsChanged: usevolumekeys" << grab; + grabVolumeKeys(grab); } } void BookView::paintEvent(QPaintEvent *e) { QWebView::paintEvent(e); - if (!mBook) { + if (!mBook || !loaded) { return; } // Paint bookmarks - if (!loadFinished) { - return; - } - QPoint scrollPos = page()->mainFrame()->scrollPosition(); + QWebFrame *frame = page()->mainFrame(); + int contentsHeight = frame->contentsSize().height(); + QPoint scrollPos = frame->scrollPosition(); QPixmap bookmarkPixmap = QPixmap::fromImage(bookmarkImage); QPainter painter(this); foreach (Book::Bookmark b, mBook->bookmarks()) { - if (b.chapter != contentIndex) { + if (b.part != contentIndex) { continue; } - int height = page()->mainFrame()->contentsSize().height(); - int bookmarkPos = (qreal)height * (qreal)b.pos; + int height = contentsHeight; + int bookmarkPos = (int)((qreal)height * (qreal)b.pos); painter.drawPixmap(2, bookmarkPos - scrollPos.y(), bookmarkPixmap); } + QPen pen(Qt::gray); + pen.setStyle(Qt::DotLine); + pen.setWidth(3); + painter.setPen(pen); + if (contentIndex > 0) { + painter.drawLine(0, -scrollPos.y(), width(), -scrollPos.y()); + } + if (contentIndex < (mBook->parts.size() - 1)) { + int h = contentsHeight - scrollPos.y() - 1; + painter.drawLine(0, h, width(), h); + } } void BookView::mousePressEvent(QMouseEvent *e) { QWebView::mousePressEvent(e); -#ifndef Q_WS_MAEMO_5 +#if defined(Q_WS_MAEMO_5) + // Start monitoring kinetic scroll + if (scrollerMonitor) { + killTimer(scrollerMonitor); + scrollerMonitor = 0; + } + if (scroller) { + scrollerMonitor = startTimer(500); + } +#else + // Handle mouse presses on the scroll bar QWebFrame *frame = page()->mainFrame(); if (frame->scrollBarGeometry(Qt::Vertical).contains(e->pos())) { e->accept(); return; } -#endif +#endif // Q_WS_MAEMO_5 e->ignore(); } -void BookView::addBookmark() +void BookView::wheelEvent(QWheelEvent *e) { - int y = page()->mainFrame()->scrollPosition().y(); - int height = page()->mainFrame()->contentsSize().height(); - qDebug() << "BookView::addBookMark" << ((qreal)y / (qreal)height); - mBook->addBookmark(contentIndex, (qreal)y / (qreal)height); - repaint(); + QWebView::wheelEvent(e); + showProgress(); } -void BookView::addNavigationBar() +void BookView::addBookmark(const QString ¬e) { + TRACE; if (!mBook) { return; } - - QString naviPrev = - "" - "" - ""; - QString naviNext = - "" - "" - ""; - if (contentIndex == 0) { - naviPrev = ""; - } - if (contentIndex >= mBook->toc.size() - 1) { - naviNext = ""; - } - - QWebFrame *frame = page()->currentFrame(); - frame->addToJavaScriptWindowObject("bv", this); - QString headerScript = "document.body.innerHTML = '" + - naviPrev + naviNext + "
" + "' + document.body.innerHTML;"; - QString trailerScript = "document.body.innerHTML += '

" + - naviPrev + naviNext + "';"; - - frame->evaluateJavaScript(headerScript); - frame->evaluateJavaScript(trailerScript); + int y = page()->mainFrame()->scrollPosition().y(); + int height = page()->mainFrame()->contentsSize().height(); + qDebug() << ((qreal)y / (qreal)height); + mBook->addBookmark(contentIndex, (qreal)y / (qreal)height, note); + update(); } QString BookView::tmpPath() @@ -277,21 +374,139 @@ QString BookView::tmpPath() return QDir::tempPath() + "/dorian"; } -void BookView::extractIcons() +bool BookView::eventFilter(QObject *o, QEvent *e) +{ +#if 0 + if (e->type() != QEvent::Paint && e->type() != QEvent::MouseMove) { + if (e->type() == QEvent::Resize) { + qDebug() << "BookView::eventFilter QEvent::Resize to" + << page()->mainFrame()->contentsSize().height(); + } else if (e->type() == QEvent::Timer) { + qDebug() << "BookView::eventFilter" << "QEvent::Timer" + << ((QTimerEvent *)e)->timerId(); + } else { + qDebug() << "BookView::eventFilter" << Trace::event(e->type()); + } + } +#endif + + // Work around Qt bug that sometimes selects web view contents during swipe + switch (e->type()) { + case QEvent::MouseButtonPress: + emit suppressedMouseButtonPress(); + mousePressed = true; + break; + case QEvent::MouseButtonRelease: + showProgress(); + mousePressed = false; + break; + case QEvent::MouseMove: + if (mousePressed) { + return true; + } + break; + case QEvent::MouseButtonDblClick: + return true; + default: + break; + } + + return QObject::eventFilter(o, e); +} + +void BookView::addJavaScriptObjects() +{ + page()->mainFrame()->addToJavaScriptWindowObject("bv", this); +} + +void BookView::goToPosition(qreal position) { - qDebug() << "BookView::extractIcons: Extracting to" << tmpPath(); + int contentsHeight = page()->mainFrame()->contentsSize().height(); + int scrollPos = (int)((qreal)contentsHeight * position); + page()->mainFrame()->setScrollPosition(QPoint(0, scrollPos)); + // FIXME: update(); + qDebug() << "BookView::goToPosition: To" << scrollPos << "(" + << (position * 100) << "%, height" << contentsHeight << ")"; +} - QFile next(ICON_PREFIX + QString("/next.png")); - QFile prev(ICON_PREFIX + QString("/previous.png")); +void BookView::showProgress() +{ + if (mBook) { + int contentsHeight = page()->mainFrame()->contentsSize().height(); + qreal pos = (qreal)(page()->mainFrame()->scrollPosition().y()) / + (qreal)contentsHeight; + emit progress(mBook->getProgress(contentIndex, pos)); + } +} - QDir().mkpath(tmpPath()); - next.copy(tmpPath() + "/next.png"); - prev.copy(tmpPath() + "/previous.png"); +void BookView::timerEvent(QTimerEvent *e) +{ +#if defined(Q_WS_MAEMO_5) + if (e->timerId() == scrollerMonitor) { + if (scroller && + ((scroller->state() == QAbstractKineticScroller::AutoScrolling) || + (scroller->state() == QAbstractKineticScroller::Pushing))) { + showProgress(); + } else { + killTimer(scrollerMonitor); + scrollerMonitor = -1; + } + } +#endif + QWebView::timerEvent(e); } -void BookView::removeIcons() +void BookView::goPreviousPage() { - QFile(ICON_PREFIX + QString("/next.png")).remove(); - QFile(ICON_PREFIX + QString("/previous.png")).remove(); - QDir().rmpath(tmpPath()); + QWebFrame *frame = page()->mainFrame(); + int pos = frame->scrollPosition().y(); + frame->scroll(0, -(height() - 19)); + if (pos == frame->scrollPosition().y()) { + if (contentIndex > 0) { + Book::Bookmark bookmark(contentIndex - 1, 1.0); + mBook->setLastBookmark(contentIndex - 1, 1.0); + goToBookmark(bookmark); + } + } else { + showProgress(); + } } + +void BookView::goNextPage() +{ + TRACE; + QWebFrame *frame = page()->mainFrame(); + int pos = frame->scrollPosition().y(); + frame->scroll(0, height() - 19); + if (pos == frame->scrollPosition().y()) { + goNext(); + } else { + // setLastBookmark(); + showProgress(); + } +} + +void BookView::grabVolumeKeys(bool grab) +{ + TRACE; + grabbingVolumeKeys = grab; +} + +#ifdef Q_OS_SYMBIAN + +void BookView::onMediaKeysPressed(MediaKeysObserver::MediaKeys key) +{ + TRACE; + qDebug() << "Key" << (int)key; + if (grabbingVolumeKeys) { + if (key == MediaKeysObserver::EVolIncKey) { + qDebug() << "Volume up"; + goPreviousPage(); + } else if (key == MediaKeysObserver::EVolDecKey){ + qDebug() << "Volume down"; + goNextPage(); + } + } +} + +#endif // Q_OS_SYMBIAN