1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the QtDeclarative module of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** 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/qdeclarativeglobal_p.h>
48 #include <QtDeclarative/qdeclarativeinfo.h>
49 #include <QtGui/qevent.h>
50 #include <QTextBoundaryFinder>
51 #include "qquicktextnode_p.h"
52 #include <QtQuick/qsgsimplerectnode.h>
54 #include <QtGui/qstylehints.h>
55 #include <QtGui/qinputpanel.h>
57 #ifndef QT_NO_ACCESSIBILITY
58 #include "qaccessible.h"
63 DEFINE_BOOL_CONFIG_OPTION(qmlDisableDistanceField, QML_DISABLE_DISTANCEFIELD)
65 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
66 static const int qt_passwordEchoDelay = QT_GUI_PASSWORD_ECHO_DELAY;
70 \qmlclass TextInput QQuickTextInput
71 \inqmlmodule QtQuick 2
72 \ingroup qml-basic-visual-elements
73 \brief The TextInput item displays an editable line of text.
76 The TextInput element displays a single line of editable plain text.
78 TextInput is used to accept a line of text input. Input constraints
79 can be placed on a TextInput item (for example, through a \l validator or \l inputMask),
80 and setting \l echoMode to an appropriate value enables TextInput to be used for
81 a password input field.
83 On Mac OS X, the Up/Down key bindings for Home/End are explicitly disabled.
84 If you want such bindings (on any platform), you will need to construct them in QML.
86 \sa TextEdit, Text, {declarative/text/textselection}{Text Selection example}
88 QQuickTextInput::QQuickTextInput(QQuickItem* parent)
89 : QQuickImplicitSizeItem(*(new QQuickTextInputPrivate), parent)
95 QQuickTextInput::~QQuickTextInput()
99 void QQuickTextInput::componentComplete()
101 Q_D(QQuickTextInput);
103 QQuickImplicitSizeItem::componentComplete();
107 updateCursorRectangle();
108 if (d->cursorComponent && d->cursorComponent->isReady())
113 \qmlproperty string QtQuick2::TextInput::text
115 The text in the TextInput.
117 QString QQuickTextInput::text() const
119 Q_D(const QQuickTextInput);
121 QString content = d->m_text;
122 if (!d->m_tentativeCommit.isEmpty())
123 content.insert(d->m_cursor, d->m_tentativeCommit);
124 QString res = d->m_maskData ? d->stripString(content) : content;
125 return (res.isNull() ? QString::fromLatin1("") : res);
128 void QQuickTextInput::setText(const QString &s)
130 Q_D(QQuickTextInput);
133 if (d->composeMode())
134 qApp->inputPanel()->reset();
135 d->m_tentativeCommit.clear();
136 d->internalSetText(s, -1, false);
140 \qmlproperty int QtQuick2::TextInput::length
142 Returns the total number of characters in the TextInput item.
144 If the TextInput has an inputMask the length will include mask characters and may differ
145 from the length of the string returned by the \l text property.
147 This property can be faster than querying the length the \l text property as it doesn't
148 require any copying or conversion of the TextInput's internal string data.
151 int QQuickTextInput::length() const
153 Q_D(const QQuickTextInput);
154 return d->m_text.length();
158 \qmlmethod string QtQuick2::TextInput::getText(int start, int end)
160 Returns the section of text that is between the \a start and \a end positions.
162 If the TextInput has an inputMask the length will include mask characters.
165 QString QQuickTextInput::getText(int start, int end) const
167 Q_D(const QQuickTextInput);
172 return d->m_text.mid(start, end - start);
175 QString QQuickTextInputPrivate::realText() const
177 QString res = m_maskData ? stripString(m_text) : m_text;
178 return (res.isNull() ? QString::fromLatin1("") : res);
182 \qmlproperty string QtQuick2::TextInput::font.family
184 Sets the family name of the font.
186 The family name is case insensitive and may optionally include a foundry name, e.g. "Helvetica [Cronyx]".
187 If the family is available from more than one foundry and the foundry isn't specified, an arbitrary foundry is chosen.
188 If the family isn't available a family will be set using the font matching algorithm.
192 \qmlproperty bool QtQuick2::TextInput::font.bold
194 Sets whether the font weight is bold.
198 \qmlproperty enumeration QtQuick2::TextInput::font.weight
200 Sets the font's weight.
202 The weight can be one of:
205 \o Font.Normal - the default
212 TextInput { text: "Hello"; font.weight: Font.DemiBold }
217 \qmlproperty bool QtQuick2::TextInput::font.italic
219 Sets whether the font has an italic style.
223 \qmlproperty bool QtQuick2::TextInput::font.underline
225 Sets whether the text is underlined.
229 \qmlproperty bool QtQuick2::TextInput::font.strikeout
231 Sets whether the font has a strikeout style.
235 \qmlproperty real QtQuick2::TextInput::font.pointSize
237 Sets the font size in points. The point size must be greater than zero.
241 \qmlproperty int QtQuick2::TextInput::font.pixelSize
243 Sets the font size in pixels.
245 Using this function makes the font device dependent.
246 Use \c pointSize to set the size of the font in a device independent manner.
250 \qmlproperty real QtQuick2::TextInput::font.letterSpacing
252 Sets the letter spacing for the font.
254 Letter spacing changes the default spacing between individual letters in the font.
255 A positive value increases the letter spacing by the corresponding pixels; a negative value decreases the spacing.
259 \qmlproperty real QtQuick2::TextInput::font.wordSpacing
261 Sets the word spacing for the font.
263 Word spacing changes the default spacing between individual words.
264 A positive value increases the word spacing by a corresponding amount of pixels,
265 while a negative value decreases the inter-word spacing accordingly.
269 \qmlproperty enumeration QtQuick2::TextInput::font.capitalization
271 Sets the capitalization for the text.
274 \o Font.MixedCase - This is the normal text rendering option where no capitalization change is applied.
275 \o Font.AllUppercase - This alters the text to be rendered in all uppercase type.
276 \o Font.AllLowercase - This alters the text to be rendered in all lowercase type.
277 \o Font.SmallCaps - This alters the text to be rendered in small-caps type.
278 \o Font.Capitalize - This alters the text to be rendered with the first character of each word as an uppercase character.
282 TextInput { text: "Hello"; font.capitalization: Font.AllLowercase }
286 QFont QQuickTextInput::font() const
288 Q_D(const QQuickTextInput);
289 return d->sourceFont;
292 void QQuickTextInput::setFont(const QFont &font)
294 Q_D(QQuickTextInput);
295 if (d->sourceFont == font)
298 d->sourceFont = font;
299 QFont oldFont = d->font;
301 if (d->font.pointSizeF() != -1) {
303 qreal size = qRound(d->font.pointSizeF()*2.0);
304 d->font.setPointSizeF(size/2.0);
306 if (oldFont != d->font) {
308 updateCursorRectangle();
309 qApp->inputPanel()->update(Qt::ImCursorRectangle | Qt::ImFont);
311 emit fontChanged(d->sourceFont);
315 \qmlproperty color QtQuick2::TextInput::color
319 QColor QQuickTextInput::color() const
321 Q_D(const QQuickTextInput);
325 void QQuickTextInput::setColor(const QColor &c)
327 Q_D(QQuickTextInput);
330 d->textLayoutDirty = true;
332 emit colorChanged(c);
338 \qmlproperty color QtQuick2::TextInput::selectionColor
340 The text highlight color, used behind selections.
342 QColor QQuickTextInput::selectionColor() const
344 Q_D(const QQuickTextInput);
345 return d->selectionColor;
348 void QQuickTextInput::setSelectionColor(const QColor &color)
350 Q_D(QQuickTextInput);
351 if (d->selectionColor == color)
354 d->selectionColor = color;
355 d->m_palette.setColor(QPalette::Highlight, d->selectionColor);
356 if (d->hasSelectedText()) {
357 d->textLayoutDirty = true;
360 emit selectionColorChanged(color);
363 \qmlproperty color QtQuick2::TextInput::selectedTextColor
365 The highlighted text color, used in selections.
367 QColor QQuickTextInput::selectedTextColor() const
369 Q_D(const QQuickTextInput);
370 return d->selectedTextColor;
373 void QQuickTextInput::setSelectedTextColor(const QColor &color)
375 Q_D(QQuickTextInput);
376 if (d->selectedTextColor == color)
379 d->selectedTextColor = color;
380 d->m_palette.setColor(QPalette::HighlightedText, d->selectedTextColor);
381 if (d->hasSelectedText()) {
382 d->textLayoutDirty = true;
385 emit selectedTextColorChanged(color);
389 \qmlproperty enumeration QtQuick2::TextInput::horizontalAlignment
390 \qmlproperty enumeration QtQuick2::TextInput::effectiveHorizontalAlignment
391 \qmlproperty enumeration QtQuick2::TextInput::verticalAlignment
393 Sets the horizontal alignment of the text within the TextInput item's
394 width and height. By default, the text alignment follows the natural alignment
395 of the text, for example text that is read from left to right will be aligned to
398 TextInput does not have vertical alignment, as the natural height is
399 exactly the height of the single line of text. If you set the height
400 manually to something larger, TextInput will always be top aligned
401 vertically. You can use anchors to align it however you want within
404 The valid values for \c horizontalAlignment are \c TextInput.AlignLeft, \c TextInput.AlignRight and
405 \c TextInput.AlignHCenter.
407 Valid values for \c verticalAlignment are \c TextEdit.AlignTop (default),
408 \c TextEdit.AlignBottom \c TextEdit.AlignVCenter.
410 When using the attached property LayoutMirroring::enabled to mirror application
411 layouts, the horizontal alignment of text will also be mirrored. However, the property
412 \c horizontalAlignment will remain unchanged. To query the effective horizontal alignment
413 of TextInput, use the read-only property \c effectiveHorizontalAlignment.
415 QQuickTextInput::HAlignment QQuickTextInput::hAlign() const
417 Q_D(const QQuickTextInput);
421 void QQuickTextInput::setHAlign(HAlignment align)
423 Q_D(QQuickTextInput);
424 bool forceAlign = d->hAlignImplicit && d->effectiveLayoutMirror;
425 d->hAlignImplicit = false;
426 if (d->setHAlign(align, forceAlign) && isComponentComplete()) {
428 updateCursorRectangle();
432 void QQuickTextInput::resetHAlign()
434 Q_D(QQuickTextInput);
435 d->hAlignImplicit = true;
436 if (d->determineHorizontalAlignment() && isComponentComplete()) {
438 updateCursorRectangle();
442 QQuickTextInput::HAlignment QQuickTextInput::effectiveHAlign() const
444 Q_D(const QQuickTextInput);
445 QQuickTextInput::HAlignment effectiveAlignment = d->hAlign;
446 if (!d->hAlignImplicit && d->effectiveLayoutMirror) {
448 case QQuickTextInput::AlignLeft:
449 effectiveAlignment = QQuickTextInput::AlignRight;
451 case QQuickTextInput::AlignRight:
452 effectiveAlignment = QQuickTextInput::AlignLeft;
458 return effectiveAlignment;
461 bool QQuickTextInputPrivate::setHAlign(QQuickTextInput::HAlignment alignment, bool forceAlign)
463 Q_Q(QQuickTextInput);
464 if ((hAlign != alignment || forceAlign) && alignment <= QQuickTextInput::AlignHCenter) { // justify not supported
465 QQuickTextInput::HAlignment oldEffectiveHAlign = q->effectiveHAlign();
467 emit q->horizontalAlignmentChanged(alignment);
468 if (oldEffectiveHAlign != q->effectiveHAlign())
469 emit q->effectiveHorizontalAlignmentChanged();
475 bool QQuickTextInputPrivate::determineHorizontalAlignment()
477 if (hAlignImplicit) {
478 // if no explicit alignment has been set, follow the natural layout direction of the text
479 QString text = q_func()->text();
481 text = m_textLayout.preeditAreaText();
482 bool isRightToLeft = text.isEmpty() ? qApp->inputPanel()->inputDirection() == Qt::RightToLeft
483 : text.isRightToLeft();
484 return setHAlign(isRightToLeft ? QQuickTextInput::AlignRight : QQuickTextInput::AlignLeft);
489 QQuickTextInput::VAlignment QQuickTextInput::vAlign() const
491 Q_D(const QQuickTextInput);
495 void QQuickTextInput::setVAlign(QQuickTextInput::VAlignment alignment)
497 Q_D(QQuickTextInput);
498 if (alignment == d->vAlign)
500 d->vAlign = alignment;
501 emit verticalAlignmentChanged(d->vAlign);
502 if (isComponentComplete()) {
503 updateCursorRectangle();
508 \qmlproperty enumeration QtQuick2::TextInput::wrapMode
510 Set this property to wrap the text to the TextEdit item's width.
511 The text will only wrap if an explicit width has been set.
514 \o TextInput.NoWrap - no wrapping will be performed. If the text contains insufficient newlines, then implicitWidth will exceed a set width.
515 \o TextInput.WordWrap - wrapping is done on word boundaries only. If a word is too long, implicitWidth will exceed a set width.
516 \o TextInput.WrapAnywhere - wrapping is done at any point on a line, even if it occurs in the middle of a word.
517 \o 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.
520 The default is TextInput.NoWrap. If you set a width, consider using TextInput.Wrap.
522 QQuickTextInput::WrapMode QQuickTextInput::wrapMode() const
524 Q_D(const QQuickTextInput);
528 void QQuickTextInput::setWrapMode(WrapMode mode)
530 Q_D(QQuickTextInput);
531 if (mode == d->wrapMode)
535 updateCursorRectangle();
536 emit wrapModeChanged();
539 void QQuickTextInputPrivate::mirrorChange()
541 Q_Q(QQuickTextInput);
542 if (q->isComponentComplete()) {
543 if (!hAlignImplicit && (hAlign == QQuickTextInput::AlignRight || hAlign == QQuickTextInput::AlignLeft)) {
544 q->updateCursorRectangle();
545 emit q->effectiveHorizontalAlignmentChanged();
551 \qmlproperty bool QtQuick2::TextInput::readOnly
553 Sets whether user input can modify the contents of the TextInput.
555 If readOnly is set to true, then user input will not affect the text
556 property. Any bindings or attempts to set the text property will still
559 bool QQuickTextInput::isReadOnly() const
561 Q_D(const QQuickTextInput);
562 return d->m_readOnly;
565 void QQuickTextInput::setReadOnly(bool ro)
567 Q_D(QQuickTextInput);
568 if (d->m_readOnly == ro)
571 setFlag(QQuickItem::ItemAcceptsInputMethod, !ro);
574 d->setCursorPosition(d->end());
576 d->emitUndoRedoChanged();
577 emit readOnlyChanged(ro);
581 \qmlproperty int QtQuick2::TextInput::maximumLength
582 The maximum permitted length of the text in the TextInput.
584 If the text is too long, it is truncated at the limit.
586 By default, this property contains a value of 32767.
588 int QQuickTextInput::maxLength() const
590 Q_D(const QQuickTextInput);
591 return d->m_maxLength;
594 void QQuickTextInput::setMaxLength(int ml)
596 Q_D(QQuickTextInput);
597 if (d->m_maxLength == ml || d->m_maskData)
601 d->internalSetText(d->m_text, -1, false);
603 emit maximumLengthChanged(ml);
607 \qmlproperty bool QtQuick2::TextInput::cursorVisible
608 Set to true when the TextInput shows a cursor.
610 This property is set and unset when the TextInput gets active focus, so that other
611 properties can be bound to whether the cursor is currently showing. As it
612 gets set and unset automatically, when you set the value yourself you must
613 keep in mind that your value may be overwritten.
615 It can be set directly in script, for example if a KeyProxy might
616 forward keys to it and you desire it to look active when this happens
617 (but without actually giving it active focus).
619 It should not be set directly on the element, like in the below QML,
620 as the specified value will be overridden an lost on focus changes.
629 In the above snippet the cursor will still become visible when the
630 TextInput gains active focus.
632 bool QQuickTextInput::isCursorVisible() const
634 Q_D(const QQuickTextInput);
635 return d->cursorVisible;
638 void QQuickTextInput::setCursorVisible(bool on)
640 Q_D(QQuickTextInput);
641 if (d->cursorVisible == on)
643 d->cursorVisible = on;
644 d->setCursorBlinkPeriod(on ? qApp->styleHints()->cursorFlashTime() : 0);
646 emit cursorVisibleChanged(d->cursorVisible);
650 \qmlproperty int QtQuick2::TextInput::cursorPosition
651 The position of the cursor in the TextInput.
653 int QQuickTextInput::cursorPosition() const
655 Q_D(const QQuickTextInput);
659 void QQuickTextInput::setCursorPosition(int cp)
661 Q_D(QQuickTextInput);
662 if (cp < 0 || cp > text().length())
668 \qmlproperty rectangle QtQuick2::TextInput::cursorRectangle
670 The rectangle where the standard text cursor is rendered within the text input. Read only.
672 The position and height of a custom cursorDelegate are updated to follow the cursorRectangle
673 automatically when it changes. The width of the delegate is unaffected by changes in the
677 QRect QQuickTextInput::cursorRectangle() const
679 Q_D(const QQuickTextInput);
682 if (d->m_preeditCursor != -1)
683 c += d->m_preeditCursor;
684 if (d->m_echoMode == NoEcho)
686 QTextLine l = d->m_textLayout.lineForTextPosition(c);
690 qRound(l.cursorToX(c) - d->hscroll),
691 qRound(l.y() - d->vscroll),
697 \qmlproperty int QtQuick2::TextInput::selectionStart
699 The cursor position before the first character in the current selection.
701 This property is read-only. To change the selection, use select(start,end),
702 selectAll(), or selectWord().
704 \sa selectionEnd, cursorPosition, selectedText
706 int QQuickTextInput::selectionStart() const
708 Q_D(const QQuickTextInput);
709 return d->lastSelectionStart;
712 \qmlproperty int QtQuick2::TextInput::selectionEnd
714 The cursor position after the last character in the current selection.
716 This property is read-only. To change the selection, use select(start,end),
717 selectAll(), or selectWord().
719 \sa selectionStart, cursorPosition, selectedText
721 int QQuickTextInput::selectionEnd() const
723 Q_D(const QQuickTextInput);
724 return d->lastSelectionEnd;
727 \qmlmethod void QtQuick2::TextInput::select(int start, int end)
729 Causes the text from \a start to \a end to be selected.
731 If either start or end is out of range, the selection is not changed.
733 After calling this, selectionStart will become the lesser
734 and selectionEnd will become the greater (regardless of the order passed
737 \sa selectionStart, selectionEnd
739 void QQuickTextInput::select(int start, int end)
741 Q_D(QQuickTextInput);
742 if (start < 0 || end < 0 || start > d->m_text.length() || end > d->m_text.length())
744 d->setSelection(start, end-start);
748 \qmlproperty string QtQuick2::TextInput::selectedText
750 This read-only property provides the text currently selected in the
753 It is equivalent to the following snippet, but is faster and easier
757 myTextInput.text.toString().substring(myTextInput.selectionStart,
758 myTextInput.selectionEnd);
761 QString QQuickTextInput::selectedText() const
763 Q_D(const QQuickTextInput);
764 return d->selectedText();
768 \qmlproperty bool QtQuick2::TextInput::activeFocusOnPress
770 Whether the TextInput should gain active focus on a mouse press. By default this is
773 bool QQuickTextInput::focusOnPress() const
775 Q_D(const QQuickTextInput);
776 return d->focusOnPress;
779 void QQuickTextInput::setFocusOnPress(bool b)
781 Q_D(QQuickTextInput);
782 if (d->focusOnPress == b)
787 emit activeFocusOnPressChanged(d->focusOnPress);
790 \qmlproperty bool QtQuick2::TextInput::autoScroll
792 Whether the TextInput should scroll when the text is longer than the width. By default this is
795 bool QQuickTextInput::autoScroll() const
797 Q_D(const QQuickTextInput);
798 return d->autoScroll;
801 void QQuickTextInput::setAutoScroll(bool b)
803 Q_D(QQuickTextInput);
804 if (d->autoScroll == b)
808 //We need to repaint so that the scrolling is taking into account.
809 updateCursorRectangle();
810 emit autoScrollChanged(d->autoScroll);
813 #ifndef QT_NO_VALIDATOR
816 \qmlclass IntValidator QIntValidator
817 \inqmlmodule QtQuick 2
818 \ingroup qml-basic-visual-elements
820 This element provides a validator for integer values.
822 IntValidator uses the \l {QLocale::setDefault()}{default locale} to interpret the number and
823 will accept locale specific digits, group separators, and positive and negative signs. In
824 addition, IntValidator is always guaranteed to accept a number formatted according to the "C"
828 \qmlproperty int QtQuick2::IntValidator::top
830 This property holds the validator's highest acceptable value.
831 By default, this property's value is derived from the highest signed integer available (typically 2147483647).
834 \qmlproperty int QtQuick2::IntValidator::bottom
836 This property holds the validator's lowest acceptable value.
837 By default, this property's value is derived from the lowest signed integer available (typically -2147483647).
841 \qmlclass DoubleValidator QDoubleValidator
842 \inqmlmodule QtQuick 2
843 \ingroup qml-basic-visual-elements
845 This element provides a validator for non-integer numbers.
847 Input is accepted if it contains a double that is within the valid range
848 and is in the correct format.
850 Input is accepected but invalid if it contains a double that is outside
851 the range or is in the wrong format; e.g. with too many digits after the
852 decimal point or is empty.
854 Input is rejected if it is not a double.
856 Note: If the valid range consists of just positive doubles (e.g. 0.0 to
857 100.0) and input is a negative double then it is rejected. If \l notation
858 is set to DoubleValidator.StandardNotation, and the input contains more
859 digits before the decimal point than a double in the valid range may have,
860 it is also rejected. If \l notation is DoubleValidator.ScientificNotation,
861 and the input is not in the valid range, it is accecpted but invalid. The
862 value may yet become valid by changing the exponent.
866 \qmlproperty real QtQuick2::DoubleValidator::top
868 This property holds the validator's maximum acceptable value.
869 By default, this property contains a value of infinity.
872 \qmlproperty real QtQuick2::DoubleValidator::bottom
874 This property holds the validator's minimum acceptable value.
875 By default, this property contains a value of -infinity.
878 \qmlproperty int QtQuick2::DoubleValidator::decimals
880 This property holds the validator's maximum number of digits after the decimal point.
881 By default, this property contains a value of 1000.
884 \qmlproperty enumeration QtQuick2::DoubleValidator::notation
885 This property holds the notation of how a string can describe a number.
887 The possible values for this property are:
890 \o DoubleValidator.StandardNotation
891 \o DoubleValidator.ScientificNotation (default)
894 If this property is set to DoubleValidator.ScientificNotation, the written number may have an exponent part (e.g. 1.5E-2).
898 \qmlclass RegExpValidator QRegExpValidator
899 \inqmlmodule QtQuick 2
900 \ingroup qml-basic-visual-elements
902 This element provides a validator, which counts as valid any string which
903 matches a specified regular expression.
906 \qmlproperty regExp QtQuick2::RegExpValidator::regExp
908 This property holds the regular expression used for validation.
910 Note that this property should be a regular expression in JS syntax, e.g /a/ for the regular expression
913 By default, this property contains a regular expression with the pattern .* that matches any string.
917 \qmlproperty Validator QtQuick2::TextInput::validator
919 Allows you to set a validator on the TextInput. When a validator is set
920 the TextInput will only accept input which leaves the text property in
921 an acceptable or intermediate state. The accepted signal will only be sent
922 if the text is in an acceptable state when enter is pressed.
924 Currently supported validators are IntValidator, DoubleValidator and
925 RegExpValidator. An example of using validators is shown below, which allows
926 input of integers between 11 and 31 into the text input:
931 validator: IntValidator{bottom: 11; top: 31;}
936 \sa acceptableInput, inputMask
939 QValidator* QQuickTextInput::validator() const
941 Q_D(const QQuickTextInput);
942 return d->m_validator;
945 void QQuickTextInput::setValidator(QValidator* v)
947 Q_D(QQuickTextInput);
948 if (d->m_validator == v)
953 if (isComponentComplete())
956 emit validatorChanged();
959 #endif // QT_NO_VALIDATOR
961 void QQuickTextInputPrivate::checkIsValid()
963 Q_Q(QQuickTextInput);
965 ValidatorState state = hasAcceptableInput(m_text);
966 m_validInput = state != InvalidInput;
967 if (state != AcceptableInput) {
968 if (m_acceptableInput) {
969 m_acceptableInput = false;
970 emit q->acceptableInputChanged();
972 } else if (!m_acceptableInput) {
973 m_acceptableInput = true;
974 emit q->acceptableInputChanged();
979 \qmlproperty string QtQuick2::TextInput::inputMask
981 Allows you to set an input mask on the TextInput, restricting the allowable
982 text inputs. See QLineEdit::inputMask for further details, as the exact
983 same mask strings are used by TextInput.
985 \sa acceptableInput, validator
987 QString QQuickTextInput::inputMask() const
989 Q_D(const QQuickTextInput);
990 return d->inputMask();
993 void QQuickTextInput::setInputMask(const QString &im)
995 Q_D(QQuickTextInput);
996 if (d->inputMask() == im)
1000 emit inputMaskChanged(d->inputMask());
1004 \qmlproperty bool QtQuick2::TextInput::acceptableInput
1006 This property is always true unless a validator or input mask has been set.
1007 If a validator or input mask has been set, this property will only be true
1008 if the current text is acceptable to the validator or input mask as a final
1009 string (not as an intermediate string).
1011 bool QQuickTextInput::hasAcceptableInput() const
1013 Q_D(const QQuickTextInput);
1014 return d->hasAcceptableInput(d->m_text) == QQuickTextInputPrivate::AcceptableInput;
1018 \qmlsignal QtQuick2::TextInput::onAccepted()
1020 This handler is called when the Return or Enter key is pressed.
1021 Note that if there is a \l validator or \l inputMask set on the text
1022 input, the handler will only be emitted if the input is in an acceptable
1026 void QQuickTextInputPrivate::updateInputMethodHints()
1028 Q_Q(QQuickTextInput);
1029 Qt::InputMethodHints hints = inputMethodHints;
1030 if (m_echoMode == QQuickTextInput::Password || m_echoMode == QQuickTextInput::NoEcho)
1031 hints |= Qt::ImhHiddenText;
1032 else if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit)
1033 hints &= ~Qt::ImhHiddenText;
1034 if (m_echoMode != QQuickTextInput::Normal)
1035 hints |= (Qt::ImhNoAutoUppercase | Qt::ImhNoPredictiveText | Qt::ImhSensitiveData);
1036 q->setInputMethodHints(hints);
1039 \qmlproperty enumeration QtQuick2::TextInput::echoMode
1041 Specifies how the text should be displayed in the TextInput.
1043 \o TextInput.Normal - Displays the text as it is. (Default)
1044 \o TextInput.Password - Displays asterisks instead of characters.
1045 \o TextInput.NoEcho - Displays nothing.
1046 \o TextInput.PasswordEchoOnEdit - Displays characters as they are entered
1047 while editing, otherwise displays asterisks.
1050 QQuickTextInput::EchoMode QQuickTextInput::echoMode() const
1052 Q_D(const QQuickTextInput);
1053 return QQuickTextInput::EchoMode(d->m_echoMode);
1056 void QQuickTextInput::setEchoMode(QQuickTextInput::EchoMode echo)
1058 Q_D(QQuickTextInput);
1059 if (echoMode() == echo)
1061 d->cancelPasswordEchoTimer();
1062 d->m_echoMode = echo;
1063 d->m_passwordEchoEditing = false;
1064 d->updateInputMethodHints();
1065 d->updateDisplayText();
1066 updateCursorRectangle();
1068 emit echoModeChanged(echoMode());
1072 \qmlproperty enumeration QtQuick2::TextInput::inputMethodHints
1074 Provides hints to the input method about the expected content of the text input and how it
1077 The value is a bit-wise combination of flags, or Qt.ImhNone if no hints are set.
1079 Flags that alter behaviour are:
1082 \o Qt.ImhHiddenText - Characters should be hidden, as is typically used when entering passwords.
1083 This is automatically set when setting echoMode to \c TextInput.Password.
1084 \o Qt.ImhSensitiveData - Typed text should not be stored by the active input method
1085 in any persistent storage like predictive user dictionary.
1086 \o Qt.ImhNoAutoUppercase - The input method should not try to automatically switch to upper case
1087 when a sentence ends.
1088 \o Qt.ImhPreferNumbers - Numbers are preferred (but not required).
1089 \o Qt.ImhPreferUppercase - Upper case letters are preferred (but not required).
1090 \o Qt.ImhPreferLowercase - Lower case letters are preferred (but not required).
1091 \o Qt.ImhNoPredictiveText - Do not use predictive text (i.e. dictionary lookup) while typing.
1093 \o Qt.ImhDate - The text editor functions as a date field.
1094 \o Qt.ImhTime - The text editor functions as a time field.
1097 Flags that restrict input (exclusive flags) are:
1100 \o Qt.ImhDigitsOnly - Only digits are allowed.
1101 \o Qt.ImhFormattedNumbersOnly - Only number input is allowed. This includes decimal point and minus sign.
1102 \o Qt.ImhUppercaseOnly - Only upper case letter input is allowed.
1103 \o Qt.ImhLowercaseOnly - Only lower case letter input is allowed.
1104 \o Qt.ImhDialableCharactersOnly - Only characters suitable for phone dialing are allowed.
1105 \o Qt.ImhEmailCharactersOnly - Only characters suitable for email addresses are allowed.
1106 \o Qt.ImhUrlCharactersOnly - Only characters suitable for URLs are allowed.
1112 \o Qt.ImhExclusiveInputMask - This mask yields nonzero if any of the exclusive flags are used.
1116 Qt::InputMethodHints QQuickTextInput::imHints() const
1118 Q_D(const QQuickTextInput);
1119 return d->inputMethodHints;
1122 void QQuickTextInput::setIMHints(Qt::InputMethodHints hints)
1124 Q_D(QQuickTextInput);
1125 if (d->inputMethodHints == hints)
1127 d->inputMethodHints = hints;
1128 d->updateInputMethodHints();
1132 \qmlproperty Component QtQuick2::TextInput::cursorDelegate
1133 The delegate for the cursor in the TextInput.
1135 If you set a cursorDelegate for a TextInput, this delegate will be used for
1136 drawing the cursor instead of the standard cursor. An instance of the
1137 delegate will be created and managed by the TextInput when a cursor is
1138 needed, and the x property of delegate instance will be set so as
1139 to be one pixel before the top left of the current character.
1141 Note that the root item of the delegate component must be a QDeclarativeItem or
1142 QDeclarativeItem derived item.
1144 QDeclarativeComponent* QQuickTextInput::cursorDelegate() const
1146 Q_D(const QQuickTextInput);
1147 return d->cursorComponent;
1150 void QQuickTextInput::setCursorDelegate(QDeclarativeComponent* c)
1152 Q_D(QQuickTextInput);
1153 if (d->cursorComponent == c)
1156 d->cursorComponent = c;
1158 //note that the components are owned by something else
1159 delete d->cursorItem;
1161 d->startCreatingCursor();
1164 emit cursorDelegateChanged();
1167 void QQuickTextInputPrivate::startCreatingCursor()
1169 Q_Q(QQuickTextInput);
1170 if (cursorComponent->isReady()) {
1172 } else if (cursorComponent->isLoading()) {
1173 q->connect(cursorComponent, SIGNAL(statusChanged(int)),
1174 q, SLOT(createCursor()));
1176 qmlInfo(q, cursorComponent->errors()) << QQuickTextInput::tr("Could not load cursor delegate");
1180 void QQuickTextInput::createCursor()
1182 Q_D(QQuickTextInput);
1183 if (!isComponentComplete())
1186 if (d->cursorComponent->isError()) {
1187 qmlInfo(this, d->cursorComponent->errors()) << tr("Could not load cursor delegate");
1191 if (!d->cursorComponent->isReady())
1195 delete d->cursorItem;
1196 QDeclarativeContext *creationContext = d->cursorComponent->creationContext();
1197 QObject *object = d->cursorComponent->create(creationContext ? creationContext : qmlContext(this));
1198 d->cursorItem = qobject_cast<QQuickItem*>(object);
1199 if (!d->cursorItem) {
1201 qmlInfo(this, d->cursorComponent->errors()) << tr("Could not instantiate cursor delegate");
1205 QRectF r = cursorRectangle();
1207 QDeclarative_setParent_noEvent(d->cursorItem, this);
1208 d->cursorItem->setParentItem(this);
1209 d->cursorItem->setPos(r.topLeft());
1210 d->cursorItem->setHeight(r.height());
1214 \qmlmethod rect QtQuick2::TextInput::positionToRectangle(int pos)
1216 This function takes a character position and returns the rectangle that the
1217 cursor would occupy, if it was placed at that character position.
1219 This is similar to setting the cursorPosition, and then querying the cursor
1220 rectangle, but the cursorPosition is not changed.
1222 QRectF QQuickTextInput::positionToRectangle(int pos) const
1224 Q_D(const QQuickTextInput);
1225 if (pos > d->m_cursor)
1226 pos += d->preeditAreaText().length();
1227 QTextLine l = d->m_textLayout.lineAt(0);
1229 ? QRectF(l.cursorToX(pos) - d->hscroll, 0.0, d->m_cursorWidth, l.height())
1234 \qmlmethod int QtQuick2::TextInput::positionAt(real x, real y, CursorPosition position = CursorBetweenCharacters)
1236 This function returns the character position at
1237 x and y pixels from the top left of the textInput. Position 0 is before the
1238 first character, position 1 is after the first character but before the second,
1239 and so on until position text.length, which is after all characters.
1241 This means that for all x values before the first character this function returns 0,
1242 and for all x values after the last character this function returns text.length. If
1243 the y value is above the text the position will be that of the nearest character on
1244 the first line line and if it is below the text the position of the nearest character
1245 on the last line will be returned.
1247 The cursor position type specifies how the cursor position should be resolved.
1250 \o TextInput.CursorBetweenCharacters - Returns the position between characters that is nearest x.
1251 \o TextInput.CursorOnCharacter - Returns the position before the character that is nearest x.
1255 void QQuickTextInput::positionAt(QDeclarativeV8Function *args) const
1257 Q_D(const QQuickTextInput);
1261 QTextLine::CursorPosition position = QTextLine::CursorBetweenCharacters;
1263 if (args->Length() < 1)
1267 v8::Local<v8::Value> arg = (*args)[i];
1268 x = arg->NumberValue();
1270 if (++i < args->Length()) {
1272 y = arg->NumberValue();
1275 if (++i < args->Length()) {
1277 position = QTextLine::CursorPosition(arg->Int32Value());
1280 int pos = d->positionAt(x, y, position);
1281 const int cursor = d->m_cursor;
1283 const int preeditLength = d->preeditAreaText().length();
1284 pos = pos > cursor + preeditLength
1285 ? pos - preeditLength
1288 args->returnValue(v8::Int32::New(pos));
1291 int QQuickTextInputPrivate::positionAt(int x, int y, QTextLine::CursorPosition position) const
1295 QTextLine line = m_textLayout.lineAt(0);
1296 for (int i = 1; i < m_textLayout.lineCount(); ++i) {
1297 QTextLine nextLine = m_textLayout.lineAt(i);
1299 if (y < (line.rect().bottom() + nextLine.y()) / 2)
1303 return line.isValid() ? line.xToCursor(x, position) : 0;
1306 void QQuickTextInput::keyPressEvent(QKeyEvent* ev)
1308 Q_D(QQuickTextInput);
1309 // Don't allow MacOSX up/down support, and we don't allow a completer.
1310 bool ignore = (ev->key() == Qt::Key_Up || ev->key() == Qt::Key_Down) && ev->modifiers() == Qt::NoModifier;
1311 if (!ignore && (d->lastSelectionStart == d->lastSelectionEnd) && (ev->key() == Qt::Key_Right || ev->key() == Qt::Key_Left)) {
1312 // Ignore when moving off the end unless there is a selection,
1313 // because then moving will do something (deselect).
1314 int cursorPosition = d->m_cursor;
1315 if (cursorPosition == 0)
1316 ignore = ev->key() == (d->layoutDirection() == Qt::LeftToRight ? Qt::Key_Left : Qt::Key_Right);
1317 if (cursorPosition == text().length())
1318 ignore = ev->key() == (d->layoutDirection() == Qt::LeftToRight ? Qt::Key_Right : Qt::Key_Left);
1323 d->processKeyEvent(ev);
1325 if (!ev->isAccepted())
1326 QQuickImplicitSizeItem::keyPressEvent(ev);
1329 void QQuickTextInput::inputMethodEvent(QInputMethodEvent *ev)
1331 Q_D(QQuickTextInput);
1332 const bool wasComposing = d->preeditAreaText().length() > 0;
1333 if (d->m_readOnly) {
1336 d->processInputMethodEvent(ev);
1338 if (!ev->isAccepted())
1339 QQuickImplicitSizeItem::inputMethodEvent(ev);
1341 if (wasComposing != (d->m_textLayout.preeditAreaText().length() > 0))
1342 emit inputMethodComposingChanged();
1345 void QQuickTextInput::mouseDoubleClickEvent(QMouseEvent *event)
1347 Q_D(QQuickTextInput);
1349 if (d->selectByMouse && event->button() == Qt::LeftButton) {
1351 int cursor = d->positionAt(event->localPos());
1352 d->selectWordAtPos(cursor);
1353 event->setAccepted(true);
1354 if (!d->hasPendingTripleClick()) {
1355 d->tripleClickStartPoint = event->localPos().toPoint();
1356 d->tripleClickTimer.start();
1359 if (d->sendMouseEventToInputContext(event))
1361 QQuickImplicitSizeItem::mouseDoubleClickEvent(event);
1365 void QQuickTextInput::mousePressEvent(QMouseEvent *event)
1367 Q_D(QQuickTextInput);
1369 d->pressPos = event->localPos();
1371 if (d->focusOnPress) {
1372 bool hadActiveFocus = hasActiveFocus();
1374 // re-open input panel on press if already focused
1375 if (hasActiveFocus() && hadActiveFocus && !d->m_readOnly)
1376 openSoftwareInputPanel();
1378 if (d->selectByMouse) {
1379 setKeepMouseGrab(false);
1380 d->selectPressed = true;
1381 QPoint distanceVector = d->pressPos.toPoint() - d->tripleClickStartPoint;
1382 if (d->hasPendingTripleClick()
1383 && distanceVector.manhattanLength() < qApp->styleHints()->startDragDistance()) {
1384 event->setAccepted(true);
1390 if (d->sendMouseEventToInputContext(event))
1393 bool mark = (event->modifiers() & Qt::ShiftModifier) && d->selectByMouse;
1394 int cursor = d->positionAt(event->localPos());
1395 d->moveCursor(cursor, mark);
1396 event->setAccepted(true);
1399 void QQuickTextInput::mouseMoveEvent(QMouseEvent *event)
1401 Q_D(QQuickTextInput);
1403 if (d->selectPressed) {
1404 if (qAbs(int(event->localPos().x() - d->pressPos.x())) > qApp->styleHints()->startDragDistance())
1405 setKeepMouseGrab(true);
1407 if (d->composeMode()) {
1409 int startPos = d->positionAt(d->pressPos);
1410 int currentPos = d->positionAt(event->localPos());
1411 if (startPos != currentPos)
1412 d->setSelection(startPos, currentPos - startPos);
1414 moveCursorSelection(d->positionAt(event->localPos()), d->mouseSelectionMode);
1416 event->setAccepted(true);
1418 QQuickImplicitSizeItem::mouseMoveEvent(event);
1422 void QQuickTextInput::mouseReleaseEvent(QMouseEvent *event)
1424 Q_D(QQuickTextInput);
1425 if (d->sendMouseEventToInputContext(event))
1427 if (d->selectPressed) {
1428 d->selectPressed = false;
1429 setKeepMouseGrab(false);
1431 #ifndef QT_NO_CLIPBOARD
1432 if (QGuiApplication::clipboard()->supportsSelection()) {
1433 if (event->button() == Qt::LeftButton) {
1434 d->copy(QClipboard::Selection);
1435 } else if (!d->m_readOnly && event->button() == Qt::MidButton) {
1437 d->insert(QGuiApplication::clipboard()->text(QClipboard::Selection));
1441 if (!event->isAccepted())
1442 QQuickImplicitSizeItem::mouseReleaseEvent(event);
1445 bool QQuickTextInputPrivate::sendMouseEventToInputContext(QMouseEvent *event)
1447 #if !defined QT_NO_IM
1448 if (composeMode()) {
1449 int tmp_cursor = positionAt(event->localPos());
1450 int mousePos = tmp_cursor - m_cursor;
1451 if (mousePos >= 0 && mousePos <= m_textLayout.preeditAreaText().length()) {
1452 if (event->type() == QEvent::MouseButtonRelease) {
1453 qApp->inputPanel()->invokeAction(QInputPanel::Click, mousePos);
1466 void QQuickTextInput::mouseUngrabEvent()
1468 Q_D(QQuickTextInput);
1469 d->selectPressed = false;
1470 setKeepMouseGrab(false);
1473 bool QQuickTextInput::event(QEvent* ev)
1475 #ifndef QT_NO_SHORTCUT
1476 Q_D(QQuickTextInput);
1477 if (ev->type() == QEvent::ShortcutOverride) {
1480 QKeyEvent* ke = static_cast<QKeyEvent*>(ev);
1481 if (ke == QKeySequence::Copy
1482 || ke == QKeySequence::Paste
1483 || ke == QKeySequence::Cut
1484 || ke == QKeySequence::Redo
1485 || ke == QKeySequence::Undo
1486 || ke == QKeySequence::MoveToNextWord
1487 || ke == QKeySequence::MoveToPreviousWord
1488 || ke == QKeySequence::MoveToStartOfDocument
1489 || ke == QKeySequence::MoveToEndOfDocument
1490 || ke == QKeySequence::SelectNextWord
1491 || ke == QKeySequence::SelectPreviousWord
1492 || ke == QKeySequence::SelectStartOfLine
1493 || ke == QKeySequence::SelectEndOfLine
1494 || ke == QKeySequence::SelectStartOfBlock
1495 || ke == QKeySequence::SelectEndOfBlock
1496 || ke == QKeySequence::SelectStartOfDocument
1497 || ke == QKeySequence::SelectAll
1498 || ke == QKeySequence::SelectEndOfDocument) {
1500 } else if (ke->modifiers() == Qt::NoModifier || ke->modifiers() == Qt::ShiftModifier
1501 || ke->modifiers() == Qt::KeypadModifier) {
1502 if (ke->key() < Qt::Key_Escape) {
1506 switch (ke->key()) {
1507 case Qt::Key_Delete:
1510 case Qt::Key_Backspace:
1522 return QQuickImplicitSizeItem::event(ev);
1525 void QQuickTextInput::geometryChanged(const QRectF &newGeometry,
1526 const QRectF &oldGeometry)
1528 Q_D(QQuickTextInput);
1529 if (newGeometry.width() != oldGeometry.width())
1531 updateCursorRectangle();
1532 QQuickImplicitSizeItem::geometryChanged(newGeometry, oldGeometry);
1535 void QQuickTextInputPrivate::updateHorizontalScroll()
1537 Q_Q(QQuickTextInput);
1538 QTextLine currentLine = m_textLayout.lineForTextPosition(m_cursor + m_preeditCursor);
1539 const int preeditLength = m_textLayout.preeditAreaText().length();
1540 const int width = qMax(0, qFloor(q->width()));
1541 int widthUsed = currentLine.isValid() ? qRound(currentLine.naturalTextWidth()) : 0;
1542 int previousScroll = hscroll;
1544 if (!autoScroll || widthUsed <= width || m_echoMode == QQuickTextInput::NoEcho) {
1547 Q_ASSERT(currentLine.isValid());
1548 int cix = qRound(currentLine.cursorToX(m_cursor + preeditLength));
1549 if (cix - hscroll >= width) {
1550 // text doesn't fit, cursor is to the right of br (scroll right)
1551 hscroll = cix - width;
1552 } else if (cix - hscroll < 0 && hscroll < widthUsed) {
1553 // text doesn't fit, cursor is to the left of br (scroll left)
1555 } else if (widthUsed - hscroll < width) {
1556 // text doesn't fit, text document is to the left of br; align
1558 hscroll = widthUsed - width;
1560 if (preeditLength > 0) {
1561 // check to ensure long pre-edit text doesn't push the cursor
1563 cix = qRound(currentLine.cursorToX(m_cursor + qMax(0, m_preeditCursor - 1)));
1568 if (previousScroll != hscroll)
1569 textLayoutDirty = true;
1572 void QQuickTextInputPrivate::updateVerticalScroll()
1574 Q_Q(QQuickTextInput);
1575 const int preeditLength = m_textLayout.preeditAreaText().length();
1576 const int height = qMax(0, qFloor(q->height()));
1577 int heightUsed = boundingRect.height();
1578 int previousScroll = vscroll;
1580 if (!autoScroll || heightUsed <= height) {
1581 // text fits in br; use vscroll for alignment
1582 switch (vAlign & ~(Qt::AlignAbsolute|Qt::AlignHorizontal_Mask)) {
1583 case Qt::AlignBottom:
1584 vscroll = heightUsed - height;
1586 case Qt::AlignVCenter:
1587 vscroll = (heightUsed - height) / 2;
1595 QTextLine currentLine = m_textLayout.lineForTextPosition(m_cursor + preeditLength);
1596 QRectF r = currentLine.isValid() ? currentLine.rect() : QRectF();
1597 int top = qFloor(r.top());
1598 int bottom = qCeil(r.bottom());
1600 if (bottom - vscroll >= height) {
1601 // text doesn't fit, cursor is to the below the br (scroll down)
1602 vscroll = bottom - height;
1603 } else if (top - vscroll < 0 && vscroll < heightUsed) {
1604 // text doesn't fit, cursor is above br (scroll up)
1606 } else if (heightUsed - vscroll < height) {
1607 // text doesn't fit, text document is to the left of br; align
1609 vscroll = heightUsed - height;
1611 if (preeditLength > 0) {
1612 // check to ensure long pre-edit text doesn't push the cursor
1614 currentLine = m_textLayout.lineForTextPosition(m_cursor + qMax(0, m_preeditCursor - 1));
1615 top = currentLine.isValid() ? qRound(currentLine.rect().top()) : 0;
1620 if (previousScroll != vscroll)
1621 textLayoutDirty = true;
1624 QSGNode *QQuickTextInput::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data)
1627 Q_D(QQuickTextInput);
1629 QQuickTextNode *node = static_cast<QQuickTextNode *>(oldNode);
1631 node = new QQuickTextNode(QQuickItemPrivate::get(this)->sceneGraphContext());
1634 if (!d->textLayoutDirty) {
1635 QSGSimpleRectNode *cursorNode = node->cursorNode();
1636 if (cursorNode != 0 && !isReadOnly()) {
1637 cursorNode->setRect(cursorRectangle());
1639 if (!d->cursorVisible || (!d->m_blinkStatus && d->m_blinkPeriod > 0)) {
1646 node->deleteContent();
1647 node->setMatrix(QMatrix4x4());
1649 QPoint offset = QPoint(0,0);
1650 QFontMetrics fm = QFontMetrics(d->font);
1651 if (d->autoScroll) {
1652 // the y offset is there to keep the baseline constant in case we have script changes in the text.
1653 offset = -QPoint(d->hscroll, d->vscroll + d->m_ascent - fm.ascent());
1655 offset = -QPoint(d->hscroll, d->vscroll);
1658 if (!d->m_textLayout.text().isEmpty() || !d->m_textLayout.preeditAreaText().isEmpty()) {
1659 node->addTextLayout(offset, &d->m_textLayout, d->color,
1660 QQuickText::Normal, QColor(),
1661 d->selectionColor, d->selectedTextColor,
1662 d->selectionStart(),
1663 d->selectionEnd() - 1); // selectionEnd() returns first char after
1667 if (!isReadOnly() && d->cursorItem == 0) {
1668 node->setCursor(cursorRectangle(), d->color);
1669 if (!d->cursorVisible || (!d->m_blinkStatus && d->m_blinkPeriod > 0)) {
1676 d->textLayoutDirty = false;
1682 QVariant QQuickTextInput::inputMethodQuery(Qt::InputMethodQuery property) const
1684 Q_D(const QQuickTextInput);
1687 return QVariant((bool)(flags() & ItemAcceptsInputMethod));
1689 return QVariant((int)inputMethodHints());
1690 case Qt::ImCursorRectangle:
1691 return cursorRectangle();
1694 case Qt::ImCursorPosition:
1695 return QVariant(d->m_cursor);
1696 case Qt::ImSurroundingText:
1697 if (d->m_echoMode == PasswordEchoOnEdit && !d->m_passwordEchoEditing) {
1698 return QVariant(displayText());
1700 return QVariant(d->realText());
1702 case Qt::ImCurrentSelection:
1703 return QVariant(selectedText());
1704 case Qt::ImMaximumTextLength:
1705 return QVariant(maxLength());
1706 case Qt::ImAnchorPosition:
1707 if (d->selectionStart() == d->selectionEnd())
1708 return QVariant(d->m_cursor);
1709 else if (d->selectionStart() == d->m_cursor)
1710 return QVariant(d->selectionEnd());
1712 return QVariant(d->selectionStart());
1719 \qmlmethod void QtQuick2::TextInput::deselect()
1721 Removes active text selection.
1723 void QQuickTextInput::deselect()
1725 Q_D(QQuickTextInput);
1730 \qmlmethod void QtQuick2::TextInput::selectAll()
1732 Causes all text to be selected.
1734 void QQuickTextInput::selectAll()
1736 Q_D(QQuickTextInput);
1737 d->setSelection(0, text().length());
1741 \qmlmethod void QtQuick2::TextInput::isRightToLeft(int start, int end)
1743 Returns true if the natural reading direction of the editor text
1744 found between positions \a start and \a end is right to left.
1746 bool QQuickTextInput::isRightToLeft(int start, int end)
1749 qmlInfo(this) << "isRightToLeft(start, end) called with the end property being smaller than the start.";
1752 return text().mid(start, end - start).isRightToLeft();
1756 #ifndef QT_NO_CLIPBOARD
1758 \qmlmethod QtQuick2::TextInput::cut()
1760 Moves the currently selected text to the system clipboard.
1762 void QQuickTextInput::cut()
1764 Q_D(QQuickTextInput);
1770 \qmlmethod QtQuick2::TextInput::copy()
1772 Copies the currently selected text to the system clipboard.
1774 void QQuickTextInput::copy()
1776 Q_D(QQuickTextInput);
1781 \qmlmethod QtQuick2::TextInput::paste()
1783 Replaces the currently selected text by the contents of the system clipboard.
1785 void QQuickTextInput::paste()
1787 Q_D(QQuickTextInput);
1791 #endif // QT_NO_CLIPBOARD
1794 Undoes the last operation if undo is \l {canUndo}{available}. Deselects any
1795 current selection, and updates the selection start to the current cursor
1799 void QQuickTextInput::undo()
1801 Q_D(QQuickTextInput);
1802 if (!d->m_readOnly) {
1804 d->finishChange(-1, true);
1809 Redoes the last operation if redo is \l {canRedo}{available}.
1812 void QQuickTextInput::redo()
1814 Q_D(QQuickTextInput);
1815 if (!d->m_readOnly) {
1822 \qmlmethod void QtQuick2::TextInput::insert(int position, string text)
1824 Inserts \a text into the TextInput at position.
1827 void QQuickTextInput::insert(int position, const QString &text)
1829 Q_D(QQuickTextInput);
1830 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
1831 if (d->m_echoMode == QQuickTextInput::Password)
1832 d->m_passwordEchoTimer.start(qt_passwordEchoDelay, this);
1835 if (position < 0 || position > d->m_text.length())
1838 const int priorState = d->m_undoState;
1840 QString insertText = text;
1842 if (d->hasSelectedText()) {
1843 d->addCommand(QQuickTextInputPrivate::Command(
1844 QQuickTextInputPrivate::SetSelection, d->m_cursor, 0, d->m_selstart, d->m_selend));
1846 if (d->m_maskData) {
1847 insertText = d->maskString(position, insertText);
1848 for (int i = 0; i < insertText.length(); ++i) {
1849 d->addCommand(QQuickTextInputPrivate::Command(
1850 QQuickTextInputPrivate::DeleteSelection, position + i, d->m_text.at(position + i), -1, -1));
1851 d->addCommand(QQuickTextInputPrivate::Command(
1852 QQuickTextInputPrivate::Insert, position + i, insertText.at(i), -1, -1));
1854 d->m_text.replace(position, insertText.length(), insertText);
1855 if (!insertText.isEmpty())
1856 d->m_textDirty = true;
1857 if (position < d->m_selend && position + insertText.length() > d->m_selstart)
1858 d->m_selDirty = true;
1860 int remaining = d->m_maxLength - d->m_text.length();
1861 if (remaining != 0) {
1862 insertText = insertText.left(remaining);
1863 d->m_text.insert(position, insertText);
1864 for (int i = 0; i < insertText.length(); ++i)
1865 d->addCommand(QQuickTextInputPrivate::Command(
1866 QQuickTextInputPrivate::Insert, position + i, insertText.at(i), -1, -1));
1867 if (d->m_cursor >= position)
1868 d->m_cursor += insertText.length();
1869 if (d->m_selstart >= position)
1870 d->m_selstart += insertText.length();
1871 if (d->m_selend >= position)
1872 d->m_selend += insertText.length();
1873 d->m_textDirty = true;
1874 if (position >= d->m_selstart && position <= d->m_selend)
1875 d->m_selDirty = true;
1879 d->addCommand(QQuickTextInputPrivate::Command(
1880 QQuickTextInputPrivate::SetSelection, d->m_cursor, 0, d->m_selstart, d->m_selend));
1881 d->finishChange(priorState);
1883 if (d->lastSelectionStart != d->lastSelectionEnd) {
1884 if (d->m_selstart != d->lastSelectionStart) {
1885 d->lastSelectionStart = d->m_selstart;
1886 emit selectionStartChanged();
1888 if (d->m_selend != d->lastSelectionEnd) {
1889 d->lastSelectionEnd = d->m_selend;
1890 emit selectionEndChanged();
1896 \qmlmethod string QtQuick2::TextInput::getText(int start, int end)
1898 Removes the section of text that is between the \a start and \a end positions from the TextInput.
1901 void QQuickTextInput::remove(int start, int end)
1903 Q_D(QQuickTextInput);
1905 start = qBound(0, start, d->m_text.length());
1906 end = qBound(0, end, d->m_text.length());
1910 else if (start == end)
1913 if (start < d->m_selend && end > d->m_selstart)
1914 d->m_selDirty = true;
1916 const int priorState = d->m_undoState;
1918 d->addCommand(QQuickTextInputPrivate::Command(
1919 QQuickTextInputPrivate::SetSelection, d->m_cursor, 0, d->m_selstart, d->m_selend));
1921 if (start <= d->m_cursor && d->m_cursor < end) {
1922 // cursor is within the selection. Split up the commands
1923 // to be able to restore the correct cursor position
1924 for (int i = d->m_cursor; i >= start; --i) {
1925 d->addCommand(QQuickTextInputPrivate::Command(
1926 QQuickTextInputPrivate::DeleteSelection, i, d->m_text.at(i), -1, 1));
1928 for (int i = end - 1; i > d->m_cursor; --i) {
1929 d->addCommand(QQuickTextInputPrivate::Command(
1930 QQuickTextInputPrivate::DeleteSelection, i - d->m_cursor + start - 1, d->m_text.at(i), -1, -1));
1933 for (int i = end - 1; i >= start; --i) {
1934 d->addCommand(QQuickTextInputPrivate::Command(
1935 QQuickTextInputPrivate::RemoveSelection, i, d->m_text.at(i), -1, -1));
1938 if (d->m_maskData) {
1939 d->m_text.replace(start, end - start, d->clearString(start, end - start));
1940 for (int i = 0; i < end - start; ++i) {
1941 d->addCommand(QQuickTextInputPrivate::Command(
1942 QQuickTextInputPrivate::Insert, start + i, d->m_text.at(start + i), -1, -1));
1945 d->m_text.remove(start, end - start);
1947 if (d->m_cursor > start)
1948 d->m_cursor -= qMin(d->m_cursor, end) - start;
1949 if (d->m_selstart > start)
1950 d->m_selstart -= qMin(d->m_selstart, end) - start;
1951 if (d->m_selend > end)
1952 d->m_selend -= qMin(d->m_selend, end) - start;
1954 d->addCommand(QQuickTextInputPrivate::Command(
1955 QQuickTextInputPrivate::SetSelection, d->m_cursor, 0, d->m_selstart, d->m_selend));
1957 d->m_textDirty = true;
1958 d->finishChange(priorState);
1960 if (d->lastSelectionStart != d->lastSelectionEnd) {
1961 if (d->m_selstart != d->lastSelectionStart) {
1962 d->lastSelectionStart = d->m_selstart;
1963 emit selectionStartChanged();
1965 if (d->m_selend != d->lastSelectionEnd) {
1966 d->lastSelectionEnd = d->m_selend;
1967 emit selectionEndChanged();
1974 \qmlmethod void QtQuick2::TextInput::selectWord()
1976 Causes the word closest to the current cursor position to be selected.
1978 void QQuickTextInput::selectWord()
1980 Q_D(QQuickTextInput);
1981 d->selectWordAtPos(d->m_cursor);
1985 \qmlproperty bool QtQuick2::TextInput::smooth
1987 This property holds whether the text is smoothly scaled or transformed.
1989 Smooth filtering gives better visual quality, but is slower. If
1990 the item is displayed at its natural size, this property has no visual or
1993 \note Generally scaling artifacts are only visible if the item is stationary on
1994 the screen. A common pattern when animating an item is to disable smooth
1995 filtering at the beginning of the animation and reenable it at the conclusion.
1999 \qmlproperty string QtQuick2::TextInput::passwordCharacter
2001 This is the character displayed when echoMode is set to Password or
2002 PasswordEchoOnEdit. By default it is an asterisk.
2004 If this property is set to a string with more than one character,
2005 the first character is used. If the string is empty, the value
2006 is ignored and the property is not set.
2008 QString QQuickTextInput::passwordCharacter() const
2010 Q_D(const QQuickTextInput);
2011 return QString(d->m_passwordCharacter);
2014 void QQuickTextInput::setPasswordCharacter(const QString &str)
2016 Q_D(QQuickTextInput);
2017 if (str.length() < 1)
2019 d->m_passwordCharacter = str.constData()[0];
2020 if (d->m_echoMode == Password || d->m_echoMode == PasswordEchoOnEdit)
2021 d->updateDisplayText();
2022 emit passwordCharacterChanged();
2026 \qmlproperty string QtQuick2::TextInput::displayText
2028 This is the text displayed in the TextInput.
2030 If \l echoMode is set to TextInput::Normal, this holds the
2031 same value as the TextInput::text property. Otherwise,
2032 this property holds the text visible to the user, while
2033 the \l text property holds the actual entered text.
2035 QString QQuickTextInput::displayText() const
2037 Q_D(const QQuickTextInput);
2038 return d->m_textLayout.text();
2042 \qmlproperty bool QtQuick2::TextInput::selectByMouse
2046 If true, the user can use the mouse to select text in some
2047 platform-specific way. Note that for some platforms this may
2048 not be an appropriate interaction (eg. may conflict with how
2049 the text needs to behave inside a Flickable.
2051 bool QQuickTextInput::selectByMouse() const
2053 Q_D(const QQuickTextInput);
2054 return d->selectByMouse;
2057 void QQuickTextInput::setSelectByMouse(bool on)
2059 Q_D(QQuickTextInput);
2060 if (d->selectByMouse != on) {
2061 d->selectByMouse = on;
2062 emit selectByMouseChanged(on);
2067 \qmlproperty enum QtQuick2::TextInput::mouseSelectionMode
2069 Specifies how text should be selected using a mouse.
2072 \o TextInput.SelectCharacters - The selection is updated with individual characters. (Default)
2073 \o TextInput.SelectWords - The selection is updated with whole words.
2076 This property only applies when \l selectByMouse is true.
2079 QQuickTextInput::SelectionMode QQuickTextInput::mouseSelectionMode() const
2081 Q_D(const QQuickTextInput);
2082 return d->mouseSelectionMode;
2085 void QQuickTextInput::setMouseSelectionMode(SelectionMode mode)
2087 Q_D(QQuickTextInput);
2088 if (d->mouseSelectionMode != mode) {
2089 d->mouseSelectionMode = mode;
2090 emit mouseSelectionModeChanged(mode);
2095 \qmlproperty bool QtQuick2::TextInput::canPaste
2097 Returns true if the TextInput is writable and the content of the clipboard is
2098 suitable for pasting into the TextEdit.
2100 bool QQuickTextInput::canPaste() const
2102 Q_D(const QQuickTextInput);
2103 if (!d->canPasteValid) {
2104 if (const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData())
2105 const_cast<QQuickTextInputPrivate *>(d)->canPaste = !d->m_readOnly && mimeData->hasText();
2106 const_cast<QQuickTextInputPrivate *>(d)->canPasteValid = true;
2112 \qmlproperty bool QtQuick2::TextInput::canUndo
2114 Returns true if the TextInput is writable and there are previous operations
2118 bool QQuickTextInput::canUndo() const
2120 Q_D(const QQuickTextInput);
2125 \qmlproperty bool QtQuick2::TextInput::canRedo
2127 Returns true if the TextInput is writable and there are \l {undo}{undone}
2128 operations that can be redone.
2131 bool QQuickTextInput::canRedo() const
2133 Q_D(const QQuickTextInput);
2137 void QQuickTextInput::moveCursorSelection(int position)
2139 Q_D(QQuickTextInput);
2140 d->moveCursor(position, true);
2144 \qmlmethod void QtQuick2::TextInput::moveCursorSelection(int position, SelectionMode mode = TextInput.SelectCharacters)
2146 Moves the cursor to \a position and updates the selection according to the optional \a mode
2147 parameter. (To only move the cursor, set the \l cursorPosition property.)
2149 When this method is called it additionally sets either the
2150 selectionStart or the selectionEnd (whichever was at the previous cursor position)
2151 to the specified position. This allows you to easily extend and contract the selected
2154 The selection mode specifies whether the selection is updated on a per character or a per word
2155 basis. If not specified the selection mode will default to TextInput.SelectCharacters.
2158 \o TextEdit.SelectCharacters - Sets either the selectionStart or selectionEnd (whichever was at
2159 the previous cursor position) to the specified position.
2160 \o TextEdit.SelectWords - Sets the selectionStart and selectionEnd to include all
2161 words between the specified position and the previous cursor position. Words partially in the
2165 For example, take this sequence of calls:
2169 moveCursorSelection(9, TextInput.SelectCharacters)
2170 moveCursorSelection(7, TextInput.SelectCharacters)
2173 This moves the cursor to position 5, extend the selection end from 5 to 9
2174 and then retract the selection end from 9 to 7, leaving the text from position 5 to 7
2175 selected (the 6th and 7th characters).
2177 The same sequence with TextInput.SelectWords will extend the selection start to a word boundary
2178 before or on position 5 and extend the selection end to a word boundary on or past position 9.
2180 void QQuickTextInput::moveCursorSelection(int pos, SelectionMode mode)
2182 Q_D(QQuickTextInput);
2184 if (mode == SelectCharacters) {
2185 d->moveCursor(pos, true);
2186 } else if (pos != d->m_cursor){
2187 const int cursor = d->m_cursor;
2189 if (!d->hasSelectedText())
2190 anchor = d->m_cursor;
2191 else if (d->selectionStart() == d->m_cursor)
2192 anchor = d->selectionEnd();
2194 anchor = d->selectionStart();
2196 if (anchor < pos || (anchor == pos && cursor < pos)) {
2197 const QString text = this->text();
2198 QTextBoundaryFinder finder(QTextBoundaryFinder::Word, text);
2199 finder.setPosition(anchor);
2201 const QTextBoundaryFinder::BoundaryReasons reasons = finder.boundaryReasons();
2202 if (anchor < text.length() && (!(reasons & QTextBoundaryFinder::StartWord)
2203 || ((reasons & QTextBoundaryFinder::EndWord) && anchor > cursor))) {
2204 finder.toPreviousBoundary();
2206 anchor = finder.position() != -1 ? finder.position() : 0;
2208 finder.setPosition(pos);
2209 if (pos > 0 && !finder.boundaryReasons())
2210 finder.toNextBoundary();
2211 const int cursor = finder.position() != -1 ? finder.position() : text.length();
2213 d->setSelection(anchor, cursor - anchor);
2214 } else if (anchor > pos || (anchor == pos && cursor > pos)) {
2215 const QString text = this->text();
2216 QTextBoundaryFinder finder(QTextBoundaryFinder::Word, text);
2217 finder.setPosition(anchor);
2219 const QTextBoundaryFinder::BoundaryReasons reasons = finder.boundaryReasons();
2220 if (anchor > 0 && (!(reasons & QTextBoundaryFinder::EndWord)
2221 || ((reasons & QTextBoundaryFinder::StartWord) && anchor < cursor))) {
2222 finder.toNextBoundary();
2225 anchor = finder.position() != -1 ? finder.position() : text.length();
2227 finder.setPosition(pos);
2228 if (pos < text.length() && !finder.boundaryReasons())
2229 finder.toPreviousBoundary();
2230 const int cursor = finder.position() != -1 ? finder.position() : 0;
2232 d->setSelection(anchor, cursor - anchor);
2238 \qmlmethod void QtQuick2::TextInput::openSoftwareInputPanel()
2240 Opens software input panels like virtual keyboards for typing, useful for
2241 customizing when you want the input keyboard to be shown and hidden in
2244 By default the opening of input panels follows the platform style. Input panels are
2245 always closed if no editor has active focus.
2247 You can disable the automatic behavior by setting the property \c activeFocusOnPress to false
2248 and use functions openSoftwareInputPanel() and closeSoftwareInputPanel() to implement
2249 the behavior you want.
2251 Only relevant on platforms, which provide virtual keyboards.
2257 text: "Hello world!"
2258 activeFocusOnPress: false
2260 anchors.fill: parent
2262 if (!textInput.activeFocus) {
2263 textInput.forceActiveFocus()
2264 textInput.openSoftwareInputPanel();
2266 textInput.focus = false;
2269 onPressAndHold: textInput.closeSoftwareInputPanel();
2274 void QQuickTextInput::openSoftwareInputPanel()
2277 qGuiApp->inputPanel()->show();
2281 \qmlmethod void QtQuick2::TextInput::closeSoftwareInputPanel()
2283 Closes a software input panel like a virtual keyboard shown on the screen, useful
2284 for customizing when you want the input keyboard to be shown and hidden in
2287 By default the opening of input panels follows the platform style. Input panels are
2288 always closed if no editor has active focus.
2290 You can disable the automatic behavior by setting the property \c activeFocusOnPress to false
2291 and use functions openSoftwareInputPanel() and closeSoftwareInputPanel() to implement
2292 the behavior you want.
2294 Only relevant on platforms, which provide virtual keyboards.
2300 text: "Hello world!"
2301 activeFocusOnPress: false
2303 anchors.fill: parent
2305 if (!textInput.activeFocus) {
2306 textInput.forceActiveFocus();
2307 textInput.openSoftwareInputPanel();
2309 textInput.focus = false;
2312 onPressAndHold: textInput.closeSoftwareInputPanel();
2317 void QQuickTextInput::closeSoftwareInputPanel()
2320 qGuiApp->inputPanel()->hide();
2323 void QQuickTextInput::focusInEvent(QFocusEvent *event)
2325 Q_D(const QQuickTextInput);
2326 if (d->focusOnPress && !d->m_readOnly)
2327 openSoftwareInputPanel();
2328 QQuickImplicitSizeItem::focusInEvent(event);
2331 void QQuickTextInput::itemChange(ItemChange change, const ItemChangeData &value)
2333 Q_D(QQuickTextInput);
2334 if (change == ItemActiveFocusHasChanged) {
2335 bool hasFocus = value.boolValue;
2336 d->focused = hasFocus;
2337 setCursorVisible(hasFocus); // ### refactor: && d->canvas && d->canvas->hasFocus()
2338 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
2339 if (!hasFocus && (d->m_passwordEchoEditing || d->m_passwordEchoTimer.isActive())) {
2341 if (!hasFocus && d->m_passwordEchoEditing) {
2343 d->updatePasswordEchoEditing(false);//QQuickTextInputPrivate sets it on key events, but doesn't deal with focus events
2349 disconnect(qApp->inputPanel(), SIGNAL(inputDirectionChanged(Qt::LayoutDirection)),
2350 this, SLOT(q_updateAlignment()));
2352 q_updateAlignment();
2353 connect(qApp->inputPanel(), SIGNAL(inputDirectionChanged(Qt::LayoutDirection)),
2354 this, SLOT(q_updateAlignment()));
2357 QQuickItem::itemChange(change, value);
2361 \qmlproperty bool QtQuick2::TextInput::inputMethodComposing
2364 This property holds whether the TextInput has partial text input from an
2367 While it is composing an input method may rely on mouse or key events from
2368 the TextInput to edit or commit the partial text. This property can be
2369 used to determine when to disable events handlers that may interfere with
2370 the correct operation of an input method.
2372 bool QQuickTextInput::isInputMethodComposing() const
2374 Q_D(const QQuickTextInput);
2375 return d->preeditAreaText().length() > 0;
2378 void QQuickTextInputPrivate::init()
2380 Q_Q(QQuickTextInput);
2381 q->setSmooth(smooth);
2382 q->setAcceptedMouseButtons(Qt::LeftButton);
2383 q->setFlag(QQuickItem::ItemAcceptsInputMethod);
2384 q->setFlag(QQuickItem::ItemHasContents);
2385 #ifndef QT_NO_CLIPBOARD
2386 q->connect(QGuiApplication::clipboard(), SIGNAL(dataChanged()),
2387 q, SLOT(q_canPasteChanged()));
2388 #endif // QT_NO_CLIPBOARD
2390 lastSelectionStart = 0;
2391 lastSelectionEnd = 0;
2392 selectedTextColor = m_palette.color(QPalette::HighlightedText);
2393 selectionColor = m_palette.color(QPalette::Highlight);
2394 determineHorizontalAlignment();
2396 if (!qmlDisableDistanceField()) {
2397 QTextOption option = m_textLayout.textOption();
2398 option.setUseDesignMetrics(true);
2399 m_textLayout.setTextOption(option);
2403 void QQuickTextInput::updateCursorRectangle()
2405 Q_D(QQuickTextInput);
2406 if (!isComponentComplete())
2409 d->updateHorizontalScroll();
2410 d->updateVerticalScroll();
2412 emit cursorRectangleChanged();
2413 if (d->cursorItem) {
2414 QRectF r = cursorRectangle();
2415 d->cursorItem->setPos(r.topLeft());
2416 d->cursorItem->setHeight(r.height());
2420 void QQuickTextInput::selectionChanged()
2422 Q_D(QQuickTextInput);
2423 d->textLayoutDirty = true; //TODO: Only update rect in selection
2425 emit selectedTextChanged();
2427 if (d->lastSelectionStart != d->selectionStart()) {
2428 d->lastSelectionStart = d->selectionStart();
2429 if (d->lastSelectionStart == -1)
2430 d->lastSelectionStart = d->m_cursor;
2431 emit selectionStartChanged();
2433 if (d->lastSelectionEnd != d->selectionEnd()) {
2434 d->lastSelectionEnd = d->selectionEnd();
2435 if (d->lastSelectionEnd == -1)
2436 d->lastSelectionEnd = d->m_cursor;
2437 emit selectionEndChanged();
2441 void QQuickTextInputPrivate::showCursor()
2443 if (textNode != 0 && textNode->cursorNode() != 0)
2444 textNode->cursorNode()->setColor(color);
2447 void QQuickTextInputPrivate::hideCursor()
2449 if (textNode != 0 && textNode->cursorNode() != 0)
2450 textNode->cursorNode()->setColor(QColor(0, 0, 0, 0));
2453 QRectF QQuickTextInput::boundingRect() const
2455 Q_D(const QQuickTextInput);
2457 int cursorWidth = d->cursorItem ? d->cursorItem->width() : d->m_cursorWidth;
2459 // Could include font max left/right bearings to either side of rectangle.
2460 QRectF r = QQuickImplicitSizeItem::boundingRect();
2461 r.setRight(r.right() + cursorWidth);
2465 void QQuickTextInput::q_canPasteChanged()
2467 Q_D(QQuickTextInput);
2468 bool old = d->canPaste;
2469 #ifndef QT_NO_CLIPBOARD
2470 if (const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData())
2471 d->canPaste = !d->m_readOnly && mimeData->hasText();
2473 d->canPaste = false;
2476 bool changed = d->canPaste != old || !d->canPasteValid;
2477 d->canPasteValid = true;
2479 emit canPasteChanged();
2483 void QQuickTextInput::q_updateAlignment()
2485 Q_D(QQuickTextInput);
2486 if (d->determineHorizontalAlignment()) {
2488 updateCursorRectangle();
2492 // ### these should come from QStyleHints
2493 const int textCursorWidth = 1;
2494 const bool fullWidthSelection = true;
2499 Updates the display text based of the current edit text
2500 If the text has changed will emit displayTextChanged()
2502 void QQuickTextInputPrivate::updateDisplayText(bool forceUpdate)
2504 QString orig = m_textLayout.text();
2506 if (m_echoMode == QQuickTextInput::NoEcho)
2507 str = QString::fromLatin1("");
2511 if (m_echoMode == QQuickTextInput::Password) {
2512 str.fill(m_passwordCharacter);
2513 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
2514 if (m_passwordEchoTimer.isActive() && m_cursor > 0 && m_cursor <= m_text.length()) {
2515 int cursor = m_cursor - 1;
2516 QChar uc = m_text.at(cursor);
2518 if (cursor > 0 && uc.unicode() >= 0xdc00 && uc.unicode() < 0xe000) {
2519 // second half of a surrogate, check if we have the first half as well,
2520 // if yes restore both at once
2521 uc = m_text.at(cursor - 1);
2522 if (uc.unicode() >= 0xd800 && uc.unicode() < 0xdc00)
2523 str[cursor - 1] = uc;
2527 } else if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit && !m_passwordEchoEditing) {
2528 str.fill(m_passwordCharacter);
2531 // replace certain non-printable characters with spaces (to avoid
2532 // drawing boxes when using fonts that don't have glyphs for such
2534 QChar* uc = str.data();
2535 for (int i = 0; i < (int)str.length(); ++i) {
2536 if ((uc[i] < 0x20 && uc[i] != 0x09)
2537 || uc[i] == QChar::LineSeparator
2538 || uc[i] == QChar::ParagraphSeparator
2539 || uc[i] == QChar::ObjectReplacementCharacter)
2540 uc[i] = QChar(0x0020);
2543 if (str != orig || forceUpdate) {
2544 m_textLayout.setText(str);
2545 updateLayout(); // polish?
2546 emit q_func()->displayTextChanged();
2550 void QQuickTextInputPrivate::updateLayout()
2552 Q_Q(QQuickTextInput);
2554 if (!q->isComponentComplete())
2557 QTextOption option = m_textLayout.textOption();
2558 option.setTextDirection(layoutDirection());
2559 option.setFlags(QTextOption::IncludeTrailingSpaces);
2560 option.setWrapMode(QTextOption::WrapMode(wrapMode));
2561 option.setAlignment(Qt::Alignment(q->effectiveHAlign()));
2562 m_textLayout.setTextOption(option);
2563 m_textLayout.setFont(font);
2565 boundingRect = QRectF();
2566 m_textLayout.beginLayout();
2567 QTextLine line = m_textLayout.createLine();
2568 qreal lineWidth = q->widthValid() ? q->width() : INT_MAX;
2570 QTextLine firstLine = line;
2572 line.setLineWidth(lineWidth);
2573 line.setPosition(QPointF(line.position().x(), height));
2574 boundingRect = boundingRect.united(line.naturalTextRect());
2576 height += line.height();
2577 line = m_textLayout.createLine();
2578 } while (line.isValid());
2579 m_textLayout.endLayout();
2581 option.setWrapMode(QTextOption::NoWrap);
2582 m_textLayout.setTextOption(option);
2584 m_ascent = qRound(firstLine.ascent());
2585 textLayoutDirty = true;
2588 q->setImplicitSize(qCeil(boundingRect.width()), qCeil(boundingRect.height()));
2592 #ifndef QT_NO_CLIPBOARD
2596 Copies the currently selected text into the clipboard using the given
2599 \note If the echo mode is set to a mode other than Normal then copy
2600 will not work. This is to prevent using copy as a method of bypassing
2601 password features of the line control.
2603 void QQuickTextInputPrivate::copy(QClipboard::Mode mode) const
2605 QString t = selectedText();
2606 if (!t.isEmpty() && m_echoMode == QQuickTextInput::Normal) {
2607 QGuiApplication::clipboard()->setText(t, mode);
2614 Inserts the text stored in the application clipboard into the line
2619 void QQuickTextInputPrivate::paste(QClipboard::Mode clipboardMode)
2621 QString clip = QGuiApplication::clipboard()->text(clipboardMode);
2622 if (!clip.isEmpty() || hasSelectedText()) {
2623 separate(); //make it a separate undo/redo command
2629 #endif // !QT_NO_CLIPBOARD
2634 Exits preedit mode and commits parts marked as tentative commit
2636 void QQuickTextInputPrivate::commitPreedit()
2641 qApp->inputPanel()->reset();
2643 if (!m_tentativeCommit.isEmpty()) {
2644 internalInsert(m_tentativeCommit);
2645 m_tentativeCommit.clear();
2646 finishChange(-1, true/*not used, not documented*/, false);
2649 m_preeditCursor = 0;
2650 m_textLayout.setPreeditArea(-1, QString());
2651 m_textLayout.clearAdditionalFormats();
2658 Handles the behavior for the backspace key or function.
2659 Removes the current selection if there is a selection, otherwise
2660 removes the character prior to the cursor position.
2664 void QQuickTextInputPrivate::backspace()
2666 int priorState = m_undoState;
2667 if (hasSelectedText()) {
2668 removeSelectedText();
2669 } else if (m_cursor) {
2672 m_cursor = prevMaskBlank(m_cursor);
2673 QChar uc = m_text.at(m_cursor);
2674 if (m_cursor > 0 && uc.unicode() >= 0xdc00 && uc.unicode() < 0xe000) {
2675 // second half of a surrogate, check if we have the first half as well,
2676 // if yes delete both at once
2677 uc = m_text.at(m_cursor - 1);
2678 if (uc.unicode() >= 0xd800 && uc.unicode() < 0xdc00) {
2679 internalDelete(true);
2683 internalDelete(true);
2685 finishChange(priorState);
2691 Handles the behavior for the delete key or function.
2692 Removes the current selection if there is a selection, otherwise
2693 removes the character after the cursor position.
2697 void QQuickTextInputPrivate::del()
2699 int priorState = m_undoState;
2700 if (hasSelectedText()) {
2701 removeSelectedText();
2703 int n = m_textLayout.nextCursorPosition(m_cursor) - m_cursor;
2707 finishChange(priorState);
2713 Inserts the given \a newText at the current cursor position.
2714 If there is any selected text it is removed prior to insertion of
2717 void QQuickTextInputPrivate::insert(const QString &newText)
2719 int priorState = m_undoState;
2720 removeSelectedText();
2721 internalInsert(newText);
2722 finishChange(priorState);
2728 Clears the line control text.
2730 void QQuickTextInputPrivate::clear()
2732 int priorState = m_undoState;
2734 m_selend = m_text.length();
2735 removeSelectedText();
2737 finishChange(priorState, /*update*/false, /*edited*/false);
2743 Sets \a length characters from the given \a start position as selected.
2744 The given \a start position must be within the current text for
2745 the line control. If \a length characters cannot be selected, then
2746 the selection will extend to the end of the current text.
2748 void QQuickTextInputPrivate::setSelection(int start, int length)
2750 Q_Q(QQuickTextInput);
2753 if (start < 0 || start > (int)m_text.length()){
2754 qWarning("QQuickTextInputPrivate::setSelection: Invalid start position");
2759 if (start == m_selstart && start + length == m_selend && m_cursor == m_selend)
2762 m_selend = qMin(start + length, (int)m_text.length());
2763 m_cursor = m_selend;
2764 } else if (length < 0){
2765 if (start == m_selend && start + length == m_selstart && m_cursor == m_selstart)
2767 m_selstart = qMax(start + length, 0);
2769 m_cursor = m_selstart;
2770 } else if (m_selstart != m_selend) {
2776 emitCursorPositionChanged();
2779 emit q->selectionChanged();
2780 emitCursorPositionChanged();
2781 qApp->inputPanel()->update(Qt::ImCursorRectangle | Qt::ImAnchorPosition
2782 | Qt::ImCursorPosition | Qt::ImCurrentSelection);
2788 Initializes the line control with a starting text value of \a txt.
2790 void QQuickTextInputPrivate::init(const QString &txt)
2794 updateDisplayText();
2795 m_cursor = m_text.length();
2801 Sets the password echo editing to \a editing. If password echo editing
2802 is true, then the text of the password is displayed even if the echo
2803 mode is set to QLineEdit::PasswordEchoOnEdit. Password echoing editing
2804 does not affect other echo modes.
2806 void QQuickTextInputPrivate::updatePasswordEchoEditing(bool editing)
2808 cancelPasswordEchoTimer();
2809 m_passwordEchoEditing = editing;
2810 updateDisplayText();
2816 Fixes the current text so that it is valid given any set validators.
2818 Returns true if the text was changed. Otherwise returns false.
2820 bool QQuickTextInputPrivate::fixup() // this function assumes that validate currently returns != Acceptable
2822 #ifndef QT_NO_VALIDATOR
2824 QString textCopy = m_text;
2825 int cursorCopy = m_cursor;
2826 m_validator->fixup(textCopy);
2827 if (m_validator->validate(textCopy, cursorCopy) == QValidator::Acceptable) {
2828 if (textCopy != m_text || cursorCopy != m_cursor)
2829 internalSetText(textCopy, cursorCopy);
2840 Moves the cursor to the given position \a pos. If \a mark is true will
2841 adjust the currently selected text.
2843 void QQuickTextInputPrivate::moveCursor(int pos, bool mark)
2845 Q_Q(QQuickTextInput);
2848 if (pos != m_cursor) {
2851 pos = pos > m_cursor ? nextMaskBlank(pos) : prevMaskBlank(pos);
2855 if (m_selend > m_selstart && m_cursor == m_selstart)
2857 else if (m_selend > m_selstart && m_cursor == m_selend)
2858 anchor = m_selstart;
2861 m_selstart = qMin(anchor, pos);
2862 m_selend = qMax(anchor, pos);
2867 if (mark || m_selDirty) {
2869 emit q->selectionChanged();
2871 emitCursorPositionChanged();
2872 q->updateMicroFocus();
2878 Applies the given input method event \a event to the text of the line
2881 void QQuickTextInputPrivate::processInputMethodEvent(QInputMethodEvent *event)
2883 Q_Q(QQuickTextInput);
2885 int priorState = -1;
2886 bool isGettingInput = !event->commitString().isEmpty()
2887 || event->preeditString() != preeditAreaText()
2888 || event->replacementLength() > 0;
2889 bool cursorPositionChanged = false;
2890 bool selectionChange = false;
2891 m_preeditDirty = event->preeditString() != preeditAreaText();
2893 if (isGettingInput) {
2894 // If any text is being input, remove selected text.
2895 priorState = m_undoState;
2896 if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit && !m_passwordEchoEditing) {
2897 updatePasswordEchoEditing(true);
2899 m_selend = m_text.length();
2901 removeSelectedText();
2904 int c = m_cursor; // cursor position after insertion of commit string
2905 if (event->replacementStart() <= 0)
2906 c += event->commitString().length() - qMin(-event->replacementStart(), event->replacementLength());
2908 m_cursor += event->replacementStart();
2912 // insert commit string
2913 if (event->replacementLength()) {
2914 m_selstart = m_cursor;
2915 m_selend = m_selstart + event->replacementLength();
2916 m_selend = qMin(m_selend, m_text.length());
2917 removeSelectedText();
2919 if (!event->commitString().isEmpty()) {
2920 internalInsert(event->commitString());
2921 cursorPositionChanged = true;
2924 m_cursor = qBound(0, c, m_text.length());
2926 for (int i = 0; i < event->attributes().size(); ++i) {
2927 const QInputMethodEvent::Attribute &a = event->attributes().at(i);
2928 if (a.type == QInputMethodEvent::Selection) {
2929 m_cursor = qBound(0, a.start + a.length, m_text.length());
2931 m_selstart = qMax(0, qMin(a.start, m_text.length()));
2932 m_selend = m_cursor;
2933 if (m_selend < m_selstart) {
2934 qSwap(m_selstart, m_selend);
2936 selectionChange = true;
2938 m_selstart = m_selend = 0;
2940 cursorPositionChanged = true;
2944 m_textLayout.setPreeditArea(m_cursor, event->preeditString());
2946 const int oldPreeditCursor = m_preeditCursor;
2947 m_preeditCursor = event->preeditString().length();
2948 m_hideCursor = false;
2949 QList<QTextLayout::FormatRange> formats;
2950 for (int i = 0; i < event->attributes().size(); ++i) {
2951 const QInputMethodEvent::Attribute &a = event->attributes().at(i);
2952 if (a.type == QInputMethodEvent::Cursor) {
2953 m_preeditCursor = a.start;
2954 m_hideCursor = !a.length;
2955 } else if (a.type == QInputMethodEvent::TextFormat) {
2956 QTextCharFormat f = qvariant_cast<QTextFormat>(a.value).toCharFormat();
2958 QTextLayout::FormatRange o;
2959 o.start = a.start + m_cursor;
2960 o.length = a.length;
2966 m_textLayout.setAdditionalFormats(formats);
2968 updateDisplayText(/*force*/ true);
2969 if (cursorPositionChanged) {
2970 emitCursorPositionChanged();
2971 } else if (m_preeditCursor != oldPreeditCursor) {
2972 q->updateCursorRectangle();
2973 qApp->inputPanel()->update(Qt::ImCursorRectangle);
2976 bool tentativeCommitChanged = m_tentativeCommit != event->tentativeCommitString();
2978 if (tentativeCommitChanged) {
2980 m_tentativeCommit = event->tentativeCommitString();
2983 if (isGettingInput || tentativeCommitChanged)
2984 finishChange(priorState);
2986 if (selectionChange) {
2987 emit q->selectionChanged();
2988 qApp->inputPanel()->update(Qt::ImCursorRectangle | Qt::ImAnchorPosition
2989 | Qt::ImCursorPosition | Qt::ImCurrentSelection);
2996 Sets the selection to cover the word at the given cursor position.
2997 The word boundaries are defined by the behavior of QTextLayout::SkipWords
3000 void QQuickTextInputPrivate::selectWordAtPos(int cursor)
3002 int next = cursor + 1;
3005 int c = m_textLayout.previousCursorPosition(next, QTextLayout::SkipWords);
3006 moveCursor(c, false);
3007 // ## text layout should support end of words.
3008 int end = m_textLayout.nextCursorPosition(c, QTextLayout::SkipWords);
3009 while (end > cursor && m_text[end-1].isSpace())
3011 moveCursor(end, true);
3017 Completes a change to the line control text. If the change is not valid
3018 will undo the line control state back to the given \a validateFromState.
3020 If \a edited is true and the change is valid, will emit textEdited() in
3021 addition to textChanged(). Otherwise only emits textChanged() on a valid
3024 The \a update value is currently unused.
3026 bool QQuickTextInputPrivate::finishChange(int validateFromState, bool update, bool /*edited*/)
3028 Q_Q(QQuickTextInput);
3031 bool notifyInputPanel = m_textDirty || m_selDirty;
3032 bool alignmentChanged = false;
3036 bool wasValidInput = m_validInput;
3037 bool wasAcceptable = m_acceptableInput;
3038 m_validInput = true;
3039 m_acceptableInput = true;
3040 #ifndef QT_NO_VALIDATOR
3042 QString textCopy = m_text;
3043 int cursorCopy = m_cursor;
3044 QValidator::State state = m_validator->validate(textCopy, cursorCopy);
3045 m_validInput = state != QValidator::Invalid;
3046 m_acceptableInput = state == QValidator::Acceptable;
3048 if (m_text != textCopy) {
3049 internalSetText(textCopy, cursorCopy);
3052 m_cursor = cursorCopy;
3054 if (!m_tentativeCommit.isEmpty()) {
3055 textCopy.insert(m_cursor, m_tentativeCommit);
3056 bool validInput = m_validator->validate(textCopy, cursorCopy) != QValidator::Invalid;
3058 m_tentativeCommit.clear();
3061 m_tentativeCommit.clear();
3065 if (validateFromState >= 0 && wasValidInput && !m_validInput) {
3066 if (m_transactions.count())
3068 internalUndo(validateFromState);
3069 m_history.resize(m_undoState);
3070 if (m_modifiedState > m_undoState)
3071 m_modifiedState = -1;
3072 m_validInput = true;
3073 m_acceptableInput = wasAcceptable;
3074 m_textDirty = false;
3078 m_textDirty = false;
3079 m_preeditDirty = false;
3080 alignmentChanged = determineHorizontalAlignment();
3081 emit q->textChanged();
3084 updateDisplayText(alignmentChanged);
3086 if (m_acceptableInput != wasAcceptable)
3087 emit q->acceptableInputChanged();
3089 if (m_preeditDirty) {
3090 m_preeditDirty = false;
3091 if (determineHorizontalAlignment()) {
3092 alignmentChanged = true;
3099 emit q->selectionChanged();
3102 notifyInputPanel |= (m_cursor == m_lastCursorPos);
3103 if (notifyInputPanel)
3104 q->updateMicroFocus();
3105 emitUndoRedoChanged();
3107 if (!emitCursorPositionChanged() && alignmentChanged)
3108 q->updateCursorRectangle();
3116 An internal function for setting the text of the line control.
3118 void QQuickTextInputPrivate::internalSetText(const QString &txt, int pos, bool edited)
3120 Q_Q(QQuickTextInput);
3122 QString oldText = m_text;
3124 m_text = maskString(0, txt, true);
3125 m_text += clearString(m_text.length(), m_maxLength - m_text.length());
3127 m_text = txt.isEmpty() ? txt : txt.left(m_maxLength);
3130 m_modifiedState = m_undoState = 0;
3131 m_cursor = (pos < 0 || pos > m_text.length()) ? m_text.length() : pos;
3132 m_textDirty = (oldText != m_text);
3134 bool changed = finishChange(-1, true, edited);
3135 #ifdef QT_NO_ACCESSIBILITY
3139 QAccessible::updateAccessibility(q, 0, QAccessible::TextUpdated);
3147 Adds the given \a command to the undo history
3148 of the line control. Does not apply the command.
3150 void QQuickTextInputPrivate::addCommand(const Command &cmd)
3152 if (m_separator && m_undoState && m_history[m_undoState - 1].type != Separator) {
3153 m_history.resize(m_undoState + 2);
3154 m_history[m_undoState++] = Command(Separator, m_cursor, 0, m_selstart, m_selend);
3156 m_history.resize(m_undoState + 1);
3158 m_separator = false;
3159 m_history[m_undoState++] = cmd;
3165 Inserts the given string \a s into the line
3168 Also adds the appropriate commands into the undo history.
3169 This function does not call finishChange(), and may leave the text
3170 in an invalid state.
3172 void QQuickTextInputPrivate::internalInsert(const QString &s)
3174 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
3175 Q_Q(QQuickTextInput);
3176 if (m_echoMode == QQuickTextInput::Password)
3177 m_passwordEchoTimer.start(qt_passwordEchoDelay, q);
3179 if (hasSelectedText())
3180 addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
3182 QString ms = maskString(m_cursor, s);
3183 for (int i = 0; i < (int) ms.length(); ++i) {
3184 addCommand (Command(DeleteSelection, m_cursor + i, m_text.at(m_cursor + i), -1, -1));
3185 addCommand(Command(Insert, m_cursor + i, ms.at(i), -1, -1));
3187 m_text.replace(m_cursor, ms.length(), ms);
3188 m_cursor += ms.length();
3189 m_cursor = nextMaskBlank(m_cursor);
3192 int remaining = m_maxLength - m_text.length();
3193 if (remaining != 0) {
3194 m_text.insert(m_cursor, s.left(remaining));
3195 for (int i = 0; i < (int) s.left(remaining).length(); ++i)
3196 addCommand(Command(Insert, m_cursor++, s.at(i), -1, -1));
3205 deletes a single character from the current text. If \a wasBackspace,
3206 the character prior to the cursor is removed. Otherwise the character
3207 after the cursor is removed.
3209 Also adds the appropriate commands into the undo history.
3210 This function does not call finishChange(), and may leave the text
3211 in an invalid state.
3213 void QQuickTextInputPrivate::internalDelete(bool wasBackspace)
3215 if (m_cursor < (int) m_text.length()) {
3216 cancelPasswordEchoTimer();
3217 if (hasSelectedText())
3218 addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
3219 addCommand(Command((CommandType)((m_maskData ? 2 : 0) + (wasBackspace ? Remove : Delete)),
3220 m_cursor, m_text.at(m_cursor), -1, -1));
3222 m_text.replace(m_cursor, 1, clearString(m_cursor, 1));
3223 addCommand(Command(Insert, m_cursor, m_text.at(m_cursor), -1, -1));
3225 m_text.remove(m_cursor, 1);
3234 removes the currently selected text from the line control.
3236 Also adds the appropriate commands into the undo history.
3237 This function does not call finishChange(), and may leave the text
3238 in an invalid state.
3240 void QQuickTextInputPrivate::removeSelectedText()
3242 if (m_selstart < m_selend && m_selend <= (int) m_text.length()) {
3243 cancelPasswordEchoTimer();
3246 addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
3247 if (m_selstart <= m_cursor && m_cursor < m_selend) {
3248 // cursor is within the selection. Split up the commands
3249 // to be able to restore the correct cursor position
3250 for (i = m_cursor; i >= m_selstart; --i)
3251 addCommand (Command(DeleteSelection, i, m_text.at(i), -1, 1));
3252 for (i = m_selend - 1; i > m_cursor; --i)
3253 addCommand (Command(DeleteSelection, i - m_cursor + m_selstart - 1, m_text.at(i), -1, -1));
3255 for (i = m_selend-1; i >= m_selstart; --i)
3256 addCommand (Command(RemoveSelection, i, m_text.at(i), -1, -1));
3259 m_text.replace(m_selstart, m_selend - m_selstart, clearString(m_selstart, m_selend - m_selstart));
3260 for (int i = 0; i < m_selend - m_selstart; ++i)
3261 addCommand(Command(Insert, m_selstart + i, m_text.at(m_selstart + i), -1, -1));
3263 m_text.remove(m_selstart, m_selend - m_selstart);
3265 if (m_cursor > m_selstart)
3266 m_cursor -= qMin(m_cursor, m_selend) - m_selstart;
3275 Parses the input mask specified by \a maskFields to generate
3276 the mask data used to handle input masks.
3278 void QQuickTextInputPrivate::parseInputMask(const QString &maskFields)
3280 int delimiter = maskFields.indexOf(QLatin1Char(';'));
3281 if (maskFields.isEmpty() || delimiter == 0) {
3283 delete [] m_maskData;
3285 m_maxLength = 32767;
3286 internalSetText(QString());
3291 if (delimiter == -1) {
3292 m_blank = QLatin1Char(' ');
3293 m_inputMask = maskFields;
3295 m_inputMask = maskFields.left(delimiter);
3296 m_blank = (delimiter + 1 < maskFields.length()) ? maskFields[delimiter + 1] : QLatin1Char(' ');
3299 // calculate m_maxLength / m_maskData length
3302 for (int i=0; i<m_inputMask.length(); i++) {
3303 c = m_inputMask.at(i);
3304 if (i > 0 && m_inputMask.at(i-1) == QLatin1Char('\\')) {
3308 if (c != QLatin1Char('\\') && c != QLatin1Char('!') &&
3309 c != QLatin1Char('<') && c != QLatin1Char('>') &&
3310 c != QLatin1Char('{') && c != QLatin1Char('}') &&
3311 c != QLatin1Char('[') && c != QLatin1Char(']'))
3315 delete [] m_maskData;
3316 m_maskData = new MaskInputData[m_maxLength];
3318 MaskInputData::Casemode m = MaskInputData::NoCaseMode;
3321 bool escape = false;
3323 for (int i = 0; i < m_inputMask.length(); i++) {
3324 c = m_inputMask.at(i);
3327 m_maskData[index].maskChar = c;
3328 m_maskData[index].separator = s;
3329 m_maskData[index].caseMode = m;
3332 } else if (c == QLatin1Char('<')) {
3333 m = MaskInputData::Lower;
3334 } else if (c == QLatin1Char('>')) {
3335 m = MaskInputData::Upper;
3336 } else if (c == QLatin1Char('!')) {
3337 m = MaskInputData::NoCaseMode;
3338 } else if (c != QLatin1Char('{') && c != QLatin1Char('}') && c != QLatin1Char('[') && c != QLatin1Char(']')) {
3339 switch (c.unicode()) {
3365 m_maskData[index].maskChar = c;
3366 m_maskData[index].separator = s;
3367 m_maskData[index].caseMode = m;
3372 internalSetText(m_text);
3379 checks if the key is valid compared to the inputMask
3381 bool QQuickTextInputPrivate::isValidInput(QChar key, QChar mask) const
3383 switch (mask.unicode()) {
3389 if (key.isLetter() || key == m_blank)
3393 if (key.isLetterOrNumber())
3397 if (key.isLetterOrNumber() || key == m_blank)
3405 if (key.isPrint() || key == m_blank)
3413 if (key.isNumber() || key == m_blank)
3417 if (key.isNumber() && key.digitValue() > 0)
3421 if ((key.isNumber() && key.digitValue() > 0) || key == m_blank)
3425 if (key.isNumber() || key == QLatin1Char('+') || key == QLatin1Char('-') || key == m_blank)
3429 if (key == QLatin1Char('0') || key == QLatin1Char('1'))
3433 if (key == QLatin1Char('0') || key == QLatin1Char('1') || key == m_blank)
3437 if (key.isNumber() || (key >= QLatin1Char('a') && key <= QLatin1Char('f')) || (key >= QLatin1Char('A') && key <= QLatin1Char('F')))
3441 if (key.isNumber() || (key >= QLatin1Char('a') && key <= QLatin1Char('f')) || (key >= QLatin1Char('A') && key <= QLatin1Char('F')) || key == m_blank)
3453 Returns true if the given text \a str is valid for any
3454 validator or input mask set for the line control.
3456 Otherwise returns false
3458 QQuickTextInputPrivate::ValidatorState QQuickTextInputPrivate::hasAcceptableInput(const QString &str) const
3460 #ifndef QT_NO_VALIDATOR
3461 QString textCopy = str;
3462 int cursorCopy = m_cursor;
3464 QValidator::State state = m_validator->validate(textCopy, cursorCopy);
3465 if (state != QValidator::Acceptable)
3466 return ValidatorState(state);
3471 return AcceptableInput;
3473 if (str.length() != m_maxLength)
3474 return InvalidInput;
3476 for (int i=0; i < m_maxLength; ++i) {
3477 if (m_maskData[i].separator) {
3478 if (str.at(i) != m_maskData[i].maskChar)
3479 return InvalidInput;
3481 if (!isValidInput(str.at(i), m_maskData[i].maskChar))
3482 return InvalidInput;
3485 return AcceptableInput;
3491 Applies the inputMask on \a str starting from position \a pos in the mask. \a clear
3492 specifies from where characters should be gotten when a separator is met in \a str - true means
3493 that blanks will be used, false that previous input is used.
3494 Calling this when no inputMask is set is undefined.
3496 QString QQuickTextInputPrivate::maskString(uint pos, const QString &str, bool clear) const
3498 if (pos >= (uint)m_maxLength)
3499 return QString::fromLatin1("");
3502 fill = clear ? clearString(0, m_maxLength) : m_text;
3505 QString s = QString::fromLatin1("");
3507 while (i < m_maxLength) {
3508 if (strIndex < str.length()) {
3509 if (m_maskData[i].separator) {
3510 s += m_maskData[i].maskChar;
3511 if (str[(int)strIndex] == m_maskData[i].maskChar)
3515 if (isValidInput(str[(int)strIndex], m_maskData[i].maskChar)) {
3516 switch (m_maskData[i].caseMode) {
3517 case MaskInputData::Upper:
3518 s += str[(int)strIndex].toUpper();
3520 case MaskInputData::Lower:
3521 s += str[(int)strIndex].toLower();
3524 s += str[(int)strIndex];
3528 // search for separator first
3529 int n = findInMask(i, true, true, str[(int)strIndex]);
3531 if (str.length() != 1 || i == 0 || (i > 0 && (!m_maskData[i-1].separator || m_maskData[i-1].maskChar != str[(int)strIndex]))) {
3532 s += fill.mid(i, n-i+1);
3533 i = n + 1; // update i to find + 1
3536 // search for valid m_blank if not
3537 n = findInMask(i, true, false, str[(int)strIndex]);
3539 s += fill.mid(i, n-i);
3540 switch (m_maskData[n].caseMode) {
3541 case MaskInputData::Upper:
3542 s += str[(int)strIndex].toUpper();
3544 case MaskInputData::Lower:
3545 s += str[(int)strIndex].toLower();
3548 s += str[(int)strIndex];
3550 i = n + 1; // updates i to find + 1
3568 Returns a "cleared" string with only separators and blank chars.
3569 Calling this when no inputMask is set is undefined.
3571 QString QQuickTextInputPrivate::clearString(uint pos, uint len) const
3573 if (pos >= (uint)m_maxLength)
3577 int end = qMin((uint)m_maxLength, pos + len);
3578 for (int i = pos; i < end; ++i)
3579 if (m_maskData[i].separator)
3580 s += m_maskData[i].maskChar;
3590 Strips blank parts of the input in a QQuickTextInputPrivate when an inputMask is set,
3591 separators are still included. Typically "127.0__.0__.1__" becomes "127.0.0.1".
3593 QString QQuickTextInputPrivate::stripString(const QString &str) const
3599 int end = qMin(m_maxLength, (int)str.length());
3600 for (int i = 0; i < end; ++i) {
3601 if (m_maskData[i].separator)
3602 s += m_maskData[i].maskChar;
3603 else if (str[i] != m_blank)
3612 searches forward/backward in m_maskData for either a separator or a m_blank
3614 int QQuickTextInputPrivate::findInMask(int pos, bool forward, bool findSeparator, QChar searchChar) const
3616 if (pos >= m_maxLength || pos < 0)
3619 int end = forward ? m_maxLength : -1;
3620 int step = forward ? 1 : -1;
3624 if (findSeparator) {
3625 if (m_maskData[i].separator && m_maskData[i].maskChar == searchChar)
3628 if (!m_maskData[i].separator) {
3629 if (searchChar.isNull())
3631 else if (isValidInput(searchChar, m_maskData[i].maskChar))
3640 void QQuickTextInputPrivate::internalUndo(int until)
3642 if (!isUndoAvailable())
3644 cancelPasswordEchoTimer();
3646 while (m_undoState && m_undoState > until) {
3647 Command& cmd = m_history[--m_undoState];
3650 m_text.remove(cmd.pos, 1);
3654 m_selstart = cmd.selStart;
3655 m_selend = cmd.selEnd;
3659 case RemoveSelection:
3660 m_text.insert(cmd.pos, cmd.uc);
3661 m_cursor = cmd.pos + 1;
3664 case DeleteSelection:
3665 m_text.insert(cmd.pos, cmd.uc);
3671 if (until < 0 && m_undoState) {
3672 Command& next = m_history[m_undoState-1];
3673 if (next.type != cmd.type && next.type < RemoveSelection
3674 && (cmd.type < RemoveSelection || next.type == Separator))
3681 void QQuickTextInputPrivate::internalRedo()
3683 if (!isRedoAvailable())
3686 while (m_undoState < (int)m_history.size()) {
3687 Command& cmd = m_history[m_undoState++];
3690 m_text.insert(cmd.pos, cmd.uc);
3691 m_cursor = cmd.pos + 1;
3694 m_selstart = cmd.selStart;
3695 m_selend = cmd.selEnd;
3700 case RemoveSelection:
3701 case DeleteSelection:
3702 m_text.remove(cmd.pos, 1);
3703 m_selstart = cmd.selStart;
3704 m_selend = cmd.selEnd;
3708 m_selstart = cmd.selStart;
3709 m_selend = cmd.selEnd;
3713 if (m_undoState < (int)m_history.size()) {
3714 Command& next = m_history[m_undoState];
3715 if (next.type != cmd.type && cmd.type < RemoveSelection && next.type != Separator
3716 && (next.type < RemoveSelection || cmd.type == Separator))
3723 void QQuickTextInputPrivate::emitUndoRedoChanged()
3725 Q_Q(QQuickTextInput);
3726 const bool previousUndo = canUndo;
3727 const bool previousRedo = canRedo;
3729 canUndo = isUndoAvailable();
3730 canRedo = isRedoAvailable();
3732 if (previousUndo != canUndo)
3733 emit q->canUndoChanged();
3734 if (previousRedo != canRedo)
3735 emit q->canRedoChanged();
3741 If the current cursor position differs from the last emitted cursor
3742 position, emits cursorPositionChanged().
3744 bool QQuickTextInputPrivate::emitCursorPositionChanged()
3746 Q_Q(QQuickTextInput);
3747 if (m_cursor != m_lastCursorPos) {
3748 m_lastCursorPos = m_cursor;
3750 q->updateCursorRectangle();
3751 emit q->cursorPositionChanged();
3752 // XXX todo - not in 4.8?
3754 resetCursorBlinkTimer();
3757 if (!hasSelectedText()) {
3758 if (lastSelectionStart != m_cursor) {
3759 lastSelectionStart = m_cursor;
3760 emit q->selectionStartChanged();
3762 if (lastSelectionEnd != m_cursor) {
3763 lastSelectionEnd = m_cursor;
3764 emit q->selectionEndChanged();
3768 #ifndef QT_NO_ACCESSIBILITY
3769 QAccessible::updateAccessibility(q, 0, QAccessible::TextCaretMoved);
3778 void QQuickTextInputPrivate::setCursorBlinkPeriod(int msec)
3780 Q_Q(QQuickTextInput);
3781 if (msec == m_blinkPeriod)
3784 q->killTimer(m_blinkTimer);
3787 m_blinkTimer = q->startTimer(msec / 2);
3791 if (m_blinkStatus == 1)
3794 m_blinkPeriod = msec;
3797 void QQuickTextInputPrivate::resetCursorBlinkTimer()
3799 Q_Q(QQuickTextInput);
3800 if (m_blinkPeriod == 0 || m_blinkTimer == 0)
3802 q->killTimer(m_blinkTimer);
3803 m_blinkTimer = q->startTimer(m_blinkPeriod / 2);
3807 void QQuickTextInput::timerEvent(QTimerEvent *event)
3809 Q_D(QQuickTextInput);
3810 if (event->timerId() == d->m_blinkTimer) {
3811 d->m_blinkStatus = !d->m_blinkStatus;
3813 } else if (event->timerId() == d->m_deleteAllTimer) {
3814 killTimer(d->m_deleteAllTimer);
3815 d->m_deleteAllTimer = 0;
3817 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
3818 } else if (event->timerId() == d->m_passwordEchoTimer.timerId()) {
3819 d->m_passwordEchoTimer.stop();
3820 d->updateDisplayText();
3825 void QQuickTextInputPrivate::processKeyEvent(QKeyEvent* event)
3827 Q_Q(QQuickTextInput);
3828 bool inlineCompletionAccepted = false;
3830 if (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return) {
3831 if (hasAcceptableInput(m_text) || fixup()) {
3834 if (inlineCompletionAccepted)
3841 if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit
3842 && !m_passwordEchoEditing
3844 && !event->text().isEmpty()
3845 && !(event->modifiers() & Qt::ControlModifier)) {
3846 // Clear the edit and reset to normal echo mode while editing; the
3847 // echo mode switches back when the edit loses focus
3848 // ### resets current content. dubious code; you can
3849 // navigate with keys up, down, back, and select(?), but if you press
3850 // "left" or "right" it clears?
3851 updatePasswordEchoEditing(true);
3855 bool unknown = false;
3856 bool visual = cursorMoveStyle() == Qt::VisualMoveStyle;
3860 #ifndef QT_NO_SHORTCUT
3861 else if (event == QKeySequence::Undo) {
3865 else if (event == QKeySequence::Redo) {
3869 else if (event == QKeySequence::SelectAll) {
3872 #ifndef QT_NO_CLIPBOARD
3873 else if (event == QKeySequence::Copy) {
3876 else if (event == QKeySequence::Paste) {
3878 QClipboard::Mode mode = QClipboard::Clipboard;
3882 else if (event == QKeySequence::Cut) {
3888 else if (event == QKeySequence::DeleteEndOfLine) {
3890 setSelection(m_cursor, end());
3895 #endif //QT_NO_CLIPBOARD
3896 else if (event == QKeySequence::MoveToStartOfLine || event == QKeySequence::MoveToStartOfBlock) {
3899 else if (event == QKeySequence::MoveToEndOfLine || event == QKeySequence::MoveToEndOfBlock) {
3902 else if (event == QKeySequence::SelectStartOfLine || event == QKeySequence::SelectStartOfBlock) {
3905 else if (event == QKeySequence::SelectEndOfLine || event == QKeySequence::SelectEndOfBlock) {
3908 else if (event == QKeySequence::MoveToNextChar) {
3909 if (hasSelectedText()) {
3910 moveCursor(selectionEnd(), false);
3912 cursorForward(0, visual ? 1 : (layoutDirection() == Qt::LeftToRight ? 1 : -1));
3915 else if (event == QKeySequence::SelectNextChar) {
3916 cursorForward(1, visual ? 1 : (layoutDirection() == Qt::LeftToRight ? 1 : -1));
3918 else if (event == QKeySequence::MoveToPreviousChar) {
3919 if (hasSelectedText()) {
3920 moveCursor(selectionStart(), false);
3922 cursorForward(0, visual ? -1 : (layoutDirection() == Qt::LeftToRight ? -1 : 1));
3925 else if (event == QKeySequence::SelectPreviousChar) {
3926 cursorForward(1, visual ? -1 : (layoutDirection() == Qt::LeftToRight ? -1 : 1));
3928 else if (event == QKeySequence::MoveToNextWord) {
3929 if (m_echoMode == QQuickTextInput::Normal)
3930 layoutDirection() == Qt::LeftToRight ? cursorWordForward(0) : cursorWordBackward(0);
3932 layoutDirection() == Qt::LeftToRight ? end(0) : home(0);
3934 else if (event == QKeySequence::MoveToPreviousWord) {
3935 if (m_echoMode == QQuickTextInput::Normal)
3936 layoutDirection() == Qt::LeftToRight ? cursorWordBackward(0) : cursorWordForward(0);
3937 else if (!m_readOnly) {
3938 layoutDirection() == Qt::LeftToRight ? home(0) : end(0);
3941 else if (event == QKeySequence::SelectNextWord) {
3942 if (m_echoMode == QQuickTextInput::Normal)
3943 layoutDirection() == Qt::LeftToRight ? cursorWordForward(1) : cursorWordBackward(1);
3945 layoutDirection() == Qt::LeftToRight ? end(1) : home(1);
3947 else if (event == QKeySequence::SelectPreviousWord) {
3948 if (m_echoMode == QQuickTextInput::Normal)
3949 layoutDirection() == Qt::LeftToRight ? cursorWordBackward(1) : cursorWordForward(1);
3951 layoutDirection() == Qt::LeftToRight ? home(1) : end(1);
3953 else if (event == QKeySequence::Delete) {
3957 else if (event == QKeySequence::DeleteEndOfWord) {
3959 cursorWordForward(true);
3963 else if (event == QKeySequence::DeleteStartOfWord) {
3965 cursorWordBackward(true);
3969 #endif // QT_NO_SHORTCUT
3971 bool handled = false;
3972 if (event->modifiers() & Qt::ControlModifier) {
3973 switch (event->key()) {
3974 case Qt::Key_Backspace:
3976 cursorWordBackward(true);
3984 } else { // ### check for *no* modifier
3985 switch (event->key()) {
3986 case Qt::Key_Backspace:
3998 if (event->key() == Qt::Key_Direction_L || event->key() == Qt::Key_Direction_R) {
3999 setLayoutDirection((event->key() == Qt::Key_Direction_L) ? Qt::LeftToRight : Qt::RightToLeft);
4003 if (unknown && !m_readOnly) {
4004 QString t = event->text();
4005 if (!t.isEmpty() && t.at(0).isPrint()) {