/* * Copyright 2012 by Marco Martin * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2, * or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details * * You should have received a copy of the GNU General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "pageitem.h" #include "documentitem.h" #include #include #include #include #include #include #include #include "ui/pagepainter.h" #include "settings.h" #define REDRAW_TIMEOUT 250 PageItem::PageItem(QDeclarativeItem *parent) : QDeclarativeItem(parent), Okular::View( QString::fromLatin1( "PageView" ) ), m_page(0), m_smooth(false), m_intentionalDraw(false), m_bookmarked(false), m_observerId(PAGEVIEW_ID) { m_observerId = PAGEVIEW_ID; setFlag(QGraphicsItem::ItemHasNoContents, false); m_redrawTimer = new QTimer(this); m_redrawTimer->setInterval(REDRAW_TIMEOUT); m_redrawTimer->setSingleShot(true); connect(m_redrawTimer, SIGNAL(timeout()), this, SLOT(delayedRedraw())); } PageItem::~PageItem() { } void PageItem::setFlickable(QDeclarativeItem *flickable) { if (m_flickable.data() == flickable) { return; } //check the object can act as a flickable if (!flickable->property("contentX").isValid() || !flickable->property("contentY").isValid()) { return; } if (m_flickable) { disconnect(m_flickable.data(), 0, this, 0); } //check the object can act as a flickable if (!flickable->property("contentX").isValid() || !flickable->property("contentY").isValid()) { m_flickable.clear(); return; } m_flickable = flickable; if (flickable) { connect(flickable, SIGNAL(contentXChanged()), this, SLOT(contentXChanged())); connect(flickable, SIGNAL(contentYChanged()), this, SLOT(contentYChanged())); } emit flickableChanged(); } QDeclarativeItem *PageItem::flickable() const { return m_flickable.data(); } DocumentItem *PageItem::document() const { return m_documentItem.data(); } void PageItem::setDocument(DocumentItem *doc) { if (doc == m_documentItem.data() || !doc) { return; } m_page = 0; disconnect(doc, 0, this, 0); m_documentItem = doc; Observer *observer = m_documentItem.data()->observerFor(m_observerId); connect(observer, SIGNAL(pageChanged(int, int)), this, SLOT(pageHasChanged(int, int))); connect(doc->document()->bookmarkManager(), SIGNAL(bookmarksChanged(KUrl)), this, SLOT(checkBookmarksChanged())); setPageNumber(0); emit documentChanged(); m_redrawTimer->start(); } int PageItem::pageNumber() const { return m_viewPort.pageNumber; } void PageItem::setPageNumber(int number) { if ((m_page && m_viewPort.pageNumber == number) || !m_documentItem || !m_documentItem.data()->isOpened() || number < 0 || (uint)number >= m_documentItem.data()->document()->pages()) { return; } m_viewPort.pageNumber = number; m_page = m_documentItem.data()->document()->page(number); emit pageNumberChanged(); emit implicitWidthChanged(); emit implicitHeightChanged(); checkBookmarksChanged(); m_redrawTimer->start(); } int PageItem::implicitWidth() const { if (m_page) { return m_page->width(); } return 0; } int PageItem::implicitHeight() const { if (m_page) { return m_page->height(); } return 0; } void PageItem::setSmooth(const bool smooth) { if (smooth == m_smooth) { return; } m_smooth = smooth; update(); } bool PageItem::smooth() const { return m_smooth; } bool PageItem::isBookmarked() { return m_bookmarked; } void PageItem::setBookmarked(bool bookmarked) { if (!m_documentItem) { return; } if (bookmarked == m_bookmarked) { return; } if (bookmarked) { m_documentItem.data()->document()->bookmarkManager()->addBookmark(m_viewPort.pageNumber); } else { m_documentItem.data()->document()->bookmarkManager()->removeBookmark(m_viewPort.pageNumber); } m_bookmarked = bookmarked; emit bookmarkedChanged(); } QStringList PageItem::bookmarks() const { QStringList list; foreach(const KBookmark &bookmark, m_documentItem.data()->document()->bookmarkManager()->bookmarks(m_viewPort.pageNumber)) { list << bookmark.url().prettyUrl(); } return list; } void PageItem::goToBookmark(const QString &bookmark) { Okular::DocumentViewport viewPort(KUrl(bookmark).htmlRef()); setPageNumber(viewPort.pageNumber); //Are we in a flickable? if (m_flickable) { //normalizedX is a proportion, so contentX will be the difference between document and viewport times normalizedX m_flickable.data()->setProperty("contentX", qMax((qreal)0, width() - m_flickable.data()->width()) * viewPort.rePos.normalizedX); m_flickable.data()->setProperty("contentY", qMax((qreal)0, height() - m_flickable.data()->height()) * viewPort.rePos.normalizedY); } } void PageItem::setBookmarkAtPos(qreal x, qreal y) { Okular::DocumentViewport viewPort(m_viewPort); viewPort.rePos.normalizedX = x; viewPort.rePos.normalizedY = y; m_documentItem.data()->document()->bookmarkManager()->addBookmark(viewPort); emit bookmarksChanged(); } void PageItem::removeBookmark(const QString &bookmark) { m_documentItem.data()->document()->bookmarkManager()->removeBookmark(bookmark); emit bookmarksChanged(); } //Reimplemented void PageItem::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) { if (newGeometry.size().isEmpty()) { return; } if (newGeometry.size() != oldGeometry.size()) { m_redrawTimer->start(); } QDeclarativeItem::geometryChanged(newGeometry, oldGeometry); //Why aren't they automatically emuitted? emit widthChanged(); emit heightChanged(); } void PageItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) { if (!m_documentItem || !m_page) { QDeclarativeItem::paint(painter, option, widget); return; } const bool setAA = m_smooth && !(painter->renderHints() & QPainter::Antialiasing); if (setAA) { painter->save(); painter->setRenderHint(QPainter::Antialiasing, true); } const int priority = m_observerId == PAGEVIEW_ID ? PAGEVIEW_PRELOAD_PRIO : THUMBNAILS_PRELOAD_PRIO; if (m_intentionalDraw) { QLinkedList requestedPixmaps; requestedPixmaps.push_back(new Okular::PixmapRequest(m_observerId, m_viewPort.pageNumber, width(), height(), priority, true)); const Okular::Document::PixmapRequestFlag prf = (m_observerId == PAGEVIEW_ID) ? Okular::Document::RemoveAllPrevious : Okular::Document::NoOption; m_documentItem.data()->document()->requestPixmaps(requestedPixmaps, prf); m_intentionalDraw = false; } const int flags = PagePainter::Accessibility | PagePainter::Highlights | PagePainter::Annotations; PagePainter::paintPageOnPainter(painter, m_page, m_observerId, flags, width(), height(), option->exposedRect.toRect()); if (setAA) { painter->restore(); } } //Protected slots void PageItem::delayedRedraw() { if (m_documentItem && m_page) { m_intentionalDraw = true; update(); } } void PageItem::pageHasChanged(int page, int flags) { if (m_viewPort.pageNumber == page) { if (flags == 32) { // skip bounding box updates //kDebug() << "32" << m_page->boundingBox(); } else if (flags == Okular::DocumentObserver::Pixmap) { // if pixmaps have updated, just repaint .. don't bother updating pixmaps AGAIN update(); } else { m_redrawTimer->start(); } } } void PageItem::checkBookmarksChanged() { if (!m_documentItem) { return; } bool newBookmarked = m_documentItem.data()->document()->bookmarkManager()->isBookmarked(m_viewPort.pageNumber); if (m_bookmarked != newBookmarked) { m_bookmarked = newBookmarked; emit bookmarkedChanged(); } //TODO: check the page emit bookmarksChanged(); } void PageItem::contentXChanged() { if (!m_flickable || !m_flickable.data()->property("contentX").isValid()) { return; } m_viewPort.rePos.normalizedX = m_flickable.data()->property("contentX").toReal(); } void PageItem::contentYChanged() { if (!m_flickable || !m_flickable.data()->property("contentY").isValid()) { return; } m_viewPort.rePos.normalizedY = m_flickable.data()->property("contentY").toReal(); } void PageItem::setIsThumbnail(bool thumbnail) { if (thumbnail == (m_observerId == THUMBNAILS_ID)) { return; } m_observerId = thumbnail ? THUMBNAILS_ID : PAGEVIEW_ID; if (thumbnail) { m_smooth = false; } /* m_redrawTimer->setInterval(thumbnail ? 0 : REDRAW_TIMEOUT); m_redrawTimer->setSingleShot(true); */ } #include "pageitem.moc"