1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the QtQml module of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** 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"
45 #include "qquicktextutil_p.h"
47 #include <private/qqmlglobal_p.h>
50 #include <QtCore/qcoreapplication.h>
51 #include <QtQml/qqmlinfo.h>
52 #include <QtGui/qevent.h>
53 #include <QTextBoundaryFinder>
54 #include "qquicktextnode_p.h"
55 #include <QtQuick/qsgsimplerectnode.h>
57 #include <QtGui/qstylehints.h>
58 #include <QtGui/qinputmethod.h>
60 #ifndef QT_NO_ACCESSIBILITY
61 #include "qaccessible.h"
66 DEFINE_BOOL_CONFIG_OPTION(qmlDisableDistanceField, QML_DISABLE_DISTANCEFIELD)
69 \qmlclass TextInput QQuickTextInput
70 \inqmlmodule QtQuick 2
71 \ingroup qtquick-visual
72 \ingroup qtquick-input
74 \brief 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();
107 updateCursorRectangle();
108 if (d->cursorComponent && isCursorVisible())
109 QQuickTextUtil::createCursor(d);
113 \qmlproperty string QtQuick2::TextInput::text
115 The text in the TextInput.
117 QString QQuickTextInput::text() const
119 Q_D(const QQuickTextInput);
121 QString content = d->m_text;
122 QString res = d->m_maskData ? d->stripString(content) : content;
123 return (res.isNull() ? QString::fromLatin1("") : res);
126 void QQuickTextInput::setText(const QString &s)
128 Q_D(QQuickTextInput);
133 d->internalSetText(s, -1, false);
138 \qmlproperty enumeration QtQuick2::TextInput::renderType
140 Override the default rendering type for this component.
142 Supported render types are:
144 \li Text.QtRendering - the default
145 \li Text.NativeRendering
148 Select Text.NativeRendering if you prefer text to look native on the target platform and do
149 not require advanced features such as transformation of the text. Using such features in
150 combination with the NativeRendering render type will lend poor and sometimes pixelated
153 QQuickTextInput::RenderType QQuickTextInput::renderType() const
155 Q_D(const QQuickTextInput);
156 return d->renderType;
159 void QQuickTextInput::setRenderType(QQuickTextInput::RenderType renderType)
161 Q_D(QQuickTextInput);
162 if (d->renderType == renderType)
165 d->renderType = renderType;
166 emit renderTypeChanged();
168 if (isComponentComplete())
173 \qmlproperty int QtQuick2::TextInput::length
175 Returns the total number of characters in the TextInput item.
177 If the TextInput has an inputMask the length will include mask characters and may differ
178 from the length of the string returned by the \l text property.
180 This property can be faster than querying the length the \l text property as it doesn't
181 require any copying or conversion of the TextInput's internal string data.
184 int QQuickTextInput::length() const
186 Q_D(const QQuickTextInput);
187 return d->m_text.length();
191 \qmlmethod string QtQuick2::TextInput::getText(int start, int end)
193 Returns the section of text that is between the \a start and \a end positions.
195 If the TextInput has an inputMask the length will include mask characters.
198 QString QQuickTextInput::getText(int start, int end) const
200 Q_D(const QQuickTextInput);
205 return d->m_text.mid(start, end - start);
208 QString QQuickTextInputPrivate::realText() const
210 QString res = m_maskData ? stripString(m_text) : m_text;
211 return (res.isNull() ? QString::fromLatin1("") : res);
215 \qmlproperty string QtQuick2::TextInput::font.family
217 Sets the family name of the font.
219 The family name is case insensitive and may optionally include a foundry name, e.g. "Helvetica [Cronyx]".
220 If the family is available from more than one foundry and the foundry isn't specified, an arbitrary foundry is chosen.
221 If the family isn't available a family will be set using the font matching algorithm.
225 \qmlproperty bool QtQuick2::TextInput::font.bold
227 Sets whether the font weight is bold.
231 \qmlproperty enumeration QtQuick2::TextInput::font.weight
233 Sets the font's weight.
235 The weight can be one of:
238 \li Font.Normal - the default
245 TextInput { text: "Hello"; font.weight: Font.DemiBold }
250 \qmlproperty bool QtQuick2::TextInput::font.italic
252 Sets whether the font has an italic style.
256 \qmlproperty bool QtQuick2::TextInput::font.underline
258 Sets whether the text is underlined.
262 \qmlproperty bool QtQuick2::TextInput::font.strikeout
264 Sets whether the font has a strikeout style.
268 \qmlproperty real QtQuick2::TextInput::font.pointSize
270 Sets the font size in points. The point size must be greater than zero.
274 \qmlproperty int QtQuick2::TextInput::font.pixelSize
276 Sets the font size in pixels.
278 Using this function makes the font device dependent.
279 Use \c pointSize to set the size of the font in a device independent manner.
283 \qmlproperty real QtQuick2::TextInput::font.letterSpacing
285 Sets the letter spacing for the font.
287 Letter spacing changes the default spacing between individual letters in the font.
288 A positive value increases the letter spacing by the corresponding pixels; a negative value decreases the spacing.
292 \qmlproperty real QtQuick2::TextInput::font.wordSpacing
294 Sets the word spacing for the font.
296 Word spacing changes the default spacing between individual words.
297 A positive value increases the word spacing by a corresponding amount of pixels,
298 while a negative value decreases the inter-word spacing accordingly.
302 \qmlproperty enumeration QtQuick2::TextInput::font.capitalization
304 Sets the capitalization for the text.
307 \li Font.MixedCase - This is the normal text rendering option where no capitalization change is applied.
308 \li Font.AllUppercase - This alters the text to be rendered in all uppercase type.
309 \li Font.AllLowercase - This alters the text to be rendered in all lowercase type.
310 \li Font.SmallCaps - This alters the text to be rendered in small-caps type.
311 \li Font.Capitalize - This alters the text to be rendered with the first character of each word as an uppercase character.
315 TextInput { text: "Hello"; font.capitalization: Font.AllLowercase }
319 QFont QQuickTextInput::font() const
321 Q_D(const QQuickTextInput);
322 return d->sourceFont;
325 void QQuickTextInput::setFont(const QFont &font)
327 Q_D(QQuickTextInput);
328 if (d->sourceFont == font)
331 d->sourceFont = font;
332 QFont oldFont = d->font;
334 if (d->font.pointSizeF() != -1) {
336 qreal size = qRound(d->font.pointSizeF()*2.0);
337 d->font.setPointSizeF(size/2.0);
339 if (oldFont != d->font) {
341 updateCursorRectangle();
342 updateInputMethod(Qt::ImCursorRectangle | Qt::ImFont);
344 emit fontChanged(d->sourceFont);
348 \qmlproperty color QtQuick2::TextInput::color
352 QColor QQuickTextInput::color() const
354 Q_D(const QQuickTextInput);
358 void QQuickTextInput::setColor(const QColor &c)
360 Q_D(QQuickTextInput);
363 d->textLayoutDirty = true;
364 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
372 \qmlproperty color QtQuick2::TextInput::selectionColor
374 The text highlight color, used behind selections.
376 QColor QQuickTextInput::selectionColor() const
378 Q_D(const QQuickTextInput);
379 return d->selectionColor;
382 void QQuickTextInput::setSelectionColor(const QColor &color)
384 Q_D(QQuickTextInput);
385 if (d->selectionColor == color)
388 d->selectionColor = color;
389 if (d->hasSelectedText()) {
390 d->textLayoutDirty = true;
391 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
394 emit selectionColorChanged();
397 \qmlproperty color QtQuick2::TextInput::selectedTextColor
399 The highlighted text color, used in selections.
401 QColor QQuickTextInput::selectedTextColor() const
403 Q_D(const QQuickTextInput);
404 return d->selectedTextColor;
407 void QQuickTextInput::setSelectedTextColor(const QColor &color)
409 Q_D(QQuickTextInput);
410 if (d->selectedTextColor == color)
413 d->selectedTextColor = color;
414 if (d->hasSelectedText()) {
415 d->textLayoutDirty = true;
416 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
419 emit selectedTextColorChanged();
423 \qmlproperty enumeration QtQuick2::TextInput::horizontalAlignment
424 \qmlproperty enumeration QtQuick2::TextInput::effectiveHorizontalAlignment
425 \qmlproperty enumeration QtQuick2::TextInput::verticalAlignment
427 Sets the horizontal alignment of the text within the TextInput item's
428 width and height. By default, the text alignment follows the natural alignment
429 of the text, for example text that is read from left to right will be aligned to
432 TextInput does not have vertical alignment, as the natural height is
433 exactly the height of the single line of text. If you set the height
434 manually to something larger, TextInput will always be top aligned
435 vertically. You can use anchors to align it however you want within
438 The valid values for \c horizontalAlignment are \c TextInput.AlignLeft, \c TextInput.AlignRight and
439 \c TextInput.AlignHCenter.
441 Valid values for \c verticalAlignment are \c TextInput.AlignTop (default),
442 \c TextInput.AlignBottom \c TextInput.AlignVCenter.
444 When using the attached property LayoutMirroring::enabled to mirror application
445 layouts, the horizontal alignment of text will also be mirrored. However, the property
446 \c horizontalAlignment will remain unchanged. To query the effective horizontal alignment
447 of TextInput, use the read-only property \c effectiveHorizontalAlignment.
449 QQuickTextInput::HAlignment QQuickTextInput::hAlign() const
451 Q_D(const QQuickTextInput);
455 void QQuickTextInput::setHAlign(HAlignment align)
457 Q_D(QQuickTextInput);
458 bool forceAlign = d->hAlignImplicit && d->effectiveLayoutMirror;
459 d->hAlignImplicit = false;
460 if (d->setHAlign(align, forceAlign) && isComponentComplete()) {
462 updateCursorRectangle();
466 void QQuickTextInput::resetHAlign()
468 Q_D(QQuickTextInput);
469 d->hAlignImplicit = true;
470 if (d->determineHorizontalAlignment() && isComponentComplete()) {
472 updateCursorRectangle();
476 QQuickTextInput::HAlignment QQuickTextInput::effectiveHAlign() const
478 Q_D(const QQuickTextInput);
479 QQuickTextInput::HAlignment effectiveAlignment = d->hAlign;
480 if (!d->hAlignImplicit && d->effectiveLayoutMirror) {
482 case QQuickTextInput::AlignLeft:
483 effectiveAlignment = QQuickTextInput::AlignRight;
485 case QQuickTextInput::AlignRight:
486 effectiveAlignment = QQuickTextInput::AlignLeft;
492 return effectiveAlignment;
495 bool QQuickTextInputPrivate::setHAlign(QQuickTextInput::HAlignment alignment, bool forceAlign)
497 Q_Q(QQuickTextInput);
498 if ((hAlign != alignment || forceAlign) && alignment <= QQuickTextInput::AlignHCenter) { // justify not supported
499 QQuickTextInput::HAlignment oldEffectiveHAlign = q->effectiveHAlign();
501 emit q->horizontalAlignmentChanged(alignment);
502 if (oldEffectiveHAlign != q->effectiveHAlign())
503 emit q->effectiveHorizontalAlignmentChanged();
509 Qt::LayoutDirection QQuickTextInputPrivate::textDirection() const
511 QString text = m_text;
513 text = m_textLayout.preeditAreaText();
515 const QChar *character = text.constData();
516 while (!character->isNull()) {
517 switch (character->direction()) {
519 return Qt::LeftToRight;
523 return Qt::RightToLeft;
529 return Qt::LayoutDirectionAuto;
532 Qt::LayoutDirection QQuickTextInputPrivate::layoutDirection() const
534 Qt::LayoutDirection direction = m_layoutDirection;
535 if (direction == Qt::LayoutDirectionAuto) {
536 direction = textDirection();
537 if (direction == Qt::LayoutDirectionAuto)
538 direction = qApp->inputMethod()->inputDirection();
540 return (direction == Qt::LayoutDirectionAuto) ? Qt::LeftToRight : direction;
543 bool QQuickTextInputPrivate::determineHorizontalAlignment()
545 if (hAlignImplicit) {
546 // if no explicit alignment has been set, follow the natural layout direction of the text
547 Qt::LayoutDirection direction = textDirection();
548 if (direction == Qt::LayoutDirectionAuto)
549 direction = qApp->inputMethod()->inputDirection();
550 return setHAlign(direction == Qt::RightToLeft ? QQuickTextInput::AlignRight : QQuickTextInput::AlignLeft);
555 QQuickTextInput::VAlignment QQuickTextInput::vAlign() const
557 Q_D(const QQuickTextInput);
561 void QQuickTextInput::setVAlign(QQuickTextInput::VAlignment alignment)
563 Q_D(QQuickTextInput);
564 if (alignment == d->vAlign)
566 d->vAlign = alignment;
567 emit verticalAlignmentChanged(d->vAlign);
568 if (isComponentComplete()) {
569 updateCursorRectangle();
574 \qmlproperty enumeration QtQuick2::TextInput::wrapMode
576 Set this property to wrap the text to the TextInput item's width.
577 The text will only wrap if an explicit width has been set.
580 \li TextInput.NoWrap - no wrapping will be performed. If the text contains insufficient newlines, then implicitWidth will exceed a set width.
581 \li TextInput.WordWrap - wrapping is done on word boundaries only. If a word is too long, implicitWidth will exceed a set width.
582 \li TextInput.WrapAnywhere - wrapping is done at any point on a line, even if it occurs in the middle of a word.
583 \li 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.
586 The default is TextInput.NoWrap. If you set a width, consider using TextInput.Wrap.
588 QQuickTextInput::WrapMode QQuickTextInput::wrapMode() const
590 Q_D(const QQuickTextInput);
594 void QQuickTextInput::setWrapMode(WrapMode mode)
596 Q_D(QQuickTextInput);
597 if (mode == d->wrapMode)
601 updateCursorRectangle();
602 emit wrapModeChanged();
605 void QQuickTextInputPrivate::mirrorChange()
607 Q_Q(QQuickTextInput);
608 if (q->isComponentComplete()) {
609 if (!hAlignImplicit && (hAlign == QQuickTextInput::AlignRight || hAlign == QQuickTextInput::AlignLeft)) {
610 q->updateCursorRectangle();
611 emit q->effectiveHorizontalAlignmentChanged();
617 \qmlproperty bool QtQuick2::TextInput::readOnly
619 Sets whether user input can modify the contents of the TextInput.
621 If readOnly is set to true, then user input will not affect the text
622 property. Any bindings or attempts to set the text property will still
625 bool QQuickTextInput::isReadOnly() const
627 Q_D(const QQuickTextInput);
628 return d->m_readOnly;
631 void QQuickTextInput::setReadOnly(bool ro)
633 Q_D(QQuickTextInput);
634 if (d->m_readOnly == ro)
637 setFlag(QQuickItem::ItemAcceptsInputMethod, !ro);
640 d->setCursorPosition(d->end());
641 updateInputMethod(Qt::ImEnabled);
643 d->emitUndoRedoChanged();
644 emit readOnlyChanged(ro);
648 \qmlproperty int QtQuick2::TextInput::maximumLength
649 The maximum permitted length of the text in the TextInput.
651 If the text is too long, it is truncated at the limit.
653 By default, this property contains a value of 32767.
655 int QQuickTextInput::maxLength() const
657 Q_D(const QQuickTextInput);
658 return d->m_maxLength;
661 void QQuickTextInput::setMaxLength(int ml)
663 Q_D(QQuickTextInput);
664 if (d->m_maxLength == ml || d->m_maskData)
668 d->internalSetText(d->m_text, -1, false);
670 emit maximumLengthChanged(ml);
674 \qmlproperty bool QtQuick2::TextInput::cursorVisible
675 Set to true when the TextInput shows a cursor.
677 This property is set and unset when the TextInput gets active focus, so that other
678 properties can be bound to whether the cursor is currently showing. As it
679 gets set and unset automatically, when you set the value yourself you must
680 keep in mind that your value may be overwritten.
682 It can be set directly in script, for example if a KeyProxy might
683 forward keys to it and you desire it to look active when this happens
684 (but without actually giving it active focus).
686 It should not be set directly on the element, like in the below QML,
687 as the specified value will be overridden an lost on focus changes.
696 In the above snippet the cursor will still become visible when the
697 TextInput gains active focus.
699 bool QQuickTextInput::isCursorVisible() const
701 Q_D(const QQuickTextInput);
702 return d->cursorVisible;
705 void QQuickTextInput::setCursorVisible(bool on)
707 Q_D(QQuickTextInput);
708 if (d->cursorVisible == on)
710 d->cursorVisible = on;
711 if (on && isComponentComplete())
712 QQuickTextUtil::createCursor(d);
713 if (!d->cursorItem) {
714 d->setCursorBlinkPeriod(on ? qApp->styleHints()->cursorFlashTime() : 0);
715 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
718 emit cursorVisibleChanged(d->cursorVisible);
722 \qmlproperty int QtQuick2::TextInput::cursorPosition
723 The position of the cursor in the TextInput.
725 int QQuickTextInput::cursorPosition() const
727 Q_D(const QQuickTextInput);
731 void QQuickTextInput::setCursorPosition(int cp)
733 Q_D(QQuickTextInput);
734 if (cp < 0 || cp > text().length())
740 \qmlproperty rectangle QtQuick2::TextInput::cursorRectangle
742 The rectangle where the standard text cursor is rendered within the text input. Read only.
744 The position and height of a custom cursorDelegate are updated to follow the cursorRectangle
745 automatically when it changes. The width of the delegate is unaffected by changes in the
749 QRectF QQuickTextInput::cursorRectangle() const
751 Q_D(const QQuickTextInput);
753 int c = d->m_cursor + d->m_preeditCursor;
754 if (d->m_echoMode == NoEcho)
756 QTextLine l = d->m_textLayout.lineForTextPosition(c);
759 return QRectF(l.cursorToX(c) - d->hscroll, l.y() - d->vscroll, 1, l.height());
763 \qmlproperty int QtQuick2::TextInput::selectionStart
765 The cursor position before the first character in the current selection.
767 This property is read-only. To change the selection, use select(start,end),
768 selectAll(), or selectWord().
770 \sa selectionEnd, cursorPosition, selectedText
772 int QQuickTextInput::selectionStart() const
774 Q_D(const QQuickTextInput);
775 return d->lastSelectionStart;
778 \qmlproperty int QtQuick2::TextInput::selectionEnd
780 The cursor position after the last character in the current selection.
782 This property is read-only. To change the selection, use select(start,end),
783 selectAll(), or selectWord().
785 \sa selectionStart, cursorPosition, selectedText
787 int QQuickTextInput::selectionEnd() const
789 Q_D(const QQuickTextInput);
790 return d->lastSelectionEnd;
793 \qmlmethod void QtQuick2::TextInput::select(int start, int end)
795 Causes the text from \a start to \a end to be selected.
797 If either start or end is out of range, the selection is not changed.
799 After calling this, selectionStart will become the lesser
800 and selectionEnd will become the greater (regardless of the order passed
803 \sa selectionStart, selectionEnd
805 void QQuickTextInput::select(int start, int end)
807 Q_D(QQuickTextInput);
808 if (start < 0 || end < 0 || start > d->m_text.length() || end > d->m_text.length())
810 d->setSelection(start, end-start);
814 \qmlproperty string QtQuick2::TextInput::selectedText
816 This read-only property provides the text currently selected in the
819 It is equivalent to the following snippet, but is faster and easier
823 myTextInput.text.toString().substring(myTextInput.selectionStart,
824 myTextInput.selectionEnd);
827 QString QQuickTextInput::selectedText() const
829 Q_D(const QQuickTextInput);
830 return d->selectedText();
834 \qmlproperty bool QtQuick2::TextInput::activeFocusOnPress
836 Whether the TextInput should gain active focus on a mouse press. By default this is
839 bool QQuickTextInput::focusOnPress() const
841 Q_D(const QQuickTextInput);
842 return d->focusOnPress;
845 void QQuickTextInput::setFocusOnPress(bool b)
847 Q_D(QQuickTextInput);
848 if (d->focusOnPress == b)
853 emit activeFocusOnPressChanged(d->focusOnPress);
856 \qmlproperty bool QtQuick2::TextInput::autoScroll
858 Whether the TextInput should scroll when the text is longer than the width. By default this is
861 bool QQuickTextInput::autoScroll() const
863 Q_D(const QQuickTextInput);
864 return d->autoScroll;
867 void QQuickTextInput::setAutoScroll(bool b)
869 Q_D(QQuickTextInput);
870 if (d->autoScroll == b)
874 //We need to repaint so that the scrolling is taking into account.
875 updateCursorRectangle();
876 emit autoScrollChanged(d->autoScroll);
879 #ifndef QT_NO_VALIDATOR
882 \qmlclass IntValidator QIntValidator
883 \inqmlmodule QtQuick 2
884 \ingroup qtquick-text-utility
885 \brief Defines a validator for integer values
887 This element provides a validator for integer values.
889 If no \l locale is set IntValidator uses the \l {QLocale::setDefault()}{default locale} to
890 interpret the number and will accept locale specific digits, group separators, and positive
891 and negative signs. In addition, IntValidator is always guaranteed to accept a number
892 formatted according to the "C" locale.
896 QQuickIntValidator::QQuickIntValidator(QObject *parent)
897 : QIntValidator(parent)
902 \qmlproperty string QtQuick2::IntValidator::locale
904 This property holds the name of the locale used to interpret the number.
909 QString QQuickIntValidator::localeName() const
911 return locale().name();
914 void QQuickIntValidator::setLocaleName(const QString &name)
916 if (locale().name() != name) {
917 setLocale(QLocale(name));
918 emit localeNameChanged();
922 void QQuickIntValidator::resetLocaleName()
924 QLocale defaultLocale;
925 if (locale() != defaultLocale) {
926 setLocale(defaultLocale);
927 emit localeNameChanged();
932 \qmlproperty int QtQuick2::IntValidator::top
934 This property holds the validator's highest acceptable value.
935 By default, this property's value is derived from the highest signed integer available (typically 2147483647).
938 \qmlproperty int QtQuick2::IntValidator::bottom
940 This property holds the validator's lowest acceptable value.
941 By default, this property's value is derived from the lowest signed integer available (typically -2147483647).
945 \qmlclass DoubleValidator QDoubleValidator
946 \inqmlmodule QtQuick 2
947 \ingroup qtquick-text-utility
948 \brief Defines a validator for non-integer numbers
950 This element provides a validator for non-integer numbers.
952 Input is accepted if it contains a double that is within the valid range
953 and is in the correct format.
955 Input is accepected but invalid if it contains a double that is outside
956 the range or is in the wrong format; e.g. with too many digits after the
957 decimal point or is empty.
959 Input is rejected if it is not a double.
961 Note: If the valid range consists of just positive doubles (e.g. 0.0 to
962 100.0) and input is a negative double then it is rejected. If \l notation
963 is set to DoubleValidator.StandardNotation, and the input contains more
964 digits before the decimal point than a double in the valid range may have,
965 it is also rejected. If \l notation is DoubleValidator.ScientificNotation,
966 and the input is not in the valid range, it is accecpted but invalid. The
967 value may yet become valid by changing the exponent.
970 QQuickDoubleValidator::QQuickDoubleValidator(QObject *parent)
971 : QDoubleValidator(parent)
976 \qmlproperty string QtQuick2::DoubleValidator::locale
978 This property holds the name of the locale used to interpret the number.
983 QString QQuickDoubleValidator::localeName() const
985 return locale().name();
988 void QQuickDoubleValidator::setLocaleName(const QString &name)
990 if (locale().name() != name) {
991 setLocale(QLocale(name));
992 emit localeNameChanged();
996 void QQuickDoubleValidator::resetLocaleName()
998 QLocale defaultLocale;
999 if (locale() != defaultLocale) {
1000 setLocale(defaultLocale);
1001 emit localeNameChanged();
1006 \qmlproperty real QtQuick2::DoubleValidator::top
1008 This property holds the validator's maximum acceptable value.
1009 By default, this property contains a value of infinity.
1012 \qmlproperty real QtQuick2::DoubleValidator::bottom
1014 This property holds the validator's minimum acceptable value.
1015 By default, this property contains a value of -infinity.
1018 \qmlproperty int QtQuick2::DoubleValidator::decimals
1020 This property holds the validator's maximum number of digits after the decimal point.
1021 By default, this property contains a value of 1000.
1024 \qmlproperty enumeration QtQuick2::DoubleValidator::notation
1025 This property holds the notation of how a string can describe a number.
1027 The possible values for this property are:
1030 \li DoubleValidator.StandardNotation
1031 \li DoubleValidator.ScientificNotation (default)
1034 If this property is set to DoubleValidator.ScientificNotation, the written number may have an exponent part (e.g. 1.5E-2).
1038 \qmlclass RegExpValidator QRegExpValidator
1039 \inqmlmodule QtQuick 2
1040 \ingroup qtquick-text-utility
1041 \brief Provides a string validator
1043 This element provides a validator, which counts as valid any string which
1044 matches a specified regular expression.
1047 \qmlproperty regExp QtQuick2::RegExpValidator::regExp
1049 This property holds the regular expression used for validation.
1051 Note that this property should be a regular expression in JS syntax, e.g /a/ for the regular expression
1054 By default, this property contains a regular expression with the pattern .* that matches any string.
1058 \qmlproperty Validator QtQuick2::TextInput::validator
1060 Allows you to set a validator on the TextInput. When a validator is set
1061 the TextInput will only accept input which leaves the text property in
1062 an acceptable or intermediate state. The accepted signal will only be sent
1063 if the text is in an acceptable state when enter is pressed.
1065 Currently supported validators are IntValidator, DoubleValidator and
1066 RegExpValidator. An example of using validators is shown below, which allows
1067 input of integers between 11 and 31 into the text input:
1072 validator: IntValidator{bottom: 11; top: 31;}
1077 \sa acceptableInput, inputMask
1080 QValidator* QQuickTextInput::validator() const
1082 Q_D(const QQuickTextInput);
1083 return d->m_validator;
1086 void QQuickTextInput::setValidator(QValidator* v)
1088 Q_D(QQuickTextInput);
1089 if (d->m_validator == v)
1092 if (d->m_validator) {
1093 qmlobject_disconnect(
1094 d->m_validator, QValidator, SIGNAL(changed()),
1095 this, QQuickTextInput, SLOT(q_validatorChanged()));
1100 if (d->m_validator) {
1102 d->m_validator, QValidator, SIGNAL(changed()),
1103 this, QQuickTextInput, SLOT(q_validatorChanged()));
1106 if (isComponentComplete())
1109 emit validatorChanged();
1112 void QQuickTextInput::q_validatorChanged()
1114 Q_D(QQuickTextInput);
1118 #endif // QT_NO_VALIDATOR
1120 void QQuickTextInputPrivate::checkIsValid()
1122 Q_Q(QQuickTextInput);
1124 ValidatorState state = hasAcceptableInput(m_text);
1125 m_validInput = state != InvalidInput;
1126 if (state != AcceptableInput) {
1127 if (m_acceptableInput) {
1128 m_acceptableInput = false;
1129 emit q->acceptableInputChanged();
1131 } else if (!m_acceptableInput) {
1132 m_acceptableInput = true;
1133 emit q->acceptableInputChanged();
1138 \qmlproperty string QtQuick2::TextInput::inputMask
1140 Allows you to set an input mask on the TextInput, restricting the allowable
1141 text inputs. See QLineEdit::inputMask for further details, as the exact
1142 same mask strings are used by TextInput.
1144 \sa acceptableInput, validator
1146 QString QQuickTextInput::inputMask() const
1148 Q_D(const QQuickTextInput);
1149 return d->inputMask();
1152 void QQuickTextInput::setInputMask(const QString &im)
1154 Q_D(QQuickTextInput);
1155 if (d->inputMask() == im)
1158 d->setInputMask(im);
1159 emit inputMaskChanged(d->inputMask());
1163 \qmlproperty bool QtQuick2::TextInput::acceptableInput
1165 This property is always true unless a validator or input mask has been set.
1166 If a validator or input mask has been set, this property will only be true
1167 if the current text is acceptable to the validator or input mask as a final
1168 string (not as an intermediate string).
1170 bool QQuickTextInput::hasAcceptableInput() const
1172 Q_D(const QQuickTextInput);
1173 return d->hasAcceptableInput(d->m_text) == QQuickTextInputPrivate::AcceptableInput;
1177 \qmlsignal QtQuick2::TextInput::onAccepted()
1179 This handler is called when the Return or Enter key is pressed.
1180 Note that if there is a \l validator or \l inputMask set on the text
1181 input, the handler will only be emitted if the input is in an acceptable
1185 Qt::InputMethodHints QQuickTextInputPrivate::effectiveInputMethodHints() const
1187 Qt::InputMethodHints hints = inputMethodHints;
1188 if (m_echoMode == QQuickTextInput::Password || m_echoMode == QQuickTextInput::NoEcho)
1189 hints |= Qt::ImhHiddenText;
1190 else if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit)
1191 hints &= ~Qt::ImhHiddenText;
1192 if (m_echoMode != QQuickTextInput::Normal)
1193 hints |= (Qt::ImhNoAutoUppercase | Qt::ImhNoPredictiveText | Qt::ImhSensitiveData);
1197 \qmlproperty enumeration QtQuick2::TextInput::echoMode
1199 Specifies how the text should be displayed in the TextInput.
1201 \li TextInput.Normal - Displays the text as it is. (Default)
1202 \li TextInput.Password - Displays asterisks instead of characters.
1203 \li TextInput.NoEcho - Displays nothing.
1204 \li TextInput.PasswordEchoOnEdit - Displays characters as they are entered
1205 while editing, otherwise displays asterisks.
1208 QQuickTextInput::EchoMode QQuickTextInput::echoMode() const
1210 Q_D(const QQuickTextInput);
1211 return QQuickTextInput::EchoMode(d->m_echoMode);
1214 void QQuickTextInput::setEchoMode(QQuickTextInput::EchoMode echo)
1216 Q_D(QQuickTextInput);
1217 if (echoMode() == echo)
1219 d->cancelPasswordEchoTimer();
1220 d->m_echoMode = echo;
1221 d->m_passwordEchoEditing = false;
1222 updateInputMethod(Qt::ImHints);
1223 d->updateDisplayText();
1224 updateCursorRectangle();
1226 emit echoModeChanged(echoMode());
1230 \qmlproperty enumeration QtQuick2::TextInput::inputMethodHints
1232 Provides hints to the input method about the expected content of the text input and how it
1235 The value is a bit-wise combination of flags, or Qt.ImhNone if no hints are set.
1237 Flags that alter behaviour are:
1240 \li Qt.ImhHiddenText - Characters should be hidden, as is typically used when entering passwords.
1241 This is automatically set when setting echoMode to \c TextInput.Password.
1242 \li Qt.ImhSensitiveData - Typed text should not be stored by the active input method
1243 in any persistent storage like predictive user dictionary.
1244 \li Qt.ImhNoAutoUppercase - The input method should not try to automatically switch to upper case
1245 when a sentence ends.
1246 \li Qt.ImhPreferNumbers - Numbers are preferred (but not required).
1247 \li Qt.ImhPreferUppercase - Upper case letters are preferred (but not required).
1248 \li Qt.ImhPreferLowercase - Lower case letters are preferred (but not required).
1249 \li Qt.ImhNoPredictiveText - Do not use predictive text (i.e. dictionary lookup) while typing.
1251 \li Qt.ImhDate - The text editor functions as a date field.
1252 \li Qt.ImhTime - The text editor functions as a time field.
1255 Flags that restrict input (exclusive flags) are:
1258 \li Qt.ImhDigitsOnly - Only digits are allowed.
1259 \li Qt.ImhFormattedNumbersOnly - Only number input is allowed. This includes decimal point and minus sign.
1260 \li Qt.ImhUppercaseOnly - Only upper case letter input is allowed.
1261 \li Qt.ImhLowercaseOnly - Only lower case letter input is allowed.
1262 \li Qt.ImhDialableCharactersOnly - Only characters suitable for phone dialing are allowed.
1263 \li Qt.ImhEmailCharactersOnly - Only characters suitable for email addresses are allowed.
1264 \li Qt.ImhUrlCharactersOnly - Only characters suitable for URLs are allowed.
1270 \li Qt.ImhExclusiveInputMask - This mask yields nonzero if any of the exclusive flags are used.
1274 Qt::InputMethodHints QQuickTextInput::inputMethodHints() const
1276 Q_D(const QQuickTextInput);
1277 return d->inputMethodHints;
1280 void QQuickTextInput::setInputMethodHints(Qt::InputMethodHints hints)
1282 Q_D(QQuickTextInput);
1284 if (hints == d->inputMethodHints)
1287 d->inputMethodHints = hints;
1288 updateInputMethod(Qt::ImHints);
1289 emit inputMethodHintsChanged();
1293 \qmlproperty Component QtQuick2::TextInput::cursorDelegate
1294 The delegate for the cursor in the TextInput.
1296 If you set a cursorDelegate for a TextInput, this delegate will be used for
1297 drawing the cursor instead of the standard cursor. An instance of the
1298 delegate will be created and managed by the TextInput when a cursor is
1299 needed, and the x property of delegate instance will be set so as
1300 to be one pixel before the top left of the current character.
1302 Note that the root item of the delegate component must be a QQuickItem or
1303 QQuickItem derived item.
1305 QQmlComponent* QQuickTextInput::cursorDelegate() const
1307 Q_D(const QQuickTextInput);
1308 return d->cursorComponent;
1311 void QQuickTextInput::setCursorDelegate(QQmlComponent* c)
1313 Q_D(QQuickTextInput);
1314 QQuickTextUtil::setCursorDelegate(d, c);
1317 void QQuickTextInput::createCursor()
1319 Q_D(QQuickTextInput);
1320 d->cursorPending = true;
1321 QQuickTextUtil::createCursor(d);
1325 \qmlmethod rect QtQuick2::TextInput::positionToRectangle(int pos)
1327 This function takes a character position and returns the rectangle that the
1328 cursor would occupy, if it was placed at that character position.
1330 This is similar to setting the cursorPosition, and then querying the cursor
1331 rectangle, but the cursorPosition is not changed.
1333 QRectF QQuickTextInput::positionToRectangle(int pos) const
1335 Q_D(const QQuickTextInput);
1336 if (d->m_echoMode == NoEcho)
1338 else if (pos > d->m_cursor)
1339 pos += d->preeditAreaText().length();
1340 QTextLine l = d->m_textLayout.lineForTextPosition(pos);
1342 ? QRectF(l.cursorToX(pos) - d->hscroll, l.y() - d->vscroll, 1, l.height())
1347 \qmlmethod int QtQuick2::TextInput::positionAt(real x, real y, CursorPosition position = CursorBetweenCharacters)
1349 This function returns the character position at
1350 x and y pixels from the top left of the textInput. Position 0 is before the
1351 first character, position 1 is after the first character but before the second,
1352 and so on until position text.length, which is after all characters.
1354 This means that for all x values before the first character this function returns 0,
1355 and for all x values after the last character this function returns text.length. If
1356 the y value is above the text the position will be that of the nearest character on
1357 the first line line and if it is below the text the position of the nearest character
1358 on the last line will be returned.
1360 The cursor position type specifies how the cursor position should be resolved.
1363 \li TextInput.CursorBetweenCharacters - Returns the position between characters that is nearest x.
1364 \li TextInput.CursorOnCharacter - Returns the position before the character that is nearest x.
1368 void QQuickTextInput::positionAt(QQmlV8Function *args) const
1370 Q_D(const QQuickTextInput);
1374 QTextLine::CursorPosition position = QTextLine::CursorBetweenCharacters;
1376 if (args->Length() < 1)
1380 v8::Local<v8::Value> arg = (*args)[i];
1381 x = arg->NumberValue();
1383 if (++i < args->Length()) {
1385 y = arg->NumberValue();
1388 if (++i < args->Length()) {
1390 position = QTextLine::CursorPosition(arg->Int32Value());
1393 int pos = d->positionAt(x, y, position);
1394 const int cursor = d->m_cursor;
1396 const int preeditLength = d->preeditAreaText().length();
1397 pos = pos > cursor + preeditLength
1398 ? pos - preeditLength
1401 args->returnValue(v8::Int32::New(pos));
1404 int QQuickTextInputPrivate::positionAt(qreal x, qreal y, QTextLine::CursorPosition position) const
1408 QTextLine line = m_textLayout.lineAt(0);
1409 for (int i = 1; i < m_textLayout.lineCount(); ++i) {
1410 QTextLine nextLine = m_textLayout.lineAt(i);
1412 if (y < (line.rect().bottom() + nextLine.y()) / 2)
1416 return line.isValid() ? line.xToCursor(x, position) : 0;
1419 void QQuickTextInput::keyPressEvent(QKeyEvent* ev)
1421 Q_D(QQuickTextInput);
1422 // Don't allow MacOSX up/down support, and we don't allow a completer.
1423 bool ignore = (ev->key() == Qt::Key_Up || ev->key() == Qt::Key_Down) && ev->modifiers() == Qt::NoModifier;
1424 if (!ignore && (d->lastSelectionStart == d->lastSelectionEnd) && (ev->key() == Qt::Key_Right || ev->key() == Qt::Key_Left)) {
1425 // Ignore when moving off the end unless there is a selection,
1426 // because then moving will do something (deselect).
1427 int cursorPosition = d->m_cursor;
1428 if (cursorPosition == 0)
1429 ignore = ev->key() == (d->layoutDirection() == Qt::LeftToRight ? Qt::Key_Left : Qt::Key_Right);
1430 if (!ignore && cursorPosition == text().length())
1431 ignore = ev->key() == (d->layoutDirection() == Qt::LeftToRight ? Qt::Key_Right : Qt::Key_Left);
1436 d->processKeyEvent(ev);
1438 if (!ev->isAccepted())
1439 QQuickImplicitSizeItem::keyPressEvent(ev);
1442 void QQuickTextInput::inputMethodEvent(QInputMethodEvent *ev)
1444 Q_D(QQuickTextInput);
1445 const bool wasComposing = d->hasImState;
1446 if (d->m_readOnly) {
1449 d->processInputMethodEvent(ev);
1451 if (!ev->isAccepted())
1452 QQuickImplicitSizeItem::inputMethodEvent(ev);
1454 if (wasComposing != d->hasImState)
1455 emit inputMethodComposingChanged();
1458 void QQuickTextInput::mouseDoubleClickEvent(QMouseEvent *event)
1460 Q_D(QQuickTextInput);
1462 if (d->selectByMouse && event->button() == Qt::LeftButton) {
1464 int cursor = d->positionAt(event->localPos());
1465 d->selectWordAtPos(cursor);
1466 event->setAccepted(true);
1467 if (!d->hasPendingTripleClick()) {
1468 d->tripleClickStartPoint = event->localPos();
1469 d->tripleClickTimer.start();
1472 if (d->sendMouseEventToInputContext(event))
1474 QQuickImplicitSizeItem::mouseDoubleClickEvent(event);
1478 void QQuickTextInput::mousePressEvent(QMouseEvent *event)
1480 Q_D(QQuickTextInput);
1482 d->pressPos = event->localPos();
1484 if (d->sendMouseEventToInputContext(event))
1487 if (d->selectByMouse) {
1488 setKeepMouseGrab(false);
1489 d->selectPressed = true;
1490 QPointF distanceVector = d->pressPos - d->tripleClickStartPoint;
1491 if (d->hasPendingTripleClick()
1492 && distanceVector.manhattanLength() < qApp->styleHints()->startDragDistance()) {
1493 event->setAccepted(true);
1499 bool mark = (event->modifiers() & Qt::ShiftModifier) && d->selectByMouse;
1500 int cursor = d->positionAt(event->localPos());
1501 d->moveCursor(cursor, mark);
1503 if (d->focusOnPress) {
1504 bool hadActiveFocus = hasActiveFocus();
1506 // re-open input panel on press if already focused
1507 if (hasActiveFocus() && hadActiveFocus && !d->m_readOnly)
1508 qGuiApp->inputMethod()->show();
1511 event->setAccepted(true);
1514 void QQuickTextInput::mouseMoveEvent(QMouseEvent *event)
1516 Q_D(QQuickTextInput);
1518 if (d->selectPressed) {
1519 if (qAbs(int(event->localPos().x() - d->pressPos.x())) > qApp->styleHints()->startDragDistance())
1520 setKeepMouseGrab(true);
1522 if (d->composeMode()) {
1524 int startPos = d->positionAt(d->pressPos);
1525 int currentPos = d->positionAt(event->localPos());
1526 if (startPos != currentPos)
1527 d->setSelection(startPos, currentPos - startPos);
1529 moveCursorSelection(d->positionAt(event->localPos()), d->mouseSelectionMode);
1531 event->setAccepted(true);
1533 QQuickImplicitSizeItem::mouseMoveEvent(event);
1537 void QQuickTextInput::mouseReleaseEvent(QMouseEvent *event)
1539 Q_D(QQuickTextInput);
1540 if (d->sendMouseEventToInputContext(event))
1542 if (d->selectPressed) {
1543 d->selectPressed = false;
1544 setKeepMouseGrab(false);
1546 #ifndef QT_NO_CLIPBOARD
1547 if (QGuiApplication::clipboard()->supportsSelection()) {
1548 if (event->button() == Qt::LeftButton) {
1549 d->copy(QClipboard::Selection);
1550 } else if (!d->m_readOnly && event->button() == Qt::MidButton) {
1552 d->insert(QGuiApplication::clipboard()->text(QClipboard::Selection));
1556 if (!event->isAccepted())
1557 QQuickImplicitSizeItem::mouseReleaseEvent(event);
1560 bool QQuickTextInputPrivate::sendMouseEventToInputContext(QMouseEvent *event)
1562 #if !defined QT_NO_IM
1563 if (composeMode()) {
1564 int tmp_cursor = positionAt(event->localPos());
1565 int mousePos = tmp_cursor - m_cursor;
1566 if (mousePos >= 0 && mousePos <= m_textLayout.preeditAreaText().length()) {
1567 if (event->type() == QEvent::MouseButtonRelease) {
1568 qApp->inputMethod()->invokeAction(QInputMethod::Click, mousePos);
1581 void QQuickTextInput::mouseUngrabEvent()
1583 Q_D(QQuickTextInput);
1584 d->selectPressed = false;
1585 setKeepMouseGrab(false);
1588 bool QQuickTextInput::event(QEvent* ev)
1590 #ifndef QT_NO_SHORTCUT
1591 Q_D(QQuickTextInput);
1592 if (ev->type() == QEvent::ShortcutOverride) {
1595 QKeyEvent* ke = static_cast<QKeyEvent*>(ev);
1596 if (ke == QKeySequence::Copy
1597 || ke == QKeySequence::Paste
1598 || ke == QKeySequence::Cut
1599 || ke == QKeySequence::Redo
1600 || ke == QKeySequence::Undo
1601 || ke == QKeySequence::MoveToNextWord
1602 || ke == QKeySequence::MoveToPreviousWord
1603 || ke == QKeySequence::MoveToStartOfDocument
1604 || ke == QKeySequence::MoveToEndOfDocument
1605 || ke == QKeySequence::SelectNextWord
1606 || ke == QKeySequence::SelectPreviousWord
1607 || ke == QKeySequence::SelectStartOfLine
1608 || ke == QKeySequence::SelectEndOfLine
1609 || ke == QKeySequence::SelectStartOfBlock
1610 || ke == QKeySequence::SelectEndOfBlock
1611 || ke == QKeySequence::SelectStartOfDocument
1612 || ke == QKeySequence::SelectAll
1613 || ke == QKeySequence::SelectEndOfDocument) {
1615 } else if (ke->modifiers() == Qt::NoModifier || ke->modifiers() == Qt::ShiftModifier
1616 || ke->modifiers() == Qt::KeypadModifier) {
1617 if (ke->key() < Qt::Key_Escape) {
1621 switch (ke->key()) {
1622 case Qt::Key_Delete:
1625 case Qt::Key_Backspace:
1637 return QQuickImplicitSizeItem::event(ev);
1640 void QQuickTextInput::geometryChanged(const QRectF &newGeometry,
1641 const QRectF &oldGeometry)
1643 Q_D(QQuickTextInput);
1645 if (newGeometry.width() != oldGeometry.width())
1647 updateCursorRectangle();
1649 QQuickImplicitSizeItem::geometryChanged(newGeometry, oldGeometry);
1652 void QQuickTextInputPrivate::updateHorizontalScroll()
1654 Q_Q(QQuickTextInput);
1655 QTextLine currentLine = m_textLayout.lineForTextPosition(m_cursor + m_preeditCursor);
1656 const int preeditLength = m_textLayout.preeditAreaText().length();
1657 const qreal width = qMax<qreal>(0, q->width());
1659 qreal widthUsed = 0;
1660 if (currentLine.isValid()) {
1661 cix = currentLine.cursorToX(m_cursor + preeditLength);
1662 const qreal cursorWidth = cix >= 0 ? cix : width - cix;
1663 widthUsed = qMax(currentLine.naturalTextWidth(), cursorWidth);
1665 int previousScroll = hscroll;
1667 if (!autoScroll || widthUsed <= width || m_echoMode == QQuickTextInput::NoEcho) {
1670 Q_ASSERT(currentLine.isValid());
1671 if (cix - hscroll >= width) {
1672 // text doesn't fit, cursor is to the right of br (scroll right)
1673 hscroll = cix - width;
1674 } else if (cix - hscroll < 0 && hscroll < widthUsed) {
1675 // text doesn't fit, cursor is to the left of br (scroll left)
1677 } else if (widthUsed - hscroll < width) {
1678 // text doesn't fit, text document is to the left of br; align
1680 hscroll = widthUsed - width;
1681 } else if (width - hscroll > widthUsed) {
1682 // text doesn't fit, text document is to the right of br; align
1684 hscroll = width - widthUsed;
1686 if (preeditLength > 0) {
1687 // check to ensure long pre-edit text doesn't push the cursor
1689 cix = currentLine.cursorToX(m_cursor + qMax(0, m_preeditCursor - 1));
1694 if (previousScroll != hscroll)
1695 textLayoutDirty = true;
1698 void QQuickTextInputPrivate::updateVerticalScroll()
1700 Q_Q(QQuickTextInput);
1701 const int preeditLength = m_textLayout.preeditAreaText().length();
1702 const qreal height = qMax<qreal>(0, q->height());
1703 qreal heightUsed = contentSize.height();
1704 qreal previousScroll = vscroll;
1706 if (!autoScroll || heightUsed <= height) {
1707 // text fits in br; use vscroll for alignment
1708 vscroll = -QQuickTextUtil::alignedY(
1709 heightUsed, height, vAlign & ~(Qt::AlignAbsolute|Qt::AlignHorizontal_Mask));
1711 QTextLine currentLine = m_textLayout.lineForTextPosition(m_cursor + preeditLength);
1712 QRectF r = currentLine.isValid() ? currentLine.rect() : QRectF();
1713 qreal top = r.top();
1714 int bottom = r.bottom();
1716 if (bottom - vscroll >= height) {
1717 // text doesn't fit, cursor is to the below the br (scroll down)
1718 vscroll = bottom - height;
1719 } else if (top - vscroll < 0 && vscroll < heightUsed) {
1720 // text doesn't fit, cursor is above br (scroll up)
1722 } else if (heightUsed - vscroll < height) {
1723 // text doesn't fit, text document is to the left of br; align
1725 vscroll = heightUsed - height;
1727 if (preeditLength > 0) {
1728 // check to ensure long pre-edit text doesn't push the cursor
1730 currentLine = m_textLayout.lineForTextPosition(m_cursor + qMax(0, m_preeditCursor - 1));
1731 top = currentLine.isValid() ? currentLine.rect().top() : 0;
1736 if (previousScroll != vscroll)
1737 textLayoutDirty = true;
1740 void QQuickTextInput::triggerPreprocess()
1742 Q_D(QQuickTextInput);
1743 if (d->updateType == QQuickTextInputPrivate::UpdateNone)
1744 d->updateType = QQuickTextInputPrivate::UpdateOnlyPreprocess;
1748 QSGNode *QQuickTextInput::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data)
1751 Q_D(QQuickTextInput);
1753 if (d->updateType != QQuickTextInputPrivate::UpdatePaintNode && oldNode != 0) {
1754 // Update done in preprocess() in the nodes
1755 d->updateType = QQuickTextInputPrivate::UpdateNone;
1759 d->updateType = QQuickTextInputPrivate::UpdateNone;
1761 QQuickTextNode *node = static_cast<QQuickTextNode *>(oldNode);
1763 node = new QQuickTextNode(QQuickItemPrivate::get(this)->sceneGraphContext(), this);
1766 if (!d->textLayoutDirty && oldNode != 0) {
1767 QSGSimpleRectNode *cursorNode = node->cursorNode();
1768 if (cursorNode != 0 && !isReadOnly()) {
1769 cursorNode->setRect(cursorRectangle());
1771 if (!d->cursorVisible || d->cursorItem || (!d->m_blinkStatus && d->m_blinkPeriod > 0)) {
1778 node->setUseNativeRenderer(d->renderType == QQuickTextInput::NativeRendering);
1779 node->deleteContent();
1780 node->setMatrix(QMatrix4x4());
1782 QPointF offset(0, 0);
1783 if (d->autoScroll && d->m_textLayout.lineCount() > 0) {
1784 QFontMetricsF fm(d->font);
1785 // the y offset is there to keep the baseline constant in case we have script changes in the text.
1786 offset = -QPoint(d->hscroll, d->vscroll + d->m_textLayout.lineAt(0).ascent() - fm.ascent());
1788 offset = -QPoint(d->hscroll, d->vscroll);
1791 if (!d->m_textLayout.text().isEmpty() || !d->m_textLayout.preeditAreaText().isEmpty()) {
1792 node->addTextLayout(offset, &d->m_textLayout, d->color,
1793 QQuickText::Normal, QColor(), QColor(),
1794 d->selectionColor, d->selectedTextColor,
1795 d->selectionStart(),
1796 d->selectionEnd() - 1); // selectionEnd() returns first char after
1800 if (!isReadOnly() && d->cursorItem == 0) {
1801 node->setCursor(cursorRectangle(), d->color);
1802 if (!d->cursorVisible || (!d->m_blinkStatus && d->m_blinkPeriod > 0)) {
1809 d->textLayoutDirty = false;
1815 QVariant QQuickTextInput::inputMethodQuery(Qt::InputMethodQuery property) const
1817 Q_D(const QQuickTextInput);
1820 return QVariant((bool)(flags() & ItemAcceptsInputMethod));
1822 return QVariant((int) d->effectiveInputMethodHints());
1823 case Qt::ImCursorRectangle:
1824 return cursorRectangle();
1827 case Qt::ImCursorPosition:
1828 return QVariant(d->m_cursor);
1829 case Qt::ImSurroundingText:
1830 if (d->m_echoMode == PasswordEchoOnEdit && !d->m_passwordEchoEditing) {
1831 return QVariant(displayText());
1833 return QVariant(d->realText());
1835 case Qt::ImCurrentSelection:
1836 return QVariant(selectedText());
1837 case Qt::ImMaximumTextLength:
1838 return QVariant(maxLength());
1839 case Qt::ImAnchorPosition:
1840 if (d->selectionStart() == d->selectionEnd())
1841 return QVariant(d->m_cursor);
1842 else if (d->selectionStart() == d->m_cursor)
1843 return QVariant(d->selectionEnd());
1845 return QVariant(d->selectionStart());
1852 \qmlmethod void QtQuick2::TextInput::deselect()
1854 Removes active text selection.
1856 void QQuickTextInput::deselect()
1858 Q_D(QQuickTextInput);
1863 \qmlmethod void QtQuick2::TextInput::selectAll()
1865 Causes all text to be selected.
1867 void QQuickTextInput::selectAll()
1869 Q_D(QQuickTextInput);
1870 d->setSelection(0, text().length());
1874 \qmlmethod void QtQuick2::TextInput::isRightToLeft(int start, int end)
1876 Returns true if the natural reading direction of the editor text
1877 found between positions \a start and \a end is right to left.
1879 bool QQuickTextInput::isRightToLeft(int start, int end)
1882 qmlInfo(this) << "isRightToLeft(start, end) called with the end property being smaller than the start.";
1885 return text().mid(start, end - start).isRightToLeft();
1889 #ifndef QT_NO_CLIPBOARD
1891 \qmlmethod QtQuick2::TextInput::cut()
1893 Moves the currently selected text to the system clipboard.
1895 void QQuickTextInput::cut()
1897 Q_D(QQuickTextInput);
1903 \qmlmethod QtQuick2::TextInput::copy()
1905 Copies the currently selected text to the system clipboard.
1907 void QQuickTextInput::copy()
1909 Q_D(QQuickTextInput);
1914 \qmlmethod QtQuick2::TextInput::paste()
1916 Replaces the currently selected text by the contents of the system clipboard.
1918 void QQuickTextInput::paste()
1920 Q_D(QQuickTextInput);
1924 #endif // QT_NO_CLIPBOARD
1927 Undoes the last operation if undo is \l {canUndo}{available}. Deselects any
1928 current selection, and updates the selection start to the current cursor
1932 void QQuickTextInput::undo()
1934 Q_D(QQuickTextInput);
1935 if (!d->m_readOnly) {
1937 d->finishChange(-1, true);
1942 Redoes the last operation if redo is \l {canRedo}{available}.
1945 void QQuickTextInput::redo()
1947 Q_D(QQuickTextInput);
1948 if (!d->m_readOnly) {
1955 \qmlmethod void QtQuick2::TextInput::insert(int position, string text)
1957 Inserts \a text into the TextInput at position.
1960 void QQuickTextInput::insert(int position, const QString &text)
1962 Q_D(QQuickTextInput);
1963 if (d->m_echoMode == QQuickTextInput::Password) {
1964 int delay = qGuiApp->styleHints()->passwordMaskDelay();
1966 d->m_passwordEchoTimer.start(delay, this);
1968 if (position < 0 || position > d->m_text.length())
1971 const int priorState = d->m_undoState;
1973 QString insertText = text;
1975 if (d->hasSelectedText()) {
1976 d->addCommand(QQuickTextInputPrivate::Command(
1977 QQuickTextInputPrivate::SetSelection, d->m_cursor, 0, d->m_selstart, d->m_selend));
1979 if (d->m_maskData) {
1980 insertText = d->maskString(position, insertText);
1981 for (int i = 0; i < insertText.length(); ++i) {
1982 d->addCommand(QQuickTextInputPrivate::Command(
1983 QQuickTextInputPrivate::DeleteSelection, position + i, d->m_text.at(position + i), -1, -1));
1984 d->addCommand(QQuickTextInputPrivate::Command(
1985 QQuickTextInputPrivate::Insert, position + i, insertText.at(i), -1, -1));
1987 d->m_text.replace(position, insertText.length(), insertText);
1988 if (!insertText.isEmpty())
1989 d->m_textDirty = true;
1990 if (position < d->m_selend && position + insertText.length() > d->m_selstart)
1991 d->m_selDirty = true;
1993 int remaining = d->m_maxLength - d->m_text.length();
1994 if (remaining != 0) {
1995 insertText = insertText.left(remaining);
1996 d->m_text.insert(position, insertText);
1997 for (int i = 0; i < insertText.length(); ++i)
1998 d->addCommand(QQuickTextInputPrivate::Command(
1999 QQuickTextInputPrivate::Insert, position + i, insertText.at(i), -1, -1));
2000 if (d->m_cursor >= position)
2001 d->m_cursor += insertText.length();
2002 if (d->m_selstart >= position)
2003 d->m_selstart += insertText.length();
2004 if (d->m_selend >= position)
2005 d->m_selend += insertText.length();
2006 d->m_textDirty = true;
2007 if (position >= d->m_selstart && position <= d->m_selend)
2008 d->m_selDirty = true;
2012 d->addCommand(QQuickTextInputPrivate::Command(
2013 QQuickTextInputPrivate::SetSelection, d->m_cursor, 0, d->m_selstart, d->m_selend));
2014 d->finishChange(priorState);
2016 if (d->lastSelectionStart != d->lastSelectionEnd) {
2017 if (d->m_selstart != d->lastSelectionStart) {
2018 d->lastSelectionStart = d->m_selstart;
2019 emit selectionStartChanged();
2021 if (d->m_selend != d->lastSelectionEnd) {
2022 d->lastSelectionEnd = d->m_selend;
2023 emit selectionEndChanged();
2029 \qmlmethod string QtQuick2::TextInput::getText(int start, int end)
2031 Removes the section of text that is between the \a start and \a end positions from the TextInput.
2034 void QQuickTextInput::remove(int start, int end)
2036 Q_D(QQuickTextInput);
2038 start = qBound(0, start, d->m_text.length());
2039 end = qBound(0, end, d->m_text.length());
2043 else if (start == end)
2046 if (start < d->m_selend && end > d->m_selstart)
2047 d->m_selDirty = true;
2049 const int priorState = d->m_undoState;
2051 d->addCommand(QQuickTextInputPrivate::Command(
2052 QQuickTextInputPrivate::SetSelection, d->m_cursor, 0, d->m_selstart, d->m_selend));
2054 if (start <= d->m_cursor && d->m_cursor < end) {
2055 // cursor is within the selection. Split up the commands
2056 // to be able to restore the correct cursor position
2057 for (int i = d->m_cursor; i >= start; --i) {
2058 d->addCommand(QQuickTextInputPrivate::Command(
2059 QQuickTextInputPrivate::DeleteSelection, i, d->m_text.at(i), -1, 1));
2061 for (int i = end - 1; i > d->m_cursor; --i) {
2062 d->addCommand(QQuickTextInputPrivate::Command(
2063 QQuickTextInputPrivate::DeleteSelection, i - d->m_cursor + start - 1, d->m_text.at(i), -1, -1));
2066 for (int i = end - 1; i >= start; --i) {
2067 d->addCommand(QQuickTextInputPrivate::Command(
2068 QQuickTextInputPrivate::RemoveSelection, i, d->m_text.at(i), -1, -1));
2071 if (d->m_maskData) {
2072 d->m_text.replace(start, end - start, d->clearString(start, end - start));
2073 for (int i = 0; i < end - start; ++i) {
2074 d->addCommand(QQuickTextInputPrivate::Command(
2075 QQuickTextInputPrivate::Insert, start + i, d->m_text.at(start + i), -1, -1));
2078 d->m_text.remove(start, end - start);
2080 if (d->m_cursor > start)
2081 d->m_cursor -= qMin(d->m_cursor, end) - start;
2082 if (d->m_selstart > start)
2083 d->m_selstart -= qMin(d->m_selstart, end) - start;
2084 if (d->m_selend > end)
2085 d->m_selend -= qMin(d->m_selend, end) - start;
2087 d->addCommand(QQuickTextInputPrivate::Command(
2088 QQuickTextInputPrivate::SetSelection, d->m_cursor, 0, d->m_selstart, d->m_selend));
2090 d->m_textDirty = true;
2091 d->finishChange(priorState);
2093 if (d->lastSelectionStart != d->lastSelectionEnd) {
2094 if (d->m_selstart != d->lastSelectionStart) {
2095 d->lastSelectionStart = d->m_selstart;
2096 emit selectionStartChanged();
2098 if (d->m_selend != d->lastSelectionEnd) {
2099 d->lastSelectionEnd = d->m_selend;
2100 emit selectionEndChanged();
2107 \qmlmethod void QtQuick2::TextInput::selectWord()
2109 Causes the word closest to the current cursor position to be selected.
2111 void QQuickTextInput::selectWord()
2113 Q_D(QQuickTextInput);
2114 d->selectWordAtPos(d->m_cursor);
2118 \qmlproperty bool QtQuick2::TextInput::smooth
2120 This property holds whether the text is smoothly scaled or transformed.
2122 Smooth filtering gives better visual quality, but is slower. If
2123 the item is displayed at its natural size, this property has no visual or
2126 \note Generally scaling artifacts are only visible if the item is stationary on
2127 the screen. A common pattern when animating an item is to disable smooth
2128 filtering at the beginning of the animation and reenable it at the conclusion.
2132 \qmlproperty string QtQuick2::TextInput::passwordCharacter
2134 This is the character displayed when echoMode is set to Password or
2135 PasswordEchoOnEdit. By default it is an asterisk.
2137 If this property is set to a string with more than one character,
2138 the first character is used. If the string is empty, the value
2139 is ignored and the property is not set.
2141 QString QQuickTextInput::passwordCharacter() const
2143 Q_D(const QQuickTextInput);
2144 return QString(d->m_passwordCharacter);
2147 void QQuickTextInput::setPasswordCharacter(const QString &str)
2149 Q_D(QQuickTextInput);
2150 if (str.length() < 1)
2152 d->m_passwordCharacter = str.constData()[0];
2153 if (d->m_echoMode == Password || d->m_echoMode == PasswordEchoOnEdit)
2154 d->updateDisplayText();
2155 emit passwordCharacterChanged();
2159 \qmlproperty string QtQuick2::TextInput::displayText
2161 This is the text displayed in the TextInput.
2163 If \l echoMode is set to TextInput::Normal, this holds the
2164 same value as the TextInput::text property. Otherwise,
2165 this property holds the text visible to the user, while
2166 the \l text property holds the actual entered text.
2168 QString QQuickTextInput::displayText() const
2170 Q_D(const QQuickTextInput);
2171 return d->m_textLayout.text();
2175 \qmlproperty bool QtQuick2::TextInput::selectByMouse
2179 If true, the user can use the mouse to select text in some
2180 platform-specific way. Note that for some platforms this may
2181 not be an appropriate interaction (eg. may conflict with how
2182 the text needs to behave inside a Flickable.
2184 bool QQuickTextInput::selectByMouse() const
2186 Q_D(const QQuickTextInput);
2187 return d->selectByMouse;
2190 void QQuickTextInput::setSelectByMouse(bool on)
2192 Q_D(QQuickTextInput);
2193 if (d->selectByMouse != on) {
2194 d->selectByMouse = on;
2195 emit selectByMouseChanged(on);
2200 \qmlproperty enumeration QtQuick2::TextInput::mouseSelectionMode
2202 Specifies how text should be selected using a mouse.
2205 \li TextInput.SelectCharacters - The selection is updated with individual characters. (Default)
2206 \li TextInput.SelectWords - The selection is updated with whole words.
2209 This property only applies when \l selectByMouse is true.
2212 QQuickTextInput::SelectionMode QQuickTextInput::mouseSelectionMode() const
2214 Q_D(const QQuickTextInput);
2215 return d->mouseSelectionMode;
2218 void QQuickTextInput::setMouseSelectionMode(SelectionMode mode)
2220 Q_D(QQuickTextInput);
2221 if (d->mouseSelectionMode != mode) {
2222 d->mouseSelectionMode = mode;
2223 emit mouseSelectionModeChanged(mode);
2228 \qmlproperty bool QtQuick2::TextInput::persistentSelection
2230 Whether the TextInput should keep its selection when it loses active focus to another
2231 item in the scene. By default this is set to false;
2234 bool QQuickTextInput::persistentSelection() const
2236 Q_D(const QQuickTextInput);
2237 return d->persistentSelection;
2240 void QQuickTextInput::setPersistentSelection(bool on)
2242 Q_D(QQuickTextInput);
2243 if (d->persistentSelection == on)
2245 d->persistentSelection = on;
2246 emit persistentSelectionChanged();
2249 #ifndef QT_NO_CLIPBOARD
2251 \qmlproperty bool QtQuick2::TextInput::canPaste
2253 Returns true if the TextInput is writable and the content of the clipboard is
2254 suitable for pasting into the TextInput.
2256 bool QQuickTextInput::canPaste() const
2258 Q_D(const QQuickTextInput);
2259 if (!d->canPasteValid) {
2260 if (const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData())
2261 const_cast<QQuickTextInputPrivate *>(d)->canPaste = !d->m_readOnly && mimeData->hasText();
2262 const_cast<QQuickTextInputPrivate *>(d)->canPasteValid = true;
2269 \qmlproperty bool QtQuick2::TextInput::canUndo
2271 Returns true if the TextInput is writable and there are previous operations
2275 bool QQuickTextInput::canUndo() const
2277 Q_D(const QQuickTextInput);
2282 \qmlproperty bool QtQuick2::TextInput::canRedo
2284 Returns true if the TextInput is writable and there are \l {undo}{undone}
2285 operations that can be redone.
2288 bool QQuickTextInput::canRedo() const
2290 Q_D(const QQuickTextInput);
2295 \qmlproperty real QtQuick2::TextInput::contentWidth
2297 Returns the width of the text, including the width past the width
2298 which is covered due to insufficient wrapping if \l wrapMode is set.
2301 qreal QQuickTextInput::contentWidth() const
2303 Q_D(const QQuickTextInput);
2304 return d->contentSize.width();
2308 \qmlproperty real QtQuick2::TextInput::contentHeight
2310 Returns the height of the text, including the height past the height
2311 that is covered if the text does not fit within the set height.
2314 qreal QQuickTextInput::contentHeight() const
2316 Q_D(const QQuickTextInput);
2317 return d->contentSize.height();
2320 void QQuickTextInput::moveCursorSelection(int position)
2322 Q_D(QQuickTextInput);
2323 d->moveCursor(position, true);
2327 \qmlmethod void QtQuick2::TextInput::moveCursorSelection(int position, SelectionMode mode = TextInput.SelectCharacters)
2329 Moves the cursor to \a position and updates the selection according to the optional \a mode
2330 parameter. (To only move the cursor, set the \l cursorPosition property.)
2332 When this method is called it additionally sets either the
2333 selectionStart or the selectionEnd (whichever was at the previous cursor position)
2334 to the specified position. This allows you to easily extend and contract the selected
2337 The selection mode specifies whether the selection is updated on a per character or a per word
2338 basis. If not specified the selection mode will default to TextInput.SelectCharacters.
2341 \li TextInput.SelectCharacters - Sets either the selectionStart or selectionEnd (whichever was at
2342 the previous cursor position) to the specified position.
2343 \li TextInput.SelectWords - Sets the selectionStart and selectionEnd to include all
2344 words between the specified position and the previous cursor position. Words partially in the
2348 For example, take this sequence of calls:
2352 moveCursorSelection(9, TextInput.SelectCharacters)
2353 moveCursorSelection(7, TextInput.SelectCharacters)
2356 This moves the cursor to position 5, extend the selection end from 5 to 9
2357 and then retract the selection end from 9 to 7, leaving the text from position 5 to 7
2358 selected (the 6th and 7th characters).
2360 The same sequence with TextInput.SelectWords will extend the selection start to a word boundary
2361 before or on position 5 and extend the selection end to a word boundary on or past position 9.
2363 void QQuickTextInput::moveCursorSelection(int pos, SelectionMode mode)
2365 Q_D(QQuickTextInput);
2367 if (mode == SelectCharacters) {
2368 d->moveCursor(pos, true);
2369 } else if (pos != d->m_cursor){
2370 const int cursor = d->m_cursor;
2372 if (!d->hasSelectedText())
2373 anchor = d->m_cursor;
2374 else if (d->selectionStart() == d->m_cursor)
2375 anchor = d->selectionEnd();
2377 anchor = d->selectionStart();
2379 if (anchor < pos || (anchor == pos && cursor < pos)) {
2380 const QString text = this->text();
2381 QTextBoundaryFinder finder(QTextBoundaryFinder::Word, text);
2382 finder.setPosition(anchor);
2384 const QTextBoundaryFinder::BoundaryReasons reasons = finder.boundaryReasons();
2385 if (anchor < text.length() && (!(reasons & QTextBoundaryFinder::StartWord)
2386 || ((reasons & QTextBoundaryFinder::EndWord) && anchor > cursor))) {
2387 finder.toPreviousBoundary();
2389 anchor = finder.position() != -1 ? finder.position() : 0;
2391 finder.setPosition(pos);
2392 if (pos > 0 && !finder.boundaryReasons())
2393 finder.toNextBoundary();
2394 const int cursor = finder.position() != -1 ? finder.position() : text.length();
2396 d->setSelection(anchor, cursor - anchor);
2397 } else if (anchor > pos || (anchor == pos && cursor > pos)) {
2398 const QString text = this->text();
2399 QTextBoundaryFinder finder(QTextBoundaryFinder::Word, text);
2400 finder.setPosition(anchor);
2402 const QTextBoundaryFinder::BoundaryReasons reasons = finder.boundaryReasons();
2403 if (anchor > 0 && (!(reasons & QTextBoundaryFinder::EndWord)
2404 || ((reasons & QTextBoundaryFinder::StartWord) && anchor < cursor))) {
2405 finder.toNextBoundary();
2408 anchor = finder.position() != -1 ? finder.position() : text.length();
2410 finder.setPosition(pos);
2411 if (pos < text.length() && !finder.boundaryReasons())
2412 finder.toPreviousBoundary();
2413 const int cursor = finder.position() != -1 ? finder.position() : 0;
2415 d->setSelection(anchor, cursor - anchor);
2420 void QQuickTextInput::focusInEvent(QFocusEvent *event)
2422 Q_D(const QQuickTextInput);
2423 if (d->focusOnPress && !d->m_readOnly)
2424 qGuiApp->inputMethod()->show();
2425 QQuickImplicitSizeItem::focusInEvent(event);
2428 void QQuickTextInput::itemChange(ItemChange change, const ItemChangeData &value)
2430 Q_D(QQuickTextInput);
2431 if (change == ItemActiveFocusHasChanged) {
2432 bool hasFocus = value.boolValue;
2433 setCursorVisible(hasFocus);
2434 if (!hasFocus && (d->m_passwordEchoEditing || d->m_passwordEchoTimer.isActive())) {
2435 d->updatePasswordEchoEditing(false);//QQuickTextInputPrivate sets it on key events, but doesn't deal with focus events
2439 if (!d->persistentSelection)
2441 disconnect(qApp->inputMethod(), SIGNAL(inputDirectionChanged(Qt::LayoutDirection)),
2442 this, SLOT(q_updateAlignment()));
2444 q_updateAlignment();
2445 connect(qApp->inputMethod(), SIGNAL(inputDirectionChanged(Qt::LayoutDirection)),
2446 this, SLOT(q_updateAlignment()));
2449 QQuickItem::itemChange(change, value);
2453 \qmlproperty bool QtQuick2::TextInput::inputMethodComposing
2456 This property holds whether the TextInput has partial text input from an
2459 While it is composing an input method may rely on mouse or key events from
2460 the TextInput to edit or commit the partial text. This property can be
2461 used to determine when to disable events handlers that may interfere with
2462 the correct operation of an input method.
2464 bool QQuickTextInput::isInputMethodComposing() const
2466 Q_D(const QQuickTextInput);
2467 return d->hasImState;
2470 void QQuickTextInputPrivate::init()
2472 Q_Q(QQuickTextInput);
2473 q->setSmooth(smooth);
2474 q->setAcceptedMouseButtons(Qt::LeftButton);
2475 q->setFlag(QQuickItem::ItemAcceptsInputMethod);
2476 q->setFlag(QQuickItem::ItemHasContents);
2477 #ifndef QT_NO_CLIPBOARD
2478 q->connect(QGuiApplication::clipboard(), SIGNAL(dataChanged()),
2479 q, SLOT(q_canPasteChanged()));
2480 #endif // QT_NO_CLIPBOARD
2482 lastSelectionStart = 0;
2483 lastSelectionEnd = 0;
2484 determineHorizontalAlignment();
2486 if (!qmlDisableDistanceField()) {
2487 QTextOption option = m_textLayout.textOption();
2488 option.setUseDesignMetrics(renderType != QQuickTextInput::NativeRendering);
2489 m_textLayout.setTextOption(option);
2493 void QQuickTextInput::updateCursorRectangle()
2495 Q_D(QQuickTextInput);
2496 if (!isComponentComplete())
2499 d->updateHorizontalScroll();
2500 d->updateVerticalScroll();
2501 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
2503 emit cursorRectangleChanged();
2504 if (d->cursorItem) {
2505 QRectF r = cursorRectangle();
2506 d->cursorItem->setPos(r.topLeft());
2507 d->cursorItem->setHeight(r.height());
2509 updateInputMethod(Qt::ImCursorRectangle);
2512 void QQuickTextInput::selectionChanged()
2514 Q_D(QQuickTextInput);
2515 d->textLayoutDirty = true; //TODO: Only update rect in selection
2516 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
2518 emit selectedTextChanged();
2520 if (d->lastSelectionStart != d->selectionStart()) {
2521 d->lastSelectionStart = d->selectionStart();
2522 if (d->lastSelectionStart == -1)
2523 d->lastSelectionStart = d->m_cursor;
2524 emit selectionStartChanged();
2526 if (d->lastSelectionEnd != d->selectionEnd()) {
2527 d->lastSelectionEnd = d->selectionEnd();
2528 if (d->lastSelectionEnd == -1)
2529 d->lastSelectionEnd = d->m_cursor;
2530 emit selectionEndChanged();
2534 void QQuickTextInputPrivate::showCursor()
2536 if (textNode != 0 && textNode->cursorNode() != 0)
2537 textNode->cursorNode()->setColor(color);
2540 void QQuickTextInputPrivate::hideCursor()
2542 if (textNode != 0 && textNode->cursorNode() != 0)
2543 textNode->cursorNode()->setColor(QColor(0, 0, 0, 0));
2546 QRectF QQuickTextInput::boundingRect() const
2548 Q_D(const QQuickTextInput);
2550 int cursorWidth = d->cursorItem ? 0 : 1;
2552 qreal hscroll = d->hscroll;
2553 if (!d->autoScroll || d->contentSize.width() < width())
2554 hscroll -= QQuickTextUtil::alignedX(d->contentSize.width(), width(), effectiveHAlign());
2556 // Could include font max left/right bearings to either side of rectangle.
2557 QRectF r(-hscroll, -d->vscroll, d->contentSize.width(), d->contentSize.height());
2558 r.setRight(r.right() + cursorWidth);
2562 QRectF QQuickTextInput::clipRect() const
2564 Q_D(const QQuickTextInput);
2566 int cursorWidth = d->cursorItem ? d->cursorItem->width() : 1;
2568 // Could include font max left/right bearings to either side of rectangle.
2569 QRectF r = QQuickImplicitSizeItem::clipRect();
2570 r.setRight(r.right() + cursorWidth);
2574 void QQuickTextInput::q_canPasteChanged()
2576 Q_D(QQuickTextInput);
2577 bool old = d->canPaste;
2578 #ifndef QT_NO_CLIPBOARD
2579 if (const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData())
2580 d->canPaste = !d->m_readOnly && mimeData->hasText();
2582 d->canPaste = false;
2585 bool changed = d->canPaste != old || !d->canPasteValid;
2586 d->canPasteValid = true;
2588 emit canPasteChanged();
2592 void QQuickTextInput::q_updateAlignment()
2594 Q_D(QQuickTextInput);
2595 if (d->determineHorizontalAlignment()) {
2597 updateCursorRectangle();
2601 // ### these should come from QStyleHints
2602 const int textCursorWidth = 1;
2603 const bool fullWidthSelection = true;
2608 Updates the display text based of the current edit text
2609 If the text has changed will emit displayTextChanged()
2611 void QQuickTextInputPrivate::updateDisplayText(bool forceUpdate)
2613 QString orig = m_textLayout.text();
2615 if (m_echoMode == QQuickTextInput::NoEcho)
2616 str = QString::fromLatin1("");
2620 if (m_echoMode == QQuickTextInput::Password) {
2621 str.fill(m_passwordCharacter);
2622 if (m_passwordEchoTimer.isActive() && m_cursor > 0 && m_cursor <= m_text.length()) {
2623 int cursor = m_cursor - 1;
2624 QChar uc = m_text.at(cursor);
2626 if (cursor > 0 && uc.unicode() >= 0xdc00 && uc.unicode() < 0xe000) {
2627 // second half of a surrogate, check if we have the first half as well,
2628 // if yes restore both at once
2629 uc = m_text.at(cursor - 1);
2630 if (uc.unicode() >= 0xd800 && uc.unicode() < 0xdc00)
2631 str[cursor - 1] = uc;
2634 } else if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit && !m_passwordEchoEditing) {
2635 str.fill(m_passwordCharacter);
2638 // replace certain non-printable characters with spaces (to avoid
2639 // drawing boxes when using fonts that don't have glyphs for such
2641 QChar* uc = str.data();
2642 for (int i = 0; i < (int)str.length(); ++i) {
2643 if ((uc[i] < 0x20 && uc[i] != 0x09)
2644 || uc[i] == QChar::LineSeparator
2645 || uc[i] == QChar::ParagraphSeparator
2646 || uc[i] == QChar::ObjectReplacementCharacter)
2647 uc[i] = QChar(0x0020);
2650 if (str != orig || forceUpdate) {
2651 m_textLayout.setText(str);
2652 updateLayout(); // polish?
2653 emit q_func()->displayTextChanged();
2657 qreal QQuickTextInputPrivate::getImplicitWidth() const
2659 Q_Q(const QQuickTextInput);
2660 if (!requireImplicitWidth) {
2661 QQuickTextInputPrivate *d = const_cast<QQuickTextInputPrivate *>(this);
2662 d->requireImplicitWidth = true;
2664 if (q->isComponentComplete()) {
2665 // One time cost, only incurred if implicitWidth is first requested after
2666 // componentComplete.
2667 QTextLayout layout(m_text);
2669 QTextOption option = m_textLayout.textOption();
2670 option.setTextDirection(m_layoutDirection);
2671 option.setFlags(QTextOption::IncludeTrailingSpaces);
2672 option.setWrapMode(QTextOption::WrapMode(wrapMode));
2673 option.setAlignment(Qt::Alignment(q->effectiveHAlign()));
2674 layout.setTextOption(option);
2675 layout.setFont(font);
2676 layout.setPreeditArea(m_textLayout.preeditAreaPosition(), m_textLayout.preeditAreaText());
2677 layout.beginLayout();
2679 QTextLine line = layout.createLine();
2680 line.setLineWidth(INT_MAX);
2681 d->implicitWidth = qCeil(line.naturalTextWidth());
2686 return implicitWidth;
2689 void QQuickTextInputPrivate::updateLayout()
2691 Q_Q(QQuickTextInput);
2693 if (!q->isComponentComplete())
2697 QTextOption option = m_textLayout.textOption();
2698 option.setTextDirection(layoutDirection());
2699 option.setWrapMode(QTextOption::WrapMode(wrapMode));
2700 option.setAlignment(Qt::Alignment(q->effectiveHAlign()));
2701 m_textLayout.setTextOption(option);
2702 m_textLayout.setFont(font);
2704 m_textLayout.beginLayout();
2706 QTextLine line = m_textLayout.createLine();
2707 if (requireImplicitWidth) {
2708 line.setLineWidth(INT_MAX);
2709 const bool wasInLayout = inLayout;
2711 q->setImplicitWidth(qCeil(line.naturalTextWidth()));
2712 inLayout = wasInLayout;
2713 if (inLayout) // probably the result of a binding loop, but by letting it
2714 return; // get this far we'll get a warning to that effect.
2716 qreal lineWidth = q->widthValid() ? q->width() : INT_MAX;
2720 line.setLineWidth(lineWidth);
2721 line.setPosition(QPointF(0, height));
2723 height += line.height();
2724 width = qMax(width, line.naturalTextWidth());
2726 line = m_textLayout.createLine();
2727 } while (line.isValid());
2728 m_textLayout.endLayout();
2730 option.setWrapMode(QTextOption::NoWrap);
2731 m_textLayout.setTextOption(option);
2733 textLayoutDirty = true;
2735 const QSizeF previousSize = contentSize;
2736 contentSize = QSizeF(width, height);
2738 updateType = UpdatePaintNode;
2741 if (!requireImplicitWidth && !q->widthValid())
2742 q->setImplicitSize(width, height);
2744 q->setImplicitHeight(height);
2746 if (previousSize != contentSize)
2747 emit q->contentSizeChanged();
2750 #ifndef QT_NO_CLIPBOARD
2754 Copies the currently selected text into the clipboard using the given
2757 \note If the echo mode is set to a mode other than Normal then copy
2758 will not work. This is to prevent using copy as a method of bypassing
2759 password features of the line control.
2761 void QQuickTextInputPrivate::copy(QClipboard::Mode mode) const
2763 QString t = selectedText();
2764 if (!t.isEmpty() && m_echoMode == QQuickTextInput::Normal) {
2765 QGuiApplication::clipboard()->setText(t, mode);
2772 Inserts the text stored in the application clipboard into the line
2777 void QQuickTextInputPrivate::paste(QClipboard::Mode clipboardMode)
2779 QString clip = QGuiApplication::clipboard()->text(clipboardMode);
2780 if (!clip.isEmpty() || hasSelectedText()) {
2781 separate(); //make it a separate undo/redo command
2787 #endif // !QT_NO_CLIPBOARD
2792 void QQuickTextInputPrivate::commitPreedit()
2794 Q_Q(QQuickTextInput);
2799 qApp->inputMethod()->commit();
2804 QInputMethodEvent ev;
2805 QCoreApplication::sendEvent(q, &ev);
2808 void QQuickTextInputPrivate::cancelPreedit()
2810 Q_Q(QQuickTextInput);
2815 qApp->inputMethod()->reset();
2817 QInputMethodEvent ev;
2818 QCoreApplication::sendEvent(q, &ev);
2824 Handles the behavior for the backspace key or function.
2825 Removes the current selection if there is a selection, otherwise
2826 removes the character prior to the cursor position.
2830 void QQuickTextInputPrivate::backspace()
2832 int priorState = m_undoState;
2833 if (hasSelectedText()) {
2834 removeSelectedText();
2835 } else if (m_cursor) {
2838 m_cursor = prevMaskBlank(m_cursor);
2839 QChar uc = m_text.at(m_cursor);
2840 if (m_cursor > 0 && uc.unicode() >= 0xdc00 && uc.unicode() < 0xe000) {
2841 // second half of a surrogate, check if we have the first half as well,
2842 // if yes delete both at once
2843 uc = m_text.at(m_cursor - 1);
2844 if (uc.unicode() >= 0xd800 && uc.unicode() < 0xdc00) {
2845 internalDelete(true);
2849 internalDelete(true);
2851 finishChange(priorState);
2857 Handles the behavior for the delete key or function.
2858 Removes the current selection if there is a selection, otherwise
2859 removes the character after the cursor position.
2863 void QQuickTextInputPrivate::del()
2865 int priorState = m_undoState;
2866 if (hasSelectedText()) {
2867 removeSelectedText();
2869 int n = m_textLayout.nextCursorPosition(m_cursor) - m_cursor;
2873 finishChange(priorState);
2879 Inserts the given \a newText at the current cursor position.
2880 If there is any selected text it is removed prior to insertion of
2883 void QQuickTextInputPrivate::insert(const QString &newText)
2885 int priorState = m_undoState;
2886 removeSelectedText();
2887 internalInsert(newText);
2888 finishChange(priorState);
2894 Clears the line control text.
2896 void QQuickTextInputPrivate::clear()
2898 int priorState = m_undoState;
2900 m_selend = m_text.length();
2901 removeSelectedText();
2903 finishChange(priorState, /*update*/false, /*edited*/false);
2909 Sets \a length characters from the given \a start position as selected.
2910 The given \a start position must be within the current text for
2911 the line control. If \a length characters cannot be selected, then
2912 the selection will extend to the end of the current text.
2914 void QQuickTextInputPrivate::setSelection(int start, int length)
2916 Q_Q(QQuickTextInput);
2919 if (start < 0 || start > (int)m_text.length()){
2920 qWarning("QQuickTextInputPrivate::setSelection: Invalid start position");
2925 if (start == m_selstart && start + length == m_selend && m_cursor == m_selend)
2928 m_selend = qMin(start + length, (int)m_text.length());
2929 m_cursor = m_selend;
2930 } else if (length < 0){
2931 if (start == m_selend && start + length == m_selstart && m_cursor == m_selstart)
2933 m_selstart = qMax(start + length, 0);
2935 m_cursor = m_selstart;
2936 } else if (m_selstart != m_selend) {
2942 emitCursorPositionChanged();
2945 emit q->selectionChanged();
2946 emitCursorPositionChanged();
2947 q->updateInputMethod(Qt::ImCursorRectangle | Qt::ImAnchorPosition
2948 | Qt::ImCursorPosition | Qt::ImCurrentSelection);
2954 Sets the password echo editing to \a editing. If password echo editing
2955 is true, then the text of the password is displayed even if the echo
2956 mode is set to QLineEdit::PasswordEchoOnEdit. Password echoing editing
2957 does not affect other echo modes.
2959 void QQuickTextInputPrivate::updatePasswordEchoEditing(bool editing)
2961 cancelPasswordEchoTimer();
2962 m_passwordEchoEditing = editing;
2963 updateDisplayText();
2969 Fixes the current text so that it is valid given any set validators.
2971 Returns true if the text was changed. Otherwise returns false.
2973 bool QQuickTextInputPrivate::fixup() // this function assumes that validate currently returns != Acceptable
2975 #ifndef QT_NO_VALIDATOR
2977 QString textCopy = m_text;
2978 int cursorCopy = m_cursor;
2979 m_validator->fixup(textCopy);
2980 if (m_validator->validate(textCopy, cursorCopy) == QValidator::Acceptable) {
2981 if (textCopy != m_text || cursorCopy != m_cursor)
2982 internalSetText(textCopy, cursorCopy);
2993 Moves the cursor to the given position \a pos. If \a mark is true will
2994 adjust the currently selected text.
2996 void QQuickTextInputPrivate::moveCursor(int pos, bool mark)
2998 Q_Q(QQuickTextInput);
3001 if (pos != m_cursor) {
3004 pos = pos > m_cursor ? nextMaskBlank(pos) : prevMaskBlank(pos);
3008 if (m_selend > m_selstart && m_cursor == m_selstart)
3010 else if (m_selend > m_selstart && m_cursor == m_selend)
3011 anchor = m_selstart;
3014 m_selstart = qMin(anchor, pos);
3015 m_selend = qMax(anchor, pos);
3020 if (mark || m_selDirty) {
3022 emit q->selectionChanged();
3024 emitCursorPositionChanged();
3025 q->updateInputMethod();
3031 Applies the given input method event \a event to the text of the line
3034 void QQuickTextInputPrivate::processInputMethodEvent(QInputMethodEvent *event)
3036 Q_Q(QQuickTextInput);
3038 int priorState = -1;
3039 bool isGettingInput = !event->commitString().isEmpty()
3040 || event->preeditString() != preeditAreaText()
3041 || event->replacementLength() > 0;
3042 bool cursorPositionChanged = false;
3043 bool selectionChange = false;
3044 m_preeditDirty = event->preeditString() != preeditAreaText();
3046 if (isGettingInput) {
3047 // If any text is being input, remove selected text.
3048 priorState = m_undoState;
3049 if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit && !m_passwordEchoEditing) {
3050 updatePasswordEchoEditing(true);
3052 m_selend = m_text.length();
3054 removeSelectedText();
3057 int c = m_cursor; // cursor position after insertion of commit string
3058 if (event->replacementStart() <= 0)
3059 c += event->commitString().length() - qMin(-event->replacementStart(), event->replacementLength());
3061 m_cursor += event->replacementStart();
3065 // insert commit string
3066 if (event->replacementLength()) {
3067 m_selstart = m_cursor;
3068 m_selend = m_selstart + event->replacementLength();
3069 m_selend = qMin(m_selend, m_text.length());
3070 removeSelectedText();
3072 if (!event->commitString().isEmpty()) {
3073 internalInsert(event->commitString());
3074 cursorPositionChanged = true;
3077 m_cursor = qBound(0, c, m_text.length());
3079 for (int i = 0; i < event->attributes().size(); ++i) {
3080 const QInputMethodEvent::Attribute &a = event->attributes().at(i);
3081 if (a.type == QInputMethodEvent::Selection) {
3082 m_cursor = qBound(0, a.start + a.length, m_text.length());
3084 m_selstart = qMax(0, qMin(a.start, m_text.length()));
3085 m_selend = m_cursor;
3086 if (m_selend < m_selstart) {
3087 qSwap(m_selstart, m_selend);
3089 selectionChange = true;
3091 m_selstart = m_selend = 0;
3093 cursorPositionChanged = true;
3097 m_textLayout.setPreeditArea(m_cursor, event->preeditString());
3099 const int oldPreeditCursor = m_preeditCursor;
3100 m_preeditCursor = event->preeditString().length();
3101 hasImState = !event->preeditString().isEmpty();
3102 bool cursorVisible = true;
3103 QList<QTextLayout::FormatRange> formats;
3104 for (int i = 0; i < event->attributes().size(); ++i) {
3105 const QInputMethodEvent::Attribute &a = event->attributes().at(i);
3106 if (a.type == QInputMethodEvent::Cursor) {
3108 m_preeditCursor = a.start;
3109 cursorVisible = a.length != 0;
3110 } else if (a.type == QInputMethodEvent::TextFormat) {
3112 QTextCharFormat f = qvariant_cast<QTextFormat>(a.value).toCharFormat();
3114 QTextLayout::FormatRange o;
3115 o.start = a.start + m_cursor;
3116 o.length = a.length;
3122 m_textLayout.setAdditionalFormats(formats);
3124 updateDisplayText(/*force*/ true);
3125 if ((cursorPositionChanged && !emitCursorPositionChanged())
3126 || m_preeditCursor != oldPreeditCursor
3127 || isGettingInput) {
3128 q->updateCursorRectangle();
3132 finishChange(priorState);
3134 q->setCursorVisible(cursorVisible);
3136 if (selectionChange) {
3137 emit q->selectionChanged();
3138 q->updateInputMethod(Qt::ImCursorRectangle | Qt::ImAnchorPosition
3139 | Qt::ImCursorPosition | Qt::ImCurrentSelection);
3146 Sets the selection to cover the word at the given cursor position.
3147 The word boundaries are defined by the behavior of QTextLayout::SkipWords
3150 void QQuickTextInputPrivate::selectWordAtPos(int cursor)
3152 int next = cursor + 1;
3155 int c = m_textLayout.previousCursorPosition(next, QTextLayout::SkipWords);
3156 moveCursor(c, false);
3157 // ## text layout should support end of words.
3158 int end = m_textLayout.nextCursorPosition(c, QTextLayout::SkipWords);
3159 while (end > cursor && m_text[end-1].isSpace())
3161 moveCursor(end, true);
3167 Completes a change to the line control text. If the change is not valid
3168 will undo the line control state back to the given \a validateFromState.
3170 If \a edited is true and the change is valid, will emit textEdited() in
3171 addition to textChanged(). Otherwise only emits textChanged() on a valid
3174 The \a update value is currently unused.
3176 bool QQuickTextInputPrivate::finishChange(int validateFromState, bool update, bool /*edited*/)
3178 Q_Q(QQuickTextInput);
3181 bool inputMethodAttributesChanged = m_textDirty || m_selDirty;
3182 bool alignmentChanged = false;
3186 bool wasValidInput = m_validInput;
3187 bool wasAcceptable = m_acceptableInput;
3188 m_validInput = true;
3189 m_acceptableInput = true;
3190 #ifndef QT_NO_VALIDATOR
3192 QString textCopy = m_text;
3193 int cursorCopy = m_cursor;
3194 QValidator::State state = m_validator->validate(textCopy, cursorCopy);
3195 m_validInput = state != QValidator::Invalid;
3196 m_acceptableInput = state == QValidator::Acceptable;
3198 if (m_text != textCopy) {
3199 internalSetText(textCopy, cursorCopy);
3202 m_cursor = cursorCopy;
3206 if (validateFromState >= 0 && wasValidInput && !m_validInput) {
3207 if (m_transactions.count())
3209 internalUndo(validateFromState);
3210 m_history.resize(m_undoState);
3211 m_validInput = true;
3212 m_acceptableInput = wasAcceptable;
3213 m_textDirty = false;
3217 m_textDirty = false;
3218 m_preeditDirty = false;
3219 alignmentChanged = determineHorizontalAlignment();
3220 emit q->textChanged();
3223 updateDisplayText(alignmentChanged);
3225 if (m_acceptableInput != wasAcceptable)
3226 emit q->acceptableInputChanged();
3228 if (m_preeditDirty) {
3229 m_preeditDirty = false;
3230 if (determineHorizontalAlignment()) {
3231 alignmentChanged = true;
3238 emit q->selectionChanged();
3241 inputMethodAttributesChanged |= (m_cursor != m_lastCursorPos);
3242 if (inputMethodAttributesChanged)
3243 q->updateInputMethod();
3244 emitUndoRedoChanged();
3246 if (!emitCursorPositionChanged() && alignmentChanged)
3247 q->updateCursorRectangle();
3255 An internal function for setting the text of the line control.
3257 void QQuickTextInputPrivate::internalSetText(const QString &txt, int pos, bool edited)
3259 Q_Q(QQuickTextInput);
3261 QString oldText = m_text;
3263 m_text = maskString(0, txt, true);
3264 m_text += clearString(m_text.length(), m_maxLength - m_text.length());
3266 m_text = txt.isEmpty() ? txt : txt.left(m_maxLength);
3270 m_cursor = (pos < 0 || pos > m_text.length()) ? m_text.length() : pos;
3271 m_textDirty = (oldText != m_text);
3273 bool changed = finishChange(-1, true, edited);
3274 #ifdef QT_NO_ACCESSIBILITY
3278 QAccessibleTextUpdateEvent ev(q, 0, oldText, m_text);
3279 QAccessible::updateAccessibility(&ev);
3288 Adds the given \a command to the undo history
3289 of the line control. Does not apply the command.
3291 void QQuickTextInputPrivate::addCommand(const Command &cmd)
3293 if (m_separator && m_undoState && m_history[m_undoState - 1].type != Separator) {
3294 m_history.resize(m_undoState + 2);
3295 m_history[m_undoState++] = Command(Separator, m_cursor, 0, m_selstart, m_selend);
3297 m_history.resize(m_undoState + 1);
3299 m_separator = false;
3300 m_history[m_undoState++] = cmd;
3306 Inserts the given string \a s into the line
3309 Also adds the appropriate commands into the undo history.
3310 This function does not call finishChange(), and may leave the text
3311 in an invalid state.
3313 void QQuickTextInputPrivate::internalInsert(const QString &s)
3315 Q_Q(QQuickTextInput);
3316 if (m_echoMode == QQuickTextInput::Password) {
3317 int delay = qGuiApp->styleHints()->passwordMaskDelay();
3319 m_passwordEchoTimer.start(delay, q);
3321 if (hasSelectedText())
3322 addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
3324 QString ms = maskString(m_cursor, s);
3325 for (int i = 0; i < (int) ms.length(); ++i) {
3326 addCommand (Command(DeleteSelection, m_cursor + i, m_text.at(m_cursor + i), -1, -1));
3327 addCommand(Command(Insert, m_cursor + i, ms.at(i), -1, -1));
3329 m_text.replace(m_cursor, ms.length(), ms);
3330 m_cursor += ms.length();
3331 m_cursor = nextMaskBlank(m_cursor);
3334 int remaining = m_maxLength - m_text.length();
3335 if (remaining != 0) {
3336 m_text.insert(m_cursor, s.left(remaining));
3337 for (int i = 0; i < (int) s.left(remaining).length(); ++i)
3338 addCommand(Command(Insert, m_cursor++, s.at(i), -1, -1));
3347 deletes a single character from the current text. If \a wasBackspace,
3348 the character prior to the cursor is removed. Otherwise the character
3349 after the cursor is removed.
3351 Also adds the appropriate commands into the undo history.
3352 This function does not call finishChange(), and may leave the text
3353 in an invalid state.
3355 void QQuickTextInputPrivate::internalDelete(bool wasBackspace)
3357 if (m_cursor < (int) m_text.length()) {
3358 cancelPasswordEchoTimer();
3359 if (hasSelectedText())
3360 addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
3361 addCommand(Command((CommandType)((m_maskData ? 2 : 0) + (wasBackspace ? Remove : Delete)),
3362 m_cursor, m_text.at(m_cursor), -1, -1));
3364 m_text.replace(m_cursor, 1, clearString(m_cursor, 1));
3365 addCommand(Command(Insert, m_cursor, m_text.at(m_cursor), -1, -1));
3367 m_text.remove(m_cursor, 1);
3376 removes the currently selected text from the line control.
3378 Also adds the appropriate commands into the undo history.
3379 This function does not call finishChange(), and may leave the text
3380 in an invalid state.
3382 void QQuickTextInputPrivate::removeSelectedText()
3384 if (m_selstart < m_selend && m_selend <= (int) m_text.length()) {
3385 cancelPasswordEchoTimer();
3388 addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
3389 if (m_selstart <= m_cursor && m_cursor < m_selend) {
3390 // cursor is within the selection. Split up the commands
3391 // to be able to restore the correct cursor position
3392 for (i = m_cursor; i >= m_selstart; --i)
3393 addCommand (Command(DeleteSelection, i, m_text.at(i), -1, 1));
3394 for (i = m_selend - 1; i > m_cursor; --i)
3395 addCommand (Command(DeleteSelection, i - m_cursor + m_selstart - 1, m_text.at(i), -1, -1));
3397 for (i = m_selend-1; i >= m_selstart; --i)
3398 addCommand (Command(RemoveSelection, i, m_text.at(i), -1, -1));
3401 m_text.replace(m_selstart, m_selend - m_selstart, clearString(m_selstart, m_selend - m_selstart));
3402 for (int i = 0; i < m_selend - m_selstart; ++i)
3403 addCommand(Command(Insert, m_selstart + i, m_text.at(m_selstart + i), -1, -1));
3405 m_text.remove(m_selstart, m_selend - m_selstart);
3407 if (m_cursor > m_selstart)
3408 m_cursor -= qMin(m_cursor, m_selend) - m_selstart;
3417 Parses the input mask specified by \a maskFields to generate
3418 the mask data used to handle input masks.
3420 void QQuickTextInputPrivate::parseInputMask(const QString &maskFields)
3422 int delimiter = maskFields.indexOf(QLatin1Char(';'));
3423 if (maskFields.isEmpty() || delimiter == 0) {
3425 delete [] m_maskData;
3427 m_maxLength = 32767;
3428 internalSetText(QString());
3433 if (delimiter == -1) {
3434 m_blank = QLatin1Char(' ');
3435 m_inputMask = maskFields;
3437 m_inputMask = maskFields.left(delimiter);
3438 m_blank = (delimiter + 1 < maskFields.length()) ? maskFields[delimiter + 1] : QLatin1Char(' ');
3441 // calculate m_maxLength / m_maskData length
3444 for (int i=0; i<m_inputMask.length(); i++) {
3445 c = m_inputMask.at(i);
3446 if (i > 0 && m_inputMask.at(i-1) == QLatin1Char('\\')) {
3450 if (c != QLatin1Char('\\') && c != QLatin1Char('!') &&
3451 c != QLatin1Char('<') && c != QLatin1Char('>') &&
3452 c != QLatin1Char('{') && c != QLatin1Char('}') &&
3453 c != QLatin1Char('[') && c != QLatin1Char(']'))
3457 delete [] m_maskData;
3458 m_maskData = new MaskInputData[m_maxLength];
3460 MaskInputData::Casemode m = MaskInputData::NoCaseMode;
3463 bool escape = false;
3465 for (int i = 0; i < m_inputMask.length(); i++) {
3466 c = m_inputMask.at(i);
3469 m_maskData[index].maskChar = c;
3470 m_maskData[index].separator = s;
3471 m_maskData[index].caseMode = m;
3474 } else if (c == QLatin1Char('<')) {
3475 m = MaskInputData::Lower;
3476 } else if (c == QLatin1Char('>')) {
3477 m = MaskInputData::Upper;
3478 } else if (c == QLatin1Char('!')) {
3479 m = MaskInputData::NoCaseMode;
3480 } else if (c != QLatin1Char('{') && c != QLatin1Char('}') && c != QLatin1Char('[') && c != QLatin1Char(']')) {
3481 switch (c.unicode()) {
3507 m_maskData[index].maskChar = c;
3508 m_maskData[index].separator = s;
3509 m_maskData[index].caseMode = m;
3514 internalSetText(m_text);
3521 checks if the key is valid compared to the inputMask
3523 bool QQuickTextInputPrivate::isValidInput(QChar key, QChar mask) const
3525 switch (mask.unicode()) {
3531 if (key.isLetter() || key == m_blank)
3535 if (key.isLetterOrNumber())
3539 if (key.isLetterOrNumber() || key == m_blank)
3547 if (key.isPrint() || key == m_blank)
3555 if (key.isNumber() || key == m_blank)
3559 if (key.isNumber() && key.digitValue() > 0)
3563 if ((key.isNumber() && key.digitValue() > 0) || key == m_blank)
3567 if (key.isNumber() || key == QLatin1Char('+') || key == QLatin1Char('-') || key == m_blank)
3571 if (key == QLatin1Char('0') || key == QLatin1Char('1'))
3575 if (key == QLatin1Char('0') || key == QLatin1Char('1') || key == m_blank)
3579 if (key.isNumber() || (key >= QLatin1Char('a') && key <= QLatin1Char('f')) || (key >= QLatin1Char('A') && key <= QLatin1Char('F')))
3583 if (key.isNumber() || (key >= QLatin1Char('a') && key <= QLatin1Char('f')) || (key >= QLatin1Char('A') && key <= QLatin1Char('F')) || key == m_blank)
3595 Returns true if the given text \a str is valid for any
3596 validator or input mask set for the line control.
3598 Otherwise returns false
3600 QQuickTextInputPrivate::ValidatorState QQuickTextInputPrivate::hasAcceptableInput(const QString &str) const
3602 #ifndef QT_NO_VALIDATOR
3603 QString textCopy = str;
3604 int cursorCopy = m_cursor;
3606 QValidator::State state = m_validator->validate(textCopy, cursorCopy);
3607 if (state != QValidator::Acceptable)
3608 return ValidatorState(state);
3613 return AcceptableInput;
3615 if (str.length() != m_maxLength)
3616 return InvalidInput;
3618 for (int i=0; i < m_maxLength; ++i) {
3619 if (m_maskData[i].separator) {
3620 if (str.at(i) != m_maskData[i].maskChar)
3621 return InvalidInput;
3623 if (!isValidInput(str.at(i), m_maskData[i].maskChar))
3624 return InvalidInput;
3627 return AcceptableInput;
3633 Applies the inputMask on \a str starting from position \a pos in the mask. \a clear
3634 specifies from where characters should be gotten when a separator is met in \a str - true means
3635 that blanks will be used, false that previous input is used.
3636 Calling this when no inputMask is set is undefined.
3638 QString QQuickTextInputPrivate::maskString(uint pos, const QString &str, bool clear) const
3640 if (pos >= (uint)m_maxLength)
3641 return QString::fromLatin1("");
3644 fill = clear ? clearString(0, m_maxLength) : m_text;
3647 QString s = QString::fromLatin1("");
3649 while (i < m_maxLength) {
3650 if (strIndex < str.length()) {
3651 if (m_maskData[i].separator) {
3652 s += m_maskData[i].maskChar;
3653 if (str[(int)strIndex] == m_maskData[i].maskChar)
3657 if (isValidInput(str[(int)strIndex], m_maskData[i].maskChar)) {
3658 switch (m_maskData[i].caseMode) {
3659 case MaskInputData::Upper:
3660 s += str[(int)strIndex].toUpper();
3662 case MaskInputData::Lower:
3663 s += str[(int)strIndex].toLower();
3666 s += str[(int)strIndex];
3670 // search for separator first
3671 int n = findInMask(i, true, true, str[(int)strIndex]);
3673 if (str.length() != 1 || i == 0 || (i > 0 && (!m_maskData[i-1].separator || m_maskData[i-1].maskChar != str[(int)strIndex]))) {
3674 s += fill.mid(i, n-i+1);
3675 i = n + 1; // update i to find + 1
3678 // search for valid m_blank if not
3679 n = findInMask(i, true, false, str[(int)strIndex]);
3681 s += fill.mid(i, n-i);
3682 switch (m_maskData[n].caseMode) {
3683 case MaskInputData::Upper:
3684 s += str[(int)strIndex].toUpper();
3686 case MaskInputData::Lower:
3687 s += str[(int)strIndex].toLower();
3690 s += str[(int)strIndex];
3692 i = n + 1; // updates i to find + 1
3710 Returns a "cleared" string with only separators and blank chars.
3711 Calling this when no inputMask is set is undefined.
3713 QString QQuickTextInputPrivate::clearString(uint pos, uint len) const
3715 if (pos >= (uint)m_maxLength)
3719 int end = qMin((uint)m_maxLength, pos + len);
3720 for (int i = pos; i < end; ++i)
3721 if (m_maskData[i].separator)
3722 s += m_maskData[i].maskChar;
3732 Strips blank parts of the input in a QQuickTextInputPrivate when an inputMask is set,
3733 separators are still included. Typically "127.0__.0__.1__" becomes "127.0.0.1".
3735 QString QQuickTextInputPrivate::stripString(const QString &str) const
3741 int end = qMin(m_maxLength, (int)str.length());
3742 for (int i = 0; i < end; ++i) {
3743 if (m_maskData[i].separator)
3744 s += m_maskData[i].maskChar;
3745 else if (str[i] != m_blank)
3754 searches forward/backward in m_maskData for either a separator or a m_blank
3756 int QQuickTextInputPrivate::findInMask(int pos, bool forward, bool findSeparator, QChar searchChar) const
3758 if (pos >= m_maxLength || pos < 0)
3761 int end = forward ? m_maxLength : -1;
3762 int step = forward ? 1 : -1;
3766 if (findSeparator) {
3767 if (m_maskData[i].separator && m_maskData[i].maskChar == searchChar)
3770 if (!m_maskData[i].separator) {
3771 if (searchChar.isNull())
3773 else if (isValidInput(searchChar, m_maskData[i].maskChar))
3782 void QQuickTextInputPrivate::internalUndo(int until)
3784 if (!isUndoAvailable())
3786 cancelPasswordEchoTimer();
3788 while (m_undoState && m_undoState > until) {
3789 Command& cmd = m_history[--m_undoState];
3792 m_text.remove(cmd.pos, 1);
3796 m_selstart = cmd.selStart;
3797 m_selend = cmd.selEnd;
3801 case RemoveSelection:
3802 m_text.insert(cmd.pos, cmd.uc);
3803 m_cursor = cmd.pos + 1;
3806 case DeleteSelection:
3807 m_text.insert(cmd.pos, cmd.uc);
3813 if (until < 0 && m_undoState) {
3814 Command& next = m_history[m_undoState-1];
3815 if (next.type != cmd.type && next.type < RemoveSelection
3816 && (cmd.type < RemoveSelection || next.type == Separator))
3823 void QQuickTextInputPrivate::internalRedo()
3825 if (!isRedoAvailable())
3828 while (m_undoState < (int)m_history.size()) {
3829 Command& cmd = m_history[m_undoState++];
3832 m_text.insert(cmd.pos, cmd.uc);
3833 m_cursor = cmd.pos + 1;
3836 m_selstart = cmd.selStart;
3837 m_selend = cmd.selEnd;
3842 case RemoveSelection:
3843 case DeleteSelection:
3844 m_text.remove(cmd.pos, 1);
3845 m_selstart = cmd.selStart;
3846 m_selend = cmd.selEnd;
3850 m_selstart = cmd.selStart;
3851 m_selend = cmd.selEnd;
3855 if (m_undoState < (int)m_history.size()) {
3856 Command& next = m_history[m_undoState];
3857 if (next.type != cmd.type && cmd.type < RemoveSelection && next.type != Separator
3858 && (next.type < RemoveSelection || cmd.type == Separator))
3865 void QQuickTextInputPrivate::emitUndoRedoChanged()
3867 Q_Q(QQuickTextInput);
3868 const bool previousUndo = canUndo;
3869 const bool previousRedo = canRedo;
3871 canUndo = isUndoAvailable();
3872 canRedo = isRedoAvailable();
3874 if (previousUndo != canUndo)
3875 emit q->canUndoChanged();
3876 if (previousRedo != canRedo)
3877 emit q->canRedoChanged();
3883 If the current cursor position differs from the last emitted cursor
3884 position, emits cursorPositionChanged().
3886 bool QQuickTextInputPrivate::emitCursorPositionChanged()
3888 Q_Q(QQuickTextInput);
3889 if (m_cursor != m_lastCursorPos) {
3890 m_lastCursorPos = m_cursor;
3892 q->updateCursorRectangle();
3893 emit q->cursorPositionChanged();
3895 if (!hasSelectedText()) {
3896 if (lastSelectionStart != m_cursor) {
3897 lastSelectionStart = m_cursor;
3898 emit q->selectionStartChanged();
3900 if (lastSelectionEnd != m_cursor) {
3901 lastSelectionEnd = m_cursor;
3902 emit q->selectionEndChanged();
3906 #ifndef QT_NO_ACCESSIBILITY
3907 QAccessibleTextCursorEvent ev(q, m_cursor);
3908 QAccessible::updateAccessibility(&ev);
3917 void QQuickTextInputPrivate::setCursorBlinkPeriod(int msec)
3919 Q_Q(QQuickTextInput);
3920 if (msec == m_blinkPeriod)
3923 q->killTimer(m_blinkTimer);
3926 m_blinkTimer = q->startTimer(msec / 2);
3930 if (m_blinkStatus == 1) {
3931 updateType = UpdatePaintNode;
3935 m_blinkPeriod = msec;
3938 void QQuickTextInput::timerEvent(QTimerEvent *event)
3940 Q_D(QQuickTextInput);
3941 if (event->timerId() == d->m_blinkTimer) {
3942 d->m_blinkStatus = !d->m_blinkStatus;
3943 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
3945 } else if (event->timerId() == d->m_passwordEchoTimer.timerId()) {
3946 d->m_passwordEchoTimer.stop();
3947 d->updateDisplayText();
3948 updateCursorRectangle();
3952 void QQuickTextInputPrivate::processKeyEvent(QKeyEvent* event)
3954 Q_Q(QQuickTextInput);
3955 bool inlineCompletionAccepted = false;
3957 if (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return) {
3958 if (hasAcceptableInput(m_text) || fixup()) {
3961 if (inlineCompletionAccepted)
3968 if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit
3969 && !m_passwordEchoEditing
3971 && !event->text().isEmpty()
3972 && !(event->modifiers() & Qt::ControlModifier)) {
3973 // Clear the edit and reset to normal echo mode while editing; the
3974 // echo mode switches back when the edit loses focus
3975 // ### resets current content. dubious code; you can
3976 // navigate with keys up, down, back, and select(?), but if you press
3977 // "left" or "right" it clears?
3978 updatePasswordEchoEditing(true);
3982 bool unknown = false;
3983 bool visual = cursorMoveStyle() == Qt::VisualMoveStyle;
3987 #ifndef QT_NO_SHORTCUT
3988 else if (event == QKeySequence::Undo) {
3991 else if (event == QKeySequence::Redo) {
3994 else if (event == QKeySequence::SelectAll) {
3997 #ifndef QT_NO_CLIPBOARD
3998 else if (event == QKeySequence::Copy) {
4001 else if (event == QKeySequence::Paste) {
4003 QClipboard::Mode mode = QClipboard::Clipboard;
4007 else if (event == QKeySequence::Cut) {
4013 else if (event == QKeySequence::DeleteEndOfLine) {
4015 setSelection(m_cursor, end());
4020 #endif //QT_NO_CLIPBOARD
4021 else if (event == QKeySequence::MoveToStartOfLine || event == QKeySequence::MoveToStartOfBlock) {
4024 else if (event == QKeySequence::MoveToEndOfLine || event == QKeySequence::MoveToEndOfBlock) {
4027 else if (event == QKeySequence::SelectStartOfLine || event == QKeySequence::SelectStartOfBlock) {
4030 else if (event == QKeySequence::SelectEndOfLine || event == QKeySequence::SelectEndOfBlock) {
4033 else if (event == QKeySequence::MoveToNextChar) {
4034 if (hasSelectedText()) {
4035 moveCursor(selectionEnd(), false);
4037 cursorForward(0, visual ? 1 : (layoutDirection() == Qt::LeftToRight ? 1 : -1));
4040 else if (event == QKeySequence::SelectNextChar) {
4041 cursorForward(1, visual ? 1 : (layoutDirection() == Qt::LeftToRight ? 1 : -1));
4043 else if (event == QKeySequence::MoveToPreviousChar) {
4044 if (hasSelectedText()) {
4045 moveCursor(selectionStart(), false);
4047 cursorForward(0, visual ? -1 : (layoutDirection() == Qt::LeftToRight ? -1 : 1));
4050 else if (event == QKeySequence::SelectPreviousChar) {
4051 cursorForward(1, visual ? -1 : (layoutDirection() == Qt::LeftToRight ? -1 : 1));
4053 else if (event == QKeySequence::MoveToNextWord) {
4054 if (m_echoMode == QQuickTextInput::Normal)
4055 layoutDirection() == Qt::LeftToRight ? cursorWordForward(0) : cursorWordBackward(0);
4057 layoutDirection() == Qt::LeftToRight ? end(0) : home(0);
4059 else if (event == QKeySequence::MoveToPreviousWord) {
4060 if (m_echoMode == QQuickTextInput::Normal)
4061 layoutDirection() == Qt::LeftToRight ? cursorWordBackward(0) : cursorWordForward(0);
4062 else if (!m_readOnly) {
4063 layoutDirection() == Qt::LeftToRight ? home(0) : end(0);
4066 else if (event == QKeySequence::SelectNextWord) {
4067 if (m_echoMode == QQuickTextInput::Normal)
4068 layoutDirection() == Qt::LeftToRight ? cursorWordForward(1) : cursorWordBackward(1);
4070 layoutDirection() == Qt::LeftToRight ? end(1) : home(1);
4072 else if (event == QKeySequence::SelectPreviousWord) {
4073 if (m_echoMode == QQuickTextInput::Normal)
4074 layoutDirection() == Qt::LeftToRight ? cursorWordBackward(1) : cursorWordForward(1);
4076 layoutDirection() == Qt::LeftToRight ? home(1) : end(1);
4078 else if (event == QKeySequence::Delete) {
4082 else if (event == QKeySequence::DeleteEndOfWord) {
4084 cursorWordForward(true);
4088 else if (event == QKeySequence::DeleteStartOfWord) {
4090 cursorWordBackward(true);
4094 #endif // QT_NO_SHORTCUT
4096 bool handled = false;
4097 if (event->modifiers() & Qt::ControlModifier) {
4098 switch (event->key()) {
4099 case Qt::Key_Backspace:
4101 cursorWordBackward(true);
4109 } else { // ### check for *no* modifier
4110 switch (event->key()) {
4111 case Qt::Key_Backspace:
4123 if (event->key() == Qt::Key_Direction_L || event->key() == Qt::Key_Direction_R) {
4124 setLayoutDirection((event->key() == Qt::Key_Direction_L) ? Qt::LeftToRight : Qt::RightToLeft);
4128 if (unknown && !m_readOnly) {
4129 QString t = event->text();
4130 if (!t.isEmpty() && t.at(0).isPrint()) {