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);
137 \qmlproperty int QtQuick2::TextInput::length
139 Returns the total number of characters in the TextInput item.
141 If the TextInput has an inputMask the length will include mask characters and may differ
142 from the length of the string returned by the \l text property.
144 This property can be faster than querying the length the \l text property as it doesn't
145 require any copying or conversion of the TextInput's internal string data.
148 int QQuickTextInput::length() const
150 Q_D(const QQuickTextInput);
151 return d->m_text.length();
155 \qmlmethod string QtQuick2::TextInput::getText(int start, int end)
157 Returns the section of text that is between the \a start and \a end positions.
159 If the TextInput has an inputMask the length will include mask characters.
162 QString QQuickTextInput::getText(int start, int end) const
164 Q_D(const QQuickTextInput);
169 return d->m_text.mid(start, end - start);
172 QString QQuickTextInputPrivate::realText() const
174 QString res = m_maskData ? stripString(m_text) : m_text;
175 return (res.isNull() ? QString::fromLatin1("") : res);
179 \qmlproperty string QtQuick2::TextInput::font.family
181 Sets the family name of the font.
183 The family name is case insensitive and may optionally include a foundry name, e.g. "Helvetica [Cronyx]".
184 If the family is available from more than one foundry and the foundry isn't specified, an arbitrary foundry is chosen.
185 If the family isn't available a family will be set using the font matching algorithm.
189 \qmlproperty bool QtQuick2::TextInput::font.bold
191 Sets whether the font weight is bold.
195 \qmlproperty enumeration QtQuick2::TextInput::font.weight
197 Sets the font's weight.
199 The weight can be one of:
202 \li Font.Normal - the default
209 TextInput { text: "Hello"; font.weight: Font.DemiBold }
214 \qmlproperty bool QtQuick2::TextInput::font.italic
216 Sets whether the font has an italic style.
220 \qmlproperty bool QtQuick2::TextInput::font.underline
222 Sets whether the text is underlined.
226 \qmlproperty bool QtQuick2::TextInput::font.strikeout
228 Sets whether the font has a strikeout style.
232 \qmlproperty real QtQuick2::TextInput::font.pointSize
234 Sets the font size in points. The point size must be greater than zero.
238 \qmlproperty int QtQuick2::TextInput::font.pixelSize
240 Sets the font size in pixels.
242 Using this function makes the font device dependent.
243 Use \c pointSize to set the size of the font in a device independent manner.
247 \qmlproperty real QtQuick2::TextInput::font.letterSpacing
249 Sets the letter spacing for the font.
251 Letter spacing changes the default spacing between individual letters in the font.
252 A positive value increases the letter spacing by the corresponding pixels; a negative value decreases the spacing.
256 \qmlproperty real QtQuick2::TextInput::font.wordSpacing
258 Sets the word spacing for the font.
260 Word spacing changes the default spacing between individual words.
261 A positive value increases the word spacing by a corresponding amount of pixels,
262 while a negative value decreases the inter-word spacing accordingly.
266 \qmlproperty enumeration QtQuick2::TextInput::font.capitalization
268 Sets the capitalization for the text.
271 \li Font.MixedCase - This is the normal text rendering option where no capitalization change is applied.
272 \li Font.AllUppercase - This alters the text to be rendered in all uppercase type.
273 \li Font.AllLowercase - This alters the text to be rendered in all lowercase type.
274 \li Font.SmallCaps - This alters the text to be rendered in small-caps type.
275 \li Font.Capitalize - This alters the text to be rendered with the first character of each word as an uppercase character.
279 TextInput { text: "Hello"; font.capitalization: Font.AllLowercase }
283 QFont QQuickTextInput::font() const
285 Q_D(const QQuickTextInput);
286 return d->sourceFont;
289 void QQuickTextInput::setFont(const QFont &font)
291 Q_D(QQuickTextInput);
292 if (d->sourceFont == font)
295 d->sourceFont = font;
296 QFont oldFont = d->font;
298 if (d->font.pointSizeF() != -1) {
300 qreal size = qRound(d->font.pointSizeF()*2.0);
301 d->font.setPointSizeF(size/2.0);
303 if (oldFont != d->font) {
305 updateCursorRectangle();
306 updateInputMethod(Qt::ImCursorRectangle | Qt::ImFont);
308 emit fontChanged(d->sourceFont);
312 \qmlproperty color QtQuick2::TextInput::color
316 QColor QQuickTextInput::color() const
318 Q_D(const QQuickTextInput);
322 void QQuickTextInput::setColor(const QColor &c)
324 Q_D(QQuickTextInput);
327 d->textLayoutDirty = true;
328 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
336 \qmlproperty color QtQuick2::TextInput::selectionColor
338 The text highlight color, used behind selections.
340 QColor QQuickTextInput::selectionColor() const
342 Q_D(const QQuickTextInput);
343 return d->selectionColor;
346 void QQuickTextInput::setSelectionColor(const QColor &color)
348 Q_D(QQuickTextInput);
349 if (d->selectionColor == color)
352 d->selectionColor = color;
353 if (d->hasSelectedText()) {
354 d->textLayoutDirty = true;
355 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
358 emit selectionColorChanged();
361 \qmlproperty color QtQuick2::TextInput::selectedTextColor
363 The highlighted text color, used in selections.
365 QColor QQuickTextInput::selectedTextColor() const
367 Q_D(const QQuickTextInput);
368 return d->selectedTextColor;
371 void QQuickTextInput::setSelectedTextColor(const QColor &color)
373 Q_D(QQuickTextInput);
374 if (d->selectedTextColor == color)
377 d->selectedTextColor = color;
378 if (d->hasSelectedText()) {
379 d->textLayoutDirty = true;
380 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
383 emit selectedTextColorChanged();
387 \qmlproperty enumeration QtQuick2::TextInput::horizontalAlignment
388 \qmlproperty enumeration QtQuick2::TextInput::effectiveHorizontalAlignment
389 \qmlproperty enumeration QtQuick2::TextInput::verticalAlignment
391 Sets the horizontal alignment of the text within the TextInput item's
392 width and height. By default, the text alignment follows the natural alignment
393 of the text, for example text that is read from left to right will be aligned to
396 TextInput does not have vertical alignment, as the natural height is
397 exactly the height of the single line of text. If you set the height
398 manually to something larger, TextInput will always be top aligned
399 vertically. You can use anchors to align it however you want within
402 The valid values for \c horizontalAlignment are \c TextInput.AlignLeft, \c TextInput.AlignRight and
403 \c TextInput.AlignHCenter.
405 Valid values for \c verticalAlignment are \c TextInput.AlignTop (default),
406 \c TextInput.AlignBottom \c TextInput.AlignVCenter.
408 When using the attached property LayoutMirroring::enabled to mirror application
409 layouts, the horizontal alignment of text will also be mirrored. However, the property
410 \c horizontalAlignment will remain unchanged. To query the effective horizontal alignment
411 of TextInput, use the read-only property \c effectiveHorizontalAlignment.
413 QQuickTextInput::HAlignment QQuickTextInput::hAlign() const
415 Q_D(const QQuickTextInput);
419 void QQuickTextInput::setHAlign(HAlignment align)
421 Q_D(QQuickTextInput);
422 bool forceAlign = d->hAlignImplicit && d->effectiveLayoutMirror;
423 d->hAlignImplicit = false;
424 if (d->setHAlign(align, forceAlign) && isComponentComplete()) {
426 updateCursorRectangle();
430 void QQuickTextInput::resetHAlign()
432 Q_D(QQuickTextInput);
433 d->hAlignImplicit = true;
434 if (d->determineHorizontalAlignment() && isComponentComplete()) {
436 updateCursorRectangle();
440 QQuickTextInput::HAlignment QQuickTextInput::effectiveHAlign() const
442 Q_D(const QQuickTextInput);
443 QQuickTextInput::HAlignment effectiveAlignment = d->hAlign;
444 if (!d->hAlignImplicit && d->effectiveLayoutMirror) {
446 case QQuickTextInput::AlignLeft:
447 effectiveAlignment = QQuickTextInput::AlignRight;
449 case QQuickTextInput::AlignRight:
450 effectiveAlignment = QQuickTextInput::AlignLeft;
456 return effectiveAlignment;
459 bool QQuickTextInputPrivate::setHAlign(QQuickTextInput::HAlignment alignment, bool forceAlign)
461 Q_Q(QQuickTextInput);
462 if ((hAlign != alignment || forceAlign) && alignment <= QQuickTextInput::AlignHCenter) { // justify not supported
463 QQuickTextInput::HAlignment oldEffectiveHAlign = q->effectiveHAlign();
465 emit q->horizontalAlignmentChanged(alignment);
466 if (oldEffectiveHAlign != q->effectiveHAlign())
467 emit q->effectiveHorizontalAlignmentChanged();
473 Qt::LayoutDirection QQuickTextInputPrivate::textDirection() const
475 QString text = m_text;
477 text = m_textLayout.preeditAreaText();
479 const QChar *character = text.constData();
480 while (!character->isNull()) {
481 switch (character->direction()) {
483 return Qt::LeftToRight;
487 return Qt::RightToLeft;
493 return Qt::LayoutDirectionAuto;
496 Qt::LayoutDirection QQuickTextInputPrivate::layoutDirection() const
498 Qt::LayoutDirection direction = m_layoutDirection;
499 if (direction == Qt::LayoutDirectionAuto) {
500 direction = textDirection();
501 if (direction == Qt::LayoutDirectionAuto)
502 direction = qApp->inputMethod()->inputDirection();
504 return (direction == Qt::LayoutDirectionAuto) ? Qt::LeftToRight : direction;
507 bool QQuickTextInputPrivate::determineHorizontalAlignment()
509 if (hAlignImplicit) {
510 // if no explicit alignment has been set, follow the natural layout direction of the text
511 Qt::LayoutDirection direction = textDirection();
512 if (direction == Qt::LayoutDirectionAuto)
513 direction = qApp->inputMethod()->inputDirection();
514 return setHAlign(direction == Qt::RightToLeft ? QQuickTextInput::AlignRight : QQuickTextInput::AlignLeft);
519 QQuickTextInput::VAlignment QQuickTextInput::vAlign() const
521 Q_D(const QQuickTextInput);
525 void QQuickTextInput::setVAlign(QQuickTextInput::VAlignment alignment)
527 Q_D(QQuickTextInput);
528 if (alignment == d->vAlign)
530 d->vAlign = alignment;
531 emit verticalAlignmentChanged(d->vAlign);
532 if (isComponentComplete()) {
533 updateCursorRectangle();
538 \qmlproperty enumeration QtQuick2::TextInput::wrapMode
540 Set this property to wrap the text to the TextInput item's width.
541 The text will only wrap if an explicit width has been set.
544 \li TextInput.NoWrap - no wrapping will be performed. If the text contains insufficient newlines, then implicitWidth will exceed a set width.
545 \li TextInput.WordWrap - wrapping is done on word boundaries only. If a word is too long, implicitWidth will exceed a set width.
546 \li TextInput.WrapAnywhere - wrapping is done at any point on a line, even if it occurs in the middle of a word.
547 \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.
550 The default is TextInput.NoWrap. If you set a width, consider using TextInput.Wrap.
552 QQuickTextInput::WrapMode QQuickTextInput::wrapMode() const
554 Q_D(const QQuickTextInput);
558 void QQuickTextInput::setWrapMode(WrapMode mode)
560 Q_D(QQuickTextInput);
561 if (mode == d->wrapMode)
565 updateCursorRectangle();
566 emit wrapModeChanged();
569 void QQuickTextInputPrivate::mirrorChange()
571 Q_Q(QQuickTextInput);
572 if (q->isComponentComplete()) {
573 if (!hAlignImplicit && (hAlign == QQuickTextInput::AlignRight || hAlign == QQuickTextInput::AlignLeft)) {
574 q->updateCursorRectangle();
575 emit q->effectiveHorizontalAlignmentChanged();
581 \qmlproperty bool QtQuick2::TextInput::readOnly
583 Sets whether user input can modify the contents of the TextInput.
585 If readOnly is set to true, then user input will not affect the text
586 property. Any bindings or attempts to set the text property will still
589 bool QQuickTextInput::isReadOnly() const
591 Q_D(const QQuickTextInput);
592 return d->m_readOnly;
595 void QQuickTextInput::setReadOnly(bool ro)
597 Q_D(QQuickTextInput);
598 if (d->m_readOnly == ro)
601 setFlag(QQuickItem::ItemAcceptsInputMethod, !ro);
604 d->setCursorPosition(d->end());
605 updateInputMethod(Qt::ImEnabled);
607 d->emitUndoRedoChanged();
608 emit readOnlyChanged(ro);
612 \qmlproperty int QtQuick2::TextInput::maximumLength
613 The maximum permitted length of the text in the TextInput.
615 If the text is too long, it is truncated at the limit.
617 By default, this property contains a value of 32767.
619 int QQuickTextInput::maxLength() const
621 Q_D(const QQuickTextInput);
622 return d->m_maxLength;
625 void QQuickTextInput::setMaxLength(int ml)
627 Q_D(QQuickTextInput);
628 if (d->m_maxLength == ml || d->m_maskData)
632 d->internalSetText(d->m_text, -1, false);
634 emit maximumLengthChanged(ml);
638 \qmlproperty bool QtQuick2::TextInput::cursorVisible
639 Set to true when the TextInput shows a cursor.
641 This property is set and unset when the TextInput gets active focus, so that other
642 properties can be bound to whether the cursor is currently showing. As it
643 gets set and unset automatically, when you set the value yourself you must
644 keep in mind that your value may be overwritten.
646 It can be set directly in script, for example if a KeyProxy might
647 forward keys to it and you desire it to look active when this happens
648 (but without actually giving it active focus).
650 It should not be set directly on the element, like in the below QML,
651 as the specified value will be overridden an lost on focus changes.
660 In the above snippet the cursor will still become visible when the
661 TextInput gains active focus.
663 bool QQuickTextInput::isCursorVisible() const
665 Q_D(const QQuickTextInput);
666 return d->cursorVisible;
669 void QQuickTextInput::setCursorVisible(bool on)
671 Q_D(QQuickTextInput);
672 if (d->cursorVisible == on)
674 d->cursorVisible = on;
675 if (on && isComponentComplete())
676 QQuickTextUtil::createCursor(d);
677 if (!d->cursorItem) {
678 d->setCursorBlinkPeriod(on ? qApp->styleHints()->cursorFlashTime() : 0);
679 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
682 emit cursorVisibleChanged(d->cursorVisible);
686 \qmlproperty int QtQuick2::TextInput::cursorPosition
687 The position of the cursor in the TextInput.
689 int QQuickTextInput::cursorPosition() const
691 Q_D(const QQuickTextInput);
695 void QQuickTextInput::setCursorPosition(int cp)
697 Q_D(QQuickTextInput);
698 if (cp < 0 || cp > text().length())
704 \qmlproperty rectangle QtQuick2::TextInput::cursorRectangle
706 The rectangle where the standard text cursor is rendered within the text input. Read only.
708 The position and height of a custom cursorDelegate are updated to follow the cursorRectangle
709 automatically when it changes. The width of the delegate is unaffected by changes in the
713 QRectF QQuickTextInput::cursorRectangle() const
715 Q_D(const QQuickTextInput);
717 int c = d->m_cursor + d->m_preeditCursor;
718 if (d->m_echoMode == NoEcho)
720 QTextLine l = d->m_textLayout.lineForTextPosition(c);
723 return QRectF(l.cursorToX(c) - d->hscroll, l.y() - d->vscroll, 1, l.height());
727 \qmlproperty int QtQuick2::TextInput::selectionStart
729 The cursor position before the first character in the current selection.
731 This property is read-only. To change the selection, use select(start,end),
732 selectAll(), or selectWord().
734 \sa selectionEnd, cursorPosition, selectedText
736 int QQuickTextInput::selectionStart() const
738 Q_D(const QQuickTextInput);
739 return d->lastSelectionStart;
742 \qmlproperty int QtQuick2::TextInput::selectionEnd
744 The cursor position after the last character in the current selection.
746 This property is read-only. To change the selection, use select(start,end),
747 selectAll(), or selectWord().
749 \sa selectionStart, cursorPosition, selectedText
751 int QQuickTextInput::selectionEnd() const
753 Q_D(const QQuickTextInput);
754 return d->lastSelectionEnd;
757 \qmlmethod void QtQuick2::TextInput::select(int start, int end)
759 Causes the text from \a start to \a end to be selected.
761 If either start or end is out of range, the selection is not changed.
763 After calling this, selectionStart will become the lesser
764 and selectionEnd will become the greater (regardless of the order passed
767 \sa selectionStart, selectionEnd
769 void QQuickTextInput::select(int start, int end)
771 Q_D(QQuickTextInput);
772 if (start < 0 || end < 0 || start > d->m_text.length() || end > d->m_text.length())
774 d->setSelection(start, end-start);
778 \qmlproperty string QtQuick2::TextInput::selectedText
780 This read-only property provides the text currently selected in the
783 It is equivalent to the following snippet, but is faster and easier
787 myTextInput.text.toString().substring(myTextInput.selectionStart,
788 myTextInput.selectionEnd);
791 QString QQuickTextInput::selectedText() const
793 Q_D(const QQuickTextInput);
794 return d->selectedText();
798 \qmlproperty bool QtQuick2::TextInput::activeFocusOnPress
800 Whether the TextInput should gain active focus on a mouse press. By default this is
803 bool QQuickTextInput::focusOnPress() const
805 Q_D(const QQuickTextInput);
806 return d->focusOnPress;
809 void QQuickTextInput::setFocusOnPress(bool b)
811 Q_D(QQuickTextInput);
812 if (d->focusOnPress == b)
817 emit activeFocusOnPressChanged(d->focusOnPress);
820 \qmlproperty bool QtQuick2::TextInput::autoScroll
822 Whether the TextInput should scroll when the text is longer than the width. By default this is
825 bool QQuickTextInput::autoScroll() const
827 Q_D(const QQuickTextInput);
828 return d->autoScroll;
831 void QQuickTextInput::setAutoScroll(bool b)
833 Q_D(QQuickTextInput);
834 if (d->autoScroll == b)
838 //We need to repaint so that the scrolling is taking into account.
839 updateCursorRectangle();
840 emit autoScrollChanged(d->autoScroll);
843 #ifndef QT_NO_VALIDATOR
846 \qmlclass IntValidator QIntValidator
847 \inqmlmodule QtQuick 2
848 \ingroup qtquick-text-utility
849 \brief Defines a validator for integer values
851 This element provides a validator for integer values.
853 If no \l locale is set IntValidator uses the \l {QLocale::setDefault()}{default locale} to
854 interpret the number and will accept locale specific digits, group separators, and positive
855 and negative signs. In addition, IntValidator is always guaranteed to accept a number
856 formatted according to the "C" locale.
860 QQuickIntValidator::QQuickIntValidator(QObject *parent)
861 : QIntValidator(parent)
866 \qmlproperty string QtQuick2::IntValidator::locale
868 This property holds the name of the locale used to interpret the number.
873 QString QQuickIntValidator::localeName() const
875 return locale().name();
878 void QQuickIntValidator::setLocaleName(const QString &name)
880 if (locale().name() != name) {
881 setLocale(QLocale(name));
882 emit localeNameChanged();
886 void QQuickIntValidator::resetLocaleName()
888 QLocale defaultLocale;
889 if (locale() != defaultLocale) {
890 setLocale(defaultLocale);
891 emit localeNameChanged();
896 \qmlproperty int QtQuick2::IntValidator::top
898 This property holds the validator's highest acceptable value.
899 By default, this property's value is derived from the highest signed integer available (typically 2147483647).
902 \qmlproperty int QtQuick2::IntValidator::bottom
904 This property holds the validator's lowest acceptable value.
905 By default, this property's value is derived from the lowest signed integer available (typically -2147483647).
909 \qmlclass DoubleValidator QDoubleValidator
910 \inqmlmodule QtQuick 2
911 \ingroup qtquick-text-utility
912 \brief Defines a validator for non-integer numbers
914 This element provides a validator for non-integer numbers.
916 Input is accepted if it contains a double that is within the valid range
917 and is in the correct format.
919 Input is accepected but invalid if it contains a double that is outside
920 the range or is in the wrong format; e.g. with too many digits after the
921 decimal point or is empty.
923 Input is rejected if it is not a double.
925 Note: If the valid range consists of just positive doubles (e.g. 0.0 to
926 100.0) and input is a negative double then it is rejected. If \l notation
927 is set to DoubleValidator.StandardNotation, and the input contains more
928 digits before the decimal point than a double in the valid range may have,
929 it is also rejected. If \l notation is DoubleValidator.ScientificNotation,
930 and the input is not in the valid range, it is accecpted but invalid. The
931 value may yet become valid by changing the exponent.
934 QQuickDoubleValidator::QQuickDoubleValidator(QObject *parent)
935 : QDoubleValidator(parent)
940 \qmlproperty string QtQuick2::DoubleValidator::locale
942 This property holds the name of the locale used to interpret the number.
947 QString QQuickDoubleValidator::localeName() const
949 return locale().name();
952 void QQuickDoubleValidator::setLocaleName(const QString &name)
954 if (locale().name() != name) {
955 setLocale(QLocale(name));
956 emit localeNameChanged();
960 void QQuickDoubleValidator::resetLocaleName()
962 QLocale defaultLocale;
963 if (locale() != defaultLocale) {
964 setLocale(defaultLocale);
965 emit localeNameChanged();
970 \qmlproperty real QtQuick2::DoubleValidator::top
972 This property holds the validator's maximum acceptable value.
973 By default, this property contains a value of infinity.
976 \qmlproperty real QtQuick2::DoubleValidator::bottom
978 This property holds the validator's minimum acceptable value.
979 By default, this property contains a value of -infinity.
982 \qmlproperty int QtQuick2::DoubleValidator::decimals
984 This property holds the validator's maximum number of digits after the decimal point.
985 By default, this property contains a value of 1000.
988 \qmlproperty enumeration QtQuick2::DoubleValidator::notation
989 This property holds the notation of how a string can describe a number.
991 The possible values for this property are:
994 \li DoubleValidator.StandardNotation
995 \li DoubleValidator.ScientificNotation (default)
998 If this property is set to DoubleValidator.ScientificNotation, the written number may have an exponent part (e.g. 1.5E-2).
1002 \qmlclass RegExpValidator QRegExpValidator
1003 \inqmlmodule QtQuick 2
1004 \ingroup qtquick-text-utility
1005 \brief Provides a string validator
1007 This element provides a validator, which counts as valid any string which
1008 matches a specified regular expression.
1011 \qmlproperty regExp QtQuick2::RegExpValidator::regExp
1013 This property holds the regular expression used for validation.
1015 Note that this property should be a regular expression in JS syntax, e.g /a/ for the regular expression
1018 By default, this property contains a regular expression with the pattern .* that matches any string.
1022 \qmlproperty Validator QtQuick2::TextInput::validator
1024 Allows you to set a validator on the TextInput. When a validator is set
1025 the TextInput will only accept input which leaves the text property in
1026 an acceptable or intermediate state. The accepted signal will only be sent
1027 if the text is in an acceptable state when enter is pressed.
1029 Currently supported validators are IntValidator, DoubleValidator and
1030 RegExpValidator. An example of using validators is shown below, which allows
1031 input of integers between 11 and 31 into the text input:
1036 validator: IntValidator{bottom: 11; top: 31;}
1041 \sa acceptableInput, inputMask
1044 QValidator* QQuickTextInput::validator() const
1046 Q_D(const QQuickTextInput);
1047 return d->m_validator;
1050 void QQuickTextInput::setValidator(QValidator* v)
1052 Q_D(QQuickTextInput);
1053 if (d->m_validator == v)
1058 if (isComponentComplete())
1061 emit validatorChanged();
1064 #endif // QT_NO_VALIDATOR
1066 void QQuickTextInputPrivate::checkIsValid()
1068 Q_Q(QQuickTextInput);
1070 ValidatorState state = hasAcceptableInput(m_text);
1071 m_validInput = state != InvalidInput;
1072 if (state != AcceptableInput) {
1073 if (m_acceptableInput) {
1074 m_acceptableInput = false;
1075 emit q->acceptableInputChanged();
1077 } else if (!m_acceptableInput) {
1078 m_acceptableInput = true;
1079 emit q->acceptableInputChanged();
1084 \qmlproperty string QtQuick2::TextInput::inputMask
1086 Allows you to set an input mask on the TextInput, restricting the allowable
1087 text inputs. See QLineEdit::inputMask for further details, as the exact
1088 same mask strings are used by TextInput.
1090 \sa acceptableInput, validator
1092 QString QQuickTextInput::inputMask() const
1094 Q_D(const QQuickTextInput);
1095 return d->inputMask();
1098 void QQuickTextInput::setInputMask(const QString &im)
1100 Q_D(QQuickTextInput);
1101 if (d->inputMask() == im)
1104 d->setInputMask(im);
1105 emit inputMaskChanged(d->inputMask());
1109 \qmlproperty bool QtQuick2::TextInput::acceptableInput
1111 This property is always true unless a validator or input mask has been set.
1112 If a validator or input mask has been set, this property will only be true
1113 if the current text is acceptable to the validator or input mask as a final
1114 string (not as an intermediate string).
1116 bool QQuickTextInput::hasAcceptableInput() const
1118 Q_D(const QQuickTextInput);
1119 return d->hasAcceptableInput(d->m_text) == QQuickTextInputPrivate::AcceptableInput;
1123 \qmlsignal QtQuick2::TextInput::onAccepted()
1125 This handler is called when the Return or Enter key is pressed.
1126 Note that if there is a \l validator or \l inputMask set on the text
1127 input, the handler will only be emitted if the input is in an acceptable
1131 Qt::InputMethodHints QQuickTextInputPrivate::effectiveInputMethodHints() const
1133 Qt::InputMethodHints hints = inputMethodHints;
1134 if (m_echoMode == QQuickTextInput::Password || m_echoMode == QQuickTextInput::NoEcho)
1135 hints |= Qt::ImhHiddenText;
1136 else if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit)
1137 hints &= ~Qt::ImhHiddenText;
1138 if (m_echoMode != QQuickTextInput::Normal)
1139 hints |= (Qt::ImhNoAutoUppercase | Qt::ImhNoPredictiveText | Qt::ImhSensitiveData);
1143 \qmlproperty enumeration QtQuick2::TextInput::echoMode
1145 Specifies how the text should be displayed in the TextInput.
1147 \li TextInput.Normal - Displays the text as it is. (Default)
1148 \li TextInput.Password - Displays asterisks instead of characters.
1149 \li TextInput.NoEcho - Displays nothing.
1150 \li TextInput.PasswordEchoOnEdit - Displays characters as they are entered
1151 while editing, otherwise displays asterisks.
1154 QQuickTextInput::EchoMode QQuickTextInput::echoMode() const
1156 Q_D(const QQuickTextInput);
1157 return QQuickTextInput::EchoMode(d->m_echoMode);
1160 void QQuickTextInput::setEchoMode(QQuickTextInput::EchoMode echo)
1162 Q_D(QQuickTextInput);
1163 if (echoMode() == echo)
1165 d->cancelPasswordEchoTimer();
1166 d->m_echoMode = echo;
1167 d->m_passwordEchoEditing = false;
1168 updateInputMethod(Qt::ImHints);
1169 d->updateDisplayText();
1170 updateCursorRectangle();
1172 emit echoModeChanged(echoMode());
1176 \qmlproperty enumeration QtQuick2::TextInput::inputMethodHints
1178 Provides hints to the input method about the expected content of the text input and how it
1181 The value is a bit-wise combination of flags, or Qt.ImhNone if no hints are set.
1183 Flags that alter behaviour are:
1186 \li Qt.ImhHiddenText - Characters should be hidden, as is typically used when entering passwords.
1187 This is automatically set when setting echoMode to \c TextInput.Password.
1188 \li Qt.ImhSensitiveData - Typed text should not be stored by the active input method
1189 in any persistent storage like predictive user dictionary.
1190 \li Qt.ImhNoAutoUppercase - The input method should not try to automatically switch to upper case
1191 when a sentence ends.
1192 \li Qt.ImhPreferNumbers - Numbers are preferred (but not required).
1193 \li Qt.ImhPreferUppercase - Upper case letters are preferred (but not required).
1194 \li Qt.ImhPreferLowercase - Lower case letters are preferred (but not required).
1195 \li Qt.ImhNoPredictiveText - Do not use predictive text (i.e. dictionary lookup) while typing.
1197 \li Qt.ImhDate - The text editor functions as a date field.
1198 \li Qt.ImhTime - The text editor functions as a time field.
1201 Flags that restrict input (exclusive flags) are:
1204 \li Qt.ImhDigitsOnly - Only digits are allowed.
1205 \li Qt.ImhFormattedNumbersOnly - Only number input is allowed. This includes decimal point and minus sign.
1206 \li Qt.ImhUppercaseOnly - Only upper case letter input is allowed.
1207 \li Qt.ImhLowercaseOnly - Only lower case letter input is allowed.
1208 \li Qt.ImhDialableCharactersOnly - Only characters suitable for phone dialing are allowed.
1209 \li Qt.ImhEmailCharactersOnly - Only characters suitable for email addresses are allowed.
1210 \li Qt.ImhUrlCharactersOnly - Only characters suitable for URLs are allowed.
1216 \li Qt.ImhExclusiveInputMask - This mask yields nonzero if any of the exclusive flags are used.
1220 Qt::InputMethodHints QQuickTextInput::inputMethodHints() const
1222 Q_D(const QQuickTextInput);
1223 return d->inputMethodHints;
1226 void QQuickTextInput::setInputMethodHints(Qt::InputMethodHints hints)
1228 Q_D(QQuickTextInput);
1230 if (hints == d->inputMethodHints)
1233 d->inputMethodHints = hints;
1234 updateInputMethod(Qt::ImHints);
1235 emit inputMethodHintsChanged();
1239 \qmlproperty Component QtQuick2::TextInput::cursorDelegate
1240 The delegate for the cursor in the TextInput.
1242 If you set a cursorDelegate for a TextInput, this delegate will be used for
1243 drawing the cursor instead of the standard cursor. An instance of the
1244 delegate will be created and managed by the TextInput when a cursor is
1245 needed, and the x property of delegate instance will be set so as
1246 to be one pixel before the top left of the current character.
1248 Note that the root item of the delegate component must be a QQuickItem or
1249 QQuickItem derived item.
1251 QQmlComponent* QQuickTextInput::cursorDelegate() const
1253 Q_D(const QQuickTextInput);
1254 return d->cursorComponent;
1257 void QQuickTextInput::setCursorDelegate(QQmlComponent* c)
1259 Q_D(QQuickTextInput);
1260 QQuickTextUtil::setCursorDelegate(d, c);
1263 void QQuickTextInput::createCursor()
1265 Q_D(QQuickTextInput);
1266 d->cursorPending = true;
1267 QQuickTextUtil::createCursor(d);
1271 \qmlmethod rect QtQuick2::TextInput::positionToRectangle(int pos)
1273 This function takes a character position and returns the rectangle that the
1274 cursor would occupy, if it was placed at that character position.
1276 This is similar to setting the cursorPosition, and then querying the cursor
1277 rectangle, but the cursorPosition is not changed.
1279 QRectF QQuickTextInput::positionToRectangle(int pos) const
1281 Q_D(const QQuickTextInput);
1282 if (d->m_echoMode == NoEcho)
1284 else if (pos > d->m_cursor)
1285 pos += d->preeditAreaText().length();
1286 QTextLine l = d->m_textLayout.lineForTextPosition(pos);
1288 ? QRectF(l.cursorToX(pos) - d->hscroll, l.y() - d->vscroll, 1, l.height())
1293 \qmlmethod int QtQuick2::TextInput::positionAt(real x, real y, CursorPosition position = CursorBetweenCharacters)
1295 This function returns the character position at
1296 x and y pixels from the top left of the textInput. Position 0 is before the
1297 first character, position 1 is after the first character but before the second,
1298 and so on until position text.length, which is after all characters.
1300 This means that for all x values before the first character this function returns 0,
1301 and for all x values after the last character this function returns text.length. If
1302 the y value is above the text the position will be that of the nearest character on
1303 the first line line and if it is below the text the position of the nearest character
1304 on the last line will be returned.
1306 The cursor position type specifies how the cursor position should be resolved.
1309 \li TextInput.CursorBetweenCharacters - Returns the position between characters that is nearest x.
1310 \li TextInput.CursorOnCharacter - Returns the position before the character that is nearest x.
1314 void QQuickTextInput::positionAt(QQmlV8Function *args) const
1316 Q_D(const QQuickTextInput);
1320 QTextLine::CursorPosition position = QTextLine::CursorBetweenCharacters;
1322 if (args->Length() < 1)
1326 v8::Local<v8::Value> arg = (*args)[i];
1327 x = arg->NumberValue();
1329 if (++i < args->Length()) {
1331 y = arg->NumberValue();
1334 if (++i < args->Length()) {
1336 position = QTextLine::CursorPosition(arg->Int32Value());
1339 int pos = d->positionAt(x, y, position);
1340 const int cursor = d->m_cursor;
1342 const int preeditLength = d->preeditAreaText().length();
1343 pos = pos > cursor + preeditLength
1344 ? pos - preeditLength
1347 args->returnValue(v8::Int32::New(pos));
1350 int QQuickTextInputPrivate::positionAt(qreal x, qreal y, QTextLine::CursorPosition position) const
1354 QTextLine line = m_textLayout.lineAt(0);
1355 for (int i = 1; i < m_textLayout.lineCount(); ++i) {
1356 QTextLine nextLine = m_textLayout.lineAt(i);
1358 if (y < (line.rect().bottom() + nextLine.y()) / 2)
1362 return line.isValid() ? line.xToCursor(x, position) : 0;
1365 void QQuickTextInput::keyPressEvent(QKeyEvent* ev)
1367 Q_D(QQuickTextInput);
1368 // Don't allow MacOSX up/down support, and we don't allow a completer.
1369 bool ignore = (ev->key() == Qt::Key_Up || ev->key() == Qt::Key_Down) && ev->modifiers() == Qt::NoModifier;
1370 if (!ignore && (d->lastSelectionStart == d->lastSelectionEnd) && (ev->key() == Qt::Key_Right || ev->key() == Qt::Key_Left)) {
1371 // Ignore when moving off the end unless there is a selection,
1372 // because then moving will do something (deselect).
1373 int cursorPosition = d->m_cursor;
1374 if (cursorPosition == 0)
1375 ignore = ev->key() == (d->layoutDirection() == Qt::LeftToRight ? Qt::Key_Left : Qt::Key_Right);
1376 if (!ignore && cursorPosition == text().length())
1377 ignore = ev->key() == (d->layoutDirection() == Qt::LeftToRight ? Qt::Key_Right : Qt::Key_Left);
1382 d->processKeyEvent(ev);
1384 if (!ev->isAccepted())
1385 QQuickImplicitSizeItem::keyPressEvent(ev);
1388 void QQuickTextInput::inputMethodEvent(QInputMethodEvent *ev)
1390 Q_D(QQuickTextInput);
1391 const bool wasComposing = d->hasImState;
1392 if (d->m_readOnly) {
1395 d->processInputMethodEvent(ev);
1397 if (!ev->isAccepted())
1398 QQuickImplicitSizeItem::inputMethodEvent(ev);
1400 if (wasComposing != d->hasImState)
1401 emit inputMethodComposingChanged();
1404 void QQuickTextInput::mouseDoubleClickEvent(QMouseEvent *event)
1406 Q_D(QQuickTextInput);
1408 if (d->selectByMouse && event->button() == Qt::LeftButton) {
1410 int cursor = d->positionAt(event->localPos());
1411 d->selectWordAtPos(cursor);
1412 event->setAccepted(true);
1413 if (!d->hasPendingTripleClick()) {
1414 d->tripleClickStartPoint = event->localPos();
1415 d->tripleClickTimer.start();
1418 if (d->sendMouseEventToInputContext(event))
1420 QQuickImplicitSizeItem::mouseDoubleClickEvent(event);
1424 void QQuickTextInput::mousePressEvent(QMouseEvent *event)
1426 Q_D(QQuickTextInput);
1428 d->pressPos = event->localPos();
1430 if (d->sendMouseEventToInputContext(event))
1433 if (d->selectByMouse) {
1434 setKeepMouseGrab(false);
1435 d->selectPressed = true;
1436 QPointF distanceVector = d->pressPos - d->tripleClickStartPoint;
1437 if (d->hasPendingTripleClick()
1438 && distanceVector.manhattanLength() < qApp->styleHints()->startDragDistance()) {
1439 event->setAccepted(true);
1445 bool mark = (event->modifiers() & Qt::ShiftModifier) && d->selectByMouse;
1446 int cursor = d->positionAt(event->localPos());
1447 d->moveCursor(cursor, mark);
1449 if (d->focusOnPress) {
1450 bool hadActiveFocus = hasActiveFocus();
1452 // re-open input panel on press if already focused
1453 if (hasActiveFocus() && hadActiveFocus && !d->m_readOnly)
1454 openSoftwareInputPanel();
1457 event->setAccepted(true);
1460 void QQuickTextInput::mouseMoveEvent(QMouseEvent *event)
1462 Q_D(QQuickTextInput);
1464 if (d->selectPressed) {
1465 if (qAbs(int(event->localPos().x() - d->pressPos.x())) > qApp->styleHints()->startDragDistance())
1466 setKeepMouseGrab(true);
1468 if (d->composeMode()) {
1470 int startPos = d->positionAt(d->pressPos);
1471 int currentPos = d->positionAt(event->localPos());
1472 if (startPos != currentPos)
1473 d->setSelection(startPos, currentPos - startPos);
1475 moveCursorSelection(d->positionAt(event->localPos()), d->mouseSelectionMode);
1477 event->setAccepted(true);
1479 QQuickImplicitSizeItem::mouseMoveEvent(event);
1483 void QQuickTextInput::mouseReleaseEvent(QMouseEvent *event)
1485 Q_D(QQuickTextInput);
1486 if (d->sendMouseEventToInputContext(event))
1488 if (d->selectPressed) {
1489 d->selectPressed = false;
1490 setKeepMouseGrab(false);
1492 #ifndef QT_NO_CLIPBOARD
1493 if (QGuiApplication::clipboard()->supportsSelection()) {
1494 if (event->button() == Qt::LeftButton) {
1495 d->copy(QClipboard::Selection);
1496 } else if (!d->m_readOnly && event->button() == Qt::MidButton) {
1498 d->insert(QGuiApplication::clipboard()->text(QClipboard::Selection));
1502 if (!event->isAccepted())
1503 QQuickImplicitSizeItem::mouseReleaseEvent(event);
1506 bool QQuickTextInputPrivate::sendMouseEventToInputContext(QMouseEvent *event)
1508 #if !defined QT_NO_IM
1509 if (composeMode()) {
1510 int tmp_cursor = positionAt(event->localPos());
1511 int mousePos = tmp_cursor - m_cursor;
1512 if (mousePos >= 0 && mousePos <= m_textLayout.preeditAreaText().length()) {
1513 if (event->type() == QEvent::MouseButtonRelease) {
1514 qApp->inputMethod()->invokeAction(QInputMethod::Click, mousePos);
1527 void QQuickTextInput::mouseUngrabEvent()
1529 Q_D(QQuickTextInput);
1530 d->selectPressed = false;
1531 setKeepMouseGrab(false);
1534 bool QQuickTextInput::event(QEvent* ev)
1536 #ifndef QT_NO_SHORTCUT
1537 Q_D(QQuickTextInput);
1538 if (ev->type() == QEvent::ShortcutOverride) {
1541 QKeyEvent* ke = static_cast<QKeyEvent*>(ev);
1542 if (ke == QKeySequence::Copy
1543 || ke == QKeySequence::Paste
1544 || ke == QKeySequence::Cut
1545 || ke == QKeySequence::Redo
1546 || ke == QKeySequence::Undo
1547 || ke == QKeySequence::MoveToNextWord
1548 || ke == QKeySequence::MoveToPreviousWord
1549 || ke == QKeySequence::MoveToStartOfDocument
1550 || ke == QKeySequence::MoveToEndOfDocument
1551 || ke == QKeySequence::SelectNextWord
1552 || ke == QKeySequence::SelectPreviousWord
1553 || ke == QKeySequence::SelectStartOfLine
1554 || ke == QKeySequence::SelectEndOfLine
1555 || ke == QKeySequence::SelectStartOfBlock
1556 || ke == QKeySequence::SelectEndOfBlock
1557 || ke == QKeySequence::SelectStartOfDocument
1558 || ke == QKeySequence::SelectAll
1559 || ke == QKeySequence::SelectEndOfDocument) {
1561 } else if (ke->modifiers() == Qt::NoModifier || ke->modifiers() == Qt::ShiftModifier
1562 || ke->modifiers() == Qt::KeypadModifier) {
1563 if (ke->key() < Qt::Key_Escape) {
1567 switch (ke->key()) {
1568 case Qt::Key_Delete:
1571 case Qt::Key_Backspace:
1583 return QQuickImplicitSizeItem::event(ev);
1586 void QQuickTextInput::geometryChanged(const QRectF &newGeometry,
1587 const QRectF &oldGeometry)
1589 Q_D(QQuickTextInput);
1591 if (newGeometry.width() != oldGeometry.width() && d->wrapMode != NoWrap)
1593 updateCursorRectangle();
1595 QQuickImplicitSizeItem::geometryChanged(newGeometry, oldGeometry);
1598 void QQuickTextInputPrivate::updateHorizontalScroll()
1600 Q_Q(QQuickTextInput);
1601 QTextLine currentLine = m_textLayout.lineForTextPosition(m_cursor + m_preeditCursor);
1602 const int preeditLength = m_textLayout.preeditAreaText().length();
1603 const qreal width = qMax<qreal>(0, q->width());
1605 qreal widthUsed = 0;
1606 if (currentLine.isValid()) {
1607 cix = currentLine.cursorToX(m_cursor + preeditLength);
1608 const qreal cursorWidth = cix >= 0 ? cix : width - cix;
1609 widthUsed = qMax(currentLine.naturalTextWidth(), cursorWidth);
1611 int previousScroll = hscroll;
1613 if (!autoScroll || widthUsed <= width || m_echoMode == QQuickTextInput::NoEcho) {
1616 Q_ASSERT(currentLine.isValid());
1617 if (cix - hscroll >= width) {
1618 // text doesn't fit, cursor is to the right of br (scroll right)
1619 hscroll = cix - width;
1620 } else if (cix - hscroll < 0 && hscroll < widthUsed) {
1621 // text doesn't fit, cursor is to the left of br (scroll left)
1623 } else if (widthUsed - hscroll < width) {
1624 // text doesn't fit, text document is to the left of br; align
1626 hscroll = widthUsed - width;
1627 } else if (width - hscroll > widthUsed) {
1628 // text doesn't fit, text document is to the right of br; align
1630 hscroll = width - widthUsed;
1632 if (preeditLength > 0) {
1633 // check to ensure long pre-edit text doesn't push the cursor
1635 cix = currentLine.cursorToX(m_cursor + qMax(0, m_preeditCursor - 1));
1640 if (previousScroll != hscroll)
1641 textLayoutDirty = true;
1644 void QQuickTextInputPrivate::updateVerticalScroll()
1646 Q_Q(QQuickTextInput);
1647 const int preeditLength = m_textLayout.preeditAreaText().length();
1648 const qreal height = qMax<qreal>(0, q->height());
1649 qreal heightUsed = contentSize.height();
1650 qreal previousScroll = vscroll;
1652 if (!autoScroll || heightUsed <= height) {
1653 // text fits in br; use vscroll for alignment
1654 switch (vAlign & ~(Qt::AlignAbsolute|Qt::AlignHorizontal_Mask)) {
1655 case Qt::AlignBottom:
1656 vscroll = heightUsed - height;
1658 case Qt::AlignVCenter:
1659 vscroll = (heightUsed - height) / 2;
1667 QTextLine currentLine = m_textLayout.lineForTextPosition(m_cursor + preeditLength);
1668 QRectF r = currentLine.isValid() ? currentLine.rect() : QRectF();
1669 qreal top = r.top();
1670 int bottom = r.bottom();
1672 if (bottom - vscroll >= height) {
1673 // text doesn't fit, cursor is to the below the br (scroll down)
1674 vscroll = bottom - height;
1675 } else if (top - vscroll < 0 && vscroll < heightUsed) {
1676 // text doesn't fit, cursor is above br (scroll up)
1678 } else if (heightUsed - vscroll < height) {
1679 // text doesn't fit, text document is to the left of br; align
1681 vscroll = heightUsed - height;
1683 if (preeditLength > 0) {
1684 // check to ensure long pre-edit text doesn't push the cursor
1686 currentLine = m_textLayout.lineForTextPosition(m_cursor + qMax(0, m_preeditCursor - 1));
1687 top = currentLine.isValid() ? currentLine.rect().top() : 0;
1692 if (previousScroll != vscroll)
1693 textLayoutDirty = true;
1696 void QQuickTextInput::triggerPreprocess()
1698 Q_D(QQuickTextInput);
1699 if (d->updateType == QQuickTextInputPrivate::UpdateNone)
1700 d->updateType = QQuickTextInputPrivate::UpdateOnlyPreprocess;
1704 QSGNode *QQuickTextInput::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data)
1707 Q_D(QQuickTextInput);
1709 if (d->updateType != QQuickTextInputPrivate::UpdatePaintNode && oldNode != 0) {
1710 // Update done in preprocess() in the nodes
1711 d->updateType = QQuickTextInputPrivate::UpdateNone;
1715 d->updateType = QQuickTextInputPrivate::UpdateNone;
1717 QQuickTextNode *node = static_cast<QQuickTextNode *>(oldNode);
1719 node = new QQuickTextNode(QQuickItemPrivate::get(this)->sceneGraphContext(), this);
1722 if (!d->textLayoutDirty && oldNode != 0) {
1723 QSGSimpleRectNode *cursorNode = node->cursorNode();
1724 if (cursorNode != 0 && !isReadOnly()) {
1725 cursorNode->setRect(cursorRectangle());
1727 if (!d->cursorVisible || d->cursorItem || (!d->m_blinkStatus && d->m_blinkPeriod > 0)) {
1734 node->deleteContent();
1735 node->setMatrix(QMatrix4x4());
1737 QPointF offset(0, 0);
1738 if (d->autoScroll && d->m_textLayout.lineCount() > 0) {
1739 QFontMetricsF fm(d->font);
1740 // the y offset is there to keep the baseline constant in case we have script changes in the text.
1741 offset = -QPoint(d->hscroll, d->vscroll + d->m_textLayout.lineAt(0).ascent() - fm.ascent());
1743 offset = -QPoint(d->hscroll, d->vscroll);
1746 if (!d->m_textLayout.text().isEmpty() || !d->m_textLayout.preeditAreaText().isEmpty()) {
1747 node->addTextLayout(offset, &d->m_textLayout, d->color,
1748 QQuickText::Normal, QColor(), QColor(),
1749 d->selectionColor, d->selectedTextColor,
1750 d->selectionStart(),
1751 d->selectionEnd() - 1); // selectionEnd() returns first char after
1755 if (!isReadOnly() && d->cursorItem == 0) {
1756 node->setCursor(cursorRectangle(), d->color);
1757 if (!d->cursorVisible || (!d->m_blinkStatus && d->m_blinkPeriod > 0)) {
1764 d->textLayoutDirty = false;
1770 QVariant QQuickTextInput::inputMethodQuery(Qt::InputMethodQuery property) const
1772 Q_D(const QQuickTextInput);
1775 return QVariant((bool)(flags() & ItemAcceptsInputMethod));
1777 return QVariant((int) d->effectiveInputMethodHints());
1778 case Qt::ImCursorRectangle:
1779 return cursorRectangle();
1782 case Qt::ImCursorPosition:
1783 return QVariant(d->m_cursor);
1784 case Qt::ImSurroundingText:
1785 if (d->m_echoMode == PasswordEchoOnEdit && !d->m_passwordEchoEditing) {
1786 return QVariant(displayText());
1788 return QVariant(d->realText());
1790 case Qt::ImCurrentSelection:
1791 return QVariant(selectedText());
1792 case Qt::ImMaximumTextLength:
1793 return QVariant(maxLength());
1794 case Qt::ImAnchorPosition:
1795 if (d->selectionStart() == d->selectionEnd())
1796 return QVariant(d->m_cursor);
1797 else if (d->selectionStart() == d->m_cursor)
1798 return QVariant(d->selectionEnd());
1800 return QVariant(d->selectionStart());
1807 \qmlmethod void QtQuick2::TextInput::deselect()
1809 Removes active text selection.
1811 void QQuickTextInput::deselect()
1813 Q_D(QQuickTextInput);
1818 \qmlmethod void QtQuick2::TextInput::selectAll()
1820 Causes all text to be selected.
1822 void QQuickTextInput::selectAll()
1824 Q_D(QQuickTextInput);
1825 d->setSelection(0, text().length());
1829 \qmlmethod void QtQuick2::TextInput::isRightToLeft(int start, int end)
1831 Returns true if the natural reading direction of the editor text
1832 found between positions \a start and \a end is right to left.
1834 bool QQuickTextInput::isRightToLeft(int start, int end)
1837 qmlInfo(this) << "isRightToLeft(start, end) called with the end property being smaller than the start.";
1840 return text().mid(start, end - start).isRightToLeft();
1844 #ifndef QT_NO_CLIPBOARD
1846 \qmlmethod QtQuick2::TextInput::cut()
1848 Moves the currently selected text to the system clipboard.
1850 void QQuickTextInput::cut()
1852 Q_D(QQuickTextInput);
1858 \qmlmethod QtQuick2::TextInput::copy()
1860 Copies the currently selected text to the system clipboard.
1862 void QQuickTextInput::copy()
1864 Q_D(QQuickTextInput);
1869 \qmlmethod QtQuick2::TextInput::paste()
1871 Replaces the currently selected text by the contents of the system clipboard.
1873 void QQuickTextInput::paste()
1875 Q_D(QQuickTextInput);
1879 #endif // QT_NO_CLIPBOARD
1882 Undoes the last operation if undo is \l {canUndo}{available}. Deselects any
1883 current selection, and updates the selection start to the current cursor
1887 void QQuickTextInput::undo()
1889 Q_D(QQuickTextInput);
1890 if (!d->m_readOnly) {
1892 d->finishChange(-1, true);
1897 Redoes the last operation if redo is \l {canRedo}{available}.
1900 void QQuickTextInput::redo()
1902 Q_D(QQuickTextInput);
1903 if (!d->m_readOnly) {
1910 \qmlmethod void QtQuick2::TextInput::insert(int position, string text)
1912 Inserts \a text into the TextInput at position.
1915 void QQuickTextInput::insert(int position, const QString &text)
1917 Q_D(QQuickTextInput);
1918 if (d->m_echoMode == QQuickTextInput::Password) {
1919 int delay = qGuiApp->styleHints()->passwordMaskDelay();
1921 d->m_passwordEchoTimer.start(delay, this);
1923 if (position < 0 || position > d->m_text.length())
1926 const int priorState = d->m_undoState;
1928 QString insertText = text;
1930 if (d->hasSelectedText()) {
1931 d->addCommand(QQuickTextInputPrivate::Command(
1932 QQuickTextInputPrivate::SetSelection, d->m_cursor, 0, d->m_selstart, d->m_selend));
1934 if (d->m_maskData) {
1935 insertText = d->maskString(position, insertText);
1936 for (int i = 0; i < insertText.length(); ++i) {
1937 d->addCommand(QQuickTextInputPrivate::Command(
1938 QQuickTextInputPrivate::DeleteSelection, position + i, d->m_text.at(position + i), -1, -1));
1939 d->addCommand(QQuickTextInputPrivate::Command(
1940 QQuickTextInputPrivate::Insert, position + i, insertText.at(i), -1, -1));
1942 d->m_text.replace(position, insertText.length(), insertText);
1943 if (!insertText.isEmpty())
1944 d->m_textDirty = true;
1945 if (position < d->m_selend && position + insertText.length() > d->m_selstart)
1946 d->m_selDirty = true;
1948 int remaining = d->m_maxLength - d->m_text.length();
1949 if (remaining != 0) {
1950 insertText = insertText.left(remaining);
1951 d->m_text.insert(position, insertText);
1952 for (int i = 0; i < insertText.length(); ++i)
1953 d->addCommand(QQuickTextInputPrivate::Command(
1954 QQuickTextInputPrivate::Insert, position + i, insertText.at(i), -1, -1));
1955 if (d->m_cursor >= position)
1956 d->m_cursor += insertText.length();
1957 if (d->m_selstart >= position)
1958 d->m_selstart += insertText.length();
1959 if (d->m_selend >= position)
1960 d->m_selend += insertText.length();
1961 d->m_textDirty = true;
1962 if (position >= d->m_selstart && position <= d->m_selend)
1963 d->m_selDirty = true;
1967 d->addCommand(QQuickTextInputPrivate::Command(
1968 QQuickTextInputPrivate::SetSelection, d->m_cursor, 0, d->m_selstart, d->m_selend));
1969 d->finishChange(priorState);
1971 if (d->lastSelectionStart != d->lastSelectionEnd) {
1972 if (d->m_selstart != d->lastSelectionStart) {
1973 d->lastSelectionStart = d->m_selstart;
1974 emit selectionStartChanged();
1976 if (d->m_selend != d->lastSelectionEnd) {
1977 d->lastSelectionEnd = d->m_selend;
1978 emit selectionEndChanged();
1984 \qmlmethod string QtQuick2::TextInput::getText(int start, int end)
1986 Removes the section of text that is between the \a start and \a end positions from the TextInput.
1989 void QQuickTextInput::remove(int start, int end)
1991 Q_D(QQuickTextInput);
1993 start = qBound(0, start, d->m_text.length());
1994 end = qBound(0, end, d->m_text.length());
1998 else if (start == end)
2001 if (start < d->m_selend && end > d->m_selstart)
2002 d->m_selDirty = true;
2004 const int priorState = d->m_undoState;
2006 d->addCommand(QQuickTextInputPrivate::Command(
2007 QQuickTextInputPrivate::SetSelection, d->m_cursor, 0, d->m_selstart, d->m_selend));
2009 if (start <= d->m_cursor && d->m_cursor < end) {
2010 // cursor is within the selection. Split up the commands
2011 // to be able to restore the correct cursor position
2012 for (int i = d->m_cursor; i >= start; --i) {
2013 d->addCommand(QQuickTextInputPrivate::Command(
2014 QQuickTextInputPrivate::DeleteSelection, i, d->m_text.at(i), -1, 1));
2016 for (int i = end - 1; i > d->m_cursor; --i) {
2017 d->addCommand(QQuickTextInputPrivate::Command(
2018 QQuickTextInputPrivate::DeleteSelection, i - d->m_cursor + start - 1, d->m_text.at(i), -1, -1));
2021 for (int i = end - 1; i >= start; --i) {
2022 d->addCommand(QQuickTextInputPrivate::Command(
2023 QQuickTextInputPrivate::RemoveSelection, i, d->m_text.at(i), -1, -1));
2026 if (d->m_maskData) {
2027 d->m_text.replace(start, end - start, d->clearString(start, end - start));
2028 for (int i = 0; i < end - start; ++i) {
2029 d->addCommand(QQuickTextInputPrivate::Command(
2030 QQuickTextInputPrivate::Insert, start + i, d->m_text.at(start + i), -1, -1));
2033 d->m_text.remove(start, end - start);
2035 if (d->m_cursor > start)
2036 d->m_cursor -= qMin(d->m_cursor, end) - start;
2037 if (d->m_selstart > start)
2038 d->m_selstart -= qMin(d->m_selstart, end) - start;
2039 if (d->m_selend > end)
2040 d->m_selend -= qMin(d->m_selend, end) - start;
2042 d->addCommand(QQuickTextInputPrivate::Command(
2043 QQuickTextInputPrivate::SetSelection, d->m_cursor, 0, d->m_selstart, d->m_selend));
2045 d->m_textDirty = true;
2046 d->finishChange(priorState);
2048 if (d->lastSelectionStart != d->lastSelectionEnd) {
2049 if (d->m_selstart != d->lastSelectionStart) {
2050 d->lastSelectionStart = d->m_selstart;
2051 emit selectionStartChanged();
2053 if (d->m_selend != d->lastSelectionEnd) {
2054 d->lastSelectionEnd = d->m_selend;
2055 emit selectionEndChanged();
2062 \qmlmethod void QtQuick2::TextInput::selectWord()
2064 Causes the word closest to the current cursor position to be selected.
2066 void QQuickTextInput::selectWord()
2068 Q_D(QQuickTextInput);
2069 d->selectWordAtPos(d->m_cursor);
2073 \qmlproperty bool QtQuick2::TextInput::smooth
2075 This property holds whether the text is smoothly scaled or transformed.
2077 Smooth filtering gives better visual quality, but is slower. If
2078 the item is displayed at its natural size, this property has no visual or
2081 \note Generally scaling artifacts are only visible if the item is stationary on
2082 the screen. A common pattern when animating an item is to disable smooth
2083 filtering at the beginning of the animation and reenable it at the conclusion.
2087 \qmlproperty string QtQuick2::TextInput::passwordCharacter
2089 This is the character displayed when echoMode is set to Password or
2090 PasswordEchoOnEdit. By default it is an asterisk.
2092 If this property is set to a string with more than one character,
2093 the first character is used. If the string is empty, the value
2094 is ignored and the property is not set.
2096 QString QQuickTextInput::passwordCharacter() const
2098 Q_D(const QQuickTextInput);
2099 return QString(d->m_passwordCharacter);
2102 void QQuickTextInput::setPasswordCharacter(const QString &str)
2104 Q_D(QQuickTextInput);
2105 if (str.length() < 1)
2107 d->m_passwordCharacter = str.constData()[0];
2108 if (d->m_echoMode == Password || d->m_echoMode == PasswordEchoOnEdit)
2109 d->updateDisplayText();
2110 emit passwordCharacterChanged();
2114 \qmlproperty string QtQuick2::TextInput::displayText
2116 This is the text displayed in the TextInput.
2118 If \l echoMode is set to TextInput::Normal, this holds the
2119 same value as the TextInput::text property. Otherwise,
2120 this property holds the text visible to the user, while
2121 the \l text property holds the actual entered text.
2123 QString QQuickTextInput::displayText() const
2125 Q_D(const QQuickTextInput);
2126 return d->m_textLayout.text();
2130 \qmlproperty bool QtQuick2::TextInput::selectByMouse
2134 If true, the user can use the mouse to select text in some
2135 platform-specific way. Note that for some platforms this may
2136 not be an appropriate interaction (eg. may conflict with how
2137 the text needs to behave inside a Flickable.
2139 bool QQuickTextInput::selectByMouse() const
2141 Q_D(const QQuickTextInput);
2142 return d->selectByMouse;
2145 void QQuickTextInput::setSelectByMouse(bool on)
2147 Q_D(QQuickTextInput);
2148 if (d->selectByMouse != on) {
2149 d->selectByMouse = on;
2150 emit selectByMouseChanged(on);
2155 \qmlproperty enum QtQuick2::TextInput::mouseSelectionMode
2157 Specifies how text should be selected using a mouse.
2160 \li TextInput.SelectCharacters - The selection is updated with individual characters. (Default)
2161 \li TextInput.SelectWords - The selection is updated with whole words.
2164 This property only applies when \l selectByMouse is true.
2167 QQuickTextInput::SelectionMode QQuickTextInput::mouseSelectionMode() const
2169 Q_D(const QQuickTextInput);
2170 return d->mouseSelectionMode;
2173 void QQuickTextInput::setMouseSelectionMode(SelectionMode mode)
2175 Q_D(QQuickTextInput);
2176 if (d->mouseSelectionMode != mode) {
2177 d->mouseSelectionMode = mode;
2178 emit mouseSelectionModeChanged(mode);
2183 \qmlproperty bool QtQuick2::TextInput::persistentSelection
2185 Whether the TextInput should keep its selection when it loses active focus to another
2186 item in the scene. By default this is set to false;
2189 bool QQuickTextInput::persistentSelection() const
2191 Q_D(const QQuickTextInput);
2192 return d->persistentSelection;
2195 void QQuickTextInput::setPersistentSelection(bool on)
2197 Q_D(QQuickTextInput);
2198 if (d->persistentSelection == on)
2200 d->persistentSelection = on;
2201 emit persistentSelectionChanged();
2204 #ifndef QT_NO_CLIPBOARD
2206 \qmlproperty bool QtQuick2::TextInput::canPaste
2208 Returns true if the TextInput is writable and the content of the clipboard is
2209 suitable for pasting into the TextInput.
2211 bool QQuickTextInput::canPaste() const
2213 Q_D(const QQuickTextInput);
2214 if (!d->canPasteValid) {
2215 if (const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData())
2216 const_cast<QQuickTextInputPrivate *>(d)->canPaste = !d->m_readOnly && mimeData->hasText();
2217 const_cast<QQuickTextInputPrivate *>(d)->canPasteValid = true;
2224 \qmlproperty bool QtQuick2::TextInput::canUndo
2226 Returns true if the TextInput is writable and there are previous operations
2230 bool QQuickTextInput::canUndo() const
2232 Q_D(const QQuickTextInput);
2237 \qmlproperty bool QtQuick2::TextInput::canRedo
2239 Returns true if the TextInput is writable and there are \l {undo}{undone}
2240 operations that can be redone.
2243 bool QQuickTextInput::canRedo() const
2245 Q_D(const QQuickTextInput);
2250 \qmlproperty real QtQuick2::TextInput::contentWidth
2252 Returns the width of the text, including the width past the width
2253 which is covered due to insufficient wrapping if \l wrapMode is set.
2256 qreal QQuickTextInput::contentWidth() const
2258 Q_D(const QQuickTextInput);
2259 return d->contentSize.width();
2263 \qmlproperty real QtQuick2::TextInput::contentHeight
2265 Returns the height of the text, including the height past the height
2266 that is covered if the text does not fit within the set height.
2269 qreal QQuickTextInput::contentHeight() const
2271 Q_D(const QQuickTextInput);
2272 return d->contentSize.height();
2275 void QQuickTextInput::moveCursorSelection(int position)
2277 Q_D(QQuickTextInput);
2278 d->moveCursor(position, true);
2282 \qmlmethod void QtQuick2::TextInput::moveCursorSelection(int position, SelectionMode mode = TextInput.SelectCharacters)
2284 Moves the cursor to \a position and updates the selection according to the optional \a mode
2285 parameter. (To only move the cursor, set the \l cursorPosition property.)
2287 When this method is called it additionally sets either the
2288 selectionStart or the selectionEnd (whichever was at the previous cursor position)
2289 to the specified position. This allows you to easily extend and contract the selected
2292 The selection mode specifies whether the selection is updated on a per character or a per word
2293 basis. If not specified the selection mode will default to TextInput.SelectCharacters.
2296 \li TextInput.SelectCharacters - Sets either the selectionStart or selectionEnd (whichever was at
2297 the previous cursor position) to the specified position.
2298 \li TextInput.SelectWords - Sets the selectionStart and selectionEnd to include all
2299 words between the specified position and the previous cursor position. Words partially in the
2303 For example, take this sequence of calls:
2307 moveCursorSelection(9, TextInput.SelectCharacters)
2308 moveCursorSelection(7, TextInput.SelectCharacters)
2311 This moves the cursor to position 5, extend the selection end from 5 to 9
2312 and then retract the selection end from 9 to 7, leaving the text from position 5 to 7
2313 selected (the 6th and 7th characters).
2315 The same sequence with TextInput.SelectWords will extend the selection start to a word boundary
2316 before or on position 5 and extend the selection end to a word boundary on or past position 9.
2318 void QQuickTextInput::moveCursorSelection(int pos, SelectionMode mode)
2320 Q_D(QQuickTextInput);
2322 if (mode == SelectCharacters) {
2323 d->moveCursor(pos, true);
2324 } else if (pos != d->m_cursor){
2325 const int cursor = d->m_cursor;
2327 if (!d->hasSelectedText())
2328 anchor = d->m_cursor;
2329 else if (d->selectionStart() == d->m_cursor)
2330 anchor = d->selectionEnd();
2332 anchor = d->selectionStart();
2334 if (anchor < pos || (anchor == pos && cursor < pos)) {
2335 const QString text = this->text();
2336 QTextBoundaryFinder finder(QTextBoundaryFinder::Word, text);
2337 finder.setPosition(anchor);
2339 const QTextBoundaryFinder::BoundaryReasons reasons = finder.boundaryReasons();
2340 if (anchor < text.length() && (!(reasons & QTextBoundaryFinder::StartWord)
2341 || ((reasons & QTextBoundaryFinder::EndWord) && anchor > cursor))) {
2342 finder.toPreviousBoundary();
2344 anchor = finder.position() != -1 ? finder.position() : 0;
2346 finder.setPosition(pos);
2347 if (pos > 0 && !finder.boundaryReasons())
2348 finder.toNextBoundary();
2349 const int cursor = finder.position() != -1 ? finder.position() : text.length();
2351 d->setSelection(anchor, cursor - anchor);
2352 } else if (anchor > pos || (anchor == pos && cursor > pos)) {
2353 const QString text = this->text();
2354 QTextBoundaryFinder finder(QTextBoundaryFinder::Word, text);
2355 finder.setPosition(anchor);
2357 const QTextBoundaryFinder::BoundaryReasons reasons = finder.boundaryReasons();
2358 if (anchor > 0 && (!(reasons & QTextBoundaryFinder::EndWord)
2359 || ((reasons & QTextBoundaryFinder::StartWord) && anchor < cursor))) {
2360 finder.toNextBoundary();
2363 anchor = finder.position() != -1 ? finder.position() : text.length();
2365 finder.setPosition(pos);
2366 if (pos < text.length() && !finder.boundaryReasons())
2367 finder.toPreviousBoundary();
2368 const int cursor = finder.position() != -1 ? finder.position() : 0;
2370 d->setSelection(anchor, cursor - anchor);
2376 \qmlmethod void QtQuick2::TextInput::openSoftwareInputPanel()
2378 Opens software input panels like virtual keyboards for typing, useful for
2379 customizing when you want the input keyboard to be shown and hidden in
2382 By default the opening of input panels follows the platform style. Input panels are
2383 always closed if no editor has active focus.
2385 You can disable the automatic behavior by setting the property \c activeFocusOnPress to false
2386 and use functions openSoftwareInputPanel() and closeSoftwareInputPanel() to implement
2387 the behavior you want.
2389 Only relevant on platforms, which provide virtual keyboards.
2395 text: "Hello world!"
2396 activeFocusOnPress: false
2398 anchors.fill: parent
2400 if (!textInput.activeFocus) {
2401 textInput.forceActiveFocus()
2402 textInput.openSoftwareInputPanel();
2404 textInput.focus = false;
2407 onPressAndHold: textInput.closeSoftwareInputPanel();
2412 void QQuickTextInput::openSoftwareInputPanel()
2415 qGuiApp->inputMethod()->show();
2419 \qmlmethod void QtQuick2::TextInput::closeSoftwareInputPanel()
2421 Closes a software input panel like a virtual keyboard shown on the screen, useful
2422 for customizing when you want the input keyboard to be shown and hidden in
2425 By default the opening of input panels follows the platform style. Input panels are
2426 always closed if no editor has active focus.
2428 You can disable the automatic behavior by setting the property \c activeFocusOnPress to false
2429 and use functions openSoftwareInputPanel() and closeSoftwareInputPanel() to implement
2430 the behavior you want.
2432 Only relevant on platforms, which provide virtual keyboards.
2438 text: "Hello world!"
2439 activeFocusOnPress: false
2441 anchors.fill: parent
2443 if (!textInput.activeFocus) {
2444 textInput.forceActiveFocus();
2445 textInput.openSoftwareInputPanel();
2447 textInput.focus = false;
2450 onPressAndHold: textInput.closeSoftwareInputPanel();
2455 void QQuickTextInput::closeSoftwareInputPanel()
2458 qGuiApp->inputMethod()->hide();
2461 void QQuickTextInput::focusInEvent(QFocusEvent *event)
2463 Q_D(const QQuickTextInput);
2464 if (d->focusOnPress && !d->m_readOnly)
2465 openSoftwareInputPanel();
2466 QQuickImplicitSizeItem::focusInEvent(event);
2469 void QQuickTextInput::itemChange(ItemChange change, const ItemChangeData &value)
2471 Q_D(QQuickTextInput);
2472 if (change == ItemActiveFocusHasChanged) {
2473 bool hasFocus = value.boolValue;
2474 setCursorVisible(hasFocus); // ### refactor: && d->canvas && d->canvas->hasFocus()
2475 if (!hasFocus && (d->m_passwordEchoEditing || d->m_passwordEchoTimer.isActive())) {
2476 d->updatePasswordEchoEditing(false);//QQuickTextInputPrivate sets it on key events, but doesn't deal with focus events
2480 if (!d->persistentSelection)
2482 disconnect(qApp->inputMethod(), SIGNAL(inputDirectionChanged(Qt::LayoutDirection)),
2483 this, SLOT(q_updateAlignment()));
2485 q_updateAlignment();
2486 connect(qApp->inputMethod(), SIGNAL(inputDirectionChanged(Qt::LayoutDirection)),
2487 this, SLOT(q_updateAlignment()));
2490 QQuickItem::itemChange(change, value);
2494 \qmlproperty bool QtQuick2::TextInput::inputMethodComposing
2497 This property holds whether the TextInput has partial text input from an
2500 While it is composing an input method may rely on mouse or key events from
2501 the TextInput to edit or commit the partial text. This property can be
2502 used to determine when to disable events handlers that may interfere with
2503 the correct operation of an input method.
2505 bool QQuickTextInput::isInputMethodComposing() const
2507 Q_D(const QQuickTextInput);
2508 return d->hasImState;
2511 void QQuickTextInputPrivate::init()
2513 Q_Q(QQuickTextInput);
2514 q->setSmooth(smooth);
2515 q->setAcceptedMouseButtons(Qt::LeftButton);
2516 q->setFlag(QQuickItem::ItemAcceptsInputMethod);
2517 q->setFlag(QQuickItem::ItemHasContents);
2518 #ifndef QT_NO_CLIPBOARD
2519 q->connect(QGuiApplication::clipboard(), SIGNAL(dataChanged()),
2520 q, SLOT(q_canPasteChanged()));
2521 #endif // QT_NO_CLIPBOARD
2523 lastSelectionStart = 0;
2524 lastSelectionEnd = 0;
2525 determineHorizontalAlignment();
2527 if (!qmlDisableDistanceField()) {
2528 QTextOption option = m_textLayout.textOption();
2529 option.setUseDesignMetrics(true);
2530 m_textLayout.setTextOption(option);
2534 void QQuickTextInput::updateCursorRectangle()
2536 Q_D(QQuickTextInput);
2537 if (!isComponentComplete())
2540 d->updateHorizontalScroll();
2541 d->updateVerticalScroll();
2542 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
2544 emit cursorRectangleChanged();
2545 if (d->cursorItem) {
2546 QRectF r = cursorRectangle();
2547 d->cursorItem->setPos(r.topLeft());
2548 d->cursorItem->setHeight(r.height());
2550 updateInputMethod(Qt::ImCursorRectangle);
2553 void QQuickTextInput::selectionChanged()
2555 Q_D(QQuickTextInput);
2556 d->textLayoutDirty = true; //TODO: Only update rect in selection
2557 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
2559 emit selectedTextChanged();
2561 if (d->lastSelectionStart != d->selectionStart()) {
2562 d->lastSelectionStart = d->selectionStart();
2563 if (d->lastSelectionStart == -1)
2564 d->lastSelectionStart = d->m_cursor;
2565 emit selectionStartChanged();
2567 if (d->lastSelectionEnd != d->selectionEnd()) {
2568 d->lastSelectionEnd = d->selectionEnd();
2569 if (d->lastSelectionEnd == -1)
2570 d->lastSelectionEnd = d->m_cursor;
2571 emit selectionEndChanged();
2575 void QQuickTextInputPrivate::showCursor()
2577 if (textNode != 0 && textNode->cursorNode() != 0)
2578 textNode->cursorNode()->setColor(color);
2581 void QQuickTextInputPrivate::hideCursor()
2583 if (textNode != 0 && textNode->cursorNode() != 0)
2584 textNode->cursorNode()->setColor(QColor(0, 0, 0, 0));
2587 QRectF QQuickTextInput::boundingRect() const
2589 Q_D(const QQuickTextInput);
2591 int cursorWidth = d->cursorItem ? 0 : 1;
2593 qreal hscroll = d->hscroll;
2594 if (!d->autoScroll || d->contentSize.width() < width()) {
2595 switch (effectiveHAlign()) {
2599 hscroll += d->contentSize.width() - width();
2602 hscroll += (d->contentSize.width() - width()) / 2;
2607 // Could include font max left/right bearings to either side of rectangle.
2608 QRectF r(-hscroll, -d->vscroll, d->contentSize.width(), d->contentSize.height());
2609 r.setRight(r.right() + cursorWidth);
2613 QRectF QQuickTextInput::clipRect() const
2615 Q_D(const QQuickTextInput);
2617 int cursorWidth = d->cursorItem ? d->cursorItem->width() : 1;
2619 // Could include font max left/right bearings to either side of rectangle.
2620 QRectF r = QQuickImplicitSizeItem::clipRect();
2621 r.setRight(r.right() + cursorWidth);
2625 void QQuickTextInput::q_canPasteChanged()
2627 Q_D(QQuickTextInput);
2628 bool old = d->canPaste;
2629 #ifndef QT_NO_CLIPBOARD
2630 if (const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData())
2631 d->canPaste = !d->m_readOnly && mimeData->hasText();
2633 d->canPaste = false;
2636 bool changed = d->canPaste != old || !d->canPasteValid;
2637 d->canPasteValid = true;
2639 emit canPasteChanged();
2643 void QQuickTextInput::q_updateAlignment()
2645 Q_D(QQuickTextInput);
2646 if (d->determineHorizontalAlignment()) {
2648 updateCursorRectangle();
2652 // ### these should come from QStyleHints
2653 const int textCursorWidth = 1;
2654 const bool fullWidthSelection = true;
2659 Updates the display text based of the current edit text
2660 If the text has changed will emit displayTextChanged()
2662 void QQuickTextInputPrivate::updateDisplayText(bool forceUpdate)
2664 QString orig = m_textLayout.text();
2666 if (m_echoMode == QQuickTextInput::NoEcho)
2667 str = QString::fromLatin1("");
2671 if (m_echoMode == QQuickTextInput::Password) {
2672 str.fill(m_passwordCharacter);
2673 if (m_passwordEchoTimer.isActive() && m_cursor > 0 && m_cursor <= m_text.length()) {
2674 int cursor = m_cursor - 1;
2675 QChar uc = m_text.at(cursor);
2677 if (cursor > 0 && uc.unicode() >= 0xdc00 && uc.unicode() < 0xe000) {
2678 // second half of a surrogate, check if we have the first half as well,
2679 // if yes restore both at once
2680 uc = m_text.at(cursor - 1);
2681 if (uc.unicode() >= 0xd800 && uc.unicode() < 0xdc00)
2682 str[cursor - 1] = uc;
2685 } else if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit && !m_passwordEchoEditing) {
2686 str.fill(m_passwordCharacter);
2689 // replace certain non-printable characters with spaces (to avoid
2690 // drawing boxes when using fonts that don't have glyphs for such
2692 QChar* uc = str.data();
2693 for (int i = 0; i < (int)str.length(); ++i) {
2694 if ((uc[i] < 0x20 && uc[i] != 0x09)
2695 || uc[i] == QChar::LineSeparator
2696 || uc[i] == QChar::ParagraphSeparator
2697 || uc[i] == QChar::ObjectReplacementCharacter)
2698 uc[i] = QChar(0x0020);
2701 if (str != orig || forceUpdate) {
2702 m_textLayout.setText(str);
2703 updateLayout(); // polish?
2704 emit q_func()->displayTextChanged();
2708 qreal QQuickTextInputPrivate::getImplicitWidth() const
2710 Q_Q(const QQuickTextInput);
2711 if (!requireImplicitWidth) {
2712 QQuickTextInputPrivate *d = const_cast<QQuickTextInputPrivate *>(this);
2713 d->requireImplicitWidth = true;
2715 if (q->isComponentComplete()) {
2716 // One time cost, only incurred if implicitWidth is first requested after
2717 // componentComplete.
2718 QTextLayout layout(m_text);
2720 QTextOption option = m_textLayout.textOption();
2721 option.setTextDirection(m_layoutDirection);
2722 option.setFlags(QTextOption::IncludeTrailingSpaces);
2723 option.setWrapMode(QTextOption::WrapMode(wrapMode));
2724 option.setAlignment(Qt::Alignment(q->effectiveHAlign()));
2725 layout.setTextOption(option);
2726 layout.setFont(font);
2727 layout.setPreeditArea(m_textLayout.preeditAreaPosition(), m_textLayout.preeditAreaText());
2728 layout.beginLayout();
2730 QTextLine line = layout.createLine();
2731 line.setLineWidth(INT_MAX);
2732 d->implicitWidth = qCeil(line.naturalTextWidth());
2737 return implicitWidth;
2740 void QQuickTextInputPrivate::updateLayout()
2742 Q_Q(QQuickTextInput);
2744 if (!q->isComponentComplete())
2748 QTextOption option = m_textLayout.textOption();
2749 option.setTextDirection(layoutDirection());
2750 option.setWrapMode(QTextOption::WrapMode(wrapMode));
2751 option.setAlignment(Qt::Alignment(q->effectiveHAlign()));
2752 m_textLayout.setTextOption(option);
2753 m_textLayout.setFont(font);
2755 m_textLayout.beginLayout();
2757 QTextLine line = m_textLayout.createLine();
2758 if (requireImplicitWidth) {
2759 line.setLineWidth(INT_MAX);
2760 const bool wasInLayout = inLayout;
2762 q->setImplicitWidth(qCeil(line.naturalTextWidth()));
2763 inLayout = wasInLayout;
2764 if (inLayout) // probably the result of a binding loop, but by letting it
2765 return; // get this far we'll get a warning to that effect.
2767 qreal lineWidth = q->widthValid() ? q->width() : INT_MAX;
2771 line.setLineWidth(lineWidth);
2772 line.setPosition(QPointF(0, height));
2774 height += line.height();
2775 width = qMax(width, line.naturalTextWidth());
2777 line = m_textLayout.createLine();
2778 } while (line.isValid());
2779 m_textLayout.endLayout();
2781 option.setWrapMode(QTextOption::NoWrap);
2782 m_textLayout.setTextOption(option);
2784 textLayoutDirty = true;
2786 const QSizeF previousSize = contentSize;
2787 contentSize = QSizeF(width, height);
2789 updateType = UpdatePaintNode;
2792 if (!requireImplicitWidth && !q->widthValid())
2793 q->setImplicitSize(width, height);
2795 q->setImplicitHeight(height);
2797 if (previousSize != contentSize)
2798 emit q->contentSizeChanged();
2801 #ifndef QT_NO_CLIPBOARD
2805 Copies the currently selected text into the clipboard using the given
2808 \note If the echo mode is set to a mode other than Normal then copy
2809 will not work. This is to prevent using copy as a method of bypassing
2810 password features of the line control.
2812 void QQuickTextInputPrivate::copy(QClipboard::Mode mode) const
2814 QString t = selectedText();
2815 if (!t.isEmpty() && m_echoMode == QQuickTextInput::Normal) {
2816 QGuiApplication::clipboard()->setText(t, mode);
2823 Inserts the text stored in the application clipboard into the line
2828 void QQuickTextInputPrivate::paste(QClipboard::Mode clipboardMode)
2830 QString clip = QGuiApplication::clipboard()->text(clipboardMode);
2831 if (!clip.isEmpty() || hasSelectedText()) {
2832 separate(); //make it a separate undo/redo command
2838 #endif // !QT_NO_CLIPBOARD
2843 void QQuickTextInputPrivate::commitPreedit()
2845 Q_Q(QQuickTextInput);
2850 qApp->inputMethod()->commit();
2855 QInputMethodEvent ev;
2856 QCoreApplication::sendEvent(q, &ev);
2859 void QQuickTextInputPrivate::cancelPreedit()
2861 Q_Q(QQuickTextInput);
2866 qApp->inputMethod()->reset();
2868 QInputMethodEvent ev;
2869 QCoreApplication::sendEvent(q, &ev);
2875 Handles the behavior for the backspace key or function.
2876 Removes the current selection if there is a selection, otherwise
2877 removes the character prior to the cursor position.
2881 void QQuickTextInputPrivate::backspace()
2883 int priorState = m_undoState;
2884 if (hasSelectedText()) {
2885 removeSelectedText();
2886 } else if (m_cursor) {
2889 m_cursor = prevMaskBlank(m_cursor);
2890 QChar uc = m_text.at(m_cursor);
2891 if (m_cursor > 0 && uc.unicode() >= 0xdc00 && uc.unicode() < 0xe000) {
2892 // second half of a surrogate, check if we have the first half as well,
2893 // if yes delete both at once
2894 uc = m_text.at(m_cursor - 1);
2895 if (uc.unicode() >= 0xd800 && uc.unicode() < 0xdc00) {
2896 internalDelete(true);
2900 internalDelete(true);
2902 finishChange(priorState);
2908 Handles the behavior for the delete key or function.
2909 Removes the current selection if there is a selection, otherwise
2910 removes the character after the cursor position.
2914 void QQuickTextInputPrivate::del()
2916 int priorState = m_undoState;
2917 if (hasSelectedText()) {
2918 removeSelectedText();
2920 int n = m_textLayout.nextCursorPosition(m_cursor) - m_cursor;
2924 finishChange(priorState);
2930 Inserts the given \a newText at the current cursor position.
2931 If there is any selected text it is removed prior to insertion of
2934 void QQuickTextInputPrivate::insert(const QString &newText)
2936 int priorState = m_undoState;
2937 removeSelectedText();
2938 internalInsert(newText);
2939 finishChange(priorState);
2945 Clears the line control text.
2947 void QQuickTextInputPrivate::clear()
2949 int priorState = m_undoState;
2951 m_selend = m_text.length();
2952 removeSelectedText();
2954 finishChange(priorState, /*update*/false, /*edited*/false);
2960 Sets \a length characters from the given \a start position as selected.
2961 The given \a start position must be within the current text for
2962 the line control. If \a length characters cannot be selected, then
2963 the selection will extend to the end of the current text.
2965 void QQuickTextInputPrivate::setSelection(int start, int length)
2967 Q_Q(QQuickTextInput);
2970 if (start < 0 || start > (int)m_text.length()){
2971 qWarning("QQuickTextInputPrivate::setSelection: Invalid start position");
2976 if (start == m_selstart && start + length == m_selend && m_cursor == m_selend)
2979 m_selend = qMin(start + length, (int)m_text.length());
2980 m_cursor = m_selend;
2981 } else if (length < 0){
2982 if (start == m_selend && start + length == m_selstart && m_cursor == m_selstart)
2984 m_selstart = qMax(start + length, 0);
2986 m_cursor = m_selstart;
2987 } else if (m_selstart != m_selend) {
2993 emitCursorPositionChanged();
2996 emit q->selectionChanged();
2997 emitCursorPositionChanged();
2998 q->updateInputMethod(Qt::ImCursorRectangle | Qt::ImAnchorPosition
2999 | Qt::ImCursorPosition | Qt::ImCurrentSelection);
3005 Sets the password echo editing to \a editing. If password echo editing
3006 is true, then the text of the password is displayed even if the echo
3007 mode is set to QLineEdit::PasswordEchoOnEdit. Password echoing editing
3008 does not affect other echo modes.
3010 void QQuickTextInputPrivate::updatePasswordEchoEditing(bool editing)
3012 cancelPasswordEchoTimer();
3013 m_passwordEchoEditing = editing;
3014 updateDisplayText();
3020 Fixes the current text so that it is valid given any set validators.
3022 Returns true if the text was changed. Otherwise returns false.
3024 bool QQuickTextInputPrivate::fixup() // this function assumes that validate currently returns != Acceptable
3026 #ifndef QT_NO_VALIDATOR
3028 QString textCopy = m_text;
3029 int cursorCopy = m_cursor;
3030 m_validator->fixup(textCopy);
3031 if (m_validator->validate(textCopy, cursorCopy) == QValidator::Acceptable) {
3032 if (textCopy != m_text || cursorCopy != m_cursor)
3033 internalSetText(textCopy, cursorCopy);
3044 Moves the cursor to the given position \a pos. If \a mark is true will
3045 adjust the currently selected text.
3047 void QQuickTextInputPrivate::moveCursor(int pos, bool mark)
3049 Q_Q(QQuickTextInput);
3052 if (pos != m_cursor) {
3055 pos = pos > m_cursor ? nextMaskBlank(pos) : prevMaskBlank(pos);
3059 if (m_selend > m_selstart && m_cursor == m_selstart)
3061 else if (m_selend > m_selstart && m_cursor == m_selend)
3062 anchor = m_selstart;
3065 m_selstart = qMin(anchor, pos);
3066 m_selend = qMax(anchor, pos);
3071 if (mark || m_selDirty) {
3073 emit q->selectionChanged();
3075 emitCursorPositionChanged();
3076 q->updateInputMethod();
3082 Applies the given input method event \a event to the text of the line
3085 void QQuickTextInputPrivate::processInputMethodEvent(QInputMethodEvent *event)
3087 Q_Q(QQuickTextInput);
3089 int priorState = -1;
3090 bool isGettingInput = !event->commitString().isEmpty()
3091 || event->preeditString() != preeditAreaText()
3092 || event->replacementLength() > 0;
3093 bool cursorPositionChanged = false;
3094 bool selectionChange = false;
3095 m_preeditDirty = event->preeditString() != preeditAreaText();
3097 if (isGettingInput) {
3098 // If any text is being input, remove selected text.
3099 priorState = m_undoState;
3100 if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit && !m_passwordEchoEditing) {
3101 updatePasswordEchoEditing(true);
3103 m_selend = m_text.length();
3105 removeSelectedText();
3108 int c = m_cursor; // cursor position after insertion of commit string
3109 if (event->replacementStart() <= 0)
3110 c += event->commitString().length() - qMin(-event->replacementStart(), event->replacementLength());
3112 m_cursor += event->replacementStart();
3116 // insert commit string
3117 if (event->replacementLength()) {
3118 m_selstart = m_cursor;
3119 m_selend = m_selstart + event->replacementLength();
3120 m_selend = qMin(m_selend, m_text.length());
3121 removeSelectedText();
3123 if (!event->commitString().isEmpty()) {
3124 internalInsert(event->commitString());
3125 cursorPositionChanged = true;
3128 m_cursor = qBound(0, c, m_text.length());
3130 for (int i = 0; i < event->attributes().size(); ++i) {
3131 const QInputMethodEvent::Attribute &a = event->attributes().at(i);
3132 if (a.type == QInputMethodEvent::Selection) {
3133 m_cursor = qBound(0, a.start + a.length, m_text.length());
3135 m_selstart = qMax(0, qMin(a.start, m_text.length()));
3136 m_selend = m_cursor;
3137 if (m_selend < m_selstart) {
3138 qSwap(m_selstart, m_selend);
3140 selectionChange = true;
3142 m_selstart = m_selend = 0;
3144 cursorPositionChanged = true;
3148 m_textLayout.setPreeditArea(m_cursor, event->preeditString());
3150 const int oldPreeditCursor = m_preeditCursor;
3151 m_preeditCursor = event->preeditString().length();
3152 hasImState = !event->preeditString().isEmpty();
3153 bool cursorVisible = true;
3154 QList<QTextLayout::FormatRange> formats;
3155 for (int i = 0; i < event->attributes().size(); ++i) {
3156 const QInputMethodEvent::Attribute &a = event->attributes().at(i);
3157 if (a.type == QInputMethodEvent::Cursor) {
3159 m_preeditCursor = a.start;
3160 cursorVisible = a.length != 0;
3161 } else if (a.type == QInputMethodEvent::TextFormat) {
3163 QTextCharFormat f = qvariant_cast<QTextFormat>(a.value).toCharFormat();
3165 QTextLayout::FormatRange o;
3166 o.start = a.start + m_cursor;
3167 o.length = a.length;
3173 m_textLayout.setAdditionalFormats(formats);
3175 updateDisplayText(/*force*/ true);
3176 if ((cursorPositionChanged && !emitCursorPositionChanged())
3177 || m_preeditCursor != oldPreeditCursor
3178 || isGettingInput) {
3179 q->updateCursorRectangle();
3183 finishChange(priorState);
3185 q->setCursorVisible(cursorVisible);
3187 if (selectionChange) {
3188 emit q->selectionChanged();
3189 q->updateInputMethod(Qt::ImCursorRectangle | Qt::ImAnchorPosition
3190 | Qt::ImCursorPosition | Qt::ImCurrentSelection);
3197 Sets the selection to cover the word at the given cursor position.
3198 The word boundaries are defined by the behavior of QTextLayout::SkipWords
3201 void QQuickTextInputPrivate::selectWordAtPos(int cursor)
3203 int next = cursor + 1;
3206 int c = m_textLayout.previousCursorPosition(next, QTextLayout::SkipWords);
3207 moveCursor(c, false);
3208 // ## text layout should support end of words.
3209 int end = m_textLayout.nextCursorPosition(c, QTextLayout::SkipWords);
3210 while (end > cursor && m_text[end-1].isSpace())
3212 moveCursor(end, true);
3218 Completes a change to the line control text. If the change is not valid
3219 will undo the line control state back to the given \a validateFromState.
3221 If \a edited is true and the change is valid, will emit textEdited() in
3222 addition to textChanged(). Otherwise only emits textChanged() on a valid
3225 The \a update value is currently unused.
3227 bool QQuickTextInputPrivate::finishChange(int validateFromState, bool update, bool /*edited*/)
3229 Q_Q(QQuickTextInput);
3232 bool inputMethodAttributesChanged = m_textDirty || m_selDirty;
3233 bool alignmentChanged = false;
3237 bool wasValidInput = m_validInput;
3238 bool wasAcceptable = m_acceptableInput;
3239 m_validInput = true;
3240 m_acceptableInput = true;
3241 #ifndef QT_NO_VALIDATOR
3243 QString textCopy = m_text;
3244 int cursorCopy = m_cursor;
3245 QValidator::State state = m_validator->validate(textCopy, cursorCopy);
3246 m_validInput = state != QValidator::Invalid;
3247 m_acceptableInput = state == QValidator::Acceptable;
3249 if (m_text != textCopy) {
3250 internalSetText(textCopy, cursorCopy);
3253 m_cursor = cursorCopy;
3257 if (validateFromState >= 0 && wasValidInput && !m_validInput) {
3258 if (m_transactions.count())
3260 internalUndo(validateFromState);
3261 m_history.resize(m_undoState);
3262 m_validInput = true;
3263 m_acceptableInput = wasAcceptable;
3264 m_textDirty = false;
3268 m_textDirty = false;
3269 m_preeditDirty = false;
3270 alignmentChanged = determineHorizontalAlignment();
3271 emit q->textChanged();
3274 updateDisplayText(alignmentChanged);
3276 if (m_acceptableInput != wasAcceptable)
3277 emit q->acceptableInputChanged();
3279 if (m_preeditDirty) {
3280 m_preeditDirty = false;
3281 if (determineHorizontalAlignment()) {
3282 alignmentChanged = true;
3289 emit q->selectionChanged();
3292 inputMethodAttributesChanged |= (m_cursor != m_lastCursorPos);
3293 if (inputMethodAttributesChanged)
3294 q->updateInputMethod();
3295 emitUndoRedoChanged();
3297 if (!emitCursorPositionChanged() && alignmentChanged)
3298 q->updateCursorRectangle();
3306 An internal function for setting the text of the line control.
3308 void QQuickTextInputPrivate::internalSetText(const QString &txt, int pos, bool edited)
3310 Q_Q(QQuickTextInput);
3312 QString oldText = m_text;
3314 m_text = maskString(0, txt, true);
3315 m_text += clearString(m_text.length(), m_maxLength - m_text.length());
3317 m_text = txt.isEmpty() ? txt : txt.left(m_maxLength);
3321 m_cursor = (pos < 0 || pos > m_text.length()) ? m_text.length() : pos;
3322 m_textDirty = (oldText != m_text);
3324 bool changed = finishChange(-1, true, edited);
3325 #ifdef QT_NO_ACCESSIBILITY
3329 QAccessibleTextUpdateEvent ev(q, 0, oldText, m_text);
3330 QAccessible::updateAccessibility(&ev);
3339 Adds the given \a command to the undo history
3340 of the line control. Does not apply the command.
3342 void QQuickTextInputPrivate::addCommand(const Command &cmd)
3344 if (m_separator && m_undoState && m_history[m_undoState - 1].type != Separator) {
3345 m_history.resize(m_undoState + 2);
3346 m_history[m_undoState++] = Command(Separator, m_cursor, 0, m_selstart, m_selend);
3348 m_history.resize(m_undoState + 1);
3350 m_separator = false;
3351 m_history[m_undoState++] = cmd;
3357 Inserts the given string \a s into the line
3360 Also adds the appropriate commands into the undo history.
3361 This function does not call finishChange(), and may leave the text
3362 in an invalid state.
3364 void QQuickTextInputPrivate::internalInsert(const QString &s)
3366 Q_Q(QQuickTextInput);
3367 if (m_echoMode == QQuickTextInput::Password) {
3368 int delay = qGuiApp->styleHints()->passwordMaskDelay();
3370 m_passwordEchoTimer.start(delay, q);
3372 if (hasSelectedText())
3373 addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
3375 QString ms = maskString(m_cursor, s);
3376 for (int i = 0; i < (int) ms.length(); ++i) {
3377 addCommand (Command(DeleteSelection, m_cursor + i, m_text.at(m_cursor + i), -1, -1));
3378 addCommand(Command(Insert, m_cursor + i, ms.at(i), -1, -1));
3380 m_text.replace(m_cursor, ms.length(), ms);
3381 m_cursor += ms.length();
3382 m_cursor = nextMaskBlank(m_cursor);
3385 int remaining = m_maxLength - m_text.length();
3386 if (remaining != 0) {
3387 m_text.insert(m_cursor, s.left(remaining));
3388 for (int i = 0; i < (int) s.left(remaining).length(); ++i)
3389 addCommand(Command(Insert, m_cursor++, s.at(i), -1, -1));
3398 deletes a single character from the current text. If \a wasBackspace,
3399 the character prior to the cursor is removed. Otherwise the character
3400 after the cursor is removed.
3402 Also adds the appropriate commands into the undo history.
3403 This function does not call finishChange(), and may leave the text
3404 in an invalid state.
3406 void QQuickTextInputPrivate::internalDelete(bool wasBackspace)
3408 if (m_cursor < (int) m_text.length()) {
3409 cancelPasswordEchoTimer();
3410 if (hasSelectedText())
3411 addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
3412 addCommand(Command((CommandType)((m_maskData ? 2 : 0) + (wasBackspace ? Remove : Delete)),
3413 m_cursor, m_text.at(m_cursor), -1, -1));
3415 m_text.replace(m_cursor, 1, clearString(m_cursor, 1));
3416 addCommand(Command(Insert, m_cursor, m_text.at(m_cursor), -1, -1));
3418 m_text.remove(m_cursor, 1);
3427 removes the currently selected text from the line control.
3429 Also adds the appropriate commands into the undo history.
3430 This function does not call finishChange(), and may leave the text
3431 in an invalid state.
3433 void QQuickTextInputPrivate::removeSelectedText()
3435 if (m_selstart < m_selend && m_selend <= (int) m_text.length()) {
3436 cancelPasswordEchoTimer();
3439 addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
3440 if (m_selstart <= m_cursor && m_cursor < m_selend) {
3441 // cursor is within the selection. Split up the commands
3442 // to be able to restore the correct cursor position
3443 for (i = m_cursor; i >= m_selstart; --i)
3444 addCommand (Command(DeleteSelection, i, m_text.at(i), -1, 1));
3445 for (i = m_selend - 1; i > m_cursor; --i)
3446 addCommand (Command(DeleteSelection, i - m_cursor + m_selstart - 1, m_text.at(i), -1, -1));
3448 for (i = m_selend-1; i >= m_selstart; --i)
3449 addCommand (Command(RemoveSelection, i, m_text.at(i), -1, -1));
3452 m_text.replace(m_selstart, m_selend - m_selstart, clearString(m_selstart, m_selend - m_selstart));
3453 for (int i = 0; i < m_selend - m_selstart; ++i)
3454 addCommand(Command(Insert, m_selstart + i, m_text.at(m_selstart + i), -1, -1));
3456 m_text.remove(m_selstart, m_selend - m_selstart);
3458 if (m_cursor > m_selstart)
3459 m_cursor -= qMin(m_cursor, m_selend) - m_selstart;
3468 Parses the input mask specified by \a maskFields to generate
3469 the mask data used to handle input masks.
3471 void QQuickTextInputPrivate::parseInputMask(const QString &maskFields)
3473 int delimiter = maskFields.indexOf(QLatin1Char(';'));
3474 if (maskFields.isEmpty() || delimiter == 0) {
3476 delete [] m_maskData;
3478 m_maxLength = 32767;
3479 internalSetText(QString());
3484 if (delimiter == -1) {
3485 m_blank = QLatin1Char(' ');
3486 m_inputMask = maskFields;
3488 m_inputMask = maskFields.left(delimiter);
3489 m_blank = (delimiter + 1 < maskFields.length()) ? maskFields[delimiter + 1] : QLatin1Char(' ');
3492 // calculate m_maxLength / m_maskData length
3495 for (int i=0; i<m_inputMask.length(); i++) {
3496 c = m_inputMask.at(i);
3497 if (i > 0 && m_inputMask.at(i-1) == QLatin1Char('\\')) {
3501 if (c != QLatin1Char('\\') && c != QLatin1Char('!') &&
3502 c != QLatin1Char('<') && c != QLatin1Char('>') &&
3503 c != QLatin1Char('{') && c != QLatin1Char('}') &&
3504 c != QLatin1Char('[') && c != QLatin1Char(']'))
3508 delete [] m_maskData;
3509 m_maskData = new MaskInputData[m_maxLength];
3511 MaskInputData::Casemode m = MaskInputData::NoCaseMode;
3514 bool escape = false;
3516 for (int i = 0; i < m_inputMask.length(); i++) {
3517 c = m_inputMask.at(i);
3520 m_maskData[index].maskChar = c;
3521 m_maskData[index].separator = s;
3522 m_maskData[index].caseMode = m;
3525 } else if (c == QLatin1Char('<')) {
3526 m = MaskInputData::Lower;
3527 } else if (c == QLatin1Char('>')) {
3528 m = MaskInputData::Upper;
3529 } else if (c == QLatin1Char('!')) {
3530 m = MaskInputData::NoCaseMode;
3531 } else if (c != QLatin1Char('{') && c != QLatin1Char('}') && c != QLatin1Char('[') && c != QLatin1Char(']')) {
3532 switch (c.unicode()) {
3558 m_maskData[index].maskChar = c;
3559 m_maskData[index].separator = s;
3560 m_maskData[index].caseMode = m;
3565 internalSetText(m_text);
3572 checks if the key is valid compared to the inputMask
3574 bool QQuickTextInputPrivate::isValidInput(QChar key, QChar mask) const
3576 switch (mask.unicode()) {
3582 if (key.isLetter() || key == m_blank)
3586 if (key.isLetterOrNumber())
3590 if (key.isLetterOrNumber() || key == m_blank)
3598 if (key.isPrint() || key == m_blank)
3606 if (key.isNumber() || key == m_blank)
3610 if (key.isNumber() && key.digitValue() > 0)
3614 if ((key.isNumber() && key.digitValue() > 0) || key == m_blank)
3618 if (key.isNumber() || key == QLatin1Char('+') || key == QLatin1Char('-') || key == m_blank)
3622 if (key == QLatin1Char('0') || key == QLatin1Char('1'))
3626 if (key == QLatin1Char('0') || key == QLatin1Char('1') || key == m_blank)
3630 if (key.isNumber() || (key >= QLatin1Char('a') && key <= QLatin1Char('f')) || (key >= QLatin1Char('A') && key <= QLatin1Char('F')))
3634 if (key.isNumber() || (key >= QLatin1Char('a') && key <= QLatin1Char('f')) || (key >= QLatin1Char('A') && key <= QLatin1Char('F')) || key == m_blank)
3646 Returns true if the given text \a str is valid for any
3647 validator or input mask set for the line control.
3649 Otherwise returns false
3651 QQuickTextInputPrivate::ValidatorState QQuickTextInputPrivate::hasAcceptableInput(const QString &str) const
3653 #ifndef QT_NO_VALIDATOR
3654 QString textCopy = str;
3655 int cursorCopy = m_cursor;
3657 QValidator::State state = m_validator->validate(textCopy, cursorCopy);
3658 if (state != QValidator::Acceptable)
3659 return ValidatorState(state);
3664 return AcceptableInput;
3666 if (str.length() != m_maxLength)
3667 return InvalidInput;
3669 for (int i=0; i < m_maxLength; ++i) {
3670 if (m_maskData[i].separator) {
3671 if (str.at(i) != m_maskData[i].maskChar)
3672 return InvalidInput;
3674 if (!isValidInput(str.at(i), m_maskData[i].maskChar))
3675 return InvalidInput;
3678 return AcceptableInput;
3684 Applies the inputMask on \a str starting from position \a pos in the mask. \a clear
3685 specifies from where characters should be gotten when a separator is met in \a str - true means
3686 that blanks will be used, false that previous input is used.
3687 Calling this when no inputMask is set is undefined.
3689 QString QQuickTextInputPrivate::maskString(uint pos, const QString &str, bool clear) const
3691 if (pos >= (uint)m_maxLength)
3692 return QString::fromLatin1("");
3695 fill = clear ? clearString(0, m_maxLength) : m_text;
3698 QString s = QString::fromLatin1("");
3700 while (i < m_maxLength) {
3701 if (strIndex < str.length()) {
3702 if (m_maskData[i].separator) {
3703 s += m_maskData[i].maskChar;
3704 if (str[(int)strIndex] == m_maskData[i].maskChar)
3708 if (isValidInput(str[(int)strIndex], m_maskData[i].maskChar)) {
3709 switch (m_maskData[i].caseMode) {
3710 case MaskInputData::Upper:
3711 s += str[(int)strIndex].toUpper();
3713 case MaskInputData::Lower:
3714 s += str[(int)strIndex].toLower();
3717 s += str[(int)strIndex];
3721 // search for separator first
3722 int n = findInMask(i, true, true, str[(int)strIndex]);
3724 if (str.length() != 1 || i == 0 || (i > 0 && (!m_maskData[i-1].separator || m_maskData[i-1].maskChar != str[(int)strIndex]))) {
3725 s += fill.mid(i, n-i+1);
3726 i = n + 1; // update i to find + 1
3729 // search for valid m_blank if not
3730 n = findInMask(i, true, false, str[(int)strIndex]);
3732 s += fill.mid(i, n-i);
3733 switch (m_maskData[n].caseMode) {
3734 case MaskInputData::Upper:
3735 s += str[(int)strIndex].toUpper();
3737 case MaskInputData::Lower:
3738 s += str[(int)strIndex].toLower();
3741 s += str[(int)strIndex];
3743 i = n + 1; // updates i to find + 1
3761 Returns a "cleared" string with only separators and blank chars.
3762 Calling this when no inputMask is set is undefined.
3764 QString QQuickTextInputPrivate::clearString(uint pos, uint len) const
3766 if (pos >= (uint)m_maxLength)
3770 int end = qMin((uint)m_maxLength, pos + len);
3771 for (int i = pos; i < end; ++i)
3772 if (m_maskData[i].separator)
3773 s += m_maskData[i].maskChar;
3783 Strips blank parts of the input in a QQuickTextInputPrivate when an inputMask is set,
3784 separators are still included. Typically "127.0__.0__.1__" becomes "127.0.0.1".
3786 QString QQuickTextInputPrivate::stripString(const QString &str) const
3792 int end = qMin(m_maxLength, (int)str.length());
3793 for (int i = 0; i < end; ++i) {
3794 if (m_maskData[i].separator)
3795 s += m_maskData[i].maskChar;
3796 else if (str[i] != m_blank)
3805 searches forward/backward in m_maskData for either a separator or a m_blank
3807 int QQuickTextInputPrivate::findInMask(int pos, bool forward, bool findSeparator, QChar searchChar) const
3809 if (pos >= m_maxLength || pos < 0)
3812 int end = forward ? m_maxLength : -1;
3813 int step = forward ? 1 : -1;
3817 if (findSeparator) {
3818 if (m_maskData[i].separator && m_maskData[i].maskChar == searchChar)
3821 if (!m_maskData[i].separator) {
3822 if (searchChar.isNull())
3824 else if (isValidInput(searchChar, m_maskData[i].maskChar))
3833 void QQuickTextInputPrivate::internalUndo(int until)
3835 if (!isUndoAvailable())
3837 cancelPasswordEchoTimer();
3839 while (m_undoState && m_undoState > until) {
3840 Command& cmd = m_history[--m_undoState];
3843 m_text.remove(cmd.pos, 1);
3847 m_selstart = cmd.selStart;
3848 m_selend = cmd.selEnd;
3852 case RemoveSelection:
3853 m_text.insert(cmd.pos, cmd.uc);
3854 m_cursor = cmd.pos + 1;
3857 case DeleteSelection:
3858 m_text.insert(cmd.pos, cmd.uc);
3864 if (until < 0 && m_undoState) {
3865 Command& next = m_history[m_undoState-1];
3866 if (next.type != cmd.type && next.type < RemoveSelection
3867 && (cmd.type < RemoveSelection || next.type == Separator))
3874 void QQuickTextInputPrivate::internalRedo()
3876 if (!isRedoAvailable())
3879 while (m_undoState < (int)m_history.size()) {
3880 Command& cmd = m_history[m_undoState++];
3883 m_text.insert(cmd.pos, cmd.uc);
3884 m_cursor = cmd.pos + 1;
3887 m_selstart = cmd.selStart;
3888 m_selend = cmd.selEnd;
3893 case RemoveSelection:
3894 case DeleteSelection:
3895 m_text.remove(cmd.pos, 1);
3896 m_selstart = cmd.selStart;
3897 m_selend = cmd.selEnd;
3901 m_selstart = cmd.selStart;
3902 m_selend = cmd.selEnd;
3906 if (m_undoState < (int)m_history.size()) {
3907 Command& next = m_history[m_undoState];
3908 if (next.type != cmd.type && cmd.type < RemoveSelection && next.type != Separator
3909 && (next.type < RemoveSelection || cmd.type == Separator))
3916 void QQuickTextInputPrivate::emitUndoRedoChanged()
3918 Q_Q(QQuickTextInput);
3919 const bool previousUndo = canUndo;
3920 const bool previousRedo = canRedo;
3922 canUndo = isUndoAvailable();
3923 canRedo = isRedoAvailable();
3925 if (previousUndo != canUndo)
3926 emit q->canUndoChanged();
3927 if (previousRedo != canRedo)
3928 emit q->canRedoChanged();
3934 If the current cursor position differs from the last emitted cursor
3935 position, emits cursorPositionChanged().
3937 bool QQuickTextInputPrivate::emitCursorPositionChanged()
3939 Q_Q(QQuickTextInput);
3940 if (m_cursor != m_lastCursorPos) {
3941 m_lastCursorPos = m_cursor;
3943 q->updateCursorRectangle();
3944 emit q->cursorPositionChanged();
3946 if (!hasSelectedText()) {
3947 if (lastSelectionStart != m_cursor) {
3948 lastSelectionStart = m_cursor;
3949 emit q->selectionStartChanged();
3951 if (lastSelectionEnd != m_cursor) {
3952 lastSelectionEnd = m_cursor;
3953 emit q->selectionEndChanged();
3957 #ifndef QT_NO_ACCESSIBILITY
3958 QAccessibleTextCursorEvent ev(q, m_cursor);
3959 QAccessible::updateAccessibility(&ev);
3968 void QQuickTextInputPrivate::setCursorBlinkPeriod(int msec)
3970 Q_Q(QQuickTextInput);
3971 if (msec == m_blinkPeriod)
3974 q->killTimer(m_blinkTimer);
3977 m_blinkTimer = q->startTimer(msec / 2);
3981 if (m_blinkStatus == 1) {
3982 updateType = UpdatePaintNode;
3986 m_blinkPeriod = msec;
3989 void QQuickTextInput::timerEvent(QTimerEvent *event)
3991 Q_D(QQuickTextInput);
3992 if (event->timerId() == d->m_blinkTimer) {
3993 d->m_blinkStatus = !d->m_blinkStatus;
3994 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
3996 } else if (event->timerId() == d->m_passwordEchoTimer.timerId()) {
3997 d->m_passwordEchoTimer.stop();
3998 d->updateDisplayText();
3999 updateCursorRectangle();
4003 void QQuickTextInputPrivate::processKeyEvent(QKeyEvent* event)
4005 Q_Q(QQuickTextInput);
4006 bool inlineCompletionAccepted = false;
4008 if (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return) {
4009 if (hasAcceptableInput(m_text) || fixup()) {
4012 if (inlineCompletionAccepted)
4019 if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit
4020 && !m_passwordEchoEditing
4022 && !event->text().isEmpty()
4023 && !(event->modifiers() & Qt::ControlModifier)) {
4024 // Clear the edit and reset to normal echo mode while editing; the
4025 // echo mode switches back when the edit loses focus
4026 // ### resets current content. dubious code; you can
4027 // navigate with keys up, down, back, and select(?), but if you press
4028 // "left" or "right" it clears?
4029 updatePasswordEchoEditing(true);
4033 bool unknown = false;
4034 bool visual = cursorMoveStyle() == Qt::VisualMoveStyle;
4038 #ifndef QT_NO_SHORTCUT
4039 else if (event == QKeySequence::Undo) {
4042 else if (event == QKeySequence::Redo) {
4045 else if (event == QKeySequence::SelectAll) {
4048 #ifndef QT_NO_CLIPBOARD
4049 else if (event == QKeySequence::Copy) {
4052 else if (event == QKeySequence::Paste) {
4054 QClipboard::Mode mode = QClipboard::Clipboard;
4058 else if (event == QKeySequence::Cut) {
4064 else if (event == QKeySequence::DeleteEndOfLine) {
4066 setSelection(m_cursor, end());
4071 #endif //QT_NO_CLIPBOARD
4072 else if (event == QKeySequence::MoveToStartOfLine || event == QKeySequence::MoveToStartOfBlock) {
4075 else if (event == QKeySequence::MoveToEndOfLine || event == QKeySequence::MoveToEndOfBlock) {
4078 else if (event == QKeySequence::SelectStartOfLine || event == QKeySequence::SelectStartOfBlock) {
4081 else if (event == QKeySequence::SelectEndOfLine || event == QKeySequence::SelectEndOfBlock) {
4084 else if (event == QKeySequence::MoveToNextChar) {
4085 if (hasSelectedText()) {
4086 moveCursor(selectionEnd(), false);
4088 cursorForward(0, visual ? 1 : (layoutDirection() == Qt::LeftToRight ? 1 : -1));
4091 else if (event == QKeySequence::SelectNextChar) {
4092 cursorForward(1, visual ? 1 : (layoutDirection() == Qt::LeftToRight ? 1 : -1));
4094 else if (event == QKeySequence::MoveToPreviousChar) {
4095 if (hasSelectedText()) {
4096 moveCursor(selectionStart(), false);
4098 cursorForward(0, visual ? -1 : (layoutDirection() == Qt::LeftToRight ? -1 : 1));
4101 else if (event == QKeySequence::SelectPreviousChar) {
4102 cursorForward(1, visual ? -1 : (layoutDirection() == Qt::LeftToRight ? -1 : 1));
4104 else if (event == QKeySequence::MoveToNextWord) {
4105 if (m_echoMode == QQuickTextInput::Normal)
4106 layoutDirection() == Qt::LeftToRight ? cursorWordForward(0) : cursorWordBackward(0);
4108 layoutDirection() == Qt::LeftToRight ? end(0) : home(0);
4110 else if (event == QKeySequence::MoveToPreviousWord) {
4111 if (m_echoMode == QQuickTextInput::Normal)
4112 layoutDirection() == Qt::LeftToRight ? cursorWordBackward(0) : cursorWordForward(0);
4113 else if (!m_readOnly) {
4114 layoutDirection() == Qt::LeftToRight ? home(0) : end(0);
4117 else if (event == QKeySequence::SelectNextWord) {
4118 if (m_echoMode == QQuickTextInput::Normal)
4119 layoutDirection() == Qt::LeftToRight ? cursorWordForward(1) : cursorWordBackward(1);
4121 layoutDirection() == Qt::LeftToRight ? end(1) : home(1);
4123 else if (event == QKeySequence::SelectPreviousWord) {
4124 if (m_echoMode == QQuickTextInput::Normal)
4125 layoutDirection() == Qt::LeftToRight ? cursorWordBackward(1) : cursorWordForward(1);
4127 layoutDirection() == Qt::LeftToRight ? home(1) : end(1);
4129 else if (event == QKeySequence::Delete) {
4133 else if (event == QKeySequence::DeleteEndOfWord) {
4135 cursorWordForward(true);
4139 else if (event == QKeySequence::DeleteStartOfWord) {
4141 cursorWordBackward(true);
4145 #endif // QT_NO_SHORTCUT
4147 bool handled = false;
4148 if (event->modifiers() & Qt::ControlModifier) {
4149 switch (event->key()) {
4150 case Qt::Key_Backspace:
4152 cursorWordBackward(true);
4160 } else { // ### check for *no* modifier
4161 switch (event->key()) {
4162 case Qt::Key_Backspace:
4174 if (event->key() == Qt::Key_Direction_L || event->key() == Qt::Key_Direction_R) {
4175 setLayoutDirection((event->key() == Qt::Key_Direction_L) ? Qt::LeftToRight : Qt::RightToLeft);
4179 if (unknown && !m_readOnly) {
4180 QString t = event->text();
4181 if (!t.isEmpty() && t.at(0).isPrint()) {