1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the QtDeclarative module of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #include "qquicktextinput_p.h"
43 #include "qquicktextinput_p_p.h"
44 #include "qquickcanvas.h"
46 #include <private/qdeclarativeglobal_p.h>
48 #include <QtDeclarative/qdeclarativeinfo.h>
49 #include <QtGui/qevent.h>
50 #include <QTextBoundaryFinder>
51 #include "qquicktextnode_p.h"
52 #include <QtQuick/qsgsimplerectnode.h>
54 #include <QtGui/qstylehints.h>
55 #include <QtGui/qinputpanel.h>
57 #ifndef QT_NO_ACCESSIBILITY
58 #include "qaccessible.h"
63 DEFINE_BOOL_CONFIG_OPTION(qmlDisableDistanceField, QML_DISABLE_DISTANCEFIELD)
65 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
66 static const int qt_passwordEchoDelay = QT_GUI_PASSWORD_ECHO_DELAY;
70 \qmlclass TextInput QQuickTextInput
71 \inqmlmodule QtQuick 2
72 \ingroup qml-basic-visual-elements
73 \brief The TextInput item displays an editable line of text.
76 The TextInput element displays a single line of editable plain text.
78 TextInput is used to accept a line of text input. Input constraints
79 can be placed on a TextInput item (for example, through a \l validator or \l inputMask),
80 and setting \l echoMode to an appropriate value enables TextInput to be used for
81 a password input field.
83 On Mac OS X, the Up/Down key bindings for Home/End are explicitly disabled.
84 If you want such bindings (on any platform), you will need to construct them in QML.
86 \sa TextEdit, Text, {declarative/text/textselection}{Text Selection example}
88 QQuickTextInput::QQuickTextInput(QQuickItem* parent)
89 : QQuickImplicitSizeItem(*(new QQuickTextInputPrivate), parent)
95 QQuickTextInput::~QQuickTextInput()
99 void QQuickTextInput::componentComplete()
101 Q_D(QQuickTextInput);
103 QQuickImplicitSizeItem::componentComplete();
106 updateCursorRectangle();
107 if (d->cursorComponent && d->cursorComponent->isReady())
112 \qmlproperty string QtQuick2::TextInput::text
114 The text in the TextInput.
116 QString QQuickTextInput::text() const
118 Q_D(const QQuickTextInput);
120 QString content = d->m_text;
121 if (!d->m_tentativeCommit.isEmpty())
122 content.insert(d->m_cursor, d->m_tentativeCommit);
123 QString res = d->m_maskData ? d->stripString(content) : content;
124 return (res.isNull() ? QString::fromLatin1("") : res);
127 void QQuickTextInput::setText(const QString &s)
129 Q_D(QQuickTextInput);
132 if (d->composeMode())
133 qApp->inputPanel()->reset();
134 d->m_tentativeCommit.clear();
135 d->internalSetText(s, -1, false);
139 \qmlproperty int QtQuick2::TextInput::length
141 Returns the total number of characters in the TextInput item.
143 If the TextInput has an inputMask the length will include mask characters and may differ
144 from the length of the string returned by the \l text property.
146 This property can be faster than querying the length the \l text property as it doesn't
147 require any copying or conversion of the TextInput's internal string data.
150 int QQuickTextInput::length() const
152 Q_D(const QQuickTextInput);
153 return d->m_text.length();
157 \qmlmethod string QtQuick2::TextInput::getText(int start, int end)
159 Returns the section of text that is between the \a start and \a end positions.
161 If the TextInput has an inputMask the length will include mask characters.
164 QString QQuickTextInput::getText(int start, int end) const
166 Q_D(const QQuickTextInput);
171 return d->m_text.mid(start, end - start);
174 QString QQuickTextInputPrivate::realText() const
176 QString res = m_maskData ? stripString(m_text) : m_text;
177 return (res.isNull() ? QString::fromLatin1("") : res);
181 \qmlproperty string QtQuick2::TextInput::font.family
183 Sets the family name of the font.
185 The family name is case insensitive and may optionally include a foundry name, e.g. "Helvetica [Cronyx]".
186 If the family is available from more than one foundry and the foundry isn't specified, an arbitrary foundry is chosen.
187 If the family isn't available a family will be set using the font matching algorithm.
191 \qmlproperty bool QtQuick2::TextInput::font.bold
193 Sets whether the font weight is bold.
197 \qmlproperty enumeration QtQuick2::TextInput::font.weight
199 Sets the font's weight.
201 The weight can be one of:
204 \o Font.Normal - the default
211 TextInput { text: "Hello"; font.weight: Font.DemiBold }
216 \qmlproperty bool QtQuick2::TextInput::font.italic
218 Sets whether the font has an italic style.
222 \qmlproperty bool QtQuick2::TextInput::font.underline
224 Sets whether the text is underlined.
228 \qmlproperty bool QtQuick2::TextInput::font.strikeout
230 Sets whether the font has a strikeout style.
234 \qmlproperty real QtQuick2::TextInput::font.pointSize
236 Sets the font size in points. The point size must be greater than zero.
240 \qmlproperty int QtQuick2::TextInput::font.pixelSize
242 Sets the font size in pixels.
244 Using this function makes the font device dependent.
245 Use \c pointSize to set the size of the font in a device independent manner.
249 \qmlproperty real QtQuick2::TextInput::font.letterSpacing
251 Sets the letter spacing for the font.
253 Letter spacing changes the default spacing between individual letters in the font.
254 A positive value increases the letter spacing by the corresponding pixels; a negative value decreases the spacing.
258 \qmlproperty real QtQuick2::TextInput::font.wordSpacing
260 Sets the word spacing for the font.
262 Word spacing changes the default spacing between individual words.
263 A positive value increases the word spacing by a corresponding amount of pixels,
264 while a negative value decreases the inter-word spacing accordingly.
268 \qmlproperty enumeration QtQuick2::TextInput::font.capitalization
270 Sets the capitalization for the text.
273 \o Font.MixedCase - This is the normal text rendering option where no capitalization change is applied.
274 \o Font.AllUppercase - This alters the text to be rendered in all uppercase type.
275 \o Font.AllLowercase - This alters the text to be rendered in all lowercase type.
276 \o Font.SmallCaps - This alters the text to be rendered in small-caps type.
277 \o Font.Capitalize - This alters the text to be rendered with the first character of each word as an uppercase character.
281 TextInput { text: "Hello"; font.capitalization: Font.AllLowercase }
285 QFont QQuickTextInput::font() const
287 Q_D(const QQuickTextInput);
288 return d->sourceFont;
291 void QQuickTextInput::setFont(const QFont &font)
293 Q_D(QQuickTextInput);
294 if (d->sourceFont == font)
297 d->sourceFont = font;
298 QFont oldFont = d->font;
300 if (d->font.pointSizeF() != -1) {
302 qreal size = qRound(d->font.pointSizeF()*2.0);
303 d->font.setPointSizeF(size/2.0);
305 if (oldFont != d->font) {
307 updateCursorRectangle();
308 qApp->inputPanel()->update(Qt::ImCursorRectangle | Qt::ImFont);
310 emit fontChanged(d->sourceFont);
314 \qmlproperty color QtQuick2::TextInput::color
318 QColor QQuickTextInput::color() const
320 Q_D(const QQuickTextInput);
324 void QQuickTextInput::setColor(const QColor &c)
326 Q_D(QQuickTextInput);
329 d->textLayoutDirty = true;
331 emit colorChanged(c);
337 \qmlproperty color QtQuick2::TextInput::selectionColor
339 The text highlight color, used behind selections.
341 QColor QQuickTextInput::selectionColor() const
343 Q_D(const QQuickTextInput);
344 return d->selectionColor;
347 void QQuickTextInput::setSelectionColor(const QColor &color)
349 Q_D(QQuickTextInput);
350 if (d->selectionColor == color)
353 d->selectionColor = color;
354 d->m_palette.setColor(QPalette::Highlight, d->selectionColor);
355 if (d->hasSelectedText()) {
356 d->textLayoutDirty = true;
359 emit selectionColorChanged(color);
362 \qmlproperty color QtQuick2::TextInput::selectedTextColor
364 The highlighted text color, used in selections.
366 QColor QQuickTextInput::selectedTextColor() const
368 Q_D(const QQuickTextInput);
369 return d->selectedTextColor;
372 void QQuickTextInput::setSelectedTextColor(const QColor &color)
374 Q_D(QQuickTextInput);
375 if (d->selectedTextColor == color)
378 d->selectedTextColor = color;
379 d->m_palette.setColor(QPalette::HighlightedText, d->selectedTextColor);
380 if (d->hasSelectedText()) {
381 d->textLayoutDirty = true;
384 emit selectedTextColorChanged(color);
388 \qmlproperty enumeration QtQuick2::TextInput::horizontalAlignment
389 \qmlproperty enumeration QtQuick2::TextInput::effectiveHorizontalAlignment
390 \qmlproperty enumeration QtQuick2::TextInput::verticalAlignment
392 Sets the horizontal alignment of the text within the TextInput item's
393 width and height. By default, the text alignment follows the natural alignment
394 of the text, for example text that is read from left to right will be aligned to
397 TextInput does not have vertical alignment, as the natural height is
398 exactly the height of the single line of text. If you set the height
399 manually to something larger, TextInput will always be top aligned
400 vertically. You can use anchors to align it however you want within
403 The valid values for \c horizontalAlignment are \c TextInput.AlignLeft, \c TextInput.AlignRight and
404 \c TextInput.AlignHCenter.
406 Valid values for \c verticalAlignment are \c TextEdit.AlignTop (default),
407 \c TextEdit.AlignBottom \c TextEdit.AlignVCenter.
409 When using the attached property LayoutMirroring::enabled to mirror application
410 layouts, the horizontal alignment of text will also be mirrored. However, the property
411 \c horizontalAlignment will remain unchanged. To query the effective horizontal alignment
412 of TextInput, use the read-only property \c effectiveHorizontalAlignment.
414 QQuickTextInput::HAlignment QQuickTextInput::hAlign() const
416 Q_D(const QQuickTextInput);
420 void QQuickTextInput::setHAlign(HAlignment align)
422 Q_D(QQuickTextInput);
423 bool forceAlign = d->hAlignImplicit && d->effectiveLayoutMirror;
424 d->hAlignImplicit = false;
425 if (d->setHAlign(align, forceAlign) && isComponentComplete()) {
427 updateCursorRectangle();
431 void QQuickTextInput::resetHAlign()
433 Q_D(QQuickTextInput);
434 d->hAlignImplicit = true;
435 if (d->determineHorizontalAlignment() && isComponentComplete()) {
437 updateCursorRectangle();
441 QQuickTextInput::HAlignment QQuickTextInput::effectiveHAlign() const
443 Q_D(const QQuickTextInput);
444 QQuickTextInput::HAlignment effectiveAlignment = d->hAlign;
445 if (!d->hAlignImplicit && d->effectiveLayoutMirror) {
447 case QQuickTextInput::AlignLeft:
448 effectiveAlignment = QQuickTextInput::AlignRight;
450 case QQuickTextInput::AlignRight:
451 effectiveAlignment = QQuickTextInput::AlignLeft;
457 return effectiveAlignment;
460 bool QQuickTextInputPrivate::setHAlign(QQuickTextInput::HAlignment alignment, bool forceAlign)
462 Q_Q(QQuickTextInput);
463 if ((hAlign != alignment || forceAlign) && alignment <= QQuickTextInput::AlignHCenter) { // justify not supported
464 QQuickTextInput::HAlignment oldEffectiveHAlign = q->effectiveHAlign();
466 emit q->horizontalAlignmentChanged(alignment);
467 if (oldEffectiveHAlign != q->effectiveHAlign())
468 emit q->effectiveHorizontalAlignmentChanged();
474 bool QQuickTextInputPrivate::determineHorizontalAlignment()
476 if (hAlignImplicit) {
477 // if no explicit alignment has been set, follow the natural layout direction of the text
478 QString text = q_func()->text();
480 text = m_textLayout.preeditAreaText();
481 bool isRightToLeft = text.isEmpty() ? QGuiApplication::keyboardInputDirection() == Qt::RightToLeft : text.isRightToLeft();
482 return setHAlign(isRightToLeft ? QQuickTextInput::AlignRight : QQuickTextInput::AlignLeft);
487 QQuickTextInput::VAlignment QQuickTextInput::vAlign() const
489 Q_D(const QQuickTextInput);
493 void QQuickTextInput::setVAlign(QQuickTextInput::VAlignment alignment)
495 Q_D(QQuickTextInput);
496 if (alignment == d->vAlign)
498 d->vAlign = alignment;
499 emit verticalAlignmentChanged(d->vAlign);
500 if (isComponentComplete()) {
501 updateCursorRectangle();
506 \qmlproperty enumeration QtQuick2::TextInput::wrapMode
508 Set this property to wrap the text to the TextEdit item's width.
509 The text will only wrap if an explicit width has been set.
512 \o TextInput.NoWrap - no wrapping will be performed. If the text contains insufficient newlines, then implicitWidth will exceed a set width.
513 \o TextInput.WordWrap - wrapping is done on word boundaries only. If a word is too long, implicitWidth will exceed a set width.
514 \o TextInput.WrapAnywhere - wrapping is done at any point on a line, even if it occurs in the middle of a word.
515 \o TextInput.Wrap - if possible, wrapping occurs at a word boundary; otherwise it will occur at the appropriate point on the line, even in the middle of a word.
518 The default is TextInput.NoWrap. If you set a width, consider using TextInput.Wrap.
520 QQuickTextInput::WrapMode QQuickTextInput::wrapMode() const
522 Q_D(const QQuickTextInput);
526 void QQuickTextInput::setWrapMode(WrapMode mode)
528 Q_D(QQuickTextInput);
529 if (mode == d->wrapMode)
533 updateCursorRectangle();
534 emit wrapModeChanged();
537 void QQuickTextInputPrivate::mirrorChange()
539 Q_Q(QQuickTextInput);
540 if (q->isComponentComplete()) {
541 if (!hAlignImplicit && (hAlign == QQuickTextInput::AlignRight || hAlign == QQuickTextInput::AlignLeft)) {
542 q->updateCursorRectangle();
543 emit q->effectiveHorizontalAlignmentChanged();
549 \qmlproperty bool QtQuick2::TextInput::readOnly
551 Sets whether user input can modify the contents of the TextInput.
553 If readOnly is set to true, then user input will not affect the text
554 property. Any bindings or attempts to set the text property will still
557 bool QQuickTextInput::isReadOnly() const
559 Q_D(const QQuickTextInput);
560 return d->m_readOnly;
563 void QQuickTextInput::setReadOnly(bool ro)
565 Q_D(QQuickTextInput);
566 if (d->m_readOnly == ro)
569 setFlag(QQuickItem::ItemAcceptsInputMethod, !ro);
572 d->setCursorPosition(d->end());
574 d->emitUndoRedoChanged();
575 emit readOnlyChanged(ro);
579 \qmlproperty int QtQuick2::TextInput::maximumLength
580 The maximum permitted length of the text in the TextInput.
582 If the text is too long, it is truncated at the limit.
584 By default, this property contains a value of 32767.
586 int QQuickTextInput::maxLength() const
588 Q_D(const QQuickTextInput);
589 return d->m_maxLength;
592 void QQuickTextInput::setMaxLength(int ml)
594 Q_D(QQuickTextInput);
595 if (d->m_maxLength == ml || d->m_maskData)
599 d->internalSetText(d->m_text, -1, false);
601 emit maximumLengthChanged(ml);
605 \qmlproperty bool QtQuick2::TextInput::cursorVisible
606 Set to true when the TextInput shows a cursor.
608 This property is set and unset when the TextInput gets active focus, so that other
609 properties can be bound to whether the cursor is currently showing. As it
610 gets set and unset automatically, when you set the value yourself you must
611 keep in mind that your value may be overwritten.
613 It can be set directly in script, for example if a KeyProxy might
614 forward keys to it and you desire it to look active when this happens
615 (but without actually giving it active focus).
617 It should not be set directly on the element, like in the below QML,
618 as the specified value will be overridden an lost on focus changes.
627 In the above snippet the cursor will still become visible when the
628 TextInput gains active focus.
630 bool QQuickTextInput::isCursorVisible() const
632 Q_D(const QQuickTextInput);
633 return d->cursorVisible;
636 void QQuickTextInput::setCursorVisible(bool on)
638 Q_D(QQuickTextInput);
639 if (d->cursorVisible == on)
641 d->cursorVisible = on;
642 d->setCursorBlinkPeriod(on ? qApp->styleHints()->cursorFlashTime() : 0);
644 emit cursorVisibleChanged(d->cursorVisible);
648 \qmlproperty int QtQuick2::TextInput::cursorPosition
649 The position of the cursor in the TextInput.
651 int QQuickTextInput::cursorPosition() const
653 Q_D(const QQuickTextInput);
657 void QQuickTextInput::setCursorPosition(int cp)
659 Q_D(QQuickTextInput);
660 if (cp < 0 || cp > text().length())
666 \qmlproperty rectangle QtQuick2::TextInput::cursorRectangle
668 The rectangle where the standard text cursor is rendered within the text input. Read only.
670 The position and height of a custom cursorDelegate are updated to follow the cursorRectangle
671 automatically when it changes. The width of the delegate is unaffected by changes in the
675 QRect QQuickTextInput::cursorRectangle() const
677 Q_D(const QQuickTextInput);
680 if (d->m_preeditCursor != -1)
681 c += d->m_preeditCursor;
682 if (d->m_echoMode == NoEcho)
684 QTextLine l = d->m_textLayout.lineForTextPosition(c);
688 qRound(l.cursorToX(c) - d->hscroll),
689 qRound(l.y() - d->vscroll),
695 \qmlproperty int QtQuick2::TextInput::selectionStart
697 The cursor position before the first character in the current selection.
699 This property is read-only. To change the selection, use select(start,end),
700 selectAll(), or selectWord().
702 \sa selectionEnd, cursorPosition, selectedText
704 int QQuickTextInput::selectionStart() const
706 Q_D(const QQuickTextInput);
707 return d->lastSelectionStart;
710 \qmlproperty int QtQuick2::TextInput::selectionEnd
712 The cursor position after the last character in the current selection.
714 This property is read-only. To change the selection, use select(start,end),
715 selectAll(), or selectWord().
717 \sa selectionStart, cursorPosition, selectedText
719 int QQuickTextInput::selectionEnd() const
721 Q_D(const QQuickTextInput);
722 return d->lastSelectionEnd;
725 \qmlmethod void QtQuick2::TextInput::select(int start, int end)
727 Causes the text from \a start to \a end to be selected.
729 If either start or end is out of range, the selection is not changed.
731 After calling this, selectionStart will become the lesser
732 and selectionEnd will become the greater (regardless of the order passed
735 \sa selectionStart, selectionEnd
737 void QQuickTextInput::select(int start, int end)
739 Q_D(QQuickTextInput);
740 if (start < 0 || end < 0 || start > d->m_text.length() || end > d->m_text.length())
742 d->setSelection(start, end-start);
746 \qmlproperty string QtQuick2::TextInput::selectedText
748 This read-only property provides the text currently selected in the
751 It is equivalent to the following snippet, but is faster and easier
755 myTextInput.text.toString().substring(myTextInput.selectionStart,
756 myTextInput.selectionEnd);
759 QString QQuickTextInput::selectedText() const
761 Q_D(const QQuickTextInput);
762 return d->selectedText();
766 \qmlproperty bool QtQuick2::TextInput::activeFocusOnPress
768 Whether the TextInput should gain active focus on a mouse press. By default this is
771 bool QQuickTextInput::focusOnPress() const
773 Q_D(const QQuickTextInput);
774 return d->focusOnPress;
777 void QQuickTextInput::setFocusOnPress(bool b)
779 Q_D(QQuickTextInput);
780 if (d->focusOnPress == b)
785 emit activeFocusOnPressChanged(d->focusOnPress);
788 \qmlproperty bool QtQuick2::TextInput::autoScroll
790 Whether the TextInput should scroll when the text is longer than the width. By default this is
793 bool QQuickTextInput::autoScroll() const
795 Q_D(const QQuickTextInput);
796 return d->autoScroll;
799 void QQuickTextInput::setAutoScroll(bool b)
801 Q_D(QQuickTextInput);
802 if (d->autoScroll == b)
806 //We need to repaint so that the scrolling is taking into account.
807 updateCursorRectangle();
808 emit autoScrollChanged(d->autoScroll);
811 #ifndef QT_NO_VALIDATOR
814 \qmlclass IntValidator QIntValidator
815 \inqmlmodule QtQuick 2
816 \ingroup qml-basic-visual-elements
818 This element provides a validator for integer values.
820 IntValidator uses the \l {QLocale::setDefault()}{default locale} to interpret the number and
821 will accept locale specific digits, group separators, and positive and negative signs. In
822 addition, IntValidator is always guaranteed to accept a number formatted according to the "C"
826 \qmlproperty int QtQuick2::IntValidator::top
828 This property holds the validator's highest acceptable value.
829 By default, this property's value is derived from the highest signed integer available (typically 2147483647).
832 \qmlproperty int QtQuick2::IntValidator::bottom
834 This property holds the validator's lowest acceptable value.
835 By default, this property's value is derived from the lowest signed integer available (typically -2147483647).
839 \qmlclass DoubleValidator QDoubleValidator
840 \inqmlmodule QtQuick 2
841 \ingroup qml-basic-visual-elements
843 This element provides a validator for non-integer numbers.
847 \qmlproperty real QtQuick2::DoubleValidator::top
849 This property holds the validator's maximum acceptable value.
850 By default, this property contains a value of infinity.
853 \qmlproperty real QtQuick2::DoubleValidator::bottom
855 This property holds the validator's minimum acceptable value.
856 By default, this property contains a value of -infinity.
859 \qmlproperty int QtQuick2::DoubleValidator::decimals
861 This property holds the validator's maximum number of digits after the decimal point.
862 By default, this property contains a value of 1000.
865 \qmlproperty enumeration QtQuick2::DoubleValidator::notation
866 This property holds the notation of how a string can describe a number.
868 The possible values for this property are:
871 \o DoubleValidator.StandardNotation
872 \o DoubleValidator.ScientificNotation (default)
875 If this property is set to DoubleValidator.ScientificNotation, the written number may have an exponent part (e.g. 1.5E-2).
879 \qmlclass RegExpValidator QRegExpValidator
880 \inqmlmodule QtQuick 2
881 \ingroup qml-basic-visual-elements
883 This element provides a validator, which counts as valid any string which
884 matches a specified regular expression.
887 \qmlproperty regExp QtQuick2::RegExpValidator::regExp
889 This property holds the regular expression used for validation.
891 Note that this property should be a regular expression in JS syntax, e.g /a/ for the regular expression
894 By default, this property contains a regular expression with the pattern .* that matches any string.
898 \qmlproperty Validator QtQuick2::TextInput::validator
900 Allows you to set a validator on the TextInput. When a validator is set
901 the TextInput will only accept input which leaves the text property in
902 an acceptable or intermediate state. The accepted signal will only be sent
903 if the text is in an acceptable state when enter is pressed.
905 Currently supported validators are IntValidator, DoubleValidator and
906 RegExpValidator. An example of using validators is shown below, which allows
907 input of integers between 11 and 31 into the text input:
912 validator: IntValidator{bottom: 11; top: 31;}
917 \sa acceptableInput, inputMask
920 QValidator* QQuickTextInput::validator() const
922 Q_D(const QQuickTextInput);
923 return d->m_validator;
926 void QQuickTextInput::setValidator(QValidator* v)
928 Q_D(QQuickTextInput);
929 if (d->m_validator == v)
933 if (!d->hasAcceptableInput(d->m_text)) {
934 d->oldValidity = false;
935 emit acceptableInputChanged();
938 emit validatorChanged();
940 #endif // QT_NO_VALIDATOR
943 \qmlproperty string QtQuick2::TextInput::inputMask
945 Allows you to set an input mask on the TextInput, restricting the allowable
946 text inputs. See QLineEdit::inputMask for further details, as the exact
947 same mask strings are used by TextInput.
949 \sa acceptableInput, validator
951 QString QQuickTextInput::inputMask() const
953 Q_D(const QQuickTextInput);
954 return d->inputMask();
957 void QQuickTextInput::setInputMask(const QString &im)
959 Q_D(QQuickTextInput);
960 if (d->inputMask() == im)
964 emit inputMaskChanged(d->inputMask());
968 \qmlproperty bool QtQuick2::TextInput::acceptableInput
970 This property is always true unless a validator or input mask has been set.
971 If a validator or input mask has been set, this property will only be true
972 if the current text is acceptable to the validator or input mask as a final
973 string (not as an intermediate string).
975 bool QQuickTextInput::hasAcceptableInput() const
977 Q_D(const QQuickTextInput);
978 return d->hasAcceptableInput(d->m_text);
982 \qmlsignal QtQuick2::TextInput::onAccepted()
984 This handler is called when the Return or Enter key is pressed.
985 Note that if there is a \l validator or \l inputMask set on the text
986 input, the handler will only be emitted if the input is in an acceptable
990 void QQuickTextInputPrivate::updateInputMethodHints()
992 Q_Q(QQuickTextInput);
993 Qt::InputMethodHints hints = inputMethodHints;
994 if (m_echoMode == QQuickTextInput::Password || m_echoMode == QQuickTextInput::NoEcho)
995 hints |= Qt::ImhHiddenText;
996 else if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit)
997 hints &= ~Qt::ImhHiddenText;
998 if (m_echoMode != QQuickTextInput::Normal)
999 hints |= (Qt::ImhNoAutoUppercase | Qt::ImhNoPredictiveText | Qt::ImhSensitiveData);
1000 q->setInputMethodHints(hints);
1003 \qmlproperty enumeration QtQuick2::TextInput::echoMode
1005 Specifies how the text should be displayed in the TextInput.
1007 \o TextInput.Normal - Displays the text as it is. (Default)
1008 \o TextInput.Password - Displays asterisks instead of characters.
1009 \o TextInput.NoEcho - Displays nothing.
1010 \o TextInput.PasswordEchoOnEdit - Displays characters as they are entered
1011 while editing, otherwise displays asterisks.
1014 QQuickTextInput::EchoMode QQuickTextInput::echoMode() const
1016 Q_D(const QQuickTextInput);
1017 return QQuickTextInput::EchoMode(d->m_echoMode);
1020 void QQuickTextInput::setEchoMode(QQuickTextInput::EchoMode echo)
1022 Q_D(QQuickTextInput);
1023 if (echoMode() == echo)
1025 d->cancelPasswordEchoTimer();
1026 d->m_echoMode = echo;
1027 d->m_passwordEchoEditing = false;
1028 d->updateInputMethodHints();
1029 d->updateDisplayText();
1030 updateCursorRectangle();
1032 emit echoModeChanged(echoMode());
1036 \qmlproperty enumeration QtQuick2::TextInput::inputMethodHints
1038 Provides hints to the input method about the expected content of the text input and how it
1041 The value is a bit-wise combination of flags, or Qt.ImhNone if no hints are set.
1043 Flags that alter behaviour are:
1046 \o Qt.ImhHiddenText - Characters should be hidden, as is typically used when entering passwords.
1047 This is automatically set when setting echoMode to \c TextInput.Password.
1048 \o Qt.ImhSensitiveData - Typed text should not be stored by the active input method
1049 in any persistent storage like predictive user dictionary.
1050 \o Qt.ImhNoAutoUppercase - The input method should not try to automatically switch to upper case
1051 when a sentence ends.
1052 \o Qt.ImhPreferNumbers - Numbers are preferred (but not required).
1053 \o Qt.ImhPreferUppercase - Upper case letters are preferred (but not required).
1054 \o Qt.ImhPreferLowercase - Lower case letters are preferred (but not required).
1055 \o Qt.ImhNoPredictiveText - Do not use predictive text (i.e. dictionary lookup) while typing.
1057 \o Qt.ImhDate - The text editor functions as a date field.
1058 \o Qt.ImhTime - The text editor functions as a time field.
1061 Flags that restrict input (exclusive flags) are:
1064 \o Qt.ImhDigitsOnly - Only digits are allowed.
1065 \o Qt.ImhFormattedNumbersOnly - Only number input is allowed. This includes decimal point and minus sign.
1066 \o Qt.ImhUppercaseOnly - Only upper case letter input is allowed.
1067 \o Qt.ImhLowercaseOnly - Only lower case letter input is allowed.
1068 \o Qt.ImhDialableCharactersOnly - Only characters suitable for phone dialing are allowed.
1069 \o Qt.ImhEmailCharactersOnly - Only characters suitable for email addresses are allowed.
1070 \o Qt.ImhUrlCharactersOnly - Only characters suitable for URLs are allowed.
1076 \o Qt.ImhExclusiveInputMask - This mask yields nonzero if any of the exclusive flags are used.
1080 Qt::InputMethodHints QQuickTextInput::imHints() const
1082 Q_D(const QQuickTextInput);
1083 return d->inputMethodHints;
1086 void QQuickTextInput::setIMHints(Qt::InputMethodHints hints)
1088 Q_D(QQuickTextInput);
1089 if (d->inputMethodHints == hints)
1091 d->inputMethodHints = hints;
1092 d->updateInputMethodHints();
1096 \qmlproperty Component QtQuick2::TextInput::cursorDelegate
1097 The delegate for the cursor in the TextInput.
1099 If you set a cursorDelegate for a TextInput, this delegate will be used for
1100 drawing the cursor instead of the standard cursor. An instance of the
1101 delegate will be created and managed by the TextInput when a cursor is
1102 needed, and the x property of delegate instance will be set so as
1103 to be one pixel before the top left of the current character.
1105 Note that the root item of the delegate component must be a QDeclarativeItem or
1106 QDeclarativeItem derived item.
1108 QDeclarativeComponent* QQuickTextInput::cursorDelegate() const
1110 Q_D(const QQuickTextInput);
1111 return d->cursorComponent;
1114 void QQuickTextInput::setCursorDelegate(QDeclarativeComponent* c)
1116 Q_D(QQuickTextInput);
1117 if (d->cursorComponent == c)
1120 d->cursorComponent = c;
1122 //note that the components are owned by something else
1123 delete d->cursorItem;
1125 d->startCreatingCursor();
1128 emit cursorDelegateChanged();
1131 void QQuickTextInputPrivate::startCreatingCursor()
1133 Q_Q(QQuickTextInput);
1134 if (cursorComponent->isReady()) {
1136 } else if (cursorComponent->isLoading()) {
1137 q->connect(cursorComponent, SIGNAL(statusChanged(int)),
1138 q, SLOT(createCursor()));
1140 qmlInfo(q, cursorComponent->errors()) << QQuickTextInput::tr("Could not load cursor delegate");
1144 void QQuickTextInput::createCursor()
1146 Q_D(QQuickTextInput);
1147 if (!isComponentComplete())
1150 if (d->cursorComponent->isError()) {
1151 qmlInfo(this, d->cursorComponent->errors()) << tr("Could not load cursor delegate");
1155 if (!d->cursorComponent->isReady())
1159 delete d->cursorItem;
1160 QDeclarativeContext *creationContext = d->cursorComponent->creationContext();
1161 QObject *object = d->cursorComponent->create(creationContext ? creationContext : qmlContext(this));
1162 d->cursorItem = qobject_cast<QQuickItem*>(object);
1163 if (!d->cursorItem) {
1165 qmlInfo(this, d->cursorComponent->errors()) << tr("Could not instantiate cursor delegate");
1169 QRectF r = cursorRectangle();
1171 QDeclarative_setParent_noEvent(d->cursorItem, this);
1172 d->cursorItem->setParentItem(this);
1173 d->cursorItem->setPos(r.topLeft());
1174 d->cursorItem->setHeight(r.height());
1178 \qmlmethod rect QtQuick2::TextInput::positionToRectangle(int pos)
1180 This function takes a character position and returns the rectangle that the
1181 cursor would occupy, if it was placed at that character position.
1183 This is similar to setting the cursorPosition, and then querying the cursor
1184 rectangle, but the cursorPosition is not changed.
1186 QRectF QQuickTextInput::positionToRectangle(int pos) const
1188 Q_D(const QQuickTextInput);
1189 if (pos > d->m_cursor)
1190 pos += d->preeditAreaText().length();
1191 QTextLine l = d->m_textLayout.lineAt(0);
1193 ? QRectF(l.cursorToX(pos) - d->hscroll, 0.0, d->m_cursorWidth, l.height())
1198 \qmlmethod int QtQuick2::TextInput::positionAt(real x, real y, CursorPosition position = CursorBetweenCharacters)
1200 This function returns the character position at
1201 x and y pixels from the top left of the textInput. Position 0 is before the
1202 first character, position 1 is after the first character but before the second,
1203 and so on until position text.length, which is after all characters.
1205 This means that for all x values before the first character this function returns 0,
1206 and for all x values after the last character this function returns text.length. If
1207 the y value is above the text the position will be that of the nearest character on
1208 the first line line and if it is below the text the position of the nearest character
1209 on the last line will be returned.
1211 The cursor position type specifies how the cursor position should be resolved.
1214 \o TextInput.CursorBetweenCharacters - Returns the position between characters that is nearest x.
1215 \o TextInput.CursorOnCharacter - Returns the position before the character that is nearest x.
1219 void QQuickTextInput::positionAt(QDeclarativeV8Function *args) const
1221 Q_D(const QQuickTextInput);
1225 QTextLine::CursorPosition position = QTextLine::CursorBetweenCharacters;
1227 if (args->Length() < 1)
1231 v8::Local<v8::Value> arg = (*args)[i];
1232 x = arg->NumberValue();
1234 if (++i < args->Length()) {
1236 y = arg->NumberValue();
1239 if (++i < args->Length()) {
1241 position = QTextLine::CursorPosition(arg->Int32Value());
1244 int pos = d->positionAt(x, y, position);
1245 const int cursor = d->m_cursor;
1247 const int preeditLength = d->preeditAreaText().length();
1248 pos = pos > cursor + preeditLength
1249 ? pos - preeditLength
1252 args->returnValue(v8::Int32::New(pos));
1255 int QQuickTextInputPrivate::positionAt(int x, int y, QTextLine::CursorPosition position) const
1259 QTextLine line = m_textLayout.lineAt(0);
1260 for (int i = 1; i < m_textLayout.lineCount(); ++i) {
1261 QTextLine nextLine = m_textLayout.lineAt(i);
1263 if (y < (line.rect().bottom() + nextLine.y()) / 2)
1267 return line.isValid() ? line.xToCursor(x, position) : 0;
1270 void QQuickTextInput::keyPressEvent(QKeyEvent* ev)
1272 Q_D(QQuickTextInput);
1273 // Don't allow MacOSX up/down support, and we don't allow a completer.
1274 bool ignore = (ev->key() == Qt::Key_Up || ev->key() == Qt::Key_Down) && ev->modifiers() == Qt::NoModifier;
1275 if (!ignore && (d->lastSelectionStart == d->lastSelectionEnd) && (ev->key() == Qt::Key_Right || ev->key() == Qt::Key_Left)) {
1276 // Ignore when moving off the end unless there is a selection,
1277 // because then moving will do something (deselect).
1278 int cursorPosition = d->m_cursor;
1279 if (cursorPosition == 0)
1280 ignore = ev->key() == (d->layoutDirection() == Qt::LeftToRight ? Qt::Key_Left : Qt::Key_Right);
1281 if (cursorPosition == text().length())
1282 ignore = ev->key() == (d->layoutDirection() == Qt::LeftToRight ? Qt::Key_Right : Qt::Key_Left);
1287 d->processKeyEvent(ev);
1289 if (!ev->isAccepted())
1290 QQuickImplicitSizeItem::keyPressEvent(ev);
1293 void QQuickTextInput::inputMethodEvent(QInputMethodEvent *ev)
1295 Q_D(QQuickTextInput);
1296 const bool wasComposing = d->preeditAreaText().length() > 0;
1297 if (d->m_readOnly) {
1300 d->processInputMethodEvent(ev);
1302 if (!ev->isAccepted())
1303 QQuickImplicitSizeItem::inputMethodEvent(ev);
1305 if (wasComposing != (d->m_textLayout.preeditAreaText().length() > 0))
1306 emit inputMethodComposingChanged();
1309 void QQuickTextInput::mouseDoubleClickEvent(QMouseEvent *event)
1311 Q_D(QQuickTextInput);
1313 if (d->selectByMouse && event->button() == Qt::LeftButton) {
1315 int cursor = d->positionAt(event->localPos());
1316 d->selectWordAtPos(cursor);
1317 event->setAccepted(true);
1318 if (!d->hasPendingTripleClick()) {
1319 d->tripleClickStartPoint = event->localPos().toPoint();
1320 d->tripleClickTimer.start();
1323 if (d->sendMouseEventToInputContext(event))
1325 QQuickImplicitSizeItem::mouseDoubleClickEvent(event);
1329 void QQuickTextInput::mousePressEvent(QMouseEvent *event)
1331 Q_D(QQuickTextInput);
1333 d->pressPos = event->localPos();
1335 if (d->focusOnPress) {
1336 bool hadActiveFocus = hasActiveFocus();
1338 // re-open input panel on press if already focused
1339 if (hasActiveFocus() && hadActiveFocus && !d->m_readOnly)
1340 openSoftwareInputPanel();
1342 if (d->selectByMouse) {
1343 setKeepMouseGrab(false);
1344 d->selectPressed = true;
1345 QPoint distanceVector = d->pressPos.toPoint() - d->tripleClickStartPoint;
1346 if (d->hasPendingTripleClick()
1347 && distanceVector.manhattanLength() < qApp->styleHints()->startDragDistance()) {
1348 event->setAccepted(true);
1354 if (d->sendMouseEventToInputContext(event))
1357 bool mark = (event->modifiers() & Qt::ShiftModifier) && d->selectByMouse;
1358 int cursor = d->positionAt(event->localPos());
1359 d->moveCursor(cursor, mark);
1360 event->setAccepted(true);
1363 void QQuickTextInput::mouseMoveEvent(QMouseEvent *event)
1365 Q_D(QQuickTextInput);
1367 if (d->selectPressed) {
1368 if (qAbs(int(event->localPos().x() - d->pressPos.x())) > qApp->styleHints()->startDragDistance())
1369 setKeepMouseGrab(true);
1371 if (d->composeMode()) {
1373 int startPos = d->positionAt(d->pressPos);
1374 int currentPos = d->positionAt(event->localPos());
1375 if (startPos != currentPos)
1376 d->setSelection(startPos, currentPos - startPos);
1378 moveCursorSelection(d->positionAt(event->localPos()), d->mouseSelectionMode);
1380 event->setAccepted(true);
1382 QQuickImplicitSizeItem::mouseMoveEvent(event);
1386 void QQuickTextInput::mouseReleaseEvent(QMouseEvent *event)
1388 Q_D(QQuickTextInput);
1389 if (d->sendMouseEventToInputContext(event))
1391 if (d->selectPressed) {
1392 d->selectPressed = false;
1393 setKeepMouseGrab(false);
1395 #ifndef QT_NO_CLIPBOARD
1396 if (QGuiApplication::clipboard()->supportsSelection()) {
1397 if (event->button() == Qt::LeftButton) {
1398 d->copy(QClipboard::Selection);
1399 } else if (!d->m_readOnly && event->button() == Qt::MidButton) {
1401 d->insert(QGuiApplication::clipboard()->text(QClipboard::Selection));
1405 if (!event->isAccepted())
1406 QQuickImplicitSizeItem::mouseReleaseEvent(event);
1409 bool QQuickTextInputPrivate::sendMouseEventToInputContext(QMouseEvent *event)
1411 #if !defined QT_NO_IM
1412 if (composeMode()) {
1413 int tmp_cursor = positionAt(event->localPos());
1414 int mousePos = tmp_cursor - m_cursor;
1415 if (mousePos >= 0 && mousePos <= m_textLayout.preeditAreaText().length()) {
1416 if (event->type() == QEvent::MouseButtonRelease) {
1417 qApp->inputPanel()->invokeAction(QInputPanel::Click, mousePos);
1430 void QQuickTextInput::mouseUngrabEvent()
1432 Q_D(QQuickTextInput);
1433 d->selectPressed = false;
1434 setKeepMouseGrab(false);
1437 bool QQuickTextInput::event(QEvent* ev)
1439 #ifndef QT_NO_SHORTCUT
1440 Q_D(QQuickTextInput);
1441 if (ev->type() == QEvent::ShortcutOverride) {
1444 QKeyEvent* ke = static_cast<QKeyEvent*>(ev);
1445 if (ke == QKeySequence::Copy
1446 || ke == QKeySequence::Paste
1447 || ke == QKeySequence::Cut
1448 || ke == QKeySequence::Redo
1449 || ke == QKeySequence::Undo
1450 || ke == QKeySequence::MoveToNextWord
1451 || ke == QKeySequence::MoveToPreviousWord
1452 || ke == QKeySequence::MoveToStartOfDocument
1453 || ke == QKeySequence::MoveToEndOfDocument
1454 || ke == QKeySequence::SelectNextWord
1455 || ke == QKeySequence::SelectPreviousWord
1456 || ke == QKeySequence::SelectStartOfLine
1457 || ke == QKeySequence::SelectEndOfLine
1458 || ke == QKeySequence::SelectStartOfBlock
1459 || ke == QKeySequence::SelectEndOfBlock
1460 || ke == QKeySequence::SelectStartOfDocument
1461 || ke == QKeySequence::SelectAll
1462 || ke == QKeySequence::SelectEndOfDocument) {
1464 } else if (ke->modifiers() == Qt::NoModifier || ke->modifiers() == Qt::ShiftModifier
1465 || ke->modifiers() == Qt::KeypadModifier) {
1466 if (ke->key() < Qt::Key_Escape) {
1470 switch (ke->key()) {
1471 case Qt::Key_Delete:
1474 case Qt::Key_Backspace:
1486 return QQuickImplicitSizeItem::event(ev);
1489 void QQuickTextInput::geometryChanged(const QRectF &newGeometry,
1490 const QRectF &oldGeometry)
1492 Q_D(QQuickTextInput);
1493 if (newGeometry.width() != oldGeometry.width())
1495 updateCursorRectangle();
1496 QQuickImplicitSizeItem::geometryChanged(newGeometry, oldGeometry);
1499 void QQuickTextInputPrivate::updateHorizontalScroll()
1501 Q_Q(QQuickTextInput);
1502 QTextLine currentLine = m_textLayout.lineForTextPosition(m_cursor + m_preeditCursor);
1503 const int preeditLength = m_textLayout.preeditAreaText().length();
1504 const int width = qMax(0, qFloor(q->width()));
1505 int widthUsed = currentLine.isValid() ? qRound(currentLine.naturalTextWidth()) : 0;
1506 int previousScroll = hscroll;
1508 if (!autoScroll || widthUsed <= width || m_echoMode == QQuickTextInput::NoEcho) {
1511 Q_ASSERT(currentLine.isValid());
1512 int cix = qRound(currentLine.cursorToX(m_cursor + preeditLength));
1513 if (cix - hscroll >= width) {
1514 // text doesn't fit, cursor is to the right of br (scroll right)
1515 hscroll = cix - width;
1516 } else if (cix - hscroll < 0 && hscroll < widthUsed) {
1517 // text doesn't fit, cursor is to the left of br (scroll left)
1519 } else if (widthUsed - hscroll < width) {
1520 // text doesn't fit, text document is to the left of br; align
1522 hscroll = widthUsed - width;
1524 if (preeditLength > 0) {
1525 // check to ensure long pre-edit text doesn't push the cursor
1527 cix = qRound(currentLine.cursorToX(m_cursor + qMax(0, m_preeditCursor - 1)));
1532 if (previousScroll != hscroll)
1533 textLayoutDirty = true;
1536 void QQuickTextInputPrivate::updateVerticalScroll()
1538 Q_Q(QQuickTextInput);
1539 const int preeditLength = m_textLayout.preeditAreaText().length();
1540 const int height = qMax(0, qFloor(q->height()));
1541 int heightUsed = boundingRect.height();
1542 int previousScroll = vscroll;
1544 if (!autoScroll || heightUsed <= height) {
1545 // text fits in br; use vscroll for alignment
1546 switch (vAlign & ~(Qt::AlignAbsolute|Qt::AlignHorizontal_Mask)) {
1547 case Qt::AlignBottom:
1548 vscroll = heightUsed - height;
1550 case Qt::AlignVCenter:
1551 vscroll = (heightUsed - height) / 2;
1559 QTextLine currentLine = m_textLayout.lineForTextPosition(m_cursor + preeditLength);
1560 QRectF r = currentLine.isValid() ? currentLine.rect() : QRectF();
1561 int top = qFloor(r.top());
1562 int bottom = qCeil(r.bottom());
1564 if (bottom - vscroll >= height) {
1565 // text doesn't fit, cursor is to the below the br (scroll down)
1566 vscroll = bottom - height;
1567 } else if (top - vscroll < 0 && vscroll < heightUsed) {
1568 // text doesn't fit, cursor is above br (scroll up)
1570 } else if (heightUsed - vscroll < height) {
1571 // text doesn't fit, text document is to the left of br; align
1573 vscroll = heightUsed - height;
1575 if (preeditLength > 0) {
1576 // check to ensure long pre-edit text doesn't push the cursor
1578 currentLine = m_textLayout.lineForTextPosition(m_cursor + qMax(0, m_preeditCursor - 1));
1579 top = currentLine.isValid() ? qRound(currentLine.rect().top()) : 0;
1584 if (previousScroll != vscroll)
1585 textLayoutDirty = true;
1588 QSGNode *QQuickTextInput::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data)
1591 Q_D(QQuickTextInput);
1593 QQuickTextNode *node = static_cast<QQuickTextNode *>(oldNode);
1595 node = new QQuickTextNode(QQuickItemPrivate::get(this)->sceneGraphContext());
1598 if (!d->textLayoutDirty) {
1599 QSGSimpleRectNode *cursorNode = node->cursorNode();
1600 if (cursorNode != 0 && !isReadOnly()) {
1601 cursorNode->setRect(cursorRectangle());
1603 if (!d->cursorVisible || (!d->m_blinkStatus && d->m_blinkPeriod > 0)) {
1610 node->deleteContent();
1611 node->setMatrix(QMatrix4x4());
1613 QPoint offset = QPoint(0,0);
1614 QFontMetrics fm = QFontMetrics(d->font);
1615 if (d->autoScroll) {
1616 // the y offset is there to keep the baseline constant in case we have script changes in the text.
1617 offset = -QPoint(d->hscroll, d->vscroll + d->m_ascent - fm.ascent());
1619 offset = -QPoint(d->hscroll, d->vscroll);
1622 if (!d->m_textLayout.text().isEmpty()) {
1623 node->addTextLayout(offset, &d->m_textLayout, d->color,
1624 QQuickText::Normal, QColor(),
1625 d->selectionColor, d->selectedTextColor,
1626 d->selectionStart(),
1627 d->selectionEnd() - 1); // selectionEnd() returns first char after
1631 if (!isReadOnly() && d->cursorItem == 0) {
1632 node->setCursor(cursorRectangle(), d->color);
1633 if (!d->cursorVisible || (!d->m_blinkStatus && d->m_blinkPeriod > 0)) {
1640 d->textLayoutDirty = false;
1646 QVariant QQuickTextInput::inputMethodQuery(Qt::InputMethodQuery property) const
1648 Q_D(const QQuickTextInput);
1651 return QVariant((bool)(flags() & ItemAcceptsInputMethod));
1653 return QVariant((int)inputMethodHints());
1654 case Qt::ImCursorRectangle:
1655 return cursorRectangle();
1658 case Qt::ImCursorPosition:
1659 return QVariant(d->m_cursor);
1660 case Qt::ImSurroundingText:
1661 if (d->m_echoMode == PasswordEchoOnEdit && !d->m_passwordEchoEditing) {
1662 return QVariant(displayText());
1664 return QVariant(d->realText());
1666 case Qt::ImCurrentSelection:
1667 return QVariant(selectedText());
1668 case Qt::ImMaximumTextLength:
1669 return QVariant(maxLength());
1670 case Qt::ImAnchorPosition:
1671 if (d->selectionStart() == d->selectionEnd())
1672 return QVariant(d->m_cursor);
1673 else if (d->selectionStart() == d->m_cursor)
1674 return QVariant(d->selectionEnd());
1676 return QVariant(d->selectionStart());
1683 \qmlmethod void QtQuick2::TextInput::deselect()
1685 Removes active text selection.
1687 void QQuickTextInput::deselect()
1689 Q_D(QQuickTextInput);
1694 \qmlmethod void QtQuick2::TextInput::selectAll()
1696 Causes all text to be selected.
1698 void QQuickTextInput::selectAll()
1700 Q_D(QQuickTextInput);
1701 d->setSelection(0, text().length());
1705 \qmlmethod void QtQuick2::TextInput::isRightToLeft(int start, int end)
1707 Returns true if the natural reading direction of the editor text
1708 found between positions \a start and \a end is right to left.
1710 bool QQuickTextInput::isRightToLeft(int start, int end)
1713 qmlInfo(this) << "isRightToLeft(start, end) called with the end property being smaller than the start.";
1716 return text().mid(start, end - start).isRightToLeft();
1720 #ifndef QT_NO_CLIPBOARD
1722 \qmlmethod QtQuick2::TextInput::cut()
1724 Moves the currently selected text to the system clipboard.
1726 void QQuickTextInput::cut()
1728 Q_D(QQuickTextInput);
1734 \qmlmethod QtQuick2::TextInput::copy()
1736 Copies the currently selected text to the system clipboard.
1738 void QQuickTextInput::copy()
1740 Q_D(QQuickTextInput);
1745 \qmlmethod QtQuick2::TextInput::paste()
1747 Replaces the currently selected text by the contents of the system clipboard.
1749 void QQuickTextInput::paste()
1751 Q_D(QQuickTextInput);
1755 #endif // QT_NO_CLIPBOARD
1758 Undoes the last operation if undo is \l {canUndo}{available}. Deselects any
1759 current selection, and updates the selection start to the current cursor
1763 void QQuickTextInput::undo()
1765 Q_D(QQuickTextInput);
1766 if (!d->m_readOnly) {
1768 d->finishChange(-1, true);
1773 Redoes the last operation if redo is \l {canRedo}{available}.
1776 void QQuickTextInput::redo()
1778 Q_D(QQuickTextInput);
1779 if (!d->m_readOnly) {
1786 \qmlmethod void QtQuick2::TextInput::insert(int position, string text)
1788 Inserts \a text into the TextInput at position.
1791 void QQuickTextInput::insert(int position, const QString &text)
1793 Q_D(QQuickTextInput);
1794 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
1795 if (d->m_echoMode == QQuickTextInput::Password)
1796 d->m_passwordEchoTimer.start(qt_passwordEchoDelay, this);
1799 if (position < 0 || position > d->m_text.length())
1802 const int priorState = d->m_undoState;
1804 QString insertText = text;
1806 if (d->hasSelectedText()) {
1807 d->addCommand(QQuickTextInputPrivate::Command(
1808 QQuickTextInputPrivate::SetSelection, d->m_cursor, 0, d->m_selstart, d->m_selend));
1810 if (d->m_maskData) {
1811 insertText = d->maskString(position, insertText);
1812 for (int i = 0; i < insertText.length(); ++i) {
1813 d->addCommand(QQuickTextInputPrivate::Command(
1814 QQuickTextInputPrivate::DeleteSelection, position + i, d->m_text.at(position + i), -1, -1));
1815 d->addCommand(QQuickTextInputPrivate::Command(
1816 QQuickTextInputPrivate::Insert, position + i, insertText.at(i), -1, -1));
1818 d->m_text.replace(position, insertText.length(), insertText);
1819 if (!insertText.isEmpty())
1820 d->m_textDirty = true;
1821 if (position < d->m_selend && position + insertText.length() > d->m_selstart)
1822 d->m_selDirty = true;
1824 int remaining = d->m_maxLength - d->m_text.length();
1825 if (remaining != 0) {
1826 insertText = insertText.left(remaining);
1827 d->m_text.insert(position, insertText);
1828 for (int i = 0; i < insertText.length(); ++i)
1829 d->addCommand(QQuickTextInputPrivate::Command(
1830 QQuickTextInputPrivate::Insert, position + i, insertText.at(i), -1, -1));
1831 if (d->m_cursor >= position)
1832 d->m_cursor += insertText.length();
1833 if (d->m_selstart >= position)
1834 d->m_selstart += insertText.length();
1835 if (d->m_selend >= position)
1836 d->m_selend += insertText.length();
1837 d->m_textDirty = true;
1838 if (position >= d->m_selstart && position <= d->m_selend)
1839 d->m_selDirty = true;
1843 d->addCommand(QQuickTextInputPrivate::Command(
1844 QQuickTextInputPrivate::SetSelection, d->m_cursor, 0, d->m_selstart, d->m_selend));
1845 d->finishChange(priorState);
1847 if (d->lastSelectionStart != d->lastSelectionEnd) {
1848 if (d->m_selstart != d->lastSelectionStart) {
1849 d->lastSelectionStart = d->m_selstart;
1850 emit selectionStartChanged();
1852 if (d->m_selend != d->lastSelectionEnd) {
1853 d->lastSelectionEnd = d->m_selend;
1854 emit selectionEndChanged();
1860 \qmlmethod string QtQuick2::TextInput::getText(int start, int end)
1862 Removes the section of text that is between the \a start and \a end positions from the TextInput.
1865 void QQuickTextInput::remove(int start, int end)
1867 Q_D(QQuickTextInput);
1869 start = qBound(0, start, d->m_text.length());
1870 end = qBound(0, end, d->m_text.length());
1874 else if (start == end)
1877 if (start < d->m_selend && end > d->m_selstart)
1878 d->m_selDirty = true;
1880 const int priorState = d->m_undoState;
1882 d->addCommand(QQuickTextInputPrivate::Command(
1883 QQuickTextInputPrivate::SetSelection, d->m_cursor, 0, d->m_selstart, d->m_selend));
1885 if (start <= d->m_cursor && d->m_cursor < end) {
1886 // cursor is within the selection. Split up the commands
1887 // to be able to restore the correct cursor position
1888 for (int i = d->m_cursor; i >= start; --i) {
1889 d->addCommand(QQuickTextInputPrivate::Command(
1890 QQuickTextInputPrivate::DeleteSelection, i, d->m_text.at(i), -1, 1));
1892 for (int i = end - 1; i > d->m_cursor; --i) {
1893 d->addCommand(QQuickTextInputPrivate::Command(
1894 QQuickTextInputPrivate::DeleteSelection, i - d->m_cursor + start - 1, d->m_text.at(i), -1, -1));
1897 for (int i = end - 1; i >= start; --i) {
1898 d->addCommand(QQuickTextInputPrivate::Command(
1899 QQuickTextInputPrivate::RemoveSelection, i, d->m_text.at(i), -1, -1));
1902 if (d->m_maskData) {
1903 d->m_text.replace(start, end - start, d->clearString(start, end - start));
1904 for (int i = 0; i < end - start; ++i) {
1905 d->addCommand(QQuickTextInputPrivate::Command(
1906 QQuickTextInputPrivate::Insert, start + i, d->m_text.at(start + i), -1, -1));
1909 d->m_text.remove(start, end - start);
1911 if (d->m_cursor > start)
1912 d->m_cursor -= qMin(d->m_cursor, end) - start;
1913 if (d->m_selstart > start)
1914 d->m_selstart -= qMin(d->m_selstart, end) - start;
1915 if (d->m_selend > end)
1916 d->m_selend -= qMin(d->m_selend, end) - start;
1918 d->addCommand(QQuickTextInputPrivate::Command(
1919 QQuickTextInputPrivate::SetSelection, d->m_cursor, 0, d->m_selstart, d->m_selend));
1921 d->m_textDirty = true;
1922 d->finishChange(priorState);
1924 if (d->lastSelectionStart != d->lastSelectionEnd) {
1925 if (d->m_selstart != d->lastSelectionStart) {
1926 d->lastSelectionStart = d->m_selstart;
1927 emit selectionStartChanged();
1929 if (d->m_selend != d->lastSelectionEnd) {
1930 d->lastSelectionEnd = d->m_selend;
1931 emit selectionEndChanged();
1938 \qmlmethod void QtQuick2::TextInput::selectWord()
1940 Causes the word closest to the current cursor position to be selected.
1942 void QQuickTextInput::selectWord()
1944 Q_D(QQuickTextInput);
1945 d->selectWordAtPos(d->m_cursor);
1949 \qmlproperty bool QtQuick2::TextInput::smooth
1951 This property holds whether the text is smoothly scaled or transformed.
1953 Smooth filtering gives better visual quality, but is slower. If
1954 the item is displayed at its natural size, this property has no visual or
1957 \note Generally scaling artifacts are only visible if the item is stationary on
1958 the screen. A common pattern when animating an item is to disable smooth
1959 filtering at the beginning of the animation and reenable it at the conclusion.
1963 \qmlproperty string QtQuick2::TextInput::passwordCharacter
1965 This is the character displayed when echoMode is set to Password or
1966 PasswordEchoOnEdit. By default it is an asterisk.
1968 If this property is set to a string with more than one character,
1969 the first character is used. If the string is empty, the value
1970 is ignored and the property is not set.
1972 QString QQuickTextInput::passwordCharacter() const
1974 Q_D(const QQuickTextInput);
1975 return QString(d->m_passwordCharacter);
1978 void QQuickTextInput::setPasswordCharacter(const QString &str)
1980 Q_D(QQuickTextInput);
1981 if (str.length() < 1)
1983 d->m_passwordCharacter = str.constData()[0];
1984 if (d->m_echoMode == Password || d->m_echoMode == PasswordEchoOnEdit)
1985 d->updateDisplayText();
1986 emit passwordCharacterChanged();
1990 \qmlproperty string QtQuick2::TextInput::displayText
1992 This is the text displayed in the TextInput.
1994 If \l echoMode is set to TextInput::Normal, this holds the
1995 same value as the TextInput::text property. Otherwise,
1996 this property holds the text visible to the user, while
1997 the \l text property holds the actual entered text.
1999 QString QQuickTextInput::displayText() const
2001 Q_D(const QQuickTextInput);
2002 return d->m_textLayout.text();
2006 \qmlproperty bool QtQuick2::TextInput::selectByMouse
2010 If true, the user can use the mouse to select text in some
2011 platform-specific way. Note that for some platforms this may
2012 not be an appropriate interaction (eg. may conflict with how
2013 the text needs to behave inside a Flickable.
2015 bool QQuickTextInput::selectByMouse() const
2017 Q_D(const QQuickTextInput);
2018 return d->selectByMouse;
2021 void QQuickTextInput::setSelectByMouse(bool on)
2023 Q_D(QQuickTextInput);
2024 if (d->selectByMouse != on) {
2025 d->selectByMouse = on;
2026 emit selectByMouseChanged(on);
2031 \qmlproperty enum QtQuick2::TextInput::mouseSelectionMode
2033 Specifies how text should be selected using a mouse.
2036 \o TextInput.SelectCharacters - The selection is updated with individual characters. (Default)
2037 \o TextInput.SelectWords - The selection is updated with whole words.
2040 This property only applies when \l selectByMouse is true.
2043 QQuickTextInput::SelectionMode QQuickTextInput::mouseSelectionMode() const
2045 Q_D(const QQuickTextInput);
2046 return d->mouseSelectionMode;
2049 void QQuickTextInput::setMouseSelectionMode(SelectionMode mode)
2051 Q_D(QQuickTextInput);
2052 if (d->mouseSelectionMode != mode) {
2053 d->mouseSelectionMode = mode;
2054 emit mouseSelectionModeChanged(mode);
2059 \qmlproperty bool QtQuick2::TextInput::canPaste
2061 Returns true if the TextInput is writable and the content of the clipboard is
2062 suitable for pasting into the TextEdit.
2064 bool QQuickTextInput::canPaste() const
2066 Q_D(const QQuickTextInput);
2067 if (!d->canPasteValid) {
2068 if (const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData())
2069 const_cast<QQuickTextInputPrivate *>(d)->canPaste = !d->m_readOnly && mimeData->hasText();
2070 const_cast<QQuickTextInputPrivate *>(d)->canPasteValid = true;
2076 \qmlproperty bool QtQuick2::TextInput::canUndo
2078 Returns true if the TextInput is writable and there are previous operations
2082 bool QQuickTextInput::canUndo() const
2084 Q_D(const QQuickTextInput);
2089 \qmlproperty bool QtQuick2::TextInput::canRedo
2091 Returns true if the TextInput is writable and there are \l {undo}{undone}
2092 operations that can be redone.
2095 bool QQuickTextInput::canRedo() const
2097 Q_D(const QQuickTextInput);
2101 void QQuickTextInput::moveCursorSelection(int position)
2103 Q_D(QQuickTextInput);
2104 d->moveCursor(position, true);
2108 \qmlmethod void QtQuick2::TextInput::moveCursorSelection(int position, SelectionMode mode = TextInput.SelectCharacters)
2110 Moves the cursor to \a position and updates the selection according to the optional \a mode
2111 parameter. (To only move the cursor, set the \l cursorPosition property.)
2113 When this method is called it additionally sets either the
2114 selectionStart or the selectionEnd (whichever was at the previous cursor position)
2115 to the specified position. This allows you to easily extend and contract the selected
2118 The selection mode specifies whether the selection is updated on a per character or a per word
2119 basis. If not specified the selection mode will default to TextInput.SelectCharacters.
2122 \o TextEdit.SelectCharacters - Sets either the selectionStart or selectionEnd (whichever was at
2123 the previous cursor position) to the specified position.
2124 \o TextEdit.SelectWords - Sets the selectionStart and selectionEnd to include all
2125 words between the specified position and the previous cursor position. Words partially in the
2129 For example, take this sequence of calls:
2133 moveCursorSelection(9, TextInput.SelectCharacters)
2134 moveCursorSelection(7, TextInput.SelectCharacters)
2137 This moves the cursor to position 5, extend the selection end from 5 to 9
2138 and then retract the selection end from 9 to 7, leaving the text from position 5 to 7
2139 selected (the 6th and 7th characters).
2141 The same sequence with TextInput.SelectWords will extend the selection start to a word boundary
2142 before or on position 5 and extend the selection end to a word boundary on or past position 9.
2144 void QQuickTextInput::moveCursorSelection(int pos, SelectionMode mode)
2146 Q_D(QQuickTextInput);
2148 if (mode == SelectCharacters) {
2149 d->moveCursor(pos, true);
2150 } else if (pos != d->m_cursor){
2151 const int cursor = d->m_cursor;
2153 if (!d->hasSelectedText())
2154 anchor = d->m_cursor;
2155 else if (d->selectionStart() == d->m_cursor)
2156 anchor = d->selectionEnd();
2158 anchor = d->selectionStart();
2160 if (anchor < pos || (anchor == pos && cursor < pos)) {
2161 const QString text = this->text();
2162 QTextBoundaryFinder finder(QTextBoundaryFinder::Word, text);
2163 finder.setPosition(anchor);
2165 const QTextBoundaryFinder::BoundaryReasons reasons = finder.boundaryReasons();
2166 if (anchor < text.length() && (!(reasons & QTextBoundaryFinder::StartWord)
2167 || ((reasons & QTextBoundaryFinder::EndWord) && anchor > cursor))) {
2168 finder.toPreviousBoundary();
2170 anchor = finder.position() != -1 ? finder.position() : 0;
2172 finder.setPosition(pos);
2173 if (pos > 0 && !finder.boundaryReasons())
2174 finder.toNextBoundary();
2175 const int cursor = finder.position() != -1 ? finder.position() : text.length();
2177 d->setSelection(anchor, cursor - anchor);
2178 } else if (anchor > pos || (anchor == pos && cursor > pos)) {
2179 const QString text = this->text();
2180 QTextBoundaryFinder finder(QTextBoundaryFinder::Word, text);
2181 finder.setPosition(anchor);
2183 const QTextBoundaryFinder::BoundaryReasons reasons = finder.boundaryReasons();
2184 if (anchor > 0 && (!(reasons & QTextBoundaryFinder::EndWord)
2185 || ((reasons & QTextBoundaryFinder::StartWord) && anchor < cursor))) {
2186 finder.toNextBoundary();
2189 anchor = finder.position() != -1 ? finder.position() : text.length();
2191 finder.setPosition(pos);
2192 if (pos < text.length() && !finder.boundaryReasons())
2193 finder.toPreviousBoundary();
2194 const int cursor = finder.position() != -1 ? finder.position() : 0;
2196 d->setSelection(anchor, cursor - anchor);
2202 \qmlmethod void QtQuick2::TextInput::openSoftwareInputPanel()
2204 Opens software input panels like virtual keyboards for typing, useful for
2205 customizing when you want the input keyboard to be shown and hidden in
2208 By default the opening of input panels follows the platform style. Input panels are
2209 always closed if no editor has active focus.
2211 You can disable the automatic behavior by setting the property \c activeFocusOnPress to false
2212 and use functions openSoftwareInputPanel() and closeSoftwareInputPanel() to implement
2213 the behavior you want.
2215 Only relevant on platforms, which provide virtual keyboards.
2221 text: "Hello world!"
2222 activeFocusOnPress: false
2224 anchors.fill: parent
2226 if (!textInput.activeFocus) {
2227 textInput.forceActiveFocus()
2228 textInput.openSoftwareInputPanel();
2230 textInput.focus = false;
2233 onPressAndHold: textInput.closeSoftwareInputPanel();
2238 void QQuickTextInput::openSoftwareInputPanel()
2241 qGuiApp->inputPanel()->show();
2245 \qmlmethod void QtQuick2::TextInput::closeSoftwareInputPanel()
2247 Closes a software input panel like a virtual keyboard shown on the screen, useful
2248 for customizing when you want the input keyboard to be shown and hidden in
2251 By default the opening of input panels follows the platform style. Input panels are
2252 always closed if no editor has active focus.
2254 You can disable the automatic behavior by setting the property \c activeFocusOnPress to false
2255 and use functions openSoftwareInputPanel() and closeSoftwareInputPanel() to implement
2256 the behavior you want.
2258 Only relevant on platforms, which provide virtual keyboards.
2264 text: "Hello world!"
2265 activeFocusOnPress: false
2267 anchors.fill: parent
2269 if (!textInput.activeFocus) {
2270 textInput.forceActiveFocus();
2271 textInput.openSoftwareInputPanel();
2273 textInput.focus = false;
2276 onPressAndHold: textInput.closeSoftwareInputPanel();
2281 void QQuickTextInput::closeSoftwareInputPanel()
2284 qGuiApp->inputPanel()->hide();
2287 void QQuickTextInput::focusInEvent(QFocusEvent *event)
2289 Q_D(const QQuickTextInput);
2290 if (d->focusOnPress && !d->m_readOnly)
2291 openSoftwareInputPanel();
2292 QQuickImplicitSizeItem::focusInEvent(event);
2295 void QQuickTextInput::itemChange(ItemChange change, const ItemChangeData &value)
2297 Q_D(QQuickTextInput);
2298 if (change == ItemActiveFocusHasChanged) {
2299 bool hasFocus = value.boolValue;
2300 d->focused = hasFocus;
2301 setCursorVisible(hasFocus); // ### refactor: && d->canvas && d->canvas->hasFocus()
2302 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
2303 if (!hasFocus && (d->m_passwordEchoEditing || d->m_passwordEchoTimer.isActive())) {
2305 if (!hasFocus && d->m_passwordEchoEditing) {
2307 d->updatePasswordEchoEditing(false);//QQuickTextInputPrivate sets it on key events, but doesn't deal with focus events
2315 QQuickItem::itemChange(change, value);
2319 \qmlproperty bool QtQuick2::TextInput::inputMethodComposing
2322 This property holds whether the TextInput has partial text input from an
2325 While it is composing an input method may rely on mouse or key events from
2326 the TextInput to edit or commit the partial text. This property can be
2327 used to determine when to disable events handlers that may interfere with
2328 the correct operation of an input method.
2330 bool QQuickTextInput::isInputMethodComposing() const
2332 Q_D(const QQuickTextInput);
2333 return d->preeditAreaText().length() > 0;
2336 void QQuickTextInputPrivate::init()
2338 Q_Q(QQuickTextInput);
2339 q->setSmooth(smooth);
2340 q->setAcceptedMouseButtons(Qt::LeftButton);
2341 q->setFlag(QQuickItem::ItemAcceptsInputMethod);
2342 q->setFlag(QQuickItem::ItemHasContents);
2343 #ifndef QT_NO_CLIPBOARD
2344 q->connect(QGuiApplication::clipboard(), SIGNAL(dataChanged()),
2345 q, SLOT(q_canPasteChanged()));
2346 #endif // QT_NO_CLIPBOARD
2348 oldValidity = hasAcceptableInput(m_text);
2349 lastSelectionStart = 0;
2350 lastSelectionEnd = 0;
2351 selectedTextColor = m_palette.color(QPalette::HighlightedText);
2352 selectionColor = m_palette.color(QPalette::Highlight);
2353 determineHorizontalAlignment();
2355 if (!qmlDisableDistanceField()) {
2356 QTextOption option = m_textLayout.textOption();
2357 option.setUseDesignMetrics(true);
2358 m_textLayout.setTextOption(option);
2362 void QQuickTextInput::updateCursorRectangle()
2364 Q_D(QQuickTextInput);
2365 if (!isComponentComplete())
2368 d->updateHorizontalScroll();
2369 d->updateVerticalScroll();
2371 emit cursorRectangleChanged();
2372 if (d->cursorItem) {
2373 QRectF r = cursorRectangle();
2374 d->cursorItem->setPos(r.topLeft());
2375 d->cursorItem->setHeight(r.height());
2379 void QQuickTextInput::selectionChanged()
2381 Q_D(QQuickTextInput);
2382 d->textLayoutDirty = true; //TODO: Only update rect in selection
2384 emit selectedTextChanged();
2386 if (d->lastSelectionStart != d->selectionStart()) {
2387 d->lastSelectionStart = d->selectionStart();
2388 if (d->lastSelectionStart == -1)
2389 d->lastSelectionStart = d->m_cursor;
2390 emit selectionStartChanged();
2392 if (d->lastSelectionEnd != d->selectionEnd()) {
2393 d->lastSelectionEnd = d->selectionEnd();
2394 if (d->lastSelectionEnd == -1)
2395 d->lastSelectionEnd = d->m_cursor;
2396 emit selectionEndChanged();
2400 void QQuickTextInputPrivate::showCursor()
2402 if (textNode != 0 && textNode->cursorNode() != 0)
2403 textNode->cursorNode()->setColor(color);
2406 void QQuickTextInputPrivate::hideCursor()
2408 if (textNode != 0 && textNode->cursorNode() != 0)
2409 textNode->cursorNode()->setColor(QColor(0, 0, 0, 0));
2412 QRectF QQuickTextInput::boundingRect() const
2414 Q_D(const QQuickTextInput);
2416 int cursorWidth = d->cursorItem ? d->cursorItem->width() : d->m_cursorWidth;
2418 // Could include font max left/right bearings to either side of rectangle.
2419 QRectF r = QQuickImplicitSizeItem::boundingRect();
2420 r.setRight(r.right() + cursorWidth);
2424 void QQuickTextInput::q_canPasteChanged()
2426 Q_D(QQuickTextInput);
2427 bool old = d->canPaste;
2428 #ifndef QT_NO_CLIPBOARD
2429 if (const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData())
2430 d->canPaste = !d->m_readOnly && mimeData->hasText();
2432 d->canPaste = false;
2435 bool changed = d->canPaste != old || !d->canPasteValid;
2436 d->canPasteValid = true;
2438 emit canPasteChanged();
2442 // ### these should come from QStyleHints
2443 const int textCursorWidth = 1;
2444 const bool fullWidthSelection = true;
2449 Updates the display text based of the current edit text
2450 If the text has changed will emit displayTextChanged()
2452 void QQuickTextInputPrivate::updateDisplayText(bool forceUpdate)
2454 QString orig = m_textLayout.text();
2456 if (m_echoMode == QQuickTextInput::NoEcho)
2457 str = QString::fromLatin1("");
2461 if (m_echoMode == QQuickTextInput::Password) {
2462 str.fill(m_passwordCharacter);
2463 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
2464 if (m_passwordEchoTimer.isActive() && m_cursor > 0 && m_cursor <= m_text.length()) {
2465 int cursor = m_cursor - 1;
2466 QChar uc = m_text.at(cursor);
2468 if (cursor > 0 && uc.unicode() >= 0xdc00 && uc.unicode() < 0xe000) {
2469 // second half of a surrogate, check if we have the first half as well,
2470 // if yes restore both at once
2471 uc = m_text.at(cursor - 1);
2472 if (uc.unicode() >= 0xd800 && uc.unicode() < 0xdc00)
2473 str[cursor - 1] = uc;
2477 } else if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit && !m_passwordEchoEditing) {
2478 str.fill(m_passwordCharacter);
2481 // replace certain non-printable characters with spaces (to avoid
2482 // drawing boxes when using fonts that don't have glyphs for such
2484 QChar* uc = str.data();
2485 for (int i = 0; i < (int)str.length(); ++i) {
2486 if ((uc[i] < 0x20 && uc[i] != 0x09)
2487 || uc[i] == QChar::LineSeparator
2488 || uc[i] == QChar::ParagraphSeparator
2489 || uc[i] == QChar::ObjectReplacementCharacter)
2490 uc[i] = QChar(0x0020);
2493 if (str != orig || forceUpdate) {
2494 m_textLayout.setText(str);
2495 updateLayout(); // polish?
2496 emit q_func()->displayTextChanged();
2500 void QQuickTextInputPrivate::updateLayout()
2502 Q_Q(QQuickTextInput);
2504 if (!q->isComponentComplete())
2507 QTextOption option = m_textLayout.textOption();
2508 option.setTextDirection(m_layoutDirection);
2509 option.setFlags(QTextOption::IncludeTrailingSpaces);
2510 option.setWrapMode(QTextOption::WrapMode(wrapMode));
2511 option.setAlignment(Qt::Alignment(q->effectiveHAlign()));
2512 m_textLayout.setTextOption(option);
2513 m_textLayout.setFont(font);
2515 boundingRect = QRectF();
2516 m_textLayout.beginLayout();
2517 QTextLine line = m_textLayout.createLine();
2518 qreal lineWidth = q->widthValid() ? q->width() : INT_MAX;
2520 QTextLine firstLine = line;
2522 line.setLineWidth(lineWidth);
2523 line.setPosition(QPointF(line.position().x(), height));
2524 boundingRect = boundingRect.united(line.naturalTextRect());
2526 height += line.height();
2527 line = m_textLayout.createLine();
2528 } while (line.isValid());
2529 m_textLayout.endLayout();
2531 option.setWrapMode(QTextOption::NoWrap);
2532 m_textLayout.setTextOption(option);
2534 m_ascent = qRound(firstLine.ascent());
2535 textLayoutDirty = true;
2538 q->setImplicitSize(qCeil(boundingRect.width()), qCeil(boundingRect.height()));
2542 #ifndef QT_NO_CLIPBOARD
2546 Copies the currently selected text into the clipboard using the given
2549 \note If the echo mode is set to a mode other than Normal then copy
2550 will not work. This is to prevent using copy as a method of bypassing
2551 password features of the line control.
2553 void QQuickTextInputPrivate::copy(QClipboard::Mode mode) const
2555 QString t = selectedText();
2556 if (!t.isEmpty() && m_echoMode == QQuickTextInput::Normal) {
2557 QGuiApplication::clipboard()->setText(t, mode);
2564 Inserts the text stored in the application clipboard into the line
2569 void QQuickTextInputPrivate::paste(QClipboard::Mode clipboardMode)
2571 QString clip = QGuiApplication::clipboard()->text(clipboardMode);
2572 if (!clip.isEmpty() || hasSelectedText()) {
2573 separate(); //make it a separate undo/redo command
2579 #endif // !QT_NO_CLIPBOARD
2584 Exits preedit mode and commits parts marked as tentative commit
2586 void QQuickTextInputPrivate::commitPreedit()
2591 qApp->inputPanel()->reset();
2593 if (!m_tentativeCommit.isEmpty()) {
2594 internalInsert(m_tentativeCommit);
2595 m_tentativeCommit.clear();
2596 finishChange(-1, true/*not used, not documented*/, false);
2599 m_preeditCursor = 0;
2600 m_textLayout.setPreeditArea(-1, QString());
2601 m_textLayout.clearAdditionalFormats();
2608 Handles the behavior for the backspace key or function.
2609 Removes the current selection if there is a selection, otherwise
2610 removes the character prior to the cursor position.
2614 void QQuickTextInputPrivate::backspace()
2616 int priorState = m_undoState;
2617 if (hasSelectedText()) {
2618 removeSelectedText();
2619 } else if (m_cursor) {
2622 m_cursor = prevMaskBlank(m_cursor);
2623 QChar uc = m_text.at(m_cursor);
2624 if (m_cursor > 0 && uc.unicode() >= 0xdc00 && uc.unicode() < 0xe000) {
2625 // second half of a surrogate, check if we have the first half as well,
2626 // if yes delete both at once
2627 uc = m_text.at(m_cursor - 1);
2628 if (uc.unicode() >= 0xd800 && uc.unicode() < 0xdc00) {
2629 internalDelete(true);
2633 internalDelete(true);
2635 finishChange(priorState);
2641 Handles the behavior for the delete key or function.
2642 Removes the current selection if there is a selection, otherwise
2643 removes the character after the cursor position.
2647 void QQuickTextInputPrivate::del()
2649 int priorState = m_undoState;
2650 if (hasSelectedText()) {
2651 removeSelectedText();
2653 int n = m_textLayout.nextCursorPosition(m_cursor) - m_cursor;
2657 finishChange(priorState);
2663 Inserts the given \a newText at the current cursor position.
2664 If there is any selected text it is removed prior to insertion of
2667 void QQuickTextInputPrivate::insert(const QString &newText)
2669 int priorState = m_undoState;
2670 removeSelectedText();
2671 internalInsert(newText);
2672 finishChange(priorState);
2678 Clears the line control text.
2680 void QQuickTextInputPrivate::clear()
2682 int priorState = m_undoState;
2684 m_selend = m_text.length();
2685 removeSelectedText();
2687 finishChange(priorState, /*update*/false, /*edited*/false);
2693 Sets \a length characters from the given \a start position as selected.
2694 The given \a start position must be within the current text for
2695 the line control. If \a length characters cannot be selected, then
2696 the selection will extend to the end of the current text.
2698 void QQuickTextInputPrivate::setSelection(int start, int length)
2700 Q_Q(QQuickTextInput);
2703 if (start < 0 || start > (int)m_text.length()){
2704 qWarning("QQuickTextInputPrivate::setSelection: Invalid start position");
2709 if (start == m_selstart && start + length == m_selend && m_cursor == m_selend)
2712 m_selend = qMin(start + length, (int)m_text.length());
2713 m_cursor = m_selend;
2714 } else if (length < 0){
2715 if (start == m_selend && start + length == m_selstart && m_cursor == m_selstart)
2717 m_selstart = qMax(start + length, 0);
2719 m_cursor = m_selstart;
2720 } else if (m_selstart != m_selend) {
2726 emitCursorPositionChanged();
2729 emit q->selectionChanged();
2730 emitCursorPositionChanged();
2731 qApp->inputPanel()->update(Qt::ImCursorRectangle | Qt::ImAnchorPosition
2732 | Qt::ImCursorPosition | Qt::ImCurrentSelection);
2738 Initializes the line control with a starting text value of \a txt.
2740 void QQuickTextInputPrivate::init(const QString &txt)
2744 updateDisplayText();
2745 m_cursor = m_text.length();
2751 Sets the password echo editing to \a editing. If password echo editing
2752 is true, then the text of the password is displayed even if the echo
2753 mode is set to QLineEdit::PasswordEchoOnEdit. Password echoing editing
2754 does not affect other echo modes.
2756 void QQuickTextInputPrivate::updatePasswordEchoEditing(bool editing)
2758 cancelPasswordEchoTimer();
2759 m_passwordEchoEditing = editing;
2760 updateDisplayText();
2766 Fixes the current text so that it is valid given any set validators.
2768 Returns true if the text was changed. Otherwise returns false.
2770 bool QQuickTextInputPrivate::fixup() // this function assumes that validate currently returns != Acceptable
2772 #ifndef QT_NO_VALIDATOR
2774 QString textCopy = m_text;
2775 int cursorCopy = m_cursor;
2776 m_validator->fixup(textCopy);
2777 if (m_validator->validate(textCopy, cursorCopy) == QValidator::Acceptable) {
2778 if (textCopy != m_text || cursorCopy != m_cursor)
2779 internalSetText(textCopy, cursorCopy);
2790 Moves the cursor to the given position \a pos. If \a mark is true will
2791 adjust the currently selected text.
2793 void QQuickTextInputPrivate::moveCursor(int pos, bool mark)
2795 Q_Q(QQuickTextInput);
2798 if (pos != m_cursor) {
2801 pos = pos > m_cursor ? nextMaskBlank(pos) : prevMaskBlank(pos);
2805 if (m_selend > m_selstart && m_cursor == m_selstart)
2807 else if (m_selend > m_selstart && m_cursor == m_selend)
2808 anchor = m_selstart;
2811 m_selstart = qMin(anchor, pos);
2812 m_selend = qMax(anchor, pos);
2817 if (mark || m_selDirty) {
2819 emit q->selectionChanged();
2821 emitCursorPositionChanged();
2822 q->updateMicroFocus();
2828 Applies the given input method event \a event to the text of the line
2831 void QQuickTextInputPrivate::processInputMethodEvent(QInputMethodEvent *event)
2833 Q_Q(QQuickTextInput);
2835 int priorState = -1;
2836 bool isGettingInput = !event->commitString().isEmpty()
2837 || event->preeditString() != preeditAreaText()
2838 || event->replacementLength() > 0;
2839 bool cursorPositionChanged = false;
2840 bool selectionChange = false;
2841 m_preeditDirty = event->preeditString() != preeditAreaText();
2843 if (isGettingInput) {
2844 // If any text is being input, remove selected text.
2845 priorState = m_undoState;
2846 if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit && !m_passwordEchoEditing) {
2847 updatePasswordEchoEditing(true);
2849 m_selend = m_text.length();
2851 removeSelectedText();
2854 int c = m_cursor; // cursor position after insertion of commit string
2855 if (event->replacementStart() <= 0)
2856 c += event->commitString().length() - qMin(-event->replacementStart(), event->replacementLength());
2858 m_cursor += event->replacementStart();
2862 // insert commit string
2863 if (event->replacementLength()) {
2864 m_selstart = m_cursor;
2865 m_selend = m_selstart + event->replacementLength();
2866 m_selend = qMin(m_selend, m_text.length());
2867 removeSelectedText();
2869 if (!event->commitString().isEmpty()) {
2870 internalInsert(event->commitString());
2871 cursorPositionChanged = true;
2874 m_cursor = qBound(0, c, m_text.length());
2876 for (int i = 0; i < event->attributes().size(); ++i) {
2877 const QInputMethodEvent::Attribute &a = event->attributes().at(i);
2878 if (a.type == QInputMethodEvent::Selection) {
2879 m_cursor = qBound(0, a.start + a.length, m_text.length());
2881 m_selstart = qMax(0, qMin(a.start, m_text.length()));
2882 m_selend = m_cursor;
2883 if (m_selend < m_selstart) {
2884 qSwap(m_selstart, m_selend);
2886 selectionChange = true;
2888 m_selstart = m_selend = 0;
2890 cursorPositionChanged = true;
2894 m_textLayout.setPreeditArea(m_cursor, event->preeditString());
2896 const int oldPreeditCursor = m_preeditCursor;
2897 m_preeditCursor = event->preeditString().length();
2898 m_hideCursor = false;
2899 QList<QTextLayout::FormatRange> formats;
2900 for (int i = 0; i < event->attributes().size(); ++i) {
2901 const QInputMethodEvent::Attribute &a = event->attributes().at(i);
2902 if (a.type == QInputMethodEvent::Cursor) {
2903 m_preeditCursor = a.start;
2904 m_hideCursor = !a.length;
2905 } else if (a.type == QInputMethodEvent::TextFormat) {
2906 QTextCharFormat f = qvariant_cast<QTextFormat>(a.value).toCharFormat();
2908 QTextLayout::FormatRange o;
2909 o.start = a.start + m_cursor;
2910 o.length = a.length;
2916 m_textLayout.setAdditionalFormats(formats);
2918 updateDisplayText(/*force*/ true);
2919 if (cursorPositionChanged) {
2920 emitCursorPositionChanged();
2921 } else if (m_preeditCursor != oldPreeditCursor) {
2922 q->updateCursorRectangle();
2923 qApp->inputPanel()->update(Qt::ImCursorRectangle);
2926 bool tentativeCommitChanged = m_tentativeCommit != event->tentativeCommitString();
2928 if (tentativeCommitChanged) {
2930 m_tentativeCommit = event->tentativeCommitString();
2933 if (isGettingInput || tentativeCommitChanged)
2934 finishChange(priorState);
2936 if (selectionChange) {
2937 emit q->selectionChanged();
2938 qApp->inputPanel()->update(Qt::ImCursorRectangle | Qt::ImAnchorPosition
2939 | Qt::ImCursorPosition | Qt::ImCurrentSelection);
2946 Sets the selection to cover the word at the given cursor position.
2947 The word boundaries are defined by the behavior of QTextLayout::SkipWords
2950 void QQuickTextInputPrivate::selectWordAtPos(int cursor)
2952 int next = cursor + 1;
2955 int c = m_textLayout.previousCursorPosition(next, QTextLayout::SkipWords);
2956 moveCursor(c, false);
2957 // ## text layout should support end of words.
2958 int end = m_textLayout.nextCursorPosition(c, QTextLayout::SkipWords);
2959 while (end > cursor && m_text[end-1].isSpace())
2961 moveCursor(end, true);
2967 Completes a change to the line control text. If the change is not valid
2968 will undo the line control state back to the given \a validateFromState.
2970 If \a edited is true and the change is valid, will emit textEdited() in
2971 addition to textChanged(). Otherwise only emits textChanged() on a valid
2974 The \a update value is currently unused.
2976 bool QQuickTextInputPrivate::finishChange(int validateFromState, bool update, bool /*edited*/)
2978 Q_Q(QQuickTextInput);
2981 bool notifyInputPanel = m_textDirty || m_selDirty;
2985 bool wasValidInput = m_validInput;
2986 m_validInput = true;
2987 #ifndef QT_NO_VALIDATOR
2989 QString textCopy = m_text;
2990 int cursorCopy = m_cursor;
2991 m_validInput = (m_validator->validate(textCopy, cursorCopy) != QValidator::Invalid);
2993 if (m_text != textCopy) {
2994 internalSetText(textCopy, cursorCopy);
2997 m_cursor = cursorCopy;
2999 if (!m_tentativeCommit.isEmpty()) {
3000 textCopy.insert(m_cursor, m_tentativeCommit);
3001 bool validInput = m_validator->validate(textCopy, cursorCopy) != QValidator::Invalid;
3003 m_tentativeCommit.clear();
3006 m_tentativeCommit.clear();
3010 if (validateFromState >= 0 && wasValidInput && !m_validInput) {
3011 if (m_transactions.count())
3013 internalUndo(validateFromState);
3014 m_history.resize(m_undoState);
3015 if (m_modifiedState > m_undoState)
3016 m_modifiedState = -1;
3017 m_validInput = true;
3018 m_textDirty = false;
3022 m_textDirty = false;
3023 m_preeditDirty = false;
3024 determineHorizontalAlignment();
3025 emit q->textChanged();
3028 updateDisplayText();
3030 if (m_validInput != wasValidInput)
3031 emit q->acceptableInputChanged();
3033 if (m_preeditDirty) {
3034 m_preeditDirty = false;
3035 determineHorizontalAlignment();
3040 emit q->selectionChanged();
3043 notifyInputPanel |= (m_cursor == m_lastCursorPos);
3044 if (notifyInputPanel)
3045 q->updateMicroFocus();
3046 emitUndoRedoChanged();
3047 emitCursorPositionChanged();
3055 An internal function for setting the text of the line control.
3057 void QQuickTextInputPrivate::internalSetText(const QString &txt, int pos, bool edited)
3059 Q_Q(QQuickTextInput);
3061 QString oldText = m_text;
3063 m_text = maskString(0, txt, true);
3064 m_text += clearString(m_text.length(), m_maxLength - m_text.length());
3066 m_text = txt.isEmpty() ? txt : txt.left(m_maxLength);
3069 m_modifiedState = m_undoState = 0;
3070 m_cursor = (pos < 0 || pos > m_text.length()) ? m_text.length() : pos;
3071 m_textDirty = (oldText != m_text);
3073 bool changed = finishChange(-1, true, edited);
3074 #ifdef QT_NO_ACCESSIBILITY
3078 QAccessible::updateAccessibility(q, 0, QAccessible::TextUpdated);
3086 Adds the given \a command to the undo history
3087 of the line control. Does not apply the command.
3089 void QQuickTextInputPrivate::addCommand(const Command &cmd)
3091 if (m_separator && m_undoState && m_history[m_undoState - 1].type != Separator) {
3092 m_history.resize(m_undoState + 2);
3093 m_history[m_undoState++] = Command(Separator, m_cursor, 0, m_selstart, m_selend);
3095 m_history.resize(m_undoState + 1);
3097 m_separator = false;
3098 m_history[m_undoState++] = cmd;
3104 Inserts the given string \a s into the line
3107 Also adds the appropriate commands into the undo history.
3108 This function does not call finishChange(), and may leave the text
3109 in an invalid state.
3111 void QQuickTextInputPrivate::internalInsert(const QString &s)
3113 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
3114 Q_Q(QQuickTextInput);
3115 if (m_echoMode == QQuickTextInput::Password)
3116 m_passwordEchoTimer.start(qt_passwordEchoDelay, q);
3118 if (hasSelectedText())
3119 addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
3121 QString ms = maskString(m_cursor, s);
3122 for (int i = 0; i < (int) ms.length(); ++i) {
3123 addCommand (Command(DeleteSelection, m_cursor + i, m_text.at(m_cursor + i), -1, -1));
3124 addCommand(Command(Insert, m_cursor + i, ms.at(i), -1, -1));
3126 m_text.replace(m_cursor, ms.length(), ms);
3127 m_cursor += ms.length();
3128 m_cursor = nextMaskBlank(m_cursor);
3131 int remaining = m_maxLength - m_text.length();
3132 if (remaining != 0) {
3133 m_text.insert(m_cursor, s.left(remaining));
3134 for (int i = 0; i < (int) s.left(remaining).length(); ++i)
3135 addCommand(Command(Insert, m_cursor++, s.at(i), -1, -1));
3144 deletes a single character from the current text. If \a wasBackspace,
3145 the character prior to the cursor is removed. Otherwise the character
3146 after the cursor is removed.
3148 Also adds the appropriate commands into the undo history.
3149 This function does not call finishChange(), and may leave the text
3150 in an invalid state.
3152 void QQuickTextInputPrivate::internalDelete(bool wasBackspace)
3154 if (m_cursor < (int) m_text.length()) {
3155 cancelPasswordEchoTimer();
3156 if (hasSelectedText())
3157 addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
3158 addCommand(Command((CommandType)((m_maskData ? 2 : 0) + (wasBackspace ? Remove : Delete)),
3159 m_cursor, m_text.at(m_cursor), -1, -1));
3161 m_text.replace(m_cursor, 1, clearString(m_cursor, 1));
3162 addCommand(Command(Insert, m_cursor, m_text.at(m_cursor), -1, -1));
3164 m_text.remove(m_cursor, 1);
3173 removes the currently selected text from the line control.
3175 Also adds the appropriate commands into the undo history.
3176 This function does not call finishChange(), and may leave the text
3177 in an invalid state.
3179 void QQuickTextInputPrivate::removeSelectedText()
3181 if (m_selstart < m_selend && m_selend <= (int) m_text.length()) {
3182 cancelPasswordEchoTimer();
3185 addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
3186 if (m_selstart <= m_cursor && m_cursor < m_selend) {
3187 // cursor is within the selection. Split up the commands
3188 // to be able to restore the correct cursor position
3189 for (i = m_cursor; i >= m_selstart; --i)
3190 addCommand (Command(DeleteSelection, i, m_text.at(i), -1, 1));
3191 for (i = m_selend - 1; i > m_cursor; --i)
3192 addCommand (Command(DeleteSelection, i - m_cursor + m_selstart - 1, m_text.at(i), -1, -1));
3194 for (i = m_selend-1; i >= m_selstart; --i)
3195 addCommand (Command(RemoveSelection, i, m_text.at(i), -1, -1));
3198 m_text.replace(m_selstart, m_selend - m_selstart, clearString(m_selstart, m_selend - m_selstart));
3199 for (int i = 0; i < m_selend - m_selstart; ++i)
3200 addCommand(Command(Insert, m_selstart + i, m_text.at(m_selstart + i), -1, -1));
3202 m_text.remove(m_selstart, m_selend - m_selstart);
3204 if (m_cursor > m_selstart)
3205 m_cursor -= qMin(m_cursor, m_selend) - m_selstart;
3214 Parses the input mask specified by \a maskFields to generate
3215 the mask data used to handle input masks.
3217 void QQuickTextInputPrivate::parseInputMask(const QString &maskFields)
3219 int delimiter = maskFields.indexOf(QLatin1Char(';'));
3220 if (maskFields.isEmpty() || delimiter == 0) {
3222 delete [] m_maskData;
3224 m_maxLength = 32767;
3225 internalSetText(QString());
3230 if (delimiter == -1) {
3231 m_blank = QLatin1Char(' ');
3232 m_inputMask = maskFields;
3234 m_inputMask = maskFields.left(delimiter);
3235 m_blank = (delimiter + 1 < maskFields.length()) ? maskFields[delimiter + 1] : QLatin1Char(' ');
3238 // calculate m_maxLength / m_maskData length
3241 for (int i=0; i<m_inputMask.length(); i++) {
3242 c = m_inputMask.at(i);
3243 if (i > 0 && m_inputMask.at(i-1) == QLatin1Char('\\')) {
3247 if (c != QLatin1Char('\\') && c != QLatin1Char('!') &&
3248 c != QLatin1Char('<') && c != QLatin1Char('>') &&
3249 c != QLatin1Char('{') && c != QLatin1Char('}') &&
3250 c != QLatin1Char('[') && c != QLatin1Char(']'))
3254 delete [] m_maskData;
3255 m_maskData = new MaskInputData[m_maxLength];
3257 MaskInputData::Casemode m = MaskInputData::NoCaseMode;
3260 bool escape = false;
3262 for (int i = 0; i < m_inputMask.length(); i++) {
3263 c = m_inputMask.at(i);
3266 m_maskData[index].maskChar = c;
3267 m_maskData[index].separator = s;
3268 m_maskData[index].caseMode = m;
3271 } else if (c == QLatin1Char('<')) {
3272 m = MaskInputData::Lower;
3273 } else if (c == QLatin1Char('>')) {
3274 m = MaskInputData::Upper;
3275 } else if (c == QLatin1Char('!')) {
3276 m = MaskInputData::NoCaseMode;
3277 } else if (c != QLatin1Char('{') && c != QLatin1Char('}') && c != QLatin1Char('[') && c != QLatin1Char(']')) {
3278 switch (c.unicode()) {
3304 m_maskData[index].maskChar = c;
3305 m_maskData[index].separator = s;
3306 m_maskData[index].caseMode = m;
3311 internalSetText(m_text);
3318 checks if the key is valid compared to the inputMask
3320 bool QQuickTextInputPrivate::isValidInput(QChar key, QChar mask) const
3322 switch (mask.unicode()) {
3328 if (key.isLetter() || key == m_blank)
3332 if (key.isLetterOrNumber())
3336 if (key.isLetterOrNumber() || key == m_blank)
3344 if (key.isPrint() || key == m_blank)
3352 if (key.isNumber() || key == m_blank)
3356 if (key.isNumber() && key.digitValue() > 0)
3360 if ((key.isNumber() && key.digitValue() > 0) || key == m_blank)
3364 if (key.isNumber() || key == QLatin1Char('+') || key == QLatin1Char('-') || key == m_blank)
3368 if (key == QLatin1Char('0') || key == QLatin1Char('1'))
3372 if (key == QLatin1Char('0') || key == QLatin1Char('1') || key == m_blank)
3376 if (key.isNumber() || (key >= QLatin1Char('a') && key <= QLatin1Char('f')) || (key >= QLatin1Char('A') && key <= QLatin1Char('F')))
3380 if (key.isNumber() || (key >= QLatin1Char('a') && key <= QLatin1Char('f')) || (key >= QLatin1Char('A') && key <= QLatin1Char('F')) || key == m_blank)
3392 Returns true if the given text \a str is valid for any
3393 validator or input mask set for the line control.
3395 Otherwise returns false
3397 bool QQuickTextInputPrivate::hasAcceptableInput(const QString &str) const
3399 #ifndef QT_NO_VALIDATOR
3400 QString textCopy = str;
3401 int cursorCopy = m_cursor;
3402 if (m_validator && m_validator->validate(textCopy, cursorCopy)
3403 != QValidator::Acceptable)
3410 if (str.length() != m_maxLength)
3413 for (int i=0; i < m_maxLength; ++i) {
3414 if (m_maskData[i].separator) {
3415 if (str.at(i) != m_maskData[i].maskChar)
3418 if (!isValidInput(str.at(i), m_maskData[i].maskChar))
3428 Applies the inputMask on \a str starting from position \a pos in the mask. \a clear
3429 specifies from where characters should be gotten when a separator is met in \a str - true means
3430 that blanks will be used, false that previous input is used.
3431 Calling this when no inputMask is set is undefined.
3433 QString QQuickTextInputPrivate::maskString(uint pos, const QString &str, bool clear) const
3435 if (pos >= (uint)m_maxLength)
3436 return QString::fromLatin1("");
3439 fill = clear ? clearString(0, m_maxLength) : m_text;
3442 QString s = QString::fromLatin1("");
3444 while (i < m_maxLength) {
3445 if (strIndex < str.length()) {
3446 if (m_maskData[i].separator) {
3447 s += m_maskData[i].maskChar;
3448 if (str[(int)strIndex] == m_maskData[i].maskChar)
3452 if (isValidInput(str[(int)strIndex], m_maskData[i].maskChar)) {
3453 switch (m_maskData[i].caseMode) {
3454 case MaskInputData::Upper:
3455 s += str[(int)strIndex].toUpper();
3457 case MaskInputData::Lower:
3458 s += str[(int)strIndex].toLower();
3461 s += str[(int)strIndex];
3465 // search for separator first
3466 int n = findInMask(i, true, true, str[(int)strIndex]);
3468 if (str.length() != 1 || i == 0 || (i > 0 && (!m_maskData[i-1].separator || m_maskData[i-1].maskChar != str[(int)strIndex]))) {
3469 s += fill.mid(i, n-i+1);
3470 i = n + 1; // update i to find + 1
3473 // search for valid m_blank if not
3474 n = findInMask(i, true, false, str[(int)strIndex]);
3476 s += fill.mid(i, n-i);
3477 switch (m_maskData[n].caseMode) {
3478 case MaskInputData::Upper:
3479 s += str[(int)strIndex].toUpper();
3481 case MaskInputData::Lower:
3482 s += str[(int)strIndex].toLower();
3485 s += str[(int)strIndex];
3487 i = n + 1; // updates i to find + 1
3505 Returns a "cleared" string with only separators and blank chars.
3506 Calling this when no inputMask is set is undefined.
3508 QString QQuickTextInputPrivate::clearString(uint pos, uint len) const
3510 if (pos >= (uint)m_maxLength)
3514 int end = qMin((uint)m_maxLength, pos + len);
3515 for (int i = pos; i < end; ++i)
3516 if (m_maskData[i].separator)
3517 s += m_maskData[i].maskChar;
3527 Strips blank parts of the input in a QQuickTextInputPrivate when an inputMask is set,
3528 separators are still included. Typically "127.0__.0__.1__" becomes "127.0.0.1".
3530 QString QQuickTextInputPrivate::stripString(const QString &str) const
3536 int end = qMin(m_maxLength, (int)str.length());
3537 for (int i = 0; i < end; ++i) {
3538 if (m_maskData[i].separator)
3539 s += m_maskData[i].maskChar;
3540 else if (str[i] != m_blank)
3549 searches forward/backward in m_maskData for either a separator or a m_blank
3551 int QQuickTextInputPrivate::findInMask(int pos, bool forward, bool findSeparator, QChar searchChar) const
3553 if (pos >= m_maxLength || pos < 0)
3556 int end = forward ? m_maxLength : -1;
3557 int step = forward ? 1 : -1;
3561 if (findSeparator) {
3562 if (m_maskData[i].separator && m_maskData[i].maskChar == searchChar)
3565 if (!m_maskData[i].separator) {
3566 if (searchChar.isNull())
3568 else if (isValidInput(searchChar, m_maskData[i].maskChar))
3577 void QQuickTextInputPrivate::internalUndo(int until)
3579 if (!isUndoAvailable())
3581 cancelPasswordEchoTimer();
3583 while (m_undoState && m_undoState > until) {
3584 Command& cmd = m_history[--m_undoState];
3587 m_text.remove(cmd.pos, 1);
3591 m_selstart = cmd.selStart;
3592 m_selend = cmd.selEnd;
3596 case RemoveSelection:
3597 m_text.insert(cmd.pos, cmd.uc);
3598 m_cursor = cmd.pos + 1;
3601 case DeleteSelection:
3602 m_text.insert(cmd.pos, cmd.uc);
3608 if (until < 0 && m_undoState) {
3609 Command& next = m_history[m_undoState-1];
3610 if (next.type != cmd.type && next.type < RemoveSelection
3611 && (cmd.type < RemoveSelection || next.type == Separator))
3618 void QQuickTextInputPrivate::internalRedo()
3620 if (!isRedoAvailable())
3623 while (m_undoState < (int)m_history.size()) {
3624 Command& cmd = m_history[m_undoState++];
3627 m_text.insert(cmd.pos, cmd.uc);
3628 m_cursor = cmd.pos + 1;
3631 m_selstart = cmd.selStart;
3632 m_selend = cmd.selEnd;
3637 case RemoveSelection:
3638 case DeleteSelection:
3639 m_text.remove(cmd.pos, 1);
3640 m_selstart = cmd.selStart;
3641 m_selend = cmd.selEnd;
3645 m_selstart = cmd.selStart;
3646 m_selend = cmd.selEnd;
3650 if (m_undoState < (int)m_history.size()) {
3651 Command& next = m_history[m_undoState];
3652 if (next.type != cmd.type && cmd.type < RemoveSelection && next.type != Separator
3653 && (next.type < RemoveSelection || cmd.type == Separator))
3660 void QQuickTextInputPrivate::emitUndoRedoChanged()
3662 Q_Q(QQuickTextInput);
3663 const bool previousUndo = canUndo;
3664 const bool previousRedo = canRedo;
3666 canUndo = isUndoAvailable();
3667 canRedo = isRedoAvailable();
3669 if (previousUndo != canUndo)
3670 emit q->canUndoChanged();
3671 if (previousRedo != canRedo)
3672 emit q->canRedoChanged();
3678 If the current cursor position differs from the last emitted cursor
3679 position, emits cursorPositionChanged().
3681 void QQuickTextInputPrivate::emitCursorPositionChanged()
3683 Q_Q(QQuickTextInput);
3684 if (m_cursor != m_lastCursorPos) {
3685 m_lastCursorPos = m_cursor;
3687 q->updateCursorRectangle();
3688 emit q->cursorPositionChanged();
3689 // XXX todo - not in 4.8?
3691 resetCursorBlinkTimer();
3694 if (!hasSelectedText()) {
3695 if (lastSelectionStart != m_cursor) {
3696 lastSelectionStart = m_cursor;
3697 emit q->selectionStartChanged();
3699 if (lastSelectionEnd != m_cursor) {
3700 lastSelectionEnd = m_cursor;
3701 emit q->selectionEndChanged();
3705 #ifndef QT_NO_ACCESSIBILITY
3706 QAccessible::updateAccessibility(q, 0, QAccessible::TextCaretMoved);
3712 void QQuickTextInputPrivate::setCursorBlinkPeriod(int msec)
3714 Q_Q(QQuickTextInput);
3715 if (msec == m_blinkPeriod)
3718 q->killTimer(m_blinkTimer);
3721 m_blinkTimer = q->startTimer(msec / 2);
3725 if (m_blinkStatus == 1)
3728 m_blinkPeriod = msec;
3731 void QQuickTextInputPrivate::resetCursorBlinkTimer()
3733 Q_Q(QQuickTextInput);
3734 if (m_blinkPeriod == 0 || m_blinkTimer == 0)
3736 q->killTimer(m_blinkTimer);
3737 m_blinkTimer = q->startTimer(m_blinkPeriod / 2);
3741 void QQuickTextInput::timerEvent(QTimerEvent *event)
3743 Q_D(QQuickTextInput);
3744 if (event->timerId() == d->m_blinkTimer) {
3745 d->m_blinkStatus = !d->m_blinkStatus;
3747 } else if (event->timerId() == d->m_deleteAllTimer) {
3748 killTimer(d->m_deleteAllTimer);
3749 d->m_deleteAllTimer = 0;
3751 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
3752 } else if (event->timerId() == d->m_passwordEchoTimer.timerId()) {
3753 d->m_passwordEchoTimer.stop();
3754 d->updateDisplayText();
3759 void QQuickTextInputPrivate::processKeyEvent(QKeyEvent* event)
3761 Q_Q(QQuickTextInput);
3762 bool inlineCompletionAccepted = false;
3764 if (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return) {
3765 if (hasAcceptableInput(m_text) || fixup()) {
3768 if (inlineCompletionAccepted)
3775 if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit
3776 && !m_passwordEchoEditing
3778 && !event->text().isEmpty()
3779 && !(event->modifiers() & Qt::ControlModifier)) {
3780 // Clear the edit and reset to normal echo mode while editing; the
3781 // echo mode switches back when the edit loses focus
3782 // ### resets current content. dubious code; you can
3783 // navigate with keys up, down, back, and select(?), but if you press
3784 // "left" or "right" it clears?
3785 updatePasswordEchoEditing(true);
3789 bool unknown = false;
3790 bool visual = cursorMoveStyle() == Qt::VisualMoveStyle;
3794 #ifndef QT_NO_SHORTCUT
3795 else if (event == QKeySequence::Undo) {
3799 else if (event == QKeySequence::Redo) {
3803 else if (event == QKeySequence::SelectAll) {
3806 #ifndef QT_NO_CLIPBOARD
3807 else if (event == QKeySequence::Copy) {
3810 else if (event == QKeySequence::Paste) {
3812 QClipboard::Mode mode = QClipboard::Clipboard;
3816 else if (event == QKeySequence::Cut) {
3822 else if (event == QKeySequence::DeleteEndOfLine) {
3824 setSelection(m_cursor, end());
3829 #endif //QT_NO_CLIPBOARD
3830 else if (event == QKeySequence::MoveToStartOfLine || event == QKeySequence::MoveToStartOfBlock) {
3833 else if (event == QKeySequence::MoveToEndOfLine || event == QKeySequence::MoveToEndOfBlock) {
3836 else if (event == QKeySequence::SelectStartOfLine || event == QKeySequence::SelectStartOfBlock) {
3839 else if (event == QKeySequence::SelectEndOfLine || event == QKeySequence::SelectEndOfBlock) {
3842 else if (event == QKeySequence::MoveToNextChar) {
3843 if (hasSelectedText()) {
3844 moveCursor(selectionEnd(), false);
3846 cursorForward(0, visual ? 1 : (layoutDirection() == Qt::LeftToRight ? 1 : -1));
3849 else if (event == QKeySequence::SelectNextChar) {
3850 cursorForward(1, visual ? 1 : (layoutDirection() == Qt::LeftToRight ? 1 : -1));
3852 else if (event == QKeySequence::MoveToPreviousChar) {
3853 if (hasSelectedText()) {
3854 moveCursor(selectionStart(), false);
3856 cursorForward(0, visual ? -1 : (layoutDirection() == Qt::LeftToRight ? -1 : 1));
3859 else if (event == QKeySequence::SelectPreviousChar) {
3860 cursorForward(1, visual ? -1 : (layoutDirection() == Qt::LeftToRight ? -1 : 1));
3862 else if (event == QKeySequence::MoveToNextWord) {
3863 if (m_echoMode == QQuickTextInput::Normal)
3864 layoutDirection() == Qt::LeftToRight ? cursorWordForward(0) : cursorWordBackward(0);
3866 layoutDirection() == Qt::LeftToRight ? end(0) : home(0);
3868 else if (event == QKeySequence::MoveToPreviousWord) {
3869 if (m_echoMode == QQuickTextInput::Normal)
3870 layoutDirection() == Qt::LeftToRight ? cursorWordBackward(0) : cursorWordForward(0);
3871 else if (!m_readOnly) {
3872 layoutDirection() == Qt::LeftToRight ? home(0) : end(0);
3875 else if (event == QKeySequence::SelectNextWord) {
3876 if (m_echoMode == QQuickTextInput::Normal)
3877 layoutDirection() == Qt::LeftToRight ? cursorWordForward(1) : cursorWordBackward(1);
3879 layoutDirection() == Qt::LeftToRight ? end(1) : home(1);
3881 else if (event == QKeySequence::SelectPreviousWord) {
3882 if (m_echoMode == QQuickTextInput::Normal)
3883 layoutDirection() == Qt::LeftToRight ? cursorWordBackward(1) : cursorWordForward(1);
3885 layoutDirection() == Qt::LeftToRight ? home(1) : end(1);
3887 else if (event == QKeySequence::Delete) {
3891 else if (event == QKeySequence::DeleteEndOfWord) {
3893 cursorWordForward(true);
3897 else if (event == QKeySequence::DeleteStartOfWord) {
3899 cursorWordBackward(true);
3903 #endif // QT_NO_SHORTCUT
3905 bool handled = false;
3906 if (event->modifiers() & Qt::ControlModifier) {
3907 switch (event->key()) {
3908 case Qt::Key_Backspace:
3910 cursorWordBackward(true);
3918 } else { // ### check for *no* modifier
3919 switch (event->key()) {
3920 case Qt::Key_Backspace:
3932 if (event->key() == Qt::Key_Direction_L || event->key() == Qt::Key_Direction_R) {
3933 setLayoutDirection((event->key() == Qt::Key_Direction_L) ? Qt::LeftToRight : Qt::RightToLeft);
3937 if (unknown && !m_readOnly) {
3938 QString t = event->text();
3939 if (!t.isEmpty() && t.at(0).isPrint()) {