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);
605 QRect r = cursorRectangle();
606 if (d->inputMask().isEmpty())
610 emit cursorVisibleChanged(d->cursorVisible);
614 \qmlproperty int QtQuick2::TextInput::cursorPosition
615 The position of the cursor in the TextInput.
617 int QQuickTextInput::cursorPosition() const
619 Q_D(const QQuickTextInput);
623 void QQuickTextInput::setCursorPosition(int cp)
625 Q_D(QQuickTextInput);
626 if (cp < 0 || cp > text().length())
632 Returns a Rect which encompasses the cursor, but which may be larger than is
633 required. Ignores custom cursor delegates.
635 QRect QQuickTextInput::cursorRectangle() const
637 Q_D(const QQuickTextInput);
640 if (d->m_preeditCursor != -1)
641 c += d->m_preeditCursor;
642 if (d->m_echoMode == NoEcho || !isComponentComplete())
644 QTextLine l = d->m_textLayout.lineForTextPosition(c);
646 qRound(l.cursorToX(c) - d->hscroll),
647 qRound(l.y() - d->vscroll),
653 \qmlproperty int QtQuick2::TextInput::selectionStart
655 The cursor position before the first character in the current selection.
657 This property is read-only. To change the selection, use select(start,end),
658 selectAll(), or selectWord().
660 \sa selectionEnd, cursorPosition, selectedText
662 int QQuickTextInput::selectionStart() const
664 Q_D(const QQuickTextInput);
665 return d->lastSelectionStart;
668 \qmlproperty int QtQuick2::TextInput::selectionEnd
670 The cursor position after the last character in the current selection.
672 This property is read-only. To change the selection, use select(start,end),
673 selectAll(), or selectWord().
675 \sa selectionStart, cursorPosition, selectedText
677 int QQuickTextInput::selectionEnd() const
679 Q_D(const QQuickTextInput);
680 return d->lastSelectionEnd;
683 \qmlmethod void QtQuick2::TextInput::select(int start, int end)
685 Causes the text from \a start to \a end to be selected.
687 If either start or end is out of range, the selection is not changed.
689 After calling this, selectionStart will become the lesser
690 and selectionEnd will become the greater (regardless of the order passed
693 \sa selectionStart, selectionEnd
695 void QQuickTextInput::select(int start, int end)
697 Q_D(QQuickTextInput);
698 if (start < 0 || end < 0 || start > text().length() || end > text().length())
700 d->setSelection(start, end-start);
704 \qmlproperty string QtQuick2::TextInput::selectedText
706 This read-only property provides the text currently selected in the
709 It is equivalent to the following snippet, but is faster and easier
713 myTextInput.text.toString().substring(myTextInput.selectionStart,
714 myTextInput.selectionEnd);
717 QString QQuickTextInput::selectedText() const
719 Q_D(const QQuickTextInput);
720 return d->selectedText();
724 \qmlproperty bool QtQuick2::TextInput::activeFocusOnPress
726 Whether the TextInput should gain active focus on a mouse press. By default this is
729 bool QQuickTextInput::focusOnPress() const
731 Q_D(const QQuickTextInput);
732 return d->focusOnPress;
735 void QQuickTextInput::setFocusOnPress(bool b)
737 Q_D(QQuickTextInput);
738 if (d->focusOnPress == b)
743 emit activeFocusOnPressChanged(d->focusOnPress);
746 \qmlproperty bool QtQuick2::TextInput::autoScroll
748 Whether the TextInput should scroll when the text is longer than the width. By default this is
751 bool QQuickTextInput::autoScroll() const
753 Q_D(const QQuickTextInput);
754 return d->autoScroll;
757 void QQuickTextInput::setAutoScroll(bool b)
759 Q_D(QQuickTextInput);
760 if (d->autoScroll == b)
764 //We need to repaint so that the scrolling is taking into account.
765 updateCursorRectangle();
766 emit autoScrollChanged(d->autoScroll);
769 #ifndef QT_NO_VALIDATOR
772 \qmlclass IntValidator QIntValidator
773 \inqmlmodule QtQuick 2
774 \ingroup qml-basic-visual-elements
776 This element provides a validator for integer values.
778 IntValidator uses the \l {QLocale::setDefault()}{default locale} to interpret the number and
779 will accept locale specific digits, group separators, and positive and negative signs. In
780 addition, IntValidator is always guaranteed to accept a number formatted according to the "C"
784 \qmlproperty int QtQuick2::IntValidator::top
786 This property holds the validator's highest acceptable value.
787 By default, this property's value is derived from the highest signed integer available (typically 2147483647).
790 \qmlproperty int QtQuick2::IntValidator::bottom
792 This property holds the validator's lowest acceptable value.
793 By default, this property's value is derived from the lowest signed integer available (typically -2147483647).
797 \qmlclass DoubleValidator QDoubleValidator
798 \inqmlmodule QtQuick 2
799 \ingroup qml-basic-visual-elements
801 This element provides a validator for non-integer numbers.
805 \qmlproperty real QtQuick2::DoubleValidator::top
807 This property holds the validator's maximum acceptable value.
808 By default, this property contains a value of infinity.
811 \qmlproperty real QtQuick2::DoubleValidator::bottom
813 This property holds the validator's minimum acceptable value.
814 By default, this property contains a value of -infinity.
817 \qmlproperty int QtQuick2::DoubleValidator::decimals
819 This property holds the validator's maximum number of digits after the decimal point.
820 By default, this property contains a value of 1000.
823 \qmlproperty enumeration QtQuick2::DoubleValidator::notation
824 This property holds the notation of how a string can describe a number.
826 The possible values for this property are:
829 \o DoubleValidator.StandardNotation
830 \o DoubleValidator.ScientificNotation (default)
833 If this property is set to DoubleValidator.ScientificNotation, the written number may have an exponent part (e.g. 1.5E-2).
837 \qmlclass RegExpValidator QRegExpValidator
838 \inqmlmodule QtQuick 2
839 \ingroup qml-basic-visual-elements
841 This element provides a validator, which counts as valid any string which
842 matches a specified regular expression.
845 \qmlproperty regExp QtQuick2::RegExpValidator::regExp
847 This property holds the regular expression used for validation.
849 Note that this property should be a regular expression in JS syntax, e.g /a/ for the regular expression
852 By default, this property contains a regular expression with the pattern .* that matches any string.
856 \qmlproperty Validator QtQuick2::TextInput::validator
858 Allows you to set a validator on the TextInput. When a validator is set
859 the TextInput will only accept input which leaves the text property in
860 an acceptable or intermediate state. The accepted signal will only be sent
861 if the text is in an acceptable state when enter is pressed.
863 Currently supported validators are IntValidator, DoubleValidator and
864 RegExpValidator. An example of using validators is shown below, which allows
865 input of integers between 11 and 31 into the text input:
870 validator: IntValidator{bottom: 11; top: 31;}
875 \sa acceptableInput, inputMask
878 QValidator* QQuickTextInput::validator() const
880 Q_D(const QQuickTextInput);
881 return d->m_validator;
884 void QQuickTextInput::setValidator(QValidator* v)
886 Q_D(QQuickTextInput);
887 if (d->m_validator == v)
891 if (!d->hasAcceptableInput(d->m_text)) {
892 d->oldValidity = false;
893 emit acceptableInputChanged();
896 emit validatorChanged();
898 #endif // QT_NO_VALIDATOR
901 \qmlproperty string QtQuick2::TextInput::inputMask
903 Allows you to set an input mask on the TextInput, restricting the allowable
904 text inputs. See QLineEdit::inputMask for further details, as the exact
905 same mask strings are used by TextInput.
907 \sa acceptableInput, validator
909 QString QQuickTextInput::inputMask() const
911 Q_D(const QQuickTextInput);
912 return d->inputMask();
915 void QQuickTextInput::setInputMask(const QString &im)
917 Q_D(QQuickTextInput);
918 if (d->inputMask() == im)
922 emit inputMaskChanged(d->inputMask());
926 \qmlproperty bool QtQuick2::TextInput::acceptableInput
928 This property is always true unless a validator or input mask has been set.
929 If a validator or input mask has been set, this property will only be true
930 if the current text is acceptable to the validator or input mask as a final
931 string (not as an intermediate string).
933 bool QQuickTextInput::hasAcceptableInput() const
935 Q_D(const QQuickTextInput);
936 return d->hasAcceptableInput(d->m_text);
940 \qmlsignal QtQuick2::TextInput::onAccepted()
942 This handler is called when the Return or Enter key is pressed.
943 Note that if there is a \l validator or \l inputMask set on the text
944 input, the handler will only be emitted if the input is in an acceptable
948 void QQuickTextInputPrivate::updateInputMethodHints()
950 Q_Q(QQuickTextInput);
951 Qt::InputMethodHints hints = inputMethodHints;
952 if (m_echoMode == QQuickTextInput::Password || m_echoMode == QQuickTextInput::NoEcho)
953 hints |= Qt::ImhHiddenText;
954 else if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit)
955 hints &= ~Qt::ImhHiddenText;
956 if (m_echoMode != QQuickTextInput::Normal)
957 hints |= (Qt::ImhNoAutoUppercase | Qt::ImhNoPredictiveText);
958 q->setInputMethodHints(hints);
961 \qmlproperty enumeration QtQuick2::TextInput::echoMode
963 Specifies how the text should be displayed in the TextInput.
965 \o TextInput.Normal - Displays the text as it is. (Default)
966 \o TextInput.Password - Displays asterisks instead of characters.
967 \o TextInput.NoEcho - Displays nothing.
968 \o TextInput.PasswordEchoOnEdit - Displays characters as they are entered
969 while editing, otherwise displays asterisks.
972 QQuickTextInput::EchoMode QQuickTextInput::echoMode() const
974 Q_D(const QQuickTextInput);
975 return QQuickTextInput::EchoMode(d->m_echoMode);
978 void QQuickTextInput::setEchoMode(QQuickTextInput::EchoMode echo)
980 Q_D(QQuickTextInput);
981 if (echoMode() == echo)
983 d->cancelPasswordEchoTimer();
984 d->m_echoMode = echo;
985 d->m_passwordEchoEditing = false;
986 d->updateInputMethodHints();
987 d->updateDisplayText();
988 updateCursorRectangle();
990 emit echoModeChanged(echoMode());
993 Qt::InputMethodHints QQuickTextInput::imHints() const
995 Q_D(const QQuickTextInput);
996 return d->inputMethodHints;
999 void QQuickTextInput::setIMHints(Qt::InputMethodHints hints)
1001 Q_D(QQuickTextInput);
1002 if (d->inputMethodHints == hints)
1004 d->inputMethodHints = hints;
1005 d->updateInputMethodHints();
1009 \qmlproperty Component QtQuick2::TextInput::cursorDelegate
1010 The delegate for the cursor in the TextInput.
1012 If you set a cursorDelegate for a TextInput, this delegate will be used for
1013 drawing the cursor instead of the standard cursor. An instance of the
1014 delegate will be created and managed by the TextInput when a cursor is
1015 needed, and the x property of delegate instance will be set so as
1016 to be one pixel before the top left of the current character.
1018 Note that the root item of the delegate component must be a QDeclarativeItem or
1019 QDeclarativeItem derived item.
1021 QDeclarativeComponent* QQuickTextInput::cursorDelegate() const
1023 Q_D(const QQuickTextInput);
1024 return d->cursorComponent;
1027 void QQuickTextInput::setCursorDelegate(QDeclarativeComponent* c)
1029 Q_D(QQuickTextInput);
1030 if (d->cursorComponent == c)
1033 d->cursorComponent = c;
1035 //note that the components are owned by something else
1036 delete d->cursorItem;
1038 d->startCreatingCursor();
1041 emit cursorDelegateChanged();
1044 void QQuickTextInputPrivate::startCreatingCursor()
1046 Q_Q(QQuickTextInput);
1047 if (cursorComponent->isReady()) {
1049 } else if (cursorComponent->isLoading()) {
1050 q->connect(cursorComponent, SIGNAL(statusChanged(int)),
1051 q, SLOT(createCursor()));
1053 qmlInfo(q, cursorComponent->errors()) << QQuickTextInput::tr("Could not load cursor delegate");
1057 void QQuickTextInput::createCursor()
1059 Q_D(QQuickTextInput);
1060 if (!isComponentComplete())
1063 if (d->cursorComponent->isError()) {
1064 qmlInfo(this, d->cursorComponent->errors()) << tr("Could not load cursor delegate");
1068 if (!d->cursorComponent->isReady())
1072 delete d->cursorItem;
1073 QDeclarativeContext *creationContext = d->cursorComponent->creationContext();
1074 QObject *object = d->cursorComponent->create(creationContext ? creationContext : qmlContext(this));
1075 d->cursorItem = qobject_cast<QQuickItem*>(object);
1076 if (!d->cursorItem) {
1078 qmlInfo(this, d->cursorComponent->errors()) << tr("Could not instantiate cursor delegate");
1082 QRectF r = cursorRectangle();
1084 QDeclarative_setParent_noEvent(d->cursorItem, this);
1085 d->cursorItem->setParentItem(this);
1086 d->cursorItem->setPos(r.topLeft());
1087 d->cursorItem->setHeight(r.height());
1091 \qmlmethod rect QtQuick2::TextInput::positionToRectangle(int pos)
1093 This function takes a character position and returns the rectangle that the
1094 cursor would occupy, if it was placed at that character position.
1096 This is similar to setting the cursorPosition, and then querying the cursor
1097 rectangle, but the cursorPosition is not changed.
1099 QRectF QQuickTextInput::positionToRectangle(int pos) const
1101 Q_D(const QQuickTextInput);
1102 if (pos > d->m_cursor)
1103 pos += d->preeditAreaText().length();
1104 QTextLine l = d->m_textLayout.lineAt(0);
1105 return 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.xToCursor(x, position);
1181 void QQuickTextInput::keyPressEvent(QKeyEvent* ev)
1183 Q_D(QQuickTextInput);
1184 // Don't allow MacOSX up/down support, and we don't allow a completer.
1185 bool ignore = (ev->key() == Qt::Key_Up || ev->key() == Qt::Key_Down) && ev->modifiers() == Qt::NoModifier;
1186 if (!ignore && (d->lastSelectionStart == d->lastSelectionEnd) && (ev->key() == Qt::Key_Right || ev->key() == Qt::Key_Left)) {
1187 // Ignore when moving off the end unless there is a selection,
1188 // because then moving will do something (deselect).
1189 int cursorPosition = d->m_cursor;
1190 if (cursorPosition == 0)
1191 ignore = ev->key() == (d->layoutDirection() == Qt::LeftToRight ? Qt::Key_Left : Qt::Key_Right);
1192 if (cursorPosition == text().length())
1193 ignore = ev->key() == (d->layoutDirection() == Qt::LeftToRight ? Qt::Key_Right : Qt::Key_Left);
1198 d->processKeyEvent(ev);
1200 if (!ev->isAccepted())
1201 QQuickImplicitSizeItem::keyPressEvent(ev);
1204 void QQuickTextInput::inputMethodEvent(QInputMethodEvent *ev)
1206 Q_D(QQuickTextInput);
1207 const bool wasComposing = d->preeditAreaText().length() > 0;
1208 if (d->m_readOnly) {
1211 d->processInputMethodEvent(ev);
1213 if (!ev->isAccepted())
1214 QQuickImplicitSizeItem::inputMethodEvent(ev);
1216 if (wasComposing != (d->m_textLayout.preeditAreaText().length() > 0))
1217 emit inputMethodComposingChanged();
1220 void QQuickTextInput::mouseDoubleClickEvent(QMouseEvent *event)
1222 Q_D(QQuickTextInput);
1224 if (d->selectByMouse && event->button() == Qt::LeftButton) {
1226 int cursor = d->positionAt(event->localPos());
1227 d->selectWordAtPos(cursor);
1228 event->setAccepted(true);
1229 if (!d->hasPendingTripleClick()) {
1230 d->tripleClickStartPoint = event->localPos().toPoint();
1231 d->tripleClickTimer.start();
1234 if (d->sendMouseEventToInputContext(event))
1236 QQuickImplicitSizeItem::mouseDoubleClickEvent(event);
1240 void QQuickTextInput::mousePressEvent(QMouseEvent *event)
1242 Q_D(QQuickTextInput);
1244 d->pressPos = event->localPos();
1246 if (d->focusOnPress) {
1247 bool hadActiveFocus = hasActiveFocus();
1249 // re-open input panel on press if already focused
1250 if (hasActiveFocus() && hadActiveFocus && !d->m_readOnly)
1251 openSoftwareInputPanel();
1253 if (d->selectByMouse) {
1254 setKeepMouseGrab(false);
1255 d->selectPressed = true;
1256 QPoint distanceVector = d->pressPos.toPoint() - d->tripleClickStartPoint;
1257 if (d->hasPendingTripleClick()
1258 && distanceVector.manhattanLength() < qApp->styleHints()->startDragDistance()) {
1259 event->setAccepted(true);
1265 if (d->sendMouseEventToInputContext(event))
1268 bool mark = (event->modifiers() & Qt::ShiftModifier) && d->selectByMouse;
1269 int cursor = d->positionAt(event->localPos());
1270 d->moveCursor(cursor, mark);
1271 event->setAccepted(true);
1274 void QQuickTextInput::mouseMoveEvent(QMouseEvent *event)
1276 Q_D(QQuickTextInput);
1278 if (d->selectPressed) {
1279 if (qAbs(int(event->localPos().x() - d->pressPos.x())) > qApp->styleHints()->startDragDistance())
1280 setKeepMouseGrab(true);
1282 if (d->composeMode()) {
1284 int startPos = d->positionAt(d->pressPos);
1285 int currentPos = d->positionAt(event->localPos());
1286 if (startPos != currentPos)
1287 d->setSelection(startPos, currentPos - startPos);
1289 moveCursorSelection(d->positionAt(event->localPos()), d->mouseSelectionMode);
1291 event->setAccepted(true);
1293 QQuickImplicitSizeItem::mouseMoveEvent(event);
1297 void QQuickTextInput::mouseReleaseEvent(QMouseEvent *event)
1299 Q_D(QQuickTextInput);
1300 if (d->sendMouseEventToInputContext(event))
1302 if (d->selectPressed) {
1303 d->selectPressed = false;
1304 setKeepMouseGrab(false);
1306 #ifndef QT_NO_CLIPBOARD
1307 if (QGuiApplication::clipboard()->supportsSelection()) {
1308 if (event->button() == Qt::LeftButton) {
1309 d->copy(QClipboard::Selection);
1310 } else if (!d->m_readOnly && event->button() == Qt::MidButton) {
1312 d->insert(QGuiApplication::clipboard()->text(QClipboard::Selection));
1316 if (!event->isAccepted())
1317 QQuickImplicitSizeItem::mouseReleaseEvent(event);
1320 bool QQuickTextInputPrivate::sendMouseEventToInputContext(QMouseEvent *event)
1322 #if !defined QT_NO_IM
1323 if (composeMode()) {
1324 int tmp_cursor = positionAt(event->localPos());
1325 int mousePos = tmp_cursor - m_cursor;
1326 if (mousePos >= 0 && mousePos <= m_textLayout.preeditAreaText().length()) {
1327 if (event->type() == QEvent::MouseButtonRelease) {
1328 qApp->inputPanel()->invokeAction(QInputPanel::Click, mousePos);
1341 void QQuickTextInput::mouseUngrabEvent()
1343 Q_D(QQuickTextInput);
1344 d->selectPressed = false;
1345 setKeepMouseGrab(false);
1348 bool QQuickTextInput::event(QEvent* ev)
1350 #ifndef QT_NO_SHORTCUT
1351 Q_D(QQuickTextInput);
1352 if (ev->type() == QEvent::ShortcutOverride) {
1355 QKeyEvent* ke = static_cast<QKeyEvent*>(ev);
1356 if (ke == QKeySequence::Copy
1357 || ke == QKeySequence::Paste
1358 || ke == QKeySequence::Cut
1359 || ke == QKeySequence::Redo
1360 || ke == QKeySequence::Undo
1361 || ke == QKeySequence::MoveToNextWord
1362 || ke == QKeySequence::MoveToPreviousWord
1363 || ke == QKeySequence::MoveToStartOfDocument
1364 || ke == QKeySequence::MoveToEndOfDocument
1365 || ke == QKeySequence::SelectNextWord
1366 || ke == QKeySequence::SelectPreviousWord
1367 || ke == QKeySequence::SelectStartOfLine
1368 || ke == QKeySequence::SelectEndOfLine
1369 || ke == QKeySequence::SelectStartOfBlock
1370 || ke == QKeySequence::SelectEndOfBlock
1371 || ke == QKeySequence::SelectStartOfDocument
1372 || ke == QKeySequence::SelectAll
1373 || ke == QKeySequence::SelectEndOfDocument) {
1375 } else if (ke->modifiers() == Qt::NoModifier || ke->modifiers() == Qt::ShiftModifier
1376 || ke->modifiers() == Qt::KeypadModifier) {
1377 if (ke->key() < Qt::Key_Escape) {
1381 switch (ke->key()) {
1382 case Qt::Key_Delete:
1385 case Qt::Key_Backspace:
1397 return QQuickImplicitSizeItem::event(ev);
1400 void QQuickTextInput::geometryChanged(const QRectF &newGeometry,
1401 const QRectF &oldGeometry)
1403 Q_D(QQuickTextInput);
1404 if (newGeometry.width() != oldGeometry.width())
1406 updateCursorRectangle();
1407 QQuickImplicitSizeItem::geometryChanged(newGeometry, oldGeometry);
1410 void QQuickTextInputPrivate::updateHorizontalScroll()
1412 Q_Q(QQuickTextInput);
1413 QTextLine currentLine = m_textLayout.lineForTextPosition(m_cursor + m_preeditCursor);
1414 const int preeditLength = m_textLayout.preeditAreaText().length();
1415 const int width = q->width();
1416 int widthUsed = currentLine.isValid() ? qRound(currentLine.naturalTextWidth()) : 0;
1417 int previousScroll = hscroll;
1419 if (!autoScroll || widthUsed <= width || m_echoMode == QQuickTextInput::NoEcho) {
1422 int cix = qRound(currentLine.cursorToX(m_cursor + preeditLength));
1423 if (cix - hscroll >= width) {
1424 // text doesn't fit, cursor is to the right of br (scroll right)
1425 hscroll = cix - width;
1426 } else if (cix - hscroll < 0 && hscroll < widthUsed) {
1427 // text doesn't fit, cursor is to the left of br (scroll left)
1429 } else if (widthUsed - hscroll < width) {
1430 // text doesn't fit, text document is to the left of br; align
1432 hscroll = widthUsed - width;
1434 if (preeditLength > 0) {
1435 // check to ensure long pre-edit text doesn't push the cursor
1437 cix = qRound(currentLine.cursorToX(m_cursor + qMax(0, m_preeditCursor - 1)));
1442 if (previousScroll != hscroll)
1443 textLayoutDirty = true;
1446 void QQuickTextInputPrivate::updateVerticalScroll()
1448 Q_Q(QQuickTextInput);
1449 const int preeditLength = m_textLayout.preeditAreaText().length();
1450 const int height = q->height();
1451 int heightUsed = boundingRect.height();
1452 int previousScroll = vscroll;
1454 if (!autoScroll || heightUsed <= height) {
1455 // text fits in br; use vscroll for alignment
1456 switch (vAlign & ~(Qt::AlignAbsolute|Qt::AlignHorizontal_Mask)) {
1457 case Qt::AlignBottom:
1458 vscroll = heightUsed - height;
1460 case Qt::AlignVCenter:
1461 vscroll = (heightUsed - height) / 2;
1469 QRectF r = m_textLayout.lineForTextPosition(m_cursor + preeditLength).rect();
1470 int top = qFloor(r.top());
1471 int bottom = qCeil(r.bottom());
1473 if (bottom - vscroll >= height) {
1474 // text doesn't fit, cursor is to the below the br (scroll down)
1475 vscroll = bottom - height;
1476 } else if (top - vscroll < 0 && vscroll < heightUsed) {
1477 // text doesn't fit, cursor is above br (scroll up)
1479 } else if (heightUsed - vscroll < height) {
1480 // text doesn't fit, text document is to the left of br; align
1482 vscroll = heightUsed - height;
1484 if (preeditLength > 0) {
1485 // check to ensure long pre-edit text doesn't push the cursor
1487 top = qRound(m_textLayout.lineForTextPosition(
1488 m_cursor + qMax(0, m_preeditCursor - 1)).rect().top());
1493 if (previousScroll != vscroll)
1494 textLayoutDirty = true;
1497 QSGNode *QQuickTextInput::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data)
1500 Q_D(QQuickTextInput);
1502 QQuickTextNode *node = static_cast<QQuickTextNode *>(oldNode);
1504 node = new QQuickTextNode(QQuickItemPrivate::get(this)->sceneGraphContext());
1507 if (!d->textLayoutDirty) {
1508 QSGSimpleRectNode *cursorNode = node->cursorNode();
1509 if (cursorNode != 0 && !isReadOnly()) {
1510 cursorNode->setRect(cursorRectangle());
1512 if (!d->cursorVisible || (!d->m_blinkStatus && d->m_blinkPeriod > 0)) {
1519 node->deleteContent();
1520 node->setMatrix(QMatrix4x4());
1522 QPoint offset = QPoint(0,0);
1523 QFontMetrics fm = QFontMetrics(d->font);
1524 if (d->autoScroll) {
1525 // the y offset is there to keep the baseline constant in case we have script changes in the text.
1526 offset = -QPoint(d->hscroll, d->vscroll + d->m_ascent - fm.ascent());
1528 offset = -QPoint(d->hscroll, d->vscroll);
1531 if (!d->m_textLayout.text().isEmpty()) {
1532 node->addTextLayout(offset, &d->m_textLayout, d->color,
1533 QQuickText::Normal, QColor(),
1534 d->selectionColor, d->selectedTextColor,
1535 d->selectionStart(),
1536 d->selectionEnd() - 1); // selectionEnd() returns first char after
1540 if (!isReadOnly() && d->cursorItem == 0) {
1541 node->setCursor(cursorRectangle(), d->color);
1542 if (!d->cursorVisible || (!d->m_blinkStatus && d->m_blinkPeriod > 0)) {
1549 d->textLayoutDirty = false;
1555 QVariant QQuickTextInput::inputMethodQuery(Qt::InputMethodQuery property) const
1557 Q_D(const QQuickTextInput);
1560 return QVariant((bool)(flags() & ItemAcceptsInputMethod));
1562 return QVariant((int)inputMethodHints());
1563 case Qt::ImCursorRectangle:
1564 return cursorRectangle();
1567 case Qt::ImCursorPosition:
1568 return QVariant(d->m_cursor);
1569 case Qt::ImSurroundingText:
1570 if (d->m_echoMode == PasswordEchoOnEdit && !d->m_passwordEchoEditing) {
1571 return QVariant(displayText());
1573 return QVariant(d->realText());
1575 case Qt::ImCurrentSelection:
1576 return QVariant(selectedText());
1577 case Qt::ImMaximumTextLength:
1578 return QVariant(maxLength());
1579 case Qt::ImAnchorPosition:
1580 if (d->selectionStart() == d->selectionEnd())
1581 return QVariant(d->m_cursor);
1582 else if (d->selectionStart() == d->m_cursor)
1583 return QVariant(d->selectionEnd());
1585 return QVariant(d->selectionStart());
1592 \qmlmethod void QtQuick2::TextInput::deselect()
1594 Removes active text selection.
1596 void QQuickTextInput::deselect()
1598 Q_D(QQuickTextInput);
1603 \qmlmethod void QtQuick2::TextInput::selectAll()
1605 Causes all text to be selected.
1607 void QQuickTextInput::selectAll()
1609 Q_D(QQuickTextInput);
1610 d->setSelection(0, text().length());
1614 \qmlmethod void QtQuick2::TextInput::isRightToLeft(int start, int end)
1616 Returns true if the natural reading direction of the editor text
1617 found between positions \a start and \a end is right to left.
1619 bool QQuickTextInput::isRightToLeft(int start, int end)
1622 qmlInfo(this) << "isRightToLeft(start, end) called with the end property being smaller than the start.";
1625 return text().mid(start, end - start).isRightToLeft();
1629 #ifndef QT_NO_CLIPBOARD
1631 \qmlmethod QtQuick2::TextInput::cut()
1633 Moves the currently selected text to the system clipboard.
1635 void QQuickTextInput::cut()
1637 Q_D(QQuickTextInput);
1643 \qmlmethod QtQuick2::TextInput::copy()
1645 Copies the currently selected text to the system clipboard.
1647 void QQuickTextInput::copy()
1649 Q_D(QQuickTextInput);
1654 \qmlmethod QtQuick2::TextInput::paste()
1656 Replaces the currently selected text by the contents of the system clipboard.
1658 void QQuickTextInput::paste()
1660 Q_D(QQuickTextInput);
1664 #endif // QT_NO_CLIPBOARD
1667 \qmlmethod void QtQuick2::TextInput::selectWord()
1669 Causes the word closest to the current cursor position to be selected.
1671 void QQuickTextInput::selectWord()
1673 Q_D(QQuickTextInput);
1674 d->selectWordAtPos(d->m_cursor);
1678 \qmlproperty bool QtQuick2::TextInput::smooth
1680 This property holds whether the text is smoothly scaled or transformed.
1682 Smooth filtering gives better visual quality, but is slower. If
1683 the item is displayed at its natural size, this property has no visual or
1686 \note Generally scaling artifacts are only visible if the item is stationary on
1687 the screen. A common pattern when animating an item is to disable smooth
1688 filtering at the beginning of the animation and reenable it at the conclusion.
1692 \qmlproperty string QtQuick2::TextInput::passwordCharacter
1694 This is the character displayed when echoMode is set to Password or
1695 PasswordEchoOnEdit. By default it is an asterisk.
1697 If this property is set to a string with more than one character,
1698 the first character is used. If the string is empty, the value
1699 is ignored and the property is not set.
1701 QString QQuickTextInput::passwordCharacter() const
1703 Q_D(const QQuickTextInput);
1704 return QString(d->m_passwordCharacter);
1707 void QQuickTextInput::setPasswordCharacter(const QString &str)
1709 Q_D(QQuickTextInput);
1710 if (str.length() < 1)
1712 d->m_passwordCharacter = str.constData()[0];
1713 if (d->m_echoMode == Password || d->m_echoMode == PasswordEchoOnEdit)
1714 d->updateDisplayText();
1715 emit passwordCharacterChanged();
1719 \qmlproperty string QtQuick2::TextInput::displayText
1721 This is the text displayed in the TextInput.
1723 If \l echoMode is set to TextInput::Normal, this holds the
1724 same value as the TextInput::text property. Otherwise,
1725 this property holds the text visible to the user, while
1726 the \l text property holds the actual entered text.
1728 QString QQuickTextInput::displayText() const
1730 Q_D(const QQuickTextInput);
1731 return d->m_textLayout.text();
1735 \qmlproperty bool QtQuick2::TextInput::selectByMouse
1739 If true, the user can use the mouse to select text in some
1740 platform-specific way. Note that for some platforms this may
1741 not be an appropriate interaction (eg. may conflict with how
1742 the text needs to behave inside a Flickable.
1744 bool QQuickTextInput::selectByMouse() const
1746 Q_D(const QQuickTextInput);
1747 return d->selectByMouse;
1750 void QQuickTextInput::setSelectByMouse(bool on)
1752 Q_D(QQuickTextInput);
1753 if (d->selectByMouse != on) {
1754 d->selectByMouse = on;
1755 emit selectByMouseChanged(on);
1760 \qmlproperty enum QtQuick2::TextInput::mouseSelectionMode
1762 Specifies how text should be selected using a mouse.
1765 \o TextInput.SelectCharacters - The selection is updated with individual characters. (Default)
1766 \o TextInput.SelectWords - The selection is updated with whole words.
1769 This property only applies when \l selectByMouse is true.
1772 QQuickTextInput::SelectionMode QQuickTextInput::mouseSelectionMode() const
1774 Q_D(const QQuickTextInput);
1775 return d->mouseSelectionMode;
1778 void QQuickTextInput::setMouseSelectionMode(SelectionMode mode)
1780 Q_D(QQuickTextInput);
1781 if (d->mouseSelectionMode != mode) {
1782 d->mouseSelectionMode = mode;
1783 emit mouseSelectionModeChanged(mode);
1788 \qmlproperty bool QtQuick2::TextInput::canPaste
1790 Returns true if the TextInput is writable and the content of the clipboard is
1791 suitable for pasting into the TextEdit.
1793 bool QQuickTextInput::canPaste() const
1795 Q_D(const QQuickTextInput);
1799 void QQuickTextInput::moveCursorSelection(int position)
1801 Q_D(QQuickTextInput);
1802 d->moveCursor(position, true);
1806 \qmlmethod void QtQuick2::TextInput::moveCursorSelection(int position, SelectionMode mode = TextInput.SelectCharacters)
1808 Moves the cursor to \a position and updates the selection according to the optional \a mode
1809 parameter. (To only move the cursor, set the \l cursorPosition property.)
1811 When this method is called it additionally sets either the
1812 selectionStart or the selectionEnd (whichever was at the previous cursor position)
1813 to the specified position. This allows you to easily extend and contract the selected
1816 The selection mode specifies whether the selection is updated on a per character or a per word
1817 basis. If not specified the selection mode will default to TextInput.SelectCharacters.
1820 \o TextEdit.SelectCharacters - Sets either the selectionStart or selectionEnd (whichever was at
1821 the previous cursor position) to the specified position.
1822 \o TextEdit.SelectWords - Sets the selectionStart and selectionEnd to include all
1823 words between the specified position and the previous cursor position. Words partially in the
1827 For example, take this sequence of calls:
1831 moveCursorSelection(9, TextInput.SelectCharacters)
1832 moveCursorSelection(7, TextInput.SelectCharacters)
1835 This moves the cursor to position 5, extend the selection end from 5 to 9
1836 and then retract the selection end from 9 to 7, leaving the text from position 5 to 7
1837 selected (the 6th and 7th characters).
1839 The same sequence with TextInput.SelectWords will extend the selection start to a word boundary
1840 before or on position 5 and extend the selection end to a word boundary on or past position 9.
1842 void QQuickTextInput::moveCursorSelection(int pos, SelectionMode mode)
1844 Q_D(QQuickTextInput);
1846 if (mode == SelectCharacters) {
1847 d->moveCursor(pos, true);
1848 } else if (pos != d->m_cursor){
1849 const int cursor = d->m_cursor;
1851 if (!d->hasSelectedText())
1852 anchor = d->m_cursor;
1853 else if (d->selectionStart() == d->m_cursor)
1854 anchor = d->selectionEnd();
1856 anchor = d->selectionStart();
1858 if (anchor < pos || (anchor == pos && cursor < pos)) {
1859 const QString text = this->text();
1860 QTextBoundaryFinder finder(QTextBoundaryFinder::Word, text);
1861 finder.setPosition(anchor);
1863 const QTextBoundaryFinder::BoundaryReasons reasons = finder.boundaryReasons();
1864 if (anchor < text.length() && (!(reasons & QTextBoundaryFinder::StartWord)
1865 || ((reasons & QTextBoundaryFinder::EndWord) && anchor > cursor))) {
1866 finder.toPreviousBoundary();
1868 anchor = finder.position() != -1 ? finder.position() : 0;
1870 finder.setPosition(pos);
1871 if (pos > 0 && !finder.boundaryReasons())
1872 finder.toNextBoundary();
1873 const int cursor = finder.position() != -1 ? finder.position() : text.length();
1875 d->setSelection(anchor, cursor - anchor);
1876 } else if (anchor > pos || (anchor == pos && cursor > pos)) {
1877 const QString text = this->text();
1878 QTextBoundaryFinder finder(QTextBoundaryFinder::Word, text);
1879 finder.setPosition(anchor);
1881 const QTextBoundaryFinder::BoundaryReasons reasons = finder.boundaryReasons();
1882 if (anchor > 0 && (!(reasons & QTextBoundaryFinder::EndWord)
1883 || ((reasons & QTextBoundaryFinder::StartWord) && anchor < cursor))) {
1884 finder.toNextBoundary();
1887 anchor = finder.position() != -1 ? finder.position() : text.length();
1889 finder.setPosition(pos);
1890 if (pos < text.length() && !finder.boundaryReasons())
1891 finder.toPreviousBoundary();
1892 const int cursor = finder.position() != -1 ? finder.position() : 0;
1894 d->setSelection(anchor, cursor - anchor);
1900 \qmlmethod void QtQuick2::TextInput::openSoftwareInputPanel()
1902 Opens software input panels like virtual keyboards for typing, useful for
1903 customizing when you want the input keyboard to be shown and hidden in
1906 By default the opening of input panels follows the platform style. Input panels are
1907 always closed if no editor has active focus.
1909 You can disable the automatic behavior by setting the property \c activeFocusOnPress to false
1910 and use functions openSoftwareInputPanel() and closeSoftwareInputPanel() to implement
1911 the behavior you want.
1913 Only relevant on platforms, which provide virtual keyboards.
1919 text: "Hello world!"
1920 activeFocusOnPress: false
1922 anchors.fill: parent
1924 if (!textInput.activeFocus) {
1925 textInput.forceActiveFocus()
1926 textInput.openSoftwareInputPanel();
1928 textInput.focus = false;
1931 onPressAndHold: textInput.closeSoftwareInputPanel();
1936 void QQuickTextInput::openSoftwareInputPanel()
1939 qGuiApp->inputPanel()->show();
1943 \qmlmethod void QtQuick2::TextInput::closeSoftwareInputPanel()
1945 Closes a software input panel like a virtual keyboard shown on the screen, useful
1946 for customizing when you want the input keyboard to be shown and hidden in
1949 By default the opening of input panels follows the platform style. Input panels are
1950 always closed if no editor has active focus.
1952 You can disable the automatic behavior by setting the property \c activeFocusOnPress to false
1953 and use functions openSoftwareInputPanel() and closeSoftwareInputPanel() to implement
1954 the behavior you want.
1956 Only relevant on platforms, which provide virtual keyboards.
1962 text: "Hello world!"
1963 activeFocusOnPress: false
1965 anchors.fill: parent
1967 if (!textInput.activeFocus) {
1968 textInput.forceActiveFocus();
1969 textInput.openSoftwareInputPanel();
1971 textInput.focus = false;
1974 onPressAndHold: textInput.closeSoftwareInputPanel();
1979 void QQuickTextInput::closeSoftwareInputPanel()
1982 qGuiApp->inputPanel()->hide();
1985 void QQuickTextInput::focusInEvent(QFocusEvent *event)
1987 Q_D(const QQuickTextInput);
1988 if (d->focusOnPress && !d->m_readOnly)
1989 openSoftwareInputPanel();
1990 QQuickImplicitSizeItem::focusInEvent(event);
1993 void QQuickTextInput::itemChange(ItemChange change, const ItemChangeData &value)
1995 Q_D(QQuickTextInput);
1996 if (change == ItemActiveFocusHasChanged) {
1997 bool hasFocus = value.boolValue;
1998 d->focused = hasFocus;
1999 setCursorVisible(hasFocus); // ### refactor: && d->canvas && d->canvas->hasFocus()
2000 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
2001 if (!hasFocus && (d->m_passwordEchoEditing || d->m_passwordEchoTimer.isActive())) {
2003 if (!hasFocus && d->m_passwordEchoEditing) {
2005 d->updatePasswordEchoEditing(false);//QQuickTextInputPrivate sets it on key events, but doesn't deal with focus events
2010 QQuickItem::itemChange(change, value);
2014 \qmlproperty bool QtQuick2::TextInput::inputMethodComposing
2017 This property holds whether the TextInput has partial text input from an
2020 While it is composing an input method may rely on mouse or key events from
2021 the TextInput to edit or commit the partial text. This property can be
2022 used to determine when to disable events handlers that may interfere with
2023 the correct operation of an input method.
2025 bool QQuickTextInput::isInputMethodComposing() const
2027 Q_D(const QQuickTextInput);
2028 return d->preeditAreaText().length() > 0;
2031 void QQuickTextInputPrivate::init()
2033 Q_Q(QQuickTextInput);
2034 q->setSmooth(smooth);
2035 q->setAcceptedMouseButtons(Qt::LeftButton);
2036 q->setFlag(QQuickItem::ItemAcceptsInputMethod);
2037 q->setFlag(QQuickItem::ItemHasContents);
2038 #ifndef QT_NO_CLIPBOARD
2039 q->connect(q, SIGNAL(readOnlyChanged(bool)),
2040 q, SLOT(q_canPasteChanged()));
2041 q->connect(QGuiApplication::clipboard(), SIGNAL(dataChanged()),
2042 q, SLOT(q_canPasteChanged()));
2043 canPaste = !m_readOnly && QGuiApplication::clipboard()->text().length() != 0;
2044 #endif // QT_NO_CLIPBOARD
2045 m_textLayout.beginLayout();
2046 m_textLayout.createLine();
2047 m_textLayout.endLayout();
2049 imHints &= ~Qt::ImhMultiLine;
2050 oldValidity = hasAcceptableInput(m_text);
2051 lastSelectionStart = 0;
2052 lastSelectionEnd = 0;
2053 selectedTextColor = m_palette.color(QPalette::HighlightedText);
2054 selectionColor = m_palette.color(QPalette::Highlight);
2055 determineHorizontalAlignment();
2057 if (!qmlDisableDistanceField()) {
2058 QTextOption option = m_textLayout.textOption();
2059 option.setUseDesignMetrics(true);
2060 m_textLayout.setTextOption(option);
2064 void QQuickTextInput::updateCursorRectangle()
2066 Q_D(QQuickTextInput);
2067 if (!isComponentComplete())
2070 d->updateHorizontalScroll();
2071 d->updateVerticalScroll();
2074 emit cursorRectangleChanged();
2075 if (d->cursorItem) {
2076 QRectF r = cursorRectangle();
2077 d->cursorItem->setPos(r.topLeft());
2078 d->cursorItem->setHeight(r.height());
2082 void QQuickTextInput::selectionChanged()
2084 Q_D(QQuickTextInput);
2085 updateRect();//TODO: Only update rect in selection
2086 emit selectedTextChanged();
2088 if (d->lastSelectionStart != d->selectionStart()) {
2089 d->lastSelectionStart = d->selectionStart();
2090 if (d->lastSelectionStart == -1)
2091 d->lastSelectionStart = d->m_cursor;
2092 emit selectionStartChanged();
2094 if (d->lastSelectionEnd != d->selectionEnd()) {
2095 d->lastSelectionEnd = d->selectionEnd();
2096 if (d->lastSelectionEnd == -1)
2097 d->lastSelectionEnd = d->m_cursor;
2098 emit selectionEndChanged();
2102 void QQuickTextInputPrivate::showCursor()
2104 if (textNode != 0 && textNode->cursorNode() != 0)
2105 textNode->cursorNode()->setColor(color);
2108 void QQuickTextInputPrivate::hideCursor()
2110 if (textNode != 0 && textNode->cursorNode() != 0)
2111 textNode->cursorNode()->setColor(QColor(0, 0, 0, 0));
2114 void QQuickTextInput::updateRect(const QRect &r)
2116 Q_D(QQuickTextInput);
2117 if (!isComponentComplete())
2121 d->textLayoutDirty = true;
2127 QRectF QQuickTextInput::boundingRect() const
2129 Q_D(const QQuickTextInput);
2131 QRectF r = d->boundingRect;
2132 int cursorWidth = d->cursorItem ? d->cursorItem->width() : d->m_cursorWidth;
2134 // Could include font max left/right bearings to either side of rectangle.
2136 r.setRight(r.right() + cursorWidth);
2137 r.translate(-d->hscroll, -d->vscroll);
2141 void QQuickTextInput::q_canPasteChanged()
2143 Q_D(QQuickTextInput);
2144 bool old = d->canPaste;
2145 #ifndef QT_NO_CLIPBOARD
2146 d->canPaste = !d->m_readOnly && QGuiApplication::clipboard()->text().length() != 0;
2148 if (d->canPaste != old)
2149 emit canPasteChanged();
2152 // ### these should come from QStyleHints
2153 const int textCursorWidth = 1;
2154 const bool fullWidthSelection = true;
2159 Updates the display text based of the current edit text
2160 If the text has changed will emit displayTextChanged()
2162 void QQuickTextInputPrivate::updateDisplayText(bool forceUpdate)
2164 QString orig = m_textLayout.text();
2166 if (m_echoMode == QQuickTextInput::NoEcho)
2167 str = QString::fromLatin1("");
2171 if (m_echoMode == QQuickTextInput::Password) {
2172 str.fill(m_passwordCharacter);
2173 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
2174 if (m_passwordEchoTimer.isActive() && m_cursor > 0 && m_cursor <= m_text.length()) {
2175 int cursor = m_cursor - 1;
2176 QChar uc = m_text.at(cursor);
2178 if (cursor > 0 && uc.unicode() >= 0xdc00 && uc.unicode() < 0xe000) {
2179 // second half of a surrogate, check if we have the first half as well,
2180 // if yes restore both at once
2181 uc = m_text.at(cursor - 1);
2182 if (uc.unicode() >= 0xd800 && uc.unicode() < 0xdc00)
2183 str[cursor - 1] = uc;
2187 } else if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit && !m_passwordEchoEditing) {
2188 str.fill(m_passwordCharacter);
2191 // replace certain non-printable characters with spaces (to avoid
2192 // drawing boxes when using fonts that don't have glyphs for such
2194 QChar* uc = str.data();
2195 for (int i = 0; i < (int)str.length(); ++i) {
2196 if ((uc[i] < 0x20 && uc[i] != 0x09)
2197 || uc[i] == QChar::LineSeparator
2198 || uc[i] == QChar::ParagraphSeparator
2199 || uc[i] == QChar::ObjectReplacementCharacter)
2200 uc[i] = QChar(0x0020);
2203 if (str != orig || forceUpdate) {
2204 m_textLayout.setText(str);
2205 updateLayout(); // polish?
2206 emit q_func()->displayTextChanged();
2210 void QQuickTextInputPrivate::updateLayout()
2212 Q_Q(QQuickTextInput);
2214 if (!q->isComponentComplete())
2217 QTextOption option = m_textLayout.textOption();
2218 option.setTextDirection(m_layoutDirection);
2219 option.setFlags(QTextOption::IncludeTrailingSpaces);
2220 option.setWrapMode(QTextOption::WrapMode(wrapMode));
2221 option.setAlignment(Qt::Alignment(q->effectiveHAlign()));
2222 m_textLayout.setTextOption(option);
2223 m_textLayout.setFont(font);
2225 boundingRect = QRectF();
2226 m_textLayout.beginLayout();
2227 QTextLine line = m_textLayout.createLine();
2228 qreal lineWidth = q->widthValid() ? q->width() : INT_MAX;
2230 QTextLine firstLine = line;
2232 line.setLineWidth(lineWidth);
2233 line.setPosition(QPointF(line.position().x(), height));
2234 boundingRect = boundingRect.united(line.naturalTextRect());
2236 height += line.height();
2237 line = m_textLayout.createLine();
2238 } while (line.isValid());
2239 m_textLayout.endLayout();
2241 option.setWrapMode(QTextOption::NoWrap);
2242 m_textLayout.setTextOption(option);
2244 m_ascent = qRound(firstLine.ascent());
2245 textLayoutDirty = true;
2248 q->setImplicitSize(qCeil(boundingRect.width()), qCeil(boundingRect.height()));
2252 #ifndef QT_NO_CLIPBOARD
2256 Copies the currently selected text into the clipboard using the given
2259 \note If the echo mode is set to a mode other than Normal then copy
2260 will not work. This is to prevent using copy as a method of bypassing
2261 password features of the line control.
2263 void QQuickTextInputPrivate::copy(QClipboard::Mode mode) const
2265 QString t = selectedText();
2266 if (!t.isEmpty() && m_echoMode == QQuickTextInput::Normal) {
2267 QGuiApplication::clipboard()->setText(t, mode);
2274 Inserts the text stored in the application clipboard into the line
2279 void QQuickTextInputPrivate::paste(QClipboard::Mode clipboardMode)
2281 QString clip = QGuiApplication::clipboard()->text(clipboardMode);
2282 if (!clip.isEmpty() || hasSelectedText()) {
2283 separate(); //make it a separate undo/redo command
2289 #endif // !QT_NO_CLIPBOARD
2294 Exits preedit mode and commits parts marked as tentative commit
2296 void QQuickTextInputPrivate::commitPreedit()
2301 qApp->inputPanel()->reset();
2303 if (!m_tentativeCommit.isEmpty()) {
2304 internalInsert(m_tentativeCommit);
2305 m_tentativeCommit.clear();
2306 finishChange(-1, true/*not used, not documented*/, false);
2309 m_preeditCursor = 0;
2310 m_textLayout.setPreeditArea(-1, QString());
2311 m_textLayout.clearAdditionalFormats();
2318 Handles the behavior for the backspace key or function.
2319 Removes the current selection if there is a selection, otherwise
2320 removes the character prior to the cursor position.
2324 void QQuickTextInputPrivate::backspace()
2326 int priorState = m_undoState;
2327 if (hasSelectedText()) {
2328 removeSelectedText();
2329 } else if (m_cursor) {
2332 m_cursor = prevMaskBlank(m_cursor);
2333 QChar uc = m_text.at(m_cursor);
2334 if (m_cursor > 0 && uc.unicode() >= 0xdc00 && uc.unicode() < 0xe000) {
2335 // second half of a surrogate, check if we have the first half as well,
2336 // if yes delete both at once
2337 uc = m_text.at(m_cursor - 1);
2338 if (uc.unicode() >= 0xd800 && uc.unicode() < 0xdc00) {
2339 internalDelete(true);
2343 internalDelete(true);
2345 finishChange(priorState);
2351 Handles the behavior for the delete key or function.
2352 Removes the current selection if there is a selection, otherwise
2353 removes the character after the cursor position.
2357 void QQuickTextInputPrivate::del()
2359 int priorState = m_undoState;
2360 if (hasSelectedText()) {
2361 removeSelectedText();
2363 int n = m_textLayout.nextCursorPosition(m_cursor) - m_cursor;
2367 finishChange(priorState);
2373 Inserts the given \a newText at the current cursor position.
2374 If there is any selected text it is removed prior to insertion of
2377 void QQuickTextInputPrivate::insert(const QString &newText)
2379 int priorState = m_undoState;
2380 removeSelectedText();
2381 internalInsert(newText);
2382 finishChange(priorState);
2388 Clears the line control text.
2390 void QQuickTextInputPrivate::clear()
2392 int priorState = m_undoState;
2394 m_selend = m_text.length();
2395 removeSelectedText();
2397 finishChange(priorState, /*update*/false, /*edited*/false);
2403 Sets \a length characters from the given \a start position as selected.
2404 The given \a start position must be within the current text for
2405 the line control. If \a length characters cannot be selected, then
2406 the selection will extend to the end of the current text.
2408 void QQuickTextInputPrivate::setSelection(int start, int length)
2410 Q_Q(QQuickTextInput);
2413 if (start < 0 || start > (int)m_text.length()){
2414 qWarning("QQuickTextInputPrivate::setSelection: Invalid start position");
2419 if (start == m_selstart && start + length == m_selend && m_cursor == m_selend)
2422 m_selend = qMin(start + length, (int)m_text.length());
2423 m_cursor = m_selend;
2424 } else if (length < 0){
2425 if (start == m_selend && start + length == m_selstart && m_cursor == m_selstart)
2427 m_selstart = qMax(start + length, 0);
2429 m_cursor = m_selstart;
2430 } else if (m_selstart != m_selend) {
2436 emitCursorPositionChanged();
2439 emit q->selectionChanged();
2440 emitCursorPositionChanged();
2446 Initializes the line control with a starting text value of \a txt.
2448 void QQuickTextInputPrivate::init(const QString &txt)
2452 updateDisplayText();
2453 m_cursor = m_text.length();
2459 Sets the password echo editing to \a editing. If password echo editing
2460 is true, then the text of the password is displayed even if the echo
2461 mode is set to QLineEdit::PasswordEchoOnEdit. Password echoing editing
2462 does not affect other echo modes.
2464 void QQuickTextInputPrivate::updatePasswordEchoEditing(bool editing)
2466 cancelPasswordEchoTimer();
2467 m_passwordEchoEditing = editing;
2468 updateDisplayText();
2474 Fixes the current text so that it is valid given any set validators.
2476 Returns true if the text was changed. Otherwise returns false.
2478 bool QQuickTextInputPrivate::fixup() // this function assumes that validate currently returns != Acceptable
2480 #ifndef QT_NO_VALIDATOR
2482 QString textCopy = m_text;
2483 int cursorCopy = m_cursor;
2484 m_validator->fixup(textCopy);
2485 if (m_validator->validate(textCopy, cursorCopy) == QValidator::Acceptable) {
2486 if (textCopy != m_text || cursorCopy != m_cursor)
2487 internalSetText(textCopy, cursorCopy);
2498 Moves the cursor to the given position \a pos. If \a mark is true will
2499 adjust the currently selected text.
2501 void QQuickTextInputPrivate::moveCursor(int pos, bool mark)
2503 Q_Q(QQuickTextInput);
2506 if (pos != m_cursor) {
2509 pos = pos > m_cursor ? nextMaskBlank(pos) : prevMaskBlank(pos);
2513 if (m_selend > m_selstart && m_cursor == m_selstart)
2515 else if (m_selend > m_selstart && m_cursor == m_selend)
2516 anchor = m_selstart;
2519 m_selstart = qMin(anchor, pos);
2520 m_selend = qMax(anchor, pos);
2525 if (mark || m_selDirty) {
2527 emit q->selectionChanged();
2529 emitCursorPositionChanged();
2535 Applies the given input method event \a event to the text of the line
2538 void QQuickTextInputPrivate::processInputMethodEvent(QInputMethodEvent *event)
2540 Q_Q(QQuickTextInput);
2542 int priorState = -1;
2543 bool isGettingInput = !event->commitString().isEmpty()
2544 || event->preeditString() != preeditAreaText()
2545 || event->replacementLength() > 0;
2546 bool cursorPositionChanged = false;
2547 bool selectionChange = false;
2548 m_preeditDirty = event->preeditString() != preeditAreaText();
2550 if (isGettingInput) {
2551 // If any text is being input, remove selected text.
2552 priorState = m_undoState;
2553 if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit && !m_passwordEchoEditing) {
2554 updatePasswordEchoEditing(true);
2556 m_selend = m_text.length();
2558 removeSelectedText();
2561 int c = m_cursor; // cursor position after insertion of commit string
2562 if (event->replacementStart() <= 0)
2563 c += event->commitString().length() - qMin(-event->replacementStart(), event->replacementLength());
2565 m_cursor += event->replacementStart();
2569 // insert commit string
2570 if (event->replacementLength()) {
2571 m_selstart = m_cursor;
2572 m_selend = m_selstart + event->replacementLength();
2573 m_selend = qMin(m_selend, m_text.length());
2574 removeSelectedText();
2576 if (!event->commitString().isEmpty()) {
2577 internalInsert(event->commitString());
2578 cursorPositionChanged = true;
2581 m_cursor = qBound(0, c, m_text.length());
2583 for (int i = 0; i < event->attributes().size(); ++i) {
2584 const QInputMethodEvent::Attribute &a = event->attributes().at(i);
2585 if (a.type == QInputMethodEvent::Selection) {
2586 m_cursor = qBound(0, a.start + a.length, m_text.length());
2588 m_selstart = qMax(0, qMin(a.start, m_text.length()));
2589 m_selend = m_cursor;
2590 if (m_selend < m_selstart) {
2591 qSwap(m_selstart, m_selend);
2593 selectionChange = true;
2595 m_selstart = m_selend = 0;
2597 cursorPositionChanged = true;
2601 m_textLayout.setPreeditArea(m_cursor, event->preeditString());
2603 const int oldPreeditCursor = m_preeditCursor;
2604 m_preeditCursor = event->preeditString().length();
2605 m_hideCursor = false;
2606 QList<QTextLayout::FormatRange> formats;
2607 for (int i = 0; i < event->attributes().size(); ++i) {
2608 const QInputMethodEvent::Attribute &a = event->attributes().at(i);
2609 if (a.type == QInputMethodEvent::Cursor) {
2610 m_preeditCursor = a.start;
2611 m_hideCursor = !a.length;
2612 } else if (a.type == QInputMethodEvent::TextFormat) {
2613 QTextCharFormat f = qvariant_cast<QTextFormat>(a.value).toCharFormat();
2615 QTextLayout::FormatRange o;
2616 o.start = a.start + m_cursor;
2617 o.length = a.length;
2623 m_textLayout.setAdditionalFormats(formats);
2625 updateDisplayText(/*force*/ true);
2626 if (cursorPositionChanged)
2627 emitCursorPositionChanged();
2628 else if (m_preeditCursor != oldPreeditCursor)
2629 q->updateCursorRectangle();
2631 bool tentativeCommitChanged = m_tentativeCommit != event->tentativeCommitString();
2633 if (tentativeCommitChanged) {
2635 m_tentativeCommit = event->tentativeCommitString();
2638 if (isGettingInput || tentativeCommitChanged)
2639 finishChange(priorState);
2641 if (selectionChange)
2642 emit q->selectionChanged();
2648 Sets the selection to cover the word at the given cursor position.
2649 The word boundaries are defined by the behavior of QTextLayout::SkipWords
2652 void QQuickTextInputPrivate::selectWordAtPos(int cursor)
2654 int next = cursor + 1;
2657 int c = m_textLayout.previousCursorPosition(next, QTextLayout::SkipWords);
2658 moveCursor(c, false);
2659 // ## text layout should support end of words.
2660 int end = m_textLayout.nextCursorPosition(c, QTextLayout::SkipWords);
2661 while (end > cursor && m_text[end-1].isSpace())
2663 moveCursor(end, true);
2669 Completes a change to the line control text. If the change is not valid
2670 will undo the line control state back to the given \a validateFromState.
2672 If \a edited is true and the change is valid, will emit textEdited() in
2673 addition to textChanged(). Otherwise only emits textChanged() on a valid
2676 The \a update value is currently unused.
2678 bool QQuickTextInputPrivate::finishChange(int validateFromState, bool update, bool /*edited*/)
2680 Q_Q(QQuickTextInput);
2686 bool wasValidInput = m_validInput;
2687 m_validInput = true;
2688 #ifndef QT_NO_VALIDATOR
2690 QString textCopy = m_text;
2691 int cursorCopy = m_cursor;
2692 m_validInput = (m_validator->validate(textCopy, cursorCopy) != QValidator::Invalid);
2694 if (m_text != textCopy) {
2695 internalSetText(textCopy, cursorCopy);
2698 m_cursor = cursorCopy;
2700 if (!m_tentativeCommit.isEmpty()) {
2701 textCopy.insert(m_cursor, m_tentativeCommit);
2702 bool validInput = m_validator->validate(textCopy, cursorCopy) != QValidator::Invalid;
2704 m_tentativeCommit.clear();
2707 m_tentativeCommit.clear();
2711 if (validateFromState >= 0 && wasValidInput && !m_validInput) {
2712 if (m_transactions.count())
2714 internalUndo(validateFromState);
2715 m_history.resize(m_undoState);
2716 if (m_modifiedState > m_undoState)
2717 m_modifiedState = -1;
2718 m_validInput = true;
2719 m_textDirty = false;
2721 updateDisplayText();
2724 m_textDirty = false;
2725 m_preeditDirty = false;
2726 determineHorizontalAlignment();
2727 emit q->textChanged();
2730 if (m_validInput != wasValidInput)
2731 emit q->acceptableInputChanged();
2733 if (m_preeditDirty) {
2734 m_preeditDirty = false;
2735 determineHorizontalAlignment();
2739 emit q->selectionChanged();
2741 emitCursorPositionChanged();
2748 An internal function for setting the text of the line control.
2750 void QQuickTextInputPrivate::internalSetText(const QString &txt, int pos, bool edited)
2752 Q_Q(QQuickTextInput);
2754 QString oldText = m_text;
2756 m_text = maskString(0, txt, true);
2757 m_text += clearString(m_text.length(), m_maxLength - m_text.length());
2759 m_text = txt.isEmpty() ? txt : txt.left(m_maxLength);
2762 m_modifiedState = m_undoState = 0;
2763 m_cursor = (pos < 0 || pos > m_text.length()) ? m_text.length() : pos;
2764 m_textDirty = (oldText != m_text);
2766 bool changed = finishChange(-1, true, edited);
2767 #ifdef QT_NO_ACCESSIBILITY
2771 QAccessible::updateAccessibility(q, 0, QAccessible::TextUpdated);
2779 Adds the given \a command to the undo history
2780 of the line control. Does not apply the command.
2782 void QQuickTextInputPrivate::addCommand(const Command &cmd)
2784 if (m_separator && m_undoState && m_history[m_undoState - 1].type != Separator) {
2785 m_history.resize(m_undoState + 2);
2786 m_history[m_undoState++] = Command(Separator, m_cursor, 0, m_selstart, m_selend);
2788 m_history.resize(m_undoState + 1);
2790 m_separator = false;
2791 m_history[m_undoState++] = cmd;
2797 Inserts the given string \a s into the line
2800 Also adds the appropriate commands into the undo history.
2801 This function does not call finishChange(), and may leave the text
2802 in an invalid state.
2804 void QQuickTextInputPrivate::internalInsert(const QString &s)
2806 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
2807 Q_Q(QQuickTextInput);
2808 if (m_echoMode == QQuickTextInput::Password)
2809 m_passwordEchoTimer.start(qt_passwordEchoDelay, q);
2811 if (hasSelectedText())
2812 addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
2814 QString ms = maskString(m_cursor, s);
2815 for (int i = 0; i < (int) ms.length(); ++i) {
2816 addCommand (Command(DeleteSelection, m_cursor + i, m_text.at(m_cursor + i), -1, -1));
2817 addCommand(Command(Insert, m_cursor + i, ms.at(i), -1, -1));
2819 m_text.replace(m_cursor, ms.length(), ms);
2820 m_cursor += ms.length();
2821 m_cursor = nextMaskBlank(m_cursor);
2824 int remaining = m_maxLength - m_text.length();
2825 if (remaining != 0) {
2826 m_text.insert(m_cursor, s.left(remaining));
2827 for (int i = 0; i < (int) s.left(remaining).length(); ++i)
2828 addCommand(Command(Insert, m_cursor++, s.at(i), -1, -1));
2837 deletes a single character from the current text. If \a wasBackspace,
2838 the character prior to the cursor is removed. Otherwise the character
2839 after the cursor is removed.
2841 Also adds the appropriate commands into the undo history.
2842 This function does not call finishChange(), and may leave the text
2843 in an invalid state.
2845 void QQuickTextInputPrivate::internalDelete(bool wasBackspace)
2847 if (m_cursor < (int) m_text.length()) {
2848 cancelPasswordEchoTimer();
2849 if (hasSelectedText())
2850 addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
2851 addCommand(Command((CommandType)((m_maskData ? 2 : 0) + (wasBackspace ? Remove : Delete)),
2852 m_cursor, m_text.at(m_cursor), -1, -1));
2854 m_text.replace(m_cursor, 1, clearString(m_cursor, 1));
2855 addCommand(Command(Insert, m_cursor, m_text.at(m_cursor), -1, -1));
2857 m_text.remove(m_cursor, 1);
2866 removes the currently selected text from the line control.
2868 Also adds the appropriate commands into the undo history.
2869 This function does not call finishChange(), and may leave the text
2870 in an invalid state.
2872 void QQuickTextInputPrivate::removeSelectedText()
2874 if (m_selstart < m_selend && m_selend <= (int) m_text.length()) {
2875 cancelPasswordEchoTimer();
2878 addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
2879 if (m_selstart <= m_cursor && m_cursor < m_selend) {
2880 // cursor is within the selection. Split up the commands
2881 // to be able to restore the correct cursor position
2882 for (i = m_cursor; i >= m_selstart; --i)
2883 addCommand (Command(DeleteSelection, i, m_text.at(i), -1, 1));
2884 for (i = m_selend - 1; i > m_cursor; --i)
2885 addCommand (Command(DeleteSelection, i - m_cursor + m_selstart - 1, m_text.at(i), -1, -1));
2887 for (i = m_selend-1; i >= m_selstart; --i)
2888 addCommand (Command(RemoveSelection, i, m_text.at(i), -1, -1));
2891 m_text.replace(m_selstart, m_selend - m_selstart, clearString(m_selstart, m_selend - m_selstart));
2892 for (int i = 0; i < m_selend - m_selstart; ++i)
2893 addCommand(Command(Insert, m_selstart + i, m_text.at(m_selstart + i), -1, -1));
2895 m_text.remove(m_selstart, m_selend - m_selstart);
2897 if (m_cursor > m_selstart)
2898 m_cursor -= qMin(m_cursor, m_selend) - m_selstart;
2907 Parses the input mask specified by \a maskFields to generate
2908 the mask data used to handle input masks.
2910 void QQuickTextInputPrivate::parseInputMask(const QString &maskFields)
2912 int delimiter = maskFields.indexOf(QLatin1Char(';'));
2913 if (maskFields.isEmpty() || delimiter == 0) {
2915 delete [] m_maskData;
2917 m_maxLength = 32767;
2918 internalSetText(QString());
2923 if (delimiter == -1) {
2924 m_blank = QLatin1Char(' ');
2925 m_inputMask = maskFields;
2927 m_inputMask = maskFields.left(delimiter);
2928 m_blank = (delimiter + 1 < maskFields.length()) ? maskFields[delimiter + 1] : QLatin1Char(' ');
2931 // calculate m_maxLength / m_maskData length
2934 for (int i=0; i<m_inputMask.length(); i++) {
2935 c = m_inputMask.at(i);
2936 if (i > 0 && m_inputMask.at(i-1) == QLatin1Char('\\')) {
2940 if (c != QLatin1Char('\\') && c != QLatin1Char('!') &&
2941 c != QLatin1Char('<') && c != QLatin1Char('>') &&
2942 c != QLatin1Char('{') && c != QLatin1Char('}') &&
2943 c != QLatin1Char('[') && c != QLatin1Char(']'))
2947 delete [] m_maskData;
2948 m_maskData = new MaskInputData[m_maxLength];
2950 MaskInputData::Casemode m = MaskInputData::NoCaseMode;
2953 bool escape = false;
2955 for (int i = 0; i < m_inputMask.length(); i++) {
2956 c = m_inputMask.at(i);
2959 m_maskData[index].maskChar = c;
2960 m_maskData[index].separator = s;
2961 m_maskData[index].caseMode = m;
2964 } else if (c == QLatin1Char('<')) {
2965 m = MaskInputData::Lower;
2966 } else if (c == QLatin1Char('>')) {
2967 m = MaskInputData::Upper;
2968 } else if (c == QLatin1Char('!')) {
2969 m = MaskInputData::NoCaseMode;
2970 } else if (c != QLatin1Char('{') && c != QLatin1Char('}') && c != QLatin1Char('[') && c != QLatin1Char(']')) {
2971 switch (c.unicode()) {
2997 m_maskData[index].maskChar = c;
2998 m_maskData[index].separator = s;
2999 m_maskData[index].caseMode = m;
3004 internalSetText(m_text);
3011 checks if the key is valid compared to the inputMask
3013 bool QQuickTextInputPrivate::isValidInput(QChar key, QChar mask) const
3015 switch (mask.unicode()) {
3021 if (key.isLetter() || key == m_blank)
3025 if (key.isLetterOrNumber())
3029 if (key.isLetterOrNumber() || key == m_blank)
3037 if (key.isPrint() || key == m_blank)
3045 if (key.isNumber() || key == m_blank)
3049 if (key.isNumber() && key.digitValue() > 0)
3053 if ((key.isNumber() && key.digitValue() > 0) || key == m_blank)
3057 if (key.isNumber() || key == QLatin1Char('+') || key == QLatin1Char('-') || key == m_blank)
3061 if (key == QLatin1Char('0') || key == QLatin1Char('1'))
3065 if (key == QLatin1Char('0') || key == QLatin1Char('1') || key == m_blank)
3069 if (key.isNumber() || (key >= QLatin1Char('a') && key <= QLatin1Char('f')) || (key >= QLatin1Char('A') && key <= QLatin1Char('F')))
3073 if (key.isNumber() || (key >= QLatin1Char('a') && key <= QLatin1Char('f')) || (key >= QLatin1Char('A') && key <= QLatin1Char('F')) || key == m_blank)
3085 Returns true if the given text \a str is valid for any
3086 validator or input mask set for the line control.
3088 Otherwise returns false
3090 bool QQuickTextInputPrivate::hasAcceptableInput(const QString &str) const
3092 #ifndef QT_NO_VALIDATOR
3093 QString textCopy = str;
3094 int cursorCopy = m_cursor;
3095 if (m_validator && m_validator->validate(textCopy, cursorCopy)
3096 != QValidator::Acceptable)
3103 if (str.length() != m_maxLength)
3106 for (int i=0; i < m_maxLength; ++i) {
3107 if (m_maskData[i].separator) {
3108 if (str.at(i) != m_maskData[i].maskChar)
3111 if (!isValidInput(str.at(i), m_maskData[i].maskChar))
3121 Applies the inputMask on \a str starting from position \a pos in the mask. \a clear
3122 specifies from where characters should be gotten when a separator is met in \a str - true means
3123 that blanks will be used, false that previous input is used.
3124 Calling this when no inputMask is set is undefined.
3126 QString QQuickTextInputPrivate::maskString(uint pos, const QString &str, bool clear) const
3128 if (pos >= (uint)m_maxLength)
3129 return QString::fromLatin1("");
3132 fill = clear ? clearString(0, m_maxLength) : m_text;
3135 QString s = QString::fromLatin1("");
3137 while (i < m_maxLength) {
3138 if (strIndex < str.length()) {
3139 if (m_maskData[i].separator) {
3140 s += m_maskData[i].maskChar;
3141 if (str[(int)strIndex] == m_maskData[i].maskChar)
3145 if (isValidInput(str[(int)strIndex], m_maskData[i].maskChar)) {
3146 switch (m_maskData[i].caseMode) {
3147 case MaskInputData::Upper:
3148 s += str[(int)strIndex].toUpper();
3150 case MaskInputData::Lower:
3151 s += str[(int)strIndex].toLower();
3154 s += str[(int)strIndex];
3158 // search for separator first
3159 int n = findInMask(i, true, true, str[(int)strIndex]);
3161 if (str.length() != 1 || i == 0 || (i > 0 && (!m_maskData[i-1].separator || m_maskData[i-1].maskChar != str[(int)strIndex]))) {
3162 s += fill.mid(i, n-i+1);
3163 i = n + 1; // update i to find + 1
3166 // search for valid m_blank if not
3167 n = findInMask(i, true, false, str[(int)strIndex]);
3169 s += fill.mid(i, n-i);
3170 switch (m_maskData[n].caseMode) {
3171 case MaskInputData::Upper:
3172 s += str[(int)strIndex].toUpper();
3174 case MaskInputData::Lower:
3175 s += str[(int)strIndex].toLower();
3178 s += str[(int)strIndex];
3180 i = n + 1; // updates i to find + 1
3198 Returns a "cleared" string with only separators and blank chars.
3199 Calling this when no inputMask is set is undefined.
3201 QString QQuickTextInputPrivate::clearString(uint pos, uint len) const
3203 if (pos >= (uint)m_maxLength)
3207 int end = qMin((uint)m_maxLength, pos + len);
3208 for (int i = pos; i < end; ++i)
3209 if (m_maskData[i].separator)
3210 s += m_maskData[i].maskChar;
3220 Strips blank parts of the input in a QQuickTextInputPrivate when an inputMask is set,
3221 separators are still included. Typically "127.0__.0__.1__" becomes "127.0.0.1".
3223 QString QQuickTextInputPrivate::stripString(const QString &str) const
3229 int end = qMin(m_maxLength, (int)str.length());
3230 for (int i = 0; i < end; ++i)
3231 if (m_maskData[i].separator)
3232 s += m_maskData[i].maskChar;
3234 if (str[i] != m_blank)
3242 searches forward/backward in m_maskData for either a separator or a m_blank
3244 int QQuickTextInputPrivate::findInMask(int pos, bool forward, bool findSeparator, QChar searchChar) const
3246 if (pos >= m_maxLength || pos < 0)
3249 int end = forward ? m_maxLength : -1;
3250 int step = forward ? 1 : -1;
3254 if (findSeparator) {
3255 if (m_maskData[i].separator && m_maskData[i].maskChar == searchChar)
3258 if (!m_maskData[i].separator) {
3259 if (searchChar.isNull())
3261 else if (isValidInput(searchChar, m_maskData[i].maskChar))
3270 void QQuickTextInputPrivate::internalUndo(int until)
3272 if (!isUndoAvailable())
3274 cancelPasswordEchoTimer();
3276 while (m_undoState && m_undoState > until) {
3277 Command& cmd = m_history[--m_undoState];
3280 m_text.remove(cmd.pos, 1);
3284 m_selstart = cmd.selStart;
3285 m_selend = cmd.selEnd;
3289 case RemoveSelection:
3290 m_text.insert(cmd.pos, cmd.uc);
3291 m_cursor = cmd.pos + 1;
3294 case DeleteSelection:
3295 m_text.insert(cmd.pos, cmd.uc);
3301 if (until < 0 && m_undoState) {
3302 Command& next = m_history[m_undoState-1];
3303 if (next.type != cmd.type && next.type < RemoveSelection
3304 && (cmd.type < RemoveSelection || next.type == Separator))
3309 emitCursorPositionChanged();
3312 void QQuickTextInputPrivate::internalRedo()
3314 if (!isRedoAvailable())
3317 while (m_undoState < (int)m_history.size()) {
3318 Command& cmd = m_history[m_undoState++];
3321 m_text.insert(cmd.pos, cmd.uc);
3322 m_cursor = cmd.pos + 1;
3325 m_selstart = cmd.selStart;
3326 m_selend = cmd.selEnd;
3331 case RemoveSelection:
3332 case DeleteSelection:
3333 m_text.remove(cmd.pos, 1);
3334 m_selstart = cmd.selStart;
3335 m_selend = cmd.selEnd;
3339 m_selstart = cmd.selStart;
3340 m_selend = cmd.selEnd;
3344 if (m_undoState < (int)m_history.size()) {
3345 Command& next = m_history[m_undoState];
3346 if (next.type != cmd.type && cmd.type < RemoveSelection && next.type != Separator
3347 && (next.type < RemoveSelection || cmd.type == Separator))
3352 emitCursorPositionChanged();
3358 If the current cursor position differs from the last emitted cursor
3359 position, emits cursorPositionChanged().
3361 void QQuickTextInputPrivate::emitCursorPositionChanged()
3363 Q_Q(QQuickTextInput);
3364 if (m_cursor != m_lastCursorPos) {
3365 m_lastCursorPos = m_cursor;
3367 q->updateCursorRectangle();
3368 emit q->cursorPositionChanged();
3369 // XXX todo - not in 4.8?
3371 resetCursorBlinkTimer();
3374 if (!hasSelectedText()) {
3375 if (lastSelectionStart != m_cursor) {
3376 lastSelectionStart = m_cursor;
3377 emit q->selectionStartChanged();
3379 if (lastSelectionEnd != m_cursor) {
3380 lastSelectionEnd = m_cursor;
3381 emit q->selectionEndChanged();
3385 #ifndef QT_NO_ACCESSIBILITY
3386 QAccessible::updateAccessibility(q, 0, QAccessible::TextCaretMoved);
3392 void QQuickTextInputPrivate::setCursorBlinkPeriod(int msec)
3394 Q_Q(QQuickTextInput);
3395 if (msec == m_blinkPeriod)
3398 q->killTimer(m_blinkTimer);
3401 m_blinkTimer = q->startTimer(msec / 2);
3405 if (m_blinkStatus == 1)
3406 emit q->updateRect(inputMask().isEmpty() ? q->cursorRectangle() : QRect());
3408 m_blinkPeriod = msec;
3411 void QQuickTextInputPrivate::resetCursorBlinkTimer()
3413 Q_Q(QQuickTextInput);
3414 if (m_blinkPeriod == 0 || m_blinkTimer == 0)
3416 q->killTimer(m_blinkTimer);
3417 m_blinkTimer = q->startTimer(m_blinkPeriod / 2);
3421 void QQuickTextInput::timerEvent(QTimerEvent *event)
3423 Q_D(QQuickTextInput);
3424 if (event->timerId() == d->m_blinkTimer) {
3425 d->m_blinkStatus = !d->m_blinkStatus;
3426 updateRect(inputMask().isEmpty() ? cursorRectangle() : QRect());
3427 } else if (event->timerId() == d->m_deleteAllTimer) {
3428 killTimer(d->m_deleteAllTimer);
3429 d->m_deleteAllTimer = 0;
3431 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
3432 } else if (event->timerId() == d->m_passwordEchoTimer.timerId()) {
3433 d->m_passwordEchoTimer.stop();
3434 d->updateDisplayText();
3439 void QQuickTextInputPrivate::processKeyEvent(QKeyEvent* event)
3441 Q_Q(QQuickTextInput);
3442 bool inlineCompletionAccepted = false;
3444 if (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return) {
3445 if (hasAcceptableInput(m_text) || fixup()) {
3448 if (inlineCompletionAccepted)
3455 if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit
3456 && !m_passwordEchoEditing
3458 && !event->text().isEmpty()
3459 && !(event->modifiers() & Qt::ControlModifier)) {
3460 // Clear the edit and reset to normal echo mode while editing; the
3461 // echo mode switches back when the edit loses focus
3462 // ### resets current content. dubious code; you can
3463 // navigate with keys up, down, back, and select(?), but if you press
3464 // "left" or "right" it clears?
3465 updatePasswordEchoEditing(true);
3469 bool unknown = false;
3470 bool visual = cursorMoveStyle() == Qt::VisualMoveStyle;
3474 #ifndef QT_NO_SHORTCUT
3475 else if (event == QKeySequence::Undo) {
3479 else if (event == QKeySequence::Redo) {
3483 else if (event == QKeySequence::SelectAll) {
3486 #ifndef QT_NO_CLIPBOARD
3487 else if (event == QKeySequence::Copy) {
3490 else if (event == QKeySequence::Paste) {
3492 QClipboard::Mode mode = QClipboard::Clipboard;
3496 else if (event == QKeySequence::Cut) {
3502 else if (event == QKeySequence::DeleteEndOfLine) {
3504 setSelection(m_cursor, end());
3509 #endif //QT_NO_CLIPBOARD
3510 else if (event == QKeySequence::MoveToStartOfLine || event == QKeySequence::MoveToStartOfBlock) {
3513 else if (event == QKeySequence::MoveToEndOfLine || event == QKeySequence::MoveToEndOfBlock) {
3516 else if (event == QKeySequence::SelectStartOfLine || event == QKeySequence::SelectStartOfBlock) {
3519 else if (event == QKeySequence::SelectEndOfLine || event == QKeySequence::SelectEndOfBlock) {
3522 else if (event == QKeySequence::MoveToNextChar) {
3523 if (hasSelectedText()) {
3524 moveCursor(selectionEnd(), false);
3526 cursorForward(0, visual ? 1 : (layoutDirection() == Qt::LeftToRight ? 1 : -1));
3529 else if (event == QKeySequence::SelectNextChar) {
3530 cursorForward(1, visual ? 1 : (layoutDirection() == Qt::LeftToRight ? 1 : -1));
3532 else if (event == QKeySequence::MoveToPreviousChar) {
3533 if (hasSelectedText()) {
3534 moveCursor(selectionStart(), false);
3536 cursorForward(0, visual ? -1 : (layoutDirection() == Qt::LeftToRight ? -1 : 1));
3539 else if (event == QKeySequence::SelectPreviousChar) {
3540 cursorForward(1, visual ? -1 : (layoutDirection() == Qt::LeftToRight ? -1 : 1));
3542 else if (event == QKeySequence::MoveToNextWord) {
3543 if (m_echoMode == QQuickTextInput::Normal)
3544 layoutDirection() == Qt::LeftToRight ? cursorWordForward(0) : cursorWordBackward(0);
3546 layoutDirection() == Qt::LeftToRight ? end(0) : home(0);
3548 else if (event == QKeySequence::MoveToPreviousWord) {
3549 if (m_echoMode == QQuickTextInput::Normal)
3550 layoutDirection() == Qt::LeftToRight ? cursorWordBackward(0) : cursorWordForward(0);
3551 else if (!m_readOnly) {
3552 layoutDirection() == Qt::LeftToRight ? home(0) : end(0);
3555 else if (event == QKeySequence::SelectNextWord) {
3556 if (m_echoMode == QQuickTextInput::Normal)
3557 layoutDirection() == Qt::LeftToRight ? cursorWordForward(1) : cursorWordBackward(1);
3559 layoutDirection() == Qt::LeftToRight ? end(1) : home(1);
3561 else if (event == QKeySequence::SelectPreviousWord) {
3562 if (m_echoMode == QQuickTextInput::Normal)
3563 layoutDirection() == Qt::LeftToRight ? cursorWordBackward(1) : cursorWordForward(1);
3565 layoutDirection() == Qt::LeftToRight ? home(1) : end(1);
3567 else if (event == QKeySequence::Delete) {
3571 else if (event == QKeySequence::DeleteEndOfWord) {
3573 cursorWordForward(true);
3577 else if (event == QKeySequence::DeleteStartOfWord) {
3579 cursorWordBackward(true);
3583 #endif // QT_NO_SHORTCUT
3585 bool handled = false;
3586 if (event->modifiers() & Qt::ControlModifier) {
3587 switch (event->key()) {
3588 case Qt::Key_Backspace:
3590 cursorWordBackward(true);
3598 } else { // ### check for *no* modifier
3599 switch (event->key()) {
3600 case Qt::Key_Backspace:
3612 if (event->key() == Qt::Key_Direction_L || event->key() == Qt::Key_Direction_R) {
3613 setLayoutDirection((event->key() == Qt::Key_Direction_L) ? Qt::LeftToRight : Qt::RightToLeft);
3617 if (unknown && !m_readOnly) {
3618 QString t = event->text();
3619 if (!t.isEmpty() && t.at(0).isPrint()) {