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);
1796 if (!d->canPasteValid) {
1797 if (const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData())
1798 const_cast<QQuickTextInputPrivate *>(d)->canPaste = !d->m_readOnly && mimeData->hasText();
1799 const_cast<QQuickTextInputPrivate *>(d)->canPasteValid = true;
1804 void QQuickTextInput::moveCursorSelection(int position)
1806 Q_D(QQuickTextInput);
1807 d->moveCursor(position, true);
1811 \qmlmethod void QtQuick2::TextInput::moveCursorSelection(int position, SelectionMode mode = TextInput.SelectCharacters)
1813 Moves the cursor to \a position and updates the selection according to the optional \a mode
1814 parameter. (To only move the cursor, set the \l cursorPosition property.)
1816 When this method is called it additionally sets either the
1817 selectionStart or the selectionEnd (whichever was at the previous cursor position)
1818 to the specified position. This allows you to easily extend and contract the selected
1821 The selection mode specifies whether the selection is updated on a per character or a per word
1822 basis. If not specified the selection mode will default to TextInput.SelectCharacters.
1825 \o TextEdit.SelectCharacters - Sets either the selectionStart or selectionEnd (whichever was at
1826 the previous cursor position) to the specified position.
1827 \o TextEdit.SelectWords - Sets the selectionStart and selectionEnd to include all
1828 words between the specified position and the previous cursor position. Words partially in the
1832 For example, take this sequence of calls:
1836 moveCursorSelection(9, TextInput.SelectCharacters)
1837 moveCursorSelection(7, TextInput.SelectCharacters)
1840 This moves the cursor to position 5, extend the selection end from 5 to 9
1841 and then retract the selection end from 9 to 7, leaving the text from position 5 to 7
1842 selected (the 6th and 7th characters).
1844 The same sequence with TextInput.SelectWords will extend the selection start to a word boundary
1845 before or on position 5 and extend the selection end to a word boundary on or past position 9.
1847 void QQuickTextInput::moveCursorSelection(int pos, SelectionMode mode)
1849 Q_D(QQuickTextInput);
1851 if (mode == SelectCharacters) {
1852 d->moveCursor(pos, true);
1853 } else if (pos != d->m_cursor){
1854 const int cursor = d->m_cursor;
1856 if (!d->hasSelectedText())
1857 anchor = d->m_cursor;
1858 else if (d->selectionStart() == d->m_cursor)
1859 anchor = d->selectionEnd();
1861 anchor = d->selectionStart();
1863 if (anchor < pos || (anchor == pos && cursor < pos)) {
1864 const QString text = this->text();
1865 QTextBoundaryFinder finder(QTextBoundaryFinder::Word, text);
1866 finder.setPosition(anchor);
1868 const QTextBoundaryFinder::BoundaryReasons reasons = finder.boundaryReasons();
1869 if (anchor < text.length() && (!(reasons & QTextBoundaryFinder::StartWord)
1870 || ((reasons & QTextBoundaryFinder::EndWord) && anchor > cursor))) {
1871 finder.toPreviousBoundary();
1873 anchor = finder.position() != -1 ? finder.position() : 0;
1875 finder.setPosition(pos);
1876 if (pos > 0 && !finder.boundaryReasons())
1877 finder.toNextBoundary();
1878 const int cursor = finder.position() != -1 ? finder.position() : text.length();
1880 d->setSelection(anchor, cursor - anchor);
1881 } else if (anchor > pos || (anchor == pos && cursor > pos)) {
1882 const QString text = this->text();
1883 QTextBoundaryFinder finder(QTextBoundaryFinder::Word, text);
1884 finder.setPosition(anchor);
1886 const QTextBoundaryFinder::BoundaryReasons reasons = finder.boundaryReasons();
1887 if (anchor > 0 && (!(reasons & QTextBoundaryFinder::EndWord)
1888 || ((reasons & QTextBoundaryFinder::StartWord) && anchor < cursor))) {
1889 finder.toNextBoundary();
1892 anchor = finder.position() != -1 ? finder.position() : text.length();
1894 finder.setPosition(pos);
1895 if (pos < text.length() && !finder.boundaryReasons())
1896 finder.toPreviousBoundary();
1897 const int cursor = finder.position() != -1 ? finder.position() : 0;
1899 d->setSelection(anchor, cursor - anchor);
1905 \qmlmethod void QtQuick2::TextInput::openSoftwareInputPanel()
1907 Opens software input panels like virtual keyboards for typing, useful for
1908 customizing when you want the input keyboard to be shown and hidden in
1911 By default the opening of input panels follows the platform style. Input panels are
1912 always closed if no editor has active focus.
1914 You can disable the automatic behavior by setting the property \c activeFocusOnPress to false
1915 and use functions openSoftwareInputPanel() and closeSoftwareInputPanel() to implement
1916 the behavior you want.
1918 Only relevant on platforms, which provide virtual keyboards.
1924 text: "Hello world!"
1925 activeFocusOnPress: false
1927 anchors.fill: parent
1929 if (!textInput.activeFocus) {
1930 textInput.forceActiveFocus()
1931 textInput.openSoftwareInputPanel();
1933 textInput.focus = false;
1936 onPressAndHold: textInput.closeSoftwareInputPanel();
1941 void QQuickTextInput::openSoftwareInputPanel()
1944 qGuiApp->inputPanel()->show();
1948 \qmlmethod void QtQuick2::TextInput::closeSoftwareInputPanel()
1950 Closes a software input panel like a virtual keyboard shown on the screen, useful
1951 for customizing when you want the input keyboard to be shown and hidden in
1954 By default the opening of input panels follows the platform style. Input panels are
1955 always closed if no editor has active focus.
1957 You can disable the automatic behavior by setting the property \c activeFocusOnPress to false
1958 and use functions openSoftwareInputPanel() and closeSoftwareInputPanel() to implement
1959 the behavior you want.
1961 Only relevant on platforms, which provide virtual keyboards.
1967 text: "Hello world!"
1968 activeFocusOnPress: false
1970 anchors.fill: parent
1972 if (!textInput.activeFocus) {
1973 textInput.forceActiveFocus();
1974 textInput.openSoftwareInputPanel();
1976 textInput.focus = false;
1979 onPressAndHold: textInput.closeSoftwareInputPanel();
1984 void QQuickTextInput::closeSoftwareInputPanel()
1987 qGuiApp->inputPanel()->hide();
1990 void QQuickTextInput::focusInEvent(QFocusEvent *event)
1992 Q_D(const QQuickTextInput);
1993 if (d->focusOnPress && !d->m_readOnly)
1994 openSoftwareInputPanel();
1995 QQuickImplicitSizeItem::focusInEvent(event);
1998 void QQuickTextInput::itemChange(ItemChange change, const ItemChangeData &value)
2000 Q_D(QQuickTextInput);
2001 if (change == ItemActiveFocusHasChanged) {
2002 bool hasFocus = value.boolValue;
2003 d->focused = hasFocus;
2004 setCursorVisible(hasFocus); // ### refactor: && d->canvas && d->canvas->hasFocus()
2005 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
2006 if (!hasFocus && (d->m_passwordEchoEditing || d->m_passwordEchoTimer.isActive())) {
2008 if (!hasFocus && d->m_passwordEchoEditing) {
2010 d->updatePasswordEchoEditing(false);//QQuickTextInputPrivate sets it on key events, but doesn't deal with focus events
2018 QQuickItem::itemChange(change, value);
2022 \qmlproperty bool QtQuick2::TextInput::inputMethodComposing
2025 This property holds whether the TextInput has partial text input from an
2028 While it is composing an input method may rely on mouse or key events from
2029 the TextInput to edit or commit the partial text. This property can be
2030 used to determine when to disable events handlers that may interfere with
2031 the correct operation of an input method.
2033 bool QQuickTextInput::isInputMethodComposing() const
2035 Q_D(const QQuickTextInput);
2036 return d->preeditAreaText().length() > 0;
2039 void QQuickTextInputPrivate::init()
2041 Q_Q(QQuickTextInput);
2042 q->setSmooth(smooth);
2043 q->setAcceptedMouseButtons(Qt::LeftButton);
2044 q->setFlag(QQuickItem::ItemAcceptsInputMethod);
2045 q->setFlag(QQuickItem::ItemHasContents);
2046 #ifndef QT_NO_CLIPBOARD
2047 q->connect(q, SIGNAL(readOnlyChanged(bool)),
2048 q, SLOT(q_canPasteChanged()));
2049 q->connect(QGuiApplication::clipboard(), SIGNAL(dataChanged()),
2050 q, SLOT(q_canPasteChanged()));
2051 #endif // QT_NO_CLIPBOARD
2052 m_textLayout.beginLayout();
2053 m_textLayout.createLine();
2054 m_textLayout.endLayout();
2056 imHints &= ~Qt::ImhMultiLine;
2057 oldValidity = hasAcceptableInput(m_text);
2058 lastSelectionStart = 0;
2059 lastSelectionEnd = 0;
2060 selectedTextColor = m_palette.color(QPalette::HighlightedText);
2061 selectionColor = m_palette.color(QPalette::Highlight);
2062 determineHorizontalAlignment();
2064 if (!qmlDisableDistanceField()) {
2065 QTextOption option = m_textLayout.textOption();
2066 option.setUseDesignMetrics(true);
2067 m_textLayout.setTextOption(option);
2071 void QQuickTextInput::updateCursorRectangle()
2073 Q_D(QQuickTextInput);
2074 if (!isComponentComplete())
2077 d->updateHorizontalScroll();
2078 d->updateVerticalScroll();
2081 emit cursorRectangleChanged();
2082 if (d->cursorItem) {
2083 QRectF r = cursorRectangle();
2084 d->cursorItem->setPos(r.topLeft());
2085 d->cursorItem->setHeight(r.height());
2089 void QQuickTextInput::selectionChanged()
2091 Q_D(QQuickTextInput);
2092 updateRect();//TODO: Only update rect in selection
2093 emit selectedTextChanged();
2095 if (d->lastSelectionStart != d->selectionStart()) {
2096 d->lastSelectionStart = d->selectionStart();
2097 if (d->lastSelectionStart == -1)
2098 d->lastSelectionStart = d->m_cursor;
2099 emit selectionStartChanged();
2101 if (d->lastSelectionEnd != d->selectionEnd()) {
2102 d->lastSelectionEnd = d->selectionEnd();
2103 if (d->lastSelectionEnd == -1)
2104 d->lastSelectionEnd = d->m_cursor;
2105 emit selectionEndChanged();
2109 void QQuickTextInputPrivate::showCursor()
2111 if (textNode != 0 && textNode->cursorNode() != 0)
2112 textNode->cursorNode()->setColor(color);
2115 void QQuickTextInputPrivate::hideCursor()
2117 if (textNode != 0 && textNode->cursorNode() != 0)
2118 textNode->cursorNode()->setColor(QColor(0, 0, 0, 0));
2121 void QQuickTextInput::updateRect(const QRect &r)
2123 Q_D(QQuickTextInput);
2124 if (!isComponentComplete())
2128 d->textLayoutDirty = true;
2134 QRectF QQuickTextInput::boundingRect() const
2136 Q_D(const QQuickTextInput);
2138 QRectF r = d->boundingRect;
2139 int cursorWidth = d->cursorItem ? d->cursorItem->width() : d->m_cursorWidth;
2141 // Could include font max left/right bearings to either side of rectangle.
2143 r.setRight(r.right() + cursorWidth);
2144 r.translate(-d->hscroll, -d->vscroll);
2148 void QQuickTextInput::q_canPasteChanged()
2150 Q_D(QQuickTextInput);
2151 bool old = d->canPaste;
2152 #ifndef QT_NO_CLIPBOARD
2153 if (const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData())
2154 d->canPaste = !d->m_readOnly && mimeData->hasText();
2156 d->canPaste = false;
2159 bool changed = d->canPaste != old || !d->canPasteValid;
2160 d->canPasteValid = true;
2162 emit canPasteChanged();
2166 // ### these should come from QStyleHints
2167 const int textCursorWidth = 1;
2168 const bool fullWidthSelection = true;
2173 Updates the display text based of the current edit text
2174 If the text has changed will emit displayTextChanged()
2176 void QQuickTextInputPrivate::updateDisplayText(bool forceUpdate)
2178 QString orig = m_textLayout.text();
2180 if (m_echoMode == QQuickTextInput::NoEcho)
2181 str = QString::fromLatin1("");
2185 if (m_echoMode == QQuickTextInput::Password) {
2186 str.fill(m_passwordCharacter);
2187 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
2188 if (m_passwordEchoTimer.isActive() && m_cursor > 0 && m_cursor <= m_text.length()) {
2189 int cursor = m_cursor - 1;
2190 QChar uc = m_text.at(cursor);
2192 if (cursor > 0 && uc.unicode() >= 0xdc00 && uc.unicode() < 0xe000) {
2193 // second half of a surrogate, check if we have the first half as well,
2194 // if yes restore both at once
2195 uc = m_text.at(cursor - 1);
2196 if (uc.unicode() >= 0xd800 && uc.unicode() < 0xdc00)
2197 str[cursor - 1] = uc;
2201 } else if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit && !m_passwordEchoEditing) {
2202 str.fill(m_passwordCharacter);
2205 // replace certain non-printable characters with spaces (to avoid
2206 // drawing boxes when using fonts that don't have glyphs for such
2208 QChar* uc = str.data();
2209 for (int i = 0; i < (int)str.length(); ++i) {
2210 if ((uc[i] < 0x20 && uc[i] != 0x09)
2211 || uc[i] == QChar::LineSeparator
2212 || uc[i] == QChar::ParagraphSeparator
2213 || uc[i] == QChar::ObjectReplacementCharacter)
2214 uc[i] = QChar(0x0020);
2217 if (str != orig || forceUpdate) {
2218 m_textLayout.setText(str);
2219 updateLayout(); // polish?
2220 emit q_func()->displayTextChanged();
2224 void QQuickTextInputPrivate::updateLayout()
2226 Q_Q(QQuickTextInput);
2228 if (!q->isComponentComplete())
2231 QTextOption option = m_textLayout.textOption();
2232 option.setTextDirection(m_layoutDirection);
2233 option.setFlags(QTextOption::IncludeTrailingSpaces);
2234 option.setWrapMode(QTextOption::WrapMode(wrapMode));
2235 option.setAlignment(Qt::Alignment(q->effectiveHAlign()));
2236 m_textLayout.setTextOption(option);
2237 m_textLayout.setFont(font);
2239 boundingRect = QRectF();
2240 m_textLayout.beginLayout();
2241 QTextLine line = m_textLayout.createLine();
2242 qreal lineWidth = q->widthValid() ? q->width() : INT_MAX;
2244 QTextLine firstLine = line;
2246 line.setLineWidth(lineWidth);
2247 line.setPosition(QPointF(line.position().x(), height));
2248 boundingRect = boundingRect.united(line.naturalTextRect());
2250 height += line.height();
2251 line = m_textLayout.createLine();
2252 } while (line.isValid());
2253 m_textLayout.endLayout();
2255 option.setWrapMode(QTextOption::NoWrap);
2256 m_textLayout.setTextOption(option);
2258 m_ascent = qRound(firstLine.ascent());
2259 textLayoutDirty = true;
2262 q->setImplicitSize(qCeil(boundingRect.width()), qCeil(boundingRect.height()));
2266 #ifndef QT_NO_CLIPBOARD
2270 Copies the currently selected text into the clipboard using the given
2273 \note If the echo mode is set to a mode other than Normal then copy
2274 will not work. This is to prevent using copy as a method of bypassing
2275 password features of the line control.
2277 void QQuickTextInputPrivate::copy(QClipboard::Mode mode) const
2279 QString t = selectedText();
2280 if (!t.isEmpty() && m_echoMode == QQuickTextInput::Normal) {
2281 QGuiApplication::clipboard()->setText(t, mode);
2288 Inserts the text stored in the application clipboard into the line
2293 void QQuickTextInputPrivate::paste(QClipboard::Mode clipboardMode)
2295 QString clip = QGuiApplication::clipboard()->text(clipboardMode);
2296 if (!clip.isEmpty() || hasSelectedText()) {
2297 separate(); //make it a separate undo/redo command
2303 #endif // !QT_NO_CLIPBOARD
2308 Exits preedit mode and commits parts marked as tentative commit
2310 void QQuickTextInputPrivate::commitPreedit()
2315 qApp->inputPanel()->reset();
2317 if (!m_tentativeCommit.isEmpty()) {
2318 internalInsert(m_tentativeCommit);
2319 m_tentativeCommit.clear();
2320 finishChange(-1, true/*not used, not documented*/, false);
2323 m_preeditCursor = 0;
2324 m_textLayout.setPreeditArea(-1, QString());
2325 m_textLayout.clearAdditionalFormats();
2332 Handles the behavior for the backspace key or function.
2333 Removes the current selection if there is a selection, otherwise
2334 removes the character prior to the cursor position.
2338 void QQuickTextInputPrivate::backspace()
2340 int priorState = m_undoState;
2341 if (hasSelectedText()) {
2342 removeSelectedText();
2343 } else if (m_cursor) {
2346 m_cursor = prevMaskBlank(m_cursor);
2347 QChar uc = m_text.at(m_cursor);
2348 if (m_cursor > 0 && uc.unicode() >= 0xdc00 && uc.unicode() < 0xe000) {
2349 // second half of a surrogate, check if we have the first half as well,
2350 // if yes delete both at once
2351 uc = m_text.at(m_cursor - 1);
2352 if (uc.unicode() >= 0xd800 && uc.unicode() < 0xdc00) {
2353 internalDelete(true);
2357 internalDelete(true);
2359 finishChange(priorState);
2365 Handles the behavior for the delete key or function.
2366 Removes the current selection if there is a selection, otherwise
2367 removes the character after the cursor position.
2371 void QQuickTextInputPrivate::del()
2373 int priorState = m_undoState;
2374 if (hasSelectedText()) {
2375 removeSelectedText();
2377 int n = m_textLayout.nextCursorPosition(m_cursor) - m_cursor;
2381 finishChange(priorState);
2387 Inserts the given \a newText at the current cursor position.
2388 If there is any selected text it is removed prior to insertion of
2391 void QQuickTextInputPrivate::insert(const QString &newText)
2393 int priorState = m_undoState;
2394 removeSelectedText();
2395 internalInsert(newText);
2396 finishChange(priorState);
2402 Clears the line control text.
2404 void QQuickTextInputPrivate::clear()
2406 int priorState = m_undoState;
2408 m_selend = m_text.length();
2409 removeSelectedText();
2411 finishChange(priorState, /*update*/false, /*edited*/false);
2417 Sets \a length characters from the given \a start position as selected.
2418 The given \a start position must be within the current text for
2419 the line control. If \a length characters cannot be selected, then
2420 the selection will extend to the end of the current text.
2422 void QQuickTextInputPrivate::setSelection(int start, int length)
2424 Q_Q(QQuickTextInput);
2427 if (start < 0 || start > (int)m_text.length()){
2428 qWarning("QQuickTextInputPrivate::setSelection: Invalid start position");
2433 if (start == m_selstart && start + length == m_selend && m_cursor == m_selend)
2436 m_selend = qMin(start + length, (int)m_text.length());
2437 m_cursor = m_selend;
2438 } else if (length < 0){
2439 if (start == m_selend && start + length == m_selstart && m_cursor == m_selstart)
2441 m_selstart = qMax(start + length, 0);
2443 m_cursor = m_selstart;
2444 } else if (m_selstart != m_selend) {
2450 emitCursorPositionChanged();
2453 emit q->selectionChanged();
2454 emitCursorPositionChanged();
2460 Initializes the line control with a starting text value of \a txt.
2462 void QQuickTextInputPrivate::init(const QString &txt)
2466 updateDisplayText();
2467 m_cursor = m_text.length();
2473 Sets the password echo editing to \a editing. If password echo editing
2474 is true, then the text of the password is displayed even if the echo
2475 mode is set to QLineEdit::PasswordEchoOnEdit. Password echoing editing
2476 does not affect other echo modes.
2478 void QQuickTextInputPrivate::updatePasswordEchoEditing(bool editing)
2480 cancelPasswordEchoTimer();
2481 m_passwordEchoEditing = editing;
2482 updateDisplayText();
2488 Fixes the current text so that it is valid given any set validators.
2490 Returns true if the text was changed. Otherwise returns false.
2492 bool QQuickTextInputPrivate::fixup() // this function assumes that validate currently returns != Acceptable
2494 #ifndef QT_NO_VALIDATOR
2496 QString textCopy = m_text;
2497 int cursorCopy = m_cursor;
2498 m_validator->fixup(textCopy);
2499 if (m_validator->validate(textCopy, cursorCopy) == QValidator::Acceptable) {
2500 if (textCopy != m_text || cursorCopy != m_cursor)
2501 internalSetText(textCopy, cursorCopy);
2512 Moves the cursor to the given position \a pos. If \a mark is true will
2513 adjust the currently selected text.
2515 void QQuickTextInputPrivate::moveCursor(int pos, bool mark)
2517 Q_Q(QQuickTextInput);
2520 if (pos != m_cursor) {
2523 pos = pos > m_cursor ? nextMaskBlank(pos) : prevMaskBlank(pos);
2527 if (m_selend > m_selstart && m_cursor == m_selstart)
2529 else if (m_selend > m_selstart && m_cursor == m_selend)
2530 anchor = m_selstart;
2533 m_selstart = qMin(anchor, pos);
2534 m_selend = qMax(anchor, pos);
2539 if (mark || m_selDirty) {
2541 emit q->selectionChanged();
2543 emitCursorPositionChanged();
2549 Applies the given input method event \a event to the text of the line
2552 void QQuickTextInputPrivate::processInputMethodEvent(QInputMethodEvent *event)
2554 Q_Q(QQuickTextInput);
2556 int priorState = -1;
2557 bool isGettingInput = !event->commitString().isEmpty()
2558 || event->preeditString() != preeditAreaText()
2559 || event->replacementLength() > 0;
2560 bool cursorPositionChanged = false;
2561 bool selectionChange = false;
2562 m_preeditDirty = event->preeditString() != preeditAreaText();
2564 if (isGettingInput) {
2565 // If any text is being input, remove selected text.
2566 priorState = m_undoState;
2567 if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit && !m_passwordEchoEditing) {
2568 updatePasswordEchoEditing(true);
2570 m_selend = m_text.length();
2572 removeSelectedText();
2575 int c = m_cursor; // cursor position after insertion of commit string
2576 if (event->replacementStart() <= 0)
2577 c += event->commitString().length() - qMin(-event->replacementStart(), event->replacementLength());
2579 m_cursor += event->replacementStart();
2583 // insert commit string
2584 if (event->replacementLength()) {
2585 m_selstart = m_cursor;
2586 m_selend = m_selstart + event->replacementLength();
2587 m_selend = qMin(m_selend, m_text.length());
2588 removeSelectedText();
2590 if (!event->commitString().isEmpty()) {
2591 internalInsert(event->commitString());
2592 cursorPositionChanged = true;
2595 m_cursor = qBound(0, c, m_text.length());
2597 for (int i = 0; i < event->attributes().size(); ++i) {
2598 const QInputMethodEvent::Attribute &a = event->attributes().at(i);
2599 if (a.type == QInputMethodEvent::Selection) {
2600 m_cursor = qBound(0, a.start + a.length, m_text.length());
2602 m_selstart = qMax(0, qMin(a.start, m_text.length()));
2603 m_selend = m_cursor;
2604 if (m_selend < m_selstart) {
2605 qSwap(m_selstart, m_selend);
2607 selectionChange = true;
2609 m_selstart = m_selend = 0;
2611 cursorPositionChanged = true;
2615 m_textLayout.setPreeditArea(m_cursor, event->preeditString());
2617 const int oldPreeditCursor = m_preeditCursor;
2618 m_preeditCursor = event->preeditString().length();
2619 m_hideCursor = false;
2620 QList<QTextLayout::FormatRange> formats;
2621 for (int i = 0; i < event->attributes().size(); ++i) {
2622 const QInputMethodEvent::Attribute &a = event->attributes().at(i);
2623 if (a.type == QInputMethodEvent::Cursor) {
2624 m_preeditCursor = a.start;
2625 m_hideCursor = !a.length;
2626 } else if (a.type == QInputMethodEvent::TextFormat) {
2627 QTextCharFormat f = qvariant_cast<QTextFormat>(a.value).toCharFormat();
2629 QTextLayout::FormatRange o;
2630 o.start = a.start + m_cursor;
2631 o.length = a.length;
2637 m_textLayout.setAdditionalFormats(formats);
2639 updateDisplayText(/*force*/ true);
2640 if (cursorPositionChanged)
2641 emitCursorPositionChanged();
2642 else if (m_preeditCursor != oldPreeditCursor)
2643 q->updateCursorRectangle();
2645 bool tentativeCommitChanged = m_tentativeCommit != event->tentativeCommitString();
2647 if (tentativeCommitChanged) {
2649 m_tentativeCommit = event->tentativeCommitString();
2652 if (isGettingInput || tentativeCommitChanged)
2653 finishChange(priorState);
2655 if (selectionChange)
2656 emit q->selectionChanged();
2662 Sets the selection to cover the word at the given cursor position.
2663 The word boundaries are defined by the behavior of QTextLayout::SkipWords
2666 void QQuickTextInputPrivate::selectWordAtPos(int cursor)
2668 int next = cursor + 1;
2671 int c = m_textLayout.previousCursorPosition(next, QTextLayout::SkipWords);
2672 moveCursor(c, false);
2673 // ## text layout should support end of words.
2674 int end = m_textLayout.nextCursorPosition(c, QTextLayout::SkipWords);
2675 while (end > cursor && m_text[end-1].isSpace())
2677 moveCursor(end, true);
2683 Completes a change to the line control text. If the change is not valid
2684 will undo the line control state back to the given \a validateFromState.
2686 If \a edited is true and the change is valid, will emit textEdited() in
2687 addition to textChanged(). Otherwise only emits textChanged() on a valid
2690 The \a update value is currently unused.
2692 bool QQuickTextInputPrivate::finishChange(int validateFromState, bool update, bool /*edited*/)
2694 Q_Q(QQuickTextInput);
2700 bool wasValidInput = m_validInput;
2701 m_validInput = true;
2702 #ifndef QT_NO_VALIDATOR
2704 QString textCopy = m_text;
2705 int cursorCopy = m_cursor;
2706 m_validInput = (m_validator->validate(textCopy, cursorCopy) != QValidator::Invalid);
2708 if (m_text != textCopy) {
2709 internalSetText(textCopy, cursorCopy);
2712 m_cursor = cursorCopy;
2714 if (!m_tentativeCommit.isEmpty()) {
2715 textCopy.insert(m_cursor, m_tentativeCommit);
2716 bool validInput = m_validator->validate(textCopy, cursorCopy) != QValidator::Invalid;
2718 m_tentativeCommit.clear();
2721 m_tentativeCommit.clear();
2725 if (validateFromState >= 0 && wasValidInput && !m_validInput) {
2726 if (m_transactions.count())
2728 internalUndo(validateFromState);
2729 m_history.resize(m_undoState);
2730 if (m_modifiedState > m_undoState)
2731 m_modifiedState = -1;
2732 m_validInput = true;
2733 m_textDirty = false;
2735 updateDisplayText();
2738 m_textDirty = false;
2739 m_preeditDirty = false;
2740 determineHorizontalAlignment();
2741 emit q->textChanged();
2744 if (m_validInput != wasValidInput)
2745 emit q->acceptableInputChanged();
2747 if (m_preeditDirty) {
2748 m_preeditDirty = false;
2749 determineHorizontalAlignment();
2753 emit q->selectionChanged();
2755 emitCursorPositionChanged();
2762 An internal function for setting the text of the line control.
2764 void QQuickTextInputPrivate::internalSetText(const QString &txt, int pos, bool edited)
2766 Q_Q(QQuickTextInput);
2768 QString oldText = m_text;
2770 m_text = maskString(0, txt, true);
2771 m_text += clearString(m_text.length(), m_maxLength - m_text.length());
2773 m_text = txt.isEmpty() ? txt : txt.left(m_maxLength);
2776 m_modifiedState = m_undoState = 0;
2777 m_cursor = (pos < 0 || pos > m_text.length()) ? m_text.length() : pos;
2778 m_textDirty = (oldText != m_text);
2780 bool changed = finishChange(-1, true, edited);
2781 #ifdef QT_NO_ACCESSIBILITY
2785 QAccessible::updateAccessibility(q, 0, QAccessible::TextUpdated);
2793 Adds the given \a command to the undo history
2794 of the line control. Does not apply the command.
2796 void QQuickTextInputPrivate::addCommand(const Command &cmd)
2798 if (m_separator && m_undoState && m_history[m_undoState - 1].type != Separator) {
2799 m_history.resize(m_undoState + 2);
2800 m_history[m_undoState++] = Command(Separator, m_cursor, 0, m_selstart, m_selend);
2802 m_history.resize(m_undoState + 1);
2804 m_separator = false;
2805 m_history[m_undoState++] = cmd;
2811 Inserts the given string \a s into the line
2814 Also adds the appropriate commands into the undo history.
2815 This function does not call finishChange(), and may leave the text
2816 in an invalid state.
2818 void QQuickTextInputPrivate::internalInsert(const QString &s)
2820 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
2821 Q_Q(QQuickTextInput);
2822 if (m_echoMode == QQuickTextInput::Password)
2823 m_passwordEchoTimer.start(qt_passwordEchoDelay, q);
2825 if (hasSelectedText())
2826 addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
2828 QString ms = maskString(m_cursor, s);
2829 for (int i = 0; i < (int) ms.length(); ++i) {
2830 addCommand (Command(DeleteSelection, m_cursor + i, m_text.at(m_cursor + i), -1, -1));
2831 addCommand(Command(Insert, m_cursor + i, ms.at(i), -1, -1));
2833 m_text.replace(m_cursor, ms.length(), ms);
2834 m_cursor += ms.length();
2835 m_cursor = nextMaskBlank(m_cursor);
2838 int remaining = m_maxLength - m_text.length();
2839 if (remaining != 0) {
2840 m_text.insert(m_cursor, s.left(remaining));
2841 for (int i = 0; i < (int) s.left(remaining).length(); ++i)
2842 addCommand(Command(Insert, m_cursor++, s.at(i), -1, -1));
2851 deletes a single character from the current text. If \a wasBackspace,
2852 the character prior to the cursor is removed. Otherwise the character
2853 after the cursor is removed.
2855 Also adds the appropriate commands into the undo history.
2856 This function does not call finishChange(), and may leave the text
2857 in an invalid state.
2859 void QQuickTextInputPrivate::internalDelete(bool wasBackspace)
2861 if (m_cursor < (int) m_text.length()) {
2862 cancelPasswordEchoTimer();
2863 if (hasSelectedText())
2864 addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
2865 addCommand(Command((CommandType)((m_maskData ? 2 : 0) + (wasBackspace ? Remove : Delete)),
2866 m_cursor, m_text.at(m_cursor), -1, -1));
2868 m_text.replace(m_cursor, 1, clearString(m_cursor, 1));
2869 addCommand(Command(Insert, m_cursor, m_text.at(m_cursor), -1, -1));
2871 m_text.remove(m_cursor, 1);
2880 removes the currently selected text from the line control.
2882 Also adds the appropriate commands into the undo history.
2883 This function does not call finishChange(), and may leave the text
2884 in an invalid state.
2886 void QQuickTextInputPrivate::removeSelectedText()
2888 if (m_selstart < m_selend && m_selend <= (int) m_text.length()) {
2889 cancelPasswordEchoTimer();
2892 addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
2893 if (m_selstart <= m_cursor && m_cursor < m_selend) {
2894 // cursor is within the selection. Split up the commands
2895 // to be able to restore the correct cursor position
2896 for (i = m_cursor; i >= m_selstart; --i)
2897 addCommand (Command(DeleteSelection, i, m_text.at(i), -1, 1));
2898 for (i = m_selend - 1; i > m_cursor; --i)
2899 addCommand (Command(DeleteSelection, i - m_cursor + m_selstart - 1, m_text.at(i), -1, -1));
2901 for (i = m_selend-1; i >= m_selstart; --i)
2902 addCommand (Command(RemoveSelection, i, m_text.at(i), -1, -1));
2905 m_text.replace(m_selstart, m_selend - m_selstart, clearString(m_selstart, m_selend - m_selstart));
2906 for (int i = 0; i < m_selend - m_selstart; ++i)
2907 addCommand(Command(Insert, m_selstart + i, m_text.at(m_selstart + i), -1, -1));
2909 m_text.remove(m_selstart, m_selend - m_selstart);
2911 if (m_cursor > m_selstart)
2912 m_cursor -= qMin(m_cursor, m_selend) - m_selstart;
2921 Parses the input mask specified by \a maskFields to generate
2922 the mask data used to handle input masks.
2924 void QQuickTextInputPrivate::parseInputMask(const QString &maskFields)
2926 int delimiter = maskFields.indexOf(QLatin1Char(';'));
2927 if (maskFields.isEmpty() || delimiter == 0) {
2929 delete [] m_maskData;
2931 m_maxLength = 32767;
2932 internalSetText(QString());
2937 if (delimiter == -1) {
2938 m_blank = QLatin1Char(' ');
2939 m_inputMask = maskFields;
2941 m_inputMask = maskFields.left(delimiter);
2942 m_blank = (delimiter + 1 < maskFields.length()) ? maskFields[delimiter + 1] : QLatin1Char(' ');
2945 // calculate m_maxLength / m_maskData length
2948 for (int i=0; i<m_inputMask.length(); i++) {
2949 c = m_inputMask.at(i);
2950 if (i > 0 && m_inputMask.at(i-1) == QLatin1Char('\\')) {
2954 if (c != QLatin1Char('\\') && c != QLatin1Char('!') &&
2955 c != QLatin1Char('<') && c != QLatin1Char('>') &&
2956 c != QLatin1Char('{') && c != QLatin1Char('}') &&
2957 c != QLatin1Char('[') && c != QLatin1Char(']'))
2961 delete [] m_maskData;
2962 m_maskData = new MaskInputData[m_maxLength];
2964 MaskInputData::Casemode m = MaskInputData::NoCaseMode;
2967 bool escape = false;
2969 for (int i = 0; i < m_inputMask.length(); i++) {
2970 c = m_inputMask.at(i);
2973 m_maskData[index].maskChar = c;
2974 m_maskData[index].separator = s;
2975 m_maskData[index].caseMode = m;
2978 } else if (c == QLatin1Char('<')) {
2979 m = MaskInputData::Lower;
2980 } else if (c == QLatin1Char('>')) {
2981 m = MaskInputData::Upper;
2982 } else if (c == QLatin1Char('!')) {
2983 m = MaskInputData::NoCaseMode;
2984 } else if (c != QLatin1Char('{') && c != QLatin1Char('}') && c != QLatin1Char('[') && c != QLatin1Char(']')) {
2985 switch (c.unicode()) {
3011 m_maskData[index].maskChar = c;
3012 m_maskData[index].separator = s;
3013 m_maskData[index].caseMode = m;
3018 internalSetText(m_text);
3025 checks if the key is valid compared to the inputMask
3027 bool QQuickTextInputPrivate::isValidInput(QChar key, QChar mask) const
3029 switch (mask.unicode()) {
3035 if (key.isLetter() || key == m_blank)
3039 if (key.isLetterOrNumber())
3043 if (key.isLetterOrNumber() || key == m_blank)
3051 if (key.isPrint() || key == m_blank)
3059 if (key.isNumber() || key == m_blank)
3063 if (key.isNumber() && key.digitValue() > 0)
3067 if ((key.isNumber() && key.digitValue() > 0) || key == m_blank)
3071 if (key.isNumber() || key == QLatin1Char('+') || key == QLatin1Char('-') || key == m_blank)
3075 if (key == QLatin1Char('0') || key == QLatin1Char('1'))
3079 if (key == QLatin1Char('0') || key == QLatin1Char('1') || key == m_blank)
3083 if (key.isNumber() || (key >= QLatin1Char('a') && key <= QLatin1Char('f')) || (key >= QLatin1Char('A') && key <= QLatin1Char('F')))
3087 if (key.isNumber() || (key >= QLatin1Char('a') && key <= QLatin1Char('f')) || (key >= QLatin1Char('A') && key <= QLatin1Char('F')) || key == m_blank)
3099 Returns true if the given text \a str is valid for any
3100 validator or input mask set for the line control.
3102 Otherwise returns false
3104 bool QQuickTextInputPrivate::hasAcceptableInput(const QString &str) const
3106 #ifndef QT_NO_VALIDATOR
3107 QString textCopy = str;
3108 int cursorCopy = m_cursor;
3109 if (m_validator && m_validator->validate(textCopy, cursorCopy)
3110 != QValidator::Acceptable)
3117 if (str.length() != m_maxLength)
3120 for (int i=0; i < m_maxLength; ++i) {
3121 if (m_maskData[i].separator) {
3122 if (str.at(i) != m_maskData[i].maskChar)
3125 if (!isValidInput(str.at(i), m_maskData[i].maskChar))
3135 Applies the inputMask on \a str starting from position \a pos in the mask. \a clear
3136 specifies from where characters should be gotten when a separator is met in \a str - true means
3137 that blanks will be used, false that previous input is used.
3138 Calling this when no inputMask is set is undefined.
3140 QString QQuickTextInputPrivate::maskString(uint pos, const QString &str, bool clear) const
3142 if (pos >= (uint)m_maxLength)
3143 return QString::fromLatin1("");
3146 fill = clear ? clearString(0, m_maxLength) : m_text;
3149 QString s = QString::fromLatin1("");
3151 while (i < m_maxLength) {
3152 if (strIndex < str.length()) {
3153 if (m_maskData[i].separator) {
3154 s += m_maskData[i].maskChar;
3155 if (str[(int)strIndex] == m_maskData[i].maskChar)
3159 if (isValidInput(str[(int)strIndex], m_maskData[i].maskChar)) {
3160 switch (m_maskData[i].caseMode) {
3161 case MaskInputData::Upper:
3162 s += str[(int)strIndex].toUpper();
3164 case MaskInputData::Lower:
3165 s += str[(int)strIndex].toLower();
3168 s += str[(int)strIndex];
3172 // search for separator first
3173 int n = findInMask(i, true, true, str[(int)strIndex]);
3175 if (str.length() != 1 || i == 0 || (i > 0 && (!m_maskData[i-1].separator || m_maskData[i-1].maskChar != str[(int)strIndex]))) {
3176 s += fill.mid(i, n-i+1);
3177 i = n + 1; // update i to find + 1
3180 // search for valid m_blank if not
3181 n = findInMask(i, true, false, str[(int)strIndex]);
3183 s += fill.mid(i, n-i);
3184 switch (m_maskData[n].caseMode) {
3185 case MaskInputData::Upper:
3186 s += str[(int)strIndex].toUpper();
3188 case MaskInputData::Lower:
3189 s += str[(int)strIndex].toLower();
3192 s += str[(int)strIndex];
3194 i = n + 1; // updates i to find + 1
3212 Returns a "cleared" string with only separators and blank chars.
3213 Calling this when no inputMask is set is undefined.
3215 QString QQuickTextInputPrivate::clearString(uint pos, uint len) const
3217 if (pos >= (uint)m_maxLength)
3221 int end = qMin((uint)m_maxLength, pos + len);
3222 for (int i = pos; i < end; ++i)
3223 if (m_maskData[i].separator)
3224 s += m_maskData[i].maskChar;
3234 Strips blank parts of the input in a QQuickTextInputPrivate when an inputMask is set,
3235 separators are still included. Typically "127.0__.0__.1__" becomes "127.0.0.1".
3237 QString QQuickTextInputPrivate::stripString(const QString &str) const
3243 int end = qMin(m_maxLength, (int)str.length());
3244 for (int i = 0; i < end; ++i)
3245 if (m_maskData[i].separator)
3246 s += m_maskData[i].maskChar;
3248 if (str[i] != m_blank)
3256 searches forward/backward in m_maskData for either a separator or a m_blank
3258 int QQuickTextInputPrivate::findInMask(int pos, bool forward, bool findSeparator, QChar searchChar) const
3260 if (pos >= m_maxLength || pos < 0)
3263 int end = forward ? m_maxLength : -1;
3264 int step = forward ? 1 : -1;
3268 if (findSeparator) {
3269 if (m_maskData[i].separator && m_maskData[i].maskChar == searchChar)
3272 if (!m_maskData[i].separator) {
3273 if (searchChar.isNull())
3275 else if (isValidInput(searchChar, m_maskData[i].maskChar))
3284 void QQuickTextInputPrivate::internalUndo(int until)
3286 if (!isUndoAvailable())
3288 cancelPasswordEchoTimer();
3290 while (m_undoState && m_undoState > until) {
3291 Command& cmd = m_history[--m_undoState];
3294 m_text.remove(cmd.pos, 1);
3298 m_selstart = cmd.selStart;
3299 m_selend = cmd.selEnd;
3303 case RemoveSelection:
3304 m_text.insert(cmd.pos, cmd.uc);
3305 m_cursor = cmd.pos + 1;
3308 case DeleteSelection:
3309 m_text.insert(cmd.pos, cmd.uc);
3315 if (until < 0 && m_undoState) {
3316 Command& next = m_history[m_undoState-1];
3317 if (next.type != cmd.type && next.type < RemoveSelection
3318 && (cmd.type < RemoveSelection || next.type == Separator))
3323 emitCursorPositionChanged();
3326 void QQuickTextInputPrivate::internalRedo()
3328 if (!isRedoAvailable())
3331 while (m_undoState < (int)m_history.size()) {
3332 Command& cmd = m_history[m_undoState++];
3335 m_text.insert(cmd.pos, cmd.uc);
3336 m_cursor = cmd.pos + 1;
3339 m_selstart = cmd.selStart;
3340 m_selend = cmd.selEnd;
3345 case RemoveSelection:
3346 case DeleteSelection:
3347 m_text.remove(cmd.pos, 1);
3348 m_selstart = cmd.selStart;
3349 m_selend = cmd.selEnd;
3353 m_selstart = cmd.selStart;
3354 m_selend = cmd.selEnd;
3358 if (m_undoState < (int)m_history.size()) {
3359 Command& next = m_history[m_undoState];
3360 if (next.type != cmd.type && cmd.type < RemoveSelection && next.type != Separator
3361 && (next.type < RemoveSelection || cmd.type == Separator))
3366 emitCursorPositionChanged();
3372 If the current cursor position differs from the last emitted cursor
3373 position, emits cursorPositionChanged().
3375 void QQuickTextInputPrivate::emitCursorPositionChanged()
3377 Q_Q(QQuickTextInput);
3378 if (m_cursor != m_lastCursorPos) {
3379 m_lastCursorPos = m_cursor;
3381 q->updateCursorRectangle();
3382 emit q->cursorPositionChanged();
3383 // XXX todo - not in 4.8?
3385 resetCursorBlinkTimer();
3388 if (!hasSelectedText()) {
3389 if (lastSelectionStart != m_cursor) {
3390 lastSelectionStart = m_cursor;
3391 emit q->selectionStartChanged();
3393 if (lastSelectionEnd != m_cursor) {
3394 lastSelectionEnd = m_cursor;
3395 emit q->selectionEndChanged();
3399 #ifndef QT_NO_ACCESSIBILITY
3400 QAccessible::updateAccessibility(q, 0, QAccessible::TextCaretMoved);
3406 void QQuickTextInputPrivate::setCursorBlinkPeriod(int msec)
3408 Q_Q(QQuickTextInput);
3409 if (msec == m_blinkPeriod)
3412 q->killTimer(m_blinkTimer);
3415 m_blinkTimer = q->startTimer(msec / 2);
3419 if (m_blinkStatus == 1)
3420 emit q->updateRect(inputMask().isEmpty() ? q->cursorRectangle() : QRect());
3422 m_blinkPeriod = msec;
3425 void QQuickTextInputPrivate::resetCursorBlinkTimer()
3427 Q_Q(QQuickTextInput);
3428 if (m_blinkPeriod == 0 || m_blinkTimer == 0)
3430 q->killTimer(m_blinkTimer);
3431 m_blinkTimer = q->startTimer(m_blinkPeriod / 2);
3435 void QQuickTextInput::timerEvent(QTimerEvent *event)
3437 Q_D(QQuickTextInput);
3438 if (event->timerId() == d->m_blinkTimer) {
3439 d->m_blinkStatus = !d->m_blinkStatus;
3440 updateRect(inputMask().isEmpty() ? cursorRectangle() : QRect());
3441 } else if (event->timerId() == d->m_deleteAllTimer) {
3442 killTimer(d->m_deleteAllTimer);
3443 d->m_deleteAllTimer = 0;
3445 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
3446 } else if (event->timerId() == d->m_passwordEchoTimer.timerId()) {
3447 d->m_passwordEchoTimer.stop();
3448 d->updateDisplayText();
3453 void QQuickTextInputPrivate::processKeyEvent(QKeyEvent* event)
3455 Q_Q(QQuickTextInput);
3456 bool inlineCompletionAccepted = false;
3458 if (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return) {
3459 if (hasAcceptableInput(m_text) || fixup()) {
3462 if (inlineCompletionAccepted)
3469 if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit
3470 && !m_passwordEchoEditing
3472 && !event->text().isEmpty()
3473 && !(event->modifiers() & Qt::ControlModifier)) {
3474 // Clear the edit and reset to normal echo mode while editing; the
3475 // echo mode switches back when the edit loses focus
3476 // ### resets current content. dubious code; you can
3477 // navigate with keys up, down, back, and select(?), but if you press
3478 // "left" or "right" it clears?
3479 updatePasswordEchoEditing(true);
3483 bool unknown = false;
3484 bool visual = cursorMoveStyle() == Qt::VisualMoveStyle;
3488 #ifndef QT_NO_SHORTCUT
3489 else if (event == QKeySequence::Undo) {
3493 else if (event == QKeySequence::Redo) {
3497 else if (event == QKeySequence::SelectAll) {
3500 #ifndef QT_NO_CLIPBOARD
3501 else if (event == QKeySequence::Copy) {
3504 else if (event == QKeySequence::Paste) {
3506 QClipboard::Mode mode = QClipboard::Clipboard;
3510 else if (event == QKeySequence::Cut) {
3516 else if (event == QKeySequence::DeleteEndOfLine) {
3518 setSelection(m_cursor, end());
3523 #endif //QT_NO_CLIPBOARD
3524 else if (event == QKeySequence::MoveToStartOfLine || event == QKeySequence::MoveToStartOfBlock) {
3527 else if (event == QKeySequence::MoveToEndOfLine || event == QKeySequence::MoveToEndOfBlock) {
3530 else if (event == QKeySequence::SelectStartOfLine || event == QKeySequence::SelectStartOfBlock) {
3533 else if (event == QKeySequence::SelectEndOfLine || event == QKeySequence::SelectEndOfBlock) {
3536 else if (event == QKeySequence::MoveToNextChar) {
3537 if (hasSelectedText()) {
3538 moveCursor(selectionEnd(), false);
3540 cursorForward(0, visual ? 1 : (layoutDirection() == Qt::LeftToRight ? 1 : -1));
3543 else if (event == QKeySequence::SelectNextChar) {
3544 cursorForward(1, visual ? 1 : (layoutDirection() == Qt::LeftToRight ? 1 : -1));
3546 else if (event == QKeySequence::MoveToPreviousChar) {
3547 if (hasSelectedText()) {
3548 moveCursor(selectionStart(), false);
3550 cursorForward(0, visual ? -1 : (layoutDirection() == Qt::LeftToRight ? -1 : 1));
3553 else if (event == QKeySequence::SelectPreviousChar) {
3554 cursorForward(1, visual ? -1 : (layoutDirection() == Qt::LeftToRight ? -1 : 1));
3556 else if (event == QKeySequence::MoveToNextWord) {
3557 if (m_echoMode == QQuickTextInput::Normal)
3558 layoutDirection() == Qt::LeftToRight ? cursorWordForward(0) : cursorWordBackward(0);
3560 layoutDirection() == Qt::LeftToRight ? end(0) : home(0);
3562 else if (event == QKeySequence::MoveToPreviousWord) {
3563 if (m_echoMode == QQuickTextInput::Normal)
3564 layoutDirection() == Qt::LeftToRight ? cursorWordBackward(0) : cursorWordForward(0);
3565 else if (!m_readOnly) {
3566 layoutDirection() == Qt::LeftToRight ? home(0) : end(0);
3569 else if (event == QKeySequence::SelectNextWord) {
3570 if (m_echoMode == QQuickTextInput::Normal)
3571 layoutDirection() == Qt::LeftToRight ? cursorWordForward(1) : cursorWordBackward(1);
3573 layoutDirection() == Qt::LeftToRight ? end(1) : home(1);
3575 else if (event == QKeySequence::SelectPreviousWord) {
3576 if (m_echoMode == QQuickTextInput::Normal)
3577 layoutDirection() == Qt::LeftToRight ? cursorWordBackward(1) : cursorWordForward(1);
3579 layoutDirection() == Qt::LeftToRight ? home(1) : end(1);
3581 else if (event == QKeySequence::Delete) {
3585 else if (event == QKeySequence::DeleteEndOfWord) {
3587 cursorWordForward(true);
3591 else if (event == QKeySequence::DeleteStartOfWord) {
3593 cursorWordBackward(true);
3597 #endif // QT_NO_SHORTCUT
3599 bool handled = false;
3600 if (event->modifiers() & Qt::ControlModifier) {
3601 switch (event->key()) {
3602 case Qt::Key_Backspace:
3604 cursorWordBackward(true);
3612 } else { // ### check for *no* modifier
3613 switch (event->key()) {
3614 case Qt::Key_Backspace:
3626 if (event->key() == Qt::Key_Direction_L || event->key() == Qt::Key_Direction_R) {
3627 setLayoutDirection((event->key() == Qt::Key_Direction_L) ? Qt::LeftToRight : Qt::RightToLeft);
3631 if (unknown && !m_readOnly) {
3632 QString t = event->text();
3633 if (!t.isEmpty() && t.at(0).isPrint()) {