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);
97
98
99
100
101
102
103
104
105
106
107
108
109
110QString QQuickTextInput::text()
const
112 Q_D(
const QQuickTextInput);
114 QString content = d->m_text;
115 QString res = d->m_maskData ? d->stripString(content) : content;
116 return (res.isNull() ? QString::fromLatin1(
"") : res);
119void QQuickTextInput::invalidate()
121 Q_D(QQuickTextInput);
123 invalidateFontCaches();
126void QQuickTextInput::setText(
const QString &s)
128 Q_D(QQuickTextInput);
135 d->internalSetText(s, -1,
false);
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164QQuickTextInput::RenderType QQuickTextInput::renderType()
const
166 Q_D(
const QQuickTextInput);
167 return d->renderType;
170void QQuickTextInput::setRenderType(QQuickTextInput::RenderType renderType)
172 Q_D(QQuickTextInput);
173 if (d->renderType == renderType)
176 d->renderType = renderType;
177 emit renderTypeChanged();
179 if (isComponentComplete())
184
185
186
187
188
189
190
191
192
193
195int QQuickTextInput::length()
const
197 Q_D(
const QQuickTextInput);
198 return d->m_text.size();
202
203
204
205
206
207
209QString QQuickTextInput::getText(
int start,
int end)
const
211 Q_D(
const QQuickTextInput);
216 return d->m_text.mid(start, end - start);
219QString QQuickTextInputPrivate::realText()
const
221 QString res = m_maskData ? stripString(m_text) : m_text;
222 return (res.isNull() ? QString::fromLatin1(
"") : res);
226
227
228
229
230
231
232
233
236
237
238
239
240
241
242
243
246
247
248
249
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
273
274
275
276
279
280
281
282
285
286
287
288
291
292
293
294
297
298
299
300
301
302
303
306
307
308
309
310
311
312
315
316
317
318
319
320
321
322
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
342
343
344
345
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
373
374
375
376
377
378
379
380
381
382
383
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
403
404
405
406
407
410
411
412
413
414
417
418
419
420
421
424
425
426
427
428
429QFont QQuickTextInput::font()
const
431 Q_D(
const QQuickTextInput);
432 return d->sourceFont;
435void QQuickTextInput::setFont(
const QFont &font)
437 Q_D(QQuickTextInput);
438 if (d->sourceFont == font)
441 d->sourceFont = font;
442 QFont oldFont = d->font;
444 if (d->font.pointSizeF() != -1) {
446 qreal size = qRound(d->font.pointSizeF()*2.0);
447 d->font.setPointSizeF(size/2.0);
449 if (oldFont != d->font) {
451 updateCursorRectangle();
453 updateInputMethod(Qt::ImCursorRectangle | Qt::ImFont | Qt::ImAnchorRectangle);
456 emit fontChanged(d->sourceFont);
460
461
462
463
464QColor QQuickTextInput::color()
const
466 Q_D(
const QQuickTextInput);
470void QQuickTextInput::setColor(
const QColor &c)
472 Q_D(QQuickTextInput);
475 d->textLayoutDirty =
true;
476 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
485
486
487
488
489QColor QQuickTextInput::selectionColor()
const
491 Q_D(
const QQuickTextInput);
492 return d->selectionColor;
495void QQuickTextInput::setSelectionColor(
const QColor &color)
497 Q_D(QQuickTextInput);
498 if (d->selectionColor == color)
501 d->selectionColor = color;
502 if (d->hasSelectedText()) {
503 d->textLayoutDirty =
true;
504 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
508 emit selectionColorChanged();
511
512
513
514
515QColor QQuickTextInput::selectedTextColor()
const
517 Q_D(
const QQuickTextInput);
518 return d->selectedTextColor;
521void QQuickTextInput::setSelectedTextColor(
const QColor &color)
523 Q_D(QQuickTextInput);
524 if (d->selectedTextColor == color)
527 d->selectedTextColor = color;
528 if (d->hasSelectedText()) {
529 d->textLayoutDirty =
true;
530 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
534 emit selectedTextColorChanged();
538
539
540
541
542
543
544
545
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572QQuickTextInput::HAlignment QQuickTextInput::hAlign()
const
574 Q_D(
const QQuickTextInput);
578void QQuickTextInput::setHAlign(HAlignment align)
580 Q_D(QQuickTextInput);
582 if (d->setHAlign(align,
true) && isComponentComplete()) {
584 updateCursorRectangle();
588void QQuickTextInput::resetHAlign()
590 Q_D(QQuickTextInput);
591 d->hAlignImplicit =
true;
592 if (d->determineHorizontalAlignment() && isComponentComplete()) {
594 updateCursorRectangle();
598QQuickTextInput::HAlignment QQuickTextInput::effectiveHAlign()
const
600 Q_D(
const QQuickTextInput);
601 QQuickTextInput::HAlignment effectiveAlignment = d->hAlign;
602 if (!d->hAlignImplicit && d->effectiveLayoutMirror) {
604 case QQuickTextInput::AlignLeft:
605 effectiveAlignment = QQuickTextInput::AlignRight;
607 case QQuickTextInput::AlignRight:
608 effectiveAlignment = QQuickTextInput::AlignLeft;
614 return effectiveAlignment;
617bool QQuickTextInputPrivate::setHAlign(QQuickTextInput::HAlignment align,
bool forceAlign)
619 Q_Q(QQuickTextInput);
620 if (align > QQuickTextInput::AlignHCenter)
623 if (hAlign == align && !forceAlign)
626 const bool wasImplicit = hAlignImplicit;
627 const auto oldEffectiveHAlign = q->effectiveHAlign();
629 hAlignImplicit = !forceAlign;
630 if (hAlign != align) {
632 emit q->horizontalAlignmentChanged(align);
635 if (q->effectiveHAlign() != oldEffectiveHAlign) {
636 emit q->effectiveHorizontalAlignmentChanged();
640 if (forceAlign && wasImplicit) {
643 emit q->effectiveHorizontalAlignmentChanged();
648Qt::LayoutDirection QQuickTextInputPrivate::textDirection()
const
650 QString text = m_text;
653 text = m_textLayout.preeditAreaText();
656 const QChar *character = text.constData();
657 while (!character->isNull()) {
658 switch (character->direction()) {
660 return Qt::LeftToRight;
664 return Qt::RightToLeft;
670 return Qt::LayoutDirectionAuto;
673Qt::LayoutDirection QQuickTextInputPrivate::layoutDirection()
const
675 Qt::LayoutDirection direction = m_layoutDirection;
676 if (direction == Qt::LayoutDirectionAuto) {
677 direction = textDirection();
679 if (direction == Qt::LayoutDirectionAuto)
680 direction = QGuiApplication::inputMethod()->inputDirection();
683 return (direction == Qt::LayoutDirectionAuto) ? Qt::LeftToRight : direction;
686bool QQuickTextInputPrivate::determineHorizontalAlignment()
692 Qt::LayoutDirection direction = textDirection();
694 if (direction == Qt::LayoutDirectionAuto)
695 direction = QGuiApplication::inputMethod()->inputDirection();
698 const auto implicitHAlign = direction == Qt::RightToLeft ?
699 QQuickTextInput::AlignRight : QQuickTextInput::AlignLeft;
700 return setHAlign(implicitHAlign);
703QQuickTextInput::VAlignment QQuickTextInput::vAlign()
const
705 Q_D(
const QQuickTextInput);
709void QQuickTextInput::setVAlign(QQuickTextInput::VAlignment alignment)
711 Q_D(QQuickTextInput);
712 if (alignment == d->vAlign)
714 d->vAlign = alignment;
715 emit verticalAlignmentChanged(d->vAlign);
716 if (isComponentComplete()) {
717 updateCursorRectangle();
718 d->updateBaselineOffset();
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742QQuickTextInput::WrapMode QQuickTextInput::wrapMode()
const
744 Q_D(
const QQuickTextInput);
748void QQuickTextInput::setWrapMode(WrapMode mode)
750 Q_D(QQuickTextInput);
751 if (mode == d->wrapMode)
755 updateCursorRectangle();
756 emit wrapModeChanged();
759void QQuickTextInputPrivate::mirrorChange()
761 Q_Q(QQuickTextInput);
762 if (q->isComponentComplete()) {
763 if (!hAlignImplicit && (hAlign == QQuickTextInput::AlignRight || hAlign == QQuickTextInput::AlignLeft)) {
764 q->updateCursorRectangle();
765 emit q->effectiveHorizontalAlignmentChanged();
771
772
773
774
775
776
777
778
779bool QQuickTextInput::isReadOnly()
const
781 Q_D(
const QQuickTextInput);
782 return d->m_readOnly;
785void QQuickTextInput::setReadOnly(
bool ro)
787 Q_D(QQuickTextInput);
788 if (d->m_readOnly == ro)
792 setFlag(QQuickItem::ItemAcceptsInputMethod, !ro);
795 d->setCursorPosition(d->end());
797 updateInputMethod(Qt::ImEnabled);
800 d->emitUndoRedoChanged();
801 emit readOnlyChanged(ro);
803 setCursorVisible(
false);
804 }
else if (hasActiveFocus()) {
805 setCursorVisible(
true);
811
812
813
814
815
816
817
818int QQuickTextInput::maxLength()
const
820 Q_D(
const QQuickTextInput);
821 return d->m_maxLength;
824void QQuickTextInput::setMaxLength(
int ml)
826 Q_D(QQuickTextInput);
827 if (d->m_maxLength == ml || d->m_maskData)
831 d->internalSetText(d->m_text, -1,
false);
833 emit maximumLengthChanged(ml);
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862bool QQuickTextInput::isCursorVisible()
const
864 Q_D(
const QQuickTextInput);
865 return d->cursorVisible;
868void QQuickTextInput::setCursorVisible(
bool on)
870 Q_D(QQuickTextInput);
871 if (d->cursorVisible == on)
873 d->cursorVisible = on;
874 if (on && isComponentComplete())
875 QQuickTextUtil::createCursor(d);
877 d->updateCursorBlinking();
878 emit cursorVisibleChanged(d->cursorVisible);
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897int QQuickTextInput::cursorPosition()
const
899 Q_D(
const QQuickTextInput);
903void QQuickTextInput::setCursorPosition(
int cp)
905 Q_D(QQuickTextInput);
906 if (cp < 0 || cp > text().size())
912
913
914
915
916
917
918
919
920
922QRectF QQuickTextInput::cursorRectangle()
const
924 Q_D(
const QQuickTextInput);
928 c += d->m_preeditCursor;
930 if (d->m_echoMode == NoEcho)
932 QTextLine l = d->m_textLayout.lineForTextPosition(c);
935 qreal x = l.cursorToX(c) - d->hscroll + leftPadding();
936 qreal y = l.y() - d->vscroll + topPadding();
938 if (d->overwriteMode) {
939 if (c < text().size())
940 w = l.cursorToX(c + 1) - x;
942 w = QFontMetrics(font()).horizontalAdvance(QLatin1Char(
' '));
944 return QRectF(x, y, w, l.height());
948
949
950
951
952
953
954
955
956
957
958int QQuickTextInput::selectionStart()
const
960 Q_D(
const QQuickTextInput);
961 return d->lastSelectionStart;
964
965
966
967
968
969
970
971
972
973
974int QQuickTextInput::selectionEnd()
const
976 Q_D(
const QQuickTextInput);
977 return d->lastSelectionEnd;
980
981
982
983
984
985
986
987
988
989
990
991
992void QQuickTextInput::select(
int start,
int end)
994 Q_D(QQuickTextInput);
995 if (start < 0 || end < 0 || start > d->m_text.size() || end > d->m_text.size())
997 d->setSelection(start, end-start);
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015QString QQuickTextInput::selectedText()
const
1017 Q_D(
const QQuickTextInput);
1018 return d->selectedText();
1022
1023
1024
1025
1026
1027bool QQuickTextInput::focusOnPress()
const
1029 Q_D(
const QQuickTextInput);
1030 return d->focusOnPress;
1033void QQuickTextInput::setFocusOnPress(
bool b)
1035 Q_D(QQuickTextInput);
1036 if (d->focusOnPress == b)
1039 d->focusOnPress = b;
1041 emit activeFocusOnPressChanged(d->focusOnPress);
1044
1045
1046
1047
1048
1049
1050
1051bool QQuickTextInput::autoScroll()
const
1053 Q_D(
const QQuickTextInput);
1054 return d->autoScroll;
1057void QQuickTextInput::setAutoScroll(
bool b)
1059 Q_D(QQuickTextInput);
1060 if (d->autoScroll == b)
1065 updateCursorRectangle();
1066 emit autoScrollChanged(d->autoScroll);
1069#if QT_CONFIG(validator)
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1094QValidator* QQuickTextInput::validator()
const
1096 Q_D(
const QQuickTextInput);
1097 return d->m_validator;
1100void QQuickTextInput::setValidator(QValidator* v)
1102 Q_D(QQuickTextInput);
1103 if (d->m_validator == v)
1106 if (d->m_validator) {
1107 qmlobject_disconnect(
1108 d->m_validator, QValidator, SIGNAL(changed()),
1109 this, QQuickTextInput, SLOT(q_validatorChanged()));
1114 if (d->m_validator) {
1116 d->m_validator, QValidator, SIGNAL(changed()),
1117 this, QQuickTextInput, SLOT(q_validatorChanged()));
1120 if (isComponentComplete())
1123 emit validatorChanged();
1126void QQuickTextInput::q_validatorChanged()
1128 Q_D(QQuickTextInput);
1133QRectF QQuickTextInputPrivate::anchorRectangle()
const
1135 Q_Q(
const QQuickTextInput);
1142 if (m_selstart == m_selend)
1147 a = m_selstart == m_cursor ? m_selend : m_selstart;
1150 a += m_preeditCursor;
1152 if (m_echoMode == QQuickTextInput::NoEcho)
1154 QTextLine l = m_textLayout.lineForTextPosition(a);
1156 qreal x = l.cursorToX(a) - hscroll + q->leftPadding();
1157 qreal y = l.y() - vscroll + q->topPadding();
1158 rect.setRect(x, y, 1, l.height());
1164void QQuickTextInputPrivate::checkIsValid()
1166 Q_Q(QQuickTextInput);
1168 ValidatorState state = hasAcceptableInput(m_text);
1170 m_validInput = state != InvalidInput;
1171 if (state != AcceptableInput) {
1172 if (m_acceptableInput) {
1173 m_acceptableInput =
false;
1174 emit q->acceptableInputChanged();
1176 }
else if (!m_acceptableInput) {
1177 m_acceptableInput =
true;
1178 emit q->acceptableInputChanged();
1183
1184
1185
1186
1187
1188
1189
1190
1191QString QQuickTextInput::inputMask()
const
1193 Q_D(
const QQuickTextInput);
1194 return d->inputMask();
1197void QQuickTextInput::setInputMask(
const QString &im)
1199 Q_D(QQuickTextInput);
1200 QString canonicalInputMask = im;
1201 if (im.lastIndexOf(QLatin1Char(
';')) == -1)
1202 canonicalInputMask.append(QLatin1String(
"; "));
1203 if (d->inputMask() == canonicalInputMask)
1206 d->setInputMask(im);
1207 emit inputMaskChanged(d->inputMask());
1211
1212
1213
1214
1215
1216
1217
1218
1219bool QQuickTextInput::hasAcceptableInput()
const
1221 Q_D(
const QQuickTextInput);
1222 return d->m_acceptableInput;
1226
1227
1228
1229
1230
1231
1232
1233
1234
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1250
1251
1252
1253
1254
1255
1256
1257
1258
1261Qt::InputMethodHints QQuickTextInputPrivate::effectiveInputMethodHints()
const
1263 Qt::InputMethodHints hints = inputMethodHints;
1264 if (m_echoMode == QQuickTextInput::NoEcho)
1265 hints |= Qt::ImhHiddenText;
1266 else if (m_echoMode == QQuickTextInput::Password || m_echoMode == QQuickTextInput::PasswordEchoOnEdit)
1267 hints &= ~Qt::ImhHiddenText;
1268 if (m_echoMode != QQuickTextInput::Normal)
1269 hints |= (Qt::ImhNoAutoUppercase | Qt::ImhNoPredictiveText | Qt::ImhSensitiveData);
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288QQuickTextInput::EchoMode QQuickTextInput::echoMode()
const
1290 Q_D(
const QQuickTextInput);
1291 return QQuickTextInput::EchoMode(d->m_echoMode);
1294void QQuickTextInput::setEchoMode(QQuickTextInput::EchoMode echo)
1296 Q_D(QQuickTextInput);
1297 if (echoMode() == echo)
1299 d->cancelPasswordEchoTimer();
1300 d->m_echoMode = echo;
1301 d->m_passwordEchoEditing =
false;
1303 updateInputMethod(Qt::ImHints);
1305 d->updateDisplayText();
1306 updateCursorRectangle();
1311 if (d->m_echoMode != QQuickTextInput::Normal)
1312 d->m_text.reserve(30);
1314 emit echoModeChanged(echoMode());
1318
1319
1320
1321
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
1354Qt::InputMethodHints QQuickTextInput::inputMethodHints()
const
1359 Q_D(
const QQuickTextInput);
1360 return d->inputMethodHints;
1364void QQuickTextInput::setInputMethodHints(Qt::InputMethodHints hints)
1369 Q_D(QQuickTextInput);
1371 if (hints == d->inputMethodHints)
1374 d->inputMethodHints = hints;
1375 updateInputMethod(Qt::ImHints);
1376 emit inputMethodHintsChanged();
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393QQmlComponent* QQuickTextInput::cursorDelegate()
const
1395 Q_D(
const QQuickTextInput);
1396 return d->cursorComponent;
1399void QQuickTextInput::setCursorDelegate(QQmlComponent* c)
1401 Q_D(QQuickTextInput);
1402 QQuickTextUtil::setCursorDelegate(d, c);
1405void QQuickTextInput::createCursor()
1407 Q_D(QQuickTextInput);
1408 d->cursorPending =
true;
1409 QQuickTextUtil::createCursor(d);
1413
1414
1415
1416
1417
1418
1419
1420
1421QRectF QQuickTextInput::positionToRectangle(
int pos)
const
1423 Q_D(
const QQuickTextInput);
1424 if (d->m_echoMode == NoEcho)
1427 else if (pos > d->m_cursor)
1428 pos += d->preeditAreaText().size();
1430 QTextLine l = d->m_textLayout.lineForTextPosition(pos);
1433 qreal x = l.cursorToX(pos) - d->hscroll;
1434 qreal y = l.y() - d->vscroll;
1436 if (d->overwriteMode) {
1437 if (pos < text().size())
1438 w = l.cursorToX(pos + 1) - x;
1440 w = QFontMetrics(font()).horizontalAdvance(QLatin1Char(
' '));
1442 return QRectF(x, y, w, l.height());
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1468int QQuickTextInput::positionAt(qreal x, qreal y, QQuickTextInput::CursorPosition positionQuick)
const
1470 Q_D(
const QQuickTextInput);
1472 QTextLine::CursorPosition position = QTextLine::CursorPosition(positionQuick);
1474 int pos = d->positionAt(x, y, position);
1475 const int cursor = d->m_cursor;
1478 const int preeditLength = d->preeditAreaText().size();
1479 pos = pos > cursor + preeditLength
1480 ? pos - preeditLength
1489int QQuickTextInputPrivate::positionAt(qreal x, qreal y, QTextLine::CursorPosition position)
const
1491 Q_Q(
const QQuickTextInput);
1492 x += hscroll - q->leftPadding();
1493 y += vscroll - q->topPadding();
1494 QTextLine line = m_textLayout.lineAt(0);
1495 for (
int i = 1; i < m_textLayout.lineCount(); ++i) {
1496 QTextLine nextLine = m_textLayout.lineAt(i);
1498 if (y < (line.rect().bottom() + nextLine.y()) / 2)
1502 return line.isValid() ? line.xToCursor(x, position) : 0;
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520bool QQuickTextInput::overwriteMode()
const
1522 Q_D(
const QQuickTextInput);
1523 return d->overwriteMode;
1526void QQuickTextInput::setOverwriteMode(
bool overwrite)
1528 Q_D(QQuickTextInput);
1529 if (d->overwriteMode == overwrite)
1531 d->overwriteMode = overwrite;
1532 emit overwriteModeChanged(overwrite);
1535void QQuickTextInput::keyPressEvent(QKeyEvent* ev)
1537 Q_D(QQuickTextInput);
1539 bool ignore = (ev->key() == Qt::Key_Up || ev->key() == Qt::Key_Down) && ev->modifiers() == Qt::NoModifier;
1540 if (!ignore && (d->lastSelectionStart == d->lastSelectionEnd) && (ev->key() == Qt::Key_Right || ev->key() == Qt::Key_Left)) {
1543 int cursorPosition = d->m_cursor;
1544 if (cursorPosition == 0)
1545 ignore = ev->key() == (d->layoutDirection() == Qt::LeftToRight ? Qt::Key_Left : Qt::Key_Right);
1546 if (!ignore && cursorPosition == d->m_text.size())
1547 ignore = ev->key() == (d->layoutDirection() == Qt::LeftToRight ? Qt::Key_Right : Qt::Key_Left);
1552 d->processKeyEvent(ev);
1554 if (!ev->isAccepted())
1555 QQuickImplicitSizeItem::keyPressEvent(ev);
1559void QQuickTextInput::inputMethodEvent(QInputMethodEvent *ev)
1561 Q_D(QQuickTextInput);
1562 const bool wasComposing = d->hasImState;
1563 d->processInputMethodEvent(ev);
1564 if (!ev->isAccepted())
1565 QQuickImplicitSizeItem::inputMethodEvent(ev);
1567 if (wasComposing != d->hasImState)
1568 emit inputMethodComposingChanged();
1572void QQuickTextInput::mouseDoubleClickEvent(QMouseEvent *event)
1574 Q_D(QQuickTextInput);
1576 if (d->selectByMouse && event->button() == Qt::LeftButton &&
1577 QQuickDeliveryAgentPrivate::isEventFromMouseOrTouchpad(event)) {
1581 int cursor = d->positionAt(event->position());
1582 d->selectWordAtPos(cursor);
1583 event->setAccepted(
true);
1584 if (!d->hasPendingTripleClick()) {
1585 d->tripleClickStartPoint = event->position();
1586 d->tripleClickTimer.start();
1589 if (d->sendMouseEventToInputContext(event))
1591 QQuickImplicitSizeItem::mouseDoubleClickEvent(event);
1595void QQuickTextInput::mousePressEvent(QMouseEvent *event)
1597 Q_D(QQuickTextInput);
1599 d->pressPos = event->position();
1601 if (d->sendMouseEventToInputContext(event))
1604 d->hadSelectionOnMousePress = d->hasSelectedText();
1606 const bool isMouse = QQuickDeliveryAgentPrivate::isEventFromMouseOrTouchpad(event);
1607 if (d->selectByMouse &&
1609#if QT_VERSION < QT_VERSION_CHECK(7
, 0
, 0
)
1610 || d->selectByTouchDrag
1613 setKeepMouseGrab(
false);
1614 d->selectPressed =
true;
1615 QPointF distanceVector = d->pressPos - d->tripleClickStartPoint;
1616 if (d->hasPendingTripleClick()
1617 && distanceVector.manhattanLength() < QGuiApplication::styleHints()->startDragDistance()) {
1618 event->setAccepted(
true);
1625#if QT_VERSION < QT_VERSION_CHECK(7
, 0
, 0
)
1626 || d->selectByTouchDrag
1629 bool mark = (event->modifiers() & Qt::ShiftModifier) && d->selectByMouse;
1630 int cursor = d->positionAt(event->position());
1631 d->moveCursor(cursor, mark);
1634 if (d->focusOnPress && !qGuiApp->styleHints()->setFocusOnTouchRelease())
1635 ensureActiveFocus(Qt::MouseFocusReason);
1637 event->setAccepted(
true);
1640void QQuickTextInput::mouseMoveEvent(QMouseEvent *event)
1642 Q_D(QQuickTextInput);
1643 if (!QQuickDeliveryAgentPrivate::isEventFromMouseOrTouchpad(event)
1644#if QT_VERSION < QT_VERSION_CHECK(7
, 0
, 0
)
1645 && ! d->selectByTouchDrag
1650 if (d->selectPressed) {
1651 if (qAbs(
int(event->position().x() - d->pressPos.x())) > QGuiApplication::styleHints()->startDragDistance())
1652 setKeepMouseGrab(
true);
1655 if (d->composeMode()) {
1657 int startPos = d->positionAt(d->pressPos);
1658 int currentPos = d->positionAt(event->position());
1659 if (startPos != currentPos)
1660 d->setSelection(startPos, currentPos - startPos);
1664 moveCursorSelection(d->positionAt(event->position()), d->mouseSelectionMode);
1666 event->setAccepted(
true);
1668 QQuickImplicitSizeItem::mouseMoveEvent(event);
1672void QQuickTextInput::mouseReleaseEvent(QMouseEvent *event)
1674 Q_D(QQuickTextInput);
1675 if (d->sendMouseEventToInputContext(event))
1677 if (d->selectPressed) {
1678 d->selectPressed =
false;
1679 setKeepMouseGrab(
false);
1681 const bool isMouse = QQuickDeliveryAgentPrivate::isEventFromMouseOrTouchpad(event)
1682#if QT_VERSION < QT_VERSION_CHECK(7
, 0
, 0
)
1683 || d->selectByTouchDrag
1687#if QT_CONFIG(clipboard)
1688 if (isMouse && QGuiApplication::clipboard()->supportsSelection()) {
1689 if (event->button() == Qt::LeftButton) {
1690 d->copy(QClipboard::Selection);
1691 }
else if (!d->m_readOnly && event->button() == Qt::MiddleButton) {
1693 d->insert(QGuiApplication::clipboard()->text(QClipboard::Selection));
1702 if (!isMouse && (!d->hasSelectedText() || d->hadSelectionOnMousePress))
1703 d->moveCursor(d->positionAt(event->position()),
false);
1707 d->hadSelectionOnMousePress =
false;
1709 if (d->focusOnPress && qGuiApp->styleHints()->setFocusOnTouchRelease())
1710 ensureActiveFocus(Qt::MouseFocusReason);
1712 if (!event->isAccepted())
1713 QQuickImplicitSizeItem::mouseReleaseEvent(event);
1716#if QT_VERSION < QT_VERSION_CHECK(7
, 0
, 0
)
1717bool QQuickTextInputPrivate::handleContextMenuEvent(QContextMenuEvent *event)
1719bool QQuickTextInput::contextMenuEvent(QContextMenuEvent *event)
1722 Q_Q(QQuickTextInput);
1723 QContextMenuEvent mapped(event->reason(), q->cursorRectangle().center().toPoint(),
1724 event->globalPos(), event->modifiers());
1725 const bool eventProcessed = QQuickItemPrivate::handleContextMenuEvent(&mapped);
1726 event->setAccepted(mapped.isAccepted());
1727 return eventProcessed;
1730bool QQuickTextInputPrivate::sendMouseEventToInputContext(QMouseEvent *event)
1733 if (composeMode()) {
1734 int tmp_cursor = positionAt(event->position());
1735 int mousePos = tmp_cursor - m_cursor;
1736 if (mousePos >= 0 && mousePos <= m_textLayout.preeditAreaText().size()) {
1737 if (event->type() == QEvent::MouseButtonRelease) {
1738 QGuiApplication::inputMethod()->invokeAction(QInputMethod::Click, mousePos);
1750void QQuickTextInput::mouseUngrabEvent()
1752 Q_D(QQuickTextInput);
1753 d->selectPressed =
false;
1754 setKeepMouseGrab(
false);
1757bool QQuickTextInput::event(QEvent* ev)
1759#if QT_CONFIG(shortcut)
1760 Q_D(QQuickTextInput);
1761 if (ev->type() == QEvent::ShortcutOverride) {
1762 if (d->m_readOnly) {
1766 QKeyEvent* ke =
static_cast<QKeyEvent*>(ev);
1767 if (ke == QKeySequence::Copy
1768 || ke == QKeySequence::Paste
1769 || ke == QKeySequence::Cut
1770 || ke == QKeySequence::Redo
1771 || ke == QKeySequence::Undo
1772 || ke == QKeySequence::MoveToNextWord
1773 || ke == QKeySequence::MoveToPreviousWord
1774 || ke == QKeySequence::MoveToStartOfDocument
1775 || ke == QKeySequence::MoveToEndOfDocument
1776 || ke == QKeySequence::SelectNextWord
1777 || ke == QKeySequence::SelectPreviousWord
1778 || ke == QKeySequence::SelectStartOfLine
1779 || ke == QKeySequence::SelectEndOfLine
1780 || ke == QKeySequence::SelectStartOfBlock
1781 || ke == QKeySequence::SelectEndOfBlock
1782 || ke == QKeySequence::SelectStartOfDocument
1783 || ke == QKeySequence::SelectAll
1784 || ke == QKeySequence::SelectEndOfDocument
1785 || ke == QKeySequence::DeleteCompleteLine) {
1788 }
else if (ke->modifiers() == Qt::NoModifier || ke->modifiers() == Qt::ShiftModifier
1789 || ke->modifiers() == Qt::KeypadModifier) {
1790 if (ke->key() < Qt::Key_Escape) {
1794 switch (ke->key()) {
1795 case Qt::Key_Delete:
1798 case Qt::Key_Backspace:
1812 return QQuickImplicitSizeItem::event(ev);
1815void QQuickTextInput::geometryChange(
const QRectF &newGeometry,
1816 const QRectF &oldGeometry)
1818 Q_D(QQuickTextInput);
1820 if (newGeometry.width() != oldGeometry.width())
1822 else if (newGeometry.height() != oldGeometry.height() && d->vAlign != QQuickTextInput::AlignTop)
1823 d->updateBaselineOffset();
1824 updateCursorRectangle();
1826 QQuickImplicitSizeItem::geometryChange(newGeometry, oldGeometry);
1829void QQuickTextInput::itemChange(ItemChange change,
const ItemChangeData &value)
1831 Q_D(QQuickTextInput);
1834 case ItemDevicePixelRatioHasChanged:
1835 if (d->containsUnscalableGlyphs) {
1846 QQuickImplicitSizeItem::itemChange(change, value);
1849void QQuickTextInputPrivate::ensureVisible(
int position,
int preeditCursor,
int preeditLength)
1851 Q_Q(QQuickTextInput);
1852 QTextLine textLine = m_textLayout.lineForTextPosition(position + preeditCursor);
1853 const qreal width = qMax<qreal>(0, q->width() - q->leftPadding() - q->rightPadding());
1855 qreal widthUsed = 0;
1856 if (textLine.isValid()) {
1857 cix = textLine.cursorToX(position + preeditLength);
1858 const qreal cursorWidth = cix >= 0 ? cix : width - cix;
1859 widthUsed = qMax(textLine.naturalTextWidth(), cursorWidth);
1861 int previousScroll = hscroll;
1863 if (widthUsed <= width) {
1866 Q_ASSERT(textLine.isValid());
1867 if (cix - hscroll >= width) {
1869 hscroll = cix - width;
1870 }
else if (cix - hscroll < 0 && hscroll < widthUsed) {
1873 }
else if (widthUsed - hscroll < width) {
1876 hscroll = widthUsed - width;
1877 }
else if (width - hscroll > widthUsed) {
1880 hscroll = width - widthUsed;
1883 if (preeditLength > 0) {
1886 cix = textLine.cursorToX(position + qMax(0, preeditCursor - 1));
1892 if (previousScroll != hscroll)
1893 textLayoutDirty =
true;
1896void QQuickTextInputPrivate::updateHorizontalScroll()
1898 if (autoScroll && m_echoMode != QQuickTextInput::NoEcho) {
1900 const int preeditLength = m_textLayout.preeditAreaText().size();
1901 ensureVisible(m_cursor, m_preeditCursor, preeditLength);
1903 ensureVisible(m_cursor);
1910void QQuickTextInputPrivate::updateVerticalScroll()
1912 Q_Q(QQuickTextInput);
1914 const int preeditLength = m_textLayout.preeditAreaText().size();
1916 const qreal height = qMax<qreal>(0, q->height() - q->topPadding() - q->bottomPadding());
1917 qreal heightUsed = contentSize.height();
1918 qreal previousScroll = vscroll;
1920 if (!autoScroll || heightUsed <= height) {
1922 vscroll = -QQuickTextUtil::alignedY(
1923 heightUsed, height, vAlign & ~(Qt::AlignAbsolute|Qt::AlignHorizontal_Mask));
1926 QTextLine currentLine = m_textLayout.lineForTextPosition(m_cursor + preeditLength);
1928 QTextLine currentLine = m_textLayout.lineForTextPosition(m_cursor);
1930 QRectF r = currentLine.isValid() ? currentLine.rect() : QRectF();
1931 qreal top = r.top();
1932 int bottom = r.bottom();
1934 if (bottom - vscroll >= height) {
1936 vscroll = bottom - height;
1937 }
else if (top - vscroll < 0 && vscroll < heightUsed) {
1940 }
else if (heightUsed - vscroll < height) {
1943 vscroll = heightUsed - height;
1946 if (preeditLength > 0) {
1949 currentLine = m_textLayout.lineForTextPosition(m_cursor + qMax(0, m_preeditCursor - 1));
1950 top = currentLine.isValid() ? currentLine.rect().top() : 0;
1956 if (previousScroll != vscroll)
1957 textLayoutDirty =
true;
1960void QQuickTextInput::triggerPreprocess()
1962 Q_D(QQuickTextInput);
1963 if (d->updateType == QQuickTextInputPrivate::UpdateNone)
1964 d->updateType = QQuickTextInputPrivate::UpdateOnlyPreprocess;
1969void QQuickTextInput::updatePolish()
1971 invalidateFontCaches();
1974void QQuickTextInput::invalidateFontCaches()
1976 Q_D(QQuickTextInput);
1978 if (d->m_textLayout.engine() !=
nullptr)
1979 d->m_textLayout.engine()->resetFontEngineCache();
1982void QQuickTextInput::ensureActiveFocus(Qt::FocusReason reason)
1984 bool hadActiveFocus = hasActiveFocus();
1985 forceActiveFocus(reason);
1987 Q_D(QQuickTextInput);
1989 if (hasActiveFocus() && hadActiveFocus && !d->m_readOnly)
1990 qGuiApp->inputMethod()->show();
1992 Q_UNUSED(hadActiveFocus);
1996QSGNode *QQuickTextInput::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data)
1999 Q_D(QQuickTextInput);
2001 if (d->updateType != QQuickTextInputPrivate::UpdatePaintNode && oldNode !=
nullptr) {
2003 d->updateType = QQuickTextInputPrivate::UpdateNone;
2007 d->updateType = QQuickTextInputPrivate::UpdateNone;
2009 QSGInternalTextNode *node =
static_cast<QSGInternalTextNode *>(oldNode);
2010 if (node ==
nullptr)
2011 node = d->sceneGraphContext()->createInternalTextNode(d->sceneGraphRenderContext());
2014 const bool showCursor = !isReadOnly() && d->cursorItem ==
nullptr && d->cursorVisible && d->m_blinkStatus;
2016 if (!d->textLayoutDirty && oldNode !=
nullptr) {
2018 node->setCursor(cursorRectangle(), d->color);
2020 node->clearCursor();
2022 node->setRenderType(QSGTextNode::RenderType(d->renderType));
2024 node->setMatrix(QMatrix4x4());
2025 node->setTextStyle(QSGInternalTextNode::Normal);
2026 node->setColor(d->color);
2027 node->setSelectionTextColor(d->selectedTextColor);
2028 node->setSelectionColor(d->selectionColor);
2029 node->setFiltering(smooth() ? QSGTexture::Linear : QSGTexture::Nearest);
2031 if (flags().testFlag(ItemObservesViewport))
2032 node->setViewport(clipRect());
2034 node->setViewport(QRectF{});
2036 QPointF offset(leftPadding(), topPadding());
2037 if (d->autoScroll && d->m_textLayout.lineCount() > 0) {
2038 QFontMetricsF fm(d->font);
2040 offset += -QPointF(d->hscroll, d->vscroll + d->m_textLayout.lineAt(0).ascent() - fm.ascent());
2042 offset += -QPointF(d->hscroll, d->vscroll);
2045 if (!d->m_textLayout.text().isEmpty()
2047 || !d->m_textLayout.preeditAreaText().isEmpty()
2050 node->addTextLayout(offset, &d->m_textLayout,
2051 d->selectionStart(),
2052 d->selectionEnd() - 1);
2057 node->setCursor(cursorRectangle(), d->color);
2059 d->textLayoutDirty =
false;
2062 d->containsUnscalableGlyphs = node->containsUnscalableGlyphs();
2064 invalidateFontCaches();
2070QVariant QQuickTextInput::inputMethodQuery(Qt::InputMethodQuery property)
const
2074 if (property == Qt::ImEnterKeyType) {
2075 Q_D(
const QQuickItem);
2077 if (!d->extra.isAllocated()
2078 || d->extra->enterKeyAttached ==
nullptr
2079 || d->extra->enterKeyAttached->type() == Qt::EnterKeyDefault) {
2081 QQuickItem *next =
const_cast<QQuickTextInput*>(
this)->nextItemInFocusChain();
2082 QQuickItem *originalNext = next;
2083 while (next && next !=
this && !next->activeFocusOnTab()) {
2084 next = next->nextItemInFocusChain();
2085 if (next == originalNext) {
2091 const auto nextYPos = next->mapToGlobal(QPoint(0, 0)).y();
2092 const auto currentYPos =
this->mapToGlobal(QPoint(0, 0)).y();
2093 if (currentYPos < nextYPos)
2096 return Qt::EnterKeyNext;
2101 return inputMethodQuery(property, QVariant());
2104QVariant QQuickTextInput::inputMethodQuery(Qt::InputMethodQuery property,
const QVariant &argument)
const
2106 Q_D(
const QQuickTextInput);
2109 return QVariant((
bool)(flags() & ItemAcceptsInputMethod));
2111 return QVariant((
int) d->effectiveInputMethodHints());
2112 case Qt::ImCursorRectangle:
2113 return cursorRectangle();
2114 case Qt::ImAnchorRectangle:
2115 return d->anchorRectangle();
2118 case Qt::ImCursorPosition: {
2119 const QPointF pt = argument.toPointF();
2121 return QVariant(d->positionAt(pt));
2122 return QVariant(d->m_cursor);
2124 case Qt::ImSurroundingText:
2125 if (d->m_echoMode == PasswordEchoOnEdit && !d->m_passwordEchoEditing) {
2126 return QVariant(displayText());
2128 return QVariant(d->realText());
2130 case Qt::ImCurrentSelection:
2131 return QVariant(selectedText());
2132 case Qt::ImMaximumTextLength:
2133 return QVariant(maxLength());
2134 case Qt::ImAnchorPosition:
2135 if (d->selectionStart() == d->selectionEnd())
2136 return QVariant(d->m_cursor);
2137 else if (d->selectionStart() == d->m_cursor)
2138 return QVariant(d->selectionEnd());
2140 return QVariant(d->selectionStart());
2141 case Qt::ImAbsolutePosition:
2142 return QVariant(d->m_cursor);
2143 case Qt::ImTextAfterCursor:
2144 if (argument.isValid())
2145 return QVariant(d->m_text.mid(d->m_cursor, argument.toInt()));
2146 return QVariant(d->m_text.mid(d->m_cursor));
2147 case Qt::ImTextBeforeCursor:
2148 if (argument.isValid())
2149 return QVariant(QStringView{d->m_text}.left(d->m_cursor).right(argument.toInt()).toString());
2150 return QVariant(d->m_text.left(d->m_cursor));
2151 case Qt::ImReadOnly:
2152 return QVariant(d->m_readOnly);
2154 return QQuickItem::inputMethodQuery(property);
2160
2161
2162
2163
2164void QQuickTextInput::deselect()
2166 Q_D(QQuickTextInput);
2171
2172
2173
2174
2175void QQuickTextInput::selectAll()
2177 Q_D(QQuickTextInput);
2178 d->setSelection(0, text().size());
2182
2183
2184
2185
2186
2187bool QQuickTextInput::isRightToLeft(
int start,
int end)
2190 qmlWarning(
this) <<
"isRightToLeft(start, end) called with the end property being smaller than the start.";
2193 return QStringView{text()}.mid(start, end - start).isRightToLeft();
2197#if QT_CONFIG(clipboard)
2199
2200
2201
2202
2203
2204
2205
2206
2207void QQuickTextInput::cut()
2209 Q_D(QQuickTextInput);
2210 if (!d->m_readOnly && d->m_echoMode == QQuickTextInput::Normal) {
2217
2218
2219
2220
2221
2222
2223
2224
2225void QQuickTextInput::copy()
2227 Q_D(QQuickTextInput);
2232
2233
2234
2235
2236void QQuickTextInput::paste()
2238 Q_D(QQuickTextInput);
2245
2246
2247
2248
2249
2250
2252void QQuickTextInput::undo()
2254 Q_D(QQuickTextInput);
2255 if (!d->m_readOnly) {
2258 d->finishChange(-1,
true);
2263
2264
2265
2266
2268void QQuickTextInput::redo()
2270 Q_D(QQuickTextInput);
2271 if (!d->m_readOnly) {
2279
2280
2281
2282
2284void QQuickTextInput::insert(
int position,
const QString &text)
2286 Q_D(QQuickTextInput);
2287 if (d->m_echoMode == QQuickTextInput::Password) {
2288 if (d->m_passwordMaskDelay > 0)
2289 d->m_passwordEchoTimer.start(d->m_passwordMaskDelay,
this);
2291 if (position < 0 || position > d->m_text.size())
2294 const int priorState = d->m_undoState;
2296 QString insertText = text;
2298 if (d->hasSelectedText()) {
2299 d->addCommand(QQuickTextInputPrivate::Command(
2300 QQuickTextInputPrivate::SetSelection, d->m_cursor, u'\0', d->m_selstart, d->m_selend));
2302 if (d->m_maskData) {
2303 insertText = d->maskString(position, insertText);
2304 for (
int i = 0; i < insertText.size(); ++i) {
2305 d->addCommand(QQuickTextInputPrivate::Command(
2306 QQuickTextInputPrivate::DeleteSelection, position + i, d->m_text.at(position + i), -1, -1));
2307 d->addCommand(QQuickTextInputPrivate::Command(
2308 QQuickTextInputPrivate::Insert, position + i, insertText.at(i), -1, -1));
2310 d->m_text.replace(position, insertText.size(), insertText);
2311 if (!insertText.isEmpty())
2312 d->m_textDirty =
true;
2313 if (position < d->m_selend && position + insertText.size() > d->m_selstart)
2314 d->m_selDirty =
true;
2316 int remaining = d->m_maxLength - d->m_text.size();
2317 if (remaining != 0) {
2318 insertText = insertText.left(remaining);
2319 d->m_text.insert(position, insertText);
2320 for (
int i = 0; i < insertText.size(); ++i)
2321 d->addCommand(QQuickTextInputPrivate::Command(
2322 QQuickTextInputPrivate::Insert, position + i, insertText.at(i), -1, -1));
2323 if (d->m_cursor >= position)
2324 d->m_cursor += insertText.size();
2325 if (d->m_selstart >= position)
2326 d->m_selstart += insertText.size();
2327 if (d->m_selend >= position)
2328 d->m_selend += insertText.size();
2329 d->m_textDirty =
true;
2330 if (position >= d->m_selstart && position <= d->m_selend)
2331 d->m_selDirty =
true;
2335 d->addCommand(QQuickTextInputPrivate::Command(
2336 QQuickTextInputPrivate::SetSelection, d->m_cursor, u'\0', d->m_selstart, d->m_selend));
2337 d->finishChange(priorState);
2339 if (d->lastSelectionStart != d->lastSelectionEnd) {
2340 if (d->m_selstart != d->lastSelectionStart) {
2341 d->lastSelectionStart = d->m_selstart;
2342 emit selectionStartChanged();
2344 if (d->m_selend != d->lastSelectionEnd) {
2345 d->lastSelectionEnd = d->m_selend;
2346 emit selectionEndChanged();
2352
2353
2354
2355
2357void QQuickTextInput::remove(
int start,
int end)
2359 Q_D(QQuickTextInput);
2361 start = qBound(0, start, d->m_text.size());
2362 end = qBound(0, end, d->m_text.size());
2366 else if (start == end)
2369 if (start < d->m_selend && end > d->m_selstart)
2370 d->m_selDirty =
true;
2372 const int priorState = d->m_undoState;
2374 d->addCommand(QQuickTextInputPrivate::Command(
2375 QQuickTextInputPrivate::SetSelection, d->m_cursor, u'\0', d->m_selstart, d->m_selend));
2377 if (start <= d->m_cursor && d->m_cursor < end) {
2380 for (
int i = d->m_cursor; i >= start; --i) {
2381 d->addCommand(QQuickTextInputPrivate::Command(
2382 QQuickTextInputPrivate::DeleteSelection, i, d->m_text.at(i), -1, 1));
2384 for (
int i = end - 1; i > d->m_cursor; --i) {
2385 d->addCommand(QQuickTextInputPrivate::Command(
2386 QQuickTextInputPrivate::DeleteSelection, i - d->m_cursor + start - 1, d->m_text.at(i), -1, -1));
2389 for (
int i = end - 1; i >= start; --i) {
2390 d->addCommand(QQuickTextInputPrivate::Command(
2391 QQuickTextInputPrivate::RemoveSelection, i, d->m_text.at(i), -1, -1));
2394 if (d->m_maskData) {
2395 d->m_text.replace(start, end - start, d->clearString(start, end - start));
2396 for (
int i = 0; i < end - start; ++i) {
2397 d->addCommand(QQuickTextInputPrivate::Command(
2398 QQuickTextInputPrivate::Insert, start + i, d->m_text.at(start + i), -1, -1));
2401 d->m_text.remove(start, end - start);
2403 if (d->m_cursor > start)
2404 d->m_cursor -= qMin(d->m_cursor, end) - start;
2405 if (d->m_selstart > start)
2406 d->m_selstart -= qMin(d->m_selstart, end) - start;
2407 if (d->m_selend >= end)
2408 d->m_selend -= end - start;
2410 d->addCommand(QQuickTextInputPrivate::Command(
2411 QQuickTextInputPrivate::SetSelection, d->m_cursor, u'\0', d->m_selstart, d->m_selend));
2413 d->m_textDirty =
true;
2414 d->finishChange(priorState);
2416 if (d->lastSelectionStart != d->lastSelectionEnd) {
2417 if (d->m_selstart != d->lastSelectionStart) {
2418 d->lastSelectionStart = d->m_selstart;
2419 emit selectionStartChanged();
2421 if (d->m_selend != d->lastSelectionEnd) {
2422 d->lastSelectionEnd = d->m_selend;
2423 emit selectionEndChanged();
2430
2431
2432
2433
2434void QQuickTextInput::selectWord()
2436 Q_D(QQuickTextInput);
2437 d->selectWordAtPos(d->m_cursor);
2441
2442
2443
2444
2445
2446
2447
2448
2449
2450
2451QString QQuickTextInput::passwordCharacter()
const
2453 Q_D(
const QQuickTextInput);
2454 return QString(d->m_passwordCharacter);
2457void QQuickTextInput::setPasswordCharacter(
const QString &str)
2459 Q_D(QQuickTextInput);
2462 d->m_passwordCharacter = str.constData()[0];
2463 if (d->m_echoMode == Password || d->m_echoMode == PasswordEchoOnEdit)
2464 d->updateDisplayText();
2465 emit passwordCharacterChanged();
2469
2470
2471
2472
2473
2474
2475
2476int QQuickTextInput::passwordMaskDelay()
const
2478 Q_D(
const QQuickTextInput);
2479 return d->m_passwordMaskDelay;
2482void QQuickTextInput::setPasswordMaskDelay(
int delay)
2484 Q_D(QQuickTextInput);
2485 if (d->m_passwordMaskDelay != delay) {
2486 d->m_passwordMaskDelay = delay;
2487 emit passwordMaskDelayChanged(delay);
2491void QQuickTextInput::resetPasswordMaskDelay()
2493 setPasswordMaskDelay(qGuiApp->styleHints()->passwordMaskDelay());
2497
2498
2499
2500
2501
2502
2503
2504
2505
2506
2507
2508
2509
2510
2511
2512QString QQuickTextInput::displayText()
const
2514 Q_D(
const QQuickTextInput);
2515 return d->m_textLayout.text().insert(d->m_textLayout.preeditAreaPosition(), d->m_textLayout.preeditAreaText());
2519
2520
2521
2522
2523
2524
2525
2526
2527
2528
2529
2530QString QQuickTextInput::preeditText()
const
2532 Q_D(
const QQuickTextInput);
2533 return d->m_textLayout.preeditAreaText();
2537
2538
2539
2540
2541
2542
2543
2544
2545
2546
2547
2548
2549
2550
2551
2552
2553
2554bool QQuickTextInput::selectByMouse()
const
2556 Q_D(
const QQuickTextInput);
2557 return d->selectByMouse;
2560void QQuickTextInput::setSelectByMouse(
bool on)
2562 Q_D(QQuickTextInput);
2563 if (d->selectByMouse != on) {
2564 d->selectByMouse = on;
2565 emit selectByMouseChanged(on);
2570
2571
2572
2573
2574
2575
2576
2577
2578
2580QQuickTextInput::SelectionMode QQuickTextInput::mouseSelectionMode()
const
2582 Q_D(
const QQuickTextInput);
2583 return d->mouseSelectionMode;
2586void QQuickTextInput::setMouseSelectionMode(SelectionMode mode)
2588 Q_D(QQuickTextInput);
2589 if (d->mouseSelectionMode != mode) {
2590 d->mouseSelectionMode = mode;
2591 emit mouseSelectionModeChanged(mode);
2596
2597
2598
2599
2600
2602bool QQuickTextInput::persistentSelection()
const
2604 Q_D(
const QQuickTextInput);
2605 return d->persistentSelection;
2608void QQuickTextInput::setPersistentSelection(
bool on)
2610 Q_D(QQuickTextInput);
2611 if (d->persistentSelection == on)
2613 d->persistentSelection = on;
2614 emit persistentSelectionChanged();
2618
2619
2620
2621
2622
2623
2624bool QQuickTextInput::canPaste()
const
2626#if QT_CONFIG(clipboard)
2627 Q_D(
const QQuickTextInput);
2628 if (!d->canPasteValid) {
2629 if (
const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData())
2630 const_cast<QQuickTextInputPrivate *>(d)->canPaste = !d->m_readOnly && mimeData->hasText() && !mimeData->text().isEmpty();
2631 const_cast<QQuickTextInputPrivate *>(d)->canPasteValid =
true;
2640
2641
2642
2643
2644
2645
2647bool QQuickTextInput::canUndo()
const
2649 Q_D(
const QQuickTextInput);
2654
2655
2656
2657
2658
2659
2661bool QQuickTextInput::canRedo()
const
2663 Q_D(
const QQuickTextInput);
2668
2669
2670
2671
2672
2673
2675qreal QQuickTextInput::contentWidth()
const
2677 Q_D(
const QQuickTextInput);
2678 return d->contentSize.width();
2682
2683
2684
2685
2686
2687
2689qreal QQuickTextInput::contentHeight()
const
2691 Q_D(
const QQuickTextInput);
2692 return d->contentSize.height();
2695void QQuickTextInput::moveCursorSelection(
int position)
2697 Q_D(QQuickTextInput);
2698 d->moveCursor(position,
true);
2702
2703
2704
2705
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
2737void QQuickTextInput::moveCursorSelection(
int pos, SelectionMode mode)
2739 Q_D(QQuickTextInput);
2741 if (mode == SelectCharacters) {
2742 d->moveCursor(pos,
true);
2743 }
else if (pos != d->m_cursor) {
2744 const int cursor = d->m_cursor;
2746 if (!d->hasSelectedText())
2747 anchor = d->m_cursor;
2748 else if (d->selectionStart() == d->m_cursor)
2749 anchor = d->selectionEnd();
2751 anchor = d->selectionStart();
2753 if (anchor < pos || (anchor == pos && cursor < pos)) {
2754 const QString text =
this->text();
2755 QTextBoundaryFinder finder(QTextBoundaryFinder::Word, text);
2756 finder.setPosition(anchor);
2758 const QTextBoundaryFinder::BoundaryReasons reasons = finder.boundaryReasons();
2759 if (anchor < text.size() && (reasons == QTextBoundaryFinder::NotAtBoundary
2760 || (reasons & QTextBoundaryFinder::EndOfItem))) {
2761 finder.toPreviousBoundary();
2763 anchor = finder.position() != -1 ? finder.position() : 0;
2765 finder.setPosition(pos);
2766 if (pos > 0 && !finder.boundaryReasons())
2767 finder.toNextBoundary();
2768 const int cursor = finder.position() != -1 ? finder.position() : text.size();
2770 d->setSelection(anchor, cursor - anchor);
2771 }
else if (anchor > pos || (anchor == pos && cursor > pos)) {
2772 const QString text =
this->text();
2773 QTextBoundaryFinder finder(QTextBoundaryFinder::Word, text);
2774 finder.setPosition(anchor);
2776 const QTextBoundaryFinder::BoundaryReasons reasons = finder.boundaryReasons();
2777 if (anchor > 0 && (reasons == QTextBoundaryFinder::NotAtBoundary
2778 || (reasons & QTextBoundaryFinder::StartOfItem))) {
2779 finder.toNextBoundary();
2781 anchor = finder.position() != -1 ? finder.position() : text.size();
2783 finder.setPosition(pos);
2784 if (pos < text.size() && !finder.boundaryReasons())
2785 finder.toPreviousBoundary();
2786 const int cursor = finder.position() != -1 ? finder.position() : 0;
2788 d->setSelection(anchor, cursor - anchor);
2793void QQuickTextInput::focusInEvent(QFocusEvent *event)
2795 Q_D(QQuickTextInput);
2796 d->handleFocusEvent(event);
2797 QQuickImplicitSizeItem::focusInEvent(event);
2800void QQuickTextInputPrivate::handleFocusEvent(QFocusEvent *event)
2802 Q_Q(QQuickTextInput);
2803 bool focus = event->gotFocus();
2805 q->setCursorVisible(focus);
2806 setBlinkingCursorEnabled(focus);
2809 q->q_updateAlignment();
2811 if (focusOnPress && !m_readOnly)
2812 qGuiApp->inputMethod()->show();
2813 q->connect(QGuiApplication::inputMethod(), SIGNAL(inputDirectionChanged(Qt::LayoutDirection)),
2814 q, SLOT(q_updateAlignment()));
2817 if ((m_passwordEchoEditing || m_passwordEchoTimer.isActive())) {
2818 updatePasswordEchoEditing(
false);
2821 if (event->reason() != Qt::ActiveWindowFocusReason
2822 && event->reason() != Qt::PopupFocusReason
2823 && hasSelectedText()
2824 && !persistentSelection)
2827 if (hasAcceptableInput(m_text) == AcceptableInput || fixup())
2828 emit q->editingFinished();
2831 q->disconnect(QGuiApplication::inputMethod(), SIGNAL(inputDirectionChanged(Qt::LayoutDirection)),
2832 q, SLOT(q_updateAlignment()));
2837void QQuickTextInput::focusOutEvent(QFocusEvent *event)
2839 Q_D(QQuickTextInput);
2840 d->handleFocusEvent(event);
2841 QQuickImplicitSizeItem::focusOutEvent(event);
2845
2846
2847
2848
2849
2850
2851
2852
2853
2854
2855
2856bool QQuickTextInput::isInputMethodComposing()
const
2861 Q_D(
const QQuickTextInput);
2862 return d->hasImState;
2866QQuickTextInputPrivate::ExtraData::ExtraData()
2872 , explicitTopPadding(
false)
2873 , explicitLeftPadding(
false)
2874 , explicitRightPadding(
false)
2875 , explicitBottomPadding(
false)
2876 , implicitResize(
true)
2880void QQuickTextInputPrivate::init()
2882 Q_Q(QQuickTextInput);
2883#if QT_CONFIG(clipboard)
2884 if (QGuiApplication::clipboard()->supportsSelection())
2885 q->setAcceptedMouseButtons(Qt::LeftButton | Qt::MiddleButton);
2888 q->setAcceptedMouseButtons(Qt::LeftButton);
2891 q->setFlag(QQuickItem::ItemAcceptsInputMethod);
2893 q->setFlag(QQuickItem::ItemHasContents);
2894#if QT_CONFIG(clipboard)
2895 qmlobject_connect(QGuiApplication::clipboard(), QClipboard, SIGNAL(dataChanged()),
2896 q, QQuickTextInput, SLOT(q_canPasteChanged()));
2899 lastSelectionStart = 0;
2900 lastSelectionEnd = 0;
2901 determineHorizontalAlignment();
2903 if (!qmlDisableDistanceField()) {
2904 QTextOption option = m_textLayout.textOption();
2905 option.setUseDesignMetrics(renderType != QQuickTextInput::NativeRendering);
2906 m_textLayout.setTextOption(option);
2909 m_inputControl =
new QInputControl(QInputControl::LineEdit, q);
2910 setSizePolicy(QLayoutPolicy::Expanding, QLayoutPolicy::Fixed);
2913void QQuickTextInputPrivate::cancelInput()
2916 Q_Q(QQuickTextInput);
2917 if (!m_readOnly && q->hasActiveFocus() && qGuiApp)
2922void QQuickTextInput::updateCursorRectangle(
bool scroll)
2924 Q_D(QQuickTextInput);
2925 if (!isComponentComplete())
2929 d->updateHorizontalScroll();
2930 d->updateVerticalScroll();
2932 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
2935 emit cursorRectangleChanged();
2936 if (d->cursorItem) {
2937 QRectF r = cursorRectangle();
2938 d->cursorItem->setPosition(r.topLeft());
2939 d->cursorItem->setHeight(r.height());
2942 updateInputMethod(Qt::ImCursorRectangle | Qt::ImAnchorRectangle);
2946void QQuickTextInput::selectionChanged()
2948 Q_D(QQuickTextInput);
2949 d->textLayoutDirty =
true;
2950 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
2953 emit selectedTextChanged();
2955 if (d->lastSelectionStart != d->selectionStart()) {
2956 d->lastSelectionStart = d->selectionStart();
2957 if (d->lastSelectionStart == -1)
2958 d->lastSelectionStart = d->m_cursor;
2959 emit selectionStartChanged();
2961 if (d->lastSelectionEnd != d->selectionEnd()) {
2962 d->lastSelectionEnd = d->selectionEnd();
2963 if (d->lastSelectionEnd == -1)
2964 d->lastSelectionEnd = d->m_cursor;
2965 emit selectionEndChanged();
2969QRectF QQuickTextInput::boundingRect()
const
2971 Q_D(
const QQuickTextInput);
2973 int cursorWidth = d->cursorItem ? 0 : 1;
2975 qreal hscroll = d->hscroll;
2976 if (!d->autoScroll || d->contentSize.width() < width())
2977 hscroll -= QQuickTextUtil::alignedX(d->contentSize.width(), width(), effectiveHAlign());
2980 QRectF r(-hscroll, -d->vscroll, d->contentSize.width(), d->contentSize.height());
2981 r.setRight(r.right() + cursorWidth);
2985QRectF QQuickTextInput::clipRect()
const
2987 Q_D(
const QQuickTextInput);
2989 int cursorWidth = d->cursorItem ? d->cursorItem->width() : 1;
2992 QRectF r = QQuickImplicitSizeItem::clipRect();
2993 r.setRight(r.right() + cursorWidth);
2997void QQuickTextInput::q_canPasteChanged()
2999 Q_D(QQuickTextInput);
3000 bool old = d->canPaste;
3001#if QT_CONFIG(clipboard)
3002 if (
const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData())
3003 d->canPaste = !d->m_readOnly && mimeData->hasText();
3005 d->canPaste =
false;
3008 bool changed = d->canPaste != old || !d->canPasteValid;
3009 d->canPasteValid =
true;
3011 emit canPasteChanged();
3015void QQuickTextInput::q_updateAlignment()
3017 Q_D(QQuickTextInput);
3018 if (d->determineHorizontalAlignment()) {
3020 updateCursorRectangle();
3025
3026
3027
3028
3029
3030void QQuickTextInputPrivate::updateDisplayText(
bool forceUpdate)
3032 QString orig = m_textLayout.text();
3034 if (m_echoMode == QQuickTextInput::NoEcho)
3035 str = QString::fromLatin1(
"");
3039 if (m_echoMode == QQuickTextInput::Password) {
3040 str.fill(m_passwordCharacter);
3041 if (m_passwordEchoTimer.isActive() && m_cursor > 0 && m_cursor <= m_text.size()) {
3042 int cursor = m_cursor - 1;
3043 QChar uc = m_text.at(cursor);
3045 if (cursor > 0 && uc.unicode() >= 0xdc00 && uc.unicode() < 0xe000) {
3048 uc = m_text.at(cursor - 1);
3049 if (uc.unicode() >= 0xd800 && uc.unicode() < 0xdc00)
3050 str[cursor - 1] = uc;
3053 }
else if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit && !m_passwordEchoEditing) {
3054 str.fill(m_passwordCharacter);
3060 QChar* uc = str.data();
3061 for (
int i = 0; i < str.size(); ++i) {
3062 if (uc[i] == QChar::LineSeparator
3063 || uc[i] == QChar::ParagraphSeparator
3064 || uc[i] == QChar::ObjectReplacementCharacter)
3065 uc[i] = QChar(0x0020);
3068 if (str != orig || forceUpdate) {
3069 m_textLayout.setText(str);
3071 emit q_func()->displayTextChanged();
3075qreal QQuickTextInputPrivate::calculateImplicitWidthForText(
const QString &text)
const
3077 Q_Q(
const QQuickTextInput);
3078 QTextLayout layout(text);
3080 QTextOption option = m_textLayout.textOption();
3081 option.setTextDirection(m_layoutDirection);
3082 option.setFlags(QTextOption::IncludeTrailingSpaces);
3083 option.setWrapMode(QTextOption::WrapMode(wrapMode));
3084 option.setAlignment(Qt::Alignment(q->effectiveHAlign()));
3085 layout.setTextOption(option);
3086 layout.setFont(font);
3088 layout.setPreeditArea(m_textLayout.preeditAreaPosition(), m_textLayout.preeditAreaText());
3090 layout.beginLayout();
3092 QTextLine line = layout.createLine();
3093 line.setLineWidth(INT_MAX);
3094 const qreal theImplicitWidth = qCeil(line.naturalTextWidth()) + q->leftPadding() + q->rightPadding();
3097 return theImplicitWidth;
3100qreal QQuickTextInputPrivate::getImplicitWidth()
const
3102 Q_Q(
const QQuickTextInput);
3103 if (!requireImplicitWidth) {
3104 QQuickTextInputPrivate *d =
const_cast<QQuickTextInputPrivate *>(
this);
3105 d->requireImplicitWidth =
true;
3107 if (q->isComponentComplete())
3108 d->implicitWidth = calculateImplicitWidthForText(m_text);
3110 return implicitWidth;
3113void QQuickTextInputPrivate::setTopPadding(qreal value,
bool reset)
3115 Q_Q(QQuickTextInput);
3116 qreal oldPadding = q->topPadding();
3117 if (!reset || extra.isAllocated()) {
3118 extra.value().topPadding = value;
3119 extra.value().explicitTopPadding = !reset;
3121 if ((!reset && !qFuzzyCompare(oldPadding, value)) || (reset && !qFuzzyCompare(oldPadding, padding()))) {
3123 q->updateCursorRectangle();
3124 emit q->topPaddingChanged();
3128void QQuickTextInputPrivate::setLeftPadding(qreal value,
bool reset)
3130 Q_Q(QQuickTextInput);
3131 qreal oldPadding = q->leftPadding();
3132 if (!reset || extra.isAllocated()) {
3133 extra.value().leftPadding = value;
3134 extra.value().explicitLeftPadding = !reset;
3136 if ((!reset && !qFuzzyCompare(oldPadding, value)) || (reset && !qFuzzyCompare(oldPadding, padding()))) {
3138 q->updateCursorRectangle();
3139 emit q->leftPaddingChanged();
3143void QQuickTextInputPrivate::setRightPadding(qreal value,
bool reset)
3145 Q_Q(QQuickTextInput);
3146 qreal oldPadding = q->rightPadding();
3147 if (!reset || extra.isAllocated()) {
3148 extra.value().rightPadding = value;
3149 extra.value().explicitRightPadding = !reset;
3151 if ((!reset && !qFuzzyCompare(oldPadding, value)) || (reset && !qFuzzyCompare(oldPadding, padding()))) {
3153 q->updateCursorRectangle();
3154 emit q->rightPaddingChanged();
3158void QQuickTextInputPrivate::setBottomPadding(qreal value,
bool reset)
3160 Q_Q(QQuickTextInput);
3161 qreal oldPadding = q->bottomPadding();
3162 if (!reset || extra.isAllocated()) {
3163 extra.value().bottomPadding = value;
3164 extra.value().explicitBottomPadding = !reset;
3166 if ((!reset && !qFuzzyCompare(oldPadding, value)) || (reset && !qFuzzyCompare(oldPadding, padding()))) {
3168 q->updateCursorRectangle();
3169 emit q->bottomPaddingChanged();
3173bool QQuickTextInputPrivate::isImplicitResizeEnabled()
const
3175 return !extra.isAllocated() || extra->implicitResize;
3178void QQuickTextInputPrivate::setImplicitResizeEnabled(
bool enabled)
3181 extra.value().implicitResize =
false;
3182 else if (extra.isAllocated())
3183 extra->implicitResize =
true;
3186void QQuickTextInputPrivate::updateLayout()
3188 Q_Q(QQuickTextInput);
3190 if (!q->isComponentComplete())
3194 QTextOption option = m_textLayout.textOption();
3195 option.setTextDirection(layoutDirection());
3196 option.setWrapMode(QTextOption::WrapMode(wrapMode));
3197 option.setAlignment(Qt::Alignment(q->effectiveHAlign()));
3198 if (!qmlDisableDistanceField())
3199 option.setUseDesignMetrics(renderType != QQuickTextInput::NativeRendering);
3201 m_textLayout.setTextOption(option);
3202 m_textLayout.setFont(font);
3204 m_textLayout.beginLayout();
3206 QTextLine line = m_textLayout.createLine();
3207 if (requireImplicitWidth) {
3208 line.setLineWidth(INT_MAX);
3209 const bool wasInLayout = inLayout;
3211 if (isImplicitResizeEnabled())
3212 q->setImplicitWidth(qCeil(line.naturalTextWidth()) + q->leftPadding() + q->rightPadding());
3213 inLayout = wasInLayout;
3217 qreal lineWidth = q->widthValid() || !isImplicitResizeEnabled() ? q->width() - q->leftPadding() - q->rightPadding() : INT_MAX;
3221 line.setLineWidth(lineWidth);
3222 line.setPosition(QPointF(0, height));
3224 height += line.height();
3225 width = qMax(width, line.naturalTextWidth());
3227 line = m_textLayout.createLine();
3228 }
while (line.isValid());
3229 m_textLayout.endLayout();
3231 option.setWrapMode(QTextOption::NoWrap);
3232 m_textLayout.setTextOption(option);
3234 textLayoutDirty =
true;
3236 const QSizeF previousSize = contentSize;
3237 contentSize = QSizeF(width, height);
3239 updateType = UpdatePaintNode;
3243 if (isImplicitResizeEnabled()) {
3244 if (!requireImplicitWidth && !q->widthValid())
3245 q->setImplicitSize(width + q->leftPadding() + q->rightPadding(), height + q->topPadding() + q->bottomPadding());
3247 q->setImplicitHeight(height + q->topPadding() + q->bottomPadding());
3250 updateBaselineOffset();
3252 if (previousSize != contentSize)
3253 emit q->contentSizeChanged();
3257
3258
3259
3260
3261
3262void QQuickTextInputPrivate::updateBaselineOffset()
3264 Q_Q(QQuickTextInput);
3265 if (!q->isComponentComplete())
3267 QFontMetricsF fm(font);
3269 if (q->heightValid()) {
3270 const qreal surplusHeight = q->height() - contentSize.height() - q->topPadding() - q->bottomPadding();
3271 if (vAlign == QQuickTextInput::AlignBottom)
3272 yoff = surplusHeight;
3273 else if (vAlign == QQuickTextInput::AlignVCenter)
3274 yoff = surplusHeight/2;
3276 q->setBaselineOffset(fm.ascent() + yoff + q->topPadding());
3279#if QT_CONFIG(clipboard)
3281
3282
3283
3284
3285
3286
3287
3288
3289
3290void QQuickTextInputPrivate::copy(QClipboard::Mode mode)
const
3292 QString t = selectedText();
3293 if (!t.isEmpty() && m_echoMode == QQuickTextInput::Normal) {
3294 QGuiApplication::clipboard()->setText(t, mode);
3299
3300
3301
3302
3303
3304
3305
3306void QQuickTextInputPrivate::paste(QClipboard::Mode clipboardMode)
3308 QString clip = QGuiApplication::clipboard()->text(clipboardMode);
3309 if (!clip.isEmpty() || hasSelectedText()) {
3320
3321
3322void QQuickTextInputPrivate::commitPreedit()
3324 Q_Q(QQuickTextInput);
3329 QGuiApplication::inputMethod()->commit();
3334 QInputMethodEvent ev;
3335 QCoreApplication::sendEvent(q, &ev);
3338void QQuickTextInputPrivate::cancelPreedit()
3340 Q_Q(QQuickTextInput);
3345 QGuiApplication::inputMethod()->reset();
3347 QInputMethodEvent ev;
3348 QCoreApplication::sendEvent(q, &ev);
3353
3354
3355
3356
3357
3358
3359
3360
3361void QQuickTextInputPrivate::backspace()
3363 int priorState = m_undoState;
3364 if (separateSelection()) {
3365 removeSelectedText();
3366 }
else if (m_cursor) {
3369 m_cursor = prevMaskBlank(m_cursor);
3370 QChar uc = m_text.at(m_cursor);
3371 if (m_cursor > 0 && uc.unicode() >= 0xdc00 && uc.unicode() < 0xe000) {
3374 uc = m_text.at(m_cursor - 1);
3375 if (uc.unicode() >= 0xd800 && uc.unicode() < 0xdc00) {
3376 internalDelete(
true);
3380 internalDelete(
true);
3382 finishChange(priorState);
3386
3387
3388
3389
3390
3391
3392
3393
3394void QQuickTextInputPrivate::del()
3396 int priorState = m_undoState;
3397 if (separateSelection()) {
3398 removeSelectedText();
3400 int n = m_textLayout.nextCursorPosition(m_cursor) - m_cursor;
3404 finishChange(priorState);
3408
3409
3410
3411
3412
3413
3414void QQuickTextInputPrivate::insert(
const QString &newText)
3416 int priorState = m_undoState;
3417 if (separateSelection())
3418 removeSelectedText();
3419 internalInsert(newText);
3420 finishChange(priorState);
3424
3425
3426
3427
3428void QQuickTextInputPrivate::clear()
3430 int priorState = m_undoState;
3431 separateSelection();
3433 m_selend = m_text.size();
3434 removeSelectedText();
3436 finishChange(priorState,
false,
false);
3440
3441
3442
3443
3444
3445
3446
3447void QQuickTextInputPrivate::setSelection(
int start,
int length)
3449 Q_Q(QQuickTextInput);
3454 if (start < 0 || start > m_text.size()) {
3455 qWarning(
"QQuickTextInputPrivate::setSelection: Invalid start position");
3460 if (start == m_selstart && start + length == m_selend && m_cursor == m_selend)
3463 m_selend = qMin(start + length, m_text.size());
3464 m_cursor = m_selend;
3465 }
else if (length < 0) {
3466 if (start == m_selend && start + length == m_selstart && m_cursor == m_selstart)
3468 m_selstart = qMax(start + length, 0);
3470 m_cursor = m_selstart;
3471 }
else if (m_selstart != m_selend) {
3477 emitCursorPositionChanged();
3480 emit q->selectionChanged();
3481 emitCursorPositionChanged();
3483 q->updateInputMethod(Qt::ImCursorRectangle | Qt::ImAnchorRectangle | Qt::ImCursorPosition | Qt::ImAnchorPosition
3484 | Qt::ImCurrentSelection);
3489
3490
3491
3492
3493
3494
3495
3496void QQuickTextInputPrivate::updatePasswordEchoEditing(
bool editing)
3498 cancelPasswordEchoTimer();
3499 m_passwordEchoEditing = editing;
3500 updateDisplayText();
3504
3505
3506
3507
3508
3509
3510bool QQuickTextInputPrivate::fixup()
3512#if QT_CONFIG(validator)
3514 QString textCopy = m_text;
3515 int cursorCopy = m_cursor;
3516 m_validator->fixup(textCopy);
3517 if (m_validator->validate(textCopy, cursorCopy) == QValidator::Acceptable) {
3518 if (textCopy != m_text || cursorCopy != m_cursor)
3519 internalSetText(textCopy, cursorCopy);
3528
3529
3530
3531
3532
3533void QQuickTextInputPrivate::moveCursor(
int pos,
bool mark)
3535 Q_Q(QQuickTextInput);
3540 if (pos != m_cursor) {
3543 pos = pos > m_cursor ? nextMaskBlank(pos) : prevMaskBlank(pos);
3547 if (m_selend > m_selstart && m_cursor == m_selstart)
3549 else if (m_selend > m_selstart && m_cursor == m_selend)
3550 anchor = m_selstart;
3553 m_selstart = qMin(anchor, pos);
3554 m_selend = qMax(anchor, pos);
3559 if (mark || m_selDirty) {
3561 emit q->selectionChanged();
3563 emitCursorPositionChanged();
3565 q->updateInputMethod();
3571
3572
3573
3574
3575
3576void QQuickTextInputPrivate::processInputMethodEvent(QInputMethodEvent *event)
3578 Q_Q(QQuickTextInput);
3580 int priorState = -1;
3581 bool isGettingInput = !event->commitString().isEmpty()
3582 || event->preeditString() != preeditAreaText()
3583 || event->replacementLength() > 0;
3584 bool cursorPositionChanged =
false;
3585 bool selectionChange =
false;
3586 m_preeditDirty = event->preeditString() != preeditAreaText();
3588 if (isGettingInput) {
3590 priorState = m_undoState;
3591 separateSelection();
3592 if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit && !m_passwordEchoEditing) {
3593 updatePasswordEchoEditing(
true);
3595 m_selend = m_text.size();
3597 removeSelectedText();
3601 if (event->replacementStart() <= 0)
3602 c += event->commitString().size() - qMin(-event->replacementStart(), event->replacementLength());
3604 int cursorInsertPos = m_cursor + event->replacementStart();
3605 if (cursorInsertPos < 0)
3606 cursorInsertPos = 0;
3609 if (event->replacementLength()) {
3610 m_selstart = cursorInsertPos;
3611 m_selend = m_selstart + event->replacementLength();
3612 m_selend = qMin(m_selend, m_text.size());
3613 removeSelectedText();
3615 m_cursor = cursorInsertPos;
3617 if (!event->commitString().isEmpty()) {
3618 internalInsert(event->commitString());
3619 cursorPositionChanged =
true;
3621 m_cursor = qBound(0, c, m_text.size());
3624 for (
int i = 0; i < event->attributes().size(); ++i) {
3625 const QInputMethodEvent::Attribute &a = event->attributes().at(i);
3626 if (a.type == QInputMethodEvent::Selection) {
3633 if (!cursorPositionChanged || !m_maskData)
3634 m_cursor = qBound(0, a.start + a.length, m_text.size());
3636 m_selstart = qMax(0, qMin(a.start, m_text.size()));
3637 m_selend = m_cursor;
3638 if (m_selend < m_selstart) {
3639 qSwap(m_selstart, m_selend);
3641 selectionChange =
true;
3643 selectionChange = m_selstart != m_selend;
3644 m_selstart = m_selend = 0;
3646 cursorPositionChanged =
true;
3649 QString oldPreeditString = m_textLayout.preeditAreaText();
3650 m_textLayout.setPreeditArea(m_cursor, event->preeditString());
3651 if (oldPreeditString != m_textLayout.preeditAreaText()) {
3652 emit q->preeditTextChanged();
3653 if (!event->preeditString().isEmpty() && m_undoPreeditState == -1)
3655 m_undoPreeditState = priorState;
3657 const int oldPreeditCursor = m_preeditCursor;
3658 m_preeditCursor = event->preeditString().size();
3659 hasImState = !event->preeditString().isEmpty();
3660 bool cursorVisible =
true;
3661 QVector<QTextLayout::FormatRange> formats;
3662 for (
int i = 0; i < event->attributes().size(); ++i) {
3663 const QInputMethodEvent::Attribute &a = event->attributes().at(i);
3664 if (a.type == QInputMethodEvent::Cursor) {
3666 m_preeditCursor = a.start;
3667 cursorVisible = a.length != 0;
3668 }
else if (a.type == QInputMethodEvent::TextFormat) {
3670 QTextCharFormat f = qvariant_cast<QTextFormat>(a.value).toCharFormat();
3672 QTextLayout::FormatRange o;
3673 o.start = a.start + m_cursor;
3674 o.length = a.length;
3680 m_textLayout.setFormats(formats);
3682 updateDisplayText(
true);
3683 if (cursorPositionChanged && emitCursorPositionChanged())
3684 q->updateInputMethod(Qt::ImCursorPosition | Qt::ImAnchorPosition);
3685 else if (m_preeditCursor != oldPreeditCursor || isGettingInput)
3686 q->updateCursorRectangle();
3689 finishChange(priorState);
3691 q->setCursorVisible(cursorVisible);
3693 if (selectionChange) {
3694 emit q->selectionChanged();
3695 q->updateInputMethod(Qt::ImCursorRectangle | Qt::ImAnchorRectangle
3696 | Qt::ImCurrentSelection);
3700 if (event->preeditString().isEmpty())
3701 m_undoPreeditState = -1;
3707
3708
3709
3710
3711
3712
3713void QQuickTextInputPrivate::selectWordAtPos(
int cursor)
3715 int next = cursor + 1;
3718 int c = m_textLayout.previousCursorPosition(next, QTextLayout::SkipWords);
3719 moveCursor(c,
false);
3721 int end = m_textLayout.nextCursorPosition(c, QTextLayout::SkipWords);
3722 while (end > cursor && m_text.at(end - 1).isSpace())
3724 moveCursor(end,
true);
3728
3729
3730
3731
3732
3733
3734
3735
3736
3737
3738
3739bool QQuickTextInputPrivate::finishChange(
int validateFromState,
bool update,
bool edited)
3741 Q_Q(QQuickTextInput);
3745 bool inputMethodAttributesChanged = m_textDirty || m_selDirty;
3747 bool alignmentChanged =
false;
3748 bool textChanged =
false;
3752 bool wasValidInput = m_validInput;
3753 bool wasAcceptable = m_acceptableInput;
3754 m_validInput =
true;
3755 m_acceptableInput =
true;
3756#if QT_CONFIG(validator)
3758 QString textCopy = m_text;
3760 textCopy = maskString(0, m_text,
true);
3761 int cursorCopy = m_cursor;
3762 QValidator::State state = m_validator->validate(textCopy, cursorCopy);
3765 m_validInput = state != QValidator::Invalid;
3766 m_acceptableInput = state == QValidator::Acceptable;
3767 if (m_validInput && !m_maskData) {
3768 if (m_text != textCopy) {
3769 internalSetText(textCopy, cursorCopy);
3772 m_cursor = cursorCopy;
3782 if (m_undoPreeditState >= 0 && (m_undoPreeditState < validateFromState || validateFromState < 0))
3783 validateFromState = m_undoPreeditState;
3785 if (validateFromState >= 0 && wasValidInput && !m_validInput) {
3786 if (m_transactions.size())
3788 internalUndo(validateFromState);
3789 m_history.resize(m_undoState);
3790 m_validInput =
true;
3791 m_acceptableInput = wasAcceptable;
3792 m_textDirty =
false;
3797 m_textDirty =
false;
3799 m_preeditDirty =
false;
3801 alignmentChanged = determineHorizontalAlignment();
3803 emit q->textEdited();
3804 emit q->textChanged();
3807 updateDisplayText(alignmentChanged);
3809 if (m_acceptableInput != wasAcceptable)
3810 emit q->acceptableInputChanged();
3813 if (m_preeditDirty) {
3814 m_preeditDirty =
false;
3815 if (determineHorizontalAlignment()) {
3816 alignmentChanged =
true;
3824 emit q->selectionChanged();
3828 inputMethodAttributesChanged |= (m_cursor != m_lastCursorPos);
3829 if (inputMethodAttributesChanged)
3830 q->updateInputMethod();
3832 emitUndoRedoChanged();
3834 if (!emitCursorPositionChanged() && (alignmentChanged || textChanged))
3835 q->updateCursorRectangle();
3841
3842
3843
3844
3845void QQuickTextInputPrivate::internalSetText(
const QString &txt,
int pos,
bool edited)
3848 QString oldText = m_text;
3850 m_text = maskString(0, txt,
true);
3851 m_text += clearString(m_text.size(), m_maxLength - m_text.size());
3853 m_text = txt.isEmpty() ? txt : txt.left(m_maxLength);
3858 m_undoPreeditState = -1;
3860 m_cursor = (pos < 0 || pos > m_text.size()) ? m_text.size() : pos;
3861 m_textDirty = (oldText != m_text);
3863 bool changed = finishChange(-1,
true, edited);
3864#if !QT_CONFIG(accessibility)
3867 Q_Q(QQuickTextInput);
3868 if (changed && QAccessible::isActive()) {
3869 if (QObject *acc = QQuickAccessibleAttached::findAccessible(q, QAccessible::EditableText)) {
3870 QAccessibleTextUpdateEvent ev(acc, 0, oldText, m_text);
3871 QAccessible::updateAccessibility(&ev);
3879
3880
3881
3882
3883
3884void QQuickTextInputPrivate::addCommand(
const Command &cmd)
3886 if (m_separator && m_undoState && m_history[m_undoState - 1].type != Separator) {
3887 m_history.resize(m_undoState + 2);
3888 m_history[m_undoState++] = Command(Separator, m_cursor, u'\0', m_selstart, m_selend);
3890 m_history.resize(m_undoState + 1);
3892 m_separator =
false;
3893 m_history[m_undoState++] = cmd;
3897
3898
3899
3900
3901
3902
3903
3904
3905
3906void QQuickTextInputPrivate::internalInsert(
const QString &s)
3908 Q_Q(QQuickTextInput);
3909 if (m_echoMode == QQuickTextInput::Password) {
3910 if (m_passwordMaskDelay > 0)
3911 m_passwordEchoTimer.start(m_passwordMaskDelay, q);
3913 Q_ASSERT(!hasSelectedText());
3915 QString ms = maskString(m_cursor, s);
3916 for (
int i = 0; i < ms.size(); ++i) {
3917 addCommand (Command(DeleteSelection, m_cursor + i, m_text.at(m_cursor + i), -1, -1));
3918 addCommand(Command(Insert, m_cursor + i, ms.at(i), -1, -1));
3920 m_text.replace(m_cursor, ms.size(), ms);
3921 m_cursor += ms.size();
3922 m_cursor = nextMaskBlank(m_cursor);
3925 int remaining = m_maxLength - m_text.size();
3926 if (remaining != 0) {
3927 const QStringView remainingStr = QStringView{s}.left(remaining);
3928 m_text.insert(m_cursor, remainingStr);
3929 for (
auto e : remainingStr)
3930 addCommand(Command(Insert, m_cursor++, e, -1, -1));
3937
3938
3939
3940
3941
3942
3943
3944
3945
3946
3947void QQuickTextInputPrivate::internalDelete(
bool wasBackspace)
3949 if (m_cursor < m_text.size()) {
3950 cancelPasswordEchoTimer();
3951 Q_ASSERT(!hasSelectedText());
3952 addCommand(Command((CommandType)((m_maskData ? 2 : 0) + (wasBackspace ? Remove : Delete)),
3953 m_cursor, m_text.at(m_cursor), -1, -1));
3955 m_text.replace(m_cursor, 1, clearString(m_cursor, 1));
3956 addCommand(Command(Insert, m_cursor, m_text.at(m_cursor), -1, -1));
3958 m_text.remove(m_cursor, 1);
3965
3966
3967
3968
3969
3970
3971
3972
3973void QQuickTextInputPrivate::removeSelectedText()
3975 if (m_selstart < m_selend && m_selend <= m_text.size()) {
3976 cancelPasswordEchoTimer();
3978 if (m_selstart <= m_cursor && m_cursor < m_selend) {
3981 for (i = m_cursor; i >= m_selstart; --i)
3982 addCommand (Command(DeleteSelection, i, m_text.at(i), -1, 1));
3983 for (i = m_selend - 1; i > m_cursor; --i)
3984 addCommand (Command(DeleteSelection, i - m_cursor + m_selstart - 1, m_text.at(i), -1, -1));
3986 for (i = m_selend-1; i >= m_selstart; --i)
3987 addCommand (Command(RemoveSelection, i, m_text.at(i), -1, -1));
3990 m_text.replace(m_selstart, m_selend - m_selstart, clearString(m_selstart, m_selend - m_selstart));
3991 for (
int i = 0; i < m_selend - m_selstart; ++i)
3992 addCommand(Command(Insert, m_selstart + i, m_text.at(m_selstart + i), -1, -1));
3994 m_text.remove(m_selstart, m_selend - m_selstart);
3996 if (m_cursor > m_selstart)
3997 m_cursor -= qMin(m_cursor, m_selend) - m_selstart;
4004
4005
4006
4007
4008
4009
4011bool QQuickTextInputPrivate::separateSelection()
4013 if (hasSelectedText()) {
4015 addCommand(Command(SetSelection, m_cursor, u'\0', m_selstart, m_selend));
4023
4024
4025
4026
4027
4028void QQuickTextInputPrivate::parseInputMask(
const QString &maskFields)
4030 int delimiter = maskFields.indexOf(QLatin1Char(
';'));
4031 if (maskFields.isEmpty() || delimiter == 0) {
4033 m_maskData.reset(
nullptr);
4034 m_maxLength = 32767;
4035 internalSetText(QString());
4040 if (delimiter == -1) {
4041 m_blank = QLatin1Char(
' ');
4042 m_inputMask = maskFields;
4044 m_inputMask = maskFields.left(delimiter);
4045 m_blank = (delimiter + 1 < maskFields.size()) ? maskFields[delimiter + 1] : QLatin1Char(
' ');
4051 for (
int i=0; i<m_inputMask.size(); i++) {
4052 c = m_inputMask.at(i);
4053 if (i > 0 && m_inputMask.at(i-1) == QLatin1Char(
'\\')) {
4057 if (c != QLatin1Char(
'\\') && c != QLatin1Char(
'!') &&
4058 c != QLatin1Char(
'<') && c != QLatin1Char(
'>') &&
4059 c != QLatin1Char(
'{') && c != QLatin1Char(
'}') &&
4060 c != QLatin1Char(
'[') && c != QLatin1Char(
']'))
4064 m_maskData.reset(
new MaskInputData[m_maxLength]);
4066 MaskInputData::Casemode m = MaskInputData::NoCaseMode;
4069 bool escape =
false;
4071 for (
int i = 0; i < m_inputMask.size(); i++) {
4072 c = m_inputMask.at(i);
4075 m_maskData[index].maskChar = c;
4076 m_maskData[index].separator = s;
4077 m_maskData[index].caseMode = m;
4080 }
else if (c == QLatin1Char(
'<')) {
4081 m = MaskInputData::Lower;
4082 }
else if (c == QLatin1Char(
'>')) {
4083 m = MaskInputData::Upper;
4084 }
else if (c == QLatin1Char(
'!')) {
4085 m = MaskInputData::NoCaseMode;
4086 }
else if (c != QLatin1Char(
'{') && c != QLatin1Char(
'}') && c != QLatin1Char(
'[') && c != QLatin1Char(
']')) {
4087 switch (c.unicode()) {
4114 m_maskData[index].maskChar = c;
4115 m_maskData[index].separator = s;
4116 m_maskData[index].caseMode = m;
4121 internalSetText(m_text);
4126
4127
4128
4129
4130bool QQuickTextInputPrivate::isValidInput(QChar key, QChar mask)
const
4132 switch (mask.unicode()) {
4138 if (key.isLetter() || key == m_blank)
4142 if (key.isLetterOrNumber())
4146 if (key.isLetterOrNumber() || key == m_blank)
4150 if (key.isPrint() && key != m_blank)
4154 if (key.isPrint() || key == m_blank)
4162 if (key.isNumber() || key == m_blank)
4166 if (key.isNumber() && key.digitValue() > 0)
4170 if ((key.isNumber() && key.digitValue() > 0) || key == m_blank)
4174 if (key.isNumber() || key == QLatin1Char(
'+') || key == QLatin1Char(
'-') || key == m_blank)
4178 if (key == QLatin1Char(
'0') || key == QLatin1Char(
'1'))
4182 if (key == QLatin1Char(
'0') || key == QLatin1Char(
'1') || key == m_blank)
4186 if (key.isNumber() || (key >= QLatin1Char(
'a') && key <= QLatin1Char(
'f')) || (key >= QLatin1Char(
'A') && key <= QLatin1Char(
'F')))
4190 if (key.isNumber() || (key >= QLatin1Char(
'a') && key <= QLatin1Char(
'f')) || (key >= QLatin1Char(
'A') && key <= QLatin1Char(
'F')) || key == m_blank)
4200
4201
4202
4203
4204
4205
4206
4207QQuickTextInputPrivate::ValidatorState QQuickTextInputPrivate::hasAcceptableInput(
const QString &str)
const
4209#if QT_CONFIG(validator)
4210 QString textCopy = str;
4211 int cursorCopy = m_cursor;
4213 QValidator::State state = m_validator->validate(textCopy, cursorCopy);
4214 if (state != QValidator::Acceptable)
4215 return ValidatorState(state);
4220 return AcceptableInput;
4222 if (str.size() != m_maxLength)
4223 return InvalidInput;
4225 for (
int i=0; i < m_maxLength; ++i) {
4226 if (m_maskData[i].separator) {
4227 if (str.at(i) != m_maskData[i].maskChar)
4228 return InvalidInput;
4230 if (!isValidInput(str.at(i), m_maskData[i].maskChar))
4231 return InvalidInput;
4234 return AcceptableInput;
4238
4239
4240
4241
4242
4243
4244
4245QString QQuickTextInputPrivate::maskString(uint pos,
const QString &str,
bool clear)
const
4247 if (pos >= (uint)m_maxLength)
4248 return QString::fromLatin1(
"");
4251 fill = clear ? clearString(0, m_maxLength) : m_text;
4254 QString s = QString::fromLatin1(
"");
4256 while (i < m_maxLength) {
4257 if (strIndex < str.size()) {
4258 if (m_maskData[i].separator) {
4259 s += m_maskData[i].maskChar;
4260 if (str[strIndex] == m_maskData[i].maskChar)
4264 if (isValidInput(str[strIndex], m_maskData[i].maskChar)) {
4265 switch (m_maskData[i].caseMode) {
4266 case MaskInputData::Upper:
4267 s += str[strIndex].toUpper();
4269 case MaskInputData::Lower:
4270 s += str[strIndex].toLower();
4278 int n = findInMask(i,
true,
true, str[strIndex]);
4280 if (str.size() != 1 || i == 0 || (i > 0 && (!m_maskData[i-1].separator || m_maskData[i-1].maskChar != str[strIndex]))) {
4281 s += QStringView{fill}.mid(i, n-i+1);
4286 n = findInMask(i,
true,
false, str[strIndex]);
4288 s += QStringView{fill}.mid(i, n-i);
4289 switch (m_maskData[n].caseMode) {
4290 case MaskInputData::Upper:
4291 s += str[strIndex].toUpper();
4293 case MaskInputData::Lower:
4294 s += str[strIndex].toLower();
4315
4316
4317
4318
4319
4320QString QQuickTextInputPrivate::clearString(uint pos, uint len)
const
4322 if (pos >= (uint)m_maxLength)
4326 int end = qMin((uint)m_maxLength, pos + len);
4327 for (
int i = pos; i < end; ++i)
4328 if (m_maskData[i].separator)
4329 s += m_maskData[i].maskChar;
4337
4338
4339
4340
4341
4342QString QQuickTextInputPrivate::stripString(
const QString &str)
const
4348 int end = qMin(m_maxLength, str.size());
4349 for (
int i = 0; i < end; ++i) {
4350 if (m_maskData[i].separator)
4351 s += m_maskData[i].maskChar;
4352 else if (str[i] != m_blank)
4360
4361
4362
4363int QQuickTextInputPrivate::findInMask(
int pos,
bool forward,
bool findSeparator, QChar searchChar)
const
4365 if (pos >= m_maxLength || pos < 0)
4368 int end = forward ? m_maxLength : -1;
4369 int step = forward ? 1 : -1;
4373 if (findSeparator) {
4374 if (m_maskData[i].separator && m_maskData[i].maskChar == searchChar)
4377 if (!m_maskData[i].separator) {
4378 if (searchChar.isNull())
4380 else if (isValidInput(searchChar, m_maskData[i].maskChar))
4389void QQuickTextInputPrivate::internalUndo(
int until)
4391 if (!isUndoAvailable())
4393 cancelPasswordEchoTimer();
4395 while (m_undoState && m_undoState > until) {
4396 Command& cmd = m_history[--m_undoState];
4399 m_text.remove(cmd.pos, 1);
4403 m_selstart = cmd.selStart;
4404 m_selend = cmd.selEnd;
4408 case RemoveSelection:
4409 m_text.insert(cmd.pos, cmd.uc);
4410 m_cursor = cmd.pos + 1;
4413 case DeleteSelection:
4414 m_text.insert(cmd.pos, cmd.uc);
4420 if (until < 0 && m_undoState) {
4421 Command& next = m_history[m_undoState-1];
4422 if (next.type != cmd.type
4423 && next.type < RemoveSelection
4424 && (cmd.type < RemoveSelection || next.type == Separator)) {
4433void QQuickTextInputPrivate::internalRedo()
4435 if (!isRedoAvailable())
4438 while (m_undoState < m_history.size()) {
4439 Command& cmd = m_history[m_undoState++];
4442 m_text.insert(cmd.pos, cmd.uc);
4443 m_cursor = cmd.pos + 1;
4446 m_selstart = cmd.selStart;
4447 m_selend = cmd.selEnd;
4452 case RemoveSelection:
4453 case DeleteSelection:
4454 m_text.remove(cmd.pos, 1);
4455 m_selstart = cmd.selStart;
4456 m_selend = cmd.selEnd;
4460 m_selstart = cmd.selStart;
4461 m_selend = cmd.selEnd;
4465 if (m_undoState < m_history.size()) {
4466 Command& next = m_history[m_undoState];
4467 if (next.type != cmd.type
4468 && cmd.type < RemoveSelection
4469 && next.type != Separator
4470 && (next.type < RemoveSelection || cmd.type == Separator)) {
4478void QQuickTextInputPrivate::emitUndoRedoChanged()
4480 Q_Q(QQuickTextInput);
4481 const bool previousUndo = canUndo;
4482 const bool previousRedo = canRedo;
4484 canUndo = isUndoAvailable();
4485 canRedo = isRedoAvailable();
4487 if (previousUndo != canUndo)
4488 emit q->canUndoChanged();
4489 if (previousRedo != canRedo)
4490 emit q->canRedoChanged();
4494
4495
4496
4497
4498
4499bool QQuickTextInputPrivate::emitCursorPositionChanged()
4501 Q_Q(QQuickTextInput);
4502 if (m_cursor != m_lastCursorPos) {
4503 m_lastCursorPos = m_cursor;
4505 q->updateCursorRectangle();
4506 emit q->cursorPositionChanged();
4508 if (!hasSelectedText()) {
4509 if (lastSelectionStart != m_cursor) {
4510 lastSelectionStart = m_cursor;
4511 emit q->selectionStartChanged();
4513 if (lastSelectionEnd != m_cursor) {
4514 lastSelectionEnd = m_cursor;
4515 emit q->selectionEndChanged();
4519#if QT_CONFIG(accessibility)
4520 if (QAccessible::isActive()) {
4521 if (QObject *acc = QQuickAccessibleAttached::findAccessible(q, QAccessible::EditableText)) {
4522 QAccessibleTextCursorEvent ev(acc, m_cursor);
4523 QAccessible::updateAccessibility(&ev);
4534void QQuickTextInputPrivate::setBlinkingCursorEnabled(
bool enable)
4536 if (enable == m_blinkEnabled)
4539 m_blinkEnabled = enable;
4540 updateCursorBlinking();
4543 connect(qApp->styleHints(), &QStyleHints::cursorFlashTimeChanged,
this, &QQuickTextInputPrivate::updateCursorBlinking);
4545 disconnect(qApp->styleHints(), &QStyleHints::cursorFlashTimeChanged,
this, &QQuickTextInputPrivate::updateCursorBlinking);
4548void QQuickTextInputPrivate::updateCursorBlinking()
4550 Q_Q(QQuickTextInput);
4553 q->killTimer(m_blinkTimer);
4557 if (m_blinkEnabled && cursorVisible && !cursorItem && !m_readOnly) {
4558 int flashTime = QGuiApplication::styleHints()->cursorFlashTime();
4560 m_blinkTimer = q->startTimer(flashTime / 2);
4564 updateType = UpdatePaintNode;
4569void QQuickTextInput::timerEvent(QTimerEvent *event)
4571 Q_D(QQuickTextInput);
4572 if (event->timerId() == d->m_blinkTimer) {
4573 d->m_blinkStatus = !d->m_blinkStatus;
4574 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
4577 }
else if (event->timerId() == d->m_passwordEchoTimer.timerId()) {
4578 d->m_passwordEchoTimer.stop();
4579 d->updateDisplayText();
4580 updateCursorRectangle();
4584void QQuickTextInputPrivate::processKeyEvent(QKeyEvent* event)
4586 Q_Q(QQuickTextInput);
4588 if (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return) {
4589 if (hasAcceptableInput(m_text) == AcceptableInput || fixup()) {
4591 QInputMethod *inputMethod = QGuiApplication::inputMethod();
4592 inputMethod->commit();
4597 emit q->editingFinished();
4607 updateCursorBlinking();
4609 if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit
4610 && !m_passwordEchoEditing
4612 && !event->text().isEmpty()
4613 && !(event->modifiers() & Qt::ControlModifier)) {
4619 updatePasswordEchoEditing(
true);
4623 bool unknown =
false;
4624#if QT_CONFIG(shortcut)
4625 bool visual = cursorMoveStyle() == Qt::VisualMoveStyle;
4630#if QT_CONFIG(shortcut)
4631 else if (event == QKeySequence::Undo) {
4634 else if (event == QKeySequence::Redo) {
4637 else if (event == QKeySequence::SelectAll) {
4640#if QT_CONFIG(clipboard)
4641 else if (event == QKeySequence::Copy) {
4644 else if (event == QKeySequence::Paste) {
4646 QClipboard::Mode mode = QClipboard::Clipboard;
4650 else if (event == QKeySequence::Cut) {
4653 else if (event == QKeySequence::DeleteEndOfLine) {
4658 else if (event == QKeySequence::MoveToStartOfLine || event == QKeySequence::MoveToStartOfBlock) {
4661 else if (event == QKeySequence::MoveToEndOfLine || event == QKeySequence::MoveToEndOfBlock) {
4664 else if (event == QKeySequence::SelectStartOfLine || event == QKeySequence::SelectStartOfBlock) {
4667 else if (event == QKeySequence::SelectEndOfLine || event == QKeySequence::SelectEndOfBlock) {
4670 else if (event == QKeySequence::MoveToNextChar) {
4671 if (hasSelectedText()) {
4672 moveCursor(selectionEnd(),
false);
4674 cursorForward(0, visual ? 1 : (layoutDirection() == Qt::LeftToRight ? 1 : -1));
4677 else if (event == QKeySequence::SelectNextChar) {
4678 cursorForward(1, visual ? 1 : (layoutDirection() == Qt::LeftToRight ? 1 : -1));
4680 else if (event == QKeySequence::MoveToPreviousChar) {
4681 if (hasSelectedText()) {
4682 moveCursor(selectionStart(),
false);
4684 cursorForward(0, visual ? -1 : (layoutDirection() == Qt::LeftToRight ? -1 : 1));
4687 else if (event == QKeySequence::SelectPreviousChar) {
4688 cursorForward(1, visual ? -1 : (layoutDirection() == Qt::LeftToRight ? -1 : 1));
4690 else if (event == QKeySequence::MoveToNextWord) {
4691 if (m_echoMode == QQuickTextInput::Normal)
4692 layoutDirection() == Qt::LeftToRight ? cursorWordForward(0) : cursorWordBackward(0);
4694 layoutDirection() == Qt::LeftToRight ? end(0) : home(0);
4696 else if (event == QKeySequence::MoveToPreviousWord) {
4697 if (m_echoMode == QQuickTextInput::Normal)
4698 layoutDirection() == Qt::LeftToRight ? cursorWordBackward(0) : cursorWordForward(0);
4699 else if (!m_readOnly) {
4700 layoutDirection() == Qt::LeftToRight ? home(0) : end(0);
4703 else if (event == QKeySequence::SelectNextWord) {
4704 if (m_echoMode == QQuickTextInput::Normal)
4705 layoutDirection() == Qt::LeftToRight ? cursorWordForward(1) : cursorWordBackward(1);
4707 layoutDirection() == Qt::LeftToRight ? end(1) : home(1);
4709 else if (event == QKeySequence::SelectPreviousWord) {
4710 if (m_echoMode == QQuickTextInput::Normal)
4711 layoutDirection() == Qt::LeftToRight ? cursorWordBackward(1) : cursorWordForward(1);
4713 layoutDirection() == Qt::LeftToRight ? home(1) : end(1);
4715 else if (event == QKeySequence::Delete) {
4719 else if (event == QKeySequence::DeleteEndOfWord) {
4723 else if (event == QKeySequence::DeleteStartOfWord) {
4725 deleteStartOfWord();
4726 }
else if (event == QKeySequence::DeleteCompleteLine) {
4729#if QT_CONFIG(clipboard)
4737 bool handled =
false;
4738 if (event->modifiers() & Qt::ControlModifier) {
4739 switch (event->key()) {
4740 case Qt::Key_Backspace:
4742 deleteStartOfWord();
4749 switch (event->key()) {
4750 case Qt::Key_Backspace:
4762 if (event->key() == Qt::Key_Direction_L || event->key() == Qt::Key_Direction_R) {
4763 setLayoutDirection((event->key() == Qt::Key_Direction_L) ? Qt::LeftToRight : Qt::RightToLeft);
4767 if (unknown && !m_readOnly) {
4768 if (m_inputControl->isAcceptableInput(event)) {
4772 && !hasSelectedText()
4773 && !(m_cursor == q_func()->text().size())) {
4777 insert(event->text());
4790
4791
4792
4793
4795void QQuickTextInputPrivate::deleteStartOfWord()
4797 int priorState = m_undoState;
4799 if (!separateSelection()) {
4800 Command cmd(SetSelection, m_cursor, u'\0', m_selstart, m_selend);
4802 cursorWordBackward(
true);
4806 removeSelectedText();
4807 finishChange(priorState);
4811
4812
4813
4814
4816void QQuickTextInputPrivate::deleteEndOfWord()
4818 int priorState = m_undoState;
4819 Command cmd(SetSelection, m_cursor, u'\0', m_selstart, m_selend);
4821 cursorWordForward(
true);
4825 removeSelectedText();
4826 finishChange(priorState);
4830
4831
4832
4833
4835void QQuickTextInputPrivate::deleteEndOfLine()
4837 int priorState = m_undoState;
4838 Command cmd(SetSelection, m_cursor, u'\0', m_selstart, m_selend);
4840 setSelection(m_cursor, end());
4842 removeSelectedText();
4843 finishChange(priorState);
4847
4848
4849
4850
4851
4852
4853
4854
4855void QQuickTextInput::ensureVisible(
int position)
4857 Q_D(QQuickTextInput);
4858 d->ensureVisible(position);
4859 updateCursorRectangle(
false);
4863
4864
4865
4866
4867
4868
4869
4870
4871
4872
4873void QQuickTextInput::clear()
4875 Q_D(QQuickTextInput);
4881
4882
4883
4884
4885
4886
4887
4888
4889
4890
4891
4892
4893
4894
4895
4896
4897
4898
4899
4900
4901
4902
4903qreal QQuickTextInput::padding()
const
4905 Q_D(
const QQuickTextInput);
4906 return d->padding();
4909void QQuickTextInput::setPadding(qreal padding)
4911 Q_D(QQuickTextInput);
4912 if (qFuzzyCompare(d->padding(), padding))
4915 d->extra.value().padding = padding;
4917 updateCursorRectangle();
4918 emit paddingChanged();
4919 if (!d->extra.isAllocated() || !d->extra->explicitTopPadding)
4920 emit topPaddingChanged();
4921 if (!d->extra.isAllocated() || !d->extra->explicitLeftPadding)
4922 emit leftPaddingChanged();
4923 if (!d->extra.isAllocated() || !d->extra->explicitRightPadding)
4924 emit rightPaddingChanged();
4925 if (!d->extra.isAllocated() || !d->extra->explicitBottomPadding)
4926 emit bottomPaddingChanged();
4929void QQuickTextInput::resetPadding()
4934qreal QQuickTextInput::topPadding()
const
4936 Q_D(
const QQuickTextInput);
4937 if (d->extra.isAllocated() && d->extra->explicitTopPadding)
4938 return d->extra->topPadding;
4939 return d->padding();
4942void QQuickTextInput::setTopPadding(qreal padding)
4944 Q_D(QQuickTextInput);
4945 d->setTopPadding(padding);
4948void QQuickTextInput::resetTopPadding()
4950 Q_D(QQuickTextInput);
4951 d->setTopPadding(0,
true);
4954qreal QQuickTextInput::leftPadding()
const
4956 Q_D(
const QQuickTextInput);
4957 if (d->extra.isAllocated() && d->extra->explicitLeftPadding)
4958 return d->extra->leftPadding;
4959 return d->padding();
4962void QQuickTextInput::setLeftPadding(qreal padding)
4964 Q_D(QQuickTextInput);
4965 d->setLeftPadding(padding);
4968void QQuickTextInput::resetLeftPadding()
4970 Q_D(QQuickTextInput);
4971 d->setLeftPadding(0,
true);
4974qreal QQuickTextInput::rightPadding()
const
4976 Q_D(
const QQuickTextInput);
4977 if (d->extra.isAllocated() && d->extra->explicitRightPadding)
4978 return d->extra->rightPadding;
4979 return d->padding();
4982void QQuickTextInput::setRightPadding(qreal padding)
4984 Q_D(QQuickTextInput);
4985 d->setRightPadding(padding);
4988void QQuickTextInput::resetRightPadding()
4990 Q_D(QQuickTextInput);
4991 d->setRightPadding(0,
true);
4994qreal QQuickTextInput::bottomPadding()
const
4996 Q_D(
const QQuickTextInput);
4997 if (d->extra.isAllocated() && d->extra->explicitBottomPadding)
4998 return d->extra->bottomPadding;
4999 return d->padding();
5002void QQuickTextInput::setBottomPadding(qreal padding)
5004 Q_D(QQuickTextInput);
5005 d->setBottomPadding(padding);
5008void QQuickTextInput::resetBottomPadding()
5010 Q_D(QQuickTextInput);
5011 d->setBottomPadding(0,
true);
5014#if QT_VERSION < QT_VERSION_CHECK(7
, 0
, 0
)
5015void QQuickTextInput::setOldSelectionDefault()
5017 Q_D(QQuickTextInput);
5018 d->selectByMouse =
false;
5019 d->selectByTouchDrag =
true;
5020 qCDebug(lcQuickTextInput,
"pre-6.4 behavior chosen: selectByMouse defaults false; if enabled, touchscreen acts like a mouse");
5024QQuickPre64TextInput::QQuickPre64TextInput(QQuickItem *parent)
5025 : QQuickTextInput(parent)
5027 setOldSelectionDefault();
5033#include "moc_qquicktextinput_p.cpp"