1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the QtQml module of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #include "qquicktextinput_p.h"
43 #include "qquicktextinput_p_p.h"
44 #include "qquickcanvas.h"
46 #include <private/qqmlglobal_p.h>
48 #include <QtCore/qcoreapplication.h>
49 #include <QtQml/qqmlinfo.h>
50 #include <QtGui/qevent.h>
51 #include <QTextBoundaryFinder>
52 #include "qquicktextnode_p.h"
53 #include <QtQuick/qsgsimplerectnode.h>
55 #include <QtGui/qstylehints.h>
56 #include <QtGui/qinputmethod.h>
58 #ifndef QT_NO_ACCESSIBILITY
59 #include "qaccessible.h"
64 DEFINE_BOOL_CONFIG_OPTION(qmlDisableDistanceField, QML_DISABLE_DISTANCEFIELD)
67 \qmlclass TextInput QQuickTextInput
68 \inqmlmodule QtQuick 2
69 \ingroup qml-basic-visual-elements
70 \brief The TextInput item displays an editable line of text.
73 The TextInput element displays a single line of editable plain text.
75 TextInput is used to accept a line of text input. Input constraints
76 can be placed on a TextInput item (for example, through a \l validator or \l inputMask),
77 and setting \l echoMode to an appropriate value enables TextInput to be used for
78 a password input field.
80 On Mac OS X, the Up/Down key bindings for Home/End are explicitly disabled.
81 If you want such bindings (on any platform), you will need to construct them in QML.
83 \sa TextEdit, Text, {declarative/text/textselection}{Text Selection example}
85 QQuickTextInput::QQuickTextInput(QQuickItem* parent)
86 : QQuickImplicitSizeItem(*(new QQuickTextInputPrivate), parent)
92 QQuickTextInput::~QQuickTextInput()
96 void QQuickTextInput::componentComplete()
100 QQuickImplicitSizeItem::componentComplete();
104 updateCursorRectangle();
105 if (d->cursorComponent && d->cursorComponent->isReady())
110 \qmlproperty string QtQuick2::TextInput::text
112 The text in the TextInput.
114 QString QQuickTextInput::text() const
116 Q_D(const QQuickTextInput);
118 QString content = d->m_text;
119 QString res = d->m_maskData ? d->stripString(content) : content;
120 return (res.isNull() ? QString::fromLatin1("") : res);
123 void QQuickTextInput::setText(const QString &s)
125 Q_D(QQuickTextInput);
130 d->internalSetText(s, -1, false);
134 \qmlproperty int QtQuick2::TextInput::length
136 Returns the total number of characters in the TextInput item.
138 If the TextInput has an inputMask the length will include mask characters and may differ
139 from the length of the string returned by the \l text property.
141 This property can be faster than querying the length the \l text property as it doesn't
142 require any copying or conversion of the TextInput's internal string data.
145 int QQuickTextInput::length() const
147 Q_D(const QQuickTextInput);
148 return d->m_text.length();
152 \qmlmethod string QtQuick2::TextInput::getText(int start, int end)
154 Returns the section of text that is between the \a start and \a end positions.
156 If the TextInput has an inputMask the length will include mask characters.
159 QString QQuickTextInput::getText(int start, int end) const
161 Q_D(const QQuickTextInput);
166 return d->m_text.mid(start, end - start);
169 QString QQuickTextInputPrivate::realText() const
171 QString res = m_maskData ? stripString(m_text) : m_text;
172 return (res.isNull() ? QString::fromLatin1("") : res);
176 \qmlproperty string QtQuick2::TextInput::font.family
178 Sets the family name of the font.
180 The family name is case insensitive and may optionally include a foundry name, e.g. "Helvetica [Cronyx]".
181 If the family is available from more than one foundry and the foundry isn't specified, an arbitrary foundry is chosen.
182 If the family isn't available a family will be set using the font matching algorithm.
186 \qmlproperty bool QtQuick2::TextInput::font.bold
188 Sets whether the font weight is bold.
192 \qmlproperty enumeration QtQuick2::TextInput::font.weight
194 Sets the font's weight.
196 The weight can be one of:
199 \li Font.Normal - the default
206 TextInput { text: "Hello"; font.weight: Font.DemiBold }
211 \qmlproperty bool QtQuick2::TextInput::font.italic
213 Sets whether the font has an italic style.
217 \qmlproperty bool QtQuick2::TextInput::font.underline
219 Sets whether the text is underlined.
223 \qmlproperty bool QtQuick2::TextInput::font.strikeout
225 Sets whether the font has a strikeout style.
229 \qmlproperty real QtQuick2::TextInput::font.pointSize
231 Sets the font size in points. The point size must be greater than zero.
235 \qmlproperty int QtQuick2::TextInput::font.pixelSize
237 Sets the font size in pixels.
239 Using this function makes the font device dependent.
240 Use \c pointSize to set the size of the font in a device independent manner.
244 \qmlproperty real QtQuick2::TextInput::font.letterSpacing
246 Sets the letter spacing for the font.
248 Letter spacing changes the default spacing between individual letters in the font.
249 A positive value increases the letter spacing by the corresponding pixels; a negative value decreases the spacing.
253 \qmlproperty real QtQuick2::TextInput::font.wordSpacing
255 Sets the word spacing for the font.
257 Word spacing changes the default spacing between individual words.
258 A positive value increases the word spacing by a corresponding amount of pixels,
259 while a negative value decreases the inter-word spacing accordingly.
263 \qmlproperty enumeration QtQuick2::TextInput::font.capitalization
265 Sets the capitalization for the text.
268 \li Font.MixedCase - This is the normal text rendering option where no capitalization change is applied.
269 \li Font.AllUppercase - This alters the text to be rendered in all uppercase type.
270 \li Font.AllLowercase - This alters the text to be rendered in all lowercase type.
271 \li Font.SmallCaps - This alters the text to be rendered in small-caps type.
272 \li Font.Capitalize - This alters the text to be rendered with the first character of each word as an uppercase character.
276 TextInput { text: "Hello"; font.capitalization: Font.AllLowercase }
280 QFont QQuickTextInput::font() const
282 Q_D(const QQuickTextInput);
283 return d->sourceFont;
286 void QQuickTextInput::setFont(const QFont &font)
288 Q_D(QQuickTextInput);
289 if (d->sourceFont == font)
292 d->sourceFont = font;
293 QFont oldFont = d->font;
295 if (d->font.pointSizeF() != -1) {
297 qreal size = qRound(d->font.pointSizeF()*2.0);
298 d->font.setPointSizeF(size/2.0);
300 if (oldFont != d->font) {
302 updateCursorRectangle();
303 updateInputMethod(Qt::ImCursorRectangle | Qt::ImFont);
305 emit fontChanged(d->sourceFont);
309 \qmlproperty color QtQuick2::TextInput::color
313 QColor QQuickTextInput::color() const
315 Q_D(const QQuickTextInput);
319 void QQuickTextInput::setColor(const QColor &c)
321 Q_D(QQuickTextInput);
324 d->textLayoutDirty = true;
325 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
333 \qmlproperty color QtQuick2::TextInput::selectionColor
335 The text highlight color, used behind selections.
337 QColor QQuickTextInput::selectionColor() const
339 Q_D(const QQuickTextInput);
340 return d->selectionColor;
343 void QQuickTextInput::setSelectionColor(const QColor &color)
345 Q_D(QQuickTextInput);
346 if (d->selectionColor == color)
349 d->selectionColor = color;
350 if (d->hasSelectedText()) {
351 d->textLayoutDirty = true;
352 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
355 emit selectionColorChanged();
358 \qmlproperty color QtQuick2::TextInput::selectedTextColor
360 The highlighted text color, used in selections.
362 QColor QQuickTextInput::selectedTextColor() const
364 Q_D(const QQuickTextInput);
365 return d->selectedTextColor;
368 void QQuickTextInput::setSelectedTextColor(const QColor &color)
370 Q_D(QQuickTextInput);
371 if (d->selectedTextColor == color)
374 d->selectedTextColor = color;
375 if (d->hasSelectedText()) {
376 d->textLayoutDirty = true;
377 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
380 emit selectedTextColorChanged();
384 \qmlproperty enumeration QtQuick2::TextInput::horizontalAlignment
385 \qmlproperty enumeration QtQuick2::TextInput::effectiveHorizontalAlignment
386 \qmlproperty enumeration QtQuick2::TextInput::verticalAlignment
388 Sets the horizontal alignment of the text within the TextInput item's
389 width and height. By default, the text alignment follows the natural alignment
390 of the text, for example text that is read from left to right will be aligned to
393 TextInput does not have vertical alignment, as the natural height is
394 exactly the height of the single line of text. If you set the height
395 manually to something larger, TextInput will always be top aligned
396 vertically. You can use anchors to align it however you want within
399 The valid values for \c horizontalAlignment are \c TextInput.AlignLeft, \c TextInput.AlignRight and
400 \c TextInput.AlignHCenter.
402 Valid values for \c verticalAlignment are \c TextInput.AlignTop (default),
403 \c TextInput.AlignBottom \c TextInput.AlignVCenter.
405 When using the attached property LayoutMirroring::enabled to mirror application
406 layouts, the horizontal alignment of text will also be mirrored. However, the property
407 \c horizontalAlignment will remain unchanged. To query the effective horizontal alignment
408 of TextInput, use the read-only property \c effectiveHorizontalAlignment.
410 QQuickTextInput::HAlignment QQuickTextInput::hAlign() const
412 Q_D(const QQuickTextInput);
416 void QQuickTextInput::setHAlign(HAlignment align)
418 Q_D(QQuickTextInput);
419 bool forceAlign = d->hAlignImplicit && d->effectiveLayoutMirror;
420 d->hAlignImplicit = false;
421 if (d->setHAlign(align, forceAlign) && isComponentComplete()) {
423 updateCursorRectangle();
427 void QQuickTextInput::resetHAlign()
429 Q_D(QQuickTextInput);
430 d->hAlignImplicit = true;
431 if (d->determineHorizontalAlignment() && isComponentComplete()) {
433 updateCursorRectangle();
437 QQuickTextInput::HAlignment QQuickTextInput::effectiveHAlign() const
439 Q_D(const QQuickTextInput);
440 QQuickTextInput::HAlignment effectiveAlignment = d->hAlign;
441 if (!d->hAlignImplicit && d->effectiveLayoutMirror) {
443 case QQuickTextInput::AlignLeft:
444 effectiveAlignment = QQuickTextInput::AlignRight;
446 case QQuickTextInput::AlignRight:
447 effectiveAlignment = QQuickTextInput::AlignLeft;
453 return effectiveAlignment;
456 bool QQuickTextInputPrivate::setHAlign(QQuickTextInput::HAlignment alignment, bool forceAlign)
458 Q_Q(QQuickTextInput);
459 if ((hAlign != alignment || forceAlign) && alignment <= QQuickTextInput::AlignHCenter) { // justify not supported
460 QQuickTextInput::HAlignment oldEffectiveHAlign = q->effectiveHAlign();
462 emit q->horizontalAlignmentChanged(alignment);
463 if (oldEffectiveHAlign != q->effectiveHAlign())
464 emit q->effectiveHorizontalAlignmentChanged();
470 Qt::LayoutDirection QQuickTextInputPrivate::textDirection() const
472 QString text = m_text;
474 text = m_textLayout.preeditAreaText();
476 const QChar *character = text.constData();
477 while (!character->isNull()) {
478 switch (character->direction()) {
480 return Qt::LeftToRight;
484 return Qt::RightToLeft;
490 return Qt::LayoutDirectionAuto;
493 Qt::LayoutDirection QQuickTextInputPrivate::layoutDirection() const
495 Qt::LayoutDirection direction = m_layoutDirection;
496 if (direction == Qt::LayoutDirectionAuto) {
497 direction = textDirection();
498 if (direction == Qt::LayoutDirectionAuto)
499 direction = qApp->inputMethod()->inputDirection();
501 return (direction == Qt::LayoutDirectionAuto) ? Qt::LeftToRight : direction;
504 bool QQuickTextInputPrivate::determineHorizontalAlignment()
506 if (hAlignImplicit) {
507 // if no explicit alignment has been set, follow the natural layout direction of the text
508 Qt::LayoutDirection direction = textDirection();
509 if (direction == Qt::LayoutDirectionAuto)
510 direction = qApp->inputMethod()->inputDirection();
511 return setHAlign(direction == Qt::RightToLeft ? QQuickTextInput::AlignRight : QQuickTextInput::AlignLeft);
516 QQuickTextInput::VAlignment QQuickTextInput::vAlign() const
518 Q_D(const QQuickTextInput);
522 void QQuickTextInput::setVAlign(QQuickTextInput::VAlignment alignment)
524 Q_D(QQuickTextInput);
525 if (alignment == d->vAlign)
527 d->vAlign = alignment;
528 emit verticalAlignmentChanged(d->vAlign);
529 if (isComponentComplete()) {
530 updateCursorRectangle();
535 \qmlproperty enumeration QtQuick2::TextInput::wrapMode
537 Set this property to wrap the text to the TextInput item's width.
538 The text will only wrap if an explicit width has been set.
541 \li TextInput.NoWrap - no wrapping will be performed. If the text contains insufficient newlines, then implicitWidth will exceed a set width.
542 \li TextInput.WordWrap - wrapping is done on word boundaries only. If a word is too long, implicitWidth will exceed a set width.
543 \li TextInput.WrapAnywhere - wrapping is done at any point on a line, even if it occurs in the middle of a word.
544 \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.
547 The default is TextInput.NoWrap. If you set a width, consider using TextInput.Wrap.
549 QQuickTextInput::WrapMode QQuickTextInput::wrapMode() const
551 Q_D(const QQuickTextInput);
555 void QQuickTextInput::setWrapMode(WrapMode mode)
557 Q_D(QQuickTextInput);
558 if (mode == d->wrapMode)
562 updateCursorRectangle();
563 emit wrapModeChanged();
566 void QQuickTextInputPrivate::mirrorChange()
568 Q_Q(QQuickTextInput);
569 if (q->isComponentComplete()) {
570 if (!hAlignImplicit && (hAlign == QQuickTextInput::AlignRight || hAlign == QQuickTextInput::AlignLeft)) {
571 q->updateCursorRectangle();
572 emit q->effectiveHorizontalAlignmentChanged();
578 \qmlproperty bool QtQuick2::TextInput::readOnly
580 Sets whether user input can modify the contents of the TextInput.
582 If readOnly is set to true, then user input will not affect the text
583 property. Any bindings or attempts to set the text property will still
586 bool QQuickTextInput::isReadOnly() const
588 Q_D(const QQuickTextInput);
589 return d->m_readOnly;
592 void QQuickTextInput::setReadOnly(bool ro)
594 Q_D(QQuickTextInput);
595 if (d->m_readOnly == ro)
598 setFlag(QQuickItem::ItemAcceptsInputMethod, !ro);
601 d->setCursorPosition(d->end());
602 updateInputMethod(Qt::ImEnabled);
604 d->emitUndoRedoChanged();
605 emit readOnlyChanged(ro);
609 \qmlproperty int QtQuick2::TextInput::maximumLength
610 The maximum permitted length of the text in the TextInput.
612 If the text is too long, it is truncated at the limit.
614 By default, this property contains a value of 32767.
616 int QQuickTextInput::maxLength() const
618 Q_D(const QQuickTextInput);
619 return d->m_maxLength;
622 void QQuickTextInput::setMaxLength(int ml)
624 Q_D(QQuickTextInput);
625 if (d->m_maxLength == ml || d->m_maskData)
629 d->internalSetText(d->m_text, -1, false);
631 emit maximumLengthChanged(ml);
635 \qmlproperty bool QtQuick2::TextInput::cursorVisible
636 Set to true when the TextInput shows a cursor.
638 This property is set and unset when the TextInput gets active focus, so that other
639 properties can be bound to whether the cursor is currently showing. As it
640 gets set and unset automatically, when you set the value yourself you must
641 keep in mind that your value may be overwritten.
643 It can be set directly in script, for example if a KeyProxy might
644 forward keys to it and you desire it to look active when this happens
645 (but without actually giving it active focus).
647 It should not be set directly on the element, like in the below QML,
648 as the specified value will be overridden an lost on focus changes.
657 In the above snippet the cursor will still become visible when the
658 TextInput gains active focus.
660 bool QQuickTextInput::isCursorVisible() const
662 Q_D(const QQuickTextInput);
663 return d->cursorVisible;
666 void QQuickTextInput::setCursorVisible(bool on)
668 Q_D(QQuickTextInput);
669 if (d->cursorVisible == on)
671 d->cursorVisible = on;
672 d->setCursorBlinkPeriod(on ? qApp->styleHints()->cursorFlashTime() : 0);
673 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
675 emit cursorVisibleChanged(d->cursorVisible);
679 \qmlproperty int QtQuick2::TextInput::cursorPosition
680 The position of the cursor in the TextInput.
682 int QQuickTextInput::cursorPosition() const
684 Q_D(const QQuickTextInput);
688 void QQuickTextInput::setCursorPosition(int cp)
690 Q_D(QQuickTextInput);
691 if (cp < 0 || cp > text().length())
697 \qmlproperty rectangle QtQuick2::TextInput::cursorRectangle
699 The rectangle where the standard text cursor is rendered within the text input. Read only.
701 The position and height of a custom cursorDelegate are updated to follow the cursorRectangle
702 automatically when it changes. The width of the delegate is unaffected by changes in the
706 QRectF QQuickTextInput::cursorRectangle() const
708 Q_D(const QQuickTextInput);
710 int c = d->m_cursor + d->m_preeditCursor;
711 if (d->m_echoMode == NoEcho)
713 QTextLine l = d->m_textLayout.lineForTextPosition(c);
716 return QRectF(l.cursorToX(c) - d->hscroll, l.y() - d->vscroll, 1, l.height());
720 \qmlproperty int QtQuick2::TextInput::selectionStart
722 The cursor position before the first character in the current selection.
724 This property is read-only. To change the selection, use select(start,end),
725 selectAll(), or selectWord().
727 \sa selectionEnd, cursorPosition, selectedText
729 int QQuickTextInput::selectionStart() const
731 Q_D(const QQuickTextInput);
732 return d->lastSelectionStart;
735 \qmlproperty int QtQuick2::TextInput::selectionEnd
737 The cursor position after the last character in the current selection.
739 This property is read-only. To change the selection, use select(start,end),
740 selectAll(), or selectWord().
742 \sa selectionStart, cursorPosition, selectedText
744 int QQuickTextInput::selectionEnd() const
746 Q_D(const QQuickTextInput);
747 return d->lastSelectionEnd;
750 \qmlmethod void QtQuick2::TextInput::select(int start, int end)
752 Causes the text from \a start to \a end to be selected.
754 If either start or end is out of range, the selection is not changed.
756 After calling this, selectionStart will become the lesser
757 and selectionEnd will become the greater (regardless of the order passed
760 \sa selectionStart, selectionEnd
762 void QQuickTextInput::select(int start, int end)
764 Q_D(QQuickTextInput);
765 if (start < 0 || end < 0 || start > d->m_text.length() || end > d->m_text.length())
767 d->setSelection(start, end-start);
771 \qmlproperty string QtQuick2::TextInput::selectedText
773 This read-only property provides the text currently selected in the
776 It is equivalent to the following snippet, but is faster and easier
780 myTextInput.text.toString().substring(myTextInput.selectionStart,
781 myTextInput.selectionEnd);
784 QString QQuickTextInput::selectedText() const
786 Q_D(const QQuickTextInput);
787 return d->selectedText();
791 \qmlproperty bool QtQuick2::TextInput::activeFocusOnPress
793 Whether the TextInput should gain active focus on a mouse press. By default this is
796 bool QQuickTextInput::focusOnPress() const
798 Q_D(const QQuickTextInput);
799 return d->focusOnPress;
802 void QQuickTextInput::setFocusOnPress(bool b)
804 Q_D(QQuickTextInput);
805 if (d->focusOnPress == b)
810 emit activeFocusOnPressChanged(d->focusOnPress);
813 \qmlproperty bool QtQuick2::TextInput::autoScroll
815 Whether the TextInput should scroll when the text is longer than the width. By default this is
818 bool QQuickTextInput::autoScroll() const
820 Q_D(const QQuickTextInput);
821 return d->autoScroll;
824 void QQuickTextInput::setAutoScroll(bool b)
826 Q_D(QQuickTextInput);
827 if (d->autoScroll == b)
831 //We need to repaint so that the scrolling is taking into account.
832 updateCursorRectangle();
833 emit autoScrollChanged(d->autoScroll);
836 #ifndef QT_NO_VALIDATOR
839 \qmlclass IntValidator QIntValidator
840 \inqmlmodule QtQuick 2
841 \ingroup qml-basic-visual-elements
843 This element provides a validator for integer values.
845 If no \l locale is set IntValidator uses the \l {QLocale::setDefault()}{default locale} to
846 interpret the number and will accept locale specific digits, group separators, and positive
847 and negative signs. In addition, IntValidator is always guaranteed to accept a number
848 formatted according to the "C" locale.
852 QQuickIntValidator::QQuickIntValidator(QObject *parent)
853 : QIntValidator(parent)
858 \qmlproperty string QtQuick2::IntValidator::locale
860 This property holds the name of the locale used to interpret the number.
865 QString QQuickIntValidator::localeName() const
867 return locale().name();
870 void QQuickIntValidator::setLocaleName(const QString &name)
872 if (locale().name() != name) {
873 setLocale(QLocale(name));
874 emit localeNameChanged();
878 void QQuickIntValidator::resetLocaleName()
880 QLocale defaultLocale;
881 if (locale() != defaultLocale) {
882 setLocale(defaultLocale);
883 emit localeNameChanged();
888 \qmlproperty int QtQuick2::IntValidator::top
890 This property holds the validator's highest acceptable value.
891 By default, this property's value is derived from the highest signed integer available (typically 2147483647).
894 \qmlproperty int QtQuick2::IntValidator::bottom
896 This property holds the validator's lowest acceptable value.
897 By default, this property's value is derived from the lowest signed integer available (typically -2147483647).
901 \qmlclass DoubleValidator QDoubleValidator
902 \inqmlmodule QtQuick 2
903 \ingroup qml-basic-visual-elements
905 This element provides a validator for non-integer numbers.
907 Input is accepted if it contains a double that is within the valid range
908 and is in the correct format.
910 Input is accepected but invalid if it contains a double that is outside
911 the range or is in the wrong format; e.g. with too many digits after the
912 decimal point or is empty.
914 Input is rejected if it is not a double.
916 Note: If the valid range consists of just positive doubles (e.g. 0.0 to
917 100.0) and input is a negative double then it is rejected. If \l notation
918 is set to DoubleValidator.StandardNotation, and the input contains more
919 digits before the decimal point than a double in the valid range may have,
920 it is also rejected. If \l notation is DoubleValidator.ScientificNotation,
921 and the input is not in the valid range, it is accecpted but invalid. The
922 value may yet become valid by changing the exponent.
925 QQuickDoubleValidator::QQuickDoubleValidator(QObject *parent)
926 : QDoubleValidator(parent)
931 \qmlproperty string QtQuick2::DoubleValidator::locale
933 This property holds the name of the locale used to interpret the number.
938 QString QQuickDoubleValidator::localeName() const
940 return locale().name();
943 void QQuickDoubleValidator::setLocaleName(const QString &name)
945 if (locale().name() != name) {
946 setLocale(QLocale(name));
947 emit localeNameChanged();
951 void QQuickDoubleValidator::resetLocaleName()
953 QLocale defaultLocale;
954 if (locale() != defaultLocale) {
955 setLocale(defaultLocale);
956 emit localeNameChanged();
961 \qmlproperty real QtQuick2::DoubleValidator::top
963 This property holds the validator's maximum acceptable value.
964 By default, this property contains a value of infinity.
967 \qmlproperty real QtQuick2::DoubleValidator::bottom
969 This property holds the validator's minimum acceptable value.
970 By default, this property contains a value of -infinity.
973 \qmlproperty int QtQuick2::DoubleValidator::decimals
975 This property holds the validator's maximum number of digits after the decimal point.
976 By default, this property contains a value of 1000.
979 \qmlproperty enumeration QtQuick2::DoubleValidator::notation
980 This property holds the notation of how a string can describe a number.
982 The possible values for this property are:
985 \li DoubleValidator.StandardNotation
986 \li DoubleValidator.ScientificNotation (default)
989 If this property is set to DoubleValidator.ScientificNotation, the written number may have an exponent part (e.g. 1.5E-2).
993 \qmlclass RegExpValidator QRegExpValidator
994 \inqmlmodule QtQuick 2
995 \ingroup qml-basic-visual-elements
997 This element provides a validator, which counts as valid any string which
998 matches a specified regular expression.
1001 \qmlproperty regExp QtQuick2::RegExpValidator::regExp
1003 This property holds the regular expression used for validation.
1005 Note that this property should be a regular expression in JS syntax, e.g /a/ for the regular expression
1008 By default, this property contains a regular expression with the pattern .* that matches any string.
1012 \qmlproperty Validator QtQuick2::TextInput::validator
1014 Allows you to set a validator on the TextInput. When a validator is set
1015 the TextInput will only accept input which leaves the text property in
1016 an acceptable or intermediate state. The accepted signal will only be sent
1017 if the text is in an acceptable state when enter is pressed.
1019 Currently supported validators are IntValidator, DoubleValidator and
1020 RegExpValidator. An example of using validators is shown below, which allows
1021 input of integers between 11 and 31 into the text input:
1026 validator: IntValidator{bottom: 11; top: 31;}
1031 \sa acceptableInput, inputMask
1034 QValidator* QQuickTextInput::validator() const
1036 Q_D(const QQuickTextInput);
1037 return d->m_validator;
1040 void QQuickTextInput::setValidator(QValidator* v)
1042 Q_D(QQuickTextInput);
1043 if (d->m_validator == v)
1048 if (isComponentComplete())
1051 emit validatorChanged();
1054 #endif // QT_NO_VALIDATOR
1056 void QQuickTextInputPrivate::checkIsValid()
1058 Q_Q(QQuickTextInput);
1060 ValidatorState state = hasAcceptableInput(m_text);
1061 m_validInput = state != InvalidInput;
1062 if (state != AcceptableInput) {
1063 if (m_acceptableInput) {
1064 m_acceptableInput = false;
1065 emit q->acceptableInputChanged();
1067 } else if (!m_acceptableInput) {
1068 m_acceptableInput = true;
1069 emit q->acceptableInputChanged();
1074 \qmlproperty string QtQuick2::TextInput::inputMask
1076 Allows you to set an input mask on the TextInput, restricting the allowable
1077 text inputs. See QLineEdit::inputMask for further details, as the exact
1078 same mask strings are used by TextInput.
1080 \sa acceptableInput, validator
1082 QString QQuickTextInput::inputMask() const
1084 Q_D(const QQuickTextInput);
1085 return d->inputMask();
1088 void QQuickTextInput::setInputMask(const QString &im)
1090 Q_D(QQuickTextInput);
1091 if (d->inputMask() == im)
1094 d->setInputMask(im);
1095 emit inputMaskChanged(d->inputMask());
1099 \qmlproperty bool QtQuick2::TextInput::acceptableInput
1101 This property is always true unless a validator or input mask has been set.
1102 If a validator or input mask has been set, this property will only be true
1103 if the current text is acceptable to the validator or input mask as a final
1104 string (not as an intermediate string).
1106 bool QQuickTextInput::hasAcceptableInput() const
1108 Q_D(const QQuickTextInput);
1109 return d->hasAcceptableInput(d->m_text) == QQuickTextInputPrivate::AcceptableInput;
1113 \qmlsignal QtQuick2::TextInput::onAccepted()
1115 This handler is called when the Return or Enter key is pressed.
1116 Note that if there is a \l validator or \l inputMask set on the text
1117 input, the handler will only be emitted if the input is in an acceptable
1121 Qt::InputMethodHints QQuickTextInputPrivate::effectiveInputMethodHints() const
1123 Qt::InputMethodHints hints = inputMethodHints;
1124 if (m_echoMode == QQuickTextInput::Password || m_echoMode == QQuickTextInput::NoEcho)
1125 hints |= Qt::ImhHiddenText;
1126 else if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit)
1127 hints &= ~Qt::ImhHiddenText;
1128 if (m_echoMode != QQuickTextInput::Normal)
1129 hints |= (Qt::ImhNoAutoUppercase | Qt::ImhNoPredictiveText | Qt::ImhSensitiveData);
1133 \qmlproperty enumeration QtQuick2::TextInput::echoMode
1135 Specifies how the text should be displayed in the TextInput.
1137 \li TextInput.Normal - Displays the text as it is. (Default)
1138 \li TextInput.Password - Displays asterisks instead of characters.
1139 \li TextInput.NoEcho - Displays nothing.
1140 \li TextInput.PasswordEchoOnEdit - Displays characters as they are entered
1141 while editing, otherwise displays asterisks.
1144 QQuickTextInput::EchoMode QQuickTextInput::echoMode() const
1146 Q_D(const QQuickTextInput);
1147 return QQuickTextInput::EchoMode(d->m_echoMode);
1150 void QQuickTextInput::setEchoMode(QQuickTextInput::EchoMode echo)
1152 Q_D(QQuickTextInput);
1153 if (echoMode() == echo)
1155 d->cancelPasswordEchoTimer();
1156 d->m_echoMode = echo;
1157 d->m_passwordEchoEditing = false;
1158 updateInputMethod(Qt::ImHints);
1159 d->updateDisplayText();
1160 updateCursorRectangle();
1162 emit echoModeChanged(echoMode());
1166 \qmlproperty enumeration QtQuick2::TextInput::inputMethodHints
1168 Provides hints to the input method about the expected content of the text input and how it
1171 The value is a bit-wise combination of flags, or Qt.ImhNone if no hints are set.
1173 Flags that alter behaviour are:
1176 \li Qt.ImhHiddenText - Characters should be hidden, as is typically used when entering passwords.
1177 This is automatically set when setting echoMode to \c TextInput.Password.
1178 \li Qt.ImhSensitiveData - Typed text should not be stored by the active input method
1179 in any persistent storage like predictive user dictionary.
1180 \li Qt.ImhNoAutoUppercase - The input method should not try to automatically switch to upper case
1181 when a sentence ends.
1182 \li Qt.ImhPreferNumbers - Numbers are preferred (but not required).
1183 \li Qt.ImhPreferUppercase - Upper case letters are preferred (but not required).
1184 \li Qt.ImhPreferLowercase - Lower case letters are preferred (but not required).
1185 \li Qt.ImhNoPredictiveText - Do not use predictive text (i.e. dictionary lookup) while typing.
1187 \li Qt.ImhDate - The text editor functions as a date field.
1188 \li Qt.ImhTime - The text editor functions as a time field.
1191 Flags that restrict input (exclusive flags) are:
1194 \li Qt.ImhDigitsOnly - Only digits are allowed.
1195 \li Qt.ImhFormattedNumbersOnly - Only number input is allowed. This includes decimal point and minus sign.
1196 \li Qt.ImhUppercaseOnly - Only upper case letter input is allowed.
1197 \li Qt.ImhLowercaseOnly - Only lower case letter input is allowed.
1198 \li Qt.ImhDialableCharactersOnly - Only characters suitable for phone dialing are allowed.
1199 \li Qt.ImhEmailCharactersOnly - Only characters suitable for email addresses are allowed.
1200 \li Qt.ImhUrlCharactersOnly - Only characters suitable for URLs are allowed.
1206 \li Qt.ImhExclusiveInputMask - This mask yields nonzero if any of the exclusive flags are used.
1210 Qt::InputMethodHints QQuickTextInput::inputMethodHints() const
1212 Q_D(const QQuickTextInput);
1213 return d->inputMethodHints;
1216 void QQuickTextInput::setInputMethodHints(Qt::InputMethodHints hints)
1218 Q_D(QQuickTextInput);
1220 if (hints == d->inputMethodHints)
1223 d->inputMethodHints = hints;
1224 updateInputMethod(Qt::ImHints);
1225 emit inputMethodHintsChanged();
1229 \qmlproperty Component QtQuick2::TextInput::cursorDelegate
1230 The delegate for the cursor in the TextInput.
1232 If you set a cursorDelegate for a TextInput, this delegate will be used for
1233 drawing the cursor instead of the standard cursor. An instance of the
1234 delegate will be created and managed by the TextInput when a cursor is
1235 needed, and the x property of delegate instance will be set so as
1236 to be one pixel before the top left of the current character.
1238 Note that the root item of the delegate component must be a QQuickItem or
1239 QQuickItem derived item.
1241 QQmlComponent* QQuickTextInput::cursorDelegate() const
1243 Q_D(const QQuickTextInput);
1244 return d->cursorComponent;
1247 void QQuickTextInput::setCursorDelegate(QQmlComponent* c)
1249 Q_D(QQuickTextInput);
1250 if (d->cursorComponent == c)
1253 d->cursorComponent = c;
1255 //note that the components are owned by something else
1256 delete d->cursorItem;
1259 d->startCreatingCursor();
1262 emit cursorDelegateChanged();
1265 void QQuickTextInputPrivate::startCreatingCursor()
1267 Q_Q(QQuickTextInput);
1268 if (cursorComponent->isReady()) {
1270 } else if (cursorComponent->isLoading()) {
1271 q->connect(cursorComponent, SIGNAL(statusChanged(int)),
1272 q, SLOT(createCursor()));
1274 qmlInfo(q, cursorComponent->errors()) << QQuickTextInput::tr("Could not load cursor delegate");
1278 void QQuickTextInput::createCursor()
1280 Q_D(QQuickTextInput);
1281 if (!isComponentComplete())
1284 if (d->cursorComponent->isError()) {
1285 qmlInfo(this, d->cursorComponent->errors()) << tr("Could not load cursor delegate");
1289 if (!d->cursorComponent->isReady())
1293 delete d->cursorItem;
1294 QQmlContext *creationContext = d->cursorComponent->creationContext();
1295 QObject *object = d->cursorComponent->create(creationContext ? creationContext : qmlContext(this));
1296 d->cursorItem = qobject_cast<QQuickItem*>(object);
1297 if (!d->cursorItem) {
1299 qmlInfo(this, d->cursorComponent->errors()) << tr("Could not instantiate cursor delegate");
1303 QRectF r = cursorRectangle();
1305 QQml_setParent_noEvent(d->cursorItem, this);
1306 d->cursorItem->setParentItem(this);
1307 d->cursorItem->setPos(r.topLeft());
1308 d->cursorItem->setHeight(r.height());
1312 \qmlmethod rect QtQuick2::TextInput::positionToRectangle(int pos)
1314 This function takes a character position and returns the rectangle that the
1315 cursor would occupy, if it was placed at that character position.
1317 This is similar to setting the cursorPosition, and then querying the cursor
1318 rectangle, but the cursorPosition is not changed.
1320 QRectF QQuickTextInput::positionToRectangle(int pos) const
1322 Q_D(const QQuickTextInput);
1323 if (d->m_echoMode == NoEcho)
1325 else if (pos > d->m_cursor)
1326 pos += d->preeditAreaText().length();
1327 QTextLine l = d->m_textLayout.lineForTextPosition(pos);
1329 ? QRectF(l.cursorToX(pos) - d->hscroll, l.y() - d->vscroll, 1, l.height())
1334 \qmlmethod int QtQuick2::TextInput::positionAt(real x, real y, CursorPosition position = CursorBetweenCharacters)
1336 This function returns the character position at
1337 x and y pixels from the top left of the textInput. Position 0 is before the
1338 first character, position 1 is after the first character but before the second,
1339 and so on until position text.length, which is after all characters.
1341 This means that for all x values before the first character this function returns 0,
1342 and for all x values after the last character this function returns text.length. If
1343 the y value is above the text the position will be that of the nearest character on
1344 the first line line and if it is below the text the position of the nearest character
1345 on the last line will be returned.
1347 The cursor position type specifies how the cursor position should be resolved.
1350 \li TextInput.CursorBetweenCharacters - Returns the position between characters that is nearest x.
1351 \li TextInput.CursorOnCharacter - Returns the position before the character that is nearest x.
1355 void QQuickTextInput::positionAt(QQmlV8Function *args) const
1357 Q_D(const QQuickTextInput);
1361 QTextLine::CursorPosition position = QTextLine::CursorBetweenCharacters;
1363 if (args->Length() < 1)
1367 v8::Local<v8::Value> arg = (*args)[i];
1368 x = arg->NumberValue();
1370 if (++i < args->Length()) {
1372 y = arg->NumberValue();
1375 if (++i < args->Length()) {
1377 position = QTextLine::CursorPosition(arg->Int32Value());
1380 int pos = d->positionAt(x, y, position);
1381 const int cursor = d->m_cursor;
1383 const int preeditLength = d->preeditAreaText().length();
1384 pos = pos > cursor + preeditLength
1385 ? pos - preeditLength
1388 args->returnValue(v8::Int32::New(pos));
1391 int QQuickTextInputPrivate::positionAt(qreal x, qreal y, QTextLine::CursorPosition position) const
1395 QTextLine line = m_textLayout.lineAt(0);
1396 for (int i = 1; i < m_textLayout.lineCount(); ++i) {
1397 QTextLine nextLine = m_textLayout.lineAt(i);
1399 if (y < (line.rect().bottom() + nextLine.y()) / 2)
1403 return line.isValid() ? line.xToCursor(x, position) : 0;
1406 void QQuickTextInput::keyPressEvent(QKeyEvent* ev)
1408 Q_D(QQuickTextInput);
1409 // Don't allow MacOSX up/down support, and we don't allow a completer.
1410 bool ignore = (ev->key() == Qt::Key_Up || ev->key() == Qt::Key_Down) && ev->modifiers() == Qt::NoModifier;
1411 if (!ignore && (d->lastSelectionStart == d->lastSelectionEnd) && (ev->key() == Qt::Key_Right || ev->key() == Qt::Key_Left)) {
1412 // Ignore when moving off the end unless there is a selection,
1413 // because then moving will do something (deselect).
1414 int cursorPosition = d->m_cursor;
1415 if (cursorPosition == 0)
1416 ignore = ev->key() == (d->layoutDirection() == Qt::LeftToRight ? Qt::Key_Left : Qt::Key_Right);
1417 if (!ignore && cursorPosition == text().length())
1418 ignore = ev->key() == (d->layoutDirection() == Qt::LeftToRight ? Qt::Key_Right : Qt::Key_Left);
1423 d->processKeyEvent(ev);
1425 if (!ev->isAccepted())
1426 QQuickImplicitSizeItem::keyPressEvent(ev);
1429 void QQuickTextInput::inputMethodEvent(QInputMethodEvent *ev)
1431 Q_D(QQuickTextInput);
1432 const bool wasComposing = d->hasImState;
1433 if (d->m_readOnly) {
1436 d->processInputMethodEvent(ev);
1438 if (!ev->isAccepted())
1439 QQuickImplicitSizeItem::inputMethodEvent(ev);
1441 if (wasComposing != d->hasImState)
1442 emit inputMethodComposingChanged();
1445 void QQuickTextInput::mouseDoubleClickEvent(QMouseEvent *event)
1447 Q_D(QQuickTextInput);
1449 if (d->selectByMouse && event->button() == Qt::LeftButton) {
1451 int cursor = d->positionAt(event->localPos());
1452 d->selectWordAtPos(cursor);
1453 event->setAccepted(true);
1454 if (!d->hasPendingTripleClick()) {
1455 d->tripleClickStartPoint = event->localPos();
1456 d->tripleClickTimer.start();
1459 if (d->sendMouseEventToInputContext(event))
1461 QQuickImplicitSizeItem::mouseDoubleClickEvent(event);
1465 void QQuickTextInput::mousePressEvent(QMouseEvent *event)
1467 Q_D(QQuickTextInput);
1469 d->pressPos = event->localPos();
1471 if (d->sendMouseEventToInputContext(event))
1474 if (d->selectByMouse) {
1475 setKeepMouseGrab(false);
1476 d->selectPressed = true;
1477 QPointF distanceVector = d->pressPos - d->tripleClickStartPoint;
1478 if (d->hasPendingTripleClick()
1479 && distanceVector.manhattanLength() < qApp->styleHints()->startDragDistance()) {
1480 event->setAccepted(true);
1486 bool mark = (event->modifiers() & Qt::ShiftModifier) && d->selectByMouse;
1487 int cursor = d->positionAt(event->localPos());
1488 d->moveCursor(cursor, mark);
1490 if (d->focusOnPress) {
1491 bool hadActiveFocus = hasActiveFocus();
1493 // re-open input panel on press if already focused
1494 if (hasActiveFocus() && hadActiveFocus && !d->m_readOnly)
1495 openSoftwareInputPanel();
1498 event->setAccepted(true);
1501 void QQuickTextInput::mouseMoveEvent(QMouseEvent *event)
1503 Q_D(QQuickTextInput);
1505 if (d->selectPressed) {
1506 if (qAbs(int(event->localPos().x() - d->pressPos.x())) > qApp->styleHints()->startDragDistance())
1507 setKeepMouseGrab(true);
1509 if (d->composeMode()) {
1511 int startPos = d->positionAt(d->pressPos);
1512 int currentPos = d->positionAt(event->localPos());
1513 if (startPos != currentPos)
1514 d->setSelection(startPos, currentPos - startPos);
1516 moveCursorSelection(d->positionAt(event->localPos()), d->mouseSelectionMode);
1518 event->setAccepted(true);
1520 QQuickImplicitSizeItem::mouseMoveEvent(event);
1524 void QQuickTextInput::mouseReleaseEvent(QMouseEvent *event)
1526 Q_D(QQuickTextInput);
1527 if (d->sendMouseEventToInputContext(event))
1529 if (d->selectPressed) {
1530 d->selectPressed = false;
1531 setKeepMouseGrab(false);
1533 #ifndef QT_NO_CLIPBOARD
1534 if (QGuiApplication::clipboard()->supportsSelection()) {
1535 if (event->button() == Qt::LeftButton) {
1536 d->copy(QClipboard::Selection);
1537 } else if (!d->m_readOnly && event->button() == Qt::MidButton) {
1539 d->insert(QGuiApplication::clipboard()->text(QClipboard::Selection));
1543 if (!event->isAccepted())
1544 QQuickImplicitSizeItem::mouseReleaseEvent(event);
1547 bool QQuickTextInputPrivate::sendMouseEventToInputContext(QMouseEvent *event)
1549 #if !defined QT_NO_IM
1550 if (composeMode()) {
1551 int tmp_cursor = positionAt(event->localPos());
1552 int mousePos = tmp_cursor - m_cursor;
1553 if (mousePos >= 0 && mousePos <= m_textLayout.preeditAreaText().length()) {
1554 if (event->type() == QEvent::MouseButtonRelease) {
1555 qApp->inputMethod()->invokeAction(QInputMethod::Click, mousePos);
1568 void QQuickTextInput::mouseUngrabEvent()
1570 Q_D(QQuickTextInput);
1571 d->selectPressed = false;
1572 setKeepMouseGrab(false);
1575 bool QQuickTextInput::event(QEvent* ev)
1577 #ifndef QT_NO_SHORTCUT
1578 Q_D(QQuickTextInput);
1579 if (ev->type() == QEvent::ShortcutOverride) {
1582 QKeyEvent* ke = static_cast<QKeyEvent*>(ev);
1583 if (ke == QKeySequence::Copy
1584 || ke == QKeySequence::Paste
1585 || ke == QKeySequence::Cut
1586 || ke == QKeySequence::Redo
1587 || ke == QKeySequence::Undo
1588 || ke == QKeySequence::MoveToNextWord
1589 || ke == QKeySequence::MoveToPreviousWord
1590 || ke == QKeySequence::MoveToStartOfDocument
1591 || ke == QKeySequence::MoveToEndOfDocument
1592 || ke == QKeySequence::SelectNextWord
1593 || ke == QKeySequence::SelectPreviousWord
1594 || ke == QKeySequence::SelectStartOfLine
1595 || ke == QKeySequence::SelectEndOfLine
1596 || ke == QKeySequence::SelectStartOfBlock
1597 || ke == QKeySequence::SelectEndOfBlock
1598 || ke == QKeySequence::SelectStartOfDocument
1599 || ke == QKeySequence::SelectAll
1600 || ke == QKeySequence::SelectEndOfDocument) {
1602 } else if (ke->modifiers() == Qt::NoModifier || ke->modifiers() == Qt::ShiftModifier
1603 || ke->modifiers() == Qt::KeypadModifier) {
1604 if (ke->key() < Qt::Key_Escape) {
1608 switch (ke->key()) {
1609 case Qt::Key_Delete:
1612 case Qt::Key_Backspace:
1624 return QQuickImplicitSizeItem::event(ev);
1627 void QQuickTextInput::geometryChanged(const QRectF &newGeometry,
1628 const QRectF &oldGeometry)
1630 Q_D(QQuickTextInput);
1632 if (newGeometry.width() != oldGeometry.width() && d->wrapMode != NoWrap)
1634 updateCursorRectangle();
1636 QQuickImplicitSizeItem::geometryChanged(newGeometry, oldGeometry);
1639 void QQuickTextInputPrivate::updateHorizontalScroll()
1641 Q_Q(QQuickTextInput);
1642 QTextLine currentLine = m_textLayout.lineForTextPosition(m_cursor + m_preeditCursor);
1643 const int preeditLength = m_textLayout.preeditAreaText().length();
1644 const qreal width = qMax<qreal>(0, q->width());
1646 qreal widthUsed = 0;
1647 if (currentLine.isValid()) {
1648 cix = currentLine.cursorToX(m_cursor + preeditLength);
1649 const qreal cursorWidth = cix >= 0 ? cix : width - cix;
1650 widthUsed = qMax(currentLine.naturalTextWidth(), cursorWidth);
1652 int previousScroll = hscroll;
1654 if (!autoScroll || widthUsed <= width || m_echoMode == QQuickTextInput::NoEcho) {
1657 Q_ASSERT(currentLine.isValid());
1658 if (cix - hscroll >= width) {
1659 // text doesn't fit, cursor is to the right of br (scroll right)
1660 hscroll = cix - width;
1661 } else if (cix - hscroll < 0 && hscroll < widthUsed) {
1662 // text doesn't fit, cursor is to the left of br (scroll left)
1664 } else if (widthUsed - hscroll < width) {
1665 // text doesn't fit, text document is to the left of br; align
1667 hscroll = widthUsed - width;
1668 } else if (width - hscroll > widthUsed) {
1669 // text doesn't fit, text document is to the right of br; align
1671 hscroll = width - widthUsed;
1673 if (preeditLength > 0) {
1674 // check to ensure long pre-edit text doesn't push the cursor
1676 cix = currentLine.cursorToX(m_cursor + qMax(0, m_preeditCursor - 1));
1681 if (previousScroll != hscroll)
1682 textLayoutDirty = true;
1685 void QQuickTextInputPrivate::updateVerticalScroll()
1687 Q_Q(QQuickTextInput);
1688 const int preeditLength = m_textLayout.preeditAreaText().length();
1689 const qreal height = qMax<qreal>(0, q->height());
1690 qreal heightUsed = contentSize.height();
1691 qreal previousScroll = vscroll;
1693 if (!autoScroll || heightUsed <= height) {
1694 // text fits in br; use vscroll for alignment
1695 switch (vAlign & ~(Qt::AlignAbsolute|Qt::AlignHorizontal_Mask)) {
1696 case Qt::AlignBottom:
1697 vscroll = heightUsed - height;
1699 case Qt::AlignVCenter:
1700 vscroll = (heightUsed - height) / 2;
1708 QTextLine currentLine = m_textLayout.lineForTextPosition(m_cursor + preeditLength);
1709 QRectF r = currentLine.isValid() ? currentLine.rect() : QRectF();
1710 qreal top = r.top();
1711 int bottom = r.bottom();
1713 if (bottom - vscroll >= height) {
1714 // text doesn't fit, cursor is to the below the br (scroll down)
1715 vscroll = bottom - height;
1716 } else if (top - vscroll < 0 && vscroll < heightUsed) {
1717 // text doesn't fit, cursor is above br (scroll up)
1719 } else if (heightUsed - vscroll < height) {
1720 // text doesn't fit, text document is to the left of br; align
1722 vscroll = heightUsed - height;
1724 if (preeditLength > 0) {
1725 // check to ensure long pre-edit text doesn't push the cursor
1727 currentLine = m_textLayout.lineForTextPosition(m_cursor + qMax(0, m_preeditCursor - 1));
1728 top = currentLine.isValid() ? currentLine.rect().top() : 0;
1733 if (previousScroll != vscroll)
1734 textLayoutDirty = true;
1737 void QQuickTextInput::triggerPreprocess()
1739 Q_D(QQuickTextInput);
1740 if (d->updateType == QQuickTextInputPrivate::UpdateNone)
1741 d->updateType = QQuickTextInputPrivate::UpdateOnlyPreprocess;
1745 QSGNode *QQuickTextInput::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data)
1748 Q_D(QQuickTextInput);
1750 if (d->updateType != QQuickTextInputPrivate::UpdatePaintNode && oldNode != 0) {
1751 // Update done in preprocess() in the nodes
1752 d->updateType = QQuickTextInputPrivate::UpdateNone;
1756 d->updateType = QQuickTextInputPrivate::UpdateNone;
1758 QQuickTextNode *node = static_cast<QQuickTextNode *>(oldNode);
1760 node = new QQuickTextNode(QQuickItemPrivate::get(this)->sceneGraphContext(), this);
1763 if (!d->textLayoutDirty && oldNode != 0) {
1764 QSGSimpleRectNode *cursorNode = node->cursorNode();
1765 if (cursorNode != 0 && !isReadOnly()) {
1766 cursorNode->setRect(cursorRectangle());
1768 if (!d->cursorVisible || (!d->m_blinkStatus && d->m_blinkPeriod > 0)) {
1775 node->deleteContent();
1776 node->setMatrix(QMatrix4x4());
1778 QPointF offset(0, 0);
1779 if (d->autoScroll && d->m_textLayout.lineCount() > 0) {
1780 QFontMetricsF fm(d->font);
1781 // the y offset is there to keep the baseline constant in case we have script changes in the text.
1782 offset = -QPoint(d->hscroll, d->vscroll + d->m_textLayout.lineAt(0).ascent() - fm.ascent());
1784 offset = -QPoint(d->hscroll, d->vscroll);
1787 if (!d->m_textLayout.text().isEmpty() || !d->m_textLayout.preeditAreaText().isEmpty()) {
1788 node->addTextLayout(offset, &d->m_textLayout, d->color,
1789 QQuickText::Normal, QColor(), QColor(),
1790 d->selectionColor, d->selectedTextColor,
1791 d->selectionStart(),
1792 d->selectionEnd() - 1); // selectionEnd() returns first char after
1796 if (!isReadOnly() && d->cursorItem == 0) {
1797 node->setCursor(cursorRectangle(), d->color);
1798 if (!d->cursorVisible || (!d->m_blinkStatus && d->m_blinkPeriod > 0)) {
1805 d->textLayoutDirty = false;
1811 QVariant QQuickTextInput::inputMethodQuery(Qt::InputMethodQuery property) const
1813 Q_D(const QQuickTextInput);
1816 return QVariant((bool)(flags() & ItemAcceptsInputMethod));
1818 return QVariant((int) d->effectiveInputMethodHints());
1819 case Qt::ImCursorRectangle:
1820 return cursorRectangle();
1823 case Qt::ImCursorPosition:
1824 return QVariant(d->m_cursor);
1825 case Qt::ImSurroundingText:
1826 if (d->m_echoMode == PasswordEchoOnEdit && !d->m_passwordEchoEditing) {
1827 return QVariant(displayText());
1829 return QVariant(d->realText());
1831 case Qt::ImCurrentSelection:
1832 return QVariant(selectedText());
1833 case Qt::ImMaximumTextLength:
1834 return QVariant(maxLength());
1835 case Qt::ImAnchorPosition:
1836 if (d->selectionStart() == d->selectionEnd())
1837 return QVariant(d->m_cursor);
1838 else if (d->selectionStart() == d->m_cursor)
1839 return QVariant(d->selectionEnd());
1841 return QVariant(d->selectionStart());
1848 \qmlmethod void QtQuick2::TextInput::deselect()
1850 Removes active text selection.
1852 void QQuickTextInput::deselect()
1854 Q_D(QQuickTextInput);
1859 \qmlmethod void QtQuick2::TextInput::selectAll()
1861 Causes all text to be selected.
1863 void QQuickTextInput::selectAll()
1865 Q_D(QQuickTextInput);
1866 d->setSelection(0, text().length());
1870 \qmlmethod void QtQuick2::TextInput::isRightToLeft(int start, int end)
1872 Returns true if the natural reading direction of the editor text
1873 found between positions \a start and \a end is right to left.
1875 bool QQuickTextInput::isRightToLeft(int start, int end)
1878 qmlInfo(this) << "isRightToLeft(start, end) called with the end property being smaller than the start.";
1881 return text().mid(start, end - start).isRightToLeft();
1885 #ifndef QT_NO_CLIPBOARD
1887 \qmlmethod QtQuick2::TextInput::cut()
1889 Moves the currently selected text to the system clipboard.
1891 void QQuickTextInput::cut()
1893 Q_D(QQuickTextInput);
1899 \qmlmethod QtQuick2::TextInput::copy()
1901 Copies the currently selected text to the system clipboard.
1903 void QQuickTextInput::copy()
1905 Q_D(QQuickTextInput);
1910 \qmlmethod QtQuick2::TextInput::paste()
1912 Replaces the currently selected text by the contents of the system clipboard.
1914 void QQuickTextInput::paste()
1916 Q_D(QQuickTextInput);
1920 #endif // QT_NO_CLIPBOARD
1923 Undoes the last operation if undo is \l {canUndo}{available}. Deselects any
1924 current selection, and updates the selection start to the current cursor
1928 void QQuickTextInput::undo()
1930 Q_D(QQuickTextInput);
1931 if (!d->m_readOnly) {
1933 d->finishChange(-1, true);
1938 Redoes the last operation if redo is \l {canRedo}{available}.
1941 void QQuickTextInput::redo()
1943 Q_D(QQuickTextInput);
1944 if (!d->m_readOnly) {
1951 \qmlmethod void QtQuick2::TextInput::insert(int position, string text)
1953 Inserts \a text into the TextInput at position.
1956 void QQuickTextInput::insert(int position, const QString &text)
1958 Q_D(QQuickTextInput);
1959 if (d->m_echoMode == QQuickTextInput::Password) {
1960 int delay = qGuiApp->styleHints()->passwordMaskDelay();
1962 d->m_passwordEchoTimer.start(delay, this);
1964 if (position < 0 || position > d->m_text.length())
1967 const int priorState = d->m_undoState;
1969 QString insertText = text;
1971 if (d->hasSelectedText()) {
1972 d->addCommand(QQuickTextInputPrivate::Command(
1973 QQuickTextInputPrivate::SetSelection, d->m_cursor, 0, d->m_selstart, d->m_selend));
1975 if (d->m_maskData) {
1976 insertText = d->maskString(position, insertText);
1977 for (int i = 0; i < insertText.length(); ++i) {
1978 d->addCommand(QQuickTextInputPrivate::Command(
1979 QQuickTextInputPrivate::DeleteSelection, position + i, d->m_text.at(position + i), -1, -1));
1980 d->addCommand(QQuickTextInputPrivate::Command(
1981 QQuickTextInputPrivate::Insert, position + i, insertText.at(i), -1, -1));
1983 d->m_text.replace(position, insertText.length(), insertText);
1984 if (!insertText.isEmpty())
1985 d->m_textDirty = true;
1986 if (position < d->m_selend && position + insertText.length() > d->m_selstart)
1987 d->m_selDirty = true;
1989 int remaining = d->m_maxLength - d->m_text.length();
1990 if (remaining != 0) {
1991 insertText = insertText.left(remaining);
1992 d->m_text.insert(position, insertText);
1993 for (int i = 0; i < insertText.length(); ++i)
1994 d->addCommand(QQuickTextInputPrivate::Command(
1995 QQuickTextInputPrivate::Insert, position + i, insertText.at(i), -1, -1));
1996 if (d->m_cursor >= position)
1997 d->m_cursor += insertText.length();
1998 if (d->m_selstart >= position)
1999 d->m_selstart += insertText.length();
2000 if (d->m_selend >= position)
2001 d->m_selend += insertText.length();
2002 d->m_textDirty = true;
2003 if (position >= d->m_selstart && position <= d->m_selend)
2004 d->m_selDirty = true;
2008 d->addCommand(QQuickTextInputPrivate::Command(
2009 QQuickTextInputPrivate::SetSelection, d->m_cursor, 0, d->m_selstart, d->m_selend));
2010 d->finishChange(priorState);
2012 if (d->lastSelectionStart != d->lastSelectionEnd) {
2013 if (d->m_selstart != d->lastSelectionStart) {
2014 d->lastSelectionStart = d->m_selstart;
2015 emit selectionStartChanged();
2017 if (d->m_selend != d->lastSelectionEnd) {
2018 d->lastSelectionEnd = d->m_selend;
2019 emit selectionEndChanged();
2025 \qmlmethod string QtQuick2::TextInput::getText(int start, int end)
2027 Removes the section of text that is between the \a start and \a end positions from the TextInput.
2030 void QQuickTextInput::remove(int start, int end)
2032 Q_D(QQuickTextInput);
2034 start = qBound(0, start, d->m_text.length());
2035 end = qBound(0, end, d->m_text.length());
2039 else if (start == end)
2042 if (start < d->m_selend && end > d->m_selstart)
2043 d->m_selDirty = true;
2045 const int priorState = d->m_undoState;
2047 d->addCommand(QQuickTextInputPrivate::Command(
2048 QQuickTextInputPrivate::SetSelection, d->m_cursor, 0, d->m_selstart, d->m_selend));
2050 if (start <= d->m_cursor && d->m_cursor < end) {
2051 // cursor is within the selection. Split up the commands
2052 // to be able to restore the correct cursor position
2053 for (int i = d->m_cursor; i >= start; --i) {
2054 d->addCommand(QQuickTextInputPrivate::Command(
2055 QQuickTextInputPrivate::DeleteSelection, i, d->m_text.at(i), -1, 1));
2057 for (int i = end - 1; i > d->m_cursor; --i) {
2058 d->addCommand(QQuickTextInputPrivate::Command(
2059 QQuickTextInputPrivate::DeleteSelection, i - d->m_cursor + start - 1, d->m_text.at(i), -1, -1));
2062 for (int i = end - 1; i >= start; --i) {
2063 d->addCommand(QQuickTextInputPrivate::Command(
2064 QQuickTextInputPrivate::RemoveSelection, i, d->m_text.at(i), -1, -1));
2067 if (d->m_maskData) {
2068 d->m_text.replace(start, end - start, d->clearString(start, end - start));
2069 for (int i = 0; i < end - start; ++i) {
2070 d->addCommand(QQuickTextInputPrivate::Command(
2071 QQuickTextInputPrivate::Insert, start + i, d->m_text.at(start + i), -1, -1));
2074 d->m_text.remove(start, end - start);
2076 if (d->m_cursor > start)
2077 d->m_cursor -= qMin(d->m_cursor, end) - start;
2078 if (d->m_selstart > start)
2079 d->m_selstart -= qMin(d->m_selstart, end) - start;
2080 if (d->m_selend > end)
2081 d->m_selend -= qMin(d->m_selend, end) - start;
2083 d->addCommand(QQuickTextInputPrivate::Command(
2084 QQuickTextInputPrivate::SetSelection, d->m_cursor, 0, d->m_selstart, d->m_selend));
2086 d->m_textDirty = true;
2087 d->finishChange(priorState);
2089 if (d->lastSelectionStart != d->lastSelectionEnd) {
2090 if (d->m_selstart != d->lastSelectionStart) {
2091 d->lastSelectionStart = d->m_selstart;
2092 emit selectionStartChanged();
2094 if (d->m_selend != d->lastSelectionEnd) {
2095 d->lastSelectionEnd = d->m_selend;
2096 emit selectionEndChanged();
2103 \qmlmethod void QtQuick2::TextInput::selectWord()
2105 Causes the word closest to the current cursor position to be selected.
2107 void QQuickTextInput::selectWord()
2109 Q_D(QQuickTextInput);
2110 d->selectWordAtPos(d->m_cursor);
2114 \qmlproperty bool QtQuick2::TextInput::smooth
2116 This property holds whether the text is smoothly scaled or transformed.
2118 Smooth filtering gives better visual quality, but is slower. If
2119 the item is displayed at its natural size, this property has no visual or
2122 \note Generally scaling artifacts are only visible if the item is stationary on
2123 the screen. A common pattern when animating an item is to disable smooth
2124 filtering at the beginning of the animation and reenable it at the conclusion.
2128 \qmlproperty string QtQuick2::TextInput::passwordCharacter
2130 This is the character displayed when echoMode is set to Password or
2131 PasswordEchoOnEdit. By default it is an asterisk.
2133 If this property is set to a string with more than one character,
2134 the first character is used. If the string is empty, the value
2135 is ignored and the property is not set.
2137 QString QQuickTextInput::passwordCharacter() const
2139 Q_D(const QQuickTextInput);
2140 return QString(d->m_passwordCharacter);
2143 void QQuickTextInput::setPasswordCharacter(const QString &str)
2145 Q_D(QQuickTextInput);
2146 if (str.length() < 1)
2148 d->m_passwordCharacter = str.constData()[0];
2149 if (d->m_echoMode == Password || d->m_echoMode == PasswordEchoOnEdit)
2150 d->updateDisplayText();
2151 emit passwordCharacterChanged();
2155 \qmlproperty string QtQuick2::TextInput::displayText
2157 This is the text displayed in the TextInput.
2159 If \l echoMode is set to TextInput::Normal, this holds the
2160 same value as the TextInput::text property. Otherwise,
2161 this property holds the text visible to the user, while
2162 the \l text property holds the actual entered text.
2164 QString QQuickTextInput::displayText() const
2166 Q_D(const QQuickTextInput);
2167 return d->m_textLayout.text();
2171 \qmlproperty bool QtQuick2::TextInput::selectByMouse
2175 If true, the user can use the mouse to select text in some
2176 platform-specific way. Note that for some platforms this may
2177 not be an appropriate interaction (eg. may conflict with how
2178 the text needs to behave inside a Flickable.
2180 bool QQuickTextInput::selectByMouse() const
2182 Q_D(const QQuickTextInput);
2183 return d->selectByMouse;
2186 void QQuickTextInput::setSelectByMouse(bool on)
2188 Q_D(QQuickTextInput);
2189 if (d->selectByMouse != on) {
2190 d->selectByMouse = on;
2191 emit selectByMouseChanged(on);
2196 \qmlproperty enum QtQuick2::TextInput::mouseSelectionMode
2198 Specifies how text should be selected using a mouse.
2201 \li TextInput.SelectCharacters - The selection is updated with individual characters. (Default)
2202 \li TextInput.SelectWords - The selection is updated with whole words.
2205 This property only applies when \l selectByMouse is true.
2208 QQuickTextInput::SelectionMode QQuickTextInput::mouseSelectionMode() const
2210 Q_D(const QQuickTextInput);
2211 return d->mouseSelectionMode;
2214 void QQuickTextInput::setMouseSelectionMode(SelectionMode mode)
2216 Q_D(QQuickTextInput);
2217 if (d->mouseSelectionMode != mode) {
2218 d->mouseSelectionMode = mode;
2219 emit mouseSelectionModeChanged(mode);
2224 \qmlproperty bool QtQuick2::TextInput::persistentSelection
2226 Whether the TextInput should keep its selection when it loses active focus to another
2227 item in the scene. By default this is set to false;
2230 bool QQuickTextInput::persistentSelection() const
2232 Q_D(const QQuickTextInput);
2233 return d->persistentSelection;
2236 void QQuickTextInput::setPersistentSelection(bool on)
2238 Q_D(QQuickTextInput);
2239 if (d->persistentSelection == on)
2241 d->persistentSelection = on;
2242 emit persistentSelectionChanged();
2245 #ifndef QT_NO_CLIPBOARD
2247 \qmlproperty bool QtQuick2::TextInput::canPaste
2249 Returns true if the TextInput is writable and the content of the clipboard is
2250 suitable for pasting into the TextInput.
2252 bool QQuickTextInput::canPaste() const
2254 Q_D(const QQuickTextInput);
2255 if (!d->canPasteValid) {
2256 if (const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData())
2257 const_cast<QQuickTextInputPrivate *>(d)->canPaste = !d->m_readOnly && mimeData->hasText();
2258 const_cast<QQuickTextInputPrivate *>(d)->canPasteValid = true;
2265 \qmlproperty bool QtQuick2::TextInput::canUndo
2267 Returns true if the TextInput is writable and there are previous operations
2271 bool QQuickTextInput::canUndo() const
2273 Q_D(const QQuickTextInput);
2278 \qmlproperty bool QtQuick2::TextInput::canRedo
2280 Returns true if the TextInput is writable and there are \l {undo}{undone}
2281 operations that can be redone.
2284 bool QQuickTextInput::canRedo() const
2286 Q_D(const QQuickTextInput);
2291 \qmlproperty real QtQuick2::TextInput::contentWidth
2293 Returns the width of the text, including the width past the width
2294 which is covered due to insufficient wrapping if \l wrapMode is set.
2297 qreal QQuickTextInput::contentWidth() const
2299 Q_D(const QQuickTextInput);
2300 return d->contentSize.width();
2304 \qmlproperty real QtQuick2::TextInput::contentHeight
2306 Returns the height of the text, including the height past the height
2307 that is covered if the text does not fit within the set height.
2310 qreal QQuickTextInput::contentHeight() const
2312 Q_D(const QQuickTextInput);
2313 return d->contentSize.height();
2316 void QQuickTextInput::moveCursorSelection(int position)
2318 Q_D(QQuickTextInput);
2319 d->moveCursor(position, true);
2323 \qmlmethod void QtQuick2::TextInput::moveCursorSelection(int position, SelectionMode mode = TextInput.SelectCharacters)
2325 Moves the cursor to \a position and updates the selection according to the optional \a mode
2326 parameter. (To only move the cursor, set the \l cursorPosition property.)
2328 When this method is called it additionally sets either the
2329 selectionStart or the selectionEnd (whichever was at the previous cursor position)
2330 to the specified position. This allows you to easily extend and contract the selected
2333 The selection mode specifies whether the selection is updated on a per character or a per word
2334 basis. If not specified the selection mode will default to TextInput.SelectCharacters.
2337 \li TextInput.SelectCharacters - Sets either the selectionStart or selectionEnd (whichever was at
2338 the previous cursor position) to the specified position.
2339 \li TextInput.SelectWords - Sets the selectionStart and selectionEnd to include all
2340 words between the specified position and the previous cursor position. Words partially in the
2344 For example, take this sequence of calls:
2348 moveCursorSelection(9, TextInput.SelectCharacters)
2349 moveCursorSelection(7, TextInput.SelectCharacters)
2352 This moves the cursor to position 5, extend the selection end from 5 to 9
2353 and then retract the selection end from 9 to 7, leaving the text from position 5 to 7
2354 selected (the 6th and 7th characters).
2356 The same sequence with TextInput.SelectWords will extend the selection start to a word boundary
2357 before or on position 5 and extend the selection end to a word boundary on or past position 9.
2359 void QQuickTextInput::moveCursorSelection(int pos, SelectionMode mode)
2361 Q_D(QQuickTextInput);
2363 if (mode == SelectCharacters) {
2364 d->moveCursor(pos, true);
2365 } else if (pos != d->m_cursor){
2366 const int cursor = d->m_cursor;
2368 if (!d->hasSelectedText())
2369 anchor = d->m_cursor;
2370 else if (d->selectionStart() == d->m_cursor)
2371 anchor = d->selectionEnd();
2373 anchor = d->selectionStart();
2375 if (anchor < pos || (anchor == pos && cursor < pos)) {
2376 const QString text = this->text();
2377 QTextBoundaryFinder finder(QTextBoundaryFinder::Word, text);
2378 finder.setPosition(anchor);
2380 const QTextBoundaryFinder::BoundaryReasons reasons = finder.boundaryReasons();
2381 if (anchor < text.length() && (!(reasons & QTextBoundaryFinder::StartWord)
2382 || ((reasons & QTextBoundaryFinder::EndWord) && anchor > cursor))) {
2383 finder.toPreviousBoundary();
2385 anchor = finder.position() != -1 ? finder.position() : 0;
2387 finder.setPosition(pos);
2388 if (pos > 0 && !finder.boundaryReasons())
2389 finder.toNextBoundary();
2390 const int cursor = finder.position() != -1 ? finder.position() : text.length();
2392 d->setSelection(anchor, cursor - anchor);
2393 } else if (anchor > pos || (anchor == pos && cursor > pos)) {
2394 const QString text = this->text();
2395 QTextBoundaryFinder finder(QTextBoundaryFinder::Word, text);
2396 finder.setPosition(anchor);
2398 const QTextBoundaryFinder::BoundaryReasons reasons = finder.boundaryReasons();
2399 if (anchor > 0 && (!(reasons & QTextBoundaryFinder::EndWord)
2400 || ((reasons & QTextBoundaryFinder::StartWord) && anchor < cursor))) {
2401 finder.toNextBoundary();
2404 anchor = finder.position() != -1 ? finder.position() : text.length();
2406 finder.setPosition(pos);
2407 if (pos < text.length() && !finder.boundaryReasons())
2408 finder.toPreviousBoundary();
2409 const int cursor = finder.position() != -1 ? finder.position() : 0;
2411 d->setSelection(anchor, cursor - anchor);
2417 \qmlmethod void QtQuick2::TextInput::openSoftwareInputPanel()
2419 Opens software input panels like virtual keyboards for typing, useful for
2420 customizing when you want the input keyboard to be shown and hidden in
2423 By default the opening of input panels follows the platform style. Input panels are
2424 always closed if no editor has active focus.
2426 You can disable the automatic behavior by setting the property \c activeFocusOnPress to false
2427 and use functions openSoftwareInputPanel() and closeSoftwareInputPanel() to implement
2428 the behavior you want.
2430 Only relevant on platforms, which provide virtual keyboards.
2436 text: "Hello world!"
2437 activeFocusOnPress: false
2439 anchors.fill: parent
2441 if (!textInput.activeFocus) {
2442 textInput.forceActiveFocus()
2443 textInput.openSoftwareInputPanel();
2445 textInput.focus = false;
2448 onPressAndHold: textInput.closeSoftwareInputPanel();
2453 void QQuickTextInput::openSoftwareInputPanel()
2456 qGuiApp->inputMethod()->show();
2460 \qmlmethod void QtQuick2::TextInput::closeSoftwareInputPanel()
2462 Closes a software input panel like a virtual keyboard shown on the screen, useful
2463 for customizing when you want the input keyboard to be shown and hidden in
2466 By default the opening of input panels follows the platform style. Input panels are
2467 always closed if no editor has active focus.
2469 You can disable the automatic behavior by setting the property \c activeFocusOnPress to false
2470 and use functions openSoftwareInputPanel() and closeSoftwareInputPanel() to implement
2471 the behavior you want.
2473 Only relevant on platforms, which provide virtual keyboards.
2479 text: "Hello world!"
2480 activeFocusOnPress: false
2482 anchors.fill: parent
2484 if (!textInput.activeFocus) {
2485 textInput.forceActiveFocus();
2486 textInput.openSoftwareInputPanel();
2488 textInput.focus = false;
2491 onPressAndHold: textInput.closeSoftwareInputPanel();
2496 void QQuickTextInput::closeSoftwareInputPanel()
2499 qGuiApp->inputMethod()->hide();
2502 void QQuickTextInput::focusInEvent(QFocusEvent *event)
2504 Q_D(const QQuickTextInput);
2505 if (d->focusOnPress && !d->m_readOnly)
2506 openSoftwareInputPanel();
2507 QQuickImplicitSizeItem::focusInEvent(event);
2510 void QQuickTextInput::itemChange(ItemChange change, const ItemChangeData &value)
2512 Q_D(QQuickTextInput);
2513 if (change == ItemActiveFocusHasChanged) {
2514 bool hasFocus = value.boolValue;
2515 setCursorVisible(hasFocus); // ### refactor: && d->canvas && d->canvas->hasFocus()
2516 if (!hasFocus && (d->m_passwordEchoEditing || d->m_passwordEchoTimer.isActive())) {
2517 d->updatePasswordEchoEditing(false);//QQuickTextInputPrivate sets it on key events, but doesn't deal with focus events
2521 if (!d->persistentSelection)
2523 disconnect(qApp->inputMethod(), SIGNAL(inputDirectionChanged(Qt::LayoutDirection)),
2524 this, SLOT(q_updateAlignment()));
2526 q_updateAlignment();
2527 connect(qApp->inputMethod(), SIGNAL(inputDirectionChanged(Qt::LayoutDirection)),
2528 this, SLOT(q_updateAlignment()));
2531 QQuickItem::itemChange(change, value);
2535 \qmlproperty bool QtQuick2::TextInput::inputMethodComposing
2538 This property holds whether the TextInput has partial text input from an
2541 While it is composing an input method may rely on mouse or key events from
2542 the TextInput to edit or commit the partial text. This property can be
2543 used to determine when to disable events handlers that may interfere with
2544 the correct operation of an input method.
2546 bool QQuickTextInput::isInputMethodComposing() const
2548 Q_D(const QQuickTextInput);
2549 return d->hasImState;
2552 void QQuickTextInputPrivate::init()
2554 Q_Q(QQuickTextInput);
2555 q->setSmooth(smooth);
2556 q->setAcceptedMouseButtons(Qt::LeftButton);
2557 q->setFlag(QQuickItem::ItemAcceptsInputMethod);
2558 q->setFlag(QQuickItem::ItemHasContents);
2559 #ifndef QT_NO_CLIPBOARD
2560 q->connect(QGuiApplication::clipboard(), SIGNAL(dataChanged()),
2561 q, SLOT(q_canPasteChanged()));
2562 #endif // QT_NO_CLIPBOARD
2564 lastSelectionStart = 0;
2565 lastSelectionEnd = 0;
2566 determineHorizontalAlignment();
2568 if (!qmlDisableDistanceField()) {
2569 QTextOption option = m_textLayout.textOption();
2570 option.setUseDesignMetrics(true);
2571 m_textLayout.setTextOption(option);
2575 void QQuickTextInput::updateCursorRectangle()
2577 Q_D(QQuickTextInput);
2578 if (!isComponentComplete())
2581 d->updateHorizontalScroll();
2582 d->updateVerticalScroll();
2583 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
2585 emit cursorRectangleChanged();
2586 if (d->cursorItem) {
2587 QRectF r = cursorRectangle();
2588 d->cursorItem->setPos(r.topLeft());
2589 d->cursorItem->setHeight(r.height());
2591 updateInputMethod(Qt::ImCursorRectangle);
2594 void QQuickTextInput::selectionChanged()
2596 Q_D(QQuickTextInput);
2597 d->textLayoutDirty = true; //TODO: Only update rect in selection
2598 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
2600 emit selectedTextChanged();
2602 if (d->lastSelectionStart != d->selectionStart()) {
2603 d->lastSelectionStart = d->selectionStart();
2604 if (d->lastSelectionStart == -1)
2605 d->lastSelectionStart = d->m_cursor;
2606 emit selectionStartChanged();
2608 if (d->lastSelectionEnd != d->selectionEnd()) {
2609 d->lastSelectionEnd = d->selectionEnd();
2610 if (d->lastSelectionEnd == -1)
2611 d->lastSelectionEnd = d->m_cursor;
2612 emit selectionEndChanged();
2616 void QQuickTextInputPrivate::showCursor()
2618 if (textNode != 0 && textNode->cursorNode() != 0)
2619 textNode->cursorNode()->setColor(color);
2622 void QQuickTextInputPrivate::hideCursor()
2624 if (textNode != 0 && textNode->cursorNode() != 0)
2625 textNode->cursorNode()->setColor(QColor(0, 0, 0, 0));
2628 QRectF QQuickTextInput::boundingRect() const
2630 Q_D(const QQuickTextInput);
2632 int cursorWidth = d->cursorItem ? 0 : 1;
2634 qreal hscroll = d->hscroll;
2635 if (!d->autoScroll || d->contentSize.width() < width()) {
2636 switch (effectiveHAlign()) {
2640 hscroll += d->contentSize.width() - width();
2643 hscroll += (d->contentSize.width() - width()) / 2;
2648 // Could include font max left/right bearings to either side of rectangle.
2649 QRectF r(-hscroll, -d->vscroll, d->contentSize.width(), d->contentSize.height());
2650 r.setRight(r.right() + cursorWidth);
2654 QRectF QQuickTextInput::clipRect() const
2656 Q_D(const QQuickTextInput);
2658 int cursorWidth = d->cursorItem ? d->cursorItem->width() : 1;
2660 // Could include font max left/right bearings to either side of rectangle.
2661 QRectF r = QQuickImplicitSizeItem::clipRect();
2662 r.setRight(r.right() + cursorWidth);
2666 void QQuickTextInput::q_canPasteChanged()
2668 Q_D(QQuickTextInput);
2669 bool old = d->canPaste;
2670 #ifndef QT_NO_CLIPBOARD
2671 if (const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData())
2672 d->canPaste = !d->m_readOnly && mimeData->hasText();
2674 d->canPaste = false;
2677 bool changed = d->canPaste != old || !d->canPasteValid;
2678 d->canPasteValid = true;
2680 emit canPasteChanged();
2684 void QQuickTextInput::q_updateAlignment()
2686 Q_D(QQuickTextInput);
2687 if (d->determineHorizontalAlignment()) {
2689 updateCursorRectangle();
2693 // ### these should come from QStyleHints
2694 const int textCursorWidth = 1;
2695 const bool fullWidthSelection = true;
2700 Updates the display text based of the current edit text
2701 If the text has changed will emit displayTextChanged()
2703 void QQuickTextInputPrivate::updateDisplayText(bool forceUpdate)
2705 QString orig = m_textLayout.text();
2707 if (m_echoMode == QQuickTextInput::NoEcho)
2708 str = QString::fromLatin1("");
2712 if (m_echoMode == QQuickTextInput::Password) {
2713 str.fill(m_passwordCharacter);
2714 if (m_passwordEchoTimer.isActive() && m_cursor > 0 && m_cursor <= m_text.length()) {
2715 int cursor = m_cursor - 1;
2716 QChar uc = m_text.at(cursor);
2718 if (cursor > 0 && uc.unicode() >= 0xdc00 && uc.unicode() < 0xe000) {
2719 // second half of a surrogate, check if we have the first half as well,
2720 // if yes restore both at once
2721 uc = m_text.at(cursor - 1);
2722 if (uc.unicode() >= 0xd800 && uc.unicode() < 0xdc00)
2723 str[cursor - 1] = uc;
2726 } else if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit && !m_passwordEchoEditing) {
2727 str.fill(m_passwordCharacter);
2730 // replace certain non-printable characters with spaces (to avoid
2731 // drawing boxes when using fonts that don't have glyphs for such
2733 QChar* uc = str.data();
2734 for (int i = 0; i < (int)str.length(); ++i) {
2735 if ((uc[i] < 0x20 && uc[i] != 0x09)
2736 || uc[i] == QChar::LineSeparator
2737 || uc[i] == QChar::ParagraphSeparator
2738 || uc[i] == QChar::ObjectReplacementCharacter)
2739 uc[i] = QChar(0x0020);
2742 if (str != orig || forceUpdate) {
2743 m_textLayout.setText(str);
2744 updateLayout(); // polish?
2745 emit q_func()->displayTextChanged();
2749 qreal QQuickTextInputPrivate::getImplicitWidth() const
2751 Q_Q(const QQuickTextInput);
2752 if (!requireImplicitWidth) {
2753 QQuickTextInputPrivate *d = const_cast<QQuickTextInputPrivate *>(this);
2754 d->requireImplicitWidth = true;
2756 if (q->isComponentComplete()) {
2757 // One time cost, only incurred if implicitWidth is first requested after
2758 // componentComplete.
2759 QTextLayout layout(m_text);
2761 QTextOption option = m_textLayout.textOption();
2762 option.setTextDirection(m_layoutDirection);
2763 option.setFlags(QTextOption::IncludeTrailingSpaces);
2764 option.setWrapMode(QTextOption::WrapMode(wrapMode));
2765 option.setAlignment(Qt::Alignment(q->effectiveHAlign()));
2766 layout.setTextOption(option);
2767 layout.setFont(font);
2768 layout.setPreeditArea(m_textLayout.preeditAreaPosition(), m_textLayout.preeditAreaText());
2769 layout.beginLayout();
2771 QTextLine line = layout.createLine();
2772 line.setLineWidth(INT_MAX);
2773 d->implicitWidth = qCeil(line.naturalTextWidth());
2778 return implicitWidth;
2781 void QQuickTextInputPrivate::updateLayout()
2783 Q_Q(QQuickTextInput);
2785 if (!q->isComponentComplete())
2789 QTextOption option = m_textLayout.textOption();
2790 option.setTextDirection(layoutDirection());
2791 option.setWrapMode(QTextOption::WrapMode(wrapMode));
2792 option.setAlignment(Qt::Alignment(q->effectiveHAlign()));
2793 m_textLayout.setTextOption(option);
2794 m_textLayout.setFont(font);
2796 m_textLayout.beginLayout();
2798 QTextLine line = m_textLayout.createLine();
2799 if (requireImplicitWidth) {
2800 line.setLineWidth(INT_MAX);
2801 const bool wasInLayout = inLayout;
2803 q->setImplicitWidth(qCeil(line.naturalTextWidth()));
2804 inLayout = wasInLayout;
2805 if (inLayout) // probably the result of a binding loop, but by letting it
2806 return; // get this far we'll get a warning to that effect.
2808 qreal lineWidth = q->widthValid() ? q->width() : INT_MAX;
2812 line.setLineWidth(lineWidth);
2813 line.setPosition(QPointF(0, height));
2815 height += line.height();
2816 width = qMax(width, line.naturalTextWidth());
2818 line = m_textLayout.createLine();
2819 } while (line.isValid());
2820 m_textLayout.endLayout();
2822 option.setWrapMode(QTextOption::NoWrap);
2823 m_textLayout.setTextOption(option);
2825 textLayoutDirty = true;
2827 const QSizeF previousSize = contentSize;
2828 contentSize = QSizeF(width, height);
2830 updateType = UpdatePaintNode;
2833 if (!requireImplicitWidth && !q->widthValid())
2834 q->setImplicitSize(width, height);
2836 q->setImplicitHeight(height);
2838 if (previousSize != contentSize)
2839 emit q->contentSizeChanged();
2842 #ifndef QT_NO_CLIPBOARD
2846 Copies the currently selected text into the clipboard using the given
2849 \note If the echo mode is set to a mode other than Normal then copy
2850 will not work. This is to prevent using copy as a method of bypassing
2851 password features of the line control.
2853 void QQuickTextInputPrivate::copy(QClipboard::Mode mode) const
2855 QString t = selectedText();
2856 if (!t.isEmpty() && m_echoMode == QQuickTextInput::Normal) {
2857 QGuiApplication::clipboard()->setText(t, mode);
2864 Inserts the text stored in the application clipboard into the line
2869 void QQuickTextInputPrivate::paste(QClipboard::Mode clipboardMode)
2871 QString clip = QGuiApplication::clipboard()->text(clipboardMode);
2872 if (!clip.isEmpty() || hasSelectedText()) {
2873 separate(); //make it a separate undo/redo command
2879 #endif // !QT_NO_CLIPBOARD
2884 void QQuickTextInputPrivate::commitPreedit()
2886 Q_Q(QQuickTextInput);
2891 qApp->inputMethod()->commit();
2896 QInputMethodEvent ev;
2897 QCoreApplication::sendEvent(q, &ev);
2900 void QQuickTextInputPrivate::cancelPreedit()
2902 Q_Q(QQuickTextInput);
2907 qApp->inputMethod()->reset();
2909 QInputMethodEvent ev;
2910 QCoreApplication::sendEvent(q, &ev);
2916 Handles the behavior for the backspace key or function.
2917 Removes the current selection if there is a selection, otherwise
2918 removes the character prior to the cursor position.
2922 void QQuickTextInputPrivate::backspace()
2924 int priorState = m_undoState;
2925 if (hasSelectedText()) {
2926 removeSelectedText();
2927 } else if (m_cursor) {
2930 m_cursor = prevMaskBlank(m_cursor);
2931 QChar uc = m_text.at(m_cursor);
2932 if (m_cursor > 0 && uc.unicode() >= 0xdc00 && uc.unicode() < 0xe000) {
2933 // second half of a surrogate, check if we have the first half as well,
2934 // if yes delete both at once
2935 uc = m_text.at(m_cursor - 1);
2936 if (uc.unicode() >= 0xd800 && uc.unicode() < 0xdc00) {
2937 internalDelete(true);
2941 internalDelete(true);
2943 finishChange(priorState);
2949 Handles the behavior for the delete key or function.
2950 Removes the current selection if there is a selection, otherwise
2951 removes the character after the cursor position.
2955 void QQuickTextInputPrivate::del()
2957 int priorState = m_undoState;
2958 if (hasSelectedText()) {
2959 removeSelectedText();
2961 int n = m_textLayout.nextCursorPosition(m_cursor) - m_cursor;
2965 finishChange(priorState);
2971 Inserts the given \a newText at the current cursor position.
2972 If there is any selected text it is removed prior to insertion of
2975 void QQuickTextInputPrivate::insert(const QString &newText)
2977 int priorState = m_undoState;
2978 removeSelectedText();
2979 internalInsert(newText);
2980 finishChange(priorState);
2986 Clears the line control text.
2988 void QQuickTextInputPrivate::clear()
2990 int priorState = m_undoState;
2992 m_selend = m_text.length();
2993 removeSelectedText();
2995 finishChange(priorState, /*update*/false, /*edited*/false);
3001 Sets \a length characters from the given \a start position as selected.
3002 The given \a start position must be within the current text for
3003 the line control. If \a length characters cannot be selected, then
3004 the selection will extend to the end of the current text.
3006 void QQuickTextInputPrivate::setSelection(int start, int length)
3008 Q_Q(QQuickTextInput);
3011 if (start < 0 || start > (int)m_text.length()){
3012 qWarning("QQuickTextInputPrivate::setSelection: Invalid start position");
3017 if (start == m_selstart && start + length == m_selend && m_cursor == m_selend)
3020 m_selend = qMin(start + length, (int)m_text.length());
3021 m_cursor = m_selend;
3022 } else if (length < 0){
3023 if (start == m_selend && start + length == m_selstart && m_cursor == m_selstart)
3025 m_selstart = qMax(start + length, 0);
3027 m_cursor = m_selstart;
3028 } else if (m_selstart != m_selend) {
3034 emitCursorPositionChanged();
3037 emit q->selectionChanged();
3038 emitCursorPositionChanged();
3039 q->updateInputMethod(Qt::ImCursorRectangle | Qt::ImAnchorPosition
3040 | Qt::ImCursorPosition | Qt::ImCurrentSelection);
3046 Sets the password echo editing to \a editing. If password echo editing
3047 is true, then the text of the password is displayed even if the echo
3048 mode is set to QLineEdit::PasswordEchoOnEdit. Password echoing editing
3049 does not affect other echo modes.
3051 void QQuickTextInputPrivate::updatePasswordEchoEditing(bool editing)
3053 cancelPasswordEchoTimer();
3054 m_passwordEchoEditing = editing;
3055 updateDisplayText();
3061 Fixes the current text so that it is valid given any set validators.
3063 Returns true if the text was changed. Otherwise returns false.
3065 bool QQuickTextInputPrivate::fixup() // this function assumes that validate currently returns != Acceptable
3067 #ifndef QT_NO_VALIDATOR
3069 QString textCopy = m_text;
3070 int cursorCopy = m_cursor;
3071 m_validator->fixup(textCopy);
3072 if (m_validator->validate(textCopy, cursorCopy) == QValidator::Acceptable) {
3073 if (textCopy != m_text || cursorCopy != m_cursor)
3074 internalSetText(textCopy, cursorCopy);
3085 Moves the cursor to the given position \a pos. If \a mark is true will
3086 adjust the currently selected text.
3088 void QQuickTextInputPrivate::moveCursor(int pos, bool mark)
3090 Q_Q(QQuickTextInput);
3093 if (pos != m_cursor) {
3096 pos = pos > m_cursor ? nextMaskBlank(pos) : prevMaskBlank(pos);
3100 if (m_selend > m_selstart && m_cursor == m_selstart)
3102 else if (m_selend > m_selstart && m_cursor == m_selend)
3103 anchor = m_selstart;
3106 m_selstart = qMin(anchor, pos);
3107 m_selend = qMax(anchor, pos);
3112 if (mark || m_selDirty) {
3114 emit q->selectionChanged();
3116 emitCursorPositionChanged();
3117 q->updateInputMethod();
3123 Applies the given input method event \a event to the text of the line
3126 void QQuickTextInputPrivate::processInputMethodEvent(QInputMethodEvent *event)
3128 Q_Q(QQuickTextInput);
3130 int priorState = -1;
3131 bool isGettingInput = !event->commitString().isEmpty()
3132 || event->preeditString() != preeditAreaText()
3133 || event->replacementLength() > 0;
3134 bool cursorPositionChanged = false;
3135 bool selectionChange = false;
3136 m_preeditDirty = event->preeditString() != preeditAreaText();
3138 if (isGettingInput) {
3139 // If any text is being input, remove selected text.
3140 priorState = m_undoState;
3141 if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit && !m_passwordEchoEditing) {
3142 updatePasswordEchoEditing(true);
3144 m_selend = m_text.length();
3146 removeSelectedText();
3149 int c = m_cursor; // cursor position after insertion of commit string
3150 if (event->replacementStart() <= 0)
3151 c += event->commitString().length() - qMin(-event->replacementStart(), event->replacementLength());
3153 m_cursor += event->replacementStart();
3157 // insert commit string
3158 if (event->replacementLength()) {
3159 m_selstart = m_cursor;
3160 m_selend = m_selstart + event->replacementLength();
3161 m_selend = qMin(m_selend, m_text.length());
3162 removeSelectedText();
3164 if (!event->commitString().isEmpty()) {
3165 internalInsert(event->commitString());
3166 cursorPositionChanged = true;
3169 m_cursor = qBound(0, c, m_text.length());
3171 for (int i = 0; i < event->attributes().size(); ++i) {
3172 const QInputMethodEvent::Attribute &a = event->attributes().at(i);
3173 if (a.type == QInputMethodEvent::Selection) {
3174 m_cursor = qBound(0, a.start + a.length, m_text.length());
3176 m_selstart = qMax(0, qMin(a.start, m_text.length()));
3177 m_selend = m_cursor;
3178 if (m_selend < m_selstart) {
3179 qSwap(m_selstart, m_selend);
3181 selectionChange = true;
3183 m_selstart = m_selend = 0;
3185 cursorPositionChanged = true;
3189 m_textLayout.setPreeditArea(m_cursor, event->preeditString());
3191 const int oldPreeditCursor = m_preeditCursor;
3192 const bool oldCursorVisible = cursorVisible;
3193 m_preeditCursor = event->preeditString().length();
3194 hasImState = !event->preeditString().isEmpty();
3195 cursorVisible = true;
3196 QList<QTextLayout::FormatRange> formats;
3197 for (int i = 0; i < event->attributes().size(); ++i) {
3198 const QInputMethodEvent::Attribute &a = event->attributes().at(i);
3199 if (a.type == QInputMethodEvent::Cursor) {
3201 m_preeditCursor = a.start;
3202 cursorVisible = a.length != 0;
3203 } else if (a.type == QInputMethodEvent::TextFormat) {
3205 QTextCharFormat f = qvariant_cast<QTextFormat>(a.value).toCharFormat();
3207 QTextLayout::FormatRange o;
3208 o.start = a.start + m_cursor;
3209 o.length = a.length;
3215 m_textLayout.setAdditionalFormats(formats);
3217 updateDisplayText(/*force*/ true);
3218 if (cursorPositionChanged) {
3219 emitCursorPositionChanged();
3220 } else if (m_preeditCursor != oldPreeditCursor || isGettingInput) {
3221 q->updateCursorRectangle();
3225 finishChange(priorState);
3227 if (cursorVisible != oldCursorVisible)
3228 emit q->cursorVisibleChanged(cursorVisible);
3230 if (selectionChange) {
3231 emit q->selectionChanged();
3232 q->updateInputMethod(Qt::ImCursorRectangle | Qt::ImAnchorPosition
3233 | Qt::ImCursorPosition | Qt::ImCurrentSelection);
3240 Sets the selection to cover the word at the given cursor position.
3241 The word boundaries are defined by the behavior of QTextLayout::SkipWords
3244 void QQuickTextInputPrivate::selectWordAtPos(int cursor)
3246 int next = cursor + 1;
3249 int c = m_textLayout.previousCursorPosition(next, QTextLayout::SkipWords);
3250 moveCursor(c, false);
3251 // ## text layout should support end of words.
3252 int end = m_textLayout.nextCursorPosition(c, QTextLayout::SkipWords);
3253 while (end > cursor && m_text[end-1].isSpace())
3255 moveCursor(end, true);
3261 Completes a change to the line control text. If the change is not valid
3262 will undo the line control state back to the given \a validateFromState.
3264 If \a edited is true and the change is valid, will emit textEdited() in
3265 addition to textChanged(). Otherwise only emits textChanged() on a valid
3268 The \a update value is currently unused.
3270 bool QQuickTextInputPrivate::finishChange(int validateFromState, bool update, bool /*edited*/)
3272 Q_Q(QQuickTextInput);
3275 bool inputMethodAttributesChanged = m_textDirty || m_selDirty;
3276 bool alignmentChanged = false;
3280 bool wasValidInput = m_validInput;
3281 bool wasAcceptable = m_acceptableInput;
3282 m_validInput = true;
3283 m_acceptableInput = true;
3284 #ifndef QT_NO_VALIDATOR
3286 QString textCopy = m_text;
3287 int cursorCopy = m_cursor;
3288 QValidator::State state = m_validator->validate(textCopy, cursorCopy);
3289 m_validInput = state != QValidator::Invalid;
3290 m_acceptableInput = state == QValidator::Acceptable;
3292 if (m_text != textCopy) {
3293 internalSetText(textCopy, cursorCopy);
3296 m_cursor = cursorCopy;
3300 if (validateFromState >= 0 && wasValidInput && !m_validInput) {
3301 if (m_transactions.count())
3303 internalUndo(validateFromState);
3304 m_history.resize(m_undoState);
3305 m_validInput = true;
3306 m_acceptableInput = wasAcceptable;
3307 m_textDirty = false;
3311 m_textDirty = false;
3312 m_preeditDirty = false;
3313 alignmentChanged = determineHorizontalAlignment();
3314 emit q->textChanged();
3317 updateDisplayText(alignmentChanged);
3319 if (m_acceptableInput != wasAcceptable)
3320 emit q->acceptableInputChanged();
3322 if (m_preeditDirty) {
3323 m_preeditDirty = false;
3324 if (determineHorizontalAlignment()) {
3325 alignmentChanged = true;
3332 emit q->selectionChanged();
3335 inputMethodAttributesChanged |= (m_cursor != m_lastCursorPos);
3336 if (inputMethodAttributesChanged)
3337 q->updateInputMethod();
3338 emitUndoRedoChanged();
3340 if (!emitCursorPositionChanged() && alignmentChanged)
3341 q->updateCursorRectangle();
3349 An internal function for setting the text of the line control.
3351 void QQuickTextInputPrivate::internalSetText(const QString &txt, int pos, bool edited)
3353 Q_Q(QQuickTextInput);
3355 QString oldText = m_text;
3357 m_text = maskString(0, txt, true);
3358 m_text += clearString(m_text.length(), m_maxLength - m_text.length());
3360 m_text = txt.isEmpty() ? txt : txt.left(m_maxLength);
3364 m_cursor = (pos < 0 || pos > m_text.length()) ? m_text.length() : pos;
3365 m_textDirty = (oldText != m_text);
3367 bool changed = finishChange(-1, true, edited);
3368 #ifdef QT_NO_ACCESSIBILITY
3372 QAccessibleTextUpdateEvent ev(q, 0, oldText, m_text);
3373 QAccessible::updateAccessibility(&ev);
3382 Adds the given \a command to the undo history
3383 of the line control. Does not apply the command.
3385 void QQuickTextInputPrivate::addCommand(const Command &cmd)
3387 if (m_separator && m_undoState && m_history[m_undoState - 1].type != Separator) {
3388 m_history.resize(m_undoState + 2);
3389 m_history[m_undoState++] = Command(Separator, m_cursor, 0, m_selstart, m_selend);
3391 m_history.resize(m_undoState + 1);
3393 m_separator = false;
3394 m_history[m_undoState++] = cmd;
3400 Inserts the given string \a s into the line
3403 Also adds the appropriate commands into the undo history.
3404 This function does not call finishChange(), and may leave the text
3405 in an invalid state.
3407 void QQuickTextInputPrivate::internalInsert(const QString &s)
3409 Q_Q(QQuickTextInput);
3410 if (m_echoMode == QQuickTextInput::Password) {
3411 int delay = qGuiApp->styleHints()->passwordMaskDelay();
3413 m_passwordEchoTimer.start(delay, q);
3415 if (hasSelectedText())
3416 addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
3418 QString ms = maskString(m_cursor, s);
3419 for (int i = 0; i < (int) ms.length(); ++i) {
3420 addCommand (Command(DeleteSelection, m_cursor + i, m_text.at(m_cursor + i), -1, -1));
3421 addCommand(Command(Insert, m_cursor + i, ms.at(i), -1, -1));
3423 m_text.replace(m_cursor, ms.length(), ms);
3424 m_cursor += ms.length();
3425 m_cursor = nextMaskBlank(m_cursor);
3428 int remaining = m_maxLength - m_text.length();
3429 if (remaining != 0) {
3430 m_text.insert(m_cursor, s.left(remaining));
3431 for (int i = 0; i < (int) s.left(remaining).length(); ++i)
3432 addCommand(Command(Insert, m_cursor++, s.at(i), -1, -1));
3441 deletes a single character from the current text. If \a wasBackspace,
3442 the character prior to the cursor is removed. Otherwise the character
3443 after the cursor is removed.
3445 Also adds the appropriate commands into the undo history.
3446 This function does not call finishChange(), and may leave the text
3447 in an invalid state.
3449 void QQuickTextInputPrivate::internalDelete(bool wasBackspace)
3451 if (m_cursor < (int) m_text.length()) {
3452 cancelPasswordEchoTimer();
3453 if (hasSelectedText())
3454 addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
3455 addCommand(Command((CommandType)((m_maskData ? 2 : 0) + (wasBackspace ? Remove : Delete)),
3456 m_cursor, m_text.at(m_cursor), -1, -1));
3458 m_text.replace(m_cursor, 1, clearString(m_cursor, 1));
3459 addCommand(Command(Insert, m_cursor, m_text.at(m_cursor), -1, -1));
3461 m_text.remove(m_cursor, 1);
3470 removes the currently selected text from the line control.
3472 Also adds the appropriate commands into the undo history.
3473 This function does not call finishChange(), and may leave the text
3474 in an invalid state.
3476 void QQuickTextInputPrivate::removeSelectedText()
3478 if (m_selstart < m_selend && m_selend <= (int) m_text.length()) {
3479 cancelPasswordEchoTimer();
3482 addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
3483 if (m_selstart <= m_cursor && m_cursor < m_selend) {
3484 // cursor is within the selection. Split up the commands
3485 // to be able to restore the correct cursor position
3486 for (i = m_cursor; i >= m_selstart; --i)
3487 addCommand (Command(DeleteSelection, i, m_text.at(i), -1, 1));
3488 for (i = m_selend - 1; i > m_cursor; --i)
3489 addCommand (Command(DeleteSelection, i - m_cursor + m_selstart - 1, m_text.at(i), -1, -1));
3491 for (i = m_selend-1; i >= m_selstart; --i)
3492 addCommand (Command(RemoveSelection, i, m_text.at(i), -1, -1));
3495 m_text.replace(m_selstart, m_selend - m_selstart, clearString(m_selstart, m_selend - m_selstart));
3496 for (int i = 0; i < m_selend - m_selstart; ++i)
3497 addCommand(Command(Insert, m_selstart + i, m_text.at(m_selstart + i), -1, -1));
3499 m_text.remove(m_selstart, m_selend - m_selstart);
3501 if (m_cursor > m_selstart)
3502 m_cursor -= qMin(m_cursor, m_selend) - m_selstart;
3511 Parses the input mask specified by \a maskFields to generate
3512 the mask data used to handle input masks.
3514 void QQuickTextInputPrivate::parseInputMask(const QString &maskFields)
3516 int delimiter = maskFields.indexOf(QLatin1Char(';'));
3517 if (maskFields.isEmpty() || delimiter == 0) {
3519 delete [] m_maskData;
3521 m_maxLength = 32767;
3522 internalSetText(QString());
3527 if (delimiter == -1) {
3528 m_blank = QLatin1Char(' ');
3529 m_inputMask = maskFields;
3531 m_inputMask = maskFields.left(delimiter);
3532 m_blank = (delimiter + 1 < maskFields.length()) ? maskFields[delimiter + 1] : QLatin1Char(' ');
3535 // calculate m_maxLength / m_maskData length
3538 for (int i=0; i<m_inputMask.length(); i++) {
3539 c = m_inputMask.at(i);
3540 if (i > 0 && m_inputMask.at(i-1) == QLatin1Char('\\')) {
3544 if (c != QLatin1Char('\\') && c != QLatin1Char('!') &&
3545 c != QLatin1Char('<') && c != QLatin1Char('>') &&
3546 c != QLatin1Char('{') && c != QLatin1Char('}') &&
3547 c != QLatin1Char('[') && c != QLatin1Char(']'))
3551 delete [] m_maskData;
3552 m_maskData = new MaskInputData[m_maxLength];
3554 MaskInputData::Casemode m = MaskInputData::NoCaseMode;
3557 bool escape = false;
3559 for (int i = 0; i < m_inputMask.length(); i++) {
3560 c = m_inputMask.at(i);
3563 m_maskData[index].maskChar = c;
3564 m_maskData[index].separator = s;
3565 m_maskData[index].caseMode = m;
3568 } else if (c == QLatin1Char('<')) {
3569 m = MaskInputData::Lower;
3570 } else if (c == QLatin1Char('>')) {
3571 m = MaskInputData::Upper;
3572 } else if (c == QLatin1Char('!')) {
3573 m = MaskInputData::NoCaseMode;
3574 } else if (c != QLatin1Char('{') && c != QLatin1Char('}') && c != QLatin1Char('[') && c != QLatin1Char(']')) {
3575 switch (c.unicode()) {
3601 m_maskData[index].maskChar = c;
3602 m_maskData[index].separator = s;
3603 m_maskData[index].caseMode = m;
3608 internalSetText(m_text);
3615 checks if the key is valid compared to the inputMask
3617 bool QQuickTextInputPrivate::isValidInput(QChar key, QChar mask) const
3619 switch (mask.unicode()) {
3625 if (key.isLetter() || key == m_blank)
3629 if (key.isLetterOrNumber())
3633 if (key.isLetterOrNumber() || key == m_blank)
3641 if (key.isPrint() || key == m_blank)
3649 if (key.isNumber() || key == m_blank)
3653 if (key.isNumber() && key.digitValue() > 0)
3657 if ((key.isNumber() && key.digitValue() > 0) || key == m_blank)
3661 if (key.isNumber() || key == QLatin1Char('+') || key == QLatin1Char('-') || key == m_blank)
3665 if (key == QLatin1Char('0') || key == QLatin1Char('1'))
3669 if (key == QLatin1Char('0') || key == QLatin1Char('1') || key == m_blank)
3673 if (key.isNumber() || (key >= QLatin1Char('a') && key <= QLatin1Char('f')) || (key >= QLatin1Char('A') && key <= QLatin1Char('F')))
3677 if (key.isNumber() || (key >= QLatin1Char('a') && key <= QLatin1Char('f')) || (key >= QLatin1Char('A') && key <= QLatin1Char('F')) || key == m_blank)
3689 Returns true if the given text \a str is valid for any
3690 validator or input mask set for the line control.
3692 Otherwise returns false
3694 QQuickTextInputPrivate::ValidatorState QQuickTextInputPrivate::hasAcceptableInput(const QString &str) const
3696 #ifndef QT_NO_VALIDATOR
3697 QString textCopy = str;
3698 int cursorCopy = m_cursor;
3700 QValidator::State state = m_validator->validate(textCopy, cursorCopy);
3701 if (state != QValidator::Acceptable)
3702 return ValidatorState(state);
3707 return AcceptableInput;
3709 if (str.length() != m_maxLength)
3710 return InvalidInput;
3712 for (int i=0; i < m_maxLength; ++i) {
3713 if (m_maskData[i].separator) {
3714 if (str.at(i) != m_maskData[i].maskChar)
3715 return InvalidInput;
3717 if (!isValidInput(str.at(i), m_maskData[i].maskChar))
3718 return InvalidInput;
3721 return AcceptableInput;
3727 Applies the inputMask on \a str starting from position \a pos in the mask. \a clear
3728 specifies from where characters should be gotten when a separator is met in \a str - true means
3729 that blanks will be used, false that previous input is used.
3730 Calling this when no inputMask is set is undefined.
3732 QString QQuickTextInputPrivate::maskString(uint pos, const QString &str, bool clear) const
3734 if (pos >= (uint)m_maxLength)
3735 return QString::fromLatin1("");
3738 fill = clear ? clearString(0, m_maxLength) : m_text;
3741 QString s = QString::fromLatin1("");
3743 while (i < m_maxLength) {
3744 if (strIndex < str.length()) {
3745 if (m_maskData[i].separator) {
3746 s += m_maskData[i].maskChar;
3747 if (str[(int)strIndex] == m_maskData[i].maskChar)
3751 if (isValidInput(str[(int)strIndex], m_maskData[i].maskChar)) {
3752 switch (m_maskData[i].caseMode) {
3753 case MaskInputData::Upper:
3754 s += str[(int)strIndex].toUpper();
3756 case MaskInputData::Lower:
3757 s += str[(int)strIndex].toLower();
3760 s += str[(int)strIndex];
3764 // search for separator first
3765 int n = findInMask(i, true, true, str[(int)strIndex]);
3767 if (str.length() != 1 || i == 0 || (i > 0 && (!m_maskData[i-1].separator || m_maskData[i-1].maskChar != str[(int)strIndex]))) {
3768 s += fill.mid(i, n-i+1);
3769 i = n + 1; // update i to find + 1
3772 // search for valid m_blank if not
3773 n = findInMask(i, true, false, str[(int)strIndex]);
3775 s += fill.mid(i, n-i);
3776 switch (m_maskData[n].caseMode) {
3777 case MaskInputData::Upper:
3778 s += str[(int)strIndex].toUpper();
3780 case MaskInputData::Lower:
3781 s += str[(int)strIndex].toLower();
3784 s += str[(int)strIndex];
3786 i = n + 1; // updates i to find + 1
3804 Returns a "cleared" string with only separators and blank chars.
3805 Calling this when no inputMask is set is undefined.
3807 QString QQuickTextInputPrivate::clearString(uint pos, uint len) const
3809 if (pos >= (uint)m_maxLength)
3813 int end = qMin((uint)m_maxLength, pos + len);
3814 for (int i = pos; i < end; ++i)
3815 if (m_maskData[i].separator)
3816 s += m_maskData[i].maskChar;
3826 Strips blank parts of the input in a QQuickTextInputPrivate when an inputMask is set,
3827 separators are still included. Typically "127.0__.0__.1__" becomes "127.0.0.1".
3829 QString QQuickTextInputPrivate::stripString(const QString &str) const
3835 int end = qMin(m_maxLength, (int)str.length());
3836 for (int i = 0; i < end; ++i) {
3837 if (m_maskData[i].separator)
3838 s += m_maskData[i].maskChar;
3839 else if (str[i] != m_blank)
3848 searches forward/backward in m_maskData for either a separator or a m_blank
3850 int QQuickTextInputPrivate::findInMask(int pos, bool forward, bool findSeparator, QChar searchChar) const
3852 if (pos >= m_maxLength || pos < 0)
3855 int end = forward ? m_maxLength : -1;
3856 int step = forward ? 1 : -1;
3860 if (findSeparator) {
3861 if (m_maskData[i].separator && m_maskData[i].maskChar == searchChar)
3864 if (!m_maskData[i].separator) {
3865 if (searchChar.isNull())
3867 else if (isValidInput(searchChar, m_maskData[i].maskChar))
3876 void QQuickTextInputPrivate::internalUndo(int until)
3878 if (!isUndoAvailable())
3880 cancelPasswordEchoTimer();
3882 while (m_undoState && m_undoState > until) {
3883 Command& cmd = m_history[--m_undoState];
3886 m_text.remove(cmd.pos, 1);
3890 m_selstart = cmd.selStart;
3891 m_selend = cmd.selEnd;
3895 case RemoveSelection:
3896 m_text.insert(cmd.pos, cmd.uc);
3897 m_cursor = cmd.pos + 1;
3900 case DeleteSelection:
3901 m_text.insert(cmd.pos, cmd.uc);
3907 if (until < 0 && m_undoState) {
3908 Command& next = m_history[m_undoState-1];
3909 if (next.type != cmd.type && next.type < RemoveSelection
3910 && (cmd.type < RemoveSelection || next.type == Separator))
3917 void QQuickTextInputPrivate::internalRedo()
3919 if (!isRedoAvailable())
3922 while (m_undoState < (int)m_history.size()) {
3923 Command& cmd = m_history[m_undoState++];
3926 m_text.insert(cmd.pos, cmd.uc);
3927 m_cursor = cmd.pos + 1;
3930 m_selstart = cmd.selStart;
3931 m_selend = cmd.selEnd;
3936 case RemoveSelection:
3937 case DeleteSelection:
3938 m_text.remove(cmd.pos, 1);
3939 m_selstart = cmd.selStart;
3940 m_selend = cmd.selEnd;
3944 m_selstart = cmd.selStart;
3945 m_selend = cmd.selEnd;
3949 if (m_undoState < (int)m_history.size()) {
3950 Command& next = m_history[m_undoState];
3951 if (next.type != cmd.type && cmd.type < RemoveSelection && next.type != Separator
3952 && (next.type < RemoveSelection || cmd.type == Separator))
3959 void QQuickTextInputPrivate::emitUndoRedoChanged()
3961 Q_Q(QQuickTextInput);
3962 const bool previousUndo = canUndo;
3963 const bool previousRedo = canRedo;
3965 canUndo = isUndoAvailable();
3966 canRedo = isRedoAvailable();
3968 if (previousUndo != canUndo)
3969 emit q->canUndoChanged();
3970 if (previousRedo != canRedo)
3971 emit q->canRedoChanged();
3977 If the current cursor position differs from the last emitted cursor
3978 position, emits cursorPositionChanged().
3980 bool QQuickTextInputPrivate::emitCursorPositionChanged()
3982 Q_Q(QQuickTextInput);
3983 if (m_cursor != m_lastCursorPos) {
3984 m_lastCursorPos = m_cursor;
3986 q->updateCursorRectangle();
3987 emit q->cursorPositionChanged();
3989 if (!hasSelectedText()) {
3990 if (lastSelectionStart != m_cursor) {
3991 lastSelectionStart = m_cursor;
3992 emit q->selectionStartChanged();
3994 if (lastSelectionEnd != m_cursor) {
3995 lastSelectionEnd = m_cursor;
3996 emit q->selectionEndChanged();
4000 #ifndef QT_NO_ACCESSIBILITY
4001 QAccessibleTextCursorEvent ev(q, m_cursor);
4002 QAccessible::updateAccessibility(&ev);
4011 void QQuickTextInputPrivate::setCursorBlinkPeriod(int msec)
4013 Q_Q(QQuickTextInput);
4014 if (msec == m_blinkPeriod)
4017 q->killTimer(m_blinkTimer);
4020 m_blinkTimer = q->startTimer(msec / 2);
4024 if (m_blinkStatus == 1) {
4025 updateType = UpdatePaintNode;
4029 m_blinkPeriod = msec;
4032 void QQuickTextInput::timerEvent(QTimerEvent *event)
4034 Q_D(QQuickTextInput);
4035 if (event->timerId() == d->m_blinkTimer) {
4036 d->m_blinkStatus = !d->m_blinkStatus;
4037 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
4039 } else if (event->timerId() == d->m_passwordEchoTimer.timerId()) {
4040 d->m_passwordEchoTimer.stop();
4041 d->updateDisplayText();
4045 void QQuickTextInputPrivate::processKeyEvent(QKeyEvent* event)
4047 Q_Q(QQuickTextInput);
4048 bool inlineCompletionAccepted = false;
4050 if (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return) {
4051 if (hasAcceptableInput(m_text) || fixup()) {
4054 if (inlineCompletionAccepted)
4061 if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit
4062 && !m_passwordEchoEditing
4064 && !event->text().isEmpty()
4065 && !(event->modifiers() & Qt::ControlModifier)) {
4066 // Clear the edit and reset to normal echo mode while editing; the
4067 // echo mode switches back when the edit loses focus
4068 // ### resets current content. dubious code; you can
4069 // navigate with keys up, down, back, and select(?), but if you press
4070 // "left" or "right" it clears?
4071 updatePasswordEchoEditing(true);
4075 bool unknown = false;
4076 bool visual = cursorMoveStyle() == Qt::VisualMoveStyle;
4080 #ifndef QT_NO_SHORTCUT
4081 else if (event == QKeySequence::Undo) {
4084 else if (event == QKeySequence::Redo) {
4087 else if (event == QKeySequence::SelectAll) {
4090 #ifndef QT_NO_CLIPBOARD
4091 else if (event == QKeySequence::Copy) {
4094 else if (event == QKeySequence::Paste) {
4096 QClipboard::Mode mode = QClipboard::Clipboard;
4100 else if (event == QKeySequence::Cut) {
4106 else if (event == QKeySequence::DeleteEndOfLine) {
4108 setSelection(m_cursor, end());
4113 #endif //QT_NO_CLIPBOARD
4114 else if (event == QKeySequence::MoveToStartOfLine || event == QKeySequence::MoveToStartOfBlock) {
4117 else if (event == QKeySequence::MoveToEndOfLine || event == QKeySequence::MoveToEndOfBlock) {
4120 else if (event == QKeySequence::SelectStartOfLine || event == QKeySequence::SelectStartOfBlock) {
4123 else if (event == QKeySequence::SelectEndOfLine || event == QKeySequence::SelectEndOfBlock) {
4126 else if (event == QKeySequence::MoveToNextChar) {
4127 if (hasSelectedText()) {
4128 moveCursor(selectionEnd(), false);
4130 cursorForward(0, visual ? 1 : (layoutDirection() == Qt::LeftToRight ? 1 : -1));
4133 else if (event == QKeySequence::SelectNextChar) {
4134 cursorForward(1, visual ? 1 : (layoutDirection() == Qt::LeftToRight ? 1 : -1));
4136 else if (event == QKeySequence::MoveToPreviousChar) {
4137 if (hasSelectedText()) {
4138 moveCursor(selectionStart(), false);
4140 cursorForward(0, visual ? -1 : (layoutDirection() == Qt::LeftToRight ? -1 : 1));
4143 else if (event == QKeySequence::SelectPreviousChar) {
4144 cursorForward(1, visual ? -1 : (layoutDirection() == Qt::LeftToRight ? -1 : 1));
4146 else if (event == QKeySequence::MoveToNextWord) {
4147 if (m_echoMode == QQuickTextInput::Normal)
4148 layoutDirection() == Qt::LeftToRight ? cursorWordForward(0) : cursorWordBackward(0);
4150 layoutDirection() == Qt::LeftToRight ? end(0) : home(0);
4152 else if (event == QKeySequence::MoveToPreviousWord) {
4153 if (m_echoMode == QQuickTextInput::Normal)
4154 layoutDirection() == Qt::LeftToRight ? cursorWordBackward(0) : cursorWordForward(0);
4155 else if (!m_readOnly) {
4156 layoutDirection() == Qt::LeftToRight ? home(0) : end(0);
4159 else if (event == QKeySequence::SelectNextWord) {
4160 if (m_echoMode == QQuickTextInput::Normal)
4161 layoutDirection() == Qt::LeftToRight ? cursorWordForward(1) : cursorWordBackward(1);
4163 layoutDirection() == Qt::LeftToRight ? end(1) : home(1);
4165 else if (event == QKeySequence::SelectPreviousWord) {
4166 if (m_echoMode == QQuickTextInput::Normal)
4167 layoutDirection() == Qt::LeftToRight ? cursorWordBackward(1) : cursorWordForward(1);
4169 layoutDirection() == Qt::LeftToRight ? home(1) : end(1);
4171 else if (event == QKeySequence::Delete) {
4175 else if (event == QKeySequence::DeleteEndOfWord) {
4177 cursorWordForward(true);
4181 else if (event == QKeySequence::DeleteStartOfWord) {
4183 cursorWordBackward(true);
4187 #endif // QT_NO_SHORTCUT
4189 bool handled = false;
4190 if (event->modifiers() & Qt::ControlModifier) {
4191 switch (event->key()) {
4192 case Qt::Key_Backspace:
4194 cursorWordBackward(true);
4202 } else { // ### check for *no* modifier
4203 switch (event->key()) {
4204 case Qt::Key_Backspace:
4216 if (event->key() == Qt::Key_Direction_L || event->key() == Qt::Key_Direction_R) {
4217 setLayoutDirection((event->key() == Qt::Key_Direction_L) ? Qt::LeftToRight : Qt::RightToLeft);
4221 if (unknown && !m_readOnly) {
4222 QString t = event->text();
4223 if (!t.isEmpty() && t.at(0).isPrint()) {