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
1358Qt::InputMethodHints QQuickTextInput::inputMethodHints()
const
1363 Q_D(
const QQuickTextInput);
1364 return d->inputMethodHints;
1368void QQuickTextInput::setInputMethodHints(Qt::InputMethodHints hints)
1373 Q_D(QQuickTextInput);
1375 if (hints == d->inputMethodHints)
1378 d->inputMethodHints = hints;
1379 updateInputMethod(Qt::ImHints);
1380 emit inputMethodHintsChanged();
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397QQmlComponent* QQuickTextInput::cursorDelegate()
const
1399 Q_D(
const QQuickTextInput);
1400 return d->cursorComponent;
1403void QQuickTextInput::setCursorDelegate(QQmlComponent* c)
1405 Q_D(QQuickTextInput);
1406 QQuickTextUtil::setCursorDelegate(d, c);
1409void QQuickTextInput::createCursor()
1411 Q_D(QQuickTextInput);
1412 d->cursorPending =
true;
1413 QQuickTextUtil::createCursor(d);
1417
1418
1419
1420
1421
1422
1423
1424
1425QRectF QQuickTextInput::positionToRectangle(
int pos)
const
1427 Q_D(
const QQuickTextInput);
1428 if (d->m_echoMode == NoEcho)
1431 else if (pos > d->m_cursor)
1432 pos += d->preeditAreaText().size();
1434 QTextLine l = d->m_textLayout.lineForTextPosition(pos);
1437 qreal x = l.cursorToX(pos) - d->hscroll;
1438 qreal y = l.y() - d->vscroll;
1440 if (d->overwriteMode) {
1441 if (pos < text().size())
1442 w = l.cursorToX(pos + 1) - x;
1444 w = QFontMetrics(font()).horizontalAdvance(QLatin1Char(
' '));
1446 return QRectF(x, y, w, l.height());
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1472int QQuickTextInput::positionAt(qreal x, qreal y, QQuickTextInput::CursorPosition positionQuick)
const
1474 Q_D(
const QQuickTextInput);
1476 QTextLine::CursorPosition position = QTextLine::CursorPosition(positionQuick);
1478 int pos = d->positionAt(x, y, position);
1479 const int cursor = d->m_cursor;
1482 const int preeditLength = d->preeditAreaText().size();
1483 pos = pos > cursor + preeditLength
1484 ? pos - preeditLength
1493int QQuickTextInputPrivate::positionAt(qreal x, qreal y, QTextLine::CursorPosition position)
const
1495 Q_Q(
const QQuickTextInput);
1496 x += hscroll - q->leftPadding();
1497 y += vscroll - q->topPadding();
1498 QTextLine line = m_textLayout.lineAt(0);
1499 for (
int i = 1; i < m_textLayout.lineCount(); ++i) {
1500 QTextLine nextLine = m_textLayout.lineAt(i);
1502 if (y < (line.rect().bottom() + nextLine.y()) / 2)
1506 return line.isValid() ? line.xToCursor(x, position) : 0;
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524bool QQuickTextInput::overwriteMode()
const
1526 Q_D(
const QQuickTextInput);
1527 return d->overwriteMode;
1530void QQuickTextInput::setOverwriteMode(
bool overwrite)
1532 Q_D(QQuickTextInput);
1533 if (d->overwriteMode == overwrite)
1535 d->overwriteMode = overwrite;
1536 emit overwriteModeChanged(overwrite);
1539void QQuickTextInput::keyPressEvent(QKeyEvent* ev)
1541 Q_D(QQuickTextInput);
1543 bool ignore = (ev->key() == Qt::Key_Up || ev->key() == Qt::Key_Down) && ev->modifiers() == Qt::NoModifier;
1544 if (!ignore && (d->lastSelectionStart == d->lastSelectionEnd) && (ev->key() == Qt::Key_Right || ev->key() == Qt::Key_Left)) {
1547 int cursorPosition = d->m_cursor;
1548 if (cursorPosition == 0)
1549 ignore = ev->key() == (d->layoutDirection() == Qt::LeftToRight ? Qt::Key_Left : Qt::Key_Right);
1550 if (!ignore && cursorPosition == d->m_text.size())
1551 ignore = ev->key() == (d->layoutDirection() == Qt::LeftToRight ? Qt::Key_Right : Qt::Key_Left);
1556 d->processKeyEvent(ev);
1558 if (!ev->isAccepted())
1559 QQuickImplicitSizeItem::keyPressEvent(ev);
1563void QQuickTextInput::inputMethodEvent(QInputMethodEvent *ev)
1565 Q_D(QQuickTextInput);
1566 const bool wasComposing = d->hasImState;
1567 d->processInputMethodEvent(ev);
1568 if (!ev->isAccepted())
1569 QQuickImplicitSizeItem::inputMethodEvent(ev);
1571 if (wasComposing != d->hasImState)
1572 emit inputMethodComposingChanged();
1576void QQuickTextInput::mouseDoubleClickEvent(QMouseEvent *event)
1578 Q_D(QQuickTextInput);
1580 if (d->selectByMouse && event->button() == Qt::LeftButton &&
1581 QQuickDeliveryAgentPrivate::isEventFromMouseOrTouchpad(event)) {
1585 int cursor = d->positionAt(event->position());
1586 d->selectWordAtPos(cursor);
1587 event->setAccepted(
true);
1588 if (!d->hasPendingTripleClick()) {
1589 d->tripleClickStartPoint = event->position();
1590 d->tripleClickTimer.start();
1593 if (d->sendMouseEventToInputContext(event))
1595 QQuickImplicitSizeItem::mouseDoubleClickEvent(event);
1599void QQuickTextInput::mousePressEvent(QMouseEvent *event)
1601 Q_D(QQuickTextInput);
1603 d->pressPos = event->position();
1605 if (d->sendMouseEventToInputContext(event))
1608 d->hadSelectionOnMousePress = d->hasSelectedText();
1610 const bool isMouse = QQuickDeliveryAgentPrivate::isEventFromMouseOrTouchpad(event);
1611 if (d->selectByMouse &&
1613#if QT_VERSION < QT_VERSION_CHECK(7
, 0
, 0
)
1614 || d->selectByTouchDrag
1617 setKeepMouseGrab(
false);
1618 d->selectPressed =
true;
1619 QPointF distanceVector = d->pressPos - d->tripleClickStartPoint;
1620 if (d->hasPendingTripleClick()
1621 && distanceVector.manhattanLength() < QGuiApplication::styleHints()->startDragDistance()) {
1622 event->setAccepted(
true);
1629#if QT_VERSION < QT_VERSION_CHECK(7
, 0
, 0
)
1630 || d->selectByTouchDrag
1633 bool mark = (event->modifiers() & Qt::ShiftModifier) && d->selectByMouse;
1634 int cursor = d->positionAt(event->position());
1635 d->moveCursor(cursor, mark);
1638 if (d->focusOnPress && !qGuiApp->styleHints()->setFocusOnTouchRelease())
1639 ensureActiveFocus(Qt::MouseFocusReason);
1641 event->setAccepted(
true);
1644void QQuickTextInput::mouseMoveEvent(QMouseEvent *event)
1646 Q_D(QQuickTextInput);
1647 if (!QQuickDeliveryAgentPrivate::isEventFromMouseOrTouchpad(event)
1648#if QT_VERSION < QT_VERSION_CHECK(7
, 0
, 0
)
1649 && ! d->selectByTouchDrag
1654 if (d->selectPressed) {
1655 if (qAbs(
int(event->position().x() - d->pressPos.x())) > QGuiApplication::styleHints()->startDragDistance())
1656 setKeepMouseGrab(
true);
1659 if (d->composeMode()) {
1661 int startPos = d->positionAt(d->pressPos);
1662 int currentPos = d->positionAt(event->position());
1663 if (startPos != currentPos)
1664 d->setSelection(startPos, currentPos - startPos);
1668 moveCursorSelection(d->positionAt(event->position()), d->mouseSelectionMode);
1670 event->setAccepted(
true);
1672 QQuickImplicitSizeItem::mouseMoveEvent(event);
1676void QQuickTextInput::mouseReleaseEvent(QMouseEvent *event)
1678 Q_D(QQuickTextInput);
1679 if (d->sendMouseEventToInputContext(event))
1681 if (d->selectPressed) {
1682 d->selectPressed =
false;
1683 setKeepMouseGrab(
false);
1685 const bool isMouse = QQuickDeliveryAgentPrivate::isEventFromMouseOrTouchpad(event)
1686#if QT_VERSION < QT_VERSION_CHECK(7
, 0
, 0
)
1687 || d->selectByTouchDrag
1691#if QT_CONFIG(clipboard)
1692 if (isMouse && QGuiApplication::clipboard()->supportsSelection()) {
1693 if (event->button() == Qt::LeftButton) {
1694 d->copy(QClipboard::Selection);
1695 }
else if (!d->m_readOnly && event->button() == Qt::MiddleButton) {
1697 d->insert(QGuiApplication::clipboard()->text(QClipboard::Selection));
1706 if (!isMouse && (!d->hasSelectedText() || d->hadSelectionOnMousePress))
1707 d->moveCursor(d->positionAt(event->position()),
false);
1711 d->hadSelectionOnMousePress =
false;
1713 if (d->focusOnPress && qGuiApp->styleHints()->setFocusOnTouchRelease())
1714 ensureActiveFocus(Qt::MouseFocusReason);
1716 if (!event->isAccepted())
1717 QQuickImplicitSizeItem::mouseReleaseEvent(event);
1720#if QT_VERSION < QT_VERSION_CHECK(7
, 0
, 0
)
1721bool QQuickTextInputPrivate::handleContextMenuEvent(QContextMenuEvent *event)
1723bool QQuickTextInput::contextMenuEvent(QContextMenuEvent *event)
1726 Q_Q(QQuickTextInput);
1727 QContextMenuEvent mapped(event->reason(),
1728 q->mapToScene(q->cursorRectangle().center()).toPoint(), event->globalPos(),
1729 event->modifiers());
1730 const bool eventProcessed = QQuickItemPrivate::handleContextMenuEvent(&mapped);
1731 event->setAccepted(mapped.isAccepted());
1732 return eventProcessed;
1735bool QQuickTextInputPrivate::sendMouseEventToInputContext(QMouseEvent *event)
1738 if (composeMode()) {
1739 int tmp_cursor = positionAt(event->position());
1740 int mousePos = tmp_cursor - m_cursor;
1741 if (mousePos >= 0 && mousePos <= m_textLayout.preeditAreaText().size()) {
1742 if (event->type() == QEvent::MouseButtonRelease) {
1743 QGuiApplication::inputMethod()->invokeAction(QInputMethod::Click, mousePos);
1755void QQuickTextInput::mouseUngrabEvent()
1757 Q_D(QQuickTextInput);
1758 d->selectPressed =
false;
1759 setKeepMouseGrab(
false);
1762bool QQuickTextInput::event(QEvent* ev)
1764#if QT_CONFIG(shortcut)
1765 Q_D(QQuickTextInput);
1766 if (ev->type() == QEvent::ShortcutOverride) {
1767 if (d->m_readOnly) {
1771 QKeyEvent* ke =
static_cast<QKeyEvent*>(ev);
1772 if (ke == QKeySequence::Copy
1773 || ke == QKeySequence::Paste
1774 || ke == QKeySequence::Cut
1775 || ke == QKeySequence::Redo
1776 || ke == QKeySequence::Undo
1777 || ke == QKeySequence::MoveToNextWord
1778 || ke == QKeySequence::MoveToPreviousWord
1779 || ke == QKeySequence::MoveToStartOfDocument
1780 || ke == QKeySequence::MoveToEndOfDocument
1781 || ke == QKeySequence::SelectNextWord
1782 || ke == QKeySequence::SelectPreviousWord
1783 || ke == QKeySequence::SelectStartOfLine
1784 || ke == QKeySequence::SelectEndOfLine
1785 || ke == QKeySequence::SelectStartOfBlock
1786 || ke == QKeySequence::SelectEndOfBlock
1787 || ke == QKeySequence::SelectStartOfDocument
1788 || ke == QKeySequence::SelectAll
1789 || ke == QKeySequence::SelectEndOfDocument
1790 || ke == QKeySequence::DeleteCompleteLine) {
1793 }
else if (ke->modifiers() == Qt::NoModifier || ke->modifiers() == Qt::ShiftModifier
1794 || ke->modifiers() == Qt::KeypadModifier) {
1795 if (ke->key() < Qt::Key_Escape) {
1799 switch (ke->key()) {
1800 case Qt::Key_Delete:
1803 case Qt::Key_Backspace:
1817 return QQuickImplicitSizeItem::event(ev);
1820void QQuickTextInput::geometryChange(
const QRectF &newGeometry,
1821 const QRectF &oldGeometry)
1823 Q_D(QQuickTextInput);
1825 if (newGeometry.width() != oldGeometry.width())
1827 else if (newGeometry.height() != oldGeometry.height() && d->vAlign != QQuickTextInput::AlignTop)
1828 d->updateBaselineOffset();
1829 updateCursorRectangle();
1831 QQuickImplicitSizeItem::geometryChange(newGeometry, oldGeometry);
1834void QQuickTextInput::itemChange(ItemChange change,
const ItemChangeData &value)
1836 Q_D(QQuickTextInput);
1839 case ItemDevicePixelRatioHasChanged:
1840 if (d->containsUnscalableGlyphs) {
1851 QQuickImplicitSizeItem::itemChange(change, value);
1854void QQuickTextInputPrivate::ensureVisible(
int position,
int preeditCursor,
int preeditLength)
1856 Q_Q(QQuickTextInput);
1857 QTextLine textLine = m_textLayout.lineForTextPosition(position + preeditCursor);
1858 const qreal width = qMax<qreal>(0, q->width() - q->leftPadding() - q->rightPadding());
1860 qreal widthUsed = 0;
1861 if (textLine.isValid()) {
1862 cix = textLine.cursorToX(position + preeditLength);
1863 const qreal cursorWidth = cix >= 0 ? cix : width - cix;
1864 widthUsed = qMax(textLine.naturalTextWidth(), cursorWidth);
1866 int previousScroll = hscroll;
1868 if (widthUsed <= width) {
1871 Q_ASSERT(textLine.isValid());
1872 if (cix - hscroll >= width) {
1874 hscroll = cix - width;
1875 }
else if (cix - hscroll < 0 && hscroll < widthUsed) {
1878 }
else if (widthUsed - hscroll < width) {
1881 hscroll = widthUsed - width;
1882 }
else if (width - hscroll > widthUsed) {
1885 hscroll = width - widthUsed;
1888 if (preeditLength > 0) {
1891 cix = textLine.cursorToX(position + qMax(0, preeditCursor - 1));
1897 if (previousScroll != hscroll)
1898 textLayoutDirty =
true;
1901void QQuickTextInputPrivate::updateHorizontalScroll()
1903 if (autoScroll && m_echoMode != QQuickTextInput::NoEcho) {
1905 const int preeditLength = m_textLayout.preeditAreaText().size();
1906 ensureVisible(m_cursor, m_preeditCursor, preeditLength);
1908 ensureVisible(m_cursor);
1915void QQuickTextInputPrivate::updateVerticalScroll()
1917 Q_Q(QQuickTextInput);
1919 const int preeditLength = m_textLayout.preeditAreaText().size();
1921 const qreal height = qMax<qreal>(0, q->height() - q->topPadding() - q->bottomPadding());
1922 qreal heightUsed = contentSize.height();
1923 qreal previousScroll = vscroll;
1925 if (!autoScroll || heightUsed <= height) {
1927 vscroll = -QQuickTextUtil::alignedY(
1928 heightUsed, height, vAlign & ~(Qt::AlignAbsolute|Qt::AlignHorizontal_Mask));
1931 QTextLine currentLine = m_textLayout.lineForTextPosition(m_cursor + preeditLength);
1933 QTextLine currentLine = m_textLayout.lineForTextPosition(m_cursor);
1935 QRectF r = currentLine.isValid() ? currentLine.rect() : QRectF();
1936 qreal top = r.top();
1937 int bottom = r.bottom();
1939 if (bottom - vscroll >= height) {
1941 vscroll = bottom - height;
1942 }
else if (top - vscroll < 0 && vscroll < heightUsed) {
1945 }
else if (heightUsed - vscroll < height) {
1948 vscroll = heightUsed - height;
1951 if (preeditLength > 0) {
1954 currentLine = m_textLayout.lineForTextPosition(m_cursor + qMax(0, m_preeditCursor - 1));
1955 top = currentLine.isValid() ? currentLine.rect().top() : 0;
1961 if (previousScroll != vscroll)
1962 textLayoutDirty =
true;
1965void QQuickTextInput::triggerPreprocess()
1967 Q_D(QQuickTextInput);
1968 if (d->updateType == QQuickTextInputPrivate::UpdateNone)
1969 d->updateType = QQuickTextInputPrivate::UpdateOnlyPreprocess;
1974void QQuickTextInput::updatePolish()
1976 invalidateFontCaches();
1979void QQuickTextInput::invalidateFontCaches()
1981 Q_D(QQuickTextInput);
1983 if (d->m_textLayout.engine() !=
nullptr)
1984 d->m_textLayout.engine()->resetFontEngineCache();
1987void QQuickTextInput::ensureActiveFocus(Qt::FocusReason reason)
1989 bool hadActiveFocus = hasActiveFocus();
1990 forceActiveFocus(reason);
1992 Q_D(QQuickTextInput);
1994 if (hasActiveFocus() && hadActiveFocus && !d->m_readOnly)
1995 qGuiApp->inputMethod()->show();
1997 Q_UNUSED(hadActiveFocus);
2001QSGNode *QQuickTextInput::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data)
2004 Q_D(QQuickTextInput);
2006 if (d->updateType != QQuickTextInputPrivate::UpdatePaintNode && oldNode !=
nullptr) {
2008 d->updateType = QQuickTextInputPrivate::UpdateNone;
2012 d->updateType = QQuickTextInputPrivate::UpdateNone;
2014 QSGInternalTextNode *node =
static_cast<QSGInternalTextNode *>(oldNode);
2015 if (node ==
nullptr)
2016 node = d->sceneGraphContext()->createInternalTextNode(d->sceneGraphRenderContext());
2019 const bool showCursor = !isReadOnly() && d->cursorItem ==
nullptr && d->cursorVisible && d->m_blinkStatus;
2021 if (!d->textLayoutDirty && oldNode !=
nullptr) {
2023 node->setCursor(cursorRectangle(), d->color);
2025 node->clearCursor();
2027 node->setRenderType(QSGTextNode::RenderType(d->renderType));
2029 node->setMatrix(QMatrix4x4());
2030 node->setTextStyle(QSGInternalTextNode::Normal);
2031 node->setColor(d->color);
2032 node->setSelectionTextColor(d->selectedTextColor);
2033 node->setSelectionColor(d->selectionColor);
2034 node->setFiltering(smooth() ? QSGTexture::Linear : QSGTexture::Nearest);
2036 if (flags().testFlag(ItemObservesViewport))
2037 node->setViewport(clipRect());
2039 node->setViewport(QRectF{});
2041 QPointF offset(leftPadding(), topPadding());
2042 if (d->autoScroll && d->m_textLayout.lineCount() > 0) {
2043 QFontMetricsF fm(d->font);
2045 offset += -QPointF(d->hscroll, d->vscroll + d->m_textLayout.lineAt(0).ascent() - fm.ascent());
2047 offset += -QPointF(d->hscroll, d->vscroll);
2050 if (!d->m_textLayout.text().isEmpty()
2052 || !d->m_textLayout.preeditAreaText().isEmpty()
2055 node->addTextLayout(offset, &d->m_textLayout,
2056 d->selectionStart(),
2057 d->selectionEnd() - 1);
2062 node->setCursor(cursorRectangle(), d->color);
2064 d->textLayoutDirty =
false;
2067 d->containsUnscalableGlyphs = node->containsUnscalableGlyphs();
2069 invalidateFontCaches();
2075QVariant QQuickTextInput::inputMethodQuery(Qt::InputMethodQuery property)
const
2079 if (property == Qt::ImEnterKeyType) {
2080 Q_D(
const QQuickItem);
2082 if (!d->extra.isAllocated()
2083 || d->extra->enterKeyAttached ==
nullptr
2084 || d->extra->enterKeyAttached->type() == Qt::EnterKeyDefault) {
2086 QQuickItem *next =
const_cast<QQuickTextInput*>(
this)->nextItemInFocusChain();
2087 QQuickItem *originalNext = next;
2088 while (next && next !=
this && !next->activeFocusOnTab()) {
2089 next = next->nextItemInFocusChain();
2090 if (next == originalNext) {
2096 const auto nextYPos = next->mapToGlobal(QPoint(0, 0)).y();
2097 const auto currentYPos =
this->mapToGlobal(QPoint(0, 0)).y();
2098 if (currentYPos < nextYPos)
2101 return Qt::EnterKeyNext;
2106 return inputMethodQuery(property, QVariant());
2109QVariant QQuickTextInput::inputMethodQuery(Qt::InputMethodQuery property,
const QVariant &argument)
const
2111 Q_D(
const QQuickTextInput);
2114 return QVariant((
bool)(flags() & ItemAcceptsInputMethod));
2116 return QVariant((
int) d->effectiveInputMethodHints());
2117 case Qt::ImCursorRectangle:
2118 return cursorRectangle();
2119 case Qt::ImAnchorRectangle:
2120 return d->anchorRectangle();
2123 case Qt::ImCursorPosition: {
2124 const QPointF pt = argument.toPointF();
2126 return QVariant(d->positionAt(pt));
2127 return QVariant(d->m_cursor);
2129 case Qt::ImSurroundingText:
2130 if (d->m_echoMode == PasswordEchoOnEdit && !d->m_passwordEchoEditing) {
2131 return QVariant(displayText());
2133 return QVariant(d->realText());
2135 case Qt::ImCurrentSelection:
2136 return QVariant(selectedText());
2137 case Qt::ImMaximumTextLength:
2138 return QVariant(maxLength());
2139 case Qt::ImAnchorPosition:
2140 if (d->selectionStart() == d->selectionEnd())
2141 return QVariant(d->m_cursor);
2142 else if (d->selectionStart() == d->m_cursor)
2143 return QVariant(d->selectionEnd());
2145 return QVariant(d->selectionStart());
2146 case Qt::ImAbsolutePosition:
2147 return QVariant(d->m_cursor);
2148 case Qt::ImTextAfterCursor:
2149 if (argument.isValid())
2150 return QVariant(d->m_text.mid(d->m_cursor, argument.toInt()));
2151 return QVariant(d->m_text.mid(d->m_cursor));
2152 case Qt::ImTextBeforeCursor:
2153 if (argument.isValid())
2154 return QVariant(QStringView{d->m_text}.left(d->m_cursor).right(argument.toInt()).toString());
2155 return QVariant(d->m_text.left(d->m_cursor));
2156 case Qt::ImReadOnly:
2157 return QVariant(d->m_readOnly);
2159 return QQuickItem::inputMethodQuery(property);
2165
2166
2167
2168
2169void QQuickTextInput::deselect()
2171 Q_D(QQuickTextInput);
2176
2177
2178
2179
2180void QQuickTextInput::selectAll()
2182 Q_D(QQuickTextInput);
2183 d->setSelection(0, text().size());
2187
2188
2189
2190
2191
2192bool QQuickTextInput::isRightToLeft(
int start,
int end)
2195 qmlWarning(
this) <<
"isRightToLeft(start, end) called with the end property being smaller than the start.";
2198 return QStringView{text()}.mid(start, end - start).isRightToLeft();
2202#if QT_CONFIG(clipboard)
2204
2205
2206
2207
2208
2209
2210
2211
2212void QQuickTextInput::cut()
2214 Q_D(QQuickTextInput);
2215 if (!d->m_readOnly && d->m_echoMode == QQuickTextInput::Normal) {
2222
2223
2224
2225
2226
2227
2228
2229
2230void QQuickTextInput::copy()
2232 Q_D(QQuickTextInput);
2237
2238
2239
2240
2241void QQuickTextInput::paste()
2243 Q_D(QQuickTextInput);
2250
2251
2252
2253
2254
2255
2257void QQuickTextInput::undo()
2259 Q_D(QQuickTextInput);
2260 if (!d->m_readOnly) {
2263 d->finishChange(-1,
true);
2268
2269
2270
2271
2273void QQuickTextInput::redo()
2275 Q_D(QQuickTextInput);
2276 if (!d->m_readOnly) {
2284
2285
2286
2287
2289void QQuickTextInput::insert(
int position,
const QString &text)
2291 Q_D(QQuickTextInput);
2292 if (d->m_echoMode == QQuickTextInput::Password) {
2293 if (d->m_passwordMaskDelay > 0)
2294 d->m_passwordEchoTimer.start(d->m_passwordMaskDelay,
this);
2296 if (position < 0 || position > d->m_text.size())
2299 const int priorState = d->m_undoState;
2301 QString insertText = text;
2303 if (d->hasSelectedText()) {
2304 d->addCommand(QQuickTextInputPrivate::Command(
2305 QQuickTextInputPrivate::SetSelection, d->m_cursor, u'\0', d->m_selstart, d->m_selend));
2307 if (d->m_maskData) {
2308 insertText = d->maskString(position, insertText);
2309 for (
int i = 0; i < insertText.size(); ++i) {
2310 d->addCommand(QQuickTextInputPrivate::Command(
2311 QQuickTextInputPrivate::DeleteSelection, position + i, d->m_text.at(position + i), -1, -1));
2312 d->addCommand(QQuickTextInputPrivate::Command(
2313 QQuickTextInputPrivate::Insert, position + i, insertText.at(i), -1, -1));
2315 d->m_text.replace(position, insertText.size(), insertText);
2316 if (!insertText.isEmpty())
2317 d->m_textDirty =
true;
2318 if (position < d->m_selend && position + insertText.size() > d->m_selstart)
2319 d->m_selDirty =
true;
2321 int remaining = d->m_maxLength - d->m_text.size();
2322 if (remaining != 0) {
2323 insertText = insertText.left(remaining);
2324 d->m_text.insert(position, insertText);
2325 for (
int i = 0; i < insertText.size(); ++i)
2326 d->addCommand(QQuickTextInputPrivate::Command(
2327 QQuickTextInputPrivate::Insert, position + i, insertText.at(i), -1, -1));
2328 if (d->m_cursor >= position)
2329 d->m_cursor += insertText.size();
2330 if (d->m_selstart >= position)
2331 d->m_selstart += insertText.size();
2332 if (d->m_selend >= position)
2333 d->m_selend += insertText.size();
2334 d->m_textDirty =
true;
2335 if (position >= d->m_selstart && position <= d->m_selend)
2336 d->m_selDirty =
true;
2340 d->addCommand(QQuickTextInputPrivate::Command(
2341 QQuickTextInputPrivate::SetSelection, d->m_cursor, u'\0', d->m_selstart, d->m_selend));
2342 d->finishChange(priorState);
2344 if (d->lastSelectionStart != d->lastSelectionEnd) {
2345 if (d->m_selstart != d->lastSelectionStart) {
2346 d->lastSelectionStart = d->m_selstart;
2347 emit selectionStartChanged();
2349 if (d->m_selend != d->lastSelectionEnd) {
2350 d->lastSelectionEnd = d->m_selend;
2351 emit selectionEndChanged();
2357
2358
2359
2360
2362void QQuickTextInput::remove(
int start,
int end)
2364 Q_D(QQuickTextInput);
2366 start = qBound(0, start, d->m_text.size());
2367 end = qBound(0, end, d->m_text.size());
2371 else if (start == end)
2374 if (start < d->m_selend && end > d->m_selstart)
2375 d->m_selDirty =
true;
2377 const int priorState = d->m_undoState;
2379 d->addCommand(QQuickTextInputPrivate::Command(
2380 QQuickTextInputPrivate::SetSelection, d->m_cursor, u'\0', d->m_selstart, d->m_selend));
2382 if (start <= d->m_cursor && d->m_cursor < end) {
2385 for (
int i = d->m_cursor; i >= start; --i) {
2386 d->addCommand(QQuickTextInputPrivate::Command(
2387 QQuickTextInputPrivate::DeleteSelection, i, d->m_text.at(i), -1, 1));
2389 for (
int i = end - 1; i > d->m_cursor; --i) {
2390 d->addCommand(QQuickTextInputPrivate::Command(
2391 QQuickTextInputPrivate::DeleteSelection, i - d->m_cursor + start - 1, d->m_text.at(i), -1, -1));
2394 for (
int i = end - 1; i >= start; --i) {
2395 d->addCommand(QQuickTextInputPrivate::Command(
2396 QQuickTextInputPrivate::RemoveSelection, i, d->m_text.at(i), -1, -1));
2399 if (d->m_maskData) {
2400 d->m_text.replace(start, end - start, d->clearString(start, end - start));
2401 for (
int i = 0; i < end - start; ++i) {
2402 d->addCommand(QQuickTextInputPrivate::Command(
2403 QQuickTextInputPrivate::Insert, start + i, d->m_text.at(start + i), -1, -1));
2406 d->m_text.remove(start, end - start);
2408 if (d->m_cursor > start)
2409 d->m_cursor -= qMin(d->m_cursor, end) - start;
2410 if (d->m_selstart > start)
2411 d->m_selstart -= qMin(d->m_selstart, end) - start;
2412 if (d->m_selend >= end)
2413 d->m_selend -= end - start;
2415 d->addCommand(QQuickTextInputPrivate::Command(
2416 QQuickTextInputPrivate::SetSelection, d->m_cursor, u'\0', d->m_selstart, d->m_selend));
2418 d->m_textDirty =
true;
2419 d->finishChange(priorState);
2421 if (d->lastSelectionStart != d->lastSelectionEnd) {
2422 if (d->m_selstart != d->lastSelectionStart) {
2423 d->lastSelectionStart = d->m_selstart;
2424 emit selectionStartChanged();
2426 if (d->m_selend != d->lastSelectionEnd) {
2427 d->lastSelectionEnd = d->m_selend;
2428 emit selectionEndChanged();
2435
2436
2437
2438
2439void QQuickTextInput::selectWord()
2441 Q_D(QQuickTextInput);
2442 d->selectWordAtPos(d->m_cursor);
2446
2447
2448
2449
2450
2451
2452
2453
2454
2455
2456QString QQuickTextInput::passwordCharacter()
const
2458 Q_D(
const QQuickTextInput);
2459 return QString(d->m_passwordCharacter);
2462void QQuickTextInput::setPasswordCharacter(
const QString &str)
2464 Q_D(QQuickTextInput);
2467 d->m_passwordCharacter = str.constData()[0];
2468 if (d->m_echoMode == Password || d->m_echoMode == PasswordEchoOnEdit)
2469 d->updateDisplayText();
2470 emit passwordCharacterChanged();
2474
2475
2476
2477
2478
2479
2480
2481int QQuickTextInput::passwordMaskDelay()
const
2483 Q_D(
const QQuickTextInput);
2484 return d->m_passwordMaskDelay;
2487void QQuickTextInput::setPasswordMaskDelay(
int delay)
2489 Q_D(QQuickTextInput);
2490 if (d->m_passwordMaskDelay != delay) {
2491 d->m_passwordMaskDelay = delay;
2492 emit passwordMaskDelayChanged(delay);
2496void QQuickTextInput::resetPasswordMaskDelay()
2498 setPasswordMaskDelay(qGuiApp->styleHints()->passwordMaskDelay());
2502
2503
2504
2505
2506
2507
2508
2509
2510
2511
2512
2513
2514
2515
2516
2517QString QQuickTextInput::displayText()
const
2519 Q_D(
const QQuickTextInput);
2520 return d->m_textLayout.text().insert(d->m_textLayout.preeditAreaPosition(), d->m_textLayout.preeditAreaText());
2524
2525
2526
2527
2528
2529
2530
2531
2532
2533
2534
2535QString QQuickTextInput::preeditText()
const
2537 Q_D(
const QQuickTextInput);
2538 return d->m_textLayout.preeditAreaText();
2542
2543
2544
2545
2546
2547
2548
2549
2550
2551
2552
2553
2554
2555
2556
2557
2558
2559bool QQuickTextInput::selectByMouse()
const
2561 Q_D(
const QQuickTextInput);
2562 return d->selectByMouse;
2565void QQuickTextInput::setSelectByMouse(
bool on)
2567 Q_D(QQuickTextInput);
2568 if (d->selectByMouse != on) {
2569 d->selectByMouse = on;
2570 emit selectByMouseChanged(on);
2575
2576
2577
2578
2579
2580
2581
2582
2583
2585QQuickTextInput::SelectionMode QQuickTextInput::mouseSelectionMode()
const
2587 Q_D(
const QQuickTextInput);
2588 return d->mouseSelectionMode;
2591void QQuickTextInput::setMouseSelectionMode(SelectionMode mode)
2593 Q_D(QQuickTextInput);
2594 if (d->mouseSelectionMode != mode) {
2595 d->mouseSelectionMode = mode;
2596 emit mouseSelectionModeChanged(mode);
2601
2602
2603
2604
2605
2607bool QQuickTextInput::persistentSelection()
const
2609 Q_D(
const QQuickTextInput);
2610 return d->persistentSelection;
2613void QQuickTextInput::setPersistentSelection(
bool on)
2615 Q_D(QQuickTextInput);
2616 if (d->persistentSelection == on)
2618 d->persistentSelection = on;
2619 emit persistentSelectionChanged();
2623
2624
2625
2626
2627
2628
2629bool QQuickTextInput::canPaste()
const
2631#if QT_CONFIG(clipboard)
2632 Q_D(
const QQuickTextInput);
2633 if (!d->canPasteValid) {
2634 if (
const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData())
2635 const_cast<QQuickTextInputPrivate *>(d)->canPaste = !d->m_readOnly && mimeData->hasText() && !mimeData->text().isEmpty();
2636 const_cast<QQuickTextInputPrivate *>(d)->canPasteValid =
true;
2645
2646
2647
2648
2649
2650
2652bool QQuickTextInput::canUndo()
const
2654 Q_D(
const QQuickTextInput);
2659
2660
2661
2662
2663
2664
2666bool QQuickTextInput::canRedo()
const
2668 Q_D(
const QQuickTextInput);
2673
2674
2675
2676
2677
2678
2680qreal QQuickTextInput::contentWidth()
const
2682 Q_D(
const QQuickTextInput);
2683 return d->contentSize.width();
2687
2688
2689
2690
2691
2692
2694qreal QQuickTextInput::contentHeight()
const
2696 Q_D(
const QQuickTextInput);
2697 return d->contentSize.height();
2700void QQuickTextInput::moveCursorSelection(
int position)
2702 Q_D(QQuickTextInput);
2703 d->moveCursor(position,
true);
2707
2708
2709
2710
2711
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
2742void QQuickTextInput::moveCursorSelection(
int pos, SelectionMode mode)
2744 Q_D(QQuickTextInput);
2746 if (mode == SelectCharacters) {
2747 d->moveCursor(pos,
true);
2748 }
else if (pos != d->m_cursor) {
2749 const int cursor = d->m_cursor;
2751 if (!d->hasSelectedText())
2752 anchor = d->m_cursor;
2753 else if (d->selectionStart() == d->m_cursor)
2754 anchor = d->selectionEnd();
2756 anchor = d->selectionStart();
2758 if (anchor < pos || (anchor == pos && cursor < pos)) {
2759 const QString text =
this->text();
2760 QTextBoundaryFinder finder(QTextBoundaryFinder::Word, text);
2761 finder.setPosition(anchor);
2763 const QTextBoundaryFinder::BoundaryReasons reasons = finder.boundaryReasons();
2764 if (anchor < text.size() && (reasons == QTextBoundaryFinder::NotAtBoundary
2765 || (reasons & QTextBoundaryFinder::EndOfItem))) {
2766 finder.toPreviousBoundary();
2768 anchor = finder.position() != -1 ? finder.position() : 0;
2770 finder.setPosition(pos);
2771 if (pos > 0 && !finder.boundaryReasons())
2772 finder.toNextBoundary();
2773 const int cursor = finder.position() != -1 ? finder.position() : text.size();
2775 d->setSelection(anchor, cursor - anchor);
2776 }
else if (anchor > pos || (anchor == pos && cursor > pos)) {
2777 const QString text =
this->text();
2778 QTextBoundaryFinder finder(QTextBoundaryFinder::Word, text);
2779 finder.setPosition(anchor);
2781 const QTextBoundaryFinder::BoundaryReasons reasons = finder.boundaryReasons();
2782 if (anchor > 0 && (reasons == QTextBoundaryFinder::NotAtBoundary
2783 || (reasons & QTextBoundaryFinder::StartOfItem))) {
2784 finder.toNextBoundary();
2786 anchor = finder.position() != -1 ? finder.position() : text.size();
2788 finder.setPosition(pos);
2789 if (pos < text.size() && !finder.boundaryReasons())
2790 finder.toPreviousBoundary();
2791 const int cursor = finder.position() != -1 ? finder.position() : 0;
2793 d->setSelection(anchor, cursor - anchor);
2798void QQuickTextInput::focusInEvent(QFocusEvent *event)
2800 Q_D(QQuickTextInput);
2801 d->handleFocusEvent(event);
2802 QQuickImplicitSizeItem::focusInEvent(event);
2805void QQuickTextInputPrivate::handleFocusEvent(QFocusEvent *event)
2807 Q_Q(QQuickTextInput);
2808 bool focus = event->gotFocus();
2810 q->setCursorVisible(focus);
2811 setBlinkingCursorEnabled(focus);
2814 q->q_updateAlignment();
2816 if (focusOnPress && !m_readOnly)
2817 qGuiApp->inputMethod()->show();
2818 q->connect(QGuiApplication::inputMethod(), SIGNAL(inputDirectionChanged(Qt::LayoutDirection)),
2819 q, SLOT(q_updateAlignment()));
2822 if ((m_passwordEchoEditing || m_passwordEchoTimer.isActive())) {
2823 updatePasswordEchoEditing(
false);
2826 if (event->reason() != Qt::ActiveWindowFocusReason
2827 && event->reason() != Qt::PopupFocusReason
2828 && hasSelectedText()
2829 && !persistentSelection)
2832 if (hasAcceptableInput(m_text) == AcceptableInput || fixup())
2833 emit q->editingFinished();
2836 q->disconnect(QGuiApplication::inputMethod(), SIGNAL(inputDirectionChanged(Qt::LayoutDirection)),
2837 q, SLOT(q_updateAlignment()));
2842void QQuickTextInput::focusOutEvent(QFocusEvent *event)
2844 Q_D(QQuickTextInput);
2845 d->handleFocusEvent(event);
2846 QQuickImplicitSizeItem::focusOutEvent(event);
2849void QQuickTextInputPrivate::readOnlyChanged(
bool isReadOnly)
2851 Q_UNUSED(isReadOnly);
2852#if QT_CONFIG(accessibility)
2853 if (QQuickAccessibleAttached *accessibleAttached =
2854 QQuickAccessibleAttached::attachedProperties(q_func()))
2855 accessibleAttached->set_readOnly(isReadOnly);
2859void QQuickTextInputPrivate::echoModeChanged(QQuickTextInput::EchoMode echoMode)
2861#if QT_CONFIG(accessibility)
2862 if (!QAccessible::isActive())
2865 if (QQuickAccessibleAttached *accessibleAttached =
2866 QQuickAccessibleAttached::attachedProperties(q_func()))
2867 accessibleAttached->set_passwordEdit((echoMode == QQuickTextInput::Password
2868 || echoMode == QQuickTextInput::PasswordEchoOnEdit)
2876#if QT_CONFIG(accessibility)
2877void QQuickTextInputPrivate::accessibilityActiveChanged(
bool active)
2882 Q_Q(QQuickTextInput);
2883 QQuickAccessibleAttached *accessibleAttached = qobject_cast<QQuickAccessibleAttached *>(
2884 qmlAttachedPropertiesObject<QQuickAccessibleAttached>(q,
true));
2885 Q_ASSERT(accessibleAttached);
2886 accessibleAttached->setRole(effectiveAccessibleRole());
2887 accessibleAttached->set_readOnly(m_readOnly);
2888 accessibleAttached->set_passwordEdit((m_echoMode == QQuickTextInput::Password
2889 || m_echoMode == QQuickTextInput::PasswordEchoOnEdit)
2894QAccessible::Role QQuickTextInputPrivate::accessibleRole()
const
2896 return QAccessible::EditableText;
2901
2902
2903
2904
2905
2906
2907
2908
2909
2910
2911
2912bool QQuickTextInput::isInputMethodComposing()
const
2917 Q_D(
const QQuickTextInput);
2918 return d->hasImState;
2922QQuickTextInputPrivate::ExtraData::ExtraData()
2928 , explicitTopPadding(
false)
2929 , explicitLeftPadding(
false)
2930 , explicitRightPadding(
false)
2931 , explicitBottomPadding(
false)
2932 , implicitResize(
true)
2936void QQuickTextInputPrivate::init()
2938 Q_Q(QQuickTextInput);
2939#if QT_CONFIG(clipboard)
2940 if (QGuiApplication::clipboard()->supportsSelection())
2941 q->setAcceptedMouseButtons(Qt::LeftButton | Qt::MiddleButton);
2944 q->setAcceptedMouseButtons(Qt::LeftButton);
2947 q->setFlag(QQuickItem::ItemAcceptsInputMethod);
2949 q->setFlag(QQuickItem::ItemHasContents);
2950#if QT_CONFIG(clipboard)
2951 qmlobject_connect(QGuiApplication::clipboard(), QClipboard, SIGNAL(dataChanged()),
2952 q, QQuickTextInput, SLOT(q_canPasteChanged()));
2955 lastSelectionStart = 0;
2956 lastSelectionEnd = 0;
2957 determineHorizontalAlignment();
2959 if (!qmlDisableDistanceField()) {
2960 QTextOption option = m_textLayout.textOption();
2961 option.setUseDesignMetrics(renderType != QQuickTextInput::NativeRendering);
2962 m_textLayout.setTextOption(option);
2965 m_inputControl =
new QInputControl(QInputControl::LineEdit, q);
2966 setSizePolicy(QLayoutPolicy::Expanding, QLayoutPolicy::Fixed);
2968 QObjectPrivate::connect(q, &QQuickTextInput::readOnlyChanged,
this,
2969 &QQuickTextInputPrivate::readOnlyChanged);
2970 QObjectPrivate::connect(q, &QQuickTextInput::echoModeChanged,
this,
2971 &QQuickTextInputPrivate::echoModeChanged);
2974void QQuickTextInputPrivate::cancelInput()
2977 Q_Q(QQuickTextInput);
2978 if (!m_readOnly && q->hasActiveFocus() && qGuiApp)
2983void QQuickTextInput::updateCursorRectangle(
bool scroll)
2985 Q_D(QQuickTextInput);
2986 if (!isComponentComplete())
2990 d->updateHorizontalScroll();
2991 d->updateVerticalScroll();
2993 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
2996 emit cursorRectangleChanged();
2997 if (d->cursorItem) {
2998 QRectF r = cursorRectangle();
2999 d->cursorItem->setPosition(r.topLeft());
3000 d->cursorItem->setHeight(r.height());
3003 updateInputMethod(Qt::ImCursorRectangle | Qt::ImAnchorRectangle);
3007void QQuickTextInput::selectionChanged()
3009 Q_D(QQuickTextInput);
3010 d->textLayoutDirty =
true;
3011 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
3014 emit selectedTextChanged();
3016 if (d->lastSelectionStart != d->selectionStart()) {
3017 d->lastSelectionStart = d->selectionStart();
3018 if (d->lastSelectionStart == -1)
3019 d->lastSelectionStart = d->m_cursor;
3020 emit selectionStartChanged();
3022 if (d->lastSelectionEnd != d->selectionEnd()) {
3023 d->lastSelectionEnd = d->selectionEnd();
3024 if (d->lastSelectionEnd == -1)
3025 d->lastSelectionEnd = d->m_cursor;
3026 emit selectionEndChanged();
3030QRectF QQuickTextInput::boundingRect()
const
3032 Q_D(
const QQuickTextInput);
3034 int cursorWidth = d->cursorItem ? 0 : 1;
3036 qreal hscroll = d->hscroll;
3037 if (!d->autoScroll || d->contentSize.width() < width())
3038 hscroll -= QQuickTextUtil::alignedX(d->contentSize.width(), width(), effectiveHAlign());
3041 QRectF r(-hscroll, -d->vscroll, d->contentSize.width(), d->contentSize.height());
3042 r.setRight(r.right() + cursorWidth);
3046QRectF QQuickTextInput::clipRect()
const
3048 Q_D(
const QQuickTextInput);
3050 int cursorWidth = d->cursorItem ? d->cursorItem->width() : 1;
3053 QRectF r = QQuickImplicitSizeItem::clipRect();
3054 r.setRight(r.right() + cursorWidth);
3058void QQuickTextInput::q_canPasteChanged()
3060 Q_D(QQuickTextInput);
3061 bool old = d->canPaste;
3062#if QT_CONFIG(clipboard)
3063 bool canPaste =
false;
3064 if (!d->m_readOnly) {
3065 if (
const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData())
3066 canPaste = mimeData->hasText();
3068 d->canPaste = canPaste;
3071 bool changed = d->canPaste != old || !d->canPasteValid;
3072 d->canPasteValid =
true;
3074 emit canPasteChanged();
3078void QQuickTextInput::q_updateAlignment()
3080 Q_D(QQuickTextInput);
3081 if (d->determineHorizontalAlignment()) {
3083 updateCursorRectangle();
3088
3089
3090
3091
3092
3093void QQuickTextInputPrivate::updateDisplayText(
bool forceUpdate)
3095 QString orig = m_textLayout.text();
3097 if (m_echoMode == QQuickTextInput::NoEcho)
3098 str = QString::fromLatin1(
"");
3102 if (m_echoMode == QQuickTextInput::Password) {
3103 str.fill(m_passwordCharacter);
3104 if (m_passwordEchoTimer.isActive() && m_cursor > 0 && m_cursor <= m_text.size()) {
3105 int cursor = m_cursor - 1;
3106 QChar uc = m_text.at(cursor);
3108 if (cursor > 0 && uc.unicode() >= 0xdc00 && uc.unicode() < 0xe000) {
3111 uc = m_text.at(cursor - 1);
3112 if (uc.unicode() >= 0xd800 && uc.unicode() < 0xdc00)
3113 str[cursor - 1] = uc;
3116 }
else if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit && !m_passwordEchoEditing) {
3117 str.fill(m_passwordCharacter);
3123 QChar* uc = str.data();
3124 for (
int i = 0; i < str.size(); ++i) {
3125 if (uc[i] == QChar::LineSeparator
3126 || uc[i] == QChar::ParagraphSeparator
3127 || uc[i] == QChar::ObjectReplacementCharacter)
3128 uc[i] = QChar(0x0020);
3131 if (str != orig || forceUpdate) {
3132 m_textLayout.setText(str);
3134 emit q_func()->displayTextChanged();
3138qreal QQuickTextInputPrivate::calculateImplicitWidthForText(
const QString &text)
const
3140 Q_Q(
const QQuickTextInput);
3141 QTextLayout layout(text);
3143 QTextOption option = m_textLayout.textOption();
3144 option.setTextDirection(m_layoutDirection);
3145 option.setFlags(QTextOption::IncludeTrailingSpaces);
3146 option.setWrapMode(QTextOption::WrapMode(wrapMode));
3147 option.setAlignment(Qt::Alignment(q->effectiveHAlign()));
3148 layout.setTextOption(option);
3149 layout.setFont(font);
3151 layout.setPreeditArea(m_textLayout.preeditAreaPosition(), m_textLayout.preeditAreaText());
3153 layout.beginLayout();
3155 QTextLine line = layout.createLine();
3156 line.setLineWidth(qreal(INT_MAX));
3157 const qreal theImplicitWidth = qCeil(line.naturalTextWidth()) + q->leftPadding() + q->rightPadding();
3160 return theImplicitWidth;
3163qreal QQuickTextInputPrivate::getImplicitWidth()
const
3165 Q_Q(
const QQuickTextInput);
3166 if (!requireImplicitWidth) {
3167 QQuickTextInputPrivate *d =
const_cast<QQuickTextInputPrivate *>(
this);
3168 d->requireImplicitWidth =
true;
3170 if (q->isComponentComplete())
3171 d->implicitWidth = calculateImplicitWidthForText(m_text);
3173 return implicitWidth;
3176void QQuickTextInputPrivate::setTopPadding(qreal value,
bool reset)
3178 Q_Q(QQuickTextInput);
3179 qreal oldPadding = q->topPadding();
3180 if (!reset || extra.isAllocated()) {
3181 extra.value().topPadding = value;
3182 extra.value().explicitTopPadding = !reset;
3184 if ((!reset && !qFuzzyCompare(oldPadding, value)) || (reset && !qFuzzyCompare(oldPadding, padding()))) {
3186 q->updateCursorRectangle();
3187 emit q->topPaddingChanged();
3191void QQuickTextInputPrivate::setLeftPadding(qreal value,
bool reset)
3193 Q_Q(QQuickTextInput);
3194 qreal oldPadding = q->leftPadding();
3195 if (!reset || extra.isAllocated()) {
3196 extra.value().leftPadding = value;
3197 extra.value().explicitLeftPadding = !reset;
3199 if ((!reset && !qFuzzyCompare(oldPadding, value)) || (reset && !qFuzzyCompare(oldPadding, padding()))) {
3201 q->updateCursorRectangle();
3202 emit q->leftPaddingChanged();
3206void QQuickTextInputPrivate::setRightPadding(qreal value,
bool reset)
3208 Q_Q(QQuickTextInput);
3209 qreal oldPadding = q->rightPadding();
3210 if (!reset || extra.isAllocated()) {
3211 extra.value().rightPadding = value;
3212 extra.value().explicitRightPadding = !reset;
3214 if ((!reset && !qFuzzyCompare(oldPadding, value)) || (reset && !qFuzzyCompare(oldPadding, padding()))) {
3216 q->updateCursorRectangle();
3217 emit q->rightPaddingChanged();
3221void QQuickTextInputPrivate::setBottomPadding(qreal value,
bool reset)
3223 Q_Q(QQuickTextInput);
3224 qreal oldPadding = q->bottomPadding();
3225 if (!reset || extra.isAllocated()) {
3226 extra.value().bottomPadding = value;
3227 extra.value().explicitBottomPadding = !reset;
3229 if ((!reset && !qFuzzyCompare(oldPadding, value)) || (reset && !qFuzzyCompare(oldPadding, padding()))) {
3231 q->updateCursorRectangle();
3232 emit q->bottomPaddingChanged();
3236bool QQuickTextInputPrivate::isImplicitResizeEnabled()
const
3238 return !extra.isAllocated() || extra->implicitResize;
3241void QQuickTextInputPrivate::setImplicitResizeEnabled(
bool enabled)
3244 extra.value().implicitResize =
false;
3245 else if (extra.isAllocated())
3246 extra->implicitResize =
true;
3249void QQuickTextInputPrivate::updateLayout()
3251 Q_Q(QQuickTextInput);
3253 if (!q->isComponentComplete())
3257 QTextOption option = m_textLayout.textOption();
3258 option.setTextDirection(layoutDirection());
3259 option.setWrapMode(QTextOption::WrapMode(wrapMode));
3260 option.setAlignment(Qt::Alignment(q->effectiveHAlign()));
3261 if (!qmlDisableDistanceField())
3262 option.setUseDesignMetrics(renderType != QQuickTextInput::NativeRendering);
3264 m_textLayout.setTextOption(option);
3265 m_textLayout.setFont(font);
3267 m_textLayout.beginLayout();
3269 QTextLine line = m_textLayout.createLine();
3270 if (requireImplicitWidth) {
3271 line.setLineWidth(qreal(INT_MAX));
3272 const bool wasInLayout = inLayout;
3274 if (isImplicitResizeEnabled())
3275 q->setImplicitWidth(qCeil(line.naturalTextWidth()) + q->leftPadding() + q->rightPadding());
3276 inLayout = wasInLayout;
3280 qreal lineWidth = q->widthValid() || !isImplicitResizeEnabled() ? q->width() - q->leftPadding() - q->rightPadding() : qreal(INT_MAX);
3284 line.setLineWidth(lineWidth);
3285 line.setPosition(QPointF(0, height));
3287 height += line.height();
3288 width = qMax(width, line.naturalTextWidth());
3290 line = m_textLayout.createLine();
3291 }
while (line.isValid());
3292 m_textLayout.endLayout();
3294 option.setWrapMode(QTextOption::NoWrap);
3295 m_textLayout.setTextOption(option);
3297 textLayoutDirty =
true;
3299 const QSizeF previousSize = contentSize;
3300 contentSize = QSizeF(width, height);
3302 updateType = UpdatePaintNode;
3306 if (isImplicitResizeEnabled()) {
3307 if (!requireImplicitWidth && !q->widthValid())
3308 q->setImplicitSize(width + q->leftPadding() + q->rightPadding(), height + q->topPadding() + q->bottomPadding());
3310 q->setImplicitHeight(height + q->topPadding() + q->bottomPadding());
3313 updateBaselineOffset();
3315 if (previousSize != contentSize)
3316 emit q->contentSizeChanged();
3320
3321
3322
3323
3324
3325void QQuickTextInputPrivate::updateBaselineOffset()
3327 Q_Q(QQuickTextInput);
3328 if (!q->isComponentComplete())
3330 QFontMetricsF fm(font);
3332 if (q->heightValid()) {
3333 const qreal surplusHeight = q->height() - contentSize.height() - q->topPadding() - q->bottomPadding();
3334 if (vAlign == QQuickTextInput::AlignBottom)
3335 yoff = surplusHeight;
3336 else if (vAlign == QQuickTextInput::AlignVCenter)
3337 yoff = surplusHeight/2;
3339 q->setBaselineOffset(fm.ascent() + yoff + q->topPadding());
3342#if QT_CONFIG(clipboard)
3344
3345
3346
3347
3348
3349
3350
3351
3352
3353void QQuickTextInputPrivate::copy(QClipboard::Mode mode)
const
3355 QString t = selectedText();
3356 if (!t.isEmpty() && m_echoMode == QQuickTextInput::Normal) {
3357 QGuiApplication::clipboard()->setText(t, mode);
3362
3363
3364
3365
3366
3367
3368
3369void QQuickTextInputPrivate::paste(QClipboard::Mode clipboardMode)
3371 QString clip = QGuiApplication::clipboard()->text(clipboardMode);
3372 if (!clip.isEmpty() || hasSelectedText()) {
3383
3384
3385void QQuickTextInputPrivate::commitPreedit()
3387 Q_Q(QQuickTextInput);
3392 QGuiApplication::inputMethod()->commit();
3397 QInputMethodEvent ev;
3398 QCoreApplication::sendEvent(q, &ev);
3401void QQuickTextInputPrivate::cancelPreedit()
3403 Q_Q(QQuickTextInput);
3408 QGuiApplication::inputMethod()->reset();
3410 QInputMethodEvent ev;
3411 QCoreApplication::sendEvent(q, &ev);
3416
3417
3418
3419
3420
3421
3422
3423
3424void QQuickTextInputPrivate::backspace()
3426 int priorState = m_undoState;
3427 if (separateSelection()) {
3428 removeSelectedText();
3429 }
else if (m_cursor) {
3432 m_cursor = prevMaskBlank(m_cursor);
3433 QChar uc = m_text.at(m_cursor);
3434 if (m_cursor > 0 && uc.unicode() >= 0xdc00 && uc.unicode() < 0xe000) {
3437 uc = m_text.at(m_cursor - 1);
3438 if (uc.unicode() >= 0xd800 && uc.unicode() < 0xdc00) {
3439 internalDelete(
true);
3443 internalDelete(
true);
3445 finishChange(priorState);
3449
3450
3451
3452
3453
3454
3455
3456
3457void QQuickTextInputPrivate::del()
3459 int priorState = m_undoState;
3460 if (separateSelection()) {
3461 removeSelectedText();
3463 int n = m_textLayout.nextCursorPosition(m_cursor) - m_cursor;
3467 finishChange(priorState);
3471
3472
3473
3474
3475
3476
3477void QQuickTextInputPrivate::insert(
const QString &newText)
3479 int priorState = m_undoState;
3480 if (separateSelection())
3481 removeSelectedText();
3482 internalInsert(newText);
3483 finishChange(priorState);
3487
3488
3489
3490
3491void QQuickTextInputPrivate::clear()
3493 int priorState = m_undoState;
3494 separateSelection();
3496 m_selend = m_text.size();
3497 removeSelectedText();
3499 finishChange(priorState,
false,
false);
3503
3504
3505
3506
3507
3508
3509
3510void QQuickTextInputPrivate::setSelection(
int start,
int length)
3512 Q_Q(QQuickTextInput);
3517 if (start < 0 || start > m_text.size()) {
3518 qWarning(
"QQuickTextInputPrivate::setSelection: Invalid start position");
3523 if (start == m_selstart && start + length == m_selend && m_cursor == m_selend)
3526 m_selend = qMin(start + length, m_text.size());
3527 m_cursor = m_selend;
3528 }
else if (length < 0) {
3529 if (start == m_selend && start + length == m_selstart && m_cursor == m_selstart)
3531 m_selstart = qMax(start + length, 0);
3533 m_cursor = m_selstart;
3534 }
else if (m_selstart != m_selend) {
3540 emitCursorPositionChanged();
3543 emit q->selectionChanged();
3544 emitCursorPositionChanged();
3546 q->updateInputMethod(Qt::ImCursorRectangle | Qt::ImAnchorRectangle | Qt::ImCursorPosition | Qt::ImAnchorPosition
3547 | Qt::ImCurrentSelection);
3552
3553
3554
3555
3556
3557
3558
3559void QQuickTextInputPrivate::updatePasswordEchoEditing(
bool editing)
3561 cancelPasswordEchoTimer();
3562 m_passwordEchoEditing = editing;
3563 updateDisplayText();
3567
3568
3569
3570
3571
3572
3573bool QQuickTextInputPrivate::fixup()
3575#if QT_CONFIG(validator)
3577 QString textCopy = m_text;
3578 int cursorCopy = m_cursor;
3579 m_validator->fixup(textCopy);
3580 if (m_validator->validate(textCopy, cursorCopy) == QValidator::Acceptable) {
3581 if (textCopy != m_text || cursorCopy != m_cursor)
3582 internalSetText(textCopy, cursorCopy);
3591
3592
3593
3594
3595
3596void QQuickTextInputPrivate::moveCursor(
int pos,
bool mark)
3598 Q_Q(QQuickTextInput);
3603 if (pos != m_cursor) {
3606 pos = pos > m_cursor ? nextMaskBlank(pos) : prevMaskBlank(pos);
3610 if (m_selend > m_selstart && m_cursor == m_selstart)
3612 else if (m_selend > m_selstart && m_cursor == m_selend)
3613 anchor = m_selstart;
3616 m_selstart = qMin(anchor, pos);
3617 m_selend = qMax(anchor, pos);
3622 if (mark || m_selDirty) {
3624 emit q->selectionChanged();
3626 emitCursorPositionChanged();
3628 q->updateInputMethod();
3634
3635
3636
3637
3638
3639void QQuickTextInputPrivate::processInputMethodEvent(QInputMethodEvent *event)
3641 Q_Q(QQuickTextInput);
3643 int priorState = -1;
3644 bool isGettingInput = !event->commitString().isEmpty()
3645 || event->preeditString() != preeditAreaText()
3646 || event->replacementLength() > 0;
3647 bool cursorPositionChanged =
false;
3648 bool selectionChange =
false;
3649 m_preeditDirty = event->preeditString() != preeditAreaText();
3651 if (isGettingInput) {
3653 priorState = m_undoState;
3654 separateSelection();
3655 if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit && !m_passwordEchoEditing) {
3656 updatePasswordEchoEditing(
true);
3658 m_selend = m_text.size();
3660 removeSelectedText();
3664 if (event->replacementStart() <= 0)
3665 c += event->commitString().size() - qMin(-event->replacementStart(), event->replacementLength());
3667 int cursorInsertPos = m_cursor + event->replacementStart();
3668 if (cursorInsertPos < 0)
3669 cursorInsertPos = 0;
3672 if (event->replacementLength()) {
3673 m_selstart = cursorInsertPos;
3674 m_selend = m_selstart + event->replacementLength();
3675 m_selend = qMin(m_selend, m_text.size());
3676 removeSelectedText();
3678 m_cursor = cursorInsertPos;
3680 if (!event->commitString().isEmpty()) {
3681 internalInsert(event->commitString());
3682 cursorPositionChanged =
true;
3684 m_cursor = qBound(0, c, m_text.size());
3687 for (
int i = 0; i < event->attributes().size(); ++i) {
3688 const QInputMethodEvent::Attribute &a = event->attributes().at(i);
3689 if (a.type == QInputMethodEvent::Selection) {
3696 if (!cursorPositionChanged || !m_maskData)
3697 m_cursor = qBound(0, a.start + a.length, m_text.size());
3699 m_selstart = qMax(0, qMin(a.start, m_text.size()));
3700 m_selend = m_cursor;
3701 if (m_selend < m_selstart) {
3702 qSwap(m_selstart, m_selend);
3704 selectionChange =
true;
3706 selectionChange = m_selstart != m_selend;
3707 m_selstart = m_selend = 0;
3709 cursorPositionChanged =
true;
3712 QString oldPreeditString = m_textLayout.preeditAreaText();
3713 m_textLayout.setPreeditArea(m_cursor, event->preeditString());
3714 if (oldPreeditString != m_textLayout.preeditAreaText()) {
3715 emit q->preeditTextChanged();
3716 if (!event->preeditString().isEmpty() && m_undoPreeditState == -1)
3718 m_undoPreeditState = priorState;
3720 const int oldPreeditCursor = m_preeditCursor;
3721 m_preeditCursor = event->preeditString().size();
3722 hasImState = !event->preeditString().isEmpty();
3723 bool cursorVisible =
true;
3724 QList<QTextLayout::FormatRange> formats;
3725 for (
int i = 0; i < event->attributes().size(); ++i) {
3726 const QInputMethodEvent::Attribute &a = event->attributes().at(i);
3727 if (a.type == QInputMethodEvent::Cursor) {
3729 m_preeditCursor = a.start;
3730 cursorVisible = a.length != 0;
3731 }
else if (a.type == QInputMethodEvent::TextFormat) {
3733 QTextCharFormat f = qvariant_cast<QTextFormat>(a.value).toCharFormat();
3735 QTextLayout::FormatRange o;
3736 o.start = a.start + m_cursor;
3737 o.length = a.length;
3743 m_textLayout.setFormats(formats);
3749 q->setCursorVisible(cursorVisible);
3751 updateDisplayText(
true);
3752 if (cursorPositionChanged && emitCursorPositionChanged())
3753 q->updateInputMethod(Qt::ImCursorPosition | Qt::ImAnchorPosition);
3754 else if (m_preeditCursor != oldPreeditCursor || isGettingInput)
3755 q->updateCursorRectangle();
3758 finishChange(priorState);
3760 if (selectionChange) {
3761 emit q->selectionChanged();
3762 q->updateInputMethod(Qt::ImCursorRectangle | Qt::ImAnchorRectangle
3763 | Qt::ImCurrentSelection);
3767 if (event->preeditString().isEmpty())
3768 m_undoPreeditState = -1;
3774
3775
3776
3777
3778
3779
3780void QQuickTextInputPrivate::selectWordAtPos(
int cursor)
3782 int next = cursor + 1;
3785 int c = m_textLayout.previousCursorPosition(next, QTextLayout::SkipWords);
3786 moveCursor(c,
false);
3788 int end = m_textLayout.nextCursorPosition(c, QTextLayout::SkipWords);
3789 while (end > cursor && m_text.at(end - 1).isSpace())
3791 moveCursor(end,
true);
3795
3796
3797
3798
3799
3800
3801
3802
3803
3804
3805
3806bool QQuickTextInputPrivate::finishChange(
int validateFromState,
bool update,
bool edited)
3808 Q_Q(QQuickTextInput);
3812 bool inputMethodAttributesChanged = m_textDirty || m_selDirty;
3814 bool alignmentChanged =
false;
3815 bool textChanged =
false;
3819 bool wasValidInput = m_validInput;
3820 bool wasAcceptable = m_acceptableInput;
3821 m_validInput =
true;
3822 m_acceptableInput =
true;
3823#if QT_CONFIG(validator)
3825 QString textCopy = m_text;
3827 textCopy = maskString(0, m_text,
true);
3828 int cursorCopy = m_cursor;
3829 QValidator::State state = m_validator->validate(textCopy, cursorCopy);
3832 m_validInput = state != QValidator::Invalid;
3833 m_acceptableInput = state == QValidator::Acceptable;
3834 if (m_validInput && !m_maskData) {
3835 if (m_text != textCopy) {
3836 internalSetText(textCopy, cursorCopy);
3839 m_cursor = cursorCopy;
3849 if (m_undoPreeditState >= 0 && (m_undoPreeditState < validateFromState || validateFromState < 0))
3850 validateFromState = m_undoPreeditState;
3852 if (validateFromState >= 0 && wasValidInput && !m_validInput) {
3853 if (m_transactions.size())
3855 internalUndo(validateFromState);
3856 m_history.resize(m_undoState);
3857 m_validInput =
true;
3858 m_acceptableInput = wasAcceptable;
3859 m_textDirty =
false;
3864 m_textDirty =
false;
3866 m_preeditDirty =
false;
3868 alignmentChanged = determineHorizontalAlignment();
3870 emit q->textEdited();
3871 emit q->textChanged();
3874 updateDisplayText(alignmentChanged);
3876 if (m_acceptableInput != wasAcceptable)
3877 emit q->acceptableInputChanged();
3880 if (m_preeditDirty) {
3881 m_preeditDirty =
false;
3882 if (determineHorizontalAlignment()) {
3883 alignmentChanged =
true;
3891 emit q->selectionChanged();
3895 inputMethodAttributesChanged |= (m_cursor != m_lastCursorPos);
3896 if (inputMethodAttributesChanged)
3897 q->updateInputMethod();
3899 emitUndoRedoChanged();
3901 if (!emitCursorPositionChanged() && (alignmentChanged || textChanged))
3902 q->updateCursorRectangle();
3908
3909
3910
3911
3912void QQuickTextInputPrivate::internalSetText(
const QString &txt,
int pos,
bool edited)
3915 QString oldText = m_text;
3917 m_text = maskString(0, txt,
true);
3918 m_text += clearString(m_text.size(), m_maxLength - m_text.size());
3920 m_text = txt.isEmpty() ? txt : txt.left(m_maxLength);
3925 m_undoPreeditState = -1;
3927 m_cursor = (pos < 0 || pos > m_text.size()) ? m_text.size() : pos;
3928 m_textDirty = (oldText != m_text);
3930 bool changed = finishChange(-1,
true, edited);
3931#if !QT_CONFIG(accessibility)
3934 Q_Q(QQuickTextInput);
3935 if (changed && QAccessible::isActive()) {
3936 if (QObject *acc = QQuickAccessibleAttached::findAccessible(q, QAccessible::EditableText)) {
3937 QAccessibleTextUpdateEvent ev(acc, 0, oldText, m_text);
3938 QAccessible::updateAccessibility(&ev);
3946
3947
3948
3949
3950
3951void QQuickTextInputPrivate::addCommand(
const Command &cmd)
3953 if (m_separator && m_undoState && m_history[m_undoState - 1].type != Separator) {
3954 m_history.resize(m_undoState + 2);
3955 m_history[m_undoState++] = Command(Separator, m_cursor, u'\0', m_selstart, m_selend);
3957 m_history.resize(m_undoState + 1);
3959 m_separator =
false;
3960 m_history[m_undoState++] = cmd;
3964
3965
3966
3967
3968
3969
3970
3971
3972
3973void QQuickTextInputPrivate::internalInsert(
const QString &s)
3975 Q_Q(QQuickTextInput);
3976 if (m_echoMode == QQuickTextInput::Password) {
3977 if (m_passwordMaskDelay > 0)
3978 m_passwordEchoTimer.start(m_passwordMaskDelay, q);
3980 Q_ASSERT(!hasSelectedText());
3982 QString ms = maskString(m_cursor, s);
3983 for (
int i = 0; i < ms.size(); ++i) {
3984 addCommand (Command(DeleteSelection, m_cursor + i, m_text.at(m_cursor + i), -1, -1));
3985 addCommand(Command(Insert, m_cursor + i, ms.at(i), -1, -1));
3987 m_text.replace(m_cursor, ms.size(), ms);
3988 m_cursor += ms.size();
3989 m_cursor = nextMaskBlank(m_cursor);
3992 int remaining = m_maxLength - m_text.size();
3993 if (remaining != 0) {
3994 const QStringView remainingStr = QStringView{s}.left(remaining);
3995 m_text.insert(m_cursor, remainingStr);
3996 for (
auto e : remainingStr)
3997 addCommand(Command(Insert, m_cursor++, e, -1, -1));
4004
4005
4006
4007
4008
4009
4010
4011
4012
4013
4014void QQuickTextInputPrivate::internalDelete(
bool wasBackspace)
4016 if (m_cursor < m_text.size()) {
4017 cancelPasswordEchoTimer();
4018 Q_ASSERT(!hasSelectedText());
4019 addCommand(Command((CommandType)((m_maskData ? 2 : 0) + (wasBackspace ? Remove : Delete)),
4020 m_cursor, m_text.at(m_cursor), -1, -1));
4022 m_text.replace(m_cursor, 1, clearString(m_cursor, 1));
4023 addCommand(Command(Insert, m_cursor, m_text.at(m_cursor), -1, -1));
4025 m_text.remove(m_cursor, 1);
4032
4033
4034
4035
4036
4037
4038
4039
4040void QQuickTextInputPrivate::removeSelectedText()
4042 if (m_selstart < m_selend && m_selend <= m_text.size()) {
4043 cancelPasswordEchoTimer();
4045 if (m_selstart <= m_cursor && m_cursor < m_selend) {
4048 for (i = m_cursor; i >= m_selstart; --i)
4049 addCommand (Command(DeleteSelection, i, m_text.at(i), -1, 1));
4050 for (i = m_selend - 1; i > m_cursor; --i)
4051 addCommand (Command(DeleteSelection, i - m_cursor + m_selstart - 1, m_text.at(i), -1, -1));
4053 for (i = m_selend-1; i >= m_selstart; --i)
4054 addCommand (Command(RemoveSelection, i, m_text.at(i), -1, -1));
4057 m_text.replace(m_selstart, m_selend - m_selstart, clearString(m_selstart, m_selend - m_selstart));
4058 for (
int i = 0; i < m_selend - m_selstart; ++i)
4059 addCommand(Command(Insert, m_selstart + i, m_text.at(m_selstart + i), -1, -1));
4061 m_text.remove(m_selstart, m_selend - m_selstart);
4063 if (m_cursor > m_selstart)
4064 m_cursor -= qMin(m_cursor, m_selend) - m_selstart;
4071
4072
4073
4074
4075
4076
4078bool QQuickTextInputPrivate::separateSelection()
4080 if (hasSelectedText()) {
4082 addCommand(Command(SetSelection, m_cursor, u'\0', m_selstart, m_selend));
4090
4091
4092
4093
4094
4095void QQuickTextInputPrivate::parseInputMask(
const QString &maskFields)
4097 int delimiter = maskFields.indexOf(QLatin1Char(
';'));
4098 if (maskFields.isEmpty() || delimiter == 0) {
4100 m_maskData.reset(
nullptr);
4101 m_maxLength = 32767;
4102 internalSetText(QString());
4107 if (delimiter == -1) {
4108 m_blank = QLatin1Char(
' ');
4109 m_inputMask = maskFields;
4111 m_inputMask = maskFields.left(delimiter);
4112 m_blank = (delimiter + 1 < maskFields.size()) ? maskFields[delimiter + 1] : QLatin1Char(
' ');
4118 for (
int i=0; i<m_inputMask.size(); i++) {
4119 c = m_inputMask.at(i);
4120 if (i > 0 && m_inputMask.at(i-1) == QLatin1Char(
'\\')) {
4124 if (c != QLatin1Char(
'\\') && c != QLatin1Char(
'!') &&
4125 c != QLatin1Char(
'<') && c != QLatin1Char(
'>') &&
4126 c != QLatin1Char(
'{') && c != QLatin1Char(
'}') &&
4127 c != QLatin1Char(
'[') && c != QLatin1Char(
']'))
4131 m_maskData.reset(
new MaskInputData[m_maxLength]);
4133 MaskInputData::Casemode m = MaskInputData::NoCaseMode;
4136 bool escape =
false;
4138 for (
int i = 0; i < m_inputMask.size(); i++) {
4139 c = m_inputMask.at(i);
4142 m_maskData[index].maskChar = c;
4143 m_maskData[index].separator = s;
4144 m_maskData[index].caseMode = m;
4147 }
else if (c == QLatin1Char(
'<')) {
4148 m = MaskInputData::Lower;
4149 }
else if (c == QLatin1Char(
'>')) {
4150 m = MaskInputData::Upper;
4151 }
else if (c == QLatin1Char(
'!')) {
4152 m = MaskInputData::NoCaseMode;
4153 }
else if (c != QLatin1Char(
'{') && c != QLatin1Char(
'}') && c != QLatin1Char(
'[') && c != QLatin1Char(
']')) {
4154 switch (c.unicode()) {
4181 m_maskData[index].maskChar = c;
4182 m_maskData[index].separator = s;
4183 m_maskData[index].caseMode = m;
4188 internalSetText(m_text);
4193
4194
4195
4196
4197bool QQuickTextInputPrivate::isValidInput(QChar key, QChar mask)
const
4199 switch (mask.unicode()) {
4205 if (key.isLetter() || key == m_blank)
4209 if (key.isLetterOrNumber())
4213 if (key.isLetterOrNumber() || key == m_blank)
4217 if (key.isPrint() && key != m_blank)
4221 if (key.isPrint() || key == m_blank)
4229 if (key.isNumber() || key == m_blank)
4233 if (key.isNumber() && key.digitValue() > 0)
4237 if ((key.isNumber() && key.digitValue() > 0) || key == m_blank)
4241 if (key.isNumber() || key == QLatin1Char(
'+') || key == QLatin1Char(
'-') || key == m_blank)
4245 if (key == QLatin1Char(
'0') || key == QLatin1Char(
'1'))
4249 if (key == QLatin1Char(
'0') || key == QLatin1Char(
'1') || key == m_blank)
4253 if (key.isNumber() || (key >= QLatin1Char(
'a') && key <= QLatin1Char(
'f')) || (key >= QLatin1Char(
'A') && key <= QLatin1Char(
'F')))
4257 if (key.isNumber() || (key >= QLatin1Char(
'a') && key <= QLatin1Char(
'f')) || (key >= QLatin1Char(
'A') && key <= QLatin1Char(
'F')) || key == m_blank)
4267
4268
4269
4270
4271
4272
4273
4274QQuickTextInputPrivate::ValidatorState QQuickTextInputPrivate::hasAcceptableInput(
const QString &str)
const
4276#if QT_CONFIG(validator)
4277 QString textCopy = str;
4278 int cursorCopy = m_cursor;
4280 QValidator::State state = m_validator->validate(textCopy, cursorCopy);
4281 if (state != QValidator::Acceptable)
4282 return ValidatorState(state);
4287 return AcceptableInput;
4289 if (str.size() != m_maxLength)
4290 return InvalidInput;
4292 for (
int i=0; i < m_maxLength; ++i) {
4293 if (m_maskData[i].separator) {
4294 if (str.at(i) != m_maskData[i].maskChar)
4295 return InvalidInput;
4297 if (!isValidInput(str.at(i), m_maskData[i].maskChar))
4298 return InvalidInput;
4301 return AcceptableInput;
4305
4306
4307
4308
4309
4310
4311
4312QString QQuickTextInputPrivate::maskString(uint pos,
const QString &str,
bool clear)
const
4314 if (pos >= (uint)m_maxLength)
4315 return QString::fromLatin1(
"");
4318 fill = clear ? clearString(0, m_maxLength) : m_text;
4321 QString s = QString::fromLatin1(
"");
4323 while (i < m_maxLength) {
4324 if (strIndex < str.size()) {
4325 if (m_maskData[i].separator) {
4326 s += m_maskData[i].maskChar;
4327 if (str[strIndex] == m_maskData[i].maskChar)
4331 if (isValidInput(str[strIndex], m_maskData[i].maskChar)) {
4332 switch (m_maskData[i].caseMode) {
4333 case MaskInputData::Upper:
4334 s += str[strIndex].toUpper();
4336 case MaskInputData::Lower:
4337 s += str[strIndex].toLower();
4345 int n = findInMask(i,
true,
true, str[strIndex]);
4347 if (str.size() != 1 || i == 0 || (i > 0 && (!m_maskData[i-1].separator || m_maskData[i-1].maskChar != str[strIndex]))) {
4348 s += QStringView{fill}.mid(i, n-i+1);
4353 n = findInMask(i,
true,
false, str[strIndex]);
4355 s += QStringView{fill}.mid(i, n-i);
4356 switch (m_maskData[n].caseMode) {
4357 case MaskInputData::Upper:
4358 s += str[strIndex].toUpper();
4360 case MaskInputData::Lower:
4361 s += str[strIndex].toLower();
4382
4383
4384
4385
4386
4387QString QQuickTextInputPrivate::clearString(uint pos, uint len)
const
4389 if (pos >= (uint)m_maxLength)
4393 int end = qMin((uint)m_maxLength, pos + len);
4394 for (
int i = pos; i < end; ++i)
4395 if (m_maskData[i].separator)
4396 s += m_maskData[i].maskChar;
4404
4405
4406
4407
4408
4409QString QQuickTextInputPrivate::stripString(
const QString &str)
const
4415 int end = qMin(m_maxLength, str.size());
4416 for (
int i = 0; i < end; ++i) {
4417 if (m_maskData[i].separator)
4418 s += m_maskData[i].maskChar;
4419 else if (str[i] != m_blank)
4427
4428
4429
4430int QQuickTextInputPrivate::findInMask(
int pos,
bool forward,
bool findSeparator, QChar searchChar)
const
4432 if (pos >= m_maxLength || pos < 0)
4435 int end = forward ? m_maxLength : -1;
4436 int step = forward ? 1 : -1;
4440 if (findSeparator) {
4441 if (m_maskData[i].separator && m_maskData[i].maskChar == searchChar)
4444 if (!m_maskData[i].separator) {
4445 if (searchChar.isNull())
4447 else if (isValidInput(searchChar, m_maskData[i].maskChar))
4456void QQuickTextInputPrivate::internalUndo(
int until)
4458 if (!isUndoAvailable())
4460 cancelPasswordEchoTimer();
4462 while (m_undoState && m_undoState > until) {
4463 Command& cmd = m_history[--m_undoState];
4466 m_text.remove(cmd.pos, 1);
4470 m_selstart = cmd.selStart;
4471 m_selend = cmd.selEnd;
4475 case RemoveSelection:
4476 m_text.insert(cmd.pos, cmd.uc);
4477 m_cursor = cmd.pos + 1;
4480 case DeleteSelection:
4481 m_text.insert(cmd.pos, cmd.uc);
4487 if (until < 0 && m_undoState) {
4488 Command& next = m_history[m_undoState-1];
4489 if (next.type != cmd.type
4490 && next.type < RemoveSelection
4491 && (cmd.type < RemoveSelection || next.type == Separator)) {
4500void QQuickTextInputPrivate::internalRedo()
4502 if (!isRedoAvailable())
4505 while (m_undoState < m_history.size()) {
4506 Command& cmd = m_history[m_undoState++];
4509 m_text.insert(cmd.pos, cmd.uc);
4510 m_cursor = cmd.pos + 1;
4513 m_selstart = cmd.selStart;
4514 m_selend = cmd.selEnd;
4519 case RemoveSelection:
4520 case DeleteSelection:
4521 m_text.remove(cmd.pos, 1);
4522 m_selstart = cmd.selStart;
4523 m_selend = cmd.selEnd;
4527 m_selstart = cmd.selStart;
4528 m_selend = cmd.selEnd;
4532 if (m_undoState < m_history.size()) {
4533 Command& next = m_history[m_undoState];
4534 if (next.type != cmd.type
4535 && cmd.type < RemoveSelection
4536 && next.type != Separator
4537 && (next.type < RemoveSelection || cmd.type == Separator)) {
4545void QQuickTextInputPrivate::emitUndoRedoChanged()
4547 Q_Q(QQuickTextInput);
4548 const bool previousUndo = canUndo;
4549 const bool previousRedo = canRedo;
4551 canUndo = isUndoAvailable();
4552 canRedo = isRedoAvailable();
4554 if (previousUndo != canUndo)
4555 emit q->canUndoChanged();
4556 if (previousRedo != canRedo)
4557 emit q->canRedoChanged();
4561
4562
4563
4564
4565
4566bool QQuickTextInputPrivate::emitCursorPositionChanged()
4568 Q_Q(QQuickTextInput);
4569 if (m_cursor != m_lastCursorPos) {
4570 m_lastCursorPos = m_cursor;
4572 q->updateCursorRectangle();
4573 emit q->cursorPositionChanged();
4575 if (!hasSelectedText()) {
4576 if (lastSelectionStart != m_cursor) {
4577 lastSelectionStart = m_cursor;
4578 emit q->selectionStartChanged();
4580 if (lastSelectionEnd != m_cursor) {
4581 lastSelectionEnd = m_cursor;
4582 emit q->selectionEndChanged();
4586#if QT_CONFIG(accessibility)
4587 if (QAccessible::isActive()) {
4588 if (QObject *acc = QQuickAccessibleAttached::findAccessible(q, QAccessible::EditableText)) {
4589 QAccessibleTextCursorEvent ev(acc, m_cursor);
4590 QAccessible::updateAccessibility(&ev);
4601void QQuickTextInputPrivate::setBlinkingCursorEnabled(
bool enable)
4603 if (enable == m_blinkEnabled)
4606 m_blinkEnabled = enable;
4607 updateCursorBlinking();
4610 connect(qApp->styleHints(), &QStyleHints::cursorFlashTimeChanged,
this, &QQuickTextInputPrivate::updateCursorBlinking);
4612 disconnect(qApp->styleHints(), &QStyleHints::cursorFlashTimeChanged,
this, &QQuickTextInputPrivate::updateCursorBlinking);
4615void QQuickTextInputPrivate::updateCursorBlinking()
4617 Q_Q(QQuickTextInput);
4620 q->killTimer(m_blinkTimer);
4624 if (m_blinkEnabled && cursorVisible && !cursorItem && !m_readOnly) {
4625 int flashTime = QGuiApplication::styleHints()->cursorFlashTime();
4627 m_blinkTimer = q->startTimer(flashTime / 2);
4631 updateType = UpdatePaintNode;
4636void QQuickTextInput::timerEvent(QTimerEvent *event)
4638 Q_D(QQuickTextInput);
4639 if (event->timerId() == d->m_blinkTimer) {
4640 d->m_blinkStatus = !d->m_blinkStatus;
4641 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
4644 }
else if (event->timerId() == d->m_passwordEchoTimer.timerId()) {
4645 d->m_passwordEchoTimer.stop();
4646 d->updateDisplayText();
4647 updateCursorRectangle();
4651void QQuickTextInputPrivate::processKeyEvent(QKeyEvent* event)
4653 Q_Q(QQuickTextInput);
4655 if (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return) {
4656 if (hasAcceptableInput(m_text) == AcceptableInput || fixup()) {
4658 QInputMethod *inputMethod = QGuiApplication::inputMethod();
4659 inputMethod->commit();
4664 emit q->editingFinished();
4674 updateCursorBlinking();
4676 if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit
4677 && !m_passwordEchoEditing
4679 && !event->text().isEmpty()
4680 && !(event->modifiers() & Qt::ControlModifier)) {
4686 updatePasswordEchoEditing(
true);
4690 bool unknown =
false;
4691#if QT_CONFIG(shortcut)
4692 bool visual = cursorMoveStyle() == Qt::VisualMoveStyle;
4697#if QT_CONFIG(shortcut)
4698 else if (event == QKeySequence::Undo) {
4701 else if (event == QKeySequence::Redo) {
4704 else if (event == QKeySequence::SelectAll) {
4707#if QT_CONFIG(clipboard)
4708 else if (event == QKeySequence::Copy) {
4711 else if (event == QKeySequence::Paste) {
4713 QClipboard::Mode mode = QClipboard::Clipboard;
4717 else if (event == QKeySequence::Cut) {
4720 else if (event == QKeySequence::DeleteEndOfLine) {
4725 else if (event == QKeySequence::MoveToStartOfLine || event == QKeySequence::MoveToStartOfBlock) {
4728 else if (event == QKeySequence::MoveToEndOfLine || event == QKeySequence::MoveToEndOfBlock) {
4731 else if (event == QKeySequence::SelectStartOfLine || event == QKeySequence::SelectStartOfBlock) {
4734 else if (event == QKeySequence::SelectEndOfLine || event == QKeySequence::SelectEndOfBlock) {
4737 else if (event == QKeySequence::MoveToNextChar) {
4738 if (hasSelectedText()) {
4739 moveCursor(selectionEnd(),
false);
4741 cursorForward(0, visual ? 1 : (layoutDirection() == Qt::LeftToRight ? 1 : -1));
4744 else if (event == QKeySequence::SelectNextChar) {
4745 cursorForward(1, visual ? 1 : (layoutDirection() == Qt::LeftToRight ? 1 : -1));
4747 else if (event == QKeySequence::MoveToPreviousChar) {
4748 if (hasSelectedText()) {
4749 moveCursor(selectionStart(),
false);
4751 cursorForward(0, visual ? -1 : (layoutDirection() == Qt::LeftToRight ? -1 : 1));
4754 else if (event == QKeySequence::SelectPreviousChar) {
4755 cursorForward(1, visual ? -1 : (layoutDirection() == Qt::LeftToRight ? -1 : 1));
4757 else if (event == QKeySequence::MoveToNextWord) {
4758 if (m_echoMode == QQuickTextInput::Normal)
4759 layoutDirection() == Qt::LeftToRight ? cursorWordForward(0) : cursorWordBackward(0);
4761 layoutDirection() == Qt::LeftToRight ? end(0) : home(0);
4763 else if (event == QKeySequence::MoveToPreviousWord) {
4764 if (m_echoMode == QQuickTextInput::Normal)
4765 layoutDirection() == Qt::LeftToRight ? cursorWordBackward(0) : cursorWordForward(0);
4766 else if (!m_readOnly) {
4767 layoutDirection() == Qt::LeftToRight ? home(0) : end(0);
4770 else if (event == QKeySequence::SelectNextWord) {
4771 if (m_echoMode == QQuickTextInput::Normal)
4772 layoutDirection() == Qt::LeftToRight ? cursorWordForward(1) : cursorWordBackward(1);
4774 layoutDirection() == Qt::LeftToRight ? end(1) : home(1);
4776 else if (event == QKeySequence::SelectPreviousWord) {
4777 if (m_echoMode == QQuickTextInput::Normal)
4778 layoutDirection() == Qt::LeftToRight ? cursorWordBackward(1) : cursorWordForward(1);
4780 layoutDirection() == Qt::LeftToRight ? home(1) : end(1);
4782 else if (event == QKeySequence::Delete) {
4786 else if (event == QKeySequence::DeleteEndOfWord) {
4790 else if (event == QKeySequence::DeleteStartOfWord) {
4792 deleteStartOfWord();
4793 }
else if (event == QKeySequence::DeleteCompleteLine) {
4796#if QT_CONFIG(clipboard)
4804 bool handled =
false;
4805 if (event->modifiers() & Qt::ControlModifier) {
4806 switch (event->key()) {
4807 case Qt::Key_Backspace:
4809 deleteStartOfWord();
4816 switch (event->key()) {
4817 case Qt::Key_Backspace:
4829 if (event->key() == Qt::Key_Direction_L || event->key() == Qt::Key_Direction_R) {
4830 setLayoutDirection((event->key() == Qt::Key_Direction_L) ? Qt::LeftToRight : Qt::RightToLeft);
4834 if (unknown && !m_readOnly) {
4835 if (m_inputControl->isAcceptableInput(event)) {
4839 && !hasSelectedText()
4840 && !(m_cursor == q_func()->text().size())) {
4844 insert(event->text());
4857
4858
4859
4860
4862void QQuickTextInputPrivate::deleteStartOfWord()
4864 int priorState = m_undoState;
4866 if (!separateSelection()) {
4867 Command cmd(SetSelection, m_cursor, u'\0', m_selstart, m_selend);
4869 cursorWordBackward(
true);
4873 removeSelectedText();
4874 finishChange(priorState);
4878
4879
4880
4881
4883void QQuickTextInputPrivate::deleteEndOfWord()
4885 int priorState = m_undoState;
4886 Command cmd(SetSelection, m_cursor, u'\0', m_selstart, m_selend);
4888 cursorWordForward(
true);
4892 removeSelectedText();
4893 finishChange(priorState);
4897
4898
4899
4900
4902void QQuickTextInputPrivate::deleteEndOfLine()
4904 int priorState = m_undoState;
4905 Command cmd(SetSelection, m_cursor, u'\0', m_selstart, m_selend);
4907 setSelection(m_cursor, end());
4909 removeSelectedText();
4910 finishChange(priorState);
4914
4915
4916
4917
4918
4919
4920
4921
4922void QQuickTextInput::ensureVisible(
int position)
4924 Q_D(QQuickTextInput);
4925 d->ensureVisible(position);
4926 updateCursorRectangle(
false);
4930
4931
4932
4933
4934
4935
4936
4937
4938
4939
4940void QQuickTextInput::clear()
4942 Q_D(QQuickTextInput);
4948
4949
4950
4951
4952
4953
4954
4955
4956
4957
4958
4959
4960
4961
4962
4963
4964
4965
4966
4967
4968
4969
4970qreal QQuickTextInput::padding()
const
4972 Q_D(
const QQuickTextInput);
4973 return d->padding();
4976void QQuickTextInput::setPadding(qreal padding)
4978 Q_D(QQuickTextInput);
4979 if (qFuzzyCompare(d->padding(), padding))
4982 d->extra.value().padding = padding;
4984 updateCursorRectangle();
4985 emit paddingChanged();
4986 if (!d->extra.isAllocated() || !d->extra->explicitTopPadding)
4987 emit topPaddingChanged();
4988 if (!d->extra.isAllocated() || !d->extra->explicitLeftPadding)
4989 emit leftPaddingChanged();
4990 if (!d->extra.isAllocated() || !d->extra->explicitRightPadding)
4991 emit rightPaddingChanged();
4992 if (!d->extra.isAllocated() || !d->extra->explicitBottomPadding)
4993 emit bottomPaddingChanged();
4996void QQuickTextInput::resetPadding()
5001qreal QQuickTextInput::topPadding()
const
5003 Q_D(
const QQuickTextInput);
5004 if (d->extra.isAllocated() && d->extra->explicitTopPadding)
5005 return d->extra->topPadding;
5006 return d->padding();
5009void QQuickTextInput::setTopPadding(qreal padding)
5011 Q_D(QQuickTextInput);
5012 d->setTopPadding(padding);
5015void QQuickTextInput::resetTopPadding()
5017 Q_D(QQuickTextInput);
5018 d->setTopPadding(0,
true);
5021qreal QQuickTextInput::leftPadding()
const
5023 Q_D(
const QQuickTextInput);
5024 if (d->extra.isAllocated() && d->extra->explicitLeftPadding)
5025 return d->extra->leftPadding;
5026 return d->padding();
5029void QQuickTextInput::setLeftPadding(qreal padding)
5031 Q_D(QQuickTextInput);
5032 d->setLeftPadding(padding);
5035void QQuickTextInput::resetLeftPadding()
5037 Q_D(QQuickTextInput);
5038 d->setLeftPadding(0,
true);
5041qreal QQuickTextInput::rightPadding()
const
5043 Q_D(
const QQuickTextInput);
5044 if (d->extra.isAllocated() && d->extra->explicitRightPadding)
5045 return d->extra->rightPadding;
5046 return d->padding();
5049void QQuickTextInput::setRightPadding(qreal padding)
5051 Q_D(QQuickTextInput);
5052 d->setRightPadding(padding);
5055void QQuickTextInput::resetRightPadding()
5057 Q_D(QQuickTextInput);
5058 d->setRightPadding(0,
true);
5061qreal QQuickTextInput::bottomPadding()
const
5063 Q_D(
const QQuickTextInput);
5064 if (d->extra.isAllocated() && d->extra->explicitBottomPadding)
5065 return d->extra->bottomPadding;
5066 return d->padding();
5069void QQuickTextInput::setBottomPadding(qreal padding)
5071 Q_D(QQuickTextInput);
5072 d->setBottomPadding(padding);
5075void QQuickTextInput::resetBottomPadding()
5077 Q_D(QQuickTextInput);
5078 d->setBottomPadding(0,
true);
5081#if QT_VERSION < QT_VERSION_CHECK(7
, 0
, 0
)
5082void QQuickTextInput::setOldSelectionDefault()
5084 Q_D(QQuickTextInput);
5085 d->selectByMouse =
false;
5086 d->selectByTouchDrag =
true;
5087 qCDebug(lcQuickTextInput,
"pre-6.4 behavior chosen: selectByMouse defaults false; if enabled, touchscreen acts like a mouse");
5091QQuickPre64TextInput::QQuickPre64TextInput(QQuickItem *parent)
5092 : QQuickTextInput(parent)
5094 setOldSelectionDefault();
5100#include "moc_qquicktextinput_p.cpp"
Combined button and popup list for selecting options.