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 "qquickwindow.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)
70 \instantiates QQuickTextInput
71 \inqmlmodule QtQuick 2
72 \ingroup qtquick-visual
73 \ingroup qtquick-input
75 \brief Displays an editable line of text
77 The TextInput type displays a single line of editable plain text.
79 TextInput is used to accept a line of text input. Input constraints
80 can be placed on a TextInput item (for example, through a \l validator or \l inputMask),
81 and setting \l echoMode to an appropriate value enables TextInput to be used for
82 a password input field.
84 On Mac OS X, the Up/Down key bindings for Home/End are explicitly disabled.
85 If you want such bindings (on any platform), you will need to construct them in QML.
87 \sa TextEdit, Text, {declarative/text/textselection}{Text Selection example}
89 QQuickTextInput::QQuickTextInput(QQuickItem* parent)
90 : QQuickImplicitSizeItem(*(new QQuickTextInputPrivate), parent)
96 QQuickTextInput::~QQuickTextInput()
100 void QQuickTextInput::componentComplete()
102 Q_D(QQuickTextInput);
104 QQuickImplicitSizeItem::componentComplete();
108 updateCursorRectangle();
109 if (d->cursorComponent && isCursorVisible())
110 QQuickTextUtil::createCursor(d);
114 \qmlproperty string QtQuick2::TextInput::text
116 The text in the TextInput.
118 QString QQuickTextInput::text() const
120 Q_D(const QQuickTextInput);
122 QString content = d->m_text;
123 QString res = d->m_maskData ? d->stripString(content) : content;
124 return (res.isNull() ? QString::fromLatin1("") : res);
127 void QQuickTextInput::setText(const QString &s)
129 Q_D(QQuickTextInput);
134 d->internalSetText(s, -1, false);
139 \qmlproperty enumeration QtQuick2::TextInput::renderType
141 Override the default rendering type for this component.
143 Supported render types are:
145 \li Text.QtRendering - the default
146 \li Text.NativeRendering
149 Select Text.NativeRendering if you prefer text to look native on the target platform and do
150 not require advanced features such as transformation of the text. Using such features in
151 combination with the NativeRendering render type will lend poor and sometimes pixelated
154 QQuickTextInput::RenderType QQuickTextInput::renderType() const
156 Q_D(const QQuickTextInput);
157 return d->renderType;
160 void QQuickTextInput::setRenderType(QQuickTextInput::RenderType renderType)
162 Q_D(QQuickTextInput);
163 if (d->renderType == renderType)
166 d->renderType = renderType;
167 emit renderTypeChanged();
169 if (isComponentComplete())
174 \qmlproperty int QtQuick2::TextInput::length
176 Returns the total number of characters in the TextInput item.
178 If the TextInput has an inputMask the length will include mask characters and may differ
179 from the length of the string returned by the \l text property.
181 This property can be faster than querying the length the \l text property as it doesn't
182 require any copying or conversion of the TextInput's internal string data.
185 int QQuickTextInput::length() const
187 Q_D(const QQuickTextInput);
188 return d->m_text.length();
192 \qmlmethod string QtQuick2::TextInput::getText(int start, int end)
194 Returns the section of text that is between the \a start and \a end positions.
196 If the TextInput has an inputMask the length will include mask characters.
199 QString QQuickTextInput::getText(int start, int end) const
201 Q_D(const QQuickTextInput);
206 return d->m_text.mid(start, end - start);
209 QString QQuickTextInputPrivate::realText() const
211 QString res = m_maskData ? stripString(m_text) : m_text;
212 return (res.isNull() ? QString::fromLatin1("") : res);
216 \qmlproperty string QtQuick2::TextInput::font.family
218 Sets the family name of the font.
220 The family name is case insensitive and may optionally include a foundry name, e.g. "Helvetica [Cronyx]".
221 If the family is available from more than one foundry and the foundry isn't specified, an arbitrary foundry is chosen.
222 If the family isn't available a family will be set using the font matching algorithm.
226 \qmlproperty bool QtQuick2::TextInput::font.bold
228 Sets whether the font weight is bold.
232 \qmlproperty enumeration QtQuick2::TextInput::font.weight
234 Sets the font's weight.
236 The weight can be one of:
239 \li Font.Normal - the default
246 TextInput { text: "Hello"; font.weight: Font.DemiBold }
251 \qmlproperty bool QtQuick2::TextInput::font.italic
253 Sets whether the font has an italic style.
257 \qmlproperty bool QtQuick2::TextInput::font.underline
259 Sets whether the text is underlined.
263 \qmlproperty bool QtQuick2::TextInput::font.strikeout
265 Sets whether the font has a strikeout style.
269 \qmlproperty real QtQuick2::TextInput::font.pointSize
271 Sets the font size in points. The point size must be greater than zero.
275 \qmlproperty int QtQuick2::TextInput::font.pixelSize
277 Sets the font size in pixels.
279 Using this function makes the font device dependent.
280 Use \c pointSize to set the size of the font in a device independent manner.
284 \qmlproperty real QtQuick2::TextInput::font.letterSpacing
286 Sets the letter spacing for the font.
288 Letter spacing changes the default spacing between individual letters in the font.
289 A positive value increases the letter spacing by the corresponding pixels; a negative value decreases the spacing.
293 \qmlproperty real QtQuick2::TextInput::font.wordSpacing
295 Sets the word spacing for the font.
297 Word spacing changes the default spacing between individual words.
298 A positive value increases the word spacing by a corresponding amount of pixels,
299 while a negative value decreases the inter-word spacing accordingly.
303 \qmlproperty enumeration QtQuick2::TextInput::font.capitalization
305 Sets the capitalization for the text.
308 \li Font.MixedCase - This is the normal text rendering option where no capitalization change is applied.
309 \li Font.AllUppercase - This alters the text to be rendered in all uppercase type.
310 \li Font.AllLowercase - This alters the text to be rendered in all lowercase type.
311 \li Font.SmallCaps - This alters the text to be rendered in small-caps type.
312 \li Font.Capitalize - This alters the text to be rendered with the first character of each word as an uppercase character.
316 TextInput { text: "Hello"; font.capitalization: Font.AllLowercase }
320 QFont QQuickTextInput::font() const
322 Q_D(const QQuickTextInput);
323 return d->sourceFont;
326 void QQuickTextInput::setFont(const QFont &font)
328 Q_D(QQuickTextInput);
329 if (d->sourceFont == font)
332 d->sourceFont = font;
333 QFont oldFont = d->font;
335 if (d->font.pointSizeF() != -1) {
337 qreal size = qRound(d->font.pointSizeF()*2.0);
338 d->font.setPointSizeF(size/2.0);
340 if (oldFont != d->font) {
342 updateCursorRectangle();
343 updateInputMethod(Qt::ImCursorRectangle | Qt::ImFont);
345 emit fontChanged(d->sourceFont);
349 \qmlproperty color QtQuick2::TextInput::color
353 QColor QQuickTextInput::color() const
355 Q_D(const QQuickTextInput);
359 void QQuickTextInput::setColor(const QColor &c)
361 Q_D(QQuickTextInput);
364 d->textLayoutDirty = true;
365 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
373 \qmlproperty color QtQuick2::TextInput::selectionColor
375 The text highlight color, used behind selections.
377 QColor QQuickTextInput::selectionColor() const
379 Q_D(const QQuickTextInput);
380 return d->selectionColor;
383 void QQuickTextInput::setSelectionColor(const QColor &color)
385 Q_D(QQuickTextInput);
386 if (d->selectionColor == color)
389 d->selectionColor = color;
390 if (d->hasSelectedText()) {
391 d->textLayoutDirty = true;
392 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
395 emit selectionColorChanged();
398 \qmlproperty color QtQuick2::TextInput::selectedTextColor
400 The highlighted text color, used in selections.
402 QColor QQuickTextInput::selectedTextColor() const
404 Q_D(const QQuickTextInput);
405 return d->selectedTextColor;
408 void QQuickTextInput::setSelectedTextColor(const QColor &color)
410 Q_D(QQuickTextInput);
411 if (d->selectedTextColor == color)
414 d->selectedTextColor = color;
415 if (d->hasSelectedText()) {
416 d->textLayoutDirty = true;
417 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
420 emit selectedTextColorChanged();
424 \qmlproperty enumeration QtQuick2::TextInput::horizontalAlignment
425 \qmlproperty enumeration QtQuick2::TextInput::effectiveHorizontalAlignment
426 \qmlproperty enumeration QtQuick2::TextInput::verticalAlignment
428 Sets the horizontal alignment of the text within the TextInput item's
429 width and height. By default, the text alignment follows the natural alignment
430 of the text, for example text that is read from left to right will be aligned to
433 TextInput does not have vertical alignment, as the natural height is
434 exactly the height of the single line of text. If you set the height
435 manually to something larger, TextInput will always be top aligned
436 vertically. You can use anchors to align it however you want within
439 The valid values for \c horizontalAlignment are \c TextInput.AlignLeft, \c TextInput.AlignRight and
440 \c TextInput.AlignHCenter.
442 Valid values for \c verticalAlignment are \c TextInput.AlignTop (default),
443 \c TextInput.AlignBottom \c TextInput.AlignVCenter.
445 When using the attached property LayoutMirroring::enabled to mirror application
446 layouts, the horizontal alignment of text will also be mirrored. However, the property
447 \c horizontalAlignment will remain unchanged. To query the effective horizontal alignment
448 of TextInput, use the read-only property \c effectiveHorizontalAlignment.
450 QQuickTextInput::HAlignment QQuickTextInput::hAlign() const
452 Q_D(const QQuickTextInput);
456 void QQuickTextInput::setHAlign(HAlignment align)
458 Q_D(QQuickTextInput);
459 bool forceAlign = d->hAlignImplicit && d->effectiveLayoutMirror;
460 d->hAlignImplicit = false;
461 if (d->setHAlign(align, forceAlign) && isComponentComplete()) {
463 updateCursorRectangle();
467 void QQuickTextInput::resetHAlign()
469 Q_D(QQuickTextInput);
470 d->hAlignImplicit = true;
471 if (d->determineHorizontalAlignment() && isComponentComplete()) {
473 updateCursorRectangle();
477 QQuickTextInput::HAlignment QQuickTextInput::effectiveHAlign() const
479 Q_D(const QQuickTextInput);
480 QQuickTextInput::HAlignment effectiveAlignment = d->hAlign;
481 if (!d->hAlignImplicit && d->effectiveLayoutMirror) {
483 case QQuickTextInput::AlignLeft:
484 effectiveAlignment = QQuickTextInput::AlignRight;
486 case QQuickTextInput::AlignRight:
487 effectiveAlignment = QQuickTextInput::AlignLeft;
493 return effectiveAlignment;
496 bool QQuickTextInputPrivate::setHAlign(QQuickTextInput::HAlignment alignment, bool forceAlign)
498 Q_Q(QQuickTextInput);
499 if ((hAlign != alignment || forceAlign) && alignment <= QQuickTextInput::AlignHCenter) { // justify not supported
500 QQuickTextInput::HAlignment oldEffectiveHAlign = q->effectiveHAlign();
502 emit q->horizontalAlignmentChanged(alignment);
503 if (oldEffectiveHAlign != q->effectiveHAlign())
504 emit q->effectiveHorizontalAlignmentChanged();
510 Qt::LayoutDirection QQuickTextInputPrivate::textDirection() const
512 QString text = m_text;
514 text = m_textLayout.preeditAreaText();
516 const QChar *character = text.constData();
517 while (!character->isNull()) {
518 switch (character->direction()) {
520 return Qt::LeftToRight;
524 return Qt::RightToLeft;
530 return Qt::LayoutDirectionAuto;
533 Qt::LayoutDirection QQuickTextInputPrivate::layoutDirection() const
535 Qt::LayoutDirection direction = m_layoutDirection;
536 if (direction == Qt::LayoutDirectionAuto) {
537 direction = textDirection();
538 if (direction == Qt::LayoutDirectionAuto)
539 direction = qApp->inputMethod()->inputDirection();
541 return (direction == Qt::LayoutDirectionAuto) ? Qt::LeftToRight : direction;
544 bool QQuickTextInputPrivate::determineHorizontalAlignment()
546 if (hAlignImplicit) {
547 // if no explicit alignment has been set, follow the natural layout direction of the text
548 Qt::LayoutDirection direction = textDirection();
549 if (direction == Qt::LayoutDirectionAuto)
550 direction = qApp->inputMethod()->inputDirection();
551 return setHAlign(direction == Qt::RightToLeft ? QQuickTextInput::AlignRight : QQuickTextInput::AlignLeft);
556 QQuickTextInput::VAlignment QQuickTextInput::vAlign() const
558 Q_D(const QQuickTextInput);
562 void QQuickTextInput::setVAlign(QQuickTextInput::VAlignment alignment)
564 Q_D(QQuickTextInput);
565 if (alignment == d->vAlign)
567 d->vAlign = alignment;
568 emit verticalAlignmentChanged(d->vAlign);
569 if (isComponentComplete()) {
570 updateCursorRectangle();
575 \qmlproperty enumeration QtQuick2::TextInput::wrapMode
577 Set this property to wrap the text to the TextInput item's width.
578 The text will only wrap if an explicit width has been set.
581 \li TextInput.NoWrap - no wrapping will be performed. If the text contains insufficient newlines, then implicitWidth will exceed a set width.
582 \li TextInput.WordWrap - wrapping is done on word boundaries only. If a word is too long, implicitWidth will exceed a set width.
583 \li TextInput.WrapAnywhere - wrapping is done at any point on a line, even if it occurs in the middle of a word.
584 \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.
587 The default is TextInput.NoWrap. If you set a width, consider using TextInput.Wrap.
589 QQuickTextInput::WrapMode QQuickTextInput::wrapMode() const
591 Q_D(const QQuickTextInput);
595 void QQuickTextInput::setWrapMode(WrapMode mode)
597 Q_D(QQuickTextInput);
598 if (mode == d->wrapMode)
602 updateCursorRectangle();
603 emit wrapModeChanged();
606 void QQuickTextInputPrivate::mirrorChange()
608 Q_Q(QQuickTextInput);
609 if (q->isComponentComplete()) {
610 if (!hAlignImplicit && (hAlign == QQuickTextInput::AlignRight || hAlign == QQuickTextInput::AlignLeft)) {
611 q->updateCursorRectangle();
612 emit q->effectiveHorizontalAlignmentChanged();
618 \qmlproperty bool QtQuick2::TextInput::readOnly
620 Sets whether user input can modify the contents of the TextInput.
622 If readOnly is set to true, then user input will not affect the text
623 property. Any bindings or attempts to set the text property will still
626 bool QQuickTextInput::isReadOnly() const
628 Q_D(const QQuickTextInput);
629 return d->m_readOnly;
632 void QQuickTextInput::setReadOnly(bool ro)
634 Q_D(QQuickTextInput);
635 if (d->m_readOnly == ro)
638 setFlag(QQuickItem::ItemAcceptsInputMethod, !ro);
641 d->setCursorPosition(d->end());
642 updateInputMethod(Qt::ImEnabled);
644 d->emitUndoRedoChanged();
645 emit readOnlyChanged(ro);
649 \qmlproperty int QtQuick2::TextInput::maximumLength
650 The maximum permitted length of the text in the TextInput.
652 If the text is too long, it is truncated at the limit.
654 By default, this property contains a value of 32767.
656 int QQuickTextInput::maxLength() const
658 Q_D(const QQuickTextInput);
659 return d->m_maxLength;
662 void QQuickTextInput::setMaxLength(int ml)
664 Q_D(QQuickTextInput);
665 if (d->m_maxLength == ml || d->m_maskData)
669 d->internalSetText(d->m_text, -1, false);
671 emit maximumLengthChanged(ml);
675 \qmlproperty bool QtQuick2::TextInput::cursorVisible
676 Set to true when the TextInput shows a cursor.
678 This property is set and unset when the TextInput gets active focus, so that other
679 properties can be bound to whether the cursor is currently showing. As it
680 gets set and unset automatically, when you set the value yourself you must
681 keep in mind that your value may be overwritten.
683 It can be set directly in script, for example if a KeyProxy might
684 forward keys to it and you desire it to look active when this happens
685 (but without actually giving it active focus).
687 It should not be set directly on the item, like in the below QML,
688 as the specified value will be overridden an lost on focus changes.
697 In the above snippet the cursor will still become visible when the
698 TextInput gains active focus.
700 bool QQuickTextInput::isCursorVisible() const
702 Q_D(const QQuickTextInput);
703 return d->cursorVisible;
706 void QQuickTextInput::setCursorVisible(bool on)
708 Q_D(QQuickTextInput);
709 if (d->cursorVisible == on)
711 d->cursorVisible = on;
712 if (on && isComponentComplete())
713 QQuickTextUtil::createCursor(d);
714 if (!d->cursorItem) {
715 d->setCursorBlinkPeriod(on ? qApp->styleHints()->cursorFlashTime() : 0);
716 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
719 emit cursorVisibleChanged(d->cursorVisible);
723 \qmlproperty int QtQuick2::TextInput::cursorPosition
724 The position of the cursor in the TextInput.
726 int QQuickTextInput::cursorPosition() const
728 Q_D(const QQuickTextInput);
732 void QQuickTextInput::setCursorPosition(int cp)
734 Q_D(QQuickTextInput);
735 if (cp < 0 || cp > text().length())
741 \qmlproperty rectangle QtQuick2::TextInput::cursorRectangle
743 The rectangle where the standard text cursor is rendered within the text input. Read only.
745 The position and height of a custom cursorDelegate are updated to follow the cursorRectangle
746 automatically when it changes. The width of the delegate is unaffected by changes in the
750 QRectF QQuickTextInput::cursorRectangle() const
752 Q_D(const QQuickTextInput);
754 int c = d->m_cursor + d->m_preeditCursor;
755 if (d->m_echoMode == NoEcho)
757 QTextLine l = d->m_textLayout.lineForTextPosition(c);
760 return QRectF(l.cursorToX(c) - d->hscroll, l.y() - d->vscroll, 1, l.height());
764 \qmlproperty int QtQuick2::TextInput::selectionStart
766 The cursor position before the first character in the current selection.
768 This property is read-only. To change the selection, use select(start,end),
769 selectAll(), or selectWord().
771 \sa selectionEnd, cursorPosition, selectedText
773 int QQuickTextInput::selectionStart() const
775 Q_D(const QQuickTextInput);
776 return d->lastSelectionStart;
779 \qmlproperty int QtQuick2::TextInput::selectionEnd
781 The cursor position after the last character in the current selection.
783 This property is read-only. To change the selection, use select(start,end),
784 selectAll(), or selectWord().
786 \sa selectionStart, cursorPosition, selectedText
788 int QQuickTextInput::selectionEnd() const
790 Q_D(const QQuickTextInput);
791 return d->lastSelectionEnd;
794 \qmlmethod QtQuick2::TextInput::select(int start, int end)
796 Causes the text from \a start to \a end to be selected.
798 If either start or end is out of range, the selection is not changed.
800 After calling this, selectionStart will become the lesser
801 and selectionEnd will become the greater (regardless of the order passed
804 \sa selectionStart, selectionEnd
806 void QQuickTextInput::select(int start, int end)
808 Q_D(QQuickTextInput);
809 if (start < 0 || end < 0 || start > d->m_text.length() || end > d->m_text.length())
811 d->setSelection(start, end-start);
815 \qmlproperty string QtQuick2::TextInput::selectedText
817 This read-only property provides the text currently selected in the
820 It is equivalent to the following snippet, but is faster and easier
824 myTextInput.text.toString().substring(myTextInput.selectionStart,
825 myTextInput.selectionEnd);
828 QString QQuickTextInput::selectedText() const
830 Q_D(const QQuickTextInput);
831 return d->selectedText();
835 \qmlproperty bool QtQuick2::TextInput::activeFocusOnPress
837 Whether the TextInput should gain active focus on a mouse press. By default this is
840 bool QQuickTextInput::focusOnPress() const
842 Q_D(const QQuickTextInput);
843 return d->focusOnPress;
846 void QQuickTextInput::setFocusOnPress(bool b)
848 Q_D(QQuickTextInput);
849 if (d->focusOnPress == b)
854 emit activeFocusOnPressChanged(d->focusOnPress);
857 \qmlproperty bool QtQuick2::TextInput::autoScroll
859 Whether the TextInput should scroll when the text is longer than the width. By default this is
862 bool QQuickTextInput::autoScroll() const
864 Q_D(const QQuickTextInput);
865 return d->autoScroll;
868 void QQuickTextInput::setAutoScroll(bool b)
870 Q_D(QQuickTextInput);
871 if (d->autoScroll == b)
875 //We need to repaint so that the scrolling is taking into account.
876 updateCursorRectangle();
877 emit autoScrollChanged(d->autoScroll);
880 #ifndef QT_NO_VALIDATOR
883 \qmltype IntValidator
884 \instantiates QIntValidator
885 \inqmlmodule QtQuick 2
886 \ingroup qtquick-text-utility
887 \brief Defines a validator for integer values
889 The IntValidator type provides a validator for integer values.
891 If no \l locale is set IntValidator uses the \l {QLocale::setDefault()}{default locale} to
892 interpret the number and will accept locale specific digits, group separators, and positive
893 and negative signs. In addition, IntValidator is always guaranteed to accept a number
894 formatted according to the "C" locale.
898 QQuickIntValidator::QQuickIntValidator(QObject *parent)
899 : QIntValidator(parent)
904 \qmlproperty string QtQuick2::IntValidator::locale
906 This property holds the name of the locale used to interpret the number.
911 QString QQuickIntValidator::localeName() const
913 return locale().name();
916 void QQuickIntValidator::setLocaleName(const QString &name)
918 if (locale().name() != name) {
919 setLocale(QLocale(name));
920 emit localeNameChanged();
924 void QQuickIntValidator::resetLocaleName()
926 QLocale defaultLocale;
927 if (locale() != defaultLocale) {
928 setLocale(defaultLocale);
929 emit localeNameChanged();
934 \qmlproperty int QtQuick2::IntValidator::top
936 This property holds the validator's highest acceptable value.
937 By default, this property's value is derived from the highest signed integer available (typically 2147483647).
940 \qmlproperty int QtQuick2::IntValidator::bottom
942 This property holds the validator's lowest acceptable value.
943 By default, this property's value is derived from the lowest signed integer available (typically -2147483647).
947 \qmltype DoubleValidator
948 \instantiates QDoubleValidator
949 \inqmlmodule QtQuick 2
950 \ingroup qtquick-text-utility
951 \brief Defines a validator for non-integer numbers
953 The DoubleValidator type provides a validator for non-integer numbers.
955 Input is accepted if it contains a double that is within the valid range
956 and is in the correct format.
958 Input is accepected but invalid if it contains a double that is outside
959 the range or is in the wrong format; e.g. with too many digits after the
960 decimal point or is empty.
962 Input is rejected if it is not a double.
964 Note: If the valid range consists of just positive doubles (e.g. 0.0 to
965 100.0) and input is a negative double then it is rejected. If \l notation
966 is set to DoubleValidator.StandardNotation, and the input contains more
967 digits before the decimal point than a double in the valid range may have,
968 it is also rejected. If \l notation is DoubleValidator.ScientificNotation,
969 and the input is not in the valid range, it is accecpted but invalid. The
970 value may yet become valid by changing the exponent.
973 QQuickDoubleValidator::QQuickDoubleValidator(QObject *parent)
974 : QDoubleValidator(parent)
979 \qmlproperty string QtQuick2::DoubleValidator::locale
981 This property holds the name of the locale used to interpret the number.
986 QString QQuickDoubleValidator::localeName() const
988 return locale().name();
991 void QQuickDoubleValidator::setLocaleName(const QString &name)
993 if (locale().name() != name) {
994 setLocale(QLocale(name));
995 emit localeNameChanged();
999 void QQuickDoubleValidator::resetLocaleName()
1001 QLocale defaultLocale;
1002 if (locale() != defaultLocale) {
1003 setLocale(defaultLocale);
1004 emit localeNameChanged();
1009 \qmlproperty real QtQuick2::DoubleValidator::top
1011 This property holds the validator's maximum acceptable value.
1012 By default, this property contains a value of infinity.
1015 \qmlproperty real QtQuick2::DoubleValidator::bottom
1017 This property holds the validator's minimum acceptable value.
1018 By default, this property contains a value of -infinity.
1021 \qmlproperty int QtQuick2::DoubleValidator::decimals
1023 This property holds the validator's maximum number of digits after the decimal point.
1024 By default, this property contains a value of 1000.
1027 \qmlproperty enumeration QtQuick2::DoubleValidator::notation
1028 This property holds the notation of how a string can describe a number.
1030 The possible values for this property are:
1033 \li DoubleValidator.StandardNotation
1034 \li DoubleValidator.ScientificNotation (default)
1037 If this property is set to DoubleValidator.ScientificNotation, the written number may have an exponent part (e.g. 1.5E-2).
1041 \qmltype RegExpValidator
1042 \instantiates QRegExpValidator
1043 \inqmlmodule QtQuick 2
1044 \ingroup qtquick-text-utility
1045 \brief Provides a string validator
1047 The RegExpValidator type provides a validator, which counts as valid any string which
1048 matches a specified regular expression.
1051 \qmlproperty regExp QtQuick2::RegExpValidator::regExp
1053 This property holds the regular expression used for validation.
1055 Note that this property should be a regular expression in JS syntax, e.g /a/ for the regular expression
1058 By default, this property contains a regular expression with the pattern .* that matches any string.
1062 \qmlproperty Validator QtQuick2::TextInput::validator
1064 Allows you to set a validator on the TextInput. When a validator is set
1065 the TextInput will only accept input which leaves the text property in
1066 an acceptable or intermediate state. The accepted signal will only be sent
1067 if the text is in an acceptable state when enter is pressed.
1069 Currently supported validators are IntValidator, DoubleValidator and
1070 RegExpValidator. An example of using validators is shown below, which allows
1071 input of integers between 11 and 31 into the text input:
1076 validator: IntValidator{bottom: 11; top: 31;}
1081 \sa acceptableInput, inputMask
1084 QValidator* QQuickTextInput::validator() const
1086 Q_D(const QQuickTextInput);
1087 return d->m_validator;
1090 void QQuickTextInput::setValidator(QValidator* v)
1092 Q_D(QQuickTextInput);
1093 if (d->m_validator == v)
1096 if (d->m_validator) {
1097 qmlobject_disconnect(
1098 d->m_validator, QValidator, SIGNAL(changed()),
1099 this, QQuickTextInput, SLOT(q_validatorChanged()));
1104 if (d->m_validator) {
1106 d->m_validator, QValidator, SIGNAL(changed()),
1107 this, QQuickTextInput, SLOT(q_validatorChanged()));
1110 if (isComponentComplete())
1113 emit validatorChanged();
1116 void QQuickTextInput::q_validatorChanged()
1118 Q_D(QQuickTextInput);
1122 #endif // QT_NO_VALIDATOR
1124 void QQuickTextInputPrivate::checkIsValid()
1126 Q_Q(QQuickTextInput);
1128 ValidatorState state = hasAcceptableInput(m_text);
1129 m_validInput = state != InvalidInput;
1130 if (state != AcceptableInput) {
1131 if (m_acceptableInput) {
1132 m_acceptableInput = false;
1133 emit q->acceptableInputChanged();
1135 } else if (!m_acceptableInput) {
1136 m_acceptableInput = true;
1137 emit q->acceptableInputChanged();
1142 \qmlproperty string QtQuick2::TextInput::inputMask
1144 Allows you to set an input mask on the TextInput, restricting the allowable
1145 text inputs. See QLineEdit::inputMask for further details, as the exact
1146 same mask strings are used by TextInput.
1148 \sa acceptableInput, validator
1150 QString QQuickTextInput::inputMask() const
1152 Q_D(const QQuickTextInput);
1153 return d->inputMask();
1156 void QQuickTextInput::setInputMask(const QString &im)
1158 Q_D(QQuickTextInput);
1159 if (d->inputMask() == im)
1162 d->setInputMask(im);
1163 emit inputMaskChanged(d->inputMask());
1167 \qmlproperty bool QtQuick2::TextInput::acceptableInput
1169 This property is always true unless a validator or input mask has been set.
1170 If a validator or input mask has been set, this property will only be true
1171 if the current text is acceptable to the validator or input mask as a final
1172 string (not as an intermediate string).
1174 bool QQuickTextInput::hasAcceptableInput() const
1176 Q_D(const QQuickTextInput);
1177 return d->hasAcceptableInput(d->m_text) == QQuickTextInputPrivate::AcceptableInput;
1181 \qmlsignal QtQuick2::TextInput::onAccepted()
1183 This handler is called when the Return or Enter key is pressed.
1184 Note that if there is a \l validator or \l inputMask set on the text
1185 input, the handler will only be emitted if the input is in an acceptable
1189 Qt::InputMethodHints QQuickTextInputPrivate::effectiveInputMethodHints() const
1191 Qt::InputMethodHints hints = inputMethodHints;
1192 if (m_echoMode == QQuickTextInput::Password || m_echoMode == QQuickTextInput::NoEcho)
1193 hints |= Qt::ImhHiddenText;
1194 else if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit)
1195 hints &= ~Qt::ImhHiddenText;
1196 if (m_echoMode != QQuickTextInput::Normal)
1197 hints |= (Qt::ImhNoAutoUppercase | Qt::ImhNoPredictiveText | Qt::ImhSensitiveData);
1201 \qmlproperty enumeration QtQuick2::TextInput::echoMode
1203 Specifies how the text should be displayed in the TextInput.
1205 \li TextInput.Normal - Displays the text as it is. (Default)
1206 \li TextInput.Password - Displays asterisks instead of characters.
1207 \li TextInput.NoEcho - Displays nothing.
1208 \li TextInput.PasswordEchoOnEdit - Displays characters as they are entered
1209 while editing, otherwise displays asterisks.
1212 QQuickTextInput::EchoMode QQuickTextInput::echoMode() const
1214 Q_D(const QQuickTextInput);
1215 return QQuickTextInput::EchoMode(d->m_echoMode);
1218 void QQuickTextInput::setEchoMode(QQuickTextInput::EchoMode echo)
1220 Q_D(QQuickTextInput);
1221 if (echoMode() == echo)
1223 d->cancelPasswordEchoTimer();
1224 d->m_echoMode = echo;
1225 d->m_passwordEchoEditing = false;
1226 updateInputMethod(Qt::ImHints);
1227 d->updateDisplayText();
1228 updateCursorRectangle();
1230 emit echoModeChanged(echoMode());
1234 \qmlproperty enumeration QtQuick2::TextInput::inputMethodHints
1236 Provides hints to the input method about the expected content of the text input and how it
1239 The value is a bit-wise combination of flags, or Qt.ImhNone if no hints are set.
1241 Flags that alter behaviour are:
1244 \li Qt.ImhHiddenText - Characters should be hidden, as is typically used when entering passwords.
1245 This is automatically set when setting echoMode to \c TextInput.Password.
1246 \li Qt.ImhSensitiveData - Typed text should not be stored by the active input method
1247 in any persistent storage like predictive user dictionary.
1248 \li Qt.ImhNoAutoUppercase - The input method should not try to automatically switch to upper case
1249 when a sentence ends.
1250 \li Qt.ImhPreferNumbers - Numbers are preferred (but not required).
1251 \li Qt.ImhPreferUppercase - Upper case letters are preferred (but not required).
1252 \li Qt.ImhPreferLowercase - Lower case letters are preferred (but not required).
1253 \li Qt.ImhNoPredictiveText - Do not use predictive text (i.e. dictionary lookup) while typing.
1255 \li Qt.ImhDate - The text editor functions as a date field.
1256 \li Qt.ImhTime - The text editor functions as a time field.
1259 Flags that restrict input (exclusive flags) are:
1262 \li Qt.ImhDigitsOnly - Only digits are allowed.
1263 \li Qt.ImhFormattedNumbersOnly - Only number input is allowed. This includes decimal point and minus sign.
1264 \li Qt.ImhUppercaseOnly - Only upper case letter input is allowed.
1265 \li Qt.ImhLowercaseOnly - Only lower case letter input is allowed.
1266 \li Qt.ImhDialableCharactersOnly - Only characters suitable for phone dialing are allowed.
1267 \li Qt.ImhEmailCharactersOnly - Only characters suitable for email addresses are allowed.
1268 \li Qt.ImhUrlCharactersOnly - Only characters suitable for URLs are allowed.
1274 \li Qt.ImhExclusiveInputMask - This mask yields nonzero if any of the exclusive flags are used.
1278 Qt::InputMethodHints QQuickTextInput::inputMethodHints() const
1280 Q_D(const QQuickTextInput);
1281 return d->inputMethodHints;
1284 void QQuickTextInput::setInputMethodHints(Qt::InputMethodHints hints)
1286 Q_D(QQuickTextInput);
1288 if (hints == d->inputMethodHints)
1291 d->inputMethodHints = hints;
1292 updateInputMethod(Qt::ImHints);
1293 emit inputMethodHintsChanged();
1297 \qmlproperty Component QtQuick2::TextInput::cursorDelegate
1298 The delegate for the cursor in the TextInput.
1300 If you set a cursorDelegate for a TextInput, this delegate will be used for
1301 drawing the cursor instead of the standard cursor. An instance of the
1302 delegate will be created and managed by the TextInput when a cursor is
1303 needed, and the x property of delegate instance will be set so as
1304 to be one pixel before the top left of the current character.
1306 Note that the root item of the delegate component must be a QQuickItem or
1307 QQuickItem derived item.
1309 QQmlComponent* QQuickTextInput::cursorDelegate() const
1311 Q_D(const QQuickTextInput);
1312 return d->cursorComponent;
1315 void QQuickTextInput::setCursorDelegate(QQmlComponent* c)
1317 Q_D(QQuickTextInput);
1318 QQuickTextUtil::setCursorDelegate(d, c);
1321 void QQuickTextInput::createCursor()
1323 Q_D(QQuickTextInput);
1324 d->cursorPending = true;
1325 QQuickTextUtil::createCursor(d);
1329 \qmlmethod rect QtQuick2::TextInput::positionToRectangle(int pos)
1331 This function takes a character position and returns the rectangle that the
1332 cursor would occupy, if it was placed at that character position.
1334 This is similar to setting the cursorPosition, and then querying the cursor
1335 rectangle, but the cursorPosition is not changed.
1337 QRectF QQuickTextInput::positionToRectangle(int pos) const
1339 Q_D(const QQuickTextInput);
1340 if (d->m_echoMode == NoEcho)
1342 else if (pos > d->m_cursor)
1343 pos += d->preeditAreaText().length();
1344 QTextLine l = d->m_textLayout.lineForTextPosition(pos);
1346 ? QRectF(l.cursorToX(pos) - d->hscroll, l.y() - d->vscroll, 1, l.height())
1351 \qmlmethod int QtQuick2::TextInput::positionAt(real x, real y, CursorPosition position = CursorBetweenCharacters)
1353 This function returns the character position at
1354 x and y pixels from the top left of the textInput. Position 0 is before the
1355 first character, position 1 is after the first character but before the second,
1356 and so on until position text.length, which is after all characters.
1358 This means that for all x values before the first character this function returns 0,
1359 and for all x values after the last character this function returns text.length. If
1360 the y value is above the text the position will be that of the nearest character on
1361 the first line line and if it is below the text the position of the nearest character
1362 on the last line will be returned.
1364 The cursor position type specifies how the cursor position should be resolved.
1367 \li TextInput.CursorBetweenCharacters - Returns the position between characters that is nearest x.
1368 \li TextInput.CursorOnCharacter - Returns the position before the character that is nearest x.
1372 void QQuickTextInput::positionAt(QQmlV8Function *args) const
1374 Q_D(const QQuickTextInput);
1378 QTextLine::CursorPosition position = QTextLine::CursorBetweenCharacters;
1380 if (args->Length() < 1)
1384 v8::Local<v8::Value> arg = (*args)[i];
1385 x = arg->NumberValue();
1387 if (++i < args->Length()) {
1389 y = arg->NumberValue();
1392 if (++i < args->Length()) {
1394 position = QTextLine::CursorPosition(arg->Int32Value());
1397 int pos = d->positionAt(x, y, position);
1398 const int cursor = d->m_cursor;
1400 const int preeditLength = d->preeditAreaText().length();
1401 pos = pos > cursor + preeditLength
1402 ? pos - preeditLength
1405 args->returnValue(v8::Int32::New(pos));
1408 int QQuickTextInputPrivate::positionAt(qreal x, qreal y, QTextLine::CursorPosition position) const
1412 QTextLine line = m_textLayout.lineAt(0);
1413 for (int i = 1; i < m_textLayout.lineCount(); ++i) {
1414 QTextLine nextLine = m_textLayout.lineAt(i);
1416 if (y < (line.rect().bottom() + nextLine.y()) / 2)
1420 return line.isValid() ? line.xToCursor(x, position) : 0;
1423 void QQuickTextInput::keyPressEvent(QKeyEvent* ev)
1425 Q_D(QQuickTextInput);
1426 // Don't allow MacOSX up/down support, and we don't allow a completer.
1427 bool ignore = (ev->key() == Qt::Key_Up || ev->key() == Qt::Key_Down) && ev->modifiers() == Qt::NoModifier;
1428 if (!ignore && (d->lastSelectionStart == d->lastSelectionEnd) && (ev->key() == Qt::Key_Right || ev->key() == Qt::Key_Left)) {
1429 // Ignore when moving off the end unless there is a selection,
1430 // because then moving will do something (deselect).
1431 int cursorPosition = d->m_cursor;
1432 if (cursorPosition == 0)
1433 ignore = ev->key() == (d->layoutDirection() == Qt::LeftToRight ? Qt::Key_Left : Qt::Key_Right);
1434 if (!ignore && cursorPosition == text().length())
1435 ignore = ev->key() == (d->layoutDirection() == Qt::LeftToRight ? Qt::Key_Right : Qt::Key_Left);
1440 d->processKeyEvent(ev);
1442 if (!ev->isAccepted())
1443 QQuickImplicitSizeItem::keyPressEvent(ev);
1446 void QQuickTextInput::inputMethodEvent(QInputMethodEvent *ev)
1448 Q_D(QQuickTextInput);
1449 const bool wasComposing = d->hasImState;
1450 if (d->m_readOnly) {
1453 d->processInputMethodEvent(ev);
1455 if (!ev->isAccepted())
1456 QQuickImplicitSizeItem::inputMethodEvent(ev);
1458 if (wasComposing != d->hasImState)
1459 emit inputMethodComposingChanged();
1462 void QQuickTextInput::mouseDoubleClickEvent(QMouseEvent *event)
1464 Q_D(QQuickTextInput);
1466 if (d->selectByMouse && event->button() == Qt::LeftButton) {
1468 int cursor = d->positionAt(event->localPos());
1469 d->selectWordAtPos(cursor);
1470 event->setAccepted(true);
1471 if (!d->hasPendingTripleClick()) {
1472 d->tripleClickStartPoint = event->localPos();
1473 d->tripleClickTimer.start();
1476 if (d->sendMouseEventToInputContext(event))
1478 QQuickImplicitSizeItem::mouseDoubleClickEvent(event);
1482 void QQuickTextInput::mousePressEvent(QMouseEvent *event)
1484 Q_D(QQuickTextInput);
1486 d->pressPos = event->localPos();
1488 if (d->sendMouseEventToInputContext(event))
1491 if (d->selectByMouse) {
1492 setKeepMouseGrab(false);
1493 d->selectPressed = true;
1494 QPointF distanceVector = d->pressPos - d->tripleClickStartPoint;
1495 if (d->hasPendingTripleClick()
1496 && distanceVector.manhattanLength() < qApp->styleHints()->startDragDistance()) {
1497 event->setAccepted(true);
1503 bool mark = (event->modifiers() & Qt::ShiftModifier) && d->selectByMouse;
1504 int cursor = d->positionAt(event->localPos());
1505 d->moveCursor(cursor, mark);
1507 if (d->focusOnPress) {
1508 bool hadActiveFocus = hasActiveFocus();
1510 // re-open input panel on press if already focused
1511 if (hasActiveFocus() && hadActiveFocus && !d->m_readOnly)
1512 qGuiApp->inputMethod()->show();
1515 event->setAccepted(true);
1518 void QQuickTextInput::mouseMoveEvent(QMouseEvent *event)
1520 Q_D(QQuickTextInput);
1522 if (d->selectPressed) {
1523 if (qAbs(int(event->localPos().x() - d->pressPos.x())) > qApp->styleHints()->startDragDistance())
1524 setKeepMouseGrab(true);
1526 if (d->composeMode()) {
1528 int startPos = d->positionAt(d->pressPos);
1529 int currentPos = d->positionAt(event->localPos());
1530 if (startPos != currentPos)
1531 d->setSelection(startPos, currentPos - startPos);
1533 moveCursorSelection(d->positionAt(event->localPos()), d->mouseSelectionMode);
1535 event->setAccepted(true);
1537 QQuickImplicitSizeItem::mouseMoveEvent(event);
1541 void QQuickTextInput::mouseReleaseEvent(QMouseEvent *event)
1543 Q_D(QQuickTextInput);
1544 if (d->sendMouseEventToInputContext(event))
1546 if (d->selectPressed) {
1547 d->selectPressed = false;
1548 setKeepMouseGrab(false);
1550 #ifndef QT_NO_CLIPBOARD
1551 if (QGuiApplication::clipboard()->supportsSelection()) {
1552 if (event->button() == Qt::LeftButton) {
1553 d->copy(QClipboard::Selection);
1554 } else if (!d->m_readOnly && event->button() == Qt::MidButton) {
1556 d->insert(QGuiApplication::clipboard()->text(QClipboard::Selection));
1560 if (!event->isAccepted())
1561 QQuickImplicitSizeItem::mouseReleaseEvent(event);
1564 bool QQuickTextInputPrivate::sendMouseEventToInputContext(QMouseEvent *event)
1566 #if !defined QT_NO_IM
1567 if (composeMode()) {
1568 int tmp_cursor = positionAt(event->localPos());
1569 int mousePos = tmp_cursor - m_cursor;
1570 if (mousePos >= 0 && mousePos <= m_textLayout.preeditAreaText().length()) {
1571 if (event->type() == QEvent::MouseButtonRelease) {
1572 qApp->inputMethod()->invokeAction(QInputMethod::Click, mousePos);
1585 void QQuickTextInput::mouseUngrabEvent()
1587 Q_D(QQuickTextInput);
1588 d->selectPressed = false;
1589 setKeepMouseGrab(false);
1592 bool QQuickTextInput::event(QEvent* ev)
1594 #ifndef QT_NO_SHORTCUT
1595 Q_D(QQuickTextInput);
1596 if (ev->type() == QEvent::ShortcutOverride) {
1599 QKeyEvent* ke = static_cast<QKeyEvent*>(ev);
1600 if (ke == QKeySequence::Copy
1601 || ke == QKeySequence::Paste
1602 || ke == QKeySequence::Cut
1603 || ke == QKeySequence::Redo
1604 || ke == QKeySequence::Undo
1605 || ke == QKeySequence::MoveToNextWord
1606 || ke == QKeySequence::MoveToPreviousWord
1607 || ke == QKeySequence::MoveToStartOfDocument
1608 || ke == QKeySequence::MoveToEndOfDocument
1609 || ke == QKeySequence::SelectNextWord
1610 || ke == QKeySequence::SelectPreviousWord
1611 || ke == QKeySequence::SelectStartOfLine
1612 || ke == QKeySequence::SelectEndOfLine
1613 || ke == QKeySequence::SelectStartOfBlock
1614 || ke == QKeySequence::SelectEndOfBlock
1615 || ke == QKeySequence::SelectStartOfDocument
1616 || ke == QKeySequence::SelectAll
1617 || ke == QKeySequence::SelectEndOfDocument) {
1619 } else if (ke->modifiers() == Qt::NoModifier || ke->modifiers() == Qt::ShiftModifier
1620 || ke->modifiers() == Qt::KeypadModifier) {
1621 if (ke->key() < Qt::Key_Escape) {
1625 switch (ke->key()) {
1626 case Qt::Key_Delete:
1629 case Qt::Key_Backspace:
1641 return QQuickImplicitSizeItem::event(ev);
1644 void QQuickTextInput::geometryChanged(const QRectF &newGeometry,
1645 const QRectF &oldGeometry)
1647 Q_D(QQuickTextInput);
1649 if (newGeometry.width() != oldGeometry.width())
1651 updateCursorRectangle();
1653 QQuickImplicitSizeItem::geometryChanged(newGeometry, oldGeometry);
1656 void QQuickTextInputPrivate::updateHorizontalScroll()
1658 Q_Q(QQuickTextInput);
1659 QTextLine currentLine = m_textLayout.lineForTextPosition(m_cursor + m_preeditCursor);
1660 const int preeditLength = m_textLayout.preeditAreaText().length();
1661 const qreal width = qMax<qreal>(0, q->width());
1663 qreal widthUsed = 0;
1664 if (currentLine.isValid()) {
1665 cix = currentLine.cursorToX(m_cursor + preeditLength);
1666 const qreal cursorWidth = cix >= 0 ? cix : width - cix;
1667 widthUsed = qMax(currentLine.naturalTextWidth(), cursorWidth);
1669 int previousScroll = hscroll;
1671 if (!autoScroll || widthUsed <= width || m_echoMode == QQuickTextInput::NoEcho) {
1674 Q_ASSERT(currentLine.isValid());
1675 if (cix - hscroll >= width) {
1676 // text doesn't fit, cursor is to the right of br (scroll right)
1677 hscroll = cix - width;
1678 } else if (cix - hscroll < 0 && hscroll < widthUsed) {
1679 // text doesn't fit, cursor is to the left of br (scroll left)
1681 } else if (widthUsed - hscroll < width) {
1682 // text doesn't fit, text document is to the left of br; align
1684 hscroll = widthUsed - width;
1685 } else if (width - hscroll > widthUsed) {
1686 // text doesn't fit, text document is to the right of br; align
1688 hscroll = width - widthUsed;
1690 if (preeditLength > 0) {
1691 // check to ensure long pre-edit text doesn't push the cursor
1693 cix = currentLine.cursorToX(m_cursor + qMax(0, m_preeditCursor - 1));
1698 if (previousScroll != hscroll)
1699 textLayoutDirty = true;
1702 void QQuickTextInputPrivate::updateVerticalScroll()
1704 Q_Q(QQuickTextInput);
1705 const int preeditLength = m_textLayout.preeditAreaText().length();
1706 const qreal height = qMax<qreal>(0, q->height());
1707 qreal heightUsed = contentSize.height();
1708 qreal previousScroll = vscroll;
1710 if (!autoScroll || heightUsed <= height) {
1711 // text fits in br; use vscroll for alignment
1712 vscroll = -QQuickTextUtil::alignedY(
1713 heightUsed, height, vAlign & ~(Qt::AlignAbsolute|Qt::AlignHorizontal_Mask));
1715 QTextLine currentLine = m_textLayout.lineForTextPosition(m_cursor + preeditLength);
1716 QRectF r = currentLine.isValid() ? currentLine.rect() : QRectF();
1717 qreal top = r.top();
1718 int bottom = r.bottom();
1720 if (bottom - vscroll >= height) {
1721 // text doesn't fit, cursor is to the below the br (scroll down)
1722 vscroll = bottom - height;
1723 } else if (top - vscroll < 0 && vscroll < heightUsed) {
1724 // text doesn't fit, cursor is above br (scroll up)
1726 } else if (heightUsed - vscroll < height) {
1727 // text doesn't fit, text document is to the left of br; align
1729 vscroll = heightUsed - height;
1731 if (preeditLength > 0) {
1732 // check to ensure long pre-edit text doesn't push the cursor
1734 currentLine = m_textLayout.lineForTextPosition(m_cursor + qMax(0, m_preeditCursor - 1));
1735 top = currentLine.isValid() ? currentLine.rect().top() : 0;
1740 if (previousScroll != vscroll)
1741 textLayoutDirty = true;
1744 void QQuickTextInput::triggerPreprocess()
1746 Q_D(QQuickTextInput);
1747 if (d->updateType == QQuickTextInputPrivate::UpdateNone)
1748 d->updateType = QQuickTextInputPrivate::UpdateOnlyPreprocess;
1752 QSGNode *QQuickTextInput::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data)
1755 Q_D(QQuickTextInput);
1757 if (d->updateType != QQuickTextInputPrivate::UpdatePaintNode && oldNode != 0) {
1758 // Update done in preprocess() in the nodes
1759 d->updateType = QQuickTextInputPrivate::UpdateNone;
1763 d->updateType = QQuickTextInputPrivate::UpdateNone;
1765 QQuickTextNode *node = static_cast<QQuickTextNode *>(oldNode);
1767 node = new QQuickTextNode(QQuickItemPrivate::get(this)->sceneGraphContext(), this);
1770 if (!d->textLayoutDirty && oldNode != 0) {
1771 QSGSimpleRectNode *cursorNode = node->cursorNode();
1772 if (cursorNode != 0 && !isReadOnly()) {
1773 cursorNode->setRect(cursorRectangle());
1775 if (!d->cursorVisible || d->cursorItem || (!d->m_blinkStatus && d->m_blinkPeriod > 0)) {
1782 node->setUseNativeRenderer(d->renderType == QQuickTextInput::NativeRendering);
1783 node->deleteContent();
1784 node->setMatrix(QMatrix4x4());
1786 QPointF offset(0, 0);
1787 if (d->autoScroll && d->m_textLayout.lineCount() > 0) {
1788 QFontMetricsF fm(d->font);
1789 // the y offset is there to keep the baseline constant in case we have script changes in the text.
1790 offset = -QPoint(d->hscroll, d->vscroll + d->m_textLayout.lineAt(0).ascent() - fm.ascent());
1792 offset = -QPoint(d->hscroll, d->vscroll);
1795 if (!d->m_textLayout.text().isEmpty() || !d->m_textLayout.preeditAreaText().isEmpty()) {
1796 node->addTextLayout(offset, &d->m_textLayout, d->color,
1797 QQuickText::Normal, QColor(), QColor(),
1798 d->selectionColor, d->selectedTextColor,
1799 d->selectionStart(),
1800 d->selectionEnd() - 1); // selectionEnd() returns first char after
1804 if (!isReadOnly() && d->cursorItem == 0) {
1805 node->setCursor(cursorRectangle(), d->color);
1806 if (!d->cursorVisible || (!d->m_blinkStatus && d->m_blinkPeriod > 0)) {
1813 d->textLayoutDirty = false;
1819 QVariant QQuickTextInput::inputMethodQuery(Qt::InputMethodQuery property) const
1821 Q_D(const QQuickTextInput);
1824 return QVariant((bool)(flags() & ItemAcceptsInputMethod));
1826 return QVariant((int) d->effectiveInputMethodHints());
1827 case Qt::ImCursorRectangle:
1828 return cursorRectangle();
1831 case Qt::ImCursorPosition:
1832 return QVariant(d->m_cursor);
1833 case Qt::ImSurroundingText:
1834 if (d->m_echoMode == PasswordEchoOnEdit && !d->m_passwordEchoEditing) {
1835 return QVariant(displayText());
1837 return QVariant(d->realText());
1839 case Qt::ImCurrentSelection:
1840 return QVariant(selectedText());
1841 case Qt::ImMaximumTextLength:
1842 return QVariant(maxLength());
1843 case Qt::ImAnchorPosition:
1844 if (d->selectionStart() == d->selectionEnd())
1845 return QVariant(d->m_cursor);
1846 else if (d->selectionStart() == d->m_cursor)
1847 return QVariant(d->selectionEnd());
1849 return QVariant(d->selectionStart());
1856 \qmlmethod QtQuick2::TextInput::deselect()
1858 Removes active text selection.
1860 void QQuickTextInput::deselect()
1862 Q_D(QQuickTextInput);
1867 \qmlmethod QtQuick2::TextInput::selectAll()
1869 Causes all text to be selected.
1871 void QQuickTextInput::selectAll()
1873 Q_D(QQuickTextInput);
1874 d->setSelection(0, text().length());
1878 \qmlmethod QtQuick2::TextInput::isRightToLeft(int start, int end)
1880 Returns true if the natural reading direction of the editor text
1881 found between positions \a start and \a end is right to left.
1883 bool QQuickTextInput::isRightToLeft(int start, int end)
1886 qmlInfo(this) << "isRightToLeft(start, end) called with the end property being smaller than the start.";
1889 return text().mid(start, end - start).isRightToLeft();
1893 #ifndef QT_NO_CLIPBOARD
1895 \qmlmethod QtQuick2::TextInput::cut()
1897 Moves the currently selected text to the system clipboard.
1899 void QQuickTextInput::cut()
1901 Q_D(QQuickTextInput);
1902 if (!d->m_readOnly) {
1909 \qmlmethod QtQuick2::TextInput::copy()
1911 Copies the currently selected text to the system clipboard.
1913 void QQuickTextInput::copy()
1915 Q_D(QQuickTextInput);
1920 \qmlmethod QtQuick2::TextInput::paste()
1922 Replaces the currently selected text by the contents of the system clipboard.
1924 void QQuickTextInput::paste()
1926 Q_D(QQuickTextInput);
1930 #endif // QT_NO_CLIPBOARD
1933 \qmlmethod QtQuick2::TextInput::undo()
1935 Undoes the last operation if undo is \l {canUndo}{available}. Deselects any
1936 current selection, and updates the selection start to the current cursor
1940 void QQuickTextInput::undo()
1942 Q_D(QQuickTextInput);
1943 if (!d->m_readOnly) {
1945 d->finishChange(-1, true);
1950 \qmlmethod QtQuick2::TextInput::redo()
1952 Redoes the last operation if redo is \l {canRedo}{available}.
1955 void QQuickTextInput::redo()
1957 Q_D(QQuickTextInput);
1958 if (!d->m_readOnly) {
1965 \qmlmethod QtQuick2::TextInput::insert(int position, string text)
1967 Inserts \a text into the TextInput at position.
1970 void QQuickTextInput::insert(int position, const QString &text)
1972 Q_D(QQuickTextInput);
1973 if (d->m_echoMode == QQuickTextInput::Password) {
1974 int delay = qGuiApp->styleHints()->passwordMaskDelay();
1976 d->m_passwordEchoTimer.start(delay, this);
1978 if (position < 0 || position > d->m_text.length())
1981 const int priorState = d->m_undoState;
1983 QString insertText = text;
1985 if (d->hasSelectedText()) {
1986 d->addCommand(QQuickTextInputPrivate::Command(
1987 QQuickTextInputPrivate::SetSelection, d->m_cursor, 0, d->m_selstart, d->m_selend));
1989 if (d->m_maskData) {
1990 insertText = d->maskString(position, insertText);
1991 for (int i = 0; i < insertText.length(); ++i) {
1992 d->addCommand(QQuickTextInputPrivate::Command(
1993 QQuickTextInputPrivate::DeleteSelection, position + i, d->m_text.at(position + i), -1, -1));
1994 d->addCommand(QQuickTextInputPrivate::Command(
1995 QQuickTextInputPrivate::Insert, position + i, insertText.at(i), -1, -1));
1997 d->m_text.replace(position, insertText.length(), insertText);
1998 if (!insertText.isEmpty())
1999 d->m_textDirty = true;
2000 if (position < d->m_selend && position + insertText.length() > d->m_selstart)
2001 d->m_selDirty = true;
2003 int remaining = d->m_maxLength - d->m_text.length();
2004 if (remaining != 0) {
2005 insertText = insertText.left(remaining);
2006 d->m_text.insert(position, insertText);
2007 for (int i = 0; i < insertText.length(); ++i)
2008 d->addCommand(QQuickTextInputPrivate::Command(
2009 QQuickTextInputPrivate::Insert, position + i, insertText.at(i), -1, -1));
2010 if (d->m_cursor >= position)
2011 d->m_cursor += insertText.length();
2012 if (d->m_selstart >= position)
2013 d->m_selstart += insertText.length();
2014 if (d->m_selend >= position)
2015 d->m_selend += insertText.length();
2016 d->m_textDirty = true;
2017 if (position >= d->m_selstart && position <= d->m_selend)
2018 d->m_selDirty = true;
2022 d->addCommand(QQuickTextInputPrivate::Command(
2023 QQuickTextInputPrivate::SetSelection, d->m_cursor, 0, d->m_selstart, d->m_selend));
2024 d->finishChange(priorState);
2026 if (d->lastSelectionStart != d->lastSelectionEnd) {
2027 if (d->m_selstart != d->lastSelectionStart) {
2028 d->lastSelectionStart = d->m_selstart;
2029 emit selectionStartChanged();
2031 if (d->m_selend != d->lastSelectionEnd) {
2032 d->lastSelectionEnd = d->m_selend;
2033 emit selectionEndChanged();
2039 \qmlmethod string QtQuick2::TextInput::getText(int start, int end)
2041 Removes the section of text that is between the \a start and \a end positions from the TextInput.
2044 void QQuickTextInput::remove(int start, int end)
2046 Q_D(QQuickTextInput);
2048 start = qBound(0, start, d->m_text.length());
2049 end = qBound(0, end, d->m_text.length());
2053 else if (start == end)
2056 if (start < d->m_selend && end > d->m_selstart)
2057 d->m_selDirty = true;
2059 const int priorState = d->m_undoState;
2061 d->addCommand(QQuickTextInputPrivate::Command(
2062 QQuickTextInputPrivate::SetSelection, d->m_cursor, 0, d->m_selstart, d->m_selend));
2064 if (start <= d->m_cursor && d->m_cursor < end) {
2065 // cursor is within the selection. Split up the commands
2066 // to be able to restore the correct cursor position
2067 for (int i = d->m_cursor; i >= start; --i) {
2068 d->addCommand(QQuickTextInputPrivate::Command(
2069 QQuickTextInputPrivate::DeleteSelection, i, d->m_text.at(i), -1, 1));
2071 for (int i = end - 1; i > d->m_cursor; --i) {
2072 d->addCommand(QQuickTextInputPrivate::Command(
2073 QQuickTextInputPrivate::DeleteSelection, i - d->m_cursor + start - 1, d->m_text.at(i), -1, -1));
2076 for (int i = end - 1; i >= start; --i) {
2077 d->addCommand(QQuickTextInputPrivate::Command(
2078 QQuickTextInputPrivate::RemoveSelection, i, d->m_text.at(i), -1, -1));
2081 if (d->m_maskData) {
2082 d->m_text.replace(start, end - start, d->clearString(start, end - start));
2083 for (int i = 0; i < end - start; ++i) {
2084 d->addCommand(QQuickTextInputPrivate::Command(
2085 QQuickTextInputPrivate::Insert, start + i, d->m_text.at(start + i), -1, -1));
2088 d->m_text.remove(start, end - start);
2090 if (d->m_cursor > start)
2091 d->m_cursor -= qMin(d->m_cursor, end) - start;
2092 if (d->m_selstart > start)
2093 d->m_selstart -= qMin(d->m_selstart, end) - start;
2094 if (d->m_selend > end)
2095 d->m_selend -= qMin(d->m_selend, end) - start;
2097 d->addCommand(QQuickTextInputPrivate::Command(
2098 QQuickTextInputPrivate::SetSelection, d->m_cursor, 0, d->m_selstart, d->m_selend));
2100 d->m_textDirty = true;
2101 d->finishChange(priorState);
2103 if (d->lastSelectionStart != d->lastSelectionEnd) {
2104 if (d->m_selstart != d->lastSelectionStart) {
2105 d->lastSelectionStart = d->m_selstart;
2106 emit selectionStartChanged();
2108 if (d->m_selend != d->lastSelectionEnd) {
2109 d->lastSelectionEnd = d->m_selend;
2110 emit selectionEndChanged();
2117 \qmlmethod QtQuick2::TextInput::selectWord()
2119 Causes the word closest to the current cursor position to be selected.
2121 void QQuickTextInput::selectWord()
2123 Q_D(QQuickTextInput);
2124 d->selectWordAtPos(d->m_cursor);
2128 \qmlproperty string QtQuick2::TextInput::passwordCharacter
2130 This is the character displayed when echoMode is set to Password or
2131 PasswordEchoOnEdit. By default it is an asterisk.
2133 If this property is set to a string with more than one character,
2134 the first character is used. If the string is empty, the value
2135 is ignored and the property is not set.
2137 QString QQuickTextInput::passwordCharacter() const
2139 Q_D(const QQuickTextInput);
2140 return QString(d->m_passwordCharacter);
2143 void QQuickTextInput::setPasswordCharacter(const QString &str)
2145 Q_D(QQuickTextInput);
2146 if (str.length() < 1)
2148 d->m_passwordCharacter = str.constData()[0];
2149 if (d->m_echoMode == Password || d->m_echoMode == PasswordEchoOnEdit)
2150 d->updateDisplayText();
2151 emit passwordCharacterChanged();
2155 \qmlproperty string QtQuick2::TextInput::displayText
2157 This is the text displayed in the TextInput.
2159 If \l echoMode is set to TextInput::Normal, this holds the
2160 same value as the TextInput::text property. Otherwise,
2161 this property holds the text visible to the user, while
2162 the \l text property holds the actual entered text.
2164 QString QQuickTextInput::displayText() const
2166 Q_D(const QQuickTextInput);
2167 return d->m_textLayout.text();
2171 \qmlproperty bool QtQuick2::TextInput::selectByMouse
2175 If true, the user can use the mouse to select text in some
2176 platform-specific way. Note that for some platforms this may
2177 not be an appropriate interaction (eg. may conflict with how
2178 the text needs to behave inside a Flickable.
2180 bool QQuickTextInput::selectByMouse() const
2182 Q_D(const QQuickTextInput);
2183 return d->selectByMouse;
2186 void QQuickTextInput::setSelectByMouse(bool on)
2188 Q_D(QQuickTextInput);
2189 if (d->selectByMouse != on) {
2190 d->selectByMouse = on;
2191 emit selectByMouseChanged(on);
2196 \qmlproperty enumeration QtQuick2::TextInput::mouseSelectionMode
2198 Specifies how text should be selected using a mouse.
2201 \li TextInput.SelectCharacters - The selection is updated with individual characters. (Default)
2202 \li TextInput.SelectWords - The selection is updated with whole words.
2205 This property only applies when \l selectByMouse is true.
2208 QQuickTextInput::SelectionMode QQuickTextInput::mouseSelectionMode() const
2210 Q_D(const QQuickTextInput);
2211 return d->mouseSelectionMode;
2214 void QQuickTextInput::setMouseSelectionMode(SelectionMode mode)
2216 Q_D(QQuickTextInput);
2217 if (d->mouseSelectionMode != mode) {
2218 d->mouseSelectionMode = mode;
2219 emit mouseSelectionModeChanged(mode);
2224 \qmlproperty bool QtQuick2::TextInput::persistentSelection
2226 Whether the TextInput should keep its selection when it loses active focus to another
2227 item in the scene. By default this is set to false;
2230 bool QQuickTextInput::persistentSelection() const
2232 Q_D(const QQuickTextInput);
2233 return d->persistentSelection;
2236 void QQuickTextInput::setPersistentSelection(bool on)
2238 Q_D(QQuickTextInput);
2239 if (d->persistentSelection == on)
2241 d->persistentSelection = on;
2242 emit persistentSelectionChanged();
2245 #ifndef QT_NO_CLIPBOARD
2247 \qmlproperty bool QtQuick2::TextInput::canPaste
2249 Returns true if the TextInput is writable and the content of the clipboard is
2250 suitable for pasting into the TextInput.
2252 bool QQuickTextInput::canPaste() const
2254 Q_D(const QQuickTextInput);
2255 if (!d->canPasteValid) {
2256 if (const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData())
2257 const_cast<QQuickTextInputPrivate *>(d)->canPaste = !d->m_readOnly && mimeData->hasText();
2258 const_cast<QQuickTextInputPrivate *>(d)->canPasteValid = true;
2265 \qmlproperty bool QtQuick2::TextInput::canUndo
2267 Returns true if the TextInput is writable and there are previous operations
2271 bool QQuickTextInput::canUndo() const
2273 Q_D(const QQuickTextInput);
2278 \qmlproperty bool QtQuick2::TextInput::canRedo
2280 Returns true if the TextInput is writable and there are \l {undo}{undone}
2281 operations that can be redone.
2284 bool QQuickTextInput::canRedo() const
2286 Q_D(const QQuickTextInput);
2291 \qmlproperty real QtQuick2::TextInput::contentWidth
2293 Returns the width of the text, including the width past the width
2294 which is covered due to insufficient wrapping if \l wrapMode is set.
2297 qreal QQuickTextInput::contentWidth() const
2299 Q_D(const QQuickTextInput);
2300 return d->contentSize.width();
2304 \qmlproperty real QtQuick2::TextInput::contentHeight
2306 Returns the height of the text, including the height past the height
2307 that is covered if the text does not fit within the set height.
2310 qreal QQuickTextInput::contentHeight() const
2312 Q_D(const QQuickTextInput);
2313 return d->contentSize.height();
2316 void QQuickTextInput::moveCursorSelection(int position)
2318 Q_D(QQuickTextInput);
2319 d->moveCursor(position, true);
2323 \qmlmethod QtQuick2::TextInput::moveCursorSelection(int position, SelectionMode mode = TextInput.SelectCharacters)
2325 Moves the cursor to \a position and updates the selection according to the optional \a mode
2326 parameter. (To only move the cursor, set the \l cursorPosition property.)
2328 When this method is called it additionally sets either the
2329 selectionStart or the selectionEnd (whichever was at the previous cursor position)
2330 to the specified position. This allows you to easily extend and contract the selected
2333 The selection mode specifies whether the selection is updated on a per character or a per word
2334 basis. If not specified the selection mode will default to TextInput.SelectCharacters.
2337 \li TextInput.SelectCharacters - Sets either the selectionStart or selectionEnd (whichever was at
2338 the previous cursor position) to the specified position.
2339 \li TextInput.SelectWords - Sets the selectionStart and selectionEnd to include all
2340 words between the specified position and the previous cursor position. Words partially in the
2344 For example, take this sequence of calls:
2348 moveCursorSelection(9, TextInput.SelectCharacters)
2349 moveCursorSelection(7, TextInput.SelectCharacters)
2352 This moves the cursor to position 5, extend the selection end from 5 to 9
2353 and then retract the selection end from 9 to 7, leaving the text from position 5 to 7
2354 selected (the 6th and 7th characters).
2356 The same sequence with TextInput.SelectWords will extend the selection start to a word boundary
2357 before or on position 5 and extend the selection end to a word boundary on or past position 9.
2359 void QQuickTextInput::moveCursorSelection(int pos, SelectionMode mode)
2361 Q_D(QQuickTextInput);
2363 if (mode == SelectCharacters) {
2364 d->moveCursor(pos, true);
2365 } else if (pos != d->m_cursor){
2366 const int cursor = d->m_cursor;
2368 if (!d->hasSelectedText())
2369 anchor = d->m_cursor;
2370 else if (d->selectionStart() == d->m_cursor)
2371 anchor = d->selectionEnd();
2373 anchor = d->selectionStart();
2375 if (anchor < pos || (anchor == pos && cursor < pos)) {
2376 const QString text = this->text();
2377 QTextBoundaryFinder finder(QTextBoundaryFinder::Word, text);
2378 finder.setPosition(anchor);
2380 const QTextBoundaryFinder::BoundaryReasons reasons = finder.boundaryReasons();
2381 if (anchor < text.length() && (!(reasons & QTextBoundaryFinder::StartWord)
2382 || ((reasons & QTextBoundaryFinder::EndWord) && anchor > cursor))) {
2383 finder.toPreviousBoundary();
2385 anchor = finder.position() != -1 ? finder.position() : 0;
2387 finder.setPosition(pos);
2388 if (pos > 0 && !finder.boundaryReasons())
2389 finder.toNextBoundary();
2390 const int cursor = finder.position() != -1 ? finder.position() : text.length();
2392 d->setSelection(anchor, cursor - anchor);
2393 } else if (anchor > pos || (anchor == pos && cursor > pos)) {
2394 const QString text = this->text();
2395 QTextBoundaryFinder finder(QTextBoundaryFinder::Word, text);
2396 finder.setPosition(anchor);
2398 const QTextBoundaryFinder::BoundaryReasons reasons = finder.boundaryReasons();
2399 if (anchor > 0 && (!(reasons & QTextBoundaryFinder::EndWord)
2400 || ((reasons & QTextBoundaryFinder::StartWord) && anchor < cursor))) {
2401 finder.toNextBoundary();
2404 anchor = finder.position() != -1 ? finder.position() : text.length();
2406 finder.setPosition(pos);
2407 if (pos < text.length() && !finder.boundaryReasons())
2408 finder.toPreviousBoundary();
2409 const int cursor = finder.position() != -1 ? finder.position() : 0;
2411 d->setSelection(anchor, cursor - anchor);
2416 void QQuickTextInput::focusInEvent(QFocusEvent *event)
2418 Q_D(const QQuickTextInput);
2419 if (d->focusOnPress && !d->m_readOnly)
2420 qGuiApp->inputMethod()->show();
2421 QQuickImplicitSizeItem::focusInEvent(event);
2424 void QQuickTextInput::itemChange(ItemChange change, const ItemChangeData &value)
2426 Q_D(QQuickTextInput);
2427 if (change == ItemActiveFocusHasChanged) {
2428 bool hasFocus = value.boolValue;
2429 setCursorVisible(hasFocus);
2430 if (!hasFocus && (d->m_passwordEchoEditing || d->m_passwordEchoTimer.isActive())) {
2431 d->updatePasswordEchoEditing(false);//QQuickTextInputPrivate sets it on key events, but doesn't deal with focus events
2435 if (!d->persistentSelection)
2437 disconnect(qApp->inputMethod(), SIGNAL(inputDirectionChanged(Qt::LayoutDirection)),
2438 this, SLOT(q_updateAlignment()));
2440 q_updateAlignment();
2441 connect(qApp->inputMethod(), SIGNAL(inputDirectionChanged(Qt::LayoutDirection)),
2442 this, SLOT(q_updateAlignment()));
2445 QQuickItem::itemChange(change, value);
2449 \qmlproperty bool QtQuick2::TextInput::inputMethodComposing
2452 This property holds whether the TextInput has partial text input from an
2455 While it is composing an input method may rely on mouse or key events from
2456 the TextInput to edit or commit the partial text. This property can be
2457 used to determine when to disable events handlers that may interfere with
2458 the correct operation of an input method.
2460 bool QQuickTextInput::isInputMethodComposing() const
2462 Q_D(const QQuickTextInput);
2463 return d->hasImState;
2466 void QQuickTextInputPrivate::init()
2468 Q_Q(QQuickTextInput);
2469 #ifndef QT_NO_CLIPBOARD
2470 if (QGuiApplication::clipboard()->supportsSelection())
2471 q->setAcceptedMouseButtons(Qt::LeftButton | Qt::MiddleButton);
2474 q->setAcceptedMouseButtons(Qt::LeftButton);
2476 q->setFlag(QQuickItem::ItemAcceptsInputMethod);
2477 q->setFlag(QQuickItem::ItemHasContents);
2478 #ifndef QT_NO_CLIPBOARD
2479 q->connect(QGuiApplication::clipboard(), SIGNAL(dataChanged()),
2480 q, SLOT(q_canPasteChanged()));
2481 #endif // QT_NO_CLIPBOARD
2483 lastSelectionStart = 0;
2484 lastSelectionEnd = 0;
2485 determineHorizontalAlignment();
2487 if (!qmlDisableDistanceField()) {
2488 QTextOption option = m_textLayout.textOption();
2489 option.setUseDesignMetrics(renderType != QQuickTextInput::NativeRendering);
2490 m_textLayout.setTextOption(option);
2494 void QQuickTextInput::updateCursorRectangle()
2496 Q_D(QQuickTextInput);
2497 if (!isComponentComplete())
2500 d->updateHorizontalScroll();
2501 d->updateVerticalScroll();
2502 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
2504 emit cursorRectangleChanged();
2505 if (d->cursorItem) {
2506 QRectF r = cursorRectangle();
2507 d->cursorItem->setPos(r.topLeft());
2508 d->cursorItem->setHeight(r.height());
2510 updateInputMethod(Qt::ImCursorRectangle);
2513 void QQuickTextInput::selectionChanged()
2515 Q_D(QQuickTextInput);
2516 d->textLayoutDirty = true; //TODO: Only update rect in selection
2517 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
2519 emit selectedTextChanged();
2521 if (d->lastSelectionStart != d->selectionStart()) {
2522 d->lastSelectionStart = d->selectionStart();
2523 if (d->lastSelectionStart == -1)
2524 d->lastSelectionStart = d->m_cursor;
2525 emit selectionStartChanged();
2527 if (d->lastSelectionEnd != d->selectionEnd()) {
2528 d->lastSelectionEnd = d->selectionEnd();
2529 if (d->lastSelectionEnd == -1)
2530 d->lastSelectionEnd = d->m_cursor;
2531 emit selectionEndChanged();
2535 void QQuickTextInputPrivate::showCursor()
2537 if (textNode != 0 && textNode->cursorNode() != 0)
2538 textNode->cursorNode()->setColor(color);
2541 void QQuickTextInputPrivate::hideCursor()
2543 if (textNode != 0 && textNode->cursorNode() != 0)
2544 textNode->cursorNode()->setColor(QColor(0, 0, 0, 0));
2547 QRectF QQuickTextInput::boundingRect() const
2549 Q_D(const QQuickTextInput);
2551 int cursorWidth = d->cursorItem ? 0 : 1;
2553 qreal hscroll = d->hscroll;
2554 if (!d->autoScroll || d->contentSize.width() < width())
2555 hscroll -= QQuickTextUtil::alignedX(d->contentSize.width(), width(), effectiveHAlign());
2557 // Could include font max left/right bearings to either side of rectangle.
2558 QRectF r(-hscroll, -d->vscroll, d->contentSize.width(), d->contentSize.height());
2559 r.setRight(r.right() + cursorWidth);
2563 QRectF QQuickTextInput::clipRect() const
2565 Q_D(const QQuickTextInput);
2567 int cursorWidth = d->cursorItem ? d->cursorItem->width() : 1;
2569 // Could include font max left/right bearings to either side of rectangle.
2570 QRectF r = QQuickImplicitSizeItem::clipRect();
2571 r.setRight(r.right() + cursorWidth);
2575 void QQuickTextInput::q_canPasteChanged()
2577 Q_D(QQuickTextInput);
2578 bool old = d->canPaste;
2579 #ifndef QT_NO_CLIPBOARD
2580 if (const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData())
2581 d->canPaste = !d->m_readOnly && mimeData->hasText();
2583 d->canPaste = false;
2586 bool changed = d->canPaste != old || !d->canPasteValid;
2587 d->canPasteValid = true;
2589 emit canPasteChanged();
2593 void QQuickTextInput::q_updateAlignment()
2595 Q_D(QQuickTextInput);
2596 if (d->determineHorizontalAlignment()) {
2598 updateCursorRectangle();
2602 // ### these should come from QStyleHints
2603 const int textCursorWidth = 1;
2604 const bool fullWidthSelection = true;
2609 Updates the display text based of the current edit text
2610 If the text has changed will emit displayTextChanged()
2612 void QQuickTextInputPrivate::updateDisplayText(bool forceUpdate)
2614 QString orig = m_textLayout.text();
2616 if (m_echoMode == QQuickTextInput::NoEcho)
2617 str = QString::fromLatin1("");
2621 if (m_echoMode == QQuickTextInput::Password) {
2622 str.fill(m_passwordCharacter);
2623 if (m_passwordEchoTimer.isActive() && m_cursor > 0 && m_cursor <= m_text.length()) {
2624 int cursor = m_cursor - 1;
2625 QChar uc = m_text.at(cursor);
2627 if (cursor > 0 && uc.unicode() >= 0xdc00 && uc.unicode() < 0xe000) {
2628 // second half of a surrogate, check if we have the first half as well,
2629 // if yes restore both at once
2630 uc = m_text.at(cursor - 1);
2631 if (uc.unicode() >= 0xd800 && uc.unicode() < 0xdc00)
2632 str[cursor - 1] = uc;
2635 } else if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit && !m_passwordEchoEditing) {
2636 str.fill(m_passwordCharacter);
2639 // replace certain non-printable characters with spaces (to avoid
2640 // drawing boxes when using fonts that don't have glyphs for such
2642 QChar* uc = str.data();
2643 for (int i = 0; i < (int)str.length(); ++i) {
2644 if ((uc[i] < 0x20 && uc[i] != 0x09)
2645 || uc[i] == QChar::LineSeparator
2646 || uc[i] == QChar::ParagraphSeparator
2647 || uc[i] == QChar::ObjectReplacementCharacter)
2648 uc[i] = QChar(0x0020);
2651 if (str != orig || forceUpdate) {
2652 m_textLayout.setText(str);
2653 updateLayout(); // polish?
2654 emit q_func()->displayTextChanged();
2658 qreal QQuickTextInputPrivate::getImplicitWidth() const
2660 Q_Q(const QQuickTextInput);
2661 if (!requireImplicitWidth) {
2662 QQuickTextInputPrivate *d = const_cast<QQuickTextInputPrivate *>(this);
2663 d->requireImplicitWidth = true;
2665 if (q->isComponentComplete()) {
2666 // One time cost, only incurred if implicitWidth is first requested after
2667 // componentComplete.
2668 QTextLayout layout(m_text);
2670 QTextOption option = m_textLayout.textOption();
2671 option.setTextDirection(m_layoutDirection);
2672 option.setFlags(QTextOption::IncludeTrailingSpaces);
2673 option.setWrapMode(QTextOption::WrapMode(wrapMode));
2674 option.setAlignment(Qt::Alignment(q->effectiveHAlign()));
2675 layout.setTextOption(option);
2676 layout.setFont(font);
2677 layout.setPreeditArea(m_textLayout.preeditAreaPosition(), m_textLayout.preeditAreaText());
2678 layout.beginLayout();
2680 QTextLine line = layout.createLine();
2681 line.setLineWidth(INT_MAX);
2682 d->implicitWidth = qCeil(line.naturalTextWidth());
2687 return implicitWidth;
2690 void QQuickTextInputPrivate::updateLayout()
2692 Q_Q(QQuickTextInput);
2694 if (!q->isComponentComplete())
2698 QTextOption option = m_textLayout.textOption();
2699 option.setTextDirection(layoutDirection());
2700 option.setWrapMode(QTextOption::WrapMode(wrapMode));
2701 option.setAlignment(Qt::Alignment(q->effectiveHAlign()));
2702 m_textLayout.setTextOption(option);
2703 m_textLayout.setFont(font);
2705 m_textLayout.beginLayout();
2707 QTextLine line = m_textLayout.createLine();
2708 if (requireImplicitWidth) {
2709 line.setLineWidth(INT_MAX);
2710 const bool wasInLayout = inLayout;
2712 q->setImplicitWidth(qCeil(line.naturalTextWidth()));
2713 inLayout = wasInLayout;
2714 if (inLayout) // probably the result of a binding loop, but by letting it
2715 return; // get this far we'll get a warning to that effect.
2717 qreal lineWidth = q->widthValid() ? q->width() : INT_MAX;
2721 line.setLineWidth(lineWidth);
2722 line.setPosition(QPointF(0, height));
2724 height += line.height();
2725 width = qMax(width, line.naturalTextWidth());
2727 line = m_textLayout.createLine();
2728 } while (line.isValid());
2729 m_textLayout.endLayout();
2731 option.setWrapMode(QTextOption::NoWrap);
2732 m_textLayout.setTextOption(option);
2734 textLayoutDirty = true;
2736 const QSizeF previousSize = contentSize;
2737 contentSize = QSizeF(width, height);
2739 updateType = UpdatePaintNode;
2742 if (!requireImplicitWidth && !q->widthValid())
2743 q->setImplicitSize(width, height);
2745 q->setImplicitHeight(height);
2747 if (previousSize != contentSize)
2748 emit q->contentSizeChanged();
2751 #ifndef QT_NO_CLIPBOARD
2755 Copies the currently selected text into the clipboard using the given
2758 \note If the echo mode is set to a mode other than Normal then copy
2759 will not work. This is to prevent using copy as a method of bypassing
2760 password features of the line control.
2762 void QQuickTextInputPrivate::copy(QClipboard::Mode mode) const
2764 QString t = selectedText();
2765 if (!t.isEmpty() && m_echoMode == QQuickTextInput::Normal) {
2766 QGuiApplication::clipboard()->setText(t, mode);
2773 Inserts the text stored in the application clipboard into the line
2778 void QQuickTextInputPrivate::paste(QClipboard::Mode clipboardMode)
2780 QString clip = QGuiApplication::clipboard()->text(clipboardMode);
2781 if (!clip.isEmpty() || hasSelectedText()) {
2782 separate(); //make it a separate undo/redo command
2788 #endif // !QT_NO_CLIPBOARD
2793 void QQuickTextInputPrivate::commitPreedit()
2795 Q_Q(QQuickTextInput);
2800 qApp->inputMethod()->commit();
2805 QInputMethodEvent ev;
2806 QCoreApplication::sendEvent(q, &ev);
2809 void QQuickTextInputPrivate::cancelPreedit()
2811 Q_Q(QQuickTextInput);
2816 qApp->inputMethod()->reset();
2818 QInputMethodEvent ev;
2819 QCoreApplication::sendEvent(q, &ev);
2825 Handles the behavior for the backspace key or function.
2826 Removes the current selection if there is a selection, otherwise
2827 removes the character prior to the cursor position.
2831 void QQuickTextInputPrivate::backspace()
2833 int priorState = m_undoState;
2834 if (separateSelection()) {
2835 removeSelectedText();
2836 } else if (m_cursor) {
2839 m_cursor = prevMaskBlank(m_cursor);
2840 QChar uc = m_text.at(m_cursor);
2841 if (m_cursor > 0 && uc.unicode() >= 0xdc00 && uc.unicode() < 0xe000) {
2842 // second half of a surrogate, check if we have the first half as well,
2843 // if yes delete both at once
2844 uc = m_text.at(m_cursor - 1);
2845 if (uc.unicode() >= 0xd800 && uc.unicode() < 0xdc00) {
2846 internalDelete(true);
2850 internalDelete(true);
2852 finishChange(priorState);
2858 Handles the behavior for the delete key or function.
2859 Removes the current selection if there is a selection, otherwise
2860 removes the character after the cursor position.
2864 void QQuickTextInputPrivate::del()
2866 int priorState = m_undoState;
2867 if (separateSelection()) {
2868 removeSelectedText();
2870 int n = m_textLayout.nextCursorPosition(m_cursor) - m_cursor;
2874 finishChange(priorState);
2880 Inserts the given \a newText at the current cursor position.
2881 If there is any selected text it is removed prior to insertion of
2884 void QQuickTextInputPrivate::insert(const QString &newText)
2886 int priorState = m_undoState;
2887 if (separateSelection())
2888 removeSelectedText();
2889 internalInsert(newText);
2890 finishChange(priorState);
2896 Clears the line control text.
2898 void QQuickTextInputPrivate::clear()
2900 int priorState = m_undoState;
2901 separateSelection();
2903 m_selend = m_text.length();
2904 removeSelectedText();
2906 finishChange(priorState, /*update*/false, /*edited*/false);
2912 Sets \a length characters from the given \a start position as selected.
2913 The given \a start position must be within the current text for
2914 the line control. If \a length characters cannot be selected, then
2915 the selection will extend to the end of the current text.
2917 void QQuickTextInputPrivate::setSelection(int start, int length)
2919 Q_Q(QQuickTextInput);
2922 if (start < 0 || start > (int)m_text.length()){
2923 qWarning("QQuickTextInputPrivate::setSelection: Invalid start position");
2928 if (start == m_selstart && start + length == m_selend && m_cursor == m_selend)
2931 m_selend = qMin(start + length, (int)m_text.length());
2932 m_cursor = m_selend;
2933 } else if (length < 0){
2934 if (start == m_selend && start + length == m_selstart && m_cursor == m_selstart)
2936 m_selstart = qMax(start + length, 0);
2938 m_cursor = m_selstart;
2939 } else if (m_selstart != m_selend) {
2945 emitCursorPositionChanged();
2948 emit q->selectionChanged();
2949 emitCursorPositionChanged();
2950 q->updateInputMethod(Qt::ImCursorRectangle | Qt::ImAnchorPosition
2951 | Qt::ImCursorPosition | Qt::ImCurrentSelection);
2957 Sets the password echo editing to \a editing. If password echo editing
2958 is true, then the text of the password is displayed even if the echo
2959 mode is set to QLineEdit::PasswordEchoOnEdit. Password echoing editing
2960 does not affect other echo modes.
2962 void QQuickTextInputPrivate::updatePasswordEchoEditing(bool editing)
2964 cancelPasswordEchoTimer();
2965 m_passwordEchoEditing = editing;
2966 updateDisplayText();
2972 Fixes the current text so that it is valid given any set validators.
2974 Returns true if the text was changed. Otherwise returns false.
2976 bool QQuickTextInputPrivate::fixup() // this function assumes that validate currently returns != Acceptable
2978 #ifndef QT_NO_VALIDATOR
2980 QString textCopy = m_text;
2981 int cursorCopy = m_cursor;
2982 m_validator->fixup(textCopy);
2983 if (m_validator->validate(textCopy, cursorCopy) == QValidator::Acceptable) {
2984 if (textCopy != m_text || cursorCopy != m_cursor)
2985 internalSetText(textCopy, cursorCopy);
2996 Moves the cursor to the given position \a pos. If \a mark is true will
2997 adjust the currently selected text.
2999 void QQuickTextInputPrivate::moveCursor(int pos, bool mark)
3001 Q_Q(QQuickTextInput);
3004 if (pos != m_cursor) {
3007 pos = pos > m_cursor ? nextMaskBlank(pos) : prevMaskBlank(pos);
3011 if (m_selend > m_selstart && m_cursor == m_selstart)
3013 else if (m_selend > m_selstart && m_cursor == m_selend)
3014 anchor = m_selstart;
3017 m_selstart = qMin(anchor, pos);
3018 m_selend = qMax(anchor, pos);
3023 if (mark || m_selDirty) {
3025 emit q->selectionChanged();
3027 emitCursorPositionChanged();
3028 q->updateInputMethod();
3034 Applies the given input method event \a event to the text of the line
3037 void QQuickTextInputPrivate::processInputMethodEvent(QInputMethodEvent *event)
3039 Q_Q(QQuickTextInput);
3041 int priorState = -1;
3042 bool isGettingInput = !event->commitString().isEmpty()
3043 || event->preeditString() != preeditAreaText()
3044 || event->replacementLength() > 0;
3045 bool cursorPositionChanged = false;
3046 bool selectionChange = false;
3047 m_preeditDirty = event->preeditString() != preeditAreaText();
3049 if (isGettingInput) {
3050 // If any text is being input, remove selected text.
3051 priorState = m_undoState;
3052 separateSelection();
3053 if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit && !m_passwordEchoEditing) {
3054 updatePasswordEchoEditing(true);
3056 m_selend = m_text.length();
3058 removeSelectedText();
3061 int c = m_cursor; // cursor position after insertion of commit string
3062 if (event->replacementStart() <= 0)
3063 c += event->commitString().length() - qMin(-event->replacementStart(), event->replacementLength());
3065 m_cursor += event->replacementStart();
3069 // insert commit string
3070 if (event->replacementLength()) {
3071 m_selstart = m_cursor;
3072 m_selend = m_selstart + event->replacementLength();
3073 m_selend = qMin(m_selend, m_text.length());
3074 removeSelectedText();
3076 if (!event->commitString().isEmpty()) {
3077 internalInsert(event->commitString());
3078 cursorPositionChanged = true;
3081 m_cursor = qBound(0, c, m_text.length());
3083 for (int i = 0; i < event->attributes().size(); ++i) {
3084 const QInputMethodEvent::Attribute &a = event->attributes().at(i);
3085 if (a.type == QInputMethodEvent::Selection) {
3086 m_cursor = qBound(0, a.start + a.length, m_text.length());
3088 m_selstart = qMax(0, qMin(a.start, m_text.length()));
3089 m_selend = m_cursor;
3090 if (m_selend < m_selstart) {
3091 qSwap(m_selstart, m_selend);
3093 selectionChange = true;
3095 m_selstart = m_selend = 0;
3097 cursorPositionChanged = true;
3101 m_textLayout.setPreeditArea(m_cursor, event->preeditString());
3103 const int oldPreeditCursor = m_preeditCursor;
3104 m_preeditCursor = event->preeditString().length();
3105 hasImState = !event->preeditString().isEmpty();
3106 bool cursorVisible = true;
3107 QList<QTextLayout::FormatRange> formats;
3108 for (int i = 0; i < event->attributes().size(); ++i) {
3109 const QInputMethodEvent::Attribute &a = event->attributes().at(i);
3110 if (a.type == QInputMethodEvent::Cursor) {
3112 m_preeditCursor = a.start;
3113 cursorVisible = a.length != 0;
3114 } else if (a.type == QInputMethodEvent::TextFormat) {
3116 QTextCharFormat f = qvariant_cast<QTextFormat>(a.value).toCharFormat();
3118 QTextLayout::FormatRange o;
3119 o.start = a.start + m_cursor;
3120 o.length = a.length;
3126 m_textLayout.setAdditionalFormats(formats);
3128 updateDisplayText(/*force*/ true);
3129 if ((cursorPositionChanged && !emitCursorPositionChanged())
3130 || m_preeditCursor != oldPreeditCursor
3131 || isGettingInput) {
3132 q->updateCursorRectangle();
3136 finishChange(priorState);
3138 q->setCursorVisible(cursorVisible);
3140 if (selectionChange) {
3141 emit q->selectionChanged();
3142 q->updateInputMethod(Qt::ImCursorRectangle | Qt::ImAnchorPosition
3143 | Qt::ImCursorPosition | Qt::ImCurrentSelection);
3150 Sets the selection to cover the word at the given cursor position.
3151 The word boundaries are defined by the behavior of QTextLayout::SkipWords
3154 void QQuickTextInputPrivate::selectWordAtPos(int cursor)
3156 int next = cursor + 1;
3159 int c = m_textLayout.previousCursorPosition(next, QTextLayout::SkipWords);
3160 moveCursor(c, false);
3161 // ## text layout should support end of words.
3162 int end = m_textLayout.nextCursorPosition(c, QTextLayout::SkipWords);
3163 while (end > cursor && m_text[end-1].isSpace())
3165 moveCursor(end, true);
3171 Completes a change to the line control text. If the change is not valid
3172 will undo the line control state back to the given \a validateFromState.
3174 If \a edited is true and the change is valid, will emit textEdited() in
3175 addition to textChanged(). Otherwise only emits textChanged() on a valid
3178 The \a update value is currently unused.
3180 bool QQuickTextInputPrivate::finishChange(int validateFromState, bool update, bool /*edited*/)
3182 Q_Q(QQuickTextInput);
3185 bool inputMethodAttributesChanged = m_textDirty || m_selDirty;
3186 bool alignmentChanged = false;
3190 bool wasValidInput = m_validInput;
3191 bool wasAcceptable = m_acceptableInput;
3192 m_validInput = true;
3193 m_acceptableInput = true;
3194 #ifndef QT_NO_VALIDATOR
3196 QString textCopy = m_text;
3197 int cursorCopy = m_cursor;
3198 QValidator::State state = m_validator->validate(textCopy, cursorCopy);
3199 m_validInput = state != QValidator::Invalid;
3200 m_acceptableInput = state == QValidator::Acceptable;
3202 if (m_text != textCopy) {
3203 internalSetText(textCopy, cursorCopy);
3206 m_cursor = cursorCopy;
3210 if (validateFromState >= 0 && wasValidInput && !m_validInput) {
3211 if (m_transactions.count())
3213 internalUndo(validateFromState);
3214 m_history.resize(m_undoState);
3215 m_validInput = true;
3216 m_acceptableInput = wasAcceptable;
3217 m_textDirty = false;
3221 m_textDirty = false;
3222 m_preeditDirty = false;
3223 alignmentChanged = determineHorizontalAlignment();
3224 emit q->textChanged();
3227 updateDisplayText(alignmentChanged);
3229 if (m_acceptableInput != wasAcceptable)
3230 emit q->acceptableInputChanged();
3232 if (m_preeditDirty) {
3233 m_preeditDirty = false;
3234 if (determineHorizontalAlignment()) {
3235 alignmentChanged = true;
3242 emit q->selectionChanged();
3245 inputMethodAttributesChanged |= (m_cursor != m_lastCursorPos);
3246 if (inputMethodAttributesChanged)
3247 q->updateInputMethod();
3248 emitUndoRedoChanged();
3250 if (!emitCursorPositionChanged() && alignmentChanged)
3251 q->updateCursorRectangle();
3259 An internal function for setting the text of the line control.
3261 void QQuickTextInputPrivate::internalSetText(const QString &txt, int pos, bool edited)
3263 Q_Q(QQuickTextInput);
3265 QString oldText = m_text;
3267 m_text = maskString(0, txt, true);
3268 m_text += clearString(m_text.length(), m_maxLength - m_text.length());
3270 m_text = txt.isEmpty() ? txt : txt.left(m_maxLength);
3274 m_cursor = (pos < 0 || pos > m_text.length()) ? m_text.length() : pos;
3275 m_textDirty = (oldText != m_text);
3277 bool changed = finishChange(-1, true, edited);
3278 #ifdef QT_NO_ACCESSIBILITY
3282 QAccessibleTextUpdateEvent ev(q, 0, oldText, m_text);
3283 QAccessible::updateAccessibility(&ev);
3292 Adds the given \a command to the undo history
3293 of the line control. Does not apply the command.
3295 void QQuickTextInputPrivate::addCommand(const Command &cmd)
3297 if (m_separator && m_undoState && m_history[m_undoState - 1].type != Separator) {
3298 m_history.resize(m_undoState + 2);
3299 m_history[m_undoState++] = Command(Separator, m_cursor, 0, m_selstart, m_selend);
3301 m_history.resize(m_undoState + 1);
3303 m_separator = false;
3304 m_history[m_undoState++] = cmd;
3310 Inserts the given string \a s into the line
3313 Also adds the appropriate commands into the undo history.
3314 This function does not call finishChange(), and may leave the text
3315 in an invalid state.
3317 void QQuickTextInputPrivate::internalInsert(const QString &s)
3319 Q_Q(QQuickTextInput);
3320 if (m_echoMode == QQuickTextInput::Password) {
3321 int delay = qGuiApp->styleHints()->passwordMaskDelay();
3323 m_passwordEchoTimer.start(delay, q);
3325 Q_ASSERT(!hasSelectedText()); // insert(), processInputMethodEvent() call removeSelectedText() first.
3327 QString ms = maskString(m_cursor, s);
3328 for (int i = 0; i < (int) ms.length(); ++i) {
3329 addCommand (Command(DeleteSelection, m_cursor + i, m_text.at(m_cursor + i), -1, -1));
3330 addCommand(Command(Insert, m_cursor + i, ms.at(i), -1, -1));
3332 m_text.replace(m_cursor, ms.length(), ms);
3333 m_cursor += ms.length();
3334 m_cursor = nextMaskBlank(m_cursor);
3337 int remaining = m_maxLength - m_text.length();
3338 if (remaining != 0) {
3339 m_text.insert(m_cursor, s.left(remaining));
3340 for (int i = 0; i < (int) s.left(remaining).length(); ++i)
3341 addCommand(Command(Insert, m_cursor++, s.at(i), -1, -1));
3350 deletes a single character from the current text. If \a wasBackspace,
3351 the character prior to the cursor is removed. Otherwise the character
3352 after the cursor is removed.
3354 Also adds the appropriate commands into the undo history.
3355 This function does not call finishChange(), and may leave the text
3356 in an invalid state.
3358 void QQuickTextInputPrivate::internalDelete(bool wasBackspace)
3360 if (m_cursor < (int) m_text.length()) {
3361 cancelPasswordEchoTimer();
3362 Q_ASSERT(!hasSelectedText()); // del(), backspace() call removeSelectedText() first.
3363 addCommand(Command((CommandType)((m_maskData ? 2 : 0) + (wasBackspace ? Remove : Delete)),
3364 m_cursor, m_text.at(m_cursor), -1, -1));
3366 m_text.replace(m_cursor, 1, clearString(m_cursor, 1));
3367 addCommand(Command(Insert, m_cursor, m_text.at(m_cursor), -1, -1));
3369 m_text.remove(m_cursor, 1);
3378 removes the currently selected text from the line control.
3380 Also adds the appropriate commands into the undo history.
3381 This function does not call finishChange(), and may leave the text
3382 in an invalid state.
3384 void QQuickTextInputPrivate::removeSelectedText()
3386 if (m_selstart < m_selend && m_selend <= (int) m_text.length()) {
3387 cancelPasswordEchoTimer();
3389 if (m_selstart <= m_cursor && m_cursor < m_selend) {
3390 // cursor is within the selection. Split up the commands
3391 // to be able to restore the correct cursor position
3392 for (i = m_cursor; i >= m_selstart; --i)
3393 addCommand (Command(DeleteSelection, i, m_text.at(i), -1, 1));
3394 for (i = m_selend - 1; i > m_cursor; --i)
3395 addCommand (Command(DeleteSelection, i - m_cursor + m_selstart - 1, m_text.at(i), -1, -1));
3397 for (i = m_selend-1; i >= m_selstart; --i)
3398 addCommand (Command(RemoveSelection, i, m_text.at(i), -1, -1));
3401 m_text.replace(m_selstart, m_selend - m_selstart, clearString(m_selstart, m_selend - m_selstart));
3402 for (int i = 0; i < m_selend - m_selstart; ++i)
3403 addCommand(Command(Insert, m_selstart + i, m_text.at(m_selstart + i), -1, -1));
3405 m_text.remove(m_selstart, m_selend - m_selstart);
3407 if (m_cursor > m_selstart)
3408 m_cursor -= qMin(m_cursor, m_selend) - m_selstart;
3417 Adds the current selection to the undo history.
3419 Returns true if there is a current selection and false otherwise.
3422 bool QQuickTextInputPrivate::separateSelection()
3424 if (hasSelectedText()) {
3426 addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
3436 Parses the input mask specified by \a maskFields to generate
3437 the mask data used to handle input masks.
3439 void QQuickTextInputPrivate::parseInputMask(const QString &maskFields)
3441 int delimiter = maskFields.indexOf(QLatin1Char(';'));
3442 if (maskFields.isEmpty() || delimiter == 0) {
3444 delete [] m_maskData;
3446 m_maxLength = 32767;
3447 internalSetText(QString());
3452 if (delimiter == -1) {
3453 m_blank = QLatin1Char(' ');
3454 m_inputMask = maskFields;
3456 m_inputMask = maskFields.left(delimiter);
3457 m_blank = (delimiter + 1 < maskFields.length()) ? maskFields[delimiter + 1] : QLatin1Char(' ');
3460 // calculate m_maxLength / m_maskData length
3463 for (int i=0; i<m_inputMask.length(); i++) {
3464 c = m_inputMask.at(i);
3465 if (i > 0 && m_inputMask.at(i-1) == QLatin1Char('\\')) {
3469 if (c != QLatin1Char('\\') && c != QLatin1Char('!') &&
3470 c != QLatin1Char('<') && c != QLatin1Char('>') &&
3471 c != QLatin1Char('{') && c != QLatin1Char('}') &&
3472 c != QLatin1Char('[') && c != QLatin1Char(']'))
3476 delete [] m_maskData;
3477 m_maskData = new MaskInputData[m_maxLength];
3479 MaskInputData::Casemode m = MaskInputData::NoCaseMode;
3482 bool escape = false;
3484 for (int i = 0; i < m_inputMask.length(); i++) {
3485 c = m_inputMask.at(i);
3488 m_maskData[index].maskChar = c;
3489 m_maskData[index].separator = s;
3490 m_maskData[index].caseMode = m;
3493 } else if (c == QLatin1Char('<')) {
3494 m = MaskInputData::Lower;
3495 } else if (c == QLatin1Char('>')) {
3496 m = MaskInputData::Upper;
3497 } else if (c == QLatin1Char('!')) {
3498 m = MaskInputData::NoCaseMode;
3499 } else if (c != QLatin1Char('{') && c != QLatin1Char('}') && c != QLatin1Char('[') && c != QLatin1Char(']')) {
3500 switch (c.unicode()) {
3526 m_maskData[index].maskChar = c;
3527 m_maskData[index].separator = s;
3528 m_maskData[index].caseMode = m;
3533 internalSetText(m_text);
3540 checks if the key is valid compared to the inputMask
3542 bool QQuickTextInputPrivate::isValidInput(QChar key, QChar mask) const
3544 switch (mask.unicode()) {
3550 if (key.isLetter() || key == m_blank)
3554 if (key.isLetterOrNumber())
3558 if (key.isLetterOrNumber() || key == m_blank)
3566 if (key.isPrint() || key == m_blank)
3574 if (key.isNumber() || key == m_blank)
3578 if (key.isNumber() && key.digitValue() > 0)
3582 if ((key.isNumber() && key.digitValue() > 0) || key == m_blank)
3586 if (key.isNumber() || key == QLatin1Char('+') || key == QLatin1Char('-') || key == m_blank)
3590 if (key == QLatin1Char('0') || key == QLatin1Char('1'))
3594 if (key == QLatin1Char('0') || key == QLatin1Char('1') || key == m_blank)
3598 if (key.isNumber() || (key >= QLatin1Char('a') && key <= QLatin1Char('f')) || (key >= QLatin1Char('A') && key <= QLatin1Char('F')))
3602 if (key.isNumber() || (key >= QLatin1Char('a') && key <= QLatin1Char('f')) || (key >= QLatin1Char('A') && key <= QLatin1Char('F')) || key == m_blank)
3614 Returns true if the given text \a str is valid for any
3615 validator or input mask set for the line control.
3617 Otherwise returns false
3619 QQuickTextInputPrivate::ValidatorState QQuickTextInputPrivate::hasAcceptableInput(const QString &str) const
3621 #ifndef QT_NO_VALIDATOR
3622 QString textCopy = str;
3623 int cursorCopy = m_cursor;
3625 QValidator::State state = m_validator->validate(textCopy, cursorCopy);
3626 if (state != QValidator::Acceptable)
3627 return ValidatorState(state);
3632 return AcceptableInput;
3634 if (str.length() != m_maxLength)
3635 return InvalidInput;
3637 for (int i=0; i < m_maxLength; ++i) {
3638 if (m_maskData[i].separator) {
3639 if (str.at(i) != m_maskData[i].maskChar)
3640 return InvalidInput;
3642 if (!isValidInput(str.at(i), m_maskData[i].maskChar))
3643 return InvalidInput;
3646 return AcceptableInput;
3652 Applies the inputMask on \a str starting from position \a pos in the mask. \a clear
3653 specifies from where characters should be gotten when a separator is met in \a str - true means
3654 that blanks will be used, false that previous input is used.
3655 Calling this when no inputMask is set is undefined.
3657 QString QQuickTextInputPrivate::maskString(uint pos, const QString &str, bool clear) const
3659 if (pos >= (uint)m_maxLength)
3660 return QString::fromLatin1("");
3663 fill = clear ? clearString(0, m_maxLength) : m_text;
3666 QString s = QString::fromLatin1("");
3668 while (i < m_maxLength) {
3669 if (strIndex < str.length()) {
3670 if (m_maskData[i].separator) {
3671 s += m_maskData[i].maskChar;
3672 if (str[(int)strIndex] == m_maskData[i].maskChar)
3676 if (isValidInput(str[(int)strIndex], m_maskData[i].maskChar)) {
3677 switch (m_maskData[i].caseMode) {
3678 case MaskInputData::Upper:
3679 s += str[(int)strIndex].toUpper();
3681 case MaskInputData::Lower:
3682 s += str[(int)strIndex].toLower();
3685 s += str[(int)strIndex];
3689 // search for separator first
3690 int n = findInMask(i, true, true, str[(int)strIndex]);
3692 if (str.length() != 1 || i == 0 || (i > 0 && (!m_maskData[i-1].separator || m_maskData[i-1].maskChar != str[(int)strIndex]))) {
3693 s += fill.mid(i, n-i+1);
3694 i = n + 1; // update i to find + 1
3697 // search for valid m_blank if not
3698 n = findInMask(i, true, false, str[(int)strIndex]);
3700 s += fill.mid(i, n-i);
3701 switch (m_maskData[n].caseMode) {
3702 case MaskInputData::Upper:
3703 s += str[(int)strIndex].toUpper();
3705 case MaskInputData::Lower:
3706 s += str[(int)strIndex].toLower();
3709 s += str[(int)strIndex];
3711 i = n + 1; // updates i to find + 1
3729 Returns a "cleared" string with only separators and blank chars.
3730 Calling this when no inputMask is set is undefined.
3732 QString QQuickTextInputPrivate::clearString(uint pos, uint len) const
3734 if (pos >= (uint)m_maxLength)
3738 int end = qMin((uint)m_maxLength, pos + len);
3739 for (int i = pos; i < end; ++i)
3740 if (m_maskData[i].separator)
3741 s += m_maskData[i].maskChar;
3751 Strips blank parts of the input in a QQuickTextInputPrivate when an inputMask is set,
3752 separators are still included. Typically "127.0__.0__.1__" becomes "127.0.0.1".
3754 QString QQuickTextInputPrivate::stripString(const QString &str) const
3760 int end = qMin(m_maxLength, (int)str.length());
3761 for (int i = 0; i < end; ++i) {
3762 if (m_maskData[i].separator)
3763 s += m_maskData[i].maskChar;
3764 else if (str[i] != m_blank)
3773 searches forward/backward in m_maskData for either a separator or a m_blank
3775 int QQuickTextInputPrivate::findInMask(int pos, bool forward, bool findSeparator, QChar searchChar) const
3777 if (pos >= m_maxLength || pos < 0)
3780 int end = forward ? m_maxLength : -1;
3781 int step = forward ? 1 : -1;
3785 if (findSeparator) {
3786 if (m_maskData[i].separator && m_maskData[i].maskChar == searchChar)
3789 if (!m_maskData[i].separator) {
3790 if (searchChar.isNull())
3792 else if (isValidInput(searchChar, m_maskData[i].maskChar))
3801 void QQuickTextInputPrivate::internalUndo(int until)
3803 if (!isUndoAvailable())
3805 cancelPasswordEchoTimer();
3807 while (m_undoState && m_undoState > until) {
3808 Command& cmd = m_history[--m_undoState];
3811 m_text.remove(cmd.pos, 1);
3815 m_selstart = cmd.selStart;
3816 m_selend = cmd.selEnd;
3820 case RemoveSelection:
3821 m_text.insert(cmd.pos, cmd.uc);
3822 m_cursor = cmd.pos + 1;
3825 case DeleteSelection:
3826 m_text.insert(cmd.pos, cmd.uc);
3832 if (until < 0 && m_undoState) {
3833 Command& next = m_history[m_undoState-1];
3834 if (next.type != cmd.type
3835 && next.type < RemoveSelection
3836 && (cmd.type < RemoveSelection || next.type == Separator)) {
3845 void QQuickTextInputPrivate::internalRedo()
3847 if (!isRedoAvailable())
3850 while (m_undoState < (int)m_history.size()) {
3851 Command& cmd = m_history[m_undoState++];
3854 m_text.insert(cmd.pos, cmd.uc);
3855 m_cursor = cmd.pos + 1;
3858 m_selstart = cmd.selStart;
3859 m_selend = cmd.selEnd;
3864 case RemoveSelection:
3865 case DeleteSelection:
3866 m_text.remove(cmd.pos, 1);
3867 m_selstart = cmd.selStart;
3868 m_selend = cmd.selEnd;
3872 m_selstart = cmd.selStart;
3873 m_selend = cmd.selEnd;
3877 if (m_undoState < (int)m_history.size()) {
3878 Command& next = m_history[m_undoState];
3879 if (next.type != cmd.type
3880 && cmd.type < RemoveSelection
3881 && next.type != Separator
3882 && (next.type < RemoveSelection || cmd.type == Separator)) {
3890 void QQuickTextInputPrivate::emitUndoRedoChanged()
3892 Q_Q(QQuickTextInput);
3893 const bool previousUndo = canUndo;
3894 const bool previousRedo = canRedo;
3896 canUndo = isUndoAvailable();
3897 canRedo = isRedoAvailable();
3899 if (previousUndo != canUndo)
3900 emit q->canUndoChanged();
3901 if (previousRedo != canRedo)
3902 emit q->canRedoChanged();
3908 If the current cursor position differs from the last emitted cursor
3909 position, emits cursorPositionChanged().
3911 bool QQuickTextInputPrivate::emitCursorPositionChanged()
3913 Q_Q(QQuickTextInput);
3914 if (m_cursor != m_lastCursorPos) {
3915 m_lastCursorPos = m_cursor;
3917 q->updateCursorRectangle();
3918 emit q->cursorPositionChanged();
3920 if (!hasSelectedText()) {
3921 if (lastSelectionStart != m_cursor) {
3922 lastSelectionStart = m_cursor;
3923 emit q->selectionStartChanged();
3925 if (lastSelectionEnd != m_cursor) {
3926 lastSelectionEnd = m_cursor;
3927 emit q->selectionEndChanged();
3931 #ifndef QT_NO_ACCESSIBILITY
3932 QAccessibleTextCursorEvent ev(q, m_cursor);
3933 QAccessible::updateAccessibility(&ev);
3942 void QQuickTextInputPrivate::setCursorBlinkPeriod(int msec)
3944 Q_Q(QQuickTextInput);
3945 if (msec == m_blinkPeriod)
3948 q->killTimer(m_blinkTimer);
3951 m_blinkTimer = q->startTimer(msec / 2);
3955 if (m_blinkStatus == 1) {
3956 updateType = UpdatePaintNode;
3960 m_blinkPeriod = msec;
3963 void QQuickTextInput::timerEvent(QTimerEvent *event)
3965 Q_D(QQuickTextInput);
3966 if (event->timerId() == d->m_blinkTimer) {
3967 d->m_blinkStatus = !d->m_blinkStatus;
3968 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
3970 } else if (event->timerId() == d->m_passwordEchoTimer.timerId()) {
3971 d->m_passwordEchoTimer.stop();
3972 d->updateDisplayText();
3973 updateCursorRectangle();
3977 void QQuickTextInputPrivate::processKeyEvent(QKeyEvent* event)
3979 Q_Q(QQuickTextInput);
3981 if (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return) {
3982 if (hasAcceptableInput(m_text) || fixup()) {
3989 if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit
3990 && !m_passwordEchoEditing
3992 && !event->text().isEmpty()
3993 && !(event->modifiers() & Qt::ControlModifier)) {
3994 // Clear the edit and reset to normal echo mode while editing; the
3995 // echo mode switches back when the edit loses focus
3996 // ### resets current content. dubious code; you can
3997 // navigate with keys up, down, back, and select(?), but if you press
3998 // "left" or "right" it clears?
3999 updatePasswordEchoEditing(true);
4003 bool unknown = false;
4004 bool visual = cursorMoveStyle() == Qt::VisualMoveStyle;
4008 #ifndef QT_NO_SHORTCUT
4009 else if (event == QKeySequence::Undo) {
4012 else if (event == QKeySequence::Redo) {
4015 else if (event == QKeySequence::SelectAll) {
4018 #ifndef QT_NO_CLIPBOARD
4019 else if (event == QKeySequence::Copy) {
4022 else if (event == QKeySequence::Paste) {
4024 QClipboard::Mode mode = QClipboard::Clipboard;
4028 else if (event == QKeySequence::Cut) {
4034 else if (event == QKeySequence::DeleteEndOfLine) {
4038 #endif //QT_NO_CLIPBOARD
4039 else if (event == QKeySequence::MoveToStartOfLine || event == QKeySequence::MoveToStartOfBlock) {
4042 else if (event == QKeySequence::MoveToEndOfLine || event == QKeySequence::MoveToEndOfBlock) {
4045 else if (event == QKeySequence::SelectStartOfLine || event == QKeySequence::SelectStartOfBlock) {
4048 else if (event == QKeySequence::SelectEndOfLine || event == QKeySequence::SelectEndOfBlock) {
4051 else if (event == QKeySequence::MoveToNextChar) {
4052 if (hasSelectedText()) {
4053 moveCursor(selectionEnd(), false);
4055 cursorForward(0, visual ? 1 : (layoutDirection() == Qt::LeftToRight ? 1 : -1));
4058 else if (event == QKeySequence::SelectNextChar) {
4059 cursorForward(1, visual ? 1 : (layoutDirection() == Qt::LeftToRight ? 1 : -1));
4061 else if (event == QKeySequence::MoveToPreviousChar) {
4062 if (hasSelectedText()) {
4063 moveCursor(selectionStart(), false);
4065 cursorForward(0, visual ? -1 : (layoutDirection() == Qt::LeftToRight ? -1 : 1));
4068 else if (event == QKeySequence::SelectPreviousChar) {
4069 cursorForward(1, visual ? -1 : (layoutDirection() == Qt::LeftToRight ? -1 : 1));
4071 else if (event == QKeySequence::MoveToNextWord) {
4072 if (m_echoMode == QQuickTextInput::Normal)
4073 layoutDirection() == Qt::LeftToRight ? cursorWordForward(0) : cursorWordBackward(0);
4075 layoutDirection() == Qt::LeftToRight ? end(0) : home(0);
4077 else if (event == QKeySequence::MoveToPreviousWord) {
4078 if (m_echoMode == QQuickTextInput::Normal)
4079 layoutDirection() == Qt::LeftToRight ? cursorWordBackward(0) : cursorWordForward(0);
4080 else if (!m_readOnly) {
4081 layoutDirection() == Qt::LeftToRight ? home(0) : end(0);
4084 else if (event == QKeySequence::SelectNextWord) {
4085 if (m_echoMode == QQuickTextInput::Normal)
4086 layoutDirection() == Qt::LeftToRight ? cursorWordForward(1) : cursorWordBackward(1);
4088 layoutDirection() == Qt::LeftToRight ? end(1) : home(1);
4090 else if (event == QKeySequence::SelectPreviousWord) {
4091 if (m_echoMode == QQuickTextInput::Normal)
4092 layoutDirection() == Qt::LeftToRight ? cursorWordBackward(1) : cursorWordForward(1);
4094 layoutDirection() == Qt::LeftToRight ? home(1) : end(1);
4096 else if (event == QKeySequence::Delete) {
4100 else if (event == QKeySequence::DeleteEndOfWord) {
4104 else if (event == QKeySequence::DeleteStartOfWord) {
4106 deleteStartOfWord();
4108 #endif // QT_NO_SHORTCUT
4110 bool handled = false;
4111 if (event->modifiers() & Qt::ControlModifier) {
4112 switch (event->key()) {
4113 case Qt::Key_Backspace:
4115 deleteStartOfWord();
4121 } else { // ### check for *no* modifier
4122 switch (event->key()) {
4123 case Qt::Key_Backspace:
4135 if (event->key() == Qt::Key_Direction_L || event->key() == Qt::Key_Direction_R) {
4136 setLayoutDirection((event->key() == Qt::Key_Direction_L) ? Qt::LeftToRight : Qt::RightToLeft);
4140 if (unknown && !m_readOnly) {
4141 QString t = event->text();
4142 if (!t.isEmpty() && t.at(0).isPrint()) {
4158 Deletes the portion of the word before the current cursor position.
4161 void QQuickTextInputPrivate::deleteStartOfWord()
4163 int priorState = m_undoState;
4164 Command cmd(SetSelection, m_cursor, 0, m_selstart, m_selend);
4166 cursorWordBackward(true);
4168 removeSelectedText();
4169 finishChange(priorState);
4175 Deletes the portion of the word after the current cursor position.
4178 void QQuickTextInputPrivate::deleteEndOfWord()
4180 int priorState = m_undoState;
4181 Command cmd(SetSelection, m_cursor, 0, m_selstart, m_selend);
4183 cursorWordForward(true);
4184 // moveCursor (sometimes) calls separate() so we need to add the command after that so the
4185 // cursor position and selection are restored in the same undo operation as the remove.
4187 removeSelectedText();
4188 finishChange(priorState);
4194 Deletes all text from the cursor position to the end of the line.
4197 void QQuickTextInputPrivate::deleteEndOfLine()
4199 int priorState = m_undoState;
4200 Command cmd(SetSelection, m_cursor, 0, m_selstart, m_selend);
4202 setSelection(m_cursor, end());
4204 removeSelectedText();
4205 finishChange(priorState);