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 QtDeclarative 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/qdeclarativeglobal_p.h>
48 #include <QtDeclarative/qdeclarativeinfo.h>
49 #include <QtGui/qevent.h>
50 #include <QTextBoundaryFinder>
51 #include "qquicktextnode_p.h"
52 #include <QtQuick/qsgsimplerectnode.h>
54 #include <QtGui/qstylehints.h>
55 #include <QtGui/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 \o 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 \o Font.MixedCase - This is the normal text rendering option where no capitalization change is applied.
275 \o Font.AllUppercase - This alters the text to be rendered in all uppercase type.
276 \o Font.AllLowercase - This alters the text to be rendered in all lowercase type.
277 \o Font.SmallCaps - This alters the text to be rendered in small-caps type.
278 \o 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;
333 emit colorChanged(c);
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 d->m_palette.setColor(QPalette::Highlight, d->selectionColor);
357 if (d->hasSelectedText()) {
358 d->textLayoutDirty = true;
359 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
362 emit selectionColorChanged(color);
365 \qmlproperty color QtQuick2::TextInput::selectedTextColor
367 The highlighted text color, used in selections.
369 QColor QQuickTextInput::selectedTextColor() const
371 Q_D(const QQuickTextInput);
372 return d->selectedTextColor;
375 void QQuickTextInput::setSelectedTextColor(const QColor &color)
377 Q_D(QQuickTextInput);
378 if (d->selectedTextColor == color)
381 d->selectedTextColor = color;
382 d->m_palette.setColor(QPalette::HighlightedText, d->selectedTextColor);
383 if (d->hasSelectedText()) {
384 d->textLayoutDirty = true;
385 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
388 emit selectedTextColorChanged(color);
392 \qmlproperty enumeration QtQuick2::TextInput::horizontalAlignment
393 \qmlproperty enumeration QtQuick2::TextInput::effectiveHorizontalAlignment
394 \qmlproperty enumeration QtQuick2::TextInput::verticalAlignment
396 Sets the horizontal alignment of the text within the TextInput item's
397 width and height. By default, the text alignment follows the natural alignment
398 of the text, for example text that is read from left to right will be aligned to
401 TextInput does not have vertical alignment, as the natural height is
402 exactly the height of the single line of text. If you set the height
403 manually to something larger, TextInput will always be top aligned
404 vertically. You can use anchors to align it however you want within
407 The valid values for \c horizontalAlignment are \c TextInput.AlignLeft, \c TextInput.AlignRight and
408 \c TextInput.AlignHCenter.
410 Valid values for \c verticalAlignment are \c TextInput.AlignTop (default),
411 \c TextInput.AlignBottom \c TextInput.AlignVCenter.
413 When using the attached property LayoutMirroring::enabled to mirror application
414 layouts, the horizontal alignment of text will also be mirrored. However, the property
415 \c horizontalAlignment will remain unchanged. To query the effective horizontal alignment
416 of TextInput, use the read-only property \c effectiveHorizontalAlignment.
418 QQuickTextInput::HAlignment QQuickTextInput::hAlign() const
420 Q_D(const QQuickTextInput);
424 void QQuickTextInput::setHAlign(HAlignment align)
426 Q_D(QQuickTextInput);
427 bool forceAlign = d->hAlignImplicit && d->effectiveLayoutMirror;
428 d->hAlignImplicit = false;
429 if (d->setHAlign(align, forceAlign) && isComponentComplete()) {
431 updateCursorRectangle();
435 void QQuickTextInput::resetHAlign()
437 Q_D(QQuickTextInput);
438 d->hAlignImplicit = true;
439 if (d->determineHorizontalAlignment() && isComponentComplete()) {
441 updateCursorRectangle();
445 QQuickTextInput::HAlignment QQuickTextInput::effectiveHAlign() const
447 Q_D(const QQuickTextInput);
448 QQuickTextInput::HAlignment effectiveAlignment = d->hAlign;
449 if (!d->hAlignImplicit && d->effectiveLayoutMirror) {
451 case QQuickTextInput::AlignLeft:
452 effectiveAlignment = QQuickTextInput::AlignRight;
454 case QQuickTextInput::AlignRight:
455 effectiveAlignment = QQuickTextInput::AlignLeft;
461 return effectiveAlignment;
464 bool QQuickTextInputPrivate::setHAlign(QQuickTextInput::HAlignment alignment, bool forceAlign)
466 Q_Q(QQuickTextInput);
467 if ((hAlign != alignment || forceAlign) && alignment <= QQuickTextInput::AlignHCenter) { // justify not supported
468 QQuickTextInput::HAlignment oldEffectiveHAlign = q->effectiveHAlign();
470 emit q->horizontalAlignmentChanged(alignment);
471 if (oldEffectiveHAlign != q->effectiveHAlign())
472 emit q->effectiveHorizontalAlignmentChanged();
478 bool QQuickTextInputPrivate::determineHorizontalAlignment()
480 if (hAlignImplicit) {
481 // if no explicit alignment has been set, follow the natural layout direction of the text
482 QString text = q_func()->text();
484 text = m_textLayout.preeditAreaText();
485 bool isRightToLeft = text.isEmpty() ? qApp->inputMethod()->inputDirection() == Qt::RightToLeft
486 : text.isRightToLeft();
487 return setHAlign(isRightToLeft ? QQuickTextInput::AlignRight : QQuickTextInput::AlignLeft);
492 QQuickTextInput::VAlignment QQuickTextInput::vAlign() const
494 Q_D(const QQuickTextInput);
498 void QQuickTextInput::setVAlign(QQuickTextInput::VAlignment alignment)
500 Q_D(QQuickTextInput);
501 if (alignment == d->vAlign)
503 d->vAlign = alignment;
504 emit verticalAlignmentChanged(d->vAlign);
505 if (isComponentComplete()) {
506 updateCursorRectangle();
511 \qmlproperty enumeration QtQuick2::TextInput::wrapMode
513 Set this property to wrap the text to the TextInput item's width.
514 The text will only wrap if an explicit width has been set.
517 \o TextInput.NoWrap - no wrapping will be performed. If the text contains insufficient newlines, then implicitWidth will exceed a set width.
518 \o TextInput.WordWrap - wrapping is done on word boundaries only. If a word is too long, implicitWidth will exceed a set width.
519 \o TextInput.WrapAnywhere - wrapping is done at any point on a line, even if it occurs in the middle of a word.
520 \o TextInput.Wrap - if possible, wrapping occurs at a word boundary; otherwise it will occur at the appropriate point on the line, even in the middle of a word.
523 The default is TextInput.NoWrap. If you set a width, consider using TextInput.Wrap.
525 QQuickTextInput::WrapMode QQuickTextInput::wrapMode() const
527 Q_D(const QQuickTextInput);
531 void QQuickTextInput::setWrapMode(WrapMode mode)
533 Q_D(QQuickTextInput);
534 if (mode == d->wrapMode)
538 updateCursorRectangle();
539 emit wrapModeChanged();
542 void QQuickTextInputPrivate::mirrorChange()
544 Q_Q(QQuickTextInput);
545 if (q->isComponentComplete()) {
546 if (!hAlignImplicit && (hAlign == QQuickTextInput::AlignRight || hAlign == QQuickTextInput::AlignLeft)) {
547 q->updateCursorRectangle();
548 emit q->effectiveHorizontalAlignmentChanged();
554 \qmlproperty bool QtQuick2::TextInput::readOnly
556 Sets whether user input can modify the contents of the TextInput.
558 If readOnly is set to true, then user input will not affect the text
559 property. Any bindings or attempts to set the text property will still
562 bool QQuickTextInput::isReadOnly() const
564 Q_D(const QQuickTextInput);
565 return d->m_readOnly;
568 void QQuickTextInput::setReadOnly(bool ro)
570 Q_D(QQuickTextInput);
571 if (d->m_readOnly == ro)
574 setFlag(QQuickItem::ItemAcceptsInputMethod, !ro);
577 d->setCursorPosition(d->end());
578 updateInputMethod(Qt::ImEnabled);
580 d->emitUndoRedoChanged();
581 emit readOnlyChanged(ro);
585 \qmlproperty int QtQuick2::TextInput::maximumLength
586 The maximum permitted length of the text in the TextInput.
588 If the text is too long, it is truncated at the limit.
590 By default, this property contains a value of 32767.
592 int QQuickTextInput::maxLength() const
594 Q_D(const QQuickTextInput);
595 return d->m_maxLength;
598 void QQuickTextInput::setMaxLength(int ml)
600 Q_D(QQuickTextInput);
601 if (d->m_maxLength == ml || d->m_maskData)
605 d->internalSetText(d->m_text, -1, false);
607 emit maximumLengthChanged(ml);
611 \qmlproperty bool QtQuick2::TextInput::cursorVisible
612 Set to true when the TextInput shows a cursor.
614 This property is set and unset when the TextInput gets active focus, so that other
615 properties can be bound to whether the cursor is currently showing. As it
616 gets set and unset automatically, when you set the value yourself you must
617 keep in mind that your value may be overwritten.
619 It can be set directly in script, for example if a KeyProxy might
620 forward keys to it and you desire it to look active when this happens
621 (but without actually giving it active focus).
623 It should not be set directly on the element, like in the below QML,
624 as the specified value will be overridden an lost on focus changes.
633 In the above snippet the cursor will still become visible when the
634 TextInput gains active focus.
636 bool QQuickTextInput::isCursorVisible() const
638 Q_D(const QQuickTextInput);
639 return d->cursorVisible;
642 void QQuickTextInput::setCursorVisible(bool on)
644 Q_D(QQuickTextInput);
645 if (d->cursorVisible == on)
647 d->cursorVisible = on;
648 d->setCursorBlinkPeriod(on ? qApp->styleHints()->cursorFlashTime() : 0);
649 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
651 emit cursorVisibleChanged(d->cursorVisible);
655 \qmlproperty int QtQuick2::TextInput::cursorPosition
656 The position of the cursor in the TextInput.
658 int QQuickTextInput::cursorPosition() const
660 Q_D(const QQuickTextInput);
664 void QQuickTextInput::setCursorPosition(int cp)
666 Q_D(QQuickTextInput);
667 if (cp < 0 || cp > text().length())
673 \qmlproperty rectangle QtQuick2::TextInput::cursorRectangle
675 The rectangle where the standard text cursor is rendered within the text input. Read only.
677 The position and height of a custom cursorDelegate are updated to follow the cursorRectangle
678 automatically when it changes. The width of the delegate is unaffected by changes in the
682 QRect QQuickTextInput::cursorRectangle() const
684 Q_D(const QQuickTextInput);
687 if (d->m_preeditCursor != -1)
688 c += d->m_preeditCursor;
689 if (d->m_echoMode == NoEcho)
691 QTextLine l = d->m_textLayout.lineForTextPosition(c);
695 qRound(l.cursorToX(c) - d->hscroll),
696 qRound(l.y() - d->vscroll),
702 \qmlproperty int QtQuick2::TextInput::selectionStart
704 The cursor position before the first character in the current selection.
706 This property is read-only. To change the selection, use select(start,end),
707 selectAll(), or selectWord().
709 \sa selectionEnd, cursorPosition, selectedText
711 int QQuickTextInput::selectionStart() const
713 Q_D(const QQuickTextInput);
714 return d->lastSelectionStart;
717 \qmlproperty int QtQuick2::TextInput::selectionEnd
719 The cursor position after the last character in the current selection.
721 This property is read-only. To change the selection, use select(start,end),
722 selectAll(), or selectWord().
724 \sa selectionStart, cursorPosition, selectedText
726 int QQuickTextInput::selectionEnd() const
728 Q_D(const QQuickTextInput);
729 return d->lastSelectionEnd;
732 \qmlmethod void QtQuick2::TextInput::select(int start, int end)
734 Causes the text from \a start to \a end to be selected.
736 If either start or end is out of range, the selection is not changed.
738 After calling this, selectionStart will become the lesser
739 and selectionEnd will become the greater (regardless of the order passed
742 \sa selectionStart, selectionEnd
744 void QQuickTextInput::select(int start, int end)
746 Q_D(QQuickTextInput);
747 if (start < 0 || end < 0 || start > d->m_text.length() || end > d->m_text.length())
749 d->setSelection(start, end-start);
753 \qmlproperty string QtQuick2::TextInput::selectedText
755 This read-only property provides the text currently selected in the
758 It is equivalent to the following snippet, but is faster and easier
762 myTextInput.text.toString().substring(myTextInput.selectionStart,
763 myTextInput.selectionEnd);
766 QString QQuickTextInput::selectedText() const
768 Q_D(const QQuickTextInput);
769 return d->selectedText();
773 \qmlproperty bool QtQuick2::TextInput::activeFocusOnPress
775 Whether the TextInput should gain active focus on a mouse press. By default this is
778 bool QQuickTextInput::focusOnPress() const
780 Q_D(const QQuickTextInput);
781 return d->focusOnPress;
784 void QQuickTextInput::setFocusOnPress(bool b)
786 Q_D(QQuickTextInput);
787 if (d->focusOnPress == b)
792 emit activeFocusOnPressChanged(d->focusOnPress);
795 \qmlproperty bool QtQuick2::TextInput::autoScroll
797 Whether the TextInput should scroll when the text is longer than the width. By default this is
800 bool QQuickTextInput::autoScroll() const
802 Q_D(const QQuickTextInput);
803 return d->autoScroll;
806 void QQuickTextInput::setAutoScroll(bool b)
808 Q_D(QQuickTextInput);
809 if (d->autoScroll == b)
813 //We need to repaint so that the scrolling is taking into account.
814 updateCursorRectangle();
815 emit autoScrollChanged(d->autoScroll);
818 #ifndef QT_NO_VALIDATOR
821 \qmlclass IntValidator QIntValidator
822 \inqmlmodule QtQuick 2
823 \ingroup qml-basic-visual-elements
825 This element provides a validator for integer values.
827 If no \l locale is set IntValidator uses the \l {QLocale::setDefault()}{default locale} to
828 interpret the number and will accept locale specific digits, group separators, and positive
829 and negative signs. In addition, IntValidator is always guaranteed to accept a number
830 formatted according to the "C" locale.
834 QQuickIntValidator::QQuickIntValidator(QObject *parent)
835 : QIntValidator(parent)
840 \qmlproperty string QtQuick2::IntValidator::locale
842 This property holds the name of the locale used to interpret the number.
847 QString QQuickIntValidator::localeName() const
849 return locale().name();
852 void QQuickIntValidator::setLocaleName(const QString &name)
854 if (locale().name() != name) {
855 setLocale(QLocale(name));
856 emit localeNameChanged();
860 void QQuickIntValidator::resetLocaleName()
862 QLocale defaultLocale;
863 if (locale() != defaultLocale) {
864 setLocale(defaultLocale);
865 emit localeNameChanged();
870 \qmlproperty int QtQuick2::IntValidator::top
872 This property holds the validator's highest acceptable value.
873 By default, this property's value is derived from the highest signed integer available (typically 2147483647).
876 \qmlproperty int QtQuick2::IntValidator::bottom
878 This property holds the validator's lowest acceptable value.
879 By default, this property's value is derived from the lowest signed integer available (typically -2147483647).
883 \qmlclass DoubleValidator QDoubleValidator
884 \inqmlmodule QtQuick 2
885 \ingroup qml-basic-visual-elements
887 This element provides a validator for non-integer numbers.
889 Input is accepted if it contains a double that is within the valid range
890 and is in the correct format.
892 Input is accepected but invalid if it contains a double that is outside
893 the range or is in the wrong format; e.g. with too many digits after the
894 decimal point or is empty.
896 Input is rejected if it is not a double.
898 Note: If the valid range consists of just positive doubles (e.g. 0.0 to
899 100.0) and input is a negative double then it is rejected. If \l notation
900 is set to DoubleValidator.StandardNotation, and the input contains more
901 digits before the decimal point than a double in the valid range may have,
902 it is also rejected. If \l notation is DoubleValidator.ScientificNotation,
903 and the input is not in the valid range, it is accecpted but invalid. The
904 value may yet become valid by changing the exponent.
907 QQuickDoubleValidator::QQuickDoubleValidator(QObject *parent)
908 : QDoubleValidator(parent)
913 \qmlproperty string QtQuick2::DoubleValidator::locale
915 This property holds the name of the locale used to interpret the number.
920 QString QQuickDoubleValidator::localeName() const
922 return locale().name();
925 void QQuickDoubleValidator::setLocaleName(const QString &name)
927 if (locale().name() != name) {
928 setLocale(QLocale(name));
929 emit localeNameChanged();
933 void QQuickDoubleValidator::resetLocaleName()
935 QLocale defaultLocale;
936 if (locale() != defaultLocale) {
937 setLocale(defaultLocale);
938 emit localeNameChanged();
943 \qmlproperty real QtQuick2::DoubleValidator::top
945 This property holds the validator's maximum acceptable value.
946 By default, this property contains a value of infinity.
949 \qmlproperty real QtQuick2::DoubleValidator::bottom
951 This property holds the validator's minimum acceptable value.
952 By default, this property contains a value of -infinity.
955 \qmlproperty int QtQuick2::DoubleValidator::decimals
957 This property holds the validator's maximum number of digits after the decimal point.
958 By default, this property contains a value of 1000.
961 \qmlproperty enumeration QtQuick2::DoubleValidator::notation
962 This property holds the notation of how a string can describe a number.
964 The possible values for this property are:
967 \o DoubleValidator.StandardNotation
968 \o DoubleValidator.ScientificNotation (default)
971 If this property is set to DoubleValidator.ScientificNotation, the written number may have an exponent part (e.g. 1.5E-2).
975 \qmlclass RegExpValidator QRegExpValidator
976 \inqmlmodule QtQuick 2
977 \ingroup qml-basic-visual-elements
979 This element provides a validator, which counts as valid any string which
980 matches a specified regular expression.
983 \qmlproperty regExp QtQuick2::RegExpValidator::regExp
985 This property holds the regular expression used for validation.
987 Note that this property should be a regular expression in JS syntax, e.g /a/ for the regular expression
990 By default, this property contains a regular expression with the pattern .* that matches any string.
994 \qmlproperty Validator QtQuick2::TextInput::validator
996 Allows you to set a validator on the TextInput. When a validator is set
997 the TextInput will only accept input which leaves the text property in
998 an acceptable or intermediate state. The accepted signal will only be sent
999 if the text is in an acceptable state when enter is pressed.
1001 Currently supported validators are IntValidator, DoubleValidator and
1002 RegExpValidator. An example of using validators is shown below, which allows
1003 input of integers between 11 and 31 into the text input:
1008 validator: IntValidator{bottom: 11; top: 31;}
1013 \sa acceptableInput, inputMask
1016 QValidator* QQuickTextInput::validator() const
1018 Q_D(const QQuickTextInput);
1019 return d->m_validator;
1022 void QQuickTextInput::setValidator(QValidator* v)
1024 Q_D(QQuickTextInput);
1025 if (d->m_validator == v)
1030 if (isComponentComplete())
1033 emit validatorChanged();
1036 #endif // QT_NO_VALIDATOR
1038 void QQuickTextInputPrivate::checkIsValid()
1040 Q_Q(QQuickTextInput);
1042 ValidatorState state = hasAcceptableInput(m_text);
1043 m_validInput = state != InvalidInput;
1044 if (state != AcceptableInput) {
1045 if (m_acceptableInput) {
1046 m_acceptableInput = false;
1047 emit q->acceptableInputChanged();
1049 } else if (!m_acceptableInput) {
1050 m_acceptableInput = true;
1051 emit q->acceptableInputChanged();
1056 \qmlproperty string QtQuick2::TextInput::inputMask
1058 Allows you to set an input mask on the TextInput, restricting the allowable
1059 text inputs. See QLineEdit::inputMask for further details, as the exact
1060 same mask strings are used by TextInput.
1062 \sa acceptableInput, validator
1064 QString QQuickTextInput::inputMask() const
1066 Q_D(const QQuickTextInput);
1067 return d->inputMask();
1070 void QQuickTextInput::setInputMask(const QString &im)
1072 Q_D(QQuickTextInput);
1073 if (d->inputMask() == im)
1076 d->setInputMask(im);
1077 emit inputMaskChanged(d->inputMask());
1081 \qmlproperty bool QtQuick2::TextInput::acceptableInput
1083 This property is always true unless a validator or input mask has been set.
1084 If a validator or input mask has been set, this property will only be true
1085 if the current text is acceptable to the validator or input mask as a final
1086 string (not as an intermediate string).
1088 bool QQuickTextInput::hasAcceptableInput() const
1090 Q_D(const QQuickTextInput);
1091 return d->hasAcceptableInput(d->m_text) == QQuickTextInputPrivate::AcceptableInput;
1095 \qmlsignal QtQuick2::TextInput::onAccepted()
1097 This handler is called when the Return or Enter key is pressed.
1098 Note that if there is a \l validator or \l inputMask set on the text
1099 input, the handler will only be emitted if the input is in an acceptable
1103 void QQuickTextInputPrivate::updateInputMethodHints()
1105 Q_Q(QQuickTextInput);
1106 Qt::InputMethodHints hints = inputMethodHints;
1107 if (m_echoMode == QQuickTextInput::Password || m_echoMode == QQuickTextInput::NoEcho)
1108 hints |= Qt::ImhHiddenText;
1109 else if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit)
1110 hints &= ~Qt::ImhHiddenText;
1111 if (m_echoMode != QQuickTextInput::Normal)
1112 hints |= (Qt::ImhNoAutoUppercase | Qt::ImhNoPredictiveText | Qt::ImhSensitiveData);
1113 effectiveInputMethodHints = hints;
1114 q->updateInputMethod(Qt::ImHints);
1117 \qmlproperty enumeration QtQuick2::TextInput::echoMode
1119 Specifies how the text should be displayed in the TextInput.
1121 \o TextInput.Normal - Displays the text as it is. (Default)
1122 \o TextInput.Password - Displays asterisks instead of characters.
1123 \o TextInput.NoEcho - Displays nothing.
1124 \o TextInput.PasswordEchoOnEdit - Displays characters as they are entered
1125 while editing, otherwise displays asterisks.
1128 QQuickTextInput::EchoMode QQuickTextInput::echoMode() const
1130 Q_D(const QQuickTextInput);
1131 return QQuickTextInput::EchoMode(d->m_echoMode);
1134 void QQuickTextInput::setEchoMode(QQuickTextInput::EchoMode echo)
1136 Q_D(QQuickTextInput);
1137 if (echoMode() == echo)
1139 d->cancelPasswordEchoTimer();
1140 d->m_echoMode = echo;
1141 d->m_passwordEchoEditing = false;
1142 d->updateInputMethodHints();
1143 d->updateDisplayText();
1144 updateCursorRectangle();
1146 emit echoModeChanged(echoMode());
1150 \qmlproperty enumeration QtQuick2::TextInput::inputMethodHints
1152 Provides hints to the input method about the expected content of the text input and how it
1155 The value is a bit-wise combination of flags, or Qt.ImhNone if no hints are set.
1157 Flags that alter behaviour are:
1160 \o Qt.ImhHiddenText - Characters should be hidden, as is typically used when entering passwords.
1161 This is automatically set when setting echoMode to \c TextInput.Password.
1162 \o Qt.ImhSensitiveData - Typed text should not be stored by the active input method
1163 in any persistent storage like predictive user dictionary.
1164 \o Qt.ImhNoAutoUppercase - The input method should not try to automatically switch to upper case
1165 when a sentence ends.
1166 \o Qt.ImhPreferNumbers - Numbers are preferred (but not required).
1167 \o Qt.ImhPreferUppercase - Upper case letters are preferred (but not required).
1168 \o Qt.ImhPreferLowercase - Lower case letters are preferred (but not required).
1169 \o Qt.ImhNoPredictiveText - Do not use predictive text (i.e. dictionary lookup) while typing.
1171 \o Qt.ImhDate - The text editor functions as a date field.
1172 \o Qt.ImhTime - The text editor functions as a time field.
1175 Flags that restrict input (exclusive flags) are:
1178 \o Qt.ImhDigitsOnly - Only digits are allowed.
1179 \o Qt.ImhFormattedNumbersOnly - Only number input is allowed. This includes decimal point and minus sign.
1180 \o Qt.ImhUppercaseOnly - Only upper case letter input is allowed.
1181 \o Qt.ImhLowercaseOnly - Only lower case letter input is allowed.
1182 \o Qt.ImhDialableCharactersOnly - Only characters suitable for phone dialing are allowed.
1183 \o Qt.ImhEmailCharactersOnly - Only characters suitable for email addresses are allowed.
1184 \o Qt.ImhUrlCharactersOnly - Only characters suitable for URLs are allowed.
1190 \o Qt.ImhExclusiveInputMask - This mask yields nonzero if any of the exclusive flags are used.
1194 Qt::InputMethodHints QQuickTextInput::inputMethodHints() const
1196 Q_D(const QQuickTextInput);
1197 return d->inputMethodHints;
1200 void QQuickTextInput::setInputMethodHints(Qt::InputMethodHints hints)
1202 Q_D(QQuickTextInput);
1204 if (hints == d->inputMethodHints)
1207 d->inputMethodHints = hints;
1208 d->updateInputMethodHints();
1209 emit inputMethodHintsChanged();
1213 \qmlproperty Component QtQuick2::TextInput::cursorDelegate
1214 The delegate for the cursor in the TextInput.
1216 If you set a cursorDelegate for a TextInput, this delegate will be used for
1217 drawing the cursor instead of the standard cursor. An instance of the
1218 delegate will be created and managed by the TextInput when a cursor is
1219 needed, and the x property of delegate instance will be set so as
1220 to be one pixel before the top left of the current character.
1222 Note that the root item of the delegate component must be a QDeclarativeItem or
1223 QDeclarativeItem derived item.
1225 QDeclarativeComponent* QQuickTextInput::cursorDelegate() const
1227 Q_D(const QQuickTextInput);
1228 return d->cursorComponent;
1231 void QQuickTextInput::setCursorDelegate(QDeclarativeComponent* c)
1233 Q_D(QQuickTextInput);
1234 if (d->cursorComponent == c)
1237 d->cursorComponent = c;
1239 //note that the components are owned by something else
1240 delete d->cursorItem;
1242 d->startCreatingCursor();
1245 emit cursorDelegateChanged();
1248 void QQuickTextInputPrivate::startCreatingCursor()
1250 Q_Q(QQuickTextInput);
1251 if (cursorComponent->isReady()) {
1253 } else if (cursorComponent->isLoading()) {
1254 q->connect(cursorComponent, SIGNAL(statusChanged(int)),
1255 q, SLOT(createCursor()));
1257 qmlInfo(q, cursorComponent->errors()) << QQuickTextInput::tr("Could not load cursor delegate");
1261 void QQuickTextInput::createCursor()
1263 Q_D(QQuickTextInput);
1264 if (!isComponentComplete())
1267 if (d->cursorComponent->isError()) {
1268 qmlInfo(this, d->cursorComponent->errors()) << tr("Could not load cursor delegate");
1272 if (!d->cursorComponent->isReady())
1276 delete d->cursorItem;
1277 QDeclarativeContext *creationContext = d->cursorComponent->creationContext();
1278 QObject *object = d->cursorComponent->create(creationContext ? creationContext : qmlContext(this));
1279 d->cursorItem = qobject_cast<QQuickItem*>(object);
1280 if (!d->cursorItem) {
1282 qmlInfo(this, d->cursorComponent->errors()) << tr("Could not instantiate cursor delegate");
1286 QRectF r = cursorRectangle();
1288 QDeclarative_setParent_noEvent(d->cursorItem, this);
1289 d->cursorItem->setParentItem(this);
1290 d->cursorItem->setPos(r.topLeft());
1291 d->cursorItem->setHeight(r.height());
1295 \qmlmethod rect QtQuick2::TextInput::positionToRectangle(int pos)
1297 This function takes a character position and returns the rectangle that the
1298 cursor would occupy, if it was placed at that character position.
1300 This is similar to setting the cursorPosition, and then querying the cursor
1301 rectangle, but the cursorPosition is not changed.
1303 QRectF QQuickTextInput::positionToRectangle(int pos) const
1305 Q_D(const QQuickTextInput);
1306 if (d->m_echoMode == NoEcho)
1308 else if (pos > d->m_cursor)
1309 pos += d->preeditAreaText().length();
1310 QTextLine l = d->m_textLayout.lineForTextPosition(pos);
1312 ? QRectF(l.cursorToX(pos) - d->hscroll, l.y() - d->vscroll, d->m_cursorWidth, l.height())
1317 \qmlmethod int QtQuick2::TextInput::positionAt(real x, real y, CursorPosition position = CursorBetweenCharacters)
1319 This function returns the character position at
1320 x and y pixels from the top left of the textInput. Position 0 is before the
1321 first character, position 1 is after the first character but before the second,
1322 and so on until position text.length, which is after all characters.
1324 This means that for all x values before the first character this function returns 0,
1325 and for all x values after the last character this function returns text.length. If
1326 the y value is above the text the position will be that of the nearest character on
1327 the first line line and if it is below the text the position of the nearest character
1328 on the last line will be returned.
1330 The cursor position type specifies how the cursor position should be resolved.
1333 \o TextInput.CursorBetweenCharacters - Returns the position between characters that is nearest x.
1334 \o TextInput.CursorOnCharacter - Returns the position before the character that is nearest x.
1338 void QQuickTextInput::positionAt(QDeclarativeV8Function *args) const
1340 Q_D(const QQuickTextInput);
1344 QTextLine::CursorPosition position = QTextLine::CursorBetweenCharacters;
1346 if (args->Length() < 1)
1350 v8::Local<v8::Value> arg = (*args)[i];
1351 x = arg->NumberValue();
1353 if (++i < args->Length()) {
1355 y = arg->NumberValue();
1358 if (++i < args->Length()) {
1360 position = QTextLine::CursorPosition(arg->Int32Value());
1363 int pos = d->positionAt(x, y, position);
1364 const int cursor = d->m_cursor;
1366 const int preeditLength = d->preeditAreaText().length();
1367 pos = pos > cursor + preeditLength
1368 ? pos - preeditLength
1371 args->returnValue(v8::Int32::New(pos));
1374 int QQuickTextInputPrivate::positionAt(int x, int y, QTextLine::CursorPosition position) const
1378 QTextLine line = m_textLayout.lineAt(0);
1379 for (int i = 1; i < m_textLayout.lineCount(); ++i) {
1380 QTextLine nextLine = m_textLayout.lineAt(i);
1382 if (y < (line.rect().bottom() + nextLine.y()) / 2)
1386 return line.isValid() ? line.xToCursor(x, position) : 0;
1389 void QQuickTextInput::keyPressEvent(QKeyEvent* ev)
1391 Q_D(QQuickTextInput);
1392 // Don't allow MacOSX up/down support, and we don't allow a completer.
1393 bool ignore = (ev->key() == Qt::Key_Up || ev->key() == Qt::Key_Down) && ev->modifiers() == Qt::NoModifier;
1394 if (!ignore && (d->lastSelectionStart == d->lastSelectionEnd) && (ev->key() == Qt::Key_Right || ev->key() == Qt::Key_Left)) {
1395 // Ignore when moving off the end unless there is a selection,
1396 // because then moving will do something (deselect).
1397 int cursorPosition = d->m_cursor;
1398 if (cursorPosition == 0)
1399 ignore = ev->key() == (d->layoutDirection() == Qt::LeftToRight ? Qt::Key_Left : Qt::Key_Right);
1400 if (cursorPosition == text().length())
1401 ignore = ev->key() == (d->layoutDirection() == Qt::LeftToRight ? Qt::Key_Right : Qt::Key_Left);
1406 d->processKeyEvent(ev);
1408 if (!ev->isAccepted())
1409 QQuickImplicitSizeItem::keyPressEvent(ev);
1412 void QQuickTextInput::inputMethodEvent(QInputMethodEvent *ev)
1414 Q_D(QQuickTextInput);
1415 const bool wasComposing = d->preeditAreaText().length() > 0;
1416 if (d->m_readOnly) {
1419 d->processInputMethodEvent(ev);
1421 if (!ev->isAccepted())
1422 QQuickImplicitSizeItem::inputMethodEvent(ev);
1424 if (wasComposing != (d->m_textLayout.preeditAreaText().length() > 0))
1425 emit inputMethodComposingChanged();
1428 void QQuickTextInput::mouseDoubleClickEvent(QMouseEvent *event)
1430 Q_D(QQuickTextInput);
1432 if (d->selectByMouse && event->button() == Qt::LeftButton) {
1434 int cursor = d->positionAt(event->localPos());
1435 d->selectWordAtPos(cursor);
1436 event->setAccepted(true);
1437 if (!d->hasPendingTripleClick()) {
1438 d->tripleClickStartPoint = event->localPos().toPoint();
1439 d->tripleClickTimer.start();
1442 if (d->sendMouseEventToInputContext(event))
1444 QQuickImplicitSizeItem::mouseDoubleClickEvent(event);
1448 void QQuickTextInput::mousePressEvent(QMouseEvent *event)
1450 Q_D(QQuickTextInput);
1452 d->pressPos = event->localPos();
1454 if (d->focusOnPress) {
1455 bool hadActiveFocus = hasActiveFocus();
1457 // re-open input panel on press if already focused
1458 if (hasActiveFocus() && hadActiveFocus && !d->m_readOnly)
1459 openSoftwareInputPanel();
1461 if (d->selectByMouse) {
1462 setKeepMouseGrab(false);
1463 d->selectPressed = true;
1464 QPoint distanceVector = d->pressPos.toPoint() - d->tripleClickStartPoint;
1465 if (d->hasPendingTripleClick()
1466 && distanceVector.manhattanLength() < qApp->styleHints()->startDragDistance()) {
1467 event->setAccepted(true);
1473 if (d->sendMouseEventToInputContext(event))
1476 bool mark = (event->modifiers() & Qt::ShiftModifier) && d->selectByMouse;
1477 int cursor = d->positionAt(event->localPos());
1478 d->moveCursor(cursor, mark);
1479 event->setAccepted(true);
1482 void QQuickTextInput::mouseMoveEvent(QMouseEvent *event)
1484 Q_D(QQuickTextInput);
1486 if (d->selectPressed) {
1487 if (qAbs(int(event->localPos().x() - d->pressPos.x())) > qApp->styleHints()->startDragDistance())
1488 setKeepMouseGrab(true);
1490 if (d->composeMode()) {
1492 int startPos = d->positionAt(d->pressPos);
1493 int currentPos = d->positionAt(event->localPos());
1494 if (startPos != currentPos)
1495 d->setSelection(startPos, currentPos - startPos);
1497 moveCursorSelection(d->positionAt(event->localPos()), d->mouseSelectionMode);
1499 event->setAccepted(true);
1501 QQuickImplicitSizeItem::mouseMoveEvent(event);
1505 void QQuickTextInput::mouseReleaseEvent(QMouseEvent *event)
1507 Q_D(QQuickTextInput);
1508 if (d->sendMouseEventToInputContext(event))
1510 if (d->selectPressed) {
1511 d->selectPressed = false;
1512 setKeepMouseGrab(false);
1514 #ifndef QT_NO_CLIPBOARD
1515 if (QGuiApplication::clipboard()->supportsSelection()) {
1516 if (event->button() == Qt::LeftButton) {
1517 d->copy(QClipboard::Selection);
1518 } else if (!d->m_readOnly && event->button() == Qt::MidButton) {
1520 d->insert(QGuiApplication::clipboard()->text(QClipboard::Selection));
1524 if (!event->isAccepted())
1525 QQuickImplicitSizeItem::mouseReleaseEvent(event);
1528 bool QQuickTextInputPrivate::sendMouseEventToInputContext(QMouseEvent *event)
1530 #if !defined QT_NO_IM
1531 if (composeMode()) {
1532 int tmp_cursor = positionAt(event->localPos());
1533 int mousePos = tmp_cursor - m_cursor;
1534 if (mousePos >= 0 && mousePos <= m_textLayout.preeditAreaText().length()) {
1535 if (event->type() == QEvent::MouseButtonRelease) {
1536 qApp->inputMethod()->invokeAction(QInputMethod::Click, mousePos);
1549 void QQuickTextInput::mouseUngrabEvent()
1551 Q_D(QQuickTextInput);
1552 d->selectPressed = false;
1553 setKeepMouseGrab(false);
1556 bool QQuickTextInput::event(QEvent* ev)
1558 #ifndef QT_NO_SHORTCUT
1559 Q_D(QQuickTextInput);
1560 if (ev->type() == QEvent::ShortcutOverride) {
1563 QKeyEvent* ke = static_cast<QKeyEvent*>(ev);
1564 if (ke == QKeySequence::Copy
1565 || ke == QKeySequence::Paste
1566 || ke == QKeySequence::Cut
1567 || ke == QKeySequence::Redo
1568 || ke == QKeySequence::Undo
1569 || ke == QKeySequence::MoveToNextWord
1570 || ke == QKeySequence::MoveToPreviousWord
1571 || ke == QKeySequence::MoveToStartOfDocument
1572 || ke == QKeySequence::MoveToEndOfDocument
1573 || ke == QKeySequence::SelectNextWord
1574 || ke == QKeySequence::SelectPreviousWord
1575 || ke == QKeySequence::SelectStartOfLine
1576 || ke == QKeySequence::SelectEndOfLine
1577 || ke == QKeySequence::SelectStartOfBlock
1578 || ke == QKeySequence::SelectEndOfBlock
1579 || ke == QKeySequence::SelectStartOfDocument
1580 || ke == QKeySequence::SelectAll
1581 || ke == QKeySequence::SelectEndOfDocument) {
1583 } else if (ke->modifiers() == Qt::NoModifier || ke->modifiers() == Qt::ShiftModifier
1584 || ke->modifiers() == Qt::KeypadModifier) {
1585 if (ke->key() < Qt::Key_Escape) {
1589 switch (ke->key()) {
1590 case Qt::Key_Delete:
1593 case Qt::Key_Backspace:
1605 return QQuickImplicitSizeItem::event(ev);
1608 void QQuickTextInput::geometryChanged(const QRectF &newGeometry,
1609 const QRectF &oldGeometry)
1611 Q_D(QQuickTextInput);
1612 if (newGeometry.width() != oldGeometry.width())
1614 updateCursorRectangle();
1615 QQuickImplicitSizeItem::geometryChanged(newGeometry, oldGeometry);
1618 void QQuickTextInputPrivate::updateHorizontalScroll()
1620 Q_Q(QQuickTextInput);
1621 QTextLine currentLine = m_textLayout.lineForTextPosition(m_cursor + m_preeditCursor);
1622 const int preeditLength = m_textLayout.preeditAreaText().length();
1623 const int width = qMax(0, qFloor(q->width()));
1624 int widthUsed = currentLine.isValid() ? qRound(currentLine.naturalTextWidth()) : 0;
1625 int previousScroll = hscroll;
1627 if (!autoScroll || widthUsed <= width || m_echoMode == QQuickTextInput::NoEcho) {
1630 Q_ASSERT(currentLine.isValid());
1631 int cix = qRound(currentLine.cursorToX(m_cursor + preeditLength));
1632 if (cix - hscroll >= width) {
1633 // text doesn't fit, cursor is to the right of br (scroll right)
1634 hscroll = cix - width;
1635 } else if (cix - hscroll < 0 && hscroll < widthUsed) {
1636 // text doesn't fit, cursor is to the left of br (scroll left)
1638 } else if (widthUsed - hscroll < width) {
1639 // text doesn't fit, text document is to the left of br; align
1641 hscroll = widthUsed - width;
1643 if (preeditLength > 0) {
1644 // check to ensure long pre-edit text doesn't push the cursor
1646 cix = qRound(currentLine.cursorToX(m_cursor + qMax(0, m_preeditCursor - 1)));
1651 if (previousScroll != hscroll)
1652 textLayoutDirty = true;
1655 void QQuickTextInputPrivate::updateVerticalScroll()
1657 Q_Q(QQuickTextInput);
1658 const int preeditLength = m_textLayout.preeditAreaText().length();
1659 const int height = qMax(0, qFloor(q->height()));
1660 int heightUsed = boundingRect.height();
1661 int previousScroll = vscroll;
1663 if (!autoScroll || heightUsed <= height) {
1664 // text fits in br; use vscroll for alignment
1665 switch (vAlign & ~(Qt::AlignAbsolute|Qt::AlignHorizontal_Mask)) {
1666 case Qt::AlignBottom:
1667 vscroll = heightUsed - height;
1669 case Qt::AlignVCenter:
1670 vscroll = (heightUsed - height) / 2;
1678 QTextLine currentLine = m_textLayout.lineForTextPosition(m_cursor + preeditLength);
1679 QRectF r = currentLine.isValid() ? currentLine.rect() : QRectF();
1680 int top = qFloor(r.top());
1681 int bottom = qCeil(r.bottom());
1683 if (bottom - vscroll >= height) {
1684 // text doesn't fit, cursor is to the below the br (scroll down)
1685 vscroll = bottom - height;
1686 } else if (top - vscroll < 0 && vscroll < heightUsed) {
1687 // text doesn't fit, cursor is above br (scroll up)
1689 } else if (heightUsed - vscroll < height) {
1690 // text doesn't fit, text document is to the left of br; align
1692 vscroll = heightUsed - height;
1694 if (preeditLength > 0) {
1695 // check to ensure long pre-edit text doesn't push the cursor
1697 currentLine = m_textLayout.lineForTextPosition(m_cursor + qMax(0, m_preeditCursor - 1));
1698 top = currentLine.isValid() ? qRound(currentLine.rect().top()) : 0;
1703 if (previousScroll != vscroll)
1704 textLayoutDirty = true;
1707 void QQuickTextInput::triggerPreprocess()
1709 Q_D(QQuickTextInput);
1710 if (d->updateType == QQuickTextInputPrivate::UpdateNone)
1711 d->updateType = QQuickTextInputPrivate::UpdateOnlyPreprocess;
1715 QSGNode *QQuickTextInput::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data)
1718 Q_D(QQuickTextInput);
1720 if (d->updateType != QQuickTextInputPrivate::UpdatePaintNode && oldNode != 0) {
1721 // Update done in preprocess() in the nodes
1722 d->updateType = QQuickTextInputPrivate::UpdateNone;
1726 d->updateType = QQuickTextInputPrivate::UpdateNone;
1728 QQuickTextNode *node = static_cast<QQuickTextNode *>(oldNode);
1730 node = new QQuickTextNode(QQuickItemPrivate::get(this)->sceneGraphContext(), this);
1733 if (!d->textLayoutDirty) {
1734 QSGSimpleRectNode *cursorNode = node->cursorNode();
1735 if (cursorNode != 0 && !isReadOnly()) {
1736 cursorNode->setRect(cursorRectangle());
1738 if (!d->cursorVisible || (!d->m_blinkStatus && d->m_blinkPeriod > 0)) {
1745 node->deleteContent();
1746 node->setMatrix(QMatrix4x4());
1748 QPoint offset = QPoint(0,0);
1749 QFontMetrics fm = QFontMetrics(d->font);
1750 if (d->autoScroll) {
1751 // the y offset is there to keep the baseline constant in case we have script changes in the text.
1752 offset = -QPoint(d->hscroll, d->vscroll + d->m_ascent - fm.ascent());
1754 offset = -QPoint(d->hscroll, d->vscroll);
1757 if (!d->m_textLayout.text().isEmpty() || !d->m_textLayout.preeditAreaText().isEmpty()) {
1758 node->addTextLayout(offset, &d->m_textLayout, d->color,
1759 QQuickText::Normal, QColor(), QColor(),
1760 d->selectionColor, d->selectedTextColor,
1761 d->selectionStart(),
1762 d->selectionEnd() - 1); // selectionEnd() returns first char after
1766 if (!isReadOnly() && d->cursorItem == 0) {
1767 node->setCursor(cursorRectangle(), d->color);
1768 if (!d->cursorVisible || (!d->m_blinkStatus && d->m_blinkPeriod > 0)) {
1775 d->textLayoutDirty = false;
1781 QVariant QQuickTextInput::inputMethodQuery(Qt::InputMethodQuery property) const
1783 Q_D(const QQuickTextInput);
1786 return QVariant((bool)(flags() & ItemAcceptsInputMethod));
1788 return QVariant((int) d->effectiveInputMethodHints);
1789 case Qt::ImCursorRectangle:
1790 return cursorRectangle();
1793 case Qt::ImCursorPosition:
1794 return QVariant(d->m_cursor);
1795 case Qt::ImSurroundingText:
1796 if (d->m_echoMode == PasswordEchoOnEdit && !d->m_passwordEchoEditing) {
1797 return QVariant(displayText());
1799 return QVariant(d->realText());
1801 case Qt::ImCurrentSelection:
1802 return QVariant(selectedText());
1803 case Qt::ImMaximumTextLength:
1804 return QVariant(maxLength());
1805 case Qt::ImAnchorPosition:
1806 if (d->selectionStart() == d->selectionEnd())
1807 return QVariant(d->m_cursor);
1808 else if (d->selectionStart() == d->m_cursor)
1809 return QVariant(d->selectionEnd());
1811 return QVariant(d->selectionStart());
1818 \qmlmethod void QtQuick2::TextInput::deselect()
1820 Removes active text selection.
1822 void QQuickTextInput::deselect()
1824 Q_D(QQuickTextInput);
1829 \qmlmethod void QtQuick2::TextInput::selectAll()
1831 Causes all text to be selected.
1833 void QQuickTextInput::selectAll()
1835 Q_D(QQuickTextInput);
1836 d->setSelection(0, text().length());
1840 \qmlmethod void QtQuick2::TextInput::isRightToLeft(int start, int end)
1842 Returns true if the natural reading direction of the editor text
1843 found between positions \a start and \a end is right to left.
1845 bool QQuickTextInput::isRightToLeft(int start, int end)
1848 qmlInfo(this) << "isRightToLeft(start, end) called with the end property being smaller than the start.";
1851 return text().mid(start, end - start).isRightToLeft();
1855 #ifndef QT_NO_CLIPBOARD
1857 \qmlmethod QtQuick2::TextInput::cut()
1859 Moves the currently selected text to the system clipboard.
1861 void QQuickTextInput::cut()
1863 Q_D(QQuickTextInput);
1869 \qmlmethod QtQuick2::TextInput::copy()
1871 Copies the currently selected text to the system clipboard.
1873 void QQuickTextInput::copy()
1875 Q_D(QQuickTextInput);
1880 \qmlmethod QtQuick2::TextInput::paste()
1882 Replaces the currently selected text by the contents of the system clipboard.
1884 void QQuickTextInput::paste()
1886 Q_D(QQuickTextInput);
1890 #endif // QT_NO_CLIPBOARD
1893 Undoes the last operation if undo is \l {canUndo}{available}. Deselects any
1894 current selection, and updates the selection start to the current cursor
1898 void QQuickTextInput::undo()
1900 Q_D(QQuickTextInput);
1901 if (!d->m_readOnly) {
1903 d->finishChange(-1, true);
1908 Redoes the last operation if redo is \l {canRedo}{available}.
1911 void QQuickTextInput::redo()
1913 Q_D(QQuickTextInput);
1914 if (!d->m_readOnly) {
1921 \qmlmethod void QtQuick2::TextInput::insert(int position, string text)
1923 Inserts \a text into the TextInput at position.
1926 void QQuickTextInput::insert(int position, const QString &text)
1928 Q_D(QQuickTextInput);
1929 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
1930 if (d->m_echoMode == QQuickTextInput::Password)
1931 d->m_passwordEchoTimer.start(qt_passwordEchoDelay, this);
1934 if (position < 0 || position > d->m_text.length())
1937 const int priorState = d->m_undoState;
1939 QString insertText = text;
1941 if (d->hasSelectedText()) {
1942 d->addCommand(QQuickTextInputPrivate::Command(
1943 QQuickTextInputPrivate::SetSelection, d->m_cursor, 0, d->m_selstart, d->m_selend));
1945 if (d->m_maskData) {
1946 insertText = d->maskString(position, insertText);
1947 for (int i = 0; i < insertText.length(); ++i) {
1948 d->addCommand(QQuickTextInputPrivate::Command(
1949 QQuickTextInputPrivate::DeleteSelection, position + i, d->m_text.at(position + i), -1, -1));
1950 d->addCommand(QQuickTextInputPrivate::Command(
1951 QQuickTextInputPrivate::Insert, position + i, insertText.at(i), -1, -1));
1953 d->m_text.replace(position, insertText.length(), insertText);
1954 if (!insertText.isEmpty())
1955 d->m_textDirty = true;
1956 if (position < d->m_selend && position + insertText.length() > d->m_selstart)
1957 d->m_selDirty = true;
1959 int remaining = d->m_maxLength - d->m_text.length();
1960 if (remaining != 0) {
1961 insertText = insertText.left(remaining);
1962 d->m_text.insert(position, insertText);
1963 for (int i = 0; i < insertText.length(); ++i)
1964 d->addCommand(QQuickTextInputPrivate::Command(
1965 QQuickTextInputPrivate::Insert, position + i, insertText.at(i), -1, -1));
1966 if (d->m_cursor >= position)
1967 d->m_cursor += insertText.length();
1968 if (d->m_selstart >= position)
1969 d->m_selstart += insertText.length();
1970 if (d->m_selend >= position)
1971 d->m_selend += insertText.length();
1972 d->m_textDirty = true;
1973 if (position >= d->m_selstart && position <= d->m_selend)
1974 d->m_selDirty = true;
1978 d->addCommand(QQuickTextInputPrivate::Command(
1979 QQuickTextInputPrivate::SetSelection, d->m_cursor, 0, d->m_selstart, d->m_selend));
1980 d->finishChange(priorState);
1982 if (d->lastSelectionStart != d->lastSelectionEnd) {
1983 if (d->m_selstart != d->lastSelectionStart) {
1984 d->lastSelectionStart = d->m_selstart;
1985 emit selectionStartChanged();
1987 if (d->m_selend != d->lastSelectionEnd) {
1988 d->lastSelectionEnd = d->m_selend;
1989 emit selectionEndChanged();
1995 \qmlmethod string QtQuick2::TextInput::getText(int start, int end)
1997 Removes the section of text that is between the \a start and \a end positions from the TextInput.
2000 void QQuickTextInput::remove(int start, int end)
2002 Q_D(QQuickTextInput);
2004 start = qBound(0, start, d->m_text.length());
2005 end = qBound(0, end, d->m_text.length());
2009 else if (start == end)
2012 if (start < d->m_selend && end > d->m_selstart)
2013 d->m_selDirty = true;
2015 const int priorState = d->m_undoState;
2017 d->addCommand(QQuickTextInputPrivate::Command(
2018 QQuickTextInputPrivate::SetSelection, d->m_cursor, 0, d->m_selstart, d->m_selend));
2020 if (start <= d->m_cursor && d->m_cursor < end) {
2021 // cursor is within the selection. Split up the commands
2022 // to be able to restore the correct cursor position
2023 for (int i = d->m_cursor; i >= start; --i) {
2024 d->addCommand(QQuickTextInputPrivate::Command(
2025 QQuickTextInputPrivate::DeleteSelection, i, d->m_text.at(i), -1, 1));
2027 for (int i = end - 1; i > d->m_cursor; --i) {
2028 d->addCommand(QQuickTextInputPrivate::Command(
2029 QQuickTextInputPrivate::DeleteSelection, i - d->m_cursor + start - 1, d->m_text.at(i), -1, -1));
2032 for (int i = end - 1; i >= start; --i) {
2033 d->addCommand(QQuickTextInputPrivate::Command(
2034 QQuickTextInputPrivate::RemoveSelection, i, d->m_text.at(i), -1, -1));
2037 if (d->m_maskData) {
2038 d->m_text.replace(start, end - start, d->clearString(start, end - start));
2039 for (int i = 0; i < end - start; ++i) {
2040 d->addCommand(QQuickTextInputPrivate::Command(
2041 QQuickTextInputPrivate::Insert, start + i, d->m_text.at(start + i), -1, -1));
2044 d->m_text.remove(start, end - start);
2046 if (d->m_cursor > start)
2047 d->m_cursor -= qMin(d->m_cursor, end) - start;
2048 if (d->m_selstart > start)
2049 d->m_selstart -= qMin(d->m_selstart, end) - start;
2050 if (d->m_selend > end)
2051 d->m_selend -= qMin(d->m_selend, end) - start;
2053 d->addCommand(QQuickTextInputPrivate::Command(
2054 QQuickTextInputPrivate::SetSelection, d->m_cursor, 0, d->m_selstart, d->m_selend));
2056 d->m_textDirty = true;
2057 d->finishChange(priorState);
2059 if (d->lastSelectionStart != d->lastSelectionEnd) {
2060 if (d->m_selstart != d->lastSelectionStart) {
2061 d->lastSelectionStart = d->m_selstart;
2062 emit selectionStartChanged();
2064 if (d->m_selend != d->lastSelectionEnd) {
2065 d->lastSelectionEnd = d->m_selend;
2066 emit selectionEndChanged();
2073 \qmlmethod void QtQuick2::TextInput::selectWord()
2075 Causes the word closest to the current cursor position to be selected.
2077 void QQuickTextInput::selectWord()
2079 Q_D(QQuickTextInput);
2080 d->selectWordAtPos(d->m_cursor);
2084 \qmlproperty bool QtQuick2::TextInput::smooth
2086 This property holds whether the text is smoothly scaled or transformed.
2088 Smooth filtering gives better visual quality, but is slower. If
2089 the item is displayed at its natural size, this property has no visual or
2092 \note Generally scaling artifacts are only visible if the item is stationary on
2093 the screen. A common pattern when animating an item is to disable smooth
2094 filtering at the beginning of the animation and reenable it at the conclusion.
2098 \qmlproperty string QtQuick2::TextInput::passwordCharacter
2100 This is the character displayed when echoMode is set to Password or
2101 PasswordEchoOnEdit. By default it is an asterisk.
2103 If this property is set to a string with more than one character,
2104 the first character is used. If the string is empty, the value
2105 is ignored and the property is not set.
2107 QString QQuickTextInput::passwordCharacter() const
2109 Q_D(const QQuickTextInput);
2110 return QString(d->m_passwordCharacter);
2113 void QQuickTextInput::setPasswordCharacter(const QString &str)
2115 Q_D(QQuickTextInput);
2116 if (str.length() < 1)
2118 d->m_passwordCharacter = str.constData()[0];
2119 if (d->m_echoMode == Password || d->m_echoMode == PasswordEchoOnEdit)
2120 d->updateDisplayText();
2121 emit passwordCharacterChanged();
2125 \qmlproperty string QtQuick2::TextInput::displayText
2127 This is the text displayed in the TextInput.
2129 If \l echoMode is set to TextInput::Normal, this holds the
2130 same value as the TextInput::text property. Otherwise,
2131 this property holds the text visible to the user, while
2132 the \l text property holds the actual entered text.
2134 QString QQuickTextInput::displayText() const
2136 Q_D(const QQuickTextInput);
2137 return d->m_textLayout.text();
2141 \qmlproperty bool QtQuick2::TextInput::selectByMouse
2145 If true, the user can use the mouse to select text in some
2146 platform-specific way. Note that for some platforms this may
2147 not be an appropriate interaction (eg. may conflict with how
2148 the text needs to behave inside a Flickable.
2150 bool QQuickTextInput::selectByMouse() const
2152 Q_D(const QQuickTextInput);
2153 return d->selectByMouse;
2156 void QQuickTextInput::setSelectByMouse(bool on)
2158 Q_D(QQuickTextInput);
2159 if (d->selectByMouse != on) {
2160 d->selectByMouse = on;
2161 emit selectByMouseChanged(on);
2166 \qmlproperty enum QtQuick2::TextInput::mouseSelectionMode
2168 Specifies how text should be selected using a mouse.
2171 \o TextInput.SelectCharacters - The selection is updated with individual characters. (Default)
2172 \o TextInput.SelectWords - The selection is updated with whole words.
2175 This property only applies when \l selectByMouse is true.
2178 QQuickTextInput::SelectionMode QQuickTextInput::mouseSelectionMode() const
2180 Q_D(const QQuickTextInput);
2181 return d->mouseSelectionMode;
2184 void QQuickTextInput::setMouseSelectionMode(SelectionMode mode)
2186 Q_D(QQuickTextInput);
2187 if (d->mouseSelectionMode != mode) {
2188 d->mouseSelectionMode = mode;
2189 emit mouseSelectionModeChanged(mode);
2194 \qmlproperty bool QtQuick2::TextInput::persistentSelection
2196 Whether the TextInput should keep its selection when it loses active focus to another
2197 item in the scene. By default this is set to false;
2200 bool QQuickTextInput::persistentSelection() const
2202 Q_D(const QQuickTextInput);
2203 return d->persistentSelection;
2206 void QQuickTextInput::setPersistentSelection(bool on)
2208 Q_D(QQuickTextInput);
2209 if (d->persistentSelection == on)
2211 d->persistentSelection = on;
2212 emit persistentSelectionChanged();
2216 \qmlproperty bool QtQuick2::TextInput::canPaste
2218 Returns true if the TextInput is writable and the content of the clipboard is
2219 suitable for pasting into the TextInput.
2221 bool QQuickTextInput::canPaste() const
2223 Q_D(const QQuickTextInput);
2224 if (!d->canPasteValid) {
2225 if (const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData())
2226 const_cast<QQuickTextInputPrivate *>(d)->canPaste = !d->m_readOnly && mimeData->hasText();
2227 const_cast<QQuickTextInputPrivate *>(d)->canPasteValid = true;
2233 \qmlproperty bool QtQuick2::TextInput::canUndo
2235 Returns true if the TextInput is writable and there are previous operations
2239 bool QQuickTextInput::canUndo() const
2241 Q_D(const QQuickTextInput);
2246 \qmlproperty bool QtQuick2::TextInput::canRedo
2248 Returns true if the TextInput is writable and there are \l {undo}{undone}
2249 operations that can be redone.
2252 bool QQuickTextInput::canRedo() const
2254 Q_D(const QQuickTextInput);
2259 \qmlproperty real QtQuick2::TextInput::contentWidth
2261 Returns the width of the text, including the width past the width
2262 which is covered due to insufficient wrapping if \l wrapMode is set.
2265 qreal QQuickTextInput::contentWidth() const
2267 Q_D(const QQuickTextInput);
2268 return d->boundingRect.width();
2272 \qmlproperty real QtQuick2::TextInput::contentHeight
2274 Returns the height of the text, including the height past the height
2275 that is covered if the text does not fit within the set height.
2278 qreal QQuickTextInput::contentHeight() const
2280 Q_D(const QQuickTextInput);
2281 return d->boundingRect.height();
2284 void QQuickTextInput::moveCursorSelection(int position)
2286 Q_D(QQuickTextInput);
2287 d->moveCursor(position, true);
2291 \qmlmethod void QtQuick2::TextInput::moveCursorSelection(int position, SelectionMode mode = TextInput.SelectCharacters)
2293 Moves the cursor to \a position and updates the selection according to the optional \a mode
2294 parameter. (To only move the cursor, set the \l cursorPosition property.)
2296 When this method is called it additionally sets either the
2297 selectionStart or the selectionEnd (whichever was at the previous cursor position)
2298 to the specified position. This allows you to easily extend and contract the selected
2301 The selection mode specifies whether the selection is updated on a per character or a per word
2302 basis. If not specified the selection mode will default to TextInput.SelectCharacters.
2305 \o TextInput.SelectCharacters - Sets either the selectionStart or selectionEnd (whichever was at
2306 the previous cursor position) to the specified position.
2307 \o TextInput.SelectWords - Sets the selectionStart and selectionEnd to include all
2308 words between the specified position and the previous cursor position. Words partially in the
2312 For example, take this sequence of calls:
2316 moveCursorSelection(9, TextInput.SelectCharacters)
2317 moveCursorSelection(7, TextInput.SelectCharacters)
2320 This moves the cursor to position 5, extend the selection end from 5 to 9
2321 and then retract the selection end from 9 to 7, leaving the text from position 5 to 7
2322 selected (the 6th and 7th characters).
2324 The same sequence with TextInput.SelectWords will extend the selection start to a word boundary
2325 before or on position 5 and extend the selection end to a word boundary on or past position 9.
2327 void QQuickTextInput::moveCursorSelection(int pos, SelectionMode mode)
2329 Q_D(QQuickTextInput);
2331 if (mode == SelectCharacters) {
2332 d->moveCursor(pos, true);
2333 } else if (pos != d->m_cursor){
2334 const int cursor = d->m_cursor;
2336 if (!d->hasSelectedText())
2337 anchor = d->m_cursor;
2338 else if (d->selectionStart() == d->m_cursor)
2339 anchor = d->selectionEnd();
2341 anchor = d->selectionStart();
2343 if (anchor < pos || (anchor == pos && cursor < pos)) {
2344 const QString text = this->text();
2345 QTextBoundaryFinder finder(QTextBoundaryFinder::Word, text);
2346 finder.setPosition(anchor);
2348 const QTextBoundaryFinder::BoundaryReasons reasons = finder.boundaryReasons();
2349 if (anchor < text.length() && (!(reasons & QTextBoundaryFinder::StartWord)
2350 || ((reasons & QTextBoundaryFinder::EndWord) && anchor > cursor))) {
2351 finder.toPreviousBoundary();
2353 anchor = finder.position() != -1 ? finder.position() : 0;
2355 finder.setPosition(pos);
2356 if (pos > 0 && !finder.boundaryReasons())
2357 finder.toNextBoundary();
2358 const int cursor = finder.position() != -1 ? finder.position() : text.length();
2360 d->setSelection(anchor, cursor - anchor);
2361 } else if (anchor > pos || (anchor == pos && cursor > pos)) {
2362 const QString text = this->text();
2363 QTextBoundaryFinder finder(QTextBoundaryFinder::Word, text);
2364 finder.setPosition(anchor);
2366 const QTextBoundaryFinder::BoundaryReasons reasons = finder.boundaryReasons();
2367 if (anchor > 0 && (!(reasons & QTextBoundaryFinder::EndWord)
2368 || ((reasons & QTextBoundaryFinder::StartWord) && anchor < cursor))) {
2369 finder.toNextBoundary();
2372 anchor = finder.position() != -1 ? finder.position() : text.length();
2374 finder.setPosition(pos);
2375 if (pos < text.length() && !finder.boundaryReasons())
2376 finder.toPreviousBoundary();
2377 const int cursor = finder.position() != -1 ? finder.position() : 0;
2379 d->setSelection(anchor, cursor - anchor);
2385 \qmlmethod void QtQuick2::TextInput::openSoftwareInputPanel()
2387 Opens software input panels like virtual keyboards for typing, useful for
2388 customizing when you want the input keyboard to be shown and hidden in
2391 By default the opening of input panels follows the platform style. Input panels are
2392 always closed if no editor has active focus.
2394 You can disable the automatic behavior by setting the property \c activeFocusOnPress to false
2395 and use functions openSoftwareInputPanel() and closeSoftwareInputPanel() to implement
2396 the behavior you want.
2398 Only relevant on platforms, which provide virtual keyboards.
2404 text: "Hello world!"
2405 activeFocusOnPress: false
2407 anchors.fill: parent
2409 if (!textInput.activeFocus) {
2410 textInput.forceActiveFocus()
2411 textInput.openSoftwareInputPanel();
2413 textInput.focus = false;
2416 onPressAndHold: textInput.closeSoftwareInputPanel();
2421 void QQuickTextInput::openSoftwareInputPanel()
2424 qGuiApp->inputMethod()->show();
2428 \qmlmethod void QtQuick2::TextInput::closeSoftwareInputPanel()
2430 Closes a software input panel like a virtual keyboard shown on the screen, useful
2431 for customizing when you want the input keyboard to be shown and hidden in
2434 By default the opening of input panels follows the platform style. Input panels are
2435 always closed if no editor has active focus.
2437 You can disable the automatic behavior by setting the property \c activeFocusOnPress to false
2438 and use functions openSoftwareInputPanel() and closeSoftwareInputPanel() to implement
2439 the behavior you want.
2441 Only relevant on platforms, which provide virtual keyboards.
2447 text: "Hello world!"
2448 activeFocusOnPress: false
2450 anchors.fill: parent
2452 if (!textInput.activeFocus) {
2453 textInput.forceActiveFocus();
2454 textInput.openSoftwareInputPanel();
2456 textInput.focus = false;
2459 onPressAndHold: textInput.closeSoftwareInputPanel();
2464 void QQuickTextInput::closeSoftwareInputPanel()
2467 qGuiApp->inputMethod()->hide();
2470 void QQuickTextInput::focusInEvent(QFocusEvent *event)
2472 Q_D(const QQuickTextInput);
2473 if (d->focusOnPress && !d->m_readOnly)
2474 openSoftwareInputPanel();
2475 QQuickImplicitSizeItem::focusInEvent(event);
2478 void QQuickTextInput::itemChange(ItemChange change, const ItemChangeData &value)
2480 Q_D(QQuickTextInput);
2481 if (change == ItemActiveFocusHasChanged) {
2482 bool hasFocus = value.boolValue;
2483 d->focused = hasFocus;
2484 setCursorVisible(hasFocus); // ### refactor: && d->canvas && d->canvas->hasFocus()
2485 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
2486 if (!hasFocus && (d->m_passwordEchoEditing || d->m_passwordEchoTimer.isActive())) {
2488 if (!hasFocus && d->m_passwordEchoEditing) {
2490 d->updatePasswordEchoEditing(false);//QQuickTextInputPrivate sets it on key events, but doesn't deal with focus events
2495 if (!d->persistentSelection)
2497 disconnect(qApp->inputMethod(), SIGNAL(inputDirectionChanged(Qt::LayoutDirection)),
2498 this, SLOT(q_updateAlignment()));
2500 q_updateAlignment();
2501 connect(qApp->inputMethod(), SIGNAL(inputDirectionChanged(Qt::LayoutDirection)),
2502 this, SLOT(q_updateAlignment()));
2505 QQuickItem::itemChange(change, value);
2509 \qmlproperty bool QtQuick2::TextInput::inputMethodComposing
2512 This property holds whether the TextInput has partial text input from an
2515 While it is composing an input method may rely on mouse or key events from
2516 the TextInput to edit or commit the partial text. This property can be
2517 used to determine when to disable events handlers that may interfere with
2518 the correct operation of an input method.
2520 bool QQuickTextInput::isInputMethodComposing() const
2522 Q_D(const QQuickTextInput);
2523 return d->preeditAreaText().length() > 0;
2526 void QQuickTextInputPrivate::init()
2528 Q_Q(QQuickTextInput);
2529 q->setSmooth(smooth);
2530 q->setAcceptedMouseButtons(Qt::LeftButton);
2531 q->setFlag(QQuickItem::ItemAcceptsInputMethod);
2532 q->setFlag(QQuickItem::ItemHasContents);
2533 #ifndef QT_NO_CLIPBOARD
2534 q->connect(QGuiApplication::clipboard(), SIGNAL(dataChanged()),
2535 q, SLOT(q_canPasteChanged()));
2536 #endif // QT_NO_CLIPBOARD
2538 lastSelectionStart = 0;
2539 lastSelectionEnd = 0;
2540 selectedTextColor = m_palette.color(QPalette::HighlightedText);
2541 selectionColor = m_palette.color(QPalette::Highlight);
2542 determineHorizontalAlignment();
2544 if (!qmlDisableDistanceField()) {
2545 QTextOption option = m_textLayout.textOption();
2546 option.setUseDesignMetrics(true);
2547 m_textLayout.setTextOption(option);
2551 void QQuickTextInput::updateCursorRectangle()
2553 Q_D(QQuickTextInput);
2554 if (!isComponentComplete())
2557 d->updateHorizontalScroll();
2558 d->updateVerticalScroll();
2559 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
2561 emit cursorRectangleChanged();
2562 if (d->cursorItem) {
2563 QRectF r = cursorRectangle();
2564 d->cursorItem->setPos(r.topLeft());
2565 d->cursorItem->setHeight(r.height());
2567 updateInputMethod(Qt::ImCursorRectangle);
2570 void QQuickTextInput::selectionChanged()
2572 Q_D(QQuickTextInput);
2573 d->textLayoutDirty = true; //TODO: Only update rect in selection
2574 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
2576 emit selectedTextChanged();
2578 if (d->lastSelectionStart != d->selectionStart()) {
2579 d->lastSelectionStart = d->selectionStart();
2580 if (d->lastSelectionStart == -1)
2581 d->lastSelectionStart = d->m_cursor;
2582 emit selectionStartChanged();
2584 if (d->lastSelectionEnd != d->selectionEnd()) {
2585 d->lastSelectionEnd = d->selectionEnd();
2586 if (d->lastSelectionEnd == -1)
2587 d->lastSelectionEnd = d->m_cursor;
2588 emit selectionEndChanged();
2592 void QQuickTextInputPrivate::showCursor()
2594 if (textNode != 0 && textNode->cursorNode() != 0)
2595 textNode->cursorNode()->setColor(color);
2598 void QQuickTextInputPrivate::hideCursor()
2600 if (textNode != 0 && textNode->cursorNode() != 0)
2601 textNode->cursorNode()->setColor(QColor(0, 0, 0, 0));
2604 QRectF QQuickTextInput::boundingRect() const
2606 Q_D(const QQuickTextInput);
2608 int cursorWidth = d->cursorItem ? d->cursorItem->width() : d->m_cursorWidth;
2610 // Could include font max left/right bearings to either side of rectangle.
2611 QRectF r = QQuickImplicitSizeItem::boundingRect();
2612 r.setRight(r.right() + cursorWidth);
2616 void QQuickTextInput::q_canPasteChanged()
2618 Q_D(QQuickTextInput);
2619 bool old = d->canPaste;
2620 #ifndef QT_NO_CLIPBOARD
2621 if (const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData())
2622 d->canPaste = !d->m_readOnly && mimeData->hasText();
2624 d->canPaste = false;
2627 bool changed = d->canPaste != old || !d->canPasteValid;
2628 d->canPasteValid = true;
2630 emit canPasteChanged();
2634 void QQuickTextInput::q_updateAlignment()
2636 Q_D(QQuickTextInput);
2637 if (d->determineHorizontalAlignment()) {
2639 updateCursorRectangle();
2643 // ### these should come from QStyleHints
2644 const int textCursorWidth = 1;
2645 const bool fullWidthSelection = true;
2650 Updates the display text based of the current edit text
2651 If the text has changed will emit displayTextChanged()
2653 void QQuickTextInputPrivate::updateDisplayText(bool forceUpdate)
2655 QString orig = m_textLayout.text();
2657 if (m_echoMode == QQuickTextInput::NoEcho)
2658 str = QString::fromLatin1("");
2662 if (m_echoMode == QQuickTextInput::Password) {
2663 str.fill(m_passwordCharacter);
2664 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
2665 if (m_passwordEchoTimer.isActive() && m_cursor > 0 && m_cursor <= m_text.length()) {
2666 int cursor = m_cursor - 1;
2667 QChar uc = m_text.at(cursor);
2669 if (cursor > 0 && uc.unicode() >= 0xdc00 && uc.unicode() < 0xe000) {
2670 // second half of a surrogate, check if we have the first half as well,
2671 // if yes restore both at once
2672 uc = m_text.at(cursor - 1);
2673 if (uc.unicode() >= 0xd800 && uc.unicode() < 0xdc00)
2674 str[cursor - 1] = uc;
2678 } else if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit && !m_passwordEchoEditing) {
2679 str.fill(m_passwordCharacter);
2682 // replace certain non-printable characters with spaces (to avoid
2683 // drawing boxes when using fonts that don't have glyphs for such
2685 QChar* uc = str.data();
2686 for (int i = 0; i < (int)str.length(); ++i) {
2687 if ((uc[i] < 0x20 && uc[i] != 0x09)
2688 || uc[i] == QChar::LineSeparator
2689 || uc[i] == QChar::ParagraphSeparator
2690 || uc[i] == QChar::ObjectReplacementCharacter)
2691 uc[i] = QChar(0x0020);
2694 if (str != orig || forceUpdate) {
2695 m_textLayout.setText(str);
2696 updateLayout(); // polish?
2697 emit q_func()->displayTextChanged();
2701 void QQuickTextInputPrivate::updateLayout()
2703 Q_Q(QQuickTextInput);
2705 if (!q->isComponentComplete())
2708 const QRectF previousRect = boundingRect;
2710 QTextOption option = m_textLayout.textOption();
2711 option.setTextDirection(layoutDirection());
2712 option.setFlags(QTextOption::IncludeTrailingSpaces);
2713 option.setWrapMode(QTextOption::WrapMode(wrapMode));
2714 option.setAlignment(Qt::Alignment(q->effectiveHAlign()));
2715 m_textLayout.setTextOption(option);
2716 m_textLayout.setFont(font);
2718 boundingRect = QRectF();
2719 m_textLayout.beginLayout();
2720 QTextLine line = m_textLayout.createLine();
2721 qreal lineWidth = q->widthValid() ? q->width() : INT_MAX;
2723 QTextLine firstLine = line;
2725 line.setLineWidth(lineWidth);
2726 line.setPosition(QPointF(line.position().x(), height));
2727 boundingRect = boundingRect.united(line.naturalTextRect());
2729 height += line.height();
2730 line = m_textLayout.createLine();
2731 } while (line.isValid());
2732 m_textLayout.endLayout();
2734 option.setWrapMode(QTextOption::NoWrap);
2735 m_textLayout.setTextOption(option);
2737 m_ascent = qRound(firstLine.ascent());
2738 textLayoutDirty = true;
2740 updateType = UpdatePaintNode;
2742 q->setImplicitSize(qCeil(boundingRect.width()), qCeil(boundingRect.height()));
2744 if (previousRect != boundingRect)
2745 emit q->contentSizeChanged();
2748 #ifndef QT_NO_CLIPBOARD
2752 Copies the currently selected text into the clipboard using the given
2755 \note If the echo mode is set to a mode other than Normal then copy
2756 will not work. This is to prevent using copy as a method of bypassing
2757 password features of the line control.
2759 void QQuickTextInputPrivate::copy(QClipboard::Mode mode) const
2761 QString t = selectedText();
2762 if (!t.isEmpty() && m_echoMode == QQuickTextInput::Normal) {
2763 QGuiApplication::clipboard()->setText(t, mode);
2770 Inserts the text stored in the application clipboard into the line
2775 void QQuickTextInputPrivate::paste(QClipboard::Mode clipboardMode)
2777 QString clip = QGuiApplication::clipboard()->text(clipboardMode);
2778 if (!clip.isEmpty() || hasSelectedText()) {
2779 separate(); //make it a separate undo/redo command
2785 #endif // !QT_NO_CLIPBOARD
2790 Exits preedit mode and commits parts marked as tentative commit
2792 void QQuickTextInputPrivate::commitPreedit()
2797 qApp->inputMethod()->reset();
2799 if (!m_tentativeCommit.isEmpty()) {
2800 internalInsert(m_tentativeCommit);
2801 m_tentativeCommit.clear();
2802 finishChange(-1, true/*not used, not documented*/, false);
2805 m_preeditCursor = 0;
2806 m_textLayout.setPreeditArea(-1, QString());
2807 m_textLayout.clearAdditionalFormats();
2814 Handles the behavior for the backspace key or function.
2815 Removes the current selection if there is a selection, otherwise
2816 removes the character prior to the cursor position.
2820 void QQuickTextInputPrivate::backspace()
2822 int priorState = m_undoState;
2823 if (hasSelectedText()) {
2824 removeSelectedText();
2825 } else if (m_cursor) {
2828 m_cursor = prevMaskBlank(m_cursor);
2829 QChar uc = m_text.at(m_cursor);
2830 if (m_cursor > 0 && uc.unicode() >= 0xdc00 && uc.unicode() < 0xe000) {
2831 // second half of a surrogate, check if we have the first half as well,
2832 // if yes delete both at once
2833 uc = m_text.at(m_cursor - 1);
2834 if (uc.unicode() >= 0xd800 && uc.unicode() < 0xdc00) {
2835 internalDelete(true);
2839 internalDelete(true);
2841 finishChange(priorState);
2847 Handles the behavior for the delete key or function.
2848 Removes the current selection if there is a selection, otherwise
2849 removes the character after the cursor position.
2853 void QQuickTextInputPrivate::del()
2855 int priorState = m_undoState;
2856 if (hasSelectedText()) {
2857 removeSelectedText();
2859 int n = m_textLayout.nextCursorPosition(m_cursor) - m_cursor;
2863 finishChange(priorState);
2869 Inserts the given \a newText at the current cursor position.
2870 If there is any selected text it is removed prior to insertion of
2873 void QQuickTextInputPrivate::insert(const QString &newText)
2875 int priorState = m_undoState;
2876 removeSelectedText();
2877 internalInsert(newText);
2878 finishChange(priorState);
2884 Clears the line control text.
2886 void QQuickTextInputPrivate::clear()
2888 int priorState = m_undoState;
2890 m_selend = m_text.length();
2891 removeSelectedText();
2893 finishChange(priorState, /*update*/false, /*edited*/false);
2899 Sets \a length characters from the given \a start position as selected.
2900 The given \a start position must be within the current text for
2901 the line control. If \a length characters cannot be selected, then
2902 the selection will extend to the end of the current text.
2904 void QQuickTextInputPrivate::setSelection(int start, int length)
2906 Q_Q(QQuickTextInput);
2909 if (start < 0 || start > (int)m_text.length()){
2910 qWarning("QQuickTextInputPrivate::setSelection: Invalid start position");
2915 if (start == m_selstart && start + length == m_selend && m_cursor == m_selend)
2918 m_selend = qMin(start + length, (int)m_text.length());
2919 m_cursor = m_selend;
2920 } else if (length < 0){
2921 if (start == m_selend && start + length == m_selstart && m_cursor == m_selstart)
2923 m_selstart = qMax(start + length, 0);
2925 m_cursor = m_selstart;
2926 } else if (m_selstart != m_selend) {
2932 emitCursorPositionChanged();
2935 emit q->selectionChanged();
2936 emitCursorPositionChanged();
2937 q->updateInputMethod(Qt::ImCursorRectangle | Qt::ImAnchorPosition
2938 | Qt::ImCursorPosition | Qt::ImCurrentSelection);
2944 Initializes the line control with a starting text value of \a txt.
2946 void QQuickTextInputPrivate::init(const QString &txt)
2950 updateDisplayText();
2951 m_cursor = m_text.length();
2957 Sets the password echo editing to \a editing. If password echo editing
2958 is true, then the text of the password is displayed even if the echo
2959 mode is set to QLineEdit::PasswordEchoOnEdit. Password echoing editing
2960 does not affect other echo modes.
2962 void QQuickTextInputPrivate::updatePasswordEchoEditing(bool editing)
2964 cancelPasswordEchoTimer();
2965 m_passwordEchoEditing = editing;
2966 updateDisplayText();
2972 Fixes the current text so that it is valid given any set validators.
2974 Returns true if the text was changed. Otherwise returns false.
2976 bool QQuickTextInputPrivate::fixup() // this function assumes that validate currently returns != Acceptable
2978 #ifndef QT_NO_VALIDATOR
2980 QString textCopy = m_text;
2981 int cursorCopy = m_cursor;
2982 m_validator->fixup(textCopy);
2983 if (m_validator->validate(textCopy, cursorCopy) == QValidator::Acceptable) {
2984 if (textCopy != m_text || cursorCopy != m_cursor)
2985 internalSetText(textCopy, cursorCopy);
2996 Moves the cursor to the given position \a pos. If \a mark is true will
2997 adjust the currently selected text.
2999 void QQuickTextInputPrivate::moveCursor(int pos, bool mark)
3001 Q_Q(QQuickTextInput);
3004 if (pos != m_cursor) {
3007 pos = pos > m_cursor ? nextMaskBlank(pos) : prevMaskBlank(pos);
3011 if (m_selend > m_selstart && m_cursor == m_selstart)
3013 else if (m_selend > m_selstart && m_cursor == m_selend)
3014 anchor = m_selstart;
3017 m_selstart = qMin(anchor, pos);
3018 m_selend = qMax(anchor, pos);
3023 if (mark || m_selDirty) {
3025 emit q->selectionChanged();
3027 emitCursorPositionChanged();
3028 q->updateInputMethod();
3034 Applies the given input method event \a event to the text of the line
3037 void QQuickTextInputPrivate::processInputMethodEvent(QInputMethodEvent *event)
3039 Q_Q(QQuickTextInput);
3041 int priorState = -1;
3042 bool isGettingInput = !event->commitString().isEmpty()
3043 || event->preeditString() != preeditAreaText()
3044 || event->replacementLength() > 0;
3045 bool cursorPositionChanged = false;
3046 bool selectionChange = false;
3047 m_preeditDirty = event->preeditString() != preeditAreaText();
3049 if (isGettingInput) {
3050 // If any text is being input, remove selected text.
3051 priorState = m_undoState;
3052 if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit && !m_passwordEchoEditing) {
3053 updatePasswordEchoEditing(true);
3055 m_selend = m_text.length();
3057 removeSelectedText();
3060 int c = m_cursor; // cursor position after insertion of commit string
3061 if (event->replacementStart() <= 0)
3062 c += event->commitString().length() - qMin(-event->replacementStart(), event->replacementLength());
3064 m_cursor += event->replacementStart();
3068 // insert commit string
3069 if (event->replacementLength()) {
3070 m_selstart = m_cursor;
3071 m_selend = m_selstart + event->replacementLength();
3072 m_selend = qMin(m_selend, m_text.length());
3073 removeSelectedText();
3075 if (!event->commitString().isEmpty()) {
3076 internalInsert(event->commitString());
3077 cursorPositionChanged = true;
3080 m_cursor = qBound(0, c, m_text.length());
3082 for (int i = 0; i < event->attributes().size(); ++i) {
3083 const QInputMethodEvent::Attribute &a = event->attributes().at(i);
3084 if (a.type == QInputMethodEvent::Selection) {
3085 m_cursor = qBound(0, a.start + a.length, m_text.length());
3087 m_selstart = qMax(0, qMin(a.start, m_text.length()));
3088 m_selend = m_cursor;
3089 if (m_selend < m_selstart) {
3090 qSwap(m_selstart, m_selend);
3092 selectionChange = true;
3094 m_selstart = m_selend = 0;
3096 cursorPositionChanged = true;
3100 m_textLayout.setPreeditArea(m_cursor, event->preeditString());
3102 const int oldPreeditCursor = m_preeditCursor;
3103 m_preeditCursor = event->preeditString().length();
3104 m_hideCursor = false;
3105 QList<QTextLayout::FormatRange> formats;
3106 for (int i = 0; i < event->attributes().size(); ++i) {
3107 const QInputMethodEvent::Attribute &a = event->attributes().at(i);
3108 if (a.type == QInputMethodEvent::Cursor) {
3109 m_preeditCursor = a.start;
3110 m_hideCursor = !a.length;
3111 } else if (a.type == QInputMethodEvent::TextFormat) {
3112 QTextCharFormat f = qvariant_cast<QTextFormat>(a.value).toCharFormat();
3114 QTextLayout::FormatRange o;
3115 o.start = a.start + m_cursor;
3116 o.length = a.length;
3122 m_textLayout.setAdditionalFormats(formats);
3124 updateDisplayText(/*force*/ true);
3125 if (cursorPositionChanged) {
3126 emitCursorPositionChanged();
3127 } else if (m_preeditCursor != oldPreeditCursor) {
3128 q->updateCursorRectangle();
3131 bool tentativeCommitChanged = m_tentativeCommit != event->tentativeCommitString();
3133 if (tentativeCommitChanged) {
3135 m_tentativeCommit = event->tentativeCommitString();
3138 if (isGettingInput || tentativeCommitChanged)
3139 finishChange(priorState);
3141 if (selectionChange) {
3142 emit q->selectionChanged();
3143 q->updateInputMethod(Qt::ImCursorRectangle | Qt::ImAnchorPosition
3144 | Qt::ImCursorPosition | Qt::ImCurrentSelection);
3151 Sets the selection to cover the word at the given cursor position.
3152 The word boundaries are defined by the behavior of QTextLayout::SkipWords
3155 void QQuickTextInputPrivate::selectWordAtPos(int cursor)
3157 int next = cursor + 1;
3160 int c = m_textLayout.previousCursorPosition(next, QTextLayout::SkipWords);
3161 moveCursor(c, false);
3162 // ## text layout should support end of words.
3163 int end = m_textLayout.nextCursorPosition(c, QTextLayout::SkipWords);
3164 while (end > cursor && m_text[end-1].isSpace())
3166 moveCursor(end, true);
3172 Completes a change to the line control text. If the change is not valid
3173 will undo the line control state back to the given \a validateFromState.
3175 If \a edited is true and the change is valid, will emit textEdited() in
3176 addition to textChanged(). Otherwise only emits textChanged() on a valid
3179 The \a update value is currently unused.
3181 bool QQuickTextInputPrivate::finishChange(int validateFromState, bool update, bool /*edited*/)
3183 Q_Q(QQuickTextInput);
3186 bool inputMethodAttributesChanged = m_textDirty || m_selDirty;
3187 bool alignmentChanged = false;
3191 bool wasValidInput = m_validInput;
3192 bool wasAcceptable = m_acceptableInput;
3193 m_validInput = true;
3194 m_acceptableInput = true;
3195 #ifndef QT_NO_VALIDATOR
3197 QString textCopy = m_text;
3198 int cursorCopy = m_cursor;
3199 QValidator::State state = m_validator->validate(textCopy, cursorCopy);
3200 m_validInput = state != QValidator::Invalid;
3201 m_acceptableInput = state == QValidator::Acceptable;
3203 if (m_text != textCopy) {
3204 internalSetText(textCopy, cursorCopy);
3207 m_cursor = cursorCopy;
3209 if (!m_tentativeCommit.isEmpty()) {
3210 textCopy.insert(m_cursor, m_tentativeCommit);
3211 bool validInput = m_validator->validate(textCopy, cursorCopy) != QValidator::Invalid;
3213 m_tentativeCommit.clear();
3216 m_tentativeCommit.clear();
3220 if (validateFromState >= 0 && wasValidInput && !m_validInput) {
3221 if (m_transactions.count())
3223 internalUndo(validateFromState);
3224 m_history.resize(m_undoState);
3225 if (m_modifiedState > m_undoState)
3226 m_modifiedState = -1;
3227 m_validInput = true;
3228 m_acceptableInput = wasAcceptable;
3229 m_textDirty = false;
3233 m_textDirty = false;
3234 m_preeditDirty = false;
3235 alignmentChanged = determineHorizontalAlignment();
3236 emit q->textChanged();
3239 updateDisplayText(alignmentChanged);
3241 if (m_acceptableInput != wasAcceptable)
3242 emit q->acceptableInputChanged();
3244 if (m_preeditDirty) {
3245 m_preeditDirty = false;
3246 if (determineHorizontalAlignment()) {
3247 alignmentChanged = true;
3254 emit q->selectionChanged();
3257 inputMethodAttributesChanged |= (m_cursor == m_lastCursorPos);
3258 if (inputMethodAttributesChanged)
3259 q->updateInputMethod();
3260 emitUndoRedoChanged();
3262 if (!emitCursorPositionChanged() && alignmentChanged)
3263 q->updateCursorRectangle();
3271 An internal function for setting the text of the line control.
3273 void QQuickTextInputPrivate::internalSetText(const QString &txt, int pos, bool edited)
3275 Q_Q(QQuickTextInput);
3277 QString oldText = m_text;
3279 m_text = maskString(0, txt, true);
3280 m_text += clearString(m_text.length(), m_maxLength - m_text.length());
3282 m_text = txt.isEmpty() ? txt : txt.left(m_maxLength);
3285 m_modifiedState = m_undoState = 0;
3286 m_cursor = (pos < 0 || pos > m_text.length()) ? m_text.length() : pos;
3287 m_textDirty = (oldText != m_text);
3289 bool changed = finishChange(-1, true, edited);
3290 #ifdef QT_NO_ACCESSIBILITY
3294 QAccessible::updateAccessibility(QAccessibleEvent(QAccessible::TextUpdated, q, 0));
3302 Adds the given \a command to the undo history
3303 of the line control. Does not apply the command.
3305 void QQuickTextInputPrivate::addCommand(const Command &cmd)
3307 if (m_separator && m_undoState && m_history[m_undoState - 1].type != Separator) {
3308 m_history.resize(m_undoState + 2);
3309 m_history[m_undoState++] = Command(Separator, m_cursor, 0, m_selstart, m_selend);
3311 m_history.resize(m_undoState + 1);
3313 m_separator = false;
3314 m_history[m_undoState++] = cmd;
3320 Inserts the given string \a s into the line
3323 Also adds the appropriate commands into the undo history.
3324 This function does not call finishChange(), and may leave the text
3325 in an invalid state.
3327 void QQuickTextInputPrivate::internalInsert(const QString &s)
3329 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
3330 Q_Q(QQuickTextInput);
3331 if (m_echoMode == QQuickTextInput::Password)
3332 m_passwordEchoTimer.start(qt_passwordEchoDelay, q);
3334 if (hasSelectedText())
3335 addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
3337 QString ms = maskString(m_cursor, s);
3338 for (int i = 0; i < (int) ms.length(); ++i) {
3339 addCommand (Command(DeleteSelection, m_cursor + i, m_text.at(m_cursor + i), -1, -1));
3340 addCommand(Command(Insert, m_cursor + i, ms.at(i), -1, -1));
3342 m_text.replace(m_cursor, ms.length(), ms);
3343 m_cursor += ms.length();
3344 m_cursor = nextMaskBlank(m_cursor);
3347 int remaining = m_maxLength - m_text.length();
3348 if (remaining != 0) {
3349 m_text.insert(m_cursor, s.left(remaining));
3350 for (int i = 0; i < (int) s.left(remaining).length(); ++i)
3351 addCommand(Command(Insert, m_cursor++, s.at(i), -1, -1));
3360 deletes a single character from the current text. If \a wasBackspace,
3361 the character prior to the cursor is removed. Otherwise the character
3362 after the cursor is removed.
3364 Also adds the appropriate commands into the undo history.
3365 This function does not call finishChange(), and may leave the text
3366 in an invalid state.
3368 void QQuickTextInputPrivate::internalDelete(bool wasBackspace)
3370 if (m_cursor < (int) m_text.length()) {
3371 cancelPasswordEchoTimer();
3372 if (hasSelectedText())
3373 addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
3374 addCommand(Command((CommandType)((m_maskData ? 2 : 0) + (wasBackspace ? Remove : Delete)),
3375 m_cursor, m_text.at(m_cursor), -1, -1));
3377 m_text.replace(m_cursor, 1, clearString(m_cursor, 1));
3378 addCommand(Command(Insert, m_cursor, m_text.at(m_cursor), -1, -1));
3380 m_text.remove(m_cursor, 1);
3389 removes the currently selected text from the line control.
3391 Also adds the appropriate commands into the undo history.
3392 This function does not call finishChange(), and may leave the text
3393 in an invalid state.
3395 void QQuickTextInputPrivate::removeSelectedText()
3397 if (m_selstart < m_selend && m_selend <= (int) m_text.length()) {
3398 cancelPasswordEchoTimer();
3401 addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
3402 if (m_selstart <= m_cursor && m_cursor < m_selend) {
3403 // cursor is within the selection. Split up the commands
3404 // to be able to restore the correct cursor position
3405 for (i = m_cursor; i >= m_selstart; --i)
3406 addCommand (Command(DeleteSelection, i, m_text.at(i), -1, 1));
3407 for (i = m_selend - 1; i > m_cursor; --i)
3408 addCommand (Command(DeleteSelection, i - m_cursor + m_selstart - 1, m_text.at(i), -1, -1));
3410 for (i = m_selend-1; i >= m_selstart; --i)
3411 addCommand (Command(RemoveSelection, i, m_text.at(i), -1, -1));
3414 m_text.replace(m_selstart, m_selend - m_selstart, clearString(m_selstart, m_selend - m_selstart));
3415 for (int i = 0; i < m_selend - m_selstart; ++i)
3416 addCommand(Command(Insert, m_selstart + i, m_text.at(m_selstart + i), -1, -1));
3418 m_text.remove(m_selstart, m_selend - m_selstart);
3420 if (m_cursor > m_selstart)
3421 m_cursor -= qMin(m_cursor, m_selend) - m_selstart;
3430 Parses the input mask specified by \a maskFields to generate
3431 the mask data used to handle input masks.
3433 void QQuickTextInputPrivate::parseInputMask(const QString &maskFields)
3435 int delimiter = maskFields.indexOf(QLatin1Char(';'));
3436 if (maskFields.isEmpty() || delimiter == 0) {
3438 delete [] m_maskData;
3440 m_maxLength = 32767;
3441 internalSetText(QString());
3446 if (delimiter == -1) {
3447 m_blank = QLatin1Char(' ');
3448 m_inputMask = maskFields;
3450 m_inputMask = maskFields.left(delimiter);
3451 m_blank = (delimiter + 1 < maskFields.length()) ? maskFields[delimiter + 1] : QLatin1Char(' ');
3454 // calculate m_maxLength / m_maskData length
3457 for (int i=0; i<m_inputMask.length(); i++) {
3458 c = m_inputMask.at(i);
3459 if (i > 0 && m_inputMask.at(i-1) == QLatin1Char('\\')) {
3463 if (c != QLatin1Char('\\') && c != QLatin1Char('!') &&
3464 c != QLatin1Char('<') && c != QLatin1Char('>') &&
3465 c != QLatin1Char('{') && c != QLatin1Char('}') &&
3466 c != QLatin1Char('[') && c != QLatin1Char(']'))
3470 delete [] m_maskData;
3471 m_maskData = new MaskInputData[m_maxLength];
3473 MaskInputData::Casemode m = MaskInputData::NoCaseMode;
3476 bool escape = false;
3478 for (int i = 0; i < m_inputMask.length(); i++) {
3479 c = m_inputMask.at(i);
3482 m_maskData[index].maskChar = c;
3483 m_maskData[index].separator = s;
3484 m_maskData[index].caseMode = m;
3487 } else if (c == QLatin1Char('<')) {
3488 m = MaskInputData::Lower;
3489 } else if (c == QLatin1Char('>')) {
3490 m = MaskInputData::Upper;
3491 } else if (c == QLatin1Char('!')) {
3492 m = MaskInputData::NoCaseMode;
3493 } else if (c != QLatin1Char('{') && c != QLatin1Char('}') && c != QLatin1Char('[') && c != QLatin1Char(']')) {
3494 switch (c.unicode()) {
3520 m_maskData[index].maskChar = c;
3521 m_maskData[index].separator = s;
3522 m_maskData[index].caseMode = m;
3527 internalSetText(m_text);
3534 checks if the key is valid compared to the inputMask
3536 bool QQuickTextInputPrivate::isValidInput(QChar key, QChar mask) const
3538 switch (mask.unicode()) {
3544 if (key.isLetter() || key == m_blank)
3548 if (key.isLetterOrNumber())
3552 if (key.isLetterOrNumber() || key == m_blank)
3560 if (key.isPrint() || key == m_blank)
3568 if (key.isNumber() || key == m_blank)
3572 if (key.isNumber() && key.digitValue() > 0)
3576 if ((key.isNumber() && key.digitValue() > 0) || key == m_blank)
3580 if (key.isNumber() || key == QLatin1Char('+') || key == QLatin1Char('-') || key == m_blank)
3584 if (key == QLatin1Char('0') || key == QLatin1Char('1'))
3588 if (key == QLatin1Char('0') || key == QLatin1Char('1') || key == m_blank)
3592 if (key.isNumber() || (key >= QLatin1Char('a') && key <= QLatin1Char('f')) || (key >= QLatin1Char('A') && key <= QLatin1Char('F')))
3596 if (key.isNumber() || (key >= QLatin1Char('a') && key <= QLatin1Char('f')) || (key >= QLatin1Char('A') && key <= QLatin1Char('F')) || key == m_blank)
3608 Returns true if the given text \a str is valid for any
3609 validator or input mask set for the line control.
3611 Otherwise returns false
3613 QQuickTextInputPrivate::ValidatorState QQuickTextInputPrivate::hasAcceptableInput(const QString &str) const
3615 #ifndef QT_NO_VALIDATOR
3616 QString textCopy = str;
3617 int cursorCopy = m_cursor;
3619 QValidator::State state = m_validator->validate(textCopy, cursorCopy);
3620 if (state != QValidator::Acceptable)
3621 return ValidatorState(state);
3626 return AcceptableInput;
3628 if (str.length() != m_maxLength)
3629 return InvalidInput;
3631 for (int i=0; i < m_maxLength; ++i) {
3632 if (m_maskData[i].separator) {
3633 if (str.at(i) != m_maskData[i].maskChar)
3634 return InvalidInput;
3636 if (!isValidInput(str.at(i), m_maskData[i].maskChar))
3637 return InvalidInput;
3640 return AcceptableInput;
3646 Applies the inputMask on \a str starting from position \a pos in the mask. \a clear
3647 specifies from where characters should be gotten when a separator is met in \a str - true means
3648 that blanks will be used, false that previous input is used.
3649 Calling this when no inputMask is set is undefined.
3651 QString QQuickTextInputPrivate::maskString(uint pos, const QString &str, bool clear) const
3653 if (pos >= (uint)m_maxLength)
3654 return QString::fromLatin1("");
3657 fill = clear ? clearString(0, m_maxLength) : m_text;
3660 QString s = QString::fromLatin1("");
3662 while (i < m_maxLength) {
3663 if (strIndex < str.length()) {
3664 if (m_maskData[i].separator) {
3665 s += m_maskData[i].maskChar;
3666 if (str[(int)strIndex] == m_maskData[i].maskChar)
3670 if (isValidInput(str[(int)strIndex], m_maskData[i].maskChar)) {
3671 switch (m_maskData[i].caseMode) {
3672 case MaskInputData::Upper:
3673 s += str[(int)strIndex].toUpper();
3675 case MaskInputData::Lower:
3676 s += str[(int)strIndex].toLower();
3679 s += str[(int)strIndex];
3683 // search for separator first
3684 int n = findInMask(i, true, true, str[(int)strIndex]);
3686 if (str.length() != 1 || i == 0 || (i > 0 && (!m_maskData[i-1].separator || m_maskData[i-1].maskChar != str[(int)strIndex]))) {
3687 s += fill.mid(i, n-i+1);
3688 i = n + 1; // update i to find + 1
3691 // search for valid m_blank if not
3692 n = findInMask(i, true, false, str[(int)strIndex]);
3694 s += fill.mid(i, n-i);
3695 switch (m_maskData[n].caseMode) {
3696 case MaskInputData::Upper:
3697 s += str[(int)strIndex].toUpper();
3699 case MaskInputData::Lower:
3700 s += str[(int)strIndex].toLower();
3703 s += str[(int)strIndex];
3705 i = n + 1; // updates i to find + 1
3723 Returns a "cleared" string with only separators and blank chars.
3724 Calling this when no inputMask is set is undefined.
3726 QString QQuickTextInputPrivate::clearString(uint pos, uint len) const
3728 if (pos >= (uint)m_maxLength)
3732 int end = qMin((uint)m_maxLength, pos + len);
3733 for (int i = pos; i < end; ++i)
3734 if (m_maskData[i].separator)
3735 s += m_maskData[i].maskChar;
3745 Strips blank parts of the input in a QQuickTextInputPrivate when an inputMask is set,
3746 separators are still included. Typically "127.0__.0__.1__" becomes "127.0.0.1".
3748 QString QQuickTextInputPrivate::stripString(const QString &str) const
3754 int end = qMin(m_maxLength, (int)str.length());
3755 for (int i = 0; i < end; ++i) {
3756 if (m_maskData[i].separator)
3757 s += m_maskData[i].maskChar;
3758 else if (str[i] != m_blank)
3767 searches forward/backward in m_maskData for either a separator or a m_blank
3769 int QQuickTextInputPrivate::findInMask(int pos, bool forward, bool findSeparator, QChar searchChar) const
3771 if (pos >= m_maxLength || pos < 0)
3774 int end = forward ? m_maxLength : -1;
3775 int step = forward ? 1 : -1;
3779 if (findSeparator) {
3780 if (m_maskData[i].separator && m_maskData[i].maskChar == searchChar)
3783 if (!m_maskData[i].separator) {
3784 if (searchChar.isNull())
3786 else if (isValidInput(searchChar, m_maskData[i].maskChar))
3795 void QQuickTextInputPrivate::internalUndo(int until)
3797 if (!isUndoAvailable())
3799 cancelPasswordEchoTimer();
3801 while (m_undoState && m_undoState > until) {
3802 Command& cmd = m_history[--m_undoState];
3805 m_text.remove(cmd.pos, 1);
3809 m_selstart = cmd.selStart;
3810 m_selend = cmd.selEnd;
3814 case RemoveSelection:
3815 m_text.insert(cmd.pos, cmd.uc);
3816 m_cursor = cmd.pos + 1;
3819 case DeleteSelection:
3820 m_text.insert(cmd.pos, cmd.uc);
3826 if (until < 0 && m_undoState) {
3827 Command& next = m_history[m_undoState-1];
3828 if (next.type != cmd.type && next.type < RemoveSelection
3829 && (cmd.type < RemoveSelection || next.type == Separator))
3836 void QQuickTextInputPrivate::internalRedo()
3838 if (!isRedoAvailable())
3841 while (m_undoState < (int)m_history.size()) {
3842 Command& cmd = m_history[m_undoState++];
3845 m_text.insert(cmd.pos, cmd.uc);
3846 m_cursor = cmd.pos + 1;
3849 m_selstart = cmd.selStart;
3850 m_selend = cmd.selEnd;
3855 case RemoveSelection:
3856 case DeleteSelection:
3857 m_text.remove(cmd.pos, 1);
3858 m_selstart = cmd.selStart;
3859 m_selend = cmd.selEnd;
3863 m_selstart = cmd.selStart;
3864 m_selend = cmd.selEnd;
3868 if (m_undoState < (int)m_history.size()) {
3869 Command& next = m_history[m_undoState];
3870 if (next.type != cmd.type && cmd.type < RemoveSelection && next.type != Separator
3871 && (next.type < RemoveSelection || cmd.type == Separator))
3878 void QQuickTextInputPrivate::emitUndoRedoChanged()
3880 Q_Q(QQuickTextInput);
3881 const bool previousUndo = canUndo;
3882 const bool previousRedo = canRedo;
3884 canUndo = isUndoAvailable();
3885 canRedo = isRedoAvailable();
3887 if (previousUndo != canUndo)
3888 emit q->canUndoChanged();
3889 if (previousRedo != canRedo)
3890 emit q->canRedoChanged();
3896 If the current cursor position differs from the last emitted cursor
3897 position, emits cursorPositionChanged().
3899 bool QQuickTextInputPrivate::emitCursorPositionChanged()
3901 Q_Q(QQuickTextInput);
3902 if (m_cursor != m_lastCursorPos) {
3903 m_lastCursorPos = m_cursor;
3905 q->updateCursorRectangle();
3906 emit q->cursorPositionChanged();
3907 // XXX todo - not in 4.8?
3909 resetCursorBlinkTimer();
3912 if (!hasSelectedText()) {
3913 if (lastSelectionStart != m_cursor) {
3914 lastSelectionStart = m_cursor;
3915 emit q->selectionStartChanged();
3917 if (lastSelectionEnd != m_cursor) {
3918 lastSelectionEnd = m_cursor;
3919 emit q->selectionEndChanged();
3923 #ifndef QT_NO_ACCESSIBILITY
3924 QAccessible::updateAccessibility(QAccessibleEvent(QAccessible::TextCaretMoved, q, 0));
3933 void QQuickTextInputPrivate::setCursorBlinkPeriod(int msec)
3935 Q_Q(QQuickTextInput);
3936 if (msec == m_blinkPeriod)
3939 q->killTimer(m_blinkTimer);
3942 m_blinkTimer = q->startTimer(msec / 2);
3946 if (m_blinkStatus == 1) {
3947 updateType = UpdatePaintNode;
3951 m_blinkPeriod = msec;
3954 void QQuickTextInputPrivate::resetCursorBlinkTimer()
3956 Q_Q(QQuickTextInput);
3957 if (m_blinkPeriod == 0 || m_blinkTimer == 0)
3959 q->killTimer(m_blinkTimer);
3960 m_blinkTimer = q->startTimer(m_blinkPeriod / 2);
3964 void QQuickTextInput::timerEvent(QTimerEvent *event)
3966 Q_D(QQuickTextInput);
3967 if (event->timerId() == d->m_blinkTimer) {
3968 d->m_blinkStatus = !d->m_blinkStatus;
3969 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
3971 } else if (event->timerId() == d->m_deleteAllTimer) {
3972 killTimer(d->m_deleteAllTimer);
3973 d->m_deleteAllTimer = 0;
3975 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
3976 } else if (event->timerId() == d->m_passwordEchoTimer.timerId()) {
3977 d->m_passwordEchoTimer.stop();
3978 d->updateDisplayText();
3983 void QQuickTextInputPrivate::processKeyEvent(QKeyEvent* event)
3985 Q_Q(QQuickTextInput);
3986 bool inlineCompletionAccepted = false;
3988 if (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return) {
3989 if (hasAcceptableInput(m_text) || fixup()) {
3992 if (inlineCompletionAccepted)
3999 if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit
4000 && !m_passwordEchoEditing
4002 && !event->text().isEmpty()
4003 && !(event->modifiers() & Qt::ControlModifier)) {
4004 // Clear the edit and reset to normal echo mode while editing; the
4005 // echo mode switches back when the edit loses focus
4006 // ### resets current content. dubious code; you can
4007 // navigate with keys up, down, back, and select(?), but if you press
4008 // "left" or "right" it clears?
4009 updatePasswordEchoEditing(true);
4013 bool unknown = false;
4014 bool visual = cursorMoveStyle() == Qt::VisualMoveStyle;
4018 #ifndef QT_NO_SHORTCUT
4019 else if (event == QKeySequence::Undo) {
4023 else if (event == QKeySequence::Redo) {
4027 else if (event == QKeySequence::SelectAll) {
4030 #ifndef QT_NO_CLIPBOARD
4031 else if (event == QKeySequence::Copy) {
4034 else if (event == QKeySequence::Paste) {
4036 QClipboard::Mode mode = QClipboard::Clipboard;
4040 else if (event == QKeySequence::Cut) {
4046 else if (event == QKeySequence::DeleteEndOfLine) {
4048 setSelection(m_cursor, end());
4053 #endif //QT_NO_CLIPBOARD
4054 else if (event == QKeySequence::MoveToStartOfLine || event == QKeySequence::MoveToStartOfBlock) {
4057 else if (event == QKeySequence::MoveToEndOfLine || event == QKeySequence::MoveToEndOfBlock) {
4060 else if (event == QKeySequence::SelectStartOfLine || event == QKeySequence::SelectStartOfBlock) {
4063 else if (event == QKeySequence::SelectEndOfLine || event == QKeySequence::SelectEndOfBlock) {
4066 else if (event == QKeySequence::MoveToNextChar) {
4067 if (hasSelectedText()) {
4068 moveCursor(selectionEnd(), false);
4070 cursorForward(0, visual ? 1 : (layoutDirection() == Qt::LeftToRight ? 1 : -1));
4073 else if (event == QKeySequence::SelectNextChar) {
4074 cursorForward(1, visual ? 1 : (layoutDirection() == Qt::LeftToRight ? 1 : -1));
4076 else if (event == QKeySequence::MoveToPreviousChar) {
4077 if (hasSelectedText()) {
4078 moveCursor(selectionStart(), false);
4080 cursorForward(0, visual ? -1 : (layoutDirection() == Qt::LeftToRight ? -1 : 1));
4083 else if (event == QKeySequence::SelectPreviousChar) {
4084 cursorForward(1, visual ? -1 : (layoutDirection() == Qt::LeftToRight ? -1 : 1));
4086 else if (event == QKeySequence::MoveToNextWord) {
4087 if (m_echoMode == QQuickTextInput::Normal)
4088 layoutDirection() == Qt::LeftToRight ? cursorWordForward(0) : cursorWordBackward(0);
4090 layoutDirection() == Qt::LeftToRight ? end(0) : home(0);
4092 else if (event == QKeySequence::MoveToPreviousWord) {
4093 if (m_echoMode == QQuickTextInput::Normal)
4094 layoutDirection() == Qt::LeftToRight ? cursorWordBackward(0) : cursorWordForward(0);
4095 else if (!m_readOnly) {
4096 layoutDirection() == Qt::LeftToRight ? home(0) : end(0);
4099 else if (event == QKeySequence::SelectNextWord) {
4100 if (m_echoMode == QQuickTextInput::Normal)
4101 layoutDirection() == Qt::LeftToRight ? cursorWordForward(1) : cursorWordBackward(1);
4103 layoutDirection() == Qt::LeftToRight ? end(1) : home(1);
4105 else if (event == QKeySequence::SelectPreviousWord) {
4106 if (m_echoMode == QQuickTextInput::Normal)
4107 layoutDirection() == Qt::LeftToRight ? cursorWordBackward(1) : cursorWordForward(1);
4109 layoutDirection() == Qt::LeftToRight ? home(1) : end(1);
4111 else if (event == QKeySequence::Delete) {
4115 else if (event == QKeySequence::DeleteEndOfWord) {
4117 cursorWordForward(true);
4121 else if (event == QKeySequence::DeleteStartOfWord) {
4123 cursorWordBackward(true);
4127 #endif // QT_NO_SHORTCUT
4129 bool handled = false;
4130 if (event->modifiers() & Qt::ControlModifier) {
4131 switch (event->key()) {
4132 case Qt::Key_Backspace:
4134 cursorWordBackward(true);
4142 } else { // ### check for *no* modifier
4143 switch (event->key()) {
4144 case Qt::Key_Backspace:
4156 if (event->key() == Qt::Key_Direction_L || event->key() == Qt::Key_Direction_R) {
4157 setLayoutDirection((event->key() == Qt::Key_Direction_L) ? Qt::LeftToRight : Qt::RightToLeft);
4161 if (unknown && !m_readOnly) {
4162 QString t = event->text();
4163 if (!t.isEmpty() && t.at(0).isPrint()) {