1 /****************************************************************************
3 ** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
6 ** This file is part of the QtQml module of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia. For licensing terms and
14 ** conditions see http://qt.digia.com/licensing. For further information
15 ** use the contact form at http://qt.digia.com/contact-us.
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights. These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file. Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
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::NotAtBoundary
2382 || (reasons & QTextBoundaryFinder::EndOfItem))) {
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::NotAtBoundary
2400 || (reasons & QTextBoundaryFinder::StartOfItem))) {
2401 finder.toNextBoundary();
2403 anchor = finder.position() != -1 ? finder.position() : text.length();
2405 finder.setPosition(pos);
2406 if (pos < text.length() && !finder.boundaryReasons())
2407 finder.toPreviousBoundary();
2408 const int cursor = finder.position() != -1 ? finder.position() : 0;
2410 d->setSelection(anchor, cursor - anchor);
2415 void QQuickTextInput::focusInEvent(QFocusEvent *event)
2417 Q_D(const QQuickTextInput);
2418 if (d->focusOnPress && !d->m_readOnly)
2419 qGuiApp->inputMethod()->show();
2420 QQuickImplicitSizeItem::focusInEvent(event);
2423 void QQuickTextInput::itemChange(ItemChange change, const ItemChangeData &value)
2425 Q_D(QQuickTextInput);
2426 if (change == ItemActiveFocusHasChanged) {
2427 bool hasFocus = value.boolValue;
2428 setCursorVisible(hasFocus);
2429 if (!hasFocus && (d->m_passwordEchoEditing || d->m_passwordEchoTimer.isActive())) {
2430 d->updatePasswordEchoEditing(false);//QQuickTextInputPrivate sets it on key events, but doesn't deal with focus events
2434 if (!d->persistentSelection)
2436 disconnect(qApp->inputMethod(), SIGNAL(inputDirectionChanged(Qt::LayoutDirection)),
2437 this, SLOT(q_updateAlignment()));
2439 q_updateAlignment();
2440 connect(qApp->inputMethod(), SIGNAL(inputDirectionChanged(Qt::LayoutDirection)),
2441 this, SLOT(q_updateAlignment()));
2444 QQuickItem::itemChange(change, value);
2448 \qmlproperty bool QtQuick2::TextInput::inputMethodComposing
2451 This property holds whether the TextInput has partial text input from an
2454 While it is composing an input method may rely on mouse or key events from
2455 the TextInput to edit or commit the partial text. This property can be
2456 used to determine when to disable events handlers that may interfere with
2457 the correct operation of an input method.
2459 bool QQuickTextInput::isInputMethodComposing() const
2461 Q_D(const QQuickTextInput);
2462 return d->hasImState;
2465 void QQuickTextInputPrivate::init()
2467 Q_Q(QQuickTextInput);
2468 #ifndef QT_NO_CLIPBOARD
2469 if (QGuiApplication::clipboard()->supportsSelection())
2470 q->setAcceptedMouseButtons(Qt::LeftButton | Qt::MiddleButton);
2473 q->setAcceptedMouseButtons(Qt::LeftButton);
2475 q->setFlag(QQuickItem::ItemAcceptsInputMethod);
2476 q->setFlag(QQuickItem::ItemHasContents);
2477 #ifndef QT_NO_CLIPBOARD
2478 q->connect(QGuiApplication::clipboard(), SIGNAL(dataChanged()),
2479 q, SLOT(q_canPasteChanged()));
2480 #endif // QT_NO_CLIPBOARD
2482 lastSelectionStart = 0;
2483 lastSelectionEnd = 0;
2484 determineHorizontalAlignment();
2486 if (!qmlDisableDistanceField()) {
2487 QTextOption option = m_textLayout.textOption();
2488 option.setUseDesignMetrics(renderType != QQuickTextInput::NativeRendering);
2489 m_textLayout.setTextOption(option);
2493 void QQuickTextInput::updateCursorRectangle()
2495 Q_D(QQuickTextInput);
2496 if (!isComponentComplete())
2499 d->updateHorizontalScroll();
2500 d->updateVerticalScroll();
2501 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
2503 emit cursorRectangleChanged();
2504 if (d->cursorItem) {
2505 QRectF r = cursorRectangle();
2506 d->cursorItem->setPos(r.topLeft());
2507 d->cursorItem->setHeight(r.height());
2509 updateInputMethod(Qt::ImCursorRectangle);
2512 void QQuickTextInput::selectionChanged()
2514 Q_D(QQuickTextInput);
2515 d->textLayoutDirty = true; //TODO: Only update rect in selection
2516 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
2518 emit selectedTextChanged();
2520 if (d->lastSelectionStart != d->selectionStart()) {
2521 d->lastSelectionStart = d->selectionStart();
2522 if (d->lastSelectionStart == -1)
2523 d->lastSelectionStart = d->m_cursor;
2524 emit selectionStartChanged();
2526 if (d->lastSelectionEnd != d->selectionEnd()) {
2527 d->lastSelectionEnd = d->selectionEnd();
2528 if (d->lastSelectionEnd == -1)
2529 d->lastSelectionEnd = d->m_cursor;
2530 emit selectionEndChanged();
2534 void QQuickTextInputPrivate::showCursor()
2536 if (textNode != 0 && textNode->cursorNode() != 0)
2537 textNode->cursorNode()->setColor(color);
2540 void QQuickTextInputPrivate::hideCursor()
2542 if (textNode != 0 && textNode->cursorNode() != 0)
2543 textNode->cursorNode()->setColor(QColor(0, 0, 0, 0));
2546 QRectF QQuickTextInput::boundingRect() const
2548 Q_D(const QQuickTextInput);
2550 int cursorWidth = d->cursorItem ? 0 : 1;
2552 qreal hscroll = d->hscroll;
2553 if (!d->autoScroll || d->contentSize.width() < width())
2554 hscroll -= QQuickTextUtil::alignedX(d->contentSize.width(), width(), effectiveHAlign());
2556 // Could include font max left/right bearings to either side of rectangle.
2557 QRectF r(-hscroll, -d->vscroll, d->contentSize.width(), d->contentSize.height());
2558 r.setRight(r.right() + cursorWidth);
2562 QRectF QQuickTextInput::clipRect() const
2564 Q_D(const QQuickTextInput);
2566 int cursorWidth = d->cursorItem ? d->cursorItem->width() : 1;
2568 // Could include font max left/right bearings to either side of rectangle.
2569 QRectF r = QQuickImplicitSizeItem::clipRect();
2570 r.setRight(r.right() + cursorWidth);
2574 void QQuickTextInput::q_canPasteChanged()
2576 Q_D(QQuickTextInput);
2577 bool old = d->canPaste;
2578 #ifndef QT_NO_CLIPBOARD
2579 if (const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData())
2580 d->canPaste = !d->m_readOnly && mimeData->hasText();
2582 d->canPaste = false;
2585 bool changed = d->canPaste != old || !d->canPasteValid;
2586 d->canPasteValid = true;
2588 emit canPasteChanged();
2592 void QQuickTextInput::q_updateAlignment()
2594 Q_D(QQuickTextInput);
2595 if (d->determineHorizontalAlignment()) {
2597 updateCursorRectangle();
2601 // ### these should come from QStyleHints
2602 const int textCursorWidth = 1;
2603 const bool fullWidthSelection = true;
2608 Updates the display text based of the current edit text
2609 If the text has changed will emit displayTextChanged()
2611 void QQuickTextInputPrivate::updateDisplayText(bool forceUpdate)
2613 QString orig = m_textLayout.text();
2615 if (m_echoMode == QQuickTextInput::NoEcho)
2616 str = QString::fromLatin1("");
2620 if (m_echoMode == QQuickTextInput::Password) {
2621 str.fill(m_passwordCharacter);
2622 if (m_passwordEchoTimer.isActive() && m_cursor > 0 && m_cursor <= m_text.length()) {
2623 int cursor = m_cursor - 1;
2624 QChar uc = m_text.at(cursor);
2626 if (cursor > 0 && uc.unicode() >= 0xdc00 && uc.unicode() < 0xe000) {
2627 // second half of a surrogate, check if we have the first half as well,
2628 // if yes restore both at once
2629 uc = m_text.at(cursor - 1);
2630 if (uc.unicode() >= 0xd800 && uc.unicode() < 0xdc00)
2631 str[cursor - 1] = uc;
2634 } else if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit && !m_passwordEchoEditing) {
2635 str.fill(m_passwordCharacter);
2638 // replace certain non-printable characters with spaces (to avoid
2639 // drawing boxes when using fonts that don't have glyphs for such
2641 QChar* uc = str.data();
2642 for (int i = 0; i < (int)str.length(); ++i) {
2643 if ((uc[i] < 0x20 && uc[i] != 0x09)
2644 || uc[i] == QChar::LineSeparator
2645 || uc[i] == QChar::ParagraphSeparator
2646 || uc[i] == QChar::ObjectReplacementCharacter)
2647 uc[i] = QChar(0x0020);
2650 if (str != orig || forceUpdate) {
2651 m_textLayout.setText(str);
2652 updateLayout(); // polish?
2653 emit q_func()->displayTextChanged();
2657 qreal QQuickTextInputPrivate::getImplicitWidth() const
2659 Q_Q(const QQuickTextInput);
2660 if (!requireImplicitWidth) {
2661 QQuickTextInputPrivate *d = const_cast<QQuickTextInputPrivate *>(this);
2662 d->requireImplicitWidth = true;
2664 if (q->isComponentComplete()) {
2665 // One time cost, only incurred if implicitWidth is first requested after
2666 // componentComplete.
2667 QTextLayout layout(m_text);
2669 QTextOption option = m_textLayout.textOption();
2670 option.setTextDirection(m_layoutDirection);
2671 option.setFlags(QTextOption::IncludeTrailingSpaces);
2672 option.setWrapMode(QTextOption::WrapMode(wrapMode));
2673 option.setAlignment(Qt::Alignment(q->effectiveHAlign()));
2674 layout.setTextOption(option);
2675 layout.setFont(font);
2676 layout.setPreeditArea(m_textLayout.preeditAreaPosition(), m_textLayout.preeditAreaText());
2677 layout.beginLayout();
2679 QTextLine line = layout.createLine();
2680 line.setLineWidth(INT_MAX);
2681 d->implicitWidth = qCeil(line.naturalTextWidth());
2686 return implicitWidth;
2689 void QQuickTextInputPrivate::updateLayout()
2691 Q_Q(QQuickTextInput);
2693 if (!q->isComponentComplete())
2697 QTextOption option = m_textLayout.textOption();
2698 option.setTextDirection(layoutDirection());
2699 option.setWrapMode(QTextOption::WrapMode(wrapMode));
2700 option.setAlignment(Qt::Alignment(q->effectiveHAlign()));
2701 m_textLayout.setTextOption(option);
2702 m_textLayout.setFont(font);
2704 m_textLayout.beginLayout();
2706 QTextLine line = m_textLayout.createLine();
2707 if (requireImplicitWidth) {
2708 line.setLineWidth(INT_MAX);
2709 const bool wasInLayout = inLayout;
2711 q->setImplicitWidth(qCeil(line.naturalTextWidth()));
2712 inLayout = wasInLayout;
2713 if (inLayout) // probably the result of a binding loop, but by letting it
2714 return; // get this far we'll get a warning to that effect.
2716 qreal lineWidth = q->widthValid() ? q->width() : INT_MAX;
2720 line.setLineWidth(lineWidth);
2721 line.setPosition(QPointF(0, height));
2723 height += line.height();
2724 width = qMax(width, line.naturalTextWidth());
2726 line = m_textLayout.createLine();
2727 } while (line.isValid());
2728 m_textLayout.endLayout();
2730 option.setWrapMode(QTextOption::NoWrap);
2731 m_textLayout.setTextOption(option);
2733 textLayoutDirty = true;
2735 const QSizeF previousSize = contentSize;
2736 contentSize = QSizeF(width, height);
2738 updateType = UpdatePaintNode;
2741 if (!requireImplicitWidth && !q->widthValid())
2742 q->setImplicitSize(width, height);
2744 q->setImplicitHeight(height);
2746 if (previousSize != contentSize)
2747 emit q->contentSizeChanged();
2750 #ifndef QT_NO_CLIPBOARD
2754 Copies the currently selected text into the clipboard using the given
2757 \note If the echo mode is set to a mode other than Normal then copy
2758 will not work. This is to prevent using copy as a method of bypassing
2759 password features of the line control.
2761 void QQuickTextInputPrivate::copy(QClipboard::Mode mode) const
2763 QString t = selectedText();
2764 if (!t.isEmpty() && m_echoMode == QQuickTextInput::Normal) {
2765 QGuiApplication::clipboard()->setText(t, mode);
2772 Inserts the text stored in the application clipboard into the line
2777 void QQuickTextInputPrivate::paste(QClipboard::Mode clipboardMode)
2779 QString clip = QGuiApplication::clipboard()->text(clipboardMode);
2780 if (!clip.isEmpty() || hasSelectedText()) {
2781 separate(); //make it a separate undo/redo command
2787 #endif // !QT_NO_CLIPBOARD
2792 void QQuickTextInputPrivate::commitPreedit()
2794 Q_Q(QQuickTextInput);
2799 qApp->inputMethod()->commit();
2804 QInputMethodEvent ev;
2805 QCoreApplication::sendEvent(q, &ev);
2808 void QQuickTextInputPrivate::cancelPreedit()
2810 Q_Q(QQuickTextInput);
2815 qApp->inputMethod()->reset();
2817 QInputMethodEvent ev;
2818 QCoreApplication::sendEvent(q, &ev);
2824 Handles the behavior for the backspace key or function.
2825 Removes the current selection if there is a selection, otherwise
2826 removes the character prior to the cursor position.
2830 void QQuickTextInputPrivate::backspace()
2832 int priorState = m_undoState;
2833 if (separateSelection()) {
2834 removeSelectedText();
2835 } else if (m_cursor) {
2838 m_cursor = prevMaskBlank(m_cursor);
2839 QChar uc = m_text.at(m_cursor);
2840 if (m_cursor > 0 && uc.unicode() >= 0xdc00 && uc.unicode() < 0xe000) {
2841 // second half of a surrogate, check if we have the first half as well,
2842 // if yes delete both at once
2843 uc = m_text.at(m_cursor - 1);
2844 if (uc.unicode() >= 0xd800 && uc.unicode() < 0xdc00) {
2845 internalDelete(true);
2849 internalDelete(true);
2851 finishChange(priorState);
2857 Handles the behavior for the delete key or function.
2858 Removes the current selection if there is a selection, otherwise
2859 removes the character after the cursor position.
2863 void QQuickTextInputPrivate::del()
2865 int priorState = m_undoState;
2866 if (separateSelection()) {
2867 removeSelectedText();
2869 int n = m_textLayout.nextCursorPosition(m_cursor) - m_cursor;
2873 finishChange(priorState);
2879 Inserts the given \a newText at the current cursor position.
2880 If there is any selected text it is removed prior to insertion of
2883 void QQuickTextInputPrivate::insert(const QString &newText)
2885 int priorState = m_undoState;
2886 if (separateSelection())
2887 removeSelectedText();
2888 internalInsert(newText);
2889 finishChange(priorState);
2895 Clears the line control text.
2897 void QQuickTextInputPrivate::clear()
2899 int priorState = m_undoState;
2900 separateSelection();
2902 m_selend = m_text.length();
2903 removeSelectedText();
2905 finishChange(priorState, /*update*/false, /*edited*/false);
2911 Sets \a length characters from the given \a start position as selected.
2912 The given \a start position must be within the current text for
2913 the line control. If \a length characters cannot be selected, then
2914 the selection will extend to the end of the current text.
2916 void QQuickTextInputPrivate::setSelection(int start, int length)
2918 Q_Q(QQuickTextInput);
2921 if (start < 0 || start > (int)m_text.length()){
2922 qWarning("QQuickTextInputPrivate::setSelection: Invalid start position");
2927 if (start == m_selstart && start + length == m_selend && m_cursor == m_selend)
2930 m_selend = qMin(start + length, (int)m_text.length());
2931 m_cursor = m_selend;
2932 } else if (length < 0){
2933 if (start == m_selend && start + length == m_selstart && m_cursor == m_selstart)
2935 m_selstart = qMax(start + length, 0);
2937 m_cursor = m_selstart;
2938 } else if (m_selstart != m_selend) {
2944 emitCursorPositionChanged();
2947 emit q->selectionChanged();
2948 emitCursorPositionChanged();
2949 q->updateInputMethod(Qt::ImCursorRectangle | Qt::ImAnchorPosition
2950 | Qt::ImCursorPosition | Qt::ImCurrentSelection);
2956 Sets the password echo editing to \a editing. If password echo editing
2957 is true, then the text of the password is displayed even if the echo
2958 mode is set to QLineEdit::PasswordEchoOnEdit. Password echoing editing
2959 does not affect other echo modes.
2961 void QQuickTextInputPrivate::updatePasswordEchoEditing(bool editing)
2963 cancelPasswordEchoTimer();
2964 m_passwordEchoEditing = editing;
2965 updateDisplayText();
2971 Fixes the current text so that it is valid given any set validators.
2973 Returns true if the text was changed. Otherwise returns false.
2975 bool QQuickTextInputPrivate::fixup() // this function assumes that validate currently returns != Acceptable
2977 #ifndef QT_NO_VALIDATOR
2979 QString textCopy = m_text;
2980 int cursorCopy = m_cursor;
2981 m_validator->fixup(textCopy);
2982 if (m_validator->validate(textCopy, cursorCopy) == QValidator::Acceptable) {
2983 if (textCopy != m_text || cursorCopy != m_cursor)
2984 internalSetText(textCopy, cursorCopy);
2995 Moves the cursor to the given position \a pos. If \a mark is true will
2996 adjust the currently selected text.
2998 void QQuickTextInputPrivate::moveCursor(int pos, bool mark)
3000 Q_Q(QQuickTextInput);
3003 if (pos != m_cursor) {
3006 pos = pos > m_cursor ? nextMaskBlank(pos) : prevMaskBlank(pos);
3010 if (m_selend > m_selstart && m_cursor == m_selstart)
3012 else if (m_selend > m_selstart && m_cursor == m_selend)
3013 anchor = m_selstart;
3016 m_selstart = qMin(anchor, pos);
3017 m_selend = qMax(anchor, pos);
3022 if (mark || m_selDirty) {
3024 emit q->selectionChanged();
3026 emitCursorPositionChanged();
3027 q->updateInputMethod();
3033 Applies the given input method event \a event to the text of the line
3036 void QQuickTextInputPrivate::processInputMethodEvent(QInputMethodEvent *event)
3038 Q_Q(QQuickTextInput);
3040 int priorState = -1;
3041 bool isGettingInput = !event->commitString().isEmpty()
3042 || event->preeditString() != preeditAreaText()
3043 || event->replacementLength() > 0;
3044 bool cursorPositionChanged = false;
3045 bool selectionChange = false;
3046 m_preeditDirty = event->preeditString() != preeditAreaText();
3048 if (isGettingInput) {
3049 // If any text is being input, remove selected text.
3050 priorState = m_undoState;
3051 separateSelection();
3052 if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit && !m_passwordEchoEditing) {
3053 updatePasswordEchoEditing(true);
3055 m_selend = m_text.length();
3057 removeSelectedText();
3060 int c = m_cursor; // cursor position after insertion of commit string
3061 if (event->replacementStart() <= 0)
3062 c += event->commitString().length() - qMin(-event->replacementStart(), event->replacementLength());
3064 m_cursor += event->replacementStart();
3068 // insert commit string
3069 if (event->replacementLength()) {
3070 m_selstart = m_cursor;
3071 m_selend = m_selstart + event->replacementLength();
3072 m_selend = qMin(m_selend, m_text.length());
3073 removeSelectedText();
3075 if (!event->commitString().isEmpty()) {
3076 internalInsert(event->commitString());
3077 cursorPositionChanged = true;
3080 m_cursor = qBound(0, c, m_text.length());
3082 for (int i = 0; i < event->attributes().size(); ++i) {
3083 const QInputMethodEvent::Attribute &a = event->attributes().at(i);
3084 if (a.type == QInputMethodEvent::Selection) {
3085 m_cursor = qBound(0, a.start + a.length, m_text.length());
3087 m_selstart = qMax(0, qMin(a.start, m_text.length()));
3088 m_selend = m_cursor;
3089 if (m_selend < m_selstart) {
3090 qSwap(m_selstart, m_selend);
3092 selectionChange = true;
3094 m_selstart = m_selend = 0;
3096 cursorPositionChanged = true;
3100 m_textLayout.setPreeditArea(m_cursor, event->preeditString());
3102 const int oldPreeditCursor = m_preeditCursor;
3103 m_preeditCursor = event->preeditString().length();
3104 hasImState = !event->preeditString().isEmpty();
3105 bool cursorVisible = true;
3106 QList<QTextLayout::FormatRange> formats;
3107 for (int i = 0; i < event->attributes().size(); ++i) {
3108 const QInputMethodEvent::Attribute &a = event->attributes().at(i);
3109 if (a.type == QInputMethodEvent::Cursor) {
3111 m_preeditCursor = a.start;
3112 cursorVisible = a.length != 0;
3113 } else if (a.type == QInputMethodEvent::TextFormat) {
3115 QTextCharFormat f = qvariant_cast<QTextFormat>(a.value).toCharFormat();
3117 QTextLayout::FormatRange o;
3118 o.start = a.start + m_cursor;
3119 o.length = a.length;
3125 m_textLayout.setAdditionalFormats(formats);
3127 updateDisplayText(/*force*/ true);
3128 if ((cursorPositionChanged && !emitCursorPositionChanged())
3129 || m_preeditCursor != oldPreeditCursor
3130 || isGettingInput) {
3131 q->updateCursorRectangle();
3135 finishChange(priorState);
3137 q->setCursorVisible(cursorVisible);
3139 if (selectionChange) {
3140 emit q->selectionChanged();
3141 q->updateInputMethod(Qt::ImCursorRectangle | Qt::ImAnchorPosition
3142 | Qt::ImCursorPosition | Qt::ImCurrentSelection);
3149 Sets the selection to cover the word at the given cursor position.
3150 The word boundaries are defined by the behavior of QTextLayout::SkipWords
3153 void QQuickTextInputPrivate::selectWordAtPos(int cursor)
3155 int next = cursor + 1;
3158 int c = m_textLayout.previousCursorPosition(next, QTextLayout::SkipWords);
3159 moveCursor(c, false);
3160 // ## text layout should support end of words.
3161 int end = m_textLayout.nextCursorPosition(c, QTextLayout::SkipWords);
3162 while (end > cursor && m_text[end-1].isSpace())
3164 moveCursor(end, true);
3170 Completes a change to the line control text. If the change is not valid
3171 will undo the line control state back to the given \a validateFromState.
3173 If \a edited is true and the change is valid, will emit textEdited() in
3174 addition to textChanged(). Otherwise only emits textChanged() on a valid
3177 The \a update value is currently unused.
3179 bool QQuickTextInputPrivate::finishChange(int validateFromState, bool update, bool /*edited*/)
3181 Q_Q(QQuickTextInput);
3184 bool inputMethodAttributesChanged = m_textDirty || m_selDirty;
3185 bool alignmentChanged = false;
3189 bool wasValidInput = m_validInput;
3190 bool wasAcceptable = m_acceptableInput;
3191 m_validInput = true;
3192 m_acceptableInput = true;
3193 #ifndef QT_NO_VALIDATOR
3195 QString textCopy = m_text;
3196 int cursorCopy = m_cursor;
3197 QValidator::State state = m_validator->validate(textCopy, cursorCopy);
3198 m_validInput = state != QValidator::Invalid;
3199 m_acceptableInput = state == QValidator::Acceptable;
3201 if (m_text != textCopy) {
3202 internalSetText(textCopy, cursorCopy);
3205 m_cursor = cursorCopy;
3209 if (validateFromState >= 0 && wasValidInput && !m_validInput) {
3210 if (m_transactions.count())
3212 internalUndo(validateFromState);
3213 m_history.resize(m_undoState);
3214 m_validInput = true;
3215 m_acceptableInput = wasAcceptable;
3216 m_textDirty = false;
3220 m_textDirty = false;
3221 m_preeditDirty = false;
3222 alignmentChanged = determineHorizontalAlignment();
3223 emit q->textChanged();
3226 updateDisplayText(alignmentChanged);
3228 if (m_acceptableInput != wasAcceptable)
3229 emit q->acceptableInputChanged();
3231 if (m_preeditDirty) {
3232 m_preeditDirty = false;
3233 if (determineHorizontalAlignment()) {
3234 alignmentChanged = true;
3241 emit q->selectionChanged();
3244 inputMethodAttributesChanged |= (m_cursor != m_lastCursorPos);
3245 if (inputMethodAttributesChanged)
3246 q->updateInputMethod();
3247 emitUndoRedoChanged();
3249 if (!emitCursorPositionChanged() && alignmentChanged)
3250 q->updateCursorRectangle();
3258 An internal function for setting the text of the line control.
3260 void QQuickTextInputPrivate::internalSetText(const QString &txt, int pos, bool edited)
3262 Q_Q(QQuickTextInput);
3264 QString oldText = m_text;
3266 m_text = maskString(0, txt, true);
3267 m_text += clearString(m_text.length(), m_maxLength - m_text.length());
3269 m_text = txt.isEmpty() ? txt : txt.left(m_maxLength);
3273 m_cursor = (pos < 0 || pos > m_text.length()) ? m_text.length() : pos;
3274 m_textDirty = (oldText != m_text);
3276 bool changed = finishChange(-1, true, edited);
3277 #ifdef QT_NO_ACCESSIBILITY
3281 QAccessibleTextUpdateEvent ev(q, 0, oldText, m_text);
3282 QAccessible::updateAccessibility(&ev);
3291 Adds the given \a command to the undo history
3292 of the line control. Does not apply the command.
3294 void QQuickTextInputPrivate::addCommand(const Command &cmd)
3296 if (m_separator && m_undoState && m_history[m_undoState - 1].type != Separator) {
3297 m_history.resize(m_undoState + 2);
3298 m_history[m_undoState++] = Command(Separator, m_cursor, 0, m_selstart, m_selend);
3300 m_history.resize(m_undoState + 1);
3302 m_separator = false;
3303 m_history[m_undoState++] = cmd;
3309 Inserts the given string \a s into the line
3312 Also adds the appropriate commands into the undo history.
3313 This function does not call finishChange(), and may leave the text
3314 in an invalid state.
3316 void QQuickTextInputPrivate::internalInsert(const QString &s)
3318 Q_Q(QQuickTextInput);
3319 if (m_echoMode == QQuickTextInput::Password) {
3320 int delay = qGuiApp->styleHints()->passwordMaskDelay();
3322 m_passwordEchoTimer.start(delay, q);
3324 Q_ASSERT(!hasSelectedText()); // insert(), processInputMethodEvent() call removeSelectedText() first.
3326 QString ms = maskString(m_cursor, s);
3327 for (int i = 0; i < (int) ms.length(); ++i) {
3328 addCommand (Command(DeleteSelection, m_cursor + i, m_text.at(m_cursor + i), -1, -1));
3329 addCommand(Command(Insert, m_cursor + i, ms.at(i), -1, -1));
3331 m_text.replace(m_cursor, ms.length(), ms);
3332 m_cursor += ms.length();
3333 m_cursor = nextMaskBlank(m_cursor);
3336 int remaining = m_maxLength - m_text.length();
3337 if (remaining != 0) {
3338 m_text.insert(m_cursor, s.left(remaining));
3339 for (int i = 0; i < (int) s.left(remaining).length(); ++i)
3340 addCommand(Command(Insert, m_cursor++, s.at(i), -1, -1));
3349 deletes a single character from the current text. If \a wasBackspace,
3350 the character prior to the cursor is removed. Otherwise the character
3351 after the cursor is removed.
3353 Also adds the appropriate commands into the undo history.
3354 This function does not call finishChange(), and may leave the text
3355 in an invalid state.
3357 void QQuickTextInputPrivate::internalDelete(bool wasBackspace)
3359 if (m_cursor < (int) m_text.length()) {
3360 cancelPasswordEchoTimer();
3361 Q_ASSERT(!hasSelectedText()); // del(), backspace() call removeSelectedText() first.
3362 addCommand(Command((CommandType)((m_maskData ? 2 : 0) + (wasBackspace ? Remove : Delete)),
3363 m_cursor, m_text.at(m_cursor), -1, -1));
3365 m_text.replace(m_cursor, 1, clearString(m_cursor, 1));
3366 addCommand(Command(Insert, m_cursor, m_text.at(m_cursor), -1, -1));
3368 m_text.remove(m_cursor, 1);
3377 removes the currently selected text from the line control.
3379 Also adds the appropriate commands into the undo history.
3380 This function does not call finishChange(), and may leave the text
3381 in an invalid state.
3383 void QQuickTextInputPrivate::removeSelectedText()
3385 if (m_selstart < m_selend && m_selend <= (int) m_text.length()) {
3386 cancelPasswordEchoTimer();
3388 if (m_selstart <= m_cursor && m_cursor < m_selend) {
3389 // cursor is within the selection. Split up the commands
3390 // to be able to restore the correct cursor position
3391 for (i = m_cursor; i >= m_selstart; --i)
3392 addCommand (Command(DeleteSelection, i, m_text.at(i), -1, 1));
3393 for (i = m_selend - 1; i > m_cursor; --i)
3394 addCommand (Command(DeleteSelection, i - m_cursor + m_selstart - 1, m_text.at(i), -1, -1));
3396 for (i = m_selend-1; i >= m_selstart; --i)
3397 addCommand (Command(RemoveSelection, i, m_text.at(i), -1, -1));
3400 m_text.replace(m_selstart, m_selend - m_selstart, clearString(m_selstart, m_selend - m_selstart));
3401 for (int i = 0; i < m_selend - m_selstart; ++i)
3402 addCommand(Command(Insert, m_selstart + i, m_text.at(m_selstart + i), -1, -1));
3404 m_text.remove(m_selstart, m_selend - m_selstart);
3406 if (m_cursor > m_selstart)
3407 m_cursor -= qMin(m_cursor, m_selend) - m_selstart;
3416 Adds the current selection to the undo history.
3418 Returns true if there is a current selection and false otherwise.
3421 bool QQuickTextInputPrivate::separateSelection()
3423 if (hasSelectedText()) {
3425 addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
3435 Parses the input mask specified by \a maskFields to generate
3436 the mask data used to handle input masks.
3438 void QQuickTextInputPrivate::parseInputMask(const QString &maskFields)
3440 int delimiter = maskFields.indexOf(QLatin1Char(';'));
3441 if (maskFields.isEmpty() || delimiter == 0) {
3443 delete [] m_maskData;
3445 m_maxLength = 32767;
3446 internalSetText(QString());
3451 if (delimiter == -1) {
3452 m_blank = QLatin1Char(' ');
3453 m_inputMask = maskFields;
3455 m_inputMask = maskFields.left(delimiter);
3456 m_blank = (delimiter + 1 < maskFields.length()) ? maskFields[delimiter + 1] : QLatin1Char(' ');
3459 // calculate m_maxLength / m_maskData length
3462 for (int i=0; i<m_inputMask.length(); i++) {
3463 c = m_inputMask.at(i);
3464 if (i > 0 && m_inputMask.at(i-1) == QLatin1Char('\\')) {
3468 if (c != QLatin1Char('\\') && c != QLatin1Char('!') &&
3469 c != QLatin1Char('<') && c != QLatin1Char('>') &&
3470 c != QLatin1Char('{') && c != QLatin1Char('}') &&
3471 c != QLatin1Char('[') && c != QLatin1Char(']'))
3475 delete [] m_maskData;
3476 m_maskData = new MaskInputData[m_maxLength];
3478 MaskInputData::Casemode m = MaskInputData::NoCaseMode;
3481 bool escape = false;
3483 for (int i = 0; i < m_inputMask.length(); i++) {
3484 c = m_inputMask.at(i);
3487 m_maskData[index].maskChar = c;
3488 m_maskData[index].separator = s;
3489 m_maskData[index].caseMode = m;
3492 } else if (c == QLatin1Char('<')) {
3493 m = MaskInputData::Lower;
3494 } else if (c == QLatin1Char('>')) {
3495 m = MaskInputData::Upper;
3496 } else if (c == QLatin1Char('!')) {
3497 m = MaskInputData::NoCaseMode;
3498 } else if (c != QLatin1Char('{') && c != QLatin1Char('}') && c != QLatin1Char('[') && c != QLatin1Char(']')) {
3499 switch (c.unicode()) {
3525 m_maskData[index].maskChar = c;
3526 m_maskData[index].separator = s;
3527 m_maskData[index].caseMode = m;
3532 internalSetText(m_text);
3539 checks if the key is valid compared to the inputMask
3541 bool QQuickTextInputPrivate::isValidInput(QChar key, QChar mask) const
3543 switch (mask.unicode()) {
3549 if (key.isLetter() || key == m_blank)
3553 if (key.isLetterOrNumber())
3557 if (key.isLetterOrNumber() || key == m_blank)
3565 if (key.isPrint() || key == m_blank)
3573 if (key.isNumber() || key == m_blank)
3577 if (key.isNumber() && key.digitValue() > 0)
3581 if ((key.isNumber() && key.digitValue() > 0) || key == m_blank)
3585 if (key.isNumber() || key == QLatin1Char('+') || key == QLatin1Char('-') || key == m_blank)
3589 if (key == QLatin1Char('0') || key == QLatin1Char('1'))
3593 if (key == QLatin1Char('0') || key == QLatin1Char('1') || key == m_blank)
3597 if (key.isNumber() || (key >= QLatin1Char('a') && key <= QLatin1Char('f')) || (key >= QLatin1Char('A') && key <= QLatin1Char('F')))
3601 if (key.isNumber() || (key >= QLatin1Char('a') && key <= QLatin1Char('f')) || (key >= QLatin1Char('A') && key <= QLatin1Char('F')) || key == m_blank)
3613 Returns true if the given text \a str is valid for any
3614 validator or input mask set for the line control.
3616 Otherwise returns false
3618 QQuickTextInputPrivate::ValidatorState QQuickTextInputPrivate::hasAcceptableInput(const QString &str) const
3620 #ifndef QT_NO_VALIDATOR
3621 QString textCopy = str;
3622 int cursorCopy = m_cursor;
3624 QValidator::State state = m_validator->validate(textCopy, cursorCopy);
3625 if (state != QValidator::Acceptable)
3626 return ValidatorState(state);
3631 return AcceptableInput;
3633 if (str.length() != m_maxLength)
3634 return InvalidInput;
3636 for (int i=0; i < m_maxLength; ++i) {
3637 if (m_maskData[i].separator) {
3638 if (str.at(i) != m_maskData[i].maskChar)
3639 return InvalidInput;
3641 if (!isValidInput(str.at(i), m_maskData[i].maskChar))
3642 return InvalidInput;
3645 return AcceptableInput;
3651 Applies the inputMask on \a str starting from position \a pos in the mask. \a clear
3652 specifies from where characters should be gotten when a separator is met in \a str - true means
3653 that blanks will be used, false that previous input is used.
3654 Calling this when no inputMask is set is undefined.
3656 QString QQuickTextInputPrivate::maskString(uint pos, const QString &str, bool clear) const
3658 if (pos >= (uint)m_maxLength)
3659 return QString::fromLatin1("");
3662 fill = clear ? clearString(0, m_maxLength) : m_text;
3665 QString s = QString::fromLatin1("");
3667 while (i < m_maxLength) {
3668 if (strIndex < str.length()) {
3669 if (m_maskData[i].separator) {
3670 s += m_maskData[i].maskChar;
3671 if (str[(int)strIndex] == m_maskData[i].maskChar)
3675 if (isValidInput(str[(int)strIndex], m_maskData[i].maskChar)) {
3676 switch (m_maskData[i].caseMode) {
3677 case MaskInputData::Upper:
3678 s += str[(int)strIndex].toUpper();
3680 case MaskInputData::Lower:
3681 s += str[(int)strIndex].toLower();
3684 s += str[(int)strIndex];
3688 // search for separator first
3689 int n = findInMask(i, true, true, str[(int)strIndex]);
3691 if (str.length() != 1 || i == 0 || (i > 0 && (!m_maskData[i-1].separator || m_maskData[i-1].maskChar != str[(int)strIndex]))) {
3692 s += fill.mid(i, n-i+1);
3693 i = n + 1; // update i to find + 1
3696 // search for valid m_blank if not
3697 n = findInMask(i, true, false, str[(int)strIndex]);
3699 s += fill.mid(i, n-i);
3700 switch (m_maskData[n].caseMode) {
3701 case MaskInputData::Upper:
3702 s += str[(int)strIndex].toUpper();
3704 case MaskInputData::Lower:
3705 s += str[(int)strIndex].toLower();
3708 s += str[(int)strIndex];
3710 i = n + 1; // updates i to find + 1
3728 Returns a "cleared" string with only separators and blank chars.
3729 Calling this when no inputMask is set is undefined.
3731 QString QQuickTextInputPrivate::clearString(uint pos, uint len) const
3733 if (pos >= (uint)m_maxLength)
3737 int end = qMin((uint)m_maxLength, pos + len);
3738 for (int i = pos; i < end; ++i)
3739 if (m_maskData[i].separator)
3740 s += m_maskData[i].maskChar;
3750 Strips blank parts of the input in a QQuickTextInputPrivate when an inputMask is set,
3751 separators are still included. Typically "127.0__.0__.1__" becomes "127.0.0.1".
3753 QString QQuickTextInputPrivate::stripString(const QString &str) const
3759 int end = qMin(m_maxLength, (int)str.length());
3760 for (int i = 0; i < end; ++i) {
3761 if (m_maskData[i].separator)
3762 s += m_maskData[i].maskChar;
3763 else if (str[i] != m_blank)
3772 searches forward/backward in m_maskData for either a separator or a m_blank
3774 int QQuickTextInputPrivate::findInMask(int pos, bool forward, bool findSeparator, QChar searchChar) const
3776 if (pos >= m_maxLength || pos < 0)
3779 int end = forward ? m_maxLength : -1;
3780 int step = forward ? 1 : -1;
3784 if (findSeparator) {
3785 if (m_maskData[i].separator && m_maskData[i].maskChar == searchChar)
3788 if (!m_maskData[i].separator) {
3789 if (searchChar.isNull())
3791 else if (isValidInput(searchChar, m_maskData[i].maskChar))
3800 void QQuickTextInputPrivate::internalUndo(int until)
3802 if (!isUndoAvailable())
3804 cancelPasswordEchoTimer();
3806 while (m_undoState && m_undoState > until) {
3807 Command& cmd = m_history[--m_undoState];
3810 m_text.remove(cmd.pos, 1);
3814 m_selstart = cmd.selStart;
3815 m_selend = cmd.selEnd;
3819 case RemoveSelection:
3820 m_text.insert(cmd.pos, cmd.uc);
3821 m_cursor = cmd.pos + 1;
3824 case DeleteSelection:
3825 m_text.insert(cmd.pos, cmd.uc);
3831 if (until < 0 && m_undoState) {
3832 Command& next = m_history[m_undoState-1];
3833 if (next.type != cmd.type
3834 && next.type < RemoveSelection
3835 && (cmd.type < RemoveSelection || next.type == Separator)) {
3844 void QQuickTextInputPrivate::internalRedo()
3846 if (!isRedoAvailable())
3849 while (m_undoState < (int)m_history.size()) {
3850 Command& cmd = m_history[m_undoState++];
3853 m_text.insert(cmd.pos, cmd.uc);
3854 m_cursor = cmd.pos + 1;
3857 m_selstart = cmd.selStart;
3858 m_selend = cmd.selEnd;
3863 case RemoveSelection:
3864 case DeleteSelection:
3865 m_text.remove(cmd.pos, 1);
3866 m_selstart = cmd.selStart;
3867 m_selend = cmd.selEnd;
3871 m_selstart = cmd.selStart;
3872 m_selend = cmd.selEnd;
3876 if (m_undoState < (int)m_history.size()) {
3877 Command& next = m_history[m_undoState];
3878 if (next.type != cmd.type
3879 && cmd.type < RemoveSelection
3880 && next.type != Separator
3881 && (next.type < RemoveSelection || cmd.type == Separator)) {
3889 void QQuickTextInputPrivate::emitUndoRedoChanged()
3891 Q_Q(QQuickTextInput);
3892 const bool previousUndo = canUndo;
3893 const bool previousRedo = canRedo;
3895 canUndo = isUndoAvailable();
3896 canRedo = isRedoAvailable();
3898 if (previousUndo != canUndo)
3899 emit q->canUndoChanged();
3900 if (previousRedo != canRedo)
3901 emit q->canRedoChanged();
3907 If the current cursor position differs from the last emitted cursor
3908 position, emits cursorPositionChanged().
3910 bool QQuickTextInputPrivate::emitCursorPositionChanged()
3912 Q_Q(QQuickTextInput);
3913 if (m_cursor != m_lastCursorPos) {
3914 m_lastCursorPos = m_cursor;
3916 q->updateCursorRectangle();
3917 emit q->cursorPositionChanged();
3919 if (!hasSelectedText()) {
3920 if (lastSelectionStart != m_cursor) {
3921 lastSelectionStart = m_cursor;
3922 emit q->selectionStartChanged();
3924 if (lastSelectionEnd != m_cursor) {
3925 lastSelectionEnd = m_cursor;
3926 emit q->selectionEndChanged();
3930 #ifndef QT_NO_ACCESSIBILITY
3931 QAccessibleTextCursorEvent ev(q, m_cursor);
3932 QAccessible::updateAccessibility(&ev);
3941 void QQuickTextInputPrivate::setCursorBlinkPeriod(int msec)
3943 Q_Q(QQuickTextInput);
3944 if (msec == m_blinkPeriod)
3947 q->killTimer(m_blinkTimer);
3950 m_blinkTimer = q->startTimer(msec / 2);
3954 if (m_blinkStatus == 1) {
3955 updateType = UpdatePaintNode;
3959 m_blinkPeriod = msec;
3962 void QQuickTextInput::timerEvent(QTimerEvent *event)
3964 Q_D(QQuickTextInput);
3965 if (event->timerId() == d->m_blinkTimer) {
3966 d->m_blinkStatus = !d->m_blinkStatus;
3967 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
3969 } else if (event->timerId() == d->m_passwordEchoTimer.timerId()) {
3970 d->m_passwordEchoTimer.stop();
3971 d->updateDisplayText();
3972 updateCursorRectangle();
3976 void QQuickTextInputPrivate::processKeyEvent(QKeyEvent* event)
3978 Q_Q(QQuickTextInput);
3980 if (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return) {
3981 if (hasAcceptableInput(m_text) || fixup()) {
3988 if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit
3989 && !m_passwordEchoEditing
3991 && !event->text().isEmpty()
3992 && !(event->modifiers() & Qt::ControlModifier)) {
3993 // Clear the edit and reset to normal echo mode while editing; the
3994 // echo mode switches back when the edit loses focus
3995 // ### resets current content. dubious code; you can
3996 // navigate with keys up, down, back, and select(?), but if you press
3997 // "left" or "right" it clears?
3998 updatePasswordEchoEditing(true);
4002 bool unknown = false;
4003 bool visual = cursorMoveStyle() == Qt::VisualMoveStyle;
4007 #ifndef QT_NO_SHORTCUT
4008 else if (event == QKeySequence::Undo) {
4011 else if (event == QKeySequence::Redo) {
4014 else if (event == QKeySequence::SelectAll) {
4017 #ifndef QT_NO_CLIPBOARD
4018 else if (event == QKeySequence::Copy) {
4021 else if (event == QKeySequence::Paste) {
4023 QClipboard::Mode mode = QClipboard::Clipboard;
4027 else if (event == QKeySequence::Cut) {
4033 else if (event == QKeySequence::DeleteEndOfLine) {
4037 #endif //QT_NO_CLIPBOARD
4038 else if (event == QKeySequence::MoveToStartOfLine || event == QKeySequence::MoveToStartOfBlock) {
4041 else if (event == QKeySequence::MoveToEndOfLine || event == QKeySequence::MoveToEndOfBlock) {
4044 else if (event == QKeySequence::SelectStartOfLine || event == QKeySequence::SelectStartOfBlock) {
4047 else if (event == QKeySequence::SelectEndOfLine || event == QKeySequence::SelectEndOfBlock) {
4050 else if (event == QKeySequence::MoveToNextChar) {
4051 if (hasSelectedText()) {
4052 moveCursor(selectionEnd(), false);
4054 cursorForward(0, visual ? 1 : (layoutDirection() == Qt::LeftToRight ? 1 : -1));
4057 else if (event == QKeySequence::SelectNextChar) {
4058 cursorForward(1, visual ? 1 : (layoutDirection() == Qt::LeftToRight ? 1 : -1));
4060 else if (event == QKeySequence::MoveToPreviousChar) {
4061 if (hasSelectedText()) {
4062 moveCursor(selectionStart(), false);
4064 cursorForward(0, visual ? -1 : (layoutDirection() == Qt::LeftToRight ? -1 : 1));
4067 else if (event == QKeySequence::SelectPreviousChar) {
4068 cursorForward(1, visual ? -1 : (layoutDirection() == Qt::LeftToRight ? -1 : 1));
4070 else if (event == QKeySequence::MoveToNextWord) {
4071 if (m_echoMode == QQuickTextInput::Normal)
4072 layoutDirection() == Qt::LeftToRight ? cursorWordForward(0) : cursorWordBackward(0);
4074 layoutDirection() == Qt::LeftToRight ? end(0) : home(0);
4076 else if (event == QKeySequence::MoveToPreviousWord) {
4077 if (m_echoMode == QQuickTextInput::Normal)
4078 layoutDirection() == Qt::LeftToRight ? cursorWordBackward(0) : cursorWordForward(0);
4079 else if (!m_readOnly) {
4080 layoutDirection() == Qt::LeftToRight ? home(0) : end(0);
4083 else if (event == QKeySequence::SelectNextWord) {
4084 if (m_echoMode == QQuickTextInput::Normal)
4085 layoutDirection() == Qt::LeftToRight ? cursorWordForward(1) : cursorWordBackward(1);
4087 layoutDirection() == Qt::LeftToRight ? end(1) : home(1);
4089 else if (event == QKeySequence::SelectPreviousWord) {
4090 if (m_echoMode == QQuickTextInput::Normal)
4091 layoutDirection() == Qt::LeftToRight ? cursorWordBackward(1) : cursorWordForward(1);
4093 layoutDirection() == Qt::LeftToRight ? home(1) : end(1);
4095 else if (event == QKeySequence::Delete) {
4099 else if (event == QKeySequence::DeleteEndOfWord) {
4103 else if (event == QKeySequence::DeleteStartOfWord) {
4105 deleteStartOfWord();
4107 #endif // QT_NO_SHORTCUT
4109 bool handled = false;
4110 if (event->modifiers() & Qt::ControlModifier) {
4111 switch (event->key()) {
4112 case Qt::Key_Backspace:
4114 deleteStartOfWord();
4120 } else { // ### check for *no* modifier
4121 switch (event->key()) {
4122 case Qt::Key_Backspace:
4134 if (event->key() == Qt::Key_Direction_L || event->key() == Qt::Key_Direction_R) {
4135 setLayoutDirection((event->key() == Qt::Key_Direction_L) ? Qt::LeftToRight : Qt::RightToLeft);
4139 if (unknown && !m_readOnly) {
4140 QString t = event->text();
4141 if (!t.isEmpty() && t.at(0).isPrint()) {
4157 Deletes the portion of the word before the current cursor position.
4160 void QQuickTextInputPrivate::deleteStartOfWord()
4162 int priorState = m_undoState;
4163 Command cmd(SetSelection, m_cursor, 0, m_selstart, m_selend);
4165 cursorWordBackward(true);
4167 removeSelectedText();
4168 finishChange(priorState);
4174 Deletes the portion of the word after the current cursor position.
4177 void QQuickTextInputPrivate::deleteEndOfWord()
4179 int priorState = m_undoState;
4180 Command cmd(SetSelection, m_cursor, 0, m_selstart, m_selend);
4182 cursorWordForward(true);
4183 // moveCursor (sometimes) calls separate() so we need to add the command after that so the
4184 // cursor position and selection are restored in the same undo operation as the remove.
4186 removeSelectedText();
4187 finishChange(priorState);
4193 Deletes all text from the cursor position to the end of the line.
4196 void QQuickTextInputPrivate::deleteEndOfLine()
4198 int priorState = m_undoState;
4199 Command cmd(SetSelection, m_cursor, 0, m_selstart, m_selend);
4201 setSelection(m_cursor, end());
4203 removeSelectedText();
4204 finishChange(priorState);