9#include <private/qqmlglobal_p.h>
10#include <private/qv4scopedvalue_p.h>
12#include <QtCore/qcoreapplication.h>
13#include <QtCore/qmimedata.h>
14#include <QtQml/qqmlinfo.h>
15#include <QtGui/qevent.h>
16#include <QTextBoundaryFinder>
18#include <QtQuick/qsgsimplerectnode.h>
20#include <QtGui/qstylehints.h>
21#include <QtGui/qinputmethod.h>
22#include <QtCore/qmath.h>
24#if QT_CONFIG(accessibility)
25#include "qaccessible.h"
26#include "qquickaccessibleattached_p.h"
29#include <QtGui/private/qtextengine_p.h>
30#include <QtGui/private/qinputcontrol_p.h>
34DEFINE_BOOL_CONFIG_OPTION(qmlDisableDistanceField, QML_DISABLE_DISTANCEFIELD)
35Q_STATIC_LOGGING_CATEGORY(lcQuickTextInput,
"qt.quick.textInput")
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65QQuickTextInput::QQuickTextInput(QQuickItem* parent)
66: QQuickImplicitSizeItem(*(
new QQuickTextInputPrivate), parent)
72QQuickTextInput::QQuickTextInput(QQuickTextInputPrivate &dd, QQuickItem *parent)
73: QQuickImplicitSizeItem(dd, parent)
79QQuickTextInput::~QQuickTextInput()
83void QQuickTextInput::componentComplete()
87 QQuickImplicitSizeItem::componentComplete();
91 updateCursorRectangle();
92 if (d->cursorComponent && isCursorVisible())
93 QQuickTextUtil::createCursor(d);
94#if QT_CONFIG(accessibility)
95 if (QAccessible::isActive())
96 d->accessibilityActiveChanged(
true);
101
102
103
104
105
106
107
108
109
110
111
112
113
114QString QQuickTextInput::text()
const
116 Q_D(
const QQuickTextInput);
118 QString content = d->m_text;
119 QString res = d->m_maskData ? d->stripString(content) : content;
120 return (res.isNull() ? QString::fromLatin1(
"") : res);
123void QQuickTextInput::invalidate()
125 Q_D(QQuickTextInput);
127 invalidateFontCaches();
130void QQuickTextInput::setText(
const QString &s)
132 Q_D(QQuickTextInput);
139 d->internalSetText(s, -1,
false);
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168QQuickTextInput::RenderType QQuickTextInput::renderType()
const
170 Q_D(
const QQuickTextInput);
171 return d->renderType;
174void QQuickTextInput::setRenderType(QQuickTextInput::RenderType renderType)
176 Q_D(QQuickTextInput);
177 if (d->renderType == renderType)
180 d->renderType = renderType;
181 emit renderTypeChanged();
183 if (isComponentComplete())
188
189
190
191
192
193
194
195
196
197
199int QQuickTextInput::length()
const
201 Q_D(
const QQuickTextInput);
202 return d->m_text.size();
206
207
208
209
210
211
213QString QQuickTextInput::getText(
int start,
int end)
const
215 Q_D(
const QQuickTextInput);
220 return d->m_text.mid(start, end - start);
223QString QQuickTextInputPrivate::realText()
const
225 QString res = m_maskData ? stripString(m_text) : m_text;
226 return (res.isNull() ? QString::fromLatin1(
"") : res);
230
231
232
233
234
235
236
237
240
241
242
243
244
245
246
247
250
251
252
253
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
277
278
279
280
283
284
285
286
289
290
291
292
295
296
297
298
301
302
303
304
305
306
307
310
311
312
313
314
315
316
319
320
321
322
323
324
325
326
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
377
378
379
380
381
382
383
384
385
386
387
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
407
408
409
410
411
414
415
416
417
418
421
422
423
424
425
428
429
430
431
432
433QFont QQuickTextInput::font()
const
435 Q_D(
const QQuickTextInput);
436 return d->sourceFont;
439void QQuickTextInput::setFont(
const QFont &font)
441 Q_D(QQuickTextInput);
442 if (d->sourceFont == font)
445 d->sourceFont = font;
446 QFont oldFont = d->font;
448 if (d->font.pointSizeF() != -1) {
450 qreal size = qRound(d->font.pointSizeF()*2.0);
451 d->font.setPointSizeF(size/2.0);
453 if (oldFont != d->font) {
455 updateCursorRectangle();
457 updateInputMethod(Qt::ImCursorRectangle | Qt::ImFont | Qt::ImAnchorRectangle);
460 emit fontChanged(d->sourceFont);
464
465
466
467
468QColor QQuickTextInput::color()
const
470 Q_D(
const QQuickTextInput);
474void QQuickTextInput::setColor(
const QColor &c)
476 Q_D(QQuickTextInput);
479 d->textLayoutDirty =
true;
480 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
489
490
491
492
493QColor QQuickTextInput::selectionColor()
const
495 Q_D(
const QQuickTextInput);
496 return d->selectionColor;
499void QQuickTextInput::setSelectionColor(
const QColor &color)
501 Q_D(QQuickTextInput);
502 if (d->selectionColor == color)
505 d->selectionColor = color;
506 if (d->hasSelectedText()) {
507 d->textLayoutDirty =
true;
508 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
512 emit selectionColorChanged();
515
516
517
518
519QColor QQuickTextInput::selectedTextColor()
const
521 Q_D(
const QQuickTextInput);
522 return d->selectedTextColor;
525void QQuickTextInput::setSelectedTextColor(
const QColor &color)
527 Q_D(QQuickTextInput);
528 if (d->selectedTextColor == color)
531 d->selectedTextColor = color;
532 if (d->hasSelectedText()) {
533 d->textLayoutDirty =
true;
534 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
538 emit selectedTextColorChanged();
542
543
544
545
546
547
548
549
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576QQuickTextInput::HAlignment QQuickTextInput::hAlign()
const
578 Q_D(
const QQuickTextInput);
582void QQuickTextInput::setHAlign(HAlignment align)
584 Q_D(QQuickTextInput);
586 if (d->setHAlign(align,
true) && isComponentComplete()) {
588 updateCursorRectangle();
592void QQuickTextInput::resetHAlign()
594 Q_D(QQuickTextInput);
595 d->hAlignImplicit =
true;
596 if (d->determineHorizontalAlignment() && isComponentComplete()) {
598 updateCursorRectangle();
602QQuickTextInput::HAlignment QQuickTextInput::effectiveHAlign()
const
604 Q_D(
const QQuickTextInput);
605 QQuickTextInput::HAlignment effectiveAlignment = d->hAlign;
606 if (!d->hAlignImplicit && d->effectiveLayoutMirror) {
608 case QQuickTextInput::AlignLeft:
609 effectiveAlignment = QQuickTextInput::AlignRight;
611 case QQuickTextInput::AlignRight:
612 effectiveAlignment = QQuickTextInput::AlignLeft;
618 return effectiveAlignment;
621bool QQuickTextInputPrivate::setHAlign(QQuickTextInput::HAlignment align,
bool forceAlign)
623 Q_Q(QQuickTextInput);
624 if (align > QQuickTextInput::AlignHCenter)
627 if (hAlign == align && !forceAlign)
630 const bool wasImplicit = hAlignImplicit;
631 const auto oldEffectiveHAlign = q->effectiveHAlign();
633 hAlignImplicit = !forceAlign;
634 if (hAlign != align) {
636 emit q->horizontalAlignmentChanged(align);
639 if (q->effectiveHAlign() != oldEffectiveHAlign) {
640 emit q->effectiveHorizontalAlignmentChanged();
644 if (forceAlign && wasImplicit) {
647 emit q->effectiveHorizontalAlignmentChanged();
652Qt::LayoutDirection QQuickTextInputPrivate::textDirection()
const
654 QString text = m_text;
657 text = m_textLayout.preeditAreaText();
660 const QChar *character = text.constData();
661 while (!character->isNull()) {
662 switch (character->direction()) {
664 return Qt::LeftToRight;
668 return Qt::RightToLeft;
674 return Qt::LayoutDirectionAuto;
677Qt::LayoutDirection QQuickTextInputPrivate::layoutDirection()
const
679 Qt::LayoutDirection direction = m_layoutDirection;
680 if (direction == Qt::LayoutDirectionAuto) {
681 direction = textDirection();
683 if (direction == Qt::LayoutDirectionAuto)
684 direction = QGuiApplication::inputMethod()->inputDirection();
687 return (direction == Qt::LayoutDirectionAuto) ? Qt::LeftToRight : direction;
690bool QQuickTextInputPrivate::determineHorizontalAlignment()
696 Qt::LayoutDirection direction = textDirection();
698 if (direction == Qt::LayoutDirectionAuto)
699 direction = QGuiApplication::inputMethod()->inputDirection();
702 const auto implicitHAlign = direction == Qt::RightToLeft ?
703 QQuickTextInput::AlignRight : QQuickTextInput::AlignLeft;
704 return setHAlign(implicitHAlign);
707QQuickTextInput::VAlignment QQuickTextInput::vAlign()
const
709 Q_D(
const QQuickTextInput);
713void QQuickTextInput::setVAlign(QQuickTextInput::VAlignment alignment)
715 Q_D(QQuickTextInput);
716 if (alignment == d->vAlign)
718 d->vAlign = alignment;
719 emit verticalAlignmentChanged(d->vAlign);
720 if (isComponentComplete()) {
721 updateCursorRectangle();
722 d->updateBaselineOffset();
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746QQuickTextInput::WrapMode QQuickTextInput::wrapMode()
const
748 Q_D(
const QQuickTextInput);
752void QQuickTextInput::setWrapMode(WrapMode mode)
754 Q_D(QQuickTextInput);
755 if (mode == d->wrapMode)
759 updateCursorRectangle();
760 emit wrapModeChanged();
763void QQuickTextInputPrivate::mirrorChange()
765 Q_Q(QQuickTextInput);
766 if (q->isComponentComplete()) {
767 if (!hAlignImplicit && (hAlign == QQuickTextInput::AlignRight || hAlign == QQuickTextInput::AlignLeft)) {
768 q->updateCursorRectangle();
769 emit q->effectiveHorizontalAlignmentChanged();
775
776
777
778
779
780
781
782
783bool QQuickTextInput::isReadOnly()
const
785 Q_D(
const QQuickTextInput);
786 return d->m_readOnly;
789void QQuickTextInput::setReadOnly(
bool ro)
791 Q_D(QQuickTextInput);
792 if (d->m_readOnly == ro)
796 setFlag(QQuickItem::ItemAcceptsInputMethod, !ro);
799 d->setCursorPosition(d->end());
801 updateInputMethod(Qt::ImEnabled);
804 d->emitUndoRedoChanged();
805 emit readOnlyChanged(ro);
807 setCursorVisible(
false);
808 }
else if (hasActiveFocus()) {
809 setCursorVisible(
true);
815
816
817
818
819
820
821
822int QQuickTextInput::maxLength()
const
824 Q_D(
const QQuickTextInput);
825 return d->m_maxLength;
828void QQuickTextInput::setMaxLength(
int ml)
830 Q_D(QQuickTextInput);
831 if (d->m_maxLength == ml || d->m_maskData)
835 d->internalSetText(d->m_text, -1,
false);
837 emit maximumLengthChanged(ml);
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866bool QQuickTextInput::isCursorVisible()
const
868 Q_D(
const QQuickTextInput);
869 return d->cursorVisible;
872void QQuickTextInput::setCursorVisible(
bool on)
874 Q_D(QQuickTextInput);
875 if (d->cursorVisible == on)
877 d->cursorVisible = on;
878 if (on && isComponentComplete())
879 QQuickTextUtil::createCursor(d);
881 d->updateCursorBlinking();
882 emit cursorVisibleChanged(d->cursorVisible);
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901int QQuickTextInput::cursorPosition()
const
903 Q_D(
const QQuickTextInput);
907void QQuickTextInput::setCursorPosition(
int cp)
909 Q_D(QQuickTextInput);
910 if (cp < 0 || cp > text().size())
916
917
918
919
920
921
922
923
924
926QRectF QQuickTextInput::cursorRectangle()
const
928 Q_D(
const QQuickTextInput);
932 c += d->m_preeditCursor;
934 if (d->m_echoMode == NoEcho)
936 QTextLine l = d->m_textLayout.lineForTextPosition(c);
939 qreal x = l.cursorToX(c) - d->hscroll + leftPadding();
940 qreal y = l.y() - d->vscroll + topPadding();
942 if (d->overwriteMode) {
943 if (c < text().size())
944 w = l.cursorToX(c + 1) - x;
946 w = QFontMetrics(font()).horizontalAdvance(QLatin1Char(
' '));
948 return QRectF(x, y, w, l.height());
952
953
954
955
956
957
958
959
960
961
962int QQuickTextInput::selectionStart()
const
964 Q_D(
const QQuickTextInput);
965 return d->lastSelectionStart;
968
969
970
971
972
973
974
975
976
977
978int QQuickTextInput::selectionEnd()
const
980 Q_D(
const QQuickTextInput);
981 return d->lastSelectionEnd;
984
985
986
987
988
989
990
991
992
993
994
995
996void QQuickTextInput::select(
int start,
int end)
998 Q_D(QQuickTextInput);
999 if (start < 0 || end < 0 || start > d->m_text.size() || end > d->m_text.size())
1001 d->setSelection(start, end-start);
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019QString QQuickTextInput::selectedText()
const
1021 Q_D(
const QQuickTextInput);
1022 return d->selectedText();
1026
1027
1028
1029
1030
1031bool QQuickTextInput::focusOnPress()
const
1033 Q_D(
const QQuickTextInput);
1034 return d->focusOnPress;
1037void QQuickTextInput::setFocusOnPress(
bool b)
1039 Q_D(QQuickTextInput);
1040 if (d->focusOnPress == b)
1043 d->focusOnPress = b;
1045 emit activeFocusOnPressChanged(d->focusOnPress);
1048
1049
1050
1051
1052
1053
1054
1055bool QQuickTextInput::autoScroll()
const
1057 Q_D(
const QQuickTextInput);
1058 return d->autoScroll;
1061void QQuickTextInput::setAutoScroll(
bool b)
1063 Q_D(QQuickTextInput);
1064 if (d->autoScroll == b)
1069 updateCursorRectangle();
1070 emit autoScrollChanged(d->autoScroll);
1073#if QT_CONFIG(validator)
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1098QValidator* QQuickTextInput::validator()
const
1100 Q_D(
const QQuickTextInput);
1101 return d->m_validator;
1104void QQuickTextInput::setValidator(QValidator* v)
1106 Q_D(QQuickTextInput);
1107 if (d->m_validator == v)
1110 if (d->m_validator) {
1111 qmlobject_disconnect(
1112 d->m_validator, QValidator, SIGNAL(changed()),
1113 this, QQuickTextInput, SLOT(q_validatorChanged()));
1118 if (d->m_validator) {
1120 d->m_validator, QValidator, SIGNAL(changed()),
1121 this, QQuickTextInput, SLOT(q_validatorChanged()));
1124 if (isComponentComplete())
1127 emit validatorChanged();
1130void QQuickTextInput::q_validatorChanged()
1132 Q_D(QQuickTextInput);
1137QRectF QQuickTextInputPrivate::anchorRectangle()
const
1139 Q_Q(
const QQuickTextInput);
1146 if (m_selstart == m_selend)
1151 a = m_selstart == m_cursor ? m_selend : m_selstart;
1154 a += m_preeditCursor;
1156 if (m_echoMode == QQuickTextInput::NoEcho)
1158 QTextLine l = m_textLayout.lineForTextPosition(a);
1160 qreal x = l.cursorToX(a) - hscroll + q->leftPadding();
1161 qreal y = l.y() - vscroll + q->topPadding();
1162 rect.setRect(x, y, 1, l.height());
1168void QQuickTextInputPrivate::checkIsValid()
1170 Q_Q(QQuickTextInput);
1172 ValidatorState state = hasAcceptableInput(m_text);
1174 m_validInput = state != InvalidInput;
1175 if (state != AcceptableInput) {
1176 if (m_acceptableInput) {
1177 m_acceptableInput =
false;
1178 emit q->acceptableInputChanged();
1180 }
else if (!m_acceptableInput) {
1181 m_acceptableInput =
true;
1182 emit q->acceptableInputChanged();
1187
1188
1189
1190
1191
1192
1193
1194
1195QString QQuickTextInput::inputMask()
const
1197 Q_D(
const QQuickTextInput);
1198 return d->inputMask();
1201void QQuickTextInput::setInputMask(
const QString &im)
1203 Q_D(QQuickTextInput);
1204 QString canonicalInputMask = im;
1205 if (im.lastIndexOf(QLatin1Char(
';')) == -1)
1206 canonicalInputMask.append(QLatin1String(
"; "));
1207 if (d->inputMask() == canonicalInputMask)
1210 d->setInputMask(im);
1211 emit inputMaskChanged(d->inputMask());
1215
1216
1217
1218
1219
1220
1221
1222
1223bool QQuickTextInput::hasAcceptableInput()
const
1225 Q_D(
const QQuickTextInput);
1226 return d->m_acceptableInput;
1230
1231
1232
1233
1234
1235
1236
1237
1238
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1254
1255
1256
1257
1258
1259
1260
1261
1262
1265Qt::InputMethodHints QQuickTextInputPrivate::effectiveInputMethodHints()
const
1267 Qt::InputMethodHints hints = inputMethodHints;
1268 if (m_echoMode == QQuickTextInput::NoEcho)
1269 hints |= Qt::ImhHiddenText;
1270 else if (m_echoMode == QQuickTextInput::Password || m_echoMode == QQuickTextInput::PasswordEchoOnEdit)
1271 hints &= ~Qt::ImhHiddenText;
1272 if (m_echoMode != QQuickTextInput::Normal)
1273 hints |= (Qt::ImhNoAutoUppercase | Qt::ImhNoPredictiveText | Qt::ImhSensitiveData);
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292QQuickTextInput::EchoMode QQuickTextInput::echoMode()
const
1294 Q_D(
const QQuickTextInput);
1295 return QQuickTextInput::EchoMode(d->m_echoMode);
1298void QQuickTextInput::setEchoMode(QQuickTextInput::EchoMode echo)
1300 Q_D(QQuickTextInput);
1301 if (echoMode() == echo)
1303 d->cancelPasswordEchoTimer();
1304 d->m_echoMode = echo;
1305 d->m_passwordEchoEditing =
false;
1307 updateInputMethod(Qt::ImHints);
1309 d->updateDisplayText();
1310 updateCursorRectangle();
1315 if (d->m_echoMode != QQuickTextInput::Normal)
1316 d->m_text.reserve(30);
1318 emit echoModeChanged(echoMode());
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1365Qt::InputMethodHints QQuickTextInput::inputMethodHints()
const
1370 Q_D(
const QQuickTextInput);
1371 return d->inputMethodHints;
1375void QQuickTextInput::setInputMethodHints(Qt::InputMethodHints hints)
1380 Q_D(QQuickTextInput);
1382 if (hints == d->inputMethodHints)
1385 d->inputMethodHints = hints;
1386 updateInputMethod(Qt::ImHints);
1387 emit inputMethodHintsChanged();
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404QQmlComponent* QQuickTextInput::cursorDelegate()
const
1406 Q_D(
const QQuickTextInput);
1407 return d->cursorComponent;
1410void QQuickTextInput::setCursorDelegate(QQmlComponent* c)
1412 Q_D(QQuickTextInput);
1413 QQuickTextUtil::setCursorDelegate(d, c);
1416void QQuickTextInput::createCursor()
1418 Q_D(QQuickTextInput);
1419 d->cursorPending =
true;
1420 QQuickTextUtil::createCursor(d);
1424
1425
1426
1427
1428
1429
1430
1431
1432QRectF QQuickTextInput::positionToRectangle(
int pos)
const
1434 Q_D(
const QQuickTextInput);
1435 if (d->m_echoMode == NoEcho)
1438 else if (pos > d->m_cursor)
1439 pos += d->preeditAreaText().size();
1441 QTextLine l = d->m_textLayout.lineForTextPosition(pos);
1444 qreal x = l.cursorToX(pos) - d->hscroll;
1445 qreal y = l.y() - d->vscroll;
1447 if (d->overwriteMode) {
1448 if (pos < text().size())
1449 w = l.cursorToX(pos + 1) - x;
1451 w = QFontMetrics(font()).horizontalAdvance(QLatin1Char(
' '));
1453 return QRectF(x, y, w, l.height());
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1479int QQuickTextInput::positionAt(qreal x, qreal y, QQuickTextInput::CursorPosition positionQuick)
const
1481 Q_D(
const QQuickTextInput);
1483 QTextLine::CursorPosition position = QTextLine::CursorPosition(positionQuick);
1485 int pos = d->positionAt(x, y, position);
1486 const int cursor = d->m_cursor;
1489 const int preeditLength = d->preeditAreaText().size();
1490 pos = pos > cursor + preeditLength
1491 ? pos - preeditLength
1500int QQuickTextInputPrivate::positionAt(qreal x, qreal y, QTextLine::CursorPosition position)
const
1502 Q_Q(
const QQuickTextInput);
1503 x += hscroll - q->leftPadding();
1504 y += vscroll - q->topPadding();
1505 QTextLine line = m_textLayout.lineAt(0);
1506 for (
int i = 1; i < m_textLayout.lineCount(); ++i) {
1507 QTextLine nextLine = m_textLayout.lineAt(i);
1509 if (y < (line.rect().bottom() + nextLine.y()) / 2)
1513 return line.isValid() ? line.xToCursor(x, position) : 0;
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531bool QQuickTextInput::overwriteMode()
const
1533 Q_D(
const QQuickTextInput);
1534 return d->overwriteMode;
1537void QQuickTextInput::setOverwriteMode(
bool overwrite)
1539 Q_D(QQuickTextInput);
1540 if (d->overwriteMode == overwrite)
1542 d->overwriteMode = overwrite;
1543 emit overwriteModeChanged(overwrite);
1546void QQuickTextInput::keyPressEvent(QKeyEvent* ev)
1548 Q_D(QQuickTextInput);
1550 bool ignore = (ev->key() == Qt::Key_Up || ev->key() == Qt::Key_Down) && ev->modifiers() == Qt::NoModifier;
1551 if (!ignore && (d->lastSelectionStart == d->lastSelectionEnd) && (ev->key() == Qt::Key_Right || ev->key() == Qt::Key_Left)) {
1554 int cursorPosition = d->m_cursor;
1555 if (cursorPosition == 0)
1556 ignore = ev->key() == (d->layoutDirection() == Qt::LeftToRight ? Qt::Key_Left : Qt::Key_Right);
1557 if (!ignore && cursorPosition == d->m_text.size())
1558 ignore = ev->key() == (d->layoutDirection() == Qt::LeftToRight ? Qt::Key_Right : Qt::Key_Left);
1563 d->processKeyEvent(ev);
1565 if (!ev->isAccepted())
1566 QQuickImplicitSizeItem::keyPressEvent(ev);
1570void QQuickTextInput::inputMethodEvent(QInputMethodEvent *ev)
1572 Q_D(QQuickTextInput);
1573 const bool wasComposing = d->hasImState;
1574 d->processInputMethodEvent(ev);
1575 if (!ev->isAccepted())
1576 QQuickImplicitSizeItem::inputMethodEvent(ev);
1578 if (wasComposing != d->hasImState)
1579 emit inputMethodComposingChanged();
1583void QQuickTextInput::mouseDoubleClickEvent(QMouseEvent *event)
1585 Q_D(QQuickTextInput);
1587 if (d->selectByMouse && event->button() == Qt::LeftButton &&
1588 QQuickDeliveryAgentPrivate::isEventFromMouseOrTouchpad(event)) {
1592 int cursor = d->positionAt(event->position());
1593 d->selectWordAtPos(cursor);
1594 event->setAccepted(
true);
1595 if (!d->hasPendingTripleClick()) {
1596 d->tripleClickStartPoint = event->position();
1597 d->tripleClickTimer.start();
1600 if (d->sendMouseEventToInputContext(event))
1602 QQuickImplicitSizeItem::mouseDoubleClickEvent(event);
1606void QQuickTextInput::mousePressEvent(QMouseEvent *event)
1608 Q_D(QQuickTextInput);
1610 d->pressPos = event->position();
1612 if (d->sendMouseEventToInputContext(event))
1615 d->hadSelectionOnMousePress = d->hasSelectedText();
1617 const bool isMouse = QQuickDeliveryAgentPrivate::isEventFromMouseOrTouchpad(event);
1618 if (d->selectByMouse &&
1620#if QT_VERSION < QT_VERSION_CHECK(7
, 0
, 0
)
1621 || d->selectByTouchDrag
1624 setKeepMouseGrab(
false);
1625 d->selectPressed =
true;
1626 QPointF distanceVector = d->pressPos - d->tripleClickStartPoint;
1627 if (d->hasPendingTripleClick()
1628 && distanceVector.manhattanLength() < QGuiApplication::styleHints()->startDragDistance()) {
1629 event->setAccepted(
true);
1636#if QT_VERSION < QT_VERSION_CHECK(7
, 0
, 0
)
1637 || d->selectByTouchDrag
1640 bool mark = (event->modifiers() & Qt::ShiftModifier) && d->selectByMouse;
1641 int cursor = d->positionAt(event->position());
1642 d->moveCursor(cursor, mark);
1645 if (d->focusOnPress && !qGuiApp->styleHints()->setFocusOnTouchRelease())
1646 ensureActiveFocus(Qt::MouseFocusReason);
1648 event->setAccepted(
true);
1651void QQuickTextInput::mouseMoveEvent(QMouseEvent *event)
1653 Q_D(QQuickTextInput);
1654 if (!QQuickDeliveryAgentPrivate::isEventFromMouseOrTouchpad(event)
1655#if QT_VERSION < QT_VERSION_CHECK(7
, 0
, 0
)
1656 && ! d->selectByTouchDrag
1661 if (d->selectPressed) {
1662 if (qAbs(
int(event->position().x() - d->pressPos.x())) > QGuiApplication::styleHints()->startDragDistance())
1663 setKeepMouseGrab(
true);
1666 if (d->composeMode()) {
1668 int startPos = d->positionAt(d->pressPos);
1669 int currentPos = d->positionAt(event->position());
1670 if (startPos != currentPos)
1671 d->setSelection(startPos, currentPos - startPos);
1675 moveCursorSelection(d->positionAt(event->position()), d->mouseSelectionMode);
1677 event->setAccepted(
true);
1679 QQuickImplicitSizeItem::mouseMoveEvent(event);
1683void QQuickTextInput::mouseReleaseEvent(QMouseEvent *event)
1685 Q_D(QQuickTextInput);
1686 if (d->sendMouseEventToInputContext(event))
1688 if (d->selectPressed) {
1689 d->selectPressed =
false;
1690 setKeepMouseGrab(
false);
1692 const bool isMouse = QQuickDeliveryAgentPrivate::isEventFromMouseOrTouchpad(event)
1693#if QT_VERSION < QT_VERSION_CHECK(7
, 0
, 0
)
1694 || d->selectByTouchDrag
1698#if QT_CONFIG(clipboard)
1699 if (isMouse && QGuiApplication::clipboard()->supportsSelection()) {
1700 if (event->button() == Qt::LeftButton) {
1701 d->copy(QClipboard::Selection);
1702 }
else if (!d->m_readOnly && event->button() == Qt::MiddleButton) {
1704 d->insert(QGuiApplication::clipboard()->text(QClipboard::Selection));
1713 if (!isMouse && (!d->hasSelectedText() || d->hadSelectionOnMousePress))
1714 d->moveCursor(d->positionAt(event->position()),
false);
1718 d->hadSelectionOnMousePress =
false;
1720 if (d->focusOnPress && qGuiApp->styleHints()->setFocusOnTouchRelease())
1721 ensureActiveFocus(Qt::MouseFocusReason);
1723 if (!event->isAccepted())
1724 QQuickImplicitSizeItem::mouseReleaseEvent(event);
1727#if QT_VERSION < QT_VERSION_CHECK(7
, 0
, 0
)
1728bool QQuickTextInputPrivate::handleContextMenuEvent(QContextMenuEvent *event)
1730bool QQuickTextInput::contextMenuEvent(QContextMenuEvent *event)
1733 Q_Q(QQuickTextInput);
1734 QContextMenuEvent mapped(event->reason(),
1735 q->mapToScene(q->cursorRectangle().center()).toPoint(), event->globalPos(),
1736 event->modifiers());
1737 const bool eventProcessed = QQuickItemPrivate::handleContextMenuEvent(&mapped);
1738 event->setAccepted(mapped.isAccepted());
1739 return eventProcessed;
1742bool QQuickTextInputPrivate::sendMouseEventToInputContext(QMouseEvent *event)
1745 if (composeMode()) {
1746 int tmp_cursor = positionAt(event->position());
1747 int mousePos = tmp_cursor - m_cursor;
1748 if (mousePos >= 0 && mousePos <= m_textLayout.preeditAreaText().size()) {
1749 if (event->type() == QEvent::MouseButtonRelease) {
1750 QGuiApplication::inputMethod()->invokeAction(QInputMethod::Click, mousePos);
1762void QQuickTextInput::mouseUngrabEvent()
1764 Q_D(QQuickTextInput);
1765 d->selectPressed =
false;
1766 setKeepMouseGrab(
false);
1769bool QQuickTextInput::event(QEvent* ev)
1771#if QT_CONFIG(shortcut)
1772 Q_D(QQuickTextInput);
1773 if (ev->type() == QEvent::ShortcutOverride) {
1774 if (d->m_readOnly) {
1778 QKeyEvent* ke =
static_cast<QKeyEvent*>(ev);
1779 if (ke == QKeySequence::Copy
1780 || ke == QKeySequence::Paste
1781 || ke == QKeySequence::Cut
1782 || ke == QKeySequence::Redo
1783 || ke == QKeySequence::Undo
1784 || ke == QKeySequence::MoveToNextWord
1785 || ke == QKeySequence::MoveToPreviousWord
1786 || ke == QKeySequence::MoveToStartOfDocument
1787 || ke == QKeySequence::MoveToEndOfDocument
1788 || ke == QKeySequence::SelectNextWord
1789 || ke == QKeySequence::SelectPreviousWord
1790 || ke == QKeySequence::SelectStartOfLine
1791 || ke == QKeySequence::SelectEndOfLine
1792 || ke == QKeySequence::SelectStartOfBlock
1793 || ke == QKeySequence::SelectEndOfBlock
1794 || ke == QKeySequence::SelectStartOfDocument
1795 || ke == QKeySequence::SelectAll
1796 || ke == QKeySequence::SelectEndOfDocument
1797 || ke == QKeySequence::DeleteCompleteLine) {
1800 }
else if (ke->modifiers() == Qt::NoModifier || ke->modifiers() == Qt::ShiftModifier
1801 || ke->modifiers() == Qt::KeypadModifier) {
1802 if (ke->key() < Qt::Key_Escape) {
1806 switch (ke->key()) {
1807 case Qt::Key_Delete:
1810 case Qt::Key_Backspace:
1824 return QQuickImplicitSizeItem::event(ev);
1827void QQuickTextInput::geometryChange(
const QRectF &newGeometry,
1828 const QRectF &oldGeometry)
1830 Q_D(QQuickTextInput);
1832 if (newGeometry.width() != oldGeometry.width())
1834 else if (newGeometry.height() != oldGeometry.height() && d->vAlign != QQuickTextInput::AlignTop)
1835 d->updateBaselineOffset();
1836 updateCursorRectangle();
1838 QQuickImplicitSizeItem::geometryChange(newGeometry, oldGeometry);
1841void QQuickTextInput::itemChange(ItemChange change,
const ItemChangeData &value)
1843 Q_D(QQuickTextInput);
1846 case ItemDevicePixelRatioHasChanged:
1847 if (d->containsUnscalableGlyphs) {
1858 QQuickImplicitSizeItem::itemChange(change, value);
1861void QQuickTextInputPrivate::ensureVisible(
int position,
int preeditCursor,
int preeditLength)
1863 Q_Q(QQuickTextInput);
1864 QTextLine textLine = m_textLayout.lineForTextPosition(position + preeditCursor);
1865 const qreal width = qMax<qreal>(0, q->width() - q->leftPadding() - q->rightPadding());
1867 qreal widthUsed = 0;
1868 if (textLine.isValid()) {
1869 cix = textLine.cursorToX(position + preeditLength);
1870 const qreal cursorWidth = cix >= 0 ? cix : width - cix;
1871 widthUsed = qMax(textLine.naturalTextWidth(), cursorWidth);
1873 int previousScroll = hscroll;
1875 if (widthUsed <= width) {
1878 Q_ASSERT(textLine.isValid());
1879 if (cix - hscroll >= width) {
1881 hscroll = cix - width;
1882 }
else if (cix - hscroll < 0 && hscroll < widthUsed) {
1885 }
else if (widthUsed - hscroll < width) {
1888 hscroll = widthUsed - width;
1889 }
else if (width - hscroll > widthUsed) {
1892 hscroll = width - widthUsed;
1895 if (preeditLength > 0) {
1898 cix = textLine.cursorToX(position + qMax(0, preeditCursor - 1));
1904 if (previousScroll != hscroll)
1905 textLayoutDirty =
true;
1908void QQuickTextInputPrivate::updateHorizontalScroll()
1910 if (autoScroll && m_echoMode != QQuickTextInput::NoEcho) {
1912 const int preeditLength = m_textLayout.preeditAreaText().size();
1913 ensureVisible(m_cursor, m_preeditCursor, preeditLength);
1915 ensureVisible(m_cursor);
1922void QQuickTextInputPrivate::updateVerticalScroll()
1924 Q_Q(QQuickTextInput);
1926 const int preeditLength = m_textLayout.preeditAreaText().size();
1928 const qreal height = qMax<qreal>(0, q->height() - q->topPadding() - q->bottomPadding());
1929 qreal heightUsed = contentSize.height();
1930 qreal previousScroll = vscroll;
1932 if (!autoScroll || heightUsed <= height) {
1934 vscroll = -QQuickTextUtil::alignedY(
1935 heightUsed, height, vAlign & ~(Qt::AlignAbsolute|Qt::AlignHorizontal_Mask));
1938 QTextLine currentLine = m_textLayout.lineForTextPosition(m_cursor + preeditLength);
1940 QTextLine currentLine = m_textLayout.lineForTextPosition(m_cursor);
1942 QRectF r = currentLine.isValid() ? currentLine.rect() : QRectF();
1943 qreal top = r.top();
1944 int bottom = r.bottom();
1946 if (bottom - vscroll >= height) {
1948 vscroll = bottom - height;
1949 }
else if (top - vscroll < 0 && vscroll < heightUsed) {
1952 }
else if (heightUsed - vscroll < height) {
1955 vscroll = heightUsed - height;
1958 if (preeditLength > 0) {
1961 currentLine = m_textLayout.lineForTextPosition(m_cursor + qMax(0, m_preeditCursor - 1));
1962 top = currentLine.isValid() ? currentLine.rect().top() : 0;
1968 if (previousScroll != vscroll)
1969 textLayoutDirty =
true;
1972void QQuickTextInput::triggerPreprocess()
1974 Q_D(QQuickTextInput);
1975 if (d->updateType == QQuickTextInputPrivate::UpdateNone)
1976 d->updateType = QQuickTextInputPrivate::UpdateOnlyPreprocess;
1981void QQuickTextInput::updatePolish()
1983 invalidateFontCaches();
1986void QQuickTextInput::invalidateFontCaches()
1988 Q_D(QQuickTextInput);
1990 if (d->m_textLayout.engine() !=
nullptr)
1991 d->m_textLayout.engine()->resetFontEngineCache();
1994void QQuickTextInput::ensureActiveFocus(Qt::FocusReason reason)
1996 bool hadActiveFocus = hasActiveFocus();
1997 forceActiveFocus(reason);
1999 Q_D(QQuickTextInput);
2001 if (hasActiveFocus() && hadActiveFocus && !d->m_readOnly)
2002 qGuiApp->inputMethod()->show();
2004 Q_UNUSED(hadActiveFocus);
2008QSGNode *QQuickTextInput::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data)
2011 Q_D(QQuickTextInput);
2013 if (d->updateType != QQuickTextInputPrivate::UpdatePaintNode && oldNode !=
nullptr) {
2015 d->updateType = QQuickTextInputPrivate::UpdateNone;
2019 d->updateType = QQuickTextInputPrivate::UpdateNone;
2021 QSGInternalTextNode *node =
static_cast<QSGInternalTextNode *>(oldNode);
2022 if (node ==
nullptr)
2023 node = d->sceneGraphContext()->createInternalTextNode(d->sceneGraphRenderContext());
2026 const bool showCursor = !isReadOnly() && d->cursorItem ==
nullptr && d->cursorVisible && d->m_blinkStatus;
2028 if (!d->textLayoutDirty && oldNode !=
nullptr) {
2030 node->setCursor(cursorRectangle(), d->color);
2032 node->clearCursor();
2034 node->setRenderType(QSGTextNode::RenderType(d->renderType));
2036 node->setMatrix(QMatrix4x4());
2037 node->setTextStyle(QSGInternalTextNode::Normal);
2038 node->setColor(d->color);
2039 node->setSelectionTextColor(d->selectedTextColor);
2040 node->setSelectionColor(d->selectionColor);
2041 node->setFiltering(smooth() ? QSGTexture::Linear : QSGTexture::Nearest);
2043 if (flags().testFlag(ItemObservesViewport))
2044 node->setViewport(clipRect());
2046 node->setViewport(QRectF{});
2048 QPointF offset(leftPadding(), topPadding());
2049 offset -= QPointF(d->hscroll, d->vscroll);
2051 if (!d->m_textLayout.text().isEmpty()
2053 || !d->m_textLayout.preeditAreaText().isEmpty()
2056 node->addTextLayout(offset, &d->m_textLayout,
2057 d->selectionStart(),
2058 d->selectionEnd() - 1);
2063 node->setCursor(cursorRectangle(), d->color);
2065 d->textLayoutDirty =
false;
2068 d->containsUnscalableGlyphs = node->containsUnscalableGlyphs();
2070 invalidateFontCaches();
2076QVariant QQuickTextInput::inputMethodQuery(Qt::InputMethodQuery property)
const
2080 if (property == Qt::ImEnterKeyType) {
2081 Q_D(
const QQuickItem);
2083 if (!d->extra.isAllocated()
2084 || d->extra->enterKeyAttached ==
nullptr
2085 || d->extra->enterKeyAttached->type() == Qt::EnterKeyDefault) {
2087 QQuickItem *next =
const_cast<QQuickTextInput*>(
this)->nextItemInFocusChain();
2088 QQuickItem *originalNext = next;
2089 while (next && next !=
this && !next->activeFocusOnTab()) {
2090 next = next->nextItemInFocusChain();
2091 if (next == originalNext) {
2097 const auto nextYPos = next->mapToGlobal(QPoint(0, 0)).y();
2098 const auto currentYPos =
this->mapToGlobal(QPoint(0, 0)).y();
2099 if (currentYPos < nextYPos)
2102 return Qt::EnterKeyNext;
2107 return inputMethodQuery(property, QVariant());
2110QVariant QQuickTextInput::inputMethodQuery(Qt::InputMethodQuery property,
const QVariant &argument)
const
2112 Q_D(
const QQuickTextInput);
2115 return QVariant((
bool)(flags() & ItemAcceptsInputMethod));
2117 return QVariant((
int) d->effectiveInputMethodHints());
2118 case Qt::ImCursorRectangle:
2119 return cursorRectangle();
2120 case Qt::ImAnchorRectangle:
2121 return d->anchorRectangle();
2124 case Qt::ImCursorPosition: {
2125 const QPointF pt = argument.toPointF();
2127 return QVariant(d->positionAt(pt));
2128 return QVariant(d->m_cursor);
2130 case Qt::ImSurroundingText:
2131 if (d->m_echoMode == PasswordEchoOnEdit && !d->m_passwordEchoEditing) {
2132 return QVariant(displayText());
2134 return QVariant(d->realText());
2136 case Qt::ImCurrentSelection:
2137 return QVariant(selectedText());
2138 case Qt::ImMaximumTextLength:
2139 return QVariant(maxLength());
2140 case Qt::ImAnchorPosition:
2141 if (d->selectionStart() == d->selectionEnd())
2142 return QVariant(d->m_cursor);
2143 else if (d->selectionStart() == d->m_cursor)
2144 return QVariant(d->selectionEnd());
2146 return QVariant(d->selectionStart());
2147 case Qt::ImAbsolutePosition:
2148 return QVariant(d->m_cursor);
2149 case Qt::ImTextAfterCursor:
2150 if (argument.isValid())
2151 return QVariant(d->m_text.mid(d->m_cursor, argument.toInt()));
2152 return QVariant(d->m_text.mid(d->m_cursor));
2153 case Qt::ImTextBeforeCursor:
2154 if (argument.isValid())
2155 return QVariant(QStringView{d->m_text}.left(d->m_cursor).right(argument.toInt()).toString());
2156 return QVariant(d->m_text.left(d->m_cursor));
2157 case Qt::ImReadOnly:
2158 return QVariant(d->m_readOnly);
2160 return QQuickItem::inputMethodQuery(property);
2166
2167
2168
2169
2170void QQuickTextInput::deselect()
2172 Q_D(QQuickTextInput);
2177
2178
2179
2180
2181void QQuickTextInput::selectAll()
2183 Q_D(QQuickTextInput);
2184 d->setSelection(0, text().size());
2188
2189
2190
2191
2192
2193bool QQuickTextInput::isRightToLeft(
int start,
int end)
2196 qmlWarning(
this) <<
"isRightToLeft(start, end) called with the end property being smaller than the start.";
2199 return QStringView{text()}.mid(start, end - start).isRightToLeft();
2203#if QT_CONFIG(clipboard)
2205
2206
2207
2208
2209
2210
2211
2212
2213void QQuickTextInput::cut()
2215 Q_D(QQuickTextInput);
2216 if (!d->m_readOnly && d->m_echoMode == QQuickTextInput::Normal) {
2223
2224
2225
2226
2227
2228
2229
2230
2231void QQuickTextInput::copy()
2233 Q_D(QQuickTextInput);
2238
2239
2240
2241
2242void QQuickTextInput::paste()
2244 Q_D(QQuickTextInput);
2251
2252
2253
2254
2255
2256
2258void QQuickTextInput::undo()
2260 Q_D(QQuickTextInput);
2261 if (!d->m_readOnly) {
2264 d->finishChange(-1,
true);
2269
2270
2271
2272
2274void QQuickTextInput::redo()
2276 Q_D(QQuickTextInput);
2277 if (!d->m_readOnly) {
2285
2286
2287
2288
2290void QQuickTextInput::insert(
int position,
const QString &text)
2292 Q_D(QQuickTextInput);
2293 if (d->m_echoMode == QQuickTextInput::Password) {
2294 if (d->m_passwordMaskDelay > 0)
2295 d->m_passwordEchoTimer.start(d->m_passwordMaskDelay,
this);
2297 if (position < 0 || position > d->m_text.size())
2300 const int priorState = d->m_undoState;
2302 QString insertText = text;
2304 if (d->hasSelectedText()) {
2305 d->addCommand(QQuickTextInputPrivate::Command(
2306 QQuickTextInputPrivate::SetSelection, d->m_cursor, u'\0', d->m_selstart, d->m_selend));
2308 if (d->m_maskData) {
2309 insertText = d->maskString(position, insertText);
2310 for (
int i = 0; i < insertText.size(); ++i) {
2311 d->addCommand(QQuickTextInputPrivate::Command(
2312 QQuickTextInputPrivate::DeleteSelection, position + i, d->m_text.at(position + i), -1, -1));
2313 d->addCommand(QQuickTextInputPrivate::Command(
2314 QQuickTextInputPrivate::Insert, position + i, insertText.at(i), -1, -1));
2316 d->m_text.replace(position, insertText.size(), insertText);
2317 if (!insertText.isEmpty())
2318 d->m_textDirty =
true;
2319 if (position < d->m_selend && position + insertText.size() > d->m_selstart)
2320 d->m_selDirty =
true;
2322 int remaining = d->m_maxLength - d->m_text.size();
2323 if (remaining != 0) {
2324 insertText = insertText.left(remaining);
2325 d->m_text.insert(position, insertText);
2326 for (
int i = 0; i < insertText.size(); ++i)
2327 d->addCommand(QQuickTextInputPrivate::Command(
2328 QQuickTextInputPrivate::Insert, position + i, insertText.at(i), -1, -1));
2329 if (d->m_cursor >= position)
2330 d->m_cursor += insertText.size();
2331 if (d->m_selstart >= position)
2332 d->m_selstart += insertText.size();
2333 if (d->m_selend >= position)
2334 d->m_selend += insertText.size();
2335 d->m_textDirty =
true;
2336 if (position >= d->m_selstart && position <= d->m_selend)
2337 d->m_selDirty =
true;
2341 d->addCommand(QQuickTextInputPrivate::Command(
2342 QQuickTextInputPrivate::SetSelection, d->m_cursor, u'\0', d->m_selstart, d->m_selend));
2343 d->finishChange(priorState);
2345 if (d->lastSelectionStart != d->lastSelectionEnd) {
2346 if (d->m_selstart != d->lastSelectionStart) {
2347 d->lastSelectionStart = d->m_selstart;
2348 emit selectionStartChanged();
2350 if (d->m_selend != d->lastSelectionEnd) {
2351 d->lastSelectionEnd = d->m_selend;
2352 emit selectionEndChanged();
2358
2359
2360
2361
2363void QQuickTextInput::remove(
int start,
int end)
2365 Q_D(QQuickTextInput);
2367 start = qBound(0, start, d->m_text.size());
2368 end = qBound(0, end, d->m_text.size());
2372 else if (start == end)
2375 if (start < d->m_selend && end > d->m_selstart)
2376 d->m_selDirty =
true;
2378 const int priorState = d->m_undoState;
2380 d->addCommand(QQuickTextInputPrivate::Command(
2381 QQuickTextInputPrivate::SetSelection, d->m_cursor, u'\0', d->m_selstart, d->m_selend));
2383 if (start <= d->m_cursor && d->m_cursor < end) {
2386 for (
int i = d->m_cursor; i >= start; --i) {
2387 d->addCommand(QQuickTextInputPrivate::Command(
2388 QQuickTextInputPrivate::DeleteSelection, i, d->m_text.at(i), -1, 1));
2390 for (
int i = end - 1; i > d->m_cursor; --i) {
2391 d->addCommand(QQuickTextInputPrivate::Command(
2392 QQuickTextInputPrivate::DeleteSelection, i - d->m_cursor + start - 1, d->m_text.at(i), -1, -1));
2395 for (
int i = end - 1; i >= start; --i) {
2396 d->addCommand(QQuickTextInputPrivate::Command(
2397 QQuickTextInputPrivate::RemoveSelection, i, d->m_text.at(i), -1, -1));
2400 if (d->m_maskData) {
2401 d->m_text.replace(start, end - start, d->clearString(start, end - start));
2402 for (
int i = 0; i < end - start; ++i) {
2403 d->addCommand(QQuickTextInputPrivate::Command(
2404 QQuickTextInputPrivate::Insert, start + i, d->m_text.at(start + i), -1, -1));
2407 d->m_text.remove(start, end - start);
2409 if (d->m_cursor > start)
2410 d->m_cursor -= qMin(d->m_cursor, end) - start;
2411 if (d->m_selstart > start)
2412 d->m_selstart -= qMin(d->m_selstart, end) - start;
2413 if (d->m_selend >= end)
2414 d->m_selend -= end - start;
2416 d->addCommand(QQuickTextInputPrivate::Command(
2417 QQuickTextInputPrivate::SetSelection, d->m_cursor, u'\0', d->m_selstart, d->m_selend));
2419 d->m_textDirty =
true;
2420 d->finishChange(priorState);
2422 if (d->lastSelectionStart != d->lastSelectionEnd) {
2423 if (d->m_selstart != d->lastSelectionStart) {
2424 d->lastSelectionStart = d->m_selstart;
2425 emit selectionStartChanged();
2427 if (d->m_selend != d->lastSelectionEnd) {
2428 d->lastSelectionEnd = d->m_selend;
2429 emit selectionEndChanged();
2436
2437
2438
2439
2440void QQuickTextInput::selectWord()
2442 Q_D(QQuickTextInput);
2443 d->selectWordAtPos(d->m_cursor);
2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457QString QQuickTextInput::passwordCharacter()
const
2459 Q_D(
const QQuickTextInput);
2460 return QString(d->m_passwordCharacter);
2463void QQuickTextInput::setPasswordCharacter(
const QString &str)
2465 Q_D(QQuickTextInput);
2468 d->m_passwordCharacter = str.constData()[0];
2469 if (d->m_echoMode == Password || d->m_echoMode == PasswordEchoOnEdit)
2470 d->updateDisplayText();
2471 emit passwordCharacterChanged();
2475
2476
2477
2478
2479
2480
2481
2482int QQuickTextInput::passwordMaskDelay()
const
2484 Q_D(
const QQuickTextInput);
2485 return d->m_passwordMaskDelay;
2488void QQuickTextInput::setPasswordMaskDelay(
int delay)
2490 Q_D(QQuickTextInput);
2491 if (d->m_passwordMaskDelay != delay) {
2492 d->m_passwordMaskDelay = delay;
2493 emit passwordMaskDelayChanged(delay);
2497void QQuickTextInput::resetPasswordMaskDelay()
2499 setPasswordMaskDelay(qGuiApp->styleHints()->passwordMaskDelay());
2503
2504
2505
2506
2507
2508
2509
2510
2511
2512
2513
2514
2515
2516
2517
2518QString QQuickTextInput::displayText()
const
2520 Q_D(
const QQuickTextInput);
2521 return d->m_textLayout.text().insert(d->m_textLayout.preeditAreaPosition(), d->m_textLayout.preeditAreaText());
2525
2526
2527
2528
2529
2530
2531
2532
2533
2534
2535
2536QString QQuickTextInput::preeditText()
const
2538 Q_D(
const QQuickTextInput);
2539 return d->m_textLayout.preeditAreaText();
2543
2544
2545
2546
2547
2548
2549
2550
2551
2552
2553
2554
2555
2556
2557
2558
2559
2560bool QQuickTextInput::selectByMouse()
const
2562 Q_D(
const QQuickTextInput);
2563 return d->selectByMouse;
2566void QQuickTextInput::setSelectByMouse(
bool on)
2568 Q_D(QQuickTextInput);
2569 if (d->selectByMouse != on) {
2570 d->selectByMouse = on;
2571 emit selectByMouseChanged(on);
2576
2577
2578
2579
2580
2581
2582
2583
2584
2586QQuickTextInput::SelectionMode QQuickTextInput::mouseSelectionMode()
const
2588 Q_D(
const QQuickTextInput);
2589 return d->mouseSelectionMode;
2592void QQuickTextInput::setMouseSelectionMode(SelectionMode mode)
2594 Q_D(QQuickTextInput);
2595 if (d->mouseSelectionMode != mode) {
2596 d->mouseSelectionMode = mode;
2597 emit mouseSelectionModeChanged(mode);
2602
2603
2604
2605
2606
2608bool QQuickTextInput::persistentSelection()
const
2610 Q_D(
const QQuickTextInput);
2611 return d->persistentSelection;
2614void QQuickTextInput::setPersistentSelection(
bool on)
2616 Q_D(QQuickTextInput);
2617 if (d->persistentSelection == on)
2619 d->persistentSelection = on;
2620 emit persistentSelectionChanged();
2624
2625
2626
2627
2628
2629
2630bool QQuickTextInput::canPaste()
const
2632#if QT_CONFIG(clipboard)
2633 Q_D(
const QQuickTextInput);
2634 if (!d->canPasteValid) {
2635 bool canPaste =
false;
2636 if (!d->m_readOnly) {
2637 if (
const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData())
2638 canPaste = mimeData->hasText() && !mimeData->text().isEmpty();
2640 const_cast<QQuickTextInputPrivate *>(d)->canPaste = canPaste;
2641 const_cast<QQuickTextInputPrivate *>(d)->canPasteValid =
true;
2650
2651
2652
2653
2654
2655
2657bool QQuickTextInput::canUndo()
const
2659 Q_D(
const QQuickTextInput);
2664
2665
2666
2667
2668
2669
2671bool QQuickTextInput::canRedo()
const
2673 Q_D(
const QQuickTextInput);
2678
2679
2680
2681
2682
2683
2685qreal QQuickTextInput::contentWidth()
const
2687 Q_D(
const QQuickTextInput);
2688 return d->contentSize.width();
2692
2693
2694
2695
2696
2697
2699qreal QQuickTextInput::contentHeight()
const
2701 Q_D(
const QQuickTextInput);
2702 return d->contentSize.height();
2705void QQuickTextInput::moveCursorSelection(
int position)
2707 Q_D(QQuickTextInput);
2708 d->moveCursor(position,
true);
2712
2713
2714
2715
2716
2717
2718
2719
2720
2721
2722
2723
2724
2725
2726
2727
2728
2729
2730
2731
2732
2733
2734
2735
2736
2737
2738
2739
2740
2741
2742
2743
2744
2745
2746
2747void QQuickTextInput::moveCursorSelection(
int pos, SelectionMode mode)
2749 Q_D(QQuickTextInput);
2751 if (mode == SelectCharacters) {
2752 d->moveCursor(pos,
true);
2753 }
else if (pos != d->m_cursor) {
2754 const int cursor = d->m_cursor;
2756 if (!d->hasSelectedText())
2757 anchor = d->m_cursor;
2758 else if (d->selectionStart() == d->m_cursor)
2759 anchor = d->selectionEnd();
2761 anchor = d->selectionStart();
2763 if (anchor < pos || (anchor == pos && cursor < pos)) {
2764 const QString text =
this->text();
2765 QTextBoundaryFinder finder(QTextBoundaryFinder::Word, text);
2766 finder.setPosition(anchor);
2768 const QTextBoundaryFinder::BoundaryReasons reasons = finder.boundaryReasons();
2769 if (anchor < text.size() && (reasons == QTextBoundaryFinder::NotAtBoundary
2770 || (reasons & QTextBoundaryFinder::EndOfItem))) {
2771 finder.toPreviousBoundary();
2773 anchor = finder.position() != -1 ? finder.position() : 0;
2775 finder.setPosition(pos);
2776 if (pos > 0 && !finder.boundaryReasons())
2777 finder.toNextBoundary();
2778 const int cursor = finder.position() != -1 ? finder.position() : text.size();
2780 d->setSelection(anchor, cursor - anchor);
2781 }
else if (anchor > pos || (anchor == pos && cursor > pos)) {
2782 const QString text =
this->text();
2783 QTextBoundaryFinder finder(QTextBoundaryFinder::Word, text);
2784 finder.setPosition(anchor);
2786 const QTextBoundaryFinder::BoundaryReasons reasons = finder.boundaryReasons();
2787 if (anchor > 0 && (reasons == QTextBoundaryFinder::NotAtBoundary
2788 || (reasons & QTextBoundaryFinder::StartOfItem))) {
2789 finder.toNextBoundary();
2791 anchor = finder.position() != -1 ? finder.position() : text.size();
2793 finder.setPosition(pos);
2794 if (pos < text.size() && !finder.boundaryReasons())
2795 finder.toPreviousBoundary();
2796 const int cursor = finder.position() != -1 ? finder.position() : 0;
2798 d->setSelection(anchor, cursor - anchor);
2803void QQuickTextInput::focusInEvent(QFocusEvent *event)
2805 Q_D(QQuickTextInput);
2806 d->handleFocusEvent(event);
2807 QQuickImplicitSizeItem::focusInEvent(event);
2810void QQuickTextInputPrivate::handleFocusEvent(QFocusEvent *event)
2812 Q_Q(QQuickTextInput);
2813 bool focus = event->gotFocus();
2815 q->setCursorVisible(focus);
2816 setBlinkingCursorEnabled(focus);
2819 q->q_updateAlignment();
2821 if (focusOnPress && !m_readOnly)
2822 qGuiApp->inputMethod()->show();
2823 q->connect(QGuiApplication::inputMethod(), SIGNAL(inputDirectionChanged(Qt::LayoutDirection)),
2824 q, SLOT(q_updateAlignment()));
2827 if ((m_passwordEchoEditing || m_passwordEchoTimer.isActive())) {
2828 updatePasswordEchoEditing(
false);
2831 if (event->reason() != Qt::ActiveWindowFocusReason
2832 && event->reason() != Qt::PopupFocusReason
2833 && hasSelectedText()
2834 && !persistentSelection)
2837 if (hasAcceptableInput(m_text) == AcceptableInput || fixup())
2838 emit q->editingFinished();
2841 q->disconnect(QGuiApplication::inputMethod(), SIGNAL(inputDirectionChanged(Qt::LayoutDirection)),
2842 q, SLOT(q_updateAlignment()));
2847void QQuickTextInput::focusOutEvent(QFocusEvent *event)
2849 Q_D(QQuickTextInput);
2850 d->handleFocusEvent(event);
2851 QQuickImplicitSizeItem::focusOutEvent(event);
2854void QQuickTextInputPrivate::readOnlyChanged(
bool isReadOnly)
2856 Q_UNUSED(isReadOnly);
2857#if QT_CONFIG(accessibility)
2858 if (QQuickAccessibleAttached *accessibleAttached =
2859 QQuickAccessibleAttached::attachedProperties(q_func()))
2860 accessibleAttached->set_readOnly(isReadOnly);
2864void QQuickTextInputPrivate::echoModeChanged(QQuickTextInput::EchoMode echoMode)
2866#if QT_CONFIG(accessibility)
2867 if (!QAccessible::isActive())
2870 if (QQuickAccessibleAttached *accessibleAttached =
2871 QQuickAccessibleAttached::attachedProperties(q_func()))
2872 accessibleAttached->set_passwordEdit((echoMode == QQuickTextInput::Password
2873 || echoMode == QQuickTextInput::PasswordEchoOnEdit)
2881#if QT_CONFIG(accessibility)
2882void QQuickTextInputPrivate::accessibilityActiveChanged(
bool active)
2887 Q_Q(QQuickTextInput);
2888 QQuickAccessibleAttached *accessibleAttached = qobject_cast<QQuickAccessibleAttached *>(
2889 qmlAttachedPropertiesObject<QQuickAccessibleAttached>(q,
true));
2890 Q_ASSERT(accessibleAttached);
2891 accessibleAttached->setRole(effectiveAccessibleRole());
2892 accessibleAttached->set_readOnly(m_readOnly);
2893 accessibleAttached->set_passwordEdit((m_echoMode == QQuickTextInput::Password
2894 || m_echoMode == QQuickTextInput::PasswordEchoOnEdit)
2899QAccessible::Role QQuickTextInputPrivate::accessibleRole()
const
2901 return QAccessible::EditableText;
2906
2907
2908
2909
2910
2911
2912
2913
2914
2915
2916
2917bool QQuickTextInput::isInputMethodComposing()
const
2922 Q_D(
const QQuickTextInput);
2923 return d->hasImState;
2927QQuickTextInputPrivate::ExtraData::ExtraData()
2933 , explicitTopPadding(
false)
2934 , explicitLeftPadding(
false)
2935 , explicitRightPadding(
false)
2936 , explicitBottomPadding(
false)
2937 , implicitResize(
true)
2941void QQuickTextInputPrivate::init()
2943 Q_Q(QQuickTextInput);
2944#if QT_CONFIG(clipboard)
2945 if (QGuiApplication::clipboard()->supportsSelection())
2946 q->setAcceptedMouseButtons(Qt::LeftButton | Qt::MiddleButton);
2949 q->setAcceptedMouseButtons(Qt::LeftButton);
2952 q->setFlag(QQuickItem::ItemAcceptsInputMethod);
2954 q->setFlag(QQuickItem::ItemHasContents);
2955#if QT_CONFIG(clipboard)
2956 qmlobject_connect(QGuiApplication::clipboard(), QClipboard, SIGNAL(dataChanged()),
2957 q, QQuickTextInput, SLOT(q_canPasteChanged()));
2960 lastSelectionStart = 0;
2961 lastSelectionEnd = 0;
2962 determineHorizontalAlignment();
2964 if (!qmlDisableDistanceField()) {
2965 QTextOption option = m_textLayout.textOption();
2966 option.setUseDesignMetrics(renderType != QQuickTextInput::NativeRendering);
2967 m_textLayout.setTextOption(option);
2970 m_inputControl =
new QInputControl(QInputControl::LineEdit, q);
2971 setSizePolicy(QLayoutPolicy::Expanding, QLayoutPolicy::Fixed);
2973 QObjectPrivate::connect(q, &QQuickTextInput::readOnlyChanged,
this,
2974 &QQuickTextInputPrivate::readOnlyChanged);
2975 QObjectPrivate::connect(q, &QQuickTextInput::echoModeChanged,
this,
2976 &QQuickTextInputPrivate::echoModeChanged);
2979void QQuickTextInputPrivate::cancelInput()
2982 Q_Q(QQuickTextInput);
2983 if (!m_readOnly && q->hasActiveFocus() && qGuiApp)
2988void QQuickTextInput::updateCursorRectangle(
bool scroll)
2990 Q_D(QQuickTextInput);
2991 if (!isComponentComplete())
2995 d->updateHorizontalScroll();
2996 d->updateVerticalScroll();
2998 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
3001 emit cursorRectangleChanged();
3002 if (d->cursorItem) {
3003 QRectF r = cursorRectangle();
3004 d->cursorItem->setPosition(r.topLeft());
3005 d->cursorItem->setHeight(r.height());
3008 updateInputMethod(Qt::ImCursorRectangle | Qt::ImAnchorRectangle);
3012void QQuickTextInput::selectionChanged()
3014 Q_D(QQuickTextInput);
3015 d->textLayoutDirty =
true;
3016 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
3019 emit selectedTextChanged();
3021 if (d->lastSelectionStart != d->selectionStart()) {
3022 d->lastSelectionStart = d->selectionStart();
3023 if (d->lastSelectionStart == -1)
3024 d->lastSelectionStart = d->m_cursor;
3025 emit selectionStartChanged();
3027 if (d->lastSelectionEnd != d->selectionEnd()) {
3028 d->lastSelectionEnd = d->selectionEnd();
3029 if (d->lastSelectionEnd == -1)
3030 d->lastSelectionEnd = d->m_cursor;
3031 emit selectionEndChanged();
3035QRectF QQuickTextInput::boundingRect()
const
3037 Q_D(
const QQuickTextInput);
3039 int cursorWidth = d->cursorItem ? 0 : 1;
3041 qreal hscroll = d->hscroll;
3042 if (!d->autoScroll || d->contentSize.width() < width())
3043 hscroll -= QQuickTextUtil::alignedX(d->contentSize.width(), width(), effectiveHAlign());
3046 QRectF r(-hscroll, -d->vscroll, d->contentSize.width(), d->contentSize.height());
3047 r.setRight(r.right() + cursorWidth);
3051QRectF QQuickTextInput::clipRect()
const
3053 Q_D(
const QQuickTextInput);
3055 int cursorWidth = d->cursorItem ? d->cursorItem->width() : 1;
3058 QRectF r = QQuickImplicitSizeItem::clipRect();
3059 r.setRight(r.right() + cursorWidth);
3063void QQuickTextInput::q_canPasteChanged()
3065 Q_D(QQuickTextInput);
3066 bool old = d->canPaste;
3067#if QT_CONFIG(clipboard)
3068 bool canPaste =
false;
3069 if (!d->m_readOnly) {
3070 if (
const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData())
3071 canPaste = mimeData->hasText() && !mimeData->text().isEmpty();
3073 d->canPaste = canPaste;
3076 bool changed = d->canPaste != old || !d->canPasteValid;
3077 d->canPasteValid =
true;
3079 emit canPasteChanged();
3083void QQuickTextInput::q_updateAlignment()
3085 Q_D(QQuickTextInput);
3086 if (d->determineHorizontalAlignment()) {
3088 updateCursorRectangle();
3093
3094
3095
3096
3097
3098void QQuickTextInputPrivate::updateDisplayText(
bool forceUpdate)
3100 QString orig = m_textLayout.text();
3102 if (m_echoMode == QQuickTextInput::NoEcho)
3103 str = QString::fromLatin1(
"");
3107 if (m_echoMode == QQuickTextInput::Password) {
3108 str.fill(m_passwordCharacter);
3109 if (m_passwordEchoTimer.isActive() && m_cursor > 0 && m_cursor <= m_text.size()) {
3110 int cursor = m_cursor - 1;
3111 QChar uc = m_text.at(cursor);
3113 if (cursor > 0 && uc.unicode() >= 0xdc00 && uc.unicode() < 0xe000) {
3116 uc = m_text.at(cursor - 1);
3117 if (uc.unicode() >= 0xd800 && uc.unicode() < 0xdc00)
3118 str[cursor - 1] = uc;
3121 }
else if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit && !m_passwordEchoEditing) {
3122 str.fill(m_passwordCharacter);
3128 QChar* uc = str.data();
3129 for (
int i = 0; i < str.size(); ++i) {
3130 if (uc[i] == QChar::LineSeparator
3131 || uc[i] == QChar::ParagraphSeparator
3132 || uc[i] == QChar::ObjectReplacementCharacter)
3133 uc[i] = QChar(0x0020);
3136 if (str != orig || forceUpdate) {
3137 m_textLayout.setText(str);
3139 emit q_func()->displayTextChanged();
3143qreal QQuickTextInputPrivate::calculateImplicitWidthForText(
const QString &text)
const
3145 Q_Q(
const QQuickTextInput);
3146 QTextLayout layout(text);
3148 QTextOption option = m_textLayout.textOption();
3149 option.setTextDirection(m_layoutDirection);
3150 option.setFlags(QTextOption::IncludeTrailingSpaces);
3151 option.setWrapMode(QTextOption::WrapMode(wrapMode));
3152 option.setAlignment(Qt::Alignment(q->effectiveHAlign()));
3153 layout.setTextOption(option);
3154 layout.setFont(font);
3156 layout.setPreeditArea(m_textLayout.preeditAreaPosition(), m_textLayout.preeditAreaText());
3158 layout.beginLayout();
3160 QTextLine line = layout.createLine();
3161 line.setLineWidth(qreal(INT_MAX));
3162 const qreal theImplicitWidth = qCeil(line.naturalTextWidth()) + q->leftPadding() + q->rightPadding();
3165 return theImplicitWidth;
3168qreal QQuickTextInputPrivate::getImplicitWidth()
const
3170 Q_Q(
const QQuickTextInput);
3171 if (!requireImplicitWidth) {
3172 QQuickTextInputPrivate *d =
const_cast<QQuickTextInputPrivate *>(
this);
3173 d->requireImplicitWidth =
true;
3175 if (q->isComponentComplete())
3176 d->implicitWidth = calculateImplicitWidthForText(m_text);
3178 return implicitWidth;
3181void QQuickTextInputPrivate::setTopPadding(qreal value,
bool reset)
3183 Q_Q(QQuickTextInput);
3184 qreal oldPadding = q->topPadding();
3185 if (!reset || extra.isAllocated()) {
3186 extra.value().topPadding = value;
3187 extra.value().explicitTopPadding = !reset;
3189 if ((!reset && !qFuzzyCompare(oldPadding, value)) || (reset && !qFuzzyCompare(oldPadding, padding()))) {
3191 q->updateCursorRectangle();
3192 emit q->topPaddingChanged();
3196void QQuickTextInputPrivate::setLeftPadding(qreal value,
bool reset)
3198 Q_Q(QQuickTextInput);
3199 qreal oldPadding = q->leftPadding();
3200 if (!reset || extra.isAllocated()) {
3201 extra.value().leftPadding = value;
3202 extra.value().explicitLeftPadding = !reset;
3204 if ((!reset && !qFuzzyCompare(oldPadding, value)) || (reset && !qFuzzyCompare(oldPadding, padding()))) {
3206 q->updateCursorRectangle();
3207 emit q->leftPaddingChanged();
3211void QQuickTextInputPrivate::setRightPadding(qreal value,
bool reset)
3213 Q_Q(QQuickTextInput);
3214 qreal oldPadding = q->rightPadding();
3215 if (!reset || extra.isAllocated()) {
3216 extra.value().rightPadding = value;
3217 extra.value().explicitRightPadding = !reset;
3219 if ((!reset && !qFuzzyCompare(oldPadding, value)) || (reset && !qFuzzyCompare(oldPadding, padding()))) {
3221 q->updateCursorRectangle();
3222 emit q->rightPaddingChanged();
3226void QQuickTextInputPrivate::setBottomPadding(qreal value,
bool reset)
3228 Q_Q(QQuickTextInput);
3229 qreal oldPadding = q->bottomPadding();
3230 if (!reset || extra.isAllocated()) {
3231 extra.value().bottomPadding = value;
3232 extra.value().explicitBottomPadding = !reset;
3234 if ((!reset && !qFuzzyCompare(oldPadding, value)) || (reset && !qFuzzyCompare(oldPadding, padding()))) {
3236 q->updateCursorRectangle();
3237 emit q->bottomPaddingChanged();
3241bool QQuickTextInputPrivate::isImplicitResizeEnabled()
const
3243 return !extra.isAllocated() || extra->implicitResize;
3246void QQuickTextInputPrivate::setImplicitResizeEnabled(
bool enabled)
3249 extra.value().implicitResize =
false;
3250 else if (extra.isAllocated())
3251 extra->implicitResize =
true;
3254void QQuickTextInputPrivate::updateLayout()
3256 Q_Q(QQuickTextInput);
3258 if (!q->isComponentComplete())
3262 QTextOption option = m_textLayout.textOption();
3263 option.setTextDirection(layoutDirection());
3264 option.setWrapMode(QTextOption::WrapMode(wrapMode));
3265 option.setAlignment(Qt::Alignment(q->effectiveHAlign()));
3266 if (!qmlDisableDistanceField())
3267 option.setUseDesignMetrics(renderType != QQuickTextInput::NativeRendering);
3269 m_textLayout.setTextOption(option);
3270 m_textLayout.setFont(font);
3272 m_textLayout.beginLayout();
3274 QTextLine line = m_textLayout.createLine();
3275 if (requireImplicitWidth) {
3276 line.setLineWidth(qreal(INT_MAX));
3277 const bool wasInLayout = inLayout;
3279 if (isImplicitResizeEnabled())
3280 q->setImplicitWidth(qCeil(line.naturalTextWidth()) + q->leftPadding() + q->rightPadding());
3281 inLayout = wasInLayout;
3285 qreal lineWidth = q->widthValid() || !isImplicitResizeEnabled() ? q->width() - q->leftPadding() - q->rightPadding() : qreal(INT_MAX);
3289 line.setLineWidth(lineWidth);
3290 line.setPosition(QPointF(0, height));
3292 height += line.height();
3293 width = qMax(width, line.naturalTextWidth());
3295 line = m_textLayout.createLine();
3296 }
while (line.isValid());
3297 m_textLayout.endLayout();
3299 option.setWrapMode(QTextOption::NoWrap);
3300 m_textLayout.setTextOption(option);
3302 textLayoutDirty =
true;
3304 const QSizeF previousSize = contentSize;
3305 contentSize = QSizeF(width, height);
3307 updateType = UpdatePaintNode;
3311 if (isImplicitResizeEnabled()) {
3312 if (!requireImplicitWidth && !q->widthValid())
3313 q->setImplicitSize(width + q->leftPadding() + q->rightPadding(), height + q->topPadding() + q->bottomPadding());
3315 q->setImplicitHeight(height + q->topPadding() + q->bottomPadding());
3318 updateBaselineOffset();
3320 if (previousSize != contentSize)
3321 emit q->contentSizeChanged();
3325
3326
3327
3328
3329
3330void QQuickTextInputPrivate::updateBaselineOffset()
3332 Q_Q(QQuickTextInput);
3333 if (!q->isComponentComplete())
3335 QFontMetricsF fm(font);
3337 if (q->heightValid()) {
3338 const qreal surplusHeight = q->height() - contentSize.height() - q->topPadding() - q->bottomPadding();
3339 if (vAlign == QQuickTextInput::AlignBottom)
3340 yoff = surplusHeight;
3341 else if (vAlign == QQuickTextInput::AlignVCenter)
3342 yoff = surplusHeight/2;
3345 if (m_textLayout.lineCount() > 0) {
3346 QTextLine line = m_textLayout.lineAt(0);
3347 ascent = line.y() + line.ascent();
3349 ascent = fm.ascent();
3351 q->setBaselineOffset(ascent + yoff + q->topPadding());
3354#if QT_CONFIG(clipboard)
3356
3357
3358
3359
3360
3361
3362
3363
3364
3365void QQuickTextInputPrivate::copy(QClipboard::Mode mode)
const
3367 QString t = selectedText();
3368 if (!t.isEmpty() && m_echoMode == QQuickTextInput::Normal) {
3369 QGuiApplication::clipboard()->setText(t, mode);
3374
3375
3376
3377
3378
3379
3380
3381void QQuickTextInputPrivate::paste(QClipboard::Mode clipboardMode)
3383 QString clip = QGuiApplication::clipboard()->text(clipboardMode);
3384 if (!clip.isEmpty() || hasSelectedText()) {
3395
3396
3397void QQuickTextInputPrivate::commitPreedit()
3399 Q_Q(QQuickTextInput);
3404 QGuiApplication::inputMethod()->commit();
3409 QInputMethodEvent ev;
3410 QCoreApplication::sendEvent(q, &ev);
3413void QQuickTextInputPrivate::cancelPreedit()
3415 Q_Q(QQuickTextInput);
3420 QGuiApplication::inputMethod()->reset();
3422 QInputMethodEvent ev;
3423 QCoreApplication::sendEvent(q, &ev);
3428
3429
3430
3431
3432
3433
3434
3435
3436void QQuickTextInputPrivate::backspace()
3438 int priorState = m_undoState;
3439 if (separateSelection()) {
3440 removeSelectedText();
3441 }
else if (m_cursor) {
3444 m_cursor = prevMaskBlank(m_cursor);
3445 QChar uc = m_text.at(m_cursor);
3446 if (m_cursor > 0 && uc.unicode() >= 0xdc00 && uc.unicode() < 0xe000) {
3449 uc = m_text.at(m_cursor - 1);
3450 if (uc.unicode() >= 0xd800 && uc.unicode() < 0xdc00) {
3451 internalDelete(
true);
3455 internalDelete(
true);
3457 finishChange(priorState);
3461
3462
3463
3464
3465
3466
3467
3468
3469void QQuickTextInputPrivate::del()
3471 int priorState = m_undoState;
3472 if (separateSelection()) {
3473 removeSelectedText();
3475 int n = m_textLayout.nextCursorPosition(m_cursor) - m_cursor;
3479 finishChange(priorState);
3483
3484
3485
3486
3487
3488
3489void QQuickTextInputPrivate::insert(
const QString &newText)
3491 int priorState = m_undoState;
3492 if (separateSelection())
3493 removeSelectedText();
3494 internalInsert(newText);
3495 finishChange(priorState);
3499
3500
3501
3502
3503void QQuickTextInputPrivate::clear()
3505 int priorState = m_undoState;
3506 separateSelection();
3508 m_selend = m_text.size();
3509 removeSelectedText();
3511 finishChange(priorState,
false,
false);
3515
3516
3517
3518
3519
3520
3521
3522void QQuickTextInputPrivate::setSelection(
int start,
int length)
3524 Q_Q(QQuickTextInput);
3529 if (start < 0 || start > m_text.size()) {
3530 qWarning(
"QQuickTextInputPrivate::setSelection: Invalid start position");
3535 if (start == m_selstart && start + length == m_selend && m_cursor == m_selend)
3538 m_selend = qMin(start + length, m_text.size());
3539 m_cursor = m_selend;
3540 }
else if (length < 0) {
3541 if (start == m_selend && start + length == m_selstart && m_cursor == m_selstart)
3543 m_selstart = qMax(start + length, 0);
3545 m_cursor = m_selstart;
3546 }
else if (m_selstart != m_selend) {
3552 emitCursorPositionChanged();
3555 emit q->selectionChanged();
3556 emitCursorPositionChanged();
3558 q->updateInputMethod(Qt::ImCursorRectangle | Qt::ImAnchorRectangle | Qt::ImCursorPosition | Qt::ImAnchorPosition
3559 | Qt::ImCurrentSelection);
3564
3565
3566
3567
3568
3569
3570
3571void QQuickTextInputPrivate::updatePasswordEchoEditing(
bool editing)
3573 cancelPasswordEchoTimer();
3574 m_passwordEchoEditing = editing;
3575 updateDisplayText();
3579
3580
3581
3582
3583
3584
3585bool QQuickTextInputPrivate::fixup()
3587#if QT_CONFIG(validator)
3589 QString textCopy = m_text;
3590 int cursorCopy = m_cursor;
3591 m_validator->fixup(textCopy);
3592 if (m_validator->validate(textCopy, cursorCopy) == QValidator::Acceptable) {
3593 if (textCopy != m_text || cursorCopy != m_cursor)
3594 internalSetText(textCopy, cursorCopy);
3603
3604
3605
3606
3607
3608void QQuickTextInputPrivate::moveCursor(
int pos,
bool mark)
3610 Q_Q(QQuickTextInput);
3615 if (pos != m_cursor) {
3618 pos = pos > m_cursor ? nextMaskBlank(pos) : prevMaskBlank(pos);
3622 if (m_selend > m_selstart && m_cursor == m_selstart)
3624 else if (m_selend > m_selstart && m_cursor == m_selend)
3625 anchor = m_selstart;
3628 m_selstart = qMin(anchor, pos);
3629 m_selend = qMax(anchor, pos);
3634 if (mark || m_selDirty) {
3636 emit q->selectionChanged();
3638 emitCursorPositionChanged();
3640 q->updateInputMethod();
3646
3647
3648
3649
3650
3651void QQuickTextInputPrivate::processInputMethodEvent(QInputMethodEvent *event)
3653 Q_Q(QQuickTextInput);
3655 int priorState = -1;
3656 bool isGettingInput = !event->commitString().isEmpty()
3657 || event->preeditString() != preeditAreaText()
3658 || event->replacementLength() > 0;
3659 bool cursorPositionChanged =
false;
3660 bool selectionChange =
false;
3661 m_preeditDirty = event->preeditString() != preeditAreaText();
3663 if (isGettingInput) {
3665 priorState = m_undoState;
3666 separateSelection();
3667 if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit && !m_passwordEchoEditing) {
3668 updatePasswordEchoEditing(
true);
3670 m_selend = m_text.size();
3672 removeSelectedText();
3676 if (event->replacementStart() <= 0)
3677 c += event->commitString().size() - qMin(-event->replacementStart(), event->replacementLength());
3679 int cursorInsertPos = m_cursor + event->replacementStart();
3680 if (cursorInsertPos < 0)
3681 cursorInsertPos = 0;
3684 if (event->replacementLength()) {
3685 m_selstart = cursorInsertPos;
3686 m_selend = m_selstart + event->replacementLength();
3687 m_selend = qMin(m_selend, m_text.size());
3688 removeSelectedText();
3690 m_cursor = cursorInsertPos;
3692 if (!event->commitString().isEmpty()) {
3693 internalInsert(event->commitString());
3694 cursorPositionChanged =
true;
3696 m_cursor = qBound(0, c, m_text.size());
3699 for (
int i = 0; i < event->attributes().size(); ++i) {
3700 const QInputMethodEvent::Attribute &a = event->attributes().at(i);
3701 if (a.type == QInputMethodEvent::Selection) {
3708 if (!cursorPositionChanged || !m_maskData)
3709 m_cursor = qBound(0, a.start + a.length, m_text.size());
3711 m_selstart = qMax(0, qMin(a.start, m_text.size()));
3712 m_selend = m_cursor;
3713 if (m_selend < m_selstart) {
3714 qSwap(m_selstart, m_selend);
3716 selectionChange =
true;
3718 selectionChange = m_selstart != m_selend;
3719 m_selstart = m_selend = 0;
3721 cursorPositionChanged =
true;
3724 QString oldPreeditString = m_textLayout.preeditAreaText();
3725 m_textLayout.setPreeditArea(m_cursor, event->preeditString());
3726 if (oldPreeditString != m_textLayout.preeditAreaText()) {
3727 emit q->preeditTextChanged();
3728 if (!event->preeditString().isEmpty() && m_undoPreeditState == -1)
3730 m_undoPreeditState = priorState;
3732 const int oldPreeditCursor = m_preeditCursor;
3733 m_preeditCursor = event->preeditString().size();
3734 hasImState = !event->preeditString().isEmpty();
3735 bool cursorVisible =
true;
3736 QList<QTextLayout::FormatRange> formats;
3737 for (
int i = 0; i < event->attributes().size(); ++i) {
3738 const QInputMethodEvent::Attribute &a = event->attributes().at(i);
3739 if (a.type == QInputMethodEvent::Cursor) {
3741 m_preeditCursor = a.start;
3742 cursorVisible = a.length != 0;
3743 }
else if (a.type == QInputMethodEvent::TextFormat) {
3745 QTextCharFormat f = qvariant_cast<QTextFormat>(a.value).toCharFormat();
3747 QTextLayout::FormatRange o;
3748 o.start = a.start + m_cursor;
3749 o.length = a.length;
3755 m_textLayout.setFormats(formats);
3761 q->setCursorVisible(cursorVisible);
3763 updateDisplayText(
true);
3764 if (cursorPositionChanged && emitCursorPositionChanged())
3765 q->updateInputMethod(Qt::ImCursorPosition | Qt::ImAnchorPosition);
3766 else if (m_preeditCursor != oldPreeditCursor || isGettingInput)
3767 q->updateCursorRectangle();
3770 finishChange(priorState);
3772 if (selectionChange) {
3773 emit q->selectionChanged();
3774 q->updateInputMethod(Qt::ImCursorRectangle | Qt::ImAnchorRectangle
3775 | Qt::ImCurrentSelection);
3779 if (event->preeditString().isEmpty())
3780 m_undoPreeditState = -1;
3786
3787
3788
3789
3790
3791
3792void QQuickTextInputPrivate::selectWordAtPos(
int cursor)
3794 int next = cursor + 1;
3797 int c = m_textLayout.previousCursorPosition(next, QTextLayout::SkipWords);
3798 moveCursor(c,
false);
3800 int end = m_textLayout.nextCursorPosition(c, QTextLayout::SkipWords);
3801 while (end > cursor && m_text.at(end - 1).isSpace())
3803 moveCursor(end,
true);
3807
3808
3809
3810
3811
3812
3813
3814
3815
3816
3817
3818bool QQuickTextInputPrivate::finishChange(
int validateFromState,
bool update,
bool edited)
3820 Q_Q(QQuickTextInput);
3824 bool inputMethodAttributesChanged = m_textDirty || m_selDirty;
3826 bool alignmentChanged =
false;
3827 bool textChanged =
false;
3831 bool wasValidInput = m_validInput;
3832 bool wasAcceptable = m_acceptableInput;
3833 m_validInput =
true;
3834 m_acceptableInput =
true;
3835#if QT_CONFIG(validator)
3837 QString textCopy = m_text;
3839 textCopy = maskString(0, m_text,
true);
3840 int cursorCopy = m_cursor;
3841 QValidator::State state = m_validator->validate(textCopy, cursorCopy);
3844 m_validInput = state != QValidator::Invalid;
3845 m_acceptableInput = state == QValidator::Acceptable;
3846 if (m_validInput && !m_maskData) {
3847 if (m_text != textCopy) {
3848 internalSetText(textCopy, cursorCopy);
3851 m_cursor = cursorCopy;
3861 if (m_undoPreeditState >= 0 && (m_undoPreeditState < validateFromState || validateFromState < 0))
3862 validateFromState = m_undoPreeditState;
3864 if (validateFromState >= 0 && wasValidInput && !m_validInput) {
3865 if (m_transactions.size())
3867 internalUndo(validateFromState);
3868 m_history.resize(m_undoState);
3869 m_validInput =
true;
3870 m_acceptableInput = wasAcceptable;
3871 m_textDirty =
false;
3876 m_textDirty =
false;
3878 m_preeditDirty =
false;
3880 alignmentChanged = determineHorizontalAlignment();
3882 emit q->textEdited();
3883 emit q->textChanged();
3886 updateDisplayText(alignmentChanged);
3888 if (m_acceptableInput != wasAcceptable)
3889 emit q->acceptableInputChanged();
3892 if (m_preeditDirty) {
3893 m_preeditDirty =
false;
3894 if (determineHorizontalAlignment()) {
3895 alignmentChanged =
true;
3903 emit q->selectionChanged();
3907 inputMethodAttributesChanged |= (m_cursor != m_lastCursorPos);
3908 if (inputMethodAttributesChanged)
3909 q->updateInputMethod();
3911 emitUndoRedoChanged();
3913 if (!emitCursorPositionChanged() && (alignmentChanged || textChanged))
3914 q->updateCursorRectangle();
3920
3921
3922
3923
3924void QQuickTextInputPrivate::internalSetText(
const QString &txt,
int pos,
bool edited)
3927 QString oldText = m_text;
3929 m_text = maskString(0, txt,
true);
3930 m_text += clearString(m_text.size(), m_maxLength - m_text.size());
3932 m_text = txt.isEmpty() ? txt : txt.left(m_maxLength);
3937 m_undoPreeditState = -1;
3939 m_cursor = (pos < 0 || pos > m_text.size()) ? m_text.size() : pos;
3940 m_textDirty = (oldText != m_text);
3942 bool changed = finishChange(-1,
true, edited);
3943#if !QT_CONFIG(accessibility)
3946 Q_Q(QQuickTextInput);
3947 if (changed && QAccessible::isActive()) {
3948 if (QObject *acc = QQuickAccessibleAttached::findAccessible(q, QAccessible::EditableText)) {
3949 QAccessibleTextUpdateEvent ev(acc, 0, oldText, m_text);
3950 QAccessible::updateAccessibility(&ev);
3958
3959
3960
3961
3962
3963void QQuickTextInputPrivate::addCommand(
const Command &cmd)
3965 if (m_separator && m_undoState && m_history[m_undoState - 1].type != Separator) {
3966 m_history.resize(m_undoState + 2);
3967 m_history[m_undoState++] = Command(Separator, m_cursor, u'\0', m_selstart, m_selend);
3969 m_history.resize(m_undoState + 1);
3971 m_separator =
false;
3972 m_history[m_undoState++] = cmd;
3976
3977
3978
3979
3980
3981
3982
3983
3984
3985void QQuickTextInputPrivate::internalInsert(
const QString &s)
3987 Q_Q(QQuickTextInput);
3988 if (m_echoMode == QQuickTextInput::Password) {
3989 if (m_passwordMaskDelay > 0)
3990 m_passwordEchoTimer.start(m_passwordMaskDelay, q);
3992 Q_ASSERT(!hasSelectedText());
3994 QString ms = maskString(m_cursor, s);
3995 for (
int i = 0; i < ms.size(); ++i) {
3996 addCommand (Command(DeleteSelection, m_cursor + i, m_text.at(m_cursor + i), -1, -1));
3997 addCommand(Command(Insert, m_cursor + i, ms.at(i), -1, -1));
3999 m_text.replace(m_cursor, ms.size(), ms);
4000 m_cursor += ms.size();
4001 m_cursor = nextMaskBlank(m_cursor);
4004 int remaining = m_maxLength - m_text.size();
4005 if (remaining != 0) {
4006 const QStringView remainingStr = QStringView{s}.left(remaining);
4007 m_text.insert(m_cursor, remainingStr);
4008 for (
auto e : remainingStr)
4009 addCommand(Command(Insert, m_cursor++, e, -1, -1));
4016
4017
4018
4019
4020
4021
4022
4023
4024
4025
4026void QQuickTextInputPrivate::internalDelete(
bool wasBackspace)
4028 if (m_cursor < m_text.size()) {
4029 cancelPasswordEchoTimer();
4030 Q_ASSERT(!hasSelectedText());
4031 addCommand(Command((CommandType)((m_maskData ? 2 : 0) + (wasBackspace ? Remove : Delete)),
4032 m_cursor, m_text.at(m_cursor), -1, -1));
4034 m_text.replace(m_cursor, 1, clearString(m_cursor, 1));
4035 addCommand(Command(Insert, m_cursor, m_text.at(m_cursor), -1, -1));
4037 m_text.remove(m_cursor, 1);
4044
4045
4046
4047
4048
4049
4050
4051
4052void QQuickTextInputPrivate::removeSelectedText()
4054 if (m_selstart < m_selend && m_selend <= m_text.size()) {
4055 cancelPasswordEchoTimer();
4057 if (m_selstart <= m_cursor && m_cursor < m_selend) {
4060 for (i = m_cursor; i >= m_selstart; --i)
4061 addCommand (Command(DeleteSelection, i, m_text.at(i), -1, 1));
4062 for (i = m_selend - 1; i > m_cursor; --i)
4063 addCommand (Command(DeleteSelection, i - m_cursor + m_selstart - 1, m_text.at(i), -1, -1));
4065 for (i = m_selend-1; i >= m_selstart; --i)
4066 addCommand (Command(RemoveSelection, i, m_text.at(i), -1, -1));
4069 m_text.replace(m_selstart, m_selend - m_selstart, clearString(m_selstart, m_selend - m_selstart));
4070 for (
int i = 0; i < m_selend - m_selstart; ++i)
4071 addCommand(Command(Insert, m_selstart + i, m_text.at(m_selstart + i), -1, -1));
4073 m_text.remove(m_selstart, m_selend - m_selstart);
4075 if (m_cursor > m_selstart)
4076 m_cursor -= qMin(m_cursor, m_selend) - m_selstart;
4083
4084
4085
4086
4087
4088
4090bool QQuickTextInputPrivate::separateSelection()
4092 if (hasSelectedText()) {
4094 addCommand(Command(SetSelection, m_cursor, u'\0', m_selstart, m_selend));
4102
4103
4104
4105
4106
4107void QQuickTextInputPrivate::parseInputMask(
const QString &maskFields)
4109 int delimiter = maskFields.indexOf(QLatin1Char(
';'));
4110 if (maskFields.isEmpty() || delimiter == 0) {
4112 m_maskData.reset(
nullptr);
4113 m_maxLength = 32767;
4114 internalSetText(QString());
4119 if (delimiter == -1) {
4120 m_blank = QLatin1Char(
' ');
4121 m_inputMask = maskFields;
4123 m_inputMask = maskFields.left(delimiter);
4124 m_blank = (delimiter + 1 < maskFields.size()) ? maskFields[delimiter + 1] : QLatin1Char(
' ');
4130 for (
int i=0; i<m_inputMask.size(); i++) {
4131 c = m_inputMask.at(i);
4132 if (i > 0 && m_inputMask.at(i-1) == QLatin1Char(
'\\')) {
4136 if (c != QLatin1Char(
'\\') && c != QLatin1Char(
'!') &&
4137 c != QLatin1Char(
'<') && c != QLatin1Char(
'>') &&
4138 c != QLatin1Char(
'{') && c != QLatin1Char(
'}') &&
4139 c != QLatin1Char(
'[') && c != QLatin1Char(
']'))
4143 m_maskData.reset(
new MaskInputData[m_maxLength]);
4145 MaskInputData::Casemode m = MaskInputData::NoCaseMode;
4148 bool escape =
false;
4150 for (
int i = 0; i < m_inputMask.size(); i++) {
4151 c = m_inputMask.at(i);
4154 m_maskData[index].maskChar = c;
4155 m_maskData[index].separator = s;
4156 m_maskData[index].caseMode = m;
4159 }
else if (c == QLatin1Char(
'<')) {
4160 m = MaskInputData::Lower;
4161 }
else if (c == QLatin1Char(
'>')) {
4162 m = MaskInputData::Upper;
4163 }
else if (c == QLatin1Char(
'!')) {
4164 m = MaskInputData::NoCaseMode;
4165 }
else if (c != QLatin1Char(
'{') && c != QLatin1Char(
'}') && c != QLatin1Char(
'[') && c != QLatin1Char(
']')) {
4166 switch (c.unicode()) {
4193 m_maskData[index].maskChar = c;
4194 m_maskData[index].separator = s;
4195 m_maskData[index].caseMode = m;
4200 internalSetText(m_text);
4205
4206
4207
4208
4209bool QQuickTextInputPrivate::isValidInput(QChar key, QChar mask)
const
4211 switch (mask.unicode()) {
4217 if (key.isLetter() || key == m_blank)
4221 if (key.isLetterOrNumber())
4225 if (key.isLetterOrNumber() || key == m_blank)
4229 if (key.isPrint() && key != m_blank)
4233 if (key.isPrint() || key == m_blank)
4241 if (key.isNumber() || key == m_blank)
4245 if (key.isNumber() && key.digitValue() > 0)
4249 if ((key.isNumber() && key.digitValue() > 0) || key == m_blank)
4253 if (key.isNumber() || key == QLatin1Char(
'+') || key == QLatin1Char(
'-') || key == m_blank)
4257 if (key == QLatin1Char(
'0') || key == QLatin1Char(
'1'))
4261 if (key == QLatin1Char(
'0') || key == QLatin1Char(
'1') || key == m_blank)
4265 if (key.isNumber() || (key >= QLatin1Char(
'a') && key <= QLatin1Char(
'f')) || (key >= QLatin1Char(
'A') && key <= QLatin1Char(
'F')))
4269 if (key.isNumber() || (key >= QLatin1Char(
'a') && key <= QLatin1Char(
'f')) || (key >= QLatin1Char(
'A') && key <= QLatin1Char(
'F')) || key == m_blank)
4279
4280
4281
4282
4283
4284
4285
4286QQuickTextInputPrivate::ValidatorState QQuickTextInputPrivate::hasAcceptableInput(
const QString &str)
const
4288#if QT_CONFIG(validator)
4289 QString textCopy = str;
4290 int cursorCopy = m_cursor;
4292 QValidator::State state = m_validator->validate(textCopy, cursorCopy);
4293 if (state != QValidator::Acceptable)
4294 return ValidatorState(state);
4299 return AcceptableInput;
4301 if (str.size() != m_maxLength)
4302 return InvalidInput;
4304 for (
int i=0; i < m_maxLength; ++i) {
4305 if (m_maskData[i].separator) {
4306 if (str.at(i) != m_maskData[i].maskChar)
4307 return InvalidInput;
4309 if (!isValidInput(str.at(i), m_maskData[i].maskChar))
4310 return InvalidInput;
4313 return AcceptableInput;
4317
4318
4319
4320
4321
4322
4323
4324QString QQuickTextInputPrivate::maskString(uint pos,
const QString &str,
bool clear)
const
4326 if (pos >= (uint)m_maxLength)
4327 return QString::fromLatin1(
"");
4330 fill = clear ? clearString(0, m_maxLength) : m_text;
4333 QString s = QString::fromLatin1(
"");
4335 while (i < m_maxLength) {
4336 if (strIndex < str.size()) {
4337 if (m_maskData[i].separator) {
4338 s += m_maskData[i].maskChar;
4339 if (str[strIndex] == m_maskData[i].maskChar)
4343 if (isValidInput(str[strIndex], m_maskData[i].maskChar)) {
4344 switch (m_maskData[i].caseMode) {
4345 case MaskInputData::Upper:
4346 s += str[strIndex].toUpper();
4348 case MaskInputData::Lower:
4349 s += str[strIndex].toLower();
4357 int n = findInMask(i,
true,
true, str[strIndex]);
4359 if (str.size() != 1 || i == 0 || (i > 0 && (!m_maskData[i-1].separator || m_maskData[i-1].maskChar != str[strIndex]))) {
4360 s += QStringView{fill}.mid(i, n-i+1);
4365 n = findInMask(i,
true,
false, str[strIndex]);
4367 s += QStringView{fill}.mid(i, n-i);
4368 switch (m_maskData[n].caseMode) {
4369 case MaskInputData::Upper:
4370 s += str[strIndex].toUpper();
4372 case MaskInputData::Lower:
4373 s += str[strIndex].toLower();
4394
4395
4396
4397
4398
4399QString QQuickTextInputPrivate::clearString(uint pos, uint len)
const
4401 if (pos >= (uint)m_maxLength)
4405 int end = qMin((uint)m_maxLength, pos + len);
4406 for (
int i = pos; i < end; ++i)
4407 if (m_maskData[i].separator)
4408 s += m_maskData[i].maskChar;
4416
4417
4418
4419
4420
4421QString QQuickTextInputPrivate::stripString(
const QString &str)
const
4427 int end = qMin(m_maxLength, str.size());
4428 for (
int i = 0; i < end; ++i) {
4429 if (m_maskData[i].separator)
4430 s += m_maskData[i].maskChar;
4431 else if (str[i] != m_blank)
4439
4440
4441
4442int QQuickTextInputPrivate::findInMask(
int pos,
bool forward,
bool findSeparator, QChar searchChar)
const
4444 if (pos >= m_maxLength || pos < 0)
4447 int end = forward ? m_maxLength : -1;
4448 int step = forward ? 1 : -1;
4452 if (findSeparator) {
4453 if (m_maskData[i].separator && m_maskData[i].maskChar == searchChar)
4456 if (!m_maskData[i].separator) {
4457 if (searchChar.isNull())
4459 else if (isValidInput(searchChar, m_maskData[i].maskChar))
4468void QQuickTextInputPrivate::internalUndo(
int until)
4470 if (!isUndoAvailable())
4472 cancelPasswordEchoTimer();
4474 while (m_undoState && m_undoState > until) {
4475 Command& cmd = m_history[--m_undoState];
4478 m_text.remove(cmd.pos, 1);
4482 m_selstart = cmd.selStart;
4483 m_selend = cmd.selEnd;
4487 case RemoveSelection:
4488 m_text.insert(cmd.pos, cmd.uc);
4489 m_cursor = cmd.pos + 1;
4492 case DeleteSelection:
4493 m_text.insert(cmd.pos, cmd.uc);
4499 if (until < 0 && m_undoState) {
4500 Command& next = m_history[m_undoState-1];
4501 if (next.type != cmd.type
4502 && next.type < RemoveSelection
4503 && (cmd.type < RemoveSelection || next.type == Separator)) {
4512void QQuickTextInputPrivate::internalRedo()
4514 if (!isRedoAvailable())
4517 while (m_undoState < m_history.size()) {
4518 Command& cmd = m_history[m_undoState++];
4521 m_text.insert(cmd.pos, cmd.uc);
4522 m_cursor = cmd.pos + 1;
4525 m_selstart = cmd.selStart;
4526 m_selend = cmd.selEnd;
4531 case RemoveSelection:
4532 case DeleteSelection:
4533 m_text.remove(cmd.pos, 1);
4534 m_selstart = cmd.selStart;
4535 m_selend = cmd.selEnd;
4539 m_selstart = cmd.selStart;
4540 m_selend = cmd.selEnd;
4544 if (m_undoState < m_history.size()) {
4545 Command& next = m_history[m_undoState];
4546 if (next.type != cmd.type
4547 && cmd.type < RemoveSelection
4548 && next.type != Separator
4549 && (next.type < RemoveSelection || cmd.type == Separator)) {
4557void QQuickTextInputPrivate::emitUndoRedoChanged()
4559 Q_Q(QQuickTextInput);
4560 const bool previousUndo = canUndo;
4561 const bool previousRedo = canRedo;
4563 canUndo = isUndoAvailable();
4564 canRedo = isRedoAvailable();
4566 if (previousUndo != canUndo)
4567 emit q->canUndoChanged();
4568 if (previousRedo != canRedo)
4569 emit q->canRedoChanged();
4573
4574
4575
4576
4577
4578bool QQuickTextInputPrivate::emitCursorPositionChanged()
4580 Q_Q(QQuickTextInput);
4581 if (m_cursor != m_lastCursorPos) {
4582 m_lastCursorPos = m_cursor;
4584 q->updateCursorRectangle();
4585 emit q->cursorPositionChanged();
4587 if (!hasSelectedText()) {
4588 if (lastSelectionStart != m_cursor) {
4589 lastSelectionStart = m_cursor;
4590 emit q->selectionStartChanged();
4592 if (lastSelectionEnd != m_cursor) {
4593 lastSelectionEnd = m_cursor;
4594 emit q->selectionEndChanged();
4598#if QT_CONFIG(accessibility)
4599 if (QAccessible::isActive()) {
4600 if (QObject *acc = QQuickAccessibleAttached::findAccessible(q, QAccessible::EditableText)) {
4601 QAccessibleTextCursorEvent ev(acc, m_cursor);
4602 QAccessible::updateAccessibility(&ev);
4613void QQuickTextInputPrivate::setBlinkingCursorEnabled(
bool enable)
4615 if (enable == m_blinkEnabled)
4618 m_blinkEnabled = enable;
4619 updateCursorBlinking();
4622 connect(qApp->styleHints(), &QStyleHints::cursorFlashTimeChanged,
this, &QQuickTextInputPrivate::updateCursorBlinking);
4624 disconnect(qApp->styleHints(), &QStyleHints::cursorFlashTimeChanged,
this, &QQuickTextInputPrivate::updateCursorBlinking);
4627void QQuickTextInputPrivate::updateCursorBlinking()
4629 Q_Q(QQuickTextInput);
4632 q->killTimer(m_blinkTimer);
4636 if (m_blinkEnabled && cursorVisible && !cursorItem && !m_readOnly) {
4637 int flashTime = QGuiApplication::styleHints()->cursorFlashTime();
4639 m_blinkTimer = q->startTimer(flashTime / 2);
4643 updateType = UpdatePaintNode;
4648void QQuickTextInput::timerEvent(QTimerEvent *event)
4650 Q_D(QQuickTextInput);
4651 if (event->timerId() == d->m_blinkTimer) {
4652 d->m_blinkStatus = !d->m_blinkStatus;
4653 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
4656 }
else if (event->timerId() == d->m_passwordEchoTimer.timerId()) {
4657 d->m_passwordEchoTimer.stop();
4658 d->updateDisplayText();
4659 updateCursorRectangle();
4663void QQuickTextInputPrivate::processKeyEvent(QKeyEvent* event)
4665 Q_Q(QQuickTextInput);
4667 if (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return) {
4668 if (hasAcceptableInput(m_text) == AcceptableInput || fixup()) {
4670 QInputMethod *inputMethod = QGuiApplication::inputMethod();
4671 inputMethod->commit();
4676 emit q->editingFinished();
4686 updateCursorBlinking();
4688 if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit
4689 && !m_passwordEchoEditing
4691 && !event->text().isEmpty()
4692 && !(event->modifiers() & Qt::ControlModifier)) {
4698 updatePasswordEchoEditing(
true);
4702 bool unknown =
false;
4703#if QT_CONFIG(shortcut)
4704 bool visual = cursorMoveStyle() == Qt::VisualMoveStyle;
4709#if QT_CONFIG(shortcut)
4710 else if (event == QKeySequence::Undo) {
4713 else if (event == QKeySequence::Redo) {
4716 else if (event == QKeySequence::SelectAll) {
4719#if QT_CONFIG(clipboard)
4720 else if (event == QKeySequence::Copy) {
4723 else if (event == QKeySequence::Paste) {
4725 QClipboard::Mode mode = QClipboard::Clipboard;
4729 else if (event == QKeySequence::Cut) {
4732 else if (event == QKeySequence::DeleteEndOfLine) {
4737 else if (event == QKeySequence::MoveToStartOfLine || event == QKeySequence::MoveToStartOfBlock) {
4740 else if (event == QKeySequence::MoveToEndOfLine || event == QKeySequence::MoveToEndOfBlock) {
4743 else if (event == QKeySequence::SelectStartOfLine || event == QKeySequence::SelectStartOfBlock) {
4746 else if (event == QKeySequence::SelectEndOfLine || event == QKeySequence::SelectEndOfBlock) {
4749 else if (event == QKeySequence::MoveToNextChar) {
4750 if (hasSelectedText()) {
4751 moveCursor(selectionEnd(),
false);
4753 cursorForward(0, visual ? 1 : (layoutDirection() == Qt::LeftToRight ? 1 : -1));
4756 else if (event == QKeySequence::SelectNextChar) {
4757 cursorForward(1, visual ? 1 : (layoutDirection() == Qt::LeftToRight ? 1 : -1));
4759 else if (event == QKeySequence::MoveToPreviousChar) {
4760 if (hasSelectedText()) {
4761 moveCursor(selectionStart(),
false);
4763 cursorForward(0, visual ? -1 : (layoutDirection() == Qt::LeftToRight ? -1 : 1));
4766 else if (event == QKeySequence::SelectPreviousChar) {
4767 cursorForward(1, visual ? -1 : (layoutDirection() == Qt::LeftToRight ? -1 : 1));
4769 else if (event == QKeySequence::MoveToNextWord) {
4770 if (m_echoMode == QQuickTextInput::Normal)
4771 layoutDirection() == Qt::LeftToRight ? cursorWordForward(0) : cursorWordBackward(0);
4773 layoutDirection() == Qt::LeftToRight ? end(0) : home(0);
4775 else if (event == QKeySequence::MoveToPreviousWord) {
4776 if (m_echoMode == QQuickTextInput::Normal)
4777 layoutDirection() == Qt::LeftToRight ? cursorWordBackward(0) : cursorWordForward(0);
4778 else if (!m_readOnly) {
4779 layoutDirection() == Qt::LeftToRight ? home(0) : end(0);
4782 else if (event == QKeySequence::SelectNextWord) {
4783 if (m_echoMode == QQuickTextInput::Normal)
4784 layoutDirection() == Qt::LeftToRight ? cursorWordForward(1) : cursorWordBackward(1);
4786 layoutDirection() == Qt::LeftToRight ? end(1) : home(1);
4788 else if (event == QKeySequence::SelectPreviousWord) {
4789 if (m_echoMode == QQuickTextInput::Normal)
4790 layoutDirection() == Qt::LeftToRight ? cursorWordBackward(1) : cursorWordForward(1);
4792 layoutDirection() == Qt::LeftToRight ? home(1) : end(1);
4794 else if (event == QKeySequence::Delete) {
4798 else if (event == QKeySequence::DeleteEndOfWord) {
4802 else if (event == QKeySequence::DeleteStartOfWord) {
4804 deleteStartOfWord();
4805 }
else if (event == QKeySequence::DeleteCompleteLine) {
4808#if QT_CONFIG(clipboard)
4816 bool handled =
false;
4817 if (event->modifiers() & Qt::ControlModifier) {
4818 switch (event->key()) {
4819 case Qt::Key_Backspace:
4821 deleteStartOfWord();
4828 switch (event->key()) {
4829 case Qt::Key_Backspace:
4841 if (event->key() == Qt::Key_Direction_L || event->key() == Qt::Key_Direction_R) {
4842 setLayoutDirection((event->key() == Qt::Key_Direction_L) ? Qt::LeftToRight : Qt::RightToLeft);
4846 if (unknown && !m_readOnly) {
4847 if (m_inputControl->isAcceptableInput(event)) {
4851 && !hasSelectedText()
4852 && !(m_cursor == q_func()->text().size())) {
4856 insert(event->text());
4869
4870
4871
4872
4874void QQuickTextInputPrivate::deleteStartOfWord()
4876 int priorState = m_undoState;
4878 if (!separateSelection()) {
4879 Command cmd(SetSelection, m_cursor, u'\0', m_selstart, m_selend);
4881 cursorWordBackward(
true);
4885 removeSelectedText();
4886 finishChange(priorState);
4890
4891
4892
4893
4895void QQuickTextInputPrivate::deleteEndOfWord()
4897 int priorState = m_undoState;
4898 Command cmd(SetSelection, m_cursor, u'\0', m_selstart, m_selend);
4900 cursorWordForward(
true);
4904 removeSelectedText();
4905 finishChange(priorState);
4909
4910
4911
4912
4914void QQuickTextInputPrivate::deleteEndOfLine()
4916 int priorState = m_undoState;
4917 Command cmd(SetSelection, m_cursor, u'\0', m_selstart, m_selend);
4919 setSelection(m_cursor, end());
4921 removeSelectedText();
4922 finishChange(priorState);
4926
4927
4928
4929
4930
4931
4932
4933
4934void QQuickTextInput::ensureVisible(
int position)
4936 Q_D(QQuickTextInput);
4937 d->ensureVisible(position);
4938 updateCursorRectangle(
false);
4942
4943
4944
4945
4946
4947
4948
4949
4950
4951
4952void QQuickTextInput::clear()
4954 Q_D(QQuickTextInput);
4960
4961
4962
4963
4964
4965
4966
4967
4968
4969
4970
4971
4972
4973
4974
4975
4976
4977
4978
4979
4980
4981
4982qreal QQuickTextInput::padding()
const
4984 Q_D(
const QQuickTextInput);
4985 return d->padding();
4988void QQuickTextInput::setPadding(qreal padding)
4990 Q_D(QQuickTextInput);
4991 if (qFuzzyCompare(d->padding(), padding))
4994 d->extra.value().padding = padding;
4996 updateCursorRectangle();
4997 emit paddingChanged();
4998 if (!d->extra.isAllocated() || !d->extra->explicitTopPadding)
4999 emit topPaddingChanged();
5000 if (!d->extra.isAllocated() || !d->extra->explicitLeftPadding)
5001 emit leftPaddingChanged();
5002 if (!d->extra.isAllocated() || !d->extra->explicitRightPadding)
5003 emit rightPaddingChanged();
5004 if (!d->extra.isAllocated() || !d->extra->explicitBottomPadding)
5005 emit bottomPaddingChanged();
5008void QQuickTextInput::resetPadding()
5013qreal QQuickTextInput::topPadding()
const
5015 Q_D(
const QQuickTextInput);
5016 if (d->extra.isAllocated() && d->extra->explicitTopPadding)
5017 return d->extra->topPadding;
5018 return d->padding();
5021void QQuickTextInput::setTopPadding(qreal padding)
5023 Q_D(QQuickTextInput);
5024 d->setTopPadding(padding);
5027void QQuickTextInput::resetTopPadding()
5029 Q_D(QQuickTextInput);
5030 d->setTopPadding(0,
true);
5033qreal QQuickTextInput::leftPadding()
const
5035 Q_D(
const QQuickTextInput);
5036 if (d->extra.isAllocated() && d->extra->explicitLeftPadding)
5037 return d->extra->leftPadding;
5038 return d->padding();
5041void QQuickTextInput::setLeftPadding(qreal padding)
5043 Q_D(QQuickTextInput);
5044 d->setLeftPadding(padding);
5047void QQuickTextInput::resetLeftPadding()
5049 Q_D(QQuickTextInput);
5050 d->setLeftPadding(0,
true);
5053qreal QQuickTextInput::rightPadding()
const
5055 Q_D(
const QQuickTextInput);
5056 if (d->extra.isAllocated() && d->extra->explicitRightPadding)
5057 return d->extra->rightPadding;
5058 return d->padding();
5061void QQuickTextInput::setRightPadding(qreal padding)
5063 Q_D(QQuickTextInput);
5064 d->setRightPadding(padding);
5067void QQuickTextInput::resetRightPadding()
5069 Q_D(QQuickTextInput);
5070 d->setRightPadding(0,
true);
5073qreal QQuickTextInput::bottomPadding()
const
5075 Q_D(
const QQuickTextInput);
5076 if (d->extra.isAllocated() && d->extra->explicitBottomPadding)
5077 return d->extra->bottomPadding;
5078 return d->padding();
5081void QQuickTextInput::setBottomPadding(qreal padding)
5083 Q_D(QQuickTextInput);
5084 d->setBottomPadding(padding);
5087void QQuickTextInput::resetBottomPadding()
5089 Q_D(QQuickTextInput);
5090 d->setBottomPadding(0,
true);
5093#if QT_VERSION < QT_VERSION_CHECK(7
, 0
, 0
)
5094void QQuickTextInput::setOldSelectionDefault()
5096 Q_D(QQuickTextInput);
5097 d->selectByMouse =
false;
5098 d->selectByTouchDrag =
true;
5099 qCDebug(lcQuickTextInput,
"pre-6.4 behavior chosen: selectByMouse defaults false; if enabled, touchscreen acts like a mouse");
5103QQuickPre64TextInput::QQuickPre64TextInput(QQuickItem *parent)
5104 : QQuickTextInput(parent)
5106 setOldSelectionDefault();
5112#include "moc_qquicktextinput_p.cpp"
Combined button and popup list for selecting options.