1 /*
2 SPDX-FileCopyrightText: 2004-2005 Enrico Ros <eros.kde@email.it>
3 SPDX-FileCopyrightText: 2004-2007 Albert Astals Cid <aacid@kde.org>
4
5 SPDX-License-Identifier: GPL-2.0-or-later
6 */
7
8 #ifndef _OKULAR_DOCUMENT_P_H_
9 #define _OKULAR_DOCUMENT_P_H_
10
11 #include "document.h"
12 #include "script/event_p.h"
13
14 #include "synctex/synctex_parser.h"
15 #include <memory>
16
17 // qt/kde/system includes
18 #include <KConfigDialog>
19 #include <KPluginMetaData>
20 #include <QHash>
21 #include <QLinkedList>
22 #include <QMap>
23 #include <QMutex>
24 #include <QPointer>
25 #include <QUrl>
26
27 // local includes
28 #include "fontinfo.h"
29 #include "generator.h"
30
31 class QUndoStack;
32 class QEventLoop;
33 class QFile;
34 class QTimer;
35 class QTemporaryFile;
36 class KPluginMetaData;
37
38 struct AllocatedPixmap;
39 struct ArchiveData;
40 struct RunningSearch;
41
42 namespace Okular
43 {
44 class ScriptAction;
45 class ConfigInterface;
46 class PageController;
47 class SaveInterface;
48 class Scripter;
49 class View;
50 }
51
52 struct GeneratorInfo {
GeneratorInfoGeneratorInfo53 explicit GeneratorInfo(Okular::Generator *g, const KPluginMetaData &data)
54 : generator(g)
55 , metadata(data)
56 , config(nullptr)
57 , save(nullptr)
58 , configChecked(false)
59 , saveChecked(false)
60 {
61 }
62
63 Okular::Generator *generator;
64 KPluginMetaData metadata;
65 Okular::ConfigInterface *config;
66 Okular::SaveInterface *save;
67 bool configChecked : 1;
68 bool saveChecked : 1;
69 };
70
71 namespace Okular
72 {
73 class OKULARCORE_EXPORT BackendConfigDialog : public KConfigDialog
74 {
75 Q_OBJECT
76 public:
BackendConfigDialog(QWidget * parent,const QString & name,KCoreConfigSkeleton * config)77 BackendConfigDialog(QWidget *parent, const QString &name, KCoreConfigSkeleton *config)
78 : KConfigDialog(parent, name, config)
79 {
80 }
81
thePageWidget()82 KPageWidget *thePageWidget()
83 {
84 return pageWidget();
85 }
86 };
87
88 class FontExtractionThread;
89
90 struct DoContinueDirectionMatchSearchStruct {
91 QSet<int> *pagesToNotify;
92 RegularAreaRect *match;
93 int currentPage;
94 int searchID;
95 };
96
97 enum LoadDocumentInfoFlag {
98 LoadNone = 0,
99 LoadPageInfo = 1, // Load annotations and forms
100 LoadGeneralInfo = 2, // History, rotation, ...
101 LoadAllInfo = 0xff
102 };
Q_DECLARE_FLAGS(LoadDocumentInfoFlags,LoadDocumentInfoFlag)103 Q_DECLARE_FLAGS(LoadDocumentInfoFlags, LoadDocumentInfoFlag)
104
105 class DocumentPrivate
106 {
107 public:
108 explicit DocumentPrivate(Document *parent)
109 : m_parent(parent)
110 , m_tempFile(nullptr)
111 , m_docSize(-1)
112 , m_allocatedPixmapsTotalMemory(0)
113 , m_maxAllocatedTextPages(0)
114 , m_warnedOutOfMemory(false)
115 , m_rotation(Rotation0)
116 , m_exportCached(false)
117 , m_bookmarkManager(nullptr)
118 , m_memCheckTimer(nullptr)
119 , m_saveBookmarksTimer(nullptr)
120 , m_generator(nullptr)
121 , m_walletGenerator(nullptr)
122 , m_generatorsLoaded(false)
123 , m_pageController(nullptr)
124 , m_closingLoop(nullptr)
125 , m_scripter(nullptr)
126 , m_archiveData(nullptr)
127 , m_fontsCached(false)
128 , m_annotationEditingEnabled(true)
129 , m_annotationBeingModified(false)
130 , m_docdataMigrationNeeded(false)
131 , m_synctex_scanner(nullptr)
132 {
133 calculateMaxTextPages();
134 }
135
136 // private methods
137 bool updateMetadataXmlNameAndDocSize();
138 QString pagesSizeString() const;
139 QString namePaperSize(double inchesWidth, double inchesHeight) const;
140 QString localizedSize(const QSizeF size) const;
141 qulonglong calculateMemoryToFree();
142 void cleanupPixmapMemory();
143 void cleanupPixmapMemory(qulonglong memoryToFree);
144 AllocatedPixmap *searchLowestPriorityPixmap(bool unloadableOnly = false, bool thenRemoveIt = false, DocumentObserver *observer = nullptr /* any */);
145 void calculateMaxTextPages();
146 qulonglong getTotalMemory();
147 qulonglong getFreeMemory(qulonglong *freeSwap = nullptr);
148 bool loadDocumentInfo(LoadDocumentInfoFlags loadWhat);
149 bool loadDocumentInfo(QFile &infoFile, LoadDocumentInfoFlags loadWhat);
150 void loadViewsInfo(View *view, const QDomElement &e);
151 void saveViewsInfo(View *view, QDomElement &e) const;
152 QUrl giveAbsoluteUrl(const QString &fileName) const;
153 bool openRelativeFile(const QString &fileName);
154 Generator *loadGeneratorLibrary(const KPluginMetaData &service);
155 void loadAllGeneratorLibraries();
156 void loadServiceList(const QVector<KPluginMetaData> &offers);
157 void unloadGenerator(const GeneratorInfo &info);
158 void cacheExportFormats();
159 void setRotationInternal(int r, bool notify);
160 ConfigInterface *generatorConfig(GeneratorInfo &info);
161 SaveInterface *generatorSave(GeneratorInfo &info);
162 Document::OpenResult openDocumentInternal(const KPluginMetaData &offer, bool isstdin, const QString &docFile, const QByteArray &filedata, const QString &password);
163 static ArchiveData *unpackDocumentArchive(const QString &archivePath);
164 bool savePageDocumentInfo(QTemporaryFile *infoFile, int what) const;
165 DocumentViewport nextDocumentViewport() const;
166 void notifyAnnotationChanges(int page);
167 void notifyFormChanges(int page);
168 bool canAddAnnotationsNatively() const;
169 bool canModifyExternalAnnotations() const;
170 bool canRemoveExternalAnnotations() const;
171 OKULARCORE_EXPORT static QString docDataFileName(const QUrl &url, qint64 document_size);
172 bool cancelRenderingBecauseOf(PixmapRequest *executingRequest, PixmapRequest *newRequest);
173
174 // Methods that implement functionality needed by undo commands
175 void performAddPageAnnotation(int page, Annotation *annotation);
176 void performRemovePageAnnotation(int page, Annotation *annotation);
177 void performModifyPageAnnotation(int page, Annotation *annotation, bool appearanceChanged);
178 void performSetAnnotationContents(const QString &newContents, Annotation *annot, int pageNumber);
179
180 void recalculateForms();
181
182 // private slots
183 void saveDocumentInfo() const;
184 void slotTimedMemoryCheck();
185 void sendGeneratorPixmapRequest();
186 void rotationFinished(int page, Okular::Page *okularPage);
187 void slotFontReadingProgress(int page);
188 void fontReadingGotFont(const Okular::FontInfo &font);
189 void slotGeneratorConfigChanged();
190 void refreshPixmaps(int);
191 void _o_configChanged();
192 void doContinueDirectionMatchSearch(void *doContinueDirectionMatchSearchStruct);
193 void doContinueAllDocumentSearch(void *pagesToNotifySet, void *pageMatchesMap, int currentPage, int searchID);
194 void doContinueGooglesDocumentSearch(void *pagesToNotifySet, void *pageMatchesMap, int currentPage, int searchID, const QStringList &words);
195
196 void doProcessSearchMatch(RegularAreaRect *match, RunningSearch *search, QSet<int> *pagesToNotify, int currentPage, int searchID, bool moveViewport, const QColor &color);
197
198 /**
199 * Executes a JavaScript script from the setInterval function.
200 *
201 * @since 1.9
202 */
203 void executeScript(const QString &function);
204
205 // generators stuff
206 /**
207 * This method is used by the generators to signal the finish of
208 * the pixmap generation @p request.
209 */
210 void requestDone(PixmapRequest *request);
211 void textGenerationDone(Page *page);
212 /**
213 * Sets the bounding box of the given @p page (in terms of upright orientation, i.e., Rotation0).
214 */
215 void setPageBoundingBox(int page, const NormalizedRect &boundingBox);
216
217 /**
218 * Request a particular metadata of the Document itself (ie, not something
219 * depending on the document type/backend).
220 */
221 QVariant documentMetaData(const Generator::DocumentMetaDataKey key, const QVariant &option) const;
222
223 /**
224 * Return whether the normalized rectangle @p rectOfInterest on page number @p rectPage
225 * is fully visible.
226 */
227 bool isNormalizedRectangleFullyVisible(const Okular::NormalizedRect &rectOfInterest, int rectPage);
228
229 // For sync files
230 void loadSyncFile(const QString &filePath);
231
232 void clearAndWaitForRequests();
233
234 /*
235 * Executes a ScriptAction with the event passed as parameter.
236 */
237 void executeScriptEvent(const std::shared_ptr<Event> &event, const Okular::ScriptAction *linkscript);
238
239 /*
240 * Find the corresponding page number for the form field passed as parameter.
241 */
242 int findFieldPageNumber(Okular::FormField *field);
243
244 // member variables
245 Document *m_parent;
246 QPointer<QWidget> m_widget;
247
248 // find descriptors, mapped by ID (we handle multiple searches)
249 QMap<int, RunningSearch *> m_searches;
250 bool m_searchCancelled;
251
252 // needed because for remote documents docFileName is a local file and
253 // we want the remote url when the document refers to relativeNames
254 QUrl m_url;
255
256 // cached stuff
257 QString m_docFileName;
258 QString m_xmlFileName;
259 QTemporaryFile *m_tempFile;
260 qint64 m_docSize;
261
262 // viewport stuff
263 QLinkedList<DocumentViewport> m_viewportHistory;
264 QLinkedList<DocumentViewport>::iterator m_viewportIterator;
265 DocumentViewport m_nextDocumentViewport; // see Link::Goto for an explanation
266 QString m_nextDocumentDestination;
267
268 // observers / requests / allocator stuff
269 QSet<DocumentObserver *> m_observers;
270 QLinkedList<PixmapRequest *> m_pixmapRequestsStack;
271 QLinkedList<PixmapRequest *> m_executingPixmapRequests;
272 QMutex m_pixmapRequestsMutex;
273 QLinkedList<AllocatedPixmap *> m_allocatedPixmaps;
274 qulonglong m_allocatedPixmapsTotalMemory;
275 QList<int> m_allocatedTextPagesFifo;
276 int m_maxAllocatedTextPages;
277 bool m_warnedOutOfMemory;
278
279 // the rotation applied to the document
280 Rotation m_rotation;
281
282 // the current size of the pages (if available), and the cache of the
283 // available page sizes
284 PageSize m_pageSize;
285 PageSize::List m_pageSizes;
286
287 // cache of the export formats
288 bool m_exportCached;
289 ExportFormat::List m_exportFormats;
290 ExportFormat m_exportToText;
291
292 // our bookmark manager
293 BookmarkManager *m_bookmarkManager;
294
295 // timers (memory checking / info saver)
296 QTimer *m_memCheckTimer;
297 QTimer *m_saveBookmarksTimer;
298
299 QHash<QString, GeneratorInfo> m_loadedGenerators;
300 Generator *m_generator;
301 QString m_generatorName;
302 Generator *m_walletGenerator;
303 bool m_generatorsLoaded;
304 QVector<Page *> m_pagesVector;
305 QVector<VisiblePageRect *> m_pageRects;
306
307 // cache of the mimetype we support
308 QStringList m_supportedMimeTypes;
309
310 PageController *m_pageController;
311 QEventLoop *m_closingLoop;
312
313 Scripter *m_scripter;
314
315 ArchiveData *m_archiveData;
316 QString m_archivedFileName;
317
318 QPointer<FontExtractionThread> m_fontThread;
319 bool m_fontsCached;
320 QSet<DocumentInfo::Key> m_documentInfoAskedKeys;
321 DocumentInfo m_documentInfo;
322 FontInfo::List m_fontsCache;
323
324 QSet<View *> m_views;
325
326 bool m_annotationEditingEnabled;
327 bool m_annotationBeingModified; // is an annotation currently being moved or resized?
328 bool m_metadataLoadingCompleted;
329
330 QUndoStack *m_undoStack;
331 QDomNode m_prevPropsOfAnnotBeingModified;
332
333 // Since 0.21, we no longer support saving annotations and form data in
334 // the docdata/ directory and we ask the user to migrate them to an
335 // external file as soon as possible, otherwise the document will be
336 // shown in read-only mode. This flag is set if the docdata/ XML file
337 // for the current document contains any annotation or form.
338 bool m_docdataMigrationNeeded;
339
340 synctex_scanner_p m_synctex_scanner;
341
342 QString m_openError;
343
344 // generator selection
345 static QVector<KPluginMetaData> availableGenerators();
346 static QVector<KPluginMetaData> configurableGenerators();
347 static KPluginMetaData generatorForMimeType(const QMimeType &type, QWidget *widget, const QVector<KPluginMetaData> &triedOffers = QVector<KPluginMetaData>());
348 };
349
350 class DocumentInfoPrivate
351 {
352 public:
353 QMap<QString, QString> values; // key -> value
354 QMap<QString, QString> titles; // key -> title For the custom keys
355 };
356
357 }
358
359 #endif
360
361 /* kate: replace-tabs on; indent-width 4; */
362