1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the QtQml module of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #include "qquicktextinput_p.h"
43 #include "qquicktextinput_p_p.h"
44 #include "qquickcanvas.h"
46 #include <private/qqmlglobal_p.h>
48 #include <QtCore/qcoreapplication.h>
49 #include <QtQml/qqmlinfo.h>
50 #include <QtGui/qevent.h>
51 #include <QTextBoundaryFinder>
52 #include "qquicktextnode_p.h"
53 #include <QtQuick/qsgsimplerectnode.h>
55 #include <QtGui/qstylehints.h>
56 #include <QtGui/qinputmethod.h>
58 #ifndef QT_NO_ACCESSIBILITY
59 #include "qaccessible.h"
64 DEFINE_BOOL_CONFIG_OPTION(qmlDisableDistanceField, QML_DISABLE_DISTANCEFIELD)
67 \qmlclass TextInput QQuickTextInput
68 \inqmlmodule QtQuick 2
69 \ingroup qml-basic-visual-elements
70 \brief The TextInput item displays an editable line of text.
73 The TextInput element displays a single line of editable plain text.
75 TextInput is used to accept a line of text input. Input constraints
76 can be placed on a TextInput item (for example, through a \l validator or \l inputMask),
77 and setting \l echoMode to an appropriate value enables TextInput to be used for
78 a password input field.
80 On Mac OS X, the Up/Down key bindings for Home/End are explicitly disabled.
81 If you want such bindings (on any platform), you will need to construct them in QML.
83 \sa TextEdit, Text, {declarative/text/textselection}{Text Selection example}
85 QQuickTextInput::QQuickTextInput(QQuickItem* parent)
86 : QQuickImplicitSizeItem(*(new QQuickTextInputPrivate), parent)
92 QQuickTextInput::~QQuickTextInput()
96 void QQuickTextInput::componentComplete()
100 QQuickImplicitSizeItem::componentComplete();
104 updateCursorRectangle();
105 if (d->cursorComponent && d->cursorComponent->isReady())
110 \qmlproperty string QtQuick2::TextInput::text
112 The text in the TextInput.
114 QString QQuickTextInput::text() const
116 Q_D(const QQuickTextInput);
118 QString content = d->m_text;
119 QString res = d->m_maskData ? d->stripString(content) : content;
120 return (res.isNull() ? QString::fromLatin1("") : res);
123 void QQuickTextInput::setText(const QString &s)
125 Q_D(QQuickTextInput);
130 d->internalSetText(s, -1, false);
134 \qmlproperty int QtQuick2::TextInput::length
136 Returns the total number of characters in the TextInput item.
138 If the TextInput has an inputMask the length will include mask characters and may differ
139 from the length of the string returned by the \l text property.
141 This property can be faster than querying the length the \l text property as it doesn't
142 require any copying or conversion of the TextInput's internal string data.
145 int QQuickTextInput::length() const
147 Q_D(const QQuickTextInput);
148 return d->m_text.length();
152 \qmlmethod string QtQuick2::TextInput::getText(int start, int end)
154 Returns the section of text that is between the \a start and \a end positions.
156 If the TextInput has an inputMask the length will include mask characters.
159 QString QQuickTextInput::getText(int start, int end) const
161 Q_D(const QQuickTextInput);
166 return d->m_text.mid(start, end - start);
169 QString QQuickTextInputPrivate::realText() const
171 QString res = m_maskData ? stripString(m_text) : m_text;
172 return (res.isNull() ? QString::fromLatin1("") : res);
176 \qmlproperty string QtQuick2::TextInput::font.family
178 Sets the family name of the font.
180 The family name is case insensitive and may optionally include a foundry name, e.g. "Helvetica [Cronyx]".
181 If the family is available from more than one foundry and the foundry isn't specified, an arbitrary foundry is chosen.
182 If the family isn't available a family will be set using the font matching algorithm.
186 \qmlproperty bool QtQuick2::TextInput::font.bold
188 Sets whether the font weight is bold.
192 \qmlproperty enumeration QtQuick2::TextInput::font.weight
194 Sets the font's weight.
196 The weight can be one of:
199 \li Font.Normal - the default
206 TextInput { text: "Hello"; font.weight: Font.DemiBold }
211 \qmlproperty bool QtQuick2::TextInput::font.italic
213 Sets whether the font has an italic style.
217 \qmlproperty bool QtQuick2::TextInput::font.underline
219 Sets whether the text is underlined.
223 \qmlproperty bool QtQuick2::TextInput::font.strikeout
225 Sets whether the font has a strikeout style.
229 \qmlproperty real QtQuick2::TextInput::font.pointSize
231 Sets the font size in points. The point size must be greater than zero.
235 \qmlproperty int QtQuick2::TextInput::font.pixelSize
237 Sets the font size in pixels.
239 Using this function makes the font device dependent.
240 Use \c pointSize to set the size of the font in a device independent manner.
244 \qmlproperty real QtQuick2::TextInput::font.letterSpacing
246 Sets the letter spacing for the font.
248 Letter spacing changes the default spacing between individual letters in the font.
249 A positive value increases the letter spacing by the corresponding pixels; a negative value decreases the spacing.
253 \qmlproperty real QtQuick2::TextInput::font.wordSpacing
255 Sets the word spacing for the font.
257 Word spacing changes the default spacing between individual words.
258 A positive value increases the word spacing by a corresponding amount of pixels,
259 while a negative value decreases the inter-word spacing accordingly.
263 \qmlproperty enumeration QtQuick2::TextInput::font.capitalization
265 Sets the capitalization for the text.
268 \li Font.MixedCase - This is the normal text rendering option where no capitalization change is applied.
269 \li Font.AllUppercase - This alters the text to be rendered in all uppercase type.
270 \li Font.AllLowercase - This alters the text to be rendered in all lowercase type.
271 \li Font.SmallCaps - This alters the text to be rendered in small-caps type.
272 \li Font.Capitalize - This alters the text to be rendered with the first character of each word as an uppercase character.
276 TextInput { text: "Hello"; font.capitalization: Font.AllLowercase }
280 QFont QQuickTextInput::font() const
282 Q_D(const QQuickTextInput);
283 return d->sourceFont;
286 void QQuickTextInput::setFont(const QFont &font)
288 Q_D(QQuickTextInput);
289 if (d->sourceFont == font)
292 d->sourceFont = font;
293 QFont oldFont = d->font;
295 if (d->font.pointSizeF() != -1) {
297 qreal size = qRound(d->font.pointSizeF()*2.0);
298 d->font.setPointSizeF(size/2.0);
300 if (oldFont != d->font) {
302 updateCursorRectangle();
303 updateInputMethod(Qt::ImCursorRectangle | Qt::ImFont);
305 emit fontChanged(d->sourceFont);
309 \qmlproperty color QtQuick2::TextInput::color
313 QColor QQuickTextInput::color() const
315 Q_D(const QQuickTextInput);
319 void QQuickTextInput::setColor(const QColor &c)
321 Q_D(QQuickTextInput);
324 d->textLayoutDirty = true;
325 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
333 \qmlproperty color QtQuick2::TextInput::selectionColor
335 The text highlight color, used behind selections.
337 QColor QQuickTextInput::selectionColor() const
339 Q_D(const QQuickTextInput);
340 return d->selectionColor;
343 void QQuickTextInput::setSelectionColor(const QColor &color)
345 Q_D(QQuickTextInput);
346 if (d->selectionColor == color)
349 d->selectionColor = color;
350 if (d->hasSelectedText()) {
351 d->textLayoutDirty = true;
352 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
355 emit selectionColorChanged();
358 \qmlproperty color QtQuick2::TextInput::selectedTextColor
360 The highlighted text color, used in selections.
362 QColor QQuickTextInput::selectedTextColor() const
364 Q_D(const QQuickTextInput);
365 return d->selectedTextColor;
368 void QQuickTextInput::setSelectedTextColor(const QColor &color)
370 Q_D(QQuickTextInput);
371 if (d->selectedTextColor == color)
374 d->selectedTextColor = color;
375 if (d->hasSelectedText()) {
376 d->textLayoutDirty = true;
377 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
380 emit selectedTextColorChanged();
384 \qmlproperty enumeration QtQuick2::TextInput::horizontalAlignment
385 \qmlproperty enumeration QtQuick2::TextInput::effectiveHorizontalAlignment
386 \qmlproperty enumeration QtQuick2::TextInput::verticalAlignment
388 Sets the horizontal alignment of the text within the TextInput item's
389 width and height. By default, the text alignment follows the natural alignment
390 of the text, for example text that is read from left to right will be aligned to
393 TextInput does not have vertical alignment, as the natural height is
394 exactly the height of the single line of text. If you set the height
395 manually to something larger, TextInput will always be top aligned
396 vertically. You can use anchors to align it however you want within
399 The valid values for \c horizontalAlignment are \c TextInput.AlignLeft, \c TextInput.AlignRight and
400 \c TextInput.AlignHCenter.
402 Valid values for \c verticalAlignment are \c TextInput.AlignTop (default),
403 \c TextInput.AlignBottom \c TextInput.AlignVCenter.
405 When using the attached property LayoutMirroring::enabled to mirror application
406 layouts, the horizontal alignment of text will also be mirrored. However, the property
407 \c horizontalAlignment will remain unchanged. To query the effective horizontal alignment
408 of TextInput, use the read-only property \c effectiveHorizontalAlignment.
410 QQuickTextInput::HAlignment QQuickTextInput::hAlign() const
412 Q_D(const QQuickTextInput);
416 void QQuickTextInput::setHAlign(HAlignment align)
418 Q_D(QQuickTextInput);
419 bool forceAlign = d->hAlignImplicit && d->effectiveLayoutMirror;
420 d->hAlignImplicit = false;
421 if (d->setHAlign(align, forceAlign) && isComponentComplete()) {
423 updateCursorRectangle();
427 void QQuickTextInput::resetHAlign()
429 Q_D(QQuickTextInput);
430 d->hAlignImplicit = true;
431 if (d->determineHorizontalAlignment() && isComponentComplete()) {
433 updateCursorRectangle();
437 QQuickTextInput::HAlignment QQuickTextInput::effectiveHAlign() const
439 Q_D(const QQuickTextInput);
440 QQuickTextInput::HAlignment effectiveAlignment = d->hAlign;
441 if (!d->hAlignImplicit && d->effectiveLayoutMirror) {
443 case QQuickTextInput::AlignLeft:
444 effectiveAlignment = QQuickTextInput::AlignRight;
446 case QQuickTextInput::AlignRight:
447 effectiveAlignment = QQuickTextInput::AlignLeft;
453 return effectiveAlignment;
456 bool QQuickTextInputPrivate::setHAlign(QQuickTextInput::HAlignment alignment, bool forceAlign)
458 Q_Q(QQuickTextInput);
459 if ((hAlign != alignment || forceAlign) && alignment <= QQuickTextInput::AlignHCenter) { // justify not supported
460 QQuickTextInput::HAlignment oldEffectiveHAlign = q->effectiveHAlign();
462 emit q->horizontalAlignmentChanged(alignment);
463 if (oldEffectiveHAlign != q->effectiveHAlign())
464 emit q->effectiveHorizontalAlignmentChanged();
470 bool QQuickTextInputPrivate::determineHorizontalAlignment()
472 if (hAlignImplicit) {
473 // if no explicit alignment has been set, follow the natural layout direction of the text
474 QString text = q_func()->text();
476 text = m_textLayout.preeditAreaText();
477 bool isRightToLeft = text.isEmpty() ? qApp->inputMethod()->inputDirection() == Qt::RightToLeft
478 : text.isRightToLeft();
479 return setHAlign(isRightToLeft ? QQuickTextInput::AlignRight : QQuickTextInput::AlignLeft);
484 QQuickTextInput::VAlignment QQuickTextInput::vAlign() const
486 Q_D(const QQuickTextInput);
490 void QQuickTextInput::setVAlign(QQuickTextInput::VAlignment alignment)
492 Q_D(QQuickTextInput);
493 if (alignment == d->vAlign)
495 d->vAlign = alignment;
496 emit verticalAlignmentChanged(d->vAlign);
497 if (isComponentComplete()) {
498 updateCursorRectangle();
503 \qmlproperty enumeration QtQuick2::TextInput::wrapMode
505 Set this property to wrap the text to the TextInput item's width.
506 The text will only wrap if an explicit width has been set.
509 \li TextInput.NoWrap - no wrapping will be performed. If the text contains insufficient newlines, then implicitWidth will exceed a set width.
510 \li TextInput.WordWrap - wrapping is done on word boundaries only. If a word is too long, implicitWidth will exceed a set width.
511 \li TextInput.WrapAnywhere - wrapping is done at any point on a line, even if it occurs in the middle of a word.
512 \li TextInput.Wrap - if possible, wrapping occurs at a word boundary; otherwise it will occur at the appropriate point on the line, even in the middle of a word.
515 The default is TextInput.NoWrap. If you set a width, consider using TextInput.Wrap.
517 QQuickTextInput::WrapMode QQuickTextInput::wrapMode() const
519 Q_D(const QQuickTextInput);
523 void QQuickTextInput::setWrapMode(WrapMode mode)
525 Q_D(QQuickTextInput);
526 if (mode == d->wrapMode)
530 updateCursorRectangle();
531 emit wrapModeChanged();
534 void QQuickTextInputPrivate::mirrorChange()
536 Q_Q(QQuickTextInput);
537 if (q->isComponentComplete()) {
538 if (!hAlignImplicit && (hAlign == QQuickTextInput::AlignRight || hAlign == QQuickTextInput::AlignLeft)) {
539 q->updateCursorRectangle();
540 emit q->effectiveHorizontalAlignmentChanged();
546 \qmlproperty bool QtQuick2::TextInput::readOnly
548 Sets whether user input can modify the contents of the TextInput.
550 If readOnly is set to true, then user input will not affect the text
551 property. Any bindings or attempts to set the text property will still
554 bool QQuickTextInput::isReadOnly() const
556 Q_D(const QQuickTextInput);
557 return d->m_readOnly;
560 void QQuickTextInput::setReadOnly(bool ro)
562 Q_D(QQuickTextInput);
563 if (d->m_readOnly == ro)
566 setFlag(QQuickItem::ItemAcceptsInputMethod, !ro);
569 d->setCursorPosition(d->end());
570 updateInputMethod(Qt::ImEnabled);
572 d->emitUndoRedoChanged();
573 emit readOnlyChanged(ro);
577 \qmlproperty int QtQuick2::TextInput::maximumLength
578 The maximum permitted length of the text in the TextInput.
580 If the text is too long, it is truncated at the limit.
582 By default, this property contains a value of 32767.
584 int QQuickTextInput::maxLength() const
586 Q_D(const QQuickTextInput);
587 return d->m_maxLength;
590 void QQuickTextInput::setMaxLength(int ml)
592 Q_D(QQuickTextInput);
593 if (d->m_maxLength == ml || d->m_maskData)
597 d->internalSetText(d->m_text, -1, false);
599 emit maximumLengthChanged(ml);
603 \qmlproperty bool QtQuick2::TextInput::cursorVisible
604 Set to true when the TextInput shows a cursor.
606 This property is set and unset when the TextInput gets active focus, so that other
607 properties can be bound to whether the cursor is currently showing. As it
608 gets set and unset automatically, when you set the value yourself you must
609 keep in mind that your value may be overwritten.
611 It can be set directly in script, for example if a KeyProxy might
612 forward keys to it and you desire it to look active when this happens
613 (but without actually giving it active focus).
615 It should not be set directly on the element, like in the below QML,
616 as the specified value will be overridden an lost on focus changes.
625 In the above snippet the cursor will still become visible when the
626 TextInput gains active focus.
628 bool QQuickTextInput::isCursorVisible() const
630 Q_D(const QQuickTextInput);
631 return d->cursorVisible;
634 void QQuickTextInput::setCursorVisible(bool on)
636 Q_D(QQuickTextInput);
637 if (d->cursorVisible == on)
639 d->cursorVisible = on;
640 d->setCursorBlinkPeriod(on ? qApp->styleHints()->cursorFlashTime() : 0);
641 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
643 emit cursorVisibleChanged(d->cursorVisible);
647 \qmlproperty int QtQuick2::TextInput::cursorPosition
648 The position of the cursor in the TextInput.
650 int QQuickTextInput::cursorPosition() const
652 Q_D(const QQuickTextInput);
656 void QQuickTextInput::setCursorPosition(int cp)
658 Q_D(QQuickTextInput);
659 if (cp < 0 || cp > text().length())
665 \qmlproperty rectangle QtQuick2::TextInput::cursorRectangle
667 The rectangle where the standard text cursor is rendered within the text input. Read only.
669 The position and height of a custom cursorDelegate are updated to follow the cursorRectangle
670 automatically when it changes. The width of the delegate is unaffected by changes in the
674 QRectF QQuickTextInput::cursorRectangle() const
676 Q_D(const QQuickTextInput);
678 int c = d->m_cursor + d->m_preeditCursor;
679 if (d->m_echoMode == NoEcho)
681 QTextLine l = d->m_textLayout.lineForTextPosition(c);
684 return QRectF(l.cursorToX(c) - d->hscroll, l.y() - d->vscroll, 1, l.height());
688 \qmlproperty int QtQuick2::TextInput::selectionStart
690 The cursor position before the first character in the current selection.
692 This property is read-only. To change the selection, use select(start,end),
693 selectAll(), or selectWord().
695 \sa selectionEnd, cursorPosition, selectedText
697 int QQuickTextInput::selectionStart() const
699 Q_D(const QQuickTextInput);
700 return d->lastSelectionStart;
703 \qmlproperty int QtQuick2::TextInput::selectionEnd
705 The cursor position after the last character in the current selection.
707 This property is read-only. To change the selection, use select(start,end),
708 selectAll(), or selectWord().
710 \sa selectionStart, cursorPosition, selectedText
712 int QQuickTextInput::selectionEnd() const
714 Q_D(const QQuickTextInput);
715 return d->lastSelectionEnd;
718 \qmlmethod void QtQuick2::TextInput::select(int start, int end)
720 Causes the text from \a start to \a end to be selected.
722 If either start or end is out of range, the selection is not changed.
724 After calling this, selectionStart will become the lesser
725 and selectionEnd will become the greater (regardless of the order passed
728 \sa selectionStart, selectionEnd
730 void QQuickTextInput::select(int start, int end)
732 Q_D(QQuickTextInput);
733 if (start < 0 || end < 0 || start > d->m_text.length() || end > d->m_text.length())
735 d->setSelection(start, end-start);
739 \qmlproperty string QtQuick2::TextInput::selectedText
741 This read-only property provides the text currently selected in the
744 It is equivalent to the following snippet, but is faster and easier
748 myTextInput.text.toString().substring(myTextInput.selectionStart,
749 myTextInput.selectionEnd);
752 QString QQuickTextInput::selectedText() const
754 Q_D(const QQuickTextInput);
755 return d->selectedText();
759 \qmlproperty bool QtQuick2::TextInput::activeFocusOnPress
761 Whether the TextInput should gain active focus on a mouse press. By default this is
764 bool QQuickTextInput::focusOnPress() const
766 Q_D(const QQuickTextInput);
767 return d->focusOnPress;
770 void QQuickTextInput::setFocusOnPress(bool b)
772 Q_D(QQuickTextInput);
773 if (d->focusOnPress == b)
778 emit activeFocusOnPressChanged(d->focusOnPress);
781 \qmlproperty bool QtQuick2::TextInput::autoScroll
783 Whether the TextInput should scroll when the text is longer than the width. By default this is
786 bool QQuickTextInput::autoScroll() const
788 Q_D(const QQuickTextInput);
789 return d->autoScroll;
792 void QQuickTextInput::setAutoScroll(bool b)
794 Q_D(QQuickTextInput);
795 if (d->autoScroll == b)
799 //We need to repaint so that the scrolling is taking into account.
800 updateCursorRectangle();
801 emit autoScrollChanged(d->autoScroll);
804 #ifndef QT_NO_VALIDATOR
807 \qmlclass IntValidator QIntValidator
808 \inqmlmodule QtQuick 2
809 \ingroup qml-basic-visual-elements
811 This element provides a validator for integer values.
813 If no \l locale is set IntValidator uses the \l {QLocale::setDefault()}{default locale} to
814 interpret the number and will accept locale specific digits, group separators, and positive
815 and negative signs. In addition, IntValidator is always guaranteed to accept a number
816 formatted according to the "C" locale.
820 QQuickIntValidator::QQuickIntValidator(QObject *parent)
821 : QIntValidator(parent)
826 \qmlproperty string QtQuick2::IntValidator::locale
828 This property holds the name of the locale used to interpret the number.
833 QString QQuickIntValidator::localeName() const
835 return locale().name();
838 void QQuickIntValidator::setLocaleName(const QString &name)
840 if (locale().name() != name) {
841 setLocale(QLocale(name));
842 emit localeNameChanged();
846 void QQuickIntValidator::resetLocaleName()
848 QLocale defaultLocale;
849 if (locale() != defaultLocale) {
850 setLocale(defaultLocale);
851 emit localeNameChanged();
856 \qmlproperty int QtQuick2::IntValidator::top
858 This property holds the validator's highest acceptable value.
859 By default, this property's value is derived from the highest signed integer available (typically 2147483647).
862 \qmlproperty int QtQuick2::IntValidator::bottom
864 This property holds the validator's lowest acceptable value.
865 By default, this property's value is derived from the lowest signed integer available (typically -2147483647).
869 \qmlclass DoubleValidator QDoubleValidator
870 \inqmlmodule QtQuick 2
871 \ingroup qml-basic-visual-elements
873 This element provides a validator for non-integer numbers.
875 Input is accepted if it contains a double that is within the valid range
876 and is in the correct format.
878 Input is accepected but invalid if it contains a double that is outside
879 the range or is in the wrong format; e.g. with too many digits after the
880 decimal point or is empty.
882 Input is rejected if it is not a double.
884 Note: If the valid range consists of just positive doubles (e.g. 0.0 to
885 100.0) and input is a negative double then it is rejected. If \l notation
886 is set to DoubleValidator.StandardNotation, and the input contains more
887 digits before the decimal point than a double in the valid range may have,
888 it is also rejected. If \l notation is DoubleValidator.ScientificNotation,
889 and the input is not in the valid range, it is accecpted but invalid. The
890 value may yet become valid by changing the exponent.
893 QQuickDoubleValidator::QQuickDoubleValidator(QObject *parent)
894 : QDoubleValidator(parent)
899 \qmlproperty string QtQuick2::DoubleValidator::locale
901 This property holds the name of the locale used to interpret the number.
906 QString QQuickDoubleValidator::localeName() const
908 return locale().name();
911 void QQuickDoubleValidator::setLocaleName(const QString &name)
913 if (locale().name() != name) {
914 setLocale(QLocale(name));
915 emit localeNameChanged();
919 void QQuickDoubleValidator::resetLocaleName()
921 QLocale defaultLocale;
922 if (locale() != defaultLocale) {
923 setLocale(defaultLocale);
924 emit localeNameChanged();
929 \qmlproperty real QtQuick2::DoubleValidator::top
931 This property holds the validator's maximum acceptable value.
932 By default, this property contains a value of infinity.
935 \qmlproperty real QtQuick2::DoubleValidator::bottom
937 This property holds the validator's minimum acceptable value.
938 By default, this property contains a value of -infinity.
941 \qmlproperty int QtQuick2::DoubleValidator::decimals
943 This property holds the validator's maximum number of digits after the decimal point.
944 By default, this property contains a value of 1000.
947 \qmlproperty enumeration QtQuick2::DoubleValidator::notation
948 This property holds the notation of how a string can describe a number.
950 The possible values for this property are:
953 \li DoubleValidator.StandardNotation
954 \li DoubleValidator.ScientificNotation (default)
957 If this property is set to DoubleValidator.ScientificNotation, the written number may have an exponent part (e.g. 1.5E-2).
961 \qmlclass RegExpValidator QRegExpValidator
962 \inqmlmodule QtQuick 2
963 \ingroup qml-basic-visual-elements
965 This element provides a validator, which counts as valid any string which
966 matches a specified regular expression.
969 \qmlproperty regExp QtQuick2::RegExpValidator::regExp
971 This property holds the regular expression used for validation.
973 Note that this property should be a regular expression in JS syntax, e.g /a/ for the regular expression
976 By default, this property contains a regular expression with the pattern .* that matches any string.
980 \qmlproperty Validator QtQuick2::TextInput::validator
982 Allows you to set a validator on the TextInput. When a validator is set
983 the TextInput will only accept input which leaves the text property in
984 an acceptable or intermediate state. The accepted signal will only be sent
985 if the text is in an acceptable state when enter is pressed.
987 Currently supported validators are IntValidator, DoubleValidator and
988 RegExpValidator. An example of using validators is shown below, which allows
989 input of integers between 11 and 31 into the text input:
994 validator: IntValidator{bottom: 11; top: 31;}
999 \sa acceptableInput, inputMask
1002 QValidator* QQuickTextInput::validator() const
1004 Q_D(const QQuickTextInput);
1005 return d->m_validator;
1008 void QQuickTextInput::setValidator(QValidator* v)
1010 Q_D(QQuickTextInput);
1011 if (d->m_validator == v)
1016 if (isComponentComplete())
1019 emit validatorChanged();
1022 #endif // QT_NO_VALIDATOR
1024 void QQuickTextInputPrivate::checkIsValid()
1026 Q_Q(QQuickTextInput);
1028 ValidatorState state = hasAcceptableInput(m_text);
1029 m_validInput = state != InvalidInput;
1030 if (state != AcceptableInput) {
1031 if (m_acceptableInput) {
1032 m_acceptableInput = false;
1033 emit q->acceptableInputChanged();
1035 } else if (!m_acceptableInput) {
1036 m_acceptableInput = true;
1037 emit q->acceptableInputChanged();
1042 \qmlproperty string QtQuick2::TextInput::inputMask
1044 Allows you to set an input mask on the TextInput, restricting the allowable
1045 text inputs. See QLineEdit::inputMask for further details, as the exact
1046 same mask strings are used by TextInput.
1048 \sa acceptableInput, validator
1050 QString QQuickTextInput::inputMask() const
1052 Q_D(const QQuickTextInput);
1053 return d->inputMask();
1056 void QQuickTextInput::setInputMask(const QString &im)
1058 Q_D(QQuickTextInput);
1059 if (d->inputMask() == im)
1062 d->setInputMask(im);
1063 emit inputMaskChanged(d->inputMask());
1067 \qmlproperty bool QtQuick2::TextInput::acceptableInput
1069 This property is always true unless a validator or input mask has been set.
1070 If a validator or input mask has been set, this property will only be true
1071 if the current text is acceptable to the validator or input mask as a final
1072 string (not as an intermediate string).
1074 bool QQuickTextInput::hasAcceptableInput() const
1076 Q_D(const QQuickTextInput);
1077 return d->hasAcceptableInput(d->m_text) == QQuickTextInputPrivate::AcceptableInput;
1081 \qmlsignal QtQuick2::TextInput::onAccepted()
1083 This handler is called when the Return or Enter key is pressed.
1084 Note that if there is a \l validator or \l inputMask set on the text
1085 input, the handler will only be emitted if the input is in an acceptable
1089 Qt::InputMethodHints QQuickTextInputPrivate::effectiveInputMethodHints() const
1091 Qt::InputMethodHints hints = inputMethodHints;
1092 if (m_echoMode == QQuickTextInput::Password || m_echoMode == QQuickTextInput::NoEcho)
1093 hints |= Qt::ImhHiddenText;
1094 else if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit)
1095 hints &= ~Qt::ImhHiddenText;
1096 if (m_echoMode != QQuickTextInput::Normal)
1097 hints |= (Qt::ImhNoAutoUppercase | Qt::ImhNoPredictiveText | Qt::ImhSensitiveData);
1101 \qmlproperty enumeration QtQuick2::TextInput::echoMode
1103 Specifies how the text should be displayed in the TextInput.
1105 \li TextInput.Normal - Displays the text as it is. (Default)
1106 \li TextInput.Password - Displays asterisks instead of characters.
1107 \li TextInput.NoEcho - Displays nothing.
1108 \li TextInput.PasswordEchoOnEdit - Displays characters as they are entered
1109 while editing, otherwise displays asterisks.
1112 QQuickTextInput::EchoMode QQuickTextInput::echoMode() const
1114 Q_D(const QQuickTextInput);
1115 return QQuickTextInput::EchoMode(d->m_echoMode);
1118 void QQuickTextInput::setEchoMode(QQuickTextInput::EchoMode echo)
1120 Q_D(QQuickTextInput);
1121 if (echoMode() == echo)
1123 d->cancelPasswordEchoTimer();
1124 d->m_echoMode = echo;
1125 d->m_passwordEchoEditing = false;
1126 updateInputMethod(Qt::ImHints);
1127 d->updateDisplayText();
1128 updateCursorRectangle();
1130 emit echoModeChanged(echoMode());
1134 \qmlproperty enumeration QtQuick2::TextInput::inputMethodHints
1136 Provides hints to the input method about the expected content of the text input and how it
1139 The value is a bit-wise combination of flags, or Qt.ImhNone if no hints are set.
1141 Flags that alter behaviour are:
1144 \li Qt.ImhHiddenText - Characters should be hidden, as is typically used when entering passwords.
1145 This is automatically set when setting echoMode to \c TextInput.Password.
1146 \li Qt.ImhSensitiveData - Typed text should not be stored by the active input method
1147 in any persistent storage like predictive user dictionary.
1148 \li Qt.ImhNoAutoUppercase - The input method should not try to automatically switch to upper case
1149 when a sentence ends.
1150 \li Qt.ImhPreferNumbers - Numbers are preferred (but not required).
1151 \li Qt.ImhPreferUppercase - Upper case letters are preferred (but not required).
1152 \li Qt.ImhPreferLowercase - Lower case letters are preferred (but not required).
1153 \li Qt.ImhNoPredictiveText - Do not use predictive text (i.e. dictionary lookup) while typing.
1155 \li Qt.ImhDate - The text editor functions as a date field.
1156 \li Qt.ImhTime - The text editor functions as a time field.
1159 Flags that restrict input (exclusive flags) are:
1162 \li Qt.ImhDigitsOnly - Only digits are allowed.
1163 \li Qt.ImhFormattedNumbersOnly - Only number input is allowed. This includes decimal point and minus sign.
1164 \li Qt.ImhUppercaseOnly - Only upper case letter input is allowed.
1165 \li Qt.ImhLowercaseOnly - Only lower case letter input is allowed.
1166 \li Qt.ImhDialableCharactersOnly - Only characters suitable for phone dialing are allowed.
1167 \li Qt.ImhEmailCharactersOnly - Only characters suitable for email addresses are allowed.
1168 \li Qt.ImhUrlCharactersOnly - Only characters suitable for URLs are allowed.
1174 \li Qt.ImhExclusiveInputMask - This mask yields nonzero if any of the exclusive flags are used.
1178 Qt::InputMethodHints QQuickTextInput::inputMethodHints() const
1180 Q_D(const QQuickTextInput);
1181 return d->inputMethodHints;
1184 void QQuickTextInput::setInputMethodHints(Qt::InputMethodHints hints)
1186 Q_D(QQuickTextInput);
1188 if (hints == d->inputMethodHints)
1191 d->inputMethodHints = hints;
1192 updateInputMethod(Qt::ImHints);
1193 emit inputMethodHintsChanged();
1197 \qmlproperty Component QtQuick2::TextInput::cursorDelegate
1198 The delegate for the cursor in the TextInput.
1200 If you set a cursorDelegate for a TextInput, this delegate will be used for
1201 drawing the cursor instead of the standard cursor. An instance of the
1202 delegate will be created and managed by the TextInput when a cursor is
1203 needed, and the x property of delegate instance will be set so as
1204 to be one pixel before the top left of the current character.
1206 Note that the root item of the delegate component must be a QQuickItem or
1207 QQuickItem derived item.
1209 QQmlComponent* QQuickTextInput::cursorDelegate() const
1211 Q_D(const QQuickTextInput);
1212 return d->cursorComponent;
1215 void QQuickTextInput::setCursorDelegate(QQmlComponent* c)
1217 Q_D(QQuickTextInput);
1218 if (d->cursorComponent == c)
1221 d->cursorComponent = c;
1223 //note that the components are owned by something else
1224 delete d->cursorItem;
1227 d->startCreatingCursor();
1230 emit cursorDelegateChanged();
1233 void QQuickTextInputPrivate::startCreatingCursor()
1235 Q_Q(QQuickTextInput);
1236 if (cursorComponent->isReady()) {
1238 } else if (cursorComponent->isLoading()) {
1239 q->connect(cursorComponent, SIGNAL(statusChanged(int)),
1240 q, SLOT(createCursor()));
1242 qmlInfo(q, cursorComponent->errors()) << QQuickTextInput::tr("Could not load cursor delegate");
1246 void QQuickTextInput::createCursor()
1248 Q_D(QQuickTextInput);
1249 if (!isComponentComplete())
1252 if (d->cursorComponent->isError()) {
1253 qmlInfo(this, d->cursorComponent->errors()) << tr("Could not load cursor delegate");
1257 if (!d->cursorComponent->isReady())
1261 delete d->cursorItem;
1262 QQmlContext *creationContext = d->cursorComponent->creationContext();
1263 QObject *object = d->cursorComponent->create(creationContext ? creationContext : qmlContext(this));
1264 d->cursorItem = qobject_cast<QQuickItem*>(object);
1265 if (!d->cursorItem) {
1267 qmlInfo(this, d->cursorComponent->errors()) << tr("Could not instantiate cursor delegate");
1271 QRectF r = cursorRectangle();
1273 QQml_setParent_noEvent(d->cursorItem, this);
1274 d->cursorItem->setParentItem(this);
1275 d->cursorItem->setPos(r.topLeft());
1276 d->cursorItem->setHeight(r.height());
1280 \qmlmethod rect QtQuick2::TextInput::positionToRectangle(int pos)
1282 This function takes a character position and returns the rectangle that the
1283 cursor would occupy, if it was placed at that character position.
1285 This is similar to setting the cursorPosition, and then querying the cursor
1286 rectangle, but the cursorPosition is not changed.
1288 QRectF QQuickTextInput::positionToRectangle(int pos) const
1290 Q_D(const QQuickTextInput);
1291 if (d->m_echoMode == NoEcho)
1293 else if (pos > d->m_cursor)
1294 pos += d->preeditAreaText().length();
1295 QTextLine l = d->m_textLayout.lineForTextPosition(pos);
1297 ? QRectF(l.cursorToX(pos) - d->hscroll, l.y() - d->vscroll, 1, l.height())
1302 \qmlmethod int QtQuick2::TextInput::positionAt(real x, real y, CursorPosition position = CursorBetweenCharacters)
1304 This function returns the character position at
1305 x and y pixels from the top left of the textInput. Position 0 is before the
1306 first character, position 1 is after the first character but before the second,
1307 and so on until position text.length, which is after all characters.
1309 This means that for all x values before the first character this function returns 0,
1310 and for all x values after the last character this function returns text.length. If
1311 the y value is above the text the position will be that of the nearest character on
1312 the first line line and if it is below the text the position of the nearest character
1313 on the last line will be returned.
1315 The cursor position type specifies how the cursor position should be resolved.
1318 \li TextInput.CursorBetweenCharacters - Returns the position between characters that is nearest x.
1319 \li TextInput.CursorOnCharacter - Returns the position before the character that is nearest x.
1323 void QQuickTextInput::positionAt(QQmlV8Function *args) const
1325 Q_D(const QQuickTextInput);
1329 QTextLine::CursorPosition position = QTextLine::CursorBetweenCharacters;
1331 if (args->Length() < 1)
1335 v8::Local<v8::Value> arg = (*args)[i];
1336 x = arg->NumberValue();
1338 if (++i < args->Length()) {
1340 y = arg->NumberValue();
1343 if (++i < args->Length()) {
1345 position = QTextLine::CursorPosition(arg->Int32Value());
1348 int pos = d->positionAt(x, y, position);
1349 const int cursor = d->m_cursor;
1351 const int preeditLength = d->preeditAreaText().length();
1352 pos = pos > cursor + preeditLength
1353 ? pos - preeditLength
1356 args->returnValue(v8::Int32::New(pos));
1359 int QQuickTextInputPrivate::positionAt(qreal x, qreal y, QTextLine::CursorPosition position) const
1363 QTextLine line = m_textLayout.lineAt(0);
1364 for (int i = 1; i < m_textLayout.lineCount(); ++i) {
1365 QTextLine nextLine = m_textLayout.lineAt(i);
1367 if (y < (line.rect().bottom() + nextLine.y()) / 2)
1371 return line.isValid() ? line.xToCursor(x, position) : 0;
1374 void QQuickTextInput::keyPressEvent(QKeyEvent* ev)
1376 Q_D(QQuickTextInput);
1377 // Don't allow MacOSX up/down support, and we don't allow a completer.
1378 bool ignore = (ev->key() == Qt::Key_Up || ev->key() == Qt::Key_Down) && ev->modifiers() == Qt::NoModifier;
1379 if (!ignore && (d->lastSelectionStart == d->lastSelectionEnd) && (ev->key() == Qt::Key_Right || ev->key() == Qt::Key_Left)) {
1380 // Ignore when moving off the end unless there is a selection,
1381 // because then moving will do something (deselect).
1382 int cursorPosition = d->m_cursor;
1383 if (cursorPosition == 0)
1384 ignore = ev->key() == (d->layoutDirection() == Qt::LeftToRight ? Qt::Key_Left : Qt::Key_Right);
1385 if (cursorPosition == text().length())
1386 ignore = ev->key() == (d->layoutDirection() == Qt::LeftToRight ? Qt::Key_Right : Qt::Key_Left);
1391 d->processKeyEvent(ev);
1393 if (!ev->isAccepted())
1394 QQuickImplicitSizeItem::keyPressEvent(ev);
1397 void QQuickTextInput::inputMethodEvent(QInputMethodEvent *ev)
1399 Q_D(QQuickTextInput);
1400 const bool wasComposing = d->hasImState;
1401 if (d->m_readOnly) {
1404 d->processInputMethodEvent(ev);
1406 if (!ev->isAccepted())
1407 QQuickImplicitSizeItem::inputMethodEvent(ev);
1409 if (wasComposing != d->hasImState)
1410 emit inputMethodComposingChanged();
1413 void QQuickTextInput::mouseDoubleClickEvent(QMouseEvent *event)
1415 Q_D(QQuickTextInput);
1417 if (d->selectByMouse && event->button() == Qt::LeftButton) {
1419 int cursor = d->positionAt(event->localPos());
1420 d->selectWordAtPos(cursor);
1421 event->setAccepted(true);
1422 if (!d->hasPendingTripleClick()) {
1423 d->tripleClickStartPoint = event->localPos();
1424 d->tripleClickTimer.start();
1427 if (d->sendMouseEventToInputContext(event))
1429 QQuickImplicitSizeItem::mouseDoubleClickEvent(event);
1433 void QQuickTextInput::mousePressEvent(QMouseEvent *event)
1435 Q_D(QQuickTextInput);
1437 d->pressPos = event->localPos();
1439 if (d->sendMouseEventToInputContext(event))
1442 if (d->selectByMouse) {
1443 setKeepMouseGrab(false);
1444 d->selectPressed = true;
1445 QPointF distanceVector = d->pressPos - d->tripleClickStartPoint;
1446 if (d->hasPendingTripleClick()
1447 && distanceVector.manhattanLength() < qApp->styleHints()->startDragDistance()) {
1448 event->setAccepted(true);
1454 bool mark = (event->modifiers() & Qt::ShiftModifier) && d->selectByMouse;
1455 int cursor = d->positionAt(event->localPos());
1456 d->moveCursor(cursor, mark);
1458 if (d->focusOnPress) {
1459 bool hadActiveFocus = hasActiveFocus();
1461 // re-open input panel on press if already focused
1462 if (hasActiveFocus() && hadActiveFocus && !d->m_readOnly)
1463 openSoftwareInputPanel();
1466 event->setAccepted(true);
1469 void QQuickTextInput::mouseMoveEvent(QMouseEvent *event)
1471 Q_D(QQuickTextInput);
1473 if (d->selectPressed) {
1474 if (qAbs(int(event->localPos().x() - d->pressPos.x())) > qApp->styleHints()->startDragDistance())
1475 setKeepMouseGrab(true);
1477 if (d->composeMode()) {
1479 int startPos = d->positionAt(d->pressPos);
1480 int currentPos = d->positionAt(event->localPos());
1481 if (startPos != currentPos)
1482 d->setSelection(startPos, currentPos - startPos);
1484 moveCursorSelection(d->positionAt(event->localPos()), d->mouseSelectionMode);
1486 event->setAccepted(true);
1488 QQuickImplicitSizeItem::mouseMoveEvent(event);
1492 void QQuickTextInput::mouseReleaseEvent(QMouseEvent *event)
1494 Q_D(QQuickTextInput);
1495 if (d->sendMouseEventToInputContext(event))
1497 if (d->selectPressed) {
1498 d->selectPressed = false;
1499 setKeepMouseGrab(false);
1501 #ifndef QT_NO_CLIPBOARD
1502 if (QGuiApplication::clipboard()->supportsSelection()) {
1503 if (event->button() == Qt::LeftButton) {
1504 d->copy(QClipboard::Selection);
1505 } else if (!d->m_readOnly && event->button() == Qt::MidButton) {
1507 d->insert(QGuiApplication::clipboard()->text(QClipboard::Selection));
1511 if (!event->isAccepted())
1512 QQuickImplicitSizeItem::mouseReleaseEvent(event);
1515 bool QQuickTextInputPrivate::sendMouseEventToInputContext(QMouseEvent *event)
1517 #if !defined QT_NO_IM
1518 if (composeMode()) {
1519 int tmp_cursor = positionAt(event->localPos());
1520 int mousePos = tmp_cursor - m_cursor;
1521 if (mousePos >= 0 && mousePos <= m_textLayout.preeditAreaText().length()) {
1522 if (event->type() == QEvent::MouseButtonRelease) {
1523 qApp->inputMethod()->invokeAction(QInputMethod::Click, mousePos);
1536 void QQuickTextInput::mouseUngrabEvent()
1538 Q_D(QQuickTextInput);
1539 d->selectPressed = false;
1540 setKeepMouseGrab(false);
1543 bool QQuickTextInput::event(QEvent* ev)
1545 #ifndef QT_NO_SHORTCUT
1546 Q_D(QQuickTextInput);
1547 if (ev->type() == QEvent::ShortcutOverride) {
1550 QKeyEvent* ke = static_cast<QKeyEvent*>(ev);
1551 if (ke == QKeySequence::Copy
1552 || ke == QKeySequence::Paste
1553 || ke == QKeySequence::Cut
1554 || ke == QKeySequence::Redo
1555 || ke == QKeySequence::Undo
1556 || ke == QKeySequence::MoveToNextWord
1557 || ke == QKeySequence::MoveToPreviousWord
1558 || ke == QKeySequence::MoveToStartOfDocument
1559 || ke == QKeySequence::MoveToEndOfDocument
1560 || ke == QKeySequence::SelectNextWord
1561 || ke == QKeySequence::SelectPreviousWord
1562 || ke == QKeySequence::SelectStartOfLine
1563 || ke == QKeySequence::SelectEndOfLine
1564 || ke == QKeySequence::SelectStartOfBlock
1565 || ke == QKeySequence::SelectEndOfBlock
1566 || ke == QKeySequence::SelectStartOfDocument
1567 || ke == QKeySequence::SelectAll
1568 || ke == QKeySequence::SelectEndOfDocument) {
1570 } else if (ke->modifiers() == Qt::NoModifier || ke->modifiers() == Qt::ShiftModifier
1571 || ke->modifiers() == Qt::KeypadModifier) {
1572 if (ke->key() < Qt::Key_Escape) {
1576 switch (ke->key()) {
1577 case Qt::Key_Delete:
1580 case Qt::Key_Backspace:
1592 return QQuickImplicitSizeItem::event(ev);
1595 void QQuickTextInput::geometryChanged(const QRectF &newGeometry,
1596 const QRectF &oldGeometry)
1598 Q_D(QQuickTextInput);
1600 if (newGeometry.width() != oldGeometry.width() && d->wrapMode != NoWrap)
1602 updateCursorRectangle();
1604 QQuickImplicitSizeItem::geometryChanged(newGeometry, oldGeometry);
1607 void QQuickTextInputPrivate::updateHorizontalScroll()
1609 Q_Q(QQuickTextInput);
1610 QTextLine currentLine = m_textLayout.lineForTextPosition(m_cursor + m_preeditCursor);
1611 const int preeditLength = m_textLayout.preeditAreaText().length();
1612 const qreal width = qMax<qreal>(0, q->width());
1614 qreal widthUsed = 0;
1615 if (currentLine.isValid()) {
1616 cix = currentLine.cursorToX(m_cursor + preeditLength);
1617 const qreal cursorWidth = cix >= 0 ? cix : width - cix;
1618 widthUsed = qMax(currentLine.naturalTextWidth(), cursorWidth);
1620 int previousScroll = hscroll;
1622 if (!autoScroll || widthUsed <= width || m_echoMode == QQuickTextInput::NoEcho) {
1625 Q_ASSERT(currentLine.isValid());
1626 if (cix - hscroll >= width) {
1627 // text doesn't fit, cursor is to the right of br (scroll right)
1628 hscroll = cix - width;
1629 } else if (cix - hscroll < 0 && hscroll < widthUsed) {
1630 // text doesn't fit, cursor is to the left of br (scroll left)
1632 } else if (widthUsed - hscroll < width) {
1633 // text doesn't fit, text document is to the left of br; align
1635 hscroll = widthUsed - width;
1636 } else if (width - hscroll > widthUsed) {
1637 // text doesn't fit, text document is to the right of br; align
1639 hscroll = width - widthUsed;
1641 if (preeditLength > 0) {
1642 // check to ensure long pre-edit text doesn't push the cursor
1644 cix = currentLine.cursorToX(m_cursor + qMax(0, m_preeditCursor - 1));
1649 if (previousScroll != hscroll)
1650 textLayoutDirty = true;
1653 void QQuickTextInputPrivate::updateVerticalScroll()
1655 Q_Q(QQuickTextInput);
1656 const int preeditLength = m_textLayout.preeditAreaText().length();
1657 const qreal height = qMax<qreal>(0, q->height());
1658 qreal heightUsed = boundingRect.height();
1659 qreal previousScroll = vscroll;
1661 if (!autoScroll || heightUsed <= height) {
1662 // text fits in br; use vscroll for alignment
1663 switch (vAlign & ~(Qt::AlignAbsolute|Qt::AlignHorizontal_Mask)) {
1664 case Qt::AlignBottom:
1665 vscroll = heightUsed - height;
1667 case Qt::AlignVCenter:
1668 vscroll = (heightUsed - height) / 2;
1676 QTextLine currentLine = m_textLayout.lineForTextPosition(m_cursor + preeditLength);
1677 QRectF r = currentLine.isValid() ? currentLine.rect() : QRectF();
1678 qreal top = r.top();
1679 int bottom = r.bottom();
1681 if (bottom - vscroll >= height) {
1682 // text doesn't fit, cursor is to the below the br (scroll down)
1683 vscroll = bottom - height;
1684 } else if (top - vscroll < 0 && vscroll < heightUsed) {
1685 // text doesn't fit, cursor is above br (scroll up)
1687 } else if (heightUsed - vscroll < height) {
1688 // text doesn't fit, text document is to the left of br; align
1690 vscroll = heightUsed - height;
1692 if (preeditLength > 0) {
1693 // check to ensure long pre-edit text doesn't push the cursor
1695 currentLine = m_textLayout.lineForTextPosition(m_cursor + qMax(0, m_preeditCursor - 1));
1696 top = currentLine.isValid() ? currentLine.rect().top() : 0;
1701 if (previousScroll != vscroll)
1702 textLayoutDirty = true;
1705 void QQuickTextInput::triggerPreprocess()
1707 Q_D(QQuickTextInput);
1708 if (d->updateType == QQuickTextInputPrivate::UpdateNone)
1709 d->updateType = QQuickTextInputPrivate::UpdateOnlyPreprocess;
1713 QSGNode *QQuickTextInput::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data)
1716 Q_D(QQuickTextInput);
1718 if (d->updateType != QQuickTextInputPrivate::UpdatePaintNode && oldNode != 0) {
1719 // Update done in preprocess() in the nodes
1720 d->updateType = QQuickTextInputPrivate::UpdateNone;
1724 d->updateType = QQuickTextInputPrivate::UpdateNone;
1726 QQuickTextNode *node = static_cast<QQuickTextNode *>(oldNode);
1728 node = new QQuickTextNode(QQuickItemPrivate::get(this)->sceneGraphContext(), this);
1731 if (!d->textLayoutDirty) {
1732 QSGSimpleRectNode *cursorNode = node->cursorNode();
1733 if (cursorNode != 0 && !isReadOnly()) {
1734 cursorNode->setRect(cursorRectangle());
1736 if (!d->cursorVisible || (!d->m_blinkStatus && d->m_blinkPeriod > 0)) {
1743 node->deleteContent();
1744 node->setMatrix(QMatrix4x4());
1746 QPointF offset(0, 0);
1747 if (d->autoScroll && d->m_textLayout.lineCount() > 0) {
1748 QFontMetricsF fm(d->font);
1749 // the y offset is there to keep the baseline constant in case we have script changes in the text.
1750 offset = -QPoint(d->hscroll, d->vscroll + d->m_textLayout.lineAt(0).ascent() - fm.ascent());
1752 offset = -QPoint(d->hscroll, d->vscroll);
1755 if (!d->m_textLayout.text().isEmpty() || !d->m_textLayout.preeditAreaText().isEmpty()) {
1756 node->addTextLayout(offset, &d->m_textLayout, d->color,
1757 QQuickText::Normal, QColor(), QColor(),
1758 d->selectionColor, d->selectedTextColor,
1759 d->selectionStart(),
1760 d->selectionEnd() - 1); // selectionEnd() returns first char after
1764 if (!isReadOnly() && d->cursorItem == 0) {
1765 node->setCursor(cursorRectangle(), d->color);
1766 if (!d->cursorVisible || (!d->m_blinkStatus && d->m_blinkPeriod > 0)) {
1773 d->textLayoutDirty = false;
1779 QVariant QQuickTextInput::inputMethodQuery(Qt::InputMethodQuery property) const
1781 Q_D(const QQuickTextInput);
1784 return QVariant((bool)(flags() & ItemAcceptsInputMethod));
1786 return QVariant((int) d->effectiveInputMethodHints());
1787 case Qt::ImCursorRectangle:
1788 return cursorRectangle();
1791 case Qt::ImCursorPosition:
1792 return QVariant(d->m_cursor);
1793 case Qt::ImSurroundingText:
1794 if (d->m_echoMode == PasswordEchoOnEdit && !d->m_passwordEchoEditing) {
1795 return QVariant(displayText());
1797 return QVariant(d->realText());
1799 case Qt::ImCurrentSelection:
1800 return QVariant(selectedText());
1801 case Qt::ImMaximumTextLength:
1802 return QVariant(maxLength());
1803 case Qt::ImAnchorPosition:
1804 if (d->selectionStart() == d->selectionEnd())
1805 return QVariant(d->m_cursor);
1806 else if (d->selectionStart() == d->m_cursor)
1807 return QVariant(d->selectionEnd());
1809 return QVariant(d->selectionStart());
1816 \qmlmethod void QtQuick2::TextInput::deselect()
1818 Removes active text selection.
1820 void QQuickTextInput::deselect()
1822 Q_D(QQuickTextInput);
1827 \qmlmethod void QtQuick2::TextInput::selectAll()
1829 Causes all text to be selected.
1831 void QQuickTextInput::selectAll()
1833 Q_D(QQuickTextInput);
1834 d->setSelection(0, text().length());
1838 \qmlmethod void QtQuick2::TextInput::isRightToLeft(int start, int end)
1840 Returns true if the natural reading direction of the editor text
1841 found between positions \a start and \a end is right to left.
1843 bool QQuickTextInput::isRightToLeft(int start, int end)
1846 qmlInfo(this) << "isRightToLeft(start, end) called with the end property being smaller than the start.";
1849 return text().mid(start, end - start).isRightToLeft();
1853 #ifndef QT_NO_CLIPBOARD
1855 \qmlmethod QtQuick2::TextInput::cut()
1857 Moves the currently selected text to the system clipboard.
1859 void QQuickTextInput::cut()
1861 Q_D(QQuickTextInput);
1867 \qmlmethod QtQuick2::TextInput::copy()
1869 Copies the currently selected text to the system clipboard.
1871 void QQuickTextInput::copy()
1873 Q_D(QQuickTextInput);
1878 \qmlmethod QtQuick2::TextInput::paste()
1880 Replaces the currently selected text by the contents of the system clipboard.
1882 void QQuickTextInput::paste()
1884 Q_D(QQuickTextInput);
1888 #endif // QT_NO_CLIPBOARD
1891 Undoes the last operation if undo is \l {canUndo}{available}. Deselects any
1892 current selection, and updates the selection start to the current cursor
1896 void QQuickTextInput::undo()
1898 Q_D(QQuickTextInput);
1899 if (!d->m_readOnly) {
1901 d->finishChange(-1, true);
1906 Redoes the last operation if redo is \l {canRedo}{available}.
1909 void QQuickTextInput::redo()
1911 Q_D(QQuickTextInput);
1912 if (!d->m_readOnly) {
1919 \qmlmethod void QtQuick2::TextInput::insert(int position, string text)
1921 Inserts \a text into the TextInput at position.
1924 void QQuickTextInput::insert(int position, const QString &text)
1926 Q_D(QQuickTextInput);
1927 if (d->m_echoMode == QQuickTextInput::Password) {
1928 int delay = qGuiApp->styleHints()->passwordMaskDelay();
1930 d->m_passwordEchoTimer.start(delay, this);
1932 if (position < 0 || position > d->m_text.length())
1935 const int priorState = d->m_undoState;
1937 QString insertText = text;
1939 if (d->hasSelectedText()) {
1940 d->addCommand(QQuickTextInputPrivate::Command(
1941 QQuickTextInputPrivate::SetSelection, d->m_cursor, 0, d->m_selstart, d->m_selend));
1943 if (d->m_maskData) {
1944 insertText = d->maskString(position, insertText);
1945 for (int i = 0; i < insertText.length(); ++i) {
1946 d->addCommand(QQuickTextInputPrivate::Command(
1947 QQuickTextInputPrivate::DeleteSelection, position + i, d->m_text.at(position + i), -1, -1));
1948 d->addCommand(QQuickTextInputPrivate::Command(
1949 QQuickTextInputPrivate::Insert, position + i, insertText.at(i), -1, -1));
1951 d->m_text.replace(position, insertText.length(), insertText);
1952 if (!insertText.isEmpty())
1953 d->m_textDirty = true;
1954 if (position < d->m_selend && position + insertText.length() > d->m_selstart)
1955 d->m_selDirty = true;
1957 int remaining = d->m_maxLength - d->m_text.length();
1958 if (remaining != 0) {
1959 insertText = insertText.left(remaining);
1960 d->m_text.insert(position, insertText);
1961 for (int i = 0; i < insertText.length(); ++i)
1962 d->addCommand(QQuickTextInputPrivate::Command(
1963 QQuickTextInputPrivate::Insert, position + i, insertText.at(i), -1, -1));
1964 if (d->m_cursor >= position)
1965 d->m_cursor += insertText.length();
1966 if (d->m_selstart >= position)
1967 d->m_selstart += insertText.length();
1968 if (d->m_selend >= position)
1969 d->m_selend += insertText.length();
1970 d->m_textDirty = true;
1971 if (position >= d->m_selstart && position <= d->m_selend)
1972 d->m_selDirty = true;
1976 d->addCommand(QQuickTextInputPrivate::Command(
1977 QQuickTextInputPrivate::SetSelection, d->m_cursor, 0, d->m_selstart, d->m_selend));
1978 d->finishChange(priorState);
1980 if (d->lastSelectionStart != d->lastSelectionEnd) {
1981 if (d->m_selstart != d->lastSelectionStart) {
1982 d->lastSelectionStart = d->m_selstart;
1983 emit selectionStartChanged();
1985 if (d->m_selend != d->lastSelectionEnd) {
1986 d->lastSelectionEnd = d->m_selend;
1987 emit selectionEndChanged();
1993 \qmlmethod string QtQuick2::TextInput::getText(int start, int end)
1995 Removes the section of text that is between the \a start and \a end positions from the TextInput.
1998 void QQuickTextInput::remove(int start, int end)
2000 Q_D(QQuickTextInput);
2002 start = qBound(0, start, d->m_text.length());
2003 end = qBound(0, end, d->m_text.length());
2007 else if (start == end)
2010 if (start < d->m_selend && end > d->m_selstart)
2011 d->m_selDirty = true;
2013 const int priorState = d->m_undoState;
2015 d->addCommand(QQuickTextInputPrivate::Command(
2016 QQuickTextInputPrivate::SetSelection, d->m_cursor, 0, d->m_selstart, d->m_selend));
2018 if (start <= d->m_cursor && d->m_cursor < end) {
2019 // cursor is within the selection. Split up the commands
2020 // to be able to restore the correct cursor position
2021 for (int i = d->m_cursor; i >= start; --i) {
2022 d->addCommand(QQuickTextInputPrivate::Command(
2023 QQuickTextInputPrivate::DeleteSelection, i, d->m_text.at(i), -1, 1));
2025 for (int i = end - 1; i > d->m_cursor; --i) {
2026 d->addCommand(QQuickTextInputPrivate::Command(
2027 QQuickTextInputPrivate::DeleteSelection, i - d->m_cursor + start - 1, d->m_text.at(i), -1, -1));
2030 for (int i = end - 1; i >= start; --i) {
2031 d->addCommand(QQuickTextInputPrivate::Command(
2032 QQuickTextInputPrivate::RemoveSelection, i, d->m_text.at(i), -1, -1));
2035 if (d->m_maskData) {
2036 d->m_text.replace(start, end - start, d->clearString(start, end - start));
2037 for (int i = 0; i < end - start; ++i) {
2038 d->addCommand(QQuickTextInputPrivate::Command(
2039 QQuickTextInputPrivate::Insert, start + i, d->m_text.at(start + i), -1, -1));
2042 d->m_text.remove(start, end - start);
2044 if (d->m_cursor > start)
2045 d->m_cursor -= qMin(d->m_cursor, end) - start;
2046 if (d->m_selstart > start)
2047 d->m_selstart -= qMin(d->m_selstart, end) - start;
2048 if (d->m_selend > end)
2049 d->m_selend -= qMin(d->m_selend, end) - start;
2051 d->addCommand(QQuickTextInputPrivate::Command(
2052 QQuickTextInputPrivate::SetSelection, d->m_cursor, 0, d->m_selstart, d->m_selend));
2054 d->m_textDirty = true;
2055 d->finishChange(priorState);
2057 if (d->lastSelectionStart != d->lastSelectionEnd) {
2058 if (d->m_selstart != d->lastSelectionStart) {
2059 d->lastSelectionStart = d->m_selstart;
2060 emit selectionStartChanged();
2062 if (d->m_selend != d->lastSelectionEnd) {
2063 d->lastSelectionEnd = d->m_selend;
2064 emit selectionEndChanged();
2071 \qmlmethod void QtQuick2::TextInput::selectWord()
2073 Causes the word closest to the current cursor position to be selected.
2075 void QQuickTextInput::selectWord()
2077 Q_D(QQuickTextInput);
2078 d->selectWordAtPos(d->m_cursor);
2082 \qmlproperty bool QtQuick2::TextInput::smooth
2084 This property holds whether the text is smoothly scaled or transformed.
2086 Smooth filtering gives better visual quality, but is slower. If
2087 the item is displayed at its natural size, this property has no visual or
2090 \note Generally scaling artifacts are only visible if the item is stationary on
2091 the screen. A common pattern when animating an item is to disable smooth
2092 filtering at the beginning of the animation and reenable it at the conclusion.
2096 \qmlproperty string QtQuick2::TextInput::passwordCharacter
2098 This is the character displayed when echoMode is set to Password or
2099 PasswordEchoOnEdit. By default it is an asterisk.
2101 If this property is set to a string with more than one character,
2102 the first character is used. If the string is empty, the value
2103 is ignored and the property is not set.
2105 QString QQuickTextInput::passwordCharacter() const
2107 Q_D(const QQuickTextInput);
2108 return QString(d->m_passwordCharacter);
2111 void QQuickTextInput::setPasswordCharacter(const QString &str)
2113 Q_D(QQuickTextInput);
2114 if (str.length() < 1)
2116 d->m_passwordCharacter = str.constData()[0];
2117 if (d->m_echoMode == Password || d->m_echoMode == PasswordEchoOnEdit)
2118 d->updateDisplayText();
2119 emit passwordCharacterChanged();
2123 \qmlproperty string QtQuick2::TextInput::displayText
2125 This is the text displayed in the TextInput.
2127 If \l echoMode is set to TextInput::Normal, this holds the
2128 same value as the TextInput::text property. Otherwise,
2129 this property holds the text visible to the user, while
2130 the \l text property holds the actual entered text.
2132 QString QQuickTextInput::displayText() const
2134 Q_D(const QQuickTextInput);
2135 return d->m_textLayout.text();
2139 \qmlproperty bool QtQuick2::TextInput::selectByMouse
2143 If true, the user can use the mouse to select text in some
2144 platform-specific way. Note that for some platforms this may
2145 not be an appropriate interaction (eg. may conflict with how
2146 the text needs to behave inside a Flickable.
2148 bool QQuickTextInput::selectByMouse() const
2150 Q_D(const QQuickTextInput);
2151 return d->selectByMouse;
2154 void QQuickTextInput::setSelectByMouse(bool on)
2156 Q_D(QQuickTextInput);
2157 if (d->selectByMouse != on) {
2158 d->selectByMouse = on;
2159 emit selectByMouseChanged(on);
2164 \qmlproperty enum QtQuick2::TextInput::mouseSelectionMode
2166 Specifies how text should be selected using a mouse.
2169 \li TextInput.SelectCharacters - The selection is updated with individual characters. (Default)
2170 \li TextInput.SelectWords - The selection is updated with whole words.
2173 This property only applies when \l selectByMouse is true.
2176 QQuickTextInput::SelectionMode QQuickTextInput::mouseSelectionMode() const
2178 Q_D(const QQuickTextInput);
2179 return d->mouseSelectionMode;
2182 void QQuickTextInput::setMouseSelectionMode(SelectionMode mode)
2184 Q_D(QQuickTextInput);
2185 if (d->mouseSelectionMode != mode) {
2186 d->mouseSelectionMode = mode;
2187 emit mouseSelectionModeChanged(mode);
2192 \qmlproperty bool QtQuick2::TextInput::persistentSelection
2194 Whether the TextInput should keep its selection when it loses active focus to another
2195 item in the scene. By default this is set to false;
2198 bool QQuickTextInput::persistentSelection() const
2200 Q_D(const QQuickTextInput);
2201 return d->persistentSelection;
2204 void QQuickTextInput::setPersistentSelection(bool on)
2206 Q_D(QQuickTextInput);
2207 if (d->persistentSelection == on)
2209 d->persistentSelection = on;
2210 emit persistentSelectionChanged();
2214 \qmlproperty bool QtQuick2::TextInput::canPaste
2216 Returns true if the TextInput is writable and the content of the clipboard is
2217 suitable for pasting into the TextInput.
2219 bool QQuickTextInput::canPaste() const
2221 Q_D(const QQuickTextInput);
2222 if (!d->canPasteValid) {
2223 if (const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData())
2224 const_cast<QQuickTextInputPrivate *>(d)->canPaste = !d->m_readOnly && mimeData->hasText();
2225 const_cast<QQuickTextInputPrivate *>(d)->canPasteValid = true;
2231 \qmlproperty bool QtQuick2::TextInput::canUndo
2233 Returns true if the TextInput is writable and there are previous operations
2237 bool QQuickTextInput::canUndo() const
2239 Q_D(const QQuickTextInput);
2244 \qmlproperty bool QtQuick2::TextInput::canRedo
2246 Returns true if the TextInput is writable and there are \l {undo}{undone}
2247 operations that can be redone.
2250 bool QQuickTextInput::canRedo() const
2252 Q_D(const QQuickTextInput);
2257 \qmlproperty real QtQuick2::TextInput::contentWidth
2259 Returns the width of the text, including the width past the width
2260 which is covered due to insufficient wrapping if \l wrapMode is set.
2263 qreal QQuickTextInput::contentWidth() const
2265 Q_D(const QQuickTextInput);
2266 return d->boundingRect.width();
2270 \qmlproperty real QtQuick2::TextInput::contentHeight
2272 Returns the height of the text, including the height past the height
2273 that is covered if the text does not fit within the set height.
2276 qreal QQuickTextInput::contentHeight() const
2278 Q_D(const QQuickTextInput);
2279 return d->boundingRect.height();
2282 void QQuickTextInput::moveCursorSelection(int position)
2284 Q_D(QQuickTextInput);
2285 d->moveCursor(position, true);
2289 \qmlmethod void QtQuick2::TextInput::moveCursorSelection(int position, SelectionMode mode = TextInput.SelectCharacters)
2291 Moves the cursor to \a position and updates the selection according to the optional \a mode
2292 parameter. (To only move the cursor, set the \l cursorPosition property.)
2294 When this method is called it additionally sets either the
2295 selectionStart or the selectionEnd (whichever was at the previous cursor position)
2296 to the specified position. This allows you to easily extend and contract the selected
2299 The selection mode specifies whether the selection is updated on a per character or a per word
2300 basis. If not specified the selection mode will default to TextInput.SelectCharacters.
2303 \li TextInput.SelectCharacters - Sets either the selectionStart or selectionEnd (whichever was at
2304 the previous cursor position) to the specified position.
2305 \li TextInput.SelectWords - Sets the selectionStart and selectionEnd to include all
2306 words between the specified position and the previous cursor position. Words partially in the
2310 For example, take this sequence of calls:
2314 moveCursorSelection(9, TextInput.SelectCharacters)
2315 moveCursorSelection(7, TextInput.SelectCharacters)
2318 This moves the cursor to position 5, extend the selection end from 5 to 9
2319 and then retract the selection end from 9 to 7, leaving the text from position 5 to 7
2320 selected (the 6th and 7th characters).
2322 The same sequence with TextInput.SelectWords will extend the selection start to a word boundary
2323 before or on position 5 and extend the selection end to a word boundary on or past position 9.
2325 void QQuickTextInput::moveCursorSelection(int pos, SelectionMode mode)
2327 Q_D(QQuickTextInput);
2329 if (mode == SelectCharacters) {
2330 d->moveCursor(pos, true);
2331 } else if (pos != d->m_cursor){
2332 const int cursor = d->m_cursor;
2334 if (!d->hasSelectedText())
2335 anchor = d->m_cursor;
2336 else if (d->selectionStart() == d->m_cursor)
2337 anchor = d->selectionEnd();
2339 anchor = d->selectionStart();
2341 if (anchor < pos || (anchor == pos && cursor < pos)) {
2342 const QString text = this->text();
2343 QTextBoundaryFinder finder(QTextBoundaryFinder::Word, text);
2344 finder.setPosition(anchor);
2346 const QTextBoundaryFinder::BoundaryReasons reasons = finder.boundaryReasons();
2347 if (anchor < text.length() && (!(reasons & QTextBoundaryFinder::StartWord)
2348 || ((reasons & QTextBoundaryFinder::EndWord) && anchor > cursor))) {
2349 finder.toPreviousBoundary();
2351 anchor = finder.position() != -1 ? finder.position() : 0;
2353 finder.setPosition(pos);
2354 if (pos > 0 && !finder.boundaryReasons())
2355 finder.toNextBoundary();
2356 const int cursor = finder.position() != -1 ? finder.position() : text.length();
2358 d->setSelection(anchor, cursor - anchor);
2359 } else if (anchor > pos || (anchor == pos && cursor > pos)) {
2360 const QString text = this->text();
2361 QTextBoundaryFinder finder(QTextBoundaryFinder::Word, text);
2362 finder.setPosition(anchor);
2364 const QTextBoundaryFinder::BoundaryReasons reasons = finder.boundaryReasons();
2365 if (anchor > 0 && (!(reasons & QTextBoundaryFinder::EndWord)
2366 || ((reasons & QTextBoundaryFinder::StartWord) && anchor < cursor))) {
2367 finder.toNextBoundary();
2370 anchor = finder.position() != -1 ? finder.position() : text.length();
2372 finder.setPosition(pos);
2373 if (pos < text.length() && !finder.boundaryReasons())
2374 finder.toPreviousBoundary();
2375 const int cursor = finder.position() != -1 ? finder.position() : 0;
2377 d->setSelection(anchor, cursor - anchor);
2383 \qmlmethod void QtQuick2::TextInput::openSoftwareInputPanel()
2385 Opens software input panels like virtual keyboards for typing, useful for
2386 customizing when you want the input keyboard to be shown and hidden in
2389 By default the opening of input panels follows the platform style. Input panels are
2390 always closed if no editor has active focus.
2392 You can disable the automatic behavior by setting the property \c activeFocusOnPress to false
2393 and use functions openSoftwareInputPanel() and closeSoftwareInputPanel() to implement
2394 the behavior you want.
2396 Only relevant on platforms, which provide virtual keyboards.
2402 text: "Hello world!"
2403 activeFocusOnPress: false
2405 anchors.fill: parent
2407 if (!textInput.activeFocus) {
2408 textInput.forceActiveFocus()
2409 textInput.openSoftwareInputPanel();
2411 textInput.focus = false;
2414 onPressAndHold: textInput.closeSoftwareInputPanel();
2419 void QQuickTextInput::openSoftwareInputPanel()
2422 qGuiApp->inputMethod()->show();
2426 \qmlmethod void QtQuick2::TextInput::closeSoftwareInputPanel()
2428 Closes a software input panel like a virtual keyboard shown on the screen, useful
2429 for customizing when you want the input keyboard to be shown and hidden in
2432 By default the opening of input panels follows the platform style. Input panels are
2433 always closed if no editor has active focus.
2435 You can disable the automatic behavior by setting the property \c activeFocusOnPress to false
2436 and use functions openSoftwareInputPanel() and closeSoftwareInputPanel() to implement
2437 the behavior you want.
2439 Only relevant on platforms, which provide virtual keyboards.
2445 text: "Hello world!"
2446 activeFocusOnPress: false
2448 anchors.fill: parent
2450 if (!textInput.activeFocus) {
2451 textInput.forceActiveFocus();
2452 textInput.openSoftwareInputPanel();
2454 textInput.focus = false;
2457 onPressAndHold: textInput.closeSoftwareInputPanel();
2462 void QQuickTextInput::closeSoftwareInputPanel()
2465 qGuiApp->inputMethod()->hide();
2468 void QQuickTextInput::focusInEvent(QFocusEvent *event)
2470 Q_D(const QQuickTextInput);
2471 if (d->focusOnPress && !d->m_readOnly)
2472 openSoftwareInputPanel();
2473 QQuickImplicitSizeItem::focusInEvent(event);
2476 void QQuickTextInput::itemChange(ItemChange change, const ItemChangeData &value)
2478 Q_D(QQuickTextInput);
2479 if (change == ItemActiveFocusHasChanged) {
2480 bool hasFocus = value.boolValue;
2481 setCursorVisible(hasFocus); // ### refactor: && d->canvas && d->canvas->hasFocus()
2482 if (!hasFocus && (d->m_passwordEchoEditing || d->m_passwordEchoTimer.isActive())) {
2483 d->updatePasswordEchoEditing(false);//QQuickTextInputPrivate sets it on key events, but doesn't deal with focus events
2487 if (!d->persistentSelection)
2489 disconnect(qApp->inputMethod(), SIGNAL(inputDirectionChanged(Qt::LayoutDirection)),
2490 this, SLOT(q_updateAlignment()));
2492 q_updateAlignment();
2493 connect(qApp->inputMethod(), SIGNAL(inputDirectionChanged(Qt::LayoutDirection)),
2494 this, SLOT(q_updateAlignment()));
2497 QQuickItem::itemChange(change, value);
2501 \qmlproperty bool QtQuick2::TextInput::inputMethodComposing
2504 This property holds whether the TextInput has partial text input from an
2507 While it is composing an input method may rely on mouse or key events from
2508 the TextInput to edit or commit the partial text. This property can be
2509 used to determine when to disable events handlers that may interfere with
2510 the correct operation of an input method.
2512 bool QQuickTextInput::isInputMethodComposing() const
2514 Q_D(const QQuickTextInput);
2515 return d->hasImState;
2518 void QQuickTextInputPrivate::init()
2520 Q_Q(QQuickTextInput);
2521 q->setSmooth(smooth);
2522 q->setAcceptedMouseButtons(Qt::LeftButton);
2523 q->setFlag(QQuickItem::ItemAcceptsInputMethod);
2524 q->setFlag(QQuickItem::ItemHasContents);
2525 #ifndef QT_NO_CLIPBOARD
2526 q->connect(QGuiApplication::clipboard(), SIGNAL(dataChanged()),
2527 q, SLOT(q_canPasteChanged()));
2528 #endif // QT_NO_CLIPBOARD
2530 lastSelectionStart = 0;
2531 lastSelectionEnd = 0;
2532 determineHorizontalAlignment();
2534 if (!qmlDisableDistanceField()) {
2535 QTextOption option = m_textLayout.textOption();
2536 option.setUseDesignMetrics(true);
2537 m_textLayout.setTextOption(option);
2541 void QQuickTextInput::updateCursorRectangle()
2543 Q_D(QQuickTextInput);
2544 if (!isComponentComplete())
2547 d->updateHorizontalScroll();
2548 d->updateVerticalScroll();
2549 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
2551 emit cursorRectangleChanged();
2552 if (d->cursorItem) {
2553 QRectF r = cursorRectangle();
2554 d->cursorItem->setPos(r.topLeft());
2555 d->cursorItem->setHeight(r.height());
2557 updateInputMethod(Qt::ImCursorRectangle);
2560 void QQuickTextInput::selectionChanged()
2562 Q_D(QQuickTextInput);
2563 d->textLayoutDirty = true; //TODO: Only update rect in selection
2564 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
2566 emit selectedTextChanged();
2568 if (d->lastSelectionStart != d->selectionStart()) {
2569 d->lastSelectionStart = d->selectionStart();
2570 if (d->lastSelectionStart == -1)
2571 d->lastSelectionStart = d->m_cursor;
2572 emit selectionStartChanged();
2574 if (d->lastSelectionEnd != d->selectionEnd()) {
2575 d->lastSelectionEnd = d->selectionEnd();
2576 if (d->lastSelectionEnd == -1)
2577 d->lastSelectionEnd = d->m_cursor;
2578 emit selectionEndChanged();
2582 void QQuickTextInputPrivate::showCursor()
2584 if (textNode != 0 && textNode->cursorNode() != 0)
2585 textNode->cursorNode()->setColor(color);
2588 void QQuickTextInputPrivate::hideCursor()
2590 if (textNode != 0 && textNode->cursorNode() != 0)
2591 textNode->cursorNode()->setColor(QColor(0, 0, 0, 0));
2594 QRectF QQuickTextInput::boundingRect() const
2596 Q_D(const QQuickTextInput);
2598 int cursorWidth = d->cursorItem ? d->cursorItem->width() : 1;
2600 // Could include font max left/right bearings to either side of rectangle.
2601 QRectF r = QQuickImplicitSizeItem::boundingRect();
2602 r.setRight(r.right() + cursorWidth);
2606 void QQuickTextInput::q_canPasteChanged()
2608 Q_D(QQuickTextInput);
2609 bool old = d->canPaste;
2610 #ifndef QT_NO_CLIPBOARD
2611 if (const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData())
2612 d->canPaste = !d->m_readOnly && mimeData->hasText();
2614 d->canPaste = false;
2617 bool changed = d->canPaste != old || !d->canPasteValid;
2618 d->canPasteValid = true;
2620 emit canPasteChanged();
2624 void QQuickTextInput::q_updateAlignment()
2626 Q_D(QQuickTextInput);
2627 if (d->determineHorizontalAlignment()) {
2629 updateCursorRectangle();
2633 // ### these should come from QStyleHints
2634 const int textCursorWidth = 1;
2635 const bool fullWidthSelection = true;
2640 Updates the display text based of the current edit text
2641 If the text has changed will emit displayTextChanged()
2643 void QQuickTextInputPrivate::updateDisplayText(bool forceUpdate)
2645 QString orig = m_textLayout.text();
2647 if (m_echoMode == QQuickTextInput::NoEcho)
2648 str = QString::fromLatin1("");
2652 if (m_echoMode == QQuickTextInput::Password) {
2653 str.fill(m_passwordCharacter);
2654 if (m_passwordEchoTimer.isActive() && m_cursor > 0 && m_cursor <= m_text.length()) {
2655 int cursor = m_cursor - 1;
2656 QChar uc = m_text.at(cursor);
2658 if (cursor > 0 && uc.unicode() >= 0xdc00 && uc.unicode() < 0xe000) {
2659 // second half of a surrogate, check if we have the first half as well,
2660 // if yes restore both at once
2661 uc = m_text.at(cursor - 1);
2662 if (uc.unicode() >= 0xd800 && uc.unicode() < 0xdc00)
2663 str[cursor - 1] = uc;
2666 } else if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit && !m_passwordEchoEditing) {
2667 str.fill(m_passwordCharacter);
2670 // replace certain non-printable characters with spaces (to avoid
2671 // drawing boxes when using fonts that don't have glyphs for such
2673 QChar* uc = str.data();
2674 for (int i = 0; i < (int)str.length(); ++i) {
2675 if ((uc[i] < 0x20 && uc[i] != 0x09)
2676 || uc[i] == QChar::LineSeparator
2677 || uc[i] == QChar::ParagraphSeparator
2678 || uc[i] == QChar::ObjectReplacementCharacter)
2679 uc[i] = QChar(0x0020);
2682 if (str != orig || forceUpdate) {
2683 m_textLayout.setText(str);
2684 updateLayout(); // polish?
2685 emit q_func()->displayTextChanged();
2689 qreal QQuickTextInputPrivate::getImplicitWidth() const
2691 Q_Q(const QQuickTextInput);
2692 if (!requireImplicitWidth) {
2693 QQuickTextInputPrivate *d = const_cast<QQuickTextInputPrivate *>(this);
2694 d->requireImplicitWidth = true;
2696 if (q->isComponentComplete()) {
2697 // One time cost, only incurred if implicitWidth is first requested after
2698 // componentComplete.
2699 QTextLayout layout(m_text);
2701 QTextOption option = m_textLayout.textOption();
2702 option.setTextDirection(m_layoutDirection);
2703 option.setFlags(QTextOption::IncludeTrailingSpaces);
2704 option.setWrapMode(QTextOption::WrapMode(wrapMode));
2705 option.setAlignment(Qt::Alignment(q->effectiveHAlign()));
2706 layout.setTextOption(option);
2707 layout.setFont(font);
2708 layout.setPreeditArea(m_textLayout.preeditAreaPosition(), m_textLayout.preeditAreaText());
2709 layout.beginLayout();
2711 QTextLine line = layout.createLine();
2712 line.setLineWidth(INT_MAX);
2713 d->implicitWidth = qCeil(line.naturalTextWidth());
2718 return implicitWidth;
2721 void QQuickTextInputPrivate::updateLayout()
2723 Q_Q(QQuickTextInput);
2725 if (!q->isComponentComplete())
2728 const QRectF previousRect = boundingRect;
2730 QTextOption option = m_textLayout.textOption();
2731 option.setTextDirection(layoutDirection());
2732 option.setWrapMode(QTextOption::WrapMode(wrapMode));
2733 option.setAlignment(Qt::Alignment(q->effectiveHAlign()));
2734 m_textLayout.setTextOption(option);
2735 m_textLayout.setFont(font);
2737 boundingRect = QRectF();
2738 m_textLayout.beginLayout();
2739 QTextLine line = m_textLayout.createLine();
2740 if (requireImplicitWidth) {
2741 line.setLineWidth(INT_MAX);
2742 const bool wasInLayout = inLayout;
2744 q->setImplicitWidth(qCeil(line.naturalTextWidth()));
2745 inLayout = wasInLayout;
2746 if (inLayout) // probably the result of a binding loop, but by letting it
2747 return; // get this far we'll get a warning to that effect.
2749 qreal lineWidth = q->widthValid() ? q->width() : INT_MAX;
2752 line.setLineWidth(lineWidth);
2753 line.setPosition(QPointF(line.position().x(), height));
2754 boundingRect = boundingRect.united(line.naturalTextRect());
2756 height += line.height();
2757 line = m_textLayout.createLine();
2758 } while (line.isValid());
2759 m_textLayout.endLayout();
2761 option.setWrapMode(QTextOption::NoWrap);
2762 m_textLayout.setTextOption(option);
2764 textLayoutDirty = true;
2766 updateType = UpdatePaintNode;
2769 if (!requireImplicitWidth && !q->widthValid())
2770 q->setImplicitSize(qCeil(boundingRect.width()), qCeil(boundingRect.height()));
2772 q->setImplicitHeight(qCeil(boundingRect.height()));
2774 if (previousRect != boundingRect)
2775 emit q->contentSizeChanged();
2778 #ifndef QT_NO_CLIPBOARD
2782 Copies the currently selected text into the clipboard using the given
2785 \note If the echo mode is set to a mode other than Normal then copy
2786 will not work. This is to prevent using copy as a method of bypassing
2787 password features of the line control.
2789 void QQuickTextInputPrivate::copy(QClipboard::Mode mode) const
2791 QString t = selectedText();
2792 if (!t.isEmpty() && m_echoMode == QQuickTextInput::Normal) {
2793 QGuiApplication::clipboard()->setText(t, mode);
2800 Inserts the text stored in the application clipboard into the line
2805 void QQuickTextInputPrivate::paste(QClipboard::Mode clipboardMode)
2807 QString clip = QGuiApplication::clipboard()->text(clipboardMode);
2808 if (!clip.isEmpty() || hasSelectedText()) {
2809 separate(); //make it a separate undo/redo command
2815 #endif // !QT_NO_CLIPBOARD
2820 void QQuickTextInputPrivate::commitPreedit()
2822 Q_Q(QQuickTextInput);
2827 qApp->inputMethod()->commit();
2832 QInputMethodEvent ev;
2833 QCoreApplication::sendEvent(q, &ev);
2836 void QQuickTextInputPrivate::cancelPreedit()
2838 Q_Q(QQuickTextInput);
2843 qApp->inputMethod()->reset();
2845 QInputMethodEvent ev;
2846 QCoreApplication::sendEvent(q, &ev);
2852 Handles the behavior for the backspace key or function.
2853 Removes the current selection if there is a selection, otherwise
2854 removes the character prior to the cursor position.
2858 void QQuickTextInputPrivate::backspace()
2860 int priorState = m_undoState;
2861 if (hasSelectedText()) {
2862 removeSelectedText();
2863 } else if (m_cursor) {
2866 m_cursor = prevMaskBlank(m_cursor);
2867 QChar uc = m_text.at(m_cursor);
2868 if (m_cursor > 0 && uc.unicode() >= 0xdc00 && uc.unicode() < 0xe000) {
2869 // second half of a surrogate, check if we have the first half as well,
2870 // if yes delete both at once
2871 uc = m_text.at(m_cursor - 1);
2872 if (uc.unicode() >= 0xd800 && uc.unicode() < 0xdc00) {
2873 internalDelete(true);
2877 internalDelete(true);
2879 finishChange(priorState);
2885 Handles the behavior for the delete key or function.
2886 Removes the current selection if there is a selection, otherwise
2887 removes the character after the cursor position.
2891 void QQuickTextInputPrivate::del()
2893 int priorState = m_undoState;
2894 if (hasSelectedText()) {
2895 removeSelectedText();
2897 int n = m_textLayout.nextCursorPosition(m_cursor) - m_cursor;
2901 finishChange(priorState);
2907 Inserts the given \a newText at the current cursor position.
2908 If there is any selected text it is removed prior to insertion of
2911 void QQuickTextInputPrivate::insert(const QString &newText)
2913 int priorState = m_undoState;
2914 removeSelectedText();
2915 internalInsert(newText);
2916 finishChange(priorState);
2922 Clears the line control text.
2924 void QQuickTextInputPrivate::clear()
2926 int priorState = m_undoState;
2928 m_selend = m_text.length();
2929 removeSelectedText();
2931 finishChange(priorState, /*update*/false, /*edited*/false);
2937 Sets \a length characters from the given \a start position as selected.
2938 The given \a start position must be within the current text for
2939 the line control. If \a length characters cannot be selected, then
2940 the selection will extend to the end of the current text.
2942 void QQuickTextInputPrivate::setSelection(int start, int length)
2944 Q_Q(QQuickTextInput);
2947 if (start < 0 || start > (int)m_text.length()){
2948 qWarning("QQuickTextInputPrivate::setSelection: Invalid start position");
2953 if (start == m_selstart && start + length == m_selend && m_cursor == m_selend)
2956 m_selend = qMin(start + length, (int)m_text.length());
2957 m_cursor = m_selend;
2958 } else if (length < 0){
2959 if (start == m_selend && start + length == m_selstart && m_cursor == m_selstart)
2961 m_selstart = qMax(start + length, 0);
2963 m_cursor = m_selstart;
2964 } else if (m_selstart != m_selend) {
2970 emitCursorPositionChanged();
2973 emit q->selectionChanged();
2974 emitCursorPositionChanged();
2975 q->updateInputMethod(Qt::ImCursorRectangle | Qt::ImAnchorPosition
2976 | Qt::ImCursorPosition | Qt::ImCurrentSelection);
2982 Sets the password echo editing to \a editing. If password echo editing
2983 is true, then the text of the password is displayed even if the echo
2984 mode is set to QLineEdit::PasswordEchoOnEdit. Password echoing editing
2985 does not affect other echo modes.
2987 void QQuickTextInputPrivate::updatePasswordEchoEditing(bool editing)
2989 cancelPasswordEchoTimer();
2990 m_passwordEchoEditing = editing;
2991 updateDisplayText();
2997 Fixes the current text so that it is valid given any set validators.
2999 Returns true if the text was changed. Otherwise returns false.
3001 bool QQuickTextInputPrivate::fixup() // this function assumes that validate currently returns != Acceptable
3003 #ifndef QT_NO_VALIDATOR
3005 QString textCopy = m_text;
3006 int cursorCopy = m_cursor;
3007 m_validator->fixup(textCopy);
3008 if (m_validator->validate(textCopy, cursorCopy) == QValidator::Acceptable) {
3009 if (textCopy != m_text || cursorCopy != m_cursor)
3010 internalSetText(textCopy, cursorCopy);
3021 Moves the cursor to the given position \a pos. If \a mark is true will
3022 adjust the currently selected text.
3024 void QQuickTextInputPrivate::moveCursor(int pos, bool mark)
3026 Q_Q(QQuickTextInput);
3029 if (pos != m_cursor) {
3032 pos = pos > m_cursor ? nextMaskBlank(pos) : prevMaskBlank(pos);
3036 if (m_selend > m_selstart && m_cursor == m_selstart)
3038 else if (m_selend > m_selstart && m_cursor == m_selend)
3039 anchor = m_selstart;
3042 m_selstart = qMin(anchor, pos);
3043 m_selend = qMax(anchor, pos);
3048 if (mark || m_selDirty) {
3050 emit q->selectionChanged();
3052 emitCursorPositionChanged();
3053 q->updateInputMethod();
3059 Applies the given input method event \a event to the text of the line
3062 void QQuickTextInputPrivate::processInputMethodEvent(QInputMethodEvent *event)
3064 Q_Q(QQuickTextInput);
3066 int priorState = -1;
3067 bool isGettingInput = !event->commitString().isEmpty()
3068 || event->preeditString() != preeditAreaText()
3069 || event->replacementLength() > 0;
3070 bool cursorPositionChanged = false;
3071 bool selectionChange = false;
3072 m_preeditDirty = event->preeditString() != preeditAreaText();
3074 if (isGettingInput) {
3075 // If any text is being input, remove selected text.
3076 priorState = m_undoState;
3077 if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit && !m_passwordEchoEditing) {
3078 updatePasswordEchoEditing(true);
3080 m_selend = m_text.length();
3082 removeSelectedText();
3085 int c = m_cursor; // cursor position after insertion of commit string
3086 if (event->replacementStart() <= 0)
3087 c += event->commitString().length() - qMin(-event->replacementStart(), event->replacementLength());
3089 m_cursor += event->replacementStart();
3093 // insert commit string
3094 if (event->replacementLength()) {
3095 m_selstart = m_cursor;
3096 m_selend = m_selstart + event->replacementLength();
3097 m_selend = qMin(m_selend, m_text.length());
3098 removeSelectedText();
3100 if (!event->commitString().isEmpty()) {
3101 internalInsert(event->commitString());
3102 cursorPositionChanged = true;
3105 m_cursor = qBound(0, c, m_text.length());
3107 for (int i = 0; i < event->attributes().size(); ++i) {
3108 const QInputMethodEvent::Attribute &a = event->attributes().at(i);
3109 if (a.type == QInputMethodEvent::Selection) {
3110 m_cursor = qBound(0, a.start + a.length, m_text.length());
3112 m_selstart = qMax(0, qMin(a.start, m_text.length()));
3113 m_selend = m_cursor;
3114 if (m_selend < m_selstart) {
3115 qSwap(m_selstart, m_selend);
3117 selectionChange = true;
3119 m_selstart = m_selend = 0;
3121 cursorPositionChanged = true;
3125 m_textLayout.setPreeditArea(m_cursor, event->preeditString());
3127 const int oldPreeditCursor = m_preeditCursor;
3128 const bool oldCursorVisible = cursorVisible;
3129 m_preeditCursor = event->preeditString().length();
3130 hasImState = !event->preeditString().isEmpty();
3131 cursorVisible = true;
3132 QList<QTextLayout::FormatRange> formats;
3133 for (int i = 0; i < event->attributes().size(); ++i) {
3134 const QInputMethodEvent::Attribute &a = event->attributes().at(i);
3135 if (a.type == QInputMethodEvent::Cursor) {
3137 m_preeditCursor = a.start;
3138 cursorVisible = a.length != 0;
3139 } else if (a.type == QInputMethodEvent::TextFormat) {
3141 QTextCharFormat f = qvariant_cast<QTextFormat>(a.value).toCharFormat();
3143 QTextLayout::FormatRange o;
3144 o.start = a.start + m_cursor;
3145 o.length = a.length;
3151 m_textLayout.setAdditionalFormats(formats);
3153 updateDisplayText(/*force*/ true);
3154 if (cursorPositionChanged) {
3155 emitCursorPositionChanged();
3156 } else if (m_preeditCursor != oldPreeditCursor) {
3157 q->updateCursorRectangle();
3161 finishChange(priorState);
3163 if (cursorVisible != oldCursorVisible)
3164 emit q->cursorVisibleChanged(cursorVisible);
3166 if (selectionChange) {
3167 emit q->selectionChanged();
3168 q->updateInputMethod(Qt::ImCursorRectangle | Qt::ImAnchorPosition
3169 | Qt::ImCursorPosition | Qt::ImCurrentSelection);
3176 Sets the selection to cover the word at the given cursor position.
3177 The word boundaries are defined by the behavior of QTextLayout::SkipWords
3180 void QQuickTextInputPrivate::selectWordAtPos(int cursor)
3182 int next = cursor + 1;
3185 int c = m_textLayout.previousCursorPosition(next, QTextLayout::SkipWords);
3186 moveCursor(c, false);
3187 // ## text layout should support end of words.
3188 int end = m_textLayout.nextCursorPosition(c, QTextLayout::SkipWords);
3189 while (end > cursor && m_text[end-1].isSpace())
3191 moveCursor(end, true);
3197 Completes a change to the line control text. If the change is not valid
3198 will undo the line control state back to the given \a validateFromState.
3200 If \a edited is true and the change is valid, will emit textEdited() in
3201 addition to textChanged(). Otherwise only emits textChanged() on a valid
3204 The \a update value is currently unused.
3206 bool QQuickTextInputPrivate::finishChange(int validateFromState, bool update, bool /*edited*/)
3208 Q_Q(QQuickTextInput);
3211 bool inputMethodAttributesChanged = m_textDirty || m_selDirty;
3212 bool alignmentChanged = false;
3216 bool wasValidInput = m_validInput;
3217 bool wasAcceptable = m_acceptableInput;
3218 m_validInput = true;
3219 m_acceptableInput = true;
3220 #ifndef QT_NO_VALIDATOR
3222 QString textCopy = m_text;
3223 int cursorCopy = m_cursor;
3224 QValidator::State state = m_validator->validate(textCopy, cursorCopy);
3225 m_validInput = state != QValidator::Invalid;
3226 m_acceptableInput = state == QValidator::Acceptable;
3228 if (m_text != textCopy) {
3229 internalSetText(textCopy, cursorCopy);
3232 m_cursor = cursorCopy;
3236 if (validateFromState >= 0 && wasValidInput && !m_validInput) {
3237 if (m_transactions.count())
3239 internalUndo(validateFromState);
3240 m_history.resize(m_undoState);
3241 m_validInput = true;
3242 m_acceptableInput = wasAcceptable;
3243 m_textDirty = false;
3247 m_textDirty = false;
3248 m_preeditDirty = false;
3249 alignmentChanged = determineHorizontalAlignment();
3250 emit q->textChanged();
3253 updateDisplayText(alignmentChanged);
3255 if (m_acceptableInput != wasAcceptable)
3256 emit q->acceptableInputChanged();
3258 if (m_preeditDirty) {
3259 m_preeditDirty = false;
3260 if (determineHorizontalAlignment()) {
3261 alignmentChanged = true;
3268 emit q->selectionChanged();
3271 inputMethodAttributesChanged |= (m_cursor == m_lastCursorPos);
3272 if (inputMethodAttributesChanged)
3273 q->updateInputMethod();
3274 emitUndoRedoChanged();
3276 if (!emitCursorPositionChanged() && alignmentChanged)
3277 q->updateCursorRectangle();
3285 An internal function for setting the text of the line control.
3287 void QQuickTextInputPrivate::internalSetText(const QString &txt, int pos, bool edited)
3289 Q_Q(QQuickTextInput);
3291 QString oldText = m_text;
3293 m_text = maskString(0, txt, true);
3294 m_text += clearString(m_text.length(), m_maxLength - m_text.length());
3296 m_text = txt.isEmpty() ? txt : txt.left(m_maxLength);
3300 m_cursor = (pos < 0 || pos > m_text.length()) ? m_text.length() : pos;
3301 m_textDirty = (oldText != m_text);
3303 bool changed = finishChange(-1, true, edited);
3304 #ifdef QT_NO_ACCESSIBILITY
3308 QAccessibleTextUpdateEvent ev(q, 0, oldText, m_text);
3309 QAccessible::updateAccessibility(&ev);
3318 Adds the given \a command to the undo history
3319 of the line control. Does not apply the command.
3321 void QQuickTextInputPrivate::addCommand(const Command &cmd)
3323 if (m_separator && m_undoState && m_history[m_undoState - 1].type != Separator) {
3324 m_history.resize(m_undoState + 2);
3325 m_history[m_undoState++] = Command(Separator, m_cursor, 0, m_selstart, m_selend);
3327 m_history.resize(m_undoState + 1);
3329 m_separator = false;
3330 m_history[m_undoState++] = cmd;
3336 Inserts the given string \a s into the line
3339 Also adds the appropriate commands into the undo history.
3340 This function does not call finishChange(), and may leave the text
3341 in an invalid state.
3343 void QQuickTextInputPrivate::internalInsert(const QString &s)
3345 Q_Q(QQuickTextInput);
3346 if (m_echoMode == QQuickTextInput::Password) {
3347 int delay = qGuiApp->styleHints()->passwordMaskDelay();
3349 m_passwordEchoTimer.start(delay, q);
3351 if (hasSelectedText())
3352 addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
3354 QString ms = maskString(m_cursor, s);
3355 for (int i = 0; i < (int) ms.length(); ++i) {
3356 addCommand (Command(DeleteSelection, m_cursor + i, m_text.at(m_cursor + i), -1, -1));
3357 addCommand(Command(Insert, m_cursor + i, ms.at(i), -1, -1));
3359 m_text.replace(m_cursor, ms.length(), ms);
3360 m_cursor += ms.length();
3361 m_cursor = nextMaskBlank(m_cursor);
3364 int remaining = m_maxLength - m_text.length();
3365 if (remaining != 0) {
3366 m_text.insert(m_cursor, s.left(remaining));
3367 for (int i = 0; i < (int) s.left(remaining).length(); ++i)
3368 addCommand(Command(Insert, m_cursor++, s.at(i), -1, -1));
3377 deletes a single character from the current text. If \a wasBackspace,
3378 the character prior to the cursor is removed. Otherwise the character
3379 after the cursor is removed.
3381 Also adds the appropriate commands into the undo history.
3382 This function does not call finishChange(), and may leave the text
3383 in an invalid state.
3385 void QQuickTextInputPrivate::internalDelete(bool wasBackspace)
3387 if (m_cursor < (int) m_text.length()) {
3388 cancelPasswordEchoTimer();
3389 if (hasSelectedText())
3390 addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
3391 addCommand(Command((CommandType)((m_maskData ? 2 : 0) + (wasBackspace ? Remove : Delete)),
3392 m_cursor, m_text.at(m_cursor), -1, -1));
3394 m_text.replace(m_cursor, 1, clearString(m_cursor, 1));
3395 addCommand(Command(Insert, m_cursor, m_text.at(m_cursor), -1, -1));
3397 m_text.remove(m_cursor, 1);
3406 removes the currently selected text from the line control.
3408 Also adds the appropriate commands into the undo history.
3409 This function does not call finishChange(), and may leave the text
3410 in an invalid state.
3412 void QQuickTextInputPrivate::removeSelectedText()
3414 if (m_selstart < m_selend && m_selend <= (int) m_text.length()) {
3415 cancelPasswordEchoTimer();
3418 addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
3419 if (m_selstart <= m_cursor && m_cursor < m_selend) {
3420 // cursor is within the selection. Split up the commands
3421 // to be able to restore the correct cursor position
3422 for (i = m_cursor; i >= m_selstart; --i)
3423 addCommand (Command(DeleteSelection, i, m_text.at(i), -1, 1));
3424 for (i = m_selend - 1; i > m_cursor; --i)
3425 addCommand (Command(DeleteSelection, i - m_cursor + m_selstart - 1, m_text.at(i), -1, -1));
3427 for (i = m_selend-1; i >= m_selstart; --i)
3428 addCommand (Command(RemoveSelection, i, m_text.at(i), -1, -1));
3431 m_text.replace(m_selstart, m_selend - m_selstart, clearString(m_selstart, m_selend - m_selstart));
3432 for (int i = 0; i < m_selend - m_selstart; ++i)
3433 addCommand(Command(Insert, m_selstart + i, m_text.at(m_selstart + i), -1, -1));
3435 m_text.remove(m_selstart, m_selend - m_selstart);
3437 if (m_cursor > m_selstart)
3438 m_cursor -= qMin(m_cursor, m_selend) - m_selstart;
3447 Parses the input mask specified by \a maskFields to generate
3448 the mask data used to handle input masks.
3450 void QQuickTextInputPrivate::parseInputMask(const QString &maskFields)
3452 int delimiter = maskFields.indexOf(QLatin1Char(';'));
3453 if (maskFields.isEmpty() || delimiter == 0) {
3455 delete [] m_maskData;
3457 m_maxLength = 32767;
3458 internalSetText(QString());
3463 if (delimiter == -1) {
3464 m_blank = QLatin1Char(' ');
3465 m_inputMask = maskFields;
3467 m_inputMask = maskFields.left(delimiter);
3468 m_blank = (delimiter + 1 < maskFields.length()) ? maskFields[delimiter + 1] : QLatin1Char(' ');
3471 // calculate m_maxLength / m_maskData length
3474 for (int i=0; i<m_inputMask.length(); i++) {
3475 c = m_inputMask.at(i);
3476 if (i > 0 && m_inputMask.at(i-1) == QLatin1Char('\\')) {
3480 if (c != QLatin1Char('\\') && c != QLatin1Char('!') &&
3481 c != QLatin1Char('<') && c != QLatin1Char('>') &&
3482 c != QLatin1Char('{') && c != QLatin1Char('}') &&
3483 c != QLatin1Char('[') && c != QLatin1Char(']'))
3487 delete [] m_maskData;
3488 m_maskData = new MaskInputData[m_maxLength];
3490 MaskInputData::Casemode m = MaskInputData::NoCaseMode;
3493 bool escape = false;
3495 for (int i = 0; i < m_inputMask.length(); i++) {
3496 c = m_inputMask.at(i);
3499 m_maskData[index].maskChar = c;
3500 m_maskData[index].separator = s;
3501 m_maskData[index].caseMode = m;
3504 } else if (c == QLatin1Char('<')) {
3505 m = MaskInputData::Lower;
3506 } else if (c == QLatin1Char('>')) {
3507 m = MaskInputData::Upper;
3508 } else if (c == QLatin1Char('!')) {
3509 m = MaskInputData::NoCaseMode;
3510 } else if (c != QLatin1Char('{') && c != QLatin1Char('}') && c != QLatin1Char('[') && c != QLatin1Char(']')) {
3511 switch (c.unicode()) {
3537 m_maskData[index].maskChar = c;
3538 m_maskData[index].separator = s;
3539 m_maskData[index].caseMode = m;
3544 internalSetText(m_text);
3551 checks if the key is valid compared to the inputMask
3553 bool QQuickTextInputPrivate::isValidInput(QChar key, QChar mask) const
3555 switch (mask.unicode()) {
3561 if (key.isLetter() || key == m_blank)
3565 if (key.isLetterOrNumber())
3569 if (key.isLetterOrNumber() || key == m_blank)
3577 if (key.isPrint() || key == m_blank)
3585 if (key.isNumber() || key == m_blank)
3589 if (key.isNumber() && key.digitValue() > 0)
3593 if ((key.isNumber() && key.digitValue() > 0) || key == m_blank)
3597 if (key.isNumber() || key == QLatin1Char('+') || key == QLatin1Char('-') || key == m_blank)
3601 if (key == QLatin1Char('0') || key == QLatin1Char('1'))
3605 if (key == QLatin1Char('0') || key == QLatin1Char('1') || key == m_blank)
3609 if (key.isNumber() || (key >= QLatin1Char('a') && key <= QLatin1Char('f')) || (key >= QLatin1Char('A') && key <= QLatin1Char('F')))
3613 if (key.isNumber() || (key >= QLatin1Char('a') && key <= QLatin1Char('f')) || (key >= QLatin1Char('A') && key <= QLatin1Char('F')) || key == m_blank)
3625 Returns true if the given text \a str is valid for any
3626 validator or input mask set for the line control.
3628 Otherwise returns false
3630 QQuickTextInputPrivate::ValidatorState QQuickTextInputPrivate::hasAcceptableInput(const QString &str) const
3632 #ifndef QT_NO_VALIDATOR
3633 QString textCopy = str;
3634 int cursorCopy = m_cursor;
3636 QValidator::State state = m_validator->validate(textCopy, cursorCopy);
3637 if (state != QValidator::Acceptable)
3638 return ValidatorState(state);
3643 return AcceptableInput;
3645 if (str.length() != m_maxLength)
3646 return InvalidInput;
3648 for (int i=0; i < m_maxLength; ++i) {
3649 if (m_maskData[i].separator) {
3650 if (str.at(i) != m_maskData[i].maskChar)
3651 return InvalidInput;
3653 if (!isValidInput(str.at(i), m_maskData[i].maskChar))
3654 return InvalidInput;
3657 return AcceptableInput;
3663 Applies the inputMask on \a str starting from position \a pos in the mask. \a clear
3664 specifies from where characters should be gotten when a separator is met in \a str - true means
3665 that blanks will be used, false that previous input is used.
3666 Calling this when no inputMask is set is undefined.
3668 QString QQuickTextInputPrivate::maskString(uint pos, const QString &str, bool clear) const
3670 if (pos >= (uint)m_maxLength)
3671 return QString::fromLatin1("");
3674 fill = clear ? clearString(0, m_maxLength) : m_text;
3677 QString s = QString::fromLatin1("");
3679 while (i < m_maxLength) {
3680 if (strIndex < str.length()) {
3681 if (m_maskData[i].separator) {
3682 s += m_maskData[i].maskChar;
3683 if (str[(int)strIndex] == m_maskData[i].maskChar)
3687 if (isValidInput(str[(int)strIndex], m_maskData[i].maskChar)) {
3688 switch (m_maskData[i].caseMode) {
3689 case MaskInputData::Upper:
3690 s += str[(int)strIndex].toUpper();
3692 case MaskInputData::Lower:
3693 s += str[(int)strIndex].toLower();
3696 s += str[(int)strIndex];
3700 // search for separator first
3701 int n = findInMask(i, true, true, str[(int)strIndex]);
3703 if (str.length() != 1 || i == 0 || (i > 0 && (!m_maskData[i-1].separator || m_maskData[i-1].maskChar != str[(int)strIndex]))) {
3704 s += fill.mid(i, n-i+1);
3705 i = n + 1; // update i to find + 1
3708 // search for valid m_blank if not
3709 n = findInMask(i, true, false, str[(int)strIndex]);
3711 s += fill.mid(i, n-i);
3712 switch (m_maskData[n].caseMode) {
3713 case MaskInputData::Upper:
3714 s += str[(int)strIndex].toUpper();
3716 case MaskInputData::Lower:
3717 s += str[(int)strIndex].toLower();
3720 s += str[(int)strIndex];
3722 i = n + 1; // updates i to find + 1
3740 Returns a "cleared" string with only separators and blank chars.
3741 Calling this when no inputMask is set is undefined.
3743 QString QQuickTextInputPrivate::clearString(uint pos, uint len) const
3745 if (pos >= (uint)m_maxLength)
3749 int end = qMin((uint)m_maxLength, pos + len);
3750 for (int i = pos; i < end; ++i)
3751 if (m_maskData[i].separator)
3752 s += m_maskData[i].maskChar;
3762 Strips blank parts of the input in a QQuickTextInputPrivate when an inputMask is set,
3763 separators are still included. Typically "127.0__.0__.1__" becomes "127.0.0.1".
3765 QString QQuickTextInputPrivate::stripString(const QString &str) const
3771 int end = qMin(m_maxLength, (int)str.length());
3772 for (int i = 0; i < end; ++i) {
3773 if (m_maskData[i].separator)
3774 s += m_maskData[i].maskChar;
3775 else if (str[i] != m_blank)
3784 searches forward/backward in m_maskData for either a separator or a m_blank
3786 int QQuickTextInputPrivate::findInMask(int pos, bool forward, bool findSeparator, QChar searchChar) const
3788 if (pos >= m_maxLength || pos < 0)
3791 int end = forward ? m_maxLength : -1;
3792 int step = forward ? 1 : -1;
3796 if (findSeparator) {
3797 if (m_maskData[i].separator && m_maskData[i].maskChar == searchChar)
3800 if (!m_maskData[i].separator) {
3801 if (searchChar.isNull())
3803 else if (isValidInput(searchChar, m_maskData[i].maskChar))
3812 void QQuickTextInputPrivate::internalUndo(int until)
3814 if (!isUndoAvailable())
3816 cancelPasswordEchoTimer();
3818 while (m_undoState && m_undoState > until) {
3819 Command& cmd = m_history[--m_undoState];
3822 m_text.remove(cmd.pos, 1);
3826 m_selstart = cmd.selStart;
3827 m_selend = cmd.selEnd;
3831 case RemoveSelection:
3832 m_text.insert(cmd.pos, cmd.uc);
3833 m_cursor = cmd.pos + 1;
3836 case DeleteSelection:
3837 m_text.insert(cmd.pos, cmd.uc);
3843 if (until < 0 && m_undoState) {
3844 Command& next = m_history[m_undoState-1];
3845 if (next.type != cmd.type && next.type < RemoveSelection
3846 && (cmd.type < RemoveSelection || next.type == Separator))
3853 void QQuickTextInputPrivate::internalRedo()
3855 if (!isRedoAvailable())
3858 while (m_undoState < (int)m_history.size()) {
3859 Command& cmd = m_history[m_undoState++];
3862 m_text.insert(cmd.pos, cmd.uc);
3863 m_cursor = cmd.pos + 1;
3866 m_selstart = cmd.selStart;
3867 m_selend = cmd.selEnd;
3872 case RemoveSelection:
3873 case DeleteSelection:
3874 m_text.remove(cmd.pos, 1);
3875 m_selstart = cmd.selStart;
3876 m_selend = cmd.selEnd;
3880 m_selstart = cmd.selStart;
3881 m_selend = cmd.selEnd;
3885 if (m_undoState < (int)m_history.size()) {
3886 Command& next = m_history[m_undoState];
3887 if (next.type != cmd.type && cmd.type < RemoveSelection && next.type != Separator
3888 && (next.type < RemoveSelection || cmd.type == Separator))
3895 void QQuickTextInputPrivate::emitUndoRedoChanged()
3897 Q_Q(QQuickTextInput);
3898 const bool previousUndo = canUndo;
3899 const bool previousRedo = canRedo;
3901 canUndo = isUndoAvailable();
3902 canRedo = isRedoAvailable();
3904 if (previousUndo != canUndo)
3905 emit q->canUndoChanged();
3906 if (previousRedo != canRedo)
3907 emit q->canRedoChanged();
3913 If the current cursor position differs from the last emitted cursor
3914 position, emits cursorPositionChanged().
3916 bool QQuickTextInputPrivate::emitCursorPositionChanged()
3918 Q_Q(QQuickTextInput);
3919 if (m_cursor != m_lastCursorPos) {
3920 m_lastCursorPos = m_cursor;
3922 q->updateCursorRectangle();
3923 emit q->cursorPositionChanged();
3925 if (!hasSelectedText()) {
3926 if (lastSelectionStart != m_cursor) {
3927 lastSelectionStart = m_cursor;
3928 emit q->selectionStartChanged();
3930 if (lastSelectionEnd != m_cursor) {
3931 lastSelectionEnd = m_cursor;
3932 emit q->selectionEndChanged();
3936 #ifndef QT_NO_ACCESSIBILITY
3937 QAccessibleTextCursorEvent ev(q, m_cursor);
3938 QAccessible::updateAccessibility(&ev);
3947 void QQuickTextInputPrivate::setCursorBlinkPeriod(int msec)
3949 Q_Q(QQuickTextInput);
3950 if (msec == m_blinkPeriod)
3953 q->killTimer(m_blinkTimer);
3956 m_blinkTimer = q->startTimer(msec / 2);
3960 if (m_blinkStatus == 1) {
3961 updateType = UpdatePaintNode;
3965 m_blinkPeriod = msec;
3968 void QQuickTextInput::timerEvent(QTimerEvent *event)
3970 Q_D(QQuickTextInput);
3971 if (event->timerId() == d->m_blinkTimer) {
3972 d->m_blinkStatus = !d->m_blinkStatus;
3973 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
3975 } else if (event->timerId() == d->m_passwordEchoTimer.timerId()) {
3976 d->m_passwordEchoTimer.stop();
3977 d->updateDisplayText();
3981 void QQuickTextInputPrivate::processKeyEvent(QKeyEvent* event)
3983 Q_Q(QQuickTextInput);
3984 bool inlineCompletionAccepted = false;
3986 if (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return) {
3987 if (hasAcceptableInput(m_text) || fixup()) {
3990 if (inlineCompletionAccepted)
3997 if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit
3998 && !m_passwordEchoEditing
4000 && !event->text().isEmpty()
4001 && !(event->modifiers() & Qt::ControlModifier)) {
4002 // Clear the edit and reset to normal echo mode while editing; the
4003 // echo mode switches back when the edit loses focus
4004 // ### resets current content. dubious code; you can
4005 // navigate with keys up, down, back, and select(?), but if you press
4006 // "left" or "right" it clears?
4007 updatePasswordEchoEditing(true);
4011 bool unknown = false;
4012 bool visual = cursorMoveStyle() == Qt::VisualMoveStyle;
4016 #ifndef QT_NO_SHORTCUT
4017 else if (event == QKeySequence::Undo) {
4020 else if (event == QKeySequence::Redo) {
4023 else if (event == QKeySequence::SelectAll) {
4026 #ifndef QT_NO_CLIPBOARD
4027 else if (event == QKeySequence::Copy) {
4030 else if (event == QKeySequence::Paste) {
4032 QClipboard::Mode mode = QClipboard::Clipboard;
4036 else if (event == QKeySequence::Cut) {
4042 else if (event == QKeySequence::DeleteEndOfLine) {
4044 setSelection(m_cursor, end());
4049 #endif //QT_NO_CLIPBOARD
4050 else if (event == QKeySequence::MoveToStartOfLine || event == QKeySequence::MoveToStartOfBlock) {
4053 else if (event == QKeySequence::MoveToEndOfLine || event == QKeySequence::MoveToEndOfBlock) {
4056 else if (event == QKeySequence::SelectStartOfLine || event == QKeySequence::SelectStartOfBlock) {
4059 else if (event == QKeySequence::SelectEndOfLine || event == QKeySequence::SelectEndOfBlock) {
4062 else if (event == QKeySequence::MoveToNextChar) {
4063 if (hasSelectedText()) {
4064 moveCursor(selectionEnd(), false);
4066 cursorForward(0, visual ? 1 : (layoutDirection() == Qt::LeftToRight ? 1 : -1));
4069 else if (event == QKeySequence::SelectNextChar) {
4070 cursorForward(1, visual ? 1 : (layoutDirection() == Qt::LeftToRight ? 1 : -1));
4072 else if (event == QKeySequence::MoveToPreviousChar) {
4073 if (hasSelectedText()) {
4074 moveCursor(selectionStart(), false);
4076 cursorForward(0, visual ? -1 : (layoutDirection() == Qt::LeftToRight ? -1 : 1));
4079 else if (event == QKeySequence::SelectPreviousChar) {
4080 cursorForward(1, visual ? -1 : (layoutDirection() == Qt::LeftToRight ? -1 : 1));
4082 else if (event == QKeySequence::MoveToNextWord) {
4083 if (m_echoMode == QQuickTextInput::Normal)
4084 layoutDirection() == Qt::LeftToRight ? cursorWordForward(0) : cursorWordBackward(0);
4086 layoutDirection() == Qt::LeftToRight ? end(0) : home(0);
4088 else if (event == QKeySequence::MoveToPreviousWord) {
4089 if (m_echoMode == QQuickTextInput::Normal)
4090 layoutDirection() == Qt::LeftToRight ? cursorWordBackward(0) : cursorWordForward(0);
4091 else if (!m_readOnly) {
4092 layoutDirection() == Qt::LeftToRight ? home(0) : end(0);
4095 else if (event == QKeySequence::SelectNextWord) {
4096 if (m_echoMode == QQuickTextInput::Normal)
4097 layoutDirection() == Qt::LeftToRight ? cursorWordForward(1) : cursorWordBackward(1);
4099 layoutDirection() == Qt::LeftToRight ? end(1) : home(1);
4101 else if (event == QKeySequence::SelectPreviousWord) {
4102 if (m_echoMode == QQuickTextInput::Normal)
4103 layoutDirection() == Qt::LeftToRight ? cursorWordBackward(1) : cursorWordForward(1);
4105 layoutDirection() == Qt::LeftToRight ? home(1) : end(1);
4107 else if (event == QKeySequence::Delete) {
4111 else if (event == QKeySequence::DeleteEndOfWord) {
4113 cursorWordForward(true);
4117 else if (event == QKeySequence::DeleteStartOfWord) {
4119 cursorWordBackward(true);
4123 #endif // QT_NO_SHORTCUT
4125 bool handled = false;
4126 if (event->modifiers() & Qt::ControlModifier) {
4127 switch (event->key()) {
4128 case Qt::Key_Backspace:
4130 cursorWordBackward(true);
4138 } else { // ### check for *no* modifier
4139 switch (event->key()) {
4140 case Qt::Key_Backspace:
4152 if (event->key() == Qt::Key_Direction_L || event->key() == Qt::Key_Direction_R) {
4153 setLayoutDirection((event->key() == Qt::Key_Direction_L) ? Qt::LeftToRight : Qt::RightToLeft);
4157 if (unknown && !m_readOnly) {
4158 QString t = event->text();
4159 if (!t.isEmpty() && t.at(0).isPrint()) {