Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qpdfbookmarkmodel.cpp
Go to the documentation of this file.
1// Copyright (C) 2020 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qpdfbookmarkmodel.h"
5
6#include "qpdfdocument.h"
7#include "qpdfdocument_p.h"
8
9#include "third_party/pdfium/public/fpdf_doc.h"
10#include "third_party/pdfium/public/fpdfview.h"
11
12#include <QLoggingCategory>
13#include <QMetaEnum>
14#include <QPointer>
15#include <QScopedPointer>
16#include <private/qabstractitemmodel_p.h>
17
19
20Q_LOGGING_CATEGORY(qLcBM, "qt.pdf.bookmarks")
21
23{
24public:
25 explicit BookmarkNode(BookmarkNode *parentNode = nullptr)
26 : m_parentNode(parentNode)
27 {
28 }
29
31 {
32 clear();
33 }
34
35 void clear()
36 {
37 qDeleteAll(m_childNodes);
38 m_childNodes.clear();
39 }
40
42 {
43 m_childNodes.append(child);
44 }
45
47 {
48 return m_childNodes.at(row);
49 }
50
51 int childCount() const
52 {
53 return m_childNodes.size();
54 }
55
56 int row() const
57 {
58 if (m_parentNode)
59 return m_parentNode->m_childNodes.indexOf(const_cast<BookmarkNode*>(this));
60
61 return 0;
62 }
63
65 {
66 return m_parentNode;
67 }
68
69 QString title() const
70 {
71 return m_title;
72 }
73
74 void setTitle(const QString &title)
75 {
76 m_title = title;
77 }
78
79 int level() const
80 {
81 return m_level;
82 }
83
84 void setLevel(int level)
85 {
86 m_level = level;
87 }
88
89 int pageNumber() const
90 {
91 return m_pageNumber;
92 }
93
94 void setPageNumber(int pageNumber)
95 {
96 m_pageNumber = pageNumber;
97 }
98
100 {
101 return m_location;
102 }
103
105 {
106 m_location = QPointF(x, y);
107 }
108
109 qreal zoom() const
110 {
111 return m_zoom;
112 }
113
114 void setZoom(qreal zoom)
115 {
116 m_zoom = zoom;
117 }
118
119private:
120 QList<BookmarkNode*> m_childNodes;
121 BookmarkNode *m_parentNode;
122
123 QString m_title;
124 int m_level = 0;
125 int m_pageNumber = 0;
126 QPointF m_location;
127 qreal m_zoom = 0;
128};
129
130
132{
138
139 void rebuild()
140 {
141 const bool documentAvailable = (m_document && m_document->status() == QPdfDocument::Status::Ready);
142
143 if (documentAvailable) {
144 q->beginResetModel();
145 m_rootNode->clear();
147 appendChildNode(m_rootNode.data(), nullptr, 0, m_document->d->doc);
148 lock.unlock();
149 q->endResetModel();
150 } else {
151 if (m_rootNode->childCount() == 0) {
152 return;
153 } else {
154 q->beginResetModel();
155 m_rootNode->clear();
156 q->endResetModel();
157 }
158 }
159 }
160
161 void appendChildNode(BookmarkNode *parentBookmarkNode, FPDF_BOOKMARK parentBookmark, int level, FPDF_DOCUMENT document)
162 {
163 FPDF_BOOKMARK bookmark = FPDFBookmark_GetFirstChild(document, parentBookmark);
164
165 while (bookmark) {
166 BookmarkNode *childBookmarkNode = nullptr;
167
168 childBookmarkNode = new BookmarkNode(parentBookmarkNode);
169 parentBookmarkNode->appendChild(childBookmarkNode);
170 Q_ASSERT(childBookmarkNode);
171
172 const int titleLength = int(FPDFBookmark_GetTitle(bookmark, nullptr, 0));
173
174 QList<char16_t> titleBuffer(titleLength);
175 FPDFBookmark_GetTitle(bookmark, titleBuffer.data(), quint32(titleBuffer.size()));
176
177 const FPDF_DEST dest = FPDFBookmark_GetDest(document, bookmark);
178 const int pageNumber = FPDFDest_GetDestPageIndex(document, dest);
179 const qreal pageHeight = m_document->pagePointSize(pageNumber).height();
180 FPDF_BOOL hasX, hasY, hasZoom;
181 FS_FLOAT x, y, zoom;
182 bool ok = FPDFDest_GetLocationInPage(dest, &hasX, &hasY, &hasZoom, &x, &y, &zoom);
183 if (ok) {
184 if (hasX && hasY)
185 childBookmarkNode->setLocation(x, pageHeight - y);
186 if (hasZoom)
187 childBookmarkNode->setZoom(zoom);
188 } else {
189 qCWarning(qLcBM) << "bookmark with invalid location and/or zoom" << x << y << zoom;
190 }
191
192 childBookmarkNode->setTitle(QString::fromUtf16(titleBuffer.data()));
193 childBookmarkNode->setLevel(level);
194 childBookmarkNode->setPageNumber(pageNumber);
195
196 // recurse down
197 appendChildNode(childBookmarkNode, bookmark, level + 1, document);
198
199 bookmark = FPDFBookmark_GetNextSibling(document, bookmark);
200 }
201 }
202
204 {
205 rebuild();
206 }
207
209
210 QScopedPointer<BookmarkNode> m_rootNode;
211 QPointer<QPdfDocument> m_document;
212 QHash<int, QByteArray> m_roleNames;
213};
214
215
245{
246 d->q = this;
247 d->m_roleNames = QAbstractItemModel::roleNames();
248 QMetaEnum rolesMetaEnum = metaObject()->enumerator(metaObject()->indexOfEnumerator("Role"));
249 for (int r = Qt::UserRole; r < int(Role::NRoles); ++r)
250 d->m_roleNames.insert(r, QByteArray(rolesMetaEnum.valueToKey(r)).toLower());
251}
252
257
259{
260 return d->m_document;
261}
262
268{
269 if (d->m_document == document)
270 return;
271
272 if (d->m_document)
273 disconnect(d->m_document, SIGNAL(statusChanged(QPdfDocument::Status)), this, SLOT(_q_documentStatusChanged()));
274
275 d->m_document = document;
276 emit documentChanged(d->m_document);
277
278 if (d->m_document)
279 connect(d->m_document, SIGNAL(statusChanged(QPdfDocument::Status)), this, SLOT(_q_documentStatusChanged()));
280
281 d->rebuild();
282}
283
288{
290 return 1;
291}
292
296QHash<int, QByteArray> QPdfBookmarkModel::roleNames() const
297{
298 return d->m_roleNames;
299}
300
305{
306 if (!index.isValid())
307 return QVariant();
308
309 const BookmarkNode *node = static_cast<BookmarkNode*>(index.internalPointer());
310 switch (Role(role)) {
311 case Role::Title:
312 return node->title();
313 case Role::Level:
314 return node->level();
315 case Role::Page:
316 return node->pageNumber();
317 case Role::Location:
318 return node->location();
319 case Role::Zoom:
320 return node->zoom();
321 case Role::NRoles:
322 break;
323 }
324 if (role == Qt::DisplayRole)
325 return node->title();
326 return QVariant();
327}
328
333{
334 if (!hasIndex(row, column, parent))
335 return QModelIndex();
336
337 BookmarkNode *parentNode;
338
339 if (!parent.isValid())
340 parentNode = d->m_rootNode.data();
341 else
342 parentNode = static_cast<BookmarkNode*>(parent.internalPointer());
343
344 BookmarkNode *childNode = parentNode->child(row);
345 if (childNode)
346 return createIndex(row, column, childNode);
347 else
348 return QModelIndex();
349}
350
355{
356 if (!index.isValid())
357 return QModelIndex();
358
359 const BookmarkNode *childNode = static_cast<BookmarkNode*>(index.internalPointer());
360 BookmarkNode *parentNode = childNode->parentNode();
361
362 if (parentNode == d->m_rootNode.data())
363 return QModelIndex();
364
365 return createIndex(parentNode->row(), 0, parentNode);
366}
367
372{
373 if (parent.column() > 0)
374 return 0;
375
376 BookmarkNode *parentNode = nullptr;
377
378 if (!parent.isValid())
379 parentNode = d->m_rootNode.data();
380 else
381 parentNode = static_cast<BookmarkNode*>(parent.internalPointer());
382
383 return parentNode->childCount();
384}
385
387
388#include "moc_qpdfbookmarkmodel.cpp"
QString title() const
void setLevel(int level)
int childCount() const
BookmarkNode * child(int row) const
qreal zoom() const
void setZoom(qreal zoom)
void setTitle(const QString &title)
BookmarkNode(BookmarkNode *parentNode=nullptr)
void setLocation(qreal x, qreal y)
void setPageNumber(int pageNumber)
int pageNumber() const
void appendChild(BookmarkNode *child)
BookmarkNode * parentNode() const
QPointF location() const
Q_INVOKABLE int const QModelIndex & parent
Returns the parent of the model item with the given index.
Q_INVOKABLE bool hasIndex(int row, int column, const QModelIndex &parent=QModelIndex()) const
Returns {true} if the model returns a valid QModelIndex for row and column with parent,...
virtual QHash< int, QByteArray > roleNames() const
QModelIndex createIndex(int row, int column, const void *data=nullptr) const
Creates a model index for the given row and column with the internal pointer ptr.
\inmodule QtCore
Definition qbytearray.h:57
QByteArray toLower() const &
Definition qbytearray.h:254
\inmodule QtCore
\inmodule QtCore
constexpr int column() const noexcept
Returns the column this model index refers to.
void * internalPointer() const noexcept
Returns a {void} {*} pointer used by the model to associate the index with the internal data structur...
constexpr bool isValid() const noexcept
Returns {true} if this model index is valid; otherwise returns {false}.
\inmodule QtCore
Definition qobject.h:103
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
Definition qobject.cpp:2960
The QPdfBookmarkModel class holds a tree of of links (anchors) within a PDF document,...
void documentChanged(QPdfDocument *document)
~QPdfBookmarkModel() override
Destroys the model.
int rowCount(const QModelIndex &parent=QModelIndex()) const override
\reimp
void setDocument(QPdfDocument *document)
Role
\value Title The name of the bookmark for display.
QVariant data(const QModelIndex &index, int role) const override
\reimp
int columnCount(const QModelIndex &parent=QModelIndex()) const override
\reimp
QModelIndex index(int row, int column, const QModelIndex &parent=QModelIndex()) const override
\reimp
QHash< int, QByteArray > roleNames() const override
\reimp
QPdfDocument * document
the PDF document in which bookmarks are to be found.
The QPdfDocument class loads a PDF document and renders pages from it.
Status status
This property holds the current status of the document.
Status
This enum describes the current status of the document.
Q_INVOKABLE QSizeF pagePointSize(int page) const
Returns the size of page page in points (1/72 of an inch).
\inmodule QtCore\reentrant
Definition qpoint.h:217
T * data() const noexcept
Returns the value of the pointer referenced by this object.
constexpr qreal height() const noexcept
Returns the height.
Definition qsize.h:335
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
static QString fromUtf16(const char16_t *, qsizetype size=-1)
Definition qstring.cpp:6045
\inmodule QtCore
Definition qvariant.h:65
void statusChanged(QQmlComponent::Status status)
[1]
Definition qlogging.cpp:11
b clear()
qDeleteAll(list.begin(), list.end())
Combined button and popup list for selecting options.
@ UserRole
@ DisplayRole
#define Q_LOGGING_CATEGORY(name,...)
#define qCWarning(category,...)
#define SLOT(a)
Definition qobjectdefs.h:52
#define SIGNAL(a)
Definition qobjectdefs.h:53
GLint GLint GLint GLint GLint x
[0]
GLenum GLuint GLint level
GLuint index
[2]
GLboolean r
[2]
GLint y
GLenum GLenum GLsizei void GLsizei void * column
GLdouble GLdouble GLdouble GLdouble q
Definition qopenglext.h:259
GLenum GLenum GLsizei void * row
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
#define emit
#define Q_UNUSED(x)
unsigned int quint32
Definition qtypes.h:50
double qreal
Definition qtypes.h:187
obj metaObject() -> className()
QObject::connect nullptr
QString title
[35]
myObject disconnect()
[26]
QReadWriteLock lock
[0]
QLayoutItem * child
[0]
void appendChildNode(BookmarkNode *parentBookmarkNode, FPDF_BOOKMARK parentBookmark, int level, FPDF_DOCUMENT document)
QScopedPointer< BookmarkNode > m_rootNode
QHash< int, QByteArray > m_roleNames
QPointer< QPdfDocument > m_document