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"
24
qreal DocumentView::s_pageSpacing = 5.0;
25
qreal DocumentView::s_thumbnailSpacing = 3.0;
27
qreal DocumentView::s_thumbnailSize = 150.0;
29
qreal DocumentView::s_minimumScaleFactor = 0.1;
30
qreal DocumentView::s_maximumScaleFactor = 10.0;
32
qreal DocumentView::pageSpacing()
37
void DocumentView::setPageSpacing(qreal pageSpacing)
39
if(pageSpacing >= 0.0)
41
s_pageSpacing = pageSpacing;
45
qreal DocumentView::thumbnailSpacing()
47
return s_thumbnailSpacing;
50
void DocumentView::setThumbnailSpacing(qreal thumbnailSpacing)
52
if(thumbnailSpacing >= 0.0)
54
s_thumbnailSpacing = thumbnailSpacing;
58
qreal DocumentView::thumbnailSize()
60
return s_thumbnailSize;
63
void DocumentView::setThumbnailSize(qreal thumbnailSize)
65
if(thumbnailSize >= 0.0)
67
s_thumbnailSize = thumbnailSize;
71
qreal DocumentView::minimumScaleFactor()
73
return s_minimumScaleFactor;
76
qreal DocumentView::maximumScaleFactor()
78
return s_maximumScaleFactor;
81
DocumentView::DocumentView(QWidget* parent) : QGraphicsView(parent),
89
m_continuousMode(false),
90
m_twoPagesMode(false),
91
m_scaleMode(ScaleFactor),
93
m_rotation(Poppler::Page::Rotate0),
94
m_highlightAll(false),
102
m_propertiesModel(0),
104
m_currentResult(m_results.end()),
107
m_pagesScene = new QGraphicsScene(this);
108
m_thumbnailsScene = new QGraphicsScene(this);
110
m_outlineModel = new QStandardItemModel(this);
111
m_propertiesModel = new QStandardItemModel(this);
113
setScene(m_pagesScene);
115
setDragMode(QGraphicsView::ScrollHandDrag);
116
setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
118
setAcceptDrops(false);
120
connect(verticalScrollBar(), SIGNAL(valueChanged(int)), SLOT(on_verticalScrollBar_valueChanged(int)));
124
m_highlight = new QGraphicsRectItem();
126
m_highlight->setVisible(false);
127
scene()->addItem(m_highlight);
129
QColor highlightColor = QApplication::palette().color(QPalette::Highlight);
131
highlightColor.setAlpha(192);
132
m_highlight->setBrush(QBrush(highlightColor));
134
highlightColor.setAlpha(255);
135
m_highlight->setPen(QPen(highlightColor));
139
m_search = new QFutureWatcher< QPair< int, QList< QRectF > > >(this);
141
connect(m_search, SIGNAL(resultReadyAt(int)), SLOT(on_search_resultReadyAt(int)));
142
connect(m_search, SIGNAL(progressValueChanged(int)), SLOT(on_search_progressValueChanged(int)));
143
connect(m_search, SIGNAL(canceled()), SIGNAL(searchCanceled()));
144
connect(m_search, SIGNAL(finished()), SIGNAL(searchFinished()));
148
m_autoRefreshWatcher = new QFileSystemWatcher(this);
149
m_autoRefreshTimer = new QTimer(this);
151
m_autoRefreshTimer->setInterval(500);
152
m_autoRefreshTimer->setSingleShot(true);
154
connect(m_autoRefreshWatcher, SIGNAL(fileChanged(QString)), m_autoRefreshTimer, SLOT(start()));
155
connect(m_autoRefreshTimer, SIGNAL(timeout()), this, SLOT(refresh()));
159
m_settings = new QSettings(this);
161
m_continuousMode = m_settings->value("documentView/continuousMode", false).toBool();
162
m_twoPagesMode = m_settings->value("documentView/twoPagesMode", false).toBool();
163
m_scaleMode = static_cast< ScaleMode >(m_settings->value("documentView/scaleMode", 0).toUInt());
164
m_scaleFactor = m_settings->value("documentView/scaleFactor", 1.0).toReal();
165
m_rotation = static_cast< Poppler::Page::Rotation >(m_settings->value("documentView/rotation", 0).toUInt());
168
DocumentView::~DocumentView()
171
qDeleteAll(m_thumbnails);
174
m_search->waitForFinished();
183
m_settings->setValue("documentView/continuousMode", m_continuousMode);
184
m_settings->setValue("documentView/twoPagesMode", m_twoPagesMode);
185
m_settings->setValue("documentView/scaleMode", static_cast< uint >(m_scaleMode));
186
m_settings->setValue("documentView/scaleFactor", m_scaleFactor);
187
m_settings->setValue("documentView/rotation", static_cast< uint >(m_rotation));
190
const QString& DocumentView::filePath() const
195
int DocumentView::numberOfPages() const
197
return m_numberOfPages;
200
int DocumentView::currentPage() const
202
return m_currentPage;
205
bool DocumentView::continousMode() const
207
return m_continuousMode;
210
void DocumentView::setContinousMode(bool continousMode)
212
if(m_continuousMode != continousMode)
214
m_continuousMode = continousMode;
218
emit continousModeChanged(m_continuousMode);
222
bool DocumentView::twoPagesMode() const
224
return m_twoPagesMode;
227
void DocumentView::setTwoPagesMode(bool twoPagesMode)
229
if(m_twoPagesMode != twoPagesMode)
231
m_twoPagesMode = twoPagesMode;
235
if(m_currentPage != (m_currentPage % 2 != 0 ? m_currentPage : m_currentPage - 1))
237
m_currentPage = m_currentPage % 2 != 0 ? m_currentPage : m_currentPage - 1;
239
emit currentPageChanged(m_currentPage);
246
emit twoPagesModeChanged(m_twoPagesMode);
250
DocumentView::ScaleMode DocumentView::scaleMode() const
255
void DocumentView::setScaleMode(ScaleMode scaleMode)
257
if(m_scaleMode != scaleMode)
259
m_scaleMode = scaleMode;
264
emit scaleModeChanged(m_scaleMode);
268
qreal DocumentView::scaleFactor() const
270
return m_scaleFactor;
273
void DocumentView::setScaleFactor(qreal scaleFactor)
275
if(m_scaleFactor != scaleFactor && scaleFactor >= s_minimumScaleFactor && scaleFactor <= s_maximumScaleFactor)
277
m_scaleFactor = scaleFactor;
279
if(m_scaleMode == ScaleFactor)
285
emit scaleFactorChanged(m_scaleFactor);
289
Poppler::Page::Rotation DocumentView::rotation() const
294
void DocumentView::setRotation(Poppler::Page::Rotation rotation)
296
if(m_rotation != rotation)
298
m_rotation = rotation;
303
emit rotationChanged(m_rotation);
307
bool DocumentView::highlightAll() const
309
return m_highlightAll;
312
void DocumentView::setHighlightAll(bool highlightAll)
314
if(m_highlightAll != highlightAll)
316
m_highlightAll = highlightAll;
318
for(int index = 0; index < m_numberOfPages; index++)
320
PageItem* page = m_pages.at(index);
322
page->setHighlights(m_highlightAll ? m_results.values(index) : QList< QRectF >());
325
emit highlightAllChanged(m_highlightAll);
329
QStandardItemModel* DocumentView::outlineModel() const
331
return m_outlineModel;
334
QStandardItemModel* DocumentView::propertiesModel() const
336
return m_propertiesModel;
339
QStandardItemModel* DocumentView::fontsModel()
343
QList< Poppler::FontInfo > fonts = m_document->fonts();
347
QStandardItemModel* fontsModel = new QStandardItemModel();
349
fontsModel->setRowCount(fonts.count());
350
fontsModel->setColumnCount(5);
352
fontsModel->setHorizontalHeaderLabels(QStringList() << tr("Name") << tr("Type") << tr("Embedded") << tr("Subset") << tr("File"));
354
for(int index = 0; index < fonts.count(); index++)
356
Poppler::FontInfo font = fonts.at(index);
358
fontsModel->setItem(index, 0, new QStandardItem(font.name()));
359
fontsModel->setItem(index, 1, new QStandardItem(font.typeName()));
360
fontsModel->setItem(index, 2, new QStandardItem(font.isEmbedded() ? tr("Yes") : tr("No")));
361
fontsModel->setItem(index, 3, new QStandardItem(font.isSubset() ? tr("Yes") : tr("No")));
362
fontsModel->setItem(index, 4, new QStandardItem(font.file()));
368
QGraphicsScene* DocumentView::thumbnailsScene() const
370
return m_thumbnailsScene;
373
QGraphicsItem* DocumentView::thumbnailsItem(int page) const
375
return m_thumbnails.value(page - 1, 0);
378
bool DocumentView::open(const QString& filePath)
380
Poppler::Document* document = Poppler::Document::load(filePath);
384
if(document->isLocked())
386
QString password = QInputDialog::getText(this, tr("Unlock document"), tr("Password:"), QLineEdit::Password);
388
if(document->unlock(password.toLatin1(), password.toLatin1()))
395
m_filePath = filePath;
396
m_numberOfPages = document->numPages();
400
prepareDocument(document);
402
emit filePathChanged(m_filePath);
403
emit numberOfPagesChanged(m_numberOfPages);
404
emit currentPageChanged(m_currentPage);
407
return document != 0;
410
bool DocumentView::refresh()
412
Poppler::Document* document = Poppler::Document::load(m_filePath);
416
if(document->isLocked())
418
QString password = QInputDialog::getText(this, tr("Unlock document"), tr("Password:"), QLineEdit::Password);
420
if(document->unlock(password.toLatin1(), password.toLatin1()))
427
m_numberOfPages = document->numPages();
428
m_currentPage = m_currentPage <= m_numberOfPages ? m_currentPage : 1;
429
m_returnToPage = m_returnToPage <= m_numberOfPages ? m_returnToPage : -1;
431
prepareDocument(document);
433
emit numberOfPagesChanged(m_numberOfPages);
434
emit currentPageChanged(m_currentPage);
437
return document != 0;
440
bool DocumentView::saveCopy(const QString& filePath)
444
Poppler::PDFConverter* pdfConverter = m_document->pdfConverter();
446
pdfConverter->setOutputFileName(filePath);
447
bool ok = pdfConverter->convert();
456
bool DocumentView::print(QPrinter* printer)
458
int fromPage = printer->fromPage() != 0 ? printer->fromPage() : 1;
459
int toPage = printer->toPage() != 0 ? printer->toPage() : m_numberOfPages;
464
cups_dest_t* dests = 0;
467
cups_option_t* options = 0;
469
cups_dest_t* dest = 0;
472
num_dests = cupsGetDests(&dests);
474
dest = cupsGetDest(printer->printerName().toLocal8Bit(), 0, num_dests, dests);
478
for(int index = 0; index < dest->num_options; index++)
480
num_options = cupsAddOption(dest->options[index].name, dest->options[index].value, num_options, &options);
483
num_options = cupsAddOption("page-ranges", QString("%1-%2").arg(fromPage).arg(toPage).toLocal8Bit(), num_options, &options);
485
num_options = cupsAddOption("copies", QString("%1").arg(printer->copyCount()).toLocal8Bit(), num_options, &options);
487
num_options = cupsAddOption("collate", QString("%1").arg(printer->collateCopies()).toLocal8Bit(), num_options, &options);
489
switch(printer->duplex())
491
case QPrinter::DuplexNone:
492
num_options = cupsAddOption("sides", "one-sided", num_options, &options);
494
case QPrinter::DuplexAuto:
496
case QPrinter::DuplexLongSide:
497
num_options = cupsAddOption("sides", "two-sided-long-edge", num_options, &options);
499
case QPrinter::DuplexShortSide:
500
num_options = cupsAddOption("sides", "two-sided-short-edge", num_options, &options);
504
switch(printer->pageOrder())
506
case QPrinter::FirstPageFirst:
507
num_options = cupsAddOption("outputorder", "normal", num_options, &options);
509
case QPrinter::LastPageFirst:
510
num_options = cupsAddOption("outputorder", "reverse", num_options, &options);
514
switch(printer->colorMode())
516
case QPrinter::Color:
518
case QPrinter::GrayScale:
519
num_options = cupsAddOption("ColorModel", "Gray", num_options, &options);
523
QFileInfo fileInfo(m_filePath);
525
jobId = cupsPrintFile(dest->name, fileInfo.absoluteFilePath().toLocal8Bit(), fileInfo.completeBaseName().toLocal8Bit(), num_options, options);
529
qDebug() << cupsLastErrorString();
534
qDebug() << cupsLastErrorString();
537
cupsFreeDests(num_dests, dests);
538
cupsFreeOptions(num_options, options);
544
QProgressDialog* progressDialog = new QProgressDialog(this);
545
progressDialog->setLabelText(tr("Printing '%1'...").arg(m_filePath));
546
progressDialog->setRange(fromPage - 1, toPage);
549
painter.begin(printer);
551
for(int index = fromPage - 1; index <= toPage - 1; index++)
553
progressDialog->setValue(index);
555
QApplication::processEvents();
560
Poppler::Page* page = m_document->page(index);
562
qreal pageWidth = printer->physicalDpiX() / 72.0 * page->pageSizeF().width();
563
qreal pageHeight = printer->physicalDpiY() / 72.0 * page->pageSizeF().height();
565
QImage image = page->renderToImage(printer->physicalDpiX(), printer->physicalDpiY());
571
qreal scaleFactor = qMin(printer->width() / pageWidth, printer->height() / pageHeight);
573
painter.setTransform(QTransform::fromScale(scaleFactor, scaleFactor));
574
painter.drawImage(QPointF(), image);
577
if(index < toPage - 1)
582
QApplication::processEvents();
584
if(progressDialog->wasCanceled())
586
delete progressDialog;
593
delete progressDialog;
599
void DocumentView::previousPage()
601
jumpToPage(currentPage() - (m_twoPagesMode ? 2 : 1));
604
void DocumentView::nextPage()
606
jumpToPage(currentPage() + (m_twoPagesMode ? 2 : 1));
609
void DocumentView::firstPage()
614
void DocumentView::lastPage()
616
jumpToPage(numberOfPages());
619
void DocumentView::jumpToPage(int page, qreal changeLeft, qreal changeTop)
621
if(page >= 1 && page <= m_numberOfPages && changeLeft >= 0.0 && changeLeft <= 1.0 && changeTop >= 0.0 && changeTop <= 1.0)
625
if(m_currentPage != (page % 2 != 0 ? page : page - 1) || changeLeft != 0.0 || changeTop != 0.0)
627
m_returnToPage = m_currentPage;
628
m_currentPage = page % 2 != 0 ? page : page - 1;
630
prepareView(changeLeft, changeTop);
632
emit currentPageChanged(m_currentPage);
637
if(m_currentPage != page || changeLeft != 0.0 || changeTop != 0.0)
639
m_returnToPage = m_currentPage;
640
m_currentPage = page;
642
prepareView(changeLeft, changeTop);
644
emit currentPageChanged(m_currentPage);
650
void DocumentView::startSearch(const QString& text, bool matchCase)
654
QList< int > indices;
656
indices.reserve(m_numberOfPages);
658
for(int index = m_currentPage - 1; index < m_numberOfPages; index++)
660
indices.append(index);
663
for(int index = 0; index < m_currentPage - 1; index++)
665
indices.append(index);
668
m_search->setFuture(QtConcurrent::mapped(indices, Search(&m_mutex, m_document, text, matchCase)));
671
void DocumentView::cancelSearch()
674
m_search->waitForFinished();
677
m_currentResult = m_results.end();
681
for(int index = 0; index < m_numberOfPages; index++)
683
PageItem* page = m_pages.at(index);
685
page->setHighlights(QList< QRectF >());
692
void DocumentView::findPrevious()
694
if(m_currentResult != m_results.end())
696
if(m_currentResult.key() == m_currentPage - 1 || (m_twoPagesMode && m_currentResult.key() == m_currentPage))
702
m_currentResult = --m_results.upperBound(m_currentPage - 1);
707
m_currentResult = --m_results.upperBound(m_currentPage - 1);
710
if(m_currentResult == m_results.end())
712
m_currentResult = --m_results.upperBound(m_numberOfPages - 1);
718
void DocumentView::findNext()
720
if(m_currentResult != m_results.end())
722
if(m_currentResult.key() == m_currentPage - 1 || (m_twoPagesMode && m_currentResult.key() == m_currentPage))
728
m_currentResult = --m_results.upperBound(m_currentPage - 1);
733
m_currentResult = --m_results.upperBound(m_currentPage - 1);
736
if(m_currentResult == m_results.end())
738
m_currentResult = m_results.lowerBound(0);
744
void DocumentView::zoomIn()
746
if(scaleMode() != ScaleFactor)
748
PageItem* page = m_pages.at(m_currentPage - 1);
750
setScaleFactor(qMin(page->scaleFactor() + 0.1, s_maximumScaleFactor));
751
setScaleMode(ScaleFactor);
755
setScaleFactor(qMin(scaleFactor() + 0.1, s_maximumScaleFactor));
759
void DocumentView::zoomOut()
761
if(scaleMode() != ScaleFactor)
763
PageItem* page = m_pages.at(m_currentPage - 1);
765
setScaleFactor(qMax(page->scaleFactor() - 0.1, s_minimumScaleFactor));
766
setScaleMode(ScaleFactor);
770
setScaleFactor(qMax(scaleFactor() - 0.1, s_minimumScaleFactor));
774
void DocumentView::originalSize()
777
setScaleMode(ScaleFactor);
780
void DocumentView::rotateLeft()
784
case Poppler::Page::Rotate0:
785
setRotation(Poppler::Page::Rotate270);
787
case Poppler::Page::Rotate90:
788
setRotation(Poppler::Page::Rotate0);
790
case Poppler::Page::Rotate180:
791
setRotation(Poppler::Page::Rotate90);
793
case Poppler::Page::Rotate270:
794
setRotation(Poppler::Page::Rotate180);
799
void DocumentView::rotateRight()
803
case Poppler::Page::Rotate0:
804
setRotation(Poppler::Page::Rotate90);
806
case Poppler::Page::Rotate90:
807
setRotation(Poppler::Page::Rotate180);
809
case Poppler::Page::Rotate180:
810
setRotation(Poppler::Page::Rotate270);
812
case Poppler::Page::Rotate270:
813
setRotation(Poppler::Page::Rotate0);
818
void DocumentView::presentation()
820
PresentationView* presentationView = new PresentationView(&m_mutex, m_document);
822
presentationView->jumpToPage(currentPage());
824
presentationView->show();
825
presentationView->setAttribute(Qt::WA_DeleteOnClose);
828
void DocumentView::on_verticalScrollBar_valueChanged(int value)
832
QMap< qreal, int >::const_iterator lowerBound = m_heightToIndex.lowerBound(-value);
834
if(lowerBound != m_heightToIndex.end())
836
int page = lowerBound.value() + 1;
838
if(m_currentPage != page)
840
m_currentPage = page;
842
emit currentPageChanged(m_currentPage);
848
void DocumentView::on_pages_linkClicked(int page, qreal left, qreal top)
850
page = page >= 1 ? page : 1;
851
page = page <= m_numberOfPages ? page : m_numberOfPages;
853
left = left >= 0.0 ? left : 0.0;
854
left = left <= 1.0 ? left : 1.0;
856
top = top >= 0.0 ? top : 0.0;
857
top = top <= 1.0 ? top : 1.0;
859
jumpToPage(page, left, top);
862
void DocumentView::on_pages_linkClicked(const QString& url)
864
if(m_settings->value("documentView/openUrl", false).toBool())
866
QDesktopServices::openUrl(QUrl(url));
870
QMessageBox::information(this, tr("Information"), tr("Opening URL is disabled in the settings."));
874
void DocumentView::on_thumbnails_pageClicked(int page)
876
page = page >= 1 ? page : 1;
877
page = page <= m_numberOfPages ? page : m_numberOfPages;
882
void DocumentView::on_search_resultReadyAt(int resultIndex)
884
int pageIndex = m_search->resultAt(resultIndex).first;
885
QList< QRectF > results = m_search->resultAt(resultIndex).second;
887
for(int index = results.count() - 1; index >= 0; index--)
889
m_results.insertMulti(pageIndex, results.at(index));
894
PageItem* page = m_pages.at(pageIndex);
896
page->setHighlights(results);
899
if(pageIndex >= m_currentPage - 1 && !results.isEmpty() && m_currentResult == m_results.end())
905
void DocumentView::on_search_progressValueChanged(int progressValue)
907
emit searchProgressed(100 * (progressValue - m_search->progressMinimum()) / (m_search->progressMaximum() - m_search->progressMinimum()));
910
void DocumentView::showEvent(QShowEvent* event)
912
QGraphicsView::showEvent(event);
914
if(!event->spontaneous())
920
void DocumentView::resizeEvent(QResizeEvent* event)
922
QGraphicsView::resizeEvent(event);
924
if(m_scaleMode != ScaleFactor)
931
void DocumentView::contextMenuEvent(QContextMenuEvent* event)
933
QMenu* menu = new QMenu();
935
QAction* returnAction = menu->addAction(tr("&Return"));
936
returnAction->setShortcut(QKeySequence(Qt::Key_Return));
937
returnAction->setEnabled(m_returnToPage != -1);
939
QAction* action = menu->exec(event->globalPos());
941
if(action == returnAction)
943
jumpToPage(m_returnToPage);
949
void DocumentView::keyPressEvent(QKeyEvent* event)
951
if(event->modifiers() == Qt::NoModifier)
953
if(event->key() == Qt::Key_Return)
955
jumpToPage(m_returnToPage);
961
if(!m_continuousMode)
963
if(event->key() == Qt::Key_PageUp && verticalScrollBar()->value() == verticalScrollBar()->minimum() && m_currentPage > 1)
967
verticalScrollBar()->setValue(verticalScrollBar()->maximum());
972
else if(event->key() == Qt::Key_PageDown && verticalScrollBar()->value() == verticalScrollBar()->maximum() && !currentPageIsLastPage())
976
verticalScrollBar()->setValue(verticalScrollBar()->minimum());
984
QGraphicsView::keyPressEvent(event);
987
void DocumentView::wheelEvent(QWheelEvent* event)
989
if(event->modifiers() == Qt::ControlModifier)
991
if(event->delta() > 0)
1003
else if(event->modifiers() == Qt::ShiftModifier)
1005
if(event->delta() > 0)
1017
else if(event->modifiers() == Qt::NoModifier)
1019
if(!m_continuousMode)
1021
if(event->delta() > 0 && verticalScrollBar()->value() == verticalScrollBar()->minimum() && m_currentPage > 1)
1025
verticalScrollBar()->setValue(verticalScrollBar()->maximum());
1030
else if(event->delta() < 0 && verticalScrollBar()->value() == verticalScrollBar()->maximum() && !currentPageIsLastPage())
1034
verticalScrollBar()->setValue(verticalScrollBar()->minimum());
1042
QGraphicsView::wheelEvent(event);
1045
bool DocumentView::currentPageIsLastPage()
1049
return m_currentPage == (m_numberOfPages % 2 != 0 ? m_numberOfPages : m_numberOfPages - 1);
1053
return m_currentPage == m_numberOfPages;
1057
void DocumentView::prepareDocument(Poppler::Document* document)
1059
qDeleteAll(m_pages);
1060
qDeleteAll(m_thumbnails);
1068
if(!m_autoRefreshWatcher->files().isEmpty())
1070
m_autoRefreshWatcher->removePaths(m_autoRefreshWatcher->files());
1074
m_document = document;
1076
if(m_settings->value("documentView/autoRefresh", false).toBool())
1078
m_autoRefreshWatcher->addPath(m_filePath);
1081
m_document->setRenderHint(Poppler::Document::Antialiasing, m_settings->value("documentView/antialiasing", true).toBool());
1082
m_document->setRenderHint(Poppler::Document::TextAntialiasing, m_settings->value("documentView/textAntialiasing", true).toBool());
1083
m_document->setRenderHint(Poppler::Document::TextHinting, m_settings->value("documentView/textHinting", false).toBool());
1086
prepareThumbnails();
1088
prepareProperties();
1094
void DocumentView::preparePages()
1097
m_pages.reserve(m_numberOfPages);
1099
for(int index = 0; index < m_numberOfPages; index++)
1101
PageItem* page = new PageItem(&m_mutex, m_document, index);
1103
page->setPhysicalDpi(physicalDpiX(), physicalDpiY());
1105
m_pagesScene->addItem(page);
1106
m_pages.append(page);
1108
connect(page, SIGNAL(linkClicked(int,qreal,qreal)), SLOT(on_pages_linkClicked(int,qreal,qreal)));
1109
connect(page, SIGNAL(linkClicked(QString)), SLOT(on_pages_linkClicked(QString)));
1112
if(m_settings->value("pageItem/decoratePages", true).toBool())
1114
m_pagesScene->setBackgroundBrush(QBrush(Qt::darkGray));
1118
m_pagesScene->setBackgroundBrush(QBrush(Qt::white));
1122
void DocumentView::prepareThumbnails()
1124
m_thumbnails.clear();
1125
m_thumbnails.reserve(m_numberOfPages);
1129
qreal height = s_thumbnailSpacing;
1131
for(int index = 0; index < m_numberOfPages; index++)
1133
ThumbnailItem* page = new ThumbnailItem(&m_mutex, m_document, index);
1135
page->setPhysicalDpi(physicalDpiX(), physicalDpiY());
1137
m_thumbnailsScene->addItem(page);
1138
m_thumbnails.append(page);
1140
connect(page, SIGNAL(pageClicked(int)), SLOT(on_thumbnails_pageClicked(int)));
1143
// prepare scale factor
1145
QSizeF size = page->size();
1147
qreal pageWidth = physicalDpiX() / 72.0 * size.width();
1148
qreal pageHeight = physicalDpiY() / 72.0 * size.height();
1150
page->setScaleFactor(qMin(s_thumbnailSize / pageWidth, s_thumbnailSize / pageHeight));
1156
QRectF boundingRect = page->boundingRect();
1158
page->setPos(-boundingRect.left() - 0.5 * boundingRect.width(), height - boundingRect.top());
1160
left = qMin(left, -0.5 * boundingRect.width() - s_thumbnailSpacing);
1161
right = qMax(right, 0.5 * boundingRect.width() + s_thumbnailSpacing);
1162
height += boundingRect.height() + s_thumbnailSpacing;
1165
QGraphicsSimpleTextItem* text = m_thumbnailsScene->addSimpleText(QString::number(index + 1));
1167
text->setPos(-0.5 * text->boundingRect().width(), height);
1169
height += text->boundingRect().height() + s_thumbnailSpacing;
1172
if(m_settings->value("pageItem/decoratePages", true).toBool())
1174
m_thumbnailsScene->setBackgroundBrush(QBrush(Qt::darkGray));
1178
m_thumbnailsScene->setBackgroundBrush(QBrush(Qt::white));
1181
m_thumbnailsScene->setSceneRect(left, 0.0, right - left, height);
1184
void DocumentView::prepareOutline()
1186
m_outlineModel->clear();
1188
QDomDocument* toc = m_document->toc();
1192
prepareOutline(toc->firstChild(), m_outlineModel->invisibleRootItem());
1198
void DocumentView::prepareOutline(const QDomNode& node, QStandardItem* parent)
1200
QDomElement element = node.toElement();
1202
QStandardItem* item = new QStandardItem();
1204
item->setFlags(Qt::ItemIsEnabled);
1206
item->setText(element.tagName());
1207
item->setToolTip(element.tagName());
1209
Poppler::LinkDestination* linkDestination = 0;
1211
if(element.hasAttribute("Destination"))
1213
linkDestination = new Poppler::LinkDestination(element.attribute("Destination"));
1215
else if(element.hasAttribute("DestinationName"))
1217
linkDestination = m_document->linkDestination(element.attribute("DestinationName"));
1220
if(linkDestination != 0)
1222
int page = linkDestination->pageNumber();
1226
page = page >= 1 ? page : 1;
1227
page = page <= m_numberOfPages ? page : m_numberOfPages;
1229
if(linkDestination->isChangeLeft())
1231
left = linkDestination->left();
1233
left = left >= 0.0 ? left : 0.0;
1234
left = left <= 1.0 ? left : 1.0;
1237
if(linkDestination->isChangeTop())
1239
top = linkDestination->top();
1241
top = top >= 0.0 ? top : 0.0;
1242
top = top <= 1.0 ? top : 1.0;
1245
item->setData(page, Qt::UserRole + 1);
1246
item->setData(left, Qt::UserRole + 2);
1247
item->setData(top, Qt::UserRole + 3);
1249
delete linkDestination;
1252
parent->appendRow(item);
1254
QDomNode siblingNode = node.nextSibling();
1255
if(!siblingNode.isNull())
1257
prepareOutline(siblingNode, parent);
1260
QDomNode childNode = node.firstChild();
1261
if(!childNode.isNull())
1263
prepareOutline(childNode, item);
1267
void DocumentView::prepareProperties()
1269
m_propertiesModel->clear();
1271
QStringList keys = m_document->infoKeys();
1273
m_propertiesModel->setRowCount(keys.count());
1274
m_propertiesModel->setColumnCount(2);
1276
for(int index = 0; index < keys.count(); index++)
1278
QString key = keys.at(index);
1279
QString value = m_document->info(key);
1281
if(value.startsWith("D:"))
1283
value = m_document->date(key).toString();
1286
m_propertiesModel->setItem(index, 0, new QStandardItem(key));
1287
m_propertiesModel->setItem(index, 1, new QStandardItem(value));
1291
void DocumentView::prepareScene()
1293
// prepare scale factor and rotation
1295
for(int index = 0; index < m_numberOfPages; index++)
1297
PageItem* page = m_pages.at(index);
1298
QSizeF size = page->size();
1300
if(m_scaleMode != ScaleFactor)
1302
qreal visibleWidth = 0.0;
1303
qreal visibleHeight = 0.0;
1305
qreal pageWidth = 0.0;
1306
qreal pageHeight = 0.0;
1308
qreal scaleFactor = 1.0;
1312
visibleWidth = 0.5 * (viewport()->width() - 6 - 3.0 * s_pageSpacing);
1316
visibleWidth = viewport()->width() - 6 - 2.0 * s_pageSpacing;
1319
visibleHeight = viewport()->height() - 2.0 * s_pageSpacing;
1323
case Poppler::Page::Rotate0:
1324
case Poppler::Page::Rotate180:
1325
pageWidth = physicalDpiX() / 72.0 * size.width();
1326
pageHeight = physicalDpiY() / 72.0 * size.height();
1328
case Poppler::Page::Rotate90:
1329
case Poppler::Page::Rotate270:
1330
pageWidth = physicalDpiX() / 72.0 * size.height();
1331
pageHeight = physicalDpiY() / 72.0 * size.width();
1339
case FitToPageWidth:
1340
scaleFactor = visibleWidth / pageWidth;
1343
scaleFactor = qMin(visibleWidth / pageWidth, visibleHeight / pageHeight);
1347
page->setScaleFactor(scaleFactor);
1351
page->setScaleFactor(m_scaleFactor);
1354
page->setRotation(m_rotation);
1359
m_heightToIndex.clear();
1361
qreal pageHeight = 0.0;
1365
qreal height = s_pageSpacing;
1367
for(int index = 0; index < m_numberOfPages; index++)
1369
PageItem* page = m_pages.at(index);
1370
QRectF boundingRect = page->boundingRect();
1376
page->setPos(-boundingRect.left() - boundingRect.width() - 0.5 * s_pageSpacing, height - boundingRect.top());
1378
m_heightToIndex.insert(-height + s_pageSpacing + 0.3 * pageHeight, index);
1380
pageHeight = boundingRect.height();
1382
left = qMin(left, -boundingRect.width() - 1.5 * s_pageSpacing);
1386
page->setPos(-boundingRect.left() + 0.5 * s_pageSpacing, height - boundingRect.top());
1388
pageHeight = qMax(pageHeight, boundingRect.height());
1390
right = qMax(right, boundingRect.width() + 1.5 * s_pageSpacing);
1391
height += pageHeight + s_pageSpacing;
1396
page->setPos(-boundingRect.left() - 0.5 * boundingRect.width(), height - boundingRect.top());
1398
m_heightToIndex.insert(-height + s_pageSpacing + 0.3 * pageHeight, index);
1400
pageHeight = boundingRect.height();
1402
left = qMin(left, -0.5 * boundingRect.width() - s_pageSpacing);
1403
right = qMax(right, 0.5 * boundingRect.width() + s_pageSpacing);
1404
height += pageHeight + s_pageSpacing;
1408
m_pagesScene->setSceneRect(left, 0.0, right - left, height);
1411
void DocumentView::prepareView(qreal changeLeft, qreal changeTop)
1413
qreal left = m_pagesScene->sceneRect().left();
1415
qreal width = m_pagesScene->sceneRect().width();
1416
qreal height = m_pagesScene->sceneRect().height();
1418
int horizontalValue = 0;
1419
int verticalValue = 0;
1421
for(int index = 0; index < m_pages.count(); index++)
1423
PageItem* page = m_pages.at(index);
1425
if(m_continuousMode)
1427
page->setVisible(true);
1429
if(Q_UNLIKELY(index == m_currentPage - 1))
1431
QRectF boundingRect = page->boundingRect().translated(page->pos());
1433
horizontalValue = qFloor(boundingRect.left() + changeLeft * boundingRect.width());
1434
verticalValue = qFloor(boundingRect.top() + changeTop * boundingRect.height());
1439
if(Q_UNLIKELY(index == m_currentPage - 1))
1441
page->setVisible(true);
1443
QRectF boundingRect = page->boundingRect().translated(page->pos());
1445
top = boundingRect.top() - s_pageSpacing;
1446
height = boundingRect.height() + 2.0 * s_pageSpacing;
1448
horizontalValue = qFloor(boundingRect.left() + changeLeft * boundingRect.width());
1449
verticalValue = qFloor(boundingRect.top() + changeTop * boundingRect.height());
1451
else if(m_twoPagesMode && Q_UNLIKELY(index == m_currentPage))
1453
page->setVisible(true);
1455
QRectF boundingRect = page->boundingRect().translated(page->pos());
1457
top = qMin(top, boundingRect.top() - s_pageSpacing);
1458
height = qMax(height, boundingRect.height() + 2.0 * s_pageSpacing);
1462
page->setVisible(false);
1466
if(m_currentResult != m_results.end())
1468
if(Q_UNLIKELY(m_currentResult.key() == index))
1470
m_highlight->setPos(page->pos());
1471
m_highlight->setTransform(page->transform());
1472
page->stackBefore(m_highlight);
1477
setSceneRect(left, top, width, height);
1479
horizontalScrollBar()->setValue(horizontalValue);
1480
verticalScrollBar()->setValue(verticalValue);
1483
void DocumentView::prepareHighlight()
1485
if(m_currentResult != m_results.end())
1487
jumpToPage(m_currentResult.key() + 1);
1489
PageItem* page = m_pages.at(m_currentResult.key());
1491
m_highlight->setPos(page->pos());
1492
m_highlight->setTransform(page->transform());
1493
page->stackBefore(m_highlight);
1495
m_highlight->setRect(m_currentResult.value());
1497
m_highlight->setVisible(true);
1499
disconnect(verticalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(on_verticalScrollBar_valueChanged(int)));
1500
centerOn(m_highlight);
1501
connect(verticalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(on_verticalScrollBar_valueChanged(int)));
1505
m_highlight->setVisible(false);
1509
DocumentView::Search::Search(QMutex *mutex, Poppler::Document *document, const QString &text, bool matchCase) :
1511
m_document(document),
1513
m_matchCase(matchCase)
1517
QPair< int, QList< QRectF > > DocumentView::Search::operator()(int index)
1519
QList< QRectF > results;
1523
Poppler::Page* page = m_document->page(index);
1525
#if defined(HAS_POPPLER_22)
1527
results = page->search(m_text, m_matchCase ? Poppler::Page::CaseSensitive : Poppler::Page::CaseInsensitive);
1529
#elif defined(HAS_POPPLER_14)
1531
double left = 0.0, top = 0.0, right = 0.0, bottom = 0.0;
1533
while(page->search(m_text, left, top, right, bottom, Poppler::Page::NextResult, m_matchCase ? Poppler::Page::CaseSensitive : Poppler::Page::CaseInsensitive))
1538
rect.setRight(right);
1539
rect.setBottom(bottom);
1541
results.append(rect);
1548
while(page->search(m_text, rect, Poppler::Page::NextResult, m_matchCase ? Poppler::Page::CaseSensitive : Poppler::Page::CaseInsensitive))
1550
results.append(rect);
1559
return qMakePair(index, results);