1
/****************************************************************************
3
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4
** Contact: http://www.qt-project.org/
6
** This file is part of the QtQml module of the Qt Toolkit.
8
** $QT_BEGIN_LICENSE:LGPL$
9
** GNU Lesser General Public License Usage
10
** This file may be used under the terms of the GNU Lesser General Public
11
** License version 2.1 as published by the Free Software Foundation and
12
** appearing in the file LICENSE.LGPL included in the packaging of this
13
** file. Please review the following information to ensure the GNU Lesser
14
** General Public License version 2.1 requirements will be met:
15
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17
** In addition, as a special exception, Nokia gives you certain additional
18
** rights. These rights are described in the Nokia Qt LGPL Exception
19
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21
** GNU General Public License Usage
22
** Alternatively, this file may be used under the terms of the GNU General
23
** Public License version 3.0 as published by the Free Software Foundation
24
** and appearing in the file LICENSE.GPL included in the packaging of this
25
** file. Please review the following information to ensure the GNU General
26
** Public License version 3.0 requirements will be met:
27
** http://www.gnu.org/copyleft/gpl.html.
30
** Alternatively, this file may be used in accordance with the terms and
31
** conditions contained in a signed written agreement between you and Nokia.
40
****************************************************************************/
42
#include "qquicktextinput_p.h"
43
#include "qquicktextinput_p_p.h"
44
#include "qquickcanvas.h"
46
#include <private/qqmlglobal_p.h>
48
#include <QtCore/qcoreapplication.h>
49
#include <QtQml/qqmlinfo.h>
50
#include <QtGui/qevent.h>
51
#include <QTextBoundaryFinder>
52
#include "qquicktextnode_p.h"
53
#include <QtQuick/qsgsimplerectnode.h>
55
#include <QtGui/qstylehints.h>
56
#include <QtGui/qinputmethod.h>
58
#ifndef QT_NO_ACCESSIBILITY
59
#include "qaccessible.h"
64
DEFINE_BOOL_CONFIG_OPTION(qmlDisableDistanceField, QML_DISABLE_DISTANCEFIELD)
67
\qmlclass TextInput QQuickTextInput
68
\inqmlmodule QtQuick 2
69
\ingroup qml-basic-visual-elements
70
\brief The TextInput item displays an editable line of text.
73
The TextInput element displays a single line of editable plain text.
75
TextInput is used to accept a line of text input. Input constraints
76
can be placed on a TextInput item (for example, through a \l validator or \l inputMask),
77
and setting \l echoMode to an appropriate value enables TextInput to be used for
78
a password input field.
80
On Mac OS X, the Up/Down key bindings for Home/End are explicitly disabled.
81
If you want such bindings (on any platform), you will need to construct them in QML.
83
\sa TextEdit, Text, {declarative/text/textselection}{Text Selection example}
85
QQuickTextInput::QQuickTextInput(QQuickItem* parent)
86
: QQuickImplicitSizeItem(*(new QQuickTextInputPrivate), parent)
92
QQuickTextInput::~QQuickTextInput()
96
void QQuickTextInput::componentComplete()
100
QQuickImplicitSizeItem::componentComplete();
104
updateCursorRectangle();
105
if (d->cursorComponent && d->cursorComponent->isReady())
110
\qmlproperty string QtQuick2::TextInput::text
112
The text in the TextInput.
114
QString 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);
123
void QQuickTextInput::setText(const QString &s)
125
Q_D(QQuickTextInput);
130
d->internalSetText(s, -1, false);
134
\qmlproperty int QtQuick2::TextInput::length
136
Returns the total number of characters in the TextInput item.
138
If the TextInput has an inputMask the length will include mask characters and may differ
139
from the length of the string returned by the \l text property.
141
This property can be faster than querying the length the \l text property as it doesn't
142
require any copying or conversion of the TextInput's internal string data.
145
int QQuickTextInput::length() const
147
Q_D(const QQuickTextInput);
148
return d->m_text.length();
152
\qmlmethod string QtQuick2::TextInput::getText(int start, int end)
154
Returns the section of text that is between the \a start and \a end positions.
156
If the TextInput has an inputMask the length will include mask characters.
159
QString QQuickTextInput::getText(int start, int end) const
161
Q_D(const QQuickTextInput);
166
return d->m_text.mid(start, end - start);
169
QString QQuickTextInputPrivate::realText() const
171
QString res = m_maskData ? stripString(m_text) : m_text;
172
return (res.isNull() ? QString::fromLatin1("") : res);
176
\qmlproperty string QtQuick2::TextInput::font.family
178
Sets the family name of the font.
180
The family name is case insensitive and may optionally include a foundry name, e.g. "Helvetica [Cronyx]".
181
If the family is available from more than one foundry and the foundry isn't specified, an arbitrary foundry is chosen.
182
If the family isn't available a family will be set using the font matching algorithm.
186
\qmlproperty bool QtQuick2::TextInput::font.bold
188
Sets whether the font weight is bold.
192
\qmlproperty enumeration QtQuick2::TextInput::font.weight
194
Sets the font's weight.
196
The weight can be one of:
199
\li Font.Normal - the default
206
TextInput { text: "Hello"; font.weight: Font.DemiBold }
211
\qmlproperty bool QtQuick2::TextInput::font.italic
213
Sets whether the font has an italic style.
217
\qmlproperty bool QtQuick2::TextInput::font.underline
219
Sets whether the text is underlined.
223
\qmlproperty bool QtQuick2::TextInput::font.strikeout
225
Sets whether the font has a strikeout style.
229
\qmlproperty real QtQuick2::TextInput::font.pointSize
231
Sets the font size in points. The point size must be greater than zero.
235
\qmlproperty int QtQuick2::TextInput::font.pixelSize
237
Sets the font size in pixels.
239
Using this function makes the font device dependent.
240
Use \c pointSize to set the size of the font in a device independent manner.
244
\qmlproperty real QtQuick2::TextInput::font.letterSpacing
246
Sets the letter spacing for the font.
248
Letter spacing changes the default spacing between individual letters in the font.
249
A positive value increases the letter spacing by the corresponding pixels; a negative value decreases the spacing.
253
\qmlproperty real QtQuick2::TextInput::font.wordSpacing
255
Sets the word spacing for the font.
257
Word spacing changes the default spacing between individual words.
258
A positive value increases the word spacing by a corresponding amount of pixels,
259
while a negative value decreases the inter-word spacing accordingly.
263
\qmlproperty enumeration QtQuick2::TextInput::font.capitalization
265
Sets the capitalization for the text.
268
\li Font.MixedCase - This is the normal text rendering option where no capitalization change is applied.
269
\li Font.AllUppercase - This alters the text to be rendered in all uppercase type.
270
\li Font.AllLowercase - This alters the text to be rendered in all lowercase type.
271
\li Font.SmallCaps - This alters the text to be rendered in small-caps type.
272
\li Font.Capitalize - This alters the text to be rendered with the first character of each word as an uppercase character.
276
TextInput { text: "Hello"; font.capitalization: Font.AllLowercase }
280
QFont QQuickTextInput::font() const
282
Q_D(const QQuickTextInput);
283
return d->sourceFont;
286
void QQuickTextInput::setFont(const QFont &font)
288
Q_D(QQuickTextInput);
289
if (d->sourceFont == font)
292
d->sourceFont = font;
293
QFont oldFont = d->font;
295
if (d->font.pointSizeF() != -1) {
297
qreal size = qRound(d->font.pointSizeF()*2.0);
298
d->font.setPointSizeF(size/2.0);
300
if (oldFont != d->font) {
302
updateCursorRectangle();
303
updateInputMethod(Qt::ImCursorRectangle | Qt::ImFont);
305
emit fontChanged(d->sourceFont);
309
\qmlproperty color QtQuick2::TextInput::color
313
QColor QQuickTextInput::color() const
315
Q_D(const QQuickTextInput);
319
void QQuickTextInput::setColor(const QColor &c)
321
Q_D(QQuickTextInput);
324
d->textLayoutDirty = true;
325
d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
333
\qmlproperty color QtQuick2::TextInput::selectionColor
335
The text highlight color, used behind selections.
337
QColor QQuickTextInput::selectionColor() const
339
Q_D(const QQuickTextInput);
340
return d->selectionColor;
343
void QQuickTextInput::setSelectionColor(const QColor &color)
345
Q_D(QQuickTextInput);
346
if (d->selectionColor == color)
349
d->selectionColor = color;
350
if (d->hasSelectedText()) {
351
d->textLayoutDirty = true;
352
d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
355
emit selectionColorChanged();
358
\qmlproperty color QtQuick2::TextInput::selectedTextColor
360
The highlighted text color, used in selections.
362
QColor QQuickTextInput::selectedTextColor() const
364
Q_D(const QQuickTextInput);
365
return d->selectedTextColor;
368
void QQuickTextInput::setSelectedTextColor(const QColor &color)
370
Q_D(QQuickTextInput);
371
if (d->selectedTextColor == color)
374
d->selectedTextColor = color;
375
if (d->hasSelectedText()) {
376
d->textLayoutDirty = true;
377
d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
380
emit selectedTextColorChanged();
384
\qmlproperty enumeration QtQuick2::TextInput::horizontalAlignment
385
\qmlproperty enumeration QtQuick2::TextInput::effectiveHorizontalAlignment
386
\qmlproperty enumeration QtQuick2::TextInput::verticalAlignment
388
Sets the horizontal alignment of the text within the TextInput item's
389
width and height. By default, the text alignment follows the natural alignment
390
of the text, for example text that is read from left to right will be aligned to
393
TextInput does not have vertical alignment, as the natural height is
394
exactly the height of the single line of text. If you set the height
395
manually to something larger, TextInput will always be top aligned
396
vertically. You can use anchors to align it however you want within
399
The valid values for \c horizontalAlignment are \c TextInput.AlignLeft, \c TextInput.AlignRight and
400
\c TextInput.AlignHCenter.
402
Valid values for \c verticalAlignment are \c TextInput.AlignTop (default),
403
\c TextInput.AlignBottom \c TextInput.AlignVCenter.
405
When using the attached property LayoutMirroring::enabled to mirror application
406
layouts, the horizontal alignment of text will also be mirrored. However, the property
407
\c horizontalAlignment will remain unchanged. To query the effective horizontal alignment
408
of TextInput, use the read-only property \c effectiveHorizontalAlignment.
410
QQuickTextInput::HAlignment QQuickTextInput::hAlign() const
412
Q_D(const QQuickTextInput);
416
void QQuickTextInput::setHAlign(HAlignment align)
418
Q_D(QQuickTextInput);
419
bool forceAlign = d->hAlignImplicit && d->effectiveLayoutMirror;
420
d->hAlignImplicit = false;
421
if (d->setHAlign(align, forceAlign) && isComponentComplete()) {
423
updateCursorRectangle();
427
void QQuickTextInput::resetHAlign()
429
Q_D(QQuickTextInput);
430
d->hAlignImplicit = true;
431
if (d->determineHorizontalAlignment() && isComponentComplete()) {
433
updateCursorRectangle();
437
QQuickTextInput::HAlignment QQuickTextInput::effectiveHAlign() const
439
Q_D(const QQuickTextInput);
440
QQuickTextInput::HAlignment effectiveAlignment = d->hAlign;
441
if (!d->hAlignImplicit && d->effectiveLayoutMirror) {
443
case QQuickTextInput::AlignLeft:
444
effectiveAlignment = QQuickTextInput::AlignRight;
446
case QQuickTextInput::AlignRight:
447
effectiveAlignment = QQuickTextInput::AlignLeft;
453
return effectiveAlignment;
456
bool QQuickTextInputPrivate::setHAlign(QQuickTextInput::HAlignment alignment, bool forceAlign)
458
Q_Q(QQuickTextInput);
459
if ((hAlign != alignment || forceAlign) && alignment <= QQuickTextInput::AlignHCenter) { // justify not supported
460
QQuickTextInput::HAlignment oldEffectiveHAlign = q->effectiveHAlign();
462
emit q->horizontalAlignmentChanged(alignment);
463
if (oldEffectiveHAlign != q->effectiveHAlign())
464
emit q->effectiveHorizontalAlignmentChanged();
470
bool QQuickTextInputPrivate::determineHorizontalAlignment()
472
if (hAlignImplicit) {
473
// if no explicit alignment has been set, follow the natural layout direction of the text
474
QString text = q_func()->text();
476
text = m_textLayout.preeditAreaText();
477
bool isRightToLeft = text.isEmpty() ? qApp->inputMethod()->inputDirection() == Qt::RightToLeft
478
: text.isRightToLeft();
479
return setHAlign(isRightToLeft ? QQuickTextInput::AlignRight : QQuickTextInput::AlignLeft);
484
QQuickTextInput::VAlignment QQuickTextInput::vAlign() const
486
Q_D(const QQuickTextInput);
490
void QQuickTextInput::setVAlign(QQuickTextInput::VAlignment alignment)
492
Q_D(QQuickTextInput);
493
if (alignment == d->vAlign)
495
d->vAlign = alignment;
496
emit verticalAlignmentChanged(d->vAlign);
497
if (isComponentComplete()) {
498
updateCursorRectangle();
503
\qmlproperty enumeration QtQuick2::TextInput::wrapMode
505
Set this property to wrap the text to the TextInput item's width.
506
The text will only wrap if an explicit width has been set.
509
\li TextInput.NoWrap - no wrapping will be performed. If the text contains insufficient newlines, then implicitWidth will exceed a set width.
510
\li TextInput.WordWrap - wrapping is done on word boundaries only. If a word is too long, implicitWidth will exceed a set width.
511
\li TextInput.WrapAnywhere - wrapping is done at any point on a line, even if it occurs in the middle of a word.
512
\li TextInput.Wrap - if possible, wrapping occurs at a word boundary; otherwise it will occur at the appropriate point on the line, even in the middle of a word.
515
The default is TextInput.NoWrap. If you set a width, consider using TextInput.Wrap.
517
QQuickTextInput::WrapMode QQuickTextInput::wrapMode() const
519
Q_D(const QQuickTextInput);
523
void QQuickTextInput::setWrapMode(WrapMode mode)
525
Q_D(QQuickTextInput);
526
if (mode == d->wrapMode)
530
updateCursorRectangle();
531
emit wrapModeChanged();
534
void QQuickTextInputPrivate::mirrorChange()
536
Q_Q(QQuickTextInput);
537
if (q->isComponentComplete()) {
538
if (!hAlignImplicit && (hAlign == QQuickTextInput::AlignRight || hAlign == QQuickTextInput::AlignLeft)) {
539
q->updateCursorRectangle();
540
emit q->effectiveHorizontalAlignmentChanged();
546
\qmlproperty bool QtQuick2::TextInput::readOnly
548
Sets whether user input can modify the contents of the TextInput.
550
If readOnly is set to true, then user input will not affect the text
551
property. Any bindings or attempts to set the text property will still
554
bool QQuickTextInput::isReadOnly() const
556
Q_D(const QQuickTextInput);
557
return d->m_readOnly;
560
void QQuickTextInput::setReadOnly(bool ro)
562
Q_D(QQuickTextInput);
563
if (d->m_readOnly == ro)
566
setFlag(QQuickItem::ItemAcceptsInputMethod, !ro);
569
d->setCursorPosition(d->end());
570
updateInputMethod(Qt::ImEnabled);
572
d->emitUndoRedoChanged();
573
emit readOnlyChanged(ro);
577
\qmlproperty int QtQuick2::TextInput::maximumLength
578
The maximum permitted length of the text in the TextInput.
580
If the text is too long, it is truncated at the limit.
582
By default, this property contains a value of 32767.
584
int QQuickTextInput::maxLength() const
586
Q_D(const QQuickTextInput);
587
return d->m_maxLength;
590
void QQuickTextInput::setMaxLength(int ml)
592
Q_D(QQuickTextInput);
593
if (d->m_maxLength == ml || d->m_maskData)
597
d->internalSetText(d->m_text, -1, false);
599
emit maximumLengthChanged(ml);
603
\qmlproperty bool QtQuick2::TextInput::cursorVisible
604
Set to true when the TextInput shows a cursor.
606
This property is set and unset when the TextInput gets active focus, so that other
607
properties can be bound to whether the cursor is currently showing. As it
608
gets set and unset automatically, when you set the value yourself you must
609
keep in mind that your value may be overwritten.
611
It can be set directly in script, for example if a KeyProxy might
612
forward keys to it and you desire it to look active when this happens
613
(but without actually giving it active focus).
615
It should not be set directly on the element, like in the below QML,
616
as the specified value will be overridden an lost on focus changes.
625
In the above snippet the cursor will still become visible when the
626
TextInput gains active focus.
628
bool QQuickTextInput::isCursorVisible() const
630
Q_D(const QQuickTextInput);
631
return d->cursorVisible;
634
void QQuickTextInput::setCursorVisible(bool on)
636
Q_D(QQuickTextInput);
637
if (d->cursorVisible == on)
639
d->cursorVisible = on;
640
d->setCursorBlinkPeriod(on ? qApp->styleHints()->cursorFlashTime() : 0);
641
d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
643
emit cursorVisibleChanged(d->cursorVisible);
647
\qmlproperty int QtQuick2::TextInput::cursorPosition
648
The position of the cursor in the TextInput.
650
int QQuickTextInput::cursorPosition() const
652
Q_D(const QQuickTextInput);
656
void QQuickTextInput::setCursorPosition(int cp)
658
Q_D(QQuickTextInput);
659
if (cp < 0 || cp > text().length())
665
\qmlproperty rectangle QtQuick2::TextInput::cursorRectangle
667
The rectangle where the standard text cursor is rendered within the text input. Read only.
669
The position and height of a custom cursorDelegate are updated to follow the cursorRectangle
670
automatically when it changes. The width of the delegate is unaffected by changes in the
674
QRectF QQuickTextInput::cursorRectangle() const
676
Q_D(const QQuickTextInput);
678
int c = d->m_cursor + d->m_preeditCursor;
679
if (d->m_echoMode == NoEcho)
681
QTextLine l = d->m_textLayout.lineForTextPosition(c);
684
return QRectF(l.cursorToX(c) - d->hscroll, l.y() - d->vscroll, 1, l.height());
688
\qmlproperty int QtQuick2::TextInput::selectionStart
690
The cursor position before the first character in the current selection.
692
This property is read-only. To change the selection, use select(start,end),
693
selectAll(), or selectWord().
695
\sa selectionEnd, cursorPosition, selectedText
697
int QQuickTextInput::selectionStart() const
699
Q_D(const QQuickTextInput);
700
return d->lastSelectionStart;
703
\qmlproperty int QtQuick2::TextInput::selectionEnd
705
The cursor position after the last character in the current selection.
707
This property is read-only. To change the selection, use select(start,end),
708
selectAll(), or selectWord().
710
\sa selectionStart, cursorPosition, selectedText
712
int QQuickTextInput::selectionEnd() const
714
Q_D(const QQuickTextInput);
715
return d->lastSelectionEnd;
718
\qmlmethod void QtQuick2::TextInput::select(int start, int end)
720
Causes the text from \a start to \a end to be selected.
722
If either start or end is out of range, the selection is not changed.
724
After calling this, selectionStart will become the lesser
725
and selectionEnd will become the greater (regardless of the order passed
728
\sa selectionStart, selectionEnd
730
void QQuickTextInput::select(int start, int end)
732
Q_D(QQuickTextInput);
733
if (start < 0 || end < 0 || start > d->m_text.length() || end > d->m_text.length())
735
d->setSelection(start, end-start);
739
\qmlproperty string QtQuick2::TextInput::selectedText
741
This read-only property provides the text currently selected in the
744
It is equivalent to the following snippet, but is faster and easier
748
myTextInput.text.toString().substring(myTextInput.selectionStart,
749
myTextInput.selectionEnd);
752
QString QQuickTextInput::selectedText() const
754
Q_D(const QQuickTextInput);
755
return d->selectedText();
759
\qmlproperty bool QtQuick2::TextInput::activeFocusOnPress
761
Whether the TextInput should gain active focus on a mouse press. By default this is
764
bool QQuickTextInput::focusOnPress() const
766
Q_D(const QQuickTextInput);
767
return d->focusOnPress;
770
void QQuickTextInput::setFocusOnPress(bool b)
772
Q_D(QQuickTextInput);
773
if (d->focusOnPress == b)
778
emit activeFocusOnPressChanged(d->focusOnPress);
781
\qmlproperty bool QtQuick2::TextInput::autoScroll
783
Whether the TextInput should scroll when the text is longer than the width. By default this is
786
bool QQuickTextInput::autoScroll() const
788
Q_D(const QQuickTextInput);
789
return d->autoScroll;
792
void QQuickTextInput::setAutoScroll(bool b)
794
Q_D(QQuickTextInput);
795
if (d->autoScroll == b)
799
//We need to repaint so that the scrolling is taking into account.
800
updateCursorRectangle();
801
emit autoScrollChanged(d->autoScroll);
804
#ifndef QT_NO_VALIDATOR
807
\qmlclass IntValidator QIntValidator
808
\inqmlmodule QtQuick 2
809
\ingroup qml-basic-visual-elements
811
This element provides a validator for integer values.
813
If no \l locale is set IntValidator uses the \l {QLocale::setDefault()}{default locale} to
814
interpret the number and will accept locale specific digits, group separators, and positive
815
and negative signs. In addition, IntValidator is always guaranteed to accept a number
816
formatted according to the "C" locale.
820
QQuickIntValidator::QQuickIntValidator(QObject *parent)
821
: QIntValidator(parent)
826
\qmlproperty string QtQuick2::IntValidator::locale
828
This property holds the name of the locale used to interpret the number.
833
QString QQuickIntValidator::localeName() const
835
return locale().name();
838
void QQuickIntValidator::setLocaleName(const QString &name)
840
if (locale().name() != name) {
841
setLocale(QLocale(name));
842
emit localeNameChanged();
846
void QQuickIntValidator::resetLocaleName()
848
QLocale defaultLocale;
849
if (locale() != defaultLocale) {
850
setLocale(defaultLocale);
851
emit localeNameChanged();
856
\qmlproperty int QtQuick2::IntValidator::top
858
This property holds the validator's highest acceptable value.
859
By default, this property's value is derived from the highest signed integer available (typically 2147483647).
862
\qmlproperty int QtQuick2::IntValidator::bottom
864
This property holds the validator's lowest acceptable value.
865
By default, this property's value is derived from the lowest signed integer available (typically -2147483647).
869
\qmlclass DoubleValidator QDoubleValidator
870
\inqmlmodule QtQuick 2
871
\ingroup qml-basic-visual-elements
873
This element provides a validator for non-integer numbers.
875
Input is accepted if it contains a double that is within the valid range
876
and is in the correct format.
878
Input is accepected but invalid if it contains a double that is outside
879
the range or is in the wrong format; e.g. with too many digits after the
880
decimal point or is empty.
882
Input is rejected if it is not a double.
884
Note: If the valid range consists of just positive doubles (e.g. 0.0 to
885
100.0) and input is a negative double then it is rejected. If \l notation
886
is set to DoubleValidator.StandardNotation, and the input contains more
887
digits before the decimal point than a double in the valid range may have,
888
it is also rejected. If \l notation is DoubleValidator.ScientificNotation,
889
and the input is not in the valid range, it is accecpted but invalid. The
890
value may yet become valid by changing the exponent.
893
QQuickDoubleValidator::QQuickDoubleValidator(QObject *parent)
894
: QDoubleValidator(parent)
899
\qmlproperty string QtQuick2::DoubleValidator::locale
901
This property holds the name of the locale used to interpret the number.
906
QString QQuickDoubleValidator::localeName() const
908
return locale().name();
911
void QQuickDoubleValidator::setLocaleName(const QString &name)
913
if (locale().name() != name) {
914
setLocale(QLocale(name));
915
emit localeNameChanged();
919
void QQuickDoubleValidator::resetLocaleName()
921
QLocale defaultLocale;
922
if (locale() != defaultLocale) {
923
setLocale(defaultLocale);
924
emit localeNameChanged();
929
\qmlproperty real QtQuick2::DoubleValidator::top
931
This property holds the validator's maximum acceptable value.
932
By default, this property contains a value of infinity.
935
\qmlproperty real QtQuick2::DoubleValidator::bottom
937
This property holds the validator's minimum acceptable value.
938
By default, this property contains a value of -infinity.
941
\qmlproperty int QtQuick2::DoubleValidator::decimals
943
This property holds the validator's maximum number of digits after the decimal point.
944
By default, this property contains a value of 1000.
947
\qmlproperty enumeration QtQuick2::DoubleValidator::notation
948
This property holds the notation of how a string can describe a number.
950
The possible values for this property are:
953
\li DoubleValidator.StandardNotation
954
\li DoubleValidator.ScientificNotation (default)
957
If this property is set to DoubleValidator.ScientificNotation, the written number may have an exponent part (e.g. 1.5E-2).
961
\qmlclass RegExpValidator QRegExpValidator
962
\inqmlmodule QtQuick 2
963
\ingroup qml-basic-visual-elements
965
This element provides a validator, which counts as valid any string which
966
matches a specified regular expression.
969
\qmlproperty regExp QtQuick2::RegExpValidator::regExp
971
This property holds the regular expression used for validation.
973
Note that this property should be a regular expression in JS syntax, e.g /a/ for the regular expression
976
By default, this property contains a regular expression with the pattern .* that matches any string.
980
\qmlproperty Validator QtQuick2::TextInput::validator
982
Allows you to set a validator on the TextInput. When a validator is set
983
the TextInput will only accept input which leaves the text property in
984
an acceptable or intermediate state. The accepted signal will only be sent
985
if the text is in an acceptable state when enter is pressed.
987
Currently supported validators are IntValidator, DoubleValidator and
988
RegExpValidator. An example of using validators is shown below, which allows
989
input of integers between 11 and 31 into the text input:
994
validator: IntValidator{bottom: 11; top: 31;}
999
\sa acceptableInput, inputMask
1002
QValidator* QQuickTextInput::validator() const
1004
Q_D(const QQuickTextInput);
1005
return d->m_validator;
1008
void QQuickTextInput::setValidator(QValidator* v)
1010
Q_D(QQuickTextInput);
1011
if (d->m_validator == v)
1016
if (isComponentComplete())
1019
emit validatorChanged();
1022
#endif // QT_NO_VALIDATOR
1024
void QQuickTextInputPrivate::checkIsValid()
1026
Q_Q(QQuickTextInput);
1028
ValidatorState state = hasAcceptableInput(m_text);
1029
m_validInput = state != InvalidInput;
1030
if (state != AcceptableInput) {
1031
if (m_acceptableInput) {
1032
m_acceptableInput = false;
1033
emit q->acceptableInputChanged();
1035
} else if (!m_acceptableInput) {
1036
m_acceptableInput = true;
1037
emit q->acceptableInputChanged();
1042
\qmlproperty string QtQuick2::TextInput::inputMask
1044
Allows you to set an input mask on the TextInput, restricting the allowable
1045
text inputs. See QLineEdit::inputMask for further details, as the exact
1046
same mask strings are used by TextInput.
1048
\sa acceptableInput, validator
1050
QString QQuickTextInput::inputMask() const
1052
Q_D(const QQuickTextInput);
1053
return d->inputMask();
1056
void QQuickTextInput::setInputMask(const QString &im)
1058
Q_D(QQuickTextInput);
1059
if (d->inputMask() == im)
1062
d->setInputMask(im);
1063
emit inputMaskChanged(d->inputMask());
1067
\qmlproperty bool QtQuick2::TextInput::acceptableInput
1069
This property is always true unless a validator or input mask has been set.
1070
If a validator or input mask has been set, this property will only be true
1071
if the current text is acceptable to the validator or input mask as a final
1072
string (not as an intermediate string).
1074
bool QQuickTextInput::hasAcceptableInput() const
1076
Q_D(const QQuickTextInput);
1077
return d->hasAcceptableInput(d->m_text) == QQuickTextInputPrivate::AcceptableInput;
1081
\qmlsignal QtQuick2::TextInput::onAccepted()
1083
This handler is called when the Return or Enter key is pressed.
1084
Note that if there is a \l validator or \l inputMask set on the text
1085
input, the handler will only be emitted if the input is in an acceptable
1089
Qt::InputMethodHints QQuickTextInputPrivate::effectiveInputMethodHints() const
1091
Qt::InputMethodHints hints = inputMethodHints;
1092
if (m_echoMode == QQuickTextInput::Password || m_echoMode == QQuickTextInput::NoEcho)
1093
hints |= Qt::ImhHiddenText;
1094
else if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit)
1095
hints &= ~Qt::ImhHiddenText;
1096
if (m_echoMode != QQuickTextInput::Normal)
1097
hints |= (Qt::ImhNoAutoUppercase | Qt::ImhNoPredictiveText | Qt::ImhSensitiveData);
1101
\qmlproperty enumeration QtQuick2::TextInput::echoMode
1103
Specifies how the text should be displayed in the TextInput.
1105
\li TextInput.Normal - Displays the text as it is. (Default)
1106
\li TextInput.Password - Displays asterisks instead of characters.
1107
\li TextInput.NoEcho - Displays nothing.
1108
\li TextInput.PasswordEchoOnEdit - Displays characters as they are entered
1109
while editing, otherwise displays asterisks.
1112
QQuickTextInput::EchoMode QQuickTextInput::echoMode() const
1114
Q_D(const QQuickTextInput);
1115
return QQuickTextInput::EchoMode(d->m_echoMode);
1118
void QQuickTextInput::setEchoMode(QQuickTextInput::EchoMode echo)
1120
Q_D(QQuickTextInput);
1121
if (echoMode() == echo)
1123
d->cancelPasswordEchoTimer();
1124
d->m_echoMode = echo;
1125
d->m_passwordEchoEditing = false;
1126
updateInputMethod(Qt::ImHints);
1127
d->updateDisplayText();
1128
updateCursorRectangle();
1130
emit echoModeChanged(echoMode());
1134
\qmlproperty enumeration QtQuick2::TextInput::inputMethodHints
1136
Provides hints to the input method about the expected content of the text input and how it
1139
The value is a bit-wise combination of flags, or Qt.ImhNone if no hints are set.
1141
Flags that alter behaviour are:
1144
\li Qt.ImhHiddenText - Characters should be hidden, as is typically used when entering passwords.
1145
This is automatically set when setting echoMode to \c TextInput.Password.
1146
\li Qt.ImhSensitiveData - Typed text should not be stored by the active input method
1147
in any persistent storage like predictive user dictionary.
1148
\li Qt.ImhNoAutoUppercase - The input method should not try to automatically switch to upper case
1149
when a sentence ends.
1150
\li Qt.ImhPreferNumbers - Numbers are preferred (but not required).
1151
\li Qt.ImhPreferUppercase - Upper case letters are preferred (but not required).
1152
\li Qt.ImhPreferLowercase - Lower case letters are preferred (but not required).
1153
\li Qt.ImhNoPredictiveText - Do not use predictive text (i.e. dictionary lookup) while typing.
1155
\li Qt.ImhDate - The text editor functions as a date field.
1156
\li Qt.ImhTime - The text editor functions as a time field.
1159
Flags that restrict input (exclusive flags) are:
1162
\li Qt.ImhDigitsOnly - Only digits are allowed.
1163
\li Qt.ImhFormattedNumbersOnly - Only number input is allowed. This includes decimal point and minus sign.
1164
\li Qt.ImhUppercaseOnly - Only upper case letter input is allowed.
1165
\li Qt.ImhLowercaseOnly - Only lower case letter input is allowed.
1166
\li Qt.ImhDialableCharactersOnly - Only characters suitable for phone dialing are allowed.
1167
\li Qt.ImhEmailCharactersOnly - Only characters suitable for email addresses are allowed.
1168
\li Qt.ImhUrlCharactersOnly - Only characters suitable for URLs are allowed.
1174
\li Qt.ImhExclusiveInputMask - This mask yields nonzero if any of the exclusive flags are used.
1178
Qt::InputMethodHints QQuickTextInput::inputMethodHints() const
1180
Q_D(const QQuickTextInput);
1181
return d->inputMethodHints;
1184
void QQuickTextInput::setInputMethodHints(Qt::InputMethodHints hints)
1186
Q_D(QQuickTextInput);
1188
if (hints == d->inputMethodHints)
1191
d->inputMethodHints = hints;
1192
updateInputMethod(Qt::ImHints);
1193
emit inputMethodHintsChanged();
1197
\qmlproperty Component QtQuick2::TextInput::cursorDelegate
1198
The delegate for the cursor in the TextInput.
1200
If you set a cursorDelegate for a TextInput, this delegate will be used for
1201
drawing the cursor instead of the standard cursor. An instance of the
1202
delegate will be created and managed by the TextInput when a cursor is
1203
needed, and the x property of delegate instance will be set so as
1204
to be one pixel before the top left of the current character.
1206
Note that the root item of the delegate component must be a QQuickItem or
1207
QQuickItem derived item.
1209
QQmlComponent* QQuickTextInput::cursorDelegate() const
1211
Q_D(const QQuickTextInput);
1212
return d->cursorComponent;
1215
void QQuickTextInput::setCursorDelegate(QQmlComponent* c)
1217
Q_D(QQuickTextInput);
1218
if (d->cursorComponent == c)
1221
d->cursorComponent = c;
1223
//note that the components are owned by something else
1224
delete d->cursorItem;
1227
d->startCreatingCursor();
1230
emit cursorDelegateChanged();
1233
void QQuickTextInputPrivate::startCreatingCursor()
1235
Q_Q(QQuickTextInput);
1236
if (cursorComponent->isReady()) {
1238
} else if (cursorComponent->isLoading()) {
1239
q->connect(cursorComponent, SIGNAL(statusChanged(int)),
1240
q, SLOT(createCursor()));
1242
qmlInfo(q, cursorComponent->errors()) << QQuickTextInput::tr("Could not load cursor delegate");
1246
void QQuickTextInput::createCursor()
1248
Q_D(QQuickTextInput);
1249
if (!isComponentComplete())
1252
if (d->cursorComponent->isError()) {
1253
qmlInfo(this, d->cursorComponent->errors()) << tr("Could not load cursor delegate");
1257
if (!d->cursorComponent->isReady())
1261
delete d->cursorItem;
1262
QQmlContext *creationContext = d->cursorComponent->creationContext();
1263
QObject *object = d->cursorComponent->create(creationContext ? creationContext : qmlContext(this));
1264
d->cursorItem = qobject_cast<QQuickItem*>(object);
1265
if (!d->cursorItem) {
1267
qmlInfo(this, d->cursorComponent->errors()) << tr("Could not instantiate cursor delegate");
1271
QRectF r = cursorRectangle();
1273
QQml_setParent_noEvent(d->cursorItem, this);
1274
d->cursorItem->setParentItem(this);
1275
d->cursorItem->setPos(r.topLeft());
1276
d->cursorItem->setHeight(r.height());
1280
\qmlmethod rect QtQuick2::TextInput::positionToRectangle(int pos)
1282
This function takes a character position and returns the rectangle that the
1283
cursor would occupy, if it was placed at that character position.
1285
This is similar to setting the cursorPosition, and then querying the cursor
1286
rectangle, but the cursorPosition is not changed.
1288
QRectF QQuickTextInput::positionToRectangle(int pos) const
1290
Q_D(const QQuickTextInput);
1291
if (d->m_echoMode == NoEcho)
1293
else if (pos > d->m_cursor)
1294
pos += d->preeditAreaText().length();
1295
QTextLine l = d->m_textLayout.lineForTextPosition(pos);
1297
? QRectF(l.cursorToX(pos) - d->hscroll, l.y() - d->vscroll, 1, l.height())
1302
\qmlmethod int QtQuick2::TextInput::positionAt(real x, real y, CursorPosition position = CursorBetweenCharacters)
1304
This function returns the character position at
1305
x and y pixels from the top left of the textInput. Position 0 is before the
1306
first character, position 1 is after the first character but before the second,
1307
and so on until position text.length, which is after all characters.
1309
This means that for all x values before the first character this function returns 0,
1310
and for all x values after the last character this function returns text.length. If
1311
the y value is above the text the position will be that of the nearest character on
1312
the first line line and if it is below the text the position of the nearest character
1313
on the last line will be returned.
1315
The cursor position type specifies how the cursor position should be resolved.
1318
\li TextInput.CursorBetweenCharacters - Returns the position between characters that is nearest x.
1319
\li TextInput.CursorOnCharacter - Returns the position before the character that is nearest x.
1323
void QQuickTextInput::positionAt(QQmlV8Function *args) const
1325
Q_D(const QQuickTextInput);
1329
QTextLine::CursorPosition position = QTextLine::CursorBetweenCharacters;
1331
if (args->Length() < 1)
1335
v8::Local<v8::Value> arg = (*args)[i];
1336
x = arg->NumberValue();
1338
if (++i < args->Length()) {
1340
y = arg->NumberValue();
1343
if (++i < args->Length()) {
1345
position = QTextLine::CursorPosition(arg->Int32Value());
1348
int pos = d->positionAt(x, y, position);
1349
const int cursor = d->m_cursor;
1351
const int preeditLength = d->preeditAreaText().length();
1352
pos = pos > cursor + preeditLength
1353
? pos - preeditLength
1356
args->returnValue(v8::Int32::New(pos));
1359
int QQuickTextInputPrivate::positionAt(qreal x, qreal y, QTextLine::CursorPosition position) const
1363
QTextLine line = m_textLayout.lineAt(0);
1364
for (int i = 1; i < m_textLayout.lineCount(); ++i) {
1365
QTextLine nextLine = m_textLayout.lineAt(i);
1367
if (y < (line.rect().bottom() + nextLine.y()) / 2)
1371
return line.isValid() ? line.xToCursor(x, position) : 0;
1374
void QQuickTextInput::keyPressEvent(QKeyEvent* ev)
1376
Q_D(QQuickTextInput);
1377
// Don't allow MacOSX up/down support, and we don't allow a completer.
1378
bool ignore = (ev->key() == Qt::Key_Up || ev->key() == Qt::Key_Down) && ev->modifiers() == Qt::NoModifier;
1379
if (!ignore && (d->lastSelectionStart == d->lastSelectionEnd) && (ev->key() == Qt::Key_Right || ev->key() == Qt::Key_Left)) {
1380
// Ignore when moving off the end unless there is a selection,
1381
// because then moving will do something (deselect).
1382
int cursorPosition = d->m_cursor;
1383
if (cursorPosition == 0)
1384
ignore = ev->key() == (d->layoutDirection() == Qt::LeftToRight ? Qt::Key_Left : Qt::Key_Right);
1385
if (cursorPosition == text().length())
1386
ignore = ev->key() == (d->layoutDirection() == Qt::LeftToRight ? Qt::Key_Right : Qt::Key_Left);
1391
d->processKeyEvent(ev);
1393
if (!ev->isAccepted())
1394
QQuickImplicitSizeItem::keyPressEvent(ev);
1397
void QQuickTextInput::inputMethodEvent(QInputMethodEvent *ev)
1399
Q_D(QQuickTextInput);
1400
const bool wasComposing = d->hasImState;
1401
if (d->m_readOnly) {
1404
d->processInputMethodEvent(ev);
1406
if (!ev->isAccepted())
1407
QQuickImplicitSizeItem::inputMethodEvent(ev);
1409
if (wasComposing != d->hasImState)
1410
emit inputMethodComposingChanged();
1413
void QQuickTextInput::mouseDoubleClickEvent(QMouseEvent *event)
1415
Q_D(QQuickTextInput);
1417
if (d->selectByMouse && event->button() == Qt::LeftButton) {
1419
int cursor = d->positionAt(event->localPos());
1420
d->selectWordAtPos(cursor);
1421
event->setAccepted(true);
1422
if (!d->hasPendingTripleClick()) {
1423
d->tripleClickStartPoint = event->localPos();
1424
d->tripleClickTimer.start();
1427
if (d->sendMouseEventToInputContext(event))
1429
QQuickImplicitSizeItem::mouseDoubleClickEvent(event);
1433
void QQuickTextInput::mousePressEvent(QMouseEvent *event)
1435
Q_D(QQuickTextInput);
1437
d->pressPos = event->localPos();
1439
if (d->sendMouseEventToInputContext(event))
1442
if (d->selectByMouse) {
1443
setKeepMouseGrab(false);
1444
d->selectPressed = true;
1445
QPointF distanceVector = d->pressPos - d->tripleClickStartPoint;
1446
if (d->hasPendingTripleClick()
1447
&& distanceVector.manhattanLength() < qApp->styleHints()->startDragDistance()) {
1448
event->setAccepted(true);
1454
bool mark = (event->modifiers() & Qt::ShiftModifier) && d->selectByMouse;
1455
int cursor = d->positionAt(event->localPos());
1456
d->moveCursor(cursor, mark);
1458
if (d->focusOnPress) {
1459
bool hadActiveFocus = hasActiveFocus();
1461
// re-open input panel on press if already focused
1462
if (hasActiveFocus() && hadActiveFocus && !d->m_readOnly)
1463
openSoftwareInputPanel();
1466
event->setAccepted(true);
1469
void QQuickTextInput::mouseMoveEvent(QMouseEvent *event)
1471
Q_D(QQuickTextInput);
1473
if (d->selectPressed) {
1474
if (qAbs(int(event->localPos().x() - d->pressPos.x())) > qApp->styleHints()->startDragDistance())
1475
setKeepMouseGrab(true);
1477
if (d->composeMode()) {
1479
int startPos = d->positionAt(d->pressPos);
1480
int currentPos = d->positionAt(event->localPos());
1481
if (startPos != currentPos)
1482
d->setSelection(startPos, currentPos - startPos);
1484
moveCursorSelection(d->positionAt(event->localPos()), d->mouseSelectionMode);
1486
event->setAccepted(true);
1488
QQuickImplicitSizeItem::mouseMoveEvent(event);
1492
void QQuickTextInput::mouseReleaseEvent(QMouseEvent *event)
1494
Q_D(QQuickTextInput);
1495
if (d->sendMouseEventToInputContext(event))
1497
if (d->selectPressed) {
1498
d->selectPressed = false;
1499
setKeepMouseGrab(false);
1501
#ifndef QT_NO_CLIPBOARD
1502
if (QGuiApplication::clipboard()->supportsSelection()) {
1503
if (event->button() == Qt::LeftButton) {
1504
d->copy(QClipboard::Selection);
1505
} else if (!d->m_readOnly && event->button() == Qt::MidButton) {
1507
d->insert(QGuiApplication::clipboard()->text(QClipboard::Selection));
1511
if (!event->isAccepted())
1512
QQuickImplicitSizeItem::mouseReleaseEvent(event);
1515
bool QQuickTextInputPrivate::sendMouseEventToInputContext(QMouseEvent *event)
1517
#if !defined QT_NO_IM
1518
if (composeMode()) {
1519
int tmp_cursor = positionAt(event->localPos());
1520
int mousePos = tmp_cursor - m_cursor;
1521
if (mousePos >= 0 && mousePos <= m_textLayout.preeditAreaText().length()) {
1522
if (event->type() == QEvent::MouseButtonRelease) {
1523
qApp->inputMethod()->invokeAction(QInputMethod::Click, mousePos);
1536
void QQuickTextInput::mouseUngrabEvent()
1538
Q_D(QQuickTextInput);
1539
d->selectPressed = false;
1540
setKeepMouseGrab(false);
1543
bool QQuickTextInput::event(QEvent* ev)
1545
#ifndef QT_NO_SHORTCUT
1546
Q_D(QQuickTextInput);
1547
if (ev->type() == QEvent::ShortcutOverride) {
1550
QKeyEvent* ke = static_cast<QKeyEvent*>(ev);
1551
if (ke == QKeySequence::Copy
1552
|| ke == QKeySequence::Paste
1553
|| ke == QKeySequence::Cut
1554
|| ke == QKeySequence::Redo
1555
|| ke == QKeySequence::Undo
1556
|| ke == QKeySequence::MoveToNextWord
1557
|| ke == QKeySequence::MoveToPreviousWord
1558
|| ke == QKeySequence::MoveToStartOfDocument
1559
|| ke == QKeySequence::MoveToEndOfDocument
1560
|| ke == QKeySequence::SelectNextWord
1561
|| ke == QKeySequence::SelectPreviousWord
1562
|| ke == QKeySequence::SelectStartOfLine
1563
|| ke == QKeySequence::SelectEndOfLine
1564
|| ke == QKeySequence::SelectStartOfBlock
1565
|| ke == QKeySequence::SelectEndOfBlock
1566
|| ke == QKeySequence::SelectStartOfDocument
1567
|| ke == QKeySequence::SelectAll
1568
|| ke == QKeySequence::SelectEndOfDocument) {
1570
} else if (ke->modifiers() == Qt::NoModifier || ke->modifiers() == Qt::ShiftModifier
1571
|| ke->modifiers() == Qt::KeypadModifier) {
1572
if (ke->key() < Qt::Key_Escape) {
1576
switch (ke->key()) {
1577
case Qt::Key_Delete:
1580
case Qt::Key_Backspace:
1592
return QQuickImplicitSizeItem::event(ev);
1595
void QQuickTextInput::geometryChanged(const QRectF &newGeometry,
1596
const QRectF &oldGeometry)
1598
Q_D(QQuickTextInput);
1600
if (newGeometry.width() != oldGeometry.width() && d->wrapMode != NoWrap)
1602
updateCursorRectangle();
1604
QQuickImplicitSizeItem::geometryChanged(newGeometry, oldGeometry);
1607
void QQuickTextInputPrivate::updateHorizontalScroll()
1609
Q_Q(QQuickTextInput);
1610
QTextLine currentLine = m_textLayout.lineForTextPosition(m_cursor + m_preeditCursor);
1611
const int preeditLength = m_textLayout.preeditAreaText().length();
1612
const qreal width = qMax<qreal>(0, q->width());
1614
qreal widthUsed = 0;
1615
if (currentLine.isValid()) {
1616
cix = currentLine.cursorToX(m_cursor + preeditLength);
1617
const qreal cursorWidth = cix >= 0 ? cix : width - cix;
1618
widthUsed = qMax(currentLine.naturalTextWidth(), cursorWidth);
1620
int previousScroll = hscroll;
1622
if (!autoScroll || widthUsed <= width || m_echoMode == QQuickTextInput::NoEcho) {
1625
Q_ASSERT(currentLine.isValid());
1626
if (cix - hscroll >= width) {
1627
// text doesn't fit, cursor is to the right of br (scroll right)
1628
hscroll = cix - width;
1629
} else if (cix - hscroll < 0 && hscroll < widthUsed) {
1630
// text doesn't fit, cursor is to the left of br (scroll left)
1632
} else if (widthUsed - hscroll < width) {
1633
// text doesn't fit, text document is to the left of br; align
1635
hscroll = widthUsed - width;
1636
} else if (width - hscroll > widthUsed) {
1637
// text doesn't fit, text document is to the right of br; align
1639
hscroll = width - widthUsed;
1641
if (preeditLength > 0) {
1642
// check to ensure long pre-edit text doesn't push the cursor
1644
cix = currentLine.cursorToX(m_cursor + qMax(0, m_preeditCursor - 1));
1649
if (previousScroll != hscroll)
1650
textLayoutDirty = true;
1653
void QQuickTextInputPrivate::updateVerticalScroll()
1655
Q_Q(QQuickTextInput);
1656
const int preeditLength = m_textLayout.preeditAreaText().length();
1657
const qreal height = qMax<qreal>(0, q->height());
1658
qreal heightUsed = boundingRect.height();
1659
qreal previousScroll = vscroll;
1661
if (!autoScroll || heightUsed <= height) {
1662
// text fits in br; use vscroll for alignment
1663
switch (vAlign & ~(Qt::AlignAbsolute|Qt::AlignHorizontal_Mask)) {
1664
case Qt::AlignBottom:
1665
vscroll = heightUsed - height;
1667
case Qt::AlignVCenter:
1668
vscroll = (heightUsed - height) / 2;
1676
QTextLine currentLine = m_textLayout.lineForTextPosition(m_cursor + preeditLength);
1677
QRectF r = currentLine.isValid() ? currentLine.rect() : QRectF();
1678
qreal top = r.top();
1679
int bottom = r.bottom();
1681
if (bottom - vscroll >= height) {
1682
// text doesn't fit, cursor is to the below the br (scroll down)
1683
vscroll = bottom - height;
1684
} else if (top - vscroll < 0 && vscroll < heightUsed) {
1685
// text doesn't fit, cursor is above br (scroll up)
1687
} else if (heightUsed - vscroll < height) {
1688
// text doesn't fit, text document is to the left of br; align
1690
vscroll = heightUsed - height;
1692
if (preeditLength > 0) {
1693
// check to ensure long pre-edit text doesn't push the cursor
1695
currentLine = m_textLayout.lineForTextPosition(m_cursor + qMax(0, m_preeditCursor - 1));
1696
top = currentLine.isValid() ? currentLine.rect().top() : 0;
1701
if (previousScroll != vscroll)
1702
textLayoutDirty = true;
1705
void QQuickTextInput::triggerPreprocess()
1707
Q_D(QQuickTextInput);
1708
if (d->updateType == QQuickTextInputPrivate::UpdateNone)
1709
d->updateType = QQuickTextInputPrivate::UpdateOnlyPreprocess;
1713
QSGNode *QQuickTextInput::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data)
1716
Q_D(QQuickTextInput);
1718
if (d->updateType != QQuickTextInputPrivate::UpdatePaintNode && oldNode != 0) {
1719
// Update done in preprocess() in the nodes
1720
d->updateType = QQuickTextInputPrivate::UpdateNone;
1724
d->updateType = QQuickTextInputPrivate::UpdateNone;
1726
QQuickTextNode *node = static_cast<QQuickTextNode *>(oldNode);
1728
node = new QQuickTextNode(QQuickItemPrivate::get(this)->sceneGraphContext(), this);
1731
if (!d->textLayoutDirty) {
1732
QSGSimpleRectNode *cursorNode = node->cursorNode();
1733
if (cursorNode != 0 && !isReadOnly()) {
1734
cursorNode->setRect(cursorRectangle());
1736
if (!d->cursorVisible || (!d->m_blinkStatus && d->m_blinkPeriod > 0)) {
1743
node->deleteContent();
1744
node->setMatrix(QMatrix4x4());
1746
QPointF offset(0, 0);
1747
if (d->autoScroll && d->m_textLayout.lineCount() > 0) {
1748
QFontMetricsF fm(d->font);
1749
// the y offset is there to keep the baseline constant in case we have script changes in the text.
1750
offset = -QPoint(d->hscroll, d->vscroll + d->m_textLayout.lineAt(0).ascent() - fm.ascent());
1752
offset = -QPoint(d->hscroll, d->vscroll);
1755
if (!d->m_textLayout.text().isEmpty() || !d->m_textLayout.preeditAreaText().isEmpty()) {
1756
node->addTextLayout(offset, &d->m_textLayout, d->color,
1757
QQuickText::Normal, QColor(), QColor(),
1758
d->selectionColor, d->selectedTextColor,
1759
d->selectionStart(),
1760
d->selectionEnd() - 1); // selectionEnd() returns first char after
1764
if (!isReadOnly() && d->cursorItem == 0) {
1765
node->setCursor(cursorRectangle(), d->color);
1766
if (!d->cursorVisible || (!d->m_blinkStatus && d->m_blinkPeriod > 0)) {
1773
d->textLayoutDirty = false;
1779
QVariant QQuickTextInput::inputMethodQuery(Qt::InputMethodQuery property) const
1781
Q_D(const QQuickTextInput);
1784
return QVariant((bool)(flags() & ItemAcceptsInputMethod));
1786
return QVariant((int) d->effectiveInputMethodHints());
1787
case Qt::ImCursorRectangle:
1788
return cursorRectangle();
1791
case Qt::ImCursorPosition:
1792
return QVariant(d->m_cursor);
1793
case Qt::ImSurroundingText:
1794
if (d->m_echoMode == PasswordEchoOnEdit && !d->m_passwordEchoEditing) {
1795
return QVariant(displayText());
1797
return QVariant(d->realText());
1799
case Qt::ImCurrentSelection:
1800
return QVariant(selectedText());
1801
case Qt::ImMaximumTextLength:
1802
return QVariant(maxLength());
1803
case Qt::ImAnchorPosition:
1804
if (d->selectionStart() == d->selectionEnd())
1805
return QVariant(d->m_cursor);
1806
else if (d->selectionStart() == d->m_cursor)
1807
return QVariant(d->selectionEnd());
1809
return QVariant(d->selectionStart());
1816
\qmlmethod void QtQuick2::TextInput::deselect()
1818
Removes active text selection.
1820
void QQuickTextInput::deselect()
1822
Q_D(QQuickTextInput);
1827
\qmlmethod void QtQuick2::TextInput::selectAll()
1829
Causes all text to be selected.
1831
void QQuickTextInput::selectAll()
1833
Q_D(QQuickTextInput);
1834
d->setSelection(0, text().length());
1838
\qmlmethod void QtQuick2::TextInput::isRightToLeft(int start, int end)
1840
Returns true if the natural reading direction of the editor text
1841
found between positions \a start and \a end is right to left.
1843
bool QQuickTextInput::isRightToLeft(int start, int end)
1846
qmlInfo(this) << "isRightToLeft(start, end) called with the end property being smaller than the start.";
1849
return text().mid(start, end - start).isRightToLeft();
1853
#ifndef QT_NO_CLIPBOARD
1855
\qmlmethod QtQuick2::TextInput::cut()
1857
Moves the currently selected text to the system clipboard.
1859
void QQuickTextInput::cut()
1861
Q_D(QQuickTextInput);
1867
\qmlmethod QtQuick2::TextInput::copy()
1869
Copies the currently selected text to the system clipboard.
1871
void QQuickTextInput::copy()
1873
Q_D(QQuickTextInput);
1878
\qmlmethod QtQuick2::TextInput::paste()
1880
Replaces the currently selected text by the contents of the system clipboard.
1882
void QQuickTextInput::paste()
1884
Q_D(QQuickTextInput);
1888
#endif // QT_NO_CLIPBOARD
1891
Undoes the last operation if undo is \l {canUndo}{available}. Deselects any
1892
current selection, and updates the selection start to the current cursor
1896
void QQuickTextInput::undo()
1898
Q_D(QQuickTextInput);
1899
if (!d->m_readOnly) {
1901
d->finishChange(-1, true);
1906
Redoes the last operation if redo is \l {canRedo}{available}.
1909
void QQuickTextInput::redo()
1911
Q_D(QQuickTextInput);
1912
if (!d->m_readOnly) {
1919
\qmlmethod void QtQuick2::TextInput::insert(int position, string text)
1921
Inserts \a text into the TextInput at position.
1924
void QQuickTextInput::insert(int position, const QString &text)
1926
Q_D(QQuickTextInput);
1927
if (d->m_echoMode == QQuickTextInput::Password) {
1928
int delay = qGuiApp->styleHints()->passwordMaskDelay();
1930
d->m_passwordEchoTimer.start(delay, this);
1932
if (position < 0 || position > d->m_text.length())
1935
const int priorState = d->m_undoState;
1937
QString insertText = text;
1939
if (d->hasSelectedText()) {
1940
d->addCommand(QQuickTextInputPrivate::Command(
1941
QQuickTextInputPrivate::SetSelection, d->m_cursor, 0, d->m_selstart, d->m_selend));
1943
if (d->m_maskData) {
1944
insertText = d->maskString(position, insertText);
1945
for (int i = 0; i < insertText.length(); ++i) {
1946
d->addCommand(QQuickTextInputPrivate::Command(
1947
QQuickTextInputPrivate::DeleteSelection, position + i, d->m_text.at(position + i), -1, -1));
1948
d->addCommand(QQuickTextInputPrivate::Command(
1949
QQuickTextInputPrivate::Insert, position + i, insertText.at(i), -1, -1));
1951
d->m_text.replace(position, insertText.length(), insertText);
1952
if (!insertText.isEmpty())
1953
d->m_textDirty = true;
1954
if (position < d->m_selend && position + insertText.length() > d->m_selstart)
1955
d->m_selDirty = true;
1957
int remaining = d->m_maxLength - d->m_text.length();
1958
if (remaining != 0) {
1959
insertText = insertText.left(remaining);
1960
d->m_text.insert(position, insertText);
1961
for (int i = 0; i < insertText.length(); ++i)
1962
d->addCommand(QQuickTextInputPrivate::Command(
1963
QQuickTextInputPrivate::Insert, position + i, insertText.at(i), -1, -1));
1964
if (d->m_cursor >= position)
1965
d->m_cursor += insertText.length();
1966
if (d->m_selstart >= position)
1967
d->m_selstart += insertText.length();
1968
if (d->m_selend >= position)
1969
d->m_selend += insertText.length();
1970
d->m_textDirty = true;
1971
if (position >= d->m_selstart && position <= d->m_selend)
1972
d->m_selDirty = true;
1976
d->addCommand(QQuickTextInputPrivate::Command(
1977
QQuickTextInputPrivate::SetSelection, d->m_cursor, 0, d->m_selstart, d->m_selend));
1978
d->finishChange(priorState);
1980
if (d->lastSelectionStart != d->lastSelectionEnd) {
1981
if (d->m_selstart != d->lastSelectionStart) {
1982
d->lastSelectionStart = d->m_selstart;
1983
emit selectionStartChanged();
1985
if (d->m_selend != d->lastSelectionEnd) {
1986
d->lastSelectionEnd = d->m_selend;
1987
emit selectionEndChanged();
1993
\qmlmethod string QtQuick2::TextInput::getText(int start, int end)
1995
Removes the section of text that is between the \a start and \a end positions from the TextInput.
1998
void QQuickTextInput::remove(int start, int end)
2000
Q_D(QQuickTextInput);
2002
start = qBound(0, start, d->m_text.length());
2003
end = qBound(0, end, d->m_text.length());
2007
else if (start == end)
2010
if (start < d->m_selend && end > d->m_selstart)
2011
d->m_selDirty = true;
2013
const int priorState = d->m_undoState;
2015
d->addCommand(QQuickTextInputPrivate::Command(
2016
QQuickTextInputPrivate::SetSelection, d->m_cursor, 0, d->m_selstart, d->m_selend));
2018
if (start <= d->m_cursor && d->m_cursor < end) {
2019
// cursor is within the selection. Split up the commands
2020
// to be able to restore the correct cursor position
2021
for (int i = d->m_cursor; i >= start; --i) {
2022
d->addCommand(QQuickTextInputPrivate::Command(
2023
QQuickTextInputPrivate::DeleteSelection, i, d->m_text.at(i), -1, 1));
2025
for (int i = end - 1; i > d->m_cursor; --i) {
2026
d->addCommand(QQuickTextInputPrivate::Command(
2027
QQuickTextInputPrivate::DeleteSelection, i - d->m_cursor + start - 1, d->m_text.at(i), -1, -1));
2030
for (int i = end - 1; i >= start; --i) {
2031
d->addCommand(QQuickTextInputPrivate::Command(
2032
QQuickTextInputPrivate::RemoveSelection, i, d->m_text.at(i), -1, -1));
2035
if (d->m_maskData) {
2036
d->m_text.replace(start, end - start, d->clearString(start, end - start));
2037
for (int i = 0; i < end - start; ++i) {
2038
d->addCommand(QQuickTextInputPrivate::Command(
2039
QQuickTextInputPrivate::Insert, start + i, d->m_text.at(start + i), -1, -1));
2042
d->m_text.remove(start, end - start);
2044
if (d->m_cursor > start)
2045
d->m_cursor -= qMin(d->m_cursor, end) - start;
2046
if (d->m_selstart > start)
2047
d->m_selstart -= qMin(d->m_selstart, end) - start;
2048
if (d->m_selend > end)
2049
d->m_selend -= qMin(d->m_selend, end) - start;
2051
d->addCommand(QQuickTextInputPrivate::Command(
2052
QQuickTextInputPrivate::SetSelection, d->m_cursor, 0, d->m_selstart, d->m_selend));
2054
d->m_textDirty = true;
2055
d->finishChange(priorState);
2057
if (d->lastSelectionStart != d->lastSelectionEnd) {
2058
if (d->m_selstart != d->lastSelectionStart) {
2059
d->lastSelectionStart = d->m_selstart;
2060
emit selectionStartChanged();
2062
if (d->m_selend != d->lastSelectionEnd) {
2063
d->lastSelectionEnd = d->m_selend;
2064
emit selectionEndChanged();
2071
\qmlmethod void QtQuick2::TextInput::selectWord()
2073
Causes the word closest to the current cursor position to be selected.
2075
void QQuickTextInput::selectWord()
2077
Q_D(QQuickTextInput);
2078
d->selectWordAtPos(d->m_cursor);
2082
\qmlproperty bool QtQuick2::TextInput::smooth
2084
This property holds whether the text is smoothly scaled or transformed.
2086
Smooth filtering gives better visual quality, but is slower. If
2087
the item is displayed at its natural size, this property has no visual or
2090
\note Generally scaling artifacts are only visible if the item is stationary on
2091
the screen. A common pattern when animating an item is to disable smooth
2092
filtering at the beginning of the animation and reenable it at the conclusion.
2096
\qmlproperty string QtQuick2::TextInput::passwordCharacter
2098
This is the character displayed when echoMode is set to Password or
2099
PasswordEchoOnEdit. By default it is an asterisk.
2101
If this property is set to a string with more than one character,
2102
the first character is used. If the string is empty, the value
2103
is ignored and the property is not set.
2105
QString QQuickTextInput::passwordCharacter() const
2107
Q_D(const QQuickTextInput);
2108
return QString(d->m_passwordCharacter);
2111
void QQuickTextInput::setPasswordCharacter(const QString &str)
2113
Q_D(QQuickTextInput);
2114
if (str.length() < 1)
2116
d->m_passwordCharacter = str.constData()[0];
2117
if (d->m_echoMode == Password || d->m_echoMode == PasswordEchoOnEdit)
2118
d->updateDisplayText();
2119
emit passwordCharacterChanged();
2123
\qmlproperty string QtQuick2::TextInput::displayText
2125
This is the text displayed in the TextInput.
2127
If \l echoMode is set to TextInput::Normal, this holds the
2128
same value as the TextInput::text property. Otherwise,
2129
this property holds the text visible to the user, while
2130
the \l text property holds the actual entered text.
2132
QString QQuickTextInput::displayText() const
2134
Q_D(const QQuickTextInput);
2135
return d->m_textLayout.text();
2139
\qmlproperty bool QtQuick2::TextInput::selectByMouse
2143
If true, the user can use the mouse to select text in some
2144
platform-specific way. Note that for some platforms this may
2145
not be an appropriate interaction (eg. may conflict with how
2146
the text needs to behave inside a Flickable.
2148
bool QQuickTextInput::selectByMouse() const
2150
Q_D(const QQuickTextInput);
2151
return d->selectByMouse;
2154
void QQuickTextInput::setSelectByMouse(bool on)
2156
Q_D(QQuickTextInput);
2157
if (d->selectByMouse != on) {
2158
d->selectByMouse = on;
2159
emit selectByMouseChanged(on);
2164
\qmlproperty enum QtQuick2::TextInput::mouseSelectionMode
2166
Specifies how text should be selected using a mouse.
2169
\li TextInput.SelectCharacters - The selection is updated with individual characters. (Default)
2170
\li TextInput.SelectWords - The selection is updated with whole words.
2173
This property only applies when \l selectByMouse is true.
2176
QQuickTextInput::SelectionMode QQuickTextInput::mouseSelectionMode() const
2178
Q_D(const QQuickTextInput);
2179
return d->mouseSelectionMode;
2182
void QQuickTextInput::setMouseSelectionMode(SelectionMode mode)
2184
Q_D(QQuickTextInput);
2185
if (d->mouseSelectionMode != mode) {
2186
d->mouseSelectionMode = mode;
2187
emit mouseSelectionModeChanged(mode);
2192
\qmlproperty bool QtQuick2::TextInput::persistentSelection
2194
Whether the TextInput should keep its selection when it loses active focus to another
2195
item in the scene. By default this is set to false;
2198
bool QQuickTextInput::persistentSelection() const
2200
Q_D(const QQuickTextInput);
2201
return d->persistentSelection;
2204
void QQuickTextInput::setPersistentSelection(bool on)
2206
Q_D(QQuickTextInput);
2207
if (d->persistentSelection == on)
2209
d->persistentSelection = on;
2210
emit persistentSelectionChanged();
2214
\qmlproperty bool QtQuick2::TextInput::canPaste
2216
Returns true if the TextInput is writable and the content of the clipboard is
2217
suitable for pasting into the TextInput.
2219
bool QQuickTextInput::canPaste() const
2221
Q_D(const QQuickTextInput);
2222
if (!d->canPasteValid) {
2223
if (const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData())
2224
const_cast<QQuickTextInputPrivate *>(d)->canPaste = !d->m_readOnly && mimeData->hasText();
2225
const_cast<QQuickTextInputPrivate *>(d)->canPasteValid = true;
2231
\qmlproperty bool QtQuick2::TextInput::canUndo
2233
Returns true if the TextInput is writable and there are previous operations
2237
bool QQuickTextInput::canUndo() const
2239
Q_D(const QQuickTextInput);
2244
\qmlproperty bool QtQuick2::TextInput::canRedo
2246
Returns true if the TextInput is writable and there are \l {undo}{undone}
2247
operations that can be redone.
2250
bool QQuickTextInput::canRedo() const
2252
Q_D(const QQuickTextInput);
2257
\qmlproperty real QtQuick2::TextInput::contentWidth
2259
Returns the width of the text, including the width past the width
2260
which is covered due to insufficient wrapping if \l wrapMode is set.
2263
qreal QQuickTextInput::contentWidth() const
2265
Q_D(const QQuickTextInput);
2266
return d->boundingRect.width();
2270
\qmlproperty real QtQuick2::TextInput::contentHeight
2272
Returns the height of the text, including the height past the height
2273
that is covered if the text does not fit within the set height.
2276
qreal QQuickTextInput::contentHeight() const
2278
Q_D(const QQuickTextInput);
2279
return d->boundingRect.height();
2282
void QQuickTextInput::moveCursorSelection(int position)
2284
Q_D(QQuickTextInput);
2285
d->moveCursor(position, true);
2289
\qmlmethod void QtQuick2::TextInput::moveCursorSelection(int position, SelectionMode mode = TextInput.SelectCharacters)
2291
Moves the cursor to \a position and updates the selection according to the optional \a mode
2292
parameter. (To only move the cursor, set the \l cursorPosition property.)
2294
When this method is called it additionally sets either the
2295
selectionStart or the selectionEnd (whichever was at the previous cursor position)
2296
to the specified position. This allows you to easily extend and contract the selected
2299
The selection mode specifies whether the selection is updated on a per character or a per word
2300
basis. If not specified the selection mode will default to TextInput.SelectCharacters.
2303
\li TextInput.SelectCharacters - Sets either the selectionStart or selectionEnd (whichever was at
2304
the previous cursor position) to the specified position.
2305
\li TextInput.SelectWords - Sets the selectionStart and selectionEnd to include all
2306
words between the specified position and the previous cursor position. Words partially in the
2310
For example, take this sequence of calls:
2314
moveCursorSelection(9, TextInput.SelectCharacters)
2315
moveCursorSelection(7, TextInput.SelectCharacters)
2318
This moves the cursor to position 5, extend the selection end from 5 to 9
2319
and then retract the selection end from 9 to 7, leaving the text from position 5 to 7
2320
selected (the 6th and 7th characters).
2322
The same sequence with TextInput.SelectWords will extend the selection start to a word boundary
2323
before or on position 5 and extend the selection end to a word boundary on or past position 9.
2325
void QQuickTextInput::moveCursorSelection(int pos, SelectionMode mode)
2327
Q_D(QQuickTextInput);
2329
if (mode == SelectCharacters) {
2330
d->moveCursor(pos, true);
2331
} else if (pos != d->m_cursor){
2332
const int cursor = d->m_cursor;
2334
if (!d->hasSelectedText())
2335
anchor = d->m_cursor;
2336
else if (d->selectionStart() == d->m_cursor)
2337
anchor = d->selectionEnd();
2339
anchor = d->selectionStart();
2341
if (anchor < pos || (anchor == pos && cursor < pos)) {
2342
const QString text = this->text();
2343
QTextBoundaryFinder finder(QTextBoundaryFinder::Word, text);
2344
finder.setPosition(anchor);
2346
const QTextBoundaryFinder::BoundaryReasons reasons = finder.boundaryReasons();
2347
if (anchor < text.length() && (!(reasons & QTextBoundaryFinder::StartWord)
2348
|| ((reasons & QTextBoundaryFinder::EndWord) && anchor > cursor))) {
2349
finder.toPreviousBoundary();
2351
anchor = finder.position() != -1 ? finder.position() : 0;
2353
finder.setPosition(pos);
2354
if (pos > 0 && !finder.boundaryReasons())
2355
finder.toNextBoundary();
2356
const int cursor = finder.position() != -1 ? finder.position() : text.length();
2358
d->setSelection(anchor, cursor - anchor);
2359
} else if (anchor > pos || (anchor == pos && cursor > pos)) {
2360
const QString text = this->text();
2361
QTextBoundaryFinder finder(QTextBoundaryFinder::Word, text);
2362
finder.setPosition(anchor);
2364
const QTextBoundaryFinder::BoundaryReasons reasons = finder.boundaryReasons();
2365
if (anchor > 0 && (!(reasons & QTextBoundaryFinder::EndWord)
2366
|| ((reasons & QTextBoundaryFinder::StartWord) && anchor < cursor))) {
2367
finder.toNextBoundary();
2370
anchor = finder.position() != -1 ? finder.position() : text.length();
2372
finder.setPosition(pos);
2373
if (pos < text.length() && !finder.boundaryReasons())
2374
finder.toPreviousBoundary();
2375
const int cursor = finder.position() != -1 ? finder.position() : 0;
2377
d->setSelection(anchor, cursor - anchor);
2383
\qmlmethod void QtQuick2::TextInput::openSoftwareInputPanel()
2385
Opens software input panels like virtual keyboards for typing, useful for
2386
customizing when you want the input keyboard to be shown and hidden in
2389
By default the opening of input panels follows the platform style. Input panels are
2390
always closed if no editor has active focus.
2392
You can disable the automatic behavior by setting the property \c activeFocusOnPress to false
2393
and use functions openSoftwareInputPanel() and closeSoftwareInputPanel() to implement
2394
the behavior you want.
2396
Only relevant on platforms, which provide virtual keyboards.
2402
text: "Hello world!"
2403
activeFocusOnPress: false
2405
anchors.fill: parent
2407
if (!textInput.activeFocus) {
2408
textInput.forceActiveFocus()
2409
textInput.openSoftwareInputPanel();
2411
textInput.focus = false;
2414
onPressAndHold: textInput.closeSoftwareInputPanel();
2419
void QQuickTextInput::openSoftwareInputPanel()
2422
qGuiApp->inputMethod()->show();
2426
\qmlmethod void QtQuick2::TextInput::closeSoftwareInputPanel()
2428
Closes a software input panel like a virtual keyboard shown on the screen, useful
2429
for customizing when you want the input keyboard to be shown and hidden in
2432
By default the opening of input panels follows the platform style. Input panels are
2433
always closed if no editor has active focus.
2435
You can disable the automatic behavior by setting the property \c activeFocusOnPress to false
2436
and use functions openSoftwareInputPanel() and closeSoftwareInputPanel() to implement
2437
the behavior you want.
2439
Only relevant on platforms, which provide virtual keyboards.
2445
text: "Hello world!"
2446
activeFocusOnPress: false
2448
anchors.fill: parent
2450
if (!textInput.activeFocus) {
2451
textInput.forceActiveFocus();
2452
textInput.openSoftwareInputPanel();
2454
textInput.focus = false;
2457
onPressAndHold: textInput.closeSoftwareInputPanel();
2462
void QQuickTextInput::closeSoftwareInputPanel()
2465
qGuiApp->inputMethod()->hide();
2468
void QQuickTextInput::focusInEvent(QFocusEvent *event)
2470
Q_D(const QQuickTextInput);
2471
if (d->focusOnPress && !d->m_readOnly)
2472
openSoftwareInputPanel();
2473
QQuickImplicitSizeItem::focusInEvent(event);
2476
void QQuickTextInput::itemChange(ItemChange change, const ItemChangeData &value)
2478
Q_D(QQuickTextInput);
2479
if (change == ItemActiveFocusHasChanged) {
2480
bool hasFocus = value.boolValue;
2481
setCursorVisible(hasFocus); // ### refactor: && d->canvas && d->canvas->hasFocus()
2482
if (!hasFocus && (d->m_passwordEchoEditing || d->m_passwordEchoTimer.isActive())) {
2483
d->updatePasswordEchoEditing(false);//QQuickTextInputPrivate sets it on key events, but doesn't deal with focus events
2487
if (!d->persistentSelection)
2489
disconnect(qApp->inputMethod(), SIGNAL(inputDirectionChanged(Qt::LayoutDirection)),
2490
this, SLOT(q_updateAlignment()));
2492
q_updateAlignment();
2493
connect(qApp->inputMethod(), SIGNAL(inputDirectionChanged(Qt::LayoutDirection)),
2494
this, SLOT(q_updateAlignment()));
2497
QQuickItem::itemChange(change, value);
2501
\qmlproperty bool QtQuick2::TextInput::inputMethodComposing
2504
This property holds whether the TextInput has partial text input from an
2507
While it is composing an input method may rely on mouse or key events from
2508
the TextInput to edit or commit the partial text. This property can be
2509
used to determine when to disable events handlers that may interfere with
2510
the correct operation of an input method.
2512
bool QQuickTextInput::isInputMethodComposing() const
2514
Q_D(const QQuickTextInput);
2515
return d->hasImState;
2518
void QQuickTextInputPrivate::init()
2520
Q_Q(QQuickTextInput);
2521
q->setSmooth(smooth);
2522
q->setAcceptedMouseButtons(Qt::LeftButton);
2523
q->setFlag(QQuickItem::ItemAcceptsInputMethod);
2524
q->setFlag(QQuickItem::ItemHasContents);
2525
#ifndef QT_NO_CLIPBOARD
2526
q->connect(QGuiApplication::clipboard(), SIGNAL(dataChanged()),
2527
q, SLOT(q_canPasteChanged()));
2528
#endif // QT_NO_CLIPBOARD
2530
lastSelectionStart = 0;
2531
lastSelectionEnd = 0;
2532
determineHorizontalAlignment();
2534
if (!qmlDisableDistanceField()) {
2535
QTextOption option = m_textLayout.textOption();
2536
option.setUseDesignMetrics(true);
2537
m_textLayout.setTextOption(option);
2541
void QQuickTextInput::updateCursorRectangle()
2543
Q_D(QQuickTextInput);
2544
if (!isComponentComplete())
2547
d->updateHorizontalScroll();
2548
d->updateVerticalScroll();
2549
d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
2551
emit cursorRectangleChanged();
2552
if (d->cursorItem) {
2553
QRectF r = cursorRectangle();
2554
d->cursorItem->setPos(r.topLeft());
2555
d->cursorItem->setHeight(r.height());
2557
updateInputMethod(Qt::ImCursorRectangle);
2560
void QQuickTextInput::selectionChanged()
2562
Q_D(QQuickTextInput);
2563
d->textLayoutDirty = true; //TODO: Only update rect in selection
2564
d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
2566
emit selectedTextChanged();
2568
if (d->lastSelectionStart != d->selectionStart()) {
2569
d->lastSelectionStart = d->selectionStart();
2570
if (d->lastSelectionStart == -1)
2571
d->lastSelectionStart = d->m_cursor;
2572
emit selectionStartChanged();
2574
if (d->lastSelectionEnd != d->selectionEnd()) {
2575
d->lastSelectionEnd = d->selectionEnd();
2576
if (d->lastSelectionEnd == -1)
2577
d->lastSelectionEnd = d->m_cursor;
2578
emit selectionEndChanged();
2582
void QQuickTextInputPrivate::showCursor()
2584
if (textNode != 0 && textNode->cursorNode() != 0)
2585
textNode->cursorNode()->setColor(color);
2588
void QQuickTextInputPrivate::hideCursor()
2590
if (textNode != 0 && textNode->cursorNode() != 0)
2591
textNode->cursorNode()->setColor(QColor(0, 0, 0, 0));
2594
QRectF QQuickTextInput::boundingRect() const
2596
Q_D(const QQuickTextInput);
2598
int cursorWidth = d->cursorItem ? d->cursorItem->width() : 1;
2600
// Could include font max left/right bearings to either side of rectangle.
2601
QRectF r = QQuickImplicitSizeItem::boundingRect();
2602
r.setRight(r.right() + cursorWidth);
2606
void QQuickTextInput::q_canPasteChanged()
2608
Q_D(QQuickTextInput);
2609
bool old = d->canPaste;
2610
#ifndef QT_NO_CLIPBOARD
2611
if (const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData())
2612
d->canPaste = !d->m_readOnly && mimeData->hasText();
2614
d->canPaste = false;
2617
bool changed = d->canPaste != old || !d->canPasteValid;
2618
d->canPasteValid = true;
2620
emit canPasteChanged();
2624
void QQuickTextInput::q_updateAlignment()
2626
Q_D(QQuickTextInput);
2627
if (d->determineHorizontalAlignment()) {
2629
updateCursorRectangle();
2633
// ### these should come from QStyleHints
2634
const int textCursorWidth = 1;
2635
const bool fullWidthSelection = true;
2640
Updates the display text based of the current edit text
2641
If the text has changed will emit displayTextChanged()
2643
void QQuickTextInputPrivate::updateDisplayText(bool forceUpdate)
2645
QString orig = m_textLayout.text();
2647
if (m_echoMode == QQuickTextInput::NoEcho)
2648
str = QString::fromLatin1("");
2652
if (m_echoMode == QQuickTextInput::Password) {
2653
str.fill(m_passwordCharacter);
2654
if (m_passwordEchoTimer.isActive() && m_cursor > 0 && m_cursor <= m_text.length()) {
2655
int cursor = m_cursor - 1;
2656
QChar uc = m_text.at(cursor);
2658
if (cursor > 0 && uc.unicode() >= 0xdc00 && uc.unicode() < 0xe000) {
2659
// second half of a surrogate, check if we have the first half as well,
2660
// if yes restore both at once
2661
uc = m_text.at(cursor - 1);
2662
if (uc.unicode() >= 0xd800 && uc.unicode() < 0xdc00)
2663
str[cursor - 1] = uc;
2666
} else if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit && !m_passwordEchoEditing) {
2667
str.fill(m_passwordCharacter);
2670
// replace certain non-printable characters with spaces (to avoid
2671
// drawing boxes when using fonts that don't have glyphs for such
2673
QChar* uc = str.data();
2674
for (int i = 0; i < (int)str.length(); ++i) {
2675
if ((uc[i] < 0x20 && uc[i] != 0x09)
2676
|| uc[i] == QChar::LineSeparator
2677
|| uc[i] == QChar::ParagraphSeparator
2678
|| uc[i] == QChar::ObjectReplacementCharacter)
2679
uc[i] = QChar(0x0020);
2682
if (str != orig || forceUpdate) {
2683
m_textLayout.setText(str);
2684
updateLayout(); // polish?
2685
emit q_func()->displayTextChanged();
2689
qreal QQuickTextInputPrivate::getImplicitWidth() const
2691
Q_Q(const QQuickTextInput);
2692
if (!requireImplicitWidth) {
2693
QQuickTextInputPrivate *d = const_cast<QQuickTextInputPrivate *>(this);
2694
d->requireImplicitWidth = true;
2696
if (q->isComponentComplete()) {
2697
// One time cost, only incurred if implicitWidth is first requested after
2698
// componentComplete.
2699
QTextLayout layout(m_text);
2701
QTextOption option = m_textLayout.textOption();
2702
option.setTextDirection(m_layoutDirection);
2703
option.setFlags(QTextOption::IncludeTrailingSpaces);
2704
option.setWrapMode(QTextOption::WrapMode(wrapMode));
2705
option.setAlignment(Qt::Alignment(q->effectiveHAlign()));
2706
layout.setTextOption(option);
2707
layout.setFont(font);
2708
layout.setPreeditArea(m_textLayout.preeditAreaPosition(), m_textLayout.preeditAreaText());
2709
layout.beginLayout();
2711
QTextLine line = layout.createLine();
2712
line.setLineWidth(INT_MAX);
2713
d->implicitWidth = qCeil(line.naturalTextWidth());
2718
return implicitWidth;
2721
void QQuickTextInputPrivate::updateLayout()
2723
Q_Q(QQuickTextInput);
2725
if (!q->isComponentComplete())
2728
const QRectF previousRect = boundingRect;
2730
QTextOption option = m_textLayout.textOption();
2731
option.setTextDirection(layoutDirection());
2732
option.setWrapMode(QTextOption::WrapMode(wrapMode));
2733
option.setAlignment(Qt::Alignment(q->effectiveHAlign()));
2734
m_textLayout.setTextOption(option);
2735
m_textLayout.setFont(font);
2737
boundingRect = QRectF();
2738
m_textLayout.beginLayout();
2739
QTextLine line = m_textLayout.createLine();
2740
if (requireImplicitWidth) {
2741
line.setLineWidth(INT_MAX);
2742
const bool wasInLayout = inLayout;
2744
q->setImplicitWidth(qCeil(line.naturalTextWidth()));
2745
inLayout = wasInLayout;
2746
if (inLayout) // probably the result of a binding loop, but by letting it
2747
return; // get this far we'll get a warning to that effect.
2749
qreal lineWidth = q->widthValid() ? q->width() : INT_MAX;
2752
line.setLineWidth(lineWidth);
2753
line.setPosition(QPointF(line.position().x(), height));
2754
boundingRect = boundingRect.united(line.naturalTextRect());
2756
height += line.height();
2757
line = m_textLayout.createLine();
2758
} while (line.isValid());
2759
m_textLayout.endLayout();
2761
option.setWrapMode(QTextOption::NoWrap);
2762
m_textLayout.setTextOption(option);
2764
textLayoutDirty = true;
2766
updateType = UpdatePaintNode;
2769
if (!requireImplicitWidth && !q->widthValid())
2770
q->setImplicitSize(qCeil(boundingRect.width()), qCeil(boundingRect.height()));
2772
q->setImplicitHeight(qCeil(boundingRect.height()));
2774
if (previousRect != boundingRect)
2775
emit q->contentSizeChanged();
2778
#ifndef QT_NO_CLIPBOARD
2782
Copies the currently selected text into the clipboard using the given
2785
\note If the echo mode is set to a mode other than Normal then copy
2786
will not work. This is to prevent using copy as a method of bypassing
2787
password features of the line control.
2789
void QQuickTextInputPrivate::copy(QClipboard::Mode mode) const
2791
QString t = selectedText();
2792
if (!t.isEmpty() && m_echoMode == QQuickTextInput::Normal) {
2793
QGuiApplication::clipboard()->setText(t, mode);
2800
Inserts the text stored in the application clipboard into the line
2805
void QQuickTextInputPrivate::paste(QClipboard::Mode clipboardMode)
2807
QString clip = QGuiApplication::clipboard()->text(clipboardMode);
2808
if (!clip.isEmpty() || hasSelectedText()) {
2809
separate(); //make it a separate undo/redo command
2815
#endif // !QT_NO_CLIPBOARD
2820
void QQuickTextInputPrivate::commitPreedit()
2822
Q_Q(QQuickTextInput);
2827
qApp->inputMethod()->commit();
2832
QInputMethodEvent ev;
2833
QCoreApplication::sendEvent(q, &ev);
2836
void QQuickTextInputPrivate::cancelPreedit()
2838
Q_Q(QQuickTextInput);
2843
qApp->inputMethod()->reset();
2845
QInputMethodEvent ev;
2846
QCoreApplication::sendEvent(q, &ev);
2852
Handles the behavior for the backspace key or function.
2853
Removes the current selection if there is a selection, otherwise
2854
removes the character prior to the cursor position.
2858
void QQuickTextInputPrivate::backspace()
2860
int priorState = m_undoState;
2861
if (hasSelectedText()) {
2862
removeSelectedText();
2863
} else if (m_cursor) {
2866
m_cursor = prevMaskBlank(m_cursor);
2867
QChar uc = m_text.at(m_cursor);
2868
if (m_cursor > 0 && uc.unicode() >= 0xdc00 && uc.unicode() < 0xe000) {
2869
// second half of a surrogate, check if we have the first half as well,
2870
// if yes delete both at once
2871
uc = m_text.at(m_cursor - 1);
2872
if (uc.unicode() >= 0xd800 && uc.unicode() < 0xdc00) {
2873
internalDelete(true);
2877
internalDelete(true);
2879
finishChange(priorState);
2885
Handles the behavior for the delete key or function.
2886
Removes the current selection if there is a selection, otherwise
2887
removes the character after the cursor position.
2891
void QQuickTextInputPrivate::del()
2893
int priorState = m_undoState;
2894
if (hasSelectedText()) {
2895
removeSelectedText();
2897
int n = m_textLayout.nextCursorPosition(m_cursor) - m_cursor;
2901
finishChange(priorState);
2907
Inserts the given \a newText at the current cursor position.
2908
If there is any selected text it is removed prior to insertion of
2911
void QQuickTextInputPrivate::insert(const QString &newText)
2913
int priorState = m_undoState;
2914
removeSelectedText();
2915
internalInsert(newText);
2916
finishChange(priorState);
2922
Clears the line control text.
2924
void QQuickTextInputPrivate::clear()
2926
int priorState = m_undoState;
2928
m_selend = m_text.length();
2929
removeSelectedText();
2931
finishChange(priorState, /*update*/false, /*edited*/false);
2937
Sets \a length characters from the given \a start position as selected.
2938
The given \a start position must be within the current text for
2939
the line control. If \a length characters cannot be selected, then
2940
the selection will extend to the end of the current text.
2942
void QQuickTextInputPrivate::setSelection(int start, int length)
2944
Q_Q(QQuickTextInput);
2947
if (start < 0 || start > (int)m_text.length()){
2948
qWarning("QQuickTextInputPrivate::setSelection: Invalid start position");
2953
if (start == m_selstart && start + length == m_selend && m_cursor == m_selend)
2956
m_selend = qMin(start + length, (int)m_text.length());
2957
m_cursor = m_selend;
2958
} else if (length < 0){
2959
if (start == m_selend && start + length == m_selstart && m_cursor == m_selstart)
2961
m_selstart = qMax(start + length, 0);
2963
m_cursor = m_selstart;
2964
} else if (m_selstart != m_selend) {
2970
emitCursorPositionChanged();
2973
emit q->selectionChanged();
2974
emitCursorPositionChanged();
2975
q->updateInputMethod(Qt::ImCursorRectangle | Qt::ImAnchorPosition
2976
| Qt::ImCursorPosition | Qt::ImCurrentSelection);
2982
Sets the password echo editing to \a editing. If password echo editing
2983
is true, then the text of the password is displayed even if the echo
2984
mode is set to QLineEdit::PasswordEchoOnEdit. Password echoing editing
2985
does not affect other echo modes.
2987
void QQuickTextInputPrivate::updatePasswordEchoEditing(bool editing)
2989
cancelPasswordEchoTimer();
2990
m_passwordEchoEditing = editing;
2991
updateDisplayText();
2997
Fixes the current text so that it is valid given any set validators.
2999
Returns true if the text was changed. Otherwise returns false.
3001
bool QQuickTextInputPrivate::fixup() // this function assumes that validate currently returns != Acceptable
3003
#ifndef QT_NO_VALIDATOR
3005
QString textCopy = m_text;
3006
int cursorCopy = m_cursor;
3007
m_validator->fixup(textCopy);
3008
if (m_validator->validate(textCopy, cursorCopy) == QValidator::Acceptable) {
3009
if (textCopy != m_text || cursorCopy != m_cursor)
3010
internalSetText(textCopy, cursorCopy);
3021
Moves the cursor to the given position \a pos. If \a mark is true will
3022
adjust the currently selected text.
3024
void QQuickTextInputPrivate::moveCursor(int pos, bool mark)
3026
Q_Q(QQuickTextInput);
3029
if (pos != m_cursor) {
3032
pos = pos > m_cursor ? nextMaskBlank(pos) : prevMaskBlank(pos);
3036
if (m_selend > m_selstart && m_cursor == m_selstart)
3038
else if (m_selend > m_selstart && m_cursor == m_selend)
3039
anchor = m_selstart;
3042
m_selstart = qMin(anchor, pos);
3043
m_selend = qMax(anchor, pos);
3048
if (mark || m_selDirty) {
3050
emit q->selectionChanged();
3052
emitCursorPositionChanged();
3053
q->updateInputMethod();
3059
Applies the given input method event \a event to the text of the line
3062
void QQuickTextInputPrivate::processInputMethodEvent(QInputMethodEvent *event)
3064
Q_Q(QQuickTextInput);
3066
int priorState = -1;
3067
bool isGettingInput = !event->commitString().isEmpty()
3068
|| event->preeditString() != preeditAreaText()
3069
|| event->replacementLength() > 0;
3070
bool cursorPositionChanged = false;
3071
bool selectionChange = false;
3072
m_preeditDirty = event->preeditString() != preeditAreaText();
3074
if (isGettingInput) {
3075
// If any text is being input, remove selected text.
3076
priorState = m_undoState;
3077
if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit && !m_passwordEchoEditing) {
3078
updatePasswordEchoEditing(true);
3080
m_selend = m_text.length();
3082
removeSelectedText();
3085
int c = m_cursor; // cursor position after insertion of commit string
3086
if (event->replacementStart() <= 0)
3087
c += event->commitString().length() - qMin(-event->replacementStart(), event->replacementLength());
3089
m_cursor += event->replacementStart();
3093
// insert commit string
3094
if (event->replacementLength()) {
3095
m_selstart = m_cursor;
3096
m_selend = m_selstart + event->replacementLength();
3097
m_selend = qMin(m_selend, m_text.length());
3098
removeSelectedText();
3100
if (!event->commitString().isEmpty()) {
3101
internalInsert(event->commitString());
3102
cursorPositionChanged = true;
3105
m_cursor = qBound(0, c, m_text.length());
3107
for (int i = 0; i < event->attributes().size(); ++i) {
3108
const QInputMethodEvent::Attribute &a = event->attributes().at(i);
3109
if (a.type == QInputMethodEvent::Selection) {
3110
m_cursor = qBound(0, a.start + a.length, m_text.length());
3112
m_selstart = qMax(0, qMin(a.start, m_text.length()));
3113
m_selend = m_cursor;
3114
if (m_selend < m_selstart) {
3115
qSwap(m_selstart, m_selend);
3117
selectionChange = true;
3119
m_selstart = m_selend = 0;
3121
cursorPositionChanged = true;
3125
m_textLayout.setPreeditArea(m_cursor, event->preeditString());
3127
const int oldPreeditCursor = m_preeditCursor;
3128
const bool oldCursorVisible = cursorVisible;
3129
m_preeditCursor = event->preeditString().length();
3130
hasImState = !event->preeditString().isEmpty();
3131
cursorVisible = true;
3132
QList<QTextLayout::FormatRange> formats;
3133
for (int i = 0; i < event->attributes().size(); ++i) {
3134
const QInputMethodEvent::Attribute &a = event->attributes().at(i);
3135
if (a.type == QInputMethodEvent::Cursor) {
3137
m_preeditCursor = a.start;
3138
cursorVisible = a.length != 0;
3139
} else if (a.type == QInputMethodEvent::TextFormat) {
3141
QTextCharFormat f = qvariant_cast<QTextFormat>(a.value).toCharFormat();
3143
QTextLayout::FormatRange o;
3144
o.start = a.start + m_cursor;
3145
o.length = a.length;
3151
m_textLayout.setAdditionalFormats(formats);
3153
updateDisplayText(/*force*/ true);
3154
if (cursorPositionChanged) {
3155
emitCursorPositionChanged();
3156
} else if (m_preeditCursor != oldPreeditCursor) {
3157
q->updateCursorRectangle();
3161
finishChange(priorState);
3163
if (cursorVisible != oldCursorVisible)
3164
emit q->cursorVisibleChanged(cursorVisible);
3166
if (selectionChange) {
3167
emit q->selectionChanged();
3168
q->updateInputMethod(Qt::ImCursorRectangle | Qt::ImAnchorPosition
3169
| Qt::ImCursorPosition | Qt::ImCurrentSelection);
3176
Sets the selection to cover the word at the given cursor position.
3177
The word boundaries are defined by the behavior of QTextLayout::SkipWords
3180
void QQuickTextInputPrivate::selectWordAtPos(int cursor)
3182
int next = cursor + 1;
3185
int c = m_textLayout.previousCursorPosition(next, QTextLayout::SkipWords);
3186
moveCursor(c, false);
3187
// ## text layout should support end of words.
3188
int end = m_textLayout.nextCursorPosition(c, QTextLayout::SkipWords);
3189
while (end > cursor && m_text[end-1].isSpace())
3191
moveCursor(end, true);
3197
Completes a change to the line control text. If the change is not valid
3198
will undo the line control state back to the given \a validateFromState.
3200
If \a edited is true and the change is valid, will emit textEdited() in
3201
addition to textChanged(). Otherwise only emits textChanged() on a valid
3204
The \a update value is currently unused.
3206
bool QQuickTextInputPrivate::finishChange(int validateFromState, bool update, bool /*edited*/)
3208
Q_Q(QQuickTextInput);
3211
bool inputMethodAttributesChanged = m_textDirty || m_selDirty;
3212
bool alignmentChanged = false;
3216
bool wasValidInput = m_validInput;
3217
bool wasAcceptable = m_acceptableInput;
3218
m_validInput = true;
3219
m_acceptableInput = true;
3220
#ifndef QT_NO_VALIDATOR
3222
QString textCopy = m_text;
3223
int cursorCopy = m_cursor;
3224
QValidator::State state = m_validator->validate(textCopy, cursorCopy);
3225
m_validInput = state != QValidator::Invalid;
3226
m_acceptableInput = state == QValidator::Acceptable;
3228
if (m_text != textCopy) {
3229
internalSetText(textCopy, cursorCopy);
3232
m_cursor = cursorCopy;
3236
if (validateFromState >= 0 && wasValidInput && !m_validInput) {
3237
if (m_transactions.count())
3239
internalUndo(validateFromState);
3240
m_history.resize(m_undoState);
3241
m_validInput = true;
3242
m_acceptableInput = wasAcceptable;
3243
m_textDirty = false;
3247
m_textDirty = false;
3248
m_preeditDirty = false;
3249
alignmentChanged = determineHorizontalAlignment();
3250
emit q->textChanged();
3253
updateDisplayText(alignmentChanged);
3255
if (m_acceptableInput != wasAcceptable)
3256
emit q->acceptableInputChanged();
3258
if (m_preeditDirty) {
3259
m_preeditDirty = false;
3260
if (determineHorizontalAlignment()) {
3261
alignmentChanged = true;
3268
emit q->selectionChanged();
3271
inputMethodAttributesChanged |= (m_cursor == m_lastCursorPos);
3272
if (inputMethodAttributesChanged)
3273
q->updateInputMethod();
3274
emitUndoRedoChanged();
3276
if (!emitCursorPositionChanged() && alignmentChanged)
3277
q->updateCursorRectangle();
3285
An internal function for setting the text of the line control.
3287
void QQuickTextInputPrivate::internalSetText(const QString &txt, int pos, bool edited)
3289
Q_Q(QQuickTextInput);
3291
QString oldText = m_text;
3293
m_text = maskString(0, txt, true);
3294
m_text += clearString(m_text.length(), m_maxLength - m_text.length());
3296
m_text = txt.isEmpty() ? txt : txt.left(m_maxLength);
3300
m_cursor = (pos < 0 || pos > m_text.length()) ? m_text.length() : pos;
3301
m_textDirty = (oldText != m_text);
3303
bool changed = finishChange(-1, true, edited);
3304
#ifdef QT_NO_ACCESSIBILITY
3308
QAccessibleTextUpdateEvent ev(q, 0, oldText, m_text);
3309
QAccessible::updateAccessibility(&ev);
3318
Adds the given \a command to the undo history
3319
of the line control. Does not apply the command.
3321
void QQuickTextInputPrivate::addCommand(const Command &cmd)
3323
if (m_separator && m_undoState && m_history[m_undoState - 1].type != Separator) {
3324
m_history.resize(m_undoState + 2);
3325
m_history[m_undoState++] = Command(Separator, m_cursor, 0, m_selstart, m_selend);
3327
m_history.resize(m_undoState + 1);
3329
m_separator = false;
3330
m_history[m_undoState++] = cmd;
3336
Inserts the given string \a s into the line
3339
Also adds the appropriate commands into the undo history.
3340
This function does not call finishChange(), and may leave the text
3341
in an invalid state.
3343
void QQuickTextInputPrivate::internalInsert(const QString &s)
3345
Q_Q(QQuickTextInput);
3346
if (m_echoMode == QQuickTextInput::Password) {
3347
int delay = qGuiApp->styleHints()->passwordMaskDelay();
3349
m_passwordEchoTimer.start(delay, q);
3351
if (hasSelectedText())
3352
addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
3354
QString ms = maskString(m_cursor, s);
3355
for (int i = 0; i < (int) ms.length(); ++i) {
3356
addCommand (Command(DeleteSelection, m_cursor + i, m_text.at(m_cursor + i), -1, -1));
3357
addCommand(Command(Insert, m_cursor + i, ms.at(i), -1, -1));
3359
m_text.replace(m_cursor, ms.length(), ms);
3360
m_cursor += ms.length();
3361
m_cursor = nextMaskBlank(m_cursor);
3364
int remaining = m_maxLength - m_text.length();
3365
if (remaining != 0) {
3366
m_text.insert(m_cursor, s.left(remaining));
3367
for (int i = 0; i < (int) s.left(remaining).length(); ++i)
3368
addCommand(Command(Insert, m_cursor++, s.at(i), -1, -1));
3377
deletes a single character from the current text. If \a wasBackspace,
3378
the character prior to the cursor is removed. Otherwise the character
3379
after the cursor is removed.
3381
Also adds the appropriate commands into the undo history.
3382
This function does not call finishChange(), and may leave the text
3383
in an invalid state.
3385
void QQuickTextInputPrivate::internalDelete(bool wasBackspace)
3387
if (m_cursor < (int) m_text.length()) {
3388
cancelPasswordEchoTimer();
3389
if (hasSelectedText())
3390
addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
3391
addCommand(Command((CommandType)((m_maskData ? 2 : 0) + (wasBackspace ? Remove : Delete)),
3392
m_cursor, m_text.at(m_cursor), -1, -1));
3394
m_text.replace(m_cursor, 1, clearString(m_cursor, 1));
3395
addCommand(Command(Insert, m_cursor, m_text.at(m_cursor), -1, -1));
3397
m_text.remove(m_cursor, 1);
3406
removes the currently selected text from the line control.
3408
Also adds the appropriate commands into the undo history.
3409
This function does not call finishChange(), and may leave the text
3410
in an invalid state.
3412
void QQuickTextInputPrivate::removeSelectedText()
3414
if (m_selstart < m_selend && m_selend <= (int) m_text.length()) {
3415
cancelPasswordEchoTimer();
3418
addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
3419
if (m_selstart <= m_cursor && m_cursor < m_selend) {
3420
// cursor is within the selection. Split up the commands
3421
// to be able to restore the correct cursor position
3422
for (i = m_cursor; i >= m_selstart; --i)
3423
addCommand (Command(DeleteSelection, i, m_text.at(i), -1, 1));
3424
for (i = m_selend - 1; i > m_cursor; --i)
3425
addCommand (Command(DeleteSelection, i - m_cursor + m_selstart - 1, m_text.at(i), -1, -1));
3427
for (i = m_selend-1; i >= m_selstart; --i)
3428
addCommand (Command(RemoveSelection, i, m_text.at(i), -1, -1));
3431
m_text.replace(m_selstart, m_selend - m_selstart, clearString(m_selstart, m_selend - m_selstart));
3432
for (int i = 0; i < m_selend - m_selstart; ++i)
3433
addCommand(Command(Insert, m_selstart + i, m_text.at(m_selstart + i), -1, -1));
3435
m_text.remove(m_selstart, m_selend - m_selstart);
3437
if (m_cursor > m_selstart)
3438
m_cursor -= qMin(m_cursor, m_selend) - m_selstart;
3447
Parses the input mask specified by \a maskFields to generate
3448
the mask data used to handle input masks.
3450
void QQuickTextInputPrivate::parseInputMask(const QString &maskFields)
3452
int delimiter = maskFields.indexOf(QLatin1Char(';'));
3453
if (maskFields.isEmpty() || delimiter == 0) {
3455
delete [] m_maskData;
3457
m_maxLength = 32767;
3458
internalSetText(QString());
3463
if (delimiter == -1) {
3464
m_blank = QLatin1Char(' ');
3465
m_inputMask = maskFields;
3467
m_inputMask = maskFields.left(delimiter);
3468
m_blank = (delimiter + 1 < maskFields.length()) ? maskFields[delimiter + 1] : QLatin1Char(' ');
3471
// calculate m_maxLength / m_maskData length
3474
for (int i=0; i<m_inputMask.length(); i++) {
3475
c = m_inputMask.at(i);
3476
if (i > 0 && m_inputMask.at(i-1) == QLatin1Char('\\')) {
3480
if (c != QLatin1Char('\\') && c != QLatin1Char('!') &&
3481
c != QLatin1Char('<') && c != QLatin1Char('>') &&
3482
c != QLatin1Char('{') && c != QLatin1Char('}') &&
3483
c != QLatin1Char('[') && c != QLatin1Char(']'))
3487
delete [] m_maskData;
3488
m_maskData = new MaskInputData[m_maxLength];
3490
MaskInputData::Casemode m = MaskInputData::NoCaseMode;
3493
bool escape = false;
3495
for (int i = 0; i < m_inputMask.length(); i++) {
3496
c = m_inputMask.at(i);
3499
m_maskData[index].maskChar = c;
3500
m_maskData[index].separator = s;
3501
m_maskData[index].caseMode = m;
3504
} else if (c == QLatin1Char('<')) {
3505
m = MaskInputData::Lower;
3506
} else if (c == QLatin1Char('>')) {
3507
m = MaskInputData::Upper;
3508
} else if (c == QLatin1Char('!')) {
3509
m = MaskInputData::NoCaseMode;
3510
} else if (c != QLatin1Char('{') && c != QLatin1Char('}') && c != QLatin1Char('[') && c != QLatin1Char(']')) {
3511
switch (c.unicode()) {
3537
m_maskData[index].maskChar = c;
3538
m_maskData[index].separator = s;
3539
m_maskData[index].caseMode = m;
3544
internalSetText(m_text);
3551
checks if the key is valid compared to the inputMask
3553
bool QQuickTextInputPrivate::isValidInput(QChar key, QChar mask) const
3555
switch (mask.unicode()) {
3561
if (key.isLetter() || key == m_blank)
3565
if (key.isLetterOrNumber())
3569
if (key.isLetterOrNumber() || key == m_blank)
3577
if (key.isPrint() || key == m_blank)
3585
if (key.isNumber() || key == m_blank)
3589
if (key.isNumber() && key.digitValue() > 0)
3593
if ((key.isNumber() && key.digitValue() > 0) || key == m_blank)
3597
if (key.isNumber() || key == QLatin1Char('+') || key == QLatin1Char('-') || key == m_blank)
3601
if (key == QLatin1Char('0') || key == QLatin1Char('1'))
3605
if (key == QLatin1Char('0') || key == QLatin1Char('1') || key == m_blank)
3609
if (key.isNumber() || (key >= QLatin1Char('a') && key <= QLatin1Char('f')) || (key >= QLatin1Char('A') && key <= QLatin1Char('F')))
3613
if (key.isNumber() || (key >= QLatin1Char('a') && key <= QLatin1Char('f')) || (key >= QLatin1Char('A') && key <= QLatin1Char('F')) || key == m_blank)
3625
Returns true if the given text \a str is valid for any
3626
validator or input mask set for the line control.
3628
Otherwise returns false
3630
QQuickTextInputPrivate::ValidatorState QQuickTextInputPrivate::hasAcceptableInput(const QString &str) const
3632
#ifndef QT_NO_VALIDATOR
3633
QString textCopy = str;
3634
int cursorCopy = m_cursor;
3636
QValidator::State state = m_validator->validate(textCopy, cursorCopy);
3637
if (state != QValidator::Acceptable)
3638
return ValidatorState(state);
3643
return AcceptableInput;
3645
if (str.length() != m_maxLength)
3646
return InvalidInput;
3648
for (int i=0; i < m_maxLength; ++i) {
3649
if (m_maskData[i].separator) {
3650
if (str.at(i) != m_maskData[i].maskChar)
3651
return InvalidInput;
3653
if (!isValidInput(str.at(i), m_maskData[i].maskChar))
3654
return InvalidInput;
3657
return AcceptableInput;
3663
Applies the inputMask on \a str starting from position \a pos in the mask. \a clear
3664
specifies from where characters should be gotten when a separator is met in \a str - true means
3665
that blanks will be used, false that previous input is used.
3666
Calling this when no inputMask is set is undefined.
3668
QString QQuickTextInputPrivate::maskString(uint pos, const QString &str, bool clear) const
3670
if (pos >= (uint)m_maxLength)
3671
return QString::fromLatin1("");
3674
fill = clear ? clearString(0, m_maxLength) : m_text;
3677
QString s = QString::fromLatin1("");
3679
while (i < m_maxLength) {
3680
if (strIndex < str.length()) {
3681
if (m_maskData[i].separator) {
3682
s += m_maskData[i].maskChar;
3683
if (str[(int)strIndex] == m_maskData[i].maskChar)
3687
if (isValidInput(str[(int)strIndex], m_maskData[i].maskChar)) {
3688
switch (m_maskData[i].caseMode) {
3689
case MaskInputData::Upper:
3690
s += str[(int)strIndex].toUpper();
3692
case MaskInputData::Lower:
3693
s += str[(int)strIndex].toLower();
3696
s += str[(int)strIndex];
3700
// search for separator first
3701
int n = findInMask(i, true, true, str[(int)strIndex]);
3703
if (str.length() != 1 || i == 0 || (i > 0 && (!m_maskData[i-1].separator || m_maskData[i-1].maskChar != str[(int)strIndex]))) {
3704
s += fill.mid(i, n-i+1);
3705
i = n + 1; // update i to find + 1
3708
// search for valid m_blank if not
3709
n = findInMask(i, true, false, str[(int)strIndex]);
3711
s += fill.mid(i, n-i);
3712
switch (m_maskData[n].caseMode) {
3713
case MaskInputData::Upper:
3714
s += str[(int)strIndex].toUpper();
3716
case MaskInputData::Lower:
3717
s += str[(int)strIndex].toLower();
3720
s += str[(int)strIndex];
3722
i = n + 1; // updates i to find + 1
3740
Returns a "cleared" string with only separators and blank chars.
3741
Calling this when no inputMask is set is undefined.
3743
QString QQuickTextInputPrivate::clearString(uint pos, uint len) const
3745
if (pos >= (uint)m_maxLength)
3749
int end = qMin((uint)m_maxLength, pos + len);
3750
for (int i = pos; i < end; ++i)
3751
if (m_maskData[i].separator)
3752
s += m_maskData[i].maskChar;
3762
Strips blank parts of the input in a QQuickTextInputPrivate when an inputMask is set,
3763
separators are still included. Typically "127.0__.0__.1__" becomes "127.0.0.1".
3765
QString QQuickTextInputPrivate::stripString(const QString &str) const
3771
int end = qMin(m_maxLength, (int)str.length());
3772
for (int i = 0; i < end; ++i) {
3773
if (m_maskData[i].separator)
3774
s += m_maskData[i].maskChar;
3775
else if (str[i] != m_blank)
3784
searches forward/backward in m_maskData for either a separator or a m_blank
3786
int QQuickTextInputPrivate::findInMask(int pos, bool forward, bool findSeparator, QChar searchChar) const
3788
if (pos >= m_maxLength || pos < 0)
3791
int end = forward ? m_maxLength : -1;
3792
int step = forward ? 1 : -1;
3796
if (findSeparator) {
3797
if (m_maskData[i].separator && m_maskData[i].maskChar == searchChar)
3800
if (!m_maskData[i].separator) {
3801
if (searchChar.isNull())
3803
else if (isValidInput(searchChar, m_maskData[i].maskChar))
3812
void QQuickTextInputPrivate::internalUndo(int until)
3814
if (!isUndoAvailable())
3816
cancelPasswordEchoTimer();
3818
while (m_undoState && m_undoState > until) {
3819
Command& cmd = m_history[--m_undoState];
3822
m_text.remove(cmd.pos, 1);
3826
m_selstart = cmd.selStart;
3827
m_selend = cmd.selEnd;
3831
case RemoveSelection:
3832
m_text.insert(cmd.pos, cmd.uc);
3833
m_cursor = cmd.pos + 1;
3836
case DeleteSelection:
3837
m_text.insert(cmd.pos, cmd.uc);
3843
if (until < 0 && m_undoState) {
3844
Command& next = m_history[m_undoState-1];
3845
if (next.type != cmd.type && next.type < RemoveSelection
3846
&& (cmd.type < RemoveSelection || next.type == Separator))
3853
void QQuickTextInputPrivate::internalRedo()
3855
if (!isRedoAvailable())
3858
while (m_undoState < (int)m_history.size()) {
3859
Command& cmd = m_history[m_undoState++];
3862
m_text.insert(cmd.pos, cmd.uc);
3863
m_cursor = cmd.pos + 1;
3866
m_selstart = cmd.selStart;
3867
m_selend = cmd.selEnd;
3872
case RemoveSelection:
3873
case DeleteSelection:
3874
m_text.remove(cmd.pos, 1);
3875
m_selstart = cmd.selStart;
3876
m_selend = cmd.selEnd;
3880
m_selstart = cmd.selStart;
3881
m_selend = cmd.selEnd;
3885
if (m_undoState < (int)m_history.size()) {
3886
Command& next = m_history[m_undoState];
3887
if (next.type != cmd.type && cmd.type < RemoveSelection && next.type != Separator
3888
&& (next.type < RemoveSelection || cmd.type == Separator))
3895
void QQuickTextInputPrivate::emitUndoRedoChanged()
3897
Q_Q(QQuickTextInput);
3898
const bool previousUndo = canUndo;
3899
const bool previousRedo = canRedo;
3901
canUndo = isUndoAvailable();
3902
canRedo = isRedoAvailable();
3904
if (previousUndo != canUndo)
3905
emit q->canUndoChanged();
3906
if (previousRedo != canRedo)
3907
emit q->canRedoChanged();
3913
If the current cursor position differs from the last emitted cursor
3914
position, emits cursorPositionChanged().
3916
bool QQuickTextInputPrivate::emitCursorPositionChanged()
3918
Q_Q(QQuickTextInput);
3919
if (m_cursor != m_lastCursorPos) {
3920
m_lastCursorPos = m_cursor;
3922
q->updateCursorRectangle();
3923
emit q->cursorPositionChanged();
3925
if (!hasSelectedText()) {
3926
if (lastSelectionStart != m_cursor) {
3927
lastSelectionStart = m_cursor;
3928
emit q->selectionStartChanged();
3930
if (lastSelectionEnd != m_cursor) {
3931
lastSelectionEnd = m_cursor;
3932
emit q->selectionEndChanged();
3936
#ifndef QT_NO_ACCESSIBILITY
3937
QAccessibleTextCursorEvent ev(q, m_cursor);
3938
QAccessible::updateAccessibility(&ev);
3947
void QQuickTextInputPrivate::setCursorBlinkPeriod(int msec)
3949
Q_Q(QQuickTextInput);
3950
if (msec == m_blinkPeriod)
3953
q->killTimer(m_blinkTimer);
3956
m_blinkTimer = q->startTimer(msec / 2);
3960
if (m_blinkStatus == 1) {
3961
updateType = UpdatePaintNode;
3965
m_blinkPeriod = msec;
3968
void QQuickTextInput::timerEvent(QTimerEvent *event)
3970
Q_D(QQuickTextInput);
3971
if (event->timerId() == d->m_blinkTimer) {
3972
d->m_blinkStatus = !d->m_blinkStatus;
3973
d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
3975
} else if (event->timerId() == d->m_passwordEchoTimer.timerId()) {
3976
d->m_passwordEchoTimer.stop();
3977
d->updateDisplayText();
3981
void QQuickTextInputPrivate::processKeyEvent(QKeyEvent* event)
3983
Q_Q(QQuickTextInput);
3984
bool inlineCompletionAccepted = false;
3986
if (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return) {
3987
if (hasAcceptableInput(m_text) || fixup()) {
3990
if (inlineCompletionAccepted)
3997
if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit
3998
&& !m_passwordEchoEditing
4000
&& !event->text().isEmpty()
4001
&& !(event->modifiers() & Qt::ControlModifier)) {
4002
// Clear the edit and reset to normal echo mode while editing; the
4003
// echo mode switches back when the edit loses focus
4004
// ### resets current content. dubious code; you can
4005
// navigate with keys up, down, back, and select(?), but if you press
4006
// "left" or "right" it clears?
4007
updatePasswordEchoEditing(true);
4011
bool unknown = false;
4012
bool visual = cursorMoveStyle() == Qt::VisualMoveStyle;
4016
#ifndef QT_NO_SHORTCUT
4017
else if (event == QKeySequence::Undo) {
4020
else if (event == QKeySequence::Redo) {
4023
else if (event == QKeySequence::SelectAll) {
4026
#ifndef QT_NO_CLIPBOARD
4027
else if (event == QKeySequence::Copy) {
4030
else if (event == QKeySequence::Paste) {
4032
QClipboard::Mode mode = QClipboard::Clipboard;
4036
else if (event == QKeySequence::Cut) {
4042
else if (event == QKeySequence::DeleteEndOfLine) {
4044
setSelection(m_cursor, end());
4049
#endif //QT_NO_CLIPBOARD
4050
else if (event == QKeySequence::MoveToStartOfLine || event == QKeySequence::MoveToStartOfBlock) {
4053
else if (event == QKeySequence::MoveToEndOfLine || event == QKeySequence::MoveToEndOfBlock) {
4056
else if (event == QKeySequence::SelectStartOfLine || event == QKeySequence::SelectStartOfBlock) {
4059
else if (event == QKeySequence::SelectEndOfLine || event == QKeySequence::SelectEndOfBlock) {
4062
else if (event == QKeySequence::MoveToNextChar) {
4063
if (hasSelectedText()) {
4064
moveCursor(selectionEnd(), false);
4066
cursorForward(0, visual ? 1 : (layoutDirection() == Qt::LeftToRight ? 1 : -1));
4069
else if (event == QKeySequence::SelectNextChar) {
4070
cursorForward(1, visual ? 1 : (layoutDirection() == Qt::LeftToRight ? 1 : -1));
4072
else if (event == QKeySequence::MoveToPreviousChar) {
4073
if (hasSelectedText()) {
4074
moveCursor(selectionStart(), false);
4076
cursorForward(0, visual ? -1 : (layoutDirection() == Qt::LeftToRight ? -1 : 1));
4079
else if (event == QKeySequence::SelectPreviousChar) {
4080
cursorForward(1, visual ? -1 : (layoutDirection() == Qt::LeftToRight ? -1 : 1));
4082
else if (event == QKeySequence::MoveToNextWord) {
4083
if (m_echoMode == QQuickTextInput::Normal)
4084
layoutDirection() == Qt::LeftToRight ? cursorWordForward(0) : cursorWordBackward(0);
4086
layoutDirection() == Qt::LeftToRight ? end(0) : home(0);
4088
else if (event == QKeySequence::MoveToPreviousWord) {
4089
if (m_echoMode == QQuickTextInput::Normal)
4090
layoutDirection() == Qt::LeftToRight ? cursorWordBackward(0) : cursorWordForward(0);
4091
else if (!m_readOnly) {
4092
layoutDirection() == Qt::LeftToRight ? home(0) : end(0);
4095
else if (event == QKeySequence::SelectNextWord) {
4096
if (m_echoMode == QQuickTextInput::Normal)
4097
layoutDirection() == Qt::LeftToRight ? cursorWordForward(1) : cursorWordBackward(1);
4099
layoutDirection() == Qt::LeftToRight ? end(1) : home(1);
4101
else if (event == QKeySequence::SelectPreviousWord) {
4102
if (m_echoMode == QQuickTextInput::Normal)
4103
layoutDirection() == Qt::LeftToRight ? cursorWordBackward(1) : cursorWordForward(1);
4105
layoutDirection() == Qt::LeftToRight ? home(1) : end(1);
4107
else if (event == QKeySequence::Delete) {
4111
else if (event == QKeySequence::DeleteEndOfWord) {
4113
cursorWordForward(true);
4117
else if (event == QKeySequence::DeleteStartOfWord) {
4119
cursorWordBackward(true);
4123
#endif // QT_NO_SHORTCUT
4125
bool handled = false;
4126
if (event->modifiers() & Qt::ControlModifier) {
4127
switch (event->key()) {
4128
case Qt::Key_Backspace:
4130
cursorWordBackward(true);
4138
} else { // ### check for *no* modifier
4139
switch (event->key()) {
4140
case Qt::Key_Backspace:
4152
if (event->key() == Qt::Key_Direction_L || event->key() == Qt::Key_Direction_R) {
4153
setLayoutDirection((event->key() == Qt::Key_Direction_L) ? Qt::LeftToRight : Qt::RightToLeft);
4157
if (unknown && !m_readOnly) {
4158
QString t = event->text();
4159
if (!t.isEmpty() && t.at(0).isPrint()) {