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"
46 #include <private/qqmlglobal_p.h>
48 #include <QtQml/qqmlinfo.h>
49 #include <QtGui/qevent.h>
50 #include <QTextBoundaryFinder>
51 #include "qquicktextnode_p.h"
52 #include <QtQuick/qsgsimplerectnode.h>
54 #include <QtGui/qstylehints.h>
55 #include <QtGui/qinputmethod.h>
57 #ifndef QT_NO_ACCESSIBILITY
58 #include "qaccessible.h"
63 DEFINE_BOOL_CONFIG_OPTION(qmlDisableDistanceField, QML_DISABLE_DISTANCEFIELD)
65 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
66 static const int qt_passwordEchoDelay = QT_GUI_PASSWORD_ECHO_DELAY;
70 \qmlclass TextInput QQuickTextInput
71 \inqmlmodule QtQuick 2
72 \ingroup qml-basic-visual-elements
73 \brief The TextInput item displays an editable line of text.
76 The TextInput element displays a single line of editable plain text.
78 TextInput is used to accept a line of text input. Input constraints
79 can be placed on a TextInput item (for example, through a \l validator or \l inputMask),
80 and setting \l echoMode to an appropriate value enables TextInput to be used for
81 a password input field.
83 On Mac OS X, the Up/Down key bindings for Home/End are explicitly disabled.
84 If you want such bindings (on any platform), you will need to construct them in QML.
86 \sa TextEdit, Text, {declarative/text/textselection}{Text Selection example}
88 QQuickTextInput::QQuickTextInput(QQuickItem* parent)
89 : QQuickImplicitSizeItem(*(new QQuickTextInputPrivate), parent)
95 QQuickTextInput::~QQuickTextInput()
99 void QQuickTextInput::componentComplete()
101 Q_D(QQuickTextInput);
103 QQuickImplicitSizeItem::componentComplete();
107 updateCursorRectangle();
108 if (d->cursorComponent && d->cursorComponent->isReady())
113 \qmlproperty string QtQuick2::TextInput::text
115 The text in the TextInput.
117 QString QQuickTextInput::text() const
119 Q_D(const QQuickTextInput);
121 QString content = d->m_text;
122 if (!d->m_tentativeCommit.isEmpty())
123 content.insert(d->m_cursor, d->m_tentativeCommit);
124 QString res = d->m_maskData ? d->stripString(content) : content;
125 return (res.isNull() ? QString::fromLatin1("") : res);
128 void QQuickTextInput::setText(const QString &s)
130 Q_D(QQuickTextInput);
133 if (d->composeMode())
134 qApp->inputMethod()->reset();
135 d->m_tentativeCommit.clear();
136 d->internalSetText(s, -1, false);
140 \qmlproperty int QtQuick2::TextInput::length
142 Returns the total number of characters in the TextInput item.
144 If the TextInput has an inputMask the length will include mask characters and may differ
145 from the length of the string returned by the \l text property.
147 This property can be faster than querying the length the \l text property as it doesn't
148 require any copying or conversion of the TextInput's internal string data.
151 int QQuickTextInput::length() const
153 Q_D(const QQuickTextInput);
154 return d->m_text.length();
158 \qmlmethod string QtQuick2::TextInput::getText(int start, int end)
160 Returns the section of text that is between the \a start and \a end positions.
162 If the TextInput has an inputMask the length will include mask characters.
165 QString QQuickTextInput::getText(int start, int end) const
167 Q_D(const QQuickTextInput);
172 return d->m_text.mid(start, end - start);
175 QString QQuickTextInputPrivate::realText() const
177 QString res = m_maskData ? stripString(m_text) : m_text;
178 return (res.isNull() ? QString::fromLatin1("") : res);
182 \qmlproperty string QtQuick2::TextInput::font.family
184 Sets the family name of the font.
186 The family name is case insensitive and may optionally include a foundry name, e.g. "Helvetica [Cronyx]".
187 If the family is available from more than one foundry and the foundry isn't specified, an arbitrary foundry is chosen.
188 If the family isn't available a family will be set using the font matching algorithm.
192 \qmlproperty bool QtQuick2::TextInput::font.bold
194 Sets whether the font weight is bold.
198 \qmlproperty enumeration QtQuick2::TextInput::font.weight
200 Sets the font's weight.
202 The weight can be one of:
205 \li Font.Normal - the default
212 TextInput { text: "Hello"; font.weight: Font.DemiBold }
217 \qmlproperty bool QtQuick2::TextInput::font.italic
219 Sets whether the font has an italic style.
223 \qmlproperty bool QtQuick2::TextInput::font.underline
225 Sets whether the text is underlined.
229 \qmlproperty bool QtQuick2::TextInput::font.strikeout
231 Sets whether the font has a strikeout style.
235 \qmlproperty real QtQuick2::TextInput::font.pointSize
237 Sets the font size in points. The point size must be greater than zero.
241 \qmlproperty int QtQuick2::TextInput::font.pixelSize
243 Sets the font size in pixels.
245 Using this function makes the font device dependent.
246 Use \c pointSize to set the size of the font in a device independent manner.
250 \qmlproperty real QtQuick2::TextInput::font.letterSpacing
252 Sets the letter spacing for the font.
254 Letter spacing changes the default spacing between individual letters in the font.
255 A positive value increases the letter spacing by the corresponding pixels; a negative value decreases the spacing.
259 \qmlproperty real QtQuick2::TextInput::font.wordSpacing
261 Sets the word spacing for the font.
263 Word spacing changes the default spacing between individual words.
264 A positive value increases the word spacing by a corresponding amount of pixels,
265 while a negative value decreases the inter-word spacing accordingly.
269 \qmlproperty enumeration QtQuick2::TextInput::font.capitalization
271 Sets the capitalization for the text.
274 \li Font.MixedCase - This is the normal text rendering option where no capitalization change is applied.
275 \li Font.AllUppercase - This alters the text to be rendered in all uppercase type.
276 \li Font.AllLowercase - This alters the text to be rendered in all lowercase type.
277 \li Font.SmallCaps - This alters the text to be rendered in small-caps type.
278 \li Font.Capitalize - This alters the text to be rendered with the first character of each word as an uppercase character.
282 TextInput { text: "Hello"; font.capitalization: Font.AllLowercase }
286 QFont QQuickTextInput::font() const
288 Q_D(const QQuickTextInput);
289 return d->sourceFont;
292 void QQuickTextInput::setFont(const QFont &font)
294 Q_D(QQuickTextInput);
295 if (d->sourceFont == font)
298 d->sourceFont = font;
299 QFont oldFont = d->font;
301 if (d->font.pointSizeF() != -1) {
303 qreal size = qRound(d->font.pointSizeF()*2.0);
304 d->font.setPointSizeF(size/2.0);
306 if (oldFont != d->font) {
308 updateCursorRectangle();
309 updateInputMethod(Qt::ImCursorRectangle | Qt::ImFont);
311 emit fontChanged(d->sourceFont);
315 \qmlproperty color QtQuick2::TextInput::color
319 QColor QQuickTextInput::color() const
321 Q_D(const QQuickTextInput);
325 void QQuickTextInput::setColor(const QColor &c)
327 Q_D(QQuickTextInput);
330 d->textLayoutDirty = true;
331 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
339 \qmlproperty color QtQuick2::TextInput::selectionColor
341 The text highlight color, used behind selections.
343 QColor QQuickTextInput::selectionColor() const
345 Q_D(const QQuickTextInput);
346 return d->selectionColor;
349 void QQuickTextInput::setSelectionColor(const QColor &color)
351 Q_D(QQuickTextInput);
352 if (d->selectionColor == color)
355 d->selectionColor = color;
356 if (d->hasSelectedText()) {
357 d->textLayoutDirty = true;
358 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
361 emit selectionColorChanged();
364 \qmlproperty color QtQuick2::TextInput::selectedTextColor
366 The highlighted text color, used in selections.
368 QColor QQuickTextInput::selectedTextColor() const
370 Q_D(const QQuickTextInput);
371 return d->selectedTextColor;
374 void QQuickTextInput::setSelectedTextColor(const QColor &color)
376 Q_D(QQuickTextInput);
377 if (d->selectedTextColor == color)
380 d->selectedTextColor = color;
381 if (d->hasSelectedText()) {
382 d->textLayoutDirty = true;
383 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
386 emit selectedTextColorChanged();
390 \qmlproperty enumeration QtQuick2::TextInput::horizontalAlignment
391 \qmlproperty enumeration QtQuick2::TextInput::effectiveHorizontalAlignment
392 \qmlproperty enumeration QtQuick2::TextInput::verticalAlignment
394 Sets the horizontal alignment of the text within the TextInput item's
395 width and height. By default, the text alignment follows the natural alignment
396 of the text, for example text that is read from left to right will be aligned to
399 TextInput does not have vertical alignment, as the natural height is
400 exactly the height of the single line of text. If you set the height
401 manually to something larger, TextInput will always be top aligned
402 vertically. You can use anchors to align it however you want within
405 The valid values for \c horizontalAlignment are \c TextInput.AlignLeft, \c TextInput.AlignRight and
406 \c TextInput.AlignHCenter.
408 Valid values for \c verticalAlignment are \c TextInput.AlignTop (default),
409 \c TextInput.AlignBottom \c TextInput.AlignVCenter.
411 When using the attached property LayoutMirroring::enabled to mirror application
412 layouts, the horizontal alignment of text will also be mirrored. However, the property
413 \c horizontalAlignment will remain unchanged. To query the effective horizontal alignment
414 of TextInput, use the read-only property \c effectiveHorizontalAlignment.
416 QQuickTextInput::HAlignment QQuickTextInput::hAlign() const
418 Q_D(const QQuickTextInput);
422 void QQuickTextInput::setHAlign(HAlignment align)
424 Q_D(QQuickTextInput);
425 bool forceAlign = d->hAlignImplicit && d->effectiveLayoutMirror;
426 d->hAlignImplicit = false;
427 if (d->setHAlign(align, forceAlign) && isComponentComplete()) {
429 updateCursorRectangle();
433 void QQuickTextInput::resetHAlign()
435 Q_D(QQuickTextInput);
436 d->hAlignImplicit = true;
437 if (d->determineHorizontalAlignment() && isComponentComplete()) {
439 updateCursorRectangle();
443 QQuickTextInput::HAlignment QQuickTextInput::effectiveHAlign() const
445 Q_D(const QQuickTextInput);
446 QQuickTextInput::HAlignment effectiveAlignment = d->hAlign;
447 if (!d->hAlignImplicit && d->effectiveLayoutMirror) {
449 case QQuickTextInput::AlignLeft:
450 effectiveAlignment = QQuickTextInput::AlignRight;
452 case QQuickTextInput::AlignRight:
453 effectiveAlignment = QQuickTextInput::AlignLeft;
459 return effectiveAlignment;
462 bool QQuickTextInputPrivate::setHAlign(QQuickTextInput::HAlignment alignment, bool forceAlign)
464 Q_Q(QQuickTextInput);
465 if ((hAlign != alignment || forceAlign) && alignment <= QQuickTextInput::AlignHCenter) { // justify not supported
466 QQuickTextInput::HAlignment oldEffectiveHAlign = q->effectiveHAlign();
468 emit q->horizontalAlignmentChanged(alignment);
469 if (oldEffectiveHAlign != q->effectiveHAlign())
470 emit q->effectiveHorizontalAlignmentChanged();
476 bool QQuickTextInputPrivate::determineHorizontalAlignment()
478 if (hAlignImplicit) {
479 // if no explicit alignment has been set, follow the natural layout direction of the text
480 QString text = q_func()->text();
482 text = m_textLayout.preeditAreaText();
483 bool isRightToLeft = text.isEmpty() ? qApp->inputMethod()->inputDirection() == Qt::RightToLeft
484 : text.isRightToLeft();
485 return setHAlign(isRightToLeft ? QQuickTextInput::AlignRight : QQuickTextInput::AlignLeft);
490 QQuickTextInput::VAlignment QQuickTextInput::vAlign() const
492 Q_D(const QQuickTextInput);
496 void QQuickTextInput::setVAlign(QQuickTextInput::VAlignment alignment)
498 Q_D(QQuickTextInput);
499 if (alignment == d->vAlign)
501 d->vAlign = alignment;
502 emit verticalAlignmentChanged(d->vAlign);
503 if (isComponentComplete()) {
504 updateCursorRectangle();
509 \qmlproperty enumeration QtQuick2::TextInput::wrapMode
511 Set this property to wrap the text to the TextInput item's width.
512 The text will only wrap if an explicit width has been set.
515 \li TextInput.NoWrap - no wrapping will be performed. If the text contains insufficient newlines, then implicitWidth will exceed a set width.
516 \li TextInput.WordWrap - wrapping is done on word boundaries only. If a word is too long, implicitWidth will exceed a set width.
517 \li TextInput.WrapAnywhere - wrapping is done at any point on a line, even if it occurs in the middle of a word.
518 \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.
521 The default is TextInput.NoWrap. If you set a width, consider using TextInput.Wrap.
523 QQuickTextInput::WrapMode QQuickTextInput::wrapMode() const
525 Q_D(const QQuickTextInput);
529 void QQuickTextInput::setWrapMode(WrapMode mode)
531 Q_D(QQuickTextInput);
532 if (mode == d->wrapMode)
536 updateCursorRectangle();
537 emit wrapModeChanged();
540 void QQuickTextInputPrivate::mirrorChange()
542 Q_Q(QQuickTextInput);
543 if (q->isComponentComplete()) {
544 if (!hAlignImplicit && (hAlign == QQuickTextInput::AlignRight || hAlign == QQuickTextInput::AlignLeft)) {
545 q->updateCursorRectangle();
546 emit q->effectiveHorizontalAlignmentChanged();
552 \qmlproperty bool QtQuick2::TextInput::readOnly
554 Sets whether user input can modify the contents of the TextInput.
556 If readOnly is set to true, then user input will not affect the text
557 property. Any bindings or attempts to set the text property will still
560 bool QQuickTextInput::isReadOnly() const
562 Q_D(const QQuickTextInput);
563 return d->m_readOnly;
566 void QQuickTextInput::setReadOnly(bool ro)
568 Q_D(QQuickTextInput);
569 if (d->m_readOnly == ro)
572 setFlag(QQuickItem::ItemAcceptsInputMethod, !ro);
575 d->setCursorPosition(d->end());
576 updateInputMethod(Qt::ImEnabled);
578 d->emitUndoRedoChanged();
579 emit readOnlyChanged(ro);
583 \qmlproperty int QtQuick2::TextInput::maximumLength
584 The maximum permitted length of the text in the TextInput.
586 If the text is too long, it is truncated at the limit.
588 By default, this property contains a value of 32767.
590 int QQuickTextInput::maxLength() const
592 Q_D(const QQuickTextInput);
593 return d->m_maxLength;
596 void QQuickTextInput::setMaxLength(int ml)
598 Q_D(QQuickTextInput);
599 if (d->m_maxLength == ml || d->m_maskData)
603 d->internalSetText(d->m_text, -1, false);
605 emit maximumLengthChanged(ml);
609 \qmlproperty bool QtQuick2::TextInput::cursorVisible
610 Set to true when the TextInput shows a cursor.
612 This property is set and unset when the TextInput gets active focus, so that other
613 properties can be bound to whether the cursor is currently showing. As it
614 gets set and unset automatically, when you set the value yourself you must
615 keep in mind that your value may be overwritten.
617 It can be set directly in script, for example if a KeyProxy might
618 forward keys to it and you desire it to look active when this happens
619 (but without actually giving it active focus).
621 It should not be set directly on the element, like in the below QML,
622 as the specified value will be overridden an lost on focus changes.
631 In the above snippet the cursor will still become visible when the
632 TextInput gains active focus.
634 bool QQuickTextInput::isCursorVisible() const
636 Q_D(const QQuickTextInput);
637 return d->cursorVisible;
640 void QQuickTextInput::setCursorVisible(bool on)
642 Q_D(QQuickTextInput);
643 if (d->cursorVisible == on)
645 d->cursorVisible = on;
646 d->setCursorBlinkPeriod(on ? qApp->styleHints()->cursorFlashTime() : 0);
647 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
649 emit cursorVisibleChanged(d->cursorVisible);
653 \qmlproperty int QtQuick2::TextInput::cursorPosition
654 The position of the cursor in the TextInput.
656 int QQuickTextInput::cursorPosition() const
658 Q_D(const QQuickTextInput);
662 void QQuickTextInput::setCursorPosition(int cp)
664 Q_D(QQuickTextInput);
665 if (cp < 0 || cp > text().length())
671 \qmlproperty rectangle QtQuick2::TextInput::cursorRectangle
673 The rectangle where the standard text cursor is rendered within the text input. Read only.
675 The position and height of a custom cursorDelegate are updated to follow the cursorRectangle
676 automatically when it changes. The width of the delegate is unaffected by changes in the
680 QRectF QQuickTextInput::cursorRectangle() const
682 Q_D(const QQuickTextInput);
685 if (d->m_preeditCursor != -1)
686 c += d->m_preeditCursor;
687 if (d->m_echoMode == NoEcho)
689 QTextLine l = d->m_textLayout.lineForTextPosition(c);
692 return QRectF(l.cursorToX(c) - d->hscroll, l.y() - d->vscroll, 1, l.height());
696 \qmlproperty int QtQuick2::TextInput::selectionStart
698 The cursor position before the first character in the current selection.
700 This property is read-only. To change the selection, use select(start,end),
701 selectAll(), or selectWord().
703 \sa selectionEnd, cursorPosition, selectedText
705 int QQuickTextInput::selectionStart() const
707 Q_D(const QQuickTextInput);
708 return d->lastSelectionStart;
711 \qmlproperty int QtQuick2::TextInput::selectionEnd
713 The cursor position after the last character in the current selection.
715 This property is read-only. To change the selection, use select(start,end),
716 selectAll(), or selectWord().
718 \sa selectionStart, cursorPosition, selectedText
720 int QQuickTextInput::selectionEnd() const
722 Q_D(const QQuickTextInput);
723 return d->lastSelectionEnd;
726 \qmlmethod void QtQuick2::TextInput::select(int start, int end)
728 Causes the text from \a start to \a end to be selected.
730 If either start or end is out of range, the selection is not changed.
732 After calling this, selectionStart will become the lesser
733 and selectionEnd will become the greater (regardless of the order passed
736 \sa selectionStart, selectionEnd
738 void QQuickTextInput::select(int start, int end)
740 Q_D(QQuickTextInput);
741 if (start < 0 || end < 0 || start > d->m_text.length() || end > d->m_text.length())
743 d->setSelection(start, end-start);
747 \qmlproperty string QtQuick2::TextInput::selectedText
749 This read-only property provides the text currently selected in the
752 It is equivalent to the following snippet, but is faster and easier
756 myTextInput.text.toString().substring(myTextInput.selectionStart,
757 myTextInput.selectionEnd);
760 QString QQuickTextInput::selectedText() const
762 Q_D(const QQuickTextInput);
763 return d->selectedText();
767 \qmlproperty bool QtQuick2::TextInput::activeFocusOnPress
769 Whether the TextInput should gain active focus on a mouse press. By default this is
772 bool QQuickTextInput::focusOnPress() const
774 Q_D(const QQuickTextInput);
775 return d->focusOnPress;
778 void QQuickTextInput::setFocusOnPress(bool b)
780 Q_D(QQuickTextInput);
781 if (d->focusOnPress == b)
786 emit activeFocusOnPressChanged(d->focusOnPress);
789 \qmlproperty bool QtQuick2::TextInput::autoScroll
791 Whether the TextInput should scroll when the text is longer than the width. By default this is
794 bool QQuickTextInput::autoScroll() const
796 Q_D(const QQuickTextInput);
797 return d->autoScroll;
800 void QQuickTextInput::setAutoScroll(bool b)
802 Q_D(QQuickTextInput);
803 if (d->autoScroll == b)
807 //We need to repaint so that the scrolling is taking into account.
808 updateCursorRectangle();
809 emit autoScrollChanged(d->autoScroll);
812 #ifndef QT_NO_VALIDATOR
815 \qmlclass IntValidator QIntValidator
816 \inqmlmodule QtQuick 2
817 \ingroup qml-basic-visual-elements
819 This element provides a validator for integer values.
821 If no \l locale is set IntValidator uses the \l {QLocale::setDefault()}{default locale} to
822 interpret the number and will accept locale specific digits, group separators, and positive
823 and negative signs. In addition, IntValidator is always guaranteed to accept a number
824 formatted according to the "C" locale.
828 QQuickIntValidator::QQuickIntValidator(QObject *parent)
829 : QIntValidator(parent)
834 \qmlproperty string QtQuick2::IntValidator::locale
836 This property holds the name of the locale used to interpret the number.
841 QString QQuickIntValidator::localeName() const
843 return locale().name();
846 void QQuickIntValidator::setLocaleName(const QString &name)
848 if (locale().name() != name) {
849 setLocale(QLocale(name));
850 emit localeNameChanged();
854 void QQuickIntValidator::resetLocaleName()
856 QLocale defaultLocale;
857 if (locale() != defaultLocale) {
858 setLocale(defaultLocale);
859 emit localeNameChanged();
864 \qmlproperty int QtQuick2::IntValidator::top
866 This property holds the validator's highest acceptable value.
867 By default, this property's value is derived from the highest signed integer available (typically 2147483647).
870 \qmlproperty int QtQuick2::IntValidator::bottom
872 This property holds the validator's lowest acceptable value.
873 By default, this property's value is derived from the lowest signed integer available (typically -2147483647).
877 \qmlclass DoubleValidator QDoubleValidator
878 \inqmlmodule QtQuick 2
879 \ingroup qml-basic-visual-elements
881 This element provides a validator for non-integer numbers.
883 Input is accepted if it contains a double that is within the valid range
884 and is in the correct format.
886 Input is accepected but invalid if it contains a double that is outside
887 the range or is in the wrong format; e.g. with too many digits after the
888 decimal point or is empty.
890 Input is rejected if it is not a double.
892 Note: If the valid range consists of just positive doubles (e.g. 0.0 to
893 100.0) and input is a negative double then it is rejected. If \l notation
894 is set to DoubleValidator.StandardNotation, and the input contains more
895 digits before the decimal point than a double in the valid range may have,
896 it is also rejected. If \l notation is DoubleValidator.ScientificNotation,
897 and the input is not in the valid range, it is accecpted but invalid. The
898 value may yet become valid by changing the exponent.
901 QQuickDoubleValidator::QQuickDoubleValidator(QObject *parent)
902 : QDoubleValidator(parent)
907 \qmlproperty string QtQuick2::DoubleValidator::locale
909 This property holds the name of the locale used to interpret the number.
914 QString QQuickDoubleValidator::localeName() const
916 return locale().name();
919 void QQuickDoubleValidator::setLocaleName(const QString &name)
921 if (locale().name() != name) {
922 setLocale(QLocale(name));
923 emit localeNameChanged();
927 void QQuickDoubleValidator::resetLocaleName()
929 QLocale defaultLocale;
930 if (locale() != defaultLocale) {
931 setLocale(defaultLocale);
932 emit localeNameChanged();
937 \qmlproperty real QtQuick2::DoubleValidator::top
939 This property holds the validator's maximum acceptable value.
940 By default, this property contains a value of infinity.
943 \qmlproperty real QtQuick2::DoubleValidator::bottom
945 This property holds the validator's minimum acceptable value.
946 By default, this property contains a value of -infinity.
949 \qmlproperty int QtQuick2::DoubleValidator::decimals
951 This property holds the validator's maximum number of digits after the decimal point.
952 By default, this property contains a value of 1000.
955 \qmlproperty enumeration QtQuick2::DoubleValidator::notation
956 This property holds the notation of how a string can describe a number.
958 The possible values for this property are:
961 \li DoubleValidator.StandardNotation
962 \li DoubleValidator.ScientificNotation (default)
965 If this property is set to DoubleValidator.ScientificNotation, the written number may have an exponent part (e.g. 1.5E-2).
969 \qmlclass RegExpValidator QRegExpValidator
970 \inqmlmodule QtQuick 2
971 \ingroup qml-basic-visual-elements
973 This element provides a validator, which counts as valid any string which
974 matches a specified regular expression.
977 \qmlproperty regExp QtQuick2::RegExpValidator::regExp
979 This property holds the regular expression used for validation.
981 Note that this property should be a regular expression in JS syntax, e.g /a/ for the regular expression
984 By default, this property contains a regular expression with the pattern .* that matches any string.
988 \qmlproperty Validator QtQuick2::TextInput::validator
990 Allows you to set a validator on the TextInput. When a validator is set
991 the TextInput will only accept input which leaves the text property in
992 an acceptable or intermediate state. The accepted signal will only be sent
993 if the text is in an acceptable state when enter is pressed.
995 Currently supported validators are IntValidator, DoubleValidator and
996 RegExpValidator. An example of using validators is shown below, which allows
997 input of integers between 11 and 31 into the text input:
1002 validator: IntValidator{bottom: 11; top: 31;}
1007 \sa acceptableInput, inputMask
1010 QValidator* QQuickTextInput::validator() const
1012 Q_D(const QQuickTextInput);
1013 return d->m_validator;
1016 void QQuickTextInput::setValidator(QValidator* v)
1018 Q_D(QQuickTextInput);
1019 if (d->m_validator == v)
1024 if (isComponentComplete())
1027 emit validatorChanged();
1030 #endif // QT_NO_VALIDATOR
1032 void QQuickTextInputPrivate::checkIsValid()
1034 Q_Q(QQuickTextInput);
1036 ValidatorState state = hasAcceptableInput(m_text);
1037 m_validInput = state != InvalidInput;
1038 if (state != AcceptableInput) {
1039 if (m_acceptableInput) {
1040 m_acceptableInput = false;
1041 emit q->acceptableInputChanged();
1043 } else if (!m_acceptableInput) {
1044 m_acceptableInput = true;
1045 emit q->acceptableInputChanged();
1050 \qmlproperty string QtQuick2::TextInput::inputMask
1052 Allows you to set an input mask on the TextInput, restricting the allowable
1053 text inputs. See QLineEdit::inputMask for further details, as the exact
1054 same mask strings are used by TextInput.
1056 \sa acceptableInput, validator
1058 QString QQuickTextInput::inputMask() const
1060 Q_D(const QQuickTextInput);
1061 return d->inputMask();
1064 void QQuickTextInput::setInputMask(const QString &im)
1066 Q_D(QQuickTextInput);
1067 if (d->inputMask() == im)
1070 d->setInputMask(im);
1071 emit inputMaskChanged(d->inputMask());
1075 \qmlproperty bool QtQuick2::TextInput::acceptableInput
1077 This property is always true unless a validator or input mask has been set.
1078 If a validator or input mask has been set, this property will only be true
1079 if the current text is acceptable to the validator or input mask as a final
1080 string (not as an intermediate string).
1082 bool QQuickTextInput::hasAcceptableInput() const
1084 Q_D(const QQuickTextInput);
1085 return d->hasAcceptableInput(d->m_text) == QQuickTextInputPrivate::AcceptableInput;
1089 \qmlsignal QtQuick2::TextInput::onAccepted()
1091 This handler is called when the Return or Enter key is pressed.
1092 Note that if there is a \l validator or \l inputMask set on the text
1093 input, the handler will only be emitted if the input is in an acceptable
1097 Qt::InputMethodHints QQuickTextInputPrivate::effectiveInputMethodHints() const
1099 Qt::InputMethodHints hints = inputMethodHints;
1100 if (m_echoMode == QQuickTextInput::Password || m_echoMode == QQuickTextInput::NoEcho)
1101 hints |= Qt::ImhHiddenText;
1102 else if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit)
1103 hints &= ~Qt::ImhHiddenText;
1104 if (m_echoMode != QQuickTextInput::Normal)
1105 hints |= (Qt::ImhNoAutoUppercase | Qt::ImhNoPredictiveText | Qt::ImhSensitiveData);
1109 \qmlproperty enumeration QtQuick2::TextInput::echoMode
1111 Specifies how the text should be displayed in the TextInput.
1113 \li TextInput.Normal - Displays the text as it is. (Default)
1114 \li TextInput.Password - Displays asterisks instead of characters.
1115 \li TextInput.NoEcho - Displays nothing.
1116 \li TextInput.PasswordEchoOnEdit - Displays characters as they are entered
1117 while editing, otherwise displays asterisks.
1120 QQuickTextInput::EchoMode QQuickTextInput::echoMode() const
1122 Q_D(const QQuickTextInput);
1123 return QQuickTextInput::EchoMode(d->m_echoMode);
1126 void QQuickTextInput::setEchoMode(QQuickTextInput::EchoMode echo)
1128 Q_D(QQuickTextInput);
1129 if (echoMode() == echo)
1131 d->cancelPasswordEchoTimer();
1132 d->m_echoMode = echo;
1133 d->m_passwordEchoEditing = false;
1134 updateInputMethod(Qt::ImHints);
1135 d->updateDisplayText();
1136 updateCursorRectangle();
1138 emit echoModeChanged(echoMode());
1142 \qmlproperty enumeration QtQuick2::TextInput::inputMethodHints
1144 Provides hints to the input method about the expected content of the text input and how it
1147 The value is a bit-wise combination of flags, or Qt.ImhNone if no hints are set.
1149 Flags that alter behaviour are:
1152 \li Qt.ImhHiddenText - Characters should be hidden, as is typically used when entering passwords.
1153 This is automatically set when setting echoMode to \c TextInput.Password.
1154 \li Qt.ImhSensitiveData - Typed text should not be stored by the active input method
1155 in any persistent storage like predictive user dictionary.
1156 \li Qt.ImhNoAutoUppercase - The input method should not try to automatically switch to upper case
1157 when a sentence ends.
1158 \li Qt.ImhPreferNumbers - Numbers are preferred (but not required).
1159 \li Qt.ImhPreferUppercase - Upper case letters are preferred (but not required).
1160 \li Qt.ImhPreferLowercase - Lower case letters are preferred (but not required).
1161 \li Qt.ImhNoPredictiveText - Do not use predictive text (i.e. dictionary lookup) while typing.
1163 \li Qt.ImhDate - The text editor functions as a date field.
1164 \li Qt.ImhTime - The text editor functions as a time field.
1167 Flags that restrict input (exclusive flags) are:
1170 \li Qt.ImhDigitsOnly - Only digits are allowed.
1171 \li Qt.ImhFormattedNumbersOnly - Only number input is allowed. This includes decimal point and minus sign.
1172 \li Qt.ImhUppercaseOnly - Only upper case letter input is allowed.
1173 \li Qt.ImhLowercaseOnly - Only lower case letter input is allowed.
1174 \li Qt.ImhDialableCharactersOnly - Only characters suitable for phone dialing are allowed.
1175 \li Qt.ImhEmailCharactersOnly - Only characters suitable for email addresses are allowed.
1176 \li Qt.ImhUrlCharactersOnly - Only characters suitable for URLs are allowed.
1182 \li Qt.ImhExclusiveInputMask - This mask yields nonzero if any of the exclusive flags are used.
1186 Qt::InputMethodHints QQuickTextInput::inputMethodHints() const
1188 Q_D(const QQuickTextInput);
1189 return d->inputMethodHints;
1192 void QQuickTextInput::setInputMethodHints(Qt::InputMethodHints hints)
1194 Q_D(QQuickTextInput);
1196 if (hints == d->inputMethodHints)
1199 d->inputMethodHints = hints;
1200 updateInputMethod(Qt::ImHints);
1201 emit inputMethodHintsChanged();
1205 \qmlproperty Component QtQuick2::TextInput::cursorDelegate
1206 The delegate for the cursor in the TextInput.
1208 If you set a cursorDelegate for a TextInput, this delegate will be used for
1209 drawing the cursor instead of the standard cursor. An instance of the
1210 delegate will be created and managed by the TextInput when a cursor is
1211 needed, and the x property of delegate instance will be set so as
1212 to be one pixel before the top left of the current character.
1214 Note that the root item of the delegate component must be a QQuickItem or
1215 QQuickItem derived item.
1217 QQmlComponent* QQuickTextInput::cursorDelegate() const
1219 Q_D(const QQuickTextInput);
1220 return d->cursorComponent;
1223 void QQuickTextInput::setCursorDelegate(QQmlComponent* c)
1225 Q_D(QQuickTextInput);
1226 if (d->cursorComponent == c)
1229 d->cursorComponent = c;
1231 //note that the components are owned by something else
1232 delete d->cursorItem;
1235 d->startCreatingCursor();
1238 emit cursorDelegateChanged();
1241 void QQuickTextInputPrivate::startCreatingCursor()
1243 Q_Q(QQuickTextInput);
1244 if (cursorComponent->isReady()) {
1246 } else if (cursorComponent->isLoading()) {
1247 q->connect(cursorComponent, SIGNAL(statusChanged(int)),
1248 q, SLOT(createCursor()));
1250 qmlInfo(q, cursorComponent->errors()) << QQuickTextInput::tr("Could not load cursor delegate");
1254 void QQuickTextInput::createCursor()
1256 Q_D(QQuickTextInput);
1257 if (!isComponentComplete())
1260 if (d->cursorComponent->isError()) {
1261 qmlInfo(this, d->cursorComponent->errors()) << tr("Could not load cursor delegate");
1265 if (!d->cursorComponent->isReady())
1269 delete d->cursorItem;
1270 QQmlContext *creationContext = d->cursorComponent->creationContext();
1271 QObject *object = d->cursorComponent->create(creationContext ? creationContext : qmlContext(this));
1272 d->cursorItem = qobject_cast<QQuickItem*>(object);
1273 if (!d->cursorItem) {
1275 qmlInfo(this, d->cursorComponent->errors()) << tr("Could not instantiate cursor delegate");
1279 QRectF r = cursorRectangle();
1281 QQml_setParent_noEvent(d->cursorItem, this);
1282 d->cursorItem->setParentItem(this);
1283 d->cursorItem->setPos(r.topLeft());
1284 d->cursorItem->setHeight(r.height());
1288 \qmlmethod rect QtQuick2::TextInput::positionToRectangle(int pos)
1290 This function takes a character position and returns the rectangle that the
1291 cursor would occupy, if it was placed at that character position.
1293 This is similar to setting the cursorPosition, and then querying the cursor
1294 rectangle, but the cursorPosition is not changed.
1296 QRectF QQuickTextInput::positionToRectangle(int pos) const
1298 Q_D(const QQuickTextInput);
1299 if (d->m_echoMode == NoEcho)
1301 else if (pos > d->m_cursor)
1302 pos += d->preeditAreaText().length();
1303 QTextLine l = d->m_textLayout.lineForTextPosition(pos);
1305 ? QRectF(l.cursorToX(pos) - d->hscroll, l.y() - d->vscroll, 1, l.height())
1310 \qmlmethod int QtQuick2::TextInput::positionAt(real x, real y, CursorPosition position = CursorBetweenCharacters)
1312 This function returns the character position at
1313 x and y pixels from the top left of the textInput. Position 0 is before the
1314 first character, position 1 is after the first character but before the second,
1315 and so on until position text.length, which is after all characters.
1317 This means that for all x values before the first character this function returns 0,
1318 and for all x values after the last character this function returns text.length. If
1319 the y value is above the text the position will be that of the nearest character on
1320 the first line line and if it is below the text the position of the nearest character
1321 on the last line will be returned.
1323 The cursor position type specifies how the cursor position should be resolved.
1326 \li TextInput.CursorBetweenCharacters - Returns the position between characters that is nearest x.
1327 \li TextInput.CursorOnCharacter - Returns the position before the character that is nearest x.
1331 void QQuickTextInput::positionAt(QQmlV8Function *args) const
1333 Q_D(const QQuickTextInput);
1337 QTextLine::CursorPosition position = QTextLine::CursorBetweenCharacters;
1339 if (args->Length() < 1)
1343 v8::Local<v8::Value> arg = (*args)[i];
1344 x = arg->NumberValue();
1346 if (++i < args->Length()) {
1348 y = arg->NumberValue();
1351 if (++i < args->Length()) {
1353 position = QTextLine::CursorPosition(arg->Int32Value());
1356 int pos = d->positionAt(x, y, position);
1357 const int cursor = d->m_cursor;
1359 const int preeditLength = d->preeditAreaText().length();
1360 pos = pos > cursor + preeditLength
1361 ? pos - preeditLength
1364 args->returnValue(v8::Int32::New(pos));
1367 int QQuickTextInputPrivate::positionAt(qreal x, qreal y, QTextLine::CursorPosition position) const
1371 QTextLine line = m_textLayout.lineAt(0);
1372 for (int i = 1; i < m_textLayout.lineCount(); ++i) {
1373 QTextLine nextLine = m_textLayout.lineAt(i);
1375 if (y < (line.rect().bottom() + nextLine.y()) / 2)
1379 return line.isValid() ? line.xToCursor(x, position) : 0;
1382 void QQuickTextInput::keyPressEvent(QKeyEvent* ev)
1384 Q_D(QQuickTextInput);
1385 // Don't allow MacOSX up/down support, and we don't allow a completer.
1386 bool ignore = (ev->key() == Qt::Key_Up || ev->key() == Qt::Key_Down) && ev->modifiers() == Qt::NoModifier;
1387 if (!ignore && (d->lastSelectionStart == d->lastSelectionEnd) && (ev->key() == Qt::Key_Right || ev->key() == Qt::Key_Left)) {
1388 // Ignore when moving off the end unless there is a selection,
1389 // because then moving will do something (deselect).
1390 int cursorPosition = d->m_cursor;
1391 if (cursorPosition == 0)
1392 ignore = ev->key() == (d->layoutDirection() == Qt::LeftToRight ? Qt::Key_Left : Qt::Key_Right);
1393 if (cursorPosition == text().length())
1394 ignore = ev->key() == (d->layoutDirection() == Qt::LeftToRight ? Qt::Key_Right : Qt::Key_Left);
1399 d->processKeyEvent(ev);
1401 if (!ev->isAccepted())
1402 QQuickImplicitSizeItem::keyPressEvent(ev);
1405 void QQuickTextInput::inputMethodEvent(QInputMethodEvent *ev)
1407 Q_D(QQuickTextInput);
1408 const bool wasComposing = d->preeditAreaText().length() > 0;
1409 if (d->m_readOnly) {
1412 d->processInputMethodEvent(ev);
1414 if (!ev->isAccepted())
1415 QQuickImplicitSizeItem::inputMethodEvent(ev);
1417 if (wasComposing != (d->m_textLayout.preeditAreaText().length() > 0))
1418 emit inputMethodComposingChanged();
1421 void QQuickTextInput::mouseDoubleClickEvent(QMouseEvent *event)
1423 Q_D(QQuickTextInput);
1425 if (d->selectByMouse && event->button() == Qt::LeftButton) {
1427 int cursor = d->positionAt(event->localPos());
1428 d->selectWordAtPos(cursor);
1429 event->setAccepted(true);
1430 if (!d->hasPendingTripleClick()) {
1431 d->tripleClickStartPoint = event->localPos();
1432 d->tripleClickTimer.start();
1435 if (d->sendMouseEventToInputContext(event))
1437 QQuickImplicitSizeItem::mouseDoubleClickEvent(event);
1441 void QQuickTextInput::mousePressEvent(QMouseEvent *event)
1443 Q_D(QQuickTextInput);
1445 d->pressPos = event->localPos();
1447 if (d->sendMouseEventToInputContext(event))
1450 if (d->selectByMouse) {
1451 setKeepMouseGrab(false);
1452 d->selectPressed = true;
1453 QPointF distanceVector = d->pressPos - d->tripleClickStartPoint;
1454 if (d->hasPendingTripleClick()
1455 && distanceVector.manhattanLength() < qApp->styleHints()->startDragDistance()) {
1456 event->setAccepted(true);
1462 bool mark = (event->modifiers() & Qt::ShiftModifier) && d->selectByMouse;
1463 int cursor = d->positionAt(event->localPos());
1464 d->moveCursor(cursor, mark);
1466 if (d->focusOnPress) {
1467 bool hadActiveFocus = hasActiveFocus();
1469 // re-open input panel on press if already focused
1470 if (hasActiveFocus() && hadActiveFocus && !d->m_readOnly)
1471 openSoftwareInputPanel();
1474 event->setAccepted(true);
1477 void QQuickTextInput::mouseMoveEvent(QMouseEvent *event)
1479 Q_D(QQuickTextInput);
1481 if (d->selectPressed) {
1482 if (qAbs(int(event->localPos().x() - d->pressPos.x())) > qApp->styleHints()->startDragDistance())
1483 setKeepMouseGrab(true);
1485 if (d->composeMode()) {
1487 int startPos = d->positionAt(d->pressPos);
1488 int currentPos = d->positionAt(event->localPos());
1489 if (startPos != currentPos)
1490 d->setSelection(startPos, currentPos - startPos);
1492 moveCursorSelection(d->positionAt(event->localPos()), d->mouseSelectionMode);
1494 event->setAccepted(true);
1496 QQuickImplicitSizeItem::mouseMoveEvent(event);
1500 void QQuickTextInput::mouseReleaseEvent(QMouseEvent *event)
1502 Q_D(QQuickTextInput);
1503 if (d->sendMouseEventToInputContext(event))
1505 if (d->selectPressed) {
1506 d->selectPressed = false;
1507 setKeepMouseGrab(false);
1509 #ifndef QT_NO_CLIPBOARD
1510 if (QGuiApplication::clipboard()->supportsSelection()) {
1511 if (event->button() == Qt::LeftButton) {
1512 d->copy(QClipboard::Selection);
1513 } else if (!d->m_readOnly && event->button() == Qt::MidButton) {
1515 d->insert(QGuiApplication::clipboard()->text(QClipboard::Selection));
1519 if (!event->isAccepted())
1520 QQuickImplicitSizeItem::mouseReleaseEvent(event);
1523 bool QQuickTextInputPrivate::sendMouseEventToInputContext(QMouseEvent *event)
1525 #if !defined QT_NO_IM
1526 if (composeMode()) {
1527 int tmp_cursor = positionAt(event->localPos());
1528 int mousePos = tmp_cursor - m_cursor;
1529 if (mousePos >= 0 && mousePos <= m_textLayout.preeditAreaText().length()) {
1530 if (event->type() == QEvent::MouseButtonRelease) {
1531 qApp->inputMethod()->invokeAction(QInputMethod::Click, mousePos);
1544 void QQuickTextInput::mouseUngrabEvent()
1546 Q_D(QQuickTextInput);
1547 d->selectPressed = false;
1548 setKeepMouseGrab(false);
1551 bool QQuickTextInput::event(QEvent* ev)
1553 #ifndef QT_NO_SHORTCUT
1554 Q_D(QQuickTextInput);
1555 if (ev->type() == QEvent::ShortcutOverride) {
1558 QKeyEvent* ke = static_cast<QKeyEvent*>(ev);
1559 if (ke == QKeySequence::Copy
1560 || ke == QKeySequence::Paste
1561 || ke == QKeySequence::Cut
1562 || ke == QKeySequence::Redo
1563 || ke == QKeySequence::Undo
1564 || ke == QKeySequence::MoveToNextWord
1565 || ke == QKeySequence::MoveToPreviousWord
1566 || ke == QKeySequence::MoveToStartOfDocument
1567 || ke == QKeySequence::MoveToEndOfDocument
1568 || ke == QKeySequence::SelectNextWord
1569 || ke == QKeySequence::SelectPreviousWord
1570 || ke == QKeySequence::SelectStartOfLine
1571 || ke == QKeySequence::SelectEndOfLine
1572 || ke == QKeySequence::SelectStartOfBlock
1573 || ke == QKeySequence::SelectEndOfBlock
1574 || ke == QKeySequence::SelectStartOfDocument
1575 || ke == QKeySequence::SelectAll
1576 || ke == QKeySequence::SelectEndOfDocument) {
1578 } else if (ke->modifiers() == Qt::NoModifier || ke->modifiers() == Qt::ShiftModifier
1579 || ke->modifiers() == Qt::KeypadModifier) {
1580 if (ke->key() < Qt::Key_Escape) {
1584 switch (ke->key()) {
1585 case Qt::Key_Delete:
1588 case Qt::Key_Backspace:
1600 return QQuickImplicitSizeItem::event(ev);
1603 void QQuickTextInput::geometryChanged(const QRectF &newGeometry,
1604 const QRectF &oldGeometry)
1606 Q_D(QQuickTextInput);
1608 if (newGeometry.width() != oldGeometry.width() && d->wrapMode != NoWrap)
1610 updateCursorRectangle();
1612 QQuickImplicitSizeItem::geometryChanged(newGeometry, oldGeometry);
1615 void QQuickTextInputPrivate::updateHorizontalScroll()
1617 Q_Q(QQuickTextInput);
1618 QTextLine currentLine = m_textLayout.lineForTextPosition(m_cursor + m_preeditCursor);
1619 const int preeditLength = m_textLayout.preeditAreaText().length();
1620 const qreal width = qMax<qreal>(0, q->width());
1622 qreal widthUsed = 0;
1623 if (currentLine.isValid()) {
1624 cix = currentLine.cursorToX(m_cursor + preeditLength);
1625 const qreal cursorWidth = cix >= 0 ? cix : width - cix;
1626 widthUsed = qMax(currentLine.naturalTextWidth(), cursorWidth);
1628 int previousScroll = hscroll;
1630 if (!autoScroll || widthUsed <= width || m_echoMode == QQuickTextInput::NoEcho) {
1633 Q_ASSERT(currentLine.isValid());
1634 if (cix - hscroll >= width) {
1635 // text doesn't fit, cursor is to the right of br (scroll right)
1636 hscroll = cix - width;
1637 } else if (cix - hscroll < 0 && hscroll < widthUsed) {
1638 // text doesn't fit, cursor is to the left of br (scroll left)
1640 } else if (widthUsed - hscroll < width) {
1641 // text doesn't fit, text document is to the left of br; align
1643 hscroll = widthUsed - width;
1644 } else if (width - hscroll > widthUsed) {
1645 // text doesn't fit, text document is to the right of br; align
1647 hscroll = width - widthUsed;
1649 if (preeditLength > 0) {
1650 // check to ensure long pre-edit text doesn't push the cursor
1652 cix = currentLine.cursorToX(m_cursor + qMax(0, m_preeditCursor - 1));
1657 if (previousScroll != hscroll)
1658 textLayoutDirty = true;
1661 void QQuickTextInputPrivate::updateVerticalScroll()
1663 Q_Q(QQuickTextInput);
1664 const int preeditLength = m_textLayout.preeditAreaText().length();
1665 const qreal height = qMax<qreal>(0, q->height());
1666 qreal heightUsed = boundingRect.height();
1667 qreal previousScroll = vscroll;
1669 if (!autoScroll || heightUsed <= height) {
1670 // text fits in br; use vscroll for alignment
1671 switch (vAlign & ~(Qt::AlignAbsolute|Qt::AlignHorizontal_Mask)) {
1672 case Qt::AlignBottom:
1673 vscroll = heightUsed - height;
1675 case Qt::AlignVCenter:
1676 vscroll = (heightUsed - height) / 2;
1684 QTextLine currentLine = m_textLayout.lineForTextPosition(m_cursor + preeditLength);
1685 QRectF r = currentLine.isValid() ? currentLine.rect() : QRectF();
1686 qreal top = r.top();
1687 int bottom = r.bottom();
1689 if (bottom - vscroll >= height) {
1690 // text doesn't fit, cursor is to the below the br (scroll down)
1691 vscroll = bottom - height;
1692 } else if (top - vscroll < 0 && vscroll < heightUsed) {
1693 // text doesn't fit, cursor is above br (scroll up)
1695 } else if (heightUsed - vscroll < height) {
1696 // text doesn't fit, text document is to the left of br; align
1698 vscroll = heightUsed - height;
1700 if (preeditLength > 0) {
1701 // check to ensure long pre-edit text doesn't push the cursor
1703 currentLine = m_textLayout.lineForTextPosition(m_cursor + qMax(0, m_preeditCursor - 1));
1704 top = currentLine.isValid() ? currentLine.rect().top() : 0;
1709 if (previousScroll != vscroll)
1710 textLayoutDirty = true;
1713 void QQuickTextInput::triggerPreprocess()
1715 Q_D(QQuickTextInput);
1716 if (d->updateType == QQuickTextInputPrivate::UpdateNone)
1717 d->updateType = QQuickTextInputPrivate::UpdateOnlyPreprocess;
1721 QSGNode *QQuickTextInput::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data)
1724 Q_D(QQuickTextInput);
1726 if (d->updateType != QQuickTextInputPrivate::UpdatePaintNode && oldNode != 0) {
1727 // Update done in preprocess() in the nodes
1728 d->updateType = QQuickTextInputPrivate::UpdateNone;
1732 d->updateType = QQuickTextInputPrivate::UpdateNone;
1734 QQuickTextNode *node = static_cast<QQuickTextNode *>(oldNode);
1736 node = new QQuickTextNode(QQuickItemPrivate::get(this)->sceneGraphContext(), this);
1739 if (!d->textLayoutDirty) {
1740 QSGSimpleRectNode *cursorNode = node->cursorNode();
1741 if (cursorNode != 0 && !isReadOnly()) {
1742 cursorNode->setRect(cursorRectangle());
1744 if (!d->cursorVisible || (!d->m_blinkStatus && d->m_blinkPeriod > 0)) {
1751 node->deleteContent();
1752 node->setMatrix(QMatrix4x4());
1754 QPointF offset(0, 0);
1755 if (d->autoScroll && d->m_textLayout.lineCount() > 0) {
1756 QFontMetricsF fm(d->font);
1757 // the y offset is there to keep the baseline constant in case we have script changes in the text.
1758 offset = -QPoint(d->hscroll, d->vscroll + d->m_textLayout.lineAt(0).ascent() - fm.ascent());
1760 offset = -QPoint(d->hscroll, d->vscroll);
1763 if (!d->m_textLayout.text().isEmpty() || !d->m_textLayout.preeditAreaText().isEmpty()) {
1764 node->addTextLayout(offset, &d->m_textLayout, d->color,
1765 QQuickText::Normal, QColor(), QColor(),
1766 d->selectionColor, d->selectedTextColor,
1767 d->selectionStart(),
1768 d->selectionEnd() - 1); // selectionEnd() returns first char after
1772 if (!isReadOnly() && d->cursorItem == 0) {
1773 node->setCursor(cursorRectangle(), d->color);
1774 if (!d->cursorVisible || (!d->m_blinkStatus && d->m_blinkPeriod > 0)) {
1781 d->textLayoutDirty = false;
1787 QVariant QQuickTextInput::inputMethodQuery(Qt::InputMethodQuery property) const
1789 Q_D(const QQuickTextInput);
1792 return QVariant((bool)(flags() & ItemAcceptsInputMethod));
1794 return QVariant((int) d->effectiveInputMethodHints());
1795 case Qt::ImCursorRectangle:
1796 return cursorRectangle();
1799 case Qt::ImCursorPosition:
1800 return QVariant(d->m_cursor);
1801 case Qt::ImSurroundingText:
1802 if (d->m_echoMode == PasswordEchoOnEdit && !d->m_passwordEchoEditing) {
1803 return QVariant(displayText());
1805 return QVariant(d->realText());
1807 case Qt::ImCurrentSelection:
1808 return QVariant(selectedText());
1809 case Qt::ImMaximumTextLength:
1810 return QVariant(maxLength());
1811 case Qt::ImAnchorPosition:
1812 if (d->selectionStart() == d->selectionEnd())
1813 return QVariant(d->m_cursor);
1814 else if (d->selectionStart() == d->m_cursor)
1815 return QVariant(d->selectionEnd());
1817 return QVariant(d->selectionStart());
1824 \qmlmethod void QtQuick2::TextInput::deselect()
1826 Removes active text selection.
1828 void QQuickTextInput::deselect()
1830 Q_D(QQuickTextInput);
1835 \qmlmethod void QtQuick2::TextInput::selectAll()
1837 Causes all text to be selected.
1839 void QQuickTextInput::selectAll()
1841 Q_D(QQuickTextInput);
1842 d->setSelection(0, text().length());
1846 \qmlmethod void QtQuick2::TextInput::isRightToLeft(int start, int end)
1848 Returns true if the natural reading direction of the editor text
1849 found between positions \a start and \a end is right to left.
1851 bool QQuickTextInput::isRightToLeft(int start, int end)
1854 qmlInfo(this) << "isRightToLeft(start, end) called with the end property being smaller than the start.";
1857 return text().mid(start, end - start).isRightToLeft();
1861 #ifndef QT_NO_CLIPBOARD
1863 \qmlmethod QtQuick2::TextInput::cut()
1865 Moves the currently selected text to the system clipboard.
1867 void QQuickTextInput::cut()
1869 Q_D(QQuickTextInput);
1875 \qmlmethod QtQuick2::TextInput::copy()
1877 Copies the currently selected text to the system clipboard.
1879 void QQuickTextInput::copy()
1881 Q_D(QQuickTextInput);
1886 \qmlmethod QtQuick2::TextInput::paste()
1888 Replaces the currently selected text by the contents of the system clipboard.
1890 void QQuickTextInput::paste()
1892 Q_D(QQuickTextInput);
1896 #endif // QT_NO_CLIPBOARD
1899 Undoes the last operation if undo is \l {canUndo}{available}. Deselects any
1900 current selection, and updates the selection start to the current cursor
1904 void QQuickTextInput::undo()
1906 Q_D(QQuickTextInput);
1907 if (!d->m_readOnly) {
1909 d->finishChange(-1, true);
1914 Redoes the last operation if redo is \l {canRedo}{available}.
1917 void QQuickTextInput::redo()
1919 Q_D(QQuickTextInput);
1920 if (!d->m_readOnly) {
1927 \qmlmethod void QtQuick2::TextInput::insert(int position, string text)
1929 Inserts \a text into the TextInput at position.
1932 void QQuickTextInput::insert(int position, const QString &text)
1934 Q_D(QQuickTextInput);
1935 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
1936 if (d->m_echoMode == QQuickTextInput::Password)
1937 d->m_passwordEchoTimer.start(qt_passwordEchoDelay, this);
1940 if (position < 0 || position > d->m_text.length())
1943 const int priorState = d->m_undoState;
1945 QString insertText = text;
1947 if (d->hasSelectedText()) {
1948 d->addCommand(QQuickTextInputPrivate::Command(
1949 QQuickTextInputPrivate::SetSelection, d->m_cursor, 0, d->m_selstart, d->m_selend));
1951 if (d->m_maskData) {
1952 insertText = d->maskString(position, insertText);
1953 for (int i = 0; i < insertText.length(); ++i) {
1954 d->addCommand(QQuickTextInputPrivate::Command(
1955 QQuickTextInputPrivate::DeleteSelection, position + i, d->m_text.at(position + i), -1, -1));
1956 d->addCommand(QQuickTextInputPrivate::Command(
1957 QQuickTextInputPrivate::Insert, position + i, insertText.at(i), -1, -1));
1959 d->m_text.replace(position, insertText.length(), insertText);
1960 if (!insertText.isEmpty())
1961 d->m_textDirty = true;
1962 if (position < d->m_selend && position + insertText.length() > d->m_selstart)
1963 d->m_selDirty = true;
1965 int remaining = d->m_maxLength - d->m_text.length();
1966 if (remaining != 0) {
1967 insertText = insertText.left(remaining);
1968 d->m_text.insert(position, insertText);
1969 for (int i = 0; i < insertText.length(); ++i)
1970 d->addCommand(QQuickTextInputPrivate::Command(
1971 QQuickTextInputPrivate::Insert, position + i, insertText.at(i), -1, -1));
1972 if (d->m_cursor >= position)
1973 d->m_cursor += insertText.length();
1974 if (d->m_selstart >= position)
1975 d->m_selstart += insertText.length();
1976 if (d->m_selend >= position)
1977 d->m_selend += insertText.length();
1978 d->m_textDirty = true;
1979 if (position >= d->m_selstart && position <= d->m_selend)
1980 d->m_selDirty = true;
1984 d->addCommand(QQuickTextInputPrivate::Command(
1985 QQuickTextInputPrivate::SetSelection, d->m_cursor, 0, d->m_selstart, d->m_selend));
1986 d->finishChange(priorState);
1988 if (d->lastSelectionStart != d->lastSelectionEnd) {
1989 if (d->m_selstart != d->lastSelectionStart) {
1990 d->lastSelectionStart = d->m_selstart;
1991 emit selectionStartChanged();
1993 if (d->m_selend != d->lastSelectionEnd) {
1994 d->lastSelectionEnd = d->m_selend;
1995 emit selectionEndChanged();
2001 \qmlmethod string QtQuick2::TextInput::getText(int start, int end)
2003 Removes the section of text that is between the \a start and \a end positions from the TextInput.
2006 void QQuickTextInput::remove(int start, int end)
2008 Q_D(QQuickTextInput);
2010 start = qBound(0, start, d->m_text.length());
2011 end = qBound(0, end, d->m_text.length());
2015 else if (start == end)
2018 if (start < d->m_selend && end > d->m_selstart)
2019 d->m_selDirty = true;
2021 const int priorState = d->m_undoState;
2023 d->addCommand(QQuickTextInputPrivate::Command(
2024 QQuickTextInputPrivate::SetSelection, d->m_cursor, 0, d->m_selstart, d->m_selend));
2026 if (start <= d->m_cursor && d->m_cursor < end) {
2027 // cursor is within the selection. Split up the commands
2028 // to be able to restore the correct cursor position
2029 for (int i = d->m_cursor; i >= start; --i) {
2030 d->addCommand(QQuickTextInputPrivate::Command(
2031 QQuickTextInputPrivate::DeleteSelection, i, d->m_text.at(i), -1, 1));
2033 for (int i = end - 1; i > d->m_cursor; --i) {
2034 d->addCommand(QQuickTextInputPrivate::Command(
2035 QQuickTextInputPrivate::DeleteSelection, i - d->m_cursor + start - 1, d->m_text.at(i), -1, -1));
2038 for (int i = end - 1; i >= start; --i) {
2039 d->addCommand(QQuickTextInputPrivate::Command(
2040 QQuickTextInputPrivate::RemoveSelection, i, d->m_text.at(i), -1, -1));
2043 if (d->m_maskData) {
2044 d->m_text.replace(start, end - start, d->clearString(start, end - start));
2045 for (int i = 0; i < end - start; ++i) {
2046 d->addCommand(QQuickTextInputPrivate::Command(
2047 QQuickTextInputPrivate::Insert, start + i, d->m_text.at(start + i), -1, -1));
2050 d->m_text.remove(start, end - start);
2052 if (d->m_cursor > start)
2053 d->m_cursor -= qMin(d->m_cursor, end) - start;
2054 if (d->m_selstart > start)
2055 d->m_selstart -= qMin(d->m_selstart, end) - start;
2056 if (d->m_selend > end)
2057 d->m_selend -= qMin(d->m_selend, end) - start;
2059 d->addCommand(QQuickTextInputPrivate::Command(
2060 QQuickTextInputPrivate::SetSelection, d->m_cursor, 0, d->m_selstart, d->m_selend));
2062 d->m_textDirty = true;
2063 d->finishChange(priorState);
2065 if (d->lastSelectionStart != d->lastSelectionEnd) {
2066 if (d->m_selstart != d->lastSelectionStart) {
2067 d->lastSelectionStart = d->m_selstart;
2068 emit selectionStartChanged();
2070 if (d->m_selend != d->lastSelectionEnd) {
2071 d->lastSelectionEnd = d->m_selend;
2072 emit selectionEndChanged();
2079 \qmlmethod void QtQuick2::TextInput::selectWord()
2081 Causes the word closest to the current cursor position to be selected.
2083 void QQuickTextInput::selectWord()
2085 Q_D(QQuickTextInput);
2086 d->selectWordAtPos(d->m_cursor);
2090 \qmlproperty bool QtQuick2::TextInput::smooth
2092 This property holds whether the text is smoothly scaled or transformed.
2094 Smooth filtering gives better visual quality, but is slower. If
2095 the item is displayed at its natural size, this property has no visual or
2098 \note Generally scaling artifacts are only visible if the item is stationary on
2099 the screen. A common pattern when animating an item is to disable smooth
2100 filtering at the beginning of the animation and reenable it at the conclusion.
2104 \qmlproperty string QtQuick2::TextInput::passwordCharacter
2106 This is the character displayed when echoMode is set to Password or
2107 PasswordEchoOnEdit. By default it is an asterisk.
2109 If this property is set to a string with more than one character,
2110 the first character is used. If the string is empty, the value
2111 is ignored and the property is not set.
2113 QString QQuickTextInput::passwordCharacter() const
2115 Q_D(const QQuickTextInput);
2116 return QString(d->m_passwordCharacter);
2119 void QQuickTextInput::setPasswordCharacter(const QString &str)
2121 Q_D(QQuickTextInput);
2122 if (str.length() < 1)
2124 d->m_passwordCharacter = str.constData()[0];
2125 if (d->m_echoMode == Password || d->m_echoMode == PasswordEchoOnEdit)
2126 d->updateDisplayText();
2127 emit passwordCharacterChanged();
2131 \qmlproperty string QtQuick2::TextInput::displayText
2133 This is the text displayed in the TextInput.
2135 If \l echoMode is set to TextInput::Normal, this holds the
2136 same value as the TextInput::text property. Otherwise,
2137 this property holds the text visible to the user, while
2138 the \l text property holds the actual entered text.
2140 QString QQuickTextInput::displayText() const
2142 Q_D(const QQuickTextInput);
2143 return d->m_textLayout.text();
2147 \qmlproperty bool QtQuick2::TextInput::selectByMouse
2151 If true, the user can use the mouse to select text in some
2152 platform-specific way. Note that for some platforms this may
2153 not be an appropriate interaction (eg. may conflict with how
2154 the text needs to behave inside a Flickable.
2156 bool QQuickTextInput::selectByMouse() const
2158 Q_D(const QQuickTextInput);
2159 return d->selectByMouse;
2162 void QQuickTextInput::setSelectByMouse(bool on)
2164 Q_D(QQuickTextInput);
2165 if (d->selectByMouse != on) {
2166 d->selectByMouse = on;
2167 emit selectByMouseChanged(on);
2172 \qmlproperty enum QtQuick2::TextInput::mouseSelectionMode
2174 Specifies how text should be selected using a mouse.
2177 \li TextInput.SelectCharacters - The selection is updated with individual characters. (Default)
2178 \li TextInput.SelectWords - The selection is updated with whole words.
2181 This property only applies when \l selectByMouse is true.
2184 QQuickTextInput::SelectionMode QQuickTextInput::mouseSelectionMode() const
2186 Q_D(const QQuickTextInput);
2187 return d->mouseSelectionMode;
2190 void QQuickTextInput::setMouseSelectionMode(SelectionMode mode)
2192 Q_D(QQuickTextInput);
2193 if (d->mouseSelectionMode != mode) {
2194 d->mouseSelectionMode = mode;
2195 emit mouseSelectionModeChanged(mode);
2200 \qmlproperty bool QtQuick2::TextInput::persistentSelection
2202 Whether the TextInput should keep its selection when it loses active focus to another
2203 item in the scene. By default this is set to false;
2206 bool QQuickTextInput::persistentSelection() const
2208 Q_D(const QQuickTextInput);
2209 return d->persistentSelection;
2212 void QQuickTextInput::setPersistentSelection(bool on)
2214 Q_D(QQuickTextInput);
2215 if (d->persistentSelection == on)
2217 d->persistentSelection = on;
2218 emit persistentSelectionChanged();
2222 \qmlproperty bool QtQuick2::TextInput::canPaste
2224 Returns true if the TextInput is writable and the content of the clipboard is
2225 suitable for pasting into the TextInput.
2227 bool QQuickTextInput::canPaste() const
2229 Q_D(const QQuickTextInput);
2230 if (!d->canPasteValid) {
2231 if (const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData())
2232 const_cast<QQuickTextInputPrivate *>(d)->canPaste = !d->m_readOnly && mimeData->hasText();
2233 const_cast<QQuickTextInputPrivate *>(d)->canPasteValid = true;
2239 \qmlproperty bool QtQuick2::TextInput::canUndo
2241 Returns true if the TextInput is writable and there are previous operations
2245 bool QQuickTextInput::canUndo() const
2247 Q_D(const QQuickTextInput);
2252 \qmlproperty bool QtQuick2::TextInput::canRedo
2254 Returns true if the TextInput is writable and there are \l {undo}{undone}
2255 operations that can be redone.
2258 bool QQuickTextInput::canRedo() const
2260 Q_D(const QQuickTextInput);
2265 \qmlproperty real QtQuick2::TextInput::contentWidth
2267 Returns the width of the text, including the width past the width
2268 which is covered due to insufficient wrapping if \l wrapMode is set.
2271 qreal QQuickTextInput::contentWidth() const
2273 Q_D(const QQuickTextInput);
2274 return d->boundingRect.width();
2278 \qmlproperty real QtQuick2::TextInput::contentHeight
2280 Returns the height of the text, including the height past the height
2281 that is covered if the text does not fit within the set height.
2284 qreal QQuickTextInput::contentHeight() const
2286 Q_D(const QQuickTextInput);
2287 return d->boundingRect.height();
2290 void QQuickTextInput::moveCursorSelection(int position)
2292 Q_D(QQuickTextInput);
2293 d->moveCursor(position, true);
2297 \qmlmethod void QtQuick2::TextInput::moveCursorSelection(int position, SelectionMode mode = TextInput.SelectCharacters)
2299 Moves the cursor to \a position and updates the selection according to the optional \a mode
2300 parameter. (To only move the cursor, set the \l cursorPosition property.)
2302 When this method is called it additionally sets either the
2303 selectionStart or the selectionEnd (whichever was at the previous cursor position)
2304 to the specified position. This allows you to easily extend and contract the selected
2307 The selection mode specifies whether the selection is updated on a per character or a per word
2308 basis. If not specified the selection mode will default to TextInput.SelectCharacters.
2311 \li TextInput.SelectCharacters - Sets either the selectionStart or selectionEnd (whichever was at
2312 the previous cursor position) to the specified position.
2313 \li TextInput.SelectWords - Sets the selectionStart and selectionEnd to include all
2314 words between the specified position and the previous cursor position. Words partially in the
2318 For example, take this sequence of calls:
2322 moveCursorSelection(9, TextInput.SelectCharacters)
2323 moveCursorSelection(7, TextInput.SelectCharacters)
2326 This moves the cursor to position 5, extend the selection end from 5 to 9
2327 and then retract the selection end from 9 to 7, leaving the text from position 5 to 7
2328 selected (the 6th and 7th characters).
2330 The same sequence with TextInput.SelectWords will extend the selection start to a word boundary
2331 before or on position 5 and extend the selection end to a word boundary on or past position 9.
2333 void QQuickTextInput::moveCursorSelection(int pos, SelectionMode mode)
2335 Q_D(QQuickTextInput);
2337 if (mode == SelectCharacters) {
2338 d->moveCursor(pos, true);
2339 } else if (pos != d->m_cursor){
2340 const int cursor = d->m_cursor;
2342 if (!d->hasSelectedText())
2343 anchor = d->m_cursor;
2344 else if (d->selectionStart() == d->m_cursor)
2345 anchor = d->selectionEnd();
2347 anchor = d->selectionStart();
2349 if (anchor < pos || (anchor == pos && cursor < pos)) {
2350 const QString text = this->text();
2351 QTextBoundaryFinder finder(QTextBoundaryFinder::Word, text);
2352 finder.setPosition(anchor);
2354 const QTextBoundaryFinder::BoundaryReasons reasons = finder.boundaryReasons();
2355 if (anchor < text.length() && (!(reasons & QTextBoundaryFinder::StartWord)
2356 || ((reasons & QTextBoundaryFinder::EndWord) && anchor > cursor))) {
2357 finder.toPreviousBoundary();
2359 anchor = finder.position() != -1 ? finder.position() : 0;
2361 finder.setPosition(pos);
2362 if (pos > 0 && !finder.boundaryReasons())
2363 finder.toNextBoundary();
2364 const int cursor = finder.position() != -1 ? finder.position() : text.length();
2366 d->setSelection(anchor, cursor - anchor);
2367 } else if (anchor > pos || (anchor == pos && cursor > pos)) {
2368 const QString text = this->text();
2369 QTextBoundaryFinder finder(QTextBoundaryFinder::Word, text);
2370 finder.setPosition(anchor);
2372 const QTextBoundaryFinder::BoundaryReasons reasons = finder.boundaryReasons();
2373 if (anchor > 0 && (!(reasons & QTextBoundaryFinder::EndWord)
2374 || ((reasons & QTextBoundaryFinder::StartWord) && anchor < cursor))) {
2375 finder.toNextBoundary();
2378 anchor = finder.position() != -1 ? finder.position() : text.length();
2380 finder.setPosition(pos);
2381 if (pos < text.length() && !finder.boundaryReasons())
2382 finder.toPreviousBoundary();
2383 const int cursor = finder.position() != -1 ? finder.position() : 0;
2385 d->setSelection(anchor, cursor - anchor);
2391 \qmlmethod void QtQuick2::TextInput::openSoftwareInputPanel()
2393 Opens software input panels like virtual keyboards for typing, useful for
2394 customizing when you want the input keyboard to be shown and hidden in
2397 By default the opening of input panels follows the platform style. Input panels are
2398 always closed if no editor has active focus.
2400 You can disable the automatic behavior by setting the property \c activeFocusOnPress to false
2401 and use functions openSoftwareInputPanel() and closeSoftwareInputPanel() to implement
2402 the behavior you want.
2404 Only relevant on platforms, which provide virtual keyboards.
2410 text: "Hello world!"
2411 activeFocusOnPress: false
2413 anchors.fill: parent
2415 if (!textInput.activeFocus) {
2416 textInput.forceActiveFocus()
2417 textInput.openSoftwareInputPanel();
2419 textInput.focus = false;
2422 onPressAndHold: textInput.closeSoftwareInputPanel();
2427 void QQuickTextInput::openSoftwareInputPanel()
2430 qGuiApp->inputMethod()->show();
2434 \qmlmethod void QtQuick2::TextInput::closeSoftwareInputPanel()
2436 Closes a software input panel like a virtual keyboard shown on the screen, useful
2437 for customizing when you want the input keyboard to be shown and hidden in
2440 By default the opening of input panels follows the platform style. Input panels are
2441 always closed if no editor has active focus.
2443 You can disable the automatic behavior by setting the property \c activeFocusOnPress to false
2444 and use functions openSoftwareInputPanel() and closeSoftwareInputPanel() to implement
2445 the behavior you want.
2447 Only relevant on platforms, which provide virtual keyboards.
2453 text: "Hello world!"
2454 activeFocusOnPress: false
2456 anchors.fill: parent
2458 if (!textInput.activeFocus) {
2459 textInput.forceActiveFocus();
2460 textInput.openSoftwareInputPanel();
2462 textInput.focus = false;
2465 onPressAndHold: textInput.closeSoftwareInputPanel();
2470 void QQuickTextInput::closeSoftwareInputPanel()
2473 qGuiApp->inputMethod()->hide();
2476 void QQuickTextInput::focusInEvent(QFocusEvent *event)
2478 Q_D(const QQuickTextInput);
2479 if (d->focusOnPress && !d->m_readOnly)
2480 openSoftwareInputPanel();
2481 QQuickImplicitSizeItem::focusInEvent(event);
2484 void QQuickTextInput::itemChange(ItemChange change, const ItemChangeData &value)
2486 Q_D(QQuickTextInput);
2487 if (change == ItemActiveFocusHasChanged) {
2488 bool hasFocus = value.boolValue;
2489 setCursorVisible(hasFocus); // ### refactor: && d->canvas && d->canvas->hasFocus()
2490 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
2491 if (!hasFocus && (d->m_passwordEchoEditing || d->m_passwordEchoTimer.isActive())) {
2493 if (!hasFocus && d->m_passwordEchoEditing) {
2495 d->updatePasswordEchoEditing(false);//QQuickTextInputPrivate sets it on key events, but doesn't deal with focus events
2500 if (!d->persistentSelection)
2502 disconnect(qApp->inputMethod(), SIGNAL(inputDirectionChanged(Qt::LayoutDirection)),
2503 this, SLOT(q_updateAlignment()));
2505 q_updateAlignment();
2506 connect(qApp->inputMethod(), SIGNAL(inputDirectionChanged(Qt::LayoutDirection)),
2507 this, SLOT(q_updateAlignment()));
2510 QQuickItem::itemChange(change, value);
2514 \qmlproperty bool QtQuick2::TextInput::inputMethodComposing
2517 This property holds whether the TextInput has partial text input from an
2520 While it is composing an input method may rely on mouse or key events from
2521 the TextInput to edit or commit the partial text. This property can be
2522 used to determine when to disable events handlers that may interfere with
2523 the correct operation of an input method.
2525 bool QQuickTextInput::isInputMethodComposing() const
2527 Q_D(const QQuickTextInput);
2528 return d->preeditAreaText().length() > 0;
2531 void QQuickTextInputPrivate::init()
2533 Q_Q(QQuickTextInput);
2534 q->setSmooth(smooth);
2535 q->setAcceptedMouseButtons(Qt::LeftButton);
2536 q->setFlag(QQuickItem::ItemAcceptsInputMethod);
2537 q->setFlag(QQuickItem::ItemHasContents);
2538 #ifndef QT_NO_CLIPBOARD
2539 q->connect(QGuiApplication::clipboard(), SIGNAL(dataChanged()),
2540 q, SLOT(q_canPasteChanged()));
2541 #endif // QT_NO_CLIPBOARD
2543 lastSelectionStart = 0;
2544 lastSelectionEnd = 0;
2545 determineHorizontalAlignment();
2547 if (!qmlDisableDistanceField()) {
2548 QTextOption option = m_textLayout.textOption();
2549 option.setUseDesignMetrics(true);
2550 m_textLayout.setTextOption(option);
2554 void QQuickTextInput::updateCursorRectangle()
2556 Q_D(QQuickTextInput);
2557 if (!isComponentComplete())
2560 d->updateHorizontalScroll();
2561 d->updateVerticalScroll();
2562 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
2564 emit cursorRectangleChanged();
2565 if (d->cursorItem) {
2566 QRectF r = cursorRectangle();
2567 d->cursorItem->setPos(r.topLeft());
2568 d->cursorItem->setHeight(r.height());
2570 updateInputMethod(Qt::ImCursorRectangle);
2573 void QQuickTextInput::selectionChanged()
2575 Q_D(QQuickTextInput);
2576 d->textLayoutDirty = true; //TODO: Only update rect in selection
2577 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
2579 emit selectedTextChanged();
2581 if (d->lastSelectionStart != d->selectionStart()) {
2582 d->lastSelectionStart = d->selectionStart();
2583 if (d->lastSelectionStart == -1)
2584 d->lastSelectionStart = d->m_cursor;
2585 emit selectionStartChanged();
2587 if (d->lastSelectionEnd != d->selectionEnd()) {
2588 d->lastSelectionEnd = d->selectionEnd();
2589 if (d->lastSelectionEnd == -1)
2590 d->lastSelectionEnd = d->m_cursor;
2591 emit selectionEndChanged();
2595 void QQuickTextInputPrivate::showCursor()
2597 if (textNode != 0 && textNode->cursorNode() != 0)
2598 textNode->cursorNode()->setColor(color);
2601 void QQuickTextInputPrivate::hideCursor()
2603 if (textNode != 0 && textNode->cursorNode() != 0)
2604 textNode->cursorNode()->setColor(QColor(0, 0, 0, 0));
2607 QRectF QQuickTextInput::boundingRect() const
2609 Q_D(const QQuickTextInput);
2611 int cursorWidth = d->cursorItem ? d->cursorItem->width() : 1;
2613 // Could include font max left/right bearings to either side of rectangle.
2614 QRectF r = QQuickImplicitSizeItem::boundingRect();
2615 r.setRight(r.right() + cursorWidth);
2619 void QQuickTextInput::q_canPasteChanged()
2621 Q_D(QQuickTextInput);
2622 bool old = d->canPaste;
2623 #ifndef QT_NO_CLIPBOARD
2624 if (const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData())
2625 d->canPaste = !d->m_readOnly && mimeData->hasText();
2627 d->canPaste = false;
2630 bool changed = d->canPaste != old || !d->canPasteValid;
2631 d->canPasteValid = true;
2633 emit canPasteChanged();
2637 void QQuickTextInput::q_updateAlignment()
2639 Q_D(QQuickTextInput);
2640 if (d->determineHorizontalAlignment()) {
2642 updateCursorRectangle();
2646 // ### these should come from QStyleHints
2647 const int textCursorWidth = 1;
2648 const bool fullWidthSelection = true;
2653 Updates the display text based of the current edit text
2654 If the text has changed will emit displayTextChanged()
2656 void QQuickTextInputPrivate::updateDisplayText(bool forceUpdate)
2658 QString orig = m_textLayout.text();
2660 if (m_echoMode == QQuickTextInput::NoEcho)
2661 str = QString::fromLatin1("");
2665 if (m_echoMode == QQuickTextInput::Password) {
2666 str.fill(m_passwordCharacter);
2667 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
2668 if (m_passwordEchoTimer.isActive() && m_cursor > 0 && m_cursor <= m_text.length()) {
2669 int cursor = m_cursor - 1;
2670 QChar uc = m_text.at(cursor);
2672 if (cursor > 0 && uc.unicode() >= 0xdc00 && uc.unicode() < 0xe000) {
2673 // second half of a surrogate, check if we have the first half as well,
2674 // if yes restore both at once
2675 uc = m_text.at(cursor - 1);
2676 if (uc.unicode() >= 0xd800 && uc.unicode() < 0xdc00)
2677 str[cursor - 1] = uc;
2681 } else if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit && !m_passwordEchoEditing) {
2682 str.fill(m_passwordCharacter);
2685 // replace certain non-printable characters with spaces (to avoid
2686 // drawing boxes when using fonts that don't have glyphs for such
2688 QChar* uc = str.data();
2689 for (int i = 0; i < (int)str.length(); ++i) {
2690 if ((uc[i] < 0x20 && uc[i] != 0x09)
2691 || uc[i] == QChar::LineSeparator
2692 || uc[i] == QChar::ParagraphSeparator
2693 || uc[i] == QChar::ObjectReplacementCharacter)
2694 uc[i] = QChar(0x0020);
2697 if (str != orig || forceUpdate) {
2698 m_textLayout.setText(str);
2699 updateLayout(); // polish?
2700 emit q_func()->displayTextChanged();
2704 qreal QQuickTextInputPrivate::getImplicitWidth() const
2706 Q_Q(const QQuickTextInput);
2707 if (!requireImplicitWidth) {
2708 QQuickTextInputPrivate *d = const_cast<QQuickTextInputPrivate *>(this);
2709 d->requireImplicitWidth = true;
2711 if (q->isComponentComplete()) {
2712 // One time cost, only incurred if implicitWidth is first requested after
2713 // componentComplete.
2714 QTextLayout layout(m_text);
2716 QTextOption option = m_textLayout.textOption();
2717 option.setTextDirection(m_layoutDirection);
2718 option.setFlags(QTextOption::IncludeTrailingSpaces);
2719 option.setWrapMode(QTextOption::WrapMode(wrapMode));
2720 option.setAlignment(Qt::Alignment(q->effectiveHAlign()));
2721 layout.setTextOption(option);
2722 layout.setFont(font);
2723 layout.setPreeditArea(m_textLayout.preeditAreaPosition(), m_textLayout.preeditAreaText());
2724 layout.beginLayout();
2726 QTextLine line = layout.createLine();
2727 line.setLineWidth(INT_MAX);
2728 d->implicitWidth = qCeil(line.naturalTextWidth());
2733 return implicitWidth;
2736 void QQuickTextInputPrivate::updateLayout()
2738 Q_Q(QQuickTextInput);
2740 if (!q->isComponentComplete())
2743 const QRectF previousRect = boundingRect;
2745 QTextOption option = m_textLayout.textOption();
2746 option.setTextDirection(layoutDirection());
2747 option.setWrapMode(QTextOption::WrapMode(wrapMode));
2748 option.setAlignment(Qt::Alignment(q->effectiveHAlign()));
2749 m_textLayout.setTextOption(option);
2750 m_textLayout.setFont(font);
2752 boundingRect = QRectF();
2753 m_textLayout.beginLayout();
2754 QTextLine line = m_textLayout.createLine();
2755 if (requireImplicitWidth) {
2756 line.setLineWidth(INT_MAX);
2757 const bool wasInLayout = inLayout;
2759 q->setImplicitWidth(qCeil(line.naturalTextWidth()));
2760 inLayout = wasInLayout;
2761 if (inLayout) // probably the result of a binding loop, but by letting it
2762 return; // get this far we'll get a warning to that effect.
2764 qreal lineWidth = q->widthValid() ? q->width() : INT_MAX;
2767 line.setLineWidth(lineWidth);
2768 line.setPosition(QPointF(line.position().x(), height));
2769 boundingRect = boundingRect.united(line.naturalTextRect());
2771 height += line.height();
2772 line = m_textLayout.createLine();
2773 } while (line.isValid());
2774 m_textLayout.endLayout();
2776 option.setWrapMode(QTextOption::NoWrap);
2777 m_textLayout.setTextOption(option);
2779 textLayoutDirty = true;
2781 updateType = UpdatePaintNode;
2784 if (!requireImplicitWidth && !q->widthValid())
2785 q->setImplicitSize(qCeil(boundingRect.width()), qCeil(boundingRect.height()));
2787 q->setImplicitHeight(qCeil(boundingRect.height()));
2789 if (previousRect != boundingRect)
2790 emit q->contentSizeChanged();
2793 #ifndef QT_NO_CLIPBOARD
2797 Copies the currently selected text into the clipboard using the given
2800 \note If the echo mode is set to a mode other than Normal then copy
2801 will not work. This is to prevent using copy as a method of bypassing
2802 password features of the line control.
2804 void QQuickTextInputPrivate::copy(QClipboard::Mode mode) const
2806 QString t = selectedText();
2807 if (!t.isEmpty() && m_echoMode == QQuickTextInput::Normal) {
2808 QGuiApplication::clipboard()->setText(t, mode);
2815 Inserts the text stored in the application clipboard into the line
2820 void QQuickTextInputPrivate::paste(QClipboard::Mode clipboardMode)
2822 QString clip = QGuiApplication::clipboard()->text(clipboardMode);
2823 if (!clip.isEmpty() || hasSelectedText()) {
2824 separate(); //make it a separate undo/redo command
2830 #endif // !QT_NO_CLIPBOARD
2835 Exits preedit mode and commits parts marked as tentative commit
2837 void QQuickTextInputPrivate::commitPreedit()
2842 qApp->inputMethod()->reset();
2844 if (!m_tentativeCommit.isEmpty()) {
2845 internalInsert(m_tentativeCommit);
2846 m_tentativeCommit.clear();
2847 finishChange(-1, true/*not used, not documented*/, false);
2850 m_preeditCursor = 0;
2851 m_textLayout.setPreeditArea(-1, QString());
2852 m_textLayout.clearAdditionalFormats();
2859 Handles the behavior for the backspace key or function.
2860 Removes the current selection if there is a selection, otherwise
2861 removes the character prior to the cursor position.
2865 void QQuickTextInputPrivate::backspace()
2867 int priorState = m_undoState;
2868 if (hasSelectedText()) {
2869 removeSelectedText();
2870 } else if (m_cursor) {
2873 m_cursor = prevMaskBlank(m_cursor);
2874 QChar uc = m_text.at(m_cursor);
2875 if (m_cursor > 0 && uc.unicode() >= 0xdc00 && uc.unicode() < 0xe000) {
2876 // second half of a surrogate, check if we have the first half as well,
2877 // if yes delete both at once
2878 uc = m_text.at(m_cursor - 1);
2879 if (uc.unicode() >= 0xd800 && uc.unicode() < 0xdc00) {
2880 internalDelete(true);
2884 internalDelete(true);
2886 finishChange(priorState);
2892 Handles the behavior for the delete key or function.
2893 Removes the current selection if there is a selection, otherwise
2894 removes the character after the cursor position.
2898 void QQuickTextInputPrivate::del()
2900 int priorState = m_undoState;
2901 if (hasSelectedText()) {
2902 removeSelectedText();
2904 int n = m_textLayout.nextCursorPosition(m_cursor) - m_cursor;
2908 finishChange(priorState);
2914 Inserts the given \a newText at the current cursor position.
2915 If there is any selected text it is removed prior to insertion of
2918 void QQuickTextInputPrivate::insert(const QString &newText)
2920 int priorState = m_undoState;
2921 removeSelectedText();
2922 internalInsert(newText);
2923 finishChange(priorState);
2929 Clears the line control text.
2931 void QQuickTextInputPrivate::clear()
2933 int priorState = m_undoState;
2935 m_selend = m_text.length();
2936 removeSelectedText();
2938 finishChange(priorState, /*update*/false, /*edited*/false);
2944 Sets \a length characters from the given \a start position as selected.
2945 The given \a start position must be within the current text for
2946 the line control. If \a length characters cannot be selected, then
2947 the selection will extend to the end of the current text.
2949 void QQuickTextInputPrivate::setSelection(int start, int length)
2951 Q_Q(QQuickTextInput);
2954 if (start < 0 || start > (int)m_text.length()){
2955 qWarning("QQuickTextInputPrivate::setSelection: Invalid start position");
2960 if (start == m_selstart && start + length == m_selend && m_cursor == m_selend)
2963 m_selend = qMin(start + length, (int)m_text.length());
2964 m_cursor = m_selend;
2965 } else if (length < 0){
2966 if (start == m_selend && start + length == m_selstart && m_cursor == m_selstart)
2968 m_selstart = qMax(start + length, 0);
2970 m_cursor = m_selstart;
2971 } else if (m_selstart != m_selend) {
2977 emitCursorPositionChanged();
2980 emit q->selectionChanged();
2981 emitCursorPositionChanged();
2982 q->updateInputMethod(Qt::ImCursorRectangle | Qt::ImAnchorPosition
2983 | Qt::ImCursorPosition | Qt::ImCurrentSelection);
2989 Sets the password echo editing to \a editing. If password echo editing
2990 is true, then the text of the password is displayed even if the echo
2991 mode is set to QLineEdit::PasswordEchoOnEdit. Password echoing editing
2992 does not affect other echo modes.
2994 void QQuickTextInputPrivate::updatePasswordEchoEditing(bool editing)
2996 cancelPasswordEchoTimer();
2997 m_passwordEchoEditing = editing;
2998 updateDisplayText();
3004 Fixes the current text so that it is valid given any set validators.
3006 Returns true if the text was changed. Otherwise returns false.
3008 bool QQuickTextInputPrivate::fixup() // this function assumes that validate currently returns != Acceptable
3010 #ifndef QT_NO_VALIDATOR
3012 QString textCopy = m_text;
3013 int cursorCopy = m_cursor;
3014 m_validator->fixup(textCopy);
3015 if (m_validator->validate(textCopy, cursorCopy) == QValidator::Acceptable) {
3016 if (textCopy != m_text || cursorCopy != m_cursor)
3017 internalSetText(textCopy, cursorCopy);
3028 Moves the cursor to the given position \a pos. If \a mark is true will
3029 adjust the currently selected text.
3031 void QQuickTextInputPrivate::moveCursor(int pos, bool mark)
3033 Q_Q(QQuickTextInput);
3036 if (pos != m_cursor) {
3039 pos = pos > m_cursor ? nextMaskBlank(pos) : prevMaskBlank(pos);
3043 if (m_selend > m_selstart && m_cursor == m_selstart)
3045 else if (m_selend > m_selstart && m_cursor == m_selend)
3046 anchor = m_selstart;
3049 m_selstart = qMin(anchor, pos);
3050 m_selend = qMax(anchor, pos);
3055 if (mark || m_selDirty) {
3057 emit q->selectionChanged();
3059 emitCursorPositionChanged();
3060 q->updateInputMethod();
3066 Applies the given input method event \a event to the text of the line
3069 void QQuickTextInputPrivate::processInputMethodEvent(QInputMethodEvent *event)
3071 Q_Q(QQuickTextInput);
3073 int priorState = -1;
3074 bool isGettingInput = !event->commitString().isEmpty()
3075 || event->preeditString() != preeditAreaText()
3076 || event->replacementLength() > 0;
3077 bool cursorPositionChanged = false;
3078 bool selectionChange = false;
3079 m_preeditDirty = event->preeditString() != preeditAreaText();
3081 if (isGettingInput) {
3082 // If any text is being input, remove selected text.
3083 priorState = m_undoState;
3084 if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit && !m_passwordEchoEditing) {
3085 updatePasswordEchoEditing(true);
3087 m_selend = m_text.length();
3089 removeSelectedText();
3092 int c = m_cursor; // cursor position after insertion of commit string
3093 if (event->replacementStart() <= 0)
3094 c += event->commitString().length() - qMin(-event->replacementStart(), event->replacementLength());
3096 m_cursor += event->replacementStart();
3100 // insert commit string
3101 if (event->replacementLength()) {
3102 m_selstart = m_cursor;
3103 m_selend = m_selstart + event->replacementLength();
3104 m_selend = qMin(m_selend, m_text.length());
3105 removeSelectedText();
3107 if (!event->commitString().isEmpty()) {
3108 internalInsert(event->commitString());
3109 cursorPositionChanged = true;
3112 m_cursor = qBound(0, c, m_text.length());
3114 for (int i = 0; i < event->attributes().size(); ++i) {
3115 const QInputMethodEvent::Attribute &a = event->attributes().at(i);
3116 if (a.type == QInputMethodEvent::Selection) {
3117 m_cursor = qBound(0, a.start + a.length, m_text.length());
3119 m_selstart = qMax(0, qMin(a.start, m_text.length()));
3120 m_selend = m_cursor;
3121 if (m_selend < m_selstart) {
3122 qSwap(m_selstart, m_selend);
3124 selectionChange = true;
3126 m_selstart = m_selend = 0;
3128 cursorPositionChanged = true;
3132 m_textLayout.setPreeditArea(m_cursor, event->preeditString());
3134 const int oldPreeditCursor = m_preeditCursor;
3135 m_preeditCursor = event->preeditString().length();
3136 m_hideCursor = false;
3137 QList<QTextLayout::FormatRange> formats;
3138 for (int i = 0; i < event->attributes().size(); ++i) {
3139 const QInputMethodEvent::Attribute &a = event->attributes().at(i);
3140 if (a.type == QInputMethodEvent::Cursor) {
3141 m_preeditCursor = a.start;
3142 m_hideCursor = !a.length;
3143 } else if (a.type == QInputMethodEvent::TextFormat) {
3144 QTextCharFormat f = qvariant_cast<QTextFormat>(a.value).toCharFormat();
3146 QTextLayout::FormatRange o;
3147 o.start = a.start + m_cursor;
3148 o.length = a.length;
3154 m_textLayout.setAdditionalFormats(formats);
3156 updateDisplayText(/*force*/ true);
3157 if (cursorPositionChanged) {
3158 emitCursorPositionChanged();
3159 } else if (m_preeditCursor != oldPreeditCursor) {
3160 q->updateCursorRectangle();
3163 bool tentativeCommitChanged = m_tentativeCommit != event->tentativeCommitString();
3165 if (tentativeCommitChanged) {
3167 m_tentativeCommit = event->tentativeCommitString();
3170 if (isGettingInput || tentativeCommitChanged)
3171 finishChange(priorState);
3173 if (selectionChange) {
3174 emit q->selectionChanged();
3175 q->updateInputMethod(Qt::ImCursorRectangle | Qt::ImAnchorPosition
3176 | Qt::ImCursorPosition | Qt::ImCurrentSelection);
3183 Sets the selection to cover the word at the given cursor position.
3184 The word boundaries are defined by the behavior of QTextLayout::SkipWords
3187 void QQuickTextInputPrivate::selectWordAtPos(int cursor)
3189 int next = cursor + 1;
3192 int c = m_textLayout.previousCursorPosition(next, QTextLayout::SkipWords);
3193 moveCursor(c, false);
3194 // ## text layout should support end of words.
3195 int end = m_textLayout.nextCursorPosition(c, QTextLayout::SkipWords);
3196 while (end > cursor && m_text[end-1].isSpace())
3198 moveCursor(end, true);
3204 Completes a change to the line control text. If the change is not valid
3205 will undo the line control state back to the given \a validateFromState.
3207 If \a edited is true and the change is valid, will emit textEdited() in
3208 addition to textChanged(). Otherwise only emits textChanged() on a valid
3211 The \a update value is currently unused.
3213 bool QQuickTextInputPrivate::finishChange(int validateFromState, bool update, bool /*edited*/)
3215 Q_Q(QQuickTextInput);
3218 bool inputMethodAttributesChanged = m_textDirty || m_selDirty;
3219 bool alignmentChanged = false;
3223 bool wasValidInput = m_validInput;
3224 bool wasAcceptable = m_acceptableInput;
3225 m_validInput = true;
3226 m_acceptableInput = true;
3227 #ifndef QT_NO_VALIDATOR
3229 QString textCopy = m_text;
3230 int cursorCopy = m_cursor;
3231 QValidator::State state = m_validator->validate(textCopy, cursorCopy);
3232 m_validInput = state != QValidator::Invalid;
3233 m_acceptableInput = state == QValidator::Acceptable;
3235 if (m_text != textCopy) {
3236 internalSetText(textCopy, cursorCopy);
3239 m_cursor = cursorCopy;
3241 if (!m_tentativeCommit.isEmpty()) {
3242 textCopy.insert(m_cursor, m_tentativeCommit);
3243 bool validInput = m_validator->validate(textCopy, cursorCopy) != QValidator::Invalid;
3245 m_tentativeCommit.clear();
3248 m_tentativeCommit.clear();
3252 if (validateFromState >= 0 && wasValidInput && !m_validInput) {
3253 if (m_transactions.count())
3255 internalUndo(validateFromState);
3256 m_history.resize(m_undoState);
3257 m_validInput = true;
3258 m_acceptableInput = wasAcceptable;
3259 m_textDirty = false;
3263 m_textDirty = false;
3264 m_preeditDirty = false;
3265 alignmentChanged = determineHorizontalAlignment();
3266 emit q->textChanged();
3269 updateDisplayText(alignmentChanged);
3271 if (m_acceptableInput != wasAcceptable)
3272 emit q->acceptableInputChanged();
3274 if (m_preeditDirty) {
3275 m_preeditDirty = false;
3276 if (determineHorizontalAlignment()) {
3277 alignmentChanged = true;
3284 emit q->selectionChanged();
3287 inputMethodAttributesChanged |= (m_cursor == m_lastCursorPos);
3288 if (inputMethodAttributesChanged)
3289 q->updateInputMethod();
3290 emitUndoRedoChanged();
3292 if (!emitCursorPositionChanged() && alignmentChanged)
3293 q->updateCursorRectangle();
3301 An internal function for setting the text of the line control.
3303 void QQuickTextInputPrivate::internalSetText(const QString &txt, int pos, bool edited)
3305 Q_Q(QQuickTextInput);
3307 QString oldText = m_text;
3309 m_text = maskString(0, txt, true);
3310 m_text += clearString(m_text.length(), m_maxLength - m_text.length());
3312 m_text = txt.isEmpty() ? txt : txt.left(m_maxLength);
3316 m_cursor = (pos < 0 || pos > m_text.length()) ? m_text.length() : pos;
3317 m_textDirty = (oldText != m_text);
3319 bool changed = finishChange(-1, true, edited);
3320 #ifdef QT_NO_ACCESSIBILITY
3324 QAccessibleTextUpdateEvent ev(q, 0, oldText, m_text);
3325 QAccessible::updateAccessibility(&ev);
3334 Adds the given \a command to the undo history
3335 of the line control. Does not apply the command.
3337 void QQuickTextInputPrivate::addCommand(const Command &cmd)
3339 if (m_separator && m_undoState && m_history[m_undoState - 1].type != Separator) {
3340 m_history.resize(m_undoState + 2);
3341 m_history[m_undoState++] = Command(Separator, m_cursor, 0, m_selstart, m_selend);
3343 m_history.resize(m_undoState + 1);
3345 m_separator = false;
3346 m_history[m_undoState++] = cmd;
3352 Inserts the given string \a s into the line
3355 Also adds the appropriate commands into the undo history.
3356 This function does not call finishChange(), and may leave the text
3357 in an invalid state.
3359 void QQuickTextInputPrivate::internalInsert(const QString &s)
3361 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
3362 Q_Q(QQuickTextInput);
3363 if (m_echoMode == QQuickTextInput::Password)
3364 m_passwordEchoTimer.start(qt_passwordEchoDelay, q);
3366 if (hasSelectedText())
3367 addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
3369 QString ms = maskString(m_cursor, s);
3370 for (int i = 0; i < (int) ms.length(); ++i) {
3371 addCommand (Command(DeleteSelection, m_cursor + i, m_text.at(m_cursor + i), -1, -1));
3372 addCommand(Command(Insert, m_cursor + i, ms.at(i), -1, -1));
3374 m_text.replace(m_cursor, ms.length(), ms);
3375 m_cursor += ms.length();
3376 m_cursor = nextMaskBlank(m_cursor);
3379 int remaining = m_maxLength - m_text.length();
3380 if (remaining != 0) {
3381 m_text.insert(m_cursor, s.left(remaining));
3382 for (int i = 0; i < (int) s.left(remaining).length(); ++i)
3383 addCommand(Command(Insert, m_cursor++, s.at(i), -1, -1));
3392 deletes a single character from the current text. If \a wasBackspace,
3393 the character prior to the cursor is removed. Otherwise the character
3394 after the cursor is removed.
3396 Also adds the appropriate commands into the undo history.
3397 This function does not call finishChange(), and may leave the text
3398 in an invalid state.
3400 void QQuickTextInputPrivate::internalDelete(bool wasBackspace)
3402 if (m_cursor < (int) m_text.length()) {
3403 cancelPasswordEchoTimer();
3404 if (hasSelectedText())
3405 addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
3406 addCommand(Command((CommandType)((m_maskData ? 2 : 0) + (wasBackspace ? Remove : Delete)),
3407 m_cursor, m_text.at(m_cursor), -1, -1));
3409 m_text.replace(m_cursor, 1, clearString(m_cursor, 1));
3410 addCommand(Command(Insert, m_cursor, m_text.at(m_cursor), -1, -1));
3412 m_text.remove(m_cursor, 1);
3421 removes the currently selected text from the line control.
3423 Also adds the appropriate commands into the undo history.
3424 This function does not call finishChange(), and may leave the text
3425 in an invalid state.
3427 void QQuickTextInputPrivate::removeSelectedText()
3429 if (m_selstart < m_selend && m_selend <= (int) m_text.length()) {
3430 cancelPasswordEchoTimer();
3433 addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
3434 if (m_selstart <= m_cursor && m_cursor < m_selend) {
3435 // cursor is within the selection. Split up the commands
3436 // to be able to restore the correct cursor position
3437 for (i = m_cursor; i >= m_selstart; --i)
3438 addCommand (Command(DeleteSelection, i, m_text.at(i), -1, 1));
3439 for (i = m_selend - 1; i > m_cursor; --i)
3440 addCommand (Command(DeleteSelection, i - m_cursor + m_selstart - 1, m_text.at(i), -1, -1));
3442 for (i = m_selend-1; i >= m_selstart; --i)
3443 addCommand (Command(RemoveSelection, i, m_text.at(i), -1, -1));
3446 m_text.replace(m_selstart, m_selend - m_selstart, clearString(m_selstart, m_selend - m_selstart));
3447 for (int i = 0; i < m_selend - m_selstart; ++i)
3448 addCommand(Command(Insert, m_selstart + i, m_text.at(m_selstart + i), -1, -1));
3450 m_text.remove(m_selstart, m_selend - m_selstart);
3452 if (m_cursor > m_selstart)
3453 m_cursor -= qMin(m_cursor, m_selend) - m_selstart;
3462 Parses the input mask specified by \a maskFields to generate
3463 the mask data used to handle input masks.
3465 void QQuickTextInputPrivate::parseInputMask(const QString &maskFields)
3467 int delimiter = maskFields.indexOf(QLatin1Char(';'));
3468 if (maskFields.isEmpty() || delimiter == 0) {
3470 delete [] m_maskData;
3472 m_maxLength = 32767;
3473 internalSetText(QString());
3478 if (delimiter == -1) {
3479 m_blank = QLatin1Char(' ');
3480 m_inputMask = maskFields;
3482 m_inputMask = maskFields.left(delimiter);
3483 m_blank = (delimiter + 1 < maskFields.length()) ? maskFields[delimiter + 1] : QLatin1Char(' ');
3486 // calculate m_maxLength / m_maskData length
3489 for (int i=0; i<m_inputMask.length(); i++) {
3490 c = m_inputMask.at(i);
3491 if (i > 0 && m_inputMask.at(i-1) == QLatin1Char('\\')) {
3495 if (c != QLatin1Char('\\') && c != QLatin1Char('!') &&
3496 c != QLatin1Char('<') && c != QLatin1Char('>') &&
3497 c != QLatin1Char('{') && c != QLatin1Char('}') &&
3498 c != QLatin1Char('[') && c != QLatin1Char(']'))
3502 delete [] m_maskData;
3503 m_maskData = new MaskInputData[m_maxLength];
3505 MaskInputData::Casemode m = MaskInputData::NoCaseMode;
3508 bool escape = false;
3510 for (int i = 0; i < m_inputMask.length(); i++) {
3511 c = m_inputMask.at(i);
3514 m_maskData[index].maskChar = c;
3515 m_maskData[index].separator = s;
3516 m_maskData[index].caseMode = m;
3519 } else if (c == QLatin1Char('<')) {
3520 m = MaskInputData::Lower;
3521 } else if (c == QLatin1Char('>')) {
3522 m = MaskInputData::Upper;
3523 } else if (c == QLatin1Char('!')) {
3524 m = MaskInputData::NoCaseMode;
3525 } else if (c != QLatin1Char('{') && c != QLatin1Char('}') && c != QLatin1Char('[') && c != QLatin1Char(']')) {
3526 switch (c.unicode()) {
3552 m_maskData[index].maskChar = c;
3553 m_maskData[index].separator = s;
3554 m_maskData[index].caseMode = m;
3559 internalSetText(m_text);
3566 checks if the key is valid compared to the inputMask
3568 bool QQuickTextInputPrivate::isValidInput(QChar key, QChar mask) const
3570 switch (mask.unicode()) {
3576 if (key.isLetter() || key == m_blank)
3580 if (key.isLetterOrNumber())
3584 if (key.isLetterOrNumber() || key == m_blank)
3592 if (key.isPrint() || key == m_blank)
3600 if (key.isNumber() || key == m_blank)
3604 if (key.isNumber() && key.digitValue() > 0)
3608 if ((key.isNumber() && key.digitValue() > 0) || key == m_blank)
3612 if (key.isNumber() || key == QLatin1Char('+') || key == QLatin1Char('-') || key == m_blank)
3616 if (key == QLatin1Char('0') || key == QLatin1Char('1'))
3620 if (key == QLatin1Char('0') || key == QLatin1Char('1') || key == m_blank)
3624 if (key.isNumber() || (key >= QLatin1Char('a') && key <= QLatin1Char('f')) || (key >= QLatin1Char('A') && key <= QLatin1Char('F')))
3628 if (key.isNumber() || (key >= QLatin1Char('a') && key <= QLatin1Char('f')) || (key >= QLatin1Char('A') && key <= QLatin1Char('F')) || key == m_blank)
3640 Returns true if the given text \a str is valid for any
3641 validator or input mask set for the line control.
3643 Otherwise returns false
3645 QQuickTextInputPrivate::ValidatorState QQuickTextInputPrivate::hasAcceptableInput(const QString &str) const
3647 #ifndef QT_NO_VALIDATOR
3648 QString textCopy = str;
3649 int cursorCopy = m_cursor;
3651 QValidator::State state = m_validator->validate(textCopy, cursorCopy);
3652 if (state != QValidator::Acceptable)
3653 return ValidatorState(state);
3658 return AcceptableInput;
3660 if (str.length() != m_maxLength)
3661 return InvalidInput;
3663 for (int i=0; i < m_maxLength; ++i) {
3664 if (m_maskData[i].separator) {
3665 if (str.at(i) != m_maskData[i].maskChar)
3666 return InvalidInput;
3668 if (!isValidInput(str.at(i), m_maskData[i].maskChar))
3669 return InvalidInput;
3672 return AcceptableInput;
3678 Applies the inputMask on \a str starting from position \a pos in the mask. \a clear
3679 specifies from where characters should be gotten when a separator is met in \a str - true means
3680 that blanks will be used, false that previous input is used.
3681 Calling this when no inputMask is set is undefined.
3683 QString QQuickTextInputPrivate::maskString(uint pos, const QString &str, bool clear) const
3685 if (pos >= (uint)m_maxLength)
3686 return QString::fromLatin1("");
3689 fill = clear ? clearString(0, m_maxLength) : m_text;
3692 QString s = QString::fromLatin1("");
3694 while (i < m_maxLength) {
3695 if (strIndex < str.length()) {
3696 if (m_maskData[i].separator) {
3697 s += m_maskData[i].maskChar;
3698 if (str[(int)strIndex] == m_maskData[i].maskChar)
3702 if (isValidInput(str[(int)strIndex], m_maskData[i].maskChar)) {
3703 switch (m_maskData[i].caseMode) {
3704 case MaskInputData::Upper:
3705 s += str[(int)strIndex].toUpper();
3707 case MaskInputData::Lower:
3708 s += str[(int)strIndex].toLower();
3711 s += str[(int)strIndex];
3715 // search for separator first
3716 int n = findInMask(i, true, true, str[(int)strIndex]);
3718 if (str.length() != 1 || i == 0 || (i > 0 && (!m_maskData[i-1].separator || m_maskData[i-1].maskChar != str[(int)strIndex]))) {
3719 s += fill.mid(i, n-i+1);
3720 i = n + 1; // update i to find + 1
3723 // search for valid m_blank if not
3724 n = findInMask(i, true, false, str[(int)strIndex]);
3726 s += fill.mid(i, n-i);
3727 switch (m_maskData[n].caseMode) {
3728 case MaskInputData::Upper:
3729 s += str[(int)strIndex].toUpper();
3731 case MaskInputData::Lower:
3732 s += str[(int)strIndex].toLower();
3735 s += str[(int)strIndex];
3737 i = n + 1; // updates i to find + 1
3755 Returns a "cleared" string with only separators and blank chars.
3756 Calling this when no inputMask is set is undefined.
3758 QString QQuickTextInputPrivate::clearString(uint pos, uint len) const
3760 if (pos >= (uint)m_maxLength)
3764 int end = qMin((uint)m_maxLength, pos + len);
3765 for (int i = pos; i < end; ++i)
3766 if (m_maskData[i].separator)
3767 s += m_maskData[i].maskChar;
3777 Strips blank parts of the input in a QQuickTextInputPrivate when an inputMask is set,
3778 separators are still included. Typically "127.0__.0__.1__" becomes "127.0.0.1".
3780 QString QQuickTextInputPrivate::stripString(const QString &str) const
3786 int end = qMin(m_maxLength, (int)str.length());
3787 for (int i = 0; i < end; ++i) {
3788 if (m_maskData[i].separator)
3789 s += m_maskData[i].maskChar;
3790 else if (str[i] != m_blank)
3799 searches forward/backward in m_maskData for either a separator or a m_blank
3801 int QQuickTextInputPrivate::findInMask(int pos, bool forward, bool findSeparator, QChar searchChar) const
3803 if (pos >= m_maxLength || pos < 0)
3806 int end = forward ? m_maxLength : -1;
3807 int step = forward ? 1 : -1;
3811 if (findSeparator) {
3812 if (m_maskData[i].separator && m_maskData[i].maskChar == searchChar)
3815 if (!m_maskData[i].separator) {
3816 if (searchChar.isNull())
3818 else if (isValidInput(searchChar, m_maskData[i].maskChar))
3827 void QQuickTextInputPrivate::internalUndo(int until)
3829 if (!isUndoAvailable())
3831 cancelPasswordEchoTimer();
3833 while (m_undoState && m_undoState > until) {
3834 Command& cmd = m_history[--m_undoState];
3837 m_text.remove(cmd.pos, 1);
3841 m_selstart = cmd.selStart;
3842 m_selend = cmd.selEnd;
3846 case RemoveSelection:
3847 m_text.insert(cmd.pos, cmd.uc);
3848 m_cursor = cmd.pos + 1;
3851 case DeleteSelection:
3852 m_text.insert(cmd.pos, cmd.uc);
3858 if (until < 0 && m_undoState) {
3859 Command& next = m_history[m_undoState-1];
3860 if (next.type != cmd.type && next.type < RemoveSelection
3861 && (cmd.type < RemoveSelection || next.type == Separator))
3868 void QQuickTextInputPrivate::internalRedo()
3870 if (!isRedoAvailable())
3873 while (m_undoState < (int)m_history.size()) {
3874 Command& cmd = m_history[m_undoState++];
3877 m_text.insert(cmd.pos, cmd.uc);
3878 m_cursor = cmd.pos + 1;
3881 m_selstart = cmd.selStart;
3882 m_selend = cmd.selEnd;
3887 case RemoveSelection:
3888 case DeleteSelection:
3889 m_text.remove(cmd.pos, 1);
3890 m_selstart = cmd.selStart;
3891 m_selend = cmd.selEnd;
3895 m_selstart = cmd.selStart;
3896 m_selend = cmd.selEnd;
3900 if (m_undoState < (int)m_history.size()) {
3901 Command& next = m_history[m_undoState];
3902 if (next.type != cmd.type && cmd.type < RemoveSelection && next.type != Separator
3903 && (next.type < RemoveSelection || cmd.type == Separator))
3910 void QQuickTextInputPrivate::emitUndoRedoChanged()
3912 Q_Q(QQuickTextInput);
3913 const bool previousUndo = canUndo;
3914 const bool previousRedo = canRedo;
3916 canUndo = isUndoAvailable();
3917 canRedo = isRedoAvailable();
3919 if (previousUndo != canUndo)
3920 emit q->canUndoChanged();
3921 if (previousRedo != canRedo)
3922 emit q->canRedoChanged();
3928 If the current cursor position differs from the last emitted cursor
3929 position, emits cursorPositionChanged().
3931 bool QQuickTextInputPrivate::emitCursorPositionChanged()
3933 Q_Q(QQuickTextInput);
3934 if (m_cursor != m_lastCursorPos) {
3935 m_lastCursorPos = m_cursor;
3937 q->updateCursorRectangle();
3938 emit q->cursorPositionChanged();
3940 if (!hasSelectedText()) {
3941 if (lastSelectionStart != m_cursor) {
3942 lastSelectionStart = m_cursor;
3943 emit q->selectionStartChanged();
3945 if (lastSelectionEnd != m_cursor) {
3946 lastSelectionEnd = m_cursor;
3947 emit q->selectionEndChanged();
3951 #ifndef QT_NO_ACCESSIBILITY
3952 QAccessibleTextCursorEvent ev(q, m_cursor);
3953 QAccessible::updateAccessibility(&ev);
3962 void QQuickTextInputPrivate::setCursorBlinkPeriod(int msec)
3964 Q_Q(QQuickTextInput);
3965 if (msec == m_blinkPeriod)
3968 q->killTimer(m_blinkTimer);
3971 m_blinkTimer = q->startTimer(msec / 2);
3975 if (m_blinkStatus == 1) {
3976 updateType = UpdatePaintNode;
3980 m_blinkPeriod = msec;
3983 void QQuickTextInput::timerEvent(QTimerEvent *event)
3985 Q_D(QQuickTextInput);
3986 if (event->timerId() == d->m_blinkTimer) {
3987 d->m_blinkStatus = !d->m_blinkStatus;
3988 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
3990 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
3991 } else if (event->timerId() == d->m_passwordEchoTimer.timerId()) {
3992 d->m_passwordEchoTimer.stop();
3993 d->updateDisplayText();
3998 void QQuickTextInputPrivate::processKeyEvent(QKeyEvent* event)
4000 Q_Q(QQuickTextInput);
4001 bool inlineCompletionAccepted = false;
4003 if (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return) {
4004 if (hasAcceptableInput(m_text) || fixup()) {
4007 if (inlineCompletionAccepted)
4014 if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit
4015 && !m_passwordEchoEditing
4017 && !event->text().isEmpty()
4018 && !(event->modifiers() & Qt::ControlModifier)) {
4019 // Clear the edit and reset to normal echo mode while editing; the
4020 // echo mode switches back when the edit loses focus
4021 // ### resets current content. dubious code; you can
4022 // navigate with keys up, down, back, and select(?), but if you press
4023 // "left" or "right" it clears?
4024 updatePasswordEchoEditing(true);
4028 bool unknown = false;
4029 bool visual = cursorMoveStyle() == Qt::VisualMoveStyle;
4033 #ifndef QT_NO_SHORTCUT
4034 else if (event == QKeySequence::Undo) {
4037 else if (event == QKeySequence::Redo) {
4040 else if (event == QKeySequence::SelectAll) {
4043 #ifndef QT_NO_CLIPBOARD
4044 else if (event == QKeySequence::Copy) {
4047 else if (event == QKeySequence::Paste) {
4049 QClipboard::Mode mode = QClipboard::Clipboard;
4053 else if (event == QKeySequence::Cut) {
4059 else if (event == QKeySequence::DeleteEndOfLine) {
4061 setSelection(m_cursor, end());
4066 #endif //QT_NO_CLIPBOARD
4067 else if (event == QKeySequence::MoveToStartOfLine || event == QKeySequence::MoveToStartOfBlock) {
4070 else if (event == QKeySequence::MoveToEndOfLine || event == QKeySequence::MoveToEndOfBlock) {
4073 else if (event == QKeySequence::SelectStartOfLine || event == QKeySequence::SelectStartOfBlock) {
4076 else if (event == QKeySequence::SelectEndOfLine || event == QKeySequence::SelectEndOfBlock) {
4079 else if (event == QKeySequence::MoveToNextChar) {
4080 if (hasSelectedText()) {
4081 moveCursor(selectionEnd(), false);
4083 cursorForward(0, visual ? 1 : (layoutDirection() == Qt::LeftToRight ? 1 : -1));
4086 else if (event == QKeySequence::SelectNextChar) {
4087 cursorForward(1, visual ? 1 : (layoutDirection() == Qt::LeftToRight ? 1 : -1));
4089 else if (event == QKeySequence::MoveToPreviousChar) {
4090 if (hasSelectedText()) {
4091 moveCursor(selectionStart(), false);
4093 cursorForward(0, visual ? -1 : (layoutDirection() == Qt::LeftToRight ? -1 : 1));
4096 else if (event == QKeySequence::SelectPreviousChar) {
4097 cursorForward(1, visual ? -1 : (layoutDirection() == Qt::LeftToRight ? -1 : 1));
4099 else if (event == QKeySequence::MoveToNextWord) {
4100 if (m_echoMode == QQuickTextInput::Normal)
4101 layoutDirection() == Qt::LeftToRight ? cursorWordForward(0) : cursorWordBackward(0);
4103 layoutDirection() == Qt::LeftToRight ? end(0) : home(0);
4105 else if (event == QKeySequence::MoveToPreviousWord) {
4106 if (m_echoMode == QQuickTextInput::Normal)
4107 layoutDirection() == Qt::LeftToRight ? cursorWordBackward(0) : cursorWordForward(0);
4108 else if (!m_readOnly) {
4109 layoutDirection() == Qt::LeftToRight ? home(0) : end(0);
4112 else if (event == QKeySequence::SelectNextWord) {
4113 if (m_echoMode == QQuickTextInput::Normal)
4114 layoutDirection() == Qt::LeftToRight ? cursorWordForward(1) : cursorWordBackward(1);
4116 layoutDirection() == Qt::LeftToRight ? end(1) : home(1);
4118 else if (event == QKeySequence::SelectPreviousWord) {
4119 if (m_echoMode == QQuickTextInput::Normal)
4120 layoutDirection() == Qt::LeftToRight ? cursorWordBackward(1) : cursorWordForward(1);
4122 layoutDirection() == Qt::LeftToRight ? home(1) : end(1);
4124 else if (event == QKeySequence::Delete) {
4128 else if (event == QKeySequence::DeleteEndOfWord) {
4130 cursorWordForward(true);
4134 else if (event == QKeySequence::DeleteStartOfWord) {
4136 cursorWordBackward(true);
4140 #endif // QT_NO_SHORTCUT
4142 bool handled = false;
4143 if (event->modifiers() & Qt::ControlModifier) {
4144 switch (event->key()) {
4145 case Qt::Key_Backspace:
4147 cursorWordBackward(true);
4155 } else { // ### check for *no* modifier
4156 switch (event->key()) {
4157 case Qt::Key_Backspace:
4169 if (event->key() == Qt::Key_Direction_L || event->key() == Qt::Key_Direction_R) {
4170 setLayoutDirection((event->key() == Qt::Key_Direction_L) ? Qt::LeftToRight : Qt::RightToLeft);
4174 if (unknown && !m_readOnly) {
4175 QString t = event->text();
4176 if (!t.isEmpty() && t.at(0).isPrint()) {