X-Git-Url: https://vcs.maemo.org/git/?a=blobdiff_plain;f=bookview.cpp;h=b751393c174e51fba51ab53e049d6af3df2e65cb;hb=HEAD;hp=f273d1f1d1f1ddd31c357976841fc59be86f9611;hpb=3ddf918a91680bdc490fd12c707f2d4166d68681;p=dorian diff --git a/bookview.cpp b/bookview.cpp index f273d1f..b751393 100644 --- a/bookview.cpp +++ b/bookview.cpp @@ -1,13 +1,9 @@ -#include -#include -#include -#include #include -#include +#include +#include -#if defined(Q_WS_MAEMO_5) -# include -#elif defined(Q_OS_SYMBIAN) +#if defined(Q_OS_SYMBIAN) +# include "mediakeysobserver.h" # include "flickcharm.h" #endif @@ -17,21 +13,29 @@ #include "settings.h" #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), loaded(false), - contentsHeight(0) +BookView::BookView(QWidget *parent): QWebView(parent), contentIndex(-1), + mBook(0), restorePositionAfterLoad(false), positionAfterLoad(0), + restoreFragmentAfterLoad(false), loaded(false), grabbingVolumeKeys(false) { TRACE; + + // Create timer for scheduling restores + restoreTimer = new QTimer(this); + + // 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::JavascriptCanAccessClipboard, + false); + settings()->setAttribute(QWebSettings::OfflineStorageDatabaseEnabled, + false); settings()->setAttribute(QWebSettings::OfflineWebApplicationCacheEnabled, false); settings()->setAttribute(QWebSettings::LocalStorageEnabled, false); @@ -40,57 +44,51 @@ BookView::BookView(QWidget *parent): false); settings()->setDefaultTextEncoding("utf-8"); page()->setContentEditable(false); - -#if defined(Q_WS_MAEMO_5) || defined(Q_OS_SYMBIAN) - // Suppress unwanted text selections on Maemo and Symbian - installEventFilter(this); -#endif QWebFrame *frame = page()->mainFrame(); #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))); - connect(frame, SIGNAL(javaScriptWindowObjectCleared()), - this, SLOT(addJavaScriptObjects())); - connect(frame, SIGNAL(contentsSizeChanged(const QSize &)), - this, SLOT(onContentsSizeChanged(const QSize &))); + // 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); + // Enable kinetic scrolling #if defined(Q_WS_MAEMO_5) scrollerMonitor = 0; scroller = property("kineticScroller").value(); #elif defined(Q_OS_SYMBIAN) - FlickCharm *charm = new FlickCharm(this); + scrollerMonitor = 0; + charm = new FlickCharm(this); charm->activateOn(this); #endif -} -BookView::~BookView() -{ - TRACE; + // 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; } @@ -101,8 +99,7 @@ void BookView::loadContent(int index) QString contentFile(mBook->content[mBook->parts[index]].href); if (mBook->parts[index] == "error") { setHtml(contentFile); - } - else { + } else { loaded = false; emit partLoadStart(index); QUrl u = QUrl::fromLocalFile(QDir(mBook->rootPath()). @@ -117,26 +114,34 @@ void BookView::setBook(Book *book) { TRACE; - // Save position in current book + // Bail out if new book is the same as current book + if (book == mBook) { + return; + } + + // Save reading position of current book setLastBookmark(); - // Open new book, restore last position - if (book != mBook) { - mBook = book; - if (book) { - contentIndex = -1; - if (book->open()) { - restoreLastBookmark(); - } else { - mBook = 0; - contentIndex = 0; - setHtml(tr("Failed to open book")); - } - } - else { - contentIndex = 0; - setHtml(tr("No book")); - } + // Set new book as the current book + mBook = book; + + // Bail out if new book is null + if (!book) { + contentIndex = 0; + setHtml(tr("No book")); + return; + } + + // Open new book + if (book->open()) { + // Restore last reading position - this will force + // a reload as well + contentIndex = -1; + restoreLastBookmark(); + } else { + mBook = 0; + contentIndex = 0; + setHtml(tr("Failed to open book")); } } @@ -163,15 +168,18 @@ void BookView::goNext() } } -void BookView::setLastBookmark() +void BookView::setLastBookmark(bool fast) { TRACE; if (mBook) { - int height = contentsHeight; - 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); + mBook->setLastBookmark(contentIndex, (qreal)pos / (qreal)height, fast); + } else { + qDebug() << "(no book)"; } } @@ -194,11 +202,42 @@ void BookView::goToBookmark(const Book::Bookmark &bookmark) positionAfterLoad = bookmark.pos; loadContent(bookmark.part); } else { + emit partLoadEnd(contentIndex); 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; + } +} + void BookView::onLoadFinished(bool ok) { TRACE; @@ -208,18 +247,70 @@ void BookView::onLoadFinished(bool ok) } loaded = true; onSettingsChanged("scheme"); + onSettingsChanged("zoom"); + onSettingsChanged("font"); + scheduleRestoreAfterLoad(); +} + +void BookView::scheduleRestoreAfterLoad() +{ + TRACE; + if (restoreTimer->isActive()) { + // Ignore request if a restore is already in progress + return; + } + + disconnect(restoreTimer, SIGNAL(timeout()), this, 0); + connect(restoreTimer, SIGNAL(timeout()), this, SLOT(restoreAfterLoad())); + restoreTimer->setSingleShot(true); + restoreTimer->start(210); +} + +void BookView::scheduleRestoreLastBookmark() +{ + TRACE; + if (restoreTimer->isActive()) { + // Ignore request if a restore is already in progress + return; + } + + disconnect(restoreTimer, SIGNAL(timeout()), this, 0); + connect(restoreTimer, SIGNAL(timeout()), this, + SLOT(restoreLastBookmark())); + restoreTimer->setSingleShot(true); + restoreTimer->start(210); +} + +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) { - TRACE; + 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(); + QString face = s->value(key, p->defaultFont()).toString(); + qDebug() << "BookView::onSettingsChanged: font" << face; settings()->setFontFamily(QWebSettings::StandardFont, face); } else if (key == "scheme") { @@ -229,11 +320,17 @@ void BookView::onSettingsChanged(const QString &key) (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); + (void)frame->evaluateJavaScript(scriptText); + } + else if (key == "usevolumekeys") { + bool grab = s->value(key, false).toBool(); + qDebug() << "BookView::onSettingsChanged: usevolumekeys" << grab; + grabVolumeKeys(grab); } } @@ -245,7 +342,9 @@ void BookView::paintEvent(QPaintEvent *e) } // Paint bookmarks - 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()) { @@ -256,12 +355,25 @@ void BookView::paintEvent(QPaintEvent *e) int bookmarkPos = (int)((qreal)height * (qreal)b.pos); painter.drawPixmap(2, bookmarkPos - scrollPos.y(), bookmarkPixmap); } + + // Paint page separator(s) + 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); -#ifdef Q_WS_MAEMO_5 +#if defined(Q_WS_MAEMO_5) // Start monitoring kinetic scroll if (scrollerMonitor) { killTimer(scrollerMonitor); @@ -270,14 +382,16 @@ void BookView::mousePressEvent(QMouseEvent *e) if (scroller) { scrollerMonitor = startTimer(500); } +#elif defined(Q_OS_SYMBIAN) + // Do nothing #else - // Handle mouse presses on the scroll bar + // Handle mouse press on the scroll bar QWebFrame *frame = page()->mainFrame(); if (frame->scrollBarGeometry(Qt::Vertical).contains(e->pos())) { e->accept(); return; } -#endif // Q_WS_MAEMO_5 +#endif e->ignore(); } @@ -307,6 +421,7 @@ QString BookView::tmpPath() 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" @@ -318,15 +433,17 @@ bool BookView::eventFilter(QObject *o, QEvent *e) 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: +#ifndef Q_OS_SYMBIAN // Too heavy on Symbian showProgress(); +#endif mousePressed = false; break; case QEvent::MouseMove: @@ -345,38 +462,14 @@ bool BookView::eventFilter(QObject *o, QEvent *e) void BookView::addJavaScriptObjects() { - page()->mainFrame()->addToJavaScriptWindowObject("bv", this); -} - -void BookView::onContentsSizeChanged(const QSize &size) -{ - contentsHeight = size.height(); - if (restorePositionAfterLoad) { - qDebug() << "BookView::onContentSizeChanged: Time to restore"; - restorePositionAfterLoad = false; - goToPosition(positionAfterLoad); - } -} - -void BookView::leaveEvent(QEvent *e) -{ TRACE; - // Save current position, to be restored later - setLastBookmark(); - QWebView::leaveEvent(e); -} - -void BookView::enterEvent(QEvent *e) -{ - TRACE; - // Restore position saved at Leave event. This seems to be required, - // after temporarily switching from portrait to landscape and back - restoreLastBookmark(); - QWebView::enterEvent(e); + page()->mainFrame()->addToJavaScriptWindowObject("bv", this); } void BookView::goToPosition(qreal position) { + TRACE; + int contentsHeight = page()->mainFrame()->contentsSize().height(); int scrollPos = (int)((qreal)contentsHeight * position); page()->mainFrame()->setScrollPosition(QPoint(0, scrollPos)); // FIXME: update(); @@ -386,7 +479,9 @@ void BookView::goToPosition(qreal position) void BookView::showProgress() { + TRACE; if (mBook) { + int contentsHeight = page()->mainFrame()->contentsSize().height(); qreal pos = (qreal)(page()->mainFrame()->scrollPosition().y()) / (qreal)contentsHeight; emit progress(mBook->getProgress(contentIndex, pos)); @@ -395,7 +490,7 @@ void BookView::showProgress() void BookView::timerEvent(QTimerEvent *e) { -#ifdef Q_WS_MAEMO_5 +#if defined(Q_WS_MAEMO_5) if (e->timerId() == scrollerMonitor) { if (scroller && ((scroller->state() == QAbstractKineticScroller::AutoScrolling) || @@ -403,34 +498,30 @@ void BookView::timerEvent(QTimerEvent *e) showProgress(); } else { killTimer(scrollerMonitor); + scrollerMonitor = -1; } } -#endif +#endif // Q_WS_MAEMO_5 + QWebView::timerEvent(e); } -void BookView::keyPressEvent(QKeyEvent* event) +void BookView::hideEvent(QHideEvent *e) { - switch (event->key()) { - case Qt::Key_F7: - goNextPage(); - event->accept(); - break; - case Qt::Key_F8: - goPreviousPage(); - event->accept(); - break; - default: - ; - } - QWebView::keyPressEvent(event); + Trace t("BookView::hideEvent"); + +#if defined(Q_OS_SYMBIAN) + setLastBookmark(); +#endif + + QWebView::hideEvent(e); } void BookView::goPreviousPage() { QWebFrame *frame = page()->mainFrame(); - int pos = frame->scrollPosition().y(); - frame->scroll(0, -height()); + const int pos = frame->scrollPosition().y(); + frame->scroll(0, -1); if (pos == frame->scrollPosition().y()) { if (contentIndex > 0) { Book::Bookmark bookmark(contentIndex - 1, 1.0); @@ -439,6 +530,15 @@ void BookView::goPreviousPage() } } else { showProgress(); + QPropertyAnimation *slide = + new QPropertyAnimation(frame, "scrollPosition"); + const QPoint *offset = new QPoint(0, height() - 18); + slide->setDuration(400); + slide->setStartValue(frame->scrollPosition()); + slide->setEndValue(frame->scrollPosition() - *offset); + slide->setEasingCurve(QEasingCurve::OutQuad); + slide->start(QAbstractAnimation::DeleteWhenStopped); + delete offset; } } @@ -446,12 +546,45 @@ void BookView::goNextPage() { TRACE; QWebFrame *frame = page()->mainFrame(); - int pos = frame->scrollPosition().y(); - frame->scroll(0, height()); + const int pos = frame->scrollPosition().y(); + frame->scroll(0, 1); if (pos == frame->scrollPosition().y()) { goNext(); } else { - setLastBookmark(); showProgress(); + QPropertyAnimation *slide = + new QPropertyAnimation(frame, "scrollPosition"); + const QPoint *offset = new QPoint(0, (height() - 18)); + slide->setDuration(400); + slide->setStartValue(frame->scrollPosition()); + slide->setEndValue(frame->scrollPosition() + *offset); + slide->setEasingCurve(QEasingCurve::OutQuad); + slide->start(QAbstractAnimation::DeleteWhenStopped); + delete offset; } } + +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