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
238
239
240
241
242
243
244
245
248
249
250
251
254
255
256
257
260
261
262
263
266
267
268
269
272
273
274
275
278
279
280
281
284
285
286
287
288
289
290
293
294
295
296
297
298
301
302
303
304
305
306
309
310
311
312
313
314
317
318
319
320
321
322
323
326
327
328
329
330
333
334
335
336
337
340
341
342
343
344
347
348
349
350
351
354
355
356
357
358
361
362
363
364
365
366QFont QQuickTextInput::font()
const
368 Q_D(
const QQuickTextInput);
369 return d->sourceFont;
372void QQuickTextInput::setFont(
const QFont &font)
374 Q_D(QQuickTextInput);
375 if (d->sourceFont == font)
378 d->sourceFont = font;
379 QFont oldFont = d->font;
381 if (d->font.pointSizeF() != -1) {
383 qreal size = qRound(d->font.pointSizeF()*2.0);
384 d->font.setPointSizeF(size/2.0);
386 if (oldFont != d->font) {
388 updateCursorRectangle();
390 updateInputMethod(Qt::ImCursorRectangle | Qt::ImFont | Qt::ImAnchorRectangle);
393 emit fontChanged(d->sourceFont);
397
398
399
400
401QColor QQuickTextInput::color()
const
403 Q_D(
const QQuickTextInput);
407void QQuickTextInput::setColor(
const QColor &c)
409 Q_D(QQuickTextInput);
412 d->textLayoutDirty =
true;
413 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
422
423
424
425
426QColor QQuickTextInput::selectionColor()
const
428 Q_D(
const QQuickTextInput);
429 return d->selectionColor;
432void QQuickTextInput::setSelectionColor(
const QColor &color)
434 Q_D(QQuickTextInput);
435 if (d->selectionColor == color)
438 d->selectionColor = color;
439 if (d->hasSelectedText()) {
440 d->textLayoutDirty =
true;
441 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
445 emit selectionColorChanged();
448
449
450
451
452QColor QQuickTextInput::selectedTextColor()
const
454 Q_D(
const QQuickTextInput);
455 return d->selectedTextColor;
458void QQuickTextInput::setSelectedTextColor(
const QColor &color)
460 Q_D(QQuickTextInput);
461 if (d->selectedTextColor == color)
464 d->selectedTextColor = color;
465 if (d->hasSelectedText()) {
466 d->textLayoutDirty =
true;
467 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
471 emit selectedTextColorChanged();
475
476
477
478
479
480
481
482
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509QQuickTextInput::HAlignment QQuickTextInput::hAlign()
const
511 Q_D(
const QQuickTextInput);
515void QQuickTextInput::setHAlign(HAlignment align)
517 Q_D(QQuickTextInput);
519 if (d->setHAlign(align,
true) && isComponentComplete()) {
521 updateCursorRectangle();
525void QQuickTextInput::resetHAlign()
527 Q_D(QQuickTextInput);
528 d->hAlignImplicit =
true;
529 if (d->determineHorizontalAlignment() && isComponentComplete()) {
531 updateCursorRectangle();
535QQuickTextInput::HAlignment QQuickTextInput::effectiveHAlign()
const
537 Q_D(
const QQuickTextInput);
538 QQuickTextInput::HAlignment effectiveAlignment = d->hAlign;
539 if (!d->hAlignImplicit && d->effectiveLayoutMirror) {
541 case QQuickTextInput::AlignLeft:
542 effectiveAlignment = QQuickTextInput::AlignRight;
544 case QQuickTextInput::AlignRight:
545 effectiveAlignment = QQuickTextInput::AlignLeft;
551 return effectiveAlignment;
554bool QQuickTextInputPrivate::setHAlign(QQuickTextInput::HAlignment align,
bool forceAlign)
556 Q_Q(QQuickTextInput);
557 if (align > QQuickTextInput::AlignHCenter)
560 if (hAlign == align && !forceAlign)
563 const bool wasImplicit = hAlignImplicit;
564 const auto oldEffectiveHAlign = q->effectiveHAlign();
566 hAlignImplicit = !forceAlign;
567 if (hAlign != align) {
569 emit q->horizontalAlignmentChanged(align);
572 if (q->effectiveHAlign() != oldEffectiveHAlign) {
573 emit q->effectiveHorizontalAlignmentChanged();
577 if (forceAlign && wasImplicit) {
580 emit q->effectiveHorizontalAlignmentChanged();
585Qt::LayoutDirection QQuickTextInputPrivate::textDirection()
const
587 QString text = m_text;
590 text = m_textLayout.preeditAreaText();
593 const QChar *character = text.constData();
594 while (!character->isNull()) {
595 switch (character->direction()) {
597 return Qt::LeftToRight;
601 return Qt::RightToLeft;
607 return Qt::LayoutDirectionAuto;
610Qt::LayoutDirection QQuickTextInputPrivate::layoutDirection()
const
612 Qt::LayoutDirection direction = m_layoutDirection;
613 if (direction == Qt::LayoutDirectionAuto) {
614 direction = textDirection();
616 if (direction == Qt::LayoutDirectionAuto)
617 direction = QGuiApplication::inputMethod()->inputDirection();
620 return (direction == Qt::LayoutDirectionAuto) ? Qt::LeftToRight : direction;
623bool QQuickTextInputPrivate::determineHorizontalAlignment()
629 Qt::LayoutDirection direction = textDirection();
631 if (direction == Qt::LayoutDirectionAuto)
632 direction = QGuiApplication::inputMethod()->inputDirection();
635 const auto implicitHAlign = direction == Qt::RightToLeft ?
636 QQuickTextInput::AlignRight : QQuickTextInput::AlignLeft;
637 return setHAlign(implicitHAlign);
640QQuickTextInput::VAlignment QQuickTextInput::vAlign()
const
642 Q_D(
const QQuickTextInput);
646void QQuickTextInput::setVAlign(QQuickTextInput::VAlignment alignment)
648 Q_D(QQuickTextInput);
649 if (alignment == d->vAlign)
651 d->vAlign = alignment;
652 emit verticalAlignmentChanged(d->vAlign);
653 if (isComponentComplete()) {
654 updateCursorRectangle();
655 d->updateBaselineOffset();
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679QQuickTextInput::WrapMode QQuickTextInput::wrapMode()
const
681 Q_D(
const QQuickTextInput);
685void QQuickTextInput::setWrapMode(WrapMode mode)
687 Q_D(QQuickTextInput);
688 if (mode == d->wrapMode)
692 updateCursorRectangle();
693 emit wrapModeChanged();
696void QQuickTextInputPrivate::mirrorChange()
698 Q_Q(QQuickTextInput);
699 if (q->isComponentComplete()) {
700 if (!hAlignImplicit && (hAlign == QQuickTextInput::AlignRight || hAlign == QQuickTextInput::AlignLeft)) {
701 q->updateCursorRectangle();
702 emit q->effectiveHorizontalAlignmentChanged();
708
709
710
711
712
713
714
715
716bool QQuickTextInput::isReadOnly()
const
718 Q_D(
const QQuickTextInput);
719 return d->m_readOnly;
722void QQuickTextInput::setReadOnly(
bool ro)
724 Q_D(QQuickTextInput);
725 if (d->m_readOnly == ro)
729 setFlag(QQuickItem::ItemAcceptsInputMethod, !ro);
732 d->setCursorPosition(d->end());
734 updateInputMethod(Qt::ImEnabled);
737 d->emitUndoRedoChanged();
738 emit readOnlyChanged(ro);
740 setCursorVisible(
false);
741 }
else if (hasActiveFocus()) {
742 setCursorVisible(
true);
748
749
750
751
752
753
754
755int QQuickTextInput::maxLength()
const
757 Q_D(
const QQuickTextInput);
758 return d->m_maxLength;
761void QQuickTextInput::setMaxLength(
int ml)
763 Q_D(QQuickTextInput);
764 if (d->m_maxLength == ml || d->m_maskData)
768 d->internalSetText(d->m_text, -1,
false);
770 emit maximumLengthChanged(ml);
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799bool QQuickTextInput::isCursorVisible()
const
801 Q_D(
const QQuickTextInput);
802 return d->cursorVisible;
805void QQuickTextInput::setCursorVisible(
bool on)
807 Q_D(QQuickTextInput);
808 if (d->cursorVisible == on)
810 d->cursorVisible = on;
811 if (on && isComponentComplete())
812 QQuickTextUtil::createCursor(d);
814 d->updateCursorBlinking();
815 emit cursorVisibleChanged(d->cursorVisible);
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834int QQuickTextInput::cursorPosition()
const
836 Q_D(
const QQuickTextInput);
840void QQuickTextInput::setCursorPosition(
int cp)
842 Q_D(QQuickTextInput);
843 if (cp < 0 || cp > text().size())
849
850
851
852
853
854
855
856
857
859QRectF QQuickTextInput::cursorRectangle()
const
861 Q_D(
const QQuickTextInput);
865 c += d->m_preeditCursor;
867 if (d->m_echoMode == NoEcho)
869 QTextLine l = d->m_textLayout.lineForTextPosition(c);
872 qreal x = l.cursorToX(c) - d->hscroll + leftPadding();
873 qreal y = l.y() - d->vscroll + topPadding();
875 if (d->overwriteMode) {
876 if (c < text().size())
877 w = l.cursorToX(c + 1) - x;
879 w = QFontMetrics(font()).horizontalAdvance(QLatin1Char(
' '));
881 return QRectF(x, y, w, l.height());
885
886
887
888
889
890
891
892
893
894
895int QQuickTextInput::selectionStart()
const
897 Q_D(
const QQuickTextInput);
898 return d->lastSelectionStart;
901
902
903
904
905
906
907
908
909
910
911int QQuickTextInput::selectionEnd()
const
913 Q_D(
const QQuickTextInput);
914 return d->lastSelectionEnd;
917
918
919
920
921
922
923
924
925
926
927
928
929void QQuickTextInput::select(
int start,
int end)
931 Q_D(QQuickTextInput);
932 if (start < 0 || end < 0 || start > d->m_text.size() || end > d->m_text.size())
934 d->setSelection(start, end-start);
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952QString QQuickTextInput::selectedText()
const
954 Q_D(
const QQuickTextInput);
955 return d->selectedText();
959
960
961
962
963
964bool QQuickTextInput::focusOnPress()
const
966 Q_D(
const QQuickTextInput);
967 return d->focusOnPress;
970void QQuickTextInput::setFocusOnPress(
bool b)
972 Q_D(QQuickTextInput);
973 if (d->focusOnPress == b)
978 emit activeFocusOnPressChanged(d->focusOnPress);
981
982
983
984
985
986
987
988bool QQuickTextInput::autoScroll()
const
990 Q_D(
const QQuickTextInput);
991 return d->autoScroll;
994void QQuickTextInput::setAutoScroll(
bool b)
996 Q_D(QQuickTextInput);
997 if (d->autoScroll == b)
1002 updateCursorRectangle();
1003 emit autoScrollChanged(d->autoScroll);
1006#if QT_CONFIG(validator)
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1031QValidator* QQuickTextInput::validator()
const
1033 Q_D(
const QQuickTextInput);
1034 return d->m_validator;
1037void QQuickTextInput::setValidator(QValidator* v)
1039 Q_D(QQuickTextInput);
1040 if (d->m_validator == v)
1043 if (d->m_validator) {
1044 qmlobject_disconnect(
1045 d->m_validator, QValidator, SIGNAL(changed()),
1046 this, QQuickTextInput, SLOT(q_validatorChanged()));
1051 if (d->m_validator) {
1053 d->m_validator, QValidator, SIGNAL(changed()),
1054 this, QQuickTextInput, SLOT(q_validatorChanged()));
1057 if (isComponentComplete())
1060 emit validatorChanged();
1063void QQuickTextInput::q_validatorChanged()
1065 Q_D(QQuickTextInput);
1070QRectF QQuickTextInputPrivate::anchorRectangle()
const
1072 Q_Q(
const QQuickTextInput);
1079 if (m_selstart == m_selend)
1084 a = m_selstart == m_cursor ? m_selend : m_selstart;
1087 a += m_preeditCursor;
1089 if (m_echoMode == QQuickTextInput::NoEcho)
1091 QTextLine l = m_textLayout.lineForTextPosition(a);
1093 qreal x = l.cursorToX(a) - hscroll + q->leftPadding();
1094 qreal y = l.y() - vscroll + q->topPadding();
1095 rect.setRect(x, y, 1, l.height());
1101void QQuickTextInputPrivate::checkIsValid()
1103 Q_Q(QQuickTextInput);
1105 ValidatorState state = hasAcceptableInput(m_text);
1107 m_validInput = state != InvalidInput;
1108 if (state != AcceptableInput) {
1109 if (m_acceptableInput) {
1110 m_acceptableInput =
false;
1111 emit q->acceptableInputChanged();
1113 }
else if (!m_acceptableInput) {
1114 m_acceptableInput =
true;
1115 emit q->acceptableInputChanged();
1120
1121
1122
1123
1124
1125
1126
1127
1128QString QQuickTextInput::inputMask()
const
1130 Q_D(
const QQuickTextInput);
1131 return d->inputMask();
1134void QQuickTextInput::setInputMask(
const QString &im)
1136 Q_D(QQuickTextInput);
1137 QString canonicalInputMask = im;
1138 if (im.lastIndexOf(QLatin1Char(
';')) == -1)
1139 canonicalInputMask.append(QLatin1String(
"; "));
1140 if (d->inputMask() == canonicalInputMask)
1143 d->setInputMask(im);
1144 emit inputMaskChanged(d->inputMask());
1148
1149
1150
1151
1152
1153
1154
1155
1156bool QQuickTextInput::hasAcceptableInput()
const
1158 Q_D(
const QQuickTextInput);
1159 return d->m_acceptableInput;
1163
1164
1165
1166
1167
1168
1169
1170
1171
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1187
1188
1189
1190
1191
1192
1193
1194
1195
1198Qt::InputMethodHints QQuickTextInputPrivate::effectiveInputMethodHints()
const
1200 Qt::InputMethodHints hints = inputMethodHints;
1201 if (m_echoMode == QQuickTextInput::NoEcho)
1202 hints |= Qt::ImhHiddenText;
1203 else if (m_echoMode == QQuickTextInput::Password || m_echoMode == QQuickTextInput::PasswordEchoOnEdit)
1204 hints &= ~Qt::ImhHiddenText;
1205 if (m_echoMode != QQuickTextInput::Normal)
1206 hints |= (Qt::ImhNoAutoUppercase | Qt::ImhNoPredictiveText | Qt::ImhSensitiveData);
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225QQuickTextInput::EchoMode QQuickTextInput::echoMode()
const
1227 Q_D(
const QQuickTextInput);
1228 return QQuickTextInput::EchoMode(d->m_echoMode);
1231void QQuickTextInput::setEchoMode(QQuickTextInput::EchoMode echo)
1233 Q_D(QQuickTextInput);
1234 if (echoMode() == echo)
1236 d->cancelPasswordEchoTimer();
1237 d->m_echoMode = echo;
1238 d->m_passwordEchoEditing =
false;
1240 updateInputMethod(Qt::ImHints);
1242 d->updateDisplayText();
1243 updateCursorRectangle();
1248 if (d->m_echoMode != QQuickTextInput::Normal)
1249 d->m_text.reserve(30);
1251 emit echoModeChanged(echoMode());
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1298Qt::InputMethodHints QQuickTextInput::inputMethodHints()
const
1303 Q_D(
const QQuickTextInput);
1304 return d->inputMethodHints;
1308void QQuickTextInput::setInputMethodHints(Qt::InputMethodHints hints)
1313 Q_D(QQuickTextInput);
1315 if (hints == d->inputMethodHints)
1318 d->inputMethodHints = hints;
1319 updateInputMethod(Qt::ImHints);
1320 emit inputMethodHintsChanged();
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337QQmlComponent* QQuickTextInput::cursorDelegate()
const
1339 Q_D(
const QQuickTextInput);
1340 return d->cursorComponent;
1343void QQuickTextInput::setCursorDelegate(QQmlComponent* c)
1345 Q_D(QQuickTextInput);
1346 QQuickTextUtil::setCursorDelegate(d, c);
1349void QQuickTextInput::createCursor()
1351 Q_D(QQuickTextInput);
1352 d->cursorPending =
true;
1353 QQuickTextUtil::createCursor(d);
1357
1358
1359
1360
1361
1362
1363
1364
1365QRectF QQuickTextInput::positionToRectangle(
int pos)
const
1367 Q_D(
const QQuickTextInput);
1368 if (d->m_echoMode == NoEcho)
1371 else if (pos > d->m_cursor)
1372 pos += d->preeditAreaText().size();
1374 QTextLine l = d->m_textLayout.lineForTextPosition(pos);
1377 qreal x = l.cursorToX(pos) - d->hscroll;
1378 qreal y = l.y() - d->vscroll;
1380 if (d->overwriteMode) {
1381 if (pos < text().size())
1382 w = l.cursorToX(pos + 1) - x;
1384 w = QFontMetrics(font()).horizontalAdvance(QLatin1Char(
' '));
1386 return QRectF(x, y, w, l.height());
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1412int QQuickTextInput::positionAt(qreal x, qreal y, QQuickTextInput::CursorPosition positionQuick)
const
1414 Q_D(
const QQuickTextInput);
1416 QTextLine::CursorPosition position = QTextLine::CursorPosition(positionQuick);
1418 int pos = d->positionAt(x, y, position);
1419 const int cursor = d->m_cursor;
1422 const int preeditLength = d->preeditAreaText().size();
1423 pos = pos > cursor + preeditLength
1424 ? pos - preeditLength
1433int QQuickTextInputPrivate::positionAt(qreal x, qreal y, QTextLine::CursorPosition position)
const
1435 Q_Q(
const QQuickTextInput);
1436 x += hscroll - q->leftPadding();
1437 y += vscroll - q->topPadding();
1438 QTextLine line = m_textLayout.lineAt(0);
1439 for (
int i = 1; i < m_textLayout.lineCount(); ++i) {
1440 QTextLine nextLine = m_textLayout.lineAt(i);
1442 if (y < (line.rect().bottom() + nextLine.y()) / 2)
1446 return line.isValid() ? line.xToCursor(x, position) : 0;
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464bool QQuickTextInput::overwriteMode()
const
1466 Q_D(
const QQuickTextInput);
1467 return d->overwriteMode;
1470void QQuickTextInput::setOverwriteMode(
bool overwrite)
1472 Q_D(QQuickTextInput);
1473 if (d->overwriteMode == overwrite)
1475 d->overwriteMode = overwrite;
1476 emit overwriteModeChanged(overwrite);
1479void QQuickTextInput::keyPressEvent(QKeyEvent* ev)
1481 Q_D(QQuickTextInput);
1483 bool ignore = (ev->key() == Qt::Key_Up || ev->key() == Qt::Key_Down) && ev->modifiers() == Qt::NoModifier;
1484 if (!ignore && (d->lastSelectionStart == d->lastSelectionEnd) && (ev->key() == Qt::Key_Right || ev->key() == Qt::Key_Left)) {
1487 int cursorPosition = d->m_cursor;
1488 if (cursorPosition == 0)
1489 ignore = ev->key() == (d->layoutDirection() == Qt::LeftToRight ? Qt::Key_Left : Qt::Key_Right);
1490 if (!ignore && cursorPosition == d->m_text.size())
1491 ignore = ev->key() == (d->layoutDirection() == Qt::LeftToRight ? Qt::Key_Right : Qt::Key_Left);
1496 d->processKeyEvent(ev);
1498 if (!ev->isAccepted())
1499 QQuickImplicitSizeItem::keyPressEvent(ev);
1503void QQuickTextInput::inputMethodEvent(QInputMethodEvent *ev)
1505 Q_D(QQuickTextInput);
1506 const bool wasComposing = d->hasImState;
1507 d->processInputMethodEvent(ev);
1508 if (!ev->isAccepted())
1509 QQuickImplicitSizeItem::inputMethodEvent(ev);
1511 if (wasComposing != d->hasImState)
1512 emit inputMethodComposingChanged();
1516void QQuickTextInput::mouseDoubleClickEvent(QMouseEvent *event)
1518 Q_D(QQuickTextInput);
1520 if (d->selectByMouse && event->button() == Qt::LeftButton &&
1521 QQuickDeliveryAgentPrivate::isEventFromMouseOrTouchpad(event)) {
1525 int cursor = d->positionAt(event->position());
1526 d->selectWordAtPos(cursor);
1527 event->setAccepted(
true);
1528 if (!d->hasPendingTripleClick()) {
1529 d->tripleClickStartPoint = event->position();
1530 d->tripleClickTimer.start();
1533 if (d->sendMouseEventToInputContext(event))
1535 QQuickImplicitSizeItem::mouseDoubleClickEvent(event);
1539void QQuickTextInput::mousePressEvent(QMouseEvent *event)
1541 Q_D(QQuickTextInput);
1543 d->pressPos = event->position();
1545 if (d->sendMouseEventToInputContext(event))
1548 d->hadSelectionOnMousePress = d->hasSelectedText();
1550 const bool isMouse = QQuickDeliveryAgentPrivate::isEventFromMouseOrTouchpad(event);
1551 if (d->selectByMouse &&
1553#if QT_VERSION < QT_VERSION_CHECK(7
, 0
, 0
)
1554 || d->selectByTouchDrag
1557 setKeepMouseGrab(
false);
1558 d->selectPressed =
true;
1559 QPointF distanceVector = d->pressPos - d->tripleClickStartPoint;
1560 if (d->hasPendingTripleClick()
1561 && distanceVector.manhattanLength() < QGuiApplication::styleHints()->startDragDistance()) {
1562 event->setAccepted(
true);
1569#if QT_VERSION < QT_VERSION_CHECK(7
, 0
, 0
)
1570 || d->selectByTouchDrag
1573 bool mark = (event->modifiers() & Qt::ShiftModifier) && d->selectByMouse;
1574 int cursor = d->positionAt(event->position());
1575 d->moveCursor(cursor, mark);
1578 if (d->focusOnPress && !qGuiApp->styleHints()->setFocusOnTouchRelease())
1579 ensureActiveFocus(Qt::MouseFocusReason);
1581 event->setAccepted(
true);
1584void QQuickTextInput::mouseMoveEvent(QMouseEvent *event)
1586 Q_D(QQuickTextInput);
1587 if (!QQuickDeliveryAgentPrivate::isEventFromMouseOrTouchpad(event)
1588#if QT_VERSION < QT_VERSION_CHECK(7
, 0
, 0
)
1589 && ! d->selectByTouchDrag
1594 if (d->selectPressed) {
1595 if (qAbs(
int(event->position().x() - d->pressPos.x())) > QGuiApplication::styleHints()->startDragDistance())
1596 setKeepMouseGrab(
true);
1599 if (d->composeMode()) {
1601 int startPos = d->positionAt(d->pressPos);
1602 int currentPos = d->positionAt(event->position());
1603 if (startPos != currentPos)
1604 d->setSelection(startPos, currentPos - startPos);
1608 moveCursorSelection(d->positionAt(event->position()), d->mouseSelectionMode);
1610 event->setAccepted(
true);
1612 QQuickImplicitSizeItem::mouseMoveEvent(event);
1616void QQuickTextInput::mouseReleaseEvent(QMouseEvent *event)
1618 Q_D(QQuickTextInput);
1619 if (d->sendMouseEventToInputContext(event))
1621 if (d->selectPressed) {
1622 d->selectPressed =
false;
1623 setKeepMouseGrab(
false);
1625 const bool isMouse = QQuickDeliveryAgentPrivate::isEventFromMouseOrTouchpad(event)
1626#if QT_VERSION < QT_VERSION_CHECK(7
, 0
, 0
)
1627 || d->selectByTouchDrag
1631#if QT_CONFIG(clipboard)
1632 if (isMouse && QGuiApplication::clipboard()->supportsSelection()) {
1633 if (event->button() == Qt::LeftButton) {
1634 d->copy(QClipboard::Selection);
1635 }
else if (!d->m_readOnly && event->button() == Qt::MiddleButton) {
1637 d->insert(QGuiApplication::clipboard()->text(QClipboard::Selection));
1646 if (!isMouse && (!d->hasSelectedText() || d->hadSelectionOnMousePress))
1647 d->moveCursor(d->positionAt(event->position()),
false);
1651 d->hadSelectionOnMousePress =
false;
1653 if (d->focusOnPress && qGuiApp->styleHints()->setFocusOnTouchRelease())
1654 ensureActiveFocus(Qt::MouseFocusReason);
1656 if (!event->isAccepted())
1657 QQuickImplicitSizeItem::mouseReleaseEvent(event);
1660#if QT_VERSION < QT_VERSION_CHECK(7
, 0
, 0
)
1661bool QQuickTextInputPrivate::handleContextMenuEvent(QContextMenuEvent *event)
1663bool QQuickTextInput::contextMenuEvent(QContextMenuEvent *event)
1666 Q_Q(QQuickTextInput);
1667 QContextMenuEvent mapped(event->reason(),
1668 q->mapToScene(q->cursorRectangle().center()).toPoint(), event->globalPos(),
1669 event->modifiers());
1670 const bool eventProcessed = QQuickItemPrivate::handleContextMenuEvent(&mapped);
1671 event->setAccepted(mapped.isAccepted());
1672 return eventProcessed;
1675bool QQuickTextInputPrivate::sendMouseEventToInputContext(QMouseEvent *event)
1678 if (composeMode()) {
1679 int tmp_cursor = positionAt(event->position());
1680 int mousePos = tmp_cursor - m_cursor;
1681 if (mousePos >= 0 && mousePos <= m_textLayout.preeditAreaText().size()) {
1682 if (event->type() == QEvent::MouseButtonRelease) {
1683 QGuiApplication::inputMethod()->invokeAction(QInputMethod::Click, mousePos);
1695void QQuickTextInput::mouseUngrabEvent()
1697 Q_D(QQuickTextInput);
1698 d->selectPressed =
false;
1699 setKeepMouseGrab(
false);
1702bool QQuickTextInput::event(QEvent* ev)
1704#if QT_CONFIG(shortcut)
1705 Q_D(QQuickTextInput);
1706 if (ev->type() == QEvent::ShortcutOverride) {
1707 if (d->m_readOnly) {
1711 QKeyEvent* ke =
static_cast<QKeyEvent*>(ev);
1712 if (ke == QKeySequence::Copy
1713 || ke == QKeySequence::Paste
1714 || ke == QKeySequence::Cut
1715 || ke == QKeySequence::Redo
1716 || ke == QKeySequence::Undo
1717 || ke == QKeySequence::MoveToNextWord
1718 || ke == QKeySequence::MoveToPreviousWord
1719 || ke == QKeySequence::MoveToStartOfDocument
1720 || ke == QKeySequence::MoveToEndOfDocument
1721 || ke == QKeySequence::SelectNextWord
1722 || ke == QKeySequence::SelectPreviousWord
1723 || ke == QKeySequence::SelectStartOfLine
1724 || ke == QKeySequence::SelectEndOfLine
1725 || ke == QKeySequence::SelectStartOfBlock
1726 || ke == QKeySequence::SelectEndOfBlock
1727 || ke == QKeySequence::SelectStartOfDocument
1728 || ke == QKeySequence::SelectAll
1729 || ke == QKeySequence::SelectEndOfDocument
1730 || ke == QKeySequence::DeleteCompleteLine) {
1733 }
else if (ke->modifiers() == Qt::NoModifier || ke->modifiers() == Qt::ShiftModifier
1734 || ke->modifiers() == Qt::KeypadModifier) {
1735 if (ke->key() < Qt::Key_Escape) {
1739 switch (ke->key()) {
1740 case Qt::Key_Delete:
1743 case Qt::Key_Backspace:
1757 return QQuickImplicitSizeItem::event(ev);
1760void QQuickTextInput::geometryChange(
const QRectF &newGeometry,
1761 const QRectF &oldGeometry)
1763 Q_D(QQuickTextInput);
1765 if (newGeometry.width() != oldGeometry.width())
1767 else if (newGeometry.height() != oldGeometry.height() && d->vAlign != QQuickTextInput::AlignTop)
1768 d->updateBaselineOffset();
1769 updateCursorRectangle();
1771 QQuickImplicitSizeItem::geometryChange(newGeometry, oldGeometry);
1774void QQuickTextInput::itemChange(ItemChange change,
const ItemChangeData &value)
1776 Q_D(QQuickTextInput);
1779 case ItemDevicePixelRatioHasChanged:
1780 if (d->containsUnscalableGlyphs) {
1791 QQuickImplicitSizeItem::itemChange(change, value);
1794void QQuickTextInputPrivate::ensureVisible(
int position,
int preeditCursor,
int preeditLength)
1796 Q_Q(QQuickTextInput);
1797 QTextLine textLine = m_textLayout.lineForTextPosition(position + preeditCursor);
1798 const qreal width = qMax<qreal>(0, q->width() - q->leftPadding() - q->rightPadding());
1800 qreal widthUsed = 0;
1801 if (textLine.isValid()) {
1802 cix = textLine.cursorToX(position + preeditLength);
1803 const qreal cursorWidth = cix >= 0 ? cix : width - cix;
1804 widthUsed = qMax(textLine.naturalTextWidth(), cursorWidth);
1806 int previousScroll = hscroll;
1808 if (widthUsed <= width) {
1811 Q_ASSERT(textLine.isValid());
1812 if (cix - hscroll >= width) {
1814 hscroll = cix - width;
1815 }
else if (cix - hscroll < 0 && hscroll < widthUsed) {
1818 }
else if (widthUsed - hscroll < width) {
1821 hscroll = widthUsed - width;
1822 }
else if (width - hscroll > widthUsed) {
1825 hscroll = width - widthUsed;
1828 if (preeditLength > 0) {
1831 cix = textLine.cursorToX(position + qMax(0, preeditCursor - 1));
1837 if (previousScroll != hscroll)
1838 textLayoutDirty =
true;
1841void QQuickTextInputPrivate::updateHorizontalScroll()
1843 if (autoScroll && m_echoMode != QQuickTextInput::NoEcho) {
1845 const int preeditLength = m_textLayout.preeditAreaText().size();
1846 ensureVisible(m_cursor, m_preeditCursor, preeditLength);
1848 ensureVisible(m_cursor);
1855void QQuickTextInputPrivate::updateVerticalScroll()
1857 Q_Q(QQuickTextInput);
1859 const int preeditLength = m_textLayout.preeditAreaText().size();
1861 const qreal height = qMax<qreal>(0, q->height() - q->topPadding() - q->bottomPadding());
1862 qreal heightUsed = contentSize.height();
1863 qreal previousScroll = vscroll;
1865 if (!autoScroll || heightUsed <= height) {
1867 vscroll = -QQuickTextUtil::alignedY(
1868 heightUsed, height, vAlign & ~(Qt::AlignAbsolute|Qt::AlignHorizontal_Mask));
1871 QTextLine currentLine = m_textLayout.lineForTextPosition(m_cursor + preeditLength);
1873 QTextLine currentLine = m_textLayout.lineForTextPosition(m_cursor);
1875 QRectF r = currentLine.isValid() ? currentLine.rect() : QRectF();
1876 qreal top = r.top();
1877 int bottom = r.bottom();
1879 if (bottom - vscroll >= height) {
1881 vscroll = bottom - height;
1882 }
else if (top - vscroll < 0 && vscroll < heightUsed) {
1885 }
else if (heightUsed - vscroll < height) {
1888 vscroll = heightUsed - height;
1891 if (preeditLength > 0) {
1894 currentLine = m_textLayout.lineForTextPosition(m_cursor + qMax(0, m_preeditCursor - 1));
1895 top = currentLine.isValid() ? currentLine.rect().top() : 0;
1901 if (previousScroll != vscroll)
1902 textLayoutDirty =
true;
1905void QQuickTextInput::triggerPreprocess()
1907 Q_D(QQuickTextInput);
1908 if (d->updateType == QQuickTextInputPrivate::UpdateNone)
1909 d->updateType = QQuickTextInputPrivate::UpdateOnlyPreprocess;
1914void QQuickTextInput::updatePolish()
1916 invalidateFontCaches();
1919void QQuickTextInput::invalidateFontCaches()
1921 Q_D(QQuickTextInput);
1923 if (d->m_textLayout.engine() !=
nullptr)
1924 d->m_textLayout.engine()->resetFontEngineCache();
1927void QQuickTextInput::ensureActiveFocus(Qt::FocusReason reason)
1929 bool hadActiveFocus = hasActiveFocus();
1930 forceActiveFocus(reason);
1932 Q_D(QQuickTextInput);
1934 if (hasActiveFocus() && hadActiveFocus && !d->m_readOnly)
1935 qGuiApp->inputMethod()->show();
1937 Q_UNUSED(hadActiveFocus);
1941QSGNode *QQuickTextInput::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data)
1944 Q_D(QQuickTextInput);
1946 if (d->updateType != QQuickTextInputPrivate::UpdatePaintNode && oldNode !=
nullptr) {
1948 d->updateType = QQuickTextInputPrivate::UpdateNone;
1952 d->updateType = QQuickTextInputPrivate::UpdateNone;
1954 QSGInternalTextNode *node =
static_cast<QSGInternalTextNode *>(oldNode);
1955 if (node ==
nullptr)
1956 node = d->sceneGraphContext()->createInternalTextNode(d->sceneGraphRenderContext());
1959 const bool showCursor = !isReadOnly() && d->cursorItem ==
nullptr && d->cursorVisible && d->m_blinkStatus;
1961 if (!d->textLayoutDirty && oldNode !=
nullptr) {
1963 node->setCursor(cursorRectangle(), d->color,
nullptr);
1965 node->clearCursor();
1967 node->setRenderType(QSGTextNode::RenderType(d->renderType));
1969 QSGInternalTextNode::RecycleBin recycleBin;
1970 node->recycle(&recycleBin);
1971 node->setMatrix(QMatrix4x4());
1972 node->setTextStyle(QSGInternalTextNode::Normal);
1973 node->setColor(d->color);
1974 node->setSelectionTextColor(d->selectedTextColor);
1975 node->setSelectionColor(d->selectionColor);
1976 node->setFiltering(smooth() ? QSGTexture::Linear : QSGTexture::Nearest);
1978 if (flags().testFlag(ItemObservesViewport))
1979 node->setViewport(clipRect());
1981 node->setViewport(QRectF{});
1983 QPointF offset(leftPadding(), topPadding());
1984 offset -= QPointF(d->hscroll, d->vscroll);
1986 if (!d->m_textLayout.text().isEmpty()
1988 || !d->m_textLayout.preeditAreaText().isEmpty()
1991 node->addTextLayout(offset,
1994 d->selectionStart(),
1995 d->selectionEnd() - 1);
2000 node->setCursor(cursorRectangle(), d->color, &recycleBin);
2001 node->discardUnusedNodes(&recycleBin);
2003 d->textLayoutDirty =
false;
2006 d->containsUnscalableGlyphs = node->containsUnscalableGlyphs();
2008 invalidateFontCaches();
2014QVariant QQuickTextInput::inputMethodQuery(Qt::InputMethodQuery property)
const
2018 if (property == Qt::ImEnterKeyType) {
2019 Q_D(
const QQuickItem);
2021 if (!d->extra.isAllocated()
2022 || d->extra->enterKeyAttached ==
nullptr
2023 || d->extra->enterKeyAttached->type() == Qt::EnterKeyDefault) {
2025 QQuickItem *next =
const_cast<QQuickTextInput*>(
this)->nextItemInFocusChain();
2026 QQuickItem *originalNext = next;
2027 while (next && next !=
this && !next->activeFocusOnTab()) {
2028 next = next->nextItemInFocusChain();
2029 if (next == originalNext) {
2035 const auto nextYPos = next->mapToGlobal(QPoint(0, 0)).y();
2036 const auto currentYPos =
this->mapToGlobal(QPoint(0, 0)).y();
2037 if (currentYPos < nextYPos)
2040 return Qt::EnterKeyNext;
2045 return inputMethodQuery(property, QVariant());
2048QVariant QQuickTextInput::inputMethodQuery(Qt::InputMethodQuery property,
const QVariant &argument)
const
2050 Q_D(
const QQuickTextInput);
2053 return QVariant((
bool)(flags() & ItemAcceptsInputMethod));
2055 return QVariant((
int) d->effectiveInputMethodHints());
2056 case Qt::ImCursorRectangle:
2057 return cursorRectangle();
2058 case Qt::ImAnchorRectangle:
2059 return d->anchorRectangle();
2062 case Qt::ImCursorPosition: {
2063 const QPointF pt = argument.toPointF();
2065 return QVariant(d->positionAt(pt));
2066 return QVariant(d->m_cursor);
2068 case Qt::ImSurroundingText:
2069 if (d->m_echoMode == PasswordEchoOnEdit && !d->m_passwordEchoEditing) {
2070 return QVariant(displayText());
2072 return QVariant(d->realText());
2074 case Qt::ImCurrentSelection:
2075 return QVariant(selectedText());
2076 case Qt::ImMaximumTextLength:
2077 return QVariant(maxLength());
2078 case Qt::ImAnchorPosition:
2079 if (d->selectionStart() == d->selectionEnd())
2080 return QVariant(d->m_cursor);
2081 else if (d->selectionStart() == d->m_cursor)
2082 return QVariant(d->selectionEnd());
2084 return QVariant(d->selectionStart());
2085 case Qt::ImAbsolutePosition:
2086 return QVariant(d->m_cursor);
2087 case Qt::ImTextAfterCursor:
2088 if (argument.isValid())
2089 return QVariant(d->m_text.mid(d->m_cursor, argument.toInt()));
2090 return QVariant(d->m_text.mid(d->m_cursor));
2091 case Qt::ImTextBeforeCursor:
2092 if (argument.isValid())
2093 return QVariant(QStringView{d->m_text}.left(d->m_cursor).right(argument.toInt()).toString());
2094 return QVariant(d->m_text.left(d->m_cursor));
2095 case Qt::ImReadOnly:
2096 return QVariant(d->m_readOnly);
2098 return QQuickItem::inputMethodQuery(property);
2104
2105
2106
2107
2108void QQuickTextInput::deselect()
2110 Q_D(QQuickTextInput);
2115
2116
2117
2118
2119void QQuickTextInput::selectAll()
2121 Q_D(QQuickTextInput);
2122 d->setSelection(0, text().size());
2126
2127
2128
2129
2130
2131bool QQuickTextInput::isRightToLeft(
int start,
int end)
2134 qmlWarning(
this) <<
"isRightToLeft(start, end) called with the end property being smaller than the start.";
2137 return QStringView{text()}.mid(start, end - start).isRightToLeft();
2141#if QT_CONFIG(clipboard)
2143
2144
2145
2146
2147
2148
2149
2150
2151void QQuickTextInput::cut()
2153 Q_D(QQuickTextInput);
2154 if (!d->m_readOnly && d->m_echoMode == QQuickTextInput::Normal) {
2161
2162
2163
2164
2165
2166
2167
2168
2169void QQuickTextInput::copy()
2171 Q_D(QQuickTextInput);
2176
2177
2178
2179
2180void QQuickTextInput::paste()
2182 Q_D(QQuickTextInput);
2189
2190
2191
2192
2193
2194
2196void QQuickTextInput::undo()
2198 Q_D(QQuickTextInput);
2199 if (!d->m_readOnly) {
2202 d->finishChange(-1,
true);
2207
2208
2209
2210
2212void QQuickTextInput::redo()
2214 Q_D(QQuickTextInput);
2215 if (!d->m_readOnly) {
2223
2224
2225
2226
2228void QQuickTextInput::insert(
int position,
const QString &text)
2230 Q_D(QQuickTextInput);
2231 if (d->m_echoMode == QQuickTextInput::Password) {
2232 if (d->m_passwordMaskDelay > 0)
2233 d->m_passwordEchoTimer.start(d->m_passwordMaskDelay,
this);
2235 if (position < 0 || position > d->m_text.size())
2238 const int priorState = d->m_undoState;
2240 QString insertText = text;
2242 if (d->hasSelectedText()) {
2243 d->addCommand(QQuickTextInputPrivate::Command(
2244 QQuickTextInputPrivate::SetSelection, d->m_cursor, u'\0', d->m_selstart, d->m_selend));
2246 if (d->m_maskData) {
2247 insertText = d->maskString(position, insertText);
2248 for (
int i = 0; i < insertText.size(); ++i) {
2249 d->addCommand(QQuickTextInputPrivate::Command(
2250 QQuickTextInputPrivate::DeleteSelection, position + i, d->m_text.at(position + i), -1, -1));
2251 d->addCommand(QQuickTextInputPrivate::Command(
2252 QQuickTextInputPrivate::Insert, position + i, insertText.at(i), -1, -1));
2254 d->m_text.replace(position, insertText.size(), insertText);
2255 if (!insertText.isEmpty())
2256 d->m_textDirty =
true;
2257 if (position < d->m_selend && position + insertText.size() > d->m_selstart)
2258 d->m_selDirty =
true;
2260 int remaining = d->m_maxLength - d->m_text.size();
2261 if (remaining != 0) {
2262 insertText = insertText.left(remaining);
2263 d->m_text.insert(position, insertText);
2264 for (
int i = 0; i < insertText.size(); ++i)
2265 d->addCommand(QQuickTextInputPrivate::Command(
2266 QQuickTextInputPrivate::Insert, position + i, insertText.at(i), -1, -1));
2267 if (d->m_cursor >= position)
2268 d->m_cursor += insertText.size();
2269 if (d->m_selstart >= position)
2270 d->m_selstart += insertText.size();
2271 if (d->m_selend >= position)
2272 d->m_selend += insertText.size();
2273 d->m_textDirty =
true;
2274 if (position >= d->m_selstart && position <= d->m_selend)
2275 d->m_selDirty =
true;
2279 d->addCommand(QQuickTextInputPrivate::Command(
2280 QQuickTextInputPrivate::SetSelection, d->m_cursor, u'\0', d->m_selstart, d->m_selend));
2281 d->finishChange(priorState);
2283 if (d->lastSelectionStart != d->lastSelectionEnd) {
2284 if (d->m_selstart != d->lastSelectionStart) {
2285 d->lastSelectionStart = d->m_selstart;
2286 emit selectionStartChanged();
2288 if (d->m_selend != d->lastSelectionEnd) {
2289 d->lastSelectionEnd = d->m_selend;
2290 emit selectionEndChanged();
2296
2297
2298
2299
2301void QQuickTextInput::remove(
int start,
int end)
2303 Q_D(QQuickTextInput);
2305 start = qBound(0, start, d->m_text.size());
2306 end = qBound(0, end, d->m_text.size());
2310 else if (start == end)
2313 if (start < d->m_selend && end > d->m_selstart)
2314 d->m_selDirty =
true;
2316 const int priorState = d->m_undoState;
2318 d->addCommand(QQuickTextInputPrivate::Command(
2319 QQuickTextInputPrivate::SetSelection, d->m_cursor, u'\0', d->m_selstart, d->m_selend));
2321 if (start <= d->m_cursor && d->m_cursor < end) {
2324 for (
int i = d->m_cursor; i >= start; --i) {
2325 d->addCommand(QQuickTextInputPrivate::Command(
2326 QQuickTextInputPrivate::DeleteSelection, i, d->m_text.at(i), -1, 1));
2328 for (
int i = end - 1; i > d->m_cursor; --i) {
2329 d->addCommand(QQuickTextInputPrivate::Command(
2330 QQuickTextInputPrivate::DeleteSelection, i - d->m_cursor + start - 1, d->m_text.at(i), -1, -1));
2333 for (
int i = end - 1; i >= start; --i) {
2334 d->addCommand(QQuickTextInputPrivate::Command(
2335 QQuickTextInputPrivate::RemoveSelection, i, d->m_text.at(i), -1, -1));
2338 if (d->m_maskData) {
2339 d->m_text.replace(start, end - start, d->clearString(start, end - start));
2340 for (
int i = 0; i < end - start; ++i) {
2341 d->addCommand(QQuickTextInputPrivate::Command(
2342 QQuickTextInputPrivate::Insert, start + i, d->m_text.at(start + i), -1, -1));
2345 d->m_text.remove(start, end - start);
2347 if (d->m_cursor > start)
2348 d->m_cursor -= qMin(d->m_cursor, end) - start;
2349 if (d->m_selstart > start)
2350 d->m_selstart -= qMin(d->m_selstart, end) - start;
2351 if (d->m_selend >= end)
2352 d->m_selend -= end - start;
2354 d->addCommand(QQuickTextInputPrivate::Command(
2355 QQuickTextInputPrivate::SetSelection, d->m_cursor, u'\0', d->m_selstart, d->m_selend));
2357 d->m_textDirty =
true;
2358 d->finishChange(priorState);
2360 if (d->lastSelectionStart != d->lastSelectionEnd) {
2361 if (d->m_selstart != d->lastSelectionStart) {
2362 d->lastSelectionStart = d->m_selstart;
2363 emit selectionStartChanged();
2365 if (d->m_selend != d->lastSelectionEnd) {
2366 d->lastSelectionEnd = d->m_selend;
2367 emit selectionEndChanged();
2374
2375
2376
2377
2378void QQuickTextInput::selectWord()
2380 Q_D(QQuickTextInput);
2381 d->selectWordAtPos(d->m_cursor);
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395QString QQuickTextInput::passwordCharacter()
const
2397 Q_D(
const QQuickTextInput);
2398 return QString(d->m_passwordCharacter);
2401void QQuickTextInput::setPasswordCharacter(
const QString &str)
2403 Q_D(QQuickTextInput);
2406 d->m_passwordCharacter = str.constData()[0];
2407 if (d->m_echoMode == Password || d->m_echoMode == PasswordEchoOnEdit)
2408 d->updateDisplayText();
2409 emit passwordCharacterChanged();
2413
2414
2415
2416
2417
2418
2419
2420int QQuickTextInput::passwordMaskDelay()
const
2422 Q_D(
const QQuickTextInput);
2423 return d->m_passwordMaskDelay;
2426void QQuickTextInput::setPasswordMaskDelay(
int delay)
2428 Q_D(QQuickTextInput);
2429 if (d->m_passwordMaskDelay != delay) {
2430 d->m_passwordMaskDelay = delay;
2431 emit passwordMaskDelayChanged(delay);
2435void QQuickTextInput::resetPasswordMaskDelay()
2437 setPasswordMaskDelay(qGuiApp->styleHints()->passwordMaskDelay());
2441
2442
2443
2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454
2455
2456QString QQuickTextInput::displayText()
const
2458 Q_D(
const QQuickTextInput);
2459 return d->m_textLayout.text().insert(d->m_textLayout.preeditAreaPosition(), d->m_textLayout.preeditAreaText());
2463
2464
2465
2466
2467
2468
2469
2470
2471
2472
2473
2474QString QQuickTextInput::preeditText()
const
2476 Q_D(
const QQuickTextInput);
2477 return d->m_textLayout.preeditAreaText();
2481
2482
2483
2484
2485
2486
2487
2488
2489
2490
2491
2492
2493
2494
2495
2496
2497
2498bool QQuickTextInput::selectByMouse()
const
2500 Q_D(
const QQuickTextInput);
2501 return d->selectByMouse;
2504void QQuickTextInput::setSelectByMouse(
bool on)
2506 Q_D(QQuickTextInput);
2507 if (d->selectByMouse != on) {
2508 d->selectByMouse = on;
2509 emit selectByMouseChanged(on);
2514
2515
2516
2517
2518
2519
2520
2521
2522
2524QQuickTextInput::SelectionMode QQuickTextInput::mouseSelectionMode()
const
2526 Q_D(
const QQuickTextInput);
2527 return d->mouseSelectionMode;
2530void QQuickTextInput::setMouseSelectionMode(SelectionMode mode)
2532 Q_D(QQuickTextInput);
2533 if (d->mouseSelectionMode != mode) {
2534 d->mouseSelectionMode = mode;
2535 emit mouseSelectionModeChanged(mode);
2540
2541
2542
2543
2544
2546bool QQuickTextInput::persistentSelection()
const
2548 Q_D(
const QQuickTextInput);
2549 return d->persistentSelection;
2552void QQuickTextInput::setPersistentSelection(
bool on)
2554 Q_D(QQuickTextInput);
2555 if (d->persistentSelection == on)
2557 d->persistentSelection = on;
2558 emit persistentSelectionChanged();
2562
2563
2564
2565
2566
2567
2568bool QQuickTextInput::canPaste()
const
2570#if QT_CONFIG(clipboard)
2571 Q_D(
const QQuickTextInput);
2572 if (!d->canPasteValid) {
2573 bool canPaste =
false;
2574 if (!d->m_readOnly) {
2575 if (
const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData())
2576 canPaste = mimeData->hasText() && !mimeData->text().isEmpty();
2578 const_cast<QQuickTextInputPrivate *>(d)->canPaste = canPaste;
2579 const_cast<QQuickTextInputPrivate *>(d)->canPasteValid =
true;
2588
2589
2590
2591
2592
2593
2595bool QQuickTextInput::canUndo()
const
2597 Q_D(
const QQuickTextInput);
2602
2603
2604
2605
2606
2607
2609bool QQuickTextInput::canRedo()
const
2611 Q_D(
const QQuickTextInput);
2616
2617
2618
2619
2620
2621
2623qreal QQuickTextInput::contentWidth()
const
2625 Q_D(
const QQuickTextInput);
2626 return d->contentSize.width();
2630
2631
2632
2633
2634
2635
2637qreal QQuickTextInput::contentHeight()
const
2639 Q_D(
const QQuickTextInput);
2640 return d->contentSize.height();
2643void QQuickTextInput::moveCursorSelection(
int position)
2645 Q_D(QQuickTextInput);
2646 d->moveCursor(position,
true);
2650
2651
2652
2653
2654
2655
2656
2657
2658
2659
2660
2661
2662
2663
2664
2665
2666
2667
2668
2669
2670
2671
2672
2673
2674
2675
2676
2677
2678
2679
2680
2681
2682
2683
2684
2685void QQuickTextInput::moveCursorSelection(
int pos, SelectionMode mode)
2687 Q_D(QQuickTextInput);
2689 if (mode == SelectCharacters) {
2690 d->moveCursor(pos,
true);
2691 }
else if (pos != d->m_cursor) {
2692 const int cursor = d->m_cursor;
2694 if (!d->hasSelectedText())
2695 anchor = d->m_cursor;
2696 else if (d->selectionStart() == d->m_cursor)
2697 anchor = d->selectionEnd();
2699 anchor = d->selectionStart();
2701 if (anchor < pos || (anchor == pos && cursor < pos)) {
2702 const QString text =
this->text();
2703 QTextBoundaryFinder finder(QTextBoundaryFinder::Word, text);
2704 finder.setPosition(anchor);
2706 const QTextBoundaryFinder::BoundaryReasons reasons = finder.boundaryReasons();
2707 if (anchor < text.size() && (reasons == QTextBoundaryFinder::NotAtBoundary
2708 || (reasons & QTextBoundaryFinder::EndOfItem))) {
2709 finder.toPreviousBoundary();
2711 anchor = finder.position() != -1 ? finder.position() : 0;
2713 finder.setPosition(pos);
2714 if (pos > 0 && !finder.boundaryReasons())
2715 finder.toNextBoundary();
2716 const int cursor = finder.position() != -1 ? finder.position() : text.size();
2718 d->setSelection(anchor, cursor - anchor);
2719 }
else if (anchor > pos || (anchor == pos && cursor > pos)) {
2720 const QString text =
this->text();
2721 QTextBoundaryFinder finder(QTextBoundaryFinder::Word, text);
2722 finder.setPosition(anchor);
2724 const QTextBoundaryFinder::BoundaryReasons reasons = finder.boundaryReasons();
2725 if (anchor > 0 && (reasons == QTextBoundaryFinder::NotAtBoundary
2726 || (reasons & QTextBoundaryFinder::StartOfItem))) {
2727 finder.toNextBoundary();
2729 anchor = finder.position() != -1 ? finder.position() : text.size();
2731 finder.setPosition(pos);
2732 if (pos < text.size() && !finder.boundaryReasons())
2733 finder.toPreviousBoundary();
2734 const int cursor = finder.position() != -1 ? finder.position() : 0;
2736 d->setSelection(anchor, cursor - anchor);
2741void QQuickTextInput::focusInEvent(QFocusEvent *event)
2743 Q_D(QQuickTextInput);
2744 d->handleFocusEvent(event);
2745 QQuickImplicitSizeItem::focusInEvent(event);
2748void QQuickTextInputPrivate::handleFocusEvent(QFocusEvent *event)
2750 Q_Q(QQuickTextInput);
2751 bool focus = event->gotFocus();
2753 q->setCursorVisible(focus);
2754 setBlinkingCursorEnabled(focus);
2757 q->q_updateAlignment();
2759 if (focusOnPress && !m_readOnly)
2760 qGuiApp->inputMethod()->show();
2761 q->connect(QGuiApplication::inputMethod(), SIGNAL(inputDirectionChanged(Qt::LayoutDirection)),
2762 q, SLOT(q_updateAlignment()));
2765 if ((m_passwordEchoEditing || m_passwordEchoTimer.isActive())) {
2766 updatePasswordEchoEditing(
false);
2769 if (event->reason() != Qt::ActiveWindowFocusReason
2770 && event->reason() != Qt::PopupFocusReason
2771 && hasSelectedText()
2772 && !persistentSelection)
2775 if (hasAcceptableInput(m_text) == AcceptableInput || fixup())
2776 emit q->editingFinished();
2779 q->disconnect(QGuiApplication::inputMethod(), SIGNAL(inputDirectionChanged(Qt::LayoutDirection)),
2780 q, SLOT(q_updateAlignment()));
2785void QQuickTextInput::focusOutEvent(QFocusEvent *event)
2787 Q_D(QQuickTextInput);
2788 d->handleFocusEvent(event);
2789 QQuickImplicitSizeItem::focusOutEvent(event);
2792void QQuickTextInputPrivate::readOnlyChanged(
bool isReadOnly)
2794 Q_UNUSED(isReadOnly);
2795#if QT_CONFIG(accessibility)
2796 if (QQuickAccessibleAttached *accessibleAttached =
2797 QQuickAccessibleAttached::attachedProperties(q_func()))
2798 accessibleAttached->set_readOnly(isReadOnly);
2802void QQuickTextInputPrivate::echoModeChanged(QQuickTextInput::EchoMode echoMode)
2804#if QT_CONFIG(accessibility)
2805 if (!QAccessible::isActive())
2808 if (QQuickAccessibleAttached *accessibleAttached =
2809 QQuickAccessibleAttached::attachedProperties(q_func()))
2810 accessibleAttached->set_passwordEdit((echoMode == QQuickTextInput::Password
2811 || echoMode == QQuickTextInput::PasswordEchoOnEdit)
2819#if QT_CONFIG(accessibility)
2820void QQuickTextInputPrivate::accessibilityActiveChanged(
bool active)
2825 Q_Q(QQuickTextInput);
2826 QQuickAccessibleAttached *accessibleAttached = qobject_cast<QQuickAccessibleAttached *>(
2827 qmlAttachedPropertiesObject<QQuickAccessibleAttached>(q,
true));
2828 Q_ASSERT(accessibleAttached);
2829 accessibleAttached->setRole(effectiveAccessibleRole());
2830 accessibleAttached->set_readOnly(m_readOnly);
2831 accessibleAttached->set_passwordEdit((m_echoMode == QQuickTextInput::Password
2832 || m_echoMode == QQuickTextInput::PasswordEchoOnEdit)
2837QAccessible::Role QQuickTextInputPrivate::accessibleRole()
const
2839 return QAccessible::EditableText;
2844
2845
2846
2847
2848
2849
2850
2851
2852
2853
2854
2855bool QQuickTextInput::isInputMethodComposing()
const
2860 Q_D(
const QQuickTextInput);
2861 return d->hasImState;
2865QQuickTextInputPrivate::ExtraData::ExtraData()
2871 , explicitTopPadding(
false)
2872 , explicitLeftPadding(
false)
2873 , explicitRightPadding(
false)
2874 , explicitBottomPadding(
false)
2875 , implicitResize(
true)
2879void QQuickTextInputPrivate::init()
2881 Q_Q(QQuickTextInput);
2882#if QT_CONFIG(clipboard)
2883 if (QGuiApplication::clipboard()->supportsSelection())
2884 q->setAcceptedMouseButtons(Qt::LeftButton | Qt::MiddleButton);
2887 q->setAcceptedMouseButtons(Qt::LeftButton);
2890 q->setFlag(QQuickItem::ItemAcceptsInputMethod);
2892 q->setFlag(QQuickItem::ItemHasContents);
2893#if QT_CONFIG(clipboard)
2894 qmlobject_connect(QGuiApplication::clipboard(), QClipboard, SIGNAL(dataChanged()),
2895 q, QQuickTextInput, SLOT(q_canPasteChanged()));
2898 lastSelectionStart = 0;
2899 lastSelectionEnd = 0;
2900 determineHorizontalAlignment();
2902 if (!qmlDisableDistanceField()) {
2903 QTextOption option = m_textLayout.textOption();
2904 option.setUseDesignMetrics(renderType != QQuickTextInput::NativeRendering);
2905 m_textLayout.setTextOption(option);
2908 m_inputControl =
new QInputControl(QInputControl::LineEdit, q);
2909 setSizePolicy(QLayoutPolicy::Expanding, QLayoutPolicy::Fixed);
2911 QObjectPrivate::connect(q, &QQuickTextInput::readOnlyChanged,
this,
2912 &QQuickTextInputPrivate::readOnlyChanged);
2913 QObjectPrivate::connect(q, &QQuickTextInput::echoModeChanged,
this,
2914 &QQuickTextInputPrivate::echoModeChanged);
2917void QQuickTextInputPrivate::cancelInput()
2920 Q_Q(QQuickTextInput);
2921 if (!m_readOnly && q->hasActiveFocus() && qGuiApp)
2926void QQuickTextInput::updateCursorRectangle(
bool scroll)
2928 Q_D(QQuickTextInput);
2929 if (!isComponentComplete())
2933 d->updateHorizontalScroll();
2934 d->updateVerticalScroll();
2936 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
2939 emit cursorRectangleChanged();
2940 if (d->cursorItem) {
2941 QRectF r = cursorRectangle();
2942 d->cursorItem->setPosition(r.topLeft());
2943 d->cursorItem->setHeight(r.height());
2946 updateInputMethod(Qt::ImCursorRectangle | Qt::ImAnchorRectangle);
2950void QQuickTextInput::selectionChanged()
2952 Q_D(QQuickTextInput);
2953 d->textLayoutDirty =
true;
2954 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
2957 emit selectedTextChanged();
2959 if (d->lastSelectionStart != d->selectionStart()) {
2960 d->lastSelectionStart = d->selectionStart();
2961 if (d->lastSelectionStart == -1)
2962 d->lastSelectionStart = d->m_cursor;
2963 emit selectionStartChanged();
2965 if (d->lastSelectionEnd != d->selectionEnd()) {
2966 d->lastSelectionEnd = d->selectionEnd();
2967 if (d->lastSelectionEnd == -1)
2968 d->lastSelectionEnd = d->m_cursor;
2969 emit selectionEndChanged();
2973QRectF QQuickTextInput::boundingRect()
const
2975 Q_D(
const QQuickTextInput);
2977 int cursorWidth = d->cursorItem ? 0 : 1;
2979 qreal hscroll = d->hscroll;
2980 if (!d->autoScroll || d->contentSize.width() < width())
2981 hscroll -= QQuickTextUtil::alignedX(d->contentSize.width(), width(), effectiveHAlign());
2984 QRectF r(-hscroll, -d->vscroll, d->contentSize.width(), d->contentSize.height());
2985 r.setRight(r.right() + cursorWidth);
2989QRectF QQuickTextInput::clipRect()
const
2991 Q_D(
const QQuickTextInput);
2993 int cursorWidth = d->cursorItem ? d->cursorItem->width() : 1;
2996 QRectF r = QQuickImplicitSizeItem::clipRect();
2997 r.setRight(r.right() + cursorWidth);
3001void QQuickTextInput::q_canPasteChanged()
3003 Q_D(QQuickTextInput);
3004 bool old = d->canPaste;
3005#if QT_CONFIG(clipboard)
3006 bool canPaste =
false;
3007 if (!d->m_readOnly) {
3008 if (
const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData())
3009 canPaste = mimeData->hasText() && !mimeData->text().isEmpty();
3011 d->canPaste = canPaste;
3014 bool changed = d->canPaste != old || !d->canPasteValid;
3015 d->canPasteValid =
true;
3017 emit canPasteChanged();
3021void QQuickTextInput::q_updateAlignment()
3023 Q_D(QQuickTextInput);
3024 if (d->determineHorizontalAlignment()) {
3026 updateCursorRectangle();
3031
3032
3033
3034
3035
3036void QQuickTextInputPrivate::updateDisplayText(
bool forceUpdate)
3038 QString orig = m_textLayout.text();
3040 if (m_echoMode == QQuickTextInput::NoEcho)
3041 str = QString::fromLatin1(
"");
3045 if (m_echoMode == QQuickTextInput::Password) {
3046 str.fill(m_passwordCharacter);
3047 if (m_passwordEchoTimer.isActive() && m_cursor > 0 && m_cursor <= m_text.size()) {
3048 int cursor = m_cursor - 1;
3049 QChar uc = m_text.at(cursor);
3051 if (cursor > 0 && uc.unicode() >= 0xdc00 && uc.unicode() < 0xe000) {
3054 uc = m_text.at(cursor - 1);
3055 if (uc.unicode() >= 0xd800 && uc.unicode() < 0xdc00)
3056 str[cursor - 1] = uc;
3059 }
else if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit && !m_passwordEchoEditing) {
3060 str.fill(m_passwordCharacter);
3066 QChar* uc = str.data();
3067 for (
int i = 0; i < str.size(); ++i) {
3068 if (uc[i] == QChar::LineSeparator
3069 || uc[i] == QChar::ParagraphSeparator
3070 || uc[i] == QChar::ObjectReplacementCharacter)
3071 uc[i] = QChar(0x0020);
3074 if (str != orig || forceUpdate) {
3075 m_textLayout.setText(str);
3077 emit q_func()->displayTextChanged();
3081qreal QQuickTextInputPrivate::calculateImplicitWidthForText(
const QString &text)
const
3083 Q_Q(
const QQuickTextInput);
3084 QTextLayout layout(text);
3086 QTextOption option = m_textLayout.textOption();
3087 option.setTextDirection(m_layoutDirection);
3088 option.setFlags(QTextOption::IncludeTrailingSpaces);
3089 option.setWrapMode(QTextOption::WrapMode(wrapMode));
3090 option.setAlignment(Qt::Alignment(q->effectiveHAlign()));
3091 layout.setTextOption(option);
3092 layout.setFont(font);
3094 layout.setPreeditArea(m_textLayout.preeditAreaPosition(), m_textLayout.preeditAreaText());
3096 layout.beginLayout();
3098 QTextLine line = layout.createLine();
3099 line.setLineWidth(qreal(INT_MAX));
3100 const qreal theImplicitWidth = qCeil(line.naturalTextWidth()) + q->leftPadding() + q->rightPadding();
3103 return theImplicitWidth;
3106qreal QQuickTextInputPrivate::getImplicitWidth()
const
3108 Q_Q(
const QQuickTextInput);
3109 if (!requireImplicitWidth) {
3110 QQuickTextInputPrivate *d =
const_cast<QQuickTextInputPrivate *>(
this);
3111 d->requireImplicitWidth =
true;
3113 if (q->isComponentComplete())
3114 d->implicitWidth = calculateImplicitWidthForText(m_text);
3116 return implicitWidth;
3119void QQuickTextInputPrivate::setTopPadding(qreal value,
bool reset)
3121 Q_Q(QQuickTextInput);
3122 qreal oldPadding = q->topPadding();
3123 if (!reset || extra.isAllocated()) {
3124 extra.value().topPadding = value;
3125 extra.value().explicitTopPadding = !reset;
3127 if ((!reset && !qFuzzyCompare(oldPadding, value)) || (reset && !qFuzzyCompare(oldPadding, padding()))) {
3129 q->updateCursorRectangle();
3130 emit q->topPaddingChanged();
3134void QQuickTextInputPrivate::setLeftPadding(qreal value,
bool reset)
3136 Q_Q(QQuickTextInput);
3137 qreal oldPadding = q->leftPadding();
3138 if (!reset || extra.isAllocated()) {
3139 extra.value().leftPadding = value;
3140 extra.value().explicitLeftPadding = !reset;
3142 if ((!reset && !qFuzzyCompare(oldPadding, value)) || (reset && !qFuzzyCompare(oldPadding, padding()))) {
3144 q->updateCursorRectangle();
3145 emit q->leftPaddingChanged();
3149void QQuickTextInputPrivate::setRightPadding(qreal value,
bool reset)
3151 Q_Q(QQuickTextInput);
3152 qreal oldPadding = q->rightPadding();
3153 if (!reset || extra.isAllocated()) {
3154 extra.value().rightPadding = value;
3155 extra.value().explicitRightPadding = !reset;
3157 if ((!reset && !qFuzzyCompare(oldPadding, value)) || (reset && !qFuzzyCompare(oldPadding, padding()))) {
3159 q->updateCursorRectangle();
3160 emit q->rightPaddingChanged();
3164void QQuickTextInputPrivate::setBottomPadding(qreal value,
bool reset)
3166 Q_Q(QQuickTextInput);
3167 qreal oldPadding = q->bottomPadding();
3168 if (!reset || extra.isAllocated()) {
3169 extra.value().bottomPadding = value;
3170 extra.value().explicitBottomPadding = !reset;
3172 if ((!reset && !qFuzzyCompare(oldPadding, value)) || (reset && !qFuzzyCompare(oldPadding, padding()))) {
3174 q->updateCursorRectangle();
3175 emit q->bottomPaddingChanged();
3179bool QQuickTextInputPrivate::isImplicitResizeEnabled()
const
3181 return !extra.isAllocated() || extra->implicitResize;
3184void QQuickTextInputPrivate::setImplicitResizeEnabled(
bool enabled)
3187 extra.value().implicitResize =
false;
3188 else if (extra.isAllocated())
3189 extra->implicitResize =
true;
3192void QQuickTextInputPrivate::updateLayout()
3194 Q_Q(QQuickTextInput);
3196 if (!q->isComponentComplete())
3200 QTextOption option = m_textLayout.textOption();
3201 option.setTextDirection(layoutDirection());
3202 option.setWrapMode(QTextOption::WrapMode(wrapMode));
3203 option.setAlignment(Qt::Alignment(q->effectiveHAlign()));
3204 if (!qmlDisableDistanceField())
3205 option.setUseDesignMetrics(renderType != QQuickTextInput::NativeRendering);
3207 m_textLayout.setTextOption(option);
3208 m_textLayout.setFont(font);
3210 m_textLayout.beginLayout();
3212 QTextLine line = m_textLayout.createLine();
3213 if (requireImplicitWidth) {
3214 line.setLineWidth(qreal(INT_MAX));
3215 const bool wasInLayout = inLayout;
3217 if (isImplicitResizeEnabled())
3218 q->setImplicitWidth(qCeil(line.naturalTextWidth()) + q->leftPadding() + q->rightPadding());
3219 inLayout = wasInLayout;
3223 qreal lineWidth = q->widthValid() || !isImplicitResizeEnabled() ? q->width() - q->leftPadding() - q->rightPadding() : qreal(INT_MAX);
3227 line.setLineWidth(lineWidth);
3228 line.setPosition(QPointF(0, height));
3230 height += line.height();
3231 width = qMax(width, line.naturalTextWidth());
3233 line = m_textLayout.createLine();
3234 }
while (line.isValid());
3235 m_textLayout.endLayout();
3237 option.setWrapMode(QTextOption::NoWrap);
3238 m_textLayout.setTextOption(option);
3240 textLayoutDirty =
true;
3242 const QSizeF previousSize = contentSize;
3243 contentSize = QSizeF(width, height);
3245 updateType = UpdatePaintNode;
3249 if (isImplicitResizeEnabled()) {
3250 if (!requireImplicitWidth && !q->widthValid())
3251 q->setImplicitSize(width + q->leftPadding() + q->rightPadding(), height + q->topPadding() + q->bottomPadding());
3253 q->setImplicitHeight(height + q->topPadding() + q->bottomPadding());
3256 updateBaselineOffset();
3258 if (previousSize != contentSize)
3259 emit q->contentSizeChanged();
3263
3264
3265
3266
3267
3268void QQuickTextInputPrivate::updateBaselineOffset()
3270 Q_Q(QQuickTextInput);
3271 if (!q->isComponentComplete())
3273 QFontMetricsF fm(font);
3275 if (q->heightValid()) {
3276 const qreal surplusHeight = q->height() - contentSize.height() - q->topPadding() - q->bottomPadding();
3277 if (vAlign == QQuickTextInput::AlignBottom)
3278 yoff = surplusHeight;
3279 else if (vAlign == QQuickTextInput::AlignVCenter)
3280 yoff = surplusHeight/2;
3283 if (m_textLayout.lineCount() > 0) {
3284 QTextLine line = m_textLayout.lineAt(0);
3285 ascent = line.y() + line.ascent();
3287 ascent = fm.ascent();
3289 q->setBaselineOffset(ascent + yoff + q->topPadding());
3292#if QT_CONFIG(clipboard)
3294
3295
3296
3297
3298
3299
3300
3301
3302
3303void QQuickTextInputPrivate::copy(QClipboard::Mode mode)
const
3305 QString t = selectedText();
3306 if (!t.isEmpty() && m_echoMode == QQuickTextInput::Normal) {
3307 QGuiApplication::clipboard()->setText(t, mode);
3312
3313
3314
3315
3316
3317
3318
3319void QQuickTextInputPrivate::paste(QClipboard::Mode clipboardMode)
3321 QString clip = QGuiApplication::clipboard()->text(clipboardMode);
3322 if (!clip.isEmpty() || hasSelectedText()) {
3333
3334
3335void QQuickTextInputPrivate::commitPreedit()
3337 Q_Q(QQuickTextInput);
3342 QGuiApplication::inputMethod()->commit();
3347 QInputMethodEvent ev;
3348 QCoreApplication::sendEvent(q, &ev);
3351void QQuickTextInputPrivate::cancelPreedit()
3353 Q_Q(QQuickTextInput);
3358 QGuiApplication::inputMethod()->reset();
3360 QInputMethodEvent ev;
3361 QCoreApplication::sendEvent(q, &ev);
3366
3367
3368
3369
3370
3371
3372
3373
3374void QQuickTextInputPrivate::backspace()
3376 int priorState = m_undoState;
3377 if (separateSelection()) {
3378 removeSelectedText();
3379 }
else if (m_cursor) {
3382 m_cursor = prevMaskBlank(m_cursor);
3383 QChar uc = m_text.at(m_cursor);
3384 if (m_cursor > 0 && uc.unicode() >= 0xdc00 && uc.unicode() < 0xe000) {
3387 uc = m_text.at(m_cursor - 1);
3388 if (uc.unicode() >= 0xd800 && uc.unicode() < 0xdc00) {
3389 internalDelete(
true);
3393 internalDelete(
true);
3395 finishChange(priorState);
3399
3400
3401
3402
3403
3404
3405
3406
3407void QQuickTextInputPrivate::del()
3409 int priorState = m_undoState;
3410 if (separateSelection()) {
3411 removeSelectedText();
3413 int n = m_textLayout.nextCursorPosition(m_cursor) - m_cursor;
3417 finishChange(priorState);
3421
3422
3423
3424
3425
3426
3427void QQuickTextInputPrivate::insert(
const QString &newText)
3429 int priorState = m_undoState;
3430 if (separateSelection())
3431 removeSelectedText();
3432 internalInsert(newText);
3433 finishChange(priorState);
3437
3438
3439
3440
3441void QQuickTextInputPrivate::clear()
3443 int priorState = m_undoState;
3444 separateSelection();
3446 m_selend = m_text.size();
3447 removeSelectedText();
3449 finishChange(priorState,
false,
false);
3453
3454
3455
3456
3457
3458
3459
3460void QQuickTextInputPrivate::setSelection(
int start,
int length)
3462 Q_Q(QQuickTextInput);
3467 if (start < 0 || start > m_text.size()) {
3468 qWarning(
"QQuickTextInputPrivate::setSelection: Invalid start position");
3473 if (start == m_selstart && start + length == m_selend && m_cursor == m_selend)
3476 m_selend = qMin(start + length, m_text.size());
3477 m_cursor = m_selend;
3478 }
else if (length < 0) {
3479 if (start == m_selend && start + length == m_selstart && m_cursor == m_selstart)
3481 m_selstart = qMax(start + length, 0);
3483 m_cursor = m_selstart;
3484 }
else if (m_selstart != m_selend) {
3490 emitCursorPositionChanged();
3493 emit q->selectionChanged();
3494 emitCursorPositionChanged();
3496 q->updateInputMethod(Qt::ImCursorRectangle | Qt::ImAnchorRectangle | Qt::ImCursorPosition | Qt::ImAnchorPosition
3497 | Qt::ImCurrentSelection);
3502
3503
3504
3505
3506
3507
3508
3509void QQuickTextInputPrivate::updatePasswordEchoEditing(
bool editing)
3511 cancelPasswordEchoTimer();
3512 m_passwordEchoEditing = editing;
3513 updateDisplayText();
3517
3518
3519
3520
3521
3522
3523bool QQuickTextInputPrivate::fixup()
3525#if QT_CONFIG(validator)
3527 QString textCopy = m_text;
3528 int cursorCopy = m_cursor;
3529 m_validator->fixup(textCopy);
3530 if (m_validator->validate(textCopy, cursorCopy) == QValidator::Acceptable) {
3531 if (textCopy != m_text || cursorCopy != m_cursor)
3532 internalSetText(textCopy, cursorCopy);
3541
3542
3543
3544
3545
3546void QQuickTextInputPrivate::moveCursor(
int pos,
bool mark)
3548 Q_Q(QQuickTextInput);
3553 if (pos != m_cursor) {
3556 pos = pos > m_cursor ? nextMaskBlank(pos) : prevMaskBlank(pos);
3560 if (m_selend > m_selstart && m_cursor == m_selstart)
3562 else if (m_selend > m_selstart && m_cursor == m_selend)
3563 anchor = m_selstart;
3566 m_selstart = qMin(anchor, pos);
3567 m_selend = qMax(anchor, pos);
3572 if (mark || m_selDirty) {
3574 emit q->selectionChanged();
3576 emitCursorPositionChanged();
3578 q->updateInputMethod();
3584
3585
3586
3587
3588
3589void QQuickTextInputPrivate::processInputMethodEvent(QInputMethodEvent *event)
3591 Q_Q(QQuickTextInput);
3593 int priorState = -1;
3594 bool isGettingInput = !event->commitString().isEmpty()
3595 || event->preeditString() != preeditAreaText()
3596 || event->replacementLength() > 0;
3597 bool cursorPositionChanged =
false;
3598 bool selectionChange =
false;
3599 m_preeditDirty = event->preeditString() != preeditAreaText();
3601 if (isGettingInput) {
3603 priorState = m_undoState;
3604 separateSelection();
3605 if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit && !m_passwordEchoEditing) {
3606 updatePasswordEchoEditing(
true);
3608 m_selend = m_text.size();
3610 removeSelectedText();
3614 if (event->replacementStart() <= 0)
3615 c += event->commitString().size() - qMin(-event->replacementStart(), event->replacementLength());
3617 int cursorInsertPos = m_cursor + event->replacementStart();
3618 if (cursorInsertPos < 0)
3619 cursorInsertPos = 0;
3622 if (event->replacementLength()) {
3623 m_selstart = cursorInsertPos;
3624 m_selend = m_selstart + event->replacementLength();
3625 m_selend = qMin(m_selend, m_text.size());
3626 removeSelectedText();
3628 m_cursor = cursorInsertPos;
3630 if (!event->commitString().isEmpty()) {
3631 internalInsert(event->commitString());
3632 cursorPositionChanged =
true;
3634 m_cursor = qBound(0, c, m_text.size());
3637 for (
int i = 0; i < event->attributes().size(); ++i) {
3638 const QInputMethodEvent::Attribute &a = event->attributes().at(i);
3639 if (a.type == QInputMethodEvent::Selection) {
3646 if (!cursorPositionChanged || !m_maskData)
3647 m_cursor = qBound(0, a.start + a.length, m_text.size());
3649 m_selstart = qMax(0, qMin(a.start, m_text.size()));
3650 m_selend = m_cursor;
3651 if (m_selend < m_selstart) {
3652 qSwap(m_selstart, m_selend);
3654 selectionChange =
true;
3656 selectionChange = m_selstart != m_selend;
3657 m_selstart = m_selend = 0;
3659 cursorPositionChanged =
true;
3662 QString oldPreeditString = m_textLayout.preeditAreaText();
3663 m_textLayout.setPreeditArea(m_cursor, event->preeditString());
3664 if (oldPreeditString != m_textLayout.preeditAreaText()) {
3665 emit q->preeditTextChanged();
3666 if (!event->preeditString().isEmpty() && m_undoPreeditState == -1)
3668 m_undoPreeditState = priorState;
3670 const int oldPreeditCursor = m_preeditCursor;
3671 m_preeditCursor = event->preeditString().size();
3672 hasImState = !event->preeditString().isEmpty();
3673 bool cursorVisible =
true;
3674 QList<QTextLayout::FormatRange> formats;
3675 for (
int i = 0; i < event->attributes().size(); ++i) {
3676 const QInputMethodEvent::Attribute &a = event->attributes().at(i);
3677 if (a.type == QInputMethodEvent::Cursor) {
3679 m_preeditCursor = a.start;
3680 cursorVisible = a.length != 0;
3681 }
else if (a.type == QInputMethodEvent::TextFormat) {
3683 QTextCharFormat f = qvariant_cast<QTextFormat>(a.value).toCharFormat();
3685 QTextLayout::FormatRange o;
3686 o.start = a.start + m_cursor;
3687 o.length = a.length;
3693 m_textLayout.setFormats(formats);
3699 q->setCursorVisible(cursorVisible);
3701 updateDisplayText(
true);
3702 if (cursorPositionChanged && emitCursorPositionChanged())
3703 q->updateInputMethod(Qt::ImCursorPosition | Qt::ImAnchorPosition);
3704 else if (m_preeditCursor != oldPreeditCursor || isGettingInput)
3705 q->updateCursorRectangle();
3708 finishChange(priorState);
3710 if (selectionChange) {
3711 emit q->selectionChanged();
3712 q->updateInputMethod(Qt::ImCursorRectangle | Qt::ImAnchorRectangle
3713 | Qt::ImCurrentSelection);
3717 if (event->preeditString().isEmpty())
3718 m_undoPreeditState = -1;
3724
3725
3726
3727
3728
3729
3730void QQuickTextInputPrivate::selectWordAtPos(
int cursor)
3732 int next = cursor + 1;
3735 int c = m_textLayout.previousCursorPosition(next, QTextLayout::SkipWords);
3736 moveCursor(c,
false);
3738 int end = m_textLayout.nextCursorPosition(c, QTextLayout::SkipWords);
3739 while (end > cursor && m_text.at(end - 1).isSpace())
3741 moveCursor(end,
true);
3745
3746
3747
3748
3749
3750
3751
3752
3753
3754
3755
3756bool QQuickTextInputPrivate::finishChange(
int validateFromState,
bool update,
bool edited)
3758 Q_Q(QQuickTextInput);
3762 bool inputMethodAttributesChanged = m_textDirty || m_selDirty;
3764 bool alignmentChanged =
false;
3765 bool textChanged =
false;
3769 bool wasValidInput = m_validInput;
3770 bool wasAcceptable = m_acceptableInput;
3771 m_validInput =
true;
3772 m_acceptableInput =
true;
3773#if QT_CONFIG(validator)
3775 QString textCopy = m_text;
3777 textCopy = maskString(0, m_text,
true);
3778 int cursorCopy = m_cursor;
3779 QValidator::State state = m_validator->validate(textCopy, cursorCopy);
3782 m_validInput = state != QValidator::Invalid;
3783 m_acceptableInput = state == QValidator::Acceptable;
3784 if (m_validInput && !m_maskData) {
3785 if (m_text != textCopy) {
3786 internalSetText(textCopy, cursorCopy);
3789 m_cursor = cursorCopy;
3799 if (m_undoPreeditState >= 0 && (m_undoPreeditState < validateFromState || validateFromState < 0))
3800 validateFromState = m_undoPreeditState;
3802 if (validateFromState >= 0 && wasValidInput && !m_validInput) {
3803 if (m_transactions.size())
3805 internalUndo(validateFromState);
3806 m_history.resize(m_undoState);
3807 m_validInput =
true;
3808 m_acceptableInput = wasAcceptable;
3809 m_textDirty =
false;
3814 m_textDirty =
false;
3816 m_preeditDirty =
false;
3818 alignmentChanged = determineHorizontalAlignment();
3820 emit q->textEdited();
3821 emit q->textChanged();
3824 updateDisplayText(alignmentChanged);
3826 if (m_acceptableInput != wasAcceptable)
3827 emit q->acceptableInputChanged();
3830 if (m_preeditDirty) {
3831 m_preeditDirty =
false;
3832 if (determineHorizontalAlignment()) {
3833 alignmentChanged =
true;
3841 emit q->selectionChanged();
3845 inputMethodAttributesChanged |= (m_cursor != m_lastCursorPos);
3846 if (inputMethodAttributesChanged)
3847 q->updateInputMethod();
3849 emitUndoRedoChanged();
3851 if (!emitCursorPositionChanged() && (alignmentChanged || textChanged))
3852 q->updateCursorRectangle();
3858
3859
3860
3861
3862void QQuickTextInputPrivate::internalSetText(
const QString &txt,
int pos,
bool edited)
3865 QString oldText = m_text;
3867 m_text = maskString(0, txt,
true);
3868 m_text += clearString(m_text.size(), m_maxLength - m_text.size());
3870 m_text = txt.isEmpty() ? txt : txt.left(m_maxLength);
3875 m_undoPreeditState = -1;
3877 m_cursor = (pos < 0 || pos > m_text.size()) ? m_text.size() : pos;
3878 m_textDirty = (oldText != m_text);
3880 bool changed = finishChange(-1,
true, edited);
3881#if !QT_CONFIG(accessibility)
3884 Q_Q(QQuickTextInput);
3885 if (changed && QAccessible::isActive()) {
3886 if (QObject *acc = QQuickAccessibleAttached::findAccessible(q, QAccessible::EditableText)) {
3887 QAccessibleTextUpdateEvent ev(acc, 0, oldText, m_text);
3888 QAccessible::updateAccessibility(&ev);
3896
3897
3898
3899
3900
3901void QQuickTextInputPrivate::addCommand(
const Command &cmd)
3903 if (m_separator && m_undoState && m_history[m_undoState - 1].type != Separator) {
3904 m_history.resize(m_undoState + 2);
3905 m_history[m_undoState++] = Command(Separator, m_cursor, u'\0', m_selstart, m_selend);
3907 m_history.resize(m_undoState + 1);
3909 m_separator =
false;
3910 m_history[m_undoState++] = cmd;
3914
3915
3916
3917
3918
3919
3920
3921
3922
3923void QQuickTextInputPrivate::internalInsert(
const QString &s)
3925 Q_Q(QQuickTextInput);
3926 if (m_echoMode == QQuickTextInput::Password) {
3927 if (m_passwordMaskDelay > 0)
3928 m_passwordEchoTimer.start(m_passwordMaskDelay, q);
3930 Q_ASSERT(!hasSelectedText());
3932 QString ms = maskString(m_cursor, s);
3933 for (
int i = 0; i < ms.size(); ++i) {
3934 addCommand (Command(DeleteSelection, m_cursor + i, m_text.at(m_cursor + i), -1, -1));
3935 addCommand(Command(Insert, m_cursor + i, ms.at(i), -1, -1));
3937 m_text.replace(m_cursor, ms.size(), ms);
3938 m_cursor += ms.size();
3939 m_cursor = nextMaskBlank(m_cursor);
3942 int remaining = m_maxLength - m_text.size();
3943 if (remaining != 0) {
3944 const QStringView remainingStr = QStringView{s}.left(remaining);
3945 m_text.insert(m_cursor, remainingStr);
3946 for (
auto e : remainingStr)
3947 addCommand(Command(Insert, m_cursor++, e, -1, -1));
3954
3955
3956
3957
3958
3959
3960
3961
3962
3963
3964void QQuickTextInputPrivate::internalDelete(
bool wasBackspace)
3966 if (m_cursor < m_text.size()) {
3967 cancelPasswordEchoTimer();
3968 Q_ASSERT(!hasSelectedText());
3969 addCommand(Command((CommandType)((m_maskData ? 2 : 0) + (wasBackspace ? Remove : Delete)),
3970 m_cursor, m_text.at(m_cursor), -1, -1));
3972 m_text.replace(m_cursor, 1, clearString(m_cursor, 1));
3973 addCommand(Command(Insert, m_cursor, m_text.at(m_cursor), -1, -1));
3975 m_text.remove(m_cursor, 1);
3982
3983
3984
3985
3986
3987
3988
3989
3990void QQuickTextInputPrivate::removeSelectedText()
3992 if (m_selstart < m_selend && m_selend <= m_text.size()) {
3993 cancelPasswordEchoTimer();
3995 if (m_selstart <= m_cursor && m_cursor < m_selend) {
3998 for (i = m_cursor; i >= m_selstart; --i)
3999 addCommand (Command(DeleteSelection, i, m_text.at(i), -1, 1));
4000 for (i = m_selend - 1; i > m_cursor; --i)
4001 addCommand (Command(DeleteSelection, i - m_cursor + m_selstart - 1, m_text.at(i), -1, -1));
4003 for (i = m_selend-1; i >= m_selstart; --i)
4004 addCommand (Command(RemoveSelection, i, m_text.at(i), -1, -1));
4007 m_text.replace(m_selstart, m_selend - m_selstart, clearString(m_selstart, m_selend - m_selstart));
4008 for (
int i = 0; i < m_selend - m_selstart; ++i)
4009 addCommand(Command(Insert, m_selstart + i, m_text.at(m_selstart + i), -1, -1));
4011 m_text.remove(m_selstart, m_selend - m_selstart);
4013 if (m_cursor > m_selstart)
4014 m_cursor -= qMin(m_cursor, m_selend) - m_selstart;
4021
4022
4023
4024
4025
4026
4028bool QQuickTextInputPrivate::separateSelection()
4030 if (hasSelectedText()) {
4032 addCommand(Command(SetSelection, m_cursor, u'\0', m_selstart, m_selend));
4040
4041
4042
4043
4044
4045void QQuickTextInputPrivate::parseInputMask(
const QString &maskFields)
4047 int delimiter = maskFields.indexOf(QLatin1Char(
';'));
4048 if (maskFields.isEmpty() || delimiter == 0) {
4050 m_maskData.reset(
nullptr);
4051 m_maxLength = 32767;
4052 internalSetText(QString());
4057 if (delimiter == -1) {
4058 m_blank = QLatin1Char(
' ');
4059 m_inputMask = maskFields;
4061 m_inputMask = maskFields.left(delimiter);
4062 m_blank = (delimiter + 1 < maskFields.size()) ? maskFields[delimiter + 1] : QLatin1Char(
' ');
4068 for (
int i=0; i<m_inputMask.size(); i++) {
4069 c = m_inputMask.at(i);
4070 if (i > 0 && m_inputMask.at(i-1) == QLatin1Char(
'\\')) {
4074 if (c != QLatin1Char(
'\\') && c != QLatin1Char(
'!') &&
4075 c != QLatin1Char(
'<') && c != QLatin1Char(
'>') &&
4076 c != QLatin1Char(
'{') && c != QLatin1Char(
'}') &&
4077 c != QLatin1Char(
'[') && c != QLatin1Char(
']'))
4081 m_maskData.reset(
new MaskInputData[m_maxLength]);
4083 MaskInputData::Casemode m = MaskInputData::NoCaseMode;
4086 bool escape =
false;
4088 for (
int i = 0; i < m_inputMask.size(); i++) {
4089 c = m_inputMask.at(i);
4092 m_maskData[index].maskChar = c;
4093 m_maskData[index].separator = s;
4094 m_maskData[index].caseMode = m;
4097 }
else if (c == QLatin1Char(
'<')) {
4098 m = MaskInputData::Lower;
4099 }
else if (c == QLatin1Char(
'>')) {
4100 m = MaskInputData::Upper;
4101 }
else if (c == QLatin1Char(
'!')) {
4102 m = MaskInputData::NoCaseMode;
4103 }
else if (c != QLatin1Char(
'{') && c != QLatin1Char(
'}') && c != QLatin1Char(
'[') && c != QLatin1Char(
']')) {
4104 switch (c.unicode()) {
4131 m_maskData[index].maskChar = c;
4132 m_maskData[index].separator = s;
4133 m_maskData[index].caseMode = m;
4138 internalSetText(m_text);
4143
4144
4145
4146
4147bool QQuickTextInputPrivate::isValidInput(QChar key, QChar mask)
const
4149 switch (mask.unicode()) {
4155 if (key.isLetter() || key == m_blank)
4159 if (key.isLetterOrNumber())
4163 if (key.isLetterOrNumber() || key == m_blank)
4167 if (key.isPrint() && key != m_blank)
4171 if (key.isPrint() || key == m_blank)
4179 if (key.isNumber() || key == m_blank)
4183 if (key.isNumber() && key.digitValue() > 0)
4187 if ((key.isNumber() && key.digitValue() > 0) || key == m_blank)
4191 if (key.isNumber() || key == QLatin1Char(
'+') || key == QLatin1Char(
'-') || key == m_blank)
4195 if (key == QLatin1Char(
'0') || key == QLatin1Char(
'1'))
4199 if (key == QLatin1Char(
'0') || key == QLatin1Char(
'1') || key == m_blank)
4203 if (key.isNumber() || (key >= QLatin1Char(
'a') && key <= QLatin1Char(
'f')) || (key >= QLatin1Char(
'A') && key <= QLatin1Char(
'F')))
4207 if (key.isNumber() || (key >= QLatin1Char(
'a') && key <= QLatin1Char(
'f')) || (key >= QLatin1Char(
'A') && key <= QLatin1Char(
'F')) || key == m_blank)
4217
4218
4219
4220
4221
4222
4223
4224QQuickTextInputPrivate::ValidatorState QQuickTextInputPrivate::hasAcceptableInput(
const QString &str)
const
4226#if QT_CONFIG(validator)
4227 QString textCopy = str;
4228 int cursorCopy = m_cursor;
4230 QValidator::State state = m_validator->validate(textCopy, cursorCopy);
4231 if (state != QValidator::Acceptable)
4232 return ValidatorState(state);
4237 return AcceptableInput;
4239 if (str.size() != m_maxLength)
4240 return InvalidInput;
4242 for (
int i=0; i < m_maxLength; ++i) {
4243 if (m_maskData[i].separator) {
4244 if (str.at(i) != m_maskData[i].maskChar)
4245 return InvalidInput;
4247 if (!isValidInput(str.at(i), m_maskData[i].maskChar))
4248 return InvalidInput;
4251 return AcceptableInput;
4255
4256
4257
4258
4259
4260
4261
4262QString QQuickTextInputPrivate::maskString(uint pos,
const QString &str,
bool clear)
const
4264 if (pos >= (uint)m_maxLength)
4265 return QString::fromLatin1(
"");
4268 fill = clear ? clearString(0, m_maxLength) : m_text;
4271 QString s = QString::fromLatin1(
"");
4273 while (i < m_maxLength) {
4274 if (strIndex < str.size()) {
4275 if (m_maskData[i].separator) {
4276 s += m_maskData[i].maskChar;
4277 if (str[strIndex] == m_maskData[i].maskChar)
4281 if (isValidInput(str[strIndex], m_maskData[i].maskChar)) {
4282 switch (m_maskData[i].caseMode) {
4283 case MaskInputData::Upper:
4284 s += str[strIndex].toUpper();
4286 case MaskInputData::Lower:
4287 s += str[strIndex].toLower();
4295 int n = findInMask(i,
true,
true, str[strIndex]);
4297 if (str.size() != 1 || i == 0 || (i > 0 && (!m_maskData[i-1].separator || m_maskData[i-1].maskChar != str[strIndex]))) {
4298 s += QStringView{fill}.mid(i, n-i+1);
4303 n = findInMask(i,
true,
false, str[strIndex]);
4305 s += QStringView{fill}.mid(i, n-i);
4306 switch (m_maskData[n].caseMode) {
4307 case MaskInputData::Upper:
4308 s += str[strIndex].toUpper();
4310 case MaskInputData::Lower:
4311 s += str[strIndex].toLower();
4332
4333
4334
4335
4336
4337QString QQuickTextInputPrivate::clearString(uint pos, uint len)
const
4339 if (pos >= (uint)m_maxLength)
4343 int end = qMin((uint)m_maxLength, pos + len);
4344 for (
int i = pos; i < end; ++i)
4345 if (m_maskData[i].separator)
4346 s += m_maskData[i].maskChar;
4354
4355
4356
4357
4358
4359QString QQuickTextInputPrivate::stripString(
const QString &str)
const
4365 int end = qMin(m_maxLength, str.size());
4366 for (
int i = 0; i < end; ++i) {
4367 if (m_maskData[i].separator)
4368 s += m_maskData[i].maskChar;
4369 else if (str[i] != m_blank)
4377
4378
4379
4380int QQuickTextInputPrivate::findInMask(
int pos,
bool forward,
bool findSeparator, QChar searchChar)
const
4382 if (pos >= m_maxLength || pos < 0)
4385 int end = forward ? m_maxLength : -1;
4386 int step = forward ? 1 : -1;
4390 if (findSeparator) {
4391 if (m_maskData[i].separator && m_maskData[i].maskChar == searchChar)
4394 if (!m_maskData[i].separator) {
4395 if (searchChar.isNull())
4397 else if (isValidInput(searchChar, m_maskData[i].maskChar))
4406void QQuickTextInputPrivate::internalUndo(
int until)
4408 if (!isUndoAvailable())
4410 cancelPasswordEchoTimer();
4412 while (m_undoState && m_undoState > until) {
4413 Command& cmd = m_history[--m_undoState];
4416 m_text.remove(cmd.pos, 1);
4420 m_selstart = cmd.selStart;
4421 m_selend = cmd.selEnd;
4425 case RemoveSelection:
4426 m_text.insert(cmd.pos, cmd.uc);
4427 m_cursor = cmd.pos + 1;
4430 case DeleteSelection:
4431 m_text.insert(cmd.pos, cmd.uc);
4437 if (until < 0 && m_undoState) {
4438 Command& next = m_history[m_undoState-1];
4439 if (next.type != cmd.type
4440 && next.type < RemoveSelection
4441 && (cmd.type < RemoveSelection || next.type == Separator)) {
4450void QQuickTextInputPrivate::internalRedo()
4452 if (!isRedoAvailable())
4455 while (m_undoState < m_history.size()) {
4456 Command& cmd = m_history[m_undoState++];
4459 m_text.insert(cmd.pos, cmd.uc);
4460 m_cursor = cmd.pos + 1;
4463 m_selstart = cmd.selStart;
4464 m_selend = cmd.selEnd;
4469 case RemoveSelection:
4470 case DeleteSelection:
4471 m_text.remove(cmd.pos, 1);
4472 m_selstart = cmd.selStart;
4473 m_selend = cmd.selEnd;
4477 m_selstart = cmd.selStart;
4478 m_selend = cmd.selEnd;
4482 if (m_undoState < m_history.size()) {
4483 Command& next = m_history[m_undoState];
4484 if (next.type != cmd.type
4485 && cmd.type < RemoveSelection
4486 && next.type != Separator
4487 && (next.type < RemoveSelection || cmd.type == Separator)) {
4495void QQuickTextInputPrivate::emitUndoRedoChanged()
4497 Q_Q(QQuickTextInput);
4498 const bool previousUndo = canUndo;
4499 const bool previousRedo = canRedo;
4501 canUndo = isUndoAvailable();
4502 canRedo = isRedoAvailable();
4504 if (previousUndo != canUndo)
4505 emit q->canUndoChanged();
4506 if (previousRedo != canRedo)
4507 emit q->canRedoChanged();
4511
4512
4513
4514
4515
4516bool QQuickTextInputPrivate::emitCursorPositionChanged()
4518 Q_Q(QQuickTextInput);
4519 if (m_cursor != m_lastCursorPos) {
4520 m_lastCursorPos = m_cursor;
4522 q->updateCursorRectangle();
4523 emit q->cursorPositionChanged();
4525 if (!hasSelectedText()) {
4526 if (lastSelectionStart != m_cursor) {
4527 lastSelectionStart = m_cursor;
4528 emit q->selectionStartChanged();
4530 if (lastSelectionEnd != m_cursor) {
4531 lastSelectionEnd = m_cursor;
4532 emit q->selectionEndChanged();
4536#if QT_CONFIG(accessibility)
4537 if (QAccessible::isActive()) {
4538 if (QObject *acc = QQuickAccessibleAttached::findAccessible(q, QAccessible::EditableText)) {
4539 QAccessibleTextCursorEvent ev(acc, m_cursor);
4540 QAccessible::updateAccessibility(&ev);
4551void QQuickTextInputPrivate::setBlinkingCursorEnabled(
bool enable)
4553 if (enable == m_blinkEnabled)
4556 m_blinkEnabled = enable;
4557 updateCursorBlinking();
4560 connect(qApp->styleHints(), &QStyleHints::cursorFlashTimeChanged,
this, &QQuickTextInputPrivate::updateCursorBlinking);
4562 disconnect(qApp->styleHints(), &QStyleHints::cursorFlashTimeChanged,
this, &QQuickTextInputPrivate::updateCursorBlinking);
4565void QQuickTextInputPrivate::updateCursorBlinking()
4567 Q_Q(QQuickTextInput);
4570 q->killTimer(m_blinkTimer);
4574 if (m_blinkEnabled && cursorVisible && !cursorItem && !m_readOnly) {
4575 int flashTime = QGuiApplication::styleHints()->cursorFlashTime();
4577 m_blinkTimer = q->startTimer(flashTime / 2);
4581 updateType = UpdatePaintNode;
4586void QQuickTextInput::timerEvent(QTimerEvent *event)
4588 Q_D(QQuickTextInput);
4589 if (event->timerId() == d->m_blinkTimer) {
4590 d->m_blinkStatus = !d->m_blinkStatus;
4591 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
4594 }
else if (event->timerId() == d->m_passwordEchoTimer.timerId()) {
4595 d->m_passwordEchoTimer.stop();
4596 d->updateDisplayText();
4597 updateCursorRectangle();
4601void QQuickTextInputPrivate::processKeyEvent(QKeyEvent* event)
4603 Q_Q(QQuickTextInput);
4605 if (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return) {
4606 if (hasAcceptableInput(m_text) == AcceptableInput || fixup()) {
4608 QInputMethod *inputMethod = QGuiApplication::inputMethod();
4609 inputMethod->commit();
4614 emit q->editingFinished();
4624 updateCursorBlinking();
4626 if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit
4627 && !m_passwordEchoEditing
4629 && !event->text().isEmpty()
4630 && !(event->modifiers() & Qt::ControlModifier)) {
4636 updatePasswordEchoEditing(
true);
4640 bool unknown =
false;
4641#if QT_CONFIG(shortcut)
4642 bool visual = cursorMoveStyle() == Qt::VisualMoveStyle;
4647#if QT_CONFIG(shortcut)
4648 else if (event == QKeySequence::Undo) {
4651 else if (event == QKeySequence::Redo) {
4654 else if (event == QKeySequence::SelectAll) {
4657#if QT_CONFIG(clipboard)
4658 else if (event == QKeySequence::Copy) {
4661 else if (event == QKeySequence::Paste) {
4663 QClipboard::Mode mode = QClipboard::Clipboard;
4667 else if (event == QKeySequence::Cut) {
4670 else if (event == QKeySequence::DeleteEndOfLine) {
4675 else if (event == QKeySequence::MoveToStartOfLine || event == QKeySequence::MoveToStartOfBlock) {
4678 else if (event == QKeySequence::MoveToEndOfLine || event == QKeySequence::MoveToEndOfBlock) {
4681 else if (event == QKeySequence::SelectStartOfLine || event == QKeySequence::SelectStartOfBlock) {
4684 else if (event == QKeySequence::SelectEndOfLine || event == QKeySequence::SelectEndOfBlock) {
4687 else if (event == QKeySequence::MoveToNextChar) {
4688 if (hasSelectedText()) {
4689 moveCursor(selectionEnd(),
false);
4691 cursorForward(0, visual ? 1 : (layoutDirection() == Qt::LeftToRight ? 1 : -1));
4694 else if (event == QKeySequence::SelectNextChar) {
4695 cursorForward(1, visual ? 1 : (layoutDirection() == Qt::LeftToRight ? 1 : -1));
4697 else if (event == QKeySequence::MoveToPreviousChar) {
4698 if (hasSelectedText()) {
4699 moveCursor(selectionStart(),
false);
4701 cursorForward(0, visual ? -1 : (layoutDirection() == Qt::LeftToRight ? -1 : 1));
4704 else if (event == QKeySequence::SelectPreviousChar) {
4705 cursorForward(1, visual ? -1 : (layoutDirection() == Qt::LeftToRight ? -1 : 1));
4707 else if (event == QKeySequence::MoveToNextWord) {
4708 if (m_echoMode == QQuickTextInput::Normal)
4709 layoutDirection() == Qt::LeftToRight ? cursorWordForward(0) : cursorWordBackward(0);
4711 layoutDirection() == Qt::LeftToRight ? end(0) : home(0);
4713 else if (event == QKeySequence::MoveToPreviousWord) {
4714 if (m_echoMode == QQuickTextInput::Normal)
4715 layoutDirection() == Qt::LeftToRight ? cursorWordBackward(0) : cursorWordForward(0);
4716 else if (!m_readOnly) {
4717 layoutDirection() == Qt::LeftToRight ? home(0) : end(0);
4720 else if (event == QKeySequence::SelectNextWord) {
4721 if (m_echoMode == QQuickTextInput::Normal)
4722 layoutDirection() == Qt::LeftToRight ? cursorWordForward(1) : cursorWordBackward(1);
4724 layoutDirection() == Qt::LeftToRight ? end(1) : home(1);
4726 else if (event == QKeySequence::SelectPreviousWord) {
4727 if (m_echoMode == QQuickTextInput::Normal)
4728 layoutDirection() == Qt::LeftToRight ? cursorWordBackward(1) : cursorWordForward(1);
4730 layoutDirection() == Qt::LeftToRight ? home(1) : end(1);
4732 else if (event == QKeySequence::Delete) {
4736 else if (event == QKeySequence::DeleteEndOfWord) {
4740 else if (event == QKeySequence::DeleteStartOfWord) {
4742 deleteStartOfWord();
4743 }
else if (event == QKeySequence::DeleteCompleteLine) {
4746#if QT_CONFIG(clipboard)
4754 bool handled =
false;
4755 if (event->modifiers() & Qt::ControlModifier) {
4756 switch (event->key()) {
4757 case Qt::Key_Backspace:
4759 deleteStartOfWord();
4766 switch (event->key()) {
4767 case Qt::Key_Backspace:
4779 if (event->key() == Qt::Key_Direction_L || event->key() == Qt::Key_Direction_R) {
4780 setLayoutDirection((event->key() == Qt::Key_Direction_L) ? Qt::LeftToRight : Qt::RightToLeft);
4784 if (unknown && !m_readOnly) {
4785 if (m_inputControl->isAcceptableInput(event)) {
4789 && !hasSelectedText()
4790 && !(m_cursor == q_func()->text().size())) {
4794 insert(event->text());
4807
4808
4809
4810
4812void QQuickTextInputPrivate::deleteStartOfWord()
4814 int priorState = m_undoState;
4816 if (!separateSelection()) {
4817 Command cmd(SetSelection, m_cursor, u'\0', m_selstart, m_selend);
4819 cursorWordBackward(
true);
4823 removeSelectedText();
4824 finishChange(priorState);
4828
4829
4830
4831
4833void QQuickTextInputPrivate::deleteEndOfWord()
4835 int priorState = m_undoState;
4836 Command cmd(SetSelection, m_cursor, u'\0', m_selstart, m_selend);
4838 cursorWordForward(
true);
4842 removeSelectedText();
4843 finishChange(priorState);
4847
4848
4849
4850
4852void QQuickTextInputPrivate::deleteEndOfLine()
4854 int priorState = m_undoState;
4855 Command cmd(SetSelection, m_cursor, u'\0', m_selstart, m_selend);
4857 setSelection(m_cursor, end());
4859 removeSelectedText();
4860 finishChange(priorState);
4864
4865
4866
4867
4868
4869
4870
4871
4872void QQuickTextInput::ensureVisible(
int position)
4874 Q_D(QQuickTextInput);
4875 d->ensureVisible(position);
4876 updateCursorRectangle(
false);
4880
4881
4882
4883
4884
4885
4886
4887
4888
4889
4890void QQuickTextInput::clear()
4892 Q_D(QQuickTextInput);
4898
4899
4900
4901
4902
4903
4904
4905
4906
4907
4908
4909
4910
4911
4912
4913
4914
4915
4916
4917
4918
4919
4920qreal QQuickTextInput::padding()
const
4922 Q_D(
const QQuickTextInput);
4923 return d->padding();
4926void QQuickTextInput::setPadding(qreal padding)
4928 Q_D(QQuickTextInput);
4929 if (qFuzzyCompare(d->padding(), padding))
4932 d->extra.value().padding = padding;
4934 updateCursorRectangle();
4935 emit paddingChanged();
4936 if (!d->extra.isAllocated() || !d->extra->explicitTopPadding)
4937 emit topPaddingChanged();
4938 if (!d->extra.isAllocated() || !d->extra->explicitLeftPadding)
4939 emit leftPaddingChanged();
4940 if (!d->extra.isAllocated() || !d->extra->explicitRightPadding)
4941 emit rightPaddingChanged();
4942 if (!d->extra.isAllocated() || !d->extra->explicitBottomPadding)
4943 emit bottomPaddingChanged();
4946void QQuickTextInput::resetPadding()
4951qreal QQuickTextInput::topPadding()
const
4953 Q_D(
const QQuickTextInput);
4954 if (d->extra.isAllocated() && d->extra->explicitTopPadding)
4955 return d->extra->topPadding;
4956 return d->padding();
4959void QQuickTextInput::setTopPadding(qreal padding)
4961 Q_D(QQuickTextInput);
4962 d->setTopPadding(padding);
4965void QQuickTextInput::resetTopPadding()
4967 Q_D(QQuickTextInput);
4968 d->setTopPadding(0,
true);
4971qreal QQuickTextInput::leftPadding()
const
4973 Q_D(
const QQuickTextInput);
4974 if (d->extra.isAllocated() && d->extra->explicitLeftPadding)
4975 return d->extra->leftPadding;
4976 return d->padding();
4979void QQuickTextInput::setLeftPadding(qreal padding)
4981 Q_D(QQuickTextInput);
4982 d->setLeftPadding(padding);
4985void QQuickTextInput::resetLeftPadding()
4987 Q_D(QQuickTextInput);
4988 d->setLeftPadding(0,
true);
4991qreal QQuickTextInput::rightPadding()
const
4993 Q_D(
const QQuickTextInput);
4994 if (d->extra.isAllocated() && d->extra->explicitRightPadding)
4995 return d->extra->rightPadding;
4996 return d->padding();
4999void QQuickTextInput::setRightPadding(qreal padding)
5001 Q_D(QQuickTextInput);
5002 d->setRightPadding(padding);
5005void QQuickTextInput::resetRightPadding()
5007 Q_D(QQuickTextInput);
5008 d->setRightPadding(0,
true);
5011qreal QQuickTextInput::bottomPadding()
const
5013 Q_D(
const QQuickTextInput);
5014 if (d->extra.isAllocated() && d->extra->explicitBottomPadding)
5015 return d->extra->bottomPadding;
5016 return d->padding();
5019void QQuickTextInput::setBottomPadding(qreal padding)
5021 Q_D(QQuickTextInput);
5022 d->setBottomPadding(padding);
5025void QQuickTextInput::resetBottomPadding()
5027 Q_D(QQuickTextInput);
5028 d->setBottomPadding(0,
true);
5031#if QT_VERSION < QT_VERSION_CHECK(7
, 0
, 0
)
5032void QQuickTextInput::setOldSelectionDefault()
5034 Q_D(QQuickTextInput);
5035 d->selectByMouse =
false;
5036 d->selectByTouchDrag =
true;
5037 qCDebug(lcQuickTextInput,
"pre-6.4 behavior chosen: selectByMouse defaults false; if enabled, touchscreen acts like a mouse");
5041QQuickPre64TextInput::QQuickPre64TextInput(QQuickItem *parent)
5042 : QQuickTextInput(parent)
5044 setOldSelectionDefault();
5050#include "moc_qquicktextinput_p.cpp"
Combined button and popup list for selecting options.