diff options
author | Shawn Rutledge <shawn.rutledge@qt.io> | 2022-06-03 07:56:23 +0200 |
---|---|---|
committer | Shawn Rutledge <shawn.rutledge@qt.io> | 2022-06-04 20:55:31 +0200 |
commit | fd39e1eeedd71f8511373d399507a0ddeedf592c (patch) | |
tree | 8df349d903f4a35ee71b7e9569e9f7c41c7f28da | |
parent | 0de16e9a20366b02b544e2279461612c69cdf11b (diff) | |
download | qtwebengine-fd39e1eeedd71f8511373d399507a0ddeedf592c.tar.gz |
Add link role to QPdfLinkModel, providing a QPdfLink instance
We want to call PdfPageNavigator.jump(link) when a link is clicked;
therefore PdfLinkModel needs to provide this object; therefore it makes
sense to store the links as QPdfLink instances, and get rid of the
redundant internal Link object type. But QPdfLink did not have storage
for a QUrl until now. The textStart and textCharCount fields sounded
useful, but in practice were set and not used.
QPdfLink gains toString() and copyToClipboard() methods.
Also removed some unused cruft in qquickpdflinkmodel.
[ChangeLog][QtPDF] PdfLinkModel now provides a QPdfLink object for each
link. QPdfLink now contains everything necessary to render delegates for
links and search results, and handle clicking links; and there is a
copyToClipboard() method for use in context menus, which will copy
the text returned trom toString(), which is also invokable.
Change-Id: Ifa5abe6df8f8d6f9ef98971044c26691ec4b9a36
Reviewed-by: Richard Moe Gustavsen <richard.gustavsen@qt.io>
-rw-r--r-- | src/pdf/qpdflink.cpp | 37 | ||||
-rw-r--r-- | src/pdf/qpdflink.h | 6 | ||||
-rw-r--r-- | src/pdf/qpdflink_p.h | 2 | ||||
-rw-r--r-- | src/pdf/qpdflinkmodel.cpp | 59 | ||||
-rw-r--r-- | src/pdf/qpdflinkmodel_p.h | 3 | ||||
-rw-r--r-- | src/pdf/qpdflinkmodel_p_p.h | 18 | ||||
-rw-r--r-- | src/pdfquick/qquickpdflinkmodel_p.h | 8 |
7 files changed, 74 insertions, 59 deletions
diff --git a/src/pdf/qpdflink.cpp b/src/pdf/qpdflink.cpp index 091a29729..94d4e741d 100644 --- a/src/pdf/qpdflink.cpp +++ b/src/pdf/qpdflink.cpp @@ -39,6 +39,8 @@ #include "qpdflink.h" #include "qpdflink_p.h" +#include "qpdflinkmodel_p.h" +#include <QGuiApplication> QT_BEGIN_NAMESPACE @@ -126,6 +128,17 @@ qreal QPdfLink::zoom() const } /*! + \property QPdfLink::url + + This property holds the destination URL if the link is an external hyperlink; + otherwise, it's empty. +*/ +QUrl QPdfLink::url() const +{ + return d->url; +} + +/*! \property QPdfLink::contextBefore This property holds adjacent text found on the page before the search string. @@ -167,6 +180,30 @@ QList<QRectF> QPdfLink::rectangles() const return d->rects; } +/*! + Returns a translated representation for display. + + \sa copyToClipboard() +*/ +QString QPdfLink::toString() const +{ + static const QString format = QPdfLinkModel::tr("page %1 location %2,%3 zoom %4"); + return d->page > 0 ? format.arg(QString::number(d->page), + QString::number(d->location.x()), + QString::number(d->location.y()), + QString::number(d->zoom)) + : d->url.toString(); +} + +/*! + Copies the toString() representation of the link to the + \l {QGuiApplication::clipboard()}{system clipboard} depending on the \a mode given. +*/ +void QPdfLink::copyToClipboard(QClipboard::Mode mode) const +{ + QGuiApplication::clipboard()->setText(toString(), mode); +} + QDebug operator<<(QDebug dbg, const QPdfLink &link) { QDebugStateSaver saver(dbg); diff --git a/src/pdf/qpdflink.h b/src/pdf/qpdflink.h index 22de24063..64185554b 100644 --- a/src/pdf/qpdflink.h +++ b/src/pdf/qpdflink.h @@ -47,6 +47,7 @@ #include <QtCore/qpoint.h> #include <QtCore/qrect.h> #include <QtCore/qshareddata.h> +#include <QtGui/qclipboard.h> QT_BEGIN_NAMESPACE @@ -59,6 +60,7 @@ class QPdfLink Q_PROPERTY(int page READ page) Q_PROPERTY(QPointF location READ location) Q_PROPERTY(qreal zoom READ zoom) + Q_PROPERTY(QUrl url READ url) Q_PROPERTY(QString contextBefore READ contextBefore) Q_PROPERTY(QString contextAfter READ contextAfter) Q_PROPERTY(QList<QRectF> rectangles READ rectangles) @@ -78,15 +80,19 @@ public: Q_PDF_EXPORT int page() const; Q_PDF_EXPORT QPointF location() const; Q_PDF_EXPORT qreal zoom() const; + Q_PDF_EXPORT QUrl url() const; Q_PDF_EXPORT QString contextBefore() const; Q_PDF_EXPORT QString contextAfter() const; Q_PDF_EXPORT QList<QRectF> rectangles() const; + Q_PDF_EXPORT Q_INVOKABLE QString toString() const; + Q_PDF_EXPORT Q_INVOKABLE void copyToClipboard(QClipboard::Mode mode = QClipboard::Clipboard) const; private: // methods QPdfLink(int page, QPointF location, qreal zoom); QPdfLink(int page, QList<QRectF> rects, QString contextBefore, QString contextAfter); QPdfLink(QPdfLinkPrivate *d); friend class QPdfDocument; + friend class QPdfLinkModelPrivate; friend class QPdfSearchModelPrivate; friend class QPdfPageNavigator; friend class QQuickPdfPageNavigator; diff --git a/src/pdf/qpdflink_p.h b/src/pdf/qpdflink_p.h index 7cda6edfc..4acfc4182 100644 --- a/src/pdf/qpdflink_p.h +++ b/src/pdf/qpdflink_p.h @@ -55,6 +55,7 @@ #include <QPointF> #include <QRectF> +#include <QUrl> QT_BEGIN_NAMESPACE @@ -79,6 +80,7 @@ public: qreal zoom = 1; QString contextBefore; QString contextAfter; + QUrl url; QList<QRectF> rects; }; diff --git a/src/pdf/qpdflinkmodel.cpp b/src/pdf/qpdflinkmodel.cpp index fba9c23c4..4997cd314 100644 --- a/src/pdf/qpdflinkmodel.cpp +++ b/src/pdf/qpdflinkmodel.cpp @@ -37,6 +37,7 @@ ** ****************************************************************************/ +#include "qpdflink_p.h" #include "qpdflinkmodel_p.h" #include "qpdflinkmodel_p_p.h" #include "qpdfdocument_p.h" @@ -76,18 +77,20 @@ int QPdfLinkModel::rowCount(const QModelIndex &parent) const QVariant QPdfLinkModel::data(const QModelIndex &index, int role) const { Q_D(const QPdfLinkModel); - const QPdfLinkModelPrivate::Link &link = d->links.at(index.row()); + const auto &link = d->links.at(index.row()); switch (Role(role)) { + case Role::Link: + return QVariant::fromValue(link); case Role::Rect: - return link.rect; + return link.rectangles().empty() ? QVariant() : link.rectangles().constFirst(); case Role::Url: - return link.url; + return link.url(); case Role::Page: - return link.page; + return link.page(); case Role::Location: - return link.location; + return link.location(); case Role::Zoom: - return link.zoom; + return link.zoom(); case Role::_Count: break; } @@ -169,16 +172,16 @@ void QPdfLinkModelPrivate::update() qCWarning(qLcLink) << "skipping link with invalid bounding box"; continue; // while enumerating links } - Link linkData; - linkData.rect = QRectF(rect.left, pageHeight - rect.top, + QPdfLink linkData; + linkData.d->rects << QRectF(rect.left, pageHeight - rect.top, rect.right - rect.left, rect.top - rect.bottom); FPDF_DEST dest = FPDFLink_GetDest(doc, linkAnnot); FPDF_ACTION action = FPDFLink_GetAction(linkAnnot); switch (FPDFAction_GetType(action)) { case PDFACTION_UNSUPPORTED: // this happens with valid links in some PDFs case PDFACTION_GOTO: { - linkData.page = FPDFDest_GetDestPageIndex(doc, dest); - if (linkData.page < 0) { + linkData.d->page = FPDFDest_GetDestPageIndex(doc, dest); + if (linkData.d->page < 0) { qCWarning(qLcLink) << "skipping link with invalid page number"; continue; // while enumerating links } @@ -186,25 +189,25 @@ void QPdfLinkModelPrivate::update() FS_FLOAT x, y, zoom; ok = FPDFDest_GetLocationInPage(dest, &hasX, &hasY, &hasZoom, &x, &y, &zoom); if (!ok) { - qCWarning(qLcLink) << "link with invalid location and/or zoom @" << linkData.rect; + qCWarning(qLcLink) << "link with invalid location and/or zoom @" << linkData.d->rects; break; // at least we got a page number, so the link will jump there } if (hasX && hasY) - linkData.location = QPointF(x, pageHeight - y); + linkData.d->location = QPointF(x, pageHeight - y); if (hasZoom) - linkData.zoom = zoom; + linkData.d->zoom = zoom; break; } case PDFACTION_URI: { unsigned long len = FPDFAction_GetURIPath(doc, action, nullptr, 0); if (len < 1) { - qCWarning(qLcLink) << "skipping link with empty URI @" << linkData.rect; + qCWarning(qLcLink) << "skipping link with empty URI @" << linkData.d->rects; continue; // while enumerating links } else { QByteArray buf(len, 0); unsigned long got = FPDFAction_GetURIPath(doc, action, buf.data(), len); Q_ASSERT(got == len); - linkData.url = QString::fromLatin1(buf.data(), got - 1); + linkData.d->url = QString::fromLatin1(buf.data(), got - 1); } break; } @@ -212,13 +215,13 @@ void QPdfLinkModelPrivate::update() case PDFACTION_REMOTEGOTO: { unsigned long len = FPDFAction_GetFilePath(action, nullptr, 0); if (len < 1) { - qCWarning(qLcLink) << "skipping link with empty file path @" << linkData.rect; + qCWarning(qLcLink) << "skipping link with empty file path @" << linkData.d->rects; continue; // while enumerating links } else { QByteArray buf(len, 0); unsigned long got = FPDFAction_GetFilePath(action, buf.data(), len); Q_ASSERT(got == len); - linkData.url = QUrl::fromLocalFile(QString::fromLatin1(buf.data(), got - 1)).toString(); + linkData.d->url = QUrl::fromLocalFile(QString::fromLatin1(buf.data(), got - 1)).toString(); // Unfortunately, according to comments in fpdf_doc.h, if it's PDFACTION_REMOTEGOTO, // we can't get the page and location without first opening the linked document @@ -237,7 +240,7 @@ void QPdfLinkModelPrivate::update() if (webLinks) { int count = FPDFLink_CountWebLinks(webLinks); for (int i = 0; i < count; ++i) { - Link linkData; + QPdfLink linkData; int len = FPDFLink_GetURL(webLinks, i, nullptr, 0); if (len < 1) { qCWarning(qLcLink) << "skipping link" << i << "with empty URL"; @@ -245,16 +248,15 @@ void QPdfLinkModelPrivate::update() QList<unsigned short> buf(len); int got = FPDFLink_GetURL(webLinks, i, buf.data(), len); Q_ASSERT(got == len); - linkData.url = QString::fromUtf16( + linkData.d->url = QString::fromUtf16( reinterpret_cast<const char16_t *>(buf.data()), got - 1); } - FPDFLink_GetTextRange(webLinks, i, &linkData.textStart, &linkData.textCharCount); len = FPDFLink_CountRects(webLinks, i); for (int r = 0; r < len; ++r) { double left, top, right, bottom; bool success = FPDFLink_GetRect(webLinks, i, r, &left, &top, &right, &bottom); if (success) { - linkData.rect = QRectF(left, pageHeight - top, right - left, top - bottom); + linkData.d->rects << QRectF(left, pageHeight - top, right - left, top - bottom); links << linkData; } } @@ -267,8 +269,8 @@ void QPdfLinkModelPrivate::update() // All done FPDF_ClosePage(pdfPage); if (Q_UNLIKELY(qLcLink().isDebugEnabled())) { - for (const Link &l : links) - qCDebug(qLcLink) << l.rect << l.toString(); + for (const auto &l : links) + qCDebug(qLcLink) << l; } q->endResetModel(); } @@ -281,17 +283,6 @@ void QPdfLinkModel::onStatusChanged(QPdfDocument::Status status) d->update(); } -QString QPdfLinkModelPrivate::Link::toString() const -{ - QString ret; - if (page >= 0) - return QLatin1String("page ") + QString::number(page) + - QLatin1String(" location ") + QString::number(location.x()) + QLatin1Char(',') + QString::number(location.y()) + - QLatin1String(" zoom ") + QString::number(zoom); - else - return url.toString(); -} - QT_END_NAMESPACE #include "moc_qpdflinkmodel_p.cpp" diff --git a/src/pdf/qpdflinkmodel_p.h b/src/pdf/qpdflinkmodel_p.h index 495370fe1..35fa28dcd 100644 --- a/src/pdf/qpdflinkmodel_p.h +++ b/src/pdf/qpdflinkmodel_p.h @@ -69,7 +69,8 @@ class Q_PDF_EXPORT QPdfLinkModel : public QAbstractListModel public: enum class Role : int { - Rect = Qt::UserRole, + Link = Qt::UserRole, + Rect, Url, Page, Location, diff --git a/src/pdf/qpdflinkmodel_p_p.h b/src/pdf/qpdflinkmodel_p_p.h index 14c8bc734..276a49fe9 100644 --- a/src/pdf/qpdflinkmodel_p_p.h +++ b/src/pdf/qpdflinkmodel_p_p.h @@ -52,6 +52,7 @@ // #include "qpdflinkmodel_p.h" +#include "qpdflink.h" #include <private/qabstractitemmodel_p.h> #include "third_party/pdfium/public/fpdfview.h" @@ -69,23 +70,8 @@ public: void update(); - struct Link { - // where it is on the current page - QRectF rect; - int textStart = -1; - int textCharCount = 0; - // destination inside PDF - int page = -1; // -1 means look at the url instead - QPointF location; - qreal zoom = 0; // 0 means no specified zoom: don't change when clicking - // web destination - QUrl url; - - QString toString() const; - }; - QPdfDocument *document = nullptr; - QList<Link> links; + QList<QPdfLink> links; int page = 0; }; diff --git a/src/pdfquick/qquickpdflinkmodel_p.h b/src/pdfquick/qquickpdflinkmodel_p.h index 156444828..153639e43 100644 --- a/src/pdfquick/qquickpdflinkmodel_p.h +++ b/src/pdfquick/qquickpdflinkmodel_p.h @@ -73,16 +73,8 @@ public: QQuickPdfDocument *document() const; void setDocument(QQuickPdfDocument *document); -signals: - void documentChanged(); - -private: - void updateResults(); - private: QQuickPdfDocument *m_quickDocument; - QList<QPolygonF> m_linksGeometry; - Q_DISABLE_COPY(QQuickPdfLinkModel) }; |