1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the QtQml module of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #include "qquicktextinput_p.h"
43 #include "qquicktextinput_p_p.h"
44 #include "qquickcanvas.h"
46 #include <private/qqmlglobal_p.h>
48 #include <QtCore/qcoreapplication.h>
49 #include <QtQml/qqmlinfo.h>
50 #include <QtGui/qevent.h>
51 #include <QTextBoundaryFinder>
52 #include "qquicktextnode_p.h"
53 #include <QtQuick/qsgsimplerectnode.h>
55 #include <QtGui/qstylehints.h>
56 #include <QtGui/qinputmethod.h>
58 #ifndef QT_NO_ACCESSIBILITY
59 #include "qaccessible.h"
64 DEFINE_BOOL_CONFIG_OPTION(qmlDisableDistanceField, QML_DISABLE_DISTANCEFIELD)
67 \qmlclass TextInput QQuickTextInput
68 \inqmlmodule QtQuick 2
69 \ingroup qml-basic-visual-elements
70 \brief The TextInput item displays an editable line of text.
73 The TextInput element displays a single line of editable plain text.
75 TextInput is used to accept a line of text input. Input constraints
76 can be placed on a TextInput item (for example, through a \l validator or \l inputMask),
77 and setting \l echoMode to an appropriate value enables TextInput to be used for
78 a password input field.
80 On Mac OS X, the Up/Down key bindings for Home/End are explicitly disabled.
81 If you want such bindings (on any platform), you will need to construct them in QML.
83 \sa TextEdit, Text, {declarative/text/textselection}{Text Selection example}
85 QQuickTextInput::QQuickTextInput(QQuickItem* parent)
86 : QQuickImplicitSizeItem(*(new QQuickTextInputPrivate), parent)
92 QQuickTextInput::~QQuickTextInput()
96 void QQuickTextInput::componentComplete()
100 QQuickImplicitSizeItem::componentComplete();
104 updateCursorRectangle();
105 if (d->cursorComponent && d->cursorComponent->isReady())
110 \qmlproperty string QtQuick2::TextInput::text
112 The text in the TextInput.
114 QString QQuickTextInput::text() const
116 Q_D(const QQuickTextInput);
118 QString content = d->m_text;
119 QString res = d->m_maskData ? d->stripString(content) : content;
120 return (res.isNull() ? QString::fromLatin1("") : res);
123 void QQuickTextInput::setText(const QString &s)
125 Q_D(QQuickTextInput);
130 d->internalSetText(s, -1, false);
134 \qmlproperty int QtQuick2::TextInput::length
136 Returns the total number of characters in the TextInput item.
138 If the TextInput has an inputMask the length will include mask characters and may differ
139 from the length of the string returned by the \l text property.
141 This property can be faster than querying the length the \l text property as it doesn't
142 require any copying or conversion of the TextInput's internal string data.
145 int QQuickTextInput::length() const
147 Q_D(const QQuickTextInput);
148 return d->m_text.length();
152 \qmlmethod string QtQuick2::TextInput::getText(int start, int end)
154 Returns the section of text that is between the \a start and \a end positions.
156 If the TextInput has an inputMask the length will include mask characters.
159 QString QQuickTextInput::getText(int start, int end) const
161 Q_D(const QQuickTextInput);
166 return d->m_text.mid(start, end - start);
169 QString QQuickTextInputPrivate::realText() const
171 QString res = m_maskData ? stripString(m_text) : m_text;
172 return (res.isNull() ? QString::fromLatin1("") : res);
176 \qmlproperty string QtQuick2::TextInput::font.family
178 Sets the family name of the font.
180 The family name is case insensitive and may optionally include a foundry name, e.g. "Helvetica [Cronyx]".
181 If the family is available from more than one foundry and the foundry isn't specified, an arbitrary foundry is chosen.
182 If the family isn't available a family will be set using the font matching algorithm.
186 \qmlproperty bool QtQuick2::TextInput::font.bold
188 Sets whether the font weight is bold.
192 \qmlproperty enumeration QtQuick2::TextInput::font.weight
194 Sets the font's weight.
196 The weight can be one of:
199 \li Font.Normal - the default
206 TextInput { text: "Hello"; font.weight: Font.DemiBold }
211 \qmlproperty bool QtQuick2::TextInput::font.italic
213 Sets whether the font has an italic style.
217 \qmlproperty bool QtQuick2::TextInput::font.underline
219 Sets whether the text is underlined.
223 \qmlproperty bool QtQuick2::TextInput::font.strikeout
225 Sets whether the font has a strikeout style.
229 \qmlproperty real QtQuick2::TextInput::font.pointSize
231 Sets the font size in points. The point size must be greater than zero.
235 \qmlproperty int QtQuick2::TextInput::font.pixelSize
237 Sets the font size in pixels.
239 Using this function makes the font device dependent.
240 Use \c pointSize to set the size of the font in a device independent manner.
244 \qmlproperty real QtQuick2::TextInput::font.letterSpacing
246 Sets the letter spacing for the font.
248 Letter spacing changes the default spacing between individual letters in the font.
249 A positive value increases the letter spacing by the corresponding pixels; a negative value decreases the spacing.
253 \qmlproperty real QtQuick2::TextInput::font.wordSpacing
255 Sets the word spacing for the font.
257 Word spacing changes the default spacing between individual words.
258 A positive value increases the word spacing by a corresponding amount of pixels,
259 while a negative value decreases the inter-word spacing accordingly.
263 \qmlproperty enumeration QtQuick2::TextInput::font.capitalization
265 Sets the capitalization for the text.
268 \li Font.MixedCase - This is the normal text rendering option where no capitalization change is applied.
269 \li Font.AllUppercase - This alters the text to be rendered in all uppercase type.
270 \li Font.AllLowercase - This alters the text to be rendered in all lowercase type.
271 \li Font.SmallCaps - This alters the text to be rendered in small-caps type.
272 \li Font.Capitalize - This alters the text to be rendered with the first character of each word as an uppercase character.
276 TextInput { text: "Hello"; font.capitalization: Font.AllLowercase }
280 QFont QQuickTextInput::font() const
282 Q_D(const QQuickTextInput);
283 return d->sourceFont;
286 void QQuickTextInput::setFont(const QFont &font)
288 Q_D(QQuickTextInput);
289 if (d->sourceFont == font)
292 d->sourceFont = font;
293 QFont oldFont = d->font;
295 if (d->font.pointSizeF() != -1) {
297 qreal size = qRound(d->font.pointSizeF()*2.0);
298 d->font.setPointSizeF(size/2.0);
300 if (oldFont != d->font) {
302 updateCursorRectangle();
303 updateInputMethod(Qt::ImCursorRectangle | Qt::ImFont);
305 emit fontChanged(d->sourceFont);
309 \qmlproperty color QtQuick2::TextInput::color
313 QColor QQuickTextInput::color() const
315 Q_D(const QQuickTextInput);
319 void QQuickTextInput::setColor(const QColor &c)
321 Q_D(QQuickTextInput);
324 d->textLayoutDirty = true;
325 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
333 \qmlproperty color QtQuick2::TextInput::selectionColor
335 The text highlight color, used behind selections.
337 QColor QQuickTextInput::selectionColor() const
339 Q_D(const QQuickTextInput);
340 return d->selectionColor;
343 void QQuickTextInput::setSelectionColor(const QColor &color)
345 Q_D(QQuickTextInput);
346 if (d->selectionColor == color)
349 d->selectionColor = color;
350 if (d->hasSelectedText()) {
351 d->textLayoutDirty = true;
352 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
355 emit selectionColorChanged();
358 \qmlproperty color QtQuick2::TextInput::selectedTextColor
360 The highlighted text color, used in selections.
362 QColor QQuickTextInput::selectedTextColor() const
364 Q_D(const QQuickTextInput);
365 return d->selectedTextColor;
368 void QQuickTextInput::setSelectedTextColor(const QColor &color)
370 Q_D(QQuickTextInput);
371 if (d->selectedTextColor == color)
374 d->selectedTextColor = color;
375 if (d->hasSelectedText()) {
376 d->textLayoutDirty = true;
377 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
380 emit selectedTextColorChanged();
384 \qmlproperty enumeration QtQuick2::TextInput::horizontalAlignment
385 \qmlproperty enumeration QtQuick2::TextInput::effectiveHorizontalAlignment
386 \qmlproperty enumeration QtQuick2::TextInput::verticalAlignment
388 Sets the horizontal alignment of the text within the TextInput item's
389 width and height. By default, the text alignment follows the natural alignment
390 of the text, for example text that is read from left to right will be aligned to
393 TextInput does not have vertical alignment, as the natural height is
394 exactly the height of the single line of text. If you set the height
395 manually to something larger, TextInput will always be top aligned
396 vertically. You can use anchors to align it however you want within
399 The valid values for \c horizontalAlignment are \c TextInput.AlignLeft, \c TextInput.AlignRight and
400 \c TextInput.AlignHCenter.
402 Valid values for \c verticalAlignment are \c TextInput.AlignTop (default),
403 \c TextInput.AlignBottom \c TextInput.AlignVCenter.
405 When using the attached property LayoutMirroring::enabled to mirror application
406 layouts, the horizontal alignment of text will also be mirrored. However, the property
407 \c horizontalAlignment will remain unchanged. To query the effective horizontal alignment
408 of TextInput, use the read-only property \c effectiveHorizontalAlignment.
410 QQuickTextInput::HAlignment QQuickTextInput::hAlign() const
412 Q_D(const QQuickTextInput);
416 void QQuickTextInput::setHAlign(HAlignment align)
418 Q_D(QQuickTextInput);
419 bool forceAlign = d->hAlignImplicit && d->effectiveLayoutMirror;
420 d->hAlignImplicit = false;
421 if (d->setHAlign(align, forceAlign) && isComponentComplete()) {
423 updateCursorRectangle();
427 void QQuickTextInput::resetHAlign()
429 Q_D(QQuickTextInput);
430 d->hAlignImplicit = true;
431 if (d->determineHorizontalAlignment() && isComponentComplete()) {
433 updateCursorRectangle();
437 QQuickTextInput::HAlignment QQuickTextInput::effectiveHAlign() const
439 Q_D(const QQuickTextInput);
440 QQuickTextInput::HAlignment effectiveAlignment = d->hAlign;
441 if (!d->hAlignImplicit && d->effectiveLayoutMirror) {
443 case QQuickTextInput::AlignLeft:
444 effectiveAlignment = QQuickTextInput::AlignRight;
446 case QQuickTextInput::AlignRight:
447 effectiveAlignment = QQuickTextInput::AlignLeft;
453 return effectiveAlignment;
456 bool QQuickTextInputPrivate::setHAlign(QQuickTextInput::HAlignment alignment, bool forceAlign)
458 Q_Q(QQuickTextInput);
459 if ((hAlign != alignment || forceAlign) && alignment <= QQuickTextInput::AlignHCenter) { // justify not supported
460 QQuickTextInput::HAlignment oldEffectiveHAlign = q->effectiveHAlign();
462 emit q->horizontalAlignmentChanged(alignment);
463 if (oldEffectiveHAlign != q->effectiveHAlign())
464 emit q->effectiveHorizontalAlignmentChanged();
470 bool QQuickTextInputPrivate::determineHorizontalAlignment()
472 if (hAlignImplicit) {
473 // if no explicit alignment has been set, follow the natural layout direction of the text
474 QString text = q_func()->text();
476 text = m_textLayout.preeditAreaText();
477 bool isRightToLeft = text.isEmpty() ? qApp->inputMethod()->inputDirection() == Qt::RightToLeft
478 : text.isRightToLeft();
479 return setHAlign(isRightToLeft ? QQuickTextInput::AlignRight : QQuickTextInput::AlignLeft);
484 QQuickTextInput::VAlignment QQuickTextInput::vAlign() const
486 Q_D(const QQuickTextInput);
490 void QQuickTextInput::setVAlign(QQuickTextInput::VAlignment alignment)
492 Q_D(QQuickTextInput);
493 if (alignment == d->vAlign)
495 d->vAlign = alignment;
496 emit verticalAlignmentChanged(d->vAlign);
497 if (isComponentComplete()) {
498 updateCursorRectangle();
503 \qmlproperty enumeration QtQuick2::TextInput::wrapMode
505 Set this property to wrap the text to the TextInput item's width.
506 The text will only wrap if an explicit width has been set.
509 \li TextInput.NoWrap - no wrapping will be performed. If the text contains insufficient newlines, then implicitWidth will exceed a set width.
510 \li TextInput.WordWrap - wrapping is done on word boundaries only. If a word is too long, implicitWidth will exceed a set width.
511 \li TextInput.WrapAnywhere - wrapping is done at any point on a line, even if it occurs in the middle of a word.
512 \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.
515 The default is TextInput.NoWrap. If you set a width, consider using TextInput.Wrap.
517 QQuickTextInput::WrapMode QQuickTextInput::wrapMode() const
519 Q_D(const QQuickTextInput);
523 void QQuickTextInput::setWrapMode(WrapMode mode)
525 Q_D(QQuickTextInput);
526 if (mode == d->wrapMode)
530 updateCursorRectangle();
531 emit wrapModeChanged();
534 void QQuickTextInputPrivate::mirrorChange()
536 Q_Q(QQuickTextInput);
537 if (q->isComponentComplete()) {
538 if (!hAlignImplicit && (hAlign == QQuickTextInput::AlignRight || hAlign == QQuickTextInput::AlignLeft)) {
539 q->updateCursorRectangle();
540 emit q->effectiveHorizontalAlignmentChanged();
546 \qmlproperty bool QtQuick2::TextInput::readOnly
548 Sets whether user input can modify the contents of the TextInput.
550 If readOnly is set to true, then user input will not affect the text
551 property. Any bindings or attempts to set the text property will still
554 bool QQuickTextInput::isReadOnly() const
556 Q_D(const QQuickTextInput);
557 return d->m_readOnly;
560 void QQuickTextInput::setReadOnly(bool ro)
562 Q_D(QQuickTextInput);
563 if (d->m_readOnly == ro)
566 setFlag(QQuickItem::ItemAcceptsInputMethod, !ro);
569 d->setCursorPosition(d->end());
570 updateInputMethod(Qt::ImEnabled);
572 d->emitUndoRedoChanged();
573 emit readOnlyChanged(ro);
577 \qmlproperty int QtQuick2::TextInput::maximumLength
578 The maximum permitted length of the text in the TextInput.
580 If the text is too long, it is truncated at the limit.
582 By default, this property contains a value of 32767.
584 int QQuickTextInput::maxLength() const
586 Q_D(const QQuickTextInput);
587 return d->m_maxLength;
590 void QQuickTextInput::setMaxLength(int ml)
592 Q_D(QQuickTextInput);
593 if (d->m_maxLength == ml || d->m_maskData)
597 d->internalSetText(d->m_text, -1, false);
599 emit maximumLengthChanged(ml);
603 \qmlproperty bool QtQuick2::TextInput::cursorVisible
604 Set to true when the TextInput shows a cursor.
606 This property is set and unset when the TextInput gets active focus, so that other
607 properties can be bound to whether the cursor is currently showing. As it
608 gets set and unset automatically, when you set the value yourself you must
609 keep in mind that your value may be overwritten.
611 It can be set directly in script, for example if a KeyProxy might
612 forward keys to it and you desire it to look active when this happens
613 (but without actually giving it active focus).
615 It should not be set directly on the element, like in the below QML,
616 as the specified value will be overridden an lost on focus changes.
625 In the above snippet the cursor will still become visible when the
626 TextInput gains active focus.
628 bool QQuickTextInput::isCursorVisible() const
630 Q_D(const QQuickTextInput);
631 return d->cursorVisible;
634 void QQuickTextInput::setCursorVisible(bool on)
636 Q_D(QQuickTextInput);
637 if (d->cursorVisible == on)
639 d->cursorVisible = on;
640 d->setCursorBlinkPeriod(on ? qApp->styleHints()->cursorFlashTime() : 0);
641 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
643 emit cursorVisibleChanged(d->cursorVisible);
647 \qmlproperty int QtQuick2::TextInput::cursorPosition
648 The position of the cursor in the TextInput.
650 int QQuickTextInput::cursorPosition() const
652 Q_D(const QQuickTextInput);
656 void QQuickTextInput::setCursorPosition(int cp)
658 Q_D(QQuickTextInput);
659 if (cp < 0 || cp > text().length())
665 \qmlproperty rectangle QtQuick2::TextInput::cursorRectangle
667 The rectangle where the standard text cursor is rendered within the text input. Read only.
669 The position and height of a custom cursorDelegate are updated to follow the cursorRectangle
670 automatically when it changes. The width of the delegate is unaffected by changes in the
674 QRectF QQuickTextInput::cursorRectangle() const
676 Q_D(const QQuickTextInput);
678 int c = d->m_cursor + d->m_preeditCursor;
679 if (d->m_echoMode == NoEcho)
681 QTextLine l = d->m_textLayout.lineForTextPosition(c);
684 return QRectF(l.cursorToX(c) - d->hscroll, l.y() - d->vscroll, 1, l.height());
688 \qmlproperty int QtQuick2::TextInput::selectionStart
690 The cursor position before the first character in the current selection.
692 This property is read-only. To change the selection, use select(start,end),
693 selectAll(), or selectWord().
695 \sa selectionEnd, cursorPosition, selectedText
697 int QQuickTextInput::selectionStart() const
699 Q_D(const QQuickTextInput);
700 return d->lastSelectionStart;
703 \qmlproperty int QtQuick2::TextInput::selectionEnd
705 The cursor position after the last character in the current selection.
707 This property is read-only. To change the selection, use select(start,end),
708 selectAll(), or selectWord().
710 \sa selectionStart, cursorPosition, selectedText
712 int QQuickTextInput::selectionEnd() const
714 Q_D(const QQuickTextInput);
715 return d->lastSelectionEnd;
718 \qmlmethod void QtQuick2::TextInput::select(int start, int end)
720 Causes the text from \a start to \a end to be selected.
722 If either start or end is out of range, the selection is not changed.
724 After calling this, selectionStart will become the lesser
725 and selectionEnd will become the greater (regardless of the order passed
728 \sa selectionStart, selectionEnd
730 void QQuickTextInput::select(int start, int end)
732 Q_D(QQuickTextInput);
733 if (start < 0 || end < 0 || start > d->m_text.length() || end > d->m_text.length())
735 d->setSelection(start, end-start);
739 \qmlproperty string QtQuick2::TextInput::selectedText
741 This read-only property provides the text currently selected in the
744 It is equivalent to the following snippet, but is faster and easier
748 myTextInput.text.toString().substring(myTextInput.selectionStart,
749 myTextInput.selectionEnd);
752 QString QQuickTextInput::selectedText() const
754 Q_D(const QQuickTextInput);
755 return d->selectedText();
759 \qmlproperty bool QtQuick2::TextInput::activeFocusOnPress
761 Whether the TextInput should gain active focus on a mouse press. By default this is
764 bool QQuickTextInput::focusOnPress() const
766 Q_D(const QQuickTextInput);
767 return d->focusOnPress;
770 void QQuickTextInput::setFocusOnPress(bool b)
772 Q_D(QQuickTextInput);
773 if (d->focusOnPress == b)
778 emit activeFocusOnPressChanged(d->focusOnPress);
781 \qmlproperty bool QtQuick2::TextInput::autoScroll
783 Whether the TextInput should scroll when the text is longer than the width. By default this is
786 bool QQuickTextInput::autoScroll() const
788 Q_D(const QQuickTextInput);
789 return d->autoScroll;
792 void QQuickTextInput::setAutoScroll(bool b)
794 Q_D(QQuickTextInput);
795 if (d->autoScroll == b)
799 //We need to repaint so that the scrolling is taking into account.
800 updateCursorRectangle();
801 emit autoScrollChanged(d->autoScroll);
804 #ifndef QT_NO_VALIDATOR
807 \qmlclass IntValidator QIntValidator
808 \inqmlmodule QtQuick 2
809 \ingroup qml-basic-visual-elements
811 This element provides a validator for integer values.
813 If no \l locale is set IntValidator uses the \l {QLocale::setDefault()}{default locale} to
814 interpret the number and will accept locale specific digits, group separators, and positive
815 and negative signs. In addition, IntValidator is always guaranteed to accept a number
816 formatted according to the "C" locale.
820 QQuickIntValidator::QQuickIntValidator(QObject *parent)
821 : QIntValidator(parent)
826 \qmlproperty string QtQuick2::IntValidator::locale
828 This property holds the name of the locale used to interpret the number.
833 QString QQuickIntValidator::localeName() const
835 return locale().name();
838 void QQuickIntValidator::setLocaleName(const QString &name)
840 if (locale().name() != name) {
841 setLocale(QLocale(name));
842 emit localeNameChanged();
846 void QQuickIntValidator::resetLocaleName()
848 QLocale defaultLocale;
849 if (locale() != defaultLocale) {
850 setLocale(defaultLocale);
851 emit localeNameChanged();
856 \qmlproperty int QtQuick2::IntValidator::top
858 This property holds the validator's highest acceptable value.
859 By default, this property's value is derived from the highest signed integer available (typically 2147483647).
862 \qmlproperty int QtQuick2::IntValidator::bottom
864 This property holds the validator's lowest acceptable value.
865 By default, this property's value is derived from the lowest signed integer available (typically -2147483647).
869 \qmlclass DoubleValidator QDoubleValidator
870 \inqmlmodule QtQuick 2
871 \ingroup qml-basic-visual-elements
873 This element provides a validator for non-integer numbers.
875 Input is accepted if it contains a double that is within the valid range
876 and is in the correct format.
878 Input is accepected but invalid if it contains a double that is outside
879 the range or is in the wrong format; e.g. with too many digits after the
880 decimal point or is empty.
882 Input is rejected if it is not a double.
884 Note: If the valid range consists of just positive doubles (e.g. 0.0 to
885 100.0) and input is a negative double then it is rejected. If \l notation
886 is set to DoubleValidator.StandardNotation, and the input contains more
887 digits before the decimal point than a double in the valid range may have,
888 it is also rejected. If \l notation is DoubleValidator.ScientificNotation,
889 and the input is not in the valid range, it is accecpted but invalid. The
890 value may yet become valid by changing the exponent.
893 QQuickDoubleValidator::QQuickDoubleValidator(QObject *parent)
894 : QDoubleValidator(parent)
899 \qmlproperty string QtQuick2::DoubleValidator::locale
901 This property holds the name of the locale used to interpret the number.
906 QString QQuickDoubleValidator::localeName() const
908 return locale().name();
911 void QQuickDoubleValidator::setLocaleName(const QString &name)
913 if (locale().name() != name) {
914 setLocale(QLocale(name));
915 emit localeNameChanged();
919 void QQuickDoubleValidator::resetLocaleName()
921 QLocale defaultLocale;
922 if (locale() != defaultLocale) {
923 setLocale(defaultLocale);
924 emit localeNameChanged();
929 \qmlproperty real QtQuick2::DoubleValidator::top
931 This property holds the validator's maximum acceptable value.
932 By default, this property contains a value of infinity.
935 \qmlproperty real QtQuick2::DoubleValidator::bottom
937 This property holds the validator's minimum acceptable value.
938 By default, this property contains a value of -infinity.
941 \qmlproperty int QtQuick2::DoubleValidator::decimals
943 This property holds the validator's maximum number of digits after the decimal point.
944 By default, this property contains a value of 1000.
947 \qmlproperty enumeration QtQuick2::DoubleValidator::notation
948 This property holds the notation of how a string can describe a number.
950 The possible values for this property are:
953 \li DoubleValidator.StandardNotation
954 \li DoubleValidator.ScientificNotation (default)
957 If this property is set to DoubleValidator.ScientificNotation, the written number may have an exponent part (e.g. 1.5E-2).
961 \qmlclass RegExpValidator QRegExpValidator
962 \inqmlmodule QtQuick 2
963 \ingroup qml-basic-visual-elements
965 This element provides a validator, which counts as valid any string which
966 matches a specified regular expression.
969 \qmlproperty regExp QtQuick2::RegExpValidator::regExp
971 This property holds the regular expression used for validation.
973 Note that this property should be a regular expression in JS syntax, e.g /a/ for the regular expression
976 By default, this property contains a regular expression with the pattern .* that matches any string.
980 \qmlproperty Validator QtQuick2::TextInput::validator
982 Allows you to set a validator on the TextInput. When a validator is set
983 the TextInput will only accept input which leaves the text property in
984 an acceptable or intermediate state. The accepted signal will only be sent
985 if the text is in an acceptable state when enter is pressed.
987 Currently supported validators are IntValidator, DoubleValidator and
988 RegExpValidator. An example of using validators is shown below, which allows
989 input of integers between 11 and 31 into the text input:
994 validator: IntValidator{bottom: 11; top: 31;}
999 \sa acceptableInput, inputMask
1002 QValidator* QQuickTextInput::validator() const
1004 Q_D(const QQuickTextInput);
1005 return d->m_validator;
1008 void QQuickTextInput::setValidator(QValidator* v)
1010 Q_D(QQuickTextInput);
1011 if (d->m_validator == v)
1016 if (isComponentComplete())
1019 emit validatorChanged();
1022 #endif // QT_NO_VALIDATOR
1024 void QQuickTextInputPrivate::checkIsValid()
1026 Q_Q(QQuickTextInput);
1028 ValidatorState state = hasAcceptableInput(m_text);
1029 m_validInput = state != InvalidInput;
1030 if (state != AcceptableInput) {
1031 if (m_acceptableInput) {
1032 m_acceptableInput = false;
1033 emit q->acceptableInputChanged();
1035 } else if (!m_acceptableInput) {
1036 m_acceptableInput = true;
1037 emit q->acceptableInputChanged();
1042 \qmlproperty string QtQuick2::TextInput::inputMask
1044 Allows you to set an input mask on the TextInput, restricting the allowable
1045 text inputs. See QLineEdit::inputMask for further details, as the exact
1046 same mask strings are used by TextInput.
1048 \sa acceptableInput, validator
1050 QString QQuickTextInput::inputMask() const
1052 Q_D(const QQuickTextInput);
1053 return d->inputMask();
1056 void QQuickTextInput::setInputMask(const QString &im)
1058 Q_D(QQuickTextInput);
1059 if (d->inputMask() == im)
1062 d->setInputMask(im);
1063 emit inputMaskChanged(d->inputMask());
1067 \qmlproperty bool QtQuick2::TextInput::acceptableInput
1069 This property is always true unless a validator or input mask has been set.
1070 If a validator or input mask has been set, this property will only be true
1071 if the current text is acceptable to the validator or input mask as a final
1072 string (not as an intermediate string).
1074 bool QQuickTextInput::hasAcceptableInput() const
1076 Q_D(const QQuickTextInput);
1077 return d->hasAcceptableInput(d->m_text) == QQuickTextInputPrivate::AcceptableInput;
1081 \qmlsignal QtQuick2::TextInput::onAccepted()
1083 This handler is called when the Return or Enter key is pressed.
1084 Note that if there is a \l validator or \l inputMask set on the text
1085 input, the handler will only be emitted if the input is in an acceptable
1089 Qt::InputMethodHints QQuickTextInputPrivate::effectiveInputMethodHints() const
1091 Qt::InputMethodHints hints = inputMethodHints;
1092 if (m_echoMode == QQuickTextInput::Password || m_echoMode == QQuickTextInput::NoEcho)
1093 hints |= Qt::ImhHiddenText;
1094 else if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit)
1095 hints &= ~Qt::ImhHiddenText;
1096 if (m_echoMode != QQuickTextInput::Normal)
1097 hints |= (Qt::ImhNoAutoUppercase | Qt::ImhNoPredictiveText | Qt::ImhSensitiveData);
1101 \qmlproperty enumeration QtQuick2::TextInput::echoMode
1103 Specifies how the text should be displayed in the TextInput.
1105 \li TextInput.Normal - Displays the text as it is. (Default)
1106 \li TextInput.Password - Displays asterisks instead of characters.
1107 \li TextInput.NoEcho - Displays nothing.
1108 \li TextInput.PasswordEchoOnEdit - Displays characters as they are entered
1109 while editing, otherwise displays asterisks.
1112 QQuickTextInput::EchoMode QQuickTextInput::echoMode() const
1114 Q_D(const QQuickTextInput);
1115 return QQuickTextInput::EchoMode(d->m_echoMode);
1118 void QQuickTextInput::setEchoMode(QQuickTextInput::EchoMode echo)
1120 Q_D(QQuickTextInput);
1121 if (echoMode() == echo)
1123 d->cancelPasswordEchoTimer();
1124 d->m_echoMode = echo;
1125 d->m_passwordEchoEditing = false;
1126 updateInputMethod(Qt::ImHints);
1127 d->updateDisplayText();
1128 updateCursorRectangle();
1130 emit echoModeChanged(echoMode());
1134 \qmlproperty enumeration QtQuick2::TextInput::inputMethodHints
1136 Provides hints to the input method about the expected content of the text input and how it
1139 The value is a bit-wise combination of flags, or Qt.ImhNone if no hints are set.
1141 Flags that alter behaviour are:
1144 \li Qt.ImhHiddenText - Characters should be hidden, as is typically used when entering passwords.
1145 This is automatically set when setting echoMode to \c TextInput.Password.
1146 \li Qt.ImhSensitiveData - Typed text should not be stored by the active input method
1147 in any persistent storage like predictive user dictionary.
1148 \li Qt.ImhNoAutoUppercase - The input method should not try to automatically switch to upper case
1149 when a sentence ends.
1150 \li Qt.ImhPreferNumbers - Numbers are preferred (but not required).
1151 \li Qt.ImhPreferUppercase - Upper case letters are preferred (but not required).
1152 \li Qt.ImhPreferLowercase - Lower case letters are preferred (but not required).
1153 \li Qt.ImhNoPredictiveText - Do not use predictive text (i.e. dictionary lookup) while typing.
1155 \li Qt.ImhDate - The text editor functions as a date field.
1156 \li Qt.ImhTime - The text editor functions as a time field.
1159 Flags that restrict input (exclusive flags) are:
1162 \li Qt.ImhDigitsOnly - Only digits are allowed.
1163 \li Qt.ImhFormattedNumbersOnly - Only number input is allowed. This includes decimal point and minus sign.
1164 \li Qt.ImhUppercaseOnly - Only upper case letter input is allowed.
1165 \li Qt.ImhLowercaseOnly - Only lower case letter input is allowed.
1166 \li Qt.ImhDialableCharactersOnly - Only characters suitable for phone dialing are allowed.
1167 \li Qt.ImhEmailCharactersOnly - Only characters suitable for email addresses are allowed.
1168 \li Qt.ImhUrlCharactersOnly - Only characters suitable for URLs are allowed.
1174 \li Qt.ImhExclusiveInputMask - This mask yields nonzero if any of the exclusive flags are used.
1178 Qt::InputMethodHints QQuickTextInput::inputMethodHints() const
1180 Q_D(const QQuickTextInput);
1181 return d->inputMethodHints;
1184 void QQuickTextInput::setInputMethodHints(Qt::InputMethodHints hints)
1186 Q_D(QQuickTextInput);
1188 if (hints == d->inputMethodHints)
1191 d->inputMethodHints = hints;
1192 updateInputMethod(Qt::ImHints);
1193 emit inputMethodHintsChanged();
1197 \qmlproperty Component QtQuick2::TextInput::cursorDelegate
1198 The delegate for the cursor in the TextInput.
1200 If you set a cursorDelegate for a TextInput, this delegate will be used for
1201 drawing the cursor instead of the standard cursor. An instance of the
1202 delegate will be created and managed by the TextInput when a cursor is
1203 needed, and the x property of delegate instance will be set so as
1204 to be one pixel before the top left of the current character.
1206 Note that the root item of the delegate component must be a QQuickItem or
1207 QQuickItem derived item.
1209 QQmlComponent* QQuickTextInput::cursorDelegate() const
1211 Q_D(const QQuickTextInput);
1212 return d->cursorComponent;
1215 void QQuickTextInput::setCursorDelegate(QQmlComponent* c)
1217 Q_D(QQuickTextInput);
1218 if (d->cursorComponent == c)
1221 d->cursorComponent = c;
1223 //note that the components are owned by something else
1224 delete d->cursorItem;
1227 d->startCreatingCursor();
1230 emit cursorDelegateChanged();
1233 void QQuickTextInputPrivate::startCreatingCursor()
1235 Q_Q(QQuickTextInput);
1236 if (cursorComponent->isReady()) {
1238 } else if (cursorComponent->isLoading()) {
1239 q->connect(cursorComponent, SIGNAL(statusChanged(int)),
1240 q, SLOT(createCursor()));
1242 qmlInfo(q, cursorComponent->errors()) << QQuickTextInput::tr("Could not load cursor delegate");
1246 void QQuickTextInput::createCursor()
1248 Q_D(QQuickTextInput);
1249 if (!isComponentComplete())
1252 if (d->cursorComponent->isError()) {
1253 qmlInfo(this, d->cursorComponent->errors()) << tr("Could not load cursor delegate");
1257 if (!d->cursorComponent->isReady())
1261 delete d->cursorItem;
1262 QQmlContext *creationContext = d->cursorComponent->creationContext();
1263 QObject *object = d->cursorComponent->create(creationContext ? creationContext : qmlContext(this));
1264 d->cursorItem = qobject_cast<QQuickItem*>(object);
1265 if (!d->cursorItem) {
1267 qmlInfo(this, d->cursorComponent->errors()) << tr("Could not instantiate cursor delegate");
1271 QRectF r = cursorRectangle();
1273 QQml_setParent_noEvent(d->cursorItem, this);
1274 d->cursorItem->setParentItem(this);
1275 d->cursorItem->setPos(r.topLeft());
1276 d->cursorItem->setHeight(r.height());
1280 \qmlmethod rect QtQuick2::TextInput::positionToRectangle(int pos)
1282 This function takes a character position and returns the rectangle that the
1283 cursor would occupy, if it was placed at that character position.
1285 This is similar to setting the cursorPosition, and then querying the cursor
1286 rectangle, but the cursorPosition is not changed.
1288 QRectF QQuickTextInput::positionToRectangle(int pos) const
1290 Q_D(const QQuickTextInput);
1291 if (d->m_echoMode == NoEcho)
1293 else if (pos > d->m_cursor)
1294 pos += d->preeditAreaText().length();
1295 QTextLine l = d->m_textLayout.lineForTextPosition(pos);
1297 ? QRectF(l.cursorToX(pos) - d->hscroll, l.y() - d->vscroll, 1, l.height())
1302 \qmlmethod int QtQuick2::TextInput::positionAt(real x, real y, CursorPosition position = CursorBetweenCharacters)
1304 This function returns the character position at
1305 x and y pixels from the top left of the textInput. Position 0 is before the
1306 first character, position 1 is after the first character but before the second,
1307 and so on until position text.length, which is after all characters.
1309 This means that for all x values before the first character this function returns 0,
1310 and for all x values after the last character this function returns text.length. If
1311 the y value is above the text the position will be that of the nearest character on
1312 the first line line and if it is below the text the position of the nearest character
1313 on the last line will be returned.
1315 The cursor position type specifies how the cursor position should be resolved.
1318 \li TextInput.CursorBetweenCharacters - Returns the position between characters that is nearest x.
1319 \li TextInput.CursorOnCharacter - Returns the position before the character that is nearest x.
1323 void QQuickTextInput::positionAt(QQmlV8Function *args) const
1325 Q_D(const QQuickTextInput);
1329 QTextLine::CursorPosition position = QTextLine::CursorBetweenCharacters;
1331 if (args->Length() < 1)
1335 v8::Local<v8::Value> arg = (*args)[i];
1336 x = arg->NumberValue();
1338 if (++i < args->Length()) {
1340 y = arg->NumberValue();
1343 if (++i < args->Length()) {
1345 position = QTextLine::CursorPosition(arg->Int32Value());
1348 int pos = d->positionAt(x, y, position);
1349 const int cursor = d->m_cursor;
1351 const int preeditLength = d->preeditAreaText().length();
1352 pos = pos > cursor + preeditLength
1353 ? pos - preeditLength
1356 args->returnValue(v8::Int32::New(pos));
1359 int QQuickTextInputPrivate::positionAt(qreal x, qreal y, QTextLine::CursorPosition position) const
1363 QTextLine line = m_textLayout.lineAt(0);
1364 for (int i = 1; i < m_textLayout.lineCount(); ++i) {
1365 QTextLine nextLine = m_textLayout.lineAt(i);
1367 if (y < (line.rect().bottom() + nextLine.y()) / 2)
1371 return line.isValid() ? line.xToCursor(x, position) : 0;
1374 void QQuickTextInput::keyPressEvent(QKeyEvent* ev)
1376 Q_D(QQuickTextInput);
1377 // Don't allow MacOSX up/down support, and we don't allow a completer.
1378 bool ignore = (ev->key() == Qt::Key_Up || ev->key() == Qt::Key_Down) && ev->modifiers() == Qt::NoModifier;
1379 if (!ignore && (d->lastSelectionStart == d->lastSelectionEnd) && (ev->key() == Qt::Key_Right || ev->key() == Qt::Key_Left)) {
1380 // Ignore when moving off the end unless there is a selection,
1381 // because then moving will do something (deselect).
1382 int cursorPosition = d->m_cursor;
1383 if (cursorPosition == 0)
1384 ignore = ev->key() == (d->layoutDirection() == Qt::LeftToRight ? Qt::Key_Left : Qt::Key_Right);
1385 if (!ignore && cursorPosition == text().length())
1386 ignore = ev->key() == (d->layoutDirection() == Qt::LeftToRight ? Qt::Key_Right : Qt::Key_Left);
1391 d->processKeyEvent(ev);
1393 if (!ev->isAccepted())
1394 QQuickImplicitSizeItem::keyPressEvent(ev);
1397 void QQuickTextInput::inputMethodEvent(QInputMethodEvent *ev)
1399 Q_D(QQuickTextInput);
1400 const bool wasComposing = d->hasImState;
1401 if (d->m_readOnly) {
1404 d->processInputMethodEvent(ev);
1406 if (!ev->isAccepted())
1407 QQuickImplicitSizeItem::inputMethodEvent(ev);
1409 if (wasComposing != d->hasImState)
1410 emit inputMethodComposingChanged();
1413 void QQuickTextInput::mouseDoubleClickEvent(QMouseEvent *event)
1415 Q_D(QQuickTextInput);
1417 if (d->selectByMouse && event->button() == Qt::LeftButton) {
1419 int cursor = d->positionAt(event->localPos());
1420 d->selectWordAtPos(cursor);
1421 event->setAccepted(true);
1422 if (!d->hasPendingTripleClick()) {
1423 d->tripleClickStartPoint = event->localPos();
1424 d->tripleClickTimer.start();
1427 if (d->sendMouseEventToInputContext(event))
1429 QQuickImplicitSizeItem::mouseDoubleClickEvent(event);
1433 void QQuickTextInput::mousePressEvent(QMouseEvent *event)
1435 Q_D(QQuickTextInput);
1437 d->pressPos = event->localPos();
1439 if (d->sendMouseEventToInputContext(event))
1442 if (d->selectByMouse) {
1443 setKeepMouseGrab(false);
1444 d->selectPressed = true;
1445 QPointF distanceVector = d->pressPos - d->tripleClickStartPoint;
1446 if (d->hasPendingTripleClick()
1447 && distanceVector.manhattanLength() < qApp->styleHints()->startDragDistance()) {
1448 event->setAccepted(true);
1454 bool mark = (event->modifiers() & Qt::ShiftModifier) && d->selectByMouse;
1455 int cursor = d->positionAt(event->localPos());
1456 d->moveCursor(cursor, mark);
1458 if (d->focusOnPress) {
1459 bool hadActiveFocus = hasActiveFocus();
1461 // re-open input panel on press if already focused
1462 if (hasActiveFocus() && hadActiveFocus && !d->m_readOnly)
1463 openSoftwareInputPanel();
1466 event->setAccepted(true);
1469 void QQuickTextInput::mouseMoveEvent(QMouseEvent *event)
1471 Q_D(QQuickTextInput);
1473 if (d->selectPressed) {
1474 if (qAbs(int(event->localPos().x() - d->pressPos.x())) > qApp->styleHints()->startDragDistance())
1475 setKeepMouseGrab(true);
1477 if (d->composeMode()) {
1479 int startPos = d->positionAt(d->pressPos);
1480 int currentPos = d->positionAt(event->localPos());
1481 if (startPos != currentPos)
1482 d->setSelection(startPos, currentPos - startPos);
1484 moveCursorSelection(d->positionAt(event->localPos()), d->mouseSelectionMode);
1486 event->setAccepted(true);
1488 QQuickImplicitSizeItem::mouseMoveEvent(event);
1492 void QQuickTextInput::mouseReleaseEvent(QMouseEvent *event)
1494 Q_D(QQuickTextInput);
1495 if (d->sendMouseEventToInputContext(event))
1497 if (d->selectPressed) {
1498 d->selectPressed = false;
1499 setKeepMouseGrab(false);
1501 #ifndef QT_NO_CLIPBOARD
1502 if (QGuiApplication::clipboard()->supportsSelection()) {
1503 if (event->button() == Qt::LeftButton) {
1504 d->copy(QClipboard::Selection);
1505 } else if (!d->m_readOnly && event->button() == Qt::MidButton) {
1507 d->insert(QGuiApplication::clipboard()->text(QClipboard::Selection));
1511 if (!event->isAccepted())
1512 QQuickImplicitSizeItem::mouseReleaseEvent(event);
1515 bool QQuickTextInputPrivate::sendMouseEventToInputContext(QMouseEvent *event)
1517 #if !defined QT_NO_IM
1518 if (composeMode()) {
1519 int tmp_cursor = positionAt(event->localPos());
1520 int mousePos = tmp_cursor - m_cursor;
1521 if (mousePos >= 0 && mousePos <= m_textLayout.preeditAreaText().length()) {
1522 if (event->type() == QEvent::MouseButtonRelease) {
1523 qApp->inputMethod()->invokeAction(QInputMethod::Click, mousePos);
1536 void QQuickTextInput::mouseUngrabEvent()
1538 Q_D(QQuickTextInput);
1539 d->selectPressed = false;
1540 setKeepMouseGrab(false);
1543 bool QQuickTextInput::event(QEvent* ev)
1545 #ifndef QT_NO_SHORTCUT
1546 Q_D(QQuickTextInput);
1547 if (ev->type() == QEvent::ShortcutOverride) {
1550 QKeyEvent* ke = static_cast<QKeyEvent*>(ev);
1551 if (ke == QKeySequence::Copy
1552 || ke == QKeySequence::Paste
1553 || ke == QKeySequence::Cut
1554 || ke == QKeySequence::Redo
1555 || ke == QKeySequence::Undo
1556 || ke == QKeySequence::MoveToNextWord
1557 || ke == QKeySequence::MoveToPreviousWord
1558 || ke == QKeySequence::MoveToStartOfDocument
1559 || ke == QKeySequence::MoveToEndOfDocument
1560 || ke == QKeySequence::SelectNextWord
1561 || ke == QKeySequence::SelectPreviousWord
1562 || ke == QKeySequence::SelectStartOfLine
1563 || ke == QKeySequence::SelectEndOfLine
1564 || ke == QKeySequence::SelectStartOfBlock
1565 || ke == QKeySequence::SelectEndOfBlock
1566 || ke == QKeySequence::SelectStartOfDocument
1567 || ke == QKeySequence::SelectAll
1568 || ke == QKeySequence::SelectEndOfDocument) {
1570 } else if (ke->modifiers() == Qt::NoModifier || ke->modifiers() == Qt::ShiftModifier
1571 || ke->modifiers() == Qt::KeypadModifier) {
1572 if (ke->key() < Qt::Key_Escape) {
1576 switch (ke->key()) {
1577 case Qt::Key_Delete:
1580 case Qt::Key_Backspace:
1592 return QQuickImplicitSizeItem::event(ev);
1595 void QQuickTextInput::geometryChanged(const QRectF &newGeometry,
1596 const QRectF &oldGeometry)
1598 Q_D(QQuickTextInput);
1600 if (newGeometry.width() != oldGeometry.width() && d->wrapMode != NoWrap)
1602 updateCursorRectangle();
1604 QQuickImplicitSizeItem::geometryChanged(newGeometry, oldGeometry);
1607 void QQuickTextInputPrivate::updateHorizontalScroll()
1609 Q_Q(QQuickTextInput);
1610 QTextLine currentLine = m_textLayout.lineForTextPosition(m_cursor + m_preeditCursor);
1611 const int preeditLength = m_textLayout.preeditAreaText().length();
1612 const qreal width = qMax<qreal>(0, q->width());
1614 qreal widthUsed = 0;
1615 if (currentLine.isValid()) {
1616 cix = currentLine.cursorToX(m_cursor + preeditLength);
1617 const qreal cursorWidth = cix >= 0 ? cix : width - cix;
1618 widthUsed = qMax(currentLine.naturalTextWidth(), cursorWidth);
1620 int previousScroll = hscroll;
1622 if (!autoScroll || widthUsed <= width || m_echoMode == QQuickTextInput::NoEcho) {
1625 Q_ASSERT(currentLine.isValid());
1626 if (cix - hscroll >= width) {
1627 // text doesn't fit, cursor is to the right of br (scroll right)
1628 hscroll = cix - width;
1629 } else if (cix - hscroll < 0 && hscroll < widthUsed) {
1630 // text doesn't fit, cursor is to the left of br (scroll left)
1632 } else if (widthUsed - hscroll < width) {
1633 // text doesn't fit, text document is to the left of br; align
1635 hscroll = widthUsed - width;
1636 } else if (width - hscroll > widthUsed) {
1637 // text doesn't fit, text document is to the right of br; align
1639 hscroll = width - widthUsed;
1641 if (preeditLength > 0) {
1642 // check to ensure long pre-edit text doesn't push the cursor
1644 cix = currentLine.cursorToX(m_cursor + qMax(0, m_preeditCursor - 1));
1649 if (previousScroll != hscroll)
1650 textLayoutDirty = true;
1653 void QQuickTextInputPrivate::updateVerticalScroll()
1655 Q_Q(QQuickTextInput);
1656 const int preeditLength = m_textLayout.preeditAreaText().length();
1657 const qreal height = qMax<qreal>(0, q->height());
1658 qreal heightUsed = contentSize.height();
1659 qreal previousScroll = vscroll;
1661 if (!autoScroll || heightUsed <= height) {
1662 // text fits in br; use vscroll for alignment
1663 switch (vAlign & ~(Qt::AlignAbsolute|Qt::AlignHorizontal_Mask)) {
1664 case Qt::AlignBottom:
1665 vscroll = heightUsed - height;
1667 case Qt::AlignVCenter:
1668 vscroll = (heightUsed - height) / 2;
1676 QTextLine currentLine = m_textLayout.lineForTextPosition(m_cursor + preeditLength);
1677 QRectF r = currentLine.isValid() ? currentLine.rect() : QRectF();
1678 qreal top = r.top();
1679 int bottom = r.bottom();
1681 if (bottom - vscroll >= height) {
1682 // text doesn't fit, cursor is to the below the br (scroll down)
1683 vscroll = bottom - height;
1684 } else if (top - vscroll < 0 && vscroll < heightUsed) {
1685 // text doesn't fit, cursor is above br (scroll up)
1687 } else if (heightUsed - vscroll < height) {
1688 // text doesn't fit, text document is to the left of br; align
1690 vscroll = heightUsed - height;
1692 if (preeditLength > 0) {
1693 // check to ensure long pre-edit text doesn't push the cursor
1695 currentLine = m_textLayout.lineForTextPosition(m_cursor + qMax(0, m_preeditCursor - 1));
1696 top = currentLine.isValid() ? currentLine.rect().top() : 0;
1701 if (previousScroll != vscroll)
1702 textLayoutDirty = true;
1705 void QQuickTextInput::triggerPreprocess()
1707 Q_D(QQuickTextInput);
1708 if (d->updateType == QQuickTextInputPrivate::UpdateNone)
1709 d->updateType = QQuickTextInputPrivate::UpdateOnlyPreprocess;
1713 QSGNode *QQuickTextInput::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data)
1716 Q_D(QQuickTextInput);
1718 if (d->updateType != QQuickTextInputPrivate::UpdatePaintNode && oldNode != 0) {
1719 // Update done in preprocess() in the nodes
1720 d->updateType = QQuickTextInputPrivate::UpdateNone;
1724 d->updateType = QQuickTextInputPrivate::UpdateNone;
1726 QQuickTextNode *node = static_cast<QQuickTextNode *>(oldNode);
1728 node = new QQuickTextNode(QQuickItemPrivate::get(this)->sceneGraphContext(), this);
1731 if (!d->textLayoutDirty && oldNode != 0) {
1732 QSGSimpleRectNode *cursorNode = node->cursorNode();
1733 if (cursorNode != 0 && !isReadOnly()) {
1734 cursorNode->setRect(cursorRectangle());
1736 if (!d->cursorVisible || (!d->m_blinkStatus && d->m_blinkPeriod > 0)) {
1743 node->deleteContent();
1744 node->setMatrix(QMatrix4x4());
1746 QPointF offset(0, 0);
1747 if (d->autoScroll && d->m_textLayout.lineCount() > 0) {
1748 QFontMetricsF fm(d->font);
1749 // the y offset is there to keep the baseline constant in case we have script changes in the text.
1750 offset = -QPoint(d->hscroll, d->vscroll + d->m_textLayout.lineAt(0).ascent() - fm.ascent());
1752 offset = -QPoint(d->hscroll, d->vscroll);
1755 if (!d->m_textLayout.text().isEmpty() || !d->m_textLayout.preeditAreaText().isEmpty()) {
1756 node->addTextLayout(offset, &d->m_textLayout, d->color,
1757 QQuickText::Normal, QColor(), QColor(),
1758 d->selectionColor, d->selectedTextColor,
1759 d->selectionStart(),
1760 d->selectionEnd() - 1); // selectionEnd() returns first char after
1764 if (!isReadOnly() && d->cursorItem == 0) {
1765 node->setCursor(cursorRectangle(), d->color);
1766 if (!d->cursorVisible || (!d->m_blinkStatus && d->m_blinkPeriod > 0)) {
1773 d->textLayoutDirty = false;
1779 QVariant QQuickTextInput::inputMethodQuery(Qt::InputMethodQuery property) const
1781 Q_D(const QQuickTextInput);
1784 return QVariant((bool)(flags() & ItemAcceptsInputMethod));
1786 return QVariant((int) d->effectiveInputMethodHints());
1787 case Qt::ImCursorRectangle:
1788 return cursorRectangle();
1791 case Qt::ImCursorPosition:
1792 return QVariant(d->m_cursor);
1793 case Qt::ImSurroundingText:
1794 if (d->m_echoMode == PasswordEchoOnEdit && !d->m_passwordEchoEditing) {
1795 return QVariant(displayText());
1797 return QVariant(d->realText());
1799 case Qt::ImCurrentSelection:
1800 return QVariant(selectedText());
1801 case Qt::ImMaximumTextLength:
1802 return QVariant(maxLength());
1803 case Qt::ImAnchorPosition:
1804 if (d->selectionStart() == d->selectionEnd())
1805 return QVariant(d->m_cursor);
1806 else if (d->selectionStart() == d->m_cursor)
1807 return QVariant(d->selectionEnd());
1809 return QVariant(d->selectionStart());
1816 \qmlmethod void QtQuick2::TextInput::deselect()
1818 Removes active text selection.
1820 void QQuickTextInput::deselect()
1822 Q_D(QQuickTextInput);
1827 \qmlmethod void QtQuick2::TextInput::selectAll()
1829 Causes all text to be selected.
1831 void QQuickTextInput::selectAll()
1833 Q_D(QQuickTextInput);
1834 d->setSelection(0, text().length());
1838 \qmlmethod void QtQuick2::TextInput::isRightToLeft(int start, int end)
1840 Returns true if the natural reading direction of the editor text
1841 found between positions \a start and \a end is right to left.
1843 bool QQuickTextInput::isRightToLeft(int start, int end)
1846 qmlInfo(this) << "isRightToLeft(start, end) called with the end property being smaller than the start.";
1849 return text().mid(start, end - start).isRightToLeft();
1853 #ifndef QT_NO_CLIPBOARD
1855 \qmlmethod QtQuick2::TextInput::cut()
1857 Moves the currently selected text to the system clipboard.
1859 void QQuickTextInput::cut()
1861 Q_D(QQuickTextInput);
1867 \qmlmethod QtQuick2::TextInput::copy()
1869 Copies the currently selected text to the system clipboard.
1871 void QQuickTextInput::copy()
1873 Q_D(QQuickTextInput);
1878 \qmlmethod QtQuick2::TextInput::paste()
1880 Replaces the currently selected text by the contents of the system clipboard.
1882 void QQuickTextInput::paste()
1884 Q_D(QQuickTextInput);
1888 #endif // QT_NO_CLIPBOARD
1891 Undoes the last operation if undo is \l {canUndo}{available}. Deselects any
1892 current selection, and updates the selection start to the current cursor
1896 void QQuickTextInput::undo()
1898 Q_D(QQuickTextInput);
1899 if (!d->m_readOnly) {
1901 d->finishChange(-1, true);
1906 Redoes the last operation if redo is \l {canRedo}{available}.
1909 void QQuickTextInput::redo()
1911 Q_D(QQuickTextInput);
1912 if (!d->m_readOnly) {
1919 \qmlmethod void QtQuick2::TextInput::insert(int position, string text)
1921 Inserts \a text into the TextInput at position.
1924 void QQuickTextInput::insert(int position, const QString &text)
1926 Q_D(QQuickTextInput);
1927 if (d->m_echoMode == QQuickTextInput::Password) {
1928 int delay = qGuiApp->styleHints()->passwordMaskDelay();
1930 d->m_passwordEchoTimer.start(delay, this);
1932 if (position < 0 || position > d->m_text.length())
1935 const int priorState = d->m_undoState;
1937 QString insertText = text;
1939 if (d->hasSelectedText()) {
1940 d->addCommand(QQuickTextInputPrivate::Command(
1941 QQuickTextInputPrivate::SetSelection, d->m_cursor, 0, d->m_selstart, d->m_selend));
1943 if (d->m_maskData) {
1944 insertText = d->maskString(position, insertText);
1945 for (int i = 0; i < insertText.length(); ++i) {
1946 d->addCommand(QQuickTextInputPrivate::Command(
1947 QQuickTextInputPrivate::DeleteSelection, position + i, d->m_text.at(position + i), -1, -1));
1948 d->addCommand(QQuickTextInputPrivate::Command(
1949 QQuickTextInputPrivate::Insert, position + i, insertText.at(i), -1, -1));
1951 d->m_text.replace(position, insertText.length(), insertText);
1952 if (!insertText.isEmpty())
1953 d->m_textDirty = true;
1954 if (position < d->m_selend && position + insertText.length() > d->m_selstart)
1955 d->m_selDirty = true;
1957 int remaining = d->m_maxLength - d->m_text.length();
1958 if (remaining != 0) {
1959 insertText = insertText.left(remaining);
1960 d->m_text.insert(position, insertText);
1961 for (int i = 0; i < insertText.length(); ++i)
1962 d->addCommand(QQuickTextInputPrivate::Command(
1963 QQuickTextInputPrivate::Insert, position + i, insertText.at(i), -1, -1));
1964 if (d->m_cursor >= position)
1965 d->m_cursor += insertText.length();
1966 if (d->m_selstart >= position)
1967 d->m_selstart += insertText.length();
1968 if (d->m_selend >= position)
1969 d->m_selend += insertText.length();
1970 d->m_textDirty = true;
1971 if (position >= d->m_selstart && position <= d->m_selend)
1972 d->m_selDirty = true;
1976 d->addCommand(QQuickTextInputPrivate::Command(
1977 QQuickTextInputPrivate::SetSelection, d->m_cursor, 0, d->m_selstart, d->m_selend));
1978 d->finishChange(priorState);
1980 if (d->lastSelectionStart != d->lastSelectionEnd) {
1981 if (d->m_selstart != d->lastSelectionStart) {
1982 d->lastSelectionStart = d->m_selstart;
1983 emit selectionStartChanged();
1985 if (d->m_selend != d->lastSelectionEnd) {
1986 d->lastSelectionEnd = d->m_selend;
1987 emit selectionEndChanged();
1993 \qmlmethod string QtQuick2::TextInput::getText(int start, int end)
1995 Removes the section of text that is between the \a start and \a end positions from the TextInput.
1998 void QQuickTextInput::remove(int start, int end)
2000 Q_D(QQuickTextInput);
2002 start = qBound(0, start, d->m_text.length());
2003 end = qBound(0, end, d->m_text.length());
2007 else if (start == end)
2010 if (start < d->m_selend && end > d->m_selstart)
2011 d->m_selDirty = true;
2013 const int priorState = d->m_undoState;
2015 d->addCommand(QQuickTextInputPrivate::Command(
2016 QQuickTextInputPrivate::SetSelection, d->m_cursor, 0, d->m_selstart, d->m_selend));
2018 if (start <= d->m_cursor && d->m_cursor < end) {
2019 // cursor is within the selection. Split up the commands
2020 // to be able to restore the correct cursor position
2021 for (int i = d->m_cursor; i >= start; --i) {
2022 d->addCommand(QQuickTextInputPrivate::Command(
2023 QQuickTextInputPrivate::DeleteSelection, i, d->m_text.at(i), -1, 1));
2025 for (int i = end - 1; i > d->m_cursor; --i) {
2026 d->addCommand(QQuickTextInputPrivate::Command(
2027 QQuickTextInputPrivate::DeleteSelection, i - d->m_cursor + start - 1, d->m_text.at(i), -1, -1));
2030 for (int i = end - 1; i >= start; --i) {
2031 d->addCommand(QQuickTextInputPrivate::Command(
2032 QQuickTextInputPrivate::RemoveSelection, i, d->m_text.at(i), -1, -1));
2035 if (d->m_maskData) {
2036 d->m_text.replace(start, end - start, d->clearString(start, end - start));
2037 for (int i = 0; i < end - start; ++i) {
2038 d->addCommand(QQuickTextInputPrivate::Command(
2039 QQuickTextInputPrivate::Insert, start + i, d->m_text.at(start + i), -1, -1));
2042 d->m_text.remove(start, end - start);
2044 if (d->m_cursor > start)
2045 d->m_cursor -= qMin(d->m_cursor, end) - start;
2046 if (d->m_selstart > start)
2047 d->m_selstart -= qMin(d->m_selstart, end) - start;
2048 if (d->m_selend > end)
2049 d->m_selend -= qMin(d->m_selend, end) - start;
2051 d->addCommand(QQuickTextInputPrivate::Command(
2052 QQuickTextInputPrivate::SetSelection, d->m_cursor, 0, d->m_selstart, d->m_selend));
2054 d->m_textDirty = true;
2055 d->finishChange(priorState);
2057 if (d->lastSelectionStart != d->lastSelectionEnd) {
2058 if (d->m_selstart != d->lastSelectionStart) {
2059 d->lastSelectionStart = d->m_selstart;
2060 emit selectionStartChanged();
2062 if (d->m_selend != d->lastSelectionEnd) {
2063 d->lastSelectionEnd = d->m_selend;
2064 emit selectionEndChanged();
2071 \qmlmethod void QtQuick2::TextInput::selectWord()
2073 Causes the word closest to the current cursor position to be selected.
2075 void QQuickTextInput::selectWord()
2077 Q_D(QQuickTextInput);
2078 d->selectWordAtPos(d->m_cursor);
2082 \qmlproperty bool QtQuick2::TextInput::smooth
2084 This property holds whether the text is smoothly scaled or transformed.
2086 Smooth filtering gives better visual quality, but is slower. If
2087 the item is displayed at its natural size, this property has no visual or
2090 \note Generally scaling artifacts are only visible if the item is stationary on
2091 the screen. A common pattern when animating an item is to disable smooth
2092 filtering at the beginning of the animation and reenable it at the conclusion.
2096 \qmlproperty string QtQuick2::TextInput::passwordCharacter
2098 This is the character displayed when echoMode is set to Password or
2099 PasswordEchoOnEdit. By default it is an asterisk.
2101 If this property is set to a string with more than one character,
2102 the first character is used. If the string is empty, the value
2103 is ignored and the property is not set.
2105 QString QQuickTextInput::passwordCharacter() const
2107 Q_D(const QQuickTextInput);
2108 return QString(d->m_passwordCharacter);
2111 void QQuickTextInput::setPasswordCharacter(const QString &str)
2113 Q_D(QQuickTextInput);
2114 if (str.length() < 1)
2116 d->m_passwordCharacter = str.constData()[0];
2117 if (d->m_echoMode == Password || d->m_echoMode == PasswordEchoOnEdit)
2118 d->updateDisplayText();
2119 emit passwordCharacterChanged();
2123 \qmlproperty string QtQuick2::TextInput::displayText
2125 This is the text displayed in the TextInput.
2127 If \l echoMode is set to TextInput::Normal, this holds the
2128 same value as the TextInput::text property. Otherwise,
2129 this property holds the text visible to the user, while
2130 the \l text property holds the actual entered text.
2132 QString QQuickTextInput::displayText() const
2134 Q_D(const QQuickTextInput);
2135 return d->m_textLayout.text();
2139 \qmlproperty bool QtQuick2::TextInput::selectByMouse
2143 If true, the user can use the mouse to select text in some
2144 platform-specific way. Note that for some platforms this may
2145 not be an appropriate interaction (eg. may conflict with how
2146 the text needs to behave inside a Flickable.
2148 bool QQuickTextInput::selectByMouse() const
2150 Q_D(const QQuickTextInput);
2151 return d->selectByMouse;
2154 void QQuickTextInput::setSelectByMouse(bool on)
2156 Q_D(QQuickTextInput);
2157 if (d->selectByMouse != on) {
2158 d->selectByMouse = on;
2159 emit selectByMouseChanged(on);
2164 \qmlproperty enum QtQuick2::TextInput::mouseSelectionMode
2166 Specifies how text should be selected using a mouse.
2169 \li TextInput.SelectCharacters - The selection is updated with individual characters. (Default)
2170 \li TextInput.SelectWords - The selection is updated with whole words.
2173 This property only applies when \l selectByMouse is true.
2176 QQuickTextInput::SelectionMode QQuickTextInput::mouseSelectionMode() const
2178 Q_D(const QQuickTextInput);
2179 return d->mouseSelectionMode;
2182 void QQuickTextInput::setMouseSelectionMode(SelectionMode mode)
2184 Q_D(QQuickTextInput);
2185 if (d->mouseSelectionMode != mode) {
2186 d->mouseSelectionMode = mode;
2187 emit mouseSelectionModeChanged(mode);
2192 \qmlproperty bool QtQuick2::TextInput::persistentSelection
2194 Whether the TextInput should keep its selection when it loses active focus to another
2195 item in the scene. By default this is set to false;
2198 bool QQuickTextInput::persistentSelection() const
2200 Q_D(const QQuickTextInput);
2201 return d->persistentSelection;
2204 void QQuickTextInput::setPersistentSelection(bool on)
2206 Q_D(QQuickTextInput);
2207 if (d->persistentSelection == on)
2209 d->persistentSelection = on;
2210 emit persistentSelectionChanged();
2213 #ifndef QT_NO_CLIPBOARD
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;
2233 \qmlproperty bool QtQuick2::TextInput::canUndo
2235 Returns true if the TextInput is writable and there are previous operations
2239 bool QQuickTextInput::canUndo() const
2241 Q_D(const QQuickTextInput);
2246 \qmlproperty bool QtQuick2::TextInput::canRedo
2248 Returns true if the TextInput is writable and there are \l {undo}{undone}
2249 operations that can be redone.
2252 bool QQuickTextInput::canRedo() const
2254 Q_D(const QQuickTextInput);
2259 \qmlproperty real QtQuick2::TextInput::contentWidth
2261 Returns the width of the text, including the width past the width
2262 which is covered due to insufficient wrapping if \l wrapMode is set.
2265 qreal QQuickTextInput::contentWidth() const
2267 Q_D(const QQuickTextInput);
2268 return d->contentSize.width();
2272 \qmlproperty real QtQuick2::TextInput::contentHeight
2274 Returns the height of the text, including the height past the height
2275 that is covered if the text does not fit within the set height.
2278 qreal QQuickTextInput::contentHeight() const
2280 Q_D(const QQuickTextInput);
2281 return d->contentSize.height();
2284 void QQuickTextInput::moveCursorSelection(int position)
2286 Q_D(QQuickTextInput);
2287 d->moveCursor(position, true);
2291 \qmlmethod void QtQuick2::TextInput::moveCursorSelection(int position, SelectionMode mode = TextInput.SelectCharacters)
2293 Moves the cursor to \a position and updates the selection according to the optional \a mode
2294 parameter. (To only move the cursor, set the \l cursorPosition property.)
2296 When this method is called it additionally sets either the
2297 selectionStart or the selectionEnd (whichever was at the previous cursor position)
2298 to the specified position. This allows you to easily extend and contract the selected
2301 The selection mode specifies whether the selection is updated on a per character or a per word
2302 basis. If not specified the selection mode will default to TextInput.SelectCharacters.
2305 \li TextInput.SelectCharacters - Sets either the selectionStart or selectionEnd (whichever was at
2306 the previous cursor position) to the specified position.
2307 \li TextInput.SelectWords - Sets the selectionStart and selectionEnd to include all
2308 words between the specified position and the previous cursor position. Words partially in the
2312 For example, take this sequence of calls:
2316 moveCursorSelection(9, TextInput.SelectCharacters)
2317 moveCursorSelection(7, TextInput.SelectCharacters)
2320 This moves the cursor to position 5, extend the selection end from 5 to 9
2321 and then retract the selection end from 9 to 7, leaving the text from position 5 to 7
2322 selected (the 6th and 7th characters).
2324 The same sequence with TextInput.SelectWords will extend the selection start to a word boundary
2325 before or on position 5 and extend the selection end to a word boundary on or past position 9.
2327 void QQuickTextInput::moveCursorSelection(int pos, SelectionMode mode)
2329 Q_D(QQuickTextInput);
2331 if (mode == SelectCharacters) {
2332 d->moveCursor(pos, true);
2333 } else if (pos != d->m_cursor){
2334 const int cursor = d->m_cursor;
2336 if (!d->hasSelectedText())
2337 anchor = d->m_cursor;
2338 else if (d->selectionStart() == d->m_cursor)
2339 anchor = d->selectionEnd();
2341 anchor = d->selectionStart();
2343 if (anchor < pos || (anchor == pos && cursor < pos)) {
2344 const QString text = this->text();
2345 QTextBoundaryFinder finder(QTextBoundaryFinder::Word, text);
2346 finder.setPosition(anchor);
2348 const QTextBoundaryFinder::BoundaryReasons reasons = finder.boundaryReasons();
2349 if (anchor < text.length() && (!(reasons & QTextBoundaryFinder::StartWord)
2350 || ((reasons & QTextBoundaryFinder::EndWord) && anchor > cursor))) {
2351 finder.toPreviousBoundary();
2353 anchor = finder.position() != -1 ? finder.position() : 0;
2355 finder.setPosition(pos);
2356 if (pos > 0 && !finder.boundaryReasons())
2357 finder.toNextBoundary();
2358 const int cursor = finder.position() != -1 ? finder.position() : text.length();
2360 d->setSelection(anchor, cursor - anchor);
2361 } else if (anchor > pos || (anchor == pos && cursor > pos)) {
2362 const QString text = this->text();
2363 QTextBoundaryFinder finder(QTextBoundaryFinder::Word, text);
2364 finder.setPosition(anchor);
2366 const QTextBoundaryFinder::BoundaryReasons reasons = finder.boundaryReasons();
2367 if (anchor > 0 && (!(reasons & QTextBoundaryFinder::EndWord)
2368 || ((reasons & QTextBoundaryFinder::StartWord) && anchor < cursor))) {
2369 finder.toNextBoundary();
2372 anchor = finder.position() != -1 ? finder.position() : text.length();
2374 finder.setPosition(pos);
2375 if (pos < text.length() && !finder.boundaryReasons())
2376 finder.toPreviousBoundary();
2377 const int cursor = finder.position() != -1 ? finder.position() : 0;
2379 d->setSelection(anchor, cursor - anchor);
2385 \qmlmethod void QtQuick2::TextInput::openSoftwareInputPanel()
2387 Opens software input panels like virtual keyboards for typing, useful for
2388 customizing when you want the input keyboard to be shown and hidden in
2391 By default the opening of input panels follows the platform style. Input panels are
2392 always closed if no editor has active focus.
2394 You can disable the automatic behavior by setting the property \c activeFocusOnPress to false
2395 and use functions openSoftwareInputPanel() and closeSoftwareInputPanel() to implement
2396 the behavior you want.
2398 Only relevant on platforms, which provide virtual keyboards.
2404 text: "Hello world!"
2405 activeFocusOnPress: false
2407 anchors.fill: parent
2409 if (!textInput.activeFocus) {
2410 textInput.forceActiveFocus()
2411 textInput.openSoftwareInputPanel();
2413 textInput.focus = false;
2416 onPressAndHold: textInput.closeSoftwareInputPanel();
2421 void QQuickTextInput::openSoftwareInputPanel()
2424 qGuiApp->inputMethod()->show();
2428 \qmlmethod void QtQuick2::TextInput::closeSoftwareInputPanel()
2430 Closes a software input panel like a virtual keyboard shown on the screen, useful
2431 for customizing when you want the input keyboard to be shown and hidden in
2434 By default the opening of input panels follows the platform style. Input panels are
2435 always closed if no editor has active focus.
2437 You can disable the automatic behavior by setting the property \c activeFocusOnPress to false
2438 and use functions openSoftwareInputPanel() and closeSoftwareInputPanel() to implement
2439 the behavior you want.
2441 Only relevant on platforms, which provide virtual keyboards.
2447 text: "Hello world!"
2448 activeFocusOnPress: false
2450 anchors.fill: parent
2452 if (!textInput.activeFocus) {
2453 textInput.forceActiveFocus();
2454 textInput.openSoftwareInputPanel();
2456 textInput.focus = false;
2459 onPressAndHold: textInput.closeSoftwareInputPanel();
2464 void QQuickTextInput::closeSoftwareInputPanel()
2467 qGuiApp->inputMethod()->hide();
2470 void QQuickTextInput::focusInEvent(QFocusEvent *event)
2472 Q_D(const QQuickTextInput);
2473 if (d->focusOnPress && !d->m_readOnly)
2474 openSoftwareInputPanel();
2475 QQuickImplicitSizeItem::focusInEvent(event);
2478 void QQuickTextInput::itemChange(ItemChange change, const ItemChangeData &value)
2480 Q_D(QQuickTextInput);
2481 if (change == ItemActiveFocusHasChanged) {
2482 bool hasFocus = value.boolValue;
2483 setCursorVisible(hasFocus); // ### refactor: && d->canvas && d->canvas->hasFocus()
2484 if (!hasFocus && (d->m_passwordEchoEditing || d->m_passwordEchoTimer.isActive())) {
2485 d->updatePasswordEchoEditing(false);//QQuickTextInputPrivate sets it on key events, but doesn't deal with focus events
2489 if (!d->persistentSelection)
2491 disconnect(qApp->inputMethod(), SIGNAL(inputDirectionChanged(Qt::LayoutDirection)),
2492 this, SLOT(q_updateAlignment()));
2494 q_updateAlignment();
2495 connect(qApp->inputMethod(), SIGNAL(inputDirectionChanged(Qt::LayoutDirection)),
2496 this, SLOT(q_updateAlignment()));
2499 QQuickItem::itemChange(change, value);
2503 \qmlproperty bool QtQuick2::TextInput::inputMethodComposing
2506 This property holds whether the TextInput has partial text input from an
2509 While it is composing an input method may rely on mouse or key events from
2510 the TextInput to edit or commit the partial text. This property can be
2511 used to determine when to disable events handlers that may interfere with
2512 the correct operation of an input method.
2514 bool QQuickTextInput::isInputMethodComposing() const
2516 Q_D(const QQuickTextInput);
2517 return d->hasImState;
2520 void QQuickTextInputPrivate::init()
2522 Q_Q(QQuickTextInput);
2523 q->setSmooth(smooth);
2524 q->setAcceptedMouseButtons(Qt::LeftButton);
2525 q->setFlag(QQuickItem::ItemAcceptsInputMethod);
2526 q->setFlag(QQuickItem::ItemHasContents);
2527 #ifndef QT_NO_CLIPBOARD
2528 q->connect(QGuiApplication::clipboard(), SIGNAL(dataChanged()),
2529 q, SLOT(q_canPasteChanged()));
2530 #endif // QT_NO_CLIPBOARD
2532 lastSelectionStart = 0;
2533 lastSelectionEnd = 0;
2534 determineHorizontalAlignment();
2536 if (!qmlDisableDistanceField()) {
2537 QTextOption option = m_textLayout.textOption();
2538 option.setUseDesignMetrics(true);
2539 m_textLayout.setTextOption(option);
2543 void QQuickTextInput::updateCursorRectangle()
2545 Q_D(QQuickTextInput);
2546 if (!isComponentComplete())
2549 d->updateHorizontalScroll();
2550 d->updateVerticalScroll();
2551 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
2553 emit cursorRectangleChanged();
2554 if (d->cursorItem) {
2555 QRectF r = cursorRectangle();
2556 d->cursorItem->setPos(r.topLeft());
2557 d->cursorItem->setHeight(r.height());
2559 updateInputMethod(Qt::ImCursorRectangle);
2562 void QQuickTextInput::selectionChanged()
2564 Q_D(QQuickTextInput);
2565 d->textLayoutDirty = true; //TODO: Only update rect in selection
2566 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
2568 emit selectedTextChanged();
2570 if (d->lastSelectionStart != d->selectionStart()) {
2571 d->lastSelectionStart = d->selectionStart();
2572 if (d->lastSelectionStart == -1)
2573 d->lastSelectionStart = d->m_cursor;
2574 emit selectionStartChanged();
2576 if (d->lastSelectionEnd != d->selectionEnd()) {
2577 d->lastSelectionEnd = d->selectionEnd();
2578 if (d->lastSelectionEnd == -1)
2579 d->lastSelectionEnd = d->m_cursor;
2580 emit selectionEndChanged();
2584 void QQuickTextInputPrivate::showCursor()
2586 if (textNode != 0 && textNode->cursorNode() != 0)
2587 textNode->cursorNode()->setColor(color);
2590 void QQuickTextInputPrivate::hideCursor()
2592 if (textNode != 0 && textNode->cursorNode() != 0)
2593 textNode->cursorNode()->setColor(QColor(0, 0, 0, 0));
2596 QRectF QQuickTextInput::boundingRect() const
2598 Q_D(const QQuickTextInput);
2600 int cursorWidth = d->cursorItem ? 0 : 1;
2602 qreal hscroll = d->hscroll;
2603 if (!d->autoScroll || d->contentSize.width() < width()) {
2604 switch (effectiveHAlign()) {
2608 hscroll += d->contentSize.width() - width();
2611 hscroll += (d->contentSize.width() - width()) / 2;
2616 // Could include font max left/right bearings to either side of rectangle.
2617 QRectF r(-hscroll, -d->vscroll, d->contentSize.width(), d->contentSize.height());
2618 r.setRight(r.right() + cursorWidth);
2622 QRectF QQuickTextInput::clipRect() const
2624 Q_D(const QQuickTextInput);
2626 int cursorWidth = d->cursorItem ? d->cursorItem->width() : 1;
2628 // Could include font max left/right bearings to either side of rectangle.
2629 QRectF r = QQuickImplicitSizeItem::clipRect();
2630 r.setRight(r.right() + cursorWidth);
2634 void QQuickTextInput::q_canPasteChanged()
2636 Q_D(QQuickTextInput);
2637 bool old = d->canPaste;
2638 #ifndef QT_NO_CLIPBOARD
2639 if (const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData())
2640 d->canPaste = !d->m_readOnly && mimeData->hasText();
2642 d->canPaste = false;
2645 bool changed = d->canPaste != old || !d->canPasteValid;
2646 d->canPasteValid = true;
2648 emit canPasteChanged();
2652 void QQuickTextInput::q_updateAlignment()
2654 Q_D(QQuickTextInput);
2655 if (d->determineHorizontalAlignment()) {
2657 updateCursorRectangle();
2661 // ### these should come from QStyleHints
2662 const int textCursorWidth = 1;
2663 const bool fullWidthSelection = true;
2668 Updates the display text based of the current edit text
2669 If the text has changed will emit displayTextChanged()
2671 void QQuickTextInputPrivate::updateDisplayText(bool forceUpdate)
2673 QString orig = m_textLayout.text();
2675 if (m_echoMode == QQuickTextInput::NoEcho)
2676 str = QString::fromLatin1("");
2680 if (m_echoMode == QQuickTextInput::Password) {
2681 str.fill(m_passwordCharacter);
2682 if (m_passwordEchoTimer.isActive() && m_cursor > 0 && m_cursor <= m_text.length()) {
2683 int cursor = m_cursor - 1;
2684 QChar uc = m_text.at(cursor);
2686 if (cursor > 0 && uc.unicode() >= 0xdc00 && uc.unicode() < 0xe000) {
2687 // second half of a surrogate, check if we have the first half as well,
2688 // if yes restore both at once
2689 uc = m_text.at(cursor - 1);
2690 if (uc.unicode() >= 0xd800 && uc.unicode() < 0xdc00)
2691 str[cursor - 1] = uc;
2694 } else if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit && !m_passwordEchoEditing) {
2695 str.fill(m_passwordCharacter);
2698 // replace certain non-printable characters with spaces (to avoid
2699 // drawing boxes when using fonts that don't have glyphs for such
2701 QChar* uc = str.data();
2702 for (int i = 0; i < (int)str.length(); ++i) {
2703 if ((uc[i] < 0x20 && uc[i] != 0x09)
2704 || uc[i] == QChar::LineSeparator
2705 || uc[i] == QChar::ParagraphSeparator
2706 || uc[i] == QChar::ObjectReplacementCharacter)
2707 uc[i] = QChar(0x0020);
2710 if (str != orig || forceUpdate) {
2711 m_textLayout.setText(str);
2712 updateLayout(); // polish?
2713 emit q_func()->displayTextChanged();
2717 qreal QQuickTextInputPrivate::getImplicitWidth() const
2719 Q_Q(const QQuickTextInput);
2720 if (!requireImplicitWidth) {
2721 QQuickTextInputPrivate *d = const_cast<QQuickTextInputPrivate *>(this);
2722 d->requireImplicitWidth = true;
2724 if (q->isComponentComplete()) {
2725 // One time cost, only incurred if implicitWidth is first requested after
2726 // componentComplete.
2727 QTextLayout layout(m_text);
2729 QTextOption option = m_textLayout.textOption();
2730 option.setTextDirection(m_layoutDirection);
2731 option.setFlags(QTextOption::IncludeTrailingSpaces);
2732 option.setWrapMode(QTextOption::WrapMode(wrapMode));
2733 option.setAlignment(Qt::Alignment(q->effectiveHAlign()));
2734 layout.setTextOption(option);
2735 layout.setFont(font);
2736 layout.setPreeditArea(m_textLayout.preeditAreaPosition(), m_textLayout.preeditAreaText());
2737 layout.beginLayout();
2739 QTextLine line = layout.createLine();
2740 line.setLineWidth(INT_MAX);
2741 d->implicitWidth = qCeil(line.naturalTextWidth());
2746 return implicitWidth;
2749 void QQuickTextInputPrivate::updateLayout()
2751 Q_Q(QQuickTextInput);
2753 if (!q->isComponentComplete())
2757 QTextOption option = m_textLayout.textOption();
2758 option.setTextDirection(layoutDirection());
2759 option.setWrapMode(QTextOption::WrapMode(wrapMode));
2760 option.setAlignment(Qt::Alignment(q->effectiveHAlign()));
2761 m_textLayout.setTextOption(option);
2762 m_textLayout.setFont(font);
2764 m_textLayout.beginLayout();
2766 QTextLine line = m_textLayout.createLine();
2767 if (requireImplicitWidth) {
2768 line.setLineWidth(INT_MAX);
2769 const bool wasInLayout = inLayout;
2771 q->setImplicitWidth(qCeil(line.naturalTextWidth()));
2772 inLayout = wasInLayout;
2773 if (inLayout) // probably the result of a binding loop, but by letting it
2774 return; // get this far we'll get a warning to that effect.
2776 qreal lineWidth = q->widthValid() ? q->width() : INT_MAX;
2780 line.setLineWidth(lineWidth);
2781 line.setPosition(QPointF(0, height));
2783 height += line.height();
2784 width = qMax(width, line.naturalTextWidth());
2786 line = m_textLayout.createLine();
2787 } while (line.isValid());
2788 m_textLayout.endLayout();
2790 option.setWrapMode(QTextOption::NoWrap);
2791 m_textLayout.setTextOption(option);
2793 textLayoutDirty = true;
2795 const QSizeF previousSize = contentSize;
2796 contentSize = QSizeF(width, height);
2798 updateType = UpdatePaintNode;
2801 if (!requireImplicitWidth && !q->widthValid())
2802 q->setImplicitSize(width, height);
2804 q->setImplicitHeight(height);
2806 if (previousSize != contentSize)
2807 emit q->contentSizeChanged();
2810 #ifndef QT_NO_CLIPBOARD
2814 Copies the currently selected text into the clipboard using the given
2817 \note If the echo mode is set to a mode other than Normal then copy
2818 will not work. This is to prevent using copy as a method of bypassing
2819 password features of the line control.
2821 void QQuickTextInputPrivate::copy(QClipboard::Mode mode) const
2823 QString t = selectedText();
2824 if (!t.isEmpty() && m_echoMode == QQuickTextInput::Normal) {
2825 QGuiApplication::clipboard()->setText(t, mode);
2832 Inserts the text stored in the application clipboard into the line
2837 void QQuickTextInputPrivate::paste(QClipboard::Mode clipboardMode)
2839 QString clip = QGuiApplication::clipboard()->text(clipboardMode);
2840 if (!clip.isEmpty() || hasSelectedText()) {
2841 separate(); //make it a separate undo/redo command
2847 #endif // !QT_NO_CLIPBOARD
2852 void QQuickTextInputPrivate::commitPreedit()
2854 Q_Q(QQuickTextInput);
2859 qApp->inputMethod()->commit();
2864 QInputMethodEvent ev;
2865 QCoreApplication::sendEvent(q, &ev);
2868 void QQuickTextInputPrivate::cancelPreedit()
2870 Q_Q(QQuickTextInput);
2875 qApp->inputMethod()->reset();
2877 QInputMethodEvent ev;
2878 QCoreApplication::sendEvent(q, &ev);
2884 Handles the behavior for the backspace key or function.
2885 Removes the current selection if there is a selection, otherwise
2886 removes the character prior to the cursor position.
2890 void QQuickTextInputPrivate::backspace()
2892 int priorState = m_undoState;
2893 if (hasSelectedText()) {
2894 removeSelectedText();
2895 } else if (m_cursor) {
2898 m_cursor = prevMaskBlank(m_cursor);
2899 QChar uc = m_text.at(m_cursor);
2900 if (m_cursor > 0 && uc.unicode() >= 0xdc00 && uc.unicode() < 0xe000) {
2901 // second half of a surrogate, check if we have the first half as well,
2902 // if yes delete both at once
2903 uc = m_text.at(m_cursor - 1);
2904 if (uc.unicode() >= 0xd800 && uc.unicode() < 0xdc00) {
2905 internalDelete(true);
2909 internalDelete(true);
2911 finishChange(priorState);
2917 Handles the behavior for the delete key or function.
2918 Removes the current selection if there is a selection, otherwise
2919 removes the character after the cursor position.
2923 void QQuickTextInputPrivate::del()
2925 int priorState = m_undoState;
2926 if (hasSelectedText()) {
2927 removeSelectedText();
2929 int n = m_textLayout.nextCursorPosition(m_cursor) - m_cursor;
2933 finishChange(priorState);
2939 Inserts the given \a newText at the current cursor position.
2940 If there is any selected text it is removed prior to insertion of
2943 void QQuickTextInputPrivate::insert(const QString &newText)
2945 int priorState = m_undoState;
2946 removeSelectedText();
2947 internalInsert(newText);
2948 finishChange(priorState);
2954 Clears the line control text.
2956 void QQuickTextInputPrivate::clear()
2958 int priorState = m_undoState;
2960 m_selend = m_text.length();
2961 removeSelectedText();
2963 finishChange(priorState, /*update*/false, /*edited*/false);
2969 Sets \a length characters from the given \a start position as selected.
2970 The given \a start position must be within the current text for
2971 the line control. If \a length characters cannot be selected, then
2972 the selection will extend to the end of the current text.
2974 void QQuickTextInputPrivate::setSelection(int start, int length)
2976 Q_Q(QQuickTextInput);
2979 if (start < 0 || start > (int)m_text.length()){
2980 qWarning("QQuickTextInputPrivate::setSelection: Invalid start position");
2985 if (start == m_selstart && start + length == m_selend && m_cursor == m_selend)
2988 m_selend = qMin(start + length, (int)m_text.length());
2989 m_cursor = m_selend;
2990 } else if (length < 0){
2991 if (start == m_selend && start + length == m_selstart && m_cursor == m_selstart)
2993 m_selstart = qMax(start + length, 0);
2995 m_cursor = m_selstart;
2996 } else if (m_selstart != m_selend) {
3002 emitCursorPositionChanged();
3005 emit q->selectionChanged();
3006 emitCursorPositionChanged();
3007 q->updateInputMethod(Qt::ImCursorRectangle | Qt::ImAnchorPosition
3008 | Qt::ImCursorPosition | Qt::ImCurrentSelection);
3014 Sets the password echo editing to \a editing. If password echo editing
3015 is true, then the text of the password is displayed even if the echo
3016 mode is set to QLineEdit::PasswordEchoOnEdit. Password echoing editing
3017 does not affect other echo modes.
3019 void QQuickTextInputPrivate::updatePasswordEchoEditing(bool editing)
3021 cancelPasswordEchoTimer();
3022 m_passwordEchoEditing = editing;
3023 updateDisplayText();
3029 Fixes the current text so that it is valid given any set validators.
3031 Returns true if the text was changed. Otherwise returns false.
3033 bool QQuickTextInputPrivate::fixup() // this function assumes that validate currently returns != Acceptable
3035 #ifndef QT_NO_VALIDATOR
3037 QString textCopy = m_text;
3038 int cursorCopy = m_cursor;
3039 m_validator->fixup(textCopy);
3040 if (m_validator->validate(textCopy, cursorCopy) == QValidator::Acceptable) {
3041 if (textCopy != m_text || cursorCopy != m_cursor)
3042 internalSetText(textCopy, cursorCopy);
3053 Moves the cursor to the given position \a pos. If \a mark is true will
3054 adjust the currently selected text.
3056 void QQuickTextInputPrivate::moveCursor(int pos, bool mark)
3058 Q_Q(QQuickTextInput);
3061 if (pos != m_cursor) {
3064 pos = pos > m_cursor ? nextMaskBlank(pos) : prevMaskBlank(pos);
3068 if (m_selend > m_selstart && m_cursor == m_selstart)
3070 else if (m_selend > m_selstart && m_cursor == m_selend)
3071 anchor = m_selstart;
3074 m_selstart = qMin(anchor, pos);
3075 m_selend = qMax(anchor, pos);
3080 if (mark || m_selDirty) {
3082 emit q->selectionChanged();
3084 emitCursorPositionChanged();
3085 q->updateInputMethod();
3091 Applies the given input method event \a event to the text of the line
3094 void QQuickTextInputPrivate::processInputMethodEvent(QInputMethodEvent *event)
3096 Q_Q(QQuickTextInput);
3098 int priorState = -1;
3099 bool isGettingInput = !event->commitString().isEmpty()
3100 || event->preeditString() != preeditAreaText()
3101 || event->replacementLength() > 0;
3102 bool cursorPositionChanged = false;
3103 bool selectionChange = false;
3104 m_preeditDirty = event->preeditString() != preeditAreaText();
3106 if (isGettingInput) {
3107 // If any text is being input, remove selected text.
3108 priorState = m_undoState;
3109 if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit && !m_passwordEchoEditing) {
3110 updatePasswordEchoEditing(true);
3112 m_selend = m_text.length();
3114 removeSelectedText();
3117 int c = m_cursor; // cursor position after insertion of commit string
3118 if (event->replacementStart() <= 0)
3119 c += event->commitString().length() - qMin(-event->replacementStart(), event->replacementLength());
3121 m_cursor += event->replacementStart();
3125 // insert commit string
3126 if (event->replacementLength()) {
3127 m_selstart = m_cursor;
3128 m_selend = m_selstart + event->replacementLength();
3129 m_selend = qMin(m_selend, m_text.length());
3130 removeSelectedText();
3132 if (!event->commitString().isEmpty()) {
3133 internalInsert(event->commitString());
3134 cursorPositionChanged = true;
3137 m_cursor = qBound(0, c, m_text.length());
3139 for (int i = 0; i < event->attributes().size(); ++i) {
3140 const QInputMethodEvent::Attribute &a = event->attributes().at(i);
3141 if (a.type == QInputMethodEvent::Selection) {
3142 m_cursor = qBound(0, a.start + a.length, m_text.length());
3144 m_selstart = qMax(0, qMin(a.start, m_text.length()));
3145 m_selend = m_cursor;
3146 if (m_selend < m_selstart) {
3147 qSwap(m_selstart, m_selend);
3149 selectionChange = true;
3151 m_selstart = m_selend = 0;
3153 cursorPositionChanged = true;
3157 m_textLayout.setPreeditArea(m_cursor, event->preeditString());
3159 const int oldPreeditCursor = m_preeditCursor;
3160 const bool oldCursorVisible = cursorVisible;
3161 m_preeditCursor = event->preeditString().length();
3162 hasImState = !event->preeditString().isEmpty();
3163 cursorVisible = true;
3164 QList<QTextLayout::FormatRange> formats;
3165 for (int i = 0; i < event->attributes().size(); ++i) {
3166 const QInputMethodEvent::Attribute &a = event->attributes().at(i);
3167 if (a.type == QInputMethodEvent::Cursor) {
3169 m_preeditCursor = a.start;
3170 cursorVisible = a.length != 0;
3171 } else if (a.type == QInputMethodEvent::TextFormat) {
3173 QTextCharFormat f = qvariant_cast<QTextFormat>(a.value).toCharFormat();
3175 QTextLayout::FormatRange o;
3176 o.start = a.start + m_cursor;
3177 o.length = a.length;
3183 m_textLayout.setAdditionalFormats(formats);
3185 updateDisplayText(/*force*/ true);
3186 if (cursorPositionChanged) {
3187 emitCursorPositionChanged();
3188 } else if (m_preeditCursor != oldPreeditCursor) {
3189 q->updateCursorRectangle();
3193 finishChange(priorState);
3195 if (cursorVisible != oldCursorVisible)
3196 emit q->cursorVisibleChanged(cursorVisible);
3198 if (selectionChange) {
3199 emit q->selectionChanged();
3200 q->updateInputMethod(Qt::ImCursorRectangle | Qt::ImAnchorPosition
3201 | Qt::ImCursorPosition | Qt::ImCurrentSelection);
3208 Sets the selection to cover the word at the given cursor position.
3209 The word boundaries are defined by the behavior of QTextLayout::SkipWords
3212 void QQuickTextInputPrivate::selectWordAtPos(int cursor)
3214 int next = cursor + 1;
3217 int c = m_textLayout.previousCursorPosition(next, QTextLayout::SkipWords);
3218 moveCursor(c, false);
3219 // ## text layout should support end of words.
3220 int end = m_textLayout.nextCursorPosition(c, QTextLayout::SkipWords);
3221 while (end > cursor && m_text[end-1].isSpace())
3223 moveCursor(end, true);
3229 Completes a change to the line control text. If the change is not valid
3230 will undo the line control state back to the given \a validateFromState.
3232 If \a edited is true and the change is valid, will emit textEdited() in
3233 addition to textChanged(). Otherwise only emits textChanged() on a valid
3236 The \a update value is currently unused.
3238 bool QQuickTextInputPrivate::finishChange(int validateFromState, bool update, bool /*edited*/)
3240 Q_Q(QQuickTextInput);
3243 bool inputMethodAttributesChanged = m_textDirty || m_selDirty;
3244 bool alignmentChanged = false;
3248 bool wasValidInput = m_validInput;
3249 bool wasAcceptable = m_acceptableInput;
3250 m_validInput = true;
3251 m_acceptableInput = true;
3252 #ifndef QT_NO_VALIDATOR
3254 QString textCopy = m_text;
3255 int cursorCopy = m_cursor;
3256 QValidator::State state = m_validator->validate(textCopy, cursorCopy);
3257 m_validInput = state != QValidator::Invalid;
3258 m_acceptableInput = state == QValidator::Acceptable;
3260 if (m_text != textCopy) {
3261 internalSetText(textCopy, cursorCopy);
3264 m_cursor = cursorCopy;
3268 if (validateFromState >= 0 && wasValidInput && !m_validInput) {
3269 if (m_transactions.count())
3271 internalUndo(validateFromState);
3272 m_history.resize(m_undoState);
3273 m_validInput = true;
3274 m_acceptableInput = wasAcceptable;
3275 m_textDirty = false;
3279 m_textDirty = false;
3280 m_preeditDirty = false;
3281 alignmentChanged = determineHorizontalAlignment();
3282 emit q->textChanged();
3285 updateDisplayText(alignmentChanged);
3287 if (m_acceptableInput != wasAcceptable)
3288 emit q->acceptableInputChanged();
3290 if (m_preeditDirty) {
3291 m_preeditDirty = false;
3292 if (determineHorizontalAlignment()) {
3293 alignmentChanged = true;
3300 emit q->selectionChanged();
3303 inputMethodAttributesChanged |= (m_cursor == m_lastCursorPos);
3304 if (inputMethodAttributesChanged)
3305 q->updateInputMethod();
3306 emitUndoRedoChanged();
3308 if (!emitCursorPositionChanged() && alignmentChanged)
3309 q->updateCursorRectangle();
3317 An internal function for setting the text of the line control.
3319 void QQuickTextInputPrivate::internalSetText(const QString &txt, int pos, bool edited)
3321 Q_Q(QQuickTextInput);
3323 QString oldText = m_text;
3325 m_text = maskString(0, txt, true);
3326 m_text += clearString(m_text.length(), m_maxLength - m_text.length());
3328 m_text = txt.isEmpty() ? txt : txt.left(m_maxLength);
3332 m_cursor = (pos < 0 || pos > m_text.length()) ? m_text.length() : pos;
3333 m_textDirty = (oldText != m_text);
3335 bool changed = finishChange(-1, true, edited);
3336 #ifdef QT_NO_ACCESSIBILITY
3340 QAccessibleTextUpdateEvent ev(q, 0, oldText, m_text);
3341 QAccessible::updateAccessibility(&ev);
3350 Adds the given \a command to the undo history
3351 of the line control. Does not apply the command.
3353 void QQuickTextInputPrivate::addCommand(const Command &cmd)
3355 if (m_separator && m_undoState && m_history[m_undoState - 1].type != Separator) {
3356 m_history.resize(m_undoState + 2);
3357 m_history[m_undoState++] = Command(Separator, m_cursor, 0, m_selstart, m_selend);
3359 m_history.resize(m_undoState + 1);
3361 m_separator = false;
3362 m_history[m_undoState++] = cmd;
3368 Inserts the given string \a s into the line
3371 Also adds the appropriate commands into the undo history.
3372 This function does not call finishChange(), and may leave the text
3373 in an invalid state.
3375 void QQuickTextInputPrivate::internalInsert(const QString &s)
3377 Q_Q(QQuickTextInput);
3378 if (m_echoMode == QQuickTextInput::Password) {
3379 int delay = qGuiApp->styleHints()->passwordMaskDelay();
3381 m_passwordEchoTimer.start(delay, q);
3383 if (hasSelectedText())
3384 addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
3386 QString ms = maskString(m_cursor, s);
3387 for (int i = 0; i < (int) ms.length(); ++i) {
3388 addCommand (Command(DeleteSelection, m_cursor + i, m_text.at(m_cursor + i), -1, -1));
3389 addCommand(Command(Insert, m_cursor + i, ms.at(i), -1, -1));
3391 m_text.replace(m_cursor, ms.length(), ms);
3392 m_cursor += ms.length();
3393 m_cursor = nextMaskBlank(m_cursor);
3396 int remaining = m_maxLength - m_text.length();
3397 if (remaining != 0) {
3398 m_text.insert(m_cursor, s.left(remaining));
3399 for (int i = 0; i < (int) s.left(remaining).length(); ++i)
3400 addCommand(Command(Insert, m_cursor++, s.at(i), -1, -1));
3409 deletes a single character from the current text. If \a wasBackspace,
3410 the character prior to the cursor is removed. Otherwise the character
3411 after the cursor is removed.
3413 Also adds the appropriate commands into the undo history.
3414 This function does not call finishChange(), and may leave the text
3415 in an invalid state.
3417 void QQuickTextInputPrivate::internalDelete(bool wasBackspace)
3419 if (m_cursor < (int) m_text.length()) {
3420 cancelPasswordEchoTimer();
3421 if (hasSelectedText())
3422 addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
3423 addCommand(Command((CommandType)((m_maskData ? 2 : 0) + (wasBackspace ? Remove : Delete)),
3424 m_cursor, m_text.at(m_cursor), -1, -1));
3426 m_text.replace(m_cursor, 1, clearString(m_cursor, 1));
3427 addCommand(Command(Insert, m_cursor, m_text.at(m_cursor), -1, -1));
3429 m_text.remove(m_cursor, 1);
3438 removes the currently selected text from the line control.
3440 Also adds the appropriate commands into the undo history.
3441 This function does not call finishChange(), and may leave the text
3442 in an invalid state.
3444 void QQuickTextInputPrivate::removeSelectedText()
3446 if (m_selstart < m_selend && m_selend <= (int) m_text.length()) {
3447 cancelPasswordEchoTimer();
3450 addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
3451 if (m_selstart <= m_cursor && m_cursor < m_selend) {
3452 // cursor is within the selection. Split up the commands
3453 // to be able to restore the correct cursor position
3454 for (i = m_cursor; i >= m_selstart; --i)
3455 addCommand (Command(DeleteSelection, i, m_text.at(i), -1, 1));
3456 for (i = m_selend - 1; i > m_cursor; --i)
3457 addCommand (Command(DeleteSelection, i - m_cursor + m_selstart - 1, m_text.at(i), -1, -1));
3459 for (i = m_selend-1; i >= m_selstart; --i)
3460 addCommand (Command(RemoveSelection, i, m_text.at(i), -1, -1));
3463 m_text.replace(m_selstart, m_selend - m_selstart, clearString(m_selstart, m_selend - m_selstart));
3464 for (int i = 0; i < m_selend - m_selstart; ++i)
3465 addCommand(Command(Insert, m_selstart + i, m_text.at(m_selstart + i), -1, -1));
3467 m_text.remove(m_selstart, m_selend - m_selstart);
3469 if (m_cursor > m_selstart)
3470 m_cursor -= qMin(m_cursor, m_selend) - m_selstart;
3479 Parses the input mask specified by \a maskFields to generate
3480 the mask data used to handle input masks.
3482 void QQuickTextInputPrivate::parseInputMask(const QString &maskFields)
3484 int delimiter = maskFields.indexOf(QLatin1Char(';'));
3485 if (maskFields.isEmpty() || delimiter == 0) {
3487 delete [] m_maskData;
3489 m_maxLength = 32767;
3490 internalSetText(QString());
3495 if (delimiter == -1) {
3496 m_blank = QLatin1Char(' ');
3497 m_inputMask = maskFields;
3499 m_inputMask = maskFields.left(delimiter);
3500 m_blank = (delimiter + 1 < maskFields.length()) ? maskFields[delimiter + 1] : QLatin1Char(' ');
3503 // calculate m_maxLength / m_maskData length
3506 for (int i=0; i<m_inputMask.length(); i++) {
3507 c = m_inputMask.at(i);
3508 if (i > 0 && m_inputMask.at(i-1) == QLatin1Char('\\')) {
3512 if (c != QLatin1Char('\\') && c != QLatin1Char('!') &&
3513 c != QLatin1Char('<') && c != QLatin1Char('>') &&
3514 c != QLatin1Char('{') && c != QLatin1Char('}') &&
3515 c != QLatin1Char('[') && c != QLatin1Char(']'))
3519 delete [] m_maskData;
3520 m_maskData = new MaskInputData[m_maxLength];
3522 MaskInputData::Casemode m = MaskInputData::NoCaseMode;
3525 bool escape = false;
3527 for (int i = 0; i < m_inputMask.length(); i++) {
3528 c = m_inputMask.at(i);
3531 m_maskData[index].maskChar = c;
3532 m_maskData[index].separator = s;
3533 m_maskData[index].caseMode = m;
3536 } else if (c == QLatin1Char('<')) {
3537 m = MaskInputData::Lower;
3538 } else if (c == QLatin1Char('>')) {
3539 m = MaskInputData::Upper;
3540 } else if (c == QLatin1Char('!')) {
3541 m = MaskInputData::NoCaseMode;
3542 } else if (c != QLatin1Char('{') && c != QLatin1Char('}') && c != QLatin1Char('[') && c != QLatin1Char(']')) {
3543 switch (c.unicode()) {
3569 m_maskData[index].maskChar = c;
3570 m_maskData[index].separator = s;
3571 m_maskData[index].caseMode = m;
3576 internalSetText(m_text);
3583 checks if the key is valid compared to the inputMask
3585 bool QQuickTextInputPrivate::isValidInput(QChar key, QChar mask) const
3587 switch (mask.unicode()) {
3593 if (key.isLetter() || key == m_blank)
3597 if (key.isLetterOrNumber())
3601 if (key.isLetterOrNumber() || key == m_blank)
3609 if (key.isPrint() || key == m_blank)
3617 if (key.isNumber() || key == m_blank)
3621 if (key.isNumber() && key.digitValue() > 0)
3625 if ((key.isNumber() && key.digitValue() > 0) || key == m_blank)
3629 if (key.isNumber() || key == QLatin1Char('+') || key == QLatin1Char('-') || key == m_blank)
3633 if (key == QLatin1Char('0') || key == QLatin1Char('1'))
3637 if (key == QLatin1Char('0') || key == QLatin1Char('1') || key == m_blank)
3641 if (key.isNumber() || (key >= QLatin1Char('a') && key <= QLatin1Char('f')) || (key >= QLatin1Char('A') && key <= QLatin1Char('F')))
3645 if (key.isNumber() || (key >= QLatin1Char('a') && key <= QLatin1Char('f')) || (key >= QLatin1Char('A') && key <= QLatin1Char('F')) || key == m_blank)
3657 Returns true if the given text \a str is valid for any
3658 validator or input mask set for the line control.
3660 Otherwise returns false
3662 QQuickTextInputPrivate::ValidatorState QQuickTextInputPrivate::hasAcceptableInput(const QString &str) const
3664 #ifndef QT_NO_VALIDATOR
3665 QString textCopy = str;
3666 int cursorCopy = m_cursor;
3668 QValidator::State state = m_validator->validate(textCopy, cursorCopy);
3669 if (state != QValidator::Acceptable)
3670 return ValidatorState(state);
3675 return AcceptableInput;
3677 if (str.length() != m_maxLength)
3678 return InvalidInput;
3680 for (int i=0; i < m_maxLength; ++i) {
3681 if (m_maskData[i].separator) {
3682 if (str.at(i) != m_maskData[i].maskChar)
3683 return InvalidInput;
3685 if (!isValidInput(str.at(i), m_maskData[i].maskChar))
3686 return InvalidInput;
3689 return AcceptableInput;
3695 Applies the inputMask on \a str starting from position \a pos in the mask. \a clear
3696 specifies from where characters should be gotten when a separator is met in \a str - true means
3697 that blanks will be used, false that previous input is used.
3698 Calling this when no inputMask is set is undefined.
3700 QString QQuickTextInputPrivate::maskString(uint pos, const QString &str, bool clear) const
3702 if (pos >= (uint)m_maxLength)
3703 return QString::fromLatin1("");
3706 fill = clear ? clearString(0, m_maxLength) : m_text;
3709 QString s = QString::fromLatin1("");
3711 while (i < m_maxLength) {
3712 if (strIndex < str.length()) {
3713 if (m_maskData[i].separator) {
3714 s += m_maskData[i].maskChar;
3715 if (str[(int)strIndex] == m_maskData[i].maskChar)
3719 if (isValidInput(str[(int)strIndex], m_maskData[i].maskChar)) {
3720 switch (m_maskData[i].caseMode) {
3721 case MaskInputData::Upper:
3722 s += str[(int)strIndex].toUpper();
3724 case MaskInputData::Lower:
3725 s += str[(int)strIndex].toLower();
3728 s += str[(int)strIndex];
3732 // search for separator first
3733 int n = findInMask(i, true, true, str[(int)strIndex]);
3735 if (str.length() != 1 || i == 0 || (i > 0 && (!m_maskData[i-1].separator || m_maskData[i-1].maskChar != str[(int)strIndex]))) {
3736 s += fill.mid(i, n-i+1);
3737 i = n + 1; // update i to find + 1
3740 // search for valid m_blank if not
3741 n = findInMask(i, true, false, str[(int)strIndex]);
3743 s += fill.mid(i, n-i);
3744 switch (m_maskData[n].caseMode) {
3745 case MaskInputData::Upper:
3746 s += str[(int)strIndex].toUpper();
3748 case MaskInputData::Lower:
3749 s += str[(int)strIndex].toLower();
3752 s += str[(int)strIndex];
3754 i = n + 1; // updates i to find + 1
3772 Returns a "cleared" string with only separators and blank chars.
3773 Calling this when no inputMask is set is undefined.
3775 QString QQuickTextInputPrivate::clearString(uint pos, uint len) const
3777 if (pos >= (uint)m_maxLength)
3781 int end = qMin((uint)m_maxLength, pos + len);
3782 for (int i = pos; i < end; ++i)
3783 if (m_maskData[i].separator)
3784 s += m_maskData[i].maskChar;
3794 Strips blank parts of the input in a QQuickTextInputPrivate when an inputMask is set,
3795 separators are still included. Typically "127.0__.0__.1__" becomes "127.0.0.1".
3797 QString QQuickTextInputPrivate::stripString(const QString &str) const
3803 int end = qMin(m_maxLength, (int)str.length());
3804 for (int i = 0; i < end; ++i) {
3805 if (m_maskData[i].separator)
3806 s += m_maskData[i].maskChar;
3807 else if (str[i] != m_blank)
3816 searches forward/backward in m_maskData for either a separator or a m_blank
3818 int QQuickTextInputPrivate::findInMask(int pos, bool forward, bool findSeparator, QChar searchChar) const
3820 if (pos >= m_maxLength || pos < 0)
3823 int end = forward ? m_maxLength : -1;
3824 int step = forward ? 1 : -1;
3828 if (findSeparator) {
3829 if (m_maskData[i].separator && m_maskData[i].maskChar == searchChar)
3832 if (!m_maskData[i].separator) {
3833 if (searchChar.isNull())
3835 else if (isValidInput(searchChar, m_maskData[i].maskChar))
3844 void QQuickTextInputPrivate::internalUndo(int until)
3846 if (!isUndoAvailable())
3848 cancelPasswordEchoTimer();
3850 while (m_undoState && m_undoState > until) {
3851 Command& cmd = m_history[--m_undoState];
3854 m_text.remove(cmd.pos, 1);
3858 m_selstart = cmd.selStart;
3859 m_selend = cmd.selEnd;
3863 case RemoveSelection:
3864 m_text.insert(cmd.pos, cmd.uc);
3865 m_cursor = cmd.pos + 1;
3868 case DeleteSelection:
3869 m_text.insert(cmd.pos, cmd.uc);
3875 if (until < 0 && m_undoState) {
3876 Command& next = m_history[m_undoState-1];
3877 if (next.type != cmd.type && next.type < RemoveSelection
3878 && (cmd.type < RemoveSelection || next.type == Separator))
3885 void QQuickTextInputPrivate::internalRedo()
3887 if (!isRedoAvailable())
3890 while (m_undoState < (int)m_history.size()) {
3891 Command& cmd = m_history[m_undoState++];
3894 m_text.insert(cmd.pos, cmd.uc);
3895 m_cursor = cmd.pos + 1;
3898 m_selstart = cmd.selStart;
3899 m_selend = cmd.selEnd;
3904 case RemoveSelection:
3905 case DeleteSelection:
3906 m_text.remove(cmd.pos, 1);
3907 m_selstart = cmd.selStart;
3908 m_selend = cmd.selEnd;
3912 m_selstart = cmd.selStart;
3913 m_selend = cmd.selEnd;
3917 if (m_undoState < (int)m_history.size()) {
3918 Command& next = m_history[m_undoState];
3919 if (next.type != cmd.type && cmd.type < RemoveSelection && next.type != Separator
3920 && (next.type < RemoveSelection || cmd.type == Separator))
3927 void QQuickTextInputPrivate::emitUndoRedoChanged()
3929 Q_Q(QQuickTextInput);
3930 const bool previousUndo = canUndo;
3931 const bool previousRedo = canRedo;
3933 canUndo = isUndoAvailable();
3934 canRedo = isRedoAvailable();
3936 if (previousUndo != canUndo)
3937 emit q->canUndoChanged();
3938 if (previousRedo != canRedo)
3939 emit q->canRedoChanged();
3945 If the current cursor position differs from the last emitted cursor
3946 position, emits cursorPositionChanged().
3948 bool QQuickTextInputPrivate::emitCursorPositionChanged()
3950 Q_Q(QQuickTextInput);
3951 if (m_cursor != m_lastCursorPos) {
3952 m_lastCursorPos = m_cursor;
3954 q->updateCursorRectangle();
3955 emit q->cursorPositionChanged();
3957 if (!hasSelectedText()) {
3958 if (lastSelectionStart != m_cursor) {
3959 lastSelectionStart = m_cursor;
3960 emit q->selectionStartChanged();
3962 if (lastSelectionEnd != m_cursor) {
3963 lastSelectionEnd = m_cursor;
3964 emit q->selectionEndChanged();
3968 #ifndef QT_NO_ACCESSIBILITY
3969 QAccessibleTextCursorEvent ev(q, m_cursor);
3970 QAccessible::updateAccessibility(&ev);
3979 void QQuickTextInputPrivate::setCursorBlinkPeriod(int msec)
3981 Q_Q(QQuickTextInput);
3982 if (msec == m_blinkPeriod)
3985 q->killTimer(m_blinkTimer);
3988 m_blinkTimer = q->startTimer(msec / 2);
3992 if (m_blinkStatus == 1) {
3993 updateType = UpdatePaintNode;
3997 m_blinkPeriod = msec;
4000 void QQuickTextInput::timerEvent(QTimerEvent *event)
4002 Q_D(QQuickTextInput);
4003 if (event->timerId() == d->m_blinkTimer) {
4004 d->m_blinkStatus = !d->m_blinkStatus;
4005 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
4007 } else if (event->timerId() == d->m_passwordEchoTimer.timerId()) {
4008 d->m_passwordEchoTimer.stop();
4009 d->updateDisplayText();
4013 void QQuickTextInputPrivate::processKeyEvent(QKeyEvent* event)
4015 Q_Q(QQuickTextInput);
4016 bool inlineCompletionAccepted = false;
4018 if (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return) {
4019 if (hasAcceptableInput(m_text) || fixup()) {
4022 if (inlineCompletionAccepted)
4029 if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit
4030 && !m_passwordEchoEditing
4032 && !event->text().isEmpty()
4033 && !(event->modifiers() & Qt::ControlModifier)) {
4034 // Clear the edit and reset to normal echo mode while editing; the
4035 // echo mode switches back when the edit loses focus
4036 // ### resets current content. dubious code; you can
4037 // navigate with keys up, down, back, and select(?), but if you press
4038 // "left" or "right" it clears?
4039 updatePasswordEchoEditing(true);
4043 bool unknown = false;
4044 bool visual = cursorMoveStyle() == Qt::VisualMoveStyle;
4048 #ifndef QT_NO_SHORTCUT
4049 else if (event == QKeySequence::Undo) {
4052 else if (event == QKeySequence::Redo) {
4055 else if (event == QKeySequence::SelectAll) {
4058 #ifndef QT_NO_CLIPBOARD
4059 else if (event == QKeySequence::Copy) {
4062 else if (event == QKeySequence::Paste) {
4064 QClipboard::Mode mode = QClipboard::Clipboard;
4068 else if (event == QKeySequence::Cut) {
4074 else if (event == QKeySequence::DeleteEndOfLine) {
4076 setSelection(m_cursor, end());
4081 #endif //QT_NO_CLIPBOARD
4082 else if (event == QKeySequence::MoveToStartOfLine || event == QKeySequence::MoveToStartOfBlock) {
4085 else if (event == QKeySequence::MoveToEndOfLine || event == QKeySequence::MoveToEndOfBlock) {
4088 else if (event == QKeySequence::SelectStartOfLine || event == QKeySequence::SelectStartOfBlock) {
4091 else if (event == QKeySequence::SelectEndOfLine || event == QKeySequence::SelectEndOfBlock) {
4094 else if (event == QKeySequence::MoveToNextChar) {
4095 if (hasSelectedText()) {
4096 moveCursor(selectionEnd(), false);
4098 cursorForward(0, visual ? 1 : (layoutDirection() == Qt::LeftToRight ? 1 : -1));
4101 else if (event == QKeySequence::SelectNextChar) {
4102 cursorForward(1, visual ? 1 : (layoutDirection() == Qt::LeftToRight ? 1 : -1));
4104 else if (event == QKeySequence::MoveToPreviousChar) {
4105 if (hasSelectedText()) {
4106 moveCursor(selectionStart(), false);
4108 cursorForward(0, visual ? -1 : (layoutDirection() == Qt::LeftToRight ? -1 : 1));
4111 else if (event == QKeySequence::SelectPreviousChar) {
4112 cursorForward(1, visual ? -1 : (layoutDirection() == Qt::LeftToRight ? -1 : 1));
4114 else if (event == QKeySequence::MoveToNextWord) {
4115 if (m_echoMode == QQuickTextInput::Normal)
4116 layoutDirection() == Qt::LeftToRight ? cursorWordForward(0) : cursorWordBackward(0);
4118 layoutDirection() == Qt::LeftToRight ? end(0) : home(0);
4120 else if (event == QKeySequence::MoveToPreviousWord) {
4121 if (m_echoMode == QQuickTextInput::Normal)
4122 layoutDirection() == Qt::LeftToRight ? cursorWordBackward(0) : cursorWordForward(0);
4123 else if (!m_readOnly) {
4124 layoutDirection() == Qt::LeftToRight ? home(0) : end(0);
4127 else if (event == QKeySequence::SelectNextWord) {
4128 if (m_echoMode == QQuickTextInput::Normal)
4129 layoutDirection() == Qt::LeftToRight ? cursorWordForward(1) : cursorWordBackward(1);
4131 layoutDirection() == Qt::LeftToRight ? end(1) : home(1);
4133 else if (event == QKeySequence::SelectPreviousWord) {
4134 if (m_echoMode == QQuickTextInput::Normal)
4135 layoutDirection() == Qt::LeftToRight ? cursorWordBackward(1) : cursorWordForward(1);
4137 layoutDirection() == Qt::LeftToRight ? home(1) : end(1);
4139 else if (event == QKeySequence::Delete) {
4143 else if (event == QKeySequence::DeleteEndOfWord) {
4145 cursorWordForward(true);
4149 else if (event == QKeySequence::DeleteStartOfWord) {
4151 cursorWordBackward(true);
4155 #endif // QT_NO_SHORTCUT
4157 bool handled = false;
4158 if (event->modifiers() & Qt::ControlModifier) {
4159 switch (event->key()) {
4160 case Qt::Key_Backspace:
4162 cursorWordBackward(true);
4170 } else { // ### check for *no* modifier
4171 switch (event->key()) {
4172 case Qt::Key_Backspace:
4184 if (event->key() == Qt::Key_Direction_L || event->key() == Qt::Key_Direction_R) {
4185 setLayoutDirection((event->key() == Qt::Key_Direction_L) ? Qt::LeftToRight : Qt::RightToLeft);
4189 if (unknown && !m_readOnly) {
4190 QString t = event->text();
4191 if (!t.isEmpty() && t.at(0).isPrint()) {