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
qquickpdfselection.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
6#include <QClipboard>
7#include <QGuiApplication>
8#include <QLoggingCategory>
9#include <QQuickItem>
10#include <QQmlEngine>
11#include <QRegularExpression>
12#include <QStandardPaths>
13#include <QtPdf/private/qpdfdocument_p.h>
14
15Q_LOGGING_CATEGORY(qLcIm, "qt.pdf.im")
16
18
20
24
45 : QQuickItem(parent)
46{
47#if QT_CONFIG(im)
48 setFlags(ItemIsFocusScope | ItemAcceptsInputMethod);
49#endif
50}
51
56
63{
64 return m_document;
65}
66
68{
69 if (m_document == document)
70 return;
71
72 if (m_document) {
74 this, &QQuickPdfSelection::resetPoints);
75 }
76 m_document = document;
78 resetPoints();
80 this, &QQuickPdfSelection::resetPoints);
81}
82
117QList<QPolygonF> QQuickPdfSelection::geometry() const
118{
119 return m_geometry;
120}
121
128{
129 m_hitPoint = QPointF();
130 m_from = QPointF();
131 m_to = QPointF();
132 m_heightAtAnchor = 0;
133 m_heightAtCursor = 0;
134 m_fromCharIndex = -1;
135 m_toCharIndex = -1;
136 m_text.clear();
137 m_geometry.clear();
139 emit toChanged();
143}
144
151{
152 if (!m_document)
153 return;
154 QPdfSelection sel = m_document->document()->getAllText(m_page);
155 if (sel.text() != m_text) {
156 m_text = sel.text();
157 if (QGuiApplication::clipboard()->supportsSelection())
158 sel.copyToClipboard(QClipboard::Selection);
160 }
161
162 if (sel.bounds() != m_geometry) {
163 m_geometry = sel.bounds();
165 }
166#if QT_CONFIG(im)
167 m_fromCharIndex = sel.startIndex();
168 m_toCharIndex = sel.endIndex();
169 if (sel.bounds().isEmpty()) {
170 m_from = QPointF();
171 m_to = QPointF();
172 } else {
173 m_from = sel.bounds().first().boundingRect().topLeft() * m_renderScale;
174 m_to = sel.bounds().last().boundingRect().bottomRight() * m_renderScale - QPointF(0, m_heightAtCursor);
175 }
176
178#endif
179}
180
181#if QT_CONFIG(im)
183{
184 qCDebug(qLcIm) << "release" << ev;
185 const auto &allText = pageText();
187 if (!m_document)
188 return;
189 // iOS sends MoveToPreviousWord first to get to the beginning of the word,
190 // and then SelectNextWord to select the whole word.
191 int i = allText.lastIndexOf(WordDelimiter, m_fromCharIndex - allText.size());
192 if (i < 0)
193 i = 0;
194 else
195 i += 1; // don't select the space before the word
196 auto sel = m_document->document()->getSelectionAtIndex(m_page, i, m_text.size() + m_fromCharIndex - i);
197 update(sel);
199 } else if (ev == QKeySequence::SelectNextWord) {
200 if (!m_document)
201 return;
202 int i = allText.indexOf(WordDelimiter, m_toCharIndex);
203 if (i < 0)
204 i = allText.size(); // go to the end of m_textAfter
205 auto sel = m_document->document()->getSelectionAtIndex(m_page, m_fromCharIndex, m_text.size() + i - m_toCharIndex);
206 update(sel);
208 } else if (ev == QKeySequence::Copy) {
209 copyToClipboard();
210 }
211}
212
213void QQuickPdfSelection::inputMethodEvent(QInputMethodEvent *event)
214{
215 for (auto attr : event->attributes()) {
216 switch (attr.type) {
218 qCDebug(qLcIm) << "QInputMethodEvent::Cursor: moved to" << attr.start << "len" << attr.length;
219 break;
221 if (!m_document)
222 return;
223 auto sel = m_document->document()->getSelectionAtIndex(m_page, attr.start, attr.length);
224 update(sel);
225 qCDebug(qLcIm) << "QInputMethodEvent::Selection: from" << attr.start << "len" << attr.length
226 << "result:" << m_fromCharIndex << "->" << m_toCharIndex << sel.boundingRectangle();
227 // the iOS plugin decided that it wanted to change the selection, but still has to be told to move the handles (!?)
229 break;
230 }
234 break;
235 }
236 }
237}
238
239QVariant QQuickPdfSelection::inputMethodQuery(Qt::InputMethodQuery query, const QVariant &argument) const
240{
241 if (!argument.isNull()) {
242 qCDebug(qLcIm) << "IM query" << query << "with arg" << argument;
244 if (!m_document)
245 return {};
246 // If it didn't move since last time, return the same result.
247 if (m_hitPoint == argument.toPointF())
248 return inputMethodQuery(query);
249 m_hitPoint = argument.toPointF();
250 auto tp = m_document->document()->d->hitTest(m_page, m_hitPoint / m_renderScale);
251 qCDebug(qLcIm) << "ImCursorPosition hit testing in px" << m_hitPoint << "pt" << (m_hitPoint / m_renderScale)
252 << "got char index" << tp.charIndex << "@" << tp.position << "pt," << tp.position * m_renderScale << "px";
253 if (tp.charIndex >= 0) {
254 m_toCharIndex = tp.charIndex;
255 m_to = tp.position * m_renderScale - QPointF(0, m_heightAtCursor);
256 m_heightAtCursor = tp.height * m_renderScale;
257 if (qFuzzyIsNull(m_heightAtAnchor))
258 m_heightAtAnchor = m_heightAtCursor;
259 }
260 }
261 }
262 return inputMethodQuery(query);
263}
264
265QVariant QQuickPdfSelection::inputMethodQuery(Qt::InputMethodQuery query) const
266{
268 switch (query) {
269 case Qt::ImEnabled:
270 ret = true;
271 break;
272 case Qt::ImHints:
274 break;
276 ret = boundingRect();
277 break;
279 ret = m_fromCharIndex;
280 break;
282 ret = m_toCharIndex;
283 break;
285 ret = m_toCharIndex;
286 break;
288 ret = QRectF(m_from, QSizeF(1, m_heightAtAnchor));
289 break;
291 ret = QRectF(m_to, QSizeF(1, m_heightAtCursor));
292 break;
294 ret = QVariant(pageText());
295 break;
297 ret = QVariant(pageText().mid(0, m_toCharIndex));
298 break;
300 ret = QVariant(pageText().mid(m_toCharIndex));
301 break;
303 ret = QVariant(m_text);
304 break;
306 break;
307 case Qt::ImFont: {
309 font.setPointSizeF(m_heightAtCursor);
310 ret = font;
311 break;
312 }
314 break;
316 break;
318 break;
319 case Qt::ImReadOnly:
320 ret = true;
321 break;
322 case Qt::ImQueryInput:
323 case Qt::ImQueryAll:
324 qWarning() << "unexpected composite query";
325 break;
326 }
327 qCDebug(qLcIm) << "IM query" << query << "returns" << ret;
328 return ret;
329}
330#endif // QT_CONFIG(im)
331
332const QString &QQuickPdfSelection::pageText() const
333{
334 if (m_pageTextDirty) {
335 if (!m_document)
336 return m_pageText;
337 m_pageText = m_document->document()->getAllText(m_page).text();
338 m_pageTextDirty = false;
339 }
340 return m_pageText;
341}
342
343void QQuickPdfSelection::resetPoints()
344{
345 bool wasHolding = m_hold;
346 m_hold = false;
347 setFrom(QPointF());
348 setTo(QPointF());
349 m_hold = wasHolding;
350}
351
360{
361 return m_page;
362}
363
365{
366 if (m_page == page)
367 return;
368
369 m_page = page;
370 m_pageTextDirty = true;
372 resetPoints();
373}
374
384{
385 return m_renderScale;
386}
387
389{
390 if (qFuzzyIsNull(scale)) {
391 qWarning() << "PdfSelection.renderScale cannot be set to 0.";
392 return;
393 }
394
395 if (qFuzzyCompare(scale, m_renderScale))
396 return;
397
398 m_renderScale = scale;
400 updateResults();
401}
402
413{
414 return m_from;
415}
416
418{
419 if (m_hold || m_from == from)
420 return;
421
422 m_from = from;
424 updateResults();
425}
426
436{
437 return m_to;
438}
439
441{
442 if (m_hold || m_to == to)
443 return;
444
445 m_to = to;
446 emit toChanged();
447 updateResults();
448}
449
459{
460 return m_hold;
461}
462
464{
465 if (m_hold == hold)
466 return;
467
468 m_hold = hold;
470}
471
478{
479 return m_text;
480}
481
482#if QT_CONFIG(clipboard)
488void QQuickPdfSelection::copyToClipboard() const
489{
490 QGuiApplication::clipboard()->setText(m_text);
491}
492#endif
493
494void QQuickPdfSelection::updateResults()
495{
496 if (!m_document)
497 return;
498 QPdfSelection sel = m_document->document()->getSelection(m_page,
499 m_from / m_renderScale, m_to / m_renderScale);
500 update(sel, true);
501}
502
503void QQuickPdfSelection::update(const QPdfSelection &sel, bool textAndGeometryOnly)
504{
505 if (sel.text() != m_text) {
506 m_text = sel.text();
507 if (QGuiApplication::clipboard()->supportsSelection())
508 sel.copyToClipboard(QClipboard::Selection);
510 }
511
512 if (sel.bounds() != m_geometry) {
513 m_geometry = sel.bounds();
515 }
516
517 if (textAndGeometryOnly)
518 return;
519
520 m_fromCharIndex = sel.startIndex();
521 m_toCharIndex = sel.endIndex();
522 if (sel.bounds().isEmpty()) {
523 m_from = sel.boundingRectangle().topLeft() * m_renderScale;
524 m_to = m_from;
525 } else {
526 Qt::InputMethodQueries toUpdate = {};
527 QRectF firstLineBounds = sel.bounds().first().boundingRect();
528 m_from = firstLineBounds.topLeft() * m_renderScale;
529 if (!qFuzzyCompare(m_heightAtAnchor, firstLineBounds.height())) {
530 m_heightAtAnchor = firstLineBounds.height() * m_renderScale;
531 toUpdate.setFlag(Qt::ImAnchorRectangle);
532 }
533 QRectF lastLineBounds = sel.bounds().last().boundingRect();
534 if (!qFuzzyCompare(m_heightAtCursor, lastLineBounds.height())) {
535 m_heightAtCursor = lastLineBounds.height() * m_renderScale;
536 toUpdate.setFlag(Qt::ImCursorRectangle);
537 }
538 m_to = lastLineBounds.topRight() * m_renderScale;
539 if (toUpdate)
540 QGuiApplication::inputMethod()->update(toUpdate);
541 }
542}
543
545
546#include "moc_qquickpdfselection_p.cpp"
\reentrant
Definition qfont.h:22
void setPointSizeF(qreal)
Sets the point size to pointSize.
Definition qfont.cpp:1010
static QClipboard * clipboard()
Returns the object for interacting with the clipboard.
static QFont font()
Returns the default application font.
static QInputMethod * inputMethod()
returns the input method.
The QInputMethodEvent class provides parameters for input method events.
Definition qevent.h:625
The QKeyEvent class describes a key event.
Definition qevent.h:424
void clear()
Definition qlist.h:434
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
TextPosition hitTest(int page, QPointF position)
Q_INVOKABLE QPdfSelection getAllText(int page)
Returns all the text and its bounds on the given page.
Q_INVOKABLE QPdfSelection getSelectionAtIndex(int page, int startIndex, int maxLength)
Returns information about the text on the given page that can be found beginning at the given startIn...
Q_INVOKABLE QPdfSelection getSelection(int page, QPointF start, QPointF end)
Returns information about the text on the given page that can be found between the given start and en...
The QPdfSelection class defines a range of text that has been selected on one page in a PDF document,...
QString text
This property holds the selected text.
\inmodule QtCore\reentrant
Definition qpoint.h:217
The QQuickItem class provides the most basic of all visual items in \l {Qt Quick}.
Definition qquickitem.h:63
virtual QRectF boundingRect() const
Returns the extents of the item in its own coordinate system: a rectangle from {0,...
virtual void keyReleaseEvent(QKeyEvent *event)
This event handler can be reimplemented in a subclass to receive key release events for an item.
qreal scale
\qmlproperty real QtQuick::Item::scale This property holds the scale factor for this item.
Definition qquickitem.h:107
void update()
Schedules a call to updatePaintNode() for this item.
void setFrom(QPointF from)
void setDocument(QQuickPdfDocument *document)
Q_INVOKABLE void clear()
\qmlmethod void PdfSelection::clear()
Q_INVOKABLE void selectAll()
\qmlmethod void PdfSelection::selectAll()
QList< QPolygonF > geometry
QQuickPdfDocument * document
~QQuickPdfSelection() override
void setRenderScale(qreal scale)
void selectedAreaChanged()
\inmodule QtCore\reentrant
Definition qrect.h:484
\inmodule QtCore \reentrant
\inmodule QtCore
Definition qsize.h:208
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
void clear()
Clears the contents of the string and makes it null.
Definition qstring.h:1252
qsizetype size() const noexcept
Returns the number of characters in this string.
Definition qstring.h:186
\inmodule QtCore
Definition qvariant.h:65
Combined button and popup list for selecting options.
InputMethodQuery
@ ImMaximumTextLength
@ ImTextBeforeCursor
@ ImAnchorRectangle
@ ImPlatformData
@ ImSurroundingText
@ ImInputItemClipRectangle
@ ImCursorPosition
@ ImEnterKeyType
@ ImCurrentSelection
@ ImAbsolutePosition
@ ImReadOnly
@ ImPreferredLanguage
@ ImFont
@ ImAnchorPosition
@ ImCursorRectangle
@ ImHints
@ ImQueryInput
@ ImEnabled
@ ImTextAfterCursor
@ ImQueryAll
@ ImhMultiLine
@ ImhNoPredictiveText
bool qFuzzyCompare(qfloat16 p1, qfloat16 p2) noexcept
Definition qfloat16.h:333
bool qFuzzyIsNull(qfloat16 f) noexcept
Definition qfloat16.h:349
#define qWarning
Definition qlogging.h:166
#define Q_LOGGING_CATEGORY(name,...)
#define qCDebug(category,...)
return ret
struct _cl_event * event
GLdouble s
[6]
Definition qopenglext.h:235
GLenum query
GLenum GLenum GLenum GLenum GLenum scale
static QT_BEGIN_NAMESPACE const QRegularExpression WordDelimiter(QStringLiteral("\\s"))
#define QStringLiteral(str)
#define emit
double qreal
Definition qtypes.h:187
myObject disconnect()
[26]
QByteArray page
[45]
QDBusArgument argument