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(), q->cursorRectangle().center().toPoint(),
1728 event->globalPos(), event->modifiers());
1729 const bool eventProcessed = QQuickItemPrivate::handleContextMenuEvent(&mapped);
1730 event->setAccepted(mapped.isAccepted());
1731 return eventProcessed;
1734bool QQuickTextInputPrivate::sendMouseEventToInputContext(QMouseEvent *event)
1737 if (composeMode()) {
1738 int tmp_cursor = positionAt(event->position());
1739 int mousePos = tmp_cursor - m_cursor;
1740 if (mousePos >= 0 && mousePos <= m_textLayout.preeditAreaText().size()) {
1741 if (event->type() == QEvent::MouseButtonRelease) {
1742 QGuiApplication::inputMethod()->invokeAction(QInputMethod::Click, mousePos);
1754void QQuickTextInput::mouseUngrabEvent()
1756 Q_D(QQuickTextInput);
1757 d->selectPressed =
false;
1758 setKeepMouseGrab(
false);
1761bool QQuickTextInput::event(QEvent* ev)
1763#if QT_CONFIG(shortcut)
1764 Q_D(QQuickTextInput);
1765 if (ev->type() == QEvent::ShortcutOverride) {
1766 if (d->m_readOnly) {
1770 QKeyEvent* ke =
static_cast<QKeyEvent*>(ev);
1771 if (ke == QKeySequence::Copy
1772 || ke == QKeySequence::Paste
1773 || ke == QKeySequence::Cut
1774 || ke == QKeySequence::Redo
1775 || ke == QKeySequence::Undo
1776 || ke == QKeySequence::MoveToNextWord
1777 || ke == QKeySequence::MoveToPreviousWord
1778 || ke == QKeySequence::MoveToStartOfDocument
1779 || ke == QKeySequence::MoveToEndOfDocument
1780 || ke == QKeySequence::SelectNextWord
1781 || ke == QKeySequence::SelectPreviousWord
1782 || ke == QKeySequence::SelectStartOfLine
1783 || ke == QKeySequence::SelectEndOfLine
1784 || ke == QKeySequence::SelectStartOfBlock
1785 || ke == QKeySequence::SelectEndOfBlock
1786 || ke == QKeySequence::SelectStartOfDocument
1787 || ke == QKeySequence::SelectAll
1788 || ke == QKeySequence::SelectEndOfDocument
1789 || ke == QKeySequence::DeleteCompleteLine) {
1792 }
else if (ke->modifiers() == Qt::NoModifier || ke->modifiers() == Qt::ShiftModifier
1793 || ke->modifiers() == Qt::KeypadModifier) {
1794 if (ke->key() < Qt::Key_Escape) {
1798 switch (ke->key()) {
1799 case Qt::Key_Delete:
1802 case Qt::Key_Backspace:
1816 return QQuickImplicitSizeItem::event(ev);
1819void QQuickTextInput::geometryChange(
const QRectF &newGeometry,
1820 const QRectF &oldGeometry)
1822 Q_D(QQuickTextInput);
1824 if (newGeometry.width() != oldGeometry.width())
1826 else if (newGeometry.height() != oldGeometry.height() && d->vAlign != QQuickTextInput::AlignTop)
1827 d->updateBaselineOffset();
1828 updateCursorRectangle();
1830 QQuickImplicitSizeItem::geometryChange(newGeometry, oldGeometry);
1833void QQuickTextInput::itemChange(ItemChange change,
const ItemChangeData &value)
1835 Q_D(QQuickTextInput);
1838 case ItemDevicePixelRatioHasChanged:
1839 if (d->containsUnscalableGlyphs) {
1850 QQuickImplicitSizeItem::itemChange(change, value);
1853void QQuickTextInputPrivate::ensureVisible(
int position,
int preeditCursor,
int preeditLength)
1855 Q_Q(QQuickTextInput);
1856 QTextLine textLine = m_textLayout.lineForTextPosition(position + preeditCursor);
1857 const qreal width = qMax<qreal>(0, q->width() - q->leftPadding() - q->rightPadding());
1859 qreal widthUsed = 0;
1860 if (textLine.isValid()) {
1861 cix = textLine.cursorToX(position + preeditLength);
1862 const qreal cursorWidth = cix >= 0 ? cix : width - cix;
1863 widthUsed = qMax(textLine.naturalTextWidth(), cursorWidth);
1865 int previousScroll = hscroll;
1867 if (widthUsed <= width) {
1870 Q_ASSERT(textLine.isValid());
1871 if (cix - hscroll >= width) {
1873 hscroll = cix - width;
1874 }
else if (cix - hscroll < 0 && hscroll < widthUsed) {
1877 }
else if (widthUsed - hscroll < width) {
1880 hscroll = widthUsed - width;
1881 }
else if (width - hscroll > widthUsed) {
1884 hscroll = width - widthUsed;
1887 if (preeditLength > 0) {
1890 cix = textLine.cursorToX(position + qMax(0, preeditCursor - 1));
1896 if (previousScroll != hscroll)
1897 textLayoutDirty =
true;
1900void QQuickTextInputPrivate::updateHorizontalScroll()
1902 if (autoScroll && m_echoMode != QQuickTextInput::NoEcho) {
1904 const int preeditLength = m_textLayout.preeditAreaText().size();
1905 ensureVisible(m_cursor, m_preeditCursor, preeditLength);
1907 ensureVisible(m_cursor);
1914void QQuickTextInputPrivate::updateVerticalScroll()
1916 Q_Q(QQuickTextInput);
1918 const int preeditLength = m_textLayout.preeditAreaText().size();
1920 const qreal height = qMax<qreal>(0, q->height() - q->topPadding() - q->bottomPadding());
1921 qreal heightUsed = contentSize.height();
1922 qreal previousScroll = vscroll;
1924 if (!autoScroll || heightUsed <= height) {
1926 vscroll = -QQuickTextUtil::alignedY(
1927 heightUsed, height, vAlign & ~(Qt::AlignAbsolute|Qt::AlignHorizontal_Mask));
1930 QTextLine currentLine = m_textLayout.lineForTextPosition(m_cursor + preeditLength);
1932 QTextLine currentLine = m_textLayout.lineForTextPosition(m_cursor);
1934 QRectF r = currentLine.isValid() ? currentLine.rect() : QRectF();
1935 qreal top = r.top();
1936 int bottom = r.bottom();
1938 if (bottom - vscroll >= height) {
1940 vscroll = bottom - height;
1941 }
else if (top - vscroll < 0 && vscroll < heightUsed) {
1944 }
else if (heightUsed - vscroll < height) {
1947 vscroll = heightUsed - height;
1950 if (preeditLength > 0) {
1953 currentLine = m_textLayout.lineForTextPosition(m_cursor + qMax(0, m_preeditCursor - 1));
1954 top = currentLine.isValid() ? currentLine.rect().top() : 0;
1960 if (previousScroll != vscroll)
1961 textLayoutDirty =
true;
1964void QQuickTextInput::triggerPreprocess()
1966 Q_D(QQuickTextInput);
1967 if (d->updateType == QQuickTextInputPrivate::UpdateNone)
1968 d->updateType = QQuickTextInputPrivate::UpdateOnlyPreprocess;
1973void QQuickTextInput::updatePolish()
1975 invalidateFontCaches();
1978void QQuickTextInput::invalidateFontCaches()
1980 Q_D(QQuickTextInput);
1982 if (d->m_textLayout.engine() !=
nullptr)
1983 d->m_textLayout.engine()->resetFontEngineCache();
1986void QQuickTextInput::ensureActiveFocus(Qt::FocusReason reason)
1988 bool hadActiveFocus = hasActiveFocus();
1989 forceActiveFocus(reason);
1991 Q_D(QQuickTextInput);
1993 if (hasActiveFocus() && hadActiveFocus && !d->m_readOnly)
1994 qGuiApp->inputMethod()->show();
1996 Q_UNUSED(hadActiveFocus);
2000QSGNode *QQuickTextInput::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data)
2003 Q_D(QQuickTextInput);
2005 if (d->updateType != QQuickTextInputPrivate::UpdatePaintNode && oldNode !=
nullptr) {
2007 d->updateType = QQuickTextInputPrivate::UpdateNone;
2011 d->updateType = QQuickTextInputPrivate::UpdateNone;
2013 QSGInternalTextNode *node =
static_cast<QSGInternalTextNode *>(oldNode);
2014 if (node ==
nullptr)
2015 node = d->sceneGraphContext()->createInternalTextNode(d->sceneGraphRenderContext());
2018 const bool showCursor = !isReadOnly() && d->cursorItem ==
nullptr && d->cursorVisible && d->m_blinkStatus;
2020 if (!d->textLayoutDirty && oldNode !=
nullptr) {
2022 node->setCursor(cursorRectangle(), d->color);
2024 node->clearCursor();
2026 node->setRenderType(QSGTextNode::RenderType(d->renderType));
2028 node->setMatrix(QMatrix4x4());
2029 node->setTextStyle(QSGInternalTextNode::Normal);
2030 node->setColor(d->color);
2031 node->setSelectionTextColor(d->selectedTextColor);
2032 node->setSelectionColor(d->selectionColor);
2033 node->setFiltering(smooth() ? QSGTexture::Linear : QSGTexture::Nearest);
2035 if (flags().testFlag(ItemObservesViewport))
2036 node->setViewport(clipRect());
2038 node->setViewport(QRectF{});
2040 QPointF offset(leftPadding(), topPadding());
2041 if (d->autoScroll && d->m_textLayout.lineCount() > 0) {
2042 QFontMetricsF fm(d->font);
2044 offset += -QPointF(d->hscroll, d->vscroll + d->m_textLayout.lineAt(0).ascent() - fm.ascent());
2046 offset += -QPointF(d->hscroll, d->vscroll);
2049 if (!d->m_textLayout.text().isEmpty()
2051 || !d->m_textLayout.preeditAreaText().isEmpty()
2054 node->addTextLayout(offset, &d->m_textLayout,
2055 d->selectionStart(),
2056 d->selectionEnd() - 1);
2061 node->setCursor(cursorRectangle(), d->color);
2063 d->textLayoutDirty =
false;
2066 d->containsUnscalableGlyphs = node->containsUnscalableGlyphs();
2068 invalidateFontCaches();
2074QVariant QQuickTextInput::inputMethodQuery(Qt::InputMethodQuery property)
const
2078 if (property == Qt::ImEnterKeyType) {
2079 Q_D(
const QQuickItem);
2081 if (!d->extra.isAllocated()
2082 || d->extra->enterKeyAttached ==
nullptr
2083 || d->extra->enterKeyAttached->type() == Qt::EnterKeyDefault) {
2085 QQuickItem *next =
const_cast<QQuickTextInput*>(
this)->nextItemInFocusChain();
2086 QQuickItem *originalNext = next;
2087 while (next && next !=
this && !next->activeFocusOnTab()) {
2088 next = next->nextItemInFocusChain();
2089 if (next == originalNext) {
2095 const auto nextYPos = next->mapToGlobal(QPoint(0, 0)).y();
2096 const auto currentYPos =
this->mapToGlobal(QPoint(0, 0)).y();
2097 if (currentYPos < nextYPos)
2100 return Qt::EnterKeyNext;
2105 return inputMethodQuery(property, QVariant());
2108QVariant QQuickTextInput::inputMethodQuery(Qt::InputMethodQuery property,
const QVariant &argument)
const
2110 Q_D(
const QQuickTextInput);
2113 return QVariant((
bool)(flags() & ItemAcceptsInputMethod));
2115 return QVariant((
int) d->effectiveInputMethodHints());
2116 case Qt::ImCursorRectangle:
2117 return cursorRectangle();
2118 case Qt::ImAnchorRectangle:
2119 return d->anchorRectangle();
2122 case Qt::ImCursorPosition: {
2123 const QPointF pt = argument.toPointF();
2125 return QVariant(d->positionAt(pt));
2126 return QVariant(d->m_cursor);
2128 case Qt::ImSurroundingText:
2129 if (d->m_echoMode == PasswordEchoOnEdit && !d->m_passwordEchoEditing) {
2130 return QVariant(displayText());
2132 return QVariant(d->realText());
2134 case Qt::ImCurrentSelection:
2135 return QVariant(selectedText());
2136 case Qt::ImMaximumTextLength:
2137 return QVariant(maxLength());
2138 case Qt::ImAnchorPosition:
2139 if (d->selectionStart() == d->selectionEnd())
2140 return QVariant(d->m_cursor);
2141 else if (d->selectionStart() == d->m_cursor)
2142 return QVariant(d->selectionEnd());
2144 return QVariant(d->selectionStart());
2145 case Qt::ImAbsolutePosition:
2146 return QVariant(d->m_cursor);
2147 case Qt::ImTextAfterCursor:
2148 if (argument.isValid())
2149 return QVariant(d->m_text.mid(d->m_cursor, argument.toInt()));
2150 return QVariant(d->m_text.mid(d->m_cursor));
2151 case Qt::ImTextBeforeCursor:
2152 if (argument.isValid())
2153 return QVariant(QStringView{d->m_text}.left(d->m_cursor).right(argument.toInt()).toString());
2154 return QVariant(d->m_text.left(d->m_cursor));
2155 case Qt::ImReadOnly:
2156 return QVariant(d->m_readOnly);
2158 return QQuickItem::inputMethodQuery(property);
2164
2165
2166
2167
2168void QQuickTextInput::deselect()
2170 Q_D(QQuickTextInput);
2175
2176
2177
2178
2179void QQuickTextInput::selectAll()
2181 Q_D(QQuickTextInput);
2182 d->setSelection(0, text().size());
2186
2187
2188
2189
2190
2191bool QQuickTextInput::isRightToLeft(
int start,
int end)
2194 qmlWarning(
this) <<
"isRightToLeft(start, end) called with the end property being smaller than the start.";
2197 return QStringView{text()}.mid(start, end - start).isRightToLeft();
2201#if QT_CONFIG(clipboard)
2203
2204
2205
2206
2207
2208
2209
2210
2211void QQuickTextInput::cut()
2213 Q_D(QQuickTextInput);
2214 if (!d->m_readOnly && d->m_echoMode == QQuickTextInput::Normal) {
2221
2222
2223
2224
2225
2226
2227
2228
2229void QQuickTextInput::copy()
2231 Q_D(QQuickTextInput);
2236
2237
2238
2239
2240void QQuickTextInput::paste()
2242 Q_D(QQuickTextInput);
2249
2250
2251
2252
2253
2254
2256void QQuickTextInput::undo()
2258 Q_D(QQuickTextInput);
2259 if (!d->m_readOnly) {
2262 d->finishChange(-1,
true);
2267
2268
2269
2270
2272void QQuickTextInput::redo()
2274 Q_D(QQuickTextInput);
2275 if (!d->m_readOnly) {
2283
2284
2285
2286
2288void QQuickTextInput::insert(
int position,
const QString &text)
2290 Q_D(QQuickTextInput);
2291 if (d->m_echoMode == QQuickTextInput::Password) {
2292 if (d->m_passwordMaskDelay > 0)
2293 d->m_passwordEchoTimer.start(d->m_passwordMaskDelay,
this);
2295 if (position < 0 || position > d->m_text.size())
2298 const int priorState = d->m_undoState;
2300 QString insertText = text;
2302 if (d->hasSelectedText()) {
2303 d->addCommand(QQuickTextInputPrivate::Command(
2304 QQuickTextInputPrivate::SetSelection, d->m_cursor, u'\0', d->m_selstart, d->m_selend));
2306 if (d->m_maskData) {
2307 insertText = d->maskString(position, insertText);
2308 for (
int i = 0; i < insertText.size(); ++i) {
2309 d->addCommand(QQuickTextInputPrivate::Command(
2310 QQuickTextInputPrivate::DeleteSelection, position + i, d->m_text.at(position + i), -1, -1));
2311 d->addCommand(QQuickTextInputPrivate::Command(
2312 QQuickTextInputPrivate::Insert, position + i, insertText.at(i), -1, -1));
2314 d->m_text.replace(position, insertText.size(), insertText);
2315 if (!insertText.isEmpty())
2316 d->m_textDirty =
true;
2317 if (position < d->m_selend && position + insertText.size() > d->m_selstart)
2318 d->m_selDirty =
true;
2320 int remaining = d->m_maxLength - d->m_text.size();
2321 if (remaining != 0) {
2322 insertText = insertText.left(remaining);
2323 d->m_text.insert(position, insertText);
2324 for (
int i = 0; i < insertText.size(); ++i)
2325 d->addCommand(QQuickTextInputPrivate::Command(
2326 QQuickTextInputPrivate::Insert, position + i, insertText.at(i), -1, -1));
2327 if (d->m_cursor >= position)
2328 d->m_cursor += insertText.size();
2329 if (d->m_selstart >= position)
2330 d->m_selstart += insertText.size();
2331 if (d->m_selend >= position)
2332 d->m_selend += insertText.size();
2333 d->m_textDirty =
true;
2334 if (position >= d->m_selstart && position <= d->m_selend)
2335 d->m_selDirty =
true;
2339 d->addCommand(QQuickTextInputPrivate::Command(
2340 QQuickTextInputPrivate::SetSelection, d->m_cursor, u'\0', d->m_selstart, d->m_selend));
2341 d->finishChange(priorState);
2343 if (d->lastSelectionStart != d->lastSelectionEnd) {
2344 if (d->m_selstart != d->lastSelectionStart) {
2345 d->lastSelectionStart = d->m_selstart;
2346 emit selectionStartChanged();
2348 if (d->m_selend != d->lastSelectionEnd) {
2349 d->lastSelectionEnd = d->m_selend;
2350 emit selectionEndChanged();
2356
2357
2358
2359
2361void QQuickTextInput::remove(
int start,
int end)
2363 Q_D(QQuickTextInput);
2365 start = qBound(0, start, d->m_text.size());
2366 end = qBound(0, end, d->m_text.size());
2370 else if (start == end)
2373 if (start < d->m_selend && end > d->m_selstart)
2374 d->m_selDirty =
true;
2376 const int priorState = d->m_undoState;
2378 d->addCommand(QQuickTextInputPrivate::Command(
2379 QQuickTextInputPrivate::SetSelection, d->m_cursor, u'\0', d->m_selstart, d->m_selend));
2381 if (start <= d->m_cursor && d->m_cursor < end) {
2384 for (
int i = d->m_cursor; i >= start; --i) {
2385 d->addCommand(QQuickTextInputPrivate::Command(
2386 QQuickTextInputPrivate::DeleteSelection, i, d->m_text.at(i), -1, 1));
2388 for (
int i = end - 1; i > d->m_cursor; --i) {
2389 d->addCommand(QQuickTextInputPrivate::Command(
2390 QQuickTextInputPrivate::DeleteSelection, i - d->m_cursor + start - 1, d->m_text.at(i), -1, -1));
2393 for (
int i = end - 1; i >= start; --i) {
2394 d->addCommand(QQuickTextInputPrivate::Command(
2395 QQuickTextInputPrivate::RemoveSelection, i, d->m_text.at(i), -1, -1));
2398 if (d->m_maskData) {
2399 d->m_text.replace(start, end - start, d->clearString(start, end - start));
2400 for (
int i = 0; i < end - start; ++i) {
2401 d->addCommand(QQuickTextInputPrivate::Command(
2402 QQuickTextInputPrivate::Insert, start + i, d->m_text.at(start + i), -1, -1));
2405 d->m_text.remove(start, end - start);
2407 if (d->m_cursor > start)
2408 d->m_cursor -= qMin(d->m_cursor, end) - start;
2409 if (d->m_selstart > start)
2410 d->m_selstart -= qMin(d->m_selstart, end) - start;
2411 if (d->m_selend >= end)
2412 d->m_selend -= end - start;
2414 d->addCommand(QQuickTextInputPrivate::Command(
2415 QQuickTextInputPrivate::SetSelection, d->m_cursor, u'\0', d->m_selstart, d->m_selend));
2417 d->m_textDirty =
true;
2418 d->finishChange(priorState);
2420 if (d->lastSelectionStart != d->lastSelectionEnd) {
2421 if (d->m_selstart != d->lastSelectionStart) {
2422 d->lastSelectionStart = d->m_selstart;
2423 emit selectionStartChanged();
2425 if (d->m_selend != d->lastSelectionEnd) {
2426 d->lastSelectionEnd = d->m_selend;
2427 emit selectionEndChanged();
2434
2435
2436
2437
2438void QQuickTextInput::selectWord()
2440 Q_D(QQuickTextInput);
2441 d->selectWordAtPos(d->m_cursor);
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454
2455QString QQuickTextInput::passwordCharacter()
const
2457 Q_D(
const QQuickTextInput);
2458 return QString(d->m_passwordCharacter);
2461void QQuickTextInput::setPasswordCharacter(
const QString &str)
2463 Q_D(QQuickTextInput);
2466 d->m_passwordCharacter = str.constData()[0];
2467 if (d->m_echoMode == Password || d->m_echoMode == PasswordEchoOnEdit)
2468 d->updateDisplayText();
2469 emit passwordCharacterChanged();
2473
2474
2475
2476
2477
2478
2479
2480int QQuickTextInput::passwordMaskDelay()
const
2482 Q_D(
const QQuickTextInput);
2483 return d->m_passwordMaskDelay;
2486void QQuickTextInput::setPasswordMaskDelay(
int delay)
2488 Q_D(QQuickTextInput);
2489 if (d->m_passwordMaskDelay != delay) {
2490 d->m_passwordMaskDelay = delay;
2491 emit passwordMaskDelayChanged(delay);
2495void QQuickTextInput::resetPasswordMaskDelay()
2497 setPasswordMaskDelay(qGuiApp->styleHints()->passwordMaskDelay());
2501
2502
2503
2504
2505
2506
2507
2508
2509
2510
2511
2512
2513
2514
2515
2516QString QQuickTextInput::displayText()
const
2518 Q_D(
const QQuickTextInput);
2519 return d->m_textLayout.text().insert(d->m_textLayout.preeditAreaPosition(), d->m_textLayout.preeditAreaText());
2523
2524
2525
2526
2527
2528
2529
2530
2531
2532
2533
2534QString QQuickTextInput::preeditText()
const
2536 Q_D(
const QQuickTextInput);
2537 return d->m_textLayout.preeditAreaText();
2541
2542
2543
2544
2545
2546
2547
2548
2549
2550
2551
2552
2553
2554
2555
2556
2557
2558bool QQuickTextInput::selectByMouse()
const
2560 Q_D(
const QQuickTextInput);
2561 return d->selectByMouse;
2564void QQuickTextInput::setSelectByMouse(
bool on)
2566 Q_D(QQuickTextInput);
2567 if (d->selectByMouse != on) {
2568 d->selectByMouse = on;
2569 emit selectByMouseChanged(on);
2574
2575
2576
2577
2578
2579
2580
2581
2582
2584QQuickTextInput::SelectionMode QQuickTextInput::mouseSelectionMode()
const
2586 Q_D(
const QQuickTextInput);
2587 return d->mouseSelectionMode;
2590void QQuickTextInput::setMouseSelectionMode(SelectionMode mode)
2592 Q_D(QQuickTextInput);
2593 if (d->mouseSelectionMode != mode) {
2594 d->mouseSelectionMode = mode;
2595 emit mouseSelectionModeChanged(mode);
2600
2601
2602
2603
2604
2606bool QQuickTextInput::persistentSelection()
const
2608 Q_D(
const QQuickTextInput);
2609 return d->persistentSelection;
2612void QQuickTextInput::setPersistentSelection(
bool on)
2614 Q_D(QQuickTextInput);
2615 if (d->persistentSelection == on)
2617 d->persistentSelection = on;
2618 emit persistentSelectionChanged();
2622
2623
2624
2625
2626
2627
2628bool QQuickTextInput::canPaste()
const
2630#if QT_CONFIG(clipboard)
2631 Q_D(
const QQuickTextInput);
2632 if (!d->canPasteValid) {
2633 if (
const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData())
2634 const_cast<QQuickTextInputPrivate *>(d)->canPaste = !d->m_readOnly && mimeData->hasText() && !mimeData->text().isEmpty();
2635 const_cast<QQuickTextInputPrivate *>(d)->canPasteValid =
true;
2644
2645
2646
2647
2648
2649
2651bool QQuickTextInput::canUndo()
const
2653 Q_D(
const QQuickTextInput);
2658
2659
2660
2661
2662
2663
2665bool QQuickTextInput::canRedo()
const
2667 Q_D(
const QQuickTextInput);
2672
2673
2674
2675
2676
2677
2679qreal QQuickTextInput::contentWidth()
const
2681 Q_D(
const QQuickTextInput);
2682 return d->contentSize.width();
2686
2687
2688
2689
2690
2691
2693qreal QQuickTextInput::contentHeight()
const
2695 Q_D(
const QQuickTextInput);
2696 return d->contentSize.height();
2699void QQuickTextInput::moveCursorSelection(
int position)
2701 Q_D(QQuickTextInput);
2702 d->moveCursor(position,
true);
2706
2707
2708
2709
2710
2711
2712
2713
2714
2715
2716
2717
2718
2719
2720
2721
2722
2723
2724
2725
2726
2727
2728
2729
2730
2731
2732
2733
2734
2735
2736
2737
2738
2739
2740
2741void QQuickTextInput::moveCursorSelection(
int pos, SelectionMode mode)
2743 Q_D(QQuickTextInput);
2745 if (mode == SelectCharacters) {
2746 d->moveCursor(pos,
true);
2747 }
else if (pos != d->m_cursor) {
2748 const int cursor = d->m_cursor;
2750 if (!d->hasSelectedText())
2751 anchor = d->m_cursor;
2752 else if (d->selectionStart() == d->m_cursor)
2753 anchor = d->selectionEnd();
2755 anchor = d->selectionStart();
2757 if (anchor < pos || (anchor == pos && cursor < pos)) {
2758 const QString text =
this->text();
2759 QTextBoundaryFinder finder(QTextBoundaryFinder::Word, text);
2760 finder.setPosition(anchor);
2762 const QTextBoundaryFinder::BoundaryReasons reasons = finder.boundaryReasons();
2763 if (anchor < text.size() && (reasons == QTextBoundaryFinder::NotAtBoundary
2764 || (reasons & QTextBoundaryFinder::EndOfItem))) {
2765 finder.toPreviousBoundary();
2767 anchor = finder.position() != -1 ? finder.position() : 0;
2769 finder.setPosition(pos);
2770 if (pos > 0 && !finder.boundaryReasons())
2771 finder.toNextBoundary();
2772 const int cursor = finder.position() != -1 ? finder.position() : text.size();
2774 d->setSelection(anchor, cursor - anchor);
2775 }
else if (anchor > pos || (anchor == pos && cursor > pos)) {
2776 const QString text =
this->text();
2777 QTextBoundaryFinder finder(QTextBoundaryFinder::Word, text);
2778 finder.setPosition(anchor);
2780 const QTextBoundaryFinder::BoundaryReasons reasons = finder.boundaryReasons();
2781 if (anchor > 0 && (reasons == QTextBoundaryFinder::NotAtBoundary
2782 || (reasons & QTextBoundaryFinder::StartOfItem))) {
2783 finder.toNextBoundary();
2785 anchor = finder.position() != -1 ? finder.position() : text.size();
2787 finder.setPosition(pos);
2788 if (pos < text.size() && !finder.boundaryReasons())
2789 finder.toPreviousBoundary();
2790 const int cursor = finder.position() != -1 ? finder.position() : 0;
2792 d->setSelection(anchor, cursor - anchor);
2797void QQuickTextInput::focusInEvent(QFocusEvent *event)
2799 Q_D(QQuickTextInput);
2800 d->handleFocusEvent(event);
2801 QQuickImplicitSizeItem::focusInEvent(event);
2804void QQuickTextInputPrivate::handleFocusEvent(QFocusEvent *event)
2806 Q_Q(QQuickTextInput);
2807 bool focus = event->gotFocus();
2809 q->setCursorVisible(focus);
2810 setBlinkingCursorEnabled(focus);
2813 q->q_updateAlignment();
2815 if (focusOnPress && !m_readOnly)
2816 qGuiApp->inputMethod()->show();
2817 q->connect(QGuiApplication::inputMethod(), SIGNAL(inputDirectionChanged(Qt::LayoutDirection)),
2818 q, SLOT(q_updateAlignment()));
2821 if ((m_passwordEchoEditing || m_passwordEchoTimer.isActive())) {
2822 updatePasswordEchoEditing(
false);
2825 if (event->reason() != Qt::ActiveWindowFocusReason
2826 && event->reason() != Qt::PopupFocusReason
2827 && hasSelectedText()
2828 && !persistentSelection)
2831 if (hasAcceptableInput(m_text) == AcceptableInput || fixup())
2832 emit q->editingFinished();
2835 q->disconnect(QGuiApplication::inputMethod(), SIGNAL(inputDirectionChanged(Qt::LayoutDirection)),
2836 q, SLOT(q_updateAlignment()));
2841void QQuickTextInput::focusOutEvent(QFocusEvent *event)
2843 Q_D(QQuickTextInput);
2844 d->handleFocusEvent(event);
2845 QQuickImplicitSizeItem::focusOutEvent(event);
2848void QQuickTextInputPrivate::readOnlyChanged(
bool isReadOnly)
2850 Q_UNUSED(isReadOnly);
2851#if QT_CONFIG(accessibility)
2852 if (QQuickAccessibleAttached *accessibleAttached =
2853 QQuickAccessibleAttached::attachedProperties(q_func()))
2854 accessibleAttached->set_readOnly(isReadOnly);
2858void QQuickTextInputPrivate::echoModeChanged(QQuickTextInput::EchoMode echoMode)
2860#if QT_CONFIG(accessibility)
2861 if (!QAccessible::isActive())
2864 if (QQuickAccessibleAttached *accessibleAttached =
2865 QQuickAccessibleAttached::attachedProperties(q_func()))
2866 accessibleAttached->set_passwordEdit((echoMode == QQuickTextInput::Password
2867 || echoMode == QQuickTextInput::PasswordEchoOnEdit)
2875#if QT_CONFIG(accessibility)
2876void QQuickTextInputPrivate::accessibilityActiveChanged(
bool active)
2881 Q_Q(QQuickTextInput);
2882 QQuickAccessibleAttached *accessibleAttached = qobject_cast<QQuickAccessibleAttached *>(
2883 qmlAttachedPropertiesObject<QQuickAccessibleAttached>(q,
true));
2884 Q_ASSERT(accessibleAttached);
2885 accessibleAttached->setRole(effectiveAccessibleRole());
2886 accessibleAttached->set_readOnly(m_readOnly);
2887 accessibleAttached->set_passwordEdit((m_echoMode == QQuickTextInput::Password
2888 || m_echoMode == QQuickTextInput::PasswordEchoOnEdit)
2893QAccessible::Role QQuickTextInputPrivate::accessibleRole()
const
2895 return QAccessible::EditableText;
2900
2901
2902
2903
2904
2905
2906
2907
2908
2909
2910
2911bool QQuickTextInput::isInputMethodComposing()
const
2916 Q_D(
const QQuickTextInput);
2917 return d->hasImState;
2921QQuickTextInputPrivate::ExtraData::ExtraData()
2927 , explicitTopPadding(
false)
2928 , explicitLeftPadding(
false)
2929 , explicitRightPadding(
false)
2930 , explicitBottomPadding(
false)
2931 , implicitResize(
true)
2935void QQuickTextInputPrivate::init()
2937 Q_Q(QQuickTextInput);
2938#if QT_CONFIG(clipboard)
2939 if (QGuiApplication::clipboard()->supportsSelection())
2940 q->setAcceptedMouseButtons(Qt::LeftButton | Qt::MiddleButton);
2943 q->setAcceptedMouseButtons(Qt::LeftButton);
2946 q->setFlag(QQuickItem::ItemAcceptsInputMethod);
2948 q->setFlag(QQuickItem::ItemHasContents);
2949#if QT_CONFIG(clipboard)
2950 qmlobject_connect(QGuiApplication::clipboard(), QClipboard, SIGNAL(dataChanged()),
2951 q, QQuickTextInput, SLOT(q_canPasteChanged()));
2954 lastSelectionStart = 0;
2955 lastSelectionEnd = 0;
2956 determineHorizontalAlignment();
2958 if (!qmlDisableDistanceField()) {
2959 QTextOption option = m_textLayout.textOption();
2960 option.setUseDesignMetrics(renderType != QQuickTextInput::NativeRendering);
2961 m_textLayout.setTextOption(option);
2964 m_inputControl =
new QInputControl(QInputControl::LineEdit, q);
2965 setSizePolicy(QLayoutPolicy::Expanding, QLayoutPolicy::Fixed);
2967 QObjectPrivate::connect(q, &QQuickTextInput::readOnlyChanged,
this,
2968 &QQuickTextInputPrivate::readOnlyChanged);
2969 QObjectPrivate::connect(q, &QQuickTextInput::echoModeChanged,
this,
2970 &QQuickTextInputPrivate::echoModeChanged);
2973void QQuickTextInputPrivate::cancelInput()
2976 Q_Q(QQuickTextInput);
2977 if (!m_readOnly && q->hasActiveFocus() && qGuiApp)
2982void QQuickTextInput::updateCursorRectangle(
bool scroll)
2984 Q_D(QQuickTextInput);
2985 if (!isComponentComplete())
2989 d->updateHorizontalScroll();
2990 d->updateVerticalScroll();
2992 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
2995 emit cursorRectangleChanged();
2996 if (d->cursorItem) {
2997 QRectF r = cursorRectangle();
2998 d->cursorItem->setPosition(r.topLeft());
2999 d->cursorItem->setHeight(r.height());
3002 updateInputMethod(Qt::ImCursorRectangle | Qt::ImAnchorRectangle);
3006void QQuickTextInput::selectionChanged()
3008 Q_D(QQuickTextInput);
3009 d->textLayoutDirty =
true;
3010 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
3013 emit selectedTextChanged();
3015 if (d->lastSelectionStart != d->selectionStart()) {
3016 d->lastSelectionStart = d->selectionStart();
3017 if (d->lastSelectionStart == -1)
3018 d->lastSelectionStart = d->m_cursor;
3019 emit selectionStartChanged();
3021 if (d->lastSelectionEnd != d->selectionEnd()) {
3022 d->lastSelectionEnd = d->selectionEnd();
3023 if (d->lastSelectionEnd == -1)
3024 d->lastSelectionEnd = d->m_cursor;
3025 emit selectionEndChanged();
3029QRectF QQuickTextInput::boundingRect()
const
3031 Q_D(
const QQuickTextInput);
3033 int cursorWidth = d->cursorItem ? 0 : 1;
3035 qreal hscroll = d->hscroll;
3036 if (!d->autoScroll || d->contentSize.width() < width())
3037 hscroll -= QQuickTextUtil::alignedX(d->contentSize.width(), width(), effectiveHAlign());
3040 QRectF r(-hscroll, -d->vscroll, d->contentSize.width(), d->contentSize.height());
3041 r.setRight(r.right() + cursorWidth);
3045QRectF QQuickTextInput::clipRect()
const
3047 Q_D(
const QQuickTextInput);
3049 int cursorWidth = d->cursorItem ? d->cursorItem->width() : 1;
3052 QRectF r = QQuickImplicitSizeItem::clipRect();
3053 r.setRight(r.right() + cursorWidth);
3057void QQuickTextInput::q_canPasteChanged()
3059 Q_D(QQuickTextInput);
3060 bool old = d->canPaste;
3061#if QT_CONFIG(clipboard)
3062 if (
const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData())
3063 d->canPaste = !d->m_readOnly && mimeData->hasText();
3065 d->canPaste =
false;
3068 bool changed = d->canPaste != old || !d->canPasteValid;
3069 d->canPasteValid =
true;
3071 emit canPasteChanged();
3075void QQuickTextInput::q_updateAlignment()
3077 Q_D(QQuickTextInput);
3078 if (d->determineHorizontalAlignment()) {
3080 updateCursorRectangle();
3085
3086
3087
3088
3089
3090void QQuickTextInputPrivate::updateDisplayText(
bool forceUpdate)
3092 QString orig = m_textLayout.text();
3094 if (m_echoMode == QQuickTextInput::NoEcho)
3095 str = QString::fromLatin1(
"");
3099 if (m_echoMode == QQuickTextInput::Password) {
3100 str.fill(m_passwordCharacter);
3101 if (m_passwordEchoTimer.isActive() && m_cursor > 0 && m_cursor <= m_text.size()) {
3102 int cursor = m_cursor - 1;
3103 QChar uc = m_text.at(cursor);
3105 if (cursor > 0 && uc.unicode() >= 0xdc00 && uc.unicode() < 0xe000) {
3108 uc = m_text.at(cursor - 1);
3109 if (uc.unicode() >= 0xd800 && uc.unicode() < 0xdc00)
3110 str[cursor - 1] = uc;
3113 }
else if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit && !m_passwordEchoEditing) {
3114 str.fill(m_passwordCharacter);
3120 QChar* uc = str.data();
3121 for (
int i = 0; i < str.size(); ++i) {
3122 if (uc[i] == QChar::LineSeparator
3123 || uc[i] == QChar::ParagraphSeparator
3124 || uc[i] == QChar::ObjectReplacementCharacter)
3125 uc[i] = QChar(0x0020);
3128 if (str != orig || forceUpdate) {
3129 m_textLayout.setText(str);
3131 emit q_func()->displayTextChanged();
3135qreal QQuickTextInputPrivate::calculateImplicitWidthForText(
const QString &text)
const
3137 Q_Q(
const QQuickTextInput);
3138 QTextLayout layout(text);
3140 QTextOption option = m_textLayout.textOption();
3141 option.setTextDirection(m_layoutDirection);
3142 option.setFlags(QTextOption::IncludeTrailingSpaces);
3143 option.setWrapMode(QTextOption::WrapMode(wrapMode));
3144 option.setAlignment(Qt::Alignment(q->effectiveHAlign()));
3145 layout.setTextOption(option);
3146 layout.setFont(font);
3148 layout.setPreeditArea(m_textLayout.preeditAreaPosition(), m_textLayout.preeditAreaText());
3150 layout.beginLayout();
3152 QTextLine line = layout.createLine();
3153 line.setLineWidth(INT_MAX);
3154 const qreal theImplicitWidth = qCeil(line.naturalTextWidth()) + q->leftPadding() + q->rightPadding();
3157 return theImplicitWidth;
3160qreal QQuickTextInputPrivate::getImplicitWidth()
const
3162 Q_Q(
const QQuickTextInput);
3163 if (!requireImplicitWidth) {
3164 QQuickTextInputPrivate *d =
const_cast<QQuickTextInputPrivate *>(
this);
3165 d->requireImplicitWidth =
true;
3167 if (q->isComponentComplete())
3168 d->implicitWidth = calculateImplicitWidthForText(m_text);
3170 return implicitWidth;
3173void QQuickTextInputPrivate::setTopPadding(qreal value,
bool reset)
3175 Q_Q(QQuickTextInput);
3176 qreal oldPadding = q->topPadding();
3177 if (!reset || extra.isAllocated()) {
3178 extra.value().topPadding = value;
3179 extra.value().explicitTopPadding = !reset;
3181 if ((!reset && !qFuzzyCompare(oldPadding, value)) || (reset && !qFuzzyCompare(oldPadding, padding()))) {
3183 q->updateCursorRectangle();
3184 emit q->topPaddingChanged();
3188void QQuickTextInputPrivate::setLeftPadding(qreal value,
bool reset)
3190 Q_Q(QQuickTextInput);
3191 qreal oldPadding = q->leftPadding();
3192 if (!reset || extra.isAllocated()) {
3193 extra.value().leftPadding = value;
3194 extra.value().explicitLeftPadding = !reset;
3196 if ((!reset && !qFuzzyCompare(oldPadding, value)) || (reset && !qFuzzyCompare(oldPadding, padding()))) {
3198 q->updateCursorRectangle();
3199 emit q->leftPaddingChanged();
3203void QQuickTextInputPrivate::setRightPadding(qreal value,
bool reset)
3205 Q_Q(QQuickTextInput);
3206 qreal oldPadding = q->rightPadding();
3207 if (!reset || extra.isAllocated()) {
3208 extra.value().rightPadding = value;
3209 extra.value().explicitRightPadding = !reset;
3211 if ((!reset && !qFuzzyCompare(oldPadding, value)) || (reset && !qFuzzyCompare(oldPadding, padding()))) {
3213 q->updateCursorRectangle();
3214 emit q->rightPaddingChanged();
3218void QQuickTextInputPrivate::setBottomPadding(qreal value,
bool reset)
3220 Q_Q(QQuickTextInput);
3221 qreal oldPadding = q->bottomPadding();
3222 if (!reset || extra.isAllocated()) {
3223 extra.value().bottomPadding = value;
3224 extra.value().explicitBottomPadding = !reset;
3226 if ((!reset && !qFuzzyCompare(oldPadding, value)) || (reset && !qFuzzyCompare(oldPadding, padding()))) {
3228 q->updateCursorRectangle();
3229 emit q->bottomPaddingChanged();
3233bool QQuickTextInputPrivate::isImplicitResizeEnabled()
const
3235 return !extra.isAllocated() || extra->implicitResize;
3238void QQuickTextInputPrivate::setImplicitResizeEnabled(
bool enabled)
3241 extra.value().implicitResize =
false;
3242 else if (extra.isAllocated())
3243 extra->implicitResize =
true;
3246void QQuickTextInputPrivate::updateLayout()
3248 Q_Q(QQuickTextInput);
3250 if (!q->isComponentComplete())
3254 QTextOption option = m_textLayout.textOption();
3255 option.setTextDirection(layoutDirection());
3256 option.setWrapMode(QTextOption::WrapMode(wrapMode));
3257 option.setAlignment(Qt::Alignment(q->effectiveHAlign()));
3258 if (!qmlDisableDistanceField())
3259 option.setUseDesignMetrics(renderType != QQuickTextInput::NativeRendering);
3261 m_textLayout.setTextOption(option);
3262 m_textLayout.setFont(font);
3264 m_textLayout.beginLayout();
3266 QTextLine line = m_textLayout.createLine();
3267 if (requireImplicitWidth) {
3268 line.setLineWidth(INT_MAX);
3269 const bool wasInLayout = inLayout;
3271 if (isImplicitResizeEnabled())
3272 q->setImplicitWidth(qCeil(line.naturalTextWidth()) + q->leftPadding() + q->rightPadding());
3273 inLayout = wasInLayout;
3277 qreal lineWidth = q->widthValid() || !isImplicitResizeEnabled() ? q->width() - q->leftPadding() - q->rightPadding() : INT_MAX;
3281 line.setLineWidth(lineWidth);
3282 line.setPosition(QPointF(0, height));
3284 height += line.height();
3285 width = qMax(width, line.naturalTextWidth());
3287 line = m_textLayout.createLine();
3288 }
while (line.isValid());
3289 m_textLayout.endLayout();
3291 option.setWrapMode(QTextOption::NoWrap);
3292 m_textLayout.setTextOption(option);
3294 textLayoutDirty =
true;
3296 const QSizeF previousSize = contentSize;
3297 contentSize = QSizeF(width, height);
3299 updateType = UpdatePaintNode;
3303 if (isImplicitResizeEnabled()) {
3304 if (!requireImplicitWidth && !q->widthValid())
3305 q->setImplicitSize(width + q->leftPadding() + q->rightPadding(), height + q->topPadding() + q->bottomPadding());
3307 q->setImplicitHeight(height + q->topPadding() + q->bottomPadding());
3310 updateBaselineOffset();
3312 if (previousSize != contentSize)
3313 emit q->contentSizeChanged();
3317
3318
3319
3320
3321
3322void QQuickTextInputPrivate::updateBaselineOffset()
3324 Q_Q(QQuickTextInput);
3325 if (!q->isComponentComplete())
3327 QFontMetricsF fm(font);
3329 if (q->heightValid()) {
3330 const qreal surplusHeight = q->height() - contentSize.height() - q->topPadding() - q->bottomPadding();
3331 if (vAlign == QQuickTextInput::AlignBottom)
3332 yoff = surplusHeight;
3333 else if (vAlign == QQuickTextInput::AlignVCenter)
3334 yoff = surplusHeight/2;
3336 q->setBaselineOffset(fm.ascent() + yoff + q->topPadding());
3339#if QT_CONFIG(clipboard)
3341
3342
3343
3344
3345
3346
3347
3348
3349
3350void QQuickTextInputPrivate::copy(QClipboard::Mode mode)
const
3352 QString t = selectedText();
3353 if (!t.isEmpty() && m_echoMode == QQuickTextInput::Normal) {
3354 QGuiApplication::clipboard()->setText(t, mode);
3359
3360
3361
3362
3363
3364
3365
3366void QQuickTextInputPrivate::paste(QClipboard::Mode clipboardMode)
3368 QString clip = QGuiApplication::clipboard()->text(clipboardMode);
3369 if (!clip.isEmpty() || hasSelectedText()) {
3380
3381
3382void QQuickTextInputPrivate::commitPreedit()
3384 Q_Q(QQuickTextInput);
3389 QGuiApplication::inputMethod()->commit();
3394 QInputMethodEvent ev;
3395 QCoreApplication::sendEvent(q, &ev);
3398void QQuickTextInputPrivate::cancelPreedit()
3400 Q_Q(QQuickTextInput);
3405 QGuiApplication::inputMethod()->reset();
3407 QInputMethodEvent ev;
3408 QCoreApplication::sendEvent(q, &ev);
3413
3414
3415
3416
3417
3418
3419
3420
3421void QQuickTextInputPrivate::backspace()
3423 int priorState = m_undoState;
3424 if (separateSelection()) {
3425 removeSelectedText();
3426 }
else if (m_cursor) {
3429 m_cursor = prevMaskBlank(m_cursor);
3430 QChar uc = m_text.at(m_cursor);
3431 if (m_cursor > 0 && uc.unicode() >= 0xdc00 && uc.unicode() < 0xe000) {
3434 uc = m_text.at(m_cursor - 1);
3435 if (uc.unicode() >= 0xd800 && uc.unicode() < 0xdc00) {
3436 internalDelete(
true);
3440 internalDelete(
true);
3442 finishChange(priorState);
3446
3447
3448
3449
3450
3451
3452
3453
3454void QQuickTextInputPrivate::del()
3456 int priorState = m_undoState;
3457 if (separateSelection()) {
3458 removeSelectedText();
3460 int n = m_textLayout.nextCursorPosition(m_cursor) - m_cursor;
3464 finishChange(priorState);
3468
3469
3470
3471
3472
3473
3474void QQuickTextInputPrivate::insert(
const QString &newText)
3476 int priorState = m_undoState;
3477 if (separateSelection())
3478 removeSelectedText();
3479 internalInsert(newText);
3480 finishChange(priorState);
3484
3485
3486
3487
3488void QQuickTextInputPrivate::clear()
3490 int priorState = m_undoState;
3491 separateSelection();
3493 m_selend = m_text.size();
3494 removeSelectedText();
3496 finishChange(priorState,
false,
false);
3500
3501
3502
3503
3504
3505
3506
3507void QQuickTextInputPrivate::setSelection(
int start,
int length)
3509 Q_Q(QQuickTextInput);
3514 if (start < 0 || start > m_text.size()) {
3515 qWarning(
"QQuickTextInputPrivate::setSelection: Invalid start position");
3520 if (start == m_selstart && start + length == m_selend && m_cursor == m_selend)
3523 m_selend = qMin(start + length, m_text.size());
3524 m_cursor = m_selend;
3525 }
else if (length < 0) {
3526 if (start == m_selend && start + length == m_selstart && m_cursor == m_selstart)
3528 m_selstart = qMax(start + length, 0);
3530 m_cursor = m_selstart;
3531 }
else if (m_selstart != m_selend) {
3537 emitCursorPositionChanged();
3540 emit q->selectionChanged();
3541 emitCursorPositionChanged();
3543 q->updateInputMethod(Qt::ImCursorRectangle | Qt::ImAnchorRectangle | Qt::ImCursorPosition | Qt::ImAnchorPosition
3544 | Qt::ImCurrentSelection);
3549
3550
3551
3552
3553
3554
3555
3556void QQuickTextInputPrivate::updatePasswordEchoEditing(
bool editing)
3558 cancelPasswordEchoTimer();
3559 m_passwordEchoEditing = editing;
3560 updateDisplayText();
3564
3565
3566
3567
3568
3569
3570bool QQuickTextInputPrivate::fixup()
3572#if QT_CONFIG(validator)
3574 QString textCopy = m_text;
3575 int cursorCopy = m_cursor;
3576 m_validator->fixup(textCopy);
3577 if (m_validator->validate(textCopy, cursorCopy) == QValidator::Acceptable) {
3578 if (textCopy != m_text || cursorCopy != m_cursor)
3579 internalSetText(textCopy, cursorCopy);
3588
3589
3590
3591
3592
3593void QQuickTextInputPrivate::moveCursor(
int pos,
bool mark)
3595 Q_Q(QQuickTextInput);
3600 if (pos != m_cursor) {
3603 pos = pos > m_cursor ? nextMaskBlank(pos) : prevMaskBlank(pos);
3607 if (m_selend > m_selstart && m_cursor == m_selstart)
3609 else if (m_selend > m_selstart && m_cursor == m_selend)
3610 anchor = m_selstart;
3613 m_selstart = qMin(anchor, pos);
3614 m_selend = qMax(anchor, pos);
3619 if (mark || m_selDirty) {
3621 emit q->selectionChanged();
3623 emitCursorPositionChanged();
3625 q->updateInputMethod();
3631
3632
3633
3634
3635
3636void QQuickTextInputPrivate::processInputMethodEvent(QInputMethodEvent *event)
3638 Q_Q(QQuickTextInput);
3640 int priorState = -1;
3641 bool isGettingInput = !event->commitString().isEmpty()
3642 || event->preeditString() != preeditAreaText()
3643 || event->replacementLength() > 0;
3644 bool cursorPositionChanged =
false;
3645 bool selectionChange =
false;
3646 m_preeditDirty = event->preeditString() != preeditAreaText();
3648 if (isGettingInput) {
3650 priorState = m_undoState;
3651 separateSelection();
3652 if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit && !m_passwordEchoEditing) {
3653 updatePasswordEchoEditing(
true);
3655 m_selend = m_text.size();
3657 removeSelectedText();
3661 if (event->replacementStart() <= 0)
3662 c += event->commitString().size() - qMin(-event->replacementStart(), event->replacementLength());
3664 int cursorInsertPos = m_cursor + event->replacementStart();
3665 if (cursorInsertPos < 0)
3666 cursorInsertPos = 0;
3669 if (event->replacementLength()) {
3670 m_selstart = cursorInsertPos;
3671 m_selend = m_selstart + event->replacementLength();
3672 m_selend = qMin(m_selend, m_text.size());
3673 removeSelectedText();
3675 m_cursor = cursorInsertPos;
3677 if (!event->commitString().isEmpty()) {
3678 internalInsert(event->commitString());
3679 cursorPositionChanged =
true;
3681 m_cursor = qBound(0, c, m_text.size());
3684 for (
int i = 0; i < event->attributes().size(); ++i) {
3685 const QInputMethodEvent::Attribute &a = event->attributes().at(i);
3686 if (a.type == QInputMethodEvent::Selection) {
3693 if (!cursorPositionChanged || !m_maskData)
3694 m_cursor = qBound(0, a.start + a.length, m_text.size());
3696 m_selstart = qMax(0, qMin(a.start, m_text.size()));
3697 m_selend = m_cursor;
3698 if (m_selend < m_selstart) {
3699 qSwap(m_selstart, m_selend);
3701 selectionChange =
true;
3703 selectionChange = m_selstart != m_selend;
3704 m_selstart = m_selend = 0;
3706 cursorPositionChanged =
true;
3709 QString oldPreeditString = m_textLayout.preeditAreaText();
3710 m_textLayout.setPreeditArea(m_cursor, event->preeditString());
3711 if (oldPreeditString != m_textLayout.preeditAreaText()) {
3712 emit q->preeditTextChanged();
3713 if (!event->preeditString().isEmpty() && m_undoPreeditState == -1)
3715 m_undoPreeditState = priorState;
3717 const int oldPreeditCursor = m_preeditCursor;
3718 m_preeditCursor = event->preeditString().size();
3719 hasImState = !event->preeditString().isEmpty();
3720 bool cursorVisible =
true;
3721 QVector<QTextLayout::FormatRange> formats;
3722 for (
int i = 0; i < event->attributes().size(); ++i) {
3723 const QInputMethodEvent::Attribute &a = event->attributes().at(i);
3724 if (a.type == QInputMethodEvent::Cursor) {
3726 m_preeditCursor = a.start;
3727 cursorVisible = a.length != 0;
3728 }
else if (a.type == QInputMethodEvent::TextFormat) {
3730 QTextCharFormat f = qvariant_cast<QTextFormat>(a.value).toCharFormat();
3732 QTextLayout::FormatRange o;
3733 o.start = a.start + m_cursor;
3734 o.length = a.length;
3740 m_textLayout.setFormats(formats);
3746 q->setCursorVisible(cursorVisible);
3748 updateDisplayText(
true);
3749 if (cursorPositionChanged && emitCursorPositionChanged())
3750 q->updateInputMethod(Qt::ImCursorPosition | Qt::ImAnchorPosition);
3751 else if (m_preeditCursor != oldPreeditCursor || isGettingInput)
3752 q->updateCursorRectangle();
3755 finishChange(priorState);
3757 if (selectionChange) {
3758 emit q->selectionChanged();
3759 q->updateInputMethod(Qt::ImCursorRectangle | Qt::ImAnchorRectangle
3760 | Qt::ImCurrentSelection);
3764 if (event->preeditString().isEmpty())
3765 m_undoPreeditState = -1;
3771
3772
3773
3774
3775
3776
3777void QQuickTextInputPrivate::selectWordAtPos(
int cursor)
3779 int next = cursor + 1;
3782 int c = m_textLayout.previousCursorPosition(next, QTextLayout::SkipWords);
3783 moveCursor(c,
false);
3785 int end = m_textLayout.nextCursorPosition(c, QTextLayout::SkipWords);
3786 while (end > cursor && m_text.at(end - 1).isSpace())
3788 moveCursor(end,
true);
3792
3793
3794
3795
3796
3797
3798
3799
3800
3801
3802
3803bool QQuickTextInputPrivate::finishChange(
int validateFromState,
bool update,
bool edited)
3805 Q_Q(QQuickTextInput);
3809 bool inputMethodAttributesChanged = m_textDirty || m_selDirty;
3811 bool alignmentChanged =
false;
3812 bool textChanged =
false;
3816 bool wasValidInput = m_validInput;
3817 bool wasAcceptable = m_acceptableInput;
3818 m_validInput =
true;
3819 m_acceptableInput =
true;
3820#if QT_CONFIG(validator)
3822 QString textCopy = m_text;
3824 textCopy = maskString(0, m_text,
true);
3825 int cursorCopy = m_cursor;
3826 QValidator::State state = m_validator->validate(textCopy, cursorCopy);
3829 m_validInput = state != QValidator::Invalid;
3830 m_acceptableInput = state == QValidator::Acceptable;
3831 if (m_validInput && !m_maskData) {
3832 if (m_text != textCopy) {
3833 internalSetText(textCopy, cursorCopy);
3836 m_cursor = cursorCopy;
3846 if (m_undoPreeditState >= 0 && (m_undoPreeditState < validateFromState || validateFromState < 0))
3847 validateFromState = m_undoPreeditState;
3849 if (validateFromState >= 0 && wasValidInput && !m_validInput) {
3850 if (m_transactions.size())
3852 internalUndo(validateFromState);
3853 m_history.resize(m_undoState);
3854 m_validInput =
true;
3855 m_acceptableInput = wasAcceptable;
3856 m_textDirty =
false;
3861 m_textDirty =
false;
3863 m_preeditDirty =
false;
3865 alignmentChanged = determineHorizontalAlignment();
3867 emit q->textEdited();
3868 emit q->textChanged();
3871 updateDisplayText(alignmentChanged);
3873 if (m_acceptableInput != wasAcceptable)
3874 emit q->acceptableInputChanged();
3877 if (m_preeditDirty) {
3878 m_preeditDirty =
false;
3879 if (determineHorizontalAlignment()) {
3880 alignmentChanged =
true;
3888 emit q->selectionChanged();
3892 inputMethodAttributesChanged |= (m_cursor != m_lastCursorPos);
3893 if (inputMethodAttributesChanged)
3894 q->updateInputMethod();
3896 emitUndoRedoChanged();
3898 if (!emitCursorPositionChanged() && (alignmentChanged || textChanged))
3899 q->updateCursorRectangle();
3905
3906
3907
3908
3909void QQuickTextInputPrivate::internalSetText(
const QString &txt,
int pos,
bool edited)
3912 QString oldText = m_text;
3914 m_text = maskString(0, txt,
true);
3915 m_text += clearString(m_text.size(), m_maxLength - m_text.size());
3917 m_text = txt.isEmpty() ? txt : txt.left(m_maxLength);
3922 m_undoPreeditState = -1;
3924 m_cursor = (pos < 0 || pos > m_text.size()) ? m_text.size() : pos;
3925 m_textDirty = (oldText != m_text);
3927 bool changed = finishChange(-1,
true, edited);
3928#if !QT_CONFIG(accessibility)
3931 Q_Q(QQuickTextInput);
3932 if (changed && QAccessible::isActive()) {
3933 if (QObject *acc = QQuickAccessibleAttached::findAccessible(q, QAccessible::EditableText)) {
3934 QAccessibleTextUpdateEvent ev(acc, 0, oldText, m_text);
3935 QAccessible::updateAccessibility(&ev);
3943
3944
3945
3946
3947
3948void QQuickTextInputPrivate::addCommand(
const Command &cmd)
3950 if (m_separator && m_undoState && m_history[m_undoState - 1].type != Separator) {
3951 m_history.resize(m_undoState + 2);
3952 m_history[m_undoState++] = Command(Separator, m_cursor, u'\0', m_selstart, m_selend);
3954 m_history.resize(m_undoState + 1);
3956 m_separator =
false;
3957 m_history[m_undoState++] = cmd;
3961
3962
3963
3964
3965
3966
3967
3968
3969
3970void QQuickTextInputPrivate::internalInsert(
const QString &s)
3972 Q_Q(QQuickTextInput);
3973 if (m_echoMode == QQuickTextInput::Password) {
3974 if (m_passwordMaskDelay > 0)
3975 m_passwordEchoTimer.start(m_passwordMaskDelay, q);
3977 Q_ASSERT(!hasSelectedText());
3979 QString ms = maskString(m_cursor, s);
3980 for (
int i = 0; i < ms.size(); ++i) {
3981 addCommand (Command(DeleteSelection, m_cursor + i, m_text.at(m_cursor + i), -1, -1));
3982 addCommand(Command(Insert, m_cursor + i, ms.at(i), -1, -1));
3984 m_text.replace(m_cursor, ms.size(), ms);
3985 m_cursor += ms.size();
3986 m_cursor = nextMaskBlank(m_cursor);
3989 int remaining = m_maxLength - m_text.size();
3990 if (remaining != 0) {
3991 const QStringView remainingStr = QStringView{s}.left(remaining);
3992 m_text.insert(m_cursor, remainingStr);
3993 for (
auto e : remainingStr)
3994 addCommand(Command(Insert, m_cursor++, e, -1, -1));
4001
4002
4003
4004
4005
4006
4007
4008
4009
4010
4011void QQuickTextInputPrivate::internalDelete(
bool wasBackspace)
4013 if (m_cursor < m_text.size()) {
4014 cancelPasswordEchoTimer();
4015 Q_ASSERT(!hasSelectedText());
4016 addCommand(Command((CommandType)((m_maskData ? 2 : 0) + (wasBackspace ? Remove : Delete)),
4017 m_cursor, m_text.at(m_cursor), -1, -1));
4019 m_text.replace(m_cursor, 1, clearString(m_cursor, 1));
4020 addCommand(Command(Insert, m_cursor, m_text.at(m_cursor), -1, -1));
4022 m_text.remove(m_cursor, 1);
4029
4030
4031
4032
4033
4034
4035
4036
4037void QQuickTextInputPrivate::removeSelectedText()
4039 if (m_selstart < m_selend && m_selend <= m_text.size()) {
4040 cancelPasswordEchoTimer();
4042 if (m_selstart <= m_cursor && m_cursor < m_selend) {
4045 for (i = m_cursor; i >= m_selstart; --i)
4046 addCommand (Command(DeleteSelection, i, m_text.at(i), -1, 1));
4047 for (i = m_selend - 1; i > m_cursor; --i)
4048 addCommand (Command(DeleteSelection, i - m_cursor + m_selstart - 1, m_text.at(i), -1, -1));
4050 for (i = m_selend-1; i >= m_selstart; --i)
4051 addCommand (Command(RemoveSelection, i, m_text.at(i), -1, -1));
4054 m_text.replace(m_selstart, m_selend - m_selstart, clearString(m_selstart, m_selend - m_selstart));
4055 for (
int i = 0; i < m_selend - m_selstart; ++i)
4056 addCommand(Command(Insert, m_selstart + i, m_text.at(m_selstart + i), -1, -1));
4058 m_text.remove(m_selstart, m_selend - m_selstart);
4060 if (m_cursor > m_selstart)
4061 m_cursor -= qMin(m_cursor, m_selend) - m_selstart;
4068
4069
4070
4071
4072
4073
4075bool QQuickTextInputPrivate::separateSelection()
4077 if (hasSelectedText()) {
4079 addCommand(Command(SetSelection, m_cursor, u'\0', m_selstart, m_selend));
4087
4088
4089
4090
4091
4092void QQuickTextInputPrivate::parseInputMask(
const QString &maskFields)
4094 int delimiter = maskFields.indexOf(QLatin1Char(
';'));
4095 if (maskFields.isEmpty() || delimiter == 0) {
4097 m_maskData.reset(
nullptr);
4098 m_maxLength = 32767;
4099 internalSetText(QString());
4104 if (delimiter == -1) {
4105 m_blank = QLatin1Char(
' ');
4106 m_inputMask = maskFields;
4108 m_inputMask = maskFields.left(delimiter);
4109 m_blank = (delimiter + 1 < maskFields.size()) ? maskFields[delimiter + 1] : QLatin1Char(
' ');
4115 for (
int i=0; i<m_inputMask.size(); i++) {
4116 c = m_inputMask.at(i);
4117 if (i > 0 && m_inputMask.at(i-1) == QLatin1Char(
'\\')) {
4121 if (c != QLatin1Char(
'\\') && c != QLatin1Char(
'!') &&
4122 c != QLatin1Char(
'<') && c != QLatin1Char(
'>') &&
4123 c != QLatin1Char(
'{') && c != QLatin1Char(
'}') &&
4124 c != QLatin1Char(
'[') && c != QLatin1Char(
']'))
4128 m_maskData.reset(
new MaskInputData[m_maxLength]);
4130 MaskInputData::Casemode m = MaskInputData::NoCaseMode;
4133 bool escape =
false;
4135 for (
int i = 0; i < m_inputMask.size(); i++) {
4136 c = m_inputMask.at(i);
4139 m_maskData[index].maskChar = c;
4140 m_maskData[index].separator = s;
4141 m_maskData[index].caseMode = m;
4144 }
else if (c == QLatin1Char(
'<')) {
4145 m = MaskInputData::Lower;
4146 }
else if (c == QLatin1Char(
'>')) {
4147 m = MaskInputData::Upper;
4148 }
else if (c == QLatin1Char(
'!')) {
4149 m = MaskInputData::NoCaseMode;
4150 }
else if (c != QLatin1Char(
'{') && c != QLatin1Char(
'}') && c != QLatin1Char(
'[') && c != QLatin1Char(
']')) {
4151 switch (c.unicode()) {
4178 m_maskData[index].maskChar = c;
4179 m_maskData[index].separator = s;
4180 m_maskData[index].caseMode = m;
4185 internalSetText(m_text);
4190
4191
4192
4193
4194bool QQuickTextInputPrivate::isValidInput(QChar key, QChar mask)
const
4196 switch (mask.unicode()) {
4202 if (key.isLetter() || key == m_blank)
4206 if (key.isLetterOrNumber())
4210 if (key.isLetterOrNumber() || key == m_blank)
4214 if (key.isPrint() && key != m_blank)
4218 if (key.isPrint() || key == m_blank)
4226 if (key.isNumber() || key == m_blank)
4230 if (key.isNumber() && key.digitValue() > 0)
4234 if ((key.isNumber() && key.digitValue() > 0) || key == m_blank)
4238 if (key.isNumber() || key == QLatin1Char(
'+') || key == QLatin1Char(
'-') || key == m_blank)
4242 if (key == QLatin1Char(
'0') || key == QLatin1Char(
'1'))
4246 if (key == QLatin1Char(
'0') || key == QLatin1Char(
'1') || key == m_blank)
4250 if (key.isNumber() || (key >= QLatin1Char(
'a') && key <= QLatin1Char(
'f')) || (key >= QLatin1Char(
'A') && key <= QLatin1Char(
'F')))
4254 if (key.isNumber() || (key >= QLatin1Char(
'a') && key <= QLatin1Char(
'f')) || (key >= QLatin1Char(
'A') && key <= QLatin1Char(
'F')) || key == m_blank)
4264
4265
4266
4267
4268
4269
4270
4271QQuickTextInputPrivate::ValidatorState QQuickTextInputPrivate::hasAcceptableInput(
const QString &str)
const
4273#if QT_CONFIG(validator)
4274 QString textCopy = str;
4275 int cursorCopy = m_cursor;
4277 QValidator::State state = m_validator->validate(textCopy, cursorCopy);
4278 if (state != QValidator::Acceptable)
4279 return ValidatorState(state);
4284 return AcceptableInput;
4286 if (str.size() != m_maxLength)
4287 return InvalidInput;
4289 for (
int i=0; i < m_maxLength; ++i) {
4290 if (m_maskData[i].separator) {
4291 if (str.at(i) != m_maskData[i].maskChar)
4292 return InvalidInput;
4294 if (!isValidInput(str.at(i), m_maskData[i].maskChar))
4295 return InvalidInput;
4298 return AcceptableInput;
4302
4303
4304
4305
4306
4307
4308
4309QString QQuickTextInputPrivate::maskString(uint pos,
const QString &str,
bool clear)
const
4311 if (pos >= (uint)m_maxLength)
4312 return QString::fromLatin1(
"");
4315 fill = clear ? clearString(0, m_maxLength) : m_text;
4318 QString s = QString::fromLatin1(
"");
4320 while (i < m_maxLength) {
4321 if (strIndex < str.size()) {
4322 if (m_maskData[i].separator) {
4323 s += m_maskData[i].maskChar;
4324 if (str[strIndex] == m_maskData[i].maskChar)
4328 if (isValidInput(str[strIndex], m_maskData[i].maskChar)) {
4329 switch (m_maskData[i].caseMode) {
4330 case MaskInputData::Upper:
4331 s += str[strIndex].toUpper();
4333 case MaskInputData::Lower:
4334 s += str[strIndex].toLower();
4342 int n = findInMask(i,
true,
true, str[strIndex]);
4344 if (str.size() != 1 || i == 0 || (i > 0 && (!m_maskData[i-1].separator || m_maskData[i-1].maskChar != str[strIndex]))) {
4345 s += QStringView{fill}.mid(i, n-i+1);
4350 n = findInMask(i,
true,
false, str[strIndex]);
4352 s += QStringView{fill}.mid(i, n-i);
4353 switch (m_maskData[n].caseMode) {
4354 case MaskInputData::Upper:
4355 s += str[strIndex].toUpper();
4357 case MaskInputData::Lower:
4358 s += str[strIndex].toLower();
4379
4380
4381
4382
4383
4384QString QQuickTextInputPrivate::clearString(uint pos, uint len)
const
4386 if (pos >= (uint)m_maxLength)
4390 int end = qMin((uint)m_maxLength, pos + len);
4391 for (
int i = pos; i < end; ++i)
4392 if (m_maskData[i].separator)
4393 s += m_maskData[i].maskChar;
4401
4402
4403
4404
4405
4406QString QQuickTextInputPrivate::stripString(
const QString &str)
const
4412 int end = qMin(m_maxLength, str.size());
4413 for (
int i = 0; i < end; ++i) {
4414 if (m_maskData[i].separator)
4415 s += m_maskData[i].maskChar;
4416 else if (str[i] != m_blank)
4424
4425
4426
4427int QQuickTextInputPrivate::findInMask(
int pos,
bool forward,
bool findSeparator, QChar searchChar)
const
4429 if (pos >= m_maxLength || pos < 0)
4432 int end = forward ? m_maxLength : -1;
4433 int step = forward ? 1 : -1;
4437 if (findSeparator) {
4438 if (m_maskData[i].separator && m_maskData[i].maskChar == searchChar)
4441 if (!m_maskData[i].separator) {
4442 if (searchChar.isNull())
4444 else if (isValidInput(searchChar, m_maskData[i].maskChar))
4453void QQuickTextInputPrivate::internalUndo(
int until)
4455 if (!isUndoAvailable())
4457 cancelPasswordEchoTimer();
4459 while (m_undoState && m_undoState > until) {
4460 Command& cmd = m_history[--m_undoState];
4463 m_text.remove(cmd.pos, 1);
4467 m_selstart = cmd.selStart;
4468 m_selend = cmd.selEnd;
4472 case RemoveSelection:
4473 m_text.insert(cmd.pos, cmd.uc);
4474 m_cursor = cmd.pos + 1;
4477 case DeleteSelection:
4478 m_text.insert(cmd.pos, cmd.uc);
4484 if (until < 0 && m_undoState) {
4485 Command& next = m_history[m_undoState-1];
4486 if (next.type != cmd.type
4487 && next.type < RemoveSelection
4488 && (cmd.type < RemoveSelection || next.type == Separator)) {
4497void QQuickTextInputPrivate::internalRedo()
4499 if (!isRedoAvailable())
4502 while (m_undoState < m_history.size()) {
4503 Command& cmd = m_history[m_undoState++];
4506 m_text.insert(cmd.pos, cmd.uc);
4507 m_cursor = cmd.pos + 1;
4510 m_selstart = cmd.selStart;
4511 m_selend = cmd.selEnd;
4516 case RemoveSelection:
4517 case DeleteSelection:
4518 m_text.remove(cmd.pos, 1);
4519 m_selstart = cmd.selStart;
4520 m_selend = cmd.selEnd;
4524 m_selstart = cmd.selStart;
4525 m_selend = cmd.selEnd;
4529 if (m_undoState < m_history.size()) {
4530 Command& next = m_history[m_undoState];
4531 if (next.type != cmd.type
4532 && cmd.type < RemoveSelection
4533 && next.type != Separator
4534 && (next.type < RemoveSelection || cmd.type == Separator)) {
4542void QQuickTextInputPrivate::emitUndoRedoChanged()
4544 Q_Q(QQuickTextInput);
4545 const bool previousUndo = canUndo;
4546 const bool previousRedo = canRedo;
4548 canUndo = isUndoAvailable();
4549 canRedo = isRedoAvailable();
4551 if (previousUndo != canUndo)
4552 emit q->canUndoChanged();
4553 if (previousRedo != canRedo)
4554 emit q->canRedoChanged();
4558
4559
4560
4561
4562
4563bool QQuickTextInputPrivate::emitCursorPositionChanged()
4565 Q_Q(QQuickTextInput);
4566 if (m_cursor != m_lastCursorPos) {
4567 m_lastCursorPos = m_cursor;
4569 q->updateCursorRectangle();
4570 emit q->cursorPositionChanged();
4572 if (!hasSelectedText()) {
4573 if (lastSelectionStart != m_cursor) {
4574 lastSelectionStart = m_cursor;
4575 emit q->selectionStartChanged();
4577 if (lastSelectionEnd != m_cursor) {
4578 lastSelectionEnd = m_cursor;
4579 emit q->selectionEndChanged();
4583#if QT_CONFIG(accessibility)
4584 if (QAccessible::isActive()) {
4585 if (QObject *acc = QQuickAccessibleAttached::findAccessible(q, QAccessible::EditableText)) {
4586 QAccessibleTextCursorEvent ev(acc, m_cursor);
4587 QAccessible::updateAccessibility(&ev);
4598void QQuickTextInputPrivate::setBlinkingCursorEnabled(
bool enable)
4600 if (enable == m_blinkEnabled)
4603 m_blinkEnabled = enable;
4604 updateCursorBlinking();
4607 connect(qApp->styleHints(), &QStyleHints::cursorFlashTimeChanged,
this, &QQuickTextInputPrivate::updateCursorBlinking);
4609 disconnect(qApp->styleHints(), &QStyleHints::cursorFlashTimeChanged,
this, &QQuickTextInputPrivate::updateCursorBlinking);
4612void QQuickTextInputPrivate::updateCursorBlinking()
4614 Q_Q(QQuickTextInput);
4617 q->killTimer(m_blinkTimer);
4621 if (m_blinkEnabled && cursorVisible && !cursorItem && !m_readOnly) {
4622 int flashTime = QGuiApplication::styleHints()->cursorFlashTime();
4624 m_blinkTimer = q->startTimer(flashTime / 2);
4628 updateType = UpdatePaintNode;
4633void QQuickTextInput::timerEvent(QTimerEvent *event)
4635 Q_D(QQuickTextInput);
4636 if (event->timerId() == d->m_blinkTimer) {
4637 d->m_blinkStatus = !d->m_blinkStatus;
4638 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
4641 }
else if (event->timerId() == d->m_passwordEchoTimer.timerId()) {
4642 d->m_passwordEchoTimer.stop();
4643 d->updateDisplayText();
4644 updateCursorRectangle();
4648void QQuickTextInputPrivate::processKeyEvent(QKeyEvent* event)
4650 Q_Q(QQuickTextInput);
4652 if (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return) {
4653 if (hasAcceptableInput(m_text) == AcceptableInput || fixup()) {
4655 QInputMethod *inputMethod = QGuiApplication::inputMethod();
4656 inputMethod->commit();
4661 emit q->editingFinished();
4671 updateCursorBlinking();
4673 if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit
4674 && !m_passwordEchoEditing
4676 && !event->text().isEmpty()
4677 && !(event->modifiers() & Qt::ControlModifier)) {
4683 updatePasswordEchoEditing(
true);
4687 bool unknown =
false;
4688#if QT_CONFIG(shortcut)
4689 bool visual = cursorMoveStyle() == Qt::VisualMoveStyle;
4694#if QT_CONFIG(shortcut)
4695 else if (event == QKeySequence::Undo) {
4698 else if (event == QKeySequence::Redo) {
4701 else if (event == QKeySequence::SelectAll) {
4704#if QT_CONFIG(clipboard)
4705 else if (event == QKeySequence::Copy) {
4708 else if (event == QKeySequence::Paste) {
4710 QClipboard::Mode mode = QClipboard::Clipboard;
4714 else if (event == QKeySequence::Cut) {
4717 else if (event == QKeySequence::DeleteEndOfLine) {
4722 else if (event == QKeySequence::MoveToStartOfLine || event == QKeySequence::MoveToStartOfBlock) {
4725 else if (event == QKeySequence::MoveToEndOfLine || event == QKeySequence::MoveToEndOfBlock) {
4728 else if (event == QKeySequence::SelectStartOfLine || event == QKeySequence::SelectStartOfBlock) {
4731 else if (event == QKeySequence::SelectEndOfLine || event == QKeySequence::SelectEndOfBlock) {
4734 else if (event == QKeySequence::MoveToNextChar) {
4735 if (hasSelectedText()) {
4736 moveCursor(selectionEnd(),
false);
4738 cursorForward(0, visual ? 1 : (layoutDirection() == Qt::LeftToRight ? 1 : -1));
4741 else if (event == QKeySequence::SelectNextChar) {
4742 cursorForward(1, visual ? 1 : (layoutDirection() == Qt::LeftToRight ? 1 : -1));
4744 else if (event == QKeySequence::MoveToPreviousChar) {
4745 if (hasSelectedText()) {
4746 moveCursor(selectionStart(),
false);
4748 cursorForward(0, visual ? -1 : (layoutDirection() == Qt::LeftToRight ? -1 : 1));
4751 else if (event == QKeySequence::SelectPreviousChar) {
4752 cursorForward(1, visual ? -1 : (layoutDirection() == Qt::LeftToRight ? -1 : 1));
4754 else if (event == QKeySequence::MoveToNextWord) {
4755 if (m_echoMode == QQuickTextInput::Normal)
4756 layoutDirection() == Qt::LeftToRight ? cursorWordForward(0) : cursorWordBackward(0);
4758 layoutDirection() == Qt::LeftToRight ? end(0) : home(0);
4760 else if (event == QKeySequence::MoveToPreviousWord) {
4761 if (m_echoMode == QQuickTextInput::Normal)
4762 layoutDirection() == Qt::LeftToRight ? cursorWordBackward(0) : cursorWordForward(0);
4763 else if (!m_readOnly) {
4764 layoutDirection() == Qt::LeftToRight ? home(0) : end(0);
4767 else if (event == QKeySequence::SelectNextWord) {
4768 if (m_echoMode == QQuickTextInput::Normal)
4769 layoutDirection() == Qt::LeftToRight ? cursorWordForward(1) : cursorWordBackward(1);
4771 layoutDirection() == Qt::LeftToRight ? end(1) : home(1);
4773 else if (event == QKeySequence::SelectPreviousWord) {
4774 if (m_echoMode == QQuickTextInput::Normal)
4775 layoutDirection() == Qt::LeftToRight ? cursorWordBackward(1) : cursorWordForward(1);
4777 layoutDirection() == Qt::LeftToRight ? home(1) : end(1);
4779 else if (event == QKeySequence::Delete) {
4783 else if (event == QKeySequence::DeleteEndOfWord) {
4787 else if (event == QKeySequence::DeleteStartOfWord) {
4789 deleteStartOfWord();
4790 }
else if (event == QKeySequence::DeleteCompleteLine) {
4793#if QT_CONFIG(clipboard)
4801 bool handled =
false;
4802 if (event->modifiers() & Qt::ControlModifier) {
4803 switch (event->key()) {
4804 case Qt::Key_Backspace:
4806 deleteStartOfWord();
4813 switch (event->key()) {
4814 case Qt::Key_Backspace:
4826 if (event->key() == Qt::Key_Direction_L || event->key() == Qt::Key_Direction_R) {
4827 setLayoutDirection((event->key() == Qt::Key_Direction_L) ? Qt::LeftToRight : Qt::RightToLeft);
4831 if (unknown && !m_readOnly) {
4832 if (m_inputControl->isAcceptableInput(event)) {
4836 && !hasSelectedText()
4837 && !(m_cursor == q_func()->text().size())) {
4841 insert(event->text());
4854
4855
4856
4857
4859void QQuickTextInputPrivate::deleteStartOfWord()
4861 int priorState = m_undoState;
4863 if (!separateSelection()) {
4864 Command cmd(SetSelection, m_cursor, u'\0', m_selstart, m_selend);
4866 cursorWordBackward(
true);
4870 removeSelectedText();
4871 finishChange(priorState);
4875
4876
4877
4878
4880void QQuickTextInputPrivate::deleteEndOfWord()
4882 int priorState = m_undoState;
4883 Command cmd(SetSelection, m_cursor, u'\0', m_selstart, m_selend);
4885 cursorWordForward(
true);
4889 removeSelectedText();
4890 finishChange(priorState);
4894
4895
4896
4897
4899void QQuickTextInputPrivate::deleteEndOfLine()
4901 int priorState = m_undoState;
4902 Command cmd(SetSelection, m_cursor, u'\0', m_selstart, m_selend);
4904 setSelection(m_cursor, end());
4906 removeSelectedText();
4907 finishChange(priorState);
4911
4912
4913
4914
4915
4916
4917
4918
4919void QQuickTextInput::ensureVisible(
int position)
4921 Q_D(QQuickTextInput);
4922 d->ensureVisible(position);
4923 updateCursorRectangle(
false);
4927
4928
4929
4930
4931
4932
4933
4934
4935
4936
4937void QQuickTextInput::clear()
4939 Q_D(QQuickTextInput);
4945
4946
4947
4948
4949
4950
4951
4952
4953
4954
4955
4956
4957
4958
4959
4960
4961
4962
4963
4964
4965
4966
4967qreal QQuickTextInput::padding()
const
4969 Q_D(
const QQuickTextInput);
4970 return d->padding();
4973void QQuickTextInput::setPadding(qreal padding)
4975 Q_D(QQuickTextInput);
4976 if (qFuzzyCompare(d->padding(), padding))
4979 d->extra.value().padding = padding;
4981 updateCursorRectangle();
4982 emit paddingChanged();
4983 if (!d->extra.isAllocated() || !d->extra->explicitTopPadding)
4984 emit topPaddingChanged();
4985 if (!d->extra.isAllocated() || !d->extra->explicitLeftPadding)
4986 emit leftPaddingChanged();
4987 if (!d->extra.isAllocated() || !d->extra->explicitRightPadding)
4988 emit rightPaddingChanged();
4989 if (!d->extra.isAllocated() || !d->extra->explicitBottomPadding)
4990 emit bottomPaddingChanged();
4993void QQuickTextInput::resetPadding()
4998qreal QQuickTextInput::topPadding()
const
5000 Q_D(
const QQuickTextInput);
5001 if (d->extra.isAllocated() && d->extra->explicitTopPadding)
5002 return d->extra->topPadding;
5003 return d->padding();
5006void QQuickTextInput::setTopPadding(qreal padding)
5008 Q_D(QQuickTextInput);
5009 d->setTopPadding(padding);
5012void QQuickTextInput::resetTopPadding()
5014 Q_D(QQuickTextInput);
5015 d->setTopPadding(0,
true);
5018qreal QQuickTextInput::leftPadding()
const
5020 Q_D(
const QQuickTextInput);
5021 if (d->extra.isAllocated() && d->extra->explicitLeftPadding)
5022 return d->extra->leftPadding;
5023 return d->padding();
5026void QQuickTextInput::setLeftPadding(qreal padding)
5028 Q_D(QQuickTextInput);
5029 d->setLeftPadding(padding);
5032void QQuickTextInput::resetLeftPadding()
5034 Q_D(QQuickTextInput);
5035 d->setLeftPadding(0,
true);
5038qreal QQuickTextInput::rightPadding()
const
5040 Q_D(
const QQuickTextInput);
5041 if (d->extra.isAllocated() && d->extra->explicitRightPadding)
5042 return d->extra->rightPadding;
5043 return d->padding();
5046void QQuickTextInput::setRightPadding(qreal padding)
5048 Q_D(QQuickTextInput);
5049 d->setRightPadding(padding);
5052void QQuickTextInput::resetRightPadding()
5054 Q_D(QQuickTextInput);
5055 d->setRightPadding(0,
true);
5058qreal QQuickTextInput::bottomPadding()
const
5060 Q_D(
const QQuickTextInput);
5061 if (d->extra.isAllocated() && d->extra->explicitBottomPadding)
5062 return d->extra->bottomPadding;
5063 return d->padding();
5066void QQuickTextInput::setBottomPadding(qreal padding)
5068 Q_D(QQuickTextInput);
5069 d->setBottomPadding(padding);
5072void QQuickTextInput::resetBottomPadding()
5074 Q_D(QQuickTextInput);
5075 d->setBottomPadding(0,
true);
5078#if QT_VERSION < QT_VERSION_CHECK(7
, 0
, 0
)
5079void QQuickTextInput::setOldSelectionDefault()
5081 Q_D(QQuickTextInput);
5082 d->selectByMouse =
false;
5083 d->selectByTouchDrag =
true;
5084 qCDebug(lcQuickTextInput,
"pre-6.4 behavior chosen: selectByMouse defaults false; if enabled, touchscreen acts like a mouse");
5088QQuickPre64TextInput::QQuickPre64TextInput(QQuickItem *parent)
5089 : QQuickTextInput(parent)
5091 setOldSelectionDefault();
5097#include "moc_qquicktextinput_p.cpp"
Combined button and popup list for selecting options.