1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the QtDeclarative module of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** 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/qdeclarativeglobal_p.h>
48 #include <QtDeclarative/qdeclarativeinfo.h>
49 #include <QtGui/qevent.h>
50 #include <QTextBoundaryFinder>
51 #include "qquicktextnode_p.h"
52 #include <QtQuick/qsgsimplerectnode.h>
54 #include <QtGui/qstylehints.h>
55 #include <QtGui/qinputpanel.h>
57 #ifndef QT_NO_ACCESSIBILITY
58 #include "qaccessible.h"
63 DEFINE_BOOL_CONFIG_OPTION(qmlDisableDistanceField, QML_DISABLE_DISTANCEFIELD)
65 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
66 static const int qt_passwordEchoDelay = QT_GUI_PASSWORD_ECHO_DELAY;
70 \qmlclass TextInput QQuickTextInput
71 \inqmlmodule QtQuick 2
72 \ingroup qml-basic-visual-elements
73 \brief The TextInput item displays an editable line of text.
76 The TextInput element displays a single line of editable plain text.
78 TextInput is used to accept a line of text input. Input constraints
79 can be placed on a TextInput item (for example, through a \l validator or \l inputMask),
80 and setting \l echoMode to an appropriate value enables TextInput to be used for
81 a password input field.
83 On Mac OS X, the Up/Down key bindings for Home/End are explicitly disabled.
84 If you want such bindings (on any platform), you will need to construct them in QML.
86 \sa TextEdit, Text, {declarative/text/textselection}{Text Selection example}
88 QQuickTextInput::QQuickTextInput(QQuickItem* parent)
89 : QQuickImplicitSizeItem(*(new QQuickTextInputPrivate), parent)
95 QQuickTextInput::~QQuickTextInput()
99 void QQuickTextInput::componentComplete()
101 Q_D(QQuickTextInput);
103 QQuickImplicitSizeItem::componentComplete();
106 updateCursorRectangle();
107 if (d->cursorComponent && d->cursorComponent->isReady())
112 \qmlproperty string QtQuick2::TextInput::text
114 The text in the TextInput.
116 QString QQuickTextInput::text() const
118 Q_D(const QQuickTextInput);
120 QString content = d->m_text;
121 if (!d->m_tentativeCommit.isEmpty())
122 content.insert(d->m_cursor, d->m_tentativeCommit);
123 QString res = d->m_maskData ? d->stripString(content) : content;
124 return (res.isNull() ? QString::fromLatin1("") : res);
127 void QQuickTextInput::setText(const QString &s)
129 Q_D(QQuickTextInput);
132 if (d->composeMode())
133 qApp->inputPanel()->reset();
134 d->m_tentativeCommit.clear();
135 d->internalSetText(s, -1, false);
139 \qmlproperty int QtQuick2::TextInput::length
141 Returns the total number of characters in the TextInput item.
143 If the TextInput has an inputMask the length will include mask characters and may differ
144 from the length of the string returned by the \l text property.
146 This property can be faster than querying the length the \l text property as it doesn't
147 require any copying or conversion of the TextInput's internal string data.
150 int QQuickTextInput::length() const
152 Q_D(const QQuickTextInput);
153 return d->m_text.length();
157 \qmlmethod string QtQuick2::TextInput::getText(int start, int end)
159 Returns the section of text that is between the \a start and \a end positions.
161 If the TextInput has an inputMask the length will include mask characters.
164 QString QQuickTextInput::getText(int start, int end) const
166 Q_D(const QQuickTextInput);
171 return d->m_text.mid(start, end - start);
174 QString QQuickTextInputPrivate::realText() const
176 QString res = m_maskData ? stripString(m_text) : m_text;
177 return (res.isNull() ? QString::fromLatin1("") : res);
181 \qmlproperty string QtQuick2::TextInput::font.family
183 Sets the family name of the font.
185 The family name is case insensitive and may optionally include a foundry name, e.g. "Helvetica [Cronyx]".
186 If the family is available from more than one foundry and the foundry isn't specified, an arbitrary foundry is chosen.
187 If the family isn't available a family will be set using the font matching algorithm.
191 \qmlproperty bool QtQuick2::TextInput::font.bold
193 Sets whether the font weight is bold.
197 \qmlproperty enumeration QtQuick2::TextInput::font.weight
199 Sets the font's weight.
201 The weight can be one of:
204 \o Font.Normal - the default
211 TextInput { text: "Hello"; font.weight: Font.DemiBold }
216 \qmlproperty bool QtQuick2::TextInput::font.italic
218 Sets whether the font has an italic style.
222 \qmlproperty bool QtQuick2::TextInput::font.underline
224 Sets whether the text is underlined.
228 \qmlproperty bool QtQuick2::TextInput::font.strikeout
230 Sets whether the font has a strikeout style.
234 \qmlproperty real QtQuick2::TextInput::font.pointSize
236 Sets the font size in points. The point size must be greater than zero.
240 \qmlproperty int QtQuick2::TextInput::font.pixelSize
242 Sets the font size in pixels.
244 Using this function makes the font device dependent.
245 Use \c pointSize to set the size of the font in a device independent manner.
249 \qmlproperty real QtQuick2::TextInput::font.letterSpacing
251 Sets the letter spacing for the font.
253 Letter spacing changes the default spacing between individual letters in the font.
254 A positive value increases the letter spacing by the corresponding pixels; a negative value decreases the spacing.
258 \qmlproperty real QtQuick2::TextInput::font.wordSpacing
260 Sets the word spacing for the font.
262 Word spacing changes the default spacing between individual words.
263 A positive value increases the word spacing by a corresponding amount of pixels,
264 while a negative value decreases the inter-word spacing accordingly.
268 \qmlproperty enumeration QtQuick2::TextInput::font.capitalization
270 Sets the capitalization for the text.
273 \o Font.MixedCase - This is the normal text rendering option where no capitalization change is applied.
274 \o Font.AllUppercase - This alters the text to be rendered in all uppercase type.
275 \o Font.AllLowercase - This alters the text to be rendered in all lowercase type.
276 \o Font.SmallCaps - This alters the text to be rendered in small-caps type.
277 \o Font.Capitalize - This alters the text to be rendered with the first character of each word as an uppercase character.
281 TextInput { text: "Hello"; font.capitalization: Font.AllLowercase }
285 QFont QQuickTextInput::font() const
287 Q_D(const QQuickTextInput);
288 return d->sourceFont;
291 void QQuickTextInput::setFont(const QFont &font)
293 Q_D(QQuickTextInput);
294 if (d->sourceFont == font)
297 d->sourceFont = font;
298 QFont oldFont = d->font;
300 if (d->font.pointSizeF() != -1) {
302 qreal size = qRound(d->font.pointSizeF()*2.0);
303 d->font.setPointSizeF(size/2.0);
305 if (oldFont != d->font) {
307 updateCursorRectangle();
308 qApp->inputPanel()->update(Qt::ImCursorRectangle | Qt::ImFont);
310 emit fontChanged(d->sourceFont);
314 \qmlproperty color QtQuick2::TextInput::color
318 QColor QQuickTextInput::color() const
320 Q_D(const QQuickTextInput);
324 void QQuickTextInput::setColor(const QColor &c)
326 Q_D(QQuickTextInput);
329 d->textLayoutDirty = true;
331 emit colorChanged(c);
337 \qmlproperty color QtQuick2::TextInput::selectionColor
339 The text highlight color, used behind selections.
341 QColor QQuickTextInput::selectionColor() const
343 Q_D(const QQuickTextInput);
344 return d->selectionColor;
347 void QQuickTextInput::setSelectionColor(const QColor &color)
349 Q_D(QQuickTextInput);
350 if (d->selectionColor == color)
353 d->selectionColor = color;
354 d->m_palette.setColor(QPalette::Highlight, d->selectionColor);
355 if (d->hasSelectedText()) {
356 d->textLayoutDirty = true;
359 emit selectionColorChanged(color);
362 \qmlproperty color QtQuick2::TextInput::selectedTextColor
364 The highlighted text color, used in selections.
366 QColor QQuickTextInput::selectedTextColor() const
368 Q_D(const QQuickTextInput);
369 return d->selectedTextColor;
372 void QQuickTextInput::setSelectedTextColor(const QColor &color)
374 Q_D(QQuickTextInput);
375 if (d->selectedTextColor == color)
378 d->selectedTextColor = color;
379 d->m_palette.setColor(QPalette::HighlightedText, d->selectedTextColor);
380 if (d->hasSelectedText()) {
381 d->textLayoutDirty = true;
384 emit selectedTextColorChanged(color);
388 \qmlproperty enumeration QtQuick2::TextInput::horizontalAlignment
389 \qmlproperty enumeration QtQuick2::TextInput::effectiveHorizontalAlignment
390 \qmlproperty enumeration QtQuick2::TextInput::verticalAlignment
392 Sets the horizontal alignment of the text within the TextInput item's
393 width and height. By default, the text alignment follows the natural alignment
394 of the text, for example text that is read from left to right will be aligned to
397 TextInput does not have vertical alignment, as the natural height is
398 exactly the height of the single line of text. If you set the height
399 manually to something larger, TextInput will always be top aligned
400 vertically. You can use anchors to align it however you want within
403 The valid values for \c horizontalAlignment are \c TextInput.AlignLeft, \c TextInput.AlignRight and
404 \c TextInput.AlignHCenter.
406 Valid values for \c verticalAlignment are \c TextEdit.AlignTop (default),
407 \c TextEdit.AlignBottom \c TextEdit.AlignVCenter.
409 When using the attached property LayoutMirroring::enabled to mirror application
410 layouts, the horizontal alignment of text will also be mirrored. However, the property
411 \c horizontalAlignment will remain unchanged. To query the effective horizontal alignment
412 of TextInput, use the read-only property \c effectiveHorizontalAlignment.
414 QQuickTextInput::HAlignment QQuickTextInput::hAlign() const
416 Q_D(const QQuickTextInput);
420 void QQuickTextInput::setHAlign(HAlignment align)
422 Q_D(QQuickTextInput);
423 bool forceAlign = d->hAlignImplicit && d->effectiveLayoutMirror;
424 d->hAlignImplicit = false;
425 if (d->setHAlign(align, forceAlign) && isComponentComplete()) {
427 updateCursorRectangle();
431 void QQuickTextInput::resetHAlign()
433 Q_D(QQuickTextInput);
434 d->hAlignImplicit = true;
435 if (d->determineHorizontalAlignment() && isComponentComplete()) {
437 updateCursorRectangle();
441 QQuickTextInput::HAlignment QQuickTextInput::effectiveHAlign() const
443 Q_D(const QQuickTextInput);
444 QQuickTextInput::HAlignment effectiveAlignment = d->hAlign;
445 if (!d->hAlignImplicit && d->effectiveLayoutMirror) {
447 case QQuickTextInput::AlignLeft:
448 effectiveAlignment = QQuickTextInput::AlignRight;
450 case QQuickTextInput::AlignRight:
451 effectiveAlignment = QQuickTextInput::AlignLeft;
457 return effectiveAlignment;
460 bool QQuickTextInputPrivate::setHAlign(QQuickTextInput::HAlignment alignment, bool forceAlign)
462 Q_Q(QQuickTextInput);
463 if ((hAlign != alignment || forceAlign) && alignment <= QQuickTextInput::AlignHCenter) { // justify not supported
464 QQuickTextInput::HAlignment oldEffectiveHAlign = q->effectiveHAlign();
466 emit q->horizontalAlignmentChanged(alignment);
467 if (oldEffectiveHAlign != q->effectiveHAlign())
468 emit q->effectiveHorizontalAlignmentChanged();
474 bool QQuickTextInputPrivate::determineHorizontalAlignment()
476 if (hAlignImplicit) {
477 // if no explicit alignment has been set, follow the natural layout direction of the text
478 QString text = q_func()->text();
480 text = m_textLayout.preeditAreaText();
481 bool isRightToLeft = text.isEmpty() ? QGuiApplication::keyboardInputDirection() == Qt::RightToLeft : text.isRightToLeft();
482 return setHAlign(isRightToLeft ? QQuickTextInput::AlignRight : QQuickTextInput::AlignLeft);
487 QQuickTextInput::VAlignment QQuickTextInput::vAlign() const
489 Q_D(const QQuickTextInput);
493 void QQuickTextInput::setVAlign(QQuickTextInput::VAlignment alignment)
495 Q_D(QQuickTextInput);
496 if (alignment == d->vAlign)
498 d->vAlign = alignment;
499 emit verticalAlignmentChanged(d->vAlign);
500 if (isComponentComplete()) {
501 updateCursorRectangle();
506 \qmlproperty enumeration QtQuick2::TextInput::wrapMode
508 Set this property to wrap the text to the TextEdit item's width.
509 The text will only wrap if an explicit width has been set.
512 \o TextInput.NoWrap - no wrapping will be performed. If the text contains insufficient newlines, then implicitWidth will exceed a set width.
513 \o TextInput.WordWrap - wrapping is done on word boundaries only. If a word is too long, implicitWidth will exceed a set width.
514 \o TextInput.WrapAnywhere - wrapping is done at any point on a line, even if it occurs in the middle of a word.
515 \o 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.
518 The default is TextInput.NoWrap. If you set a width, consider using TextInput.Wrap.
520 QQuickTextInput::WrapMode QQuickTextInput::wrapMode() const
522 Q_D(const QQuickTextInput);
526 void QQuickTextInput::setWrapMode(WrapMode mode)
528 Q_D(QQuickTextInput);
529 if (mode == d->wrapMode)
533 updateCursorRectangle();
534 emit wrapModeChanged();
537 void QQuickTextInputPrivate::mirrorChange()
539 Q_Q(QQuickTextInput);
540 if (q->isComponentComplete()) {
541 if (!hAlignImplicit && (hAlign == QQuickTextInput::AlignRight || hAlign == QQuickTextInput::AlignLeft)) {
542 q->updateCursorRectangle();
543 emit q->effectiveHorizontalAlignmentChanged();
549 \qmlproperty bool QtQuick2::TextInput::readOnly
551 Sets whether user input can modify the contents of the TextInput.
553 If readOnly is set to true, then user input will not affect the text
554 property. Any bindings or attempts to set the text property will still
557 bool QQuickTextInput::isReadOnly() const
559 Q_D(const QQuickTextInput);
560 return d->m_readOnly;
563 void QQuickTextInput::setReadOnly(bool ro)
565 Q_D(QQuickTextInput);
566 if (d->m_readOnly == ro)
569 setFlag(QQuickItem::ItemAcceptsInputMethod, !ro);
572 d->setCursorPosition(d->end());
574 d->emitUndoRedoChanged();
575 emit readOnlyChanged(ro);
579 \qmlproperty int QtQuick2::TextInput::maximumLength
580 The maximum permitted length of the text in the TextInput.
582 If the text is too long, it is truncated at the limit.
584 By default, this property contains a value of 32767.
586 int QQuickTextInput::maxLength() const
588 Q_D(const QQuickTextInput);
589 return d->m_maxLength;
592 void QQuickTextInput::setMaxLength(int ml)
594 Q_D(QQuickTextInput);
595 if (d->m_maxLength == ml || d->m_maskData)
599 d->internalSetText(d->m_text, -1, false);
601 emit maximumLengthChanged(ml);
605 \qmlproperty bool QtQuick2::TextInput::cursorVisible
606 Set to true when the TextInput shows a cursor.
608 This property is set and unset when the TextInput gets active focus, so that other
609 properties can be bound to whether the cursor is currently showing. As it
610 gets set and unset automatically, when you set the value yourself you must
611 keep in mind that your value may be overwritten.
613 It can be set directly in script, for example if a KeyProxy might
614 forward keys to it and you desire it to look active when this happens
615 (but without actually giving it active focus).
617 It should not be set directly on the element, like in the below QML,
618 as the specified value will be overridden an lost on focus changes.
627 In the above snippet the cursor will still become visible when the
628 TextInput gains active focus.
630 bool QQuickTextInput::isCursorVisible() const
632 Q_D(const QQuickTextInput);
633 return d->cursorVisible;
636 void QQuickTextInput::setCursorVisible(bool on)
638 Q_D(QQuickTextInput);
639 if (d->cursorVisible == on)
641 d->cursorVisible = on;
642 d->setCursorBlinkPeriod(on ? qApp->styleHints()->cursorFlashTime() : 0);
644 emit cursorVisibleChanged(d->cursorVisible);
648 \qmlproperty int QtQuick2::TextInput::cursorPosition
649 The position of the cursor in the TextInput.
651 int QQuickTextInput::cursorPosition() const
653 Q_D(const QQuickTextInput);
657 void QQuickTextInput::setCursorPosition(int cp)
659 Q_D(QQuickTextInput);
660 if (cp < 0 || cp > text().length())
666 \qmlproperty rectangle QtQuick2::TextInput::cursorRectangle
668 The rectangle where the standard text cursor is rendered within the text input. Read only.
670 The position and height of a custom cursorDelegate are updated to follow the cursorRectangle
671 automatically when it changes. The width of the delegate is unaffected by changes in the
675 QRect QQuickTextInput::cursorRectangle() const
677 Q_D(const QQuickTextInput);
680 if (d->m_preeditCursor != -1)
681 c += d->m_preeditCursor;
682 if (d->m_echoMode == NoEcho)
684 QTextLine l = d->m_textLayout.lineForTextPosition(c);
688 qRound(l.cursorToX(c) - d->hscroll),
689 qRound(l.y() - d->vscroll),
695 \qmlproperty int QtQuick2::TextInput::selectionStart
697 The cursor position before the first character in the current selection.
699 This property is read-only. To change the selection, use select(start,end),
700 selectAll(), or selectWord().
702 \sa selectionEnd, cursorPosition, selectedText
704 int QQuickTextInput::selectionStart() const
706 Q_D(const QQuickTextInput);
707 return d->lastSelectionStart;
710 \qmlproperty int QtQuick2::TextInput::selectionEnd
712 The cursor position after the last character in the current selection.
714 This property is read-only. To change the selection, use select(start,end),
715 selectAll(), or selectWord().
717 \sa selectionStart, cursorPosition, selectedText
719 int QQuickTextInput::selectionEnd() const
721 Q_D(const QQuickTextInput);
722 return d->lastSelectionEnd;
725 \qmlmethod void QtQuick2::TextInput::select(int start, int end)
727 Causes the text from \a start to \a end to be selected.
729 If either start or end is out of range, the selection is not changed.
731 After calling this, selectionStart will become the lesser
732 and selectionEnd will become the greater (regardless of the order passed
735 \sa selectionStart, selectionEnd
737 void QQuickTextInput::select(int start, int end)
739 Q_D(QQuickTextInput);
740 if (start < 0 || end < 0 || start > d->m_text.length() || end > d->m_text.length())
742 d->setSelection(start, end-start);
746 \qmlproperty string QtQuick2::TextInput::selectedText
748 This read-only property provides the text currently selected in the
751 It is equivalent to the following snippet, but is faster and easier
755 myTextInput.text.toString().substring(myTextInput.selectionStart,
756 myTextInput.selectionEnd);
759 QString QQuickTextInput::selectedText() const
761 Q_D(const QQuickTextInput);
762 return d->selectedText();
766 \qmlproperty bool QtQuick2::TextInput::activeFocusOnPress
768 Whether the TextInput should gain active focus on a mouse press. By default this is
771 bool QQuickTextInput::focusOnPress() const
773 Q_D(const QQuickTextInput);
774 return d->focusOnPress;
777 void QQuickTextInput::setFocusOnPress(bool b)
779 Q_D(QQuickTextInput);
780 if (d->focusOnPress == b)
785 emit activeFocusOnPressChanged(d->focusOnPress);
788 \qmlproperty bool QtQuick2::TextInput::autoScroll
790 Whether the TextInput should scroll when the text is longer than the width. By default this is
793 bool QQuickTextInput::autoScroll() const
795 Q_D(const QQuickTextInput);
796 return d->autoScroll;
799 void QQuickTextInput::setAutoScroll(bool b)
801 Q_D(QQuickTextInput);
802 if (d->autoScroll == b)
806 //We need to repaint so that the scrolling is taking into account.
807 updateCursorRectangle();
808 emit autoScrollChanged(d->autoScroll);
811 #ifndef QT_NO_VALIDATOR
814 \qmlclass IntValidator QIntValidator
815 \inqmlmodule QtQuick 2
816 \ingroup qml-basic-visual-elements
818 This element provides a validator for integer values.
820 IntValidator uses the \l {QLocale::setDefault()}{default locale} to interpret the number and
821 will accept locale specific digits, group separators, and positive and negative signs. In
822 addition, IntValidator is always guaranteed to accept a number formatted according to the "C"
826 \qmlproperty int QtQuick2::IntValidator::top
828 This property holds the validator's highest acceptable value.
829 By default, this property's value is derived from the highest signed integer available (typically 2147483647).
832 \qmlproperty int QtQuick2::IntValidator::bottom
834 This property holds the validator's lowest acceptable value.
835 By default, this property's value is derived from the lowest signed integer available (typically -2147483647).
839 \qmlclass DoubleValidator QDoubleValidator
840 \inqmlmodule QtQuick 2
841 \ingroup qml-basic-visual-elements
843 This element provides a validator for non-integer numbers.
847 \qmlproperty real QtQuick2::DoubleValidator::top
849 This property holds the validator's maximum acceptable value.
850 By default, this property contains a value of infinity.
853 \qmlproperty real QtQuick2::DoubleValidator::bottom
855 This property holds the validator's minimum acceptable value.
856 By default, this property contains a value of -infinity.
859 \qmlproperty int QtQuick2::DoubleValidator::decimals
861 This property holds the validator's maximum number of digits after the decimal point.
862 By default, this property contains a value of 1000.
865 \qmlproperty enumeration QtQuick2::DoubleValidator::notation
866 This property holds the notation of how a string can describe a number.
868 The possible values for this property are:
871 \o DoubleValidator.StandardNotation
872 \o DoubleValidator.ScientificNotation (default)
875 If this property is set to DoubleValidator.ScientificNotation, the written number may have an exponent part (e.g. 1.5E-2).
879 \qmlclass RegExpValidator QRegExpValidator
880 \inqmlmodule QtQuick 2
881 \ingroup qml-basic-visual-elements
883 This element provides a validator, which counts as valid any string which
884 matches a specified regular expression.
887 \qmlproperty regExp QtQuick2::RegExpValidator::regExp
889 This property holds the regular expression used for validation.
891 Note that this property should be a regular expression in JS syntax, e.g /a/ for the regular expression
894 By default, this property contains a regular expression with the pattern .* that matches any string.
898 \qmlproperty Validator QtQuick2::TextInput::validator
900 Allows you to set a validator on the TextInput. When a validator is set
901 the TextInput will only accept input which leaves the text property in
902 an acceptable or intermediate state. The accepted signal will only be sent
903 if the text is in an acceptable state when enter is pressed.
905 Currently supported validators are IntValidator, DoubleValidator and
906 RegExpValidator. An example of using validators is shown below, which allows
907 input of integers between 11 and 31 into the text input:
912 validator: IntValidator{bottom: 11; top: 31;}
917 \sa acceptableInput, inputMask
920 QValidator* QQuickTextInput::validator() const
922 Q_D(const QQuickTextInput);
923 return d->m_validator;
926 void QQuickTextInput::setValidator(QValidator* v)
928 Q_D(QQuickTextInput);
929 if (d->m_validator == v)
933 if (!d->hasAcceptableInput(d->m_text)) {
934 if (d->m_validInput) {
935 d->m_validInput = false;
936 emit acceptableInputChanged();
938 } else if (!d->m_validInput) {
939 d->m_validInput = true;
940 emit acceptableInputChanged();
943 emit validatorChanged();
945 #endif // QT_NO_VALIDATOR
948 \qmlproperty string QtQuick2::TextInput::inputMask
950 Allows you to set an input mask on the TextInput, restricting the allowable
951 text inputs. See QLineEdit::inputMask for further details, as the exact
952 same mask strings are used by TextInput.
954 \sa acceptableInput, validator
956 QString QQuickTextInput::inputMask() const
958 Q_D(const QQuickTextInput);
959 return d->inputMask();
962 void QQuickTextInput::setInputMask(const QString &im)
964 Q_D(QQuickTextInput);
965 if (d->inputMask() == im)
969 emit inputMaskChanged(d->inputMask());
973 \qmlproperty bool QtQuick2::TextInput::acceptableInput
975 This property is always true unless a validator or input mask has been set.
976 If a validator or input mask has been set, this property will only be true
977 if the current text is acceptable to the validator or input mask as a final
978 string (not as an intermediate string).
980 bool QQuickTextInput::hasAcceptableInput() const
982 Q_D(const QQuickTextInput);
983 return d->hasAcceptableInput(d->m_text);
987 \qmlsignal QtQuick2::TextInput::onAccepted()
989 This handler is called when the Return or Enter key is pressed.
990 Note that if there is a \l validator or \l inputMask set on the text
991 input, the handler will only be emitted if the input is in an acceptable
995 void QQuickTextInputPrivate::updateInputMethodHints()
997 Q_Q(QQuickTextInput);
998 Qt::InputMethodHints hints = inputMethodHints;
999 if (m_echoMode == QQuickTextInput::Password || m_echoMode == QQuickTextInput::NoEcho)
1000 hints |= Qt::ImhHiddenText;
1001 else if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit)
1002 hints &= ~Qt::ImhHiddenText;
1003 if (m_echoMode != QQuickTextInput::Normal)
1004 hints |= (Qt::ImhNoAutoUppercase | Qt::ImhNoPredictiveText | Qt::ImhSensitiveData);
1005 q->setInputMethodHints(hints);
1008 \qmlproperty enumeration QtQuick2::TextInput::echoMode
1010 Specifies how the text should be displayed in the TextInput.
1012 \o TextInput.Normal - Displays the text as it is. (Default)
1013 \o TextInput.Password - Displays asterisks instead of characters.
1014 \o TextInput.NoEcho - Displays nothing.
1015 \o TextInput.PasswordEchoOnEdit - Displays characters as they are entered
1016 while editing, otherwise displays asterisks.
1019 QQuickTextInput::EchoMode QQuickTextInput::echoMode() const
1021 Q_D(const QQuickTextInput);
1022 return QQuickTextInput::EchoMode(d->m_echoMode);
1025 void QQuickTextInput::setEchoMode(QQuickTextInput::EchoMode echo)
1027 Q_D(QQuickTextInput);
1028 if (echoMode() == echo)
1030 d->cancelPasswordEchoTimer();
1031 d->m_echoMode = echo;
1032 d->m_passwordEchoEditing = false;
1033 d->updateInputMethodHints();
1034 d->updateDisplayText();
1035 updateCursorRectangle();
1037 emit echoModeChanged(echoMode());
1041 \qmlproperty enumeration QtQuick2::TextInput::inputMethodHints
1043 Provides hints to the input method about the expected content of the text input and how it
1046 The value is a bit-wise combination of flags, or Qt.ImhNone if no hints are set.
1048 Flags that alter behaviour are:
1051 \o Qt.ImhHiddenText - Characters should be hidden, as is typically used when entering passwords.
1052 This is automatically set when setting echoMode to \c TextInput.Password.
1053 \o Qt.ImhSensitiveData - Typed text should not be stored by the active input method
1054 in any persistent storage like predictive user dictionary.
1055 \o Qt.ImhNoAutoUppercase - The input method should not try to automatically switch to upper case
1056 when a sentence ends.
1057 \o Qt.ImhPreferNumbers - Numbers are preferred (but not required).
1058 \o Qt.ImhPreferUppercase - Upper case letters are preferred (but not required).
1059 \o Qt.ImhPreferLowercase - Lower case letters are preferred (but not required).
1060 \o Qt.ImhNoPredictiveText - Do not use predictive text (i.e. dictionary lookup) while typing.
1062 \o Qt.ImhDate - The text editor functions as a date field.
1063 \o Qt.ImhTime - The text editor functions as a time field.
1066 Flags that restrict input (exclusive flags) are:
1069 \o Qt.ImhDigitsOnly - Only digits are allowed.
1070 \o Qt.ImhFormattedNumbersOnly - Only number input is allowed. This includes decimal point and minus sign.
1071 \o Qt.ImhUppercaseOnly - Only upper case letter input is allowed.
1072 \o Qt.ImhLowercaseOnly - Only lower case letter input is allowed.
1073 \o Qt.ImhDialableCharactersOnly - Only characters suitable for phone dialing are allowed.
1074 \o Qt.ImhEmailCharactersOnly - Only characters suitable for email addresses are allowed.
1075 \o Qt.ImhUrlCharactersOnly - Only characters suitable for URLs are allowed.
1081 \o Qt.ImhExclusiveInputMask - This mask yields nonzero if any of the exclusive flags are used.
1085 Qt::InputMethodHints QQuickTextInput::imHints() const
1087 Q_D(const QQuickTextInput);
1088 return d->inputMethodHints;
1091 void QQuickTextInput::setIMHints(Qt::InputMethodHints hints)
1093 Q_D(QQuickTextInput);
1094 if (d->inputMethodHints == hints)
1096 d->inputMethodHints = hints;
1097 d->updateInputMethodHints();
1101 \qmlproperty Component QtQuick2::TextInput::cursorDelegate
1102 The delegate for the cursor in the TextInput.
1104 If you set a cursorDelegate for a TextInput, this delegate will be used for
1105 drawing the cursor instead of the standard cursor. An instance of the
1106 delegate will be created and managed by the TextInput when a cursor is
1107 needed, and the x property of delegate instance will be set so as
1108 to be one pixel before the top left of the current character.
1110 Note that the root item of the delegate component must be a QDeclarativeItem or
1111 QDeclarativeItem derived item.
1113 QDeclarativeComponent* QQuickTextInput::cursorDelegate() const
1115 Q_D(const QQuickTextInput);
1116 return d->cursorComponent;
1119 void QQuickTextInput::setCursorDelegate(QDeclarativeComponent* c)
1121 Q_D(QQuickTextInput);
1122 if (d->cursorComponent == c)
1125 d->cursorComponent = c;
1127 //note that the components are owned by something else
1128 delete d->cursorItem;
1130 d->startCreatingCursor();
1133 emit cursorDelegateChanged();
1136 void QQuickTextInputPrivate::startCreatingCursor()
1138 Q_Q(QQuickTextInput);
1139 if (cursorComponent->isReady()) {
1141 } else if (cursorComponent->isLoading()) {
1142 q->connect(cursorComponent, SIGNAL(statusChanged(int)),
1143 q, SLOT(createCursor()));
1145 qmlInfo(q, cursorComponent->errors()) << QQuickTextInput::tr("Could not load cursor delegate");
1149 void QQuickTextInput::createCursor()
1151 Q_D(QQuickTextInput);
1152 if (!isComponentComplete())
1155 if (d->cursorComponent->isError()) {
1156 qmlInfo(this, d->cursorComponent->errors()) << tr("Could not load cursor delegate");
1160 if (!d->cursorComponent->isReady())
1164 delete d->cursorItem;
1165 QDeclarativeContext *creationContext = d->cursorComponent->creationContext();
1166 QObject *object = d->cursorComponent->create(creationContext ? creationContext : qmlContext(this));
1167 d->cursorItem = qobject_cast<QQuickItem*>(object);
1168 if (!d->cursorItem) {
1170 qmlInfo(this, d->cursorComponent->errors()) << tr("Could not instantiate cursor delegate");
1174 QRectF r = cursorRectangle();
1176 QDeclarative_setParent_noEvent(d->cursorItem, this);
1177 d->cursorItem->setParentItem(this);
1178 d->cursorItem->setPos(r.topLeft());
1179 d->cursorItem->setHeight(r.height());
1183 \qmlmethod rect QtQuick2::TextInput::positionToRectangle(int pos)
1185 This function takes a character position and returns the rectangle that the
1186 cursor would occupy, if it was placed at that character position.
1188 This is similar to setting the cursorPosition, and then querying the cursor
1189 rectangle, but the cursorPosition is not changed.
1191 QRectF QQuickTextInput::positionToRectangle(int pos) const
1193 Q_D(const QQuickTextInput);
1194 if (pos > d->m_cursor)
1195 pos += d->preeditAreaText().length();
1196 QTextLine l = d->m_textLayout.lineAt(0);
1198 ? QRectF(l.cursorToX(pos) - d->hscroll, 0.0, d->m_cursorWidth, l.height())
1203 \qmlmethod int QtQuick2::TextInput::positionAt(real x, real y, CursorPosition position = CursorBetweenCharacters)
1205 This function returns the character position at
1206 x and y pixels from the top left of the textInput. Position 0 is before the
1207 first character, position 1 is after the first character but before the second,
1208 and so on until position text.length, which is after all characters.
1210 This means that for all x values before the first character this function returns 0,
1211 and for all x values after the last character this function returns text.length. If
1212 the y value is above the text the position will be that of the nearest character on
1213 the first line line and if it is below the text the position of the nearest character
1214 on the last line will be returned.
1216 The cursor position type specifies how the cursor position should be resolved.
1219 \o TextInput.CursorBetweenCharacters - Returns the position between characters that is nearest x.
1220 \o TextInput.CursorOnCharacter - Returns the position before the character that is nearest x.
1224 void QQuickTextInput::positionAt(QDeclarativeV8Function *args) const
1226 Q_D(const QQuickTextInput);
1230 QTextLine::CursorPosition position = QTextLine::CursorBetweenCharacters;
1232 if (args->Length() < 1)
1236 v8::Local<v8::Value> arg = (*args)[i];
1237 x = arg->NumberValue();
1239 if (++i < args->Length()) {
1241 y = arg->NumberValue();
1244 if (++i < args->Length()) {
1246 position = QTextLine::CursorPosition(arg->Int32Value());
1249 int pos = d->positionAt(x, y, position);
1250 const int cursor = d->m_cursor;
1252 const int preeditLength = d->preeditAreaText().length();
1253 pos = pos > cursor + preeditLength
1254 ? pos - preeditLength
1257 args->returnValue(v8::Int32::New(pos));
1260 int QQuickTextInputPrivate::positionAt(int x, int y, QTextLine::CursorPosition position) const
1264 QTextLine line = m_textLayout.lineAt(0);
1265 for (int i = 1; i < m_textLayout.lineCount(); ++i) {
1266 QTextLine nextLine = m_textLayout.lineAt(i);
1268 if (y < (line.rect().bottom() + nextLine.y()) / 2)
1272 return line.isValid() ? line.xToCursor(x, position) : 0;
1275 void QQuickTextInput::keyPressEvent(QKeyEvent* ev)
1277 Q_D(QQuickTextInput);
1278 // Don't allow MacOSX up/down support, and we don't allow a completer.
1279 bool ignore = (ev->key() == Qt::Key_Up || ev->key() == Qt::Key_Down) && ev->modifiers() == Qt::NoModifier;
1280 if (!ignore && (d->lastSelectionStart == d->lastSelectionEnd) && (ev->key() == Qt::Key_Right || ev->key() == Qt::Key_Left)) {
1281 // Ignore when moving off the end unless there is a selection,
1282 // because then moving will do something (deselect).
1283 int cursorPosition = d->m_cursor;
1284 if (cursorPosition == 0)
1285 ignore = ev->key() == (d->layoutDirection() == Qt::LeftToRight ? Qt::Key_Left : Qt::Key_Right);
1286 if (cursorPosition == text().length())
1287 ignore = ev->key() == (d->layoutDirection() == Qt::LeftToRight ? Qt::Key_Right : Qt::Key_Left);
1292 d->processKeyEvent(ev);
1294 if (!ev->isAccepted())
1295 QQuickImplicitSizeItem::keyPressEvent(ev);
1298 void QQuickTextInput::inputMethodEvent(QInputMethodEvent *ev)
1300 Q_D(QQuickTextInput);
1301 const bool wasComposing = d->preeditAreaText().length() > 0;
1302 if (d->m_readOnly) {
1305 d->processInputMethodEvent(ev);
1307 if (!ev->isAccepted())
1308 QQuickImplicitSizeItem::inputMethodEvent(ev);
1310 if (wasComposing != (d->m_textLayout.preeditAreaText().length() > 0))
1311 emit inputMethodComposingChanged();
1314 void QQuickTextInput::mouseDoubleClickEvent(QMouseEvent *event)
1316 Q_D(QQuickTextInput);
1318 if (d->selectByMouse && event->button() == Qt::LeftButton) {
1320 int cursor = d->positionAt(event->localPos());
1321 d->selectWordAtPos(cursor);
1322 event->setAccepted(true);
1323 if (!d->hasPendingTripleClick()) {
1324 d->tripleClickStartPoint = event->localPos().toPoint();
1325 d->tripleClickTimer.start();
1328 if (d->sendMouseEventToInputContext(event))
1330 QQuickImplicitSizeItem::mouseDoubleClickEvent(event);
1334 void QQuickTextInput::mousePressEvent(QMouseEvent *event)
1336 Q_D(QQuickTextInput);
1338 d->pressPos = event->localPos();
1340 if (d->focusOnPress) {
1341 bool hadActiveFocus = hasActiveFocus();
1343 // re-open input panel on press if already focused
1344 if (hasActiveFocus() && hadActiveFocus && !d->m_readOnly)
1345 openSoftwareInputPanel();
1347 if (d->selectByMouse) {
1348 setKeepMouseGrab(false);
1349 d->selectPressed = true;
1350 QPoint distanceVector = d->pressPos.toPoint() - d->tripleClickStartPoint;
1351 if (d->hasPendingTripleClick()
1352 && distanceVector.manhattanLength() < qApp->styleHints()->startDragDistance()) {
1353 event->setAccepted(true);
1359 if (d->sendMouseEventToInputContext(event))
1362 bool mark = (event->modifiers() & Qt::ShiftModifier) && d->selectByMouse;
1363 int cursor = d->positionAt(event->localPos());
1364 d->moveCursor(cursor, mark);
1365 event->setAccepted(true);
1368 void QQuickTextInput::mouseMoveEvent(QMouseEvent *event)
1370 Q_D(QQuickTextInput);
1372 if (d->selectPressed) {
1373 if (qAbs(int(event->localPos().x() - d->pressPos.x())) > qApp->styleHints()->startDragDistance())
1374 setKeepMouseGrab(true);
1376 if (d->composeMode()) {
1378 int startPos = d->positionAt(d->pressPos);
1379 int currentPos = d->positionAt(event->localPos());
1380 if (startPos != currentPos)
1381 d->setSelection(startPos, currentPos - startPos);
1383 moveCursorSelection(d->positionAt(event->localPos()), d->mouseSelectionMode);
1385 event->setAccepted(true);
1387 QQuickImplicitSizeItem::mouseMoveEvent(event);
1391 void QQuickTextInput::mouseReleaseEvent(QMouseEvent *event)
1393 Q_D(QQuickTextInput);
1394 if (d->sendMouseEventToInputContext(event))
1396 if (d->selectPressed) {
1397 d->selectPressed = false;
1398 setKeepMouseGrab(false);
1400 #ifndef QT_NO_CLIPBOARD
1401 if (QGuiApplication::clipboard()->supportsSelection()) {
1402 if (event->button() == Qt::LeftButton) {
1403 d->copy(QClipboard::Selection);
1404 } else if (!d->m_readOnly && event->button() == Qt::MidButton) {
1406 d->insert(QGuiApplication::clipboard()->text(QClipboard::Selection));
1410 if (!event->isAccepted())
1411 QQuickImplicitSizeItem::mouseReleaseEvent(event);
1414 bool QQuickTextInputPrivate::sendMouseEventToInputContext(QMouseEvent *event)
1416 #if !defined QT_NO_IM
1417 if (composeMode()) {
1418 int tmp_cursor = positionAt(event->localPos());
1419 int mousePos = tmp_cursor - m_cursor;
1420 if (mousePos >= 0 && mousePos <= m_textLayout.preeditAreaText().length()) {
1421 if (event->type() == QEvent::MouseButtonRelease) {
1422 qApp->inputPanel()->invokeAction(QInputPanel::Click, mousePos);
1435 void QQuickTextInput::mouseUngrabEvent()
1437 Q_D(QQuickTextInput);
1438 d->selectPressed = false;
1439 setKeepMouseGrab(false);
1442 bool QQuickTextInput::event(QEvent* ev)
1444 #ifndef QT_NO_SHORTCUT
1445 Q_D(QQuickTextInput);
1446 if (ev->type() == QEvent::ShortcutOverride) {
1449 QKeyEvent* ke = static_cast<QKeyEvent*>(ev);
1450 if (ke == QKeySequence::Copy
1451 || ke == QKeySequence::Paste
1452 || ke == QKeySequence::Cut
1453 || ke == QKeySequence::Redo
1454 || ke == QKeySequence::Undo
1455 || ke == QKeySequence::MoveToNextWord
1456 || ke == QKeySequence::MoveToPreviousWord
1457 || ke == QKeySequence::MoveToStartOfDocument
1458 || ke == QKeySequence::MoveToEndOfDocument
1459 || ke == QKeySequence::SelectNextWord
1460 || ke == QKeySequence::SelectPreviousWord
1461 || ke == QKeySequence::SelectStartOfLine
1462 || ke == QKeySequence::SelectEndOfLine
1463 || ke == QKeySequence::SelectStartOfBlock
1464 || ke == QKeySequence::SelectEndOfBlock
1465 || ke == QKeySequence::SelectStartOfDocument
1466 || ke == QKeySequence::SelectAll
1467 || ke == QKeySequence::SelectEndOfDocument) {
1469 } else if (ke->modifiers() == Qt::NoModifier || ke->modifiers() == Qt::ShiftModifier
1470 || ke->modifiers() == Qt::KeypadModifier) {
1471 if (ke->key() < Qt::Key_Escape) {
1475 switch (ke->key()) {
1476 case Qt::Key_Delete:
1479 case Qt::Key_Backspace:
1491 return QQuickImplicitSizeItem::event(ev);
1494 void QQuickTextInput::geometryChanged(const QRectF &newGeometry,
1495 const QRectF &oldGeometry)
1497 Q_D(QQuickTextInput);
1498 if (newGeometry.width() != oldGeometry.width())
1500 updateCursorRectangle();
1501 QQuickImplicitSizeItem::geometryChanged(newGeometry, oldGeometry);
1504 void QQuickTextInputPrivate::updateHorizontalScroll()
1506 Q_Q(QQuickTextInput);
1507 QTextLine currentLine = m_textLayout.lineForTextPosition(m_cursor + m_preeditCursor);
1508 const int preeditLength = m_textLayout.preeditAreaText().length();
1509 const int width = qMax(0, qFloor(q->width()));
1510 int widthUsed = currentLine.isValid() ? qRound(currentLine.naturalTextWidth()) : 0;
1511 int previousScroll = hscroll;
1513 if (!autoScroll || widthUsed <= width || m_echoMode == QQuickTextInput::NoEcho) {
1516 Q_ASSERT(currentLine.isValid());
1517 int cix = qRound(currentLine.cursorToX(m_cursor + preeditLength));
1518 if (cix - hscroll >= width) {
1519 // text doesn't fit, cursor is to the right of br (scroll right)
1520 hscroll = cix - width;
1521 } else if (cix - hscroll < 0 && hscroll < widthUsed) {
1522 // text doesn't fit, cursor is to the left of br (scroll left)
1524 } else if (widthUsed - hscroll < width) {
1525 // text doesn't fit, text document is to the left of br; align
1527 hscroll = widthUsed - width;
1529 if (preeditLength > 0) {
1530 // check to ensure long pre-edit text doesn't push the cursor
1532 cix = qRound(currentLine.cursorToX(m_cursor + qMax(0, m_preeditCursor - 1)));
1537 if (previousScroll != hscroll)
1538 textLayoutDirty = true;
1541 void QQuickTextInputPrivate::updateVerticalScroll()
1543 Q_Q(QQuickTextInput);
1544 const int preeditLength = m_textLayout.preeditAreaText().length();
1545 const int height = qMax(0, qFloor(q->height()));
1546 int heightUsed = boundingRect.height();
1547 int previousScroll = vscroll;
1549 if (!autoScroll || heightUsed <= height) {
1550 // text fits in br; use vscroll for alignment
1551 switch (vAlign & ~(Qt::AlignAbsolute|Qt::AlignHorizontal_Mask)) {
1552 case Qt::AlignBottom:
1553 vscroll = heightUsed - height;
1555 case Qt::AlignVCenter:
1556 vscroll = (heightUsed - height) / 2;
1564 QTextLine currentLine = m_textLayout.lineForTextPosition(m_cursor + preeditLength);
1565 QRectF r = currentLine.isValid() ? currentLine.rect() : QRectF();
1566 int top = qFloor(r.top());
1567 int bottom = qCeil(r.bottom());
1569 if (bottom - vscroll >= height) {
1570 // text doesn't fit, cursor is to the below the br (scroll down)
1571 vscroll = bottom - height;
1572 } else if (top - vscroll < 0 && vscroll < heightUsed) {
1573 // text doesn't fit, cursor is above br (scroll up)
1575 } else if (heightUsed - vscroll < height) {
1576 // text doesn't fit, text document is to the left of br; align
1578 vscroll = heightUsed - height;
1580 if (preeditLength > 0) {
1581 // check to ensure long pre-edit text doesn't push the cursor
1583 currentLine = m_textLayout.lineForTextPosition(m_cursor + qMax(0, m_preeditCursor - 1));
1584 top = currentLine.isValid() ? qRound(currentLine.rect().top()) : 0;
1589 if (previousScroll != vscroll)
1590 textLayoutDirty = true;
1593 QSGNode *QQuickTextInput::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data)
1596 Q_D(QQuickTextInput);
1598 QQuickTextNode *node = static_cast<QQuickTextNode *>(oldNode);
1600 node = new QQuickTextNode(QQuickItemPrivate::get(this)->sceneGraphContext());
1603 if (!d->textLayoutDirty) {
1604 QSGSimpleRectNode *cursorNode = node->cursorNode();
1605 if (cursorNode != 0 && !isReadOnly()) {
1606 cursorNode->setRect(cursorRectangle());
1608 if (!d->cursorVisible || (!d->m_blinkStatus && d->m_blinkPeriod > 0)) {
1615 node->deleteContent();
1616 node->setMatrix(QMatrix4x4());
1618 QPoint offset = QPoint(0,0);
1619 QFontMetrics fm = QFontMetrics(d->font);
1620 if (d->autoScroll) {
1621 // the y offset is there to keep the baseline constant in case we have script changes in the text.
1622 offset = -QPoint(d->hscroll, d->vscroll + d->m_ascent - fm.ascent());
1624 offset = -QPoint(d->hscroll, d->vscroll);
1627 if (!d->m_textLayout.text().isEmpty()) {
1628 node->addTextLayout(offset, &d->m_textLayout, d->color,
1629 QQuickText::Normal, QColor(),
1630 d->selectionColor, d->selectedTextColor,
1631 d->selectionStart(),
1632 d->selectionEnd() - 1); // selectionEnd() returns first char after
1636 if (!isReadOnly() && d->cursorItem == 0) {
1637 node->setCursor(cursorRectangle(), d->color);
1638 if (!d->cursorVisible || (!d->m_blinkStatus && d->m_blinkPeriod > 0)) {
1645 d->textLayoutDirty = false;
1651 QVariant QQuickTextInput::inputMethodQuery(Qt::InputMethodQuery property) const
1653 Q_D(const QQuickTextInput);
1656 return QVariant((bool)(flags() & ItemAcceptsInputMethod));
1658 return QVariant((int)inputMethodHints());
1659 case Qt::ImCursorRectangle:
1660 return cursorRectangle();
1663 case Qt::ImCursorPosition:
1664 return QVariant(d->m_cursor);
1665 case Qt::ImSurroundingText:
1666 if (d->m_echoMode == PasswordEchoOnEdit && !d->m_passwordEchoEditing) {
1667 return QVariant(displayText());
1669 return QVariant(d->realText());
1671 case Qt::ImCurrentSelection:
1672 return QVariant(selectedText());
1673 case Qt::ImMaximumTextLength:
1674 return QVariant(maxLength());
1675 case Qt::ImAnchorPosition:
1676 if (d->selectionStart() == d->selectionEnd())
1677 return QVariant(d->m_cursor);
1678 else if (d->selectionStart() == d->m_cursor)
1679 return QVariant(d->selectionEnd());
1681 return QVariant(d->selectionStart());
1688 \qmlmethod void QtQuick2::TextInput::deselect()
1690 Removes active text selection.
1692 void QQuickTextInput::deselect()
1694 Q_D(QQuickTextInput);
1699 \qmlmethod void QtQuick2::TextInput::selectAll()
1701 Causes all text to be selected.
1703 void QQuickTextInput::selectAll()
1705 Q_D(QQuickTextInput);
1706 d->setSelection(0, text().length());
1710 \qmlmethod void QtQuick2::TextInput::isRightToLeft(int start, int end)
1712 Returns true if the natural reading direction of the editor text
1713 found between positions \a start and \a end is right to left.
1715 bool QQuickTextInput::isRightToLeft(int start, int end)
1718 qmlInfo(this) << "isRightToLeft(start, end) called with the end property being smaller than the start.";
1721 return text().mid(start, end - start).isRightToLeft();
1725 #ifndef QT_NO_CLIPBOARD
1727 \qmlmethod QtQuick2::TextInput::cut()
1729 Moves the currently selected text to the system clipboard.
1731 void QQuickTextInput::cut()
1733 Q_D(QQuickTextInput);
1739 \qmlmethod QtQuick2::TextInput::copy()
1741 Copies the currently selected text to the system clipboard.
1743 void QQuickTextInput::copy()
1745 Q_D(QQuickTextInput);
1750 \qmlmethod QtQuick2::TextInput::paste()
1752 Replaces the currently selected text by the contents of the system clipboard.
1754 void QQuickTextInput::paste()
1756 Q_D(QQuickTextInput);
1760 #endif // QT_NO_CLIPBOARD
1763 Undoes the last operation if undo is \l {canUndo}{available}. Deselects any
1764 current selection, and updates the selection start to the current cursor
1768 void QQuickTextInput::undo()
1770 Q_D(QQuickTextInput);
1771 if (!d->m_readOnly) {
1773 d->finishChange(-1, true);
1778 Redoes the last operation if redo is \l {canRedo}{available}.
1781 void QQuickTextInput::redo()
1783 Q_D(QQuickTextInput);
1784 if (!d->m_readOnly) {
1791 \qmlmethod void QtQuick2::TextInput::insert(int position, string text)
1793 Inserts \a text into the TextInput at position.
1796 void QQuickTextInput::insert(int position, const QString &text)
1798 Q_D(QQuickTextInput);
1799 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
1800 if (d->m_echoMode == QQuickTextInput::Password)
1801 d->m_passwordEchoTimer.start(qt_passwordEchoDelay, this);
1804 if (position < 0 || position > d->m_text.length())
1807 const int priorState = d->m_undoState;
1809 QString insertText = text;
1811 if (d->hasSelectedText()) {
1812 d->addCommand(QQuickTextInputPrivate::Command(
1813 QQuickTextInputPrivate::SetSelection, d->m_cursor, 0, d->m_selstart, d->m_selend));
1815 if (d->m_maskData) {
1816 insertText = d->maskString(position, insertText);
1817 for (int i = 0; i < insertText.length(); ++i) {
1818 d->addCommand(QQuickTextInputPrivate::Command(
1819 QQuickTextInputPrivate::DeleteSelection, position + i, d->m_text.at(position + i), -1, -1));
1820 d->addCommand(QQuickTextInputPrivate::Command(
1821 QQuickTextInputPrivate::Insert, position + i, insertText.at(i), -1, -1));
1823 d->m_text.replace(position, insertText.length(), insertText);
1824 if (!insertText.isEmpty())
1825 d->m_textDirty = true;
1826 if (position < d->m_selend && position + insertText.length() > d->m_selstart)
1827 d->m_selDirty = true;
1829 int remaining = d->m_maxLength - d->m_text.length();
1830 if (remaining != 0) {
1831 insertText = insertText.left(remaining);
1832 d->m_text.insert(position, insertText);
1833 for (int i = 0; i < insertText.length(); ++i)
1834 d->addCommand(QQuickTextInputPrivate::Command(
1835 QQuickTextInputPrivate::Insert, position + i, insertText.at(i), -1, -1));
1836 if (d->m_cursor >= position)
1837 d->m_cursor += insertText.length();
1838 if (d->m_selstart >= position)
1839 d->m_selstart += insertText.length();
1840 if (d->m_selend >= position)
1841 d->m_selend += insertText.length();
1842 d->m_textDirty = true;
1843 if (position >= d->m_selstart && position <= d->m_selend)
1844 d->m_selDirty = true;
1848 d->addCommand(QQuickTextInputPrivate::Command(
1849 QQuickTextInputPrivate::SetSelection, d->m_cursor, 0, d->m_selstart, d->m_selend));
1850 d->finishChange(priorState);
1852 if (d->lastSelectionStart != d->lastSelectionEnd) {
1853 if (d->m_selstart != d->lastSelectionStart) {
1854 d->lastSelectionStart = d->m_selstart;
1855 emit selectionStartChanged();
1857 if (d->m_selend != d->lastSelectionEnd) {
1858 d->lastSelectionEnd = d->m_selend;
1859 emit selectionEndChanged();
1865 \qmlmethod string QtQuick2::TextInput::getText(int start, int end)
1867 Removes the section of text that is between the \a start and \a end positions from the TextInput.
1870 void QQuickTextInput::remove(int start, int end)
1872 Q_D(QQuickTextInput);
1874 start = qBound(0, start, d->m_text.length());
1875 end = qBound(0, end, d->m_text.length());
1879 else if (start == end)
1882 if (start < d->m_selend && end > d->m_selstart)
1883 d->m_selDirty = true;
1885 const int priorState = d->m_undoState;
1887 d->addCommand(QQuickTextInputPrivate::Command(
1888 QQuickTextInputPrivate::SetSelection, d->m_cursor, 0, d->m_selstart, d->m_selend));
1890 if (start <= d->m_cursor && d->m_cursor < end) {
1891 // cursor is within the selection. Split up the commands
1892 // to be able to restore the correct cursor position
1893 for (int i = d->m_cursor; i >= start; --i) {
1894 d->addCommand(QQuickTextInputPrivate::Command(
1895 QQuickTextInputPrivate::DeleteSelection, i, d->m_text.at(i), -1, 1));
1897 for (int i = end - 1; i > d->m_cursor; --i) {
1898 d->addCommand(QQuickTextInputPrivate::Command(
1899 QQuickTextInputPrivate::DeleteSelection, i - d->m_cursor + start - 1, d->m_text.at(i), -1, -1));
1902 for (int i = end - 1; i >= start; --i) {
1903 d->addCommand(QQuickTextInputPrivate::Command(
1904 QQuickTextInputPrivate::RemoveSelection, i, d->m_text.at(i), -1, -1));
1907 if (d->m_maskData) {
1908 d->m_text.replace(start, end - start, d->clearString(start, end - start));
1909 for (int i = 0; i < end - start; ++i) {
1910 d->addCommand(QQuickTextInputPrivate::Command(
1911 QQuickTextInputPrivate::Insert, start + i, d->m_text.at(start + i), -1, -1));
1914 d->m_text.remove(start, end - start);
1916 if (d->m_cursor > start)
1917 d->m_cursor -= qMin(d->m_cursor, end) - start;
1918 if (d->m_selstart > start)
1919 d->m_selstart -= qMin(d->m_selstart, end) - start;
1920 if (d->m_selend > end)
1921 d->m_selend -= qMin(d->m_selend, end) - start;
1923 d->addCommand(QQuickTextInputPrivate::Command(
1924 QQuickTextInputPrivate::SetSelection, d->m_cursor, 0, d->m_selstart, d->m_selend));
1926 d->m_textDirty = true;
1927 d->finishChange(priorState);
1929 if (d->lastSelectionStart != d->lastSelectionEnd) {
1930 if (d->m_selstart != d->lastSelectionStart) {
1931 d->lastSelectionStart = d->m_selstart;
1932 emit selectionStartChanged();
1934 if (d->m_selend != d->lastSelectionEnd) {
1935 d->lastSelectionEnd = d->m_selend;
1936 emit selectionEndChanged();
1943 \qmlmethod void QtQuick2::TextInput::selectWord()
1945 Causes the word closest to the current cursor position to be selected.
1947 void QQuickTextInput::selectWord()
1949 Q_D(QQuickTextInput);
1950 d->selectWordAtPos(d->m_cursor);
1954 \qmlproperty bool QtQuick2::TextInput::smooth
1956 This property holds whether the text is smoothly scaled or transformed.
1958 Smooth filtering gives better visual quality, but is slower. If
1959 the item is displayed at its natural size, this property has no visual or
1962 \note Generally scaling artifacts are only visible if the item is stationary on
1963 the screen. A common pattern when animating an item is to disable smooth
1964 filtering at the beginning of the animation and reenable it at the conclusion.
1968 \qmlproperty string QtQuick2::TextInput::passwordCharacter
1970 This is the character displayed when echoMode is set to Password or
1971 PasswordEchoOnEdit. By default it is an asterisk.
1973 If this property is set to a string with more than one character,
1974 the first character is used. If the string is empty, the value
1975 is ignored and the property is not set.
1977 QString QQuickTextInput::passwordCharacter() const
1979 Q_D(const QQuickTextInput);
1980 return QString(d->m_passwordCharacter);
1983 void QQuickTextInput::setPasswordCharacter(const QString &str)
1985 Q_D(QQuickTextInput);
1986 if (str.length() < 1)
1988 d->m_passwordCharacter = str.constData()[0];
1989 if (d->m_echoMode == Password || d->m_echoMode == PasswordEchoOnEdit)
1990 d->updateDisplayText();
1991 emit passwordCharacterChanged();
1995 \qmlproperty string QtQuick2::TextInput::displayText
1997 This is the text displayed in the TextInput.
1999 If \l echoMode is set to TextInput::Normal, this holds the
2000 same value as the TextInput::text property. Otherwise,
2001 this property holds the text visible to the user, while
2002 the \l text property holds the actual entered text.
2004 QString QQuickTextInput::displayText() const
2006 Q_D(const QQuickTextInput);
2007 return d->m_textLayout.text();
2011 \qmlproperty bool QtQuick2::TextInput::selectByMouse
2015 If true, the user can use the mouse to select text in some
2016 platform-specific way. Note that for some platforms this may
2017 not be an appropriate interaction (eg. may conflict with how
2018 the text needs to behave inside a Flickable.
2020 bool QQuickTextInput::selectByMouse() const
2022 Q_D(const QQuickTextInput);
2023 return d->selectByMouse;
2026 void QQuickTextInput::setSelectByMouse(bool on)
2028 Q_D(QQuickTextInput);
2029 if (d->selectByMouse != on) {
2030 d->selectByMouse = on;
2031 emit selectByMouseChanged(on);
2036 \qmlproperty enum QtQuick2::TextInput::mouseSelectionMode
2038 Specifies how text should be selected using a mouse.
2041 \o TextInput.SelectCharacters - The selection is updated with individual characters. (Default)
2042 \o TextInput.SelectWords - The selection is updated with whole words.
2045 This property only applies when \l selectByMouse is true.
2048 QQuickTextInput::SelectionMode QQuickTextInput::mouseSelectionMode() const
2050 Q_D(const QQuickTextInput);
2051 return d->mouseSelectionMode;
2054 void QQuickTextInput::setMouseSelectionMode(SelectionMode mode)
2056 Q_D(QQuickTextInput);
2057 if (d->mouseSelectionMode != mode) {
2058 d->mouseSelectionMode = mode;
2059 emit mouseSelectionModeChanged(mode);
2064 \qmlproperty bool QtQuick2::TextInput::canPaste
2066 Returns true if the TextInput is writable and the content of the clipboard is
2067 suitable for pasting into the TextEdit.
2069 bool QQuickTextInput::canPaste() const
2071 Q_D(const QQuickTextInput);
2072 if (!d->canPasteValid) {
2073 if (const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData())
2074 const_cast<QQuickTextInputPrivate *>(d)->canPaste = !d->m_readOnly && mimeData->hasText();
2075 const_cast<QQuickTextInputPrivate *>(d)->canPasteValid = true;
2081 \qmlproperty bool QtQuick2::TextInput::canUndo
2083 Returns true if the TextInput is writable and there are previous operations
2087 bool QQuickTextInput::canUndo() const
2089 Q_D(const QQuickTextInput);
2094 \qmlproperty bool QtQuick2::TextInput::canRedo
2096 Returns true if the TextInput is writable and there are \l {undo}{undone}
2097 operations that can be redone.
2100 bool QQuickTextInput::canRedo() const
2102 Q_D(const QQuickTextInput);
2106 void QQuickTextInput::moveCursorSelection(int position)
2108 Q_D(QQuickTextInput);
2109 d->moveCursor(position, true);
2113 \qmlmethod void QtQuick2::TextInput::moveCursorSelection(int position, SelectionMode mode = TextInput.SelectCharacters)
2115 Moves the cursor to \a position and updates the selection according to the optional \a mode
2116 parameter. (To only move the cursor, set the \l cursorPosition property.)
2118 When this method is called it additionally sets either the
2119 selectionStart or the selectionEnd (whichever was at the previous cursor position)
2120 to the specified position. This allows you to easily extend and contract the selected
2123 The selection mode specifies whether the selection is updated on a per character or a per word
2124 basis. If not specified the selection mode will default to TextInput.SelectCharacters.
2127 \o TextEdit.SelectCharacters - Sets either the selectionStart or selectionEnd (whichever was at
2128 the previous cursor position) to the specified position.
2129 \o TextEdit.SelectWords - Sets the selectionStart and selectionEnd to include all
2130 words between the specified position and the previous cursor position. Words partially in the
2134 For example, take this sequence of calls:
2138 moveCursorSelection(9, TextInput.SelectCharacters)
2139 moveCursorSelection(7, TextInput.SelectCharacters)
2142 This moves the cursor to position 5, extend the selection end from 5 to 9
2143 and then retract the selection end from 9 to 7, leaving the text from position 5 to 7
2144 selected (the 6th and 7th characters).
2146 The same sequence with TextInput.SelectWords will extend the selection start to a word boundary
2147 before or on position 5 and extend the selection end to a word boundary on or past position 9.
2149 void QQuickTextInput::moveCursorSelection(int pos, SelectionMode mode)
2151 Q_D(QQuickTextInput);
2153 if (mode == SelectCharacters) {
2154 d->moveCursor(pos, true);
2155 } else if (pos != d->m_cursor){
2156 const int cursor = d->m_cursor;
2158 if (!d->hasSelectedText())
2159 anchor = d->m_cursor;
2160 else if (d->selectionStart() == d->m_cursor)
2161 anchor = d->selectionEnd();
2163 anchor = d->selectionStart();
2165 if (anchor < pos || (anchor == pos && cursor < pos)) {
2166 const QString text = this->text();
2167 QTextBoundaryFinder finder(QTextBoundaryFinder::Word, text);
2168 finder.setPosition(anchor);
2170 const QTextBoundaryFinder::BoundaryReasons reasons = finder.boundaryReasons();
2171 if (anchor < text.length() && (!(reasons & QTextBoundaryFinder::StartWord)
2172 || ((reasons & QTextBoundaryFinder::EndWord) && anchor > cursor))) {
2173 finder.toPreviousBoundary();
2175 anchor = finder.position() != -1 ? finder.position() : 0;
2177 finder.setPosition(pos);
2178 if (pos > 0 && !finder.boundaryReasons())
2179 finder.toNextBoundary();
2180 const int cursor = finder.position() != -1 ? finder.position() : text.length();
2182 d->setSelection(anchor, cursor - anchor);
2183 } else if (anchor > pos || (anchor == pos && cursor > pos)) {
2184 const QString text = this->text();
2185 QTextBoundaryFinder finder(QTextBoundaryFinder::Word, text);
2186 finder.setPosition(anchor);
2188 const QTextBoundaryFinder::BoundaryReasons reasons = finder.boundaryReasons();
2189 if (anchor > 0 && (!(reasons & QTextBoundaryFinder::EndWord)
2190 || ((reasons & QTextBoundaryFinder::StartWord) && anchor < cursor))) {
2191 finder.toNextBoundary();
2194 anchor = finder.position() != -1 ? finder.position() : text.length();
2196 finder.setPosition(pos);
2197 if (pos < text.length() && !finder.boundaryReasons())
2198 finder.toPreviousBoundary();
2199 const int cursor = finder.position() != -1 ? finder.position() : 0;
2201 d->setSelection(anchor, cursor - anchor);
2207 \qmlmethod void QtQuick2::TextInput::openSoftwareInputPanel()
2209 Opens software input panels like virtual keyboards for typing, useful for
2210 customizing when you want the input keyboard to be shown and hidden in
2213 By default the opening of input panels follows the platform style. Input panels are
2214 always closed if no editor has active focus.
2216 You can disable the automatic behavior by setting the property \c activeFocusOnPress to false
2217 and use functions openSoftwareInputPanel() and closeSoftwareInputPanel() to implement
2218 the behavior you want.
2220 Only relevant on platforms, which provide virtual keyboards.
2226 text: "Hello world!"
2227 activeFocusOnPress: false
2229 anchors.fill: parent
2231 if (!textInput.activeFocus) {
2232 textInput.forceActiveFocus()
2233 textInput.openSoftwareInputPanel();
2235 textInput.focus = false;
2238 onPressAndHold: textInput.closeSoftwareInputPanel();
2243 void QQuickTextInput::openSoftwareInputPanel()
2246 qGuiApp->inputPanel()->show();
2250 \qmlmethod void QtQuick2::TextInput::closeSoftwareInputPanel()
2252 Closes a software input panel like a virtual keyboard shown on the screen, useful
2253 for customizing when you want the input keyboard to be shown and hidden in
2256 By default the opening of input panels follows the platform style. Input panels are
2257 always closed if no editor has active focus.
2259 You can disable the automatic behavior by setting the property \c activeFocusOnPress to false
2260 and use functions openSoftwareInputPanel() and closeSoftwareInputPanel() to implement
2261 the behavior you want.
2263 Only relevant on platforms, which provide virtual keyboards.
2269 text: "Hello world!"
2270 activeFocusOnPress: false
2272 anchors.fill: parent
2274 if (!textInput.activeFocus) {
2275 textInput.forceActiveFocus();
2276 textInput.openSoftwareInputPanel();
2278 textInput.focus = false;
2281 onPressAndHold: textInput.closeSoftwareInputPanel();
2286 void QQuickTextInput::closeSoftwareInputPanel()
2289 qGuiApp->inputPanel()->hide();
2292 void QQuickTextInput::focusInEvent(QFocusEvent *event)
2294 Q_D(const QQuickTextInput);
2295 if (d->focusOnPress && !d->m_readOnly)
2296 openSoftwareInputPanel();
2297 QQuickImplicitSizeItem::focusInEvent(event);
2300 void QQuickTextInput::itemChange(ItemChange change, const ItemChangeData &value)
2302 Q_D(QQuickTextInput);
2303 if (change == ItemActiveFocusHasChanged) {
2304 bool hasFocus = value.boolValue;
2305 d->focused = hasFocus;
2306 setCursorVisible(hasFocus); // ### refactor: && d->canvas && d->canvas->hasFocus()
2307 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
2308 if (!hasFocus && (d->m_passwordEchoEditing || d->m_passwordEchoTimer.isActive())) {
2310 if (!hasFocus && d->m_passwordEchoEditing) {
2312 d->updatePasswordEchoEditing(false);//QQuickTextInputPrivate sets it on key events, but doesn't deal with focus events
2320 QQuickItem::itemChange(change, value);
2324 \qmlproperty bool QtQuick2::TextInput::inputMethodComposing
2327 This property holds whether the TextInput has partial text input from an
2330 While it is composing an input method may rely on mouse or key events from
2331 the TextInput to edit or commit the partial text. This property can be
2332 used to determine when to disable events handlers that may interfere with
2333 the correct operation of an input method.
2335 bool QQuickTextInput::isInputMethodComposing() const
2337 Q_D(const QQuickTextInput);
2338 return d->preeditAreaText().length() > 0;
2341 void QQuickTextInputPrivate::init()
2343 Q_Q(QQuickTextInput);
2344 q->setSmooth(smooth);
2345 q->setAcceptedMouseButtons(Qt::LeftButton);
2346 q->setFlag(QQuickItem::ItemAcceptsInputMethod);
2347 q->setFlag(QQuickItem::ItemHasContents);
2348 #ifndef QT_NO_CLIPBOARD
2349 q->connect(QGuiApplication::clipboard(), SIGNAL(dataChanged()),
2350 q, SLOT(q_canPasteChanged()));
2351 #endif // QT_NO_CLIPBOARD
2353 lastSelectionStart = 0;
2354 lastSelectionEnd = 0;
2355 selectedTextColor = m_palette.color(QPalette::HighlightedText);
2356 selectionColor = m_palette.color(QPalette::Highlight);
2357 determineHorizontalAlignment();
2359 if (!qmlDisableDistanceField()) {
2360 QTextOption option = m_textLayout.textOption();
2361 option.setUseDesignMetrics(true);
2362 m_textLayout.setTextOption(option);
2366 void QQuickTextInput::updateCursorRectangle()
2368 Q_D(QQuickTextInput);
2369 if (!isComponentComplete())
2372 d->updateHorizontalScroll();
2373 d->updateVerticalScroll();
2375 emit cursorRectangleChanged();
2376 if (d->cursorItem) {
2377 QRectF r = cursorRectangle();
2378 d->cursorItem->setPos(r.topLeft());
2379 d->cursorItem->setHeight(r.height());
2383 void QQuickTextInput::selectionChanged()
2385 Q_D(QQuickTextInput);
2386 d->textLayoutDirty = true; //TODO: Only update rect in selection
2388 emit selectedTextChanged();
2390 if (d->lastSelectionStart != d->selectionStart()) {
2391 d->lastSelectionStart = d->selectionStart();
2392 if (d->lastSelectionStart == -1)
2393 d->lastSelectionStart = d->m_cursor;
2394 emit selectionStartChanged();
2396 if (d->lastSelectionEnd != d->selectionEnd()) {
2397 d->lastSelectionEnd = d->selectionEnd();
2398 if (d->lastSelectionEnd == -1)
2399 d->lastSelectionEnd = d->m_cursor;
2400 emit selectionEndChanged();
2404 void QQuickTextInputPrivate::showCursor()
2406 if (textNode != 0 && textNode->cursorNode() != 0)
2407 textNode->cursorNode()->setColor(color);
2410 void QQuickTextInputPrivate::hideCursor()
2412 if (textNode != 0 && textNode->cursorNode() != 0)
2413 textNode->cursorNode()->setColor(QColor(0, 0, 0, 0));
2416 QRectF QQuickTextInput::boundingRect() const
2418 Q_D(const QQuickTextInput);
2420 int cursorWidth = d->cursorItem ? d->cursorItem->width() : d->m_cursorWidth;
2422 // Could include font max left/right bearings to either side of rectangle.
2423 QRectF r = QQuickImplicitSizeItem::boundingRect();
2424 r.setRight(r.right() + cursorWidth);
2428 void QQuickTextInput::q_canPasteChanged()
2430 Q_D(QQuickTextInput);
2431 bool old = d->canPaste;
2432 #ifndef QT_NO_CLIPBOARD
2433 if (const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData())
2434 d->canPaste = !d->m_readOnly && mimeData->hasText();
2436 d->canPaste = false;
2439 bool changed = d->canPaste != old || !d->canPasteValid;
2440 d->canPasteValid = true;
2442 emit canPasteChanged();
2446 // ### these should come from QStyleHints
2447 const int textCursorWidth = 1;
2448 const bool fullWidthSelection = true;
2453 Updates the display text based of the current edit text
2454 If the text has changed will emit displayTextChanged()
2456 void QQuickTextInputPrivate::updateDisplayText(bool forceUpdate)
2458 QString orig = m_textLayout.text();
2460 if (m_echoMode == QQuickTextInput::NoEcho)
2461 str = QString::fromLatin1("");
2465 if (m_echoMode == QQuickTextInput::Password) {
2466 str.fill(m_passwordCharacter);
2467 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
2468 if (m_passwordEchoTimer.isActive() && m_cursor > 0 && m_cursor <= m_text.length()) {
2469 int cursor = m_cursor - 1;
2470 QChar uc = m_text.at(cursor);
2472 if (cursor > 0 && uc.unicode() >= 0xdc00 && uc.unicode() < 0xe000) {
2473 // second half of a surrogate, check if we have the first half as well,
2474 // if yes restore both at once
2475 uc = m_text.at(cursor - 1);
2476 if (uc.unicode() >= 0xd800 && uc.unicode() < 0xdc00)
2477 str[cursor - 1] = uc;
2481 } else if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit && !m_passwordEchoEditing) {
2482 str.fill(m_passwordCharacter);
2485 // replace certain non-printable characters with spaces (to avoid
2486 // drawing boxes when using fonts that don't have glyphs for such
2488 QChar* uc = str.data();
2489 for (int i = 0; i < (int)str.length(); ++i) {
2490 if ((uc[i] < 0x20 && uc[i] != 0x09)
2491 || uc[i] == QChar::LineSeparator
2492 || uc[i] == QChar::ParagraphSeparator
2493 || uc[i] == QChar::ObjectReplacementCharacter)
2494 uc[i] = QChar(0x0020);
2497 if (str != orig || forceUpdate) {
2498 m_textLayout.setText(str);
2499 updateLayout(); // polish?
2500 emit q_func()->displayTextChanged();
2504 void QQuickTextInputPrivate::updateLayout()
2506 Q_Q(QQuickTextInput);
2508 if (!q->isComponentComplete())
2511 QTextOption option = m_textLayout.textOption();
2512 option.setTextDirection(m_layoutDirection);
2513 option.setFlags(QTextOption::IncludeTrailingSpaces);
2514 option.setWrapMode(QTextOption::WrapMode(wrapMode));
2515 option.setAlignment(Qt::Alignment(q->effectiveHAlign()));
2516 m_textLayout.setTextOption(option);
2517 m_textLayout.setFont(font);
2519 boundingRect = QRectF();
2520 m_textLayout.beginLayout();
2521 QTextLine line = m_textLayout.createLine();
2522 qreal lineWidth = q->widthValid() ? q->width() : INT_MAX;
2524 QTextLine firstLine = line;
2526 line.setLineWidth(lineWidth);
2527 line.setPosition(QPointF(line.position().x(), height));
2528 boundingRect = boundingRect.united(line.naturalTextRect());
2530 height += line.height();
2531 line = m_textLayout.createLine();
2532 } while (line.isValid());
2533 m_textLayout.endLayout();
2535 option.setWrapMode(QTextOption::NoWrap);
2536 m_textLayout.setTextOption(option);
2538 m_ascent = qRound(firstLine.ascent());
2539 textLayoutDirty = true;
2542 q->setImplicitSize(qCeil(boundingRect.width()), qCeil(boundingRect.height()));
2546 #ifndef QT_NO_CLIPBOARD
2550 Copies the currently selected text into the clipboard using the given
2553 \note If the echo mode is set to a mode other than Normal then copy
2554 will not work. This is to prevent using copy as a method of bypassing
2555 password features of the line control.
2557 void QQuickTextInputPrivate::copy(QClipboard::Mode mode) const
2559 QString t = selectedText();
2560 if (!t.isEmpty() && m_echoMode == QQuickTextInput::Normal) {
2561 QGuiApplication::clipboard()->setText(t, mode);
2568 Inserts the text stored in the application clipboard into the line
2573 void QQuickTextInputPrivate::paste(QClipboard::Mode clipboardMode)
2575 QString clip = QGuiApplication::clipboard()->text(clipboardMode);
2576 if (!clip.isEmpty() || hasSelectedText()) {
2577 separate(); //make it a separate undo/redo command
2583 #endif // !QT_NO_CLIPBOARD
2588 Exits preedit mode and commits parts marked as tentative commit
2590 void QQuickTextInputPrivate::commitPreedit()
2595 qApp->inputPanel()->reset();
2597 if (!m_tentativeCommit.isEmpty()) {
2598 internalInsert(m_tentativeCommit);
2599 m_tentativeCommit.clear();
2600 finishChange(-1, true/*not used, not documented*/, false);
2603 m_preeditCursor = 0;
2604 m_textLayout.setPreeditArea(-1, QString());
2605 m_textLayout.clearAdditionalFormats();
2612 Handles the behavior for the backspace key or function.
2613 Removes the current selection if there is a selection, otherwise
2614 removes the character prior to the cursor position.
2618 void QQuickTextInputPrivate::backspace()
2620 int priorState = m_undoState;
2621 if (hasSelectedText()) {
2622 removeSelectedText();
2623 } else if (m_cursor) {
2626 m_cursor = prevMaskBlank(m_cursor);
2627 QChar uc = m_text.at(m_cursor);
2628 if (m_cursor > 0 && uc.unicode() >= 0xdc00 && uc.unicode() < 0xe000) {
2629 // second half of a surrogate, check if we have the first half as well,
2630 // if yes delete both at once
2631 uc = m_text.at(m_cursor - 1);
2632 if (uc.unicode() >= 0xd800 && uc.unicode() < 0xdc00) {
2633 internalDelete(true);
2637 internalDelete(true);
2639 finishChange(priorState);
2645 Handles the behavior for the delete key or function.
2646 Removes the current selection if there is a selection, otherwise
2647 removes the character after the cursor position.
2651 void QQuickTextInputPrivate::del()
2653 int priorState = m_undoState;
2654 if (hasSelectedText()) {
2655 removeSelectedText();
2657 int n = m_textLayout.nextCursorPosition(m_cursor) - m_cursor;
2661 finishChange(priorState);
2667 Inserts the given \a newText at the current cursor position.
2668 If there is any selected text it is removed prior to insertion of
2671 void QQuickTextInputPrivate::insert(const QString &newText)
2673 int priorState = m_undoState;
2674 removeSelectedText();
2675 internalInsert(newText);
2676 finishChange(priorState);
2682 Clears the line control text.
2684 void QQuickTextInputPrivate::clear()
2686 int priorState = m_undoState;
2688 m_selend = m_text.length();
2689 removeSelectedText();
2691 finishChange(priorState, /*update*/false, /*edited*/false);
2697 Sets \a length characters from the given \a start position as selected.
2698 The given \a start position must be within the current text for
2699 the line control. If \a length characters cannot be selected, then
2700 the selection will extend to the end of the current text.
2702 void QQuickTextInputPrivate::setSelection(int start, int length)
2704 Q_Q(QQuickTextInput);
2707 if (start < 0 || start > (int)m_text.length()){
2708 qWarning("QQuickTextInputPrivate::setSelection: Invalid start position");
2713 if (start == m_selstart && start + length == m_selend && m_cursor == m_selend)
2716 m_selend = qMin(start + length, (int)m_text.length());
2717 m_cursor = m_selend;
2718 } else if (length < 0){
2719 if (start == m_selend && start + length == m_selstart && m_cursor == m_selstart)
2721 m_selstart = qMax(start + length, 0);
2723 m_cursor = m_selstart;
2724 } else if (m_selstart != m_selend) {
2730 emitCursorPositionChanged();
2733 emit q->selectionChanged();
2734 emitCursorPositionChanged();
2735 qApp->inputPanel()->update(Qt::ImCursorRectangle | Qt::ImAnchorPosition
2736 | Qt::ImCursorPosition | Qt::ImCurrentSelection);
2742 Initializes the line control with a starting text value of \a txt.
2744 void QQuickTextInputPrivate::init(const QString &txt)
2748 updateDisplayText();
2749 m_cursor = m_text.length();
2755 Sets the password echo editing to \a editing. If password echo editing
2756 is true, then the text of the password is displayed even if the echo
2757 mode is set to QLineEdit::PasswordEchoOnEdit. Password echoing editing
2758 does not affect other echo modes.
2760 void QQuickTextInputPrivate::updatePasswordEchoEditing(bool editing)
2762 cancelPasswordEchoTimer();
2763 m_passwordEchoEditing = editing;
2764 updateDisplayText();
2770 Fixes the current text so that it is valid given any set validators.
2772 Returns true if the text was changed. Otherwise returns false.
2774 bool QQuickTextInputPrivate::fixup() // this function assumes that validate currently returns != Acceptable
2776 #ifndef QT_NO_VALIDATOR
2778 QString textCopy = m_text;
2779 int cursorCopy = m_cursor;
2780 m_validator->fixup(textCopy);
2781 if (m_validator->validate(textCopy, cursorCopy) == QValidator::Acceptable) {
2782 if (textCopy != m_text || cursorCopy != m_cursor)
2783 internalSetText(textCopy, cursorCopy);
2794 Moves the cursor to the given position \a pos. If \a mark is true will
2795 adjust the currently selected text.
2797 void QQuickTextInputPrivate::moveCursor(int pos, bool mark)
2799 Q_Q(QQuickTextInput);
2802 if (pos != m_cursor) {
2805 pos = pos > m_cursor ? nextMaskBlank(pos) : prevMaskBlank(pos);
2809 if (m_selend > m_selstart && m_cursor == m_selstart)
2811 else if (m_selend > m_selstart && m_cursor == m_selend)
2812 anchor = m_selstart;
2815 m_selstart = qMin(anchor, pos);
2816 m_selend = qMax(anchor, pos);
2821 if (mark || m_selDirty) {
2823 emit q->selectionChanged();
2825 emitCursorPositionChanged();
2826 q->updateMicroFocus();
2832 Applies the given input method event \a event to the text of the line
2835 void QQuickTextInputPrivate::processInputMethodEvent(QInputMethodEvent *event)
2837 Q_Q(QQuickTextInput);
2839 int priorState = -1;
2840 bool isGettingInput = !event->commitString().isEmpty()
2841 || event->preeditString() != preeditAreaText()
2842 || event->replacementLength() > 0;
2843 bool cursorPositionChanged = false;
2844 bool selectionChange = false;
2845 m_preeditDirty = event->preeditString() != preeditAreaText();
2847 if (isGettingInput) {
2848 // If any text is being input, remove selected text.
2849 priorState = m_undoState;
2850 if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit && !m_passwordEchoEditing) {
2851 updatePasswordEchoEditing(true);
2853 m_selend = m_text.length();
2855 removeSelectedText();
2858 int c = m_cursor; // cursor position after insertion of commit string
2859 if (event->replacementStart() <= 0)
2860 c += event->commitString().length() - qMin(-event->replacementStart(), event->replacementLength());
2862 m_cursor += event->replacementStart();
2866 // insert commit string
2867 if (event->replacementLength()) {
2868 m_selstart = m_cursor;
2869 m_selend = m_selstart + event->replacementLength();
2870 m_selend = qMin(m_selend, m_text.length());
2871 removeSelectedText();
2873 if (!event->commitString().isEmpty()) {
2874 internalInsert(event->commitString());
2875 cursorPositionChanged = true;
2878 m_cursor = qBound(0, c, m_text.length());
2880 for (int i = 0; i < event->attributes().size(); ++i) {
2881 const QInputMethodEvent::Attribute &a = event->attributes().at(i);
2882 if (a.type == QInputMethodEvent::Selection) {
2883 m_cursor = qBound(0, a.start + a.length, m_text.length());
2885 m_selstart = qMax(0, qMin(a.start, m_text.length()));
2886 m_selend = m_cursor;
2887 if (m_selend < m_selstart) {
2888 qSwap(m_selstart, m_selend);
2890 selectionChange = true;
2892 m_selstart = m_selend = 0;
2894 cursorPositionChanged = true;
2898 m_textLayout.setPreeditArea(m_cursor, event->preeditString());
2900 const int oldPreeditCursor = m_preeditCursor;
2901 m_preeditCursor = event->preeditString().length();
2902 m_hideCursor = false;
2903 QList<QTextLayout::FormatRange> formats;
2904 for (int i = 0; i < event->attributes().size(); ++i) {
2905 const QInputMethodEvent::Attribute &a = event->attributes().at(i);
2906 if (a.type == QInputMethodEvent::Cursor) {
2907 m_preeditCursor = a.start;
2908 m_hideCursor = !a.length;
2909 } else if (a.type == QInputMethodEvent::TextFormat) {
2910 QTextCharFormat f = qvariant_cast<QTextFormat>(a.value).toCharFormat();
2912 QTextLayout::FormatRange o;
2913 o.start = a.start + m_cursor;
2914 o.length = a.length;
2920 m_textLayout.setAdditionalFormats(formats);
2922 updateDisplayText(/*force*/ true);
2923 if (cursorPositionChanged) {
2924 emitCursorPositionChanged();
2925 } else if (m_preeditCursor != oldPreeditCursor) {
2926 q->updateCursorRectangle();
2927 qApp->inputPanel()->update(Qt::ImCursorRectangle);
2930 bool tentativeCommitChanged = m_tentativeCommit != event->tentativeCommitString();
2932 if (tentativeCommitChanged) {
2934 m_tentativeCommit = event->tentativeCommitString();
2937 if (isGettingInput || tentativeCommitChanged)
2938 finishChange(priorState);
2940 if (selectionChange) {
2941 emit q->selectionChanged();
2942 qApp->inputPanel()->update(Qt::ImCursorRectangle | Qt::ImAnchorPosition
2943 | Qt::ImCursorPosition | Qt::ImCurrentSelection);
2950 Sets the selection to cover the word at the given cursor position.
2951 The word boundaries are defined by the behavior of QTextLayout::SkipWords
2954 void QQuickTextInputPrivate::selectWordAtPos(int cursor)
2956 int next = cursor + 1;
2959 int c = m_textLayout.previousCursorPosition(next, QTextLayout::SkipWords);
2960 moveCursor(c, false);
2961 // ## text layout should support end of words.
2962 int end = m_textLayout.nextCursorPosition(c, QTextLayout::SkipWords);
2963 while (end > cursor && m_text[end-1].isSpace())
2965 moveCursor(end, true);
2971 Completes a change to the line control text. If the change is not valid
2972 will undo the line control state back to the given \a validateFromState.
2974 If \a edited is true and the change is valid, will emit textEdited() in
2975 addition to textChanged(). Otherwise only emits textChanged() on a valid
2978 The \a update value is currently unused.
2980 bool QQuickTextInputPrivate::finishChange(int validateFromState, bool update, bool /*edited*/)
2982 Q_Q(QQuickTextInput);
2985 bool notifyInputPanel = m_textDirty || m_selDirty;
2989 bool wasValidInput = m_validInput;
2990 m_validInput = true;
2991 #ifndef QT_NO_VALIDATOR
2993 QString textCopy = m_text;
2994 int cursorCopy = m_cursor;
2995 m_validInput = (m_validator->validate(textCopy, cursorCopy) != QValidator::Invalid);
2997 if (m_text != textCopy) {
2998 internalSetText(textCopy, cursorCopy);
3001 m_cursor = cursorCopy;
3003 if (!m_tentativeCommit.isEmpty()) {
3004 textCopy.insert(m_cursor, m_tentativeCommit);
3005 bool validInput = m_validator->validate(textCopy, cursorCopy) != QValidator::Invalid;
3007 m_tentativeCommit.clear();
3010 m_tentativeCommit.clear();
3014 if (validateFromState >= 0 && wasValidInput && !m_validInput) {
3015 if (m_transactions.count())
3017 internalUndo(validateFromState);
3018 m_history.resize(m_undoState);
3019 if (m_modifiedState > m_undoState)
3020 m_modifiedState = -1;
3021 m_validInput = true;
3022 m_textDirty = false;
3026 m_textDirty = false;
3027 m_preeditDirty = false;
3028 determineHorizontalAlignment();
3029 emit q->textChanged();
3032 updateDisplayText();
3034 if (m_validInput != wasValidInput)
3035 emit q->acceptableInputChanged();
3037 if (m_preeditDirty) {
3038 m_preeditDirty = false;
3039 determineHorizontalAlignment();
3044 emit q->selectionChanged();
3047 notifyInputPanel |= (m_cursor == m_lastCursorPos);
3048 if (notifyInputPanel)
3049 q->updateMicroFocus();
3050 emitUndoRedoChanged();
3051 emitCursorPositionChanged();
3059 An internal function for setting the text of the line control.
3061 void QQuickTextInputPrivate::internalSetText(const QString &txt, int pos, bool edited)
3063 Q_Q(QQuickTextInput);
3065 QString oldText = m_text;
3067 m_text = maskString(0, txt, true);
3068 m_text += clearString(m_text.length(), m_maxLength - m_text.length());
3070 m_text = txt.isEmpty() ? txt : txt.left(m_maxLength);
3073 m_modifiedState = m_undoState = 0;
3074 m_cursor = (pos < 0 || pos > m_text.length()) ? m_text.length() : pos;
3075 m_textDirty = (oldText != m_text);
3077 bool changed = finishChange(-1, true, edited);
3078 #ifdef QT_NO_ACCESSIBILITY
3082 QAccessible::updateAccessibility(q, 0, QAccessible::TextUpdated);
3090 Adds the given \a command to the undo history
3091 of the line control. Does not apply the command.
3093 void QQuickTextInputPrivate::addCommand(const Command &cmd)
3095 if (m_separator && m_undoState && m_history[m_undoState - 1].type != Separator) {
3096 m_history.resize(m_undoState + 2);
3097 m_history[m_undoState++] = Command(Separator, m_cursor, 0, m_selstart, m_selend);
3099 m_history.resize(m_undoState + 1);
3101 m_separator = false;
3102 m_history[m_undoState++] = cmd;
3108 Inserts the given string \a s into the line
3111 Also adds the appropriate commands into the undo history.
3112 This function does not call finishChange(), and may leave the text
3113 in an invalid state.
3115 void QQuickTextInputPrivate::internalInsert(const QString &s)
3117 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
3118 Q_Q(QQuickTextInput);
3119 if (m_echoMode == QQuickTextInput::Password)
3120 m_passwordEchoTimer.start(qt_passwordEchoDelay, q);
3122 if (hasSelectedText())
3123 addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
3125 QString ms = maskString(m_cursor, s);
3126 for (int i = 0; i < (int) ms.length(); ++i) {
3127 addCommand (Command(DeleteSelection, m_cursor + i, m_text.at(m_cursor + i), -1, -1));
3128 addCommand(Command(Insert, m_cursor + i, ms.at(i), -1, -1));
3130 m_text.replace(m_cursor, ms.length(), ms);
3131 m_cursor += ms.length();
3132 m_cursor = nextMaskBlank(m_cursor);
3135 int remaining = m_maxLength - m_text.length();
3136 if (remaining != 0) {
3137 m_text.insert(m_cursor, s.left(remaining));
3138 for (int i = 0; i < (int) s.left(remaining).length(); ++i)
3139 addCommand(Command(Insert, m_cursor++, s.at(i), -1, -1));
3148 deletes a single character from the current text. If \a wasBackspace,
3149 the character prior to the cursor is removed. Otherwise the character
3150 after the cursor is removed.
3152 Also adds the appropriate commands into the undo history.
3153 This function does not call finishChange(), and may leave the text
3154 in an invalid state.
3156 void QQuickTextInputPrivate::internalDelete(bool wasBackspace)
3158 if (m_cursor < (int) m_text.length()) {
3159 cancelPasswordEchoTimer();
3160 if (hasSelectedText())
3161 addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
3162 addCommand(Command((CommandType)((m_maskData ? 2 : 0) + (wasBackspace ? Remove : Delete)),
3163 m_cursor, m_text.at(m_cursor), -1, -1));
3165 m_text.replace(m_cursor, 1, clearString(m_cursor, 1));
3166 addCommand(Command(Insert, m_cursor, m_text.at(m_cursor), -1, -1));
3168 m_text.remove(m_cursor, 1);
3177 removes the currently selected text from the line control.
3179 Also adds the appropriate commands into the undo history.
3180 This function does not call finishChange(), and may leave the text
3181 in an invalid state.
3183 void QQuickTextInputPrivate::removeSelectedText()
3185 if (m_selstart < m_selend && m_selend <= (int) m_text.length()) {
3186 cancelPasswordEchoTimer();
3189 addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
3190 if (m_selstart <= m_cursor && m_cursor < m_selend) {
3191 // cursor is within the selection. Split up the commands
3192 // to be able to restore the correct cursor position
3193 for (i = m_cursor; i >= m_selstart; --i)
3194 addCommand (Command(DeleteSelection, i, m_text.at(i), -1, 1));
3195 for (i = m_selend - 1; i > m_cursor; --i)
3196 addCommand (Command(DeleteSelection, i - m_cursor + m_selstart - 1, m_text.at(i), -1, -1));
3198 for (i = m_selend-1; i >= m_selstart; --i)
3199 addCommand (Command(RemoveSelection, i, m_text.at(i), -1, -1));
3202 m_text.replace(m_selstart, m_selend - m_selstart, clearString(m_selstart, m_selend - m_selstart));
3203 for (int i = 0; i < m_selend - m_selstart; ++i)
3204 addCommand(Command(Insert, m_selstart + i, m_text.at(m_selstart + i), -1, -1));
3206 m_text.remove(m_selstart, m_selend - m_selstart);
3208 if (m_cursor > m_selstart)
3209 m_cursor -= qMin(m_cursor, m_selend) - m_selstart;
3218 Parses the input mask specified by \a maskFields to generate
3219 the mask data used to handle input masks.
3221 void QQuickTextInputPrivate::parseInputMask(const QString &maskFields)
3223 int delimiter = maskFields.indexOf(QLatin1Char(';'));
3224 if (maskFields.isEmpty() || delimiter == 0) {
3226 delete [] m_maskData;
3228 m_maxLength = 32767;
3229 internalSetText(QString());
3234 if (delimiter == -1) {
3235 m_blank = QLatin1Char(' ');
3236 m_inputMask = maskFields;
3238 m_inputMask = maskFields.left(delimiter);
3239 m_blank = (delimiter + 1 < maskFields.length()) ? maskFields[delimiter + 1] : QLatin1Char(' ');
3242 // calculate m_maxLength / m_maskData length
3245 for (int i=0; i<m_inputMask.length(); i++) {
3246 c = m_inputMask.at(i);
3247 if (i > 0 && m_inputMask.at(i-1) == QLatin1Char('\\')) {
3251 if (c != QLatin1Char('\\') && c != QLatin1Char('!') &&
3252 c != QLatin1Char('<') && c != QLatin1Char('>') &&
3253 c != QLatin1Char('{') && c != QLatin1Char('}') &&
3254 c != QLatin1Char('[') && c != QLatin1Char(']'))
3258 delete [] m_maskData;
3259 m_maskData = new MaskInputData[m_maxLength];
3261 MaskInputData::Casemode m = MaskInputData::NoCaseMode;
3264 bool escape = false;
3266 for (int i = 0; i < m_inputMask.length(); i++) {
3267 c = m_inputMask.at(i);
3270 m_maskData[index].maskChar = c;
3271 m_maskData[index].separator = s;
3272 m_maskData[index].caseMode = m;
3275 } else if (c == QLatin1Char('<')) {
3276 m = MaskInputData::Lower;
3277 } else if (c == QLatin1Char('>')) {
3278 m = MaskInputData::Upper;
3279 } else if (c == QLatin1Char('!')) {
3280 m = MaskInputData::NoCaseMode;
3281 } else if (c != QLatin1Char('{') && c != QLatin1Char('}') && c != QLatin1Char('[') && c != QLatin1Char(']')) {
3282 switch (c.unicode()) {
3308 m_maskData[index].maskChar = c;
3309 m_maskData[index].separator = s;
3310 m_maskData[index].caseMode = m;
3315 internalSetText(m_text);
3322 checks if the key is valid compared to the inputMask
3324 bool QQuickTextInputPrivate::isValidInput(QChar key, QChar mask) const
3326 switch (mask.unicode()) {
3332 if (key.isLetter() || key == m_blank)
3336 if (key.isLetterOrNumber())
3340 if (key.isLetterOrNumber() || key == m_blank)
3348 if (key.isPrint() || key == m_blank)
3356 if (key.isNumber() || key == m_blank)
3360 if (key.isNumber() && key.digitValue() > 0)
3364 if ((key.isNumber() && key.digitValue() > 0) || key == m_blank)
3368 if (key.isNumber() || key == QLatin1Char('+') || key == QLatin1Char('-') || key == m_blank)
3372 if (key == QLatin1Char('0') || key == QLatin1Char('1'))
3376 if (key == QLatin1Char('0') || key == QLatin1Char('1') || key == m_blank)
3380 if (key.isNumber() || (key >= QLatin1Char('a') && key <= QLatin1Char('f')) || (key >= QLatin1Char('A') && key <= QLatin1Char('F')))
3384 if (key.isNumber() || (key >= QLatin1Char('a') && key <= QLatin1Char('f')) || (key >= QLatin1Char('A') && key <= QLatin1Char('F')) || key == m_blank)
3396 Returns true if the given text \a str is valid for any
3397 validator or input mask set for the line control.
3399 Otherwise returns false
3401 bool QQuickTextInputPrivate::hasAcceptableInput(const QString &str) const
3403 #ifndef QT_NO_VALIDATOR
3404 QString textCopy = str;
3405 int cursorCopy = m_cursor;
3406 if (m_validator && m_validator->validate(textCopy, cursorCopy)
3407 != QValidator::Acceptable)
3414 if (str.length() != m_maxLength)
3417 for (int i=0; i < m_maxLength; ++i) {
3418 if (m_maskData[i].separator) {
3419 if (str.at(i) != m_maskData[i].maskChar)
3422 if (!isValidInput(str.at(i), m_maskData[i].maskChar))
3432 Applies the inputMask on \a str starting from position \a pos in the mask. \a clear
3433 specifies from where characters should be gotten when a separator is met in \a str - true means
3434 that blanks will be used, false that previous input is used.
3435 Calling this when no inputMask is set is undefined.
3437 QString QQuickTextInputPrivate::maskString(uint pos, const QString &str, bool clear) const
3439 if (pos >= (uint)m_maxLength)
3440 return QString::fromLatin1("");
3443 fill = clear ? clearString(0, m_maxLength) : m_text;
3446 QString s = QString::fromLatin1("");
3448 while (i < m_maxLength) {
3449 if (strIndex < str.length()) {
3450 if (m_maskData[i].separator) {
3451 s += m_maskData[i].maskChar;
3452 if (str[(int)strIndex] == m_maskData[i].maskChar)
3456 if (isValidInput(str[(int)strIndex], m_maskData[i].maskChar)) {
3457 switch (m_maskData[i].caseMode) {
3458 case MaskInputData::Upper:
3459 s += str[(int)strIndex].toUpper();
3461 case MaskInputData::Lower:
3462 s += str[(int)strIndex].toLower();
3465 s += str[(int)strIndex];
3469 // search for separator first
3470 int n = findInMask(i, true, true, str[(int)strIndex]);
3472 if (str.length() != 1 || i == 0 || (i > 0 && (!m_maskData[i-1].separator || m_maskData[i-1].maskChar != str[(int)strIndex]))) {
3473 s += fill.mid(i, n-i+1);
3474 i = n + 1; // update i to find + 1
3477 // search for valid m_blank if not
3478 n = findInMask(i, true, false, str[(int)strIndex]);
3480 s += fill.mid(i, n-i);
3481 switch (m_maskData[n].caseMode) {
3482 case MaskInputData::Upper:
3483 s += str[(int)strIndex].toUpper();
3485 case MaskInputData::Lower:
3486 s += str[(int)strIndex].toLower();
3489 s += str[(int)strIndex];
3491 i = n + 1; // updates i to find + 1
3509 Returns a "cleared" string with only separators and blank chars.
3510 Calling this when no inputMask is set is undefined.
3512 QString QQuickTextInputPrivate::clearString(uint pos, uint len) const
3514 if (pos >= (uint)m_maxLength)
3518 int end = qMin((uint)m_maxLength, pos + len);
3519 for (int i = pos; i < end; ++i)
3520 if (m_maskData[i].separator)
3521 s += m_maskData[i].maskChar;
3531 Strips blank parts of the input in a QQuickTextInputPrivate when an inputMask is set,
3532 separators are still included. Typically "127.0__.0__.1__" becomes "127.0.0.1".
3534 QString QQuickTextInputPrivate::stripString(const QString &str) const
3540 int end = qMin(m_maxLength, (int)str.length());
3541 for (int i = 0; i < end; ++i) {
3542 if (m_maskData[i].separator)
3543 s += m_maskData[i].maskChar;
3544 else if (str[i] != m_blank)
3553 searches forward/backward in m_maskData for either a separator or a m_blank
3555 int QQuickTextInputPrivate::findInMask(int pos, bool forward, bool findSeparator, QChar searchChar) const
3557 if (pos >= m_maxLength || pos < 0)
3560 int end = forward ? m_maxLength : -1;
3561 int step = forward ? 1 : -1;
3565 if (findSeparator) {
3566 if (m_maskData[i].separator && m_maskData[i].maskChar == searchChar)
3569 if (!m_maskData[i].separator) {
3570 if (searchChar.isNull())
3572 else if (isValidInput(searchChar, m_maskData[i].maskChar))
3581 void QQuickTextInputPrivate::internalUndo(int until)
3583 if (!isUndoAvailable())
3585 cancelPasswordEchoTimer();
3587 while (m_undoState && m_undoState > until) {
3588 Command& cmd = m_history[--m_undoState];
3591 m_text.remove(cmd.pos, 1);
3595 m_selstart = cmd.selStart;
3596 m_selend = cmd.selEnd;
3600 case RemoveSelection:
3601 m_text.insert(cmd.pos, cmd.uc);
3602 m_cursor = cmd.pos + 1;
3605 case DeleteSelection:
3606 m_text.insert(cmd.pos, cmd.uc);
3612 if (until < 0 && m_undoState) {
3613 Command& next = m_history[m_undoState-1];
3614 if (next.type != cmd.type && next.type < RemoveSelection
3615 && (cmd.type < RemoveSelection || next.type == Separator))
3622 void QQuickTextInputPrivate::internalRedo()
3624 if (!isRedoAvailable())
3627 while (m_undoState < (int)m_history.size()) {
3628 Command& cmd = m_history[m_undoState++];
3631 m_text.insert(cmd.pos, cmd.uc);
3632 m_cursor = cmd.pos + 1;
3635 m_selstart = cmd.selStart;
3636 m_selend = cmd.selEnd;
3641 case RemoveSelection:
3642 case DeleteSelection:
3643 m_text.remove(cmd.pos, 1);
3644 m_selstart = cmd.selStart;
3645 m_selend = cmd.selEnd;
3649 m_selstart = cmd.selStart;
3650 m_selend = cmd.selEnd;
3654 if (m_undoState < (int)m_history.size()) {
3655 Command& next = m_history[m_undoState];
3656 if (next.type != cmd.type && cmd.type < RemoveSelection && next.type != Separator
3657 && (next.type < RemoveSelection || cmd.type == Separator))
3664 void QQuickTextInputPrivate::emitUndoRedoChanged()
3666 Q_Q(QQuickTextInput);
3667 const bool previousUndo = canUndo;
3668 const bool previousRedo = canRedo;
3670 canUndo = isUndoAvailable();
3671 canRedo = isRedoAvailable();
3673 if (previousUndo != canUndo)
3674 emit q->canUndoChanged();
3675 if (previousRedo != canRedo)
3676 emit q->canRedoChanged();
3682 If the current cursor position differs from the last emitted cursor
3683 position, emits cursorPositionChanged().
3685 void QQuickTextInputPrivate::emitCursorPositionChanged()
3687 Q_Q(QQuickTextInput);
3688 if (m_cursor != m_lastCursorPos) {
3689 m_lastCursorPos = m_cursor;
3691 q->updateCursorRectangle();
3692 emit q->cursorPositionChanged();
3693 // XXX todo - not in 4.8?
3695 resetCursorBlinkTimer();
3698 if (!hasSelectedText()) {
3699 if (lastSelectionStart != m_cursor) {
3700 lastSelectionStart = m_cursor;
3701 emit q->selectionStartChanged();
3703 if (lastSelectionEnd != m_cursor) {
3704 lastSelectionEnd = m_cursor;
3705 emit q->selectionEndChanged();
3709 #ifndef QT_NO_ACCESSIBILITY
3710 QAccessible::updateAccessibility(q, 0, QAccessible::TextCaretMoved);
3716 void QQuickTextInputPrivate::setCursorBlinkPeriod(int msec)
3718 Q_Q(QQuickTextInput);
3719 if (msec == m_blinkPeriod)
3722 q->killTimer(m_blinkTimer);
3725 m_blinkTimer = q->startTimer(msec / 2);
3729 if (m_blinkStatus == 1)
3732 m_blinkPeriod = msec;
3735 void QQuickTextInputPrivate::resetCursorBlinkTimer()
3737 Q_Q(QQuickTextInput);
3738 if (m_blinkPeriod == 0 || m_blinkTimer == 0)
3740 q->killTimer(m_blinkTimer);
3741 m_blinkTimer = q->startTimer(m_blinkPeriod / 2);
3745 void QQuickTextInput::timerEvent(QTimerEvent *event)
3747 Q_D(QQuickTextInput);
3748 if (event->timerId() == d->m_blinkTimer) {
3749 d->m_blinkStatus = !d->m_blinkStatus;
3751 } else if (event->timerId() == d->m_deleteAllTimer) {
3752 killTimer(d->m_deleteAllTimer);
3753 d->m_deleteAllTimer = 0;
3755 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
3756 } else if (event->timerId() == d->m_passwordEchoTimer.timerId()) {
3757 d->m_passwordEchoTimer.stop();
3758 d->updateDisplayText();
3763 void QQuickTextInputPrivate::processKeyEvent(QKeyEvent* event)
3765 Q_Q(QQuickTextInput);
3766 bool inlineCompletionAccepted = false;
3768 if (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return) {
3769 if (hasAcceptableInput(m_text) || fixup()) {
3772 if (inlineCompletionAccepted)
3779 if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit
3780 && !m_passwordEchoEditing
3782 && !event->text().isEmpty()
3783 && !(event->modifiers() & Qt::ControlModifier)) {
3784 // Clear the edit and reset to normal echo mode while editing; the
3785 // echo mode switches back when the edit loses focus
3786 // ### resets current content. dubious code; you can
3787 // navigate with keys up, down, back, and select(?), but if you press
3788 // "left" or "right" it clears?
3789 updatePasswordEchoEditing(true);
3793 bool unknown = false;
3794 bool visual = cursorMoveStyle() == Qt::VisualMoveStyle;
3798 #ifndef QT_NO_SHORTCUT
3799 else if (event == QKeySequence::Undo) {
3803 else if (event == QKeySequence::Redo) {
3807 else if (event == QKeySequence::SelectAll) {
3810 #ifndef QT_NO_CLIPBOARD
3811 else if (event == QKeySequence::Copy) {
3814 else if (event == QKeySequence::Paste) {
3816 QClipboard::Mode mode = QClipboard::Clipboard;
3820 else if (event == QKeySequence::Cut) {
3826 else if (event == QKeySequence::DeleteEndOfLine) {
3828 setSelection(m_cursor, end());
3833 #endif //QT_NO_CLIPBOARD
3834 else if (event == QKeySequence::MoveToStartOfLine || event == QKeySequence::MoveToStartOfBlock) {
3837 else if (event == QKeySequence::MoveToEndOfLine || event == QKeySequence::MoveToEndOfBlock) {
3840 else if (event == QKeySequence::SelectStartOfLine || event == QKeySequence::SelectStartOfBlock) {
3843 else if (event == QKeySequence::SelectEndOfLine || event == QKeySequence::SelectEndOfBlock) {
3846 else if (event == QKeySequence::MoveToNextChar) {
3847 if (hasSelectedText()) {
3848 moveCursor(selectionEnd(), false);
3850 cursorForward(0, visual ? 1 : (layoutDirection() == Qt::LeftToRight ? 1 : -1));
3853 else if (event == QKeySequence::SelectNextChar) {
3854 cursorForward(1, visual ? 1 : (layoutDirection() == Qt::LeftToRight ? 1 : -1));
3856 else if (event == QKeySequence::MoveToPreviousChar) {
3857 if (hasSelectedText()) {
3858 moveCursor(selectionStart(), false);
3860 cursorForward(0, visual ? -1 : (layoutDirection() == Qt::LeftToRight ? -1 : 1));
3863 else if (event == QKeySequence::SelectPreviousChar) {
3864 cursorForward(1, visual ? -1 : (layoutDirection() == Qt::LeftToRight ? -1 : 1));
3866 else if (event == QKeySequence::MoveToNextWord) {
3867 if (m_echoMode == QQuickTextInput::Normal)
3868 layoutDirection() == Qt::LeftToRight ? cursorWordForward(0) : cursorWordBackward(0);
3870 layoutDirection() == Qt::LeftToRight ? end(0) : home(0);
3872 else if (event == QKeySequence::MoveToPreviousWord) {
3873 if (m_echoMode == QQuickTextInput::Normal)
3874 layoutDirection() == Qt::LeftToRight ? cursorWordBackward(0) : cursorWordForward(0);
3875 else if (!m_readOnly) {
3876 layoutDirection() == Qt::LeftToRight ? home(0) : end(0);
3879 else if (event == QKeySequence::SelectNextWord) {
3880 if (m_echoMode == QQuickTextInput::Normal)
3881 layoutDirection() == Qt::LeftToRight ? cursorWordForward(1) : cursorWordBackward(1);
3883 layoutDirection() == Qt::LeftToRight ? end(1) : home(1);
3885 else if (event == QKeySequence::SelectPreviousWord) {
3886 if (m_echoMode == QQuickTextInput::Normal)
3887 layoutDirection() == Qt::LeftToRight ? cursorWordBackward(1) : cursorWordForward(1);
3889 layoutDirection() == Qt::LeftToRight ? home(1) : end(1);
3891 else if (event == QKeySequence::Delete) {
3895 else if (event == QKeySequence::DeleteEndOfWord) {
3897 cursorWordForward(true);
3901 else if (event == QKeySequence::DeleteStartOfWord) {
3903 cursorWordBackward(true);
3907 #endif // QT_NO_SHORTCUT
3909 bool handled = false;
3910 if (event->modifiers() & Qt::ControlModifier) {
3911 switch (event->key()) {
3912 case Qt::Key_Backspace:
3914 cursorWordBackward(true);
3922 } else { // ### check for *no* modifier
3923 switch (event->key()) {
3924 case Qt::Key_Backspace:
3936 if (event->key() == Qt::Key_Direction_L || event->key() == Qt::Key_Direction_R) {
3937 setLayoutDirection((event->key() == Qt::Key_Direction_L) ? Qt::LeftToRight : Qt::RightToLeft);
3941 if (unknown && !m_readOnly) {
3942 QString t = event->text();
3943 if (!t.isEmpty() && t.at(0).isPrint()) {