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 \qmlproperty rectangle QtQuick2::TextInput::cursorRectangle
666 The rectangle where the standard text cursor is rendered within the text input. Read only.
668 The position and height of a custom cursorDelegate are updated to follow the cursorRectangle
669 automatically when it changes. The width of the delegate is unaffected by changes in the
673 QRect QQuickTextInput::cursorRectangle() const
675 Q_D(const QQuickTextInput);
678 if (d->m_preeditCursor != -1)
679 c += d->m_preeditCursor;
680 if (d->m_echoMode == NoEcho)
682 QTextLine l = d->m_textLayout.lineForTextPosition(c);
686 qRound(l.cursorToX(c) - d->hscroll),
687 qRound(l.y() - d->vscroll),
693 \qmlproperty int QtQuick2::TextInput::selectionStart
695 The cursor position before the first character in the current selection.
697 This property is read-only. To change the selection, use select(start,end),
698 selectAll(), or selectWord().
700 \sa selectionEnd, cursorPosition, selectedText
702 int QQuickTextInput::selectionStart() const
704 Q_D(const QQuickTextInput);
705 return d->lastSelectionStart;
708 \qmlproperty int QtQuick2::TextInput::selectionEnd
710 The cursor position after the last character in the current selection.
712 This property is read-only. To change the selection, use select(start,end),
713 selectAll(), or selectWord().
715 \sa selectionStart, cursorPosition, selectedText
717 int QQuickTextInput::selectionEnd() const
719 Q_D(const QQuickTextInput);
720 return d->lastSelectionEnd;
723 \qmlmethod void QtQuick2::TextInput::select(int start, int end)
725 Causes the text from \a start to \a end to be selected.
727 If either start or end is out of range, the selection is not changed.
729 After calling this, selectionStart will become the lesser
730 and selectionEnd will become the greater (regardless of the order passed
733 \sa selectionStart, selectionEnd
735 void QQuickTextInput::select(int start, int end)
737 Q_D(QQuickTextInput);
738 if (start < 0 || end < 0 || start > d->m_text.length() || end > d->m_text.length())
740 d->setSelection(start, end-start);
744 \qmlproperty string QtQuick2::TextInput::selectedText
746 This read-only property provides the text currently selected in the
749 It is equivalent to the following snippet, but is faster and easier
753 myTextInput.text.toString().substring(myTextInput.selectionStart,
754 myTextInput.selectionEnd);
757 QString QQuickTextInput::selectedText() const
759 Q_D(const QQuickTextInput);
760 return d->selectedText();
764 \qmlproperty bool QtQuick2::TextInput::activeFocusOnPress
766 Whether the TextInput should gain active focus on a mouse press. By default this is
769 bool QQuickTextInput::focusOnPress() const
771 Q_D(const QQuickTextInput);
772 return d->focusOnPress;
775 void QQuickTextInput::setFocusOnPress(bool b)
777 Q_D(QQuickTextInput);
778 if (d->focusOnPress == b)
783 emit activeFocusOnPressChanged(d->focusOnPress);
786 \qmlproperty bool QtQuick2::TextInput::autoScroll
788 Whether the TextInput should scroll when the text is longer than the width. By default this is
791 bool QQuickTextInput::autoScroll() const
793 Q_D(const QQuickTextInput);
794 return d->autoScroll;
797 void QQuickTextInput::setAutoScroll(bool b)
799 Q_D(QQuickTextInput);
800 if (d->autoScroll == b)
804 //We need to repaint so that the scrolling is taking into account.
805 updateCursorRectangle();
806 emit autoScrollChanged(d->autoScroll);
809 #ifndef QT_NO_VALIDATOR
812 \qmlclass IntValidator QIntValidator
813 \inqmlmodule QtQuick 2
814 \ingroup qml-basic-visual-elements
816 This element provides a validator for integer values.
818 IntValidator uses the \l {QLocale::setDefault()}{default locale} to interpret the number and
819 will accept locale specific digits, group separators, and positive and negative signs. In
820 addition, IntValidator is always guaranteed to accept a number formatted according to the "C"
824 \qmlproperty int QtQuick2::IntValidator::top
826 This property holds the validator's highest acceptable value.
827 By default, this property's value is derived from the highest signed integer available (typically 2147483647).
830 \qmlproperty int QtQuick2::IntValidator::bottom
832 This property holds the validator's lowest acceptable value.
833 By default, this property's value is derived from the lowest signed integer available (typically -2147483647).
837 \qmlclass DoubleValidator QDoubleValidator
838 \inqmlmodule QtQuick 2
839 \ingroup qml-basic-visual-elements
841 This element provides a validator for non-integer numbers.
845 \qmlproperty real QtQuick2::DoubleValidator::top
847 This property holds the validator's maximum acceptable value.
848 By default, this property contains a value of infinity.
851 \qmlproperty real QtQuick2::DoubleValidator::bottom
853 This property holds the validator's minimum acceptable value.
854 By default, this property contains a value of -infinity.
857 \qmlproperty int QtQuick2::DoubleValidator::decimals
859 This property holds the validator's maximum number of digits after the decimal point.
860 By default, this property contains a value of 1000.
863 \qmlproperty enumeration QtQuick2::DoubleValidator::notation
864 This property holds the notation of how a string can describe a number.
866 The possible values for this property are:
869 \o DoubleValidator.StandardNotation
870 \o DoubleValidator.ScientificNotation (default)
873 If this property is set to DoubleValidator.ScientificNotation, the written number may have an exponent part (e.g. 1.5E-2).
877 \qmlclass RegExpValidator QRegExpValidator
878 \inqmlmodule QtQuick 2
879 \ingroup qml-basic-visual-elements
881 This element provides a validator, which counts as valid any string which
882 matches a specified regular expression.
885 \qmlproperty regExp QtQuick2::RegExpValidator::regExp
887 This property holds the regular expression used for validation.
889 Note that this property should be a regular expression in JS syntax, e.g /a/ for the regular expression
892 By default, this property contains a regular expression with the pattern .* that matches any string.
896 \qmlproperty Validator QtQuick2::TextInput::validator
898 Allows you to set a validator on the TextInput. When a validator is set
899 the TextInput will only accept input which leaves the text property in
900 an acceptable or intermediate state. The accepted signal will only be sent
901 if the text is in an acceptable state when enter is pressed.
903 Currently supported validators are IntValidator, DoubleValidator and
904 RegExpValidator. An example of using validators is shown below, which allows
905 input of integers between 11 and 31 into the text input:
910 validator: IntValidator{bottom: 11; top: 31;}
915 \sa acceptableInput, inputMask
918 QValidator* QQuickTextInput::validator() const
920 Q_D(const QQuickTextInput);
921 return d->m_validator;
924 void QQuickTextInput::setValidator(QValidator* v)
926 Q_D(QQuickTextInput);
927 if (d->m_validator == v)
931 if (!d->hasAcceptableInput(d->m_text)) {
932 d->oldValidity = false;
933 emit acceptableInputChanged();
936 emit validatorChanged();
938 #endif // QT_NO_VALIDATOR
941 \qmlproperty string QtQuick2::TextInput::inputMask
943 Allows you to set an input mask on the TextInput, restricting the allowable
944 text inputs. See QLineEdit::inputMask for further details, as the exact
945 same mask strings are used by TextInput.
947 \sa acceptableInput, validator
949 QString QQuickTextInput::inputMask() const
951 Q_D(const QQuickTextInput);
952 return d->inputMask();
955 void QQuickTextInput::setInputMask(const QString &im)
957 Q_D(QQuickTextInput);
958 if (d->inputMask() == im)
962 emit inputMaskChanged(d->inputMask());
966 \qmlproperty bool QtQuick2::TextInput::acceptableInput
968 This property is always true unless a validator or input mask has been set.
969 If a validator or input mask has been set, this property will only be true
970 if the current text is acceptable to the validator or input mask as a final
971 string (not as an intermediate string).
973 bool QQuickTextInput::hasAcceptableInput() const
975 Q_D(const QQuickTextInput);
976 return d->hasAcceptableInput(d->m_text);
980 \qmlsignal QtQuick2::TextInput::onAccepted()
982 This handler is called when the Return or Enter key is pressed.
983 Note that if there is a \l validator or \l inputMask set on the text
984 input, the handler will only be emitted if the input is in an acceptable
988 void QQuickTextInputPrivate::updateInputMethodHints()
990 Q_Q(QQuickTextInput);
991 Qt::InputMethodHints hints = inputMethodHints;
992 if (m_echoMode == QQuickTextInput::Password || m_echoMode == QQuickTextInput::NoEcho)
993 hints |= Qt::ImhHiddenText;
994 else if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit)
995 hints &= ~Qt::ImhHiddenText;
996 if (m_echoMode != QQuickTextInput::Normal)
997 hints |= (Qt::ImhNoAutoUppercase | Qt::ImhNoPredictiveText | Qt::ImhSensitiveData);
998 q->setInputMethodHints(hints);
1001 \qmlproperty enumeration QtQuick2::TextInput::echoMode
1003 Specifies how the text should be displayed in the TextInput.
1005 \o TextInput.Normal - Displays the text as it is. (Default)
1006 \o TextInput.Password - Displays asterisks instead of characters.
1007 \o TextInput.NoEcho - Displays nothing.
1008 \o TextInput.PasswordEchoOnEdit - Displays characters as they are entered
1009 while editing, otherwise displays asterisks.
1012 QQuickTextInput::EchoMode QQuickTextInput::echoMode() const
1014 Q_D(const QQuickTextInput);
1015 return QQuickTextInput::EchoMode(d->m_echoMode);
1018 void QQuickTextInput::setEchoMode(QQuickTextInput::EchoMode echo)
1020 Q_D(QQuickTextInput);
1021 if (echoMode() == echo)
1023 d->cancelPasswordEchoTimer();
1024 d->m_echoMode = echo;
1025 d->m_passwordEchoEditing = false;
1026 d->updateInputMethodHints();
1027 d->updateDisplayText();
1028 updateCursorRectangle();
1030 emit echoModeChanged(echoMode());
1034 \qmlproperty enumeration QtQuick2::TextInput::inputMethodHints
1036 Provides hints to the input method about the expected content of the text input and how it
1039 The value is a bit-wise combination of flags, or Qt.ImhNone if no hints are set.
1041 Flags that alter behaviour are:
1044 \o Qt.ImhHiddenText - Characters should be hidden, as is typically used when entering passwords.
1045 This is automatically set when setting echoMode to \c TextInput.Password.
1046 \o Qt.ImhSensitiveData - Typed text should not be stored by the active input method
1047 in any persistent storage like predictive user dictionary.
1048 \o Qt.ImhNoAutoUppercase - The input method should not try to automatically switch to upper case
1049 when a sentence ends.
1050 \o Qt.ImhPreferNumbers - Numbers are preferred (but not required).
1051 \o Qt.ImhPreferUppercase - Upper case letters are preferred (but not required).
1052 \o Qt.ImhPreferLowercase - Lower case letters are preferred (but not required).
1053 \o Qt.ImhNoPredictiveText - Do not use predictive text (i.e. dictionary lookup) while typing.
1055 \o Qt.ImhDate - The text editor functions as a date field.
1056 \o Qt.ImhTime - The text editor functions as a time field.
1059 Flags that restrict input (exclusive flags) are:
1062 \o Qt.ImhDigitsOnly - Only digits are allowed.
1063 \o Qt.ImhFormattedNumbersOnly - Only number input is allowed. This includes decimal point and minus sign.
1064 \o Qt.ImhUppercaseOnly - Only upper case letter input is allowed.
1065 \o Qt.ImhLowercaseOnly - Only lower case letter input is allowed.
1066 \o Qt.ImhDialableCharactersOnly - Only characters suitable for phone dialing are allowed.
1067 \o Qt.ImhEmailCharactersOnly - Only characters suitable for email addresses are allowed.
1068 \o Qt.ImhUrlCharactersOnly - Only characters suitable for URLs are allowed.
1074 \o Qt.ImhExclusiveInputMask - This mask yields nonzero if any of the exclusive flags are used.
1078 Qt::InputMethodHints QQuickTextInput::imHints() const
1080 Q_D(const QQuickTextInput);
1081 return d->inputMethodHints;
1084 void QQuickTextInput::setIMHints(Qt::InputMethodHints hints)
1086 Q_D(QQuickTextInput);
1087 if (d->inputMethodHints == hints)
1089 d->inputMethodHints = hints;
1090 d->updateInputMethodHints();
1094 \qmlproperty Component QtQuick2::TextInput::cursorDelegate
1095 The delegate for the cursor in the TextInput.
1097 If you set a cursorDelegate for a TextInput, this delegate will be used for
1098 drawing the cursor instead of the standard cursor. An instance of the
1099 delegate will be created and managed by the TextInput when a cursor is
1100 needed, and the x property of delegate instance will be set so as
1101 to be one pixel before the top left of the current character.
1103 Note that the root item of the delegate component must be a QDeclarativeItem or
1104 QDeclarativeItem derived item.
1106 QDeclarativeComponent* QQuickTextInput::cursorDelegate() const
1108 Q_D(const QQuickTextInput);
1109 return d->cursorComponent;
1112 void QQuickTextInput::setCursorDelegate(QDeclarativeComponent* c)
1114 Q_D(QQuickTextInput);
1115 if (d->cursorComponent == c)
1118 d->cursorComponent = c;
1120 //note that the components are owned by something else
1121 delete d->cursorItem;
1123 d->startCreatingCursor();
1126 emit cursorDelegateChanged();
1129 void QQuickTextInputPrivate::startCreatingCursor()
1131 Q_Q(QQuickTextInput);
1132 if (cursorComponent->isReady()) {
1134 } else if (cursorComponent->isLoading()) {
1135 q->connect(cursorComponent, SIGNAL(statusChanged(int)),
1136 q, SLOT(createCursor()));
1138 qmlInfo(q, cursorComponent->errors()) << QQuickTextInput::tr("Could not load cursor delegate");
1142 void QQuickTextInput::createCursor()
1144 Q_D(QQuickTextInput);
1145 if (!isComponentComplete())
1148 if (d->cursorComponent->isError()) {
1149 qmlInfo(this, d->cursorComponent->errors()) << tr("Could not load cursor delegate");
1153 if (!d->cursorComponent->isReady())
1157 delete d->cursorItem;
1158 QDeclarativeContext *creationContext = d->cursorComponent->creationContext();
1159 QObject *object = d->cursorComponent->create(creationContext ? creationContext : qmlContext(this));
1160 d->cursorItem = qobject_cast<QQuickItem*>(object);
1161 if (!d->cursorItem) {
1163 qmlInfo(this, d->cursorComponent->errors()) << tr("Could not instantiate cursor delegate");
1167 QRectF r = cursorRectangle();
1169 QDeclarative_setParent_noEvent(d->cursorItem, this);
1170 d->cursorItem->setParentItem(this);
1171 d->cursorItem->setPos(r.topLeft());
1172 d->cursorItem->setHeight(r.height());
1176 \qmlmethod rect QtQuick2::TextInput::positionToRectangle(int pos)
1178 This function takes a character position and returns the rectangle that the
1179 cursor would occupy, if it was placed at that character position.
1181 This is similar to setting the cursorPosition, and then querying the cursor
1182 rectangle, but the cursorPosition is not changed.
1184 QRectF QQuickTextInput::positionToRectangle(int pos) const
1186 Q_D(const QQuickTextInput);
1187 if (pos > d->m_cursor)
1188 pos += d->preeditAreaText().length();
1189 QTextLine l = d->m_textLayout.lineAt(0);
1191 ? QRectF(l.cursorToX(pos) - d->hscroll, 0.0, d->m_cursorWidth, l.height())
1196 \qmlmethod int QtQuick2::TextInput::positionAt(real x, real y, CursorPosition position = CursorBetweenCharacters)
1198 This function returns the character position at
1199 x and y pixels from the top left of the textInput. Position 0 is before the
1200 first character, position 1 is after the first character but before the second,
1201 and so on until position text.length, which is after all characters.
1203 This means that for all x values before the first character this function returns 0,
1204 and for all x values after the last character this function returns text.length. If
1205 the y value is above the text the position will be that of the nearest character on
1206 the first line line and if it is below the text the position of the nearest character
1207 on the last line will be returned.
1209 The cursor position type specifies how the cursor position should be resolved.
1212 \o TextInput.CursorBetweenCharacters - Returns the position between characters that is nearest x.
1213 \o TextInput.CursorOnCharacter - Returns the position before the character that is nearest x.
1217 void QQuickTextInput::positionAt(QDeclarativeV8Function *args) const
1219 Q_D(const QQuickTextInput);
1223 QTextLine::CursorPosition position = QTextLine::CursorBetweenCharacters;
1225 if (args->Length() < 1)
1229 v8::Local<v8::Value> arg = (*args)[i];
1230 x = arg->NumberValue();
1232 if (++i < args->Length()) {
1234 y = arg->NumberValue();
1237 if (++i < args->Length()) {
1239 position = QTextLine::CursorPosition(arg->Int32Value());
1242 int pos = d->positionAt(x, y, position);
1243 const int cursor = d->m_cursor;
1245 const int preeditLength = d->preeditAreaText().length();
1246 pos = pos > cursor + preeditLength
1247 ? pos - preeditLength
1250 args->returnValue(v8::Int32::New(pos));
1253 int QQuickTextInputPrivate::positionAt(int x, int y, QTextLine::CursorPosition position) const
1257 QTextLine line = m_textLayout.lineAt(0);
1258 for (int i = 1; i < m_textLayout.lineCount(); ++i) {
1259 QTextLine nextLine = m_textLayout.lineAt(i);
1261 if (y < (line.rect().bottom() + nextLine.y()) / 2)
1265 return line.isValid() ? line.xToCursor(x, position) : 0;
1268 void QQuickTextInput::keyPressEvent(QKeyEvent* ev)
1270 Q_D(QQuickTextInput);
1271 // Don't allow MacOSX up/down support, and we don't allow a completer.
1272 bool ignore = (ev->key() == Qt::Key_Up || ev->key() == Qt::Key_Down) && ev->modifiers() == Qt::NoModifier;
1273 if (!ignore && (d->lastSelectionStart == d->lastSelectionEnd) && (ev->key() == Qt::Key_Right || ev->key() == Qt::Key_Left)) {
1274 // Ignore when moving off the end unless there is a selection,
1275 // because then moving will do something (deselect).
1276 int cursorPosition = d->m_cursor;
1277 if (cursorPosition == 0)
1278 ignore = ev->key() == (d->layoutDirection() == Qt::LeftToRight ? Qt::Key_Left : Qt::Key_Right);
1279 if (cursorPosition == text().length())
1280 ignore = ev->key() == (d->layoutDirection() == Qt::LeftToRight ? Qt::Key_Right : Qt::Key_Left);
1285 d->processKeyEvent(ev);
1287 if (!ev->isAccepted())
1288 QQuickImplicitSizeItem::keyPressEvent(ev);
1291 void QQuickTextInput::inputMethodEvent(QInputMethodEvent *ev)
1293 Q_D(QQuickTextInput);
1294 const bool wasComposing = d->preeditAreaText().length() > 0;
1295 if (d->m_readOnly) {
1298 d->processInputMethodEvent(ev);
1300 if (!ev->isAccepted())
1301 QQuickImplicitSizeItem::inputMethodEvent(ev);
1303 if (wasComposing != (d->m_textLayout.preeditAreaText().length() > 0))
1304 emit inputMethodComposingChanged();
1307 void QQuickTextInput::mouseDoubleClickEvent(QMouseEvent *event)
1309 Q_D(QQuickTextInput);
1311 if (d->selectByMouse && event->button() == Qt::LeftButton) {
1313 int cursor = d->positionAt(event->localPos());
1314 d->selectWordAtPos(cursor);
1315 event->setAccepted(true);
1316 if (!d->hasPendingTripleClick()) {
1317 d->tripleClickStartPoint = event->localPos().toPoint();
1318 d->tripleClickTimer.start();
1321 if (d->sendMouseEventToInputContext(event))
1323 QQuickImplicitSizeItem::mouseDoubleClickEvent(event);
1327 void QQuickTextInput::mousePressEvent(QMouseEvent *event)
1329 Q_D(QQuickTextInput);
1331 d->pressPos = event->localPos();
1333 if (d->focusOnPress) {
1334 bool hadActiveFocus = hasActiveFocus();
1336 // re-open input panel on press if already focused
1337 if (hasActiveFocus() && hadActiveFocus && !d->m_readOnly)
1338 openSoftwareInputPanel();
1340 if (d->selectByMouse) {
1341 setKeepMouseGrab(false);
1342 d->selectPressed = true;
1343 QPoint distanceVector = d->pressPos.toPoint() - d->tripleClickStartPoint;
1344 if (d->hasPendingTripleClick()
1345 && distanceVector.manhattanLength() < qApp->styleHints()->startDragDistance()) {
1346 event->setAccepted(true);
1352 if (d->sendMouseEventToInputContext(event))
1355 bool mark = (event->modifiers() & Qt::ShiftModifier) && d->selectByMouse;
1356 int cursor = d->positionAt(event->localPos());
1357 d->moveCursor(cursor, mark);
1358 event->setAccepted(true);
1361 void QQuickTextInput::mouseMoveEvent(QMouseEvent *event)
1363 Q_D(QQuickTextInput);
1365 if (d->selectPressed) {
1366 if (qAbs(int(event->localPos().x() - d->pressPos.x())) > qApp->styleHints()->startDragDistance())
1367 setKeepMouseGrab(true);
1369 if (d->composeMode()) {
1371 int startPos = d->positionAt(d->pressPos);
1372 int currentPos = d->positionAt(event->localPos());
1373 if (startPos != currentPos)
1374 d->setSelection(startPos, currentPos - startPos);
1376 moveCursorSelection(d->positionAt(event->localPos()), d->mouseSelectionMode);
1378 event->setAccepted(true);
1380 QQuickImplicitSizeItem::mouseMoveEvent(event);
1384 void QQuickTextInput::mouseReleaseEvent(QMouseEvent *event)
1386 Q_D(QQuickTextInput);
1387 if (d->sendMouseEventToInputContext(event))
1389 if (d->selectPressed) {
1390 d->selectPressed = false;
1391 setKeepMouseGrab(false);
1393 #ifndef QT_NO_CLIPBOARD
1394 if (QGuiApplication::clipboard()->supportsSelection()) {
1395 if (event->button() == Qt::LeftButton) {
1396 d->copy(QClipboard::Selection);
1397 } else if (!d->m_readOnly && event->button() == Qt::MidButton) {
1399 d->insert(QGuiApplication::clipboard()->text(QClipboard::Selection));
1403 if (!event->isAccepted())
1404 QQuickImplicitSizeItem::mouseReleaseEvent(event);
1407 bool QQuickTextInputPrivate::sendMouseEventToInputContext(QMouseEvent *event)
1409 #if !defined QT_NO_IM
1410 if (composeMode()) {
1411 int tmp_cursor = positionAt(event->localPos());
1412 int mousePos = tmp_cursor - m_cursor;
1413 if (mousePos >= 0 && mousePos <= m_textLayout.preeditAreaText().length()) {
1414 if (event->type() == QEvent::MouseButtonRelease) {
1415 qApp->inputPanel()->invokeAction(QInputPanel::Click, mousePos);
1428 void QQuickTextInput::mouseUngrabEvent()
1430 Q_D(QQuickTextInput);
1431 d->selectPressed = false;
1432 setKeepMouseGrab(false);
1435 bool QQuickTextInput::event(QEvent* ev)
1437 #ifndef QT_NO_SHORTCUT
1438 Q_D(QQuickTextInput);
1439 if (ev->type() == QEvent::ShortcutOverride) {
1442 QKeyEvent* ke = static_cast<QKeyEvent*>(ev);
1443 if (ke == QKeySequence::Copy
1444 || ke == QKeySequence::Paste
1445 || ke == QKeySequence::Cut
1446 || ke == QKeySequence::Redo
1447 || ke == QKeySequence::Undo
1448 || ke == QKeySequence::MoveToNextWord
1449 || ke == QKeySequence::MoveToPreviousWord
1450 || ke == QKeySequence::MoveToStartOfDocument
1451 || ke == QKeySequence::MoveToEndOfDocument
1452 || ke == QKeySequence::SelectNextWord
1453 || ke == QKeySequence::SelectPreviousWord
1454 || ke == QKeySequence::SelectStartOfLine
1455 || ke == QKeySequence::SelectEndOfLine
1456 || ke == QKeySequence::SelectStartOfBlock
1457 || ke == QKeySequence::SelectEndOfBlock
1458 || ke == QKeySequence::SelectStartOfDocument
1459 || ke == QKeySequence::SelectAll
1460 || ke == QKeySequence::SelectEndOfDocument) {
1462 } else if (ke->modifiers() == Qt::NoModifier || ke->modifiers() == Qt::ShiftModifier
1463 || ke->modifiers() == Qt::KeypadModifier) {
1464 if (ke->key() < Qt::Key_Escape) {
1468 switch (ke->key()) {
1469 case Qt::Key_Delete:
1472 case Qt::Key_Backspace:
1484 return QQuickImplicitSizeItem::event(ev);
1487 void QQuickTextInput::geometryChanged(const QRectF &newGeometry,
1488 const QRectF &oldGeometry)
1490 Q_D(QQuickTextInput);
1491 if (newGeometry.width() != oldGeometry.width())
1493 updateCursorRectangle();
1494 QQuickImplicitSizeItem::geometryChanged(newGeometry, oldGeometry);
1497 void QQuickTextInputPrivate::updateHorizontalScroll()
1499 Q_Q(QQuickTextInput);
1500 QTextLine currentLine = m_textLayout.lineForTextPosition(m_cursor + m_preeditCursor);
1501 const int preeditLength = m_textLayout.preeditAreaText().length();
1502 const int width = qMax(0, qFloor(q->width()));
1503 int widthUsed = currentLine.isValid() ? qRound(currentLine.naturalTextWidth()) : 0;
1504 int previousScroll = hscroll;
1506 if (!autoScroll || widthUsed <= width || m_echoMode == QQuickTextInput::NoEcho) {
1509 Q_ASSERT(currentLine.isValid());
1510 int cix = qRound(currentLine.cursorToX(m_cursor + preeditLength));
1511 if (cix - hscroll >= width) {
1512 // text doesn't fit, cursor is to the right of br (scroll right)
1513 hscroll = cix - width;
1514 } else if (cix - hscroll < 0 && hscroll < widthUsed) {
1515 // text doesn't fit, cursor is to the left of br (scroll left)
1517 } else if (widthUsed - hscroll < width) {
1518 // text doesn't fit, text document is to the left of br; align
1520 hscroll = widthUsed - width;
1522 if (preeditLength > 0) {
1523 // check to ensure long pre-edit text doesn't push the cursor
1525 cix = qRound(currentLine.cursorToX(m_cursor + qMax(0, m_preeditCursor - 1)));
1530 if (previousScroll != hscroll)
1531 textLayoutDirty = true;
1534 void QQuickTextInputPrivate::updateVerticalScroll()
1536 Q_Q(QQuickTextInput);
1537 const int preeditLength = m_textLayout.preeditAreaText().length();
1538 const int height = qMax(0, qFloor(q->height()));
1539 int heightUsed = boundingRect.height();
1540 int previousScroll = vscroll;
1542 if (!autoScroll || heightUsed <= height) {
1543 // text fits in br; use vscroll for alignment
1544 switch (vAlign & ~(Qt::AlignAbsolute|Qt::AlignHorizontal_Mask)) {
1545 case Qt::AlignBottom:
1546 vscroll = heightUsed - height;
1548 case Qt::AlignVCenter:
1549 vscroll = (heightUsed - height) / 2;
1557 QTextLine currentLine = m_textLayout.lineForTextPosition(m_cursor + preeditLength);
1558 QRectF r = currentLine.isValid() ? currentLine.rect() : QRectF();
1559 int top = qFloor(r.top());
1560 int bottom = qCeil(r.bottom());
1562 if (bottom - vscroll >= height) {
1563 // text doesn't fit, cursor is to the below the br (scroll down)
1564 vscroll = bottom - height;
1565 } else if (top - vscroll < 0 && vscroll < heightUsed) {
1566 // text doesn't fit, cursor is above br (scroll up)
1568 } else if (heightUsed - vscroll < height) {
1569 // text doesn't fit, text document is to the left of br; align
1571 vscroll = heightUsed - height;
1573 if (preeditLength > 0) {
1574 // check to ensure long pre-edit text doesn't push the cursor
1576 currentLine = m_textLayout.lineForTextPosition(m_cursor + qMax(0, m_preeditCursor - 1));
1577 top = currentLine.isValid() ? qRound(currentLine.rect().top()) : 0;
1582 if (previousScroll != vscroll)
1583 textLayoutDirty = true;
1586 QSGNode *QQuickTextInput::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data)
1589 Q_D(QQuickTextInput);
1591 QQuickTextNode *node = static_cast<QQuickTextNode *>(oldNode);
1593 node = new QQuickTextNode(QQuickItemPrivate::get(this)->sceneGraphContext());
1596 if (!d->textLayoutDirty) {
1597 QSGSimpleRectNode *cursorNode = node->cursorNode();
1598 if (cursorNode != 0 && !isReadOnly()) {
1599 cursorNode->setRect(cursorRectangle());
1601 if (!d->cursorVisible || (!d->m_blinkStatus && d->m_blinkPeriod > 0)) {
1608 node->deleteContent();
1609 node->setMatrix(QMatrix4x4());
1611 QPoint offset = QPoint(0,0);
1612 QFontMetrics fm = QFontMetrics(d->font);
1613 if (d->autoScroll) {
1614 // the y offset is there to keep the baseline constant in case we have script changes in the text.
1615 offset = -QPoint(d->hscroll, d->vscroll + d->m_ascent - fm.ascent());
1617 offset = -QPoint(d->hscroll, d->vscroll);
1620 if (!d->m_textLayout.text().isEmpty()) {
1621 node->addTextLayout(offset, &d->m_textLayout, d->color,
1622 QQuickText::Normal, QColor(),
1623 d->selectionColor, d->selectedTextColor,
1624 d->selectionStart(),
1625 d->selectionEnd() - 1); // selectionEnd() returns first char after
1629 if (!isReadOnly() && d->cursorItem == 0) {
1630 node->setCursor(cursorRectangle(), d->color);
1631 if (!d->cursorVisible || (!d->m_blinkStatus && d->m_blinkPeriod > 0)) {
1638 d->textLayoutDirty = false;
1644 QVariant QQuickTextInput::inputMethodQuery(Qt::InputMethodQuery property) const
1646 Q_D(const QQuickTextInput);
1649 return QVariant((bool)(flags() & ItemAcceptsInputMethod));
1651 return QVariant((int)inputMethodHints());
1652 case Qt::ImCursorRectangle:
1653 return cursorRectangle();
1656 case Qt::ImCursorPosition:
1657 return QVariant(d->m_cursor);
1658 case Qt::ImSurroundingText:
1659 if (d->m_echoMode == PasswordEchoOnEdit && !d->m_passwordEchoEditing) {
1660 return QVariant(displayText());
1662 return QVariant(d->realText());
1664 case Qt::ImCurrentSelection:
1665 return QVariant(selectedText());
1666 case Qt::ImMaximumTextLength:
1667 return QVariant(maxLength());
1668 case Qt::ImAnchorPosition:
1669 if (d->selectionStart() == d->selectionEnd())
1670 return QVariant(d->m_cursor);
1671 else if (d->selectionStart() == d->m_cursor)
1672 return QVariant(d->selectionEnd());
1674 return QVariant(d->selectionStart());
1681 \qmlmethod void QtQuick2::TextInput::deselect()
1683 Removes active text selection.
1685 void QQuickTextInput::deselect()
1687 Q_D(QQuickTextInput);
1692 \qmlmethod void QtQuick2::TextInput::selectAll()
1694 Causes all text to be selected.
1696 void QQuickTextInput::selectAll()
1698 Q_D(QQuickTextInput);
1699 d->setSelection(0, text().length());
1703 \qmlmethod void QtQuick2::TextInput::isRightToLeft(int start, int end)
1705 Returns true if the natural reading direction of the editor text
1706 found between positions \a start and \a end is right to left.
1708 bool QQuickTextInput::isRightToLeft(int start, int end)
1711 qmlInfo(this) << "isRightToLeft(start, end) called with the end property being smaller than the start.";
1714 return text().mid(start, end - start).isRightToLeft();
1718 #ifndef QT_NO_CLIPBOARD
1720 \qmlmethod QtQuick2::TextInput::cut()
1722 Moves the currently selected text to the system clipboard.
1724 void QQuickTextInput::cut()
1726 Q_D(QQuickTextInput);
1732 \qmlmethod QtQuick2::TextInput::copy()
1734 Copies the currently selected text to the system clipboard.
1736 void QQuickTextInput::copy()
1738 Q_D(QQuickTextInput);
1743 \qmlmethod QtQuick2::TextInput::paste()
1745 Replaces the currently selected text by the contents of the system clipboard.
1747 void QQuickTextInput::paste()
1749 Q_D(QQuickTextInput);
1753 #endif // QT_NO_CLIPBOARD
1756 \qmlmethod void QtQuick2::TextInput::insert(int position, string text)
1758 Inserts \a text into the TextInput at position.
1761 void QQuickTextInput::insert(int position, const QString &text)
1763 Q_D(QQuickTextInput);
1764 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
1765 if (d->m_echoMode == QQuickTextInput::Password)
1766 d->m_passwordEchoTimer.start(qt_passwordEchoDelay, this);
1769 if (position < 0 || position > d->m_text.length())
1772 const int priorState = d->m_undoState;
1774 QString insertText = text;
1776 if (d->hasSelectedText()) {
1777 d->addCommand(QQuickTextInputPrivate::Command(
1778 QQuickTextInputPrivate::SetSelection, d->m_cursor, 0, d->m_selstart, d->m_selend));
1780 if (d->m_maskData) {
1781 insertText = d->maskString(position, insertText);
1782 for (int i = 0; i < insertText.length(); ++i) {
1783 d->addCommand(QQuickTextInputPrivate::Command(
1784 QQuickTextInputPrivate::DeleteSelection, position + i, d->m_text.at(position + i), -1, -1));
1785 d->addCommand(QQuickTextInputPrivate::Command(
1786 QQuickTextInputPrivate::Insert, position + i, insertText.at(i), -1, -1));
1788 d->m_text.replace(position, insertText.length(), insertText);
1789 if (!insertText.isEmpty())
1790 d->m_textDirty = true;
1791 if (position < d->m_selend && position + insertText.length() > d->m_selstart)
1792 d->m_selDirty = true;
1794 int remaining = d->m_maxLength - d->m_text.length();
1795 if (remaining != 0) {
1796 insertText = insertText.left(remaining);
1797 d->m_text.insert(position, insertText);
1798 for (int i = 0; i < insertText.length(); ++i)
1799 d->addCommand(QQuickTextInputPrivate::Command(
1800 QQuickTextInputPrivate::Insert, position + i, insertText.at(i), -1, -1));
1801 if (d->m_cursor >= position)
1802 d->m_cursor += insertText.length();
1803 if (d->m_selstart >= position)
1804 d->m_selstart += insertText.length();
1805 if (d->m_selend >= position)
1806 d->m_selend += insertText.length();
1807 d->m_textDirty = true;
1808 if (position >= d->m_selstart && position <= d->m_selend)
1809 d->m_selDirty = true;
1813 d->addCommand(QQuickTextInputPrivate::Command(
1814 QQuickTextInputPrivate::SetSelection, d->m_cursor, 0, d->m_selstart, d->m_selend));
1815 d->finishChange(priorState);
1817 if (d->lastSelectionStart != d->lastSelectionEnd) {
1818 if (d->m_selstart != d->lastSelectionStart) {
1819 d->lastSelectionStart = d->m_selstart;
1820 emit selectionStartChanged();
1822 if (d->m_selend != d->lastSelectionEnd) {
1823 d->lastSelectionEnd = d->m_selend;
1824 emit selectionEndChanged();
1830 \qmlmethod string QtQuick2::TextInput::getText(int start, int end)
1832 Removes the section of text that is between the \a start and \a end positions from the TextInput.
1835 void QQuickTextInput::remove(int start, int end)
1837 Q_D(QQuickTextInput);
1839 start = qBound(0, start, d->m_text.length());
1840 end = qBound(0, end, d->m_text.length());
1844 else if (start == end)
1847 if (start < d->m_selend && end > d->m_selstart)
1848 d->m_selDirty = true;
1850 const int priorState = d->m_undoState;
1852 d->addCommand(QQuickTextInputPrivate::Command(
1853 QQuickTextInputPrivate::SetSelection, d->m_cursor, 0, d->m_selstart, d->m_selend));
1855 if (start <= d->m_cursor && d->m_cursor < end) {
1856 // cursor is within the selection. Split up the commands
1857 // to be able to restore the correct cursor position
1858 for (int i = d->m_cursor; i >= start; --i) {
1859 d->addCommand(QQuickTextInputPrivate::Command(
1860 QQuickTextInputPrivate::DeleteSelection, i, d->m_text.at(i), -1, 1));
1862 for (int i = end - 1; i > d->m_cursor; --i) {
1863 d->addCommand(QQuickTextInputPrivate::Command(
1864 QQuickTextInputPrivate::DeleteSelection, i - d->m_cursor + start - 1, d->m_text.at(i), -1, -1));
1867 for (int i = end - 1; i >= start; --i) {
1868 d->addCommand(QQuickTextInputPrivate::Command(
1869 QQuickTextInputPrivate::RemoveSelection, i, d->m_text.at(i), -1, -1));
1872 if (d->m_maskData) {
1873 d->m_text.replace(start, end - start, d->clearString(start, end - start));
1874 for (int i = 0; i < end - start; ++i) {
1875 d->addCommand(QQuickTextInputPrivate::Command(
1876 QQuickTextInputPrivate::Insert, start + i, d->m_text.at(start + i), -1, -1));
1879 d->m_text.remove(start, end - start);
1881 if (d->m_cursor > start)
1882 d->m_cursor -= qMin(d->m_cursor, end) - start;
1883 if (d->m_selstart > start)
1884 d->m_selstart -= qMin(d->m_selstart, end) - start;
1885 if (d->m_selend > end)
1886 d->m_selend -= qMin(d->m_selend, end) - start;
1888 d->addCommand(QQuickTextInputPrivate::Command(
1889 QQuickTextInputPrivate::SetSelection, d->m_cursor, 0, d->m_selstart, d->m_selend));
1891 d->m_textDirty = true;
1892 d->finishChange(priorState);
1894 if (d->lastSelectionStart != d->lastSelectionEnd) {
1895 if (d->m_selstart != d->lastSelectionStart) {
1896 d->lastSelectionStart = d->m_selstart;
1897 emit selectionStartChanged();
1899 if (d->m_selend != d->lastSelectionEnd) {
1900 d->lastSelectionEnd = d->m_selend;
1901 emit selectionEndChanged();
1908 \qmlmethod void QtQuick2::TextInput::selectWord()
1910 Causes the word closest to the current cursor position to be selected.
1912 void QQuickTextInput::selectWord()
1914 Q_D(QQuickTextInput);
1915 d->selectWordAtPos(d->m_cursor);
1919 \qmlproperty bool QtQuick2::TextInput::smooth
1921 This property holds whether the text is smoothly scaled or transformed.
1923 Smooth filtering gives better visual quality, but is slower. If
1924 the item is displayed at its natural size, this property has no visual or
1927 \note Generally scaling artifacts are only visible if the item is stationary on
1928 the screen. A common pattern when animating an item is to disable smooth
1929 filtering at the beginning of the animation and reenable it at the conclusion.
1933 \qmlproperty string QtQuick2::TextInput::passwordCharacter
1935 This is the character displayed when echoMode is set to Password or
1936 PasswordEchoOnEdit. By default it is an asterisk.
1938 If this property is set to a string with more than one character,
1939 the first character is used. If the string is empty, the value
1940 is ignored and the property is not set.
1942 QString QQuickTextInput::passwordCharacter() const
1944 Q_D(const QQuickTextInput);
1945 return QString(d->m_passwordCharacter);
1948 void QQuickTextInput::setPasswordCharacter(const QString &str)
1950 Q_D(QQuickTextInput);
1951 if (str.length() < 1)
1953 d->m_passwordCharacter = str.constData()[0];
1954 if (d->m_echoMode == Password || d->m_echoMode == PasswordEchoOnEdit)
1955 d->updateDisplayText();
1956 emit passwordCharacterChanged();
1960 \qmlproperty string QtQuick2::TextInput::displayText
1962 This is the text displayed in the TextInput.
1964 If \l echoMode is set to TextInput::Normal, this holds the
1965 same value as the TextInput::text property. Otherwise,
1966 this property holds the text visible to the user, while
1967 the \l text property holds the actual entered text.
1969 QString QQuickTextInput::displayText() const
1971 Q_D(const QQuickTextInput);
1972 return d->m_textLayout.text();
1976 \qmlproperty bool QtQuick2::TextInput::selectByMouse
1980 If true, the user can use the mouse to select text in some
1981 platform-specific way. Note that for some platforms this may
1982 not be an appropriate interaction (eg. may conflict with how
1983 the text needs to behave inside a Flickable.
1985 bool QQuickTextInput::selectByMouse() const
1987 Q_D(const QQuickTextInput);
1988 return d->selectByMouse;
1991 void QQuickTextInput::setSelectByMouse(bool on)
1993 Q_D(QQuickTextInput);
1994 if (d->selectByMouse != on) {
1995 d->selectByMouse = on;
1996 emit selectByMouseChanged(on);
2001 \qmlproperty enum QtQuick2::TextInput::mouseSelectionMode
2003 Specifies how text should be selected using a mouse.
2006 \o TextInput.SelectCharacters - The selection is updated with individual characters. (Default)
2007 \o TextInput.SelectWords - The selection is updated with whole words.
2010 This property only applies when \l selectByMouse is true.
2013 QQuickTextInput::SelectionMode QQuickTextInput::mouseSelectionMode() const
2015 Q_D(const QQuickTextInput);
2016 return d->mouseSelectionMode;
2019 void QQuickTextInput::setMouseSelectionMode(SelectionMode mode)
2021 Q_D(QQuickTextInput);
2022 if (d->mouseSelectionMode != mode) {
2023 d->mouseSelectionMode = mode;
2024 emit mouseSelectionModeChanged(mode);
2029 \qmlproperty bool QtQuick2::TextInput::canPaste
2031 Returns true if the TextInput is writable and the content of the clipboard is
2032 suitable for pasting into the TextEdit.
2034 bool QQuickTextInput::canPaste() const
2036 Q_D(const QQuickTextInput);
2037 if (!d->canPasteValid) {
2038 if (const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData())
2039 const_cast<QQuickTextInputPrivate *>(d)->canPaste = !d->m_readOnly && mimeData->hasText();
2040 const_cast<QQuickTextInputPrivate *>(d)->canPasteValid = true;
2045 void QQuickTextInput::moveCursorSelection(int position)
2047 Q_D(QQuickTextInput);
2048 d->moveCursor(position, true);
2052 \qmlmethod void QtQuick2::TextInput::moveCursorSelection(int position, SelectionMode mode = TextInput.SelectCharacters)
2054 Moves the cursor to \a position and updates the selection according to the optional \a mode
2055 parameter. (To only move the cursor, set the \l cursorPosition property.)
2057 When this method is called it additionally sets either the
2058 selectionStart or the selectionEnd (whichever was at the previous cursor position)
2059 to the specified position. This allows you to easily extend and contract the selected
2062 The selection mode specifies whether the selection is updated on a per character or a per word
2063 basis. If not specified the selection mode will default to TextInput.SelectCharacters.
2066 \o TextEdit.SelectCharacters - Sets either the selectionStart or selectionEnd (whichever was at
2067 the previous cursor position) to the specified position.
2068 \o TextEdit.SelectWords - Sets the selectionStart and selectionEnd to include all
2069 words between the specified position and the previous cursor position. Words partially in the
2073 For example, take this sequence of calls:
2077 moveCursorSelection(9, TextInput.SelectCharacters)
2078 moveCursorSelection(7, TextInput.SelectCharacters)
2081 This moves the cursor to position 5, extend the selection end from 5 to 9
2082 and then retract the selection end from 9 to 7, leaving the text from position 5 to 7
2083 selected (the 6th and 7th characters).
2085 The same sequence with TextInput.SelectWords will extend the selection start to a word boundary
2086 before or on position 5 and extend the selection end to a word boundary on or past position 9.
2088 void QQuickTextInput::moveCursorSelection(int pos, SelectionMode mode)
2090 Q_D(QQuickTextInput);
2092 if (mode == SelectCharacters) {
2093 d->moveCursor(pos, true);
2094 } else if (pos != d->m_cursor){
2095 const int cursor = d->m_cursor;
2097 if (!d->hasSelectedText())
2098 anchor = d->m_cursor;
2099 else if (d->selectionStart() == d->m_cursor)
2100 anchor = d->selectionEnd();
2102 anchor = d->selectionStart();
2104 if (anchor < pos || (anchor == pos && cursor < pos)) {
2105 const QString text = this->text();
2106 QTextBoundaryFinder finder(QTextBoundaryFinder::Word, text);
2107 finder.setPosition(anchor);
2109 const QTextBoundaryFinder::BoundaryReasons reasons = finder.boundaryReasons();
2110 if (anchor < text.length() && (!(reasons & QTextBoundaryFinder::StartWord)
2111 || ((reasons & QTextBoundaryFinder::EndWord) && anchor > cursor))) {
2112 finder.toPreviousBoundary();
2114 anchor = finder.position() != -1 ? finder.position() : 0;
2116 finder.setPosition(pos);
2117 if (pos > 0 && !finder.boundaryReasons())
2118 finder.toNextBoundary();
2119 const int cursor = finder.position() != -1 ? finder.position() : text.length();
2121 d->setSelection(anchor, cursor - anchor);
2122 } else if (anchor > pos || (anchor == pos && cursor > pos)) {
2123 const QString text = this->text();
2124 QTextBoundaryFinder finder(QTextBoundaryFinder::Word, text);
2125 finder.setPosition(anchor);
2127 const QTextBoundaryFinder::BoundaryReasons reasons = finder.boundaryReasons();
2128 if (anchor > 0 && (!(reasons & QTextBoundaryFinder::EndWord)
2129 || ((reasons & QTextBoundaryFinder::StartWord) && anchor < cursor))) {
2130 finder.toNextBoundary();
2133 anchor = finder.position() != -1 ? finder.position() : text.length();
2135 finder.setPosition(pos);
2136 if (pos < text.length() && !finder.boundaryReasons())
2137 finder.toPreviousBoundary();
2138 const int cursor = finder.position() != -1 ? finder.position() : 0;
2140 d->setSelection(anchor, cursor - anchor);
2146 \qmlmethod void QtQuick2::TextInput::openSoftwareInputPanel()
2148 Opens software input panels like virtual keyboards for typing, useful for
2149 customizing when you want the input keyboard to be shown and hidden in
2152 By default the opening of input panels follows the platform style. Input panels are
2153 always closed if no editor has active focus.
2155 You can disable the automatic behavior by setting the property \c activeFocusOnPress to false
2156 and use functions openSoftwareInputPanel() and closeSoftwareInputPanel() to implement
2157 the behavior you want.
2159 Only relevant on platforms, which provide virtual keyboards.
2165 text: "Hello world!"
2166 activeFocusOnPress: false
2168 anchors.fill: parent
2170 if (!textInput.activeFocus) {
2171 textInput.forceActiveFocus()
2172 textInput.openSoftwareInputPanel();
2174 textInput.focus = false;
2177 onPressAndHold: textInput.closeSoftwareInputPanel();
2182 void QQuickTextInput::openSoftwareInputPanel()
2185 qGuiApp->inputPanel()->show();
2189 \qmlmethod void QtQuick2::TextInput::closeSoftwareInputPanel()
2191 Closes a software input panel like a virtual keyboard shown on the screen, useful
2192 for customizing when you want the input keyboard to be shown and hidden in
2195 By default the opening of input panels follows the platform style. Input panels are
2196 always closed if no editor has active focus.
2198 You can disable the automatic behavior by setting the property \c activeFocusOnPress to false
2199 and use functions openSoftwareInputPanel() and closeSoftwareInputPanel() to implement
2200 the behavior you want.
2202 Only relevant on platforms, which provide virtual keyboards.
2208 text: "Hello world!"
2209 activeFocusOnPress: false
2211 anchors.fill: parent
2213 if (!textInput.activeFocus) {
2214 textInput.forceActiveFocus();
2215 textInput.openSoftwareInputPanel();
2217 textInput.focus = false;
2220 onPressAndHold: textInput.closeSoftwareInputPanel();
2225 void QQuickTextInput::closeSoftwareInputPanel()
2228 qGuiApp->inputPanel()->hide();
2231 void QQuickTextInput::focusInEvent(QFocusEvent *event)
2233 Q_D(const QQuickTextInput);
2234 if (d->focusOnPress && !d->m_readOnly)
2235 openSoftwareInputPanel();
2236 QQuickImplicitSizeItem::focusInEvent(event);
2239 void QQuickTextInput::itemChange(ItemChange change, const ItemChangeData &value)
2241 Q_D(QQuickTextInput);
2242 if (change == ItemActiveFocusHasChanged) {
2243 bool hasFocus = value.boolValue;
2244 d->focused = hasFocus;
2245 setCursorVisible(hasFocus); // ### refactor: && d->canvas && d->canvas->hasFocus()
2246 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
2247 if (!hasFocus && (d->m_passwordEchoEditing || d->m_passwordEchoTimer.isActive())) {
2249 if (!hasFocus && d->m_passwordEchoEditing) {
2251 d->updatePasswordEchoEditing(false);//QQuickTextInputPrivate sets it on key events, but doesn't deal with focus events
2259 QQuickItem::itemChange(change, value);
2263 \qmlproperty bool QtQuick2::TextInput::inputMethodComposing
2266 This property holds whether the TextInput has partial text input from an
2269 While it is composing an input method may rely on mouse or key events from
2270 the TextInput to edit or commit the partial text. This property can be
2271 used to determine when to disable events handlers that may interfere with
2272 the correct operation of an input method.
2274 bool QQuickTextInput::isInputMethodComposing() const
2276 Q_D(const QQuickTextInput);
2277 return d->preeditAreaText().length() > 0;
2280 void QQuickTextInputPrivate::init()
2282 Q_Q(QQuickTextInput);
2283 q->setSmooth(smooth);
2284 q->setAcceptedMouseButtons(Qt::LeftButton);
2285 q->setFlag(QQuickItem::ItemAcceptsInputMethod);
2286 q->setFlag(QQuickItem::ItemHasContents);
2287 #ifndef QT_NO_CLIPBOARD
2288 q->connect(QGuiApplication::clipboard(), SIGNAL(dataChanged()),
2289 q, SLOT(q_canPasteChanged()));
2290 #endif // QT_NO_CLIPBOARD
2292 oldValidity = hasAcceptableInput(m_text);
2293 lastSelectionStart = 0;
2294 lastSelectionEnd = 0;
2295 selectedTextColor = m_palette.color(QPalette::HighlightedText);
2296 selectionColor = m_palette.color(QPalette::Highlight);
2297 determineHorizontalAlignment();
2299 if (!qmlDisableDistanceField()) {
2300 QTextOption option = m_textLayout.textOption();
2301 option.setUseDesignMetrics(true);
2302 m_textLayout.setTextOption(option);
2306 void QQuickTextInput::updateCursorRectangle()
2308 Q_D(QQuickTextInput);
2309 if (!isComponentComplete())
2312 d->updateHorizontalScroll();
2313 d->updateVerticalScroll();
2316 emit cursorRectangleChanged();
2317 if (d->cursorItem) {
2318 QRectF r = cursorRectangle();
2319 d->cursorItem->setPos(r.topLeft());
2320 d->cursorItem->setHeight(r.height());
2324 void QQuickTextInput::selectionChanged()
2326 Q_D(QQuickTextInput);
2327 d->textLayoutDirty = true; //TODO: Only update rect in selection
2329 emit selectedTextChanged();
2331 if (d->lastSelectionStart != d->selectionStart()) {
2332 d->lastSelectionStart = d->selectionStart();
2333 if (d->lastSelectionStart == -1)
2334 d->lastSelectionStart = d->m_cursor;
2335 emit selectionStartChanged();
2337 if (d->lastSelectionEnd != d->selectionEnd()) {
2338 d->lastSelectionEnd = d->selectionEnd();
2339 if (d->lastSelectionEnd == -1)
2340 d->lastSelectionEnd = d->m_cursor;
2341 emit selectionEndChanged();
2345 void QQuickTextInputPrivate::showCursor()
2347 if (textNode != 0 && textNode->cursorNode() != 0)
2348 textNode->cursorNode()->setColor(color);
2351 void QQuickTextInputPrivate::hideCursor()
2353 if (textNode != 0 && textNode->cursorNode() != 0)
2354 textNode->cursorNode()->setColor(QColor(0, 0, 0, 0));
2357 QRectF QQuickTextInput::boundingRect() const
2359 Q_D(const QQuickTextInput);
2361 int cursorWidth = d->cursorItem ? d->cursorItem->width() : d->m_cursorWidth;
2363 // Could include font max left/right bearings to either side of rectangle.
2364 QRectF r = QQuickImplicitSizeItem::boundingRect();
2365 r.setRight(r.right() + cursorWidth);
2369 void QQuickTextInput::q_canPasteChanged()
2371 Q_D(QQuickTextInput);
2372 bool old = d->canPaste;
2373 #ifndef QT_NO_CLIPBOARD
2374 if (const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData())
2375 d->canPaste = !d->m_readOnly && mimeData->hasText();
2377 d->canPaste = false;
2380 bool changed = d->canPaste != old || !d->canPasteValid;
2381 d->canPasteValid = true;
2383 emit canPasteChanged();
2387 // ### these should come from QStyleHints
2388 const int textCursorWidth = 1;
2389 const bool fullWidthSelection = true;
2394 Updates the display text based of the current edit text
2395 If the text has changed will emit displayTextChanged()
2397 void QQuickTextInputPrivate::updateDisplayText(bool forceUpdate)
2399 QString orig = m_textLayout.text();
2401 if (m_echoMode == QQuickTextInput::NoEcho)
2402 str = QString::fromLatin1("");
2406 if (m_echoMode == QQuickTextInput::Password) {
2407 str.fill(m_passwordCharacter);
2408 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
2409 if (m_passwordEchoTimer.isActive() && m_cursor > 0 && m_cursor <= m_text.length()) {
2410 int cursor = m_cursor - 1;
2411 QChar uc = m_text.at(cursor);
2413 if (cursor > 0 && uc.unicode() >= 0xdc00 && uc.unicode() < 0xe000) {
2414 // second half of a surrogate, check if we have the first half as well,
2415 // if yes restore both at once
2416 uc = m_text.at(cursor - 1);
2417 if (uc.unicode() >= 0xd800 && uc.unicode() < 0xdc00)
2418 str[cursor - 1] = uc;
2422 } else if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit && !m_passwordEchoEditing) {
2423 str.fill(m_passwordCharacter);
2426 // replace certain non-printable characters with spaces (to avoid
2427 // drawing boxes when using fonts that don't have glyphs for such
2429 QChar* uc = str.data();
2430 for (int i = 0; i < (int)str.length(); ++i) {
2431 if ((uc[i] < 0x20 && uc[i] != 0x09)
2432 || uc[i] == QChar::LineSeparator
2433 || uc[i] == QChar::ParagraphSeparator
2434 || uc[i] == QChar::ObjectReplacementCharacter)
2435 uc[i] = QChar(0x0020);
2438 if (str != orig || forceUpdate) {
2439 m_textLayout.setText(str);
2440 updateLayout(); // polish?
2441 emit q_func()->displayTextChanged();
2445 void QQuickTextInputPrivate::updateLayout()
2447 Q_Q(QQuickTextInput);
2449 if (!q->isComponentComplete())
2452 QTextOption option = m_textLayout.textOption();
2453 option.setTextDirection(m_layoutDirection);
2454 option.setFlags(QTextOption::IncludeTrailingSpaces);
2455 option.setWrapMode(QTextOption::WrapMode(wrapMode));
2456 option.setAlignment(Qt::Alignment(q->effectiveHAlign()));
2457 m_textLayout.setTextOption(option);
2458 m_textLayout.setFont(font);
2460 boundingRect = QRectF();
2461 m_textLayout.beginLayout();
2462 QTextLine line = m_textLayout.createLine();
2463 qreal lineWidth = q->widthValid() ? q->width() : INT_MAX;
2465 QTextLine firstLine = line;
2467 line.setLineWidth(lineWidth);
2468 line.setPosition(QPointF(line.position().x(), height));
2469 boundingRect = boundingRect.united(line.naturalTextRect());
2471 height += line.height();
2472 line = m_textLayout.createLine();
2473 } while (line.isValid());
2474 m_textLayout.endLayout();
2476 option.setWrapMode(QTextOption::NoWrap);
2477 m_textLayout.setTextOption(option);
2479 m_ascent = qRound(firstLine.ascent());
2480 textLayoutDirty = true;
2483 q->setImplicitSize(qCeil(boundingRect.width()), qCeil(boundingRect.height()));
2487 #ifndef QT_NO_CLIPBOARD
2491 Copies the currently selected text into the clipboard using the given
2494 \note If the echo mode is set to a mode other than Normal then copy
2495 will not work. This is to prevent using copy as a method of bypassing
2496 password features of the line control.
2498 void QQuickTextInputPrivate::copy(QClipboard::Mode mode) const
2500 QString t = selectedText();
2501 if (!t.isEmpty() && m_echoMode == QQuickTextInput::Normal) {
2502 QGuiApplication::clipboard()->setText(t, mode);
2509 Inserts the text stored in the application clipboard into the line
2514 void QQuickTextInputPrivate::paste(QClipboard::Mode clipboardMode)
2516 QString clip = QGuiApplication::clipboard()->text(clipboardMode);
2517 if (!clip.isEmpty() || hasSelectedText()) {
2518 separate(); //make it a separate undo/redo command
2524 #endif // !QT_NO_CLIPBOARD
2529 Exits preedit mode and commits parts marked as tentative commit
2531 void QQuickTextInputPrivate::commitPreedit()
2536 qApp->inputPanel()->reset();
2538 if (!m_tentativeCommit.isEmpty()) {
2539 internalInsert(m_tentativeCommit);
2540 m_tentativeCommit.clear();
2541 finishChange(-1, true/*not used, not documented*/, false);
2544 m_preeditCursor = 0;
2545 m_textLayout.setPreeditArea(-1, QString());
2546 m_textLayout.clearAdditionalFormats();
2553 Handles the behavior for the backspace key or function.
2554 Removes the current selection if there is a selection, otherwise
2555 removes the character prior to the cursor position.
2559 void QQuickTextInputPrivate::backspace()
2561 int priorState = m_undoState;
2562 if (hasSelectedText()) {
2563 removeSelectedText();
2564 } else if (m_cursor) {
2567 m_cursor = prevMaskBlank(m_cursor);
2568 QChar uc = m_text.at(m_cursor);
2569 if (m_cursor > 0 && uc.unicode() >= 0xdc00 && uc.unicode() < 0xe000) {
2570 // second half of a surrogate, check if we have the first half as well,
2571 // if yes delete both at once
2572 uc = m_text.at(m_cursor - 1);
2573 if (uc.unicode() >= 0xd800 && uc.unicode() < 0xdc00) {
2574 internalDelete(true);
2578 internalDelete(true);
2580 finishChange(priorState);
2586 Handles the behavior for the delete key or function.
2587 Removes the current selection if there is a selection, otherwise
2588 removes the character after the cursor position.
2592 void QQuickTextInputPrivate::del()
2594 int priorState = m_undoState;
2595 if (hasSelectedText()) {
2596 removeSelectedText();
2598 int n = m_textLayout.nextCursorPosition(m_cursor) - m_cursor;
2602 finishChange(priorState);
2608 Inserts the given \a newText at the current cursor position.
2609 If there is any selected text it is removed prior to insertion of
2612 void QQuickTextInputPrivate::insert(const QString &newText)
2614 int priorState = m_undoState;
2615 removeSelectedText();
2616 internalInsert(newText);
2617 finishChange(priorState);
2623 Clears the line control text.
2625 void QQuickTextInputPrivate::clear()
2627 int priorState = m_undoState;
2629 m_selend = m_text.length();
2630 removeSelectedText();
2632 finishChange(priorState, /*update*/false, /*edited*/false);
2638 Sets \a length characters from the given \a start position as selected.
2639 The given \a start position must be within the current text for
2640 the line control. If \a length characters cannot be selected, then
2641 the selection will extend to the end of the current text.
2643 void QQuickTextInputPrivate::setSelection(int start, int length)
2645 Q_Q(QQuickTextInput);
2648 if (start < 0 || start > (int)m_text.length()){
2649 qWarning("QQuickTextInputPrivate::setSelection: Invalid start position");
2654 if (start == m_selstart && start + length == m_selend && m_cursor == m_selend)
2657 m_selend = qMin(start + length, (int)m_text.length());
2658 m_cursor = m_selend;
2659 } else if (length < 0){
2660 if (start == m_selend && start + length == m_selstart && m_cursor == m_selstart)
2662 m_selstart = qMax(start + length, 0);
2664 m_cursor = m_selstart;
2665 } else if (m_selstart != m_selend) {
2671 emitCursorPositionChanged();
2674 emit q->selectionChanged();
2675 emitCursorPositionChanged();
2681 Initializes the line control with a starting text value of \a txt.
2683 void QQuickTextInputPrivate::init(const QString &txt)
2687 updateDisplayText();
2688 m_cursor = m_text.length();
2694 Sets the password echo editing to \a editing. If password echo editing
2695 is true, then the text of the password is displayed even if the echo
2696 mode is set to QLineEdit::PasswordEchoOnEdit. Password echoing editing
2697 does not affect other echo modes.
2699 void QQuickTextInputPrivate::updatePasswordEchoEditing(bool editing)
2701 cancelPasswordEchoTimer();
2702 m_passwordEchoEditing = editing;
2703 updateDisplayText();
2709 Fixes the current text so that it is valid given any set validators.
2711 Returns true if the text was changed. Otherwise returns false.
2713 bool QQuickTextInputPrivate::fixup() // this function assumes that validate currently returns != Acceptable
2715 #ifndef QT_NO_VALIDATOR
2717 QString textCopy = m_text;
2718 int cursorCopy = m_cursor;
2719 m_validator->fixup(textCopy);
2720 if (m_validator->validate(textCopy, cursorCopy) == QValidator::Acceptable) {
2721 if (textCopy != m_text || cursorCopy != m_cursor)
2722 internalSetText(textCopy, cursorCopy);
2733 Moves the cursor to the given position \a pos. If \a mark is true will
2734 adjust the currently selected text.
2736 void QQuickTextInputPrivate::moveCursor(int pos, bool mark)
2738 Q_Q(QQuickTextInput);
2741 if (pos != m_cursor) {
2744 pos = pos > m_cursor ? nextMaskBlank(pos) : prevMaskBlank(pos);
2748 if (m_selend > m_selstart && m_cursor == m_selstart)
2750 else if (m_selend > m_selstart && m_cursor == m_selend)
2751 anchor = m_selstart;
2754 m_selstart = qMin(anchor, pos);
2755 m_selend = qMax(anchor, pos);
2760 if (mark || m_selDirty) {
2762 emit q->selectionChanged();
2764 emitCursorPositionChanged();
2770 Applies the given input method event \a event to the text of the line
2773 void QQuickTextInputPrivate::processInputMethodEvent(QInputMethodEvent *event)
2775 Q_Q(QQuickTextInput);
2777 int priorState = -1;
2778 bool isGettingInput = !event->commitString().isEmpty()
2779 || event->preeditString() != preeditAreaText()
2780 || event->replacementLength() > 0;
2781 bool cursorPositionChanged = false;
2782 bool selectionChange = false;
2783 m_preeditDirty = event->preeditString() != preeditAreaText();
2785 if (isGettingInput) {
2786 // If any text is being input, remove selected text.
2787 priorState = m_undoState;
2788 if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit && !m_passwordEchoEditing) {
2789 updatePasswordEchoEditing(true);
2791 m_selend = m_text.length();
2793 removeSelectedText();
2796 int c = m_cursor; // cursor position after insertion of commit string
2797 if (event->replacementStart() <= 0)
2798 c += event->commitString().length() - qMin(-event->replacementStart(), event->replacementLength());
2800 m_cursor += event->replacementStart();
2804 // insert commit string
2805 if (event->replacementLength()) {
2806 m_selstart = m_cursor;
2807 m_selend = m_selstart + event->replacementLength();
2808 m_selend = qMin(m_selend, m_text.length());
2809 removeSelectedText();
2811 if (!event->commitString().isEmpty()) {
2812 internalInsert(event->commitString());
2813 cursorPositionChanged = true;
2816 m_cursor = qBound(0, c, m_text.length());
2818 for (int i = 0; i < event->attributes().size(); ++i) {
2819 const QInputMethodEvent::Attribute &a = event->attributes().at(i);
2820 if (a.type == QInputMethodEvent::Selection) {
2821 m_cursor = qBound(0, a.start + a.length, m_text.length());
2823 m_selstart = qMax(0, qMin(a.start, m_text.length()));
2824 m_selend = m_cursor;
2825 if (m_selend < m_selstart) {
2826 qSwap(m_selstart, m_selend);
2828 selectionChange = true;
2830 m_selstart = m_selend = 0;
2832 cursorPositionChanged = true;
2836 m_textLayout.setPreeditArea(m_cursor, event->preeditString());
2838 const int oldPreeditCursor = m_preeditCursor;
2839 m_preeditCursor = event->preeditString().length();
2840 m_hideCursor = false;
2841 QList<QTextLayout::FormatRange> formats;
2842 for (int i = 0; i < event->attributes().size(); ++i) {
2843 const QInputMethodEvent::Attribute &a = event->attributes().at(i);
2844 if (a.type == QInputMethodEvent::Cursor) {
2845 m_preeditCursor = a.start;
2846 m_hideCursor = !a.length;
2847 } else if (a.type == QInputMethodEvent::TextFormat) {
2848 QTextCharFormat f = qvariant_cast<QTextFormat>(a.value).toCharFormat();
2850 QTextLayout::FormatRange o;
2851 o.start = a.start + m_cursor;
2852 o.length = a.length;
2858 m_textLayout.setAdditionalFormats(formats);
2860 updateDisplayText(/*force*/ true);
2861 if (cursorPositionChanged)
2862 emitCursorPositionChanged();
2863 else if (m_preeditCursor != oldPreeditCursor)
2864 q->updateCursorRectangle();
2866 bool tentativeCommitChanged = m_tentativeCommit != event->tentativeCommitString();
2868 if (tentativeCommitChanged) {
2870 m_tentativeCommit = event->tentativeCommitString();
2873 if (isGettingInput || tentativeCommitChanged)
2874 finishChange(priorState);
2876 if (selectionChange)
2877 emit q->selectionChanged();
2883 Sets the selection to cover the word at the given cursor position.
2884 The word boundaries are defined by the behavior of QTextLayout::SkipWords
2887 void QQuickTextInputPrivate::selectWordAtPos(int cursor)
2889 int next = cursor + 1;
2892 int c = m_textLayout.previousCursorPosition(next, QTextLayout::SkipWords);
2893 moveCursor(c, false);
2894 // ## text layout should support end of words.
2895 int end = m_textLayout.nextCursorPosition(c, QTextLayout::SkipWords);
2896 while (end > cursor && m_text[end-1].isSpace())
2898 moveCursor(end, true);
2904 Completes a change to the line control text. If the change is not valid
2905 will undo the line control state back to the given \a validateFromState.
2907 If \a edited is true and the change is valid, will emit textEdited() in
2908 addition to textChanged(). Otherwise only emits textChanged() on a valid
2911 The \a update value is currently unused.
2913 bool QQuickTextInputPrivate::finishChange(int validateFromState, bool update, bool /*edited*/)
2915 Q_Q(QQuickTextInput);
2921 bool wasValidInput = m_validInput;
2922 m_validInput = true;
2923 #ifndef QT_NO_VALIDATOR
2925 QString textCopy = m_text;
2926 int cursorCopy = m_cursor;
2927 m_validInput = (m_validator->validate(textCopy, cursorCopy) != QValidator::Invalid);
2929 if (m_text != textCopy) {
2930 internalSetText(textCopy, cursorCopy);
2933 m_cursor = cursorCopy;
2935 if (!m_tentativeCommit.isEmpty()) {
2936 textCopy.insert(m_cursor, m_tentativeCommit);
2937 bool validInput = m_validator->validate(textCopy, cursorCopy) != QValidator::Invalid;
2939 m_tentativeCommit.clear();
2942 m_tentativeCommit.clear();
2946 if (validateFromState >= 0 && wasValidInput && !m_validInput) {
2947 if (m_transactions.count())
2949 internalUndo(validateFromState);
2950 m_history.resize(m_undoState);
2951 if (m_modifiedState > m_undoState)
2952 m_modifiedState = -1;
2953 m_validInput = true;
2954 m_textDirty = false;
2956 updateDisplayText();
2959 m_textDirty = false;
2960 m_preeditDirty = false;
2961 determineHorizontalAlignment();
2962 emit q->textChanged();
2965 if (m_validInput != wasValidInput)
2966 emit q->acceptableInputChanged();
2968 if (m_preeditDirty) {
2969 m_preeditDirty = false;
2970 determineHorizontalAlignment();
2975 emit q->selectionChanged();
2977 emitCursorPositionChanged();
2985 An internal function for setting the text of the line control.
2987 void QQuickTextInputPrivate::internalSetText(const QString &txt, int pos, bool edited)
2989 Q_Q(QQuickTextInput);
2991 QString oldText = m_text;
2993 m_text = maskString(0, txt, true);
2994 m_text += clearString(m_text.length(), m_maxLength - m_text.length());
2996 m_text = txt.isEmpty() ? txt : txt.left(m_maxLength);
2999 m_modifiedState = m_undoState = 0;
3000 m_cursor = (pos < 0 || pos > m_text.length()) ? m_text.length() : pos;
3001 m_textDirty = (oldText != m_text);
3003 bool changed = finishChange(-1, true, edited);
3004 #ifdef QT_NO_ACCESSIBILITY
3008 QAccessible::updateAccessibility(q, 0, QAccessible::TextUpdated);
3016 Adds the given \a command to the undo history
3017 of the line control. Does not apply the command.
3019 void QQuickTextInputPrivate::addCommand(const Command &cmd)
3021 if (m_separator && m_undoState && m_history[m_undoState - 1].type != Separator) {
3022 m_history.resize(m_undoState + 2);
3023 m_history[m_undoState++] = Command(Separator, m_cursor, 0, m_selstart, m_selend);
3025 m_history.resize(m_undoState + 1);
3027 m_separator = false;
3028 m_history[m_undoState++] = cmd;
3034 Inserts the given string \a s into the line
3037 Also adds the appropriate commands into the undo history.
3038 This function does not call finishChange(), and may leave the text
3039 in an invalid state.
3041 void QQuickTextInputPrivate::internalInsert(const QString &s)
3043 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
3044 Q_Q(QQuickTextInput);
3045 if (m_echoMode == QQuickTextInput::Password)
3046 m_passwordEchoTimer.start(qt_passwordEchoDelay, q);
3048 if (hasSelectedText())
3049 addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
3051 QString ms = maskString(m_cursor, s);
3052 for (int i = 0; i < (int) ms.length(); ++i) {
3053 addCommand (Command(DeleteSelection, m_cursor + i, m_text.at(m_cursor + i), -1, -1));
3054 addCommand(Command(Insert, m_cursor + i, ms.at(i), -1, -1));
3056 m_text.replace(m_cursor, ms.length(), ms);
3057 m_cursor += ms.length();
3058 m_cursor = nextMaskBlank(m_cursor);
3061 int remaining = m_maxLength - m_text.length();
3062 if (remaining != 0) {
3063 m_text.insert(m_cursor, s.left(remaining));
3064 for (int i = 0; i < (int) s.left(remaining).length(); ++i)
3065 addCommand(Command(Insert, m_cursor++, s.at(i), -1, -1));
3074 deletes a single character from the current text. If \a wasBackspace,
3075 the character prior to the cursor is removed. Otherwise the character
3076 after the cursor is removed.
3078 Also adds the appropriate commands into the undo history.
3079 This function does not call finishChange(), and may leave the text
3080 in an invalid state.
3082 void QQuickTextInputPrivate::internalDelete(bool wasBackspace)
3084 if (m_cursor < (int) m_text.length()) {
3085 cancelPasswordEchoTimer();
3086 if (hasSelectedText())
3087 addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
3088 addCommand(Command((CommandType)((m_maskData ? 2 : 0) + (wasBackspace ? Remove : Delete)),
3089 m_cursor, m_text.at(m_cursor), -1, -1));
3091 m_text.replace(m_cursor, 1, clearString(m_cursor, 1));
3092 addCommand(Command(Insert, m_cursor, m_text.at(m_cursor), -1, -1));
3094 m_text.remove(m_cursor, 1);
3103 removes the currently selected text from the line control.
3105 Also adds the appropriate commands into the undo history.
3106 This function does not call finishChange(), and may leave the text
3107 in an invalid state.
3109 void QQuickTextInputPrivate::removeSelectedText()
3111 if (m_selstart < m_selend && m_selend <= (int) m_text.length()) {
3112 cancelPasswordEchoTimer();
3115 addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
3116 if (m_selstart <= m_cursor && m_cursor < m_selend) {
3117 // cursor is within the selection. Split up the commands
3118 // to be able to restore the correct cursor position
3119 for (i = m_cursor; i >= m_selstart; --i)
3120 addCommand (Command(DeleteSelection, i, m_text.at(i), -1, 1));
3121 for (i = m_selend - 1; i > m_cursor; --i)
3122 addCommand (Command(DeleteSelection, i - m_cursor + m_selstart - 1, m_text.at(i), -1, -1));
3124 for (i = m_selend-1; i >= m_selstart; --i)
3125 addCommand (Command(RemoveSelection, i, m_text.at(i), -1, -1));
3128 m_text.replace(m_selstart, m_selend - m_selstart, clearString(m_selstart, m_selend - m_selstart));
3129 for (int i = 0; i < m_selend - m_selstart; ++i)
3130 addCommand(Command(Insert, m_selstart + i, m_text.at(m_selstart + i), -1, -1));
3132 m_text.remove(m_selstart, m_selend - m_selstart);
3134 if (m_cursor > m_selstart)
3135 m_cursor -= qMin(m_cursor, m_selend) - m_selstart;
3144 Parses the input mask specified by \a maskFields to generate
3145 the mask data used to handle input masks.
3147 void QQuickTextInputPrivate::parseInputMask(const QString &maskFields)
3149 int delimiter = maskFields.indexOf(QLatin1Char(';'));
3150 if (maskFields.isEmpty() || delimiter == 0) {
3152 delete [] m_maskData;
3154 m_maxLength = 32767;
3155 internalSetText(QString());
3160 if (delimiter == -1) {
3161 m_blank = QLatin1Char(' ');
3162 m_inputMask = maskFields;
3164 m_inputMask = maskFields.left(delimiter);
3165 m_blank = (delimiter + 1 < maskFields.length()) ? maskFields[delimiter + 1] : QLatin1Char(' ');
3168 // calculate m_maxLength / m_maskData length
3171 for (int i=0; i<m_inputMask.length(); i++) {
3172 c = m_inputMask.at(i);
3173 if (i > 0 && m_inputMask.at(i-1) == QLatin1Char('\\')) {
3177 if (c != QLatin1Char('\\') && c != QLatin1Char('!') &&
3178 c != QLatin1Char('<') && c != QLatin1Char('>') &&
3179 c != QLatin1Char('{') && c != QLatin1Char('}') &&
3180 c != QLatin1Char('[') && c != QLatin1Char(']'))
3184 delete [] m_maskData;
3185 m_maskData = new MaskInputData[m_maxLength];
3187 MaskInputData::Casemode m = MaskInputData::NoCaseMode;
3190 bool escape = false;
3192 for (int i = 0; i < m_inputMask.length(); i++) {
3193 c = m_inputMask.at(i);
3196 m_maskData[index].maskChar = c;
3197 m_maskData[index].separator = s;
3198 m_maskData[index].caseMode = m;
3201 } else if (c == QLatin1Char('<')) {
3202 m = MaskInputData::Lower;
3203 } else if (c == QLatin1Char('>')) {
3204 m = MaskInputData::Upper;
3205 } else if (c == QLatin1Char('!')) {
3206 m = MaskInputData::NoCaseMode;
3207 } else if (c != QLatin1Char('{') && c != QLatin1Char('}') && c != QLatin1Char('[') && c != QLatin1Char(']')) {
3208 switch (c.unicode()) {
3234 m_maskData[index].maskChar = c;
3235 m_maskData[index].separator = s;
3236 m_maskData[index].caseMode = m;
3241 internalSetText(m_text);
3248 checks if the key is valid compared to the inputMask
3250 bool QQuickTextInputPrivate::isValidInput(QChar key, QChar mask) const
3252 switch (mask.unicode()) {
3258 if (key.isLetter() || key == m_blank)
3262 if (key.isLetterOrNumber())
3266 if (key.isLetterOrNumber() || key == m_blank)
3274 if (key.isPrint() || key == m_blank)
3282 if (key.isNumber() || key == m_blank)
3286 if (key.isNumber() && key.digitValue() > 0)
3290 if ((key.isNumber() && key.digitValue() > 0) || key == m_blank)
3294 if (key.isNumber() || key == QLatin1Char('+') || key == QLatin1Char('-') || key == m_blank)
3298 if (key == QLatin1Char('0') || key == QLatin1Char('1'))
3302 if (key == QLatin1Char('0') || key == QLatin1Char('1') || key == m_blank)
3306 if (key.isNumber() || (key >= QLatin1Char('a') && key <= QLatin1Char('f')) || (key >= QLatin1Char('A') && key <= QLatin1Char('F')))
3310 if (key.isNumber() || (key >= QLatin1Char('a') && key <= QLatin1Char('f')) || (key >= QLatin1Char('A') && key <= QLatin1Char('F')) || key == m_blank)
3322 Returns true if the given text \a str is valid for any
3323 validator or input mask set for the line control.
3325 Otherwise returns false
3327 bool QQuickTextInputPrivate::hasAcceptableInput(const QString &str) const
3329 #ifndef QT_NO_VALIDATOR
3330 QString textCopy = str;
3331 int cursorCopy = m_cursor;
3332 if (m_validator && m_validator->validate(textCopy, cursorCopy)
3333 != QValidator::Acceptable)
3340 if (str.length() != m_maxLength)
3343 for (int i=0; i < m_maxLength; ++i) {
3344 if (m_maskData[i].separator) {
3345 if (str.at(i) != m_maskData[i].maskChar)
3348 if (!isValidInput(str.at(i), m_maskData[i].maskChar))
3358 Applies the inputMask on \a str starting from position \a pos in the mask. \a clear
3359 specifies from where characters should be gotten when a separator is met in \a str - true means
3360 that blanks will be used, false that previous input is used.
3361 Calling this when no inputMask is set is undefined.
3363 QString QQuickTextInputPrivate::maskString(uint pos, const QString &str, bool clear) const
3365 if (pos >= (uint)m_maxLength)
3366 return QString::fromLatin1("");
3369 fill = clear ? clearString(0, m_maxLength) : m_text;
3372 QString s = QString::fromLatin1("");
3374 while (i < m_maxLength) {
3375 if (strIndex < str.length()) {
3376 if (m_maskData[i].separator) {
3377 s += m_maskData[i].maskChar;
3378 if (str[(int)strIndex] == m_maskData[i].maskChar)
3382 if (isValidInput(str[(int)strIndex], m_maskData[i].maskChar)) {
3383 switch (m_maskData[i].caseMode) {
3384 case MaskInputData::Upper:
3385 s += str[(int)strIndex].toUpper();
3387 case MaskInputData::Lower:
3388 s += str[(int)strIndex].toLower();
3391 s += str[(int)strIndex];
3395 // search for separator first
3396 int n = findInMask(i, true, true, str[(int)strIndex]);
3398 if (str.length() != 1 || i == 0 || (i > 0 && (!m_maskData[i-1].separator || m_maskData[i-1].maskChar != str[(int)strIndex]))) {
3399 s += fill.mid(i, n-i+1);
3400 i = n + 1; // update i to find + 1
3403 // search for valid m_blank if not
3404 n = findInMask(i, true, false, str[(int)strIndex]);
3406 s += fill.mid(i, n-i);
3407 switch (m_maskData[n].caseMode) {
3408 case MaskInputData::Upper:
3409 s += str[(int)strIndex].toUpper();
3411 case MaskInputData::Lower:
3412 s += str[(int)strIndex].toLower();
3415 s += str[(int)strIndex];
3417 i = n + 1; // updates i to find + 1
3435 Returns a "cleared" string with only separators and blank chars.
3436 Calling this when no inputMask is set is undefined.
3438 QString QQuickTextInputPrivate::clearString(uint pos, uint len) const
3440 if (pos >= (uint)m_maxLength)
3444 int end = qMin((uint)m_maxLength, pos + len);
3445 for (int i = pos; i < end; ++i)
3446 if (m_maskData[i].separator)
3447 s += m_maskData[i].maskChar;
3457 Strips blank parts of the input in a QQuickTextInputPrivate when an inputMask is set,
3458 separators are still included. Typically "127.0__.0__.1__" becomes "127.0.0.1".
3460 QString QQuickTextInputPrivate::stripString(const QString &str) const
3466 int end = qMin(m_maxLength, (int)str.length());
3467 for (int i = 0; i < end; ++i) {
3468 if (m_maskData[i].separator)
3469 s += m_maskData[i].maskChar;
3470 else if (str[i] != m_blank)
3479 searches forward/backward in m_maskData for either a separator or a m_blank
3481 int QQuickTextInputPrivate::findInMask(int pos, bool forward, bool findSeparator, QChar searchChar) const
3483 if (pos >= m_maxLength || pos < 0)
3486 int end = forward ? m_maxLength : -1;
3487 int step = forward ? 1 : -1;
3491 if (findSeparator) {
3492 if (m_maskData[i].separator && m_maskData[i].maskChar == searchChar)
3495 if (!m_maskData[i].separator) {
3496 if (searchChar.isNull())
3498 else if (isValidInput(searchChar, m_maskData[i].maskChar))
3507 void QQuickTextInputPrivate::internalUndo(int until)
3509 if (!isUndoAvailable())
3511 cancelPasswordEchoTimer();
3513 while (m_undoState && m_undoState > until) {
3514 Command& cmd = m_history[--m_undoState];
3517 m_text.remove(cmd.pos, 1);
3521 m_selstart = cmd.selStart;
3522 m_selend = cmd.selEnd;
3526 case RemoveSelection:
3527 m_text.insert(cmd.pos, cmd.uc);
3528 m_cursor = cmd.pos + 1;
3531 case DeleteSelection:
3532 m_text.insert(cmd.pos, cmd.uc);
3538 if (until < 0 && m_undoState) {
3539 Command& next = m_history[m_undoState-1];
3540 if (next.type != cmd.type && next.type < RemoveSelection
3541 && (cmd.type < RemoveSelection || next.type == Separator))
3546 emitCursorPositionChanged();
3549 void QQuickTextInputPrivate::internalRedo()
3551 if (!isRedoAvailable())
3554 while (m_undoState < (int)m_history.size()) {
3555 Command& cmd = m_history[m_undoState++];
3558 m_text.insert(cmd.pos, cmd.uc);
3559 m_cursor = cmd.pos + 1;
3562 m_selstart = cmd.selStart;
3563 m_selend = cmd.selEnd;
3568 case RemoveSelection:
3569 case DeleteSelection:
3570 m_text.remove(cmd.pos, 1);
3571 m_selstart = cmd.selStart;
3572 m_selend = cmd.selEnd;
3576 m_selstart = cmd.selStart;
3577 m_selend = cmd.selEnd;
3581 if (m_undoState < (int)m_history.size()) {
3582 Command& next = m_history[m_undoState];
3583 if (next.type != cmd.type && cmd.type < RemoveSelection && next.type != Separator
3584 && (next.type < RemoveSelection || cmd.type == Separator))
3589 emitCursorPositionChanged();
3595 If the current cursor position differs from the last emitted cursor
3596 position, emits cursorPositionChanged().
3598 void QQuickTextInputPrivate::emitCursorPositionChanged()
3600 Q_Q(QQuickTextInput);
3601 if (m_cursor != m_lastCursorPos) {
3602 m_lastCursorPos = m_cursor;
3604 q->updateCursorRectangle();
3605 emit q->cursorPositionChanged();
3606 // XXX todo - not in 4.8?
3608 resetCursorBlinkTimer();
3611 if (!hasSelectedText()) {
3612 if (lastSelectionStart != m_cursor) {
3613 lastSelectionStart = m_cursor;
3614 emit q->selectionStartChanged();
3616 if (lastSelectionEnd != m_cursor) {
3617 lastSelectionEnd = m_cursor;
3618 emit q->selectionEndChanged();
3622 #ifndef QT_NO_ACCESSIBILITY
3623 QAccessible::updateAccessibility(q, 0, QAccessible::TextCaretMoved);
3629 void QQuickTextInputPrivate::setCursorBlinkPeriod(int msec)
3631 Q_Q(QQuickTextInput);
3632 if (msec == m_blinkPeriod)
3635 q->killTimer(m_blinkTimer);
3638 m_blinkTimer = q->startTimer(msec / 2);
3642 if (m_blinkStatus == 1)
3645 m_blinkPeriod = msec;
3648 void QQuickTextInputPrivate::resetCursorBlinkTimer()
3650 Q_Q(QQuickTextInput);
3651 if (m_blinkPeriod == 0 || m_blinkTimer == 0)
3653 q->killTimer(m_blinkTimer);
3654 m_blinkTimer = q->startTimer(m_blinkPeriod / 2);
3658 void QQuickTextInput::timerEvent(QTimerEvent *event)
3660 Q_D(QQuickTextInput);
3661 if (event->timerId() == d->m_blinkTimer) {
3662 d->m_blinkStatus = !d->m_blinkStatus;
3664 } else if (event->timerId() == d->m_deleteAllTimer) {
3665 killTimer(d->m_deleteAllTimer);
3666 d->m_deleteAllTimer = 0;
3668 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
3669 } else if (event->timerId() == d->m_passwordEchoTimer.timerId()) {
3670 d->m_passwordEchoTimer.stop();
3671 d->updateDisplayText();
3676 void QQuickTextInputPrivate::processKeyEvent(QKeyEvent* event)
3678 Q_Q(QQuickTextInput);
3679 bool inlineCompletionAccepted = false;
3681 if (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return) {
3682 if (hasAcceptableInput(m_text) || fixup()) {
3685 if (inlineCompletionAccepted)
3692 if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit
3693 && !m_passwordEchoEditing
3695 && !event->text().isEmpty()
3696 && !(event->modifiers() & Qt::ControlModifier)) {
3697 // Clear the edit and reset to normal echo mode while editing; the
3698 // echo mode switches back when the edit loses focus
3699 // ### resets current content. dubious code; you can
3700 // navigate with keys up, down, back, and select(?), but if you press
3701 // "left" or "right" it clears?
3702 updatePasswordEchoEditing(true);
3706 bool unknown = false;
3707 bool visual = cursorMoveStyle() == Qt::VisualMoveStyle;
3711 #ifndef QT_NO_SHORTCUT
3712 else if (event == QKeySequence::Undo) {
3716 else if (event == QKeySequence::Redo) {
3720 else if (event == QKeySequence::SelectAll) {
3723 #ifndef QT_NO_CLIPBOARD
3724 else if (event == QKeySequence::Copy) {
3727 else if (event == QKeySequence::Paste) {
3729 QClipboard::Mode mode = QClipboard::Clipboard;
3733 else if (event == QKeySequence::Cut) {
3739 else if (event == QKeySequence::DeleteEndOfLine) {
3741 setSelection(m_cursor, end());
3746 #endif //QT_NO_CLIPBOARD
3747 else if (event == QKeySequence::MoveToStartOfLine || event == QKeySequence::MoveToStartOfBlock) {
3750 else if (event == QKeySequence::MoveToEndOfLine || event == QKeySequence::MoveToEndOfBlock) {
3753 else if (event == QKeySequence::SelectStartOfLine || event == QKeySequence::SelectStartOfBlock) {
3756 else if (event == QKeySequence::SelectEndOfLine || event == QKeySequence::SelectEndOfBlock) {
3759 else if (event == QKeySequence::MoveToNextChar) {
3760 if (hasSelectedText()) {
3761 moveCursor(selectionEnd(), false);
3763 cursorForward(0, visual ? 1 : (layoutDirection() == Qt::LeftToRight ? 1 : -1));
3766 else if (event == QKeySequence::SelectNextChar) {
3767 cursorForward(1, visual ? 1 : (layoutDirection() == Qt::LeftToRight ? 1 : -1));
3769 else if (event == QKeySequence::MoveToPreviousChar) {
3770 if (hasSelectedText()) {
3771 moveCursor(selectionStart(), false);
3773 cursorForward(0, visual ? -1 : (layoutDirection() == Qt::LeftToRight ? -1 : 1));
3776 else if (event == QKeySequence::SelectPreviousChar) {
3777 cursorForward(1, visual ? -1 : (layoutDirection() == Qt::LeftToRight ? -1 : 1));
3779 else if (event == QKeySequence::MoveToNextWord) {
3780 if (m_echoMode == QQuickTextInput::Normal)
3781 layoutDirection() == Qt::LeftToRight ? cursorWordForward(0) : cursorWordBackward(0);
3783 layoutDirection() == Qt::LeftToRight ? end(0) : home(0);
3785 else if (event == QKeySequence::MoveToPreviousWord) {
3786 if (m_echoMode == QQuickTextInput::Normal)
3787 layoutDirection() == Qt::LeftToRight ? cursorWordBackward(0) : cursorWordForward(0);
3788 else if (!m_readOnly) {
3789 layoutDirection() == Qt::LeftToRight ? home(0) : end(0);
3792 else if (event == QKeySequence::SelectNextWord) {
3793 if (m_echoMode == QQuickTextInput::Normal)
3794 layoutDirection() == Qt::LeftToRight ? cursorWordForward(1) : cursorWordBackward(1);
3796 layoutDirection() == Qt::LeftToRight ? end(1) : home(1);
3798 else if (event == QKeySequence::SelectPreviousWord) {
3799 if (m_echoMode == QQuickTextInput::Normal)
3800 layoutDirection() == Qt::LeftToRight ? cursorWordBackward(1) : cursorWordForward(1);
3802 layoutDirection() == Qt::LeftToRight ? home(1) : end(1);
3804 else if (event == QKeySequence::Delete) {
3808 else if (event == QKeySequence::DeleteEndOfWord) {
3810 cursorWordForward(true);
3814 else if (event == QKeySequence::DeleteStartOfWord) {
3816 cursorWordBackward(true);
3820 #endif // QT_NO_SHORTCUT
3822 bool handled = false;
3823 if (event->modifiers() & Qt::ControlModifier) {
3824 switch (event->key()) {
3825 case Qt::Key_Backspace:
3827 cursorWordBackward(true);
3835 } else { // ### check for *no* modifier
3836 switch (event->key()) {
3837 case Qt::Key_Backspace:
3849 if (event->key() == Qt::Key_Direction_L || event->key() == Qt::Key_Direction_R) {
3850 setLayoutDirection((event->key() == Qt::Key_Direction_L) ? Qt::LeftToRight : Qt::RightToLeft);
3854 if (unknown && !m_readOnly) {
3855 QString t = event->text();
3856 if (!t.isEmpty() && t.at(0).isPrint()) {