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() ? qApp->inputPanel()->inputDirection() == Qt::RightToLeft
482 : text.isRightToLeft();
483 return setHAlign(isRightToLeft ? QQuickTextInput::AlignRight : QQuickTextInput::AlignLeft);
488 QQuickTextInput::VAlignment QQuickTextInput::vAlign() const
490 Q_D(const QQuickTextInput);
494 void QQuickTextInput::setVAlign(QQuickTextInput::VAlignment alignment)
496 Q_D(QQuickTextInput);
497 if (alignment == d->vAlign)
499 d->vAlign = alignment;
500 emit verticalAlignmentChanged(d->vAlign);
501 if (isComponentComplete()) {
502 updateCursorRectangle();
507 \qmlproperty enumeration QtQuick2::TextInput::wrapMode
509 Set this property to wrap the text to the TextEdit item's width.
510 The text will only wrap if an explicit width has been set.
513 \o TextInput.NoWrap - no wrapping will be performed. If the text contains insufficient newlines, then implicitWidth will exceed a set width.
514 \o TextInput.WordWrap - wrapping is done on word boundaries only. If a word is too long, implicitWidth will exceed a set width.
515 \o TextInput.WrapAnywhere - wrapping is done at any point on a line, even if it occurs in the middle of a word.
516 \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.
519 The default is TextInput.NoWrap. If you set a width, consider using TextInput.Wrap.
521 QQuickTextInput::WrapMode QQuickTextInput::wrapMode() const
523 Q_D(const QQuickTextInput);
527 void QQuickTextInput::setWrapMode(WrapMode mode)
529 Q_D(QQuickTextInput);
530 if (mode == d->wrapMode)
534 updateCursorRectangle();
535 emit wrapModeChanged();
538 void QQuickTextInputPrivate::mirrorChange()
540 Q_Q(QQuickTextInput);
541 if (q->isComponentComplete()) {
542 if (!hAlignImplicit && (hAlign == QQuickTextInput::AlignRight || hAlign == QQuickTextInput::AlignLeft)) {
543 q->updateCursorRectangle();
544 emit q->effectiveHorizontalAlignmentChanged();
550 \qmlproperty bool QtQuick2::TextInput::readOnly
552 Sets whether user input can modify the contents of the TextInput.
554 If readOnly is set to true, then user input will not affect the text
555 property. Any bindings or attempts to set the text property will still
558 bool QQuickTextInput::isReadOnly() const
560 Q_D(const QQuickTextInput);
561 return d->m_readOnly;
564 void QQuickTextInput::setReadOnly(bool ro)
566 Q_D(QQuickTextInput);
567 if (d->m_readOnly == ro)
570 setFlag(QQuickItem::ItemAcceptsInputMethod, !ro);
573 d->setCursorPosition(d->end());
575 d->emitUndoRedoChanged();
576 emit readOnlyChanged(ro);
580 \qmlproperty int QtQuick2::TextInput::maximumLength
581 The maximum permitted length of the text in the TextInput.
583 If the text is too long, it is truncated at the limit.
585 By default, this property contains a value of 32767.
587 int QQuickTextInput::maxLength() const
589 Q_D(const QQuickTextInput);
590 return d->m_maxLength;
593 void QQuickTextInput::setMaxLength(int ml)
595 Q_D(QQuickTextInput);
596 if (d->m_maxLength == ml || d->m_maskData)
600 d->internalSetText(d->m_text, -1, false);
602 emit maximumLengthChanged(ml);
606 \qmlproperty bool QtQuick2::TextInput::cursorVisible
607 Set to true when the TextInput shows a cursor.
609 This property is set and unset when the TextInput gets active focus, so that other
610 properties can be bound to whether the cursor is currently showing. As it
611 gets set and unset automatically, when you set the value yourself you must
612 keep in mind that your value may be overwritten.
614 It can be set directly in script, for example if a KeyProxy might
615 forward keys to it and you desire it to look active when this happens
616 (but without actually giving it active focus).
618 It should not be set directly on the element, like in the below QML,
619 as the specified value will be overridden an lost on focus changes.
628 In the above snippet the cursor will still become visible when the
629 TextInput gains active focus.
631 bool QQuickTextInput::isCursorVisible() const
633 Q_D(const QQuickTextInput);
634 return d->cursorVisible;
637 void QQuickTextInput::setCursorVisible(bool on)
639 Q_D(QQuickTextInput);
640 if (d->cursorVisible == on)
642 d->cursorVisible = on;
643 d->setCursorBlinkPeriod(on ? qApp->styleHints()->cursorFlashTime() : 0);
645 emit cursorVisibleChanged(d->cursorVisible);
649 \qmlproperty int QtQuick2::TextInput::cursorPosition
650 The position of the cursor in the TextInput.
652 int QQuickTextInput::cursorPosition() const
654 Q_D(const QQuickTextInput);
658 void QQuickTextInput::setCursorPosition(int cp)
660 Q_D(QQuickTextInput);
661 if (cp < 0 || cp > text().length())
667 \qmlproperty rectangle QtQuick2::TextInput::cursorRectangle
669 The rectangle where the standard text cursor is rendered within the text input. Read only.
671 The position and height of a custom cursorDelegate are updated to follow the cursorRectangle
672 automatically when it changes. The width of the delegate is unaffected by changes in the
676 QRect QQuickTextInput::cursorRectangle() const
678 Q_D(const QQuickTextInput);
681 if (d->m_preeditCursor != -1)
682 c += d->m_preeditCursor;
683 if (d->m_echoMode == NoEcho)
685 QTextLine l = d->m_textLayout.lineForTextPosition(c);
689 qRound(l.cursorToX(c) - d->hscroll),
690 qRound(l.y() - d->vscroll),
696 \qmlproperty int QtQuick2::TextInput::selectionStart
698 The cursor position before the first character in the current selection.
700 This property is read-only. To change the selection, use select(start,end),
701 selectAll(), or selectWord().
703 \sa selectionEnd, cursorPosition, selectedText
705 int QQuickTextInput::selectionStart() const
707 Q_D(const QQuickTextInput);
708 return d->lastSelectionStart;
711 \qmlproperty int QtQuick2::TextInput::selectionEnd
713 The cursor position after the last character in the current selection.
715 This property is read-only. To change the selection, use select(start,end),
716 selectAll(), or selectWord().
718 \sa selectionStart, cursorPosition, selectedText
720 int QQuickTextInput::selectionEnd() const
722 Q_D(const QQuickTextInput);
723 return d->lastSelectionEnd;
726 \qmlmethod void QtQuick2::TextInput::select(int start, int end)
728 Causes the text from \a start to \a end to be selected.
730 If either start or end is out of range, the selection is not changed.
732 After calling this, selectionStart will become the lesser
733 and selectionEnd will become the greater (regardless of the order passed
736 \sa selectionStart, selectionEnd
738 void QQuickTextInput::select(int start, int end)
740 Q_D(QQuickTextInput);
741 if (start < 0 || end < 0 || start > d->m_text.length() || end > d->m_text.length())
743 d->setSelection(start, end-start);
747 \qmlproperty string QtQuick2::TextInput::selectedText
749 This read-only property provides the text currently selected in the
752 It is equivalent to the following snippet, but is faster and easier
756 myTextInput.text.toString().substring(myTextInput.selectionStart,
757 myTextInput.selectionEnd);
760 QString QQuickTextInput::selectedText() const
762 Q_D(const QQuickTextInput);
763 return d->selectedText();
767 \qmlproperty bool QtQuick2::TextInput::activeFocusOnPress
769 Whether the TextInput should gain active focus on a mouse press. By default this is
772 bool QQuickTextInput::focusOnPress() const
774 Q_D(const QQuickTextInput);
775 return d->focusOnPress;
778 void QQuickTextInput::setFocusOnPress(bool b)
780 Q_D(QQuickTextInput);
781 if (d->focusOnPress == b)
786 emit activeFocusOnPressChanged(d->focusOnPress);
789 \qmlproperty bool QtQuick2::TextInput::autoScroll
791 Whether the TextInput should scroll when the text is longer than the width. By default this is
794 bool QQuickTextInput::autoScroll() const
796 Q_D(const QQuickTextInput);
797 return d->autoScroll;
800 void QQuickTextInput::setAutoScroll(bool b)
802 Q_D(QQuickTextInput);
803 if (d->autoScroll == b)
807 //We need to repaint so that the scrolling is taking into account.
808 updateCursorRectangle();
809 emit autoScrollChanged(d->autoScroll);
812 #ifndef QT_NO_VALIDATOR
815 \qmlclass IntValidator QIntValidator
816 \inqmlmodule QtQuick 2
817 \ingroup qml-basic-visual-elements
819 This element provides a validator for integer values.
821 IntValidator uses the \l {QLocale::setDefault()}{default locale} to interpret the number and
822 will accept locale specific digits, group separators, and positive and negative signs. In
823 addition, IntValidator is always guaranteed to accept a number formatted according to the "C"
827 \qmlproperty int QtQuick2::IntValidator::top
829 This property holds the validator's highest acceptable value.
830 By default, this property's value is derived from the highest signed integer available (typically 2147483647).
833 \qmlproperty int QtQuick2::IntValidator::bottom
835 This property holds the validator's lowest acceptable value.
836 By default, this property's value is derived from the lowest signed integer available (typically -2147483647).
840 \qmlclass DoubleValidator QDoubleValidator
841 \inqmlmodule QtQuick 2
842 \ingroup qml-basic-visual-elements
844 This element provides a validator for non-integer numbers.
848 \qmlproperty real QtQuick2::DoubleValidator::top
850 This property holds the validator's maximum acceptable value.
851 By default, this property contains a value of infinity.
854 \qmlproperty real QtQuick2::DoubleValidator::bottom
856 This property holds the validator's minimum acceptable value.
857 By default, this property contains a value of -infinity.
860 \qmlproperty int QtQuick2::DoubleValidator::decimals
862 This property holds the validator's maximum number of digits after the decimal point.
863 By default, this property contains a value of 1000.
866 \qmlproperty enumeration QtQuick2::DoubleValidator::notation
867 This property holds the notation of how a string can describe a number.
869 The possible values for this property are:
872 \o DoubleValidator.StandardNotation
873 \o DoubleValidator.ScientificNotation (default)
876 If this property is set to DoubleValidator.ScientificNotation, the written number may have an exponent part (e.g. 1.5E-2).
880 \qmlclass RegExpValidator QRegExpValidator
881 \inqmlmodule QtQuick 2
882 \ingroup qml-basic-visual-elements
884 This element provides a validator, which counts as valid any string which
885 matches a specified regular expression.
888 \qmlproperty regExp QtQuick2::RegExpValidator::regExp
890 This property holds the regular expression used for validation.
892 Note that this property should be a regular expression in JS syntax, e.g /a/ for the regular expression
895 By default, this property contains a regular expression with the pattern .* that matches any string.
899 \qmlproperty Validator QtQuick2::TextInput::validator
901 Allows you to set a validator on the TextInput. When a validator is set
902 the TextInput will only accept input which leaves the text property in
903 an acceptable or intermediate state. The accepted signal will only be sent
904 if the text is in an acceptable state when enter is pressed.
906 Currently supported validators are IntValidator, DoubleValidator and
907 RegExpValidator. An example of using validators is shown below, which allows
908 input of integers between 11 and 31 into the text input:
913 validator: IntValidator{bottom: 11; top: 31;}
918 \sa acceptableInput, inputMask
921 QValidator* QQuickTextInput::validator() const
923 Q_D(const QQuickTextInput);
924 return d->m_validator;
927 void QQuickTextInput::setValidator(QValidator* v)
929 Q_D(QQuickTextInput);
930 if (d->m_validator == v)
934 if (!d->hasAcceptableInput(d->m_text)) {
935 if (d->m_validInput) {
936 d->m_validInput = false;
937 emit acceptableInputChanged();
939 } else if (!d->m_validInput) {
940 d->m_validInput = true;
941 emit acceptableInputChanged();
944 emit validatorChanged();
946 #endif // QT_NO_VALIDATOR
949 \qmlproperty string QtQuick2::TextInput::inputMask
951 Allows you to set an input mask on the TextInput, restricting the allowable
952 text inputs. See QLineEdit::inputMask for further details, as the exact
953 same mask strings are used by TextInput.
955 \sa acceptableInput, validator
957 QString QQuickTextInput::inputMask() const
959 Q_D(const QQuickTextInput);
960 return d->inputMask();
963 void QQuickTextInput::setInputMask(const QString &im)
965 Q_D(QQuickTextInput);
966 if (d->inputMask() == im)
970 emit inputMaskChanged(d->inputMask());
974 \qmlproperty bool QtQuick2::TextInput::acceptableInput
976 This property is always true unless a validator or input mask has been set.
977 If a validator or input mask has been set, this property will only be true
978 if the current text is acceptable to the validator or input mask as a final
979 string (not as an intermediate string).
981 bool QQuickTextInput::hasAcceptableInput() const
983 Q_D(const QQuickTextInput);
984 return d->hasAcceptableInput(d->m_text);
988 \qmlsignal QtQuick2::TextInput::onAccepted()
990 This handler is called when the Return or Enter key is pressed.
991 Note that if there is a \l validator or \l inputMask set on the text
992 input, the handler will only be emitted if the input is in an acceptable
996 void QQuickTextInputPrivate::updateInputMethodHints()
998 Q_Q(QQuickTextInput);
999 Qt::InputMethodHints hints = inputMethodHints;
1000 if (m_echoMode == QQuickTextInput::Password || m_echoMode == QQuickTextInput::NoEcho)
1001 hints |= Qt::ImhHiddenText;
1002 else if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit)
1003 hints &= ~Qt::ImhHiddenText;
1004 if (m_echoMode != QQuickTextInput::Normal)
1005 hints |= (Qt::ImhNoAutoUppercase | Qt::ImhNoPredictiveText | Qt::ImhSensitiveData);
1006 q->setInputMethodHints(hints);
1009 \qmlproperty enumeration QtQuick2::TextInput::echoMode
1011 Specifies how the text should be displayed in the TextInput.
1013 \o TextInput.Normal - Displays the text as it is. (Default)
1014 \o TextInput.Password - Displays asterisks instead of characters.
1015 \o TextInput.NoEcho - Displays nothing.
1016 \o TextInput.PasswordEchoOnEdit - Displays characters as they are entered
1017 while editing, otherwise displays asterisks.
1020 QQuickTextInput::EchoMode QQuickTextInput::echoMode() const
1022 Q_D(const QQuickTextInput);
1023 return QQuickTextInput::EchoMode(d->m_echoMode);
1026 void QQuickTextInput::setEchoMode(QQuickTextInput::EchoMode echo)
1028 Q_D(QQuickTextInput);
1029 if (echoMode() == echo)
1031 d->cancelPasswordEchoTimer();
1032 d->m_echoMode = echo;
1033 d->m_passwordEchoEditing = false;
1034 d->updateInputMethodHints();
1035 d->updateDisplayText();
1036 updateCursorRectangle();
1038 emit echoModeChanged(echoMode());
1042 \qmlproperty enumeration QtQuick2::TextInput::inputMethodHints
1044 Provides hints to the input method about the expected content of the text input and how it
1047 The value is a bit-wise combination of flags, or Qt.ImhNone if no hints are set.
1049 Flags that alter behaviour are:
1052 \o Qt.ImhHiddenText - Characters should be hidden, as is typically used when entering passwords.
1053 This is automatically set when setting echoMode to \c TextInput.Password.
1054 \o Qt.ImhSensitiveData - Typed text should not be stored by the active input method
1055 in any persistent storage like predictive user dictionary.
1056 \o Qt.ImhNoAutoUppercase - The input method should not try to automatically switch to upper case
1057 when a sentence ends.
1058 \o Qt.ImhPreferNumbers - Numbers are preferred (but not required).
1059 \o Qt.ImhPreferUppercase - Upper case letters are preferred (but not required).
1060 \o Qt.ImhPreferLowercase - Lower case letters are preferred (but not required).
1061 \o Qt.ImhNoPredictiveText - Do not use predictive text (i.e. dictionary lookup) while typing.
1063 \o Qt.ImhDate - The text editor functions as a date field.
1064 \o Qt.ImhTime - The text editor functions as a time field.
1067 Flags that restrict input (exclusive flags) are:
1070 \o Qt.ImhDigitsOnly - Only digits are allowed.
1071 \o Qt.ImhFormattedNumbersOnly - Only number input is allowed. This includes decimal point and minus sign.
1072 \o Qt.ImhUppercaseOnly - Only upper case letter input is allowed.
1073 \o Qt.ImhLowercaseOnly - Only lower case letter input is allowed.
1074 \o Qt.ImhDialableCharactersOnly - Only characters suitable for phone dialing are allowed.
1075 \o Qt.ImhEmailCharactersOnly - Only characters suitable for email addresses are allowed.
1076 \o Qt.ImhUrlCharactersOnly - Only characters suitable for URLs are allowed.
1082 \o Qt.ImhExclusiveInputMask - This mask yields nonzero if any of the exclusive flags are used.
1086 Qt::InputMethodHints QQuickTextInput::imHints() const
1088 Q_D(const QQuickTextInput);
1089 return d->inputMethodHints;
1092 void QQuickTextInput::setIMHints(Qt::InputMethodHints hints)
1094 Q_D(QQuickTextInput);
1095 if (d->inputMethodHints == hints)
1097 d->inputMethodHints = hints;
1098 d->updateInputMethodHints();
1102 \qmlproperty Component QtQuick2::TextInput::cursorDelegate
1103 The delegate for the cursor in the TextInput.
1105 If you set a cursorDelegate for a TextInput, this delegate will be used for
1106 drawing the cursor instead of the standard cursor. An instance of the
1107 delegate will be created and managed by the TextInput when a cursor is
1108 needed, and the x property of delegate instance will be set so as
1109 to be one pixel before the top left of the current character.
1111 Note that the root item of the delegate component must be a QDeclarativeItem or
1112 QDeclarativeItem derived item.
1114 QDeclarativeComponent* QQuickTextInput::cursorDelegate() const
1116 Q_D(const QQuickTextInput);
1117 return d->cursorComponent;
1120 void QQuickTextInput::setCursorDelegate(QDeclarativeComponent* c)
1122 Q_D(QQuickTextInput);
1123 if (d->cursorComponent == c)
1126 d->cursorComponent = c;
1128 //note that the components are owned by something else
1129 delete d->cursorItem;
1131 d->startCreatingCursor();
1134 emit cursorDelegateChanged();
1137 void QQuickTextInputPrivate::startCreatingCursor()
1139 Q_Q(QQuickTextInput);
1140 if (cursorComponent->isReady()) {
1142 } else if (cursorComponent->isLoading()) {
1143 q->connect(cursorComponent, SIGNAL(statusChanged(int)),
1144 q, SLOT(createCursor()));
1146 qmlInfo(q, cursorComponent->errors()) << QQuickTextInput::tr("Could not load cursor delegate");
1150 void QQuickTextInput::createCursor()
1152 Q_D(QQuickTextInput);
1153 if (!isComponentComplete())
1156 if (d->cursorComponent->isError()) {
1157 qmlInfo(this, d->cursorComponent->errors()) << tr("Could not load cursor delegate");
1161 if (!d->cursorComponent->isReady())
1165 delete d->cursorItem;
1166 QDeclarativeContext *creationContext = d->cursorComponent->creationContext();
1167 QObject *object = d->cursorComponent->create(creationContext ? creationContext : qmlContext(this));
1168 d->cursorItem = qobject_cast<QQuickItem*>(object);
1169 if (!d->cursorItem) {
1171 qmlInfo(this, d->cursorComponent->errors()) << tr("Could not instantiate cursor delegate");
1175 QRectF r = cursorRectangle();
1177 QDeclarative_setParent_noEvent(d->cursorItem, this);
1178 d->cursorItem->setParentItem(this);
1179 d->cursorItem->setPos(r.topLeft());
1180 d->cursorItem->setHeight(r.height());
1184 \qmlmethod rect QtQuick2::TextInput::positionToRectangle(int pos)
1186 This function takes a character position and returns the rectangle that the
1187 cursor would occupy, if it was placed at that character position.
1189 This is similar to setting the cursorPosition, and then querying the cursor
1190 rectangle, but the cursorPosition is not changed.
1192 QRectF QQuickTextInput::positionToRectangle(int pos) const
1194 Q_D(const QQuickTextInput);
1195 if (pos > d->m_cursor)
1196 pos += d->preeditAreaText().length();
1197 QTextLine l = d->m_textLayout.lineAt(0);
1199 ? QRectF(l.cursorToX(pos) - d->hscroll, 0.0, d->m_cursorWidth, l.height())
1204 \qmlmethod int QtQuick2::TextInput::positionAt(real x, real y, CursorPosition position = CursorBetweenCharacters)
1206 This function returns the character position at
1207 x and y pixels from the top left of the textInput. Position 0 is before the
1208 first character, position 1 is after the first character but before the second,
1209 and so on until position text.length, which is after all characters.
1211 This means that for all x values before the first character this function returns 0,
1212 and for all x values after the last character this function returns text.length. If
1213 the y value is above the text the position will be that of the nearest character on
1214 the first line line and if it is below the text the position of the nearest character
1215 on the last line will be returned.
1217 The cursor position type specifies how the cursor position should be resolved.
1220 \o TextInput.CursorBetweenCharacters - Returns the position between characters that is nearest x.
1221 \o TextInput.CursorOnCharacter - Returns the position before the character that is nearest x.
1225 void QQuickTextInput::positionAt(QDeclarativeV8Function *args) const
1227 Q_D(const QQuickTextInput);
1231 QTextLine::CursorPosition position = QTextLine::CursorBetweenCharacters;
1233 if (args->Length() < 1)
1237 v8::Local<v8::Value> arg = (*args)[i];
1238 x = arg->NumberValue();
1240 if (++i < args->Length()) {
1242 y = arg->NumberValue();
1245 if (++i < args->Length()) {
1247 position = QTextLine::CursorPosition(arg->Int32Value());
1250 int pos = d->positionAt(x, y, position);
1251 const int cursor = d->m_cursor;
1253 const int preeditLength = d->preeditAreaText().length();
1254 pos = pos > cursor + preeditLength
1255 ? pos - preeditLength
1258 args->returnValue(v8::Int32::New(pos));
1261 int QQuickTextInputPrivate::positionAt(int x, int y, QTextLine::CursorPosition position) const
1265 QTextLine line = m_textLayout.lineAt(0);
1266 for (int i = 1; i < m_textLayout.lineCount(); ++i) {
1267 QTextLine nextLine = m_textLayout.lineAt(i);
1269 if (y < (line.rect().bottom() + nextLine.y()) / 2)
1273 return line.isValid() ? line.xToCursor(x, position) : 0;
1276 void QQuickTextInput::keyPressEvent(QKeyEvent* ev)
1278 Q_D(QQuickTextInput);
1279 // Don't allow MacOSX up/down support, and we don't allow a completer.
1280 bool ignore = (ev->key() == Qt::Key_Up || ev->key() == Qt::Key_Down) && ev->modifiers() == Qt::NoModifier;
1281 if (!ignore && (d->lastSelectionStart == d->lastSelectionEnd) && (ev->key() == Qt::Key_Right || ev->key() == Qt::Key_Left)) {
1282 // Ignore when moving off the end unless there is a selection,
1283 // because then moving will do something (deselect).
1284 int cursorPosition = d->m_cursor;
1285 if (cursorPosition == 0)
1286 ignore = ev->key() == (d->layoutDirection() == Qt::LeftToRight ? Qt::Key_Left : Qt::Key_Right);
1287 if (cursorPosition == text().length())
1288 ignore = ev->key() == (d->layoutDirection() == Qt::LeftToRight ? Qt::Key_Right : Qt::Key_Left);
1293 d->processKeyEvent(ev);
1295 if (!ev->isAccepted())
1296 QQuickImplicitSizeItem::keyPressEvent(ev);
1299 void QQuickTextInput::inputMethodEvent(QInputMethodEvent *ev)
1301 Q_D(QQuickTextInput);
1302 const bool wasComposing = d->preeditAreaText().length() > 0;
1303 if (d->m_readOnly) {
1306 d->processInputMethodEvent(ev);
1308 if (!ev->isAccepted())
1309 QQuickImplicitSizeItem::inputMethodEvent(ev);
1311 if (wasComposing != (d->m_textLayout.preeditAreaText().length() > 0))
1312 emit inputMethodComposingChanged();
1315 void QQuickTextInput::mouseDoubleClickEvent(QMouseEvent *event)
1317 Q_D(QQuickTextInput);
1319 if (d->selectByMouse && event->button() == Qt::LeftButton) {
1321 int cursor = d->positionAt(event->localPos());
1322 d->selectWordAtPos(cursor);
1323 event->setAccepted(true);
1324 if (!d->hasPendingTripleClick()) {
1325 d->tripleClickStartPoint = event->localPos().toPoint();
1326 d->tripleClickTimer.start();
1329 if (d->sendMouseEventToInputContext(event))
1331 QQuickImplicitSizeItem::mouseDoubleClickEvent(event);
1335 void QQuickTextInput::mousePressEvent(QMouseEvent *event)
1337 Q_D(QQuickTextInput);
1339 d->pressPos = event->localPos();
1341 if (d->focusOnPress) {
1342 bool hadActiveFocus = hasActiveFocus();
1344 // re-open input panel on press if already focused
1345 if (hasActiveFocus() && hadActiveFocus && !d->m_readOnly)
1346 openSoftwareInputPanel();
1348 if (d->selectByMouse) {
1349 setKeepMouseGrab(false);
1350 d->selectPressed = true;
1351 QPoint distanceVector = d->pressPos.toPoint() - d->tripleClickStartPoint;
1352 if (d->hasPendingTripleClick()
1353 && distanceVector.manhattanLength() < qApp->styleHints()->startDragDistance()) {
1354 event->setAccepted(true);
1360 if (d->sendMouseEventToInputContext(event))
1363 bool mark = (event->modifiers() & Qt::ShiftModifier) && d->selectByMouse;
1364 int cursor = d->positionAt(event->localPos());
1365 d->moveCursor(cursor, mark);
1366 event->setAccepted(true);
1369 void QQuickTextInput::mouseMoveEvent(QMouseEvent *event)
1371 Q_D(QQuickTextInput);
1373 if (d->selectPressed) {
1374 if (qAbs(int(event->localPos().x() - d->pressPos.x())) > qApp->styleHints()->startDragDistance())
1375 setKeepMouseGrab(true);
1377 if (d->composeMode()) {
1379 int startPos = d->positionAt(d->pressPos);
1380 int currentPos = d->positionAt(event->localPos());
1381 if (startPos != currentPos)
1382 d->setSelection(startPos, currentPos - startPos);
1384 moveCursorSelection(d->positionAt(event->localPos()), d->mouseSelectionMode);
1386 event->setAccepted(true);
1388 QQuickImplicitSizeItem::mouseMoveEvent(event);
1392 void QQuickTextInput::mouseReleaseEvent(QMouseEvent *event)
1394 Q_D(QQuickTextInput);
1395 if (d->sendMouseEventToInputContext(event))
1397 if (d->selectPressed) {
1398 d->selectPressed = false;
1399 setKeepMouseGrab(false);
1401 #ifndef QT_NO_CLIPBOARD
1402 if (QGuiApplication::clipboard()->supportsSelection()) {
1403 if (event->button() == Qt::LeftButton) {
1404 d->copy(QClipboard::Selection);
1405 } else if (!d->m_readOnly && event->button() == Qt::MidButton) {
1407 d->insert(QGuiApplication::clipboard()->text(QClipboard::Selection));
1411 if (!event->isAccepted())
1412 QQuickImplicitSizeItem::mouseReleaseEvent(event);
1415 bool QQuickTextInputPrivate::sendMouseEventToInputContext(QMouseEvent *event)
1417 #if !defined QT_NO_IM
1418 if (composeMode()) {
1419 int tmp_cursor = positionAt(event->localPos());
1420 int mousePos = tmp_cursor - m_cursor;
1421 if (mousePos >= 0 && mousePos <= m_textLayout.preeditAreaText().length()) {
1422 if (event->type() == QEvent::MouseButtonRelease) {
1423 qApp->inputPanel()->invokeAction(QInputPanel::Click, mousePos);
1436 void QQuickTextInput::mouseUngrabEvent()
1438 Q_D(QQuickTextInput);
1439 d->selectPressed = false;
1440 setKeepMouseGrab(false);
1443 bool QQuickTextInput::event(QEvent* ev)
1445 #ifndef QT_NO_SHORTCUT
1446 Q_D(QQuickTextInput);
1447 if (ev->type() == QEvent::ShortcutOverride) {
1450 QKeyEvent* ke = static_cast<QKeyEvent*>(ev);
1451 if (ke == QKeySequence::Copy
1452 || ke == QKeySequence::Paste
1453 || ke == QKeySequence::Cut
1454 || ke == QKeySequence::Redo
1455 || ke == QKeySequence::Undo
1456 || ke == QKeySequence::MoveToNextWord
1457 || ke == QKeySequence::MoveToPreviousWord
1458 || ke == QKeySequence::MoveToStartOfDocument
1459 || ke == QKeySequence::MoveToEndOfDocument
1460 || ke == QKeySequence::SelectNextWord
1461 || ke == QKeySequence::SelectPreviousWord
1462 || ke == QKeySequence::SelectStartOfLine
1463 || ke == QKeySequence::SelectEndOfLine
1464 || ke == QKeySequence::SelectStartOfBlock
1465 || ke == QKeySequence::SelectEndOfBlock
1466 || ke == QKeySequence::SelectStartOfDocument
1467 || ke == QKeySequence::SelectAll
1468 || ke == QKeySequence::SelectEndOfDocument) {
1470 } else if (ke->modifiers() == Qt::NoModifier || ke->modifiers() == Qt::ShiftModifier
1471 || ke->modifiers() == Qt::KeypadModifier) {
1472 if (ke->key() < Qt::Key_Escape) {
1476 switch (ke->key()) {
1477 case Qt::Key_Delete:
1480 case Qt::Key_Backspace:
1492 return QQuickImplicitSizeItem::event(ev);
1495 void QQuickTextInput::geometryChanged(const QRectF &newGeometry,
1496 const QRectF &oldGeometry)
1498 Q_D(QQuickTextInput);
1499 if (newGeometry.width() != oldGeometry.width())
1501 updateCursorRectangle();
1502 QQuickImplicitSizeItem::geometryChanged(newGeometry, oldGeometry);
1505 void QQuickTextInputPrivate::updateHorizontalScroll()
1507 Q_Q(QQuickTextInput);
1508 QTextLine currentLine = m_textLayout.lineForTextPosition(m_cursor + m_preeditCursor);
1509 const int preeditLength = m_textLayout.preeditAreaText().length();
1510 const int width = qMax(0, qFloor(q->width()));
1511 int widthUsed = currentLine.isValid() ? qRound(currentLine.naturalTextWidth()) : 0;
1512 int previousScroll = hscroll;
1514 if (!autoScroll || widthUsed <= width || m_echoMode == QQuickTextInput::NoEcho) {
1517 Q_ASSERT(currentLine.isValid());
1518 int cix = qRound(currentLine.cursorToX(m_cursor + preeditLength));
1519 if (cix - hscroll >= width) {
1520 // text doesn't fit, cursor is to the right of br (scroll right)
1521 hscroll = cix - width;
1522 } else if (cix - hscroll < 0 && hscroll < widthUsed) {
1523 // text doesn't fit, cursor is to the left of br (scroll left)
1525 } else if (widthUsed - hscroll < width) {
1526 // text doesn't fit, text document is to the left of br; align
1528 hscroll = widthUsed - width;
1530 if (preeditLength > 0) {
1531 // check to ensure long pre-edit text doesn't push the cursor
1533 cix = qRound(currentLine.cursorToX(m_cursor + qMax(0, m_preeditCursor - 1)));
1538 if (previousScroll != hscroll)
1539 textLayoutDirty = true;
1542 void QQuickTextInputPrivate::updateVerticalScroll()
1544 Q_Q(QQuickTextInput);
1545 const int preeditLength = m_textLayout.preeditAreaText().length();
1546 const int height = qMax(0, qFloor(q->height()));
1547 int heightUsed = boundingRect.height();
1548 int previousScroll = vscroll;
1550 if (!autoScroll || heightUsed <= height) {
1551 // text fits in br; use vscroll for alignment
1552 switch (vAlign & ~(Qt::AlignAbsolute|Qt::AlignHorizontal_Mask)) {
1553 case Qt::AlignBottom:
1554 vscroll = heightUsed - height;
1556 case Qt::AlignVCenter:
1557 vscroll = (heightUsed - height) / 2;
1565 QTextLine currentLine = m_textLayout.lineForTextPosition(m_cursor + preeditLength);
1566 QRectF r = currentLine.isValid() ? currentLine.rect() : QRectF();
1567 int top = qFloor(r.top());
1568 int bottom = qCeil(r.bottom());
1570 if (bottom - vscroll >= height) {
1571 // text doesn't fit, cursor is to the below the br (scroll down)
1572 vscroll = bottom - height;
1573 } else if (top - vscroll < 0 && vscroll < heightUsed) {
1574 // text doesn't fit, cursor is above br (scroll up)
1576 } else if (heightUsed - vscroll < height) {
1577 // text doesn't fit, text document is to the left of br; align
1579 vscroll = heightUsed - height;
1581 if (preeditLength > 0) {
1582 // check to ensure long pre-edit text doesn't push the cursor
1584 currentLine = m_textLayout.lineForTextPosition(m_cursor + qMax(0, m_preeditCursor - 1));
1585 top = currentLine.isValid() ? qRound(currentLine.rect().top()) : 0;
1590 if (previousScroll != vscroll)
1591 textLayoutDirty = true;
1594 QSGNode *QQuickTextInput::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data)
1597 Q_D(QQuickTextInput);
1599 QQuickTextNode *node = static_cast<QQuickTextNode *>(oldNode);
1601 node = new QQuickTextNode(QQuickItemPrivate::get(this)->sceneGraphContext());
1604 if (!d->textLayoutDirty) {
1605 QSGSimpleRectNode *cursorNode = node->cursorNode();
1606 if (cursorNode != 0 && !isReadOnly()) {
1607 cursorNode->setRect(cursorRectangle());
1609 if (!d->cursorVisible || (!d->m_blinkStatus && d->m_blinkPeriod > 0)) {
1616 node->deleteContent();
1617 node->setMatrix(QMatrix4x4());
1619 QPoint offset = QPoint(0,0);
1620 QFontMetrics fm = QFontMetrics(d->font);
1621 if (d->autoScroll) {
1622 // the y offset is there to keep the baseline constant in case we have script changes in the text.
1623 offset = -QPoint(d->hscroll, d->vscroll + d->m_ascent - fm.ascent());
1625 offset = -QPoint(d->hscroll, d->vscroll);
1628 if (!d->m_textLayout.text().isEmpty()) {
1629 node->addTextLayout(offset, &d->m_textLayout, d->color,
1630 QQuickText::Normal, QColor(),
1631 d->selectionColor, d->selectedTextColor,
1632 d->selectionStart(),
1633 d->selectionEnd() - 1); // selectionEnd() returns first char after
1637 if (!isReadOnly() && d->cursorItem == 0) {
1638 node->setCursor(cursorRectangle(), d->color);
1639 if (!d->cursorVisible || (!d->m_blinkStatus && d->m_blinkPeriod > 0)) {
1646 d->textLayoutDirty = false;
1652 QVariant QQuickTextInput::inputMethodQuery(Qt::InputMethodQuery property) const
1654 Q_D(const QQuickTextInput);
1657 return QVariant((bool)(flags() & ItemAcceptsInputMethod));
1659 return QVariant((int)inputMethodHints());
1660 case Qt::ImCursorRectangle:
1661 return cursorRectangle();
1664 case Qt::ImCursorPosition:
1665 return QVariant(d->m_cursor);
1666 case Qt::ImSurroundingText:
1667 if (d->m_echoMode == PasswordEchoOnEdit && !d->m_passwordEchoEditing) {
1668 return QVariant(displayText());
1670 return QVariant(d->realText());
1672 case Qt::ImCurrentSelection:
1673 return QVariant(selectedText());
1674 case Qt::ImMaximumTextLength:
1675 return QVariant(maxLength());
1676 case Qt::ImAnchorPosition:
1677 if (d->selectionStart() == d->selectionEnd())
1678 return QVariant(d->m_cursor);
1679 else if (d->selectionStart() == d->m_cursor)
1680 return QVariant(d->selectionEnd());
1682 return QVariant(d->selectionStart());
1689 \qmlmethod void QtQuick2::TextInput::deselect()
1691 Removes active text selection.
1693 void QQuickTextInput::deselect()
1695 Q_D(QQuickTextInput);
1700 \qmlmethod void QtQuick2::TextInput::selectAll()
1702 Causes all text to be selected.
1704 void QQuickTextInput::selectAll()
1706 Q_D(QQuickTextInput);
1707 d->setSelection(0, text().length());
1711 \qmlmethod void QtQuick2::TextInput::isRightToLeft(int start, int end)
1713 Returns true if the natural reading direction of the editor text
1714 found between positions \a start and \a end is right to left.
1716 bool QQuickTextInput::isRightToLeft(int start, int end)
1719 qmlInfo(this) << "isRightToLeft(start, end) called with the end property being smaller than the start.";
1722 return text().mid(start, end - start).isRightToLeft();
1726 #ifndef QT_NO_CLIPBOARD
1728 \qmlmethod QtQuick2::TextInput::cut()
1730 Moves the currently selected text to the system clipboard.
1732 void QQuickTextInput::cut()
1734 Q_D(QQuickTextInput);
1740 \qmlmethod QtQuick2::TextInput::copy()
1742 Copies the currently selected text to the system clipboard.
1744 void QQuickTextInput::copy()
1746 Q_D(QQuickTextInput);
1751 \qmlmethod QtQuick2::TextInput::paste()
1753 Replaces the currently selected text by the contents of the system clipboard.
1755 void QQuickTextInput::paste()
1757 Q_D(QQuickTextInput);
1761 #endif // QT_NO_CLIPBOARD
1764 Undoes the last operation if undo is \l {canUndo}{available}. Deselects any
1765 current selection, and updates the selection start to the current cursor
1769 void QQuickTextInput::undo()
1771 Q_D(QQuickTextInput);
1772 if (!d->m_readOnly) {
1774 d->finishChange(-1, true);
1779 Redoes the last operation if redo is \l {canRedo}{available}.
1782 void QQuickTextInput::redo()
1784 Q_D(QQuickTextInput);
1785 if (!d->m_readOnly) {
1792 \qmlmethod void QtQuick2::TextInput::insert(int position, string text)
1794 Inserts \a text into the TextInput at position.
1797 void QQuickTextInput::insert(int position, const QString &text)
1799 Q_D(QQuickTextInput);
1800 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
1801 if (d->m_echoMode == QQuickTextInput::Password)
1802 d->m_passwordEchoTimer.start(qt_passwordEchoDelay, this);
1805 if (position < 0 || position > d->m_text.length())
1808 const int priorState = d->m_undoState;
1810 QString insertText = text;
1812 if (d->hasSelectedText()) {
1813 d->addCommand(QQuickTextInputPrivate::Command(
1814 QQuickTextInputPrivate::SetSelection, d->m_cursor, 0, d->m_selstart, d->m_selend));
1816 if (d->m_maskData) {
1817 insertText = d->maskString(position, insertText);
1818 for (int i = 0; i < insertText.length(); ++i) {
1819 d->addCommand(QQuickTextInputPrivate::Command(
1820 QQuickTextInputPrivate::DeleteSelection, position + i, d->m_text.at(position + i), -1, -1));
1821 d->addCommand(QQuickTextInputPrivate::Command(
1822 QQuickTextInputPrivate::Insert, position + i, insertText.at(i), -1, -1));
1824 d->m_text.replace(position, insertText.length(), insertText);
1825 if (!insertText.isEmpty())
1826 d->m_textDirty = true;
1827 if (position < d->m_selend && position + insertText.length() > d->m_selstart)
1828 d->m_selDirty = true;
1830 int remaining = d->m_maxLength - d->m_text.length();
1831 if (remaining != 0) {
1832 insertText = insertText.left(remaining);
1833 d->m_text.insert(position, insertText);
1834 for (int i = 0; i < insertText.length(); ++i)
1835 d->addCommand(QQuickTextInputPrivate::Command(
1836 QQuickTextInputPrivate::Insert, position + i, insertText.at(i), -1, -1));
1837 if (d->m_cursor >= position)
1838 d->m_cursor += insertText.length();
1839 if (d->m_selstart >= position)
1840 d->m_selstart += insertText.length();
1841 if (d->m_selend >= position)
1842 d->m_selend += insertText.length();
1843 d->m_textDirty = true;
1844 if (position >= d->m_selstart && position <= d->m_selend)
1845 d->m_selDirty = true;
1849 d->addCommand(QQuickTextInputPrivate::Command(
1850 QQuickTextInputPrivate::SetSelection, d->m_cursor, 0, d->m_selstart, d->m_selend));
1851 d->finishChange(priorState);
1853 if (d->lastSelectionStart != d->lastSelectionEnd) {
1854 if (d->m_selstart != d->lastSelectionStart) {
1855 d->lastSelectionStart = d->m_selstart;
1856 emit selectionStartChanged();
1858 if (d->m_selend != d->lastSelectionEnd) {
1859 d->lastSelectionEnd = d->m_selend;
1860 emit selectionEndChanged();
1866 \qmlmethod string QtQuick2::TextInput::getText(int start, int end)
1868 Removes the section of text that is between the \a start and \a end positions from the TextInput.
1871 void QQuickTextInput::remove(int start, int end)
1873 Q_D(QQuickTextInput);
1875 start = qBound(0, start, d->m_text.length());
1876 end = qBound(0, end, d->m_text.length());
1880 else if (start == end)
1883 if (start < d->m_selend && end > d->m_selstart)
1884 d->m_selDirty = true;
1886 const int priorState = d->m_undoState;
1888 d->addCommand(QQuickTextInputPrivate::Command(
1889 QQuickTextInputPrivate::SetSelection, d->m_cursor, 0, d->m_selstart, d->m_selend));
1891 if (start <= d->m_cursor && d->m_cursor < end) {
1892 // cursor is within the selection. Split up the commands
1893 // to be able to restore the correct cursor position
1894 for (int i = d->m_cursor; i >= start; --i) {
1895 d->addCommand(QQuickTextInputPrivate::Command(
1896 QQuickTextInputPrivate::DeleteSelection, i, d->m_text.at(i), -1, 1));
1898 for (int i = end - 1; i > d->m_cursor; --i) {
1899 d->addCommand(QQuickTextInputPrivate::Command(
1900 QQuickTextInputPrivate::DeleteSelection, i - d->m_cursor + start - 1, d->m_text.at(i), -1, -1));
1903 for (int i = end - 1; i >= start; --i) {
1904 d->addCommand(QQuickTextInputPrivate::Command(
1905 QQuickTextInputPrivate::RemoveSelection, i, d->m_text.at(i), -1, -1));
1908 if (d->m_maskData) {
1909 d->m_text.replace(start, end - start, d->clearString(start, end - start));
1910 for (int i = 0; i < end - start; ++i) {
1911 d->addCommand(QQuickTextInputPrivate::Command(
1912 QQuickTextInputPrivate::Insert, start + i, d->m_text.at(start + i), -1, -1));
1915 d->m_text.remove(start, end - start);
1917 if (d->m_cursor > start)
1918 d->m_cursor -= qMin(d->m_cursor, end) - start;
1919 if (d->m_selstart > start)
1920 d->m_selstart -= qMin(d->m_selstart, end) - start;
1921 if (d->m_selend > end)
1922 d->m_selend -= qMin(d->m_selend, end) - start;
1924 d->addCommand(QQuickTextInputPrivate::Command(
1925 QQuickTextInputPrivate::SetSelection, d->m_cursor, 0, d->m_selstart, d->m_selend));
1927 d->m_textDirty = true;
1928 d->finishChange(priorState);
1930 if (d->lastSelectionStart != d->lastSelectionEnd) {
1931 if (d->m_selstart != d->lastSelectionStart) {
1932 d->lastSelectionStart = d->m_selstart;
1933 emit selectionStartChanged();
1935 if (d->m_selend != d->lastSelectionEnd) {
1936 d->lastSelectionEnd = d->m_selend;
1937 emit selectionEndChanged();
1944 \qmlmethod void QtQuick2::TextInput::selectWord()
1946 Causes the word closest to the current cursor position to be selected.
1948 void QQuickTextInput::selectWord()
1950 Q_D(QQuickTextInput);
1951 d->selectWordAtPos(d->m_cursor);
1955 \qmlproperty bool QtQuick2::TextInput::smooth
1957 This property holds whether the text is smoothly scaled or transformed.
1959 Smooth filtering gives better visual quality, but is slower. If
1960 the item is displayed at its natural size, this property has no visual or
1963 \note Generally scaling artifacts are only visible if the item is stationary on
1964 the screen. A common pattern when animating an item is to disable smooth
1965 filtering at the beginning of the animation and reenable it at the conclusion.
1969 \qmlproperty string QtQuick2::TextInput::passwordCharacter
1971 This is the character displayed when echoMode is set to Password or
1972 PasswordEchoOnEdit. By default it is an asterisk.
1974 If this property is set to a string with more than one character,
1975 the first character is used. If the string is empty, the value
1976 is ignored and the property is not set.
1978 QString QQuickTextInput::passwordCharacter() const
1980 Q_D(const QQuickTextInput);
1981 return QString(d->m_passwordCharacter);
1984 void QQuickTextInput::setPasswordCharacter(const QString &str)
1986 Q_D(QQuickTextInput);
1987 if (str.length() < 1)
1989 d->m_passwordCharacter = str.constData()[0];
1990 if (d->m_echoMode == Password || d->m_echoMode == PasswordEchoOnEdit)
1991 d->updateDisplayText();
1992 emit passwordCharacterChanged();
1996 \qmlproperty string QtQuick2::TextInput::displayText
1998 This is the text displayed in the TextInput.
2000 If \l echoMode is set to TextInput::Normal, this holds the
2001 same value as the TextInput::text property. Otherwise,
2002 this property holds the text visible to the user, while
2003 the \l text property holds the actual entered text.
2005 QString QQuickTextInput::displayText() const
2007 Q_D(const QQuickTextInput);
2008 return d->m_textLayout.text();
2012 \qmlproperty bool QtQuick2::TextInput::selectByMouse
2016 If true, the user can use the mouse to select text in some
2017 platform-specific way. Note that for some platforms this may
2018 not be an appropriate interaction (eg. may conflict with how
2019 the text needs to behave inside a Flickable.
2021 bool QQuickTextInput::selectByMouse() const
2023 Q_D(const QQuickTextInput);
2024 return d->selectByMouse;
2027 void QQuickTextInput::setSelectByMouse(bool on)
2029 Q_D(QQuickTextInput);
2030 if (d->selectByMouse != on) {
2031 d->selectByMouse = on;
2032 emit selectByMouseChanged(on);
2037 \qmlproperty enum QtQuick2::TextInput::mouseSelectionMode
2039 Specifies how text should be selected using a mouse.
2042 \o TextInput.SelectCharacters - The selection is updated with individual characters. (Default)
2043 \o TextInput.SelectWords - The selection is updated with whole words.
2046 This property only applies when \l selectByMouse is true.
2049 QQuickTextInput::SelectionMode QQuickTextInput::mouseSelectionMode() const
2051 Q_D(const QQuickTextInput);
2052 return d->mouseSelectionMode;
2055 void QQuickTextInput::setMouseSelectionMode(SelectionMode mode)
2057 Q_D(QQuickTextInput);
2058 if (d->mouseSelectionMode != mode) {
2059 d->mouseSelectionMode = mode;
2060 emit mouseSelectionModeChanged(mode);
2065 \qmlproperty bool QtQuick2::TextInput::canPaste
2067 Returns true if the TextInput is writable and the content of the clipboard is
2068 suitable for pasting into the TextEdit.
2070 bool QQuickTextInput::canPaste() const
2072 Q_D(const QQuickTextInput);
2073 if (!d->canPasteValid) {
2074 if (const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData())
2075 const_cast<QQuickTextInputPrivate *>(d)->canPaste = !d->m_readOnly && mimeData->hasText();
2076 const_cast<QQuickTextInputPrivate *>(d)->canPasteValid = true;
2082 \qmlproperty bool QtQuick2::TextInput::canUndo
2084 Returns true if the TextInput is writable and there are previous operations
2088 bool QQuickTextInput::canUndo() const
2090 Q_D(const QQuickTextInput);
2095 \qmlproperty bool QtQuick2::TextInput::canRedo
2097 Returns true if the TextInput is writable and there are \l {undo}{undone}
2098 operations that can be redone.
2101 bool QQuickTextInput::canRedo() const
2103 Q_D(const QQuickTextInput);
2107 void QQuickTextInput::moveCursorSelection(int position)
2109 Q_D(QQuickTextInput);
2110 d->moveCursor(position, true);
2114 \qmlmethod void QtQuick2::TextInput::moveCursorSelection(int position, SelectionMode mode = TextInput.SelectCharacters)
2116 Moves the cursor to \a position and updates the selection according to the optional \a mode
2117 parameter. (To only move the cursor, set the \l cursorPosition property.)
2119 When this method is called it additionally sets either the
2120 selectionStart or the selectionEnd (whichever was at the previous cursor position)
2121 to the specified position. This allows you to easily extend and contract the selected
2124 The selection mode specifies whether the selection is updated on a per character or a per word
2125 basis. If not specified the selection mode will default to TextInput.SelectCharacters.
2128 \o TextEdit.SelectCharacters - Sets either the selectionStart or selectionEnd (whichever was at
2129 the previous cursor position) to the specified position.
2130 \o TextEdit.SelectWords - Sets the selectionStart and selectionEnd to include all
2131 words between the specified position and the previous cursor position. Words partially in the
2135 For example, take this sequence of calls:
2139 moveCursorSelection(9, TextInput.SelectCharacters)
2140 moveCursorSelection(7, TextInput.SelectCharacters)
2143 This moves the cursor to position 5, extend the selection end from 5 to 9
2144 and then retract the selection end from 9 to 7, leaving the text from position 5 to 7
2145 selected (the 6th and 7th characters).
2147 The same sequence with TextInput.SelectWords will extend the selection start to a word boundary
2148 before or on position 5 and extend the selection end to a word boundary on or past position 9.
2150 void QQuickTextInput::moveCursorSelection(int pos, SelectionMode mode)
2152 Q_D(QQuickTextInput);
2154 if (mode == SelectCharacters) {
2155 d->moveCursor(pos, true);
2156 } else if (pos != d->m_cursor){
2157 const int cursor = d->m_cursor;
2159 if (!d->hasSelectedText())
2160 anchor = d->m_cursor;
2161 else if (d->selectionStart() == d->m_cursor)
2162 anchor = d->selectionEnd();
2164 anchor = d->selectionStart();
2166 if (anchor < pos || (anchor == pos && cursor < pos)) {
2167 const QString text = this->text();
2168 QTextBoundaryFinder finder(QTextBoundaryFinder::Word, text);
2169 finder.setPosition(anchor);
2171 const QTextBoundaryFinder::BoundaryReasons reasons = finder.boundaryReasons();
2172 if (anchor < text.length() && (!(reasons & QTextBoundaryFinder::StartWord)
2173 || ((reasons & QTextBoundaryFinder::EndWord) && anchor > cursor))) {
2174 finder.toPreviousBoundary();
2176 anchor = finder.position() != -1 ? finder.position() : 0;
2178 finder.setPosition(pos);
2179 if (pos > 0 && !finder.boundaryReasons())
2180 finder.toNextBoundary();
2181 const int cursor = finder.position() != -1 ? finder.position() : text.length();
2183 d->setSelection(anchor, cursor - anchor);
2184 } else if (anchor > pos || (anchor == pos && cursor > pos)) {
2185 const QString text = this->text();
2186 QTextBoundaryFinder finder(QTextBoundaryFinder::Word, text);
2187 finder.setPosition(anchor);
2189 const QTextBoundaryFinder::BoundaryReasons reasons = finder.boundaryReasons();
2190 if (anchor > 0 && (!(reasons & QTextBoundaryFinder::EndWord)
2191 || ((reasons & QTextBoundaryFinder::StartWord) && anchor < cursor))) {
2192 finder.toNextBoundary();
2195 anchor = finder.position() != -1 ? finder.position() : text.length();
2197 finder.setPosition(pos);
2198 if (pos < text.length() && !finder.boundaryReasons())
2199 finder.toPreviousBoundary();
2200 const int cursor = finder.position() != -1 ? finder.position() : 0;
2202 d->setSelection(anchor, cursor - anchor);
2208 \qmlmethod void QtQuick2::TextInput::openSoftwareInputPanel()
2210 Opens software input panels like virtual keyboards for typing, useful for
2211 customizing when you want the input keyboard to be shown and hidden in
2214 By default the opening of input panels follows the platform style. Input panels are
2215 always closed if no editor has active focus.
2217 You can disable the automatic behavior by setting the property \c activeFocusOnPress to false
2218 and use functions openSoftwareInputPanel() and closeSoftwareInputPanel() to implement
2219 the behavior you want.
2221 Only relevant on platforms, which provide virtual keyboards.
2227 text: "Hello world!"
2228 activeFocusOnPress: false
2230 anchors.fill: parent
2232 if (!textInput.activeFocus) {
2233 textInput.forceActiveFocus()
2234 textInput.openSoftwareInputPanel();
2236 textInput.focus = false;
2239 onPressAndHold: textInput.closeSoftwareInputPanel();
2244 void QQuickTextInput::openSoftwareInputPanel()
2247 qGuiApp->inputPanel()->show();
2251 \qmlmethod void QtQuick2::TextInput::closeSoftwareInputPanel()
2253 Closes a software input panel like a virtual keyboard shown on the screen, useful
2254 for customizing when you want the input keyboard to be shown and hidden in
2257 By default the opening of input panels follows the platform style. Input panels are
2258 always closed if no editor has active focus.
2260 You can disable the automatic behavior by setting the property \c activeFocusOnPress to false
2261 and use functions openSoftwareInputPanel() and closeSoftwareInputPanel() to implement
2262 the behavior you want.
2264 Only relevant on platforms, which provide virtual keyboards.
2270 text: "Hello world!"
2271 activeFocusOnPress: false
2273 anchors.fill: parent
2275 if (!textInput.activeFocus) {
2276 textInput.forceActiveFocus();
2277 textInput.openSoftwareInputPanel();
2279 textInput.focus = false;
2282 onPressAndHold: textInput.closeSoftwareInputPanel();
2287 void QQuickTextInput::closeSoftwareInputPanel()
2290 qGuiApp->inputPanel()->hide();
2293 void QQuickTextInput::focusInEvent(QFocusEvent *event)
2295 Q_D(const QQuickTextInput);
2296 if (d->focusOnPress && !d->m_readOnly)
2297 openSoftwareInputPanel();
2298 QQuickImplicitSizeItem::focusInEvent(event);
2301 void QQuickTextInput::itemChange(ItemChange change, const ItemChangeData &value)
2303 Q_D(QQuickTextInput);
2304 if (change == ItemActiveFocusHasChanged) {
2305 bool hasFocus = value.boolValue;
2306 d->focused = hasFocus;
2307 setCursorVisible(hasFocus); // ### refactor: && d->canvas && d->canvas->hasFocus()
2308 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
2309 if (!hasFocus && (d->m_passwordEchoEditing || d->m_passwordEchoTimer.isActive())) {
2311 if (!hasFocus && d->m_passwordEchoEditing) {
2313 d->updatePasswordEchoEditing(false);//QQuickTextInputPrivate sets it on key events, but doesn't deal with focus events
2321 QQuickItem::itemChange(change, value);
2325 \qmlproperty bool QtQuick2::TextInput::inputMethodComposing
2328 This property holds whether the TextInput has partial text input from an
2331 While it is composing an input method may rely on mouse or key events from
2332 the TextInput to edit or commit the partial text. This property can be
2333 used to determine when to disable events handlers that may interfere with
2334 the correct operation of an input method.
2336 bool QQuickTextInput::isInputMethodComposing() const
2338 Q_D(const QQuickTextInput);
2339 return d->preeditAreaText().length() > 0;
2342 void QQuickTextInputPrivate::init()
2344 Q_Q(QQuickTextInput);
2345 q->setSmooth(smooth);
2346 q->setAcceptedMouseButtons(Qt::LeftButton);
2347 q->setFlag(QQuickItem::ItemAcceptsInputMethod);
2348 q->setFlag(QQuickItem::ItemHasContents);
2349 #ifndef QT_NO_CLIPBOARD
2350 q->connect(QGuiApplication::clipboard(), SIGNAL(dataChanged()),
2351 q, SLOT(q_canPasteChanged()));
2352 #endif // QT_NO_CLIPBOARD
2354 lastSelectionStart = 0;
2355 lastSelectionEnd = 0;
2356 selectedTextColor = m_palette.color(QPalette::HighlightedText);
2357 selectionColor = m_palette.color(QPalette::Highlight);
2358 determineHorizontalAlignment();
2360 if (!qmlDisableDistanceField()) {
2361 QTextOption option = m_textLayout.textOption();
2362 option.setUseDesignMetrics(true);
2363 m_textLayout.setTextOption(option);
2367 void QQuickTextInput::updateCursorRectangle()
2369 Q_D(QQuickTextInput);
2370 if (!isComponentComplete())
2373 d->updateHorizontalScroll();
2374 d->updateVerticalScroll();
2376 emit cursorRectangleChanged();
2377 if (d->cursorItem) {
2378 QRectF r = cursorRectangle();
2379 d->cursorItem->setPos(r.topLeft());
2380 d->cursorItem->setHeight(r.height());
2384 void QQuickTextInput::selectionChanged()
2386 Q_D(QQuickTextInput);
2387 d->textLayoutDirty = true; //TODO: Only update rect in selection
2389 emit selectedTextChanged();
2391 if (d->lastSelectionStart != d->selectionStart()) {
2392 d->lastSelectionStart = d->selectionStart();
2393 if (d->lastSelectionStart == -1)
2394 d->lastSelectionStart = d->m_cursor;
2395 emit selectionStartChanged();
2397 if (d->lastSelectionEnd != d->selectionEnd()) {
2398 d->lastSelectionEnd = d->selectionEnd();
2399 if (d->lastSelectionEnd == -1)
2400 d->lastSelectionEnd = d->m_cursor;
2401 emit selectionEndChanged();
2405 void QQuickTextInputPrivate::showCursor()
2407 if (textNode != 0 && textNode->cursorNode() != 0)
2408 textNode->cursorNode()->setColor(color);
2411 void QQuickTextInputPrivate::hideCursor()
2413 if (textNode != 0 && textNode->cursorNode() != 0)
2414 textNode->cursorNode()->setColor(QColor(0, 0, 0, 0));
2417 QRectF QQuickTextInput::boundingRect() const
2419 Q_D(const QQuickTextInput);
2421 int cursorWidth = d->cursorItem ? d->cursorItem->width() : d->m_cursorWidth;
2423 // Could include font max left/right bearings to either side of rectangle.
2424 QRectF r = QQuickImplicitSizeItem::boundingRect();
2425 r.setRight(r.right() + cursorWidth);
2429 void QQuickTextInput::q_canPasteChanged()
2431 Q_D(QQuickTextInput);
2432 bool old = d->canPaste;
2433 #ifndef QT_NO_CLIPBOARD
2434 if (const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData())
2435 d->canPaste = !d->m_readOnly && mimeData->hasText();
2437 d->canPaste = false;
2440 bool changed = d->canPaste != old || !d->canPasteValid;
2441 d->canPasteValid = true;
2443 emit canPasteChanged();
2447 // ### these should come from QStyleHints
2448 const int textCursorWidth = 1;
2449 const bool fullWidthSelection = true;
2454 Updates the display text based of the current edit text
2455 If the text has changed will emit displayTextChanged()
2457 void QQuickTextInputPrivate::updateDisplayText(bool forceUpdate)
2459 QString orig = m_textLayout.text();
2461 if (m_echoMode == QQuickTextInput::NoEcho)
2462 str = QString::fromLatin1("");
2466 if (m_echoMode == QQuickTextInput::Password) {
2467 str.fill(m_passwordCharacter);
2468 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
2469 if (m_passwordEchoTimer.isActive() && m_cursor > 0 && m_cursor <= m_text.length()) {
2470 int cursor = m_cursor - 1;
2471 QChar uc = m_text.at(cursor);
2473 if (cursor > 0 && uc.unicode() >= 0xdc00 && uc.unicode() < 0xe000) {
2474 // second half of a surrogate, check if we have the first half as well,
2475 // if yes restore both at once
2476 uc = m_text.at(cursor - 1);
2477 if (uc.unicode() >= 0xd800 && uc.unicode() < 0xdc00)
2478 str[cursor - 1] = uc;
2482 } else if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit && !m_passwordEchoEditing) {
2483 str.fill(m_passwordCharacter);
2486 // replace certain non-printable characters with spaces (to avoid
2487 // drawing boxes when using fonts that don't have glyphs for such
2489 QChar* uc = str.data();
2490 for (int i = 0; i < (int)str.length(); ++i) {
2491 if ((uc[i] < 0x20 && uc[i] != 0x09)
2492 || uc[i] == QChar::LineSeparator
2493 || uc[i] == QChar::ParagraphSeparator
2494 || uc[i] == QChar::ObjectReplacementCharacter)
2495 uc[i] = QChar(0x0020);
2498 if (str != orig || forceUpdate) {
2499 m_textLayout.setText(str);
2500 updateLayout(); // polish?
2501 emit q_func()->displayTextChanged();
2505 void QQuickTextInputPrivate::updateLayout()
2507 Q_Q(QQuickTextInput);
2509 if (!q->isComponentComplete())
2512 QTextOption option = m_textLayout.textOption();
2513 option.setTextDirection(m_layoutDirection);
2514 option.setFlags(QTextOption::IncludeTrailingSpaces);
2515 option.setWrapMode(QTextOption::WrapMode(wrapMode));
2516 option.setAlignment(Qt::Alignment(q->effectiveHAlign()));
2517 m_textLayout.setTextOption(option);
2518 m_textLayout.setFont(font);
2520 boundingRect = QRectF();
2521 m_textLayout.beginLayout();
2522 QTextLine line = m_textLayout.createLine();
2523 qreal lineWidth = q->widthValid() ? q->width() : INT_MAX;
2525 QTextLine firstLine = line;
2527 line.setLineWidth(lineWidth);
2528 line.setPosition(QPointF(line.position().x(), height));
2529 boundingRect = boundingRect.united(line.naturalTextRect());
2531 height += line.height();
2532 line = m_textLayout.createLine();
2533 } while (line.isValid());
2534 m_textLayout.endLayout();
2536 option.setWrapMode(QTextOption::NoWrap);
2537 m_textLayout.setTextOption(option);
2539 m_ascent = qRound(firstLine.ascent());
2540 textLayoutDirty = true;
2543 q->setImplicitSize(qCeil(boundingRect.width()), qCeil(boundingRect.height()));
2547 #ifndef QT_NO_CLIPBOARD
2551 Copies the currently selected text into the clipboard using the given
2554 \note If the echo mode is set to a mode other than Normal then copy
2555 will not work. This is to prevent using copy as a method of bypassing
2556 password features of the line control.
2558 void QQuickTextInputPrivate::copy(QClipboard::Mode mode) const
2560 QString t = selectedText();
2561 if (!t.isEmpty() && m_echoMode == QQuickTextInput::Normal) {
2562 QGuiApplication::clipboard()->setText(t, mode);
2569 Inserts the text stored in the application clipboard into the line
2574 void QQuickTextInputPrivate::paste(QClipboard::Mode clipboardMode)
2576 QString clip = QGuiApplication::clipboard()->text(clipboardMode);
2577 if (!clip.isEmpty() || hasSelectedText()) {
2578 separate(); //make it a separate undo/redo command
2584 #endif // !QT_NO_CLIPBOARD
2589 Exits preedit mode and commits parts marked as tentative commit
2591 void QQuickTextInputPrivate::commitPreedit()
2596 qApp->inputPanel()->reset();
2598 if (!m_tentativeCommit.isEmpty()) {
2599 internalInsert(m_tentativeCommit);
2600 m_tentativeCommit.clear();
2601 finishChange(-1, true/*not used, not documented*/, false);
2604 m_preeditCursor = 0;
2605 m_textLayout.setPreeditArea(-1, QString());
2606 m_textLayout.clearAdditionalFormats();
2613 Handles the behavior for the backspace key or function.
2614 Removes the current selection if there is a selection, otherwise
2615 removes the character prior to the cursor position.
2619 void QQuickTextInputPrivate::backspace()
2621 int priorState = m_undoState;
2622 if (hasSelectedText()) {
2623 removeSelectedText();
2624 } else if (m_cursor) {
2627 m_cursor = prevMaskBlank(m_cursor);
2628 QChar uc = m_text.at(m_cursor);
2629 if (m_cursor > 0 && uc.unicode() >= 0xdc00 && uc.unicode() < 0xe000) {
2630 // second half of a surrogate, check if we have the first half as well,
2631 // if yes delete both at once
2632 uc = m_text.at(m_cursor - 1);
2633 if (uc.unicode() >= 0xd800 && uc.unicode() < 0xdc00) {
2634 internalDelete(true);
2638 internalDelete(true);
2640 finishChange(priorState);
2646 Handles the behavior for the delete key or function.
2647 Removes the current selection if there is a selection, otherwise
2648 removes the character after the cursor position.
2652 void QQuickTextInputPrivate::del()
2654 int priorState = m_undoState;
2655 if (hasSelectedText()) {
2656 removeSelectedText();
2658 int n = m_textLayout.nextCursorPosition(m_cursor) - m_cursor;
2662 finishChange(priorState);
2668 Inserts the given \a newText at the current cursor position.
2669 If there is any selected text it is removed prior to insertion of
2672 void QQuickTextInputPrivate::insert(const QString &newText)
2674 int priorState = m_undoState;
2675 removeSelectedText();
2676 internalInsert(newText);
2677 finishChange(priorState);
2683 Clears the line control text.
2685 void QQuickTextInputPrivate::clear()
2687 int priorState = m_undoState;
2689 m_selend = m_text.length();
2690 removeSelectedText();
2692 finishChange(priorState, /*update*/false, /*edited*/false);
2698 Sets \a length characters from the given \a start position as selected.
2699 The given \a start position must be within the current text for
2700 the line control. If \a length characters cannot be selected, then
2701 the selection will extend to the end of the current text.
2703 void QQuickTextInputPrivate::setSelection(int start, int length)
2705 Q_Q(QQuickTextInput);
2708 if (start < 0 || start > (int)m_text.length()){
2709 qWarning("QQuickTextInputPrivate::setSelection: Invalid start position");
2714 if (start == m_selstart && start + length == m_selend && m_cursor == m_selend)
2717 m_selend = qMin(start + length, (int)m_text.length());
2718 m_cursor = m_selend;
2719 } else if (length < 0){
2720 if (start == m_selend && start + length == m_selstart && m_cursor == m_selstart)
2722 m_selstart = qMax(start + length, 0);
2724 m_cursor = m_selstart;
2725 } else if (m_selstart != m_selend) {
2731 emitCursorPositionChanged();
2734 emit q->selectionChanged();
2735 emitCursorPositionChanged();
2736 qApp->inputPanel()->update(Qt::ImCursorRectangle | Qt::ImAnchorPosition
2737 | Qt::ImCursorPosition | Qt::ImCurrentSelection);
2743 Initializes the line control with a starting text value of \a txt.
2745 void QQuickTextInputPrivate::init(const QString &txt)
2749 updateDisplayText();
2750 m_cursor = m_text.length();
2756 Sets the password echo editing to \a editing. If password echo editing
2757 is true, then the text of the password is displayed even if the echo
2758 mode is set to QLineEdit::PasswordEchoOnEdit. Password echoing editing
2759 does not affect other echo modes.
2761 void QQuickTextInputPrivate::updatePasswordEchoEditing(bool editing)
2763 cancelPasswordEchoTimer();
2764 m_passwordEchoEditing = editing;
2765 updateDisplayText();
2771 Fixes the current text so that it is valid given any set validators.
2773 Returns true if the text was changed. Otherwise returns false.
2775 bool QQuickTextInputPrivate::fixup() // this function assumes that validate currently returns != Acceptable
2777 #ifndef QT_NO_VALIDATOR
2779 QString textCopy = m_text;
2780 int cursorCopy = m_cursor;
2781 m_validator->fixup(textCopy);
2782 if (m_validator->validate(textCopy, cursorCopy) == QValidator::Acceptable) {
2783 if (textCopy != m_text || cursorCopy != m_cursor)
2784 internalSetText(textCopy, cursorCopy);
2795 Moves the cursor to the given position \a pos. If \a mark is true will
2796 adjust the currently selected text.
2798 void QQuickTextInputPrivate::moveCursor(int pos, bool mark)
2800 Q_Q(QQuickTextInput);
2803 if (pos != m_cursor) {
2806 pos = pos > m_cursor ? nextMaskBlank(pos) : prevMaskBlank(pos);
2810 if (m_selend > m_selstart && m_cursor == m_selstart)
2812 else if (m_selend > m_selstart && m_cursor == m_selend)
2813 anchor = m_selstart;
2816 m_selstart = qMin(anchor, pos);
2817 m_selend = qMax(anchor, pos);
2822 if (mark || m_selDirty) {
2824 emit q->selectionChanged();
2826 emitCursorPositionChanged();
2827 q->updateMicroFocus();
2833 Applies the given input method event \a event to the text of the line
2836 void QQuickTextInputPrivate::processInputMethodEvent(QInputMethodEvent *event)
2838 Q_Q(QQuickTextInput);
2840 int priorState = -1;
2841 bool isGettingInput = !event->commitString().isEmpty()
2842 || event->preeditString() != preeditAreaText()
2843 || event->replacementLength() > 0;
2844 bool cursorPositionChanged = false;
2845 bool selectionChange = false;
2846 m_preeditDirty = event->preeditString() != preeditAreaText();
2848 if (isGettingInput) {
2849 // If any text is being input, remove selected text.
2850 priorState = m_undoState;
2851 if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit && !m_passwordEchoEditing) {
2852 updatePasswordEchoEditing(true);
2854 m_selend = m_text.length();
2856 removeSelectedText();
2859 int c = m_cursor; // cursor position after insertion of commit string
2860 if (event->replacementStart() <= 0)
2861 c += event->commitString().length() - qMin(-event->replacementStart(), event->replacementLength());
2863 m_cursor += event->replacementStart();
2867 // insert commit string
2868 if (event->replacementLength()) {
2869 m_selstart = m_cursor;
2870 m_selend = m_selstart + event->replacementLength();
2871 m_selend = qMin(m_selend, m_text.length());
2872 removeSelectedText();
2874 if (!event->commitString().isEmpty()) {
2875 internalInsert(event->commitString());
2876 cursorPositionChanged = true;
2879 m_cursor = qBound(0, c, m_text.length());
2881 for (int i = 0; i < event->attributes().size(); ++i) {
2882 const QInputMethodEvent::Attribute &a = event->attributes().at(i);
2883 if (a.type == QInputMethodEvent::Selection) {
2884 m_cursor = qBound(0, a.start + a.length, m_text.length());
2886 m_selstart = qMax(0, qMin(a.start, m_text.length()));
2887 m_selend = m_cursor;
2888 if (m_selend < m_selstart) {
2889 qSwap(m_selstart, m_selend);
2891 selectionChange = true;
2893 m_selstart = m_selend = 0;
2895 cursorPositionChanged = true;
2899 m_textLayout.setPreeditArea(m_cursor, event->preeditString());
2901 const int oldPreeditCursor = m_preeditCursor;
2902 m_preeditCursor = event->preeditString().length();
2903 m_hideCursor = false;
2904 QList<QTextLayout::FormatRange> formats;
2905 for (int i = 0; i < event->attributes().size(); ++i) {
2906 const QInputMethodEvent::Attribute &a = event->attributes().at(i);
2907 if (a.type == QInputMethodEvent::Cursor) {
2908 m_preeditCursor = a.start;
2909 m_hideCursor = !a.length;
2910 } else if (a.type == QInputMethodEvent::TextFormat) {
2911 QTextCharFormat f = qvariant_cast<QTextFormat>(a.value).toCharFormat();
2913 QTextLayout::FormatRange o;
2914 o.start = a.start + m_cursor;
2915 o.length = a.length;
2921 m_textLayout.setAdditionalFormats(formats);
2923 updateDisplayText(/*force*/ true);
2924 if (cursorPositionChanged) {
2925 emitCursorPositionChanged();
2926 } else if (m_preeditCursor != oldPreeditCursor) {
2927 q->updateCursorRectangle();
2928 qApp->inputPanel()->update(Qt::ImCursorRectangle);
2931 bool tentativeCommitChanged = m_tentativeCommit != event->tentativeCommitString();
2933 if (tentativeCommitChanged) {
2935 m_tentativeCommit = event->tentativeCommitString();
2938 if (isGettingInput || tentativeCommitChanged)
2939 finishChange(priorState);
2941 if (selectionChange) {
2942 emit q->selectionChanged();
2943 qApp->inputPanel()->update(Qt::ImCursorRectangle | Qt::ImAnchorPosition
2944 | Qt::ImCursorPosition | Qt::ImCurrentSelection);
2951 Sets the selection to cover the word at the given cursor position.
2952 The word boundaries are defined by the behavior of QTextLayout::SkipWords
2955 void QQuickTextInputPrivate::selectWordAtPos(int cursor)
2957 int next = cursor + 1;
2960 int c = m_textLayout.previousCursorPosition(next, QTextLayout::SkipWords);
2961 moveCursor(c, false);
2962 // ## text layout should support end of words.
2963 int end = m_textLayout.nextCursorPosition(c, QTextLayout::SkipWords);
2964 while (end > cursor && m_text[end-1].isSpace())
2966 moveCursor(end, true);
2972 Completes a change to the line control text. If the change is not valid
2973 will undo the line control state back to the given \a validateFromState.
2975 If \a edited is true and the change is valid, will emit textEdited() in
2976 addition to textChanged(). Otherwise only emits textChanged() on a valid
2979 The \a update value is currently unused.
2981 bool QQuickTextInputPrivate::finishChange(int validateFromState, bool update, bool /*edited*/)
2983 Q_Q(QQuickTextInput);
2986 bool notifyInputPanel = m_textDirty || m_selDirty;
2990 bool wasValidInput = m_validInput;
2991 m_validInput = true;
2992 #ifndef QT_NO_VALIDATOR
2994 QString textCopy = m_text;
2995 int cursorCopy = m_cursor;
2996 m_validInput = (m_validator->validate(textCopy, cursorCopy) != QValidator::Invalid);
2998 if (m_text != textCopy) {
2999 internalSetText(textCopy, cursorCopy);
3002 m_cursor = cursorCopy;
3004 if (!m_tentativeCommit.isEmpty()) {
3005 textCopy.insert(m_cursor, m_tentativeCommit);
3006 bool validInput = m_validator->validate(textCopy, cursorCopy) != QValidator::Invalid;
3008 m_tentativeCommit.clear();
3011 m_tentativeCommit.clear();
3015 if (validateFromState >= 0 && wasValidInput && !m_validInput) {
3016 if (m_transactions.count())
3018 internalUndo(validateFromState);
3019 m_history.resize(m_undoState);
3020 if (m_modifiedState > m_undoState)
3021 m_modifiedState = -1;
3022 m_validInput = true;
3023 m_textDirty = false;
3027 m_textDirty = false;
3028 m_preeditDirty = false;
3029 determineHorizontalAlignment();
3030 emit q->textChanged();
3033 updateDisplayText();
3035 if (m_validInput != wasValidInput)
3036 emit q->acceptableInputChanged();
3038 if (m_preeditDirty) {
3039 m_preeditDirty = false;
3040 determineHorizontalAlignment();
3045 emit q->selectionChanged();
3048 notifyInputPanel |= (m_cursor == m_lastCursorPos);
3049 if (notifyInputPanel)
3050 q->updateMicroFocus();
3051 emitUndoRedoChanged();
3052 emitCursorPositionChanged();
3060 An internal function for setting the text of the line control.
3062 void QQuickTextInputPrivate::internalSetText(const QString &txt, int pos, bool edited)
3064 Q_Q(QQuickTextInput);
3066 QString oldText = m_text;
3068 m_text = maskString(0, txt, true);
3069 m_text += clearString(m_text.length(), m_maxLength - m_text.length());
3071 m_text = txt.isEmpty() ? txt : txt.left(m_maxLength);
3074 m_modifiedState = m_undoState = 0;
3075 m_cursor = (pos < 0 || pos > m_text.length()) ? m_text.length() : pos;
3076 m_textDirty = (oldText != m_text);
3078 bool changed = finishChange(-1, true, edited);
3079 #ifdef QT_NO_ACCESSIBILITY
3083 QAccessible::updateAccessibility(q, 0, QAccessible::TextUpdated);
3091 Adds the given \a command to the undo history
3092 of the line control. Does not apply the command.
3094 void QQuickTextInputPrivate::addCommand(const Command &cmd)
3096 if (m_separator && m_undoState && m_history[m_undoState - 1].type != Separator) {
3097 m_history.resize(m_undoState + 2);
3098 m_history[m_undoState++] = Command(Separator, m_cursor, 0, m_selstart, m_selend);
3100 m_history.resize(m_undoState + 1);
3102 m_separator = false;
3103 m_history[m_undoState++] = cmd;
3109 Inserts the given string \a s into the line
3112 Also adds the appropriate commands into the undo history.
3113 This function does not call finishChange(), and may leave the text
3114 in an invalid state.
3116 void QQuickTextInputPrivate::internalInsert(const QString &s)
3118 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
3119 Q_Q(QQuickTextInput);
3120 if (m_echoMode == QQuickTextInput::Password)
3121 m_passwordEchoTimer.start(qt_passwordEchoDelay, q);
3123 if (hasSelectedText())
3124 addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
3126 QString ms = maskString(m_cursor, s);
3127 for (int i = 0; i < (int) ms.length(); ++i) {
3128 addCommand (Command(DeleteSelection, m_cursor + i, m_text.at(m_cursor + i), -1, -1));
3129 addCommand(Command(Insert, m_cursor + i, ms.at(i), -1, -1));
3131 m_text.replace(m_cursor, ms.length(), ms);
3132 m_cursor += ms.length();
3133 m_cursor = nextMaskBlank(m_cursor);
3136 int remaining = m_maxLength - m_text.length();
3137 if (remaining != 0) {
3138 m_text.insert(m_cursor, s.left(remaining));
3139 for (int i = 0; i < (int) s.left(remaining).length(); ++i)
3140 addCommand(Command(Insert, m_cursor++, s.at(i), -1, -1));
3149 deletes a single character from the current text. If \a wasBackspace,
3150 the character prior to the cursor is removed. Otherwise the character
3151 after the cursor is removed.
3153 Also adds the appropriate commands into the undo history.
3154 This function does not call finishChange(), and may leave the text
3155 in an invalid state.
3157 void QQuickTextInputPrivate::internalDelete(bool wasBackspace)
3159 if (m_cursor < (int) m_text.length()) {
3160 cancelPasswordEchoTimer();
3161 if (hasSelectedText())
3162 addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
3163 addCommand(Command((CommandType)((m_maskData ? 2 : 0) + (wasBackspace ? Remove : Delete)),
3164 m_cursor, m_text.at(m_cursor), -1, -1));
3166 m_text.replace(m_cursor, 1, clearString(m_cursor, 1));
3167 addCommand(Command(Insert, m_cursor, m_text.at(m_cursor), -1, -1));
3169 m_text.remove(m_cursor, 1);
3178 removes the currently selected text from the line control.
3180 Also adds the appropriate commands into the undo history.
3181 This function does not call finishChange(), and may leave the text
3182 in an invalid state.
3184 void QQuickTextInputPrivate::removeSelectedText()
3186 if (m_selstart < m_selend && m_selend <= (int) m_text.length()) {
3187 cancelPasswordEchoTimer();
3190 addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
3191 if (m_selstart <= m_cursor && m_cursor < m_selend) {
3192 // cursor is within the selection. Split up the commands
3193 // to be able to restore the correct cursor position
3194 for (i = m_cursor; i >= m_selstart; --i)
3195 addCommand (Command(DeleteSelection, i, m_text.at(i), -1, 1));
3196 for (i = m_selend - 1; i > m_cursor; --i)
3197 addCommand (Command(DeleteSelection, i - m_cursor + m_selstart - 1, m_text.at(i), -1, -1));
3199 for (i = m_selend-1; i >= m_selstart; --i)
3200 addCommand (Command(RemoveSelection, i, m_text.at(i), -1, -1));
3203 m_text.replace(m_selstart, m_selend - m_selstart, clearString(m_selstart, m_selend - m_selstart));
3204 for (int i = 0; i < m_selend - m_selstart; ++i)
3205 addCommand(Command(Insert, m_selstart + i, m_text.at(m_selstart + i), -1, -1));
3207 m_text.remove(m_selstart, m_selend - m_selstart);
3209 if (m_cursor > m_selstart)
3210 m_cursor -= qMin(m_cursor, m_selend) - m_selstart;
3219 Parses the input mask specified by \a maskFields to generate
3220 the mask data used to handle input masks.
3222 void QQuickTextInputPrivate::parseInputMask(const QString &maskFields)
3224 int delimiter = maskFields.indexOf(QLatin1Char(';'));
3225 if (maskFields.isEmpty() || delimiter == 0) {
3227 delete [] m_maskData;
3229 m_maxLength = 32767;
3230 internalSetText(QString());
3235 if (delimiter == -1) {
3236 m_blank = QLatin1Char(' ');
3237 m_inputMask = maskFields;
3239 m_inputMask = maskFields.left(delimiter);
3240 m_blank = (delimiter + 1 < maskFields.length()) ? maskFields[delimiter + 1] : QLatin1Char(' ');
3243 // calculate m_maxLength / m_maskData length
3246 for (int i=0; i<m_inputMask.length(); i++) {
3247 c = m_inputMask.at(i);
3248 if (i > 0 && m_inputMask.at(i-1) == QLatin1Char('\\')) {
3252 if (c != QLatin1Char('\\') && c != QLatin1Char('!') &&
3253 c != QLatin1Char('<') && c != QLatin1Char('>') &&
3254 c != QLatin1Char('{') && c != QLatin1Char('}') &&
3255 c != QLatin1Char('[') && c != QLatin1Char(']'))
3259 delete [] m_maskData;
3260 m_maskData = new MaskInputData[m_maxLength];
3262 MaskInputData::Casemode m = MaskInputData::NoCaseMode;
3265 bool escape = false;
3267 for (int i = 0; i < m_inputMask.length(); i++) {
3268 c = m_inputMask.at(i);
3271 m_maskData[index].maskChar = c;
3272 m_maskData[index].separator = s;
3273 m_maskData[index].caseMode = m;
3276 } else if (c == QLatin1Char('<')) {
3277 m = MaskInputData::Lower;
3278 } else if (c == QLatin1Char('>')) {
3279 m = MaskInputData::Upper;
3280 } else if (c == QLatin1Char('!')) {
3281 m = MaskInputData::NoCaseMode;
3282 } else if (c != QLatin1Char('{') && c != QLatin1Char('}') && c != QLatin1Char('[') && c != QLatin1Char(']')) {
3283 switch (c.unicode()) {
3309 m_maskData[index].maskChar = c;
3310 m_maskData[index].separator = s;
3311 m_maskData[index].caseMode = m;
3316 internalSetText(m_text);
3323 checks if the key is valid compared to the inputMask
3325 bool QQuickTextInputPrivate::isValidInput(QChar key, QChar mask) const
3327 switch (mask.unicode()) {
3333 if (key.isLetter() || key == m_blank)
3337 if (key.isLetterOrNumber())
3341 if (key.isLetterOrNumber() || key == m_blank)
3349 if (key.isPrint() || key == m_blank)
3357 if (key.isNumber() || key == m_blank)
3361 if (key.isNumber() && key.digitValue() > 0)
3365 if ((key.isNumber() && key.digitValue() > 0) || key == m_blank)
3369 if (key.isNumber() || key == QLatin1Char('+') || key == QLatin1Char('-') || key == m_blank)
3373 if (key == QLatin1Char('0') || key == QLatin1Char('1'))
3377 if (key == QLatin1Char('0') || key == QLatin1Char('1') || key == m_blank)
3381 if (key.isNumber() || (key >= QLatin1Char('a') && key <= QLatin1Char('f')) || (key >= QLatin1Char('A') && key <= QLatin1Char('F')))
3385 if (key.isNumber() || (key >= QLatin1Char('a') && key <= QLatin1Char('f')) || (key >= QLatin1Char('A') && key <= QLatin1Char('F')) || key == m_blank)
3397 Returns true if the given text \a str is valid for any
3398 validator or input mask set for the line control.
3400 Otherwise returns false
3402 bool QQuickTextInputPrivate::hasAcceptableInput(const QString &str) const
3404 #ifndef QT_NO_VALIDATOR
3405 QString textCopy = str;
3406 int cursorCopy = m_cursor;
3407 if (m_validator && m_validator->validate(textCopy, cursorCopy)
3408 != QValidator::Acceptable)
3415 if (str.length() != m_maxLength)
3418 for (int i=0; i < m_maxLength; ++i) {
3419 if (m_maskData[i].separator) {
3420 if (str.at(i) != m_maskData[i].maskChar)
3423 if (!isValidInput(str.at(i), m_maskData[i].maskChar))
3433 Applies the inputMask on \a str starting from position \a pos in the mask. \a clear
3434 specifies from where characters should be gotten when a separator is met in \a str - true means
3435 that blanks will be used, false that previous input is used.
3436 Calling this when no inputMask is set is undefined.
3438 QString QQuickTextInputPrivate::maskString(uint pos, const QString &str, bool clear) const
3440 if (pos >= (uint)m_maxLength)
3441 return QString::fromLatin1("");
3444 fill = clear ? clearString(0, m_maxLength) : m_text;
3447 QString s = QString::fromLatin1("");
3449 while (i < m_maxLength) {
3450 if (strIndex < str.length()) {
3451 if (m_maskData[i].separator) {
3452 s += m_maskData[i].maskChar;
3453 if (str[(int)strIndex] == m_maskData[i].maskChar)
3457 if (isValidInput(str[(int)strIndex], m_maskData[i].maskChar)) {
3458 switch (m_maskData[i].caseMode) {
3459 case MaskInputData::Upper:
3460 s += str[(int)strIndex].toUpper();
3462 case MaskInputData::Lower:
3463 s += str[(int)strIndex].toLower();
3466 s += str[(int)strIndex];
3470 // search for separator first
3471 int n = findInMask(i, true, true, str[(int)strIndex]);
3473 if (str.length() != 1 || i == 0 || (i > 0 && (!m_maskData[i-1].separator || m_maskData[i-1].maskChar != str[(int)strIndex]))) {
3474 s += fill.mid(i, n-i+1);
3475 i = n + 1; // update i to find + 1
3478 // search for valid m_blank if not
3479 n = findInMask(i, true, false, str[(int)strIndex]);
3481 s += fill.mid(i, n-i);
3482 switch (m_maskData[n].caseMode) {
3483 case MaskInputData::Upper:
3484 s += str[(int)strIndex].toUpper();
3486 case MaskInputData::Lower:
3487 s += str[(int)strIndex].toLower();
3490 s += str[(int)strIndex];
3492 i = n + 1; // updates i to find + 1
3510 Returns a "cleared" string with only separators and blank chars.
3511 Calling this when no inputMask is set is undefined.
3513 QString QQuickTextInputPrivate::clearString(uint pos, uint len) const
3515 if (pos >= (uint)m_maxLength)
3519 int end = qMin((uint)m_maxLength, pos + len);
3520 for (int i = pos; i < end; ++i)
3521 if (m_maskData[i].separator)
3522 s += m_maskData[i].maskChar;
3532 Strips blank parts of the input in a QQuickTextInputPrivate when an inputMask is set,
3533 separators are still included. Typically "127.0__.0__.1__" becomes "127.0.0.1".
3535 QString QQuickTextInputPrivate::stripString(const QString &str) const
3541 int end = qMin(m_maxLength, (int)str.length());
3542 for (int i = 0; i < end; ++i) {
3543 if (m_maskData[i].separator)
3544 s += m_maskData[i].maskChar;
3545 else if (str[i] != m_blank)
3554 searches forward/backward in m_maskData for either a separator or a m_blank
3556 int QQuickTextInputPrivate::findInMask(int pos, bool forward, bool findSeparator, QChar searchChar) const
3558 if (pos >= m_maxLength || pos < 0)
3561 int end = forward ? m_maxLength : -1;
3562 int step = forward ? 1 : -1;
3566 if (findSeparator) {
3567 if (m_maskData[i].separator && m_maskData[i].maskChar == searchChar)
3570 if (!m_maskData[i].separator) {
3571 if (searchChar.isNull())
3573 else if (isValidInput(searchChar, m_maskData[i].maskChar))
3582 void QQuickTextInputPrivate::internalUndo(int until)
3584 if (!isUndoAvailable())
3586 cancelPasswordEchoTimer();
3588 while (m_undoState && m_undoState > until) {
3589 Command& cmd = m_history[--m_undoState];
3592 m_text.remove(cmd.pos, 1);
3596 m_selstart = cmd.selStart;
3597 m_selend = cmd.selEnd;
3601 case RemoveSelection:
3602 m_text.insert(cmd.pos, cmd.uc);
3603 m_cursor = cmd.pos + 1;
3606 case DeleteSelection:
3607 m_text.insert(cmd.pos, cmd.uc);
3613 if (until < 0 && m_undoState) {
3614 Command& next = m_history[m_undoState-1];
3615 if (next.type != cmd.type && next.type < RemoveSelection
3616 && (cmd.type < RemoveSelection || next.type == Separator))
3623 void QQuickTextInputPrivate::internalRedo()
3625 if (!isRedoAvailable())
3628 while (m_undoState < (int)m_history.size()) {
3629 Command& cmd = m_history[m_undoState++];
3632 m_text.insert(cmd.pos, cmd.uc);
3633 m_cursor = cmd.pos + 1;
3636 m_selstart = cmd.selStart;
3637 m_selend = cmd.selEnd;
3642 case RemoveSelection:
3643 case DeleteSelection:
3644 m_text.remove(cmd.pos, 1);
3645 m_selstart = cmd.selStart;
3646 m_selend = cmd.selEnd;
3650 m_selstart = cmd.selStart;
3651 m_selend = cmd.selEnd;
3655 if (m_undoState < (int)m_history.size()) {
3656 Command& next = m_history[m_undoState];
3657 if (next.type != cmd.type && cmd.type < RemoveSelection && next.type != Separator
3658 && (next.type < RemoveSelection || cmd.type == Separator))
3665 void QQuickTextInputPrivate::emitUndoRedoChanged()
3667 Q_Q(QQuickTextInput);
3668 const bool previousUndo = canUndo;
3669 const bool previousRedo = canRedo;
3671 canUndo = isUndoAvailable();
3672 canRedo = isRedoAvailable();
3674 if (previousUndo != canUndo)
3675 emit q->canUndoChanged();
3676 if (previousRedo != canRedo)
3677 emit q->canRedoChanged();
3683 If the current cursor position differs from the last emitted cursor
3684 position, emits cursorPositionChanged().
3686 void QQuickTextInputPrivate::emitCursorPositionChanged()
3688 Q_Q(QQuickTextInput);
3689 if (m_cursor != m_lastCursorPos) {
3690 m_lastCursorPos = m_cursor;
3692 q->updateCursorRectangle();
3693 emit q->cursorPositionChanged();
3694 // XXX todo - not in 4.8?
3696 resetCursorBlinkTimer();
3699 if (!hasSelectedText()) {
3700 if (lastSelectionStart != m_cursor) {
3701 lastSelectionStart = m_cursor;
3702 emit q->selectionStartChanged();
3704 if (lastSelectionEnd != m_cursor) {
3705 lastSelectionEnd = m_cursor;
3706 emit q->selectionEndChanged();
3710 #ifndef QT_NO_ACCESSIBILITY
3711 QAccessible::updateAccessibility(q, 0, QAccessible::TextCaretMoved);
3717 void QQuickTextInputPrivate::setCursorBlinkPeriod(int msec)
3719 Q_Q(QQuickTextInput);
3720 if (msec == m_blinkPeriod)
3723 q->killTimer(m_blinkTimer);
3726 m_blinkTimer = q->startTimer(msec / 2);
3730 if (m_blinkStatus == 1)
3733 m_blinkPeriod = msec;
3736 void QQuickTextInputPrivate::resetCursorBlinkTimer()
3738 Q_Q(QQuickTextInput);
3739 if (m_blinkPeriod == 0 || m_blinkTimer == 0)
3741 q->killTimer(m_blinkTimer);
3742 m_blinkTimer = q->startTimer(m_blinkPeriod / 2);
3746 void QQuickTextInput::timerEvent(QTimerEvent *event)
3748 Q_D(QQuickTextInput);
3749 if (event->timerId() == d->m_blinkTimer) {
3750 d->m_blinkStatus = !d->m_blinkStatus;
3752 } else if (event->timerId() == d->m_deleteAllTimer) {
3753 killTimer(d->m_deleteAllTimer);
3754 d->m_deleteAllTimer = 0;
3756 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
3757 } else if (event->timerId() == d->m_passwordEchoTimer.timerId()) {
3758 d->m_passwordEchoTimer.stop();
3759 d->updateDisplayText();
3764 void QQuickTextInputPrivate::processKeyEvent(QKeyEvent* event)
3766 Q_Q(QQuickTextInput);
3767 bool inlineCompletionAccepted = false;
3769 if (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return) {
3770 if (hasAcceptableInput(m_text) || fixup()) {
3773 if (inlineCompletionAccepted)
3780 if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit
3781 && !m_passwordEchoEditing
3783 && !event->text().isEmpty()
3784 && !(event->modifiers() & Qt::ControlModifier)) {
3785 // Clear the edit and reset to normal echo mode while editing; the
3786 // echo mode switches back when the edit loses focus
3787 // ### resets current content. dubious code; you can
3788 // navigate with keys up, down, back, and select(?), but if you press
3789 // "left" or "right" it clears?
3790 updatePasswordEchoEditing(true);
3794 bool unknown = false;
3795 bool visual = cursorMoveStyle() == Qt::VisualMoveStyle;
3799 #ifndef QT_NO_SHORTCUT
3800 else if (event == QKeySequence::Undo) {
3804 else if (event == QKeySequence::Redo) {
3808 else if (event == QKeySequence::SelectAll) {
3811 #ifndef QT_NO_CLIPBOARD
3812 else if (event == QKeySequence::Copy) {
3815 else if (event == QKeySequence::Paste) {
3817 QClipboard::Mode mode = QClipboard::Clipboard;
3821 else if (event == QKeySequence::Cut) {
3827 else if (event == QKeySequence::DeleteEndOfLine) {
3829 setSelection(m_cursor, end());
3834 #endif //QT_NO_CLIPBOARD
3835 else if (event == QKeySequence::MoveToStartOfLine || event == QKeySequence::MoveToStartOfBlock) {
3838 else if (event == QKeySequence::MoveToEndOfLine || event == QKeySequence::MoveToEndOfBlock) {
3841 else if (event == QKeySequence::SelectStartOfLine || event == QKeySequence::SelectStartOfBlock) {
3844 else if (event == QKeySequence::SelectEndOfLine || event == QKeySequence::SelectEndOfBlock) {
3847 else if (event == QKeySequence::MoveToNextChar) {
3848 if (hasSelectedText()) {
3849 moveCursor(selectionEnd(), false);
3851 cursorForward(0, visual ? 1 : (layoutDirection() == Qt::LeftToRight ? 1 : -1));
3854 else if (event == QKeySequence::SelectNextChar) {
3855 cursorForward(1, visual ? 1 : (layoutDirection() == Qt::LeftToRight ? 1 : -1));
3857 else if (event == QKeySequence::MoveToPreviousChar) {
3858 if (hasSelectedText()) {
3859 moveCursor(selectionStart(), false);
3861 cursorForward(0, visual ? -1 : (layoutDirection() == Qt::LeftToRight ? -1 : 1));
3864 else if (event == QKeySequence::SelectPreviousChar) {
3865 cursorForward(1, visual ? -1 : (layoutDirection() == Qt::LeftToRight ? -1 : 1));
3867 else if (event == QKeySequence::MoveToNextWord) {
3868 if (m_echoMode == QQuickTextInput::Normal)
3869 layoutDirection() == Qt::LeftToRight ? cursorWordForward(0) : cursorWordBackward(0);
3871 layoutDirection() == Qt::LeftToRight ? end(0) : home(0);
3873 else if (event == QKeySequence::MoveToPreviousWord) {
3874 if (m_echoMode == QQuickTextInput::Normal)
3875 layoutDirection() == Qt::LeftToRight ? cursorWordBackward(0) : cursorWordForward(0);
3876 else if (!m_readOnly) {
3877 layoutDirection() == Qt::LeftToRight ? home(0) : end(0);
3880 else if (event == QKeySequence::SelectNextWord) {
3881 if (m_echoMode == QQuickTextInput::Normal)
3882 layoutDirection() == Qt::LeftToRight ? cursorWordForward(1) : cursorWordBackward(1);
3884 layoutDirection() == Qt::LeftToRight ? end(1) : home(1);
3886 else if (event == QKeySequence::SelectPreviousWord) {
3887 if (m_echoMode == QQuickTextInput::Normal)
3888 layoutDirection() == Qt::LeftToRight ? cursorWordBackward(1) : cursorWordForward(1);
3890 layoutDirection() == Qt::LeftToRight ? home(1) : end(1);
3892 else if (event == QKeySequence::Delete) {
3896 else if (event == QKeySequence::DeleteEndOfWord) {
3898 cursorWordForward(true);
3902 else if (event == QKeySequence::DeleteStartOfWord) {
3904 cursorWordBackward(true);
3908 #endif // QT_NO_SHORTCUT
3910 bool handled = false;
3911 if (event->modifiers() & Qt::ControlModifier) {
3912 switch (event->key()) {
3913 case Qt::Key_Backspace:
3915 cursorWordBackward(true);
3923 } else { // ### check for *no* modifier
3924 switch (event->key()) {
3925 case Qt::Key_Backspace:
3937 if (event->key() == Qt::Key_Direction_L || event->key() == Qt::Key_Direction_R) {
3938 setLayoutDirection((event->key() == Qt::Key_Direction_L) ? Qt::LeftToRight : Qt::RightToLeft);
3942 if (unknown && !m_readOnly) {
3943 QString t = event->text();
3944 if (!t.isEmpty() && t.at(0).isPrint()) {