1 /****************************************************************************
3 ** Copyright (C) 2011 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);
138 QString QQuickTextInputPrivate::realText() const
140 QString res = m_maskData ? stripString(m_text) : m_text;
141 return (res.isNull() ? QString::fromLatin1("") : res);
145 \qmlproperty string QtQuick2::TextInput::font.family
147 Sets the family name of the font.
149 The family name is case insensitive and may optionally include a foundry name, e.g. "Helvetica [Cronyx]".
150 If the family is available from more than one foundry and the foundry isn't specified, an arbitrary foundry is chosen.
151 If the family isn't available a family will be set using the font matching algorithm.
155 \qmlproperty bool QtQuick2::TextInput::font.bold
157 Sets whether the font weight is bold.
161 \qmlproperty enumeration QtQuick2::TextInput::font.weight
163 Sets the font's weight.
165 The weight can be one of:
168 \o Font.Normal - the default
175 TextInput { text: "Hello"; font.weight: Font.DemiBold }
180 \qmlproperty bool QtQuick2::TextInput::font.italic
182 Sets whether the font has an italic style.
186 \qmlproperty bool QtQuick2::TextInput::font.underline
188 Sets whether the text is underlined.
192 \qmlproperty bool QtQuick2::TextInput::font.strikeout
194 Sets whether the font has a strikeout style.
198 \qmlproperty real QtQuick2::TextInput::font.pointSize
200 Sets the font size in points. The point size must be greater than zero.
204 \qmlproperty int QtQuick2::TextInput::font.pixelSize
206 Sets the font size in pixels.
208 Using this function makes the font device dependent.
209 Use \c pointSize to set the size of the font in a device independent manner.
213 \qmlproperty real QtQuick2::TextInput::font.letterSpacing
215 Sets the letter spacing for the font.
217 Letter spacing changes the default spacing between individual letters in the font.
218 A positive value increases the letter spacing by the corresponding pixels; a negative value decreases the spacing.
222 \qmlproperty real QtQuick2::TextInput::font.wordSpacing
224 Sets the word spacing for the font.
226 Word spacing changes the default spacing between individual words.
227 A positive value increases the word spacing by a corresponding amount of pixels,
228 while a negative value decreases the inter-word spacing accordingly.
232 \qmlproperty enumeration QtQuick2::TextInput::font.capitalization
234 Sets the capitalization for the text.
237 \o Font.MixedCase - This is the normal text rendering option where no capitalization change is applied.
238 \o Font.AllUppercase - This alters the text to be rendered in all uppercase type.
239 \o Font.AllLowercase - This alters the text to be rendered in all lowercase type.
240 \o Font.SmallCaps - This alters the text to be rendered in small-caps type.
241 \o Font.Capitalize - This alters the text to be rendered with the first character of each word as an uppercase character.
245 TextInput { text: "Hello"; font.capitalization: Font.AllLowercase }
249 QFont QQuickTextInput::font() const
251 Q_D(const QQuickTextInput);
252 return d->sourceFont;
255 void QQuickTextInput::setFont(const QFont &font)
257 Q_D(QQuickTextInput);
258 if (d->sourceFont == font)
261 d->sourceFont = font;
262 QFont oldFont = d->font;
264 if (d->font.pointSizeF() != -1) {
266 qreal size = qRound(d->font.pointSizeF()*2.0);
267 d->font.setPointSizeF(size/2.0);
269 if (oldFont != d->font) {
271 updateCursorRectangle();
273 emit fontChanged(d->sourceFont);
277 \qmlproperty color QtQuick2::TextInput::color
281 QColor QQuickTextInput::color() const
283 Q_D(const QQuickTextInput);
287 void QQuickTextInput::setColor(const QColor &c)
289 Q_D(QQuickTextInput);
292 d->textLayoutDirty = true;
294 emit colorChanged(c);
300 \qmlproperty color QtQuick2::TextInput::selectionColor
302 The text highlight color, used behind selections.
304 QColor QQuickTextInput::selectionColor() const
306 Q_D(const QQuickTextInput);
307 return d->selectionColor;
310 void QQuickTextInput::setSelectionColor(const QColor &color)
312 Q_D(QQuickTextInput);
313 if (d->selectionColor == color)
316 d->selectionColor = color;
317 d->m_palette.setColor(QPalette::Highlight, d->selectionColor);
318 if (d->hasSelectedText()) {
319 d->textLayoutDirty = true;
322 emit selectionColorChanged(color);
325 \qmlproperty color QtQuick2::TextInput::selectedTextColor
327 The highlighted text color, used in selections.
329 QColor QQuickTextInput::selectedTextColor() const
331 Q_D(const QQuickTextInput);
332 return d->selectedTextColor;
335 void QQuickTextInput::setSelectedTextColor(const QColor &color)
337 Q_D(QQuickTextInput);
338 if (d->selectedTextColor == color)
341 d->selectedTextColor = color;
342 d->m_palette.setColor(QPalette::HighlightedText, d->selectedTextColor);
343 if (d->hasSelectedText()) {
344 d->textLayoutDirty = true;
347 emit selectedTextColorChanged(color);
351 \qmlproperty enumeration QtQuick2::TextInput::horizontalAlignment
352 \qmlproperty enumeration QtQuick2::TextInput::effectiveHorizontalAlignment
353 \qmlproperty enumeration QtQuick2::TextInput::verticalAlignment
355 Sets the horizontal alignment of the text within the TextInput item's
356 width and height. By default, the text alignment follows the natural alignment
357 of the text, for example text that is read from left to right will be aligned to
360 TextInput does not have vertical alignment, as the natural height is
361 exactly the height of the single line of text. If you set the height
362 manually to something larger, TextInput will always be top aligned
363 vertically. You can use anchors to align it however you want within
366 The valid values for \c horizontalAlignment are \c TextInput.AlignLeft, \c TextInput.AlignRight and
367 \c TextInput.AlignHCenter.
369 Valid values for \c verticalAlignment are \c TextEdit.AlignTop (default),
370 \c TextEdit.AlignBottom \c TextEdit.AlignVCenter.
372 When using the attached property LayoutMirroring::enabled to mirror application
373 layouts, the horizontal alignment of text will also be mirrored. However, the property
374 \c horizontalAlignment will remain unchanged. To query the effective horizontal alignment
375 of TextInput, use the read-only property \c effectiveHorizontalAlignment.
377 QQuickTextInput::HAlignment QQuickTextInput::hAlign() const
379 Q_D(const QQuickTextInput);
383 void QQuickTextInput::setHAlign(HAlignment align)
385 Q_D(QQuickTextInput);
386 bool forceAlign = d->hAlignImplicit && d->effectiveLayoutMirror;
387 d->hAlignImplicit = false;
388 if (d->setHAlign(align, forceAlign) && isComponentComplete()) {
390 updateCursorRectangle();
394 void QQuickTextInput::resetHAlign()
396 Q_D(QQuickTextInput);
397 d->hAlignImplicit = true;
398 if (d->determineHorizontalAlignment() && isComponentComplete()) {
400 updateCursorRectangle();
404 QQuickTextInput::HAlignment QQuickTextInput::effectiveHAlign() const
406 Q_D(const QQuickTextInput);
407 QQuickTextInput::HAlignment effectiveAlignment = d->hAlign;
408 if (!d->hAlignImplicit && d->effectiveLayoutMirror) {
410 case QQuickTextInput::AlignLeft:
411 effectiveAlignment = QQuickTextInput::AlignRight;
413 case QQuickTextInput::AlignRight:
414 effectiveAlignment = QQuickTextInput::AlignLeft;
420 return effectiveAlignment;
423 bool QQuickTextInputPrivate::setHAlign(QQuickTextInput::HAlignment alignment, bool forceAlign)
425 Q_Q(QQuickTextInput);
426 if ((hAlign != alignment || forceAlign) && alignment <= QQuickTextInput::AlignHCenter) { // justify not supported
427 QQuickTextInput::HAlignment oldEffectiveHAlign = q->effectiveHAlign();
429 emit q->horizontalAlignmentChanged(alignment);
430 if (oldEffectiveHAlign != q->effectiveHAlign())
431 emit q->effectiveHorizontalAlignmentChanged();
437 bool QQuickTextInputPrivate::determineHorizontalAlignment()
439 if (hAlignImplicit) {
440 // if no explicit alignment has been set, follow the natural layout direction of the text
441 QString text = q_func()->text();
443 text = m_textLayout.preeditAreaText();
444 bool isRightToLeft = text.isEmpty() ? QGuiApplication::keyboardInputDirection() == Qt::RightToLeft : text.isRightToLeft();
445 return setHAlign(isRightToLeft ? QQuickTextInput::AlignRight : QQuickTextInput::AlignLeft);
450 QQuickTextInput::VAlignment QQuickTextInput::vAlign() const
452 Q_D(const QQuickTextInput);
456 void QQuickTextInput::setVAlign(QQuickTextInput::VAlignment alignment)
458 Q_D(QQuickTextInput);
459 if (alignment == d->vAlign)
461 d->vAlign = alignment;
462 emit verticalAlignmentChanged(d->vAlign);
463 if (isComponentComplete()) {
464 updateCursorRectangle();
469 \qmlproperty enumeration QtQuick2::TextInput::wrapMode
471 Set this property to wrap the text to the TextEdit item's width.
472 The text will only wrap if an explicit width has been set.
475 \o TextInput.NoWrap - no wrapping will be performed. If the text contains insufficient newlines, then implicitWidth will exceed a set width.
476 \o TextInput.WordWrap - wrapping is done on word boundaries only. If a word is too long, implicitWidth will exceed a set width.
477 \o TextInput.WrapAnywhere - wrapping is done at any point on a line, even if it occurs in the middle of a word.
478 \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.
481 The default is TextInput.NoWrap. If you set a width, consider using TextInput.Wrap.
483 QQuickTextInput::WrapMode QQuickTextInput::wrapMode() const
485 Q_D(const QQuickTextInput);
489 void QQuickTextInput::setWrapMode(WrapMode mode)
491 Q_D(QQuickTextInput);
492 if (mode == d->wrapMode)
496 updateCursorRectangle();
497 emit wrapModeChanged();
500 void QQuickTextInputPrivate::mirrorChange()
502 Q_Q(QQuickTextInput);
503 if (q->isComponentComplete()) {
504 if (!hAlignImplicit && (hAlign == QQuickTextInput::AlignRight || hAlign == QQuickTextInput::AlignLeft)) {
505 q->updateCursorRectangle();
506 emit q->effectiveHorizontalAlignmentChanged();
512 \qmlproperty bool QtQuick2::TextInput::readOnly
514 Sets whether user input can modify the contents of the TextInput.
516 If readOnly is set to true, then user input will not affect the text
517 property. Any bindings or attempts to set the text property will still
520 bool QQuickTextInput::isReadOnly() const
522 Q_D(const QQuickTextInput);
523 return d->m_readOnly;
526 void QQuickTextInput::setReadOnly(bool ro)
528 Q_D(QQuickTextInput);
529 if (d->m_readOnly == ro)
532 setFlag(QQuickItem::ItemAcceptsInputMethod, !ro);
535 d->setCursorPosition(d->end());
537 emit readOnlyChanged(ro);
541 \qmlproperty int QtQuick2::TextInput::maximumLength
542 The maximum permitted length of the text in the TextInput.
544 If the text is too long, it is truncated at the limit.
546 By default, this property contains a value of 32767.
548 int QQuickTextInput::maxLength() const
550 Q_D(const QQuickTextInput);
551 return d->m_maxLength;
554 void QQuickTextInput::setMaxLength(int ml)
556 Q_D(QQuickTextInput);
557 if (d->m_maxLength == ml || d->m_maskData)
561 d->internalSetText(d->m_text, -1, false);
563 emit maximumLengthChanged(ml);
567 \qmlproperty bool QtQuick2::TextInput::cursorVisible
568 Set to true when the TextInput shows a cursor.
570 This property is set and unset when the TextInput gets active focus, so that other
571 properties can be bound to whether the cursor is currently showing. As it
572 gets set and unset automatically, when you set the value yourself you must
573 keep in mind that your value may be overwritten.
575 It can be set directly in script, for example if a KeyProxy might
576 forward keys to it and you desire it to look active when this happens
577 (but without actually giving it active focus).
579 It should not be set directly on the element, like in the below QML,
580 as the specified value will be overridden an lost on focus changes.
589 In the above snippet the cursor will still become visible when the
590 TextInput gains active focus.
592 bool QQuickTextInput::isCursorVisible() const
594 Q_D(const QQuickTextInput);
595 return d->cursorVisible;
598 void QQuickTextInput::setCursorVisible(bool on)
600 Q_D(QQuickTextInput);
601 if (d->cursorVisible == on)
603 d->cursorVisible = on;
604 d->setCursorBlinkPeriod(on ? qApp->styleHints()->cursorFlashTime() : 0);
606 emit cursorVisibleChanged(d->cursorVisible);
610 \qmlproperty int QtQuick2::TextInput::cursorPosition
611 The position of the cursor in the TextInput.
613 int QQuickTextInput::cursorPosition() const
615 Q_D(const QQuickTextInput);
619 void QQuickTextInput::setCursorPosition(int cp)
621 Q_D(QQuickTextInput);
622 if (cp < 0 || cp > text().length())
628 Returns a Rect which encompasses the cursor, but which may be larger than is
629 required. Ignores custom cursor delegates.
631 QRect QQuickTextInput::cursorRectangle() const
633 Q_D(const QQuickTextInput);
636 if (d->m_preeditCursor != -1)
637 c += d->m_preeditCursor;
638 if (d->m_echoMode == NoEcho)
640 QTextLine l = d->m_textLayout.lineForTextPosition(c);
644 qRound(l.cursorToX(c) - d->hscroll),
645 qRound(l.y() - d->vscroll),
651 \qmlproperty int QtQuick2::TextInput::selectionStart
653 The cursor position before the first character in the current selection.
655 This property is read-only. To change the selection, use select(start,end),
656 selectAll(), or selectWord().
658 \sa selectionEnd, cursorPosition, selectedText
660 int QQuickTextInput::selectionStart() const
662 Q_D(const QQuickTextInput);
663 return d->lastSelectionStart;
666 \qmlproperty int QtQuick2::TextInput::selectionEnd
668 The cursor position after the last character in the current selection.
670 This property is read-only. To change the selection, use select(start,end),
671 selectAll(), or selectWord().
673 \sa selectionStart, cursorPosition, selectedText
675 int QQuickTextInput::selectionEnd() const
677 Q_D(const QQuickTextInput);
678 return d->lastSelectionEnd;
681 \qmlmethod void QtQuick2::TextInput::select(int start, int end)
683 Causes the text from \a start to \a end to be selected.
685 If either start or end is out of range, the selection is not changed.
687 After calling this, selectionStart will become the lesser
688 and selectionEnd will become the greater (regardless of the order passed
691 \sa selectionStart, selectionEnd
693 void QQuickTextInput::select(int start, int end)
695 Q_D(QQuickTextInput);
696 if (start < 0 || end < 0 || start > text().length() || end > text().length())
698 d->setSelection(start, end-start);
702 \qmlproperty string QtQuick2::TextInput::selectedText
704 This read-only property provides the text currently selected in the
707 It is equivalent to the following snippet, but is faster and easier
711 myTextInput.text.toString().substring(myTextInput.selectionStart,
712 myTextInput.selectionEnd);
715 QString QQuickTextInput::selectedText() const
717 Q_D(const QQuickTextInput);
718 return d->selectedText();
722 \qmlproperty bool QtQuick2::TextInput::activeFocusOnPress
724 Whether the TextInput should gain active focus on a mouse press. By default this is
727 bool QQuickTextInput::focusOnPress() const
729 Q_D(const QQuickTextInput);
730 return d->focusOnPress;
733 void QQuickTextInput::setFocusOnPress(bool b)
735 Q_D(QQuickTextInput);
736 if (d->focusOnPress == b)
741 emit activeFocusOnPressChanged(d->focusOnPress);
744 \qmlproperty bool QtQuick2::TextInput::autoScroll
746 Whether the TextInput should scroll when the text is longer than the width. By default this is
749 bool QQuickTextInput::autoScroll() const
751 Q_D(const QQuickTextInput);
752 return d->autoScroll;
755 void QQuickTextInput::setAutoScroll(bool b)
757 Q_D(QQuickTextInput);
758 if (d->autoScroll == b)
762 //We need to repaint so that the scrolling is taking into account.
763 updateCursorRectangle();
764 emit autoScrollChanged(d->autoScroll);
767 #ifndef QT_NO_VALIDATOR
770 \qmlclass IntValidator QIntValidator
771 \inqmlmodule QtQuick 2
772 \ingroup qml-basic-visual-elements
774 This element provides a validator for integer values.
776 IntValidator uses the \l {QLocale::setDefault()}{default locale} to interpret the number and
777 will accept locale specific digits, group separators, and positive and negative signs. In
778 addition, IntValidator is always guaranteed to accept a number formatted according to the "C"
782 \qmlproperty int QtQuick2::IntValidator::top
784 This property holds the validator's highest acceptable value.
785 By default, this property's value is derived from the highest signed integer available (typically 2147483647).
788 \qmlproperty int QtQuick2::IntValidator::bottom
790 This property holds the validator's lowest acceptable value.
791 By default, this property's value is derived from the lowest signed integer available (typically -2147483647).
795 \qmlclass DoubleValidator QDoubleValidator
796 \inqmlmodule QtQuick 2
797 \ingroup qml-basic-visual-elements
799 This element provides a validator for non-integer numbers.
803 \qmlproperty real QtQuick2::DoubleValidator::top
805 This property holds the validator's maximum acceptable value.
806 By default, this property contains a value of infinity.
809 \qmlproperty real QtQuick2::DoubleValidator::bottom
811 This property holds the validator's minimum acceptable value.
812 By default, this property contains a value of -infinity.
815 \qmlproperty int QtQuick2::DoubleValidator::decimals
817 This property holds the validator's maximum number of digits after the decimal point.
818 By default, this property contains a value of 1000.
821 \qmlproperty enumeration QtQuick2::DoubleValidator::notation
822 This property holds the notation of how a string can describe a number.
824 The possible values for this property are:
827 \o DoubleValidator.StandardNotation
828 \o DoubleValidator.ScientificNotation (default)
831 If this property is set to DoubleValidator.ScientificNotation, the written number may have an exponent part (e.g. 1.5E-2).
835 \qmlclass RegExpValidator QRegExpValidator
836 \inqmlmodule QtQuick 2
837 \ingroup qml-basic-visual-elements
839 This element provides a validator, which counts as valid any string which
840 matches a specified regular expression.
843 \qmlproperty regExp QtQuick2::RegExpValidator::regExp
845 This property holds the regular expression used for validation.
847 Note that this property should be a regular expression in JS syntax, e.g /a/ for the regular expression
850 By default, this property contains a regular expression with the pattern .* that matches any string.
854 \qmlproperty Validator QtQuick2::TextInput::validator
856 Allows you to set a validator on the TextInput. When a validator is set
857 the TextInput will only accept input which leaves the text property in
858 an acceptable or intermediate state. The accepted signal will only be sent
859 if the text is in an acceptable state when enter is pressed.
861 Currently supported validators are IntValidator, DoubleValidator and
862 RegExpValidator. An example of using validators is shown below, which allows
863 input of integers between 11 and 31 into the text input:
868 validator: IntValidator{bottom: 11; top: 31;}
873 \sa acceptableInput, inputMask
876 QValidator* QQuickTextInput::validator() const
878 Q_D(const QQuickTextInput);
879 return d->m_validator;
882 void QQuickTextInput::setValidator(QValidator* v)
884 Q_D(QQuickTextInput);
885 if (d->m_validator == v)
889 if (!d->hasAcceptableInput(d->m_text)) {
890 d->oldValidity = false;
891 emit acceptableInputChanged();
894 emit validatorChanged();
896 #endif // QT_NO_VALIDATOR
899 \qmlproperty string QtQuick2::TextInput::inputMask
901 Allows you to set an input mask on the TextInput, restricting the allowable
902 text inputs. See QLineEdit::inputMask for further details, as the exact
903 same mask strings are used by TextInput.
905 \sa acceptableInput, validator
907 QString QQuickTextInput::inputMask() const
909 Q_D(const QQuickTextInput);
910 return d->inputMask();
913 void QQuickTextInput::setInputMask(const QString &im)
915 Q_D(QQuickTextInput);
916 if (d->inputMask() == im)
920 emit inputMaskChanged(d->inputMask());
924 \qmlproperty bool QtQuick2::TextInput::acceptableInput
926 This property is always true unless a validator or input mask has been set.
927 If a validator or input mask has been set, this property will only be true
928 if the current text is acceptable to the validator or input mask as a final
929 string (not as an intermediate string).
931 bool QQuickTextInput::hasAcceptableInput() const
933 Q_D(const QQuickTextInput);
934 return d->hasAcceptableInput(d->m_text);
938 \qmlsignal QtQuick2::TextInput::onAccepted()
940 This handler is called when the Return or Enter key is pressed.
941 Note that if there is a \l validator or \l inputMask set on the text
942 input, the handler will only be emitted if the input is in an acceptable
946 void QQuickTextInputPrivate::updateInputMethodHints()
948 Q_Q(QQuickTextInput);
949 Qt::InputMethodHints hints = inputMethodHints;
950 if (m_echoMode == QQuickTextInput::Password || m_echoMode == QQuickTextInput::NoEcho)
951 hints |= Qt::ImhHiddenText;
952 else if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit)
953 hints &= ~Qt::ImhHiddenText;
954 if (m_echoMode != QQuickTextInput::Normal)
955 hints |= (Qt::ImhNoAutoUppercase | Qt::ImhNoPredictiveText | Qt::ImhSensitiveData);
956 q->setInputMethodHints(hints);
959 \qmlproperty enumeration QtQuick2::TextInput::echoMode
961 Specifies how the text should be displayed in the TextInput.
963 \o TextInput.Normal - Displays the text as it is. (Default)
964 \o TextInput.Password - Displays asterisks instead of characters.
965 \o TextInput.NoEcho - Displays nothing.
966 \o TextInput.PasswordEchoOnEdit - Displays characters as they are entered
967 while editing, otherwise displays asterisks.
970 QQuickTextInput::EchoMode QQuickTextInput::echoMode() const
972 Q_D(const QQuickTextInput);
973 return QQuickTextInput::EchoMode(d->m_echoMode);
976 void QQuickTextInput::setEchoMode(QQuickTextInput::EchoMode echo)
978 Q_D(QQuickTextInput);
979 if (echoMode() == echo)
981 d->cancelPasswordEchoTimer();
982 d->m_echoMode = echo;
983 d->m_passwordEchoEditing = false;
984 d->updateInputMethodHints();
985 d->updateDisplayText();
986 updateCursorRectangle();
988 emit echoModeChanged(echoMode());
991 Qt::InputMethodHints QQuickTextInput::imHints() const
993 Q_D(const QQuickTextInput);
994 return d->inputMethodHints;
997 void QQuickTextInput::setIMHints(Qt::InputMethodHints hints)
999 Q_D(QQuickTextInput);
1000 if (d->inputMethodHints == hints)
1002 d->inputMethodHints = hints;
1003 d->updateInputMethodHints();
1007 \qmlproperty Component QtQuick2::TextInput::cursorDelegate
1008 The delegate for the cursor in the TextInput.
1010 If you set a cursorDelegate for a TextInput, this delegate will be used for
1011 drawing the cursor instead of the standard cursor. An instance of the
1012 delegate will be created and managed by the TextInput when a cursor is
1013 needed, and the x property of delegate instance will be set so as
1014 to be one pixel before the top left of the current character.
1016 Note that the root item of the delegate component must be a QDeclarativeItem or
1017 QDeclarativeItem derived item.
1019 QDeclarativeComponent* QQuickTextInput::cursorDelegate() const
1021 Q_D(const QQuickTextInput);
1022 return d->cursorComponent;
1025 void QQuickTextInput::setCursorDelegate(QDeclarativeComponent* c)
1027 Q_D(QQuickTextInput);
1028 if (d->cursorComponent == c)
1031 d->cursorComponent = c;
1033 //note that the components are owned by something else
1034 delete d->cursorItem;
1036 d->startCreatingCursor();
1039 emit cursorDelegateChanged();
1042 void QQuickTextInputPrivate::startCreatingCursor()
1044 Q_Q(QQuickTextInput);
1045 if (cursorComponent->isReady()) {
1047 } else if (cursorComponent->isLoading()) {
1048 q->connect(cursorComponent, SIGNAL(statusChanged(int)),
1049 q, SLOT(createCursor()));
1051 qmlInfo(q, cursorComponent->errors()) << QQuickTextInput::tr("Could not load cursor delegate");
1055 void QQuickTextInput::createCursor()
1057 Q_D(QQuickTextInput);
1058 if (!isComponentComplete())
1061 if (d->cursorComponent->isError()) {
1062 qmlInfo(this, d->cursorComponent->errors()) << tr("Could not load cursor delegate");
1066 if (!d->cursorComponent->isReady())
1070 delete d->cursorItem;
1071 QDeclarativeContext *creationContext = d->cursorComponent->creationContext();
1072 QObject *object = d->cursorComponent->create(creationContext ? creationContext : qmlContext(this));
1073 d->cursorItem = qobject_cast<QQuickItem*>(object);
1074 if (!d->cursorItem) {
1076 qmlInfo(this, d->cursorComponent->errors()) << tr("Could not instantiate cursor delegate");
1080 QRectF r = cursorRectangle();
1082 QDeclarative_setParent_noEvent(d->cursorItem, this);
1083 d->cursorItem->setParentItem(this);
1084 d->cursorItem->setPos(r.topLeft());
1085 d->cursorItem->setHeight(r.height());
1089 \qmlmethod rect QtQuick2::TextInput::positionToRectangle(int pos)
1091 This function takes a character position and returns the rectangle that the
1092 cursor would occupy, if it was placed at that character position.
1094 This is similar to setting the cursorPosition, and then querying the cursor
1095 rectangle, but the cursorPosition is not changed.
1097 QRectF QQuickTextInput::positionToRectangle(int pos) const
1099 Q_D(const QQuickTextInput);
1100 if (pos > d->m_cursor)
1101 pos += d->preeditAreaText().length();
1102 QTextLine l = d->m_textLayout.lineAt(0);
1104 ? QRectF(l.cursorToX(pos) - d->hscroll, 0.0, d->m_cursorWidth, l.height())
1109 \qmlmethod int QtQuick2::TextInput::positionAt(real x, real y, CursorPosition position = CursorBetweenCharacters)
1111 This function returns the character position at
1112 x and y pixels from the top left of the textInput. Position 0 is before the
1113 first character, position 1 is after the first character but before the second,
1114 and so on until position text.length, which is after all characters.
1116 This means that for all x values before the first character this function returns 0,
1117 and for all x values after the last character this function returns text.length. If
1118 the y value is above the text the position will be that of the nearest character on
1119 the first line line and if it is below the text the position of the nearest character
1120 on the last line will be returned.
1122 The cursor position type specifies how the cursor position should be resolved.
1125 \o TextInput.CursorBetweenCharacters - Returns the position between characters that is nearest x.
1126 \o TextInput.CursorOnCharacter - Returns the position before the character that is nearest x.
1130 void QQuickTextInput::positionAt(QDeclarativeV8Function *args) const
1132 Q_D(const QQuickTextInput);
1136 QTextLine::CursorPosition position = QTextLine::CursorBetweenCharacters;
1138 if (args->Length() < 1)
1142 v8::Local<v8::Value> arg = (*args)[i];
1143 x = arg->NumberValue();
1145 if (++i < args->Length()) {
1147 y = arg->NumberValue();
1150 if (++i < args->Length()) {
1152 position = QTextLine::CursorPosition(arg->Int32Value());
1155 int pos = d->positionAt(x, y, position);
1156 const int cursor = d->m_cursor;
1158 const int preeditLength = d->preeditAreaText().length();
1159 pos = pos > cursor + preeditLength
1160 ? pos - preeditLength
1163 args->returnValue(v8::Int32::New(pos));
1166 int QQuickTextInputPrivate::positionAt(int x, int y, QTextLine::CursorPosition position) const
1170 QTextLine line = m_textLayout.lineAt(0);
1171 for (int i = 1; i < m_textLayout.lineCount(); ++i) {
1172 QTextLine nextLine = m_textLayout.lineAt(i);
1174 if (y < (line.rect().bottom() + nextLine.y()) / 2)
1178 return line.isValid() ? line.xToCursor(x, position) : 0;
1181 void QQuickTextInput::keyPressEvent(QKeyEvent* ev)
1183 Q_D(QQuickTextInput);
1184 // Don't allow MacOSX up/down support, and we don't allow a completer.
1185 bool ignore = (ev->key() == Qt::Key_Up || ev->key() == Qt::Key_Down) && ev->modifiers() == Qt::NoModifier;
1186 if (!ignore && (d->lastSelectionStart == d->lastSelectionEnd) && (ev->key() == Qt::Key_Right || ev->key() == Qt::Key_Left)) {
1187 // Ignore when moving off the end unless there is a selection,
1188 // because then moving will do something (deselect).
1189 int cursorPosition = d->m_cursor;
1190 if (cursorPosition == 0)
1191 ignore = ev->key() == (d->layoutDirection() == Qt::LeftToRight ? Qt::Key_Left : Qt::Key_Right);
1192 if (cursorPosition == text().length())
1193 ignore = ev->key() == (d->layoutDirection() == Qt::LeftToRight ? Qt::Key_Right : Qt::Key_Left);
1198 d->processKeyEvent(ev);
1200 if (!ev->isAccepted())
1201 QQuickImplicitSizeItem::keyPressEvent(ev);
1204 void QQuickTextInput::inputMethodEvent(QInputMethodEvent *ev)
1206 Q_D(QQuickTextInput);
1207 const bool wasComposing = d->preeditAreaText().length() > 0;
1208 if (d->m_readOnly) {
1211 d->processInputMethodEvent(ev);
1213 if (!ev->isAccepted())
1214 QQuickImplicitSizeItem::inputMethodEvent(ev);
1216 if (wasComposing != (d->m_textLayout.preeditAreaText().length() > 0))
1217 emit inputMethodComposingChanged();
1220 void QQuickTextInput::mouseDoubleClickEvent(QMouseEvent *event)
1222 Q_D(QQuickTextInput);
1224 if (d->selectByMouse && event->button() == Qt::LeftButton) {
1226 int cursor = d->positionAt(event->localPos());
1227 d->selectWordAtPos(cursor);
1228 event->setAccepted(true);
1229 if (!d->hasPendingTripleClick()) {
1230 d->tripleClickStartPoint = event->localPos().toPoint();
1231 d->tripleClickTimer.start();
1234 if (d->sendMouseEventToInputContext(event))
1236 QQuickImplicitSizeItem::mouseDoubleClickEvent(event);
1240 void QQuickTextInput::mousePressEvent(QMouseEvent *event)
1242 Q_D(QQuickTextInput);
1244 d->pressPos = event->localPos();
1246 if (d->focusOnPress) {
1247 bool hadActiveFocus = hasActiveFocus();
1249 // re-open input panel on press if already focused
1250 if (hasActiveFocus() && hadActiveFocus && !d->m_readOnly)
1251 openSoftwareInputPanel();
1253 if (d->selectByMouse) {
1254 setKeepMouseGrab(false);
1255 d->selectPressed = true;
1256 QPoint distanceVector = d->pressPos.toPoint() - d->tripleClickStartPoint;
1257 if (d->hasPendingTripleClick()
1258 && distanceVector.manhattanLength() < qApp->styleHints()->startDragDistance()) {
1259 event->setAccepted(true);
1265 if (d->sendMouseEventToInputContext(event))
1268 bool mark = (event->modifiers() & Qt::ShiftModifier) && d->selectByMouse;
1269 int cursor = d->positionAt(event->localPos());
1270 d->moveCursor(cursor, mark);
1271 event->setAccepted(true);
1274 void QQuickTextInput::mouseMoveEvent(QMouseEvent *event)
1276 Q_D(QQuickTextInput);
1278 if (d->selectPressed) {
1279 if (qAbs(int(event->localPos().x() - d->pressPos.x())) > qApp->styleHints()->startDragDistance())
1280 setKeepMouseGrab(true);
1282 if (d->composeMode()) {
1284 int startPos = d->positionAt(d->pressPos);
1285 int currentPos = d->positionAt(event->localPos());
1286 if (startPos != currentPos)
1287 d->setSelection(startPos, currentPos - startPos);
1289 moveCursorSelection(d->positionAt(event->localPos()), d->mouseSelectionMode);
1291 event->setAccepted(true);
1293 QQuickImplicitSizeItem::mouseMoveEvent(event);
1297 void QQuickTextInput::mouseReleaseEvent(QMouseEvent *event)
1299 Q_D(QQuickTextInput);
1300 if (d->sendMouseEventToInputContext(event))
1302 if (d->selectPressed) {
1303 d->selectPressed = false;
1304 setKeepMouseGrab(false);
1306 #ifndef QT_NO_CLIPBOARD
1307 if (QGuiApplication::clipboard()->supportsSelection()) {
1308 if (event->button() == Qt::LeftButton) {
1309 d->copy(QClipboard::Selection);
1310 } else if (!d->m_readOnly && event->button() == Qt::MidButton) {
1312 d->insert(QGuiApplication::clipboard()->text(QClipboard::Selection));
1316 if (!event->isAccepted())
1317 QQuickImplicitSizeItem::mouseReleaseEvent(event);
1320 bool QQuickTextInputPrivate::sendMouseEventToInputContext(QMouseEvent *event)
1322 #if !defined QT_NO_IM
1323 if (composeMode()) {
1324 int tmp_cursor = positionAt(event->localPos());
1325 int mousePos = tmp_cursor - m_cursor;
1326 if (mousePos >= 0 && mousePos <= m_textLayout.preeditAreaText().length()) {
1327 if (event->type() == QEvent::MouseButtonRelease) {
1328 qApp->inputPanel()->invokeAction(QInputPanel::Click, mousePos);
1341 void QQuickTextInput::mouseUngrabEvent()
1343 Q_D(QQuickTextInput);
1344 d->selectPressed = false;
1345 setKeepMouseGrab(false);
1348 bool QQuickTextInput::event(QEvent* ev)
1350 #ifndef QT_NO_SHORTCUT
1351 Q_D(QQuickTextInput);
1352 if (ev->type() == QEvent::ShortcutOverride) {
1355 QKeyEvent* ke = static_cast<QKeyEvent*>(ev);
1356 if (ke == QKeySequence::Copy
1357 || ke == QKeySequence::Paste
1358 || ke == QKeySequence::Cut
1359 || ke == QKeySequence::Redo
1360 || ke == QKeySequence::Undo
1361 || ke == QKeySequence::MoveToNextWord
1362 || ke == QKeySequence::MoveToPreviousWord
1363 || ke == QKeySequence::MoveToStartOfDocument
1364 || ke == QKeySequence::MoveToEndOfDocument
1365 || ke == QKeySequence::SelectNextWord
1366 || ke == QKeySequence::SelectPreviousWord
1367 || ke == QKeySequence::SelectStartOfLine
1368 || ke == QKeySequence::SelectEndOfLine
1369 || ke == QKeySequence::SelectStartOfBlock
1370 || ke == QKeySequence::SelectEndOfBlock
1371 || ke == QKeySequence::SelectStartOfDocument
1372 || ke == QKeySequence::SelectAll
1373 || ke == QKeySequence::SelectEndOfDocument) {
1375 } else if (ke->modifiers() == Qt::NoModifier || ke->modifiers() == Qt::ShiftModifier
1376 || ke->modifiers() == Qt::KeypadModifier) {
1377 if (ke->key() < Qt::Key_Escape) {
1381 switch (ke->key()) {
1382 case Qt::Key_Delete:
1385 case Qt::Key_Backspace:
1397 return QQuickImplicitSizeItem::event(ev);
1400 void QQuickTextInput::geometryChanged(const QRectF &newGeometry,
1401 const QRectF &oldGeometry)
1403 Q_D(QQuickTextInput);
1404 if (newGeometry.width() != oldGeometry.width())
1406 updateCursorRectangle();
1407 QQuickImplicitSizeItem::geometryChanged(newGeometry, oldGeometry);
1410 void QQuickTextInputPrivate::updateHorizontalScroll()
1412 Q_Q(QQuickTextInput);
1413 QTextLine currentLine = m_textLayout.lineForTextPosition(m_cursor + m_preeditCursor);
1414 const int preeditLength = m_textLayout.preeditAreaText().length();
1415 const int width = q->width();
1416 int widthUsed = currentLine.isValid() ? qRound(currentLine.naturalTextWidth()) : 0;
1417 int previousScroll = hscroll;
1419 if (!autoScroll || widthUsed <= width || m_echoMode == QQuickTextInput::NoEcho) {
1422 int cix = qRound(currentLine.cursorToX(m_cursor + preeditLength));
1423 if (cix - hscroll >= width) {
1424 // text doesn't fit, cursor is to the right of br (scroll right)
1425 hscroll = cix - width;
1426 } else if (cix - hscroll < 0 && hscroll < widthUsed) {
1427 // text doesn't fit, cursor is to the left of br (scroll left)
1429 } else if (widthUsed - hscroll < width) {
1430 // text doesn't fit, text document is to the left of br; align
1432 hscroll = widthUsed - width;
1434 if (preeditLength > 0) {
1435 // check to ensure long pre-edit text doesn't push the cursor
1437 cix = qRound(currentLine.cursorToX(m_cursor + qMax(0, m_preeditCursor - 1)));
1442 if (previousScroll != hscroll)
1443 textLayoutDirty = true;
1446 void QQuickTextInputPrivate::updateVerticalScroll()
1448 Q_Q(QQuickTextInput);
1449 const int preeditLength = m_textLayout.preeditAreaText().length();
1450 const int height = q->height();
1451 int heightUsed = boundingRect.height();
1452 int previousScroll = vscroll;
1454 if (!autoScroll || heightUsed <= height) {
1455 // text fits in br; use vscroll for alignment
1456 switch (vAlign & ~(Qt::AlignAbsolute|Qt::AlignHorizontal_Mask)) {
1457 case Qt::AlignBottom:
1458 vscroll = heightUsed - height;
1460 case Qt::AlignVCenter:
1461 vscroll = (heightUsed - height) / 2;
1469 QRectF r = m_textLayout.lineForTextPosition(m_cursor + preeditLength).rect();
1470 int top = qFloor(r.top());
1471 int bottom = qCeil(r.bottom());
1473 if (bottom - vscroll >= height) {
1474 // text doesn't fit, cursor is to the below the br (scroll down)
1475 vscroll = bottom - height;
1476 } else if (top - vscroll < 0 && vscroll < heightUsed) {
1477 // text doesn't fit, cursor is above br (scroll up)
1479 } else if (heightUsed - vscroll < height) {
1480 // text doesn't fit, text document is to the left of br; align
1482 vscroll = heightUsed - height;
1484 if (preeditLength > 0) {
1485 // check to ensure long pre-edit text doesn't push the cursor
1487 top = qRound(m_textLayout.lineForTextPosition(
1488 m_cursor + qMax(0, m_preeditCursor - 1)).rect().top());
1493 if (previousScroll != vscroll)
1494 textLayoutDirty = true;
1497 QSGNode *QQuickTextInput::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data)
1500 Q_D(QQuickTextInput);
1502 QQuickTextNode *node = static_cast<QQuickTextNode *>(oldNode);
1504 node = new QQuickTextNode(QQuickItemPrivate::get(this)->sceneGraphContext());
1507 if (!d->textLayoutDirty) {
1508 QSGSimpleRectNode *cursorNode = node->cursorNode();
1509 if (cursorNode != 0 && !isReadOnly()) {
1510 cursorNode->setRect(cursorRectangle());
1512 if (!d->cursorVisible || (!d->m_blinkStatus && d->m_blinkPeriod > 0)) {
1519 node->deleteContent();
1520 node->setMatrix(QMatrix4x4());
1522 QPoint offset = QPoint(0,0);
1523 QFontMetrics fm = QFontMetrics(d->font);
1524 if (d->autoScroll) {
1525 // the y offset is there to keep the baseline constant in case we have script changes in the text.
1526 offset = -QPoint(d->hscroll, d->vscroll + d->m_ascent - fm.ascent());
1528 offset = -QPoint(d->hscroll, d->vscroll);
1531 if (!d->m_textLayout.text().isEmpty()) {
1532 node->addTextLayout(offset, &d->m_textLayout, d->color,
1533 QQuickText::Normal, QColor(),
1534 d->selectionColor, d->selectedTextColor,
1535 d->selectionStart(),
1536 d->selectionEnd() - 1); // selectionEnd() returns first char after
1540 if (!isReadOnly() && d->cursorItem == 0) {
1541 node->setCursor(cursorRectangle(), d->color);
1542 if (!d->cursorVisible || (!d->m_blinkStatus && d->m_blinkPeriod > 0)) {
1549 d->textLayoutDirty = false;
1555 QVariant QQuickTextInput::inputMethodQuery(Qt::InputMethodQuery property) const
1557 Q_D(const QQuickTextInput);
1560 return QVariant((bool)(flags() & ItemAcceptsInputMethod));
1562 return QVariant((int)inputMethodHints());
1563 case Qt::ImCursorRectangle:
1564 return cursorRectangle();
1567 case Qt::ImCursorPosition:
1568 return QVariant(d->m_cursor);
1569 case Qt::ImSurroundingText:
1570 if (d->m_echoMode == PasswordEchoOnEdit && !d->m_passwordEchoEditing) {
1571 return QVariant(displayText());
1573 return QVariant(d->realText());
1575 case Qt::ImCurrentSelection:
1576 return QVariant(selectedText());
1577 case Qt::ImMaximumTextLength:
1578 return QVariant(maxLength());
1579 case Qt::ImAnchorPosition:
1580 if (d->selectionStart() == d->selectionEnd())
1581 return QVariant(d->m_cursor);
1582 else if (d->selectionStart() == d->m_cursor)
1583 return QVariant(d->selectionEnd());
1585 return QVariant(d->selectionStart());
1592 \qmlmethod void QtQuick2::TextInput::deselect()
1594 Removes active text selection.
1596 void QQuickTextInput::deselect()
1598 Q_D(QQuickTextInput);
1603 \qmlmethod void QtQuick2::TextInput::selectAll()
1605 Causes all text to be selected.
1607 void QQuickTextInput::selectAll()
1609 Q_D(QQuickTextInput);
1610 d->setSelection(0, text().length());
1614 \qmlmethod void QtQuick2::TextInput::isRightToLeft(int start, int end)
1616 Returns true if the natural reading direction of the editor text
1617 found between positions \a start and \a end is right to left.
1619 bool QQuickTextInput::isRightToLeft(int start, int end)
1622 qmlInfo(this) << "isRightToLeft(start, end) called with the end property being smaller than the start.";
1625 return text().mid(start, end - start).isRightToLeft();
1629 #ifndef QT_NO_CLIPBOARD
1631 \qmlmethod QtQuick2::TextInput::cut()
1633 Moves the currently selected text to the system clipboard.
1635 void QQuickTextInput::cut()
1637 Q_D(QQuickTextInput);
1643 \qmlmethod QtQuick2::TextInput::copy()
1645 Copies the currently selected text to the system clipboard.
1647 void QQuickTextInput::copy()
1649 Q_D(QQuickTextInput);
1654 \qmlmethod QtQuick2::TextInput::paste()
1656 Replaces the currently selected text by the contents of the system clipboard.
1658 void QQuickTextInput::paste()
1660 Q_D(QQuickTextInput);
1664 #endif // QT_NO_CLIPBOARD
1667 \qmlmethod void QtQuick2::TextInput::selectWord()
1669 Causes the word closest to the current cursor position to be selected.
1671 void QQuickTextInput::selectWord()
1673 Q_D(QQuickTextInput);
1674 d->selectWordAtPos(d->m_cursor);
1678 \qmlproperty bool QtQuick2::TextInput::smooth
1680 This property holds whether the text is smoothly scaled or transformed.
1682 Smooth filtering gives better visual quality, but is slower. If
1683 the item is displayed at its natural size, this property has no visual or
1686 \note Generally scaling artifacts are only visible if the item is stationary on
1687 the screen. A common pattern when animating an item is to disable smooth
1688 filtering at the beginning of the animation and reenable it at the conclusion.
1692 \qmlproperty string QtQuick2::TextInput::passwordCharacter
1694 This is the character displayed when echoMode is set to Password or
1695 PasswordEchoOnEdit. By default it is an asterisk.
1697 If this property is set to a string with more than one character,
1698 the first character is used. If the string is empty, the value
1699 is ignored and the property is not set.
1701 QString QQuickTextInput::passwordCharacter() const
1703 Q_D(const QQuickTextInput);
1704 return QString(d->m_passwordCharacter);
1707 void QQuickTextInput::setPasswordCharacter(const QString &str)
1709 Q_D(QQuickTextInput);
1710 if (str.length() < 1)
1712 d->m_passwordCharacter = str.constData()[0];
1713 if (d->m_echoMode == Password || d->m_echoMode == PasswordEchoOnEdit)
1714 d->updateDisplayText();
1715 emit passwordCharacterChanged();
1719 \qmlproperty string QtQuick2::TextInput::displayText
1721 This is the text displayed in the TextInput.
1723 If \l echoMode is set to TextInput::Normal, this holds the
1724 same value as the TextInput::text property. Otherwise,
1725 this property holds the text visible to the user, while
1726 the \l text property holds the actual entered text.
1728 QString QQuickTextInput::displayText() const
1730 Q_D(const QQuickTextInput);
1731 return d->m_textLayout.text();
1735 \qmlproperty bool QtQuick2::TextInput::selectByMouse
1739 If true, the user can use the mouse to select text in some
1740 platform-specific way. Note that for some platforms this may
1741 not be an appropriate interaction (eg. may conflict with how
1742 the text needs to behave inside a Flickable.
1744 bool QQuickTextInput::selectByMouse() const
1746 Q_D(const QQuickTextInput);
1747 return d->selectByMouse;
1750 void QQuickTextInput::setSelectByMouse(bool on)
1752 Q_D(QQuickTextInput);
1753 if (d->selectByMouse != on) {
1754 d->selectByMouse = on;
1755 emit selectByMouseChanged(on);
1760 \qmlproperty enum QtQuick2::TextInput::mouseSelectionMode
1762 Specifies how text should be selected using a mouse.
1765 \o TextInput.SelectCharacters - The selection is updated with individual characters. (Default)
1766 \o TextInput.SelectWords - The selection is updated with whole words.
1769 This property only applies when \l selectByMouse is true.
1772 QQuickTextInput::SelectionMode QQuickTextInput::mouseSelectionMode() const
1774 Q_D(const QQuickTextInput);
1775 return d->mouseSelectionMode;
1778 void QQuickTextInput::setMouseSelectionMode(SelectionMode mode)
1780 Q_D(QQuickTextInput);
1781 if (d->mouseSelectionMode != mode) {
1782 d->mouseSelectionMode = mode;
1783 emit mouseSelectionModeChanged(mode);
1788 \qmlproperty bool QtQuick2::TextInput::canPaste
1790 Returns true if the TextInput is writable and the content of the clipboard is
1791 suitable for pasting into the TextEdit.
1793 bool QQuickTextInput::canPaste() const
1795 Q_D(const QQuickTextInput);
1796 if (!d->canPasteValid) {
1797 if (const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData())
1798 const_cast<QQuickTextInputPrivate *>(d)->canPaste = !d->m_readOnly && mimeData->hasText();
1799 const_cast<QQuickTextInputPrivate *>(d)->canPasteValid = true;
1804 void QQuickTextInput::moveCursorSelection(int position)
1806 Q_D(QQuickTextInput);
1807 d->moveCursor(position, true);
1811 \qmlmethod void QtQuick2::TextInput::moveCursorSelection(int position, SelectionMode mode = TextInput.SelectCharacters)
1813 Moves the cursor to \a position and updates the selection according to the optional \a mode
1814 parameter. (To only move the cursor, set the \l cursorPosition property.)
1816 When this method is called it additionally sets either the
1817 selectionStart or the selectionEnd (whichever was at the previous cursor position)
1818 to the specified position. This allows you to easily extend and contract the selected
1821 The selection mode specifies whether the selection is updated on a per character or a per word
1822 basis. If not specified the selection mode will default to TextInput.SelectCharacters.
1825 \o TextEdit.SelectCharacters - Sets either the selectionStart or selectionEnd (whichever was at
1826 the previous cursor position) to the specified position.
1827 \o TextEdit.SelectWords - Sets the selectionStart and selectionEnd to include all
1828 words between the specified position and the previous cursor position. Words partially in the
1832 For example, take this sequence of calls:
1836 moveCursorSelection(9, TextInput.SelectCharacters)
1837 moveCursorSelection(7, TextInput.SelectCharacters)
1840 This moves the cursor to position 5, extend the selection end from 5 to 9
1841 and then retract the selection end from 9 to 7, leaving the text from position 5 to 7
1842 selected (the 6th and 7th characters).
1844 The same sequence with TextInput.SelectWords will extend the selection start to a word boundary
1845 before or on position 5 and extend the selection end to a word boundary on or past position 9.
1847 void QQuickTextInput::moveCursorSelection(int pos, SelectionMode mode)
1849 Q_D(QQuickTextInput);
1851 if (mode == SelectCharacters) {
1852 d->moveCursor(pos, true);
1853 } else if (pos != d->m_cursor){
1854 const int cursor = d->m_cursor;
1856 if (!d->hasSelectedText())
1857 anchor = d->m_cursor;
1858 else if (d->selectionStart() == d->m_cursor)
1859 anchor = d->selectionEnd();
1861 anchor = d->selectionStart();
1863 if (anchor < pos || (anchor == pos && cursor < pos)) {
1864 const QString text = this->text();
1865 QTextBoundaryFinder finder(QTextBoundaryFinder::Word, text);
1866 finder.setPosition(anchor);
1868 const QTextBoundaryFinder::BoundaryReasons reasons = finder.boundaryReasons();
1869 if (anchor < text.length() && (!(reasons & QTextBoundaryFinder::StartWord)
1870 || ((reasons & QTextBoundaryFinder::EndWord) && anchor > cursor))) {
1871 finder.toPreviousBoundary();
1873 anchor = finder.position() != -1 ? finder.position() : 0;
1875 finder.setPosition(pos);
1876 if (pos > 0 && !finder.boundaryReasons())
1877 finder.toNextBoundary();
1878 const int cursor = finder.position() != -1 ? finder.position() : text.length();
1880 d->setSelection(anchor, cursor - anchor);
1881 } else if (anchor > pos || (anchor == pos && cursor > pos)) {
1882 const QString text = this->text();
1883 QTextBoundaryFinder finder(QTextBoundaryFinder::Word, text);
1884 finder.setPosition(anchor);
1886 const QTextBoundaryFinder::BoundaryReasons reasons = finder.boundaryReasons();
1887 if (anchor > 0 && (!(reasons & QTextBoundaryFinder::EndWord)
1888 || ((reasons & QTextBoundaryFinder::StartWord) && anchor < cursor))) {
1889 finder.toNextBoundary();
1892 anchor = finder.position() != -1 ? finder.position() : text.length();
1894 finder.setPosition(pos);
1895 if (pos < text.length() && !finder.boundaryReasons())
1896 finder.toPreviousBoundary();
1897 const int cursor = finder.position() != -1 ? finder.position() : 0;
1899 d->setSelection(anchor, cursor - anchor);
1905 \qmlmethod void QtQuick2::TextInput::openSoftwareInputPanel()
1907 Opens software input panels like virtual keyboards for typing, useful for
1908 customizing when you want the input keyboard to be shown and hidden in
1911 By default the opening of input panels follows the platform style. Input panels are
1912 always closed if no editor has active focus.
1914 You can disable the automatic behavior by setting the property \c activeFocusOnPress to false
1915 and use functions openSoftwareInputPanel() and closeSoftwareInputPanel() to implement
1916 the behavior you want.
1918 Only relevant on platforms, which provide virtual keyboards.
1924 text: "Hello world!"
1925 activeFocusOnPress: false
1927 anchors.fill: parent
1929 if (!textInput.activeFocus) {
1930 textInput.forceActiveFocus()
1931 textInput.openSoftwareInputPanel();
1933 textInput.focus = false;
1936 onPressAndHold: textInput.closeSoftwareInputPanel();
1941 void QQuickTextInput::openSoftwareInputPanel()
1944 qGuiApp->inputPanel()->show();
1948 \qmlmethod void QtQuick2::TextInput::closeSoftwareInputPanel()
1950 Closes a software input panel like a virtual keyboard shown on the screen, useful
1951 for customizing when you want the input keyboard to be shown and hidden in
1954 By default the opening of input panels follows the platform style. Input panels are
1955 always closed if no editor has active focus.
1957 You can disable the automatic behavior by setting the property \c activeFocusOnPress to false
1958 and use functions openSoftwareInputPanel() and closeSoftwareInputPanel() to implement
1959 the behavior you want.
1961 Only relevant on platforms, which provide virtual keyboards.
1967 text: "Hello world!"
1968 activeFocusOnPress: false
1970 anchors.fill: parent
1972 if (!textInput.activeFocus) {
1973 textInput.forceActiveFocus();
1974 textInput.openSoftwareInputPanel();
1976 textInput.focus = false;
1979 onPressAndHold: textInput.closeSoftwareInputPanel();
1984 void QQuickTextInput::closeSoftwareInputPanel()
1987 qGuiApp->inputPanel()->hide();
1990 void QQuickTextInput::focusInEvent(QFocusEvent *event)
1992 Q_D(const QQuickTextInput);
1993 if (d->focusOnPress && !d->m_readOnly)
1994 openSoftwareInputPanel();
1995 QQuickImplicitSizeItem::focusInEvent(event);
1998 void QQuickTextInput::itemChange(ItemChange change, const ItemChangeData &value)
2000 Q_D(QQuickTextInput);
2001 if (change == ItemActiveFocusHasChanged) {
2002 bool hasFocus = value.boolValue;
2003 d->focused = hasFocus;
2004 setCursorVisible(hasFocus); // ### refactor: && d->canvas && d->canvas->hasFocus()
2005 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
2006 if (!hasFocus && (d->m_passwordEchoEditing || d->m_passwordEchoTimer.isActive())) {
2008 if (!hasFocus && d->m_passwordEchoEditing) {
2010 d->updatePasswordEchoEditing(false);//QQuickTextInputPrivate sets it on key events, but doesn't deal with focus events
2018 QQuickItem::itemChange(change, value);
2022 \qmlproperty bool QtQuick2::TextInput::inputMethodComposing
2025 This property holds whether the TextInput has partial text input from an
2028 While it is composing an input method may rely on mouse or key events from
2029 the TextInput to edit or commit the partial text. This property can be
2030 used to determine when to disable events handlers that may interfere with
2031 the correct operation of an input method.
2033 bool QQuickTextInput::isInputMethodComposing() const
2035 Q_D(const QQuickTextInput);
2036 return d->preeditAreaText().length() > 0;
2039 void QQuickTextInputPrivate::init()
2041 Q_Q(QQuickTextInput);
2042 q->setSmooth(smooth);
2043 q->setAcceptedMouseButtons(Qt::LeftButton);
2044 q->setFlag(QQuickItem::ItemAcceptsInputMethod);
2045 q->setFlag(QQuickItem::ItemHasContents);
2046 #ifndef QT_NO_CLIPBOARD
2047 q->connect(QGuiApplication::clipboard(), SIGNAL(dataChanged()),
2048 q, SLOT(q_canPasteChanged()));
2049 #endif // QT_NO_CLIPBOARD
2051 oldValidity = hasAcceptableInput(m_text);
2052 lastSelectionStart = 0;
2053 lastSelectionEnd = 0;
2054 selectedTextColor = m_palette.color(QPalette::HighlightedText);
2055 selectionColor = m_palette.color(QPalette::Highlight);
2056 determineHorizontalAlignment();
2058 if (!qmlDisableDistanceField()) {
2059 QTextOption option = m_textLayout.textOption();
2060 option.setUseDesignMetrics(true);
2061 m_textLayout.setTextOption(option);
2065 void QQuickTextInput::updateCursorRectangle()
2067 Q_D(QQuickTextInput);
2068 if (!isComponentComplete())
2071 d->updateHorizontalScroll();
2072 d->updateVerticalScroll();
2075 emit cursorRectangleChanged();
2076 if (d->cursorItem) {
2077 QRectF r = cursorRectangle();
2078 d->cursorItem->setPos(r.topLeft());
2079 d->cursorItem->setHeight(r.height());
2083 void QQuickTextInput::selectionChanged()
2085 Q_D(QQuickTextInput);
2086 d->textLayoutDirty = true; //TODO: Only update rect in selection
2088 emit selectedTextChanged();
2090 if (d->lastSelectionStart != d->selectionStart()) {
2091 d->lastSelectionStart = d->selectionStart();
2092 if (d->lastSelectionStart == -1)
2093 d->lastSelectionStart = d->m_cursor;
2094 emit selectionStartChanged();
2096 if (d->lastSelectionEnd != d->selectionEnd()) {
2097 d->lastSelectionEnd = d->selectionEnd();
2098 if (d->lastSelectionEnd == -1)
2099 d->lastSelectionEnd = d->m_cursor;
2100 emit selectionEndChanged();
2104 void QQuickTextInputPrivate::showCursor()
2106 if (textNode != 0 && textNode->cursorNode() != 0)
2107 textNode->cursorNode()->setColor(color);
2110 void QQuickTextInputPrivate::hideCursor()
2112 if (textNode != 0 && textNode->cursorNode() != 0)
2113 textNode->cursorNode()->setColor(QColor(0, 0, 0, 0));
2116 QRectF QQuickTextInput::boundingRect() const
2118 Q_D(const QQuickTextInput);
2120 QRectF r = d->boundingRect;
2121 int cursorWidth = d->cursorItem ? d->cursorItem->width() : d->m_cursorWidth;
2123 // Could include font max left/right bearings to either side of rectangle.
2125 r.setRight(r.right() + cursorWidth);
2126 r.translate(-d->hscroll, -d->vscroll);
2130 void QQuickTextInput::q_canPasteChanged()
2132 Q_D(QQuickTextInput);
2133 bool old = d->canPaste;
2134 #ifndef QT_NO_CLIPBOARD
2135 if (const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData())
2136 d->canPaste = !d->m_readOnly && mimeData->hasText();
2138 d->canPaste = false;
2141 bool changed = d->canPaste != old || !d->canPasteValid;
2142 d->canPasteValid = true;
2144 emit canPasteChanged();
2148 // ### these should come from QStyleHints
2149 const int textCursorWidth = 1;
2150 const bool fullWidthSelection = true;
2155 Updates the display text based of the current edit text
2156 If the text has changed will emit displayTextChanged()
2158 void QQuickTextInputPrivate::updateDisplayText(bool forceUpdate)
2160 QString orig = m_textLayout.text();
2162 if (m_echoMode == QQuickTextInput::NoEcho)
2163 str = QString::fromLatin1("");
2167 if (m_echoMode == QQuickTextInput::Password) {
2168 str.fill(m_passwordCharacter);
2169 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
2170 if (m_passwordEchoTimer.isActive() && m_cursor > 0 && m_cursor <= m_text.length()) {
2171 int cursor = m_cursor - 1;
2172 QChar uc = m_text.at(cursor);
2174 if (cursor > 0 && uc.unicode() >= 0xdc00 && uc.unicode() < 0xe000) {
2175 // second half of a surrogate, check if we have the first half as well,
2176 // if yes restore both at once
2177 uc = m_text.at(cursor - 1);
2178 if (uc.unicode() >= 0xd800 && uc.unicode() < 0xdc00)
2179 str[cursor - 1] = uc;
2183 } else if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit && !m_passwordEchoEditing) {
2184 str.fill(m_passwordCharacter);
2187 // replace certain non-printable characters with spaces (to avoid
2188 // drawing boxes when using fonts that don't have glyphs for such
2190 QChar* uc = str.data();
2191 for (int i = 0; i < (int)str.length(); ++i) {
2192 if ((uc[i] < 0x20 && uc[i] != 0x09)
2193 || uc[i] == QChar::LineSeparator
2194 || uc[i] == QChar::ParagraphSeparator
2195 || uc[i] == QChar::ObjectReplacementCharacter)
2196 uc[i] = QChar(0x0020);
2199 if (str != orig || forceUpdate) {
2200 m_textLayout.setText(str);
2201 updateLayout(); // polish?
2202 emit q_func()->displayTextChanged();
2206 void QQuickTextInputPrivate::updateLayout()
2208 Q_Q(QQuickTextInput);
2210 if (!q->isComponentComplete())
2213 QTextOption option = m_textLayout.textOption();
2214 option.setTextDirection(m_layoutDirection);
2215 option.setFlags(QTextOption::IncludeTrailingSpaces);
2216 option.setWrapMode(QTextOption::WrapMode(wrapMode));
2217 option.setAlignment(Qt::Alignment(q->effectiveHAlign()));
2218 m_textLayout.setTextOption(option);
2219 m_textLayout.setFont(font);
2221 boundingRect = QRectF();
2222 m_textLayout.beginLayout();
2223 QTextLine line = m_textLayout.createLine();
2224 qreal lineWidth = q->widthValid() ? q->width() : INT_MAX;
2226 QTextLine firstLine = line;
2228 line.setLineWidth(lineWidth);
2229 line.setPosition(QPointF(line.position().x(), height));
2230 boundingRect = boundingRect.united(line.naturalTextRect());
2232 height += line.height();
2233 line = m_textLayout.createLine();
2234 } while (line.isValid());
2235 m_textLayout.endLayout();
2237 option.setWrapMode(QTextOption::NoWrap);
2238 m_textLayout.setTextOption(option);
2240 m_ascent = qRound(firstLine.ascent());
2241 textLayoutDirty = true;
2244 q->setImplicitSize(qCeil(boundingRect.width()), qCeil(boundingRect.height()));
2248 #ifndef QT_NO_CLIPBOARD
2252 Copies the currently selected text into the clipboard using the given
2255 \note If the echo mode is set to a mode other than Normal then copy
2256 will not work. This is to prevent using copy as a method of bypassing
2257 password features of the line control.
2259 void QQuickTextInputPrivate::copy(QClipboard::Mode mode) const
2261 QString t = selectedText();
2262 if (!t.isEmpty() && m_echoMode == QQuickTextInput::Normal) {
2263 QGuiApplication::clipboard()->setText(t, mode);
2270 Inserts the text stored in the application clipboard into the line
2275 void QQuickTextInputPrivate::paste(QClipboard::Mode clipboardMode)
2277 QString clip = QGuiApplication::clipboard()->text(clipboardMode);
2278 if (!clip.isEmpty() || hasSelectedText()) {
2279 separate(); //make it a separate undo/redo command
2285 #endif // !QT_NO_CLIPBOARD
2290 Exits preedit mode and commits parts marked as tentative commit
2292 void QQuickTextInputPrivate::commitPreedit()
2297 qApp->inputPanel()->reset();
2299 if (!m_tentativeCommit.isEmpty()) {
2300 internalInsert(m_tentativeCommit);
2301 m_tentativeCommit.clear();
2302 finishChange(-1, true/*not used, not documented*/, false);
2305 m_preeditCursor = 0;
2306 m_textLayout.setPreeditArea(-1, QString());
2307 m_textLayout.clearAdditionalFormats();
2314 Handles the behavior for the backspace key or function.
2315 Removes the current selection if there is a selection, otherwise
2316 removes the character prior to the cursor position.
2320 void QQuickTextInputPrivate::backspace()
2322 int priorState = m_undoState;
2323 if (hasSelectedText()) {
2324 removeSelectedText();
2325 } else if (m_cursor) {
2328 m_cursor = prevMaskBlank(m_cursor);
2329 QChar uc = m_text.at(m_cursor);
2330 if (m_cursor > 0 && uc.unicode() >= 0xdc00 && uc.unicode() < 0xe000) {
2331 // second half of a surrogate, check if we have the first half as well,
2332 // if yes delete both at once
2333 uc = m_text.at(m_cursor - 1);
2334 if (uc.unicode() >= 0xd800 && uc.unicode() < 0xdc00) {
2335 internalDelete(true);
2339 internalDelete(true);
2341 finishChange(priorState);
2347 Handles the behavior for the delete key or function.
2348 Removes the current selection if there is a selection, otherwise
2349 removes the character after the cursor position.
2353 void QQuickTextInputPrivate::del()
2355 int priorState = m_undoState;
2356 if (hasSelectedText()) {
2357 removeSelectedText();
2359 int n = m_textLayout.nextCursorPosition(m_cursor) - m_cursor;
2363 finishChange(priorState);
2369 Inserts the given \a newText at the current cursor position.
2370 If there is any selected text it is removed prior to insertion of
2373 void QQuickTextInputPrivate::insert(const QString &newText)
2375 int priorState = m_undoState;
2376 removeSelectedText();
2377 internalInsert(newText);
2378 finishChange(priorState);
2384 Clears the line control text.
2386 void QQuickTextInputPrivate::clear()
2388 int priorState = m_undoState;
2390 m_selend = m_text.length();
2391 removeSelectedText();
2393 finishChange(priorState, /*update*/false, /*edited*/false);
2399 Sets \a length characters from the given \a start position as selected.
2400 The given \a start position must be within the current text for
2401 the line control. If \a length characters cannot be selected, then
2402 the selection will extend to the end of the current text.
2404 void QQuickTextInputPrivate::setSelection(int start, int length)
2406 Q_Q(QQuickTextInput);
2409 if (start < 0 || start > (int)m_text.length()){
2410 qWarning("QQuickTextInputPrivate::setSelection: Invalid start position");
2415 if (start == m_selstart && start + length == m_selend && m_cursor == m_selend)
2418 m_selend = qMin(start + length, (int)m_text.length());
2419 m_cursor = m_selend;
2420 } else if (length < 0){
2421 if (start == m_selend && start + length == m_selstart && m_cursor == m_selstart)
2423 m_selstart = qMax(start + length, 0);
2425 m_cursor = m_selstart;
2426 } else if (m_selstart != m_selend) {
2432 emitCursorPositionChanged();
2435 emit q->selectionChanged();
2436 emitCursorPositionChanged();
2442 Initializes the line control with a starting text value of \a txt.
2444 void QQuickTextInputPrivate::init(const QString &txt)
2448 updateDisplayText();
2449 m_cursor = m_text.length();
2455 Sets the password echo editing to \a editing. If password echo editing
2456 is true, then the text of the password is displayed even if the echo
2457 mode is set to QLineEdit::PasswordEchoOnEdit. Password echoing editing
2458 does not affect other echo modes.
2460 void QQuickTextInputPrivate::updatePasswordEchoEditing(bool editing)
2462 cancelPasswordEchoTimer();
2463 m_passwordEchoEditing = editing;
2464 updateDisplayText();
2470 Fixes the current text so that it is valid given any set validators.
2472 Returns true if the text was changed. Otherwise returns false.
2474 bool QQuickTextInputPrivate::fixup() // this function assumes that validate currently returns != Acceptable
2476 #ifndef QT_NO_VALIDATOR
2478 QString textCopy = m_text;
2479 int cursorCopy = m_cursor;
2480 m_validator->fixup(textCopy);
2481 if (m_validator->validate(textCopy, cursorCopy) == QValidator::Acceptable) {
2482 if (textCopy != m_text || cursorCopy != m_cursor)
2483 internalSetText(textCopy, cursorCopy);
2494 Moves the cursor to the given position \a pos. If \a mark is true will
2495 adjust the currently selected text.
2497 void QQuickTextInputPrivate::moveCursor(int pos, bool mark)
2499 Q_Q(QQuickTextInput);
2502 if (pos != m_cursor) {
2505 pos = pos > m_cursor ? nextMaskBlank(pos) : prevMaskBlank(pos);
2509 if (m_selend > m_selstart && m_cursor == m_selstart)
2511 else if (m_selend > m_selstart && m_cursor == m_selend)
2512 anchor = m_selstart;
2515 m_selstart = qMin(anchor, pos);
2516 m_selend = qMax(anchor, pos);
2521 if (mark || m_selDirty) {
2523 emit q->selectionChanged();
2525 emitCursorPositionChanged();
2531 Applies the given input method event \a event to the text of the line
2534 void QQuickTextInputPrivate::processInputMethodEvent(QInputMethodEvent *event)
2536 Q_Q(QQuickTextInput);
2538 int priorState = -1;
2539 bool isGettingInput = !event->commitString().isEmpty()
2540 || event->preeditString() != preeditAreaText()
2541 || event->replacementLength() > 0;
2542 bool cursorPositionChanged = false;
2543 bool selectionChange = false;
2544 m_preeditDirty = event->preeditString() != preeditAreaText();
2546 if (isGettingInput) {
2547 // If any text is being input, remove selected text.
2548 priorState = m_undoState;
2549 if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit && !m_passwordEchoEditing) {
2550 updatePasswordEchoEditing(true);
2552 m_selend = m_text.length();
2554 removeSelectedText();
2557 int c = m_cursor; // cursor position after insertion of commit string
2558 if (event->replacementStart() <= 0)
2559 c += event->commitString().length() - qMin(-event->replacementStart(), event->replacementLength());
2561 m_cursor += event->replacementStart();
2565 // insert commit string
2566 if (event->replacementLength()) {
2567 m_selstart = m_cursor;
2568 m_selend = m_selstart + event->replacementLength();
2569 m_selend = qMin(m_selend, m_text.length());
2570 removeSelectedText();
2572 if (!event->commitString().isEmpty()) {
2573 internalInsert(event->commitString());
2574 cursorPositionChanged = true;
2577 m_cursor = qBound(0, c, m_text.length());
2579 for (int i = 0; i < event->attributes().size(); ++i) {
2580 const QInputMethodEvent::Attribute &a = event->attributes().at(i);
2581 if (a.type == QInputMethodEvent::Selection) {
2582 m_cursor = qBound(0, a.start + a.length, m_text.length());
2584 m_selstart = qMax(0, qMin(a.start, m_text.length()));
2585 m_selend = m_cursor;
2586 if (m_selend < m_selstart) {
2587 qSwap(m_selstart, m_selend);
2589 selectionChange = true;
2591 m_selstart = m_selend = 0;
2593 cursorPositionChanged = true;
2597 m_textLayout.setPreeditArea(m_cursor, event->preeditString());
2599 const int oldPreeditCursor = m_preeditCursor;
2600 m_preeditCursor = event->preeditString().length();
2601 m_hideCursor = false;
2602 QList<QTextLayout::FormatRange> formats;
2603 for (int i = 0; i < event->attributes().size(); ++i) {
2604 const QInputMethodEvent::Attribute &a = event->attributes().at(i);
2605 if (a.type == QInputMethodEvent::Cursor) {
2606 m_preeditCursor = a.start;
2607 m_hideCursor = !a.length;
2608 } else if (a.type == QInputMethodEvent::TextFormat) {
2609 QTextCharFormat f = qvariant_cast<QTextFormat>(a.value).toCharFormat();
2611 QTextLayout::FormatRange o;
2612 o.start = a.start + m_cursor;
2613 o.length = a.length;
2619 m_textLayout.setAdditionalFormats(formats);
2621 updateDisplayText(/*force*/ true);
2622 if (cursorPositionChanged)
2623 emitCursorPositionChanged();
2624 else if (m_preeditCursor != oldPreeditCursor)
2625 q->updateCursorRectangle();
2627 bool tentativeCommitChanged = m_tentativeCommit != event->tentativeCommitString();
2629 if (tentativeCommitChanged) {
2631 m_tentativeCommit = event->tentativeCommitString();
2634 if (isGettingInput || tentativeCommitChanged)
2635 finishChange(priorState);
2637 if (selectionChange)
2638 emit q->selectionChanged();
2644 Sets the selection to cover the word at the given cursor position.
2645 The word boundaries are defined by the behavior of QTextLayout::SkipWords
2648 void QQuickTextInputPrivate::selectWordAtPos(int cursor)
2650 int next = cursor + 1;
2653 int c = m_textLayout.previousCursorPosition(next, QTextLayout::SkipWords);
2654 moveCursor(c, false);
2655 // ## text layout should support end of words.
2656 int end = m_textLayout.nextCursorPosition(c, QTextLayout::SkipWords);
2657 while (end > cursor && m_text[end-1].isSpace())
2659 moveCursor(end, true);
2665 Completes a change to the line control text. If the change is not valid
2666 will undo the line control state back to the given \a validateFromState.
2668 If \a edited is true and the change is valid, will emit textEdited() in
2669 addition to textChanged(). Otherwise only emits textChanged() on a valid
2672 The \a update value is currently unused.
2674 bool QQuickTextInputPrivate::finishChange(int validateFromState, bool update, bool /*edited*/)
2676 Q_Q(QQuickTextInput);
2682 bool wasValidInput = m_validInput;
2683 m_validInput = true;
2684 #ifndef QT_NO_VALIDATOR
2686 QString textCopy = m_text;
2687 int cursorCopy = m_cursor;
2688 m_validInput = (m_validator->validate(textCopy, cursorCopy) != QValidator::Invalid);
2690 if (m_text != textCopy) {
2691 internalSetText(textCopy, cursorCopy);
2694 m_cursor = cursorCopy;
2696 if (!m_tentativeCommit.isEmpty()) {
2697 textCopy.insert(m_cursor, m_tentativeCommit);
2698 bool validInput = m_validator->validate(textCopy, cursorCopy) != QValidator::Invalid;
2700 m_tentativeCommit.clear();
2703 m_tentativeCommit.clear();
2707 if (validateFromState >= 0 && wasValidInput && !m_validInput) {
2708 if (m_transactions.count())
2710 internalUndo(validateFromState);
2711 m_history.resize(m_undoState);
2712 if (m_modifiedState > m_undoState)
2713 m_modifiedState = -1;
2714 m_validInput = true;
2715 m_textDirty = false;
2717 updateDisplayText();
2720 m_textDirty = false;
2721 m_preeditDirty = false;
2722 determineHorizontalAlignment();
2723 emit q->textChanged();
2726 if (m_validInput != wasValidInput)
2727 emit q->acceptableInputChanged();
2729 if (m_preeditDirty) {
2730 m_preeditDirty = false;
2731 determineHorizontalAlignment();
2735 emit q->selectionChanged();
2737 emitCursorPositionChanged();
2744 An internal function for setting the text of the line control.
2746 void QQuickTextInputPrivate::internalSetText(const QString &txt, int pos, bool edited)
2748 Q_Q(QQuickTextInput);
2750 QString oldText = m_text;
2752 m_text = maskString(0, txt, true);
2753 m_text += clearString(m_text.length(), m_maxLength - m_text.length());
2755 m_text = txt.isEmpty() ? txt : txt.left(m_maxLength);
2758 m_modifiedState = m_undoState = 0;
2759 m_cursor = (pos < 0 || pos > m_text.length()) ? m_text.length() : pos;
2760 m_textDirty = (oldText != m_text);
2762 bool changed = finishChange(-1, true, edited);
2763 #ifdef QT_NO_ACCESSIBILITY
2767 QAccessible::updateAccessibility(q, 0, QAccessible::TextUpdated);
2775 Adds the given \a command to the undo history
2776 of the line control. Does not apply the command.
2778 void QQuickTextInputPrivate::addCommand(const Command &cmd)
2780 if (m_separator && m_undoState && m_history[m_undoState - 1].type != Separator) {
2781 m_history.resize(m_undoState + 2);
2782 m_history[m_undoState++] = Command(Separator, m_cursor, 0, m_selstart, m_selend);
2784 m_history.resize(m_undoState + 1);
2786 m_separator = false;
2787 m_history[m_undoState++] = cmd;
2793 Inserts the given string \a s into the line
2796 Also adds the appropriate commands into the undo history.
2797 This function does not call finishChange(), and may leave the text
2798 in an invalid state.
2800 void QQuickTextInputPrivate::internalInsert(const QString &s)
2802 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
2803 Q_Q(QQuickTextInput);
2804 if (m_echoMode == QQuickTextInput::Password)
2805 m_passwordEchoTimer.start(qt_passwordEchoDelay, q);
2807 if (hasSelectedText())
2808 addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
2810 QString ms = maskString(m_cursor, s);
2811 for (int i = 0; i < (int) ms.length(); ++i) {
2812 addCommand (Command(DeleteSelection, m_cursor + i, m_text.at(m_cursor + i), -1, -1));
2813 addCommand(Command(Insert, m_cursor + i, ms.at(i), -1, -1));
2815 m_text.replace(m_cursor, ms.length(), ms);
2816 m_cursor += ms.length();
2817 m_cursor = nextMaskBlank(m_cursor);
2820 int remaining = m_maxLength - m_text.length();
2821 if (remaining != 0) {
2822 m_text.insert(m_cursor, s.left(remaining));
2823 for (int i = 0; i < (int) s.left(remaining).length(); ++i)
2824 addCommand(Command(Insert, m_cursor++, s.at(i), -1, -1));
2833 deletes a single character from the current text. If \a wasBackspace,
2834 the character prior to the cursor is removed. Otherwise the character
2835 after the cursor is removed.
2837 Also adds the appropriate commands into the undo history.
2838 This function does not call finishChange(), and may leave the text
2839 in an invalid state.
2841 void QQuickTextInputPrivate::internalDelete(bool wasBackspace)
2843 if (m_cursor < (int) m_text.length()) {
2844 cancelPasswordEchoTimer();
2845 if (hasSelectedText())
2846 addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
2847 addCommand(Command((CommandType)((m_maskData ? 2 : 0) + (wasBackspace ? Remove : Delete)),
2848 m_cursor, m_text.at(m_cursor), -1, -1));
2850 m_text.replace(m_cursor, 1, clearString(m_cursor, 1));
2851 addCommand(Command(Insert, m_cursor, m_text.at(m_cursor), -1, -1));
2853 m_text.remove(m_cursor, 1);
2862 removes the currently selected text from the line control.
2864 Also adds the appropriate commands into the undo history.
2865 This function does not call finishChange(), and may leave the text
2866 in an invalid state.
2868 void QQuickTextInputPrivate::removeSelectedText()
2870 if (m_selstart < m_selend && m_selend <= (int) m_text.length()) {
2871 cancelPasswordEchoTimer();
2874 addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
2875 if (m_selstart <= m_cursor && m_cursor < m_selend) {
2876 // cursor is within the selection. Split up the commands
2877 // to be able to restore the correct cursor position
2878 for (i = m_cursor; i >= m_selstart; --i)
2879 addCommand (Command(DeleteSelection, i, m_text.at(i), -1, 1));
2880 for (i = m_selend - 1; i > m_cursor; --i)
2881 addCommand (Command(DeleteSelection, i - m_cursor + m_selstart - 1, m_text.at(i), -1, -1));
2883 for (i = m_selend-1; i >= m_selstart; --i)
2884 addCommand (Command(RemoveSelection, i, m_text.at(i), -1, -1));
2887 m_text.replace(m_selstart, m_selend - m_selstart, clearString(m_selstart, m_selend - m_selstart));
2888 for (int i = 0; i < m_selend - m_selstart; ++i)
2889 addCommand(Command(Insert, m_selstart + i, m_text.at(m_selstart + i), -1, -1));
2891 m_text.remove(m_selstart, m_selend - m_selstart);
2893 if (m_cursor > m_selstart)
2894 m_cursor -= qMin(m_cursor, m_selend) - m_selstart;
2903 Parses the input mask specified by \a maskFields to generate
2904 the mask data used to handle input masks.
2906 void QQuickTextInputPrivate::parseInputMask(const QString &maskFields)
2908 int delimiter = maskFields.indexOf(QLatin1Char(';'));
2909 if (maskFields.isEmpty() || delimiter == 0) {
2911 delete [] m_maskData;
2913 m_maxLength = 32767;
2914 internalSetText(QString());
2919 if (delimiter == -1) {
2920 m_blank = QLatin1Char(' ');
2921 m_inputMask = maskFields;
2923 m_inputMask = maskFields.left(delimiter);
2924 m_blank = (delimiter + 1 < maskFields.length()) ? maskFields[delimiter + 1] : QLatin1Char(' ');
2927 // calculate m_maxLength / m_maskData length
2930 for (int i=0; i<m_inputMask.length(); i++) {
2931 c = m_inputMask.at(i);
2932 if (i > 0 && m_inputMask.at(i-1) == QLatin1Char('\\')) {
2936 if (c != QLatin1Char('\\') && c != QLatin1Char('!') &&
2937 c != QLatin1Char('<') && c != QLatin1Char('>') &&
2938 c != QLatin1Char('{') && c != QLatin1Char('}') &&
2939 c != QLatin1Char('[') && c != QLatin1Char(']'))
2943 delete [] m_maskData;
2944 m_maskData = new MaskInputData[m_maxLength];
2946 MaskInputData::Casemode m = MaskInputData::NoCaseMode;
2949 bool escape = false;
2951 for (int i = 0; i < m_inputMask.length(); i++) {
2952 c = m_inputMask.at(i);
2955 m_maskData[index].maskChar = c;
2956 m_maskData[index].separator = s;
2957 m_maskData[index].caseMode = m;
2960 } else if (c == QLatin1Char('<')) {
2961 m = MaskInputData::Lower;
2962 } else if (c == QLatin1Char('>')) {
2963 m = MaskInputData::Upper;
2964 } else if (c == QLatin1Char('!')) {
2965 m = MaskInputData::NoCaseMode;
2966 } else if (c != QLatin1Char('{') && c != QLatin1Char('}') && c != QLatin1Char('[') && c != QLatin1Char(']')) {
2967 switch (c.unicode()) {
2993 m_maskData[index].maskChar = c;
2994 m_maskData[index].separator = s;
2995 m_maskData[index].caseMode = m;
3000 internalSetText(m_text);
3007 checks if the key is valid compared to the inputMask
3009 bool QQuickTextInputPrivate::isValidInput(QChar key, QChar mask) const
3011 switch (mask.unicode()) {
3017 if (key.isLetter() || key == m_blank)
3021 if (key.isLetterOrNumber())
3025 if (key.isLetterOrNumber() || key == m_blank)
3033 if (key.isPrint() || key == m_blank)
3041 if (key.isNumber() || key == m_blank)
3045 if (key.isNumber() && key.digitValue() > 0)
3049 if ((key.isNumber() && key.digitValue() > 0) || key == m_blank)
3053 if (key.isNumber() || key == QLatin1Char('+') || key == QLatin1Char('-') || key == m_blank)
3057 if (key == QLatin1Char('0') || key == QLatin1Char('1'))
3061 if (key == QLatin1Char('0') || key == QLatin1Char('1') || key == m_blank)
3065 if (key.isNumber() || (key >= QLatin1Char('a') && key <= QLatin1Char('f')) || (key >= QLatin1Char('A') && key <= QLatin1Char('F')))
3069 if (key.isNumber() || (key >= QLatin1Char('a') && key <= QLatin1Char('f')) || (key >= QLatin1Char('A') && key <= QLatin1Char('F')) || key == m_blank)
3081 Returns true if the given text \a str is valid for any
3082 validator or input mask set for the line control.
3084 Otherwise returns false
3086 bool QQuickTextInputPrivate::hasAcceptableInput(const QString &str) const
3088 #ifndef QT_NO_VALIDATOR
3089 QString textCopy = str;
3090 int cursorCopy = m_cursor;
3091 if (m_validator && m_validator->validate(textCopy, cursorCopy)
3092 != QValidator::Acceptable)
3099 if (str.length() != m_maxLength)
3102 for (int i=0; i < m_maxLength; ++i) {
3103 if (m_maskData[i].separator) {
3104 if (str.at(i) != m_maskData[i].maskChar)
3107 if (!isValidInput(str.at(i), m_maskData[i].maskChar))
3117 Applies the inputMask on \a str starting from position \a pos in the mask. \a clear
3118 specifies from where characters should be gotten when a separator is met in \a str - true means
3119 that blanks will be used, false that previous input is used.
3120 Calling this when no inputMask is set is undefined.
3122 QString QQuickTextInputPrivate::maskString(uint pos, const QString &str, bool clear) const
3124 if (pos >= (uint)m_maxLength)
3125 return QString::fromLatin1("");
3128 fill = clear ? clearString(0, m_maxLength) : m_text;
3131 QString s = QString::fromLatin1("");
3133 while (i < m_maxLength) {
3134 if (strIndex < str.length()) {
3135 if (m_maskData[i].separator) {
3136 s += m_maskData[i].maskChar;
3137 if (str[(int)strIndex] == m_maskData[i].maskChar)
3141 if (isValidInput(str[(int)strIndex], m_maskData[i].maskChar)) {
3142 switch (m_maskData[i].caseMode) {
3143 case MaskInputData::Upper:
3144 s += str[(int)strIndex].toUpper();
3146 case MaskInputData::Lower:
3147 s += str[(int)strIndex].toLower();
3150 s += str[(int)strIndex];
3154 // search for separator first
3155 int n = findInMask(i, true, true, str[(int)strIndex]);
3157 if (str.length() != 1 || i == 0 || (i > 0 && (!m_maskData[i-1].separator || m_maskData[i-1].maskChar != str[(int)strIndex]))) {
3158 s += fill.mid(i, n-i+1);
3159 i = n + 1; // update i to find + 1
3162 // search for valid m_blank if not
3163 n = findInMask(i, true, false, str[(int)strIndex]);
3165 s += fill.mid(i, n-i);
3166 switch (m_maskData[n].caseMode) {
3167 case MaskInputData::Upper:
3168 s += str[(int)strIndex].toUpper();
3170 case MaskInputData::Lower:
3171 s += str[(int)strIndex].toLower();
3174 s += str[(int)strIndex];
3176 i = n + 1; // updates i to find + 1
3194 Returns a "cleared" string with only separators and blank chars.
3195 Calling this when no inputMask is set is undefined.
3197 QString QQuickTextInputPrivate::clearString(uint pos, uint len) const
3199 if (pos >= (uint)m_maxLength)
3203 int end = qMin((uint)m_maxLength, pos + len);
3204 for (int i = pos; i < end; ++i)
3205 if (m_maskData[i].separator)
3206 s += m_maskData[i].maskChar;
3216 Strips blank parts of the input in a QQuickTextInputPrivate when an inputMask is set,
3217 separators are still included. Typically "127.0__.0__.1__" becomes "127.0.0.1".
3219 QString QQuickTextInputPrivate::stripString(const QString &str) const
3225 int end = qMin(m_maxLength, (int)str.length());
3226 for (int i = 0; i < end; ++i)
3227 if (m_maskData[i].separator)
3228 s += m_maskData[i].maskChar;
3230 if (str[i] != m_blank)
3238 searches forward/backward in m_maskData for either a separator or a m_blank
3240 int QQuickTextInputPrivate::findInMask(int pos, bool forward, bool findSeparator, QChar searchChar) const
3242 if (pos >= m_maxLength || pos < 0)
3245 int end = forward ? m_maxLength : -1;
3246 int step = forward ? 1 : -1;
3250 if (findSeparator) {
3251 if (m_maskData[i].separator && m_maskData[i].maskChar == searchChar)
3254 if (!m_maskData[i].separator) {
3255 if (searchChar.isNull())
3257 else if (isValidInput(searchChar, m_maskData[i].maskChar))
3266 void QQuickTextInputPrivate::internalUndo(int until)
3268 if (!isUndoAvailable())
3270 cancelPasswordEchoTimer();
3272 while (m_undoState && m_undoState > until) {
3273 Command& cmd = m_history[--m_undoState];
3276 m_text.remove(cmd.pos, 1);
3280 m_selstart = cmd.selStart;
3281 m_selend = cmd.selEnd;
3285 case RemoveSelection:
3286 m_text.insert(cmd.pos, cmd.uc);
3287 m_cursor = cmd.pos + 1;
3290 case DeleteSelection:
3291 m_text.insert(cmd.pos, cmd.uc);
3297 if (until < 0 && m_undoState) {
3298 Command& next = m_history[m_undoState-1];
3299 if (next.type != cmd.type && next.type < RemoveSelection
3300 && (cmd.type < RemoveSelection || next.type == Separator))
3305 emitCursorPositionChanged();
3308 void QQuickTextInputPrivate::internalRedo()
3310 if (!isRedoAvailable())
3313 while (m_undoState < (int)m_history.size()) {
3314 Command& cmd = m_history[m_undoState++];
3317 m_text.insert(cmd.pos, cmd.uc);
3318 m_cursor = cmd.pos + 1;
3321 m_selstart = cmd.selStart;
3322 m_selend = cmd.selEnd;
3327 case RemoveSelection:
3328 case DeleteSelection:
3329 m_text.remove(cmd.pos, 1);
3330 m_selstart = cmd.selStart;
3331 m_selend = cmd.selEnd;
3335 m_selstart = cmd.selStart;
3336 m_selend = cmd.selEnd;
3340 if (m_undoState < (int)m_history.size()) {
3341 Command& next = m_history[m_undoState];
3342 if (next.type != cmd.type && cmd.type < RemoveSelection && next.type != Separator
3343 && (next.type < RemoveSelection || cmd.type == Separator))
3348 emitCursorPositionChanged();
3354 If the current cursor position differs from the last emitted cursor
3355 position, emits cursorPositionChanged().
3357 void QQuickTextInputPrivate::emitCursorPositionChanged()
3359 Q_Q(QQuickTextInput);
3360 if (m_cursor != m_lastCursorPos) {
3361 m_lastCursorPos = m_cursor;
3363 q->updateCursorRectangle();
3364 emit q->cursorPositionChanged();
3365 // XXX todo - not in 4.8?
3367 resetCursorBlinkTimer();
3370 if (!hasSelectedText()) {
3371 if (lastSelectionStart != m_cursor) {
3372 lastSelectionStart = m_cursor;
3373 emit q->selectionStartChanged();
3375 if (lastSelectionEnd != m_cursor) {
3376 lastSelectionEnd = m_cursor;
3377 emit q->selectionEndChanged();
3381 #ifndef QT_NO_ACCESSIBILITY
3382 QAccessible::updateAccessibility(q, 0, QAccessible::TextCaretMoved);
3388 void QQuickTextInputPrivate::setCursorBlinkPeriod(int msec)
3390 Q_Q(QQuickTextInput);
3391 if (msec == m_blinkPeriod)
3394 q->killTimer(m_blinkTimer);
3397 m_blinkTimer = q->startTimer(msec / 2);
3401 if (m_blinkStatus == 1)
3404 m_blinkPeriod = msec;
3407 void QQuickTextInputPrivate::resetCursorBlinkTimer()
3409 Q_Q(QQuickTextInput);
3410 if (m_blinkPeriod == 0 || m_blinkTimer == 0)
3412 q->killTimer(m_blinkTimer);
3413 m_blinkTimer = q->startTimer(m_blinkPeriod / 2);
3417 void QQuickTextInput::timerEvent(QTimerEvent *event)
3419 Q_D(QQuickTextInput);
3420 if (event->timerId() == d->m_blinkTimer) {
3421 d->m_blinkStatus = !d->m_blinkStatus;
3423 } else if (event->timerId() == d->m_deleteAllTimer) {
3424 killTimer(d->m_deleteAllTimer);
3425 d->m_deleteAllTimer = 0;
3427 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
3428 } else if (event->timerId() == d->m_passwordEchoTimer.timerId()) {
3429 d->m_passwordEchoTimer.stop();
3430 d->updateDisplayText();
3435 void QQuickTextInputPrivate::processKeyEvent(QKeyEvent* event)
3437 Q_Q(QQuickTextInput);
3438 bool inlineCompletionAccepted = false;
3440 if (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return) {
3441 if (hasAcceptableInput(m_text) || fixup()) {
3444 if (inlineCompletionAccepted)
3451 if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit
3452 && !m_passwordEchoEditing
3454 && !event->text().isEmpty()
3455 && !(event->modifiers() & Qt::ControlModifier)) {
3456 // Clear the edit and reset to normal echo mode while editing; the
3457 // echo mode switches back when the edit loses focus
3458 // ### resets current content. dubious code; you can
3459 // navigate with keys up, down, back, and select(?), but if you press
3460 // "left" or "right" it clears?
3461 updatePasswordEchoEditing(true);
3465 bool unknown = false;
3466 bool visual = cursorMoveStyle() == Qt::VisualMoveStyle;
3470 #ifndef QT_NO_SHORTCUT
3471 else if (event == QKeySequence::Undo) {
3475 else if (event == QKeySequence::Redo) {
3479 else if (event == QKeySequence::SelectAll) {
3482 #ifndef QT_NO_CLIPBOARD
3483 else if (event == QKeySequence::Copy) {
3486 else if (event == QKeySequence::Paste) {
3488 QClipboard::Mode mode = QClipboard::Clipboard;
3492 else if (event == QKeySequence::Cut) {
3498 else if (event == QKeySequence::DeleteEndOfLine) {
3500 setSelection(m_cursor, end());
3505 #endif //QT_NO_CLIPBOARD
3506 else if (event == QKeySequence::MoveToStartOfLine || event == QKeySequence::MoveToStartOfBlock) {
3509 else if (event == QKeySequence::MoveToEndOfLine || event == QKeySequence::MoveToEndOfBlock) {
3512 else if (event == QKeySequence::SelectStartOfLine || event == QKeySequence::SelectStartOfBlock) {
3515 else if (event == QKeySequence::SelectEndOfLine || event == QKeySequence::SelectEndOfBlock) {
3518 else if (event == QKeySequence::MoveToNextChar) {
3519 if (hasSelectedText()) {
3520 moveCursor(selectionEnd(), false);
3522 cursorForward(0, visual ? 1 : (layoutDirection() == Qt::LeftToRight ? 1 : -1));
3525 else if (event == QKeySequence::SelectNextChar) {
3526 cursorForward(1, visual ? 1 : (layoutDirection() == Qt::LeftToRight ? 1 : -1));
3528 else if (event == QKeySequence::MoveToPreviousChar) {
3529 if (hasSelectedText()) {
3530 moveCursor(selectionStart(), false);
3532 cursorForward(0, visual ? -1 : (layoutDirection() == Qt::LeftToRight ? -1 : 1));
3535 else if (event == QKeySequence::SelectPreviousChar) {
3536 cursorForward(1, visual ? -1 : (layoutDirection() == Qt::LeftToRight ? -1 : 1));
3538 else if (event == QKeySequence::MoveToNextWord) {
3539 if (m_echoMode == QQuickTextInput::Normal)
3540 layoutDirection() == Qt::LeftToRight ? cursorWordForward(0) : cursorWordBackward(0);
3542 layoutDirection() == Qt::LeftToRight ? end(0) : home(0);
3544 else if (event == QKeySequence::MoveToPreviousWord) {
3545 if (m_echoMode == QQuickTextInput::Normal)
3546 layoutDirection() == Qt::LeftToRight ? cursorWordBackward(0) : cursorWordForward(0);
3547 else if (!m_readOnly) {
3548 layoutDirection() == Qt::LeftToRight ? home(0) : end(0);
3551 else if (event == QKeySequence::SelectNextWord) {
3552 if (m_echoMode == QQuickTextInput::Normal)
3553 layoutDirection() == Qt::LeftToRight ? cursorWordForward(1) : cursorWordBackward(1);
3555 layoutDirection() == Qt::LeftToRight ? end(1) : home(1);
3557 else if (event == QKeySequence::SelectPreviousWord) {
3558 if (m_echoMode == QQuickTextInput::Normal)
3559 layoutDirection() == Qt::LeftToRight ? cursorWordBackward(1) : cursorWordForward(1);
3561 layoutDirection() == Qt::LeftToRight ? home(1) : end(1);
3563 else if (event == QKeySequence::Delete) {
3567 else if (event == QKeySequence::DeleteEndOfWord) {
3569 cursorWordForward(true);
3573 else if (event == QKeySequence::DeleteStartOfWord) {
3575 cursorWordBackward(true);
3579 #endif // QT_NO_SHORTCUT
3581 bool handled = false;
3582 if (event->modifiers() & Qt::ControlModifier) {
3583 switch (event->key()) {
3584 case Qt::Key_Backspace:
3586 cursorWordBackward(true);
3594 } else { // ### check for *no* modifier
3595 switch (event->key()) {
3596 case Qt::Key_Backspace:
3608 if (event->key() == Qt::Key_Direction_L || event->key() == Qt::Key_Direction_R) {
3609 setLayoutDirection((event->key() == Qt::Key_Direction_L) ? Qt::LeftToRight : Qt::RightToLeft);
3613 if (unknown && !m_readOnly) {
3614 QString t = event->text();
3615 if (!t.isEmpty() && t.at(0).isPrint()) {