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"));
83 scroller = property("kineticScroller").value<QAbstractKineticScroller *>();
89 Trace t("BookView::~BookView");
93 void BookView::loadContent(int index)
95 Trace t("BookView::loadContent");
99 if ((index < 0) || (index >= mBook->parts.size())) {
103 QString contentFile(mBook->content[mBook->parts[index]].href);
104 if (mBook->parts[index] == "error") {
105 setHtml(contentFile);
110 emit partLoadStart(index);
111 load(QUrl(contentFile));
113 contentIndex = index;
116 void BookView::setBook(Book *book)
118 Trace t("BookView::setBook");
120 // Save position in current book
123 // Open new book, restore last position
129 restoreLastBookmark();
133 setHtml(tr("Failed to open book"));
138 setHtml(tr("No book"));
143 Book *BookView::book()
148 void BookView::goPrevious()
150 Trace t("BookView::goPrevious");
151 loadContent(contentIndex - 1);
154 void BookView::goNext()
156 Trace t("BookView::goNext");
157 loadContent(contentIndex + 1);
160 void BookView::setLastBookmark()
162 Trace t("BookView::setLastBookmark");
164 int height = contentsHeight;
165 int pos = page()->mainFrame()->scrollPosition().y();
166 t.trace(QString("At %1 (%2%, height %3)").
167 arg(pos).arg((qreal)pos / (qreal)height * 100).arg(height));
168 mBook->setLastBookmark(contentIndex, (qreal)pos / (qreal)height);
172 void BookView::restoreLastBookmark()
174 Trace t("BookView::restoreLastBookmark");
176 goToBookmark(mBook->lastBookmark());
180 void BookView::goToBookmark(const Book::Bookmark &bookmark)
182 Trace t("BookView::goToBookmark");
184 if (bookmark.part != contentIndex) {
185 t.trace(QString("Loading new part %1").arg(bookmark.part));
186 mBook->setLastBookmark(bookmark.part, bookmark.pos);
187 restorePositionAfterLoad = true;
188 positionAfterLoad = bookmark.pos;
189 loadContent(bookmark.part);
191 goToPosition(bookmark.pos);
196 void BookView::onLoadFinished(bool ok)
198 Trace t("BookView::onLoadFinished");
205 onSettingsChanged("scheme");
206 emit partLoadEnd(contentIndex);
210 void BookView::onSettingsChanged(const QString &key)
212 Trace t("BookView::onSettingsChanged " + key);
214 setZoomFactor(Settings::instance()->value(key).toFloat() / 100.);
216 else if (key == "font") {
217 QString face = Settings::instance()->value("font").toString();
218 settings()->setFontFamily(QWebSettings::StandardFont, face);
220 else if (key == "scheme") {
221 QWebFrame *frame = page()->mainFrame();
222 QString scheme = Settings::instance()->value("scheme").toString();
223 if ((scheme != "day") && (scheme != "night") && (scheme != "sand") &&
224 (scheme != "default")) {
227 QFile script(":/styles/" + scheme + ".js");
228 script.open(QFile::ReadOnly);
229 QString scriptText = script.readAll();
231 QVariant ret = frame->evaluateJavaScript(scriptText);
235 void BookView::paintEvent(QPaintEvent *e)
237 QWebView::paintEvent(e);
238 if (!mBook || !loaded) {
243 QPoint scrollPos = page()->mainFrame()->scrollPosition();
244 QPixmap bookmarkPixmap = QPixmap::fromImage(bookmarkImage);
245 QPainter painter(this);
246 foreach (Book::Bookmark b, mBook->bookmarks()) {
247 if (b.part != contentIndex) {
250 int height = contentsHeight;
251 int bookmarkPos = (qreal)height * (qreal)b.pos;
252 painter.drawPixmap(2, bookmarkPos - scrollPos.y(), bookmarkPixmap);
256 void BookView::mousePressEvent(QMouseEvent *e)
258 QWebView::mousePressEvent(e);
261 scrollerMonitor = startTimer(250);
264 QWebFrame *frame = page()->mainFrame();
265 if (frame->scrollBarGeometry(Qt::Vertical).contains(e->pos())) {
269 #endif // Q_WS_MAEMO_5
273 void BookView::wheelEvent(QWheelEvent *e)
275 QWebView::wheelEvent(e);
279 void BookView::addBookmark()
281 Trace t("BookView::addBookmark");
285 int y = page()->mainFrame()->scrollPosition().y();
286 int height = page()->mainFrame()->contentsSize().height();
287 t.trace(QString().setNum((qreal)y / (qreal)height));
288 mBook->addBookmark(contentIndex, (qreal)y / (qreal)height);
292 void BookView::addNavigationBar()
294 Trace t("BookView::addNavigationBar");
300 "<a href=\"javascript:bv.goPrevious();\">"
301 "<img width=\"95\" height=\"95\" style=\"float:left;clear:none;\" "
307 "<a href=\"javascript:bv.goNext();\">"
308 "<img width=\"95\" height=\"95\" style=\"float:right;clear:none;\" "
313 if (contentIndex == 0) {
316 if (contentIndex >= mBook->parts.size() - 1) {
320 QWebFrame *frame = page()->currentFrame();
321 QString headerScript = "document.body.innerHTML = '" +
322 naviPrev + naviNext + "<br />" + "' + document.body.innerHTML;";
323 QString trailerScript = "document.body.innerHTML += '<br /><br />" +
324 naviPrev + naviNext + "';";
326 frame->evaluateJavaScript(headerScript);
327 frame->evaluateJavaScript(trailerScript);
331 QString BookView::tmpPath()
333 return QDir::tempPath() + "/dorian";
336 void BookView::extractIcons()
338 QFile next(ICON_PREFIX + QString("/next.png"));
339 QFile prev(ICON_PREFIX + QString("/previous.png"));
341 QDir().mkpath(tmpPath());
342 next.copy(tmpPath() + "/next.png");
343 prev.copy(tmpPath() + "/previous.png");
346 void BookView::removeIcons()
348 QFile(ICON_PREFIX + QString("/next.png")).remove();
349 QFile(ICON_PREFIX + QString("/previous.png")).remove();
350 QDir().rmpath(tmpPath());
353 bool BookView::eventFilter(QObject *o, QEvent *e)
355 if (e->type() != QEvent::Paint && e->type() != QEvent::MouseMove) {
356 if (e->type() == QEvent::Resize) {
357 Trace::trace(QString("BookView::eventFilter QEvent::Resize to %1").
358 arg(page()->mainFrame()->contentsSize().height()));
360 Trace::trace(QString("BookView::eventFilter %1").
361 arg(Trace::event(e->type())));
366 case QEvent::MouseButtonPress:
367 emit suppressedMouseButtonPress();
370 case QEvent::MouseButtonRelease:
372 mousePressed = false;
374 case QEvent::MouseMove:
379 case QEvent::MouseButtonDblClick:
385 return QObject::eventFilter(o, e);
388 void BookView::addJavaScriptObjects()
390 page()->mainFrame()->addToJavaScriptWindowObject("bv", this);
393 void BookView::onContentsSizeChanged(const QSize &size)
395 contentsHeight = size.height();
397 if (restorePositionAfterLoad) {
398 Trace::trace("BookView::onContentSizeChanged: Time to restore");
399 restorePositionAfterLoad = false;
400 goToPosition(positionAfterLoad);
405 void BookView::leaveEvent(QEvent *e)
407 Trace t("BookView::leaveEvent");
408 // Save current position, to be restored later
410 QWebView::leaveEvent(e);
413 void BookView::enterEvent(QEvent *e)
415 Trace t("BookView::enterEvent");
416 // Restore position saved at Leave event. This seems to be required,
417 // after temporarily switching from portrait to landscape and back
418 restoreLastBookmark();
419 QWebView::enterEvent(e);
422 void BookView::goToPosition(qreal position)
424 int scrollPos = (qreal)contentsHeight * position;
425 page()->mainFrame()->setScrollPosition(QPoint(0, scrollPos));
427 Trace::trace(QString("BookView::goToPosition: To %1 (%2%, height %3)").
428 arg(scrollPos).arg(position * 100).arg(contentsHeight));
431 void BookView::showProgress()
434 qreal pos = (qreal)(page()->mainFrame()->scrollPosition().y()) /
435 (qreal)contentsHeight;
436 emit progress(mBook->getProgress(contentIndex, pos));
440 void BookView::timerEvent(QTimerEvent *e)
442 if (e->timerId() == scrollerMonitor) {
445 ((scroller->state() == QAbstractKineticScroller::AutoScrolling) ||
446 (scroller->state() == QAbstractKineticScroller::Pushing))) {
449 killTimer(scrollerMonitor);
451 #endif // Q_WS_MAEMO_5
455 void BookView::keyPressEvent(QKeyEvent* event)
457 switch (event->key()) {
469 QWebView::keyPressEvent(event);
472 void BookView::goPreviousPage()
474 QWebFrame *frame = page()->mainFrame();
475 int pos = frame->scrollPosition().y();
476 frame->scroll(0, -height());
477 if (pos == frame->scrollPosition().y()) {
478 if (contentIndex > 0) {
479 goToBookmark(Book::Bookmark(contentIndex - 1, 1.0));
486 void BookView::goNextPage()
488 Trace t("BookView::goNextPage");
489 QWebFrame *frame = page()->mainFrame();
490 int pos = frame->scrollPosition().y();
491 frame->scroll(0, height());
492 if (pos == frame->scrollPosition().y()) {