1 /****************************************************************************
3 ** Copyright (C) 2011 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();
106 updateCursorRectangle();
107 if (d->cursorComponent && d->cursorComponent->isReady())
112 \qmlproperty string QtQuick2::TextInput::text
114 The text in the TextInput.
116 QString QQuickTextInput::text() const
118 Q_D(const QQuickTextInput);
120 QString content = d->m_text;
121 if (!d->m_tentativeCommit.isEmpty())
122 content.insert(d->m_cursor, d->m_tentativeCommit);
123 QString res = d->m_maskData ? d->stripString(content) : content;
124 return (res.isNull() ? QString::fromLatin1("") : res);
127 void QQuickTextInput::setText(const QString &s)
129 Q_D(QQuickTextInput);
132 if (d->composeMode())
133 qApp->inputPanel()->reset();
134 d->m_tentativeCommit.clear();
135 d->internalSetText(s, -1, false);
139 \qmlproperty int QtQuick2::TextInput::length
141 Returns the total number of characters in the TextInput item.
143 If the TextInput has an inputMask the length will include mask characters and may differ
144 from the length of the string returned by the \l text property.
146 This property can be faster than querying the length the \l text property as it doesn't
147 require any copying or conversion of the TextInput's internal string data.
150 int QQuickTextInput::length() const
152 Q_D(const QQuickTextInput);
153 return d->m_text.length();
157 \qmlmethod string QtQuick2::TextInput::getText(int start, int end)
159 Returns the section of text that is between the \a start and \a end positions.
161 If the TextInput has an inputMask the length will include mask characters.
164 QString QQuickTextInput::getText(int start, int end) const
166 Q_D(const QQuickTextInput);
171 return d->m_text.mid(start, end - start);
174 QString QQuickTextInputPrivate::realText() const
176 QString res = m_maskData ? stripString(m_text) : m_text;
177 return (res.isNull() ? QString::fromLatin1("") : res);
181 \qmlproperty string QtQuick2::TextInput::font.family
183 Sets the family name of the font.
185 The family name is case insensitive and may optionally include a foundry name, e.g. "Helvetica [Cronyx]".
186 If the family is available from more than one foundry and the foundry isn't specified, an arbitrary foundry is chosen.
187 If the family isn't available a family will be set using the font matching algorithm.
191 \qmlproperty bool QtQuick2::TextInput::font.bold
193 Sets whether the font weight is bold.
197 \qmlproperty enumeration QtQuick2::TextInput::font.weight
199 Sets the font's weight.
201 The weight can be one of:
204 \o Font.Normal - the default
211 TextInput { text: "Hello"; font.weight: Font.DemiBold }
216 \qmlproperty bool QtQuick2::TextInput::font.italic
218 Sets whether the font has an italic style.
222 \qmlproperty bool QtQuick2::TextInput::font.underline
224 Sets whether the text is underlined.
228 \qmlproperty bool QtQuick2::TextInput::font.strikeout
230 Sets whether the font has a strikeout style.
234 \qmlproperty real QtQuick2::TextInput::font.pointSize
236 Sets the font size in points. The point size must be greater than zero.
240 \qmlproperty int QtQuick2::TextInput::font.pixelSize
242 Sets the font size in pixels.
244 Using this function makes the font device dependent.
245 Use \c pointSize to set the size of the font in a device independent manner.
249 \qmlproperty real QtQuick2::TextInput::font.letterSpacing
251 Sets the letter spacing for the font.
253 Letter spacing changes the default spacing between individual letters in the font.
254 A positive value increases the letter spacing by the corresponding pixels; a negative value decreases the spacing.
258 \qmlproperty real QtQuick2::TextInput::font.wordSpacing
260 Sets the word spacing for the font.
262 Word spacing changes the default spacing between individual words.
263 A positive value increases the word spacing by a corresponding amount of pixels,
264 while a negative value decreases the inter-word spacing accordingly.
268 \qmlproperty enumeration QtQuick2::TextInput::font.capitalization
270 Sets the capitalization for the text.
273 \o Font.MixedCase - This is the normal text rendering option where no capitalization change is applied.
274 \o Font.AllUppercase - This alters the text to be rendered in all uppercase type.
275 \o Font.AllLowercase - This alters the text to be rendered in all lowercase type.
276 \o Font.SmallCaps - This alters the text to be rendered in small-caps type.
277 \o Font.Capitalize - This alters the text to be rendered with the first character of each word as an uppercase character.
281 TextInput { text: "Hello"; font.capitalization: Font.AllLowercase }
285 QFont QQuickTextInput::font() const
287 Q_D(const QQuickTextInput);
288 return d->sourceFont;
291 void QQuickTextInput::setFont(const QFont &font)
293 Q_D(QQuickTextInput);
294 if (d->sourceFont == font)
297 d->sourceFont = font;
298 QFont oldFont = d->font;
300 if (d->font.pointSizeF() != -1) {
302 qreal size = qRound(d->font.pointSizeF()*2.0);
303 d->font.setPointSizeF(size/2.0);
305 if (oldFont != d->font) {
307 updateCursorRectangle();
309 emit fontChanged(d->sourceFont);
313 \qmlproperty color QtQuick2::TextInput::color
317 QColor QQuickTextInput::color() const
319 Q_D(const QQuickTextInput);
323 void QQuickTextInput::setColor(const QColor &c)
325 Q_D(QQuickTextInput);
328 d->textLayoutDirty = true;
330 emit colorChanged(c);
336 \qmlproperty color QtQuick2::TextInput::selectionColor
338 The text highlight color, used behind selections.
340 QColor QQuickTextInput::selectionColor() const
342 Q_D(const QQuickTextInput);
343 return d->selectionColor;
346 void QQuickTextInput::setSelectionColor(const QColor &color)
348 Q_D(QQuickTextInput);
349 if (d->selectionColor == color)
352 d->selectionColor = color;
353 d->m_palette.setColor(QPalette::Highlight, d->selectionColor);
354 if (d->hasSelectedText()) {
355 d->textLayoutDirty = true;
358 emit selectionColorChanged(color);
361 \qmlproperty color QtQuick2::TextInput::selectedTextColor
363 The highlighted text color, used in selections.
365 QColor QQuickTextInput::selectedTextColor() const
367 Q_D(const QQuickTextInput);
368 return d->selectedTextColor;
371 void QQuickTextInput::setSelectedTextColor(const QColor &color)
373 Q_D(QQuickTextInput);
374 if (d->selectedTextColor == color)
377 d->selectedTextColor = color;
378 d->m_palette.setColor(QPalette::HighlightedText, d->selectedTextColor);
379 if (d->hasSelectedText()) {
380 d->textLayoutDirty = true;
383 emit selectedTextColorChanged(color);
387 \qmlproperty enumeration QtQuick2::TextInput::horizontalAlignment
388 \qmlproperty enumeration QtQuick2::TextInput::effectiveHorizontalAlignment
389 \qmlproperty enumeration QtQuick2::TextInput::verticalAlignment
391 Sets the horizontal alignment of the text within the TextInput item's
392 width and height. By default, the text alignment follows the natural alignment
393 of the text, for example text that is read from left to right will be aligned to
396 TextInput does not have vertical alignment, as the natural height is
397 exactly the height of the single line of text. If you set the height
398 manually to something larger, TextInput will always be top aligned
399 vertically. You can use anchors to align it however you want within
402 The valid values for \c horizontalAlignment are \c TextInput.AlignLeft, \c TextInput.AlignRight and
403 \c TextInput.AlignHCenter.
405 Valid values for \c verticalAlignment are \c TextEdit.AlignTop (default),
406 \c TextEdit.AlignBottom \c TextEdit.AlignVCenter.
408 When using the attached property LayoutMirroring::enabled to mirror application
409 layouts, the horizontal alignment of text will also be mirrored. However, the property
410 \c horizontalAlignment will remain unchanged. To query the effective horizontal alignment
411 of TextInput, use the read-only property \c effectiveHorizontalAlignment.
413 QQuickTextInput::HAlignment QQuickTextInput::hAlign() const
415 Q_D(const QQuickTextInput);
419 void QQuickTextInput::setHAlign(HAlignment align)
421 Q_D(QQuickTextInput);
422 bool forceAlign = d->hAlignImplicit && d->effectiveLayoutMirror;
423 d->hAlignImplicit = false;
424 if (d->setHAlign(align, forceAlign) && isComponentComplete()) {
426 updateCursorRectangle();
430 void QQuickTextInput::resetHAlign()
432 Q_D(QQuickTextInput);
433 d->hAlignImplicit = true;
434 if (d->determineHorizontalAlignment() && isComponentComplete()) {
436 updateCursorRectangle();
440 QQuickTextInput::HAlignment QQuickTextInput::effectiveHAlign() const
442 Q_D(const QQuickTextInput);
443 QQuickTextInput::HAlignment effectiveAlignment = d->hAlign;
444 if (!d->hAlignImplicit && d->effectiveLayoutMirror) {
446 case QQuickTextInput::AlignLeft:
447 effectiveAlignment = QQuickTextInput::AlignRight;
449 case QQuickTextInput::AlignRight:
450 effectiveAlignment = QQuickTextInput::AlignLeft;
456 return effectiveAlignment;
459 bool QQuickTextInputPrivate::setHAlign(QQuickTextInput::HAlignment alignment, bool forceAlign)
461 Q_Q(QQuickTextInput);
462 if ((hAlign != alignment || forceAlign) && alignment <= QQuickTextInput::AlignHCenter) { // justify not supported
463 QQuickTextInput::HAlignment oldEffectiveHAlign = q->effectiveHAlign();
465 emit q->horizontalAlignmentChanged(alignment);
466 if (oldEffectiveHAlign != q->effectiveHAlign())
467 emit q->effectiveHorizontalAlignmentChanged();
473 bool QQuickTextInputPrivate::determineHorizontalAlignment()
475 if (hAlignImplicit) {
476 // if no explicit alignment has been set, follow the natural layout direction of the text
477 QString text = q_func()->text();
479 text = m_textLayout.preeditAreaText();
480 bool isRightToLeft = text.isEmpty() ? QGuiApplication::keyboardInputDirection() == Qt::RightToLeft : text.isRightToLeft();
481 return setHAlign(isRightToLeft ? QQuickTextInput::AlignRight : QQuickTextInput::AlignLeft);
486 QQuickTextInput::VAlignment QQuickTextInput::vAlign() const
488 Q_D(const QQuickTextInput);
492 void QQuickTextInput::setVAlign(QQuickTextInput::VAlignment alignment)
494 Q_D(QQuickTextInput);
495 if (alignment == d->vAlign)
497 d->vAlign = alignment;
498 emit verticalAlignmentChanged(d->vAlign);
499 if (isComponentComplete()) {
500 updateCursorRectangle();
505 \qmlproperty enumeration QtQuick2::TextInput::wrapMode
507 Set this property to wrap the text to the TextEdit item's width.
508 The text will only wrap if an explicit width has been set.
511 \o TextInput.NoWrap - no wrapping will be performed. If the text contains insufficient newlines, then implicitWidth will exceed a set width.
512 \o TextInput.WordWrap - wrapping is done on word boundaries only. If a word is too long, implicitWidth will exceed a set width.
513 \o TextInput.WrapAnywhere - wrapping is done at any point on a line, even if it occurs in the middle of a word.
514 \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.
517 The default is TextInput.NoWrap. If you set a width, consider using TextInput.Wrap.
519 QQuickTextInput::WrapMode QQuickTextInput::wrapMode() const
521 Q_D(const QQuickTextInput);
525 void QQuickTextInput::setWrapMode(WrapMode mode)
527 Q_D(QQuickTextInput);
528 if (mode == d->wrapMode)
532 updateCursorRectangle();
533 emit wrapModeChanged();
536 void QQuickTextInputPrivate::mirrorChange()
538 Q_Q(QQuickTextInput);
539 if (q->isComponentComplete()) {
540 if (!hAlignImplicit && (hAlign == QQuickTextInput::AlignRight || hAlign == QQuickTextInput::AlignLeft)) {
541 q->updateCursorRectangle();
542 emit q->effectiveHorizontalAlignmentChanged();
548 \qmlproperty bool QtQuick2::TextInput::readOnly
550 Sets whether user input can modify the contents of the TextInput.
552 If readOnly is set to true, then user input will not affect the text
553 property. Any bindings or attempts to set the text property will still
556 bool QQuickTextInput::isReadOnly() const
558 Q_D(const QQuickTextInput);
559 return d->m_readOnly;
562 void QQuickTextInput::setReadOnly(bool ro)
564 Q_D(QQuickTextInput);
565 if (d->m_readOnly == ro)
568 setFlag(QQuickItem::ItemAcceptsInputMethod, !ro);
571 d->setCursorPosition(d->end());
573 emit readOnlyChanged(ro);
577 \qmlproperty int QtQuick2::TextInput::maximumLength
578 The maximum permitted length of the text in the TextInput.
580 If the text is too long, it is truncated at the limit.
582 By default, this property contains a value of 32767.
584 int QQuickTextInput::maxLength() const
586 Q_D(const QQuickTextInput);
587 return d->m_maxLength;
590 void QQuickTextInput::setMaxLength(int ml)
592 Q_D(QQuickTextInput);
593 if (d->m_maxLength == ml || d->m_maskData)
597 d->internalSetText(d->m_text, -1, false);
599 emit maximumLengthChanged(ml);
603 \qmlproperty bool QtQuick2::TextInput::cursorVisible
604 Set to true when the TextInput shows a cursor.
606 This property is set and unset when the TextInput gets active focus, so that other
607 properties can be bound to whether the cursor is currently showing. As it
608 gets set and unset automatically, when you set the value yourself you must
609 keep in mind that your value may be overwritten.
611 It can be set directly in script, for example if a KeyProxy might
612 forward keys to it and you desire it to look active when this happens
613 (but without actually giving it active focus).
615 It should not be set directly on the element, like in the below QML,
616 as the specified value will be overridden an lost on focus changes.
625 In the above snippet the cursor will still become visible when the
626 TextInput gains active focus.
628 bool QQuickTextInput::isCursorVisible() const
630 Q_D(const QQuickTextInput);
631 return d->cursorVisible;
634 void QQuickTextInput::setCursorVisible(bool on)
636 Q_D(QQuickTextInput);
637 if (d->cursorVisible == on)
639 d->cursorVisible = on;
640 d->setCursorBlinkPeriod(on ? qApp->styleHints()->cursorFlashTime() : 0);
642 emit cursorVisibleChanged(d->cursorVisible);
646 \qmlproperty int QtQuick2::TextInput::cursorPosition
647 The position of the cursor in the TextInput.
649 int QQuickTextInput::cursorPosition() const
651 Q_D(const QQuickTextInput);
655 void QQuickTextInput::setCursorPosition(int cp)
657 Q_D(QQuickTextInput);
658 if (cp < 0 || cp > text().length())
664 Returns a Rect which encompasses the cursor, but which may be larger than is
665 required. Ignores custom cursor delegates.
667 QRect QQuickTextInput::cursorRectangle() const
669 Q_D(const QQuickTextInput);
672 if (d->m_preeditCursor != -1)
673 c += d->m_preeditCursor;
674 if (d->m_echoMode == NoEcho)
676 QTextLine l = d->m_textLayout.lineForTextPosition(c);
680 qRound(l.cursorToX(c) - d->hscroll),
681 qRound(l.y() - d->vscroll),
687 \qmlproperty int QtQuick2::TextInput::selectionStart
689 The cursor position before the first character in the current selection.
691 This property is read-only. To change the selection, use select(start,end),
692 selectAll(), or selectWord().
694 \sa selectionEnd, cursorPosition, selectedText
696 int QQuickTextInput::selectionStart() const
698 Q_D(const QQuickTextInput);
699 return d->lastSelectionStart;
702 \qmlproperty int QtQuick2::TextInput::selectionEnd
704 The cursor position after the last character in the current selection.
706 This property is read-only. To change the selection, use select(start,end),
707 selectAll(), or selectWord().
709 \sa selectionStart, cursorPosition, selectedText
711 int QQuickTextInput::selectionEnd() const
713 Q_D(const QQuickTextInput);
714 return d->lastSelectionEnd;
717 \qmlmethod void QtQuick2::TextInput::select(int start, int end)
719 Causes the text from \a start to \a end to be selected.
721 If either start or end is out of range, the selection is not changed.
723 After calling this, selectionStart will become the lesser
724 and selectionEnd will become the greater (regardless of the order passed
727 \sa selectionStart, selectionEnd
729 void QQuickTextInput::select(int start, int end)
731 Q_D(QQuickTextInput);
732 if (start < 0 || end < 0 || start > d->m_text.length() || end > d->m_text.length())
734 d->setSelection(start, end-start);
738 \qmlproperty string QtQuick2::TextInput::selectedText
740 This read-only property provides the text currently selected in the
743 It is equivalent to the following snippet, but is faster and easier
747 myTextInput.text.toString().substring(myTextInput.selectionStart,
748 myTextInput.selectionEnd);
751 QString QQuickTextInput::selectedText() const
753 Q_D(const QQuickTextInput);
754 return d->selectedText();
758 \qmlproperty bool QtQuick2::TextInput::activeFocusOnPress
760 Whether the TextInput should gain active focus on a mouse press. By default this is
763 bool QQuickTextInput::focusOnPress() const
765 Q_D(const QQuickTextInput);
766 return d->focusOnPress;
769 void QQuickTextInput::setFocusOnPress(bool b)
771 Q_D(QQuickTextInput);
772 if (d->focusOnPress == b)
777 emit activeFocusOnPressChanged(d->focusOnPress);
780 \qmlproperty bool QtQuick2::TextInput::autoScroll
782 Whether the TextInput should scroll when the text is longer than the width. By default this is
785 bool QQuickTextInput::autoScroll() const
787 Q_D(const QQuickTextInput);
788 return d->autoScroll;
791 void QQuickTextInput::setAutoScroll(bool b)
793 Q_D(QQuickTextInput);
794 if (d->autoScroll == b)
798 //We need to repaint so that the scrolling is taking into account.
799 updateCursorRectangle();
800 emit autoScrollChanged(d->autoScroll);
803 #ifndef QT_NO_VALIDATOR
806 \qmlclass IntValidator QIntValidator
807 \inqmlmodule QtQuick 2
808 \ingroup qml-basic-visual-elements
810 This element provides a validator for integer values.
812 IntValidator uses the \l {QLocale::setDefault()}{default locale} to interpret the number and
813 will accept locale specific digits, group separators, and positive and negative signs. In
814 addition, IntValidator is always guaranteed to accept a number formatted according to the "C"
818 \qmlproperty int QtQuick2::IntValidator::top
820 This property holds the validator's highest acceptable value.
821 By default, this property's value is derived from the highest signed integer available (typically 2147483647).
824 \qmlproperty int QtQuick2::IntValidator::bottom
826 This property holds the validator's lowest acceptable value.
827 By default, this property's value is derived from the lowest signed integer available (typically -2147483647).
831 \qmlclass DoubleValidator QDoubleValidator
832 \inqmlmodule QtQuick 2
833 \ingroup qml-basic-visual-elements
835 This element provides a validator for non-integer numbers.
839 \qmlproperty real QtQuick2::DoubleValidator::top
841 This property holds the validator's maximum acceptable value.
842 By default, this property contains a value of infinity.
845 \qmlproperty real QtQuick2::DoubleValidator::bottom
847 This property holds the validator's minimum acceptable value.
848 By default, this property contains a value of -infinity.
851 \qmlproperty int QtQuick2::DoubleValidator::decimals
853 This property holds the validator's maximum number of digits after the decimal point.
854 By default, this property contains a value of 1000.
857 \qmlproperty enumeration QtQuick2::DoubleValidator::notation
858 This property holds the notation of how a string can describe a number.
860 The possible values for this property are:
863 \o DoubleValidator.StandardNotation
864 \o DoubleValidator.ScientificNotation (default)
867 If this property is set to DoubleValidator.ScientificNotation, the written number may have an exponent part (e.g. 1.5E-2).
871 \qmlclass RegExpValidator QRegExpValidator
872 \inqmlmodule QtQuick 2
873 \ingroup qml-basic-visual-elements
875 This element provides a validator, which counts as valid any string which
876 matches a specified regular expression.
879 \qmlproperty regExp QtQuick2::RegExpValidator::regExp
881 This property holds the regular expression used for validation.
883 Note that this property should be a regular expression in JS syntax, e.g /a/ for the regular expression
886 By default, this property contains a regular expression with the pattern .* that matches any string.
890 \qmlproperty Validator QtQuick2::TextInput::validator
892 Allows you to set a validator on the TextInput. When a validator is set
893 the TextInput will only accept input which leaves the text property in
894 an acceptable or intermediate state. The accepted signal will only be sent
895 if the text is in an acceptable state when enter is pressed.
897 Currently supported validators are IntValidator, DoubleValidator and
898 RegExpValidator. An example of using validators is shown below, which allows
899 input of integers between 11 and 31 into the text input:
904 validator: IntValidator{bottom: 11; top: 31;}
909 \sa acceptableInput, inputMask
912 QValidator* QQuickTextInput::validator() const
914 Q_D(const QQuickTextInput);
915 return d->m_validator;
918 void QQuickTextInput::setValidator(QValidator* v)
920 Q_D(QQuickTextInput);
921 if (d->m_validator == v)
925 if (!d->hasAcceptableInput(d->m_text)) {
926 d->oldValidity = false;
927 emit acceptableInputChanged();
930 emit validatorChanged();
932 #endif // QT_NO_VALIDATOR
935 \qmlproperty string QtQuick2::TextInput::inputMask
937 Allows you to set an input mask on the TextInput, restricting the allowable
938 text inputs. See QLineEdit::inputMask for further details, as the exact
939 same mask strings are used by TextInput.
941 \sa acceptableInput, validator
943 QString QQuickTextInput::inputMask() const
945 Q_D(const QQuickTextInput);
946 return d->inputMask();
949 void QQuickTextInput::setInputMask(const QString &im)
951 Q_D(QQuickTextInput);
952 if (d->inputMask() == im)
956 emit inputMaskChanged(d->inputMask());
960 \qmlproperty bool QtQuick2::TextInput::acceptableInput
962 This property is always true unless a validator or input mask has been set.
963 If a validator or input mask has been set, this property will only be true
964 if the current text is acceptable to the validator or input mask as a final
965 string (not as an intermediate string).
967 bool QQuickTextInput::hasAcceptableInput() const
969 Q_D(const QQuickTextInput);
970 return d->hasAcceptableInput(d->m_text);
974 \qmlsignal QtQuick2::TextInput::onAccepted()
976 This handler is called when the Return or Enter key is pressed.
977 Note that if there is a \l validator or \l inputMask set on the text
978 input, the handler will only be emitted if the input is in an acceptable
982 void QQuickTextInputPrivate::updateInputMethodHints()
984 Q_Q(QQuickTextInput);
985 Qt::InputMethodHints hints = inputMethodHints;
986 if (m_echoMode == QQuickTextInput::Password || m_echoMode == QQuickTextInput::NoEcho)
987 hints |= Qt::ImhHiddenText;
988 else if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit)
989 hints &= ~Qt::ImhHiddenText;
990 if (m_echoMode != QQuickTextInput::Normal)
991 hints |= (Qt::ImhNoAutoUppercase | Qt::ImhNoPredictiveText | Qt::ImhSensitiveData);
992 q->setInputMethodHints(hints);
995 \qmlproperty enumeration QtQuick2::TextInput::echoMode
997 Specifies how the text should be displayed in the TextInput.
999 \o TextInput.Normal - Displays the text as it is. (Default)
1000 \o TextInput.Password - Displays asterisks instead of characters.
1001 \o TextInput.NoEcho - Displays nothing.
1002 \o TextInput.PasswordEchoOnEdit - Displays characters as they are entered
1003 while editing, otherwise displays asterisks.
1006 QQuickTextInput::EchoMode QQuickTextInput::echoMode() const
1008 Q_D(const QQuickTextInput);
1009 return QQuickTextInput::EchoMode(d->m_echoMode);
1012 void QQuickTextInput::setEchoMode(QQuickTextInput::EchoMode echo)
1014 Q_D(QQuickTextInput);
1015 if (echoMode() == echo)
1017 d->cancelPasswordEchoTimer();
1018 d->m_echoMode = echo;
1019 d->m_passwordEchoEditing = false;
1020 d->updateInputMethodHints();
1021 d->updateDisplayText();
1022 updateCursorRectangle();
1024 emit echoModeChanged(echoMode());
1027 Qt::InputMethodHints QQuickTextInput::imHints() const
1029 Q_D(const QQuickTextInput);
1030 return d->inputMethodHints;
1033 void QQuickTextInput::setIMHints(Qt::InputMethodHints hints)
1035 Q_D(QQuickTextInput);
1036 if (d->inputMethodHints == hints)
1038 d->inputMethodHints = hints;
1039 d->updateInputMethodHints();
1043 \qmlproperty Component QtQuick2::TextInput::cursorDelegate
1044 The delegate for the cursor in the TextInput.
1046 If you set a cursorDelegate for a TextInput, this delegate will be used for
1047 drawing the cursor instead of the standard cursor. An instance of the
1048 delegate will be created and managed by the TextInput when a cursor is
1049 needed, and the x property of delegate instance will be set so as
1050 to be one pixel before the top left of the current character.
1052 Note that the root item of the delegate component must be a QDeclarativeItem or
1053 QDeclarativeItem derived item.
1055 QDeclarativeComponent* QQuickTextInput::cursorDelegate() const
1057 Q_D(const QQuickTextInput);
1058 return d->cursorComponent;
1061 void QQuickTextInput::setCursorDelegate(QDeclarativeComponent* c)
1063 Q_D(QQuickTextInput);
1064 if (d->cursorComponent == c)
1067 d->cursorComponent = c;
1069 //note that the components are owned by something else
1070 delete d->cursorItem;
1072 d->startCreatingCursor();
1075 emit cursorDelegateChanged();
1078 void QQuickTextInputPrivate::startCreatingCursor()
1080 Q_Q(QQuickTextInput);
1081 if (cursorComponent->isReady()) {
1083 } else if (cursorComponent->isLoading()) {
1084 q->connect(cursorComponent, SIGNAL(statusChanged(int)),
1085 q, SLOT(createCursor()));
1087 qmlInfo(q, cursorComponent->errors()) << QQuickTextInput::tr("Could not load cursor delegate");
1091 void QQuickTextInput::createCursor()
1093 Q_D(QQuickTextInput);
1094 if (!isComponentComplete())
1097 if (d->cursorComponent->isError()) {
1098 qmlInfo(this, d->cursorComponent->errors()) << tr("Could not load cursor delegate");
1102 if (!d->cursorComponent->isReady())
1106 delete d->cursorItem;
1107 QDeclarativeContext *creationContext = d->cursorComponent->creationContext();
1108 QObject *object = d->cursorComponent->create(creationContext ? creationContext : qmlContext(this));
1109 d->cursorItem = qobject_cast<QQuickItem*>(object);
1110 if (!d->cursorItem) {
1112 qmlInfo(this, d->cursorComponent->errors()) << tr("Could not instantiate cursor delegate");
1116 QRectF r = cursorRectangle();
1118 QDeclarative_setParent_noEvent(d->cursorItem, this);
1119 d->cursorItem->setParentItem(this);
1120 d->cursorItem->setPos(r.topLeft());
1121 d->cursorItem->setHeight(r.height());
1125 \qmlmethod rect QtQuick2::TextInput::positionToRectangle(int pos)
1127 This function takes a character position and returns the rectangle that the
1128 cursor would occupy, if it was placed at that character position.
1130 This is similar to setting the cursorPosition, and then querying the cursor
1131 rectangle, but the cursorPosition is not changed.
1133 QRectF QQuickTextInput::positionToRectangle(int pos) const
1135 Q_D(const QQuickTextInput);
1136 if (pos > d->m_cursor)
1137 pos += d->preeditAreaText().length();
1138 QTextLine l = d->m_textLayout.lineAt(0);
1140 ? QRectF(l.cursorToX(pos) - d->hscroll, 0.0, d->m_cursorWidth, l.height())
1145 \qmlmethod int QtQuick2::TextInput::positionAt(real x, real y, CursorPosition position = CursorBetweenCharacters)
1147 This function returns the character position at
1148 x and y pixels from the top left of the textInput. Position 0 is before the
1149 first character, position 1 is after the first character but before the second,
1150 and so on until position text.length, which is after all characters.
1152 This means that for all x values before the first character this function returns 0,
1153 and for all x values after the last character this function returns text.length. If
1154 the y value is above the text the position will be that of the nearest character on
1155 the first line line and if it is below the text the position of the nearest character
1156 on the last line will be returned.
1158 The cursor position type specifies how the cursor position should be resolved.
1161 \o TextInput.CursorBetweenCharacters - Returns the position between characters that is nearest x.
1162 \o TextInput.CursorOnCharacter - Returns the position before the character that is nearest x.
1166 void QQuickTextInput::positionAt(QDeclarativeV8Function *args) const
1168 Q_D(const QQuickTextInput);
1172 QTextLine::CursorPosition position = QTextLine::CursorBetweenCharacters;
1174 if (args->Length() < 1)
1178 v8::Local<v8::Value> arg = (*args)[i];
1179 x = arg->NumberValue();
1181 if (++i < args->Length()) {
1183 y = arg->NumberValue();
1186 if (++i < args->Length()) {
1188 position = QTextLine::CursorPosition(arg->Int32Value());
1191 int pos = d->positionAt(x, y, position);
1192 const int cursor = d->m_cursor;
1194 const int preeditLength = d->preeditAreaText().length();
1195 pos = pos > cursor + preeditLength
1196 ? pos - preeditLength
1199 args->returnValue(v8::Int32::New(pos));
1202 int QQuickTextInputPrivate::positionAt(int x, int y, QTextLine::CursorPosition position) const
1206 QTextLine line = m_textLayout.lineAt(0);
1207 for (int i = 1; i < m_textLayout.lineCount(); ++i) {
1208 QTextLine nextLine = m_textLayout.lineAt(i);
1210 if (y < (line.rect().bottom() + nextLine.y()) / 2)
1214 return line.isValid() ? line.xToCursor(x, position) : 0;
1217 void QQuickTextInput::keyPressEvent(QKeyEvent* ev)
1219 Q_D(QQuickTextInput);
1220 // Don't allow MacOSX up/down support, and we don't allow a completer.
1221 bool ignore = (ev->key() == Qt::Key_Up || ev->key() == Qt::Key_Down) && ev->modifiers() == Qt::NoModifier;
1222 if (!ignore && (d->lastSelectionStart == d->lastSelectionEnd) && (ev->key() == Qt::Key_Right || ev->key() == Qt::Key_Left)) {
1223 // Ignore when moving off the end unless there is a selection,
1224 // because then moving will do something (deselect).
1225 int cursorPosition = d->m_cursor;
1226 if (cursorPosition == 0)
1227 ignore = ev->key() == (d->layoutDirection() == Qt::LeftToRight ? Qt::Key_Left : Qt::Key_Right);
1228 if (cursorPosition == text().length())
1229 ignore = ev->key() == (d->layoutDirection() == Qt::LeftToRight ? Qt::Key_Right : Qt::Key_Left);
1234 d->processKeyEvent(ev);
1236 if (!ev->isAccepted())
1237 QQuickImplicitSizeItem::keyPressEvent(ev);
1240 void QQuickTextInput::inputMethodEvent(QInputMethodEvent *ev)
1242 Q_D(QQuickTextInput);
1243 const bool wasComposing = d->preeditAreaText().length() > 0;
1244 if (d->m_readOnly) {
1247 d->processInputMethodEvent(ev);
1249 if (!ev->isAccepted())
1250 QQuickImplicitSizeItem::inputMethodEvent(ev);
1252 if (wasComposing != (d->m_textLayout.preeditAreaText().length() > 0))
1253 emit inputMethodComposingChanged();
1256 void QQuickTextInput::mouseDoubleClickEvent(QMouseEvent *event)
1258 Q_D(QQuickTextInput);
1260 if (d->selectByMouse && event->button() == Qt::LeftButton) {
1262 int cursor = d->positionAt(event->localPos());
1263 d->selectWordAtPos(cursor);
1264 event->setAccepted(true);
1265 if (!d->hasPendingTripleClick()) {
1266 d->tripleClickStartPoint = event->localPos().toPoint();
1267 d->tripleClickTimer.start();
1270 if (d->sendMouseEventToInputContext(event))
1272 QQuickImplicitSizeItem::mouseDoubleClickEvent(event);
1276 void QQuickTextInput::mousePressEvent(QMouseEvent *event)
1278 Q_D(QQuickTextInput);
1280 d->pressPos = event->localPos();
1282 if (d->focusOnPress) {
1283 bool hadActiveFocus = hasActiveFocus();
1285 // re-open input panel on press if already focused
1286 if (hasActiveFocus() && hadActiveFocus && !d->m_readOnly)
1287 openSoftwareInputPanel();
1289 if (d->selectByMouse) {
1290 setKeepMouseGrab(false);
1291 d->selectPressed = true;
1292 QPoint distanceVector = d->pressPos.toPoint() - d->tripleClickStartPoint;
1293 if (d->hasPendingTripleClick()
1294 && distanceVector.manhattanLength() < qApp->styleHints()->startDragDistance()) {
1295 event->setAccepted(true);
1301 if (d->sendMouseEventToInputContext(event))
1304 bool mark = (event->modifiers() & Qt::ShiftModifier) && d->selectByMouse;
1305 int cursor = d->positionAt(event->localPos());
1306 d->moveCursor(cursor, mark);
1307 event->setAccepted(true);
1310 void QQuickTextInput::mouseMoveEvent(QMouseEvent *event)
1312 Q_D(QQuickTextInput);
1314 if (d->selectPressed) {
1315 if (qAbs(int(event->localPos().x() - d->pressPos.x())) > qApp->styleHints()->startDragDistance())
1316 setKeepMouseGrab(true);
1318 if (d->composeMode()) {
1320 int startPos = d->positionAt(d->pressPos);
1321 int currentPos = d->positionAt(event->localPos());
1322 if (startPos != currentPos)
1323 d->setSelection(startPos, currentPos - startPos);
1325 moveCursorSelection(d->positionAt(event->localPos()), d->mouseSelectionMode);
1327 event->setAccepted(true);
1329 QQuickImplicitSizeItem::mouseMoveEvent(event);
1333 void QQuickTextInput::mouseReleaseEvent(QMouseEvent *event)
1335 Q_D(QQuickTextInput);
1336 if (d->sendMouseEventToInputContext(event))
1338 if (d->selectPressed) {
1339 d->selectPressed = false;
1340 setKeepMouseGrab(false);
1342 #ifndef QT_NO_CLIPBOARD
1343 if (QGuiApplication::clipboard()->supportsSelection()) {
1344 if (event->button() == Qt::LeftButton) {
1345 d->copy(QClipboard::Selection);
1346 } else if (!d->m_readOnly && event->button() == Qt::MidButton) {
1348 d->insert(QGuiApplication::clipboard()->text(QClipboard::Selection));
1352 if (!event->isAccepted())
1353 QQuickImplicitSizeItem::mouseReleaseEvent(event);
1356 bool QQuickTextInputPrivate::sendMouseEventToInputContext(QMouseEvent *event)
1358 #if !defined QT_NO_IM
1359 if (composeMode()) {
1360 int tmp_cursor = positionAt(event->localPos());
1361 int mousePos = tmp_cursor - m_cursor;
1362 if (mousePos >= 0 && mousePos <= m_textLayout.preeditAreaText().length()) {
1363 if (event->type() == QEvent::MouseButtonRelease) {
1364 qApp->inputPanel()->invokeAction(QInputPanel::Click, mousePos);
1377 void QQuickTextInput::mouseUngrabEvent()
1379 Q_D(QQuickTextInput);
1380 d->selectPressed = false;
1381 setKeepMouseGrab(false);
1384 bool QQuickTextInput::event(QEvent* ev)
1386 #ifndef QT_NO_SHORTCUT
1387 Q_D(QQuickTextInput);
1388 if (ev->type() == QEvent::ShortcutOverride) {
1391 QKeyEvent* ke = static_cast<QKeyEvent*>(ev);
1392 if (ke == QKeySequence::Copy
1393 || ke == QKeySequence::Paste
1394 || ke == QKeySequence::Cut
1395 || ke == QKeySequence::Redo
1396 || ke == QKeySequence::Undo
1397 || ke == QKeySequence::MoveToNextWord
1398 || ke == QKeySequence::MoveToPreviousWord
1399 || ke == QKeySequence::MoveToStartOfDocument
1400 || ke == QKeySequence::MoveToEndOfDocument
1401 || ke == QKeySequence::SelectNextWord
1402 || ke == QKeySequence::SelectPreviousWord
1403 || ke == QKeySequence::SelectStartOfLine
1404 || ke == QKeySequence::SelectEndOfLine
1405 || ke == QKeySequence::SelectStartOfBlock
1406 || ke == QKeySequence::SelectEndOfBlock
1407 || ke == QKeySequence::SelectStartOfDocument
1408 || ke == QKeySequence::SelectAll
1409 || ke == QKeySequence::SelectEndOfDocument) {
1411 } else if (ke->modifiers() == Qt::NoModifier || ke->modifiers() == Qt::ShiftModifier
1412 || ke->modifiers() == Qt::KeypadModifier) {
1413 if (ke->key() < Qt::Key_Escape) {
1417 switch (ke->key()) {
1418 case Qt::Key_Delete:
1421 case Qt::Key_Backspace:
1433 return QQuickImplicitSizeItem::event(ev);
1436 void QQuickTextInput::geometryChanged(const QRectF &newGeometry,
1437 const QRectF &oldGeometry)
1439 Q_D(QQuickTextInput);
1440 if (newGeometry.width() != oldGeometry.width())
1442 updateCursorRectangle();
1443 QQuickImplicitSizeItem::geometryChanged(newGeometry, oldGeometry);
1446 void QQuickTextInputPrivate::updateHorizontalScroll()
1448 Q_Q(QQuickTextInput);
1449 QTextLine currentLine = m_textLayout.lineForTextPosition(m_cursor + m_preeditCursor);
1450 const int preeditLength = m_textLayout.preeditAreaText().length();
1451 const int width = qMax(0, qFloor(q->width()));
1452 int widthUsed = currentLine.isValid() ? qRound(currentLine.naturalTextWidth()) : 0;
1453 int previousScroll = hscroll;
1455 if (!autoScroll || widthUsed <= width || m_echoMode == QQuickTextInput::NoEcho) {
1458 Q_ASSERT(currentLine.isValid());
1459 int cix = qRound(currentLine.cursorToX(m_cursor + preeditLength));
1460 if (cix - hscroll >= width) {
1461 // text doesn't fit, cursor is to the right of br (scroll right)
1462 hscroll = cix - width;
1463 } else if (cix - hscroll < 0 && hscroll < widthUsed) {
1464 // text doesn't fit, cursor is to the left of br (scroll left)
1466 } else if (widthUsed - hscroll < width) {
1467 // text doesn't fit, text document is to the left of br; align
1469 hscroll = widthUsed - width;
1471 if (preeditLength > 0) {
1472 // check to ensure long pre-edit text doesn't push the cursor
1474 cix = qRound(currentLine.cursorToX(m_cursor + qMax(0, m_preeditCursor - 1)));
1479 if (previousScroll != hscroll)
1480 textLayoutDirty = true;
1483 void QQuickTextInputPrivate::updateVerticalScroll()
1485 Q_Q(QQuickTextInput);
1486 const int preeditLength = m_textLayout.preeditAreaText().length();
1487 const int height = qMax(0, qFloor(q->height()));
1488 int heightUsed = boundingRect.height();
1489 int previousScroll = vscroll;
1491 if (!autoScroll || heightUsed <= height) {
1492 // text fits in br; use vscroll for alignment
1493 switch (vAlign & ~(Qt::AlignAbsolute|Qt::AlignHorizontal_Mask)) {
1494 case Qt::AlignBottom:
1495 vscroll = heightUsed - height;
1497 case Qt::AlignVCenter:
1498 vscroll = (heightUsed - height) / 2;
1506 QTextLine currentLine = m_textLayout.lineForTextPosition(m_cursor + preeditLength);
1507 QRectF r = currentLine.isValid() ? currentLine.rect() : QRectF();
1508 int top = qFloor(r.top());
1509 int bottom = qCeil(r.bottom());
1511 if (bottom - vscroll >= height) {
1512 // text doesn't fit, cursor is to the below the br (scroll down)
1513 vscroll = bottom - height;
1514 } else if (top - vscroll < 0 && vscroll < heightUsed) {
1515 // text doesn't fit, cursor is above br (scroll up)
1517 } else if (heightUsed - vscroll < height) {
1518 // text doesn't fit, text document is to the left of br; align
1520 vscroll = heightUsed - height;
1522 if (preeditLength > 0) {
1523 // check to ensure long pre-edit text doesn't push the cursor
1525 currentLine = m_textLayout.lineForTextPosition(m_cursor + qMax(0, m_preeditCursor - 1));
1526 top = currentLine.isValid() ? qRound(currentLine.rect().top()) : 0;
1531 if (previousScroll != vscroll)
1532 textLayoutDirty = true;
1535 QSGNode *QQuickTextInput::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data)
1538 Q_D(QQuickTextInput);
1540 QQuickTextNode *node = static_cast<QQuickTextNode *>(oldNode);
1542 node = new QQuickTextNode(QQuickItemPrivate::get(this)->sceneGraphContext());
1545 if (!d->textLayoutDirty) {
1546 QSGSimpleRectNode *cursorNode = node->cursorNode();
1547 if (cursorNode != 0 && !isReadOnly()) {
1548 cursorNode->setRect(cursorRectangle());
1550 if (!d->cursorVisible || (!d->m_blinkStatus && d->m_blinkPeriod > 0)) {
1557 node->deleteContent();
1558 node->setMatrix(QMatrix4x4());
1560 QPoint offset = QPoint(0,0);
1561 QFontMetrics fm = QFontMetrics(d->font);
1562 if (d->autoScroll) {
1563 // the y offset is there to keep the baseline constant in case we have script changes in the text.
1564 offset = -QPoint(d->hscroll, d->vscroll + d->m_ascent - fm.ascent());
1566 offset = -QPoint(d->hscroll, d->vscroll);
1569 if (!d->m_textLayout.text().isEmpty()) {
1570 node->addTextLayout(offset, &d->m_textLayout, d->color,
1571 QQuickText::Normal, QColor(),
1572 d->selectionColor, d->selectedTextColor,
1573 d->selectionStart(),
1574 d->selectionEnd() - 1); // selectionEnd() returns first char after
1578 if (!isReadOnly() && d->cursorItem == 0) {
1579 node->setCursor(cursorRectangle(), d->color);
1580 if (!d->cursorVisible || (!d->m_blinkStatus && d->m_blinkPeriod > 0)) {
1587 d->textLayoutDirty = false;
1593 QVariant QQuickTextInput::inputMethodQuery(Qt::InputMethodQuery property) const
1595 Q_D(const QQuickTextInput);
1598 return QVariant((bool)(flags() & ItemAcceptsInputMethod));
1600 return QVariant((int)inputMethodHints());
1601 case Qt::ImCursorRectangle:
1602 return cursorRectangle();
1605 case Qt::ImCursorPosition:
1606 return QVariant(d->m_cursor);
1607 case Qt::ImSurroundingText:
1608 if (d->m_echoMode == PasswordEchoOnEdit && !d->m_passwordEchoEditing) {
1609 return QVariant(displayText());
1611 return QVariant(d->realText());
1613 case Qt::ImCurrentSelection:
1614 return QVariant(selectedText());
1615 case Qt::ImMaximumTextLength:
1616 return QVariant(maxLength());
1617 case Qt::ImAnchorPosition:
1618 if (d->selectionStart() == d->selectionEnd())
1619 return QVariant(d->m_cursor);
1620 else if (d->selectionStart() == d->m_cursor)
1621 return QVariant(d->selectionEnd());
1623 return QVariant(d->selectionStart());
1630 \qmlmethod void QtQuick2::TextInput::deselect()
1632 Removes active text selection.
1634 void QQuickTextInput::deselect()
1636 Q_D(QQuickTextInput);
1641 \qmlmethod void QtQuick2::TextInput::selectAll()
1643 Causes all text to be selected.
1645 void QQuickTextInput::selectAll()
1647 Q_D(QQuickTextInput);
1648 d->setSelection(0, text().length());
1652 \qmlmethod void QtQuick2::TextInput::isRightToLeft(int start, int end)
1654 Returns true if the natural reading direction of the editor text
1655 found between positions \a start and \a end is right to left.
1657 bool QQuickTextInput::isRightToLeft(int start, int end)
1660 qmlInfo(this) << "isRightToLeft(start, end) called with the end property being smaller than the start.";
1663 return text().mid(start, end - start).isRightToLeft();
1667 #ifndef QT_NO_CLIPBOARD
1669 \qmlmethod QtQuick2::TextInput::cut()
1671 Moves the currently selected text to the system clipboard.
1673 void QQuickTextInput::cut()
1675 Q_D(QQuickTextInput);
1681 \qmlmethod QtQuick2::TextInput::copy()
1683 Copies the currently selected text to the system clipboard.
1685 void QQuickTextInput::copy()
1687 Q_D(QQuickTextInput);
1692 \qmlmethod QtQuick2::TextInput::paste()
1694 Replaces the currently selected text by the contents of the system clipboard.
1696 void QQuickTextInput::paste()
1698 Q_D(QQuickTextInput);
1702 #endif // QT_NO_CLIPBOARD
1705 \qmlmethod void QtQuick2::TextInput::insert(int position, string text)
1707 Inserts \a text into the TextInput at position.
1710 void QQuickTextInput::insert(int position, const QString &text)
1712 Q_D(QQuickTextInput);
1713 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
1714 if (d->m_echoMode == QQuickTextInput::Password)
1715 d->m_passwordEchoTimer.start(qt_passwordEchoDelay, this);
1718 if (position < 0 || position > d->m_text.length())
1721 const int priorState = d->m_undoState;
1723 QString insertText = text;
1725 if (d->hasSelectedText()) {
1726 d->addCommand(QQuickTextInputPrivate::Command(
1727 QQuickTextInputPrivate::SetSelection, d->m_cursor, 0, d->m_selstart, d->m_selend));
1729 if (d->m_maskData) {
1730 insertText = d->maskString(position, insertText);
1731 for (int i = 0; i < insertText.length(); ++i) {
1732 d->addCommand(QQuickTextInputPrivate::Command(
1733 QQuickTextInputPrivate::DeleteSelection, position + i, d->m_text.at(position + i), -1, -1));
1734 d->addCommand(QQuickTextInputPrivate::Command(
1735 QQuickTextInputPrivate::Insert, position + i, insertText.at(i), -1, -1));
1737 d->m_text.replace(position, insertText.length(), insertText);
1738 if (!insertText.isEmpty())
1739 d->m_textDirty = true;
1740 if (position < d->m_selend && position + insertText.length() > d->m_selstart)
1741 d->m_selDirty = true;
1743 int remaining = d->m_maxLength - d->m_text.length();
1744 if (remaining != 0) {
1745 insertText = insertText.left(remaining);
1746 d->m_text.insert(position, insertText);
1747 for (int i = 0; i < insertText.length(); ++i)
1748 d->addCommand(QQuickTextInputPrivate::Command(
1749 QQuickTextInputPrivate::Insert, position + i, insertText.at(i), -1, -1));
1750 if (d->m_cursor >= position)
1751 d->m_cursor += insertText.length();
1752 if (d->m_selstart >= position)
1753 d->m_selstart += insertText.length();
1754 if (d->m_selend >= position)
1755 d->m_selend += insertText.length();
1756 d->m_textDirty = true;
1757 if (position >= d->m_selstart && position <= d->m_selend)
1758 d->m_selDirty = true;
1762 d->addCommand(QQuickTextInputPrivate::Command(
1763 QQuickTextInputPrivate::SetSelection, d->m_cursor, 0, d->m_selstart, d->m_selend));
1764 d->finishChange(priorState);
1766 if (d->lastSelectionStart != d->lastSelectionEnd) {
1767 if (d->m_selstart != d->lastSelectionStart) {
1768 d->lastSelectionStart = d->m_selstart;
1769 emit selectionStartChanged();
1771 if (d->m_selend != d->lastSelectionEnd) {
1772 d->lastSelectionEnd = d->m_selend;
1773 emit selectionEndChanged();
1779 \qmlmethod string QtQuick2::TextInput::getText(int start, int end)
1781 Removes the section of text that is between the \a start and \a end positions from the TextInput.
1784 void QQuickTextInput::remove(int start, int end)
1786 Q_D(QQuickTextInput);
1788 start = qBound(0, start, d->m_text.length());
1789 end = qBound(0, end, d->m_text.length());
1793 else if (start == end)
1796 if (start < d->m_selend && end > d->m_selstart)
1797 d->m_selDirty = true;
1799 const int priorState = d->m_undoState;
1801 d->addCommand(QQuickTextInputPrivate::Command(
1802 QQuickTextInputPrivate::SetSelection, d->m_cursor, 0, d->m_selstart, d->m_selend));
1804 if (start <= d->m_cursor && d->m_cursor < end) {
1805 // cursor is within the selection. Split up the commands
1806 // to be able to restore the correct cursor position
1807 for (int i = d->m_cursor; i >= start; --i) {
1808 d->addCommand(QQuickTextInputPrivate::Command(
1809 QQuickTextInputPrivate::DeleteSelection, i, d->m_text.at(i), -1, 1));
1811 for (int i = end - 1; i > d->m_cursor; --i) {
1812 d->addCommand(QQuickTextInputPrivate::Command(
1813 QQuickTextInputPrivate::DeleteSelection, i - d->m_cursor + start - 1, d->m_text.at(i), -1, -1));
1816 for (int i = end - 1; i >= start; --i) {
1817 d->addCommand(QQuickTextInputPrivate::Command(
1818 QQuickTextInputPrivate::RemoveSelection, i, d->m_text.at(i), -1, -1));
1821 if (d->m_maskData) {
1822 d->m_text.replace(start, end - start, d->clearString(start, end - start));
1823 for (int i = 0; i < end - start; ++i) {
1824 d->addCommand(QQuickTextInputPrivate::Command(
1825 QQuickTextInputPrivate::Insert, start + i, d->m_text.at(start + i), -1, -1));
1828 d->m_text.remove(start, end - start);
1830 if (d->m_cursor > start)
1831 d->m_cursor -= qMin(d->m_cursor, end) - start;
1832 if (d->m_selstart > start)
1833 d->m_selstart -= qMin(d->m_selstart, end) - start;
1834 if (d->m_selend > end)
1835 d->m_selend -= qMin(d->m_selend, end) - start;
1837 d->addCommand(QQuickTextInputPrivate::Command(
1838 QQuickTextInputPrivate::SetSelection, d->m_cursor, 0, d->m_selstart, d->m_selend));
1840 d->m_textDirty = true;
1841 d->finishChange(priorState);
1843 if (d->lastSelectionStart != d->lastSelectionEnd) {
1844 if (d->m_selstart != d->lastSelectionStart) {
1845 d->lastSelectionStart = d->m_selstart;
1846 emit selectionStartChanged();
1848 if (d->m_selend != d->lastSelectionEnd) {
1849 d->lastSelectionEnd = d->m_selend;
1850 emit selectionEndChanged();
1857 \qmlmethod void QtQuick2::TextInput::selectWord()
1859 Causes the word closest to the current cursor position to be selected.
1861 void QQuickTextInput::selectWord()
1863 Q_D(QQuickTextInput);
1864 d->selectWordAtPos(d->m_cursor);
1868 \qmlproperty bool QtQuick2::TextInput::smooth
1870 This property holds whether the text is smoothly scaled or transformed.
1872 Smooth filtering gives better visual quality, but is slower. If
1873 the item is displayed at its natural size, this property has no visual or
1876 \note Generally scaling artifacts are only visible if the item is stationary on
1877 the screen. A common pattern when animating an item is to disable smooth
1878 filtering at the beginning of the animation and reenable it at the conclusion.
1882 \qmlproperty string QtQuick2::TextInput::passwordCharacter
1884 This is the character displayed when echoMode is set to Password or
1885 PasswordEchoOnEdit. By default it is an asterisk.
1887 If this property is set to a string with more than one character,
1888 the first character is used. If the string is empty, the value
1889 is ignored and the property is not set.
1891 QString QQuickTextInput::passwordCharacter() const
1893 Q_D(const QQuickTextInput);
1894 return QString(d->m_passwordCharacter);
1897 void QQuickTextInput::setPasswordCharacter(const QString &str)
1899 Q_D(QQuickTextInput);
1900 if (str.length() < 1)
1902 d->m_passwordCharacter = str.constData()[0];
1903 if (d->m_echoMode == Password || d->m_echoMode == PasswordEchoOnEdit)
1904 d->updateDisplayText();
1905 emit passwordCharacterChanged();
1909 \qmlproperty string QtQuick2::TextInput::displayText
1911 This is the text displayed in the TextInput.
1913 If \l echoMode is set to TextInput::Normal, this holds the
1914 same value as the TextInput::text property. Otherwise,
1915 this property holds the text visible to the user, while
1916 the \l text property holds the actual entered text.
1918 QString QQuickTextInput::displayText() const
1920 Q_D(const QQuickTextInput);
1921 return d->m_textLayout.text();
1925 \qmlproperty bool QtQuick2::TextInput::selectByMouse
1929 If true, the user can use the mouse to select text in some
1930 platform-specific way. Note that for some platforms this may
1931 not be an appropriate interaction (eg. may conflict with how
1932 the text needs to behave inside a Flickable.
1934 bool QQuickTextInput::selectByMouse() const
1936 Q_D(const QQuickTextInput);
1937 return d->selectByMouse;
1940 void QQuickTextInput::setSelectByMouse(bool on)
1942 Q_D(QQuickTextInput);
1943 if (d->selectByMouse != on) {
1944 d->selectByMouse = on;
1945 emit selectByMouseChanged(on);
1950 \qmlproperty enum QtQuick2::TextInput::mouseSelectionMode
1952 Specifies how text should be selected using a mouse.
1955 \o TextInput.SelectCharacters - The selection is updated with individual characters. (Default)
1956 \o TextInput.SelectWords - The selection is updated with whole words.
1959 This property only applies when \l selectByMouse is true.
1962 QQuickTextInput::SelectionMode QQuickTextInput::mouseSelectionMode() const
1964 Q_D(const QQuickTextInput);
1965 return d->mouseSelectionMode;
1968 void QQuickTextInput::setMouseSelectionMode(SelectionMode mode)
1970 Q_D(QQuickTextInput);
1971 if (d->mouseSelectionMode != mode) {
1972 d->mouseSelectionMode = mode;
1973 emit mouseSelectionModeChanged(mode);
1978 \qmlproperty bool QtQuick2::TextInput::canPaste
1980 Returns true if the TextInput is writable and the content of the clipboard is
1981 suitable for pasting into the TextEdit.
1983 bool QQuickTextInput::canPaste() const
1985 Q_D(const QQuickTextInput);
1986 if (!d->canPasteValid) {
1987 if (const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData())
1988 const_cast<QQuickTextInputPrivate *>(d)->canPaste = !d->m_readOnly && mimeData->hasText();
1989 const_cast<QQuickTextInputPrivate *>(d)->canPasteValid = true;
1994 void QQuickTextInput::moveCursorSelection(int position)
1996 Q_D(QQuickTextInput);
1997 d->moveCursor(position, true);
2001 \qmlmethod void QtQuick2::TextInput::moveCursorSelection(int position, SelectionMode mode = TextInput.SelectCharacters)
2003 Moves the cursor to \a position and updates the selection according to the optional \a mode
2004 parameter. (To only move the cursor, set the \l cursorPosition property.)
2006 When this method is called it additionally sets either the
2007 selectionStart or the selectionEnd (whichever was at the previous cursor position)
2008 to the specified position. This allows you to easily extend and contract the selected
2011 The selection mode specifies whether the selection is updated on a per character or a per word
2012 basis. If not specified the selection mode will default to TextInput.SelectCharacters.
2015 \o TextEdit.SelectCharacters - Sets either the selectionStart or selectionEnd (whichever was at
2016 the previous cursor position) to the specified position.
2017 \o TextEdit.SelectWords - Sets the selectionStart and selectionEnd to include all
2018 words between the specified position and the previous cursor position. Words partially in the
2022 For example, take this sequence of calls:
2026 moveCursorSelection(9, TextInput.SelectCharacters)
2027 moveCursorSelection(7, TextInput.SelectCharacters)
2030 This moves the cursor to position 5, extend the selection end from 5 to 9
2031 and then retract the selection end from 9 to 7, leaving the text from position 5 to 7
2032 selected (the 6th and 7th characters).
2034 The same sequence with TextInput.SelectWords will extend the selection start to a word boundary
2035 before or on position 5 and extend the selection end to a word boundary on or past position 9.
2037 void QQuickTextInput::moveCursorSelection(int pos, SelectionMode mode)
2039 Q_D(QQuickTextInput);
2041 if (mode == SelectCharacters) {
2042 d->moveCursor(pos, true);
2043 } else if (pos != d->m_cursor){
2044 const int cursor = d->m_cursor;
2046 if (!d->hasSelectedText())
2047 anchor = d->m_cursor;
2048 else if (d->selectionStart() == d->m_cursor)
2049 anchor = d->selectionEnd();
2051 anchor = d->selectionStart();
2053 if (anchor < pos || (anchor == pos && cursor < pos)) {
2054 const QString text = this->text();
2055 QTextBoundaryFinder finder(QTextBoundaryFinder::Word, text);
2056 finder.setPosition(anchor);
2058 const QTextBoundaryFinder::BoundaryReasons reasons = finder.boundaryReasons();
2059 if (anchor < text.length() && (!(reasons & QTextBoundaryFinder::StartWord)
2060 || ((reasons & QTextBoundaryFinder::EndWord) && anchor > cursor))) {
2061 finder.toPreviousBoundary();
2063 anchor = finder.position() != -1 ? finder.position() : 0;
2065 finder.setPosition(pos);
2066 if (pos > 0 && !finder.boundaryReasons())
2067 finder.toNextBoundary();
2068 const int cursor = finder.position() != -1 ? finder.position() : text.length();
2070 d->setSelection(anchor, cursor - anchor);
2071 } else if (anchor > pos || (anchor == pos && cursor > pos)) {
2072 const QString text = this->text();
2073 QTextBoundaryFinder finder(QTextBoundaryFinder::Word, text);
2074 finder.setPosition(anchor);
2076 const QTextBoundaryFinder::BoundaryReasons reasons = finder.boundaryReasons();
2077 if (anchor > 0 && (!(reasons & QTextBoundaryFinder::EndWord)
2078 || ((reasons & QTextBoundaryFinder::StartWord) && anchor < cursor))) {
2079 finder.toNextBoundary();
2082 anchor = finder.position() != -1 ? finder.position() : text.length();
2084 finder.setPosition(pos);
2085 if (pos < text.length() && !finder.boundaryReasons())
2086 finder.toPreviousBoundary();
2087 const int cursor = finder.position() != -1 ? finder.position() : 0;
2089 d->setSelection(anchor, cursor - anchor);
2095 \qmlmethod void QtQuick2::TextInput::openSoftwareInputPanel()
2097 Opens software input panels like virtual keyboards for typing, useful for
2098 customizing when you want the input keyboard to be shown and hidden in
2101 By default the opening of input panels follows the platform style. Input panels are
2102 always closed if no editor has active focus.
2104 You can disable the automatic behavior by setting the property \c activeFocusOnPress to false
2105 and use functions openSoftwareInputPanel() and closeSoftwareInputPanel() to implement
2106 the behavior you want.
2108 Only relevant on platforms, which provide virtual keyboards.
2114 text: "Hello world!"
2115 activeFocusOnPress: false
2117 anchors.fill: parent
2119 if (!textInput.activeFocus) {
2120 textInput.forceActiveFocus()
2121 textInput.openSoftwareInputPanel();
2123 textInput.focus = false;
2126 onPressAndHold: textInput.closeSoftwareInputPanel();
2131 void QQuickTextInput::openSoftwareInputPanel()
2134 qGuiApp->inputPanel()->show();
2138 \qmlmethod void QtQuick2::TextInput::closeSoftwareInputPanel()
2140 Closes a software input panel like a virtual keyboard shown on the screen, useful
2141 for customizing when you want the input keyboard to be shown and hidden in
2144 By default the opening of input panels follows the platform style. Input panels are
2145 always closed if no editor has active focus.
2147 You can disable the automatic behavior by setting the property \c activeFocusOnPress to false
2148 and use functions openSoftwareInputPanel() and closeSoftwareInputPanel() to implement
2149 the behavior you want.
2151 Only relevant on platforms, which provide virtual keyboards.
2157 text: "Hello world!"
2158 activeFocusOnPress: false
2160 anchors.fill: parent
2162 if (!textInput.activeFocus) {
2163 textInput.forceActiveFocus();
2164 textInput.openSoftwareInputPanel();
2166 textInput.focus = false;
2169 onPressAndHold: textInput.closeSoftwareInputPanel();
2174 void QQuickTextInput::closeSoftwareInputPanel()
2177 qGuiApp->inputPanel()->hide();
2180 void QQuickTextInput::focusInEvent(QFocusEvent *event)
2182 Q_D(const QQuickTextInput);
2183 if (d->focusOnPress && !d->m_readOnly)
2184 openSoftwareInputPanel();
2185 QQuickImplicitSizeItem::focusInEvent(event);
2188 void QQuickTextInput::itemChange(ItemChange change, const ItemChangeData &value)
2190 Q_D(QQuickTextInput);
2191 if (change == ItemActiveFocusHasChanged) {
2192 bool hasFocus = value.boolValue;
2193 d->focused = hasFocus;
2194 setCursorVisible(hasFocus); // ### refactor: && d->canvas && d->canvas->hasFocus()
2195 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
2196 if (!hasFocus && (d->m_passwordEchoEditing || d->m_passwordEchoTimer.isActive())) {
2198 if (!hasFocus && d->m_passwordEchoEditing) {
2200 d->updatePasswordEchoEditing(false);//QQuickTextInputPrivate sets it on key events, but doesn't deal with focus events
2208 QQuickItem::itemChange(change, value);
2212 \qmlproperty bool QtQuick2::TextInput::inputMethodComposing
2215 This property holds whether the TextInput has partial text input from an
2218 While it is composing an input method may rely on mouse or key events from
2219 the TextInput to edit or commit the partial text. This property can be
2220 used to determine when to disable events handlers that may interfere with
2221 the correct operation of an input method.
2223 bool QQuickTextInput::isInputMethodComposing() const
2225 Q_D(const QQuickTextInput);
2226 return d->preeditAreaText().length() > 0;
2229 void QQuickTextInputPrivate::init()
2231 Q_Q(QQuickTextInput);
2232 q->setSmooth(smooth);
2233 q->setAcceptedMouseButtons(Qt::LeftButton);
2234 q->setFlag(QQuickItem::ItemAcceptsInputMethod);
2235 q->setFlag(QQuickItem::ItemHasContents);
2236 #ifndef QT_NO_CLIPBOARD
2237 q->connect(QGuiApplication::clipboard(), SIGNAL(dataChanged()),
2238 q, SLOT(q_canPasteChanged()));
2239 #endif // QT_NO_CLIPBOARD
2241 oldValidity = hasAcceptableInput(m_text);
2242 lastSelectionStart = 0;
2243 lastSelectionEnd = 0;
2244 selectedTextColor = m_palette.color(QPalette::HighlightedText);
2245 selectionColor = m_palette.color(QPalette::Highlight);
2246 determineHorizontalAlignment();
2248 if (!qmlDisableDistanceField()) {
2249 QTextOption option = m_textLayout.textOption();
2250 option.setUseDesignMetrics(true);
2251 m_textLayout.setTextOption(option);
2255 void QQuickTextInput::updateCursorRectangle()
2257 Q_D(QQuickTextInput);
2258 if (!isComponentComplete())
2261 d->updateHorizontalScroll();
2262 d->updateVerticalScroll();
2265 emit cursorRectangleChanged();
2266 if (d->cursorItem) {
2267 QRectF r = cursorRectangle();
2268 d->cursorItem->setPos(r.topLeft());
2269 d->cursorItem->setHeight(r.height());
2273 void QQuickTextInput::selectionChanged()
2275 Q_D(QQuickTextInput);
2276 d->textLayoutDirty = true; //TODO: Only update rect in selection
2278 emit selectedTextChanged();
2280 if (d->lastSelectionStart != d->selectionStart()) {
2281 d->lastSelectionStart = d->selectionStart();
2282 if (d->lastSelectionStart == -1)
2283 d->lastSelectionStart = d->m_cursor;
2284 emit selectionStartChanged();
2286 if (d->lastSelectionEnd != d->selectionEnd()) {
2287 d->lastSelectionEnd = d->selectionEnd();
2288 if (d->lastSelectionEnd == -1)
2289 d->lastSelectionEnd = d->m_cursor;
2290 emit selectionEndChanged();
2294 void QQuickTextInputPrivate::showCursor()
2296 if (textNode != 0 && textNode->cursorNode() != 0)
2297 textNode->cursorNode()->setColor(color);
2300 void QQuickTextInputPrivate::hideCursor()
2302 if (textNode != 0 && textNode->cursorNode() != 0)
2303 textNode->cursorNode()->setColor(QColor(0, 0, 0, 0));
2306 QRectF QQuickTextInput::boundingRect() const
2308 Q_D(const QQuickTextInput);
2310 QRectF r = d->boundingRect;
2311 int cursorWidth = d->cursorItem ? d->cursorItem->width() : d->m_cursorWidth;
2313 // Could include font max left/right bearings to either side of rectangle.
2315 r.setRight(r.right() + cursorWidth);
2316 r.translate(-d->hscroll, -d->vscroll);
2320 void QQuickTextInput::q_canPasteChanged()
2322 Q_D(QQuickTextInput);
2323 bool old = d->canPaste;
2324 #ifndef QT_NO_CLIPBOARD
2325 if (const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData())
2326 d->canPaste = !d->m_readOnly && mimeData->hasText();
2328 d->canPaste = false;
2331 bool changed = d->canPaste != old || !d->canPasteValid;
2332 d->canPasteValid = true;
2334 emit canPasteChanged();
2338 // ### these should come from QStyleHints
2339 const int textCursorWidth = 1;
2340 const bool fullWidthSelection = true;
2345 Updates the display text based of the current edit text
2346 If the text has changed will emit displayTextChanged()
2348 void QQuickTextInputPrivate::updateDisplayText(bool forceUpdate)
2350 QString orig = m_textLayout.text();
2352 if (m_echoMode == QQuickTextInput::NoEcho)
2353 str = QString::fromLatin1("");
2357 if (m_echoMode == QQuickTextInput::Password) {
2358 str.fill(m_passwordCharacter);
2359 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
2360 if (m_passwordEchoTimer.isActive() && m_cursor > 0 && m_cursor <= m_text.length()) {
2361 int cursor = m_cursor - 1;
2362 QChar uc = m_text.at(cursor);
2364 if (cursor > 0 && uc.unicode() >= 0xdc00 && uc.unicode() < 0xe000) {
2365 // second half of a surrogate, check if we have the first half as well,
2366 // if yes restore both at once
2367 uc = m_text.at(cursor - 1);
2368 if (uc.unicode() >= 0xd800 && uc.unicode() < 0xdc00)
2369 str[cursor - 1] = uc;
2373 } else if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit && !m_passwordEchoEditing) {
2374 str.fill(m_passwordCharacter);
2377 // replace certain non-printable characters with spaces (to avoid
2378 // drawing boxes when using fonts that don't have glyphs for such
2380 QChar* uc = str.data();
2381 for (int i = 0; i < (int)str.length(); ++i) {
2382 if ((uc[i] < 0x20 && uc[i] != 0x09)
2383 || uc[i] == QChar::LineSeparator
2384 || uc[i] == QChar::ParagraphSeparator
2385 || uc[i] == QChar::ObjectReplacementCharacter)
2386 uc[i] = QChar(0x0020);
2389 if (str != orig || forceUpdate) {
2390 m_textLayout.setText(str);
2391 updateLayout(); // polish?
2392 emit q_func()->displayTextChanged();
2396 void QQuickTextInputPrivate::updateLayout()
2398 Q_Q(QQuickTextInput);
2400 if (!q->isComponentComplete())
2403 QTextOption option = m_textLayout.textOption();
2404 option.setTextDirection(m_layoutDirection);
2405 option.setFlags(QTextOption::IncludeTrailingSpaces);
2406 option.setWrapMode(QTextOption::WrapMode(wrapMode));
2407 option.setAlignment(Qt::Alignment(q->effectiveHAlign()));
2408 m_textLayout.setTextOption(option);
2409 m_textLayout.setFont(font);
2411 boundingRect = QRectF();
2412 m_textLayout.beginLayout();
2413 QTextLine line = m_textLayout.createLine();
2414 qreal lineWidth = q->widthValid() ? q->width() : INT_MAX;
2416 QTextLine firstLine = line;
2418 line.setLineWidth(lineWidth);
2419 line.setPosition(QPointF(line.position().x(), height));
2420 boundingRect = boundingRect.united(line.naturalTextRect());
2422 height += line.height();
2423 line = m_textLayout.createLine();
2424 } while (line.isValid());
2425 m_textLayout.endLayout();
2427 option.setWrapMode(QTextOption::NoWrap);
2428 m_textLayout.setTextOption(option);
2430 m_ascent = qRound(firstLine.ascent());
2431 textLayoutDirty = true;
2434 q->setImplicitSize(qCeil(boundingRect.width()), qCeil(boundingRect.height()));
2438 #ifndef QT_NO_CLIPBOARD
2442 Copies the currently selected text into the clipboard using the given
2445 \note If the echo mode is set to a mode other than Normal then copy
2446 will not work. This is to prevent using copy as a method of bypassing
2447 password features of the line control.
2449 void QQuickTextInputPrivate::copy(QClipboard::Mode mode) const
2451 QString t = selectedText();
2452 if (!t.isEmpty() && m_echoMode == QQuickTextInput::Normal) {
2453 QGuiApplication::clipboard()->setText(t, mode);
2460 Inserts the text stored in the application clipboard into the line
2465 void QQuickTextInputPrivate::paste(QClipboard::Mode clipboardMode)
2467 QString clip = QGuiApplication::clipboard()->text(clipboardMode);
2468 if (!clip.isEmpty() || hasSelectedText()) {
2469 separate(); //make it a separate undo/redo command
2475 #endif // !QT_NO_CLIPBOARD
2480 Exits preedit mode and commits parts marked as tentative commit
2482 void QQuickTextInputPrivate::commitPreedit()
2487 qApp->inputPanel()->reset();
2489 if (!m_tentativeCommit.isEmpty()) {
2490 internalInsert(m_tentativeCommit);
2491 m_tentativeCommit.clear();
2492 finishChange(-1, true/*not used, not documented*/, false);
2495 m_preeditCursor = 0;
2496 m_textLayout.setPreeditArea(-1, QString());
2497 m_textLayout.clearAdditionalFormats();
2504 Handles the behavior for the backspace key or function.
2505 Removes the current selection if there is a selection, otherwise
2506 removes the character prior to the cursor position.
2510 void QQuickTextInputPrivate::backspace()
2512 int priorState = m_undoState;
2513 if (hasSelectedText()) {
2514 removeSelectedText();
2515 } else if (m_cursor) {
2518 m_cursor = prevMaskBlank(m_cursor);
2519 QChar uc = m_text.at(m_cursor);
2520 if (m_cursor > 0 && uc.unicode() >= 0xdc00 && uc.unicode() < 0xe000) {
2521 // second half of a surrogate, check if we have the first half as well,
2522 // if yes delete both at once
2523 uc = m_text.at(m_cursor - 1);
2524 if (uc.unicode() >= 0xd800 && uc.unicode() < 0xdc00) {
2525 internalDelete(true);
2529 internalDelete(true);
2531 finishChange(priorState);
2537 Handles the behavior for the delete key or function.
2538 Removes the current selection if there is a selection, otherwise
2539 removes the character after the cursor position.
2543 void QQuickTextInputPrivate::del()
2545 int priorState = m_undoState;
2546 if (hasSelectedText()) {
2547 removeSelectedText();
2549 int n = m_textLayout.nextCursorPosition(m_cursor) - m_cursor;
2553 finishChange(priorState);
2559 Inserts the given \a newText at the current cursor position.
2560 If there is any selected text it is removed prior to insertion of
2563 void QQuickTextInputPrivate::insert(const QString &newText)
2565 int priorState = m_undoState;
2566 removeSelectedText();
2567 internalInsert(newText);
2568 finishChange(priorState);
2574 Clears the line control text.
2576 void QQuickTextInputPrivate::clear()
2578 int priorState = m_undoState;
2580 m_selend = m_text.length();
2581 removeSelectedText();
2583 finishChange(priorState, /*update*/false, /*edited*/false);
2589 Sets \a length characters from the given \a start position as selected.
2590 The given \a start position must be within the current text for
2591 the line control. If \a length characters cannot be selected, then
2592 the selection will extend to the end of the current text.
2594 void QQuickTextInputPrivate::setSelection(int start, int length)
2596 Q_Q(QQuickTextInput);
2599 if (start < 0 || start > (int)m_text.length()){
2600 qWarning("QQuickTextInputPrivate::setSelection: Invalid start position");
2605 if (start == m_selstart && start + length == m_selend && m_cursor == m_selend)
2608 m_selend = qMin(start + length, (int)m_text.length());
2609 m_cursor = m_selend;
2610 } else if (length < 0){
2611 if (start == m_selend && start + length == m_selstart && m_cursor == m_selstart)
2613 m_selstart = qMax(start + length, 0);
2615 m_cursor = m_selstart;
2616 } else if (m_selstart != m_selend) {
2622 emitCursorPositionChanged();
2625 emit q->selectionChanged();
2626 emitCursorPositionChanged();
2632 Initializes the line control with a starting text value of \a txt.
2634 void QQuickTextInputPrivate::init(const QString &txt)
2638 updateDisplayText();
2639 m_cursor = m_text.length();
2645 Sets the password echo editing to \a editing. If password echo editing
2646 is true, then the text of the password is displayed even if the echo
2647 mode is set to QLineEdit::PasswordEchoOnEdit. Password echoing editing
2648 does not affect other echo modes.
2650 void QQuickTextInputPrivate::updatePasswordEchoEditing(bool editing)
2652 cancelPasswordEchoTimer();
2653 m_passwordEchoEditing = editing;
2654 updateDisplayText();
2660 Fixes the current text so that it is valid given any set validators.
2662 Returns true if the text was changed. Otherwise returns false.
2664 bool QQuickTextInputPrivate::fixup() // this function assumes that validate currently returns != Acceptable
2666 #ifndef QT_NO_VALIDATOR
2668 QString textCopy = m_text;
2669 int cursorCopy = m_cursor;
2670 m_validator->fixup(textCopy);
2671 if (m_validator->validate(textCopy, cursorCopy) == QValidator::Acceptable) {
2672 if (textCopy != m_text || cursorCopy != m_cursor)
2673 internalSetText(textCopy, cursorCopy);
2684 Moves the cursor to the given position \a pos. If \a mark is true will
2685 adjust the currently selected text.
2687 void QQuickTextInputPrivate::moveCursor(int pos, bool mark)
2689 Q_Q(QQuickTextInput);
2692 if (pos != m_cursor) {
2695 pos = pos > m_cursor ? nextMaskBlank(pos) : prevMaskBlank(pos);
2699 if (m_selend > m_selstart && m_cursor == m_selstart)
2701 else if (m_selend > m_selstart && m_cursor == m_selend)
2702 anchor = m_selstart;
2705 m_selstart = qMin(anchor, pos);
2706 m_selend = qMax(anchor, pos);
2711 if (mark || m_selDirty) {
2713 emit q->selectionChanged();
2715 emitCursorPositionChanged();
2721 Applies the given input method event \a event to the text of the line
2724 void QQuickTextInputPrivate::processInputMethodEvent(QInputMethodEvent *event)
2726 Q_Q(QQuickTextInput);
2728 int priorState = -1;
2729 bool isGettingInput = !event->commitString().isEmpty()
2730 || event->preeditString() != preeditAreaText()
2731 || event->replacementLength() > 0;
2732 bool cursorPositionChanged = false;
2733 bool selectionChange = false;
2734 m_preeditDirty = event->preeditString() != preeditAreaText();
2736 if (isGettingInput) {
2737 // If any text is being input, remove selected text.
2738 priorState = m_undoState;
2739 if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit && !m_passwordEchoEditing) {
2740 updatePasswordEchoEditing(true);
2742 m_selend = m_text.length();
2744 removeSelectedText();
2747 int c = m_cursor; // cursor position after insertion of commit string
2748 if (event->replacementStart() <= 0)
2749 c += event->commitString().length() - qMin(-event->replacementStart(), event->replacementLength());
2751 m_cursor += event->replacementStart();
2755 // insert commit string
2756 if (event->replacementLength()) {
2757 m_selstart = m_cursor;
2758 m_selend = m_selstart + event->replacementLength();
2759 m_selend = qMin(m_selend, m_text.length());
2760 removeSelectedText();
2762 if (!event->commitString().isEmpty()) {
2763 internalInsert(event->commitString());
2764 cursorPositionChanged = true;
2767 m_cursor = qBound(0, c, m_text.length());
2769 for (int i = 0; i < event->attributes().size(); ++i) {
2770 const QInputMethodEvent::Attribute &a = event->attributes().at(i);
2771 if (a.type == QInputMethodEvent::Selection) {
2772 m_cursor = qBound(0, a.start + a.length, m_text.length());
2774 m_selstart = qMax(0, qMin(a.start, m_text.length()));
2775 m_selend = m_cursor;
2776 if (m_selend < m_selstart) {
2777 qSwap(m_selstart, m_selend);
2779 selectionChange = true;
2781 m_selstart = m_selend = 0;
2783 cursorPositionChanged = true;
2787 m_textLayout.setPreeditArea(m_cursor, event->preeditString());
2789 const int oldPreeditCursor = m_preeditCursor;
2790 m_preeditCursor = event->preeditString().length();
2791 m_hideCursor = false;
2792 QList<QTextLayout::FormatRange> formats;
2793 for (int i = 0; i < event->attributes().size(); ++i) {
2794 const QInputMethodEvent::Attribute &a = event->attributes().at(i);
2795 if (a.type == QInputMethodEvent::Cursor) {
2796 m_preeditCursor = a.start;
2797 m_hideCursor = !a.length;
2798 } else if (a.type == QInputMethodEvent::TextFormat) {
2799 QTextCharFormat f = qvariant_cast<QTextFormat>(a.value).toCharFormat();
2801 QTextLayout::FormatRange o;
2802 o.start = a.start + m_cursor;
2803 o.length = a.length;
2809 m_textLayout.setAdditionalFormats(formats);
2811 updateDisplayText(/*force*/ true);
2812 if (cursorPositionChanged)
2813 emitCursorPositionChanged();
2814 else if (m_preeditCursor != oldPreeditCursor)
2815 q->updateCursorRectangle();
2817 bool tentativeCommitChanged = m_tentativeCommit != event->tentativeCommitString();
2819 if (tentativeCommitChanged) {
2821 m_tentativeCommit = event->tentativeCommitString();
2824 if (isGettingInput || tentativeCommitChanged)
2825 finishChange(priorState);
2827 if (selectionChange)
2828 emit q->selectionChanged();
2834 Sets the selection to cover the word at the given cursor position.
2835 The word boundaries are defined by the behavior of QTextLayout::SkipWords
2838 void QQuickTextInputPrivate::selectWordAtPos(int cursor)
2840 int next = cursor + 1;
2843 int c = m_textLayout.previousCursorPosition(next, QTextLayout::SkipWords);
2844 moveCursor(c, false);
2845 // ## text layout should support end of words.
2846 int end = m_textLayout.nextCursorPosition(c, QTextLayout::SkipWords);
2847 while (end > cursor && m_text[end-1].isSpace())
2849 moveCursor(end, true);
2855 Completes a change to the line control text. If the change is not valid
2856 will undo the line control state back to the given \a validateFromState.
2858 If \a edited is true and the change is valid, will emit textEdited() in
2859 addition to textChanged(). Otherwise only emits textChanged() on a valid
2862 The \a update value is currently unused.
2864 bool QQuickTextInputPrivate::finishChange(int validateFromState, bool update, bool /*edited*/)
2866 Q_Q(QQuickTextInput);
2872 bool wasValidInput = m_validInput;
2873 m_validInput = true;
2874 #ifndef QT_NO_VALIDATOR
2876 QString textCopy = m_text;
2877 int cursorCopy = m_cursor;
2878 m_validInput = (m_validator->validate(textCopy, cursorCopy) != QValidator::Invalid);
2880 if (m_text != textCopy) {
2881 internalSetText(textCopy, cursorCopy);
2884 m_cursor = cursorCopy;
2886 if (!m_tentativeCommit.isEmpty()) {
2887 textCopy.insert(m_cursor, m_tentativeCommit);
2888 bool validInput = m_validator->validate(textCopy, cursorCopy) != QValidator::Invalid;
2890 m_tentativeCommit.clear();
2893 m_tentativeCommit.clear();
2897 if (validateFromState >= 0 && wasValidInput && !m_validInput) {
2898 if (m_transactions.count())
2900 internalUndo(validateFromState);
2901 m_history.resize(m_undoState);
2902 if (m_modifiedState > m_undoState)
2903 m_modifiedState = -1;
2904 m_validInput = true;
2905 m_textDirty = false;
2907 updateDisplayText();
2910 m_textDirty = false;
2911 m_preeditDirty = false;
2912 determineHorizontalAlignment();
2913 emit q->textChanged();
2916 if (m_validInput != wasValidInput)
2917 emit q->acceptableInputChanged();
2919 if (m_preeditDirty) {
2920 m_preeditDirty = false;
2921 determineHorizontalAlignment();
2926 emit q->selectionChanged();
2928 emitCursorPositionChanged();
2936 An internal function for setting the text of the line control.
2938 void QQuickTextInputPrivate::internalSetText(const QString &txt, int pos, bool edited)
2940 Q_Q(QQuickTextInput);
2942 QString oldText = m_text;
2944 m_text = maskString(0, txt, true);
2945 m_text += clearString(m_text.length(), m_maxLength - m_text.length());
2947 m_text = txt.isEmpty() ? txt : txt.left(m_maxLength);
2950 m_modifiedState = m_undoState = 0;
2951 m_cursor = (pos < 0 || pos > m_text.length()) ? m_text.length() : pos;
2952 m_textDirty = (oldText != m_text);
2954 bool changed = finishChange(-1, true, edited);
2955 #ifdef QT_NO_ACCESSIBILITY
2959 QAccessible::updateAccessibility(q, 0, QAccessible::TextUpdated);
2967 Adds the given \a command to the undo history
2968 of the line control. Does not apply the command.
2970 void QQuickTextInputPrivate::addCommand(const Command &cmd)
2972 if (m_separator && m_undoState && m_history[m_undoState - 1].type != Separator) {
2973 m_history.resize(m_undoState + 2);
2974 m_history[m_undoState++] = Command(Separator, m_cursor, 0, m_selstart, m_selend);
2976 m_history.resize(m_undoState + 1);
2978 m_separator = false;
2979 m_history[m_undoState++] = cmd;
2985 Inserts the given string \a s into the line
2988 Also adds the appropriate commands into the undo history.
2989 This function does not call finishChange(), and may leave the text
2990 in an invalid state.
2992 void QQuickTextInputPrivate::internalInsert(const QString &s)
2994 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
2995 Q_Q(QQuickTextInput);
2996 if (m_echoMode == QQuickTextInput::Password)
2997 m_passwordEchoTimer.start(qt_passwordEchoDelay, q);
2999 if (hasSelectedText())
3000 addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
3002 QString ms = maskString(m_cursor, s);
3003 for (int i = 0; i < (int) ms.length(); ++i) {
3004 addCommand (Command(DeleteSelection, m_cursor + i, m_text.at(m_cursor + i), -1, -1));
3005 addCommand(Command(Insert, m_cursor + i, ms.at(i), -1, -1));
3007 m_text.replace(m_cursor, ms.length(), ms);
3008 m_cursor += ms.length();
3009 m_cursor = nextMaskBlank(m_cursor);
3012 int remaining = m_maxLength - m_text.length();
3013 if (remaining != 0) {
3014 m_text.insert(m_cursor, s.left(remaining));
3015 for (int i = 0; i < (int) s.left(remaining).length(); ++i)
3016 addCommand(Command(Insert, m_cursor++, s.at(i), -1, -1));
3025 deletes a single character from the current text. If \a wasBackspace,
3026 the character prior to the cursor is removed. Otherwise the character
3027 after the cursor is removed.
3029 Also adds the appropriate commands into the undo history.
3030 This function does not call finishChange(), and may leave the text
3031 in an invalid state.
3033 void QQuickTextInputPrivate::internalDelete(bool wasBackspace)
3035 if (m_cursor < (int) m_text.length()) {
3036 cancelPasswordEchoTimer();
3037 if (hasSelectedText())
3038 addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
3039 addCommand(Command((CommandType)((m_maskData ? 2 : 0) + (wasBackspace ? Remove : Delete)),
3040 m_cursor, m_text.at(m_cursor), -1, -1));
3042 m_text.replace(m_cursor, 1, clearString(m_cursor, 1));
3043 addCommand(Command(Insert, m_cursor, m_text.at(m_cursor), -1, -1));
3045 m_text.remove(m_cursor, 1);
3054 removes the currently selected text from the line control.
3056 Also adds the appropriate commands into the undo history.
3057 This function does not call finishChange(), and may leave the text
3058 in an invalid state.
3060 void QQuickTextInputPrivate::removeSelectedText()
3062 if (m_selstart < m_selend && m_selend <= (int) m_text.length()) {
3063 cancelPasswordEchoTimer();
3066 addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
3067 if (m_selstart <= m_cursor && m_cursor < m_selend) {
3068 // cursor is within the selection. Split up the commands
3069 // to be able to restore the correct cursor position
3070 for (i = m_cursor; i >= m_selstart; --i)
3071 addCommand (Command(DeleteSelection, i, m_text.at(i), -1, 1));
3072 for (i = m_selend - 1; i > m_cursor; --i)
3073 addCommand (Command(DeleteSelection, i - m_cursor + m_selstart - 1, m_text.at(i), -1, -1));
3075 for (i = m_selend-1; i >= m_selstart; --i)
3076 addCommand (Command(RemoveSelection, i, m_text.at(i), -1, -1));
3079 m_text.replace(m_selstart, m_selend - m_selstart, clearString(m_selstart, m_selend - m_selstart));
3080 for (int i = 0; i < m_selend - m_selstart; ++i)
3081 addCommand(Command(Insert, m_selstart + i, m_text.at(m_selstart + i), -1, -1));
3083 m_text.remove(m_selstart, m_selend - m_selstart);
3085 if (m_cursor > m_selstart)
3086 m_cursor -= qMin(m_cursor, m_selend) - m_selstart;
3095 Parses the input mask specified by \a maskFields to generate
3096 the mask data used to handle input masks.
3098 void QQuickTextInputPrivate::parseInputMask(const QString &maskFields)
3100 int delimiter = maskFields.indexOf(QLatin1Char(';'));
3101 if (maskFields.isEmpty() || delimiter == 0) {
3103 delete [] m_maskData;
3105 m_maxLength = 32767;
3106 internalSetText(QString());
3111 if (delimiter == -1) {
3112 m_blank = QLatin1Char(' ');
3113 m_inputMask = maskFields;
3115 m_inputMask = maskFields.left(delimiter);
3116 m_blank = (delimiter + 1 < maskFields.length()) ? maskFields[delimiter + 1] : QLatin1Char(' ');
3119 // calculate m_maxLength / m_maskData length
3122 for (int i=0; i<m_inputMask.length(); i++) {
3123 c = m_inputMask.at(i);
3124 if (i > 0 && m_inputMask.at(i-1) == QLatin1Char('\\')) {
3128 if (c != QLatin1Char('\\') && c != QLatin1Char('!') &&
3129 c != QLatin1Char('<') && c != QLatin1Char('>') &&
3130 c != QLatin1Char('{') && c != QLatin1Char('}') &&
3131 c != QLatin1Char('[') && c != QLatin1Char(']'))
3135 delete [] m_maskData;
3136 m_maskData = new MaskInputData[m_maxLength];
3138 MaskInputData::Casemode m = MaskInputData::NoCaseMode;
3141 bool escape = false;
3143 for (int i = 0; i < m_inputMask.length(); i++) {
3144 c = m_inputMask.at(i);
3147 m_maskData[index].maskChar = c;
3148 m_maskData[index].separator = s;
3149 m_maskData[index].caseMode = m;
3152 } else if (c == QLatin1Char('<')) {
3153 m = MaskInputData::Lower;
3154 } else if (c == QLatin1Char('>')) {
3155 m = MaskInputData::Upper;
3156 } else if (c == QLatin1Char('!')) {
3157 m = MaskInputData::NoCaseMode;
3158 } else if (c != QLatin1Char('{') && c != QLatin1Char('}') && c != QLatin1Char('[') && c != QLatin1Char(']')) {
3159 switch (c.unicode()) {
3185 m_maskData[index].maskChar = c;
3186 m_maskData[index].separator = s;
3187 m_maskData[index].caseMode = m;
3192 internalSetText(m_text);
3199 checks if the key is valid compared to the inputMask
3201 bool QQuickTextInputPrivate::isValidInput(QChar key, QChar mask) const
3203 switch (mask.unicode()) {
3209 if (key.isLetter() || key == m_blank)
3213 if (key.isLetterOrNumber())
3217 if (key.isLetterOrNumber() || key == m_blank)
3225 if (key.isPrint() || key == m_blank)
3233 if (key.isNumber() || key == m_blank)
3237 if (key.isNumber() && key.digitValue() > 0)
3241 if ((key.isNumber() && key.digitValue() > 0) || key == m_blank)
3245 if (key.isNumber() || key == QLatin1Char('+') || key == QLatin1Char('-') || key == m_blank)
3249 if (key == QLatin1Char('0') || key == QLatin1Char('1'))
3253 if (key == QLatin1Char('0') || key == QLatin1Char('1') || key == m_blank)
3257 if (key.isNumber() || (key >= QLatin1Char('a') && key <= QLatin1Char('f')) || (key >= QLatin1Char('A') && key <= QLatin1Char('F')))
3261 if (key.isNumber() || (key >= QLatin1Char('a') && key <= QLatin1Char('f')) || (key >= QLatin1Char('A') && key <= QLatin1Char('F')) || key == m_blank)
3273 Returns true if the given text \a str is valid for any
3274 validator or input mask set for the line control.
3276 Otherwise returns false
3278 bool QQuickTextInputPrivate::hasAcceptableInput(const QString &str) const
3280 #ifndef QT_NO_VALIDATOR
3281 QString textCopy = str;
3282 int cursorCopy = m_cursor;
3283 if (m_validator && m_validator->validate(textCopy, cursorCopy)
3284 != QValidator::Acceptable)
3291 if (str.length() != m_maxLength)
3294 for (int i=0; i < m_maxLength; ++i) {
3295 if (m_maskData[i].separator) {
3296 if (str.at(i) != m_maskData[i].maskChar)
3299 if (!isValidInput(str.at(i), m_maskData[i].maskChar))
3309 Applies the inputMask on \a str starting from position \a pos in the mask. \a clear
3310 specifies from where characters should be gotten when a separator is met in \a str - true means
3311 that blanks will be used, false that previous input is used.
3312 Calling this when no inputMask is set is undefined.
3314 QString QQuickTextInputPrivate::maskString(uint pos, const QString &str, bool clear) const
3316 if (pos >= (uint)m_maxLength)
3317 return QString::fromLatin1("");
3320 fill = clear ? clearString(0, m_maxLength) : m_text;
3323 QString s = QString::fromLatin1("");
3325 while (i < m_maxLength) {
3326 if (strIndex < str.length()) {
3327 if (m_maskData[i].separator) {
3328 s += m_maskData[i].maskChar;
3329 if (str[(int)strIndex] == m_maskData[i].maskChar)
3333 if (isValidInput(str[(int)strIndex], m_maskData[i].maskChar)) {
3334 switch (m_maskData[i].caseMode) {
3335 case MaskInputData::Upper:
3336 s += str[(int)strIndex].toUpper();
3338 case MaskInputData::Lower:
3339 s += str[(int)strIndex].toLower();
3342 s += str[(int)strIndex];
3346 // search for separator first
3347 int n = findInMask(i, true, true, str[(int)strIndex]);
3349 if (str.length() != 1 || i == 0 || (i > 0 && (!m_maskData[i-1].separator || m_maskData[i-1].maskChar != str[(int)strIndex]))) {
3350 s += fill.mid(i, n-i+1);
3351 i = n + 1; // update i to find + 1
3354 // search for valid m_blank if not
3355 n = findInMask(i, true, false, str[(int)strIndex]);
3357 s += fill.mid(i, n-i);
3358 switch (m_maskData[n].caseMode) {
3359 case MaskInputData::Upper:
3360 s += str[(int)strIndex].toUpper();
3362 case MaskInputData::Lower:
3363 s += str[(int)strIndex].toLower();
3366 s += str[(int)strIndex];
3368 i = n + 1; // updates i to find + 1
3386 Returns a "cleared" string with only separators and blank chars.
3387 Calling this when no inputMask is set is undefined.
3389 QString QQuickTextInputPrivate::clearString(uint pos, uint len) const
3391 if (pos >= (uint)m_maxLength)
3395 int end = qMin((uint)m_maxLength, pos + len);
3396 for (int i = pos; i < end; ++i)
3397 if (m_maskData[i].separator)
3398 s += m_maskData[i].maskChar;
3408 Strips blank parts of the input in a QQuickTextInputPrivate when an inputMask is set,
3409 separators are still included. Typically "127.0__.0__.1__" becomes "127.0.0.1".
3411 QString QQuickTextInputPrivate::stripString(const QString &str) const
3417 int end = qMin(m_maxLength, (int)str.length());
3418 for (int i = 0; i < end; ++i) {
3419 if (m_maskData[i].separator)
3420 s += m_maskData[i].maskChar;
3421 else if (str[i] != m_blank)
3430 searches forward/backward in m_maskData for either a separator or a m_blank
3432 int QQuickTextInputPrivate::findInMask(int pos, bool forward, bool findSeparator, QChar searchChar) const
3434 if (pos >= m_maxLength || pos < 0)
3437 int end = forward ? m_maxLength : -1;
3438 int step = forward ? 1 : -1;
3442 if (findSeparator) {
3443 if (m_maskData[i].separator && m_maskData[i].maskChar == searchChar)
3446 if (!m_maskData[i].separator) {
3447 if (searchChar.isNull())
3449 else if (isValidInput(searchChar, m_maskData[i].maskChar))
3458 void QQuickTextInputPrivate::internalUndo(int until)
3460 if (!isUndoAvailable())
3462 cancelPasswordEchoTimer();
3464 while (m_undoState && m_undoState > until) {
3465 Command& cmd = m_history[--m_undoState];
3468 m_text.remove(cmd.pos, 1);
3472 m_selstart = cmd.selStart;
3473 m_selend = cmd.selEnd;
3477 case RemoveSelection:
3478 m_text.insert(cmd.pos, cmd.uc);
3479 m_cursor = cmd.pos + 1;
3482 case DeleteSelection:
3483 m_text.insert(cmd.pos, cmd.uc);
3489 if (until < 0 && m_undoState) {
3490 Command& next = m_history[m_undoState-1];
3491 if (next.type != cmd.type && next.type < RemoveSelection
3492 && (cmd.type < RemoveSelection || next.type == Separator))
3497 emitCursorPositionChanged();
3500 void QQuickTextInputPrivate::internalRedo()
3502 if (!isRedoAvailable())
3505 while (m_undoState < (int)m_history.size()) {
3506 Command& cmd = m_history[m_undoState++];
3509 m_text.insert(cmd.pos, cmd.uc);
3510 m_cursor = cmd.pos + 1;
3513 m_selstart = cmd.selStart;
3514 m_selend = cmd.selEnd;
3519 case RemoveSelection:
3520 case DeleteSelection:
3521 m_text.remove(cmd.pos, 1);
3522 m_selstart = cmd.selStart;
3523 m_selend = cmd.selEnd;
3527 m_selstart = cmd.selStart;
3528 m_selend = cmd.selEnd;
3532 if (m_undoState < (int)m_history.size()) {
3533 Command& next = m_history[m_undoState];
3534 if (next.type != cmd.type && cmd.type < RemoveSelection && next.type != Separator
3535 && (next.type < RemoveSelection || cmd.type == Separator))
3540 emitCursorPositionChanged();
3546 If the current cursor position differs from the last emitted cursor
3547 position, emits cursorPositionChanged().
3549 void QQuickTextInputPrivate::emitCursorPositionChanged()
3551 Q_Q(QQuickTextInput);
3552 if (m_cursor != m_lastCursorPos) {
3553 m_lastCursorPos = m_cursor;
3555 q->updateCursorRectangle();
3556 emit q->cursorPositionChanged();
3557 // XXX todo - not in 4.8?
3559 resetCursorBlinkTimer();
3562 if (!hasSelectedText()) {
3563 if (lastSelectionStart != m_cursor) {
3564 lastSelectionStart = m_cursor;
3565 emit q->selectionStartChanged();
3567 if (lastSelectionEnd != m_cursor) {
3568 lastSelectionEnd = m_cursor;
3569 emit q->selectionEndChanged();
3573 #ifndef QT_NO_ACCESSIBILITY
3574 QAccessible::updateAccessibility(q, 0, QAccessible::TextCaretMoved);
3580 void QQuickTextInputPrivate::setCursorBlinkPeriod(int msec)
3582 Q_Q(QQuickTextInput);
3583 if (msec == m_blinkPeriod)
3586 q->killTimer(m_blinkTimer);
3589 m_blinkTimer = q->startTimer(msec / 2);
3593 if (m_blinkStatus == 1)
3596 m_blinkPeriod = msec;
3599 void QQuickTextInputPrivate::resetCursorBlinkTimer()
3601 Q_Q(QQuickTextInput);
3602 if (m_blinkPeriod == 0 || m_blinkTimer == 0)
3604 q->killTimer(m_blinkTimer);
3605 m_blinkTimer = q->startTimer(m_blinkPeriod / 2);
3609 void QQuickTextInput::timerEvent(QTimerEvent *event)
3611 Q_D(QQuickTextInput);
3612 if (event->timerId() == d->m_blinkTimer) {
3613 d->m_blinkStatus = !d->m_blinkStatus;
3615 } else if (event->timerId() == d->m_deleteAllTimer) {
3616 killTimer(d->m_deleteAllTimer);
3617 d->m_deleteAllTimer = 0;
3619 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
3620 } else if (event->timerId() == d->m_passwordEchoTimer.timerId()) {
3621 d->m_passwordEchoTimer.stop();
3622 d->updateDisplayText();
3627 void QQuickTextInputPrivate::processKeyEvent(QKeyEvent* event)
3629 Q_Q(QQuickTextInput);
3630 bool inlineCompletionAccepted = false;
3632 if (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return) {
3633 if (hasAcceptableInput(m_text) || fixup()) {
3636 if (inlineCompletionAccepted)
3643 if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit
3644 && !m_passwordEchoEditing
3646 && !event->text().isEmpty()
3647 && !(event->modifiers() & Qt::ControlModifier)) {
3648 // Clear the edit and reset to normal echo mode while editing; the
3649 // echo mode switches back when the edit loses focus
3650 // ### resets current content. dubious code; you can
3651 // navigate with keys up, down, back, and select(?), but if you press
3652 // "left" or "right" it clears?
3653 updatePasswordEchoEditing(true);
3657 bool unknown = false;
3658 bool visual = cursorMoveStyle() == Qt::VisualMoveStyle;
3662 #ifndef QT_NO_SHORTCUT
3663 else if (event == QKeySequence::Undo) {
3667 else if (event == QKeySequence::Redo) {
3671 else if (event == QKeySequence::SelectAll) {
3674 #ifndef QT_NO_CLIPBOARD
3675 else if (event == QKeySequence::Copy) {
3678 else if (event == QKeySequence::Paste) {
3680 QClipboard::Mode mode = QClipboard::Clipboard;
3684 else if (event == QKeySequence::Cut) {
3690 else if (event == QKeySequence::DeleteEndOfLine) {
3692 setSelection(m_cursor, end());
3697 #endif //QT_NO_CLIPBOARD
3698 else if (event == QKeySequence::MoveToStartOfLine || event == QKeySequence::MoveToStartOfBlock) {
3701 else if (event == QKeySequence::MoveToEndOfLine || event == QKeySequence::MoveToEndOfBlock) {
3704 else if (event == QKeySequence::SelectStartOfLine || event == QKeySequence::SelectStartOfBlock) {
3707 else if (event == QKeySequence::SelectEndOfLine || event == QKeySequence::SelectEndOfBlock) {
3710 else if (event == QKeySequence::MoveToNextChar) {
3711 if (hasSelectedText()) {
3712 moveCursor(selectionEnd(), false);
3714 cursorForward(0, visual ? 1 : (layoutDirection() == Qt::LeftToRight ? 1 : -1));
3717 else if (event == QKeySequence::SelectNextChar) {
3718 cursorForward(1, visual ? 1 : (layoutDirection() == Qt::LeftToRight ? 1 : -1));
3720 else if (event == QKeySequence::MoveToPreviousChar) {
3721 if (hasSelectedText()) {
3722 moveCursor(selectionStart(), false);
3724 cursorForward(0, visual ? -1 : (layoutDirection() == Qt::LeftToRight ? -1 : 1));
3727 else if (event == QKeySequence::SelectPreviousChar) {
3728 cursorForward(1, visual ? -1 : (layoutDirection() == Qt::LeftToRight ? -1 : 1));
3730 else if (event == QKeySequence::MoveToNextWord) {
3731 if (m_echoMode == QQuickTextInput::Normal)
3732 layoutDirection() == Qt::LeftToRight ? cursorWordForward(0) : cursorWordBackward(0);
3734 layoutDirection() == Qt::LeftToRight ? end(0) : home(0);
3736 else if (event == QKeySequence::MoveToPreviousWord) {
3737 if (m_echoMode == QQuickTextInput::Normal)
3738 layoutDirection() == Qt::LeftToRight ? cursorWordBackward(0) : cursorWordForward(0);
3739 else if (!m_readOnly) {
3740 layoutDirection() == Qt::LeftToRight ? home(0) : end(0);
3743 else if (event == QKeySequence::SelectNextWord) {
3744 if (m_echoMode == QQuickTextInput::Normal)
3745 layoutDirection() == Qt::LeftToRight ? cursorWordForward(1) : cursorWordBackward(1);
3747 layoutDirection() == Qt::LeftToRight ? end(1) : home(1);
3749 else if (event == QKeySequence::SelectPreviousWord) {
3750 if (m_echoMode == QQuickTextInput::Normal)
3751 layoutDirection() == Qt::LeftToRight ? cursorWordBackward(1) : cursorWordForward(1);
3753 layoutDirection() == Qt::LeftToRight ? home(1) : end(1);
3755 else if (event == QKeySequence::Delete) {
3759 else if (event == QKeySequence::DeleteEndOfWord) {
3761 cursorWordForward(true);
3765 else if (event == QKeySequence::DeleteStartOfWord) {
3767 cursorWordBackward(true);
3771 #endif // QT_NO_SHORTCUT
3773 bool handled = false;
3774 if (event->modifiers() & Qt::ControlModifier) {
3775 switch (event->key()) {
3776 case Qt::Key_Backspace:
3778 cursorWordBackward(true);
3786 } else { // ### check for *no* modifier
3787 switch (event->key()) {
3788 case Qt::Key_Backspace:
3800 if (event->key() == Qt::Key_Direction_L || event->key() == Qt::Key_Direction_R) {
3801 setLayoutDirection((event->key() == Qt::Key_Direction_L) ? Qt::LeftToRight : Qt::RightToLeft);
3805 if (unknown && !m_readOnly) {
3806 QString t = event->text();
3807 if (!t.isEmpty() && t.at(0).isPrint()) {