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 bool canPaste =
false;
2635 if (!d->m_readOnly) {
2636 if (
const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData())
2637 canPaste = mimeData->hasText() && !mimeData->text().isEmpty();
2639 const_cast<QQuickTextInputPrivate *>(d)->canPaste = canPaste;
2640 const_cast<QQuickTextInputPrivate *>(d)->canPasteValid =
true;
2649
2650
2651
2652
2653
2654
2656bool QQuickTextInput::canUndo()
const
2658 Q_D(
const QQuickTextInput);
2663
2664
2665
2666
2667
2668
2670bool QQuickTextInput::canRedo()
const
2672 Q_D(
const QQuickTextInput);
2677
2678
2679
2680
2681
2682
2684qreal QQuickTextInput::contentWidth()
const
2686 Q_D(
const QQuickTextInput);
2687 return d->contentSize.width();
2691
2692
2693
2694
2695
2696
2698qreal QQuickTextInput::contentHeight()
const
2700 Q_D(
const QQuickTextInput);
2701 return d->contentSize.height();
2704void QQuickTextInput::moveCursorSelection(
int position)
2706 Q_D(QQuickTextInput);
2707 d->moveCursor(position,
true);
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
2742
2743
2744
2745
2746void QQuickTextInput::moveCursorSelection(
int pos, SelectionMode mode)
2748 Q_D(QQuickTextInput);
2750 if (mode == SelectCharacters) {
2751 d->moveCursor(pos,
true);
2752 }
else if (pos != d->m_cursor) {
2753 const int cursor = d->m_cursor;
2755 if (!d->hasSelectedText())
2756 anchor = d->m_cursor;
2757 else if (d->selectionStart() == d->m_cursor)
2758 anchor = d->selectionEnd();
2760 anchor = d->selectionStart();
2762 if (anchor < pos || (anchor == pos && cursor < pos)) {
2763 const QString text =
this->text();
2764 QTextBoundaryFinder finder(QTextBoundaryFinder::Word, text);
2765 finder.setPosition(anchor);
2767 const QTextBoundaryFinder::BoundaryReasons reasons = finder.boundaryReasons();
2768 if (anchor < text.size() && (reasons == QTextBoundaryFinder::NotAtBoundary
2769 || (reasons & QTextBoundaryFinder::EndOfItem))) {
2770 finder.toPreviousBoundary();
2772 anchor = finder.position() != -1 ? finder.position() : 0;
2774 finder.setPosition(pos);
2775 if (pos > 0 && !finder.boundaryReasons())
2776 finder.toNextBoundary();
2777 const int cursor = finder.position() != -1 ? finder.position() : text.size();
2779 d->setSelection(anchor, cursor - anchor);
2780 }
else if (anchor > pos || (anchor == pos && cursor > pos)) {
2781 const QString text =
this->text();
2782 QTextBoundaryFinder finder(QTextBoundaryFinder::Word, text);
2783 finder.setPosition(anchor);
2785 const QTextBoundaryFinder::BoundaryReasons reasons = finder.boundaryReasons();
2786 if (anchor > 0 && (reasons == QTextBoundaryFinder::NotAtBoundary
2787 || (reasons & QTextBoundaryFinder::StartOfItem))) {
2788 finder.toNextBoundary();
2790 anchor = finder.position() != -1 ? finder.position() : text.size();
2792 finder.setPosition(pos);
2793 if (pos < text.size() && !finder.boundaryReasons())
2794 finder.toPreviousBoundary();
2795 const int cursor = finder.position() != -1 ? finder.position() : 0;
2797 d->setSelection(anchor, cursor - anchor);
2802void QQuickTextInput::focusInEvent(QFocusEvent *event)
2804 Q_D(QQuickTextInput);
2805 d->handleFocusEvent(event);
2806 QQuickImplicitSizeItem::focusInEvent(event);
2809void QQuickTextInputPrivate::handleFocusEvent(QFocusEvent *event)
2811 Q_Q(QQuickTextInput);
2812 bool focus = event->gotFocus();
2814 q->setCursorVisible(focus);
2815 setBlinkingCursorEnabled(focus);
2818 q->q_updateAlignment();
2820 if (focusOnPress && !m_readOnly)
2821 qGuiApp->inputMethod()->show();
2822 q->connect(QGuiApplication::inputMethod(), SIGNAL(inputDirectionChanged(Qt::LayoutDirection)),
2823 q, SLOT(q_updateAlignment()));
2826 if ((m_passwordEchoEditing || m_passwordEchoTimer.isActive())) {
2827 updatePasswordEchoEditing(
false);
2830 if (event->reason() != Qt::ActiveWindowFocusReason
2831 && event->reason() != Qt::PopupFocusReason
2832 && hasSelectedText()
2833 && !persistentSelection)
2836 if (hasAcceptableInput(m_text) == AcceptableInput || fixup())
2837 emit q->editingFinished();
2840 q->disconnect(QGuiApplication::inputMethod(), SIGNAL(inputDirectionChanged(Qt::LayoutDirection)),
2841 q, SLOT(q_updateAlignment()));
2846void QQuickTextInput::focusOutEvent(QFocusEvent *event)
2848 Q_D(QQuickTextInput);
2849 d->handleFocusEvent(event);
2850 QQuickImplicitSizeItem::focusOutEvent(event);
2853void QQuickTextInputPrivate::readOnlyChanged(
bool isReadOnly)
2855 Q_UNUSED(isReadOnly);
2856#if QT_CONFIG(accessibility)
2857 if (QQuickAccessibleAttached *accessibleAttached =
2858 QQuickAccessibleAttached::attachedProperties(q_func()))
2859 accessibleAttached->set_readOnly(isReadOnly);
2863void QQuickTextInputPrivate::echoModeChanged(QQuickTextInput::EchoMode echoMode)
2865#if QT_CONFIG(accessibility)
2866 if (!QAccessible::isActive())
2869 if (QQuickAccessibleAttached *accessibleAttached =
2870 QQuickAccessibleAttached::attachedProperties(q_func()))
2871 accessibleAttached->set_passwordEdit((echoMode == QQuickTextInput::Password
2872 || echoMode == QQuickTextInput::PasswordEchoOnEdit)
2880#if QT_CONFIG(accessibility)
2881void QQuickTextInputPrivate::accessibilityActiveChanged(
bool active)
2886 Q_Q(QQuickTextInput);
2887 QQuickAccessibleAttached *accessibleAttached = qobject_cast<QQuickAccessibleAttached *>(
2888 qmlAttachedPropertiesObject<QQuickAccessibleAttached>(q,
true));
2889 Q_ASSERT(accessibleAttached);
2890 accessibleAttached->setRole(effectiveAccessibleRole());
2891 accessibleAttached->set_readOnly(m_readOnly);
2892 accessibleAttached->set_passwordEdit((m_echoMode == QQuickTextInput::Password
2893 || m_echoMode == QQuickTextInput::PasswordEchoOnEdit)
2898QAccessible::Role QQuickTextInputPrivate::accessibleRole()
const
2900 return QAccessible::EditableText;
2905
2906
2907
2908
2909
2910
2911
2912
2913
2914
2915
2916bool QQuickTextInput::isInputMethodComposing()
const
2921 Q_D(
const QQuickTextInput);
2922 return d->hasImState;
2926QQuickTextInputPrivate::ExtraData::ExtraData()
2932 , explicitTopPadding(
false)
2933 , explicitLeftPadding(
false)
2934 , explicitRightPadding(
false)
2935 , explicitBottomPadding(
false)
2936 , implicitResize(
true)
2940void QQuickTextInputPrivate::init()
2942 Q_Q(QQuickTextInput);
2943#if QT_CONFIG(clipboard)
2944 if (QGuiApplication::clipboard()->supportsSelection())
2945 q->setAcceptedMouseButtons(Qt::LeftButton | Qt::MiddleButton);
2948 q->setAcceptedMouseButtons(Qt::LeftButton);
2951 q->setFlag(QQuickItem::ItemAcceptsInputMethod);
2953 q->setFlag(QQuickItem::ItemHasContents);
2954#if QT_CONFIG(clipboard)
2955 qmlobject_connect(QGuiApplication::clipboard(), QClipboard, SIGNAL(dataChanged()),
2956 q, QQuickTextInput, SLOT(q_canPasteChanged()));
2959 lastSelectionStart = 0;
2960 lastSelectionEnd = 0;
2961 determineHorizontalAlignment();
2963 if (!qmlDisableDistanceField()) {
2964 QTextOption option = m_textLayout.textOption();
2965 option.setUseDesignMetrics(renderType != QQuickTextInput::NativeRendering);
2966 m_textLayout.setTextOption(option);
2969 m_inputControl =
new QInputControl(QInputControl::LineEdit, q);
2970 setSizePolicy(QLayoutPolicy::Expanding, QLayoutPolicy::Fixed);
2972 QObjectPrivate::connect(q, &QQuickTextInput::readOnlyChanged,
this,
2973 &QQuickTextInputPrivate::readOnlyChanged);
2974 QObjectPrivate::connect(q, &QQuickTextInput::echoModeChanged,
this,
2975 &QQuickTextInputPrivate::echoModeChanged);
2978void QQuickTextInputPrivate::cancelInput()
2981 Q_Q(QQuickTextInput);
2982 if (!m_readOnly && q->hasActiveFocus() && qGuiApp)
2987void QQuickTextInput::updateCursorRectangle(
bool scroll)
2989 Q_D(QQuickTextInput);
2990 if (!isComponentComplete())
2994 d->updateHorizontalScroll();
2995 d->updateVerticalScroll();
2997 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
3000 emit cursorRectangleChanged();
3001 if (d->cursorItem) {
3002 QRectF r = cursorRectangle();
3003 d->cursorItem->setPosition(r.topLeft());
3004 d->cursorItem->setHeight(r.height());
3007 updateInputMethod(Qt::ImCursorRectangle | Qt::ImAnchorRectangle);
3011void QQuickTextInput::selectionChanged()
3013 Q_D(QQuickTextInput);
3014 d->textLayoutDirty =
true;
3015 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
3018 emit selectedTextChanged();
3020 if (d->lastSelectionStart != d->selectionStart()) {
3021 d->lastSelectionStart = d->selectionStart();
3022 if (d->lastSelectionStart == -1)
3023 d->lastSelectionStart = d->m_cursor;
3024 emit selectionStartChanged();
3026 if (d->lastSelectionEnd != d->selectionEnd()) {
3027 d->lastSelectionEnd = d->selectionEnd();
3028 if (d->lastSelectionEnd == -1)
3029 d->lastSelectionEnd = d->m_cursor;
3030 emit selectionEndChanged();
3034QRectF QQuickTextInput::boundingRect()
const
3036 Q_D(
const QQuickTextInput);
3038 int cursorWidth = d->cursorItem ? 0 : 1;
3040 qreal hscroll = d->hscroll;
3041 if (!d->autoScroll || d->contentSize.width() < width())
3042 hscroll -= QQuickTextUtil::alignedX(d->contentSize.width(), width(), effectiveHAlign());
3045 QRectF r(-hscroll, -d->vscroll, d->contentSize.width(), d->contentSize.height());
3046 r.setRight(r.right() + cursorWidth);
3050QRectF QQuickTextInput::clipRect()
const
3052 Q_D(
const QQuickTextInput);
3054 int cursorWidth = d->cursorItem ? d->cursorItem->width() : 1;
3057 QRectF r = QQuickImplicitSizeItem::clipRect();
3058 r.setRight(r.right() + cursorWidth);
3062void QQuickTextInput::q_canPasteChanged()
3064 Q_D(QQuickTextInput);
3065 bool old = d->canPaste;
3066#if QT_CONFIG(clipboard)
3067 bool canPaste =
false;
3068 if (!d->m_readOnly) {
3069 if (
const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData())
3070 canPaste = mimeData->hasText() && !mimeData->text().isEmpty();
3072 d->canPaste = canPaste;
3075 bool changed = d->canPaste != old || !d->canPasteValid;
3076 d->canPasteValid =
true;
3078 emit canPasteChanged();
3082void QQuickTextInput::q_updateAlignment()
3084 Q_D(QQuickTextInput);
3085 if (d->determineHorizontalAlignment()) {
3087 updateCursorRectangle();
3092
3093
3094
3095
3096
3097void QQuickTextInputPrivate::updateDisplayText(
bool forceUpdate)
3099 QString orig = m_textLayout.text();
3101 if (m_echoMode == QQuickTextInput::NoEcho)
3102 str = QString::fromLatin1(
"");
3106 if (m_echoMode == QQuickTextInput::Password) {
3107 str.fill(m_passwordCharacter);
3108 if (m_passwordEchoTimer.isActive() && m_cursor > 0 && m_cursor <= m_text.size()) {
3109 int cursor = m_cursor - 1;
3110 QChar uc = m_text.at(cursor);
3112 if (cursor > 0 && uc.unicode() >= 0xdc00 && uc.unicode() < 0xe000) {
3115 uc = m_text.at(cursor - 1);
3116 if (uc.unicode() >= 0xd800 && uc.unicode() < 0xdc00)
3117 str[cursor - 1] = uc;
3120 }
else if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit && !m_passwordEchoEditing) {
3121 str.fill(m_passwordCharacter);
3127 QChar* uc = str.data();
3128 for (
int i = 0; i < str.size(); ++i) {
3129 if (uc[i] == QChar::LineSeparator
3130 || uc[i] == QChar::ParagraphSeparator
3131 || uc[i] == QChar::ObjectReplacementCharacter)
3132 uc[i] = QChar(0x0020);
3135 if (str != orig || forceUpdate) {
3136 m_textLayout.setText(str);
3138 emit q_func()->displayTextChanged();
3142qreal QQuickTextInputPrivate::calculateImplicitWidthForText(
const QString &text)
const
3144 Q_Q(
const QQuickTextInput);
3145 QTextLayout layout(text);
3147 QTextOption option = m_textLayout.textOption();
3148 option.setTextDirection(m_layoutDirection);
3149 option.setFlags(QTextOption::IncludeTrailingSpaces);
3150 option.setWrapMode(QTextOption::WrapMode(wrapMode));
3151 option.setAlignment(Qt::Alignment(q->effectiveHAlign()));
3152 layout.setTextOption(option);
3153 layout.setFont(font);
3155 layout.setPreeditArea(m_textLayout.preeditAreaPosition(), m_textLayout.preeditAreaText());
3157 layout.beginLayout();
3159 QTextLine line = layout.createLine();
3160 line.setLineWidth(qreal(INT_MAX));
3161 const qreal theImplicitWidth = qCeil(line.naturalTextWidth()) + q->leftPadding() + q->rightPadding();
3164 return theImplicitWidth;
3167qreal QQuickTextInputPrivate::getImplicitWidth()
const
3169 Q_Q(
const QQuickTextInput);
3170 if (!requireImplicitWidth) {
3171 QQuickTextInputPrivate *d =
const_cast<QQuickTextInputPrivate *>(
this);
3172 d->requireImplicitWidth =
true;
3174 if (q->isComponentComplete())
3175 d->implicitWidth = calculateImplicitWidthForText(m_text);
3177 return implicitWidth;
3180void QQuickTextInputPrivate::setTopPadding(qreal value,
bool reset)
3182 Q_Q(QQuickTextInput);
3183 qreal oldPadding = q->topPadding();
3184 if (!reset || extra.isAllocated()) {
3185 extra.value().topPadding = value;
3186 extra.value().explicitTopPadding = !reset;
3188 if ((!reset && !qFuzzyCompare(oldPadding, value)) || (reset && !qFuzzyCompare(oldPadding, padding()))) {
3190 q->updateCursorRectangle();
3191 emit q->topPaddingChanged();
3195void QQuickTextInputPrivate::setLeftPadding(qreal value,
bool reset)
3197 Q_Q(QQuickTextInput);
3198 qreal oldPadding = q->leftPadding();
3199 if (!reset || extra.isAllocated()) {
3200 extra.value().leftPadding = value;
3201 extra.value().explicitLeftPadding = !reset;
3203 if ((!reset && !qFuzzyCompare(oldPadding, value)) || (reset && !qFuzzyCompare(oldPadding, padding()))) {
3205 q->updateCursorRectangle();
3206 emit q->leftPaddingChanged();
3210void QQuickTextInputPrivate::setRightPadding(qreal value,
bool reset)
3212 Q_Q(QQuickTextInput);
3213 qreal oldPadding = q->rightPadding();
3214 if (!reset || extra.isAllocated()) {
3215 extra.value().rightPadding = value;
3216 extra.value().explicitRightPadding = !reset;
3218 if ((!reset && !qFuzzyCompare(oldPadding, value)) || (reset && !qFuzzyCompare(oldPadding, padding()))) {
3220 q->updateCursorRectangle();
3221 emit q->rightPaddingChanged();
3225void QQuickTextInputPrivate::setBottomPadding(qreal value,
bool reset)
3227 Q_Q(QQuickTextInput);
3228 qreal oldPadding = q->bottomPadding();
3229 if (!reset || extra.isAllocated()) {
3230 extra.value().bottomPadding = value;
3231 extra.value().explicitBottomPadding = !reset;
3233 if ((!reset && !qFuzzyCompare(oldPadding, value)) || (reset && !qFuzzyCompare(oldPadding, padding()))) {
3235 q->updateCursorRectangle();
3236 emit q->bottomPaddingChanged();
3240bool QQuickTextInputPrivate::isImplicitResizeEnabled()
const
3242 return !extra.isAllocated() || extra->implicitResize;
3245void QQuickTextInputPrivate::setImplicitResizeEnabled(
bool enabled)
3248 extra.value().implicitResize =
false;
3249 else if (extra.isAllocated())
3250 extra->implicitResize =
true;
3253void QQuickTextInputPrivate::updateLayout()
3255 Q_Q(QQuickTextInput);
3257 if (!q->isComponentComplete())
3261 QTextOption option = m_textLayout.textOption();
3262 option.setTextDirection(layoutDirection());
3263 option.setWrapMode(QTextOption::WrapMode(wrapMode));
3264 option.setAlignment(Qt::Alignment(q->effectiveHAlign()));
3265 if (!qmlDisableDistanceField())
3266 option.setUseDesignMetrics(renderType != QQuickTextInput::NativeRendering);
3268 m_textLayout.setTextOption(option);
3269 m_textLayout.setFont(font);
3271 m_textLayout.beginLayout();
3273 QTextLine line = m_textLayout.createLine();
3274 if (requireImplicitWidth) {
3275 line.setLineWidth(qreal(INT_MAX));
3276 const bool wasInLayout = inLayout;
3278 if (isImplicitResizeEnabled())
3279 q->setImplicitWidth(qCeil(line.naturalTextWidth()) + q->leftPadding() + q->rightPadding());
3280 inLayout = wasInLayout;
3284 qreal lineWidth = q->widthValid() || !isImplicitResizeEnabled() ? q->width() - q->leftPadding() - q->rightPadding() : qreal(INT_MAX);
3288 line.setLineWidth(lineWidth);
3289 line.setPosition(QPointF(0, height));
3291 height += line.height();
3292 width = qMax(width, line.naturalTextWidth());
3294 line = m_textLayout.createLine();
3295 }
while (line.isValid());
3296 m_textLayout.endLayout();
3298 option.setWrapMode(QTextOption::NoWrap);
3299 m_textLayout.setTextOption(option);
3301 textLayoutDirty =
true;
3303 const QSizeF previousSize = contentSize;
3304 contentSize = QSizeF(width, height);
3306 updateType = UpdatePaintNode;
3310 if (isImplicitResizeEnabled()) {
3311 if (!requireImplicitWidth && !q->widthValid())
3312 q->setImplicitSize(width + q->leftPadding() + q->rightPadding(), height + q->topPadding() + q->bottomPadding());
3314 q->setImplicitHeight(height + q->topPadding() + q->bottomPadding());
3317 updateBaselineOffset();
3319 if (previousSize != contentSize)
3320 emit q->contentSizeChanged();
3324
3325
3326
3327
3328
3329void QQuickTextInputPrivate::updateBaselineOffset()
3331 Q_Q(QQuickTextInput);
3332 if (!q->isComponentComplete())
3334 QFontMetricsF fm(font);
3336 if (q->heightValid()) {
3337 const qreal surplusHeight = q->height() - contentSize.height() - q->topPadding() - q->bottomPadding();
3338 if (vAlign == QQuickTextInput::AlignBottom)
3339 yoff = surplusHeight;
3340 else if (vAlign == QQuickTextInput::AlignVCenter)
3341 yoff = surplusHeight/2;
3343 q->setBaselineOffset(fm.ascent() + yoff + q->topPadding());
3346#if QT_CONFIG(clipboard)
3348
3349
3350
3351
3352
3353
3354
3355
3356
3357void QQuickTextInputPrivate::copy(QClipboard::Mode mode)
const
3359 QString t = selectedText();
3360 if (!t.isEmpty() && m_echoMode == QQuickTextInput::Normal) {
3361 QGuiApplication::clipboard()->setText(t, mode);
3366
3367
3368
3369
3370
3371
3372
3373void QQuickTextInputPrivate::paste(QClipboard::Mode clipboardMode)
3375 QString clip = QGuiApplication::clipboard()->text(clipboardMode);
3376 if (!clip.isEmpty() || hasSelectedText()) {
3387
3388
3389void QQuickTextInputPrivate::commitPreedit()
3391 Q_Q(QQuickTextInput);
3396 QGuiApplication::inputMethod()->commit();
3401 QInputMethodEvent ev;
3402 QCoreApplication::sendEvent(q, &ev);
3405void QQuickTextInputPrivate::cancelPreedit()
3407 Q_Q(QQuickTextInput);
3412 QGuiApplication::inputMethod()->reset();
3414 QInputMethodEvent ev;
3415 QCoreApplication::sendEvent(q, &ev);
3420
3421
3422
3423
3424
3425
3426
3427
3428void QQuickTextInputPrivate::backspace()
3430 int priorState = m_undoState;
3431 if (separateSelection()) {
3432 removeSelectedText();
3433 }
else if (m_cursor) {
3436 m_cursor = prevMaskBlank(m_cursor);
3437 QChar uc = m_text.at(m_cursor);
3438 if (m_cursor > 0 && uc.unicode() >= 0xdc00 && uc.unicode() < 0xe000) {
3441 uc = m_text.at(m_cursor - 1);
3442 if (uc.unicode() >= 0xd800 && uc.unicode() < 0xdc00) {
3443 internalDelete(
true);
3447 internalDelete(
true);
3449 finishChange(priorState);
3453
3454
3455
3456
3457
3458
3459
3460
3461void QQuickTextInputPrivate::del()
3463 int priorState = m_undoState;
3464 if (separateSelection()) {
3465 removeSelectedText();
3467 int n = m_textLayout.nextCursorPosition(m_cursor) - m_cursor;
3471 finishChange(priorState);
3475
3476
3477
3478
3479
3480
3481void QQuickTextInputPrivate::insert(
const QString &newText)
3483 int priorState = m_undoState;
3484 if (separateSelection())
3485 removeSelectedText();
3486 internalInsert(newText);
3487 finishChange(priorState);
3491
3492
3493
3494
3495void QQuickTextInputPrivate::clear()
3497 int priorState = m_undoState;
3498 separateSelection();
3500 m_selend = m_text.size();
3501 removeSelectedText();
3503 finishChange(priorState,
false,
false);
3507
3508
3509
3510
3511
3512
3513
3514void QQuickTextInputPrivate::setSelection(
int start,
int length)
3516 Q_Q(QQuickTextInput);
3521 if (start < 0 || start > m_text.size()) {
3522 qWarning(
"QQuickTextInputPrivate::setSelection: Invalid start position");
3527 if (start == m_selstart && start + length == m_selend && m_cursor == m_selend)
3530 m_selend = qMin(start + length, m_text.size());
3531 m_cursor = m_selend;
3532 }
else if (length < 0) {
3533 if (start == m_selend && start + length == m_selstart && m_cursor == m_selstart)
3535 m_selstart = qMax(start + length, 0);
3537 m_cursor = m_selstart;
3538 }
else if (m_selstart != m_selend) {
3544 emitCursorPositionChanged();
3547 emit q->selectionChanged();
3548 emitCursorPositionChanged();
3550 q->updateInputMethod(Qt::ImCursorRectangle | Qt::ImAnchorRectangle | Qt::ImCursorPosition | Qt::ImAnchorPosition
3551 | Qt::ImCurrentSelection);
3556
3557
3558
3559
3560
3561
3562
3563void QQuickTextInputPrivate::updatePasswordEchoEditing(
bool editing)
3565 cancelPasswordEchoTimer();
3566 m_passwordEchoEditing = editing;
3567 updateDisplayText();
3571
3572
3573
3574
3575
3576
3577bool QQuickTextInputPrivate::fixup()
3579#if QT_CONFIG(validator)
3581 QString textCopy = m_text;
3582 int cursorCopy = m_cursor;
3583 m_validator->fixup(textCopy);
3584 if (m_validator->validate(textCopy, cursorCopy) == QValidator::Acceptable) {
3585 if (textCopy != m_text || cursorCopy != m_cursor)
3586 internalSetText(textCopy, cursorCopy);
3595
3596
3597
3598
3599
3600void QQuickTextInputPrivate::moveCursor(
int pos,
bool mark)
3602 Q_Q(QQuickTextInput);
3607 if (pos != m_cursor) {
3610 pos = pos > m_cursor ? nextMaskBlank(pos) : prevMaskBlank(pos);
3614 if (m_selend > m_selstart && m_cursor == m_selstart)
3616 else if (m_selend > m_selstart && m_cursor == m_selend)
3617 anchor = m_selstart;
3620 m_selstart = qMin(anchor, pos);
3621 m_selend = qMax(anchor, pos);
3626 if (mark || m_selDirty) {
3628 emit q->selectionChanged();
3630 emitCursorPositionChanged();
3632 q->updateInputMethod();
3638
3639
3640
3641
3642
3643void QQuickTextInputPrivate::processInputMethodEvent(QInputMethodEvent *event)
3645 Q_Q(QQuickTextInput);
3647 int priorState = -1;
3648 bool isGettingInput = !event->commitString().isEmpty()
3649 || event->preeditString() != preeditAreaText()
3650 || event->replacementLength() > 0;
3651 bool cursorPositionChanged =
false;
3652 bool selectionChange =
false;
3653 m_preeditDirty = event->preeditString() != preeditAreaText();
3655 if (isGettingInput) {
3657 priorState = m_undoState;
3658 separateSelection();
3659 if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit && !m_passwordEchoEditing) {
3660 updatePasswordEchoEditing(
true);
3662 m_selend = m_text.size();
3664 removeSelectedText();
3668 if (event->replacementStart() <= 0)
3669 c += event->commitString().size() - qMin(-event->replacementStart(), event->replacementLength());
3671 int cursorInsertPos = m_cursor + event->replacementStart();
3672 if (cursorInsertPos < 0)
3673 cursorInsertPos = 0;
3676 if (event->replacementLength()) {
3677 m_selstart = cursorInsertPos;
3678 m_selend = m_selstart + event->replacementLength();
3679 m_selend = qMin(m_selend, m_text.size());
3680 removeSelectedText();
3682 m_cursor = cursorInsertPos;
3684 if (!event->commitString().isEmpty()) {
3685 internalInsert(event->commitString());
3686 cursorPositionChanged =
true;
3688 m_cursor = qBound(0, c, m_text.size());
3691 for (
int i = 0; i < event->attributes().size(); ++i) {
3692 const QInputMethodEvent::Attribute &a = event->attributes().at(i);
3693 if (a.type == QInputMethodEvent::Selection) {
3700 if (!cursorPositionChanged || !m_maskData)
3701 m_cursor = qBound(0, a.start + a.length, m_text.size());
3703 m_selstart = qMax(0, qMin(a.start, m_text.size()));
3704 m_selend = m_cursor;
3705 if (m_selend < m_selstart) {
3706 qSwap(m_selstart, m_selend);
3708 selectionChange =
true;
3710 selectionChange = m_selstart != m_selend;
3711 m_selstart = m_selend = 0;
3713 cursorPositionChanged =
true;
3716 QString oldPreeditString = m_textLayout.preeditAreaText();
3717 m_textLayout.setPreeditArea(m_cursor, event->preeditString());
3718 if (oldPreeditString != m_textLayout.preeditAreaText()) {
3719 emit q->preeditTextChanged();
3720 if (!event->preeditString().isEmpty() && m_undoPreeditState == -1)
3722 m_undoPreeditState = priorState;
3724 const int oldPreeditCursor = m_preeditCursor;
3725 m_preeditCursor = event->preeditString().size();
3726 hasImState = !event->preeditString().isEmpty();
3727 bool cursorVisible =
true;
3728 QList<QTextLayout::FormatRange> formats;
3729 for (
int i = 0; i < event->attributes().size(); ++i) {
3730 const QInputMethodEvent::Attribute &a = event->attributes().at(i);
3731 if (a.type == QInputMethodEvent::Cursor) {
3733 m_preeditCursor = a.start;
3734 cursorVisible = a.length != 0;
3735 }
else if (a.type == QInputMethodEvent::TextFormat) {
3737 QTextCharFormat f = qvariant_cast<QTextFormat>(a.value).toCharFormat();
3739 QTextLayout::FormatRange o;
3740 o.start = a.start + m_cursor;
3741 o.length = a.length;
3747 m_textLayout.setFormats(formats);
3753 q->setCursorVisible(cursorVisible);
3755 updateDisplayText(
true);
3756 if (cursorPositionChanged && emitCursorPositionChanged())
3757 q->updateInputMethod(Qt::ImCursorPosition | Qt::ImAnchorPosition);
3758 else if (m_preeditCursor != oldPreeditCursor || isGettingInput)
3759 q->updateCursorRectangle();
3762 finishChange(priorState);
3764 if (selectionChange) {
3765 emit q->selectionChanged();
3766 q->updateInputMethod(Qt::ImCursorRectangle | Qt::ImAnchorRectangle
3767 | Qt::ImCurrentSelection);
3771 if (event->preeditString().isEmpty())
3772 m_undoPreeditState = -1;
3778
3779
3780
3781
3782
3783
3784void QQuickTextInputPrivate::selectWordAtPos(
int cursor)
3786 int next = cursor + 1;
3789 int c = m_textLayout.previousCursorPosition(next, QTextLayout::SkipWords);
3790 moveCursor(c,
false);
3792 int end = m_textLayout.nextCursorPosition(c, QTextLayout::SkipWords);
3793 while (end > cursor && m_text.at(end - 1).isSpace())
3795 moveCursor(end,
true);
3799
3800
3801
3802
3803
3804
3805
3806
3807
3808
3809
3810bool QQuickTextInputPrivate::finishChange(
int validateFromState,
bool update,
bool edited)
3812 Q_Q(QQuickTextInput);
3816 bool inputMethodAttributesChanged = m_textDirty || m_selDirty;
3818 bool alignmentChanged =
false;
3819 bool textChanged =
false;
3823 bool wasValidInput = m_validInput;
3824 bool wasAcceptable = m_acceptableInput;
3825 m_validInput =
true;
3826 m_acceptableInput =
true;
3827#if QT_CONFIG(validator)
3829 QString textCopy = m_text;
3831 textCopy = maskString(0, m_text,
true);
3832 int cursorCopy = m_cursor;
3833 QValidator::State state = m_validator->validate(textCopy, cursorCopy);
3836 m_validInput = state != QValidator::Invalid;
3837 m_acceptableInput = state == QValidator::Acceptable;
3838 if (m_validInput && !m_maskData) {
3839 if (m_text != textCopy) {
3840 internalSetText(textCopy, cursorCopy);
3843 m_cursor = cursorCopy;
3853 if (m_undoPreeditState >= 0 && (m_undoPreeditState < validateFromState || validateFromState < 0))
3854 validateFromState = m_undoPreeditState;
3856 if (validateFromState >= 0 && wasValidInput && !m_validInput) {
3857 if (m_transactions.size())
3859 internalUndo(validateFromState);
3860 m_history.resize(m_undoState);
3861 m_validInput =
true;
3862 m_acceptableInput = wasAcceptable;
3863 m_textDirty =
false;
3868 m_textDirty =
false;
3870 m_preeditDirty =
false;
3872 alignmentChanged = determineHorizontalAlignment();
3874 emit q->textEdited();
3875 emit q->textChanged();
3878 updateDisplayText(alignmentChanged);
3880 if (m_acceptableInput != wasAcceptable)
3881 emit q->acceptableInputChanged();
3884 if (m_preeditDirty) {
3885 m_preeditDirty =
false;
3886 if (determineHorizontalAlignment()) {
3887 alignmentChanged =
true;
3895 emit q->selectionChanged();
3899 inputMethodAttributesChanged |= (m_cursor != m_lastCursorPos);
3900 if (inputMethodAttributesChanged)
3901 q->updateInputMethod();
3903 emitUndoRedoChanged();
3905 if (!emitCursorPositionChanged() && (alignmentChanged || textChanged))
3906 q->updateCursorRectangle();
3912
3913
3914
3915
3916void QQuickTextInputPrivate::internalSetText(
const QString &txt,
int pos,
bool edited)
3919 QString oldText = m_text;
3921 m_text = maskString(0, txt,
true);
3922 m_text += clearString(m_text.size(), m_maxLength - m_text.size());
3924 m_text = txt.isEmpty() ? txt : txt.left(m_maxLength);
3929 m_undoPreeditState = -1;
3931 m_cursor = (pos < 0 || pos > m_text.size()) ? m_text.size() : pos;
3932 m_textDirty = (oldText != m_text);
3934 bool changed = finishChange(-1,
true, edited);
3935#if !QT_CONFIG(accessibility)
3938 Q_Q(QQuickTextInput);
3939 if (changed && QAccessible::isActive()) {
3940 if (QObject *acc = QQuickAccessibleAttached::findAccessible(q, QAccessible::EditableText)) {
3941 QAccessibleTextUpdateEvent ev(acc, 0, oldText, m_text);
3942 QAccessible::updateAccessibility(&ev);
3950
3951
3952
3953
3954
3955void QQuickTextInputPrivate::addCommand(
const Command &cmd)
3957 if (m_separator && m_undoState && m_history[m_undoState - 1].type != Separator) {
3958 m_history.resize(m_undoState + 2);
3959 m_history[m_undoState++] = Command(Separator, m_cursor, u'\0', m_selstart, m_selend);
3961 m_history.resize(m_undoState + 1);
3963 m_separator =
false;
3964 m_history[m_undoState++] = cmd;
3968
3969
3970
3971
3972
3973
3974
3975
3976
3977void QQuickTextInputPrivate::internalInsert(
const QString &s)
3979 Q_Q(QQuickTextInput);
3980 if (m_echoMode == QQuickTextInput::Password) {
3981 if (m_passwordMaskDelay > 0)
3982 m_passwordEchoTimer.start(m_passwordMaskDelay, q);
3984 Q_ASSERT(!hasSelectedText());
3986 QString ms = maskString(m_cursor, s);
3987 for (
int i = 0; i < ms.size(); ++i) {
3988 addCommand (Command(DeleteSelection, m_cursor + i, m_text.at(m_cursor + i), -1, -1));
3989 addCommand(Command(Insert, m_cursor + i, ms.at(i), -1, -1));
3991 m_text.replace(m_cursor, ms.size(), ms);
3992 m_cursor += ms.size();
3993 m_cursor = nextMaskBlank(m_cursor);
3996 int remaining = m_maxLength - m_text.size();
3997 if (remaining != 0) {
3998 const QStringView remainingStr = QStringView{s}.left(remaining);
3999 m_text.insert(m_cursor, remainingStr);
4000 for (
auto e : remainingStr)
4001 addCommand(Command(Insert, m_cursor++, e, -1, -1));
4008
4009
4010
4011
4012
4013
4014
4015
4016
4017
4018void QQuickTextInputPrivate::internalDelete(
bool wasBackspace)
4020 if (m_cursor < m_text.size()) {
4021 cancelPasswordEchoTimer();
4022 Q_ASSERT(!hasSelectedText());
4023 addCommand(Command((CommandType)((m_maskData ? 2 : 0) + (wasBackspace ? Remove : Delete)),
4024 m_cursor, m_text.at(m_cursor), -1, -1));
4026 m_text.replace(m_cursor, 1, clearString(m_cursor, 1));
4027 addCommand(Command(Insert, m_cursor, m_text.at(m_cursor), -1, -1));
4029 m_text.remove(m_cursor, 1);
4036
4037
4038
4039
4040
4041
4042
4043
4044void QQuickTextInputPrivate::removeSelectedText()
4046 if (m_selstart < m_selend && m_selend <= m_text.size()) {
4047 cancelPasswordEchoTimer();
4049 if (m_selstart <= m_cursor && m_cursor < m_selend) {
4052 for (i = m_cursor; i >= m_selstart; --i)
4053 addCommand (Command(DeleteSelection, i, m_text.at(i), -1, 1));
4054 for (i = m_selend - 1; i > m_cursor; --i)
4055 addCommand (Command(DeleteSelection, i - m_cursor + m_selstart - 1, m_text.at(i), -1, -1));
4057 for (i = m_selend-1; i >= m_selstart; --i)
4058 addCommand (Command(RemoveSelection, i, m_text.at(i), -1, -1));
4061 m_text.replace(m_selstart, m_selend - m_selstart, clearString(m_selstart, m_selend - m_selstart));
4062 for (
int i = 0; i < m_selend - m_selstart; ++i)
4063 addCommand(Command(Insert, m_selstart + i, m_text.at(m_selstart + i), -1, -1));
4065 m_text.remove(m_selstart, m_selend - m_selstart);
4067 if (m_cursor > m_selstart)
4068 m_cursor -= qMin(m_cursor, m_selend) - m_selstart;
4075
4076
4077
4078
4079
4080
4082bool QQuickTextInputPrivate::separateSelection()
4084 if (hasSelectedText()) {
4086 addCommand(Command(SetSelection, m_cursor, u'\0', m_selstart, m_selend));
4094
4095
4096
4097
4098
4099void QQuickTextInputPrivate::parseInputMask(
const QString &maskFields)
4101 int delimiter = maskFields.indexOf(QLatin1Char(
';'));
4102 if (maskFields.isEmpty() || delimiter == 0) {
4104 m_maskData.reset(
nullptr);
4105 m_maxLength = 32767;
4106 internalSetText(QString());
4111 if (delimiter == -1) {
4112 m_blank = QLatin1Char(
' ');
4113 m_inputMask = maskFields;
4115 m_inputMask = maskFields.left(delimiter);
4116 m_blank = (delimiter + 1 < maskFields.size()) ? maskFields[delimiter + 1] : QLatin1Char(
' ');
4122 for (
int i=0; i<m_inputMask.size(); i++) {
4123 c = m_inputMask.at(i);
4124 if (i > 0 && m_inputMask.at(i-1) == QLatin1Char(
'\\')) {
4128 if (c != QLatin1Char(
'\\') && c != QLatin1Char(
'!') &&
4129 c != QLatin1Char(
'<') && c != QLatin1Char(
'>') &&
4130 c != QLatin1Char(
'{') && c != QLatin1Char(
'}') &&
4131 c != QLatin1Char(
'[') && c != QLatin1Char(
']'))
4135 m_maskData.reset(
new MaskInputData[m_maxLength]);
4137 MaskInputData::Casemode m = MaskInputData::NoCaseMode;
4140 bool escape =
false;
4142 for (
int i = 0; i < m_inputMask.size(); i++) {
4143 c = m_inputMask.at(i);
4146 m_maskData[index].maskChar = c;
4147 m_maskData[index].separator = s;
4148 m_maskData[index].caseMode = m;
4151 }
else if (c == QLatin1Char(
'<')) {
4152 m = MaskInputData::Lower;
4153 }
else if (c == QLatin1Char(
'>')) {
4154 m = MaskInputData::Upper;
4155 }
else if (c == QLatin1Char(
'!')) {
4156 m = MaskInputData::NoCaseMode;
4157 }
else if (c != QLatin1Char(
'{') && c != QLatin1Char(
'}') && c != QLatin1Char(
'[') && c != QLatin1Char(
']')) {
4158 switch (c.unicode()) {
4185 m_maskData[index].maskChar = c;
4186 m_maskData[index].separator = s;
4187 m_maskData[index].caseMode = m;
4192 internalSetText(m_text);
4197
4198
4199
4200
4201bool QQuickTextInputPrivate::isValidInput(QChar key, QChar mask)
const
4203 switch (mask.unicode()) {
4209 if (key.isLetter() || key == m_blank)
4213 if (key.isLetterOrNumber())
4217 if (key.isLetterOrNumber() || key == m_blank)
4221 if (key.isPrint() && key != m_blank)
4225 if (key.isPrint() || key == m_blank)
4233 if (key.isNumber() || key == m_blank)
4237 if (key.isNumber() && key.digitValue() > 0)
4241 if ((key.isNumber() && key.digitValue() > 0) || key == m_blank)
4245 if (key.isNumber() || key == QLatin1Char(
'+') || key == QLatin1Char(
'-') || key == m_blank)
4249 if (key == QLatin1Char(
'0') || key == QLatin1Char(
'1'))
4253 if (key == QLatin1Char(
'0') || key == QLatin1Char(
'1') || key == m_blank)
4257 if (key.isNumber() || (key >= QLatin1Char(
'a') && key <= QLatin1Char(
'f')) || (key >= QLatin1Char(
'A') && key <= QLatin1Char(
'F')))
4261 if (key.isNumber() || (key >= QLatin1Char(
'a') && key <= QLatin1Char(
'f')) || (key >= QLatin1Char(
'A') && key <= QLatin1Char(
'F')) || key == m_blank)
4271
4272
4273
4274
4275
4276
4277
4278QQuickTextInputPrivate::ValidatorState QQuickTextInputPrivate::hasAcceptableInput(
const QString &str)
const
4280#if QT_CONFIG(validator)
4281 QString textCopy = str;
4282 int cursorCopy = m_cursor;
4284 QValidator::State state = m_validator->validate(textCopy, cursorCopy);
4285 if (state != QValidator::Acceptable)
4286 return ValidatorState(state);
4291 return AcceptableInput;
4293 if (str.size() != m_maxLength)
4294 return InvalidInput;
4296 for (
int i=0; i < m_maxLength; ++i) {
4297 if (m_maskData[i].separator) {
4298 if (str.at(i) != m_maskData[i].maskChar)
4299 return InvalidInput;
4301 if (!isValidInput(str.at(i), m_maskData[i].maskChar))
4302 return InvalidInput;
4305 return AcceptableInput;
4309
4310
4311
4312
4313
4314
4315
4316QString QQuickTextInputPrivate::maskString(uint pos,
const QString &str,
bool clear)
const
4318 if (pos >= (uint)m_maxLength)
4319 return QString::fromLatin1(
"");
4322 fill = clear ? clearString(0, m_maxLength) : m_text;
4325 QString s = QString::fromLatin1(
"");
4327 while (i < m_maxLength) {
4328 if (strIndex < str.size()) {
4329 if (m_maskData[i].separator) {
4330 s += m_maskData[i].maskChar;
4331 if (str[strIndex] == m_maskData[i].maskChar)
4335 if (isValidInput(str[strIndex], m_maskData[i].maskChar)) {
4336 switch (m_maskData[i].caseMode) {
4337 case MaskInputData::Upper:
4338 s += str[strIndex].toUpper();
4340 case MaskInputData::Lower:
4341 s += str[strIndex].toLower();
4349 int n = findInMask(i,
true,
true, str[strIndex]);
4351 if (str.size() != 1 || i == 0 || (i > 0 && (!m_maskData[i-1].separator || m_maskData[i-1].maskChar != str[strIndex]))) {
4352 s += QStringView{fill}.mid(i, n-i+1);
4357 n = findInMask(i,
true,
false, str[strIndex]);
4359 s += QStringView{fill}.mid(i, n-i);
4360 switch (m_maskData[n].caseMode) {
4361 case MaskInputData::Upper:
4362 s += str[strIndex].toUpper();
4364 case MaskInputData::Lower:
4365 s += str[strIndex].toLower();
4386
4387
4388
4389
4390
4391QString QQuickTextInputPrivate::clearString(uint pos, uint len)
const
4393 if (pos >= (uint)m_maxLength)
4397 int end = qMin((uint)m_maxLength, pos + len);
4398 for (
int i = pos; i < end; ++i)
4399 if (m_maskData[i].separator)
4400 s += m_maskData[i].maskChar;
4408
4409
4410
4411
4412
4413QString QQuickTextInputPrivate::stripString(
const QString &str)
const
4419 int end = qMin(m_maxLength, str.size());
4420 for (
int i = 0; i < end; ++i) {
4421 if (m_maskData[i].separator)
4422 s += m_maskData[i].maskChar;
4423 else if (str[i] != m_blank)
4431
4432
4433
4434int QQuickTextInputPrivate::findInMask(
int pos,
bool forward,
bool findSeparator, QChar searchChar)
const
4436 if (pos >= m_maxLength || pos < 0)
4439 int end = forward ? m_maxLength : -1;
4440 int step = forward ? 1 : -1;
4444 if (findSeparator) {
4445 if (m_maskData[i].separator && m_maskData[i].maskChar == searchChar)
4448 if (!m_maskData[i].separator) {
4449 if (searchChar.isNull())
4451 else if (isValidInput(searchChar, m_maskData[i].maskChar))
4460void QQuickTextInputPrivate::internalUndo(
int until)
4462 if (!isUndoAvailable())
4464 cancelPasswordEchoTimer();
4466 while (m_undoState && m_undoState > until) {
4467 Command& cmd = m_history[--m_undoState];
4470 m_text.remove(cmd.pos, 1);
4474 m_selstart = cmd.selStart;
4475 m_selend = cmd.selEnd;
4479 case RemoveSelection:
4480 m_text.insert(cmd.pos, cmd.uc);
4481 m_cursor = cmd.pos + 1;
4484 case DeleteSelection:
4485 m_text.insert(cmd.pos, cmd.uc);
4491 if (until < 0 && m_undoState) {
4492 Command& next = m_history[m_undoState-1];
4493 if (next.type != cmd.type
4494 && next.type < RemoveSelection
4495 && (cmd.type < RemoveSelection || next.type == Separator)) {
4504void QQuickTextInputPrivate::internalRedo()
4506 if (!isRedoAvailable())
4509 while (m_undoState < m_history.size()) {
4510 Command& cmd = m_history[m_undoState++];
4513 m_text.insert(cmd.pos, cmd.uc);
4514 m_cursor = cmd.pos + 1;
4517 m_selstart = cmd.selStart;
4518 m_selend = cmd.selEnd;
4523 case RemoveSelection:
4524 case DeleteSelection:
4525 m_text.remove(cmd.pos, 1);
4526 m_selstart = cmd.selStart;
4527 m_selend = cmd.selEnd;
4531 m_selstart = cmd.selStart;
4532 m_selend = cmd.selEnd;
4536 if (m_undoState < m_history.size()) {
4537 Command& next = m_history[m_undoState];
4538 if (next.type != cmd.type
4539 && cmd.type < RemoveSelection
4540 && next.type != Separator
4541 && (next.type < RemoveSelection || cmd.type == Separator)) {
4549void QQuickTextInputPrivate::emitUndoRedoChanged()
4551 Q_Q(QQuickTextInput);
4552 const bool previousUndo = canUndo;
4553 const bool previousRedo = canRedo;
4555 canUndo = isUndoAvailable();
4556 canRedo = isRedoAvailable();
4558 if (previousUndo != canUndo)
4559 emit q->canUndoChanged();
4560 if (previousRedo != canRedo)
4561 emit q->canRedoChanged();
4565
4566
4567
4568
4569
4570bool QQuickTextInputPrivate::emitCursorPositionChanged()
4572 Q_Q(QQuickTextInput);
4573 if (m_cursor != m_lastCursorPos) {
4574 m_lastCursorPos = m_cursor;
4576 q->updateCursorRectangle();
4577 emit q->cursorPositionChanged();
4579 if (!hasSelectedText()) {
4580 if (lastSelectionStart != m_cursor) {
4581 lastSelectionStart = m_cursor;
4582 emit q->selectionStartChanged();
4584 if (lastSelectionEnd != m_cursor) {
4585 lastSelectionEnd = m_cursor;
4586 emit q->selectionEndChanged();
4590#if QT_CONFIG(accessibility)
4591 if (QAccessible::isActive()) {
4592 if (QObject *acc = QQuickAccessibleAttached::findAccessible(q, QAccessible::EditableText)) {
4593 QAccessibleTextCursorEvent ev(acc, m_cursor);
4594 QAccessible::updateAccessibility(&ev);
4605void QQuickTextInputPrivate::setBlinkingCursorEnabled(
bool enable)
4607 if (enable == m_blinkEnabled)
4610 m_blinkEnabled = enable;
4611 updateCursorBlinking();
4614 connect(qApp->styleHints(), &QStyleHints::cursorFlashTimeChanged,
this, &QQuickTextInputPrivate::updateCursorBlinking);
4616 disconnect(qApp->styleHints(), &QStyleHints::cursorFlashTimeChanged,
this, &QQuickTextInputPrivate::updateCursorBlinking);
4619void QQuickTextInputPrivate::updateCursorBlinking()
4621 Q_Q(QQuickTextInput);
4624 q->killTimer(m_blinkTimer);
4628 if (m_blinkEnabled && cursorVisible && !cursorItem && !m_readOnly) {
4629 int flashTime = QGuiApplication::styleHints()->cursorFlashTime();
4631 m_blinkTimer = q->startTimer(flashTime / 2);
4635 updateType = UpdatePaintNode;
4640void QQuickTextInput::timerEvent(QTimerEvent *event)
4642 Q_D(QQuickTextInput);
4643 if (event->timerId() == d->m_blinkTimer) {
4644 d->m_blinkStatus = !d->m_blinkStatus;
4645 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
4648 }
else if (event->timerId() == d->m_passwordEchoTimer.timerId()) {
4649 d->m_passwordEchoTimer.stop();
4650 d->updateDisplayText();
4651 updateCursorRectangle();
4655void QQuickTextInputPrivate::processKeyEvent(QKeyEvent* event)
4657 Q_Q(QQuickTextInput);
4659 if (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return) {
4660 if (hasAcceptableInput(m_text) == AcceptableInput || fixup()) {
4662 QInputMethod *inputMethod = QGuiApplication::inputMethod();
4663 inputMethod->commit();
4668 emit q->editingFinished();
4678 updateCursorBlinking();
4680 if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit
4681 && !m_passwordEchoEditing
4683 && !event->text().isEmpty()
4684 && !(event->modifiers() & Qt::ControlModifier)) {
4690 updatePasswordEchoEditing(
true);
4694 bool unknown =
false;
4695#if QT_CONFIG(shortcut)
4696 bool visual = cursorMoveStyle() == Qt::VisualMoveStyle;
4701#if QT_CONFIG(shortcut)
4702 else if (event == QKeySequence::Undo) {
4705 else if (event == QKeySequence::Redo) {
4708 else if (event == QKeySequence::SelectAll) {
4711#if QT_CONFIG(clipboard)
4712 else if (event == QKeySequence::Copy) {
4715 else if (event == QKeySequence::Paste) {
4717 QClipboard::Mode mode = QClipboard::Clipboard;
4721 else if (event == QKeySequence::Cut) {
4724 else if (event == QKeySequence::DeleteEndOfLine) {
4729 else if (event == QKeySequence::MoveToStartOfLine || event == QKeySequence::MoveToStartOfBlock) {
4732 else if (event == QKeySequence::MoveToEndOfLine || event == QKeySequence::MoveToEndOfBlock) {
4735 else if (event == QKeySequence::SelectStartOfLine || event == QKeySequence::SelectStartOfBlock) {
4738 else if (event == QKeySequence::SelectEndOfLine || event == QKeySequence::SelectEndOfBlock) {
4741 else if (event == QKeySequence::MoveToNextChar) {
4742 if (hasSelectedText()) {
4743 moveCursor(selectionEnd(),
false);
4745 cursorForward(0, visual ? 1 : (layoutDirection() == Qt::LeftToRight ? 1 : -1));
4748 else if (event == QKeySequence::SelectNextChar) {
4749 cursorForward(1, visual ? 1 : (layoutDirection() == Qt::LeftToRight ? 1 : -1));
4751 else if (event == QKeySequence::MoveToPreviousChar) {
4752 if (hasSelectedText()) {
4753 moveCursor(selectionStart(),
false);
4755 cursorForward(0, visual ? -1 : (layoutDirection() == Qt::LeftToRight ? -1 : 1));
4758 else if (event == QKeySequence::SelectPreviousChar) {
4759 cursorForward(1, visual ? -1 : (layoutDirection() == Qt::LeftToRight ? -1 : 1));
4761 else if (event == QKeySequence::MoveToNextWord) {
4762 if (m_echoMode == QQuickTextInput::Normal)
4763 layoutDirection() == Qt::LeftToRight ? cursorWordForward(0) : cursorWordBackward(0);
4765 layoutDirection() == Qt::LeftToRight ? end(0) : home(0);
4767 else if (event == QKeySequence::MoveToPreviousWord) {
4768 if (m_echoMode == QQuickTextInput::Normal)
4769 layoutDirection() == Qt::LeftToRight ? cursorWordBackward(0) : cursorWordForward(0);
4770 else if (!m_readOnly) {
4771 layoutDirection() == Qt::LeftToRight ? home(0) : end(0);
4774 else if (event == QKeySequence::SelectNextWord) {
4775 if (m_echoMode == QQuickTextInput::Normal)
4776 layoutDirection() == Qt::LeftToRight ? cursorWordForward(1) : cursorWordBackward(1);
4778 layoutDirection() == Qt::LeftToRight ? end(1) : home(1);
4780 else if (event == QKeySequence::SelectPreviousWord) {
4781 if (m_echoMode == QQuickTextInput::Normal)
4782 layoutDirection() == Qt::LeftToRight ? cursorWordBackward(1) : cursorWordForward(1);
4784 layoutDirection() == Qt::LeftToRight ? home(1) : end(1);
4786 else if (event == QKeySequence::Delete) {
4790 else if (event == QKeySequence::DeleteEndOfWord) {
4794 else if (event == QKeySequence::DeleteStartOfWord) {
4796 deleteStartOfWord();
4797 }
else if (event == QKeySequence::DeleteCompleteLine) {
4800#if QT_CONFIG(clipboard)
4808 bool handled =
false;
4809 if (event->modifiers() & Qt::ControlModifier) {
4810 switch (event->key()) {
4811 case Qt::Key_Backspace:
4813 deleteStartOfWord();
4820 switch (event->key()) {
4821 case Qt::Key_Backspace:
4833 if (event->key() == Qt::Key_Direction_L || event->key() == Qt::Key_Direction_R) {
4834 setLayoutDirection((event->key() == Qt::Key_Direction_L) ? Qt::LeftToRight : Qt::RightToLeft);
4838 if (unknown && !m_readOnly) {
4839 if (m_inputControl->isAcceptableInput(event)) {
4843 && !hasSelectedText()
4844 && !(m_cursor == q_func()->text().size())) {
4848 insert(event->text());
4861
4862
4863
4864
4866void QQuickTextInputPrivate::deleteStartOfWord()
4868 int priorState = m_undoState;
4870 if (!separateSelection()) {
4871 Command cmd(SetSelection, m_cursor, u'\0', m_selstart, m_selend);
4873 cursorWordBackward(
true);
4877 removeSelectedText();
4878 finishChange(priorState);
4882
4883
4884
4885
4887void QQuickTextInputPrivate::deleteEndOfWord()
4889 int priorState = m_undoState;
4890 Command cmd(SetSelection, m_cursor, u'\0', m_selstart, m_selend);
4892 cursorWordForward(
true);
4896 removeSelectedText();
4897 finishChange(priorState);
4901
4902
4903
4904
4906void QQuickTextInputPrivate::deleteEndOfLine()
4908 int priorState = m_undoState;
4909 Command cmd(SetSelection, m_cursor, u'\0', m_selstart, m_selend);
4911 setSelection(m_cursor, end());
4913 removeSelectedText();
4914 finishChange(priorState);
4918
4919
4920
4921
4922
4923
4924
4925
4926void QQuickTextInput::ensureVisible(
int position)
4928 Q_D(QQuickTextInput);
4929 d->ensureVisible(position);
4930 updateCursorRectangle(
false);
4934
4935
4936
4937
4938
4939
4940
4941
4942
4943
4944void QQuickTextInput::clear()
4946 Q_D(QQuickTextInput);
4952
4953
4954
4955
4956
4957
4958
4959
4960
4961
4962
4963
4964
4965
4966
4967
4968
4969
4970
4971
4972
4973
4974qreal QQuickTextInput::padding()
const
4976 Q_D(
const QQuickTextInput);
4977 return d->padding();
4980void QQuickTextInput::setPadding(qreal padding)
4982 Q_D(QQuickTextInput);
4983 if (qFuzzyCompare(d->padding(), padding))
4986 d->extra.value().padding = padding;
4988 updateCursorRectangle();
4989 emit paddingChanged();
4990 if (!d->extra.isAllocated() || !d->extra->explicitTopPadding)
4991 emit topPaddingChanged();
4992 if (!d->extra.isAllocated() || !d->extra->explicitLeftPadding)
4993 emit leftPaddingChanged();
4994 if (!d->extra.isAllocated() || !d->extra->explicitRightPadding)
4995 emit rightPaddingChanged();
4996 if (!d->extra.isAllocated() || !d->extra->explicitBottomPadding)
4997 emit bottomPaddingChanged();
5000void QQuickTextInput::resetPadding()
5005qreal QQuickTextInput::topPadding()
const
5007 Q_D(
const QQuickTextInput);
5008 if (d->extra.isAllocated() && d->extra->explicitTopPadding)
5009 return d->extra->topPadding;
5010 return d->padding();
5013void QQuickTextInput::setTopPadding(qreal padding)
5015 Q_D(QQuickTextInput);
5016 d->setTopPadding(padding);
5019void QQuickTextInput::resetTopPadding()
5021 Q_D(QQuickTextInput);
5022 d->setTopPadding(0,
true);
5025qreal QQuickTextInput::leftPadding()
const
5027 Q_D(
const QQuickTextInput);
5028 if (d->extra.isAllocated() && d->extra->explicitLeftPadding)
5029 return d->extra->leftPadding;
5030 return d->padding();
5033void QQuickTextInput::setLeftPadding(qreal padding)
5035 Q_D(QQuickTextInput);
5036 d->setLeftPadding(padding);
5039void QQuickTextInput::resetLeftPadding()
5041 Q_D(QQuickTextInput);
5042 d->setLeftPadding(0,
true);
5045qreal QQuickTextInput::rightPadding()
const
5047 Q_D(
const QQuickTextInput);
5048 if (d->extra.isAllocated() && d->extra->explicitRightPadding)
5049 return d->extra->rightPadding;
5050 return d->padding();
5053void QQuickTextInput::setRightPadding(qreal padding)
5055 Q_D(QQuickTextInput);
5056 d->setRightPadding(padding);
5059void QQuickTextInput::resetRightPadding()
5061 Q_D(QQuickTextInput);
5062 d->setRightPadding(0,
true);
5065qreal QQuickTextInput::bottomPadding()
const
5067 Q_D(
const QQuickTextInput);
5068 if (d->extra.isAllocated() && d->extra->explicitBottomPadding)
5069 return d->extra->bottomPadding;
5070 return d->padding();
5073void QQuickTextInput::setBottomPadding(qreal padding)
5075 Q_D(QQuickTextInput);
5076 d->setBottomPadding(padding);
5079void QQuickTextInput::resetBottomPadding()
5081 Q_D(QQuickTextInput);
5082 d->setBottomPadding(0,
true);
5085#if QT_VERSION < QT_VERSION_CHECK(7
, 0
, 0
)
5086void QQuickTextInput::setOldSelectionDefault()
5088 Q_D(QQuickTextInput);
5089 d->selectByMouse =
false;
5090 d->selectByTouchDrag =
true;
5091 qCDebug(lcQuickTextInput,
"pre-6.4 behavior chosen: selectByMouse defaults false; if enabled, touchscreen acts like a mouse");
5095QQuickPre64TextInput::QQuickPre64TextInput(QQuickItem *parent)
5096 : QQuickTextInput(parent)
5098 setOldSelectionDefault();
5104#include "moc_qquicktextinput_p.cpp"
Combined button and popup list for selecting options.