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"
45 #include "qquicktextutil_p.h"
47 #include <private/qqmlglobal_p.h>
50 #include <QtCore/qcoreapplication.h>
51 #include <QtQml/qqmlinfo.h>
52 #include <QtGui/qevent.h>
53 #include <QTextBoundaryFinder>
54 #include "qquicktextnode_p.h"
55 #include <QtQuick/qsgsimplerectnode.h>
57 #include <QtGui/qstylehints.h>
58 #include <QtGui/qinputmethod.h>
60 #ifndef QT_NO_ACCESSIBILITY
61 #include "qaccessible.h"
66 DEFINE_BOOL_CONFIG_OPTION(qmlDisableDistanceField, QML_DISABLE_DISTANCEFIELD)
69 \qmlclass TextInput QQuickTextInput
70 \inqmlmodule QtQuick 2
71 \ingroup qml-basic-visual-elements
72 \brief The TextInput item displays an editable line of text.
75 The TextInput element displays a single line of editable plain text.
77 TextInput is used to accept a line of text input. Input constraints
78 can be placed on a TextInput item (for example, through a \l validator or \l inputMask),
79 and setting \l echoMode to an appropriate value enables TextInput to be used for
80 a password input field.
82 On Mac OS X, the Up/Down key bindings for Home/End are explicitly disabled.
83 If you want such bindings (on any platform), you will need to construct them in QML.
85 \sa TextEdit, Text, {declarative/text/textselection}{Text Selection example}
87 QQuickTextInput::QQuickTextInput(QQuickItem* parent)
88 : QQuickImplicitSizeItem(*(new QQuickTextInputPrivate), parent)
94 QQuickTextInput::~QQuickTextInput()
98 void QQuickTextInput::componentComplete()
100 Q_D(QQuickTextInput);
102 QQuickImplicitSizeItem::componentComplete();
106 updateCursorRectangle();
107 if (d->cursorComponent && isCursorVisible())
108 QQuickTextUtil::createCursor(d);
112 \qmlproperty string QtQuick2::TextInput::text
114 The text in the TextInput.
116 QString QQuickTextInput::text() const
118 Q_D(const QQuickTextInput);
120 QString content = d->m_text;
121 QString res = d->m_maskData ? d->stripString(content) : content;
122 return (res.isNull() ? QString::fromLatin1("") : res);
125 void QQuickTextInput::setText(const QString &s)
127 Q_D(QQuickTextInput);
132 d->internalSetText(s, -1, false);
136 \qmlproperty int QtQuick2::TextInput::length
138 Returns the total number of characters in the TextInput item.
140 If the TextInput has an inputMask the length will include mask characters and may differ
141 from the length of the string returned by the \l text property.
143 This property can be faster than querying the length the \l text property as it doesn't
144 require any copying or conversion of the TextInput's internal string data.
147 int QQuickTextInput::length() const
149 Q_D(const QQuickTextInput);
150 return d->m_text.length();
154 \qmlmethod string QtQuick2::TextInput::getText(int start, int end)
156 Returns the section of text that is between the \a start and \a end positions.
158 If the TextInput has an inputMask the length will include mask characters.
161 QString QQuickTextInput::getText(int start, int end) const
163 Q_D(const QQuickTextInput);
168 return d->m_text.mid(start, end - start);
171 QString QQuickTextInputPrivate::realText() const
173 QString res = m_maskData ? stripString(m_text) : m_text;
174 return (res.isNull() ? QString::fromLatin1("") : res);
178 \qmlproperty string QtQuick2::TextInput::font.family
180 Sets the family name of the font.
182 The family name is case insensitive and may optionally include a foundry name, e.g. "Helvetica [Cronyx]".
183 If the family is available from more than one foundry and the foundry isn't specified, an arbitrary foundry is chosen.
184 If the family isn't available a family will be set using the font matching algorithm.
188 \qmlproperty bool QtQuick2::TextInput::font.bold
190 Sets whether the font weight is bold.
194 \qmlproperty enumeration QtQuick2::TextInput::font.weight
196 Sets the font's weight.
198 The weight can be one of:
201 \li Font.Normal - the default
208 TextInput { text: "Hello"; font.weight: Font.DemiBold }
213 \qmlproperty bool QtQuick2::TextInput::font.italic
215 Sets whether the font has an italic style.
219 \qmlproperty bool QtQuick2::TextInput::font.underline
221 Sets whether the text is underlined.
225 \qmlproperty bool QtQuick2::TextInput::font.strikeout
227 Sets whether the font has a strikeout style.
231 \qmlproperty real QtQuick2::TextInput::font.pointSize
233 Sets the font size in points. The point size must be greater than zero.
237 \qmlproperty int QtQuick2::TextInput::font.pixelSize
239 Sets the font size in pixels.
241 Using this function makes the font device dependent.
242 Use \c pointSize to set the size of the font in a device independent manner.
246 \qmlproperty real QtQuick2::TextInput::font.letterSpacing
248 Sets the letter spacing for the font.
250 Letter spacing changes the default spacing between individual letters in the font.
251 A positive value increases the letter spacing by the corresponding pixels; a negative value decreases the spacing.
255 \qmlproperty real QtQuick2::TextInput::font.wordSpacing
257 Sets the word spacing for the font.
259 Word spacing changes the default spacing between individual words.
260 A positive value increases the word spacing by a corresponding amount of pixels,
261 while a negative value decreases the inter-word spacing accordingly.
265 \qmlproperty enumeration QtQuick2::TextInput::font.capitalization
267 Sets the capitalization for the text.
270 \li Font.MixedCase - This is the normal text rendering option where no capitalization change is applied.
271 \li Font.AllUppercase - This alters the text to be rendered in all uppercase type.
272 \li Font.AllLowercase - This alters the text to be rendered in all lowercase type.
273 \li Font.SmallCaps - This alters the text to be rendered in small-caps type.
274 \li Font.Capitalize - This alters the text to be rendered with the first character of each word as an uppercase character.
278 TextInput { text: "Hello"; font.capitalization: Font.AllLowercase }
282 QFont QQuickTextInput::font() const
284 Q_D(const QQuickTextInput);
285 return d->sourceFont;
288 void QQuickTextInput::setFont(const QFont &font)
290 Q_D(QQuickTextInput);
291 if (d->sourceFont == font)
294 d->sourceFont = font;
295 QFont oldFont = d->font;
297 if (d->font.pointSizeF() != -1) {
299 qreal size = qRound(d->font.pointSizeF()*2.0);
300 d->font.setPointSizeF(size/2.0);
302 if (oldFont != d->font) {
304 updateCursorRectangle();
305 updateInputMethod(Qt::ImCursorRectangle | Qt::ImFont);
307 emit fontChanged(d->sourceFont);
311 \qmlproperty color QtQuick2::TextInput::color
315 QColor QQuickTextInput::color() const
317 Q_D(const QQuickTextInput);
321 void QQuickTextInput::setColor(const QColor &c)
323 Q_D(QQuickTextInput);
326 d->textLayoutDirty = true;
327 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
335 \qmlproperty color QtQuick2::TextInput::selectionColor
337 The text highlight color, used behind selections.
339 QColor QQuickTextInput::selectionColor() const
341 Q_D(const QQuickTextInput);
342 return d->selectionColor;
345 void QQuickTextInput::setSelectionColor(const QColor &color)
347 Q_D(QQuickTextInput);
348 if (d->selectionColor == color)
351 d->selectionColor = color;
352 if (d->hasSelectedText()) {
353 d->textLayoutDirty = true;
354 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
357 emit selectionColorChanged();
360 \qmlproperty color QtQuick2::TextInput::selectedTextColor
362 The highlighted text color, used in selections.
364 QColor QQuickTextInput::selectedTextColor() const
366 Q_D(const QQuickTextInput);
367 return d->selectedTextColor;
370 void QQuickTextInput::setSelectedTextColor(const QColor &color)
372 Q_D(QQuickTextInput);
373 if (d->selectedTextColor == color)
376 d->selectedTextColor = color;
377 if (d->hasSelectedText()) {
378 d->textLayoutDirty = true;
379 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
382 emit selectedTextColorChanged();
386 \qmlproperty enumeration QtQuick2::TextInput::horizontalAlignment
387 \qmlproperty enumeration QtQuick2::TextInput::effectiveHorizontalAlignment
388 \qmlproperty enumeration QtQuick2::TextInput::verticalAlignment
390 Sets the horizontal alignment of the text within the TextInput item's
391 width and height. By default, the text alignment follows the natural alignment
392 of the text, for example text that is read from left to right will be aligned to
395 TextInput does not have vertical alignment, as the natural height is
396 exactly the height of the single line of text. If you set the height
397 manually to something larger, TextInput will always be top aligned
398 vertically. You can use anchors to align it however you want within
401 The valid values for \c horizontalAlignment are \c TextInput.AlignLeft, \c TextInput.AlignRight and
402 \c TextInput.AlignHCenter.
404 Valid values for \c verticalAlignment are \c TextInput.AlignTop (default),
405 \c TextInput.AlignBottom \c TextInput.AlignVCenter.
407 When using the attached property LayoutMirroring::enabled to mirror application
408 layouts, the horizontal alignment of text will also be mirrored. However, the property
409 \c horizontalAlignment will remain unchanged. To query the effective horizontal alignment
410 of TextInput, use the read-only property \c effectiveHorizontalAlignment.
412 QQuickTextInput::HAlignment QQuickTextInput::hAlign() const
414 Q_D(const QQuickTextInput);
418 void QQuickTextInput::setHAlign(HAlignment align)
420 Q_D(QQuickTextInput);
421 bool forceAlign = d->hAlignImplicit && d->effectiveLayoutMirror;
422 d->hAlignImplicit = false;
423 if (d->setHAlign(align, forceAlign) && isComponentComplete()) {
425 updateCursorRectangle();
429 void QQuickTextInput::resetHAlign()
431 Q_D(QQuickTextInput);
432 d->hAlignImplicit = true;
433 if (d->determineHorizontalAlignment() && isComponentComplete()) {
435 updateCursorRectangle();
439 QQuickTextInput::HAlignment QQuickTextInput::effectiveHAlign() const
441 Q_D(const QQuickTextInput);
442 QQuickTextInput::HAlignment effectiveAlignment = d->hAlign;
443 if (!d->hAlignImplicit && d->effectiveLayoutMirror) {
445 case QQuickTextInput::AlignLeft:
446 effectiveAlignment = QQuickTextInput::AlignRight;
448 case QQuickTextInput::AlignRight:
449 effectiveAlignment = QQuickTextInput::AlignLeft;
455 return effectiveAlignment;
458 bool QQuickTextInputPrivate::setHAlign(QQuickTextInput::HAlignment alignment, bool forceAlign)
460 Q_Q(QQuickTextInput);
461 if ((hAlign != alignment || forceAlign) && alignment <= QQuickTextInput::AlignHCenter) { // justify not supported
462 QQuickTextInput::HAlignment oldEffectiveHAlign = q->effectiveHAlign();
464 emit q->horizontalAlignmentChanged(alignment);
465 if (oldEffectiveHAlign != q->effectiveHAlign())
466 emit q->effectiveHorizontalAlignmentChanged();
472 Qt::LayoutDirection QQuickTextInputPrivate::textDirection() const
474 QString text = m_text;
476 text = m_textLayout.preeditAreaText();
478 const QChar *character = text.constData();
479 while (!character->isNull()) {
480 switch (character->direction()) {
482 return Qt::LeftToRight;
486 return Qt::RightToLeft;
492 return Qt::LayoutDirectionAuto;
495 Qt::LayoutDirection QQuickTextInputPrivate::layoutDirection() const
497 Qt::LayoutDirection direction = m_layoutDirection;
498 if (direction == Qt::LayoutDirectionAuto) {
499 direction = textDirection();
500 if (direction == Qt::LayoutDirectionAuto)
501 direction = qApp->inputMethod()->inputDirection();
503 return (direction == Qt::LayoutDirectionAuto) ? Qt::LeftToRight : direction;
506 bool QQuickTextInputPrivate::determineHorizontalAlignment()
508 if (hAlignImplicit) {
509 // if no explicit alignment has been set, follow the natural layout direction of the text
510 Qt::LayoutDirection direction = textDirection();
511 if (direction == Qt::LayoutDirectionAuto)
512 direction = qApp->inputMethod()->inputDirection();
513 return setHAlign(direction == Qt::RightToLeft ? QQuickTextInput::AlignRight : QQuickTextInput::AlignLeft);
518 QQuickTextInput::VAlignment QQuickTextInput::vAlign() const
520 Q_D(const QQuickTextInput);
524 void QQuickTextInput::setVAlign(QQuickTextInput::VAlignment alignment)
526 Q_D(QQuickTextInput);
527 if (alignment == d->vAlign)
529 d->vAlign = alignment;
530 emit verticalAlignmentChanged(d->vAlign);
531 if (isComponentComplete()) {
532 updateCursorRectangle();
537 \qmlproperty enumeration QtQuick2::TextInput::wrapMode
539 Set this property to wrap the text to the TextInput item's width.
540 The text will only wrap if an explicit width has been set.
543 \li TextInput.NoWrap - no wrapping will be performed. If the text contains insufficient newlines, then implicitWidth will exceed a set width.
544 \li TextInput.WordWrap - wrapping is done on word boundaries only. If a word is too long, implicitWidth will exceed a set width.
545 \li TextInput.WrapAnywhere - wrapping is done at any point on a line, even if it occurs in the middle of a word.
546 \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.
549 The default is TextInput.NoWrap. If you set a width, consider using TextInput.Wrap.
551 QQuickTextInput::WrapMode QQuickTextInput::wrapMode() const
553 Q_D(const QQuickTextInput);
557 void QQuickTextInput::setWrapMode(WrapMode mode)
559 Q_D(QQuickTextInput);
560 if (mode == d->wrapMode)
564 updateCursorRectangle();
565 emit wrapModeChanged();
568 void QQuickTextInputPrivate::mirrorChange()
570 Q_Q(QQuickTextInput);
571 if (q->isComponentComplete()) {
572 if (!hAlignImplicit && (hAlign == QQuickTextInput::AlignRight || hAlign == QQuickTextInput::AlignLeft)) {
573 q->updateCursorRectangle();
574 emit q->effectiveHorizontalAlignmentChanged();
580 \qmlproperty bool QtQuick2::TextInput::readOnly
582 Sets whether user input can modify the contents of the TextInput.
584 If readOnly is set to true, then user input will not affect the text
585 property. Any bindings or attempts to set the text property will still
588 bool QQuickTextInput::isReadOnly() const
590 Q_D(const QQuickTextInput);
591 return d->m_readOnly;
594 void QQuickTextInput::setReadOnly(bool ro)
596 Q_D(QQuickTextInput);
597 if (d->m_readOnly == ro)
600 setFlag(QQuickItem::ItemAcceptsInputMethod, !ro);
603 d->setCursorPosition(d->end());
604 updateInputMethod(Qt::ImEnabled);
606 d->emitUndoRedoChanged();
607 emit readOnlyChanged(ro);
611 \qmlproperty int QtQuick2::TextInput::maximumLength
612 The maximum permitted length of the text in the TextInput.
614 If the text is too long, it is truncated at the limit.
616 By default, this property contains a value of 32767.
618 int QQuickTextInput::maxLength() const
620 Q_D(const QQuickTextInput);
621 return d->m_maxLength;
624 void QQuickTextInput::setMaxLength(int ml)
626 Q_D(QQuickTextInput);
627 if (d->m_maxLength == ml || d->m_maskData)
631 d->internalSetText(d->m_text, -1, false);
633 emit maximumLengthChanged(ml);
637 \qmlproperty bool QtQuick2::TextInput::cursorVisible
638 Set to true when the TextInput shows a cursor.
640 This property is set and unset when the TextInput gets active focus, so that other
641 properties can be bound to whether the cursor is currently showing. As it
642 gets set and unset automatically, when you set the value yourself you must
643 keep in mind that your value may be overwritten.
645 It can be set directly in script, for example if a KeyProxy might
646 forward keys to it and you desire it to look active when this happens
647 (but without actually giving it active focus).
649 It should not be set directly on the element, like in the below QML,
650 as the specified value will be overridden an lost on focus changes.
659 In the above snippet the cursor will still become visible when the
660 TextInput gains active focus.
662 bool QQuickTextInput::isCursorVisible() const
664 Q_D(const QQuickTextInput);
665 return d->cursorVisible;
668 void QQuickTextInput::setCursorVisible(bool on)
670 Q_D(QQuickTextInput);
671 if (d->cursorVisible == on)
673 d->cursorVisible = on;
674 if (on && isComponentComplete())
675 QQuickTextUtil::createCursor(d);
676 if (!d->cursorItem) {
677 d->setCursorBlinkPeriod(on ? qApp->styleHints()->cursorFlashTime() : 0);
678 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
681 emit cursorVisibleChanged(d->cursorVisible);
685 \qmlproperty int QtQuick2::TextInput::cursorPosition
686 The position of the cursor in the TextInput.
688 int QQuickTextInput::cursorPosition() const
690 Q_D(const QQuickTextInput);
694 void QQuickTextInput::setCursorPosition(int cp)
696 Q_D(QQuickTextInput);
697 if (cp < 0 || cp > text().length())
703 \qmlproperty rectangle QtQuick2::TextInput::cursorRectangle
705 The rectangle where the standard text cursor is rendered within the text input. Read only.
707 The position and height of a custom cursorDelegate are updated to follow the cursorRectangle
708 automatically when it changes. The width of the delegate is unaffected by changes in the
712 QRectF QQuickTextInput::cursorRectangle() const
714 Q_D(const QQuickTextInput);
716 int c = d->m_cursor + d->m_preeditCursor;
717 if (d->m_echoMode == NoEcho)
719 QTextLine l = d->m_textLayout.lineForTextPosition(c);
722 return QRectF(l.cursorToX(c) - d->hscroll, l.y() - d->vscroll, 1, l.height());
726 \qmlproperty int QtQuick2::TextInput::selectionStart
728 The cursor position before the first character in the current selection.
730 This property is read-only. To change the selection, use select(start,end),
731 selectAll(), or selectWord().
733 \sa selectionEnd, cursorPosition, selectedText
735 int QQuickTextInput::selectionStart() const
737 Q_D(const QQuickTextInput);
738 return d->lastSelectionStart;
741 \qmlproperty int QtQuick2::TextInput::selectionEnd
743 The cursor position after the last character in the current selection.
745 This property is read-only. To change the selection, use select(start,end),
746 selectAll(), or selectWord().
748 \sa selectionStart, cursorPosition, selectedText
750 int QQuickTextInput::selectionEnd() const
752 Q_D(const QQuickTextInput);
753 return d->lastSelectionEnd;
756 \qmlmethod void QtQuick2::TextInput::select(int start, int end)
758 Causes the text from \a start to \a end to be selected.
760 If either start or end is out of range, the selection is not changed.
762 After calling this, selectionStart will become the lesser
763 and selectionEnd will become the greater (regardless of the order passed
766 \sa selectionStart, selectionEnd
768 void QQuickTextInput::select(int start, int end)
770 Q_D(QQuickTextInput);
771 if (start < 0 || end < 0 || start > d->m_text.length() || end > d->m_text.length())
773 d->setSelection(start, end-start);
777 \qmlproperty string QtQuick2::TextInput::selectedText
779 This read-only property provides the text currently selected in the
782 It is equivalent to the following snippet, but is faster and easier
786 myTextInput.text.toString().substring(myTextInput.selectionStart,
787 myTextInput.selectionEnd);
790 QString QQuickTextInput::selectedText() const
792 Q_D(const QQuickTextInput);
793 return d->selectedText();
797 \qmlproperty bool QtQuick2::TextInput::activeFocusOnPress
799 Whether the TextInput should gain active focus on a mouse press. By default this is
802 bool QQuickTextInput::focusOnPress() const
804 Q_D(const QQuickTextInput);
805 return d->focusOnPress;
808 void QQuickTextInput::setFocusOnPress(bool b)
810 Q_D(QQuickTextInput);
811 if (d->focusOnPress == b)
816 emit activeFocusOnPressChanged(d->focusOnPress);
819 \qmlproperty bool QtQuick2::TextInput::autoScroll
821 Whether the TextInput should scroll when the text is longer than the width. By default this is
824 bool QQuickTextInput::autoScroll() const
826 Q_D(const QQuickTextInput);
827 return d->autoScroll;
830 void QQuickTextInput::setAutoScroll(bool b)
832 Q_D(QQuickTextInput);
833 if (d->autoScroll == b)
837 //We need to repaint so that the scrolling is taking into account.
838 updateCursorRectangle();
839 emit autoScrollChanged(d->autoScroll);
842 #ifndef QT_NO_VALIDATOR
845 \qmlclass IntValidator QIntValidator
846 \inqmlmodule QtQuick 2
847 \ingroup qml-basic-visual-elements
849 This element provides a validator for integer values.
851 If no \l locale is set IntValidator uses the \l {QLocale::setDefault()}{default locale} to
852 interpret the number and will accept locale specific digits, group separators, and positive
853 and negative signs. In addition, IntValidator is always guaranteed to accept a number
854 formatted according to the "C" locale.
858 QQuickIntValidator::QQuickIntValidator(QObject *parent)
859 : QIntValidator(parent)
864 \qmlproperty string QtQuick2::IntValidator::locale
866 This property holds the name of the locale used to interpret the number.
871 QString QQuickIntValidator::localeName() const
873 return locale().name();
876 void QQuickIntValidator::setLocaleName(const QString &name)
878 if (locale().name() != name) {
879 setLocale(QLocale(name));
880 emit localeNameChanged();
884 void QQuickIntValidator::resetLocaleName()
886 QLocale defaultLocale;
887 if (locale() != defaultLocale) {
888 setLocale(defaultLocale);
889 emit localeNameChanged();
894 \qmlproperty int QtQuick2::IntValidator::top
896 This property holds the validator's highest acceptable value.
897 By default, this property's value is derived from the highest signed integer available (typically 2147483647).
900 \qmlproperty int QtQuick2::IntValidator::bottom
902 This property holds the validator's lowest acceptable value.
903 By default, this property's value is derived from the lowest signed integer available (typically -2147483647).
907 \qmlclass DoubleValidator QDoubleValidator
908 \inqmlmodule QtQuick 2
909 \ingroup qml-basic-visual-elements
911 This element provides a validator for non-integer numbers.
913 Input is accepted if it contains a double that is within the valid range
914 and is in the correct format.
916 Input is accepected but invalid if it contains a double that is outside
917 the range or is in the wrong format; e.g. with too many digits after the
918 decimal point or is empty.
920 Input is rejected if it is not a double.
922 Note: If the valid range consists of just positive doubles (e.g. 0.0 to
923 100.0) and input is a negative double then it is rejected. If \l notation
924 is set to DoubleValidator.StandardNotation, and the input contains more
925 digits before the decimal point than a double in the valid range may have,
926 it is also rejected. If \l notation is DoubleValidator.ScientificNotation,
927 and the input is not in the valid range, it is accecpted but invalid. The
928 value may yet become valid by changing the exponent.
931 QQuickDoubleValidator::QQuickDoubleValidator(QObject *parent)
932 : QDoubleValidator(parent)
937 \qmlproperty string QtQuick2::DoubleValidator::locale
939 This property holds the name of the locale used to interpret the number.
944 QString QQuickDoubleValidator::localeName() const
946 return locale().name();
949 void QQuickDoubleValidator::setLocaleName(const QString &name)
951 if (locale().name() != name) {
952 setLocale(QLocale(name));
953 emit localeNameChanged();
957 void QQuickDoubleValidator::resetLocaleName()
959 QLocale defaultLocale;
960 if (locale() != defaultLocale) {
961 setLocale(defaultLocale);
962 emit localeNameChanged();
967 \qmlproperty real QtQuick2::DoubleValidator::top
969 This property holds the validator's maximum acceptable value.
970 By default, this property contains a value of infinity.
973 \qmlproperty real QtQuick2::DoubleValidator::bottom
975 This property holds the validator's minimum acceptable value.
976 By default, this property contains a value of -infinity.
979 \qmlproperty int QtQuick2::DoubleValidator::decimals
981 This property holds the validator's maximum number of digits after the decimal point.
982 By default, this property contains a value of 1000.
985 \qmlproperty enumeration QtQuick2::DoubleValidator::notation
986 This property holds the notation of how a string can describe a number.
988 The possible values for this property are:
991 \li DoubleValidator.StandardNotation
992 \li DoubleValidator.ScientificNotation (default)
995 If this property is set to DoubleValidator.ScientificNotation, the written number may have an exponent part (e.g. 1.5E-2).
999 \qmlclass RegExpValidator QRegExpValidator
1000 \inqmlmodule QtQuick 2
1001 \ingroup qml-basic-visual-elements
1003 This element provides a validator, which counts as valid any string which
1004 matches a specified regular expression.
1007 \qmlproperty regExp QtQuick2::RegExpValidator::regExp
1009 This property holds the regular expression used for validation.
1011 Note that this property should be a regular expression in JS syntax, e.g /a/ for the regular expression
1014 By default, this property contains a regular expression with the pattern .* that matches any string.
1018 \qmlproperty Validator QtQuick2::TextInput::validator
1020 Allows you to set a validator on the TextInput. When a validator is set
1021 the TextInput will only accept input which leaves the text property in
1022 an acceptable or intermediate state. The accepted signal will only be sent
1023 if the text is in an acceptable state when enter is pressed.
1025 Currently supported validators are IntValidator, DoubleValidator and
1026 RegExpValidator. An example of using validators is shown below, which allows
1027 input of integers between 11 and 31 into the text input:
1032 validator: IntValidator{bottom: 11; top: 31;}
1037 \sa acceptableInput, inputMask
1040 QValidator* QQuickTextInput::validator() const
1042 Q_D(const QQuickTextInput);
1043 return d->m_validator;
1046 void QQuickTextInput::setValidator(QValidator* v)
1048 Q_D(QQuickTextInput);
1049 if (d->m_validator == v)
1054 if (isComponentComplete())
1057 emit validatorChanged();
1060 #endif // QT_NO_VALIDATOR
1062 void QQuickTextInputPrivate::checkIsValid()
1064 Q_Q(QQuickTextInput);
1066 ValidatorState state = hasAcceptableInput(m_text);
1067 m_validInput = state != InvalidInput;
1068 if (state != AcceptableInput) {
1069 if (m_acceptableInput) {
1070 m_acceptableInput = false;
1071 emit q->acceptableInputChanged();
1073 } else if (!m_acceptableInput) {
1074 m_acceptableInput = true;
1075 emit q->acceptableInputChanged();
1080 \qmlproperty string QtQuick2::TextInput::inputMask
1082 Allows you to set an input mask on the TextInput, restricting the allowable
1083 text inputs. See QLineEdit::inputMask for further details, as the exact
1084 same mask strings are used by TextInput.
1086 \sa acceptableInput, validator
1088 QString QQuickTextInput::inputMask() const
1090 Q_D(const QQuickTextInput);
1091 return d->inputMask();
1094 void QQuickTextInput::setInputMask(const QString &im)
1096 Q_D(QQuickTextInput);
1097 if (d->inputMask() == im)
1100 d->setInputMask(im);
1101 emit inputMaskChanged(d->inputMask());
1105 \qmlproperty bool QtQuick2::TextInput::acceptableInput
1107 This property is always true unless a validator or input mask has been set.
1108 If a validator or input mask has been set, this property will only be true
1109 if the current text is acceptable to the validator or input mask as a final
1110 string (not as an intermediate string).
1112 bool QQuickTextInput::hasAcceptableInput() const
1114 Q_D(const QQuickTextInput);
1115 return d->hasAcceptableInput(d->m_text) == QQuickTextInputPrivate::AcceptableInput;
1119 \qmlsignal QtQuick2::TextInput::onAccepted()
1121 This handler is called when the Return or Enter key is pressed.
1122 Note that if there is a \l validator or \l inputMask set on the text
1123 input, the handler will only be emitted if the input is in an acceptable
1127 Qt::InputMethodHints QQuickTextInputPrivate::effectiveInputMethodHints() const
1129 Qt::InputMethodHints hints = inputMethodHints;
1130 if (m_echoMode == QQuickTextInput::Password || m_echoMode == QQuickTextInput::NoEcho)
1131 hints |= Qt::ImhHiddenText;
1132 else if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit)
1133 hints &= ~Qt::ImhHiddenText;
1134 if (m_echoMode != QQuickTextInput::Normal)
1135 hints |= (Qt::ImhNoAutoUppercase | Qt::ImhNoPredictiveText | Qt::ImhSensitiveData);
1139 \qmlproperty enumeration QtQuick2::TextInput::echoMode
1141 Specifies how the text should be displayed in the TextInput.
1143 \li TextInput.Normal - Displays the text as it is. (Default)
1144 \li TextInput.Password - Displays asterisks instead of characters.
1145 \li TextInput.NoEcho - Displays nothing.
1146 \li TextInput.PasswordEchoOnEdit - Displays characters as they are entered
1147 while editing, otherwise displays asterisks.
1150 QQuickTextInput::EchoMode QQuickTextInput::echoMode() const
1152 Q_D(const QQuickTextInput);
1153 return QQuickTextInput::EchoMode(d->m_echoMode);
1156 void QQuickTextInput::setEchoMode(QQuickTextInput::EchoMode echo)
1158 Q_D(QQuickTextInput);
1159 if (echoMode() == echo)
1161 d->cancelPasswordEchoTimer();
1162 d->m_echoMode = echo;
1163 d->m_passwordEchoEditing = false;
1164 updateInputMethod(Qt::ImHints);
1165 d->updateDisplayText();
1166 updateCursorRectangle();
1168 emit echoModeChanged(echoMode());
1172 \qmlproperty enumeration QtQuick2::TextInput::inputMethodHints
1174 Provides hints to the input method about the expected content of the text input and how it
1177 The value is a bit-wise combination of flags, or Qt.ImhNone if no hints are set.
1179 Flags that alter behaviour are:
1182 \li Qt.ImhHiddenText - Characters should be hidden, as is typically used when entering passwords.
1183 This is automatically set when setting echoMode to \c TextInput.Password.
1184 \li Qt.ImhSensitiveData - Typed text should not be stored by the active input method
1185 in any persistent storage like predictive user dictionary.
1186 \li Qt.ImhNoAutoUppercase - The input method should not try to automatically switch to upper case
1187 when a sentence ends.
1188 \li Qt.ImhPreferNumbers - Numbers are preferred (but not required).
1189 \li Qt.ImhPreferUppercase - Upper case letters are preferred (but not required).
1190 \li Qt.ImhPreferLowercase - Lower case letters are preferred (but not required).
1191 \li Qt.ImhNoPredictiveText - Do not use predictive text (i.e. dictionary lookup) while typing.
1193 \li Qt.ImhDate - The text editor functions as a date field.
1194 \li Qt.ImhTime - The text editor functions as a time field.
1197 Flags that restrict input (exclusive flags) are:
1200 \li Qt.ImhDigitsOnly - Only digits are allowed.
1201 \li Qt.ImhFormattedNumbersOnly - Only number input is allowed. This includes decimal point and minus sign.
1202 \li Qt.ImhUppercaseOnly - Only upper case letter input is allowed.
1203 \li Qt.ImhLowercaseOnly - Only lower case letter input is allowed.
1204 \li Qt.ImhDialableCharactersOnly - Only characters suitable for phone dialing are allowed.
1205 \li Qt.ImhEmailCharactersOnly - Only characters suitable for email addresses are allowed.
1206 \li Qt.ImhUrlCharactersOnly - Only characters suitable for URLs are allowed.
1212 \li Qt.ImhExclusiveInputMask - This mask yields nonzero if any of the exclusive flags are used.
1216 Qt::InputMethodHints QQuickTextInput::inputMethodHints() const
1218 Q_D(const QQuickTextInput);
1219 return d->inputMethodHints;
1222 void QQuickTextInput::setInputMethodHints(Qt::InputMethodHints hints)
1224 Q_D(QQuickTextInput);
1226 if (hints == d->inputMethodHints)
1229 d->inputMethodHints = hints;
1230 updateInputMethod(Qt::ImHints);
1231 emit inputMethodHintsChanged();
1235 \qmlproperty Component QtQuick2::TextInput::cursorDelegate
1236 The delegate for the cursor in the TextInput.
1238 If you set a cursorDelegate for a TextInput, this delegate will be used for
1239 drawing the cursor instead of the standard cursor. An instance of the
1240 delegate will be created and managed by the TextInput when a cursor is
1241 needed, and the x property of delegate instance will be set so as
1242 to be one pixel before the top left of the current character.
1244 Note that the root item of the delegate component must be a QQuickItem or
1245 QQuickItem derived item.
1247 QQmlComponent* QQuickTextInput::cursorDelegate() const
1249 Q_D(const QQuickTextInput);
1250 return d->cursorComponent;
1253 void QQuickTextInput::setCursorDelegate(QQmlComponent* c)
1255 Q_D(QQuickTextInput);
1256 QQuickTextUtil::setCursorDelegate(d, c);
1259 void QQuickTextInput::createCursor()
1261 Q_D(QQuickTextInput);
1262 d->cursorPending = true;
1263 QQuickTextUtil::createCursor(d);
1267 \qmlmethod rect QtQuick2::TextInput::positionToRectangle(int pos)
1269 This function takes a character position and returns the rectangle that the
1270 cursor would occupy, if it was placed at that character position.
1272 This is similar to setting the cursorPosition, and then querying the cursor
1273 rectangle, but the cursorPosition is not changed.
1275 QRectF QQuickTextInput::positionToRectangle(int pos) const
1277 Q_D(const QQuickTextInput);
1278 if (d->m_echoMode == NoEcho)
1280 else if (pos > d->m_cursor)
1281 pos += d->preeditAreaText().length();
1282 QTextLine l = d->m_textLayout.lineForTextPosition(pos);
1284 ? QRectF(l.cursorToX(pos) - d->hscroll, l.y() - d->vscroll, 1, l.height())
1289 \qmlmethod int QtQuick2::TextInput::positionAt(real x, real y, CursorPosition position = CursorBetweenCharacters)
1291 This function returns the character position at
1292 x and y pixels from the top left of the textInput. Position 0 is before the
1293 first character, position 1 is after the first character but before the second,
1294 and so on until position text.length, which is after all characters.
1296 This means that for all x values before the first character this function returns 0,
1297 and for all x values after the last character this function returns text.length. If
1298 the y value is above the text the position will be that of the nearest character on
1299 the first line line and if it is below the text the position of the nearest character
1300 on the last line will be returned.
1302 The cursor position type specifies how the cursor position should be resolved.
1305 \li TextInput.CursorBetweenCharacters - Returns the position between characters that is nearest x.
1306 \li TextInput.CursorOnCharacter - Returns the position before the character that is nearest x.
1310 void QQuickTextInput::positionAt(QQmlV8Function *args) const
1312 Q_D(const QQuickTextInput);
1316 QTextLine::CursorPosition position = QTextLine::CursorBetweenCharacters;
1318 if (args->Length() < 1)
1322 v8::Local<v8::Value> arg = (*args)[i];
1323 x = arg->NumberValue();
1325 if (++i < args->Length()) {
1327 y = arg->NumberValue();
1330 if (++i < args->Length()) {
1332 position = QTextLine::CursorPosition(arg->Int32Value());
1335 int pos = d->positionAt(x, y, position);
1336 const int cursor = d->m_cursor;
1338 const int preeditLength = d->preeditAreaText().length();
1339 pos = pos > cursor + preeditLength
1340 ? pos - preeditLength
1343 args->returnValue(v8::Int32::New(pos));
1346 int QQuickTextInputPrivate::positionAt(qreal x, qreal y, QTextLine::CursorPosition position) const
1350 QTextLine line = m_textLayout.lineAt(0);
1351 for (int i = 1; i < m_textLayout.lineCount(); ++i) {
1352 QTextLine nextLine = m_textLayout.lineAt(i);
1354 if (y < (line.rect().bottom() + nextLine.y()) / 2)
1358 return line.isValid() ? line.xToCursor(x, position) : 0;
1361 void QQuickTextInput::keyPressEvent(QKeyEvent* ev)
1363 Q_D(QQuickTextInput);
1364 // Don't allow MacOSX up/down support, and we don't allow a completer.
1365 bool ignore = (ev->key() == Qt::Key_Up || ev->key() == Qt::Key_Down) && ev->modifiers() == Qt::NoModifier;
1366 if (!ignore && (d->lastSelectionStart == d->lastSelectionEnd) && (ev->key() == Qt::Key_Right || ev->key() == Qt::Key_Left)) {
1367 // Ignore when moving off the end unless there is a selection,
1368 // because then moving will do something (deselect).
1369 int cursorPosition = d->m_cursor;
1370 if (cursorPosition == 0)
1371 ignore = ev->key() == (d->layoutDirection() == Qt::LeftToRight ? Qt::Key_Left : Qt::Key_Right);
1372 if (!ignore && cursorPosition == text().length())
1373 ignore = ev->key() == (d->layoutDirection() == Qt::LeftToRight ? Qt::Key_Right : Qt::Key_Left);
1378 d->processKeyEvent(ev);
1380 if (!ev->isAccepted())
1381 QQuickImplicitSizeItem::keyPressEvent(ev);
1384 void QQuickTextInput::inputMethodEvent(QInputMethodEvent *ev)
1386 Q_D(QQuickTextInput);
1387 const bool wasComposing = d->hasImState;
1388 if (d->m_readOnly) {
1391 d->processInputMethodEvent(ev);
1393 if (!ev->isAccepted())
1394 QQuickImplicitSizeItem::inputMethodEvent(ev);
1396 if (wasComposing != d->hasImState)
1397 emit inputMethodComposingChanged();
1400 void QQuickTextInput::mouseDoubleClickEvent(QMouseEvent *event)
1402 Q_D(QQuickTextInput);
1404 if (d->selectByMouse && event->button() == Qt::LeftButton) {
1406 int cursor = d->positionAt(event->localPos());
1407 d->selectWordAtPos(cursor);
1408 event->setAccepted(true);
1409 if (!d->hasPendingTripleClick()) {
1410 d->tripleClickStartPoint = event->localPos();
1411 d->tripleClickTimer.start();
1414 if (d->sendMouseEventToInputContext(event))
1416 QQuickImplicitSizeItem::mouseDoubleClickEvent(event);
1420 void QQuickTextInput::mousePressEvent(QMouseEvent *event)
1422 Q_D(QQuickTextInput);
1424 d->pressPos = event->localPos();
1426 if (d->sendMouseEventToInputContext(event))
1429 if (d->selectByMouse) {
1430 setKeepMouseGrab(false);
1431 d->selectPressed = true;
1432 QPointF distanceVector = d->pressPos - d->tripleClickStartPoint;
1433 if (d->hasPendingTripleClick()
1434 && distanceVector.manhattanLength() < qApp->styleHints()->startDragDistance()) {
1435 event->setAccepted(true);
1441 bool mark = (event->modifiers() & Qt::ShiftModifier) && d->selectByMouse;
1442 int cursor = d->positionAt(event->localPos());
1443 d->moveCursor(cursor, mark);
1445 if (d->focusOnPress) {
1446 bool hadActiveFocus = hasActiveFocus();
1448 // re-open input panel on press if already focused
1449 if (hasActiveFocus() && hadActiveFocus && !d->m_readOnly)
1450 openSoftwareInputPanel();
1453 event->setAccepted(true);
1456 void QQuickTextInput::mouseMoveEvent(QMouseEvent *event)
1458 Q_D(QQuickTextInput);
1460 if (d->selectPressed) {
1461 if (qAbs(int(event->localPos().x() - d->pressPos.x())) > qApp->styleHints()->startDragDistance())
1462 setKeepMouseGrab(true);
1464 if (d->composeMode()) {
1466 int startPos = d->positionAt(d->pressPos);
1467 int currentPos = d->positionAt(event->localPos());
1468 if (startPos != currentPos)
1469 d->setSelection(startPos, currentPos - startPos);
1471 moveCursorSelection(d->positionAt(event->localPos()), d->mouseSelectionMode);
1473 event->setAccepted(true);
1475 QQuickImplicitSizeItem::mouseMoveEvent(event);
1479 void QQuickTextInput::mouseReleaseEvent(QMouseEvent *event)
1481 Q_D(QQuickTextInput);
1482 if (d->sendMouseEventToInputContext(event))
1484 if (d->selectPressed) {
1485 d->selectPressed = false;
1486 setKeepMouseGrab(false);
1488 #ifndef QT_NO_CLIPBOARD
1489 if (QGuiApplication::clipboard()->supportsSelection()) {
1490 if (event->button() == Qt::LeftButton) {
1491 d->copy(QClipboard::Selection);
1492 } else if (!d->m_readOnly && event->button() == Qt::MidButton) {
1494 d->insert(QGuiApplication::clipboard()->text(QClipboard::Selection));
1498 if (!event->isAccepted())
1499 QQuickImplicitSizeItem::mouseReleaseEvent(event);
1502 bool QQuickTextInputPrivate::sendMouseEventToInputContext(QMouseEvent *event)
1504 #if !defined QT_NO_IM
1505 if (composeMode()) {
1506 int tmp_cursor = positionAt(event->localPos());
1507 int mousePos = tmp_cursor - m_cursor;
1508 if (mousePos >= 0 && mousePos <= m_textLayout.preeditAreaText().length()) {
1509 if (event->type() == QEvent::MouseButtonRelease) {
1510 qApp->inputMethod()->invokeAction(QInputMethod::Click, mousePos);
1523 void QQuickTextInput::mouseUngrabEvent()
1525 Q_D(QQuickTextInput);
1526 d->selectPressed = false;
1527 setKeepMouseGrab(false);
1530 bool QQuickTextInput::event(QEvent* ev)
1532 #ifndef QT_NO_SHORTCUT
1533 Q_D(QQuickTextInput);
1534 if (ev->type() == QEvent::ShortcutOverride) {
1537 QKeyEvent* ke = static_cast<QKeyEvent*>(ev);
1538 if (ke == QKeySequence::Copy
1539 || ke == QKeySequence::Paste
1540 || ke == QKeySequence::Cut
1541 || ke == QKeySequence::Redo
1542 || ke == QKeySequence::Undo
1543 || ke == QKeySequence::MoveToNextWord
1544 || ke == QKeySequence::MoveToPreviousWord
1545 || ke == QKeySequence::MoveToStartOfDocument
1546 || ke == QKeySequence::MoveToEndOfDocument
1547 || ke == QKeySequence::SelectNextWord
1548 || ke == QKeySequence::SelectPreviousWord
1549 || ke == QKeySequence::SelectStartOfLine
1550 || ke == QKeySequence::SelectEndOfLine
1551 || ke == QKeySequence::SelectStartOfBlock
1552 || ke == QKeySequence::SelectEndOfBlock
1553 || ke == QKeySequence::SelectStartOfDocument
1554 || ke == QKeySequence::SelectAll
1555 || ke == QKeySequence::SelectEndOfDocument) {
1557 } else if (ke->modifiers() == Qt::NoModifier || ke->modifiers() == Qt::ShiftModifier
1558 || ke->modifiers() == Qt::KeypadModifier) {
1559 if (ke->key() < Qt::Key_Escape) {
1563 switch (ke->key()) {
1564 case Qt::Key_Delete:
1567 case Qt::Key_Backspace:
1579 return QQuickImplicitSizeItem::event(ev);
1582 void QQuickTextInput::geometryChanged(const QRectF &newGeometry,
1583 const QRectF &oldGeometry)
1585 Q_D(QQuickTextInput);
1587 if (newGeometry.width() != oldGeometry.width() && d->wrapMode != NoWrap)
1589 updateCursorRectangle();
1591 QQuickImplicitSizeItem::geometryChanged(newGeometry, oldGeometry);
1594 void QQuickTextInputPrivate::updateHorizontalScroll()
1596 Q_Q(QQuickTextInput);
1597 QTextLine currentLine = m_textLayout.lineForTextPosition(m_cursor + m_preeditCursor);
1598 const int preeditLength = m_textLayout.preeditAreaText().length();
1599 const qreal width = qMax<qreal>(0, q->width());
1601 qreal widthUsed = 0;
1602 if (currentLine.isValid()) {
1603 cix = currentLine.cursorToX(m_cursor + preeditLength);
1604 const qreal cursorWidth = cix >= 0 ? cix : width - cix;
1605 widthUsed = qMax(currentLine.naturalTextWidth(), cursorWidth);
1607 int previousScroll = hscroll;
1609 if (!autoScroll || widthUsed <= width || m_echoMode == QQuickTextInput::NoEcho) {
1612 Q_ASSERT(currentLine.isValid());
1613 if (cix - hscroll >= width) {
1614 // text doesn't fit, cursor is to the right of br (scroll right)
1615 hscroll = cix - width;
1616 } else if (cix - hscroll < 0 && hscroll < widthUsed) {
1617 // text doesn't fit, cursor is to the left of br (scroll left)
1619 } else if (widthUsed - hscroll < width) {
1620 // text doesn't fit, text document is to the left of br; align
1622 hscroll = widthUsed - width;
1623 } else if (width - hscroll > widthUsed) {
1624 // text doesn't fit, text document is to the right of br; align
1626 hscroll = width - widthUsed;
1628 if (preeditLength > 0) {
1629 // check to ensure long pre-edit text doesn't push the cursor
1631 cix = currentLine.cursorToX(m_cursor + qMax(0, m_preeditCursor - 1));
1636 if (previousScroll != hscroll)
1637 textLayoutDirty = true;
1640 void QQuickTextInputPrivate::updateVerticalScroll()
1642 Q_Q(QQuickTextInput);
1643 const int preeditLength = m_textLayout.preeditAreaText().length();
1644 const qreal height = qMax<qreal>(0, q->height());
1645 qreal heightUsed = contentSize.height();
1646 qreal previousScroll = vscroll;
1648 if (!autoScroll || heightUsed <= height) {
1649 // text fits in br; use vscroll for alignment
1650 switch (vAlign & ~(Qt::AlignAbsolute|Qt::AlignHorizontal_Mask)) {
1651 case Qt::AlignBottom:
1652 vscroll = heightUsed - height;
1654 case Qt::AlignVCenter:
1655 vscroll = (heightUsed - height) / 2;
1663 QTextLine currentLine = m_textLayout.lineForTextPosition(m_cursor + preeditLength);
1664 QRectF r = currentLine.isValid() ? currentLine.rect() : QRectF();
1665 qreal top = r.top();
1666 int bottom = r.bottom();
1668 if (bottom - vscroll >= height) {
1669 // text doesn't fit, cursor is to the below the br (scroll down)
1670 vscroll = bottom - height;
1671 } else if (top - vscroll < 0 && vscroll < heightUsed) {
1672 // text doesn't fit, cursor is above br (scroll up)
1674 } else if (heightUsed - vscroll < height) {
1675 // text doesn't fit, text document is to the left of br; align
1677 vscroll = heightUsed - height;
1679 if (preeditLength > 0) {
1680 // check to ensure long pre-edit text doesn't push the cursor
1682 currentLine = m_textLayout.lineForTextPosition(m_cursor + qMax(0, m_preeditCursor - 1));
1683 top = currentLine.isValid() ? currentLine.rect().top() : 0;
1688 if (previousScroll != vscroll)
1689 textLayoutDirty = true;
1692 void QQuickTextInput::triggerPreprocess()
1694 Q_D(QQuickTextInput);
1695 if (d->updateType == QQuickTextInputPrivate::UpdateNone)
1696 d->updateType = QQuickTextInputPrivate::UpdateOnlyPreprocess;
1700 QSGNode *QQuickTextInput::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data)
1703 Q_D(QQuickTextInput);
1705 if (d->updateType != QQuickTextInputPrivate::UpdatePaintNode && oldNode != 0) {
1706 // Update done in preprocess() in the nodes
1707 d->updateType = QQuickTextInputPrivate::UpdateNone;
1711 d->updateType = QQuickTextInputPrivate::UpdateNone;
1713 QQuickTextNode *node = static_cast<QQuickTextNode *>(oldNode);
1715 node = new QQuickTextNode(QQuickItemPrivate::get(this)->sceneGraphContext(), this);
1718 if (!d->textLayoutDirty && oldNode != 0) {
1719 QSGSimpleRectNode *cursorNode = node->cursorNode();
1720 if (cursorNode != 0 && !isReadOnly()) {
1721 cursorNode->setRect(cursorRectangle());
1723 if (!d->cursorVisible || (!d->m_blinkStatus && d->m_blinkPeriod > 0)) {
1730 node->deleteContent();
1731 node->setMatrix(QMatrix4x4());
1733 QPointF offset(0, 0);
1734 if (d->autoScroll && d->m_textLayout.lineCount() > 0) {
1735 QFontMetricsF fm(d->font);
1736 // the y offset is there to keep the baseline constant in case we have script changes in the text.
1737 offset = -QPoint(d->hscroll, d->vscroll + d->m_textLayout.lineAt(0).ascent() - fm.ascent());
1739 offset = -QPoint(d->hscroll, d->vscroll);
1742 if (!d->m_textLayout.text().isEmpty() || !d->m_textLayout.preeditAreaText().isEmpty()) {
1743 node->addTextLayout(offset, &d->m_textLayout, d->color,
1744 QQuickText::Normal, QColor(), QColor(),
1745 d->selectionColor, d->selectedTextColor,
1746 d->selectionStart(),
1747 d->selectionEnd() - 1); // selectionEnd() returns first char after
1751 if (!isReadOnly() && d->cursorItem == 0) {
1752 node->setCursor(cursorRectangle(), d->color);
1753 if (!d->cursorVisible || (!d->m_blinkStatus && d->m_blinkPeriod > 0)) {
1760 d->textLayoutDirty = false;
1766 QVariant QQuickTextInput::inputMethodQuery(Qt::InputMethodQuery property) const
1768 Q_D(const QQuickTextInput);
1771 return QVariant((bool)(flags() & ItemAcceptsInputMethod));
1773 return QVariant((int) d->effectiveInputMethodHints());
1774 case Qt::ImCursorRectangle:
1775 return cursorRectangle();
1778 case Qt::ImCursorPosition:
1779 return QVariant(d->m_cursor);
1780 case Qt::ImSurroundingText:
1781 if (d->m_echoMode == PasswordEchoOnEdit && !d->m_passwordEchoEditing) {
1782 return QVariant(displayText());
1784 return QVariant(d->realText());
1786 case Qt::ImCurrentSelection:
1787 return QVariant(selectedText());
1788 case Qt::ImMaximumTextLength:
1789 return QVariant(maxLength());
1790 case Qt::ImAnchorPosition:
1791 if (d->selectionStart() == d->selectionEnd())
1792 return QVariant(d->m_cursor);
1793 else if (d->selectionStart() == d->m_cursor)
1794 return QVariant(d->selectionEnd());
1796 return QVariant(d->selectionStart());
1803 \qmlmethod void QtQuick2::TextInput::deselect()
1805 Removes active text selection.
1807 void QQuickTextInput::deselect()
1809 Q_D(QQuickTextInput);
1814 \qmlmethod void QtQuick2::TextInput::selectAll()
1816 Causes all text to be selected.
1818 void QQuickTextInput::selectAll()
1820 Q_D(QQuickTextInput);
1821 d->setSelection(0, text().length());
1825 \qmlmethod void QtQuick2::TextInput::isRightToLeft(int start, int end)
1827 Returns true if the natural reading direction of the editor text
1828 found between positions \a start and \a end is right to left.
1830 bool QQuickTextInput::isRightToLeft(int start, int end)
1833 qmlInfo(this) << "isRightToLeft(start, end) called with the end property being smaller than the start.";
1836 return text().mid(start, end - start).isRightToLeft();
1840 #ifndef QT_NO_CLIPBOARD
1842 \qmlmethod QtQuick2::TextInput::cut()
1844 Moves the currently selected text to the system clipboard.
1846 void QQuickTextInput::cut()
1848 Q_D(QQuickTextInput);
1854 \qmlmethod QtQuick2::TextInput::copy()
1856 Copies the currently selected text to the system clipboard.
1858 void QQuickTextInput::copy()
1860 Q_D(QQuickTextInput);
1865 \qmlmethod QtQuick2::TextInput::paste()
1867 Replaces the currently selected text by the contents of the system clipboard.
1869 void QQuickTextInput::paste()
1871 Q_D(QQuickTextInput);
1875 #endif // QT_NO_CLIPBOARD
1878 Undoes the last operation if undo is \l {canUndo}{available}. Deselects any
1879 current selection, and updates the selection start to the current cursor
1883 void QQuickTextInput::undo()
1885 Q_D(QQuickTextInput);
1886 if (!d->m_readOnly) {
1888 d->finishChange(-1, true);
1893 Redoes the last operation if redo is \l {canRedo}{available}.
1896 void QQuickTextInput::redo()
1898 Q_D(QQuickTextInput);
1899 if (!d->m_readOnly) {
1906 \qmlmethod void QtQuick2::TextInput::insert(int position, string text)
1908 Inserts \a text into the TextInput at position.
1911 void QQuickTextInput::insert(int position, const QString &text)
1913 Q_D(QQuickTextInput);
1914 if (d->m_echoMode == QQuickTextInput::Password) {
1915 int delay = qGuiApp->styleHints()->passwordMaskDelay();
1917 d->m_passwordEchoTimer.start(delay, this);
1919 if (position < 0 || position > d->m_text.length())
1922 const int priorState = d->m_undoState;
1924 QString insertText = text;
1926 if (d->hasSelectedText()) {
1927 d->addCommand(QQuickTextInputPrivate::Command(
1928 QQuickTextInputPrivate::SetSelection, d->m_cursor, 0, d->m_selstart, d->m_selend));
1930 if (d->m_maskData) {
1931 insertText = d->maskString(position, insertText);
1932 for (int i = 0; i < insertText.length(); ++i) {
1933 d->addCommand(QQuickTextInputPrivate::Command(
1934 QQuickTextInputPrivate::DeleteSelection, position + i, d->m_text.at(position + i), -1, -1));
1935 d->addCommand(QQuickTextInputPrivate::Command(
1936 QQuickTextInputPrivate::Insert, position + i, insertText.at(i), -1, -1));
1938 d->m_text.replace(position, insertText.length(), insertText);
1939 if (!insertText.isEmpty())
1940 d->m_textDirty = true;
1941 if (position < d->m_selend && position + insertText.length() > d->m_selstart)
1942 d->m_selDirty = true;
1944 int remaining = d->m_maxLength - d->m_text.length();
1945 if (remaining != 0) {
1946 insertText = insertText.left(remaining);
1947 d->m_text.insert(position, insertText);
1948 for (int i = 0; i < insertText.length(); ++i)
1949 d->addCommand(QQuickTextInputPrivate::Command(
1950 QQuickTextInputPrivate::Insert, position + i, insertText.at(i), -1, -1));
1951 if (d->m_cursor >= position)
1952 d->m_cursor += insertText.length();
1953 if (d->m_selstart >= position)
1954 d->m_selstart += insertText.length();
1955 if (d->m_selend >= position)
1956 d->m_selend += insertText.length();
1957 d->m_textDirty = true;
1958 if (position >= d->m_selstart && position <= d->m_selend)
1959 d->m_selDirty = true;
1963 d->addCommand(QQuickTextInputPrivate::Command(
1964 QQuickTextInputPrivate::SetSelection, d->m_cursor, 0, d->m_selstart, d->m_selend));
1965 d->finishChange(priorState);
1967 if (d->lastSelectionStart != d->lastSelectionEnd) {
1968 if (d->m_selstart != d->lastSelectionStart) {
1969 d->lastSelectionStart = d->m_selstart;
1970 emit selectionStartChanged();
1972 if (d->m_selend != d->lastSelectionEnd) {
1973 d->lastSelectionEnd = d->m_selend;
1974 emit selectionEndChanged();
1980 \qmlmethod string QtQuick2::TextInput::getText(int start, int end)
1982 Removes the section of text that is between the \a start and \a end positions from the TextInput.
1985 void QQuickTextInput::remove(int start, int end)
1987 Q_D(QQuickTextInput);
1989 start = qBound(0, start, d->m_text.length());
1990 end = qBound(0, end, d->m_text.length());
1994 else if (start == end)
1997 if (start < d->m_selend && end > d->m_selstart)
1998 d->m_selDirty = true;
2000 const int priorState = d->m_undoState;
2002 d->addCommand(QQuickTextInputPrivate::Command(
2003 QQuickTextInputPrivate::SetSelection, d->m_cursor, 0, d->m_selstart, d->m_selend));
2005 if (start <= d->m_cursor && d->m_cursor < end) {
2006 // cursor is within the selection. Split up the commands
2007 // to be able to restore the correct cursor position
2008 for (int i = d->m_cursor; i >= start; --i) {
2009 d->addCommand(QQuickTextInputPrivate::Command(
2010 QQuickTextInputPrivate::DeleteSelection, i, d->m_text.at(i), -1, 1));
2012 for (int i = end - 1; i > d->m_cursor; --i) {
2013 d->addCommand(QQuickTextInputPrivate::Command(
2014 QQuickTextInputPrivate::DeleteSelection, i - d->m_cursor + start - 1, d->m_text.at(i), -1, -1));
2017 for (int i = end - 1; i >= start; --i) {
2018 d->addCommand(QQuickTextInputPrivate::Command(
2019 QQuickTextInputPrivate::RemoveSelection, i, d->m_text.at(i), -1, -1));
2022 if (d->m_maskData) {
2023 d->m_text.replace(start, end - start, d->clearString(start, end - start));
2024 for (int i = 0; i < end - start; ++i) {
2025 d->addCommand(QQuickTextInputPrivate::Command(
2026 QQuickTextInputPrivate::Insert, start + i, d->m_text.at(start + i), -1, -1));
2029 d->m_text.remove(start, end - start);
2031 if (d->m_cursor > start)
2032 d->m_cursor -= qMin(d->m_cursor, end) - start;
2033 if (d->m_selstart > start)
2034 d->m_selstart -= qMin(d->m_selstart, end) - start;
2035 if (d->m_selend > end)
2036 d->m_selend -= qMin(d->m_selend, end) - start;
2038 d->addCommand(QQuickTextInputPrivate::Command(
2039 QQuickTextInputPrivate::SetSelection, d->m_cursor, 0, d->m_selstart, d->m_selend));
2041 d->m_textDirty = true;
2042 d->finishChange(priorState);
2044 if (d->lastSelectionStart != d->lastSelectionEnd) {
2045 if (d->m_selstart != d->lastSelectionStart) {
2046 d->lastSelectionStart = d->m_selstart;
2047 emit selectionStartChanged();
2049 if (d->m_selend != d->lastSelectionEnd) {
2050 d->lastSelectionEnd = d->m_selend;
2051 emit selectionEndChanged();
2058 \qmlmethod void QtQuick2::TextInput::selectWord()
2060 Causes the word closest to the current cursor position to be selected.
2062 void QQuickTextInput::selectWord()
2064 Q_D(QQuickTextInput);
2065 d->selectWordAtPos(d->m_cursor);
2069 \qmlproperty bool QtQuick2::TextInput::smooth
2071 This property holds whether the text is smoothly scaled or transformed.
2073 Smooth filtering gives better visual quality, but is slower. If
2074 the item is displayed at its natural size, this property has no visual or
2077 \note Generally scaling artifacts are only visible if the item is stationary on
2078 the screen. A common pattern when animating an item is to disable smooth
2079 filtering at the beginning of the animation and reenable it at the conclusion.
2083 \qmlproperty string QtQuick2::TextInput::passwordCharacter
2085 This is the character displayed when echoMode is set to Password or
2086 PasswordEchoOnEdit. By default it is an asterisk.
2088 If this property is set to a string with more than one character,
2089 the first character is used. If the string is empty, the value
2090 is ignored and the property is not set.
2092 QString QQuickTextInput::passwordCharacter() const
2094 Q_D(const QQuickTextInput);
2095 return QString(d->m_passwordCharacter);
2098 void QQuickTextInput::setPasswordCharacter(const QString &str)
2100 Q_D(QQuickTextInput);
2101 if (str.length() < 1)
2103 d->m_passwordCharacter = str.constData()[0];
2104 if (d->m_echoMode == Password || d->m_echoMode == PasswordEchoOnEdit)
2105 d->updateDisplayText();
2106 emit passwordCharacterChanged();
2110 \qmlproperty string QtQuick2::TextInput::displayText
2112 This is the text displayed in the TextInput.
2114 If \l echoMode is set to TextInput::Normal, this holds the
2115 same value as the TextInput::text property. Otherwise,
2116 this property holds the text visible to the user, while
2117 the \l text property holds the actual entered text.
2119 QString QQuickTextInput::displayText() const
2121 Q_D(const QQuickTextInput);
2122 return d->m_textLayout.text();
2126 \qmlproperty bool QtQuick2::TextInput::selectByMouse
2130 If true, the user can use the mouse to select text in some
2131 platform-specific way. Note that for some platforms this may
2132 not be an appropriate interaction (eg. may conflict with how
2133 the text needs to behave inside a Flickable.
2135 bool QQuickTextInput::selectByMouse() const
2137 Q_D(const QQuickTextInput);
2138 return d->selectByMouse;
2141 void QQuickTextInput::setSelectByMouse(bool on)
2143 Q_D(QQuickTextInput);
2144 if (d->selectByMouse != on) {
2145 d->selectByMouse = on;
2146 emit selectByMouseChanged(on);
2151 \qmlproperty enum QtQuick2::TextInput::mouseSelectionMode
2153 Specifies how text should be selected using a mouse.
2156 \li TextInput.SelectCharacters - The selection is updated with individual characters. (Default)
2157 \li TextInput.SelectWords - The selection is updated with whole words.
2160 This property only applies when \l selectByMouse is true.
2163 QQuickTextInput::SelectionMode QQuickTextInput::mouseSelectionMode() const
2165 Q_D(const QQuickTextInput);
2166 return d->mouseSelectionMode;
2169 void QQuickTextInput::setMouseSelectionMode(SelectionMode mode)
2171 Q_D(QQuickTextInput);
2172 if (d->mouseSelectionMode != mode) {
2173 d->mouseSelectionMode = mode;
2174 emit mouseSelectionModeChanged(mode);
2179 \qmlproperty bool QtQuick2::TextInput::persistentSelection
2181 Whether the TextInput should keep its selection when it loses active focus to another
2182 item in the scene. By default this is set to false;
2185 bool QQuickTextInput::persistentSelection() const
2187 Q_D(const QQuickTextInput);
2188 return d->persistentSelection;
2191 void QQuickTextInput::setPersistentSelection(bool on)
2193 Q_D(QQuickTextInput);
2194 if (d->persistentSelection == on)
2196 d->persistentSelection = on;
2197 emit persistentSelectionChanged();
2200 #ifndef QT_NO_CLIPBOARD
2202 \qmlproperty bool QtQuick2::TextInput::canPaste
2204 Returns true if the TextInput is writable and the content of the clipboard is
2205 suitable for pasting into the TextInput.
2207 bool QQuickTextInput::canPaste() const
2209 Q_D(const QQuickTextInput);
2210 if (!d->canPasteValid) {
2211 if (const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData())
2212 const_cast<QQuickTextInputPrivate *>(d)->canPaste = !d->m_readOnly && mimeData->hasText();
2213 const_cast<QQuickTextInputPrivate *>(d)->canPasteValid = true;
2220 \qmlproperty bool QtQuick2::TextInput::canUndo
2222 Returns true if the TextInput is writable and there are previous operations
2226 bool QQuickTextInput::canUndo() const
2228 Q_D(const QQuickTextInput);
2233 \qmlproperty bool QtQuick2::TextInput::canRedo
2235 Returns true if the TextInput is writable and there are \l {undo}{undone}
2236 operations that can be redone.
2239 bool QQuickTextInput::canRedo() const
2241 Q_D(const QQuickTextInput);
2246 \qmlproperty real QtQuick2::TextInput::contentWidth
2248 Returns the width of the text, including the width past the width
2249 which is covered due to insufficient wrapping if \l wrapMode is set.
2252 qreal QQuickTextInput::contentWidth() const
2254 Q_D(const QQuickTextInput);
2255 return d->contentSize.width();
2259 \qmlproperty real QtQuick2::TextInput::contentHeight
2261 Returns the height of the text, including the height past the height
2262 that is covered if the text does not fit within the set height.
2265 qreal QQuickTextInput::contentHeight() const
2267 Q_D(const QQuickTextInput);
2268 return d->contentSize.height();
2271 void QQuickTextInput::moveCursorSelection(int position)
2273 Q_D(QQuickTextInput);
2274 d->moveCursor(position, true);
2278 \qmlmethod void QtQuick2::TextInput::moveCursorSelection(int position, SelectionMode mode = TextInput.SelectCharacters)
2280 Moves the cursor to \a position and updates the selection according to the optional \a mode
2281 parameter. (To only move the cursor, set the \l cursorPosition property.)
2283 When this method is called it additionally sets either the
2284 selectionStart or the selectionEnd (whichever was at the previous cursor position)
2285 to the specified position. This allows you to easily extend and contract the selected
2288 The selection mode specifies whether the selection is updated on a per character or a per word
2289 basis. If not specified the selection mode will default to TextInput.SelectCharacters.
2292 \li TextInput.SelectCharacters - Sets either the selectionStart or selectionEnd (whichever was at
2293 the previous cursor position) to the specified position.
2294 \li TextInput.SelectWords - Sets the selectionStart and selectionEnd to include all
2295 words between the specified position and the previous cursor position. Words partially in the
2299 For example, take this sequence of calls:
2303 moveCursorSelection(9, TextInput.SelectCharacters)
2304 moveCursorSelection(7, TextInput.SelectCharacters)
2307 This moves the cursor to position 5, extend the selection end from 5 to 9
2308 and then retract the selection end from 9 to 7, leaving the text from position 5 to 7
2309 selected (the 6th and 7th characters).
2311 The same sequence with TextInput.SelectWords will extend the selection start to a word boundary
2312 before or on position 5 and extend the selection end to a word boundary on or past position 9.
2314 void QQuickTextInput::moveCursorSelection(int pos, SelectionMode mode)
2316 Q_D(QQuickTextInput);
2318 if (mode == SelectCharacters) {
2319 d->moveCursor(pos, true);
2320 } else if (pos != d->m_cursor){
2321 const int cursor = d->m_cursor;
2323 if (!d->hasSelectedText())
2324 anchor = d->m_cursor;
2325 else if (d->selectionStart() == d->m_cursor)
2326 anchor = d->selectionEnd();
2328 anchor = d->selectionStart();
2330 if (anchor < pos || (anchor == pos && cursor < pos)) {
2331 const QString text = this->text();
2332 QTextBoundaryFinder finder(QTextBoundaryFinder::Word, text);
2333 finder.setPosition(anchor);
2335 const QTextBoundaryFinder::BoundaryReasons reasons = finder.boundaryReasons();
2336 if (anchor < text.length() && (!(reasons & QTextBoundaryFinder::StartWord)
2337 || ((reasons & QTextBoundaryFinder::EndWord) && anchor > cursor))) {
2338 finder.toPreviousBoundary();
2340 anchor = finder.position() != -1 ? finder.position() : 0;
2342 finder.setPosition(pos);
2343 if (pos > 0 && !finder.boundaryReasons())
2344 finder.toNextBoundary();
2345 const int cursor = finder.position() != -1 ? finder.position() : text.length();
2347 d->setSelection(anchor, cursor - anchor);
2348 } else if (anchor > pos || (anchor == pos && cursor > pos)) {
2349 const QString text = this->text();
2350 QTextBoundaryFinder finder(QTextBoundaryFinder::Word, text);
2351 finder.setPosition(anchor);
2353 const QTextBoundaryFinder::BoundaryReasons reasons = finder.boundaryReasons();
2354 if (anchor > 0 && (!(reasons & QTextBoundaryFinder::EndWord)
2355 || ((reasons & QTextBoundaryFinder::StartWord) && anchor < cursor))) {
2356 finder.toNextBoundary();
2359 anchor = finder.position() != -1 ? finder.position() : text.length();
2361 finder.setPosition(pos);
2362 if (pos < text.length() && !finder.boundaryReasons())
2363 finder.toPreviousBoundary();
2364 const int cursor = finder.position() != -1 ? finder.position() : 0;
2366 d->setSelection(anchor, cursor - anchor);
2372 \qmlmethod void QtQuick2::TextInput::openSoftwareInputPanel()
2374 Opens software input panels like virtual keyboards for typing, useful for
2375 customizing when you want the input keyboard to be shown and hidden in
2378 By default the opening of input panels follows the platform style. Input panels are
2379 always closed if no editor has active focus.
2381 You can disable the automatic behavior by setting the property \c activeFocusOnPress to false
2382 and use functions openSoftwareInputPanel() and closeSoftwareInputPanel() to implement
2383 the behavior you want.
2385 Only relevant on platforms, which provide virtual keyboards.
2391 text: "Hello world!"
2392 activeFocusOnPress: false
2394 anchors.fill: parent
2396 if (!textInput.activeFocus) {
2397 textInput.forceActiveFocus()
2398 textInput.openSoftwareInputPanel();
2400 textInput.focus = false;
2403 onPressAndHold: textInput.closeSoftwareInputPanel();
2408 void QQuickTextInput::openSoftwareInputPanel()
2411 qGuiApp->inputMethod()->show();
2415 \qmlmethod void QtQuick2::TextInput::closeSoftwareInputPanel()
2417 Closes a software input panel like a virtual keyboard shown on the screen, useful
2418 for customizing when you want the input keyboard to be shown and hidden in
2421 By default the opening of input panels follows the platform style. Input panels are
2422 always closed if no editor has active focus.
2424 You can disable the automatic behavior by setting the property \c activeFocusOnPress to false
2425 and use functions openSoftwareInputPanel() and closeSoftwareInputPanel() to implement
2426 the behavior you want.
2428 Only relevant on platforms, which provide virtual keyboards.
2434 text: "Hello world!"
2435 activeFocusOnPress: false
2437 anchors.fill: parent
2439 if (!textInput.activeFocus) {
2440 textInput.forceActiveFocus();
2441 textInput.openSoftwareInputPanel();
2443 textInput.focus = false;
2446 onPressAndHold: textInput.closeSoftwareInputPanel();
2451 void QQuickTextInput::closeSoftwareInputPanel()
2454 qGuiApp->inputMethod()->hide();
2457 void QQuickTextInput::focusInEvent(QFocusEvent *event)
2459 Q_D(const QQuickTextInput);
2460 if (d->focusOnPress && !d->m_readOnly)
2461 openSoftwareInputPanel();
2462 QQuickImplicitSizeItem::focusInEvent(event);
2465 void QQuickTextInput::itemChange(ItemChange change, const ItemChangeData &value)
2467 Q_D(QQuickTextInput);
2468 if (change == ItemActiveFocusHasChanged) {
2469 bool hasFocus = value.boolValue;
2470 setCursorVisible(hasFocus); // ### refactor: && d->canvas && d->canvas->hasFocus()
2471 if (!hasFocus && (d->m_passwordEchoEditing || d->m_passwordEchoTimer.isActive())) {
2472 d->updatePasswordEchoEditing(false);//QQuickTextInputPrivate sets it on key events, but doesn't deal with focus events
2476 if (!d->persistentSelection)
2478 disconnect(qApp->inputMethod(), SIGNAL(inputDirectionChanged(Qt::LayoutDirection)),
2479 this, SLOT(q_updateAlignment()));
2481 q_updateAlignment();
2482 connect(qApp->inputMethod(), SIGNAL(inputDirectionChanged(Qt::LayoutDirection)),
2483 this, SLOT(q_updateAlignment()));
2486 QQuickItem::itemChange(change, value);
2490 \qmlproperty bool QtQuick2::TextInput::inputMethodComposing
2493 This property holds whether the TextInput has partial text input from an
2496 While it is composing an input method may rely on mouse or key events from
2497 the TextInput to edit or commit the partial text. This property can be
2498 used to determine when to disable events handlers that may interfere with
2499 the correct operation of an input method.
2501 bool QQuickTextInput::isInputMethodComposing() const
2503 Q_D(const QQuickTextInput);
2504 return d->hasImState;
2507 void QQuickTextInputPrivate::init()
2509 Q_Q(QQuickTextInput);
2510 q->setSmooth(smooth);
2511 q->setAcceptedMouseButtons(Qt::LeftButton);
2512 q->setFlag(QQuickItem::ItemAcceptsInputMethod);
2513 q->setFlag(QQuickItem::ItemHasContents);
2514 #ifndef QT_NO_CLIPBOARD
2515 q->connect(QGuiApplication::clipboard(), SIGNAL(dataChanged()),
2516 q, SLOT(q_canPasteChanged()));
2517 #endif // QT_NO_CLIPBOARD
2519 lastSelectionStart = 0;
2520 lastSelectionEnd = 0;
2521 determineHorizontalAlignment();
2523 if (!qmlDisableDistanceField()) {
2524 QTextOption option = m_textLayout.textOption();
2525 option.setUseDesignMetrics(true);
2526 m_textLayout.setTextOption(option);
2530 void QQuickTextInput::updateCursorRectangle()
2532 Q_D(QQuickTextInput);
2533 if (!isComponentComplete())
2536 d->updateHorizontalScroll();
2537 d->updateVerticalScroll();
2538 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
2540 emit cursorRectangleChanged();
2541 if (d->cursorItem) {
2542 QRectF r = cursorRectangle();
2543 d->cursorItem->setPos(r.topLeft());
2544 d->cursorItem->setHeight(r.height());
2546 updateInputMethod(Qt::ImCursorRectangle);
2549 void QQuickTextInput::selectionChanged()
2551 Q_D(QQuickTextInput);
2552 d->textLayoutDirty = true; //TODO: Only update rect in selection
2553 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
2555 emit selectedTextChanged();
2557 if (d->lastSelectionStart != d->selectionStart()) {
2558 d->lastSelectionStart = d->selectionStart();
2559 if (d->lastSelectionStart == -1)
2560 d->lastSelectionStart = d->m_cursor;
2561 emit selectionStartChanged();
2563 if (d->lastSelectionEnd != d->selectionEnd()) {
2564 d->lastSelectionEnd = d->selectionEnd();
2565 if (d->lastSelectionEnd == -1)
2566 d->lastSelectionEnd = d->m_cursor;
2567 emit selectionEndChanged();
2571 void QQuickTextInputPrivate::showCursor()
2573 if (textNode != 0 && textNode->cursorNode() != 0)
2574 textNode->cursorNode()->setColor(color);
2577 void QQuickTextInputPrivate::hideCursor()
2579 if (textNode != 0 && textNode->cursorNode() != 0)
2580 textNode->cursorNode()->setColor(QColor(0, 0, 0, 0));
2583 QRectF QQuickTextInput::boundingRect() const
2585 Q_D(const QQuickTextInput);
2587 int cursorWidth = d->cursorItem ? 0 : 1;
2589 qreal hscroll = d->hscroll;
2590 if (!d->autoScroll || d->contentSize.width() < width()) {
2591 switch (effectiveHAlign()) {
2595 hscroll += d->contentSize.width() - width();
2598 hscroll += (d->contentSize.width() - width()) / 2;
2603 // Could include font max left/right bearings to either side of rectangle.
2604 QRectF r(-hscroll, -d->vscroll, d->contentSize.width(), d->contentSize.height());
2605 r.setRight(r.right() + cursorWidth);
2609 QRectF QQuickTextInput::clipRect() const
2611 Q_D(const QQuickTextInput);
2613 int cursorWidth = d->cursorItem ? d->cursorItem->width() : 1;
2615 // Could include font max left/right bearings to either side of rectangle.
2616 QRectF r = QQuickImplicitSizeItem::clipRect();
2617 r.setRight(r.right() + cursorWidth);
2621 void QQuickTextInput::q_canPasteChanged()
2623 Q_D(QQuickTextInput);
2624 bool old = d->canPaste;
2625 #ifndef QT_NO_CLIPBOARD
2626 if (const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData())
2627 d->canPaste = !d->m_readOnly && mimeData->hasText();
2629 d->canPaste = false;
2632 bool changed = d->canPaste != old || !d->canPasteValid;
2633 d->canPasteValid = true;
2635 emit canPasteChanged();
2639 void QQuickTextInput::q_updateAlignment()
2641 Q_D(QQuickTextInput);
2642 if (d->determineHorizontalAlignment()) {
2644 updateCursorRectangle();
2648 // ### these should come from QStyleHints
2649 const int textCursorWidth = 1;
2650 const bool fullWidthSelection = true;
2655 Updates the display text based of the current edit text
2656 If the text has changed will emit displayTextChanged()
2658 void QQuickTextInputPrivate::updateDisplayText(bool forceUpdate)
2660 QString orig = m_textLayout.text();
2662 if (m_echoMode == QQuickTextInput::NoEcho)
2663 str = QString::fromLatin1("");
2667 if (m_echoMode == QQuickTextInput::Password) {
2668 str.fill(m_passwordCharacter);
2669 if (m_passwordEchoTimer.isActive() && m_cursor > 0 && m_cursor <= m_text.length()) {
2670 int cursor = m_cursor - 1;
2671 QChar uc = m_text.at(cursor);
2673 if (cursor > 0 && uc.unicode() >= 0xdc00 && uc.unicode() < 0xe000) {
2674 // second half of a surrogate, check if we have the first half as well,
2675 // if yes restore both at once
2676 uc = m_text.at(cursor - 1);
2677 if (uc.unicode() >= 0xd800 && uc.unicode() < 0xdc00)
2678 str[cursor - 1] = uc;
2681 } else if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit && !m_passwordEchoEditing) {
2682 str.fill(m_passwordCharacter);
2685 // replace certain non-printable characters with spaces (to avoid
2686 // drawing boxes when using fonts that don't have glyphs for such
2688 QChar* uc = str.data();
2689 for (int i = 0; i < (int)str.length(); ++i) {
2690 if ((uc[i] < 0x20 && uc[i] != 0x09)
2691 || uc[i] == QChar::LineSeparator
2692 || uc[i] == QChar::ParagraphSeparator
2693 || uc[i] == QChar::ObjectReplacementCharacter)
2694 uc[i] = QChar(0x0020);
2697 if (str != orig || forceUpdate) {
2698 m_textLayout.setText(str);
2699 updateLayout(); // polish?
2700 emit q_func()->displayTextChanged();
2704 qreal QQuickTextInputPrivate::getImplicitWidth() const
2706 Q_Q(const QQuickTextInput);
2707 if (!requireImplicitWidth) {
2708 QQuickTextInputPrivate *d = const_cast<QQuickTextInputPrivate *>(this);
2709 d->requireImplicitWidth = true;
2711 if (q->isComponentComplete()) {
2712 // One time cost, only incurred if implicitWidth is first requested after
2713 // componentComplete.
2714 QTextLayout layout(m_text);
2716 QTextOption option = m_textLayout.textOption();
2717 option.setTextDirection(m_layoutDirection);
2718 option.setFlags(QTextOption::IncludeTrailingSpaces);
2719 option.setWrapMode(QTextOption::WrapMode(wrapMode));
2720 option.setAlignment(Qt::Alignment(q->effectiveHAlign()));
2721 layout.setTextOption(option);
2722 layout.setFont(font);
2723 layout.setPreeditArea(m_textLayout.preeditAreaPosition(), m_textLayout.preeditAreaText());
2724 layout.beginLayout();
2726 QTextLine line = layout.createLine();
2727 line.setLineWidth(INT_MAX);
2728 d->implicitWidth = qCeil(line.naturalTextWidth());
2733 return implicitWidth;
2736 void QQuickTextInputPrivate::updateLayout()
2738 Q_Q(QQuickTextInput);
2740 if (!q->isComponentComplete())
2744 QTextOption option = m_textLayout.textOption();
2745 option.setTextDirection(layoutDirection());
2746 option.setWrapMode(QTextOption::WrapMode(wrapMode));
2747 option.setAlignment(Qt::Alignment(q->effectiveHAlign()));
2748 m_textLayout.setTextOption(option);
2749 m_textLayout.setFont(font);
2751 m_textLayout.beginLayout();
2753 QTextLine line = m_textLayout.createLine();
2754 if (requireImplicitWidth) {
2755 line.setLineWidth(INT_MAX);
2756 const bool wasInLayout = inLayout;
2758 q->setImplicitWidth(qCeil(line.naturalTextWidth()));
2759 inLayout = wasInLayout;
2760 if (inLayout) // probably the result of a binding loop, but by letting it
2761 return; // get this far we'll get a warning to that effect.
2763 qreal lineWidth = q->widthValid() ? q->width() : INT_MAX;
2767 line.setLineWidth(lineWidth);
2768 line.setPosition(QPointF(0, height));
2770 height += line.height();
2771 width = qMax(width, line.naturalTextWidth());
2773 line = m_textLayout.createLine();
2774 } while (line.isValid());
2775 m_textLayout.endLayout();
2777 option.setWrapMode(QTextOption::NoWrap);
2778 m_textLayout.setTextOption(option);
2780 textLayoutDirty = true;
2782 const QSizeF previousSize = contentSize;
2783 contentSize = QSizeF(width, height);
2785 updateType = UpdatePaintNode;
2788 if (!requireImplicitWidth && !q->widthValid())
2789 q->setImplicitSize(width, height);
2791 q->setImplicitHeight(height);
2793 if (previousSize != contentSize)
2794 emit q->contentSizeChanged();
2797 #ifndef QT_NO_CLIPBOARD
2801 Copies the currently selected text into the clipboard using the given
2804 \note If the echo mode is set to a mode other than Normal then copy
2805 will not work. This is to prevent using copy as a method of bypassing
2806 password features of the line control.
2808 void QQuickTextInputPrivate::copy(QClipboard::Mode mode) const
2810 QString t = selectedText();
2811 if (!t.isEmpty() && m_echoMode == QQuickTextInput::Normal) {
2812 QGuiApplication::clipboard()->setText(t, mode);
2819 Inserts the text stored in the application clipboard into the line
2824 void QQuickTextInputPrivate::paste(QClipboard::Mode clipboardMode)
2826 QString clip = QGuiApplication::clipboard()->text(clipboardMode);
2827 if (!clip.isEmpty() || hasSelectedText()) {
2828 separate(); //make it a separate undo/redo command
2834 #endif // !QT_NO_CLIPBOARD
2839 void QQuickTextInputPrivate::commitPreedit()
2841 Q_Q(QQuickTextInput);
2846 qApp->inputMethod()->commit();
2851 QInputMethodEvent ev;
2852 QCoreApplication::sendEvent(q, &ev);
2855 void QQuickTextInputPrivate::cancelPreedit()
2857 Q_Q(QQuickTextInput);
2862 qApp->inputMethod()->reset();
2864 QInputMethodEvent ev;
2865 QCoreApplication::sendEvent(q, &ev);
2871 Handles the behavior for the backspace key or function.
2872 Removes the current selection if there is a selection, otherwise
2873 removes the character prior to the cursor position.
2877 void QQuickTextInputPrivate::backspace()
2879 int priorState = m_undoState;
2880 if (hasSelectedText()) {
2881 removeSelectedText();
2882 } else if (m_cursor) {
2885 m_cursor = prevMaskBlank(m_cursor);
2886 QChar uc = m_text.at(m_cursor);
2887 if (m_cursor > 0 && uc.unicode() >= 0xdc00 && uc.unicode() < 0xe000) {
2888 // second half of a surrogate, check if we have the first half as well,
2889 // if yes delete both at once
2890 uc = m_text.at(m_cursor - 1);
2891 if (uc.unicode() >= 0xd800 && uc.unicode() < 0xdc00) {
2892 internalDelete(true);
2896 internalDelete(true);
2898 finishChange(priorState);
2904 Handles the behavior for the delete key or function.
2905 Removes the current selection if there is a selection, otherwise
2906 removes the character after the cursor position.
2910 void QQuickTextInputPrivate::del()
2912 int priorState = m_undoState;
2913 if (hasSelectedText()) {
2914 removeSelectedText();
2916 int n = m_textLayout.nextCursorPosition(m_cursor) - m_cursor;
2920 finishChange(priorState);
2926 Inserts the given \a newText at the current cursor position.
2927 If there is any selected text it is removed prior to insertion of
2930 void QQuickTextInputPrivate::insert(const QString &newText)
2932 int priorState = m_undoState;
2933 removeSelectedText();
2934 internalInsert(newText);
2935 finishChange(priorState);
2941 Clears the line control text.
2943 void QQuickTextInputPrivate::clear()
2945 int priorState = m_undoState;
2947 m_selend = m_text.length();
2948 removeSelectedText();
2950 finishChange(priorState, /*update*/false, /*edited*/false);
2956 Sets \a length characters from the given \a start position as selected.
2957 The given \a start position must be within the current text for
2958 the line control. If \a length characters cannot be selected, then
2959 the selection will extend to the end of the current text.
2961 void QQuickTextInputPrivate::setSelection(int start, int length)
2963 Q_Q(QQuickTextInput);
2966 if (start < 0 || start > (int)m_text.length()){
2967 qWarning("QQuickTextInputPrivate::setSelection: Invalid start position");
2972 if (start == m_selstart && start + length == m_selend && m_cursor == m_selend)
2975 m_selend = qMin(start + length, (int)m_text.length());
2976 m_cursor = m_selend;
2977 } else if (length < 0){
2978 if (start == m_selend && start + length == m_selstart && m_cursor == m_selstart)
2980 m_selstart = qMax(start + length, 0);
2982 m_cursor = m_selstart;
2983 } else if (m_selstart != m_selend) {
2989 emitCursorPositionChanged();
2992 emit q->selectionChanged();
2993 emitCursorPositionChanged();
2994 q->updateInputMethod(Qt::ImCursorRectangle | Qt::ImAnchorPosition
2995 | Qt::ImCursorPosition | Qt::ImCurrentSelection);
3001 Sets the password echo editing to \a editing. If password echo editing
3002 is true, then the text of the password is displayed even if the echo
3003 mode is set to QLineEdit::PasswordEchoOnEdit. Password echoing editing
3004 does not affect other echo modes.
3006 void QQuickTextInputPrivate::updatePasswordEchoEditing(bool editing)
3008 cancelPasswordEchoTimer();
3009 m_passwordEchoEditing = editing;
3010 updateDisplayText();
3016 Fixes the current text so that it is valid given any set validators.
3018 Returns true if the text was changed. Otherwise returns false.
3020 bool QQuickTextInputPrivate::fixup() // this function assumes that validate currently returns != Acceptable
3022 #ifndef QT_NO_VALIDATOR
3024 QString textCopy = m_text;
3025 int cursorCopy = m_cursor;
3026 m_validator->fixup(textCopy);
3027 if (m_validator->validate(textCopy, cursorCopy) == QValidator::Acceptable) {
3028 if (textCopy != m_text || cursorCopy != m_cursor)
3029 internalSetText(textCopy, cursorCopy);
3040 Moves the cursor to the given position \a pos. If \a mark is true will
3041 adjust the currently selected text.
3043 void QQuickTextInputPrivate::moveCursor(int pos, bool mark)
3045 Q_Q(QQuickTextInput);
3048 if (pos != m_cursor) {
3051 pos = pos > m_cursor ? nextMaskBlank(pos) : prevMaskBlank(pos);
3055 if (m_selend > m_selstart && m_cursor == m_selstart)
3057 else if (m_selend > m_selstart && m_cursor == m_selend)
3058 anchor = m_selstart;
3061 m_selstart = qMin(anchor, pos);
3062 m_selend = qMax(anchor, pos);
3067 if (mark || m_selDirty) {
3069 emit q->selectionChanged();
3071 emitCursorPositionChanged();
3072 q->updateInputMethod();
3078 Applies the given input method event \a event to the text of the line
3081 void QQuickTextInputPrivate::processInputMethodEvent(QInputMethodEvent *event)
3083 Q_Q(QQuickTextInput);
3085 int priorState = -1;
3086 bool isGettingInput = !event->commitString().isEmpty()
3087 || event->preeditString() != preeditAreaText()
3088 || event->replacementLength() > 0;
3089 bool cursorPositionChanged = false;
3090 bool selectionChange = false;
3091 m_preeditDirty = event->preeditString() != preeditAreaText();
3093 if (isGettingInput) {
3094 // If any text is being input, remove selected text.
3095 priorState = m_undoState;
3096 if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit && !m_passwordEchoEditing) {
3097 updatePasswordEchoEditing(true);
3099 m_selend = m_text.length();
3101 removeSelectedText();
3104 int c = m_cursor; // cursor position after insertion of commit string
3105 if (event->replacementStart() <= 0)
3106 c += event->commitString().length() - qMin(-event->replacementStart(), event->replacementLength());
3108 m_cursor += event->replacementStart();
3112 // insert commit string
3113 if (event->replacementLength()) {
3114 m_selstart = m_cursor;
3115 m_selend = m_selstart + event->replacementLength();
3116 m_selend = qMin(m_selend, m_text.length());
3117 removeSelectedText();
3119 if (!event->commitString().isEmpty()) {
3120 internalInsert(event->commitString());
3121 cursorPositionChanged = true;
3124 m_cursor = qBound(0, c, m_text.length());
3126 for (int i = 0; i < event->attributes().size(); ++i) {
3127 const QInputMethodEvent::Attribute &a = event->attributes().at(i);
3128 if (a.type == QInputMethodEvent::Selection) {
3129 m_cursor = qBound(0, a.start + a.length, m_text.length());
3131 m_selstart = qMax(0, qMin(a.start, m_text.length()));
3132 m_selend = m_cursor;
3133 if (m_selend < m_selstart) {
3134 qSwap(m_selstart, m_selend);
3136 selectionChange = true;
3138 m_selstart = m_selend = 0;
3140 cursorPositionChanged = true;
3144 m_textLayout.setPreeditArea(m_cursor, event->preeditString());
3146 const int oldPreeditCursor = m_preeditCursor;
3147 m_preeditCursor = event->preeditString().length();
3148 hasImState = !event->preeditString().isEmpty();
3149 bool cursorVisible = true;
3150 QList<QTextLayout::FormatRange> formats;
3151 for (int i = 0; i < event->attributes().size(); ++i) {
3152 const QInputMethodEvent::Attribute &a = event->attributes().at(i);
3153 if (a.type == QInputMethodEvent::Cursor) {
3155 m_preeditCursor = a.start;
3156 cursorVisible = a.length != 0;
3157 } else if (a.type == QInputMethodEvent::TextFormat) {
3159 QTextCharFormat f = qvariant_cast<QTextFormat>(a.value).toCharFormat();
3161 QTextLayout::FormatRange o;
3162 o.start = a.start + m_cursor;
3163 o.length = a.length;
3169 m_textLayout.setAdditionalFormats(formats);
3171 updateDisplayText(/*force*/ true);
3172 if (cursorPositionChanged) {
3173 emitCursorPositionChanged();
3174 } else if (m_preeditCursor != oldPreeditCursor || isGettingInput) {
3175 q->updateCursorRectangle();
3179 finishChange(priorState);
3181 q->setCursorVisible(cursorVisible);
3183 if (selectionChange) {
3184 emit q->selectionChanged();
3185 q->updateInputMethod(Qt::ImCursorRectangle | Qt::ImAnchorPosition
3186 | Qt::ImCursorPosition | Qt::ImCurrentSelection);
3193 Sets the selection to cover the word at the given cursor position.
3194 The word boundaries are defined by the behavior of QTextLayout::SkipWords
3197 void QQuickTextInputPrivate::selectWordAtPos(int cursor)
3199 int next = cursor + 1;
3202 int c = m_textLayout.previousCursorPosition(next, QTextLayout::SkipWords);
3203 moveCursor(c, false);
3204 // ## text layout should support end of words.
3205 int end = m_textLayout.nextCursorPosition(c, QTextLayout::SkipWords);
3206 while (end > cursor && m_text[end-1].isSpace())
3208 moveCursor(end, true);
3214 Completes a change to the line control text. If the change is not valid
3215 will undo the line control state back to the given \a validateFromState.
3217 If \a edited is true and the change is valid, will emit textEdited() in
3218 addition to textChanged(). Otherwise only emits textChanged() on a valid
3221 The \a update value is currently unused.
3223 bool QQuickTextInputPrivate::finishChange(int validateFromState, bool update, bool /*edited*/)
3225 Q_Q(QQuickTextInput);
3228 bool inputMethodAttributesChanged = m_textDirty || m_selDirty;
3229 bool alignmentChanged = false;
3233 bool wasValidInput = m_validInput;
3234 bool wasAcceptable = m_acceptableInput;
3235 m_validInput = true;
3236 m_acceptableInput = true;
3237 #ifndef QT_NO_VALIDATOR
3239 QString textCopy = m_text;
3240 int cursorCopy = m_cursor;
3241 QValidator::State state = m_validator->validate(textCopy, cursorCopy);
3242 m_validInput = state != QValidator::Invalid;
3243 m_acceptableInput = state == QValidator::Acceptable;
3245 if (m_text != textCopy) {
3246 internalSetText(textCopy, cursorCopy);
3249 m_cursor = cursorCopy;
3253 if (validateFromState >= 0 && wasValidInput && !m_validInput) {
3254 if (m_transactions.count())
3256 internalUndo(validateFromState);
3257 m_history.resize(m_undoState);
3258 m_validInput = true;
3259 m_acceptableInput = wasAcceptable;
3260 m_textDirty = false;
3264 m_textDirty = false;
3265 m_preeditDirty = false;
3266 alignmentChanged = determineHorizontalAlignment();
3267 emit q->textChanged();
3270 updateDisplayText(alignmentChanged);
3272 if (m_acceptableInput != wasAcceptable)
3273 emit q->acceptableInputChanged();
3275 if (m_preeditDirty) {
3276 m_preeditDirty = false;
3277 if (determineHorizontalAlignment()) {
3278 alignmentChanged = true;
3285 emit q->selectionChanged();
3288 inputMethodAttributesChanged |= (m_cursor != m_lastCursorPos);
3289 if (inputMethodAttributesChanged)
3290 q->updateInputMethod();
3291 emitUndoRedoChanged();
3293 if (!emitCursorPositionChanged() && alignmentChanged)
3294 q->updateCursorRectangle();
3302 An internal function for setting the text of the line control.
3304 void QQuickTextInputPrivate::internalSetText(const QString &txt, int pos, bool edited)
3306 Q_Q(QQuickTextInput);
3308 QString oldText = m_text;
3310 m_text = maskString(0, txt, true);
3311 m_text += clearString(m_text.length(), m_maxLength - m_text.length());
3313 m_text = txt.isEmpty() ? txt : txt.left(m_maxLength);
3317 m_cursor = (pos < 0 || pos > m_text.length()) ? m_text.length() : pos;
3318 m_textDirty = (oldText != m_text);
3320 bool changed = finishChange(-1, true, edited);
3321 #ifdef QT_NO_ACCESSIBILITY
3325 QAccessibleTextUpdateEvent ev(q, 0, oldText, m_text);
3326 QAccessible::updateAccessibility(&ev);
3335 Adds the given \a command to the undo history
3336 of the line control. Does not apply the command.
3338 void QQuickTextInputPrivate::addCommand(const Command &cmd)
3340 if (m_separator && m_undoState && m_history[m_undoState - 1].type != Separator) {
3341 m_history.resize(m_undoState + 2);
3342 m_history[m_undoState++] = Command(Separator, m_cursor, 0, m_selstart, m_selend);
3344 m_history.resize(m_undoState + 1);
3346 m_separator = false;
3347 m_history[m_undoState++] = cmd;
3353 Inserts the given string \a s into the line
3356 Also adds the appropriate commands into the undo history.
3357 This function does not call finishChange(), and may leave the text
3358 in an invalid state.
3360 void QQuickTextInputPrivate::internalInsert(const QString &s)
3362 Q_Q(QQuickTextInput);
3363 if (m_echoMode == QQuickTextInput::Password) {
3364 int delay = qGuiApp->styleHints()->passwordMaskDelay();
3366 m_passwordEchoTimer.start(delay, q);
3368 if (hasSelectedText())
3369 addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
3371 QString ms = maskString(m_cursor, s);
3372 for (int i = 0; i < (int) ms.length(); ++i) {
3373 addCommand (Command(DeleteSelection, m_cursor + i, m_text.at(m_cursor + i), -1, -1));
3374 addCommand(Command(Insert, m_cursor + i, ms.at(i), -1, -1));
3376 m_text.replace(m_cursor, ms.length(), ms);
3377 m_cursor += ms.length();
3378 m_cursor = nextMaskBlank(m_cursor);
3381 int remaining = m_maxLength - m_text.length();
3382 if (remaining != 0) {
3383 m_text.insert(m_cursor, s.left(remaining));
3384 for (int i = 0; i < (int) s.left(remaining).length(); ++i)
3385 addCommand(Command(Insert, m_cursor++, s.at(i), -1, -1));
3394 deletes a single character from the current text. If \a wasBackspace,
3395 the character prior to the cursor is removed. Otherwise the character
3396 after the cursor is removed.
3398 Also adds the appropriate commands into the undo history.
3399 This function does not call finishChange(), and may leave the text
3400 in an invalid state.
3402 void QQuickTextInputPrivate::internalDelete(bool wasBackspace)
3404 if (m_cursor < (int) m_text.length()) {
3405 cancelPasswordEchoTimer();
3406 if (hasSelectedText())
3407 addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
3408 addCommand(Command((CommandType)((m_maskData ? 2 : 0) + (wasBackspace ? Remove : Delete)),
3409 m_cursor, m_text.at(m_cursor), -1, -1));
3411 m_text.replace(m_cursor, 1, clearString(m_cursor, 1));
3412 addCommand(Command(Insert, m_cursor, m_text.at(m_cursor), -1, -1));
3414 m_text.remove(m_cursor, 1);
3423 removes the currently selected text from the line control.
3425 Also adds the appropriate commands into the undo history.
3426 This function does not call finishChange(), and may leave the text
3427 in an invalid state.
3429 void QQuickTextInputPrivate::removeSelectedText()
3431 if (m_selstart < m_selend && m_selend <= (int) m_text.length()) {
3432 cancelPasswordEchoTimer();
3435 addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
3436 if (m_selstart <= m_cursor && m_cursor < m_selend) {
3437 // cursor is within the selection. Split up the commands
3438 // to be able to restore the correct cursor position
3439 for (i = m_cursor; i >= m_selstart; --i)
3440 addCommand (Command(DeleteSelection, i, m_text.at(i), -1, 1));
3441 for (i = m_selend - 1; i > m_cursor; --i)
3442 addCommand (Command(DeleteSelection, i - m_cursor + m_selstart - 1, m_text.at(i), -1, -1));
3444 for (i = m_selend-1; i >= m_selstart; --i)
3445 addCommand (Command(RemoveSelection, i, m_text.at(i), -1, -1));
3448 m_text.replace(m_selstart, m_selend - m_selstart, clearString(m_selstart, m_selend - m_selstart));
3449 for (int i = 0; i < m_selend - m_selstart; ++i)
3450 addCommand(Command(Insert, m_selstart + i, m_text.at(m_selstart + i), -1, -1));
3452 m_text.remove(m_selstart, m_selend - m_selstart);
3454 if (m_cursor > m_selstart)
3455 m_cursor -= qMin(m_cursor, m_selend) - m_selstart;
3464 Parses the input mask specified by \a maskFields to generate
3465 the mask data used to handle input masks.
3467 void QQuickTextInputPrivate::parseInputMask(const QString &maskFields)
3469 int delimiter = maskFields.indexOf(QLatin1Char(';'));
3470 if (maskFields.isEmpty() || delimiter == 0) {
3472 delete [] m_maskData;
3474 m_maxLength = 32767;
3475 internalSetText(QString());
3480 if (delimiter == -1) {
3481 m_blank = QLatin1Char(' ');
3482 m_inputMask = maskFields;
3484 m_inputMask = maskFields.left(delimiter);
3485 m_blank = (delimiter + 1 < maskFields.length()) ? maskFields[delimiter + 1] : QLatin1Char(' ');
3488 // calculate m_maxLength / m_maskData length
3491 for (int i=0; i<m_inputMask.length(); i++) {
3492 c = m_inputMask.at(i);
3493 if (i > 0 && m_inputMask.at(i-1) == QLatin1Char('\\')) {
3497 if (c != QLatin1Char('\\') && c != QLatin1Char('!') &&
3498 c != QLatin1Char('<') && c != QLatin1Char('>') &&
3499 c != QLatin1Char('{') && c != QLatin1Char('}') &&
3500 c != QLatin1Char('[') && c != QLatin1Char(']'))
3504 delete [] m_maskData;
3505 m_maskData = new MaskInputData[m_maxLength];
3507 MaskInputData::Casemode m = MaskInputData::NoCaseMode;
3510 bool escape = false;
3512 for (int i = 0; i < m_inputMask.length(); i++) {
3513 c = m_inputMask.at(i);
3516 m_maskData[index].maskChar = c;
3517 m_maskData[index].separator = s;
3518 m_maskData[index].caseMode = m;
3521 } else if (c == QLatin1Char('<')) {
3522 m = MaskInputData::Lower;
3523 } else if (c == QLatin1Char('>')) {
3524 m = MaskInputData::Upper;
3525 } else if (c == QLatin1Char('!')) {
3526 m = MaskInputData::NoCaseMode;
3527 } else if (c != QLatin1Char('{') && c != QLatin1Char('}') && c != QLatin1Char('[') && c != QLatin1Char(']')) {
3528 switch (c.unicode()) {
3554 m_maskData[index].maskChar = c;
3555 m_maskData[index].separator = s;
3556 m_maskData[index].caseMode = m;
3561 internalSetText(m_text);
3568 checks if the key is valid compared to the inputMask
3570 bool QQuickTextInputPrivate::isValidInput(QChar key, QChar mask) const
3572 switch (mask.unicode()) {
3578 if (key.isLetter() || key == m_blank)
3582 if (key.isLetterOrNumber())
3586 if (key.isLetterOrNumber() || key == m_blank)
3594 if (key.isPrint() || key == m_blank)
3602 if (key.isNumber() || key == m_blank)
3606 if (key.isNumber() && key.digitValue() > 0)
3610 if ((key.isNumber() && key.digitValue() > 0) || key == m_blank)
3614 if (key.isNumber() || key == QLatin1Char('+') || key == QLatin1Char('-') || key == m_blank)
3618 if (key == QLatin1Char('0') || key == QLatin1Char('1'))
3622 if (key == QLatin1Char('0') || key == QLatin1Char('1') || key == m_blank)
3626 if (key.isNumber() || (key >= QLatin1Char('a') && key <= QLatin1Char('f')) || (key >= QLatin1Char('A') && key <= QLatin1Char('F')))
3630 if (key.isNumber() || (key >= QLatin1Char('a') && key <= QLatin1Char('f')) || (key >= QLatin1Char('A') && key <= QLatin1Char('F')) || key == m_blank)
3642 Returns true if the given text \a str is valid for any
3643 validator or input mask set for the line control.
3645 Otherwise returns false
3647 QQuickTextInputPrivate::ValidatorState QQuickTextInputPrivate::hasAcceptableInput(const QString &str) const
3649 #ifndef QT_NO_VALIDATOR
3650 QString textCopy = str;
3651 int cursorCopy = m_cursor;
3653 QValidator::State state = m_validator->validate(textCopy, cursorCopy);
3654 if (state != QValidator::Acceptable)
3655 return ValidatorState(state);
3660 return AcceptableInput;
3662 if (str.length() != m_maxLength)
3663 return InvalidInput;
3665 for (int i=0; i < m_maxLength; ++i) {
3666 if (m_maskData[i].separator) {
3667 if (str.at(i) != m_maskData[i].maskChar)
3668 return InvalidInput;
3670 if (!isValidInput(str.at(i), m_maskData[i].maskChar))
3671 return InvalidInput;
3674 return AcceptableInput;
3680 Applies the inputMask on \a str starting from position \a pos in the mask. \a clear
3681 specifies from where characters should be gotten when a separator is met in \a str - true means
3682 that blanks will be used, false that previous input is used.
3683 Calling this when no inputMask is set is undefined.
3685 QString QQuickTextInputPrivate::maskString(uint pos, const QString &str, bool clear) const
3687 if (pos >= (uint)m_maxLength)
3688 return QString::fromLatin1("");
3691 fill = clear ? clearString(0, m_maxLength) : m_text;
3694 QString s = QString::fromLatin1("");
3696 while (i < m_maxLength) {
3697 if (strIndex < str.length()) {
3698 if (m_maskData[i].separator) {
3699 s += m_maskData[i].maskChar;
3700 if (str[(int)strIndex] == m_maskData[i].maskChar)
3704 if (isValidInput(str[(int)strIndex], m_maskData[i].maskChar)) {
3705 switch (m_maskData[i].caseMode) {
3706 case MaskInputData::Upper:
3707 s += str[(int)strIndex].toUpper();
3709 case MaskInputData::Lower:
3710 s += str[(int)strIndex].toLower();
3713 s += str[(int)strIndex];
3717 // search for separator first
3718 int n = findInMask(i, true, true, str[(int)strIndex]);
3720 if (str.length() != 1 || i == 0 || (i > 0 && (!m_maskData[i-1].separator || m_maskData[i-1].maskChar != str[(int)strIndex]))) {
3721 s += fill.mid(i, n-i+1);
3722 i = n + 1; // update i to find + 1
3725 // search for valid m_blank if not
3726 n = findInMask(i, true, false, str[(int)strIndex]);
3728 s += fill.mid(i, n-i);
3729 switch (m_maskData[n].caseMode) {
3730 case MaskInputData::Upper:
3731 s += str[(int)strIndex].toUpper();
3733 case MaskInputData::Lower:
3734 s += str[(int)strIndex].toLower();
3737 s += str[(int)strIndex];
3739 i = n + 1; // updates i to find + 1
3757 Returns a "cleared" string with only separators and blank chars.
3758 Calling this when no inputMask is set is undefined.
3760 QString QQuickTextInputPrivate::clearString(uint pos, uint len) const
3762 if (pos >= (uint)m_maxLength)
3766 int end = qMin((uint)m_maxLength, pos + len);
3767 for (int i = pos; i < end; ++i)
3768 if (m_maskData[i].separator)
3769 s += m_maskData[i].maskChar;
3779 Strips blank parts of the input in a QQuickTextInputPrivate when an inputMask is set,
3780 separators are still included. Typically "127.0__.0__.1__" becomes "127.0.0.1".
3782 QString QQuickTextInputPrivate::stripString(const QString &str) const
3788 int end = qMin(m_maxLength, (int)str.length());
3789 for (int i = 0; i < end; ++i) {
3790 if (m_maskData[i].separator)
3791 s += m_maskData[i].maskChar;
3792 else if (str[i] != m_blank)
3801 searches forward/backward in m_maskData for either a separator or a m_blank
3803 int QQuickTextInputPrivate::findInMask(int pos, bool forward, bool findSeparator, QChar searchChar) const
3805 if (pos >= m_maxLength || pos < 0)
3808 int end = forward ? m_maxLength : -1;
3809 int step = forward ? 1 : -1;
3813 if (findSeparator) {
3814 if (m_maskData[i].separator && m_maskData[i].maskChar == searchChar)
3817 if (!m_maskData[i].separator) {
3818 if (searchChar.isNull())
3820 else if (isValidInput(searchChar, m_maskData[i].maskChar))
3829 void QQuickTextInputPrivate::internalUndo(int until)
3831 if (!isUndoAvailable())
3833 cancelPasswordEchoTimer();
3835 while (m_undoState && m_undoState > until) {
3836 Command& cmd = m_history[--m_undoState];
3839 m_text.remove(cmd.pos, 1);
3843 m_selstart = cmd.selStart;
3844 m_selend = cmd.selEnd;
3848 case RemoveSelection:
3849 m_text.insert(cmd.pos, cmd.uc);
3850 m_cursor = cmd.pos + 1;
3853 case DeleteSelection:
3854 m_text.insert(cmd.pos, cmd.uc);
3860 if (until < 0 && m_undoState) {
3861 Command& next = m_history[m_undoState-1];
3862 if (next.type != cmd.type && next.type < RemoveSelection
3863 && (cmd.type < RemoveSelection || next.type == Separator))
3870 void QQuickTextInputPrivate::internalRedo()
3872 if (!isRedoAvailable())
3875 while (m_undoState < (int)m_history.size()) {
3876 Command& cmd = m_history[m_undoState++];
3879 m_text.insert(cmd.pos, cmd.uc);
3880 m_cursor = cmd.pos + 1;
3883 m_selstart = cmd.selStart;
3884 m_selend = cmd.selEnd;
3889 case RemoveSelection:
3890 case DeleteSelection:
3891 m_text.remove(cmd.pos, 1);
3892 m_selstart = cmd.selStart;
3893 m_selend = cmd.selEnd;
3897 m_selstart = cmd.selStart;
3898 m_selend = cmd.selEnd;
3902 if (m_undoState < (int)m_history.size()) {
3903 Command& next = m_history[m_undoState];
3904 if (next.type != cmd.type && cmd.type < RemoveSelection && next.type != Separator
3905 && (next.type < RemoveSelection || cmd.type == Separator))
3912 void QQuickTextInputPrivate::emitUndoRedoChanged()
3914 Q_Q(QQuickTextInput);
3915 const bool previousUndo = canUndo;
3916 const bool previousRedo = canRedo;
3918 canUndo = isUndoAvailable();
3919 canRedo = isRedoAvailable();
3921 if (previousUndo != canUndo)
3922 emit q->canUndoChanged();
3923 if (previousRedo != canRedo)
3924 emit q->canRedoChanged();
3930 If the current cursor position differs from the last emitted cursor
3931 position, emits cursorPositionChanged().
3933 bool QQuickTextInputPrivate::emitCursorPositionChanged()
3935 Q_Q(QQuickTextInput);
3936 if (m_cursor != m_lastCursorPos) {
3937 m_lastCursorPos = m_cursor;
3939 q->updateCursorRectangle();
3940 emit q->cursorPositionChanged();
3942 if (!hasSelectedText()) {
3943 if (lastSelectionStart != m_cursor) {
3944 lastSelectionStart = m_cursor;
3945 emit q->selectionStartChanged();
3947 if (lastSelectionEnd != m_cursor) {
3948 lastSelectionEnd = m_cursor;
3949 emit q->selectionEndChanged();
3953 #ifndef QT_NO_ACCESSIBILITY
3954 QAccessibleTextCursorEvent ev(q, m_cursor);
3955 QAccessible::updateAccessibility(&ev);
3964 void QQuickTextInputPrivate::setCursorBlinkPeriod(int msec)
3966 Q_Q(QQuickTextInput);
3967 if (msec == m_blinkPeriod)
3970 q->killTimer(m_blinkTimer);
3973 m_blinkTimer = q->startTimer(msec / 2);
3977 if (m_blinkStatus == 1) {
3978 updateType = UpdatePaintNode;
3982 m_blinkPeriod = msec;
3985 void QQuickTextInput::timerEvent(QTimerEvent *event)
3987 Q_D(QQuickTextInput);
3988 if (event->timerId() == d->m_blinkTimer) {
3989 d->m_blinkStatus = !d->m_blinkStatus;
3990 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
3992 } else if (event->timerId() == d->m_passwordEchoTimer.timerId()) {
3993 d->m_passwordEchoTimer.stop();
3994 d->updateDisplayText();
3998 void QQuickTextInputPrivate::processKeyEvent(QKeyEvent* event)
4000 Q_Q(QQuickTextInput);
4001 bool inlineCompletionAccepted = false;
4003 if (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return) {
4004 if (hasAcceptableInput(m_text) || fixup()) {
4007 if (inlineCompletionAccepted)
4014 if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit
4015 && !m_passwordEchoEditing
4017 && !event->text().isEmpty()
4018 && !(event->modifiers() & Qt::ControlModifier)) {
4019 // Clear the edit and reset to normal echo mode while editing; the
4020 // echo mode switches back when the edit loses focus
4021 // ### resets current content. dubious code; you can
4022 // navigate with keys up, down, back, and select(?), but if you press
4023 // "left" or "right" it clears?
4024 updatePasswordEchoEditing(true);
4028 bool unknown = false;
4029 bool visual = cursorMoveStyle() == Qt::VisualMoveStyle;
4033 #ifndef QT_NO_SHORTCUT
4034 else if (event == QKeySequence::Undo) {
4037 else if (event == QKeySequence::Redo) {
4040 else if (event == QKeySequence::SelectAll) {
4043 #ifndef QT_NO_CLIPBOARD
4044 else if (event == QKeySequence::Copy) {
4047 else if (event == QKeySequence::Paste) {
4049 QClipboard::Mode mode = QClipboard::Clipboard;
4053 else if (event == QKeySequence::Cut) {
4059 else if (event == QKeySequence::DeleteEndOfLine) {
4061 setSelection(m_cursor, end());
4066 #endif //QT_NO_CLIPBOARD
4067 else if (event == QKeySequence::MoveToStartOfLine || event == QKeySequence::MoveToStartOfBlock) {
4070 else if (event == QKeySequence::MoveToEndOfLine || event == QKeySequence::MoveToEndOfBlock) {
4073 else if (event == QKeySequence::SelectStartOfLine || event == QKeySequence::SelectStartOfBlock) {
4076 else if (event == QKeySequence::SelectEndOfLine || event == QKeySequence::SelectEndOfBlock) {
4079 else if (event == QKeySequence::MoveToNextChar) {
4080 if (hasSelectedText()) {
4081 moveCursor(selectionEnd(), false);
4083 cursorForward(0, visual ? 1 : (layoutDirection() == Qt::LeftToRight ? 1 : -1));
4086 else if (event == QKeySequence::SelectNextChar) {
4087 cursorForward(1, visual ? 1 : (layoutDirection() == Qt::LeftToRight ? 1 : -1));
4089 else if (event == QKeySequence::MoveToPreviousChar) {
4090 if (hasSelectedText()) {
4091 moveCursor(selectionStart(), false);
4093 cursorForward(0, visual ? -1 : (layoutDirection() == Qt::LeftToRight ? -1 : 1));
4096 else if (event == QKeySequence::SelectPreviousChar) {
4097 cursorForward(1, visual ? -1 : (layoutDirection() == Qt::LeftToRight ? -1 : 1));
4099 else if (event == QKeySequence::MoveToNextWord) {
4100 if (m_echoMode == QQuickTextInput::Normal)
4101 layoutDirection() == Qt::LeftToRight ? cursorWordForward(0) : cursorWordBackward(0);
4103 layoutDirection() == Qt::LeftToRight ? end(0) : home(0);
4105 else if (event == QKeySequence::MoveToPreviousWord) {
4106 if (m_echoMode == QQuickTextInput::Normal)
4107 layoutDirection() == Qt::LeftToRight ? cursorWordBackward(0) : cursorWordForward(0);
4108 else if (!m_readOnly) {
4109 layoutDirection() == Qt::LeftToRight ? home(0) : end(0);
4112 else if (event == QKeySequence::SelectNextWord) {
4113 if (m_echoMode == QQuickTextInput::Normal)
4114 layoutDirection() == Qt::LeftToRight ? cursorWordForward(1) : cursorWordBackward(1);
4116 layoutDirection() == Qt::LeftToRight ? end(1) : home(1);
4118 else if (event == QKeySequence::SelectPreviousWord) {
4119 if (m_echoMode == QQuickTextInput::Normal)
4120 layoutDirection() == Qt::LeftToRight ? cursorWordBackward(1) : cursorWordForward(1);
4122 layoutDirection() == Qt::LeftToRight ? home(1) : end(1);
4124 else if (event == QKeySequence::Delete) {
4128 else if (event == QKeySequence::DeleteEndOfWord) {
4130 cursorWordForward(true);
4134 else if (event == QKeySequence::DeleteStartOfWord) {
4136 cursorWordBackward(true);
4140 #endif // QT_NO_SHORTCUT
4142 bool handled = false;
4143 if (event->modifiers() & Qt::ControlModifier) {
4144 switch (event->key()) {
4145 case Qt::Key_Backspace:
4147 cursorWordBackward(true);
4155 } else { // ### check for *no* modifier
4156 switch (event->key()) {
4157 case Qt::Key_Backspace:
4169 if (event->key() == Qt::Key_Direction_L || event->key() == Qt::Key_Direction_R) {
4170 setLayoutDirection((event->key() == Qt::Key_Direction_L) ? Qt::LeftToRight : Qt::RightToLeft);
4174 if (unknown && !m_readOnly) {
4175 QString t = event->text();
4176 if (!t.isEmpty() && t.at(0).isPrint()) {