70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
94
95
96
97
98
99
105#if !defined(QQUICKTEXT_LARGETEXT_THRESHOLD)
106 #define QQUICKTEXT_LARGETEXT_THRESHOLD 10000
112 class RootNode :
public QSGTransformNode
115 RootNode() : cursorNode(
nullptr), frameDecorationsNode(
nullptr)
118 void resetFrameDecorations(QSGInternalTextNode* newNode)
120 if (frameDecorationsNode) {
121 removeChildNode(frameDecorationsNode);
122 delete frameDecorationsNode;
124 frameDecorationsNode = newNode;
125 newNode->setFlag(QSGNode::OwnedByParent);
128 void resetCursorNode(QSGInternalRectangleNode* newNode)
131 removeChildNode(cursorNode);
133 cursorNode = newNode;
135 appendChildNode(cursorNode);
136 cursorNode->setFlag(QSGNode::OwnedByParent);
140 QSGInternalRectangleNode *cursorNode;
141 QSGInternalTextNode* frameDecorationsNode;
146QQuickTextEdit::QQuickTextEdit(QQuickItem *parent)
147: QQuickImplicitSizeItem(*(
new QQuickTextEditPrivate), parent)
153QQuickTextEdit::~QQuickTextEdit()
156 qDeleteAll(d->pixmapsInProgress);
159QQuickTextEdit::QQuickTextEdit(QQuickTextEditPrivate &dd, QQuickItem *parent)
160: QQuickImplicitSizeItem(dd, parent)
166QString QQuickTextEdit::text()
const
168 Q_D(
const QQuickTextEdit);
169 if (!d->textCached && isComponentComplete()) {
170 QQuickTextEditPrivate *d =
const_cast<QQuickTextEditPrivate *>(d_func());
171#if QT_CONFIG(texthtmlparser)
173 d->text = d->control->toHtml();
176#if QT_CONFIG(textmarkdownwriter)
178 d->text = d->control->toMarkdown();
181 d->text = d->control->toPlainText();
182 d->textCached =
true;
188
189
190
191
192
193
196
197
198
199
200
201
202
203
207
208
209
210
213
214
215
216
219
220
221
222
225
226
227
228
231
232
233
234
237
238
239
240
243
244
245
246
247
248
249
250
253
254
255
256
257
258
261
262
263
264
265
266
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
286
287
288
289
290
291
292
295
296
297
298
299
302
303
304
305
306
309
310
311
312
313
316
317
318
319
320
323
324
325
326
327
330
331
332
333
334
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365void QQuickTextEdit::setText(
const QString &text)
368 if (QQuickTextEdit::text() == text)
371 d->richText = d->format == RichText || (d->format == AutoText && Qt::mightBeRichText(text));
372 d->markdownText = d->format == MarkdownText;
373 if (!isComponentComplete()) {
375 }
else if (d->richText) {
376#if QT_CONFIG(texthtmlparser)
377 d->control->setHtml(text);
379 d->control->setPlainText(text);
381 }
else if (d->markdownText) {
382 d->control->setMarkdownText(text);
384 d->control->setPlainText(text);
386 setFlag(QQuickItem::ItemObservesViewport, text.size() > QQuickTextEditPrivate::largeTextSizeThreshold);
389void QQuickTextEdit::invalidate()
391 QMetaObject::invokeMethod(
this, &QQuickTextEdit::q_invalidate);
394void QQuickTextEdit::q_invalidate()
397 if (isComponentComplete()) {
398 if (d->document !=
nullptr)
399 d->document->markContentsDirty(0, d->document->characterCount());
400 invalidateFontCaches();
401 d->updateType = QQuickTextEditPrivate::UpdateAll;
407
408
409
410
411
412
413
414
415
416
417
418QString QQuickTextEdit::preeditText()
const
420 Q_D(
const QQuickTextEdit);
421 return d->control->preeditText();
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479QQuickTextEdit::TextFormat QQuickTextEdit::textFormat()
const
481 Q_D(
const QQuickTextEdit);
485void QQuickTextEdit::setTextFormat(TextFormat format)
488 if (format == d->format)
491 auto mightBeRichText = [
this]() {
492 return Qt::mightBeRichText(text());
495 auto findSourceFormat = [d, mightBeRichText](Qt::TextFormat detectedFormat) {
496 if (d->format == PlainText)
498 if (d->richText)
return RichText;
499 if (d->markdownText)
return MarkdownText;
500 if (detectedFormat == Qt::AutoText && mightBeRichText())
505 auto findDestinationFormat = [format, mightBeRichText](Qt::TextFormat detectedFormat, TextFormat sourceFormat) {
506 if (format == AutoText) {
507 if (detectedFormat == Qt::MarkdownText || (detectedFormat == Qt::AutoText && sourceFormat == MarkdownText))
509 if (detectedFormat == Qt::RichText || (detectedFormat == Qt::AutoText && (sourceFormat == RichText || mightBeRichText())))
516 bool textCachedChanged =
false;
517 bool converted =
false;
519 if (isComponentComplete()) {
520 Qt::TextFormat detectedFormat = Qt::AutoText;
521 if (d->quickDocument) {
524 detectedFormat = QQuickTextDocumentPrivate::get(d->quickDocument)->detectedFormat;
527 const TextFormat sourceFormat = findSourceFormat(detectedFormat);
528 const TextFormat destinationFormat = findDestinationFormat(detectedFormat, sourceFormat);
530 d->richText = destinationFormat == RichText;
531 d->markdownText = destinationFormat == MarkdownText;
534 if (format != PlainText && (sourceFormat != destinationFormat)) {
535 d->textCached =
false;
536 textCachedChanged =
true;
539 switch (destinationFormat) {
541#if QT_CONFIG(texthtmlparser)
542 if (sourceFormat == RichText) {
546 d->control->setPlainText(d->textCached ? d->text : d->control->toHtml());
550#if QT_CONFIG(textmarkdownwriter) && QT_CONFIG(textmarkdownreader)
551 if (sourceFormat == MarkdownText) {
555 d->control->setPlainText(d->textCached ? d->text : d->control->toMarkdown());
561#if QT_CONFIG(texthtmlparser)
562 switch (sourceFormat) {
565 d->control->setHtml(d->control->toHtml());
571 d->control->setHtml(d->textCached ? d->text : d->control->toPlainText());
581#if QT_CONFIG(textmarkdownwriter) && QT_CONFIG(textmarkdownreader)
582 switch (sourceFormat) {
585 d->control->setMarkdownText(d->control->toMarkdown());
591 d->control->setMarkdownText(d->textCached ? d->text : d->control->toPlainText());
607 d->richText = format == RichText || (format == AutoText && (d->richText || mightBeRichText()));
608 d->markdownText = format == MarkdownText;
611 qCDebug(lcTextEdit) << d->format <<
"->" << format
612 <<
"rich?" << d->richText <<
"md?" << d->markdownText
613 <<
"converted?" << converted <<
"cache invalidated?" << textCachedChanged;
616 d->control->setAcceptRichText(d->format != PlainText);
617 emit textFormatChanged(d->format);
618 if (textCachedChanged)
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647QQuickTextEdit::RenderType QQuickTextEdit::renderType()
const
649 Q_D(
const QQuickTextEdit);
650 return d->renderType;
653void QQuickTextEdit::setRenderType(QQuickTextEdit::RenderType renderType)
656 if (d->renderType == renderType)
659 d->renderType = renderType;
660 emit renderTypeChanged();
661 d->updateDefaultTextOption();
663 if (isComponentComplete())
667QFont QQuickTextEdit::font()
const
669 Q_D(
const QQuickTextEdit);
670 return d->sourceFont;
673void QQuickTextEdit::setFont(
const QFont &font)
676 if (d->sourceFont == font)
679 d->sourceFont = font;
680 QFont oldFont = d->font;
682 if (d->font.pointSizeF() != -1) {
684 qreal size = qRound(d->font.pointSizeF()*2.0);
685 d->font.setPointSizeF(size/2.0);
688 if (oldFont != d->font) {
689 d->document->setDefaultFont(d->font);
691 d->cursorItem->setHeight(QFontMetrics(d->font).height());
692 moveCursorDelegate();
695 updateWholeDocument();
697 updateInputMethod(Qt::ImCursorRectangle | Qt::ImAnchorRectangle | Qt::ImFont);
700 emit fontChanged(d->sourceFont);
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718QColor QQuickTextEdit::color()
const
720 Q_D(
const QQuickTextEdit);
724void QQuickTextEdit::setColor(
const QColor &color)
727 if (d->color == color)
731 updateWholeDocument();
732 emit colorChanged(d->color);
736
737
738
739
740QColor QQuickTextEdit::selectionColor()
const
742 Q_D(
const QQuickTextEdit);
743 return d->selectionColor;
746void QQuickTextEdit::setSelectionColor(
const QColor &color)
749 if (d->selectionColor == color)
752 d->selectionColor = color;
753 updateWholeDocument();
754 emit selectionColorChanged(d->selectionColor);
758
759
760
761
762QColor QQuickTextEdit::selectedTextColor()
const
764 Q_D(
const QQuickTextEdit);
765 return d->selectedTextColor;
768void QQuickTextEdit::setSelectedTextColor(
const QColor &color)
771 if (d->selectedTextColor == color)
774 d->selectedTextColor = color;
775 updateWholeDocument();
776 emit selectedTextColorChanged(d->selectedTextColor);
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811QQuickTextEdit::HAlignment QQuickTextEdit::hAlign()
const
813 Q_D(
const QQuickTextEdit);
817void QQuickTextEdit::setHAlign(HAlignment align)
821 if (d->setHAlign(align,
true) && isComponentComplete()) {
822 d->updateDefaultTextOption();
824 updateWholeDocument();
825 moveCursorDelegate();
829void QQuickTextEdit::resetHAlign()
832 d->hAlignImplicit =
true;
833 if (d->determineHorizontalAlignment() && isComponentComplete()) {
834 d->updateDefaultTextOption();
836 updateWholeDocument();
837 moveCursorDelegate();
841QQuickTextEdit::HAlignment QQuickTextEdit::effectiveHAlign()
const
843 Q_D(
const QQuickTextEdit);
844 QQuickTextEdit::HAlignment effectiveAlignment = d->hAlign;
845 if (!d->hAlignImplicit && d->effectiveLayoutMirror) {
847 case QQuickTextEdit::AlignLeft:
848 effectiveAlignment = QQuickTextEdit::AlignRight;
850 case QQuickTextEdit::AlignRight:
851 effectiveAlignment = QQuickTextEdit::AlignLeft;
857 return effectiveAlignment;
860bool QQuickTextEditPrivate::setHAlign(QQuickTextEdit::HAlignment align,
bool forceAlign)
863 if (hAlign == align && !forceAlign)
866 const bool wasImplicit = hAlignImplicit;
867 const auto oldEffectiveHAlign = q->effectiveHAlign();
869 hAlignImplicit = !forceAlign;
870 if (hAlign != align) {
872 emit q->horizontalAlignmentChanged(align);
875 if (q->effectiveHAlign() != oldEffectiveHAlign) {
876 emit q->effectiveHorizontalAlignmentChanged();
880 if (forceAlign && wasImplicit) {
883 emit q->effectiveHorizontalAlignmentChanged();
888Qt::LayoutDirection QQuickTextEditPrivate::textDirection(
const QString &text)
const
890 const QChar *character = text.constData();
891 while (!character->isNull()) {
892 switch (character->direction()) {
894 return Qt::LeftToRight;
898 return Qt::RightToLeft;
904 return Qt::LayoutDirectionAuto;
907bool QQuickTextEditPrivate::determineHorizontalAlignment()
910 if (!hAlignImplicit || !q->isComponentComplete())
913 Qt::LayoutDirection direction = contentDirection;
915 if (direction == Qt::LayoutDirectionAuto) {
916 QTextBlock block = control->textCursor().block();
919 direction = textDirection(block.layout()->preeditAreaText());
921 if (direction == Qt::LayoutDirectionAuto)
922 direction = qGuiApp->inputMethod()->inputDirection();
925 const auto implicitHAlign = direction == Qt::RightToLeft ?
926 QQuickTextEdit::AlignRight : QQuickTextEdit::AlignLeft;
927 return setHAlign(implicitHAlign);
930void QQuickTextEditPrivate::mirrorChange()
933 if (q->isComponentComplete()) {
934 if (!hAlignImplicit && (hAlign == QQuickTextEdit::AlignRight || hAlign == QQuickTextEdit::AlignLeft)) {
935 updateDefaultTextOption();
937 q->updateWholeDocument();
938 emit q->effectiveHorizontalAlignmentChanged();
943bool QQuickTextEditPrivate::transformChanged(QQuickItem *transformedItem)
946 qCDebug(lcVP) << q <<
"sees that" << transformedItem <<
"moved in VP" << q->clipRect();
951 if (flags & QQuickItem::ItemObservesViewport) {
952 if (QQuickItem *viewport = q->viewportItem()) {
953 QRectF vp = q->mapRectFromItem(viewport, viewport->clipRect());
954 if (!(vp.top() > renderedRegion.top() && vp.bottom() < renderedRegion.bottom())) {
955 qCDebug(lcVP) <<
"viewport" << vp <<
"now goes beyond rendered region" << renderedRegion <<
"; updating";
956 q->updateWholeDocument();
958 const bool textCursorVisible = cursorVisible && q->cursorRectangle().intersects(vp);
960 cursorItem->setVisible(textCursorVisible);
962 control->setCursorVisible(textCursorVisible);
965 return QQuickImplicitSizeItemPrivate::transformChanged(transformedItem);
969Qt::InputMethodHints QQuickTextEditPrivate::effectiveInputMethodHints()
const
971 return inputMethodHints | Qt::ImhMultiLine;
975#if QT_CONFIG(accessibility)
976void QQuickTextEditPrivate::accessibilityActiveChanged(
bool active)
982 if (QQuickAccessibleAttached *accessibleAttached = qobject_cast<QQuickAccessibleAttached *>(
983 qmlAttachedPropertiesObject<QQuickAccessibleAttached>(q,
true))) {
984 accessibleAttached->setRole(effectiveAccessibleRole());
985 accessibleAttached->set_readOnly(q->isReadOnly());
989QAccessible::Role QQuickTextEditPrivate::accessibleRole()
const
991 return QAccessible::EditableText;
995void QQuickTextEditPrivate::setTopPadding(qreal value,
bool reset)
998 qreal oldPadding = q->topPadding();
999 if (!reset || extra.isAllocated()) {
1000 extra.value().topPadding = value;
1001 extra.value().explicitTopPadding = !reset;
1003 if ((!reset && !qFuzzyCompare(oldPadding, value)) || (reset && !qFuzzyCompare(oldPadding, padding()))) {
1005 q->updateWholeDocument();
1006 emit q->topPaddingChanged();
1010void QQuickTextEditPrivate::setLeftPadding(qreal value,
bool reset)
1012 Q_Q(QQuickTextEdit);
1013 qreal oldPadding = q->leftPadding();
1014 if (!reset || extra.isAllocated()) {
1015 extra.value().leftPadding = value;
1016 extra.value().explicitLeftPadding = !reset;
1018 if ((!reset && !qFuzzyCompare(oldPadding, value)) || (reset && !qFuzzyCompare(oldPadding, padding()))) {
1020 q->updateWholeDocument();
1021 emit q->leftPaddingChanged();
1025void QQuickTextEditPrivate::setRightPadding(qreal value,
bool reset)
1027 Q_Q(QQuickTextEdit);
1028 qreal oldPadding = q->rightPadding();
1029 if (!reset || extra.isAllocated()) {
1030 extra.value().rightPadding = value;
1031 extra.value().explicitRightPadding = !reset;
1033 if ((!reset && !qFuzzyCompare(oldPadding, value)) || (reset && !qFuzzyCompare(oldPadding, padding()))) {
1035 q->updateWholeDocument();
1036 emit q->rightPaddingChanged();
1040void QQuickTextEditPrivate::setBottomPadding(qreal value,
bool reset)
1042 Q_Q(QQuickTextEdit);
1043 qreal oldPadding = q->bottomPadding();
1044 if (!reset || extra.isAllocated()) {
1045 extra.value().bottomPadding = value;
1046 extra.value().explicitBottomPadding = !reset;
1048 if ((!reset && !qFuzzyCompare(oldPadding, value)) || (reset && !qFuzzyCompare(oldPadding, padding()))) {
1050 q->updateWholeDocument();
1051 emit q->bottomPaddingChanged();
1055bool QQuickTextEditPrivate::isImplicitResizeEnabled()
const
1057 return !extra.isAllocated() || extra->implicitResize;
1060void QQuickTextEditPrivate::setImplicitResizeEnabled(
bool enabled)
1063 extra.value().implicitResize =
false;
1064 else if (extra.isAllocated())
1065 extra->implicitResize =
true;
1068QQuickTextEdit::VAlignment QQuickTextEdit::vAlign()
const
1070 Q_D(
const QQuickTextEdit);
1074void QQuickTextEdit::setVAlign(QQuickTextEdit::VAlignment alignment)
1076 Q_D(QQuickTextEdit);
1077 if (alignment == d->vAlign)
1079 d->vAlign = alignment;
1080 d->updateDefaultTextOption();
1082 updateWholeDocument();
1083 moveCursorDelegate();
1084 emit verticalAlignmentChanged(d->vAlign);
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107QQuickTextEdit::WrapMode QQuickTextEdit::wrapMode()
const
1109 Q_D(
const QQuickTextEdit);
1113void QQuickTextEdit::setWrapMode(WrapMode mode)
1115 Q_D(QQuickTextEdit);
1116 if (mode == d->wrapMode)
1119 d->updateDefaultTextOption();
1121 emit wrapModeChanged();
1125
1126
1127
1128
1129int QQuickTextEdit::lineCount()
const
1131 Q_D(
const QQuickTextEdit);
1132 return d->lineCount;
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1147int QQuickTextEdit::length()
const
1149 Q_D(
const QQuickTextEdit);
1151 return qMax(0, d->document->characterCount() - 1);
1155
1156
1157
1158
1159
1160qreal QQuickTextEdit::contentWidth()
const
1162 Q_D(
const QQuickTextEdit);
1163 return d->contentSize.width();
1167
1168
1169
1170
1171
1172qreal QQuickTextEdit::contentHeight()
const
1174 Q_D(
const QQuickTextEdit);
1175 return d->contentSize.height();
1179
1180
1181
1182
1183
1184
1185
1187QUrl QQuickTextEdit::baseUrl()
const
1189 Q_D(
const QQuickTextEdit);
1190 if (d->baseUrl.isEmpty()) {
1191 if (QQmlContext *context = qmlContext(
this))
1192 const_cast<QQuickTextEditPrivate *>(d)->baseUrl = context->baseUrl();
1197void QQuickTextEdit::setBaseUrl(
const QUrl &url)
1199 Q_D(QQuickTextEdit);
1200 if (baseUrl() != url) {
1203 d->document->setBaseUrl(url);
1204 emit baseUrlChanged();
1208void QQuickTextEdit::resetBaseUrl()
1210 if (QQmlContext *context = qmlContext(
this))
1211 setBaseUrl(context->baseUrl());
1217
1218
1219
1220
1221
1222
1223QRectF QQuickTextEdit::positionToRectangle(
int pos)
const
1225 Q_D(
const QQuickTextEdit);
1226 QTextCursor c(d->document);
1228 return d->control->cursorRect(c).translated(d->xoff, d->yoff);
1233
1234
1235
1236
1237
1238
1239
1240int QQuickTextEdit::positionAt(qreal x, qreal y)
const
1242 Q_D(
const QQuickTextEdit);
1246 int r = d->document->documentLayout()->hitTest(QPointF(x, y), Qt::FuzzyHit);
1248 QTextCursor cursor = d->control->textCursor();
1249 if (r > cursor.position()) {
1253 QTextLayout *layout = cursor.block().layout();
1254 const int preeditLength = layout
1255 ? layout->preeditAreaText().size()
1257 if (preeditLength > 0
1258 && d->document->documentLayout()->blockBoundingRect(cursor.block()).contains(x, y)) {
1259 r = r > cursor.position() + preeditLength
1261 : cursor.position();
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278QQuickTextSelection *QQuickTextEdit::cursorSelection()
const
1280 Q_D(
const QQuickTextEdit);
1281 if (!d->cursorSelection)
1282 d->cursorSelection =
new QQuickTextSelection(
const_cast<QQuickTextEdit *>(
this));
1283 return d->cursorSelection;
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322void QQuickTextEdit::moveCursorSelection(
int pos)
1325 Q_D(QQuickTextEdit);
1326 QTextCursor cursor = d->control->textCursor();
1327 if (cursor.position() == pos)
1329 cursor.setPosition(pos, QTextCursor::KeepAnchor);
1330 d->control->setTextCursor(cursor);
1333void QQuickTextEdit::moveCursorSelection(
int pos, SelectionMode mode)
1335 Q_D(QQuickTextEdit);
1336 QTextCursor cursor = d->control->textCursor();
1337 if (cursor.position() == pos)
1339 if (mode == SelectCharacters) {
1340 cursor.setPosition(pos, QTextCursor::KeepAnchor);
1341 }
else if (cursor.anchor() < pos || (cursor.anchor() == pos && cursor.position() < pos)) {
1342 if (cursor.anchor() > cursor.position()) {
1343 cursor.setPosition(cursor.anchor(), QTextCursor::MoveAnchor);
1344 cursor.movePosition(QTextCursor::StartOfWord, QTextCursor::KeepAnchor);
1345 if (cursor.position() == cursor.anchor())
1346 cursor.movePosition(QTextCursor::PreviousWord, QTextCursor::MoveAnchor);
1348 cursor.setPosition(cursor.position(), QTextCursor::MoveAnchor);
1350 cursor.setPosition(cursor.anchor(), QTextCursor::MoveAnchor);
1351 cursor.movePosition(QTextCursor::StartOfWord, QTextCursor::MoveAnchor);
1354 cursor.setPosition(pos, QTextCursor::KeepAnchor);
1355 cursor.movePosition(QTextCursor::StartOfWord, QTextCursor::KeepAnchor);
1356 if (cursor.position() != pos)
1357 cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor);
1358 }
else if (cursor.anchor() > pos || (cursor.anchor() == pos && cursor.position() > pos)) {
1359 if (cursor.anchor() < cursor.position()) {
1360 cursor.setPosition(cursor.anchor(), QTextCursor::MoveAnchor);
1361 cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::MoveAnchor);
1363 cursor.setPosition(cursor.anchor(), QTextCursor::MoveAnchor);
1364 cursor.movePosition(QTextCursor::PreviousCharacter, QTextCursor::KeepAnchor);
1365 cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor);
1366 if (cursor.position() != cursor.anchor()) {
1367 cursor.setPosition(cursor.anchor(), QTextCursor::MoveAnchor);
1368 cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::MoveAnchor);
1372 cursor.setPosition(pos, QTextCursor::KeepAnchor);
1373 cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor);
1374 if (cursor.position() != pos) {
1375 cursor.movePosition(QTextCursor::PreviousCharacter, QTextCursor::KeepAnchor);
1376 cursor.movePosition(QTextCursor::StartOfWord, QTextCursor::KeepAnchor);
1379 d->control->setTextCursor(cursor);
1383
1384
1385
1386
1387
1388
1389bool QQuickTextEdit::isCursorVisible()
const
1391 Q_D(
const QQuickTextEdit);
1392 return d->cursorVisible;
1395void QQuickTextEdit::setCursorVisible(
bool on)
1397 Q_D(QQuickTextEdit);
1398 if (d->cursorVisible == on)
1400 d->cursorVisible = on;
1401 if (on && isComponentComplete())
1402 QQuickTextUtil::createCursor(d);
1403 if (!on && !d->persistentSelection)
1404 d->control->setCursorIsFocusIndicator(
true);
1405 d->control->setCursorVisible(on);
1406 emit cursorVisibleChanged(d->cursorVisible);
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421int QQuickTextEdit::cursorPosition()
const
1423 Q_D(
const QQuickTextEdit);
1424 return d->control->textCursor().position();
1427void QQuickTextEdit::setCursorPosition(
int pos)
1429 Q_D(QQuickTextEdit);
1430 if (pos < 0 || pos >= d->document->characterCount())
1432 QTextCursor cursor = d->control->textCursor();
1433 if (cursor.position() == pos && cursor.anchor() == pos)
1435 cursor.setPosition(pos);
1436 d->control->setTextCursor(cursor);
1437 d->control->updateCursorRectangle(
true);
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453QQmlComponent* QQuickTextEdit::cursorDelegate()
const
1455 Q_D(
const QQuickTextEdit);
1456 return d->cursorComponent;
1459void QQuickTextEdit::setCursorDelegate(QQmlComponent* c)
1461 Q_D(QQuickTextEdit);
1462 QQuickTextUtil::setCursorDelegate(d, c);
1465void QQuickTextEdit::createCursor()
1467 Q_D(QQuickTextEdit);
1468 d->cursorPending =
true;
1469 QQuickTextUtil::createCursor(d);
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482int QQuickTextEdit::selectionStart()
const
1484 Q_D(
const QQuickTextEdit);
1485 return d->control->textCursor().selectionStart();
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498int QQuickTextEdit::selectionEnd()
const
1500 Q_D(
const QQuickTextEdit);
1501 return d->control->textCursor().selectionEnd();
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518QString QQuickTextEdit::selectedText()
const
1520 Q_D(
const QQuickTextEdit);
1521#if QT_CONFIG(texthtmlparser)
1522 return d->richText || d->markdownText
1523 ? d->control->textCursor().selectedText()
1524 : d->control->textCursor().selection().toPlainText();
1526 return d->control->textCursor().selection().toPlainText();
1531
1532
1533
1534
1535
1536bool QQuickTextEdit::focusOnPress()
const
1538 Q_D(
const QQuickTextEdit);
1539 return d->focusOnPress;
1542void QQuickTextEdit::setFocusOnPress(
bool on)
1544 Q_D(QQuickTextEdit);
1545 if (d->focusOnPress == on)
1547 d->focusOnPress = on;
1548 emit activeFocusOnPressChanged(d->focusOnPress);
1552
1553
1554
1555
1556
1557bool QQuickTextEdit::persistentSelection()
const
1559 Q_D(
const QQuickTextEdit);
1560 return d->persistentSelection;
1563void QQuickTextEdit::setPersistentSelection(
bool on)
1565 Q_D(QQuickTextEdit);
1566 if (d->persistentSelection == on)
1568 d->persistentSelection = on;
1569 emit persistentSelectionChanged(d->persistentSelection);
1573
1574
1575
1576
1577qreal QQuickTextEdit::textMargin()
const
1579 Q_D(
const QQuickTextEdit);
1580 return d->textMargin;
1583void QQuickTextEdit::setTextMargin(qreal margin)
1585 Q_D(QQuickTextEdit);
1586 if (d->textMargin == margin)
1588 d->textMargin = margin;
1589 d->document->setDocumentMargin(d->textMargin);
1590 emit textMarginChanged(d->textMargin);
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1630Qt::InputMethodHints QQuickTextEdit::inputMethodHints()
const
1635 Q_D(
const QQuickTextEdit);
1636 return d->inputMethodHints;
1640void QQuickTextEdit::setInputMethodHints(Qt::InputMethodHints hints)
1645 Q_D(QQuickTextEdit);
1647 if (hints == d->inputMethodHints)
1650 d->inputMethodHints = hints;
1651 updateInputMethod(Qt::ImHints);
1652 emit inputMethodHintsChanged();
1656void QQuickTextEdit::geometryChange(
const QRectF &newGeometry,
const QRectF &oldGeometry)
1658 Q_D(QQuickTextEdit);
1659 if (!d->inLayout && ((newGeometry.width() != oldGeometry.width())
1660 || (newGeometry.height() != oldGeometry.height()))) {
1662 updateWholeDocument();
1663 if (widthValid() || heightValid())
1664 moveCursorDelegate();
1666 QQuickImplicitSizeItem::geometryChange(newGeometry, oldGeometry);
1669void QQuickTextEdit::itemChange(ItemChange change,
const ItemChangeData &value)
1671 Q_D(QQuickTextEdit);
1674 case ItemDevicePixelRatioHasChanged:
1675 if (d->containsUnscalableGlyphs) {
1680 updateWholeDocument();
1687 QQuickImplicitSizeItem::itemChange(change, value);
1691
1692
1693
1694void QQuickTextEdit::componentComplete()
1696 Q_D(QQuickTextEdit);
1697 QQuickImplicitSizeItem::componentComplete();
1699 const QUrl url = baseUrl();
1700 const QQmlContext *context = qmlContext(
this);
1701 d->document->setBaseUrl(context ? context->resolvedUrl(url) : url);
1702 if (!d->text.isEmpty()) {
1703#if QT_CONFIG(texthtmlparser)
1705 d->control->setHtml(d->text);
1708#if QT_CONFIG(textmarkdownreader)
1709 if (d->markdownText)
1710 d->control->setMarkdownText(d->text);
1713 d->control->setPlainText(d->text);
1717 d->determineHorizontalAlignment();
1718 d->updateDefaultTextOption();
1722 if (d->cursorComponent && isCursorVisible())
1723 QQuickTextUtil::createCursor(d);
1726#if QT_CONFIG(accessibility)
1727 if (QAccessible::isActive())
1728 d->accessibilityActiveChanged(
true);
1732int QQuickTextEdit::resourcesLoading()
const
1734 Q_D(
const QQuickTextEdit);
1735 return d->pixmapsInProgress.size();
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752bool QQuickTextEdit::selectByKeyboard()
const
1754 Q_D(
const QQuickTextEdit);
1755 if (d->selectByKeyboardSet)
1756 return d->selectByKeyboard;
1757 return !isReadOnly();
1760void QQuickTextEdit::setSelectByKeyboard(
bool on)
1762 Q_D(QQuickTextEdit);
1763 bool was = selectByKeyboard();
1764 if (!d->selectByKeyboardSet || was != on) {
1765 d->selectByKeyboardSet =
true;
1766 d->selectByKeyboard = on;
1768 d->control->setTextInteractionFlags(d->control->textInteractionFlags() | Qt::TextSelectableByKeyboard);
1770 d->control->setTextInteractionFlags(d->control->textInteractionFlags() & ~Qt::TextSelectableByKeyboard);
1771 emit selectByKeyboardChanged(on);
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798bool QQuickTextEdit::selectByMouse()
const
1800 Q_D(
const QQuickTextEdit);
1801 return d->selectByMouse;
1804void QQuickTextEdit::setSelectByMouse(
bool on)
1806 Q_D(QQuickTextEdit);
1807 if (d->selectByMouse == on)
1810 d->selectByMouse = on;
1811 setKeepMouseGrab(on);
1813 d->control->setTextInteractionFlags(d->control->textInteractionFlags() | Qt::TextSelectableByMouse);
1815 d->control->setTextInteractionFlags(d->control->textInteractionFlags() & ~Qt::TextSelectableByMouse);
1817#if QT_CONFIG(cursor)
1818 d->updateMouseCursorShape();
1820 emit selectByMouseChanged(on);
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833QQuickTextEdit::SelectionMode QQuickTextEdit::mouseSelectionMode()
const
1835 Q_D(
const QQuickTextEdit);
1836 return d->mouseSelectionMode;
1839void QQuickTextEdit::setMouseSelectionMode(SelectionMode mode)
1841 Q_D(QQuickTextEdit);
1842 if (d->mouseSelectionMode != mode) {
1843 d->mouseSelectionMode = mode;
1844 d->control->setWordSelectionEnabled(mode == SelectWords);
1845 emit mouseSelectionModeChanged(mode);
1850
1851
1852
1853
1854
1855
1856
1857void QQuickTextEdit::setReadOnly(
bool r)
1859 Q_D(QQuickTextEdit);
1860 if (r == isReadOnly())
1864 setFlag(QQuickItem::ItemAcceptsInputMethod, !r);
1866 Qt::TextInteractionFlags flags = Qt::LinksAccessibleByMouse;
1867 if (d->selectByMouse)
1868 flags = flags | Qt::TextSelectableByMouse;
1869 if (d->selectByKeyboardSet && d->selectByKeyboard)
1870 flags = flags | Qt::TextSelectableByKeyboard;
1871 else if (!d->selectByKeyboardSet && !r)
1872 flags = flags | Qt::TextSelectableByKeyboard;
1874 flags = flags | Qt::TextEditable;
1875 d->control->setTextInteractionFlags(flags);
1876 d->control->moveCursor(QTextCursor::End);
1879 updateInputMethod(Qt::ImEnabled);
1881#if QT_CONFIG(cursor)
1882 d->updateMouseCursorShape();
1884 q_canPasteChanged();
1885 emit readOnlyChanged(r);
1886 if (!d->selectByKeyboardSet)
1887 emit selectByKeyboardChanged(!r);
1889 setCursorVisible(
false);
1890 }
else if (hasActiveFocus()) {
1891 setCursorVisible(
true);
1894#if QT_CONFIG(accessibility)
1895 if (QAccessible::isActive()) {
1896 if (QQuickAccessibleAttached *accessibleAttached = QQuickAccessibleAttached::attachedProperties(
this))
1897 accessibleAttached->set_readOnly(r);
1902bool QQuickTextEdit::isReadOnly()
const
1904 Q_D(
const QQuickTextEdit);
1905 return !(d->control->textInteractionFlags() & Qt::TextEditable);
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918QRectF QQuickTextEdit::cursorRectangle()
const
1920 Q_D(
const QQuickTextEdit);
1921 return d->control->cursorRect().translated(d->xoff, d->yoff);
1924bool QQuickTextEdit::event(QEvent *event)
1926 Q_D(QQuickTextEdit);
1927 bool state = QQuickImplicitSizeItem::event(event);
1928 if (event->type() == QEvent::ShortcutOverride && !event->isAccepted()) {
1929 d->control->processEvent(event, QPointF(-d->xoff, -d->yoff));
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949bool QQuickTextEdit::overwriteMode()
const
1951 Q_D(
const QQuickTextEdit);
1952 return d->control->overwriteMode();
1955void QQuickTextEdit::setOverwriteMode(
bool overwrite)
1957 Q_D(QQuickTextEdit);
1958 d->control->setOverwriteMode(overwrite);
1962
1963
1964
1965void QQuickTextEdit::keyPressEvent(QKeyEvent *event)
1967 Q_D(QQuickTextEdit);
1968 d->control->processEvent(event, QPointF(-d->xoff, -d->yoff));
1969 if (!event->isAccepted())
1970 QQuickImplicitSizeItem::keyPressEvent(event);
1974
1975
1976
1977void QQuickTextEdit::keyReleaseEvent(QKeyEvent *event)
1979 Q_D(QQuickTextEdit);
1980 d->control->processEvent(event, QPointF(-d->xoff, -d->yoff));
1981 if (!event->isAccepted())
1982 QQuickImplicitSizeItem::keyReleaseEvent(event);
1986
1987
1988
1989
1990void QQuickTextEdit::deselect()
1992 Q_D(QQuickTextEdit);
1993 QTextCursor c = d->control->textCursor();
1995 d->control->setTextCursor(c);
1999
2000
2001
2002
2003void QQuickTextEdit::selectAll()
2005 Q_D(QQuickTextEdit);
2006 d->control->selectAll();
2010
2011
2012
2013
2014void QQuickTextEdit::selectWord()
2016 Q_D(QQuickTextEdit);
2017 QTextCursor c = d->control->textCursor();
2018 c.select(QTextCursor::WordUnderCursor);
2019 d->control->setTextCursor(c);
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035void QQuickTextEdit::select(
int start,
int end)
2037 Q_D(QQuickTextEdit);
2038 if (start < 0 || end < 0 || start >= d->document->characterCount() || end >= d->document->characterCount())
2040 QTextCursor cursor = d->control->textCursor();
2041 cursor.beginEditBlock();
2042 cursor.setPosition(start, QTextCursor::MoveAnchor);
2043 cursor.setPosition(end, QTextCursor::KeepAnchor);
2044 cursor.endEditBlock();
2045 d->control->setTextCursor(cursor);
2050 updateInputMethod();
2055
2056
2057
2058
2059
2060bool QQuickTextEdit::isRightToLeft(
int start,
int end)
2063 qmlWarning(
this) <<
"isRightToLeft(start, end) called with the end property being smaller than the start.";
2066 return getText(start, end).isRightToLeft();
2070#if QT_CONFIG(clipboard)
2072
2073
2074
2075
2076void QQuickTextEdit::cut()
2078 Q_D(QQuickTextEdit);
2083
2084
2085
2086
2087void QQuickTextEdit::copy()
2089 Q_D(QQuickTextEdit);
2094
2095
2096
2097
2098void QQuickTextEdit::paste()
2100 Q_D(QQuickTextEdit);
2101 d->control->paste();
2107
2108
2109
2110
2111
2112
2114void QQuickTextEdit::undo()
2116 Q_D(QQuickTextEdit);
2121
2122
2123
2124
2126void QQuickTextEdit::redo()
2128 Q_D(QQuickTextEdit);
2133
2134
2135
2136void QQuickTextEdit::mousePressEvent(QMouseEvent *event)
2138 Q_D(QQuickTextEdit);
2139 const bool isMouse = QQuickDeliveryAgentPrivate::isEventFromMouseOrTouchpad(event);
2140 setKeepMouseGrab(d->selectByMouse && isMouse);
2141 d->control->processEvent(event, QPointF(-d->xoff, -d->yoff));
2142 if (d->focusOnPress){
2143 bool hadActiveFocus = hasActiveFocus();
2144 forceActiveFocus(Qt::MouseFocusReason);
2147 if (hasActiveFocus() && hadActiveFocus && !isReadOnly())
2148 qGuiApp->inputMethod()->show();
2150 Q_UNUSED(hadActiveFocus);
2153 if (!event->isAccepted())
2154 QQuickImplicitSizeItem::mousePressEvent(event);
2158
2159
2160
2161void QQuickTextEdit::mouseReleaseEvent(QMouseEvent *event)
2163 Q_D(QQuickTextEdit);
2164 d->control->processEvent(event, QPointF(-d->xoff, -d->yoff));
2166 if (!event->isAccepted())
2167 QQuickImplicitSizeItem::mouseReleaseEvent(event);
2171
2172
2173
2174void QQuickTextEdit::mouseDoubleClickEvent(QMouseEvent *event)
2176 Q_D(QQuickTextEdit);
2177 d->control->processEvent(event, QPointF(-d->xoff, -d->yoff));
2178 if (!event->isAccepted())
2179 QQuickImplicitSizeItem::mouseDoubleClickEvent(event);
2183
2184
2185
2186void QQuickTextEdit::mouseMoveEvent(QMouseEvent *event)
2188 Q_D(QQuickTextEdit);
2189 d->control->processEvent(event, QPointF(-d->xoff, -d->yoff));
2190 if (!event->isAccepted())
2191 QQuickImplicitSizeItem::mouseMoveEvent(event);
2196
2197
2198
2199void QQuickTextEdit::inputMethodEvent(QInputMethodEvent *event)
2201 Q_D(QQuickTextEdit);
2202 const bool wasComposing = isInputMethodComposing();
2203 d->control->processEvent(event, QPointF(-d->xoff, -d->yoff));
2204 setCursorVisible(d->control->cursorVisible());
2205 if (wasComposing != isInputMethodComposing())
2206 emit inputMethodComposingChanged();
2210
2211
2212
2213QVariant QQuickTextEdit::inputMethodQuery(Qt::InputMethodQuery property, QVariant argument)
const
2215 Q_D(
const QQuickTextEdit);
2220 v = (
bool)(flags() & ItemAcceptsInputMethod);
2223 v = (
int)d->effectiveInputMethodHints();
2225 case Qt::ImInputItemClipRectangle:
2226 v = QQuickItem::inputMethodQuery(property);
2228 case Qt::ImReadOnly:
2232 if (property == Qt::ImCursorPosition && !argument.isNull())
2233 argument = QVariant(argument.toPointF() - QPointF(d->xoff, d->yoff));
2234 v = d->control->inputMethodQuery(property, argument);
2235 if (property == Qt::ImCursorRectangle || property == Qt::ImAnchorRectangle)
2236 v = QVariant(v.toRectF().translated(d->xoff, d->yoff));
2243
2244
2245
2246QVariant QQuickTextEdit::inputMethodQuery(Qt::InputMethodQuery property)
const
2248 return inputMethodQuery(property, QVariant());
2252void QQuickTextEdit::triggerPreprocess()
2254 Q_D(QQuickTextEdit);
2255 if (d->updateType == QQuickTextEditPrivate::UpdateNone)
2256 d->updateType = QQuickTextEditPrivate::UpdateOnlyPreprocess;
2262
2263
2264
2265
2266QVariant QQuickTextEdit::loadResource(
int type,
const QUrl &source)
2268 Q_D(QQuickTextEdit);
2269 const QUrl url = d->document->baseUrl().resolved(source);
2270 if (url.isLocalFile()) {
2272 QFileInfo fi(QQmlFile::urlToLocalFileOrQrc(url));
2274 qmlWarning(
this) <<
"Cannot open: " << url.toString();
2280 if (!url.scheme().compare(
"qrc"_L1, Qt::CaseInsensitive)) {
2282 QFile f(QQmlFile::urlToLocalFileOrQrc(url));
2283 if (f.open(QFile::ReadOnly)) {
2284 QByteArray buf = f.readAll();
2287 image.loadFromData(buf);
2288 if (!image.isNull())
2292 qmlWarning(
this) <<
"Cannot read resource: " << f.fileName();
2297 auto existingJobIter = std::find_if(
2298 d->pixmapsInProgress.cbegin(), d->pixmapsInProgress.cend(),
2299 [&url](
const auto *job) {
return job->url() == url; } );
2300 if (existingJobIter != d->pixmapsInProgress.cend()) {
2301 const QQuickPixmap *job = *existingJobIter;
2302 if (job->isError()) {
2303 qmlWarning(
this) << job->error();
2304 d->pixmapsInProgress.erase(existingJobIter);
2308 qCDebug(lcTextEdit) <<
"already downloading" << url;
2310 return job->isReady() ? job->image() : QVariant();
2315 qCDebug(lcTextEdit) <<
"loading" << source <<
"resolved" << url
2316 <<
"type" <<
static_cast<QTextDocument::ResourceType>(type);
2317 QQmlContext *context = qmlContext(
this);
2320 QQuickPixmap *p =
new QQuickPixmap(context->engine(), url, QQuickPixmap::Options{});
2321 p->connectFinished(
this, SLOT(resourceRequestFinished()));
2322 d->pixmapsInProgress.append(p);
2324 return p->isReady() ? p->image() : QVariant();
2328
2329
2330void QQuickTextEdit::resourceRequestFinished()
2332 Q_D(QQuickTextEdit);
2333 for (
auto it = d->pixmapsInProgress.cbegin(); it != d->pixmapsInProgress.cend(); ++it) {
2335 if (job->isError()) {
2337 qCDebug(lcTextEdit) <<
"failed to load (error)" << job->url();
2338 d->document->resource(QTextDocument::ImageResource, job->url());
2342 }
else if (job->isReady()) {
2344 auto res = d->document->resource(QTextDocument::ImageResource, job->url());
2346 qCDebug(lcTextEdit) << (res.isValid() ?
"done downloading" :
"failed to load") << job->url() << job->rect();
2347 d->pixmapsInProgress.erase(it);
2352 if (d->pixmapsInProgress.isEmpty()) {
2360using TextNodeIterator = QQuickTextEditPrivate::TextNodeIterator;
2364 return n1.startPos() < n2.startPos();
2369 QMatrix4x4 transformMatrix;
2370 transformMatrix.translate(topLeft.x(), topLeft.y());
2371 node->setMatrix(transformMatrix);
2375
2376
2377
2378
2379
2380void QQuickTextEdit::invalidateFontCaches()
2382 Q_D(QQuickTextEdit);
2383 if (d->document ==
nullptr)
2387 for (block = d->document->firstBlock(); block.isValid(); block = block.next()) {
2388 if (block.layout() !=
nullptr && block.layout()->engine() !=
nullptr)
2389 block.layout()->engine()->resetFontEngineCache();
2393QTextDocument *QQuickTextEdit::document()
const
2395 Q_D(
const QQuickTextEdit);
2399void QQuickTextEdit::setDocument(QTextDocument *doc)
2401 Q_D(QQuickTextEdit);
2403 std::unique_ptr<QTextDocument> cleanup(d->ownsDocument ? d->document :
nullptr);
2405 d->ownsDocument =
false;
2406 d->control->setDocument(doc);
2416 engine->setDevicePixelRatio(dpr);
2419QSGNode *QQuickTextEdit::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *updatePaintNodeData)
2421 Q_UNUSED(updatePaintNodeData);
2422 Q_D(QQuickTextEdit);
2424 if (d->updateType != QQuickTextEditPrivate::UpdatePaintNode
2425 && d->updateType != QQuickTextEditPrivate::UpdateAll
2426 && oldNode !=
nullptr) {
2428 d->updateType = QQuickTextEditPrivate::UpdateNone;
2432 d->containsUnscalableGlyphs =
false;
2433 if (!oldNode || d->updateType == QQuickTextEditPrivate::UpdateAll) {
2439 d->textNodeMap.clear();
2442 d->updateType = QQuickTextEditPrivate::UpdateNone;
2444 RootNode *rootNode =
static_cast<RootNode *>(oldNode);
2445 TextNodeIterator nodeIterator = d->textNodeMap.begin();
2446 std::optional<
int> firstPosAcrossAllNodes;
2447 if (nodeIterator != d->textNodeMap.end())
2448 firstPosAcrossAllNodes = nodeIterator->startPos();
2450 while (nodeIterator != d->textNodeMap.end() && !nodeIterator->dirty())
2453 const auto dpr = d->effectiveDevicePixelRatio();
2454 QQuickTextNodeEngine engine;
2455 engine.setDevicePixelRatio(dpr);
2456 QQuickTextNodeEngine frameDecorationsEngine;
2457 frameDecorationsEngine.setDevicePixelRatio(dpr);
2459 if (!oldNode || nodeIterator < d->textNodeMap.end() || d->textNodeMap.isEmpty()) {
2462 rootNode =
new RootNode;
2464 int firstDirtyPos = 0;
2465 if (nodeIterator != d->textNodeMap.end()) {
2466 firstDirtyPos = nodeIterator->startPos();
2469 QSGInternalTextNode *firstCleanNode =
nullptr;
2470 auto it = d->textNodeMap.constEnd();
2471 while (it != nodeIterator) {
2475 firstCleanNode = it->textNode();
2478 rootNode->removeChildNode(nodeIterator->textNode());
2479 delete nodeIterator->textNode();
2480 nodeIterator = d->textNodeMap.erase(nodeIterator);
2481 }
while (nodeIterator != d->textNodeMap.constEnd() && nodeIterator->textNode() != firstCleanNode);
2486 if (flags().testFlag(QQuickItem::ItemObservesViewport)) {
2487 viewport = clipRect();
2488 qCDebug(lcVP) <<
"text viewport" << viewport;
2492 rootNode->resetFrameDecorations(d->createTextNode());
2493 resetEngine(&frameDecorationsEngine, d->color, d->selectedTextColor, d->selectionColor, dpr);
2495 QSGInternalTextNode *node =
nullptr;
2497 int currentNodeSize = 0;
2498 int nodeStart = firstDirtyPos;
2499 QPointF basePosition(d->xoff, d->yoff);
2500 QMatrix4x4 basePositionMatrix;
2501 basePositionMatrix.translate(basePosition.x(), basePosition.y());
2502 rootNode->setMatrix(basePositionMatrix);
2505 const TextNode firstCleanNode = (nodeIterator != d->textNodeMap.end()) ? *nodeIterator
2508 QList<QTextFrame *> frames;
2509 frames.append(d->document->rootFrame());
2512 d->firstBlockInViewport = -1;
2513 d->firstBlockPastViewport = -1;
2514 int frameCount = -1;
2515 while (!frames.isEmpty()) {
2516 QTextFrame *textFrame = frames.takeFirst();
2520 qCDebug(lcVP) <<
"frame" << frameCount << textFrame
2521 <<
"from" << positionToRectangle(textFrame->firstPosition()).topLeft()
2522 <<
"to" << positionToRectangle(textFrame->lastPosition()).bottomRight();
2523 frames.append(textFrame->childFrames());
2524 frameDecorationsEngine.addFrameDecorations(d->document, textFrame);
2525 resetEngine(&engine, d->color, d->selectedTextColor, d->selectionColor, dpr);
2527 if (textFrame->firstPosition() > textFrame->lastPosition()
2528 && textFrame->frameFormat().position() != QTextFrameFormat::InFlow) {
2529 node = d->createTextNode();
2530 updateNodeTransform(node, d->document->documentLayout()->frameBoundingRect(textFrame).topLeft());
2531 const int pos = textFrame->firstPosition() - 1;
2532 auto *a =
static_cast<QtPrivate::ProtectedLayoutAccessor *>(d->document->documentLayout());
2533 QTextCharFormat format = a->formatAccessor(pos);
2534 QTextBlock block = textFrame->firstCursorPosition().block();
2535 nodeOffset = d->document->documentLayout()->blockBoundingRect(block).topLeft();
2537 if (!viewport.isNull() && block.layout()) {
2538 QRectF coveredRegion = block.layout()->boundingRect().adjusted(nodeOffset.x(), nodeOffset.y(), nodeOffset.x(), nodeOffset.y());
2539 inView = coveredRegion.bottom() >= viewport.top() && coveredRegion.top() <= viewport.bottom();
2540 qCDebug(lcVP) <<
"non-flow frame" << coveredRegion <<
"in viewport?" << inView;
2543 engine.setCurrentLine(block.layout()->lineForTextPosition(pos - block.position()));
2544 engine.addTextObject(block, QPointF(0, 0), format, QQuickTextNodeEngine::Unselected, d->document,
2545 pos, textFrame->frameFormat().position());
2550 QVarLengthArray<
int, 8> frameBoundaries;
2551 frameBoundaries.reserve(frames.size());
2552 for (QTextFrame *frame : std::as_const(frames))
2553 frameBoundaries.append(frame->firstPosition());
2554 std::sort(frameBoundaries.begin(), frameBoundaries.end());
2556 QTextFrame::iterator it = textFrame->begin();
2557 while (!it.atEnd()) {
2558 QTextBlock block = it.currentBlock();
2559 if (block.position() < firstDirtyPos) {
2564 if (!engine.hasContents())
2565 nodeOffset = d->document->documentLayout()->blockBoundingRect(block).topLeft();
2568 if (!viewport.isNull()) {
2569 QRectF coveredRegion;
2570 if (block.layout()) {
2571 coveredRegion = block.layout()->boundingRect().adjusted(nodeOffset.x(), nodeOffset.y(), nodeOffset.x(), nodeOffset.y());
2572 inView = coveredRegion.bottom() > viewport.top();
2574 const bool potentiallyScrollingBackwards = firstPosAcrossAllNodes && *firstPosAcrossAllNodes == firstDirtyPos;
2575 if (d->firstBlockInViewport < 0 && inView && potentiallyScrollingBackwards) {
2577 if (coveredRegion.top() > viewport.top() + 1) {
2578 qCDebug(lcVP) <<
"checking backwards from block" << block.blockNumber() <<
"@" << nodeOffset.y() << coveredRegion;
2579 while (it != textFrame->begin() && it.currentBlock().layout() &&
2580 it.currentBlock().layout()->boundingRect().top() + nodeOffset.y() > viewport.top()) {
2581 nodeOffset = d->document->documentLayout()->blockBoundingRect(it.currentBlock()).topLeft();
2584 if (!it.currentBlock().layout())
2586 if (Q_LIKELY(it.currentBlock().layout())) {
2587 block = it.currentBlock();
2588 coveredRegion = block.layout()->boundingRect().adjusted(nodeOffset.x(), nodeOffset.y(), nodeOffset.x(), nodeOffset.y());
2589 firstDirtyPos = it.currentBlock().position();
2591 qCWarning(lcVP) <<
"failed to find a text block with layout during back-scrolling";
2594 qCDebug(lcVP) <<
"first block in viewport" << block.blockNumber() <<
"@" << nodeOffset.y() << coveredRegion;
2596 d->renderedRegion = coveredRegion;
2598 if (nodeOffset.y() > viewport.bottom()) {
2600 if (d->firstBlockInViewport >= 0 && d->firstBlockPastViewport < 0) {
2601 qCDebug(lcVP) <<
"first block past viewport" << viewport << block.blockNumber()
2602 <<
"@" << nodeOffset.y() <<
"total region rendered" << d->renderedRegion;
2603 d->firstBlockPastViewport = block.blockNumber();
2607 if (inView && !block.text().isEmpty() && coveredRegion.isValid()) {
2608 d->renderedRegion = d->renderedRegion.united(coveredRegion);
2611 if (!frames.isEmpty())
2612 viewport = viewport.united(d->renderedRegion);
2615 if (inView && d->firstBlockInViewport < 0)
2616 d->firstBlockInViewport = block.blockNumber();
2619 bool createdNodeInView =
false;
2621 if (!engine.hasContents()) {
2623 d->containsUnscalableGlyphs = d->containsUnscalableGlyphs
2624 || node->containsUnscalableGlyphs();
2625 if (!node->parent())
2626 d->addCurrentTextNodeToRoot(&engine, rootNode, node, nodeIterator, nodeStart);
2628 node = d->createTextNode();
2629 createdNodeInView =
true;
2630 updateNodeTransform(node, nodeOffset);
2631 nodeStart = block.position();
2633 engine.addTextBlock(d->document, block, -nodeOffset, d->color, QColor(), selectionStart(), selectionEnd() - 1);
2634 currentNodeSize += block.length();
2637 if ((it.atEnd()) || block.next().position() >= firstCleanNode.startPos())
2639 const auto lowerBound =
2640 std::lower_bound(frameBoundaries.constBegin(),
2641 frameBoundaries.constEnd(), block.next().position());
2642 if (node && (currentNodeSize > nodeBreakingSize || lowerBound == frameBoundaries.constEnd() || *lowerBound > nodeStart)) {
2643 currentNodeSize = 0;
2644 d->containsUnscalableGlyphs = d->containsUnscalableGlyphs
2645 || node->containsUnscalableGlyphs();
2646 if (!node->parent())
2647 d->addCurrentTextNodeToRoot(&engine, rootNode, node, nodeIterator, nodeStart);
2648 if (!createdNodeInView)
2649 node = d->createTextNode();
2650 resetEngine(&engine, d->color, d->selectedTextColor, d->selectionColor, dpr);
2651 nodeStart = block.next().position();
2656 if (Q_LIKELY(node)) {
2657 d->containsUnscalableGlyphs = d->containsUnscalableGlyphs
2658 || node->containsUnscalableGlyphs();
2659 if (Q_LIKELY(!node->parent()))
2660 d->addCurrentTextNodeToRoot(&engine, rootNode, node, nodeIterator, nodeStart);
2663 frameDecorationsEngine.addToSceneGraph(rootNode->frameDecorationsNode,
nullptr, QQuickText::Normal, QColor());
2665 rootNode->prependChildNode(rootNode->frameDecorationsNode);
2667 Q_ASSERT(nodeIterator == d->textNodeMap.end()
2668 || (nodeIterator->textNode() == firstCleanNode.textNode()
2669 && nodeIterator->startPos() == firstCleanNode.startPos()));
2671 if (firstCleanNode.textNode() !=
nullptr) {
2672 QPointF oldOffset = firstCleanNode.textNode()->matrix().map(QPointF(0,0));
2673 QPointF currentOffset = d->document->documentLayout()->blockBoundingRect(
2674 d->document->findBlock(firstCleanNode.startPos())).topLeft();
2675 QPointF delta = currentOffset - oldOffset;
2676 while (nodeIterator != d->textNodeMap.end()) {
2677 QMatrix4x4 transformMatrix = nodeIterator->textNode()->matrix();
2678 transformMatrix.translate(delta.x(), delta.y());
2679 nodeIterator->textNode()->setMatrix(transformMatrix);
2687 std::sort(d->textNodeMap.begin(), d->textNodeMap.end());
2690 if (d->cursorComponent ==
nullptr) {
2691 QSGInternalRectangleNode* cursor =
nullptr;
2692 if (!isReadOnly() && d->cursorVisible && d->control->cursorOn() && d->control->cursorVisible())
2693 cursor = d->sceneGraphContext()->createInternalRectangleNode(d->control->cursorRect(), d->color);
2694 rootNode->resetCursorNode(cursor);
2697 invalidateFontCaches();
2702void QQuickTextEdit::updatePolish()
2704 invalidateFontCaches();
2708
2709
2710
2711
2712
2713bool QQuickTextEdit::canPaste()
const
2715 Q_D(
const QQuickTextEdit);
2716 if (!d->canPasteValid) {
2717 const_cast<QQuickTextEditPrivate *>(d)->canPaste = d->control->canPaste();
2718 const_cast<QQuickTextEditPrivate *>(d)->canPasteValid =
true;
2724
2725
2726
2727
2728
2730bool QQuickTextEdit::canUndo()
const
2732 Q_D(
const QQuickTextEdit);
2733 return d->document->isUndoAvailable();
2737
2738
2739
2740
2741
2743bool QQuickTextEdit::canRedo()
const
2745 Q_D(
const QQuickTextEdit);
2746 return d->document->isRedoAvailable();
2750
2751
2752
2753
2754
2755
2756
2757
2758
2759
2760
2761bool QQuickTextEdit::isInputMethodComposing()
const
2766 Q_D(
const QQuickTextEdit);
2767 return d->control->hasImState();
2771QQuickTextEditPrivate::ExtraData::ExtraData()
2772 : explicitTopPadding(
false)
2773 , explicitLeftPadding(
false)
2774 , explicitRightPadding(
false)
2775 , explicitBottomPadding(
false)
2776 , implicitResize(
true)
2780void QQuickTextEditPrivate::init()
2782 Q_Q(QQuickTextEdit);
2784#if QT_CONFIG(clipboard)
2785 if (QGuiApplication::clipboard()->supportsSelection())
2786 q->setAcceptedMouseButtons(Qt::LeftButton | Qt::MiddleButton);
2789 q->setAcceptedMouseButtons(Qt::LeftButton);
2792 q->setFlag(QQuickItem::ItemAcceptsInputMethod);
2794 q->setFlag(QQuickItem::ItemHasContents);
2796 q->setAcceptHoverEvents(
true);
2798 document =
new QTextDocument(q);
2799 ownsDocument =
true;
2800 auto *imageHandler =
new QQuickTextImageHandler(document);
2801 document->documentLayout()->registerHandler(QTextFormat::ImageObject, imageHandler);
2803 control =
new QQuickTextControl(document, q);
2804 control->setTextInteractionFlags(Qt::LinksAccessibleByMouse | Qt::TextSelectableByMouse | Qt::TextSelectableByKeyboard | Qt::TextEditable);
2805 control->setAcceptRichText(
false);
2806 control->setCursorIsFocusIndicator(
true);
2807 q->setKeepMouseGrab(
true);
2809 qmlobject_connect(control, QQuickTextControl, SIGNAL(updateCursorRequest()), q, QQuickTextEdit, SLOT(updateCursor()));
2810 qmlobject_connect(control, QQuickTextControl, SIGNAL(selectionChanged()), q, QQuickTextEdit, SIGNAL(selectedTextChanged()));
2811 qmlobject_connect(control, QQuickTextControl, SIGNAL(selectionChanged()), q, QQuickTextEdit, SLOT(updateSelection()));
2812 qmlobject_connect(control, QQuickTextControl, SIGNAL(cursorPositionChanged()), q, QQuickTextEdit, SLOT(updateSelection()));
2813 qmlobject_connect(control, QQuickTextControl, SIGNAL(cursorPositionChanged()), q, QQuickTextEdit, SIGNAL(cursorPositionChanged()));
2814 qmlobject_connect(control, QQuickTextControl, SIGNAL(cursorRectangleChanged()), q, QQuickTextEdit, SLOT(moveCursorDelegate()));
2815 qmlobject_connect(control, QQuickTextControl, SIGNAL(linkActivated(QString)), q, QQuickTextEdit, SIGNAL(linkActivated(QString)));
2816 qmlobject_connect(control, QQuickTextControl, SIGNAL(overwriteModeChanged(
bool)), q, QQuickTextEdit, SIGNAL(overwriteModeChanged(
bool)));
2817 qmlobject_connect(control, QQuickTextControl, SIGNAL(textChanged()), q, QQuickTextEdit, SLOT(q_textChanged()));
2818 qmlobject_connect(control, QQuickTextControl, SIGNAL(preeditTextChanged()), q, QQuickTextEdit, SIGNAL(preeditTextChanged()));
2819#if QT_CONFIG(clipboard)
2820 qmlobject_connect(QGuiApplication::clipboard(), QClipboard, SIGNAL(dataChanged()), q, QQuickTextEdit, SLOT(q_canPasteChanged()));
2822 qmlobject_connect(document, QTextDocument, SIGNAL(undoAvailable(
bool)), q, QQuickTextEdit, SIGNAL(canUndoChanged()));
2823 qmlobject_connect(document, QTextDocument, SIGNAL(redoAvailable(
bool)), q, QQuickTextEdit, SIGNAL(canRedoChanged()));
2824 QObject::connect(document, &QTextDocument::contentsChange, q, &QQuickTextEdit::q_contentsChange);
2825 QObject::connect(document->documentLayout(), &QAbstractTextDocumentLayout::updateBlock, q, &QQuickTextEdit::invalidateBlock);
2826 QObject::connect(control, &QQuickTextControl::linkHovered, q, &QQuickTextEdit::q_linkHovered);
2827 QObject::connect(control, &QQuickTextControl::markerHovered, q, &QQuickTextEdit::q_markerHovered);
2829 document->setPageSize(QSizeF(0, 0));
2830 document->setDefaultFont(font);
2831 document->setDocumentMargin(textMargin);
2832 document->setUndoRedoEnabled(
false);
2833 document->setUndoRedoEnabled(
true);
2834 updateDefaultTextOption();
2835 document->setModified(
false);
2837#if QT_CONFIG(cursor)
2838 updateMouseCursorShape();
2840 setSizePolicy(QLayoutPolicy::Expanding, QLayoutPolicy::Expanding);
2843void QQuickTextEditPrivate::resetInputMethod()
2845 Q_Q(QQuickTextEdit);
2846 if (!q->isReadOnly() && q->hasActiveFocus() && qGuiApp)
2847 QGuiApplication::inputMethod()->reset();
2850void QQuickTextEdit::q_textChanged()
2852 Q_D(QQuickTextEdit);
2853 d->textCached =
false;
2854 for (QTextBlock it = d->document->begin(); it != d->document->end(); it = it.next()) {
2855 d->contentDirection = d->textDirection(it.text());
2856 if (d->contentDirection != Qt::LayoutDirectionAuto)
2859 d->determineHorizontalAlignment();
2860 d->updateDefaultTextOption();
2863 markDirtyNodesForRange(0, d->document->characterCount(), 0);
2864 if (isComponentComplete()) {
2866 d->updateType = QQuickTextEditPrivate::UpdatePaintNode;
2871 if (d->control->isBeingEdited())
2875void QQuickTextEdit::markDirtyNodesForRange(
int start,
int end,
int charDelta)
2877 Q_D(QQuickTextEdit);
2881 TextNode dummyNode(start);
2883 const TextNodeIterator textNodeMapBegin = d->textNodeMap.begin();
2884 const TextNodeIterator textNodeMapEnd = d->textNodeMap.end();
2886 TextNodeIterator it = std::lower_bound(textNodeMapBegin, textNodeMapEnd, dummyNode);
2889 if (it != textNodeMapBegin) {
2891 TextNode otherDummy(it->startPos());
2892 it = std::lower_bound(textNodeMapBegin, textNodeMapEnd, otherDummy);
2896 while (it != textNodeMapEnd) {
2897 if (it->startPos() <= end)
2900 it->moveStartPos(charDelta);
2907void QQuickTextEdit::q_contentsChange(
int pos,
int charsRemoved,
int charsAdded)
2909 Q_D(QQuickTextEdit);
2911 const int editRange = pos + qMax(charsAdded, charsRemoved);
2912 const int delta = charsAdded - charsRemoved;
2914 markDirtyNodesForRange(pos, editRange, delta);
2916 if (isComponentComplete()) {
2918 d->updateType = QQuickTextEditPrivate::UpdatePaintNode;
2923void QQuickTextEdit::moveCursorDelegate()
2925 Q_D(QQuickTextEdit);
2927 updateInputMethod();
2929 emit cursorRectangleChanged();
2932 QRectF cursorRect = cursorRectangle();
2933 d->cursorItem->setX(cursorRect.x());
2934 d->cursorItem->setY(cursorRect.y());
2935 d->cursorItem->setHeight(cursorRect.height());
2938void QQuickTextEdit::updateSelection()
2940 Q_D(QQuickTextEdit);
2943 if (d->control->textCursor().hasSelection() || d->hadSelection) {
2944 markDirtyNodesForRange(qMin(d->lastSelectionStart, d->control->textCursor().selectionStart()), qMax(d->control->textCursor().selectionEnd(), d->lastSelectionEnd), 0);
2945 if (isComponentComplete()) {
2947 d->updateType = QQuickTextEditPrivate::UpdatePaintNode;
2952 d->hadSelection = d->control->textCursor().hasSelection();
2954 if (d->lastSelectionStart != d->control->textCursor().selectionStart()) {
2955 d->lastSelectionStart = d->control->textCursor().selectionStart();
2956 emit selectionStartChanged();
2958 if (d->lastSelectionEnd != d->control->textCursor().selectionEnd()) {
2959 d->lastSelectionEnd = d->control->textCursor().selectionEnd();
2960 emit selectionEndChanged();
2964QRectF QQuickTextEdit::boundingRect()
const
2966 Q_D(
const QQuickTextEdit);
2968 QQuickTextUtil::alignedX(d->contentSize.width(), width(), effectiveHAlign()),
2970 d->contentSize.width(),
2971 d->contentSize.height());
2973 int cursorWidth = 1;
2976 else if (!d->document->isEmpty())
2980 r.setRight(r.right() + cursorWidth);
2985QRectF QQuickTextEdit::clipRect()
const
2987 Q_D(
const QQuickTextEdit);
2988 QRectF r = QQuickImplicitSizeItem::clipRect();
2989 int cursorWidth = 1;
2991 cursorWidth = d->cursorItem->width();
2992 if (!d->document->isEmpty())
2997 r.setRight(r.right() + cursorWidth);
3001qreal QQuickTextEditPrivate::getImplicitWidth()
const
3003 Q_Q(
const QQuickTextEdit);
3004 if (!requireImplicitWidth) {
3007 const_cast<QQuickTextEditPrivate*>(
this)->requireImplicitWidth =
true;
3008 const_cast<QQuickTextEdit*>(q)->updateSize();
3010 return implicitWidth;
3015void QQuickTextEdit::updateSize()
3017 Q_D(QQuickTextEdit);
3018 if (!isComponentComplete()) {
3026 if (!d->requireImplicitWidth) {
3027 emit implicitWidthChanged();
3029 if (d->requireImplicitWidth)
3032 if (d->requireImplicitWidth) {
3033 d->document->setTextWidth(-1);
3034 const qreal naturalWidth = d->document->idealWidth();
3035 const bool wasInLayout = d->inLayout;
3037 if (d->isImplicitResizeEnabled())
3038 setImplicitWidth(naturalWidth + leftPadding() + rightPadding());
3039 d->inLayout = wasInLayout;
3043 const qreal newTextWidth = width() - leftPadding() - rightPadding();
3044 if (d->document->textWidth() != newTextWidth)
3045 d->document->setTextWidth(newTextWidth);
3046 }
else if (d->wrapMode == NoWrap) {
3050 const qreal newTextWidth = d->document->idealWidth();
3051 if (d->document->textWidth() != newTextWidth)
3052 d->document->setTextWidth(newTextWidth);
3054 d->document->setTextWidth(-1);
3057 QFontMetricsF fm(d->font);
3058 const qreal newHeight = d->document->isEmpty() ? qCeil(fm.height()) : d->document->size().height();
3059 const qreal newWidth = d->document->idealWidth();
3061 if (d->isImplicitResizeEnabled()) {
3064 setImplicitSize(newWidth + leftPadding() + rightPadding(), newHeight + topPadding() + bottomPadding());
3066 setImplicitHeight(newHeight + topPadding() + bottomPadding());
3069 d->xoff = leftPadding() + qMax(qreal(0), QQuickTextUtil::alignedX(d->document->size().width(), width() - leftPadding() - rightPadding(), effectiveHAlign()));
3070 d->yoff = topPadding() + QQuickTextUtil::alignedY(d->document->size().height(), height() - topPadding() - bottomPadding(), d->vAlign);
3072 qreal baseline = fm.ascent();
3073 QTextBlock firstBlock = d->document->firstBlock();
3074 if (firstBlock.isValid() && firstBlock.layout() !=
nullptr && firstBlock.lineCount() > 0) {
3075 QTextLine firstLine = firstBlock.layout()->lineAt(0);
3076 if (firstLine.isValid())
3077 baseline = firstLine.ascent();
3080 setBaselineOffset(baseline + d->yoff + d->textMargin);
3082 QSizeF size(newWidth, newHeight);
3083 if (d->contentSize != size) {
3084 d->contentSize = size;
3086 const bool wasInResize = d->inResize;
3089 emit contentSizeChanged();
3090 d->inResize = wasInResize;
3095void QQuickTextEdit::updateWholeDocument()
3097 Q_D(QQuickTextEdit);
3098 if (!d->textNodeMap.isEmpty()) {
3099 for (TextNode &node : d->textNodeMap)
3103 if (isComponentComplete()) {
3105 d->updateType = QQuickTextEditPrivate::UpdatePaintNode;
3110void QQuickTextEdit::invalidateBlock(
const QTextBlock &block)
3112 Q_D(QQuickTextEdit);
3113 markDirtyNodesForRange(block.position(), block.position() + block.length(), 0);
3115 if (isComponentComplete()) {
3117 d->updateType = QQuickTextEditPrivate::UpdatePaintNode;
3122void QQuickTextEdit::updateCursor()
3124 Q_D(QQuickTextEdit);
3125 if (isComponentComplete() && isVisible()) {
3127 d->updateType = QQuickTextEditPrivate::UpdatePaintNode;
3132void QQuickTextEdit::q_linkHovered(
const QString &link)
3134 Q_D(QQuickTextEdit);
3135 emit linkHovered(link);
3136#if QT_CONFIG(cursor)
3137 if (link.isEmpty()) {
3138 d->updateMouseCursorShape();
3139 }
else if (cursor().shape() != Qt::PointingHandCursor) {
3140 setCursor(Qt::PointingHandCursor);
3145void QQuickTextEdit::q_markerHovered(
bool hovered)
3147 Q_D(QQuickTextEdit);
3148#if QT_CONFIG(cursor)
3150 d->updateMouseCursorShape();
3151 }
else if (cursor().shape() != Qt::PointingHandCursor) {
3152 setCursor(Qt::PointingHandCursor);
3157void QQuickTextEdit::q_updateAlignment()
3159 Q_D(QQuickTextEdit);
3160 if (d->determineHorizontalAlignment()) {
3161 d->updateDefaultTextOption();
3162 d->xoff = qMax(qreal(0), QQuickTextUtil::alignedX(d->document->size().width(), width(), effectiveHAlign()));
3163 moveCursorDelegate();
3164 updateWholeDocument();
3168void QQuickTextEdit::updateTotalLines()
3170 Q_D(QQuickTextEdit);
3174 for (QTextBlock it = d->document->begin(); it != d->document->end(); it = it.next()) {
3175 QTextLayout *layout = it.layout();
3178 subLines += layout->lineCount()-1;
3181 int newTotalLines = d->document->lineCount() + subLines;
3182 if (d->lineCount != newTotalLines) {
3183 d->lineCount = newTotalLines;
3184 emit lineCountChanged();
3188void QQuickTextEditPrivate::updateDefaultTextOption()
3190 Q_Q(QQuickTextEdit);
3191 QTextOption opt = document->defaultTextOption();
3192 const Qt::Alignment oldAlignment = opt.alignment();
3193 Qt::LayoutDirection oldTextDirection = opt.textDirection();
3195 QQuickTextEdit::HAlignment horizontalAlignment = q->effectiveHAlign();
3196 if (contentDirection == Qt::RightToLeft) {
3197 if (horizontalAlignment == QQuickTextEdit::AlignLeft)
3198 horizontalAlignment = QQuickTextEdit::AlignRight;
3199 else if (horizontalAlignment == QQuickTextEdit::AlignRight)
3200 horizontalAlignment = QQuickTextEdit::AlignLeft;
3202 if (!hAlignImplicit)
3203 opt.setAlignment((Qt::Alignment)(
int)(horizontalAlignment | vAlign));
3205 opt.setAlignment(Qt::Alignment(vAlign));
3208 if (contentDirection == Qt::LayoutDirectionAuto) {
3209 opt.setTextDirection(qGuiApp->inputMethod()->inputDirection());
3213 opt.setTextDirection(contentDirection);
3216 QTextOption::WrapMode oldWrapMode = opt.wrapMode();
3217 opt.setWrapMode(QTextOption::WrapMode(wrapMode));
3219 bool oldUseDesignMetrics = opt.useDesignMetrics();
3220 opt.setUseDesignMetrics(renderType != QQuickTextEdit::NativeRendering);
3222 if (oldWrapMode != opt.wrapMode() || oldAlignment != opt.alignment()
3223 || oldTextDirection != opt.textDirection()
3224 || oldUseDesignMetrics != opt.useDesignMetrics()) {
3225 document->setDefaultTextOption(opt);
3229void QQuickTextEditPrivate::onDocumentStatusChanged()
3231 Q_ASSERT(quickDocument);
3232 switch (quickDocument->status()) {
3233 case QQuickTextDocument::Status::Loaded:
3234 case QQuickTextDocument::Status::Saved:
3235 switch (QQuickTextDocumentPrivate::get(quickDocument)->detectedFormat) {
3237 richText = (format == QQuickTextEdit::RichText || format == QQuickTextEdit::AutoText);
3238 markdownText =
false;
3240 case Qt::MarkdownText:
3242 markdownText = (format == QQuickTextEdit::MarkdownText || format == QQuickTextEdit::AutoText);
3246 markdownText =
false;
3257void QQuickTextEdit::focusInEvent(QFocusEvent *event)
3259 Q_D(QQuickTextEdit);
3260 d->handleFocusEvent(event);
3261 QQuickImplicitSizeItem::focusInEvent(event);
3264void QQuickTextEdit::focusOutEvent(QFocusEvent *event)
3266 Q_D(QQuickTextEdit);
3267 d->handleFocusEvent(event);
3268 QQuickImplicitSizeItem::focusOutEvent(event);
3271#if QT_VERSION < QT_VERSION_CHECK(7
, 0
, 0
)
3272bool QQuickTextEditPrivate::handleContextMenuEvent(QContextMenuEvent *event)
3274bool QQuickTextEdit::contextMenuEvent(QContextMenuEvent *event)
3277 Q_Q(QQuickTextEdit);
3278 QContextMenuEvent mapped(event->reason(),
3279 q->mapToScene(q->cursorRectangle().center()).toPoint(), event->globalPos(),
3280 event->modifiers());
3281 const bool eventProcessed = QQuickItemPrivate::handleContextMenuEvent(&mapped);
3282 event->setAccepted(mapped.isAccepted());
3283 return eventProcessed;
3286void QQuickTextEditPrivate::handleFocusEvent(QFocusEvent *event)
3288 Q_Q(QQuickTextEdit);
3289 bool focus = event->type() == QEvent::FocusIn;
3290 if (!q->isReadOnly())
3291 q->setCursorVisible(focus);
3292 control->processEvent(event, QPointF(-xoff, -yoff));
3294 q->q_updateAlignment();
3296 if (focusOnPress && !q->isReadOnly())
3297 qGuiApp->inputMethod()->show();
3298 q->connect(QGuiApplication::inputMethod(), SIGNAL(inputDirectionChanged(Qt::LayoutDirection)),
3299 q, SLOT(q_updateAlignment()));
3303 q->disconnect(QGuiApplication::inputMethod(), SIGNAL(inputDirectionChanged(Qt::LayoutDirection)),
3304 q, SLOT(q_updateAlignment()));
3306 if (event->reason() != Qt::ActiveWindowFocusReason
3307 && event->reason() != Qt::PopupFocusReason
3308 && control->textCursor().hasSelection()
3309 && !persistentSelection)
3312 emit q->editingFinished();
3316void QQuickTextEditPrivate::addCurrentTextNodeToRoot(QQuickTextNodeEngine *engine, QSGTransformNode *root, QSGInternalTextNode *node, TextNodeIterator &it,
int startPos)
3318 engine->addToSceneGraph(node,
nullptr, QQuickText::Normal, QColor());
3319 it = textNodeMap.insert(it, TextNode(startPos, node));
3321 root->appendChildNode(node);
3322 ++renderedBlockCount;
3325QSGInternalTextNode *QQuickTextEditPrivate::createTextNode()
3327 Q_Q(QQuickTextEdit);
3328 QSGInternalTextNode* node = sceneGraphContext()->createInternalTextNode(sceneGraphRenderContext());
3329 node->setRenderType(QSGTextNode::RenderType(renderType));
3330 node->setFiltering(q->smooth() ? QSGTexture::Linear : QSGTexture::Nearest);
3334void QQuickTextEdit::q_canPasteChanged()
3336 Q_D(QQuickTextEdit);
3337 bool old = d->canPaste;
3338 d->canPaste = d->control->canPaste();
3339 bool changed = old!=d->canPaste || !d->canPasteValid;
3340 d->canPasteValid =
true;
3342 emit canPasteChanged();
3346
3347
3348
3349
3350
3351
3353QString QQuickTextEdit::getText(
int start,
int end)
const
3355 Q_D(
const QQuickTextEdit);
3356 start = qBound(0, start, d->document->characterCount() - 1);
3357 end = qBound(0, end, d->document->characterCount() - 1);
3358 QTextCursor cursor(d->document);
3359 cursor.setPosition(start, QTextCursor::MoveAnchor);
3360 cursor.setPosition(end, QTextCursor::KeepAnchor);
3361#if QT_CONFIG(texthtmlparser)
3362 return d->richText || d->markdownText
3363 ? cursor.selectedText()
3364 : cursor.selection().toPlainText();
3366 return cursor.selection().toPlainText();
3371
3372
3373
3374
3375
3376
3378QString QQuickTextEdit::getFormattedText(
int start,
int end)
const
3380 Q_D(
const QQuickTextEdit);
3382 start = qBound(0, start, d->document->characterCount() - 1);
3383 end = qBound(0, end, d->document->characterCount() - 1);
3385 QTextCursor cursor(d->document);
3386 cursor.setPosition(start, QTextCursor::MoveAnchor);
3387 cursor.setPosition(end, QTextCursor::KeepAnchor);
3390#if QT_CONFIG(texthtmlparser)
3391 return cursor.selection().toHtml();
3393 return cursor.selection().toPlainText();
3395 }
else if (d->markdownText) {
3396#if QT_CONFIG(textmarkdownwriter)
3397 return cursor.selection().toMarkdown();
3399 return cursor.selection().toPlainText();
3402 return cursor.selection().toPlainText();
3407
3408
3409
3410
3411void QQuickTextEdit::insert(
int position,
const QString &text)
3413 Q_D(QQuickTextEdit);
3414 if (position < 0 || position >= d->document->characterCount())
3416 QTextCursor cursor(d->document);
3417 cursor.setPosition(position);
3418 d->richText = d->richText || (d->format == AutoText && Qt::mightBeRichText(text));
3420#if QT_CONFIG(texthtmlparser)
3421 cursor.insertHtml(text);
3423 cursor.insertText(text);
3425 }
else if (d->markdownText) {
3426#if QT_CONFIG(textmarkdownreader)
3427 cursor.insertMarkdown(text);
3429 cursor.insertText(text);
3432 cursor.insertText(text);
3434 d->control->updateCursorRectangle(
false);
3438
3439
3440
3441
3443void QQuickTextEdit::remove(
int start,
int end)
3445 Q_D(QQuickTextEdit);
3446 start = qBound(0, start, d->document->characterCount() - 1);
3447 end = qBound(0, end, d->document->characterCount() - 1);
3448 QTextCursor cursor(d->document);
3449 cursor.setPosition(start, QTextCursor::MoveAnchor);
3450 cursor.setPosition(end, QTextCursor::KeepAnchor);
3451 cursor.removeSelectedText();
3452 d->control->updateCursorRectangle(
false);
3456
3457
3458
3459
3460
3461
3462
3463
3464
3465
3467QQuickTextDocument *QQuickTextEdit::textDocument()
3469 Q_D(QQuickTextEdit);
3470 if (!d->quickDocument) {
3471 d->quickDocument =
new QQuickTextDocument(
this);
3472 connect(d->quickDocument, &QQuickTextDocument::statusChanged, d->quickDocument,
3473 [d]() { d->onDocumentStatusChanged(); } );
3475 return d->quickDocument;
3478bool QQuickTextEditPrivate::isLinkHoveredConnected()
3480 Q_Q(QQuickTextEdit);
3481 IS_SIGNAL_CONNECTED(q, QQuickTextEdit, linkHovered, (
const QString &));
3484#if QT_CONFIG(cursor)
3485void QQuickTextEditPrivate::updateMouseCursorShape()
3487 Q_Q(QQuickTextEdit);
3488 q->setCursor(q->isReadOnly() && !q->selectByMouse() ? Qt::ArrowCursor : Qt::IBeamCursor);
3493
3494
3495
3496
3497
3498
3499
3500
3501
3504
3505
3506
3507
3508
3511
3512
3513
3514
3515
3516
3517
3518
3519
3522
3523
3524
3525
3526
3527
3528
3530QString QQuickTextEdit::hoveredLink()
const
3532 Q_D(
const QQuickTextEdit);
3533 if (
const_cast<QQuickTextEditPrivate *>(d)->isLinkHoveredConnected()) {
3534 return d->control->hoveredLink();
3536#if QT_CONFIG(cursor)
3537 if (QQuickWindow *wnd = window()) {
3538 QPointF pos = QCursor::pos(wnd->screen()) - wnd->position() - mapToScene(QPointF(0, 0));
3539 return d->control->anchorAt(pos);
3546void QQuickTextEdit::hoverEnterEvent(QHoverEvent *event)
3548 Q_D(QQuickTextEdit);
3549 if (d->isLinkHoveredConnected())
3550 d->control->processEvent(event, QPointF(-d->xoff, -d->yoff));
3554void QQuickTextEdit::hoverMoveEvent(QHoverEvent *event)
3556 Q_D(QQuickTextEdit);
3557 if (d->isLinkHoveredConnected())
3558 d->control->processEvent(event, QPointF(-d->xoff, -d->yoff));
3562void QQuickTextEdit::hoverLeaveEvent(QHoverEvent *event)
3564 Q_D(QQuickTextEdit);
3565 if (d->isLinkHoveredConnected())
3566 d->control->processEvent(event, QPointF(-d->xoff, -d->yoff));
3571
3572
3573
3574
3575
3576
3577
3578
3579void QQuickTextEdit::append(
const QString &text)
3581 Q_D(QQuickTextEdit);
3582 QTextCursor cursor(d->document);
3583 cursor.beginEditBlock();
3584 cursor.movePosition(QTextCursor::End);
3586 if (!d->document->isEmpty())
3587 cursor.insertBlock();
3589 if (d->format == RichText || (d->format == AutoText && Qt::mightBeRichText(text))) {
3590#if QT_CONFIG(texthtmlparser)
3591 cursor.insertHtml(text);
3593 cursor.insertText(text);
3595 }
else if (d->format == MarkdownText) {
3596#if QT_CONFIG(textmarkdownreader)
3597 cursor.insertMarkdown(text);
3599 cursor.insertText(text);
3602 cursor.insertText(text);
3605 cursor.endEditBlock();
3606 d->control->updateCursorRectangle(
false);
3610
3611
3612
3613
3614
3615
3616
3617
3618QString QQuickTextEdit::linkAt(qreal x, qreal y)
const
3620 Q_D(
const QQuickTextEdit);
3621 return d->control->anchorAt(QPointF(x + topPadding(), y + leftPadding()));
3625
3626
3627
3628
3629
3630
3631
3632
3633
3634
3635qreal QQuickTextEdit::padding()
const
3637 Q_D(
const QQuickTextEdit);
3638 return d->padding();
3641void QQuickTextEdit::setPadding(qreal padding)
3643 Q_D(QQuickTextEdit);
3644 if (qFuzzyCompare(d->padding(), padding))
3647 d->extra.value().padding = padding;
3649 if (isComponentComplete()) {
3650 d->updateType = QQuickTextEditPrivate::UpdatePaintNode;
3653 emit paddingChanged();
3654 if (!d->extra.isAllocated() || !d->extra->explicitTopPadding)
3655 emit topPaddingChanged();
3656 if (!d->extra.isAllocated() || !d->extra->explicitLeftPadding)
3657 emit leftPaddingChanged();
3658 if (!d->extra.isAllocated() || !d->extra->explicitRightPadding)
3659 emit rightPaddingChanged();
3660 if (!d->extra.isAllocated() || !d->extra->explicitBottomPadding)
3661 emit bottomPaddingChanged();
3664void QQuickTextEdit::resetPadding()
3669qreal QQuickTextEdit::topPadding()
const
3671 Q_D(
const QQuickTextEdit);
3672 if (d->extra.isAllocated() && d->extra->explicitTopPadding)
3673 return d->extra->topPadding;
3674 return d->padding();
3677void QQuickTextEdit::setTopPadding(qreal padding)
3679 Q_D(QQuickTextEdit);
3680 d->setTopPadding(padding);
3683void QQuickTextEdit::resetTopPadding()
3685 Q_D(QQuickTextEdit);
3686 d->setTopPadding(0,
true);
3689qreal QQuickTextEdit::leftPadding()
const
3691 Q_D(
const QQuickTextEdit);
3692 if (d->extra.isAllocated() && d->extra->explicitLeftPadding)
3693 return d->extra->leftPadding;
3694 return d->padding();
3697void QQuickTextEdit::setLeftPadding(qreal padding)
3699 Q_D(QQuickTextEdit);
3700 d->setLeftPadding(padding);
3703void QQuickTextEdit::resetLeftPadding()
3705 Q_D(QQuickTextEdit);
3706 d->setLeftPadding(0,
true);
3709qreal QQuickTextEdit::rightPadding()
const
3711 Q_D(
const QQuickTextEdit);
3712 if (d->extra.isAllocated() && d->extra->explicitRightPadding)
3713 return d->extra->rightPadding;
3714 return d->padding();
3717void QQuickTextEdit::setRightPadding(qreal padding)
3719 Q_D(QQuickTextEdit);
3720 d->setRightPadding(padding);
3723void QQuickTextEdit::resetRightPadding()
3725 Q_D(QQuickTextEdit);
3726 d->setRightPadding(0,
true);
3729qreal QQuickTextEdit::bottomPadding()
const
3731 Q_D(
const QQuickTextEdit);
3732 if (d->extra.isAllocated() && d->extra->explicitBottomPadding)
3733 return d->extra->bottomPadding;
3734 return d->padding();
3737void QQuickTextEdit::setBottomPadding(qreal padding)
3739 Q_D(QQuickTextEdit);
3740 d->setBottomPadding(padding);
3743void QQuickTextEdit::resetBottomPadding()
3745 Q_D(QQuickTextEdit);
3746 d->setBottomPadding(0,
true);
3750
3751
3752
3753
3754
3755
3756
3757int QQuickTextEdit::tabStopDistance()
const
3759 Q_D(
const QQuickTextEdit);
3760 return d->document->defaultTextOption().tabStopDistance();
3763void QQuickTextEdit::setTabStopDistance(qreal distance)
3765 Q_D(QQuickTextEdit);
3766 QTextOption textOptions = d->document->defaultTextOption();
3767 if (textOptions.tabStopDistance() == distance)
3770 textOptions.setTabStopDistance(distance);
3771 d->document->setDefaultTextOption(textOptions);
3772 emit tabStopDistanceChanged(distance);
3776
3777
3778
3779
3780
3781
3782
3783
3784
3785
3786void QQuickTextEdit::clear()
3788 Q_D(QQuickTextEdit);
3789 d->resetInputMethod();
3790 d->control->clear();
3793#ifndef QT_NO_DEBUG_STREAM
3796 QDebugStateSaver saver(debug);
3798 debug <<
"Node(startPos:" << n.m_startPos <<
"dirty:" << n.m_dirty << n.m_node <<
')';