1 /***************************************************************************
2 * copyright : (C) 2012-2017 by Pascal Brachet *
3 * http://www.xm1math.net/texmaker/ *
4 * based on qpdfview Copyright 2012 Adam Reichold GPL *
5 * *
6 * This program is free software; you can redistribute it and/or modify *
7 * it under the terms of the GNU General Public License as published by *
8 * the Free Software Foundation; either version 2 of the License, or *
9 * (at your option) any later version. *
10 * *
11 ***************************************************************************/
12 /*
13
14 Copyright 2012 Adam Reichold
15
16 This file is part of qpdfview.
17
18 modified by Pascal Brachet
19
20 */
21
22 #include "documentview.h"
23 #include <QProgressDialog>
24 #include <QDir>
25 #include <QFileDialog>
26 #include <QMessageBox>
27 #include <QDebug>
28 #include <QProgressBar>
29 #include <QScrollBar>
30 #include <QApplication>
31 #include <QInputDialog>
32 #include <QLineEdit>
33
34 bool DocumentView::s_openUrl = false;
35
36 bool DocumentView::s_autoRefresh = false;
37
38 bool DocumentView::s_antialiasing = true;
39 bool DocumentView::s_textAntialiasing = true;
40 bool DocumentView::s_textHinting = false;
41
42 bool DocumentView::s_prefetch = false;
43
44 qreal DocumentView::s_pageSpacing = 5.0;
45
46 qreal DocumentView::s_minimumScaleFactor = 0.1;
47 qreal DocumentView::s_maximumScaleFactor = 10.0;
48
openUrl()49 bool DocumentView::openUrl()
50 {
51 return s_openUrl;
52 }
53
setOpenUrl(bool openUrl)54 void DocumentView::setOpenUrl(bool openUrl)
55 {
56 s_openUrl = openUrl;
57 }
58
autoRefresh()59 bool DocumentView::autoRefresh()
60 {
61 return s_autoRefresh;
62 }
63
setAutoRefresh(bool autoRefresh)64 void DocumentView::setAutoRefresh(bool autoRefresh)
65 {
66 s_autoRefresh = autoRefresh;
67 }
68
antialiasing()69 bool DocumentView::antialiasing()
70 {
71 return s_antialiasing;
72 }
73
setAntialiasing(bool antialiasing)74 void DocumentView::setAntialiasing(bool antialiasing)
75 {
76 s_antialiasing = antialiasing;
77 }
78
textAntialiasing()79 bool DocumentView::textAntialiasing()
80 {
81 return s_textAntialiasing;
82 }
83
setTextAntialiasing(bool textAntialiasing)84 void DocumentView::setTextAntialiasing(bool textAntialiasing)
85 {
86 s_textAntialiasing = textAntialiasing;
87 }
88
textHinting()89 bool DocumentView::textHinting()
90 {
91 return s_textHinting;
92 }
93
setTextHinting(bool textHinting)94 void DocumentView::setTextHinting(bool textHinting)
95 {
96 s_textHinting = textHinting;
97 }
98
prefetch()99 bool DocumentView::prefetch()
100 {
101 return s_prefetch;
102 }
103
setPrefetch(bool prefetch)104 void DocumentView::setPrefetch(bool prefetch)
105 {
106 s_prefetch = prefetch;
107 }
108
pageSpacing()109 qreal DocumentView::pageSpacing()
110 {
111 return s_pageSpacing;
112 }
113
setPageSpacing(qreal pageSpacing)114 void DocumentView::setPageSpacing(qreal pageSpacing)
115 {
116 if(pageSpacing >= 0.0)
117 {
118 s_pageSpacing = pageSpacing;
119 }
120 }
121
minimumScaleFactor()122 qreal DocumentView::minimumScaleFactor()
123 {
124 return s_minimumScaleFactor;
125 }
126
maximumScaleFactor()127 qreal DocumentView::maximumScaleFactor()
128 {
129 return s_maximumScaleFactor;
130 }
131
DocumentView(QWidget * parent)132 DocumentView::DocumentView(QWidget* parent) : QGraphicsView(parent),
133 m_autoRefreshWatcher(0),
134 m_autoRefreshTimer(0),
135 m_prefetchTimer(0),
136 m_mutex(),
137 m_document(0),
138 m_filePath(),
139 m_numberOfPages(-1),
140 m_currentPage(-1),
141 m_returnToPage(-1),
142 m_returnToLeft(0.0),
143 m_returnToTop(0.0),
144 m_continuousMode(false),
145 m_twoPagesMode(false),
146 m_scaleMode(ScaleFactor),
147 m_scaleFactor(0.1),
148 m_rotation(QPdf::Rotate0),
149 m_pagesScene(0),
150 m_pages(),
151 m_heightToIndex(),
152 m_highlight(0),
153 m_outlineModel(0),
154 m_propertiesModel(0)
155 {
156 m_pagesScene = new QGraphicsScene(this);
157 m_outlineModel = new QPdfBookmarkModel(this);
158 m_propertiesModel = new QStandardItemModel(this);
159
160 m_filePath="";
161 m_currentPage=-1;
162 m_returnToPage=-1;
163
164 setScene(m_pagesScene);
165
166 setDragMode(QGraphicsView::ScrollHandDrag);
167 setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
168 setCursor(Qt::ArrowCursor);
169 // setLineWidth(1);
170 setFrameShape(QFrame::Box);
171 setFrameShadow(QFrame::Plain);
172 //QApplication::setOverrideCursor(Qt::ArrowCursor);
173 setAcceptDrops(false);
174
175 connect(verticalScrollBar(), SIGNAL(valueChanged(int)), this,SLOT(on_verticalScrollBar_valueChanged(int)));
176 connect(horizontalScrollBar(), SIGNAL(valueChanged(int)), this,SLOT(on_horizontalScrollBar_valueChanged(int)));
177
178 // highlight
179
180 m_highlight = new QGraphicsRectItem();
181
182 m_highlight->setVisible(false);
183 scene()->addItem(m_highlight);
184
185 QColor highlightColor = QApplication::palette().color(QPalette::Highlight);
186
187 highlightColor.setAlpha(127);
188 m_highlight->setBrush(QBrush(highlightColor));
189
190 highlightColor.setAlpha(255);
191 m_highlight->setPen(QPen(highlightColor));
192
193
194 // auto-refresh
195
196 m_autoRefreshWatcher = new QFileSystemWatcher(this);
197 m_autoRefreshTimer = new QTimer(this);
198
199 m_autoRefreshTimer->setInterval(500);
200 m_autoRefreshTimer->setSingleShot(true);
201
202 connect(m_autoRefreshWatcher, SIGNAL(fileChanged(QString)), m_autoRefreshTimer, SLOT(start()));
203 connect(m_autoRefreshTimer, SIGNAL(timeout()), this, SLOT(refresh()));
204
205 // prefetch
206
207 m_prefetchTimer = new QTimer(this);
208 m_prefetchTimer->setInterval(250);
209 m_prefetchTimer->setSingleShot(true);
210
211 connect(this, SIGNAL(currentPageChanged(int)), m_prefetchTimer, SLOT(start()));
212 connect(this, SIGNAL(scaleModeChanged(DocumentView::ScaleMode)), m_prefetchTimer, SLOT(start()));
213 connect(this, SIGNAL(scaleFactorChanged(qreal)), m_prefetchTimer, SLOT(start()));
214 connect(this, SIGNAL(rotationChanged(QPdf::Rotation)), m_prefetchTimer, SLOT(start()));
215
216 connect(m_prefetchTimer, SIGNAL(timeout()), this,SLOT(on_prefetch_timeout()));
217 }
218
~DocumentView()219 DocumentView::~DocumentView()
220 {
221 qDeleteAll(m_pages);
222
223
224 }
225
clearAll()226 void DocumentView::clearAll()
227 {
228 disconnect(verticalScrollBar(), SIGNAL(valueChanged(int)), this,SLOT(on_verticalScrollBar_valueChanged(int)));
229 disconnect(horizontalScrollBar(), SIGNAL(valueChanged(int)),this, SLOT(on_horizontalScrollBar_valueChanged(int)));
230 disconnect(m_autoRefreshWatcher, SIGNAL(fileChanged(QString)), m_autoRefreshTimer, SLOT(start()));
231 disconnect(m_autoRefreshTimer, SIGNAL(timeout()), this, SLOT(refresh()));
232 disconnect(this, SIGNAL(currentPageChanged(int)), m_prefetchTimer, SLOT(start()));
233 disconnect(this, SIGNAL(scaleModeChanged(DocumentView::ScaleMode)), m_prefetchTimer, SLOT(start()));
234 disconnect(this, SIGNAL(scaleFactorChanged(qreal)), m_prefetchTimer, SLOT(start()));
235 disconnect(this, SIGNAL(rotationChanged(QPdf::Rotation)), m_prefetchTimer, SLOT(start()));
236 disconnect(m_prefetchTimer, SIGNAL(timeout()), this,SLOT(on_prefetch_timeout()));
237 m_pages.clear();
238 m_numberOfPages=-1;
239 scene()->clear();
240 m_pagesScene = new QGraphicsScene(this);
241 m_filePath="";
242 m_currentPage=-1;
243 m_returnToPage=-1;
244 setScene(m_pagesScene);
245 m_highlight = new QGraphicsRectItem();
246 m_highlight->setVisible(false);
247 scene()->addItem(m_highlight);
248 prepareScene();
249 prepareView(0,0);
250 QColor highlightColor = QApplication::palette().color(QPalette::Highlight);
251 highlightColor.setAlpha(127);
252 m_highlight->setBrush(QBrush(highlightColor));
253 highlightColor.setAlpha(255);
254 m_highlight->setPen(QPen(highlightColor));
255 update();
256 connect(verticalScrollBar(), SIGNAL(valueChanged(int)), SLOT(on_verticalScrollBar_valueChanged(int)));
257 connect(horizontalScrollBar(), SIGNAL(valueChanged(int)), SLOT(on_horizontalScrollBar_valueChanged(int)));
258 connect(m_autoRefreshWatcher, SIGNAL(fileChanged(QString)), m_autoRefreshTimer, SLOT(start()));
259 connect(m_autoRefreshTimer, SIGNAL(timeout()), this, SLOT(refresh()));
260 connect(this, SIGNAL(currentPageChanged(int)), m_prefetchTimer, SLOT(start()));
261 connect(this, SIGNAL(scaleModeChanged(DocumentView::ScaleMode)), m_prefetchTimer, SLOT(start()));
262 connect(this, SIGNAL(scaleFactorChanged(qreal)), m_prefetchTimer, SLOT(start()));
263 connect(this, SIGNAL(rotationChanged(QPdf::Rotation)), m_prefetchTimer, SLOT(start()));
264 connect(m_prefetchTimer, SIGNAL(timeout()), SLOT(on_prefetch_timeout()));
265 }
266
filePath() const267 const QString& DocumentView::filePath() const
268 {
269 return m_filePath;
270 }
271
numberOfPages() const272 int DocumentView::numberOfPages() const
273 {
274 return m_numberOfPages;
275 }
276
currentPage() const277 int DocumentView::currentPage() const
278 {
279 return m_currentPage;
280 }
281
continousMode() const282 bool DocumentView::continousMode() const
283 {
284 return m_continuousMode;
285 }
286
setContinousMode(bool continousMode)287 void DocumentView::setContinousMode(bool continousMode)
288 {
289 if (m_pages.count()<1) return;
290 if(m_continuousMode != continousMode)
291 {
292 m_continuousMode = continousMode;
293
294 qreal left = 0.0, top = 0.0;
295 saveLeftAndTop(left, top);
296
297 prepareView(left, top);
298
299 emit continousModeChanged(m_continuousMode);
300 }
301 }
302
twoPagesMode() const303 bool DocumentView::twoPagesMode() const
304 {
305 return m_twoPagesMode;
306 }
307
setTwoPagesMode(bool twoPagesMode)308 void DocumentView::setTwoPagesMode(bool twoPagesMode)
309 {
310 if (m_pages.count()<1) return;
311 if(m_twoPagesMode != twoPagesMode)
312 {
313 m_twoPagesMode = twoPagesMode;
314
315 if(m_twoPagesMode)
316 {
317 if(m_currentPage != (m_currentPage % 2 != 0 ? m_currentPage : m_currentPage - 1))
318 {
319 m_currentPage = m_currentPage % 2 != 0 ? m_currentPage : m_currentPage - 1;
320
321 emit currentPageChanged(m_currentPage);
322 }
323 }
324
325 prepareScene();
326 prepareView();
327
328 emit twoPagesModeChanged(m_twoPagesMode);
329 }
330 }
331
scaleMode() const332 DocumentView::ScaleMode DocumentView::scaleMode() const
333 {
334 return m_scaleMode;
335 }
336
setScaleMode(ScaleMode scaleMode)337 void DocumentView::setScaleMode(ScaleMode scaleMode)
338 {
339 if (m_pages.count()<1) return;
340 if(m_scaleMode != scaleMode)
341 {
342 m_scaleMode = scaleMode;
343
344 qreal left = 0.0, top = 0.0;
345 saveLeftAndTop(left, top);
346
347 prepareScene();
348 prepareView(left, top);
349
350 emit scaleModeChanged(m_scaleMode);
351 }
352 }
353
scaleFactor() const354 qreal DocumentView::scaleFactor() const
355 {
356 return m_scaleFactor;
357 }
358
realScale() const359 qreal DocumentView::realScale() const
360 {
361 if (m_pages.count()<1) return 1;
362 return m_pages.at(0)->scaleFactor();
363 }
364
setScaleFactor(qreal scaleFactor)365 void DocumentView::setScaleFactor(qreal scaleFactor)
366 {
367 if (m_pages.count()<1) return;
368 if(m_scaleFactor != scaleFactor && scaleFactor >= s_minimumScaleFactor && scaleFactor <= s_maximumScaleFactor)
369 {
370 m_scaleFactor = scaleFactor;
371
372 if(m_scaleMode == ScaleFactor)
373 {
374 qreal left = 0.0, top = 0.0;
375 saveLeftAndTop(left, top);
376
377 prepareScene();
378 prepareView(left, top);
379 // #if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
380 // viewport()->update();
381 // #endif
382 }
383
384 emit scaleFactorChanged(m_scaleFactor);
385 }
386 }
387
doc() const388 QPdfDocument* DocumentView::doc() const
389 {
390 return m_document;
391 }
392
rotation() const393 QPdf::Rotation DocumentView::rotation() const
394 {
395 return m_rotation;
396 }
397
setRotation(QPdf::Rotation rotation)398 void DocumentView::setRotation(QPdf::Rotation rotation)
399 {
400 if (m_pages.count()<1) return;
401 if(m_rotation != rotation)
402 {
403 m_rotation = rotation;
404
405 prepareScene();
406 prepareView();
407
408 emit rotationChanged(m_rotation);
409 }
410 }
411
412
clearPaths(int index)413 void DocumentView::clearPaths(int index)
414 {
415 if ((m_pages.count()<1) || (index>=m_pages.count())) return;
416 m_pages.at(index)->clearPaths();
417 }
418
setHighlightPath(int index,const QPainterPath & path)419 void DocumentView::setHighlightPath(int index, const QPainterPath& path)
420 {
421 if ((m_pages.count()<1) || (index>=m_pages.count())) return;
422 m_pages.at(index)->setHighlightPath(path);
423 }
424
setSearchPath(int index,const QPainterPath & path)425 void DocumentView::setSearchPath(int index, const QPainterPath& path)
426 {
427 if ((m_pages.count()<1) || (index>=m_pages.count())) return;
428 m_pages.at(index)->setSearchPath(path);
429 }
430
outlineModel() const431 QPdfBookmarkModel* DocumentView::outlineModel() const
432 {
433 return m_outlineModel;
434 }
435
propertiesModel() const436 QStandardItemModel* DocumentView::propertiesModel() const
437 {
438 return m_propertiesModel;
439 }
440
441
442
show()443 void DocumentView::show()
444 {
445 QGraphicsView::show();
446
447 prepareView();
448 }
449
open(const QString & filePath)450 bool DocumentView::open(const QString& filePath)
451 {
452 QPdfDocument* document=new QPdfDocument(this);
453 QPdfDocument::DocumentError result=document->load(filePath);
454
455 if (result== QPdfDocument::NoError)
456 {
457 m_filePath = filePath;
458 m_numberOfPages = document->pageCount();
459 m_currentPage = 1;
460 m_returnToPage = -1;
461 prepareDocument(document);
462 prepareScene();
463 prepareView();
464 emit filePathChanged(m_filePath);
465 emit numberOfPagesChanged(m_numberOfPages);
466 emit currentPageChanged(m_currentPage);
467 }
468
469 return result== QPdfDocument::NoError ;
470 }
471
refresh()472 bool DocumentView::refresh()
473 {
474 QPdfDocument* document=new QPdfDocument(this);
475 QPdfDocument::DocumentError result=document->load(m_filePath);
476
477 if (result== QPdfDocument::NoError)
478 {
479
480 qreal left = 0.0, top = 0.0;
481 saveLeftAndTop(left, top);
482
483 m_numberOfPages = document->pageCount();
484 m_currentPage = m_currentPage <= m_numberOfPages ? m_currentPage : 1;
485
486 m_returnToPage = m_returnToPage <= m_numberOfPages ? m_returnToPage : -1;
487
488 prepareDocument(document);
489
490 prepareScene();
491 prepareView(left, top);
492
493 emit numberOfPagesChanged(m_numberOfPages);
494 emit currentPageChanged(m_currentPage);
495 }
496
497 return result== QPdfDocument::NoError ;
498 }
499
print(QPrinter * printer)500 bool DocumentView::print(QPrinter* printer)
501 {
502 int fromPage = printer->fromPage() != 0 ? printer->fromPage() : 1;
503 int toPage = printer->toPage() != 0 ? printer->toPage() : m_numberOfPages;
504
505 QProgressDialog* progressDialog = new QProgressDialog(this);
506 progressDialog->setLabelText(tr("Printing '%1'...").arg(m_filePath));
507 progressDialog->setRange(fromPage - 1, toPage);
508
509 QPainter painter;
510 painter.begin(printer);
511
512 for(int index = fromPage - 1; index <= toPage - 1; index++)
513 {
514 progressDialog->setValue(index);
515
516 QApplication::processEvents();
517
518 {
519 m_mutex.lock();
520
521 const QSizeF size = m_document->pageSize(index);
522
523 qreal pageWidth = printer->physicalDpiX() / 72.0 * size.width();
524 qreal pageHeight = printer->physicalDpiY() / 72.0 * size.height();
525
526 ////????????????????????????
527 QImage image = m_document->render(index,QSize(size.width()*printer-> physicalDpiX()/72,size.height()*printer-> physicalDpiY()/72));
528
529 //QImage image = page->renderToImage(printer->physicalDpiX(), printer->physicalDpiY());
530
531
532
533 m_mutex.unlock();
534
535 qreal scaleFactor = qMin(printer->width() / pageWidth, printer->height() / pageHeight);
536
537 painter.setTransform(QTransform::fromScale(scaleFactor, scaleFactor));
538 painter.drawImage(QPointF(), image);
539 }
540
541 if(index < toPage - 1)
542 {
543 printer->newPage();
544 }
545
546 QApplication::processEvents();
547
548 if(progressDialog->wasCanceled())
549 {
550 delete progressDialog;
551 return false;
552 }
553 }
554
555 painter.end();
556
557 delete progressDialog;
558 return true;
559 }
560
previousPage()561 void DocumentView::previousPage()
562 {
563 if (m_pages.count()<1) return;
564 jumpToPage(currentPage() - (m_twoPagesMode ? 2 : 1), 0.0, 0.0, false);
565 }
566
nextPage()567 void DocumentView::nextPage()
568 {
569 if (m_pages.count()<1) return;
570 jumpToPage(currentPage() + (m_twoPagesMode ? 2 : 1), 0.0, 0.0, false);
571 }
572
firstPage()573 void DocumentView::firstPage()
574 {
575 if (m_pages.count()<1) return;
576 jumpToPage(1);
577 }
578
lastPage()579 void DocumentView::lastPage()
580 {
581 if (m_pages.count()<1) return;
582 jumpToPage(numberOfPages());
583 }
584
jumpToPage(int page,qreal changeLeft,qreal changeTop,bool returnTo)585 void DocumentView::jumpToPage(int page, qreal changeLeft, qreal changeTop, bool returnTo)
586 {
587 if (m_pages.count()<1) return;
588 if(page >= 1 && page <= m_numberOfPages)
589 {
590 qreal left = 0.0, top = 0.0;
591 saveLeftAndTop(left, top);
592
593 if(m_currentPage != currentPageForPage(page) || !qFuzzyCompare(1.0 + left, 1.0 + changeLeft) || !qFuzzyCompare(1.0 + top, 1.0 + changeTop))
594 {
595 if(returnTo)
596 {
597 m_returnToPage = m_currentPage;
598 m_returnToLeft = left; m_returnToTop = top;
599 }
600
601 m_currentPage = currentPageForPage(page);
602
603 prepareView(changeLeft, changeTop);
604
605 emit currentPageChanged(m_currentPage);
606 }
607 }
608 }
609
610
611
zoomIn()612 void DocumentView::zoomIn()
613 {
614 if (m_pages.count()<1) return;
615 if(scaleMode() != ScaleFactor)
616 {
617 PageItem* page = m_pages.at(m_currentPage - 1);
618
619 setScaleFactor(qMin(page->scaleFactor() + 0.1f, s_maximumScaleFactor));
620 setScaleMode(ScaleFactor);
621 }
622 else
623 {
624 setScaleFactor(qMin(scaleFactor() + 0.1f, s_maximumScaleFactor));
625 }
626 }
627
zoomOut()628 void DocumentView::zoomOut()
629 {
630 if (m_pages.count()<1) return;
631 if(scaleMode() != ScaleFactor)
632 {
633 PageItem* page = m_pages.at(m_currentPage - 1);
634
635 setScaleFactor(qMax(page->scaleFactor() - 0.1f, s_minimumScaleFactor));
636 setScaleMode(ScaleFactor);
637 }
638 else
639 {
640 setScaleFactor(qMax(scaleFactor() - 0.1f, s_minimumScaleFactor));
641 }
642 }
643
originalSize()644 void DocumentView::originalSize()
645 {
646 setScaleFactor(1.0);
647 setScaleMode(ScaleFactor);
648 }
649
rotateLeft()650 void DocumentView::rotateLeft()
651 {
652 switch(rotation())
653 {
654 case QPdf::Rotate0:
655 setRotation(QPdf::Rotate270);
656 break;
657 case QPdf::Rotate90:
658 setRotation(QPdf::Rotate0);
659 break;
660 case QPdf::Rotate180:
661 setRotation(QPdf::Rotate90);
662 break;
663 case QPdf::Rotate270:
664 setRotation(QPdf::Rotate180);
665 break;
666 }
667 }
668
rotateRight()669 void DocumentView::rotateRight()
670 {
671 switch(rotation())
672 {
673 case QPdf::Rotate0:
674 setRotation(QPdf::Rotate90);
675 break;
676 case QPdf::Rotate90:
677 setRotation(QPdf::Rotate180);
678 break;
679 case QPdf::Rotate180:
680 setRotation(QPdf::Rotate270);
681 break;
682 case QPdf::Rotate270:
683 setRotation(QPdf::Rotate0);
684 break;
685 }
686 }
687
presentation()688 void DocumentView::presentation()
689 {
690 if (m_pages.count()<1) return;
691 PresentationView* presentationView = new PresentationView(&m_mutex, m_document);
692
693 presentationView->jumpToPage(currentPage());
694
695 presentationView->show();
696 presentationView->setAttribute(Qt::WA_DeleteOnClose);
697 }
698
on_horizontalScrollBar_valueChanged(int value)699 void DocumentView::on_horizontalScrollBar_valueChanged(int value)
700 {
701 if (m_pages.count()<1) return;
702 if ( horizontalScrollBar()->maximum()!=0) emit doHScroll(value);
703 }
704
on_verticalScrollBar_valueChanged(int value)705 void DocumentView::on_verticalScrollBar_valueChanged(int value)
706 {
707 if (m_pages.count()<1) return;
708 if(m_continuousMode)
709 {
710 QRectF visibleRect = mapToScene(viewport()->rect()).boundingRect();
711
712 foreach(PageItem* page, m_pages)
713 {
714 if(!page->boundingRect().translated(page->pos()).intersects(visibleRect))
715 {
716 page->cancelRender();
717 }
718 }
719
720 QMap< qreal, int >::const_iterator lowerBound = m_heightToIndex.lowerBound(-value);
721
722 if(lowerBound != m_heightToIndex.end())
723 {
724 int page = lowerBound.value() + 1;
725
726 if(m_currentPage != page)
727 {
728 m_currentPage = page;
729
730 emit currentPageChanged(m_currentPage);
731 }
732 }
733 }
734 }
735
736
on_prefetch_timeout()737 void DocumentView::on_prefetch_timeout()
738 {
739 if (m_pages.count()<1) return;
740 int fromPage = m_currentPage - (m_twoPagesMode ? 2 : 1);
741 int toPage = m_currentPage + (m_twoPagesMode ? 3 : 1);
742
743 fromPage = fromPage >= 1 ? fromPage : 1;
744 toPage = toPage <= m_numberOfPages ? toPage : m_numberOfPages;
745
746 for(int index = fromPage - 1; index <= toPage - 1; index++)
747 {
748 PageItem* page = m_pages.at(index);
749
750 page->startRender(true);
751 }
752 }
753
on_pages_linkClicked(int page,qreal left,qreal top)754 void DocumentView::on_pages_linkClicked(int page, qreal left, qreal top)
755 {
756 if (m_pages.count()<1) return;
757 page = page >= 1 ? page : 1;
758 page = page <= m_numberOfPages ? page : m_numberOfPages;
759
760 left = left >= 0.0 ? left : 0.0;
761 left = left <= 1.0 ? left : 1.0;
762
763 top = top >= 0.0 ? top : 0.0;
764 top = top <= 1.0 ? top : 1.0;
765
766 emit gotoDest(page, left, top);
767 }
768
on_pages_linkClicked(const QString & url)769 void DocumentView::on_pages_linkClicked(const QString& url)
770 {
771 QUrl theurl = QUrl::fromEncoded(url.toLatin1());
772 QDesktopServices::openUrl(theurl);
773 }
774
resizeEvent(QResizeEvent * event)775 void DocumentView::resizeEvent(QResizeEvent* event)
776 {
777 QGraphicsView::resizeEvent(event);
778
779 if(m_scaleMode != ScaleFactor)
780 {
781 qreal left = 0.0, top = 0.0;
782 saveLeftAndTop(left, top);
783
784 prepareScene();
785 prepareView(left, top);
786 }
787 }
788
keyPressEvent(QKeyEvent * event)789 void DocumentView::keyPressEvent(QKeyEvent* event)
790 {
791 if (m_pages.count()<1) return;
792 if(event->modifiers() == Qt::NoModifier)
793 {
794 if(event->key() == Qt::Key_Return)
795 {
796 jumpToPage(m_returnToPage, m_returnToLeft, m_returnToTop);
797
798 event->accept();
799 return;
800 }
801
802 if(!m_continuousMode)
803 {
804 if(event->key() == Qt::Key_PageUp && verticalScrollBar()->value() == verticalScrollBar()->minimum() && m_currentPage > 1)
805 {
806 previousPage();
807
808 verticalScrollBar()->setValue(verticalScrollBar()->maximum());
809
810 event->accept();
811 return;
812 }
813 else if(event->key() == Qt::Key_PageDown && verticalScrollBar()->value() == verticalScrollBar()->maximum() && m_currentPage != currentPageForPage(m_numberOfPages))
814 {
815 nextPage();
816
817 verticalScrollBar()->setValue(verticalScrollBar()->minimum());
818
819 event->accept();
820 return;
821 }
822 }
823 }
824 int qtKeyCode = event->key();
825
826 if(event->modifiers() & Qt::ShiftModifier) {
827 qtKeyCode += Qt::SHIFT;
828 }
829 if(event->modifiers() & Qt::ControlModifier) {
830 qtKeyCode += Qt::CTRL;
831 }
832 if(event->modifiers() & Qt::AltModifier) {
833 qtKeyCode += Qt::ALT;
834 }
835 if(event->modifiers() & Qt::MetaModifier) {
836 qtKeyCode += Qt::META;
837 }
838 QKeySequence s1 = QKeySequence(qtKeyCode);
839 if (hasFocus() && (s1.matches(QKeySequence(Qt::CTRL + Qt::Key_Left))==QKeySequence::ExactMatch)) rotateLeft();
840 else if (hasFocus() && (s1.matches(QKeySequence(Qt::CTRL + Qt::Key_Right))==QKeySequence::ExactMatch)) rotateRight();
841 else QGraphicsView::keyPressEvent(event);
842 }
843
844
mouseReleaseEvent(QMouseEvent * event)845 void DocumentView::mouseReleaseEvent(QMouseEvent* event)
846 {
847 QApplication::setOverrideCursor(Qt::ArrowCursor);
848 QGraphicsView::mouseReleaseEvent(event);
849 }
850
mousePressEvent(QMouseEvent * event)851 void DocumentView::mousePressEvent(QMouseEvent* event)
852 {
853 QGraphicsView::mousePressEvent(event);
854 //QApplication::setOverrideCursor(Qt::ArrowCursor);
855
856 // if(!event->isAccepted() && event->modifiers() == Qt::NoModifier && event->button() == Qt::RightButton)
857 // {
858 // QMenu* menu = new QMenu();
859 //
860 // QAction* returnToPageAction = menu->addAction(tr("&Return to page %1").arg(m_returnToPage));
861 // returnToPageAction->setShortcut(QKeySequence(Qt::Key_Return));
862 // returnToPageAction->setIcon(QIcon::fromTheme("go-jump", QIcon(":icons/go-jump.svg")));
863 // returnToPageAction->setIconVisibleInMenu(true);
864 //
865 // returnToPageAction->setVisible(m_returnToPage != -1);
866 //
867 // QAction* previousPageAction = menu->addAction(tr("&Previous page"));
868 // previousPageAction->setShortcut(QKeySequence(Qt::Key_Backspace));
869 // previousPageAction->setIcon(QIcon::fromTheme("go-previous", QIcon(":icons/go-previous.svg")));
870 // previousPageAction->setIconVisibleInMenu(true);
871 //
872 // QAction* nextPageAction = menu->addAction(tr("&Next page"));
873 // nextPageAction->setShortcut(QKeySequence(Qt::Key_Space));
874 // nextPageAction->setIcon(QIcon::fromTheme("go-next", QIcon(":icons/go-next.svg")));
875 // nextPageAction->setIconVisibleInMenu(true);
876 //
877 // QAction* refreshAction = menu->addAction(tr("&Refresh"));
878 // refreshAction->setShortcut(QKeySequence::Refresh);
879 // refreshAction->setIcon(QIcon::fromTheme("view-refresh", QIcon(":icons/view-refresh.svg")));
880 // refreshAction->setIconVisibleInMenu(true);
881 //
882 // QAction* action = menu->exec(event->globalPos());
883 //
884 // if(action == returnToPageAction)
885 // {
886 // jumpToPage(m_returnToPage, m_returnToLeft, m_returnToTop);
887 // }
888 // else if(action == previousPageAction)
889 // {
890 // previousPage();
891 // }
892 // else if(action == nextPageAction)
893 // {
894 // nextPage();
895 // }
896 // else if(action == refreshAction)
897 // {
898 // refresh();
899 // }
900 //
901 // delete menu;
902 // }
903 }
904
wheelEvent(QWheelEvent * event)905 void DocumentView::wheelEvent(QWheelEvent* event)
906 {
907 if (m_pages.count()<1) return;
908 if(event->modifiers() == Qt::ControlModifier)
909 {
910 if(event->delta() > 0)
911 {
912 emit requestZoomIn();//zoomIn();
913 }
914 else
915 {
916 emit requestZoomOut();//zoomOut();
917 }
918
919 event->accept();
920 return;
921 }
922 else if(event->modifiers() == Qt::ShiftModifier)
923 {
924 if(event->delta() > 0)
925 {
926 rotateLeft();
927 }
928 else
929 {
930 rotateRight();
931 }
932
933 event->accept();
934 return;
935 }
936 else if(event->modifiers() == Qt::NoModifier)
937 {
938 if(!m_continuousMode)
939 {
940 if(event->delta() > 0 && verticalScrollBar()->value() == verticalScrollBar()->minimum() && m_currentPage > 1)
941 {
942 previousPage();
943
944 verticalScrollBar()->setValue(verticalScrollBar()->maximum());
945
946 event->accept();
947 return;
948 }
949 else if(event->delta() < 0 && verticalScrollBar()->value() == verticalScrollBar()->maximum() && m_currentPage != currentPageForPage(m_numberOfPages))
950 {
951 nextPage();
952
953 verticalScrollBar()->setValue(verticalScrollBar()->minimum());
954
955 event->accept();
956 return;
957 }
958 }
959 }
960
961 QGraphicsView::wheelEvent(event);
962 }
963
currentPageForPage(int page)964 int DocumentView::currentPageForPage(int page)
965 {
966 if(m_twoPagesMode)
967 {
968 return page % 2 != 0 ? page : page - 1;
969 }
970 else
971 {
972 return page;
973 }
974 }
975
saveLeftAndTop(qreal & left,qreal & top)976 void DocumentView::saveLeftAndTop(qreal& left, qreal& top)
977 {
978 if ((m_pages.count()>0) && (m_currentPage>=1))
979 {
980 PageItem* page = m_pages.at(m_currentPage - 1);
981
982 QRectF boundingRect = page->boundingRect().translated(page->pos());
983 QPointF topLeft = mapToScene(viewport()->rect().topLeft());
984
985 left = (topLeft.x() - boundingRect.x()) / boundingRect.width();
986 top = (topLeft.y() - boundingRect.y()) / boundingRect.height();
987 }
988 }
989
prepareDocument(QPdfDocument * document)990 void DocumentView::prepareDocument(QPdfDocument* document)
991 {
992 m_prefetchTimer->blockSignals(true);
993 m_prefetchTimer->stop();
994
995 qDeleteAll(m_pages);
996
997
998
999 if(m_document != 0)
1000 {
1001 delete m_document;
1002
1003 if(!m_autoRefreshWatcher->files().isEmpty())
1004 {
1005 m_autoRefreshWatcher->removePaths(m_autoRefreshWatcher->files());
1006 }
1007 }
1008
1009 m_document = document;
1010
1011 if(s_autoRefresh)
1012 {
1013 m_autoRefreshWatcher->addPath(m_filePath);
1014 }
1015
1016 // m_document->setRenderHint(Poppler::Document::Antialiasing, s_antialiasing);
1017 // m_document->setRenderHint(Poppler::Document::TextAntialiasing, s_textAntialiasing);
1018 // m_document->setRenderHint(Poppler::Document::TextHinting, s_textHinting);
1019
1020 preparePages();
1021 prepareOutline();
1022 prepareProperties();
1023
1024 if(s_prefetch)
1025 {
1026 m_prefetchTimer->blockSignals(false);
1027 m_prefetchTimer->start();
1028 }
1029 }
1030
preparePages()1031 void DocumentView::preparePages()
1032 {
1033 m_pages.clear();
1034 m_pages.reserve(m_numberOfPages);
1035
1036 QProgressDialog* progressDialog = new QProgressDialog(this);
1037 // QProgressBar* progress = new QProgressBar();
1038 // progress->setFormat(" ");
1039 // progress->setMaximum(0);
1040 // progress->setMinimum(0);
1041 // progressDialog->setBar(progress);
1042 progressDialog->setLabelText(tr("Loading pdf..."));
1043 progressDialog->setCancelButton(0);
1044 progressDialog->setRange(0,m_numberOfPages-1);
1045 // progressDialog->setMinimumDuration(0);
1046 // progressDialog->show();
1047 // progressDialog->raise();
1048
1049 for(int index = 0; index < m_numberOfPages; index++)
1050 {
1051 progressDialog->setValue(index);
1052 //QApplication::processEvents();
1053 PageItem* page = new PageItem(&m_mutex, m_document, index);
1054 const int dpr = int(qApp->devicePixelRatio());
1055 if (qApp->devicePixelRatio()>=2) page->setPhysicalDpi(physicalDpiX()*dpr, physicalDpiY()*dpr);
1056 else page->setPhysicalDpi(physicalDpiX(), physicalDpiY());
1057
1058 m_pagesScene->addItem(page);
1059 m_pages.append(page);
1060
1061 connect(page, SIGNAL(linkClicked(int,qreal,qreal)), SLOT(on_pages_linkClicked(int,qreal,qreal)));
1062 connect(page, SIGNAL(linkClicked(QString)), SLOT(on_pages_linkClicked(QString)));
1063 connect(page, SIGNAL(syncpage(int, const QPointF&)), this, SLOT(on_syncpage(int, const QPointF&)));
1064 connect(page, SIGNAL(wantPngExport(int)), this, SLOT(pngExport(int)));
1065 connect(page, SIGNAL(wantNumWords()), this, SLOT(countWords()));
1066 connect(page, SIGNAL(wantNumPageWords(int)), this, SLOT(countPageWords(int)));
1067 connect(page, SIGNAL(wantOpenLocation()), this, SLOT(openFileBrowser()));
1068 }
1069
1070 progressDialog->cancel();
1071 delete progressDialog;
1072 if(PageItem::decoratePages())
1073 {
1074 m_pagesScene->setBackgroundBrush(QBrush(Qt::darkGray));
1075 }
1076 else
1077 {
1078 m_pagesScene->setBackgroundBrush(QBrush(PageItem::invertColors() ? Qt::black : Qt::white));
1079 }
1080 }
1081
1082
prepareOutline()1083 void DocumentView::prepareOutline()
1084 {
1085 //m_outlineModel->clear();
1086 m_outlineModel->setDocument(m_document);
1087 }
1088
1089
1090
prepareProperties()1091 void DocumentView::prepareProperties()
1092 {
1093 // m_propertiesModel->clear();
1094 //
1095 // QStringList keys = m_document->infoKeys();
1096 //
1097 // m_propertiesModel->setRowCount(keys.count());
1098 // m_propertiesModel->setColumnCount(2);
1099 //
1100 // for(int index = 0; index < keys.count(); index++)
1101 // {
1102 // QString key = keys.at(index);
1103 // QString value = m_document->info(key);
1104 //
1105 // if(value.startsWith("D:"))
1106 // {
1107 // value = m_document->date(key).toString();
1108 // }
1109 //
1110 // m_propertiesModel->setItem(index, 0, new QStandardItem(key));
1111 // m_propertiesModel->setItem(index, 1, new QStandardItem(value));
1112 // }
1113 }
1114
prepareScene()1115 void DocumentView::prepareScene()
1116 {
1117 // prepare scale factor and rotation
1118
1119 for(int index = 0; index < m_numberOfPages; index++)
1120 {
1121 PageItem* page = m_pages.at(index);
1122 QSizeF size = page->size();
1123
1124 if(m_scaleMode != ScaleFactor)
1125 {
1126 qreal visibleWidth = 0.0;
1127 qreal visibleHeight = 0.0;
1128
1129 qreal pageWidth = 0.0;
1130 qreal pageHeight = 0.0;
1131
1132 qreal scaleFactor = 1.0;
1133
1134 if(m_twoPagesMode)
1135 {
1136 visibleWidth = 0.5 * (viewport()->width() - 6.0 - 3.0 * s_pageSpacing);
1137 }
1138 else
1139 {
1140 visibleWidth = viewport()->width() - 6.0 - 2.0 * s_pageSpacing;
1141 }
1142 visibleHeight = viewport()->height() - 2.0 * s_pageSpacing;
1143
1144 switch(m_rotation)
1145 {
1146 case QPdf::Rotate0:
1147 case QPdf::Rotate180:
1148 pageWidth = physicalDpiX() / 72.0 * size.width();
1149 pageHeight = physicalDpiY() / 72.0 * size.height();
1150 break;
1151 case QPdf::Rotate90:
1152 case QPdf::Rotate270:
1153 pageWidth = physicalDpiX() / 72.0 * size.height();
1154 pageHeight = physicalDpiY() / 72.0 * size.width();
1155 break;
1156 }
1157
1158 switch(m_scaleMode)
1159 {
1160 case ScaleFactor:
1161 break;
1162 case FitToPageWidth:
1163 scaleFactor = visibleWidth / pageWidth;
1164 break;
1165 case FitToPageSize:
1166 scaleFactor = qMin(visibleWidth / pageWidth, visibleHeight / pageHeight);
1167 break;
1168 }
1169
1170 page->setScaleFactor(scaleFactor);
1171 }
1172 else
1173 {
1174 page->setScaleFactor(m_scaleFactor);
1175 }
1176
1177 page->setRotation(m_rotation);
1178 }
1179
1180 // prepare layout
1181
1182 m_heightToIndex.clear();
1183
1184 qreal pageHeight = 0.0;
1185
1186 qreal left = 0.0;
1187 qreal right = 0.0;
1188 qreal height = s_pageSpacing;
1189
1190 for(int index = 0; index < m_numberOfPages; index++)
1191 {
1192 PageItem* page = m_pages.at(index);
1193 QRectF boundingRect = page->boundingRect();
1194
1195 if(m_twoPagesMode)
1196 {
1197 if(index % 2 == 0)
1198 {
1199 page->setPos(-boundingRect.left() - boundingRect.width() - 0.5 * s_pageSpacing, height - boundingRect.top());
1200
1201 m_heightToIndex.insert(-height + s_pageSpacing + 0.3 * pageHeight, index);
1202
1203 pageHeight = boundingRect.height();
1204
1205 left = qMin(left, -boundingRect.width() - 1.5f * s_pageSpacing);
1206 }
1207 else
1208 {
1209 page->setPos(-boundingRect.left() + 0.5 * s_pageSpacing, height - boundingRect.top());
1210
1211 pageHeight = qMax(pageHeight, boundingRect.height());
1212
1213 right = qMax(right, boundingRect.width() + 1.5f * s_pageSpacing);
1214 height += pageHeight + s_pageSpacing;
1215 }
1216 }
1217 else
1218 {
1219 page->setPos(-boundingRect.left() - 0.5 * boundingRect.width(), height - boundingRect.top());
1220
1221 m_heightToIndex.insert(-height + s_pageSpacing + 0.3 * pageHeight, index);
1222
1223 pageHeight = boundingRect.height();
1224
1225 left = qMin(left, -0.5f * boundingRect.width() - s_pageSpacing);
1226 right = qMax(right, 0.5f * boundingRect.width() + s_pageSpacing);
1227 height += pageHeight + s_pageSpacing;
1228 }
1229 }
1230
1231 if(m_twoPagesMode && m_numberOfPages % 2 != 0)
1232 {
1233 right = qMax(right, 0.5f * s_pageSpacing);
1234 height += pageHeight + s_pageSpacing;
1235 }
1236
1237 m_pagesScene->setSceneRect(left, 0.0, right - left, height);
1238 }
1239
prepareView(qreal changeLeft,qreal changeTop)1240 void DocumentView::prepareView(qreal changeLeft, qreal changeTop)
1241 {
1242 qreal left = m_pagesScene->sceneRect().left();
1243 qreal top = m_pagesScene->sceneRect().top();
1244 qreal width = m_pagesScene->sceneRect().width();
1245 qreal height = m_pagesScene->sceneRect().height();
1246
1247 int horizontalValue = 0;
1248 int verticalValue = 0;
1249
1250 for(int index = 0; index < m_pages.count(); index++)
1251 {
1252 PageItem* page = m_pages.at(index);
1253
1254 if(m_continuousMode)
1255 {
1256 page->setVisible(true);
1257
1258 if(index == m_currentPage - 1)
1259 {
1260 QRectF boundingRect = page->boundingRect().translated(page->pos());
1261
1262 horizontalValue = qFloor(boundingRect.left() + changeLeft * boundingRect.width());
1263 verticalValue = qFloor(boundingRect.top() + changeTop * boundingRect.height());
1264 }
1265 }
1266 else
1267 {
1268 if(index == m_currentPage - 1)
1269 {
1270 page->setVisible(true);
1271
1272 QRectF boundingRect = page->boundingRect().translated(page->pos());
1273
1274 top = boundingRect.top() - s_pageSpacing;
1275 height = boundingRect.height() + 2.0 * s_pageSpacing;
1276
1277 horizontalValue = qFloor(boundingRect.left() + changeLeft * boundingRect.width());
1278 verticalValue = qFloor(boundingRect.top() + changeTop * boundingRect.height());
1279 }
1280 else if(m_twoPagesMode && index == m_currentPage)
1281 {
1282 page->setVisible(true);
1283
1284 QRectF boundingRect = page->boundingRect().translated(page->pos());
1285
1286 top = qMin(top, boundingRect.top() - s_pageSpacing);
1287 height = qMax(height, boundingRect.height() + 2.0f * s_pageSpacing);
1288 }
1289 else
1290 {
1291 page->setVisible(false);
1292
1293 page->cancelRender();
1294 }
1295 }
1296
1297 }
1298
1299 setSceneRect(left, top, width, height);
1300
1301 horizontalScrollBar()->setValue(horizontalValue);
1302 verticalScrollBar()->setValue(verticalValue);
1303 viewport()->update();
1304 }
1305
prepareHighlight()1306 void DocumentView::prepareHighlight()
1307 {
1308
1309 m_highlight->setVisible(false);
1310 }
1311
showRect(int index,const QRectF & r)1312 void DocumentView::showRect(int index, const QRectF &r)
1313 {
1314 QGraphicsRectItem* h=new QGraphicsRectItem();
1315 jumpToPage(index+1);
1316 if (index >= m_pages.count()) return;
1317 PageItem* page = m_pages.at(index);
1318 h->setPos(page->pos());
1319 h->setTransform(page->transform());
1320 h->setRect(r.normalized());
1321 h->setVisible(true);
1322 disconnect(verticalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(on_verticalScrollBar_valueChanged(int)));
1323 centerOn(h);
1324 connect(verticalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(on_verticalScrollBar_valueChanged(int)));
1325
1326 }
1327
on_syncpage(int index,const QPointF & pagePos)1328 void DocumentView::on_syncpage(int index, const QPointF& pagePos)
1329 {
1330 QPointF pos((pagePos.x()) / scaleFactor() / physicalDpiX() * 72.0,(pagePos.y()) / scaleFactor() / physicalDpiY() * 72.0 );
1331 emit syncpage(index, pos);
1332 }
1333
countWords()1334 void DocumentView::countWords()
1335 {
1336 QString pdf_text="";
1337 int numwords=0;
1338 int pagewords=0;
1339 QProgressDialog progress("",tr("Cancel"), 0, m_document->pageCount(), this);
1340 progress.setWindowTitle("Texmaker");
1341 progress.setWindowModality(Qt::WindowModal);
1342 for (int i = 0; i < m_document->pageCount(); ++i)
1343 {
1344 progress.setValue(i);
1345 qApp->processEvents();
1346 if (progress.wasCanceled()) return;
1347 pagewords=0;
1348 pdf_text=m_document->checkTextAt(i, m_pages.at(i)->boundingRect(), m_pages.at(i)->boundingRect());
1349 pdf_text=pdf_text.simplified();
1350 pagewords=pdf_text.count(" ");
1351 if (!pdf_text.isEmpty()) pagewords++;
1352 numwords+=pagewords;
1353 }
1354 progress.setValue(m_document->pageCount());
1355 QMessageBox::information( this,"Texmaker",tr("Number of words in the document")+QString(" : ")+QString::number(numwords));
1356 }
1357
pngExport(int page)1358 void DocumentView::pngExport(int page)
1359 {
1360 QImage image = m_pages.at(page)->exportImagePage();
1361 if (image.isNull()) return;
1362 QString currentDir=QDir::homePath();
1363 QFileInfo fi(m_filePath);
1364 if (fi.exists() && fi.isReadable()) currentDir=fi.absolutePath();
1365 QString fn = QFileDialog::getSaveFileName(this,tr("Save As"),currentDir,"Png Image (*.png)");
1366 if ( !fn.isEmpty() )
1367 {
1368 image.save(fn,"PNG");
1369 }
1370 }
1371
countPageWords(int page)1372 void DocumentView::countPageWords(int page)
1373 {
1374 QString pdf_text="";
1375 int numwords=0;
1376 int pagewords=0;
1377 pdf_text=m_document->checkTextAt(page, m_pages.at(page)->boundingRect(), m_pages.at(page)->boundingRect());
1378 pdf_text=pdf_text.simplified();
1379 pagewords=pdf_text.count(" ");
1380 if (!pdf_text.isEmpty()) pagewords++;
1381 numwords+=pagewords;
1382 QMessageBox::information( this,"Texmaker",tr("Number of words in the page")+QString(" : ")+QString::number(numwords));
1383 }
1384
openFileBrowser()1385 void DocumentView::openFileBrowser()
1386 {
1387 QString currentDir="file://";
1388 QFileInfo fi(m_filePath);
1389 if (fi.exists() && fi.isReadable()) currentDir+=fi.absolutePath();
1390 QDesktopServices::openUrl(QUrl(currentDir));
1391 }
1392
1393
1394