70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
93
94
95
96
97
98
104#if !defined(QQUICKTEXT_LARGETEXT_THRESHOLD)
105 #define QQUICKTEXT_LARGETEXT_THRESHOLD 10000
111 class RootNode :
public QSGTransformNode
114 RootNode() : cursorNode(
nullptr), frameDecorationsNode(
nullptr)
117 void resetFrameDecorations(QSGInternalTextNode* newNode)
119 if (frameDecorationsNode) {
120 removeChildNode(frameDecorationsNode);
121 delete frameDecorationsNode;
123 frameDecorationsNode = newNode;
124 newNode->setFlag(QSGNode::OwnedByParent);
127 void resetCursorNode(QSGInternalRectangleNode* newNode)
130 removeChildNode(cursorNode);
132 cursorNode = newNode;
134 appendChildNode(cursorNode);
135 cursorNode->setFlag(QSGNode::OwnedByParent);
139 QSGInternalRectangleNode *cursorNode;
140 QSGInternalTextNode* frameDecorationsNode;
145QQuickTextEdit::QQuickTextEdit(QQuickItem *parent)
146: QQuickImplicitSizeItem(*(
new QQuickTextEditPrivate), parent)
152QQuickTextEdit::~QQuickTextEdit()
155 qDeleteAll(d->pixmapsInProgress);
158QQuickTextEdit::QQuickTextEdit(QQuickTextEditPrivate &dd, QQuickItem *parent)
159: QQuickImplicitSizeItem(dd, parent)
165QString QQuickTextEdit::text()
const
167 Q_D(
const QQuickTextEdit);
168 if (!d->textCached && isComponentComplete()) {
169 QQuickTextEditPrivate *d =
const_cast<QQuickTextEditPrivate *>(d_func());
170#if QT_CONFIG(texthtmlparser)
172 d->text = d->control->toHtml();
175#if QT_CONFIG(textmarkdownwriter)
177 d->text = d->control->toMarkdown();
180 d->text = d->control->toPlainText();
181 d->textCached =
true;
187
188
189
190
191
192
195
196
197
198
199
200
201
202
206
207
208
209
212
213
214
215
218
219
220
221
224
225
226
227
230
231
232
233
236
237
238
239
242
243
244
245
246
247
248
249
252
253
254
255
256
257
260
261
262
263
264
265
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
285
286
287
288
289
290
291
294
295
296
297
298
301
302
303
304
305
308
309
310
311
312
315
316
317
318
319
322
323
324
325
326
329
330
331
332
333
336
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
364void QQuickTextEdit::setText(
const QString &text)
367 if (QQuickTextEdit::text() == text)
370 d->richText = d->format == RichText || (d->format == AutoText && Qt::mightBeRichText(text));
371 d->markdownText = d->format == MarkdownText;
372 if (!isComponentComplete()) {
374 }
else if (d->richText) {
375#if QT_CONFIG(texthtmlparser)
376 d->control->setHtml(text);
378 d->control->setPlainText(text);
380 }
else if (d->markdownText) {
381 d->control->setMarkdownText(text);
383 d->control->setPlainText(text);
385 setFlag(QQuickItem::ItemObservesViewport, text.size() > QQuickTextEditPrivate::largeTextSizeThreshold);
388void QQuickTextEdit::invalidate()
390 QMetaObject::invokeMethod(
this, &QQuickTextEdit::q_invalidate);
393void QQuickTextEdit::q_invalidate()
396 if (isComponentComplete()) {
397 if (d->document !=
nullptr)
398 d->document->markContentsDirty(0, d->document->characterCount());
399 invalidateFontCaches();
400 d->updateType = QQuickTextEditPrivate::UpdateAll;
406
407
408
409
410
411
412
413
414
415
416
417QString QQuickTextEdit::preeditText()
const
419 Q_D(
const QQuickTextEdit);
420 return d->control->preeditText();
424
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
477QQuickTextEdit::TextFormat QQuickTextEdit::textFormat()
const
479 Q_D(
const QQuickTextEdit);
483void QQuickTextEdit::setTextFormat(TextFormat format)
486 if (format == d->format)
489 auto mightBeRichText = [
this]() {
490 return Qt::mightBeRichText(text());
493 auto findSourceFormat = [d, mightBeRichText](Qt::TextFormat detectedFormat) {
494 if (d->format == PlainText)
496 if (d->richText)
return RichText;
497 if (d->markdownText)
return MarkdownText;
498 if (detectedFormat == Qt::AutoText && mightBeRichText())
503 auto findDestinationFormat = [format, mightBeRichText](Qt::TextFormat detectedFormat, TextFormat sourceFormat) {
504 if (format == AutoText) {
505 if (detectedFormat == Qt::MarkdownText || (detectedFormat == Qt::AutoText && sourceFormat == MarkdownText))
507 if (detectedFormat == Qt::RichText || (detectedFormat == Qt::AutoText && (sourceFormat == RichText || mightBeRichText())))
514 bool textCachedChanged =
false;
515 bool converted =
false;
517 if (isComponentComplete()) {
518 Qt::TextFormat detectedFormat = Qt::AutoText;
519 if (d->quickDocument) {
522 detectedFormat = QQuickTextDocumentPrivate::get(d->quickDocument)->detectedFormat;
525 const TextFormat sourceFormat = findSourceFormat(detectedFormat);
526 const TextFormat destinationFormat = findDestinationFormat(detectedFormat, sourceFormat);
528 d->richText = destinationFormat == RichText;
529 d->markdownText = destinationFormat == MarkdownText;
532 if (format != PlainText && (sourceFormat != destinationFormat)) {
533 d->textCached =
false;
534 textCachedChanged =
true;
537 switch (destinationFormat) {
539#if QT_CONFIG(texthtmlparser)
540 if (sourceFormat == RichText) {
544 d->control->setPlainText(d->textCached ? d->text : d->control->toHtml());
548#if QT_CONFIG(textmarkdownwriter) && QT_CONFIG(textmarkdownreader)
549 if (sourceFormat == MarkdownText) {
553 d->control->setPlainText(d->textCached ? d->text : d->control->toMarkdown());
559#if QT_CONFIG(texthtmlparser)
560 switch (sourceFormat) {
563 d->control->setHtml(d->control->toHtml());
569 d->control->setHtml(d->textCached ? d->text : d->control->toPlainText());
579#if QT_CONFIG(textmarkdownwriter) && QT_CONFIG(textmarkdownreader)
580 switch (sourceFormat) {
583 d->control->setMarkdownText(d->control->toMarkdown());
589 d->control->setMarkdownText(d->textCached ? d->text : d->control->toPlainText());
605 d->richText = format == RichText || (format == AutoText && (d->richText || mightBeRichText()));
606 d->markdownText = format == MarkdownText;
609 qCDebug(lcTextEdit) << d->format <<
"->" << format
610 <<
"rich?" << d->richText <<
"md?" << d->markdownText
611 <<
"converted?" << converted <<
"cache invalidated?" << textCachedChanged;
614 d->control->setAcceptRichText(d->format != PlainText);
615 emit textFormatChanged(d->format);
616 if (textCachedChanged)
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645QQuickTextEdit::RenderType QQuickTextEdit::renderType()
const
647 Q_D(
const QQuickTextEdit);
648 return d->renderType;
651void QQuickTextEdit::setRenderType(QQuickTextEdit::RenderType renderType)
654 if (d->renderType == renderType)
657 d->renderType = renderType;
658 emit renderTypeChanged();
659 d->updateDefaultTextOption();
661 if (isComponentComplete())
665QFont QQuickTextEdit::font()
const
667 Q_D(
const QQuickTextEdit);
668 return d->sourceFont;
671void QQuickTextEdit::setFont(
const QFont &font)
674 if (d->sourceFont == font)
677 d->sourceFont = font;
678 QFont oldFont = d->font;
680 if (d->font.pointSizeF() != -1) {
682 qreal size = qRound(d->font.pointSizeF()*2.0);
683 d->font.setPointSizeF(size/2.0);
686 if (oldFont != d->font) {
687 d->document->setDefaultFont(d->font);
689 d->cursorItem->setHeight(QFontMetrics(d->font).height());
690 moveCursorDelegate();
693 updateWholeDocument();
695 updateInputMethod(Qt::ImCursorRectangle | Qt::ImAnchorRectangle | Qt::ImFont);
698 emit fontChanged(d->sourceFont);
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716QColor QQuickTextEdit::color()
const
718 Q_D(
const QQuickTextEdit);
722void QQuickTextEdit::setColor(
const QColor &color)
725 if (d->color == color)
729 updateWholeDocument();
730 emit colorChanged(d->color);
734
735
736
737
738QColor QQuickTextEdit::selectionColor()
const
740 Q_D(
const QQuickTextEdit);
741 return d->selectionColor;
744void QQuickTextEdit::setSelectionColor(
const QColor &color)
747 if (d->selectionColor == color)
750 d->selectionColor = color;
751 updateWholeDocument();
752 emit selectionColorChanged(d->selectionColor);
756
757
758
759
760QColor QQuickTextEdit::selectedTextColor()
const
762 Q_D(
const QQuickTextEdit);
763 return d->selectedTextColor;
766void QQuickTextEdit::setSelectedTextColor(
const QColor &color)
769 if (d->selectedTextColor == color)
772 d->selectedTextColor = color;
773 updateWholeDocument();
774 emit selectedTextColorChanged(d->selectedTextColor);
778
779
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
809QQuickTextEdit::HAlignment QQuickTextEdit::hAlign()
const
811 Q_D(
const QQuickTextEdit);
815void QQuickTextEdit::setHAlign(HAlignment align)
819 if (d->setHAlign(align,
true) && isComponentComplete()) {
820 d->updateDefaultTextOption();
822 updateWholeDocument();
826void QQuickTextEdit::resetHAlign()
829 d->hAlignImplicit =
true;
830 if (d->determineHorizontalAlignment() && isComponentComplete()) {
831 d->updateDefaultTextOption();
836QQuickTextEdit::HAlignment QQuickTextEdit::effectiveHAlign()
const
838 Q_D(
const QQuickTextEdit);
839 QQuickTextEdit::HAlignment effectiveAlignment = d->hAlign;
840 if (!d->hAlignImplicit && d->effectiveLayoutMirror) {
842 case QQuickTextEdit::AlignLeft:
843 effectiveAlignment = QQuickTextEdit::AlignRight;
845 case QQuickTextEdit::AlignRight:
846 effectiveAlignment = QQuickTextEdit::AlignLeft;
852 return effectiveAlignment;
855bool QQuickTextEditPrivate::setHAlign(QQuickTextEdit::HAlignment align,
bool forceAlign)
858 if (hAlign == align && !forceAlign)
861 const bool wasImplicit = hAlignImplicit;
862 const auto oldEffectiveHAlign = q->effectiveHAlign();
864 hAlignImplicit = !forceAlign;
865 if (hAlign != align) {
867 emit q->horizontalAlignmentChanged(align);
870 if (q->effectiveHAlign() != oldEffectiveHAlign) {
871 emit q->effectiveHorizontalAlignmentChanged();
875 if (forceAlign && wasImplicit) {
878 emit q->effectiveHorizontalAlignmentChanged();
883Qt::LayoutDirection QQuickTextEditPrivate::textDirection(
const QString &text)
const
885 const QChar *character = text.constData();
886 while (!character->isNull()) {
887 switch (character->direction()) {
889 return Qt::LeftToRight;
893 return Qt::RightToLeft;
899 return Qt::LayoutDirectionAuto;
902bool QQuickTextEditPrivate::determineHorizontalAlignment()
905 if (!hAlignImplicit || !q->isComponentComplete())
908 Qt::LayoutDirection direction = contentDirection;
910 if (direction == Qt::LayoutDirectionAuto) {
911 QTextBlock block = control->textCursor().block();
914 direction = textDirection(block.layout()->preeditAreaText());
916 if (direction == Qt::LayoutDirectionAuto)
917 direction = qGuiApp->inputMethod()->inputDirection();
920 const auto implicitHAlign = direction == Qt::RightToLeft ?
921 QQuickTextEdit::AlignRight : QQuickTextEdit::AlignLeft;
922 return setHAlign(implicitHAlign);
925void QQuickTextEditPrivate::mirrorChange()
928 if (q->isComponentComplete()) {
929 if (!hAlignImplicit && (hAlign == QQuickTextEdit::AlignRight || hAlign == QQuickTextEdit::AlignLeft)) {
930 updateDefaultTextOption();
932 q->updateWholeDocument();
933 emit q->effectiveHorizontalAlignmentChanged();
938bool QQuickTextEditPrivate::transformChanged(QQuickItem *transformedItem)
941 qCDebug(lcVP) << q <<
"sees that" << transformedItem <<
"moved in VP" << q->clipRect();
946 if (flags & QQuickItem::ItemObservesViewport) {
947 if (QQuickItem *viewport = q->viewportItem()) {
948 QRectF vp = q->mapRectFromItem(viewport, viewport->clipRect());
949 if (!(vp.top() > renderedRegion.top() && vp.bottom() < renderedRegion.bottom())) {
950 qCDebug(lcVP) <<
"viewport" << vp <<
"now goes beyond rendered region" << renderedRegion <<
"; updating";
951 q->updateWholeDocument();
953 const bool textCursorVisible = cursorVisible && q->cursorRectangle().intersects(vp);
955 cursorItem->setVisible(textCursorVisible);
957 control->setCursorVisible(textCursorVisible);
960 return QQuickImplicitSizeItemPrivate::transformChanged(transformedItem);
964Qt::InputMethodHints QQuickTextEditPrivate::effectiveInputMethodHints()
const
966 return inputMethodHints | Qt::ImhMultiLine;
970#if QT_CONFIG(accessibility)
971void QQuickTextEditPrivate::accessibilityActiveChanged(
bool active)
977 if (QQuickAccessibleAttached *accessibleAttached = qobject_cast<QQuickAccessibleAttached *>(
978 qmlAttachedPropertiesObject<QQuickAccessibleAttached>(q,
true))) {
979 accessibleAttached->setRole(effectiveAccessibleRole());
980 accessibleAttached->set_readOnly(q->isReadOnly());
984QAccessible::Role QQuickTextEditPrivate::accessibleRole()
const
986 return QAccessible::EditableText;
990void QQuickTextEditPrivate::setTopPadding(qreal value,
bool reset)
993 qreal oldPadding = q->topPadding();
994 if (!reset || extra.isAllocated()) {
995 extra.value().topPadding = value;
996 extra.value().explicitTopPadding = !reset;
998 if ((!reset && !qFuzzyCompare(oldPadding, value)) || (reset && !qFuzzyCompare(oldPadding, padding()))) {
1000 q->updateWholeDocument();
1001 emit q->topPaddingChanged();
1005void QQuickTextEditPrivate::setLeftPadding(qreal value,
bool reset)
1007 Q_Q(QQuickTextEdit);
1008 qreal oldPadding = q->leftPadding();
1009 if (!reset || extra.isAllocated()) {
1010 extra.value().leftPadding = value;
1011 extra.value().explicitLeftPadding = !reset;
1013 if ((!reset && !qFuzzyCompare(oldPadding, value)) || (reset && !qFuzzyCompare(oldPadding, padding()))) {
1015 q->updateWholeDocument();
1016 emit q->leftPaddingChanged();
1020void QQuickTextEditPrivate::setRightPadding(qreal value,
bool reset)
1022 Q_Q(QQuickTextEdit);
1023 qreal oldPadding = q->rightPadding();
1024 if (!reset || extra.isAllocated()) {
1025 extra.value().rightPadding = value;
1026 extra.value().explicitRightPadding = !reset;
1028 if ((!reset && !qFuzzyCompare(oldPadding, value)) || (reset && !qFuzzyCompare(oldPadding, padding()))) {
1030 q->updateWholeDocument();
1031 emit q->rightPaddingChanged();
1035void QQuickTextEditPrivate::setBottomPadding(qreal value,
bool reset)
1037 Q_Q(QQuickTextEdit);
1038 qreal oldPadding = q->bottomPadding();
1039 if (!reset || extra.isAllocated()) {
1040 extra.value().bottomPadding = value;
1041 extra.value().explicitBottomPadding = !reset;
1043 if ((!reset && !qFuzzyCompare(oldPadding, value)) || (reset && !qFuzzyCompare(oldPadding, padding()))) {
1045 q->updateWholeDocument();
1046 emit q->bottomPaddingChanged();
1050bool QQuickTextEditPrivate::isImplicitResizeEnabled()
const
1052 return !extra.isAllocated() || extra->implicitResize;
1055void QQuickTextEditPrivate::setImplicitResizeEnabled(
bool enabled)
1058 extra.value().implicitResize =
false;
1059 else if (extra.isAllocated())
1060 extra->implicitResize =
true;
1063QQuickTextEdit::VAlignment QQuickTextEdit::vAlign()
const
1065 Q_D(
const QQuickTextEdit);
1069void QQuickTextEdit::setVAlign(QQuickTextEdit::VAlignment alignment)
1071 Q_D(QQuickTextEdit);
1072 if (alignment == d->vAlign)
1074 d->vAlign = alignment;
1075 d->updateDefaultTextOption();
1077 moveCursorDelegate();
1078 emit verticalAlignmentChanged(d->vAlign);
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101QQuickTextEdit::WrapMode QQuickTextEdit::wrapMode()
const
1103 Q_D(
const QQuickTextEdit);
1107void QQuickTextEdit::setWrapMode(WrapMode mode)
1109 Q_D(QQuickTextEdit);
1110 if (mode == d->wrapMode)
1113 d->updateDefaultTextOption();
1115 emit wrapModeChanged();
1119
1120
1121
1122
1123int QQuickTextEdit::lineCount()
const
1125 Q_D(
const QQuickTextEdit);
1126 return d->lineCount;
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1141int QQuickTextEdit::length()
const
1143 Q_D(
const QQuickTextEdit);
1145 return qMax(0, d->document->characterCount() - 1);
1149
1150
1151
1152
1153
1154qreal QQuickTextEdit::contentWidth()
const
1156 Q_D(
const QQuickTextEdit);
1157 return d->contentSize.width();
1161
1162
1163
1164
1165
1166qreal QQuickTextEdit::contentHeight()
const
1168 Q_D(
const QQuickTextEdit);
1169 return d->contentSize.height();
1173
1174
1175
1176
1177
1178
1179
1181QUrl QQuickTextEdit::baseUrl()
const
1183 Q_D(
const QQuickTextEdit);
1184 if (d->baseUrl.isEmpty()) {
1185 if (QQmlContext *context = qmlContext(
this))
1186 const_cast<QQuickTextEditPrivate *>(d)->baseUrl = context->baseUrl();
1191void QQuickTextEdit::setBaseUrl(
const QUrl &url)
1193 Q_D(QQuickTextEdit);
1194 if (baseUrl() != url) {
1197 d->document->setBaseUrl(url);
1198 emit baseUrlChanged();
1202void QQuickTextEdit::resetBaseUrl()
1204 if (QQmlContext *context = qmlContext(
this))
1205 setBaseUrl(context->baseUrl());
1211
1212
1213
1214
1215
1216
1217QRectF QQuickTextEdit::positionToRectangle(
int pos)
const
1219 Q_D(
const QQuickTextEdit);
1220 QTextCursor c(d->document);
1222 return d->control->cursorRect(c).translated(d->xoff, d->yoff);
1227
1228
1229
1230
1231
1232
1233
1234int QQuickTextEdit::positionAt(qreal x, qreal y)
const
1236 Q_D(
const QQuickTextEdit);
1240 int r = d->document->documentLayout()->hitTest(QPointF(x, y), Qt::FuzzyHit);
1242 QTextCursor cursor = d->control->textCursor();
1243 if (r > cursor.position()) {
1247 QTextLayout *layout = cursor.block().layout();
1248 const int preeditLength = layout
1249 ? layout->preeditAreaText().size()
1251 if (preeditLength > 0
1252 && d->document->documentLayout()->blockBoundingRect(cursor.block()).contains(x, y)) {
1253 r = r > cursor.position() + preeditLength
1255 : cursor.position();
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272QQuickTextSelection *QQuickTextEdit::cursorSelection()
const
1274 Q_D(
const QQuickTextEdit);
1275 if (!d->cursorSelection)
1276 d->cursorSelection =
new QQuickTextSelection(
const_cast<QQuickTextEdit *>(
this));
1277 return d->cursorSelection;
1281
1282
1283
1284
1285
1286
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
1316void QQuickTextEdit::moveCursorSelection(
int pos)
1319 Q_D(QQuickTextEdit);
1320 QTextCursor cursor = d->control->textCursor();
1321 if (cursor.position() == pos)
1323 cursor.setPosition(pos, QTextCursor::KeepAnchor);
1324 d->control->setTextCursor(cursor);
1327void QQuickTextEdit::moveCursorSelection(
int pos, SelectionMode mode)
1329 Q_D(QQuickTextEdit);
1330 QTextCursor cursor = d->control->textCursor();
1331 if (cursor.position() == pos)
1333 if (mode == SelectCharacters) {
1334 cursor.setPosition(pos, QTextCursor::KeepAnchor);
1335 }
else if (cursor.anchor() < pos || (cursor.anchor() == pos && cursor.position() < pos)) {
1336 if (cursor.anchor() > cursor.position()) {
1337 cursor.setPosition(cursor.anchor(), QTextCursor::MoveAnchor);
1338 cursor.movePosition(QTextCursor::StartOfWord, QTextCursor::KeepAnchor);
1339 if (cursor.position() == cursor.anchor())
1340 cursor.movePosition(QTextCursor::PreviousWord, QTextCursor::MoveAnchor);
1342 cursor.setPosition(cursor.position(), QTextCursor::MoveAnchor);
1344 cursor.setPosition(cursor.anchor(), QTextCursor::MoveAnchor);
1345 cursor.movePosition(QTextCursor::StartOfWord, QTextCursor::MoveAnchor);
1348 cursor.setPosition(pos, QTextCursor::KeepAnchor);
1349 cursor.movePosition(QTextCursor::StartOfWord, QTextCursor::KeepAnchor);
1350 if (cursor.position() != pos)
1351 cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor);
1352 }
else if (cursor.anchor() > pos || (cursor.anchor() == pos && cursor.position() > pos)) {
1353 if (cursor.anchor() < cursor.position()) {
1354 cursor.setPosition(cursor.anchor(), QTextCursor::MoveAnchor);
1355 cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::MoveAnchor);
1357 cursor.setPosition(cursor.anchor(), QTextCursor::MoveAnchor);
1358 cursor.movePosition(QTextCursor::PreviousCharacter, QTextCursor::KeepAnchor);
1359 cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor);
1360 if (cursor.position() != cursor.anchor()) {
1361 cursor.setPosition(cursor.anchor(), QTextCursor::MoveAnchor);
1362 cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::MoveAnchor);
1366 cursor.setPosition(pos, QTextCursor::KeepAnchor);
1367 cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor);
1368 if (cursor.position() != pos) {
1369 cursor.movePosition(QTextCursor::PreviousCharacter, QTextCursor::KeepAnchor);
1370 cursor.movePosition(QTextCursor::StartOfWord, QTextCursor::KeepAnchor);
1373 d->control->setTextCursor(cursor);
1377
1378
1379
1380
1381
1382
1383bool QQuickTextEdit::isCursorVisible()
const
1385 Q_D(
const QQuickTextEdit);
1386 return d->cursorVisible;
1389void QQuickTextEdit::setCursorVisible(
bool on)
1391 Q_D(QQuickTextEdit);
1392 if (d->cursorVisible == on)
1394 d->cursorVisible = on;
1395 if (on && isComponentComplete())
1396 QQuickTextUtil::createCursor(d);
1397 if (!on && !d->persistentSelection)
1398 d->control->setCursorIsFocusIndicator(
true);
1399 d->control->setCursorVisible(on);
1400 emit cursorVisibleChanged(d->cursorVisible);
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415int QQuickTextEdit::cursorPosition()
const
1417 Q_D(
const QQuickTextEdit);
1418 return d->control->textCursor().position();
1421void QQuickTextEdit::setCursorPosition(
int pos)
1423 Q_D(QQuickTextEdit);
1424 if (pos < 0 || pos >= d->document->characterCount())
1426 QTextCursor cursor = d->control->textCursor();
1427 if (cursor.position() == pos && cursor.anchor() == pos)
1429 cursor.setPosition(pos);
1430 d->control->setTextCursor(cursor);
1431 d->control->updateCursorRectangle(
true);
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447QQmlComponent* QQuickTextEdit::cursorDelegate()
const
1449 Q_D(
const QQuickTextEdit);
1450 return d->cursorComponent;
1453void QQuickTextEdit::setCursorDelegate(QQmlComponent* c)
1455 Q_D(QQuickTextEdit);
1456 QQuickTextUtil::setCursorDelegate(d, c);
1459void QQuickTextEdit::createCursor()
1461 Q_D(QQuickTextEdit);
1462 d->cursorPending =
true;
1463 QQuickTextUtil::createCursor(d);
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476int QQuickTextEdit::selectionStart()
const
1478 Q_D(
const QQuickTextEdit);
1479 return d->control->textCursor().selectionStart();
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492int QQuickTextEdit::selectionEnd()
const
1494 Q_D(
const QQuickTextEdit);
1495 return d->control->textCursor().selectionEnd();
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512QString QQuickTextEdit::selectedText()
const
1514 Q_D(
const QQuickTextEdit);
1515#if QT_CONFIG(texthtmlparser)
1516 return d->richText || d->markdownText
1517 ? d->control->textCursor().selectedText()
1518 : d->control->textCursor().selection().toPlainText();
1520 return d->control->textCursor().selection().toPlainText();
1525
1526
1527
1528
1529
1530bool QQuickTextEdit::focusOnPress()
const
1532 Q_D(
const QQuickTextEdit);
1533 return d->focusOnPress;
1536void QQuickTextEdit::setFocusOnPress(
bool on)
1538 Q_D(QQuickTextEdit);
1539 if (d->focusOnPress == on)
1541 d->focusOnPress = on;
1542 emit activeFocusOnPressChanged(d->focusOnPress);
1546
1547
1548
1549
1550
1551bool QQuickTextEdit::persistentSelection()
const
1553 Q_D(
const QQuickTextEdit);
1554 return d->persistentSelection;
1557void QQuickTextEdit::setPersistentSelection(
bool on)
1559 Q_D(QQuickTextEdit);
1560 if (d->persistentSelection == on)
1562 d->persistentSelection = on;
1563 emit persistentSelectionChanged(d->persistentSelection);
1567
1568
1569
1570
1571qreal QQuickTextEdit::textMargin()
const
1573 Q_D(
const QQuickTextEdit);
1574 return d->textMargin;
1577void QQuickTextEdit::setTextMargin(qreal margin)
1579 Q_D(QQuickTextEdit);
1580 if (d->textMargin == margin)
1582 d->textMargin = margin;
1583 d->document->setDocumentMargin(d->textMargin);
1584 emit textMarginChanged(d->textMargin);
1588
1589
1590
1591
1592
1593
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
1624Qt::InputMethodHints QQuickTextEdit::inputMethodHints()
const
1629 Q_D(
const QQuickTextEdit);
1630 return d->inputMethodHints;
1634void QQuickTextEdit::setInputMethodHints(Qt::InputMethodHints hints)
1639 Q_D(QQuickTextEdit);
1641 if (hints == d->inputMethodHints)
1644 d->inputMethodHints = hints;
1645 updateInputMethod(Qt::ImHints);
1646 emit inputMethodHintsChanged();
1650void QQuickTextEdit::geometryChange(
const QRectF &newGeometry,
const QRectF &oldGeometry)
1652 Q_D(QQuickTextEdit);
1653 if (!d->inLayout && ((newGeometry.width() != oldGeometry.width())
1654 || (newGeometry.height() != oldGeometry.height()))) {
1656 updateWholeDocument();
1657 if (widthValid() || heightValid())
1658 moveCursorDelegate();
1660 QQuickImplicitSizeItem::geometryChange(newGeometry, oldGeometry);
1663void QQuickTextEdit::itemChange(ItemChange change,
const ItemChangeData &value)
1665 Q_D(QQuickTextEdit);
1668 case ItemDevicePixelRatioHasChanged:
1669 if (d->containsUnscalableGlyphs) {
1674 updateWholeDocument();
1681 QQuickImplicitSizeItem::itemChange(change, value);
1685
1686
1687
1688void QQuickTextEdit::componentComplete()
1690 Q_D(QQuickTextEdit);
1691 QQuickImplicitSizeItem::componentComplete();
1693 const QUrl url = baseUrl();
1694 const QQmlContext *context = qmlContext(
this);
1695 d->document->setBaseUrl(context ? context->resolvedUrl(url) : url);
1696 if (!d->text.isEmpty()) {
1697#if QT_CONFIG(texthtmlparser)
1699 d->control->setHtml(d->text);
1702#if QT_CONFIG(textmarkdownreader)
1703 if (d->markdownText)
1704 d->control->setMarkdownText(d->text);
1707 d->control->setPlainText(d->text);
1711 d->determineHorizontalAlignment();
1712 d->updateDefaultTextOption();
1716 if (d->cursorComponent && isCursorVisible())
1717 QQuickTextUtil::createCursor(d);
1720#if QT_CONFIG(accessibility)
1721 if (QAccessible::isActive())
1722 d->accessibilityActiveChanged(
true);
1726int QQuickTextEdit::resourcesLoading()
const
1728 Q_D(
const QQuickTextEdit);
1729 return d->pixmapsInProgress.size();
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746bool QQuickTextEdit::selectByKeyboard()
const
1748 Q_D(
const QQuickTextEdit);
1749 if (d->selectByKeyboardSet)
1750 return d->selectByKeyboard;
1751 return !isReadOnly();
1754void QQuickTextEdit::setSelectByKeyboard(
bool on)
1756 Q_D(QQuickTextEdit);
1757 bool was = selectByKeyboard();
1758 if (!d->selectByKeyboardSet || was != on) {
1759 d->selectByKeyboardSet =
true;
1760 d->selectByKeyboard = on;
1762 d->control->setTextInteractionFlags(d->control->textInteractionFlags() | Qt::TextSelectableByKeyboard);
1764 d->control->setTextInteractionFlags(d->control->textInteractionFlags() & ~Qt::TextSelectableByKeyboard);
1765 emit selectByKeyboardChanged(on);
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792bool QQuickTextEdit::selectByMouse()
const
1794 Q_D(
const QQuickTextEdit);
1795 return d->selectByMouse;
1798void QQuickTextEdit::setSelectByMouse(
bool on)
1800 Q_D(QQuickTextEdit);
1801 if (d->selectByMouse == on)
1804 d->selectByMouse = on;
1805 setKeepMouseGrab(on);
1807 d->control->setTextInteractionFlags(d->control->textInteractionFlags() | Qt::TextSelectableByMouse);
1809 d->control->setTextInteractionFlags(d->control->textInteractionFlags() & ~Qt::TextSelectableByMouse);
1811#if QT_CONFIG(cursor)
1812 d->updateMouseCursorShape();
1814 emit selectByMouseChanged(on);
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827QQuickTextEdit::SelectionMode QQuickTextEdit::mouseSelectionMode()
const
1829 Q_D(
const QQuickTextEdit);
1830 return d->mouseSelectionMode;
1833void QQuickTextEdit::setMouseSelectionMode(SelectionMode mode)
1835 Q_D(QQuickTextEdit);
1836 if (d->mouseSelectionMode != mode) {
1837 d->mouseSelectionMode = mode;
1838 d->control->setWordSelectionEnabled(mode == SelectWords);
1839 emit mouseSelectionModeChanged(mode);
1844
1845
1846
1847
1848
1849
1850
1851void QQuickTextEdit::setReadOnly(
bool r)
1853 Q_D(QQuickTextEdit);
1854 if (r == isReadOnly())
1858 setFlag(QQuickItem::ItemAcceptsInputMethod, !r);
1860 Qt::TextInteractionFlags flags = Qt::LinksAccessibleByMouse;
1861 if (d->selectByMouse)
1862 flags = flags | Qt::TextSelectableByMouse;
1863 if (d->selectByKeyboardSet && d->selectByKeyboard)
1864 flags = flags | Qt::TextSelectableByKeyboard;
1865 else if (!d->selectByKeyboardSet && !r)
1866 flags = flags | Qt::TextSelectableByKeyboard;
1868 flags = flags | Qt::TextEditable;
1869 d->control->setTextInteractionFlags(flags);
1870 d->control->moveCursor(QTextCursor::End);
1873 updateInputMethod(Qt::ImEnabled);
1875#if QT_CONFIG(cursor)
1876 d->updateMouseCursorShape();
1878 q_canPasteChanged();
1879 emit readOnlyChanged(r);
1880 if (!d->selectByKeyboardSet)
1881 emit selectByKeyboardChanged(!r);
1883 setCursorVisible(
false);
1884 }
else if (hasActiveFocus()) {
1885 setCursorVisible(
true);
1888#if QT_CONFIG(accessibility)
1889 if (QAccessible::isActive()) {
1890 if (QQuickAccessibleAttached *accessibleAttached = QQuickAccessibleAttached::attachedProperties(
this))
1891 accessibleAttached->set_readOnly(r);
1896bool QQuickTextEdit::isReadOnly()
const
1898 Q_D(
const QQuickTextEdit);
1899 return !(d->control->textInteractionFlags() & Qt::TextEditable);
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912QRectF QQuickTextEdit::cursorRectangle()
const
1914 Q_D(
const QQuickTextEdit);
1915 return d->control->cursorRect().translated(d->xoff, d->yoff);
1918bool QQuickTextEdit::event(QEvent *event)
1920 Q_D(QQuickTextEdit);
1921 bool state = QQuickImplicitSizeItem::event(event);
1922 if (event->type() == QEvent::ShortcutOverride && !event->isAccepted()) {
1923 d->control->processEvent(event, QPointF(-d->xoff, -d->yoff));
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943bool QQuickTextEdit::overwriteMode()
const
1945 Q_D(
const QQuickTextEdit);
1946 return d->control->overwriteMode();
1949void QQuickTextEdit::setOverwriteMode(
bool overwrite)
1951 Q_D(QQuickTextEdit);
1952 d->control->setOverwriteMode(overwrite);
1956
1957
1958
1959void QQuickTextEdit::keyPressEvent(QKeyEvent *event)
1961 Q_D(QQuickTextEdit);
1962 d->control->processEvent(event, QPointF(-d->xoff, -d->yoff));
1963 if (!event->isAccepted())
1964 QQuickImplicitSizeItem::keyPressEvent(event);
1968
1969
1970
1971void QQuickTextEdit::keyReleaseEvent(QKeyEvent *event)
1973 Q_D(QQuickTextEdit);
1974 d->control->processEvent(event, QPointF(-d->xoff, -d->yoff));
1975 if (!event->isAccepted())
1976 QQuickImplicitSizeItem::keyReleaseEvent(event);
1980
1981
1982
1983
1984void QQuickTextEdit::deselect()
1986 Q_D(QQuickTextEdit);
1987 QTextCursor c = d->control->textCursor();
1989 d->control->setTextCursor(c);
1993
1994
1995
1996
1997void QQuickTextEdit::selectAll()
1999 Q_D(QQuickTextEdit);
2000 d->control->selectAll();
2004
2005
2006
2007
2008void QQuickTextEdit::selectWord()
2010 Q_D(QQuickTextEdit);
2011 QTextCursor c = d->control->textCursor();
2012 c.select(QTextCursor::WordUnderCursor);
2013 d->control->setTextCursor(c);
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029void QQuickTextEdit::select(
int start,
int end)
2031 Q_D(QQuickTextEdit);
2032 if (start < 0 || end < 0 || start >= d->document->characterCount() || end >= d->document->characterCount())
2034 QTextCursor cursor = d->control->textCursor();
2035 cursor.beginEditBlock();
2036 cursor.setPosition(start, QTextCursor::MoveAnchor);
2037 cursor.setPosition(end, QTextCursor::KeepAnchor);
2038 cursor.endEditBlock();
2039 d->control->setTextCursor(cursor);
2044 updateInputMethod();
2049
2050
2051
2052
2053
2054bool QQuickTextEdit::isRightToLeft(
int start,
int end)
2057 qmlWarning(
this) <<
"isRightToLeft(start, end) called with the end property being smaller than the start.";
2060 return getText(start, end).isRightToLeft();
2064#if QT_CONFIG(clipboard)
2066
2067
2068
2069
2070void QQuickTextEdit::cut()
2072 Q_D(QQuickTextEdit);
2077
2078
2079
2080
2081void QQuickTextEdit::copy()
2083 Q_D(QQuickTextEdit);
2088
2089
2090
2091
2092void QQuickTextEdit::paste()
2094 Q_D(QQuickTextEdit);
2095 d->control->paste();
2101
2102
2103
2104
2105
2106
2108void QQuickTextEdit::undo()
2110 Q_D(QQuickTextEdit);
2115
2116
2117
2118
2120void QQuickTextEdit::redo()
2122 Q_D(QQuickTextEdit);
2127
2128
2129
2130void QQuickTextEdit::mousePressEvent(QMouseEvent *event)
2132 Q_D(QQuickTextEdit);
2133 const bool isMouse = QQuickDeliveryAgentPrivate::isEventFromMouseOrTouchpad(event);
2134 setKeepMouseGrab(d->selectByMouse && isMouse);
2135 d->control->processEvent(event, QPointF(-d->xoff, -d->yoff));
2136 if (d->focusOnPress){
2137 bool hadActiveFocus = hasActiveFocus();
2138 forceActiveFocus(Qt::MouseFocusReason);
2141 if (hasActiveFocus() && hadActiveFocus && !isReadOnly())
2142 qGuiApp->inputMethod()->show();
2144 Q_UNUSED(hadActiveFocus);
2147 if (!event->isAccepted())
2148 QQuickImplicitSizeItem::mousePressEvent(event);
2152
2153
2154
2155void QQuickTextEdit::mouseReleaseEvent(QMouseEvent *event)
2157 Q_D(QQuickTextEdit);
2158 d->control->processEvent(event, QPointF(-d->xoff, -d->yoff));
2160 if (!event->isAccepted())
2161 QQuickImplicitSizeItem::mouseReleaseEvent(event);
2165
2166
2167
2168void QQuickTextEdit::mouseDoubleClickEvent(QMouseEvent *event)
2170 Q_D(QQuickTextEdit);
2171 d->control->processEvent(event, QPointF(-d->xoff, -d->yoff));
2172 if (!event->isAccepted())
2173 QQuickImplicitSizeItem::mouseDoubleClickEvent(event);
2177
2178
2179
2180void QQuickTextEdit::mouseMoveEvent(QMouseEvent *event)
2182 Q_D(QQuickTextEdit);
2183 d->control->processEvent(event, QPointF(-d->xoff, -d->yoff));
2184 if (!event->isAccepted())
2185 QQuickImplicitSizeItem::mouseMoveEvent(event);
2190
2191
2192
2193void QQuickTextEdit::inputMethodEvent(QInputMethodEvent *event)
2195 Q_D(QQuickTextEdit);
2196 const bool wasComposing = isInputMethodComposing();
2197 d->control->processEvent(event, QPointF(-d->xoff, -d->yoff));
2198 setCursorVisible(d->control->cursorVisible());
2199 if (wasComposing != isInputMethodComposing())
2200 emit inputMethodComposingChanged();
2204
2205
2206
2207QVariant QQuickTextEdit::inputMethodQuery(Qt::InputMethodQuery property, QVariant argument)
const
2209 Q_D(
const QQuickTextEdit);
2214 v = (
bool)(flags() & ItemAcceptsInputMethod);
2217 v = (
int)d->effectiveInputMethodHints();
2219 case Qt::ImInputItemClipRectangle:
2220 v = QQuickItem::inputMethodQuery(property);
2222 case Qt::ImReadOnly:
2226 if (property == Qt::ImCursorPosition && !argument.isNull())
2227 argument = QVariant(argument.toPointF() - QPointF(d->xoff, d->yoff));
2228 v = d->control->inputMethodQuery(property, argument);
2229 if (property == Qt::ImCursorRectangle || property == Qt::ImAnchorRectangle)
2230 v = QVariant(v.toRectF().translated(d->xoff, d->yoff));
2237
2238
2239
2240QVariant QQuickTextEdit::inputMethodQuery(Qt::InputMethodQuery property)
const
2242 return inputMethodQuery(property, QVariant());
2246void QQuickTextEdit::triggerPreprocess()
2248 Q_D(QQuickTextEdit);
2249 if (d->updateType == QQuickTextEditPrivate::UpdateNone)
2250 d->updateType = QQuickTextEditPrivate::UpdateOnlyPreprocess;
2256
2257
2258
2259
2260QVariant QQuickTextEdit::loadResource(
int type,
const QUrl &source)
2262 Q_D(QQuickTextEdit);
2263 const QUrl url = d->document->baseUrl().resolved(source);
2264 if (url.isLocalFile()) {
2266 QFileInfo fi(QQmlFile::urlToLocalFileOrQrc(url));
2268 qmlWarning(
this) <<
"Cannot open: " << url.toString();
2274 if (!url.scheme().compare(
"qrc"_L1, Qt::CaseInsensitive)) {
2276 QFile f(QQmlFile::urlToLocalFileOrQrc(url));
2277 if (f.open(QFile::ReadOnly)) {
2278 QByteArray buf = f.readAll();
2281 image.loadFromData(buf);
2282 if (!image.isNull())
2286 qmlWarning(
this) <<
"Cannot read resource: " << f.fileName();
2291 auto existingJobIter = std::find_if(
2292 d->pixmapsInProgress.cbegin(), d->pixmapsInProgress.cend(),
2293 [&url](
const auto *job) {
return job->url() == url; } );
2294 if (existingJobIter != d->pixmapsInProgress.cend()) {
2295 const QQuickPixmap *job = *existingJobIter;
2296 if (job->isError()) {
2297 qmlWarning(
this) << job->error();
2298 d->pixmapsInProgress.erase(existingJobIter);
2302 qCDebug(lcTextEdit) <<
"already downloading" << url;
2304 return job->isReady() ? job->image() : QVariant();
2309 qCDebug(lcTextEdit) <<
"loading" << source <<
"resolved" << url
2310 <<
"type" <<
static_cast<QTextDocument::ResourceType>(type);
2311 QQmlContext *context = qmlContext(
this);
2314 QQuickPixmap *p =
new QQuickPixmap(context->engine(), url, QQuickPixmap::Options{});
2315 p->connectFinished(
this, SLOT(resourceRequestFinished()));
2316 d->pixmapsInProgress.append(p);
2318 return p->isReady() ? p->image() : QVariant();
2322
2323
2324void QQuickTextEdit::resourceRequestFinished()
2326 Q_D(QQuickTextEdit);
2327 for (
auto it = d->pixmapsInProgress.cbegin(); it != d->pixmapsInProgress.cend(); ++it) {
2329 if (job->isError()) {
2331 qCDebug(lcTextEdit) <<
"failed to load (error)" << job->url();
2332 d->document->resource(QTextDocument::ImageResource, job->url());
2336 }
else if (job->isReady()) {
2338 auto res = d->document->resource(QTextDocument::ImageResource, job->url());
2340 qCDebug(lcTextEdit) << (res.isValid() ?
"done downloading" :
"failed to load") << job->url() << job->rect();
2341 d->pixmapsInProgress.erase(it);
2346 if (d->pixmapsInProgress.isEmpty()) {
2354using TextNodeIterator = QQuickTextEditPrivate::TextNodeIterator;
2358 return n1.startPos() < n2.startPos();
2363 QMatrix4x4 transformMatrix;
2364 transformMatrix.translate(topLeft.x(), topLeft.y());
2365 node->setMatrix(transformMatrix);
2369
2370
2371
2372
2373
2374void QQuickTextEdit::invalidateFontCaches()
2376 Q_D(QQuickTextEdit);
2377 if (d->document ==
nullptr)
2381 for (block = d->document->firstBlock(); block.isValid(); block = block.next()) {
2382 if (block.layout() !=
nullptr && block.layout()->engine() !=
nullptr)
2383 block.layout()->engine()->resetFontEngineCache();
2387QTextDocument *QQuickTextEdit::document()
const
2389 Q_D(
const QQuickTextEdit);
2393void QQuickTextEdit::setDocument(QTextDocument *doc)
2395 Q_D(QQuickTextEdit);
2397 std::unique_ptr<QTextDocument> cleanup(d->ownsDocument ? d->document :
nullptr);
2399 d->ownsDocument =
false;
2400 d->control->setDocument(doc);
2410 engine->setDevicePixelRatio(dpr);
2413QSGNode *QQuickTextEdit::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *updatePaintNodeData)
2415 Q_UNUSED(updatePaintNodeData);
2416 Q_D(QQuickTextEdit);
2418 if (d->updateType != QQuickTextEditPrivate::UpdatePaintNode
2419 && d->updateType != QQuickTextEditPrivate::UpdateAll
2420 && oldNode !=
nullptr) {
2422 d->updateType = QQuickTextEditPrivate::UpdateNone;
2426 d->containsUnscalableGlyphs =
false;
2427 if (!oldNode || d->updateType == QQuickTextEditPrivate::UpdateAll) {
2433 d->textNodeMap.clear();
2436 d->updateType = QQuickTextEditPrivate::UpdateNone;
2438 RootNode *rootNode =
static_cast<RootNode *>(oldNode);
2439 TextNodeIterator nodeIterator = d->textNodeMap.begin();
2440 std::optional<
int> firstPosAcrossAllNodes;
2441 if (nodeIterator != d->textNodeMap.end())
2442 firstPosAcrossAllNodes = nodeIterator->startPos();
2444 while (nodeIterator != d->textNodeMap.end() && !nodeIterator->dirty())
2447 const auto dpr = d->effectiveDevicePixelRatio();
2448 QQuickTextNodeEngine engine;
2449 engine.setDevicePixelRatio(dpr);
2450 QQuickTextNodeEngine frameDecorationsEngine;
2451 frameDecorationsEngine.setDevicePixelRatio(dpr);
2453 if (!oldNode || nodeIterator < d->textNodeMap.end() || d->textNodeMap.isEmpty()) {
2456 rootNode =
new RootNode;
2458 int firstDirtyPos = 0;
2459 if (nodeIterator != d->textNodeMap.end()) {
2460 firstDirtyPos = nodeIterator->startPos();
2463 QSGInternalTextNode *firstCleanNode =
nullptr;
2464 auto it = d->textNodeMap.constEnd();
2465 while (it != nodeIterator) {
2469 firstCleanNode = it->textNode();
2472 rootNode->removeChildNode(nodeIterator->textNode());
2473 delete nodeIterator->textNode();
2474 nodeIterator = d->textNodeMap.erase(nodeIterator);
2475 }
while (nodeIterator != d->textNodeMap.constEnd() && nodeIterator->textNode() != firstCleanNode);
2480 if (flags().testFlag(QQuickItem::ItemObservesViewport)) {
2481 viewport = clipRect();
2482 qCDebug(lcVP) <<
"text viewport" << viewport;
2486 rootNode->resetFrameDecorations(d->createTextNode());
2487 resetEngine(&frameDecorationsEngine, d->color, d->selectedTextColor, d->selectionColor, dpr);
2489 QSGInternalTextNode *node =
nullptr;
2491 int currentNodeSize = 0;
2492 int nodeStart = firstDirtyPos;
2493 QPointF basePosition(d->xoff, d->yoff);
2494 QMatrix4x4 basePositionMatrix;
2495 basePositionMatrix.translate(basePosition.x(), basePosition.y());
2496 rootNode->setMatrix(basePositionMatrix);
2499 const TextNode firstCleanNode = (nodeIterator != d->textNodeMap.end()) ? *nodeIterator
2502 QList<QTextFrame *> frames;
2503 frames.append(d->document->rootFrame());
2506 d->firstBlockInViewport = -1;
2507 d->firstBlockPastViewport = -1;
2508 int frameCount = -1;
2509 while (!frames.isEmpty()) {
2510 QTextFrame *textFrame = frames.takeFirst();
2514 qCDebug(lcVP) <<
"frame" << frameCount << textFrame
2515 <<
"from" << positionToRectangle(textFrame->firstPosition()).topLeft()
2516 <<
"to" << positionToRectangle(textFrame->lastPosition()).bottomRight();
2517 frames.append(textFrame->childFrames());
2518 frameDecorationsEngine.addFrameDecorations(d->document, textFrame);
2519 resetEngine(&engine, d->color, d->selectedTextColor, d->selectionColor, dpr);
2521 if (textFrame->firstPosition() > textFrame->lastPosition()
2522 && textFrame->frameFormat().position() != QTextFrameFormat::InFlow) {
2523 node = d->createTextNode();
2524 updateNodeTransform(node, d->document->documentLayout()->frameBoundingRect(textFrame).topLeft());
2525 const int pos = textFrame->firstPosition() - 1;
2526 auto *a =
static_cast<QtPrivate::ProtectedLayoutAccessor *>(d->document->documentLayout());
2527 QTextCharFormat format = a->formatAccessor(pos);
2528 QTextBlock block = textFrame->firstCursorPosition().block();
2529 nodeOffset = d->document->documentLayout()->blockBoundingRect(block).topLeft();
2531 if (!viewport.isNull() && block.layout()) {
2532 QRectF coveredRegion = block.layout()->boundingRect().adjusted(nodeOffset.x(), nodeOffset.y(), nodeOffset.x(), nodeOffset.y());
2533 inView = coveredRegion.bottom() >= viewport.top() && coveredRegion.top() <= viewport.bottom();
2534 qCDebug(lcVP) <<
"non-flow frame" << coveredRegion <<
"in viewport?" << inView;
2537 engine.setCurrentLine(block.layout()->lineForTextPosition(pos - block.position()));
2538 engine.addTextObject(block, QPointF(0, 0), format, QQuickTextNodeEngine::Unselected, d->document,
2539 pos, textFrame->frameFormat().position());
2544 QVarLengthArray<
int, 8> frameBoundaries;
2545 frameBoundaries.reserve(frames.size());
2546 for (QTextFrame *frame : std::as_const(frames))
2547 frameBoundaries.append(frame->firstPosition());
2548 std::sort(frameBoundaries.begin(), frameBoundaries.end());
2550 QTextFrame::iterator it = textFrame->begin();
2551 while (!it.atEnd()) {
2552 QTextBlock block = it.currentBlock();
2553 if (block.position() < firstDirtyPos) {
2558 if (!engine.hasContents())
2559 nodeOffset = d->document->documentLayout()->blockBoundingRect(block).topLeft();
2562 if (!viewport.isNull()) {
2563 QRectF coveredRegion;
2564 if (block.layout()) {
2565 coveredRegion = block.layout()->boundingRect().adjusted(nodeOffset.x(), nodeOffset.y(), nodeOffset.x(), nodeOffset.y());
2566 inView = coveredRegion.bottom() > viewport.top();
2568 const bool potentiallyScrollingBackwards = firstPosAcrossAllNodes && *firstPosAcrossAllNodes == firstDirtyPos;
2569 if (d->firstBlockInViewport < 0 && inView && potentiallyScrollingBackwards) {
2571 if (coveredRegion.top() > viewport.top() + 1) {
2572 qCDebug(lcVP) <<
"checking backwards from block" << block.blockNumber() <<
"@" << nodeOffset.y() << coveredRegion;
2573 while (it != textFrame->begin() && it.currentBlock().layout() &&
2574 it.currentBlock().layout()->boundingRect().top() + nodeOffset.y() > viewport.top()) {
2575 nodeOffset = d->document->documentLayout()->blockBoundingRect(it.currentBlock()).topLeft();
2578 if (!it.currentBlock().layout())
2580 if (Q_LIKELY(it.currentBlock().layout())) {
2581 block = it.currentBlock();
2582 coveredRegion = block.layout()->boundingRect().adjusted(nodeOffset.x(), nodeOffset.y(), nodeOffset.x(), nodeOffset.y());
2583 firstDirtyPos = it.currentBlock().position();
2585 qCWarning(lcVP) <<
"failed to find a text block with layout during back-scrolling";
2588 qCDebug(lcVP) <<
"first block in viewport" << block.blockNumber() <<
"@" << nodeOffset.y() << coveredRegion;
2590 d->renderedRegion = coveredRegion;
2592 if (nodeOffset.y() > viewport.bottom()) {
2594 if (d->firstBlockInViewport >= 0 && d->firstBlockPastViewport < 0) {
2595 qCDebug(lcVP) <<
"first block past viewport" << viewport << block.blockNumber()
2596 <<
"@" << nodeOffset.y() <<
"total region rendered" << d->renderedRegion;
2597 d->firstBlockPastViewport = block.blockNumber();
2601 if (inView && !block.text().isEmpty() && coveredRegion.isValid()) {
2602 d->renderedRegion = d->renderedRegion.united(coveredRegion);
2605 if (!frames.isEmpty())
2606 viewport = viewport.united(d->renderedRegion);
2609 if (inView && d->firstBlockInViewport < 0)
2610 d->firstBlockInViewport = block.blockNumber();
2613 bool createdNodeInView =
false;
2615 if (!engine.hasContents()) {
2617 d->containsUnscalableGlyphs = d->containsUnscalableGlyphs
2618 || node->containsUnscalableGlyphs();
2619 if (!node->parent())
2620 d->addCurrentTextNodeToRoot(&engine, rootNode, node, nodeIterator, nodeStart);
2622 node = d->createTextNode();
2623 createdNodeInView =
true;
2624 updateNodeTransform(node, nodeOffset);
2625 nodeStart = block.position();
2627 engine.addTextBlock(d->document, block, -nodeOffset, d->color, QColor(), selectionStart(), selectionEnd() - 1);
2628 currentNodeSize += block.length();
2631 if ((it.atEnd()) || block.next().position() >= firstCleanNode.startPos())
2633 const auto lowerBound =
2634 std::lower_bound(frameBoundaries.constBegin(),
2635 frameBoundaries.constEnd(), block.next().position());
2636 if (node && (currentNodeSize > nodeBreakingSize || lowerBound == frameBoundaries.constEnd() || *lowerBound > nodeStart)) {
2637 currentNodeSize = 0;
2638 d->containsUnscalableGlyphs = d->containsUnscalableGlyphs
2639 || node->containsUnscalableGlyphs();
2640 if (!node->parent())
2641 d->addCurrentTextNodeToRoot(&engine, rootNode, node, nodeIterator, nodeStart);
2642 if (!createdNodeInView)
2643 node = d->createTextNode();
2644 resetEngine(&engine, d->color, d->selectedTextColor, d->selectionColor, dpr);
2645 nodeStart = block.next().position();
2650 if (Q_LIKELY(node)) {
2651 d->containsUnscalableGlyphs = d->containsUnscalableGlyphs
2652 || node->containsUnscalableGlyphs();
2653 if (Q_LIKELY(!node->parent()))
2654 d->addCurrentTextNodeToRoot(&engine, rootNode, node, nodeIterator, nodeStart);
2657 frameDecorationsEngine.addToSceneGraph(rootNode->frameDecorationsNode, QQuickText::Normal, QColor());
2659 rootNode->prependChildNode(rootNode->frameDecorationsNode);
2661 Q_ASSERT(nodeIterator == d->textNodeMap.end()
2662 || (nodeIterator->textNode() == firstCleanNode.textNode()
2663 && nodeIterator->startPos() == firstCleanNode.startPos()));
2665 if (firstCleanNode.textNode() !=
nullptr) {
2666 QPointF oldOffset = firstCleanNode.textNode()->matrix().map(QPointF(0,0));
2667 QPointF currentOffset = d->document->documentLayout()->blockBoundingRect(
2668 d->document->findBlock(firstCleanNode.startPos())).topLeft();
2669 QPointF delta = currentOffset - oldOffset;
2670 while (nodeIterator != d->textNodeMap.end()) {
2671 QMatrix4x4 transformMatrix = nodeIterator->textNode()->matrix();
2672 transformMatrix.translate(delta.x(), delta.y());
2673 nodeIterator->textNode()->setMatrix(transformMatrix);
2681 std::sort(d->textNodeMap.begin(), d->textNodeMap.end());
2684 if (d->cursorComponent ==
nullptr) {
2685 QSGInternalRectangleNode* cursor =
nullptr;
2686 if (!isReadOnly() && d->cursorVisible && d->control->cursorOn() && d->control->cursorVisible())
2687 cursor = d->sceneGraphContext()->createInternalRectangleNode(d->control->cursorRect(), d->color);
2688 rootNode->resetCursorNode(cursor);
2691 invalidateFontCaches();
2696void QQuickTextEdit::updatePolish()
2698 invalidateFontCaches();
2702
2703
2704
2705
2706
2707bool QQuickTextEdit::canPaste()
const
2709 Q_D(
const QQuickTextEdit);
2710 if (!d->canPasteValid) {
2711 const_cast<QQuickTextEditPrivate *>(d)->canPaste = d->control->canPaste();
2712 const_cast<QQuickTextEditPrivate *>(d)->canPasteValid =
true;
2718
2719
2720
2721
2722
2724bool QQuickTextEdit::canUndo()
const
2726 Q_D(
const QQuickTextEdit);
2727 return d->document->isUndoAvailable();
2731
2732
2733
2734
2735
2737bool QQuickTextEdit::canRedo()
const
2739 Q_D(
const QQuickTextEdit);
2740 return d->document->isRedoAvailable();
2744
2745
2746
2747
2748
2749
2750
2751
2752
2753
2754
2755bool QQuickTextEdit::isInputMethodComposing()
const
2760 Q_D(
const QQuickTextEdit);
2761 return d->control->hasImState();
2765QQuickTextEditPrivate::ExtraData::ExtraData()
2766 : explicitTopPadding(
false)
2767 , explicitLeftPadding(
false)
2768 , explicitRightPadding(
false)
2769 , explicitBottomPadding(
false)
2770 , implicitResize(
true)
2774void QQuickTextEditPrivate::init()
2776 Q_Q(QQuickTextEdit);
2778#if QT_CONFIG(clipboard)
2779 if (QGuiApplication::clipboard()->supportsSelection())
2780 q->setAcceptedMouseButtons(Qt::LeftButton | Qt::MiddleButton);
2783 q->setAcceptedMouseButtons(Qt::LeftButton);
2786 q->setFlag(QQuickItem::ItemAcceptsInputMethod);
2788 q->setFlag(QQuickItem::ItemHasContents);
2790 q->setAcceptHoverEvents(
true);
2792 document =
new QTextDocument(q);
2793 ownsDocument =
true;
2794 auto *imageHandler =
new QQuickTextImageHandler(document);
2795 document->documentLayout()->registerHandler(QTextFormat::ImageObject, imageHandler);
2797 control =
new QQuickTextControl(document, q);
2798 control->setTextInteractionFlags(Qt::LinksAccessibleByMouse | Qt::TextSelectableByMouse | Qt::TextSelectableByKeyboard | Qt::TextEditable);
2799 control->setAcceptRichText(
false);
2800 control->setCursorIsFocusIndicator(
true);
2801 q->setKeepMouseGrab(
true);
2803 qmlobject_connect(control, QQuickTextControl, SIGNAL(updateCursorRequest()), q, QQuickTextEdit, SLOT(updateCursor()));
2804 qmlobject_connect(control, QQuickTextControl, SIGNAL(selectionChanged()), q, QQuickTextEdit, SIGNAL(selectedTextChanged()));
2805 qmlobject_connect(control, QQuickTextControl, SIGNAL(selectionChanged()), q, QQuickTextEdit, SLOT(updateSelection()));
2806 qmlobject_connect(control, QQuickTextControl, SIGNAL(cursorPositionChanged()), q, QQuickTextEdit, SLOT(updateSelection()));
2807 qmlobject_connect(control, QQuickTextControl, SIGNAL(cursorPositionChanged()), q, QQuickTextEdit, SIGNAL(cursorPositionChanged()));
2808 qmlobject_connect(control, QQuickTextControl, SIGNAL(cursorRectangleChanged()), q, QQuickTextEdit, SLOT(moveCursorDelegate()));
2809 qmlobject_connect(control, QQuickTextControl, SIGNAL(linkActivated(QString)), q, QQuickTextEdit, SIGNAL(linkActivated(QString)));
2810 qmlobject_connect(control, QQuickTextControl, SIGNAL(overwriteModeChanged(
bool)), q, QQuickTextEdit, SIGNAL(overwriteModeChanged(
bool)));
2811 qmlobject_connect(control, QQuickTextControl, SIGNAL(textChanged()), q, QQuickTextEdit, SLOT(q_textChanged()));
2812 qmlobject_connect(control, QQuickTextControl, SIGNAL(preeditTextChanged()), q, QQuickTextEdit, SIGNAL(preeditTextChanged()));
2813#if QT_CONFIG(clipboard)
2814 qmlobject_connect(QGuiApplication::clipboard(), QClipboard, SIGNAL(dataChanged()), q, QQuickTextEdit, SLOT(q_canPasteChanged()));
2816 qmlobject_connect(document, QTextDocument, SIGNAL(undoAvailable(
bool)), q, QQuickTextEdit, SIGNAL(canUndoChanged()));
2817 qmlobject_connect(document, QTextDocument, SIGNAL(redoAvailable(
bool)), q, QQuickTextEdit, SIGNAL(canRedoChanged()));
2818 QObject::connect(document, &QTextDocument::contentsChange, q, &QQuickTextEdit::q_contentsChange);
2819 QObject::connect(document->documentLayout(), &QAbstractTextDocumentLayout::updateBlock, q, &QQuickTextEdit::invalidateBlock);
2820 QObject::connect(control, &QQuickTextControl::linkHovered, q, &QQuickTextEdit::q_linkHovered);
2821 QObject::connect(control, &QQuickTextControl::markerHovered, q, &QQuickTextEdit::q_markerHovered);
2823 document->setPageSize(QSizeF(0, 0));
2824 document->setDefaultFont(font);
2825 document->setDocumentMargin(textMargin);
2826 document->setUndoRedoEnabled(
false);
2827 document->setUndoRedoEnabled(
true);
2828 updateDefaultTextOption();
2829 document->setModified(
false);
2831#if QT_CONFIG(cursor)
2832 updateMouseCursorShape();
2834 setSizePolicy(QLayoutPolicy::Expanding, QLayoutPolicy::Expanding);
2837void QQuickTextEditPrivate::resetInputMethod()
2839 Q_Q(QQuickTextEdit);
2840 if (!q->isReadOnly() && q->hasActiveFocus() && qGuiApp)
2841 QGuiApplication::inputMethod()->reset();
2844void QQuickTextEdit::q_textChanged()
2846 Q_D(QQuickTextEdit);
2847 d->textCached =
false;
2848 for (QTextBlock it = d->document->begin(); it != d->document->end(); it = it.next()) {
2849 d->contentDirection = d->textDirection(it.text());
2850 if (d->contentDirection != Qt::LayoutDirectionAuto)
2853 d->determineHorizontalAlignment();
2854 d->updateDefaultTextOption();
2857 markDirtyNodesForRange(0, d->document->characterCount(), 0);
2858 if (isComponentComplete()) {
2860 d->updateType = QQuickTextEditPrivate::UpdatePaintNode;
2865 if (d->control->isBeingEdited())
2869void QQuickTextEdit::markDirtyNodesForRange(
int start,
int end,
int charDelta)
2871 Q_D(QQuickTextEdit);
2875 TextNode dummyNode(start);
2877 const TextNodeIterator textNodeMapBegin = d->textNodeMap.begin();
2878 const TextNodeIterator textNodeMapEnd = d->textNodeMap.end();
2880 TextNodeIterator it = std::lower_bound(textNodeMapBegin, textNodeMapEnd, dummyNode);
2883 if (it != textNodeMapBegin) {
2885 TextNode otherDummy(it->startPos());
2886 it = std::lower_bound(textNodeMapBegin, textNodeMapEnd, otherDummy);
2890 while (it != textNodeMapEnd) {
2891 if (it->startPos() <= end)
2894 it->moveStartPos(charDelta);
2901void QQuickTextEdit::q_contentsChange(
int pos,
int charsRemoved,
int charsAdded)
2903 Q_D(QQuickTextEdit);
2905 const int editRange = pos + qMax(charsAdded, charsRemoved);
2906 const int delta = charsAdded - charsRemoved;
2908 markDirtyNodesForRange(pos, editRange, delta);
2910 if (isComponentComplete()) {
2912 d->updateType = QQuickTextEditPrivate::UpdatePaintNode;
2917void QQuickTextEdit::moveCursorDelegate()
2919 Q_D(QQuickTextEdit);
2921 updateInputMethod();
2923 emit cursorRectangleChanged();
2926 QRectF cursorRect = cursorRectangle();
2927 d->cursorItem->setX(cursorRect.x());
2928 d->cursorItem->setY(cursorRect.y());
2929 d->cursorItem->setHeight(cursorRect.height());
2932void QQuickTextEdit::updateSelection()
2934 Q_D(QQuickTextEdit);
2937 if (d->control->textCursor().hasSelection() || d->hadSelection) {
2938 markDirtyNodesForRange(qMin(d->lastSelectionStart, d->control->textCursor().selectionStart()), qMax(d->control->textCursor().selectionEnd(), d->lastSelectionEnd), 0);
2939 if (isComponentComplete()) {
2941 d->updateType = QQuickTextEditPrivate::UpdatePaintNode;
2946 d->hadSelection = d->control->textCursor().hasSelection();
2948 if (d->lastSelectionStart != d->control->textCursor().selectionStart()) {
2949 d->lastSelectionStart = d->control->textCursor().selectionStart();
2950 emit selectionStartChanged();
2952 if (d->lastSelectionEnd != d->control->textCursor().selectionEnd()) {
2953 d->lastSelectionEnd = d->control->textCursor().selectionEnd();
2954 emit selectionEndChanged();
2958QRectF QQuickTextEdit::boundingRect()
const
2960 Q_D(
const QQuickTextEdit);
2962 QQuickTextUtil::alignedX(d->contentSize.width(), width(), effectiveHAlign()),
2964 d->contentSize.width(),
2965 d->contentSize.height());
2967 int cursorWidth = 1;
2970 else if (!d->document->isEmpty())
2974 r.setRight(r.right() + cursorWidth);
2979QRectF QQuickTextEdit::clipRect()
const
2981 Q_D(
const QQuickTextEdit);
2982 QRectF r = QQuickImplicitSizeItem::clipRect();
2983 int cursorWidth = 1;
2985 cursorWidth = d->cursorItem->width();
2986 if (!d->document->isEmpty())
2991 r.setRight(r.right() + cursorWidth);
2995qreal QQuickTextEditPrivate::getImplicitWidth()
const
2997 Q_Q(
const QQuickTextEdit);
2998 if (!requireImplicitWidth) {
3001 const_cast<QQuickTextEditPrivate*>(
this)->requireImplicitWidth =
true;
3002 const_cast<QQuickTextEdit*>(q)->updateSize();
3004 return implicitWidth;
3009void QQuickTextEdit::updateSize()
3011 Q_D(QQuickTextEdit);
3012 if (!isComponentComplete()) {
3020 if (!d->requireImplicitWidth) {
3021 emit implicitWidthChanged();
3023 if (d->requireImplicitWidth)
3026 if (d->requireImplicitWidth) {
3027 d->document->setTextWidth(-1);
3028 const qreal naturalWidth = d->document->idealWidth();
3029 const bool wasInLayout = d->inLayout;
3031 if (d->isImplicitResizeEnabled())
3032 setImplicitWidth(naturalWidth + leftPadding() + rightPadding());
3033 d->inLayout = wasInLayout;
3037 const qreal newTextWidth = width() - leftPadding() - rightPadding();
3038 if (d->document->textWidth() != newTextWidth)
3039 d->document->setTextWidth(newTextWidth);
3040 }
else if (d->wrapMode == NoWrap) {
3044 const qreal newTextWidth = d->document->idealWidth();
3045 if (d->document->textWidth() != newTextWidth)
3046 d->document->setTextWidth(newTextWidth);
3048 d->document->setTextWidth(-1);
3051 QFontMetricsF fm(d->font);
3052 const qreal newHeight = d->document->isEmpty() ? qCeil(fm.height()) : d->document->size().height();
3053 const qreal newWidth = d->document->idealWidth();
3055 if (d->isImplicitResizeEnabled()) {
3058 setImplicitSize(newWidth + leftPadding() + rightPadding(), newHeight + topPadding() + bottomPadding());
3060 setImplicitHeight(newHeight + topPadding() + bottomPadding());
3063 d->xoff = leftPadding() + qMax(qreal(0), QQuickTextUtil::alignedX(d->document->size().width(), width() - leftPadding() - rightPadding(), effectiveHAlign()));
3064 d->yoff = topPadding() + QQuickTextUtil::alignedY(d->document->size().height(), height() - topPadding() - bottomPadding(), d->vAlign);
3066 qreal baseline = fm.ascent();
3067 QTextBlock firstBlock = d->document->firstBlock();
3068 if (firstBlock.isValid() && firstBlock.layout() !=
nullptr && firstBlock.lineCount() > 0) {
3069 QTextLine firstLine = firstBlock.layout()->lineAt(0);
3070 if (firstLine.isValid())
3071 baseline = firstLine.ascent();
3074 setBaselineOffset(baseline + d->yoff + d->textMargin);
3076 QSizeF size(newWidth, newHeight);
3077 if (d->contentSize != size) {
3078 d->contentSize = size;
3080 const bool wasInResize = d->inResize;
3083 emit contentSizeChanged();
3084 d->inResize = wasInResize;
3089void QQuickTextEdit::updateWholeDocument()
3091 Q_D(QQuickTextEdit);
3092 if (!d->textNodeMap.isEmpty()) {
3093 for (TextNode &node : d->textNodeMap)
3097 if (isComponentComplete()) {
3099 d->updateType = QQuickTextEditPrivate::UpdatePaintNode;
3104void QQuickTextEdit::invalidateBlock(
const QTextBlock &block)
3106 Q_D(QQuickTextEdit);
3107 markDirtyNodesForRange(block.position(), block.position() + block.length(), 0);
3109 if (isComponentComplete()) {
3111 d->updateType = QQuickTextEditPrivate::UpdatePaintNode;
3116void QQuickTextEdit::updateCursor()
3118 Q_D(QQuickTextEdit);
3119 if (isComponentComplete() && isVisible()) {
3121 d->updateType = QQuickTextEditPrivate::UpdatePaintNode;
3126void QQuickTextEdit::q_linkHovered(
const QString &link)
3128 Q_D(QQuickTextEdit);
3129 emit linkHovered(link);
3130#if QT_CONFIG(cursor)
3131 if (link.isEmpty()) {
3132 d->updateMouseCursorShape();
3133 }
else if (cursor().shape() != Qt::PointingHandCursor) {
3134 setCursor(Qt::PointingHandCursor);
3139void QQuickTextEdit::q_markerHovered(
bool hovered)
3141 Q_D(QQuickTextEdit);
3142#if QT_CONFIG(cursor)
3144 d->updateMouseCursorShape();
3145 }
else if (cursor().shape() != Qt::PointingHandCursor) {
3146 setCursor(Qt::PointingHandCursor);
3151void QQuickTextEdit::q_updateAlignment()
3153 Q_D(QQuickTextEdit);
3154 if (d->determineHorizontalAlignment()) {
3155 d->updateDefaultTextOption();
3156 d->xoff = qMax(qreal(0), QQuickTextUtil::alignedX(d->document->size().width(), width(), effectiveHAlign()));
3157 moveCursorDelegate();
3161void QQuickTextEdit::updateTotalLines()
3163 Q_D(QQuickTextEdit);
3167 for (QTextBlock it = d->document->begin(); it != d->document->end(); it = it.next()) {
3168 QTextLayout *layout = it.layout();
3171 subLines += layout->lineCount()-1;
3174 int newTotalLines = d->document->lineCount() + subLines;
3175 if (d->lineCount != newTotalLines) {
3176 d->lineCount = newTotalLines;
3177 emit lineCountChanged();
3181void QQuickTextEditPrivate::updateDefaultTextOption()
3183 Q_Q(QQuickTextEdit);
3184 QTextOption opt = document->defaultTextOption();
3185 const Qt::Alignment oldAlignment = opt.alignment();
3186 Qt::LayoutDirection oldTextDirection = opt.textDirection();
3188 QQuickTextEdit::HAlignment horizontalAlignment = q->effectiveHAlign();
3189 if (contentDirection == Qt::RightToLeft) {
3190 if (horizontalAlignment == QQuickTextEdit::AlignLeft)
3191 horizontalAlignment = QQuickTextEdit::AlignRight;
3192 else if (horizontalAlignment == QQuickTextEdit::AlignRight)
3193 horizontalAlignment = QQuickTextEdit::AlignLeft;
3195 if (!hAlignImplicit)
3196 opt.setAlignment((Qt::Alignment)(
int)(horizontalAlignment | vAlign));
3198 opt.setAlignment(Qt::Alignment(vAlign));
3201 if (contentDirection == Qt::LayoutDirectionAuto) {
3202 opt.setTextDirection(qGuiApp->inputMethod()->inputDirection());
3206 opt.setTextDirection(contentDirection);
3209 QTextOption::WrapMode oldWrapMode = opt.wrapMode();
3210 opt.setWrapMode(QTextOption::WrapMode(wrapMode));
3212 bool oldUseDesignMetrics = opt.useDesignMetrics();
3213 opt.setUseDesignMetrics(renderType != QQuickTextEdit::NativeRendering);
3215 if (oldWrapMode != opt.wrapMode() || oldAlignment != opt.alignment()
3216 || oldTextDirection != opt.textDirection()
3217 || oldUseDesignMetrics != opt.useDesignMetrics()) {
3218 document->setDefaultTextOption(opt);
3222void QQuickTextEditPrivate::onDocumentStatusChanged()
3224 Q_ASSERT(quickDocument);
3225 switch (quickDocument->status()) {
3226 case QQuickTextDocument::Status::Loaded:
3227 case QQuickTextDocument::Status::Saved:
3228 switch (QQuickTextDocumentPrivate::get(quickDocument)->detectedFormat) {
3230 richText = (format == QQuickTextEdit::RichText || format == QQuickTextEdit::AutoText);
3231 markdownText =
false;
3233 case Qt::MarkdownText:
3235 markdownText = (format == QQuickTextEdit::MarkdownText || format == QQuickTextEdit::AutoText);
3239 markdownText =
false;
3250void QQuickTextEdit::focusInEvent(QFocusEvent *event)
3252 Q_D(QQuickTextEdit);
3253 d->handleFocusEvent(event);
3254 QQuickImplicitSizeItem::focusInEvent(event);
3257void QQuickTextEdit::focusOutEvent(QFocusEvent *event)
3259 Q_D(QQuickTextEdit);
3260 d->handleFocusEvent(event);
3261 QQuickImplicitSizeItem::focusOutEvent(event);
3264#if QT_VERSION < QT_VERSION_CHECK(7
, 0
, 0
)
3265bool QQuickTextEditPrivate::handleContextMenuEvent(QContextMenuEvent *event)
3267bool QQuickTextEdit::contextMenuEvent(QContextMenuEvent *event)
3270 Q_Q(QQuickTextEdit);
3271 QContextMenuEvent mapped(event->reason(),
3272 q->mapToScene(q->cursorRectangle().center()).toPoint(), event->globalPos(),
3273 event->modifiers());
3274 const bool eventProcessed = QQuickItemPrivate::handleContextMenuEvent(&mapped);
3275 event->setAccepted(mapped.isAccepted());
3276 return eventProcessed;
3279void QQuickTextEditPrivate::handleFocusEvent(QFocusEvent *event)
3281 Q_Q(QQuickTextEdit);
3282 bool focus = event->type() == QEvent::FocusIn;
3283 if (!q->isReadOnly())
3284 q->setCursorVisible(focus);
3285 control->processEvent(event, QPointF(-xoff, -yoff));
3287 q->q_updateAlignment();
3289 if (focusOnPress && !q->isReadOnly())
3290 qGuiApp->inputMethod()->show();
3291 q->connect(QGuiApplication::inputMethod(), SIGNAL(inputDirectionChanged(Qt::LayoutDirection)),
3292 q, SLOT(q_updateAlignment()));
3296 q->disconnect(QGuiApplication::inputMethod(), SIGNAL(inputDirectionChanged(Qt::LayoutDirection)),
3297 q, SLOT(q_updateAlignment()));
3299 if (event->reason() != Qt::ActiveWindowFocusReason
3300 && event->reason() != Qt::PopupFocusReason
3301 && control->textCursor().hasSelection()
3302 && !persistentSelection)
3305 emit q->editingFinished();
3309void QQuickTextEditPrivate::addCurrentTextNodeToRoot(QQuickTextNodeEngine *engine, QSGTransformNode *root, QSGInternalTextNode *node, TextNodeIterator &it,
int startPos)
3311 engine->addToSceneGraph(node, QQuickText::Normal, QColor());
3312 it = textNodeMap.insert(it, TextNode(startPos, node));
3314 root->appendChildNode(node);
3315 ++renderedBlockCount;
3318QSGInternalTextNode *QQuickTextEditPrivate::createTextNode()
3320 Q_Q(QQuickTextEdit);
3321 QSGInternalTextNode* node = sceneGraphContext()->createInternalTextNode(sceneGraphRenderContext());
3322 node->setRenderType(QSGTextNode::RenderType(renderType));
3323 node->setFiltering(q->smooth() ? QSGTexture::Linear : QSGTexture::Nearest);
3327void QQuickTextEdit::q_canPasteChanged()
3329 Q_D(QQuickTextEdit);
3330 bool old = d->canPaste;
3331 d->canPaste = d->control->canPaste();
3332 bool changed = old!=d->canPaste || !d->canPasteValid;
3333 d->canPasteValid =
true;
3335 emit canPasteChanged();
3339
3340
3341
3342
3343
3344
3346QString QQuickTextEdit::getText(
int start,
int end)
const
3348 Q_D(
const QQuickTextEdit);
3349 start = qBound(0, start, d->document->characterCount() - 1);
3350 end = qBound(0, end, d->document->characterCount() - 1);
3351 QTextCursor cursor(d->document);
3352 cursor.setPosition(start, QTextCursor::MoveAnchor);
3353 cursor.setPosition(end, QTextCursor::KeepAnchor);
3354#if QT_CONFIG(texthtmlparser)
3355 return d->richText || d->markdownText
3356 ? cursor.selectedText()
3357 : cursor.selection().toPlainText();
3359 return cursor.selection().toPlainText();
3364
3365
3366
3367
3368
3369
3371QString QQuickTextEdit::getFormattedText(
int start,
int end)
const
3373 Q_D(
const QQuickTextEdit);
3375 start = qBound(0, start, d->document->characterCount() - 1);
3376 end = qBound(0, end, d->document->characterCount() - 1);
3378 QTextCursor cursor(d->document);
3379 cursor.setPosition(start, QTextCursor::MoveAnchor);
3380 cursor.setPosition(end, QTextCursor::KeepAnchor);
3383#if QT_CONFIG(texthtmlparser)
3384 return cursor.selection().toHtml();
3386 return cursor.selection().toPlainText();
3388 }
else if (d->markdownText) {
3389#if QT_CONFIG(textmarkdownwriter)
3390 return cursor.selection().toMarkdown();
3392 return cursor.selection().toPlainText();
3395 return cursor.selection().toPlainText();
3400
3401
3402
3403
3404void QQuickTextEdit::insert(
int position,
const QString &text)
3406 Q_D(QQuickTextEdit);
3407 if (position < 0 || position >= d->document->characterCount())
3409 QTextCursor cursor(d->document);
3410 cursor.setPosition(position);
3411 d->richText = d->richText || (d->format == AutoText && Qt::mightBeRichText(text));
3413#if QT_CONFIG(texthtmlparser)
3414 cursor.insertHtml(text);
3416 cursor.insertText(text);
3418 }
else if (d->markdownText) {
3419#if QT_CONFIG(textmarkdownreader)
3420 cursor.insertMarkdown(text);
3422 cursor.insertText(text);
3425 cursor.insertText(text);
3427 d->control->updateCursorRectangle(
false);
3431
3432
3433
3434
3436void QQuickTextEdit::remove(
int start,
int end)
3438 Q_D(QQuickTextEdit);
3439 start = qBound(0, start, d->document->characterCount() - 1);
3440 end = qBound(0, end, d->document->characterCount() - 1);
3441 QTextCursor cursor(d->document);
3442 cursor.setPosition(start, QTextCursor::MoveAnchor);
3443 cursor.setPosition(end, QTextCursor::KeepAnchor);
3444 cursor.removeSelectedText();
3445 d->control->updateCursorRectangle(
false);
3449
3450
3451
3452
3453
3454
3455
3456
3457
3458
3460QQuickTextDocument *QQuickTextEdit::textDocument()
3462 Q_D(QQuickTextEdit);
3463 if (!d->quickDocument) {
3464 d->quickDocument =
new QQuickTextDocument(
this);
3465 connect(d->quickDocument, &QQuickTextDocument::statusChanged, d->quickDocument,
3466 [d]() { d->onDocumentStatusChanged(); } );
3468 return d->quickDocument;
3471bool QQuickTextEditPrivate::isLinkHoveredConnected()
3473 Q_Q(QQuickTextEdit);
3474 IS_SIGNAL_CONNECTED(q, QQuickTextEdit, linkHovered, (
const QString &));
3477#if QT_CONFIG(cursor)
3478void QQuickTextEditPrivate::updateMouseCursorShape()
3480 Q_Q(QQuickTextEdit);
3481 q->setCursor(q->isReadOnly() && !q->selectByMouse() ? Qt::ArrowCursor : Qt::IBeamCursor);
3486
3487
3488
3489
3490
3491
3492
3493
3494
3497
3498
3499
3500
3501
3504
3505
3506
3507
3508
3509
3510
3511
3512
3515
3516
3517
3518
3519
3520
3521
3523QString QQuickTextEdit::hoveredLink()
const
3525 Q_D(
const QQuickTextEdit);
3526 if (
const_cast<QQuickTextEditPrivate *>(d)->isLinkHoveredConnected()) {
3527 return d->control->hoveredLink();
3529#if QT_CONFIG(cursor)
3530 if (QQuickWindow *wnd = window()) {
3531 QPointF pos = QCursor::pos(wnd->screen()) - wnd->position() - mapToScene(QPointF(0, 0));
3532 return d->control->anchorAt(pos);
3539void QQuickTextEdit::hoverEnterEvent(QHoverEvent *event)
3541 Q_D(QQuickTextEdit);
3542 if (d->isLinkHoveredConnected())
3543 d->control->processEvent(event, QPointF(-d->xoff, -d->yoff));
3547void QQuickTextEdit::hoverMoveEvent(QHoverEvent *event)
3549 Q_D(QQuickTextEdit);
3550 if (d->isLinkHoveredConnected())
3551 d->control->processEvent(event, QPointF(-d->xoff, -d->yoff));
3555void QQuickTextEdit::hoverLeaveEvent(QHoverEvent *event)
3557 Q_D(QQuickTextEdit);
3558 if (d->isLinkHoveredConnected())
3559 d->control->processEvent(event, QPointF(-d->xoff, -d->yoff));
3564
3565
3566
3567
3568
3569
3570
3571
3572void QQuickTextEdit::append(
const QString &text)
3574 Q_D(QQuickTextEdit);
3575 QTextCursor cursor(d->document);
3576 cursor.beginEditBlock();
3577 cursor.movePosition(QTextCursor::End);
3579 if (!d->document->isEmpty())
3580 cursor.insertBlock();
3582 if (d->format == RichText || (d->format == AutoText && Qt::mightBeRichText(text))) {
3583#if QT_CONFIG(texthtmlparser)
3584 cursor.insertHtml(text);
3586 cursor.insertText(text);
3588 }
else if (d->format == MarkdownText) {
3589#if QT_CONFIG(textmarkdownreader)
3590 cursor.insertMarkdown(text);
3592 cursor.insertText(text);
3595 cursor.insertText(text);
3598 cursor.endEditBlock();
3599 d->control->updateCursorRectangle(
false);
3603
3604
3605
3606
3607
3608
3609
3610
3611QString QQuickTextEdit::linkAt(qreal x, qreal y)
const
3613 Q_D(
const QQuickTextEdit);
3614 return d->control->anchorAt(QPointF(x + topPadding(), y + leftPadding()));
3618
3619
3620
3621
3622
3623
3624
3625
3626
3627
3628qreal QQuickTextEdit::padding()
const
3630 Q_D(
const QQuickTextEdit);
3631 return d->padding();
3634void QQuickTextEdit::setPadding(qreal padding)
3636 Q_D(QQuickTextEdit);
3637 if (qFuzzyCompare(d->padding(), padding))
3640 d->extra.value().padding = padding;
3642 if (isComponentComplete()) {
3643 d->updateType = QQuickTextEditPrivate::UpdatePaintNode;
3646 emit paddingChanged();
3647 if (!d->extra.isAllocated() || !d->extra->explicitTopPadding)
3648 emit topPaddingChanged();
3649 if (!d->extra.isAllocated() || !d->extra->explicitLeftPadding)
3650 emit leftPaddingChanged();
3651 if (!d->extra.isAllocated() || !d->extra->explicitRightPadding)
3652 emit rightPaddingChanged();
3653 if (!d->extra.isAllocated() || !d->extra->explicitBottomPadding)
3654 emit bottomPaddingChanged();
3657void QQuickTextEdit::resetPadding()
3662qreal QQuickTextEdit::topPadding()
const
3664 Q_D(
const QQuickTextEdit);
3665 if (d->extra.isAllocated() && d->extra->explicitTopPadding)
3666 return d->extra->topPadding;
3667 return d->padding();
3670void QQuickTextEdit::setTopPadding(qreal padding)
3672 Q_D(QQuickTextEdit);
3673 d->setTopPadding(padding);
3676void QQuickTextEdit::resetTopPadding()
3678 Q_D(QQuickTextEdit);
3679 d->setTopPadding(0,
true);
3682qreal QQuickTextEdit::leftPadding()
const
3684 Q_D(
const QQuickTextEdit);
3685 if (d->extra.isAllocated() && d->extra->explicitLeftPadding)
3686 return d->extra->leftPadding;
3687 return d->padding();
3690void QQuickTextEdit::setLeftPadding(qreal padding)
3692 Q_D(QQuickTextEdit);
3693 d->setLeftPadding(padding);
3696void QQuickTextEdit::resetLeftPadding()
3698 Q_D(QQuickTextEdit);
3699 d->setLeftPadding(0,
true);
3702qreal QQuickTextEdit::rightPadding()
const
3704 Q_D(
const QQuickTextEdit);
3705 if (d->extra.isAllocated() && d->extra->explicitRightPadding)
3706 return d->extra->rightPadding;
3707 return d->padding();
3710void QQuickTextEdit::setRightPadding(qreal padding)
3712 Q_D(QQuickTextEdit);
3713 d->setRightPadding(padding);
3716void QQuickTextEdit::resetRightPadding()
3718 Q_D(QQuickTextEdit);
3719 d->setRightPadding(0,
true);
3722qreal QQuickTextEdit::bottomPadding()
const
3724 Q_D(
const QQuickTextEdit);
3725 if (d->extra.isAllocated() && d->extra->explicitBottomPadding)
3726 return d->extra->bottomPadding;
3727 return d->padding();
3730void QQuickTextEdit::setBottomPadding(qreal padding)
3732 Q_D(QQuickTextEdit);
3733 d->setBottomPadding(padding);
3736void QQuickTextEdit::resetBottomPadding()
3738 Q_D(QQuickTextEdit);
3739 d->setBottomPadding(0,
true);
3743
3744
3745
3746
3747
3748
3749
3750int QQuickTextEdit::tabStopDistance()
const
3752 Q_D(
const QQuickTextEdit);
3753 return d->document->defaultTextOption().tabStopDistance();
3756void QQuickTextEdit::setTabStopDistance(qreal distance)
3758 Q_D(QQuickTextEdit);
3759 QTextOption textOptions = d->document->defaultTextOption();
3760 if (textOptions.tabStopDistance() == distance)
3763 textOptions.setTabStopDistance(distance);
3764 d->document->setDefaultTextOption(textOptions);
3765 emit tabStopDistanceChanged(distance);
3769
3770
3771
3772
3773
3774
3775
3776
3777
3778
3779void QQuickTextEdit::clear()
3781 Q_D(QQuickTextEdit);
3782 d->resetInputMethod();
3783 d->control->clear();
3786#ifndef QT_NO_DEBUG_STREAM
3789 QDebugStateSaver saver(debug);
3791 debug <<
"Node(startPos:" << n.m_startPos <<
"dirty:" << n.m_dirty << n.m_node <<
')';