diff options
Diffstat (limited to 'src/pdf/quick/qquickpdfselection.cpp')
-rw-r--r-- | src/pdf/quick/qquickpdfselection.cpp | 541 |
1 files changed, 0 insertions, 541 deletions
diff --git a/src/pdf/quick/qquickpdfselection.cpp b/src/pdf/quick/qquickpdfselection.cpp deleted file mode 100644 index 23fbb80b9..000000000 --- a/src/pdf/quick/qquickpdfselection.cpp +++ /dev/null @@ -1,541 +0,0 @@ -/**************************************************************************** -** -** 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 <QGuiApplication> -#include <QLoggingCategory> -#include <QQuickItem> -#include <QQmlEngine> -#include <QRegularExpression> -#include <QStandardPaths> -#include <QtPdf/private/qpdfdocument_p.h> - -Q_LOGGING_CATEGORY(qLcIm, "qt.pdf.im") - -QT_BEGIN_NAMESPACE - -static const QRegularExpression WordDelimiter("\\s"); - -/*! - \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. - - To modify the selection using the mouse, bind \l fromPoint and \l toPoint - to the suitable properties of an input handler so that they will be set to - the positions where the drag gesture begins and ends, respectively; and - bind the \l hold property so that it will be set to \c true during the drag - gesture and \c false when the gesture ends. - - PdfSelection also directly handles Input Method queries so that text - selection handles can be used on platforms such as iOS. For this purpose, - it must have keyboard focus. -*/ - -/*! - Constructs a SearchModel. -*/ -QQuickPdfSelection::QQuickPdfSelection(QQuickItem *parent) - : QQuickItem(parent) -{ -#if QT_CONFIG(im) - setFlags(ItemIsFocusScope | ItemAcceptsInputMethod); - // workaround to get Copy instead of Paste on the popover menu (QTBUG-83811) - setProperty("qt_im_readonly", QVariant(true)); -#endif -} - -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::clear() -{ - m_hitPoint = QPointF(); - m_fromPoint = QPointF(); - m_toPoint = QPointF(); - m_heightAtAnchor = 0; - m_heightAtCursor = 0; - m_fromCharIndex = -1; - m_toCharIndex = -1; - m_text.clear(); - m_geometry.clear(); - emit fromPointChanged(); - emit toPointChanged(); - emit textChanged(); - emit selectedAreaChanged(); - QGuiApplication::inputMethod()->update(Qt::ImQueryInput); -} - -void QQuickPdfSelection::selectAll() -{ - QPdfSelection sel = m_document->m_doc.getAllText(m_page); - 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 selectedAreaChanged(); - } -#if QT_CONFIG(im) - m_fromCharIndex = sel.startIndex(); - m_toCharIndex = sel.endIndex(); - if (sel.bounds().isEmpty()) { - m_fromPoint = QPointF(); - m_toPoint = QPointF(); - } else { - m_fromPoint = sel.bounds().first().boundingRect().topLeft() * m_renderScale; - m_toPoint = sel.bounds().last().boundingRect().bottomRight() * m_renderScale - QPointF(0, m_heightAtCursor); - } - - QGuiApplication::inputMethod()->update(Qt::ImCursorRectangle | Qt::ImAnchorRectangle); -#endif -} - -#if QT_CONFIG(im) -void QQuickPdfSelection::keyReleaseEvent(QKeyEvent *ev) -{ - qCDebug(qLcIm) << "release" << ev; - const auto &allText = pageText(); - if (ev == QKeySequence::MoveToPreviousWord) { - // iOS sends MoveToPreviousWord first to get to the beginning of the word, - // and then SelectNextWord to select the whole word. - int i = allText.lastIndexOf(WordDelimiter, m_fromCharIndex - allText.length()); - if (i < 0) - i = 0; - else - i += 1; // don't select the space before the word - auto sel = m_document->m_doc.getSelectionAtIndex(m_page, i, m_text.length() + m_fromCharIndex - i); - update(sel); - QGuiApplication::inputMethod()->update(Qt::ImAnchorRectangle); - } else if (ev == QKeySequence::SelectNextWord) { - int i = allText.indexOf(WordDelimiter, m_toCharIndex); - if (i < 0) - i = allText.length(); // go to the end of m_textAfter - auto sel = m_document->m_doc.getSelectionAtIndex(m_page, m_fromCharIndex, m_text.length() + i - m_toCharIndex); - update(sel); - QGuiApplication::inputMethod()->update(Qt::ImCursorRectangle); - } else if (ev == QKeySequence::Copy) { - copyToClipboard(); - } -} - -void QQuickPdfSelection::inputMethodEvent(QInputMethodEvent *event) -{ - for (auto attr : event->attributes()) { - switch (attr.type) { - case QInputMethodEvent::Cursor: - qCDebug(qLcIm) << "QInputMethodEvent::Cursor: moved to" << attr.start << "len" << attr.length; - break; - case QInputMethodEvent::Selection: { - auto sel = m_document->m_doc.getSelectionAtIndex(m_page, attr.start, attr.length); - update(sel); - qCDebug(qLcIm) << "QInputMethodEvent::Selection: from" << attr.start << "len" << attr.length - << "result:" << m_fromCharIndex << "->" << m_toCharIndex << sel.boundingRectangle(); - // the iOS plugin decided that it wanted to change the selection, but still has to be told to move the handles (!?) - QGuiApplication::inputMethod()->update(Qt::ImCursorRectangle | Qt::ImAnchorRectangle); - break; - } - case QInputMethodEvent::Language: - case QInputMethodEvent::Ruby: - case QInputMethodEvent::TextFormat: - break; - } - } -} - -QVariant QQuickPdfSelection::inputMethodQuery(Qt::InputMethodQuery query, const QVariant &argument) const -{ - if (!argument.isNull()) { - qCDebug(qLcIm) << "IM query" << query << "with arg" << argument; - if (query == Qt::ImCursorPosition) { - // If it didn't move since last time, return the same result. - if (m_hitPoint == argument.toPointF()) - return inputMethodQuery(query); - m_hitPoint = argument.toPointF(); - auto tp = m_document->m_doc.d->hitTest(m_page, m_hitPoint / m_renderScale); - qCDebug(qLcIm) << "ImCursorPosition hit testing in px" << m_hitPoint << "pt" << (m_hitPoint / m_renderScale) - << "got char index" << tp.charIndex << "@" << tp.position << "pt," << tp.position * m_renderScale << "px"; - if (tp.charIndex >= 0) { - m_toCharIndex = tp.charIndex; - m_toPoint = tp.position * m_renderScale - QPointF(0, m_heightAtCursor); - m_heightAtCursor = tp.height * m_renderScale; - if (qFuzzyIsNull(m_heightAtAnchor)) - m_heightAtAnchor = m_heightAtCursor; - } - } - } - return inputMethodQuery(query); -} - -QVariant QQuickPdfSelection::inputMethodQuery(Qt::InputMethodQuery query) const -{ - QVariant ret; - switch (query) { - case Qt::ImEnabled: - ret = true; - break; - case Qt::ImHints: - ret = QVariant(Qt::ImhMultiLine | Qt::ImhNoPredictiveText); - break; - case Qt::ImInputItemClipRectangle: - ret = boundingRect(); - break; - case Qt::ImAnchorPosition: - ret = m_fromCharIndex; - break; - case Qt::ImAbsolutePosition: - ret = m_toCharIndex; - break; - case Qt::ImCursorPosition: - ret = m_toCharIndex; - break; - case Qt::ImAnchorRectangle: - ret = QRectF(m_fromPoint, QSizeF(1, m_heightAtAnchor)); - break; - case Qt::ImCursorRectangle: - ret = QRectF(m_toPoint, QSizeF(1, m_heightAtCursor)); - break; - case Qt::ImSurroundingText: - ret = QVariant(pageText()); - break; - case Qt::ImTextBeforeCursor: - ret = QVariant(pageText().mid(0, m_toCharIndex)); - break; - case Qt::ImTextAfterCursor: - ret = QVariant(pageText().mid(m_toCharIndex)); - break; - case Qt::ImCurrentSelection: - ret = QVariant(m_text); - break; - case Qt::ImEnterKeyType: - break; - case Qt::ImFont: { - QFont font = QGuiApplication::font(); - font.setPointSizeF(m_heightAtCursor); - ret = font; - break; - } - case Qt::ImMaximumTextLength: - break; - case Qt::ImPreferredLanguage: - break; - case Qt::ImPlatformData: - break; - case Qt::ImQueryInput: - case Qt::ImQueryAll: - qWarning() << "unexpected composite query"; - break; - } - qCDebug(qLcIm) << "IM query" << query << "returns" << ret; - return ret; -} -#endif // QT_CONFIG(im) - -const QString &QQuickPdfSelection::pageText() const -{ - if (m_pageTextDirty) { - m_pageText = m_document->m_doc.getAllText(m_page).text(); - m_pageTextDirty = false; - } - return m_pageText; -} - -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; - m_pageTextDirty = true; - emit pageChanged(); - resetPoints(); -} - -/*! - \qmlproperty real PdfSelection::renderScale - \brief The ratio from points to pixels at which the page is rendered. - - This is used to scale \l fromPoint and \l toPoint to find ranges of - selected characters in the document, because positions within the document - are always given in points. -*/ -qreal QQuickPdfSelection::renderScale() const -{ - return m_renderScale; -} - -void QQuickPdfSelection::setRenderScale(qreal scale) -{ - if (qFuzzyCompare(scale, m_renderScale)) - return; - - m_renderScale = scale; - emit renderScaleChanged(); - updateResults(); -} - -/*! - \qmlproperty point PdfSelection::fromPoint - - The beginning location, in pixels from the upper-left corner of the page, - from which to find selected text. This can be bound to 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 pixels from the upper-left corner of the page, - from which to find selected text. This can be bound to 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_renderScale, m_toPoint / m_renderScale); - update(sel, true); -} - -void QQuickPdfSelection::update(const QPdfSelection &sel, bool textAndGeometryOnly) -{ - 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 selectedAreaChanged(); - } - - if (textAndGeometryOnly) - return; - - m_fromCharIndex = sel.startIndex(); - m_toCharIndex = sel.endIndex(); - if (sel.bounds().isEmpty()) { - m_fromPoint = sel.boundingRectangle().topLeft() * m_renderScale; - m_toPoint = m_fromPoint; - } else { - Qt::InputMethodQueries toUpdate = {}; - QRectF firstLineBounds = sel.bounds().first().boundingRect(); - m_fromPoint = firstLineBounds.topLeft() * m_renderScale; - if (!qFuzzyCompare(m_heightAtAnchor, firstLineBounds.height())) { - m_heightAtAnchor = firstLineBounds.height() * m_renderScale; - toUpdate.setFlag(Qt::ImAnchorRectangle); - } - QRectF lastLineBounds = sel.bounds().last().boundingRect(); - if (!qFuzzyCompare(m_heightAtCursor, lastLineBounds.height())) { - m_heightAtCursor = lastLineBounds.height() * m_renderScale; - toUpdate.setFlag(Qt::ImCursorRectangle); - } - m_toPoint = lastLineBounds.topRight() * m_renderScale; - if (toUpdate) - QGuiApplication::inputMethod()->update(toUpdate); - } -} - -QT_END_NAMESPACE |