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