9 # include <QAbstractKineticScroller>
20 # define ICON_PREFIX ":/icons/mac/"
22 # define ICON_PREFIX ":/icons/"
25 BookView::BookView(QWidget *parent):
26 QWebView(parent), contentIndex(-1), mBook(0),
27 restorePositionAfterLoad(false), positionAfterLoad(0), loaded(false),
28 contentsHeight(0), decorated(false), scrollerMonitor(-1)
30 Trace t("BookView::BookView");
31 settings()->setAttribute(QWebSettings::AutoLoadImages, true);
32 settings()->setAttribute(QWebSettings::JavascriptEnabled, true);
33 settings()->setAttribute(QWebSettings::JavaEnabled, false);
34 settings()->setAttribute(QWebSettings::PluginsEnabled, false);
35 settings()->setAttribute(QWebSettings::PrivateBrowsingEnabled, true);
36 settings()->setAttribute(QWebSettings::JavascriptCanOpenWindows, false);
37 settings()->setAttribute(QWebSettings::JavascriptCanAccessClipboard, false);
38 settings()->setAttribute(QWebSettings::OfflineStorageDatabaseEnabled, false);
39 settings()->setAttribute(QWebSettings::OfflineWebApplicationCacheEnabled,
41 settings()->setAttribute(QWebSettings::LocalStorageEnabled, false);
42 settings()->setAttribute(QWebSettings::ZoomTextOnly, true);
43 settings()->setAttribute(QWebSettings::LocalContentCanAccessRemoteUrls,
45 settings()->setDefaultTextEncoding("utf-8");
46 page()->setContentEditable(false);
48 #if defined(Q_WS_MAEMO_5)
49 // Suppress unwanted text selections on Maemo
50 installEventFilter(this);
52 QWebFrame *frame = page()->mainFrame();
53 #if defined(Q_WS_MAEMO_5)
54 frame->setScrollBarPolicy(Qt::Vertical, Qt::ScrollBarAlwaysOff);
56 frame->setScrollBarPolicy(Qt::Horizontal, Qt::ScrollBarAlwaysOff);
58 bookmarkImage = QImage(":/icons/bookmark.png");
60 connect(this, SIGNAL(loadFinished(bool)), this, SLOT(onLoadFinished(bool)));
61 connect(frame, SIGNAL(javaScriptWindowObjectCleared()),
62 this, SLOT(addJavaScriptObjects()));
63 connect(frame, SIGNAL(contentsSizeChanged(const QSize &)),
64 this, SLOT(onContentsSizeChanged(const QSize &)));
65 connect(Settings::instance(), SIGNAL(valueChanged(const QString &)),
66 this, SLOT(onSettingsChanged(const QString &)));
67 Settings *s = Settings::instance();
68 s->setValue("zoom", s->value("zoom", 160));
69 s->setValue("font", s->value("font",
70 #if defined(Q_WS_MAEMO_5) || defined(Q_WS_X11)
72 #elif defined(Q_WS_MAC)
78 s->setValue("scheme", s->value("scheme", "default"));
84 scroller = property("kineticScroller").value<QAbstractKineticScroller *>();
86 t.trace("Got scroller");
93 Trace t("BookView::~BookView");
97 void BookView::loadContent(int index)
99 Trace t("BookView::loadContent");
103 if ((index < 0) || (index >= mBook->parts.size())) {
107 QString contentFile(mBook->content[mBook->parts[index]].href);
108 if (mBook->parts[index] == "error") {
109 setHtml(contentFile);
114 emit partLoadStart(index);
115 load(QUrl(contentFile));
117 contentIndex = index;
120 void BookView::setBook(Book *book)
122 Trace t("BookView::setBook");
124 // Save position in current book
127 // Open new book, restore last position
133 restoreLastBookmark();
137 setHtml(tr("Failed to open book"));
142 setHtml(tr("No book"));
147 Book *BookView::book()
152 void BookView::goPrevious()
154 Trace t("BookView::goPrevious");
155 loadContent(contentIndex - 1);
158 void BookView::goNext()
160 Trace t("BookView::goNext");
161 loadContent(contentIndex + 1);
164 void BookView::setLastBookmark()
166 Trace t("BookView::setLastBookmark");
168 int height = contentsHeight;
169 int pos = page()->mainFrame()->scrollPosition().y();
170 t.trace(QString("At %1 (%2%, height %3)").
171 arg(pos).arg((qreal)pos / (qreal)height * 100).arg(height));
172 mBook->setLastBookmark(contentIndex, (qreal)pos / (qreal)height);
176 void BookView::restoreLastBookmark()
178 Trace t("BookView::restoreLastBookmark");
180 goToBookmark(mBook->lastBookmark());
184 void BookView::goToBookmark(const Book::Bookmark &bookmark)
186 Trace t("BookView::goToBookmark");
188 if (bookmark.part != contentIndex) {
189 t.trace(QString("Loading new part %1").arg(bookmark.part));
190 mBook->setLastBookmark(bookmark.part, bookmark.pos);
191 restorePositionAfterLoad = true;
192 positionAfterLoad = bookmark.pos;
193 loadContent(bookmark.part);
195 goToPosition(bookmark.pos);
200 void BookView::onLoadFinished(bool ok)
202 Trace t("BookView::onLoadFinished");
209 onSettingsChanged("scheme");
210 emit partLoadEnd(contentIndex);
214 void BookView::onSettingsChanged(const QString &key)
216 Trace t("BookView::onSettingsChanged " + key);
218 setZoomFactor(Settings::instance()->value(key).toFloat() / 100.);
220 else if (key == "font") {
221 QString face = Settings::instance()->value("font").toString();
222 settings()->setFontFamily(QWebSettings::StandardFont, face);
224 else if (key == "scheme") {
225 QWebFrame *frame = page()->mainFrame();
226 QString scheme = Settings::instance()->value("scheme").toString();
227 if ((scheme != "day") && (scheme != "night") && (scheme != "sand") &&
228 (scheme != "default")) {
231 QFile script(":/styles/" + scheme + ".js");
232 script.open(QFile::ReadOnly);
233 QString scriptText = script.readAll();
235 QVariant ret = frame->evaluateJavaScript(scriptText);
239 void BookView::paintEvent(QPaintEvent *e)
241 QWebView::paintEvent(e);
242 if (!mBook || !loaded) {
247 QPoint scrollPos = page()->mainFrame()->scrollPosition();
248 QPixmap bookmarkPixmap = QPixmap::fromImage(bookmarkImage);
249 QPainter painter(this);
250 foreach (Book::Bookmark b, mBook->bookmarks()) {
251 if (b.part != contentIndex) {
254 int height = contentsHeight;
255 int bookmarkPos = (qreal)height * (qreal)b.pos;
256 painter.drawPixmap(2, bookmarkPos - scrollPos.y(), bookmarkPixmap);
260 void BookView::mousePressEvent(QMouseEvent *e)
262 QWebView::mousePressEvent(e);
265 scrollerMonitor = startTimer(250);
268 QWebFrame *frame = page()->mainFrame();
269 if (frame->scrollBarGeometry(Qt::Vertical).contains(e->pos())) {
273 #endif // Q_WS_MAEMO_5
277 void BookView::wheelEvent(QWheelEvent *e)
279 QWebView::wheelEvent(e);
283 void BookView::addBookmark()
285 Trace t("BookView::addBookmark");
289 int y = page()->mainFrame()->scrollPosition().y();
290 int height = page()->mainFrame()->contentsSize().height();
291 t.trace(QString().setNum((qreal)y / (qreal)height));
292 mBook->addBookmark(contentIndex, (qreal)y / (qreal)height);
296 void BookView::addNavigationBar()
298 Trace t("BookView::addNavigationBar");
304 "<a href=\"javascript:bv.goPrevious();\">"
305 "<img width=\"95\" height=\"95\" style=\"float:left;clear:none;\" "
311 "<a href=\"javascript:bv.goNext();\">"
312 "<img width=\"95\" height=\"95\" style=\"float:right;clear:none;\" "
317 if (contentIndex == 0) {
320 if (contentIndex >= mBook->parts.size() - 1) {
324 QWebFrame *frame = page()->currentFrame();
325 QString headerScript = "document.body.innerHTML = '" +
326 naviPrev + naviNext + "<br />" + "' + document.body.innerHTML;";
327 QString trailerScript = "document.body.innerHTML += '<br /><br />" +
328 naviPrev + naviNext + "';";
330 frame->evaluateJavaScript(headerScript);
331 frame->evaluateJavaScript(trailerScript);
335 QString BookView::tmpPath()
337 return QDir::tempPath() + "/dorian";
340 void BookView::extractIcons()
342 QFile next(ICON_PREFIX + QString("/next.png"));
343 QFile prev(ICON_PREFIX + QString("/previous.png"));
345 QDir().mkpath(tmpPath());
346 next.copy(tmpPath() + "/next.png");
347 prev.copy(tmpPath() + "/previous.png");
350 void BookView::removeIcons()
352 QFile(ICON_PREFIX + QString("/next.png")).remove();
353 QFile(ICON_PREFIX + QString("/previous.png")).remove();
354 QDir().rmpath(tmpPath());
357 bool BookView::eventFilter(QObject *o, QEvent *e)
360 if (e->type() != QEvent::Paint && e->type() != QEvent::MouseMove) {
361 if (e->type() == QEvent::Resize) {
362 Trace::trace(QString("BookView::eventFilter QEvent::Resize to %1").
363 arg(page()->mainFrame()->contentsSize().height()));
365 Trace::trace(QString("BookView::eventFilter %1").
366 arg(Trace::event(e->type())));
372 case QEvent::MouseButtonPress:
373 emit suppressedMouseButtonPress();
376 case QEvent::MouseButtonRelease:
378 mousePressed = false;
380 case QEvent::MouseMove:
385 case QEvent::MouseButtonDblClick:
391 return QObject::eventFilter(o, e);
394 void BookView::addJavaScriptObjects()
396 page()->mainFrame()->addToJavaScriptWindowObject("bv", this);
399 void BookView::onContentsSizeChanged(const QSize &size)
401 contentsHeight = size.height();
403 if (restorePositionAfterLoad) {
404 Trace::trace("BookView::onContentSizeChanged: Time to restore");
405 restorePositionAfterLoad = false;
406 goToPosition(positionAfterLoad);
411 void BookView::leaveEvent(QEvent *e)
413 Trace t("BookView::leaveEvent");
414 // Save current position, to be restored later
416 QWebView::leaveEvent(e);
419 void BookView::enterEvent(QEvent *e)
421 Trace t("BookView::enterEvent");
422 // Restore position saved at Leave event. This seems to be required,
423 // after temporarily switching from portrait to landscape and back
424 restoreLastBookmark();
425 QWebView::enterEvent(e);
428 void BookView::goToPosition(qreal position)
430 int scrollPos = (qreal)contentsHeight * position;
431 page()->mainFrame()->setScrollPosition(QPoint(0, scrollPos));
433 Trace::trace(QString("BookView::goToPosition: To %1 (%2%, height %3)").
434 arg(scrollPos).arg(position * 100).arg(contentsHeight));
437 void BookView::showProgress()
440 qreal pos = (qreal)(page()->mainFrame()->scrollPosition().y()) /
441 (qreal)contentsHeight;
442 emit progress(mBook->getProgress(contentIndex, pos));
446 void BookView::timerEvent(QTimerEvent *e)
448 if (e->timerId() == scrollerMonitor) {
451 ((scroller->state() == QAbstractKineticScroller::AutoScrolling) ||
452 (scroller->state() == QAbstractKineticScroller::Pushing))) {
455 killTimer(scrollerMonitor);
458 #endif // Q_WS_MAEMO_5