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)
66 \qmlclass TextInput QQuickTextInput
67 \inqmlmodule QtQuick 2
68 \ingroup qml-basic-visual-elements
69 \brief The TextInput item displays an editable line of text.
72 The TextInput element displays a single line of editable plain text.
74 TextInput is used to accept a line of text input. Input constraints
75 can be placed on a TextInput item (for example, through a \l validator or \l inputMask),
76 and setting \l echoMode to an appropriate value enables TextInput to be used for
77 a password input field.
79 On Mac OS X, the Up/Down key bindings for Home/End are explicitly disabled.
80 If you want such bindings (on any platform), you will need to construct them in QML.
82 \sa TextEdit, Text, {declarative/text/textselection}{Text Selection example}
84 QQuickTextInput::QQuickTextInput(QQuickItem* parent)
85 : QQuickImplicitSizeItem(*(new QQuickTextInputPrivate), parent)
91 QQuickTextInput::~QQuickTextInput()
95 void QQuickTextInput::componentComplete()
99 QQuickImplicitSizeItem::componentComplete();
102 updateCursorRectangle();
103 if (d->cursorComponent && d->cursorComponent->isReady())
108 \qmlproperty string QtQuick2::TextInput::text
110 The text in the TextInput.
112 QString QQuickTextInput::text() const
114 Q_D(const QQuickTextInput);
116 QString content = d->m_text;
117 if (!d->m_tentativeCommit.isEmpty())
118 content.insert(d->m_cursor, d->m_tentativeCommit);
119 QString res = d->m_maskData ? d->stripString(content) : content;
120 return (res.isNull() ? QString::fromLatin1("") : res);
123 void QQuickTextInput::setText(const QString &s)
125 Q_D(QQuickTextInput);
128 if (d->composeMode())
129 qApp->inputPanel()->reset();
130 d->m_tentativeCommit.clear();
131 d->internalSetText(s, -1, false);
134 QString QQuickTextInputPrivate::realText() const
136 QString res = m_maskData ? stripString(m_text) : m_text;
137 return (res.isNull() ? QString::fromLatin1("") : res);
141 \qmlproperty string QtQuick2::TextInput::font.family
143 Sets the family name of the font.
145 The family name is case insensitive and may optionally include a foundry name, e.g. "Helvetica [Cronyx]".
146 If the family is available from more than one foundry and the foundry isn't specified, an arbitrary foundry is chosen.
147 If the family isn't available a family will be set using the font matching algorithm.
151 \qmlproperty bool QtQuick2::TextInput::font.bold
153 Sets whether the font weight is bold.
157 \qmlproperty enumeration QtQuick2::TextInput::font.weight
159 Sets the font's weight.
161 The weight can be one of:
164 \o Font.Normal - the default
171 TextInput { text: "Hello"; font.weight: Font.DemiBold }
176 \qmlproperty bool QtQuick2::TextInput::font.italic
178 Sets whether the font has an italic style.
182 \qmlproperty bool QtQuick2::TextInput::font.underline
184 Sets whether the text is underlined.
188 \qmlproperty bool QtQuick2::TextInput::font.strikeout
190 Sets whether the font has a strikeout style.
194 \qmlproperty real QtQuick2::TextInput::font.pointSize
196 Sets the font size in points. The point size must be greater than zero.
200 \qmlproperty int QtQuick2::TextInput::font.pixelSize
202 Sets the font size in pixels.
204 Using this function makes the font device dependent.
205 Use \c pointSize to set the size of the font in a device independent manner.
209 \qmlproperty real QtQuick2::TextInput::font.letterSpacing
211 Sets the letter spacing for the font.
213 Letter spacing changes the default spacing between individual letters in the font.
214 A positive value increases the letter spacing by the corresponding pixels; a negative value decreases the spacing.
218 \qmlproperty real QtQuick2::TextInput::font.wordSpacing
220 Sets the word spacing for the font.
222 Word spacing changes the default spacing between individual words.
223 A positive value increases the word spacing by a corresponding amount of pixels,
224 while a negative value decreases the inter-word spacing accordingly.
228 \qmlproperty enumeration QtQuick2::TextInput::font.capitalization
230 Sets the capitalization for the text.
233 \o Font.MixedCase - This is the normal text rendering option where no capitalization change is applied.
234 \o Font.AllUppercase - This alters the text to be rendered in all uppercase type.
235 \o Font.AllLowercase - This alters the text to be rendered in all lowercase type.
236 \o Font.SmallCaps - This alters the text to be rendered in small-caps type.
237 \o Font.Capitalize - This alters the text to be rendered with the first character of each word as an uppercase character.
241 TextInput { text: "Hello"; font.capitalization: Font.AllLowercase }
245 QFont QQuickTextInput::font() const
247 Q_D(const QQuickTextInput);
248 return d->sourceFont;
251 void QQuickTextInput::setFont(const QFont &font)
253 Q_D(QQuickTextInput);
254 if (d->sourceFont == font)
257 d->sourceFont = font;
258 QFont oldFont = d->font;
260 if (d->font.pointSizeF() != -1) {
262 qreal size = qRound(d->font.pointSizeF()*2.0);
263 d->font.setPointSizeF(size/2.0);
265 if (oldFont != d->font) {
267 updateCursorRectangle();
269 emit fontChanged(d->sourceFont);
273 \qmlproperty color QtQuick2::TextInput::color
277 QColor QQuickTextInput::color() const
279 Q_D(const QQuickTextInput);
283 void QQuickTextInput::setColor(const QColor &c)
285 Q_D(QQuickTextInput);
288 d->textLayoutDirty = true;
290 emit colorChanged(c);
296 \qmlproperty color QtQuick2::TextInput::selectionColor
298 The text highlight color, used behind selections.
300 QColor QQuickTextInput::selectionColor() const
302 Q_D(const QQuickTextInput);
303 return d->selectionColor;
306 void QQuickTextInput::setSelectionColor(const QColor &color)
308 Q_D(QQuickTextInput);
309 if (d->selectionColor == color)
312 d->selectionColor = color;
313 d->m_palette.setColor(QPalette::Highlight, d->selectionColor);
314 if (d->hasSelectedText()) {
315 d->textLayoutDirty = true;
318 emit selectionColorChanged(color);
321 \qmlproperty color QtQuick2::TextInput::selectedTextColor
323 The highlighted text color, used in selections.
325 QColor QQuickTextInput::selectedTextColor() const
327 Q_D(const QQuickTextInput);
328 return d->selectedTextColor;
331 void QQuickTextInput::setSelectedTextColor(const QColor &color)
333 Q_D(QQuickTextInput);
334 if (d->selectedTextColor == color)
337 d->selectedTextColor = color;
338 d->m_palette.setColor(QPalette::HighlightedText, d->selectedTextColor);
339 if (d->hasSelectedText()) {
340 d->textLayoutDirty = true;
343 emit selectedTextColorChanged(color);
347 \qmlproperty enumeration QtQuick2::TextInput::horizontalAlignment
348 \qmlproperty enumeration QtQuick2::TextInput::effectiveHorizontalAlignment
349 \qmlproperty enumeration QtQuick2::TextInput::verticalAlignment
351 Sets the horizontal alignment of the text within the TextInput item's
352 width and height. By default, the text alignment follows the natural alignment
353 of the text, for example text that is read from left to right will be aligned to
356 TextInput does not have vertical alignment, as the natural height is
357 exactly the height of the single line of text. If you set the height
358 manually to something larger, TextInput will always be top aligned
359 vertically. You can use anchors to align it however you want within
362 The valid values for \c horizontalAlignment are \c TextInput.AlignLeft, \c TextInput.AlignRight and
363 \c TextInput.AlignHCenter.
365 Valid values for \c verticalAlignment are \c TextEdit.AlignTop (default),
366 \c TextEdit.AlignBottom \c TextEdit.AlignVCenter.
368 When using the attached property LayoutMirroring::enabled to mirror application
369 layouts, the horizontal alignment of text will also be mirrored. However, the property
370 \c horizontalAlignment will remain unchanged. To query the effective horizontal alignment
371 of TextInput, use the read-only property \c effectiveHorizontalAlignment.
373 QQuickTextInput::HAlignment QQuickTextInput::hAlign() const
375 Q_D(const QQuickTextInput);
379 void QQuickTextInput::setHAlign(HAlignment align)
381 Q_D(QQuickTextInput);
382 bool forceAlign = d->hAlignImplicit && d->effectiveLayoutMirror;
383 d->hAlignImplicit = false;
384 if (d->setHAlign(align, forceAlign) && isComponentComplete()) {
386 updateCursorRectangle();
390 void QQuickTextInput::resetHAlign()
392 Q_D(QQuickTextInput);
393 d->hAlignImplicit = true;
394 if (d->determineHorizontalAlignment() && isComponentComplete()) {
396 updateCursorRectangle();
400 QQuickTextInput::HAlignment QQuickTextInput::effectiveHAlign() const
402 Q_D(const QQuickTextInput);
403 QQuickTextInput::HAlignment effectiveAlignment = d->hAlign;
404 if (!d->hAlignImplicit && d->effectiveLayoutMirror) {
406 case QQuickTextInput::AlignLeft:
407 effectiveAlignment = QQuickTextInput::AlignRight;
409 case QQuickTextInput::AlignRight:
410 effectiveAlignment = QQuickTextInput::AlignLeft;
416 return effectiveAlignment;
419 bool QQuickTextInputPrivate::setHAlign(QQuickTextInput::HAlignment alignment, bool forceAlign)
421 Q_Q(QQuickTextInput);
422 if ((hAlign != alignment || forceAlign) && alignment <= QQuickTextInput::AlignHCenter) { // justify not supported
423 QQuickTextInput::HAlignment oldEffectiveHAlign = q->effectiveHAlign();
425 emit q->horizontalAlignmentChanged(alignment);
426 if (oldEffectiveHAlign != q->effectiveHAlign())
427 emit q->effectiveHorizontalAlignmentChanged();
433 bool QQuickTextInputPrivate::determineHorizontalAlignment()
435 if (hAlignImplicit) {
436 // if no explicit alignment has been set, follow the natural layout direction of the text
437 QString text = q_func()->text();
439 text = m_textLayout.preeditAreaText();
440 bool isRightToLeft = text.isEmpty() ? QGuiApplication::keyboardInputDirection() == Qt::RightToLeft : text.isRightToLeft();
441 return setHAlign(isRightToLeft ? QQuickTextInput::AlignRight : QQuickTextInput::AlignLeft);
446 QQuickTextInput::VAlignment QQuickTextInput::vAlign() const
448 Q_D(const QQuickTextInput);
452 void QQuickTextInput::setVAlign(QQuickTextInput::VAlignment alignment)
454 Q_D(QQuickTextInput);
455 if (alignment == d->vAlign)
457 d->vAlign = alignment;
458 emit verticalAlignmentChanged(d->vAlign);
459 if (isComponentComplete()) {
460 updateCursorRectangle();
465 \qmlproperty enumeration QtQuick2::TextInput::wrapMode
467 Set this property to wrap the text to the TextEdit item's width.
468 The text will only wrap if an explicit width has been set.
471 \o TextInput.NoWrap - no wrapping will be performed. If the text contains insufficient newlines, then implicitWidth will exceed a set width.
472 \o TextInput.WordWrap - wrapping is done on word boundaries only. If a word is too long, implicitWidth will exceed a set width.
473 \o TextInput.WrapAnywhere - wrapping is done at any point on a line, even if it occurs in the middle of a word.
474 \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.
477 The default is TextInput.NoWrap. If you set a width, consider using TextInput.Wrap.
479 QQuickTextInput::WrapMode QQuickTextInput::wrapMode() const
481 Q_D(const QQuickTextInput);
485 void QQuickTextInput::setWrapMode(WrapMode mode)
487 Q_D(QQuickTextInput);
488 if (mode == d->wrapMode)
492 updateCursorRectangle();
493 emit wrapModeChanged();
496 void QQuickTextInputPrivate::mirrorChange()
498 Q_Q(QQuickTextInput);
499 if (q->isComponentComplete()) {
500 if (!hAlignImplicit && (hAlign == QQuickTextInput::AlignRight || hAlign == QQuickTextInput::AlignLeft)) {
501 q->updateCursorRectangle();
502 emit q->effectiveHorizontalAlignmentChanged();
508 \qmlproperty bool QtQuick2::TextInput::readOnly
510 Sets whether user input can modify the contents of the TextInput.
512 If readOnly is set to true, then user input will not affect the text
513 property. Any bindings or attempts to set the text property will still
516 bool QQuickTextInput::isReadOnly() const
518 Q_D(const QQuickTextInput);
519 return d->m_readOnly;
522 void QQuickTextInput::setReadOnly(bool ro)
524 Q_D(QQuickTextInput);
525 if (d->m_readOnly == ro)
528 setFlag(QQuickItem::ItemAcceptsInputMethod, !ro);
531 d->setCursorPosition(d->end());
533 emit readOnlyChanged(ro);
537 \qmlproperty int QtQuick2::TextInput::maximumLength
538 The maximum permitted length of the text in the TextInput.
540 If the text is too long, it is truncated at the limit.
542 By default, this property contains a value of 32767.
544 int QQuickTextInput::maxLength() const
546 Q_D(const QQuickTextInput);
547 return d->m_maxLength;
550 void QQuickTextInput::setMaxLength(int ml)
552 Q_D(QQuickTextInput);
553 if (d->m_maxLength == ml || d->m_maskData)
557 d->internalSetText(d->m_text, -1, false);
559 emit maximumLengthChanged(ml);
563 \qmlproperty bool QtQuick2::TextInput::cursorVisible
564 Set to true when the TextInput shows a cursor.
566 This property is set and unset when the TextInput gets active focus, so that other
567 properties can be bound to whether the cursor is currently showing. As it
568 gets set and unset automatically, when you set the value yourself you must
569 keep in mind that your value may be overwritten.
571 It can be set directly in script, for example if a KeyProxy might
572 forward keys to it and you desire it to look active when this happens
573 (but without actually giving it active focus).
575 It should not be set directly on the element, like in the below QML,
576 as the specified value will be overridden an lost on focus changes.
585 In the above snippet the cursor will still become visible when the
586 TextInput gains active focus.
588 bool QQuickTextInput::isCursorVisible() const
590 Q_D(const QQuickTextInput);
591 return d->cursorVisible;
594 void QQuickTextInput::setCursorVisible(bool on)
596 Q_D(QQuickTextInput);
597 if (d->cursorVisible == on)
599 d->cursorVisible = on;
600 d->setCursorBlinkPeriod(on ? qApp->styleHints()->cursorFlashTime() : 0);
601 QRect r = cursorRectangle();
602 if (d->inputMask().isEmpty())
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 || !isComponentComplete())
640 QTextLine l = d->m_textLayout.lineForTextPosition(c);
642 qRound(l.cursorToX(c) - d->hscroll),
643 qRound(l.y() - d->vscroll),
649 \qmlproperty int QtQuick2::TextInput::selectionStart
651 The cursor position before the first character in the current selection.
653 This property is read-only. To change the selection, use select(start,end),
654 selectAll(), or selectWord().
656 \sa selectionEnd, cursorPosition, selectedText
658 int QQuickTextInput::selectionStart() const
660 Q_D(const QQuickTextInput);
661 return d->lastSelectionStart;
664 \qmlproperty int QtQuick2::TextInput::selectionEnd
666 The cursor position after the last character in the current selection.
668 This property is read-only. To change the selection, use select(start,end),
669 selectAll(), or selectWord().
671 \sa selectionStart, cursorPosition, selectedText
673 int QQuickTextInput::selectionEnd() const
675 Q_D(const QQuickTextInput);
676 return d->lastSelectionEnd;
679 \qmlmethod void QtQuick2::TextInput::select(int start, int end)
681 Causes the text from \a start to \a end to be selected.
683 If either start or end is out of range, the selection is not changed.
685 After calling this, selectionStart will become the lesser
686 and selectionEnd will become the greater (regardless of the order passed
689 \sa selectionStart, selectionEnd
691 void QQuickTextInput::select(int start, int end)
693 Q_D(QQuickTextInput);
694 if (start < 0 || end < 0 || start > text().length() || end > text().length())
696 d->setSelection(start, end-start);
700 \qmlproperty string QtQuick2::TextInput::selectedText
702 This read-only property provides the text currently selected in the
705 It is equivalent to the following snippet, but is faster and easier
709 myTextInput.text.toString().substring(myTextInput.selectionStart,
710 myTextInput.selectionEnd);
713 QString QQuickTextInput::selectedText() const
715 Q_D(const QQuickTextInput);
716 return d->selectedText();
720 \qmlproperty bool QtQuick2::TextInput::activeFocusOnPress
722 Whether the TextInput should gain active focus on a mouse press. By default this is
725 bool QQuickTextInput::focusOnPress() const
727 Q_D(const QQuickTextInput);
728 return d->focusOnPress;
731 void QQuickTextInput::setFocusOnPress(bool b)
733 Q_D(QQuickTextInput);
734 if (d->focusOnPress == b)
739 emit activeFocusOnPressChanged(d->focusOnPress);
742 \qmlproperty bool QtQuick2::TextInput::autoScroll
744 Whether the TextInput should scroll when the text is longer than the width. By default this is
747 bool QQuickTextInput::autoScroll() const
749 Q_D(const QQuickTextInput);
750 return d->autoScroll;
753 void QQuickTextInput::setAutoScroll(bool b)
755 Q_D(QQuickTextInput);
756 if (d->autoScroll == b)
760 //We need to repaint so that the scrolling is taking into account.
761 updateCursorRectangle();
762 emit autoScrollChanged(d->autoScroll);
765 #ifndef QT_NO_VALIDATOR
768 \qmlclass IntValidator QIntValidator
769 \inqmlmodule QtQuick 2
770 \ingroup qml-basic-visual-elements
772 This element provides a validator for integer values.
774 IntValidator uses the \l {QLocale::setDefault()}{default locale} to interpret the number and
775 will accept locale specific digits, group separators, and positive and negative signs. In
776 addition, IntValidator is always guaranteed to accept a number formatted according to the "C"
780 \qmlproperty int QtQuick2::IntValidator::top
782 This property holds the validator's highest acceptable value.
783 By default, this property's value is derived from the highest signed integer available (typically 2147483647).
786 \qmlproperty int QtQuick2::IntValidator::bottom
788 This property holds the validator's lowest acceptable value.
789 By default, this property's value is derived from the lowest signed integer available (typically -2147483647).
793 \qmlclass DoubleValidator QDoubleValidator
794 \inqmlmodule QtQuick 2
795 \ingroup qml-basic-visual-elements
797 This element provides a validator for non-integer numbers.
801 \qmlproperty real QtQuick2::DoubleValidator::top
803 This property holds the validator's maximum acceptable value.
804 By default, this property contains a value of infinity.
807 \qmlproperty real QtQuick2::DoubleValidator::bottom
809 This property holds the validator's minimum acceptable value.
810 By default, this property contains a value of -infinity.
813 \qmlproperty int QtQuick2::DoubleValidator::decimals
815 This property holds the validator's maximum number of digits after the decimal point.
816 By default, this property contains a value of 1000.
819 \qmlproperty enumeration QtQuick2::DoubleValidator::notation
820 This property holds the notation of how a string can describe a number.
822 The possible values for this property are:
825 \o DoubleValidator.StandardNotation
826 \o DoubleValidator.ScientificNotation (default)
829 If this property is set to DoubleValidator.ScientificNotation, the written number may have an exponent part (e.g. 1.5E-2).
833 \qmlclass RegExpValidator QRegExpValidator
834 \inqmlmodule QtQuick 2
835 \ingroup qml-basic-visual-elements
837 This element provides a validator, which counts as valid any string which
838 matches a specified regular expression.
841 \qmlproperty regExp QtQuick2::RegExpValidator::regExp
843 This property holds the regular expression used for validation.
845 Note that this property should be a regular expression in JS syntax, e.g /a/ for the regular expression
848 By default, this property contains a regular expression with the pattern .* that matches any string.
852 \qmlproperty Validator QtQuick2::TextInput::validator
854 Allows you to set a validator on the TextInput. When a validator is set
855 the TextInput will only accept input which leaves the text property in
856 an acceptable or intermediate state. The accepted signal will only be sent
857 if the text is in an acceptable state when enter is pressed.
859 Currently supported validators are IntValidator, DoubleValidator and
860 RegExpValidator. An example of using validators is shown below, which allows
861 input of integers between 11 and 31 into the text input:
866 validator: IntValidator{bottom: 11; top: 31;}
871 \sa acceptableInput, inputMask
874 QValidator* QQuickTextInput::validator() const
876 Q_D(const QQuickTextInput);
877 return d->m_validator;
880 void QQuickTextInput::setValidator(QValidator* v)
882 Q_D(QQuickTextInput);
883 if (d->m_validator == v)
887 if (!d->hasAcceptableInput(d->m_text)) {
888 d->oldValidity = false;
889 emit acceptableInputChanged();
892 emit validatorChanged();
894 #endif // QT_NO_VALIDATOR
897 \qmlproperty string QtQuick2::TextInput::inputMask
899 Allows you to set an input mask on the TextInput, restricting the allowable
900 text inputs. See QLineEdit::inputMask for further details, as the exact
901 same mask strings are used by TextInput.
903 \sa acceptableInput, validator
905 QString QQuickTextInput::inputMask() const
907 Q_D(const QQuickTextInput);
908 return d->inputMask();
911 void QQuickTextInput::setInputMask(const QString &im)
913 Q_D(QQuickTextInput);
914 if (d->inputMask() == im)
918 emit inputMaskChanged(d->inputMask());
922 \qmlproperty bool QtQuick2::TextInput::acceptableInput
924 This property is always true unless a validator or input mask has been set.
925 If a validator or input mask has been set, this property will only be true
926 if the current text is acceptable to the validator or input mask as a final
927 string (not as an intermediate string).
929 bool QQuickTextInput::hasAcceptableInput() const
931 Q_D(const QQuickTextInput);
932 return d->hasAcceptableInput(d->m_text);
936 \qmlsignal QtQuick2::TextInput::onAccepted()
938 This handler is called when the Return or Enter key is pressed.
939 Note that if there is a \l validator or \l inputMask set on the text
940 input, the handler will only be emitted if the input is in an acceptable
944 void QQuickTextInputPrivate::updateInputMethodHints()
946 Q_Q(QQuickTextInput);
947 Qt::InputMethodHints hints = inputMethodHints;
948 if (m_echoMode == QQuickTextInput::Password || m_echoMode == QQuickTextInput::NoEcho)
949 hints |= Qt::ImhHiddenText;
950 else if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit)
951 hints &= ~Qt::ImhHiddenText;
952 if (m_echoMode != QQuickTextInput::Normal)
953 hints |= (Qt::ImhNoAutoUppercase | Qt::ImhNoPredictiveText);
954 q->setInputMethodHints(hints);
957 \qmlproperty enumeration QtQuick2::TextInput::echoMode
959 Specifies how the text should be displayed in the TextInput.
961 \o TextInput.Normal - Displays the text as it is. (Default)
962 \o TextInput.Password - Displays asterisks instead of characters.
963 \o TextInput.NoEcho - Displays nothing.
964 \o TextInput.PasswordEchoOnEdit - Displays characters as they are entered
965 while editing, otherwise displays asterisks.
968 QQuickTextInput::EchoMode QQuickTextInput::echoMode() const
970 Q_D(const QQuickTextInput);
971 return QQuickTextInput::EchoMode(d->m_echoMode);
974 void QQuickTextInput::setEchoMode(QQuickTextInput::EchoMode echo)
976 Q_D(QQuickTextInput);
977 if (echoMode() == echo)
979 d->m_echoMode = echo;
980 d->m_passwordEchoEditing = false;
981 d->updateInputMethodHints();
982 d->updateDisplayText();
983 updateCursorRectangle();
985 emit echoModeChanged(echoMode());
988 Qt::InputMethodHints QQuickTextInput::imHints() const
990 Q_D(const QQuickTextInput);
991 return d->inputMethodHints;
994 void QQuickTextInput::setIMHints(Qt::InputMethodHints hints)
996 Q_D(QQuickTextInput);
997 if (d->inputMethodHints == hints)
999 d->inputMethodHints = hints;
1000 d->updateInputMethodHints();
1004 \qmlproperty Component QtQuick2::TextInput::cursorDelegate
1005 The delegate for the cursor in the TextInput.
1007 If you set a cursorDelegate for a TextInput, this delegate will be used for
1008 drawing the cursor instead of the standard cursor. An instance of the
1009 delegate will be created and managed by the TextInput when a cursor is
1010 needed, and the x property of delegate instance will be set so as
1011 to be one pixel before the top left of the current character.
1013 Note that the root item of the delegate component must be a QDeclarativeItem or
1014 QDeclarativeItem derived item.
1016 QDeclarativeComponent* QQuickTextInput::cursorDelegate() const
1018 Q_D(const QQuickTextInput);
1019 return d->cursorComponent;
1022 void QQuickTextInput::setCursorDelegate(QDeclarativeComponent* c)
1024 Q_D(QQuickTextInput);
1025 if (d->cursorComponent == c)
1028 d->cursorComponent = c;
1030 //note that the components are owned by something else
1031 delete d->cursorItem;
1033 d->startCreatingCursor();
1036 emit cursorDelegateChanged();
1039 void QQuickTextInputPrivate::startCreatingCursor()
1041 Q_Q(QQuickTextInput);
1042 if (cursorComponent->isReady()) {
1044 } else if (cursorComponent->isLoading()) {
1045 q->connect(cursorComponent, SIGNAL(statusChanged(int)),
1046 q, SLOT(createCursor()));
1048 qmlInfo(q, cursorComponent->errors()) << QQuickTextInput::tr("Could not load cursor delegate");
1052 void QQuickTextInput::createCursor()
1054 Q_D(QQuickTextInput);
1055 if (!isComponentComplete())
1058 if (d->cursorComponent->isError()) {
1059 qmlInfo(this, d->cursorComponent->errors()) << tr("Could not load cursor delegate");
1063 if (!d->cursorComponent->isReady())
1067 delete d->cursorItem;
1068 QDeclarativeContext *creationContext = d->cursorComponent->creationContext();
1069 QObject *object = d->cursorComponent->create(creationContext ? creationContext : qmlContext(this));
1070 d->cursorItem = qobject_cast<QQuickItem*>(object);
1071 if (!d->cursorItem) {
1073 qmlInfo(this, d->cursorComponent->errors()) << tr("Could not instantiate cursor delegate");
1077 QRectF r = cursorRectangle();
1079 QDeclarative_setParent_noEvent(d->cursorItem, this);
1080 d->cursorItem->setParentItem(this);
1081 d->cursorItem->setPos(r.topLeft());
1082 d->cursorItem->setHeight(r.height());
1086 \qmlmethod rect QtQuick2::TextInput::positionToRectangle(int pos)
1088 This function takes a character position and returns the rectangle that the
1089 cursor would occupy, if it was placed at that character position.
1091 This is similar to setting the cursorPosition, and then querying the cursor
1092 rectangle, but the cursorPosition is not changed.
1094 QRectF QQuickTextInput::positionToRectangle(int pos) const
1096 Q_D(const QQuickTextInput);
1097 if (pos > d->m_cursor)
1098 pos += d->preeditAreaText().length();
1099 QTextLine l = d->m_textLayout.lineAt(0);
1100 return QRectF(l.cursorToX(pos) - d->hscroll, 0.0, d->m_cursorWidth, l.height());
1104 \qmlmethod int QtQuick2::TextInput::positionAt(real x, real y, CursorPosition position = CursorBetweenCharacters)
1106 This function returns the character position at
1107 x and y pixels from the top left of the textInput. Position 0 is before the
1108 first character, position 1 is after the first character but before the second,
1109 and so on until position text.length, which is after all characters.
1111 This means that for all x values before the first character this function returns 0,
1112 and for all x values after the last character this function returns text.length. If
1113 the y value is above the text the position will be that of the nearest character on
1114 the first line line and if it is below the text the position of the nearest character
1115 on the last line will be returned.
1117 The cursor position type specifies how the cursor position should be resolved.
1120 \o TextInput.CursorBetweenCharacters - Returns the position between characters that is nearest x.
1121 \o TextInput.CursorOnCharacter - Returns the position before the character that is nearest x.
1125 void QQuickTextInput::positionAt(QDeclarativeV8Function *args) const
1127 Q_D(const QQuickTextInput);
1131 QTextLine::CursorPosition position = QTextLine::CursorBetweenCharacters;
1133 if (args->Length() < 1)
1137 v8::Local<v8::Value> arg = (*args)[i];
1138 x = arg->NumberValue();
1140 if (++i < args->Length()) {
1142 y = arg->NumberValue();
1145 if (++i < args->Length()) {
1147 position = QTextLine::CursorPosition(arg->Int32Value());
1150 int pos = d->positionAt(x, y, position);
1151 const int cursor = d->m_cursor;
1153 const int preeditLength = d->preeditAreaText().length();
1154 pos = pos > cursor + preeditLength
1155 ? pos - preeditLength
1158 args->returnValue(v8::Int32::New(pos));
1161 int QQuickTextInputPrivate::positionAt(int x, int y, QTextLine::CursorPosition position) const
1165 QTextLine line = m_textLayout.lineAt(0);
1166 for (int i = 1; i < m_textLayout.lineCount(); ++i) {
1167 QTextLine nextLine = m_textLayout.lineAt(i);
1169 if (y < (line.rect().bottom() + nextLine.y()) / 2)
1173 return line.xToCursor(x, position);
1176 void QQuickTextInput::keyPressEvent(QKeyEvent* ev)
1178 Q_D(QQuickTextInput);
1179 // Don't allow MacOSX up/down support, and we don't allow a completer.
1180 bool ignore = (ev->key() == Qt::Key_Up || ev->key() == Qt::Key_Down) && ev->modifiers() == Qt::NoModifier;
1181 if (!ignore && (d->lastSelectionStart == d->lastSelectionEnd) && (ev->key() == Qt::Key_Right || ev->key() == Qt::Key_Left)) {
1182 // Ignore when moving off the end unless there is a selection,
1183 // because then moving will do something (deselect).
1184 int cursorPosition = d->m_cursor;
1185 if (cursorPosition == 0)
1186 ignore = ev->key() == (d->layoutDirection() == Qt::LeftToRight ? Qt::Key_Left : Qt::Key_Right);
1187 if (cursorPosition == text().length())
1188 ignore = ev->key() == (d->layoutDirection() == Qt::LeftToRight ? Qt::Key_Right : Qt::Key_Left);
1193 d->processKeyEvent(ev);
1195 if (!ev->isAccepted())
1196 QQuickImplicitSizeItem::keyPressEvent(ev);
1199 void QQuickTextInput::inputMethodEvent(QInputMethodEvent *ev)
1201 Q_D(QQuickTextInput);
1202 const bool wasComposing = d->preeditAreaText().length() > 0;
1203 if (d->m_readOnly) {
1206 d->processInputMethodEvent(ev);
1208 if (!ev->isAccepted())
1209 QQuickImplicitSizeItem::inputMethodEvent(ev);
1211 if (wasComposing != (d->m_textLayout.preeditAreaText().length() > 0))
1212 emit inputMethodComposingChanged();
1215 void QQuickTextInput::mouseDoubleClickEvent(QMouseEvent *event)
1217 Q_D(QQuickTextInput);
1219 if (d->selectByMouse && event->button() == Qt::LeftButton) {
1221 int cursor = d->positionAt(event->localPos());
1222 d->selectWordAtPos(cursor);
1223 event->setAccepted(true);
1224 if (!d->hasPendingTripleClick()) {
1225 d->tripleClickStartPoint = event->localPos().toPoint();
1226 d->tripleClickTimer.start();
1229 if (d->sendMouseEventToInputContext(event))
1231 QQuickImplicitSizeItem::mouseDoubleClickEvent(event);
1235 void QQuickTextInput::mousePressEvent(QMouseEvent *event)
1237 Q_D(QQuickTextInput);
1239 d->pressPos = event->localPos();
1241 if (d->focusOnPress) {
1242 bool hadActiveFocus = hasActiveFocus();
1244 // re-open input panel on press if already focused
1245 if (hasActiveFocus() && hadActiveFocus && !d->m_readOnly)
1246 openSoftwareInputPanel();
1248 if (d->selectByMouse) {
1249 setKeepMouseGrab(false);
1250 d->selectPressed = true;
1251 QPoint distanceVector = d->pressPos.toPoint() - d->tripleClickStartPoint;
1252 if (d->hasPendingTripleClick()
1253 && distanceVector.manhattanLength() < qApp->styleHints()->startDragDistance()) {
1254 event->setAccepted(true);
1260 if (d->sendMouseEventToInputContext(event))
1263 bool mark = (event->modifiers() & Qt::ShiftModifier) && d->selectByMouse;
1264 int cursor = d->positionAt(event->localPos());
1265 d->moveCursor(cursor, mark);
1266 event->setAccepted(true);
1269 void QQuickTextInput::mouseMoveEvent(QMouseEvent *event)
1271 Q_D(QQuickTextInput);
1273 if (d->selectPressed) {
1274 if (qAbs(int(event->localPos().x() - d->pressPos.x())) > qApp->styleHints()->startDragDistance())
1275 setKeepMouseGrab(true);
1277 if (d->composeMode()) {
1279 int startPos = d->positionAt(d->pressPos);
1280 int currentPos = d->positionAt(event->localPos());
1281 if (startPos != currentPos)
1282 d->setSelection(startPos, currentPos - startPos);
1284 moveCursorSelection(d->positionAt(event->localPos()), d->mouseSelectionMode);
1286 event->setAccepted(true);
1288 QQuickImplicitSizeItem::mouseMoveEvent(event);
1292 void QQuickTextInput::mouseReleaseEvent(QMouseEvent *event)
1294 Q_D(QQuickTextInput);
1295 if (d->sendMouseEventToInputContext(event))
1297 if (d->selectPressed) {
1298 d->selectPressed = false;
1299 setKeepMouseGrab(false);
1301 #ifndef QT_NO_CLIPBOARD
1302 if (QGuiApplication::clipboard()->supportsSelection()) {
1303 if (event->button() == Qt::LeftButton) {
1304 d->copy(QClipboard::Selection);
1305 } else if (!d->m_readOnly && event->button() == Qt::MidButton) {
1307 d->insert(QGuiApplication::clipboard()->text(QClipboard::Selection));
1311 if (!event->isAccepted())
1312 QQuickImplicitSizeItem::mouseReleaseEvent(event);
1315 bool QQuickTextInputPrivate::sendMouseEventToInputContext(QMouseEvent *event)
1317 #if !defined QT_NO_IM
1318 if (composeMode()) {
1319 int tmp_cursor = positionAt(event->localPos());
1320 int mousePos = tmp_cursor - m_cursor;
1321 if (mousePos >= 0 && mousePos <= m_textLayout.preeditAreaText().length()) {
1322 if (event->type() == QEvent::MouseButtonRelease) {
1323 qApp->inputPanel()->invokeAction(QInputPanel::Click, mousePos);
1336 void QQuickTextInput::mouseUngrabEvent()
1338 Q_D(QQuickTextInput);
1339 d->selectPressed = false;
1340 setKeepMouseGrab(false);
1343 bool QQuickTextInput::event(QEvent* ev)
1345 #ifndef QT_NO_SHORTCUT
1346 Q_D(QQuickTextInput);
1347 if (ev->type() == QEvent::ShortcutOverride) {
1350 QKeyEvent* ke = static_cast<QKeyEvent*>(ev);
1351 if (ke == QKeySequence::Copy
1352 || ke == QKeySequence::Paste
1353 || ke == QKeySequence::Cut
1354 || ke == QKeySequence::Redo
1355 || ke == QKeySequence::Undo
1356 || ke == QKeySequence::MoveToNextWord
1357 || ke == QKeySequence::MoveToPreviousWord
1358 || ke == QKeySequence::MoveToStartOfDocument
1359 || ke == QKeySequence::MoveToEndOfDocument
1360 || ke == QKeySequence::SelectNextWord
1361 || ke == QKeySequence::SelectPreviousWord
1362 || ke == QKeySequence::SelectStartOfLine
1363 || ke == QKeySequence::SelectEndOfLine
1364 || ke == QKeySequence::SelectStartOfBlock
1365 || ke == QKeySequence::SelectEndOfBlock
1366 || ke == QKeySequence::SelectStartOfDocument
1367 || ke == QKeySequence::SelectAll
1368 || ke == QKeySequence::SelectEndOfDocument) {
1370 } else if (ke->modifiers() == Qt::NoModifier || ke->modifiers() == Qt::ShiftModifier
1371 || ke->modifiers() == Qt::KeypadModifier) {
1372 if (ke->key() < Qt::Key_Escape) {
1376 switch (ke->key()) {
1377 case Qt::Key_Delete:
1380 case Qt::Key_Backspace:
1392 return QQuickImplicitSizeItem::event(ev);
1395 void QQuickTextInput::geometryChanged(const QRectF &newGeometry,
1396 const QRectF &oldGeometry)
1398 Q_D(QQuickTextInput);
1399 if (newGeometry.width() != oldGeometry.width())
1401 updateCursorRectangle();
1402 QQuickImplicitSizeItem::geometryChanged(newGeometry, oldGeometry);
1405 void QQuickTextInputPrivate::updateHorizontalScroll()
1407 Q_Q(QQuickTextInput);
1408 QTextLine currentLine = m_textLayout.lineForTextPosition(m_cursor + m_preeditCursor);
1409 const int preeditLength = m_textLayout.preeditAreaText().length();
1410 const int width = q->width();
1411 int widthUsed = currentLine.isValid() ? qRound(currentLine.naturalTextWidth()) : 0;
1412 int previousScroll = hscroll;
1414 if (!autoScroll || widthUsed <= width || m_echoMode == QQuickTextInput::NoEcho) {
1417 int cix = qRound(currentLine.cursorToX(m_cursor + preeditLength));
1418 if (cix - hscroll >= width) {
1419 // text doesn't fit, cursor is to the right of br (scroll right)
1420 hscroll = cix - width;
1421 } else if (cix - hscroll < 0 && hscroll < widthUsed) {
1422 // text doesn't fit, cursor is to the left of br (scroll left)
1424 } else if (widthUsed - hscroll < width) {
1425 // text doesn't fit, text document is to the left of br; align
1427 hscroll = widthUsed - width;
1429 if (preeditLength > 0) {
1430 // check to ensure long pre-edit text doesn't push the cursor
1432 cix = qRound(currentLine.cursorToX(m_cursor + qMax(0, m_preeditCursor - 1)));
1437 if (previousScroll != hscroll)
1438 textLayoutDirty = true;
1441 void QQuickTextInputPrivate::updateVerticalScroll()
1443 Q_Q(QQuickTextInput);
1444 const int preeditLength = m_textLayout.preeditAreaText().length();
1445 const int height = q->height();
1446 int heightUsed = boundingRect.height();
1447 int previousScroll = vscroll;
1449 if (!autoScroll || heightUsed <= height) {
1450 // text fits in br; use vscroll for alignment
1451 switch (vAlign & ~(Qt::AlignAbsolute|Qt::AlignHorizontal_Mask)) {
1452 case Qt::AlignBottom:
1453 vscroll = heightUsed - height;
1455 case Qt::AlignVCenter:
1456 vscroll = (heightUsed - height) / 2;
1464 QRectF r = m_textLayout.lineForTextPosition(m_cursor + preeditLength).rect();
1465 int top = qFloor(r.top());
1466 int bottom = qCeil(r.bottom());
1468 if (bottom - vscroll >= height) {
1469 // text doesn't fit, cursor is to the below the br (scroll down)
1470 vscroll = bottom - height;
1471 } else if (top - vscroll < 0 && vscroll < heightUsed) {
1472 // text doesn't fit, cursor is above br (scroll up)
1474 } else if (heightUsed - vscroll < height) {
1475 // text doesn't fit, text document is to the left of br; align
1477 vscroll = heightUsed - height;
1479 if (preeditLength > 0) {
1480 // check to ensure long pre-edit text doesn't push the cursor
1482 top = qRound(m_textLayout.lineForTextPosition(
1483 m_cursor + qMax(0, m_preeditCursor - 1)).rect().top());
1488 if (previousScroll != vscroll)
1489 textLayoutDirty = true;
1492 QSGNode *QQuickTextInput::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data)
1495 Q_D(QQuickTextInput);
1497 QQuickTextNode *node = static_cast<QQuickTextNode *>(oldNode);
1499 node = new QQuickTextNode(QQuickItemPrivate::get(this)->sceneGraphContext());
1502 if (!d->textLayoutDirty) {
1503 QSGSimpleRectNode *cursorNode = node->cursorNode();
1504 if (cursorNode != 0 && !isReadOnly()) {
1505 cursorNode->setRect(cursorRectangle());
1507 if (!d->cursorVisible || (!d->m_blinkStatus && d->m_blinkPeriod > 0)) {
1514 node->deleteContent();
1515 node->setMatrix(QMatrix4x4());
1517 QPoint offset = QPoint(0,0);
1518 QFontMetrics fm = QFontMetrics(d->font);
1519 if (d->autoScroll) {
1520 // the y offset is there to keep the baseline constant in case we have script changes in the text.
1521 offset = -QPoint(d->hscroll, d->vscroll + d->m_ascent - fm.ascent());
1523 offset = -QPoint(d->hscroll, d->vscroll);
1526 if (!d->m_textLayout.text().isEmpty()) {
1527 node->addTextLayout(offset, &d->m_textLayout, d->color,
1528 QQuickText::Normal, QColor(),
1529 d->selectionColor, d->selectedTextColor,
1530 d->selectionStart(),
1531 d->selectionEnd() - 1); // selectionEnd() returns first char after
1535 if (!isReadOnly() && d->cursorItem == 0) {
1536 node->setCursor(cursorRectangle(), d->color);
1537 if (!d->cursorVisible || (!d->m_blinkStatus && d->m_blinkPeriod > 0)) {
1544 d->textLayoutDirty = false;
1550 QVariant QQuickTextInput::inputMethodQuery(Qt::InputMethodQuery property) const
1552 Q_D(const QQuickTextInput);
1555 return QVariant((bool)(flags() & ItemAcceptsInputMethod));
1557 return QVariant((int)inputMethodHints());
1558 case Qt::ImCursorRectangle:
1559 return cursorRectangle();
1562 case Qt::ImCursorPosition:
1563 return QVariant(d->m_cursor);
1564 case Qt::ImSurroundingText:
1565 if (d->m_echoMode == PasswordEchoOnEdit && !d->m_passwordEchoEditing) {
1566 return QVariant(displayText());
1568 return QVariant(d->realText());
1570 case Qt::ImCurrentSelection:
1571 return QVariant(selectedText());
1572 case Qt::ImMaximumTextLength:
1573 return QVariant(maxLength());
1574 case Qt::ImAnchorPosition:
1575 if (d->selectionStart() == d->selectionEnd())
1576 return QVariant(d->m_cursor);
1577 else if (d->selectionStart() == d->m_cursor)
1578 return QVariant(d->selectionEnd());
1580 return QVariant(d->selectionStart());
1587 \qmlmethod void QtQuick2::TextInput::deselect()
1589 Removes active text selection.
1591 void QQuickTextInput::deselect()
1593 Q_D(QQuickTextInput);
1598 \qmlmethod void QtQuick2::TextInput::selectAll()
1600 Causes all text to be selected.
1602 void QQuickTextInput::selectAll()
1604 Q_D(QQuickTextInput);
1605 d->setSelection(0, text().length());
1609 \qmlmethod void QtQuick2::TextInput::isRightToLeft(int start, int end)
1611 Returns true if the natural reading direction of the editor text
1612 found between positions \a start and \a end is right to left.
1614 bool QQuickTextInput::isRightToLeft(int start, int end)
1617 qmlInfo(this) << "isRightToLeft(start, end) called with the end property being smaller than the start.";
1620 return text().mid(start, end - start).isRightToLeft();
1624 #ifndef QT_NO_CLIPBOARD
1626 \qmlmethod QtQuick2::TextInput::cut()
1628 Moves the currently selected text to the system clipboard.
1630 void QQuickTextInput::cut()
1632 Q_D(QQuickTextInput);
1638 \qmlmethod QtQuick2::TextInput::copy()
1640 Copies the currently selected text to the system clipboard.
1642 void QQuickTextInput::copy()
1644 Q_D(QQuickTextInput);
1649 \qmlmethod QtQuick2::TextInput::paste()
1651 Replaces the currently selected text by the contents of the system clipboard.
1653 void QQuickTextInput::paste()
1655 Q_D(QQuickTextInput);
1659 #endif // QT_NO_CLIPBOARD
1662 \qmlmethod void QtQuick2::TextInput::selectWord()
1664 Causes the word closest to the current cursor position to be selected.
1666 void QQuickTextInput::selectWord()
1668 Q_D(QQuickTextInput);
1669 d->selectWordAtPos(d->m_cursor);
1673 \qmlproperty bool QtQuick2::TextInput::smooth
1675 This property holds whether the text is smoothly scaled or transformed.
1677 Smooth filtering gives better visual quality, but is slower. If
1678 the item is displayed at its natural size, this property has no visual or
1681 \note Generally scaling artifacts are only visible if the item is stationary on
1682 the screen. A common pattern when animating an item is to disable smooth
1683 filtering at the beginning of the animation and reenable it at the conclusion.
1687 \qmlproperty string QtQuick2::TextInput::passwordCharacter
1689 This is the character displayed when echoMode is set to Password or
1690 PasswordEchoOnEdit. By default it is an asterisk.
1692 If this property is set to a string with more than one character,
1693 the first character is used. If the string is empty, the value
1694 is ignored and the property is not set.
1696 QString QQuickTextInput::passwordCharacter() const
1698 Q_D(const QQuickTextInput);
1699 return QString(d->m_passwordCharacter);
1702 void QQuickTextInput::setPasswordCharacter(const QString &str)
1704 Q_D(QQuickTextInput);
1705 if (str.length() < 1)
1707 d->m_passwordCharacter = str.constData()[0];
1708 if (d->m_echoMode == Password || d->m_echoMode == PasswordEchoOnEdit)
1709 d->updateDisplayText();
1710 emit passwordCharacterChanged();
1714 \qmlproperty string QtQuick2::TextInput::displayText
1716 This is the text displayed in the TextInput.
1718 If \l echoMode is set to TextInput::Normal, this holds the
1719 same value as the TextInput::text property. Otherwise,
1720 this property holds the text visible to the user, while
1721 the \l text property holds the actual entered text.
1723 QString QQuickTextInput::displayText() const
1725 Q_D(const QQuickTextInput);
1726 return d->m_textLayout.text();
1730 \qmlproperty bool QtQuick2::TextInput::selectByMouse
1734 If true, the user can use the mouse to select text in some
1735 platform-specific way. Note that for some platforms this may
1736 not be an appropriate interaction (eg. may conflict with how
1737 the text needs to behave inside a Flickable.
1739 bool QQuickTextInput::selectByMouse() const
1741 Q_D(const QQuickTextInput);
1742 return d->selectByMouse;
1745 void QQuickTextInput::setSelectByMouse(bool on)
1747 Q_D(QQuickTextInput);
1748 if (d->selectByMouse != on) {
1749 d->selectByMouse = on;
1750 emit selectByMouseChanged(on);
1755 \qmlproperty enum QtQuick2::TextInput::mouseSelectionMode
1757 Specifies how text should be selected using a mouse.
1760 \o TextInput.SelectCharacters - The selection is updated with individual characters. (Default)
1761 \o TextInput.SelectWords - The selection is updated with whole words.
1764 This property only applies when \l selectByMouse is true.
1767 QQuickTextInput::SelectionMode QQuickTextInput::mouseSelectionMode() const
1769 Q_D(const QQuickTextInput);
1770 return d->mouseSelectionMode;
1773 void QQuickTextInput::setMouseSelectionMode(SelectionMode mode)
1775 Q_D(QQuickTextInput);
1776 if (d->mouseSelectionMode != mode) {
1777 d->mouseSelectionMode = mode;
1778 emit mouseSelectionModeChanged(mode);
1783 \qmlproperty bool QtQuick2::TextInput::canPaste
1785 Returns true if the TextInput is writable and the content of the clipboard is
1786 suitable for pasting into the TextEdit.
1788 bool QQuickTextInput::canPaste() const
1790 Q_D(const QQuickTextInput);
1794 void QQuickTextInput::moveCursorSelection(int position)
1796 Q_D(QQuickTextInput);
1797 d->moveCursor(position, true);
1801 \qmlmethod void QtQuick2::TextInput::moveCursorSelection(int position, SelectionMode mode = TextInput.SelectCharacters)
1803 Moves the cursor to \a position and updates the selection according to the optional \a mode
1804 parameter. (To only move the cursor, set the \l cursorPosition property.)
1806 When this method is called it additionally sets either the
1807 selectionStart or the selectionEnd (whichever was at the previous cursor position)
1808 to the specified position. This allows you to easily extend and contract the selected
1811 The selection mode specifies whether the selection is updated on a per character or a per word
1812 basis. If not specified the selection mode will default to TextInput.SelectCharacters.
1815 \o TextEdit.SelectCharacters - Sets either the selectionStart or selectionEnd (whichever was at
1816 the previous cursor position) to the specified position.
1817 \o TextEdit.SelectWords - Sets the selectionStart and selectionEnd to include all
1818 words between the specified position and the previous cursor position. Words partially in the
1822 For example, take this sequence of calls:
1826 moveCursorSelection(9, TextInput.SelectCharacters)
1827 moveCursorSelection(7, TextInput.SelectCharacters)
1830 This moves the cursor to position 5, extend the selection end from 5 to 9
1831 and then retract the selection end from 9 to 7, leaving the text from position 5 to 7
1832 selected (the 6th and 7th characters).
1834 The same sequence with TextInput.SelectWords will extend the selection start to a word boundary
1835 before or on position 5 and extend the selection end to a word boundary on or past position 9.
1837 void QQuickTextInput::moveCursorSelection(int pos, SelectionMode mode)
1839 Q_D(QQuickTextInput);
1841 if (mode == SelectCharacters) {
1842 d->moveCursor(pos, true);
1843 } else if (pos != d->m_cursor){
1844 const int cursor = d->m_cursor;
1846 if (!d->hasSelectedText())
1847 anchor = d->m_cursor;
1848 else if (d->selectionStart() == d->m_cursor)
1849 anchor = d->selectionEnd();
1851 anchor = d->selectionStart();
1853 if (anchor < pos || (anchor == pos && cursor < pos)) {
1854 const QString text = this->text();
1855 QTextBoundaryFinder finder(QTextBoundaryFinder::Word, text);
1856 finder.setPosition(anchor);
1858 const QTextBoundaryFinder::BoundaryReasons reasons = finder.boundaryReasons();
1859 if (anchor < text.length() && (!(reasons & QTextBoundaryFinder::StartWord)
1860 || ((reasons & QTextBoundaryFinder::EndWord) && anchor > cursor))) {
1861 finder.toPreviousBoundary();
1863 anchor = finder.position() != -1 ? finder.position() : 0;
1865 finder.setPosition(pos);
1866 if (pos > 0 && !finder.boundaryReasons())
1867 finder.toNextBoundary();
1868 const int cursor = finder.position() != -1 ? finder.position() : text.length();
1870 d->setSelection(anchor, cursor - anchor);
1871 } else if (anchor > pos || (anchor == pos && cursor > pos)) {
1872 const QString text = this->text();
1873 QTextBoundaryFinder finder(QTextBoundaryFinder::Word, text);
1874 finder.setPosition(anchor);
1876 const QTextBoundaryFinder::BoundaryReasons reasons = finder.boundaryReasons();
1877 if (anchor > 0 && (!(reasons & QTextBoundaryFinder::EndWord)
1878 || ((reasons & QTextBoundaryFinder::StartWord) && anchor < cursor))) {
1879 finder.toNextBoundary();
1882 anchor = finder.position() != -1 ? finder.position() : text.length();
1884 finder.setPosition(pos);
1885 if (pos < text.length() && !finder.boundaryReasons())
1886 finder.toPreviousBoundary();
1887 const int cursor = finder.position() != -1 ? finder.position() : 0;
1889 d->setSelection(anchor, cursor - anchor);
1895 \qmlmethod void QtQuick2::TextInput::openSoftwareInputPanel()
1897 Opens software input panels like virtual keyboards for typing, useful for
1898 customizing when you want the input keyboard to be shown and hidden in
1901 By default the opening of input panels follows the platform style. Input panels are
1902 always closed if no editor has active focus.
1904 You can disable the automatic behavior by setting the property \c activeFocusOnPress to false
1905 and use functions openSoftwareInputPanel() and closeSoftwareInputPanel() to implement
1906 the behavior you want.
1908 Only relevant on platforms, which provide virtual keyboards.
1914 text: "Hello world!"
1915 activeFocusOnPress: false
1917 anchors.fill: parent
1919 if (!textInput.activeFocus) {
1920 textInput.forceActiveFocus()
1921 textInput.openSoftwareInputPanel();
1923 textInput.focus = false;
1926 onPressAndHold: textInput.closeSoftwareInputPanel();
1931 void QQuickTextInput::openSoftwareInputPanel()
1934 qGuiApp->inputPanel()->show();
1938 \qmlmethod void QtQuick2::TextInput::closeSoftwareInputPanel()
1940 Closes a software input panel like a virtual keyboard shown on the screen, useful
1941 for customizing when you want the input keyboard to be shown and hidden in
1944 By default the opening of input panels follows the platform style. Input panels are
1945 always closed if no editor has active focus.
1947 You can disable the automatic behavior by setting the property \c activeFocusOnPress to false
1948 and use functions openSoftwareInputPanel() and closeSoftwareInputPanel() to implement
1949 the behavior you want.
1951 Only relevant on platforms, which provide virtual keyboards.
1957 text: "Hello world!"
1958 activeFocusOnPress: false
1960 anchors.fill: parent
1962 if (!textInput.activeFocus) {
1963 textInput.forceActiveFocus();
1964 textInput.openSoftwareInputPanel();
1966 textInput.focus = false;
1969 onPressAndHold: textInput.closeSoftwareInputPanel();
1974 void QQuickTextInput::closeSoftwareInputPanel()
1977 qGuiApp->inputPanel()->hide();
1980 void QQuickTextInput::focusInEvent(QFocusEvent *event)
1982 Q_D(const QQuickTextInput);
1983 if (d->focusOnPress && !d->m_readOnly)
1984 openSoftwareInputPanel();
1985 QQuickImplicitSizeItem::focusInEvent(event);
1988 void QQuickTextInput::itemChange(ItemChange change, const ItemChangeData &value)
1990 Q_D(QQuickTextInput);
1991 if (change == ItemActiveFocusHasChanged) {
1992 bool hasFocus = value.boolValue;
1993 d->focused = hasFocus;
1994 setCursorVisible(hasFocus); // ### refactor: && d->canvas && d->canvas->hasFocus()
1995 if (echoMode() == QQuickTextInput::PasswordEchoOnEdit && !hasFocus)
1996 d->updatePasswordEchoEditing(false);//QQuickTextInputPrivate sets it on key events, but doesn't deal with focus events
2000 QQuickItem::itemChange(change, value);
2004 \qmlproperty bool QtQuick2::TextInput::inputMethodComposing
2007 This property holds whether the TextInput has partial text input from an
2010 While it is composing an input method may rely on mouse or key events from
2011 the TextInput to edit or commit the partial text. This property can be
2012 used to determine when to disable events handlers that may interfere with
2013 the correct operation of an input method.
2015 bool QQuickTextInput::isInputMethodComposing() const
2017 Q_D(const QQuickTextInput);
2018 return d->preeditAreaText().length() > 0;
2021 void QQuickTextInputPrivate::init()
2023 Q_Q(QQuickTextInput);
2024 q->setSmooth(smooth);
2025 q->setAcceptedMouseButtons(Qt::LeftButton);
2026 q->setFlag(QQuickItem::ItemAcceptsInputMethod);
2027 q->setFlag(QQuickItem::ItemHasContents);
2028 #ifndef QT_NO_CLIPBOARD
2029 q->connect(q, SIGNAL(readOnlyChanged(bool)),
2030 q, SLOT(q_canPasteChanged()));
2031 q->connect(QGuiApplication::clipboard(), SIGNAL(dataChanged()),
2032 q, SLOT(q_canPasteChanged()));
2033 canPaste = !m_readOnly && QGuiApplication::clipboard()->text().length() != 0;
2034 #endif // QT_NO_CLIPBOARD
2035 m_textLayout.beginLayout();
2036 m_textLayout.createLine();
2037 m_textLayout.endLayout();
2039 imHints &= ~Qt::ImhMultiLine;
2040 oldValidity = hasAcceptableInput(m_text);
2041 lastSelectionStart = 0;
2042 lastSelectionEnd = 0;
2043 selectedTextColor = m_palette.color(QPalette::HighlightedText);
2044 selectionColor = m_palette.color(QPalette::Highlight);
2045 determineHorizontalAlignment();
2047 if (!qmlDisableDistanceField()) {
2048 QTextOption option = m_textLayout.textOption();
2049 option.setUseDesignMetrics(true);
2050 m_textLayout.setTextOption(option);
2054 void QQuickTextInput::updateCursorRectangle()
2056 Q_D(QQuickTextInput);
2057 if (!isComponentComplete())
2060 d->updateHorizontalScroll();
2061 d->updateVerticalScroll();
2064 emit cursorRectangleChanged();
2065 if (d->cursorItem) {
2066 QRectF r = cursorRectangle();
2067 d->cursorItem->setPos(r.topLeft());
2068 d->cursorItem->setHeight(r.height());
2072 void QQuickTextInput::selectionChanged()
2074 Q_D(QQuickTextInput);
2075 updateRect();//TODO: Only update rect in selection
2076 emit selectedTextChanged();
2078 if (d->lastSelectionStart != d->selectionStart()) {
2079 d->lastSelectionStart = d->selectionStart();
2080 if (d->lastSelectionStart == -1)
2081 d->lastSelectionStart = d->m_cursor;
2082 emit selectionStartChanged();
2084 if (d->lastSelectionEnd != d->selectionEnd()) {
2085 d->lastSelectionEnd = d->selectionEnd();
2086 if (d->lastSelectionEnd == -1)
2087 d->lastSelectionEnd = d->m_cursor;
2088 emit selectionEndChanged();
2092 void QQuickTextInputPrivate::showCursor()
2094 if (textNode != 0 && textNode->cursorNode() != 0)
2095 textNode->cursorNode()->setColor(color);
2098 void QQuickTextInputPrivate::hideCursor()
2100 if (textNode != 0 && textNode->cursorNode() != 0)
2101 textNode->cursorNode()->setColor(QColor(0, 0, 0, 0));
2104 void QQuickTextInput::updateRect(const QRect &r)
2106 Q_D(QQuickTextInput);
2107 if (!isComponentComplete())
2111 d->textLayoutDirty = true;
2117 QRectF QQuickTextInput::boundingRect() const
2119 Q_D(const QQuickTextInput);
2121 QRectF r = d->boundingRect;
2122 int cursorWidth = d->cursorItem ? d->cursorItem->width() : d->m_cursorWidth;
2124 // Could include font max left/right bearings to either side of rectangle.
2126 r.setRight(r.right() + cursorWidth);
2127 r.translate(-d->hscroll, -d->vscroll);
2131 void QQuickTextInput::q_canPasteChanged()
2133 Q_D(QQuickTextInput);
2134 bool old = d->canPaste;
2135 #ifndef QT_NO_CLIPBOARD
2136 d->canPaste = !d->m_readOnly && QGuiApplication::clipboard()->text().length() != 0;
2138 if (d->canPaste != old)
2139 emit canPasteChanged();
2142 // ### these should come from QStyleHints
2143 const int textCursorWidth = 1;
2144 const bool fullWidthSelection = true;
2149 Updates the display text based of the current edit text
2150 If the text has changed will emit displayTextChanged()
2152 void QQuickTextInputPrivate::updateDisplayText(bool forceUpdate)
2154 QString orig = m_textLayout.text();
2156 if (m_echoMode == QQuickTextInput::NoEcho)
2157 str = QString::fromLatin1("");
2161 if (m_echoMode == QQuickTextInput::Password
2162 || (m_echoMode == QQuickTextInput::PasswordEchoOnEdit && !m_passwordEchoEditing))
2163 str.fill(m_passwordCharacter);
2165 // replace certain non-printable characters with spaces (to avoid
2166 // drawing boxes when using fonts that don't have glyphs for such
2168 QChar* uc = str.data();
2169 for (int i = 0; i < (int)str.length(); ++i) {
2170 if ((uc[i] < 0x20 && uc[i] != 0x09)
2171 || uc[i] == QChar::LineSeparator
2172 || uc[i] == QChar::ParagraphSeparator
2173 || uc[i] == QChar::ObjectReplacementCharacter)
2174 uc[i] = QChar(0x0020);
2177 if (str != orig || forceUpdate) {
2178 m_textLayout.setText(str);
2179 updateLayout(); // polish?
2180 emit q_func()->displayTextChanged();
2184 void QQuickTextInputPrivate::updateLayout()
2186 Q_Q(QQuickTextInput);
2188 if (!q->isComponentComplete())
2191 QTextOption option = m_textLayout.textOption();
2192 option.setTextDirection(m_layoutDirection);
2193 option.setFlags(QTextOption::IncludeTrailingSpaces);
2194 option.setWrapMode(QTextOption::WrapMode(wrapMode));
2195 option.setAlignment(Qt::Alignment(q->effectiveHAlign()));
2196 m_textLayout.setTextOption(option);
2197 m_textLayout.setFont(font);
2199 boundingRect = QRectF();
2200 m_textLayout.beginLayout();
2201 QTextLine line = m_textLayout.createLine();
2202 qreal lineWidth = q->widthValid() ? q->width() : INT_MAX;
2204 QTextLine firstLine = line;
2206 line.setLineWidth(lineWidth);
2207 line.setPosition(QPointF(line.position().x(), height));
2208 boundingRect = boundingRect.united(line.naturalTextRect());
2210 height += line.height();
2211 line = m_textLayout.createLine();
2212 } while (line.isValid());
2213 m_textLayout.endLayout();
2215 option.setWrapMode(QTextOption::NoWrap);
2216 m_textLayout.setTextOption(option);
2218 m_ascent = qRound(firstLine.ascent());
2219 textLayoutDirty = true;
2222 q->setImplicitSize(qCeil(boundingRect.width()), qCeil(boundingRect.height()));
2226 #ifndef QT_NO_CLIPBOARD
2230 Copies the currently selected text into the clipboard using the given
2233 \note If the echo mode is set to a mode other than Normal then copy
2234 will not work. This is to prevent using copy as a method of bypassing
2235 password features of the line control.
2237 void QQuickTextInputPrivate::copy(QClipboard::Mode mode) const
2239 QString t = selectedText();
2240 if (!t.isEmpty() && m_echoMode == QQuickTextInput::Normal) {
2241 QGuiApplication::clipboard()->setText(t, mode);
2248 Inserts the text stored in the application clipboard into the line
2253 void QQuickTextInputPrivate::paste(QClipboard::Mode clipboardMode)
2255 QString clip = QGuiApplication::clipboard()->text(clipboardMode);
2256 if (!clip.isEmpty() || hasSelectedText()) {
2257 separate(); //make it a separate undo/redo command
2263 #endif // !QT_NO_CLIPBOARD
2268 Exits preedit mode and commits parts marked as tentative commit
2270 void QQuickTextInputPrivate::commitPreedit()
2275 qApp->inputPanel()->reset();
2277 if (!m_tentativeCommit.isEmpty()) {
2278 internalInsert(m_tentativeCommit);
2279 m_tentativeCommit.clear();
2280 finishChange(-1, true/*not used, not documented*/, false);
2283 m_preeditCursor = 0;
2284 m_textLayout.setPreeditArea(-1, QString());
2285 m_textLayout.clearAdditionalFormats();
2292 Handles the behavior for the backspace key or function.
2293 Removes the current selection if there is a selection, otherwise
2294 removes the character prior to the cursor position.
2298 void QQuickTextInputPrivate::backspace()
2300 int priorState = m_undoState;
2301 if (hasSelectedText()) {
2302 removeSelectedText();
2303 } else if (m_cursor) {
2306 m_cursor = prevMaskBlank(m_cursor);
2307 QChar uc = m_text.at(m_cursor);
2308 if (m_cursor > 0 && uc.unicode() >= 0xdc00 && uc.unicode() < 0xe000) {
2309 // second half of a surrogate, check if we have the first half as well,
2310 // if yes delete both at once
2311 uc = m_text.at(m_cursor - 1);
2312 if (uc.unicode() >= 0xd800 && uc.unicode() < 0xdc00) {
2313 internalDelete(true);
2317 internalDelete(true);
2319 finishChange(priorState);
2325 Handles the behavior for the delete key or function.
2326 Removes the current selection if there is a selection, otherwise
2327 removes the character after the cursor position.
2331 void QQuickTextInputPrivate::del()
2333 int priorState = m_undoState;
2334 if (hasSelectedText()) {
2335 removeSelectedText();
2337 int n = m_textLayout.nextCursorPosition(m_cursor) - m_cursor;
2341 finishChange(priorState);
2347 Inserts the given \a newText at the current cursor position.
2348 If there is any selected text it is removed prior to insertion of
2351 void QQuickTextInputPrivate::insert(const QString &newText)
2353 int priorState = m_undoState;
2354 removeSelectedText();
2355 internalInsert(newText);
2356 finishChange(priorState);
2362 Clears the line control text.
2364 void QQuickTextInputPrivate::clear()
2366 int priorState = m_undoState;
2368 m_selend = m_text.length();
2369 removeSelectedText();
2371 finishChange(priorState, /*update*/false, /*edited*/false);
2377 Sets \a length characters from the given \a start position as selected.
2378 The given \a start position must be within the current text for
2379 the line control. If \a length characters cannot be selected, then
2380 the selection will extend to the end of the current text.
2382 void QQuickTextInputPrivate::setSelection(int start, int length)
2384 Q_Q(QQuickTextInput);
2387 if (start < 0 || start > (int)m_text.length()){
2388 qWarning("QQuickTextInputPrivate::setSelection: Invalid start position");
2393 if (start == m_selstart && start + length == m_selend && m_cursor == m_selend)
2396 m_selend = qMin(start + length, (int)m_text.length());
2397 m_cursor = m_selend;
2398 } else if (length < 0){
2399 if (start == m_selend && start + length == m_selstart && m_cursor == m_selstart)
2401 m_selstart = qMax(start + length, 0);
2403 m_cursor = m_selstart;
2404 } else if (m_selstart != m_selend) {
2410 emitCursorPositionChanged();
2413 emit q->selectionChanged();
2414 emitCursorPositionChanged();
2420 Initializes the line control with a starting text value of \a txt.
2422 void QQuickTextInputPrivate::init(const QString &txt)
2426 updateDisplayText();
2427 m_cursor = m_text.length();
2433 Sets the password echo editing to \a editing. If password echo editing
2434 is true, then the text of the password is displayed even if the echo
2435 mode is set to QLineEdit::PasswordEchoOnEdit. Password echoing editing
2436 does not affect other echo modes.
2438 void QQuickTextInputPrivate::updatePasswordEchoEditing(bool editing)
2440 m_passwordEchoEditing = editing;
2441 updateDisplayText();
2447 Fixes the current text so that it is valid given any set validators.
2449 Returns true if the text was changed. Otherwise returns false.
2451 bool QQuickTextInputPrivate::fixup() // this function assumes that validate currently returns != Acceptable
2453 #ifndef QT_NO_VALIDATOR
2455 QString textCopy = m_text;
2456 int cursorCopy = m_cursor;
2457 m_validator->fixup(textCopy);
2458 if (m_validator->validate(textCopy, cursorCopy) == QValidator::Acceptable) {
2459 if (textCopy != m_text || cursorCopy != m_cursor)
2460 internalSetText(textCopy, cursorCopy);
2471 Moves the cursor to the given position \a pos. If \a mark is true will
2472 adjust the currently selected text.
2474 void QQuickTextInputPrivate::moveCursor(int pos, bool mark)
2476 Q_Q(QQuickTextInput);
2479 if (pos != m_cursor) {
2482 pos = pos > m_cursor ? nextMaskBlank(pos) : prevMaskBlank(pos);
2486 if (m_selend > m_selstart && m_cursor == m_selstart)
2488 else if (m_selend > m_selstart && m_cursor == m_selend)
2489 anchor = m_selstart;
2492 m_selstart = qMin(anchor, pos);
2493 m_selend = qMax(anchor, pos);
2498 if (mark || m_selDirty) {
2500 emit q->selectionChanged();
2502 emitCursorPositionChanged();
2508 Applies the given input method event \a event to the text of the line
2511 void QQuickTextInputPrivate::processInputMethodEvent(QInputMethodEvent *event)
2513 Q_Q(QQuickTextInput);
2515 int priorState = -1;
2516 bool isGettingInput = !event->commitString().isEmpty()
2517 || event->preeditString() != preeditAreaText()
2518 || event->replacementLength() > 0;
2519 bool cursorPositionChanged = false;
2520 bool selectionChange = false;
2521 m_preeditDirty = event->preeditString() != preeditAreaText();
2523 if (isGettingInput) {
2524 // If any text is being input, remove selected text.
2525 priorState = m_undoState;
2526 if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit && !m_passwordEchoEditing) {
2527 updatePasswordEchoEditing(true);
2529 m_selend = m_text.length();
2531 removeSelectedText();
2534 int c = m_cursor; // cursor position after insertion of commit string
2535 if (event->replacementStart() <= 0)
2536 c += event->commitString().length() - qMin(-event->replacementStart(), event->replacementLength());
2538 m_cursor += event->replacementStart();
2542 // insert commit string
2543 if (event->replacementLength()) {
2544 m_selstart = m_cursor;
2545 m_selend = m_selstart + event->replacementLength();
2546 removeSelectedText();
2548 if (!event->commitString().isEmpty()) {
2549 internalInsert(event->commitString());
2550 cursorPositionChanged = true;
2553 m_cursor = qBound(0, c, m_text.length());
2555 for (int i = 0; i < event->attributes().size(); ++i) {
2556 const QInputMethodEvent::Attribute &a = event->attributes().at(i);
2557 if (a.type == QInputMethodEvent::Selection) {
2558 m_cursor = qBound(0, a.start + a.length, m_text.length());
2560 m_selstart = qMax(0, qMin(a.start, m_text.length()));
2561 m_selend = m_cursor;
2562 if (m_selend < m_selstart) {
2563 qSwap(m_selstart, m_selend);
2565 selectionChange = true;
2567 m_selstart = m_selend = 0;
2569 cursorPositionChanged = true;
2573 m_textLayout.setPreeditArea(m_cursor, event->preeditString());
2575 const int oldPreeditCursor = m_preeditCursor;
2576 m_preeditCursor = event->preeditString().length();
2577 m_hideCursor = false;
2578 QList<QTextLayout::FormatRange> formats;
2579 for (int i = 0; i < event->attributes().size(); ++i) {
2580 const QInputMethodEvent::Attribute &a = event->attributes().at(i);
2581 if (a.type == QInputMethodEvent::Cursor) {
2582 m_preeditCursor = a.start;
2583 m_hideCursor = !a.length;
2584 } else if (a.type == QInputMethodEvent::TextFormat) {
2585 QTextCharFormat f = qvariant_cast<QTextFormat>(a.value).toCharFormat();
2587 QTextLayout::FormatRange o;
2588 o.start = a.start + m_cursor;
2589 o.length = a.length;
2595 m_textLayout.setAdditionalFormats(formats);
2597 updateDisplayText(/*force*/ true);
2598 if (cursorPositionChanged)
2599 emitCursorPositionChanged();
2600 else if (m_preeditCursor != oldPreeditCursor)
2601 q->updateCursorRectangle();
2603 bool tentativeCommitChanged = m_tentativeCommit != event->tentativeCommitString();
2605 if (tentativeCommitChanged) {
2607 m_tentativeCommit = event->tentativeCommitString();
2610 if (isGettingInput || tentativeCommitChanged)
2611 finishChange(priorState);
2613 if (selectionChange)
2614 emit q->selectionChanged();
2620 Sets the selection to cover the word at the given cursor position.
2621 The word boundaries are defined by the behavior of QTextLayout::SkipWords
2624 void QQuickTextInputPrivate::selectWordAtPos(int cursor)
2626 int next = cursor + 1;
2629 int c = m_textLayout.previousCursorPosition(next, QTextLayout::SkipWords);
2630 moveCursor(c, false);
2631 // ## text layout should support end of words.
2632 int end = m_textLayout.nextCursorPosition(c, QTextLayout::SkipWords);
2633 while (end > cursor && m_text[end-1].isSpace())
2635 moveCursor(end, true);
2641 Completes a change to the line control text. If the change is not valid
2642 will undo the line control state back to the given \a validateFromState.
2644 If \a edited is true and the change is valid, will emit textEdited() in
2645 addition to textChanged(). Otherwise only emits textChanged() on a valid
2648 The \a update value is currently unused.
2650 bool QQuickTextInputPrivate::finishChange(int validateFromState, bool update, bool /*edited*/)
2652 Q_Q(QQuickTextInput);
2658 bool wasValidInput = m_validInput;
2659 m_validInput = true;
2660 #ifndef QT_NO_VALIDATOR
2662 QString textCopy = m_text;
2663 int cursorCopy = m_cursor;
2664 m_validInput = (m_validator->validate(textCopy, cursorCopy) != QValidator::Invalid);
2666 if (m_text != textCopy) {
2667 internalSetText(textCopy, cursorCopy);
2670 m_cursor = cursorCopy;
2672 if (!m_tentativeCommit.isEmpty()) {
2673 textCopy.insert(m_cursor, m_tentativeCommit);
2674 bool validInput = m_validator->validate(textCopy, cursorCopy) != QValidator::Invalid;
2676 m_tentativeCommit.clear();
2679 m_tentativeCommit.clear();
2683 if (validateFromState >= 0 && wasValidInput && !m_validInput) {
2684 if (m_transactions.count())
2686 internalUndo(validateFromState);
2687 m_history.resize(m_undoState);
2688 if (m_modifiedState > m_undoState)
2689 m_modifiedState = -1;
2690 m_validInput = true;
2691 m_textDirty = false;
2693 updateDisplayText();
2696 m_textDirty = false;
2697 m_preeditDirty = false;
2698 determineHorizontalAlignment();
2699 emit q->textChanged();
2702 if (m_validInput != wasValidInput)
2703 emit q->acceptableInputChanged();
2705 if (m_preeditDirty) {
2706 m_preeditDirty = false;
2707 determineHorizontalAlignment();
2711 emit q->selectionChanged();
2713 emitCursorPositionChanged();
2720 An internal function for setting the text of the line control.
2722 void QQuickTextInputPrivate::internalSetText(const QString &txt, int pos, bool edited)
2724 Q_Q(QQuickTextInput);
2726 QString oldText = m_text;
2728 m_text = maskString(0, txt, true);
2729 m_text += clearString(m_text.length(), m_maxLength - m_text.length());
2731 m_text = txt.isEmpty() ? txt : txt.left(m_maxLength);
2734 m_modifiedState = m_undoState = 0;
2735 m_cursor = (pos < 0 || pos > m_text.length()) ? m_text.length() : pos;
2736 m_textDirty = (oldText != m_text);
2738 bool changed = finishChange(-1, true, edited);
2739 #ifdef QT_NO_ACCESSIBILITY
2743 QAccessible::updateAccessibility(q, 0, QAccessible::TextUpdated);
2751 Adds the given \a command to the undo history
2752 of the line control. Does not apply the command.
2754 void QQuickTextInputPrivate::addCommand(const Command &cmd)
2756 if (m_separator && m_undoState && m_history[m_undoState - 1].type != Separator) {
2757 m_history.resize(m_undoState + 2);
2758 m_history[m_undoState++] = Command(Separator, m_cursor, 0, m_selstart, m_selend);
2760 m_history.resize(m_undoState + 1);
2762 m_separator = false;
2763 m_history[m_undoState++] = cmd;
2769 Inserts the given string \a s into the line
2772 Also adds the appropriate commands into the undo history.
2773 This function does not call finishChange(), and may leave the text
2774 in an invalid state.
2776 void QQuickTextInputPrivate::internalInsert(const QString &s)
2778 if (hasSelectedText())
2779 addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
2781 QString ms = maskString(m_cursor, s);
2782 for (int i = 0; i < (int) ms.length(); ++i) {
2783 addCommand (Command(DeleteSelection, m_cursor + i, m_text.at(m_cursor + i), -1, -1));
2784 addCommand(Command(Insert, m_cursor + i, ms.at(i), -1, -1));
2786 m_text.replace(m_cursor, ms.length(), ms);
2787 m_cursor += ms.length();
2788 m_cursor = nextMaskBlank(m_cursor);
2791 int remaining = m_maxLength - m_text.length();
2792 if (remaining != 0) {
2793 m_text.insert(m_cursor, s.left(remaining));
2794 for (int i = 0; i < (int) s.left(remaining).length(); ++i)
2795 addCommand(Command(Insert, m_cursor++, s.at(i), -1, -1));
2804 deletes a single character from the current text. If \a wasBackspace,
2805 the character prior to the cursor is removed. Otherwise the character
2806 after the cursor is removed.
2808 Also adds the appropriate commands into the undo history.
2809 This function does not call finishChange(), and may leave the text
2810 in an invalid state.
2812 void QQuickTextInputPrivate::internalDelete(bool wasBackspace)
2814 if (m_cursor < (int) m_text.length()) {
2815 if (hasSelectedText())
2816 addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
2817 addCommand(Command((CommandType)((m_maskData ? 2 : 0) + (wasBackspace ? Remove : Delete)),
2818 m_cursor, m_text.at(m_cursor), -1, -1));
2820 m_text.replace(m_cursor, 1, clearString(m_cursor, 1));
2821 addCommand(Command(Insert, m_cursor, m_text.at(m_cursor), -1, -1));
2823 m_text.remove(m_cursor, 1);
2832 removes the currently selected text from the line control.
2834 Also adds the appropriate commands into the undo history.
2835 This function does not call finishChange(), and may leave the text
2836 in an invalid state.
2838 void QQuickTextInputPrivate::removeSelectedText()
2840 if (m_selstart < m_selend && m_selend <= (int) m_text.length()) {
2843 addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
2844 if (m_selstart <= m_cursor && m_cursor < m_selend) {
2845 // cursor is within the selection. Split up the commands
2846 // to be able to restore the correct cursor position
2847 for (i = m_cursor; i >= m_selstart; --i)
2848 addCommand (Command(DeleteSelection, i, m_text.at(i), -1, 1));
2849 for (i = m_selend - 1; i > m_cursor; --i)
2850 addCommand (Command(DeleteSelection, i - m_cursor + m_selstart - 1, m_text.at(i), -1, -1));
2852 for (i = m_selend-1; i >= m_selstart; --i)
2853 addCommand (Command(RemoveSelection, i, m_text.at(i), -1, -1));
2856 m_text.replace(m_selstart, m_selend - m_selstart, clearString(m_selstart, m_selend - m_selstart));
2857 for (int i = 0; i < m_selend - m_selstart; ++i)
2858 addCommand(Command(Insert, m_selstart + i, m_text.at(m_selstart + i), -1, -1));
2860 m_text.remove(m_selstart, m_selend - m_selstart);
2862 if (m_cursor > m_selstart)
2863 m_cursor -= qMin(m_cursor, m_selend) - m_selstart;
2872 Parses the input mask specified by \a maskFields to generate
2873 the mask data used to handle input masks.
2875 void QQuickTextInputPrivate::parseInputMask(const QString &maskFields)
2877 int delimiter = maskFields.indexOf(QLatin1Char(';'));
2878 if (maskFields.isEmpty() || delimiter == 0) {
2880 delete [] m_maskData;
2882 m_maxLength = 32767;
2883 internalSetText(QString());
2888 if (delimiter == -1) {
2889 m_blank = QLatin1Char(' ');
2890 m_inputMask = maskFields;
2892 m_inputMask = maskFields.left(delimiter);
2893 m_blank = (delimiter + 1 < maskFields.length()) ? maskFields[delimiter + 1] : QLatin1Char(' ');
2896 // calculate m_maxLength / m_maskData length
2899 for (int i=0; i<m_inputMask.length(); i++) {
2900 c = m_inputMask.at(i);
2901 if (i > 0 && m_inputMask.at(i-1) == QLatin1Char('\\')) {
2905 if (c != QLatin1Char('\\') && c != QLatin1Char('!') &&
2906 c != QLatin1Char('<') && c != QLatin1Char('>') &&
2907 c != QLatin1Char('{') && c != QLatin1Char('}') &&
2908 c != QLatin1Char('[') && c != QLatin1Char(']'))
2912 delete [] m_maskData;
2913 m_maskData = new MaskInputData[m_maxLength];
2915 MaskInputData::Casemode m = MaskInputData::NoCaseMode;
2918 bool escape = false;
2920 for (int i = 0; i < m_inputMask.length(); i++) {
2921 c = m_inputMask.at(i);
2924 m_maskData[index].maskChar = c;
2925 m_maskData[index].separator = s;
2926 m_maskData[index].caseMode = m;
2929 } else if (c == QLatin1Char('<')) {
2930 m = MaskInputData::Lower;
2931 } else if (c == QLatin1Char('>')) {
2932 m = MaskInputData::Upper;
2933 } else if (c == QLatin1Char('!')) {
2934 m = MaskInputData::NoCaseMode;
2935 } else if (c != QLatin1Char('{') && c != QLatin1Char('}') && c != QLatin1Char('[') && c != QLatin1Char(']')) {
2936 switch (c.unicode()) {
2962 m_maskData[index].maskChar = c;
2963 m_maskData[index].separator = s;
2964 m_maskData[index].caseMode = m;
2969 internalSetText(m_text);
2976 checks if the key is valid compared to the inputMask
2978 bool QQuickTextInputPrivate::isValidInput(QChar key, QChar mask) const
2980 switch (mask.unicode()) {
2986 if (key.isLetter() || key == m_blank)
2990 if (key.isLetterOrNumber())
2994 if (key.isLetterOrNumber() || key == m_blank)
3002 if (key.isPrint() || key == m_blank)
3010 if (key.isNumber() || key == m_blank)
3014 if (key.isNumber() && key.digitValue() > 0)
3018 if ((key.isNumber() && key.digitValue() > 0) || key == m_blank)
3022 if (key.isNumber() || key == QLatin1Char('+') || key == QLatin1Char('-') || key == m_blank)
3026 if (key == QLatin1Char('0') || key == QLatin1Char('1'))
3030 if (key == QLatin1Char('0') || key == QLatin1Char('1') || key == m_blank)
3034 if (key.isNumber() || (key >= QLatin1Char('a') && key <= QLatin1Char('f')) || (key >= QLatin1Char('A') && key <= QLatin1Char('F')))
3038 if (key.isNumber() || (key >= QLatin1Char('a') && key <= QLatin1Char('f')) || (key >= QLatin1Char('A') && key <= QLatin1Char('F')) || key == m_blank)
3050 Returns true if the given text \a str is valid for any
3051 validator or input mask set for the line control.
3053 Otherwise returns false
3055 bool QQuickTextInputPrivate::hasAcceptableInput(const QString &str) const
3057 #ifndef QT_NO_VALIDATOR
3058 QString textCopy = str;
3059 int cursorCopy = m_cursor;
3060 if (m_validator && m_validator->validate(textCopy, cursorCopy)
3061 != QValidator::Acceptable)
3068 if (str.length() != m_maxLength)
3071 for (int i=0; i < m_maxLength; ++i) {
3072 if (m_maskData[i].separator) {
3073 if (str.at(i) != m_maskData[i].maskChar)
3076 if (!isValidInput(str.at(i), m_maskData[i].maskChar))
3086 Applies the inputMask on \a str starting from position \a pos in the mask. \a clear
3087 specifies from where characters should be gotten when a separator is met in \a str - true means
3088 that blanks will be used, false that previous input is used.
3089 Calling this when no inputMask is set is undefined.
3091 QString QQuickTextInputPrivate::maskString(uint pos, const QString &str, bool clear) const
3093 if (pos >= (uint)m_maxLength)
3094 return QString::fromLatin1("");
3097 fill = clear ? clearString(0, m_maxLength) : m_text;
3100 QString s = QString::fromLatin1("");
3102 while (i < m_maxLength) {
3103 if (strIndex < str.length()) {
3104 if (m_maskData[i].separator) {
3105 s += m_maskData[i].maskChar;
3106 if (str[(int)strIndex] == m_maskData[i].maskChar)
3110 if (isValidInput(str[(int)strIndex], m_maskData[i].maskChar)) {
3111 switch (m_maskData[i].caseMode) {
3112 case MaskInputData::Upper:
3113 s += str[(int)strIndex].toUpper();
3115 case MaskInputData::Lower:
3116 s += str[(int)strIndex].toLower();
3119 s += str[(int)strIndex];
3123 // search for separator first
3124 int n = findInMask(i, true, true, str[(int)strIndex]);
3126 if (str.length() != 1 || i == 0 || (i > 0 && (!m_maskData[i-1].separator || m_maskData[i-1].maskChar != str[(int)strIndex]))) {
3127 s += fill.mid(i, n-i+1);
3128 i = n + 1; // update i to find + 1
3131 // search for valid m_blank if not
3132 n = findInMask(i, true, false, str[(int)strIndex]);
3134 s += fill.mid(i, n-i);
3135 switch (m_maskData[n].caseMode) {
3136 case MaskInputData::Upper:
3137 s += str[(int)strIndex].toUpper();
3139 case MaskInputData::Lower:
3140 s += str[(int)strIndex].toLower();
3143 s += str[(int)strIndex];
3145 i = n + 1; // updates i to find + 1
3163 Returns a "cleared" string with only separators and blank chars.
3164 Calling this when no inputMask is set is undefined.
3166 QString QQuickTextInputPrivate::clearString(uint pos, uint len) const
3168 if (pos >= (uint)m_maxLength)
3172 int end = qMin((uint)m_maxLength, pos + len);
3173 for (int i = pos; i < end; ++i)
3174 if (m_maskData[i].separator)
3175 s += m_maskData[i].maskChar;
3185 Strips blank parts of the input in a QQuickTextInputPrivate when an inputMask is set,
3186 separators are still included. Typically "127.0__.0__.1__" becomes "127.0.0.1".
3188 QString QQuickTextInputPrivate::stripString(const QString &str) const
3194 int end = qMin(m_maxLength, (int)str.length());
3195 for (int i = 0; i < end; ++i)
3196 if (m_maskData[i].separator)
3197 s += m_maskData[i].maskChar;
3199 if (str[i] != m_blank)
3207 searches forward/backward in m_maskData for either a separator or a m_blank
3209 int QQuickTextInputPrivate::findInMask(int pos, bool forward, bool findSeparator, QChar searchChar) const
3211 if (pos >= m_maxLength || pos < 0)
3214 int end = forward ? m_maxLength : -1;
3215 int step = forward ? 1 : -1;
3219 if (findSeparator) {
3220 if (m_maskData[i].separator && m_maskData[i].maskChar == searchChar)
3223 if (!m_maskData[i].separator) {
3224 if (searchChar.isNull())
3226 else if (isValidInput(searchChar, m_maskData[i].maskChar))
3235 void QQuickTextInputPrivate::internalUndo(int until)
3237 if (!isUndoAvailable())
3240 while (m_undoState && m_undoState > until) {
3241 Command& cmd = m_history[--m_undoState];
3244 m_text.remove(cmd.pos, 1);
3248 m_selstart = cmd.selStart;
3249 m_selend = cmd.selEnd;
3253 case RemoveSelection:
3254 m_text.insert(cmd.pos, cmd.uc);
3255 m_cursor = cmd.pos + 1;
3258 case DeleteSelection:
3259 m_text.insert(cmd.pos, cmd.uc);
3265 if (until < 0 && m_undoState) {
3266 Command& next = m_history[m_undoState-1];
3267 if (next.type != cmd.type && next.type < RemoveSelection
3268 && (cmd.type < RemoveSelection || next.type == Separator))
3273 emitCursorPositionChanged();
3276 void QQuickTextInputPrivate::internalRedo()
3278 if (!isRedoAvailable())
3281 while (m_undoState < (int)m_history.size()) {
3282 Command& cmd = m_history[m_undoState++];
3285 m_text.insert(cmd.pos, cmd.uc);
3286 m_cursor = cmd.pos + 1;
3289 m_selstart = cmd.selStart;
3290 m_selend = cmd.selEnd;
3295 case RemoveSelection:
3296 case DeleteSelection:
3297 m_text.remove(cmd.pos, 1);
3298 m_selstart = cmd.selStart;
3299 m_selend = cmd.selEnd;
3303 m_selstart = cmd.selStart;
3304 m_selend = cmd.selEnd;
3308 if (m_undoState < (int)m_history.size()) {
3309 Command& next = m_history[m_undoState];
3310 if (next.type != cmd.type && cmd.type < RemoveSelection && next.type != Separator
3311 && (next.type < RemoveSelection || cmd.type == Separator))
3316 emitCursorPositionChanged();
3322 If the current cursor position differs from the last emitted cursor
3323 position, emits cursorPositionChanged().
3325 void QQuickTextInputPrivate::emitCursorPositionChanged()
3327 Q_Q(QQuickTextInput);
3328 if (m_cursor != m_lastCursorPos) {
3329 m_lastCursorPos = m_cursor;
3331 q->updateCursorRectangle();
3332 emit q->cursorPositionChanged();
3333 // XXX todo - not in 4.8?
3335 resetCursorBlinkTimer();
3338 if (!hasSelectedText()) {
3339 if (lastSelectionStart != m_cursor) {
3340 lastSelectionStart = m_cursor;
3341 emit q->selectionStartChanged();
3343 if (lastSelectionEnd != m_cursor) {
3344 lastSelectionEnd = m_cursor;
3345 emit q->selectionEndChanged();
3349 #ifndef QT_NO_ACCESSIBILITY
3350 QAccessible::updateAccessibility(q, 0, QAccessible::TextCaretMoved);
3356 void QQuickTextInputPrivate::setCursorBlinkPeriod(int msec)
3358 Q_Q(QQuickTextInput);
3359 if (msec == m_blinkPeriod)
3362 q->killTimer(m_blinkTimer);
3365 m_blinkTimer = q->startTimer(msec / 2);
3369 if (m_blinkStatus == 1)
3370 emit q->updateRect(inputMask().isEmpty() ? q->cursorRectangle() : QRect());
3372 m_blinkPeriod = msec;
3375 void QQuickTextInputPrivate::resetCursorBlinkTimer()
3377 Q_Q(QQuickTextInput);
3378 if (m_blinkPeriod == 0 || m_blinkTimer == 0)
3380 q->killTimer(m_blinkTimer);
3381 m_blinkTimer = q->startTimer(m_blinkPeriod / 2);
3385 void QQuickTextInput::timerEvent(QTimerEvent *event)
3387 Q_D(QQuickTextInput);
3388 if (event->timerId() == d->m_blinkTimer) {
3389 d->m_blinkStatus = !d->m_blinkStatus;
3390 updateRect(inputMask().isEmpty() ? cursorRectangle() : QRect());
3391 } else if (event->timerId() == d->m_deleteAllTimer) {
3392 killTimer(d->m_deleteAllTimer);
3393 d->m_deleteAllTimer = 0;
3398 void QQuickTextInputPrivate::processKeyEvent(QKeyEvent* event)
3400 Q_Q(QQuickTextInput);
3401 bool inlineCompletionAccepted = false;
3403 if (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return) {
3404 if (hasAcceptableInput(m_text) || fixup()) {
3407 if (inlineCompletionAccepted)
3414 if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit
3415 && !m_passwordEchoEditing
3417 && !event->text().isEmpty()
3418 && !(event->modifiers() & Qt::ControlModifier)) {
3419 // Clear the edit and reset to normal echo mode while editing; the
3420 // echo mode switches back when the edit loses focus
3421 // ### resets current content. dubious code; you can
3422 // navigate with keys up, down, back, and select(?), but if you press
3423 // "left" or "right" it clears?
3424 updatePasswordEchoEditing(true);
3428 bool unknown = false;
3429 bool visual = cursorMoveStyle() == Qt::VisualMoveStyle;
3433 #ifndef QT_NO_SHORTCUT
3434 else if (event == QKeySequence::Undo) {
3438 else if (event == QKeySequence::Redo) {
3442 else if (event == QKeySequence::SelectAll) {
3445 #ifndef QT_NO_CLIPBOARD
3446 else if (event == QKeySequence::Copy) {
3449 else if (event == QKeySequence::Paste) {
3451 QClipboard::Mode mode = QClipboard::Clipboard;
3455 else if (event == QKeySequence::Cut) {
3461 else if (event == QKeySequence::DeleteEndOfLine) {
3463 setSelection(m_cursor, end());
3468 #endif //QT_NO_CLIPBOARD
3469 else if (event == QKeySequence::MoveToStartOfLine || event == QKeySequence::MoveToStartOfBlock) {
3472 else if (event == QKeySequence::MoveToEndOfLine || event == QKeySequence::MoveToEndOfBlock) {
3475 else if (event == QKeySequence::SelectStartOfLine || event == QKeySequence::SelectStartOfBlock) {
3478 else if (event == QKeySequence::SelectEndOfLine || event == QKeySequence::SelectEndOfBlock) {
3481 else if (event == QKeySequence::MoveToNextChar) {
3482 if (hasSelectedText()) {
3483 moveCursor(selectionEnd(), false);
3485 cursorForward(0, visual ? 1 : (layoutDirection() == Qt::LeftToRight ? 1 : -1));
3488 else if (event == QKeySequence::SelectNextChar) {
3489 cursorForward(1, visual ? 1 : (layoutDirection() == Qt::LeftToRight ? 1 : -1));
3491 else if (event == QKeySequence::MoveToPreviousChar) {
3492 if (hasSelectedText()) {
3493 moveCursor(selectionStart(), false);
3495 cursorForward(0, visual ? -1 : (layoutDirection() == Qt::LeftToRight ? -1 : 1));
3498 else if (event == QKeySequence::SelectPreviousChar) {
3499 cursorForward(1, visual ? -1 : (layoutDirection() == Qt::LeftToRight ? -1 : 1));
3501 else if (event == QKeySequence::MoveToNextWord) {
3502 if (m_echoMode == QQuickTextInput::Normal)
3503 layoutDirection() == Qt::LeftToRight ? cursorWordForward(0) : cursorWordBackward(0);
3505 layoutDirection() == Qt::LeftToRight ? end(0) : home(0);
3507 else if (event == QKeySequence::MoveToPreviousWord) {
3508 if (m_echoMode == QQuickTextInput::Normal)
3509 layoutDirection() == Qt::LeftToRight ? cursorWordBackward(0) : cursorWordForward(0);
3510 else if (!m_readOnly) {
3511 layoutDirection() == Qt::LeftToRight ? home(0) : end(0);
3514 else if (event == QKeySequence::SelectNextWord) {
3515 if (m_echoMode == QQuickTextInput::Normal)
3516 layoutDirection() == Qt::LeftToRight ? cursorWordForward(1) : cursorWordBackward(1);
3518 layoutDirection() == Qt::LeftToRight ? end(1) : home(1);
3520 else if (event == QKeySequence::SelectPreviousWord) {
3521 if (m_echoMode == QQuickTextInput::Normal)
3522 layoutDirection() == Qt::LeftToRight ? cursorWordBackward(1) : cursorWordForward(1);
3524 layoutDirection() == Qt::LeftToRight ? home(1) : end(1);
3526 else if (event == QKeySequence::Delete) {
3530 else if (event == QKeySequence::DeleteEndOfWord) {
3532 cursorWordForward(true);
3536 else if (event == QKeySequence::DeleteStartOfWord) {
3538 cursorWordBackward(true);
3542 #endif // QT_NO_SHORTCUT
3544 bool handled = false;
3545 if (event->modifiers() & Qt::ControlModifier) {
3546 switch (event->key()) {
3547 case Qt::Key_Backspace:
3549 cursorWordBackward(true);
3557 } else { // ### check for *no* modifier
3558 switch (event->key()) {
3559 case Qt::Key_Backspace:
3571 if (event->key() == Qt::Key_Direction_L || event->key() == Qt::Key_Direction_R) {
3572 setLayoutDirection((event->key() == Qt::Key_Direction_L) ? Qt::LeftToRight : Qt::RightToLeft);
3576 if (unknown && !m_readOnly) {
3577 QString t = event->text();
3578 if (!t.isEmpty() && t.at(0).isPrint()) {