summaryrefslogtreecommitdiffstats
path: root/src/pdf/qpdflinkmodel.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/pdf/qpdflinkmodel.cpp')
-rw-r--r--src/pdf/qpdflinkmodel.cpp72
1 files changed, 54 insertions, 18 deletions
diff --git a/src/pdf/qpdflinkmodel.cpp b/src/pdf/qpdflinkmodel.cpp
index 4fc9d8aea..0a8b1e812 100644
--- a/src/pdf/qpdflinkmodel.cpp
+++ b/src/pdf/qpdflinkmodel.cpp
@@ -2,8 +2,8 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qpdflink_p.h"
+#include "qpdflinkmodel.h"
#include "qpdflinkmodel_p.h"
-#include "qpdflinkmodel_p_p.h"
#include "qpdfdocument_p.h"
#include "third_party/pdfium/public/fpdf_doc.h"
@@ -18,7 +18,7 @@ Q_LOGGING_CATEGORY(qLcLink, "qt.pdf.links")
/*!
\class QPdfLinkModel
- \since 5.15
+ \since 6.6
\inmodule QtPdf
\inherits QAbstractListModel
@@ -37,18 +37,20 @@ Q_LOGGING_CATEGORY(qLcLink, "qt.pdf.links")
\value Page If the link is an internal link, the page number to which the link should jump; otherwise \c {-1}.
\value Location If the link is an internal link, the location on the page to which the link should jump.
\value Zoom If the link is an internal link, the suggested zoom level on the destination page.
- \omitvalue _Count
+ \omitvalue NRoles
*/
/*!
Constructs a new link model with parent object \a parent.
*/
QPdfLinkModel::QPdfLinkModel(QObject *parent)
- : QAbstractListModel(*(new QPdfLinkModelPrivate()), parent)
+ : QAbstractListModel(parent),
+ d_ptr{std::make_unique<QPdfLinkModelPrivate>(this)}
{
+ Q_D(QPdfLinkModel);
QMetaEnum rolesMetaEnum = metaObject()->enumerator(metaObject()->indexOfEnumerator("Role"));
- for (int r = Qt::UserRole; r < int(Role::_Count); ++r)
- m_roleNames.insert(r, QByteArray(rolesMetaEnum.valueToKey(r)).toLower());
+ for (int r = Qt::UserRole; r < int(Role::NRoles); ++r)
+ d->roleNames.insert(r, QByteArray(rolesMetaEnum.valueToKey(r)).toLower());
}
/*!
@@ -58,7 +60,8 @@ QPdfLinkModel::~QPdfLinkModel() {}
QHash<int, QByteArray> QPdfLinkModel::roleNames() const
{
- return m_roleNames;
+ Q_D(const QPdfLinkModel);
+ return d->roleNames;
}
/*!
@@ -68,7 +71,7 @@ int QPdfLinkModel::rowCount(const QModelIndex &parent) const
{
Q_D(const QPdfLinkModel);
Q_UNUSED(parent);
- return d->links.count();
+ return d->links.size();
}
/*!
@@ -91,7 +94,7 @@ QVariant QPdfLinkModel::data(const QModelIndex &index, int role) const
return link.location();
case Role::Zoom:
return link.zoom();
- case Role::_Count:
+ case Role::NRoles:
break;
}
if (role == Qt::DisplayRole)
@@ -101,7 +104,7 @@ QVariant QPdfLinkModel::data(const QModelIndex &index, int role) const
/*!
\property QPdfLinkModel::document
- \brief the document to load links from
+ \brief The document to load links from.
*/
QPdfDocument *QPdfLinkModel::document() const
{
@@ -127,7 +130,7 @@ void QPdfLinkModel::setDocument(QPdfDocument *document)
/*!
\property QPdfLinkModel::page
- \brief the page to load links from
+ \brief The page to load links from.
*/
int QPdfLinkModel::page() const
{
@@ -146,8 +149,22 @@ void QPdfLinkModel::setPage(int page)
d->update();
}
-QPdfLinkModelPrivate::QPdfLinkModelPrivate() : QAbstractItemModelPrivate()
+/*!
+ Returns a \l {QPdfLink::isValid()}{valid} link if found under the \a point
+ (given in units of points, 1/72 of an inch), or an invalid link if it is
+ not found. In other words, this function is useful for picking, to handle
+ mouse click or hover.
+*/
+QPdfLink QPdfLinkModel::linkAt(QPointF point) const
{
+ Q_D(const QPdfLinkModel);
+ for (const auto &link : std::as_const(d->links)) {
+ for (const auto &rect : link.rectangles()) {
+ if (rect.contains(point))
+ return link;
+ }
+ }
+ return {};
}
void QPdfLinkModelPrivate::update()
@@ -162,7 +179,6 @@ void QPdfLinkModelPrivate::update()
qCWarning(qLcLink) << "failed to load page" << page;
return;
}
- double pageHeight = FPDF_GetPageHeight(pdfPage);
q->beginResetModel();
links.clear();
@@ -187,8 +203,28 @@ void QPdfLinkModelPrivate::update()
std::swap(rect.bottom, rect.top);
QPdfLink linkData;
- linkData.d->rects << QRectF(rect.left, pageHeight - rect.top,
- rect.right - rect.left, rect.top - rect.bottom);
+ // Use quad points if present; otherwise use the rect.
+ if (int quadPointsCount = FPDFLink_CountQuadPoints(linkAnnot) > 0) {
+ for (int i = 0; i < quadPointsCount; ++i) {
+ FS_QUADPOINTSF point;
+ if (FPDFLink_GetQuadPoints(linkAnnot, i, &point)) {
+ // Quadpoints are counter clockwise from bottom left (x1, y1)
+ QPolygonF poly;
+ poly << QPointF(point.x1, point.y1);
+ poly << QPointF(point.x2, point.y2);
+ poly << QPointF(point.x3, point.y3);
+ poly << QPointF(point.x4, point.y4);
+ QRectF bounds = poly.boundingRect();
+ bounds = document->d->mapPageToView(pdfPage, bounds.left(), bounds.top(), bounds.right(), bounds.bottom());
+ qCDebug(qLcLink) << "quadpoints" << i << "of" << quadPointsCount << ":" << poly << "mapped bounds" << bounds;
+ linkData.d->rects << bounds;
+ // QPdfLink could store polygons rather than rects, to get the benefit of quadpoints;
+ // so far we didn't bother. It would be an API change, and we'd need to use Shapes in PdfLinkDelegate.qml
+ }
+ }
+ } else {
+ linkData.d->rects << document->d->mapPageToView(pdfPage, rect.left, rect.top, rect.right, rect.bottom);
+ }
FPDF_DEST dest = FPDFLink_GetDest(doc, linkAnnot);
FPDF_ACTION action = FPDFLink_GetAction(linkAnnot);
switch (FPDFAction_GetType(action)) {
@@ -196,7 +232,7 @@ void QPdfLinkModelPrivate::update()
case PDFACTION_GOTO: {
linkData.d->page = FPDFDest_GetDestPageIndex(doc, dest);
if (linkData.d->page < 0) {
- qCWarning(qLcLink) << "skipping link with invalid page number";
+ qCWarning(qLcLink) << "skipping link with invalid page number" << linkData.d->page;
continue; // while enumerating links
}
FPDF_BOOL hasX, hasY, hasZoom;
@@ -207,7 +243,7 @@ void QPdfLinkModelPrivate::update()
break; // at least we got a page number, so the link will jump there
}
if (hasX && hasY)
- linkData.d->location = QPointF(x, pageHeight - y);
+ linkData.d->location = document->d->mapPageToView(pdfPage, x, y);
if (hasZoom)
linkData.d->zoom = zoom;
break;
@@ -270,7 +306,7 @@ void QPdfLinkModelPrivate::update()
double left, top, right, bottom;
bool success = FPDFLink_GetRect(webLinks, i, r, &left, &top, &right, &bottom);
if (success) {
- linkData.d->rects << QRectF(left, pageHeight - top, right - left, top - bottom);
+ linkData.d->rects << document->d->mapPageToView(pdfPage, left, top, right, bottom);
links << linkData;
}
}