1 /*
2 	This is part of TeXworks, an environment for working with TeX documents
3 	Copyright (C) 2007-2010  Jonathan Kew
4 
5 	This program is free software; you can redistribute it and/or modify
6 	it under the terms of the GNU General Public License as published by
7 	the Free Software Foundation; either version 2 of the License, or
8 	(at your option) any later version.
9 
10 	This program is distributed in the hope that it will be useful,
11 	but WITHOUT ANY WARRANTY; without even the implied warranty of
12 	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 	GNU General Public License for more details.
14 
15 	You should have received a copy of the GNU General Public License
16 	along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 
18 	For links to further information, or to contact the author,
19 	see <http://texworks.org/>.
20 */
21 
22 #ifndef Header_PDF_Document
23 #define Header_PDF_Document
24 
25 #ifndef NO_POPPLER_PREVIEW
26 
27 
28 #include "mostQtHeaders.h"
29 
30 #include <QGestureEvent>
31 #include <QPinchGesture>
32 #include <QTapGesture>
33 #include <QPainterPath>
34 #include <QProgressDialog>
35 #include <QPainterPath>
36 #if QT_VERSION_MAJOR>5
37 #include "poppler-qt6.h"
38 #else
39 #include "poppler-qt5.h"
40 #endif
41 #include "poppler-version.h"
42 #include "qsynctex.h"
43 
44 #include "pdfrendermanager.h"
45 
46 
47 const int kPDFWindowStateVersion = 1;
48 
49 class QAction;
50 class QMenu;
51 class QToolBar;
52 class QScrollArea;
53 class QShortcut;
54 class QFileSystemWatcher;
55 class ConfigManagerInterface;
56 class PDFDocument;
57 class PDFWidget;
58 
59 class TitledPanel;
60 class PDFAnnotations;
61 class PDFAnnotation;
62 class PDFAnnotationTableView;
63 class MessageFrame;
64 
65 
66 class PDFMagnifier : public QLabel
67 {
68 	Q_OBJECT
69 
70 public:
71 	PDFMagnifier(QWidget *parent, qreal inDpi);
72 	void setPage(int p, qreal scale, const QRect &visibleRect);
73 	void reshape();
74 
75 public slots:
76 	void setImage(const QPixmap &img, int pageNr);
77 
78 protected:
79 	virtual void paintEvent(QPaintEvent *event);
80 	QPixmap &getConvertedImage();
81 
82 private:
83 	int oldshape;
84 	int page;
85     qreal   overScale;
86 	qreal	scaleFactor;
87 	qreal	parentDpi;
88 	QPixmap	image;
89 	QPixmap	convertedImage;
90 	bool	convertedImageIsGrayscale;
91 	bool	convertedImageIsColorInverted;
92 
93 	QPoint mouseTranslate;
94 
95 	QPoint	imageLoc, mouseOffset;
96 	QSize	imageSize;
97 	qreal	imageDpi;
98 	int imagePage;
99 };
100 
101 #ifdef PHONON
102 #include <phonon/VideoPlayer>
103 
104 class PDFMovie: public Phonon::VideoPlayer
105 {
106 	Q_OBJECT
107 public:
108 	PDFMovie(PDFWidget *parent, QSharedPointer<Poppler::MovieAnnotation> annot, int page);
109 	void place();
110 protected:
111 	void contextMenuEvent(QContextMenuEvent *);
112 	void mouseReleaseEvent(QMouseEvent *e);
113 public slots:
114 	void realPlay();
115 	void setVolumeDialog();
116 	void seekDialog();
117 private:
118 	QMenu *popup;
119 	QRectF boundary;
120 	int page;
121 };
122 #endif
123 
124 typedef enum {
125 	kFixedMag,
126 	kFitWidth,
127 	kFitWindow,
128 	kFitTextWidth
129 } autoScaleOption;
130 
131 struct PDFPageHistoryItem{
132 	int page;
133     double x, y;
PDFPageHistoryItemPDFPageHistoryItem134 	PDFPageHistoryItem():page(0),x(0),y(0){}
PDFPageHistoryItemPDFPageHistoryItem135     PDFPageHistoryItem(int page, double x, double y):page(page),x(x),y(y){}
136 };
137 
138 class PDFScrollArea;
139 class PDFWidget : public QLabel
140 {
141 	Q_OBJECT
142 
143 public:
144 	explicit PDFWidget(bool embedded = false);
145 	virtual ~PDFWidget();
146 
147 	void setDocument(const QSharedPointer<Poppler::Document> &doc);
148 	void setPDFDocument(PDFDocument *docu);
149 
150 	void saveState(); // used when toggling full screen mode
151 	void restoreState();
152 	void setResolution(int res);
153 	void resetMagnifier();
154 	Q_INVOKABLE int normalizedPageIndex(int pageIndex);
155 	Q_INVOKABLE void goToPageDirect(int pageIndex, bool sync);
156     Q_INVOKABLE void setHighlightPath(const int pageIndex, const QPainterPath &path, const bool dontRemove=false);
157 	Q_INVOKABLE int getHighlightPage() const;
158 	Q_INVOKABLE void goToDestination(const QString &destName);
159     Q_INVOKABLE void goToPageRelativePosition(int page, double xinpage, double yinpage);
160 	Q_INVOKABLE int getPageIndex();
161     Q_INVOKABLE void reloadPage(bool sync = true);
162 	void updateStatusBar();
163 	void setGridSize(int gx, int gy, bool setAsDefault = false);
164 	Q_INVOKABLE int visiblePages() const;
165 	Q_INVOKABLE int pseudoNumPages() const;
166 	Q_INVOKABLE int realNumPages() const;
167 	Q_INVOKABLE int pageStep();
168 	Q_INVOKABLE int gridCols() const;
169 	Q_INVOKABLE int gridRowHeight() const;
170 	Q_INVOKABLE int gridBorder() const;
171 	Q_INVOKABLE PDFDocument *getPDFDocument();
172 	Q_INVOKABLE int getPageOffset() const;
getScaleOption()173 	autoScaleOption getScaleOption() { return scaleOption; }
174 	double totalScaleFactor() const;
175 
176 	int currentPageHistoryIndex() const;
177 	const QList<PDFPageHistoryItem> currentPageHistory() const;
178 	void updateCurrentPageHistoryOffset();
179 
180 	QPoint gridPagePosition(int pageIndex) const;
181 	QRect gridPageRect(int pageIndex) const;
182 	int gridPageIndex(const QPoint &position) const;
183 	void mapToScaledPosition(const QPoint &position, int &page, QPointF &scaledPos) const;
184 	QPoint mapFromScaledPosition(int page, const QPointF &scaledPos) const;
185 	int pageFromPos(const QPoint &pos) const;
186 	QRect pageRect(int page) const;
187 	QSizeF maxPageSizeF() const;
188 	QSizeF maxPageSizeFDpiAdjusted() const;
189 	QRectF horizontalTextRangeF();
190 
191 	Q_INVOKABLE void zoom(qreal scale);
192 
193 	virtual void wheelEvent(QWheelEvent *event);
194 
195 protected slots: //not private, so scripts have access
196 	void goFirst();
197 	void goPrev();
198 	void goNext();
199 	void goLast();
200 	void goForward();
201 	void goBack();
202 	void doPageDialog();
203 
204 	void fitWidth(bool checked = true);
205 	void fitTextWidth(bool checked = true);
206 	void zoomIn();
207 	void zoomOut();
208 	void jumpToSource();
209 
210 	void upOrPrev();
211 	void leftOrPrev();
212 	void pageUpOrPrev();
213 
214 	void downOrNext();
215 	void rightOrNext();
216 	void pageDownOrNext();
217 
218 	void clearHighlight();
219 	void openAnnotationDialog(const PDFAnnotation *annon);
220 
221 public slots:
222 	void setSinglePageStep(bool step);
223 	void windowResized();
224 	void fitWindow(bool checked = true);
225 	void setTool(int tool);
226 	void syncWindowClick(const QPoint &p, bool activate);
227 	void syncCurrentPage(bool activate);
228 	void fixedScale(qreal scale = 1.0);
229 	void setImage(QPixmap img, int pageNr);
230     void delayedUpdate();
231 
232 signals:
233 	void changedPage(int, bool);
234 	void changedZoom(qreal);
235 	void changedScaleOption(autoScaleOption);
236 	void syncClick(int, const QPointF &, bool activate); //page position in page coordinates
237 
238 protected:
239 	virtual void paintEvent(QPaintEvent *event);
240 
241 	virtual void mousePressEvent(QMouseEvent *event);
242 	virtual void mouseReleaseEvent(QMouseEvent *event);
243 	virtual void mouseDoubleClickEvent(QMouseEvent *event);
244 	virtual void mouseMoveEvent(QMouseEvent *event);
245 
246 	virtual void keyPressEvent(QKeyEvent *event);
247 	virtual void keyReleaseEvent(QKeyEvent *event);
248 
249 	virtual void focusInEvent(QFocusEvent *event);
250 
251 	virtual void contextMenuEvent(QContextMenuEvent *event);
252 
253 	virtual bool event(QEvent *event);
254 
255 	bool gestureEvent(QGestureEvent *event);
256 	void pinchEvent(QPinchGesture *gesture);
257 	void tapEvent(QTapGesture *gesture);
258 
259 private:
260     friend class PDFMagnifier;
261 
262 	void init();
263 	void adjustSize();
264 	void updateCursor();
265 	void updateCursor(const QPoint &pos);
266 	QRect mapPopplerRectToWidget(QRectF rect, const QSizeF &pageSize) const;
267 	void useMagnifier(const QMouseEvent *inEvent);
268 	void goToDestination(const Poppler::LinkDestination &dest);
269 	void doLink(const QSharedPointer<Poppler::Link> link);
270 	void annotationClicked(QSharedPointer<Poppler::Annotation> annotation, int page);
271 	void doZoom(const QPoint &clickPos, int dir, qreal newScaleFactor = 1.0);
272     void doZoom(const QPointF &clickPos, int dir, qreal newScaleFactor = 1.0);
273 
274 	PDFScrollArea *getScrollArea() const;
275 
276 	QSharedPointer<Poppler::Document> document;
277 	QMutex textwidthCalculationMutex;
278 
279 	//QList<int> pages;
280 	QSharedPointer<Poppler::Link> clickedLink;
281 	QSharedPointer<Poppler::Annotation> clickedAnnotation;
282 
283 	int realPageIndex, oldRealPageIndex;
284 	QList<int> pages;
285 	qreal	scaleFactor;
286 	qreal	dpi;
287 	autoScaleOption scaleOption;
288 
289 	bool inhibitNextContextMenuEvent;
290     double summedWheelDegrees;
291 
292 	int docPages;
293 	qreal			saveScaleFactor;
294 	autoScaleOption	saveScaleOption;
295 
296 	QAction	*ctxZoomInAction;
297 	QAction	*ctxZoomOutAction;
298 	QShortcut *shortcutUp;
299 	QShortcut *shortcutLeft;
300 	QShortcut *shortcutDown;
301 	QShortcut *shortcutRight;
302 
303 	QPixmap image;
304 	QRect	imageRect;
305 	qreal	imageDpi;
306 	int	imagePage;
307 
308 	PDFMagnifier	*magnifier;
309 #ifdef PHONON
310 	PDFMovie	*movie;
311 #endif
312 	int		currentTool;	// the current tool selected in the toolbar
313 	int		usingTool;	// the tool actually being used in an ongoing mouse drag
314 	bool		singlePageStep;
315 
316 	int gridx, gridy;
317 
318 	bool forceUpdate;
319 
320 	QPainterPath	highlightPath;
321 	int highlightPage;
322 	QTimer highlightRemover;
323 
324 	static QCursor	*magnifierCursor;
325 	static QCursor	*zoomInCursor;
326 	static QCursor	*zoomOutCursor;
327 
328 	mutable QSizeF maxPageSize; //cache pageSize
329 	mutable QRectF horizontalTextRange;
330 
331 	QList<PDFPageHistoryItem> pageHistory;
332 	int pageHistoryIndex;
333 
334 	PDFDocument *pdfdocument;
335 };
336 
337 class PDFSearchResult
338 {
339 public:
340     explicit PDFSearchResult(const PDFDocument *pdfdoc = nullptr, int page = -1, QRectF rect = QRectF())
doc(pdfdoc)341 		: doc(pdfdoc), pageIdx(page), selRect(rect)
342 	{ }
343 
344 	const PDFDocument *doc;
345 	int pageIdx;
346 	QRectF selRect;
347 };
348 
349 
350 
351 struct PDFDocumentConfig;
352 class PDFDock;
353 class PDFSearchDock;
354 class PDFScrollArea;
355 class PDFDocument : public QMainWindow
356 {
357 	Q_OBJECT
358 
359 	Q_PROPERTY(QString fileName READ fileName)
360 
361 public:
362 	explicit PDFDocument(PDFDocumentConfig *const pdfConfig, bool embedded = false);
363 	virtual ~PDFDocument();
364 
365 	enum DisplayFlagsEnum {
366 		NoDisplayFlags = 0x0000,
367 		FocusEmbedded = 0x0001,
368 		FocusWindowed = 0x0010,
369 		Raise = 0x0100,
370 
371 		// window state independent combinations
372 		Focus = FocusEmbedded | FocusWindowed,
373 		// filter
374 		FilterEmbedded = 0xFF0F,
375 		FilterWindowed = 0xFFF0,
376 	};
377 	Q_DECLARE_FLAGS(DisplayFlags, DisplayFlagsEnum)
378 
379 	static PDFDocument *findDocument(const QString &fileName);
documentList()380 	static QList<PDFDocument *> documentList() { return docList; }
381 
fileName()382 	Q_INVOKABLE QString fileName() const { return curFile; }
getMasterFile()383 	Q_INVOKABLE QFileInfo getMasterFile() const { return masterFile; }
384 
385 	void saveGeometryToConfig();
386 
387 	Q_INVOKABLE void zoomToRight(QWidget *otherWindow);
388 	void showScale(qreal scale);
389 	Q_INVOKABLE void showPage(int page);
390 	Q_INVOKABLE void setResolution(int res);
391 	void resetMagnifier();
392 	Q_INVOKABLE void goToDestination(const QString &destName);
393 	Q_INVOKABLE void goToPage(const int page);
394 	Q_INVOKABLE void focus();
hasSyncData()395 	bool hasSyncData() { return scanner.isValid(); }
396 
popplerDoc()397 	const QSharedPointer<Poppler::Document> &popplerDoc() const { return document; }
398 
widget()399 	Q_INVOKABLE PDFWidget *widget() { return pdfWidget; }
widget()400 	const PDFWidget *widget() const { return pdfWidget; }
401 
402 	bool followCursor() const;
403 	bool ignoreSynchronization() const;
404 	PDFRenderManager *renderManager;
405 
406 	static bool isCompiling, isMaybeCompiling;
407 	bool embeddedMode;
408 	bool autoClose;
409 
410 	void setStateEnlarged(bool state);
411 
412 protected:
413 	virtual void changeEvent(QEvent *event);
414 	virtual void closeEvent(QCloseEvent *event);
415 	virtual void dragEnterEvent(QDragEnterEvent *event);
416 	virtual void dropEvent(QDropEvent *event);
417 	virtual void enterEvent(QEvent *event);
418 	virtual void leaveEvent(QEvent *event);
419 	virtual void mouseMoveEvent(QMouseEvent *event);
420 	void setToolbarsVisible(bool visible);
421 	void shortcutOnlyIfFocused(const QList<QAction *> &actions);
422 
423 public slots:
424 	void reloadSettings();
425 	void loadCurrentFile(bool fillCache = true);
426 	void fillRenderCache(int pg = -1);
427 	void sideBySide();
428 	void doFindDialog(const QString command = "");
429 	void doFindAgain();
430 	void goToSource();
431 	void toggleFullScreen(const bool fullscreen);
432     int syncFromSource(const QString &sourceFile, int lineNo, int column, PDFDocument::DisplayFlags displayFlags);  // lineNo, column are 0-based
433 	void syncFromView(const QString &pdfFile, const QFileInfo &masterFile, int page);
434     void loadFile(const QString &fileName, QFileInfo masterFile = QFileInfo(), PDFDocument::DisplayFlags displayFlags = DisplayFlagsEnum(Raise | Focus));
435 	void printPDF();
436 	void setAutoHideToolbars(bool enabled);
437 	void hideToolbars();
438 	void showToolbars();
439 	void showToolbarsDelayed();
440 	void setToolbarIconSize(int sz);
441 	void showMessage(const QString &text);
442 
443 	void splitMergeTool();
444 private slots:
445 	void fileOpen();
446 
447 	void enablePageActions(int, bool);
448 	void enableZoomActions(qreal);
449 	void adjustScaleActions(autoScaleOption);
450 	void syncClick(int page, const QPointF &pos, bool activate);
451 	void stopReloadTimer();
452 	void reloadWhenIdle();
453 	void idleReload();
454 
455 	void runExternalViewer();
456 	void runInternalViewer();
457 	void toggleEmbedded();
458 	void toggleAutoHideToolbars();
459 	void runQuickBuild();
460 
461 	void setGrid();
462 
463 public slots:
464 	bool closeElement();
465 private slots:
466 	void tileWindows();
467 	void stackWindows();
468 	void unminimize();
469     void updateDisplayState(PDFDocument::DisplayFlags displayFlags);
470 	void arrangeWindows(bool tile);
471 	void updateToolBarForOrientation(Qt::Orientation orientation);
472 
473 	void jumpToPage();
474 
475 	void search(bool backward, bool incremental);
476     void clearHightlight(bool visible);
477 public:
478 	void search(const QString &searchText, bool backward, bool incremental, bool caseSensitive, bool wholeWords, bool sync);
479 	void search();
480 	static QString debugSyncTeX(const QString &filename);
481 private slots:
482 	void gotoAnnotation(const PDFAnnotation *ann);
483 
484 	void zoomFromAction();
485 	void zoomSliderChange(int pos = 0);
486 	void enlarge();
487 	void shrink();
488 signals:
489 	void documentClosed();
490 	void documentLoaded();
491 	void syncSource(const QString &sourceFile, int line, bool activate, const QString &guessedWord); //view -> source
492 	void syncView(const QString &pdfFile, const QFileInfo &masterFile, int page); //view -> other view
493 	void focusEditor();
494 	void fileDropped(const QUrl &url);
495 
496 	void runCommand(const QString &command, const QFileInfo &masterFile, const QFileInfo &currentFile, int linenr);
497 
498 	void triggeredAbout();
499 	void triggeredManual();
500 	void triggeredQuit();
501 	void triggeredPlaceOnLeft();
502 	void triggeredConfigure();
503 	void triggeredEnlarge();
504 	void triggeredShrink();
505 
506 	void triggeredClone();
507 
508 private:
509 	void init(bool embedded = false);
510     void setupMenus(bool embedded);
511     void setupToolBar();
512 	void setCurrentFile(const QString &fileName);
513 	void loadSyncData();
514 
515 	qreal zoomSliderPosToScale(int pos);
516 	int scaleToZoomSliderPos(qreal scale);
517 
518 	QString curFile, curFileUnnormalized;
519 	qint64 curFileSize;
520 	QDateTime curFileLastModified;
521 	QFileInfo masterFile;
522 	QSynctex::TeXSyncPoint lastSyncPoint;
523 
524 	QSharedPointer<Poppler::Document> document;
525 
526 	PDFWidget	*pdfWidget;
527 	PDFScrollArea	*scrollArea;
528 	MessageFrame *messageFrame;
529 	TitledPanel *annotationPanel;
530 	PDFAnnotations *annotations;
531 	PDFAnnotationTableView *annotationTable;
532 
533 	QMenuBar *menubar;
534     QMenu *menuroot;
535 	QMenu *menuHelp;
536 	QMenu *menuFile;
537 	QMenu *menuEdit;
538 	QMenu *menuView;
539 	QMenu *menuGrid;
540 	QMenu *menuWindow;
541     QList<QMenu *>menus;
542 
543     QAction *actionAbout_TW;
544     QAction *actionFirst_Page;
545     QAction *actionPrevious_Page;
546     QAction *actionNext_Page;
547     QAction *actionLast_Page;
548     QAction *actionGo_to_Page;
549     QAction *actionZoom_In;
550     QAction *actionZoom_Out;
551     QAction *actionFit_to_Window;
552     QAction *actionActual_Size;
553     QAction *actionFit_to_Width;
554     QAction *actionNew;
555     QAction *actionOpen;
556     QAction *actionOpen_Recent;
557     QAction *actionClose;
558     QAction *actionUndo;
559     QAction *actionRedo;
560     QAction *actionCut;
561     QAction *actionCopy;
562     QAction *actionPaste;
563     QAction *actionClear;
564     QAction *actionTypeset;
565     QAction *actionExternalViewer;
566     QAction *actionPreferences;
567     QAction *actionStack;
568     QAction *actionTile;
569     QAction *actionGo_to_Source;
570     QAction *actionNew_from_Template;
571     QAction *actionFull_Screen;
572     QAction *actionMagnify;
573     QAction *actionScroll;
574     QAction *actionSelect_Text;
575     QAction *actionSelect_Image;
576     QAction *actionUserManual;
577     QAction *actionWriteToMailingList;
578     QAction *actionSide_by_Side;
579     QAction *actionPlace_on_Left;
580     QAction *actionPlace_on_Right;
581     QAction *actionQuit_TeXworks;
582     QAction *actionFind;
583     QAction *actionFind_Again;
584     QAction *actionUpdate_Scripts;
585     QAction *actionManage_Scripts;
586     QAction *actionShow_Scripts_Folder;
587     QAction *actionAbout_Scripts;
588     QAction *actionS;
589     QAction *actionCloseElement;
590     QAction *actionScrolling_follows_cursor;
591     QAction *actionCursor_follows_scrolling;
592     QAction *actionFind_2;
593     QAction *actionFind_again;
594     QAction *actionNew_Window;
595     QAction *actionGrid11;
596     QAction *actionGrid21;
597     QAction *actionGrid12;
598     QAction *actionGrid22;
599     QAction *actionGrid23;
600     QAction *actionGrid33;
601     QAction *actionCustom;
602     QAction *actionSinglePageStep;
603     QAction *actionSynchronize_multiple_views, *actionNoSynchronization;
604     QAction *actionPresentation;
605     QAction *actionContinuous;
606     QAction *action_Print;
607     QAction *actionFileOpen;
608     QAction *actionBack;
609     QAction *actionForward;
610     QAction *actionToggleEmbedded;
611     QAction *actionEnlargeViewer;
612     QAction *actionShrinkViewer;
613 	QAction *actionAutoHideToolbars;
614     QAction *actionInvertColors;
615     QAction *actionFocus_Editor;
616     QAction *actionFit_to_Text_Width;
617     QAction *actionGrayscale;
618     QAction *actionSplitMerge;
619 
620     QStatusBar *statusbar;
621     QToolBar *toolBar;
622     QTimer *toolBarTimer;
623 public:
624 	QMenu *menuShow;
625 private:
626 	QMenu *menuEdit_2;
627 
628 	QAction *actionPage_Up;
629 	QAction *actionPage_Down;
630 
631 	QButtonGroup	*toolButtonGroup;
632 	QToolButton *comboZoom;
633 	QLineEdit *leCurrentPage;
634 	QLabel *pageCountSeparator;
635 	QLabel *pageCountLabel;
636 	QIntValidator *leCurrentPageValidator;
637 
638 	QLabel *pageLabel;
639 	QToolButton *scaleButton;
640 	QSlider *zoomSlider;
641 	QList<QAction *> recentFileActions;
642 	QShortcut *exitFullscreen;
643 
644 	QFileSystemWatcher *watcher;
645 	QTimer *reloadTimer;
646 
647 	QSynctex::Scanner scanner;
648 
649 	static QList<PDFDocument *> docList;
650 
651 	PDFDock *dwClock, *dwOutline, *dwFonts, *dwInfo, *dwOverview;
652 	bool dwVisOutline, dwVisFonts, dwVisInfo, dwVisSearch, dwVisOverview;
653 	bool wasContinuous;
654 	PDFSearchDock *dwSearch;
655 
656 	PDFSearchResult lastSearchResult;
657 	// stores the page idx a search was started on
658 	// after wrapping the search will continue only up to this page
659 	int firstSearchPage;
660 
661 	bool wasMaximized;
662 	bool syncFromSourceBlocked;  //temporary disable sync from source
663 	bool syncToSourceBlocked;    //temporary disable sync to source (only for continuous scrolling)
664 };
665 Q_DECLARE_OPERATORS_FOR_FLAGS(PDFDocument::DisplayFlags)
666 
667 #endif
668 
669 #endif
670