3
Copyright 2012 Adam Reichold
5
This file is part of qpdfview.
7
qpdfview is free software: you can redistribute it and/or modify
8
it under the terms of the GNU General Public License as published by
9
the Free Software Foundation, either version 2 of the License, or
10
(at your option) any later version.
12
qpdfview is distributed in the hope that it will be useful,
13
but WITHOUT ANY WARRANTY; without even the implied warranty of
14
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
GNU General Public License for more details.
17
You should have received a copy of the GNU General Public License
18
along with qpdfview. If not, see <http://www.gnu.org/licenses/>.
22
#include "documentview.h"
26
const qreal DocumentView::pageSpacing = 5.0;
27
const qreal DocumentView::thumbnailSpacing = 2.5;
29
qreal DocumentView::thumbnailWidth = 96.0;
30
qreal DocumentView::thumbnailHeight = 144.0;
32
const qreal DocumentView::zoomBy = 0.1;
34
const qreal DocumentView::mininumScaleFactor = 0.1;
35
const qreal DocumentView::maximumScaleFactor = 5.0;
37
bool DocumentView::fitToEqualWidth = false;
39
bool DocumentView::highlightLinks = true;
40
bool DocumentView::externalLinks = false;
44
DocumentView::PageItem::PageItem(QGraphicsItem* parent, QGraphicsScene* scene) : QGraphicsItem(parent, scene),
52
m_highlightTransform(),
55
setAcceptHoverEvents(true);
58
DocumentView::PageItem::~PageItem()
60
m_render.waitForFinished();
68
QRectF DocumentView::PageItem::boundingRect() const
70
DocumentView* parent = qobject_cast< DocumentView* >(scene()->parent()); Q_ASSERT(parent);
72
return QRectF(0.0, 0.0, qCeil(m_scale * parent->m_resolutionX / 72.0 * m_size.width()), qCeil(m_scale * parent->m_resolutionY / 72.0 * m_size.height()));
75
void DocumentView::PageItem::paint(QPainter* painter, const QStyleOptionGraphicsItem*, QWidget*)
77
DocumentView* parent = qobject_cast< DocumentView* >(scene()->parent()); Q_ASSERT(parent);
81
painter->fillRect(boundingRect(), QBrush(Qt::white));
83
#ifdef RENDER_IN_PAINT
85
parent->m_documentMutex.lock();
87
QImage image = m_page->renderToImage(m_scale * parent->m_resolutionX, m_scale * parent->m_resolutionY);
89
parent->m_documentMutex.unlock();
91
painter->drawImage(0.0, 0.0, image);
95
parent->m_pageCacheMutex.lock();
97
DocumentView::PageCacheKey key(m_index, m_scale * parent->m_resolutionX, m_scale * parent->m_resolutionY);
99
if(parent->m_pageCache.contains(key))
101
DocumentView::PageCacheValue& value = parent->m_pageCache[key];
103
value.time = QTime::currentTime();
104
painter->drawImage(0.0, 0.0, value.image);
108
if(!m_render.isRunning())
110
m_render = QtConcurrent::run(this, &DocumentView::PageItem::render, m_scale, false);
114
parent->m_pageCacheMutex.unlock();
118
painter->setPen(QPen(Qt::black));
119
painter->drawRect(boundingRect());
123
if(DocumentView::highlightLinks)
127
painter->setTransform(m_linkTransform, true);
128
painter->setPen(QPen(QColor(255, 0, 0, 127)));
130
foreach(Link link, m_links)
132
painter->drawRect(link.area);
142
painter->setTransform(m_highlightTransform, true);
144
if(parent->m_highlightAll)
146
foreach(QRectF highlight, parent->m_results.values(m_index))
148
painter->fillRect(highlight, QBrush(QColor(0, 255, 0, 127)));
156
if(!m_rubberBand.isNull())
158
painter->setPen(QPen(Qt::DashLine));
159
painter->drawRect(m_rubberBand);
163
void DocumentView::PageItem::hoverEnterEvent(QGraphicsSceneHoverEvent* event)
168
void DocumentView::PageItem::hoverMoveEvent(QGraphicsSceneHoverEvent* event)
170
DocumentView* parent = qobject_cast< DocumentView* >(scene()->parent()); Q_ASSERT(parent);
172
QApplication::restoreOverrideCursor();
174
foreach(Link link, m_links)
176
if(m_linkTransform.mapRect(link.area).contains(event->pos()))
178
QApplication::setOverrideCursor(Qt::PointingHandCursor);
182
QToolTip::showText(event->screenPos(), tr("Go to page %1.").arg(link.page), parent);
184
else if(!link.url.isEmpty())
186
QToolTip::showText(event->screenPos(), tr("Open URL \"%1\".").arg(link.url), parent);
193
QToolTip::hideText();
196
void DocumentView::PageItem::hoverLeaveEvent(QGraphicsSceneHoverEvent* event)
201
void DocumentView::PageItem::mousePressEvent(QGraphicsSceneMouseEvent* event)
203
DocumentView* parent = qobject_cast< DocumentView* >(scene()->parent()); Q_ASSERT(parent);
205
if(event->button() == Qt::LeftButton)
207
foreach(Link link, m_links)
209
if(m_linkTransform.mapRect(link.area).contains(event->pos()))
213
parent->setCurrentPage(link.page, link.top);
215
else if(!link.url.isEmpty())
217
if(DocumentView::externalLinks)
219
QDesktopServices::openUrl(QUrl(link.url));
223
QMessageBox::information(parent, tr("Information"), tr("External links are disabled in the settings."));
233
if(event->modifiers() == Qt::ShiftModifier)
235
m_rubberBand = QRectF(event->pos(), QSizeF());
250
void DocumentView::PageItem::mouseMoveEvent(QGraphicsSceneMouseEvent* event)
252
if(!m_rubberBand.isNull())
254
m_rubberBand.setBottomRight(event->pos());
256
update(boundingRect());
266
void DocumentView::PageItem::mouseReleaseEvent(QGraphicsSceneMouseEvent* event)
268
DocumentView* parent = qobject_cast< DocumentView* >(scene()->parent()); Q_ASSERT(parent);
270
if(!m_rubberBand.isNull())
272
m_rubberBand.setBottomRight(event->pos());
274
m_rubberBand = m_rubberBand.normalized();
276
// copy text or image
280
QAction* copyTextAction = menu.addAction(tr("Copy &text"));
281
QAction* copyImageAction = menu.addAction(tr("Copy &image"));
283
QAction* action = menu.exec(event->screenPos());
285
if(action == copyTextAction)
287
parent->m_documentMutex.lock();
289
QString text = m_page->text(m_highlightTransform.inverted().mapRect(m_rubberBand));
291
parent->m_documentMutex.unlock();
295
QApplication::clipboard()->setText(text);
298
else if(action == copyImageAction)
300
parent->m_documentMutex.lock();
302
QImage image = m_page->renderToImage(m_scale * parent->m_resolutionX, m_scale * parent->m_resolutionY, m_rubberBand.x(), m_rubberBand.y(), m_rubberBand.width(), m_rubberBand.height());
304
parent->m_documentMutex.unlock();
308
QApplication::clipboard()->setImage(image);
312
m_rubberBand = QRectF();
314
update(boundingRect());
324
void DocumentView::PageItem::render(qreal scale, bool prefetch)
326
DocumentView* parent = qobject_cast< DocumentView* >(scene()->parent()); Q_ASSERT(parent);
328
QRectF rect = parent->m_pageTransform.mapRect(boundingRect()).translated(pos());
329
QRectF visibleRect = parent->m_view->mapToScene(parent->m_view->viewport()->rect()).boundingRect();
331
if(!rect.intersects(visibleRect) && !prefetch)
336
#ifdef RENDER_FROM_DISK
338
Poppler::Document* document = Poppler::Document::load(parent->m_filePath);
346
Poppler::Page* page = document->page(m_index);
354
Poppler::Document::RenderHints renderHints = parent->m_document->renderHints();
356
document->setRenderHint(Poppler::Document::Antialiasing, renderHints.testFlag(Poppler::Document::Antialiasing));
357
document->setRenderHint(Poppler::Document::TextAntialiasing, renderHints.testFlag(Poppler::Document::TextAntialiasing));
358
document->setRenderHint(Poppler::Document::TextHinting, renderHints.testFlag(Poppler::Document::TextHinting));
360
QImage image = page->renderToImage(scale * parent->m_resolutionX, scale * parent->m_resolutionY);
367
parent->m_documentMutex.lock();
369
QImage image = m_page->renderToImage(scale * parent->m_resolutionX, scale * parent->m_resolutionY);
371
parent->m_documentMutex.unlock();
375
DocumentView::PageCacheKey key(m_index, scale * parent->m_resolutionX, scale * parent->m_resolutionY);
376
DocumentView::PageCacheValue value(image);
378
parent->updatePageCache(key, value);
380
emit parent->pageItemChanged(m_index);
385
DocumentView::ThumbnailItem::ThumbnailItem(QGraphicsItem* parent, QGraphicsScene* scene) : QGraphicsItem(parent, scene),
394
DocumentView::ThumbnailItem::~ThumbnailItem()
396
m_render.waitForFinished();
404
QRectF DocumentView::ThumbnailItem::boundingRect() const
406
DocumentView* parent = qobject_cast< DocumentView* >(scene()->parent()); Q_ASSERT(parent);
408
return QRectF(0.0, 0.0, qCeil(m_scale * parent->physicalDpiX() / 72.0 * m_size.width()), qCeil(m_scale * parent->physicalDpiY() / 72.0 * m_size.height()));
411
void DocumentView::ThumbnailItem::paint(QPainter* painter, const QStyleOptionGraphicsItem*, QWidget*)
413
DocumentView* parent = qobject_cast< DocumentView* >(scene()->parent()); Q_ASSERT(parent);
417
painter->fillRect(boundingRect(), QBrush(Qt::white));
419
#ifdef RENDER_IN_PAINT
421
parent->m_documentMutex.lock();
423
QImage image = m_page->renderToImage(m_scale * parent->physicalDpiX(), m_scale * parent->physicalDpiY());
425
parent->m_documentMutex.unlock();
427
painter->drawImage(0.0, 0.0, image);
431
parent->m_pageCacheMutex.lock();
433
DocumentView::PageCacheKey key(m_index, m_scale * parent->physicalDpiX(), m_scale * parent->physicalDpiY());
435
if(parent->m_pageCache.contains(key))
437
DocumentView::PageCacheValue& value = parent->m_pageCache[key];
439
value.time = QTime::currentTime();
440
painter->drawImage(0.0, 0.0, value.image);
444
if(!m_render.isRunning())
446
m_render = QtConcurrent::run(this, &DocumentView::ThumbnailItem::render, m_scale);
450
parent->m_pageCacheMutex.unlock();
454
painter->setPen(QPen(Qt::black));
455
painter->drawRect(boundingRect());
458
void DocumentView::ThumbnailItem::mouseDoubleClickEvent(QGraphicsSceneMouseEvent*)
460
DocumentView* parent = qobject_cast< DocumentView* >(scene()->parent()); Q_ASSERT(parent);
462
parent->setCurrentPage(m_index + 1);
465
void DocumentView::ThumbnailItem::render(qreal scale)
467
DocumentView* parent = qobject_cast< DocumentView* >(scene()->parent()); Q_ASSERT(parent);
469
QRectF rect = boundingRect().translated(pos());
470
QRectF visibleRect = parent->m_thumbnailsGraphicsView->mapToScene(parent->m_thumbnailsGraphicsView->viewport()->rect()).boundingRect();
472
if(!rect.intersects(visibleRect))
477
#ifdef RENDER_FROM_DISK
479
Poppler::Document* document = Poppler::Document::load(parent->m_filePath);
487
Poppler::Page* page = document->page(m_index);
495
Poppler::Document::RenderHints renderHints = parent->m_document->renderHints();
497
document->setRenderHint(Poppler::Document::Antialiasing, renderHints.testFlag(Poppler::Document::Antialiasing));
498
document->setRenderHint(Poppler::Document::TextAntialiasing, renderHints.testFlag(Poppler::Document::TextAntialiasing));
499
document->setRenderHint(Poppler::Document::TextHinting, renderHints.testFlag(Poppler::Document::TextHinting));
501
QImage image = page->renderToImage(scale * parent->physicalDpiX(), scale * parent->physicalDpiY());
508
parent->m_documentMutex.lock();
510
QImage image = m_page->renderToImage(scale * parent->physicalDpiX(), scale * parent->physicalDpiY());
512
parent->m_documentMutex.unlock();
516
DocumentView::PageCacheKey key(m_index, scale * parent->physicalDpiX(), scale * parent->physicalDpiY());
517
DocumentView::PageCacheValue value(image);
519
parent->updatePageCache(key, value);
521
emit parent->thumbnailItemChanged(m_index);
526
DocumentView::DocumentView(QWidget* parent) : QWidget(parent),
532
m_maximumPageCacheSize(33554432u),
536
m_pageLayout(OnePage),
537
m_scaleMode(DoNotScale),
539
m_rotation(RotateBy0),
540
m_highlightAll(false),
543
m_thumbnailsByIndex(),
547
m_autoRefreshWatcher(0),
550
m_currentResult(m_results.end()),
554
connect(this, SIGNAL(pageItemChanged(int)), SLOT(slotUpdatePageItem(int)));
555
connect(this, SIGNAL(thumbnailItemChanged(int)), SLOT(slotUpdateThumbnailItem(int)));
557
connect(this, SIGNAL(currentPageChanged(int)), SLOT(slotThumbnailsEnsureVisible(int)));
559
connect(this, SIGNAL(firstResultFound()), SLOT(findNext()));
563
m_pageLayout = static_cast< PageLayout >(m_settings.value("documentView/pageLayout", static_cast< uint >(m_pageLayout)).toUInt());
564
m_scaleMode = static_cast< ScaleMode >(m_settings.value("documentView/scaleMode", static_cast< uint >(m_scaleMode)).toUInt());
565
m_scaleFactor = m_settings.value("documentView/scaleFactor", m_scaleFactor).toReal();
566
m_rotation = static_cast< Rotation >(m_settings.value("documentView/rotation", static_cast< uint >(m_rotation)).toUInt());
568
m_highlightAll = m_settings.value("documentView/highlightAll", m_highlightAll).toBool();
572
m_scene = new QGraphicsScene(this);
573
m_scene->setBackgroundBrush(QBrush(Qt::darkGray));
575
m_view = new QGraphicsView(m_scene, this);
576
m_view->setDragMode(QGraphicsView::ScrollHandDrag);
578
m_view->setAcceptDrops(false);
580
setFocusProxy(m_view);
584
m_highlight = new QGraphicsRectItem();
585
m_highlight->setPen(QPen(QColor(0, 255, 0, 255)));
586
m_highlight->setBrush(QBrush(QColor(0, 255, 0, 127)));
587
m_highlight->setVisible(false);
589
m_scene->addItem(m_highlight);
591
// vertical scrollbar
593
m_view->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
595
connect(m_view->verticalScrollBar(), SIGNAL(valueChanged(int)), SLOT(slotVerticalScrollBarValueChanged(int)));
597
m_view->installEventFilter(this);
598
m_view->verticalScrollBar()->installEventFilter(this);
600
// auto-refresh timer
602
m_autoRefreshTimer = new QTimer(this);
603
m_autoRefreshTimer->setInterval(500);
604
m_autoRefreshTimer->setSingleShot(true);
606
connect(m_autoRefreshTimer, SIGNAL(timeout()), SLOT(refresh()));
610
m_prefetchTimer = new QTimer(this);
611
m_prefetchTimer->setInterval(500);
612
m_prefetchTimer->setSingleShot(true);
614
connect(this, SIGNAL(currentPageChanged(int)), m_prefetchTimer, SLOT(start()));
615
connect(this, SIGNAL(pageLayoutChanged(DocumentView::PageLayout)), m_prefetchTimer, SLOT(start()));
616
connect(this, SIGNAL(scaleModeChanged(DocumentView::ScaleMode)), m_prefetchTimer, SLOT(start()));
618
connect(m_prefetchTimer, SIGNAL(timeout()), SLOT(slotPrefetchTimerTimeout()));
622
m_bookmarksMenu = new BookmarksMenu(this);
623
m_bookmarksMenu->updateCurrentPage(m_currentPage);
624
m_bookmarksMenu->updateValue(m_view->verticalScrollBar()->value());
625
m_bookmarksMenu->updateRange(m_view->verticalScrollBar()->minimum(), m_view->verticalScrollBar()->maximum());
627
connect(this, SIGNAL(currentPageChanged(int)), m_bookmarksMenu, SLOT(updateCurrentPage(int)));
628
connect(m_view->verticalScrollBar(), SIGNAL(valueChanged(int)), m_bookmarksMenu, SLOT(updateValue(int)));
629
connect(m_view->verticalScrollBar(), SIGNAL(rangeChanged(int,int)), m_bookmarksMenu, SLOT(updateRange(int,int)));
631
connect(m_bookmarksMenu, SIGNAL(entrySelected(int,int)), SLOT(slotBookmarksMenuEntrySelected(int,int)));
635
m_tabAction = new QAction(this);
637
connect(m_tabAction, SIGNAL(triggered()), SLOT(slotTabActionTriggered()));
641
m_outlineTreeWidget = new QTreeWidget();
642
m_outlineTreeWidget->setAlternatingRowColors(true);
643
m_outlineTreeWidget->setEditTriggers(QAbstractItemView::NoEditTriggers);
644
m_outlineTreeWidget->header()->setVisible(false);
645
m_outlineTreeWidget->header()->setResizeMode(QHeaderView::Stretch);
647
connect(m_outlineTreeWidget, SIGNAL(itemClicked(QTreeWidgetItem*,int)), SLOT(slotOutlineTreeWidgetItemClicked(QTreeWidgetItem*,int)));
651
m_metaInformationTableWidget = new QTableWidget();
652
m_metaInformationTableWidget->setAlternatingRowColors(true);
653
m_metaInformationTableWidget->setEditTriggers(QAbstractItemView::NoEditTriggers);
654
m_metaInformationTableWidget->horizontalHeader()->setVisible(false);
655
m_metaInformationTableWidget->horizontalHeader()->setResizeMode(QHeaderView::Stretch);
656
m_metaInformationTableWidget->verticalHeader()->setVisible(false);
657
m_metaInformationTableWidget->verticalHeader()->setResizeMode(QHeaderView::ResizeToContents);
661
m_thumbnailsGraphicsView = new QGraphicsView(new QGraphicsScene(this));
662
m_thumbnailsGraphicsView->scene()->setBackgroundBrush(QBrush(Qt::darkGray));
663
m_thumbnailsGraphicsView->setDragMode(QGraphicsView::ScrollHandDrag);
666
DocumentView::~DocumentView()
671
m_search.waitForFinished();
674
m_print.waitForFinished();
681
if(m_autoRefreshWatcher != 0)
683
delete m_autoRefreshWatcher;
686
delete m_outlineTreeWidget;
687
delete m_metaInformationTableWidget;
688
delete m_thumbnailsGraphicsView;
691
const QString& DocumentView::filePath() const
696
int DocumentView::numberOfPages() const
698
return m_numberOfPages;
701
int DocumentView::currentPage() const
703
return m_currentPage;
706
DocumentView::PageLayout DocumentView::pageLayout() const
711
void DocumentView::setPageLayout(DocumentView::PageLayout pageLayout)
713
if(m_pageLayout != pageLayout)
715
m_pageLayout = pageLayout;
717
m_settings.setValue("documentView/pageLayout", static_cast< uint >(m_pageLayout));
719
if((m_pageLayout == TwoPages || m_pageLayout == TwoColumns) && m_currentPage % 2 == 0)
723
emit currentPageChanged(m_currentPage);
729
emit pageLayoutChanged(m_pageLayout);
733
DocumentView::ScaleMode DocumentView::scaleMode() const
738
void DocumentView::setScaleMode(DocumentView::ScaleMode scaleMode)
740
if(m_scaleMode != scaleMode)
742
m_scaleMode = scaleMode;
744
m_settings.setValue("documentView/scaleMode", static_cast< uint >(m_scaleMode));
749
emit scaleModeChanged(m_scaleMode);
753
qreal DocumentView::scaleFactor() const
755
return m_scaleFactor;
758
void DocumentView::setScaleFactor(qreal scaleFactor)
760
if(m_scaleFactor != scaleFactor && scaleFactor >= mininumScaleFactor && scaleFactor <= maximumScaleFactor)
762
m_scaleFactor = scaleFactor;
764
m_settings.setValue("documentView/scaleFactor", m_scaleFactor);
769
emit scaleFactorChanged(m_scaleFactor);
773
DocumentView::Rotation DocumentView::rotation() const
778
void DocumentView::setRotation(DocumentView::Rotation rotation)
780
if(m_rotation != rotation)
782
m_rotation = rotation;
784
m_settings.setValue("documentView/rotation", static_cast< uint >(m_rotation));
789
emit rotationChanged(m_rotation);
793
bool DocumentView::highlightAll() const
795
return m_highlightAll;
798
void DocumentView::setHighlightAll(bool highlightAll)
800
if(m_highlightAll != highlightAll)
802
m_highlightAll = highlightAll;
804
m_settings.setValue("documentView/highlightAll", m_highlightAll);
806
foreach(PageItem* pageItem, m_pagesByIndex)
808
pageItem->update(pageItem->boundingRect());
811
emit highlightAllChanged(m_highlightAll);
815
QAction* DocumentView::tabAction() const
820
QTreeWidget* DocumentView::outlineTreeWidget() const
822
return m_outlineTreeWidget;
825
QTableWidget* DocumentView::metaInformationTableWidget() const
827
return m_metaInformationTableWidget;
830
QGraphicsView* DocumentView::thumbnailsGraphicsView() const
832
return m_thumbnailsGraphicsView;
835
QTableWidget* DocumentView::fontsTableWidget()
837
QTableWidget* fontsTableWidget = new QTableWidget();
839
fontsTableWidget->setAlternatingRowColors(true);
840
fontsTableWidget->setSortingEnabled(true);
841
fontsTableWidget->setEditTriggers(QAbstractItemView::NoEditTriggers);
842
fontsTableWidget->horizontalHeader()->setResizeMode(QHeaderView::ResizeToContents);
843
fontsTableWidget->setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel);
844
fontsTableWidget->verticalHeader()->setResizeMode(QHeaderView::ResizeToContents);
845
fontsTableWidget->verticalHeader()->setVisible(false);
847
m_documentMutex.lock();
849
QList< Poppler::FontInfo > fonts = m_document->fonts();
851
m_documentMutex.unlock();
853
fontsTableWidget->setRowCount(fonts.count());
854
fontsTableWidget->setColumnCount(5);
856
fontsTableWidget->setHorizontalHeaderLabels(QStringList() << tr("Name") << tr("Type") << tr("Embedded") << tr("Subset") << tr("File"));
858
for(int index = 0; index < fonts.count(); index++)
860
Poppler::FontInfo font = fonts.at(index);
862
fontsTableWidget->setItem(index, 0,new QTableWidgetItem(font.name()));
863
fontsTableWidget->setItem(index, 1, new QTableWidgetItem(font.typeName()));
864
fontsTableWidget->setItem(index, 2, new QTableWidgetItem(font.isEmbedded() ? tr("Yes") : tr("No")));
865
fontsTableWidget->setItem(index, 3, new QTableWidgetItem(font.isSubset() ? tr("Yes") : tr("No")));
866
fontsTableWidget->setItem(index, 4, new QTableWidgetItem(font.file()));
869
return fontsTableWidget;
872
void DocumentView::clearBookmarks()
874
m_bookmarksMenu->clearList();
877
bool DocumentView::open(const QString& filePath)
879
m_prefetchTimer->blockSignals(true);
881
Poppler::Document* document = Poppler::Document::load(filePath);
885
if(document->isLocked())
887
QString password = QInputDialog::getText(0, tr("Password"), tr("Please enter the password required to unlock the document file \"%1\".").arg(filePath), QLineEdit::Password);
889
if(document->unlock(password.toLatin1(), password.toLatin1()))
891
qWarning() << tr("Could not unlock the document file \"%1\".").arg(filePath);
908
if(m_autoRefreshWatcher != 0)
910
delete m_autoRefreshWatcher;
913
m_document = document;
915
if(m_settings.value("documentView/autoRefresh", false).toBool())
917
m_autoRefreshWatcher = new QFileSystemWatcher(QStringList(filePath));
919
connect(m_autoRefreshWatcher, SIGNAL(fileChanged(QString)), m_autoRefreshTimer, SLOT(start()));
922
m_filePath = filePath;
923
m_numberOfPages = m_document->numPages();
925
emit filePathChanged(m_filePath);
926
emit numberOfPagesChanged(m_numberOfPages);
930
emit currentPageChanged(m_currentPage);
932
QFileInfo fileInfo(m_filePath);
934
m_tabAction->setText(fileInfo.completeBaseName());
935
m_tabAction->setToolTip(fileInfo.absoluteFilePath());
940
prepareMetaInformation();
943
m_document->setRenderHint(Poppler::Document::Antialiasing, m_settings.value("documentView/antialiasing", true).toBool());
944
m_document->setRenderHint(Poppler::Document::TextAntialiasing, m_settings.value("documentView/textAntialiasing", true).toBool());
945
m_document->setRenderHint(Poppler::Document::TextHinting, m_settings.value("documentView/textHinting", false).toBool());
952
if(m_settings.value("documentView/prefetch").toBool())
954
m_prefetchTimer->blockSignals(false);
955
m_prefetchTimer->start();
959
return document != 0;
962
bool DocumentView::refresh()
964
m_prefetchTimer->blockSignals(true);
966
Poppler::Document* document = Poppler::Document::load(m_filePath);
970
if(document->isLocked())
972
QString password = QInputDialog::getText(0, tr("Password"), tr("Please enter the password required to unlock the document file \"%1\".").arg(m_filePath), QLineEdit::Password);
974
if(document->unlock(password.toLatin1(), password.toLatin1()))
976
qWarning() << tr("Could not unlock the document file \"%1\".").arg(m_filePath);
993
m_document = document;
995
int numberOfPages = m_document->numPages();
997
if(m_numberOfPages != numberOfPages)
999
m_numberOfPages = numberOfPages;
1001
emit numberOfPagesChanged(m_numberOfPages);
1004
if(m_currentPage > m_numberOfPages)
1008
emit currentPageChanged(m_currentPage);
1014
prepareMetaInformation();
1015
prepareThumbnails();
1017
m_document->setRenderHint(Poppler::Document::Antialiasing, m_settings.value("documentView/antialiasing", true).toBool());
1018
m_document->setRenderHint(Poppler::Document::TextAntialiasing, m_settings.value("documentView/textAntialiasing", true).toBool());
1019
m_document->setRenderHint(Poppler::Document::TextHinting, m_settings.value("documentView/textHinting", false).toBool());
1026
if(m_settings.value("documentView/prefetch").toBool())
1028
m_prefetchTimer->blockSignals(false);
1029
m_prefetchTimer->start();
1033
return document != 0;
1036
bool DocumentView::saveCopy(const QString& filePath)
1040
m_documentMutex.lock();
1042
Poppler::PDFConverter* converter = m_document->pdfConverter();
1044
converter->setOutputFileName(filePath);
1046
bool success = converter->convert();
1050
m_documentMutex.unlock();
1058
void DocumentView::setCurrentPage(int currentPage, qreal top)
1060
if(currentPage >= 1 && currentPage <= m_numberOfPages && top >= 0.0 && top <= 1.0)
1062
PageItem* pageItem = m_pagesByIndex.value(m_currentPage - 1, 0);
1066
QRectF rect = m_pageTransform.mapRect(pageItem->boundingRect()).translated(pageItem->pos());
1068
switch(m_pageLayout)
1072
if(m_currentPage != currentPage)
1074
m_bookmarksMenu->setReturnPosition(m_currentPage, m_view->verticalScrollBar()->value());
1076
m_currentPage = currentPage;
1080
emit currentPageChanged(m_currentPage);
1082
else if(!qFuzzyCompare(1.0 + (qCeil(m_view->verticalScrollBar()->value() - rect.top()) / rect.height()), 1.0 + top))
1090
if(m_currentPage != (currentPage % 2 != 0 ? currentPage : currentPage - 1))
1092
m_bookmarksMenu->setReturnPosition(m_currentPage, m_view->verticalScrollBar()->value());
1094
m_currentPage = currentPage % 2 != 0 ? currentPage : currentPage - 1;
1098
emit currentPageChanged(m_currentPage);
1100
else if(!qFuzzyCompare(1.0 + (qCeil(m_view->verticalScrollBar()->value() - rect.top()) / rect.height()), 1.0 + top))
1111
void DocumentView::previousPage()
1113
switch(m_pageLayout)
1117
if(m_currentPage > 1)
1123
emit currentPageChanged(m_currentPage);
1129
if(m_currentPage > 1)
1135
emit currentPageChanged(m_currentPage);
1142
void DocumentView::nextPage()
1144
switch(m_pageLayout)
1148
if(m_currentPage < m_numberOfPages)
1154
emit currentPageChanged(m_currentPage);
1160
if(m_currentPage < (m_numberOfPages % 2 != 0 ? m_numberOfPages : m_numberOfPages - 1))
1166
emit currentPageChanged(m_currentPage);
1173
void DocumentView::firstPage()
1175
if(m_currentPage != 1)
1181
emit currentPageChanged(m_currentPage);
1185
void DocumentView::lastPage()
1187
switch(m_pageLayout)
1191
if(m_currentPage != m_numberOfPages)
1193
m_currentPage = m_numberOfPages;
1197
emit currentPageChanged(m_currentPage);
1203
if(m_currentPage != (m_numberOfPages % 2 != 0 ? m_numberOfPages : m_numberOfPages - 1))
1205
m_currentPage = m_numberOfPages % 2 != 0 ? m_numberOfPages : m_numberOfPages - 1;
1209
emit currentPageChanged(m_currentPage);
1216
void DocumentView::zoomIn()
1218
PageItem* pageItem = m_pagesByIndex.value(m_currentPage - 1, 0);
1223
case FitToPageWidth:
1226
setScaleFactor(qMin(pageItem->m_scale + zoomBy, maximumScaleFactor));
1227
setScaleMode(ScaleFactor);
1232
setScaleFactor(1.0 + zoomBy);
1233
setScaleMode(ScaleFactor);
1237
setScaleFactor(qMin(scaleFactor() + zoomBy, maximumScaleFactor));
1243
void DocumentView::zoomOut()
1245
PageItem* pageItem = m_pagesByIndex.value(m_currentPage - 1, 0);
1250
case FitToPageWidth:
1253
setScaleFactor(qMax(pageItem->m_scale - zoomBy, mininumScaleFactor));
1254
setScaleMode(ScaleFactor);
1259
setScaleFactor(1.0 - zoomBy);
1260
setScaleMode(ScaleFactor);
1264
setScaleFactor(qMax(scaleFactor() - zoomBy, mininumScaleFactor));
1270
void DocumentView::rotateLeft()
1275
setRotation(RotateBy270); break;
1277
setRotation(RotateBy0); break;
1279
setRotation(RotateBy90); break;
1281
setRotation(RotateBy180); break;
1285
void DocumentView::rotateRight()
1290
setRotation(RotateBy90); break;
1292
setRotation(RotateBy180); break;
1294
setRotation(RotateBy270); break;
1296
setRotation(RotateBy0); break;
1300
void DocumentView::startSearch(const QString& text, bool matchCase)
1304
if(m_document != 0 && !text.isEmpty())
1306
m_search = QtConcurrent::run(this, &DocumentView::search, text, matchCase);
1310
void DocumentView::cancelSearch()
1313
m_search.waitForFinished();
1315
m_resultsMutex.lock();
1318
m_currentResult = m_results.end();
1320
m_resultsMutex.unlock();
1322
m_highlight->setVisible(false);
1326
foreach(PageItem* pageItem, m_pagesByIndex)
1328
pageItem->update(pageItem->boundingRect());
1333
void DocumentView::findPrevious()
1335
if(m_currentResult != m_results.end())
1337
switch(m_pageLayout)
1341
if(m_currentResult.key() != m_currentPage - 1)
1343
m_currentResult = --m_results.upperBound(m_currentPage - 1);
1350
if(m_currentResult == m_results.end())
1352
m_currentResult = --m_results.upperBound(m_numberOfPages - 1);
1358
if(m_currentResult.key() != m_currentPage - 1 && m_currentResult.key() != m_currentPage)
1360
m_currentResult = --m_results.upperBound(m_currentPage - 1);
1367
if(m_currentResult == m_results.end())
1369
m_currentResult = --m_results.upperBound(m_numberOfPages - 1);
1377
m_currentResult = --m_results.upperBound(m_currentPage - 1);
1379
if(m_currentResult == m_results.end())
1381
m_currentResult = --m_results.upperBound(m_numberOfPages - 1);
1385
if(m_currentResult != m_results.end())
1387
switch(m_pageLayout)
1391
if(m_currentPage != m_currentResult.key() + 1)
1393
m_currentPage = m_currentResult.key() + 1;
1395
emit currentPageChanged(m_currentPage);
1401
if(m_currentPage != (m_currentResult.key() % 2 == 0 ? m_currentResult.key() + 1 : m_currentResult.key()))
1403
m_currentPage = m_currentResult.key() % 2 == 0 ? m_currentResult.key() + 1 : m_currentResult.key();
1405
emit currentPageChanged(m_currentPage);
1411
disconnect(m_view->verticalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(slotVerticalScrollBarValueChanged(int)));
1413
m_view->centerOn(m_highlight);
1415
connect(m_view->verticalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(slotVerticalScrollBarValueChanged(int)));
1419
void DocumentView::findNext()
1421
if(m_currentResult != m_results.end())
1423
switch(m_pageLayout)
1427
if(m_currentResult.key() != m_currentPage - 1)
1429
m_currentResult = --m_results.upperBound(m_currentPage - 1);
1436
if(m_currentResult == m_results.end())
1438
m_currentResult = m_results.lowerBound(0);
1444
if(m_currentResult.key() != m_currentPage - 1 && m_currentResult.key() != m_currentPage)
1446
m_currentResult = --m_results.upperBound(m_currentPage - 1);
1453
if(m_currentResult == m_results.end())
1455
m_currentResult = m_results.lowerBound(0);
1463
m_currentResult = m_results.lowerBound(m_currentPage - 1);
1465
if(m_currentResult == m_results.end())
1467
m_currentResult = m_results.lowerBound(0);
1471
if(m_currentResult != m_results.end())
1473
switch(m_pageLayout)
1477
if(m_currentPage != m_currentResult.key() + 1)
1479
m_currentPage = m_currentResult.key() + 1;
1481
emit currentPageChanged(m_currentPage);
1487
if(m_currentPage != (m_currentResult.key() % 2 == 0 ? m_currentResult.key() + 1 : m_currentResult.key()))
1489
m_currentPage = m_currentResult.key() % 2 == 0 ? m_currentResult.key() + 1 : m_currentResult.key();
1491
emit currentPageChanged(m_currentPage);
1497
disconnect(m_view->verticalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(slotVerticalScrollBarValueChanged(int)));
1499
m_view->centerOn(m_highlight);
1501
connect(m_view->verticalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(slotVerticalScrollBarValueChanged(int)));
1505
void DocumentView::startPrint(QPrinter* printer, int fromPage, int toPage)
1509
if(m_document != 0 && fromPage >= 1 && fromPage <= m_numberOfPages && toPage >= 1 && toPage <= m_numberOfPages && fromPage <= toPage)
1511
m_print = QtConcurrent::run(this, &DocumentView::print, printer, fromPage, toPage);
1515
void DocumentView::cancelPrint()
1518
m_print.waitForFinished();
1521
bool DocumentView::eventFilter(QObject* object, QEvent* event)
1523
if(object == m_view && event->type() == QEvent::KeyPress)
1525
QKeyEvent* keyEvent = static_cast< QKeyEvent* >(event);
1527
if(keyEvent->modifiers() == Qt::NoModifier && (keyEvent->key() == Qt::Key_PageUp || keyEvent->key() == Qt::Key_PageDown))
1529
keyPressEvent(keyEvent);
1534
else if(object == m_view->verticalScrollBar() && event->type() == QEvent::Wheel)
1536
QWheelEvent* wheelEvent = static_cast< QWheelEvent* >(event);
1538
return wheelEvent->modifiers() == Qt::ControlModifier || wheelEvent->modifiers() == Qt::ShiftModifier || wheelEvent->modifiers() == Qt::AltModifier;
1544
void DocumentView::showEvent(QShowEvent* event)
1546
if(!event->spontaneous())
1555
void DocumentView::resizeEvent(QResizeEvent* event)
1557
m_view->resize(event->size());
1559
if(m_scaleMode == FitToPage || m_scaleMode == FitToPageWidth)
1566
void DocumentView::contextMenuEvent(QContextMenuEvent* event)
1568
m_bookmarksMenu->exec(event->globalPos());
1571
void DocumentView::keyPressEvent(QKeyEvent* event)
1573
if(event->modifiers() == Qt::NoModifier && (event->key() == Qt::Key_PageUp || event->key() == Qt::Key_Backspace))
1575
switch(m_pageLayout)
1579
if(m_view->verticalScrollBar()->value() == m_view->verticalScrollBar()->minimum() && m_currentPage > 1)
1583
m_view->verticalScrollBar()->setValue(m_view->verticalScrollBar()->maximum());
1585
else if(m_view->verticalScrollBar()->value() - m_view->verticalScrollBar()->pageStep() < m_view->verticalScrollBar()->minimum())
1587
m_view->verticalScrollBar()->setValue(m_view->verticalScrollBar()->minimum());
1591
m_view->verticalScrollBar()->setValue(m_view->verticalScrollBar()->value() - m_view->verticalScrollBar()->pageStep());
1597
m_view->verticalScrollBar()->setValue(m_view->verticalScrollBar()->value() - m_view->verticalScrollBar()->pageStep());
1602
else if(event->modifiers() == Qt::NoModifier && (event->key() == Qt::Key_PageDown || event->key() == Qt::Key_Space))
1606
switch(m_pageLayout)
1610
lastPage = m_numberOfPages; break;
1613
lastPage = m_numberOfPages % 2 != 0 ? m_numberOfPages : m_numberOfPages - 1; break;
1616
switch(m_pageLayout)
1620
if(m_view->verticalScrollBar()->value() == m_view->verticalScrollBar()->maximum() && m_currentPage < lastPage)
1624
m_view->verticalScrollBar()->setValue(m_view->verticalScrollBar()->minimum());
1626
else if(m_view->verticalScrollBar()->value() + m_view->verticalScrollBar()->pageStep() > m_view->verticalScrollBar()->maximum())
1628
m_view->verticalScrollBar()->setValue(m_view->verticalScrollBar()->maximum());
1632
m_view->verticalScrollBar()->setValue(m_view->verticalScrollBar()->value() + m_view->verticalScrollBar()->pageStep());
1638
m_view->verticalScrollBar()->setValue(m_view->verticalScrollBar()->value() + m_view->verticalScrollBar()->pageStep());
1645
QKeySequence shortcut(event->modifiers() + event->key());
1647
foreach(QAction* action, m_bookmarksMenu->actions())
1649
if(action->shortcut() == shortcut)
1659
void DocumentView::wheelEvent(QWheelEvent* event)
1661
if(event->modifiers() == Qt::NoModifier)
1665
switch(m_pageLayout)
1669
lastPage = m_numberOfPages; break;
1672
lastPage = m_numberOfPages % 2 != 0 ? m_numberOfPages : m_numberOfPages - 1; break;
1675
switch(m_pageLayout)
1679
if(event->delta() > 0 && m_view->verticalScrollBar()->value() == m_view->verticalScrollBar()->minimum() && m_currentPage > 1)
1683
m_view->verticalScrollBar()->setValue(m_view->verticalScrollBar()->maximum());
1685
else if(event->delta() < 0 && m_view->verticalScrollBar()->value() == m_view->verticalScrollBar()->maximum() && m_currentPage < lastPage)
1689
m_view->verticalScrollBar()->setValue(m_view->verticalScrollBar()->minimum());
1698
else if(event->modifiers() == Qt::ControlModifier)
1700
if(event->delta() > 0)
1704
else if(event->delta() < 0)
1709
else if(event->modifiers() == Qt::ShiftModifier)
1711
if(event->delta() > 0)
1715
else if(event->delta() < 0)
1720
else if(event->modifiers() == Qt::AltModifier)
1722
QWheelEvent wheelEvent(*event);
1723
wheelEvent.setModifiers(Qt::NoModifier);
1725
QApplication::sendEvent(m_view->horizontalScrollBar(), &wheelEvent);
1729
void DocumentView::slotUpdatePageItem(int index)
1731
PageItem* pageItem = m_pagesByIndex.value(index, 0);
1735
pageItem->update(pageItem->boundingRect());
1739
void DocumentView::slotUpdateThumbnailItem(int index)
1741
ThumbnailItem* thumbnailItem = m_thumbnailsByIndex.value(index, 0);
1743
if(thumbnailItem != 0)
1745
thumbnailItem->update(thumbnailItem->boundingRect());
1749
void DocumentView::slotVerticalScrollBarValueChanged(int value)
1751
if(m_pageLayout == OneColumn || m_pageLayout == TwoColumns)
1753
QMap< qreal, PageItem* >::const_iterator iterator = --m_pagesByHeight.lowerBound(value + 0.5 * m_view->verticalScrollBar()->pageStep());
1755
if(iterator != m_pagesByHeight.end())
1757
if(m_currentPage != iterator.value()->m_index + 1)
1759
m_currentPage = iterator.value()->m_index + 1;
1761
emit currentPageChanged(m_currentPage);
1767
void DocumentView::slotThumbnailsEnsureVisible(int currentPage)
1769
ThumbnailItem* thumbnailItem = m_thumbnailsByIndex.value(currentPage - 1, 0);
1771
if(thumbnailItem != 0)
1773
m_thumbnailsGraphicsView->ensureVisible(thumbnailItem);
1777
void DocumentView::slotPrefetchTimerTimeout()
1779
#ifndef RENDER_IN_PAINT
1781
int fromPage = -1, toPage = -1;
1783
switch(m_pageLayout)
1787
fromPage = m_currentPage - 1;
1788
toPage = m_currentPage + 2;
1793
fromPage = m_currentPage - 2;
1794
toPage = m_currentPage + 4;
1799
fromPage = qMax(fromPage, 1);
1800
toPage = qMin(toPage, m_numberOfPages);
1802
for(int page = fromPage; page <= toPage; page++)
1804
PageItem* pageItem = m_pagesByIndex.value(page - 1, 0);
1808
m_pageCacheMutex.lock();
1810
PageCacheKey key(pageItem->m_index, pageItem->m_scale * m_resolutionX, pageItem->m_scale * m_resolutionY);
1812
if(!m_pageCache.contains(key))
1814
if(!pageItem->m_render.isRunning())
1816
pageItem->m_render = QtConcurrent::run(pageItem, &DocumentView::PageItem::render, pageItem->m_scale, true);
1820
m_pageCacheMutex.unlock();
1827
void DocumentView::slotBookmarksMenuEntrySelected(int page, int value)
1829
setCurrentPage(page);
1831
m_view->verticalScrollBar()->setValue(value);
1834
void DocumentView::slotTabActionTriggered()
1836
TabWidget* tabWidget = qobject_cast< TabWidget* >(this->parent()->parent()); Q_ASSERT(tabWidget);
1838
tabWidget->setCurrentIndex(tabWidget->indexOf(this));
1841
void DocumentView::slotOutlineTreeWidgetItemClicked(QTreeWidgetItem* item, int column)
1843
setCurrentPage(item->data(column, Qt::UserRole).toInt(), item->data(column, Qt::UserRole+1).toReal());
1846
void DocumentView::search(const QString& text, bool matchCase)
1850
for(int index = m_currentPage - 1; index < m_numberOfPages; index++)
1852
indices.append(index);
1855
for(int index = 0; index < m_currentPage - 1; index++)
1857
indices.append(index);
1860
bool firstResult = true;
1862
emit searchProgressed(0);
1864
foreach(int index, indices)
1866
if(m_search.isCanceled())
1868
emit searchCanceled();
1873
m_documentMutex.lock();
1875
Poppler::Page* page = m_document->page(index);
1877
QList< QRectF > results;
1879
#ifdef HAS_POPPLER_14
1880
double rectLeft = 0.0, rectTop = 0.0, rectRight = 0.0, rectBottom = 0.0;
1882
while(page->search(text, rectLeft, rectTop, rectRight, rectBottom, Poppler::Page::NextResult, matchCase ? Poppler::Page::CaseSensitive : Poppler::Page::CaseInsensitive))
1885
rect.setLeft(rectLeft);
1886
rect.setTop(rectTop);
1887
rect.setRight(rectRight);
1888
rect.setBottom(rectBottom);
1890
results.append(rect.normalized());
1895
while(page->search(text, rect, Poppler::Page::NextResult, matchCase ? Poppler::Page::CaseSensitive : Poppler::Page::CaseInsensitive))
1897
results.append(rect.normalized());
1903
m_documentMutex.unlock();
1905
m_resultsMutex.lock();
1907
while(!results.isEmpty())
1909
m_results.insertMulti(index, results.takeLast());
1912
if(m_results.contains(index) && firstResult)
1914
emit firstResultFound();
1916
firstResult = false;
1919
m_resultsMutex.unlock();
1923
emit pageItemChanged(index);
1926
emit searchProgressed((100 * (indices.indexOf(index) + 1)) / indices.count());
1929
emit searchFinished();
1932
void DocumentView::print(QPrinter* printer, int fromPage, int toPage)
1936
emit printProgressed(0);
1939
cups_dest_t* dests = 0;
1941
num_dests = cupsGetDests(&dests);
1943
cups_dest_t* dest = 0;
1945
dest = cupsGetDest(printer->printerName().toLocal8Bit(), 0, num_dests, dests);
1949
int num_options = 0;
1950
cups_option_t* options = 0;
1952
for(int i = 0; i < dest->num_options; i++)
1954
num_options = cupsAddOption(dest->options[i].name, dest->options[i].value, num_options, &options);
1957
// page layout and range
1959
switch(m_pageLayout)
1963
num_options = cupsAddOption("number-up", QString("%1").arg(1).toLocal8Bit(), num_options, &options);
1964
num_options = cupsAddOption("page-ranges", QString("%1-%2").arg(fromPage).arg(toPage).toLocal8Bit(), num_options, &options);
1969
num_options = cupsAddOption("number-up", QString("%1").arg(2).toLocal8Bit(), num_options, &options);
1970
num_options = cupsAddOption("page-ranges", QString("%1-%2").arg(fromPage % 2 == 0 ? fromPage / 2 : (fromPage + 1) / 2).arg(toPage % 2 == 0 ? toPage / 2 : (toPage + 1) / 2).toLocal8Bit(), num_options, &options);
1977
num_options = cupsAddOption("copies", QString("%1").arg(printer->copyCount()).toLocal8Bit(), num_options, &options);
1981
num_options = cupsAddOption("collate", QString("%1").arg(printer->collateCopies()).toLocal8Bit(), num_options, &options);
1985
switch(printer->duplex())
1987
case QPrinter::DuplexNone:
1988
num_options = cupsAddOption("sides", "one-sided", num_options, &options); break;
1989
case QPrinter::DuplexAuto:
1991
case QPrinter::DuplexLongSide:
1992
num_options = cupsAddOption("sides", "two-sided-long-edge", num_options, &options); break;
1993
case QPrinter::DuplexShortSide:
1994
num_options = cupsAddOption("sides", "two-sided-short-edge", num_options, &options); break;
1999
switch(printer->pageOrder())
2001
case QPrinter::FirstPageFirst:
2002
num_options = cupsAddOption("outputorder", "normal", num_options, &options); break;
2003
case QPrinter::LastPageFirst:
2004
num_options = cupsAddOption("outputorder", "reverse", num_options, &options); break;
2009
switch(printer->colorMode())
2011
case QPrinter::Color:
2013
case QPrinter::GrayScale:
2014
num_options = cupsAddOption("ColorModel", "Gray", num_options, &options); break;
2017
QFileInfo fileInfo(m_filePath);
2019
int jobId = cupsPrintFile(dest->name, fileInfo.absoluteFilePath().toLocal8Bit(), fileInfo.completeBaseName().toLocal8Bit(), num_options, options);
2021
cupsFreeDests(num_dests, dests);
2022
cupsFreeOptions(num_options, options);
2026
qDebug() << "CUPS:" << cupsLastErrorString();
2031
qDebug() << "CUPS:" << cupsLastErrorString();
2036
emit printProgressed(100);
2038
emit printFinished();
2042
printer->setFullPage(true);
2044
QPainter* painter = new QPainter(printer);
2046
emit printProgressed(0);
2048
for(int index = fromPage - 1; index <= toPage - 1; index++)
2050
if(m_print.isCanceled())
2052
emit printCanceled();
2059
m_documentMutex.lock();
2061
Poppler::Page* page = m_document->page(index);
2063
qreal fitToWidth = printer->width() / (printer->physicalDpiX() / 72.0 * page->pageSizeF().width());
2064
qreal fitToHeight = printer->height() / (printer->physicalDpiY() / 72.0 * page->pageSizeF().height());
2065
qreal fit = qMin(fitToWidth, fitToHeight);
2067
QImage image = page->renderToImage(printer->physicalDpiX(), printer->physicalDpiY());
2071
m_documentMutex.unlock();
2073
painter->setTransform(QTransform::fromScale(fit, fit));
2074
painter->drawImage(0.0, 0.0, image);
2076
if(index < toPage - 1)
2081
emit printProgressed((100 * (index + 1 - fromPage + 1)) / (toPage - fromPage + 1));
2084
emit printFinished();
2092
void DocumentView::clearScene()
2094
m_pagesByIndex.clear();
2095
m_thumbnailsByIndex.clear();
2097
m_scene->removeItem(m_highlight);
2099
m_scene->addItem(m_highlight);
2101
m_thumbnailsGraphicsView->scene()->clear();
2104
void DocumentView::clearPageCache()
2106
m_pageCacheMutex.lock();
2108
m_pageCache.clear();
2109
m_pageCacheSize = 0u;
2110
m_maximumPageCacheSize = m_settings.value("documentView/maximumPageCacheSize", 33554432u).toUInt();
2112
m_pageCacheMutex.unlock();
2115
void DocumentView::updatePageCache(const DocumentView::PageCacheKey& key, const DocumentView::PageCacheValue& value)
2117
m_pageCacheMutex.lock();
2119
uint byteCount = value.image.byteCount();
2121
if(m_maximumPageCacheSize < 3 * byteCount)
2123
m_maximumPageCacheSize = 3 * byteCount;
2125
qWarning() << tr("Maximum page cache size is too small. Increased it to %1 bytes to hold at least three pages.").arg(3 * byteCount);
2128
while(m_pageCacheSize + byteCount > m_maximumPageCacheSize)
2130
QMap< DocumentView::PageCacheKey, DocumentView::PageCacheValue >::const_iterator first = m_pageCache.begin();
2131
QMap< DocumentView::PageCacheKey, DocumentView::PageCacheValue >::const_iterator last = --m_pageCache.end();
2133
if(first.value().time < last.value().time)
2135
m_pageCacheSize -= first.value().image.byteCount();
2136
m_pageCache.remove(first.key());
2140
m_pageCacheSize -= last.value().image.byteCount();
2141
m_pageCache.remove(last.key());
2145
m_pageCacheSize += byteCount;
2146
m_pageCache.insert(key, value);
2148
m_pageCacheMutex.unlock();
2151
void DocumentView::preparePages()
2153
m_scene->removeItem(m_highlight);
2155
m_scene->addItem(m_highlight);
2157
m_pagesByIndex.clear();
2158
m_pagesByIndex.reserve(m_numberOfPages);
2160
for(int index = 0; index < m_numberOfPages; index++)
2162
PageItem* pageItem = new PageItem();
2164
pageItem->m_index = index;
2165
pageItem->m_page = m_document->page(pageItem->m_index);
2166
pageItem->m_size = pageItem->m_page->pageSizeF();
2168
foreach(Poppler::Link* link, pageItem->m_page->links())
2170
if(link->linkType() == Poppler::Link::Goto)
2172
if(!static_cast< Poppler::LinkGoto* >(link)->isExternal())
2174
QRectF area = link->linkArea().normalized();
2175
int page = static_cast< Poppler::LinkGoto* >(link)->destination().pageNumber();
2176
qreal top = static_cast< Poppler::LinkGoto* >(link)->destination().isChangeTop() ? static_cast< Poppler::LinkGoto* >(link)->destination().top() : 0.0;
2178
page = qMax(page, 1);
2179
page = qMin(page, m_numberOfPages);
2181
top = qMax(top, static_cast< qreal >(0.0));
2182
top = qMin(top, static_cast< qreal >(1.0));
2184
pageItem->m_links.append(Link(area, page, top));
2187
else if(link->linkType() == Poppler::Link::Browse)
2189
QRectF area = link->linkArea().normalized();
2190
QString url = static_cast< Poppler::LinkBrowse* >(link)->url();
2192
pageItem->m_links.append(Link(area, url));
2198
m_scene->addItem(pageItem);
2200
m_pagesByIndex.append(pageItem);
2204
void DocumentView::prepareOutline()
2206
m_outlineTreeWidget->clear();
2208
QDomDocument* toc = m_document->toc();
2212
prepareOutline(toc->firstChild(), 0, 0);
2218
void DocumentView::prepareOutline(const QDomNode& node, QTreeWidgetItem* parent, QTreeWidgetItem* sibling)
2220
QDomElement element = node.toElement();
2222
QTreeWidgetItem* item = 0;
2226
item = new QTreeWidgetItem(parent);
2230
item = new QTreeWidgetItem(m_outlineTreeWidget, sibling);
2233
item->setText(0, element.tagName());
2234
item->setToolTip(0, element.tagName());
2236
if(element.hasAttribute("Destination"))
2238
Poppler::LinkDestination linkDestination(element.attribute("Destination"));
2240
int page = linkDestination.pageNumber();
2241
qreal top = linkDestination.isChangeTop() ? linkDestination.top() : 0.0;
2243
page = qMax(page, 1);
2244
page = qMin(page, m_numberOfPages);
2246
top = qMax(top, static_cast< qreal >(0.0));
2247
top = qMin(top, static_cast< qreal >(1.0));
2249
item->setData(0, Qt::UserRole, page);
2250
item->setData(0, Qt::UserRole+1, top);
2252
else if(element.hasAttribute("DestinationName"))
2254
Poppler::LinkDestination* linkDestination = m_document->linkDestination(element.attribute("DestinationName"));
2256
int page = linkDestination != 0 ? linkDestination->pageNumber() : 1;
2257
qreal top = linkDestination != 0 ? (linkDestination->isChangeTop() ? linkDestination->top() : 0.0) : 0.0;
2259
page = qMax(page, 1);
2260
page = qMin(page, m_numberOfPages);
2262
top = qMax(top, static_cast< qreal >(0.0));
2263
top = qMin(top, static_cast< qreal >(1.0));
2265
item->setData(0, Qt::UserRole, page);
2266
item->setData(0, Qt::UserRole+1, top);
2268
delete linkDestination;
2272
item->setData(0, Qt::UserRole, -1);
2275
if(QVariant(element.attribute("Open", "false")).toBool())
2277
m_outlineTreeWidget->expandItem(item);
2280
QDomNode siblingNode = node.nextSibling();
2281
if(!siblingNode.isNull())
2283
prepareOutline(siblingNode, parent, item);
2286
QDomNode childNode = node.firstChild();
2287
if(!childNode.isNull())
2289
prepareOutline(childNode, item, 0);
2293
void DocumentView::prepareMetaInformation()
2295
m_metaInformationTableWidget->clear();
2297
QStringList keys = m_document->infoKeys();
2299
m_metaInformationTableWidget->setRowCount(keys.count());
2300
m_metaInformationTableWidget->setColumnCount(2);
2302
for(int index = 0; index < keys.count(); index++)
2304
QString key = keys.at(index);
2305
QString value = m_document->info(key);
2307
if(value.startsWith("D:"))
2309
value = QLocale::system().toString(m_document->date(key));
2312
m_metaInformationTableWidget->setItem(index, 0, new QTableWidgetItem(key));
2313
m_metaInformationTableWidget->setItem(index, 1, new QTableWidgetItem(value));
2317
void DocumentView::prepareThumbnails()
2319
m_thumbnailsGraphicsView->scene()->clear();
2321
m_thumbnailsByIndex.clear();
2322
m_thumbnailsByIndex.reserve(m_numberOfPages);
2324
qreal sceneWidth = 0.0, sceneHeight = thumbnailSpacing;
2326
for(int index = 0; index < m_numberOfPages; index++)
2328
ThumbnailItem* thumbnailItem = new ThumbnailItem();
2330
thumbnailItem->m_index = index;
2331
thumbnailItem->m_page = m_document->page(thumbnailItem->m_index);
2332
thumbnailItem->m_size = thumbnailItem->m_page->pageSizeF();
2334
thumbnailItem->m_scale = qMin(
2335
thumbnailWidth / (physicalDpiX() / 72.0 * thumbnailItem->m_size.width()),
2336
thumbnailHeight / (physicalDpiY() / 72.0 * thumbnailItem->m_size.height()));
2338
thumbnailItem->setPos(thumbnailSpacing, sceneHeight);
2340
m_thumbnailsGraphicsView->scene()->addItem(thumbnailItem);
2342
m_thumbnailsByIndex.append(thumbnailItem);
2344
sceneWidth = qMax(sceneWidth, thumbnailItem->boundingRect().width() + 2 * thumbnailSpacing);
2345
sceneHeight += thumbnailItem->boundingRect().height() + thumbnailSpacing;
2347
QGraphicsSimpleTextItem* textItem = new QGraphicsSimpleTextItem(QLocale::system().toString(index + 1));
2349
textItem->setPos(2 * thumbnailSpacing, sceneHeight);
2351
m_thumbnailsGraphicsView->scene()->addItem(textItem);
2353
sceneWidth = qMax(sceneWidth, textItem->boundingRect().width() + 3 * thumbnailSpacing);
2354
sceneHeight += textItem->boundingRect().height() + thumbnailSpacing;
2357
m_thumbnailsGraphicsView->scene()->setSceneRect(0.0, 0.0, sceneWidth, sceneHeight);
2358
m_thumbnailsGraphicsView->setSceneRect(0.0, 0.0, sceneWidth, sceneHeight);
2360
m_thumbnailsGraphicsView->setMinimumWidth(sceneWidth + 35);
2363
void DocumentView::prepareScene()
2371
m_resolutionX = physicalDpiX();
2372
m_resolutionY = physicalDpiY();
2377
m_resolutionX = physicalDpiY();
2378
m_resolutionY = physicalDpiX();
2383
if(m_scaleMode == FitToPage || m_scaleMode == FitToPageWidth)
2385
qreal pageWidth = 0.0, pageHeight = 0.0;
2386
qreal visibleWidth = m_view->viewport()->width() - 5;
2387
qreal visibleHeight = m_view->viewport()->height() - 5;
2389
switch(m_pageLayout)
2393
for(int index = 0; index < m_numberOfPages; index++)
2395
PageItem* pageItem = m_pagesByIndex.at(index);
2401
pageWidth = m_resolutionX / 72.0 * pageItem->m_size.width();
2402
pageHeight = m_resolutionY / 72.0 * pageItem->m_size.height();
2407
pageWidth = m_resolutionY / 72.0 * pageItem->m_size.height();
2408
pageHeight = m_resolutionX / 72.0 * pageItem->m_size.width();
2413
qreal scale = (visibleWidth - 2 * pageSpacing) / pageWidth;
2414
if(m_scaleMode == FitToPage)
2416
scale = qMin(scale, (visibleHeight - 2 * pageSpacing) / pageHeight);
2419
pageItem->m_scale = scale;
2425
for(int index = 0; index < (m_numberOfPages % 2 == 0 ? m_numberOfPages : m_numberOfPages - 1); index += 2)
2427
PageItem* leftPageItem = m_pagesByIndex.at(index);
2428
PageItem* rightPageItem = m_pagesByIndex.at(index + 1);
2436
pageWidth = m_resolutionX / 72.0 * 2.0 * qMax(leftPageItem->m_size.width(), rightPageItem->m_size.width());
2437
pageHeight = m_resolutionY / 72.0 * qMax(
2438
qMax(leftPageItem->m_size.width(), rightPageItem->m_size.width()) / leftPageItem->m_size.width() * leftPageItem->m_size.height(),
2439
qMax(leftPageItem->m_size.width(), rightPageItem->m_size.width()) / rightPageItem->m_size.width() * rightPageItem->m_size.height());
2444
pageWidth = m_resolutionY / 72.0 * 2.0 * qMax(leftPageItem->m_size.height(), rightPageItem->m_size.height());
2445
pageHeight = m_resolutionX / 72.0 * qMax(
2446
qMax(leftPageItem->m_size.height(), rightPageItem->m_size.height()) / leftPageItem->m_size.height() * leftPageItem->m_size.width(),
2447
qMax(leftPageItem->m_size.height(), rightPageItem->m_size.height()) / rightPageItem->m_size.height() * rightPageItem->m_size.width());
2452
qreal scale = (visibleWidth - 3 * pageSpacing) / pageWidth;
2453
if(m_scaleMode == FitToPage)
2455
scale = qMin(scale, (visibleHeight - 2 * pageSpacing) / pageHeight);
2462
leftPageItem->m_scale = scale * qMax(leftPageItem->m_size.width(), rightPageItem->m_size.width()) / leftPageItem->m_size.width();
2463
rightPageItem->m_scale = scale * qMax(leftPageItem->m_size.width(), rightPageItem->m_size.width()) / rightPageItem->m_size.width();
2468
leftPageItem->m_scale = scale * qMax(leftPageItem->m_size.height(), rightPageItem->m_size.height()) / leftPageItem->m_size.height();
2469
rightPageItem->m_scale = scale * qMax(leftPageItem->m_size.height(), rightPageItem->m_size.height()) / rightPageItem->m_size.height();
2480
pageWidth = m_resolutionX / 72.0 * (leftPageItem->m_size.width() + rightPageItem->m_size.width());
2481
pageHeight = m_resolutionY / 72.0 * qMax(leftPageItem->m_size.height(), rightPageItem->m_size.height());
2486
pageWidth = m_resolutionY / 72.0 * (leftPageItem->m_size.height() + rightPageItem->m_size.height());
2487
pageHeight = m_resolutionX / 72.0 * qMax(leftPageItem->m_size.width(), rightPageItem->m_size.width());
2492
qreal scale = (visibleWidth - 3 * pageSpacing) / pageWidth;
2493
if(m_scaleMode == FitToPage)
2495
scale = qMin(scale, (visibleHeight - 2 * pageSpacing) / pageHeight);
2498
leftPageItem->m_scale = scale;
2499
rightPageItem->m_scale = scale;
2503
if(m_numberOfPages % 2 != 0)
2505
PageItem* leftPageItem = m_pagesByIndex.at(m_numberOfPages - 1);
2511
pageWidth = m_resolutionX / 72.0 * leftPageItem->m_size.width();
2512
pageHeight = m_resolutionY / 72.0 * leftPageItem->m_size.height();
2517
pageWidth = m_resolutionY / 72.0 * leftPageItem->m_size.height();
2518
pageHeight = m_resolutionX / 72.0 * leftPageItem->m_size.width();
2523
qreal scale = (visibleWidth - 2 * pageSpacing) / pageWidth;
2524
if(m_scaleMode == FitToPage)
2526
scale = qMin(scale, (visibleHeight - 2 * pageSpacing) / pageHeight);
2529
leftPageItem->m_scale = scale;
2535
else if(m_scaleMode == DoNotScale || m_scaleMode == ScaleFactor)
2537
foreach(PageItem* pageItem, m_pagesByIndex)
2539
pageItem->m_scale = m_scaleMode == DoNotScale ? 1.0 : m_scaleFactor;
2543
// calculate transformations
2545
m_pageTransform.reset();
2550
m_pageTransform.rotate(0.0); break;
2552
m_pageTransform.rotate(90.0); break;
2554
m_pageTransform.rotate(180.0); break;
2556
m_pageTransform.rotate(270.0); break;
2559
foreach(PageItem* pageItem, m_pagesByIndex)
2561
pageItem->prepareGeometryChange();
2563
pageItem->m_linkTransform.reset();
2564
pageItem->m_linkTransform.scale(pageItem->m_scale * m_resolutionX / 72.0 * pageItem->m_size.width(), pageItem->m_scale * m_resolutionY / 72.0 * pageItem->m_size.height());
2566
pageItem->m_highlightTransform.reset();
2567
pageItem->m_highlightTransform.scale(pageItem->m_scale * m_resolutionX / 72.0, pageItem->m_scale * m_resolutionY / 72.0);
2572
pageItem->setRotation(0.0); break;
2574
pageItem->setRotation(90.0); break;
2576
pageItem->setRotation(180.0); break;
2578
pageItem->setRotation(270.0); break;
2584
disconnect(m_view->verticalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(slotVerticalScrollBarValueChanged(int)));
2586
m_pagesByHeight.clear();
2587
m_bookmarksMenu->clearList();
2589
qreal sceneWidth = 0.0, sceneHeight = pageSpacing;
2591
switch(m_pageLayout)
2595
for(int index = 0; index < m_numberOfPages; index++)
2597
PageItem* pageItem = m_pagesByIndex.at(index);
2598
QRectF rect = m_pageTransform.mapRect(pageItem->boundingRect());
2600
pageItem->setPos(pageSpacing - rect.left(), sceneHeight - rect.top());
2601
m_pagesByHeight.insert(sceneHeight, pageItem);
2603
sceneWidth = qMax(sceneWidth, rect.width() + 2 * pageSpacing);
2604
sceneHeight += rect.height() + pageSpacing;
2610
for(int index = 0; index < (m_numberOfPages % 2 == 0 ? m_numberOfPages : m_numberOfPages - 1); index += 2)
2612
PageItem* leftPageItem = m_pagesByIndex.at(index);
2613
PageItem* rightPageItem = m_pagesByIndex.at(index + 1);
2614
QRectF leftRect = m_pageTransform.mapRect(leftPageItem->boundingRect());
2615
QRectF rightRect = m_pageTransform.mapRect(rightPageItem->boundingRect());
2617
leftPageItem->setPos(pageSpacing - leftRect.left(), sceneHeight - leftRect.top());
2618
rightPageItem->setPos(2 * pageSpacing + leftRect.width() - rightRect.left(), sceneHeight - rightRect.top());
2619
m_pagesByHeight.insert(sceneHeight, leftPageItem);
2621
sceneWidth = qMax(sceneWidth, leftRect.width() + rightRect.width() + 3 * pageSpacing);
2622
sceneHeight += qMax(leftRect.height(), rightRect.height()) + pageSpacing;
2625
if(m_numberOfPages % 2 != 0)
2627
PageItem* leftPageItem = m_pagesByIndex.at(m_numberOfPages - 1);
2628
QRectF leftRect = m_pageTransform.mapRect(leftPageItem->boundingRect());
2630
leftPageItem->setPos(pageSpacing - leftRect.left(), sceneHeight - leftRect.top());
2631
m_pagesByHeight.insert(sceneHeight, leftPageItem);
2633
sceneWidth = qMax(sceneWidth, leftRect.width() + 2 * pageSpacing);
2634
sceneHeight += leftRect.height() + pageSpacing;
2640
m_scene->setSceneRect(0.0, 0.0, sceneWidth, sceneHeight);
2641
m_view->setSceneRect(0.0, 0.0, sceneWidth, sceneHeight);
2643
connect(m_view->verticalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(slotVerticalScrollBarValueChanged(int)));
2646
void DocumentView::prepareView(qreal top)
2648
disconnect(m_view->verticalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(slotVerticalScrollBarValueChanged(int)));
2650
PageItem* leftPageItem = m_pagesByIndex.value(m_currentPage - 1, 0);
2651
PageItem* rightPageItem = m_pagesByIndex.value(m_currentPage, 0);
2653
switch(m_pageLayout)
2656
foreach(PageItem* pageItem, m_pagesByIndex)
2658
pageItem->setVisible(false);
2661
if(leftPageItem != 0)
2663
leftPageItem->setVisible(true);
2665
QRectF leftRect = m_pageTransform.mapRect(leftPageItem->boundingRect()).translated(leftPageItem->pos());
2667
m_view->setSceneRect(leftRect.adjusted(-pageSpacing, -pageSpacing, pageSpacing, pageSpacing));
2668
m_view->verticalScrollBar()->setValue(qFloor(leftRect.top() + leftRect.height() * top));
2673
foreach(PageItem* pageItem, m_pagesByIndex)
2675
pageItem->setVisible(false);
2678
if(leftPageItem != 0 && rightPageItem != 0)
2680
leftPageItem->setVisible(true);
2681
rightPageItem->setVisible(true);
2683
QRectF leftRect = m_pageTransform.mapRect(leftPageItem->boundingRect()).translated(leftPageItem->pos());
2684
QRectF rightRect = m_pageTransform.mapRect(rightPageItem->boundingRect()).translated(rightPageItem->pos());
2686
m_view->setSceneRect(leftRect.united(rightRect).adjusted(-pageSpacing, -pageSpacing, pageSpacing, pageSpacing));
2687
m_view->verticalScrollBar()->setValue(qFloor(leftRect.top() + leftRect.height() * top));
2689
else if(leftPageItem != 0)
2691
leftPageItem->setVisible(true);
2693
QRectF leftRect = m_pageTransform.mapRect(leftPageItem->boundingRect()).translated(leftPageItem->pos());
2695
m_view->setSceneRect(leftRect.adjusted(-pageSpacing, -pageSpacing, pageSpacing, pageSpacing));
2696
m_view->verticalScrollBar()->setValue(qFloor(leftRect.top() + leftRect.height() * top));
2702
foreach(PageItem* pageItem, m_pagesByIndex)
2704
pageItem->setVisible(true);
2707
if(leftPageItem != 0)
2709
QRectF leftRect = m_pageTransform.mapRect(leftPageItem->boundingRect()).translated(leftPageItem->pos());
2711
m_view->verticalScrollBar()->setValue(qFloor(leftRect.top() + leftRect.height() * top));
2719
connect(m_view->verticalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(slotVerticalScrollBarValueChanged(int)));
2723
if(m_currentResult != m_results.end())
2725
PageItem* pageItem = m_pagesByIndex.value(m_currentResult.key(), 0);
2729
m_highlight->setPos(pageItem->pos());
2730
m_highlight->setTransform(pageItem->m_highlightTransform);
2731
m_highlight->setTransform(m_pageTransform, true);
2733
m_highlight->setRect(m_currentResult.value().adjusted(-1.0, -1.0, 1.0, 1.0));
2735
pageItem->stackBefore(m_highlight);
2737
m_highlight->setVisible(true);
2741
m_highlight->setVisible(false);
2746
m_highlight->setVisible(false);