1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the QtDeclarative module of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #include "qquicktextinput_p.h"
43 #include "qquicktextinput_p_p.h"
44 #include "qquickcanvas.h"
46 #include <private/qdeclarativeglobal_p.h>
48 #include <QtDeclarative/qdeclarativeinfo.h>
49 #include <QtGui/qevent.h>
50 #include <QTextBoundaryFinder>
51 #include "qquicktextnode_p.h"
52 #include <QtQuick/qsgsimplerectnode.h>
54 #include <QtGui/qstylehints.h>
55 #include <QtGui/qinputpanel.h>
57 #ifndef QT_NO_ACCESSIBILITY
58 #include "qaccessible.h"
63 DEFINE_BOOL_CONFIG_OPTION(qmlDisableDistanceField, QML_DISABLE_DISTANCEFIELD)
65 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
66 static const int qt_passwordEchoDelay = QT_GUI_PASSWORD_ECHO_DELAY;
70 \qmlclass TextInput QQuickTextInput
71 \inqmlmodule QtQuick 2
72 \ingroup qml-basic-visual-elements
73 \brief The TextInput item displays an editable line of text.
76 The TextInput element displays a single line of editable plain text.
78 TextInput is used to accept a line of text input. Input constraints
79 can be placed on a TextInput item (for example, through a \l validator or \l inputMask),
80 and setting \l echoMode to an appropriate value enables TextInput to be used for
81 a password input field.
83 On Mac OS X, the Up/Down key bindings for Home/End are explicitly disabled.
84 If you want such bindings (on any platform), you will need to construct them in QML.
86 \sa TextEdit, Text, {declarative/text/textselection}{Text Selection example}
88 QQuickTextInput::QQuickTextInput(QQuickItem* parent)
89 : QQuickImplicitSizeItem(*(new QQuickTextInputPrivate), parent)
95 QQuickTextInput::~QQuickTextInput()
99 void QQuickTextInput::componentComplete()
101 Q_D(QQuickTextInput);
103 QQuickImplicitSizeItem::componentComplete();
106 updateCursorRectangle();
107 if (d->cursorComponent && d->cursorComponent->isReady())
112 \qmlproperty string QtQuick2::TextInput::text
114 The text in the TextInput.
116 QString QQuickTextInput::text() const
118 Q_D(const QQuickTextInput);
120 QString content = d->m_text;
121 if (!d->m_tentativeCommit.isEmpty())
122 content.insert(d->m_cursor, d->m_tentativeCommit);
123 QString res = d->m_maskData ? d->stripString(content) : content;
124 return (res.isNull() ? QString::fromLatin1("") : res);
127 void QQuickTextInput::setText(const QString &s)
129 Q_D(QQuickTextInput);
132 if (d->composeMode())
133 qApp->inputPanel()->reset();
134 d->m_tentativeCommit.clear();
135 d->internalSetText(s, -1, false);
139 \qmlproperty int QtQuick2::TextInput::length
141 Returns the total number of characters in the TextInput item.
143 If the TextInput has an inputMask the length will include mask characters and may differ
144 from the length of the string returned by the \l text property.
146 This property can be faster than querying the length the \l text property as it doesn't
147 require any copying or conversion of the TextInput's internal string data.
150 int QQuickTextInput::length() const
152 Q_D(const QQuickTextInput);
153 return d->m_text.length();
157 \qmlmethod string QtQuick2::TextInput::getText(int start, int end)
159 Returns the section of text that is between the \a start and \a end positions.
161 If the TextInput has an inputMask the length will include mask characters.
164 QString QQuickTextInput::getText(int start, int end) const
166 Q_D(const QQuickTextInput);
171 return d->m_text.mid(start, end - start);
174 QString QQuickTextInputPrivate::realText() const
176 QString res = m_maskData ? stripString(m_text) : m_text;
177 return (res.isNull() ? QString::fromLatin1("") : res);
181 \qmlproperty string QtQuick2::TextInput::font.family
183 Sets the family name of the font.
185 The family name is case insensitive and may optionally include a foundry name, e.g. "Helvetica [Cronyx]".
186 If the family is available from more than one foundry and the foundry isn't specified, an arbitrary foundry is chosen.
187 If the family isn't available a family will be set using the font matching algorithm.
191 \qmlproperty bool QtQuick2::TextInput::font.bold
193 Sets whether the font weight is bold.
197 \qmlproperty enumeration QtQuick2::TextInput::font.weight
199 Sets the font's weight.
201 The weight can be one of:
204 \o Font.Normal - the default
211 TextInput { text: "Hello"; font.weight: Font.DemiBold }
216 \qmlproperty bool QtQuick2::TextInput::font.italic
218 Sets whether the font has an italic style.
222 \qmlproperty bool QtQuick2::TextInput::font.underline
224 Sets whether the text is underlined.
228 \qmlproperty bool QtQuick2::TextInput::font.strikeout
230 Sets whether the font has a strikeout style.
234 \qmlproperty real QtQuick2::TextInput::font.pointSize
236 Sets the font size in points. The point size must be greater than zero.
240 \qmlproperty int QtQuick2::TextInput::font.pixelSize
242 Sets the font size in pixels.
244 Using this function makes the font device dependent.
245 Use \c pointSize to set the size of the font in a device independent manner.
249 \qmlproperty real QtQuick2::TextInput::font.letterSpacing
251 Sets the letter spacing for the font.
253 Letter spacing changes the default spacing between individual letters in the font.
254 A positive value increases the letter spacing by the corresponding pixels; a negative value decreases the spacing.
258 \qmlproperty real QtQuick2::TextInput::font.wordSpacing
260 Sets the word spacing for the font.
262 Word spacing changes the default spacing between individual words.
263 A positive value increases the word spacing by a corresponding amount of pixels,
264 while a negative value decreases the inter-word spacing accordingly.
268 \qmlproperty enumeration QtQuick2::TextInput::font.capitalization
270 Sets the capitalization for the text.
273 \o Font.MixedCase - This is the normal text rendering option where no capitalization change is applied.
274 \o Font.AllUppercase - This alters the text to be rendered in all uppercase type.
275 \o Font.AllLowercase - This alters the text to be rendered in all lowercase type.
276 \o Font.SmallCaps - This alters the text to be rendered in small-caps type.
277 \o Font.Capitalize - This alters the text to be rendered with the first character of each word as an uppercase character.
281 TextInput { text: "Hello"; font.capitalization: Font.AllLowercase }
285 QFont QQuickTextInput::font() const
287 Q_D(const QQuickTextInput);
288 return d->sourceFont;
291 void QQuickTextInput::setFont(const QFont &font)
293 Q_D(QQuickTextInput);
294 if (d->sourceFont == font)
297 d->sourceFont = font;
298 QFont oldFont = d->font;
300 if (d->font.pointSizeF() != -1) {
302 qreal size = qRound(d->font.pointSizeF()*2.0);
303 d->font.setPointSizeF(size/2.0);
305 if (oldFont != d->font) {
307 updateCursorRectangle();
308 qApp->inputPanel()->update(Qt::ImCursorRectangle | Qt::ImFont);
310 emit fontChanged(d->sourceFont);
314 \qmlproperty color QtQuick2::TextInput::color
318 QColor QQuickTextInput::color() const
320 Q_D(const QQuickTextInput);
324 void QQuickTextInput::setColor(const QColor &c)
326 Q_D(QQuickTextInput);
329 d->textLayoutDirty = true;
331 emit colorChanged(c);
337 \qmlproperty color QtQuick2::TextInput::selectionColor
339 The text highlight color, used behind selections.
341 QColor QQuickTextInput::selectionColor() const
343 Q_D(const QQuickTextInput);
344 return d->selectionColor;
347 void QQuickTextInput::setSelectionColor(const QColor &color)
349 Q_D(QQuickTextInput);
350 if (d->selectionColor == color)
353 d->selectionColor = color;
354 d->m_palette.setColor(QPalette::Highlight, d->selectionColor);
355 if (d->hasSelectedText()) {
356 d->textLayoutDirty = true;
359 emit selectionColorChanged(color);
362 \qmlproperty color QtQuick2::TextInput::selectedTextColor
364 The highlighted text color, used in selections.
366 QColor QQuickTextInput::selectedTextColor() const
368 Q_D(const QQuickTextInput);
369 return d->selectedTextColor;
372 void QQuickTextInput::setSelectedTextColor(const QColor &color)
374 Q_D(QQuickTextInput);
375 if (d->selectedTextColor == color)
378 d->selectedTextColor = color;
379 d->m_palette.setColor(QPalette::HighlightedText, d->selectedTextColor);
380 if (d->hasSelectedText()) {
381 d->textLayoutDirty = true;
384 emit selectedTextColorChanged(color);
388 \qmlproperty enumeration QtQuick2::TextInput::horizontalAlignment
389 \qmlproperty enumeration QtQuick2::TextInput::effectiveHorizontalAlignment
390 \qmlproperty enumeration QtQuick2::TextInput::verticalAlignment
392 Sets the horizontal alignment of the text within the TextInput item's
393 width and height. By default, the text alignment follows the natural alignment
394 of the text, for example text that is read from left to right will be aligned to
397 TextInput does not have vertical alignment, as the natural height is
398 exactly the height of the single line of text. If you set the height
399 manually to something larger, TextInput will always be top aligned
400 vertically. You can use anchors to align it however you want within
403 The valid values for \c horizontalAlignment are \c TextInput.AlignLeft, \c TextInput.AlignRight and
404 \c TextInput.AlignHCenter.
406 Valid values for \c verticalAlignment are \c TextEdit.AlignTop (default),
407 \c TextEdit.AlignBottom \c TextEdit.AlignVCenter.
409 When using the attached property LayoutMirroring::enabled to mirror application
410 layouts, the horizontal alignment of text will also be mirrored. However, the property
411 \c horizontalAlignment will remain unchanged. To query the effective horizontal alignment
412 of TextInput, use the read-only property \c effectiveHorizontalAlignment.
414 QQuickTextInput::HAlignment QQuickTextInput::hAlign() const
416 Q_D(const QQuickTextInput);
420 void QQuickTextInput::setHAlign(HAlignment align)
422 Q_D(QQuickTextInput);
423 bool forceAlign = d->hAlignImplicit && d->effectiveLayoutMirror;
424 d->hAlignImplicit = false;
425 if (d->setHAlign(align, forceAlign) && isComponentComplete()) {
427 updateCursorRectangle();
431 void QQuickTextInput::resetHAlign()
433 Q_D(QQuickTextInput);
434 d->hAlignImplicit = true;
435 if (d->determineHorizontalAlignment() && isComponentComplete()) {
437 updateCursorRectangle();
441 QQuickTextInput::HAlignment QQuickTextInput::effectiveHAlign() const
443 Q_D(const QQuickTextInput);
444 QQuickTextInput::HAlignment effectiveAlignment = d->hAlign;
445 if (!d->hAlignImplicit && d->effectiveLayoutMirror) {
447 case QQuickTextInput::AlignLeft:
448 effectiveAlignment = QQuickTextInput::AlignRight;
450 case QQuickTextInput::AlignRight:
451 effectiveAlignment = QQuickTextInput::AlignLeft;
457 return effectiveAlignment;
460 bool QQuickTextInputPrivate::setHAlign(QQuickTextInput::HAlignment alignment, bool forceAlign)
462 Q_Q(QQuickTextInput);
463 if ((hAlign != alignment || forceAlign) && alignment <= QQuickTextInput::AlignHCenter) { // justify not supported
464 QQuickTextInput::HAlignment oldEffectiveHAlign = q->effectiveHAlign();
466 emit q->horizontalAlignmentChanged(alignment);
467 if (oldEffectiveHAlign != q->effectiveHAlign())
468 emit q->effectiveHorizontalAlignmentChanged();
474 bool QQuickTextInputPrivate::determineHorizontalAlignment()
476 if (hAlignImplicit) {
477 // if no explicit alignment has been set, follow the natural layout direction of the text
478 QString text = q_func()->text();
480 text = m_textLayout.preeditAreaText();
481 bool isRightToLeft = text.isEmpty() ? qApp->inputPanel()->inputDirection() == Qt::RightToLeft
482 : text.isRightToLeft();
483 return setHAlign(isRightToLeft ? QQuickTextInput::AlignRight : QQuickTextInput::AlignLeft);
488 QQuickTextInput::VAlignment QQuickTextInput::vAlign() const
490 Q_D(const QQuickTextInput);
494 void QQuickTextInput::setVAlign(QQuickTextInput::VAlignment alignment)
496 Q_D(QQuickTextInput);
497 if (alignment == d->vAlign)
499 d->vAlign = alignment;
500 emit verticalAlignmentChanged(d->vAlign);
501 if (isComponentComplete()) {
502 updateCursorRectangle();
507 \qmlproperty enumeration QtQuick2::TextInput::wrapMode
509 Set this property to wrap the text to the TextEdit item's width.
510 The text will only wrap if an explicit width has been set.
513 \o TextInput.NoWrap - no wrapping will be performed. If the text contains insufficient newlines, then implicitWidth will exceed a set width.
514 \o TextInput.WordWrap - wrapping is done on word boundaries only. If a word is too long, implicitWidth will exceed a set width.
515 \o TextInput.WrapAnywhere - wrapping is done at any point on a line, even if it occurs in the middle of a word.
516 \o TextInput.Wrap - if possible, wrapping occurs at a word boundary; otherwise it will occur at the appropriate point on the line, even in the middle of a word.
519 The default is TextInput.NoWrap. If you set a width, consider using TextInput.Wrap.
521 QQuickTextInput::WrapMode QQuickTextInput::wrapMode() const
523 Q_D(const QQuickTextInput);
527 void QQuickTextInput::setWrapMode(WrapMode mode)
529 Q_D(QQuickTextInput);
530 if (mode == d->wrapMode)
534 updateCursorRectangle();
535 emit wrapModeChanged();
538 void QQuickTextInputPrivate::mirrorChange()
540 Q_Q(QQuickTextInput);
541 if (q->isComponentComplete()) {
542 if (!hAlignImplicit && (hAlign == QQuickTextInput::AlignRight || hAlign == QQuickTextInput::AlignLeft)) {
543 q->updateCursorRectangle();
544 emit q->effectiveHorizontalAlignmentChanged();
550 \qmlproperty bool QtQuick2::TextInput::readOnly
552 Sets whether user input can modify the contents of the TextInput.
554 If readOnly is set to true, then user input will not affect the text
555 property. Any bindings or attempts to set the text property will still
558 bool QQuickTextInput::isReadOnly() const
560 Q_D(const QQuickTextInput);
561 return d->m_readOnly;
564 void QQuickTextInput::setReadOnly(bool ro)
566 Q_D(QQuickTextInput);
567 if (d->m_readOnly == ro)
570 setFlag(QQuickItem::ItemAcceptsInputMethod, !ro);
573 d->setCursorPosition(d->end());
575 d->emitUndoRedoChanged();
576 emit readOnlyChanged(ro);
580 \qmlproperty int QtQuick2::TextInput::maximumLength
581 The maximum permitted length of the text in the TextInput.
583 If the text is too long, it is truncated at the limit.
585 By default, this property contains a value of 32767.
587 int QQuickTextInput::maxLength() const
589 Q_D(const QQuickTextInput);
590 return d->m_maxLength;
593 void QQuickTextInput::setMaxLength(int ml)
595 Q_D(QQuickTextInput);
596 if (d->m_maxLength == ml || d->m_maskData)
600 d->internalSetText(d->m_text, -1, false);
602 emit maximumLengthChanged(ml);
606 \qmlproperty bool QtQuick2::TextInput::cursorVisible
607 Set to true when the TextInput shows a cursor.
609 This property is set and unset when the TextInput gets active focus, so that other
610 properties can be bound to whether the cursor is currently showing. As it
611 gets set and unset automatically, when you set the value yourself you must
612 keep in mind that your value may be overwritten.
614 It can be set directly in script, for example if a KeyProxy might
615 forward keys to it and you desire it to look active when this happens
616 (but without actually giving it active focus).
618 It should not be set directly on the element, like in the below QML,
619 as the specified value will be overridden an lost on focus changes.
628 In the above snippet the cursor will still become visible when the
629 TextInput gains active focus.
631 bool QQuickTextInput::isCursorVisible() const
633 Q_D(const QQuickTextInput);
634 return d->cursorVisible;
637 void QQuickTextInput::setCursorVisible(bool on)
639 Q_D(QQuickTextInput);
640 if (d->cursorVisible == on)
642 d->cursorVisible = on;
643 d->setCursorBlinkPeriod(on ? qApp->styleHints()->cursorFlashTime() : 0);
645 emit cursorVisibleChanged(d->cursorVisible);
649 \qmlproperty int QtQuick2::TextInput::cursorPosition
650 The position of the cursor in the TextInput.
652 int QQuickTextInput::cursorPosition() const
654 Q_D(const QQuickTextInput);
658 void QQuickTextInput::setCursorPosition(int cp)
660 Q_D(QQuickTextInput);
661 if (cp < 0 || cp > text().length())
667 \qmlproperty rectangle QtQuick2::TextInput::cursorRectangle
669 The rectangle where the standard text cursor is rendered within the text input. Read only.
671 The position and height of a custom cursorDelegate are updated to follow the cursorRectangle
672 automatically when it changes. The width of the delegate is unaffected by changes in the
676 QRect QQuickTextInput::cursorRectangle() const
678 Q_D(const QQuickTextInput);
681 if (d->m_preeditCursor != -1)
682 c += d->m_preeditCursor;
683 if (d->m_echoMode == NoEcho)
685 QTextLine l = d->m_textLayout.lineForTextPosition(c);
689 qRound(l.cursorToX(c) - d->hscroll),
690 qRound(l.y() - d->vscroll),
696 \qmlproperty int QtQuick2::TextInput::selectionStart
698 The cursor position before the first character in the current selection.
700 This property is read-only. To change the selection, use select(start,end),
701 selectAll(), or selectWord().
703 \sa selectionEnd, cursorPosition, selectedText
705 int QQuickTextInput::selectionStart() const
707 Q_D(const QQuickTextInput);
708 return d->lastSelectionStart;
711 \qmlproperty int QtQuick2::TextInput::selectionEnd
713 The cursor position after the last character in the current selection.
715 This property is read-only. To change the selection, use select(start,end),
716 selectAll(), or selectWord().
718 \sa selectionStart, cursorPosition, selectedText
720 int QQuickTextInput::selectionEnd() const
722 Q_D(const QQuickTextInput);
723 return d->lastSelectionEnd;
726 \qmlmethod void QtQuick2::TextInput::select(int start, int end)
728 Causes the text from \a start to \a end to be selected.
730 If either start or end is out of range, the selection is not changed.
732 After calling this, selectionStart will become the lesser
733 and selectionEnd will become the greater (regardless of the order passed
736 \sa selectionStart, selectionEnd
738 void QQuickTextInput::select(int start, int end)
740 Q_D(QQuickTextInput);
741 if (start < 0 || end < 0 || start > d->m_text.length() || end > d->m_text.length())
743 d->setSelection(start, end-start);
747 \qmlproperty string QtQuick2::TextInput::selectedText
749 This read-only property provides the text currently selected in the
752 It is equivalent to the following snippet, but is faster and easier
756 myTextInput.text.toString().substring(myTextInput.selectionStart,
757 myTextInput.selectionEnd);
760 QString QQuickTextInput::selectedText() const
762 Q_D(const QQuickTextInput);
763 return d->selectedText();
767 \qmlproperty bool QtQuick2::TextInput::activeFocusOnPress
769 Whether the TextInput should gain active focus on a mouse press. By default this is
772 bool QQuickTextInput::focusOnPress() const
774 Q_D(const QQuickTextInput);
775 return d->focusOnPress;
778 void QQuickTextInput::setFocusOnPress(bool b)
780 Q_D(QQuickTextInput);
781 if (d->focusOnPress == b)
786 emit activeFocusOnPressChanged(d->focusOnPress);
789 \qmlproperty bool QtQuick2::TextInput::autoScroll
791 Whether the TextInput should scroll when the text is longer than the width. By default this is
794 bool QQuickTextInput::autoScroll() const
796 Q_D(const QQuickTextInput);
797 return d->autoScroll;
800 void QQuickTextInput::setAutoScroll(bool b)
802 Q_D(QQuickTextInput);
803 if (d->autoScroll == b)
807 //We need to repaint so that the scrolling is taking into account.
808 updateCursorRectangle();
809 emit autoScrollChanged(d->autoScroll);
812 #ifndef QT_NO_VALIDATOR
815 \qmlclass IntValidator QIntValidator
816 \inqmlmodule QtQuick 2
817 \ingroup qml-basic-visual-elements
819 This element provides a validator for integer values.
821 IntValidator uses the \l {QLocale::setDefault()}{default locale} to interpret the number and
822 will accept locale specific digits, group separators, and positive and negative signs. In
823 addition, IntValidator is always guaranteed to accept a number formatted according to the "C"
827 \qmlproperty int QtQuick2::IntValidator::top
829 This property holds the validator's highest acceptable value.
830 By default, this property's value is derived from the highest signed integer available (typically 2147483647).
833 \qmlproperty int QtQuick2::IntValidator::bottom
835 This property holds the validator's lowest acceptable value.
836 By default, this property's value is derived from the lowest signed integer available (typically -2147483647).
840 \qmlclass DoubleValidator QDoubleValidator
841 \inqmlmodule QtQuick 2
842 \ingroup qml-basic-visual-elements
844 This element provides a validator for non-integer numbers.
848 \qmlproperty real QtQuick2::DoubleValidator::top
850 This property holds the validator's maximum acceptable value.
851 By default, this property contains a value of infinity.
854 \qmlproperty real QtQuick2::DoubleValidator::bottom
856 This property holds the validator's minimum acceptable value.
857 By default, this property contains a value of -infinity.
860 \qmlproperty int QtQuick2::DoubleValidator::decimals
862 This property holds the validator's maximum number of digits after the decimal point.
863 By default, this property contains a value of 1000.
866 \qmlproperty enumeration QtQuick2::DoubleValidator::notation
867 This property holds the notation of how a string can describe a number.
869 The possible values for this property are:
872 \o DoubleValidator.StandardNotation
873 \o DoubleValidator.ScientificNotation (default)
876 If this property is set to DoubleValidator.ScientificNotation, the written number may have an exponent part (e.g. 1.5E-2).
880 \qmlclass RegExpValidator QRegExpValidator
881 \inqmlmodule QtQuick 2
882 \ingroup qml-basic-visual-elements
884 This element provides a validator, which counts as valid any string which
885 matches a specified regular expression.
888 \qmlproperty regExp QtQuick2::RegExpValidator::regExp
890 This property holds the regular expression used for validation.
892 Note that this property should be a regular expression in JS syntax, e.g /a/ for the regular expression
895 By default, this property contains a regular expression with the pattern .* that matches any string.
899 \qmlproperty Validator QtQuick2::TextInput::validator
901 Allows you to set a validator on the TextInput. When a validator is set
902 the TextInput will only accept input which leaves the text property in
903 an acceptable or intermediate state. The accepted signal will only be sent
904 if the text is in an acceptable state when enter is pressed.
906 Currently supported validators are IntValidator, DoubleValidator and
907 RegExpValidator. An example of using validators is shown below, which allows
908 input of integers between 11 and 31 into the text input:
913 validator: IntValidator{bottom: 11; top: 31;}
918 \sa acceptableInput, inputMask
921 QValidator* QQuickTextInput::validator() const
923 Q_D(const QQuickTextInput);
924 return d->m_validator;
927 void QQuickTextInput::setValidator(QValidator* v)
929 Q_D(QQuickTextInput);
930 if (d->m_validator == v)
934 if (!d->hasAcceptableInput(d->m_text)) {
935 if (d->m_validInput) {
936 d->m_validInput = false;
937 emit acceptableInputChanged();
939 } else if (!d->m_validInput) {
940 d->m_validInput = true;
941 emit acceptableInputChanged();
944 emit validatorChanged();
946 #endif // QT_NO_VALIDATOR
949 \qmlproperty string QtQuick2::TextInput::inputMask
951 Allows you to set an input mask on the TextInput, restricting the allowable
952 text inputs. See QLineEdit::inputMask for further details, as the exact
953 same mask strings are used by TextInput.
955 \sa acceptableInput, validator
957 QString QQuickTextInput::inputMask() const
959 Q_D(const QQuickTextInput);
960 return d->inputMask();
963 void QQuickTextInput::setInputMask(const QString &im)
965 Q_D(QQuickTextInput);
966 if (d->inputMask() == im)
970 emit inputMaskChanged(d->inputMask());
974 \qmlproperty bool QtQuick2::TextInput::acceptableInput
976 This property is always true unless a validator or input mask has been set.
977 If a validator or input mask has been set, this property will only be true
978 if the current text is acceptable to the validator or input mask as a final
979 string (not as an intermediate string).
981 bool QQuickTextInput::hasAcceptableInput() const
983 Q_D(const QQuickTextInput);
984 return d->hasAcceptableInput(d->m_text);
988 \qmlsignal QtQuick2::TextInput::onAccepted()
990 This handler is called when the Return or Enter key is pressed.
991 Note that if there is a \l validator or \l inputMask set on the text
992 input, the handler will only be emitted if the input is in an acceptable
996 void QQuickTextInputPrivate::updateInputMethodHints()
998 Q_Q(QQuickTextInput);
999 Qt::InputMethodHints hints = inputMethodHints;
1000 if (m_echoMode == QQuickTextInput::Password || m_echoMode == QQuickTextInput::NoEcho)
1001 hints |= Qt::ImhHiddenText;
1002 else if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit)
1003 hints &= ~Qt::ImhHiddenText;
1004 if (m_echoMode != QQuickTextInput::Normal)
1005 hints |= (Qt::ImhNoAutoUppercase | Qt::ImhNoPredictiveText | Qt::ImhSensitiveData);
1006 q->setInputMethodHints(hints);
1009 \qmlproperty enumeration QtQuick2::TextInput::echoMode
1011 Specifies how the text should be displayed in the TextInput.
1013 \o TextInput.Normal - Displays the text as it is. (Default)
1014 \o TextInput.Password - Displays asterisks instead of characters.
1015 \o TextInput.NoEcho - Displays nothing.
1016 \o TextInput.PasswordEchoOnEdit - Displays characters as they are entered
1017 while editing, otherwise displays asterisks.
1020 QQuickTextInput::EchoMode QQuickTextInput::echoMode() const
1022 Q_D(const QQuickTextInput);
1023 return QQuickTextInput::EchoMode(d->m_echoMode);
1026 void QQuickTextInput::setEchoMode(QQuickTextInput::EchoMode echo)
1028 Q_D(QQuickTextInput);
1029 if (echoMode() == echo)
1031 d->cancelPasswordEchoTimer();
1032 d->m_echoMode = echo;
1033 d->m_passwordEchoEditing = false;
1034 d->updateInputMethodHints();
1035 d->updateDisplayText();
1036 updateCursorRectangle();
1038 emit echoModeChanged(echoMode());
1042 \qmlproperty enumeration QtQuick2::TextInput::inputMethodHints
1044 Provides hints to the input method about the expected content of the text input and how it
1047 The value is a bit-wise combination of flags, or Qt.ImhNone if no hints are set.
1049 Flags that alter behaviour are:
1052 \o Qt.ImhHiddenText - Characters should be hidden, as is typically used when entering passwords.
1053 This is automatically set when setting echoMode to \c TextInput.Password.
1054 \o Qt.ImhSensitiveData - Typed text should not be stored by the active input method
1055 in any persistent storage like predictive user dictionary.
1056 \o Qt.ImhNoAutoUppercase - The input method should not try to automatically switch to upper case
1057 when a sentence ends.
1058 \o Qt.ImhPreferNumbers - Numbers are preferred (but not required).
1059 \o Qt.ImhPreferUppercase - Upper case letters are preferred (but not required).
1060 \o Qt.ImhPreferLowercase - Lower case letters are preferred (but not required).
1061 \o Qt.ImhNoPredictiveText - Do not use predictive text (i.e. dictionary lookup) while typing.
1063 \o Qt.ImhDate - The text editor functions as a date field.
1064 \o Qt.ImhTime - The text editor functions as a time field.
1067 Flags that restrict input (exclusive flags) are:
1070 \o Qt.ImhDigitsOnly - Only digits are allowed.
1071 \o Qt.ImhFormattedNumbersOnly - Only number input is allowed. This includes decimal point and minus sign.
1072 \o Qt.ImhUppercaseOnly - Only upper case letter input is allowed.
1073 \o Qt.ImhLowercaseOnly - Only lower case letter input is allowed.
1074 \o Qt.ImhDialableCharactersOnly - Only characters suitable for phone dialing are allowed.
1075 \o Qt.ImhEmailCharactersOnly - Only characters suitable for email addresses are allowed.
1076 \o Qt.ImhUrlCharactersOnly - Only characters suitable for URLs are allowed.
1082 \o Qt.ImhExclusiveInputMask - This mask yields nonzero if any of the exclusive flags are used.
1086 Qt::InputMethodHints QQuickTextInput::imHints() const
1088 Q_D(const QQuickTextInput);
1089 return d->inputMethodHints;
1092 void QQuickTextInput::setIMHints(Qt::InputMethodHints hints)
1094 Q_D(QQuickTextInput);
1095 if (d->inputMethodHints == hints)
1097 d->inputMethodHints = hints;
1098 d->updateInputMethodHints();
1102 \qmlproperty Component QtQuick2::TextInput::cursorDelegate
1103 The delegate for the cursor in the TextInput.
1105 If you set a cursorDelegate for a TextInput, this delegate will be used for
1106 drawing the cursor instead of the standard cursor. An instance of the
1107 delegate will be created and managed by the TextInput when a cursor is
1108 needed, and the x property of delegate instance will be set so as
1109 to be one pixel before the top left of the current character.
1111 Note that the root item of the delegate component must be a QDeclarativeItem or
1112 QDeclarativeItem derived item.
1114 QDeclarativeComponent* QQuickTextInput::cursorDelegate() const
1116 Q_D(const QQuickTextInput);
1117 return d->cursorComponent;
1120 void QQuickTextInput::setCursorDelegate(QDeclarativeComponent* c)
1122 Q_D(QQuickTextInput);
1123 if (d->cursorComponent == c)
1126 d->cursorComponent = c;
1128 //note that the components are owned by something else
1129 delete d->cursorItem;
1131 d->startCreatingCursor();
1134 emit cursorDelegateChanged();
1137 void QQuickTextInputPrivate::startCreatingCursor()
1139 Q_Q(QQuickTextInput);
1140 if (cursorComponent->isReady()) {
1142 } else if (cursorComponent->isLoading()) {
1143 q->connect(cursorComponent, SIGNAL(statusChanged(int)),
1144 q, SLOT(createCursor()));
1146 qmlInfo(q, cursorComponent->errors()) << QQuickTextInput::tr("Could not load cursor delegate");
1150 void QQuickTextInput::createCursor()
1152 Q_D(QQuickTextInput);
1153 if (!isComponentComplete())
1156 if (d->cursorComponent->isError()) {
1157 qmlInfo(this, d->cursorComponent->errors()) << tr("Could not load cursor delegate");
1161 if (!d->cursorComponent->isReady())
1165 delete d->cursorItem;
1166 QDeclarativeContext *creationContext = d->cursorComponent->creationContext();
1167 QObject *object = d->cursorComponent->create(creationContext ? creationContext : qmlContext(this));
1168 d->cursorItem = qobject_cast<QQuickItem*>(object);
1169 if (!d->cursorItem) {
1171 qmlInfo(this, d->cursorComponent->errors()) << tr("Could not instantiate cursor delegate");
1175 QRectF r = cursorRectangle();
1177 QDeclarative_setParent_noEvent(d->cursorItem, this);
1178 d->cursorItem->setParentItem(this);
1179 d->cursorItem->setPos(r.topLeft());
1180 d->cursorItem->setHeight(r.height());
1184 \qmlmethod rect QtQuick2::TextInput::positionToRectangle(int pos)
1186 This function takes a character position and returns the rectangle that the
1187 cursor would occupy, if it was placed at that character position.
1189 This is similar to setting the cursorPosition, and then querying the cursor
1190 rectangle, but the cursorPosition is not changed.
1192 QRectF QQuickTextInput::positionToRectangle(int pos) const
1194 Q_D(const QQuickTextInput);
1195 if (pos > d->m_cursor)
1196 pos += d->preeditAreaText().length();
1197 QTextLine l = d->m_textLayout.lineAt(0);
1199 ? QRectF(l.cursorToX(pos) - d->hscroll, 0.0, d->m_cursorWidth, l.height())
1204 \qmlmethod int QtQuick2::TextInput::positionAt(real x, real y, CursorPosition position = CursorBetweenCharacters)
1206 This function returns the character position at
1207 x and y pixels from the top left of the textInput. Position 0 is before the
1208 first character, position 1 is after the first character but before the second,
1209 and so on until position text.length, which is after all characters.
1211 This means that for all x values before the first character this function returns 0,
1212 and for all x values after the last character this function returns text.length. If
1213 the y value is above the text the position will be that of the nearest character on
1214 the first line line and if it is below the text the position of the nearest character
1215 on the last line will be returned.
1217 The cursor position type specifies how the cursor position should be resolved.
1220 \o TextInput.CursorBetweenCharacters - Returns the position between characters that is nearest x.
1221 \o TextInput.CursorOnCharacter - Returns the position before the character that is nearest x.
1225 void QQuickTextInput::positionAt(QDeclarativeV8Function *args) const
1227 Q_D(const QQuickTextInput);
1231 QTextLine::CursorPosition position = QTextLine::CursorBetweenCharacters;
1233 if (args->Length() < 1)
1237 v8::Local<v8::Value> arg = (*args)[i];
1238 x = arg->NumberValue();
1240 if (++i < args->Length()) {
1242 y = arg->NumberValue();
1245 if (++i < args->Length()) {
1247 position = QTextLine::CursorPosition(arg->Int32Value());
1250 int pos = d->positionAt(x, y, position);
1251 const int cursor = d->m_cursor;
1253 const int preeditLength = d->preeditAreaText().length();
1254 pos = pos > cursor + preeditLength
1255 ? pos - preeditLength
1258 args->returnValue(v8::Int32::New(pos));
1261 int QQuickTextInputPrivate::positionAt(int x, int y, QTextLine::CursorPosition position) const
1265 QTextLine line = m_textLayout.lineAt(0);
1266 for (int i = 1; i < m_textLayout.lineCount(); ++i) {
1267 QTextLine nextLine = m_textLayout.lineAt(i);
1269 if (y < (line.rect().bottom() + nextLine.y()) / 2)
1273 return line.isValid() ? line.xToCursor(x, position) : 0;
1276 void QQuickTextInput::keyPressEvent(QKeyEvent* ev)
1278 Q_D(QQuickTextInput);
1279 // Don't allow MacOSX up/down support, and we don't allow a completer.
1280 bool ignore = (ev->key() == Qt::Key_Up || ev->key() == Qt::Key_Down) && ev->modifiers() == Qt::NoModifier;
1281 if (!ignore && (d->lastSelectionStart == d->lastSelectionEnd) && (ev->key() == Qt::Key_Right || ev->key() == Qt::Key_Left)) {
1282 // Ignore when moving off the end unless there is a selection,
1283 // because then moving will do something (deselect).
1284 int cursorPosition = d->m_cursor;
1285 if (cursorPosition == 0)
1286 ignore = ev->key() == (d->layoutDirection() == Qt::LeftToRight ? Qt::Key_Left : Qt::Key_Right);
1287 if (cursorPosition == text().length())
1288 ignore = ev->key() == (d->layoutDirection() == Qt::LeftToRight ? Qt::Key_Right : Qt::Key_Left);
1293 d->processKeyEvent(ev);
1295 if (!ev->isAccepted())
1296 QQuickImplicitSizeItem::keyPressEvent(ev);
1299 void QQuickTextInput::inputMethodEvent(QInputMethodEvent *ev)
1301 Q_D(QQuickTextInput);
1302 const bool wasComposing = d->preeditAreaText().length() > 0;
1303 if (d->m_readOnly) {
1306 d->processInputMethodEvent(ev);
1308 if (!ev->isAccepted())
1309 QQuickImplicitSizeItem::inputMethodEvent(ev);
1311 if (wasComposing != (d->m_textLayout.preeditAreaText().length() > 0))
1312 emit inputMethodComposingChanged();
1315 void QQuickTextInput::mouseDoubleClickEvent(QMouseEvent *event)
1317 Q_D(QQuickTextInput);
1319 if (d->selectByMouse && event->button() == Qt::LeftButton) {
1321 int cursor = d->positionAt(event->localPos());
1322 d->selectWordAtPos(cursor);
1323 event->setAccepted(true);
1324 if (!d->hasPendingTripleClick()) {
1325 d->tripleClickStartPoint = event->localPos().toPoint();
1326 d->tripleClickTimer.start();
1329 if (d->sendMouseEventToInputContext(event))
1331 QQuickImplicitSizeItem::mouseDoubleClickEvent(event);
1335 void QQuickTextInput::mousePressEvent(QMouseEvent *event)
1337 Q_D(QQuickTextInput);
1339 d->pressPos = event->localPos();
1341 if (d->focusOnPress) {
1342 bool hadActiveFocus = hasActiveFocus();
1344 // re-open input panel on press if already focused
1345 if (hasActiveFocus() && hadActiveFocus && !d->m_readOnly)
1346 openSoftwareInputPanel();
1348 if (d->selectByMouse) {
1349 setKeepMouseGrab(false);
1350 d->selectPressed = true;
1351 QPoint distanceVector = d->pressPos.toPoint() - d->tripleClickStartPoint;
1352 if (d->hasPendingTripleClick()
1353 && distanceVector.manhattanLength() < qApp->styleHints()->startDragDistance()) {
1354 event->setAccepted(true);
1360 if (d->sendMouseEventToInputContext(event))
1363 bool mark = (event->modifiers() & Qt::ShiftModifier) && d->selectByMouse;
1364 int cursor = d->positionAt(event->localPos());
1365 d->moveCursor(cursor, mark);
1366 event->setAccepted(true);
1369 void QQuickTextInput::mouseMoveEvent(QMouseEvent *event)
1371 Q_D(QQuickTextInput);
1373 if (d->selectPressed) {
1374 if (qAbs(int(event->localPos().x() - d->pressPos.x())) > qApp->styleHints()->startDragDistance())
1375 setKeepMouseGrab(true);
1377 if (d->composeMode()) {
1379 int startPos = d->positionAt(d->pressPos);
1380 int currentPos = d->positionAt(event->localPos());
1381 if (startPos != currentPos)
1382 d->setSelection(startPos, currentPos - startPos);
1384 moveCursorSelection(d->positionAt(event->localPos()), d->mouseSelectionMode);
1386 event->setAccepted(true);
1388 QQuickImplicitSizeItem::mouseMoveEvent(event);
1392 void QQuickTextInput::mouseReleaseEvent(QMouseEvent *event)
1394 Q_D(QQuickTextInput);
1395 if (d->sendMouseEventToInputContext(event))
1397 if (d->selectPressed) {
1398 d->selectPressed = false;
1399 setKeepMouseGrab(false);
1401 #ifndef QT_NO_CLIPBOARD
1402 if (QGuiApplication::clipboard()->supportsSelection()) {
1403 if (event->button() == Qt::LeftButton) {
1404 d->copy(QClipboard::Selection);
1405 } else if (!d->m_readOnly && event->button() == Qt::MidButton) {
1407 d->insert(QGuiApplication::clipboard()->text(QClipboard::Selection));
1411 if (!event->isAccepted())
1412 QQuickImplicitSizeItem::mouseReleaseEvent(event);
1415 bool QQuickTextInputPrivate::sendMouseEventToInputContext(QMouseEvent *event)
1417 #if !defined QT_NO_IM
1418 if (composeMode()) {
1419 int tmp_cursor = positionAt(event->localPos());
1420 int mousePos = tmp_cursor - m_cursor;
1421 if (mousePos >= 0 && mousePos <= m_textLayout.preeditAreaText().length()) {
1422 if (event->type() == QEvent::MouseButtonRelease) {
1423 qApp->inputPanel()->invokeAction(QInputPanel::Click, mousePos);
1436 void QQuickTextInput::mouseUngrabEvent()
1438 Q_D(QQuickTextInput);
1439 d->selectPressed = false;
1440 setKeepMouseGrab(false);
1443 bool QQuickTextInput::event(QEvent* ev)
1445 #ifndef QT_NO_SHORTCUT
1446 Q_D(QQuickTextInput);
1447 if (ev->type() == QEvent::ShortcutOverride) {
1450 QKeyEvent* ke = static_cast<QKeyEvent*>(ev);
1451 if (ke == QKeySequence::Copy
1452 || ke == QKeySequence::Paste
1453 || ke == QKeySequence::Cut
1454 || ke == QKeySequence::Redo
1455 || ke == QKeySequence::Undo
1456 || ke == QKeySequence::MoveToNextWord
1457 || ke == QKeySequence::MoveToPreviousWord
1458 || ke == QKeySequence::MoveToStartOfDocument
1459 || ke == QKeySequence::MoveToEndOfDocument
1460 || ke == QKeySequence::SelectNextWord
1461 || ke == QKeySequence::SelectPreviousWord
1462 || ke == QKeySequence::SelectStartOfLine
1463 || ke == QKeySequence::SelectEndOfLine
1464 || ke == QKeySequence::SelectStartOfBlock
1465 || ke == QKeySequence::SelectEndOfBlock
1466 || ke == QKeySequence::SelectStartOfDocument
1467 || ke == QKeySequence::SelectAll
1468 || ke == QKeySequence::SelectEndOfDocument) {
1470 } else if (ke->modifiers() == Qt::NoModifier || ke->modifiers() == Qt::ShiftModifier
1471 || ke->modifiers() == Qt::KeypadModifier) {
1472 if (ke->key() < Qt::Key_Escape) {
1476 switch (ke->key()) {
1477 case Qt::Key_Delete:
1480 case Qt::Key_Backspace:
1492 return QQuickImplicitSizeItem::event(ev);
1495 void QQuickTextInput::geometryChanged(const QRectF &newGeometry,
1496 const QRectF &oldGeometry)
1498 Q_D(QQuickTextInput);
1499 if (newGeometry.width() != oldGeometry.width())
1501 updateCursorRectangle();
1502 QQuickImplicitSizeItem::geometryChanged(newGeometry, oldGeometry);
1505 void QQuickTextInputPrivate::updateHorizontalScroll()
1507 Q_Q(QQuickTextInput);
1508 QTextLine currentLine = m_textLayout.lineForTextPosition(m_cursor + m_preeditCursor);
1509 const int preeditLength = m_textLayout.preeditAreaText().length();
1510 const int width = qMax(0, qFloor(q->width()));
1511 int widthUsed = currentLine.isValid() ? qRound(currentLine.naturalTextWidth()) : 0;
1512 int previousScroll = hscroll;
1514 if (!autoScroll || widthUsed <= width || m_echoMode == QQuickTextInput::NoEcho) {
1517 Q_ASSERT(currentLine.isValid());
1518 int cix = qRound(currentLine.cursorToX(m_cursor + preeditLength));
1519 if (cix - hscroll >= width) {
1520 // text doesn't fit, cursor is to the right of br (scroll right)
1521 hscroll = cix - width;
1522 } else if (cix - hscroll < 0 && hscroll < widthUsed) {
1523 // text doesn't fit, cursor is to the left of br (scroll left)
1525 } else if (widthUsed - hscroll < width) {
1526 // text doesn't fit, text document is to the left of br; align
1528 hscroll = widthUsed - width;
1530 if (preeditLength > 0) {
1531 // check to ensure long pre-edit text doesn't push the cursor
1533 cix = qRound(currentLine.cursorToX(m_cursor + qMax(0, m_preeditCursor - 1)));
1538 if (previousScroll != hscroll)
1539 textLayoutDirty = true;
1542 void QQuickTextInputPrivate::updateVerticalScroll()
1544 Q_Q(QQuickTextInput);
1545 const int preeditLength = m_textLayout.preeditAreaText().length();
1546 const int height = qMax(0, qFloor(q->height()));
1547 int heightUsed = boundingRect.height();
1548 int previousScroll = vscroll;
1550 if (!autoScroll || heightUsed <= height) {
1551 // text fits in br; use vscroll for alignment
1552 switch (vAlign & ~(Qt::AlignAbsolute|Qt::AlignHorizontal_Mask)) {
1553 case Qt::AlignBottom:
1554 vscroll = heightUsed - height;
1556 case Qt::AlignVCenter:
1557 vscroll = (heightUsed - height) / 2;
1565 QTextLine currentLine = m_textLayout.lineForTextPosition(m_cursor + preeditLength);
1566 QRectF r = currentLine.isValid() ? currentLine.rect() : QRectF();
1567 int top = qFloor(r.top());
1568 int bottom = qCeil(r.bottom());
1570 if (bottom - vscroll >= height) {
1571 // text doesn't fit, cursor is to the below the br (scroll down)
1572 vscroll = bottom - height;
1573 } else if (top - vscroll < 0 && vscroll < heightUsed) {
1574 // text doesn't fit, cursor is above br (scroll up)
1576 } else if (heightUsed - vscroll < height) {
1577 // text doesn't fit, text document is to the left of br; align
1579 vscroll = heightUsed - height;
1581 if (preeditLength > 0) {
1582 // check to ensure long pre-edit text doesn't push the cursor
1584 currentLine = m_textLayout.lineForTextPosition(m_cursor + qMax(0, m_preeditCursor - 1));
1585 top = currentLine.isValid() ? qRound(currentLine.rect().top()) : 0;
1590 if (previousScroll != vscroll)
1591 textLayoutDirty = true;
1594 QSGNode *QQuickTextInput::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data)
1597 Q_D(QQuickTextInput);
1599 QQuickTextNode *node = static_cast<QQuickTextNode *>(oldNode);
1601 node = new QQuickTextNode(QQuickItemPrivate::get(this)->sceneGraphContext());
1604 if (!d->textLayoutDirty) {
1605 QSGSimpleRectNode *cursorNode = node->cursorNode();
1606 if (cursorNode != 0 && !isReadOnly()) {
1607 cursorNode->setRect(cursorRectangle());
1609 if (!d->cursorVisible || (!d->m_blinkStatus && d->m_blinkPeriod > 0)) {
1616 node->deleteContent();
1617 node->setMatrix(QMatrix4x4());
1619 QPoint offset = QPoint(0,0);
1620 QFontMetrics fm = QFontMetrics(d->font);
1621 if (d->autoScroll) {
1622 // the y offset is there to keep the baseline constant in case we have script changes in the text.
1623 offset = -QPoint(d->hscroll, d->vscroll + d->m_ascent - fm.ascent());
1625 offset = -QPoint(d->hscroll, d->vscroll);
1628 if (!d->m_textLayout.text().isEmpty() || !d->m_textLayout.preeditAreaText().isEmpty()) {
1629 node->addTextLayout(offset, &d->m_textLayout, d->color,
1630 QQuickText::Normal, QColor(),
1631 d->selectionColor, d->selectedTextColor,
1632 d->selectionStart(),
1633 d->selectionEnd() - 1); // selectionEnd() returns first char after
1637 if (!isReadOnly() && d->cursorItem == 0) {
1638 node->setCursor(cursorRectangle(), d->color);
1639 if (!d->cursorVisible || (!d->m_blinkStatus && d->m_blinkPeriod > 0)) {
1646 d->textLayoutDirty = false;
1652 QVariant QQuickTextInput::inputMethodQuery(Qt::InputMethodQuery property) const
1654 Q_D(const QQuickTextInput);
1657 return QVariant((bool)(flags() & ItemAcceptsInputMethod));
1659 return QVariant((int)inputMethodHints());
1660 case Qt::ImCursorRectangle:
1661 return cursorRectangle();
1664 case Qt::ImCursorPosition:
1665 return QVariant(d->m_cursor);
1666 case Qt::ImSurroundingText:
1667 if (d->m_echoMode == PasswordEchoOnEdit && !d->m_passwordEchoEditing) {
1668 return QVariant(displayText());
1670 return QVariant(d->realText());
1672 case Qt::ImCurrentSelection:
1673 return QVariant(selectedText());
1674 case Qt::ImMaximumTextLength:
1675 return QVariant(maxLength());
1676 case Qt::ImAnchorPosition:
1677 if (d->selectionStart() == d->selectionEnd())
1678 return QVariant(d->m_cursor);
1679 else if (d->selectionStart() == d->m_cursor)
1680 return QVariant(d->selectionEnd());
1682 return QVariant(d->selectionStart());
1689 \qmlmethod void QtQuick2::TextInput::deselect()
1691 Removes active text selection.
1693 void QQuickTextInput::deselect()
1695 Q_D(QQuickTextInput);
1700 \qmlmethod void QtQuick2::TextInput::selectAll()
1702 Causes all text to be selected.
1704 void QQuickTextInput::selectAll()
1706 Q_D(QQuickTextInput);
1707 d->setSelection(0, text().length());
1711 \qmlmethod void QtQuick2::TextInput::isRightToLeft(int start, int end)
1713 Returns true if the natural reading direction of the editor text
1714 found between positions \a start and \a end is right to left.
1716 bool QQuickTextInput::isRightToLeft(int start, int end)
1719 qmlInfo(this) << "isRightToLeft(start, end) called with the end property being smaller than the start.";
1722 return text().mid(start, end - start).isRightToLeft();
1726 #ifndef QT_NO_CLIPBOARD
1728 \qmlmethod QtQuick2::TextInput::cut()
1730 Moves the currently selected text to the system clipboard.
1732 void QQuickTextInput::cut()
1734 Q_D(QQuickTextInput);
1740 \qmlmethod QtQuick2::TextInput::copy()
1742 Copies the currently selected text to the system clipboard.
1744 void QQuickTextInput::copy()
1746 Q_D(QQuickTextInput);
1751 \qmlmethod QtQuick2::TextInput::paste()
1753 Replaces the currently selected text by the contents of the system clipboard.
1755 void QQuickTextInput::paste()
1757 Q_D(QQuickTextInput);
1761 #endif // QT_NO_CLIPBOARD
1764 Undoes the last operation if undo is \l {canUndo}{available}. Deselects any
1765 current selection, and updates the selection start to the current cursor
1769 void QQuickTextInput::undo()
1771 Q_D(QQuickTextInput);
1772 if (!d->m_readOnly) {
1774 d->finishChange(-1, true);
1779 Redoes the last operation if redo is \l {canRedo}{available}.
1782 void QQuickTextInput::redo()
1784 Q_D(QQuickTextInput);
1785 if (!d->m_readOnly) {
1792 \qmlmethod void QtQuick2::TextInput::insert(int position, string text)
1794 Inserts \a text into the TextInput at position.
1797 void QQuickTextInput::insert(int position, const QString &text)
1799 Q_D(QQuickTextInput);
1800 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
1801 if (d->m_echoMode == QQuickTextInput::Password)
1802 d->m_passwordEchoTimer.start(qt_passwordEchoDelay, this);
1805 if (position < 0 || position > d->m_text.length())
1808 const int priorState = d->m_undoState;
1810 QString insertText = text;
1812 if (d->hasSelectedText()) {
1813 d->addCommand(QQuickTextInputPrivate::Command(
1814 QQuickTextInputPrivate::SetSelection, d->m_cursor, 0, d->m_selstart, d->m_selend));
1816 if (d->m_maskData) {
1817 insertText = d->maskString(position, insertText);
1818 for (int i = 0; i < insertText.length(); ++i) {
1819 d->addCommand(QQuickTextInputPrivate::Command(
1820 QQuickTextInputPrivate::DeleteSelection, position + i, d->m_text.at(position + i), -1, -1));
1821 d->addCommand(QQuickTextInputPrivate::Command(
1822 QQuickTextInputPrivate::Insert, position + i, insertText.at(i), -1, -1));
1824 d->m_text.replace(position, insertText.length(), insertText);
1825 if (!insertText.isEmpty())
1826 d->m_textDirty = true;
1827 if (position < d->m_selend && position + insertText.length() > d->m_selstart)
1828 d->m_selDirty = true;
1830 int remaining = d->m_maxLength - d->m_text.length();
1831 if (remaining != 0) {
1832 insertText = insertText.left(remaining);
1833 d->m_text.insert(position, insertText);
1834 for (int i = 0; i < insertText.length(); ++i)
1835 d->addCommand(QQuickTextInputPrivate::Command(
1836 QQuickTextInputPrivate::Insert, position + i, insertText.at(i), -1, -1));
1837 if (d->m_cursor >= position)
1838 d->m_cursor += insertText.length();
1839 if (d->m_selstart >= position)
1840 d->m_selstart += insertText.length();
1841 if (d->m_selend >= position)
1842 d->m_selend += insertText.length();
1843 d->m_textDirty = true;
1844 if (position >= d->m_selstart && position <= d->m_selend)
1845 d->m_selDirty = true;
1849 d->addCommand(QQuickTextInputPrivate::Command(
1850 QQuickTextInputPrivate::SetSelection, d->m_cursor, 0, d->m_selstart, d->m_selend));
1851 d->finishChange(priorState);
1853 if (d->lastSelectionStart != d->lastSelectionEnd) {
1854 if (d->m_selstart != d->lastSelectionStart) {
1855 d->lastSelectionStart = d->m_selstart;
1856 emit selectionStartChanged();
1858 if (d->m_selend != d->lastSelectionEnd) {
1859 d->lastSelectionEnd = d->m_selend;
1860 emit selectionEndChanged();
1866 \qmlmethod string QtQuick2::TextInput::getText(int start, int end)
1868 Removes the section of text that is between the \a start and \a end positions from the TextInput.
1871 void QQuickTextInput::remove(int start, int end)
1873 Q_D(QQuickTextInput);
1875 start = qBound(0, start, d->m_text.length());
1876 end = qBound(0, end, d->m_text.length());
1880 else if (start == end)
1883 if (start < d->m_selend && end > d->m_selstart)
1884 d->m_selDirty = true;
1886 const int priorState = d->m_undoState;
1888 d->addCommand(QQuickTextInputPrivate::Command(
1889 QQuickTextInputPrivate::SetSelection, d->m_cursor, 0, d->m_selstart, d->m_selend));
1891 if (start <= d->m_cursor && d->m_cursor < end) {
1892 // cursor is within the selection. Split up the commands
1893 // to be able to restore the correct cursor position
1894 for (int i = d->m_cursor; i >= start; --i) {
1895 d->addCommand(QQuickTextInputPrivate::Command(
1896 QQuickTextInputPrivate::DeleteSelection, i, d->m_text.at(i), -1, 1));
1898 for (int i = end - 1; i > d->m_cursor; --i) {
1899 d->addCommand(QQuickTextInputPrivate::Command(
1900 QQuickTextInputPrivate::DeleteSelection, i - d->m_cursor + start - 1, d->m_text.at(i), -1, -1));
1903 for (int i = end - 1; i >= start; --i) {
1904 d->addCommand(QQuickTextInputPrivate::Command(
1905 QQuickTextInputPrivate::RemoveSelection, i, d->m_text.at(i), -1, -1));
1908 if (d->m_maskData) {
1909 d->m_text.replace(start, end - start, d->clearString(start, end - start));
1910 for (int i = 0; i < end - start; ++i) {
1911 d->addCommand(QQuickTextInputPrivate::Command(
1912 QQuickTextInputPrivate::Insert, start + i, d->m_text.at(start + i), -1, -1));
1915 d->m_text.remove(start, end - start);
1917 if (d->m_cursor > start)
1918 d->m_cursor -= qMin(d->m_cursor, end) - start;
1919 if (d->m_selstart > start)
1920 d->m_selstart -= qMin(d->m_selstart, end) - start;
1921 if (d->m_selend > end)
1922 d->m_selend -= qMin(d->m_selend, end) - start;
1924 d->addCommand(QQuickTextInputPrivate::Command(
1925 QQuickTextInputPrivate::SetSelection, d->m_cursor, 0, d->m_selstart, d->m_selend));
1927 d->m_textDirty = true;
1928 d->finishChange(priorState);
1930 if (d->lastSelectionStart != d->lastSelectionEnd) {
1931 if (d->m_selstart != d->lastSelectionStart) {
1932 d->lastSelectionStart = d->m_selstart;
1933 emit selectionStartChanged();
1935 if (d->m_selend != d->lastSelectionEnd) {
1936 d->lastSelectionEnd = d->m_selend;
1937 emit selectionEndChanged();
1944 \qmlmethod void QtQuick2::TextInput::selectWord()
1946 Causes the word closest to the current cursor position to be selected.
1948 void QQuickTextInput::selectWord()
1950 Q_D(QQuickTextInput);
1951 d->selectWordAtPos(d->m_cursor);
1955 \qmlproperty bool QtQuick2::TextInput::smooth
1957 This property holds whether the text is smoothly scaled or transformed.
1959 Smooth filtering gives better visual quality, but is slower. If
1960 the item is displayed at its natural size, this property has no visual or
1963 \note Generally scaling artifacts are only visible if the item is stationary on
1964 the screen. A common pattern when animating an item is to disable smooth
1965 filtering at the beginning of the animation and reenable it at the conclusion.
1969 \qmlproperty string QtQuick2::TextInput::passwordCharacter
1971 This is the character displayed when echoMode is set to Password or
1972 PasswordEchoOnEdit. By default it is an asterisk.
1974 If this property is set to a string with more than one character,
1975 the first character is used. If the string is empty, the value
1976 is ignored and the property is not set.
1978 QString QQuickTextInput::passwordCharacter() const
1980 Q_D(const QQuickTextInput);
1981 return QString(d->m_passwordCharacter);
1984 void QQuickTextInput::setPasswordCharacter(const QString &str)
1986 Q_D(QQuickTextInput);
1987 if (str.length() < 1)
1989 d->m_passwordCharacter = str.constData()[0];
1990 if (d->m_echoMode == Password || d->m_echoMode == PasswordEchoOnEdit)
1991 d->updateDisplayText();
1992 emit passwordCharacterChanged();
1996 \qmlproperty string QtQuick2::TextInput::displayText
1998 This is the text displayed in the TextInput.
2000 If \l echoMode is set to TextInput::Normal, this holds the
2001 same value as the TextInput::text property. Otherwise,
2002 this property holds the text visible to the user, while
2003 the \l text property holds the actual entered text.
2005 QString QQuickTextInput::displayText() const
2007 Q_D(const QQuickTextInput);
2008 return d->m_textLayout.text();
2012 \qmlproperty bool QtQuick2::TextInput::selectByMouse
2016 If true, the user can use the mouse to select text in some
2017 platform-specific way. Note that for some platforms this may
2018 not be an appropriate interaction (eg. may conflict with how
2019 the text needs to behave inside a Flickable.
2021 bool QQuickTextInput::selectByMouse() const
2023 Q_D(const QQuickTextInput);
2024 return d->selectByMouse;
2027 void QQuickTextInput::setSelectByMouse(bool on)
2029 Q_D(QQuickTextInput);
2030 if (d->selectByMouse != on) {
2031 d->selectByMouse = on;
2032 emit selectByMouseChanged(on);
2037 \qmlproperty enum QtQuick2::TextInput::mouseSelectionMode
2039 Specifies how text should be selected using a mouse.
2042 \o TextInput.SelectCharacters - The selection is updated with individual characters. (Default)
2043 \o TextInput.SelectWords - The selection is updated with whole words.
2046 This property only applies when \l selectByMouse is true.
2049 QQuickTextInput::SelectionMode QQuickTextInput::mouseSelectionMode() const
2051 Q_D(const QQuickTextInput);
2052 return d->mouseSelectionMode;
2055 void QQuickTextInput::setMouseSelectionMode(SelectionMode mode)
2057 Q_D(QQuickTextInput);
2058 if (d->mouseSelectionMode != mode) {
2059 d->mouseSelectionMode = mode;
2060 emit mouseSelectionModeChanged(mode);
2065 \qmlproperty bool QtQuick2::TextInput::canPaste
2067 Returns true if the TextInput is writable and the content of the clipboard is
2068 suitable for pasting into the TextEdit.
2070 bool QQuickTextInput::canPaste() const
2072 Q_D(const QQuickTextInput);
2073 if (!d->canPasteValid) {
2074 if (const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData())
2075 const_cast<QQuickTextInputPrivate *>(d)->canPaste = !d->m_readOnly && mimeData->hasText();
2076 const_cast<QQuickTextInputPrivate *>(d)->canPasteValid = true;
2082 \qmlproperty bool QtQuick2::TextInput::canUndo
2084 Returns true if the TextInput is writable and there are previous operations
2088 bool QQuickTextInput::canUndo() const
2090 Q_D(const QQuickTextInput);
2095 \qmlproperty bool QtQuick2::TextInput::canRedo
2097 Returns true if the TextInput is writable and there are \l {undo}{undone}
2098 operations that can be redone.
2101 bool QQuickTextInput::canRedo() const
2103 Q_D(const QQuickTextInput);
2107 void QQuickTextInput::moveCursorSelection(int position)
2109 Q_D(QQuickTextInput);
2110 d->moveCursor(position, true);
2114 \qmlmethod void QtQuick2::TextInput::moveCursorSelection(int position, SelectionMode mode = TextInput.SelectCharacters)
2116 Moves the cursor to \a position and updates the selection according to the optional \a mode
2117 parameter. (To only move the cursor, set the \l cursorPosition property.)
2119 When this method is called it additionally sets either the
2120 selectionStart or the selectionEnd (whichever was at the previous cursor position)
2121 to the specified position. This allows you to easily extend and contract the selected
2124 The selection mode specifies whether the selection is updated on a per character or a per word
2125 basis. If not specified the selection mode will default to TextInput.SelectCharacters.
2128 \o TextEdit.SelectCharacters - Sets either the selectionStart or selectionEnd (whichever was at
2129 the previous cursor position) to the specified position.
2130 \o TextEdit.SelectWords - Sets the selectionStart and selectionEnd to include all
2131 words between the specified position and the previous cursor position. Words partially in the
2135 For example, take this sequence of calls:
2139 moveCursorSelection(9, TextInput.SelectCharacters)
2140 moveCursorSelection(7, TextInput.SelectCharacters)
2143 This moves the cursor to position 5, extend the selection end from 5 to 9
2144 and then retract the selection end from 9 to 7, leaving the text from position 5 to 7
2145 selected (the 6th and 7th characters).
2147 The same sequence with TextInput.SelectWords will extend the selection start to a word boundary
2148 before or on position 5 and extend the selection end to a word boundary on or past position 9.
2150 void QQuickTextInput::moveCursorSelection(int pos, SelectionMode mode)
2152 Q_D(QQuickTextInput);
2154 if (mode == SelectCharacters) {
2155 d->moveCursor(pos, true);
2156 } else if (pos != d->m_cursor){
2157 const int cursor = d->m_cursor;
2159 if (!d->hasSelectedText())
2160 anchor = d->m_cursor;
2161 else if (d->selectionStart() == d->m_cursor)
2162 anchor = d->selectionEnd();
2164 anchor = d->selectionStart();
2166 if (anchor < pos || (anchor == pos && cursor < pos)) {
2167 const QString text = this->text();
2168 QTextBoundaryFinder finder(QTextBoundaryFinder::Word, text);
2169 finder.setPosition(anchor);
2171 const QTextBoundaryFinder::BoundaryReasons reasons = finder.boundaryReasons();
2172 if (anchor < text.length() && (!(reasons & QTextBoundaryFinder::StartWord)
2173 || ((reasons & QTextBoundaryFinder::EndWord) && anchor > cursor))) {
2174 finder.toPreviousBoundary();
2176 anchor = finder.position() != -1 ? finder.position() : 0;
2178 finder.setPosition(pos);
2179 if (pos > 0 && !finder.boundaryReasons())
2180 finder.toNextBoundary();
2181 const int cursor = finder.position() != -1 ? finder.position() : text.length();
2183 d->setSelection(anchor, cursor - anchor);
2184 } else if (anchor > pos || (anchor == pos && cursor > pos)) {
2185 const QString text = this->text();
2186 QTextBoundaryFinder finder(QTextBoundaryFinder::Word, text);
2187 finder.setPosition(anchor);
2189 const QTextBoundaryFinder::BoundaryReasons reasons = finder.boundaryReasons();
2190 if (anchor > 0 && (!(reasons & QTextBoundaryFinder::EndWord)
2191 || ((reasons & QTextBoundaryFinder::StartWord) && anchor < cursor))) {
2192 finder.toNextBoundary();
2195 anchor = finder.position() != -1 ? finder.position() : text.length();
2197 finder.setPosition(pos);
2198 if (pos < text.length() && !finder.boundaryReasons())
2199 finder.toPreviousBoundary();
2200 const int cursor = finder.position() != -1 ? finder.position() : 0;
2202 d->setSelection(anchor, cursor - anchor);
2208 \qmlmethod void QtQuick2::TextInput::openSoftwareInputPanel()
2210 Opens software input panels like virtual keyboards for typing, useful for
2211 customizing when you want the input keyboard to be shown and hidden in
2214 By default the opening of input panels follows the platform style. Input panels are
2215 always closed if no editor has active focus.
2217 You can disable the automatic behavior by setting the property \c activeFocusOnPress to false
2218 and use functions openSoftwareInputPanel() and closeSoftwareInputPanel() to implement
2219 the behavior you want.
2221 Only relevant on platforms, which provide virtual keyboards.
2227 text: "Hello world!"
2228 activeFocusOnPress: false
2230 anchors.fill: parent
2232 if (!textInput.activeFocus) {
2233 textInput.forceActiveFocus()
2234 textInput.openSoftwareInputPanel();
2236 textInput.focus = false;
2239 onPressAndHold: textInput.closeSoftwareInputPanel();
2244 void QQuickTextInput::openSoftwareInputPanel()
2247 qGuiApp->inputPanel()->show();
2251 \qmlmethod void QtQuick2::TextInput::closeSoftwareInputPanel()
2253 Closes a software input panel like a virtual keyboard shown on the screen, useful
2254 for customizing when you want the input keyboard to be shown and hidden in
2257 By default the opening of input panels follows the platform style. Input panels are
2258 always closed if no editor has active focus.
2260 You can disable the automatic behavior by setting the property \c activeFocusOnPress to false
2261 and use functions openSoftwareInputPanel() and closeSoftwareInputPanel() to implement
2262 the behavior you want.
2264 Only relevant on platforms, which provide virtual keyboards.
2270 text: "Hello world!"
2271 activeFocusOnPress: false
2273 anchors.fill: parent
2275 if (!textInput.activeFocus) {
2276 textInput.forceActiveFocus();
2277 textInput.openSoftwareInputPanel();
2279 textInput.focus = false;
2282 onPressAndHold: textInput.closeSoftwareInputPanel();
2287 void QQuickTextInput::closeSoftwareInputPanel()
2290 qGuiApp->inputPanel()->hide();
2293 void QQuickTextInput::focusInEvent(QFocusEvent *event)
2295 Q_D(const QQuickTextInput);
2296 if (d->focusOnPress && !d->m_readOnly)
2297 openSoftwareInputPanel();
2298 QQuickImplicitSizeItem::focusInEvent(event);
2301 void QQuickTextInput::itemChange(ItemChange change, const ItemChangeData &value)
2303 Q_D(QQuickTextInput);
2304 if (change == ItemActiveFocusHasChanged) {
2305 bool hasFocus = value.boolValue;
2306 d->focused = hasFocus;
2307 setCursorVisible(hasFocus); // ### refactor: && d->canvas && d->canvas->hasFocus()
2308 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
2309 if (!hasFocus && (d->m_passwordEchoEditing || d->m_passwordEchoTimer.isActive())) {
2311 if (!hasFocus && d->m_passwordEchoEditing) {
2313 d->updatePasswordEchoEditing(false);//QQuickTextInputPrivate sets it on key events, but doesn't deal with focus events
2319 disconnect(qApp->inputPanel(), SIGNAL(inputDirectionChanged(Qt::LayoutDirection)),
2320 this, SLOT(q_updateAlignment()));
2322 q_updateAlignment();
2323 connect(qApp->inputPanel(), SIGNAL(inputDirectionChanged(Qt::LayoutDirection)),
2324 this, SLOT(q_updateAlignment()));
2327 QQuickItem::itemChange(change, value);
2331 \qmlproperty bool QtQuick2::TextInput::inputMethodComposing
2334 This property holds whether the TextInput has partial text input from an
2337 While it is composing an input method may rely on mouse or key events from
2338 the TextInput to edit or commit the partial text. This property can be
2339 used to determine when to disable events handlers that may interfere with
2340 the correct operation of an input method.
2342 bool QQuickTextInput::isInputMethodComposing() const
2344 Q_D(const QQuickTextInput);
2345 return d->preeditAreaText().length() > 0;
2348 void QQuickTextInputPrivate::init()
2350 Q_Q(QQuickTextInput);
2351 q->setSmooth(smooth);
2352 q->setAcceptedMouseButtons(Qt::LeftButton);
2353 q->setFlag(QQuickItem::ItemAcceptsInputMethod);
2354 q->setFlag(QQuickItem::ItemHasContents);
2355 #ifndef QT_NO_CLIPBOARD
2356 q->connect(QGuiApplication::clipboard(), SIGNAL(dataChanged()),
2357 q, SLOT(q_canPasteChanged()));
2358 #endif // QT_NO_CLIPBOARD
2360 lastSelectionStart = 0;
2361 lastSelectionEnd = 0;
2362 selectedTextColor = m_palette.color(QPalette::HighlightedText);
2363 selectionColor = m_palette.color(QPalette::Highlight);
2364 determineHorizontalAlignment();
2366 if (!qmlDisableDistanceField()) {
2367 QTextOption option = m_textLayout.textOption();
2368 option.setUseDesignMetrics(true);
2369 m_textLayout.setTextOption(option);
2373 void QQuickTextInput::updateCursorRectangle()
2375 Q_D(QQuickTextInput);
2376 if (!isComponentComplete())
2379 d->updateHorizontalScroll();
2380 d->updateVerticalScroll();
2382 emit cursorRectangleChanged();
2383 if (d->cursorItem) {
2384 QRectF r = cursorRectangle();
2385 d->cursorItem->setPos(r.topLeft());
2386 d->cursorItem->setHeight(r.height());
2390 void QQuickTextInput::selectionChanged()
2392 Q_D(QQuickTextInput);
2393 d->textLayoutDirty = true; //TODO: Only update rect in selection
2395 emit selectedTextChanged();
2397 if (d->lastSelectionStart != d->selectionStart()) {
2398 d->lastSelectionStart = d->selectionStart();
2399 if (d->lastSelectionStart == -1)
2400 d->lastSelectionStart = d->m_cursor;
2401 emit selectionStartChanged();
2403 if (d->lastSelectionEnd != d->selectionEnd()) {
2404 d->lastSelectionEnd = d->selectionEnd();
2405 if (d->lastSelectionEnd == -1)
2406 d->lastSelectionEnd = d->m_cursor;
2407 emit selectionEndChanged();
2411 void QQuickTextInputPrivate::showCursor()
2413 if (textNode != 0 && textNode->cursorNode() != 0)
2414 textNode->cursorNode()->setColor(color);
2417 void QQuickTextInputPrivate::hideCursor()
2419 if (textNode != 0 && textNode->cursorNode() != 0)
2420 textNode->cursorNode()->setColor(QColor(0, 0, 0, 0));
2423 QRectF QQuickTextInput::boundingRect() const
2425 Q_D(const QQuickTextInput);
2427 int cursorWidth = d->cursorItem ? d->cursorItem->width() : d->m_cursorWidth;
2429 // Could include font max left/right bearings to either side of rectangle.
2430 QRectF r = QQuickImplicitSizeItem::boundingRect();
2431 r.setRight(r.right() + cursorWidth);
2435 void QQuickTextInput::q_canPasteChanged()
2437 Q_D(QQuickTextInput);
2438 bool old = d->canPaste;
2439 #ifndef QT_NO_CLIPBOARD
2440 if (const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData())
2441 d->canPaste = !d->m_readOnly && mimeData->hasText();
2443 d->canPaste = false;
2446 bool changed = d->canPaste != old || !d->canPasteValid;
2447 d->canPasteValid = true;
2449 emit canPasteChanged();
2453 void QQuickTextInput::q_updateAlignment()
2455 Q_D(QQuickTextInput);
2456 if (d->determineHorizontalAlignment()) {
2458 updateCursorRectangle();
2462 // ### these should come from QStyleHints
2463 const int textCursorWidth = 1;
2464 const bool fullWidthSelection = true;
2469 Updates the display text based of the current edit text
2470 If the text has changed will emit displayTextChanged()
2472 void QQuickTextInputPrivate::updateDisplayText(bool forceUpdate)
2474 QString orig = m_textLayout.text();
2476 if (m_echoMode == QQuickTextInput::NoEcho)
2477 str = QString::fromLatin1("");
2481 if (m_echoMode == QQuickTextInput::Password) {
2482 str.fill(m_passwordCharacter);
2483 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
2484 if (m_passwordEchoTimer.isActive() && m_cursor > 0 && m_cursor <= m_text.length()) {
2485 int cursor = m_cursor - 1;
2486 QChar uc = m_text.at(cursor);
2488 if (cursor > 0 && uc.unicode() >= 0xdc00 && uc.unicode() < 0xe000) {
2489 // second half of a surrogate, check if we have the first half as well,
2490 // if yes restore both at once
2491 uc = m_text.at(cursor - 1);
2492 if (uc.unicode() >= 0xd800 && uc.unicode() < 0xdc00)
2493 str[cursor - 1] = uc;
2497 } else if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit && !m_passwordEchoEditing) {
2498 str.fill(m_passwordCharacter);
2501 // replace certain non-printable characters with spaces (to avoid
2502 // drawing boxes when using fonts that don't have glyphs for such
2504 QChar* uc = str.data();
2505 for (int i = 0; i < (int)str.length(); ++i) {
2506 if ((uc[i] < 0x20 && uc[i] != 0x09)
2507 || uc[i] == QChar::LineSeparator
2508 || uc[i] == QChar::ParagraphSeparator
2509 || uc[i] == QChar::ObjectReplacementCharacter)
2510 uc[i] = QChar(0x0020);
2513 if (str != orig || forceUpdate) {
2514 m_textLayout.setText(str);
2515 updateLayout(); // polish?
2516 emit q_func()->displayTextChanged();
2520 void QQuickTextInputPrivate::updateLayout()
2522 Q_Q(QQuickTextInput);
2524 if (!q->isComponentComplete())
2527 QTextOption option = m_textLayout.textOption();
2528 option.setTextDirection(layoutDirection());
2529 option.setFlags(QTextOption::IncludeTrailingSpaces);
2530 option.setWrapMode(QTextOption::WrapMode(wrapMode));
2531 option.setAlignment(Qt::Alignment(q->effectiveHAlign()));
2532 m_textLayout.setTextOption(option);
2533 m_textLayout.setFont(font);
2535 boundingRect = QRectF();
2536 m_textLayout.beginLayout();
2537 QTextLine line = m_textLayout.createLine();
2538 qreal lineWidth = q->widthValid() ? q->width() : INT_MAX;
2540 QTextLine firstLine = line;
2542 line.setLineWidth(lineWidth);
2543 line.setPosition(QPointF(line.position().x(), height));
2544 boundingRect = boundingRect.united(line.naturalTextRect());
2546 height += line.height();
2547 line = m_textLayout.createLine();
2548 } while (line.isValid());
2549 m_textLayout.endLayout();
2551 option.setWrapMode(QTextOption::NoWrap);
2552 m_textLayout.setTextOption(option);
2554 m_ascent = qRound(firstLine.ascent());
2555 textLayoutDirty = true;
2558 q->setImplicitSize(qCeil(boundingRect.width()), qCeil(boundingRect.height()));
2562 #ifndef QT_NO_CLIPBOARD
2566 Copies the currently selected text into the clipboard using the given
2569 \note If the echo mode is set to a mode other than Normal then copy
2570 will not work. This is to prevent using copy as a method of bypassing
2571 password features of the line control.
2573 void QQuickTextInputPrivate::copy(QClipboard::Mode mode) const
2575 QString t = selectedText();
2576 if (!t.isEmpty() && m_echoMode == QQuickTextInput::Normal) {
2577 QGuiApplication::clipboard()->setText(t, mode);
2584 Inserts the text stored in the application clipboard into the line
2589 void QQuickTextInputPrivate::paste(QClipboard::Mode clipboardMode)
2591 QString clip = QGuiApplication::clipboard()->text(clipboardMode);
2592 if (!clip.isEmpty() || hasSelectedText()) {
2593 separate(); //make it a separate undo/redo command
2599 #endif // !QT_NO_CLIPBOARD
2604 Exits preedit mode and commits parts marked as tentative commit
2606 void QQuickTextInputPrivate::commitPreedit()
2611 qApp->inputPanel()->reset();
2613 if (!m_tentativeCommit.isEmpty()) {
2614 internalInsert(m_tentativeCommit);
2615 m_tentativeCommit.clear();
2616 finishChange(-1, true/*not used, not documented*/, false);
2619 m_preeditCursor = 0;
2620 m_textLayout.setPreeditArea(-1, QString());
2621 m_textLayout.clearAdditionalFormats();
2628 Handles the behavior for the backspace key or function.
2629 Removes the current selection if there is a selection, otherwise
2630 removes the character prior to the cursor position.
2634 void QQuickTextInputPrivate::backspace()
2636 int priorState = m_undoState;
2637 if (hasSelectedText()) {
2638 removeSelectedText();
2639 } else if (m_cursor) {
2642 m_cursor = prevMaskBlank(m_cursor);
2643 QChar uc = m_text.at(m_cursor);
2644 if (m_cursor > 0 && uc.unicode() >= 0xdc00 && uc.unicode() < 0xe000) {
2645 // second half of a surrogate, check if we have the first half as well,
2646 // if yes delete both at once
2647 uc = m_text.at(m_cursor - 1);
2648 if (uc.unicode() >= 0xd800 && uc.unicode() < 0xdc00) {
2649 internalDelete(true);
2653 internalDelete(true);
2655 finishChange(priorState);
2661 Handles the behavior for the delete key or function.
2662 Removes the current selection if there is a selection, otherwise
2663 removes the character after the cursor position.
2667 void QQuickTextInputPrivate::del()
2669 int priorState = m_undoState;
2670 if (hasSelectedText()) {
2671 removeSelectedText();
2673 int n = m_textLayout.nextCursorPosition(m_cursor) - m_cursor;
2677 finishChange(priorState);
2683 Inserts the given \a newText at the current cursor position.
2684 If there is any selected text it is removed prior to insertion of
2687 void QQuickTextInputPrivate::insert(const QString &newText)
2689 int priorState = m_undoState;
2690 removeSelectedText();
2691 internalInsert(newText);
2692 finishChange(priorState);
2698 Clears the line control text.
2700 void QQuickTextInputPrivate::clear()
2702 int priorState = m_undoState;
2704 m_selend = m_text.length();
2705 removeSelectedText();
2707 finishChange(priorState, /*update*/false, /*edited*/false);
2713 Sets \a length characters from the given \a start position as selected.
2714 The given \a start position must be within the current text for
2715 the line control. If \a length characters cannot be selected, then
2716 the selection will extend to the end of the current text.
2718 void QQuickTextInputPrivate::setSelection(int start, int length)
2720 Q_Q(QQuickTextInput);
2723 if (start < 0 || start > (int)m_text.length()){
2724 qWarning("QQuickTextInputPrivate::setSelection: Invalid start position");
2729 if (start == m_selstart && start + length == m_selend && m_cursor == m_selend)
2732 m_selend = qMin(start + length, (int)m_text.length());
2733 m_cursor = m_selend;
2734 } else if (length < 0){
2735 if (start == m_selend && start + length == m_selstart && m_cursor == m_selstart)
2737 m_selstart = qMax(start + length, 0);
2739 m_cursor = m_selstart;
2740 } else if (m_selstart != m_selend) {
2746 emitCursorPositionChanged();
2749 emit q->selectionChanged();
2750 emitCursorPositionChanged();
2751 qApp->inputPanel()->update(Qt::ImCursorRectangle | Qt::ImAnchorPosition
2752 | Qt::ImCursorPosition | Qt::ImCurrentSelection);
2758 Initializes the line control with a starting text value of \a txt.
2760 void QQuickTextInputPrivate::init(const QString &txt)
2764 updateDisplayText();
2765 m_cursor = m_text.length();
2771 Sets the password echo editing to \a editing. If password echo editing
2772 is true, then the text of the password is displayed even if the echo
2773 mode is set to QLineEdit::PasswordEchoOnEdit. Password echoing editing
2774 does not affect other echo modes.
2776 void QQuickTextInputPrivate::updatePasswordEchoEditing(bool editing)
2778 cancelPasswordEchoTimer();
2779 m_passwordEchoEditing = editing;
2780 updateDisplayText();
2786 Fixes the current text so that it is valid given any set validators.
2788 Returns true if the text was changed. Otherwise returns false.
2790 bool QQuickTextInputPrivate::fixup() // this function assumes that validate currently returns != Acceptable
2792 #ifndef QT_NO_VALIDATOR
2794 QString textCopy = m_text;
2795 int cursorCopy = m_cursor;
2796 m_validator->fixup(textCopy);
2797 if (m_validator->validate(textCopy, cursorCopy) == QValidator::Acceptable) {
2798 if (textCopy != m_text || cursorCopy != m_cursor)
2799 internalSetText(textCopy, cursorCopy);
2810 Moves the cursor to the given position \a pos. If \a mark is true will
2811 adjust the currently selected text.
2813 void QQuickTextInputPrivate::moveCursor(int pos, bool mark)
2815 Q_Q(QQuickTextInput);
2818 if (pos != m_cursor) {
2821 pos = pos > m_cursor ? nextMaskBlank(pos) : prevMaskBlank(pos);
2825 if (m_selend > m_selstart && m_cursor == m_selstart)
2827 else if (m_selend > m_selstart && m_cursor == m_selend)
2828 anchor = m_selstart;
2831 m_selstart = qMin(anchor, pos);
2832 m_selend = qMax(anchor, pos);
2837 if (mark || m_selDirty) {
2839 emit q->selectionChanged();
2841 emitCursorPositionChanged();
2842 q->updateMicroFocus();
2848 Applies the given input method event \a event to the text of the line
2851 void QQuickTextInputPrivate::processInputMethodEvent(QInputMethodEvent *event)
2853 Q_Q(QQuickTextInput);
2855 int priorState = -1;
2856 bool isGettingInput = !event->commitString().isEmpty()
2857 || event->preeditString() != preeditAreaText()
2858 || event->replacementLength() > 0;
2859 bool cursorPositionChanged = false;
2860 bool selectionChange = false;
2861 m_preeditDirty = event->preeditString() != preeditAreaText();
2863 if (isGettingInput) {
2864 // If any text is being input, remove selected text.
2865 priorState = m_undoState;
2866 if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit && !m_passwordEchoEditing) {
2867 updatePasswordEchoEditing(true);
2869 m_selend = m_text.length();
2871 removeSelectedText();
2874 int c = m_cursor; // cursor position after insertion of commit string
2875 if (event->replacementStart() <= 0)
2876 c += event->commitString().length() - qMin(-event->replacementStart(), event->replacementLength());
2878 m_cursor += event->replacementStart();
2882 // insert commit string
2883 if (event->replacementLength()) {
2884 m_selstart = m_cursor;
2885 m_selend = m_selstart + event->replacementLength();
2886 m_selend = qMin(m_selend, m_text.length());
2887 removeSelectedText();
2889 if (!event->commitString().isEmpty()) {
2890 internalInsert(event->commitString());
2891 cursorPositionChanged = true;
2894 m_cursor = qBound(0, c, m_text.length());
2896 for (int i = 0; i < event->attributes().size(); ++i) {
2897 const QInputMethodEvent::Attribute &a = event->attributes().at(i);
2898 if (a.type == QInputMethodEvent::Selection) {
2899 m_cursor = qBound(0, a.start + a.length, m_text.length());
2901 m_selstart = qMax(0, qMin(a.start, m_text.length()));
2902 m_selend = m_cursor;
2903 if (m_selend < m_selstart) {
2904 qSwap(m_selstart, m_selend);
2906 selectionChange = true;
2908 m_selstart = m_selend = 0;
2910 cursorPositionChanged = true;
2914 m_textLayout.setPreeditArea(m_cursor, event->preeditString());
2916 const int oldPreeditCursor = m_preeditCursor;
2917 m_preeditCursor = event->preeditString().length();
2918 m_hideCursor = false;
2919 QList<QTextLayout::FormatRange> formats;
2920 for (int i = 0; i < event->attributes().size(); ++i) {
2921 const QInputMethodEvent::Attribute &a = event->attributes().at(i);
2922 if (a.type == QInputMethodEvent::Cursor) {
2923 m_preeditCursor = a.start;
2924 m_hideCursor = !a.length;
2925 } else if (a.type == QInputMethodEvent::TextFormat) {
2926 QTextCharFormat f = qvariant_cast<QTextFormat>(a.value).toCharFormat();
2928 QTextLayout::FormatRange o;
2929 o.start = a.start + m_cursor;
2930 o.length = a.length;
2936 m_textLayout.setAdditionalFormats(formats);
2938 updateDisplayText(/*force*/ true);
2939 if (cursorPositionChanged) {
2940 emitCursorPositionChanged();
2941 } else if (m_preeditCursor != oldPreeditCursor) {
2942 q->updateCursorRectangle();
2943 qApp->inputPanel()->update(Qt::ImCursorRectangle);
2946 bool tentativeCommitChanged = m_tentativeCommit != event->tentativeCommitString();
2948 if (tentativeCommitChanged) {
2950 m_tentativeCommit = event->tentativeCommitString();
2953 if (isGettingInput || tentativeCommitChanged)
2954 finishChange(priorState);
2956 if (selectionChange) {
2957 emit q->selectionChanged();
2958 qApp->inputPanel()->update(Qt::ImCursorRectangle | Qt::ImAnchorPosition
2959 | Qt::ImCursorPosition | Qt::ImCurrentSelection);
2966 Sets the selection to cover the word at the given cursor position.
2967 The word boundaries are defined by the behavior of QTextLayout::SkipWords
2970 void QQuickTextInputPrivate::selectWordAtPos(int cursor)
2972 int next = cursor + 1;
2975 int c = m_textLayout.previousCursorPosition(next, QTextLayout::SkipWords);
2976 moveCursor(c, false);
2977 // ## text layout should support end of words.
2978 int end = m_textLayout.nextCursorPosition(c, QTextLayout::SkipWords);
2979 while (end > cursor && m_text[end-1].isSpace())
2981 moveCursor(end, true);
2987 Completes a change to the line control text. If the change is not valid
2988 will undo the line control state back to the given \a validateFromState.
2990 If \a edited is true and the change is valid, will emit textEdited() in
2991 addition to textChanged(). Otherwise only emits textChanged() on a valid
2994 The \a update value is currently unused.
2996 bool QQuickTextInputPrivate::finishChange(int validateFromState, bool update, bool /*edited*/)
2998 Q_Q(QQuickTextInput);
3001 bool notifyInputPanel = m_textDirty || m_selDirty;
3002 bool alignmentChanged = false;
3006 bool wasValidInput = m_validInput;
3007 m_validInput = true;
3008 #ifndef QT_NO_VALIDATOR
3010 QString textCopy = m_text;
3011 int cursorCopy = m_cursor;
3012 m_validInput = (m_validator->validate(textCopy, cursorCopy) != QValidator::Invalid);
3014 if (m_text != textCopy) {
3015 internalSetText(textCopy, cursorCopy);
3018 m_cursor = cursorCopy;
3020 if (!m_tentativeCommit.isEmpty()) {
3021 textCopy.insert(m_cursor, m_tentativeCommit);
3022 bool validInput = m_validator->validate(textCopy, cursorCopy) != QValidator::Invalid;
3024 m_tentativeCommit.clear();
3027 m_tentativeCommit.clear();
3031 if (validateFromState >= 0 && wasValidInput && !m_validInput) {
3032 if (m_transactions.count())
3034 internalUndo(validateFromState);
3035 m_history.resize(m_undoState);
3036 if (m_modifiedState > m_undoState)
3037 m_modifiedState = -1;
3038 m_validInput = true;
3039 m_textDirty = false;
3043 m_textDirty = false;
3044 m_preeditDirty = false;
3045 alignmentChanged = determineHorizontalAlignment();
3046 emit q->textChanged();
3049 updateDisplayText(alignmentChanged);
3051 if (m_validInput != wasValidInput)
3052 emit q->acceptableInputChanged();
3054 if (m_preeditDirty) {
3055 m_preeditDirty = false;
3056 if (determineHorizontalAlignment()) {
3057 alignmentChanged = true;
3064 emit q->selectionChanged();
3067 notifyInputPanel |= (m_cursor == m_lastCursorPos);
3068 if (notifyInputPanel)
3069 q->updateMicroFocus();
3070 emitUndoRedoChanged();
3072 if (!emitCursorPositionChanged() && alignmentChanged)
3073 q->updateCursorRectangle();
3081 An internal function for setting the text of the line control.
3083 void QQuickTextInputPrivate::internalSetText(const QString &txt, int pos, bool edited)
3085 Q_Q(QQuickTextInput);
3087 QString oldText = m_text;
3089 m_text = maskString(0, txt, true);
3090 m_text += clearString(m_text.length(), m_maxLength - m_text.length());
3092 m_text = txt.isEmpty() ? txt : txt.left(m_maxLength);
3095 m_modifiedState = m_undoState = 0;
3096 m_cursor = (pos < 0 || pos > m_text.length()) ? m_text.length() : pos;
3097 m_textDirty = (oldText != m_text);
3099 bool changed = finishChange(-1, true, edited);
3100 #ifdef QT_NO_ACCESSIBILITY
3104 QAccessible::updateAccessibility(q, 0, QAccessible::TextUpdated);
3112 Adds the given \a command to the undo history
3113 of the line control. Does not apply the command.
3115 void QQuickTextInputPrivate::addCommand(const Command &cmd)
3117 if (m_separator && m_undoState && m_history[m_undoState - 1].type != Separator) {
3118 m_history.resize(m_undoState + 2);
3119 m_history[m_undoState++] = Command(Separator, m_cursor, 0, m_selstart, m_selend);
3121 m_history.resize(m_undoState + 1);
3123 m_separator = false;
3124 m_history[m_undoState++] = cmd;
3130 Inserts the given string \a s into the line
3133 Also adds the appropriate commands into the undo history.
3134 This function does not call finishChange(), and may leave the text
3135 in an invalid state.
3137 void QQuickTextInputPrivate::internalInsert(const QString &s)
3139 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
3140 Q_Q(QQuickTextInput);
3141 if (m_echoMode == QQuickTextInput::Password)
3142 m_passwordEchoTimer.start(qt_passwordEchoDelay, q);
3144 if (hasSelectedText())
3145 addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
3147 QString ms = maskString(m_cursor, s);
3148 for (int i = 0; i < (int) ms.length(); ++i) {
3149 addCommand (Command(DeleteSelection, m_cursor + i, m_text.at(m_cursor + i), -1, -1));
3150 addCommand(Command(Insert, m_cursor + i, ms.at(i), -1, -1));
3152 m_text.replace(m_cursor, ms.length(), ms);
3153 m_cursor += ms.length();
3154 m_cursor = nextMaskBlank(m_cursor);
3157 int remaining = m_maxLength - m_text.length();
3158 if (remaining != 0) {
3159 m_text.insert(m_cursor, s.left(remaining));
3160 for (int i = 0; i < (int) s.left(remaining).length(); ++i)
3161 addCommand(Command(Insert, m_cursor++, s.at(i), -1, -1));
3170 deletes a single character from the current text. If \a wasBackspace,
3171 the character prior to the cursor is removed. Otherwise the character
3172 after the cursor is removed.
3174 Also adds the appropriate commands into the undo history.
3175 This function does not call finishChange(), and may leave the text
3176 in an invalid state.
3178 void QQuickTextInputPrivate::internalDelete(bool wasBackspace)
3180 if (m_cursor < (int) m_text.length()) {
3181 cancelPasswordEchoTimer();
3182 if (hasSelectedText())
3183 addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
3184 addCommand(Command((CommandType)((m_maskData ? 2 : 0) + (wasBackspace ? Remove : Delete)),
3185 m_cursor, m_text.at(m_cursor), -1, -1));
3187 m_text.replace(m_cursor, 1, clearString(m_cursor, 1));
3188 addCommand(Command(Insert, m_cursor, m_text.at(m_cursor), -1, -1));
3190 m_text.remove(m_cursor, 1);
3199 removes the currently selected text from the line control.
3201 Also adds the appropriate commands into the undo history.
3202 This function does not call finishChange(), and may leave the text
3203 in an invalid state.
3205 void QQuickTextInputPrivate::removeSelectedText()
3207 if (m_selstart < m_selend && m_selend <= (int) m_text.length()) {
3208 cancelPasswordEchoTimer();
3211 addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
3212 if (m_selstart <= m_cursor && m_cursor < m_selend) {
3213 // cursor is within the selection. Split up the commands
3214 // to be able to restore the correct cursor position
3215 for (i = m_cursor; i >= m_selstart; --i)
3216 addCommand (Command(DeleteSelection, i, m_text.at(i), -1, 1));
3217 for (i = m_selend - 1; i > m_cursor; --i)
3218 addCommand (Command(DeleteSelection, i - m_cursor + m_selstart - 1, m_text.at(i), -1, -1));
3220 for (i = m_selend-1; i >= m_selstart; --i)
3221 addCommand (Command(RemoveSelection, i, m_text.at(i), -1, -1));
3224 m_text.replace(m_selstart, m_selend - m_selstart, clearString(m_selstart, m_selend - m_selstart));
3225 for (int i = 0; i < m_selend - m_selstart; ++i)
3226 addCommand(Command(Insert, m_selstart + i, m_text.at(m_selstart + i), -1, -1));
3228 m_text.remove(m_selstart, m_selend - m_selstart);
3230 if (m_cursor > m_selstart)
3231 m_cursor -= qMin(m_cursor, m_selend) - m_selstart;
3240 Parses the input mask specified by \a maskFields to generate
3241 the mask data used to handle input masks.
3243 void QQuickTextInputPrivate::parseInputMask(const QString &maskFields)
3245 int delimiter = maskFields.indexOf(QLatin1Char(';'));
3246 if (maskFields.isEmpty() || delimiter == 0) {
3248 delete [] m_maskData;
3250 m_maxLength = 32767;
3251 internalSetText(QString());
3256 if (delimiter == -1) {
3257 m_blank = QLatin1Char(' ');
3258 m_inputMask = maskFields;
3260 m_inputMask = maskFields.left(delimiter);
3261 m_blank = (delimiter + 1 < maskFields.length()) ? maskFields[delimiter + 1] : QLatin1Char(' ');
3264 // calculate m_maxLength / m_maskData length
3267 for (int i=0; i<m_inputMask.length(); i++) {
3268 c = m_inputMask.at(i);
3269 if (i > 0 && m_inputMask.at(i-1) == QLatin1Char('\\')) {
3273 if (c != QLatin1Char('\\') && c != QLatin1Char('!') &&
3274 c != QLatin1Char('<') && c != QLatin1Char('>') &&
3275 c != QLatin1Char('{') && c != QLatin1Char('}') &&
3276 c != QLatin1Char('[') && c != QLatin1Char(']'))
3280 delete [] m_maskData;
3281 m_maskData = new MaskInputData[m_maxLength];
3283 MaskInputData::Casemode m = MaskInputData::NoCaseMode;
3286 bool escape = false;
3288 for (int i = 0; i < m_inputMask.length(); i++) {
3289 c = m_inputMask.at(i);
3292 m_maskData[index].maskChar = c;
3293 m_maskData[index].separator = s;
3294 m_maskData[index].caseMode = m;
3297 } else if (c == QLatin1Char('<')) {
3298 m = MaskInputData::Lower;
3299 } else if (c == QLatin1Char('>')) {
3300 m = MaskInputData::Upper;
3301 } else if (c == QLatin1Char('!')) {
3302 m = MaskInputData::NoCaseMode;
3303 } else if (c != QLatin1Char('{') && c != QLatin1Char('}') && c != QLatin1Char('[') && c != QLatin1Char(']')) {
3304 switch (c.unicode()) {
3330 m_maskData[index].maskChar = c;
3331 m_maskData[index].separator = s;
3332 m_maskData[index].caseMode = m;
3337 internalSetText(m_text);
3344 checks if the key is valid compared to the inputMask
3346 bool QQuickTextInputPrivate::isValidInput(QChar key, QChar mask) const
3348 switch (mask.unicode()) {
3354 if (key.isLetter() || key == m_blank)
3358 if (key.isLetterOrNumber())
3362 if (key.isLetterOrNumber() || key == m_blank)
3370 if (key.isPrint() || key == m_blank)
3378 if (key.isNumber() || key == m_blank)
3382 if (key.isNumber() && key.digitValue() > 0)
3386 if ((key.isNumber() && key.digitValue() > 0) || key == m_blank)
3390 if (key.isNumber() || key == QLatin1Char('+') || key == QLatin1Char('-') || key == m_blank)
3394 if (key == QLatin1Char('0') || key == QLatin1Char('1'))
3398 if (key == QLatin1Char('0') || key == QLatin1Char('1') || key == m_blank)
3402 if (key.isNumber() || (key >= QLatin1Char('a') && key <= QLatin1Char('f')) || (key >= QLatin1Char('A') && key <= QLatin1Char('F')))
3406 if (key.isNumber() || (key >= QLatin1Char('a') && key <= QLatin1Char('f')) || (key >= QLatin1Char('A') && key <= QLatin1Char('F')) || key == m_blank)
3418 Returns true if the given text \a str is valid for any
3419 validator or input mask set for the line control.
3421 Otherwise returns false
3423 bool QQuickTextInputPrivate::hasAcceptableInput(const QString &str) const
3425 #ifndef QT_NO_VALIDATOR
3426 QString textCopy = str;
3427 int cursorCopy = m_cursor;
3428 if (m_validator && m_validator->validate(textCopy, cursorCopy)
3429 != QValidator::Acceptable)
3436 if (str.length() != m_maxLength)
3439 for (int i=0; i < m_maxLength; ++i) {
3440 if (m_maskData[i].separator) {
3441 if (str.at(i) != m_maskData[i].maskChar)
3444 if (!isValidInput(str.at(i), m_maskData[i].maskChar))
3454 Applies the inputMask on \a str starting from position \a pos in the mask. \a clear
3455 specifies from where characters should be gotten when a separator is met in \a str - true means
3456 that blanks will be used, false that previous input is used.
3457 Calling this when no inputMask is set is undefined.
3459 QString QQuickTextInputPrivate::maskString(uint pos, const QString &str, bool clear) const
3461 if (pos >= (uint)m_maxLength)
3462 return QString::fromLatin1("");
3465 fill = clear ? clearString(0, m_maxLength) : m_text;
3468 QString s = QString::fromLatin1("");
3470 while (i < m_maxLength) {
3471 if (strIndex < str.length()) {
3472 if (m_maskData[i].separator) {
3473 s += m_maskData[i].maskChar;
3474 if (str[(int)strIndex] == m_maskData[i].maskChar)
3478 if (isValidInput(str[(int)strIndex], m_maskData[i].maskChar)) {
3479 switch (m_maskData[i].caseMode) {
3480 case MaskInputData::Upper:
3481 s += str[(int)strIndex].toUpper();
3483 case MaskInputData::Lower:
3484 s += str[(int)strIndex].toLower();
3487 s += str[(int)strIndex];
3491 // search for separator first
3492 int n = findInMask(i, true, true, str[(int)strIndex]);
3494 if (str.length() != 1 || i == 0 || (i > 0 && (!m_maskData[i-1].separator || m_maskData[i-1].maskChar != str[(int)strIndex]))) {
3495 s += fill.mid(i, n-i+1);
3496 i = n + 1; // update i to find + 1
3499 // search for valid m_blank if not
3500 n = findInMask(i, true, false, str[(int)strIndex]);
3502 s += fill.mid(i, n-i);
3503 switch (m_maskData[n].caseMode) {
3504 case MaskInputData::Upper:
3505 s += str[(int)strIndex].toUpper();
3507 case MaskInputData::Lower:
3508 s += str[(int)strIndex].toLower();
3511 s += str[(int)strIndex];
3513 i = n + 1; // updates i to find + 1
3531 Returns a "cleared" string with only separators and blank chars.
3532 Calling this when no inputMask is set is undefined.
3534 QString QQuickTextInputPrivate::clearString(uint pos, uint len) const
3536 if (pos >= (uint)m_maxLength)
3540 int end = qMin((uint)m_maxLength, pos + len);
3541 for (int i = pos; i < end; ++i)
3542 if (m_maskData[i].separator)
3543 s += m_maskData[i].maskChar;
3553 Strips blank parts of the input in a QQuickTextInputPrivate when an inputMask is set,
3554 separators are still included. Typically "127.0__.0__.1__" becomes "127.0.0.1".
3556 QString QQuickTextInputPrivate::stripString(const QString &str) const
3562 int end = qMin(m_maxLength, (int)str.length());
3563 for (int i = 0; i < end; ++i) {
3564 if (m_maskData[i].separator)
3565 s += m_maskData[i].maskChar;
3566 else if (str[i] != m_blank)
3575 searches forward/backward in m_maskData for either a separator or a m_blank
3577 int QQuickTextInputPrivate::findInMask(int pos, bool forward, bool findSeparator, QChar searchChar) const
3579 if (pos >= m_maxLength || pos < 0)
3582 int end = forward ? m_maxLength : -1;
3583 int step = forward ? 1 : -1;
3587 if (findSeparator) {
3588 if (m_maskData[i].separator && m_maskData[i].maskChar == searchChar)
3591 if (!m_maskData[i].separator) {
3592 if (searchChar.isNull())
3594 else if (isValidInput(searchChar, m_maskData[i].maskChar))
3603 void QQuickTextInputPrivate::internalUndo(int until)
3605 if (!isUndoAvailable())
3607 cancelPasswordEchoTimer();
3609 while (m_undoState && m_undoState > until) {
3610 Command& cmd = m_history[--m_undoState];
3613 m_text.remove(cmd.pos, 1);
3617 m_selstart = cmd.selStart;
3618 m_selend = cmd.selEnd;
3622 case RemoveSelection:
3623 m_text.insert(cmd.pos, cmd.uc);
3624 m_cursor = cmd.pos + 1;
3627 case DeleteSelection:
3628 m_text.insert(cmd.pos, cmd.uc);
3634 if (until < 0 && m_undoState) {
3635 Command& next = m_history[m_undoState-1];
3636 if (next.type != cmd.type && next.type < RemoveSelection
3637 && (cmd.type < RemoveSelection || next.type == Separator))
3644 void QQuickTextInputPrivate::internalRedo()
3646 if (!isRedoAvailable())
3649 while (m_undoState < (int)m_history.size()) {
3650 Command& cmd = m_history[m_undoState++];
3653 m_text.insert(cmd.pos, cmd.uc);
3654 m_cursor = cmd.pos + 1;
3657 m_selstart = cmd.selStart;
3658 m_selend = cmd.selEnd;
3663 case RemoveSelection:
3664 case DeleteSelection:
3665 m_text.remove(cmd.pos, 1);
3666 m_selstart = cmd.selStart;
3667 m_selend = cmd.selEnd;
3671 m_selstart = cmd.selStart;
3672 m_selend = cmd.selEnd;
3676 if (m_undoState < (int)m_history.size()) {
3677 Command& next = m_history[m_undoState];
3678 if (next.type != cmd.type && cmd.type < RemoveSelection && next.type != Separator
3679 && (next.type < RemoveSelection || cmd.type == Separator))
3686 void QQuickTextInputPrivate::emitUndoRedoChanged()
3688 Q_Q(QQuickTextInput);
3689 const bool previousUndo = canUndo;
3690 const bool previousRedo = canRedo;
3692 canUndo = isUndoAvailable();
3693 canRedo = isRedoAvailable();
3695 if (previousUndo != canUndo)
3696 emit q->canUndoChanged();
3697 if (previousRedo != canRedo)
3698 emit q->canRedoChanged();
3704 If the current cursor position differs from the last emitted cursor
3705 position, emits cursorPositionChanged().
3707 bool QQuickTextInputPrivate::emitCursorPositionChanged()
3709 Q_Q(QQuickTextInput);
3710 if (m_cursor != m_lastCursorPos) {
3711 m_lastCursorPos = m_cursor;
3713 q->updateCursorRectangle();
3714 emit q->cursorPositionChanged();
3715 // XXX todo - not in 4.8?
3717 resetCursorBlinkTimer();
3720 if (!hasSelectedText()) {
3721 if (lastSelectionStart != m_cursor) {
3722 lastSelectionStart = m_cursor;
3723 emit q->selectionStartChanged();
3725 if (lastSelectionEnd != m_cursor) {
3726 lastSelectionEnd = m_cursor;
3727 emit q->selectionEndChanged();
3731 #ifndef QT_NO_ACCESSIBILITY
3732 QAccessible::updateAccessibility(q, 0, QAccessible::TextCaretMoved);
3741 void QQuickTextInputPrivate::setCursorBlinkPeriod(int msec)
3743 Q_Q(QQuickTextInput);
3744 if (msec == m_blinkPeriod)
3747 q->killTimer(m_blinkTimer);
3750 m_blinkTimer = q->startTimer(msec / 2);
3754 if (m_blinkStatus == 1)
3757 m_blinkPeriod = msec;
3760 void QQuickTextInputPrivate::resetCursorBlinkTimer()
3762 Q_Q(QQuickTextInput);
3763 if (m_blinkPeriod == 0 || m_blinkTimer == 0)
3765 q->killTimer(m_blinkTimer);
3766 m_blinkTimer = q->startTimer(m_blinkPeriod / 2);
3770 void QQuickTextInput::timerEvent(QTimerEvent *event)
3772 Q_D(QQuickTextInput);
3773 if (event->timerId() == d->m_blinkTimer) {
3774 d->m_blinkStatus = !d->m_blinkStatus;
3776 } else if (event->timerId() == d->m_deleteAllTimer) {
3777 killTimer(d->m_deleteAllTimer);
3778 d->m_deleteAllTimer = 0;
3780 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
3781 } else if (event->timerId() == d->m_passwordEchoTimer.timerId()) {
3782 d->m_passwordEchoTimer.stop();
3783 d->updateDisplayText();
3788 void QQuickTextInputPrivate::processKeyEvent(QKeyEvent* event)
3790 Q_Q(QQuickTextInput);
3791 bool inlineCompletionAccepted = false;
3793 if (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return) {
3794 if (hasAcceptableInput(m_text) || fixup()) {
3797 if (inlineCompletionAccepted)
3804 if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit
3805 && !m_passwordEchoEditing
3807 && !event->text().isEmpty()
3808 && !(event->modifiers() & Qt::ControlModifier)) {
3809 // Clear the edit and reset to normal echo mode while editing; the
3810 // echo mode switches back when the edit loses focus
3811 // ### resets current content. dubious code; you can
3812 // navigate with keys up, down, back, and select(?), but if you press
3813 // "left" or "right" it clears?
3814 updatePasswordEchoEditing(true);
3818 bool unknown = false;
3819 bool visual = cursorMoveStyle() == Qt::VisualMoveStyle;
3823 #ifndef QT_NO_SHORTCUT
3824 else if (event == QKeySequence::Undo) {
3828 else if (event == QKeySequence::Redo) {
3832 else if (event == QKeySequence::SelectAll) {
3835 #ifndef QT_NO_CLIPBOARD
3836 else if (event == QKeySequence::Copy) {
3839 else if (event == QKeySequence::Paste) {
3841 QClipboard::Mode mode = QClipboard::Clipboard;
3845 else if (event == QKeySequence::Cut) {
3851 else if (event == QKeySequence::DeleteEndOfLine) {
3853 setSelection(m_cursor, end());
3858 #endif //QT_NO_CLIPBOARD
3859 else if (event == QKeySequence::MoveToStartOfLine || event == QKeySequence::MoveToStartOfBlock) {
3862 else if (event == QKeySequence::MoveToEndOfLine || event == QKeySequence::MoveToEndOfBlock) {
3865 else if (event == QKeySequence::SelectStartOfLine || event == QKeySequence::SelectStartOfBlock) {
3868 else if (event == QKeySequence::SelectEndOfLine || event == QKeySequence::SelectEndOfBlock) {
3871 else if (event == QKeySequence::MoveToNextChar) {
3872 if (hasSelectedText()) {
3873 moveCursor(selectionEnd(), false);
3875 cursorForward(0, visual ? 1 : (layoutDirection() == Qt::LeftToRight ? 1 : -1));
3878 else if (event == QKeySequence::SelectNextChar) {
3879 cursorForward(1, visual ? 1 : (layoutDirection() == Qt::LeftToRight ? 1 : -1));
3881 else if (event == QKeySequence::MoveToPreviousChar) {
3882 if (hasSelectedText()) {
3883 moveCursor(selectionStart(), false);
3885 cursorForward(0, visual ? -1 : (layoutDirection() == Qt::LeftToRight ? -1 : 1));
3888 else if (event == QKeySequence::SelectPreviousChar) {
3889 cursorForward(1, visual ? -1 : (layoutDirection() == Qt::LeftToRight ? -1 : 1));
3891 else if (event == QKeySequence::MoveToNextWord) {
3892 if (m_echoMode == QQuickTextInput::Normal)
3893 layoutDirection() == Qt::LeftToRight ? cursorWordForward(0) : cursorWordBackward(0);
3895 layoutDirection() == Qt::LeftToRight ? end(0) : home(0);
3897 else if (event == QKeySequence::MoveToPreviousWord) {
3898 if (m_echoMode == QQuickTextInput::Normal)
3899 layoutDirection() == Qt::LeftToRight ? cursorWordBackward(0) : cursorWordForward(0);
3900 else if (!m_readOnly) {
3901 layoutDirection() == Qt::LeftToRight ? home(0) : end(0);
3904 else if (event == QKeySequence::SelectNextWord) {
3905 if (m_echoMode == QQuickTextInput::Normal)
3906 layoutDirection() == Qt::LeftToRight ? cursorWordForward(1) : cursorWordBackward(1);
3908 layoutDirection() == Qt::LeftToRight ? end(1) : home(1);
3910 else if (event == QKeySequence::SelectPreviousWord) {
3911 if (m_echoMode == QQuickTextInput::Normal)
3912 layoutDirection() == Qt::LeftToRight ? cursorWordBackward(1) : cursorWordForward(1);
3914 layoutDirection() == Qt::LeftToRight ? home(1) : end(1);
3916 else if (event == QKeySequence::Delete) {
3920 else if (event == QKeySequence::DeleteEndOfWord) {
3922 cursorWordForward(true);
3926 else if (event == QKeySequence::DeleteStartOfWord) {
3928 cursorWordBackward(true);
3932 #endif // QT_NO_SHORTCUT
3934 bool handled = false;
3935 if (event->modifiers() & Qt::ControlModifier) {
3936 switch (event->key()) {
3937 case Qt::Key_Backspace:
3939 cursorWordBackward(true);
3947 } else { // ### check for *no* modifier
3948 switch (event->key()) {
3949 case Qt::Key_Backspace:
3961 if (event->key() == Qt::Key_Direction_L || event->key() == Qt::Key_Direction_R) {
3962 setLayoutDirection((event->key() == Qt::Key_Direction_L) ? Qt::LeftToRight : Qt::RightToLeft);
3966 if (unknown && !m_readOnly) {
3967 QString t = event->text();
3968 if (!t.isEmpty() && t.at(0).isPrint()) {