1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the QtDeclarative module of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #include "qquicktextinput_p.h"
43 #include "qquicktextinput_p_p.h"
44 #include "qquickcanvas.h"
46 #include <private/qdeclarativeglobal_p.h>
48 #include <QtDeclarative/qdeclarativeinfo.h>
49 #include <QtGui/qevent.h>
50 #include <QTextBoundaryFinder>
51 #include "qquicktextnode_p.h"
52 #include <QtQuick/qsgsimplerectnode.h>
54 #include <QtGui/qstylehints.h>
55 #include <QtGui/qinputpanel.h>
57 #ifndef QT_NO_ACCESSIBILITY
58 #include "qaccessible.h"
63 DEFINE_BOOL_CONFIG_OPTION(qmlDisableDistanceField, QML_DISABLE_DISTANCEFIELD)
65 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
66 static const int qt_passwordEchoDelay = QT_GUI_PASSWORD_ECHO_DELAY;
70 \qmlclass TextInput QQuickTextInput
71 \inqmlmodule QtQuick 2
72 \ingroup qml-basic-visual-elements
73 \brief The TextInput item displays an editable line of text.
76 The TextInput element displays a single line of editable plain text.
78 TextInput is used to accept a line of text input. Input constraints
79 can be placed on a TextInput item (for example, through a \l validator or \l inputMask),
80 and setting \l echoMode to an appropriate value enables TextInput to be used for
81 a password input field.
83 On Mac OS X, the Up/Down key bindings for Home/End are explicitly disabled.
84 If you want such bindings (on any platform), you will need to construct them in QML.
86 \sa TextEdit, Text, {declarative/text/textselection}{Text Selection example}
88 QQuickTextInput::QQuickTextInput(QQuickItem* parent)
89 : QQuickImplicitSizeItem(*(new QQuickTextInputPrivate), parent)
95 QQuickTextInput::~QQuickTextInput()
99 void QQuickTextInput::componentComplete()
101 Q_D(QQuickTextInput);
103 QQuickImplicitSizeItem::componentComplete();
106 updateCursorRectangle();
107 if (d->cursorComponent && d->cursorComponent->isReady())
112 \qmlproperty string QtQuick2::TextInput::text
114 The text in the TextInput.
116 QString QQuickTextInput::text() const
118 Q_D(const QQuickTextInput);
120 QString content = d->m_text;
121 if (!d->m_tentativeCommit.isEmpty())
122 content.insert(d->m_cursor, d->m_tentativeCommit);
123 QString res = d->m_maskData ? d->stripString(content) : content;
124 return (res.isNull() ? QString::fromLatin1("") : res);
127 void QQuickTextInput::setText(const QString &s)
129 Q_D(QQuickTextInput);
132 if (d->composeMode())
133 qApp->inputPanel()->reset();
134 d->m_tentativeCommit.clear();
135 d->internalSetText(s, -1, false);
139 \qmlproperty int QtQuick2::TextInput::length
141 Returns the total number of characters in the TextInput item.
143 If the TextInput has an inputMask the length will include mask characters and may differ
144 from the length of the string returned by the \l text property.
146 This property can be faster than querying the length the \l text property as it doesn't
147 require any copying or conversion of the TextInput's internal string data.
150 int QQuickTextInput::length() const
152 Q_D(const QQuickTextInput);
153 return d->m_text.length();
157 \qmlmethod string QtQuick2::TextInput::getText(int start, int end)
159 Returns the section of text that is between the \a start and \a end positions.
161 If the TextInput has an inputMask the length will include mask characters.
164 QString QQuickTextInput::getText(int start, int end) const
166 Q_D(const QQuickTextInput);
171 return d->m_text.mid(start, end - start);
174 QString QQuickTextInputPrivate::realText() const
176 QString res = m_maskData ? stripString(m_text) : m_text;
177 return (res.isNull() ? QString::fromLatin1("") : res);
181 \qmlproperty string QtQuick2::TextInput::font.family
183 Sets the family name of the font.
185 The family name is case insensitive and may optionally include a foundry name, e.g. "Helvetica [Cronyx]".
186 If the family is available from more than one foundry and the foundry isn't specified, an arbitrary foundry is chosen.
187 If the family isn't available a family will be set using the font matching algorithm.
191 \qmlproperty bool QtQuick2::TextInput::font.bold
193 Sets whether the font weight is bold.
197 \qmlproperty enumeration QtQuick2::TextInput::font.weight
199 Sets the font's weight.
201 The weight can be one of:
204 \o Font.Normal - the default
211 TextInput { text: "Hello"; font.weight: Font.DemiBold }
216 \qmlproperty bool QtQuick2::TextInput::font.italic
218 Sets whether the font has an italic style.
222 \qmlproperty bool QtQuick2::TextInput::font.underline
224 Sets whether the text is underlined.
228 \qmlproperty bool QtQuick2::TextInput::font.strikeout
230 Sets whether the font has a strikeout style.
234 \qmlproperty real QtQuick2::TextInput::font.pointSize
236 Sets the font size in points. The point size must be greater than zero.
240 \qmlproperty int QtQuick2::TextInput::font.pixelSize
242 Sets the font size in pixels.
244 Using this function makes the font device dependent.
245 Use \c pointSize to set the size of the font in a device independent manner.
249 \qmlproperty real QtQuick2::TextInput::font.letterSpacing
251 Sets the letter spacing for the font.
253 Letter spacing changes the default spacing between individual letters in the font.
254 A positive value increases the letter spacing by the corresponding pixels; a negative value decreases the spacing.
258 \qmlproperty real QtQuick2::TextInput::font.wordSpacing
260 Sets the word spacing for the font.
262 Word spacing changes the default spacing between individual words.
263 A positive value increases the word spacing by a corresponding amount of pixels,
264 while a negative value decreases the inter-word spacing accordingly.
268 \qmlproperty enumeration QtQuick2::TextInput::font.capitalization
270 Sets the capitalization for the text.
273 \o Font.MixedCase - This is the normal text rendering option where no capitalization change is applied.
274 \o Font.AllUppercase - This alters the text to be rendered in all uppercase type.
275 \o Font.AllLowercase - This alters the text to be rendered in all lowercase type.
276 \o Font.SmallCaps - This alters the text to be rendered in small-caps type.
277 \o Font.Capitalize - This alters the text to be rendered with the first character of each word as an uppercase character.
281 TextInput { text: "Hello"; font.capitalization: Font.AllLowercase }
285 QFont QQuickTextInput::font() const
287 Q_D(const QQuickTextInput);
288 return d->sourceFont;
291 void QQuickTextInput::setFont(const QFont &font)
293 Q_D(QQuickTextInput);
294 if (d->sourceFont == font)
297 d->sourceFont = font;
298 QFont oldFont = d->font;
300 if (d->font.pointSizeF() != -1) {
302 qreal size = qRound(d->font.pointSizeF()*2.0);
303 d->font.setPointSizeF(size/2.0);
305 if (oldFont != d->font) {
307 updateCursorRectangle();
308 qApp->inputPanel()->update(Qt::ImCursorRectangle | Qt::ImFont);
310 emit fontChanged(d->sourceFont);
314 \qmlproperty color QtQuick2::TextInput::color
318 QColor QQuickTextInput::color() const
320 Q_D(const QQuickTextInput);
324 void QQuickTextInput::setColor(const QColor &c)
326 Q_D(QQuickTextInput);
329 d->textLayoutDirty = true;
331 emit colorChanged(c);
337 \qmlproperty color QtQuick2::TextInput::selectionColor
339 The text highlight color, used behind selections.
341 QColor QQuickTextInput::selectionColor() const
343 Q_D(const QQuickTextInput);
344 return d->selectionColor;
347 void QQuickTextInput::setSelectionColor(const QColor &color)
349 Q_D(QQuickTextInput);
350 if (d->selectionColor == color)
353 d->selectionColor = color;
354 d->m_palette.setColor(QPalette::Highlight, d->selectionColor);
355 if (d->hasSelectedText()) {
356 d->textLayoutDirty = true;
359 emit selectionColorChanged(color);
362 \qmlproperty color QtQuick2::TextInput::selectedTextColor
364 The highlighted text color, used in selections.
366 QColor QQuickTextInput::selectedTextColor() const
368 Q_D(const QQuickTextInput);
369 return d->selectedTextColor;
372 void QQuickTextInput::setSelectedTextColor(const QColor &color)
374 Q_D(QQuickTextInput);
375 if (d->selectedTextColor == color)
378 d->selectedTextColor = color;
379 d->m_palette.setColor(QPalette::HighlightedText, d->selectedTextColor);
380 if (d->hasSelectedText()) {
381 d->textLayoutDirty = true;
384 emit selectedTextColorChanged(color);
388 \qmlproperty enumeration QtQuick2::TextInput::horizontalAlignment
389 \qmlproperty enumeration QtQuick2::TextInput::effectiveHorizontalAlignment
390 \qmlproperty enumeration QtQuick2::TextInput::verticalAlignment
392 Sets the horizontal alignment of the text within the TextInput item's
393 width and height. By default, the text alignment follows the natural alignment
394 of the text, for example text that is read from left to right will be aligned to
397 TextInput does not have vertical alignment, as the natural height is
398 exactly the height of the single line of text. If you set the height
399 manually to something larger, TextInput will always be top aligned
400 vertically. You can use anchors to align it however you want within
403 The valid values for \c horizontalAlignment are \c TextInput.AlignLeft, \c TextInput.AlignRight and
404 \c TextInput.AlignHCenter.
406 Valid values for \c verticalAlignment are \c TextEdit.AlignTop (default),
407 \c TextEdit.AlignBottom \c TextEdit.AlignVCenter.
409 When using the attached property LayoutMirroring::enabled to mirror application
410 layouts, the horizontal alignment of text will also be mirrored. However, the property
411 \c horizontalAlignment will remain unchanged. To query the effective horizontal alignment
412 of TextInput, use the read-only property \c effectiveHorizontalAlignment.
414 QQuickTextInput::HAlignment QQuickTextInput::hAlign() const
416 Q_D(const QQuickTextInput);
420 void QQuickTextInput::setHAlign(HAlignment align)
422 Q_D(QQuickTextInput);
423 bool forceAlign = d->hAlignImplicit && d->effectiveLayoutMirror;
424 d->hAlignImplicit = false;
425 if (d->setHAlign(align, forceAlign) && isComponentComplete()) {
427 updateCursorRectangle();
431 void QQuickTextInput::resetHAlign()
433 Q_D(QQuickTextInput);
434 d->hAlignImplicit = true;
435 if (d->determineHorizontalAlignment() && isComponentComplete()) {
437 updateCursorRectangle();
441 QQuickTextInput::HAlignment QQuickTextInput::effectiveHAlign() const
443 Q_D(const QQuickTextInput);
444 QQuickTextInput::HAlignment effectiveAlignment = d->hAlign;
445 if (!d->hAlignImplicit && d->effectiveLayoutMirror) {
447 case QQuickTextInput::AlignLeft:
448 effectiveAlignment = QQuickTextInput::AlignRight;
450 case QQuickTextInput::AlignRight:
451 effectiveAlignment = QQuickTextInput::AlignLeft;
457 return effectiveAlignment;
460 bool QQuickTextInputPrivate::setHAlign(QQuickTextInput::HAlignment alignment, bool forceAlign)
462 Q_Q(QQuickTextInput);
463 if ((hAlign != alignment || forceAlign) && alignment <= QQuickTextInput::AlignHCenter) { // justify not supported
464 QQuickTextInput::HAlignment oldEffectiveHAlign = q->effectiveHAlign();
466 emit q->horizontalAlignmentChanged(alignment);
467 if (oldEffectiveHAlign != q->effectiveHAlign())
468 emit q->effectiveHorizontalAlignmentChanged();
474 bool QQuickTextInputPrivate::determineHorizontalAlignment()
476 if (hAlignImplicit) {
477 // if no explicit alignment has been set, follow the natural layout direction of the text
478 QString text = q_func()->text();
480 text = m_textLayout.preeditAreaText();
481 bool isRightToLeft = text.isEmpty() ? QGuiApplication::keyboardInputDirection() == Qt::RightToLeft : text.isRightToLeft();
482 return setHAlign(isRightToLeft ? QQuickTextInput::AlignRight : QQuickTextInput::AlignLeft);
487 QQuickTextInput::VAlignment QQuickTextInput::vAlign() const
489 Q_D(const QQuickTextInput);
493 void QQuickTextInput::setVAlign(QQuickTextInput::VAlignment alignment)
495 Q_D(QQuickTextInput);
496 if (alignment == d->vAlign)
498 d->vAlign = alignment;
499 emit verticalAlignmentChanged(d->vAlign);
500 if (isComponentComplete()) {
501 updateCursorRectangle();
506 \qmlproperty enumeration QtQuick2::TextInput::wrapMode
508 Set this property to wrap the text to the TextEdit item's width.
509 The text will only wrap if an explicit width has been set.
512 \o TextInput.NoWrap - no wrapping will be performed. If the text contains insufficient newlines, then implicitWidth will exceed a set width.
513 \o TextInput.WordWrap - wrapping is done on word boundaries only. If a word is too long, implicitWidth will exceed a set width.
514 \o TextInput.WrapAnywhere - wrapping is done at any point on a line, even if it occurs in the middle of a word.
515 \o TextInput.Wrap - if possible, wrapping occurs at a word boundary; otherwise it will occur at the appropriate point on the line, even in the middle of a word.
518 The default is TextInput.NoWrap. If you set a width, consider using TextInput.Wrap.
520 QQuickTextInput::WrapMode QQuickTextInput::wrapMode() const
522 Q_D(const QQuickTextInput);
526 void QQuickTextInput::setWrapMode(WrapMode mode)
528 Q_D(QQuickTextInput);
529 if (mode == d->wrapMode)
533 updateCursorRectangle();
534 emit wrapModeChanged();
537 void QQuickTextInputPrivate::mirrorChange()
539 Q_Q(QQuickTextInput);
540 if (q->isComponentComplete()) {
541 if (!hAlignImplicit && (hAlign == QQuickTextInput::AlignRight || hAlign == QQuickTextInput::AlignLeft)) {
542 q->updateCursorRectangle();
543 emit q->effectiveHorizontalAlignmentChanged();
549 \qmlproperty bool QtQuick2::TextInput::readOnly
551 Sets whether user input can modify the contents of the TextInput.
553 If readOnly is set to true, then user input will not affect the text
554 property. Any bindings or attempts to set the text property will still
557 bool QQuickTextInput::isReadOnly() const
559 Q_D(const QQuickTextInput);
560 return d->m_readOnly;
563 void QQuickTextInput::setReadOnly(bool ro)
565 Q_D(QQuickTextInput);
566 if (d->m_readOnly == ro)
569 setFlag(QQuickItem::ItemAcceptsInputMethod, !ro);
572 d->setCursorPosition(d->end());
574 emit readOnlyChanged(ro);
578 \qmlproperty int QtQuick2::TextInput::maximumLength
579 The maximum permitted length of the text in the TextInput.
581 If the text is too long, it is truncated at the limit.
583 By default, this property contains a value of 32767.
585 int QQuickTextInput::maxLength() const
587 Q_D(const QQuickTextInput);
588 return d->m_maxLength;
591 void QQuickTextInput::setMaxLength(int ml)
593 Q_D(QQuickTextInput);
594 if (d->m_maxLength == ml || d->m_maskData)
598 d->internalSetText(d->m_text, -1, false);
600 emit maximumLengthChanged(ml);
604 \qmlproperty bool QtQuick2::TextInput::cursorVisible
605 Set to true when the TextInput shows a cursor.
607 This property is set and unset when the TextInput gets active focus, so that other
608 properties can be bound to whether the cursor is currently showing. As it
609 gets set and unset automatically, when you set the value yourself you must
610 keep in mind that your value may be overwritten.
612 It can be set directly in script, for example if a KeyProxy might
613 forward keys to it and you desire it to look active when this happens
614 (but without actually giving it active focus).
616 It should not be set directly on the element, like in the below QML,
617 as the specified value will be overridden an lost on focus changes.
626 In the above snippet the cursor will still become visible when the
627 TextInput gains active focus.
629 bool QQuickTextInput::isCursorVisible() const
631 Q_D(const QQuickTextInput);
632 return d->cursorVisible;
635 void QQuickTextInput::setCursorVisible(bool on)
637 Q_D(QQuickTextInput);
638 if (d->cursorVisible == on)
640 d->cursorVisible = on;
641 d->setCursorBlinkPeriod(on ? qApp->styleHints()->cursorFlashTime() : 0);
643 emit cursorVisibleChanged(d->cursorVisible);
647 \qmlproperty int QtQuick2::TextInput::cursorPosition
648 The position of the cursor in the TextInput.
650 int QQuickTextInput::cursorPosition() const
652 Q_D(const QQuickTextInput);
656 void QQuickTextInput::setCursorPosition(int cp)
658 Q_D(QQuickTextInput);
659 if (cp < 0 || cp > text().length())
665 \qmlproperty rectangle QtQuick2::TextInput::cursorRectangle
667 The rectangle where the standard text cursor is rendered within the text input. Read only.
669 The position and height of a custom cursorDelegate are updated to follow the cursorRectangle
670 automatically when it changes. The width of the delegate is unaffected by changes in the
674 QRect QQuickTextInput::cursorRectangle() const
676 Q_D(const QQuickTextInput);
679 if (d->m_preeditCursor != -1)
680 c += d->m_preeditCursor;
681 if (d->m_echoMode == NoEcho)
683 QTextLine l = d->m_textLayout.lineForTextPosition(c);
687 qRound(l.cursorToX(c) - d->hscroll),
688 qRound(l.y() - d->vscroll),
694 \qmlproperty int QtQuick2::TextInput::selectionStart
696 The cursor position before the first character in the current selection.
698 This property is read-only. To change the selection, use select(start,end),
699 selectAll(), or selectWord().
701 \sa selectionEnd, cursorPosition, selectedText
703 int QQuickTextInput::selectionStart() const
705 Q_D(const QQuickTextInput);
706 return d->lastSelectionStart;
709 \qmlproperty int QtQuick2::TextInput::selectionEnd
711 The cursor position after the last character in the current selection.
713 This property is read-only. To change the selection, use select(start,end),
714 selectAll(), or selectWord().
716 \sa selectionStart, cursorPosition, selectedText
718 int QQuickTextInput::selectionEnd() const
720 Q_D(const QQuickTextInput);
721 return d->lastSelectionEnd;
724 \qmlmethod void QtQuick2::TextInput::select(int start, int end)
726 Causes the text from \a start to \a end to be selected.
728 If either start or end is out of range, the selection is not changed.
730 After calling this, selectionStart will become the lesser
731 and selectionEnd will become the greater (regardless of the order passed
734 \sa selectionStart, selectionEnd
736 void QQuickTextInput::select(int start, int end)
738 Q_D(QQuickTextInput);
739 if (start < 0 || end < 0 || start > d->m_text.length() || end > d->m_text.length())
741 d->setSelection(start, end-start);
745 \qmlproperty string QtQuick2::TextInput::selectedText
747 This read-only property provides the text currently selected in the
750 It is equivalent to the following snippet, but is faster and easier
754 myTextInput.text.toString().substring(myTextInput.selectionStart,
755 myTextInput.selectionEnd);
758 QString QQuickTextInput::selectedText() const
760 Q_D(const QQuickTextInput);
761 return d->selectedText();
765 \qmlproperty bool QtQuick2::TextInput::activeFocusOnPress
767 Whether the TextInput should gain active focus on a mouse press. By default this is
770 bool QQuickTextInput::focusOnPress() const
772 Q_D(const QQuickTextInput);
773 return d->focusOnPress;
776 void QQuickTextInput::setFocusOnPress(bool b)
778 Q_D(QQuickTextInput);
779 if (d->focusOnPress == b)
784 emit activeFocusOnPressChanged(d->focusOnPress);
787 \qmlproperty bool QtQuick2::TextInput::autoScroll
789 Whether the TextInput should scroll when the text is longer than the width. By default this is
792 bool QQuickTextInput::autoScroll() const
794 Q_D(const QQuickTextInput);
795 return d->autoScroll;
798 void QQuickTextInput::setAutoScroll(bool b)
800 Q_D(QQuickTextInput);
801 if (d->autoScroll == b)
805 //We need to repaint so that the scrolling is taking into account.
806 updateCursorRectangle();
807 emit autoScrollChanged(d->autoScroll);
810 #ifndef QT_NO_VALIDATOR
813 \qmlclass IntValidator QIntValidator
814 \inqmlmodule QtQuick 2
815 \ingroup qml-basic-visual-elements
817 This element provides a validator for integer values.
819 IntValidator uses the \l {QLocale::setDefault()}{default locale} to interpret the number and
820 will accept locale specific digits, group separators, and positive and negative signs. In
821 addition, IntValidator is always guaranteed to accept a number formatted according to the "C"
825 \qmlproperty int QtQuick2::IntValidator::top
827 This property holds the validator's highest acceptable value.
828 By default, this property's value is derived from the highest signed integer available (typically 2147483647).
831 \qmlproperty int QtQuick2::IntValidator::bottom
833 This property holds the validator's lowest acceptable value.
834 By default, this property's value is derived from the lowest signed integer available (typically -2147483647).
838 \qmlclass DoubleValidator QDoubleValidator
839 \inqmlmodule QtQuick 2
840 \ingroup qml-basic-visual-elements
842 This element provides a validator for non-integer numbers.
846 \qmlproperty real QtQuick2::DoubleValidator::top
848 This property holds the validator's maximum acceptable value.
849 By default, this property contains a value of infinity.
852 \qmlproperty real QtQuick2::DoubleValidator::bottom
854 This property holds the validator's minimum acceptable value.
855 By default, this property contains a value of -infinity.
858 \qmlproperty int QtQuick2::DoubleValidator::decimals
860 This property holds the validator's maximum number of digits after the decimal point.
861 By default, this property contains a value of 1000.
864 \qmlproperty enumeration QtQuick2::DoubleValidator::notation
865 This property holds the notation of how a string can describe a number.
867 The possible values for this property are:
870 \o DoubleValidator.StandardNotation
871 \o DoubleValidator.ScientificNotation (default)
874 If this property is set to DoubleValidator.ScientificNotation, the written number may have an exponent part (e.g. 1.5E-2).
878 \qmlclass RegExpValidator QRegExpValidator
879 \inqmlmodule QtQuick 2
880 \ingroup qml-basic-visual-elements
882 This element provides a validator, which counts as valid any string which
883 matches a specified regular expression.
886 \qmlproperty regExp QtQuick2::RegExpValidator::regExp
888 This property holds the regular expression used for validation.
890 Note that this property should be a regular expression in JS syntax, e.g /a/ for the regular expression
893 By default, this property contains a regular expression with the pattern .* that matches any string.
897 \qmlproperty Validator QtQuick2::TextInput::validator
899 Allows you to set a validator on the TextInput. When a validator is set
900 the TextInput will only accept input which leaves the text property in
901 an acceptable or intermediate state. The accepted signal will only be sent
902 if the text is in an acceptable state when enter is pressed.
904 Currently supported validators are IntValidator, DoubleValidator and
905 RegExpValidator. An example of using validators is shown below, which allows
906 input of integers between 11 and 31 into the text input:
911 validator: IntValidator{bottom: 11; top: 31;}
916 \sa acceptableInput, inputMask
919 QValidator* QQuickTextInput::validator() const
921 Q_D(const QQuickTextInput);
922 return d->m_validator;
925 void QQuickTextInput::setValidator(QValidator* v)
927 Q_D(QQuickTextInput);
928 if (d->m_validator == v)
932 if (!d->hasAcceptableInput(d->m_text)) {
933 d->oldValidity = false;
934 emit acceptableInputChanged();
937 emit validatorChanged();
939 #endif // QT_NO_VALIDATOR
942 \qmlproperty string QtQuick2::TextInput::inputMask
944 Allows you to set an input mask on the TextInput, restricting the allowable
945 text inputs. See QLineEdit::inputMask for further details, as the exact
946 same mask strings are used by TextInput.
948 \sa acceptableInput, validator
950 QString QQuickTextInput::inputMask() const
952 Q_D(const QQuickTextInput);
953 return d->inputMask();
956 void QQuickTextInput::setInputMask(const QString &im)
958 Q_D(QQuickTextInput);
959 if (d->inputMask() == im)
963 emit inputMaskChanged(d->inputMask());
967 \qmlproperty bool QtQuick2::TextInput::acceptableInput
969 This property is always true unless a validator or input mask has been set.
970 If a validator or input mask has been set, this property will only be true
971 if the current text is acceptable to the validator or input mask as a final
972 string (not as an intermediate string).
974 bool QQuickTextInput::hasAcceptableInput() const
976 Q_D(const QQuickTextInput);
977 return d->hasAcceptableInput(d->m_text);
981 \qmlsignal QtQuick2::TextInput::onAccepted()
983 This handler is called when the Return or Enter key is pressed.
984 Note that if there is a \l validator or \l inputMask set on the text
985 input, the handler will only be emitted if the input is in an acceptable
989 void QQuickTextInputPrivate::updateInputMethodHints()
991 Q_Q(QQuickTextInput);
992 Qt::InputMethodHints hints = inputMethodHints;
993 if (m_echoMode == QQuickTextInput::Password || m_echoMode == QQuickTextInput::NoEcho)
994 hints |= Qt::ImhHiddenText;
995 else if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit)
996 hints &= ~Qt::ImhHiddenText;
997 if (m_echoMode != QQuickTextInput::Normal)
998 hints |= (Qt::ImhNoAutoUppercase | Qt::ImhNoPredictiveText | Qt::ImhSensitiveData);
999 q->setInputMethodHints(hints);
1002 \qmlproperty enumeration QtQuick2::TextInput::echoMode
1004 Specifies how the text should be displayed in the TextInput.
1006 \o TextInput.Normal - Displays the text as it is. (Default)
1007 \o TextInput.Password - Displays asterisks instead of characters.
1008 \o TextInput.NoEcho - Displays nothing.
1009 \o TextInput.PasswordEchoOnEdit - Displays characters as they are entered
1010 while editing, otherwise displays asterisks.
1013 QQuickTextInput::EchoMode QQuickTextInput::echoMode() const
1015 Q_D(const QQuickTextInput);
1016 return QQuickTextInput::EchoMode(d->m_echoMode);
1019 void QQuickTextInput::setEchoMode(QQuickTextInput::EchoMode echo)
1021 Q_D(QQuickTextInput);
1022 if (echoMode() == echo)
1024 d->cancelPasswordEchoTimer();
1025 d->m_echoMode = echo;
1026 d->m_passwordEchoEditing = false;
1027 d->updateInputMethodHints();
1028 d->updateDisplayText();
1029 updateCursorRectangle();
1031 emit echoModeChanged(echoMode());
1035 \qmlproperty enumeration QtQuick2::TextInput::inputMethodHints
1037 Provides hints to the input method about the expected content of the text input and how it
1040 The value is a bit-wise combination of flags, or Qt.ImhNone if no hints are set.
1042 Flags that alter behaviour are:
1045 \o Qt.ImhHiddenText - Characters should be hidden, as is typically used when entering passwords.
1046 This is automatically set when setting echoMode to \c TextInput.Password.
1047 \o Qt.ImhSensitiveData - Typed text should not be stored by the active input method
1048 in any persistent storage like predictive user dictionary.
1049 \o Qt.ImhNoAutoUppercase - The input method should not try to automatically switch to upper case
1050 when a sentence ends.
1051 \o Qt.ImhPreferNumbers - Numbers are preferred (but not required).
1052 \o Qt.ImhPreferUppercase - Upper case letters are preferred (but not required).
1053 \o Qt.ImhPreferLowercase - Lower case letters are preferred (but not required).
1054 \o Qt.ImhNoPredictiveText - Do not use predictive text (i.e. dictionary lookup) while typing.
1056 \o Qt.ImhDate - The text editor functions as a date field.
1057 \o Qt.ImhTime - The text editor functions as a time field.
1060 Flags that restrict input (exclusive flags) are:
1063 \o Qt.ImhDigitsOnly - Only digits are allowed.
1064 \o Qt.ImhFormattedNumbersOnly - Only number input is allowed. This includes decimal point and minus sign.
1065 \o Qt.ImhUppercaseOnly - Only upper case letter input is allowed.
1066 \o Qt.ImhLowercaseOnly - Only lower case letter input is allowed.
1067 \o Qt.ImhDialableCharactersOnly - Only characters suitable for phone dialing are allowed.
1068 \o Qt.ImhEmailCharactersOnly - Only characters suitable for email addresses are allowed.
1069 \o Qt.ImhUrlCharactersOnly - Only characters suitable for URLs are allowed.
1075 \o Qt.ImhExclusiveInputMask - This mask yields nonzero if any of the exclusive flags are used.
1079 Qt::InputMethodHints QQuickTextInput::imHints() const
1081 Q_D(const QQuickTextInput);
1082 return d->inputMethodHints;
1085 void QQuickTextInput::setIMHints(Qt::InputMethodHints hints)
1087 Q_D(QQuickTextInput);
1088 if (d->inputMethodHints == hints)
1090 d->inputMethodHints = hints;
1091 d->updateInputMethodHints();
1095 \qmlproperty Component QtQuick2::TextInput::cursorDelegate
1096 The delegate for the cursor in the TextInput.
1098 If you set a cursorDelegate for a TextInput, this delegate will be used for
1099 drawing the cursor instead of the standard cursor. An instance of the
1100 delegate will be created and managed by the TextInput when a cursor is
1101 needed, and the x property of delegate instance will be set so as
1102 to be one pixel before the top left of the current character.
1104 Note that the root item of the delegate component must be a QDeclarativeItem or
1105 QDeclarativeItem derived item.
1107 QDeclarativeComponent* QQuickTextInput::cursorDelegate() const
1109 Q_D(const QQuickTextInput);
1110 return d->cursorComponent;
1113 void QQuickTextInput::setCursorDelegate(QDeclarativeComponent* c)
1115 Q_D(QQuickTextInput);
1116 if (d->cursorComponent == c)
1119 d->cursorComponent = c;
1121 //note that the components are owned by something else
1122 delete d->cursorItem;
1124 d->startCreatingCursor();
1127 emit cursorDelegateChanged();
1130 void QQuickTextInputPrivate::startCreatingCursor()
1132 Q_Q(QQuickTextInput);
1133 if (cursorComponent->isReady()) {
1135 } else if (cursorComponent->isLoading()) {
1136 q->connect(cursorComponent, SIGNAL(statusChanged(int)),
1137 q, SLOT(createCursor()));
1139 qmlInfo(q, cursorComponent->errors()) << QQuickTextInput::tr("Could not load cursor delegate");
1143 void QQuickTextInput::createCursor()
1145 Q_D(QQuickTextInput);
1146 if (!isComponentComplete())
1149 if (d->cursorComponent->isError()) {
1150 qmlInfo(this, d->cursorComponent->errors()) << tr("Could not load cursor delegate");
1154 if (!d->cursorComponent->isReady())
1158 delete d->cursorItem;
1159 QDeclarativeContext *creationContext = d->cursorComponent->creationContext();
1160 QObject *object = d->cursorComponent->create(creationContext ? creationContext : qmlContext(this));
1161 d->cursorItem = qobject_cast<QQuickItem*>(object);
1162 if (!d->cursorItem) {
1164 qmlInfo(this, d->cursorComponent->errors()) << tr("Could not instantiate cursor delegate");
1168 QRectF r = cursorRectangle();
1170 QDeclarative_setParent_noEvent(d->cursorItem, this);
1171 d->cursorItem->setParentItem(this);
1172 d->cursorItem->setPos(r.topLeft());
1173 d->cursorItem->setHeight(r.height());
1177 \qmlmethod rect QtQuick2::TextInput::positionToRectangle(int pos)
1179 This function takes a character position and returns the rectangle that the
1180 cursor would occupy, if it was placed at that character position.
1182 This is similar to setting the cursorPosition, and then querying the cursor
1183 rectangle, but the cursorPosition is not changed.
1185 QRectF QQuickTextInput::positionToRectangle(int pos) const
1187 Q_D(const QQuickTextInput);
1188 if (pos > d->m_cursor)
1189 pos += d->preeditAreaText().length();
1190 QTextLine l = d->m_textLayout.lineAt(0);
1192 ? QRectF(l.cursorToX(pos) - d->hscroll, 0.0, d->m_cursorWidth, l.height())
1197 \qmlmethod int QtQuick2::TextInput::positionAt(real x, real y, CursorPosition position = CursorBetweenCharacters)
1199 This function returns the character position at
1200 x and y pixels from the top left of the textInput. Position 0 is before the
1201 first character, position 1 is after the first character but before the second,
1202 and so on until position text.length, which is after all characters.
1204 This means that for all x values before the first character this function returns 0,
1205 and for all x values after the last character this function returns text.length. If
1206 the y value is above the text the position will be that of the nearest character on
1207 the first line line and if it is below the text the position of the nearest character
1208 on the last line will be returned.
1210 The cursor position type specifies how the cursor position should be resolved.
1213 \o TextInput.CursorBetweenCharacters - Returns the position between characters that is nearest x.
1214 \o TextInput.CursorOnCharacter - Returns the position before the character that is nearest x.
1218 void QQuickTextInput::positionAt(QDeclarativeV8Function *args) const
1220 Q_D(const QQuickTextInput);
1224 QTextLine::CursorPosition position = QTextLine::CursorBetweenCharacters;
1226 if (args->Length() < 1)
1230 v8::Local<v8::Value> arg = (*args)[i];
1231 x = arg->NumberValue();
1233 if (++i < args->Length()) {
1235 y = arg->NumberValue();
1238 if (++i < args->Length()) {
1240 position = QTextLine::CursorPosition(arg->Int32Value());
1243 int pos = d->positionAt(x, y, position);
1244 const int cursor = d->m_cursor;
1246 const int preeditLength = d->preeditAreaText().length();
1247 pos = pos > cursor + preeditLength
1248 ? pos - preeditLength
1251 args->returnValue(v8::Int32::New(pos));
1254 int QQuickTextInputPrivate::positionAt(int x, int y, QTextLine::CursorPosition position) const
1258 QTextLine line = m_textLayout.lineAt(0);
1259 for (int i = 1; i < m_textLayout.lineCount(); ++i) {
1260 QTextLine nextLine = m_textLayout.lineAt(i);
1262 if (y < (line.rect().bottom() + nextLine.y()) / 2)
1266 return line.isValid() ? line.xToCursor(x, position) : 0;
1269 void QQuickTextInput::keyPressEvent(QKeyEvent* ev)
1271 Q_D(QQuickTextInput);
1272 // Don't allow MacOSX up/down support, and we don't allow a completer.
1273 bool ignore = (ev->key() == Qt::Key_Up || ev->key() == Qt::Key_Down) && ev->modifiers() == Qt::NoModifier;
1274 if (!ignore && (d->lastSelectionStart == d->lastSelectionEnd) && (ev->key() == Qt::Key_Right || ev->key() == Qt::Key_Left)) {
1275 // Ignore when moving off the end unless there is a selection,
1276 // because then moving will do something (deselect).
1277 int cursorPosition = d->m_cursor;
1278 if (cursorPosition == 0)
1279 ignore = ev->key() == (d->layoutDirection() == Qt::LeftToRight ? Qt::Key_Left : Qt::Key_Right);
1280 if (cursorPosition == text().length())
1281 ignore = ev->key() == (d->layoutDirection() == Qt::LeftToRight ? Qt::Key_Right : Qt::Key_Left);
1286 d->processKeyEvent(ev);
1288 if (!ev->isAccepted())
1289 QQuickImplicitSizeItem::keyPressEvent(ev);
1292 void QQuickTextInput::inputMethodEvent(QInputMethodEvent *ev)
1294 Q_D(QQuickTextInput);
1295 const bool wasComposing = d->preeditAreaText().length() > 0;
1296 if (d->m_readOnly) {
1299 d->processInputMethodEvent(ev);
1301 if (!ev->isAccepted())
1302 QQuickImplicitSizeItem::inputMethodEvent(ev);
1304 if (wasComposing != (d->m_textLayout.preeditAreaText().length() > 0))
1305 emit inputMethodComposingChanged();
1308 void QQuickTextInput::mouseDoubleClickEvent(QMouseEvent *event)
1310 Q_D(QQuickTextInput);
1312 if (d->selectByMouse && event->button() == Qt::LeftButton) {
1314 int cursor = d->positionAt(event->localPos());
1315 d->selectWordAtPos(cursor);
1316 event->setAccepted(true);
1317 if (!d->hasPendingTripleClick()) {
1318 d->tripleClickStartPoint = event->localPos().toPoint();
1319 d->tripleClickTimer.start();
1322 if (d->sendMouseEventToInputContext(event))
1324 QQuickImplicitSizeItem::mouseDoubleClickEvent(event);
1328 void QQuickTextInput::mousePressEvent(QMouseEvent *event)
1330 Q_D(QQuickTextInput);
1332 d->pressPos = event->localPos();
1334 if (d->focusOnPress) {
1335 bool hadActiveFocus = hasActiveFocus();
1337 // re-open input panel on press if already focused
1338 if (hasActiveFocus() && hadActiveFocus && !d->m_readOnly)
1339 openSoftwareInputPanel();
1341 if (d->selectByMouse) {
1342 setKeepMouseGrab(false);
1343 d->selectPressed = true;
1344 QPoint distanceVector = d->pressPos.toPoint() - d->tripleClickStartPoint;
1345 if (d->hasPendingTripleClick()
1346 && distanceVector.manhattanLength() < qApp->styleHints()->startDragDistance()) {
1347 event->setAccepted(true);
1353 if (d->sendMouseEventToInputContext(event))
1356 bool mark = (event->modifiers() & Qt::ShiftModifier) && d->selectByMouse;
1357 int cursor = d->positionAt(event->localPos());
1358 d->moveCursor(cursor, mark);
1359 event->setAccepted(true);
1362 void QQuickTextInput::mouseMoveEvent(QMouseEvent *event)
1364 Q_D(QQuickTextInput);
1366 if (d->selectPressed) {
1367 if (qAbs(int(event->localPos().x() - d->pressPos.x())) > qApp->styleHints()->startDragDistance())
1368 setKeepMouseGrab(true);
1370 if (d->composeMode()) {
1372 int startPos = d->positionAt(d->pressPos);
1373 int currentPos = d->positionAt(event->localPos());
1374 if (startPos != currentPos)
1375 d->setSelection(startPos, currentPos - startPos);
1377 moveCursorSelection(d->positionAt(event->localPos()), d->mouseSelectionMode);
1379 event->setAccepted(true);
1381 QQuickImplicitSizeItem::mouseMoveEvent(event);
1385 void QQuickTextInput::mouseReleaseEvent(QMouseEvent *event)
1387 Q_D(QQuickTextInput);
1388 if (d->sendMouseEventToInputContext(event))
1390 if (d->selectPressed) {
1391 d->selectPressed = false;
1392 setKeepMouseGrab(false);
1394 #ifndef QT_NO_CLIPBOARD
1395 if (QGuiApplication::clipboard()->supportsSelection()) {
1396 if (event->button() == Qt::LeftButton) {
1397 d->copy(QClipboard::Selection);
1398 } else if (!d->m_readOnly && event->button() == Qt::MidButton) {
1400 d->insert(QGuiApplication::clipboard()->text(QClipboard::Selection));
1404 if (!event->isAccepted())
1405 QQuickImplicitSizeItem::mouseReleaseEvent(event);
1408 bool QQuickTextInputPrivate::sendMouseEventToInputContext(QMouseEvent *event)
1410 #if !defined QT_NO_IM
1411 if (composeMode()) {
1412 int tmp_cursor = positionAt(event->localPos());
1413 int mousePos = tmp_cursor - m_cursor;
1414 if (mousePos >= 0 && mousePos <= m_textLayout.preeditAreaText().length()) {
1415 if (event->type() == QEvent::MouseButtonRelease) {
1416 qApp->inputPanel()->invokeAction(QInputPanel::Click, mousePos);
1429 void QQuickTextInput::mouseUngrabEvent()
1431 Q_D(QQuickTextInput);
1432 d->selectPressed = false;
1433 setKeepMouseGrab(false);
1436 bool QQuickTextInput::event(QEvent* ev)
1438 #ifndef QT_NO_SHORTCUT
1439 Q_D(QQuickTextInput);
1440 if (ev->type() == QEvent::ShortcutOverride) {
1443 QKeyEvent* ke = static_cast<QKeyEvent*>(ev);
1444 if (ke == QKeySequence::Copy
1445 || ke == QKeySequence::Paste
1446 || ke == QKeySequence::Cut
1447 || ke == QKeySequence::Redo
1448 || ke == QKeySequence::Undo
1449 || ke == QKeySequence::MoveToNextWord
1450 || ke == QKeySequence::MoveToPreviousWord
1451 || ke == QKeySequence::MoveToStartOfDocument
1452 || ke == QKeySequence::MoveToEndOfDocument
1453 || ke == QKeySequence::SelectNextWord
1454 || ke == QKeySequence::SelectPreviousWord
1455 || ke == QKeySequence::SelectStartOfLine
1456 || ke == QKeySequence::SelectEndOfLine
1457 || ke == QKeySequence::SelectStartOfBlock
1458 || ke == QKeySequence::SelectEndOfBlock
1459 || ke == QKeySequence::SelectStartOfDocument
1460 || ke == QKeySequence::SelectAll
1461 || ke == QKeySequence::SelectEndOfDocument) {
1463 } else if (ke->modifiers() == Qt::NoModifier || ke->modifiers() == Qt::ShiftModifier
1464 || ke->modifiers() == Qt::KeypadModifier) {
1465 if (ke->key() < Qt::Key_Escape) {
1469 switch (ke->key()) {
1470 case Qt::Key_Delete:
1473 case Qt::Key_Backspace:
1485 return QQuickImplicitSizeItem::event(ev);
1488 void QQuickTextInput::geometryChanged(const QRectF &newGeometry,
1489 const QRectF &oldGeometry)
1491 Q_D(QQuickTextInput);
1492 if (newGeometry.width() != oldGeometry.width())
1494 updateCursorRectangle();
1495 QQuickImplicitSizeItem::geometryChanged(newGeometry, oldGeometry);
1498 void QQuickTextInputPrivate::updateHorizontalScroll()
1500 Q_Q(QQuickTextInput);
1501 QTextLine currentLine = m_textLayout.lineForTextPosition(m_cursor + m_preeditCursor);
1502 const int preeditLength = m_textLayout.preeditAreaText().length();
1503 const int width = qMax(0, qFloor(q->width()));
1504 int widthUsed = currentLine.isValid() ? qRound(currentLine.naturalTextWidth()) : 0;
1505 int previousScroll = hscroll;
1507 if (!autoScroll || widthUsed <= width || m_echoMode == QQuickTextInput::NoEcho) {
1510 Q_ASSERT(currentLine.isValid());
1511 int cix = qRound(currentLine.cursorToX(m_cursor + preeditLength));
1512 if (cix - hscroll >= width) {
1513 // text doesn't fit, cursor is to the right of br (scroll right)
1514 hscroll = cix - width;
1515 } else if (cix - hscroll < 0 && hscroll < widthUsed) {
1516 // text doesn't fit, cursor is to the left of br (scroll left)
1518 } else if (widthUsed - hscroll < width) {
1519 // text doesn't fit, text document is to the left of br; align
1521 hscroll = widthUsed - width;
1523 if (preeditLength > 0) {
1524 // check to ensure long pre-edit text doesn't push the cursor
1526 cix = qRound(currentLine.cursorToX(m_cursor + qMax(0, m_preeditCursor - 1)));
1531 if (previousScroll != hscroll)
1532 textLayoutDirty = true;
1535 void QQuickTextInputPrivate::updateVerticalScroll()
1537 Q_Q(QQuickTextInput);
1538 const int preeditLength = m_textLayout.preeditAreaText().length();
1539 const int height = qMax(0, qFloor(q->height()));
1540 int heightUsed = boundingRect.height();
1541 int previousScroll = vscroll;
1543 if (!autoScroll || heightUsed <= height) {
1544 // text fits in br; use vscroll for alignment
1545 switch (vAlign & ~(Qt::AlignAbsolute|Qt::AlignHorizontal_Mask)) {
1546 case Qt::AlignBottom:
1547 vscroll = heightUsed - height;
1549 case Qt::AlignVCenter:
1550 vscroll = (heightUsed - height) / 2;
1558 QTextLine currentLine = m_textLayout.lineForTextPosition(m_cursor + preeditLength);
1559 QRectF r = currentLine.isValid() ? currentLine.rect() : QRectF();
1560 int top = qFloor(r.top());
1561 int bottom = qCeil(r.bottom());
1563 if (bottom - vscroll >= height) {
1564 // text doesn't fit, cursor is to the below the br (scroll down)
1565 vscroll = bottom - height;
1566 } else if (top - vscroll < 0 && vscroll < heightUsed) {
1567 // text doesn't fit, cursor is above br (scroll up)
1569 } else if (heightUsed - vscroll < height) {
1570 // text doesn't fit, text document is to the left of br; align
1572 vscroll = heightUsed - height;
1574 if (preeditLength > 0) {
1575 // check to ensure long pre-edit text doesn't push the cursor
1577 currentLine = m_textLayout.lineForTextPosition(m_cursor + qMax(0, m_preeditCursor - 1));
1578 top = currentLine.isValid() ? qRound(currentLine.rect().top()) : 0;
1583 if (previousScroll != vscroll)
1584 textLayoutDirty = true;
1587 QSGNode *QQuickTextInput::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data)
1590 Q_D(QQuickTextInput);
1592 QQuickTextNode *node = static_cast<QQuickTextNode *>(oldNode);
1594 node = new QQuickTextNode(QQuickItemPrivate::get(this)->sceneGraphContext());
1597 if (!d->textLayoutDirty) {
1598 QSGSimpleRectNode *cursorNode = node->cursorNode();
1599 if (cursorNode != 0 && !isReadOnly()) {
1600 cursorNode->setRect(cursorRectangle());
1602 if (!d->cursorVisible || (!d->m_blinkStatus && d->m_blinkPeriod > 0)) {
1609 node->deleteContent();
1610 node->setMatrix(QMatrix4x4());
1612 QPoint offset = QPoint(0,0);
1613 QFontMetrics fm = QFontMetrics(d->font);
1614 if (d->autoScroll) {
1615 // the y offset is there to keep the baseline constant in case we have script changes in the text.
1616 offset = -QPoint(d->hscroll, d->vscroll + d->m_ascent - fm.ascent());
1618 offset = -QPoint(d->hscroll, d->vscroll);
1621 if (!d->m_textLayout.text().isEmpty()) {
1622 node->addTextLayout(offset, &d->m_textLayout, d->color,
1623 QQuickText::Normal, QColor(),
1624 d->selectionColor, d->selectedTextColor,
1625 d->selectionStart(),
1626 d->selectionEnd() - 1); // selectionEnd() returns first char after
1630 if (!isReadOnly() && d->cursorItem == 0) {
1631 node->setCursor(cursorRectangle(), d->color);
1632 if (!d->cursorVisible || (!d->m_blinkStatus && d->m_blinkPeriod > 0)) {
1639 d->textLayoutDirty = false;
1645 QVariant QQuickTextInput::inputMethodQuery(Qt::InputMethodQuery property) const
1647 Q_D(const QQuickTextInput);
1650 return QVariant((bool)(flags() & ItemAcceptsInputMethod));
1652 return QVariant((int)inputMethodHints());
1653 case Qt::ImCursorRectangle:
1654 return cursorRectangle();
1657 case Qt::ImCursorPosition:
1658 return QVariant(d->m_cursor);
1659 case Qt::ImSurroundingText:
1660 if (d->m_echoMode == PasswordEchoOnEdit && !d->m_passwordEchoEditing) {
1661 return QVariant(displayText());
1663 return QVariant(d->realText());
1665 case Qt::ImCurrentSelection:
1666 return QVariant(selectedText());
1667 case Qt::ImMaximumTextLength:
1668 return QVariant(maxLength());
1669 case Qt::ImAnchorPosition:
1670 if (d->selectionStart() == d->selectionEnd())
1671 return QVariant(d->m_cursor);
1672 else if (d->selectionStart() == d->m_cursor)
1673 return QVariant(d->selectionEnd());
1675 return QVariant(d->selectionStart());
1682 \qmlmethod void QtQuick2::TextInput::deselect()
1684 Removes active text selection.
1686 void QQuickTextInput::deselect()
1688 Q_D(QQuickTextInput);
1693 \qmlmethod void QtQuick2::TextInput::selectAll()
1695 Causes all text to be selected.
1697 void QQuickTextInput::selectAll()
1699 Q_D(QQuickTextInput);
1700 d->setSelection(0, text().length());
1704 \qmlmethod void QtQuick2::TextInput::isRightToLeft(int start, int end)
1706 Returns true if the natural reading direction of the editor text
1707 found between positions \a start and \a end is right to left.
1709 bool QQuickTextInput::isRightToLeft(int start, int end)
1712 qmlInfo(this) << "isRightToLeft(start, end) called with the end property being smaller than the start.";
1715 return text().mid(start, end - start).isRightToLeft();
1719 #ifndef QT_NO_CLIPBOARD
1721 \qmlmethod QtQuick2::TextInput::cut()
1723 Moves the currently selected text to the system clipboard.
1725 void QQuickTextInput::cut()
1727 Q_D(QQuickTextInput);
1733 \qmlmethod QtQuick2::TextInput::copy()
1735 Copies the currently selected text to the system clipboard.
1737 void QQuickTextInput::copy()
1739 Q_D(QQuickTextInput);
1744 \qmlmethod QtQuick2::TextInput::paste()
1746 Replaces the currently selected text by the contents of the system clipboard.
1748 void QQuickTextInput::paste()
1750 Q_D(QQuickTextInput);
1754 #endif // QT_NO_CLIPBOARD
1757 \qmlmethod void QtQuick2::TextInput::insert(int position, string text)
1759 Inserts \a text into the TextInput at position.
1762 void QQuickTextInput::insert(int position, const QString &text)
1764 Q_D(QQuickTextInput);
1765 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
1766 if (d->m_echoMode == QQuickTextInput::Password)
1767 d->m_passwordEchoTimer.start(qt_passwordEchoDelay, this);
1770 if (position < 0 || position > d->m_text.length())
1773 const int priorState = d->m_undoState;
1775 QString insertText = text;
1777 if (d->hasSelectedText()) {
1778 d->addCommand(QQuickTextInputPrivate::Command(
1779 QQuickTextInputPrivate::SetSelection, d->m_cursor, 0, d->m_selstart, d->m_selend));
1781 if (d->m_maskData) {
1782 insertText = d->maskString(position, insertText);
1783 for (int i = 0; i < insertText.length(); ++i) {
1784 d->addCommand(QQuickTextInputPrivate::Command(
1785 QQuickTextInputPrivate::DeleteSelection, position + i, d->m_text.at(position + i), -1, -1));
1786 d->addCommand(QQuickTextInputPrivate::Command(
1787 QQuickTextInputPrivate::Insert, position + i, insertText.at(i), -1, -1));
1789 d->m_text.replace(position, insertText.length(), insertText);
1790 if (!insertText.isEmpty())
1791 d->m_textDirty = true;
1792 if (position < d->m_selend && position + insertText.length() > d->m_selstart)
1793 d->m_selDirty = true;
1795 int remaining = d->m_maxLength - d->m_text.length();
1796 if (remaining != 0) {
1797 insertText = insertText.left(remaining);
1798 d->m_text.insert(position, insertText);
1799 for (int i = 0; i < insertText.length(); ++i)
1800 d->addCommand(QQuickTextInputPrivate::Command(
1801 QQuickTextInputPrivate::Insert, position + i, insertText.at(i), -1, -1));
1802 if (d->m_cursor >= position)
1803 d->m_cursor += insertText.length();
1804 if (d->m_selstart >= position)
1805 d->m_selstart += insertText.length();
1806 if (d->m_selend >= position)
1807 d->m_selend += insertText.length();
1808 d->m_textDirty = true;
1809 if (position >= d->m_selstart && position <= d->m_selend)
1810 d->m_selDirty = true;
1814 d->addCommand(QQuickTextInputPrivate::Command(
1815 QQuickTextInputPrivate::SetSelection, d->m_cursor, 0, d->m_selstart, d->m_selend));
1816 d->finishChange(priorState);
1818 if (d->lastSelectionStart != d->lastSelectionEnd) {
1819 if (d->m_selstart != d->lastSelectionStart) {
1820 d->lastSelectionStart = d->m_selstart;
1821 emit selectionStartChanged();
1823 if (d->m_selend != d->lastSelectionEnd) {
1824 d->lastSelectionEnd = d->m_selend;
1825 emit selectionEndChanged();
1831 \qmlmethod string QtQuick2::TextInput::getText(int start, int end)
1833 Removes the section of text that is between the \a start and \a end positions from the TextInput.
1836 void QQuickTextInput::remove(int start, int end)
1838 Q_D(QQuickTextInput);
1840 start = qBound(0, start, d->m_text.length());
1841 end = qBound(0, end, d->m_text.length());
1845 else if (start == end)
1848 if (start < d->m_selend && end > d->m_selstart)
1849 d->m_selDirty = true;
1851 const int priorState = d->m_undoState;
1853 d->addCommand(QQuickTextInputPrivate::Command(
1854 QQuickTextInputPrivate::SetSelection, d->m_cursor, 0, d->m_selstart, d->m_selend));
1856 if (start <= d->m_cursor && d->m_cursor < end) {
1857 // cursor is within the selection. Split up the commands
1858 // to be able to restore the correct cursor position
1859 for (int i = d->m_cursor; i >= start; --i) {
1860 d->addCommand(QQuickTextInputPrivate::Command(
1861 QQuickTextInputPrivate::DeleteSelection, i, d->m_text.at(i), -1, 1));
1863 for (int i = end - 1; i > d->m_cursor; --i) {
1864 d->addCommand(QQuickTextInputPrivate::Command(
1865 QQuickTextInputPrivate::DeleteSelection, i - d->m_cursor + start - 1, d->m_text.at(i), -1, -1));
1868 for (int i = end - 1; i >= start; --i) {
1869 d->addCommand(QQuickTextInputPrivate::Command(
1870 QQuickTextInputPrivate::RemoveSelection, i, d->m_text.at(i), -1, -1));
1873 if (d->m_maskData) {
1874 d->m_text.replace(start, end - start, d->clearString(start, end - start));
1875 for (int i = 0; i < end - start; ++i) {
1876 d->addCommand(QQuickTextInputPrivate::Command(
1877 QQuickTextInputPrivate::Insert, start + i, d->m_text.at(start + i), -1, -1));
1880 d->m_text.remove(start, end - start);
1882 if (d->m_cursor > start)
1883 d->m_cursor -= qMin(d->m_cursor, end) - start;
1884 if (d->m_selstart > start)
1885 d->m_selstart -= qMin(d->m_selstart, end) - start;
1886 if (d->m_selend > end)
1887 d->m_selend -= qMin(d->m_selend, end) - start;
1889 d->addCommand(QQuickTextInputPrivate::Command(
1890 QQuickTextInputPrivate::SetSelection, d->m_cursor, 0, d->m_selstart, d->m_selend));
1892 d->m_textDirty = true;
1893 d->finishChange(priorState);
1895 if (d->lastSelectionStart != d->lastSelectionEnd) {
1896 if (d->m_selstart != d->lastSelectionStart) {
1897 d->lastSelectionStart = d->m_selstart;
1898 emit selectionStartChanged();
1900 if (d->m_selend != d->lastSelectionEnd) {
1901 d->lastSelectionEnd = d->m_selend;
1902 emit selectionEndChanged();
1909 \qmlmethod void QtQuick2::TextInput::selectWord()
1911 Causes the word closest to the current cursor position to be selected.
1913 void QQuickTextInput::selectWord()
1915 Q_D(QQuickTextInput);
1916 d->selectWordAtPos(d->m_cursor);
1920 \qmlproperty bool QtQuick2::TextInput::smooth
1922 This property holds whether the text is smoothly scaled or transformed.
1924 Smooth filtering gives better visual quality, but is slower. If
1925 the item is displayed at its natural size, this property has no visual or
1928 \note Generally scaling artifacts are only visible if the item is stationary on
1929 the screen. A common pattern when animating an item is to disable smooth
1930 filtering at the beginning of the animation and reenable it at the conclusion.
1934 \qmlproperty string QtQuick2::TextInput::passwordCharacter
1936 This is the character displayed when echoMode is set to Password or
1937 PasswordEchoOnEdit. By default it is an asterisk.
1939 If this property is set to a string with more than one character,
1940 the first character is used. If the string is empty, the value
1941 is ignored and the property is not set.
1943 QString QQuickTextInput::passwordCharacter() const
1945 Q_D(const QQuickTextInput);
1946 return QString(d->m_passwordCharacter);
1949 void QQuickTextInput::setPasswordCharacter(const QString &str)
1951 Q_D(QQuickTextInput);
1952 if (str.length() < 1)
1954 d->m_passwordCharacter = str.constData()[0];
1955 if (d->m_echoMode == Password || d->m_echoMode == PasswordEchoOnEdit)
1956 d->updateDisplayText();
1957 emit passwordCharacterChanged();
1961 \qmlproperty string QtQuick2::TextInput::displayText
1963 This is the text displayed in the TextInput.
1965 If \l echoMode is set to TextInput::Normal, this holds the
1966 same value as the TextInput::text property. Otherwise,
1967 this property holds the text visible to the user, while
1968 the \l text property holds the actual entered text.
1970 QString QQuickTextInput::displayText() const
1972 Q_D(const QQuickTextInput);
1973 return d->m_textLayout.text();
1977 \qmlproperty bool QtQuick2::TextInput::selectByMouse
1981 If true, the user can use the mouse to select text in some
1982 platform-specific way. Note that for some platforms this may
1983 not be an appropriate interaction (eg. may conflict with how
1984 the text needs to behave inside a Flickable.
1986 bool QQuickTextInput::selectByMouse() const
1988 Q_D(const QQuickTextInput);
1989 return d->selectByMouse;
1992 void QQuickTextInput::setSelectByMouse(bool on)
1994 Q_D(QQuickTextInput);
1995 if (d->selectByMouse != on) {
1996 d->selectByMouse = on;
1997 emit selectByMouseChanged(on);
2002 \qmlproperty enum QtQuick2::TextInput::mouseSelectionMode
2004 Specifies how text should be selected using a mouse.
2007 \o TextInput.SelectCharacters - The selection is updated with individual characters. (Default)
2008 \o TextInput.SelectWords - The selection is updated with whole words.
2011 This property only applies when \l selectByMouse is true.
2014 QQuickTextInput::SelectionMode QQuickTextInput::mouseSelectionMode() const
2016 Q_D(const QQuickTextInput);
2017 return d->mouseSelectionMode;
2020 void QQuickTextInput::setMouseSelectionMode(SelectionMode mode)
2022 Q_D(QQuickTextInput);
2023 if (d->mouseSelectionMode != mode) {
2024 d->mouseSelectionMode = mode;
2025 emit mouseSelectionModeChanged(mode);
2030 \qmlproperty bool QtQuick2::TextInput::canPaste
2032 Returns true if the TextInput is writable and the content of the clipboard is
2033 suitable for pasting into the TextEdit.
2035 bool QQuickTextInput::canPaste() const
2037 Q_D(const QQuickTextInput);
2038 if (!d->canPasteValid) {
2039 if (const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData())
2040 const_cast<QQuickTextInputPrivate *>(d)->canPaste = !d->m_readOnly && mimeData->hasText();
2041 const_cast<QQuickTextInputPrivate *>(d)->canPasteValid = true;
2046 void QQuickTextInput::moveCursorSelection(int position)
2048 Q_D(QQuickTextInput);
2049 d->moveCursor(position, true);
2053 \qmlmethod void QtQuick2::TextInput::moveCursorSelection(int position, SelectionMode mode = TextInput.SelectCharacters)
2055 Moves the cursor to \a position and updates the selection according to the optional \a mode
2056 parameter. (To only move the cursor, set the \l cursorPosition property.)
2058 When this method is called it additionally sets either the
2059 selectionStart or the selectionEnd (whichever was at the previous cursor position)
2060 to the specified position. This allows you to easily extend and contract the selected
2063 The selection mode specifies whether the selection is updated on a per character or a per word
2064 basis. If not specified the selection mode will default to TextInput.SelectCharacters.
2067 \o TextEdit.SelectCharacters - Sets either the selectionStart or selectionEnd (whichever was at
2068 the previous cursor position) to the specified position.
2069 \o TextEdit.SelectWords - Sets the selectionStart and selectionEnd to include all
2070 words between the specified position and the previous cursor position. Words partially in the
2074 For example, take this sequence of calls:
2078 moveCursorSelection(9, TextInput.SelectCharacters)
2079 moveCursorSelection(7, TextInput.SelectCharacters)
2082 This moves the cursor to position 5, extend the selection end from 5 to 9
2083 and then retract the selection end from 9 to 7, leaving the text from position 5 to 7
2084 selected (the 6th and 7th characters).
2086 The same sequence with TextInput.SelectWords will extend the selection start to a word boundary
2087 before or on position 5 and extend the selection end to a word boundary on or past position 9.
2089 void QQuickTextInput::moveCursorSelection(int pos, SelectionMode mode)
2091 Q_D(QQuickTextInput);
2093 if (mode == SelectCharacters) {
2094 d->moveCursor(pos, true);
2095 } else if (pos != d->m_cursor){
2096 const int cursor = d->m_cursor;
2098 if (!d->hasSelectedText())
2099 anchor = d->m_cursor;
2100 else if (d->selectionStart() == d->m_cursor)
2101 anchor = d->selectionEnd();
2103 anchor = d->selectionStart();
2105 if (anchor < pos || (anchor == pos && cursor < pos)) {
2106 const QString text = this->text();
2107 QTextBoundaryFinder finder(QTextBoundaryFinder::Word, text);
2108 finder.setPosition(anchor);
2110 const QTextBoundaryFinder::BoundaryReasons reasons = finder.boundaryReasons();
2111 if (anchor < text.length() && (!(reasons & QTextBoundaryFinder::StartWord)
2112 || ((reasons & QTextBoundaryFinder::EndWord) && anchor > cursor))) {
2113 finder.toPreviousBoundary();
2115 anchor = finder.position() != -1 ? finder.position() : 0;
2117 finder.setPosition(pos);
2118 if (pos > 0 && !finder.boundaryReasons())
2119 finder.toNextBoundary();
2120 const int cursor = finder.position() != -1 ? finder.position() : text.length();
2122 d->setSelection(anchor, cursor - anchor);
2123 } else if (anchor > pos || (anchor == pos && cursor > pos)) {
2124 const QString text = this->text();
2125 QTextBoundaryFinder finder(QTextBoundaryFinder::Word, text);
2126 finder.setPosition(anchor);
2128 const QTextBoundaryFinder::BoundaryReasons reasons = finder.boundaryReasons();
2129 if (anchor > 0 && (!(reasons & QTextBoundaryFinder::EndWord)
2130 || ((reasons & QTextBoundaryFinder::StartWord) && anchor < cursor))) {
2131 finder.toNextBoundary();
2134 anchor = finder.position() != -1 ? finder.position() : text.length();
2136 finder.setPosition(pos);
2137 if (pos < text.length() && !finder.boundaryReasons())
2138 finder.toPreviousBoundary();
2139 const int cursor = finder.position() != -1 ? finder.position() : 0;
2141 d->setSelection(anchor, cursor - anchor);
2147 \qmlmethod void QtQuick2::TextInput::openSoftwareInputPanel()
2149 Opens software input panels like virtual keyboards for typing, useful for
2150 customizing when you want the input keyboard to be shown and hidden in
2153 By default the opening of input panels follows the platform style. Input panels are
2154 always closed if no editor has active focus.
2156 You can disable the automatic behavior by setting the property \c activeFocusOnPress to false
2157 and use functions openSoftwareInputPanel() and closeSoftwareInputPanel() to implement
2158 the behavior you want.
2160 Only relevant on platforms, which provide virtual keyboards.
2166 text: "Hello world!"
2167 activeFocusOnPress: false
2169 anchors.fill: parent
2171 if (!textInput.activeFocus) {
2172 textInput.forceActiveFocus()
2173 textInput.openSoftwareInputPanel();
2175 textInput.focus = false;
2178 onPressAndHold: textInput.closeSoftwareInputPanel();
2183 void QQuickTextInput::openSoftwareInputPanel()
2186 qGuiApp->inputPanel()->show();
2190 \qmlmethod void QtQuick2::TextInput::closeSoftwareInputPanel()
2192 Closes a software input panel like a virtual keyboard shown on the screen, useful
2193 for customizing when you want the input keyboard to be shown and hidden in
2196 By default the opening of input panels follows the platform style. Input panels are
2197 always closed if no editor has active focus.
2199 You can disable the automatic behavior by setting the property \c activeFocusOnPress to false
2200 and use functions openSoftwareInputPanel() and closeSoftwareInputPanel() to implement
2201 the behavior you want.
2203 Only relevant on platforms, which provide virtual keyboards.
2209 text: "Hello world!"
2210 activeFocusOnPress: false
2212 anchors.fill: parent
2214 if (!textInput.activeFocus) {
2215 textInput.forceActiveFocus();
2216 textInput.openSoftwareInputPanel();
2218 textInput.focus = false;
2221 onPressAndHold: textInput.closeSoftwareInputPanel();
2226 void QQuickTextInput::closeSoftwareInputPanel()
2229 qGuiApp->inputPanel()->hide();
2232 void QQuickTextInput::focusInEvent(QFocusEvent *event)
2234 Q_D(const QQuickTextInput);
2235 if (d->focusOnPress && !d->m_readOnly)
2236 openSoftwareInputPanel();
2237 QQuickImplicitSizeItem::focusInEvent(event);
2240 void QQuickTextInput::itemChange(ItemChange change, const ItemChangeData &value)
2242 Q_D(QQuickTextInput);
2243 if (change == ItemActiveFocusHasChanged) {
2244 bool hasFocus = value.boolValue;
2245 d->focused = hasFocus;
2246 setCursorVisible(hasFocus); // ### refactor: && d->canvas && d->canvas->hasFocus()
2247 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
2248 if (!hasFocus && (d->m_passwordEchoEditing || d->m_passwordEchoTimer.isActive())) {
2250 if (!hasFocus && d->m_passwordEchoEditing) {
2252 d->updatePasswordEchoEditing(false);//QQuickTextInputPrivate sets it on key events, but doesn't deal with focus events
2260 QQuickItem::itemChange(change, value);
2264 \qmlproperty bool QtQuick2::TextInput::inputMethodComposing
2267 This property holds whether the TextInput has partial text input from an
2270 While it is composing an input method may rely on mouse or key events from
2271 the TextInput to edit or commit the partial text. This property can be
2272 used to determine when to disable events handlers that may interfere with
2273 the correct operation of an input method.
2275 bool QQuickTextInput::isInputMethodComposing() const
2277 Q_D(const QQuickTextInput);
2278 return d->preeditAreaText().length() > 0;
2281 void QQuickTextInputPrivate::init()
2283 Q_Q(QQuickTextInput);
2284 q->setSmooth(smooth);
2285 q->setAcceptedMouseButtons(Qt::LeftButton);
2286 q->setFlag(QQuickItem::ItemAcceptsInputMethod);
2287 q->setFlag(QQuickItem::ItemHasContents);
2288 #ifndef QT_NO_CLIPBOARD
2289 q->connect(QGuiApplication::clipboard(), SIGNAL(dataChanged()),
2290 q, SLOT(q_canPasteChanged()));
2291 #endif // QT_NO_CLIPBOARD
2293 oldValidity = hasAcceptableInput(m_text);
2294 lastSelectionStart = 0;
2295 lastSelectionEnd = 0;
2296 selectedTextColor = m_palette.color(QPalette::HighlightedText);
2297 selectionColor = m_palette.color(QPalette::Highlight);
2298 determineHorizontalAlignment();
2300 if (!qmlDisableDistanceField()) {
2301 QTextOption option = m_textLayout.textOption();
2302 option.setUseDesignMetrics(true);
2303 m_textLayout.setTextOption(option);
2307 void QQuickTextInput::updateCursorRectangle()
2309 Q_D(QQuickTextInput);
2310 if (!isComponentComplete())
2313 d->updateHorizontalScroll();
2314 d->updateVerticalScroll();
2316 emit cursorRectangleChanged();
2317 if (d->cursorItem) {
2318 QRectF r = cursorRectangle();
2319 d->cursorItem->setPos(r.topLeft());
2320 d->cursorItem->setHeight(r.height());
2324 void QQuickTextInput::selectionChanged()
2326 Q_D(QQuickTextInput);
2327 d->textLayoutDirty = true; //TODO: Only update rect in selection
2329 emit selectedTextChanged();
2331 if (d->lastSelectionStart != d->selectionStart()) {
2332 d->lastSelectionStart = d->selectionStart();
2333 if (d->lastSelectionStart == -1)
2334 d->lastSelectionStart = d->m_cursor;
2335 emit selectionStartChanged();
2337 if (d->lastSelectionEnd != d->selectionEnd()) {
2338 d->lastSelectionEnd = d->selectionEnd();
2339 if (d->lastSelectionEnd == -1)
2340 d->lastSelectionEnd = d->m_cursor;
2341 emit selectionEndChanged();
2345 void QQuickTextInputPrivate::showCursor()
2347 if (textNode != 0 && textNode->cursorNode() != 0)
2348 textNode->cursorNode()->setColor(color);
2351 void QQuickTextInputPrivate::hideCursor()
2353 if (textNode != 0 && textNode->cursorNode() != 0)
2354 textNode->cursorNode()->setColor(QColor(0, 0, 0, 0));
2357 QRectF QQuickTextInput::boundingRect() const
2359 Q_D(const QQuickTextInput);
2361 int cursorWidth = d->cursorItem ? d->cursorItem->width() : d->m_cursorWidth;
2363 // Could include font max left/right bearings to either side of rectangle.
2364 QRectF r = QQuickImplicitSizeItem::boundingRect();
2365 r.setRight(r.right() + cursorWidth);
2369 void QQuickTextInput::q_canPasteChanged()
2371 Q_D(QQuickTextInput);
2372 bool old = d->canPaste;
2373 #ifndef QT_NO_CLIPBOARD
2374 if (const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData())
2375 d->canPaste = !d->m_readOnly && mimeData->hasText();
2377 d->canPaste = false;
2380 bool changed = d->canPaste != old || !d->canPasteValid;
2381 d->canPasteValid = true;
2383 emit canPasteChanged();
2387 // ### these should come from QStyleHints
2388 const int textCursorWidth = 1;
2389 const bool fullWidthSelection = true;
2394 Updates the display text based of the current edit text
2395 If the text has changed will emit displayTextChanged()
2397 void QQuickTextInputPrivate::updateDisplayText(bool forceUpdate)
2399 QString orig = m_textLayout.text();
2401 if (m_echoMode == QQuickTextInput::NoEcho)
2402 str = QString::fromLatin1("");
2406 if (m_echoMode == QQuickTextInput::Password) {
2407 str.fill(m_passwordCharacter);
2408 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
2409 if (m_passwordEchoTimer.isActive() && m_cursor > 0 && m_cursor <= m_text.length()) {
2410 int cursor = m_cursor - 1;
2411 QChar uc = m_text.at(cursor);
2413 if (cursor > 0 && uc.unicode() >= 0xdc00 && uc.unicode() < 0xe000) {
2414 // second half of a surrogate, check if we have the first half as well,
2415 // if yes restore both at once
2416 uc = m_text.at(cursor - 1);
2417 if (uc.unicode() >= 0xd800 && uc.unicode() < 0xdc00)
2418 str[cursor - 1] = uc;
2422 } else if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit && !m_passwordEchoEditing) {
2423 str.fill(m_passwordCharacter);
2426 // replace certain non-printable characters with spaces (to avoid
2427 // drawing boxes when using fonts that don't have glyphs for such
2429 QChar* uc = str.data();
2430 for (int i = 0; i < (int)str.length(); ++i) {
2431 if ((uc[i] < 0x20 && uc[i] != 0x09)
2432 || uc[i] == QChar::LineSeparator
2433 || uc[i] == QChar::ParagraphSeparator
2434 || uc[i] == QChar::ObjectReplacementCharacter)
2435 uc[i] = QChar(0x0020);
2438 if (str != orig || forceUpdate) {
2439 m_textLayout.setText(str);
2440 updateLayout(); // polish?
2441 emit q_func()->displayTextChanged();
2445 void QQuickTextInputPrivate::updateLayout()
2447 Q_Q(QQuickTextInput);
2449 if (!q->isComponentComplete())
2452 QTextOption option = m_textLayout.textOption();
2453 option.setTextDirection(m_layoutDirection);
2454 option.setFlags(QTextOption::IncludeTrailingSpaces);
2455 option.setWrapMode(QTextOption::WrapMode(wrapMode));
2456 option.setAlignment(Qt::Alignment(q->effectiveHAlign()));
2457 m_textLayout.setTextOption(option);
2458 m_textLayout.setFont(font);
2460 boundingRect = QRectF();
2461 m_textLayout.beginLayout();
2462 QTextLine line = m_textLayout.createLine();
2463 qreal lineWidth = q->widthValid() ? q->width() : INT_MAX;
2465 QTextLine firstLine = line;
2467 line.setLineWidth(lineWidth);
2468 line.setPosition(QPointF(line.position().x(), height));
2469 boundingRect = boundingRect.united(line.naturalTextRect());
2471 height += line.height();
2472 line = m_textLayout.createLine();
2473 } while (line.isValid());
2474 m_textLayout.endLayout();
2476 option.setWrapMode(QTextOption::NoWrap);
2477 m_textLayout.setTextOption(option);
2479 m_ascent = qRound(firstLine.ascent());
2480 textLayoutDirty = true;
2483 q->setImplicitSize(qCeil(boundingRect.width()), qCeil(boundingRect.height()));
2487 #ifndef QT_NO_CLIPBOARD
2491 Copies the currently selected text into the clipboard using the given
2494 \note If the echo mode is set to a mode other than Normal then copy
2495 will not work. This is to prevent using copy as a method of bypassing
2496 password features of the line control.
2498 void QQuickTextInputPrivate::copy(QClipboard::Mode mode) const
2500 QString t = selectedText();
2501 if (!t.isEmpty() && m_echoMode == QQuickTextInput::Normal) {
2502 QGuiApplication::clipboard()->setText(t, mode);
2509 Inserts the text stored in the application clipboard into the line
2514 void QQuickTextInputPrivate::paste(QClipboard::Mode clipboardMode)
2516 QString clip = QGuiApplication::clipboard()->text(clipboardMode);
2517 if (!clip.isEmpty() || hasSelectedText()) {
2518 separate(); //make it a separate undo/redo command
2524 #endif // !QT_NO_CLIPBOARD
2529 Exits preedit mode and commits parts marked as tentative commit
2531 void QQuickTextInputPrivate::commitPreedit()
2536 qApp->inputPanel()->reset();
2538 if (!m_tentativeCommit.isEmpty()) {
2539 internalInsert(m_tentativeCommit);
2540 m_tentativeCommit.clear();
2541 finishChange(-1, true/*not used, not documented*/, false);
2544 m_preeditCursor = 0;
2545 m_textLayout.setPreeditArea(-1, QString());
2546 m_textLayout.clearAdditionalFormats();
2553 Handles the behavior for the backspace key or function.
2554 Removes the current selection if there is a selection, otherwise
2555 removes the character prior to the cursor position.
2559 void QQuickTextInputPrivate::backspace()
2561 int priorState = m_undoState;
2562 if (hasSelectedText()) {
2563 removeSelectedText();
2564 } else if (m_cursor) {
2567 m_cursor = prevMaskBlank(m_cursor);
2568 QChar uc = m_text.at(m_cursor);
2569 if (m_cursor > 0 && uc.unicode() >= 0xdc00 && uc.unicode() < 0xe000) {
2570 // second half of a surrogate, check if we have the first half as well,
2571 // if yes delete both at once
2572 uc = m_text.at(m_cursor - 1);
2573 if (uc.unicode() >= 0xd800 && uc.unicode() < 0xdc00) {
2574 internalDelete(true);
2578 internalDelete(true);
2580 finishChange(priorState);
2586 Handles the behavior for the delete key or function.
2587 Removes the current selection if there is a selection, otherwise
2588 removes the character after the cursor position.
2592 void QQuickTextInputPrivate::del()
2594 int priorState = m_undoState;
2595 if (hasSelectedText()) {
2596 removeSelectedText();
2598 int n = m_textLayout.nextCursorPosition(m_cursor) - m_cursor;
2602 finishChange(priorState);
2608 Inserts the given \a newText at the current cursor position.
2609 If there is any selected text it is removed prior to insertion of
2612 void QQuickTextInputPrivate::insert(const QString &newText)
2614 int priorState = m_undoState;
2615 removeSelectedText();
2616 internalInsert(newText);
2617 finishChange(priorState);
2623 Clears the line control text.
2625 void QQuickTextInputPrivate::clear()
2627 int priorState = m_undoState;
2629 m_selend = m_text.length();
2630 removeSelectedText();
2632 finishChange(priorState, /*update*/false, /*edited*/false);
2638 Sets \a length characters from the given \a start position as selected.
2639 The given \a start position must be within the current text for
2640 the line control. If \a length characters cannot be selected, then
2641 the selection will extend to the end of the current text.
2643 void QQuickTextInputPrivate::setSelection(int start, int length)
2645 Q_Q(QQuickTextInput);
2648 if (start < 0 || start > (int)m_text.length()){
2649 qWarning("QQuickTextInputPrivate::setSelection: Invalid start position");
2654 if (start == m_selstart && start + length == m_selend && m_cursor == m_selend)
2657 m_selend = qMin(start + length, (int)m_text.length());
2658 m_cursor = m_selend;
2659 } else if (length < 0){
2660 if (start == m_selend && start + length == m_selstart && m_cursor == m_selstart)
2662 m_selstart = qMax(start + length, 0);
2664 m_cursor = m_selstart;
2665 } else if (m_selstart != m_selend) {
2671 emitCursorPositionChanged();
2674 emit q->selectionChanged();
2675 emitCursorPositionChanged();
2676 qApp->inputPanel()->update(Qt::ImCursorRectangle | Qt::ImAnchorPosition
2677 | Qt::ImCursorPosition | Qt::ImCurrentSelection);
2683 Initializes the line control with a starting text value of \a txt.
2685 void QQuickTextInputPrivate::init(const QString &txt)
2689 updateDisplayText();
2690 m_cursor = m_text.length();
2696 Sets the password echo editing to \a editing. If password echo editing
2697 is true, then the text of the password is displayed even if the echo
2698 mode is set to QLineEdit::PasswordEchoOnEdit. Password echoing editing
2699 does not affect other echo modes.
2701 void QQuickTextInputPrivate::updatePasswordEchoEditing(bool editing)
2703 cancelPasswordEchoTimer();
2704 m_passwordEchoEditing = editing;
2705 updateDisplayText();
2711 Fixes the current text so that it is valid given any set validators.
2713 Returns true if the text was changed. Otherwise returns false.
2715 bool QQuickTextInputPrivate::fixup() // this function assumes that validate currently returns != Acceptable
2717 #ifndef QT_NO_VALIDATOR
2719 QString textCopy = m_text;
2720 int cursorCopy = m_cursor;
2721 m_validator->fixup(textCopy);
2722 if (m_validator->validate(textCopy, cursorCopy) == QValidator::Acceptable) {
2723 if (textCopy != m_text || cursorCopy != m_cursor)
2724 internalSetText(textCopy, cursorCopy);
2735 Moves the cursor to the given position \a pos. If \a mark is true will
2736 adjust the currently selected text.
2738 void QQuickTextInputPrivate::moveCursor(int pos, bool mark)
2740 Q_Q(QQuickTextInput);
2743 if (pos != m_cursor) {
2746 pos = pos > m_cursor ? nextMaskBlank(pos) : prevMaskBlank(pos);
2750 if (m_selend > m_selstart && m_cursor == m_selstart)
2752 else if (m_selend > m_selstart && m_cursor == m_selend)
2753 anchor = m_selstart;
2756 m_selstart = qMin(anchor, pos);
2757 m_selend = qMax(anchor, pos);
2762 if (mark || m_selDirty) {
2764 emit q->selectionChanged();
2766 emitCursorPositionChanged();
2767 q->updateMicroFocus();
2773 Applies the given input method event \a event to the text of the line
2776 void QQuickTextInputPrivate::processInputMethodEvent(QInputMethodEvent *event)
2778 Q_Q(QQuickTextInput);
2780 int priorState = -1;
2781 bool isGettingInput = !event->commitString().isEmpty()
2782 || event->preeditString() != preeditAreaText()
2783 || event->replacementLength() > 0;
2784 bool cursorPositionChanged = false;
2785 bool selectionChange = false;
2786 m_preeditDirty = event->preeditString() != preeditAreaText();
2788 if (isGettingInput) {
2789 // If any text is being input, remove selected text.
2790 priorState = m_undoState;
2791 if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit && !m_passwordEchoEditing) {
2792 updatePasswordEchoEditing(true);
2794 m_selend = m_text.length();
2796 removeSelectedText();
2799 int c = m_cursor; // cursor position after insertion of commit string
2800 if (event->replacementStart() <= 0)
2801 c += event->commitString().length() - qMin(-event->replacementStart(), event->replacementLength());
2803 m_cursor += event->replacementStart();
2807 // insert commit string
2808 if (event->replacementLength()) {
2809 m_selstart = m_cursor;
2810 m_selend = m_selstart + event->replacementLength();
2811 m_selend = qMin(m_selend, m_text.length());
2812 removeSelectedText();
2814 if (!event->commitString().isEmpty()) {
2815 internalInsert(event->commitString());
2816 cursorPositionChanged = true;
2819 m_cursor = qBound(0, c, m_text.length());
2821 for (int i = 0; i < event->attributes().size(); ++i) {
2822 const QInputMethodEvent::Attribute &a = event->attributes().at(i);
2823 if (a.type == QInputMethodEvent::Selection) {
2824 m_cursor = qBound(0, a.start + a.length, m_text.length());
2826 m_selstart = qMax(0, qMin(a.start, m_text.length()));
2827 m_selend = m_cursor;
2828 if (m_selend < m_selstart) {
2829 qSwap(m_selstart, m_selend);
2831 selectionChange = true;
2833 m_selstart = m_selend = 0;
2835 cursorPositionChanged = true;
2839 m_textLayout.setPreeditArea(m_cursor, event->preeditString());
2841 const int oldPreeditCursor = m_preeditCursor;
2842 m_preeditCursor = event->preeditString().length();
2843 m_hideCursor = false;
2844 QList<QTextLayout::FormatRange> formats;
2845 for (int i = 0; i < event->attributes().size(); ++i) {
2846 const QInputMethodEvent::Attribute &a = event->attributes().at(i);
2847 if (a.type == QInputMethodEvent::Cursor) {
2848 m_preeditCursor = a.start;
2849 m_hideCursor = !a.length;
2850 } else if (a.type == QInputMethodEvent::TextFormat) {
2851 QTextCharFormat f = qvariant_cast<QTextFormat>(a.value).toCharFormat();
2853 QTextLayout::FormatRange o;
2854 o.start = a.start + m_cursor;
2855 o.length = a.length;
2861 m_textLayout.setAdditionalFormats(formats);
2863 updateDisplayText(/*force*/ true);
2864 if (cursorPositionChanged) {
2865 emitCursorPositionChanged();
2866 } else if (m_preeditCursor != oldPreeditCursor) {
2867 q->updateCursorRectangle();
2868 qApp->inputPanel()->update(Qt::ImCursorRectangle);
2871 bool tentativeCommitChanged = m_tentativeCommit != event->tentativeCommitString();
2873 if (tentativeCommitChanged) {
2875 m_tentativeCommit = event->tentativeCommitString();
2878 if (isGettingInput || tentativeCommitChanged)
2879 finishChange(priorState);
2881 if (selectionChange) {
2882 emit q->selectionChanged();
2883 qApp->inputPanel()->update(Qt::ImCursorRectangle | Qt::ImAnchorPosition
2884 | Qt::ImCursorPosition | Qt::ImCurrentSelection);
2891 Sets the selection to cover the word at the given cursor position.
2892 The word boundaries are defined by the behavior of QTextLayout::SkipWords
2895 void QQuickTextInputPrivate::selectWordAtPos(int cursor)
2897 int next = cursor + 1;
2900 int c = m_textLayout.previousCursorPosition(next, QTextLayout::SkipWords);
2901 moveCursor(c, false);
2902 // ## text layout should support end of words.
2903 int end = m_textLayout.nextCursorPosition(c, QTextLayout::SkipWords);
2904 while (end > cursor && m_text[end-1].isSpace())
2906 moveCursor(end, true);
2912 Completes a change to the line control text. If the change is not valid
2913 will undo the line control state back to the given \a validateFromState.
2915 If \a edited is true and the change is valid, will emit textEdited() in
2916 addition to textChanged(). Otherwise only emits textChanged() on a valid
2919 The \a update value is currently unused.
2921 bool QQuickTextInputPrivate::finishChange(int validateFromState, bool update, bool /*edited*/)
2923 Q_Q(QQuickTextInput);
2926 bool notifyInputPanel = m_textDirty || m_selDirty;
2930 bool wasValidInput = m_validInput;
2931 m_validInput = true;
2932 #ifndef QT_NO_VALIDATOR
2934 QString textCopy = m_text;
2935 int cursorCopy = m_cursor;
2936 m_validInput = (m_validator->validate(textCopy, cursorCopy) != QValidator::Invalid);
2938 if (m_text != textCopy) {
2939 internalSetText(textCopy, cursorCopy);
2942 m_cursor = cursorCopy;
2944 if (!m_tentativeCommit.isEmpty()) {
2945 textCopy.insert(m_cursor, m_tentativeCommit);
2946 bool validInput = m_validator->validate(textCopy, cursorCopy) != QValidator::Invalid;
2948 m_tentativeCommit.clear();
2951 m_tentativeCommit.clear();
2955 if (validateFromState >= 0 && wasValidInput && !m_validInput) {
2956 if (m_transactions.count())
2958 internalUndo(validateFromState);
2959 m_history.resize(m_undoState);
2960 if (m_modifiedState > m_undoState)
2961 m_modifiedState = -1;
2962 m_validInput = true;
2963 m_textDirty = false;
2965 updateDisplayText();
2968 m_textDirty = false;
2969 m_preeditDirty = false;
2970 determineHorizontalAlignment();
2971 emit q->textChanged();
2974 if (m_validInput != wasValidInput)
2975 emit q->acceptableInputChanged();
2977 if (m_preeditDirty) {
2978 m_preeditDirty = false;
2979 determineHorizontalAlignment();
2984 emit q->selectionChanged();
2987 notifyInputPanel |= (m_cursor == m_lastCursorPos);
2988 if (notifyInputPanel)
2989 q->updateMicroFocus();
2990 emitCursorPositionChanged();
2998 An internal function for setting the text of the line control.
3000 void QQuickTextInputPrivate::internalSetText(const QString &txt, int pos, bool edited)
3002 Q_Q(QQuickTextInput);
3004 QString oldText = m_text;
3006 m_text = maskString(0, txt, true);
3007 m_text += clearString(m_text.length(), m_maxLength - m_text.length());
3009 m_text = txt.isEmpty() ? txt : txt.left(m_maxLength);
3012 m_modifiedState = m_undoState = 0;
3013 m_cursor = (pos < 0 || pos > m_text.length()) ? m_text.length() : pos;
3014 m_textDirty = (oldText != m_text);
3016 bool changed = finishChange(-1, true, edited);
3017 #ifdef QT_NO_ACCESSIBILITY
3021 QAccessible::updateAccessibility(q, 0, QAccessible::TextUpdated);
3029 Adds the given \a command to the undo history
3030 of the line control. Does not apply the command.
3032 void QQuickTextInputPrivate::addCommand(const Command &cmd)
3034 if (m_separator && m_undoState && m_history[m_undoState - 1].type != Separator) {
3035 m_history.resize(m_undoState + 2);
3036 m_history[m_undoState++] = Command(Separator, m_cursor, 0, m_selstart, m_selend);
3038 m_history.resize(m_undoState + 1);
3040 m_separator = false;
3041 m_history[m_undoState++] = cmd;
3047 Inserts the given string \a s into the line
3050 Also adds the appropriate commands into the undo history.
3051 This function does not call finishChange(), and may leave the text
3052 in an invalid state.
3054 void QQuickTextInputPrivate::internalInsert(const QString &s)
3056 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
3057 Q_Q(QQuickTextInput);
3058 if (m_echoMode == QQuickTextInput::Password)
3059 m_passwordEchoTimer.start(qt_passwordEchoDelay, q);
3061 if (hasSelectedText())
3062 addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
3064 QString ms = maskString(m_cursor, s);
3065 for (int i = 0; i < (int) ms.length(); ++i) {
3066 addCommand (Command(DeleteSelection, m_cursor + i, m_text.at(m_cursor + i), -1, -1));
3067 addCommand(Command(Insert, m_cursor + i, ms.at(i), -1, -1));
3069 m_text.replace(m_cursor, ms.length(), ms);
3070 m_cursor += ms.length();
3071 m_cursor = nextMaskBlank(m_cursor);
3074 int remaining = m_maxLength - m_text.length();
3075 if (remaining != 0) {
3076 m_text.insert(m_cursor, s.left(remaining));
3077 for (int i = 0; i < (int) s.left(remaining).length(); ++i)
3078 addCommand(Command(Insert, m_cursor++, s.at(i), -1, -1));
3087 deletes a single character from the current text. If \a wasBackspace,
3088 the character prior to the cursor is removed. Otherwise the character
3089 after the cursor is removed.
3091 Also adds the appropriate commands into the undo history.
3092 This function does not call finishChange(), and may leave the text
3093 in an invalid state.
3095 void QQuickTextInputPrivate::internalDelete(bool wasBackspace)
3097 if (m_cursor < (int) m_text.length()) {
3098 cancelPasswordEchoTimer();
3099 if (hasSelectedText())
3100 addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
3101 addCommand(Command((CommandType)((m_maskData ? 2 : 0) + (wasBackspace ? Remove : Delete)),
3102 m_cursor, m_text.at(m_cursor), -1, -1));
3104 m_text.replace(m_cursor, 1, clearString(m_cursor, 1));
3105 addCommand(Command(Insert, m_cursor, m_text.at(m_cursor), -1, -1));
3107 m_text.remove(m_cursor, 1);
3116 removes the currently selected text from the line control.
3118 Also adds the appropriate commands into the undo history.
3119 This function does not call finishChange(), and may leave the text
3120 in an invalid state.
3122 void QQuickTextInputPrivate::removeSelectedText()
3124 if (m_selstart < m_selend && m_selend <= (int) m_text.length()) {
3125 cancelPasswordEchoTimer();
3128 addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
3129 if (m_selstart <= m_cursor && m_cursor < m_selend) {
3130 // cursor is within the selection. Split up the commands
3131 // to be able to restore the correct cursor position
3132 for (i = m_cursor; i >= m_selstart; --i)
3133 addCommand (Command(DeleteSelection, i, m_text.at(i), -1, 1));
3134 for (i = m_selend - 1; i > m_cursor; --i)
3135 addCommand (Command(DeleteSelection, i - m_cursor + m_selstart - 1, m_text.at(i), -1, -1));
3137 for (i = m_selend-1; i >= m_selstart; --i)
3138 addCommand (Command(RemoveSelection, i, m_text.at(i), -1, -1));
3141 m_text.replace(m_selstart, m_selend - m_selstart, clearString(m_selstart, m_selend - m_selstart));
3142 for (int i = 0; i < m_selend - m_selstart; ++i)
3143 addCommand(Command(Insert, m_selstart + i, m_text.at(m_selstart + i), -1, -1));
3145 m_text.remove(m_selstart, m_selend - m_selstart);
3147 if (m_cursor > m_selstart)
3148 m_cursor -= qMin(m_cursor, m_selend) - m_selstart;
3157 Parses the input mask specified by \a maskFields to generate
3158 the mask data used to handle input masks.
3160 void QQuickTextInputPrivate::parseInputMask(const QString &maskFields)
3162 int delimiter = maskFields.indexOf(QLatin1Char(';'));
3163 if (maskFields.isEmpty() || delimiter == 0) {
3165 delete [] m_maskData;
3167 m_maxLength = 32767;
3168 internalSetText(QString());
3173 if (delimiter == -1) {
3174 m_blank = QLatin1Char(' ');
3175 m_inputMask = maskFields;
3177 m_inputMask = maskFields.left(delimiter);
3178 m_blank = (delimiter + 1 < maskFields.length()) ? maskFields[delimiter + 1] : QLatin1Char(' ');
3181 // calculate m_maxLength / m_maskData length
3184 for (int i=0; i<m_inputMask.length(); i++) {
3185 c = m_inputMask.at(i);
3186 if (i > 0 && m_inputMask.at(i-1) == QLatin1Char('\\')) {
3190 if (c != QLatin1Char('\\') && c != QLatin1Char('!') &&
3191 c != QLatin1Char('<') && c != QLatin1Char('>') &&
3192 c != QLatin1Char('{') && c != QLatin1Char('}') &&
3193 c != QLatin1Char('[') && c != QLatin1Char(']'))
3197 delete [] m_maskData;
3198 m_maskData = new MaskInputData[m_maxLength];
3200 MaskInputData::Casemode m = MaskInputData::NoCaseMode;
3203 bool escape = false;
3205 for (int i = 0; i < m_inputMask.length(); i++) {
3206 c = m_inputMask.at(i);
3209 m_maskData[index].maskChar = c;
3210 m_maskData[index].separator = s;
3211 m_maskData[index].caseMode = m;
3214 } else if (c == QLatin1Char('<')) {
3215 m = MaskInputData::Lower;
3216 } else if (c == QLatin1Char('>')) {
3217 m = MaskInputData::Upper;
3218 } else if (c == QLatin1Char('!')) {
3219 m = MaskInputData::NoCaseMode;
3220 } else if (c != QLatin1Char('{') && c != QLatin1Char('}') && c != QLatin1Char('[') && c != QLatin1Char(']')) {
3221 switch (c.unicode()) {
3247 m_maskData[index].maskChar = c;
3248 m_maskData[index].separator = s;
3249 m_maskData[index].caseMode = m;
3254 internalSetText(m_text);
3261 checks if the key is valid compared to the inputMask
3263 bool QQuickTextInputPrivate::isValidInput(QChar key, QChar mask) const
3265 switch (mask.unicode()) {
3271 if (key.isLetter() || key == m_blank)
3275 if (key.isLetterOrNumber())
3279 if (key.isLetterOrNumber() || key == m_blank)
3287 if (key.isPrint() || key == m_blank)
3295 if (key.isNumber() || key == m_blank)
3299 if (key.isNumber() && key.digitValue() > 0)
3303 if ((key.isNumber() && key.digitValue() > 0) || key == m_blank)
3307 if (key.isNumber() || key == QLatin1Char('+') || key == QLatin1Char('-') || key == m_blank)
3311 if (key == QLatin1Char('0') || key == QLatin1Char('1'))
3315 if (key == QLatin1Char('0') || key == QLatin1Char('1') || key == m_blank)
3319 if (key.isNumber() || (key >= QLatin1Char('a') && key <= QLatin1Char('f')) || (key >= QLatin1Char('A') && key <= QLatin1Char('F')))
3323 if (key.isNumber() || (key >= QLatin1Char('a') && key <= QLatin1Char('f')) || (key >= QLatin1Char('A') && key <= QLatin1Char('F')) || key == m_blank)
3335 Returns true if the given text \a str is valid for any
3336 validator or input mask set for the line control.
3338 Otherwise returns false
3340 bool QQuickTextInputPrivate::hasAcceptableInput(const QString &str) const
3342 #ifndef QT_NO_VALIDATOR
3343 QString textCopy = str;
3344 int cursorCopy = m_cursor;
3345 if (m_validator && m_validator->validate(textCopy, cursorCopy)
3346 != QValidator::Acceptable)
3353 if (str.length() != m_maxLength)
3356 for (int i=0; i < m_maxLength; ++i) {
3357 if (m_maskData[i].separator) {
3358 if (str.at(i) != m_maskData[i].maskChar)
3361 if (!isValidInput(str.at(i), m_maskData[i].maskChar))
3371 Applies the inputMask on \a str starting from position \a pos in the mask. \a clear
3372 specifies from where characters should be gotten when a separator is met in \a str - true means
3373 that blanks will be used, false that previous input is used.
3374 Calling this when no inputMask is set is undefined.
3376 QString QQuickTextInputPrivate::maskString(uint pos, const QString &str, bool clear) const
3378 if (pos >= (uint)m_maxLength)
3379 return QString::fromLatin1("");
3382 fill = clear ? clearString(0, m_maxLength) : m_text;
3385 QString s = QString::fromLatin1("");
3387 while (i < m_maxLength) {
3388 if (strIndex < str.length()) {
3389 if (m_maskData[i].separator) {
3390 s += m_maskData[i].maskChar;
3391 if (str[(int)strIndex] == m_maskData[i].maskChar)
3395 if (isValidInput(str[(int)strIndex], m_maskData[i].maskChar)) {
3396 switch (m_maskData[i].caseMode) {
3397 case MaskInputData::Upper:
3398 s += str[(int)strIndex].toUpper();
3400 case MaskInputData::Lower:
3401 s += str[(int)strIndex].toLower();
3404 s += str[(int)strIndex];
3408 // search for separator first
3409 int n = findInMask(i, true, true, str[(int)strIndex]);
3411 if (str.length() != 1 || i == 0 || (i > 0 && (!m_maskData[i-1].separator || m_maskData[i-1].maskChar != str[(int)strIndex]))) {
3412 s += fill.mid(i, n-i+1);
3413 i = n + 1; // update i to find + 1
3416 // search for valid m_blank if not
3417 n = findInMask(i, true, false, str[(int)strIndex]);
3419 s += fill.mid(i, n-i);
3420 switch (m_maskData[n].caseMode) {
3421 case MaskInputData::Upper:
3422 s += str[(int)strIndex].toUpper();
3424 case MaskInputData::Lower:
3425 s += str[(int)strIndex].toLower();
3428 s += str[(int)strIndex];
3430 i = n + 1; // updates i to find + 1
3448 Returns a "cleared" string with only separators and blank chars.
3449 Calling this when no inputMask is set is undefined.
3451 QString QQuickTextInputPrivate::clearString(uint pos, uint len) const
3453 if (pos >= (uint)m_maxLength)
3457 int end = qMin((uint)m_maxLength, pos + len);
3458 for (int i = pos; i < end; ++i)
3459 if (m_maskData[i].separator)
3460 s += m_maskData[i].maskChar;
3470 Strips blank parts of the input in a QQuickTextInputPrivate when an inputMask is set,
3471 separators are still included. Typically "127.0__.0__.1__" becomes "127.0.0.1".
3473 QString QQuickTextInputPrivate::stripString(const QString &str) const
3479 int end = qMin(m_maxLength, (int)str.length());
3480 for (int i = 0; i < end; ++i) {
3481 if (m_maskData[i].separator)
3482 s += m_maskData[i].maskChar;
3483 else if (str[i] != m_blank)
3492 searches forward/backward in m_maskData for either a separator or a m_blank
3494 int QQuickTextInputPrivate::findInMask(int pos, bool forward, bool findSeparator, QChar searchChar) const
3496 if (pos >= m_maxLength || pos < 0)
3499 int end = forward ? m_maxLength : -1;
3500 int step = forward ? 1 : -1;
3504 if (findSeparator) {
3505 if (m_maskData[i].separator && m_maskData[i].maskChar == searchChar)
3508 if (!m_maskData[i].separator) {
3509 if (searchChar.isNull())
3511 else if (isValidInput(searchChar, m_maskData[i].maskChar))
3520 void QQuickTextInputPrivate::internalUndo(int until)
3522 if (!isUndoAvailable())
3524 cancelPasswordEchoTimer();
3526 while (m_undoState && m_undoState > until) {
3527 Command& cmd = m_history[--m_undoState];
3530 m_text.remove(cmd.pos, 1);
3534 m_selstart = cmd.selStart;
3535 m_selend = cmd.selEnd;
3539 case RemoveSelection:
3540 m_text.insert(cmd.pos, cmd.uc);
3541 m_cursor = cmd.pos + 1;
3544 case DeleteSelection:
3545 m_text.insert(cmd.pos, cmd.uc);
3551 if (until < 0 && m_undoState) {
3552 Command& next = m_history[m_undoState-1];
3553 if (next.type != cmd.type && next.type < RemoveSelection
3554 && (cmd.type < RemoveSelection || next.type == Separator))
3559 emitCursorPositionChanged();
3562 void QQuickTextInputPrivate::internalRedo()
3564 if (!isRedoAvailable())
3567 while (m_undoState < (int)m_history.size()) {
3568 Command& cmd = m_history[m_undoState++];
3571 m_text.insert(cmd.pos, cmd.uc);
3572 m_cursor = cmd.pos + 1;
3575 m_selstart = cmd.selStart;
3576 m_selend = cmd.selEnd;
3581 case RemoveSelection:
3582 case DeleteSelection:
3583 m_text.remove(cmd.pos, 1);
3584 m_selstart = cmd.selStart;
3585 m_selend = cmd.selEnd;
3589 m_selstart = cmd.selStart;
3590 m_selend = cmd.selEnd;
3594 if (m_undoState < (int)m_history.size()) {
3595 Command& next = m_history[m_undoState];
3596 if (next.type != cmd.type && cmd.type < RemoveSelection && next.type != Separator
3597 && (next.type < RemoveSelection || cmd.type == Separator))
3602 emitCursorPositionChanged();
3608 If the current cursor position differs from the last emitted cursor
3609 position, emits cursorPositionChanged().
3611 void QQuickTextInputPrivate::emitCursorPositionChanged()
3613 Q_Q(QQuickTextInput);
3614 if (m_cursor != m_lastCursorPos) {
3615 m_lastCursorPos = m_cursor;
3617 q->updateCursorRectangle();
3618 emit q->cursorPositionChanged();
3619 // XXX todo - not in 4.8?
3621 resetCursorBlinkTimer();
3624 if (!hasSelectedText()) {
3625 if (lastSelectionStart != m_cursor) {
3626 lastSelectionStart = m_cursor;
3627 emit q->selectionStartChanged();
3629 if (lastSelectionEnd != m_cursor) {
3630 lastSelectionEnd = m_cursor;
3631 emit q->selectionEndChanged();
3635 #ifndef QT_NO_ACCESSIBILITY
3636 QAccessible::updateAccessibility(q, 0, QAccessible::TextCaretMoved);
3642 void QQuickTextInputPrivate::setCursorBlinkPeriod(int msec)
3644 Q_Q(QQuickTextInput);
3645 if (msec == m_blinkPeriod)
3648 q->killTimer(m_blinkTimer);
3651 m_blinkTimer = q->startTimer(msec / 2);
3655 if (m_blinkStatus == 1)
3658 m_blinkPeriod = msec;
3661 void QQuickTextInputPrivate::resetCursorBlinkTimer()
3663 Q_Q(QQuickTextInput);
3664 if (m_blinkPeriod == 0 || m_blinkTimer == 0)
3666 q->killTimer(m_blinkTimer);
3667 m_blinkTimer = q->startTimer(m_blinkPeriod / 2);
3671 void QQuickTextInput::timerEvent(QTimerEvent *event)
3673 Q_D(QQuickTextInput);
3674 if (event->timerId() == d->m_blinkTimer) {
3675 d->m_blinkStatus = !d->m_blinkStatus;
3677 } else if (event->timerId() == d->m_deleteAllTimer) {
3678 killTimer(d->m_deleteAllTimer);
3679 d->m_deleteAllTimer = 0;
3681 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
3682 } else if (event->timerId() == d->m_passwordEchoTimer.timerId()) {
3683 d->m_passwordEchoTimer.stop();
3684 d->updateDisplayText();
3689 void QQuickTextInputPrivate::processKeyEvent(QKeyEvent* event)
3691 Q_Q(QQuickTextInput);
3692 bool inlineCompletionAccepted = false;
3694 if (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return) {
3695 if (hasAcceptableInput(m_text) || fixup()) {
3698 if (inlineCompletionAccepted)
3705 if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit
3706 && !m_passwordEchoEditing
3708 && !event->text().isEmpty()
3709 && !(event->modifiers() & Qt::ControlModifier)) {
3710 // Clear the edit and reset to normal echo mode while editing; the
3711 // echo mode switches back when the edit loses focus
3712 // ### resets current content. dubious code; you can
3713 // navigate with keys up, down, back, and select(?), but if you press
3714 // "left" or "right" it clears?
3715 updatePasswordEchoEditing(true);
3719 bool unknown = false;
3720 bool visual = cursorMoveStyle() == Qt::VisualMoveStyle;
3724 #ifndef QT_NO_SHORTCUT
3725 else if (event == QKeySequence::Undo) {
3729 else if (event == QKeySequence::Redo) {
3733 else if (event == QKeySequence::SelectAll) {
3736 #ifndef QT_NO_CLIPBOARD
3737 else if (event == QKeySequence::Copy) {
3740 else if (event == QKeySequence::Paste) {
3742 QClipboard::Mode mode = QClipboard::Clipboard;
3746 else if (event == QKeySequence::Cut) {
3752 else if (event == QKeySequence::DeleteEndOfLine) {
3754 setSelection(m_cursor, end());
3759 #endif //QT_NO_CLIPBOARD
3760 else if (event == QKeySequence::MoveToStartOfLine || event == QKeySequence::MoveToStartOfBlock) {
3763 else if (event == QKeySequence::MoveToEndOfLine || event == QKeySequence::MoveToEndOfBlock) {
3766 else if (event == QKeySequence::SelectStartOfLine || event == QKeySequence::SelectStartOfBlock) {
3769 else if (event == QKeySequence::SelectEndOfLine || event == QKeySequence::SelectEndOfBlock) {
3772 else if (event == QKeySequence::MoveToNextChar) {
3773 if (hasSelectedText()) {
3774 moveCursor(selectionEnd(), false);
3776 cursorForward(0, visual ? 1 : (layoutDirection() == Qt::LeftToRight ? 1 : -1));
3779 else if (event == QKeySequence::SelectNextChar) {
3780 cursorForward(1, visual ? 1 : (layoutDirection() == Qt::LeftToRight ? 1 : -1));
3782 else if (event == QKeySequence::MoveToPreviousChar) {
3783 if (hasSelectedText()) {
3784 moveCursor(selectionStart(), false);
3786 cursorForward(0, visual ? -1 : (layoutDirection() == Qt::LeftToRight ? -1 : 1));
3789 else if (event == QKeySequence::SelectPreviousChar) {
3790 cursorForward(1, visual ? -1 : (layoutDirection() == Qt::LeftToRight ? -1 : 1));
3792 else if (event == QKeySequence::MoveToNextWord) {
3793 if (m_echoMode == QQuickTextInput::Normal)
3794 layoutDirection() == Qt::LeftToRight ? cursorWordForward(0) : cursorWordBackward(0);
3796 layoutDirection() == Qt::LeftToRight ? end(0) : home(0);
3798 else if (event == QKeySequence::MoveToPreviousWord) {
3799 if (m_echoMode == QQuickTextInput::Normal)
3800 layoutDirection() == Qt::LeftToRight ? cursorWordBackward(0) : cursorWordForward(0);
3801 else if (!m_readOnly) {
3802 layoutDirection() == Qt::LeftToRight ? home(0) : end(0);
3805 else if (event == QKeySequence::SelectNextWord) {
3806 if (m_echoMode == QQuickTextInput::Normal)
3807 layoutDirection() == Qt::LeftToRight ? cursorWordForward(1) : cursorWordBackward(1);
3809 layoutDirection() == Qt::LeftToRight ? end(1) : home(1);
3811 else if (event == QKeySequence::SelectPreviousWord) {
3812 if (m_echoMode == QQuickTextInput::Normal)
3813 layoutDirection() == Qt::LeftToRight ? cursorWordBackward(1) : cursorWordForward(1);
3815 layoutDirection() == Qt::LeftToRight ? home(1) : end(1);
3817 else if (event == QKeySequence::Delete) {
3821 else if (event == QKeySequence::DeleteEndOfWord) {
3823 cursorWordForward(true);
3827 else if (event == QKeySequence::DeleteStartOfWord) {
3829 cursorWordBackward(true);
3833 #endif // QT_NO_SHORTCUT
3835 bool handled = false;
3836 if (event->modifiers() & Qt::ControlModifier) {
3837 switch (event->key()) {
3838 case Qt::Key_Backspace:
3840 cursorWordBackward(true);
3848 } else { // ### check for *no* modifier
3849 switch (event->key()) {
3850 case Qt::Key_Backspace:
3862 if (event->key() == Qt::Key_Direction_L || event->key() == Qt::Key_Direction_R) {
3863 setLayoutDirection((event->key() == Qt::Key_Direction_L) ? Qt::LeftToRight : Qt::RightToLeft);
3867 if (unknown && !m_readOnly) {
3868 QString t = event->text();
3869 if (!t.isEmpty() && t.at(0).isPrint()) {