diff options
author | Shawn Rutledge <shawn.rutledge@qt.io> | 2020-01-20 18:29:05 +0100 |
---|---|---|
committer | Shawn Rutledge <shawn.rutledge@qt.io> | 2020-01-30 16:26:27 +0100 |
commit | bc1d6ddeb5076f68e0a758725a20c3f2a6d081f0 (patch) | |
tree | c730d9ffbe79b262fbe6962fa2daa3f14adf0fc5 /src | |
parent | 4f5f0705bc161ff95899fdb2c5fcdb4581bf15bb (diff) |
Add QPdfSelection and QQuickPdfSelection
So now you can select text by mouse-drag and copy it to the clipboard.
Task-number: QTBUG-77509
Change-Id: I689ee4158974de8bc541c319a5a5cc2f8f3c2ae6
Reviewed-by: Michal Klocek <michal.klocek@qt.io>
Diffstat (limited to 'src')
-rw-r--r-- | src/pdf/api/qpdfdocument.h | 3 | ||||
-rw-r--r-- | src/pdf/api/qpdfselection.h | 83 | ||||
-rw-r--r-- | src/pdf/api/qpdfselection_p.h | 59 | ||||
-rw-r--r-- | src/pdf/pdfcore.pro | 3 | ||||
-rw-r--r-- | src/pdf/qpdfdocument.cpp | 47 | ||||
-rw-r--r-- | src/pdf/qpdfselection.cpp | 138 | ||||
-rw-r--r-- | src/pdf/quick/plugin.cpp | 2 | ||||
-rw-r--r-- | src/pdf/quick/qml/PdfPageView.qml | 30 | ||||
-rw-r--r-- | src/pdf/quick/qquickpdfsearchmodel_p.h | 1 | ||||
-rw-r--r-- | src/pdf/quick/qquickpdfselection.cpp | 268 | ||||
-rw-r--r-- | src/pdf/quick/qquickpdfselection_p.h | 122 | ||||
-rw-r--r-- | src/pdf/quick/quick.pro | 2 |
12 files changed, 758 insertions, 0 deletions
diff --git a/src/pdf/api/qpdfdocument.h b/src/pdf/api/qpdfdocument.h index 1252fa6d2..46d197f1d 100644 --- a/src/pdf/api/qpdfdocument.h +++ b/src/pdf/api/qpdfdocument.h @@ -41,6 +41,7 @@ #include <QImage> #include <QObject> #include <QtPdf/QPdfDocumentRenderOptions> +#include "qpdfselection.h" QT_BEGIN_NAMESPACE @@ -111,6 +112,8 @@ public: QImage render(int page, QSize imageSize, QPdfDocumentRenderOptions options = QPdfDocumentRenderOptions()); + Q_INVOKABLE QPdfSelection getSelection(int page, QPointF start, QPointF end); + Q_SIGNALS: void passwordChanged(); void passwordRequired(); diff --git a/src/pdf/api/qpdfselection.h b/src/pdf/api/qpdfselection.h new file mode 100644 index 000000000..900b203cf --- /dev/null +++ b/src/pdf/api/qpdfselection.h @@ -0,0 +1,83 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtPDF module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QPDFSELECTION_H +#define QPDFSELECTION_H + +#include <QtPdf/qtpdfglobal.h> +#include <QClipboard> +#include <QExplicitlySharedDataPointer> +#include <QObject> +#include <QPolygonF> + +QT_BEGIN_NAMESPACE + +class QPdfSelectionPrivate; + +class Q_PDF_EXPORT QPdfSelection +{ + Q_GADGET + Q_PROPERTY(bool valid READ isValid) + Q_PROPERTY(QVector<QPolygonF> bounds READ bounds) + Q_PROPERTY(QString text READ text) + +public: + QPdfSelection(const QPdfSelection &other); + ~QPdfSelection(); + QPdfSelection &operator=(const QPdfSelection &other); + inline QPdfSelection &operator=(QPdfSelection &&other) noexcept { swap(other); return *this; } + void swap(QPdfSelection &other) noexcept { d.swap(other.d); } + bool isValid() const; + QVector<QPolygonF> bounds() const; + QString text() const; +#if QT_CONFIG(clipboard) + void copyToClipboard(QClipboard::Mode mode = QClipboard::Clipboard) const; +#endif + +private: + QPdfSelection(); + QPdfSelection(const QString &text, QVector<QPolygonF> bounds); + QPdfSelection(QPdfSelectionPrivate *d); + friend class QPdfDocument; + friend class QQuickPdfSelection; + +private: + QExplicitlySharedDataPointer<QPdfSelectionPrivate> d; +}; + +QT_END_NAMESPACE + +#endif // QPDFSELECTION_H diff --git a/src/pdf/api/qpdfselection_p.h b/src/pdf/api/qpdfselection_p.h new file mode 100644 index 000000000..37145f7f9 --- /dev/null +++ b/src/pdf/api/qpdfselection_p.h @@ -0,0 +1,59 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtPDF module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QPDFSELECTION_P_H +#define QPDFSELECTION_P_H + +#include <QPolygonF> +#include <QVector> + +QT_BEGIN_NAMESPACE + +class QPdfSelectionPrivate : public QSharedData +{ +public: + QPdfSelectionPrivate() = default; + QPdfSelectionPrivate(const QString &text, QVector<QPolygonF> bounds) + : text(text), + bounds(bounds) { } + + QString text; + QVector<QPolygonF> bounds; +}; + +QT_END_NAMESPACE + +#endif // QPDFSELECTION_P_H diff --git a/src/pdf/pdfcore.pro b/src/pdf/pdfcore.pro index 1f9f21e0a..f50c3aa06 100644 --- a/src/pdf/pdfcore.pro +++ b/src/pdf/pdfcore.pro @@ -64,6 +64,7 @@ SOURCES += \ qpdfpagenavigation.cpp \ qpdfpagerenderer.cpp \ qpdfsearchmodel.cpp \ + qpdfselection.cpp \ # all "public" headers must be in "api" for sync script and to hide auto generated headers # by Chromium in case of in-source build @@ -79,5 +80,7 @@ HEADERS += \ api/qpdfpagerenderer.h \ api/qpdfsearchmodel.h \ qpdfsearchmodel_p.h \ + api/qpdfselection.h \ + api/qpdfselection_p.h \ load(qt_module) diff --git a/src/pdf/qpdfdocument.cpp b/src/pdf/qpdfdocument.cpp index 728bf1245..37eeb8426 100644 --- a/src/pdf/qpdfdocument.cpp +++ b/src/pdf/qpdfdocument.cpp @@ -38,6 +38,7 @@ #include "qpdfdocument_p.h" #include "third_party/pdfium/public/fpdf_doc.h" +#include "third_party/pdfium/public/fpdf_text.h" #include <QDateTime> #include <QDebug> @@ -53,6 +54,7 @@ QT_BEGIN_NAMESPACE // The library is not thread-safe at all, it has a lot of global variables. Q_GLOBAL_STATIC_WITH_ARGS(QMutex, pdfMutex, (QMutex::Recursive)); static int libraryRefCount; +static const double CharacterHitTolerance = 6.0; Q_LOGGING_CATEGORY(qLcDoc, "qt.pdf.document") QPdfMutexLocker::QPdfMutexLocker() @@ -714,6 +716,51 @@ QImage QPdfDocument::render(int page, QSize imageSize, QPdfDocumentRenderOptions return result; } +/*! + Returns information about the text on the given \a page that can be found + between the given \a start and \a end points, if any. +*/ +QPdfSelection QPdfDocument::getSelection(int page, QPointF start, QPointF end) +{ + const QPdfMutexLocker lock; + FPDF_PAGE pdfPage = FPDF_LoadPage(d->doc, page); + double pageHeight = FPDF_GetPageHeight(pdfPage); + FPDF_TEXTPAGE textPage = FPDFText_LoadPage(pdfPage); + int startIndex = FPDFText_GetCharIndexAtPos(textPage, start.x(), pageHeight - start.y(), + CharacterHitTolerance, CharacterHitTolerance); + int endIndex = FPDFText_GetCharIndexAtPos(textPage, end.x(), pageHeight - end.y(), + CharacterHitTolerance, CharacterHitTolerance); + if (startIndex >= 0 && endIndex != startIndex) { + QString text; + if (startIndex > endIndex) + qSwap(startIndex, endIndex); + int count = endIndex - startIndex + 1; + QVector<ushort> buf(count + 1); + // TODO is that enough space in case one unicode character is more than one in utf-16? + int len = FPDFText_GetText(textPage, startIndex, count, buf.data()); + Q_ASSERT(len - 1 <= count); // len is number of characters written, including the terminator + text = QString::fromUtf16(buf.constData(), len - 1); + QVector<QPolygonF> bounds; + int rectCount = FPDFText_CountRects(textPage, startIndex, endIndex - startIndex); + for (int i = 0; i < rectCount; ++i) { + double l, r, b, t; + FPDFText_GetRect(textPage, i, &l, &t, &r, &b); + QPolygonF poly; + poly << QPointF(l, pageHeight - t); + poly << QPointF(r, pageHeight - t); + poly << QPointF(r, pageHeight - b); + poly << QPointF(l, pageHeight - b); + poly << QPointF(l, pageHeight - t); + bounds << poly; + } + qCDebug(qLcDoc) << page << start << "->" << end << "found" << startIndex << "->" << endIndex << text; + return QPdfSelection(text, bounds); + } + + qDebug(qLcDoc) << page << start << "->" << end << "nothing found"; + return QPdfSelection(); +} + QT_END_NAMESPACE #include "moc_qpdfdocument.cpp" diff --git a/src/pdf/qpdfselection.cpp b/src/pdf/qpdfselection.cpp new file mode 100644 index 000000000..8c3d6fde0 --- /dev/null +++ b/src/pdf/qpdfselection.cpp @@ -0,0 +1,138 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtPDF module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qpdfselection.h" +#include "qpdfselection_p.h" +#include <QGuiApplication> + +QT_BEGIN_NAMESPACE + +/*! + \class QPdfSelection + \since 5.15 + \inmodule QtPdf + + \brief The QPdfSelection class defines a range of text that has been selected + on one page in a PDF document, and its geometric boundaries. + + \sa QPdfDocument::getSelection() +*/ + +/*! + Constructs an invalid selection. + + \sa valid +*/ +QPdfSelection::QPdfSelection() + : d(new QPdfSelectionPrivate()) +{ +} + +/*! + \internal + Constructs a selection including the range of characters that make up the + \a text string, and which take up space on the page within the polygon + regions given in \a bounds. +*/ +QPdfSelection::QPdfSelection(const QString &text, QVector<QPolygonF> bounds) + : d(new QPdfSelectionPrivate(text, bounds)) +{ +} + +QPdfSelection::QPdfSelection(QPdfSelectionPrivate *d) + : d(d) +{ +} + +QPdfSelection::QPdfSelection(const QPdfSelection &other) + : d(other.d) +{ +} + +QPdfSelection::~QPdfSelection() +{ +} + +/*! + \property QPdfSelection::valid + + This property holds whether the selection is valid. +*/ +bool QPdfSelection::isValid() const +{ + return !d->bounds.isEmpty(); +} + +/*! + \property QPdfSelection::bounds + + This property holds a set of regions that the selected text occupies on the + page, represented as polygons. The coordinate system for the polygons has + the origin at the upper-left corner of the page, and the units are + \l {https://en.wikipedia.org/wiki/Point_(typography)}{points}. + + \note For now, the polygons returned from \l QPdfDocument::getSelection() + are always rectangles; but in the future it may be possible to represent + more complex regions. +*/ +QVector<QPolygonF> QPdfSelection::bounds() const +{ + return d->bounds; +} + +/*! + \property QPdfSelection::text + + This property holds the selected text. +*/ +QString QPdfSelection::text() const +{ + return d->text; +} + +#if QT_CONFIG(clipboard) +/*! + Copies \l text to the \l {QGuiApplication::clipboard()}{system clipboard}. +*/ +void QPdfSelection::copyToClipboard(QClipboard::Mode mode) const +{ + QGuiApplication::clipboard()->setText(d->text, mode); +} +#endif + +QT_END_NAMESPACE + +#include "moc_qpdfselection.cpp" diff --git a/src/pdf/quick/plugin.cpp b/src/pdf/quick/plugin.cpp index 664ba51ab..72aa12d6a 100644 --- a/src/pdf/quick/plugin.cpp +++ b/src/pdf/quick/plugin.cpp @@ -40,6 +40,7 @@ #include <QtQml/qqmlextensionplugin.h> #include "qquickpdfdocument_p.h" #include "qquickpdfsearchmodel_p.h" +#include "qquickpdfselection_p.h" QT_BEGIN_NAMESPACE @@ -81,6 +82,7 @@ public: qmlRegisterType<QQuickPdfDocument>(uri, 5, 15, "PdfDocument"); qmlRegisterType<QQuickPdfSearchModel>(uri, 5, 15, "PdfSearchModel"); + qmlRegisterType<QQuickPdfSelection>(uri, 5, 15, "PdfSelection"); qmlRegisterType(QUrl("qrc:/qt-project.org/qtpdf/qml/PdfPageView.qml"), uri, 5, 15, "PdfPageView"); } diff --git a/src/pdf/quick/qml/PdfPageView.qml b/src/pdf/quick/qml/PdfPageView.qml index b7f75f4c2..2f9c5ef99 100644 --- a/src/pdf/quick/qml/PdfPageView.qml +++ b/src/pdf/quick/qml/PdfPageView.qml @@ -51,10 +51,23 @@ Rectangle { property alias currentPage: image.currentFrame property alias pageCount: image.frameCount property alias searchString: searchModel.searchString + property alias selectedText: selection.text property alias status: image.status property real __pageScale: image.paintedWidth / document.pagePointSize(image.currentFrame).width + PdfSelection { + id: selection + document: paper.document + page: image.currentFrame + fromPoint: Qt.point(textSelectionDrag.centroid.pressPosition.x / paper.__pageScale, textSelectionDrag.centroid.pressPosition.y / paper.__pageScale) + toPoint: Qt.point(textSelectionDrag.centroid.position.x / paper.__pageScale, textSelectionDrag.centroid.position.y / paper.__pageScale) + hold: !textSelectionDrag.active && !tapHandler.pressed + } + function copySelectionToClipboard() { + selection.copyToClipboard() + } + PdfSearchModel { id: searchModel document: paper.document @@ -96,6 +109,14 @@ Rectangle { paths: searchModel.matchGeometry } } + ShapePath { + fillColor: "orange" + scale: Qt.size(paper.__pageScale, paper.__pageScale) + PathMultiline { + id: selectionBoundaries + paths: selection.geometry + } + } } PinchHandler { id: pinch @@ -116,4 +137,13 @@ Rectangle { acceptedButtons: Qt.MiddleButton snapMode: DragHandler.NoSnap } + DragHandler { + id: textSelectionDrag + acceptedDevices: PointerDevice.Mouse | PointerDevice.Stylus + target: null + } + TapHandler { + id: tapHandler + acceptedDevices: PointerDevice.Mouse | PointerDevice.Stylus + } } diff --git a/src/pdf/quick/qquickpdfsearchmodel_p.h b/src/pdf/quick/qquickpdfsearchmodel_p.h index 799ef825f..82a6289d0 100644 --- a/src/pdf/quick/qquickpdfsearchmodel_p.h +++ b/src/pdf/quick/qquickpdfsearchmodel_p.h @@ -99,5 +99,6 @@ private: QT_END_NAMESPACE QML_DECLARE_TYPE(QQuickPdfSearchModel) +QML_DECLARE_TYPE(QPdfSelection) #endif // QQUICKPDFSEARCHMODEL_P_H diff --git a/src/pdf/quick/qquickpdfselection.cpp b/src/pdf/quick/qquickpdfselection.cpp new file mode 100644 index 000000000..d313820ba --- /dev/null +++ b/src/pdf/quick/qquickpdfselection.cpp @@ -0,0 +1,268 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtPDF module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qquickpdfselection_p.h" +#include "qquickpdfdocument_p.h" +#include <QClipboard> +#include <QQuickItem> +#include <QQmlEngine> +#include <QStandardPaths> +#include <private/qguiapplication_p.h> + +QT_BEGIN_NAMESPACE + +/*! + \qmltype PdfSelection + \instantiates QQuickPdfSelection + \inqmlmodule QtQuick.Pdf + \ingroup pdf + \brief A representation of a text selection within a PDF Document. + \since 5.15 + + PdfSelection provides the text string and its geometry within a bounding box + from one point to another. +*/ + +/*! + Constructs a SearchModel. +*/ +QQuickPdfSelection::QQuickPdfSelection(QObject *parent) + : QObject(parent) +{ +} + +QQuickPdfDocument *QQuickPdfSelection::document() const +{ + return m_document; +} + +void QQuickPdfSelection::setDocument(QQuickPdfDocument *document) +{ + if (m_document == document) + return; + + if (m_document) { + disconnect(m_document, &QQuickPdfDocument::sourceChanged, + this, &QQuickPdfSelection::resetPoints); + } + m_document = document; + emit documentChanged(); + resetPoints(); + connect(m_document, &QQuickPdfDocument::sourceChanged, + this, &QQuickPdfSelection::resetPoints); +} + +/*! + \qmlproperty list<list<point>> PdfSelection::geometry + + A set of paths in a form that can be bound to the \c paths property of a + \l {QtQuick::PathMultiline}{PathMultiline} instance to render a batch of + rectangles around the text regions that are included in the selection: + + \qml + PdfDocument { + id: doc + } + PdfSelection { + id: selection + document: doc + fromPoint: textSelectionDrag.centroid.pressPosition + toPoint: textSelectionDrag.centroid.position + hold: !textSelectionDrag.active + } + Shape { + ShapePath { + PathMultiline { + paths: selection.geometry + } + } + } + DragHandler { + id: textSelectionDrag + acceptedDevices: PointerDevice.Mouse | PointerDevice.Stylus + target: null + } + \endqml + + \sa PathMultiline +*/ +QVector<QPolygonF> QQuickPdfSelection::geometry() const +{ + return m_geometry; +} + +void QQuickPdfSelection::resetPoints() +{ + bool wasHolding = m_hold; + m_hold = false; + setFromPoint(QPointF()); + setToPoint(QPointF()); + m_hold = wasHolding; +} + +/*! + \qmlproperty int PdfSelection::page + + The page number on which to search. + + \sa QtQuick::Image::currentFrame +*/ +int QQuickPdfSelection::page() const +{ + return m_page; +} + +void QQuickPdfSelection::setPage(int page) +{ + if (m_page == page) + return; + + m_page = page; + emit pageChanged(); + resetPoints(); +} + +/*! + \qmlproperty point PdfSelection::fromPoint + + The beginning location, in \l {https://en.wikipedia.org/wiki/Point_(typography)}{points} + from the upper-left corner of the page, from which to find selected text. + This can be bound to a scaled version of the \c centroid.pressPosition + of a \l DragHandler to begin selecting text from the position where the user + presses the mouse button and begins dragging, for example. +*/ +QPointF QQuickPdfSelection::fromPoint() const +{ + return m_fromPoint; +} + +void QQuickPdfSelection::setFromPoint(QPointF fromPoint) +{ + if (m_hold || m_fromPoint == fromPoint) + return; + + m_fromPoint = fromPoint; + emit fromPointChanged(); + updateResults(); +} + +/*! + \qmlproperty point PdfSelection::toPoint + + The ending location, in \l {https://en.wikipedia.org/wiki/Point_(typography)}{points} + from the upper-left corner of the page, from which to find selected text. + This can be bound to a scaled version of the \c centroid.position + of a \l DragHandler to end selection of text at the position where the user + is currently dragging the mouse, for example. +*/ +QPointF QQuickPdfSelection::toPoint() const +{ + return m_toPoint; +} + +void QQuickPdfSelection::setToPoint(QPointF toPoint) +{ + if (m_hold || m_toPoint == toPoint) + return; + + m_toPoint = toPoint; + emit toPointChanged(); + updateResults(); +} + +/*! + \qmlproperty bool PdfSelection::hold + + Controls whether to hold the existing selection regardless of changes to + \l fromPoint and \l toPoint. This property can be set to \c true when the mouse + or touchpoint is released, so that the selection is not lost due to the + point bindings changing. +*/ +bool QQuickPdfSelection::hold() const +{ + return m_hold; +} + +void QQuickPdfSelection::setHold(bool hold) +{ + if (m_hold == hold) + return; + + m_hold = hold; + emit holdChanged(); +} + +/*! + \qmlproperty string PdfSelection::string + + The string found. +*/ +QString QQuickPdfSelection::text() const +{ + return m_text; +} + +#if QT_CONFIG(clipboard) +/*! + \qmlmethod void PdfSelection::copyToClipboard() + + Copies plain text from the \l string property to the system clipboard. +*/ +void QQuickPdfSelection::copyToClipboard() const +{ + QGuiApplication::clipboard()->setText(m_text); +} +#endif + +void QQuickPdfSelection::updateResults() +{ + if (!m_document) + return; + QPdfSelection sel = m_document->document().getSelection(m_page, m_fromPoint, m_toPoint); + if (sel.text() != m_text) { + m_text = sel.text(); + if (QGuiApplication::clipboard()->supportsSelection()) + sel.copyToClipboard(QClipboard::Selection); + emit textChanged(); + } + + if (sel.bounds() != m_geometry) { + m_geometry = sel.bounds(); + emit geometryChanged(); + } +} + +QT_END_NAMESPACE diff --git a/src/pdf/quick/qquickpdfselection_p.h b/src/pdf/quick/qquickpdfselection_p.h new file mode 100644 index 000000000..a0e6d1a8d --- /dev/null +++ b/src/pdf/quick/qquickpdfselection_p.h @@ -0,0 +1,122 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtPDF module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQUICKPDFSELECTION_P_H +#define QQUICKPDFSELECTION_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <QPointF> +#include <QPolygonF> +#include <QVariant> +#include <QtQml/qqml.h> + +QT_BEGIN_NAMESPACE + +class QQuickPdfDocument; + +class QQuickPdfSelection : public QObject +{ + Q_OBJECT + Q_PROPERTY(QQuickPdfDocument *document READ document WRITE setDocument NOTIFY documentChanged) + Q_PROPERTY(int page READ page WRITE setPage NOTIFY pageChanged) + Q_PROPERTY(QPointF fromPoint READ fromPoint WRITE setFromPoint NOTIFY fromPointChanged) + Q_PROPERTY(QPointF toPoint READ toPoint WRITE setToPoint NOTIFY toPointChanged) + Q_PROPERTY(bool hold READ hold WRITE setHold NOTIFY holdChanged) + + Q_PROPERTY(QString text READ text NOTIFY textChanged) + Q_PROPERTY(QVector<QPolygonF> geometry READ geometry NOTIFY geometryChanged) + +public: + explicit QQuickPdfSelection(QObject *parent = nullptr); + + QQuickPdfDocument *document() const; + void setDocument(QQuickPdfDocument * document); + int page() const; + void setPage(int page); + QPointF fromPoint() const; + void setFromPoint(QPointF fromPoint); + QPointF toPoint() const; + void setToPoint(QPointF toPoint); + bool hold() const; + void setHold(bool hold); + + QString text() const; + QVector<QPolygonF> geometry() const; + +#if QT_CONFIG(clipboard) + Q_INVOKABLE void copyToClipboard() const; +#endif + +signals: + void documentChanged(); + void pageChanged(); + void fromPointChanged(); + void toPointChanged(); + void holdChanged(); + void textChanged(); + void geometryChanged(); + +private: + void resetPoints(); + void updateResults(); + +private: + QQuickPdfDocument *m_document = nullptr; + QPointF m_fromPoint; + QPointF m_toPoint; + QString m_text; + QVector<QPolygonF> m_geometry; + int m_page = 0; + bool m_hold = false; + + Q_DISABLE_COPY(QQuickPdfSelection) +}; + +QT_END_NAMESPACE + +QML_DECLARE_TYPE(QQuickPdfSelection) +\ +#endif // QQUICKPDFSELECTION_P_H diff --git a/src/pdf/quick/quick.pro b/src/pdf/quick/quick.pro index cda768369..d999ffb0b 100644 --- a/src/pdf/quick/quick.pro +++ b/src/pdf/quick/quick.pro @@ -16,10 +16,12 @@ SOURCES += \ plugin.cpp \ qquickpdfdocument.cpp \ qquickpdfsearchmodel.cpp \ + qquickpdfselection.cpp \ HEADERS += \ qquickpdfdocument_p.h \ qquickpdfsearchmodel_p.h \ + qquickpdfselection_p.h \ QT += pdf quick-private gui gui-private core core-private qml qml-private |