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);
1965 node->clearCursor();
1967 node->setRenderType(QSGTextNode::RenderType(d->renderType));
1969 node->setMatrix(QMatrix4x4());
1970 node->setTextStyle(QSGInternalTextNode::Normal);
1971 node->setColor(d->color);
1972 node->setSelectionTextColor(d->selectedTextColor);
1973 node->setSelectionColor(d->selectionColor);
1974 node->setFiltering(smooth() ? QSGTexture::Linear : QSGTexture::Nearest);
1976 if (flags().testFlag(ItemObservesViewport))
1977 node->setViewport(clipRect());
1979 node->setViewport(QRectF{});
1981 QPointF offset(leftPadding(), topPadding());
1982 offset -= QPointF(d->hscroll, d->vscroll);
1984 if (!d->m_textLayout.text().isEmpty()
1986 || !d->m_textLayout.preeditAreaText().isEmpty()
1989 node->addTextLayout(offset, &d->m_textLayout,
1990 d->selectionStart(),
1991 d->selectionEnd() - 1);
1996 node->setCursor(cursorRectangle(), d->color);
1998 d->textLayoutDirty =
false;
2001 d->containsUnscalableGlyphs = node->containsUnscalableGlyphs();
2003 invalidateFontCaches();
2009QVariant QQuickTextInput::inputMethodQuery(Qt::InputMethodQuery property)
const
2013 if (property == Qt::ImEnterKeyType) {
2014 Q_D(
const QQuickItem);
2016 if (!d->extra.isAllocated()
2017 || d->extra->enterKeyAttached ==
nullptr
2018 || d->extra->enterKeyAttached->type() == Qt::EnterKeyDefault) {
2020 QQuickItem *next =
const_cast<QQuickTextInput*>(
this)->nextItemInFocusChain();
2021 QQuickItem *originalNext = next;
2022 while (next && next !=
this && !next->activeFocusOnTab()) {
2023 next = next->nextItemInFocusChain();
2024 if (next == originalNext) {
2030 const auto nextYPos = next->mapToGlobal(QPoint(0, 0)).y();
2031 const auto currentYPos =
this->mapToGlobal(QPoint(0, 0)).y();
2032 if (currentYPos < nextYPos)
2035 return Qt::EnterKeyNext;
2040 return inputMethodQuery(property, QVariant());
2043QVariant QQuickTextInput::inputMethodQuery(Qt::InputMethodQuery property,
const QVariant &argument)
const
2045 Q_D(
const QQuickTextInput);
2048 return QVariant((
bool)(flags() & ItemAcceptsInputMethod));
2050 return QVariant((
int) d->effectiveInputMethodHints());
2051 case Qt::ImCursorRectangle:
2052 return cursorRectangle();
2053 case Qt::ImAnchorRectangle:
2054 return d->anchorRectangle();
2057 case Qt::ImCursorPosition: {
2058 const QPointF pt = argument.toPointF();
2060 return QVariant(d->positionAt(pt));
2061 return QVariant(d->m_cursor);
2063 case Qt::ImSurroundingText:
2064 if (d->m_echoMode == PasswordEchoOnEdit && !d->m_passwordEchoEditing) {
2065 return QVariant(displayText());
2067 return QVariant(d->realText());
2069 case Qt::ImCurrentSelection:
2070 return QVariant(selectedText());
2071 case Qt::ImMaximumTextLength:
2072 return QVariant(maxLength());
2073 case Qt::ImAnchorPosition:
2074 if (d->selectionStart() == d->selectionEnd())
2075 return QVariant(d->m_cursor);
2076 else if (d->selectionStart() == d->m_cursor)
2077 return QVariant(d->selectionEnd());
2079 return QVariant(d->selectionStart());
2080 case Qt::ImAbsolutePosition:
2081 return QVariant(d->m_cursor);
2082 case Qt::ImTextAfterCursor:
2083 if (argument.isValid())
2084 return QVariant(d->m_text.mid(d->m_cursor, argument.toInt()));
2085 return QVariant(d->m_text.mid(d->m_cursor));
2086 case Qt::ImTextBeforeCursor:
2087 if (argument.isValid())
2088 return QVariant(QStringView{d->m_text}.left(d->m_cursor).right(argument.toInt()).toString());
2089 return QVariant(d->m_text.left(d->m_cursor));
2090 case Qt::ImReadOnly:
2091 return QVariant(d->m_readOnly);
2093 return QQuickItem::inputMethodQuery(property);
2099
2100
2101
2102
2103void QQuickTextInput::deselect()
2105 Q_D(QQuickTextInput);
2110
2111
2112
2113
2114void QQuickTextInput::selectAll()
2116 Q_D(QQuickTextInput);
2117 d->setSelection(0, text().size());
2121
2122
2123
2124
2125
2126bool QQuickTextInput::isRightToLeft(
int start,
int end)
2129 qmlWarning(
this) <<
"isRightToLeft(start, end) called with the end property being smaller than the start.";
2132 return QStringView{text()}.mid(start, end - start).isRightToLeft();
2136#if QT_CONFIG(clipboard)
2138
2139
2140
2141
2142
2143
2144
2145
2146void QQuickTextInput::cut()
2148 Q_D(QQuickTextInput);
2149 if (!d->m_readOnly && d->m_echoMode == QQuickTextInput::Normal) {
2156
2157
2158
2159
2160
2161
2162
2163
2164void QQuickTextInput::copy()
2166 Q_D(QQuickTextInput);
2171
2172
2173
2174
2175void QQuickTextInput::paste()
2177 Q_D(QQuickTextInput);
2184
2185
2186
2187
2188
2189
2191void QQuickTextInput::undo()
2193 Q_D(QQuickTextInput);
2194 if (!d->m_readOnly) {
2197 d->finishChange(-1,
true);
2202
2203
2204
2205
2207void QQuickTextInput::redo()
2209 Q_D(QQuickTextInput);
2210 if (!d->m_readOnly) {
2218
2219
2220
2221
2223void QQuickTextInput::insert(
int position,
const QString &text)
2225 Q_D(QQuickTextInput);
2226 if (d->m_echoMode == QQuickTextInput::Password) {
2227 if (d->m_passwordMaskDelay > 0)
2228 d->m_passwordEchoTimer.start(d->m_passwordMaskDelay,
this);
2230 if (position < 0 || position > d->m_text.size())
2233 const int priorState = d->m_undoState;
2235 QString insertText = text;
2237 if (d->hasSelectedText()) {
2238 d->addCommand(QQuickTextInputPrivate::Command(
2239 QQuickTextInputPrivate::SetSelection, d->m_cursor, u'\0', d->m_selstart, d->m_selend));
2241 if (d->m_maskData) {
2242 insertText = d->maskString(position, insertText);
2243 for (
int i = 0; i < insertText.size(); ++i) {
2244 d->addCommand(QQuickTextInputPrivate::Command(
2245 QQuickTextInputPrivate::DeleteSelection, position + i, d->m_text.at(position + i), -1, -1));
2246 d->addCommand(QQuickTextInputPrivate::Command(
2247 QQuickTextInputPrivate::Insert, position + i, insertText.at(i), -1, -1));
2249 d->m_text.replace(position, insertText.size(), insertText);
2250 if (!insertText.isEmpty())
2251 d->m_textDirty =
true;
2252 if (position < d->m_selend && position + insertText.size() > d->m_selstart)
2253 d->m_selDirty =
true;
2255 int remaining = d->m_maxLength - d->m_text.size();
2256 if (remaining != 0) {
2257 insertText = insertText.left(remaining);
2258 d->m_text.insert(position, insertText);
2259 for (
int i = 0; i < insertText.size(); ++i)
2260 d->addCommand(QQuickTextInputPrivate::Command(
2261 QQuickTextInputPrivate::Insert, position + i, insertText.at(i), -1, -1));
2262 if (d->m_cursor >= position)
2263 d->m_cursor += insertText.size();
2264 if (d->m_selstart >= position)
2265 d->m_selstart += insertText.size();
2266 if (d->m_selend >= position)
2267 d->m_selend += insertText.size();
2268 d->m_textDirty =
true;
2269 if (position >= d->m_selstart && position <= d->m_selend)
2270 d->m_selDirty =
true;
2274 d->addCommand(QQuickTextInputPrivate::Command(
2275 QQuickTextInputPrivate::SetSelection, d->m_cursor, u'\0', d->m_selstart, d->m_selend));
2276 d->finishChange(priorState);
2278 if (d->lastSelectionStart != d->lastSelectionEnd) {
2279 if (d->m_selstart != d->lastSelectionStart) {
2280 d->lastSelectionStart = d->m_selstart;
2281 emit selectionStartChanged();
2283 if (d->m_selend != d->lastSelectionEnd) {
2284 d->lastSelectionEnd = d->m_selend;
2285 emit selectionEndChanged();
2291
2292
2293
2294
2296void QQuickTextInput::remove(
int start,
int end)
2298 Q_D(QQuickTextInput);
2300 start = qBound(0, start, d->m_text.size());
2301 end = qBound(0, end, d->m_text.size());
2305 else if (start == end)
2308 if (start < d->m_selend && end > d->m_selstart)
2309 d->m_selDirty =
true;
2311 const int priorState = d->m_undoState;
2313 d->addCommand(QQuickTextInputPrivate::Command(
2314 QQuickTextInputPrivate::SetSelection, d->m_cursor, u'\0', d->m_selstart, d->m_selend));
2316 if (start <= d->m_cursor && d->m_cursor < end) {
2319 for (
int i = d->m_cursor; i >= start; --i) {
2320 d->addCommand(QQuickTextInputPrivate::Command(
2321 QQuickTextInputPrivate::DeleteSelection, i, d->m_text.at(i), -1, 1));
2323 for (
int i = end - 1; i > d->m_cursor; --i) {
2324 d->addCommand(QQuickTextInputPrivate::Command(
2325 QQuickTextInputPrivate::DeleteSelection, i - d->m_cursor + start - 1, d->m_text.at(i), -1, -1));
2328 for (
int i = end - 1; i >= start; --i) {
2329 d->addCommand(QQuickTextInputPrivate::Command(
2330 QQuickTextInputPrivate::RemoveSelection, i, d->m_text.at(i), -1, -1));
2333 if (d->m_maskData) {
2334 d->m_text.replace(start, end - start, d->clearString(start, end - start));
2335 for (
int i = 0; i < end - start; ++i) {
2336 d->addCommand(QQuickTextInputPrivate::Command(
2337 QQuickTextInputPrivate::Insert, start + i, d->m_text.at(start + i), -1, -1));
2340 d->m_text.remove(start, end - start);
2342 if (d->m_cursor > start)
2343 d->m_cursor -= qMin(d->m_cursor, end) - start;
2344 if (d->m_selstart > start)
2345 d->m_selstart -= qMin(d->m_selstart, end) - start;
2346 if (d->m_selend >= end)
2347 d->m_selend -= end - start;
2349 d->addCommand(QQuickTextInputPrivate::Command(
2350 QQuickTextInputPrivate::SetSelection, d->m_cursor, u'\0', d->m_selstart, d->m_selend));
2352 d->m_textDirty =
true;
2353 d->finishChange(priorState);
2355 if (d->lastSelectionStart != d->lastSelectionEnd) {
2356 if (d->m_selstart != d->lastSelectionStart) {
2357 d->lastSelectionStart = d->m_selstart;
2358 emit selectionStartChanged();
2360 if (d->m_selend != d->lastSelectionEnd) {
2361 d->lastSelectionEnd = d->m_selend;
2362 emit selectionEndChanged();
2369
2370
2371
2372
2373void QQuickTextInput::selectWord()
2375 Q_D(QQuickTextInput);
2376 d->selectWordAtPos(d->m_cursor);
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390QString QQuickTextInput::passwordCharacter()
const
2392 Q_D(
const QQuickTextInput);
2393 return QString(d->m_passwordCharacter);
2396void QQuickTextInput::setPasswordCharacter(
const QString &str)
2398 Q_D(QQuickTextInput);
2401 d->m_passwordCharacter = str.constData()[0];
2402 if (d->m_echoMode == Password || d->m_echoMode == PasswordEchoOnEdit)
2403 d->updateDisplayText();
2404 emit passwordCharacterChanged();
2408
2409
2410
2411
2412
2413
2414
2415int QQuickTextInput::passwordMaskDelay()
const
2417 Q_D(
const QQuickTextInput);
2418 return d->m_passwordMaskDelay;
2421void QQuickTextInput::setPasswordMaskDelay(
int delay)
2423 Q_D(QQuickTextInput);
2424 if (d->m_passwordMaskDelay != delay) {
2425 d->m_passwordMaskDelay = delay;
2426 emit passwordMaskDelayChanged(delay);
2430void QQuickTextInput::resetPasswordMaskDelay()
2432 setPasswordMaskDelay(qGuiApp->styleHints()->passwordMaskDelay());
2436
2437
2438
2439
2440
2441
2442
2443
2444
2445
2446
2447
2448
2449
2450
2451QString QQuickTextInput::displayText()
const
2453 Q_D(
const QQuickTextInput);
2454 return d->m_textLayout.text().insert(d->m_textLayout.preeditAreaPosition(), d->m_textLayout.preeditAreaText());
2458
2459
2460
2461
2462
2463
2464
2465
2466
2467
2468
2469QString QQuickTextInput::preeditText()
const
2471 Q_D(
const QQuickTextInput);
2472 return d->m_textLayout.preeditAreaText();
2476
2477
2478
2479
2480
2481
2482
2483
2484
2485
2486
2487
2488
2489
2490
2491
2492
2493bool QQuickTextInput::selectByMouse()
const
2495 Q_D(
const QQuickTextInput);
2496 return d->selectByMouse;
2499void QQuickTextInput::setSelectByMouse(
bool on)
2501 Q_D(QQuickTextInput);
2502 if (d->selectByMouse != on) {
2503 d->selectByMouse = on;
2504 emit selectByMouseChanged(on);
2509
2510
2511
2512
2513
2514
2515
2516
2517
2519QQuickTextInput::SelectionMode QQuickTextInput::mouseSelectionMode()
const
2521 Q_D(
const QQuickTextInput);
2522 return d->mouseSelectionMode;
2525void QQuickTextInput::setMouseSelectionMode(SelectionMode mode)
2527 Q_D(QQuickTextInput);
2528 if (d->mouseSelectionMode != mode) {
2529 d->mouseSelectionMode = mode;
2530 emit mouseSelectionModeChanged(mode);
2535
2536
2537
2538
2539
2541bool QQuickTextInput::persistentSelection()
const
2543 Q_D(
const QQuickTextInput);
2544 return d->persistentSelection;
2547void QQuickTextInput::setPersistentSelection(
bool on)
2549 Q_D(QQuickTextInput);
2550 if (d->persistentSelection == on)
2552 d->persistentSelection = on;
2553 emit persistentSelectionChanged();
2557
2558
2559
2560
2561
2562
2563bool QQuickTextInput::canPaste()
const
2565#if QT_CONFIG(clipboard)
2566 Q_D(
const QQuickTextInput);
2567 if (!d->canPasteValid) {
2568 bool canPaste =
false;
2569 if (!d->m_readOnly) {
2570 if (
const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData())
2571 canPaste = mimeData->hasText() && !mimeData->text().isEmpty();
2573 const_cast<QQuickTextInputPrivate *>(d)->canPaste = canPaste;
2574 const_cast<QQuickTextInputPrivate *>(d)->canPasteValid =
true;
2583
2584
2585
2586
2587
2588
2590bool QQuickTextInput::canUndo()
const
2592 Q_D(
const QQuickTextInput);
2597
2598
2599
2600
2601
2602
2604bool QQuickTextInput::canRedo()
const
2606 Q_D(
const QQuickTextInput);
2611
2612
2613
2614
2615
2616
2618qreal QQuickTextInput::contentWidth()
const
2620 Q_D(
const QQuickTextInput);
2621 return d->contentSize.width();
2625
2626
2627
2628
2629
2630
2632qreal QQuickTextInput::contentHeight()
const
2634 Q_D(
const QQuickTextInput);
2635 return d->contentSize.height();
2638void QQuickTextInput::moveCursorSelection(
int position)
2640 Q_D(QQuickTextInput);
2641 d->moveCursor(position,
true);
2645
2646
2647
2648
2649
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
2680void QQuickTextInput::moveCursorSelection(
int pos, SelectionMode mode)
2682 Q_D(QQuickTextInput);
2684 if (mode == SelectCharacters) {
2685 d->moveCursor(pos,
true);
2686 }
else if (pos != d->m_cursor) {
2687 const int cursor = d->m_cursor;
2689 if (!d->hasSelectedText())
2690 anchor = d->m_cursor;
2691 else if (d->selectionStart() == d->m_cursor)
2692 anchor = d->selectionEnd();
2694 anchor = d->selectionStart();
2696 if (anchor < pos || (anchor == pos && cursor < pos)) {
2697 const QString text =
this->text();
2698 QTextBoundaryFinder finder(QTextBoundaryFinder::Word, text);
2699 finder.setPosition(anchor);
2701 const QTextBoundaryFinder::BoundaryReasons reasons = finder.boundaryReasons();
2702 if (anchor < text.size() && (reasons == QTextBoundaryFinder::NotAtBoundary
2703 || (reasons & QTextBoundaryFinder::EndOfItem))) {
2704 finder.toPreviousBoundary();
2706 anchor = finder.position() != -1 ? finder.position() : 0;
2708 finder.setPosition(pos);
2709 if (pos > 0 && !finder.boundaryReasons())
2710 finder.toNextBoundary();
2711 const int cursor = finder.position() != -1 ? finder.position() : text.size();
2713 d->setSelection(anchor, cursor - anchor);
2714 }
else if (anchor > pos || (anchor == pos && cursor > pos)) {
2715 const QString text =
this->text();
2716 QTextBoundaryFinder finder(QTextBoundaryFinder::Word, text);
2717 finder.setPosition(anchor);
2719 const QTextBoundaryFinder::BoundaryReasons reasons = finder.boundaryReasons();
2720 if (anchor > 0 && (reasons == QTextBoundaryFinder::NotAtBoundary
2721 || (reasons & QTextBoundaryFinder::StartOfItem))) {
2722 finder.toNextBoundary();
2724 anchor = finder.position() != -1 ? finder.position() : text.size();
2726 finder.setPosition(pos);
2727 if (pos < text.size() && !finder.boundaryReasons())
2728 finder.toPreviousBoundary();
2729 const int cursor = finder.position() != -1 ? finder.position() : 0;
2731 d->setSelection(anchor, cursor - anchor);
2736void QQuickTextInput::focusInEvent(QFocusEvent *event)
2738 Q_D(QQuickTextInput);
2739 d->handleFocusEvent(event);
2740 QQuickImplicitSizeItem::focusInEvent(event);
2743void QQuickTextInputPrivate::handleFocusEvent(QFocusEvent *event)
2745 Q_Q(QQuickTextInput);
2746 bool focus = event->gotFocus();
2748 q->setCursorVisible(focus);
2749 setBlinkingCursorEnabled(focus);
2752 q->q_updateAlignment();
2754 if (focusOnPress && !m_readOnly)
2755 qGuiApp->inputMethod()->show();
2756 q->connect(QGuiApplication::inputMethod(), SIGNAL(inputDirectionChanged(Qt::LayoutDirection)),
2757 q, SLOT(q_updateAlignment()));
2760 if ((m_passwordEchoEditing || m_passwordEchoTimer.isActive())) {
2761 updatePasswordEchoEditing(
false);
2764 if (event->reason() != Qt::ActiveWindowFocusReason
2765 && event->reason() != Qt::PopupFocusReason
2766 && hasSelectedText()
2767 && !persistentSelection)
2770 if (hasAcceptableInput(m_text) == AcceptableInput || fixup())
2771 emit q->editingFinished();
2774 q->disconnect(QGuiApplication::inputMethod(), SIGNAL(inputDirectionChanged(Qt::LayoutDirection)),
2775 q, SLOT(q_updateAlignment()));
2780void QQuickTextInput::focusOutEvent(QFocusEvent *event)
2782 Q_D(QQuickTextInput);
2783 d->handleFocusEvent(event);
2784 QQuickImplicitSizeItem::focusOutEvent(event);
2787void QQuickTextInputPrivate::readOnlyChanged(
bool isReadOnly)
2789 Q_UNUSED(isReadOnly);
2790#if QT_CONFIG(accessibility)
2791 if (QQuickAccessibleAttached *accessibleAttached =
2792 QQuickAccessibleAttached::attachedProperties(q_func()))
2793 accessibleAttached->set_readOnly(isReadOnly);
2797void QQuickTextInputPrivate::echoModeChanged(QQuickTextInput::EchoMode echoMode)
2799#if QT_CONFIG(accessibility)
2800 if (!QAccessible::isActive())
2803 if (QQuickAccessibleAttached *accessibleAttached =
2804 QQuickAccessibleAttached::attachedProperties(q_func()))
2805 accessibleAttached->set_passwordEdit((echoMode == QQuickTextInput::Password
2806 || echoMode == QQuickTextInput::PasswordEchoOnEdit)
2814#if QT_CONFIG(accessibility)
2815void QQuickTextInputPrivate::accessibilityActiveChanged(
bool active)
2820 Q_Q(QQuickTextInput);
2821 QQuickAccessibleAttached *accessibleAttached = qobject_cast<QQuickAccessibleAttached *>(
2822 qmlAttachedPropertiesObject<QQuickAccessibleAttached>(q,
true));
2823 Q_ASSERT(accessibleAttached);
2824 accessibleAttached->setRole(effectiveAccessibleRole());
2825 accessibleAttached->set_readOnly(m_readOnly);
2826 accessibleAttached->set_passwordEdit((m_echoMode == QQuickTextInput::Password
2827 || m_echoMode == QQuickTextInput::PasswordEchoOnEdit)
2832QAccessible::Role QQuickTextInputPrivate::accessibleRole()
const
2834 return QAccessible::EditableText;
2839
2840
2841
2842
2843
2844
2845
2846
2847
2848
2849
2850bool QQuickTextInput::isInputMethodComposing()
const
2855 Q_D(
const QQuickTextInput);
2856 return d->hasImState;
2860QQuickTextInputPrivate::ExtraData::ExtraData()
2866 , explicitTopPadding(
false)
2867 , explicitLeftPadding(
false)
2868 , explicitRightPadding(
false)
2869 , explicitBottomPadding(
false)
2870 , implicitResize(
true)
2874void QQuickTextInputPrivate::init()
2876 Q_Q(QQuickTextInput);
2877#if QT_CONFIG(clipboard)
2878 if (QGuiApplication::clipboard()->supportsSelection())
2879 q->setAcceptedMouseButtons(Qt::LeftButton | Qt::MiddleButton);
2882 q->setAcceptedMouseButtons(Qt::LeftButton);
2885 q->setFlag(QQuickItem::ItemAcceptsInputMethod);
2887 q->setFlag(QQuickItem::ItemHasContents);
2888#if QT_CONFIG(clipboard)
2889 qmlobject_connect(QGuiApplication::clipboard(), QClipboard, SIGNAL(dataChanged()),
2890 q, QQuickTextInput, SLOT(q_canPasteChanged()));
2893 lastSelectionStart = 0;
2894 lastSelectionEnd = 0;
2895 determineHorizontalAlignment();
2897 if (!qmlDisableDistanceField()) {
2898 QTextOption option = m_textLayout.textOption();
2899 option.setUseDesignMetrics(renderType != QQuickTextInput::NativeRendering);
2900 m_textLayout.setTextOption(option);
2903 m_inputControl =
new QInputControl(QInputControl::LineEdit, q);
2904 setSizePolicy(QLayoutPolicy::Expanding, QLayoutPolicy::Fixed);
2906 QObjectPrivate::connect(q, &QQuickTextInput::readOnlyChanged,
this,
2907 &QQuickTextInputPrivate::readOnlyChanged);
2908 QObjectPrivate::connect(q, &QQuickTextInput::echoModeChanged,
this,
2909 &QQuickTextInputPrivate::echoModeChanged);
2912void QQuickTextInputPrivate::cancelInput()
2915 Q_Q(QQuickTextInput);
2916 if (!m_readOnly && q->hasActiveFocus() && qGuiApp)
2921void QQuickTextInput::updateCursorRectangle(
bool scroll)
2923 Q_D(QQuickTextInput);
2924 if (!isComponentComplete())
2928 d->updateHorizontalScroll();
2929 d->updateVerticalScroll();
2931 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
2934 emit cursorRectangleChanged();
2935 if (d->cursorItem) {
2936 QRectF r = cursorRectangle();
2937 d->cursorItem->setPosition(r.topLeft());
2938 d->cursorItem->setHeight(r.height());
2941 updateInputMethod(Qt::ImCursorRectangle | Qt::ImAnchorRectangle);
2945void QQuickTextInput::selectionChanged()
2947 Q_D(QQuickTextInput);
2948 d->textLayoutDirty =
true;
2949 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
2952 emit selectedTextChanged();
2954 if (d->lastSelectionStart != d->selectionStart()) {
2955 d->lastSelectionStart = d->selectionStart();
2956 if (d->lastSelectionStart == -1)
2957 d->lastSelectionStart = d->m_cursor;
2958 emit selectionStartChanged();
2960 if (d->lastSelectionEnd != d->selectionEnd()) {
2961 d->lastSelectionEnd = d->selectionEnd();
2962 if (d->lastSelectionEnd == -1)
2963 d->lastSelectionEnd = d->m_cursor;
2964 emit selectionEndChanged();
2968QRectF QQuickTextInput::boundingRect()
const
2970 Q_D(
const QQuickTextInput);
2972 int cursorWidth = d->cursorItem ? 0 : 1;
2974 qreal hscroll = d->hscroll;
2975 if (!d->autoScroll || d->contentSize.width() < width())
2976 hscroll -= QQuickTextUtil::alignedX(d->contentSize.width(), width(), effectiveHAlign());
2979 QRectF r(-hscroll, -d->vscroll, d->contentSize.width(), d->contentSize.height());
2980 r.setRight(r.right() + cursorWidth);
2984QRectF QQuickTextInput::clipRect()
const
2986 Q_D(
const QQuickTextInput);
2988 int cursorWidth = d->cursorItem ? d->cursorItem->width() : 1;
2991 QRectF r = QQuickImplicitSizeItem::clipRect();
2992 r.setRight(r.right() + cursorWidth);
2996void QQuickTextInput::q_canPasteChanged()
2998 Q_D(QQuickTextInput);
2999 bool old = d->canPaste;
3000#if QT_CONFIG(clipboard)
3001 bool canPaste =
false;
3002 if (!d->m_readOnly) {
3003 if (
const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData())
3004 canPaste = mimeData->hasText() && !mimeData->text().isEmpty();
3006 d->canPaste = canPaste;
3009 bool changed = d->canPaste != old || !d->canPasteValid;
3010 d->canPasteValid =
true;
3012 emit canPasteChanged();
3016void QQuickTextInput::q_updateAlignment()
3018 Q_D(QQuickTextInput);
3019 if (d->determineHorizontalAlignment()) {
3021 updateCursorRectangle();
3026
3027
3028
3029
3030
3031void QQuickTextInputPrivate::updateDisplayText(
bool forceUpdate)
3033 QString orig = m_textLayout.text();
3035 if (m_echoMode == QQuickTextInput::NoEcho)
3036 str = QString::fromLatin1(
"");
3040 if (m_echoMode == QQuickTextInput::Password) {
3041 str.fill(m_passwordCharacter);
3042 if (m_passwordEchoTimer.isActive() && m_cursor > 0 && m_cursor <= m_text.size()) {
3043 int cursor = m_cursor - 1;
3044 QChar uc = m_text.at(cursor);
3046 if (cursor > 0 && uc.unicode() >= 0xdc00 && uc.unicode() < 0xe000) {
3049 uc = m_text.at(cursor - 1);
3050 if (uc.unicode() >= 0xd800 && uc.unicode() < 0xdc00)
3051 str[cursor - 1] = uc;
3054 }
else if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit && !m_passwordEchoEditing) {
3055 str.fill(m_passwordCharacter);
3061 QChar* uc = str.data();
3062 for (
int i = 0; i < str.size(); ++i) {
3063 if (uc[i] == QChar::LineSeparator
3064 || uc[i] == QChar::ParagraphSeparator
3065 || uc[i] == QChar::ObjectReplacementCharacter)
3066 uc[i] = QChar(0x0020);
3069 if (str != orig || forceUpdate) {
3070 m_textLayout.setText(str);
3072 emit q_func()->displayTextChanged();
3076qreal QQuickTextInputPrivate::calculateImplicitWidthForText(
const QString &text)
const
3078 Q_Q(
const QQuickTextInput);
3079 QTextLayout layout(text);
3081 QTextOption option = m_textLayout.textOption();
3082 option.setTextDirection(m_layoutDirection);
3083 option.setFlags(QTextOption::IncludeTrailingSpaces);
3084 option.setWrapMode(QTextOption::WrapMode(wrapMode));
3085 option.setAlignment(Qt::Alignment(q->effectiveHAlign()));
3086 layout.setTextOption(option);
3087 layout.setFont(font);
3089 layout.setPreeditArea(m_textLayout.preeditAreaPosition(), m_textLayout.preeditAreaText());
3091 layout.beginLayout();
3093 QTextLine line = layout.createLine();
3094 line.setLineWidth(qreal(INT_MAX));
3095 const qreal theImplicitWidth = qCeil(line.naturalTextWidth()) + q->leftPadding() + q->rightPadding();
3098 return theImplicitWidth;
3101qreal QQuickTextInputPrivate::getImplicitWidth()
const
3103 Q_Q(
const QQuickTextInput);
3104 if (!requireImplicitWidth) {
3105 QQuickTextInputPrivate *d =
const_cast<QQuickTextInputPrivate *>(
this);
3106 d->requireImplicitWidth =
true;
3108 if (q->isComponentComplete())
3109 d->implicitWidth = calculateImplicitWidthForText(m_text);
3111 return implicitWidth;
3114void QQuickTextInputPrivate::setTopPadding(qreal value,
bool reset)
3116 Q_Q(QQuickTextInput);
3117 qreal oldPadding = q->topPadding();
3118 if (!reset || extra.isAllocated()) {
3119 extra.value().topPadding = value;
3120 extra.value().explicitTopPadding = !reset;
3122 if ((!reset && !qFuzzyCompare(oldPadding, value)) || (reset && !qFuzzyCompare(oldPadding, padding()))) {
3124 q->updateCursorRectangle();
3125 emit q->topPaddingChanged();
3129void QQuickTextInputPrivate::setLeftPadding(qreal value,
bool reset)
3131 Q_Q(QQuickTextInput);
3132 qreal oldPadding = q->leftPadding();
3133 if (!reset || extra.isAllocated()) {
3134 extra.value().leftPadding = value;
3135 extra.value().explicitLeftPadding = !reset;
3137 if ((!reset && !qFuzzyCompare(oldPadding, value)) || (reset && !qFuzzyCompare(oldPadding, padding()))) {
3139 q->updateCursorRectangle();
3140 emit q->leftPaddingChanged();
3144void QQuickTextInputPrivate::setRightPadding(qreal value,
bool reset)
3146 Q_Q(QQuickTextInput);
3147 qreal oldPadding = q->rightPadding();
3148 if (!reset || extra.isAllocated()) {
3149 extra.value().rightPadding = value;
3150 extra.value().explicitRightPadding = !reset;
3152 if ((!reset && !qFuzzyCompare(oldPadding, value)) || (reset && !qFuzzyCompare(oldPadding, padding()))) {
3154 q->updateCursorRectangle();
3155 emit q->rightPaddingChanged();
3159void QQuickTextInputPrivate::setBottomPadding(qreal value,
bool reset)
3161 Q_Q(QQuickTextInput);
3162 qreal oldPadding = q->bottomPadding();
3163 if (!reset || extra.isAllocated()) {
3164 extra.value().bottomPadding = value;
3165 extra.value().explicitBottomPadding = !reset;
3167 if ((!reset && !qFuzzyCompare(oldPadding, value)) || (reset && !qFuzzyCompare(oldPadding, padding()))) {
3169 q->updateCursorRectangle();
3170 emit q->bottomPaddingChanged();
3174bool QQuickTextInputPrivate::isImplicitResizeEnabled()
const
3176 return !extra.isAllocated() || extra->implicitResize;
3179void QQuickTextInputPrivate::setImplicitResizeEnabled(
bool enabled)
3182 extra.value().implicitResize =
false;
3183 else if (extra.isAllocated())
3184 extra->implicitResize =
true;
3187void QQuickTextInputPrivate::updateLayout()
3189 Q_Q(QQuickTextInput);
3191 if (!q->isComponentComplete())
3195 QTextOption option = m_textLayout.textOption();
3196 option.setTextDirection(layoutDirection());
3197 option.setWrapMode(QTextOption::WrapMode(wrapMode));
3198 option.setAlignment(Qt::Alignment(q->effectiveHAlign()));
3199 if (!qmlDisableDistanceField())
3200 option.setUseDesignMetrics(renderType != QQuickTextInput::NativeRendering);
3202 m_textLayout.setTextOption(option);
3203 m_textLayout.setFont(font);
3205 m_textLayout.beginLayout();
3207 QTextLine line = m_textLayout.createLine();
3208 if (requireImplicitWidth) {
3209 line.setLineWidth(qreal(INT_MAX));
3210 const bool wasInLayout = inLayout;
3212 if (isImplicitResizeEnabled())
3213 q->setImplicitWidth(qCeil(line.naturalTextWidth()) + q->leftPadding() + q->rightPadding());
3214 inLayout = wasInLayout;
3218 qreal lineWidth = q->widthValid() || !isImplicitResizeEnabled() ? q->width() - q->leftPadding() - q->rightPadding() : qreal(INT_MAX);
3222 line.setLineWidth(lineWidth);
3223 line.setPosition(QPointF(0, height));
3225 height += line.height();
3226 width = qMax(width, line.naturalTextWidth());
3228 line = m_textLayout.createLine();
3229 }
while (line.isValid());
3230 m_textLayout.endLayout();
3232 option.setWrapMode(QTextOption::NoWrap);
3233 m_textLayout.setTextOption(option);
3235 textLayoutDirty =
true;
3237 const QSizeF previousSize = contentSize;
3238 contentSize = QSizeF(width, height);
3240 updateType = UpdatePaintNode;
3244 if (isImplicitResizeEnabled()) {
3245 if (!requireImplicitWidth && !q->widthValid())
3246 q->setImplicitSize(width + q->leftPadding() + q->rightPadding(), height + q->topPadding() + q->bottomPadding());
3248 q->setImplicitHeight(height + q->topPadding() + q->bottomPadding());
3251 updateBaselineOffset();
3253 if (previousSize != contentSize)
3254 emit q->contentSizeChanged();
3258
3259
3260
3261
3262
3263void QQuickTextInputPrivate::updateBaselineOffset()
3265 Q_Q(QQuickTextInput);
3266 if (!q->isComponentComplete())
3268 QFontMetricsF fm(font);
3270 if (q->heightValid()) {
3271 const qreal surplusHeight = q->height() - contentSize.height() - q->topPadding() - q->bottomPadding();
3272 if (vAlign == QQuickTextInput::AlignBottom)
3273 yoff = surplusHeight;
3274 else if (vAlign == QQuickTextInput::AlignVCenter)
3275 yoff = surplusHeight/2;
3278 if (m_textLayout.lineCount() > 0) {
3279 QTextLine line = m_textLayout.lineAt(0);
3280 ascent = line.y() + line.ascent();
3282 ascent = fm.ascent();
3284 q->setBaselineOffset(ascent + yoff + q->topPadding());
3287#if QT_CONFIG(clipboard)
3289
3290
3291
3292
3293
3294
3295
3296
3297
3298void QQuickTextInputPrivate::copy(QClipboard::Mode mode)
const
3300 QString t = selectedText();
3301 if (!t.isEmpty() && m_echoMode == QQuickTextInput::Normal) {
3302 QGuiApplication::clipboard()->setText(t, mode);
3307
3308
3309
3310
3311
3312
3313
3314void QQuickTextInputPrivate::paste(QClipboard::Mode clipboardMode)
3316 QString clip = QGuiApplication::clipboard()->text(clipboardMode);
3317 if (!clip.isEmpty() || hasSelectedText()) {
3328
3329
3330void QQuickTextInputPrivate::commitPreedit()
3332 Q_Q(QQuickTextInput);
3337 QGuiApplication::inputMethod()->commit();
3342 QInputMethodEvent ev;
3343 QCoreApplication::sendEvent(q, &ev);
3346void QQuickTextInputPrivate::cancelPreedit()
3348 Q_Q(QQuickTextInput);
3353 QGuiApplication::inputMethod()->reset();
3355 QInputMethodEvent ev;
3356 QCoreApplication::sendEvent(q, &ev);
3361
3362
3363
3364
3365
3366
3367
3368
3369void QQuickTextInputPrivate::backspace()
3371 int priorState = m_undoState;
3372 if (separateSelection()) {
3373 removeSelectedText();
3374 }
else if (m_cursor) {
3377 m_cursor = prevMaskBlank(m_cursor);
3378 QChar uc = m_text.at(m_cursor);
3379 if (m_cursor > 0 && uc.unicode() >= 0xdc00 && uc.unicode() < 0xe000) {
3382 uc = m_text.at(m_cursor - 1);
3383 if (uc.unicode() >= 0xd800 && uc.unicode() < 0xdc00) {
3384 internalDelete(
true);
3388 internalDelete(
true);
3390 finishChange(priorState);
3394
3395
3396
3397
3398
3399
3400
3401
3402void QQuickTextInputPrivate::del()
3404 int priorState = m_undoState;
3405 if (separateSelection()) {
3406 removeSelectedText();
3408 int n = m_textLayout.nextCursorPosition(m_cursor) - m_cursor;
3412 finishChange(priorState);
3416
3417
3418
3419
3420
3421
3422void QQuickTextInputPrivate::insert(
const QString &newText)
3424 int priorState = m_undoState;
3425 if (separateSelection())
3426 removeSelectedText();
3427 internalInsert(newText);
3428 finishChange(priorState);
3432
3433
3434
3435
3436void QQuickTextInputPrivate::clear()
3438 int priorState = m_undoState;
3439 separateSelection();
3441 m_selend = m_text.size();
3442 removeSelectedText();
3444 finishChange(priorState,
false,
false);
3448
3449
3450
3451
3452
3453
3454
3455void QQuickTextInputPrivate::setSelection(
int start,
int length)
3457 Q_Q(QQuickTextInput);
3462 if (start < 0 || start > m_text.size()) {
3463 qWarning(
"QQuickTextInputPrivate::setSelection: Invalid start position");
3468 if (start == m_selstart && start + length == m_selend && m_cursor == m_selend)
3471 m_selend = qMin(start + length, m_text.size());
3472 m_cursor = m_selend;
3473 }
else if (length < 0) {
3474 if (start == m_selend && start + length == m_selstart && m_cursor == m_selstart)
3476 m_selstart = qMax(start + length, 0);
3478 m_cursor = m_selstart;
3479 }
else if (m_selstart != m_selend) {
3485 emitCursorPositionChanged();
3488 emit q->selectionChanged();
3489 emitCursorPositionChanged();
3491 q->updateInputMethod(Qt::ImCursorRectangle | Qt::ImAnchorRectangle | Qt::ImCursorPosition | Qt::ImAnchorPosition
3492 | Qt::ImCurrentSelection);
3497
3498
3499
3500
3501
3502
3503
3504void QQuickTextInputPrivate::updatePasswordEchoEditing(
bool editing)
3506 cancelPasswordEchoTimer();
3507 m_passwordEchoEditing = editing;
3508 updateDisplayText();
3512
3513
3514
3515
3516
3517
3518bool QQuickTextInputPrivate::fixup()
3520#if QT_CONFIG(validator)
3522 QString textCopy = m_text;
3523 int cursorCopy = m_cursor;
3524 m_validator->fixup(textCopy);
3525 if (m_validator->validate(textCopy, cursorCopy) == QValidator::Acceptable) {
3526 if (textCopy != m_text || cursorCopy != m_cursor)
3527 internalSetText(textCopy, cursorCopy);
3536
3537
3538
3539
3540
3541void QQuickTextInputPrivate::moveCursor(
int pos,
bool mark)
3543 Q_Q(QQuickTextInput);
3548 if (pos != m_cursor) {
3551 pos = pos > m_cursor ? nextMaskBlank(pos) : prevMaskBlank(pos);
3555 if (m_selend > m_selstart && m_cursor == m_selstart)
3557 else if (m_selend > m_selstart && m_cursor == m_selend)
3558 anchor = m_selstart;
3561 m_selstart = qMin(anchor, pos);
3562 m_selend = qMax(anchor, pos);
3567 if (mark || m_selDirty) {
3569 emit q->selectionChanged();
3571 emitCursorPositionChanged();
3573 q->updateInputMethod();
3579
3580
3581
3582
3583
3584void QQuickTextInputPrivate::processInputMethodEvent(QInputMethodEvent *event)
3586 Q_Q(QQuickTextInput);
3588 int priorState = -1;
3589 bool isGettingInput = !event->commitString().isEmpty()
3590 || event->preeditString() != preeditAreaText()
3591 || event->replacementLength() > 0;
3592 bool cursorPositionChanged =
false;
3593 bool selectionChange =
false;
3594 m_preeditDirty = event->preeditString() != preeditAreaText();
3596 if (isGettingInput) {
3598 priorState = m_undoState;
3599 separateSelection();
3600 if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit && !m_passwordEchoEditing) {
3601 updatePasswordEchoEditing(
true);
3603 m_selend = m_text.size();
3605 removeSelectedText();
3609 if (event->replacementStart() <= 0)
3610 c += event->commitString().size() - qMin(-event->replacementStart(), event->replacementLength());
3612 int cursorInsertPos = m_cursor + event->replacementStart();
3613 if (cursorInsertPos < 0)
3614 cursorInsertPos = 0;
3617 if (event->replacementLength()) {
3618 m_selstart = cursorInsertPos;
3619 m_selend = m_selstart + event->replacementLength();
3620 m_selend = qMin(m_selend, m_text.size());
3621 removeSelectedText();
3623 m_cursor = cursorInsertPos;
3625 if (!event->commitString().isEmpty()) {
3626 internalInsert(event->commitString());
3627 cursorPositionChanged =
true;
3629 m_cursor = qBound(0, c, m_text.size());
3632 for (
int i = 0; i < event->attributes().size(); ++i) {
3633 const QInputMethodEvent::Attribute &a = event->attributes().at(i);
3634 if (a.type == QInputMethodEvent::Selection) {
3641 if (!cursorPositionChanged || !m_maskData)
3642 m_cursor = qBound(0, a.start + a.length, m_text.size());
3644 m_selstart = qMax(0, qMin(a.start, m_text.size()));
3645 m_selend = m_cursor;
3646 if (m_selend < m_selstart) {
3647 qSwap(m_selstart, m_selend);
3649 selectionChange =
true;
3651 selectionChange = m_selstart != m_selend;
3652 m_selstart = m_selend = 0;
3654 cursorPositionChanged =
true;
3657 QString oldPreeditString = m_textLayout.preeditAreaText();
3658 m_textLayout.setPreeditArea(m_cursor, event->preeditString());
3659 if (oldPreeditString != m_textLayout.preeditAreaText()) {
3660 emit q->preeditTextChanged();
3661 if (!event->preeditString().isEmpty() && m_undoPreeditState == -1)
3663 m_undoPreeditState = priorState;
3665 const int oldPreeditCursor = m_preeditCursor;
3666 m_preeditCursor = event->preeditString().size();
3667 hasImState = !event->preeditString().isEmpty();
3668 bool cursorVisible =
true;
3669 QList<QTextLayout::FormatRange> formats;
3670 for (
int i = 0; i < event->attributes().size(); ++i) {
3671 const QInputMethodEvent::Attribute &a = event->attributes().at(i);
3672 if (a.type == QInputMethodEvent::Cursor) {
3674 m_preeditCursor = a.start;
3675 cursorVisible = a.length != 0;
3676 }
else if (a.type == QInputMethodEvent::TextFormat) {
3678 QTextCharFormat f = qvariant_cast<QTextFormat>(a.value).toCharFormat();
3680 QTextLayout::FormatRange o;
3681 o.start = a.start + m_cursor;
3682 o.length = a.length;
3688 m_textLayout.setFormats(formats);
3694 q->setCursorVisible(cursorVisible);
3696 updateDisplayText(
true);
3697 if (cursorPositionChanged && emitCursorPositionChanged())
3698 q->updateInputMethod(Qt::ImCursorPosition | Qt::ImAnchorPosition);
3699 else if (m_preeditCursor != oldPreeditCursor || isGettingInput)
3700 q->updateCursorRectangle();
3703 finishChange(priorState);
3705 if (selectionChange) {
3706 emit q->selectionChanged();
3707 q->updateInputMethod(Qt::ImCursorRectangle | Qt::ImAnchorRectangle
3708 | Qt::ImCurrentSelection);
3712 if (event->preeditString().isEmpty())
3713 m_undoPreeditState = -1;
3719
3720
3721
3722
3723
3724
3725void QQuickTextInputPrivate::selectWordAtPos(
int cursor)
3727 int next = cursor + 1;
3730 int c = m_textLayout.previousCursorPosition(next, QTextLayout::SkipWords);
3731 moveCursor(c,
false);
3733 int end = m_textLayout.nextCursorPosition(c, QTextLayout::SkipWords);
3734 while (end > cursor && m_text.at(end - 1).isSpace())
3736 moveCursor(end,
true);
3740
3741
3742
3743
3744
3745
3746
3747
3748
3749
3750
3751bool QQuickTextInputPrivate::finishChange(
int validateFromState,
bool update,
bool edited)
3753 Q_Q(QQuickTextInput);
3757 bool inputMethodAttributesChanged = m_textDirty || m_selDirty;
3759 bool alignmentChanged =
false;
3760 bool textChanged =
false;
3764 bool wasValidInput = m_validInput;
3765 bool wasAcceptable = m_acceptableInput;
3766 m_validInput =
true;
3767 m_acceptableInput =
true;
3768#if QT_CONFIG(validator)
3770 QString textCopy = m_text;
3772 textCopy = maskString(0, m_text,
true);
3773 int cursorCopy = m_cursor;
3774 QValidator::State state = m_validator->validate(textCopy, cursorCopy);
3777 m_validInput = state != QValidator::Invalid;
3778 m_acceptableInput = state == QValidator::Acceptable;
3779 if (m_validInput && !m_maskData) {
3780 if (m_text != textCopy) {
3781 internalSetText(textCopy, cursorCopy);
3784 m_cursor = cursorCopy;
3794 if (m_undoPreeditState >= 0 && (m_undoPreeditState < validateFromState || validateFromState < 0))
3795 validateFromState = m_undoPreeditState;
3797 if (validateFromState >= 0 && wasValidInput && !m_validInput) {
3798 if (m_transactions.size())
3800 internalUndo(validateFromState);
3801 m_history.resize(m_undoState);
3802 m_validInput =
true;
3803 m_acceptableInput = wasAcceptable;
3804 m_textDirty =
false;
3809 m_textDirty =
false;
3811 m_preeditDirty =
false;
3813 alignmentChanged = determineHorizontalAlignment();
3815 emit q->textEdited();
3816 emit q->textChanged();
3819 updateDisplayText(alignmentChanged);
3821 if (m_acceptableInput != wasAcceptable)
3822 emit q->acceptableInputChanged();
3825 if (m_preeditDirty) {
3826 m_preeditDirty =
false;
3827 if (determineHorizontalAlignment()) {
3828 alignmentChanged =
true;
3836 emit q->selectionChanged();
3840 inputMethodAttributesChanged |= (m_cursor != m_lastCursorPos);
3841 if (inputMethodAttributesChanged)
3842 q->updateInputMethod();
3844 emitUndoRedoChanged();
3846 if (!emitCursorPositionChanged() && (alignmentChanged || textChanged))
3847 q->updateCursorRectangle();
3853
3854
3855
3856
3857void QQuickTextInputPrivate::internalSetText(
const QString &txt,
int pos,
bool edited)
3860 QString oldText = m_text;
3862 m_text = maskString(0, txt,
true);
3863 m_text += clearString(m_text.size(), m_maxLength - m_text.size());
3865 m_text = txt.isEmpty() ? txt : txt.left(m_maxLength);
3870 m_undoPreeditState = -1;
3872 m_cursor = (pos < 0 || pos > m_text.size()) ? m_text.size() : pos;
3873 m_textDirty = (oldText != m_text);
3875 bool changed = finishChange(-1,
true, edited);
3876#if !QT_CONFIG(accessibility)
3879 Q_Q(QQuickTextInput);
3880 if (changed && QAccessible::isActive()) {
3881 if (QObject *acc = QQuickAccessibleAttached::findAccessible(q, QAccessible::EditableText)) {
3882 QAccessibleTextUpdateEvent ev(acc, 0, oldText, m_text);
3883 QAccessible::updateAccessibility(&ev);
3891
3892
3893
3894
3895
3896void QQuickTextInputPrivate::addCommand(
const Command &cmd)
3898 if (m_separator && m_undoState && m_history[m_undoState - 1].type != Separator) {
3899 m_history.resize(m_undoState + 2);
3900 m_history[m_undoState++] = Command(Separator, m_cursor, u'\0', m_selstart, m_selend);
3902 m_history.resize(m_undoState + 1);
3904 m_separator =
false;
3905 m_history[m_undoState++] = cmd;
3909
3910
3911
3912
3913
3914
3915
3916
3917
3918void QQuickTextInputPrivate::internalInsert(
const QString &s)
3920 Q_Q(QQuickTextInput);
3921 if (m_echoMode == QQuickTextInput::Password) {
3922 if (m_passwordMaskDelay > 0)
3923 m_passwordEchoTimer.start(m_passwordMaskDelay, q);
3925 Q_ASSERT(!hasSelectedText());
3927 QString ms = maskString(m_cursor, s);
3928 for (
int i = 0; i < ms.size(); ++i) {
3929 addCommand (Command(DeleteSelection, m_cursor + i, m_text.at(m_cursor + i), -1, -1));
3930 addCommand(Command(Insert, m_cursor + i, ms.at(i), -1, -1));
3932 m_text.replace(m_cursor, ms.size(), ms);
3933 m_cursor += ms.size();
3934 m_cursor = nextMaskBlank(m_cursor);
3937 int remaining = m_maxLength - m_text.size();
3938 if (remaining != 0) {
3939 const QStringView remainingStr = QStringView{s}.left(remaining);
3940 m_text.insert(m_cursor, remainingStr);
3941 for (
auto e : remainingStr)
3942 addCommand(Command(Insert, m_cursor++, e, -1, -1));
3949
3950
3951
3952
3953
3954
3955
3956
3957
3958
3959void QQuickTextInputPrivate::internalDelete(
bool wasBackspace)
3961 if (m_cursor < m_text.size()) {
3962 cancelPasswordEchoTimer();
3963 Q_ASSERT(!hasSelectedText());
3964 addCommand(Command((CommandType)((m_maskData ? 2 : 0) + (wasBackspace ? Remove : Delete)),
3965 m_cursor, m_text.at(m_cursor), -1, -1));
3967 m_text.replace(m_cursor, 1, clearString(m_cursor, 1));
3968 addCommand(Command(Insert, m_cursor, m_text.at(m_cursor), -1, -1));
3970 m_text.remove(m_cursor, 1);
3977
3978
3979
3980
3981
3982
3983
3984
3985void QQuickTextInputPrivate::removeSelectedText()
3987 if (m_selstart < m_selend && m_selend <= m_text.size()) {
3988 cancelPasswordEchoTimer();
3990 if (m_selstart <= m_cursor && m_cursor < m_selend) {
3993 for (i = m_cursor; i >= m_selstart; --i)
3994 addCommand (Command(DeleteSelection, i, m_text.at(i), -1, 1));
3995 for (i = m_selend - 1; i > m_cursor; --i)
3996 addCommand (Command(DeleteSelection, i - m_cursor + m_selstart - 1, m_text.at(i), -1, -1));
3998 for (i = m_selend-1; i >= m_selstart; --i)
3999 addCommand (Command(RemoveSelection, i, m_text.at(i), -1, -1));
4002 m_text.replace(m_selstart, m_selend - m_selstart, clearString(m_selstart, m_selend - m_selstart));
4003 for (
int i = 0; i < m_selend - m_selstart; ++i)
4004 addCommand(Command(Insert, m_selstart + i, m_text.at(m_selstart + i), -1, -1));
4006 m_text.remove(m_selstart, m_selend - m_selstart);
4008 if (m_cursor > m_selstart)
4009 m_cursor -= qMin(m_cursor, m_selend) - m_selstart;
4016
4017
4018
4019
4020
4021
4023bool QQuickTextInputPrivate::separateSelection()
4025 if (hasSelectedText()) {
4027 addCommand(Command(SetSelection, m_cursor, u'\0', m_selstart, m_selend));
4035
4036
4037
4038
4039
4040void QQuickTextInputPrivate::parseInputMask(
const QString &maskFields)
4042 int delimiter = maskFields.indexOf(QLatin1Char(
';'));
4043 if (maskFields.isEmpty() || delimiter == 0) {
4045 m_maskData.reset(
nullptr);
4046 m_maxLength = 32767;
4047 internalSetText(QString());
4052 if (delimiter == -1) {
4053 m_blank = QLatin1Char(
' ');
4054 m_inputMask = maskFields;
4056 m_inputMask = maskFields.left(delimiter);
4057 m_blank = (delimiter + 1 < maskFields.size()) ? maskFields[delimiter + 1] : QLatin1Char(
' ');
4063 for (
int i=0; i<m_inputMask.size(); i++) {
4064 c = m_inputMask.at(i);
4065 if (i > 0 && m_inputMask.at(i-1) == QLatin1Char(
'\\')) {
4069 if (c != QLatin1Char(
'\\') && c != QLatin1Char(
'!') &&
4070 c != QLatin1Char(
'<') && c != QLatin1Char(
'>') &&
4071 c != QLatin1Char(
'{') && c != QLatin1Char(
'}') &&
4072 c != QLatin1Char(
'[') && c != QLatin1Char(
']'))
4076 m_maskData.reset(
new MaskInputData[m_maxLength]);
4078 MaskInputData::Casemode m = MaskInputData::NoCaseMode;
4081 bool escape =
false;
4083 for (
int i = 0; i < m_inputMask.size(); i++) {
4084 c = m_inputMask.at(i);
4087 m_maskData[index].maskChar = c;
4088 m_maskData[index].separator = s;
4089 m_maskData[index].caseMode = m;
4092 }
else if (c == QLatin1Char(
'<')) {
4093 m = MaskInputData::Lower;
4094 }
else if (c == QLatin1Char(
'>')) {
4095 m = MaskInputData::Upper;
4096 }
else if (c == QLatin1Char(
'!')) {
4097 m = MaskInputData::NoCaseMode;
4098 }
else if (c != QLatin1Char(
'{') && c != QLatin1Char(
'}') && c != QLatin1Char(
'[') && c != QLatin1Char(
']')) {
4099 switch (c.unicode()) {
4126 m_maskData[index].maskChar = c;
4127 m_maskData[index].separator = s;
4128 m_maskData[index].caseMode = m;
4133 internalSetText(m_text);
4138
4139
4140
4141
4142bool QQuickTextInputPrivate::isValidInput(QChar key, QChar mask)
const
4144 switch (mask.unicode()) {
4150 if (key.isLetter() || key == m_blank)
4154 if (key.isLetterOrNumber())
4158 if (key.isLetterOrNumber() || key == m_blank)
4162 if (key.isPrint() && key != m_blank)
4166 if (key.isPrint() || key == m_blank)
4174 if (key.isNumber() || key == m_blank)
4178 if (key.isNumber() && key.digitValue() > 0)
4182 if ((key.isNumber() && key.digitValue() > 0) || key == m_blank)
4186 if (key.isNumber() || key == QLatin1Char(
'+') || key == QLatin1Char(
'-') || key == m_blank)
4190 if (key == QLatin1Char(
'0') || key == QLatin1Char(
'1'))
4194 if (key == QLatin1Char(
'0') || key == QLatin1Char(
'1') || key == m_blank)
4198 if (key.isNumber() || (key >= QLatin1Char(
'a') && key <= QLatin1Char(
'f')) || (key >= QLatin1Char(
'A') && key <= QLatin1Char(
'F')))
4202 if (key.isNumber() || (key >= QLatin1Char(
'a') && key <= QLatin1Char(
'f')) || (key >= QLatin1Char(
'A') && key <= QLatin1Char(
'F')) || key == m_blank)
4212
4213
4214
4215
4216
4217
4218
4219QQuickTextInputPrivate::ValidatorState QQuickTextInputPrivate::hasAcceptableInput(
const QString &str)
const
4221#if QT_CONFIG(validator)
4222 QString textCopy = str;
4223 int cursorCopy = m_cursor;
4225 QValidator::State state = m_validator->validate(textCopy, cursorCopy);
4226 if (state != QValidator::Acceptable)
4227 return ValidatorState(state);
4232 return AcceptableInput;
4234 if (str.size() != m_maxLength)
4235 return InvalidInput;
4237 for (
int i=0; i < m_maxLength; ++i) {
4238 if (m_maskData[i].separator) {
4239 if (str.at(i) != m_maskData[i].maskChar)
4240 return InvalidInput;
4242 if (!isValidInput(str.at(i), m_maskData[i].maskChar))
4243 return InvalidInput;
4246 return AcceptableInput;
4250
4251
4252
4253
4254
4255
4256
4257QString QQuickTextInputPrivate::maskString(uint pos,
const QString &str,
bool clear)
const
4259 if (pos >= (uint)m_maxLength)
4260 return QString::fromLatin1(
"");
4263 fill = clear ? clearString(0, m_maxLength) : m_text;
4266 QString s = QString::fromLatin1(
"");
4268 while (i < m_maxLength) {
4269 if (strIndex < str.size()) {
4270 if (m_maskData[i].separator) {
4271 s += m_maskData[i].maskChar;
4272 if (str[strIndex] == m_maskData[i].maskChar)
4276 if (isValidInput(str[strIndex], m_maskData[i].maskChar)) {
4277 switch (m_maskData[i].caseMode) {
4278 case MaskInputData::Upper:
4279 s += str[strIndex].toUpper();
4281 case MaskInputData::Lower:
4282 s += str[strIndex].toLower();
4290 int n = findInMask(i,
true,
true, str[strIndex]);
4292 if (str.size() != 1 || i == 0 || (i > 0 && (!m_maskData[i-1].separator || m_maskData[i-1].maskChar != str[strIndex]))) {
4293 s += QStringView{fill}.mid(i, n-i+1);
4298 n = findInMask(i,
true,
false, str[strIndex]);
4300 s += QStringView{fill}.mid(i, n-i);
4301 switch (m_maskData[n].caseMode) {
4302 case MaskInputData::Upper:
4303 s += str[strIndex].toUpper();
4305 case MaskInputData::Lower:
4306 s += str[strIndex].toLower();
4327
4328
4329
4330
4331
4332QString QQuickTextInputPrivate::clearString(uint pos, uint len)
const
4334 if (pos >= (uint)m_maxLength)
4338 int end = qMin((uint)m_maxLength, pos + len);
4339 for (
int i = pos; i < end; ++i)
4340 if (m_maskData[i].separator)
4341 s += m_maskData[i].maskChar;
4349
4350
4351
4352
4353
4354QString QQuickTextInputPrivate::stripString(
const QString &str)
const
4360 int end = qMin(m_maxLength, str.size());
4361 for (
int i = 0; i < end; ++i) {
4362 if (m_maskData[i].separator)
4363 s += m_maskData[i].maskChar;
4364 else if (str[i] != m_blank)
4372
4373
4374
4375int QQuickTextInputPrivate::findInMask(
int pos,
bool forward,
bool findSeparator, QChar searchChar)
const
4377 if (pos >= m_maxLength || pos < 0)
4380 int end = forward ? m_maxLength : -1;
4381 int step = forward ? 1 : -1;
4385 if (findSeparator) {
4386 if (m_maskData[i].separator && m_maskData[i].maskChar == searchChar)
4389 if (!m_maskData[i].separator) {
4390 if (searchChar.isNull())
4392 else if (isValidInput(searchChar, m_maskData[i].maskChar))
4401void QQuickTextInputPrivate::internalUndo(
int until)
4403 if (!isUndoAvailable())
4405 cancelPasswordEchoTimer();
4407 while (m_undoState && m_undoState > until) {
4408 Command& cmd = m_history[--m_undoState];
4411 m_text.remove(cmd.pos, 1);
4415 m_selstart = cmd.selStart;
4416 m_selend = cmd.selEnd;
4420 case RemoveSelection:
4421 m_text.insert(cmd.pos, cmd.uc);
4422 m_cursor = cmd.pos + 1;
4425 case DeleteSelection:
4426 m_text.insert(cmd.pos, cmd.uc);
4432 if (until < 0 && m_undoState) {
4433 Command& next = m_history[m_undoState-1];
4434 if (next.type != cmd.type
4435 && next.type < RemoveSelection
4436 && (cmd.type < RemoveSelection || next.type == Separator)) {
4445void QQuickTextInputPrivate::internalRedo()
4447 if (!isRedoAvailable())
4450 while (m_undoState < m_history.size()) {
4451 Command& cmd = m_history[m_undoState++];
4454 m_text.insert(cmd.pos, cmd.uc);
4455 m_cursor = cmd.pos + 1;
4458 m_selstart = cmd.selStart;
4459 m_selend = cmd.selEnd;
4464 case RemoveSelection:
4465 case DeleteSelection:
4466 m_text.remove(cmd.pos, 1);
4467 m_selstart = cmd.selStart;
4468 m_selend = cmd.selEnd;
4472 m_selstart = cmd.selStart;
4473 m_selend = cmd.selEnd;
4477 if (m_undoState < m_history.size()) {
4478 Command& next = m_history[m_undoState];
4479 if (next.type != cmd.type
4480 && cmd.type < RemoveSelection
4481 && next.type != Separator
4482 && (next.type < RemoveSelection || cmd.type == Separator)) {
4490void QQuickTextInputPrivate::emitUndoRedoChanged()
4492 Q_Q(QQuickTextInput);
4493 const bool previousUndo = canUndo;
4494 const bool previousRedo = canRedo;
4496 canUndo = isUndoAvailable();
4497 canRedo = isRedoAvailable();
4499 if (previousUndo != canUndo)
4500 emit q->canUndoChanged();
4501 if (previousRedo != canRedo)
4502 emit q->canRedoChanged();
4506
4507
4508
4509
4510
4511bool QQuickTextInputPrivate::emitCursorPositionChanged()
4513 Q_Q(QQuickTextInput);
4514 if (m_cursor != m_lastCursorPos) {
4515 m_lastCursorPos = m_cursor;
4517 q->updateCursorRectangle();
4518 emit q->cursorPositionChanged();
4520 if (!hasSelectedText()) {
4521 if (lastSelectionStart != m_cursor) {
4522 lastSelectionStart = m_cursor;
4523 emit q->selectionStartChanged();
4525 if (lastSelectionEnd != m_cursor) {
4526 lastSelectionEnd = m_cursor;
4527 emit q->selectionEndChanged();
4531#if QT_CONFIG(accessibility)
4532 if (QAccessible::isActive()) {
4533 if (QObject *acc = QQuickAccessibleAttached::findAccessible(q, QAccessible::EditableText)) {
4534 QAccessibleTextCursorEvent ev(acc, m_cursor);
4535 QAccessible::updateAccessibility(&ev);
4546void QQuickTextInputPrivate::setBlinkingCursorEnabled(
bool enable)
4548 if (enable == m_blinkEnabled)
4551 m_blinkEnabled = enable;
4552 updateCursorBlinking();
4555 connect(qApp->styleHints(), &QStyleHints::cursorFlashTimeChanged,
this, &QQuickTextInputPrivate::updateCursorBlinking);
4557 disconnect(qApp->styleHints(), &QStyleHints::cursorFlashTimeChanged,
this, &QQuickTextInputPrivate::updateCursorBlinking);
4560void QQuickTextInputPrivate::updateCursorBlinking()
4562 Q_Q(QQuickTextInput);
4565 q->killTimer(m_blinkTimer);
4569 if (m_blinkEnabled && cursorVisible && !cursorItem && !m_readOnly) {
4570 int flashTime = QGuiApplication::styleHints()->cursorFlashTime();
4572 m_blinkTimer = q->startTimer(flashTime / 2);
4576 updateType = UpdatePaintNode;
4581void QQuickTextInput::timerEvent(QTimerEvent *event)
4583 Q_D(QQuickTextInput);
4584 if (event->timerId() == d->m_blinkTimer) {
4585 d->m_blinkStatus = !d->m_blinkStatus;
4586 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
4589 }
else if (event->timerId() == d->m_passwordEchoTimer.timerId()) {
4590 d->m_passwordEchoTimer.stop();
4591 d->updateDisplayText();
4592 updateCursorRectangle();
4596void QQuickTextInputPrivate::processKeyEvent(QKeyEvent* event)
4598 Q_Q(QQuickTextInput);
4600 if (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return) {
4601 if (hasAcceptableInput(m_text) == AcceptableInput || fixup()) {
4603 QInputMethod *inputMethod = QGuiApplication::inputMethod();
4604 inputMethod->commit();
4609 emit q->editingFinished();
4619 updateCursorBlinking();
4621 if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit
4622 && !m_passwordEchoEditing
4624 && !event->text().isEmpty()
4625 && !(event->modifiers() & Qt::ControlModifier)) {
4631 updatePasswordEchoEditing(
true);
4635 bool unknown =
false;
4636#if QT_CONFIG(shortcut)
4637 bool visual = cursorMoveStyle() == Qt::VisualMoveStyle;
4642#if QT_CONFIG(shortcut)
4643 else if (event == QKeySequence::Undo) {
4646 else if (event == QKeySequence::Redo) {
4649 else if (event == QKeySequence::SelectAll) {
4652#if QT_CONFIG(clipboard)
4653 else if (event == QKeySequence::Copy) {
4656 else if (event == QKeySequence::Paste) {
4658 QClipboard::Mode mode = QClipboard::Clipboard;
4662 else if (event == QKeySequence::Cut) {
4665 else if (event == QKeySequence::DeleteEndOfLine) {
4670 else if (event == QKeySequence::MoveToStartOfLine || event == QKeySequence::MoveToStartOfBlock) {
4673 else if (event == QKeySequence::MoveToEndOfLine || event == QKeySequence::MoveToEndOfBlock) {
4676 else if (event == QKeySequence::SelectStartOfLine || event == QKeySequence::SelectStartOfBlock) {
4679 else if (event == QKeySequence::SelectEndOfLine || event == QKeySequence::SelectEndOfBlock) {
4682 else if (event == QKeySequence::MoveToNextChar) {
4683 if (hasSelectedText()) {
4684 moveCursor(selectionEnd(),
false);
4686 cursorForward(0, visual ? 1 : (layoutDirection() == Qt::LeftToRight ? 1 : -1));
4689 else if (event == QKeySequence::SelectNextChar) {
4690 cursorForward(1, visual ? 1 : (layoutDirection() == Qt::LeftToRight ? 1 : -1));
4692 else if (event == QKeySequence::MoveToPreviousChar) {
4693 if (hasSelectedText()) {
4694 moveCursor(selectionStart(),
false);
4696 cursorForward(0, visual ? -1 : (layoutDirection() == Qt::LeftToRight ? -1 : 1));
4699 else if (event == QKeySequence::SelectPreviousChar) {
4700 cursorForward(1, visual ? -1 : (layoutDirection() == Qt::LeftToRight ? -1 : 1));
4702 else if (event == QKeySequence::MoveToNextWord) {
4703 if (m_echoMode == QQuickTextInput::Normal)
4704 layoutDirection() == Qt::LeftToRight ? cursorWordForward(0) : cursorWordBackward(0);
4706 layoutDirection() == Qt::LeftToRight ? end(0) : home(0);
4708 else if (event == QKeySequence::MoveToPreviousWord) {
4709 if (m_echoMode == QQuickTextInput::Normal)
4710 layoutDirection() == Qt::LeftToRight ? cursorWordBackward(0) : cursorWordForward(0);
4711 else if (!m_readOnly) {
4712 layoutDirection() == Qt::LeftToRight ? home(0) : end(0);
4715 else if (event == QKeySequence::SelectNextWord) {
4716 if (m_echoMode == QQuickTextInput::Normal)
4717 layoutDirection() == Qt::LeftToRight ? cursorWordForward(1) : cursorWordBackward(1);
4719 layoutDirection() == Qt::LeftToRight ? end(1) : home(1);
4721 else if (event == QKeySequence::SelectPreviousWord) {
4722 if (m_echoMode == QQuickTextInput::Normal)
4723 layoutDirection() == Qt::LeftToRight ? cursorWordBackward(1) : cursorWordForward(1);
4725 layoutDirection() == Qt::LeftToRight ? home(1) : end(1);
4727 else if (event == QKeySequence::Delete) {
4731 else if (event == QKeySequence::DeleteEndOfWord) {
4735 else if (event == QKeySequence::DeleteStartOfWord) {
4737 deleteStartOfWord();
4738 }
else if (event == QKeySequence::DeleteCompleteLine) {
4741#if QT_CONFIG(clipboard)
4749 bool handled =
false;
4750 if (event->modifiers() & Qt::ControlModifier) {
4751 switch (event->key()) {
4752 case Qt::Key_Backspace:
4754 deleteStartOfWord();
4761 switch (event->key()) {
4762 case Qt::Key_Backspace:
4774 if (event->key() == Qt::Key_Direction_L || event->key() == Qt::Key_Direction_R) {
4775 setLayoutDirection((event->key() == Qt::Key_Direction_L) ? Qt::LeftToRight : Qt::RightToLeft);
4779 if (unknown && !m_readOnly) {
4780 if (m_inputControl->isAcceptableInput(event)) {
4784 && !hasSelectedText()
4785 && !(m_cursor == q_func()->text().size())) {
4789 insert(event->text());
4802
4803
4804
4805
4807void QQuickTextInputPrivate::deleteStartOfWord()
4809 int priorState = m_undoState;
4811 if (!separateSelection()) {
4812 Command cmd(SetSelection, m_cursor, u'\0', m_selstart, m_selend);
4814 cursorWordBackward(
true);
4818 removeSelectedText();
4819 finishChange(priorState);
4823
4824
4825
4826
4828void QQuickTextInputPrivate::deleteEndOfWord()
4830 int priorState = m_undoState;
4831 Command cmd(SetSelection, m_cursor, u'\0', m_selstart, m_selend);
4833 cursorWordForward(
true);
4837 removeSelectedText();
4838 finishChange(priorState);
4842
4843
4844
4845
4847void QQuickTextInputPrivate::deleteEndOfLine()
4849 int priorState = m_undoState;
4850 Command cmd(SetSelection, m_cursor, u'\0', m_selstart, m_selend);
4852 setSelection(m_cursor, end());
4854 removeSelectedText();
4855 finishChange(priorState);
4859
4860
4861
4862
4863
4864
4865
4866
4867void QQuickTextInput::ensureVisible(
int position)
4869 Q_D(QQuickTextInput);
4870 d->ensureVisible(position);
4871 updateCursorRectangle(
false);
4875
4876
4877
4878
4879
4880
4881
4882
4883
4884
4885void QQuickTextInput::clear()
4887 Q_D(QQuickTextInput);
4893
4894
4895
4896
4897
4898
4899
4900
4901
4902
4903
4904
4905
4906
4907
4908
4909
4910
4911
4912
4913
4914
4915qreal QQuickTextInput::padding()
const
4917 Q_D(
const QQuickTextInput);
4918 return d->padding();
4921void QQuickTextInput::setPadding(qreal padding)
4923 Q_D(QQuickTextInput);
4924 if (qFuzzyCompare(d->padding(), padding))
4927 d->extra.value().padding = padding;
4929 updateCursorRectangle();
4930 emit paddingChanged();
4931 if (!d->extra.isAllocated() || !d->extra->explicitTopPadding)
4932 emit topPaddingChanged();
4933 if (!d->extra.isAllocated() || !d->extra->explicitLeftPadding)
4934 emit leftPaddingChanged();
4935 if (!d->extra.isAllocated() || !d->extra->explicitRightPadding)
4936 emit rightPaddingChanged();
4937 if (!d->extra.isAllocated() || !d->extra->explicitBottomPadding)
4938 emit bottomPaddingChanged();
4941void QQuickTextInput::resetPadding()
4946qreal QQuickTextInput::topPadding()
const
4948 Q_D(
const QQuickTextInput);
4949 if (d->extra.isAllocated() && d->extra->explicitTopPadding)
4950 return d->extra->topPadding;
4951 return d->padding();
4954void QQuickTextInput::setTopPadding(qreal padding)
4956 Q_D(QQuickTextInput);
4957 d->setTopPadding(padding);
4960void QQuickTextInput::resetTopPadding()
4962 Q_D(QQuickTextInput);
4963 d->setTopPadding(0,
true);
4966qreal QQuickTextInput::leftPadding()
const
4968 Q_D(
const QQuickTextInput);
4969 if (d->extra.isAllocated() && d->extra->explicitLeftPadding)
4970 return d->extra->leftPadding;
4971 return d->padding();
4974void QQuickTextInput::setLeftPadding(qreal padding)
4976 Q_D(QQuickTextInput);
4977 d->setLeftPadding(padding);
4980void QQuickTextInput::resetLeftPadding()
4982 Q_D(QQuickTextInput);
4983 d->setLeftPadding(0,
true);
4986qreal QQuickTextInput::rightPadding()
const
4988 Q_D(
const QQuickTextInput);
4989 if (d->extra.isAllocated() && d->extra->explicitRightPadding)
4990 return d->extra->rightPadding;
4991 return d->padding();
4994void QQuickTextInput::setRightPadding(qreal padding)
4996 Q_D(QQuickTextInput);
4997 d->setRightPadding(padding);
5000void QQuickTextInput::resetRightPadding()
5002 Q_D(QQuickTextInput);
5003 d->setRightPadding(0,
true);
5006qreal QQuickTextInput::bottomPadding()
const
5008 Q_D(
const QQuickTextInput);
5009 if (d->extra.isAllocated() && d->extra->explicitBottomPadding)
5010 return d->extra->bottomPadding;
5011 return d->padding();
5014void QQuickTextInput::setBottomPadding(qreal padding)
5016 Q_D(QQuickTextInput);
5017 d->setBottomPadding(padding);
5020void QQuickTextInput::resetBottomPadding()
5022 Q_D(QQuickTextInput);
5023 d->setBottomPadding(0,
true);
5026#if QT_VERSION < QT_VERSION_CHECK(7
, 0
, 0
)
5027void QQuickTextInput::setOldSelectionDefault()
5029 Q_D(QQuickTextInput);
5030 d->selectByMouse =
false;
5031 d->selectByTouchDrag =
true;
5032 qCDebug(lcQuickTextInput,
"pre-6.4 behavior chosen: selectByMouse defaults false; if enabled, touchscreen acts like a mouse");
5036QQuickPre64TextInput::QQuickPre64TextInput(QQuickItem *parent)
5037 : QQuickTextInput(parent)
5039 setOldSelectionDefault();
5045#include "moc_qquicktextinput_p.cpp"
Combined button and popup list for selecting options.