1 /****************************************************************************
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the QtDeclarative module of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #include "qquicktextinput_p.h"
43 #include "qquicktextinput_p_p.h"
44 #include "qquickcanvas.h"
46 #include <private/qdeclarativeglobal_p.h>
48 #include <QtDeclarative/qdeclarativeinfo.h>
49 #include <QtGui/qevent.h>
50 #include <QTextBoundaryFinder>
51 #include "qquicktextnode_p.h"
52 #include <QtQuick/qsgsimplerectnode.h>
54 #include <QtGui/qstylehints.h>
55 #include <QtGui/qinputpanel.h>
57 #ifndef QT_NO_ACCESSIBILITY
58 #include "qaccessible.h"
63 DEFINE_BOOL_CONFIG_OPTION(qmlDisableDistanceField, QML_DISABLE_DISTANCEFIELD)
65 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
66 static const int qt_passwordEchoDelay = QT_GUI_PASSWORD_ECHO_DELAY;
70 \qmlclass TextInput QQuickTextInput
71 \inqmlmodule QtQuick 2
72 \ingroup qml-basic-visual-elements
73 \brief The TextInput item displays an editable line of text.
76 The TextInput element displays a single line of editable plain text.
78 TextInput is used to accept a line of text input. Input constraints
79 can be placed on a TextInput item (for example, through a \l validator or \l inputMask),
80 and setting \l echoMode to an appropriate value enables TextInput to be used for
81 a password input field.
83 On Mac OS X, the Up/Down key bindings for Home/End are explicitly disabled.
84 If you want such bindings (on any platform), you will need to construct them in QML.
86 \sa TextEdit, Text, {declarative/text/textselection}{Text Selection example}
88 QQuickTextInput::QQuickTextInput(QQuickItem* parent)
89 : QQuickImplicitSizeItem(*(new QQuickTextInputPrivate), parent)
95 QQuickTextInput::~QQuickTextInput()
99 void QQuickTextInput::componentComplete()
101 Q_D(QQuickTextInput);
103 QQuickImplicitSizeItem::componentComplete();
106 updateCursorRectangle();
107 if (d->cursorComponent && d->cursorComponent->isReady())
112 \qmlproperty string QtQuick2::TextInput::text
114 The text in the TextInput.
116 QString QQuickTextInput::text() const
118 Q_D(const QQuickTextInput);
120 QString content = d->m_text;
121 if (!d->m_tentativeCommit.isEmpty())
122 content.insert(d->m_cursor, d->m_tentativeCommit);
123 QString res = d->m_maskData ? d->stripString(content) : content;
124 return (res.isNull() ? QString::fromLatin1("") : res);
127 void QQuickTextInput::setText(const QString &s)
129 Q_D(QQuickTextInput);
132 if (d->composeMode())
133 qApp->inputPanel()->reset();
134 d->m_tentativeCommit.clear();
135 d->internalSetText(s, -1, false);
138 QString QQuickTextInputPrivate::realText() const
140 QString res = m_maskData ? stripString(m_text) : m_text;
141 return (res.isNull() ? QString::fromLatin1("") : res);
145 \qmlproperty string QtQuick2::TextInput::font.family
147 Sets the family name of the font.
149 The family name is case insensitive and may optionally include a foundry name, e.g. "Helvetica [Cronyx]".
150 If the family is available from more than one foundry and the foundry isn't specified, an arbitrary foundry is chosen.
151 If the family isn't available a family will be set using the font matching algorithm.
155 \qmlproperty bool QtQuick2::TextInput::font.bold
157 Sets whether the font weight is bold.
161 \qmlproperty enumeration QtQuick2::TextInput::font.weight
163 Sets the font's weight.
165 The weight can be one of:
168 \o Font.Normal - the default
175 TextInput { text: "Hello"; font.weight: Font.DemiBold }
180 \qmlproperty bool QtQuick2::TextInput::font.italic
182 Sets whether the font has an italic style.
186 \qmlproperty bool QtQuick2::TextInput::font.underline
188 Sets whether the text is underlined.
192 \qmlproperty bool QtQuick2::TextInput::font.strikeout
194 Sets whether the font has a strikeout style.
198 \qmlproperty real QtQuick2::TextInput::font.pointSize
200 Sets the font size in points. The point size must be greater than zero.
204 \qmlproperty int QtQuick2::TextInput::font.pixelSize
206 Sets the font size in pixels.
208 Using this function makes the font device dependent.
209 Use \c pointSize to set the size of the font in a device independent manner.
213 \qmlproperty real QtQuick2::TextInput::font.letterSpacing
215 Sets the letter spacing for the font.
217 Letter spacing changes the default spacing between individual letters in the font.
218 A positive value increases the letter spacing by the corresponding pixels; a negative value decreases the spacing.
222 \qmlproperty real QtQuick2::TextInput::font.wordSpacing
224 Sets the word spacing for the font.
226 Word spacing changes the default spacing between individual words.
227 A positive value increases the word spacing by a corresponding amount of pixels,
228 while a negative value decreases the inter-word spacing accordingly.
232 \qmlproperty enumeration QtQuick2::TextInput::font.capitalization
234 Sets the capitalization for the text.
237 \o Font.MixedCase - This is the normal text rendering option where no capitalization change is applied.
238 \o Font.AllUppercase - This alters the text to be rendered in all uppercase type.
239 \o Font.AllLowercase - This alters the text to be rendered in all lowercase type.
240 \o Font.SmallCaps - This alters the text to be rendered in small-caps type.
241 \o Font.Capitalize - This alters the text to be rendered with the first character of each word as an uppercase character.
245 TextInput { text: "Hello"; font.capitalization: Font.AllLowercase }
249 QFont QQuickTextInput::font() const
251 Q_D(const QQuickTextInput);
252 return d->sourceFont;
255 void QQuickTextInput::setFont(const QFont &font)
257 Q_D(QQuickTextInput);
258 if (d->sourceFont == font)
261 d->sourceFont = font;
262 QFont oldFont = d->font;
264 if (d->font.pointSizeF() != -1) {
266 qreal size = qRound(d->font.pointSizeF()*2.0);
267 d->font.setPointSizeF(size/2.0);
269 if (oldFont != d->font) {
271 updateCursorRectangle();
273 emit fontChanged(d->sourceFont);
277 \qmlproperty color QtQuick2::TextInput::color
281 QColor QQuickTextInput::color() const
283 Q_D(const QQuickTextInput);
287 void QQuickTextInput::setColor(const QColor &c)
289 Q_D(QQuickTextInput);
292 d->textLayoutDirty = true;
294 emit colorChanged(c);
300 \qmlproperty color QtQuick2::TextInput::selectionColor
302 The text highlight color, used behind selections.
304 QColor QQuickTextInput::selectionColor() const
306 Q_D(const QQuickTextInput);
307 return d->selectionColor;
310 void QQuickTextInput::setSelectionColor(const QColor &color)
312 Q_D(QQuickTextInput);
313 if (d->selectionColor == color)
316 d->selectionColor = color;
317 d->m_palette.setColor(QPalette::Highlight, d->selectionColor);
318 if (d->hasSelectedText()) {
319 d->textLayoutDirty = true;
322 emit selectionColorChanged(color);
325 \qmlproperty color QtQuick2::TextInput::selectedTextColor
327 The highlighted text color, used in selections.
329 QColor QQuickTextInput::selectedTextColor() const
331 Q_D(const QQuickTextInput);
332 return d->selectedTextColor;
335 void QQuickTextInput::setSelectedTextColor(const QColor &color)
337 Q_D(QQuickTextInput);
338 if (d->selectedTextColor == color)
341 d->selectedTextColor = color;
342 d->m_palette.setColor(QPalette::HighlightedText, d->selectedTextColor);
343 if (d->hasSelectedText()) {
344 d->textLayoutDirty = true;
347 emit selectedTextColorChanged(color);
351 \qmlproperty enumeration QtQuick2::TextInput::horizontalAlignment
352 \qmlproperty enumeration QtQuick2::TextInput::effectiveHorizontalAlignment
353 \qmlproperty enumeration QtQuick2::TextInput::verticalAlignment
355 Sets the horizontal alignment of the text within the TextInput item's
356 width and height. By default, the text alignment follows the natural alignment
357 of the text, for example text that is read from left to right will be aligned to
360 TextInput does not have vertical alignment, as the natural height is
361 exactly the height of the single line of text. If you set the height
362 manually to something larger, TextInput will always be top aligned
363 vertically. You can use anchors to align it however you want within
366 The valid values for \c horizontalAlignment are \c TextInput.AlignLeft, \c TextInput.AlignRight and
367 \c TextInput.AlignHCenter.
369 Valid values for \c verticalAlignment are \c TextEdit.AlignTop (default),
370 \c TextEdit.AlignBottom \c TextEdit.AlignVCenter.
372 When using the attached property LayoutMirroring::enabled to mirror application
373 layouts, the horizontal alignment of text will also be mirrored. However, the property
374 \c horizontalAlignment will remain unchanged. To query the effective horizontal alignment
375 of TextInput, use the read-only property \c effectiveHorizontalAlignment.
377 QQuickTextInput::HAlignment QQuickTextInput::hAlign() const
379 Q_D(const QQuickTextInput);
383 void QQuickTextInput::setHAlign(HAlignment align)
385 Q_D(QQuickTextInput);
386 bool forceAlign = d->hAlignImplicit && d->effectiveLayoutMirror;
387 d->hAlignImplicit = false;
388 if (d->setHAlign(align, forceAlign) && isComponentComplete()) {
390 updateCursorRectangle();
394 void QQuickTextInput::resetHAlign()
396 Q_D(QQuickTextInput);
397 d->hAlignImplicit = true;
398 if (d->determineHorizontalAlignment() && isComponentComplete()) {
400 updateCursorRectangle();
404 QQuickTextInput::HAlignment QQuickTextInput::effectiveHAlign() const
406 Q_D(const QQuickTextInput);
407 QQuickTextInput::HAlignment effectiveAlignment = d->hAlign;
408 if (!d->hAlignImplicit && d->effectiveLayoutMirror) {
410 case QQuickTextInput::AlignLeft:
411 effectiveAlignment = QQuickTextInput::AlignRight;
413 case QQuickTextInput::AlignRight:
414 effectiveAlignment = QQuickTextInput::AlignLeft;
420 return effectiveAlignment;
423 bool QQuickTextInputPrivate::setHAlign(QQuickTextInput::HAlignment alignment, bool forceAlign)
425 Q_Q(QQuickTextInput);
426 if ((hAlign != alignment || forceAlign) && alignment <= QQuickTextInput::AlignHCenter) { // justify not supported
427 QQuickTextInput::HAlignment oldEffectiveHAlign = q->effectiveHAlign();
429 emit q->horizontalAlignmentChanged(alignment);
430 if (oldEffectiveHAlign != q->effectiveHAlign())
431 emit q->effectiveHorizontalAlignmentChanged();
437 bool QQuickTextInputPrivate::determineHorizontalAlignment()
439 if (hAlignImplicit) {
440 // if no explicit alignment has been set, follow the natural layout direction of the text
441 QString text = q_func()->text();
443 text = m_textLayout.preeditAreaText();
444 bool isRightToLeft = text.isEmpty() ? QGuiApplication::keyboardInputDirection() == Qt::RightToLeft : text.isRightToLeft();
445 return setHAlign(isRightToLeft ? QQuickTextInput::AlignRight : QQuickTextInput::AlignLeft);
450 QQuickTextInput::VAlignment QQuickTextInput::vAlign() const
452 Q_D(const QQuickTextInput);
456 void QQuickTextInput::setVAlign(QQuickTextInput::VAlignment alignment)
458 Q_D(QQuickTextInput);
459 if (alignment == d->vAlign)
461 d->vAlign = alignment;
462 emit verticalAlignmentChanged(d->vAlign);
463 if (isComponentComplete()) {
464 updateCursorRectangle();
469 \qmlproperty enumeration QtQuick2::TextInput::wrapMode
471 Set this property to wrap the text to the TextEdit item's width.
472 The text will only wrap if an explicit width has been set.
475 \o TextInput.NoWrap - no wrapping will be performed. If the text contains insufficient newlines, then implicitWidth will exceed a set width.
476 \o TextInput.WordWrap - wrapping is done on word boundaries only. If a word is too long, implicitWidth will exceed a set width.
477 \o TextInput.WrapAnywhere - wrapping is done at any point on a line, even if it occurs in the middle of a word.
478 \o TextInput.Wrap - if possible, wrapping occurs at a word boundary; otherwise it will occur at the appropriate point on the line, even in the middle of a word.
481 The default is TextInput.NoWrap. If you set a width, consider using TextInput.Wrap.
483 QQuickTextInput::WrapMode QQuickTextInput::wrapMode() const
485 Q_D(const QQuickTextInput);
489 void QQuickTextInput::setWrapMode(WrapMode mode)
491 Q_D(QQuickTextInput);
492 if (mode == d->wrapMode)
496 updateCursorRectangle();
497 emit wrapModeChanged();
500 void QQuickTextInputPrivate::mirrorChange()
502 Q_Q(QQuickTextInput);
503 if (q->isComponentComplete()) {
504 if (!hAlignImplicit && (hAlign == QQuickTextInput::AlignRight || hAlign == QQuickTextInput::AlignLeft)) {
505 q->updateCursorRectangle();
506 emit q->effectiveHorizontalAlignmentChanged();
512 \qmlproperty bool QtQuick2::TextInput::readOnly
514 Sets whether user input can modify the contents of the TextInput.
516 If readOnly is set to true, then user input will not affect the text
517 property. Any bindings or attempts to set the text property will still
520 bool QQuickTextInput::isReadOnly() const
522 Q_D(const QQuickTextInput);
523 return d->m_readOnly;
526 void QQuickTextInput::setReadOnly(bool ro)
528 Q_D(QQuickTextInput);
529 if (d->m_readOnly == ro)
532 setFlag(QQuickItem::ItemAcceptsInputMethod, !ro);
535 d->setCursorPosition(d->end());
537 emit readOnlyChanged(ro);
541 \qmlproperty int QtQuick2::TextInput::maximumLength
542 The maximum permitted length of the text in the TextInput.
544 If the text is too long, it is truncated at the limit.
546 By default, this property contains a value of 32767.
548 int QQuickTextInput::maxLength() const
550 Q_D(const QQuickTextInput);
551 return d->m_maxLength;
554 void QQuickTextInput::setMaxLength(int ml)
556 Q_D(QQuickTextInput);
557 if (d->m_maxLength == ml || d->m_maskData)
561 d->internalSetText(d->m_text, -1, false);
563 emit maximumLengthChanged(ml);
567 \qmlproperty bool QtQuick2::TextInput::cursorVisible
568 Set to true when the TextInput shows a cursor.
570 This property is set and unset when the TextInput gets active focus, so that other
571 properties can be bound to whether the cursor is currently showing. As it
572 gets set and unset automatically, when you set the value yourself you must
573 keep in mind that your value may be overwritten.
575 It can be set directly in script, for example if a KeyProxy might
576 forward keys to it and you desire it to look active when this happens
577 (but without actually giving it active focus).
579 It should not be set directly on the element, like in the below QML,
580 as the specified value will be overridden an lost on focus changes.
589 In the above snippet the cursor will still become visible when the
590 TextInput gains active focus.
592 bool QQuickTextInput::isCursorVisible() const
594 Q_D(const QQuickTextInput);
595 return d->cursorVisible;
598 void QQuickTextInput::setCursorVisible(bool on)
600 Q_D(QQuickTextInput);
601 if (d->cursorVisible == on)
603 d->cursorVisible = on;
604 d->setCursorBlinkPeriod(on ? qApp->styleHints()->cursorFlashTime() : 0);
605 QRect r = cursorRectangle();
606 if (d->inputMask().isEmpty())
610 emit cursorVisibleChanged(d->cursorVisible);
614 \qmlproperty int QtQuick2::TextInput::cursorPosition
615 The position of the cursor in the TextInput.
617 int QQuickTextInput::cursorPosition() const
619 Q_D(const QQuickTextInput);
623 void QQuickTextInput::setCursorPosition(int cp)
625 Q_D(QQuickTextInput);
626 if (cp < 0 || cp > text().length())
632 Returns a Rect which encompasses the cursor, but which may be larger than is
633 required. Ignores custom cursor delegates.
635 QRect QQuickTextInput::cursorRectangle() const
637 Q_D(const QQuickTextInput);
640 if (d->m_preeditCursor != -1)
641 c += d->m_preeditCursor;
642 if (d->m_echoMode == NoEcho || !isComponentComplete())
644 QTextLine l = d->m_textLayout.lineForTextPosition(c);
646 qRound(l.cursorToX(c) - d->hscroll),
647 qRound(l.y() - d->vscroll),
653 \qmlproperty int QtQuick2::TextInput::selectionStart
655 The cursor position before the first character in the current selection.
657 This property is read-only. To change the selection, use select(start,end),
658 selectAll(), or selectWord().
660 \sa selectionEnd, cursorPosition, selectedText
662 int QQuickTextInput::selectionStart() const
664 Q_D(const QQuickTextInput);
665 return d->lastSelectionStart;
668 \qmlproperty int QtQuick2::TextInput::selectionEnd
670 The cursor position after the last character in the current selection.
672 This property is read-only. To change the selection, use select(start,end),
673 selectAll(), or selectWord().
675 \sa selectionStart, cursorPosition, selectedText
677 int QQuickTextInput::selectionEnd() const
679 Q_D(const QQuickTextInput);
680 return d->lastSelectionEnd;
683 \qmlmethod void QtQuick2::TextInput::select(int start, int end)
685 Causes the text from \a start to \a end to be selected.
687 If either start or end is out of range, the selection is not changed.
689 After calling this, selectionStart will become the lesser
690 and selectionEnd will become the greater (regardless of the order passed
693 \sa selectionStart, selectionEnd
695 void QQuickTextInput::select(int start, int end)
697 Q_D(QQuickTextInput);
698 if (start < 0 || end < 0 || start > text().length() || end > text().length())
700 d->setSelection(start, end-start);
704 \qmlproperty string QtQuick2::TextInput::selectedText
706 This read-only property provides the text currently selected in the
709 It is equivalent to the following snippet, but is faster and easier
713 myTextInput.text.toString().substring(myTextInput.selectionStart,
714 myTextInput.selectionEnd);
717 QString QQuickTextInput::selectedText() const
719 Q_D(const QQuickTextInput);
720 return d->selectedText();
724 \qmlproperty bool QtQuick2::TextInput::activeFocusOnPress
726 Whether the TextInput should gain active focus on a mouse press. By default this is
729 bool QQuickTextInput::focusOnPress() const
731 Q_D(const QQuickTextInput);
732 return d->focusOnPress;
735 void QQuickTextInput::setFocusOnPress(bool b)
737 Q_D(QQuickTextInput);
738 if (d->focusOnPress == b)
743 emit activeFocusOnPressChanged(d->focusOnPress);
746 \qmlproperty bool QtQuick2::TextInput::autoScroll
748 Whether the TextInput should scroll when the text is longer than the width. By default this is
751 bool QQuickTextInput::autoScroll() const
753 Q_D(const QQuickTextInput);
754 return d->autoScroll;
757 void QQuickTextInput::setAutoScroll(bool b)
759 Q_D(QQuickTextInput);
760 if (d->autoScroll == b)
764 //We need to repaint so that the scrolling is taking into account.
765 updateCursorRectangle();
766 emit autoScrollChanged(d->autoScroll);
769 #ifndef QT_NO_VALIDATOR
772 \qmlclass IntValidator QIntValidator
773 \inqmlmodule QtQuick 2
774 \ingroup qml-basic-visual-elements
776 This element provides a validator for integer values.
778 IntValidator uses the \l {QLocale::setDefault()}{default locale} to interpret the number and
779 will accept locale specific digits, group separators, and positive and negative signs. In
780 addition, IntValidator is always guaranteed to accept a number formatted according to the "C"
784 \qmlproperty int QtQuick2::IntValidator::top
786 This property holds the validator's highest acceptable value.
787 By default, this property's value is derived from the highest signed integer available (typically 2147483647).
790 \qmlproperty int QtQuick2::IntValidator::bottom
792 This property holds the validator's lowest acceptable value.
793 By default, this property's value is derived from the lowest signed integer available (typically -2147483647).
797 \qmlclass DoubleValidator QDoubleValidator
798 \inqmlmodule QtQuick 2
799 \ingroup qml-basic-visual-elements
801 This element provides a validator for non-integer numbers.
805 \qmlproperty real QtQuick2::DoubleValidator::top
807 This property holds the validator's maximum acceptable value.
808 By default, this property contains a value of infinity.
811 \qmlproperty real QtQuick2::DoubleValidator::bottom
813 This property holds the validator's minimum acceptable value.
814 By default, this property contains a value of -infinity.
817 \qmlproperty int QtQuick2::DoubleValidator::decimals
819 This property holds the validator's maximum number of digits after the decimal point.
820 By default, this property contains a value of 1000.
823 \qmlproperty enumeration QtQuick2::DoubleValidator::notation
824 This property holds the notation of how a string can describe a number.
826 The possible values for this property are:
829 \o DoubleValidator.StandardNotation
830 \o DoubleValidator.ScientificNotation (default)
833 If this property is set to DoubleValidator.ScientificNotation, the written number may have an exponent part (e.g. 1.5E-2).
837 \qmlclass RegExpValidator QRegExpValidator
838 \inqmlmodule QtQuick 2
839 \ingroup qml-basic-visual-elements
841 This element provides a validator, which counts as valid any string which
842 matches a specified regular expression.
845 \qmlproperty regExp QtQuick2::RegExpValidator::regExp
847 This property holds the regular expression used for validation.
849 Note that this property should be a regular expression in JS syntax, e.g /a/ for the regular expression
852 By default, this property contains a regular expression with the pattern .* that matches any string.
856 \qmlproperty Validator QtQuick2::TextInput::validator
858 Allows you to set a validator on the TextInput. When a validator is set
859 the TextInput will only accept input which leaves the text property in
860 an acceptable or intermediate state. The accepted signal will only be sent
861 if the text is in an acceptable state when enter is pressed.
863 Currently supported validators are IntValidator, DoubleValidator and
864 RegExpValidator. An example of using validators is shown below, which allows
865 input of integers between 11 and 31 into the text input:
870 validator: IntValidator{bottom: 11; top: 31;}
875 \sa acceptableInput, inputMask
878 QValidator* QQuickTextInput::validator() const
880 Q_D(const QQuickTextInput);
881 return d->m_validator;
884 void QQuickTextInput::setValidator(QValidator* v)
886 Q_D(QQuickTextInput);
887 if (d->m_validator == v)
891 if (!d->hasAcceptableInput(d->m_text)) {
892 d->oldValidity = false;
893 emit acceptableInputChanged();
896 emit validatorChanged();
898 #endif // QT_NO_VALIDATOR
901 \qmlproperty string QtQuick2::TextInput::inputMask
903 Allows you to set an input mask on the TextInput, restricting the allowable
904 text inputs. See QLineEdit::inputMask for further details, as the exact
905 same mask strings are used by TextInput.
907 \sa acceptableInput, validator
909 QString QQuickTextInput::inputMask() const
911 Q_D(const QQuickTextInput);
912 return d->inputMask();
915 void QQuickTextInput::setInputMask(const QString &im)
917 Q_D(QQuickTextInput);
918 if (d->inputMask() == im)
922 emit inputMaskChanged(d->inputMask());
926 \qmlproperty bool QtQuick2::TextInput::acceptableInput
928 This property is always true unless a validator or input mask has been set.
929 If a validator or input mask has been set, this property will only be true
930 if the current text is acceptable to the validator or input mask as a final
931 string (not as an intermediate string).
933 bool QQuickTextInput::hasAcceptableInput() const
935 Q_D(const QQuickTextInput);
936 return d->hasAcceptableInput(d->m_text);
940 \qmlsignal QtQuick2::TextInput::onAccepted()
942 This handler is called when the Return or Enter key is pressed.
943 Note that if there is a \l validator or \l inputMask set on the text
944 input, the handler will only be emitted if the input is in an acceptable
948 void QQuickTextInputPrivate::updateInputMethodHints()
950 Q_Q(QQuickTextInput);
951 Qt::InputMethodHints hints = inputMethodHints;
952 if (m_echoMode == QQuickTextInput::Password || m_echoMode == QQuickTextInput::NoEcho)
953 hints |= Qt::ImhHiddenText;
954 else if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit)
955 hints &= ~Qt::ImhHiddenText;
956 if (m_echoMode != QQuickTextInput::Normal)
957 hints |= (Qt::ImhNoAutoUppercase | Qt::ImhNoPredictiveText);
958 q->setInputMethodHints(hints);
961 \qmlproperty enumeration QtQuick2::TextInput::echoMode
963 Specifies how the text should be displayed in the TextInput.
965 \o TextInput.Normal - Displays the text as it is. (Default)
966 \o TextInput.Password - Displays asterisks instead of characters.
967 \o TextInput.NoEcho - Displays nothing.
968 \o TextInput.PasswordEchoOnEdit - Displays characters as they are entered
969 while editing, otherwise displays asterisks.
972 QQuickTextInput::EchoMode QQuickTextInput::echoMode() const
974 Q_D(const QQuickTextInput);
975 return QQuickTextInput::EchoMode(d->m_echoMode);
978 void QQuickTextInput::setEchoMode(QQuickTextInput::EchoMode echo)
980 Q_D(QQuickTextInput);
981 if (echoMode() == echo)
983 d->cancelPasswordEchoTimer();
984 d->m_echoMode = echo;
985 d->m_passwordEchoEditing = false;
986 d->updateInputMethodHints();
987 d->updateDisplayText();
988 updateCursorRectangle();
990 emit echoModeChanged(echoMode());
993 Qt::InputMethodHints QQuickTextInput::imHints() const
995 Q_D(const QQuickTextInput);
996 return d->inputMethodHints;
999 void QQuickTextInput::setIMHints(Qt::InputMethodHints hints)
1001 Q_D(QQuickTextInput);
1002 if (d->inputMethodHints == hints)
1004 d->inputMethodHints = hints;
1005 d->updateInputMethodHints();
1009 \qmlproperty Component QtQuick2::TextInput::cursorDelegate
1010 The delegate for the cursor in the TextInput.
1012 If you set a cursorDelegate for a TextInput, this delegate will be used for
1013 drawing the cursor instead of the standard cursor. An instance of the
1014 delegate will be created and managed by the TextInput when a cursor is
1015 needed, and the x property of delegate instance will be set so as
1016 to be one pixel before the top left of the current character.
1018 Note that the root item of the delegate component must be a QDeclarativeItem or
1019 QDeclarativeItem derived item.
1021 QDeclarativeComponent* QQuickTextInput::cursorDelegate() const
1023 Q_D(const QQuickTextInput);
1024 return d->cursorComponent;
1027 void QQuickTextInput::setCursorDelegate(QDeclarativeComponent* c)
1029 Q_D(QQuickTextInput);
1030 if (d->cursorComponent == c)
1033 d->cursorComponent = c;
1035 //note that the components are owned by something else
1036 delete d->cursorItem;
1038 d->startCreatingCursor();
1041 emit cursorDelegateChanged();
1044 void QQuickTextInputPrivate::startCreatingCursor()
1046 Q_Q(QQuickTextInput);
1047 if (cursorComponent->isReady()) {
1049 } else if (cursorComponent->isLoading()) {
1050 q->connect(cursorComponent, SIGNAL(statusChanged(int)),
1051 q, SLOT(createCursor()));
1053 qmlInfo(q, cursorComponent->errors()) << QQuickTextInput::tr("Could not load cursor delegate");
1057 void QQuickTextInput::createCursor()
1059 Q_D(QQuickTextInput);
1060 if (!isComponentComplete())
1063 if (d->cursorComponent->isError()) {
1064 qmlInfo(this, d->cursorComponent->errors()) << tr("Could not load cursor delegate");
1068 if (!d->cursorComponent->isReady())
1072 delete d->cursorItem;
1073 QDeclarativeContext *creationContext = d->cursorComponent->creationContext();
1074 QObject *object = d->cursorComponent->create(creationContext ? creationContext : qmlContext(this));
1075 d->cursorItem = qobject_cast<QQuickItem*>(object);
1076 if (!d->cursorItem) {
1078 qmlInfo(this, d->cursorComponent->errors()) << tr("Could not instantiate cursor delegate");
1082 QRectF r = cursorRectangle();
1084 QDeclarative_setParent_noEvent(d->cursorItem, this);
1085 d->cursorItem->setParentItem(this);
1086 d->cursorItem->setPos(r.topLeft());
1087 d->cursorItem->setHeight(r.height());
1091 \qmlmethod rect QtQuick2::TextInput::positionToRectangle(int pos)
1093 This function takes a character position and returns the rectangle that the
1094 cursor would occupy, if it was placed at that character position.
1096 This is similar to setting the cursorPosition, and then querying the cursor
1097 rectangle, but the cursorPosition is not changed.
1099 QRectF QQuickTextInput::positionToRectangle(int pos) const
1101 Q_D(const QQuickTextInput);
1102 if (pos > d->m_cursor)
1103 pos += d->preeditAreaText().length();
1104 QTextLine l = d->m_textLayout.lineAt(0);
1105 return QRectF(l.cursorToX(pos) - d->hscroll, 0.0, d->m_cursorWidth, l.height());
1109 \qmlmethod int QtQuick2::TextInput::positionAt(real x, real y, CursorPosition position = CursorBetweenCharacters)
1111 This function returns the character position at
1112 x and y pixels from the top left of the textInput. Position 0 is before the
1113 first character, position 1 is after the first character but before the second,
1114 and so on until position text.length, which is after all characters.
1116 This means that for all x values before the first character this function returns 0,
1117 and for all x values after the last character this function returns text.length. If
1118 the y value is above the text the position will be that of the nearest character on
1119 the first line line and if it is below the text the position of the nearest character
1120 on the last line will be returned.
1122 The cursor position type specifies how the cursor position should be resolved.
1125 \o TextInput.CursorBetweenCharacters - Returns the position between characters that is nearest x.
1126 \o TextInput.CursorOnCharacter - Returns the position before the character that is nearest x.
1130 void QQuickTextInput::positionAt(QDeclarativeV8Function *args) const
1132 Q_D(const QQuickTextInput);
1136 QTextLine::CursorPosition position = QTextLine::CursorBetweenCharacters;
1138 if (args->Length() < 1)
1142 v8::Local<v8::Value> arg = (*args)[i];
1143 x = arg->NumberValue();
1145 if (++i < args->Length()) {
1147 y = arg->NumberValue();
1150 if (++i < args->Length()) {
1152 position = QTextLine::CursorPosition(arg->Int32Value());
1155 int pos = d->positionAt(x, y, position);
1156 const int cursor = d->m_cursor;
1158 const int preeditLength = d->preeditAreaText().length();
1159 pos = pos > cursor + preeditLength
1160 ? pos - preeditLength
1163 args->returnValue(v8::Int32::New(pos));
1166 int QQuickTextInputPrivate::positionAt(int x, int y, QTextLine::CursorPosition position) const
1170 QTextLine line = m_textLayout.lineAt(0);
1171 for (int i = 1; i < m_textLayout.lineCount(); ++i) {
1172 QTextLine nextLine = m_textLayout.lineAt(i);
1174 if (y < (line.rect().bottom() + nextLine.y()) / 2)
1178 return line.xToCursor(x, position);
1181 void QQuickTextInput::keyPressEvent(QKeyEvent* ev)
1183 Q_D(QQuickTextInput);
1184 // Don't allow MacOSX up/down support, and we don't allow a completer.
1185 bool ignore = (ev->key() == Qt::Key_Up || ev->key() == Qt::Key_Down) && ev->modifiers() == Qt::NoModifier;
1186 if (!ignore && (d->lastSelectionStart == d->lastSelectionEnd) && (ev->key() == Qt::Key_Right || ev->key() == Qt::Key_Left)) {
1187 // Ignore when moving off the end unless there is a selection,
1188 // because then moving will do something (deselect).
1189 int cursorPosition = d->m_cursor;
1190 if (cursorPosition == 0)
1191 ignore = ev->key() == (d->layoutDirection() == Qt::LeftToRight ? Qt::Key_Left : Qt::Key_Right);
1192 if (cursorPosition == text().length())
1193 ignore = ev->key() == (d->layoutDirection() == Qt::LeftToRight ? Qt::Key_Right : Qt::Key_Left);
1198 d->processKeyEvent(ev);
1200 if (!ev->isAccepted())
1201 QQuickImplicitSizeItem::keyPressEvent(ev);
1204 void QQuickTextInput::inputMethodEvent(QInputMethodEvent *ev)
1206 Q_D(QQuickTextInput);
1207 const bool wasComposing = d->preeditAreaText().length() > 0;
1208 if (d->m_readOnly) {
1211 d->processInputMethodEvent(ev);
1213 if (!ev->isAccepted())
1214 QQuickImplicitSizeItem::inputMethodEvent(ev);
1216 if (wasComposing != (d->m_textLayout.preeditAreaText().length() > 0))
1217 emit inputMethodComposingChanged();
1220 void QQuickTextInput::mouseDoubleClickEvent(QMouseEvent *event)
1222 Q_D(QQuickTextInput);
1224 if (d->selectByMouse && event->button() == Qt::LeftButton) {
1226 int cursor = d->positionAt(event->localPos());
1227 d->selectWordAtPos(cursor);
1228 event->setAccepted(true);
1229 if (!d->hasPendingTripleClick()) {
1230 d->tripleClickStartPoint = event->localPos().toPoint();
1231 d->tripleClickTimer.start();
1234 if (d->sendMouseEventToInputContext(event))
1236 QQuickImplicitSizeItem::mouseDoubleClickEvent(event);
1240 void QQuickTextInput::mousePressEvent(QMouseEvent *event)
1242 Q_D(QQuickTextInput);
1244 d->pressPos = event->localPos();
1246 if (d->focusOnPress) {
1247 bool hadActiveFocus = hasActiveFocus();
1249 // re-open input panel on press if already focused
1250 if (hasActiveFocus() && hadActiveFocus && !d->m_readOnly)
1251 openSoftwareInputPanel();
1253 if (d->selectByMouse) {
1254 setKeepMouseGrab(false);
1255 d->selectPressed = true;
1256 QPoint distanceVector = d->pressPos.toPoint() - d->tripleClickStartPoint;
1257 if (d->hasPendingTripleClick()
1258 && distanceVector.manhattanLength() < qApp->styleHints()->startDragDistance()) {
1259 event->setAccepted(true);
1265 if (d->sendMouseEventToInputContext(event))
1268 bool mark = (event->modifiers() & Qt::ShiftModifier) && d->selectByMouse;
1269 int cursor = d->positionAt(event->localPos());
1270 d->moveCursor(cursor, mark);
1271 event->setAccepted(true);
1274 void QQuickTextInput::mouseMoveEvent(QMouseEvent *event)
1276 Q_D(QQuickTextInput);
1278 if (d->selectPressed) {
1279 if (qAbs(int(event->localPos().x() - d->pressPos.x())) > qApp->styleHints()->startDragDistance())
1280 setKeepMouseGrab(true);
1282 if (d->composeMode()) {
1284 int startPos = d->positionAt(d->pressPos);
1285 int currentPos = d->positionAt(event->localPos());
1286 if (startPos != currentPos)
1287 d->setSelection(startPos, currentPos - startPos);
1289 moveCursorSelection(d->positionAt(event->localPos()), d->mouseSelectionMode);
1291 event->setAccepted(true);
1293 QQuickImplicitSizeItem::mouseMoveEvent(event);
1297 void QQuickTextInput::mouseReleaseEvent(QMouseEvent *event)
1299 Q_D(QQuickTextInput);
1300 if (d->sendMouseEventToInputContext(event))
1302 if (d->selectPressed) {
1303 d->selectPressed = false;
1304 setKeepMouseGrab(false);
1306 #ifndef QT_NO_CLIPBOARD
1307 if (QGuiApplication::clipboard()->supportsSelection()) {
1308 if (event->button() == Qt::LeftButton) {
1309 d->copy(QClipboard::Selection);
1310 } else if (!d->m_readOnly && event->button() == Qt::MidButton) {
1312 d->insert(QGuiApplication::clipboard()->text(QClipboard::Selection));
1316 if (!event->isAccepted())
1317 QQuickImplicitSizeItem::mouseReleaseEvent(event);
1320 bool QQuickTextInputPrivate::sendMouseEventToInputContext(QMouseEvent *event)
1322 #if !defined QT_NO_IM
1323 if (composeMode()) {
1324 int tmp_cursor = positionAt(event->localPos());
1325 int mousePos = tmp_cursor - m_cursor;
1326 if (mousePos >= 0 && mousePos <= m_textLayout.preeditAreaText().length()) {
1327 if (event->type() == QEvent::MouseButtonRelease) {
1328 qApp->inputPanel()->invokeAction(QInputPanel::Click, mousePos);
1341 void QQuickTextInput::mouseUngrabEvent()
1343 Q_D(QQuickTextInput);
1344 d->selectPressed = false;
1345 setKeepMouseGrab(false);
1348 bool QQuickTextInput::event(QEvent* ev)
1350 #ifndef QT_NO_SHORTCUT
1351 Q_D(QQuickTextInput);
1352 if (ev->type() == QEvent::ShortcutOverride) {
1355 QKeyEvent* ke = static_cast<QKeyEvent*>(ev);
1356 if (ke == QKeySequence::Copy
1357 || ke == QKeySequence::Paste
1358 || ke == QKeySequence::Cut
1359 || ke == QKeySequence::Redo
1360 || ke == QKeySequence::Undo
1361 || ke == QKeySequence::MoveToNextWord
1362 || ke == QKeySequence::MoveToPreviousWord
1363 || ke == QKeySequence::MoveToStartOfDocument
1364 || ke == QKeySequence::MoveToEndOfDocument
1365 || ke == QKeySequence::SelectNextWord
1366 || ke == QKeySequence::SelectPreviousWord
1367 || ke == QKeySequence::SelectStartOfLine
1368 || ke == QKeySequence::SelectEndOfLine
1369 || ke == QKeySequence::SelectStartOfBlock
1370 || ke == QKeySequence::SelectEndOfBlock
1371 || ke == QKeySequence::SelectStartOfDocument
1372 || ke == QKeySequence::SelectAll
1373 || ke == QKeySequence::SelectEndOfDocument) {
1375 } else if (ke->modifiers() == Qt::NoModifier || ke->modifiers() == Qt::ShiftModifier
1376 || ke->modifiers() == Qt::KeypadModifier) {
1377 if (ke->key() < Qt::Key_Escape) {
1381 switch (ke->key()) {
1382 case Qt::Key_Delete:
1385 case Qt::Key_Backspace:
1397 return QQuickImplicitSizeItem::event(ev);
1400 void QQuickTextInput::geometryChanged(const QRectF &newGeometry,
1401 const QRectF &oldGeometry)
1403 Q_D(QQuickTextInput);
1404 if (newGeometry.width() != oldGeometry.width())
1406 updateCursorRectangle();
1407 QQuickImplicitSizeItem::geometryChanged(newGeometry, oldGeometry);
1410 void QQuickTextInputPrivate::updateHorizontalScroll()
1412 Q_Q(QQuickTextInput);
1413 QTextLine currentLine = m_textLayout.lineForTextPosition(m_cursor + m_preeditCursor);
1414 const int preeditLength = m_textLayout.preeditAreaText().length();
1415 const int width = q->width();
1416 int widthUsed = currentLine.isValid() ? qRound(currentLine.naturalTextWidth()) : 0;
1417 int previousScroll = hscroll;
1419 if (!autoScroll || widthUsed <= width || m_echoMode == QQuickTextInput::NoEcho) {
1422 int cix = qRound(currentLine.cursorToX(m_cursor + preeditLength));
1423 if (cix - hscroll >= width) {
1424 // text doesn't fit, cursor is to the right of br (scroll right)
1425 hscroll = cix - width;
1426 } else if (cix - hscroll < 0 && hscroll < widthUsed) {
1427 // text doesn't fit, cursor is to the left of br (scroll left)
1429 } else if (widthUsed - hscroll < width) {
1430 // text doesn't fit, text document is to the left of br; align
1432 hscroll = widthUsed - width;
1434 if (preeditLength > 0) {
1435 // check to ensure long pre-edit text doesn't push the cursor
1437 cix = qRound(currentLine.cursorToX(m_cursor + qMax(0, m_preeditCursor - 1)));
1442 if (previousScroll != hscroll)
1443 textLayoutDirty = true;
1446 void QQuickTextInputPrivate::updateVerticalScroll()
1448 Q_Q(QQuickTextInput);
1449 const int preeditLength = m_textLayout.preeditAreaText().length();
1450 const int height = q->height();
1451 int heightUsed = boundingRect.height();
1452 int previousScroll = vscroll;
1454 if (!autoScroll || heightUsed <= height) {
1455 // text fits in br; use vscroll for alignment
1456 switch (vAlign & ~(Qt::AlignAbsolute|Qt::AlignHorizontal_Mask)) {
1457 case Qt::AlignBottom:
1458 vscroll = heightUsed - height;
1460 case Qt::AlignVCenter:
1461 vscroll = (heightUsed - height) / 2;
1469 QRectF r = m_textLayout.lineForTextPosition(m_cursor + preeditLength).rect();
1470 int top = qFloor(r.top());
1471 int bottom = qCeil(r.bottom());
1473 if (bottom - vscroll >= height) {
1474 // text doesn't fit, cursor is to the below the br (scroll down)
1475 vscroll = bottom - height;
1476 } else if (top - vscroll < 0 && vscroll < heightUsed) {
1477 // text doesn't fit, cursor is above br (scroll up)
1479 } else if (heightUsed - vscroll < height) {
1480 // text doesn't fit, text document is to the left of br; align
1482 vscroll = heightUsed - height;
1484 if (preeditLength > 0) {
1485 // check to ensure long pre-edit text doesn't push the cursor
1487 top = qRound(m_textLayout.lineForTextPosition(
1488 m_cursor + qMax(0, m_preeditCursor - 1)).rect().top());
1493 if (previousScroll != vscroll)
1494 textLayoutDirty = true;
1497 QSGNode *QQuickTextInput::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data)
1500 Q_D(QQuickTextInput);
1502 QQuickTextNode *node = static_cast<QQuickTextNode *>(oldNode);
1504 node = new QQuickTextNode(QQuickItemPrivate::get(this)->sceneGraphContext());
1507 if (!d->textLayoutDirty) {
1508 QSGSimpleRectNode *cursorNode = node->cursorNode();
1509 if (cursorNode != 0 && !isReadOnly()) {
1510 cursorNode->setRect(cursorRectangle());
1512 if (!d->cursorVisible || (!d->m_blinkStatus && d->m_blinkPeriod > 0)) {
1519 node->deleteContent();
1520 node->setMatrix(QMatrix4x4());
1522 QPoint offset = QPoint(0,0);
1523 QFontMetrics fm = QFontMetrics(d->font);
1524 if (d->autoScroll) {
1525 // the y offset is there to keep the baseline constant in case we have script changes in the text.
1526 offset = -QPoint(d->hscroll, d->vscroll + d->m_ascent - fm.ascent());
1528 offset = -QPoint(d->hscroll, d->vscroll);
1531 if (!d->m_textLayout.text().isEmpty()) {
1532 node->addTextLayout(offset, &d->m_textLayout, d->color,
1533 QQuickText::Normal, QColor(),
1534 d->selectionColor, d->selectedTextColor,
1535 d->selectionStart(),
1536 d->selectionEnd() - 1); // selectionEnd() returns first char after
1540 if (!isReadOnly() && d->cursorItem == 0) {
1541 node->setCursor(cursorRectangle(), d->color);
1542 if (!d->cursorVisible || (!d->m_blinkStatus && d->m_blinkPeriod > 0)) {
1549 d->textLayoutDirty = false;
1555 QVariant QQuickTextInput::inputMethodQuery(Qt::InputMethodQuery property) const
1557 Q_D(const QQuickTextInput);
1560 return QVariant((bool)(flags() & ItemAcceptsInputMethod));
1562 return QVariant((int)inputMethodHints());
1563 case Qt::ImCursorRectangle:
1564 return cursorRectangle();
1567 case Qt::ImCursorPosition:
1568 return QVariant(d->m_cursor);
1569 case Qt::ImSurroundingText:
1570 if (d->m_echoMode == PasswordEchoOnEdit && !d->m_passwordEchoEditing) {
1571 return QVariant(displayText());
1573 return QVariant(d->realText());
1575 case Qt::ImCurrentSelection:
1576 return QVariant(selectedText());
1577 case Qt::ImMaximumTextLength:
1578 return QVariant(maxLength());
1579 case Qt::ImAnchorPosition:
1580 if (d->selectionStart() == d->selectionEnd())
1581 return QVariant(d->m_cursor);
1582 else if (d->selectionStart() == d->m_cursor)
1583 return QVariant(d->selectionEnd());
1585 return QVariant(d->selectionStart());
1592 \qmlmethod void QtQuick2::TextInput::deselect()
1594 Removes active text selection.
1596 void QQuickTextInput::deselect()
1598 Q_D(QQuickTextInput);
1603 \qmlmethod void QtQuick2::TextInput::selectAll()
1605 Causes all text to be selected.
1607 void QQuickTextInput::selectAll()
1609 Q_D(QQuickTextInput);
1610 d->setSelection(0, text().length());
1614 \qmlmethod void QtQuick2::TextInput::isRightToLeft(int start, int end)
1616 Returns true if the natural reading direction of the editor text
1617 found between positions \a start and \a end is right to left.
1619 bool QQuickTextInput::isRightToLeft(int start, int end)
1622 qmlInfo(this) << "isRightToLeft(start, end) called with the end property being smaller than the start.";
1625 return text().mid(start, end - start).isRightToLeft();
1629 #ifndef QT_NO_CLIPBOARD
1631 \qmlmethod QtQuick2::TextInput::cut()
1633 Moves the currently selected text to the system clipboard.
1635 void QQuickTextInput::cut()
1637 Q_D(QQuickTextInput);
1643 \qmlmethod QtQuick2::TextInput::copy()
1645 Copies the currently selected text to the system clipboard.
1647 void QQuickTextInput::copy()
1649 Q_D(QQuickTextInput);
1654 \qmlmethod QtQuick2::TextInput::paste()
1656 Replaces the currently selected text by the contents of the system clipboard.
1658 void QQuickTextInput::paste()
1660 Q_D(QQuickTextInput);
1664 #endif // QT_NO_CLIPBOARD
1667 \qmlmethod void QtQuick2::TextInput::selectWord()
1669 Causes the word closest to the current cursor position to be selected.
1671 void QQuickTextInput::selectWord()
1673 Q_D(QQuickTextInput);
1674 d->selectWordAtPos(d->m_cursor);
1678 \qmlproperty bool QtQuick2::TextInput::smooth
1680 This property holds whether the text is smoothly scaled or transformed.
1682 Smooth filtering gives better visual quality, but is slower. If
1683 the item is displayed at its natural size, this property has no visual or
1686 \note Generally scaling artifacts are only visible if the item is stationary on
1687 the screen. A common pattern when animating an item is to disable smooth
1688 filtering at the beginning of the animation and reenable it at the conclusion.
1692 \qmlproperty string QtQuick2::TextInput::passwordCharacter
1694 This is the character displayed when echoMode is set to Password or
1695 PasswordEchoOnEdit. By default it is an asterisk.
1697 If this property is set to a string with more than one character,
1698 the first character is used. If the string is empty, the value
1699 is ignored and the property is not set.
1701 QString QQuickTextInput::passwordCharacter() const
1703 Q_D(const QQuickTextInput);
1704 return QString(d->m_passwordCharacter);
1707 void QQuickTextInput::setPasswordCharacter(const QString &str)
1709 Q_D(QQuickTextInput);
1710 if (str.length() < 1)
1712 d->m_passwordCharacter = str.constData()[0];
1713 if (d->m_echoMode == Password || d->m_echoMode == PasswordEchoOnEdit)
1714 d->updateDisplayText();
1715 emit passwordCharacterChanged();
1719 \qmlproperty string QtQuick2::TextInput::displayText
1721 This is the text displayed in the TextInput.
1723 If \l echoMode is set to TextInput::Normal, this holds the
1724 same value as the TextInput::text property. Otherwise,
1725 this property holds the text visible to the user, while
1726 the \l text property holds the actual entered text.
1728 QString QQuickTextInput::displayText() const
1730 Q_D(const QQuickTextInput);
1731 return d->m_textLayout.text();
1735 \qmlproperty bool QtQuick2::TextInput::selectByMouse
1739 If true, the user can use the mouse to select text in some
1740 platform-specific way. Note that for some platforms this may
1741 not be an appropriate interaction (eg. may conflict with how
1742 the text needs to behave inside a Flickable.
1744 bool QQuickTextInput::selectByMouse() const
1746 Q_D(const QQuickTextInput);
1747 return d->selectByMouse;
1750 void QQuickTextInput::setSelectByMouse(bool on)
1752 Q_D(QQuickTextInput);
1753 if (d->selectByMouse != on) {
1754 d->selectByMouse = on;
1755 emit selectByMouseChanged(on);
1760 \qmlproperty enum QtQuick2::TextInput::mouseSelectionMode
1762 Specifies how text should be selected using a mouse.
1765 \o TextInput.SelectCharacters - The selection is updated with individual characters. (Default)
1766 \o TextInput.SelectWords - The selection is updated with whole words.
1769 This property only applies when \l selectByMouse is true.
1772 QQuickTextInput::SelectionMode QQuickTextInput::mouseSelectionMode() const
1774 Q_D(const QQuickTextInput);
1775 return d->mouseSelectionMode;
1778 void QQuickTextInput::setMouseSelectionMode(SelectionMode mode)
1780 Q_D(QQuickTextInput);
1781 if (d->mouseSelectionMode != mode) {
1782 d->mouseSelectionMode = mode;
1783 emit mouseSelectionModeChanged(mode);
1788 \qmlproperty bool QtQuick2::TextInput::canPaste
1790 Returns true if the TextInput is writable and the content of the clipboard is
1791 suitable for pasting into the TextEdit.
1793 bool QQuickTextInput::canPaste() const
1795 Q_D(const QQuickTextInput);
1799 void QQuickTextInput::moveCursorSelection(int position)
1801 Q_D(QQuickTextInput);
1802 d->moveCursor(position, true);
1806 \qmlmethod void QtQuick2::TextInput::moveCursorSelection(int position, SelectionMode mode = TextInput.SelectCharacters)
1808 Moves the cursor to \a position and updates the selection according to the optional \a mode
1809 parameter. (To only move the cursor, set the \l cursorPosition property.)
1811 When this method is called it additionally sets either the
1812 selectionStart or the selectionEnd (whichever was at the previous cursor position)
1813 to the specified position. This allows you to easily extend and contract the selected
1816 The selection mode specifies whether the selection is updated on a per character or a per word
1817 basis. If not specified the selection mode will default to TextInput.SelectCharacters.
1820 \o TextEdit.SelectCharacters - Sets either the selectionStart or selectionEnd (whichever was at
1821 the previous cursor position) to the specified position.
1822 \o TextEdit.SelectWords - Sets the selectionStart and selectionEnd to include all
1823 words between the specified position and the previous cursor position. Words partially in the
1827 For example, take this sequence of calls:
1831 moveCursorSelection(9, TextInput.SelectCharacters)
1832 moveCursorSelection(7, TextInput.SelectCharacters)
1835 This moves the cursor to position 5, extend the selection end from 5 to 9
1836 and then retract the selection end from 9 to 7, leaving the text from position 5 to 7
1837 selected (the 6th and 7th characters).
1839 The same sequence with TextInput.SelectWords will extend the selection start to a word boundary
1840 before or on position 5 and extend the selection end to a word boundary on or past position 9.
1842 void QQuickTextInput::moveCursorSelection(int pos, SelectionMode mode)
1844 Q_D(QQuickTextInput);
1846 if (mode == SelectCharacters) {
1847 d->moveCursor(pos, true);
1848 } else if (pos != d->m_cursor){
1849 const int cursor = d->m_cursor;
1851 if (!d->hasSelectedText())
1852 anchor = d->m_cursor;
1853 else if (d->selectionStart() == d->m_cursor)
1854 anchor = d->selectionEnd();
1856 anchor = d->selectionStart();
1858 if (anchor < pos || (anchor == pos && cursor < pos)) {
1859 const QString text = this->text();
1860 QTextBoundaryFinder finder(QTextBoundaryFinder::Word, text);
1861 finder.setPosition(anchor);
1863 const QTextBoundaryFinder::BoundaryReasons reasons = finder.boundaryReasons();
1864 if (anchor < text.length() && (!(reasons & QTextBoundaryFinder::StartWord)
1865 || ((reasons & QTextBoundaryFinder::EndWord) && anchor > cursor))) {
1866 finder.toPreviousBoundary();
1868 anchor = finder.position() != -1 ? finder.position() : 0;
1870 finder.setPosition(pos);
1871 if (pos > 0 && !finder.boundaryReasons())
1872 finder.toNextBoundary();
1873 const int cursor = finder.position() != -1 ? finder.position() : text.length();
1875 d->setSelection(anchor, cursor - anchor);
1876 } else if (anchor > pos || (anchor == pos && cursor > pos)) {
1877 const QString text = this->text();
1878 QTextBoundaryFinder finder(QTextBoundaryFinder::Word, text);
1879 finder.setPosition(anchor);
1881 const QTextBoundaryFinder::BoundaryReasons reasons = finder.boundaryReasons();
1882 if (anchor > 0 && (!(reasons & QTextBoundaryFinder::EndWord)
1883 || ((reasons & QTextBoundaryFinder::StartWord) && anchor < cursor))) {
1884 finder.toNextBoundary();
1887 anchor = finder.position() != -1 ? finder.position() : text.length();
1889 finder.setPosition(pos);
1890 if (pos < text.length() && !finder.boundaryReasons())
1891 finder.toPreviousBoundary();
1892 const int cursor = finder.position() != -1 ? finder.position() : 0;
1894 d->setSelection(anchor, cursor - anchor);
1900 \qmlmethod void QtQuick2::TextInput::openSoftwareInputPanel()
1902 Opens software input panels like virtual keyboards for typing, useful for
1903 customizing when you want the input keyboard to be shown and hidden in
1906 By default the opening of input panels follows the platform style. Input panels are
1907 always closed if no editor has active focus.
1909 You can disable the automatic behavior by setting the property \c activeFocusOnPress to false
1910 and use functions openSoftwareInputPanel() and closeSoftwareInputPanel() to implement
1911 the behavior you want.
1913 Only relevant on platforms, which provide virtual keyboards.
1919 text: "Hello world!"
1920 activeFocusOnPress: false
1922 anchors.fill: parent
1924 if (!textInput.activeFocus) {
1925 textInput.forceActiveFocus()
1926 textInput.openSoftwareInputPanel();
1928 textInput.focus = false;
1931 onPressAndHold: textInput.closeSoftwareInputPanel();
1936 void QQuickTextInput::openSoftwareInputPanel()
1939 qGuiApp->inputPanel()->show();
1943 \qmlmethod void QtQuick2::TextInput::closeSoftwareInputPanel()
1945 Closes a software input panel like a virtual keyboard shown on the screen, useful
1946 for customizing when you want the input keyboard to be shown and hidden in
1949 By default the opening of input panels follows the platform style. Input panels are
1950 always closed if no editor has active focus.
1952 You can disable the automatic behavior by setting the property \c activeFocusOnPress to false
1953 and use functions openSoftwareInputPanel() and closeSoftwareInputPanel() to implement
1954 the behavior you want.
1956 Only relevant on platforms, which provide virtual keyboards.
1962 text: "Hello world!"
1963 activeFocusOnPress: false
1965 anchors.fill: parent
1967 if (!textInput.activeFocus) {
1968 textInput.forceActiveFocus();
1969 textInput.openSoftwareInputPanel();
1971 textInput.focus = false;
1974 onPressAndHold: textInput.closeSoftwareInputPanel();
1979 void QQuickTextInput::closeSoftwareInputPanel()
1982 qGuiApp->inputPanel()->hide();
1985 void QQuickTextInput::focusInEvent(QFocusEvent *event)
1987 Q_D(const QQuickTextInput);
1988 if (d->focusOnPress && !d->m_readOnly)
1989 openSoftwareInputPanel();
1990 QQuickImplicitSizeItem::focusInEvent(event);
1993 void QQuickTextInput::itemChange(ItemChange change, const ItemChangeData &value)
1995 Q_D(QQuickTextInput);
1996 if (change == ItemActiveFocusHasChanged) {
1997 bool hasFocus = value.boolValue;
1998 d->focused = hasFocus;
1999 setCursorVisible(hasFocus); // ### refactor: && d->canvas && d->canvas->hasFocus()
2000 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
2001 if (!hasFocus && (d->m_passwordEchoEditing || d->m_passwordEchoTimer.isActive())) {
2003 if (!hasFocus && d->m_passwordEchoEditing) {
2005 d->updatePasswordEchoEditing(false);//QQuickTextInputPrivate sets it on key events, but doesn't deal with focus events
2013 QQuickItem::itemChange(change, value);
2017 \qmlproperty bool QtQuick2::TextInput::inputMethodComposing
2020 This property holds whether the TextInput has partial text input from an
2023 While it is composing an input method may rely on mouse or key events from
2024 the TextInput to edit or commit the partial text. This property can be
2025 used to determine when to disable events handlers that may interfere with
2026 the correct operation of an input method.
2028 bool QQuickTextInput::isInputMethodComposing() const
2030 Q_D(const QQuickTextInput);
2031 return d->preeditAreaText().length() > 0;
2034 void QQuickTextInputPrivate::init()
2036 Q_Q(QQuickTextInput);
2037 q->setSmooth(smooth);
2038 q->setAcceptedMouseButtons(Qt::LeftButton);
2039 q->setFlag(QQuickItem::ItemAcceptsInputMethod);
2040 q->setFlag(QQuickItem::ItemHasContents);
2041 #ifndef QT_NO_CLIPBOARD
2042 q->connect(q, SIGNAL(readOnlyChanged(bool)),
2043 q, SLOT(q_canPasteChanged()));
2044 q->connect(QGuiApplication::clipboard(), SIGNAL(dataChanged()),
2045 q, SLOT(q_canPasteChanged()));
2046 canPaste = !m_readOnly && QGuiApplication::clipboard()->text().length() != 0;
2047 #endif // QT_NO_CLIPBOARD
2048 m_textLayout.beginLayout();
2049 m_textLayout.createLine();
2050 m_textLayout.endLayout();
2052 imHints &= ~Qt::ImhMultiLine;
2053 oldValidity = hasAcceptableInput(m_text);
2054 lastSelectionStart = 0;
2055 lastSelectionEnd = 0;
2056 selectedTextColor = m_palette.color(QPalette::HighlightedText);
2057 selectionColor = m_palette.color(QPalette::Highlight);
2058 determineHorizontalAlignment();
2060 if (!qmlDisableDistanceField()) {
2061 QTextOption option = m_textLayout.textOption();
2062 option.setUseDesignMetrics(true);
2063 m_textLayout.setTextOption(option);
2067 void QQuickTextInput::updateCursorRectangle()
2069 Q_D(QQuickTextInput);
2070 if (!isComponentComplete())
2073 d->updateHorizontalScroll();
2074 d->updateVerticalScroll();
2077 emit cursorRectangleChanged();
2078 if (d->cursorItem) {
2079 QRectF r = cursorRectangle();
2080 d->cursorItem->setPos(r.topLeft());
2081 d->cursorItem->setHeight(r.height());
2085 void QQuickTextInput::selectionChanged()
2087 Q_D(QQuickTextInput);
2088 updateRect();//TODO: Only update rect in selection
2089 emit selectedTextChanged();
2091 if (d->lastSelectionStart != d->selectionStart()) {
2092 d->lastSelectionStart = d->selectionStart();
2093 if (d->lastSelectionStart == -1)
2094 d->lastSelectionStart = d->m_cursor;
2095 emit selectionStartChanged();
2097 if (d->lastSelectionEnd != d->selectionEnd()) {
2098 d->lastSelectionEnd = d->selectionEnd();
2099 if (d->lastSelectionEnd == -1)
2100 d->lastSelectionEnd = d->m_cursor;
2101 emit selectionEndChanged();
2105 void QQuickTextInputPrivate::showCursor()
2107 if (textNode != 0 && textNode->cursorNode() != 0)
2108 textNode->cursorNode()->setColor(color);
2111 void QQuickTextInputPrivate::hideCursor()
2113 if (textNode != 0 && textNode->cursorNode() != 0)
2114 textNode->cursorNode()->setColor(QColor(0, 0, 0, 0));
2117 void QQuickTextInput::updateRect(const QRect &r)
2119 Q_D(QQuickTextInput);
2120 if (!isComponentComplete())
2124 d->textLayoutDirty = true;
2130 QRectF QQuickTextInput::boundingRect() const
2132 Q_D(const QQuickTextInput);
2134 QRectF r = d->boundingRect;
2135 int cursorWidth = d->cursorItem ? d->cursorItem->width() : d->m_cursorWidth;
2137 // Could include font max left/right bearings to either side of rectangle.
2139 r.setRight(r.right() + cursorWidth);
2140 r.translate(-d->hscroll, -d->vscroll);
2144 void QQuickTextInput::q_canPasteChanged()
2146 Q_D(QQuickTextInput);
2147 bool old = d->canPaste;
2148 #ifndef QT_NO_CLIPBOARD
2149 d->canPaste = !d->m_readOnly && QGuiApplication::clipboard()->text().length() != 0;
2151 if (d->canPaste != old)
2152 emit canPasteChanged();
2155 // ### these should come from QStyleHints
2156 const int textCursorWidth = 1;
2157 const bool fullWidthSelection = true;
2162 Updates the display text based of the current edit text
2163 If the text has changed will emit displayTextChanged()
2165 void QQuickTextInputPrivate::updateDisplayText(bool forceUpdate)
2167 QString orig = m_textLayout.text();
2169 if (m_echoMode == QQuickTextInput::NoEcho)
2170 str = QString::fromLatin1("");
2174 if (m_echoMode == QQuickTextInput::Password) {
2175 str.fill(m_passwordCharacter);
2176 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
2177 if (m_passwordEchoTimer.isActive() && m_cursor > 0 && m_cursor <= m_text.length()) {
2178 int cursor = m_cursor - 1;
2179 QChar uc = m_text.at(cursor);
2181 if (cursor > 0 && uc.unicode() >= 0xdc00 && uc.unicode() < 0xe000) {
2182 // second half of a surrogate, check if we have the first half as well,
2183 // if yes restore both at once
2184 uc = m_text.at(cursor - 1);
2185 if (uc.unicode() >= 0xd800 && uc.unicode() < 0xdc00)
2186 str[cursor - 1] = uc;
2190 } else if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit && !m_passwordEchoEditing) {
2191 str.fill(m_passwordCharacter);
2194 // replace certain non-printable characters with spaces (to avoid
2195 // drawing boxes when using fonts that don't have glyphs for such
2197 QChar* uc = str.data();
2198 for (int i = 0; i < (int)str.length(); ++i) {
2199 if ((uc[i] < 0x20 && uc[i] != 0x09)
2200 || uc[i] == QChar::LineSeparator
2201 || uc[i] == QChar::ParagraphSeparator
2202 || uc[i] == QChar::ObjectReplacementCharacter)
2203 uc[i] = QChar(0x0020);
2206 if (str != orig || forceUpdate) {
2207 m_textLayout.setText(str);
2208 updateLayout(); // polish?
2209 emit q_func()->displayTextChanged();
2213 void QQuickTextInputPrivate::updateLayout()
2215 Q_Q(QQuickTextInput);
2217 if (!q->isComponentComplete())
2220 QTextOption option = m_textLayout.textOption();
2221 option.setTextDirection(m_layoutDirection);
2222 option.setFlags(QTextOption::IncludeTrailingSpaces);
2223 option.setWrapMode(QTextOption::WrapMode(wrapMode));
2224 option.setAlignment(Qt::Alignment(q->effectiveHAlign()));
2225 m_textLayout.setTextOption(option);
2226 m_textLayout.setFont(font);
2228 boundingRect = QRectF();
2229 m_textLayout.beginLayout();
2230 QTextLine line = m_textLayout.createLine();
2231 qreal lineWidth = q->widthValid() ? q->width() : INT_MAX;
2233 QTextLine firstLine = line;
2235 line.setLineWidth(lineWidth);
2236 line.setPosition(QPointF(line.position().x(), height));
2237 boundingRect = boundingRect.united(line.naturalTextRect());
2239 height += line.height();
2240 line = m_textLayout.createLine();
2241 } while (line.isValid());
2242 m_textLayout.endLayout();
2244 option.setWrapMode(QTextOption::NoWrap);
2245 m_textLayout.setTextOption(option);
2247 m_ascent = qRound(firstLine.ascent());
2248 textLayoutDirty = true;
2251 q->setImplicitSize(qCeil(boundingRect.width()), qCeil(boundingRect.height()));
2255 #ifndef QT_NO_CLIPBOARD
2259 Copies the currently selected text into the clipboard using the given
2262 \note If the echo mode is set to a mode other than Normal then copy
2263 will not work. This is to prevent using copy as a method of bypassing
2264 password features of the line control.
2266 void QQuickTextInputPrivate::copy(QClipboard::Mode mode) const
2268 QString t = selectedText();
2269 if (!t.isEmpty() && m_echoMode == QQuickTextInput::Normal) {
2270 QGuiApplication::clipboard()->setText(t, mode);
2277 Inserts the text stored in the application clipboard into the line
2282 void QQuickTextInputPrivate::paste(QClipboard::Mode clipboardMode)
2284 QString clip = QGuiApplication::clipboard()->text(clipboardMode);
2285 if (!clip.isEmpty() || hasSelectedText()) {
2286 separate(); //make it a separate undo/redo command
2292 #endif // !QT_NO_CLIPBOARD
2297 Exits preedit mode and commits parts marked as tentative commit
2299 void QQuickTextInputPrivate::commitPreedit()
2304 qApp->inputPanel()->reset();
2306 if (!m_tentativeCommit.isEmpty()) {
2307 internalInsert(m_tentativeCommit);
2308 m_tentativeCommit.clear();
2309 finishChange(-1, true/*not used, not documented*/, false);
2312 m_preeditCursor = 0;
2313 m_textLayout.setPreeditArea(-1, QString());
2314 m_textLayout.clearAdditionalFormats();
2321 Handles the behavior for the backspace key or function.
2322 Removes the current selection if there is a selection, otherwise
2323 removes the character prior to the cursor position.
2327 void QQuickTextInputPrivate::backspace()
2329 int priorState = m_undoState;
2330 if (hasSelectedText()) {
2331 removeSelectedText();
2332 } else if (m_cursor) {
2335 m_cursor = prevMaskBlank(m_cursor);
2336 QChar uc = m_text.at(m_cursor);
2337 if (m_cursor > 0 && uc.unicode() >= 0xdc00 && uc.unicode() < 0xe000) {
2338 // second half of a surrogate, check if we have the first half as well,
2339 // if yes delete both at once
2340 uc = m_text.at(m_cursor - 1);
2341 if (uc.unicode() >= 0xd800 && uc.unicode() < 0xdc00) {
2342 internalDelete(true);
2346 internalDelete(true);
2348 finishChange(priorState);
2354 Handles the behavior for the delete key or function.
2355 Removes the current selection if there is a selection, otherwise
2356 removes the character after the cursor position.
2360 void QQuickTextInputPrivate::del()
2362 int priorState = m_undoState;
2363 if (hasSelectedText()) {
2364 removeSelectedText();
2366 int n = m_textLayout.nextCursorPosition(m_cursor) - m_cursor;
2370 finishChange(priorState);
2376 Inserts the given \a newText at the current cursor position.
2377 If there is any selected text it is removed prior to insertion of
2380 void QQuickTextInputPrivate::insert(const QString &newText)
2382 int priorState = m_undoState;
2383 removeSelectedText();
2384 internalInsert(newText);
2385 finishChange(priorState);
2391 Clears the line control text.
2393 void QQuickTextInputPrivate::clear()
2395 int priorState = m_undoState;
2397 m_selend = m_text.length();
2398 removeSelectedText();
2400 finishChange(priorState, /*update*/false, /*edited*/false);
2406 Sets \a length characters from the given \a start position as selected.
2407 The given \a start position must be within the current text for
2408 the line control. If \a length characters cannot be selected, then
2409 the selection will extend to the end of the current text.
2411 void QQuickTextInputPrivate::setSelection(int start, int length)
2413 Q_Q(QQuickTextInput);
2416 if (start < 0 || start > (int)m_text.length()){
2417 qWarning("QQuickTextInputPrivate::setSelection: Invalid start position");
2422 if (start == m_selstart && start + length == m_selend && m_cursor == m_selend)
2425 m_selend = qMin(start + length, (int)m_text.length());
2426 m_cursor = m_selend;
2427 } else if (length < 0){
2428 if (start == m_selend && start + length == m_selstart && m_cursor == m_selstart)
2430 m_selstart = qMax(start + length, 0);
2432 m_cursor = m_selstart;
2433 } else if (m_selstart != m_selend) {
2439 emitCursorPositionChanged();
2442 emit q->selectionChanged();
2443 emitCursorPositionChanged();
2449 Initializes the line control with a starting text value of \a txt.
2451 void QQuickTextInputPrivate::init(const QString &txt)
2455 updateDisplayText();
2456 m_cursor = m_text.length();
2462 Sets the password echo editing to \a editing. If password echo editing
2463 is true, then the text of the password is displayed even if the echo
2464 mode is set to QLineEdit::PasswordEchoOnEdit. Password echoing editing
2465 does not affect other echo modes.
2467 void QQuickTextInputPrivate::updatePasswordEchoEditing(bool editing)
2469 cancelPasswordEchoTimer();
2470 m_passwordEchoEditing = editing;
2471 updateDisplayText();
2477 Fixes the current text so that it is valid given any set validators.
2479 Returns true if the text was changed. Otherwise returns false.
2481 bool QQuickTextInputPrivate::fixup() // this function assumes that validate currently returns != Acceptable
2483 #ifndef QT_NO_VALIDATOR
2485 QString textCopy = m_text;
2486 int cursorCopy = m_cursor;
2487 m_validator->fixup(textCopy);
2488 if (m_validator->validate(textCopy, cursorCopy) == QValidator::Acceptable) {
2489 if (textCopy != m_text || cursorCopy != m_cursor)
2490 internalSetText(textCopy, cursorCopy);
2501 Moves the cursor to the given position \a pos. If \a mark is true will
2502 adjust the currently selected text.
2504 void QQuickTextInputPrivate::moveCursor(int pos, bool mark)
2506 Q_Q(QQuickTextInput);
2509 if (pos != m_cursor) {
2512 pos = pos > m_cursor ? nextMaskBlank(pos) : prevMaskBlank(pos);
2516 if (m_selend > m_selstart && m_cursor == m_selstart)
2518 else if (m_selend > m_selstart && m_cursor == m_selend)
2519 anchor = m_selstart;
2522 m_selstart = qMin(anchor, pos);
2523 m_selend = qMax(anchor, pos);
2528 if (mark || m_selDirty) {
2530 emit q->selectionChanged();
2532 emitCursorPositionChanged();
2538 Applies the given input method event \a event to the text of the line
2541 void QQuickTextInputPrivate::processInputMethodEvent(QInputMethodEvent *event)
2543 Q_Q(QQuickTextInput);
2545 int priorState = -1;
2546 bool isGettingInput = !event->commitString().isEmpty()
2547 || event->preeditString() != preeditAreaText()
2548 || event->replacementLength() > 0;
2549 bool cursorPositionChanged = false;
2550 bool selectionChange = false;
2551 m_preeditDirty = event->preeditString() != preeditAreaText();
2553 if (isGettingInput) {
2554 // If any text is being input, remove selected text.
2555 priorState = m_undoState;
2556 if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit && !m_passwordEchoEditing) {
2557 updatePasswordEchoEditing(true);
2559 m_selend = m_text.length();
2561 removeSelectedText();
2564 int c = m_cursor; // cursor position after insertion of commit string
2565 if (event->replacementStart() <= 0)
2566 c += event->commitString().length() - qMin(-event->replacementStart(), event->replacementLength());
2568 m_cursor += event->replacementStart();
2572 // insert commit string
2573 if (event->replacementLength()) {
2574 m_selstart = m_cursor;
2575 m_selend = m_selstart + event->replacementLength();
2576 m_selend = qMin(m_selend, m_text.length());
2577 removeSelectedText();
2579 if (!event->commitString().isEmpty()) {
2580 internalInsert(event->commitString());
2581 cursorPositionChanged = true;
2584 m_cursor = qBound(0, c, m_text.length());
2586 for (int i = 0; i < event->attributes().size(); ++i) {
2587 const QInputMethodEvent::Attribute &a = event->attributes().at(i);
2588 if (a.type == QInputMethodEvent::Selection) {
2589 m_cursor = qBound(0, a.start + a.length, m_text.length());
2591 m_selstart = qMax(0, qMin(a.start, m_text.length()));
2592 m_selend = m_cursor;
2593 if (m_selend < m_selstart) {
2594 qSwap(m_selstart, m_selend);
2596 selectionChange = true;
2598 m_selstart = m_selend = 0;
2600 cursorPositionChanged = true;
2604 m_textLayout.setPreeditArea(m_cursor, event->preeditString());
2606 const int oldPreeditCursor = m_preeditCursor;
2607 m_preeditCursor = event->preeditString().length();
2608 m_hideCursor = false;
2609 QList<QTextLayout::FormatRange> formats;
2610 for (int i = 0; i < event->attributes().size(); ++i) {
2611 const QInputMethodEvent::Attribute &a = event->attributes().at(i);
2612 if (a.type == QInputMethodEvent::Cursor) {
2613 m_preeditCursor = a.start;
2614 m_hideCursor = !a.length;
2615 } else if (a.type == QInputMethodEvent::TextFormat) {
2616 QTextCharFormat f = qvariant_cast<QTextFormat>(a.value).toCharFormat();
2618 QTextLayout::FormatRange o;
2619 o.start = a.start + m_cursor;
2620 o.length = a.length;
2626 m_textLayout.setAdditionalFormats(formats);
2628 updateDisplayText(/*force*/ true);
2629 if (cursorPositionChanged)
2630 emitCursorPositionChanged();
2631 else if (m_preeditCursor != oldPreeditCursor)
2632 q->updateCursorRectangle();
2634 bool tentativeCommitChanged = m_tentativeCommit != event->tentativeCommitString();
2636 if (tentativeCommitChanged) {
2638 m_tentativeCommit = event->tentativeCommitString();
2641 if (isGettingInput || tentativeCommitChanged)
2642 finishChange(priorState);
2644 if (selectionChange)
2645 emit q->selectionChanged();
2651 Sets the selection to cover the word at the given cursor position.
2652 The word boundaries are defined by the behavior of QTextLayout::SkipWords
2655 void QQuickTextInputPrivate::selectWordAtPos(int cursor)
2657 int next = cursor + 1;
2660 int c = m_textLayout.previousCursorPosition(next, QTextLayout::SkipWords);
2661 moveCursor(c, false);
2662 // ## text layout should support end of words.
2663 int end = m_textLayout.nextCursorPosition(c, QTextLayout::SkipWords);
2664 while (end > cursor && m_text[end-1].isSpace())
2666 moveCursor(end, true);
2672 Completes a change to the line control text. If the change is not valid
2673 will undo the line control state back to the given \a validateFromState.
2675 If \a edited is true and the change is valid, will emit textEdited() in
2676 addition to textChanged(). Otherwise only emits textChanged() on a valid
2679 The \a update value is currently unused.
2681 bool QQuickTextInputPrivate::finishChange(int validateFromState, bool update, bool /*edited*/)
2683 Q_Q(QQuickTextInput);
2689 bool wasValidInput = m_validInput;
2690 m_validInput = true;
2691 #ifndef QT_NO_VALIDATOR
2693 QString textCopy = m_text;
2694 int cursorCopy = m_cursor;
2695 m_validInput = (m_validator->validate(textCopy, cursorCopy) != QValidator::Invalid);
2697 if (m_text != textCopy) {
2698 internalSetText(textCopy, cursorCopy);
2701 m_cursor = cursorCopy;
2703 if (!m_tentativeCommit.isEmpty()) {
2704 textCopy.insert(m_cursor, m_tentativeCommit);
2705 bool validInput = m_validator->validate(textCopy, cursorCopy) != QValidator::Invalid;
2707 m_tentativeCommit.clear();
2710 m_tentativeCommit.clear();
2714 if (validateFromState >= 0 && wasValidInput && !m_validInput) {
2715 if (m_transactions.count())
2717 internalUndo(validateFromState);
2718 m_history.resize(m_undoState);
2719 if (m_modifiedState > m_undoState)
2720 m_modifiedState = -1;
2721 m_validInput = true;
2722 m_textDirty = false;
2724 updateDisplayText();
2727 m_textDirty = false;
2728 m_preeditDirty = false;
2729 determineHorizontalAlignment();
2730 emit q->textChanged();
2733 if (m_validInput != wasValidInput)
2734 emit q->acceptableInputChanged();
2736 if (m_preeditDirty) {
2737 m_preeditDirty = false;
2738 determineHorizontalAlignment();
2742 emit q->selectionChanged();
2744 emitCursorPositionChanged();
2751 An internal function for setting the text of the line control.
2753 void QQuickTextInputPrivate::internalSetText(const QString &txt, int pos, bool edited)
2755 Q_Q(QQuickTextInput);
2757 QString oldText = m_text;
2759 m_text = maskString(0, txt, true);
2760 m_text += clearString(m_text.length(), m_maxLength - m_text.length());
2762 m_text = txt.isEmpty() ? txt : txt.left(m_maxLength);
2765 m_modifiedState = m_undoState = 0;
2766 m_cursor = (pos < 0 || pos > m_text.length()) ? m_text.length() : pos;
2767 m_textDirty = (oldText != m_text);
2769 bool changed = finishChange(-1, true, edited);
2770 #ifdef QT_NO_ACCESSIBILITY
2774 QAccessible::updateAccessibility(q, 0, QAccessible::TextUpdated);
2782 Adds the given \a command to the undo history
2783 of the line control. Does not apply the command.
2785 void QQuickTextInputPrivate::addCommand(const Command &cmd)
2787 if (m_separator && m_undoState && m_history[m_undoState - 1].type != Separator) {
2788 m_history.resize(m_undoState + 2);
2789 m_history[m_undoState++] = Command(Separator, m_cursor, 0, m_selstart, m_selend);
2791 m_history.resize(m_undoState + 1);
2793 m_separator = false;
2794 m_history[m_undoState++] = cmd;
2800 Inserts the given string \a s into the line
2803 Also adds the appropriate commands into the undo history.
2804 This function does not call finishChange(), and may leave the text
2805 in an invalid state.
2807 void QQuickTextInputPrivate::internalInsert(const QString &s)
2809 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
2810 Q_Q(QQuickTextInput);
2811 if (m_echoMode == QQuickTextInput::Password)
2812 m_passwordEchoTimer.start(qt_passwordEchoDelay, q);
2814 if (hasSelectedText())
2815 addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
2817 QString ms = maskString(m_cursor, s);
2818 for (int i = 0; i < (int) ms.length(); ++i) {
2819 addCommand (Command(DeleteSelection, m_cursor + i, m_text.at(m_cursor + i), -1, -1));
2820 addCommand(Command(Insert, m_cursor + i, ms.at(i), -1, -1));
2822 m_text.replace(m_cursor, ms.length(), ms);
2823 m_cursor += ms.length();
2824 m_cursor = nextMaskBlank(m_cursor);
2827 int remaining = m_maxLength - m_text.length();
2828 if (remaining != 0) {
2829 m_text.insert(m_cursor, s.left(remaining));
2830 for (int i = 0; i < (int) s.left(remaining).length(); ++i)
2831 addCommand(Command(Insert, m_cursor++, s.at(i), -1, -1));
2840 deletes a single character from the current text. If \a wasBackspace,
2841 the character prior to the cursor is removed. Otherwise the character
2842 after the cursor is removed.
2844 Also adds the appropriate commands into the undo history.
2845 This function does not call finishChange(), and may leave the text
2846 in an invalid state.
2848 void QQuickTextInputPrivate::internalDelete(bool wasBackspace)
2850 if (m_cursor < (int) m_text.length()) {
2851 cancelPasswordEchoTimer();
2852 if (hasSelectedText())
2853 addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
2854 addCommand(Command((CommandType)((m_maskData ? 2 : 0) + (wasBackspace ? Remove : Delete)),
2855 m_cursor, m_text.at(m_cursor), -1, -1));
2857 m_text.replace(m_cursor, 1, clearString(m_cursor, 1));
2858 addCommand(Command(Insert, m_cursor, m_text.at(m_cursor), -1, -1));
2860 m_text.remove(m_cursor, 1);
2869 removes the currently selected text from the line control.
2871 Also adds the appropriate commands into the undo history.
2872 This function does not call finishChange(), and may leave the text
2873 in an invalid state.
2875 void QQuickTextInputPrivate::removeSelectedText()
2877 if (m_selstart < m_selend && m_selend <= (int) m_text.length()) {
2878 cancelPasswordEchoTimer();
2881 addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
2882 if (m_selstart <= m_cursor && m_cursor < m_selend) {
2883 // cursor is within the selection. Split up the commands
2884 // to be able to restore the correct cursor position
2885 for (i = m_cursor; i >= m_selstart; --i)
2886 addCommand (Command(DeleteSelection, i, m_text.at(i), -1, 1));
2887 for (i = m_selend - 1; i > m_cursor; --i)
2888 addCommand (Command(DeleteSelection, i - m_cursor + m_selstart - 1, m_text.at(i), -1, -1));
2890 for (i = m_selend-1; i >= m_selstart; --i)
2891 addCommand (Command(RemoveSelection, i, m_text.at(i), -1, -1));
2894 m_text.replace(m_selstart, m_selend - m_selstart, clearString(m_selstart, m_selend - m_selstart));
2895 for (int i = 0; i < m_selend - m_selstart; ++i)
2896 addCommand(Command(Insert, m_selstart + i, m_text.at(m_selstart + i), -1, -1));
2898 m_text.remove(m_selstart, m_selend - m_selstart);
2900 if (m_cursor > m_selstart)
2901 m_cursor -= qMin(m_cursor, m_selend) - m_selstart;
2910 Parses the input mask specified by \a maskFields to generate
2911 the mask data used to handle input masks.
2913 void QQuickTextInputPrivate::parseInputMask(const QString &maskFields)
2915 int delimiter = maskFields.indexOf(QLatin1Char(';'));
2916 if (maskFields.isEmpty() || delimiter == 0) {
2918 delete [] m_maskData;
2920 m_maxLength = 32767;
2921 internalSetText(QString());
2926 if (delimiter == -1) {
2927 m_blank = QLatin1Char(' ');
2928 m_inputMask = maskFields;
2930 m_inputMask = maskFields.left(delimiter);
2931 m_blank = (delimiter + 1 < maskFields.length()) ? maskFields[delimiter + 1] : QLatin1Char(' ');
2934 // calculate m_maxLength / m_maskData length
2937 for (int i=0; i<m_inputMask.length(); i++) {
2938 c = m_inputMask.at(i);
2939 if (i > 0 && m_inputMask.at(i-1) == QLatin1Char('\\')) {
2943 if (c != QLatin1Char('\\') && c != QLatin1Char('!') &&
2944 c != QLatin1Char('<') && c != QLatin1Char('>') &&
2945 c != QLatin1Char('{') && c != QLatin1Char('}') &&
2946 c != QLatin1Char('[') && c != QLatin1Char(']'))
2950 delete [] m_maskData;
2951 m_maskData = new MaskInputData[m_maxLength];
2953 MaskInputData::Casemode m = MaskInputData::NoCaseMode;
2956 bool escape = false;
2958 for (int i = 0; i < m_inputMask.length(); i++) {
2959 c = m_inputMask.at(i);
2962 m_maskData[index].maskChar = c;
2963 m_maskData[index].separator = s;
2964 m_maskData[index].caseMode = m;
2967 } else if (c == QLatin1Char('<')) {
2968 m = MaskInputData::Lower;
2969 } else if (c == QLatin1Char('>')) {
2970 m = MaskInputData::Upper;
2971 } else if (c == QLatin1Char('!')) {
2972 m = MaskInputData::NoCaseMode;
2973 } else if (c != QLatin1Char('{') && c != QLatin1Char('}') && c != QLatin1Char('[') && c != QLatin1Char(']')) {
2974 switch (c.unicode()) {
3000 m_maskData[index].maskChar = c;
3001 m_maskData[index].separator = s;
3002 m_maskData[index].caseMode = m;
3007 internalSetText(m_text);
3014 checks if the key is valid compared to the inputMask
3016 bool QQuickTextInputPrivate::isValidInput(QChar key, QChar mask) const
3018 switch (mask.unicode()) {
3024 if (key.isLetter() || key == m_blank)
3028 if (key.isLetterOrNumber())
3032 if (key.isLetterOrNumber() || key == m_blank)
3040 if (key.isPrint() || key == m_blank)
3048 if (key.isNumber() || key == m_blank)
3052 if (key.isNumber() && key.digitValue() > 0)
3056 if ((key.isNumber() && key.digitValue() > 0) || key == m_blank)
3060 if (key.isNumber() || key == QLatin1Char('+') || key == QLatin1Char('-') || key == m_blank)
3064 if (key == QLatin1Char('0') || key == QLatin1Char('1'))
3068 if (key == QLatin1Char('0') || key == QLatin1Char('1') || key == m_blank)
3072 if (key.isNumber() || (key >= QLatin1Char('a') && key <= QLatin1Char('f')) || (key >= QLatin1Char('A') && key <= QLatin1Char('F')))
3076 if (key.isNumber() || (key >= QLatin1Char('a') && key <= QLatin1Char('f')) || (key >= QLatin1Char('A') && key <= QLatin1Char('F')) || key == m_blank)
3088 Returns true if the given text \a str is valid for any
3089 validator or input mask set for the line control.
3091 Otherwise returns false
3093 bool QQuickTextInputPrivate::hasAcceptableInput(const QString &str) const
3095 #ifndef QT_NO_VALIDATOR
3096 QString textCopy = str;
3097 int cursorCopy = m_cursor;
3098 if (m_validator && m_validator->validate(textCopy, cursorCopy)
3099 != QValidator::Acceptable)
3106 if (str.length() != m_maxLength)
3109 for (int i=0; i < m_maxLength; ++i) {
3110 if (m_maskData[i].separator) {
3111 if (str.at(i) != m_maskData[i].maskChar)
3114 if (!isValidInput(str.at(i), m_maskData[i].maskChar))
3124 Applies the inputMask on \a str starting from position \a pos in the mask. \a clear
3125 specifies from where characters should be gotten when a separator is met in \a str - true means
3126 that blanks will be used, false that previous input is used.
3127 Calling this when no inputMask is set is undefined.
3129 QString QQuickTextInputPrivate::maskString(uint pos, const QString &str, bool clear) const
3131 if (pos >= (uint)m_maxLength)
3132 return QString::fromLatin1("");
3135 fill = clear ? clearString(0, m_maxLength) : m_text;
3138 QString s = QString::fromLatin1("");
3140 while (i < m_maxLength) {
3141 if (strIndex < str.length()) {
3142 if (m_maskData[i].separator) {
3143 s += m_maskData[i].maskChar;
3144 if (str[(int)strIndex] == m_maskData[i].maskChar)
3148 if (isValidInput(str[(int)strIndex], m_maskData[i].maskChar)) {
3149 switch (m_maskData[i].caseMode) {
3150 case MaskInputData::Upper:
3151 s += str[(int)strIndex].toUpper();
3153 case MaskInputData::Lower:
3154 s += str[(int)strIndex].toLower();
3157 s += str[(int)strIndex];
3161 // search for separator first
3162 int n = findInMask(i, true, true, str[(int)strIndex]);
3164 if (str.length() != 1 || i == 0 || (i > 0 && (!m_maskData[i-1].separator || m_maskData[i-1].maskChar != str[(int)strIndex]))) {
3165 s += fill.mid(i, n-i+1);
3166 i = n + 1; // update i to find + 1
3169 // search for valid m_blank if not
3170 n = findInMask(i, true, false, str[(int)strIndex]);
3172 s += fill.mid(i, n-i);
3173 switch (m_maskData[n].caseMode) {
3174 case MaskInputData::Upper:
3175 s += str[(int)strIndex].toUpper();
3177 case MaskInputData::Lower:
3178 s += str[(int)strIndex].toLower();
3181 s += str[(int)strIndex];
3183 i = n + 1; // updates i to find + 1
3201 Returns a "cleared" string with only separators and blank chars.
3202 Calling this when no inputMask is set is undefined.
3204 QString QQuickTextInputPrivate::clearString(uint pos, uint len) const
3206 if (pos >= (uint)m_maxLength)
3210 int end = qMin((uint)m_maxLength, pos + len);
3211 for (int i = pos; i < end; ++i)
3212 if (m_maskData[i].separator)
3213 s += m_maskData[i].maskChar;
3223 Strips blank parts of the input in a QQuickTextInputPrivate when an inputMask is set,
3224 separators are still included. Typically "127.0__.0__.1__" becomes "127.0.0.1".
3226 QString QQuickTextInputPrivate::stripString(const QString &str) const
3232 int end = qMin(m_maxLength, (int)str.length());
3233 for (int i = 0; i < end; ++i)
3234 if (m_maskData[i].separator)
3235 s += m_maskData[i].maskChar;
3237 if (str[i] != m_blank)
3245 searches forward/backward in m_maskData for either a separator or a m_blank
3247 int QQuickTextInputPrivate::findInMask(int pos, bool forward, bool findSeparator, QChar searchChar) const
3249 if (pos >= m_maxLength || pos < 0)
3252 int end = forward ? m_maxLength : -1;
3253 int step = forward ? 1 : -1;
3257 if (findSeparator) {
3258 if (m_maskData[i].separator && m_maskData[i].maskChar == searchChar)
3261 if (!m_maskData[i].separator) {
3262 if (searchChar.isNull())
3264 else if (isValidInput(searchChar, m_maskData[i].maskChar))
3273 void QQuickTextInputPrivate::internalUndo(int until)
3275 if (!isUndoAvailable())
3277 cancelPasswordEchoTimer();
3279 while (m_undoState && m_undoState > until) {
3280 Command& cmd = m_history[--m_undoState];
3283 m_text.remove(cmd.pos, 1);
3287 m_selstart = cmd.selStart;
3288 m_selend = cmd.selEnd;
3292 case RemoveSelection:
3293 m_text.insert(cmd.pos, cmd.uc);
3294 m_cursor = cmd.pos + 1;
3297 case DeleteSelection:
3298 m_text.insert(cmd.pos, cmd.uc);
3304 if (until < 0 && m_undoState) {
3305 Command& next = m_history[m_undoState-1];
3306 if (next.type != cmd.type && next.type < RemoveSelection
3307 && (cmd.type < RemoveSelection || next.type == Separator))
3312 emitCursorPositionChanged();
3315 void QQuickTextInputPrivate::internalRedo()
3317 if (!isRedoAvailable())
3320 while (m_undoState < (int)m_history.size()) {
3321 Command& cmd = m_history[m_undoState++];
3324 m_text.insert(cmd.pos, cmd.uc);
3325 m_cursor = cmd.pos + 1;
3328 m_selstart = cmd.selStart;
3329 m_selend = cmd.selEnd;
3334 case RemoveSelection:
3335 case DeleteSelection:
3336 m_text.remove(cmd.pos, 1);
3337 m_selstart = cmd.selStart;
3338 m_selend = cmd.selEnd;
3342 m_selstart = cmd.selStart;
3343 m_selend = cmd.selEnd;
3347 if (m_undoState < (int)m_history.size()) {
3348 Command& next = m_history[m_undoState];
3349 if (next.type != cmd.type && cmd.type < RemoveSelection && next.type != Separator
3350 && (next.type < RemoveSelection || cmd.type == Separator))
3355 emitCursorPositionChanged();
3361 If the current cursor position differs from the last emitted cursor
3362 position, emits cursorPositionChanged().
3364 void QQuickTextInputPrivate::emitCursorPositionChanged()
3366 Q_Q(QQuickTextInput);
3367 if (m_cursor != m_lastCursorPos) {
3368 m_lastCursorPos = m_cursor;
3370 q->updateCursorRectangle();
3371 emit q->cursorPositionChanged();
3372 // XXX todo - not in 4.8?
3374 resetCursorBlinkTimer();
3377 if (!hasSelectedText()) {
3378 if (lastSelectionStart != m_cursor) {
3379 lastSelectionStart = m_cursor;
3380 emit q->selectionStartChanged();
3382 if (lastSelectionEnd != m_cursor) {
3383 lastSelectionEnd = m_cursor;
3384 emit q->selectionEndChanged();
3388 #ifndef QT_NO_ACCESSIBILITY
3389 QAccessible::updateAccessibility(q, 0, QAccessible::TextCaretMoved);
3395 void QQuickTextInputPrivate::setCursorBlinkPeriod(int msec)
3397 Q_Q(QQuickTextInput);
3398 if (msec == m_blinkPeriod)
3401 q->killTimer(m_blinkTimer);
3404 m_blinkTimer = q->startTimer(msec / 2);
3408 if (m_blinkStatus == 1)
3409 emit q->updateRect(inputMask().isEmpty() ? q->cursorRectangle() : QRect());
3411 m_blinkPeriod = msec;
3414 void QQuickTextInputPrivate::resetCursorBlinkTimer()
3416 Q_Q(QQuickTextInput);
3417 if (m_blinkPeriod == 0 || m_blinkTimer == 0)
3419 q->killTimer(m_blinkTimer);
3420 m_blinkTimer = q->startTimer(m_blinkPeriod / 2);
3424 void QQuickTextInput::timerEvent(QTimerEvent *event)
3426 Q_D(QQuickTextInput);
3427 if (event->timerId() == d->m_blinkTimer) {
3428 d->m_blinkStatus = !d->m_blinkStatus;
3429 updateRect(inputMask().isEmpty() ? cursorRectangle() : QRect());
3430 } else if (event->timerId() == d->m_deleteAllTimer) {
3431 killTimer(d->m_deleteAllTimer);
3432 d->m_deleteAllTimer = 0;
3434 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
3435 } else if (event->timerId() == d->m_passwordEchoTimer.timerId()) {
3436 d->m_passwordEchoTimer.stop();
3437 d->updateDisplayText();
3442 void QQuickTextInputPrivate::processKeyEvent(QKeyEvent* event)
3444 Q_Q(QQuickTextInput);
3445 bool inlineCompletionAccepted = false;
3447 if (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return) {
3448 if (hasAcceptableInput(m_text) || fixup()) {
3451 if (inlineCompletionAccepted)
3458 if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit
3459 && !m_passwordEchoEditing
3461 && !event->text().isEmpty()
3462 && !(event->modifiers() & Qt::ControlModifier)) {
3463 // Clear the edit and reset to normal echo mode while editing; the
3464 // echo mode switches back when the edit loses focus
3465 // ### resets current content. dubious code; you can
3466 // navigate with keys up, down, back, and select(?), but if you press
3467 // "left" or "right" it clears?
3468 updatePasswordEchoEditing(true);
3472 bool unknown = false;
3473 bool visual = cursorMoveStyle() == Qt::VisualMoveStyle;
3477 #ifndef QT_NO_SHORTCUT
3478 else if (event == QKeySequence::Undo) {
3482 else if (event == QKeySequence::Redo) {
3486 else if (event == QKeySequence::SelectAll) {
3489 #ifndef QT_NO_CLIPBOARD
3490 else if (event == QKeySequence::Copy) {
3493 else if (event == QKeySequence::Paste) {
3495 QClipboard::Mode mode = QClipboard::Clipboard;
3499 else if (event == QKeySequence::Cut) {
3505 else if (event == QKeySequence::DeleteEndOfLine) {
3507 setSelection(m_cursor, end());
3512 #endif //QT_NO_CLIPBOARD
3513 else if (event == QKeySequence::MoveToStartOfLine || event == QKeySequence::MoveToStartOfBlock) {
3516 else if (event == QKeySequence::MoveToEndOfLine || event == QKeySequence::MoveToEndOfBlock) {
3519 else if (event == QKeySequence::SelectStartOfLine || event == QKeySequence::SelectStartOfBlock) {
3522 else if (event == QKeySequence::SelectEndOfLine || event == QKeySequence::SelectEndOfBlock) {
3525 else if (event == QKeySequence::MoveToNextChar) {
3526 if (hasSelectedText()) {
3527 moveCursor(selectionEnd(), false);
3529 cursorForward(0, visual ? 1 : (layoutDirection() == Qt::LeftToRight ? 1 : -1));
3532 else if (event == QKeySequence::SelectNextChar) {
3533 cursorForward(1, visual ? 1 : (layoutDirection() == Qt::LeftToRight ? 1 : -1));
3535 else if (event == QKeySequence::MoveToPreviousChar) {
3536 if (hasSelectedText()) {
3537 moveCursor(selectionStart(), false);
3539 cursorForward(0, visual ? -1 : (layoutDirection() == Qt::LeftToRight ? -1 : 1));
3542 else if (event == QKeySequence::SelectPreviousChar) {
3543 cursorForward(1, visual ? -1 : (layoutDirection() == Qt::LeftToRight ? -1 : 1));
3545 else if (event == QKeySequence::MoveToNextWord) {
3546 if (m_echoMode == QQuickTextInput::Normal)
3547 layoutDirection() == Qt::LeftToRight ? cursorWordForward(0) : cursorWordBackward(0);
3549 layoutDirection() == Qt::LeftToRight ? end(0) : home(0);
3551 else if (event == QKeySequence::MoveToPreviousWord) {
3552 if (m_echoMode == QQuickTextInput::Normal)
3553 layoutDirection() == Qt::LeftToRight ? cursorWordBackward(0) : cursorWordForward(0);
3554 else if (!m_readOnly) {
3555 layoutDirection() == Qt::LeftToRight ? home(0) : end(0);
3558 else if (event == QKeySequence::SelectNextWord) {
3559 if (m_echoMode == QQuickTextInput::Normal)
3560 layoutDirection() == Qt::LeftToRight ? cursorWordForward(1) : cursorWordBackward(1);
3562 layoutDirection() == Qt::LeftToRight ? end(1) : home(1);
3564 else if (event == QKeySequence::SelectPreviousWord) {
3565 if (m_echoMode == QQuickTextInput::Normal)
3566 layoutDirection() == Qt::LeftToRight ? cursorWordBackward(1) : cursorWordForward(1);
3568 layoutDirection() == Qt::LeftToRight ? home(1) : end(1);
3570 else if (event == QKeySequence::Delete) {
3574 else if (event == QKeySequence::DeleteEndOfWord) {
3576 cursorWordForward(true);
3580 else if (event == QKeySequence::DeleteStartOfWord) {
3582 cursorWordBackward(true);
3586 #endif // QT_NO_SHORTCUT
3588 bool handled = false;
3589 if (event->modifiers() & Qt::ControlModifier) {
3590 switch (event->key()) {
3591 case Qt::Key_Backspace:
3593 cursorWordBackward(true);
3601 } else { // ### check for *no* modifier
3602 switch (event->key()) {
3603 case Qt::Key_Backspace:
3615 if (event->key() == Qt::Key_Direction_L || event->key() == Qt::Key_Direction_R) {
3616 setLayoutDirection((event->key() == Qt::Key_Direction_L) ? Qt::LeftToRight : Qt::RightToLeft);
3620 if (unknown && !m_readOnly) {
3621 QString t = event->text();
3622 if (!t.isEmpty() && t.at(0).isPrint()) {