1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the QtQml module of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #include "qquicktextinput_p.h"
43 #include "qquicktextinput_p_p.h"
44 #include "qquickcanvas.h"
46 #include <private/qqmlglobal_p.h>
48 #include <QtQml/qqmlinfo.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/qinputmethod.h>
57 #ifndef QT_NO_ACCESSIBILITY
58 #include "qaccessible.h"
63 DEFINE_BOOL_CONFIG_OPTION(qmlDisableDistanceField, QML_DISABLE_DISTANCEFIELD)
65 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
66 static const int qt_passwordEchoDelay = QT_GUI_PASSWORD_ECHO_DELAY;
70 \qmlclass TextInput QQuickTextInput
71 \inqmlmodule QtQuick 2
72 \ingroup qml-basic-visual-elements
73 \brief The TextInput item displays an editable line of text.
76 The TextInput element displays a single line of editable plain text.
78 TextInput is used to accept a line of text input. Input constraints
79 can be placed on a TextInput item (for example, through a \l validator or \l inputMask),
80 and setting \l echoMode to an appropriate value enables TextInput to be used for
81 a password input field.
83 On Mac OS X, the Up/Down key bindings for Home/End are explicitly disabled.
84 If you want such bindings (on any platform), you will need to construct them in QML.
86 \sa TextEdit, Text, {declarative/text/textselection}{Text Selection example}
88 QQuickTextInput::QQuickTextInput(QQuickItem* parent)
89 : QQuickImplicitSizeItem(*(new QQuickTextInputPrivate), parent)
95 QQuickTextInput::~QQuickTextInput()
99 void QQuickTextInput::componentComplete()
101 Q_D(QQuickTextInput);
103 QQuickImplicitSizeItem::componentComplete();
107 updateCursorRectangle();
108 if (d->cursorComponent && d->cursorComponent->isReady())
113 \qmlproperty string QtQuick2::TextInput::text
115 The text in the TextInput.
117 QString QQuickTextInput::text() const
119 Q_D(const QQuickTextInput);
121 QString content = d->m_text;
122 QString res = d->m_maskData ? d->stripString(content) : content;
123 return (res.isNull() ? QString::fromLatin1("") : res);
126 void QQuickTextInput::setText(const QString &s)
128 Q_D(QQuickTextInput);
131 if (d->composeMode())
132 qApp->inputMethod()->reset();
133 d->internalSetText(s, -1, false);
137 \qmlproperty int QtQuick2::TextInput::length
139 Returns the total number of characters in the TextInput item.
141 If the TextInput has an inputMask the length will include mask characters and may differ
142 from the length of the string returned by the \l text property.
144 This property can be faster than querying the length the \l text property as it doesn't
145 require any copying or conversion of the TextInput's internal string data.
148 int QQuickTextInput::length() const
150 Q_D(const QQuickTextInput);
151 return d->m_text.length();
155 \qmlmethod string QtQuick2::TextInput::getText(int start, int end)
157 Returns the section of text that is between the \a start and \a end positions.
159 If the TextInput has an inputMask the length will include mask characters.
162 QString QQuickTextInput::getText(int start, int end) const
164 Q_D(const QQuickTextInput);
169 return d->m_text.mid(start, end - start);
172 QString QQuickTextInputPrivate::realText() const
174 QString res = m_maskData ? stripString(m_text) : m_text;
175 return (res.isNull() ? QString::fromLatin1("") : res);
179 \qmlproperty string QtQuick2::TextInput::font.family
181 Sets the family name of the font.
183 The family name is case insensitive and may optionally include a foundry name, e.g. "Helvetica [Cronyx]".
184 If the family is available from more than one foundry and the foundry isn't specified, an arbitrary foundry is chosen.
185 If the family isn't available a family will be set using the font matching algorithm.
189 \qmlproperty bool QtQuick2::TextInput::font.bold
191 Sets whether the font weight is bold.
195 \qmlproperty enumeration QtQuick2::TextInput::font.weight
197 Sets the font's weight.
199 The weight can be one of:
202 \li Font.Normal - the default
209 TextInput { text: "Hello"; font.weight: Font.DemiBold }
214 \qmlproperty bool QtQuick2::TextInput::font.italic
216 Sets whether the font has an italic style.
220 \qmlproperty bool QtQuick2::TextInput::font.underline
222 Sets whether the text is underlined.
226 \qmlproperty bool QtQuick2::TextInput::font.strikeout
228 Sets whether the font has a strikeout style.
232 \qmlproperty real QtQuick2::TextInput::font.pointSize
234 Sets the font size in points. The point size must be greater than zero.
238 \qmlproperty int QtQuick2::TextInput::font.pixelSize
240 Sets the font size in pixels.
242 Using this function makes the font device dependent.
243 Use \c pointSize to set the size of the font in a device independent manner.
247 \qmlproperty real QtQuick2::TextInput::font.letterSpacing
249 Sets the letter spacing for the font.
251 Letter spacing changes the default spacing between individual letters in the font.
252 A positive value increases the letter spacing by the corresponding pixels; a negative value decreases the spacing.
256 \qmlproperty real QtQuick2::TextInput::font.wordSpacing
258 Sets the word spacing for the font.
260 Word spacing changes the default spacing between individual words.
261 A positive value increases the word spacing by a corresponding amount of pixels,
262 while a negative value decreases the inter-word spacing accordingly.
266 \qmlproperty enumeration QtQuick2::TextInput::font.capitalization
268 Sets the capitalization for the text.
271 \li Font.MixedCase - This is the normal text rendering option where no capitalization change is applied.
272 \li Font.AllUppercase - This alters the text to be rendered in all uppercase type.
273 \li Font.AllLowercase - This alters the text to be rendered in all lowercase type.
274 \li Font.SmallCaps - This alters the text to be rendered in small-caps type.
275 \li Font.Capitalize - This alters the text to be rendered with the first character of each word as an uppercase character.
279 TextInput { text: "Hello"; font.capitalization: Font.AllLowercase }
283 QFont QQuickTextInput::font() const
285 Q_D(const QQuickTextInput);
286 return d->sourceFont;
289 void QQuickTextInput::setFont(const QFont &font)
291 Q_D(QQuickTextInput);
292 if (d->sourceFont == font)
295 d->sourceFont = font;
296 QFont oldFont = d->font;
298 if (d->font.pointSizeF() != -1) {
300 qreal size = qRound(d->font.pointSizeF()*2.0);
301 d->font.setPointSizeF(size/2.0);
303 if (oldFont != d->font) {
305 updateCursorRectangle();
306 updateInputMethod(Qt::ImCursorRectangle | Qt::ImFont);
308 emit fontChanged(d->sourceFont);
312 \qmlproperty color QtQuick2::TextInput::color
316 QColor QQuickTextInput::color() const
318 Q_D(const QQuickTextInput);
322 void QQuickTextInput::setColor(const QColor &c)
324 Q_D(QQuickTextInput);
327 d->textLayoutDirty = true;
328 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
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 if (d->hasSelectedText()) {
354 d->textLayoutDirty = true;
355 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
358 emit selectionColorChanged();
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 if (d->hasSelectedText()) {
379 d->textLayoutDirty = true;
380 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
383 emit selectedTextColorChanged();
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 TextInput.AlignTop (default),
406 \c TextInput.AlignBottom \c TextInput.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() ? qApp->inputMethod()->inputDirection() == Qt::RightToLeft
481 : text.isRightToLeft();
482 return setHAlign(isRightToLeft ? QQuickTextInput::AlignRight : QQuickTextInput::AlignLeft);
487 QQuickTextInput::VAlignment QQuickTextInput::vAlign() const
489 Q_D(const QQuickTextInput);
493 void QQuickTextInput::setVAlign(QQuickTextInput::VAlignment alignment)
495 Q_D(QQuickTextInput);
496 if (alignment == d->vAlign)
498 d->vAlign = alignment;
499 emit verticalAlignmentChanged(d->vAlign);
500 if (isComponentComplete()) {
501 updateCursorRectangle();
506 \qmlproperty enumeration QtQuick2::TextInput::wrapMode
508 Set this property to wrap the text to the TextInput item's width.
509 The text will only wrap if an explicit width has been set.
512 \li TextInput.NoWrap - no wrapping will be performed. If the text contains insufficient newlines, then implicitWidth will exceed a set width.
513 \li TextInput.WordWrap - wrapping is done on word boundaries only. If a word is too long, implicitWidth will exceed a set width.
514 \li TextInput.WrapAnywhere - wrapping is done at any point on a line, even if it occurs in the middle of a word.
515 \li TextInput.Wrap - if possible, wrapping occurs at a word boundary; otherwise it will occur at the appropriate point on the line, even in the middle of a word.
518 The default is TextInput.NoWrap. If you set a width, consider using TextInput.Wrap.
520 QQuickTextInput::WrapMode QQuickTextInput::wrapMode() const
522 Q_D(const QQuickTextInput);
526 void QQuickTextInput::setWrapMode(WrapMode mode)
528 Q_D(QQuickTextInput);
529 if (mode == d->wrapMode)
533 updateCursorRectangle();
534 emit wrapModeChanged();
537 void QQuickTextInputPrivate::mirrorChange()
539 Q_Q(QQuickTextInput);
540 if (q->isComponentComplete()) {
541 if (!hAlignImplicit && (hAlign == QQuickTextInput::AlignRight || hAlign == QQuickTextInput::AlignLeft)) {
542 q->updateCursorRectangle();
543 emit q->effectiveHorizontalAlignmentChanged();
549 \qmlproperty bool QtQuick2::TextInput::readOnly
551 Sets whether user input can modify the contents of the TextInput.
553 If readOnly is set to true, then user input will not affect the text
554 property. Any bindings or attempts to set the text property will still
557 bool QQuickTextInput::isReadOnly() const
559 Q_D(const QQuickTextInput);
560 return d->m_readOnly;
563 void QQuickTextInput::setReadOnly(bool ro)
565 Q_D(QQuickTextInput);
566 if (d->m_readOnly == ro)
569 setFlag(QQuickItem::ItemAcceptsInputMethod, !ro);
572 d->setCursorPosition(d->end());
573 updateInputMethod(Qt::ImEnabled);
575 d->emitUndoRedoChanged();
576 emit readOnlyChanged(ro);
580 \qmlproperty int QtQuick2::TextInput::maximumLength
581 The maximum permitted length of the text in the TextInput.
583 If the text is too long, it is truncated at the limit.
585 By default, this property contains a value of 32767.
587 int QQuickTextInput::maxLength() const
589 Q_D(const QQuickTextInput);
590 return d->m_maxLength;
593 void QQuickTextInput::setMaxLength(int ml)
595 Q_D(QQuickTextInput);
596 if (d->m_maxLength == ml || d->m_maskData)
600 d->internalSetText(d->m_text, -1, false);
602 emit maximumLengthChanged(ml);
606 \qmlproperty bool QtQuick2::TextInput::cursorVisible
607 Set to true when the TextInput shows a cursor.
609 This property is set and unset when the TextInput gets active focus, so that other
610 properties can be bound to whether the cursor is currently showing. As it
611 gets set and unset automatically, when you set the value yourself you must
612 keep in mind that your value may be overwritten.
614 It can be set directly in script, for example if a KeyProxy might
615 forward keys to it and you desire it to look active when this happens
616 (but without actually giving it active focus).
618 It should not be set directly on the element, like in the below QML,
619 as the specified value will be overridden an lost on focus changes.
628 In the above snippet the cursor will still become visible when the
629 TextInput gains active focus.
631 bool QQuickTextInput::isCursorVisible() const
633 Q_D(const QQuickTextInput);
634 return d->cursorVisible;
637 void QQuickTextInput::setCursorVisible(bool on)
639 Q_D(QQuickTextInput);
640 if (d->cursorVisible == on)
642 d->cursorVisible = on;
643 d->setCursorBlinkPeriod(on ? qApp->styleHints()->cursorFlashTime() : 0);
644 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
646 emit cursorVisibleChanged(d->cursorVisible);
650 \qmlproperty int QtQuick2::TextInput::cursorPosition
651 The position of the cursor in the TextInput.
653 int QQuickTextInput::cursorPosition() const
655 Q_D(const QQuickTextInput);
659 void QQuickTextInput::setCursorPosition(int cp)
661 Q_D(QQuickTextInput);
662 if (cp < 0 || cp > text().length())
668 \qmlproperty rectangle QtQuick2::TextInput::cursorRectangle
670 The rectangle where the standard text cursor is rendered within the text input. Read only.
672 The position and height of a custom cursorDelegate are updated to follow the cursorRectangle
673 automatically when it changes. The width of the delegate is unaffected by changes in the
677 QRectF QQuickTextInput::cursorRectangle() const
679 Q_D(const QQuickTextInput);
682 if (d->m_preeditCursor != -1)
683 c += d->m_preeditCursor;
684 if (d->m_echoMode == NoEcho)
686 QTextLine l = d->m_textLayout.lineForTextPosition(c);
689 return QRectF(l.cursorToX(c) - d->hscroll, l.y() - d->vscroll, 1, l.height());
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 If no \l locale is set IntValidator uses the \l {QLocale::setDefault()}{default locale} to
819 interpret the number and will accept locale specific digits, group separators, and positive
820 and negative signs. In addition, IntValidator is always guaranteed to accept a number
821 formatted according to the "C" locale.
825 QQuickIntValidator::QQuickIntValidator(QObject *parent)
826 : QIntValidator(parent)
831 \qmlproperty string QtQuick2::IntValidator::locale
833 This property holds the name of the locale used to interpret the number.
838 QString QQuickIntValidator::localeName() const
840 return locale().name();
843 void QQuickIntValidator::setLocaleName(const QString &name)
845 if (locale().name() != name) {
846 setLocale(QLocale(name));
847 emit localeNameChanged();
851 void QQuickIntValidator::resetLocaleName()
853 QLocale defaultLocale;
854 if (locale() != defaultLocale) {
855 setLocale(defaultLocale);
856 emit localeNameChanged();
861 \qmlproperty int QtQuick2::IntValidator::top
863 This property holds the validator's highest acceptable value.
864 By default, this property's value is derived from the highest signed integer available (typically 2147483647).
867 \qmlproperty int QtQuick2::IntValidator::bottom
869 This property holds the validator's lowest acceptable value.
870 By default, this property's value is derived from the lowest signed integer available (typically -2147483647).
874 \qmlclass DoubleValidator QDoubleValidator
875 \inqmlmodule QtQuick 2
876 \ingroup qml-basic-visual-elements
878 This element provides a validator for non-integer numbers.
880 Input is accepted if it contains a double that is within the valid range
881 and is in the correct format.
883 Input is accepected but invalid if it contains a double that is outside
884 the range or is in the wrong format; e.g. with too many digits after the
885 decimal point or is empty.
887 Input is rejected if it is not a double.
889 Note: If the valid range consists of just positive doubles (e.g. 0.0 to
890 100.0) and input is a negative double then it is rejected. If \l notation
891 is set to DoubleValidator.StandardNotation, and the input contains more
892 digits before the decimal point than a double in the valid range may have,
893 it is also rejected. If \l notation is DoubleValidator.ScientificNotation,
894 and the input is not in the valid range, it is accecpted but invalid. The
895 value may yet become valid by changing the exponent.
898 QQuickDoubleValidator::QQuickDoubleValidator(QObject *parent)
899 : QDoubleValidator(parent)
904 \qmlproperty string QtQuick2::DoubleValidator::locale
906 This property holds the name of the locale used to interpret the number.
911 QString QQuickDoubleValidator::localeName() const
913 return locale().name();
916 void QQuickDoubleValidator::setLocaleName(const QString &name)
918 if (locale().name() != name) {
919 setLocale(QLocale(name));
920 emit localeNameChanged();
924 void QQuickDoubleValidator::resetLocaleName()
926 QLocale defaultLocale;
927 if (locale() != defaultLocale) {
928 setLocale(defaultLocale);
929 emit localeNameChanged();
934 \qmlproperty real QtQuick2::DoubleValidator::top
936 This property holds the validator's maximum acceptable value.
937 By default, this property contains a value of infinity.
940 \qmlproperty real QtQuick2::DoubleValidator::bottom
942 This property holds the validator's minimum acceptable value.
943 By default, this property contains a value of -infinity.
946 \qmlproperty int QtQuick2::DoubleValidator::decimals
948 This property holds the validator's maximum number of digits after the decimal point.
949 By default, this property contains a value of 1000.
952 \qmlproperty enumeration QtQuick2::DoubleValidator::notation
953 This property holds the notation of how a string can describe a number.
955 The possible values for this property are:
958 \li DoubleValidator.StandardNotation
959 \li DoubleValidator.ScientificNotation (default)
962 If this property is set to DoubleValidator.ScientificNotation, the written number may have an exponent part (e.g. 1.5E-2).
966 \qmlclass RegExpValidator QRegExpValidator
967 \inqmlmodule QtQuick 2
968 \ingroup qml-basic-visual-elements
970 This element provides a validator, which counts as valid any string which
971 matches a specified regular expression.
974 \qmlproperty regExp QtQuick2::RegExpValidator::regExp
976 This property holds the regular expression used for validation.
978 Note that this property should be a regular expression in JS syntax, e.g /a/ for the regular expression
981 By default, this property contains a regular expression with the pattern .* that matches any string.
985 \qmlproperty Validator QtQuick2::TextInput::validator
987 Allows you to set a validator on the TextInput. When a validator is set
988 the TextInput will only accept input which leaves the text property in
989 an acceptable or intermediate state. The accepted signal will only be sent
990 if the text is in an acceptable state when enter is pressed.
992 Currently supported validators are IntValidator, DoubleValidator and
993 RegExpValidator. An example of using validators is shown below, which allows
994 input of integers between 11 and 31 into the text input:
999 validator: IntValidator{bottom: 11; top: 31;}
1004 \sa acceptableInput, inputMask
1007 QValidator* QQuickTextInput::validator() const
1009 Q_D(const QQuickTextInput);
1010 return d->m_validator;
1013 void QQuickTextInput::setValidator(QValidator* v)
1015 Q_D(QQuickTextInput);
1016 if (d->m_validator == v)
1021 if (isComponentComplete())
1024 emit validatorChanged();
1027 #endif // QT_NO_VALIDATOR
1029 void QQuickTextInputPrivate::checkIsValid()
1031 Q_Q(QQuickTextInput);
1033 ValidatorState state = hasAcceptableInput(m_text);
1034 m_validInput = state != InvalidInput;
1035 if (state != AcceptableInput) {
1036 if (m_acceptableInput) {
1037 m_acceptableInput = false;
1038 emit q->acceptableInputChanged();
1040 } else if (!m_acceptableInput) {
1041 m_acceptableInput = true;
1042 emit q->acceptableInputChanged();
1047 \qmlproperty string QtQuick2::TextInput::inputMask
1049 Allows you to set an input mask on the TextInput, restricting the allowable
1050 text inputs. See QLineEdit::inputMask for further details, as the exact
1051 same mask strings are used by TextInput.
1053 \sa acceptableInput, validator
1055 QString QQuickTextInput::inputMask() const
1057 Q_D(const QQuickTextInput);
1058 return d->inputMask();
1061 void QQuickTextInput::setInputMask(const QString &im)
1063 Q_D(QQuickTextInput);
1064 if (d->inputMask() == im)
1067 d->setInputMask(im);
1068 emit inputMaskChanged(d->inputMask());
1072 \qmlproperty bool QtQuick2::TextInput::acceptableInput
1074 This property is always true unless a validator or input mask has been set.
1075 If a validator or input mask has been set, this property will only be true
1076 if the current text is acceptable to the validator or input mask as a final
1077 string (not as an intermediate string).
1079 bool QQuickTextInput::hasAcceptableInput() const
1081 Q_D(const QQuickTextInput);
1082 return d->hasAcceptableInput(d->m_text) == QQuickTextInputPrivate::AcceptableInput;
1086 \qmlsignal QtQuick2::TextInput::onAccepted()
1088 This handler is called when the Return or Enter key is pressed.
1089 Note that if there is a \l validator or \l inputMask set on the text
1090 input, the handler will only be emitted if the input is in an acceptable
1094 Qt::InputMethodHints QQuickTextInputPrivate::effectiveInputMethodHints() const
1096 Qt::InputMethodHints hints = inputMethodHints;
1097 if (m_echoMode == QQuickTextInput::Password || m_echoMode == QQuickTextInput::NoEcho)
1098 hints |= Qt::ImhHiddenText;
1099 else if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit)
1100 hints &= ~Qt::ImhHiddenText;
1101 if (m_echoMode != QQuickTextInput::Normal)
1102 hints |= (Qt::ImhNoAutoUppercase | Qt::ImhNoPredictiveText | Qt::ImhSensitiveData);
1106 \qmlproperty enumeration QtQuick2::TextInput::echoMode
1108 Specifies how the text should be displayed in the TextInput.
1110 \li TextInput.Normal - Displays the text as it is. (Default)
1111 \li TextInput.Password - Displays asterisks instead of characters.
1112 \li TextInput.NoEcho - Displays nothing.
1113 \li TextInput.PasswordEchoOnEdit - Displays characters as they are entered
1114 while editing, otherwise displays asterisks.
1117 QQuickTextInput::EchoMode QQuickTextInput::echoMode() const
1119 Q_D(const QQuickTextInput);
1120 return QQuickTextInput::EchoMode(d->m_echoMode);
1123 void QQuickTextInput::setEchoMode(QQuickTextInput::EchoMode echo)
1125 Q_D(QQuickTextInput);
1126 if (echoMode() == echo)
1128 d->cancelPasswordEchoTimer();
1129 d->m_echoMode = echo;
1130 d->m_passwordEchoEditing = false;
1131 updateInputMethod(Qt::ImHints);
1132 d->updateDisplayText();
1133 updateCursorRectangle();
1135 emit echoModeChanged(echoMode());
1139 \qmlproperty enumeration QtQuick2::TextInput::inputMethodHints
1141 Provides hints to the input method about the expected content of the text input and how it
1144 The value is a bit-wise combination of flags, or Qt.ImhNone if no hints are set.
1146 Flags that alter behaviour are:
1149 \li Qt.ImhHiddenText - Characters should be hidden, as is typically used when entering passwords.
1150 This is automatically set when setting echoMode to \c TextInput.Password.
1151 \li Qt.ImhSensitiveData - Typed text should not be stored by the active input method
1152 in any persistent storage like predictive user dictionary.
1153 \li Qt.ImhNoAutoUppercase - The input method should not try to automatically switch to upper case
1154 when a sentence ends.
1155 \li Qt.ImhPreferNumbers - Numbers are preferred (but not required).
1156 \li Qt.ImhPreferUppercase - Upper case letters are preferred (but not required).
1157 \li Qt.ImhPreferLowercase - Lower case letters are preferred (but not required).
1158 \li Qt.ImhNoPredictiveText - Do not use predictive text (i.e. dictionary lookup) while typing.
1160 \li Qt.ImhDate - The text editor functions as a date field.
1161 \li Qt.ImhTime - The text editor functions as a time field.
1164 Flags that restrict input (exclusive flags) are:
1167 \li Qt.ImhDigitsOnly - Only digits are allowed.
1168 \li Qt.ImhFormattedNumbersOnly - Only number input is allowed. This includes decimal point and minus sign.
1169 \li Qt.ImhUppercaseOnly - Only upper case letter input is allowed.
1170 \li Qt.ImhLowercaseOnly - Only lower case letter input is allowed.
1171 \li Qt.ImhDialableCharactersOnly - Only characters suitable for phone dialing are allowed.
1172 \li Qt.ImhEmailCharactersOnly - Only characters suitable for email addresses are allowed.
1173 \li Qt.ImhUrlCharactersOnly - Only characters suitable for URLs are allowed.
1179 \li Qt.ImhExclusiveInputMask - This mask yields nonzero if any of the exclusive flags are used.
1183 Qt::InputMethodHints QQuickTextInput::inputMethodHints() const
1185 Q_D(const QQuickTextInput);
1186 return d->inputMethodHints;
1189 void QQuickTextInput::setInputMethodHints(Qt::InputMethodHints hints)
1191 Q_D(QQuickTextInput);
1193 if (hints == d->inputMethodHints)
1196 d->inputMethodHints = hints;
1197 updateInputMethod(Qt::ImHints);
1198 emit inputMethodHintsChanged();
1202 \qmlproperty Component QtQuick2::TextInput::cursorDelegate
1203 The delegate for the cursor in the TextInput.
1205 If you set a cursorDelegate for a TextInput, this delegate will be used for
1206 drawing the cursor instead of the standard cursor. An instance of the
1207 delegate will be created and managed by the TextInput when a cursor is
1208 needed, and the x property of delegate instance will be set so as
1209 to be one pixel before the top left of the current character.
1211 Note that the root item of the delegate component must be a QQuickItem or
1212 QQuickItem derived item.
1214 QQmlComponent* QQuickTextInput::cursorDelegate() const
1216 Q_D(const QQuickTextInput);
1217 return d->cursorComponent;
1220 void QQuickTextInput::setCursorDelegate(QQmlComponent* c)
1222 Q_D(QQuickTextInput);
1223 if (d->cursorComponent == c)
1226 d->cursorComponent = c;
1228 //note that the components are owned by something else
1229 delete d->cursorItem;
1232 d->startCreatingCursor();
1235 emit cursorDelegateChanged();
1238 void QQuickTextInputPrivate::startCreatingCursor()
1240 Q_Q(QQuickTextInput);
1241 if (cursorComponent->isReady()) {
1243 } else if (cursorComponent->isLoading()) {
1244 q->connect(cursorComponent, SIGNAL(statusChanged(int)),
1245 q, SLOT(createCursor()));
1247 qmlInfo(q, cursorComponent->errors()) << QQuickTextInput::tr("Could not load cursor delegate");
1251 void QQuickTextInput::createCursor()
1253 Q_D(QQuickTextInput);
1254 if (!isComponentComplete())
1257 if (d->cursorComponent->isError()) {
1258 qmlInfo(this, d->cursorComponent->errors()) << tr("Could not load cursor delegate");
1262 if (!d->cursorComponent->isReady())
1266 delete d->cursorItem;
1267 QQmlContext *creationContext = d->cursorComponent->creationContext();
1268 QObject *object = d->cursorComponent->create(creationContext ? creationContext : qmlContext(this));
1269 d->cursorItem = qobject_cast<QQuickItem*>(object);
1270 if (!d->cursorItem) {
1272 qmlInfo(this, d->cursorComponent->errors()) << tr("Could not instantiate cursor delegate");
1276 QRectF r = cursorRectangle();
1278 QQml_setParent_noEvent(d->cursorItem, this);
1279 d->cursorItem->setParentItem(this);
1280 d->cursorItem->setPos(r.topLeft());
1281 d->cursorItem->setHeight(r.height());
1285 \qmlmethod rect QtQuick2::TextInput::positionToRectangle(int pos)
1287 This function takes a character position and returns the rectangle that the
1288 cursor would occupy, if it was placed at that character position.
1290 This is similar to setting the cursorPosition, and then querying the cursor
1291 rectangle, but the cursorPosition is not changed.
1293 QRectF QQuickTextInput::positionToRectangle(int pos) const
1295 Q_D(const QQuickTextInput);
1296 if (d->m_echoMode == NoEcho)
1298 else if (pos > d->m_cursor)
1299 pos += d->preeditAreaText().length();
1300 QTextLine l = d->m_textLayout.lineForTextPosition(pos);
1302 ? QRectF(l.cursorToX(pos) - d->hscroll, l.y() - d->vscroll, 1, l.height())
1307 \qmlmethod int QtQuick2::TextInput::positionAt(real x, real y, CursorPosition position = CursorBetweenCharacters)
1309 This function returns the character position at
1310 x and y pixels from the top left of the textInput. Position 0 is before the
1311 first character, position 1 is after the first character but before the second,
1312 and so on until position text.length, which is after all characters.
1314 This means that for all x values before the first character this function returns 0,
1315 and for all x values after the last character this function returns text.length. If
1316 the y value is above the text the position will be that of the nearest character on
1317 the first line line and if it is below the text the position of the nearest character
1318 on the last line will be returned.
1320 The cursor position type specifies how the cursor position should be resolved.
1323 \li TextInput.CursorBetweenCharacters - Returns the position between characters that is nearest x.
1324 \li TextInput.CursorOnCharacter - Returns the position before the character that is nearest x.
1328 void QQuickTextInput::positionAt(QQmlV8Function *args) const
1330 Q_D(const QQuickTextInput);
1334 QTextLine::CursorPosition position = QTextLine::CursorBetweenCharacters;
1336 if (args->Length() < 1)
1340 v8::Local<v8::Value> arg = (*args)[i];
1341 x = arg->NumberValue();
1343 if (++i < args->Length()) {
1345 y = arg->NumberValue();
1348 if (++i < args->Length()) {
1350 position = QTextLine::CursorPosition(arg->Int32Value());
1353 int pos = d->positionAt(x, y, position);
1354 const int cursor = d->m_cursor;
1356 const int preeditLength = d->preeditAreaText().length();
1357 pos = pos > cursor + preeditLength
1358 ? pos - preeditLength
1361 args->returnValue(v8::Int32::New(pos));
1364 int QQuickTextInputPrivate::positionAt(qreal x, qreal y, QTextLine::CursorPosition position) const
1368 QTextLine line = m_textLayout.lineAt(0);
1369 for (int i = 1; i < m_textLayout.lineCount(); ++i) {
1370 QTextLine nextLine = m_textLayout.lineAt(i);
1372 if (y < (line.rect().bottom() + nextLine.y()) / 2)
1376 return line.isValid() ? line.xToCursor(x, position) : 0;
1379 void QQuickTextInput::keyPressEvent(QKeyEvent* ev)
1381 Q_D(QQuickTextInput);
1382 // Don't allow MacOSX up/down support, and we don't allow a completer.
1383 bool ignore = (ev->key() == Qt::Key_Up || ev->key() == Qt::Key_Down) && ev->modifiers() == Qt::NoModifier;
1384 if (!ignore && (d->lastSelectionStart == d->lastSelectionEnd) && (ev->key() == Qt::Key_Right || ev->key() == Qt::Key_Left)) {
1385 // Ignore when moving off the end unless there is a selection,
1386 // because then moving will do something (deselect).
1387 int cursorPosition = d->m_cursor;
1388 if (cursorPosition == 0)
1389 ignore = ev->key() == (d->layoutDirection() == Qt::LeftToRight ? Qt::Key_Left : Qt::Key_Right);
1390 if (cursorPosition == text().length())
1391 ignore = ev->key() == (d->layoutDirection() == Qt::LeftToRight ? Qt::Key_Right : Qt::Key_Left);
1396 d->processKeyEvent(ev);
1398 if (!ev->isAccepted())
1399 QQuickImplicitSizeItem::keyPressEvent(ev);
1402 void QQuickTextInput::inputMethodEvent(QInputMethodEvent *ev)
1404 Q_D(QQuickTextInput);
1405 const bool wasComposing = d->preeditAreaText().length() > 0;
1406 if (d->m_readOnly) {
1409 d->processInputMethodEvent(ev);
1411 if (!ev->isAccepted())
1412 QQuickImplicitSizeItem::inputMethodEvent(ev);
1414 if (wasComposing != (d->m_textLayout.preeditAreaText().length() > 0))
1415 emit inputMethodComposingChanged();
1418 void QQuickTextInput::mouseDoubleClickEvent(QMouseEvent *event)
1420 Q_D(QQuickTextInput);
1422 if (d->selectByMouse && event->button() == Qt::LeftButton) {
1424 int cursor = d->positionAt(event->localPos());
1425 d->selectWordAtPos(cursor);
1426 event->setAccepted(true);
1427 if (!d->hasPendingTripleClick()) {
1428 d->tripleClickStartPoint = event->localPos();
1429 d->tripleClickTimer.start();
1432 if (d->sendMouseEventToInputContext(event))
1434 QQuickImplicitSizeItem::mouseDoubleClickEvent(event);
1438 void QQuickTextInput::mousePressEvent(QMouseEvent *event)
1440 Q_D(QQuickTextInput);
1442 d->pressPos = event->localPos();
1444 if (d->sendMouseEventToInputContext(event))
1447 if (d->selectByMouse) {
1448 setKeepMouseGrab(false);
1449 d->selectPressed = true;
1450 QPointF distanceVector = d->pressPos - d->tripleClickStartPoint;
1451 if (d->hasPendingTripleClick()
1452 && distanceVector.manhattanLength() < qApp->styleHints()->startDragDistance()) {
1453 event->setAccepted(true);
1459 bool mark = (event->modifiers() & Qt::ShiftModifier) && d->selectByMouse;
1460 int cursor = d->positionAt(event->localPos());
1461 d->moveCursor(cursor, mark);
1463 if (d->focusOnPress) {
1464 bool hadActiveFocus = hasActiveFocus();
1466 // re-open input panel on press if already focused
1467 if (hasActiveFocus() && hadActiveFocus && !d->m_readOnly)
1468 openSoftwareInputPanel();
1471 event->setAccepted(true);
1474 void QQuickTextInput::mouseMoveEvent(QMouseEvent *event)
1476 Q_D(QQuickTextInput);
1478 if (d->selectPressed) {
1479 if (qAbs(int(event->localPos().x() - d->pressPos.x())) > qApp->styleHints()->startDragDistance())
1480 setKeepMouseGrab(true);
1482 if (d->composeMode()) {
1484 int startPos = d->positionAt(d->pressPos);
1485 int currentPos = d->positionAt(event->localPos());
1486 if (startPos != currentPos)
1487 d->setSelection(startPos, currentPos - startPos);
1489 moveCursorSelection(d->positionAt(event->localPos()), d->mouseSelectionMode);
1491 event->setAccepted(true);
1493 QQuickImplicitSizeItem::mouseMoveEvent(event);
1497 void QQuickTextInput::mouseReleaseEvent(QMouseEvent *event)
1499 Q_D(QQuickTextInput);
1500 if (d->sendMouseEventToInputContext(event))
1502 if (d->selectPressed) {
1503 d->selectPressed = false;
1504 setKeepMouseGrab(false);
1506 #ifndef QT_NO_CLIPBOARD
1507 if (QGuiApplication::clipboard()->supportsSelection()) {
1508 if (event->button() == Qt::LeftButton) {
1509 d->copy(QClipboard::Selection);
1510 } else if (!d->m_readOnly && event->button() == Qt::MidButton) {
1512 d->insert(QGuiApplication::clipboard()->text(QClipboard::Selection));
1516 if (!event->isAccepted())
1517 QQuickImplicitSizeItem::mouseReleaseEvent(event);
1520 bool QQuickTextInputPrivate::sendMouseEventToInputContext(QMouseEvent *event)
1522 #if !defined QT_NO_IM
1523 if (composeMode()) {
1524 int tmp_cursor = positionAt(event->localPos());
1525 int mousePos = tmp_cursor - m_cursor;
1526 if (mousePos >= 0 && mousePos <= m_textLayout.preeditAreaText().length()) {
1527 if (event->type() == QEvent::MouseButtonRelease) {
1528 qApp->inputMethod()->invokeAction(QInputMethod::Click, mousePos);
1541 void QQuickTextInput::mouseUngrabEvent()
1543 Q_D(QQuickTextInput);
1544 d->selectPressed = false;
1545 setKeepMouseGrab(false);
1548 bool QQuickTextInput::event(QEvent* ev)
1550 #ifndef QT_NO_SHORTCUT
1551 Q_D(QQuickTextInput);
1552 if (ev->type() == QEvent::ShortcutOverride) {
1555 QKeyEvent* ke = static_cast<QKeyEvent*>(ev);
1556 if (ke == QKeySequence::Copy
1557 || ke == QKeySequence::Paste
1558 || ke == QKeySequence::Cut
1559 || ke == QKeySequence::Redo
1560 || ke == QKeySequence::Undo
1561 || ke == QKeySequence::MoveToNextWord
1562 || ke == QKeySequence::MoveToPreviousWord
1563 || ke == QKeySequence::MoveToStartOfDocument
1564 || ke == QKeySequence::MoveToEndOfDocument
1565 || ke == QKeySequence::SelectNextWord
1566 || ke == QKeySequence::SelectPreviousWord
1567 || ke == QKeySequence::SelectStartOfLine
1568 || ke == QKeySequence::SelectEndOfLine
1569 || ke == QKeySequence::SelectStartOfBlock
1570 || ke == QKeySequence::SelectEndOfBlock
1571 || ke == QKeySequence::SelectStartOfDocument
1572 || ke == QKeySequence::SelectAll
1573 || ke == QKeySequence::SelectEndOfDocument) {
1575 } else if (ke->modifiers() == Qt::NoModifier || ke->modifiers() == Qt::ShiftModifier
1576 || ke->modifiers() == Qt::KeypadModifier) {
1577 if (ke->key() < Qt::Key_Escape) {
1581 switch (ke->key()) {
1582 case Qt::Key_Delete:
1585 case Qt::Key_Backspace:
1597 return QQuickImplicitSizeItem::event(ev);
1600 void QQuickTextInput::geometryChanged(const QRectF &newGeometry,
1601 const QRectF &oldGeometry)
1603 Q_D(QQuickTextInput);
1605 if (newGeometry.width() != oldGeometry.width() && d->wrapMode != NoWrap)
1607 updateCursorRectangle();
1609 QQuickImplicitSizeItem::geometryChanged(newGeometry, oldGeometry);
1612 void QQuickTextInputPrivate::updateHorizontalScroll()
1614 Q_Q(QQuickTextInput);
1615 QTextLine currentLine = m_textLayout.lineForTextPosition(m_cursor + m_preeditCursor);
1616 const int preeditLength = m_textLayout.preeditAreaText().length();
1617 const qreal width = qMax<qreal>(0, q->width());
1619 qreal widthUsed = 0;
1620 if (currentLine.isValid()) {
1621 cix = currentLine.cursorToX(m_cursor + preeditLength);
1622 const qreal cursorWidth = cix >= 0 ? cix : width - cix;
1623 widthUsed = qMax(currentLine.naturalTextWidth(), cursorWidth);
1625 int previousScroll = hscroll;
1627 if (!autoScroll || widthUsed <= width || m_echoMode == QQuickTextInput::NoEcho) {
1630 Q_ASSERT(currentLine.isValid());
1631 if (cix - hscroll >= width) {
1632 // text doesn't fit, cursor is to the right of br (scroll right)
1633 hscroll = cix - width;
1634 } else if (cix - hscroll < 0 && hscroll < widthUsed) {
1635 // text doesn't fit, cursor is to the left of br (scroll left)
1637 } else if (widthUsed - hscroll < width) {
1638 // text doesn't fit, text document is to the left of br; align
1640 hscroll = widthUsed - width;
1641 } else if (width - hscroll > widthUsed) {
1642 // text doesn't fit, text document is to the right of br; align
1644 hscroll = width - widthUsed;
1646 if (preeditLength > 0) {
1647 // check to ensure long pre-edit text doesn't push the cursor
1649 cix = currentLine.cursorToX(m_cursor + qMax(0, m_preeditCursor - 1));
1654 if (previousScroll != hscroll)
1655 textLayoutDirty = true;
1658 void QQuickTextInputPrivate::updateVerticalScroll()
1660 Q_Q(QQuickTextInput);
1661 const int preeditLength = m_textLayout.preeditAreaText().length();
1662 const qreal height = qMax<qreal>(0, q->height());
1663 qreal heightUsed = boundingRect.height();
1664 qreal previousScroll = vscroll;
1666 if (!autoScroll || heightUsed <= height) {
1667 // text fits in br; use vscroll for alignment
1668 switch (vAlign & ~(Qt::AlignAbsolute|Qt::AlignHorizontal_Mask)) {
1669 case Qt::AlignBottom:
1670 vscroll = heightUsed - height;
1672 case Qt::AlignVCenter:
1673 vscroll = (heightUsed - height) / 2;
1681 QTextLine currentLine = m_textLayout.lineForTextPosition(m_cursor + preeditLength);
1682 QRectF r = currentLine.isValid() ? currentLine.rect() : QRectF();
1683 qreal top = r.top();
1684 int bottom = r.bottom();
1686 if (bottom - vscroll >= height) {
1687 // text doesn't fit, cursor is to the below the br (scroll down)
1688 vscroll = bottom - height;
1689 } else if (top - vscroll < 0 && vscroll < heightUsed) {
1690 // text doesn't fit, cursor is above br (scroll up)
1692 } else if (heightUsed - vscroll < height) {
1693 // text doesn't fit, text document is to the left of br; align
1695 vscroll = heightUsed - height;
1697 if (preeditLength > 0) {
1698 // check to ensure long pre-edit text doesn't push the cursor
1700 currentLine = m_textLayout.lineForTextPosition(m_cursor + qMax(0, m_preeditCursor - 1));
1701 top = currentLine.isValid() ? currentLine.rect().top() : 0;
1706 if (previousScroll != vscroll)
1707 textLayoutDirty = true;
1710 void QQuickTextInput::triggerPreprocess()
1712 Q_D(QQuickTextInput);
1713 if (d->updateType == QQuickTextInputPrivate::UpdateNone)
1714 d->updateType = QQuickTextInputPrivate::UpdateOnlyPreprocess;
1718 QSGNode *QQuickTextInput::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data)
1721 Q_D(QQuickTextInput);
1723 if (d->updateType != QQuickTextInputPrivate::UpdatePaintNode && oldNode != 0) {
1724 // Update done in preprocess() in the nodes
1725 d->updateType = QQuickTextInputPrivate::UpdateNone;
1729 d->updateType = QQuickTextInputPrivate::UpdateNone;
1731 QQuickTextNode *node = static_cast<QQuickTextNode *>(oldNode);
1733 node = new QQuickTextNode(QQuickItemPrivate::get(this)->sceneGraphContext(), this);
1736 if (!d->textLayoutDirty) {
1737 QSGSimpleRectNode *cursorNode = node->cursorNode();
1738 if (cursorNode != 0 && !isReadOnly()) {
1739 cursorNode->setRect(cursorRectangle());
1741 if (!d->cursorVisible || (!d->m_blinkStatus && d->m_blinkPeriod > 0)) {
1748 node->deleteContent();
1749 node->setMatrix(QMatrix4x4());
1751 QPointF offset(0, 0);
1752 if (d->autoScroll && d->m_textLayout.lineCount() > 0) {
1753 QFontMetricsF fm(d->font);
1754 // the y offset is there to keep the baseline constant in case we have script changes in the text.
1755 offset = -QPoint(d->hscroll, d->vscroll + d->m_textLayout.lineAt(0).ascent() - fm.ascent());
1757 offset = -QPoint(d->hscroll, d->vscroll);
1760 if (!d->m_textLayout.text().isEmpty() || !d->m_textLayout.preeditAreaText().isEmpty()) {
1761 node->addTextLayout(offset, &d->m_textLayout, d->color,
1762 QQuickText::Normal, QColor(), QColor(),
1763 d->selectionColor, d->selectedTextColor,
1764 d->selectionStart(),
1765 d->selectionEnd() - 1); // selectionEnd() returns first char after
1769 if (!isReadOnly() && d->cursorItem == 0) {
1770 node->setCursor(cursorRectangle(), d->color);
1771 if (!d->cursorVisible || (!d->m_blinkStatus && d->m_blinkPeriod > 0)) {
1778 d->textLayoutDirty = false;
1784 QVariant QQuickTextInput::inputMethodQuery(Qt::InputMethodQuery property) const
1786 Q_D(const QQuickTextInput);
1789 return QVariant((bool)(flags() & ItemAcceptsInputMethod));
1791 return QVariant((int) d->effectiveInputMethodHints());
1792 case Qt::ImCursorRectangle:
1793 return cursorRectangle();
1796 case Qt::ImCursorPosition:
1797 return QVariant(d->m_cursor);
1798 case Qt::ImSurroundingText:
1799 if (d->m_echoMode == PasswordEchoOnEdit && !d->m_passwordEchoEditing) {
1800 return QVariant(displayText());
1802 return QVariant(d->realText());
1804 case Qt::ImCurrentSelection:
1805 return QVariant(selectedText());
1806 case Qt::ImMaximumTextLength:
1807 return QVariant(maxLength());
1808 case Qt::ImAnchorPosition:
1809 if (d->selectionStart() == d->selectionEnd())
1810 return QVariant(d->m_cursor);
1811 else if (d->selectionStart() == d->m_cursor)
1812 return QVariant(d->selectionEnd());
1814 return QVariant(d->selectionStart());
1821 \qmlmethod void QtQuick2::TextInput::deselect()
1823 Removes active text selection.
1825 void QQuickTextInput::deselect()
1827 Q_D(QQuickTextInput);
1832 \qmlmethod void QtQuick2::TextInput::selectAll()
1834 Causes all text to be selected.
1836 void QQuickTextInput::selectAll()
1838 Q_D(QQuickTextInput);
1839 d->setSelection(0, text().length());
1843 \qmlmethod void QtQuick2::TextInput::isRightToLeft(int start, int end)
1845 Returns true if the natural reading direction of the editor text
1846 found between positions \a start and \a end is right to left.
1848 bool QQuickTextInput::isRightToLeft(int start, int end)
1851 qmlInfo(this) << "isRightToLeft(start, end) called with the end property being smaller than the start.";
1854 return text().mid(start, end - start).isRightToLeft();
1858 #ifndef QT_NO_CLIPBOARD
1860 \qmlmethod QtQuick2::TextInput::cut()
1862 Moves the currently selected text to the system clipboard.
1864 void QQuickTextInput::cut()
1866 Q_D(QQuickTextInput);
1872 \qmlmethod QtQuick2::TextInput::copy()
1874 Copies the currently selected text to the system clipboard.
1876 void QQuickTextInput::copy()
1878 Q_D(QQuickTextInput);
1883 \qmlmethod QtQuick2::TextInput::paste()
1885 Replaces the currently selected text by the contents of the system clipboard.
1887 void QQuickTextInput::paste()
1889 Q_D(QQuickTextInput);
1893 #endif // QT_NO_CLIPBOARD
1896 Undoes the last operation if undo is \l {canUndo}{available}. Deselects any
1897 current selection, and updates the selection start to the current cursor
1901 void QQuickTextInput::undo()
1903 Q_D(QQuickTextInput);
1904 if (!d->m_readOnly) {
1906 d->finishChange(-1, true);
1911 Redoes the last operation if redo is \l {canRedo}{available}.
1914 void QQuickTextInput::redo()
1916 Q_D(QQuickTextInput);
1917 if (!d->m_readOnly) {
1924 \qmlmethod void QtQuick2::TextInput::insert(int position, string text)
1926 Inserts \a text into the TextInput at position.
1929 void QQuickTextInput::insert(int position, const QString &text)
1931 Q_D(QQuickTextInput);
1932 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
1933 if (d->m_echoMode == QQuickTextInput::Password)
1934 d->m_passwordEchoTimer.start(qt_passwordEchoDelay, this);
1937 if (position < 0 || position > d->m_text.length())
1940 const int priorState = d->m_undoState;
1942 QString insertText = text;
1944 if (d->hasSelectedText()) {
1945 d->addCommand(QQuickTextInputPrivate::Command(
1946 QQuickTextInputPrivate::SetSelection, d->m_cursor, 0, d->m_selstart, d->m_selend));
1948 if (d->m_maskData) {
1949 insertText = d->maskString(position, insertText);
1950 for (int i = 0; i < insertText.length(); ++i) {
1951 d->addCommand(QQuickTextInputPrivate::Command(
1952 QQuickTextInputPrivate::DeleteSelection, position + i, d->m_text.at(position + i), -1, -1));
1953 d->addCommand(QQuickTextInputPrivate::Command(
1954 QQuickTextInputPrivate::Insert, position + i, insertText.at(i), -1, -1));
1956 d->m_text.replace(position, insertText.length(), insertText);
1957 if (!insertText.isEmpty())
1958 d->m_textDirty = true;
1959 if (position < d->m_selend && position + insertText.length() > d->m_selstart)
1960 d->m_selDirty = true;
1962 int remaining = d->m_maxLength - d->m_text.length();
1963 if (remaining != 0) {
1964 insertText = insertText.left(remaining);
1965 d->m_text.insert(position, insertText);
1966 for (int i = 0; i < insertText.length(); ++i)
1967 d->addCommand(QQuickTextInputPrivate::Command(
1968 QQuickTextInputPrivate::Insert, position + i, insertText.at(i), -1, -1));
1969 if (d->m_cursor >= position)
1970 d->m_cursor += insertText.length();
1971 if (d->m_selstart >= position)
1972 d->m_selstart += insertText.length();
1973 if (d->m_selend >= position)
1974 d->m_selend += insertText.length();
1975 d->m_textDirty = true;
1976 if (position >= d->m_selstart && position <= d->m_selend)
1977 d->m_selDirty = true;
1981 d->addCommand(QQuickTextInputPrivate::Command(
1982 QQuickTextInputPrivate::SetSelection, d->m_cursor, 0, d->m_selstart, d->m_selend));
1983 d->finishChange(priorState);
1985 if (d->lastSelectionStart != d->lastSelectionEnd) {
1986 if (d->m_selstart != d->lastSelectionStart) {
1987 d->lastSelectionStart = d->m_selstart;
1988 emit selectionStartChanged();
1990 if (d->m_selend != d->lastSelectionEnd) {
1991 d->lastSelectionEnd = d->m_selend;
1992 emit selectionEndChanged();
1998 \qmlmethod string QtQuick2::TextInput::getText(int start, int end)
2000 Removes the section of text that is between the \a start and \a end positions from the TextInput.
2003 void QQuickTextInput::remove(int start, int end)
2005 Q_D(QQuickTextInput);
2007 start = qBound(0, start, d->m_text.length());
2008 end = qBound(0, end, d->m_text.length());
2012 else if (start == end)
2015 if (start < d->m_selend && end > d->m_selstart)
2016 d->m_selDirty = true;
2018 const int priorState = d->m_undoState;
2020 d->addCommand(QQuickTextInputPrivate::Command(
2021 QQuickTextInputPrivate::SetSelection, d->m_cursor, 0, d->m_selstart, d->m_selend));
2023 if (start <= d->m_cursor && d->m_cursor < end) {
2024 // cursor is within the selection. Split up the commands
2025 // to be able to restore the correct cursor position
2026 for (int i = d->m_cursor; i >= start; --i) {
2027 d->addCommand(QQuickTextInputPrivate::Command(
2028 QQuickTextInputPrivate::DeleteSelection, i, d->m_text.at(i), -1, 1));
2030 for (int i = end - 1; i > d->m_cursor; --i) {
2031 d->addCommand(QQuickTextInputPrivate::Command(
2032 QQuickTextInputPrivate::DeleteSelection, i - d->m_cursor + start - 1, d->m_text.at(i), -1, -1));
2035 for (int i = end - 1; i >= start; --i) {
2036 d->addCommand(QQuickTextInputPrivate::Command(
2037 QQuickTextInputPrivate::RemoveSelection, i, d->m_text.at(i), -1, -1));
2040 if (d->m_maskData) {
2041 d->m_text.replace(start, end - start, d->clearString(start, end - start));
2042 for (int i = 0; i < end - start; ++i) {
2043 d->addCommand(QQuickTextInputPrivate::Command(
2044 QQuickTextInputPrivate::Insert, start + i, d->m_text.at(start + i), -1, -1));
2047 d->m_text.remove(start, end - start);
2049 if (d->m_cursor > start)
2050 d->m_cursor -= qMin(d->m_cursor, end) - start;
2051 if (d->m_selstart > start)
2052 d->m_selstart -= qMin(d->m_selstart, end) - start;
2053 if (d->m_selend > end)
2054 d->m_selend -= qMin(d->m_selend, end) - start;
2056 d->addCommand(QQuickTextInputPrivate::Command(
2057 QQuickTextInputPrivate::SetSelection, d->m_cursor, 0, d->m_selstart, d->m_selend));
2059 d->m_textDirty = true;
2060 d->finishChange(priorState);
2062 if (d->lastSelectionStart != d->lastSelectionEnd) {
2063 if (d->m_selstart != d->lastSelectionStart) {
2064 d->lastSelectionStart = d->m_selstart;
2065 emit selectionStartChanged();
2067 if (d->m_selend != d->lastSelectionEnd) {
2068 d->lastSelectionEnd = d->m_selend;
2069 emit selectionEndChanged();
2076 \qmlmethod void QtQuick2::TextInput::selectWord()
2078 Causes the word closest to the current cursor position to be selected.
2080 void QQuickTextInput::selectWord()
2082 Q_D(QQuickTextInput);
2083 d->selectWordAtPos(d->m_cursor);
2087 \qmlproperty bool QtQuick2::TextInput::smooth
2089 This property holds whether the text is smoothly scaled or transformed.
2091 Smooth filtering gives better visual quality, but is slower. If
2092 the item is displayed at its natural size, this property has no visual or
2095 \note Generally scaling artifacts are only visible if the item is stationary on
2096 the screen. A common pattern when animating an item is to disable smooth
2097 filtering at the beginning of the animation and reenable it at the conclusion.
2101 \qmlproperty string QtQuick2::TextInput::passwordCharacter
2103 This is the character displayed when echoMode is set to Password or
2104 PasswordEchoOnEdit. By default it is an asterisk.
2106 If this property is set to a string with more than one character,
2107 the first character is used. If the string is empty, the value
2108 is ignored and the property is not set.
2110 QString QQuickTextInput::passwordCharacter() const
2112 Q_D(const QQuickTextInput);
2113 return QString(d->m_passwordCharacter);
2116 void QQuickTextInput::setPasswordCharacter(const QString &str)
2118 Q_D(QQuickTextInput);
2119 if (str.length() < 1)
2121 d->m_passwordCharacter = str.constData()[0];
2122 if (d->m_echoMode == Password || d->m_echoMode == PasswordEchoOnEdit)
2123 d->updateDisplayText();
2124 emit passwordCharacterChanged();
2128 \qmlproperty string QtQuick2::TextInput::displayText
2130 This is the text displayed in the TextInput.
2132 If \l echoMode is set to TextInput::Normal, this holds the
2133 same value as the TextInput::text property. Otherwise,
2134 this property holds the text visible to the user, while
2135 the \l text property holds the actual entered text.
2137 QString QQuickTextInput::displayText() const
2139 Q_D(const QQuickTextInput);
2140 return d->m_textLayout.text();
2144 \qmlproperty bool QtQuick2::TextInput::selectByMouse
2148 If true, the user can use the mouse to select text in some
2149 platform-specific way. Note that for some platforms this may
2150 not be an appropriate interaction (eg. may conflict with how
2151 the text needs to behave inside a Flickable.
2153 bool QQuickTextInput::selectByMouse() const
2155 Q_D(const QQuickTextInput);
2156 return d->selectByMouse;
2159 void QQuickTextInput::setSelectByMouse(bool on)
2161 Q_D(QQuickTextInput);
2162 if (d->selectByMouse != on) {
2163 d->selectByMouse = on;
2164 emit selectByMouseChanged(on);
2169 \qmlproperty enum QtQuick2::TextInput::mouseSelectionMode
2171 Specifies how text should be selected using a mouse.
2174 \li TextInput.SelectCharacters - The selection is updated with individual characters. (Default)
2175 \li TextInput.SelectWords - The selection is updated with whole words.
2178 This property only applies when \l selectByMouse is true.
2181 QQuickTextInput::SelectionMode QQuickTextInput::mouseSelectionMode() const
2183 Q_D(const QQuickTextInput);
2184 return d->mouseSelectionMode;
2187 void QQuickTextInput::setMouseSelectionMode(SelectionMode mode)
2189 Q_D(QQuickTextInput);
2190 if (d->mouseSelectionMode != mode) {
2191 d->mouseSelectionMode = mode;
2192 emit mouseSelectionModeChanged(mode);
2197 \qmlproperty bool QtQuick2::TextInput::persistentSelection
2199 Whether the TextInput should keep its selection when it loses active focus to another
2200 item in the scene. By default this is set to false;
2203 bool QQuickTextInput::persistentSelection() const
2205 Q_D(const QQuickTextInput);
2206 return d->persistentSelection;
2209 void QQuickTextInput::setPersistentSelection(bool on)
2211 Q_D(QQuickTextInput);
2212 if (d->persistentSelection == on)
2214 d->persistentSelection = on;
2215 emit persistentSelectionChanged();
2219 \qmlproperty bool QtQuick2::TextInput::canPaste
2221 Returns true if the TextInput is writable and the content of the clipboard is
2222 suitable for pasting into the TextInput.
2224 bool QQuickTextInput::canPaste() const
2226 Q_D(const QQuickTextInput);
2227 if (!d->canPasteValid) {
2228 if (const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData())
2229 const_cast<QQuickTextInputPrivate *>(d)->canPaste = !d->m_readOnly && mimeData->hasText();
2230 const_cast<QQuickTextInputPrivate *>(d)->canPasteValid = true;
2236 \qmlproperty bool QtQuick2::TextInput::canUndo
2238 Returns true if the TextInput is writable and there are previous operations
2242 bool QQuickTextInput::canUndo() const
2244 Q_D(const QQuickTextInput);
2249 \qmlproperty bool QtQuick2::TextInput::canRedo
2251 Returns true if the TextInput is writable and there are \l {undo}{undone}
2252 operations that can be redone.
2255 bool QQuickTextInput::canRedo() const
2257 Q_D(const QQuickTextInput);
2262 \qmlproperty real QtQuick2::TextInput::contentWidth
2264 Returns the width of the text, including the width past the width
2265 which is covered due to insufficient wrapping if \l wrapMode is set.
2268 qreal QQuickTextInput::contentWidth() const
2270 Q_D(const QQuickTextInput);
2271 return d->boundingRect.width();
2275 \qmlproperty real QtQuick2::TextInput::contentHeight
2277 Returns the height of the text, including the height past the height
2278 that is covered if the text does not fit within the set height.
2281 qreal QQuickTextInput::contentHeight() const
2283 Q_D(const QQuickTextInput);
2284 return d->boundingRect.height();
2287 void QQuickTextInput::moveCursorSelection(int position)
2289 Q_D(QQuickTextInput);
2290 d->moveCursor(position, true);
2294 \qmlmethod void QtQuick2::TextInput::moveCursorSelection(int position, SelectionMode mode = TextInput.SelectCharacters)
2296 Moves the cursor to \a position and updates the selection according to the optional \a mode
2297 parameter. (To only move the cursor, set the \l cursorPosition property.)
2299 When this method is called it additionally sets either the
2300 selectionStart or the selectionEnd (whichever was at the previous cursor position)
2301 to the specified position. This allows you to easily extend and contract the selected
2304 The selection mode specifies whether the selection is updated on a per character or a per word
2305 basis. If not specified the selection mode will default to TextInput.SelectCharacters.
2308 \li TextInput.SelectCharacters - Sets either the selectionStart or selectionEnd (whichever was at
2309 the previous cursor position) to the specified position.
2310 \li TextInput.SelectWords - Sets the selectionStart and selectionEnd to include all
2311 words between the specified position and the previous cursor position. Words partially in the
2315 For example, take this sequence of calls:
2319 moveCursorSelection(9, TextInput.SelectCharacters)
2320 moveCursorSelection(7, TextInput.SelectCharacters)
2323 This moves the cursor to position 5, extend the selection end from 5 to 9
2324 and then retract the selection end from 9 to 7, leaving the text from position 5 to 7
2325 selected (the 6th and 7th characters).
2327 The same sequence with TextInput.SelectWords will extend the selection start to a word boundary
2328 before or on position 5 and extend the selection end to a word boundary on or past position 9.
2330 void QQuickTextInput::moveCursorSelection(int pos, SelectionMode mode)
2332 Q_D(QQuickTextInput);
2334 if (mode == SelectCharacters) {
2335 d->moveCursor(pos, true);
2336 } else if (pos != d->m_cursor){
2337 const int cursor = d->m_cursor;
2339 if (!d->hasSelectedText())
2340 anchor = d->m_cursor;
2341 else if (d->selectionStart() == d->m_cursor)
2342 anchor = d->selectionEnd();
2344 anchor = d->selectionStart();
2346 if (anchor < pos || (anchor == pos && cursor < pos)) {
2347 const QString text = this->text();
2348 QTextBoundaryFinder finder(QTextBoundaryFinder::Word, text);
2349 finder.setPosition(anchor);
2351 const QTextBoundaryFinder::BoundaryReasons reasons = finder.boundaryReasons();
2352 if (anchor < text.length() && (!(reasons & QTextBoundaryFinder::StartWord)
2353 || ((reasons & QTextBoundaryFinder::EndWord) && anchor > cursor))) {
2354 finder.toPreviousBoundary();
2356 anchor = finder.position() != -1 ? finder.position() : 0;
2358 finder.setPosition(pos);
2359 if (pos > 0 && !finder.boundaryReasons())
2360 finder.toNextBoundary();
2361 const int cursor = finder.position() != -1 ? finder.position() : text.length();
2363 d->setSelection(anchor, cursor - anchor);
2364 } else if (anchor > pos || (anchor == pos && cursor > pos)) {
2365 const QString text = this->text();
2366 QTextBoundaryFinder finder(QTextBoundaryFinder::Word, text);
2367 finder.setPosition(anchor);
2369 const QTextBoundaryFinder::BoundaryReasons reasons = finder.boundaryReasons();
2370 if (anchor > 0 && (!(reasons & QTextBoundaryFinder::EndWord)
2371 || ((reasons & QTextBoundaryFinder::StartWord) && anchor < cursor))) {
2372 finder.toNextBoundary();
2375 anchor = finder.position() != -1 ? finder.position() : text.length();
2377 finder.setPosition(pos);
2378 if (pos < text.length() && !finder.boundaryReasons())
2379 finder.toPreviousBoundary();
2380 const int cursor = finder.position() != -1 ? finder.position() : 0;
2382 d->setSelection(anchor, cursor - anchor);
2388 \qmlmethod void QtQuick2::TextInput::openSoftwareInputPanel()
2390 Opens software input panels like virtual keyboards for typing, useful for
2391 customizing when you want the input keyboard to be shown and hidden in
2394 By default the opening of input panels follows the platform style. Input panels are
2395 always closed if no editor has active focus.
2397 You can disable the automatic behavior by setting the property \c activeFocusOnPress to false
2398 and use functions openSoftwareInputPanel() and closeSoftwareInputPanel() to implement
2399 the behavior you want.
2401 Only relevant on platforms, which provide virtual keyboards.
2407 text: "Hello world!"
2408 activeFocusOnPress: false
2410 anchors.fill: parent
2412 if (!textInput.activeFocus) {
2413 textInput.forceActiveFocus()
2414 textInput.openSoftwareInputPanel();
2416 textInput.focus = false;
2419 onPressAndHold: textInput.closeSoftwareInputPanel();
2424 void QQuickTextInput::openSoftwareInputPanel()
2427 qGuiApp->inputMethod()->show();
2431 \qmlmethod void QtQuick2::TextInput::closeSoftwareInputPanel()
2433 Closes a software input panel like a virtual keyboard shown on the screen, useful
2434 for customizing when you want the input keyboard to be shown and hidden in
2437 By default the opening of input panels follows the platform style. Input panels are
2438 always closed if no editor has active focus.
2440 You can disable the automatic behavior by setting the property \c activeFocusOnPress to false
2441 and use functions openSoftwareInputPanel() and closeSoftwareInputPanel() to implement
2442 the behavior you want.
2444 Only relevant on platforms, which provide virtual keyboards.
2450 text: "Hello world!"
2451 activeFocusOnPress: false
2453 anchors.fill: parent
2455 if (!textInput.activeFocus) {
2456 textInput.forceActiveFocus();
2457 textInput.openSoftwareInputPanel();
2459 textInput.focus = false;
2462 onPressAndHold: textInput.closeSoftwareInputPanel();
2467 void QQuickTextInput::closeSoftwareInputPanel()
2470 qGuiApp->inputMethod()->hide();
2473 void QQuickTextInput::focusInEvent(QFocusEvent *event)
2475 Q_D(const QQuickTextInput);
2476 if (d->focusOnPress && !d->m_readOnly)
2477 openSoftwareInputPanel();
2478 QQuickImplicitSizeItem::focusInEvent(event);
2481 void QQuickTextInput::itemChange(ItemChange change, const ItemChangeData &value)
2483 Q_D(QQuickTextInput);
2484 if (change == ItemActiveFocusHasChanged) {
2485 bool hasFocus = value.boolValue;
2486 setCursorVisible(hasFocus); // ### refactor: && d->canvas && d->canvas->hasFocus()
2487 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
2488 if (!hasFocus && (d->m_passwordEchoEditing || d->m_passwordEchoTimer.isActive())) {
2490 if (!hasFocus && d->m_passwordEchoEditing) {
2492 d->updatePasswordEchoEditing(false);//QQuickTextInputPrivate sets it on key events, but doesn't deal with focus events
2496 if (!d->persistentSelection)
2498 disconnect(qApp->inputMethod(), SIGNAL(inputDirectionChanged(Qt::LayoutDirection)),
2499 this, SLOT(q_updateAlignment()));
2501 q_updateAlignment();
2502 connect(qApp->inputMethod(), SIGNAL(inputDirectionChanged(Qt::LayoutDirection)),
2503 this, SLOT(q_updateAlignment()));
2506 QQuickItem::itemChange(change, value);
2510 \qmlproperty bool QtQuick2::TextInput::inputMethodComposing
2513 This property holds whether the TextInput has partial text input from an
2516 While it is composing an input method may rely on mouse or key events from
2517 the TextInput to edit or commit the partial text. This property can be
2518 used to determine when to disable events handlers that may interfere with
2519 the correct operation of an input method.
2521 bool QQuickTextInput::isInputMethodComposing() const
2523 Q_D(const QQuickTextInput);
2524 return d->preeditAreaText().length() > 0;
2527 void QQuickTextInputPrivate::init()
2529 Q_Q(QQuickTextInput);
2530 q->setSmooth(smooth);
2531 q->setAcceptedMouseButtons(Qt::LeftButton);
2532 q->setFlag(QQuickItem::ItemAcceptsInputMethod);
2533 q->setFlag(QQuickItem::ItemHasContents);
2534 #ifndef QT_NO_CLIPBOARD
2535 q->connect(QGuiApplication::clipboard(), SIGNAL(dataChanged()),
2536 q, SLOT(q_canPasteChanged()));
2537 #endif // QT_NO_CLIPBOARD
2539 lastSelectionStart = 0;
2540 lastSelectionEnd = 0;
2541 determineHorizontalAlignment();
2543 if (!qmlDisableDistanceField()) {
2544 QTextOption option = m_textLayout.textOption();
2545 option.setUseDesignMetrics(true);
2546 m_textLayout.setTextOption(option);
2550 void QQuickTextInput::updateCursorRectangle()
2552 Q_D(QQuickTextInput);
2553 if (!isComponentComplete())
2556 d->updateHorizontalScroll();
2557 d->updateVerticalScroll();
2558 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
2560 emit cursorRectangleChanged();
2561 if (d->cursorItem) {
2562 QRectF r = cursorRectangle();
2563 d->cursorItem->setPos(r.topLeft());
2564 d->cursorItem->setHeight(r.height());
2566 updateInputMethod(Qt::ImCursorRectangle);
2569 void QQuickTextInput::selectionChanged()
2571 Q_D(QQuickTextInput);
2572 d->textLayoutDirty = true; //TODO: Only update rect in selection
2573 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
2575 emit selectedTextChanged();
2577 if (d->lastSelectionStart != d->selectionStart()) {
2578 d->lastSelectionStart = d->selectionStart();
2579 if (d->lastSelectionStart == -1)
2580 d->lastSelectionStart = d->m_cursor;
2581 emit selectionStartChanged();
2583 if (d->lastSelectionEnd != d->selectionEnd()) {
2584 d->lastSelectionEnd = d->selectionEnd();
2585 if (d->lastSelectionEnd == -1)
2586 d->lastSelectionEnd = d->m_cursor;
2587 emit selectionEndChanged();
2591 void QQuickTextInputPrivate::showCursor()
2593 if (textNode != 0 && textNode->cursorNode() != 0)
2594 textNode->cursorNode()->setColor(color);
2597 void QQuickTextInputPrivate::hideCursor()
2599 if (textNode != 0 && textNode->cursorNode() != 0)
2600 textNode->cursorNode()->setColor(QColor(0, 0, 0, 0));
2603 QRectF QQuickTextInput::boundingRect() const
2605 Q_D(const QQuickTextInput);
2607 int cursorWidth = d->cursorItem ? d->cursorItem->width() : 1;
2609 // Could include font max left/right bearings to either side of rectangle.
2610 QRectF r = QQuickImplicitSizeItem::boundingRect();
2611 r.setRight(r.right() + cursorWidth);
2615 void QQuickTextInput::q_canPasteChanged()
2617 Q_D(QQuickTextInput);
2618 bool old = d->canPaste;
2619 #ifndef QT_NO_CLIPBOARD
2620 if (const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData())
2621 d->canPaste = !d->m_readOnly && mimeData->hasText();
2623 d->canPaste = false;
2626 bool changed = d->canPaste != old || !d->canPasteValid;
2627 d->canPasteValid = true;
2629 emit canPasteChanged();
2633 void QQuickTextInput::q_updateAlignment()
2635 Q_D(QQuickTextInput);
2636 if (d->determineHorizontalAlignment()) {
2638 updateCursorRectangle();
2642 // ### these should come from QStyleHints
2643 const int textCursorWidth = 1;
2644 const bool fullWidthSelection = true;
2649 Updates the display text based of the current edit text
2650 If the text has changed will emit displayTextChanged()
2652 void QQuickTextInputPrivate::updateDisplayText(bool forceUpdate)
2654 QString orig = m_textLayout.text();
2656 if (m_echoMode == QQuickTextInput::NoEcho)
2657 str = QString::fromLatin1("");
2661 if (m_echoMode == QQuickTextInput::Password) {
2662 str.fill(m_passwordCharacter);
2663 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
2664 if (m_passwordEchoTimer.isActive() && m_cursor > 0 && m_cursor <= m_text.length()) {
2665 int cursor = m_cursor - 1;
2666 QChar uc = m_text.at(cursor);
2668 if (cursor > 0 && uc.unicode() >= 0xdc00 && uc.unicode() < 0xe000) {
2669 // second half of a surrogate, check if we have the first half as well,
2670 // if yes restore both at once
2671 uc = m_text.at(cursor - 1);
2672 if (uc.unicode() >= 0xd800 && uc.unicode() < 0xdc00)
2673 str[cursor - 1] = uc;
2677 } else if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit && !m_passwordEchoEditing) {
2678 str.fill(m_passwordCharacter);
2681 // replace certain non-printable characters with spaces (to avoid
2682 // drawing boxes when using fonts that don't have glyphs for such
2684 QChar* uc = str.data();
2685 for (int i = 0; i < (int)str.length(); ++i) {
2686 if ((uc[i] < 0x20 && uc[i] != 0x09)
2687 || uc[i] == QChar::LineSeparator
2688 || uc[i] == QChar::ParagraphSeparator
2689 || uc[i] == QChar::ObjectReplacementCharacter)
2690 uc[i] = QChar(0x0020);
2693 if (str != orig || forceUpdate) {
2694 m_textLayout.setText(str);
2695 updateLayout(); // polish?
2696 emit q_func()->displayTextChanged();
2700 qreal QQuickTextInputPrivate::getImplicitWidth() const
2702 Q_Q(const QQuickTextInput);
2703 if (!requireImplicitWidth) {
2704 QQuickTextInputPrivate *d = const_cast<QQuickTextInputPrivate *>(this);
2705 d->requireImplicitWidth = true;
2707 if (q->isComponentComplete()) {
2708 // One time cost, only incurred if implicitWidth is first requested after
2709 // componentComplete.
2710 QTextLayout layout(m_text);
2712 QTextOption option = m_textLayout.textOption();
2713 option.setTextDirection(m_layoutDirection);
2714 option.setFlags(QTextOption::IncludeTrailingSpaces);
2715 option.setWrapMode(QTextOption::WrapMode(wrapMode));
2716 option.setAlignment(Qt::Alignment(q->effectiveHAlign()));
2717 layout.setTextOption(option);
2718 layout.setFont(font);
2719 layout.setPreeditArea(m_textLayout.preeditAreaPosition(), m_textLayout.preeditAreaText());
2720 layout.beginLayout();
2722 QTextLine line = layout.createLine();
2723 line.setLineWidth(INT_MAX);
2724 d->implicitWidth = qCeil(line.naturalTextWidth());
2729 return implicitWidth;
2732 void QQuickTextInputPrivate::updateLayout()
2734 Q_Q(QQuickTextInput);
2736 if (!q->isComponentComplete())
2739 const QRectF previousRect = boundingRect;
2741 QTextOption option = m_textLayout.textOption();
2742 option.setTextDirection(layoutDirection());
2743 option.setWrapMode(QTextOption::WrapMode(wrapMode));
2744 option.setAlignment(Qt::Alignment(q->effectiveHAlign()));
2745 m_textLayout.setTextOption(option);
2746 m_textLayout.setFont(font);
2748 boundingRect = QRectF();
2749 m_textLayout.beginLayout();
2750 QTextLine line = m_textLayout.createLine();
2751 if (requireImplicitWidth) {
2752 line.setLineWidth(INT_MAX);
2753 const bool wasInLayout = inLayout;
2755 q->setImplicitWidth(qCeil(line.naturalTextWidth()));
2756 inLayout = wasInLayout;
2757 if (inLayout) // probably the result of a binding loop, but by letting it
2758 return; // get this far we'll get a warning to that effect.
2760 qreal lineWidth = q->widthValid() ? q->width() : INT_MAX;
2763 line.setLineWidth(lineWidth);
2764 line.setPosition(QPointF(line.position().x(), height));
2765 boundingRect = boundingRect.united(line.naturalTextRect());
2767 height += line.height();
2768 line = m_textLayout.createLine();
2769 } while (line.isValid());
2770 m_textLayout.endLayout();
2772 option.setWrapMode(QTextOption::NoWrap);
2773 m_textLayout.setTextOption(option);
2775 textLayoutDirty = true;
2777 updateType = UpdatePaintNode;
2780 if (!requireImplicitWidth && !q->widthValid())
2781 q->setImplicitSize(qCeil(boundingRect.width()), qCeil(boundingRect.height()));
2783 q->setImplicitHeight(qCeil(boundingRect.height()));
2785 if (previousRect != boundingRect)
2786 emit q->contentSizeChanged();
2789 #ifndef QT_NO_CLIPBOARD
2793 Copies the currently selected text into the clipboard using the given
2796 \note If the echo mode is set to a mode other than Normal then copy
2797 will not work. This is to prevent using copy as a method of bypassing
2798 password features of the line control.
2800 void QQuickTextInputPrivate::copy(QClipboard::Mode mode) const
2802 QString t = selectedText();
2803 if (!t.isEmpty() && m_echoMode == QQuickTextInput::Normal) {
2804 QGuiApplication::clipboard()->setText(t, mode);
2811 Inserts the text stored in the application clipboard into the line
2816 void QQuickTextInputPrivate::paste(QClipboard::Mode clipboardMode)
2818 QString clip = QGuiApplication::clipboard()->text(clipboardMode);
2819 if (!clip.isEmpty() || hasSelectedText()) {
2820 separate(); //make it a separate undo/redo command
2826 #endif // !QT_NO_CLIPBOARD
2831 void QQuickTextInputPrivate::commitPreedit()
2836 qApp->inputMethod()->commit();
2841 m_preeditCursor = 0;
2842 m_textLayout.setPreeditArea(-1, QString());
2843 m_textLayout.clearAdditionalFormats();
2850 Handles the behavior for the backspace key or function.
2851 Removes the current selection if there is a selection, otherwise
2852 removes the character prior to the cursor position.
2856 void QQuickTextInputPrivate::backspace()
2858 int priorState = m_undoState;
2859 if (hasSelectedText()) {
2860 removeSelectedText();
2861 } else if (m_cursor) {
2864 m_cursor = prevMaskBlank(m_cursor);
2865 QChar uc = m_text.at(m_cursor);
2866 if (m_cursor > 0 && uc.unicode() >= 0xdc00 && uc.unicode() < 0xe000) {
2867 // second half of a surrogate, check if we have the first half as well,
2868 // if yes delete both at once
2869 uc = m_text.at(m_cursor - 1);
2870 if (uc.unicode() >= 0xd800 && uc.unicode() < 0xdc00) {
2871 internalDelete(true);
2875 internalDelete(true);
2877 finishChange(priorState);
2883 Handles the behavior for the delete key or function.
2884 Removes the current selection if there is a selection, otherwise
2885 removes the character after the cursor position.
2889 void QQuickTextInputPrivate::del()
2891 int priorState = m_undoState;
2892 if (hasSelectedText()) {
2893 removeSelectedText();
2895 int n = m_textLayout.nextCursorPosition(m_cursor) - m_cursor;
2899 finishChange(priorState);
2905 Inserts the given \a newText at the current cursor position.
2906 If there is any selected text it is removed prior to insertion of
2909 void QQuickTextInputPrivate::insert(const QString &newText)
2911 int priorState = m_undoState;
2912 removeSelectedText();
2913 internalInsert(newText);
2914 finishChange(priorState);
2920 Clears the line control text.
2922 void QQuickTextInputPrivate::clear()
2924 int priorState = m_undoState;
2926 m_selend = m_text.length();
2927 removeSelectedText();
2929 finishChange(priorState, /*update*/false, /*edited*/false);
2935 Sets \a length characters from the given \a start position as selected.
2936 The given \a start position must be within the current text for
2937 the line control. If \a length characters cannot be selected, then
2938 the selection will extend to the end of the current text.
2940 void QQuickTextInputPrivate::setSelection(int start, int length)
2942 Q_Q(QQuickTextInput);
2945 if (start < 0 || start > (int)m_text.length()){
2946 qWarning("QQuickTextInputPrivate::setSelection: Invalid start position");
2951 if (start == m_selstart && start + length == m_selend && m_cursor == m_selend)
2954 m_selend = qMin(start + length, (int)m_text.length());
2955 m_cursor = m_selend;
2956 } else if (length < 0){
2957 if (start == m_selend && start + length == m_selstart && m_cursor == m_selstart)
2959 m_selstart = qMax(start + length, 0);
2961 m_cursor = m_selstart;
2962 } else if (m_selstart != m_selend) {
2968 emitCursorPositionChanged();
2971 emit q->selectionChanged();
2972 emitCursorPositionChanged();
2973 q->updateInputMethod(Qt::ImCursorRectangle | Qt::ImAnchorPosition
2974 | Qt::ImCursorPosition | Qt::ImCurrentSelection);
2980 Sets the password echo editing to \a editing. If password echo editing
2981 is true, then the text of the password is displayed even if the echo
2982 mode is set to QLineEdit::PasswordEchoOnEdit. Password echoing editing
2983 does not affect other echo modes.
2985 void QQuickTextInputPrivate::updatePasswordEchoEditing(bool editing)
2987 cancelPasswordEchoTimer();
2988 m_passwordEchoEditing = editing;
2989 updateDisplayText();
2995 Fixes the current text so that it is valid given any set validators.
2997 Returns true if the text was changed. Otherwise returns false.
2999 bool QQuickTextInputPrivate::fixup() // this function assumes that validate currently returns != Acceptable
3001 #ifndef QT_NO_VALIDATOR
3003 QString textCopy = m_text;
3004 int cursorCopy = m_cursor;
3005 m_validator->fixup(textCopy);
3006 if (m_validator->validate(textCopy, cursorCopy) == QValidator::Acceptable) {
3007 if (textCopy != m_text || cursorCopy != m_cursor)
3008 internalSetText(textCopy, cursorCopy);
3019 Moves the cursor to the given position \a pos. If \a mark is true will
3020 adjust the currently selected text.
3022 void QQuickTextInputPrivate::moveCursor(int pos, bool mark)
3024 Q_Q(QQuickTextInput);
3027 if (pos != m_cursor) {
3030 pos = pos > m_cursor ? nextMaskBlank(pos) : prevMaskBlank(pos);
3034 if (m_selend > m_selstart && m_cursor == m_selstart)
3036 else if (m_selend > m_selstart && m_cursor == m_selend)
3037 anchor = m_selstart;
3040 m_selstart = qMin(anchor, pos);
3041 m_selend = qMax(anchor, pos);
3046 if (mark || m_selDirty) {
3048 emit q->selectionChanged();
3050 emitCursorPositionChanged();
3051 q->updateInputMethod();
3057 Applies the given input method event \a event to the text of the line
3060 void QQuickTextInputPrivate::processInputMethodEvent(QInputMethodEvent *event)
3062 Q_Q(QQuickTextInput);
3064 int priorState = -1;
3065 bool isGettingInput = !event->commitString().isEmpty()
3066 || event->preeditString() != preeditAreaText()
3067 || event->replacementLength() > 0;
3068 bool cursorPositionChanged = false;
3069 bool selectionChange = false;
3070 m_preeditDirty = event->preeditString() != preeditAreaText();
3072 if (isGettingInput) {
3073 // If any text is being input, remove selected text.
3074 priorState = m_undoState;
3075 if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit && !m_passwordEchoEditing) {
3076 updatePasswordEchoEditing(true);
3078 m_selend = m_text.length();
3080 removeSelectedText();
3083 int c = m_cursor; // cursor position after insertion of commit string
3084 if (event->replacementStart() <= 0)
3085 c += event->commitString().length() - qMin(-event->replacementStart(), event->replacementLength());
3087 m_cursor += event->replacementStart();
3091 // insert commit string
3092 if (event->replacementLength()) {
3093 m_selstart = m_cursor;
3094 m_selend = m_selstart + event->replacementLength();
3095 m_selend = qMin(m_selend, m_text.length());
3096 removeSelectedText();
3098 if (!event->commitString().isEmpty()) {
3099 internalInsert(event->commitString());
3100 cursorPositionChanged = true;
3103 m_cursor = qBound(0, c, m_text.length());
3105 for (int i = 0; i < event->attributes().size(); ++i) {
3106 const QInputMethodEvent::Attribute &a = event->attributes().at(i);
3107 if (a.type == QInputMethodEvent::Selection) {
3108 m_cursor = qBound(0, a.start + a.length, m_text.length());
3110 m_selstart = qMax(0, qMin(a.start, m_text.length()));
3111 m_selend = m_cursor;
3112 if (m_selend < m_selstart) {
3113 qSwap(m_selstart, m_selend);
3115 selectionChange = true;
3117 m_selstart = m_selend = 0;
3119 cursorPositionChanged = true;
3123 m_textLayout.setPreeditArea(m_cursor, event->preeditString());
3125 const int oldPreeditCursor = m_preeditCursor;
3126 m_preeditCursor = event->preeditString().length();
3127 m_hideCursor = false;
3128 QList<QTextLayout::FormatRange> formats;
3129 for (int i = 0; i < event->attributes().size(); ++i) {
3130 const QInputMethodEvent::Attribute &a = event->attributes().at(i);
3131 if (a.type == QInputMethodEvent::Cursor) {
3132 m_preeditCursor = a.start;
3133 m_hideCursor = !a.length;
3134 } else if (a.type == QInputMethodEvent::TextFormat) {
3135 QTextCharFormat f = qvariant_cast<QTextFormat>(a.value).toCharFormat();
3137 QTextLayout::FormatRange o;
3138 o.start = a.start + m_cursor;
3139 o.length = a.length;
3145 m_textLayout.setAdditionalFormats(formats);
3147 updateDisplayText(/*force*/ true);
3148 if (cursorPositionChanged) {
3149 emitCursorPositionChanged();
3150 } else if (m_preeditCursor != oldPreeditCursor) {
3151 q->updateCursorRectangle();
3155 finishChange(priorState);
3157 if (selectionChange) {
3158 emit q->selectionChanged();
3159 q->updateInputMethod(Qt::ImCursorRectangle | Qt::ImAnchorPosition
3160 | Qt::ImCursorPosition | Qt::ImCurrentSelection);
3167 Sets the selection to cover the word at the given cursor position.
3168 The word boundaries are defined by the behavior of QTextLayout::SkipWords
3171 void QQuickTextInputPrivate::selectWordAtPos(int cursor)
3173 int next = cursor + 1;
3176 int c = m_textLayout.previousCursorPosition(next, QTextLayout::SkipWords);
3177 moveCursor(c, false);
3178 // ## text layout should support end of words.
3179 int end = m_textLayout.nextCursorPosition(c, QTextLayout::SkipWords);
3180 while (end > cursor && m_text[end-1].isSpace())
3182 moveCursor(end, true);
3188 Completes a change to the line control text. If the change is not valid
3189 will undo the line control state back to the given \a validateFromState.
3191 If \a edited is true and the change is valid, will emit textEdited() in
3192 addition to textChanged(). Otherwise only emits textChanged() on a valid
3195 The \a update value is currently unused.
3197 bool QQuickTextInputPrivate::finishChange(int validateFromState, bool update, bool /*edited*/)
3199 Q_Q(QQuickTextInput);
3202 bool inputMethodAttributesChanged = m_textDirty || m_selDirty;
3203 bool alignmentChanged = false;
3207 bool wasValidInput = m_validInput;
3208 bool wasAcceptable = m_acceptableInput;
3209 m_validInput = true;
3210 m_acceptableInput = true;
3211 #ifndef QT_NO_VALIDATOR
3213 QString textCopy = m_text;
3214 int cursorCopy = m_cursor;
3215 QValidator::State state = m_validator->validate(textCopy, cursorCopy);
3216 m_validInput = state != QValidator::Invalid;
3217 m_acceptableInput = state == QValidator::Acceptable;
3219 if (m_text != textCopy) {
3220 internalSetText(textCopy, cursorCopy);
3223 m_cursor = cursorCopy;
3227 if (validateFromState >= 0 && wasValidInput && !m_validInput) {
3228 if (m_transactions.count())
3230 internalUndo(validateFromState);
3231 m_history.resize(m_undoState);
3232 m_validInput = true;
3233 m_acceptableInput = wasAcceptable;
3234 m_textDirty = false;
3238 m_textDirty = false;
3239 m_preeditDirty = false;
3240 alignmentChanged = determineHorizontalAlignment();
3241 emit q->textChanged();
3244 updateDisplayText(alignmentChanged);
3246 if (m_acceptableInput != wasAcceptable)
3247 emit q->acceptableInputChanged();
3249 if (m_preeditDirty) {
3250 m_preeditDirty = false;
3251 if (determineHorizontalAlignment()) {
3252 alignmentChanged = true;
3259 emit q->selectionChanged();
3262 inputMethodAttributesChanged |= (m_cursor == m_lastCursorPos);
3263 if (inputMethodAttributesChanged)
3264 q->updateInputMethod();
3265 emitUndoRedoChanged();
3267 if (!emitCursorPositionChanged() && alignmentChanged)
3268 q->updateCursorRectangle();
3276 An internal function for setting the text of the line control.
3278 void QQuickTextInputPrivate::internalSetText(const QString &txt, int pos, bool edited)
3280 Q_Q(QQuickTextInput);
3282 QString oldText = m_text;
3284 m_text = maskString(0, txt, true);
3285 m_text += clearString(m_text.length(), m_maxLength - m_text.length());
3287 m_text = txt.isEmpty() ? txt : txt.left(m_maxLength);
3291 m_cursor = (pos < 0 || pos > m_text.length()) ? m_text.length() : pos;
3292 m_textDirty = (oldText != m_text);
3294 bool changed = finishChange(-1, true, edited);
3295 #ifdef QT_NO_ACCESSIBILITY
3299 QAccessibleTextUpdateEvent ev(q, 0, oldText, m_text);
3300 QAccessible::updateAccessibility(&ev);
3309 Adds the given \a command to the undo history
3310 of the line control. Does not apply the command.
3312 void QQuickTextInputPrivate::addCommand(const Command &cmd)
3314 if (m_separator && m_undoState && m_history[m_undoState - 1].type != Separator) {
3315 m_history.resize(m_undoState + 2);
3316 m_history[m_undoState++] = Command(Separator, m_cursor, 0, m_selstart, m_selend);
3318 m_history.resize(m_undoState + 1);
3320 m_separator = false;
3321 m_history[m_undoState++] = cmd;
3327 Inserts the given string \a s into the line
3330 Also adds the appropriate commands into the undo history.
3331 This function does not call finishChange(), and may leave the text
3332 in an invalid state.
3334 void QQuickTextInputPrivate::internalInsert(const QString &s)
3336 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
3337 Q_Q(QQuickTextInput);
3338 if (m_echoMode == QQuickTextInput::Password)
3339 m_passwordEchoTimer.start(qt_passwordEchoDelay, q);
3341 if (hasSelectedText())
3342 addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
3344 QString ms = maskString(m_cursor, s);
3345 for (int i = 0; i < (int) ms.length(); ++i) {
3346 addCommand (Command(DeleteSelection, m_cursor + i, m_text.at(m_cursor + i), -1, -1));
3347 addCommand(Command(Insert, m_cursor + i, ms.at(i), -1, -1));
3349 m_text.replace(m_cursor, ms.length(), ms);
3350 m_cursor += ms.length();
3351 m_cursor = nextMaskBlank(m_cursor);
3354 int remaining = m_maxLength - m_text.length();
3355 if (remaining != 0) {
3356 m_text.insert(m_cursor, s.left(remaining));
3357 for (int i = 0; i < (int) s.left(remaining).length(); ++i)
3358 addCommand(Command(Insert, m_cursor++, s.at(i), -1, -1));
3367 deletes a single character from the current text. If \a wasBackspace,
3368 the character prior to the cursor is removed. Otherwise the character
3369 after the cursor is removed.
3371 Also adds the appropriate commands into the undo history.
3372 This function does not call finishChange(), and may leave the text
3373 in an invalid state.
3375 void QQuickTextInputPrivate::internalDelete(bool wasBackspace)
3377 if (m_cursor < (int) m_text.length()) {
3378 cancelPasswordEchoTimer();
3379 if (hasSelectedText())
3380 addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
3381 addCommand(Command((CommandType)((m_maskData ? 2 : 0) + (wasBackspace ? Remove : Delete)),
3382 m_cursor, m_text.at(m_cursor), -1, -1));
3384 m_text.replace(m_cursor, 1, clearString(m_cursor, 1));
3385 addCommand(Command(Insert, m_cursor, m_text.at(m_cursor), -1, -1));
3387 m_text.remove(m_cursor, 1);
3396 removes the currently selected text from the line control.
3398 Also adds the appropriate commands into the undo history.
3399 This function does not call finishChange(), and may leave the text
3400 in an invalid state.
3402 void QQuickTextInputPrivate::removeSelectedText()
3404 if (m_selstart < m_selend && m_selend <= (int) m_text.length()) {
3405 cancelPasswordEchoTimer();
3408 addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
3409 if (m_selstart <= m_cursor && m_cursor < m_selend) {
3410 // cursor is within the selection. Split up the commands
3411 // to be able to restore the correct cursor position
3412 for (i = m_cursor; i >= m_selstart; --i)
3413 addCommand (Command(DeleteSelection, i, m_text.at(i), -1, 1));
3414 for (i = m_selend - 1; i > m_cursor; --i)
3415 addCommand (Command(DeleteSelection, i - m_cursor + m_selstart - 1, m_text.at(i), -1, -1));
3417 for (i = m_selend-1; i >= m_selstart; --i)
3418 addCommand (Command(RemoveSelection, i, m_text.at(i), -1, -1));
3421 m_text.replace(m_selstart, m_selend - m_selstart, clearString(m_selstart, m_selend - m_selstart));
3422 for (int i = 0; i < m_selend - m_selstart; ++i)
3423 addCommand(Command(Insert, m_selstart + i, m_text.at(m_selstart + i), -1, -1));
3425 m_text.remove(m_selstart, m_selend - m_selstart);
3427 if (m_cursor > m_selstart)
3428 m_cursor -= qMin(m_cursor, m_selend) - m_selstart;
3437 Parses the input mask specified by \a maskFields to generate
3438 the mask data used to handle input masks.
3440 void QQuickTextInputPrivate::parseInputMask(const QString &maskFields)
3442 int delimiter = maskFields.indexOf(QLatin1Char(';'));
3443 if (maskFields.isEmpty() || delimiter == 0) {
3445 delete [] m_maskData;
3447 m_maxLength = 32767;
3448 internalSetText(QString());
3453 if (delimiter == -1) {
3454 m_blank = QLatin1Char(' ');
3455 m_inputMask = maskFields;
3457 m_inputMask = maskFields.left(delimiter);
3458 m_blank = (delimiter + 1 < maskFields.length()) ? maskFields[delimiter + 1] : QLatin1Char(' ');
3461 // calculate m_maxLength / m_maskData length
3464 for (int i=0; i<m_inputMask.length(); i++) {
3465 c = m_inputMask.at(i);
3466 if (i > 0 && m_inputMask.at(i-1) == QLatin1Char('\\')) {
3470 if (c != QLatin1Char('\\') && c != QLatin1Char('!') &&
3471 c != QLatin1Char('<') && c != QLatin1Char('>') &&
3472 c != QLatin1Char('{') && c != QLatin1Char('}') &&
3473 c != QLatin1Char('[') && c != QLatin1Char(']'))
3477 delete [] m_maskData;
3478 m_maskData = new MaskInputData[m_maxLength];
3480 MaskInputData::Casemode m = MaskInputData::NoCaseMode;
3483 bool escape = false;
3485 for (int i = 0; i < m_inputMask.length(); i++) {
3486 c = m_inputMask.at(i);
3489 m_maskData[index].maskChar = c;
3490 m_maskData[index].separator = s;
3491 m_maskData[index].caseMode = m;
3494 } else if (c == QLatin1Char('<')) {
3495 m = MaskInputData::Lower;
3496 } else if (c == QLatin1Char('>')) {
3497 m = MaskInputData::Upper;
3498 } else if (c == QLatin1Char('!')) {
3499 m = MaskInputData::NoCaseMode;
3500 } else if (c != QLatin1Char('{') && c != QLatin1Char('}') && c != QLatin1Char('[') && c != QLatin1Char(']')) {
3501 switch (c.unicode()) {
3527 m_maskData[index].maskChar = c;
3528 m_maskData[index].separator = s;
3529 m_maskData[index].caseMode = m;
3534 internalSetText(m_text);
3541 checks if the key is valid compared to the inputMask
3543 bool QQuickTextInputPrivate::isValidInput(QChar key, QChar mask) const
3545 switch (mask.unicode()) {
3551 if (key.isLetter() || key == m_blank)
3555 if (key.isLetterOrNumber())
3559 if (key.isLetterOrNumber() || key == m_blank)
3567 if (key.isPrint() || key == m_blank)
3575 if (key.isNumber() || key == m_blank)
3579 if (key.isNumber() && key.digitValue() > 0)
3583 if ((key.isNumber() && key.digitValue() > 0) || key == m_blank)
3587 if (key.isNumber() || key == QLatin1Char('+') || key == QLatin1Char('-') || key == m_blank)
3591 if (key == QLatin1Char('0') || key == QLatin1Char('1'))
3595 if (key == QLatin1Char('0') || key == QLatin1Char('1') || key == m_blank)
3599 if (key.isNumber() || (key >= QLatin1Char('a') && key <= QLatin1Char('f')) || (key >= QLatin1Char('A') && key <= QLatin1Char('F')))
3603 if (key.isNumber() || (key >= QLatin1Char('a') && key <= QLatin1Char('f')) || (key >= QLatin1Char('A') && key <= QLatin1Char('F')) || key == m_blank)
3615 Returns true if the given text \a str is valid for any
3616 validator or input mask set for the line control.
3618 Otherwise returns false
3620 QQuickTextInputPrivate::ValidatorState QQuickTextInputPrivate::hasAcceptableInput(const QString &str) const
3622 #ifndef QT_NO_VALIDATOR
3623 QString textCopy = str;
3624 int cursorCopy = m_cursor;
3626 QValidator::State state = m_validator->validate(textCopy, cursorCopy);
3627 if (state != QValidator::Acceptable)
3628 return ValidatorState(state);
3633 return AcceptableInput;
3635 if (str.length() != m_maxLength)
3636 return InvalidInput;
3638 for (int i=0; i < m_maxLength; ++i) {
3639 if (m_maskData[i].separator) {
3640 if (str.at(i) != m_maskData[i].maskChar)
3641 return InvalidInput;
3643 if (!isValidInput(str.at(i), m_maskData[i].maskChar))
3644 return InvalidInput;
3647 return AcceptableInput;
3653 Applies the inputMask on \a str starting from position \a pos in the mask. \a clear
3654 specifies from where characters should be gotten when a separator is met in \a str - true means
3655 that blanks will be used, false that previous input is used.
3656 Calling this when no inputMask is set is undefined.
3658 QString QQuickTextInputPrivate::maskString(uint pos, const QString &str, bool clear) const
3660 if (pos >= (uint)m_maxLength)
3661 return QString::fromLatin1("");
3664 fill = clear ? clearString(0, m_maxLength) : m_text;
3667 QString s = QString::fromLatin1("");
3669 while (i < m_maxLength) {
3670 if (strIndex < str.length()) {
3671 if (m_maskData[i].separator) {
3672 s += m_maskData[i].maskChar;
3673 if (str[(int)strIndex] == m_maskData[i].maskChar)
3677 if (isValidInput(str[(int)strIndex], m_maskData[i].maskChar)) {
3678 switch (m_maskData[i].caseMode) {
3679 case MaskInputData::Upper:
3680 s += str[(int)strIndex].toUpper();
3682 case MaskInputData::Lower:
3683 s += str[(int)strIndex].toLower();
3686 s += str[(int)strIndex];
3690 // search for separator first
3691 int n = findInMask(i, true, true, str[(int)strIndex]);
3693 if (str.length() != 1 || i == 0 || (i > 0 && (!m_maskData[i-1].separator || m_maskData[i-1].maskChar != str[(int)strIndex]))) {
3694 s += fill.mid(i, n-i+1);
3695 i = n + 1; // update i to find + 1
3698 // search for valid m_blank if not
3699 n = findInMask(i, true, false, str[(int)strIndex]);
3701 s += fill.mid(i, n-i);
3702 switch (m_maskData[n].caseMode) {
3703 case MaskInputData::Upper:
3704 s += str[(int)strIndex].toUpper();
3706 case MaskInputData::Lower:
3707 s += str[(int)strIndex].toLower();
3710 s += str[(int)strIndex];
3712 i = n + 1; // updates i to find + 1
3730 Returns a "cleared" string with only separators and blank chars.
3731 Calling this when no inputMask is set is undefined.
3733 QString QQuickTextInputPrivate::clearString(uint pos, uint len) const
3735 if (pos >= (uint)m_maxLength)
3739 int end = qMin((uint)m_maxLength, pos + len);
3740 for (int i = pos; i < end; ++i)
3741 if (m_maskData[i].separator)
3742 s += m_maskData[i].maskChar;
3752 Strips blank parts of the input in a QQuickTextInputPrivate when an inputMask is set,
3753 separators are still included. Typically "127.0__.0__.1__" becomes "127.0.0.1".
3755 QString QQuickTextInputPrivate::stripString(const QString &str) const
3761 int end = qMin(m_maxLength, (int)str.length());
3762 for (int i = 0; i < end; ++i) {
3763 if (m_maskData[i].separator)
3764 s += m_maskData[i].maskChar;
3765 else if (str[i] != m_blank)
3774 searches forward/backward in m_maskData for either a separator or a m_blank
3776 int QQuickTextInputPrivate::findInMask(int pos, bool forward, bool findSeparator, QChar searchChar) const
3778 if (pos >= m_maxLength || pos < 0)
3781 int end = forward ? m_maxLength : -1;
3782 int step = forward ? 1 : -1;
3786 if (findSeparator) {
3787 if (m_maskData[i].separator && m_maskData[i].maskChar == searchChar)
3790 if (!m_maskData[i].separator) {
3791 if (searchChar.isNull())
3793 else if (isValidInput(searchChar, m_maskData[i].maskChar))
3802 void QQuickTextInputPrivate::internalUndo(int until)
3804 if (!isUndoAvailable())
3806 cancelPasswordEchoTimer();
3808 while (m_undoState && m_undoState > until) {
3809 Command& cmd = m_history[--m_undoState];
3812 m_text.remove(cmd.pos, 1);
3816 m_selstart = cmd.selStart;
3817 m_selend = cmd.selEnd;
3821 case RemoveSelection:
3822 m_text.insert(cmd.pos, cmd.uc);
3823 m_cursor = cmd.pos + 1;
3826 case DeleteSelection:
3827 m_text.insert(cmd.pos, cmd.uc);
3833 if (until < 0 && m_undoState) {
3834 Command& next = m_history[m_undoState-1];
3835 if (next.type != cmd.type && next.type < RemoveSelection
3836 && (cmd.type < RemoveSelection || next.type == Separator))
3843 void QQuickTextInputPrivate::internalRedo()
3845 if (!isRedoAvailable())
3848 while (m_undoState < (int)m_history.size()) {
3849 Command& cmd = m_history[m_undoState++];
3852 m_text.insert(cmd.pos, cmd.uc);
3853 m_cursor = cmd.pos + 1;
3856 m_selstart = cmd.selStart;
3857 m_selend = cmd.selEnd;
3862 case RemoveSelection:
3863 case DeleteSelection:
3864 m_text.remove(cmd.pos, 1);
3865 m_selstart = cmd.selStart;
3866 m_selend = cmd.selEnd;
3870 m_selstart = cmd.selStart;
3871 m_selend = cmd.selEnd;
3875 if (m_undoState < (int)m_history.size()) {
3876 Command& next = m_history[m_undoState];
3877 if (next.type != cmd.type && cmd.type < RemoveSelection && next.type != Separator
3878 && (next.type < RemoveSelection || cmd.type == Separator))
3885 void QQuickTextInputPrivate::emitUndoRedoChanged()
3887 Q_Q(QQuickTextInput);
3888 const bool previousUndo = canUndo;
3889 const bool previousRedo = canRedo;
3891 canUndo = isUndoAvailable();
3892 canRedo = isRedoAvailable();
3894 if (previousUndo != canUndo)
3895 emit q->canUndoChanged();
3896 if (previousRedo != canRedo)
3897 emit q->canRedoChanged();
3903 If the current cursor position differs from the last emitted cursor
3904 position, emits cursorPositionChanged().
3906 bool QQuickTextInputPrivate::emitCursorPositionChanged()
3908 Q_Q(QQuickTextInput);
3909 if (m_cursor != m_lastCursorPos) {
3910 m_lastCursorPos = m_cursor;
3912 q->updateCursorRectangle();
3913 emit q->cursorPositionChanged();
3915 if (!hasSelectedText()) {
3916 if (lastSelectionStart != m_cursor) {
3917 lastSelectionStart = m_cursor;
3918 emit q->selectionStartChanged();
3920 if (lastSelectionEnd != m_cursor) {
3921 lastSelectionEnd = m_cursor;
3922 emit q->selectionEndChanged();
3926 #ifndef QT_NO_ACCESSIBILITY
3927 QAccessibleTextCursorEvent ev(q, m_cursor);
3928 QAccessible::updateAccessibility(&ev);
3937 void QQuickTextInputPrivate::setCursorBlinkPeriod(int msec)
3939 Q_Q(QQuickTextInput);
3940 if (msec == m_blinkPeriod)
3943 q->killTimer(m_blinkTimer);
3946 m_blinkTimer = q->startTimer(msec / 2);
3950 if (m_blinkStatus == 1) {
3951 updateType = UpdatePaintNode;
3955 m_blinkPeriod = msec;
3958 void QQuickTextInput::timerEvent(QTimerEvent *event)
3960 Q_D(QQuickTextInput);
3961 if (event->timerId() == d->m_blinkTimer) {
3962 d->m_blinkStatus = !d->m_blinkStatus;
3963 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
3965 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
3966 } else if (event->timerId() == d->m_passwordEchoTimer.timerId()) {
3967 d->m_passwordEchoTimer.stop();
3968 d->updateDisplayText();
3973 void QQuickTextInputPrivate::processKeyEvent(QKeyEvent* event)
3975 Q_Q(QQuickTextInput);
3976 bool inlineCompletionAccepted = false;
3978 if (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return) {
3979 if (hasAcceptableInput(m_text) || fixup()) {
3982 if (inlineCompletionAccepted)
3989 if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit
3990 && !m_passwordEchoEditing
3992 && !event->text().isEmpty()
3993 && !(event->modifiers() & Qt::ControlModifier)) {
3994 // Clear the edit and reset to normal echo mode while editing; the
3995 // echo mode switches back when the edit loses focus
3996 // ### resets current content. dubious code; you can
3997 // navigate with keys up, down, back, and select(?), but if you press
3998 // "left" or "right" it clears?
3999 updatePasswordEchoEditing(true);
4003 bool unknown = false;
4004 bool visual = cursorMoveStyle() == Qt::VisualMoveStyle;
4008 #ifndef QT_NO_SHORTCUT
4009 else if (event == QKeySequence::Undo) {
4012 else if (event == QKeySequence::Redo) {
4015 else if (event == QKeySequence::SelectAll) {
4018 #ifndef QT_NO_CLIPBOARD
4019 else if (event == QKeySequence::Copy) {
4022 else if (event == QKeySequence::Paste) {
4024 QClipboard::Mode mode = QClipboard::Clipboard;
4028 else if (event == QKeySequence::Cut) {
4034 else if (event == QKeySequence::DeleteEndOfLine) {
4036 setSelection(m_cursor, end());
4041 #endif //QT_NO_CLIPBOARD
4042 else if (event == QKeySequence::MoveToStartOfLine || event == QKeySequence::MoveToStartOfBlock) {
4045 else if (event == QKeySequence::MoveToEndOfLine || event == QKeySequence::MoveToEndOfBlock) {
4048 else if (event == QKeySequence::SelectStartOfLine || event == QKeySequence::SelectStartOfBlock) {
4051 else if (event == QKeySequence::SelectEndOfLine || event == QKeySequence::SelectEndOfBlock) {
4054 else if (event == QKeySequence::MoveToNextChar) {
4055 if (hasSelectedText()) {
4056 moveCursor(selectionEnd(), false);
4058 cursorForward(0, visual ? 1 : (layoutDirection() == Qt::LeftToRight ? 1 : -1));
4061 else if (event == QKeySequence::SelectNextChar) {
4062 cursorForward(1, visual ? 1 : (layoutDirection() == Qt::LeftToRight ? 1 : -1));
4064 else if (event == QKeySequence::MoveToPreviousChar) {
4065 if (hasSelectedText()) {
4066 moveCursor(selectionStart(), false);
4068 cursorForward(0, visual ? -1 : (layoutDirection() == Qt::LeftToRight ? -1 : 1));
4071 else if (event == QKeySequence::SelectPreviousChar) {
4072 cursorForward(1, visual ? -1 : (layoutDirection() == Qt::LeftToRight ? -1 : 1));
4074 else if (event == QKeySequence::MoveToNextWord) {
4075 if (m_echoMode == QQuickTextInput::Normal)
4076 layoutDirection() == Qt::LeftToRight ? cursorWordForward(0) : cursorWordBackward(0);
4078 layoutDirection() == Qt::LeftToRight ? end(0) : home(0);
4080 else if (event == QKeySequence::MoveToPreviousWord) {
4081 if (m_echoMode == QQuickTextInput::Normal)
4082 layoutDirection() == Qt::LeftToRight ? cursorWordBackward(0) : cursorWordForward(0);
4083 else if (!m_readOnly) {
4084 layoutDirection() == Qt::LeftToRight ? home(0) : end(0);
4087 else if (event == QKeySequence::SelectNextWord) {
4088 if (m_echoMode == QQuickTextInput::Normal)
4089 layoutDirection() == Qt::LeftToRight ? cursorWordForward(1) : cursorWordBackward(1);
4091 layoutDirection() == Qt::LeftToRight ? end(1) : home(1);
4093 else if (event == QKeySequence::SelectPreviousWord) {
4094 if (m_echoMode == QQuickTextInput::Normal)
4095 layoutDirection() == Qt::LeftToRight ? cursorWordBackward(1) : cursorWordForward(1);
4097 layoutDirection() == Qt::LeftToRight ? home(1) : end(1);
4099 else if (event == QKeySequence::Delete) {
4103 else if (event == QKeySequence::DeleteEndOfWord) {
4105 cursorWordForward(true);
4109 else if (event == QKeySequence::DeleteStartOfWord) {
4111 cursorWordBackward(true);
4115 #endif // QT_NO_SHORTCUT
4117 bool handled = false;
4118 if (event->modifiers() & Qt::ControlModifier) {
4119 switch (event->key()) {
4120 case Qt::Key_Backspace:
4122 cursorWordBackward(true);
4130 } else { // ### check for *no* modifier
4131 switch (event->key()) {
4132 case Qt::Key_Backspace:
4144 if (event->key() == Qt::Key_Direction_L || event->key() == Qt::Key_Direction_R) {
4145 setLayoutDirection((event->key() == Qt::Key_Direction_L) ? Qt::LeftToRight : Qt::RightToLeft);
4149 if (unknown && !m_readOnly) {
4150 QString t = event->text();
4151 if (!t.isEmpty() && t.at(0).isPrint()) {