1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the QtQml module of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #include "qquicktextinput_p.h"
43 #include "qquicktextinput_p_p.h"
44 #include "qquickcanvas.h"
46 #include <private/qqmlglobal_p.h>
48 #include <QtQml/qqmlinfo.h>
49 #include <QtGui/qevent.h>
50 #include <QTextBoundaryFinder>
51 #include "qquicktextnode_p.h"
52 #include <QtQuick/qsgsimplerectnode.h>
54 #include <QtGui/qstylehints.h>
55 #include <QtGui/qinputmethod.h>
57 #ifndef QT_NO_ACCESSIBILITY
58 #include "qaccessible.h"
63 DEFINE_BOOL_CONFIG_OPTION(qmlDisableDistanceField, QML_DISABLE_DISTANCEFIELD)
66 \qmlclass TextInput QQuickTextInput
67 \inqmlmodule QtQuick 2
68 \ingroup qml-basic-visual-elements
69 \brief The TextInput item displays an editable line of text.
72 The TextInput element displays a single line of editable plain text.
74 TextInput is used to accept a line of text input. Input constraints
75 can be placed on a TextInput item (for example, through a \l validator or \l inputMask),
76 and setting \l echoMode to an appropriate value enables TextInput to be used for
77 a password input field.
79 On Mac OS X, the Up/Down key bindings for Home/End are explicitly disabled.
80 If you want such bindings (on any platform), you will need to construct them in QML.
82 \sa TextEdit, Text, {declarative/text/textselection}{Text Selection example}
84 QQuickTextInput::QQuickTextInput(QQuickItem* parent)
85 : QQuickImplicitSizeItem(*(new QQuickTextInputPrivate), parent)
91 QQuickTextInput::~QQuickTextInput()
95 void QQuickTextInput::componentComplete()
99 QQuickImplicitSizeItem::componentComplete();
103 updateCursorRectangle();
104 if (d->cursorComponent && d->cursorComponent->isReady())
109 \qmlproperty string QtQuick2::TextInput::text
111 The text in the TextInput.
113 QString QQuickTextInput::text() const
115 Q_D(const QQuickTextInput);
117 QString content = d->m_text;
118 QString res = d->m_maskData ? d->stripString(content) : content;
119 return (res.isNull() ? QString::fromLatin1("") : res);
122 void QQuickTextInput::setText(const QString &s)
124 Q_D(QQuickTextInput);
127 if (d->composeMode())
128 qApp->inputMethod()->reset();
129 d->internalSetText(s, -1, false);
133 \qmlproperty int QtQuick2::TextInput::length
135 Returns the total number of characters in the TextInput item.
137 If the TextInput has an inputMask the length will include mask characters and may differ
138 from the length of the string returned by the \l text property.
140 This property can be faster than querying the length the \l text property as it doesn't
141 require any copying or conversion of the TextInput's internal string data.
144 int QQuickTextInput::length() const
146 Q_D(const QQuickTextInput);
147 return d->m_text.length();
151 \qmlmethod string QtQuick2::TextInput::getText(int start, int end)
153 Returns the section of text that is between the \a start and \a end positions.
155 If the TextInput has an inputMask the length will include mask characters.
158 QString QQuickTextInput::getText(int start, int end) const
160 Q_D(const QQuickTextInput);
165 return d->m_text.mid(start, end - start);
168 QString QQuickTextInputPrivate::realText() const
170 QString res = m_maskData ? stripString(m_text) : m_text;
171 return (res.isNull() ? QString::fromLatin1("") : res);
175 \qmlproperty string QtQuick2::TextInput::font.family
177 Sets the family name of the font.
179 The family name is case insensitive and may optionally include a foundry name, e.g. "Helvetica [Cronyx]".
180 If the family is available from more than one foundry and the foundry isn't specified, an arbitrary foundry is chosen.
181 If the family isn't available a family will be set using the font matching algorithm.
185 \qmlproperty bool QtQuick2::TextInput::font.bold
187 Sets whether the font weight is bold.
191 \qmlproperty enumeration QtQuick2::TextInput::font.weight
193 Sets the font's weight.
195 The weight can be one of:
198 \li Font.Normal - the default
205 TextInput { text: "Hello"; font.weight: Font.DemiBold }
210 \qmlproperty bool QtQuick2::TextInput::font.italic
212 Sets whether the font has an italic style.
216 \qmlproperty bool QtQuick2::TextInput::font.underline
218 Sets whether the text is underlined.
222 \qmlproperty bool QtQuick2::TextInput::font.strikeout
224 Sets whether the font has a strikeout style.
228 \qmlproperty real QtQuick2::TextInput::font.pointSize
230 Sets the font size in points. The point size must be greater than zero.
234 \qmlproperty int QtQuick2::TextInput::font.pixelSize
236 Sets the font size in pixels.
238 Using this function makes the font device dependent.
239 Use \c pointSize to set the size of the font in a device independent manner.
243 \qmlproperty real QtQuick2::TextInput::font.letterSpacing
245 Sets the letter spacing for the font.
247 Letter spacing changes the default spacing between individual letters in the font.
248 A positive value increases the letter spacing by the corresponding pixels; a negative value decreases the spacing.
252 \qmlproperty real QtQuick2::TextInput::font.wordSpacing
254 Sets the word spacing for the font.
256 Word spacing changes the default spacing between individual words.
257 A positive value increases the word spacing by a corresponding amount of pixels,
258 while a negative value decreases the inter-word spacing accordingly.
262 \qmlproperty enumeration QtQuick2::TextInput::font.capitalization
264 Sets the capitalization for the text.
267 \li Font.MixedCase - This is the normal text rendering option where no capitalization change is applied.
268 \li Font.AllUppercase - This alters the text to be rendered in all uppercase type.
269 \li Font.AllLowercase - This alters the text to be rendered in all lowercase type.
270 \li Font.SmallCaps - This alters the text to be rendered in small-caps type.
271 \li Font.Capitalize - This alters the text to be rendered with the first character of each word as an uppercase character.
275 TextInput { text: "Hello"; font.capitalization: Font.AllLowercase }
279 QFont QQuickTextInput::font() const
281 Q_D(const QQuickTextInput);
282 return d->sourceFont;
285 void QQuickTextInput::setFont(const QFont &font)
287 Q_D(QQuickTextInput);
288 if (d->sourceFont == font)
291 d->sourceFont = font;
292 QFont oldFont = d->font;
294 if (d->font.pointSizeF() != -1) {
296 qreal size = qRound(d->font.pointSizeF()*2.0);
297 d->font.setPointSizeF(size/2.0);
299 if (oldFont != d->font) {
301 updateCursorRectangle();
302 updateInputMethod(Qt::ImCursorRectangle | Qt::ImFont);
304 emit fontChanged(d->sourceFont);
308 \qmlproperty color QtQuick2::TextInput::color
312 QColor QQuickTextInput::color() const
314 Q_D(const QQuickTextInput);
318 void QQuickTextInput::setColor(const QColor &c)
320 Q_D(QQuickTextInput);
323 d->textLayoutDirty = true;
324 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
332 \qmlproperty color QtQuick2::TextInput::selectionColor
334 The text highlight color, used behind selections.
336 QColor QQuickTextInput::selectionColor() const
338 Q_D(const QQuickTextInput);
339 return d->selectionColor;
342 void QQuickTextInput::setSelectionColor(const QColor &color)
344 Q_D(QQuickTextInput);
345 if (d->selectionColor == color)
348 d->selectionColor = color;
349 if (d->hasSelectedText()) {
350 d->textLayoutDirty = true;
351 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
354 emit selectionColorChanged();
357 \qmlproperty color QtQuick2::TextInput::selectedTextColor
359 The highlighted text color, used in selections.
361 QColor QQuickTextInput::selectedTextColor() const
363 Q_D(const QQuickTextInput);
364 return d->selectedTextColor;
367 void QQuickTextInput::setSelectedTextColor(const QColor &color)
369 Q_D(QQuickTextInput);
370 if (d->selectedTextColor == color)
373 d->selectedTextColor = color;
374 if (d->hasSelectedText()) {
375 d->textLayoutDirty = true;
376 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
379 emit selectedTextColorChanged();
383 \qmlproperty enumeration QtQuick2::TextInput::horizontalAlignment
384 \qmlproperty enumeration QtQuick2::TextInput::effectiveHorizontalAlignment
385 \qmlproperty enumeration QtQuick2::TextInput::verticalAlignment
387 Sets the horizontal alignment of the text within the TextInput item's
388 width and height. By default, the text alignment follows the natural alignment
389 of the text, for example text that is read from left to right will be aligned to
392 TextInput does not have vertical alignment, as the natural height is
393 exactly the height of the single line of text. If you set the height
394 manually to something larger, TextInput will always be top aligned
395 vertically. You can use anchors to align it however you want within
398 The valid values for \c horizontalAlignment are \c TextInput.AlignLeft, \c TextInput.AlignRight and
399 \c TextInput.AlignHCenter.
401 Valid values for \c verticalAlignment are \c TextInput.AlignTop (default),
402 \c TextInput.AlignBottom \c TextInput.AlignVCenter.
404 When using the attached property LayoutMirroring::enabled to mirror application
405 layouts, the horizontal alignment of text will also be mirrored. However, the property
406 \c horizontalAlignment will remain unchanged. To query the effective horizontal alignment
407 of TextInput, use the read-only property \c effectiveHorizontalAlignment.
409 QQuickTextInput::HAlignment QQuickTextInput::hAlign() const
411 Q_D(const QQuickTextInput);
415 void QQuickTextInput::setHAlign(HAlignment align)
417 Q_D(QQuickTextInput);
418 bool forceAlign = d->hAlignImplicit && d->effectiveLayoutMirror;
419 d->hAlignImplicit = false;
420 if (d->setHAlign(align, forceAlign) && isComponentComplete()) {
422 updateCursorRectangle();
426 void QQuickTextInput::resetHAlign()
428 Q_D(QQuickTextInput);
429 d->hAlignImplicit = true;
430 if (d->determineHorizontalAlignment() && isComponentComplete()) {
432 updateCursorRectangle();
436 QQuickTextInput::HAlignment QQuickTextInput::effectiveHAlign() const
438 Q_D(const QQuickTextInput);
439 QQuickTextInput::HAlignment effectiveAlignment = d->hAlign;
440 if (!d->hAlignImplicit && d->effectiveLayoutMirror) {
442 case QQuickTextInput::AlignLeft:
443 effectiveAlignment = QQuickTextInput::AlignRight;
445 case QQuickTextInput::AlignRight:
446 effectiveAlignment = QQuickTextInput::AlignLeft;
452 return effectiveAlignment;
455 bool QQuickTextInputPrivate::setHAlign(QQuickTextInput::HAlignment alignment, bool forceAlign)
457 Q_Q(QQuickTextInput);
458 if ((hAlign != alignment || forceAlign) && alignment <= QQuickTextInput::AlignHCenter) { // justify not supported
459 QQuickTextInput::HAlignment oldEffectiveHAlign = q->effectiveHAlign();
461 emit q->horizontalAlignmentChanged(alignment);
462 if (oldEffectiveHAlign != q->effectiveHAlign())
463 emit q->effectiveHorizontalAlignmentChanged();
469 bool QQuickTextInputPrivate::determineHorizontalAlignment()
471 if (hAlignImplicit) {
472 // if no explicit alignment has been set, follow the natural layout direction of the text
473 QString text = q_func()->text();
475 text = m_textLayout.preeditAreaText();
476 bool isRightToLeft = text.isEmpty() ? qApp->inputMethod()->inputDirection() == Qt::RightToLeft
477 : text.isRightToLeft();
478 return setHAlign(isRightToLeft ? QQuickTextInput::AlignRight : QQuickTextInput::AlignLeft);
483 QQuickTextInput::VAlignment QQuickTextInput::vAlign() const
485 Q_D(const QQuickTextInput);
489 void QQuickTextInput::setVAlign(QQuickTextInput::VAlignment alignment)
491 Q_D(QQuickTextInput);
492 if (alignment == d->vAlign)
494 d->vAlign = alignment;
495 emit verticalAlignmentChanged(d->vAlign);
496 if (isComponentComplete()) {
497 updateCursorRectangle();
502 \qmlproperty enumeration QtQuick2::TextInput::wrapMode
504 Set this property to wrap the text to the TextInput item's width.
505 The text will only wrap if an explicit width has been set.
508 \li TextInput.NoWrap - no wrapping will be performed. If the text contains insufficient newlines, then implicitWidth will exceed a set width.
509 \li TextInput.WordWrap - wrapping is done on word boundaries only. If a word is too long, implicitWidth will exceed a set width.
510 \li TextInput.WrapAnywhere - wrapping is done at any point on a line, even if it occurs in the middle of a word.
511 \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.
514 The default is TextInput.NoWrap. If you set a width, consider using TextInput.Wrap.
516 QQuickTextInput::WrapMode QQuickTextInput::wrapMode() const
518 Q_D(const QQuickTextInput);
522 void QQuickTextInput::setWrapMode(WrapMode mode)
524 Q_D(QQuickTextInput);
525 if (mode == d->wrapMode)
529 updateCursorRectangle();
530 emit wrapModeChanged();
533 void QQuickTextInputPrivate::mirrorChange()
535 Q_Q(QQuickTextInput);
536 if (q->isComponentComplete()) {
537 if (!hAlignImplicit && (hAlign == QQuickTextInput::AlignRight || hAlign == QQuickTextInput::AlignLeft)) {
538 q->updateCursorRectangle();
539 emit q->effectiveHorizontalAlignmentChanged();
545 \qmlproperty bool QtQuick2::TextInput::readOnly
547 Sets whether user input can modify the contents of the TextInput.
549 If readOnly is set to true, then user input will not affect the text
550 property. Any bindings or attempts to set the text property will still
553 bool QQuickTextInput::isReadOnly() const
555 Q_D(const QQuickTextInput);
556 return d->m_readOnly;
559 void QQuickTextInput::setReadOnly(bool ro)
561 Q_D(QQuickTextInput);
562 if (d->m_readOnly == ro)
565 setFlag(QQuickItem::ItemAcceptsInputMethod, !ro);
568 d->setCursorPosition(d->end());
569 updateInputMethod(Qt::ImEnabled);
571 d->emitUndoRedoChanged();
572 emit readOnlyChanged(ro);
576 \qmlproperty int QtQuick2::TextInput::maximumLength
577 The maximum permitted length of the text in the TextInput.
579 If the text is too long, it is truncated at the limit.
581 By default, this property contains a value of 32767.
583 int QQuickTextInput::maxLength() const
585 Q_D(const QQuickTextInput);
586 return d->m_maxLength;
589 void QQuickTextInput::setMaxLength(int ml)
591 Q_D(QQuickTextInput);
592 if (d->m_maxLength == ml || d->m_maskData)
596 d->internalSetText(d->m_text, -1, false);
598 emit maximumLengthChanged(ml);
602 \qmlproperty bool QtQuick2::TextInput::cursorVisible
603 Set to true when the TextInput shows a cursor.
605 This property is set and unset when the TextInput gets active focus, so that other
606 properties can be bound to whether the cursor is currently showing. As it
607 gets set and unset automatically, when you set the value yourself you must
608 keep in mind that your value may be overwritten.
610 It can be set directly in script, for example if a KeyProxy might
611 forward keys to it and you desire it to look active when this happens
612 (but without actually giving it active focus).
614 It should not be set directly on the element, like in the below QML,
615 as the specified value will be overridden an lost on focus changes.
624 In the above snippet the cursor will still become visible when the
625 TextInput gains active focus.
627 bool QQuickTextInput::isCursorVisible() const
629 Q_D(const QQuickTextInput);
630 return d->cursorVisible;
633 void QQuickTextInput::setCursorVisible(bool on)
635 Q_D(QQuickTextInput);
636 if (d->cursorVisible == on)
638 d->cursorVisible = on;
639 d->setCursorBlinkPeriod(on ? qApp->styleHints()->cursorFlashTime() : 0);
640 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
642 emit cursorVisibleChanged(d->cursorVisible);
646 \qmlproperty int QtQuick2::TextInput::cursorPosition
647 The position of the cursor in the TextInput.
649 int QQuickTextInput::cursorPosition() const
651 Q_D(const QQuickTextInput);
655 void QQuickTextInput::setCursorPosition(int cp)
657 Q_D(QQuickTextInput);
658 if (cp < 0 || cp > text().length())
664 \qmlproperty rectangle QtQuick2::TextInput::cursorRectangle
666 The rectangle where the standard text cursor is rendered within the text input. Read only.
668 The position and height of a custom cursorDelegate are updated to follow the cursorRectangle
669 automatically when it changes. The width of the delegate is unaffected by changes in the
673 QRectF QQuickTextInput::cursorRectangle() const
675 Q_D(const QQuickTextInput);
678 if (d->m_preeditCursor != -1)
679 c += d->m_preeditCursor;
680 if (d->m_echoMode == NoEcho)
682 QTextLine l = d->m_textLayout.lineForTextPosition(c);
685 return QRectF(l.cursorToX(c) - d->hscroll, l.y() - d->vscroll, 1, l.height());
689 \qmlproperty int QtQuick2::TextInput::selectionStart
691 The cursor position before the first character in the current selection.
693 This property is read-only. To change the selection, use select(start,end),
694 selectAll(), or selectWord().
696 \sa selectionEnd, cursorPosition, selectedText
698 int QQuickTextInput::selectionStart() const
700 Q_D(const QQuickTextInput);
701 return d->lastSelectionStart;
704 \qmlproperty int QtQuick2::TextInput::selectionEnd
706 The cursor position after the last character in the current selection.
708 This property is read-only. To change the selection, use select(start,end),
709 selectAll(), or selectWord().
711 \sa selectionStart, cursorPosition, selectedText
713 int QQuickTextInput::selectionEnd() const
715 Q_D(const QQuickTextInput);
716 return d->lastSelectionEnd;
719 \qmlmethod void QtQuick2::TextInput::select(int start, int end)
721 Causes the text from \a start to \a end to be selected.
723 If either start or end is out of range, the selection is not changed.
725 After calling this, selectionStart will become the lesser
726 and selectionEnd will become the greater (regardless of the order passed
729 \sa selectionStart, selectionEnd
731 void QQuickTextInput::select(int start, int end)
733 Q_D(QQuickTextInput);
734 if (start < 0 || end < 0 || start > d->m_text.length() || end > d->m_text.length())
736 d->setSelection(start, end-start);
740 \qmlproperty string QtQuick2::TextInput::selectedText
742 This read-only property provides the text currently selected in the
745 It is equivalent to the following snippet, but is faster and easier
749 myTextInput.text.toString().substring(myTextInput.selectionStart,
750 myTextInput.selectionEnd);
753 QString QQuickTextInput::selectedText() const
755 Q_D(const QQuickTextInput);
756 return d->selectedText();
760 \qmlproperty bool QtQuick2::TextInput::activeFocusOnPress
762 Whether the TextInput should gain active focus on a mouse press. By default this is
765 bool QQuickTextInput::focusOnPress() const
767 Q_D(const QQuickTextInput);
768 return d->focusOnPress;
771 void QQuickTextInput::setFocusOnPress(bool b)
773 Q_D(QQuickTextInput);
774 if (d->focusOnPress == b)
779 emit activeFocusOnPressChanged(d->focusOnPress);
782 \qmlproperty bool QtQuick2::TextInput::autoScroll
784 Whether the TextInput should scroll when the text is longer than the width. By default this is
787 bool QQuickTextInput::autoScroll() const
789 Q_D(const QQuickTextInput);
790 return d->autoScroll;
793 void QQuickTextInput::setAutoScroll(bool b)
795 Q_D(QQuickTextInput);
796 if (d->autoScroll == b)
800 //We need to repaint so that the scrolling is taking into account.
801 updateCursorRectangle();
802 emit autoScrollChanged(d->autoScroll);
805 #ifndef QT_NO_VALIDATOR
808 \qmlclass IntValidator QIntValidator
809 \inqmlmodule QtQuick 2
810 \ingroup qml-basic-visual-elements
812 This element provides a validator for integer values.
814 If no \l locale is set IntValidator uses the \l {QLocale::setDefault()}{default locale} to
815 interpret the number and will accept locale specific digits, group separators, and positive
816 and negative signs. In addition, IntValidator is always guaranteed to accept a number
817 formatted according to the "C" locale.
821 QQuickIntValidator::QQuickIntValidator(QObject *parent)
822 : QIntValidator(parent)
827 \qmlproperty string QtQuick2::IntValidator::locale
829 This property holds the name of the locale used to interpret the number.
834 QString QQuickIntValidator::localeName() const
836 return locale().name();
839 void QQuickIntValidator::setLocaleName(const QString &name)
841 if (locale().name() != name) {
842 setLocale(QLocale(name));
843 emit localeNameChanged();
847 void QQuickIntValidator::resetLocaleName()
849 QLocale defaultLocale;
850 if (locale() != defaultLocale) {
851 setLocale(defaultLocale);
852 emit localeNameChanged();
857 \qmlproperty int QtQuick2::IntValidator::top
859 This property holds the validator's highest acceptable value.
860 By default, this property's value is derived from the highest signed integer available (typically 2147483647).
863 \qmlproperty int QtQuick2::IntValidator::bottom
865 This property holds the validator's lowest acceptable value.
866 By default, this property's value is derived from the lowest signed integer available (typically -2147483647).
870 \qmlclass DoubleValidator QDoubleValidator
871 \inqmlmodule QtQuick 2
872 \ingroup qml-basic-visual-elements
874 This element provides a validator for non-integer numbers.
876 Input is accepted if it contains a double that is within the valid range
877 and is in the correct format.
879 Input is accepected but invalid if it contains a double that is outside
880 the range or is in the wrong format; e.g. with too many digits after the
881 decimal point or is empty.
883 Input is rejected if it is not a double.
885 Note: If the valid range consists of just positive doubles (e.g. 0.0 to
886 100.0) and input is a negative double then it is rejected. If \l notation
887 is set to DoubleValidator.StandardNotation, and the input contains more
888 digits before the decimal point than a double in the valid range may have,
889 it is also rejected. If \l notation is DoubleValidator.ScientificNotation,
890 and the input is not in the valid range, it is accecpted but invalid. The
891 value may yet become valid by changing the exponent.
894 QQuickDoubleValidator::QQuickDoubleValidator(QObject *parent)
895 : QDoubleValidator(parent)
900 \qmlproperty string QtQuick2::DoubleValidator::locale
902 This property holds the name of the locale used to interpret the number.
907 QString QQuickDoubleValidator::localeName() const
909 return locale().name();
912 void QQuickDoubleValidator::setLocaleName(const QString &name)
914 if (locale().name() != name) {
915 setLocale(QLocale(name));
916 emit localeNameChanged();
920 void QQuickDoubleValidator::resetLocaleName()
922 QLocale defaultLocale;
923 if (locale() != defaultLocale) {
924 setLocale(defaultLocale);
925 emit localeNameChanged();
930 \qmlproperty real QtQuick2::DoubleValidator::top
932 This property holds the validator's maximum acceptable value.
933 By default, this property contains a value of infinity.
936 \qmlproperty real QtQuick2::DoubleValidator::bottom
938 This property holds the validator's minimum acceptable value.
939 By default, this property contains a value of -infinity.
942 \qmlproperty int QtQuick2::DoubleValidator::decimals
944 This property holds the validator's maximum number of digits after the decimal point.
945 By default, this property contains a value of 1000.
948 \qmlproperty enumeration QtQuick2::DoubleValidator::notation
949 This property holds the notation of how a string can describe a number.
951 The possible values for this property are:
954 \li DoubleValidator.StandardNotation
955 \li DoubleValidator.ScientificNotation (default)
958 If this property is set to DoubleValidator.ScientificNotation, the written number may have an exponent part (e.g. 1.5E-2).
962 \qmlclass RegExpValidator QRegExpValidator
963 \inqmlmodule QtQuick 2
964 \ingroup qml-basic-visual-elements
966 This element provides a validator, which counts as valid any string which
967 matches a specified regular expression.
970 \qmlproperty regExp QtQuick2::RegExpValidator::regExp
972 This property holds the regular expression used for validation.
974 Note that this property should be a regular expression in JS syntax, e.g /a/ for the regular expression
977 By default, this property contains a regular expression with the pattern .* that matches any string.
981 \qmlproperty Validator QtQuick2::TextInput::validator
983 Allows you to set a validator on the TextInput. When a validator is set
984 the TextInput will only accept input which leaves the text property in
985 an acceptable or intermediate state. The accepted signal will only be sent
986 if the text is in an acceptable state when enter is pressed.
988 Currently supported validators are IntValidator, DoubleValidator and
989 RegExpValidator. An example of using validators is shown below, which allows
990 input of integers between 11 and 31 into the text input:
995 validator: IntValidator{bottom: 11; top: 31;}
1000 \sa acceptableInput, inputMask
1003 QValidator* QQuickTextInput::validator() const
1005 Q_D(const QQuickTextInput);
1006 return d->m_validator;
1009 void QQuickTextInput::setValidator(QValidator* v)
1011 Q_D(QQuickTextInput);
1012 if (d->m_validator == v)
1017 if (isComponentComplete())
1020 emit validatorChanged();
1023 #endif // QT_NO_VALIDATOR
1025 void QQuickTextInputPrivate::checkIsValid()
1027 Q_Q(QQuickTextInput);
1029 ValidatorState state = hasAcceptableInput(m_text);
1030 m_validInput = state != InvalidInput;
1031 if (state != AcceptableInput) {
1032 if (m_acceptableInput) {
1033 m_acceptableInput = false;
1034 emit q->acceptableInputChanged();
1036 } else if (!m_acceptableInput) {
1037 m_acceptableInput = true;
1038 emit q->acceptableInputChanged();
1043 \qmlproperty string QtQuick2::TextInput::inputMask
1045 Allows you to set an input mask on the TextInput, restricting the allowable
1046 text inputs. See QLineEdit::inputMask for further details, as the exact
1047 same mask strings are used by TextInput.
1049 \sa acceptableInput, validator
1051 QString QQuickTextInput::inputMask() const
1053 Q_D(const QQuickTextInput);
1054 return d->inputMask();
1057 void QQuickTextInput::setInputMask(const QString &im)
1059 Q_D(QQuickTextInput);
1060 if (d->inputMask() == im)
1063 d->setInputMask(im);
1064 emit inputMaskChanged(d->inputMask());
1068 \qmlproperty bool QtQuick2::TextInput::acceptableInput
1070 This property is always true unless a validator or input mask has been set.
1071 If a validator or input mask has been set, this property will only be true
1072 if the current text is acceptable to the validator or input mask as a final
1073 string (not as an intermediate string).
1075 bool QQuickTextInput::hasAcceptableInput() const
1077 Q_D(const QQuickTextInput);
1078 return d->hasAcceptableInput(d->m_text) == QQuickTextInputPrivate::AcceptableInput;
1082 \qmlsignal QtQuick2::TextInput::onAccepted()
1084 This handler is called when the Return or Enter key is pressed.
1085 Note that if there is a \l validator or \l inputMask set on the text
1086 input, the handler will only be emitted if the input is in an acceptable
1090 Qt::InputMethodHints QQuickTextInputPrivate::effectiveInputMethodHints() const
1092 Qt::InputMethodHints hints = inputMethodHints;
1093 if (m_echoMode == QQuickTextInput::Password || m_echoMode == QQuickTextInput::NoEcho)
1094 hints |= Qt::ImhHiddenText;
1095 else if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit)
1096 hints &= ~Qt::ImhHiddenText;
1097 if (m_echoMode != QQuickTextInput::Normal)
1098 hints |= (Qt::ImhNoAutoUppercase | Qt::ImhNoPredictiveText | Qt::ImhSensitiveData);
1102 \qmlproperty enumeration QtQuick2::TextInput::echoMode
1104 Specifies how the text should be displayed in the TextInput.
1106 \li TextInput.Normal - Displays the text as it is. (Default)
1107 \li TextInput.Password - Displays asterisks instead of characters.
1108 \li TextInput.NoEcho - Displays nothing.
1109 \li TextInput.PasswordEchoOnEdit - Displays characters as they are entered
1110 while editing, otherwise displays asterisks.
1113 QQuickTextInput::EchoMode QQuickTextInput::echoMode() const
1115 Q_D(const QQuickTextInput);
1116 return QQuickTextInput::EchoMode(d->m_echoMode);
1119 void QQuickTextInput::setEchoMode(QQuickTextInput::EchoMode echo)
1121 Q_D(QQuickTextInput);
1122 if (echoMode() == echo)
1124 d->cancelPasswordEchoTimer();
1125 d->m_echoMode = echo;
1126 d->m_passwordEchoEditing = false;
1127 updateInputMethod(Qt::ImHints);
1128 d->updateDisplayText();
1129 updateCursorRectangle();
1131 emit echoModeChanged(echoMode());
1135 \qmlproperty enumeration QtQuick2::TextInput::inputMethodHints
1137 Provides hints to the input method about the expected content of the text input and how it
1140 The value is a bit-wise combination of flags, or Qt.ImhNone if no hints are set.
1142 Flags that alter behaviour are:
1145 \li Qt.ImhHiddenText - Characters should be hidden, as is typically used when entering passwords.
1146 This is automatically set when setting echoMode to \c TextInput.Password.
1147 \li Qt.ImhSensitiveData - Typed text should not be stored by the active input method
1148 in any persistent storage like predictive user dictionary.
1149 \li Qt.ImhNoAutoUppercase - The input method should not try to automatically switch to upper case
1150 when a sentence ends.
1151 \li Qt.ImhPreferNumbers - Numbers are preferred (but not required).
1152 \li Qt.ImhPreferUppercase - Upper case letters are preferred (but not required).
1153 \li Qt.ImhPreferLowercase - Lower case letters are preferred (but not required).
1154 \li Qt.ImhNoPredictiveText - Do not use predictive text (i.e. dictionary lookup) while typing.
1156 \li Qt.ImhDate - The text editor functions as a date field.
1157 \li Qt.ImhTime - The text editor functions as a time field.
1160 Flags that restrict input (exclusive flags) are:
1163 \li Qt.ImhDigitsOnly - Only digits are allowed.
1164 \li Qt.ImhFormattedNumbersOnly - Only number input is allowed. This includes decimal point and minus sign.
1165 \li Qt.ImhUppercaseOnly - Only upper case letter input is allowed.
1166 \li Qt.ImhLowercaseOnly - Only lower case letter input is allowed.
1167 \li Qt.ImhDialableCharactersOnly - Only characters suitable for phone dialing are allowed.
1168 \li Qt.ImhEmailCharactersOnly - Only characters suitable for email addresses are allowed.
1169 \li Qt.ImhUrlCharactersOnly - Only characters suitable for URLs are allowed.
1175 \li Qt.ImhExclusiveInputMask - This mask yields nonzero if any of the exclusive flags are used.
1179 Qt::InputMethodHints QQuickTextInput::inputMethodHints() const
1181 Q_D(const QQuickTextInput);
1182 return d->inputMethodHints;
1185 void QQuickTextInput::setInputMethodHints(Qt::InputMethodHints hints)
1187 Q_D(QQuickTextInput);
1189 if (hints == d->inputMethodHints)
1192 d->inputMethodHints = hints;
1193 updateInputMethod(Qt::ImHints);
1194 emit inputMethodHintsChanged();
1198 \qmlproperty Component QtQuick2::TextInput::cursorDelegate
1199 The delegate for the cursor in the TextInput.
1201 If you set a cursorDelegate for a TextInput, this delegate will be used for
1202 drawing the cursor instead of the standard cursor. An instance of the
1203 delegate will be created and managed by the TextInput when a cursor is
1204 needed, and the x property of delegate instance will be set so as
1205 to be one pixel before the top left of the current character.
1207 Note that the root item of the delegate component must be a QQuickItem or
1208 QQuickItem derived item.
1210 QQmlComponent* QQuickTextInput::cursorDelegate() const
1212 Q_D(const QQuickTextInput);
1213 return d->cursorComponent;
1216 void QQuickTextInput::setCursorDelegate(QQmlComponent* c)
1218 Q_D(QQuickTextInput);
1219 if (d->cursorComponent == c)
1222 d->cursorComponent = c;
1224 //note that the components are owned by something else
1225 delete d->cursorItem;
1228 d->startCreatingCursor();
1231 emit cursorDelegateChanged();
1234 void QQuickTextInputPrivate::startCreatingCursor()
1236 Q_Q(QQuickTextInput);
1237 if (cursorComponent->isReady()) {
1239 } else if (cursorComponent->isLoading()) {
1240 q->connect(cursorComponent, SIGNAL(statusChanged(int)),
1241 q, SLOT(createCursor()));
1243 qmlInfo(q, cursorComponent->errors()) << QQuickTextInput::tr("Could not load cursor delegate");
1247 void QQuickTextInput::createCursor()
1249 Q_D(QQuickTextInput);
1250 if (!isComponentComplete())
1253 if (d->cursorComponent->isError()) {
1254 qmlInfo(this, d->cursorComponent->errors()) << tr("Could not load cursor delegate");
1258 if (!d->cursorComponent->isReady())
1262 delete d->cursorItem;
1263 QQmlContext *creationContext = d->cursorComponent->creationContext();
1264 QObject *object = d->cursorComponent->create(creationContext ? creationContext : qmlContext(this));
1265 d->cursorItem = qobject_cast<QQuickItem*>(object);
1266 if (!d->cursorItem) {
1268 qmlInfo(this, d->cursorComponent->errors()) << tr("Could not instantiate cursor delegate");
1272 QRectF r = cursorRectangle();
1274 QQml_setParent_noEvent(d->cursorItem, this);
1275 d->cursorItem->setParentItem(this);
1276 d->cursorItem->setPos(r.topLeft());
1277 d->cursorItem->setHeight(r.height());
1281 \qmlmethod rect QtQuick2::TextInput::positionToRectangle(int pos)
1283 This function takes a character position and returns the rectangle that the
1284 cursor would occupy, if it was placed at that character position.
1286 This is similar to setting the cursorPosition, and then querying the cursor
1287 rectangle, but the cursorPosition is not changed.
1289 QRectF QQuickTextInput::positionToRectangle(int pos) const
1291 Q_D(const QQuickTextInput);
1292 if (d->m_echoMode == NoEcho)
1294 else if (pos > d->m_cursor)
1295 pos += d->preeditAreaText().length();
1296 QTextLine l = d->m_textLayout.lineForTextPosition(pos);
1298 ? QRectF(l.cursorToX(pos) - d->hscroll, l.y() - d->vscroll, 1, l.height())
1303 \qmlmethod int QtQuick2::TextInput::positionAt(real x, real y, CursorPosition position = CursorBetweenCharacters)
1305 This function returns the character position at
1306 x and y pixels from the top left of the textInput. Position 0 is before the
1307 first character, position 1 is after the first character but before the second,
1308 and so on until position text.length, which is after all characters.
1310 This means that for all x values before the first character this function returns 0,
1311 and for all x values after the last character this function returns text.length. If
1312 the y value is above the text the position will be that of the nearest character on
1313 the first line line and if it is below the text the position of the nearest character
1314 on the last line will be returned.
1316 The cursor position type specifies how the cursor position should be resolved.
1319 \li TextInput.CursorBetweenCharacters - Returns the position between characters that is nearest x.
1320 \li TextInput.CursorOnCharacter - Returns the position before the character that is nearest x.
1324 void QQuickTextInput::positionAt(QQmlV8Function *args) const
1326 Q_D(const QQuickTextInput);
1330 QTextLine::CursorPosition position = QTextLine::CursorBetweenCharacters;
1332 if (args->Length() < 1)
1336 v8::Local<v8::Value> arg = (*args)[i];
1337 x = arg->NumberValue();
1339 if (++i < args->Length()) {
1341 y = arg->NumberValue();
1344 if (++i < args->Length()) {
1346 position = QTextLine::CursorPosition(arg->Int32Value());
1349 int pos = d->positionAt(x, y, position);
1350 const int cursor = d->m_cursor;
1352 const int preeditLength = d->preeditAreaText().length();
1353 pos = pos > cursor + preeditLength
1354 ? pos - preeditLength
1357 args->returnValue(v8::Int32::New(pos));
1360 int QQuickTextInputPrivate::positionAt(qreal x, qreal y, QTextLine::CursorPosition position) const
1364 QTextLine line = m_textLayout.lineAt(0);
1365 for (int i = 1; i < m_textLayout.lineCount(); ++i) {
1366 QTextLine nextLine = m_textLayout.lineAt(i);
1368 if (y < (line.rect().bottom() + nextLine.y()) / 2)
1372 return line.isValid() ? line.xToCursor(x, position) : 0;
1375 void QQuickTextInput::keyPressEvent(QKeyEvent* ev)
1377 Q_D(QQuickTextInput);
1378 // Don't allow MacOSX up/down support, and we don't allow a completer.
1379 bool ignore = (ev->key() == Qt::Key_Up || ev->key() == Qt::Key_Down) && ev->modifiers() == Qt::NoModifier;
1380 if (!ignore && (d->lastSelectionStart == d->lastSelectionEnd) && (ev->key() == Qt::Key_Right || ev->key() == Qt::Key_Left)) {
1381 // Ignore when moving off the end unless there is a selection,
1382 // because then moving will do something (deselect).
1383 int cursorPosition = d->m_cursor;
1384 if (cursorPosition == 0)
1385 ignore = ev->key() == (d->layoutDirection() == Qt::LeftToRight ? Qt::Key_Left : Qt::Key_Right);
1386 if (cursorPosition == text().length())
1387 ignore = ev->key() == (d->layoutDirection() == Qt::LeftToRight ? Qt::Key_Right : Qt::Key_Left);
1392 d->processKeyEvent(ev);
1394 if (!ev->isAccepted())
1395 QQuickImplicitSizeItem::keyPressEvent(ev);
1398 void QQuickTextInput::inputMethodEvent(QInputMethodEvent *ev)
1400 Q_D(QQuickTextInput);
1401 const bool wasComposing = d->preeditAreaText().length() > 0;
1402 if (d->m_readOnly) {
1405 d->processInputMethodEvent(ev);
1407 if (!ev->isAccepted())
1408 QQuickImplicitSizeItem::inputMethodEvent(ev);
1410 if (wasComposing != (d->m_textLayout.preeditAreaText().length() > 0))
1411 emit inputMethodComposingChanged();
1414 void QQuickTextInput::mouseDoubleClickEvent(QMouseEvent *event)
1416 Q_D(QQuickTextInput);
1418 if (d->selectByMouse && event->button() == Qt::LeftButton) {
1420 int cursor = d->positionAt(event->localPos());
1421 d->selectWordAtPos(cursor);
1422 event->setAccepted(true);
1423 if (!d->hasPendingTripleClick()) {
1424 d->tripleClickStartPoint = event->localPos();
1425 d->tripleClickTimer.start();
1428 if (d->sendMouseEventToInputContext(event))
1430 QQuickImplicitSizeItem::mouseDoubleClickEvent(event);
1434 void QQuickTextInput::mousePressEvent(QMouseEvent *event)
1436 Q_D(QQuickTextInput);
1438 d->pressPos = event->localPos();
1440 if (d->sendMouseEventToInputContext(event))
1443 if (d->selectByMouse) {
1444 setKeepMouseGrab(false);
1445 d->selectPressed = true;
1446 QPointF distanceVector = d->pressPos - d->tripleClickStartPoint;
1447 if (d->hasPendingTripleClick()
1448 && distanceVector.manhattanLength() < qApp->styleHints()->startDragDistance()) {
1449 event->setAccepted(true);
1455 bool mark = (event->modifiers() & Qt::ShiftModifier) && d->selectByMouse;
1456 int cursor = d->positionAt(event->localPos());
1457 d->moveCursor(cursor, mark);
1459 if (d->focusOnPress) {
1460 bool hadActiveFocus = hasActiveFocus();
1462 // re-open input panel on press if already focused
1463 if (hasActiveFocus() && hadActiveFocus && !d->m_readOnly)
1464 openSoftwareInputPanel();
1467 event->setAccepted(true);
1470 void QQuickTextInput::mouseMoveEvent(QMouseEvent *event)
1472 Q_D(QQuickTextInput);
1474 if (d->selectPressed) {
1475 if (qAbs(int(event->localPos().x() - d->pressPos.x())) > qApp->styleHints()->startDragDistance())
1476 setKeepMouseGrab(true);
1478 if (d->composeMode()) {
1480 int startPos = d->positionAt(d->pressPos);
1481 int currentPos = d->positionAt(event->localPos());
1482 if (startPos != currentPos)
1483 d->setSelection(startPos, currentPos - startPos);
1485 moveCursorSelection(d->positionAt(event->localPos()), d->mouseSelectionMode);
1487 event->setAccepted(true);
1489 QQuickImplicitSizeItem::mouseMoveEvent(event);
1493 void QQuickTextInput::mouseReleaseEvent(QMouseEvent *event)
1495 Q_D(QQuickTextInput);
1496 if (d->sendMouseEventToInputContext(event))
1498 if (d->selectPressed) {
1499 d->selectPressed = false;
1500 setKeepMouseGrab(false);
1502 #ifndef QT_NO_CLIPBOARD
1503 if (QGuiApplication::clipboard()->supportsSelection()) {
1504 if (event->button() == Qt::LeftButton) {
1505 d->copy(QClipboard::Selection);
1506 } else if (!d->m_readOnly && event->button() == Qt::MidButton) {
1508 d->insert(QGuiApplication::clipboard()->text(QClipboard::Selection));
1512 if (!event->isAccepted())
1513 QQuickImplicitSizeItem::mouseReleaseEvent(event);
1516 bool QQuickTextInputPrivate::sendMouseEventToInputContext(QMouseEvent *event)
1518 #if !defined QT_NO_IM
1519 if (composeMode()) {
1520 int tmp_cursor = positionAt(event->localPos());
1521 int mousePos = tmp_cursor - m_cursor;
1522 if (mousePos >= 0 && mousePos <= m_textLayout.preeditAreaText().length()) {
1523 if (event->type() == QEvent::MouseButtonRelease) {
1524 qApp->inputMethod()->invokeAction(QInputMethod::Click, mousePos);
1537 void QQuickTextInput::mouseUngrabEvent()
1539 Q_D(QQuickTextInput);
1540 d->selectPressed = false;
1541 setKeepMouseGrab(false);
1544 bool QQuickTextInput::event(QEvent* ev)
1546 #ifndef QT_NO_SHORTCUT
1547 Q_D(QQuickTextInput);
1548 if (ev->type() == QEvent::ShortcutOverride) {
1551 QKeyEvent* ke = static_cast<QKeyEvent*>(ev);
1552 if (ke == QKeySequence::Copy
1553 || ke == QKeySequence::Paste
1554 || ke == QKeySequence::Cut
1555 || ke == QKeySequence::Redo
1556 || ke == QKeySequence::Undo
1557 || ke == QKeySequence::MoveToNextWord
1558 || ke == QKeySequence::MoveToPreviousWord
1559 || ke == QKeySequence::MoveToStartOfDocument
1560 || ke == QKeySequence::MoveToEndOfDocument
1561 || ke == QKeySequence::SelectNextWord
1562 || ke == QKeySequence::SelectPreviousWord
1563 || ke == QKeySequence::SelectStartOfLine
1564 || ke == QKeySequence::SelectEndOfLine
1565 || ke == QKeySequence::SelectStartOfBlock
1566 || ke == QKeySequence::SelectEndOfBlock
1567 || ke == QKeySequence::SelectStartOfDocument
1568 || ke == QKeySequence::SelectAll
1569 || ke == QKeySequence::SelectEndOfDocument) {
1571 } else if (ke->modifiers() == Qt::NoModifier || ke->modifiers() == Qt::ShiftModifier
1572 || ke->modifiers() == Qt::KeypadModifier) {
1573 if (ke->key() < Qt::Key_Escape) {
1577 switch (ke->key()) {
1578 case Qt::Key_Delete:
1581 case Qt::Key_Backspace:
1593 return QQuickImplicitSizeItem::event(ev);
1596 void QQuickTextInput::geometryChanged(const QRectF &newGeometry,
1597 const QRectF &oldGeometry)
1599 Q_D(QQuickTextInput);
1601 if (newGeometry.width() != oldGeometry.width() && d->wrapMode != NoWrap)
1603 updateCursorRectangle();
1605 QQuickImplicitSizeItem::geometryChanged(newGeometry, oldGeometry);
1608 void QQuickTextInputPrivate::updateHorizontalScroll()
1610 Q_Q(QQuickTextInput);
1611 QTextLine currentLine = m_textLayout.lineForTextPosition(m_cursor + m_preeditCursor);
1612 const int preeditLength = m_textLayout.preeditAreaText().length();
1613 const qreal width = qMax<qreal>(0, q->width());
1615 qreal widthUsed = 0;
1616 if (currentLine.isValid()) {
1617 cix = currentLine.cursorToX(m_cursor + preeditLength);
1618 const qreal cursorWidth = cix >= 0 ? cix : width - cix;
1619 widthUsed = qMax(currentLine.naturalTextWidth(), cursorWidth);
1621 int previousScroll = hscroll;
1623 if (!autoScroll || widthUsed <= width || m_echoMode == QQuickTextInput::NoEcho) {
1626 Q_ASSERT(currentLine.isValid());
1627 if (cix - hscroll >= width) {
1628 // text doesn't fit, cursor is to the right of br (scroll right)
1629 hscroll = cix - width;
1630 } else if (cix - hscroll < 0 && hscroll < widthUsed) {
1631 // text doesn't fit, cursor is to the left of br (scroll left)
1633 } else if (widthUsed - hscroll < width) {
1634 // text doesn't fit, text document is to the left of br; align
1636 hscroll = widthUsed - width;
1637 } else if (width - hscroll > widthUsed) {
1638 // text doesn't fit, text document is to the right of br; align
1640 hscroll = width - widthUsed;
1642 if (preeditLength > 0) {
1643 // check to ensure long pre-edit text doesn't push the cursor
1645 cix = currentLine.cursorToX(m_cursor + qMax(0, m_preeditCursor - 1));
1650 if (previousScroll != hscroll)
1651 textLayoutDirty = true;
1654 void QQuickTextInputPrivate::updateVerticalScroll()
1656 Q_Q(QQuickTextInput);
1657 const int preeditLength = m_textLayout.preeditAreaText().length();
1658 const qreal height = qMax<qreal>(0, q->height());
1659 qreal heightUsed = boundingRect.height();
1660 qreal previousScroll = vscroll;
1662 if (!autoScroll || heightUsed <= height) {
1663 // text fits in br; use vscroll for alignment
1664 switch (vAlign & ~(Qt::AlignAbsolute|Qt::AlignHorizontal_Mask)) {
1665 case Qt::AlignBottom:
1666 vscroll = heightUsed - height;
1668 case Qt::AlignVCenter:
1669 vscroll = (heightUsed - height) / 2;
1677 QTextLine currentLine = m_textLayout.lineForTextPosition(m_cursor + preeditLength);
1678 QRectF r = currentLine.isValid() ? currentLine.rect() : QRectF();
1679 qreal top = r.top();
1680 int bottom = r.bottom();
1682 if (bottom - vscroll >= height) {
1683 // text doesn't fit, cursor is to the below the br (scroll down)
1684 vscroll = bottom - height;
1685 } else if (top - vscroll < 0 && vscroll < heightUsed) {
1686 // text doesn't fit, cursor is above br (scroll up)
1688 } else if (heightUsed - vscroll < height) {
1689 // text doesn't fit, text document is to the left of br; align
1691 vscroll = heightUsed - height;
1693 if (preeditLength > 0) {
1694 // check to ensure long pre-edit text doesn't push the cursor
1696 currentLine = m_textLayout.lineForTextPosition(m_cursor + qMax(0, m_preeditCursor - 1));
1697 top = currentLine.isValid() ? currentLine.rect().top() : 0;
1702 if (previousScroll != vscroll)
1703 textLayoutDirty = true;
1706 void QQuickTextInput::triggerPreprocess()
1708 Q_D(QQuickTextInput);
1709 if (d->updateType == QQuickTextInputPrivate::UpdateNone)
1710 d->updateType = QQuickTextInputPrivate::UpdateOnlyPreprocess;
1714 QSGNode *QQuickTextInput::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data)
1717 Q_D(QQuickTextInput);
1719 if (d->updateType != QQuickTextInputPrivate::UpdatePaintNode && oldNode != 0) {
1720 // Update done in preprocess() in the nodes
1721 d->updateType = QQuickTextInputPrivate::UpdateNone;
1725 d->updateType = QQuickTextInputPrivate::UpdateNone;
1727 QQuickTextNode *node = static_cast<QQuickTextNode *>(oldNode);
1729 node = new QQuickTextNode(QQuickItemPrivate::get(this)->sceneGraphContext(), this);
1732 if (!d->textLayoutDirty) {
1733 QSGSimpleRectNode *cursorNode = node->cursorNode();
1734 if (cursorNode != 0 && !isReadOnly()) {
1735 cursorNode->setRect(cursorRectangle());
1737 if (!d->cursorVisible || (!d->m_blinkStatus && d->m_blinkPeriod > 0)) {
1744 node->deleteContent();
1745 node->setMatrix(QMatrix4x4());
1747 QPointF offset(0, 0);
1748 if (d->autoScroll && d->m_textLayout.lineCount() > 0) {
1749 QFontMetricsF fm(d->font);
1750 // the y offset is there to keep the baseline constant in case we have script changes in the text.
1751 offset = -QPoint(d->hscroll, d->vscroll + d->m_textLayout.lineAt(0).ascent() - fm.ascent());
1753 offset = -QPoint(d->hscroll, d->vscroll);
1756 if (!d->m_textLayout.text().isEmpty() || !d->m_textLayout.preeditAreaText().isEmpty()) {
1757 node->addTextLayout(offset, &d->m_textLayout, d->color,
1758 QQuickText::Normal, QColor(), QColor(),
1759 d->selectionColor, d->selectedTextColor,
1760 d->selectionStart(),
1761 d->selectionEnd() - 1); // selectionEnd() returns first char after
1765 if (!isReadOnly() && d->cursorItem == 0) {
1766 node->setCursor(cursorRectangle(), d->color);
1767 if (!d->cursorVisible || (!d->m_blinkStatus && d->m_blinkPeriod > 0)) {
1774 d->textLayoutDirty = false;
1780 QVariant QQuickTextInput::inputMethodQuery(Qt::InputMethodQuery property) const
1782 Q_D(const QQuickTextInput);
1785 return QVariant((bool)(flags() & ItemAcceptsInputMethod));
1787 return QVariant((int) d->effectiveInputMethodHints());
1788 case Qt::ImCursorRectangle:
1789 return cursorRectangle();
1792 case Qt::ImCursorPosition:
1793 return QVariant(d->m_cursor);
1794 case Qt::ImSurroundingText:
1795 if (d->m_echoMode == PasswordEchoOnEdit && !d->m_passwordEchoEditing) {
1796 return QVariant(displayText());
1798 return QVariant(d->realText());
1800 case Qt::ImCurrentSelection:
1801 return QVariant(selectedText());
1802 case Qt::ImMaximumTextLength:
1803 return QVariant(maxLength());
1804 case Qt::ImAnchorPosition:
1805 if (d->selectionStart() == d->selectionEnd())
1806 return QVariant(d->m_cursor);
1807 else if (d->selectionStart() == d->m_cursor)
1808 return QVariant(d->selectionEnd());
1810 return QVariant(d->selectionStart());
1817 \qmlmethod void QtQuick2::TextInput::deselect()
1819 Removes active text selection.
1821 void QQuickTextInput::deselect()
1823 Q_D(QQuickTextInput);
1828 \qmlmethod void QtQuick2::TextInput::selectAll()
1830 Causes all text to be selected.
1832 void QQuickTextInput::selectAll()
1834 Q_D(QQuickTextInput);
1835 d->setSelection(0, text().length());
1839 \qmlmethod void QtQuick2::TextInput::isRightToLeft(int start, int end)
1841 Returns true if the natural reading direction of the editor text
1842 found between positions \a start and \a end is right to left.
1844 bool QQuickTextInput::isRightToLeft(int start, int end)
1847 qmlInfo(this) << "isRightToLeft(start, end) called with the end property being smaller than the start.";
1850 return text().mid(start, end - start).isRightToLeft();
1854 #ifndef QT_NO_CLIPBOARD
1856 \qmlmethod QtQuick2::TextInput::cut()
1858 Moves the currently selected text to the system clipboard.
1860 void QQuickTextInput::cut()
1862 Q_D(QQuickTextInput);
1868 \qmlmethod QtQuick2::TextInput::copy()
1870 Copies the currently selected text to the system clipboard.
1872 void QQuickTextInput::copy()
1874 Q_D(QQuickTextInput);
1879 \qmlmethod QtQuick2::TextInput::paste()
1881 Replaces the currently selected text by the contents of the system clipboard.
1883 void QQuickTextInput::paste()
1885 Q_D(QQuickTextInput);
1889 #endif // QT_NO_CLIPBOARD
1892 Undoes the last operation if undo is \l {canUndo}{available}. Deselects any
1893 current selection, and updates the selection start to the current cursor
1897 void QQuickTextInput::undo()
1899 Q_D(QQuickTextInput);
1900 if (!d->m_readOnly) {
1902 d->finishChange(-1, true);
1907 Redoes the last operation if redo is \l {canRedo}{available}.
1910 void QQuickTextInput::redo()
1912 Q_D(QQuickTextInput);
1913 if (!d->m_readOnly) {
1920 \qmlmethod void QtQuick2::TextInput::insert(int position, string text)
1922 Inserts \a text into the TextInput at position.
1925 void QQuickTextInput::insert(int position, const QString &text)
1927 Q_D(QQuickTextInput);
1928 if (d->m_echoMode == QQuickTextInput::Password) {
1929 int delay = qGuiApp->styleHints()->passwordMaskDelay();
1931 d->m_passwordEchoTimer.start(delay, this);
1933 if (position < 0 || position > d->m_text.length())
1936 const int priorState = d->m_undoState;
1938 QString insertText = text;
1940 if (d->hasSelectedText()) {
1941 d->addCommand(QQuickTextInputPrivate::Command(
1942 QQuickTextInputPrivate::SetSelection, d->m_cursor, 0, d->m_selstart, d->m_selend));
1944 if (d->m_maskData) {
1945 insertText = d->maskString(position, insertText);
1946 for (int i = 0; i < insertText.length(); ++i) {
1947 d->addCommand(QQuickTextInputPrivate::Command(
1948 QQuickTextInputPrivate::DeleteSelection, position + i, d->m_text.at(position + i), -1, -1));
1949 d->addCommand(QQuickTextInputPrivate::Command(
1950 QQuickTextInputPrivate::Insert, position + i, insertText.at(i), -1, -1));
1952 d->m_text.replace(position, insertText.length(), insertText);
1953 if (!insertText.isEmpty())
1954 d->m_textDirty = true;
1955 if (position < d->m_selend && position + insertText.length() > d->m_selstart)
1956 d->m_selDirty = true;
1958 int remaining = d->m_maxLength - d->m_text.length();
1959 if (remaining != 0) {
1960 insertText = insertText.left(remaining);
1961 d->m_text.insert(position, insertText);
1962 for (int i = 0; i < insertText.length(); ++i)
1963 d->addCommand(QQuickTextInputPrivate::Command(
1964 QQuickTextInputPrivate::Insert, position + i, insertText.at(i), -1, -1));
1965 if (d->m_cursor >= position)
1966 d->m_cursor += insertText.length();
1967 if (d->m_selstart >= position)
1968 d->m_selstart += insertText.length();
1969 if (d->m_selend >= position)
1970 d->m_selend += insertText.length();
1971 d->m_textDirty = true;
1972 if (position >= d->m_selstart && position <= d->m_selend)
1973 d->m_selDirty = true;
1977 d->addCommand(QQuickTextInputPrivate::Command(
1978 QQuickTextInputPrivate::SetSelection, d->m_cursor, 0, d->m_selstart, d->m_selend));
1979 d->finishChange(priorState);
1981 if (d->lastSelectionStart != d->lastSelectionEnd) {
1982 if (d->m_selstart != d->lastSelectionStart) {
1983 d->lastSelectionStart = d->m_selstart;
1984 emit selectionStartChanged();
1986 if (d->m_selend != d->lastSelectionEnd) {
1987 d->lastSelectionEnd = d->m_selend;
1988 emit selectionEndChanged();
1994 \qmlmethod string QtQuick2::TextInput::getText(int start, int end)
1996 Removes the section of text that is between the \a start and \a end positions from the TextInput.
1999 void QQuickTextInput::remove(int start, int end)
2001 Q_D(QQuickTextInput);
2003 start = qBound(0, start, d->m_text.length());
2004 end = qBound(0, end, d->m_text.length());
2008 else if (start == end)
2011 if (start < d->m_selend && end > d->m_selstart)
2012 d->m_selDirty = true;
2014 const int priorState = d->m_undoState;
2016 d->addCommand(QQuickTextInputPrivate::Command(
2017 QQuickTextInputPrivate::SetSelection, d->m_cursor, 0, d->m_selstart, d->m_selend));
2019 if (start <= d->m_cursor && d->m_cursor < end) {
2020 // cursor is within the selection. Split up the commands
2021 // to be able to restore the correct cursor position
2022 for (int i = d->m_cursor; i >= start; --i) {
2023 d->addCommand(QQuickTextInputPrivate::Command(
2024 QQuickTextInputPrivate::DeleteSelection, i, d->m_text.at(i), -1, 1));
2026 for (int i = end - 1; i > d->m_cursor; --i) {
2027 d->addCommand(QQuickTextInputPrivate::Command(
2028 QQuickTextInputPrivate::DeleteSelection, i - d->m_cursor + start - 1, d->m_text.at(i), -1, -1));
2031 for (int i = end - 1; i >= start; --i) {
2032 d->addCommand(QQuickTextInputPrivate::Command(
2033 QQuickTextInputPrivate::RemoveSelection, i, d->m_text.at(i), -1, -1));
2036 if (d->m_maskData) {
2037 d->m_text.replace(start, end - start, d->clearString(start, end - start));
2038 for (int i = 0; i < end - start; ++i) {
2039 d->addCommand(QQuickTextInputPrivate::Command(
2040 QQuickTextInputPrivate::Insert, start + i, d->m_text.at(start + i), -1, -1));
2043 d->m_text.remove(start, end - start);
2045 if (d->m_cursor > start)
2046 d->m_cursor -= qMin(d->m_cursor, end) - start;
2047 if (d->m_selstart > start)
2048 d->m_selstart -= qMin(d->m_selstart, end) - start;
2049 if (d->m_selend > end)
2050 d->m_selend -= qMin(d->m_selend, end) - start;
2052 d->addCommand(QQuickTextInputPrivate::Command(
2053 QQuickTextInputPrivate::SetSelection, d->m_cursor, 0, d->m_selstart, d->m_selend));
2055 d->m_textDirty = true;
2056 d->finishChange(priorState);
2058 if (d->lastSelectionStart != d->lastSelectionEnd) {
2059 if (d->m_selstart != d->lastSelectionStart) {
2060 d->lastSelectionStart = d->m_selstart;
2061 emit selectionStartChanged();
2063 if (d->m_selend != d->lastSelectionEnd) {
2064 d->lastSelectionEnd = d->m_selend;
2065 emit selectionEndChanged();
2072 \qmlmethod void QtQuick2::TextInput::selectWord()
2074 Causes the word closest to the current cursor position to be selected.
2076 void QQuickTextInput::selectWord()
2078 Q_D(QQuickTextInput);
2079 d->selectWordAtPos(d->m_cursor);
2083 \qmlproperty bool QtQuick2::TextInput::smooth
2085 This property holds whether the text is smoothly scaled or transformed.
2087 Smooth filtering gives better visual quality, but is slower. If
2088 the item is displayed at its natural size, this property has no visual or
2091 \note Generally scaling artifacts are only visible if the item is stationary on
2092 the screen. A common pattern when animating an item is to disable smooth
2093 filtering at the beginning of the animation and reenable it at the conclusion.
2097 \qmlproperty string QtQuick2::TextInput::passwordCharacter
2099 This is the character displayed when echoMode is set to Password or
2100 PasswordEchoOnEdit. By default it is an asterisk.
2102 If this property is set to a string with more than one character,
2103 the first character is used. If the string is empty, the value
2104 is ignored and the property is not set.
2106 QString QQuickTextInput::passwordCharacter() const
2108 Q_D(const QQuickTextInput);
2109 return QString(d->m_passwordCharacter);
2112 void QQuickTextInput::setPasswordCharacter(const QString &str)
2114 Q_D(QQuickTextInput);
2115 if (str.length() < 1)
2117 d->m_passwordCharacter = str.constData()[0];
2118 if (d->m_echoMode == Password || d->m_echoMode == PasswordEchoOnEdit)
2119 d->updateDisplayText();
2120 emit passwordCharacterChanged();
2124 \qmlproperty string QtQuick2::TextInput::displayText
2126 This is the text displayed in the TextInput.
2128 If \l echoMode is set to TextInput::Normal, this holds the
2129 same value as the TextInput::text property. Otherwise,
2130 this property holds the text visible to the user, while
2131 the \l text property holds the actual entered text.
2133 QString QQuickTextInput::displayText() const
2135 Q_D(const QQuickTextInput);
2136 return d->m_textLayout.text();
2140 \qmlproperty bool QtQuick2::TextInput::selectByMouse
2144 If true, the user can use the mouse to select text in some
2145 platform-specific way. Note that for some platforms this may
2146 not be an appropriate interaction (eg. may conflict with how
2147 the text needs to behave inside a Flickable.
2149 bool QQuickTextInput::selectByMouse() const
2151 Q_D(const QQuickTextInput);
2152 return d->selectByMouse;
2155 void QQuickTextInput::setSelectByMouse(bool on)
2157 Q_D(QQuickTextInput);
2158 if (d->selectByMouse != on) {
2159 d->selectByMouse = on;
2160 emit selectByMouseChanged(on);
2165 \qmlproperty enum QtQuick2::TextInput::mouseSelectionMode
2167 Specifies how text should be selected using a mouse.
2170 \li TextInput.SelectCharacters - The selection is updated with individual characters. (Default)
2171 \li TextInput.SelectWords - The selection is updated with whole words.
2174 This property only applies when \l selectByMouse is true.
2177 QQuickTextInput::SelectionMode QQuickTextInput::mouseSelectionMode() const
2179 Q_D(const QQuickTextInput);
2180 return d->mouseSelectionMode;
2183 void QQuickTextInput::setMouseSelectionMode(SelectionMode mode)
2185 Q_D(QQuickTextInput);
2186 if (d->mouseSelectionMode != mode) {
2187 d->mouseSelectionMode = mode;
2188 emit mouseSelectionModeChanged(mode);
2193 \qmlproperty bool QtQuick2::TextInput::persistentSelection
2195 Whether the TextInput should keep its selection when it loses active focus to another
2196 item in the scene. By default this is set to false;
2199 bool QQuickTextInput::persistentSelection() const
2201 Q_D(const QQuickTextInput);
2202 return d->persistentSelection;
2205 void QQuickTextInput::setPersistentSelection(bool on)
2207 Q_D(QQuickTextInput);
2208 if (d->persistentSelection == on)
2210 d->persistentSelection = on;
2211 emit persistentSelectionChanged();
2215 \qmlproperty bool QtQuick2::TextInput::canPaste
2217 Returns true if the TextInput is writable and the content of the clipboard is
2218 suitable for pasting into the TextInput.
2220 bool QQuickTextInput::canPaste() const
2222 Q_D(const QQuickTextInput);
2223 if (!d->canPasteValid) {
2224 if (const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData())
2225 const_cast<QQuickTextInputPrivate *>(d)->canPaste = !d->m_readOnly && mimeData->hasText();
2226 const_cast<QQuickTextInputPrivate *>(d)->canPasteValid = true;
2232 \qmlproperty bool QtQuick2::TextInput::canUndo
2234 Returns true if the TextInput is writable and there are previous operations
2238 bool QQuickTextInput::canUndo() const
2240 Q_D(const QQuickTextInput);
2245 \qmlproperty bool QtQuick2::TextInput::canRedo
2247 Returns true if the TextInput is writable and there are \l {undo}{undone}
2248 operations that can be redone.
2251 bool QQuickTextInput::canRedo() const
2253 Q_D(const QQuickTextInput);
2258 \qmlproperty real QtQuick2::TextInput::contentWidth
2260 Returns the width of the text, including the width past the width
2261 which is covered due to insufficient wrapping if \l wrapMode is set.
2264 qreal QQuickTextInput::contentWidth() const
2266 Q_D(const QQuickTextInput);
2267 return d->boundingRect.width();
2271 \qmlproperty real QtQuick2::TextInput::contentHeight
2273 Returns the height of the text, including the height past the height
2274 that is covered if the text does not fit within the set height.
2277 qreal QQuickTextInput::contentHeight() const
2279 Q_D(const QQuickTextInput);
2280 return d->boundingRect.height();
2283 void QQuickTextInput::moveCursorSelection(int position)
2285 Q_D(QQuickTextInput);
2286 d->moveCursor(position, true);
2290 \qmlmethod void QtQuick2::TextInput::moveCursorSelection(int position, SelectionMode mode = TextInput.SelectCharacters)
2292 Moves the cursor to \a position and updates the selection according to the optional \a mode
2293 parameter. (To only move the cursor, set the \l cursorPosition property.)
2295 When this method is called it additionally sets either the
2296 selectionStart or the selectionEnd (whichever was at the previous cursor position)
2297 to the specified position. This allows you to easily extend and contract the selected
2300 The selection mode specifies whether the selection is updated on a per character or a per word
2301 basis. If not specified the selection mode will default to TextInput.SelectCharacters.
2304 \li TextInput.SelectCharacters - Sets either the selectionStart or selectionEnd (whichever was at
2305 the previous cursor position) to the specified position.
2306 \li TextInput.SelectWords - Sets the selectionStart and selectionEnd to include all
2307 words between the specified position and the previous cursor position. Words partially in the
2311 For example, take this sequence of calls:
2315 moveCursorSelection(9, TextInput.SelectCharacters)
2316 moveCursorSelection(7, TextInput.SelectCharacters)
2319 This moves the cursor to position 5, extend the selection end from 5 to 9
2320 and then retract the selection end from 9 to 7, leaving the text from position 5 to 7
2321 selected (the 6th and 7th characters).
2323 The same sequence with TextInput.SelectWords will extend the selection start to a word boundary
2324 before or on position 5 and extend the selection end to a word boundary on or past position 9.
2326 void QQuickTextInput::moveCursorSelection(int pos, SelectionMode mode)
2328 Q_D(QQuickTextInput);
2330 if (mode == SelectCharacters) {
2331 d->moveCursor(pos, true);
2332 } else if (pos != d->m_cursor){
2333 const int cursor = d->m_cursor;
2335 if (!d->hasSelectedText())
2336 anchor = d->m_cursor;
2337 else if (d->selectionStart() == d->m_cursor)
2338 anchor = d->selectionEnd();
2340 anchor = d->selectionStart();
2342 if (anchor < pos || (anchor == pos && cursor < pos)) {
2343 const QString text = this->text();
2344 QTextBoundaryFinder finder(QTextBoundaryFinder::Word, text);
2345 finder.setPosition(anchor);
2347 const QTextBoundaryFinder::BoundaryReasons reasons = finder.boundaryReasons();
2348 if (anchor < text.length() && (!(reasons & QTextBoundaryFinder::StartWord)
2349 || ((reasons & QTextBoundaryFinder::EndWord) && anchor > cursor))) {
2350 finder.toPreviousBoundary();
2352 anchor = finder.position() != -1 ? finder.position() : 0;
2354 finder.setPosition(pos);
2355 if (pos > 0 && !finder.boundaryReasons())
2356 finder.toNextBoundary();
2357 const int cursor = finder.position() != -1 ? finder.position() : text.length();
2359 d->setSelection(anchor, cursor - anchor);
2360 } else if (anchor > pos || (anchor == pos && cursor > pos)) {
2361 const QString text = this->text();
2362 QTextBoundaryFinder finder(QTextBoundaryFinder::Word, text);
2363 finder.setPosition(anchor);
2365 const QTextBoundaryFinder::BoundaryReasons reasons = finder.boundaryReasons();
2366 if (anchor > 0 && (!(reasons & QTextBoundaryFinder::EndWord)
2367 || ((reasons & QTextBoundaryFinder::StartWord) && anchor < cursor))) {
2368 finder.toNextBoundary();
2371 anchor = finder.position() != -1 ? finder.position() : text.length();
2373 finder.setPosition(pos);
2374 if (pos < text.length() && !finder.boundaryReasons())
2375 finder.toPreviousBoundary();
2376 const int cursor = finder.position() != -1 ? finder.position() : 0;
2378 d->setSelection(anchor, cursor - anchor);
2384 \qmlmethod void QtQuick2::TextInput::openSoftwareInputPanel()
2386 Opens software input panels like virtual keyboards for typing, useful for
2387 customizing when you want the input keyboard to be shown and hidden in
2390 By default the opening of input panels follows the platform style. Input panels are
2391 always closed if no editor has active focus.
2393 You can disable the automatic behavior by setting the property \c activeFocusOnPress to false
2394 and use functions openSoftwareInputPanel() and closeSoftwareInputPanel() to implement
2395 the behavior you want.
2397 Only relevant on platforms, which provide virtual keyboards.
2403 text: "Hello world!"
2404 activeFocusOnPress: false
2406 anchors.fill: parent
2408 if (!textInput.activeFocus) {
2409 textInput.forceActiveFocus()
2410 textInput.openSoftwareInputPanel();
2412 textInput.focus = false;
2415 onPressAndHold: textInput.closeSoftwareInputPanel();
2420 void QQuickTextInput::openSoftwareInputPanel()
2423 qGuiApp->inputMethod()->show();
2427 \qmlmethod void QtQuick2::TextInput::closeSoftwareInputPanel()
2429 Closes a software input panel like a virtual keyboard shown on the screen, useful
2430 for customizing when you want the input keyboard to be shown and hidden in
2433 By default the opening of input panels follows the platform style. Input panels are
2434 always closed if no editor has active focus.
2436 You can disable the automatic behavior by setting the property \c activeFocusOnPress to false
2437 and use functions openSoftwareInputPanel() and closeSoftwareInputPanel() to implement
2438 the behavior you want.
2440 Only relevant on platforms, which provide virtual keyboards.
2446 text: "Hello world!"
2447 activeFocusOnPress: false
2449 anchors.fill: parent
2451 if (!textInput.activeFocus) {
2452 textInput.forceActiveFocus();
2453 textInput.openSoftwareInputPanel();
2455 textInput.focus = false;
2458 onPressAndHold: textInput.closeSoftwareInputPanel();
2463 void QQuickTextInput::closeSoftwareInputPanel()
2466 qGuiApp->inputMethod()->hide();
2469 void QQuickTextInput::focusInEvent(QFocusEvent *event)
2471 Q_D(const QQuickTextInput);
2472 if (d->focusOnPress && !d->m_readOnly)
2473 openSoftwareInputPanel();
2474 QQuickImplicitSizeItem::focusInEvent(event);
2477 void QQuickTextInput::itemChange(ItemChange change, const ItemChangeData &value)
2479 Q_D(QQuickTextInput);
2480 if (change == ItemActiveFocusHasChanged) {
2481 bool hasFocus = value.boolValue;
2482 setCursorVisible(hasFocus); // ### refactor: && d->canvas && d->canvas->hasFocus()
2483 if (!hasFocus && (d->m_passwordEchoEditing || d->m_passwordEchoTimer.isActive())) {
2484 d->updatePasswordEchoEditing(false);//QQuickTextInputPrivate sets it on key events, but doesn't deal with focus events
2488 if (!d->persistentSelection)
2490 disconnect(qApp->inputMethod(), SIGNAL(inputDirectionChanged(Qt::LayoutDirection)),
2491 this, SLOT(q_updateAlignment()));
2493 q_updateAlignment();
2494 connect(qApp->inputMethod(), SIGNAL(inputDirectionChanged(Qt::LayoutDirection)),
2495 this, SLOT(q_updateAlignment()));
2498 QQuickItem::itemChange(change, value);
2502 \qmlproperty bool QtQuick2::TextInput::inputMethodComposing
2505 This property holds whether the TextInput has partial text input from an
2508 While it is composing an input method may rely on mouse or key events from
2509 the TextInput to edit or commit the partial text. This property can be
2510 used to determine when to disable events handlers that may interfere with
2511 the correct operation of an input method.
2513 bool QQuickTextInput::isInputMethodComposing() const
2515 Q_D(const QQuickTextInput);
2516 return d->preeditAreaText().length() > 0;
2519 void QQuickTextInputPrivate::init()
2521 Q_Q(QQuickTextInput);
2522 q->setSmooth(smooth);
2523 q->setAcceptedMouseButtons(Qt::LeftButton);
2524 q->setFlag(QQuickItem::ItemAcceptsInputMethod);
2525 q->setFlag(QQuickItem::ItemHasContents);
2526 #ifndef QT_NO_CLIPBOARD
2527 q->connect(QGuiApplication::clipboard(), SIGNAL(dataChanged()),
2528 q, SLOT(q_canPasteChanged()));
2529 #endif // QT_NO_CLIPBOARD
2531 lastSelectionStart = 0;
2532 lastSelectionEnd = 0;
2533 determineHorizontalAlignment();
2535 if (!qmlDisableDistanceField()) {
2536 QTextOption option = m_textLayout.textOption();
2537 option.setUseDesignMetrics(true);
2538 m_textLayout.setTextOption(option);
2542 void QQuickTextInput::updateCursorRectangle()
2544 Q_D(QQuickTextInput);
2545 if (!isComponentComplete())
2548 d->updateHorizontalScroll();
2549 d->updateVerticalScroll();
2550 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
2552 emit cursorRectangleChanged();
2553 if (d->cursorItem) {
2554 QRectF r = cursorRectangle();
2555 d->cursorItem->setPos(r.topLeft());
2556 d->cursorItem->setHeight(r.height());
2558 updateInputMethod(Qt::ImCursorRectangle);
2561 void QQuickTextInput::selectionChanged()
2563 Q_D(QQuickTextInput);
2564 d->textLayoutDirty = true; //TODO: Only update rect in selection
2565 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
2567 emit selectedTextChanged();
2569 if (d->lastSelectionStart != d->selectionStart()) {
2570 d->lastSelectionStart = d->selectionStart();
2571 if (d->lastSelectionStart == -1)
2572 d->lastSelectionStart = d->m_cursor;
2573 emit selectionStartChanged();
2575 if (d->lastSelectionEnd != d->selectionEnd()) {
2576 d->lastSelectionEnd = d->selectionEnd();
2577 if (d->lastSelectionEnd == -1)
2578 d->lastSelectionEnd = d->m_cursor;
2579 emit selectionEndChanged();
2583 void QQuickTextInputPrivate::showCursor()
2585 if (textNode != 0 && textNode->cursorNode() != 0)
2586 textNode->cursorNode()->setColor(color);
2589 void QQuickTextInputPrivate::hideCursor()
2591 if (textNode != 0 && textNode->cursorNode() != 0)
2592 textNode->cursorNode()->setColor(QColor(0, 0, 0, 0));
2595 QRectF QQuickTextInput::boundingRect() const
2597 Q_D(const QQuickTextInput);
2599 int cursorWidth = d->cursorItem ? d->cursorItem->width() : 1;
2601 // Could include font max left/right bearings to either side of rectangle.
2602 QRectF r = QQuickImplicitSizeItem::boundingRect();
2603 r.setRight(r.right() + cursorWidth);
2607 void QQuickTextInput::q_canPasteChanged()
2609 Q_D(QQuickTextInput);
2610 bool old = d->canPaste;
2611 #ifndef QT_NO_CLIPBOARD
2612 if (const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData())
2613 d->canPaste = !d->m_readOnly && mimeData->hasText();
2615 d->canPaste = false;
2618 bool changed = d->canPaste != old || !d->canPasteValid;
2619 d->canPasteValid = true;
2621 emit canPasteChanged();
2625 void QQuickTextInput::q_updateAlignment()
2627 Q_D(QQuickTextInput);
2628 if (d->determineHorizontalAlignment()) {
2630 updateCursorRectangle();
2634 // ### these should come from QStyleHints
2635 const int textCursorWidth = 1;
2636 const bool fullWidthSelection = true;
2641 Updates the display text based of the current edit text
2642 If the text has changed will emit displayTextChanged()
2644 void QQuickTextInputPrivate::updateDisplayText(bool forceUpdate)
2646 QString orig = m_textLayout.text();
2648 if (m_echoMode == QQuickTextInput::NoEcho)
2649 str = QString::fromLatin1("");
2653 if (m_echoMode == QQuickTextInput::Password) {
2654 str.fill(m_passwordCharacter);
2655 if (m_passwordEchoTimer.isActive() && m_cursor > 0 && m_cursor <= m_text.length()) {
2656 int cursor = m_cursor - 1;
2657 QChar uc = m_text.at(cursor);
2659 if (cursor > 0 && uc.unicode() >= 0xdc00 && uc.unicode() < 0xe000) {
2660 // second half of a surrogate, check if we have the first half as well,
2661 // if yes restore both at once
2662 uc = m_text.at(cursor - 1);
2663 if (uc.unicode() >= 0xd800 && uc.unicode() < 0xdc00)
2664 str[cursor - 1] = uc;
2667 } else if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit && !m_passwordEchoEditing) {
2668 str.fill(m_passwordCharacter);
2671 // replace certain non-printable characters with spaces (to avoid
2672 // drawing boxes when using fonts that don't have glyphs for such
2674 QChar* uc = str.data();
2675 for (int i = 0; i < (int)str.length(); ++i) {
2676 if ((uc[i] < 0x20 && uc[i] != 0x09)
2677 || uc[i] == QChar::LineSeparator
2678 || uc[i] == QChar::ParagraphSeparator
2679 || uc[i] == QChar::ObjectReplacementCharacter)
2680 uc[i] = QChar(0x0020);
2683 if (str != orig || forceUpdate) {
2684 m_textLayout.setText(str);
2685 updateLayout(); // polish?
2686 emit q_func()->displayTextChanged();
2690 qreal QQuickTextInputPrivate::getImplicitWidth() const
2692 Q_Q(const QQuickTextInput);
2693 if (!requireImplicitWidth) {
2694 QQuickTextInputPrivate *d = const_cast<QQuickTextInputPrivate *>(this);
2695 d->requireImplicitWidth = true;
2697 if (q->isComponentComplete()) {
2698 // One time cost, only incurred if implicitWidth is first requested after
2699 // componentComplete.
2700 QTextLayout layout(m_text);
2702 QTextOption option = m_textLayout.textOption();
2703 option.setTextDirection(m_layoutDirection);
2704 option.setFlags(QTextOption::IncludeTrailingSpaces);
2705 option.setWrapMode(QTextOption::WrapMode(wrapMode));
2706 option.setAlignment(Qt::Alignment(q->effectiveHAlign()));
2707 layout.setTextOption(option);
2708 layout.setFont(font);
2709 layout.setPreeditArea(m_textLayout.preeditAreaPosition(), m_textLayout.preeditAreaText());
2710 layout.beginLayout();
2712 QTextLine line = layout.createLine();
2713 line.setLineWidth(INT_MAX);
2714 d->implicitWidth = qCeil(line.naturalTextWidth());
2719 return implicitWidth;
2722 void QQuickTextInputPrivate::updateLayout()
2724 Q_Q(QQuickTextInput);
2726 if (!q->isComponentComplete())
2729 const QRectF previousRect = boundingRect;
2731 QTextOption option = m_textLayout.textOption();
2732 option.setTextDirection(layoutDirection());
2733 option.setWrapMode(QTextOption::WrapMode(wrapMode));
2734 option.setAlignment(Qt::Alignment(q->effectiveHAlign()));
2735 m_textLayout.setTextOption(option);
2736 m_textLayout.setFont(font);
2738 boundingRect = QRectF();
2739 m_textLayout.beginLayout();
2740 QTextLine line = m_textLayout.createLine();
2741 if (requireImplicitWidth) {
2742 line.setLineWidth(INT_MAX);
2743 const bool wasInLayout = inLayout;
2745 q->setImplicitWidth(qCeil(line.naturalTextWidth()));
2746 inLayout = wasInLayout;
2747 if (inLayout) // probably the result of a binding loop, but by letting it
2748 return; // get this far we'll get a warning to that effect.
2750 qreal lineWidth = q->widthValid() ? q->width() : INT_MAX;
2753 line.setLineWidth(lineWidth);
2754 line.setPosition(QPointF(line.position().x(), height));
2755 boundingRect = boundingRect.united(line.naturalTextRect());
2757 height += line.height();
2758 line = m_textLayout.createLine();
2759 } while (line.isValid());
2760 m_textLayout.endLayout();
2762 option.setWrapMode(QTextOption::NoWrap);
2763 m_textLayout.setTextOption(option);
2765 textLayoutDirty = true;
2767 updateType = UpdatePaintNode;
2770 if (!requireImplicitWidth && !q->widthValid())
2771 q->setImplicitSize(qCeil(boundingRect.width()), qCeil(boundingRect.height()));
2773 q->setImplicitHeight(qCeil(boundingRect.height()));
2775 if (previousRect != boundingRect)
2776 emit q->contentSizeChanged();
2779 #ifndef QT_NO_CLIPBOARD
2783 Copies the currently selected text into the clipboard using the given
2786 \note If the echo mode is set to a mode other than Normal then copy
2787 will not work. This is to prevent using copy as a method of bypassing
2788 password features of the line control.
2790 void QQuickTextInputPrivate::copy(QClipboard::Mode mode) const
2792 QString t = selectedText();
2793 if (!t.isEmpty() && m_echoMode == QQuickTextInput::Normal) {
2794 QGuiApplication::clipboard()->setText(t, mode);
2801 Inserts the text stored in the application clipboard into the line
2806 void QQuickTextInputPrivate::paste(QClipboard::Mode clipboardMode)
2808 QString clip = QGuiApplication::clipboard()->text(clipboardMode);
2809 if (!clip.isEmpty() || hasSelectedText()) {
2810 separate(); //make it a separate undo/redo command
2816 #endif // !QT_NO_CLIPBOARD
2821 void QQuickTextInputPrivate::commitPreedit()
2826 qApp->inputMethod()->commit();
2831 m_preeditCursor = 0;
2832 m_textLayout.setPreeditArea(-1, QString());
2833 m_textLayout.clearAdditionalFormats();
2840 Handles the behavior for the backspace key or function.
2841 Removes the current selection if there is a selection, otherwise
2842 removes the character prior to the cursor position.
2846 void QQuickTextInputPrivate::backspace()
2848 int priorState = m_undoState;
2849 if (hasSelectedText()) {
2850 removeSelectedText();
2851 } else if (m_cursor) {
2854 m_cursor = prevMaskBlank(m_cursor);
2855 QChar uc = m_text.at(m_cursor);
2856 if (m_cursor > 0 && uc.unicode() >= 0xdc00 && uc.unicode() < 0xe000) {
2857 // second half of a surrogate, check if we have the first half as well,
2858 // if yes delete both at once
2859 uc = m_text.at(m_cursor - 1);
2860 if (uc.unicode() >= 0xd800 && uc.unicode() < 0xdc00) {
2861 internalDelete(true);
2865 internalDelete(true);
2867 finishChange(priorState);
2873 Handles the behavior for the delete key or function.
2874 Removes the current selection if there is a selection, otherwise
2875 removes the character after the cursor position.
2879 void QQuickTextInputPrivate::del()
2881 int priorState = m_undoState;
2882 if (hasSelectedText()) {
2883 removeSelectedText();
2885 int n = m_textLayout.nextCursorPosition(m_cursor) - m_cursor;
2889 finishChange(priorState);
2895 Inserts the given \a newText at the current cursor position.
2896 If there is any selected text it is removed prior to insertion of
2899 void QQuickTextInputPrivate::insert(const QString &newText)
2901 int priorState = m_undoState;
2902 removeSelectedText();
2903 internalInsert(newText);
2904 finishChange(priorState);
2910 Clears the line control text.
2912 void QQuickTextInputPrivate::clear()
2914 int priorState = m_undoState;
2916 m_selend = m_text.length();
2917 removeSelectedText();
2919 finishChange(priorState, /*update*/false, /*edited*/false);
2925 Sets \a length characters from the given \a start position as selected.
2926 The given \a start position must be within the current text for
2927 the line control. If \a length characters cannot be selected, then
2928 the selection will extend to the end of the current text.
2930 void QQuickTextInputPrivate::setSelection(int start, int length)
2932 Q_Q(QQuickTextInput);
2935 if (start < 0 || start > (int)m_text.length()){
2936 qWarning("QQuickTextInputPrivate::setSelection: Invalid start position");
2941 if (start == m_selstart && start + length == m_selend && m_cursor == m_selend)
2944 m_selend = qMin(start + length, (int)m_text.length());
2945 m_cursor = m_selend;
2946 } else if (length < 0){
2947 if (start == m_selend && start + length == m_selstart && m_cursor == m_selstart)
2949 m_selstart = qMax(start + length, 0);
2951 m_cursor = m_selstart;
2952 } else if (m_selstart != m_selend) {
2958 emitCursorPositionChanged();
2961 emit q->selectionChanged();
2962 emitCursorPositionChanged();
2963 q->updateInputMethod(Qt::ImCursorRectangle | Qt::ImAnchorPosition
2964 | Qt::ImCursorPosition | Qt::ImCurrentSelection);
2970 Sets the password echo editing to \a editing. If password echo editing
2971 is true, then the text of the password is displayed even if the echo
2972 mode is set to QLineEdit::PasswordEchoOnEdit. Password echoing editing
2973 does not affect other echo modes.
2975 void QQuickTextInputPrivate::updatePasswordEchoEditing(bool editing)
2977 cancelPasswordEchoTimer();
2978 m_passwordEchoEditing = editing;
2979 updateDisplayText();
2985 Fixes the current text so that it is valid given any set validators.
2987 Returns true if the text was changed. Otherwise returns false.
2989 bool QQuickTextInputPrivate::fixup() // this function assumes that validate currently returns != Acceptable
2991 #ifndef QT_NO_VALIDATOR
2993 QString textCopy = m_text;
2994 int cursorCopy = m_cursor;
2995 m_validator->fixup(textCopy);
2996 if (m_validator->validate(textCopy, cursorCopy) == QValidator::Acceptable) {
2997 if (textCopy != m_text || cursorCopy != m_cursor)
2998 internalSetText(textCopy, cursorCopy);
3009 Moves the cursor to the given position \a pos. If \a mark is true will
3010 adjust the currently selected text.
3012 void QQuickTextInputPrivate::moveCursor(int pos, bool mark)
3014 Q_Q(QQuickTextInput);
3017 if (pos != m_cursor) {
3020 pos = pos > m_cursor ? nextMaskBlank(pos) : prevMaskBlank(pos);
3024 if (m_selend > m_selstart && m_cursor == m_selstart)
3026 else if (m_selend > m_selstart && m_cursor == m_selend)
3027 anchor = m_selstart;
3030 m_selstart = qMin(anchor, pos);
3031 m_selend = qMax(anchor, pos);
3036 if (mark || m_selDirty) {
3038 emit q->selectionChanged();
3040 emitCursorPositionChanged();
3041 q->updateInputMethod();
3047 Applies the given input method event \a event to the text of the line
3050 void QQuickTextInputPrivate::processInputMethodEvent(QInputMethodEvent *event)
3052 Q_Q(QQuickTextInput);
3054 int priorState = -1;
3055 bool isGettingInput = !event->commitString().isEmpty()
3056 || event->preeditString() != preeditAreaText()
3057 || event->replacementLength() > 0;
3058 bool cursorPositionChanged = false;
3059 bool selectionChange = false;
3060 m_preeditDirty = event->preeditString() != preeditAreaText();
3062 if (isGettingInput) {
3063 // If any text is being input, remove selected text.
3064 priorState = m_undoState;
3065 if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit && !m_passwordEchoEditing) {
3066 updatePasswordEchoEditing(true);
3068 m_selend = m_text.length();
3070 removeSelectedText();
3073 int c = m_cursor; // cursor position after insertion of commit string
3074 if (event->replacementStart() <= 0)
3075 c += event->commitString().length() - qMin(-event->replacementStart(), event->replacementLength());
3077 m_cursor += event->replacementStart();
3081 // insert commit string
3082 if (event->replacementLength()) {
3083 m_selstart = m_cursor;
3084 m_selend = m_selstart + event->replacementLength();
3085 m_selend = qMin(m_selend, m_text.length());
3086 removeSelectedText();
3088 if (!event->commitString().isEmpty()) {
3089 internalInsert(event->commitString());
3090 cursorPositionChanged = true;
3093 m_cursor = qBound(0, c, m_text.length());
3095 for (int i = 0; i < event->attributes().size(); ++i) {
3096 const QInputMethodEvent::Attribute &a = event->attributes().at(i);
3097 if (a.type == QInputMethodEvent::Selection) {
3098 m_cursor = qBound(0, a.start + a.length, m_text.length());
3100 m_selstart = qMax(0, qMin(a.start, m_text.length()));
3101 m_selend = m_cursor;
3102 if (m_selend < m_selstart) {
3103 qSwap(m_selstart, m_selend);
3105 selectionChange = true;
3107 m_selstart = m_selend = 0;
3109 cursorPositionChanged = true;
3113 m_textLayout.setPreeditArea(m_cursor, event->preeditString());
3115 const int oldPreeditCursor = m_preeditCursor;
3116 m_preeditCursor = event->preeditString().length();
3117 m_hideCursor = false;
3118 QList<QTextLayout::FormatRange> formats;
3119 for (int i = 0; i < event->attributes().size(); ++i) {
3120 const QInputMethodEvent::Attribute &a = event->attributes().at(i);
3121 if (a.type == QInputMethodEvent::Cursor) {
3122 m_preeditCursor = a.start;
3123 m_hideCursor = !a.length;
3124 } else if (a.type == QInputMethodEvent::TextFormat) {
3125 QTextCharFormat f = qvariant_cast<QTextFormat>(a.value).toCharFormat();
3127 QTextLayout::FormatRange o;
3128 o.start = a.start + m_cursor;
3129 o.length = a.length;
3135 m_textLayout.setAdditionalFormats(formats);
3137 updateDisplayText(/*force*/ true);
3138 if (cursorPositionChanged) {
3139 emitCursorPositionChanged();
3140 } else if (m_preeditCursor != oldPreeditCursor) {
3141 q->updateCursorRectangle();
3145 finishChange(priorState);
3147 if (selectionChange) {
3148 emit q->selectionChanged();
3149 q->updateInputMethod(Qt::ImCursorRectangle | Qt::ImAnchorPosition
3150 | Qt::ImCursorPosition | Qt::ImCurrentSelection);
3157 Sets the selection to cover the word at the given cursor position.
3158 The word boundaries are defined by the behavior of QTextLayout::SkipWords
3161 void QQuickTextInputPrivate::selectWordAtPos(int cursor)
3163 int next = cursor + 1;
3166 int c = m_textLayout.previousCursorPosition(next, QTextLayout::SkipWords);
3167 moveCursor(c, false);
3168 // ## text layout should support end of words.
3169 int end = m_textLayout.nextCursorPosition(c, QTextLayout::SkipWords);
3170 while (end > cursor && m_text[end-1].isSpace())
3172 moveCursor(end, true);
3178 Completes a change to the line control text. If the change is not valid
3179 will undo the line control state back to the given \a validateFromState.
3181 If \a edited is true and the change is valid, will emit textEdited() in
3182 addition to textChanged(). Otherwise only emits textChanged() on a valid
3185 The \a update value is currently unused.
3187 bool QQuickTextInputPrivate::finishChange(int validateFromState, bool update, bool /*edited*/)
3189 Q_Q(QQuickTextInput);
3192 bool inputMethodAttributesChanged = m_textDirty || m_selDirty;
3193 bool alignmentChanged = false;
3197 bool wasValidInput = m_validInput;
3198 bool wasAcceptable = m_acceptableInput;
3199 m_validInput = true;
3200 m_acceptableInput = true;
3201 #ifndef QT_NO_VALIDATOR
3203 QString textCopy = m_text;
3204 int cursorCopy = m_cursor;
3205 QValidator::State state = m_validator->validate(textCopy, cursorCopy);
3206 m_validInput = state != QValidator::Invalid;
3207 m_acceptableInput = state == QValidator::Acceptable;
3209 if (m_text != textCopy) {
3210 internalSetText(textCopy, cursorCopy);
3213 m_cursor = cursorCopy;
3217 if (validateFromState >= 0 && wasValidInput && !m_validInput) {
3218 if (m_transactions.count())
3220 internalUndo(validateFromState);
3221 m_history.resize(m_undoState);
3222 m_validInput = true;
3223 m_acceptableInput = wasAcceptable;
3224 m_textDirty = false;
3228 m_textDirty = false;
3229 m_preeditDirty = false;
3230 alignmentChanged = determineHorizontalAlignment();
3231 emit q->textChanged();
3234 updateDisplayText(alignmentChanged);
3236 if (m_acceptableInput != wasAcceptable)
3237 emit q->acceptableInputChanged();
3239 if (m_preeditDirty) {
3240 m_preeditDirty = false;
3241 if (determineHorizontalAlignment()) {
3242 alignmentChanged = true;
3249 emit q->selectionChanged();
3252 inputMethodAttributesChanged |= (m_cursor == m_lastCursorPos);
3253 if (inputMethodAttributesChanged)
3254 q->updateInputMethod();
3255 emitUndoRedoChanged();
3257 if (!emitCursorPositionChanged() && alignmentChanged)
3258 q->updateCursorRectangle();
3266 An internal function for setting the text of the line control.
3268 void QQuickTextInputPrivate::internalSetText(const QString &txt, int pos, bool edited)
3270 Q_Q(QQuickTextInput);
3272 QString oldText = m_text;
3274 m_text = maskString(0, txt, true);
3275 m_text += clearString(m_text.length(), m_maxLength - m_text.length());
3277 m_text = txt.isEmpty() ? txt : txt.left(m_maxLength);
3281 m_cursor = (pos < 0 || pos > m_text.length()) ? m_text.length() : pos;
3282 m_textDirty = (oldText != m_text);
3284 bool changed = finishChange(-1, true, edited);
3285 #ifdef QT_NO_ACCESSIBILITY
3289 QAccessibleTextUpdateEvent ev(q, 0, oldText, m_text);
3290 QAccessible::updateAccessibility(&ev);
3299 Adds the given \a command to the undo history
3300 of the line control. Does not apply the command.
3302 void QQuickTextInputPrivate::addCommand(const Command &cmd)
3304 if (m_separator && m_undoState && m_history[m_undoState - 1].type != Separator) {
3305 m_history.resize(m_undoState + 2);
3306 m_history[m_undoState++] = Command(Separator, m_cursor, 0, m_selstart, m_selend);
3308 m_history.resize(m_undoState + 1);
3310 m_separator = false;
3311 m_history[m_undoState++] = cmd;
3317 Inserts the given string \a s into the line
3320 Also adds the appropriate commands into the undo history.
3321 This function does not call finishChange(), and may leave the text
3322 in an invalid state.
3324 void QQuickTextInputPrivate::internalInsert(const QString &s)
3326 Q_Q(QQuickTextInput);
3327 if (m_echoMode == QQuickTextInput::Password) {
3328 int delay = qGuiApp->styleHints()->passwordMaskDelay();
3330 m_passwordEchoTimer.start(delay, q);
3332 if (hasSelectedText())
3333 addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
3335 QString ms = maskString(m_cursor, s);
3336 for (int i = 0; i < (int) ms.length(); ++i) {
3337 addCommand (Command(DeleteSelection, m_cursor + i, m_text.at(m_cursor + i), -1, -1));
3338 addCommand(Command(Insert, m_cursor + i, ms.at(i), -1, -1));
3340 m_text.replace(m_cursor, ms.length(), ms);
3341 m_cursor += ms.length();
3342 m_cursor = nextMaskBlank(m_cursor);
3345 int remaining = m_maxLength - m_text.length();
3346 if (remaining != 0) {
3347 m_text.insert(m_cursor, s.left(remaining));
3348 for (int i = 0; i < (int) s.left(remaining).length(); ++i)
3349 addCommand(Command(Insert, m_cursor++, s.at(i), -1, -1));
3358 deletes a single character from the current text. If \a wasBackspace,
3359 the character prior to the cursor is removed. Otherwise the character
3360 after the cursor is removed.
3362 Also adds the appropriate commands into the undo history.
3363 This function does not call finishChange(), and may leave the text
3364 in an invalid state.
3366 void QQuickTextInputPrivate::internalDelete(bool wasBackspace)
3368 if (m_cursor < (int) m_text.length()) {
3369 cancelPasswordEchoTimer();
3370 if (hasSelectedText())
3371 addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
3372 addCommand(Command((CommandType)((m_maskData ? 2 : 0) + (wasBackspace ? Remove : Delete)),
3373 m_cursor, m_text.at(m_cursor), -1, -1));
3375 m_text.replace(m_cursor, 1, clearString(m_cursor, 1));
3376 addCommand(Command(Insert, m_cursor, m_text.at(m_cursor), -1, -1));
3378 m_text.remove(m_cursor, 1);
3387 removes the currently selected text from the line control.
3389 Also adds the appropriate commands into the undo history.
3390 This function does not call finishChange(), and may leave the text
3391 in an invalid state.
3393 void QQuickTextInputPrivate::removeSelectedText()
3395 if (m_selstart < m_selend && m_selend <= (int) m_text.length()) {
3396 cancelPasswordEchoTimer();
3399 addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
3400 if (m_selstart <= m_cursor && m_cursor < m_selend) {
3401 // cursor is within the selection. Split up the commands
3402 // to be able to restore the correct cursor position
3403 for (i = m_cursor; i >= m_selstart; --i)
3404 addCommand (Command(DeleteSelection, i, m_text.at(i), -1, 1));
3405 for (i = m_selend - 1; i > m_cursor; --i)
3406 addCommand (Command(DeleteSelection, i - m_cursor + m_selstart - 1, m_text.at(i), -1, -1));
3408 for (i = m_selend-1; i >= m_selstart; --i)
3409 addCommand (Command(RemoveSelection, i, m_text.at(i), -1, -1));
3412 m_text.replace(m_selstart, m_selend - m_selstart, clearString(m_selstart, m_selend - m_selstart));
3413 for (int i = 0; i < m_selend - m_selstart; ++i)
3414 addCommand(Command(Insert, m_selstart + i, m_text.at(m_selstart + i), -1, -1));
3416 m_text.remove(m_selstart, m_selend - m_selstart);
3418 if (m_cursor > m_selstart)
3419 m_cursor -= qMin(m_cursor, m_selend) - m_selstart;
3428 Parses the input mask specified by \a maskFields to generate
3429 the mask data used to handle input masks.
3431 void QQuickTextInputPrivate::parseInputMask(const QString &maskFields)
3433 int delimiter = maskFields.indexOf(QLatin1Char(';'));
3434 if (maskFields.isEmpty() || delimiter == 0) {
3436 delete [] m_maskData;
3438 m_maxLength = 32767;
3439 internalSetText(QString());
3444 if (delimiter == -1) {
3445 m_blank = QLatin1Char(' ');
3446 m_inputMask = maskFields;
3448 m_inputMask = maskFields.left(delimiter);
3449 m_blank = (delimiter + 1 < maskFields.length()) ? maskFields[delimiter + 1] : QLatin1Char(' ');
3452 // calculate m_maxLength / m_maskData length
3455 for (int i=0; i<m_inputMask.length(); i++) {
3456 c = m_inputMask.at(i);
3457 if (i > 0 && m_inputMask.at(i-1) == QLatin1Char('\\')) {
3461 if (c != QLatin1Char('\\') && c != QLatin1Char('!') &&
3462 c != QLatin1Char('<') && c != QLatin1Char('>') &&
3463 c != QLatin1Char('{') && c != QLatin1Char('}') &&
3464 c != QLatin1Char('[') && c != QLatin1Char(']'))
3468 delete [] m_maskData;
3469 m_maskData = new MaskInputData[m_maxLength];
3471 MaskInputData::Casemode m = MaskInputData::NoCaseMode;
3474 bool escape = false;
3476 for (int i = 0; i < m_inputMask.length(); i++) {
3477 c = m_inputMask.at(i);
3480 m_maskData[index].maskChar = c;
3481 m_maskData[index].separator = s;
3482 m_maskData[index].caseMode = m;
3485 } else if (c == QLatin1Char('<')) {
3486 m = MaskInputData::Lower;
3487 } else if (c == QLatin1Char('>')) {
3488 m = MaskInputData::Upper;
3489 } else if (c == QLatin1Char('!')) {
3490 m = MaskInputData::NoCaseMode;
3491 } else if (c != QLatin1Char('{') && c != QLatin1Char('}') && c != QLatin1Char('[') && c != QLatin1Char(']')) {
3492 switch (c.unicode()) {
3518 m_maskData[index].maskChar = c;
3519 m_maskData[index].separator = s;
3520 m_maskData[index].caseMode = m;
3525 internalSetText(m_text);
3532 checks if the key is valid compared to the inputMask
3534 bool QQuickTextInputPrivate::isValidInput(QChar key, QChar mask) const
3536 switch (mask.unicode()) {
3542 if (key.isLetter() || key == m_blank)
3546 if (key.isLetterOrNumber())
3550 if (key.isLetterOrNumber() || key == m_blank)
3558 if (key.isPrint() || key == m_blank)
3566 if (key.isNumber() || key == m_blank)
3570 if (key.isNumber() && key.digitValue() > 0)
3574 if ((key.isNumber() && key.digitValue() > 0) || key == m_blank)
3578 if (key.isNumber() || key == QLatin1Char('+') || key == QLatin1Char('-') || key == m_blank)
3582 if (key == QLatin1Char('0') || key == QLatin1Char('1'))
3586 if (key == QLatin1Char('0') || key == QLatin1Char('1') || key == m_blank)
3590 if (key.isNumber() || (key >= QLatin1Char('a') && key <= QLatin1Char('f')) || (key >= QLatin1Char('A') && key <= QLatin1Char('F')))
3594 if (key.isNumber() || (key >= QLatin1Char('a') && key <= QLatin1Char('f')) || (key >= QLatin1Char('A') && key <= QLatin1Char('F')) || key == m_blank)
3606 Returns true if the given text \a str is valid for any
3607 validator or input mask set for the line control.
3609 Otherwise returns false
3611 QQuickTextInputPrivate::ValidatorState QQuickTextInputPrivate::hasAcceptableInput(const QString &str) const
3613 #ifndef QT_NO_VALIDATOR
3614 QString textCopy = str;
3615 int cursorCopy = m_cursor;
3617 QValidator::State state = m_validator->validate(textCopy, cursorCopy);
3618 if (state != QValidator::Acceptable)
3619 return ValidatorState(state);
3624 return AcceptableInput;
3626 if (str.length() != m_maxLength)
3627 return InvalidInput;
3629 for (int i=0; i < m_maxLength; ++i) {
3630 if (m_maskData[i].separator) {
3631 if (str.at(i) != m_maskData[i].maskChar)
3632 return InvalidInput;
3634 if (!isValidInput(str.at(i), m_maskData[i].maskChar))
3635 return InvalidInput;
3638 return AcceptableInput;
3644 Applies the inputMask on \a str starting from position \a pos in the mask. \a clear
3645 specifies from where characters should be gotten when a separator is met in \a str - true means
3646 that blanks will be used, false that previous input is used.
3647 Calling this when no inputMask is set is undefined.
3649 QString QQuickTextInputPrivate::maskString(uint pos, const QString &str, bool clear) const
3651 if (pos >= (uint)m_maxLength)
3652 return QString::fromLatin1("");
3655 fill = clear ? clearString(0, m_maxLength) : m_text;
3658 QString s = QString::fromLatin1("");
3660 while (i < m_maxLength) {
3661 if (strIndex < str.length()) {
3662 if (m_maskData[i].separator) {
3663 s += m_maskData[i].maskChar;
3664 if (str[(int)strIndex] == m_maskData[i].maskChar)
3668 if (isValidInput(str[(int)strIndex], m_maskData[i].maskChar)) {
3669 switch (m_maskData[i].caseMode) {
3670 case MaskInputData::Upper:
3671 s += str[(int)strIndex].toUpper();
3673 case MaskInputData::Lower:
3674 s += str[(int)strIndex].toLower();
3677 s += str[(int)strIndex];
3681 // search for separator first
3682 int n = findInMask(i, true, true, str[(int)strIndex]);
3684 if (str.length() != 1 || i == 0 || (i > 0 && (!m_maskData[i-1].separator || m_maskData[i-1].maskChar != str[(int)strIndex]))) {
3685 s += fill.mid(i, n-i+1);
3686 i = n + 1; // update i to find + 1
3689 // search for valid m_blank if not
3690 n = findInMask(i, true, false, str[(int)strIndex]);
3692 s += fill.mid(i, n-i);
3693 switch (m_maskData[n].caseMode) {
3694 case MaskInputData::Upper:
3695 s += str[(int)strIndex].toUpper();
3697 case MaskInputData::Lower:
3698 s += str[(int)strIndex].toLower();
3701 s += str[(int)strIndex];
3703 i = n + 1; // updates i to find + 1
3721 Returns a "cleared" string with only separators and blank chars.
3722 Calling this when no inputMask is set is undefined.
3724 QString QQuickTextInputPrivate::clearString(uint pos, uint len) const
3726 if (pos >= (uint)m_maxLength)
3730 int end = qMin((uint)m_maxLength, pos + len);
3731 for (int i = pos; i < end; ++i)
3732 if (m_maskData[i].separator)
3733 s += m_maskData[i].maskChar;
3743 Strips blank parts of the input in a QQuickTextInputPrivate when an inputMask is set,
3744 separators are still included. Typically "127.0__.0__.1__" becomes "127.0.0.1".
3746 QString QQuickTextInputPrivate::stripString(const QString &str) const
3752 int end = qMin(m_maxLength, (int)str.length());
3753 for (int i = 0; i < end; ++i) {
3754 if (m_maskData[i].separator)
3755 s += m_maskData[i].maskChar;
3756 else if (str[i] != m_blank)
3765 searches forward/backward in m_maskData for either a separator or a m_blank
3767 int QQuickTextInputPrivate::findInMask(int pos, bool forward, bool findSeparator, QChar searchChar) const
3769 if (pos >= m_maxLength || pos < 0)
3772 int end = forward ? m_maxLength : -1;
3773 int step = forward ? 1 : -1;
3777 if (findSeparator) {
3778 if (m_maskData[i].separator && m_maskData[i].maskChar == searchChar)
3781 if (!m_maskData[i].separator) {
3782 if (searchChar.isNull())
3784 else if (isValidInput(searchChar, m_maskData[i].maskChar))
3793 void QQuickTextInputPrivate::internalUndo(int until)
3795 if (!isUndoAvailable())
3797 cancelPasswordEchoTimer();
3799 while (m_undoState && m_undoState > until) {
3800 Command& cmd = m_history[--m_undoState];
3803 m_text.remove(cmd.pos, 1);
3807 m_selstart = cmd.selStart;
3808 m_selend = cmd.selEnd;
3812 case RemoveSelection:
3813 m_text.insert(cmd.pos, cmd.uc);
3814 m_cursor = cmd.pos + 1;
3817 case DeleteSelection:
3818 m_text.insert(cmd.pos, cmd.uc);
3824 if (until < 0 && m_undoState) {
3825 Command& next = m_history[m_undoState-1];
3826 if (next.type != cmd.type && next.type < RemoveSelection
3827 && (cmd.type < RemoveSelection || next.type == Separator))
3834 void QQuickTextInputPrivate::internalRedo()
3836 if (!isRedoAvailable())
3839 while (m_undoState < (int)m_history.size()) {
3840 Command& cmd = m_history[m_undoState++];
3843 m_text.insert(cmd.pos, cmd.uc);
3844 m_cursor = cmd.pos + 1;
3847 m_selstart = cmd.selStart;
3848 m_selend = cmd.selEnd;
3853 case RemoveSelection:
3854 case DeleteSelection:
3855 m_text.remove(cmd.pos, 1);
3856 m_selstart = cmd.selStart;
3857 m_selend = cmd.selEnd;
3861 m_selstart = cmd.selStart;
3862 m_selend = cmd.selEnd;
3866 if (m_undoState < (int)m_history.size()) {
3867 Command& next = m_history[m_undoState];
3868 if (next.type != cmd.type && cmd.type < RemoveSelection && next.type != Separator
3869 && (next.type < RemoveSelection || cmd.type == Separator))
3876 void QQuickTextInputPrivate::emitUndoRedoChanged()
3878 Q_Q(QQuickTextInput);
3879 const bool previousUndo = canUndo;
3880 const bool previousRedo = canRedo;
3882 canUndo = isUndoAvailable();
3883 canRedo = isRedoAvailable();
3885 if (previousUndo != canUndo)
3886 emit q->canUndoChanged();
3887 if (previousRedo != canRedo)
3888 emit q->canRedoChanged();
3894 If the current cursor position differs from the last emitted cursor
3895 position, emits cursorPositionChanged().
3897 bool QQuickTextInputPrivate::emitCursorPositionChanged()
3899 Q_Q(QQuickTextInput);
3900 if (m_cursor != m_lastCursorPos) {
3901 m_lastCursorPos = m_cursor;
3903 q->updateCursorRectangle();
3904 emit q->cursorPositionChanged();
3906 if (!hasSelectedText()) {
3907 if (lastSelectionStart != m_cursor) {
3908 lastSelectionStart = m_cursor;
3909 emit q->selectionStartChanged();
3911 if (lastSelectionEnd != m_cursor) {
3912 lastSelectionEnd = m_cursor;
3913 emit q->selectionEndChanged();
3917 #ifndef QT_NO_ACCESSIBILITY
3918 QAccessibleTextCursorEvent ev(q, m_cursor);
3919 QAccessible::updateAccessibility(&ev);
3928 void QQuickTextInputPrivate::setCursorBlinkPeriod(int msec)
3930 Q_Q(QQuickTextInput);
3931 if (msec == m_blinkPeriod)
3934 q->killTimer(m_blinkTimer);
3937 m_blinkTimer = q->startTimer(msec / 2);
3941 if (m_blinkStatus == 1) {
3942 updateType = UpdatePaintNode;
3946 m_blinkPeriod = msec;
3949 void QQuickTextInput::timerEvent(QTimerEvent *event)
3951 Q_D(QQuickTextInput);
3952 if (event->timerId() == d->m_blinkTimer) {
3953 d->m_blinkStatus = !d->m_blinkStatus;
3954 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
3956 } else if (event->timerId() == d->m_passwordEchoTimer.timerId()) {
3957 d->m_passwordEchoTimer.stop();
3958 d->updateDisplayText();
3962 void QQuickTextInputPrivate::processKeyEvent(QKeyEvent* event)
3964 Q_Q(QQuickTextInput);
3965 bool inlineCompletionAccepted = false;
3967 if (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return) {
3968 if (hasAcceptableInput(m_text) || fixup()) {
3971 if (inlineCompletionAccepted)
3978 if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit
3979 && !m_passwordEchoEditing
3981 && !event->text().isEmpty()
3982 && !(event->modifiers() & Qt::ControlModifier)) {
3983 // Clear the edit and reset to normal echo mode while editing; the
3984 // echo mode switches back when the edit loses focus
3985 // ### resets current content. dubious code; you can
3986 // navigate with keys up, down, back, and select(?), but if you press
3987 // "left" or "right" it clears?
3988 updatePasswordEchoEditing(true);
3992 bool unknown = false;
3993 bool visual = cursorMoveStyle() == Qt::VisualMoveStyle;
3997 #ifndef QT_NO_SHORTCUT
3998 else if (event == QKeySequence::Undo) {
4001 else if (event == QKeySequence::Redo) {
4004 else if (event == QKeySequence::SelectAll) {
4007 #ifndef QT_NO_CLIPBOARD
4008 else if (event == QKeySequence::Copy) {
4011 else if (event == QKeySequence::Paste) {
4013 QClipboard::Mode mode = QClipboard::Clipboard;
4017 else if (event == QKeySequence::Cut) {
4023 else if (event == QKeySequence::DeleteEndOfLine) {
4025 setSelection(m_cursor, end());
4030 #endif //QT_NO_CLIPBOARD
4031 else if (event == QKeySequence::MoveToStartOfLine || event == QKeySequence::MoveToStartOfBlock) {
4034 else if (event == QKeySequence::MoveToEndOfLine || event == QKeySequence::MoveToEndOfBlock) {
4037 else if (event == QKeySequence::SelectStartOfLine || event == QKeySequence::SelectStartOfBlock) {
4040 else if (event == QKeySequence::SelectEndOfLine || event == QKeySequence::SelectEndOfBlock) {
4043 else if (event == QKeySequence::MoveToNextChar) {
4044 if (hasSelectedText()) {
4045 moveCursor(selectionEnd(), false);
4047 cursorForward(0, visual ? 1 : (layoutDirection() == Qt::LeftToRight ? 1 : -1));
4050 else if (event == QKeySequence::SelectNextChar) {
4051 cursorForward(1, visual ? 1 : (layoutDirection() == Qt::LeftToRight ? 1 : -1));
4053 else if (event == QKeySequence::MoveToPreviousChar) {
4054 if (hasSelectedText()) {
4055 moveCursor(selectionStart(), false);
4057 cursorForward(0, visual ? -1 : (layoutDirection() == Qt::LeftToRight ? -1 : 1));
4060 else if (event == QKeySequence::SelectPreviousChar) {
4061 cursorForward(1, visual ? -1 : (layoutDirection() == Qt::LeftToRight ? -1 : 1));
4063 else if (event == QKeySequence::MoveToNextWord) {
4064 if (m_echoMode == QQuickTextInput::Normal)
4065 layoutDirection() == Qt::LeftToRight ? cursorWordForward(0) : cursorWordBackward(0);
4067 layoutDirection() == Qt::LeftToRight ? end(0) : home(0);
4069 else if (event == QKeySequence::MoveToPreviousWord) {
4070 if (m_echoMode == QQuickTextInput::Normal)
4071 layoutDirection() == Qt::LeftToRight ? cursorWordBackward(0) : cursorWordForward(0);
4072 else if (!m_readOnly) {
4073 layoutDirection() == Qt::LeftToRight ? home(0) : end(0);
4076 else if (event == QKeySequence::SelectNextWord) {
4077 if (m_echoMode == QQuickTextInput::Normal)
4078 layoutDirection() == Qt::LeftToRight ? cursorWordForward(1) : cursorWordBackward(1);
4080 layoutDirection() == Qt::LeftToRight ? end(1) : home(1);
4082 else if (event == QKeySequence::SelectPreviousWord) {
4083 if (m_echoMode == QQuickTextInput::Normal)
4084 layoutDirection() == Qt::LeftToRight ? cursorWordBackward(1) : cursorWordForward(1);
4086 layoutDirection() == Qt::LeftToRight ? home(1) : end(1);
4088 else if (event == QKeySequence::Delete) {
4092 else if (event == QKeySequence::DeleteEndOfWord) {
4094 cursorWordForward(true);
4098 else if (event == QKeySequence::DeleteStartOfWord) {
4100 cursorWordBackward(true);
4104 #endif // QT_NO_SHORTCUT
4106 bool handled = false;
4107 if (event->modifiers() & Qt::ControlModifier) {
4108 switch (event->key()) {
4109 case Qt::Key_Backspace:
4111 cursorWordBackward(true);
4119 } else { // ### check for *no* modifier
4120 switch (event->key()) {
4121 case Qt::Key_Backspace:
4133 if (event->key() == Qt::Key_Direction_L || event->key() == Qt::Key_Direction_R) {
4134 setLayoutDirection((event->key() == Qt::Key_Direction_L) ? Qt::LeftToRight : Qt::RightToLeft);
4138 if (unknown && !m_readOnly) {
4139 QString t = event->text();
4140 if (!t.isEmpty() && t.at(0).isPrint()) {