1 /*
2 * Xournal++
3 *
4 * The document
5 *
6 * All methods are unlocked, you need to lock the document before you change something and unlock after.
7 *
8 * @author Xournal++ Team
9 * https://github.com/xournalpp/xournalpp
10 *
11 * @license GNU GPLv2 or later
12 */
13
14 #pragma once
15
16 #include <memory>
17 #include <string>
18 #include <unordered_map>
19 #include <vector>
20
21 #include "pdf/base/XojPdfBookmarkIterator.h"
22 #include "pdf/base/XojPdfDocument.h"
23 #include "pdf/base/XojPdfPage.h"
24
25 #include "DocumentHandler.h"
26 #include "LinkDestination.h"
27 #include "PageRef.h"
28 #include "XournalType.h"
29 #include "filesystem.h"
30
31 class Document {
32 public:
33 Document(DocumentHandler* handler);
34 virtual ~Document();
35
36 public:
37 enum DocumentType { XOPP, XOJ, PDF };
38
39 bool readPdf(const fs::path& filename, bool initPages, bool attachToDocument, gpointer data = nullptr,
40 gsize length = 0);
41
42 size_t getPageCount();
43 size_t getPdfPageCount();
44 XojPdfPageSPtr getPdfPage(size_t page);
45 XojPdfDocument& getPdfDocument();
46
47 void insertPage(const PageRef& p, size_t position);
48 void addPage(const PageRef& p);
49 template <class InputIter>
50 void addPages(InputIter first, InputIter last);
51 PageRef getPage(size_t page);
52 void deletePage(size_t pNr);
53
54 static void setPageSize(PageRef p, double width, double height);
55 static double getPageWidth(PageRef p);
56 static double getPageHeight(PageRef p);
57
58 size_t indexOf(const PageRef& page);
59
60 /**
61 * @return The last error message to show to the user
62 */
63 string getLastErrorMsg();
64
65 size_t findPdfPage(size_t pdfPage);
66
67 Document& operator=(const Document& doc);
68
69 void setFilepath(fs::path filepath);
70 fs::path getFilepath();
71 fs::path getPdfFilepath();
72 fs::path createSaveFolder(fs::path lastSavePath);
73 fs::path createSaveFilename(DocumentType type, const string& defaultSaveName);
74
75 fs::path getEvMetadataFilename();
76
77 GtkTreeModel* getContentsModel();
78
79 void setCreateBackupOnSave(bool backup);
80 bool shouldCreateBackupOnSave() const;
81
82 void clearDocument(bool destroy = false);
83
84 bool isAttachPdf() const;
85
86 cairo_surface_t* getPreview();
87 void setPreview(cairo_surface_t* preview);
88
89 void lock();
90 void unlock();
91 bool tryLock();
92
93 private:
94 void buildContentsModel();
95 void freeTreeContentModel();
96 static bool freeTreeContentEntry(GtkTreeModel* treeModel, GtkTreePath* path, GtkTreeIter* iter, Document* doc);
97
98 void buildTreeContentsModel(GtkTreeIter* parent, XojPdfBookmarkIterator* iter);
99 void updateIndexPageNumbers();
100 static bool fillPageLabels(GtkTreeModel* treeModel, GtkTreePath* path, GtkTreeIter* iter, Document* doc);
101
102 private:
103 DocumentHandler* handler = nullptr;
104
105 XojPdfDocument pdfDocument;
106
107 fs::path filepath;
108 fs::path pdfFilepath;
109 bool attachPdf = false;
110
111 /**
112 * Password: not handled yet
113 */
114 string password;
115
116 string lastError;
117
118 /**
119 * The pages in the document
120 */
121 vector<PageRef> pages;
122
123 /**
124 * Index from pdf page number to document page number
125 */
126 using PageIndex = std::unordered_map<size_t, size_t>;
127
128 /**
129 * The cached page index
130 */
131 std::unique_ptr<PageIndex> pageIndex;
132
133 /**
134 * Creates an index from pdf page number to document page number
135 *
136 * Clears the index first in case it is already exists.
137 */
138 void indexPdfPages();
139
140 /**
141 * The bookmark contents model
142 */
143 GtkTreeModel* contentsModel = nullptr;
144
145 /**
146 * create a backup before save, because the original file was an older fileversion
147 */
148 bool createBackupOnSave = false;
149
150 /**
151 * The preview for the file
152 */
153 cairo_surface_t* preview = nullptr;
154
155 /**
156 * The lock of the document
157 */
158 GMutex documentLock{};
159 };
160
161 template <class InputIter>
addPages(InputIter first,InputIter last)162 void Document::addPages(InputIter first, InputIter last) {
163 this->pages.insert(this->pages.end(), first, last);
164 this->pageIndex.reset();
165 updateIndexPageNumbers();
166 }
167