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 = qMax(0, qFloor(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 Q_ASSERT(currentLine.isValid());
1423 int cix = qRound(currentLine.cursorToX(m_cursor + preeditLength));
1424 if (cix - hscroll >= width) {
1425 // text doesn't fit, cursor is to the right of br (scroll right)
1426 hscroll = cix - width;
1427 } else if (cix - hscroll < 0 && hscroll < widthUsed) {
1428 // text doesn't fit, cursor is to the left of br (scroll left)
1430 } else if (widthUsed - hscroll < width) {
1431 // text doesn't fit, text document is to the left of br; align
1433 hscroll = widthUsed - width;
1435 if (preeditLength > 0) {
1436 // check to ensure long pre-edit text doesn't push the cursor
1438 cix = qRound(currentLine.cursorToX(m_cursor + qMax(0, m_preeditCursor - 1)));
1443 if (previousScroll != hscroll)
1444 textLayoutDirty = true;
1447 void QQuickTextInputPrivate::updateVerticalScroll()
1449 Q_Q(QQuickTextInput);
1450 const int preeditLength = m_textLayout.preeditAreaText().length();
1451 const int height = qMax(0, qFloor(q->height()));
1452 int heightUsed = boundingRect.height();
1453 int previousScroll = vscroll;
1455 if (!autoScroll || heightUsed <= height) {
1456 // text fits in br; use vscroll for alignment
1457 switch (vAlign & ~(Qt::AlignAbsolute|Qt::AlignHorizontal_Mask)) {
1458 case Qt::AlignBottom:
1459 vscroll = heightUsed - height;
1461 case Qt::AlignVCenter:
1462 vscroll = (heightUsed - height) / 2;
1470 QTextLine currentLine = m_textLayout.lineForTextPosition(m_cursor + preeditLength);
1471 QRectF r = currentLine.isValid() ? currentLine.rect() : QRectF();
1472 int top = qFloor(r.top());
1473 int bottom = qCeil(r.bottom());
1475 if (bottom - vscroll >= height) {
1476 // text doesn't fit, cursor is to the below the br (scroll down)
1477 vscroll = bottom - height;
1478 } else if (top - vscroll < 0 && vscroll < heightUsed) {
1479 // text doesn't fit, cursor is above br (scroll up)
1481 } else if (heightUsed - vscroll < height) {
1482 // text doesn't fit, text document is to the left of br; align
1484 vscroll = heightUsed - height;
1486 if (preeditLength > 0) {
1487 // check to ensure long pre-edit text doesn't push the cursor
1489 currentLine = m_textLayout.lineForTextPosition(m_cursor + qMax(0, m_preeditCursor - 1));
1490 top = currentLine.isValid() ? qRound(currentLine.rect().top()) : 0;
1495 if (previousScroll != vscroll)
1496 textLayoutDirty = true;
1499 QSGNode *QQuickTextInput::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data)
1502 Q_D(QQuickTextInput);
1504 QQuickTextNode *node = static_cast<QQuickTextNode *>(oldNode);
1506 node = new QQuickTextNode(QQuickItemPrivate::get(this)->sceneGraphContext());
1509 if (!d->textLayoutDirty) {
1510 QSGSimpleRectNode *cursorNode = node->cursorNode();
1511 if (cursorNode != 0 && !isReadOnly()) {
1512 cursorNode->setRect(cursorRectangle());
1514 if (!d->cursorVisible || (!d->m_blinkStatus && d->m_blinkPeriod > 0)) {
1521 node->deleteContent();
1522 node->setMatrix(QMatrix4x4());
1524 QPoint offset = QPoint(0,0);
1525 QFontMetrics fm = QFontMetrics(d->font);
1526 if (d->autoScroll) {
1527 // the y offset is there to keep the baseline constant in case we have script changes in the text.
1528 offset = -QPoint(d->hscroll, d->vscroll + d->m_ascent - fm.ascent());
1530 offset = -QPoint(d->hscroll, d->vscroll);
1533 if (!d->m_textLayout.text().isEmpty()) {
1534 node->addTextLayout(offset, &d->m_textLayout, d->color,
1535 QQuickText::Normal, QColor(),
1536 d->selectionColor, d->selectedTextColor,
1537 d->selectionStart(),
1538 d->selectionEnd() - 1); // selectionEnd() returns first char after
1542 if (!isReadOnly() && d->cursorItem == 0) {
1543 node->setCursor(cursorRectangle(), d->color);
1544 if (!d->cursorVisible || (!d->m_blinkStatus && d->m_blinkPeriod > 0)) {
1551 d->textLayoutDirty = false;
1557 QVariant QQuickTextInput::inputMethodQuery(Qt::InputMethodQuery property) const
1559 Q_D(const QQuickTextInput);
1562 return QVariant((bool)(flags() & ItemAcceptsInputMethod));
1564 return QVariant((int)inputMethodHints());
1565 case Qt::ImCursorRectangle:
1566 return cursorRectangle();
1569 case Qt::ImCursorPosition:
1570 return QVariant(d->m_cursor);
1571 case Qt::ImSurroundingText:
1572 if (d->m_echoMode == PasswordEchoOnEdit && !d->m_passwordEchoEditing) {
1573 return QVariant(displayText());
1575 return QVariant(d->realText());
1577 case Qt::ImCurrentSelection:
1578 return QVariant(selectedText());
1579 case Qt::ImMaximumTextLength:
1580 return QVariant(maxLength());
1581 case Qt::ImAnchorPosition:
1582 if (d->selectionStart() == d->selectionEnd())
1583 return QVariant(d->m_cursor);
1584 else if (d->selectionStart() == d->m_cursor)
1585 return QVariant(d->selectionEnd());
1587 return QVariant(d->selectionStart());
1594 \qmlmethod void QtQuick2::TextInput::deselect()
1596 Removes active text selection.
1598 void QQuickTextInput::deselect()
1600 Q_D(QQuickTextInput);
1605 \qmlmethod void QtQuick2::TextInput::selectAll()
1607 Causes all text to be selected.
1609 void QQuickTextInput::selectAll()
1611 Q_D(QQuickTextInput);
1612 d->setSelection(0, text().length());
1616 \qmlmethod void QtQuick2::TextInput::isRightToLeft(int start, int end)
1618 Returns true if the natural reading direction of the editor text
1619 found between positions \a start and \a end is right to left.
1621 bool QQuickTextInput::isRightToLeft(int start, int end)
1624 qmlInfo(this) << "isRightToLeft(start, end) called with the end property being smaller than the start.";
1627 return text().mid(start, end - start).isRightToLeft();
1631 #ifndef QT_NO_CLIPBOARD
1633 \qmlmethod QtQuick2::TextInput::cut()
1635 Moves the currently selected text to the system clipboard.
1637 void QQuickTextInput::cut()
1639 Q_D(QQuickTextInput);
1645 \qmlmethod QtQuick2::TextInput::copy()
1647 Copies the currently selected text to the system clipboard.
1649 void QQuickTextInput::copy()
1651 Q_D(QQuickTextInput);
1656 \qmlmethod QtQuick2::TextInput::paste()
1658 Replaces the currently selected text by the contents of the system clipboard.
1660 void QQuickTextInput::paste()
1662 Q_D(QQuickTextInput);
1666 #endif // QT_NO_CLIPBOARD
1669 \qmlmethod void QtQuick2::TextInput::selectWord()
1671 Causes the word closest to the current cursor position to be selected.
1673 void QQuickTextInput::selectWord()
1675 Q_D(QQuickTextInput);
1676 d->selectWordAtPos(d->m_cursor);
1680 \qmlproperty bool QtQuick2::TextInput::smooth
1682 This property holds whether the text is smoothly scaled or transformed.
1684 Smooth filtering gives better visual quality, but is slower. If
1685 the item is displayed at its natural size, this property has no visual or
1688 \note Generally scaling artifacts are only visible if the item is stationary on
1689 the screen. A common pattern when animating an item is to disable smooth
1690 filtering at the beginning of the animation and reenable it at the conclusion.
1694 \qmlproperty string QtQuick2::TextInput::passwordCharacter
1696 This is the character displayed when echoMode is set to Password or
1697 PasswordEchoOnEdit. By default it is an asterisk.
1699 If this property is set to a string with more than one character,
1700 the first character is used. If the string is empty, the value
1701 is ignored and the property is not set.
1703 QString QQuickTextInput::passwordCharacter() const
1705 Q_D(const QQuickTextInput);
1706 return QString(d->m_passwordCharacter);
1709 void QQuickTextInput::setPasswordCharacter(const QString &str)
1711 Q_D(QQuickTextInput);
1712 if (str.length() < 1)
1714 d->m_passwordCharacter = str.constData()[0];
1715 if (d->m_echoMode == Password || d->m_echoMode == PasswordEchoOnEdit)
1716 d->updateDisplayText();
1717 emit passwordCharacterChanged();
1721 \qmlproperty string QtQuick2::TextInput::displayText
1723 This is the text displayed in the TextInput.
1725 If \l echoMode is set to TextInput::Normal, this holds the
1726 same value as the TextInput::text property. Otherwise,
1727 this property holds the text visible to the user, while
1728 the \l text property holds the actual entered text.
1730 QString QQuickTextInput::displayText() const
1732 Q_D(const QQuickTextInput);
1733 return d->m_textLayout.text();
1737 \qmlproperty bool QtQuick2::TextInput::selectByMouse
1741 If true, the user can use the mouse to select text in some
1742 platform-specific way. Note that for some platforms this may
1743 not be an appropriate interaction (eg. may conflict with how
1744 the text needs to behave inside a Flickable.
1746 bool QQuickTextInput::selectByMouse() const
1748 Q_D(const QQuickTextInput);
1749 return d->selectByMouse;
1752 void QQuickTextInput::setSelectByMouse(bool on)
1754 Q_D(QQuickTextInput);
1755 if (d->selectByMouse != on) {
1756 d->selectByMouse = on;
1757 emit selectByMouseChanged(on);
1762 \qmlproperty enum QtQuick2::TextInput::mouseSelectionMode
1764 Specifies how text should be selected using a mouse.
1767 \o TextInput.SelectCharacters - The selection is updated with individual characters. (Default)
1768 \o TextInput.SelectWords - The selection is updated with whole words.
1771 This property only applies when \l selectByMouse is true.
1774 QQuickTextInput::SelectionMode QQuickTextInput::mouseSelectionMode() const
1776 Q_D(const QQuickTextInput);
1777 return d->mouseSelectionMode;
1780 void QQuickTextInput::setMouseSelectionMode(SelectionMode mode)
1782 Q_D(QQuickTextInput);
1783 if (d->mouseSelectionMode != mode) {
1784 d->mouseSelectionMode = mode;
1785 emit mouseSelectionModeChanged(mode);
1790 \qmlproperty bool QtQuick2::TextInput::canPaste
1792 Returns true if the TextInput is writable and the content of the clipboard is
1793 suitable for pasting into the TextEdit.
1795 bool QQuickTextInput::canPaste() const
1797 Q_D(const QQuickTextInput);
1798 if (!d->canPasteValid) {
1799 if (const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData())
1800 const_cast<QQuickTextInputPrivate *>(d)->canPaste = !d->m_readOnly && mimeData->hasText();
1801 const_cast<QQuickTextInputPrivate *>(d)->canPasteValid = true;
1806 void QQuickTextInput::moveCursorSelection(int position)
1808 Q_D(QQuickTextInput);
1809 d->moveCursor(position, true);
1813 \qmlmethod void QtQuick2::TextInput::moveCursorSelection(int position, SelectionMode mode = TextInput.SelectCharacters)
1815 Moves the cursor to \a position and updates the selection according to the optional \a mode
1816 parameter. (To only move the cursor, set the \l cursorPosition property.)
1818 When this method is called it additionally sets either the
1819 selectionStart or the selectionEnd (whichever was at the previous cursor position)
1820 to the specified position. This allows you to easily extend and contract the selected
1823 The selection mode specifies whether the selection is updated on a per character or a per word
1824 basis. If not specified the selection mode will default to TextInput.SelectCharacters.
1827 \o TextEdit.SelectCharacters - Sets either the selectionStart or selectionEnd (whichever was at
1828 the previous cursor position) to the specified position.
1829 \o TextEdit.SelectWords - Sets the selectionStart and selectionEnd to include all
1830 words between the specified position and the previous cursor position. Words partially in the
1834 For example, take this sequence of calls:
1838 moveCursorSelection(9, TextInput.SelectCharacters)
1839 moveCursorSelection(7, TextInput.SelectCharacters)
1842 This moves the cursor to position 5, extend the selection end from 5 to 9
1843 and then retract the selection end from 9 to 7, leaving the text from position 5 to 7
1844 selected (the 6th and 7th characters).
1846 The same sequence with TextInput.SelectWords will extend the selection start to a word boundary
1847 before or on position 5 and extend the selection end to a word boundary on or past position 9.
1849 void QQuickTextInput::moveCursorSelection(int pos, SelectionMode mode)
1851 Q_D(QQuickTextInput);
1853 if (mode == SelectCharacters) {
1854 d->moveCursor(pos, true);
1855 } else if (pos != d->m_cursor){
1856 const int cursor = d->m_cursor;
1858 if (!d->hasSelectedText())
1859 anchor = d->m_cursor;
1860 else if (d->selectionStart() == d->m_cursor)
1861 anchor = d->selectionEnd();
1863 anchor = d->selectionStart();
1865 if (anchor < pos || (anchor == pos && cursor < pos)) {
1866 const QString text = this->text();
1867 QTextBoundaryFinder finder(QTextBoundaryFinder::Word, text);
1868 finder.setPosition(anchor);
1870 const QTextBoundaryFinder::BoundaryReasons reasons = finder.boundaryReasons();
1871 if (anchor < text.length() && (!(reasons & QTextBoundaryFinder::StartWord)
1872 || ((reasons & QTextBoundaryFinder::EndWord) && anchor > cursor))) {
1873 finder.toPreviousBoundary();
1875 anchor = finder.position() != -1 ? finder.position() : 0;
1877 finder.setPosition(pos);
1878 if (pos > 0 && !finder.boundaryReasons())
1879 finder.toNextBoundary();
1880 const int cursor = finder.position() != -1 ? finder.position() : text.length();
1882 d->setSelection(anchor, cursor - anchor);
1883 } else if (anchor > pos || (anchor == pos && cursor > pos)) {
1884 const QString text = this->text();
1885 QTextBoundaryFinder finder(QTextBoundaryFinder::Word, text);
1886 finder.setPosition(anchor);
1888 const QTextBoundaryFinder::BoundaryReasons reasons = finder.boundaryReasons();
1889 if (anchor > 0 && (!(reasons & QTextBoundaryFinder::EndWord)
1890 || ((reasons & QTextBoundaryFinder::StartWord) && anchor < cursor))) {
1891 finder.toNextBoundary();
1894 anchor = finder.position() != -1 ? finder.position() : text.length();
1896 finder.setPosition(pos);
1897 if (pos < text.length() && !finder.boundaryReasons())
1898 finder.toPreviousBoundary();
1899 const int cursor = finder.position() != -1 ? finder.position() : 0;
1901 d->setSelection(anchor, cursor - anchor);
1907 \qmlmethod void QtQuick2::TextInput::openSoftwareInputPanel()
1909 Opens software input panels like virtual keyboards for typing, useful for
1910 customizing when you want the input keyboard to be shown and hidden in
1913 By default the opening of input panels follows the platform style. Input panels are
1914 always closed if no editor has active focus.
1916 You can disable the automatic behavior by setting the property \c activeFocusOnPress to false
1917 and use functions openSoftwareInputPanel() and closeSoftwareInputPanel() to implement
1918 the behavior you want.
1920 Only relevant on platforms, which provide virtual keyboards.
1926 text: "Hello world!"
1927 activeFocusOnPress: false
1929 anchors.fill: parent
1931 if (!textInput.activeFocus) {
1932 textInput.forceActiveFocus()
1933 textInput.openSoftwareInputPanel();
1935 textInput.focus = false;
1938 onPressAndHold: textInput.closeSoftwareInputPanel();
1943 void QQuickTextInput::openSoftwareInputPanel()
1946 qGuiApp->inputPanel()->show();
1950 \qmlmethod void QtQuick2::TextInput::closeSoftwareInputPanel()
1952 Closes a software input panel like a virtual keyboard shown on the screen, useful
1953 for customizing when you want the input keyboard to be shown and hidden in
1956 By default the opening of input panels follows the platform style. Input panels are
1957 always closed if no editor has active focus.
1959 You can disable the automatic behavior by setting the property \c activeFocusOnPress to false
1960 and use functions openSoftwareInputPanel() and closeSoftwareInputPanel() to implement
1961 the behavior you want.
1963 Only relevant on platforms, which provide virtual keyboards.
1969 text: "Hello world!"
1970 activeFocusOnPress: false
1972 anchors.fill: parent
1974 if (!textInput.activeFocus) {
1975 textInput.forceActiveFocus();
1976 textInput.openSoftwareInputPanel();
1978 textInput.focus = false;
1981 onPressAndHold: textInput.closeSoftwareInputPanel();
1986 void QQuickTextInput::closeSoftwareInputPanel()
1989 qGuiApp->inputPanel()->hide();
1992 void QQuickTextInput::focusInEvent(QFocusEvent *event)
1994 Q_D(const QQuickTextInput);
1995 if (d->focusOnPress && !d->m_readOnly)
1996 openSoftwareInputPanel();
1997 QQuickImplicitSizeItem::focusInEvent(event);
2000 void QQuickTextInput::itemChange(ItemChange change, const ItemChangeData &value)
2002 Q_D(QQuickTextInput);
2003 if (change == ItemActiveFocusHasChanged) {
2004 bool hasFocus = value.boolValue;
2005 d->focused = hasFocus;
2006 setCursorVisible(hasFocus); // ### refactor: && d->canvas && d->canvas->hasFocus()
2007 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
2008 if (!hasFocus && (d->m_passwordEchoEditing || d->m_passwordEchoTimer.isActive())) {
2010 if (!hasFocus && d->m_passwordEchoEditing) {
2012 d->updatePasswordEchoEditing(false);//QQuickTextInputPrivate sets it on key events, but doesn't deal with focus events
2020 QQuickItem::itemChange(change, value);
2024 \qmlproperty bool QtQuick2::TextInput::inputMethodComposing
2027 This property holds whether the TextInput has partial text input from an
2030 While it is composing an input method may rely on mouse or key events from
2031 the TextInput to edit or commit the partial text. This property can be
2032 used to determine when to disable events handlers that may interfere with
2033 the correct operation of an input method.
2035 bool QQuickTextInput::isInputMethodComposing() const
2037 Q_D(const QQuickTextInput);
2038 return d->preeditAreaText().length() > 0;
2041 void QQuickTextInputPrivate::init()
2043 Q_Q(QQuickTextInput);
2044 q->setSmooth(smooth);
2045 q->setAcceptedMouseButtons(Qt::LeftButton);
2046 q->setFlag(QQuickItem::ItemAcceptsInputMethod);
2047 q->setFlag(QQuickItem::ItemHasContents);
2048 #ifndef QT_NO_CLIPBOARD
2049 q->connect(QGuiApplication::clipboard(), SIGNAL(dataChanged()),
2050 q, SLOT(q_canPasteChanged()));
2051 #endif // QT_NO_CLIPBOARD
2053 oldValidity = hasAcceptableInput(m_text);
2054 lastSelectionStart = 0;
2055 lastSelectionEnd = 0;
2056 selectedTextColor = m_palette.color(QPalette::HighlightedText);
2057 selectionColor = m_palette.color(QPalette::Highlight);
2058 determineHorizontalAlignment();
2060 if (!qmlDisableDistanceField()) {
2061 QTextOption option = m_textLayout.textOption();
2062 option.setUseDesignMetrics(true);
2063 m_textLayout.setTextOption(option);
2067 void QQuickTextInput::updateCursorRectangle()
2069 Q_D(QQuickTextInput);
2070 if (!isComponentComplete())
2073 d->updateHorizontalScroll();
2074 d->updateVerticalScroll();
2077 emit cursorRectangleChanged();
2078 if (d->cursorItem) {
2079 QRectF r = cursorRectangle();
2080 d->cursorItem->setPos(r.topLeft());
2081 d->cursorItem->setHeight(r.height());
2085 void QQuickTextInput::selectionChanged()
2087 Q_D(QQuickTextInput);
2088 d->textLayoutDirty = true; //TODO: Only update rect in selection
2090 emit selectedTextChanged();
2092 if (d->lastSelectionStart != d->selectionStart()) {
2093 d->lastSelectionStart = d->selectionStart();
2094 if (d->lastSelectionStart == -1)
2095 d->lastSelectionStart = d->m_cursor;
2096 emit selectionStartChanged();
2098 if (d->lastSelectionEnd != d->selectionEnd()) {
2099 d->lastSelectionEnd = d->selectionEnd();
2100 if (d->lastSelectionEnd == -1)
2101 d->lastSelectionEnd = d->m_cursor;
2102 emit selectionEndChanged();
2106 void QQuickTextInputPrivate::showCursor()
2108 if (textNode != 0 && textNode->cursorNode() != 0)
2109 textNode->cursorNode()->setColor(color);
2112 void QQuickTextInputPrivate::hideCursor()
2114 if (textNode != 0 && textNode->cursorNode() != 0)
2115 textNode->cursorNode()->setColor(QColor(0, 0, 0, 0));
2118 QRectF QQuickTextInput::boundingRect() const
2120 Q_D(const QQuickTextInput);
2122 QRectF r = d->boundingRect;
2123 int cursorWidth = d->cursorItem ? d->cursorItem->width() : d->m_cursorWidth;
2125 // Could include font max left/right bearings to either side of rectangle.
2127 r.setRight(r.right() + cursorWidth);
2128 r.translate(-d->hscroll, -d->vscroll);
2132 void QQuickTextInput::q_canPasteChanged()
2134 Q_D(QQuickTextInput);
2135 bool old = d->canPaste;
2136 #ifndef QT_NO_CLIPBOARD
2137 if (const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData())
2138 d->canPaste = !d->m_readOnly && mimeData->hasText();
2140 d->canPaste = false;
2143 bool changed = d->canPaste != old || !d->canPasteValid;
2144 d->canPasteValid = true;
2146 emit canPasteChanged();
2150 // ### these should come from QStyleHints
2151 const int textCursorWidth = 1;
2152 const bool fullWidthSelection = true;
2157 Updates the display text based of the current edit text
2158 If the text has changed will emit displayTextChanged()
2160 void QQuickTextInputPrivate::updateDisplayText(bool forceUpdate)
2162 QString orig = m_textLayout.text();
2164 if (m_echoMode == QQuickTextInput::NoEcho)
2165 str = QString::fromLatin1("");
2169 if (m_echoMode == QQuickTextInput::Password) {
2170 str.fill(m_passwordCharacter);
2171 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
2172 if (m_passwordEchoTimer.isActive() && m_cursor > 0 && m_cursor <= m_text.length()) {
2173 int cursor = m_cursor - 1;
2174 QChar uc = m_text.at(cursor);
2176 if (cursor > 0 && uc.unicode() >= 0xdc00 && uc.unicode() < 0xe000) {
2177 // second half of a surrogate, check if we have the first half as well,
2178 // if yes restore both at once
2179 uc = m_text.at(cursor - 1);
2180 if (uc.unicode() >= 0xd800 && uc.unicode() < 0xdc00)
2181 str[cursor - 1] = uc;
2185 } else if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit && !m_passwordEchoEditing) {
2186 str.fill(m_passwordCharacter);
2189 // replace certain non-printable characters with spaces (to avoid
2190 // drawing boxes when using fonts that don't have glyphs for such
2192 QChar* uc = str.data();
2193 for (int i = 0; i < (int)str.length(); ++i) {
2194 if ((uc[i] < 0x20 && uc[i] != 0x09)
2195 || uc[i] == QChar::LineSeparator
2196 || uc[i] == QChar::ParagraphSeparator
2197 || uc[i] == QChar::ObjectReplacementCharacter)
2198 uc[i] = QChar(0x0020);
2201 if (str != orig || forceUpdate) {
2202 m_textLayout.setText(str);
2203 updateLayout(); // polish?
2204 emit q_func()->displayTextChanged();
2208 void QQuickTextInputPrivate::updateLayout()
2210 Q_Q(QQuickTextInput);
2212 if (!q->isComponentComplete())
2215 QTextOption option = m_textLayout.textOption();
2216 option.setTextDirection(m_layoutDirection);
2217 option.setFlags(QTextOption::IncludeTrailingSpaces);
2218 option.setWrapMode(QTextOption::WrapMode(wrapMode));
2219 option.setAlignment(Qt::Alignment(q->effectiveHAlign()));
2220 m_textLayout.setTextOption(option);
2221 m_textLayout.setFont(font);
2223 boundingRect = QRectF();
2224 m_textLayout.beginLayout();
2225 QTextLine line = m_textLayout.createLine();
2226 qreal lineWidth = q->widthValid() ? q->width() : INT_MAX;
2228 QTextLine firstLine = line;
2230 line.setLineWidth(lineWidth);
2231 line.setPosition(QPointF(line.position().x(), height));
2232 boundingRect = boundingRect.united(line.naturalTextRect());
2234 height += line.height();
2235 line = m_textLayout.createLine();
2236 } while (line.isValid());
2237 m_textLayout.endLayout();
2239 option.setWrapMode(QTextOption::NoWrap);
2240 m_textLayout.setTextOption(option);
2242 m_ascent = qRound(firstLine.ascent());
2243 textLayoutDirty = true;
2246 q->setImplicitSize(qCeil(boundingRect.width()), qCeil(boundingRect.height()));
2250 #ifndef QT_NO_CLIPBOARD
2254 Copies the currently selected text into the clipboard using the given
2257 \note If the echo mode is set to a mode other than Normal then copy
2258 will not work. This is to prevent using copy as a method of bypassing
2259 password features of the line control.
2261 void QQuickTextInputPrivate::copy(QClipboard::Mode mode) const
2263 QString t = selectedText();
2264 if (!t.isEmpty() && m_echoMode == QQuickTextInput::Normal) {
2265 QGuiApplication::clipboard()->setText(t, mode);
2272 Inserts the text stored in the application clipboard into the line
2277 void QQuickTextInputPrivate::paste(QClipboard::Mode clipboardMode)
2279 QString clip = QGuiApplication::clipboard()->text(clipboardMode);
2280 if (!clip.isEmpty() || hasSelectedText()) {
2281 separate(); //make it a separate undo/redo command
2287 #endif // !QT_NO_CLIPBOARD
2292 Exits preedit mode and commits parts marked as tentative commit
2294 void QQuickTextInputPrivate::commitPreedit()
2299 qApp->inputPanel()->reset();
2301 if (!m_tentativeCommit.isEmpty()) {
2302 internalInsert(m_tentativeCommit);
2303 m_tentativeCommit.clear();
2304 finishChange(-1, true/*not used, not documented*/, false);
2307 m_preeditCursor = 0;
2308 m_textLayout.setPreeditArea(-1, QString());
2309 m_textLayout.clearAdditionalFormats();
2316 Handles the behavior for the backspace key or function.
2317 Removes the current selection if there is a selection, otherwise
2318 removes the character prior to the cursor position.
2322 void QQuickTextInputPrivate::backspace()
2324 int priorState = m_undoState;
2325 if (hasSelectedText()) {
2326 removeSelectedText();
2327 } else if (m_cursor) {
2330 m_cursor = prevMaskBlank(m_cursor);
2331 QChar uc = m_text.at(m_cursor);
2332 if (m_cursor > 0 && uc.unicode() >= 0xdc00 && uc.unicode() < 0xe000) {
2333 // second half of a surrogate, check if we have the first half as well,
2334 // if yes delete both at once
2335 uc = m_text.at(m_cursor - 1);
2336 if (uc.unicode() >= 0xd800 && uc.unicode() < 0xdc00) {
2337 internalDelete(true);
2341 internalDelete(true);
2343 finishChange(priorState);
2349 Handles the behavior for the delete key or function.
2350 Removes the current selection if there is a selection, otherwise
2351 removes the character after the cursor position.
2355 void QQuickTextInputPrivate::del()
2357 int priorState = m_undoState;
2358 if (hasSelectedText()) {
2359 removeSelectedText();
2361 int n = m_textLayout.nextCursorPosition(m_cursor) - m_cursor;
2365 finishChange(priorState);
2371 Inserts the given \a newText at the current cursor position.
2372 If there is any selected text it is removed prior to insertion of
2375 void QQuickTextInputPrivate::insert(const QString &newText)
2377 int priorState = m_undoState;
2378 removeSelectedText();
2379 internalInsert(newText);
2380 finishChange(priorState);
2386 Clears the line control text.
2388 void QQuickTextInputPrivate::clear()
2390 int priorState = m_undoState;
2392 m_selend = m_text.length();
2393 removeSelectedText();
2395 finishChange(priorState, /*update*/false, /*edited*/false);
2401 Sets \a length characters from the given \a start position as selected.
2402 The given \a start position must be within the current text for
2403 the line control. If \a length characters cannot be selected, then
2404 the selection will extend to the end of the current text.
2406 void QQuickTextInputPrivate::setSelection(int start, int length)
2408 Q_Q(QQuickTextInput);
2411 if (start < 0 || start > (int)m_text.length()){
2412 qWarning("QQuickTextInputPrivate::setSelection: Invalid start position");
2417 if (start == m_selstart && start + length == m_selend && m_cursor == m_selend)
2420 m_selend = qMin(start + length, (int)m_text.length());
2421 m_cursor = m_selend;
2422 } else if (length < 0){
2423 if (start == m_selend && start + length == m_selstart && m_cursor == m_selstart)
2425 m_selstart = qMax(start + length, 0);
2427 m_cursor = m_selstart;
2428 } else if (m_selstart != m_selend) {
2434 emitCursorPositionChanged();
2437 emit q->selectionChanged();
2438 emitCursorPositionChanged();
2444 Initializes the line control with a starting text value of \a txt.
2446 void QQuickTextInputPrivate::init(const QString &txt)
2450 updateDisplayText();
2451 m_cursor = m_text.length();
2457 Sets the password echo editing to \a editing. If password echo editing
2458 is true, then the text of the password is displayed even if the echo
2459 mode is set to QLineEdit::PasswordEchoOnEdit. Password echoing editing
2460 does not affect other echo modes.
2462 void QQuickTextInputPrivate::updatePasswordEchoEditing(bool editing)
2464 cancelPasswordEchoTimer();
2465 m_passwordEchoEditing = editing;
2466 updateDisplayText();
2472 Fixes the current text so that it is valid given any set validators.
2474 Returns true if the text was changed. Otherwise returns false.
2476 bool QQuickTextInputPrivate::fixup() // this function assumes that validate currently returns != Acceptable
2478 #ifndef QT_NO_VALIDATOR
2480 QString textCopy = m_text;
2481 int cursorCopy = m_cursor;
2482 m_validator->fixup(textCopy);
2483 if (m_validator->validate(textCopy, cursorCopy) == QValidator::Acceptable) {
2484 if (textCopy != m_text || cursorCopy != m_cursor)
2485 internalSetText(textCopy, cursorCopy);
2496 Moves the cursor to the given position \a pos. If \a mark is true will
2497 adjust the currently selected text.
2499 void QQuickTextInputPrivate::moveCursor(int pos, bool mark)
2501 Q_Q(QQuickTextInput);
2504 if (pos != m_cursor) {
2507 pos = pos > m_cursor ? nextMaskBlank(pos) : prevMaskBlank(pos);
2511 if (m_selend > m_selstart && m_cursor == m_selstart)
2513 else if (m_selend > m_selstart && m_cursor == m_selend)
2514 anchor = m_selstart;
2517 m_selstart = qMin(anchor, pos);
2518 m_selend = qMax(anchor, pos);
2523 if (mark || m_selDirty) {
2525 emit q->selectionChanged();
2527 emitCursorPositionChanged();
2533 Applies the given input method event \a event to the text of the line
2536 void QQuickTextInputPrivate::processInputMethodEvent(QInputMethodEvent *event)
2538 Q_Q(QQuickTextInput);
2540 int priorState = -1;
2541 bool isGettingInput = !event->commitString().isEmpty()
2542 || event->preeditString() != preeditAreaText()
2543 || event->replacementLength() > 0;
2544 bool cursorPositionChanged = false;
2545 bool selectionChange = false;
2546 m_preeditDirty = event->preeditString() != preeditAreaText();
2548 if (isGettingInput) {
2549 // If any text is being input, remove selected text.
2550 priorState = m_undoState;
2551 if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit && !m_passwordEchoEditing) {
2552 updatePasswordEchoEditing(true);
2554 m_selend = m_text.length();
2556 removeSelectedText();
2559 int c = m_cursor; // cursor position after insertion of commit string
2560 if (event->replacementStart() <= 0)
2561 c += event->commitString().length() - qMin(-event->replacementStart(), event->replacementLength());
2563 m_cursor += event->replacementStart();
2567 // insert commit string
2568 if (event->replacementLength()) {
2569 m_selstart = m_cursor;
2570 m_selend = m_selstart + event->replacementLength();
2571 m_selend = qMin(m_selend, m_text.length());
2572 removeSelectedText();
2574 if (!event->commitString().isEmpty()) {
2575 internalInsert(event->commitString());
2576 cursorPositionChanged = true;
2579 m_cursor = qBound(0, c, m_text.length());
2581 for (int i = 0; i < event->attributes().size(); ++i) {
2582 const QInputMethodEvent::Attribute &a = event->attributes().at(i);
2583 if (a.type == QInputMethodEvent::Selection) {
2584 m_cursor = qBound(0, a.start + a.length, m_text.length());
2586 m_selstart = qMax(0, qMin(a.start, m_text.length()));
2587 m_selend = m_cursor;
2588 if (m_selend < m_selstart) {
2589 qSwap(m_selstart, m_selend);
2591 selectionChange = true;
2593 m_selstart = m_selend = 0;
2595 cursorPositionChanged = true;
2599 m_textLayout.setPreeditArea(m_cursor, event->preeditString());
2601 const int oldPreeditCursor = m_preeditCursor;
2602 m_preeditCursor = event->preeditString().length();
2603 m_hideCursor = false;
2604 QList<QTextLayout::FormatRange> formats;
2605 for (int i = 0; i < event->attributes().size(); ++i) {
2606 const QInputMethodEvent::Attribute &a = event->attributes().at(i);
2607 if (a.type == QInputMethodEvent::Cursor) {
2608 m_preeditCursor = a.start;
2609 m_hideCursor = !a.length;
2610 } else if (a.type == QInputMethodEvent::TextFormat) {
2611 QTextCharFormat f = qvariant_cast<QTextFormat>(a.value).toCharFormat();
2613 QTextLayout::FormatRange o;
2614 o.start = a.start + m_cursor;
2615 o.length = a.length;
2621 m_textLayout.setAdditionalFormats(formats);
2623 updateDisplayText(/*force*/ true);
2624 if (cursorPositionChanged)
2625 emitCursorPositionChanged();
2626 else if (m_preeditCursor != oldPreeditCursor)
2627 q->updateCursorRectangle();
2629 bool tentativeCommitChanged = m_tentativeCommit != event->tentativeCommitString();
2631 if (tentativeCommitChanged) {
2633 m_tentativeCommit = event->tentativeCommitString();
2636 if (isGettingInput || tentativeCommitChanged)
2637 finishChange(priorState);
2639 if (selectionChange)
2640 emit q->selectionChanged();
2646 Sets the selection to cover the word at the given cursor position.
2647 The word boundaries are defined by the behavior of QTextLayout::SkipWords
2650 void QQuickTextInputPrivate::selectWordAtPos(int cursor)
2652 int next = cursor + 1;
2655 int c = m_textLayout.previousCursorPosition(next, QTextLayout::SkipWords);
2656 moveCursor(c, false);
2657 // ## text layout should support end of words.
2658 int end = m_textLayout.nextCursorPosition(c, QTextLayout::SkipWords);
2659 while (end > cursor && m_text[end-1].isSpace())
2661 moveCursor(end, true);
2667 Completes a change to the line control text. If the change is not valid
2668 will undo the line control state back to the given \a validateFromState.
2670 If \a edited is true and the change is valid, will emit textEdited() in
2671 addition to textChanged(). Otherwise only emits textChanged() on a valid
2674 The \a update value is currently unused.
2676 bool QQuickTextInputPrivate::finishChange(int validateFromState, bool update, bool /*edited*/)
2678 Q_Q(QQuickTextInput);
2684 bool wasValidInput = m_validInput;
2685 m_validInput = true;
2686 #ifndef QT_NO_VALIDATOR
2688 QString textCopy = m_text;
2689 int cursorCopy = m_cursor;
2690 m_validInput = (m_validator->validate(textCopy, cursorCopy) != QValidator::Invalid);
2692 if (m_text != textCopy) {
2693 internalSetText(textCopy, cursorCopy);
2696 m_cursor = cursorCopy;
2698 if (!m_tentativeCommit.isEmpty()) {
2699 textCopy.insert(m_cursor, m_tentativeCommit);
2700 bool validInput = m_validator->validate(textCopy, cursorCopy) != QValidator::Invalid;
2702 m_tentativeCommit.clear();
2705 m_tentativeCommit.clear();
2709 if (validateFromState >= 0 && wasValidInput && !m_validInput) {
2710 if (m_transactions.count())
2712 internalUndo(validateFromState);
2713 m_history.resize(m_undoState);
2714 if (m_modifiedState > m_undoState)
2715 m_modifiedState = -1;
2716 m_validInput = true;
2717 m_textDirty = false;
2719 updateDisplayText();
2722 m_textDirty = false;
2723 m_preeditDirty = false;
2724 determineHorizontalAlignment();
2725 emit q->textChanged();
2728 if (m_validInput != wasValidInput)
2729 emit q->acceptableInputChanged();
2731 if (m_preeditDirty) {
2732 m_preeditDirty = false;
2733 determineHorizontalAlignment();
2737 emit q->selectionChanged();
2739 emitCursorPositionChanged();
2746 An internal function for setting the text of the line control.
2748 void QQuickTextInputPrivate::internalSetText(const QString &txt, int pos, bool edited)
2750 Q_Q(QQuickTextInput);
2752 QString oldText = m_text;
2754 m_text = maskString(0, txt, true);
2755 m_text += clearString(m_text.length(), m_maxLength - m_text.length());
2757 m_text = txt.isEmpty() ? txt : txt.left(m_maxLength);
2760 m_modifiedState = m_undoState = 0;
2761 m_cursor = (pos < 0 || pos > m_text.length()) ? m_text.length() : pos;
2762 m_textDirty = (oldText != m_text);
2764 bool changed = finishChange(-1, true, edited);
2765 #ifdef QT_NO_ACCESSIBILITY
2769 QAccessible::updateAccessibility(q, 0, QAccessible::TextUpdated);
2777 Adds the given \a command to the undo history
2778 of the line control. Does not apply the command.
2780 void QQuickTextInputPrivate::addCommand(const Command &cmd)
2782 if (m_separator && m_undoState && m_history[m_undoState - 1].type != Separator) {
2783 m_history.resize(m_undoState + 2);
2784 m_history[m_undoState++] = Command(Separator, m_cursor, 0, m_selstart, m_selend);
2786 m_history.resize(m_undoState + 1);
2788 m_separator = false;
2789 m_history[m_undoState++] = cmd;
2795 Inserts the given string \a s into the line
2798 Also adds the appropriate commands into the undo history.
2799 This function does not call finishChange(), and may leave the text
2800 in an invalid state.
2802 void QQuickTextInputPrivate::internalInsert(const QString &s)
2804 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
2805 Q_Q(QQuickTextInput);
2806 if (m_echoMode == QQuickTextInput::Password)
2807 m_passwordEchoTimer.start(qt_passwordEchoDelay, q);
2809 if (hasSelectedText())
2810 addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
2812 QString ms = maskString(m_cursor, s);
2813 for (int i = 0; i < (int) ms.length(); ++i) {
2814 addCommand (Command(DeleteSelection, m_cursor + i, m_text.at(m_cursor + i), -1, -1));
2815 addCommand(Command(Insert, m_cursor + i, ms.at(i), -1, -1));
2817 m_text.replace(m_cursor, ms.length(), ms);
2818 m_cursor += ms.length();
2819 m_cursor = nextMaskBlank(m_cursor);
2822 int remaining = m_maxLength - m_text.length();
2823 if (remaining != 0) {
2824 m_text.insert(m_cursor, s.left(remaining));
2825 for (int i = 0; i < (int) s.left(remaining).length(); ++i)
2826 addCommand(Command(Insert, m_cursor++, s.at(i), -1, -1));
2835 deletes a single character from the current text. If \a wasBackspace,
2836 the character prior to the cursor is removed. Otherwise the character
2837 after the cursor is removed.
2839 Also adds the appropriate commands into the undo history.
2840 This function does not call finishChange(), and may leave the text
2841 in an invalid state.
2843 void QQuickTextInputPrivate::internalDelete(bool wasBackspace)
2845 if (m_cursor < (int) m_text.length()) {
2846 cancelPasswordEchoTimer();
2847 if (hasSelectedText())
2848 addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
2849 addCommand(Command((CommandType)((m_maskData ? 2 : 0) + (wasBackspace ? Remove : Delete)),
2850 m_cursor, m_text.at(m_cursor), -1, -1));
2852 m_text.replace(m_cursor, 1, clearString(m_cursor, 1));
2853 addCommand(Command(Insert, m_cursor, m_text.at(m_cursor), -1, -1));
2855 m_text.remove(m_cursor, 1);
2864 removes the currently selected text from the line control.
2866 Also adds the appropriate commands into the undo history.
2867 This function does not call finishChange(), and may leave the text
2868 in an invalid state.
2870 void QQuickTextInputPrivate::removeSelectedText()
2872 if (m_selstart < m_selend && m_selend <= (int) m_text.length()) {
2873 cancelPasswordEchoTimer();
2876 addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
2877 if (m_selstart <= m_cursor && m_cursor < m_selend) {
2878 // cursor is within the selection. Split up the commands
2879 // to be able to restore the correct cursor position
2880 for (i = m_cursor; i >= m_selstart; --i)
2881 addCommand (Command(DeleteSelection, i, m_text.at(i), -1, 1));
2882 for (i = m_selend - 1; i > m_cursor; --i)
2883 addCommand (Command(DeleteSelection, i - m_cursor + m_selstart - 1, m_text.at(i), -1, -1));
2885 for (i = m_selend-1; i >= m_selstart; --i)
2886 addCommand (Command(RemoveSelection, i, m_text.at(i), -1, -1));
2889 m_text.replace(m_selstart, m_selend - m_selstart, clearString(m_selstart, m_selend - m_selstart));
2890 for (int i = 0; i < m_selend - m_selstart; ++i)
2891 addCommand(Command(Insert, m_selstart + i, m_text.at(m_selstart + i), -1, -1));
2893 m_text.remove(m_selstart, m_selend - m_selstart);
2895 if (m_cursor > m_selstart)
2896 m_cursor -= qMin(m_cursor, m_selend) - m_selstart;
2905 Parses the input mask specified by \a maskFields to generate
2906 the mask data used to handle input masks.
2908 void QQuickTextInputPrivate::parseInputMask(const QString &maskFields)
2910 int delimiter = maskFields.indexOf(QLatin1Char(';'));
2911 if (maskFields.isEmpty() || delimiter == 0) {
2913 delete [] m_maskData;
2915 m_maxLength = 32767;
2916 internalSetText(QString());
2921 if (delimiter == -1) {
2922 m_blank = QLatin1Char(' ');
2923 m_inputMask = maskFields;
2925 m_inputMask = maskFields.left(delimiter);
2926 m_blank = (delimiter + 1 < maskFields.length()) ? maskFields[delimiter + 1] : QLatin1Char(' ');
2929 // calculate m_maxLength / m_maskData length
2932 for (int i=0; i<m_inputMask.length(); i++) {
2933 c = m_inputMask.at(i);
2934 if (i > 0 && m_inputMask.at(i-1) == QLatin1Char('\\')) {
2938 if (c != QLatin1Char('\\') && c != QLatin1Char('!') &&
2939 c != QLatin1Char('<') && c != QLatin1Char('>') &&
2940 c != QLatin1Char('{') && c != QLatin1Char('}') &&
2941 c != QLatin1Char('[') && c != QLatin1Char(']'))
2945 delete [] m_maskData;
2946 m_maskData = new MaskInputData[m_maxLength];
2948 MaskInputData::Casemode m = MaskInputData::NoCaseMode;
2951 bool escape = false;
2953 for (int i = 0; i < m_inputMask.length(); i++) {
2954 c = m_inputMask.at(i);
2957 m_maskData[index].maskChar = c;
2958 m_maskData[index].separator = s;
2959 m_maskData[index].caseMode = m;
2962 } else if (c == QLatin1Char('<')) {
2963 m = MaskInputData::Lower;
2964 } else if (c == QLatin1Char('>')) {
2965 m = MaskInputData::Upper;
2966 } else if (c == QLatin1Char('!')) {
2967 m = MaskInputData::NoCaseMode;
2968 } else if (c != QLatin1Char('{') && c != QLatin1Char('}') && c != QLatin1Char('[') && c != QLatin1Char(']')) {
2969 switch (c.unicode()) {
2995 m_maskData[index].maskChar = c;
2996 m_maskData[index].separator = s;
2997 m_maskData[index].caseMode = m;
3002 internalSetText(m_text);
3009 checks if the key is valid compared to the inputMask
3011 bool QQuickTextInputPrivate::isValidInput(QChar key, QChar mask) const
3013 switch (mask.unicode()) {
3019 if (key.isLetter() || key == m_blank)
3023 if (key.isLetterOrNumber())
3027 if (key.isLetterOrNumber() || key == m_blank)
3035 if (key.isPrint() || key == m_blank)
3043 if (key.isNumber() || key == m_blank)
3047 if (key.isNumber() && key.digitValue() > 0)
3051 if ((key.isNumber() && key.digitValue() > 0) || key == m_blank)
3055 if (key.isNumber() || key == QLatin1Char('+') || key == QLatin1Char('-') || key == m_blank)
3059 if (key == QLatin1Char('0') || key == QLatin1Char('1'))
3063 if (key == QLatin1Char('0') || key == QLatin1Char('1') || key == m_blank)
3067 if (key.isNumber() || (key >= QLatin1Char('a') && key <= QLatin1Char('f')) || (key >= QLatin1Char('A') && key <= QLatin1Char('F')))
3071 if (key.isNumber() || (key >= QLatin1Char('a') && key <= QLatin1Char('f')) || (key >= QLatin1Char('A') && key <= QLatin1Char('F')) || key == m_blank)
3083 Returns true if the given text \a str is valid for any
3084 validator or input mask set for the line control.
3086 Otherwise returns false
3088 bool QQuickTextInputPrivate::hasAcceptableInput(const QString &str) const
3090 #ifndef QT_NO_VALIDATOR
3091 QString textCopy = str;
3092 int cursorCopy = m_cursor;
3093 if (m_validator && m_validator->validate(textCopy, cursorCopy)
3094 != QValidator::Acceptable)
3101 if (str.length() != m_maxLength)
3104 for (int i=0; i < m_maxLength; ++i) {
3105 if (m_maskData[i].separator) {
3106 if (str.at(i) != m_maskData[i].maskChar)
3109 if (!isValidInput(str.at(i), m_maskData[i].maskChar))
3119 Applies the inputMask on \a str starting from position \a pos in the mask. \a clear
3120 specifies from where characters should be gotten when a separator is met in \a str - true means
3121 that blanks will be used, false that previous input is used.
3122 Calling this when no inputMask is set is undefined.
3124 QString QQuickTextInputPrivate::maskString(uint pos, const QString &str, bool clear) const
3126 if (pos >= (uint)m_maxLength)
3127 return QString::fromLatin1("");
3130 fill = clear ? clearString(0, m_maxLength) : m_text;
3133 QString s = QString::fromLatin1("");
3135 while (i < m_maxLength) {
3136 if (strIndex < str.length()) {
3137 if (m_maskData[i].separator) {
3138 s += m_maskData[i].maskChar;
3139 if (str[(int)strIndex] == m_maskData[i].maskChar)
3143 if (isValidInput(str[(int)strIndex], m_maskData[i].maskChar)) {
3144 switch (m_maskData[i].caseMode) {
3145 case MaskInputData::Upper:
3146 s += str[(int)strIndex].toUpper();
3148 case MaskInputData::Lower:
3149 s += str[(int)strIndex].toLower();
3152 s += str[(int)strIndex];
3156 // search for separator first
3157 int n = findInMask(i, true, true, str[(int)strIndex]);
3159 if (str.length() != 1 || i == 0 || (i > 0 && (!m_maskData[i-1].separator || m_maskData[i-1].maskChar != str[(int)strIndex]))) {
3160 s += fill.mid(i, n-i+1);
3161 i = n + 1; // update i to find + 1
3164 // search for valid m_blank if not
3165 n = findInMask(i, true, false, str[(int)strIndex]);
3167 s += fill.mid(i, n-i);
3168 switch (m_maskData[n].caseMode) {
3169 case MaskInputData::Upper:
3170 s += str[(int)strIndex].toUpper();
3172 case MaskInputData::Lower:
3173 s += str[(int)strIndex].toLower();
3176 s += str[(int)strIndex];
3178 i = n + 1; // updates i to find + 1
3196 Returns a "cleared" string with only separators and blank chars.
3197 Calling this when no inputMask is set is undefined.
3199 QString QQuickTextInputPrivate::clearString(uint pos, uint len) const
3201 if (pos >= (uint)m_maxLength)
3205 int end = qMin((uint)m_maxLength, pos + len);
3206 for (int i = pos; i < end; ++i)
3207 if (m_maskData[i].separator)
3208 s += m_maskData[i].maskChar;
3218 Strips blank parts of the input in a QQuickTextInputPrivate when an inputMask is set,
3219 separators are still included. Typically "127.0__.0__.1__" becomes "127.0.0.1".
3221 QString QQuickTextInputPrivate::stripString(const QString &str) const
3227 int end = qMin(m_maxLength, (int)str.length());
3228 for (int i = 0; i < end; ++i)
3229 if (m_maskData[i].separator)
3230 s += m_maskData[i].maskChar;
3232 if (str[i] != m_blank)
3240 searches forward/backward in m_maskData for either a separator or a m_blank
3242 int QQuickTextInputPrivate::findInMask(int pos, bool forward, bool findSeparator, QChar searchChar) const
3244 if (pos >= m_maxLength || pos < 0)
3247 int end = forward ? m_maxLength : -1;
3248 int step = forward ? 1 : -1;
3252 if (findSeparator) {
3253 if (m_maskData[i].separator && m_maskData[i].maskChar == searchChar)
3256 if (!m_maskData[i].separator) {
3257 if (searchChar.isNull())
3259 else if (isValidInput(searchChar, m_maskData[i].maskChar))
3268 void QQuickTextInputPrivate::internalUndo(int until)
3270 if (!isUndoAvailable())
3272 cancelPasswordEchoTimer();
3274 while (m_undoState && m_undoState > until) {
3275 Command& cmd = m_history[--m_undoState];
3278 m_text.remove(cmd.pos, 1);
3282 m_selstart = cmd.selStart;
3283 m_selend = cmd.selEnd;
3287 case RemoveSelection:
3288 m_text.insert(cmd.pos, cmd.uc);
3289 m_cursor = cmd.pos + 1;
3292 case DeleteSelection:
3293 m_text.insert(cmd.pos, cmd.uc);
3299 if (until < 0 && m_undoState) {
3300 Command& next = m_history[m_undoState-1];
3301 if (next.type != cmd.type && next.type < RemoveSelection
3302 && (cmd.type < RemoveSelection || next.type == Separator))
3307 emitCursorPositionChanged();
3310 void QQuickTextInputPrivate::internalRedo()
3312 if (!isRedoAvailable())
3315 while (m_undoState < (int)m_history.size()) {
3316 Command& cmd = m_history[m_undoState++];
3319 m_text.insert(cmd.pos, cmd.uc);
3320 m_cursor = cmd.pos + 1;
3323 m_selstart = cmd.selStart;
3324 m_selend = cmd.selEnd;
3329 case RemoveSelection:
3330 case DeleteSelection:
3331 m_text.remove(cmd.pos, 1);
3332 m_selstart = cmd.selStart;
3333 m_selend = cmd.selEnd;
3337 m_selstart = cmd.selStart;
3338 m_selend = cmd.selEnd;
3342 if (m_undoState < (int)m_history.size()) {
3343 Command& next = m_history[m_undoState];
3344 if (next.type != cmd.type && cmd.type < RemoveSelection && next.type != Separator
3345 && (next.type < RemoveSelection || cmd.type == Separator))
3350 emitCursorPositionChanged();
3356 If the current cursor position differs from the last emitted cursor
3357 position, emits cursorPositionChanged().
3359 void QQuickTextInputPrivate::emitCursorPositionChanged()
3361 Q_Q(QQuickTextInput);
3362 if (m_cursor != m_lastCursorPos) {
3363 m_lastCursorPos = m_cursor;
3365 q->updateCursorRectangle();
3366 emit q->cursorPositionChanged();
3367 // XXX todo - not in 4.8?
3369 resetCursorBlinkTimer();
3372 if (!hasSelectedText()) {
3373 if (lastSelectionStart != m_cursor) {
3374 lastSelectionStart = m_cursor;
3375 emit q->selectionStartChanged();
3377 if (lastSelectionEnd != m_cursor) {
3378 lastSelectionEnd = m_cursor;
3379 emit q->selectionEndChanged();
3383 #ifndef QT_NO_ACCESSIBILITY
3384 QAccessible::updateAccessibility(q, 0, QAccessible::TextCaretMoved);
3390 void QQuickTextInputPrivate::setCursorBlinkPeriod(int msec)
3392 Q_Q(QQuickTextInput);
3393 if (msec == m_blinkPeriod)
3396 q->killTimer(m_blinkTimer);
3399 m_blinkTimer = q->startTimer(msec / 2);
3403 if (m_blinkStatus == 1)
3406 m_blinkPeriod = msec;
3409 void QQuickTextInputPrivate::resetCursorBlinkTimer()
3411 Q_Q(QQuickTextInput);
3412 if (m_blinkPeriod == 0 || m_blinkTimer == 0)
3414 q->killTimer(m_blinkTimer);
3415 m_blinkTimer = q->startTimer(m_blinkPeriod / 2);
3419 void QQuickTextInput::timerEvent(QTimerEvent *event)
3421 Q_D(QQuickTextInput);
3422 if (event->timerId() == d->m_blinkTimer) {
3423 d->m_blinkStatus = !d->m_blinkStatus;
3425 } else if (event->timerId() == d->m_deleteAllTimer) {
3426 killTimer(d->m_deleteAllTimer);
3427 d->m_deleteAllTimer = 0;
3429 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
3430 } else if (event->timerId() == d->m_passwordEchoTimer.timerId()) {
3431 d->m_passwordEchoTimer.stop();
3432 d->updateDisplayText();
3437 void QQuickTextInputPrivate::processKeyEvent(QKeyEvent* event)
3439 Q_Q(QQuickTextInput);
3440 bool inlineCompletionAccepted = false;
3442 if (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return) {
3443 if (hasAcceptableInput(m_text) || fixup()) {
3446 if (inlineCompletionAccepted)
3453 if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit
3454 && !m_passwordEchoEditing
3456 && !event->text().isEmpty()
3457 && !(event->modifiers() & Qt::ControlModifier)) {
3458 // Clear the edit and reset to normal echo mode while editing; the
3459 // echo mode switches back when the edit loses focus
3460 // ### resets current content. dubious code; you can
3461 // navigate with keys up, down, back, and select(?), but if you press
3462 // "left" or "right" it clears?
3463 updatePasswordEchoEditing(true);
3467 bool unknown = false;
3468 bool visual = cursorMoveStyle() == Qt::VisualMoveStyle;
3472 #ifndef QT_NO_SHORTCUT
3473 else if (event == QKeySequence::Undo) {
3477 else if (event == QKeySequence::Redo) {
3481 else if (event == QKeySequence::SelectAll) {
3484 #ifndef QT_NO_CLIPBOARD
3485 else if (event == QKeySequence::Copy) {
3488 else if (event == QKeySequence::Paste) {
3490 QClipboard::Mode mode = QClipboard::Clipboard;
3494 else if (event == QKeySequence::Cut) {
3500 else if (event == QKeySequence::DeleteEndOfLine) {
3502 setSelection(m_cursor, end());
3507 #endif //QT_NO_CLIPBOARD
3508 else if (event == QKeySequence::MoveToStartOfLine || event == QKeySequence::MoveToStartOfBlock) {
3511 else if (event == QKeySequence::MoveToEndOfLine || event == QKeySequence::MoveToEndOfBlock) {
3514 else if (event == QKeySequence::SelectStartOfLine || event == QKeySequence::SelectStartOfBlock) {
3517 else if (event == QKeySequence::SelectEndOfLine || event == QKeySequence::SelectEndOfBlock) {
3520 else if (event == QKeySequence::MoveToNextChar) {
3521 if (hasSelectedText()) {
3522 moveCursor(selectionEnd(), false);
3524 cursorForward(0, visual ? 1 : (layoutDirection() == Qt::LeftToRight ? 1 : -1));
3527 else if (event == QKeySequence::SelectNextChar) {
3528 cursorForward(1, visual ? 1 : (layoutDirection() == Qt::LeftToRight ? 1 : -1));
3530 else if (event == QKeySequence::MoveToPreviousChar) {
3531 if (hasSelectedText()) {
3532 moveCursor(selectionStart(), false);
3534 cursorForward(0, visual ? -1 : (layoutDirection() == Qt::LeftToRight ? -1 : 1));
3537 else if (event == QKeySequence::SelectPreviousChar) {
3538 cursorForward(1, visual ? -1 : (layoutDirection() == Qt::LeftToRight ? -1 : 1));
3540 else if (event == QKeySequence::MoveToNextWord) {
3541 if (m_echoMode == QQuickTextInput::Normal)
3542 layoutDirection() == Qt::LeftToRight ? cursorWordForward(0) : cursorWordBackward(0);
3544 layoutDirection() == Qt::LeftToRight ? end(0) : home(0);
3546 else if (event == QKeySequence::MoveToPreviousWord) {
3547 if (m_echoMode == QQuickTextInput::Normal)
3548 layoutDirection() == Qt::LeftToRight ? cursorWordBackward(0) : cursorWordForward(0);
3549 else if (!m_readOnly) {
3550 layoutDirection() == Qt::LeftToRight ? home(0) : end(0);
3553 else if (event == QKeySequence::SelectNextWord) {
3554 if (m_echoMode == QQuickTextInput::Normal)
3555 layoutDirection() == Qt::LeftToRight ? cursorWordForward(1) : cursorWordBackward(1);
3557 layoutDirection() == Qt::LeftToRight ? end(1) : home(1);
3559 else if (event == QKeySequence::SelectPreviousWord) {
3560 if (m_echoMode == QQuickTextInput::Normal)
3561 layoutDirection() == Qt::LeftToRight ? cursorWordBackward(1) : cursorWordForward(1);
3563 layoutDirection() == Qt::LeftToRight ? home(1) : end(1);
3565 else if (event == QKeySequence::Delete) {
3569 else if (event == QKeySequence::DeleteEndOfWord) {
3571 cursorWordForward(true);
3575 else if (event == QKeySequence::DeleteStartOfWord) {
3577 cursorWordBackward(true);
3581 #endif // QT_NO_SHORTCUT
3583 bool handled = false;
3584 if (event->modifiers() & Qt::ControlModifier) {
3585 switch (event->key()) {
3586 case Qt::Key_Backspace:
3588 cursorWordBackward(true);
3596 } else { // ### check for *no* modifier
3597 switch (event->key()) {
3598 case Qt::Key_Backspace:
3610 if (event->key() == Qt::Key_Direction_L || event->key() == Qt::Key_Direction_R) {
3611 setLayoutDirection((event->key() == Qt::Key_Direction_L) ? Qt::LeftToRight : Qt::RightToLeft);
3615 if (unknown && !m_readOnly) {
3616 QString t = event->text();
3617 if (!t.isEmpty() && t.at(0).isPrint()) {