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 qml-basic-visual-elements
73 \brief Displays an editable line of text
75 The TextInput element displays a single line of editable plain text.
77 TextInput is used to accept a line of text input. Input constraints
78 can be placed on a TextInput item (for example, through a \l validator or \l inputMask),
79 and setting \l echoMode to an appropriate value enables TextInput to be used for
80 a password input field.
82 On Mac OS X, the Up/Down key bindings for Home/End are explicitly disabled.
83 If you want such bindings (on any platform), you will need to construct them in QML.
85 \sa TextEdit, Text, {declarative/text/textselection}{Text Selection example}
87 QQuickTextInput::QQuickTextInput(QQuickItem* parent)
88 : QQuickImplicitSizeItem(*(new QQuickTextInputPrivate), parent)
94 QQuickTextInput::~QQuickTextInput()
98 void QQuickTextInput::componentComplete()
100 Q_D(QQuickTextInput);
102 QQuickImplicitSizeItem::componentComplete();
106 updateCursorRectangle();
107 if (d->cursorComponent && isCursorVisible())
108 QQuickTextUtil::createCursor(d);
112 \qmlproperty string QtQuick2::TextInput::text
114 The text in the TextInput.
116 QString QQuickTextInput::text() const
118 Q_D(const QQuickTextInput);
120 QString content = d->m_text;
121 QString res = d->m_maskData ? d->stripString(content) : content;
122 return (res.isNull() ? QString::fromLatin1("") : res);
125 void QQuickTextInput::setText(const QString &s)
127 Q_D(QQuickTextInput);
132 d->internalSetText(s, -1, false);
136 \qmlproperty int QtQuick2::TextInput::length
138 Returns the total number of characters in the TextInput item.
140 If the TextInput has an inputMask the length will include mask characters and may differ
141 from the length of the string returned by the \l text property.
143 This property can be faster than querying the length the \l text property as it doesn't
144 require any copying or conversion of the TextInput's internal string data.
147 int QQuickTextInput::length() const
149 Q_D(const QQuickTextInput);
150 return d->m_text.length();
154 \qmlmethod string QtQuick2::TextInput::getText(int start, int end)
156 Returns the section of text that is between the \a start and \a end positions.
158 If the TextInput has an inputMask the length will include mask characters.
161 QString QQuickTextInput::getText(int start, int end) const
163 Q_D(const QQuickTextInput);
168 return d->m_text.mid(start, end - start);
171 QString QQuickTextInputPrivate::realText() const
173 QString res = m_maskData ? stripString(m_text) : m_text;
174 return (res.isNull() ? QString::fromLatin1("") : res);
178 \qmlproperty string QtQuick2::TextInput::font.family
180 Sets the family name of the font.
182 The family name is case insensitive and may optionally include a foundry name, e.g. "Helvetica [Cronyx]".
183 If the family is available from more than one foundry and the foundry isn't specified, an arbitrary foundry is chosen.
184 If the family isn't available a family will be set using the font matching algorithm.
188 \qmlproperty bool QtQuick2::TextInput::font.bold
190 Sets whether the font weight is bold.
194 \qmlproperty enumeration QtQuick2::TextInput::font.weight
196 Sets the font's weight.
198 The weight can be one of:
201 \li Font.Normal - the default
208 TextInput { text: "Hello"; font.weight: Font.DemiBold }
213 \qmlproperty bool QtQuick2::TextInput::font.italic
215 Sets whether the font has an italic style.
219 \qmlproperty bool QtQuick2::TextInput::font.underline
221 Sets whether the text is underlined.
225 \qmlproperty bool QtQuick2::TextInput::font.strikeout
227 Sets whether the font has a strikeout style.
231 \qmlproperty real QtQuick2::TextInput::font.pointSize
233 Sets the font size in points. The point size must be greater than zero.
237 \qmlproperty int QtQuick2::TextInput::font.pixelSize
239 Sets the font size in pixels.
241 Using this function makes the font device dependent.
242 Use \c pointSize to set the size of the font in a device independent manner.
246 \qmlproperty real QtQuick2::TextInput::font.letterSpacing
248 Sets the letter spacing for the font.
250 Letter spacing changes the default spacing between individual letters in the font.
251 A positive value increases the letter spacing by the corresponding pixels; a negative value decreases the spacing.
255 \qmlproperty real QtQuick2::TextInput::font.wordSpacing
257 Sets the word spacing for the font.
259 Word spacing changes the default spacing between individual words.
260 A positive value increases the word spacing by a corresponding amount of pixels,
261 while a negative value decreases the inter-word spacing accordingly.
265 \qmlproperty enumeration QtQuick2::TextInput::font.capitalization
267 Sets the capitalization for the text.
270 \li Font.MixedCase - This is the normal text rendering option where no capitalization change is applied.
271 \li Font.AllUppercase - This alters the text to be rendered in all uppercase type.
272 \li Font.AllLowercase - This alters the text to be rendered in all lowercase type.
273 \li Font.SmallCaps - This alters the text to be rendered in small-caps type.
274 \li Font.Capitalize - This alters the text to be rendered with the first character of each word as an uppercase character.
278 TextInput { text: "Hello"; font.capitalization: Font.AllLowercase }
282 QFont QQuickTextInput::font() const
284 Q_D(const QQuickTextInput);
285 return d->sourceFont;
288 void QQuickTextInput::setFont(const QFont &font)
290 Q_D(QQuickTextInput);
291 if (d->sourceFont == font)
294 d->sourceFont = font;
295 QFont oldFont = d->font;
297 if (d->font.pointSizeF() != -1) {
299 qreal size = qRound(d->font.pointSizeF()*2.0);
300 d->font.setPointSizeF(size/2.0);
302 if (oldFont != d->font) {
304 updateCursorRectangle();
305 updateInputMethod(Qt::ImCursorRectangle | Qt::ImFont);
307 emit fontChanged(d->sourceFont);
311 \qmlproperty color QtQuick2::TextInput::color
315 QColor QQuickTextInput::color() const
317 Q_D(const QQuickTextInput);
321 void QQuickTextInput::setColor(const QColor &c)
323 Q_D(QQuickTextInput);
326 d->textLayoutDirty = true;
327 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
335 \qmlproperty color QtQuick2::TextInput::selectionColor
337 The text highlight color, used behind selections.
339 QColor QQuickTextInput::selectionColor() const
341 Q_D(const QQuickTextInput);
342 return d->selectionColor;
345 void QQuickTextInput::setSelectionColor(const QColor &color)
347 Q_D(QQuickTextInput);
348 if (d->selectionColor == color)
351 d->selectionColor = color;
352 if (d->hasSelectedText()) {
353 d->textLayoutDirty = true;
354 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
357 emit selectionColorChanged();
360 \qmlproperty color QtQuick2::TextInput::selectedTextColor
362 The highlighted text color, used in selections.
364 QColor QQuickTextInput::selectedTextColor() const
366 Q_D(const QQuickTextInput);
367 return d->selectedTextColor;
370 void QQuickTextInput::setSelectedTextColor(const QColor &color)
372 Q_D(QQuickTextInput);
373 if (d->selectedTextColor == color)
376 d->selectedTextColor = color;
377 if (d->hasSelectedText()) {
378 d->textLayoutDirty = true;
379 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
382 emit selectedTextColorChanged();
386 \qmlproperty enumeration QtQuick2::TextInput::horizontalAlignment
387 \qmlproperty enumeration QtQuick2::TextInput::effectiveHorizontalAlignment
388 \qmlproperty enumeration QtQuick2::TextInput::verticalAlignment
390 Sets the horizontal alignment of the text within the TextInput item's
391 width and height. By default, the text alignment follows the natural alignment
392 of the text, for example text that is read from left to right will be aligned to
395 TextInput does not have vertical alignment, as the natural height is
396 exactly the height of the single line of text. If you set the height
397 manually to something larger, TextInput will always be top aligned
398 vertically. You can use anchors to align it however you want within
401 The valid values for \c horizontalAlignment are \c TextInput.AlignLeft, \c TextInput.AlignRight and
402 \c TextInput.AlignHCenter.
404 Valid values for \c verticalAlignment are \c TextInput.AlignTop (default),
405 \c TextInput.AlignBottom \c TextInput.AlignVCenter.
407 When using the attached property LayoutMirroring::enabled to mirror application
408 layouts, the horizontal alignment of text will also be mirrored. However, the property
409 \c horizontalAlignment will remain unchanged. To query the effective horizontal alignment
410 of TextInput, use the read-only property \c effectiveHorizontalAlignment.
412 QQuickTextInput::HAlignment QQuickTextInput::hAlign() const
414 Q_D(const QQuickTextInput);
418 void QQuickTextInput::setHAlign(HAlignment align)
420 Q_D(QQuickTextInput);
421 bool forceAlign = d->hAlignImplicit && d->effectiveLayoutMirror;
422 d->hAlignImplicit = false;
423 if (d->setHAlign(align, forceAlign) && isComponentComplete()) {
425 updateCursorRectangle();
429 void QQuickTextInput::resetHAlign()
431 Q_D(QQuickTextInput);
432 d->hAlignImplicit = true;
433 if (d->determineHorizontalAlignment() && isComponentComplete()) {
435 updateCursorRectangle();
439 QQuickTextInput::HAlignment QQuickTextInput::effectiveHAlign() const
441 Q_D(const QQuickTextInput);
442 QQuickTextInput::HAlignment effectiveAlignment = d->hAlign;
443 if (!d->hAlignImplicit && d->effectiveLayoutMirror) {
445 case QQuickTextInput::AlignLeft:
446 effectiveAlignment = QQuickTextInput::AlignRight;
448 case QQuickTextInput::AlignRight:
449 effectiveAlignment = QQuickTextInput::AlignLeft;
455 return effectiveAlignment;
458 bool QQuickTextInputPrivate::setHAlign(QQuickTextInput::HAlignment alignment, bool forceAlign)
460 Q_Q(QQuickTextInput);
461 if ((hAlign != alignment || forceAlign) && alignment <= QQuickTextInput::AlignHCenter) { // justify not supported
462 QQuickTextInput::HAlignment oldEffectiveHAlign = q->effectiveHAlign();
464 emit q->horizontalAlignmentChanged(alignment);
465 if (oldEffectiveHAlign != q->effectiveHAlign())
466 emit q->effectiveHorizontalAlignmentChanged();
472 Qt::LayoutDirection QQuickTextInputPrivate::textDirection() const
474 QString text = m_text;
476 text = m_textLayout.preeditAreaText();
478 const QChar *character = text.constData();
479 while (!character->isNull()) {
480 switch (character->direction()) {
482 return Qt::LeftToRight;
486 return Qt::RightToLeft;
492 return Qt::LayoutDirectionAuto;
495 Qt::LayoutDirection QQuickTextInputPrivate::layoutDirection() const
497 Qt::LayoutDirection direction = m_layoutDirection;
498 if (direction == Qt::LayoutDirectionAuto) {
499 direction = textDirection();
500 if (direction == Qt::LayoutDirectionAuto)
501 direction = qApp->inputMethod()->inputDirection();
503 return (direction == Qt::LayoutDirectionAuto) ? Qt::LeftToRight : direction;
506 bool QQuickTextInputPrivate::determineHorizontalAlignment()
508 if (hAlignImplicit) {
509 // if no explicit alignment has been set, follow the natural layout direction of the text
510 Qt::LayoutDirection direction = textDirection();
511 if (direction == Qt::LayoutDirectionAuto)
512 direction = qApp->inputMethod()->inputDirection();
513 return setHAlign(direction == Qt::RightToLeft ? QQuickTextInput::AlignRight : QQuickTextInput::AlignLeft);
518 QQuickTextInput::VAlignment QQuickTextInput::vAlign() const
520 Q_D(const QQuickTextInput);
524 void QQuickTextInput::setVAlign(QQuickTextInput::VAlignment alignment)
526 Q_D(QQuickTextInput);
527 if (alignment == d->vAlign)
529 d->vAlign = alignment;
530 emit verticalAlignmentChanged(d->vAlign);
531 if (isComponentComplete()) {
532 updateCursorRectangle();
537 \qmlproperty enumeration QtQuick2::TextInput::wrapMode
539 Set this property to wrap the text to the TextInput item's width.
540 The text will only wrap if an explicit width has been set.
543 \li TextInput.NoWrap - no wrapping will be performed. If the text contains insufficient newlines, then implicitWidth will exceed a set width.
544 \li TextInput.WordWrap - wrapping is done on word boundaries only. If a word is too long, implicitWidth will exceed a set width.
545 \li TextInput.WrapAnywhere - wrapping is done at any point on a line, even if it occurs in the middle of a word.
546 \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.
549 The default is TextInput.NoWrap. If you set a width, consider using TextInput.Wrap.
551 QQuickTextInput::WrapMode QQuickTextInput::wrapMode() const
553 Q_D(const QQuickTextInput);
557 void QQuickTextInput::setWrapMode(WrapMode mode)
559 Q_D(QQuickTextInput);
560 if (mode == d->wrapMode)
564 updateCursorRectangle();
565 emit wrapModeChanged();
568 void QQuickTextInputPrivate::mirrorChange()
570 Q_Q(QQuickTextInput);
571 if (q->isComponentComplete()) {
572 if (!hAlignImplicit && (hAlign == QQuickTextInput::AlignRight || hAlign == QQuickTextInput::AlignLeft)) {
573 q->updateCursorRectangle();
574 emit q->effectiveHorizontalAlignmentChanged();
580 \qmlproperty bool QtQuick2::TextInput::readOnly
582 Sets whether user input can modify the contents of the TextInput.
584 If readOnly is set to true, then user input will not affect the text
585 property. Any bindings or attempts to set the text property will still
588 bool QQuickTextInput::isReadOnly() const
590 Q_D(const QQuickTextInput);
591 return d->m_readOnly;
594 void QQuickTextInput::setReadOnly(bool ro)
596 Q_D(QQuickTextInput);
597 if (d->m_readOnly == ro)
600 setFlag(QQuickItem::ItemAcceptsInputMethod, !ro);
603 d->setCursorPosition(d->end());
604 updateInputMethod(Qt::ImEnabled);
606 d->emitUndoRedoChanged();
607 emit readOnlyChanged(ro);
611 \qmlproperty int QtQuick2::TextInput::maximumLength
612 The maximum permitted length of the text in the TextInput.
614 If the text is too long, it is truncated at the limit.
616 By default, this property contains a value of 32767.
618 int QQuickTextInput::maxLength() const
620 Q_D(const QQuickTextInput);
621 return d->m_maxLength;
624 void QQuickTextInput::setMaxLength(int ml)
626 Q_D(QQuickTextInput);
627 if (d->m_maxLength == ml || d->m_maskData)
631 d->internalSetText(d->m_text, -1, false);
633 emit maximumLengthChanged(ml);
637 \qmlproperty bool QtQuick2::TextInput::cursorVisible
638 Set to true when the TextInput shows a cursor.
640 This property is set and unset when the TextInput gets active focus, so that other
641 properties can be bound to whether the cursor is currently showing. As it
642 gets set and unset automatically, when you set the value yourself you must
643 keep in mind that your value may be overwritten.
645 It can be set directly in script, for example if a KeyProxy might
646 forward keys to it and you desire it to look active when this happens
647 (but without actually giving it active focus).
649 It should not be set directly on the element, like in the below QML,
650 as the specified value will be overridden an lost on focus changes.
659 In the above snippet the cursor will still become visible when the
660 TextInput gains active focus.
662 bool QQuickTextInput::isCursorVisible() const
664 Q_D(const QQuickTextInput);
665 return d->cursorVisible;
668 void QQuickTextInput::setCursorVisible(bool on)
670 Q_D(QQuickTextInput);
671 if (d->cursorVisible == on)
673 d->cursorVisible = on;
674 if (on && isComponentComplete())
675 QQuickTextUtil::createCursor(d);
676 if (!d->cursorItem) {
677 d->setCursorBlinkPeriod(on ? qApp->styleHints()->cursorFlashTime() : 0);
678 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
681 emit cursorVisibleChanged(d->cursorVisible);
685 \qmlproperty int QtQuick2::TextInput::cursorPosition
686 The position of the cursor in the TextInput.
688 int QQuickTextInput::cursorPosition() const
690 Q_D(const QQuickTextInput);
694 void QQuickTextInput::setCursorPosition(int cp)
696 Q_D(QQuickTextInput);
697 if (cp < 0 || cp > text().length())
703 \qmlproperty rectangle QtQuick2::TextInput::cursorRectangle
705 The rectangle where the standard text cursor is rendered within the text input. Read only.
707 The position and height of a custom cursorDelegate are updated to follow the cursorRectangle
708 automatically when it changes. The width of the delegate is unaffected by changes in the
712 QRectF QQuickTextInput::cursorRectangle() const
714 Q_D(const QQuickTextInput);
716 int c = d->m_cursor + d->m_preeditCursor;
717 if (d->m_echoMode == NoEcho)
719 QTextLine l = d->m_textLayout.lineForTextPosition(c);
722 return QRectF(l.cursorToX(c) - d->hscroll, l.y() - d->vscroll, 1, l.height());
726 \qmlproperty int QtQuick2::TextInput::selectionStart
728 The cursor position before the first character in the current selection.
730 This property is read-only. To change the selection, use select(start,end),
731 selectAll(), or selectWord().
733 \sa selectionEnd, cursorPosition, selectedText
735 int QQuickTextInput::selectionStart() const
737 Q_D(const QQuickTextInput);
738 return d->lastSelectionStart;
741 \qmlproperty int QtQuick2::TextInput::selectionEnd
743 The cursor position after the last character in the current selection.
745 This property is read-only. To change the selection, use select(start,end),
746 selectAll(), or selectWord().
748 \sa selectionStart, cursorPosition, selectedText
750 int QQuickTextInput::selectionEnd() const
752 Q_D(const QQuickTextInput);
753 return d->lastSelectionEnd;
756 \qmlmethod void QtQuick2::TextInput::select(int start, int end)
758 Causes the text from \a start to \a end to be selected.
760 If either start or end is out of range, the selection is not changed.
762 After calling this, selectionStart will become the lesser
763 and selectionEnd will become the greater (regardless of the order passed
766 \sa selectionStart, selectionEnd
768 void QQuickTextInput::select(int start, int end)
770 Q_D(QQuickTextInput);
771 if (start < 0 || end < 0 || start > d->m_text.length() || end > d->m_text.length())
773 d->setSelection(start, end-start);
777 \qmlproperty string QtQuick2::TextInput::selectedText
779 This read-only property provides the text currently selected in the
782 It is equivalent to the following snippet, but is faster and easier
786 myTextInput.text.toString().substring(myTextInput.selectionStart,
787 myTextInput.selectionEnd);
790 QString QQuickTextInput::selectedText() const
792 Q_D(const QQuickTextInput);
793 return d->selectedText();
797 \qmlproperty bool QtQuick2::TextInput::activeFocusOnPress
799 Whether the TextInput should gain active focus on a mouse press. By default this is
802 bool QQuickTextInput::focusOnPress() const
804 Q_D(const QQuickTextInput);
805 return d->focusOnPress;
808 void QQuickTextInput::setFocusOnPress(bool b)
810 Q_D(QQuickTextInput);
811 if (d->focusOnPress == b)
816 emit activeFocusOnPressChanged(d->focusOnPress);
819 \qmlproperty bool QtQuick2::TextInput::autoScroll
821 Whether the TextInput should scroll when the text is longer than the width. By default this is
824 bool QQuickTextInput::autoScroll() const
826 Q_D(const QQuickTextInput);
827 return d->autoScroll;
830 void QQuickTextInput::setAutoScroll(bool b)
832 Q_D(QQuickTextInput);
833 if (d->autoScroll == b)
837 //We need to repaint so that the scrolling is taking into account.
838 updateCursorRectangle();
839 emit autoScrollChanged(d->autoScroll);
842 #ifndef QT_NO_VALIDATOR
845 \qmlclass IntValidator QIntValidator
846 \inqmlmodule QtQuick 2
847 \ingroup qml-basic-visual-elements
848 \brief Defines a validator for integer values
850 This element provides a validator for integer values.
852 If no \l locale is set IntValidator uses the \l {QLocale::setDefault()}{default locale} to
853 interpret the number and will accept locale specific digits, group separators, and positive
854 and negative signs. In addition, IntValidator is always guaranteed to accept a number
855 formatted according to the "C" locale.
859 QQuickIntValidator::QQuickIntValidator(QObject *parent)
860 : QIntValidator(parent)
865 \qmlproperty string QtQuick2::IntValidator::locale
867 This property holds the name of the locale used to interpret the number.
872 QString QQuickIntValidator::localeName() const
874 return locale().name();
877 void QQuickIntValidator::setLocaleName(const QString &name)
879 if (locale().name() != name) {
880 setLocale(QLocale(name));
881 emit localeNameChanged();
885 void QQuickIntValidator::resetLocaleName()
887 QLocale defaultLocale;
888 if (locale() != defaultLocale) {
889 setLocale(defaultLocale);
890 emit localeNameChanged();
895 \qmlproperty int QtQuick2::IntValidator::top
897 This property holds the validator's highest acceptable value.
898 By default, this property's value is derived from the highest signed integer available (typically 2147483647).
901 \qmlproperty int QtQuick2::IntValidator::bottom
903 This property holds the validator's lowest acceptable value.
904 By default, this property's value is derived from the lowest signed integer available (typically -2147483647).
908 \qmlclass DoubleValidator QDoubleValidator
909 \inqmlmodule QtQuick 2
910 \ingroup qml-basic-visual-elements
911 \brief Defines a validator for non-integer numbers
913 This element provides a validator for non-integer numbers.
915 Input is accepted if it contains a double that is within the valid range
916 and is in the correct format.
918 Input is accepected but invalid if it contains a double that is outside
919 the range or is in the wrong format; e.g. with too many digits after the
920 decimal point or is empty.
922 Input is rejected if it is not a double.
924 Note: If the valid range consists of just positive doubles (e.g. 0.0 to
925 100.0) and input is a negative double then it is rejected. If \l notation
926 is set to DoubleValidator.StandardNotation, and the input contains more
927 digits before the decimal point than a double in the valid range may have,
928 it is also rejected. If \l notation is DoubleValidator.ScientificNotation,
929 and the input is not in the valid range, it is accecpted but invalid. The
930 value may yet become valid by changing the exponent.
933 QQuickDoubleValidator::QQuickDoubleValidator(QObject *parent)
934 : QDoubleValidator(parent)
939 \qmlproperty string QtQuick2::DoubleValidator::locale
941 This property holds the name of the locale used to interpret the number.
946 QString QQuickDoubleValidator::localeName() const
948 return locale().name();
951 void QQuickDoubleValidator::setLocaleName(const QString &name)
953 if (locale().name() != name) {
954 setLocale(QLocale(name));
955 emit localeNameChanged();
959 void QQuickDoubleValidator::resetLocaleName()
961 QLocale defaultLocale;
962 if (locale() != defaultLocale) {
963 setLocale(defaultLocale);
964 emit localeNameChanged();
969 \qmlproperty real QtQuick2::DoubleValidator::top
971 This property holds the validator's maximum acceptable value.
972 By default, this property contains a value of infinity.
975 \qmlproperty real QtQuick2::DoubleValidator::bottom
977 This property holds the validator's minimum acceptable value.
978 By default, this property contains a value of -infinity.
981 \qmlproperty int QtQuick2::DoubleValidator::decimals
983 This property holds the validator's maximum number of digits after the decimal point.
984 By default, this property contains a value of 1000.
987 \qmlproperty enumeration QtQuick2::DoubleValidator::notation
988 This property holds the notation of how a string can describe a number.
990 The possible values for this property are:
993 \li DoubleValidator.StandardNotation
994 \li DoubleValidator.ScientificNotation (default)
997 If this property is set to DoubleValidator.ScientificNotation, the written number may have an exponent part (e.g. 1.5E-2).
1001 \qmlclass RegExpValidator QRegExpValidator
1002 \inqmlmodule QtQuick 2
1003 \ingroup qml-basic-visual-elements
1004 \brief Provides a string validator
1006 This element provides a validator, which counts as valid any string which
1007 matches a specified regular expression.
1010 \qmlproperty regExp QtQuick2::RegExpValidator::regExp
1012 This property holds the regular expression used for validation.
1014 Note that this property should be a regular expression in JS syntax, e.g /a/ for the regular expression
1017 By default, this property contains a regular expression with the pattern .* that matches any string.
1021 \qmlproperty Validator QtQuick2::TextInput::validator
1023 Allows you to set a validator on the TextInput. When a validator is set
1024 the TextInput will only accept input which leaves the text property in
1025 an acceptable or intermediate state. The accepted signal will only be sent
1026 if the text is in an acceptable state when enter is pressed.
1028 Currently supported validators are IntValidator, DoubleValidator and
1029 RegExpValidator. An example of using validators is shown below, which allows
1030 input of integers between 11 and 31 into the text input:
1035 validator: IntValidator{bottom: 11; top: 31;}
1040 \sa acceptableInput, inputMask
1043 QValidator* QQuickTextInput::validator() const
1045 Q_D(const QQuickTextInput);
1046 return d->m_validator;
1049 void QQuickTextInput::setValidator(QValidator* v)
1051 Q_D(QQuickTextInput);
1052 if (d->m_validator == v)
1057 if (isComponentComplete())
1060 emit validatorChanged();
1063 #endif // QT_NO_VALIDATOR
1065 void QQuickTextInputPrivate::checkIsValid()
1067 Q_Q(QQuickTextInput);
1069 ValidatorState state = hasAcceptableInput(m_text);
1070 m_validInput = state != InvalidInput;
1071 if (state != AcceptableInput) {
1072 if (m_acceptableInput) {
1073 m_acceptableInput = false;
1074 emit q->acceptableInputChanged();
1076 } else if (!m_acceptableInput) {
1077 m_acceptableInput = true;
1078 emit q->acceptableInputChanged();
1083 \qmlproperty string QtQuick2::TextInput::inputMask
1085 Allows you to set an input mask on the TextInput, restricting the allowable
1086 text inputs. See QLineEdit::inputMask for further details, as the exact
1087 same mask strings are used by TextInput.
1089 \sa acceptableInput, validator
1091 QString QQuickTextInput::inputMask() const
1093 Q_D(const QQuickTextInput);
1094 return d->inputMask();
1097 void QQuickTextInput::setInputMask(const QString &im)
1099 Q_D(QQuickTextInput);
1100 if (d->inputMask() == im)
1103 d->setInputMask(im);
1104 emit inputMaskChanged(d->inputMask());
1108 \qmlproperty bool QtQuick2::TextInput::acceptableInput
1110 This property is always true unless a validator or input mask has been set.
1111 If a validator or input mask has been set, this property will only be true
1112 if the current text is acceptable to the validator or input mask as a final
1113 string (not as an intermediate string).
1115 bool QQuickTextInput::hasAcceptableInput() const
1117 Q_D(const QQuickTextInput);
1118 return d->hasAcceptableInput(d->m_text) == QQuickTextInputPrivate::AcceptableInput;
1122 \qmlsignal QtQuick2::TextInput::onAccepted()
1124 This handler is called when the Return or Enter key is pressed.
1125 Note that if there is a \l validator or \l inputMask set on the text
1126 input, the handler will only be emitted if the input is in an acceptable
1130 Qt::InputMethodHints QQuickTextInputPrivate::effectiveInputMethodHints() const
1132 Qt::InputMethodHints hints = inputMethodHints;
1133 if (m_echoMode == QQuickTextInput::Password || m_echoMode == QQuickTextInput::NoEcho)
1134 hints |= Qt::ImhHiddenText;
1135 else if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit)
1136 hints &= ~Qt::ImhHiddenText;
1137 if (m_echoMode != QQuickTextInput::Normal)
1138 hints |= (Qt::ImhNoAutoUppercase | Qt::ImhNoPredictiveText | Qt::ImhSensitiveData);
1142 \qmlproperty enumeration QtQuick2::TextInput::echoMode
1144 Specifies how the text should be displayed in the TextInput.
1146 \li TextInput.Normal - Displays the text as it is. (Default)
1147 \li TextInput.Password - Displays asterisks instead of characters.
1148 \li TextInput.NoEcho - Displays nothing.
1149 \li TextInput.PasswordEchoOnEdit - Displays characters as they are entered
1150 while editing, otherwise displays asterisks.
1153 QQuickTextInput::EchoMode QQuickTextInput::echoMode() const
1155 Q_D(const QQuickTextInput);
1156 return QQuickTextInput::EchoMode(d->m_echoMode);
1159 void QQuickTextInput::setEchoMode(QQuickTextInput::EchoMode echo)
1161 Q_D(QQuickTextInput);
1162 if (echoMode() == echo)
1164 d->cancelPasswordEchoTimer();
1165 d->m_echoMode = echo;
1166 d->m_passwordEchoEditing = false;
1167 updateInputMethod(Qt::ImHints);
1168 d->updateDisplayText();
1169 updateCursorRectangle();
1171 emit echoModeChanged(echoMode());
1175 \qmlproperty enumeration QtQuick2::TextInput::inputMethodHints
1177 Provides hints to the input method about the expected content of the text input and how it
1180 The value is a bit-wise combination of flags, or Qt.ImhNone if no hints are set.
1182 Flags that alter behaviour are:
1185 \li Qt.ImhHiddenText - Characters should be hidden, as is typically used when entering passwords.
1186 This is automatically set when setting echoMode to \c TextInput.Password.
1187 \li Qt.ImhSensitiveData - Typed text should not be stored by the active input method
1188 in any persistent storage like predictive user dictionary.
1189 \li Qt.ImhNoAutoUppercase - The input method should not try to automatically switch to upper case
1190 when a sentence ends.
1191 \li Qt.ImhPreferNumbers - Numbers are preferred (but not required).
1192 \li Qt.ImhPreferUppercase - Upper case letters are preferred (but not required).
1193 \li Qt.ImhPreferLowercase - Lower case letters are preferred (but not required).
1194 \li Qt.ImhNoPredictiveText - Do not use predictive text (i.e. dictionary lookup) while typing.
1196 \li Qt.ImhDate - The text editor functions as a date field.
1197 \li Qt.ImhTime - The text editor functions as a time field.
1200 Flags that restrict input (exclusive flags) are:
1203 \li Qt.ImhDigitsOnly - Only digits are allowed.
1204 \li Qt.ImhFormattedNumbersOnly - Only number input is allowed. This includes decimal point and minus sign.
1205 \li Qt.ImhUppercaseOnly - Only upper case letter input is allowed.
1206 \li Qt.ImhLowercaseOnly - Only lower case letter input is allowed.
1207 \li Qt.ImhDialableCharactersOnly - Only characters suitable for phone dialing are allowed.
1208 \li Qt.ImhEmailCharactersOnly - Only characters suitable for email addresses are allowed.
1209 \li Qt.ImhUrlCharactersOnly - Only characters suitable for URLs are allowed.
1215 \li Qt.ImhExclusiveInputMask - This mask yields nonzero if any of the exclusive flags are used.
1219 Qt::InputMethodHints QQuickTextInput::inputMethodHints() const
1221 Q_D(const QQuickTextInput);
1222 return d->inputMethodHints;
1225 void QQuickTextInput::setInputMethodHints(Qt::InputMethodHints hints)
1227 Q_D(QQuickTextInput);
1229 if (hints == d->inputMethodHints)
1232 d->inputMethodHints = hints;
1233 updateInputMethod(Qt::ImHints);
1234 emit inputMethodHintsChanged();
1238 \qmlproperty Component QtQuick2::TextInput::cursorDelegate
1239 The delegate for the cursor in the TextInput.
1241 If you set a cursorDelegate for a TextInput, this delegate will be used for
1242 drawing the cursor instead of the standard cursor. An instance of the
1243 delegate will be created and managed by the TextInput when a cursor is
1244 needed, and the x property of delegate instance will be set so as
1245 to be one pixel before the top left of the current character.
1247 Note that the root item of the delegate component must be a QQuickItem or
1248 QQuickItem derived item.
1250 QQmlComponent* QQuickTextInput::cursorDelegate() const
1252 Q_D(const QQuickTextInput);
1253 return d->cursorComponent;
1256 void QQuickTextInput::setCursorDelegate(QQmlComponent* c)
1258 Q_D(QQuickTextInput);
1259 QQuickTextUtil::setCursorDelegate(d, c);
1262 void QQuickTextInput::createCursor()
1264 Q_D(QQuickTextInput);
1265 d->cursorPending = true;
1266 QQuickTextUtil::createCursor(d);
1270 \qmlmethod rect QtQuick2::TextInput::positionToRectangle(int pos)
1272 This function takes a character position and returns the rectangle that the
1273 cursor would occupy, if it was placed at that character position.
1275 This is similar to setting the cursorPosition, and then querying the cursor
1276 rectangle, but the cursorPosition is not changed.
1278 QRectF QQuickTextInput::positionToRectangle(int pos) const
1280 Q_D(const QQuickTextInput);
1281 if (d->m_echoMode == NoEcho)
1283 else if (pos > d->m_cursor)
1284 pos += d->preeditAreaText().length();
1285 QTextLine l = d->m_textLayout.lineForTextPosition(pos);
1287 ? QRectF(l.cursorToX(pos) - d->hscroll, l.y() - d->vscroll, 1, l.height())
1292 \qmlmethod int QtQuick2::TextInput::positionAt(real x, real y, CursorPosition position = CursorBetweenCharacters)
1294 This function returns the character position at
1295 x and y pixels from the top left of the textInput. Position 0 is before the
1296 first character, position 1 is after the first character but before the second,
1297 and so on until position text.length, which is after all characters.
1299 This means that for all x values before the first character this function returns 0,
1300 and for all x values after the last character this function returns text.length. If
1301 the y value is above the text the position will be that of the nearest character on
1302 the first line line and if it is below the text the position of the nearest character
1303 on the last line will be returned.
1305 The cursor position type specifies how the cursor position should be resolved.
1308 \li TextInput.CursorBetweenCharacters - Returns the position between characters that is nearest x.
1309 \li TextInput.CursorOnCharacter - Returns the position before the character that is nearest x.
1313 void QQuickTextInput::positionAt(QQmlV8Function *args) const
1315 Q_D(const QQuickTextInput);
1319 QTextLine::CursorPosition position = QTextLine::CursorBetweenCharacters;
1321 if (args->Length() < 1)
1325 v8::Local<v8::Value> arg = (*args)[i];
1326 x = arg->NumberValue();
1328 if (++i < args->Length()) {
1330 y = arg->NumberValue();
1333 if (++i < args->Length()) {
1335 position = QTextLine::CursorPosition(arg->Int32Value());
1338 int pos = d->positionAt(x, y, position);
1339 const int cursor = d->m_cursor;
1341 const int preeditLength = d->preeditAreaText().length();
1342 pos = pos > cursor + preeditLength
1343 ? pos - preeditLength
1346 args->returnValue(v8::Int32::New(pos));
1349 int QQuickTextInputPrivate::positionAt(qreal x, qreal y, QTextLine::CursorPosition position) const
1353 QTextLine line = m_textLayout.lineAt(0);
1354 for (int i = 1; i < m_textLayout.lineCount(); ++i) {
1355 QTextLine nextLine = m_textLayout.lineAt(i);
1357 if (y < (line.rect().bottom() + nextLine.y()) / 2)
1361 return line.isValid() ? line.xToCursor(x, position) : 0;
1364 void QQuickTextInput::keyPressEvent(QKeyEvent* ev)
1366 Q_D(QQuickTextInput);
1367 // Don't allow MacOSX up/down support, and we don't allow a completer.
1368 bool ignore = (ev->key() == Qt::Key_Up || ev->key() == Qt::Key_Down) && ev->modifiers() == Qt::NoModifier;
1369 if (!ignore && (d->lastSelectionStart == d->lastSelectionEnd) && (ev->key() == Qt::Key_Right || ev->key() == Qt::Key_Left)) {
1370 // Ignore when moving off the end unless there is a selection,
1371 // because then moving will do something (deselect).
1372 int cursorPosition = d->m_cursor;
1373 if (cursorPosition == 0)
1374 ignore = ev->key() == (d->layoutDirection() == Qt::LeftToRight ? Qt::Key_Left : Qt::Key_Right);
1375 if (!ignore && cursorPosition == text().length())
1376 ignore = ev->key() == (d->layoutDirection() == Qt::LeftToRight ? Qt::Key_Right : Qt::Key_Left);
1381 d->processKeyEvent(ev);
1383 if (!ev->isAccepted())
1384 QQuickImplicitSizeItem::keyPressEvent(ev);
1387 void QQuickTextInput::inputMethodEvent(QInputMethodEvent *ev)
1389 Q_D(QQuickTextInput);
1390 const bool wasComposing = d->hasImState;
1391 if (d->m_readOnly) {
1394 d->processInputMethodEvent(ev);
1396 if (!ev->isAccepted())
1397 QQuickImplicitSizeItem::inputMethodEvent(ev);
1399 if (wasComposing != d->hasImState)
1400 emit inputMethodComposingChanged();
1403 void QQuickTextInput::mouseDoubleClickEvent(QMouseEvent *event)
1405 Q_D(QQuickTextInput);
1407 if (d->selectByMouse && event->button() == Qt::LeftButton) {
1409 int cursor = d->positionAt(event->localPos());
1410 d->selectWordAtPos(cursor);
1411 event->setAccepted(true);
1412 if (!d->hasPendingTripleClick()) {
1413 d->tripleClickStartPoint = event->localPos();
1414 d->tripleClickTimer.start();
1417 if (d->sendMouseEventToInputContext(event))
1419 QQuickImplicitSizeItem::mouseDoubleClickEvent(event);
1423 void QQuickTextInput::mousePressEvent(QMouseEvent *event)
1425 Q_D(QQuickTextInput);
1427 d->pressPos = event->localPos();
1429 if (d->sendMouseEventToInputContext(event))
1432 if (d->selectByMouse) {
1433 setKeepMouseGrab(false);
1434 d->selectPressed = true;
1435 QPointF distanceVector = d->pressPos - d->tripleClickStartPoint;
1436 if (d->hasPendingTripleClick()
1437 && distanceVector.manhattanLength() < qApp->styleHints()->startDragDistance()) {
1438 event->setAccepted(true);
1444 bool mark = (event->modifiers() & Qt::ShiftModifier) && d->selectByMouse;
1445 int cursor = d->positionAt(event->localPos());
1446 d->moveCursor(cursor, mark);
1448 if (d->focusOnPress) {
1449 bool hadActiveFocus = hasActiveFocus();
1451 // re-open input panel on press if already focused
1452 if (hasActiveFocus() && hadActiveFocus && !d->m_readOnly)
1453 openSoftwareInputPanel();
1456 event->setAccepted(true);
1459 void QQuickTextInput::mouseMoveEvent(QMouseEvent *event)
1461 Q_D(QQuickTextInput);
1463 if (d->selectPressed) {
1464 if (qAbs(int(event->localPos().x() - d->pressPos.x())) > qApp->styleHints()->startDragDistance())
1465 setKeepMouseGrab(true);
1467 if (d->composeMode()) {
1469 int startPos = d->positionAt(d->pressPos);
1470 int currentPos = d->positionAt(event->localPos());
1471 if (startPos != currentPos)
1472 d->setSelection(startPos, currentPos - startPos);
1474 moveCursorSelection(d->positionAt(event->localPos()), d->mouseSelectionMode);
1476 event->setAccepted(true);
1478 QQuickImplicitSizeItem::mouseMoveEvent(event);
1482 void QQuickTextInput::mouseReleaseEvent(QMouseEvent *event)
1484 Q_D(QQuickTextInput);
1485 if (d->sendMouseEventToInputContext(event))
1487 if (d->selectPressed) {
1488 d->selectPressed = false;
1489 setKeepMouseGrab(false);
1491 #ifndef QT_NO_CLIPBOARD
1492 if (QGuiApplication::clipboard()->supportsSelection()) {
1493 if (event->button() == Qt::LeftButton) {
1494 d->copy(QClipboard::Selection);
1495 } else if (!d->m_readOnly && event->button() == Qt::MidButton) {
1497 d->insert(QGuiApplication::clipboard()->text(QClipboard::Selection));
1501 if (!event->isAccepted())
1502 QQuickImplicitSizeItem::mouseReleaseEvent(event);
1505 bool QQuickTextInputPrivate::sendMouseEventToInputContext(QMouseEvent *event)
1507 #if !defined QT_NO_IM
1508 if (composeMode()) {
1509 int tmp_cursor = positionAt(event->localPos());
1510 int mousePos = tmp_cursor - m_cursor;
1511 if (mousePos >= 0 && mousePos <= m_textLayout.preeditAreaText().length()) {
1512 if (event->type() == QEvent::MouseButtonRelease) {
1513 qApp->inputMethod()->invokeAction(QInputMethod::Click, mousePos);
1526 void QQuickTextInput::mouseUngrabEvent()
1528 Q_D(QQuickTextInput);
1529 d->selectPressed = false;
1530 setKeepMouseGrab(false);
1533 bool QQuickTextInput::event(QEvent* ev)
1535 #ifndef QT_NO_SHORTCUT
1536 Q_D(QQuickTextInput);
1537 if (ev->type() == QEvent::ShortcutOverride) {
1540 QKeyEvent* ke = static_cast<QKeyEvent*>(ev);
1541 if (ke == QKeySequence::Copy
1542 || ke == QKeySequence::Paste
1543 || ke == QKeySequence::Cut
1544 || ke == QKeySequence::Redo
1545 || ke == QKeySequence::Undo
1546 || ke == QKeySequence::MoveToNextWord
1547 || ke == QKeySequence::MoveToPreviousWord
1548 || ke == QKeySequence::MoveToStartOfDocument
1549 || ke == QKeySequence::MoveToEndOfDocument
1550 || ke == QKeySequence::SelectNextWord
1551 || ke == QKeySequence::SelectPreviousWord
1552 || ke == QKeySequence::SelectStartOfLine
1553 || ke == QKeySequence::SelectEndOfLine
1554 || ke == QKeySequence::SelectStartOfBlock
1555 || ke == QKeySequence::SelectEndOfBlock
1556 || ke == QKeySequence::SelectStartOfDocument
1557 || ke == QKeySequence::SelectAll
1558 || ke == QKeySequence::SelectEndOfDocument) {
1560 } else if (ke->modifiers() == Qt::NoModifier || ke->modifiers() == Qt::ShiftModifier
1561 || ke->modifiers() == Qt::KeypadModifier) {
1562 if (ke->key() < Qt::Key_Escape) {
1566 switch (ke->key()) {
1567 case Qt::Key_Delete:
1570 case Qt::Key_Backspace:
1582 return QQuickImplicitSizeItem::event(ev);
1585 void QQuickTextInput::geometryChanged(const QRectF &newGeometry,
1586 const QRectF &oldGeometry)
1588 Q_D(QQuickTextInput);
1590 if (newGeometry.width() != oldGeometry.width() && d->wrapMode != NoWrap)
1592 updateCursorRectangle();
1594 QQuickImplicitSizeItem::geometryChanged(newGeometry, oldGeometry);
1597 void QQuickTextInputPrivate::updateHorizontalScroll()
1599 Q_Q(QQuickTextInput);
1600 QTextLine currentLine = m_textLayout.lineForTextPosition(m_cursor + m_preeditCursor);
1601 const int preeditLength = m_textLayout.preeditAreaText().length();
1602 const qreal width = qMax<qreal>(0, q->width());
1604 qreal widthUsed = 0;
1605 if (currentLine.isValid()) {
1606 cix = currentLine.cursorToX(m_cursor + preeditLength);
1607 const qreal cursorWidth = cix >= 0 ? cix : width - cix;
1608 widthUsed = qMax(currentLine.naturalTextWidth(), cursorWidth);
1610 int previousScroll = hscroll;
1612 if (!autoScroll || widthUsed <= width || m_echoMode == QQuickTextInput::NoEcho) {
1615 Q_ASSERT(currentLine.isValid());
1616 if (cix - hscroll >= width) {
1617 // text doesn't fit, cursor is to the right of br (scroll right)
1618 hscroll = cix - width;
1619 } else if (cix - hscroll < 0 && hscroll < widthUsed) {
1620 // text doesn't fit, cursor is to the left of br (scroll left)
1622 } else if (widthUsed - hscroll < width) {
1623 // text doesn't fit, text document is to the left of br; align
1625 hscroll = widthUsed - width;
1626 } else if (width - hscroll > widthUsed) {
1627 // text doesn't fit, text document is to the right of br; align
1629 hscroll = width - widthUsed;
1631 if (preeditLength > 0) {
1632 // check to ensure long pre-edit text doesn't push the cursor
1634 cix = currentLine.cursorToX(m_cursor + qMax(0, m_preeditCursor - 1));
1639 if (previousScroll != hscroll)
1640 textLayoutDirty = true;
1643 void QQuickTextInputPrivate::updateVerticalScroll()
1645 Q_Q(QQuickTextInput);
1646 const int preeditLength = m_textLayout.preeditAreaText().length();
1647 const qreal height = qMax<qreal>(0, q->height());
1648 qreal heightUsed = contentSize.height();
1649 qreal previousScroll = vscroll;
1651 if (!autoScroll || heightUsed <= height) {
1652 // text fits in br; use vscroll for alignment
1653 switch (vAlign & ~(Qt::AlignAbsolute|Qt::AlignHorizontal_Mask)) {
1654 case Qt::AlignBottom:
1655 vscroll = heightUsed - height;
1657 case Qt::AlignVCenter:
1658 vscroll = (heightUsed - height) / 2;
1666 QTextLine currentLine = m_textLayout.lineForTextPosition(m_cursor + preeditLength);
1667 QRectF r = currentLine.isValid() ? currentLine.rect() : QRectF();
1668 qreal top = r.top();
1669 int bottom = r.bottom();
1671 if (bottom - vscroll >= height) {
1672 // text doesn't fit, cursor is to the below the br (scroll down)
1673 vscroll = bottom - height;
1674 } else if (top - vscroll < 0 && vscroll < heightUsed) {
1675 // text doesn't fit, cursor is above br (scroll up)
1677 } else if (heightUsed - vscroll < height) {
1678 // text doesn't fit, text document is to the left of br; align
1680 vscroll = heightUsed - height;
1682 if (preeditLength > 0) {
1683 // check to ensure long pre-edit text doesn't push the cursor
1685 currentLine = m_textLayout.lineForTextPosition(m_cursor + qMax(0, m_preeditCursor - 1));
1686 top = currentLine.isValid() ? currentLine.rect().top() : 0;
1691 if (previousScroll != vscroll)
1692 textLayoutDirty = true;
1695 void QQuickTextInput::triggerPreprocess()
1697 Q_D(QQuickTextInput);
1698 if (d->updateType == QQuickTextInputPrivate::UpdateNone)
1699 d->updateType = QQuickTextInputPrivate::UpdateOnlyPreprocess;
1703 QSGNode *QQuickTextInput::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data)
1706 Q_D(QQuickTextInput);
1708 if (d->updateType != QQuickTextInputPrivate::UpdatePaintNode && oldNode != 0) {
1709 // Update done in preprocess() in the nodes
1710 d->updateType = QQuickTextInputPrivate::UpdateNone;
1714 d->updateType = QQuickTextInputPrivate::UpdateNone;
1716 QQuickTextNode *node = static_cast<QQuickTextNode *>(oldNode);
1718 node = new QQuickTextNode(QQuickItemPrivate::get(this)->sceneGraphContext(), this);
1721 if (!d->textLayoutDirty && oldNode != 0) {
1722 QSGSimpleRectNode *cursorNode = node->cursorNode();
1723 if (cursorNode != 0 && !isReadOnly()) {
1724 cursorNode->setRect(cursorRectangle());
1726 if (!d->cursorVisible || (!d->m_blinkStatus && d->m_blinkPeriod > 0)) {
1733 node->deleteContent();
1734 node->setMatrix(QMatrix4x4());
1736 QPointF offset(0, 0);
1737 if (d->autoScroll && d->m_textLayout.lineCount() > 0) {
1738 QFontMetricsF fm(d->font);
1739 // the y offset is there to keep the baseline constant in case we have script changes in the text.
1740 offset = -QPoint(d->hscroll, d->vscroll + d->m_textLayout.lineAt(0).ascent() - fm.ascent());
1742 offset = -QPoint(d->hscroll, d->vscroll);
1745 if (!d->m_textLayout.text().isEmpty() || !d->m_textLayout.preeditAreaText().isEmpty()) {
1746 node->addTextLayout(offset, &d->m_textLayout, d->color,
1747 QQuickText::Normal, QColor(), QColor(),
1748 d->selectionColor, d->selectedTextColor,
1749 d->selectionStart(),
1750 d->selectionEnd() - 1); // selectionEnd() returns first char after
1754 if (!isReadOnly() && d->cursorItem == 0) {
1755 node->setCursor(cursorRectangle(), d->color);
1756 if (!d->cursorVisible || (!d->m_blinkStatus && d->m_blinkPeriod > 0)) {
1763 d->textLayoutDirty = false;
1769 QVariant QQuickTextInput::inputMethodQuery(Qt::InputMethodQuery property) const
1771 Q_D(const QQuickTextInput);
1774 return QVariant((bool)(flags() & ItemAcceptsInputMethod));
1776 return QVariant((int) d->effectiveInputMethodHints());
1777 case Qt::ImCursorRectangle:
1778 return cursorRectangle();
1781 case Qt::ImCursorPosition:
1782 return QVariant(d->m_cursor);
1783 case Qt::ImSurroundingText:
1784 if (d->m_echoMode == PasswordEchoOnEdit && !d->m_passwordEchoEditing) {
1785 return QVariant(displayText());
1787 return QVariant(d->realText());
1789 case Qt::ImCurrentSelection:
1790 return QVariant(selectedText());
1791 case Qt::ImMaximumTextLength:
1792 return QVariant(maxLength());
1793 case Qt::ImAnchorPosition:
1794 if (d->selectionStart() == d->selectionEnd())
1795 return QVariant(d->m_cursor);
1796 else if (d->selectionStart() == d->m_cursor)
1797 return QVariant(d->selectionEnd());
1799 return QVariant(d->selectionStart());
1806 \qmlmethod void QtQuick2::TextInput::deselect()
1808 Removes active text selection.
1810 void QQuickTextInput::deselect()
1812 Q_D(QQuickTextInput);
1817 \qmlmethod void QtQuick2::TextInput::selectAll()
1819 Causes all text to be selected.
1821 void QQuickTextInput::selectAll()
1823 Q_D(QQuickTextInput);
1824 d->setSelection(0, text().length());
1828 \qmlmethod void QtQuick2::TextInput::isRightToLeft(int start, int end)
1830 Returns true if the natural reading direction of the editor text
1831 found between positions \a start and \a end is right to left.
1833 bool QQuickTextInput::isRightToLeft(int start, int end)
1836 qmlInfo(this) << "isRightToLeft(start, end) called with the end property being smaller than the start.";
1839 return text().mid(start, end - start).isRightToLeft();
1843 #ifndef QT_NO_CLIPBOARD
1845 \qmlmethod QtQuick2::TextInput::cut()
1847 Moves the currently selected text to the system clipboard.
1849 void QQuickTextInput::cut()
1851 Q_D(QQuickTextInput);
1857 \qmlmethod QtQuick2::TextInput::copy()
1859 Copies the currently selected text to the system clipboard.
1861 void QQuickTextInput::copy()
1863 Q_D(QQuickTextInput);
1868 \qmlmethod QtQuick2::TextInput::paste()
1870 Replaces the currently selected text by the contents of the system clipboard.
1872 void QQuickTextInput::paste()
1874 Q_D(QQuickTextInput);
1878 #endif // QT_NO_CLIPBOARD
1881 Undoes the last operation if undo is \l {canUndo}{available}. Deselects any
1882 current selection, and updates the selection start to the current cursor
1886 void QQuickTextInput::undo()
1888 Q_D(QQuickTextInput);
1889 if (!d->m_readOnly) {
1891 d->finishChange(-1, true);
1896 Redoes the last operation if redo is \l {canRedo}{available}.
1899 void QQuickTextInput::redo()
1901 Q_D(QQuickTextInput);
1902 if (!d->m_readOnly) {
1909 \qmlmethod void QtQuick2::TextInput::insert(int position, string text)
1911 Inserts \a text into the TextInput at position.
1914 void QQuickTextInput::insert(int position, const QString &text)
1916 Q_D(QQuickTextInput);
1917 if (d->m_echoMode == QQuickTextInput::Password) {
1918 int delay = qGuiApp->styleHints()->passwordMaskDelay();
1920 d->m_passwordEchoTimer.start(delay, this);
1922 if (position < 0 || position > d->m_text.length())
1925 const int priorState = d->m_undoState;
1927 QString insertText = text;
1929 if (d->hasSelectedText()) {
1930 d->addCommand(QQuickTextInputPrivate::Command(
1931 QQuickTextInputPrivate::SetSelection, d->m_cursor, 0, d->m_selstart, d->m_selend));
1933 if (d->m_maskData) {
1934 insertText = d->maskString(position, insertText);
1935 for (int i = 0; i < insertText.length(); ++i) {
1936 d->addCommand(QQuickTextInputPrivate::Command(
1937 QQuickTextInputPrivate::DeleteSelection, position + i, d->m_text.at(position + i), -1, -1));
1938 d->addCommand(QQuickTextInputPrivate::Command(
1939 QQuickTextInputPrivate::Insert, position + i, insertText.at(i), -1, -1));
1941 d->m_text.replace(position, insertText.length(), insertText);
1942 if (!insertText.isEmpty())
1943 d->m_textDirty = true;
1944 if (position < d->m_selend && position + insertText.length() > d->m_selstart)
1945 d->m_selDirty = true;
1947 int remaining = d->m_maxLength - d->m_text.length();
1948 if (remaining != 0) {
1949 insertText = insertText.left(remaining);
1950 d->m_text.insert(position, insertText);
1951 for (int i = 0; i < insertText.length(); ++i)
1952 d->addCommand(QQuickTextInputPrivate::Command(
1953 QQuickTextInputPrivate::Insert, position + i, insertText.at(i), -1, -1));
1954 if (d->m_cursor >= position)
1955 d->m_cursor += insertText.length();
1956 if (d->m_selstart >= position)
1957 d->m_selstart += insertText.length();
1958 if (d->m_selend >= position)
1959 d->m_selend += insertText.length();
1960 d->m_textDirty = true;
1961 if (position >= d->m_selstart && position <= d->m_selend)
1962 d->m_selDirty = true;
1966 d->addCommand(QQuickTextInputPrivate::Command(
1967 QQuickTextInputPrivate::SetSelection, d->m_cursor, 0, d->m_selstart, d->m_selend));
1968 d->finishChange(priorState);
1970 if (d->lastSelectionStart != d->lastSelectionEnd) {
1971 if (d->m_selstart != d->lastSelectionStart) {
1972 d->lastSelectionStart = d->m_selstart;
1973 emit selectionStartChanged();
1975 if (d->m_selend != d->lastSelectionEnd) {
1976 d->lastSelectionEnd = d->m_selend;
1977 emit selectionEndChanged();
1983 \qmlmethod string QtQuick2::TextInput::getText(int start, int end)
1985 Removes the section of text that is between the \a start and \a end positions from the TextInput.
1988 void QQuickTextInput::remove(int start, int end)
1990 Q_D(QQuickTextInput);
1992 start = qBound(0, start, d->m_text.length());
1993 end = qBound(0, end, d->m_text.length());
1997 else if (start == end)
2000 if (start < d->m_selend && end > d->m_selstart)
2001 d->m_selDirty = true;
2003 const int priorState = d->m_undoState;
2005 d->addCommand(QQuickTextInputPrivate::Command(
2006 QQuickTextInputPrivate::SetSelection, d->m_cursor, 0, d->m_selstart, d->m_selend));
2008 if (start <= d->m_cursor && d->m_cursor < end) {
2009 // cursor is within the selection. Split up the commands
2010 // to be able to restore the correct cursor position
2011 for (int i = d->m_cursor; i >= start; --i) {
2012 d->addCommand(QQuickTextInputPrivate::Command(
2013 QQuickTextInputPrivate::DeleteSelection, i, d->m_text.at(i), -1, 1));
2015 for (int i = end - 1; i > d->m_cursor; --i) {
2016 d->addCommand(QQuickTextInputPrivate::Command(
2017 QQuickTextInputPrivate::DeleteSelection, i - d->m_cursor + start - 1, d->m_text.at(i), -1, -1));
2020 for (int i = end - 1; i >= start; --i) {
2021 d->addCommand(QQuickTextInputPrivate::Command(
2022 QQuickTextInputPrivate::RemoveSelection, i, d->m_text.at(i), -1, -1));
2025 if (d->m_maskData) {
2026 d->m_text.replace(start, end - start, d->clearString(start, end - start));
2027 for (int i = 0; i < end - start; ++i) {
2028 d->addCommand(QQuickTextInputPrivate::Command(
2029 QQuickTextInputPrivate::Insert, start + i, d->m_text.at(start + i), -1, -1));
2032 d->m_text.remove(start, end - start);
2034 if (d->m_cursor > start)
2035 d->m_cursor -= qMin(d->m_cursor, end) - start;
2036 if (d->m_selstart > start)
2037 d->m_selstart -= qMin(d->m_selstart, end) - start;
2038 if (d->m_selend > end)
2039 d->m_selend -= qMin(d->m_selend, end) - start;
2041 d->addCommand(QQuickTextInputPrivate::Command(
2042 QQuickTextInputPrivate::SetSelection, d->m_cursor, 0, d->m_selstart, d->m_selend));
2044 d->m_textDirty = true;
2045 d->finishChange(priorState);
2047 if (d->lastSelectionStart != d->lastSelectionEnd) {
2048 if (d->m_selstart != d->lastSelectionStart) {
2049 d->lastSelectionStart = d->m_selstart;
2050 emit selectionStartChanged();
2052 if (d->m_selend != d->lastSelectionEnd) {
2053 d->lastSelectionEnd = d->m_selend;
2054 emit selectionEndChanged();
2061 \qmlmethod void QtQuick2::TextInput::selectWord()
2063 Causes the word closest to the current cursor position to be selected.
2065 void QQuickTextInput::selectWord()
2067 Q_D(QQuickTextInput);
2068 d->selectWordAtPos(d->m_cursor);
2072 \qmlproperty bool QtQuick2::TextInput::smooth
2074 This property holds whether the text is smoothly scaled or transformed.
2076 Smooth filtering gives better visual quality, but is slower. If
2077 the item is displayed at its natural size, this property has no visual or
2080 \note Generally scaling artifacts are only visible if the item is stationary on
2081 the screen. A common pattern when animating an item is to disable smooth
2082 filtering at the beginning of the animation and reenable it at the conclusion.
2086 \qmlproperty string QtQuick2::TextInput::passwordCharacter
2088 This is the character displayed when echoMode is set to Password or
2089 PasswordEchoOnEdit. By default it is an asterisk.
2091 If this property is set to a string with more than one character,
2092 the first character is used. If the string is empty, the value
2093 is ignored and the property is not set.
2095 QString QQuickTextInput::passwordCharacter() const
2097 Q_D(const QQuickTextInput);
2098 return QString(d->m_passwordCharacter);
2101 void QQuickTextInput::setPasswordCharacter(const QString &str)
2103 Q_D(QQuickTextInput);
2104 if (str.length() < 1)
2106 d->m_passwordCharacter = str.constData()[0];
2107 if (d->m_echoMode == Password || d->m_echoMode == PasswordEchoOnEdit)
2108 d->updateDisplayText();
2109 emit passwordCharacterChanged();
2113 \qmlproperty string QtQuick2::TextInput::displayText
2115 This is the text displayed in the TextInput.
2117 If \l echoMode is set to TextInput::Normal, this holds the
2118 same value as the TextInput::text property. Otherwise,
2119 this property holds the text visible to the user, while
2120 the \l text property holds the actual entered text.
2122 QString QQuickTextInput::displayText() const
2124 Q_D(const QQuickTextInput);
2125 return d->m_textLayout.text();
2129 \qmlproperty bool QtQuick2::TextInput::selectByMouse
2133 If true, the user can use the mouse to select text in some
2134 platform-specific way. Note that for some platforms this may
2135 not be an appropriate interaction (eg. may conflict with how
2136 the text needs to behave inside a Flickable.
2138 bool QQuickTextInput::selectByMouse() const
2140 Q_D(const QQuickTextInput);
2141 return d->selectByMouse;
2144 void QQuickTextInput::setSelectByMouse(bool on)
2146 Q_D(QQuickTextInput);
2147 if (d->selectByMouse != on) {
2148 d->selectByMouse = on;
2149 emit selectByMouseChanged(on);
2154 \qmlproperty enum QtQuick2::TextInput::mouseSelectionMode
2156 Specifies how text should be selected using a mouse.
2159 \li TextInput.SelectCharacters - The selection is updated with individual characters. (Default)
2160 \li TextInput.SelectWords - The selection is updated with whole words.
2163 This property only applies when \l selectByMouse is true.
2166 QQuickTextInput::SelectionMode QQuickTextInput::mouseSelectionMode() const
2168 Q_D(const QQuickTextInput);
2169 return d->mouseSelectionMode;
2172 void QQuickTextInput::setMouseSelectionMode(SelectionMode mode)
2174 Q_D(QQuickTextInput);
2175 if (d->mouseSelectionMode != mode) {
2176 d->mouseSelectionMode = mode;
2177 emit mouseSelectionModeChanged(mode);
2182 \qmlproperty bool QtQuick2::TextInput::persistentSelection
2184 Whether the TextInput should keep its selection when it loses active focus to another
2185 item in the scene. By default this is set to false;
2188 bool QQuickTextInput::persistentSelection() const
2190 Q_D(const QQuickTextInput);
2191 return d->persistentSelection;
2194 void QQuickTextInput::setPersistentSelection(bool on)
2196 Q_D(QQuickTextInput);
2197 if (d->persistentSelection == on)
2199 d->persistentSelection = on;
2200 emit persistentSelectionChanged();
2203 #ifndef QT_NO_CLIPBOARD
2205 \qmlproperty bool QtQuick2::TextInput::canPaste
2207 Returns true if the TextInput is writable and the content of the clipboard is
2208 suitable for pasting into the TextInput.
2210 bool QQuickTextInput::canPaste() const
2212 Q_D(const QQuickTextInput);
2213 if (!d->canPasteValid) {
2214 if (const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData())
2215 const_cast<QQuickTextInputPrivate *>(d)->canPaste = !d->m_readOnly && mimeData->hasText();
2216 const_cast<QQuickTextInputPrivate *>(d)->canPasteValid = true;
2223 \qmlproperty bool QtQuick2::TextInput::canUndo
2225 Returns true if the TextInput is writable and there are previous operations
2229 bool QQuickTextInput::canUndo() const
2231 Q_D(const QQuickTextInput);
2236 \qmlproperty bool QtQuick2::TextInput::canRedo
2238 Returns true if the TextInput is writable and there are \l {undo}{undone}
2239 operations that can be redone.
2242 bool QQuickTextInput::canRedo() const
2244 Q_D(const QQuickTextInput);
2249 \qmlproperty real QtQuick2::TextInput::contentWidth
2251 Returns the width of the text, including the width past the width
2252 which is covered due to insufficient wrapping if \l wrapMode is set.
2255 qreal QQuickTextInput::contentWidth() const
2257 Q_D(const QQuickTextInput);
2258 return d->contentSize.width();
2262 \qmlproperty real QtQuick2::TextInput::contentHeight
2264 Returns the height of the text, including the height past the height
2265 that is covered if the text does not fit within the set height.
2268 qreal QQuickTextInput::contentHeight() const
2270 Q_D(const QQuickTextInput);
2271 return d->contentSize.height();
2274 void QQuickTextInput::moveCursorSelection(int position)
2276 Q_D(QQuickTextInput);
2277 d->moveCursor(position, true);
2281 \qmlmethod void QtQuick2::TextInput::moveCursorSelection(int position, SelectionMode mode = TextInput.SelectCharacters)
2283 Moves the cursor to \a position and updates the selection according to the optional \a mode
2284 parameter. (To only move the cursor, set the \l cursorPosition property.)
2286 When this method is called it additionally sets either the
2287 selectionStart or the selectionEnd (whichever was at the previous cursor position)
2288 to the specified position. This allows you to easily extend and contract the selected
2291 The selection mode specifies whether the selection is updated on a per character or a per word
2292 basis. If not specified the selection mode will default to TextInput.SelectCharacters.
2295 \li TextInput.SelectCharacters - Sets either the selectionStart or selectionEnd (whichever was at
2296 the previous cursor position) to the specified position.
2297 \li TextInput.SelectWords - Sets the selectionStart and selectionEnd to include all
2298 words between the specified position and the previous cursor position. Words partially in the
2302 For example, take this sequence of calls:
2306 moveCursorSelection(9, TextInput.SelectCharacters)
2307 moveCursorSelection(7, TextInput.SelectCharacters)
2310 This moves the cursor to position 5, extend the selection end from 5 to 9
2311 and then retract the selection end from 9 to 7, leaving the text from position 5 to 7
2312 selected (the 6th and 7th characters).
2314 The same sequence with TextInput.SelectWords will extend the selection start to a word boundary
2315 before or on position 5 and extend the selection end to a word boundary on or past position 9.
2317 void QQuickTextInput::moveCursorSelection(int pos, SelectionMode mode)
2319 Q_D(QQuickTextInput);
2321 if (mode == SelectCharacters) {
2322 d->moveCursor(pos, true);
2323 } else if (pos != d->m_cursor){
2324 const int cursor = d->m_cursor;
2326 if (!d->hasSelectedText())
2327 anchor = d->m_cursor;
2328 else if (d->selectionStart() == d->m_cursor)
2329 anchor = d->selectionEnd();
2331 anchor = d->selectionStart();
2333 if (anchor < pos || (anchor == pos && cursor < pos)) {
2334 const QString text = this->text();
2335 QTextBoundaryFinder finder(QTextBoundaryFinder::Word, text);
2336 finder.setPosition(anchor);
2338 const QTextBoundaryFinder::BoundaryReasons reasons = finder.boundaryReasons();
2339 if (anchor < text.length() && (!(reasons & QTextBoundaryFinder::StartWord)
2340 || ((reasons & QTextBoundaryFinder::EndWord) && anchor > cursor))) {
2341 finder.toPreviousBoundary();
2343 anchor = finder.position() != -1 ? finder.position() : 0;
2345 finder.setPosition(pos);
2346 if (pos > 0 && !finder.boundaryReasons())
2347 finder.toNextBoundary();
2348 const int cursor = finder.position() != -1 ? finder.position() : text.length();
2350 d->setSelection(anchor, cursor - anchor);
2351 } else if (anchor > pos || (anchor == pos && cursor > pos)) {
2352 const QString text = this->text();
2353 QTextBoundaryFinder finder(QTextBoundaryFinder::Word, text);
2354 finder.setPosition(anchor);
2356 const QTextBoundaryFinder::BoundaryReasons reasons = finder.boundaryReasons();
2357 if (anchor > 0 && (!(reasons & QTextBoundaryFinder::EndWord)
2358 || ((reasons & QTextBoundaryFinder::StartWord) && anchor < cursor))) {
2359 finder.toNextBoundary();
2362 anchor = finder.position() != -1 ? finder.position() : text.length();
2364 finder.setPosition(pos);
2365 if (pos < text.length() && !finder.boundaryReasons())
2366 finder.toPreviousBoundary();
2367 const int cursor = finder.position() != -1 ? finder.position() : 0;
2369 d->setSelection(anchor, cursor - anchor);
2375 \qmlmethod void QtQuick2::TextInput::openSoftwareInputPanel()
2377 Opens software input panels like virtual keyboards for typing, useful for
2378 customizing when you want the input keyboard to be shown and hidden in
2381 By default the opening of input panels follows the platform style. Input panels are
2382 always closed if no editor has active focus.
2384 You can disable the automatic behavior by setting the property \c activeFocusOnPress to false
2385 and use functions openSoftwareInputPanel() and closeSoftwareInputPanel() to implement
2386 the behavior you want.
2388 Only relevant on platforms, which provide virtual keyboards.
2394 text: "Hello world!"
2395 activeFocusOnPress: false
2397 anchors.fill: parent
2399 if (!textInput.activeFocus) {
2400 textInput.forceActiveFocus()
2401 textInput.openSoftwareInputPanel();
2403 textInput.focus = false;
2406 onPressAndHold: textInput.closeSoftwareInputPanel();
2411 void QQuickTextInput::openSoftwareInputPanel()
2414 qGuiApp->inputMethod()->show();
2418 \qmlmethod void QtQuick2::TextInput::closeSoftwareInputPanel()
2420 Closes a software input panel like a virtual keyboard shown on the screen, useful
2421 for customizing when you want the input keyboard to be shown and hidden in
2424 By default the opening of input panels follows the platform style. Input panels are
2425 always closed if no editor has active focus.
2427 You can disable the automatic behavior by setting the property \c activeFocusOnPress to false
2428 and use functions openSoftwareInputPanel() and closeSoftwareInputPanel() to implement
2429 the behavior you want.
2431 Only relevant on platforms, which provide virtual keyboards.
2437 text: "Hello world!"
2438 activeFocusOnPress: false
2440 anchors.fill: parent
2442 if (!textInput.activeFocus) {
2443 textInput.forceActiveFocus();
2444 textInput.openSoftwareInputPanel();
2446 textInput.focus = false;
2449 onPressAndHold: textInput.closeSoftwareInputPanel();
2454 void QQuickTextInput::closeSoftwareInputPanel()
2457 qGuiApp->inputMethod()->hide();
2460 void QQuickTextInput::focusInEvent(QFocusEvent *event)
2462 Q_D(const QQuickTextInput);
2463 if (d->focusOnPress && !d->m_readOnly)
2464 openSoftwareInputPanel();
2465 QQuickImplicitSizeItem::focusInEvent(event);
2468 void QQuickTextInput::itemChange(ItemChange change, const ItemChangeData &value)
2470 Q_D(QQuickTextInput);
2471 if (change == ItemActiveFocusHasChanged) {
2472 bool hasFocus = value.boolValue;
2473 setCursorVisible(hasFocus); // ### refactor: && d->canvas && d->canvas->hasFocus()
2474 if (!hasFocus && (d->m_passwordEchoEditing || d->m_passwordEchoTimer.isActive())) {
2475 d->updatePasswordEchoEditing(false);//QQuickTextInputPrivate sets it on key events, but doesn't deal with focus events
2479 if (!d->persistentSelection)
2481 disconnect(qApp->inputMethod(), SIGNAL(inputDirectionChanged(Qt::LayoutDirection)),
2482 this, SLOT(q_updateAlignment()));
2484 q_updateAlignment();
2485 connect(qApp->inputMethod(), SIGNAL(inputDirectionChanged(Qt::LayoutDirection)),
2486 this, SLOT(q_updateAlignment()));
2489 QQuickItem::itemChange(change, value);
2493 \qmlproperty bool QtQuick2::TextInput::inputMethodComposing
2496 This property holds whether the TextInput has partial text input from an
2499 While it is composing an input method may rely on mouse or key events from
2500 the TextInput to edit or commit the partial text. This property can be
2501 used to determine when to disable events handlers that may interfere with
2502 the correct operation of an input method.
2504 bool QQuickTextInput::isInputMethodComposing() const
2506 Q_D(const QQuickTextInput);
2507 return d->hasImState;
2510 void QQuickTextInputPrivate::init()
2512 Q_Q(QQuickTextInput);
2513 q->setSmooth(smooth);
2514 q->setAcceptedMouseButtons(Qt::LeftButton);
2515 q->setFlag(QQuickItem::ItemAcceptsInputMethod);
2516 q->setFlag(QQuickItem::ItemHasContents);
2517 #ifndef QT_NO_CLIPBOARD
2518 q->connect(QGuiApplication::clipboard(), SIGNAL(dataChanged()),
2519 q, SLOT(q_canPasteChanged()));
2520 #endif // QT_NO_CLIPBOARD
2522 lastSelectionStart = 0;
2523 lastSelectionEnd = 0;
2524 determineHorizontalAlignment();
2526 if (!qmlDisableDistanceField()) {
2527 QTextOption option = m_textLayout.textOption();
2528 option.setUseDesignMetrics(true);
2529 m_textLayout.setTextOption(option);
2533 void QQuickTextInput::updateCursorRectangle()
2535 Q_D(QQuickTextInput);
2536 if (!isComponentComplete())
2539 d->updateHorizontalScroll();
2540 d->updateVerticalScroll();
2541 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
2543 emit cursorRectangleChanged();
2544 if (d->cursorItem) {
2545 QRectF r = cursorRectangle();
2546 d->cursorItem->setPos(r.topLeft());
2547 d->cursorItem->setHeight(r.height());
2549 updateInputMethod(Qt::ImCursorRectangle);
2552 void QQuickTextInput::selectionChanged()
2554 Q_D(QQuickTextInput);
2555 d->textLayoutDirty = true; //TODO: Only update rect in selection
2556 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
2558 emit selectedTextChanged();
2560 if (d->lastSelectionStart != d->selectionStart()) {
2561 d->lastSelectionStart = d->selectionStart();
2562 if (d->lastSelectionStart == -1)
2563 d->lastSelectionStart = d->m_cursor;
2564 emit selectionStartChanged();
2566 if (d->lastSelectionEnd != d->selectionEnd()) {
2567 d->lastSelectionEnd = d->selectionEnd();
2568 if (d->lastSelectionEnd == -1)
2569 d->lastSelectionEnd = d->m_cursor;
2570 emit selectionEndChanged();
2574 void QQuickTextInputPrivate::showCursor()
2576 if (textNode != 0 && textNode->cursorNode() != 0)
2577 textNode->cursorNode()->setColor(color);
2580 void QQuickTextInputPrivate::hideCursor()
2582 if (textNode != 0 && textNode->cursorNode() != 0)
2583 textNode->cursorNode()->setColor(QColor(0, 0, 0, 0));
2586 QRectF QQuickTextInput::boundingRect() const
2588 Q_D(const QQuickTextInput);
2590 int cursorWidth = d->cursorItem ? 0 : 1;
2592 qreal hscroll = d->hscroll;
2593 if (!d->autoScroll || d->contentSize.width() < width()) {
2594 switch (effectiveHAlign()) {
2598 hscroll += d->contentSize.width() - width();
2601 hscroll += (d->contentSize.width() - width()) / 2;
2606 // Could include font max left/right bearings to either side of rectangle.
2607 QRectF r(-hscroll, -d->vscroll, d->contentSize.width(), d->contentSize.height());
2608 r.setRight(r.right() + cursorWidth);
2612 QRectF QQuickTextInput::clipRect() const
2614 Q_D(const QQuickTextInput);
2616 int cursorWidth = d->cursorItem ? d->cursorItem->width() : 1;
2618 // Could include font max left/right bearings to either side of rectangle.
2619 QRectF r = QQuickImplicitSizeItem::clipRect();
2620 r.setRight(r.right() + cursorWidth);
2624 void QQuickTextInput::q_canPasteChanged()
2626 Q_D(QQuickTextInput);
2627 bool old = d->canPaste;
2628 #ifndef QT_NO_CLIPBOARD
2629 if (const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData())
2630 d->canPaste = !d->m_readOnly && mimeData->hasText();
2632 d->canPaste = false;
2635 bool changed = d->canPaste != old || !d->canPasteValid;
2636 d->canPasteValid = true;
2638 emit canPasteChanged();
2642 void QQuickTextInput::q_updateAlignment()
2644 Q_D(QQuickTextInput);
2645 if (d->determineHorizontalAlignment()) {
2647 updateCursorRectangle();
2651 // ### these should come from QStyleHints
2652 const int textCursorWidth = 1;
2653 const bool fullWidthSelection = true;
2658 Updates the display text based of the current edit text
2659 If the text has changed will emit displayTextChanged()
2661 void QQuickTextInputPrivate::updateDisplayText(bool forceUpdate)
2663 QString orig = m_textLayout.text();
2665 if (m_echoMode == QQuickTextInput::NoEcho)
2666 str = QString::fromLatin1("");
2670 if (m_echoMode == QQuickTextInput::Password) {
2671 str.fill(m_passwordCharacter);
2672 if (m_passwordEchoTimer.isActive() && m_cursor > 0 && m_cursor <= m_text.length()) {
2673 int cursor = m_cursor - 1;
2674 QChar uc = m_text.at(cursor);
2676 if (cursor > 0 && uc.unicode() >= 0xdc00 && uc.unicode() < 0xe000) {
2677 // second half of a surrogate, check if we have the first half as well,
2678 // if yes restore both at once
2679 uc = m_text.at(cursor - 1);
2680 if (uc.unicode() >= 0xd800 && uc.unicode() < 0xdc00)
2681 str[cursor - 1] = uc;
2684 } else if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit && !m_passwordEchoEditing) {
2685 str.fill(m_passwordCharacter);
2688 // replace certain non-printable characters with spaces (to avoid
2689 // drawing boxes when using fonts that don't have glyphs for such
2691 QChar* uc = str.data();
2692 for (int i = 0; i < (int)str.length(); ++i) {
2693 if ((uc[i] < 0x20 && uc[i] != 0x09)
2694 || uc[i] == QChar::LineSeparator
2695 || uc[i] == QChar::ParagraphSeparator
2696 || uc[i] == QChar::ObjectReplacementCharacter)
2697 uc[i] = QChar(0x0020);
2700 if (str != orig || forceUpdate) {
2701 m_textLayout.setText(str);
2702 updateLayout(); // polish?
2703 emit q_func()->displayTextChanged();
2707 qreal QQuickTextInputPrivate::getImplicitWidth() const
2709 Q_Q(const QQuickTextInput);
2710 if (!requireImplicitWidth) {
2711 QQuickTextInputPrivate *d = const_cast<QQuickTextInputPrivate *>(this);
2712 d->requireImplicitWidth = true;
2714 if (q->isComponentComplete()) {
2715 // One time cost, only incurred if implicitWidth is first requested after
2716 // componentComplete.
2717 QTextLayout layout(m_text);
2719 QTextOption option = m_textLayout.textOption();
2720 option.setTextDirection(m_layoutDirection);
2721 option.setFlags(QTextOption::IncludeTrailingSpaces);
2722 option.setWrapMode(QTextOption::WrapMode(wrapMode));
2723 option.setAlignment(Qt::Alignment(q->effectiveHAlign()));
2724 layout.setTextOption(option);
2725 layout.setFont(font);
2726 layout.setPreeditArea(m_textLayout.preeditAreaPosition(), m_textLayout.preeditAreaText());
2727 layout.beginLayout();
2729 QTextLine line = layout.createLine();
2730 line.setLineWidth(INT_MAX);
2731 d->implicitWidth = qCeil(line.naturalTextWidth());
2736 return implicitWidth;
2739 void QQuickTextInputPrivate::updateLayout()
2741 Q_Q(QQuickTextInput);
2743 if (!q->isComponentComplete())
2747 QTextOption option = m_textLayout.textOption();
2748 option.setTextDirection(layoutDirection());
2749 option.setWrapMode(QTextOption::WrapMode(wrapMode));
2750 option.setAlignment(Qt::Alignment(q->effectiveHAlign()));
2751 m_textLayout.setTextOption(option);
2752 m_textLayout.setFont(font);
2754 m_textLayout.beginLayout();
2756 QTextLine line = m_textLayout.createLine();
2757 if (requireImplicitWidth) {
2758 line.setLineWidth(INT_MAX);
2759 const bool wasInLayout = inLayout;
2761 q->setImplicitWidth(qCeil(line.naturalTextWidth()));
2762 inLayout = wasInLayout;
2763 if (inLayout) // probably the result of a binding loop, but by letting it
2764 return; // get this far we'll get a warning to that effect.
2766 qreal lineWidth = q->widthValid() ? q->width() : INT_MAX;
2770 line.setLineWidth(lineWidth);
2771 line.setPosition(QPointF(0, height));
2773 height += line.height();
2774 width = qMax(width, line.naturalTextWidth());
2776 line = m_textLayout.createLine();
2777 } while (line.isValid());
2778 m_textLayout.endLayout();
2780 option.setWrapMode(QTextOption::NoWrap);
2781 m_textLayout.setTextOption(option);
2783 textLayoutDirty = true;
2785 const QSizeF previousSize = contentSize;
2786 contentSize = QSizeF(width, height);
2788 updateType = UpdatePaintNode;
2791 if (!requireImplicitWidth && !q->widthValid())
2792 q->setImplicitSize(width, height);
2794 q->setImplicitHeight(height);
2796 if (previousSize != contentSize)
2797 emit q->contentSizeChanged();
2800 #ifndef QT_NO_CLIPBOARD
2804 Copies the currently selected text into the clipboard using the given
2807 \note If the echo mode is set to a mode other than Normal then copy
2808 will not work. This is to prevent using copy as a method of bypassing
2809 password features of the line control.
2811 void QQuickTextInputPrivate::copy(QClipboard::Mode mode) const
2813 QString t = selectedText();
2814 if (!t.isEmpty() && m_echoMode == QQuickTextInput::Normal) {
2815 QGuiApplication::clipboard()->setText(t, mode);
2822 Inserts the text stored in the application clipboard into the line
2827 void QQuickTextInputPrivate::paste(QClipboard::Mode clipboardMode)
2829 QString clip = QGuiApplication::clipboard()->text(clipboardMode);
2830 if (!clip.isEmpty() || hasSelectedText()) {
2831 separate(); //make it a separate undo/redo command
2837 #endif // !QT_NO_CLIPBOARD
2842 void QQuickTextInputPrivate::commitPreedit()
2844 Q_Q(QQuickTextInput);
2849 qApp->inputMethod()->commit();
2854 QInputMethodEvent ev;
2855 QCoreApplication::sendEvent(q, &ev);
2858 void QQuickTextInputPrivate::cancelPreedit()
2860 Q_Q(QQuickTextInput);
2865 qApp->inputMethod()->reset();
2867 QInputMethodEvent ev;
2868 QCoreApplication::sendEvent(q, &ev);
2874 Handles the behavior for the backspace key or function.
2875 Removes the current selection if there is a selection, otherwise
2876 removes the character prior to the cursor position.
2880 void QQuickTextInputPrivate::backspace()
2882 int priorState = m_undoState;
2883 if (hasSelectedText()) {
2884 removeSelectedText();
2885 } else if (m_cursor) {
2888 m_cursor = prevMaskBlank(m_cursor);
2889 QChar uc = m_text.at(m_cursor);
2890 if (m_cursor > 0 && uc.unicode() >= 0xdc00 && uc.unicode() < 0xe000) {
2891 // second half of a surrogate, check if we have the first half as well,
2892 // if yes delete both at once
2893 uc = m_text.at(m_cursor - 1);
2894 if (uc.unicode() >= 0xd800 && uc.unicode() < 0xdc00) {
2895 internalDelete(true);
2899 internalDelete(true);
2901 finishChange(priorState);
2907 Handles the behavior for the delete key or function.
2908 Removes the current selection if there is a selection, otherwise
2909 removes the character after the cursor position.
2913 void QQuickTextInputPrivate::del()
2915 int priorState = m_undoState;
2916 if (hasSelectedText()) {
2917 removeSelectedText();
2919 int n = m_textLayout.nextCursorPosition(m_cursor) - m_cursor;
2923 finishChange(priorState);
2929 Inserts the given \a newText at the current cursor position.
2930 If there is any selected text it is removed prior to insertion of
2933 void QQuickTextInputPrivate::insert(const QString &newText)
2935 int priorState = m_undoState;
2936 removeSelectedText();
2937 internalInsert(newText);
2938 finishChange(priorState);
2944 Clears the line control text.
2946 void QQuickTextInputPrivate::clear()
2948 int priorState = m_undoState;
2950 m_selend = m_text.length();
2951 removeSelectedText();
2953 finishChange(priorState, /*update*/false, /*edited*/false);
2959 Sets \a length characters from the given \a start position as selected.
2960 The given \a start position must be within the current text for
2961 the line control. If \a length characters cannot be selected, then
2962 the selection will extend to the end of the current text.
2964 void QQuickTextInputPrivate::setSelection(int start, int length)
2966 Q_Q(QQuickTextInput);
2969 if (start < 0 || start > (int)m_text.length()){
2970 qWarning("QQuickTextInputPrivate::setSelection: Invalid start position");
2975 if (start == m_selstart && start + length == m_selend && m_cursor == m_selend)
2978 m_selend = qMin(start + length, (int)m_text.length());
2979 m_cursor = m_selend;
2980 } else if (length < 0){
2981 if (start == m_selend && start + length == m_selstart && m_cursor == m_selstart)
2983 m_selstart = qMax(start + length, 0);
2985 m_cursor = m_selstart;
2986 } else if (m_selstart != m_selend) {
2992 emitCursorPositionChanged();
2995 emit q->selectionChanged();
2996 emitCursorPositionChanged();
2997 q->updateInputMethod(Qt::ImCursorRectangle | Qt::ImAnchorPosition
2998 | Qt::ImCursorPosition | Qt::ImCurrentSelection);
3004 Sets the password echo editing to \a editing. If password echo editing
3005 is true, then the text of the password is displayed even if the echo
3006 mode is set to QLineEdit::PasswordEchoOnEdit. Password echoing editing
3007 does not affect other echo modes.
3009 void QQuickTextInputPrivate::updatePasswordEchoEditing(bool editing)
3011 cancelPasswordEchoTimer();
3012 m_passwordEchoEditing = editing;
3013 updateDisplayText();
3019 Fixes the current text so that it is valid given any set validators.
3021 Returns true if the text was changed. Otherwise returns false.
3023 bool QQuickTextInputPrivate::fixup() // this function assumes that validate currently returns != Acceptable
3025 #ifndef QT_NO_VALIDATOR
3027 QString textCopy = m_text;
3028 int cursorCopy = m_cursor;
3029 m_validator->fixup(textCopy);
3030 if (m_validator->validate(textCopy, cursorCopy) == QValidator::Acceptable) {
3031 if (textCopy != m_text || cursorCopy != m_cursor)
3032 internalSetText(textCopy, cursorCopy);
3043 Moves the cursor to the given position \a pos. If \a mark is true will
3044 adjust the currently selected text.
3046 void QQuickTextInputPrivate::moveCursor(int pos, bool mark)
3048 Q_Q(QQuickTextInput);
3051 if (pos != m_cursor) {
3054 pos = pos > m_cursor ? nextMaskBlank(pos) : prevMaskBlank(pos);
3058 if (m_selend > m_selstart && m_cursor == m_selstart)
3060 else if (m_selend > m_selstart && m_cursor == m_selend)
3061 anchor = m_selstart;
3064 m_selstart = qMin(anchor, pos);
3065 m_selend = qMax(anchor, pos);
3070 if (mark || m_selDirty) {
3072 emit q->selectionChanged();
3074 emitCursorPositionChanged();
3075 q->updateInputMethod();
3081 Applies the given input method event \a event to the text of the line
3084 void QQuickTextInputPrivate::processInputMethodEvent(QInputMethodEvent *event)
3086 Q_Q(QQuickTextInput);
3088 int priorState = -1;
3089 bool isGettingInput = !event->commitString().isEmpty()
3090 || event->preeditString() != preeditAreaText()
3091 || event->replacementLength() > 0;
3092 bool cursorPositionChanged = false;
3093 bool selectionChange = false;
3094 m_preeditDirty = event->preeditString() != preeditAreaText();
3096 if (isGettingInput) {
3097 // If any text is being input, remove selected text.
3098 priorState = m_undoState;
3099 if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit && !m_passwordEchoEditing) {
3100 updatePasswordEchoEditing(true);
3102 m_selend = m_text.length();
3104 removeSelectedText();
3107 int c = m_cursor; // cursor position after insertion of commit string
3108 if (event->replacementStart() <= 0)
3109 c += event->commitString().length() - qMin(-event->replacementStart(), event->replacementLength());
3111 m_cursor += event->replacementStart();
3115 // insert commit string
3116 if (event->replacementLength()) {
3117 m_selstart = m_cursor;
3118 m_selend = m_selstart + event->replacementLength();
3119 m_selend = qMin(m_selend, m_text.length());
3120 removeSelectedText();
3122 if (!event->commitString().isEmpty()) {
3123 internalInsert(event->commitString());
3124 cursorPositionChanged = true;
3127 m_cursor = qBound(0, c, m_text.length());
3129 for (int i = 0; i < event->attributes().size(); ++i) {
3130 const QInputMethodEvent::Attribute &a = event->attributes().at(i);
3131 if (a.type == QInputMethodEvent::Selection) {
3132 m_cursor = qBound(0, a.start + a.length, m_text.length());
3134 m_selstart = qMax(0, qMin(a.start, m_text.length()));
3135 m_selend = m_cursor;
3136 if (m_selend < m_selstart) {
3137 qSwap(m_selstart, m_selend);
3139 selectionChange = true;
3141 m_selstart = m_selend = 0;
3143 cursorPositionChanged = true;
3147 m_textLayout.setPreeditArea(m_cursor, event->preeditString());
3149 const int oldPreeditCursor = m_preeditCursor;
3150 m_preeditCursor = event->preeditString().length();
3151 hasImState = !event->preeditString().isEmpty();
3152 bool cursorVisible = true;
3153 QList<QTextLayout::FormatRange> formats;
3154 for (int i = 0; i < event->attributes().size(); ++i) {
3155 const QInputMethodEvent::Attribute &a = event->attributes().at(i);
3156 if (a.type == QInputMethodEvent::Cursor) {
3158 m_preeditCursor = a.start;
3159 cursorVisible = a.length != 0;
3160 } else if (a.type == QInputMethodEvent::TextFormat) {
3162 QTextCharFormat f = qvariant_cast<QTextFormat>(a.value).toCharFormat();
3164 QTextLayout::FormatRange o;
3165 o.start = a.start + m_cursor;
3166 o.length = a.length;
3172 m_textLayout.setAdditionalFormats(formats);
3174 updateDisplayText(/*force*/ true);
3175 if (cursorPositionChanged) {
3176 emitCursorPositionChanged();
3177 } else if (m_preeditCursor != oldPreeditCursor || isGettingInput) {
3178 q->updateCursorRectangle();
3182 finishChange(priorState);
3184 q->setCursorVisible(cursorVisible);
3186 if (selectionChange) {
3187 emit q->selectionChanged();
3188 q->updateInputMethod(Qt::ImCursorRectangle | Qt::ImAnchorPosition
3189 | Qt::ImCursorPosition | Qt::ImCurrentSelection);
3196 Sets the selection to cover the word at the given cursor position.
3197 The word boundaries are defined by the behavior of QTextLayout::SkipWords
3200 void QQuickTextInputPrivate::selectWordAtPos(int cursor)
3202 int next = cursor + 1;
3205 int c = m_textLayout.previousCursorPosition(next, QTextLayout::SkipWords);
3206 moveCursor(c, false);
3207 // ## text layout should support end of words.
3208 int end = m_textLayout.nextCursorPosition(c, QTextLayout::SkipWords);
3209 while (end > cursor && m_text[end-1].isSpace())
3211 moveCursor(end, true);
3217 Completes a change to the line control text. If the change is not valid
3218 will undo the line control state back to the given \a validateFromState.
3220 If \a edited is true and the change is valid, will emit textEdited() in
3221 addition to textChanged(). Otherwise only emits textChanged() on a valid
3224 The \a update value is currently unused.
3226 bool QQuickTextInputPrivate::finishChange(int validateFromState, bool update, bool /*edited*/)
3228 Q_Q(QQuickTextInput);
3231 bool inputMethodAttributesChanged = m_textDirty || m_selDirty;
3232 bool alignmentChanged = false;
3236 bool wasValidInput = m_validInput;
3237 bool wasAcceptable = m_acceptableInput;
3238 m_validInput = true;
3239 m_acceptableInput = true;
3240 #ifndef QT_NO_VALIDATOR
3242 QString textCopy = m_text;
3243 int cursorCopy = m_cursor;
3244 QValidator::State state = m_validator->validate(textCopy, cursorCopy);
3245 m_validInput = state != QValidator::Invalid;
3246 m_acceptableInput = state == QValidator::Acceptable;
3248 if (m_text != textCopy) {
3249 internalSetText(textCopy, cursorCopy);
3252 m_cursor = cursorCopy;
3256 if (validateFromState >= 0 && wasValidInput && !m_validInput) {
3257 if (m_transactions.count())
3259 internalUndo(validateFromState);
3260 m_history.resize(m_undoState);
3261 m_validInput = true;
3262 m_acceptableInput = wasAcceptable;
3263 m_textDirty = false;
3267 m_textDirty = false;
3268 m_preeditDirty = false;
3269 alignmentChanged = determineHorizontalAlignment();
3270 emit q->textChanged();
3273 updateDisplayText(alignmentChanged);
3275 if (m_acceptableInput != wasAcceptable)
3276 emit q->acceptableInputChanged();
3278 if (m_preeditDirty) {
3279 m_preeditDirty = false;
3280 if (determineHorizontalAlignment()) {
3281 alignmentChanged = true;
3288 emit q->selectionChanged();
3291 inputMethodAttributesChanged |= (m_cursor != m_lastCursorPos);
3292 if (inputMethodAttributesChanged)
3293 q->updateInputMethod();
3294 emitUndoRedoChanged();
3296 if (!emitCursorPositionChanged() && alignmentChanged)
3297 q->updateCursorRectangle();
3305 An internal function for setting the text of the line control.
3307 void QQuickTextInputPrivate::internalSetText(const QString &txt, int pos, bool edited)
3309 Q_Q(QQuickTextInput);
3311 QString oldText = m_text;
3313 m_text = maskString(0, txt, true);
3314 m_text += clearString(m_text.length(), m_maxLength - m_text.length());
3316 m_text = txt.isEmpty() ? txt : txt.left(m_maxLength);
3320 m_cursor = (pos < 0 || pos > m_text.length()) ? m_text.length() : pos;
3321 m_textDirty = (oldText != m_text);
3323 bool changed = finishChange(-1, true, edited);
3324 #ifdef QT_NO_ACCESSIBILITY
3328 QAccessibleTextUpdateEvent ev(q, 0, oldText, m_text);
3329 QAccessible::updateAccessibility(&ev);
3338 Adds the given \a command to the undo history
3339 of the line control. Does not apply the command.
3341 void QQuickTextInputPrivate::addCommand(const Command &cmd)
3343 if (m_separator && m_undoState && m_history[m_undoState - 1].type != Separator) {
3344 m_history.resize(m_undoState + 2);
3345 m_history[m_undoState++] = Command(Separator, m_cursor, 0, m_selstart, m_selend);
3347 m_history.resize(m_undoState + 1);
3349 m_separator = false;
3350 m_history[m_undoState++] = cmd;
3356 Inserts the given string \a s into the line
3359 Also adds the appropriate commands into the undo history.
3360 This function does not call finishChange(), and may leave the text
3361 in an invalid state.
3363 void QQuickTextInputPrivate::internalInsert(const QString &s)
3365 Q_Q(QQuickTextInput);
3366 if (m_echoMode == QQuickTextInput::Password) {
3367 int delay = qGuiApp->styleHints()->passwordMaskDelay();
3369 m_passwordEchoTimer.start(delay, q);
3371 if (hasSelectedText())
3372 addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
3374 QString ms = maskString(m_cursor, s);
3375 for (int i = 0; i < (int) ms.length(); ++i) {
3376 addCommand (Command(DeleteSelection, m_cursor + i, m_text.at(m_cursor + i), -1, -1));
3377 addCommand(Command(Insert, m_cursor + i, ms.at(i), -1, -1));
3379 m_text.replace(m_cursor, ms.length(), ms);
3380 m_cursor += ms.length();
3381 m_cursor = nextMaskBlank(m_cursor);
3384 int remaining = m_maxLength - m_text.length();
3385 if (remaining != 0) {
3386 m_text.insert(m_cursor, s.left(remaining));
3387 for (int i = 0; i < (int) s.left(remaining).length(); ++i)
3388 addCommand(Command(Insert, m_cursor++, s.at(i), -1, -1));
3397 deletes a single character from the current text. If \a wasBackspace,
3398 the character prior to the cursor is removed. Otherwise the character
3399 after the cursor is removed.
3401 Also adds the appropriate commands into the undo history.
3402 This function does not call finishChange(), and may leave the text
3403 in an invalid state.
3405 void QQuickTextInputPrivate::internalDelete(bool wasBackspace)
3407 if (m_cursor < (int) m_text.length()) {
3408 cancelPasswordEchoTimer();
3409 if (hasSelectedText())
3410 addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
3411 addCommand(Command((CommandType)((m_maskData ? 2 : 0) + (wasBackspace ? Remove : Delete)),
3412 m_cursor, m_text.at(m_cursor), -1, -1));
3414 m_text.replace(m_cursor, 1, clearString(m_cursor, 1));
3415 addCommand(Command(Insert, m_cursor, m_text.at(m_cursor), -1, -1));
3417 m_text.remove(m_cursor, 1);
3426 removes the currently selected text from the line control.
3428 Also adds the appropriate commands into the undo history.
3429 This function does not call finishChange(), and may leave the text
3430 in an invalid state.
3432 void QQuickTextInputPrivate::removeSelectedText()
3434 if (m_selstart < m_selend && m_selend <= (int) m_text.length()) {
3435 cancelPasswordEchoTimer();
3438 addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
3439 if (m_selstart <= m_cursor && m_cursor < m_selend) {
3440 // cursor is within the selection. Split up the commands
3441 // to be able to restore the correct cursor position
3442 for (i = m_cursor; i >= m_selstart; --i)
3443 addCommand (Command(DeleteSelection, i, m_text.at(i), -1, 1));
3444 for (i = m_selend - 1; i > m_cursor; --i)
3445 addCommand (Command(DeleteSelection, i - m_cursor + m_selstart - 1, m_text.at(i), -1, -1));
3447 for (i = m_selend-1; i >= m_selstart; --i)
3448 addCommand (Command(RemoveSelection, i, m_text.at(i), -1, -1));
3451 m_text.replace(m_selstart, m_selend - m_selstart, clearString(m_selstart, m_selend - m_selstart));
3452 for (int i = 0; i < m_selend - m_selstart; ++i)
3453 addCommand(Command(Insert, m_selstart + i, m_text.at(m_selstart + i), -1, -1));
3455 m_text.remove(m_selstart, m_selend - m_selstart);
3457 if (m_cursor > m_selstart)
3458 m_cursor -= qMin(m_cursor, m_selend) - m_selstart;
3467 Parses the input mask specified by \a maskFields to generate
3468 the mask data used to handle input masks.
3470 void QQuickTextInputPrivate::parseInputMask(const QString &maskFields)
3472 int delimiter = maskFields.indexOf(QLatin1Char(';'));
3473 if (maskFields.isEmpty() || delimiter == 0) {
3475 delete [] m_maskData;
3477 m_maxLength = 32767;
3478 internalSetText(QString());
3483 if (delimiter == -1) {
3484 m_blank = QLatin1Char(' ');
3485 m_inputMask = maskFields;
3487 m_inputMask = maskFields.left(delimiter);
3488 m_blank = (delimiter + 1 < maskFields.length()) ? maskFields[delimiter + 1] : QLatin1Char(' ');
3491 // calculate m_maxLength / m_maskData length
3494 for (int i=0; i<m_inputMask.length(); i++) {
3495 c = m_inputMask.at(i);
3496 if (i > 0 && m_inputMask.at(i-1) == QLatin1Char('\\')) {
3500 if (c != QLatin1Char('\\') && c != QLatin1Char('!') &&
3501 c != QLatin1Char('<') && c != QLatin1Char('>') &&
3502 c != QLatin1Char('{') && c != QLatin1Char('}') &&
3503 c != QLatin1Char('[') && c != QLatin1Char(']'))
3507 delete [] m_maskData;
3508 m_maskData = new MaskInputData[m_maxLength];
3510 MaskInputData::Casemode m = MaskInputData::NoCaseMode;
3513 bool escape = false;
3515 for (int i = 0; i < m_inputMask.length(); i++) {
3516 c = m_inputMask.at(i);
3519 m_maskData[index].maskChar = c;
3520 m_maskData[index].separator = s;
3521 m_maskData[index].caseMode = m;
3524 } else if (c == QLatin1Char('<')) {
3525 m = MaskInputData::Lower;
3526 } else if (c == QLatin1Char('>')) {
3527 m = MaskInputData::Upper;
3528 } else if (c == QLatin1Char('!')) {
3529 m = MaskInputData::NoCaseMode;
3530 } else if (c != QLatin1Char('{') && c != QLatin1Char('}') && c != QLatin1Char('[') && c != QLatin1Char(']')) {
3531 switch (c.unicode()) {
3557 m_maskData[index].maskChar = c;
3558 m_maskData[index].separator = s;
3559 m_maskData[index].caseMode = m;
3564 internalSetText(m_text);
3571 checks if the key is valid compared to the inputMask
3573 bool QQuickTextInputPrivate::isValidInput(QChar key, QChar mask) const
3575 switch (mask.unicode()) {
3581 if (key.isLetter() || key == m_blank)
3585 if (key.isLetterOrNumber())
3589 if (key.isLetterOrNumber() || key == m_blank)
3597 if (key.isPrint() || key == m_blank)
3605 if (key.isNumber() || key == m_blank)
3609 if (key.isNumber() && key.digitValue() > 0)
3613 if ((key.isNumber() && key.digitValue() > 0) || key == m_blank)
3617 if (key.isNumber() || key == QLatin1Char('+') || key == QLatin1Char('-') || key == m_blank)
3621 if (key == QLatin1Char('0') || key == QLatin1Char('1'))
3625 if (key == QLatin1Char('0') || key == QLatin1Char('1') || key == m_blank)
3629 if (key.isNumber() || (key >= QLatin1Char('a') && key <= QLatin1Char('f')) || (key >= QLatin1Char('A') && key <= QLatin1Char('F')))
3633 if (key.isNumber() || (key >= QLatin1Char('a') && key <= QLatin1Char('f')) || (key >= QLatin1Char('A') && key <= QLatin1Char('F')) || key == m_blank)
3645 Returns true if the given text \a str is valid for any
3646 validator or input mask set for the line control.
3648 Otherwise returns false
3650 QQuickTextInputPrivate::ValidatorState QQuickTextInputPrivate::hasAcceptableInput(const QString &str) const
3652 #ifndef QT_NO_VALIDATOR
3653 QString textCopy = str;
3654 int cursorCopy = m_cursor;
3656 QValidator::State state = m_validator->validate(textCopy, cursorCopy);
3657 if (state != QValidator::Acceptable)
3658 return ValidatorState(state);
3663 return AcceptableInput;
3665 if (str.length() != m_maxLength)
3666 return InvalidInput;
3668 for (int i=0; i < m_maxLength; ++i) {
3669 if (m_maskData[i].separator) {
3670 if (str.at(i) != m_maskData[i].maskChar)
3671 return InvalidInput;
3673 if (!isValidInput(str.at(i), m_maskData[i].maskChar))
3674 return InvalidInput;
3677 return AcceptableInput;
3683 Applies the inputMask on \a str starting from position \a pos in the mask. \a clear
3684 specifies from where characters should be gotten when a separator is met in \a str - true means
3685 that blanks will be used, false that previous input is used.
3686 Calling this when no inputMask is set is undefined.
3688 QString QQuickTextInputPrivate::maskString(uint pos, const QString &str, bool clear) const
3690 if (pos >= (uint)m_maxLength)
3691 return QString::fromLatin1("");
3694 fill = clear ? clearString(0, m_maxLength) : m_text;
3697 QString s = QString::fromLatin1("");
3699 while (i < m_maxLength) {
3700 if (strIndex < str.length()) {
3701 if (m_maskData[i].separator) {
3702 s += m_maskData[i].maskChar;
3703 if (str[(int)strIndex] == m_maskData[i].maskChar)
3707 if (isValidInput(str[(int)strIndex], m_maskData[i].maskChar)) {
3708 switch (m_maskData[i].caseMode) {
3709 case MaskInputData::Upper:
3710 s += str[(int)strIndex].toUpper();
3712 case MaskInputData::Lower:
3713 s += str[(int)strIndex].toLower();
3716 s += str[(int)strIndex];
3720 // search for separator first
3721 int n = findInMask(i, true, true, str[(int)strIndex]);
3723 if (str.length() != 1 || i == 0 || (i > 0 && (!m_maskData[i-1].separator || m_maskData[i-1].maskChar != str[(int)strIndex]))) {
3724 s += fill.mid(i, n-i+1);
3725 i = n + 1; // update i to find + 1
3728 // search for valid m_blank if not
3729 n = findInMask(i, true, false, str[(int)strIndex]);
3731 s += fill.mid(i, n-i);
3732 switch (m_maskData[n].caseMode) {
3733 case MaskInputData::Upper:
3734 s += str[(int)strIndex].toUpper();
3736 case MaskInputData::Lower:
3737 s += str[(int)strIndex].toLower();
3740 s += str[(int)strIndex];
3742 i = n + 1; // updates i to find + 1
3760 Returns a "cleared" string with only separators and blank chars.
3761 Calling this when no inputMask is set is undefined.
3763 QString QQuickTextInputPrivate::clearString(uint pos, uint len) const
3765 if (pos >= (uint)m_maxLength)
3769 int end = qMin((uint)m_maxLength, pos + len);
3770 for (int i = pos; i < end; ++i)
3771 if (m_maskData[i].separator)
3772 s += m_maskData[i].maskChar;
3782 Strips blank parts of the input in a QQuickTextInputPrivate when an inputMask is set,
3783 separators are still included. Typically "127.0__.0__.1__" becomes "127.0.0.1".
3785 QString QQuickTextInputPrivate::stripString(const QString &str) const
3791 int end = qMin(m_maxLength, (int)str.length());
3792 for (int i = 0; i < end; ++i) {
3793 if (m_maskData[i].separator)
3794 s += m_maskData[i].maskChar;
3795 else if (str[i] != m_blank)
3804 searches forward/backward in m_maskData for either a separator or a m_blank
3806 int QQuickTextInputPrivate::findInMask(int pos, bool forward, bool findSeparator, QChar searchChar) const
3808 if (pos >= m_maxLength || pos < 0)
3811 int end = forward ? m_maxLength : -1;
3812 int step = forward ? 1 : -1;
3816 if (findSeparator) {
3817 if (m_maskData[i].separator && m_maskData[i].maskChar == searchChar)
3820 if (!m_maskData[i].separator) {
3821 if (searchChar.isNull())
3823 else if (isValidInput(searchChar, m_maskData[i].maskChar))
3832 void QQuickTextInputPrivate::internalUndo(int until)
3834 if (!isUndoAvailable())
3836 cancelPasswordEchoTimer();
3838 while (m_undoState && m_undoState > until) {
3839 Command& cmd = m_history[--m_undoState];
3842 m_text.remove(cmd.pos, 1);
3846 m_selstart = cmd.selStart;
3847 m_selend = cmd.selEnd;
3851 case RemoveSelection:
3852 m_text.insert(cmd.pos, cmd.uc);
3853 m_cursor = cmd.pos + 1;
3856 case DeleteSelection:
3857 m_text.insert(cmd.pos, cmd.uc);
3863 if (until < 0 && m_undoState) {
3864 Command& next = m_history[m_undoState-1];
3865 if (next.type != cmd.type && next.type < RemoveSelection
3866 && (cmd.type < RemoveSelection || next.type == Separator))
3873 void QQuickTextInputPrivate::internalRedo()
3875 if (!isRedoAvailable())
3878 while (m_undoState < (int)m_history.size()) {
3879 Command& cmd = m_history[m_undoState++];
3882 m_text.insert(cmd.pos, cmd.uc);
3883 m_cursor = cmd.pos + 1;
3886 m_selstart = cmd.selStart;
3887 m_selend = cmd.selEnd;
3892 case RemoveSelection:
3893 case DeleteSelection:
3894 m_text.remove(cmd.pos, 1);
3895 m_selstart = cmd.selStart;
3896 m_selend = cmd.selEnd;
3900 m_selstart = cmd.selStart;
3901 m_selend = cmd.selEnd;
3905 if (m_undoState < (int)m_history.size()) {
3906 Command& next = m_history[m_undoState];
3907 if (next.type != cmd.type && cmd.type < RemoveSelection && next.type != Separator
3908 && (next.type < RemoveSelection || cmd.type == Separator))
3915 void QQuickTextInputPrivate::emitUndoRedoChanged()
3917 Q_Q(QQuickTextInput);
3918 const bool previousUndo = canUndo;
3919 const bool previousRedo = canRedo;
3921 canUndo = isUndoAvailable();
3922 canRedo = isRedoAvailable();
3924 if (previousUndo != canUndo)
3925 emit q->canUndoChanged();
3926 if (previousRedo != canRedo)
3927 emit q->canRedoChanged();
3933 If the current cursor position differs from the last emitted cursor
3934 position, emits cursorPositionChanged().
3936 bool QQuickTextInputPrivate::emitCursorPositionChanged()
3938 Q_Q(QQuickTextInput);
3939 if (m_cursor != m_lastCursorPos) {
3940 m_lastCursorPos = m_cursor;
3942 q->updateCursorRectangle();
3943 emit q->cursorPositionChanged();
3945 if (!hasSelectedText()) {
3946 if (lastSelectionStart != m_cursor) {
3947 lastSelectionStart = m_cursor;
3948 emit q->selectionStartChanged();
3950 if (lastSelectionEnd != m_cursor) {
3951 lastSelectionEnd = m_cursor;
3952 emit q->selectionEndChanged();
3956 #ifndef QT_NO_ACCESSIBILITY
3957 QAccessibleTextCursorEvent ev(q, m_cursor);
3958 QAccessible::updateAccessibility(&ev);
3967 void QQuickTextInputPrivate::setCursorBlinkPeriod(int msec)
3969 Q_Q(QQuickTextInput);
3970 if (msec == m_blinkPeriod)
3973 q->killTimer(m_blinkTimer);
3976 m_blinkTimer = q->startTimer(msec / 2);
3980 if (m_blinkStatus == 1) {
3981 updateType = UpdatePaintNode;
3985 m_blinkPeriod = msec;
3988 void QQuickTextInput::timerEvent(QTimerEvent *event)
3990 Q_D(QQuickTextInput);
3991 if (event->timerId() == d->m_blinkTimer) {
3992 d->m_blinkStatus = !d->m_blinkStatus;
3993 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
3995 } else if (event->timerId() == d->m_passwordEchoTimer.timerId()) {
3996 d->m_passwordEchoTimer.stop();
3997 d->updateDisplayText();
4001 void QQuickTextInputPrivate::processKeyEvent(QKeyEvent* event)
4003 Q_Q(QQuickTextInput);
4004 bool inlineCompletionAccepted = false;
4006 if (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return) {
4007 if (hasAcceptableInput(m_text) || fixup()) {
4010 if (inlineCompletionAccepted)
4017 if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit
4018 && !m_passwordEchoEditing
4020 && !event->text().isEmpty()
4021 && !(event->modifiers() & Qt::ControlModifier)) {
4022 // Clear the edit and reset to normal echo mode while editing; the
4023 // echo mode switches back when the edit loses focus
4024 // ### resets current content. dubious code; you can
4025 // navigate with keys up, down, back, and select(?), but if you press
4026 // "left" or "right" it clears?
4027 updatePasswordEchoEditing(true);
4031 bool unknown = false;
4032 bool visual = cursorMoveStyle() == Qt::VisualMoveStyle;
4036 #ifndef QT_NO_SHORTCUT
4037 else if (event == QKeySequence::Undo) {
4040 else if (event == QKeySequence::Redo) {
4043 else if (event == QKeySequence::SelectAll) {
4046 #ifndef QT_NO_CLIPBOARD
4047 else if (event == QKeySequence::Copy) {
4050 else if (event == QKeySequence::Paste) {
4052 QClipboard::Mode mode = QClipboard::Clipboard;
4056 else if (event == QKeySequence::Cut) {
4062 else if (event == QKeySequence::DeleteEndOfLine) {
4064 setSelection(m_cursor, end());
4069 #endif //QT_NO_CLIPBOARD
4070 else if (event == QKeySequence::MoveToStartOfLine || event == QKeySequence::MoveToStartOfBlock) {
4073 else if (event == QKeySequence::MoveToEndOfLine || event == QKeySequence::MoveToEndOfBlock) {
4076 else if (event == QKeySequence::SelectStartOfLine || event == QKeySequence::SelectStartOfBlock) {
4079 else if (event == QKeySequence::SelectEndOfLine || event == QKeySequence::SelectEndOfBlock) {
4082 else if (event == QKeySequence::MoveToNextChar) {
4083 if (hasSelectedText()) {
4084 moveCursor(selectionEnd(), false);
4086 cursorForward(0, visual ? 1 : (layoutDirection() == Qt::LeftToRight ? 1 : -1));
4089 else if (event == QKeySequence::SelectNextChar) {
4090 cursorForward(1, visual ? 1 : (layoutDirection() == Qt::LeftToRight ? 1 : -1));
4092 else if (event == QKeySequence::MoveToPreviousChar) {
4093 if (hasSelectedText()) {
4094 moveCursor(selectionStart(), false);
4096 cursorForward(0, visual ? -1 : (layoutDirection() == Qt::LeftToRight ? -1 : 1));
4099 else if (event == QKeySequence::SelectPreviousChar) {
4100 cursorForward(1, visual ? -1 : (layoutDirection() == Qt::LeftToRight ? -1 : 1));
4102 else if (event == QKeySequence::MoveToNextWord) {
4103 if (m_echoMode == QQuickTextInput::Normal)
4104 layoutDirection() == Qt::LeftToRight ? cursorWordForward(0) : cursorWordBackward(0);
4106 layoutDirection() == Qt::LeftToRight ? end(0) : home(0);
4108 else if (event == QKeySequence::MoveToPreviousWord) {
4109 if (m_echoMode == QQuickTextInput::Normal)
4110 layoutDirection() == Qt::LeftToRight ? cursorWordBackward(0) : cursorWordForward(0);
4111 else if (!m_readOnly) {
4112 layoutDirection() == Qt::LeftToRight ? home(0) : end(0);
4115 else if (event == QKeySequence::SelectNextWord) {
4116 if (m_echoMode == QQuickTextInput::Normal)
4117 layoutDirection() == Qt::LeftToRight ? cursorWordForward(1) : cursorWordBackward(1);
4119 layoutDirection() == Qt::LeftToRight ? end(1) : home(1);
4121 else if (event == QKeySequence::SelectPreviousWord) {
4122 if (m_echoMode == QQuickTextInput::Normal)
4123 layoutDirection() == Qt::LeftToRight ? cursorWordBackward(1) : cursorWordForward(1);
4125 layoutDirection() == Qt::LeftToRight ? home(1) : end(1);
4127 else if (event == QKeySequence::Delete) {
4131 else if (event == QKeySequence::DeleteEndOfWord) {
4133 cursorWordForward(true);
4137 else if (event == QKeySequence::DeleteStartOfWord) {
4139 cursorWordBackward(true);
4143 #endif // QT_NO_SHORTCUT
4145 bool handled = false;
4146 if (event->modifiers() & Qt::ControlModifier) {
4147 switch (event->key()) {
4148 case Qt::Key_Backspace:
4150 cursorWordBackward(true);
4158 } else { // ### check for *no* modifier
4159 switch (event->key()) {
4160 case Qt::Key_Backspace:
4172 if (event->key() == Qt::Key_Direction_L || event->key() == Qt::Key_Direction_R) {
4173 setLayoutDirection((event->key() == Qt::Key_Direction_L) ? Qt::LeftToRight : Qt::RightToLeft);
4177 if (unknown && !m_readOnly) {
4178 QString t = event->text();
4179 if (!t.isEmpty() && t.at(0).isPrint()) {