1 /*
2     dspdfviewer - Dual Screen PDF Viewer for LaTeX-Beamer
3     Copyright (C) 2012  Danny Edel <mail@danny-edel.de>
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 along
16     with this program; if not, write to the Free Software Foundation, Inc.,
17     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19 
20 
21 #ifndef PDFRENDERFACTORY_H
22 #define PDFRENDERFACTORY_H
23 
24 #include <QObject>
25 #include <QMutex>
26 #include <QCache>
27 #include <QThread>
28 #include <QFileSystemWatcher>
29 #include <QTimer>
30 #include <qimage.h>
31 #include "poppler-qt.h"
32 #include "renderedpage.h"
33 #include "runtimeconfiguration.h"
34 #include "pdfcacheoption.h"
35 #include "pdfdocumentreference.h"
36 
37 
38 /** Factory for rendered pages
39  *
40  * This class is responsible for rendering the PDF to images.
41  *
42  * You create a factory using a filename (if the file cannot be opened this will throw),
43  * then you can simply request renderings by supplying the desired size and page part
44  * to requestPageRendering.
45  *
46  * The class uses the global instance of QThreadPool and renders in paralell, meaning it
47  * can take advantage of SMP or Multi-Core Systems.
48  *
49  * NOTE for updating the external file:
50  * If you plan on rewriting the displayed file while this application is running,
51  * you can cache the entire file to memory. This can be done via constructor parameter.
52  *
53  * That way, if you create an invalid PDF file (for example you make an error in your latex
54  * document), it still has a copy of the old file present.
55  * The tradeoff is that this will cost you additional memory for *the entire PDF file*, which
56  * can be a lot if you have an image-heavy PDF file.
57  *
58  * The class will notify you via signals when it detects a file change. Then it will try to re-read
59  * the file, and it will notify you if that has succeeded or failed.
60  *
61  * If the re-reading failed, you can still get pages from cache, and you can keep rendering new ones
62  * if you have used the memory cache. However, if you try to render new pages, you will probably
63  * experience strange behaviour or the program will crash.
64  *
65  * If the re-reading went well, the cache will be cleared and new page renders will use the new pdf
66  * file.
67  *
68  */
69 class PdfRenderFactory : public QObject
70 {
71   Q_OBJECT
72 
73 private:
74   PDFDocumentReference documentReference;
75   QFileSystemWatcher fileWatcher;
76   QTimer fileWatcherRewatchTimer;
77 
78   QSet< RenderingIdentifier > currentlyRenderingPages;
79   QCache< RenderingIdentifier, RenderedPage> renderedPages;
80 
81   mutable QMutex mutex;
82 
83   /** This is a little helper for the cache-clear-function to detect
84    * renderings that have been started before, but finished after
85    * a cache clearing.
86    */
87   quint64 currentVersion;
88 
89   int numberOfPages_;
90 
91 private:
92   void clearAllCaches();
93 
94 public:
95   PdfRenderFactory( const RuntimeConfiguration& );
96   ~PdfRenderFactory();
97 
98   /** Request a page rendering. Defaults to low priority (i.e. background rendering), please set High priority manually
99    * on the current page.
100    */
101   void requestPageRendering( const RenderingIdentifier& originalIdentifier, QThread::Priority priority = QThread::LowPriority);
102 
103   int numberOfPages() const;
104 
105 private slots:
106   void fileOnDiskChanged(const QString& filename);
107   void pageThreadFinishedRendering( QSharedPointer<RenderedPage> renderedPage );
108 
109 signals:
110   void pageRendered( QSharedPointer<RenderedPage> renderedPage);
111 
112   void pdfFileChanged();
113   void pdfFileRereadSuccesfully();
114   void pdfFileRereadFailed();
115 
116   public slots:
117   void rewatchFile();
118 };
119 
120 #endif // PDFRENDERFACTORY_H
121