okular/active/components/pageitem.cpp

366 lines
9.7 KiB
C++
Raw Normal View History

/*
* Copyright 2012 by Marco Martin <mart@kde.org>
*
* This program is free software; you can redistribute it and/or modify
2012-10-03 09:32:42 +00:00
* 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
2012-10-03 09:32:42 +00:00
* GNU General Public License for more details
*
2012-10-03 09:32:42 +00:00
* 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 <QPainter>
#include <QTimer>
#include <QStyleOptionGraphicsItem>
2012-08-01 16:14:12 +00:00
#include <core/bookmarkmanager.h>
#include <core/document.h>
#include <core/generator.h>
2012-08-01 16:14:12 +00:00
#include <core/page.h>
2012-10-02 12:19:09 +00:00
#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),
2012-05-25 19:28:53 +00:00
m_smooth(false),
2012-10-07 19:09:15 +00:00
m_intentionalDraw(false),
m_bookmarked(false),
m_observerId(PAGEVIEW_ID)
{
m_observerId = PAGEVIEW_ID;
setFlag(QGraphicsItem::ItemHasNoContents, false);
m_redrawTimer = new QTimer(this);
2012-10-07 19:09:15 +00:00
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;
2012-08-01 16:14:12 +00:00
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)),
2012-08-01 16:14:12 +00:00
this, SLOT(checkBookmarksChanged()));
setPageNumber(0);
emit documentChanged();
2012-10-07 19:09:15 +00:00
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();
2012-08-01 16:14:12 +00:00
checkBookmarksChanged();
2012-10-07 19:09:15 +00:00
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;
}
2012-08-01 16:14:12 +00:00
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);
2012-08-01 16:14:12 +00:00
} else {
m_documentItem.data()->document()->bookmarkManager()->removeBookmark(m_viewPort.pageNumber);
2012-08-01 16:14:12 +00:00
}
m_bookmarked = bookmarked;
emit bookmarkedChanged();
}
QStringList PageItem::bookmarks() const
{
QStringList list;
foreach(const KBookmark &bookmark, m_documentItem.data()->document()->bookmarkManager()->bookmarks(m_viewPort.pageNumber)) {
2012-10-12 08:51:32 +00:00
list << bookmark.url().prettyUrl();
}
return list;
}
void PageItem::goToBookmark(const QString &bookmark)
{
2012-10-12 08:51:32 +00:00
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;
}
2012-05-25 19:28:53 +00:00
if (newGeometry.size() != oldGeometry.size()) {
2012-10-07 19:09:15 +00:00
m_redrawTimer->start();
2012-05-25 19:28:53 +00:00
}
QDeclarativeItem::geometryChanged(newGeometry, oldGeometry);
//Why aren't they automatically emuitted?
emit widthChanged();
emit heightChanged();
}
void PageItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
2012-05-22 14:08:03 +00:00
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);
}
2012-05-22 14:08:03 +00:00
const int priority = m_observerId == PAGEVIEW_ID ? PAGEVIEW_PRELOAD_PRIO : THUMBNAILS_PRELOAD_PRIO;
2012-05-25 19:28:53 +00:00
if (m_intentionalDraw) {
2012-10-07 19:09:15 +00:00
QLinkedList<Okular::PixmapRequest *> 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);
2012-10-07 19:09:15 +00:00
m_intentionalDraw = false;
2012-05-25 19:28:53 +00:00
}
2012-05-22 14:08:03 +00:00
const int flags = PagePainter::Accessibility | PagePainter::Highlights | PagePainter::Annotations;
2012-05-25 19:45:40 +00:00
PagePainter::paintPageOnPainter(painter, m_page, m_observerId, flags, width(), height(), option->exposedRect.toRect());
if (setAA) {
painter->restore();
}
}
//Protected slots
void PageItem::delayedRedraw()
{
2012-05-22 14:08:03 +00:00
if (m_documentItem && m_page) {
2012-05-25 19:28:53 +00:00
m_intentionalDraw = true;
2012-05-22 14:08:03 +00:00
update();
}
}
2012-10-07 19:09:09 +00:00
void PageItem::pageHasChanged(int page, int flags)
{
if (m_viewPort.pageNumber == page) {
2012-10-07 19:09:09 +00:00
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();
}
2012-05-22 14:03:34 +00:00
}
}
2012-08-01 16:14:12 +00:00
void PageItem::checkBookmarksChanged()
{
if (!m_documentItem) {
return;
}
bool newBookmarked = m_documentItem.data()->document()->bookmarkManager()->isBookmarked(m_viewPort.pageNumber);
2012-08-01 16:14:12 +00:00
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();
2012-08-01 16:14:12 +00:00
}
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"