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/qinputpanel.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->inputPanel()->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->inputPanel()->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 q->setInputMethodHints(hints);
1116 \qmlproperty enumeration QtQuick2::TextInput::echoMode
1118 Specifies how the text should be displayed in the TextInput.
1120 \o TextInput.Normal - Displays the text as it is. (Default)
1121 \o TextInput.Password - Displays asterisks instead of characters.
1122 \o TextInput.NoEcho - Displays nothing.
1123 \o TextInput.PasswordEchoOnEdit - Displays characters as they are entered
1124 while editing, otherwise displays asterisks.
1127 QQuickTextInput::EchoMode QQuickTextInput::echoMode() const
1129 Q_D(const QQuickTextInput);
1130 return QQuickTextInput::EchoMode(d->m_echoMode);
1133 void QQuickTextInput::setEchoMode(QQuickTextInput::EchoMode echo)
1135 Q_D(QQuickTextInput);
1136 if (echoMode() == echo)
1138 d->cancelPasswordEchoTimer();
1139 d->m_echoMode = echo;
1140 d->m_passwordEchoEditing = false;
1141 d->updateInputMethodHints();
1142 d->updateDisplayText();
1143 updateCursorRectangle();
1145 emit echoModeChanged(echoMode());
1149 \qmlproperty enumeration QtQuick2::TextInput::inputMethodHints
1151 Provides hints to the input method about the expected content of the text input and how it
1154 The value is a bit-wise combination of flags, or Qt.ImhNone if no hints are set.
1156 Flags that alter behaviour are:
1159 \o Qt.ImhHiddenText - Characters should be hidden, as is typically used when entering passwords.
1160 This is automatically set when setting echoMode to \c TextInput.Password.
1161 \o Qt.ImhSensitiveData - Typed text should not be stored by the active input method
1162 in any persistent storage like predictive user dictionary.
1163 \o Qt.ImhNoAutoUppercase - The input method should not try to automatically switch to upper case
1164 when a sentence ends.
1165 \o Qt.ImhPreferNumbers - Numbers are preferred (but not required).
1166 \o Qt.ImhPreferUppercase - Upper case letters are preferred (but not required).
1167 \o Qt.ImhPreferLowercase - Lower case letters are preferred (but not required).
1168 \o Qt.ImhNoPredictiveText - Do not use predictive text (i.e. dictionary lookup) while typing.
1170 \o Qt.ImhDate - The text editor functions as a date field.
1171 \o Qt.ImhTime - The text editor functions as a time field.
1174 Flags that restrict input (exclusive flags) are:
1177 \o Qt.ImhDigitsOnly - Only digits are allowed.
1178 \o Qt.ImhFormattedNumbersOnly - Only number input is allowed. This includes decimal point and minus sign.
1179 \o Qt.ImhUppercaseOnly - Only upper case letter input is allowed.
1180 \o Qt.ImhLowercaseOnly - Only lower case letter input is allowed.
1181 \o Qt.ImhDialableCharactersOnly - Only characters suitable for phone dialing are allowed.
1182 \o Qt.ImhEmailCharactersOnly - Only characters suitable for email addresses are allowed.
1183 \o Qt.ImhUrlCharactersOnly - Only characters suitable for URLs are allowed.
1189 \o Qt.ImhExclusiveInputMask - This mask yields nonzero if any of the exclusive flags are used.
1193 Qt::InputMethodHints QQuickTextInput::imHints() const
1195 Q_D(const QQuickTextInput);
1196 return d->inputMethodHints;
1199 void QQuickTextInput::setIMHints(Qt::InputMethodHints hints)
1201 Q_D(QQuickTextInput);
1202 if (d->inputMethodHints == hints)
1204 d->inputMethodHints = hints;
1205 d->updateInputMethodHints();
1209 \qmlproperty Component QtQuick2::TextInput::cursorDelegate
1210 The delegate for the cursor in the TextInput.
1212 If you set a cursorDelegate for a TextInput, this delegate will be used for
1213 drawing the cursor instead of the standard cursor. An instance of the
1214 delegate will be created and managed by the TextInput when a cursor is
1215 needed, and the x property of delegate instance will be set so as
1216 to be one pixel before the top left of the current character.
1218 Note that the root item of the delegate component must be a QDeclarativeItem or
1219 QDeclarativeItem derived item.
1221 QDeclarativeComponent* QQuickTextInput::cursorDelegate() const
1223 Q_D(const QQuickTextInput);
1224 return d->cursorComponent;
1227 void QQuickTextInput::setCursorDelegate(QDeclarativeComponent* c)
1229 Q_D(QQuickTextInput);
1230 if (d->cursorComponent == c)
1233 d->cursorComponent = c;
1235 //note that the components are owned by something else
1236 delete d->cursorItem;
1238 d->startCreatingCursor();
1241 emit cursorDelegateChanged();
1244 void QQuickTextInputPrivate::startCreatingCursor()
1246 Q_Q(QQuickTextInput);
1247 if (cursorComponent->isReady()) {
1249 } else if (cursorComponent->isLoading()) {
1250 q->connect(cursorComponent, SIGNAL(statusChanged(int)),
1251 q, SLOT(createCursor()));
1253 qmlInfo(q, cursorComponent->errors()) << QQuickTextInput::tr("Could not load cursor delegate");
1257 void QQuickTextInput::createCursor()
1259 Q_D(QQuickTextInput);
1260 if (!isComponentComplete())
1263 if (d->cursorComponent->isError()) {
1264 qmlInfo(this, d->cursorComponent->errors()) << tr("Could not load cursor delegate");
1268 if (!d->cursorComponent->isReady())
1272 delete d->cursorItem;
1273 QDeclarativeContext *creationContext = d->cursorComponent->creationContext();
1274 QObject *object = d->cursorComponent->create(creationContext ? creationContext : qmlContext(this));
1275 d->cursorItem = qobject_cast<QQuickItem*>(object);
1276 if (!d->cursorItem) {
1278 qmlInfo(this, d->cursorComponent->errors()) << tr("Could not instantiate cursor delegate");
1282 QRectF r = cursorRectangle();
1284 QDeclarative_setParent_noEvent(d->cursorItem, this);
1285 d->cursorItem->setParentItem(this);
1286 d->cursorItem->setPos(r.topLeft());
1287 d->cursorItem->setHeight(r.height());
1291 \qmlmethod rect QtQuick2::TextInput::positionToRectangle(int pos)
1293 This function takes a character position and returns the rectangle that the
1294 cursor would occupy, if it was placed at that character position.
1296 This is similar to setting the cursorPosition, and then querying the cursor
1297 rectangle, but the cursorPosition is not changed.
1299 QRectF QQuickTextInput::positionToRectangle(int pos) const
1301 Q_D(const QQuickTextInput);
1302 if (d->m_echoMode == NoEcho)
1304 else if (pos > d->m_cursor)
1305 pos += d->preeditAreaText().length();
1306 QTextLine l = d->m_textLayout.lineForTextPosition(pos);
1308 ? QRectF(l.cursorToX(pos) - d->hscroll, l.y() - d->vscroll, d->m_cursorWidth, l.height())
1313 \qmlmethod int QtQuick2::TextInput::positionAt(real x, real y, CursorPosition position = CursorBetweenCharacters)
1315 This function returns the character position at
1316 x and y pixels from the top left of the textInput. Position 0 is before the
1317 first character, position 1 is after the first character but before the second,
1318 and so on until position text.length, which is after all characters.
1320 This means that for all x values before the first character this function returns 0,
1321 and for all x values after the last character this function returns text.length. If
1322 the y value is above the text the position will be that of the nearest character on
1323 the first line line and if it is below the text the position of the nearest character
1324 on the last line will be returned.
1326 The cursor position type specifies how the cursor position should be resolved.
1329 \o TextInput.CursorBetweenCharacters - Returns the position between characters that is nearest x.
1330 \o TextInput.CursorOnCharacter - Returns the position before the character that is nearest x.
1334 void QQuickTextInput::positionAt(QDeclarativeV8Function *args) const
1336 Q_D(const QQuickTextInput);
1340 QTextLine::CursorPosition position = QTextLine::CursorBetweenCharacters;
1342 if (args->Length() < 1)
1346 v8::Local<v8::Value> arg = (*args)[i];
1347 x = arg->NumberValue();
1349 if (++i < args->Length()) {
1351 y = arg->NumberValue();
1354 if (++i < args->Length()) {
1356 position = QTextLine::CursorPosition(arg->Int32Value());
1359 int pos = d->positionAt(x, y, position);
1360 const int cursor = d->m_cursor;
1362 const int preeditLength = d->preeditAreaText().length();
1363 pos = pos > cursor + preeditLength
1364 ? pos - preeditLength
1367 args->returnValue(v8::Int32::New(pos));
1370 int QQuickTextInputPrivate::positionAt(int x, int y, QTextLine::CursorPosition position) const
1374 QTextLine line = m_textLayout.lineAt(0);
1375 for (int i = 1; i < m_textLayout.lineCount(); ++i) {
1376 QTextLine nextLine = m_textLayout.lineAt(i);
1378 if (y < (line.rect().bottom() + nextLine.y()) / 2)
1382 return line.isValid() ? line.xToCursor(x, position) : 0;
1385 void QQuickTextInput::keyPressEvent(QKeyEvent* ev)
1387 Q_D(QQuickTextInput);
1388 // Don't allow MacOSX up/down support, and we don't allow a completer.
1389 bool ignore = (ev->key() == Qt::Key_Up || ev->key() == Qt::Key_Down) && ev->modifiers() == Qt::NoModifier;
1390 if (!ignore && (d->lastSelectionStart == d->lastSelectionEnd) && (ev->key() == Qt::Key_Right || ev->key() == Qt::Key_Left)) {
1391 // Ignore when moving off the end unless there is a selection,
1392 // because then moving will do something (deselect).
1393 int cursorPosition = d->m_cursor;
1394 if (cursorPosition == 0)
1395 ignore = ev->key() == (d->layoutDirection() == Qt::LeftToRight ? Qt::Key_Left : Qt::Key_Right);
1396 if (cursorPosition == text().length())
1397 ignore = ev->key() == (d->layoutDirection() == Qt::LeftToRight ? Qt::Key_Right : Qt::Key_Left);
1402 d->processKeyEvent(ev);
1404 if (!ev->isAccepted())
1405 QQuickImplicitSizeItem::keyPressEvent(ev);
1408 void QQuickTextInput::inputMethodEvent(QInputMethodEvent *ev)
1410 Q_D(QQuickTextInput);
1411 const bool wasComposing = d->preeditAreaText().length() > 0;
1412 if (d->m_readOnly) {
1415 d->processInputMethodEvent(ev);
1417 if (!ev->isAccepted())
1418 QQuickImplicitSizeItem::inputMethodEvent(ev);
1420 if (wasComposing != (d->m_textLayout.preeditAreaText().length() > 0))
1421 emit inputMethodComposingChanged();
1424 void QQuickTextInput::mouseDoubleClickEvent(QMouseEvent *event)
1426 Q_D(QQuickTextInput);
1428 if (d->selectByMouse && event->button() == Qt::LeftButton) {
1430 int cursor = d->positionAt(event->localPos());
1431 d->selectWordAtPos(cursor);
1432 event->setAccepted(true);
1433 if (!d->hasPendingTripleClick()) {
1434 d->tripleClickStartPoint = event->localPos().toPoint();
1435 d->tripleClickTimer.start();
1438 if (d->sendMouseEventToInputContext(event))
1440 QQuickImplicitSizeItem::mouseDoubleClickEvent(event);
1444 void QQuickTextInput::mousePressEvent(QMouseEvent *event)
1446 Q_D(QQuickTextInput);
1448 d->pressPos = event->localPos();
1450 if (d->focusOnPress) {
1451 bool hadActiveFocus = hasActiveFocus();
1453 // re-open input panel on press if already focused
1454 if (hasActiveFocus() && hadActiveFocus && !d->m_readOnly)
1455 openSoftwareInputPanel();
1457 if (d->selectByMouse) {
1458 setKeepMouseGrab(false);
1459 d->selectPressed = true;
1460 QPoint distanceVector = d->pressPos.toPoint() - d->tripleClickStartPoint;
1461 if (d->hasPendingTripleClick()
1462 && distanceVector.manhattanLength() < qApp->styleHints()->startDragDistance()) {
1463 event->setAccepted(true);
1469 if (d->sendMouseEventToInputContext(event))
1472 bool mark = (event->modifiers() & Qt::ShiftModifier) && d->selectByMouse;
1473 int cursor = d->positionAt(event->localPos());
1474 d->moveCursor(cursor, mark);
1475 event->setAccepted(true);
1478 void QQuickTextInput::mouseMoveEvent(QMouseEvent *event)
1480 Q_D(QQuickTextInput);
1482 if (d->selectPressed) {
1483 if (qAbs(int(event->localPos().x() - d->pressPos.x())) > qApp->styleHints()->startDragDistance())
1484 setKeepMouseGrab(true);
1486 if (d->composeMode()) {
1488 int startPos = d->positionAt(d->pressPos);
1489 int currentPos = d->positionAt(event->localPos());
1490 if (startPos != currentPos)
1491 d->setSelection(startPos, currentPos - startPos);
1493 moveCursorSelection(d->positionAt(event->localPos()), d->mouseSelectionMode);
1495 event->setAccepted(true);
1497 QQuickImplicitSizeItem::mouseMoveEvent(event);
1501 void QQuickTextInput::mouseReleaseEvent(QMouseEvent *event)
1503 Q_D(QQuickTextInput);
1504 if (d->sendMouseEventToInputContext(event))
1506 if (d->selectPressed) {
1507 d->selectPressed = false;
1508 setKeepMouseGrab(false);
1510 #ifndef QT_NO_CLIPBOARD
1511 if (QGuiApplication::clipboard()->supportsSelection()) {
1512 if (event->button() == Qt::LeftButton) {
1513 d->copy(QClipboard::Selection);
1514 } else if (!d->m_readOnly && event->button() == Qt::MidButton) {
1516 d->insert(QGuiApplication::clipboard()->text(QClipboard::Selection));
1520 if (!event->isAccepted())
1521 QQuickImplicitSizeItem::mouseReleaseEvent(event);
1524 bool QQuickTextInputPrivate::sendMouseEventToInputContext(QMouseEvent *event)
1526 #if !defined QT_NO_IM
1527 if (composeMode()) {
1528 int tmp_cursor = positionAt(event->localPos());
1529 int mousePos = tmp_cursor - m_cursor;
1530 if (mousePos >= 0 && mousePos <= m_textLayout.preeditAreaText().length()) {
1531 if (event->type() == QEvent::MouseButtonRelease) {
1532 qApp->inputPanel()->invokeAction(QInputPanel::Click, mousePos);
1545 void QQuickTextInput::mouseUngrabEvent()
1547 Q_D(QQuickTextInput);
1548 d->selectPressed = false;
1549 setKeepMouseGrab(false);
1552 bool QQuickTextInput::event(QEvent* ev)
1554 #ifndef QT_NO_SHORTCUT
1555 Q_D(QQuickTextInput);
1556 if (ev->type() == QEvent::ShortcutOverride) {
1559 QKeyEvent* ke = static_cast<QKeyEvent*>(ev);
1560 if (ke == QKeySequence::Copy
1561 || ke == QKeySequence::Paste
1562 || ke == QKeySequence::Cut
1563 || ke == QKeySequence::Redo
1564 || ke == QKeySequence::Undo
1565 || ke == QKeySequence::MoveToNextWord
1566 || ke == QKeySequence::MoveToPreviousWord
1567 || ke == QKeySequence::MoveToStartOfDocument
1568 || ke == QKeySequence::MoveToEndOfDocument
1569 || ke == QKeySequence::SelectNextWord
1570 || ke == QKeySequence::SelectPreviousWord
1571 || ke == QKeySequence::SelectStartOfLine
1572 || ke == QKeySequence::SelectEndOfLine
1573 || ke == QKeySequence::SelectStartOfBlock
1574 || ke == QKeySequence::SelectEndOfBlock
1575 || ke == QKeySequence::SelectStartOfDocument
1576 || ke == QKeySequence::SelectAll
1577 || ke == QKeySequence::SelectEndOfDocument) {
1579 } else if (ke->modifiers() == Qt::NoModifier || ke->modifiers() == Qt::ShiftModifier
1580 || ke->modifiers() == Qt::KeypadModifier) {
1581 if (ke->key() < Qt::Key_Escape) {
1585 switch (ke->key()) {
1586 case Qt::Key_Delete:
1589 case Qt::Key_Backspace:
1601 return QQuickImplicitSizeItem::event(ev);
1604 void QQuickTextInput::geometryChanged(const QRectF &newGeometry,
1605 const QRectF &oldGeometry)
1607 Q_D(QQuickTextInput);
1608 if (newGeometry.width() != oldGeometry.width())
1610 updateCursorRectangle();
1611 QQuickImplicitSizeItem::geometryChanged(newGeometry, oldGeometry);
1614 void QQuickTextInputPrivate::updateHorizontalScroll()
1616 Q_Q(QQuickTextInput);
1617 QTextLine currentLine = m_textLayout.lineForTextPosition(m_cursor + m_preeditCursor);
1618 const int preeditLength = m_textLayout.preeditAreaText().length();
1619 const int width = qMax(0, qFloor(q->width()));
1620 int widthUsed = currentLine.isValid() ? qRound(currentLine.naturalTextWidth()) : 0;
1621 int previousScroll = hscroll;
1623 if (!autoScroll || widthUsed <= width || m_echoMode == QQuickTextInput::NoEcho) {
1626 Q_ASSERT(currentLine.isValid());
1627 int cix = qRound(currentLine.cursorToX(m_cursor + preeditLength));
1628 if (cix - hscroll >= width) {
1629 // text doesn't fit, cursor is to the right of br (scroll right)
1630 hscroll = cix - width;
1631 } else if (cix - hscroll < 0 && hscroll < widthUsed) {
1632 // text doesn't fit, cursor is to the left of br (scroll left)
1634 } else if (widthUsed - hscroll < width) {
1635 // text doesn't fit, text document is to the left of br; align
1637 hscroll = widthUsed - width;
1639 if (preeditLength > 0) {
1640 // check to ensure long pre-edit text doesn't push the cursor
1642 cix = qRound(currentLine.cursorToX(m_cursor + qMax(0, m_preeditCursor - 1)));
1647 if (previousScroll != hscroll)
1648 textLayoutDirty = true;
1651 void QQuickTextInputPrivate::updateVerticalScroll()
1653 Q_Q(QQuickTextInput);
1654 const int preeditLength = m_textLayout.preeditAreaText().length();
1655 const int height = qMax(0, qFloor(q->height()));
1656 int heightUsed = boundingRect.height();
1657 int previousScroll = vscroll;
1659 if (!autoScroll || heightUsed <= height) {
1660 // text fits in br; use vscroll for alignment
1661 switch (vAlign & ~(Qt::AlignAbsolute|Qt::AlignHorizontal_Mask)) {
1662 case Qt::AlignBottom:
1663 vscroll = heightUsed - height;
1665 case Qt::AlignVCenter:
1666 vscroll = (heightUsed - height) / 2;
1674 QTextLine currentLine = m_textLayout.lineForTextPosition(m_cursor + preeditLength);
1675 QRectF r = currentLine.isValid() ? currentLine.rect() : QRectF();
1676 int top = qFloor(r.top());
1677 int bottom = qCeil(r.bottom());
1679 if (bottom - vscroll >= height) {
1680 // text doesn't fit, cursor is to the below the br (scroll down)
1681 vscroll = bottom - height;
1682 } else if (top - vscroll < 0 && vscroll < heightUsed) {
1683 // text doesn't fit, cursor is above br (scroll up)
1685 } else if (heightUsed - vscroll < height) {
1686 // text doesn't fit, text document is to the left of br; align
1688 vscroll = heightUsed - height;
1690 if (preeditLength > 0) {
1691 // check to ensure long pre-edit text doesn't push the cursor
1693 currentLine = m_textLayout.lineForTextPosition(m_cursor + qMax(0, m_preeditCursor - 1));
1694 top = currentLine.isValid() ? qRound(currentLine.rect().top()) : 0;
1699 if (previousScroll != vscroll)
1700 textLayoutDirty = true;
1703 void QQuickTextInput::triggerPreprocess()
1705 Q_D(QQuickTextInput);
1706 if (d->updateType == QQuickTextInputPrivate::UpdateNone)
1707 d->updateType = QQuickTextInputPrivate::UpdateOnlyPreprocess;
1711 QSGNode *QQuickTextInput::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data)
1714 Q_D(QQuickTextInput);
1716 if (d->updateType != QQuickTextInputPrivate::UpdatePaintNode && oldNode != 0) {
1717 // Update done in preprocess() in the nodes
1718 d->updateType = QQuickTextInputPrivate::UpdateNone;
1722 d->updateType = QQuickTextInputPrivate::UpdateNone;
1724 QQuickTextNode *node = static_cast<QQuickTextNode *>(oldNode);
1726 node = new QQuickTextNode(QQuickItemPrivate::get(this)->sceneGraphContext(), this);
1729 if (!d->textLayoutDirty) {
1730 QSGSimpleRectNode *cursorNode = node->cursorNode();
1731 if (cursorNode != 0 && !isReadOnly()) {
1732 cursorNode->setRect(cursorRectangle());
1734 if (!d->cursorVisible || (!d->m_blinkStatus && d->m_blinkPeriod > 0)) {
1741 node->deleteContent();
1742 node->setMatrix(QMatrix4x4());
1744 QPoint offset = QPoint(0,0);
1745 QFontMetrics fm = QFontMetrics(d->font);
1746 if (d->autoScroll) {
1747 // the y offset is there to keep the baseline constant in case we have script changes in the text.
1748 offset = -QPoint(d->hscroll, d->vscroll + d->m_ascent - fm.ascent());
1750 offset = -QPoint(d->hscroll, d->vscroll);
1753 if (!d->m_textLayout.text().isEmpty() || !d->m_textLayout.preeditAreaText().isEmpty()) {
1754 node->addTextLayout(offset, &d->m_textLayout, d->color,
1755 QQuickText::Normal, QColor(),
1756 d->selectionColor, d->selectedTextColor,
1757 d->selectionStart(),
1758 d->selectionEnd() - 1); // selectionEnd() returns first char after
1762 if (!isReadOnly() && d->cursorItem == 0) {
1763 node->setCursor(cursorRectangle(), d->color);
1764 if (!d->cursorVisible || (!d->m_blinkStatus && d->m_blinkPeriod > 0)) {
1771 d->textLayoutDirty = false;
1777 QVariant QQuickTextInput::inputMethodQuery(Qt::InputMethodQuery property) const
1779 Q_D(const QQuickTextInput);
1782 return QVariant((bool)(flags() & ItemAcceptsInputMethod));
1784 return QVariant((int)inputMethodHints());
1785 case Qt::ImCursorRectangle:
1786 return cursorRectangle();
1789 case Qt::ImCursorPosition:
1790 return QVariant(d->m_cursor);
1791 case Qt::ImSurroundingText:
1792 if (d->m_echoMode == PasswordEchoOnEdit && !d->m_passwordEchoEditing) {
1793 return QVariant(displayText());
1795 return QVariant(d->realText());
1797 case Qt::ImCurrentSelection:
1798 return QVariant(selectedText());
1799 case Qt::ImMaximumTextLength:
1800 return QVariant(maxLength());
1801 case Qt::ImAnchorPosition:
1802 if (d->selectionStart() == d->selectionEnd())
1803 return QVariant(d->m_cursor);
1804 else if (d->selectionStart() == d->m_cursor)
1805 return QVariant(d->selectionEnd());
1807 return QVariant(d->selectionStart());
1814 \qmlmethod void QtQuick2::TextInput::deselect()
1816 Removes active text selection.
1818 void QQuickTextInput::deselect()
1820 Q_D(QQuickTextInput);
1825 \qmlmethod void QtQuick2::TextInput::selectAll()
1827 Causes all text to be selected.
1829 void QQuickTextInput::selectAll()
1831 Q_D(QQuickTextInput);
1832 d->setSelection(0, text().length());
1836 \qmlmethod void QtQuick2::TextInput::isRightToLeft(int start, int end)
1838 Returns true if the natural reading direction of the editor text
1839 found between positions \a start and \a end is right to left.
1841 bool QQuickTextInput::isRightToLeft(int start, int end)
1844 qmlInfo(this) << "isRightToLeft(start, end) called with the end property being smaller than the start.";
1847 return text().mid(start, end - start).isRightToLeft();
1851 #ifndef QT_NO_CLIPBOARD
1853 \qmlmethod QtQuick2::TextInput::cut()
1855 Moves the currently selected text to the system clipboard.
1857 void QQuickTextInput::cut()
1859 Q_D(QQuickTextInput);
1865 \qmlmethod QtQuick2::TextInput::copy()
1867 Copies the currently selected text to the system clipboard.
1869 void QQuickTextInput::copy()
1871 Q_D(QQuickTextInput);
1876 \qmlmethod QtQuick2::TextInput::paste()
1878 Replaces the currently selected text by the contents of the system clipboard.
1880 void QQuickTextInput::paste()
1882 Q_D(QQuickTextInput);
1886 #endif // QT_NO_CLIPBOARD
1889 Undoes the last operation if undo is \l {canUndo}{available}. Deselects any
1890 current selection, and updates the selection start to the current cursor
1894 void QQuickTextInput::undo()
1896 Q_D(QQuickTextInput);
1897 if (!d->m_readOnly) {
1899 d->finishChange(-1, true);
1904 Redoes the last operation if redo is \l {canRedo}{available}.
1907 void QQuickTextInput::redo()
1909 Q_D(QQuickTextInput);
1910 if (!d->m_readOnly) {
1917 \qmlmethod void QtQuick2::TextInput::insert(int position, string text)
1919 Inserts \a text into the TextInput at position.
1922 void QQuickTextInput::insert(int position, const QString &text)
1924 Q_D(QQuickTextInput);
1925 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
1926 if (d->m_echoMode == QQuickTextInput::Password)
1927 d->m_passwordEchoTimer.start(qt_passwordEchoDelay, this);
1930 if (position < 0 || position > d->m_text.length())
1933 const int priorState = d->m_undoState;
1935 QString insertText = text;
1937 if (d->hasSelectedText()) {
1938 d->addCommand(QQuickTextInputPrivate::Command(
1939 QQuickTextInputPrivate::SetSelection, d->m_cursor, 0, d->m_selstart, d->m_selend));
1941 if (d->m_maskData) {
1942 insertText = d->maskString(position, insertText);
1943 for (int i = 0; i < insertText.length(); ++i) {
1944 d->addCommand(QQuickTextInputPrivate::Command(
1945 QQuickTextInputPrivate::DeleteSelection, position + i, d->m_text.at(position + i), -1, -1));
1946 d->addCommand(QQuickTextInputPrivate::Command(
1947 QQuickTextInputPrivate::Insert, position + i, insertText.at(i), -1, -1));
1949 d->m_text.replace(position, insertText.length(), insertText);
1950 if (!insertText.isEmpty())
1951 d->m_textDirty = true;
1952 if (position < d->m_selend && position + insertText.length() > d->m_selstart)
1953 d->m_selDirty = true;
1955 int remaining = d->m_maxLength - d->m_text.length();
1956 if (remaining != 0) {
1957 insertText = insertText.left(remaining);
1958 d->m_text.insert(position, insertText);
1959 for (int i = 0; i < insertText.length(); ++i)
1960 d->addCommand(QQuickTextInputPrivate::Command(
1961 QQuickTextInputPrivate::Insert, position + i, insertText.at(i), -1, -1));
1962 if (d->m_cursor >= position)
1963 d->m_cursor += insertText.length();
1964 if (d->m_selstart >= position)
1965 d->m_selstart += insertText.length();
1966 if (d->m_selend >= position)
1967 d->m_selend += insertText.length();
1968 d->m_textDirty = true;
1969 if (position >= d->m_selstart && position <= d->m_selend)
1970 d->m_selDirty = true;
1974 d->addCommand(QQuickTextInputPrivate::Command(
1975 QQuickTextInputPrivate::SetSelection, d->m_cursor, 0, d->m_selstart, d->m_selend));
1976 d->finishChange(priorState);
1978 if (d->lastSelectionStart != d->lastSelectionEnd) {
1979 if (d->m_selstart != d->lastSelectionStart) {
1980 d->lastSelectionStart = d->m_selstart;
1981 emit selectionStartChanged();
1983 if (d->m_selend != d->lastSelectionEnd) {
1984 d->lastSelectionEnd = d->m_selend;
1985 emit selectionEndChanged();
1991 \qmlmethod string QtQuick2::TextInput::getText(int start, int end)
1993 Removes the section of text that is between the \a start and \a end positions from the TextInput.
1996 void QQuickTextInput::remove(int start, int end)
1998 Q_D(QQuickTextInput);
2000 start = qBound(0, start, d->m_text.length());
2001 end = qBound(0, end, d->m_text.length());
2005 else if (start == end)
2008 if (start < d->m_selend && end > d->m_selstart)
2009 d->m_selDirty = true;
2011 const int priorState = d->m_undoState;
2013 d->addCommand(QQuickTextInputPrivate::Command(
2014 QQuickTextInputPrivate::SetSelection, d->m_cursor, 0, d->m_selstart, d->m_selend));
2016 if (start <= d->m_cursor && d->m_cursor < end) {
2017 // cursor is within the selection. Split up the commands
2018 // to be able to restore the correct cursor position
2019 for (int i = d->m_cursor; i >= start; --i) {
2020 d->addCommand(QQuickTextInputPrivate::Command(
2021 QQuickTextInputPrivate::DeleteSelection, i, d->m_text.at(i), -1, 1));
2023 for (int i = end - 1; i > d->m_cursor; --i) {
2024 d->addCommand(QQuickTextInputPrivate::Command(
2025 QQuickTextInputPrivate::DeleteSelection, i - d->m_cursor + start - 1, d->m_text.at(i), -1, -1));
2028 for (int i = end - 1; i >= start; --i) {
2029 d->addCommand(QQuickTextInputPrivate::Command(
2030 QQuickTextInputPrivate::RemoveSelection, i, d->m_text.at(i), -1, -1));
2033 if (d->m_maskData) {
2034 d->m_text.replace(start, end - start, d->clearString(start, end - start));
2035 for (int i = 0; i < end - start; ++i) {
2036 d->addCommand(QQuickTextInputPrivate::Command(
2037 QQuickTextInputPrivate::Insert, start + i, d->m_text.at(start + i), -1, -1));
2040 d->m_text.remove(start, end - start);
2042 if (d->m_cursor > start)
2043 d->m_cursor -= qMin(d->m_cursor, end) - start;
2044 if (d->m_selstart > start)
2045 d->m_selstart -= qMin(d->m_selstart, end) - start;
2046 if (d->m_selend > end)
2047 d->m_selend -= qMin(d->m_selend, end) - start;
2049 d->addCommand(QQuickTextInputPrivate::Command(
2050 QQuickTextInputPrivate::SetSelection, d->m_cursor, 0, d->m_selstart, d->m_selend));
2052 d->m_textDirty = true;
2053 d->finishChange(priorState);
2055 if (d->lastSelectionStart != d->lastSelectionEnd) {
2056 if (d->m_selstart != d->lastSelectionStart) {
2057 d->lastSelectionStart = d->m_selstart;
2058 emit selectionStartChanged();
2060 if (d->m_selend != d->lastSelectionEnd) {
2061 d->lastSelectionEnd = d->m_selend;
2062 emit selectionEndChanged();
2069 \qmlmethod void QtQuick2::TextInput::selectWord()
2071 Causes the word closest to the current cursor position to be selected.
2073 void QQuickTextInput::selectWord()
2075 Q_D(QQuickTextInput);
2076 d->selectWordAtPos(d->m_cursor);
2080 \qmlproperty bool QtQuick2::TextInput::smooth
2082 This property holds whether the text is smoothly scaled or transformed.
2084 Smooth filtering gives better visual quality, but is slower. If
2085 the item is displayed at its natural size, this property has no visual or
2088 \note Generally scaling artifacts are only visible if the item is stationary on
2089 the screen. A common pattern when animating an item is to disable smooth
2090 filtering at the beginning of the animation and reenable it at the conclusion.
2094 \qmlproperty string QtQuick2::TextInput::passwordCharacter
2096 This is the character displayed when echoMode is set to Password or
2097 PasswordEchoOnEdit. By default it is an asterisk.
2099 If this property is set to a string with more than one character,
2100 the first character is used. If the string is empty, the value
2101 is ignored and the property is not set.
2103 QString QQuickTextInput::passwordCharacter() const
2105 Q_D(const QQuickTextInput);
2106 return QString(d->m_passwordCharacter);
2109 void QQuickTextInput::setPasswordCharacter(const QString &str)
2111 Q_D(QQuickTextInput);
2112 if (str.length() < 1)
2114 d->m_passwordCharacter = str.constData()[0];
2115 if (d->m_echoMode == Password || d->m_echoMode == PasswordEchoOnEdit)
2116 d->updateDisplayText();
2117 emit passwordCharacterChanged();
2121 \qmlproperty string QtQuick2::TextInput::displayText
2123 This is the text displayed in the TextInput.
2125 If \l echoMode is set to TextInput::Normal, this holds the
2126 same value as the TextInput::text property. Otherwise,
2127 this property holds the text visible to the user, while
2128 the \l text property holds the actual entered text.
2130 QString QQuickTextInput::displayText() const
2132 Q_D(const QQuickTextInput);
2133 return d->m_textLayout.text();
2137 \qmlproperty bool QtQuick2::TextInput::selectByMouse
2141 If true, the user can use the mouse to select text in some
2142 platform-specific way. Note that for some platforms this may
2143 not be an appropriate interaction (eg. may conflict with how
2144 the text needs to behave inside a Flickable.
2146 bool QQuickTextInput::selectByMouse() const
2148 Q_D(const QQuickTextInput);
2149 return d->selectByMouse;
2152 void QQuickTextInput::setSelectByMouse(bool on)
2154 Q_D(QQuickTextInput);
2155 if (d->selectByMouse != on) {
2156 d->selectByMouse = on;
2157 emit selectByMouseChanged(on);
2162 \qmlproperty enum QtQuick2::TextInput::mouseSelectionMode
2164 Specifies how text should be selected using a mouse.
2167 \o TextInput.SelectCharacters - The selection is updated with individual characters. (Default)
2168 \o TextInput.SelectWords - The selection is updated with whole words.
2171 This property only applies when \l selectByMouse is true.
2174 QQuickTextInput::SelectionMode QQuickTextInput::mouseSelectionMode() const
2176 Q_D(const QQuickTextInput);
2177 return d->mouseSelectionMode;
2180 void QQuickTextInput::setMouseSelectionMode(SelectionMode mode)
2182 Q_D(QQuickTextInput);
2183 if (d->mouseSelectionMode != mode) {
2184 d->mouseSelectionMode = mode;
2185 emit mouseSelectionModeChanged(mode);
2190 \qmlproperty bool QtQuick2::TextInput::persistentSelection
2192 Whether the TextInput should keep its selection when it loses active focus to another
2193 item in the scene. By default this is set to false;
2196 bool QQuickTextInput::persistentSelection() const
2198 Q_D(const QQuickTextInput);
2199 return d->persistentSelection;
2202 void QQuickTextInput::setPersistentSelection(bool on)
2204 Q_D(QQuickTextInput);
2205 if (d->persistentSelection == on)
2207 d->persistentSelection = on;
2208 emit persistentSelectionChanged();
2212 \qmlproperty bool QtQuick2::TextInput::canPaste
2214 Returns true if the TextInput is writable and the content of the clipboard is
2215 suitable for pasting into the TextInput.
2217 bool QQuickTextInput::canPaste() const
2219 Q_D(const QQuickTextInput);
2220 if (!d->canPasteValid) {
2221 if (const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData())
2222 const_cast<QQuickTextInputPrivate *>(d)->canPaste = !d->m_readOnly && mimeData->hasText();
2223 const_cast<QQuickTextInputPrivate *>(d)->canPasteValid = true;
2229 \qmlproperty bool QtQuick2::TextInput::canUndo
2231 Returns true if the TextInput is writable and there are previous operations
2235 bool QQuickTextInput::canUndo() const
2237 Q_D(const QQuickTextInput);
2242 \qmlproperty bool QtQuick2::TextInput::canRedo
2244 Returns true if the TextInput is writable and there are \l {undo}{undone}
2245 operations that can be redone.
2248 bool QQuickTextInput::canRedo() const
2250 Q_D(const QQuickTextInput);
2254 void QQuickTextInput::moveCursorSelection(int position)
2256 Q_D(QQuickTextInput);
2257 d->moveCursor(position, true);
2261 \qmlmethod void QtQuick2::TextInput::moveCursorSelection(int position, SelectionMode mode = TextInput.SelectCharacters)
2263 Moves the cursor to \a position and updates the selection according to the optional \a mode
2264 parameter. (To only move the cursor, set the \l cursorPosition property.)
2266 When this method is called it additionally sets either the
2267 selectionStart or the selectionEnd (whichever was at the previous cursor position)
2268 to the specified position. This allows you to easily extend and contract the selected
2271 The selection mode specifies whether the selection is updated on a per character or a per word
2272 basis. If not specified the selection mode will default to TextInput.SelectCharacters.
2275 \o TextInput.SelectCharacters - Sets either the selectionStart or selectionEnd (whichever was at
2276 the previous cursor position) to the specified position.
2277 \o TextInput.SelectWords - Sets the selectionStart and selectionEnd to include all
2278 words between the specified position and the previous cursor position. Words partially in the
2282 For example, take this sequence of calls:
2286 moveCursorSelection(9, TextInput.SelectCharacters)
2287 moveCursorSelection(7, TextInput.SelectCharacters)
2290 This moves the cursor to position 5, extend the selection end from 5 to 9
2291 and then retract the selection end from 9 to 7, leaving the text from position 5 to 7
2292 selected (the 6th and 7th characters).
2294 The same sequence with TextInput.SelectWords will extend the selection start to a word boundary
2295 before or on position 5 and extend the selection end to a word boundary on or past position 9.
2297 void QQuickTextInput::moveCursorSelection(int pos, SelectionMode mode)
2299 Q_D(QQuickTextInput);
2301 if (mode == SelectCharacters) {
2302 d->moveCursor(pos, true);
2303 } else if (pos != d->m_cursor){
2304 const int cursor = d->m_cursor;
2306 if (!d->hasSelectedText())
2307 anchor = d->m_cursor;
2308 else if (d->selectionStart() == d->m_cursor)
2309 anchor = d->selectionEnd();
2311 anchor = d->selectionStart();
2313 if (anchor < pos || (anchor == pos && cursor < pos)) {
2314 const QString text = this->text();
2315 QTextBoundaryFinder finder(QTextBoundaryFinder::Word, text);
2316 finder.setPosition(anchor);
2318 const QTextBoundaryFinder::BoundaryReasons reasons = finder.boundaryReasons();
2319 if (anchor < text.length() && (!(reasons & QTextBoundaryFinder::StartWord)
2320 || ((reasons & QTextBoundaryFinder::EndWord) && anchor > cursor))) {
2321 finder.toPreviousBoundary();
2323 anchor = finder.position() != -1 ? finder.position() : 0;
2325 finder.setPosition(pos);
2326 if (pos > 0 && !finder.boundaryReasons())
2327 finder.toNextBoundary();
2328 const int cursor = finder.position() != -1 ? finder.position() : text.length();
2330 d->setSelection(anchor, cursor - anchor);
2331 } else if (anchor > pos || (anchor == pos && cursor > pos)) {
2332 const QString text = this->text();
2333 QTextBoundaryFinder finder(QTextBoundaryFinder::Word, text);
2334 finder.setPosition(anchor);
2336 const QTextBoundaryFinder::BoundaryReasons reasons = finder.boundaryReasons();
2337 if (anchor > 0 && (!(reasons & QTextBoundaryFinder::EndWord)
2338 || ((reasons & QTextBoundaryFinder::StartWord) && anchor < cursor))) {
2339 finder.toNextBoundary();
2342 anchor = finder.position() != -1 ? finder.position() : text.length();
2344 finder.setPosition(pos);
2345 if (pos < text.length() && !finder.boundaryReasons())
2346 finder.toPreviousBoundary();
2347 const int cursor = finder.position() != -1 ? finder.position() : 0;
2349 d->setSelection(anchor, cursor - anchor);
2355 \qmlmethod void QtQuick2::TextInput::openSoftwareInputPanel()
2357 Opens software input panels like virtual keyboards for typing, useful for
2358 customizing when you want the input keyboard to be shown and hidden in
2361 By default the opening of input panels follows the platform style. Input panels are
2362 always closed if no editor has active focus.
2364 You can disable the automatic behavior by setting the property \c activeFocusOnPress to false
2365 and use functions openSoftwareInputPanel() and closeSoftwareInputPanel() to implement
2366 the behavior you want.
2368 Only relevant on platforms, which provide virtual keyboards.
2374 text: "Hello world!"
2375 activeFocusOnPress: false
2377 anchors.fill: parent
2379 if (!textInput.activeFocus) {
2380 textInput.forceActiveFocus()
2381 textInput.openSoftwareInputPanel();
2383 textInput.focus = false;
2386 onPressAndHold: textInput.closeSoftwareInputPanel();
2391 void QQuickTextInput::openSoftwareInputPanel()
2394 qGuiApp->inputPanel()->show();
2398 \qmlmethod void QtQuick2::TextInput::closeSoftwareInputPanel()
2400 Closes a software input panel like a virtual keyboard shown on the screen, useful
2401 for customizing when you want the input keyboard to be shown and hidden in
2404 By default the opening of input panels follows the platform style. Input panels are
2405 always closed if no editor has active focus.
2407 You can disable the automatic behavior by setting the property \c activeFocusOnPress to false
2408 and use functions openSoftwareInputPanel() and closeSoftwareInputPanel() to implement
2409 the behavior you want.
2411 Only relevant on platforms, which provide virtual keyboards.
2417 text: "Hello world!"
2418 activeFocusOnPress: false
2420 anchors.fill: parent
2422 if (!textInput.activeFocus) {
2423 textInput.forceActiveFocus();
2424 textInput.openSoftwareInputPanel();
2426 textInput.focus = false;
2429 onPressAndHold: textInput.closeSoftwareInputPanel();
2434 void QQuickTextInput::closeSoftwareInputPanel()
2437 qGuiApp->inputPanel()->hide();
2440 void QQuickTextInput::focusInEvent(QFocusEvent *event)
2442 Q_D(const QQuickTextInput);
2443 if (d->focusOnPress && !d->m_readOnly)
2444 openSoftwareInputPanel();
2445 QQuickImplicitSizeItem::focusInEvent(event);
2448 void QQuickTextInput::itemChange(ItemChange change, const ItemChangeData &value)
2450 Q_D(QQuickTextInput);
2451 if (change == ItemActiveFocusHasChanged) {
2452 bool hasFocus = value.boolValue;
2453 d->focused = hasFocus;
2454 setCursorVisible(hasFocus); // ### refactor: && d->canvas && d->canvas->hasFocus()
2455 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
2456 if (!hasFocus && (d->m_passwordEchoEditing || d->m_passwordEchoTimer.isActive())) {
2458 if (!hasFocus && d->m_passwordEchoEditing) {
2460 d->updatePasswordEchoEditing(false);//QQuickTextInputPrivate sets it on key events, but doesn't deal with focus events
2465 if (!d->persistentSelection)
2467 disconnect(qApp->inputPanel(), SIGNAL(inputDirectionChanged(Qt::LayoutDirection)),
2468 this, SLOT(q_updateAlignment()));
2470 q_updateAlignment();
2471 connect(qApp->inputPanel(), SIGNAL(inputDirectionChanged(Qt::LayoutDirection)),
2472 this, SLOT(q_updateAlignment()));
2475 QQuickItem::itemChange(change, value);
2479 \qmlproperty bool QtQuick2::TextInput::inputMethodComposing
2482 This property holds whether the TextInput has partial text input from an
2485 While it is composing an input method may rely on mouse or key events from
2486 the TextInput to edit or commit the partial text. This property can be
2487 used to determine when to disable events handlers that may interfere with
2488 the correct operation of an input method.
2490 bool QQuickTextInput::isInputMethodComposing() const
2492 Q_D(const QQuickTextInput);
2493 return d->preeditAreaText().length() > 0;
2496 void QQuickTextInputPrivate::init()
2498 Q_Q(QQuickTextInput);
2499 q->setSmooth(smooth);
2500 q->setAcceptedMouseButtons(Qt::LeftButton);
2501 q->setFlag(QQuickItem::ItemAcceptsInputMethod);
2502 q->setFlag(QQuickItem::ItemHasContents);
2503 #ifndef QT_NO_CLIPBOARD
2504 q->connect(QGuiApplication::clipboard(), SIGNAL(dataChanged()),
2505 q, SLOT(q_canPasteChanged()));
2506 #endif // QT_NO_CLIPBOARD
2508 lastSelectionStart = 0;
2509 lastSelectionEnd = 0;
2510 selectedTextColor = m_palette.color(QPalette::HighlightedText);
2511 selectionColor = m_palette.color(QPalette::Highlight);
2512 determineHorizontalAlignment();
2514 if (!qmlDisableDistanceField()) {
2515 QTextOption option = m_textLayout.textOption();
2516 option.setUseDesignMetrics(true);
2517 m_textLayout.setTextOption(option);
2521 void QQuickTextInput::updateCursorRectangle()
2523 Q_D(QQuickTextInput);
2524 if (!isComponentComplete())
2527 d->updateHorizontalScroll();
2528 d->updateVerticalScroll();
2529 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
2531 emit cursorRectangleChanged();
2532 if (d->cursorItem) {
2533 QRectF r = cursorRectangle();
2534 d->cursorItem->setPos(r.topLeft());
2535 d->cursorItem->setHeight(r.height());
2537 updateInputMethod(Qt::ImCursorRectangle);
2540 void QQuickTextInput::selectionChanged()
2542 Q_D(QQuickTextInput);
2543 d->textLayoutDirty = true; //TODO: Only update rect in selection
2544 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
2546 emit selectedTextChanged();
2548 if (d->lastSelectionStart != d->selectionStart()) {
2549 d->lastSelectionStart = d->selectionStart();
2550 if (d->lastSelectionStart == -1)
2551 d->lastSelectionStart = d->m_cursor;
2552 emit selectionStartChanged();
2554 if (d->lastSelectionEnd != d->selectionEnd()) {
2555 d->lastSelectionEnd = d->selectionEnd();
2556 if (d->lastSelectionEnd == -1)
2557 d->lastSelectionEnd = d->m_cursor;
2558 emit selectionEndChanged();
2562 void QQuickTextInputPrivate::showCursor()
2564 if (textNode != 0 && textNode->cursorNode() != 0)
2565 textNode->cursorNode()->setColor(color);
2568 void QQuickTextInputPrivate::hideCursor()
2570 if (textNode != 0 && textNode->cursorNode() != 0)
2571 textNode->cursorNode()->setColor(QColor(0, 0, 0, 0));
2574 QRectF QQuickTextInput::boundingRect() const
2576 Q_D(const QQuickTextInput);
2578 int cursorWidth = d->cursorItem ? d->cursorItem->width() : d->m_cursorWidth;
2580 // Could include font max left/right bearings to either side of rectangle.
2581 QRectF r = QQuickImplicitSizeItem::boundingRect();
2582 r.setRight(r.right() + cursorWidth);
2586 void QQuickTextInput::q_canPasteChanged()
2588 Q_D(QQuickTextInput);
2589 bool old = d->canPaste;
2590 #ifndef QT_NO_CLIPBOARD
2591 if (const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData())
2592 d->canPaste = !d->m_readOnly && mimeData->hasText();
2594 d->canPaste = false;
2597 bool changed = d->canPaste != old || !d->canPasteValid;
2598 d->canPasteValid = true;
2600 emit canPasteChanged();
2604 void QQuickTextInput::q_updateAlignment()
2606 Q_D(QQuickTextInput);
2607 if (d->determineHorizontalAlignment()) {
2609 updateCursorRectangle();
2613 // ### these should come from QStyleHints
2614 const int textCursorWidth = 1;
2615 const bool fullWidthSelection = true;
2620 Updates the display text based of the current edit text
2621 If the text has changed will emit displayTextChanged()
2623 void QQuickTextInputPrivate::updateDisplayText(bool forceUpdate)
2625 QString orig = m_textLayout.text();
2627 if (m_echoMode == QQuickTextInput::NoEcho)
2628 str = QString::fromLatin1("");
2632 if (m_echoMode == QQuickTextInput::Password) {
2633 str.fill(m_passwordCharacter);
2634 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
2635 if (m_passwordEchoTimer.isActive() && m_cursor > 0 && m_cursor <= m_text.length()) {
2636 int cursor = m_cursor - 1;
2637 QChar uc = m_text.at(cursor);
2639 if (cursor > 0 && uc.unicode() >= 0xdc00 && uc.unicode() < 0xe000) {
2640 // second half of a surrogate, check if we have the first half as well,
2641 // if yes restore both at once
2642 uc = m_text.at(cursor - 1);
2643 if (uc.unicode() >= 0xd800 && uc.unicode() < 0xdc00)
2644 str[cursor - 1] = uc;
2648 } else if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit && !m_passwordEchoEditing) {
2649 str.fill(m_passwordCharacter);
2652 // replace certain non-printable characters with spaces (to avoid
2653 // drawing boxes when using fonts that don't have glyphs for such
2655 QChar* uc = str.data();
2656 for (int i = 0; i < (int)str.length(); ++i) {
2657 if ((uc[i] < 0x20 && uc[i] != 0x09)
2658 || uc[i] == QChar::LineSeparator
2659 || uc[i] == QChar::ParagraphSeparator
2660 || uc[i] == QChar::ObjectReplacementCharacter)
2661 uc[i] = QChar(0x0020);
2664 if (str != orig || forceUpdate) {
2665 m_textLayout.setText(str);
2666 updateLayout(); // polish?
2667 emit q_func()->displayTextChanged();
2671 void QQuickTextInputPrivate::updateLayout()
2673 Q_Q(QQuickTextInput);
2675 if (!q->isComponentComplete())
2678 QTextOption option = m_textLayout.textOption();
2679 option.setTextDirection(layoutDirection());
2680 option.setFlags(QTextOption::IncludeTrailingSpaces);
2681 option.setWrapMode(QTextOption::WrapMode(wrapMode));
2682 option.setAlignment(Qt::Alignment(q->effectiveHAlign()));
2683 m_textLayout.setTextOption(option);
2684 m_textLayout.setFont(font);
2686 boundingRect = QRectF();
2687 m_textLayout.beginLayout();
2688 QTextLine line = m_textLayout.createLine();
2689 qreal lineWidth = q->widthValid() ? q->width() : INT_MAX;
2691 QTextLine firstLine = line;
2693 line.setLineWidth(lineWidth);
2694 line.setPosition(QPointF(line.position().x(), height));
2695 boundingRect = boundingRect.united(line.naturalTextRect());
2697 height += line.height();
2698 line = m_textLayout.createLine();
2699 } while (line.isValid());
2700 m_textLayout.endLayout();
2702 option.setWrapMode(QTextOption::NoWrap);
2703 m_textLayout.setTextOption(option);
2705 m_ascent = qRound(firstLine.ascent());
2706 textLayoutDirty = true;
2708 updateType = UpdatePaintNode;
2710 q->setImplicitSize(qCeil(boundingRect.width()), qCeil(boundingRect.height()));
2714 #ifndef QT_NO_CLIPBOARD
2718 Copies the currently selected text into the clipboard using the given
2721 \note If the echo mode is set to a mode other than Normal then copy
2722 will not work. This is to prevent using copy as a method of bypassing
2723 password features of the line control.
2725 void QQuickTextInputPrivate::copy(QClipboard::Mode mode) const
2727 QString t = selectedText();
2728 if (!t.isEmpty() && m_echoMode == QQuickTextInput::Normal) {
2729 QGuiApplication::clipboard()->setText(t, mode);
2736 Inserts the text stored in the application clipboard into the line
2741 void QQuickTextInputPrivate::paste(QClipboard::Mode clipboardMode)
2743 QString clip = QGuiApplication::clipboard()->text(clipboardMode);
2744 if (!clip.isEmpty() || hasSelectedText()) {
2745 separate(); //make it a separate undo/redo command
2751 #endif // !QT_NO_CLIPBOARD
2756 Exits preedit mode and commits parts marked as tentative commit
2758 void QQuickTextInputPrivate::commitPreedit()
2763 qApp->inputPanel()->reset();
2765 if (!m_tentativeCommit.isEmpty()) {
2766 internalInsert(m_tentativeCommit);
2767 m_tentativeCommit.clear();
2768 finishChange(-1, true/*not used, not documented*/, false);
2771 m_preeditCursor = 0;
2772 m_textLayout.setPreeditArea(-1, QString());
2773 m_textLayout.clearAdditionalFormats();
2780 Handles the behavior for the backspace key or function.
2781 Removes the current selection if there is a selection, otherwise
2782 removes the character prior to the cursor position.
2786 void QQuickTextInputPrivate::backspace()
2788 int priorState = m_undoState;
2789 if (hasSelectedText()) {
2790 removeSelectedText();
2791 } else if (m_cursor) {
2794 m_cursor = prevMaskBlank(m_cursor);
2795 QChar uc = m_text.at(m_cursor);
2796 if (m_cursor > 0 && uc.unicode() >= 0xdc00 && uc.unicode() < 0xe000) {
2797 // second half of a surrogate, check if we have the first half as well,
2798 // if yes delete both at once
2799 uc = m_text.at(m_cursor - 1);
2800 if (uc.unicode() >= 0xd800 && uc.unicode() < 0xdc00) {
2801 internalDelete(true);
2805 internalDelete(true);
2807 finishChange(priorState);
2813 Handles the behavior for the delete key or function.
2814 Removes the current selection if there is a selection, otherwise
2815 removes the character after the cursor position.
2819 void QQuickTextInputPrivate::del()
2821 int priorState = m_undoState;
2822 if (hasSelectedText()) {
2823 removeSelectedText();
2825 int n = m_textLayout.nextCursorPosition(m_cursor) - m_cursor;
2829 finishChange(priorState);
2835 Inserts the given \a newText at the current cursor position.
2836 If there is any selected text it is removed prior to insertion of
2839 void QQuickTextInputPrivate::insert(const QString &newText)
2841 int priorState = m_undoState;
2842 removeSelectedText();
2843 internalInsert(newText);
2844 finishChange(priorState);
2850 Clears the line control text.
2852 void QQuickTextInputPrivate::clear()
2854 int priorState = m_undoState;
2856 m_selend = m_text.length();
2857 removeSelectedText();
2859 finishChange(priorState, /*update*/false, /*edited*/false);
2865 Sets \a length characters from the given \a start position as selected.
2866 The given \a start position must be within the current text for
2867 the line control. If \a length characters cannot be selected, then
2868 the selection will extend to the end of the current text.
2870 void QQuickTextInputPrivate::setSelection(int start, int length)
2872 Q_Q(QQuickTextInput);
2875 if (start < 0 || start > (int)m_text.length()){
2876 qWarning("QQuickTextInputPrivate::setSelection: Invalid start position");
2881 if (start == m_selstart && start + length == m_selend && m_cursor == m_selend)
2884 m_selend = qMin(start + length, (int)m_text.length());
2885 m_cursor = m_selend;
2886 } else if (length < 0){
2887 if (start == m_selend && start + length == m_selstart && m_cursor == m_selstart)
2889 m_selstart = qMax(start + length, 0);
2891 m_cursor = m_selstart;
2892 } else if (m_selstart != m_selend) {
2898 emitCursorPositionChanged();
2901 emit q->selectionChanged();
2902 emitCursorPositionChanged();
2903 q->updateInputMethod(Qt::ImCursorRectangle | Qt::ImAnchorPosition
2904 | Qt::ImCursorPosition | Qt::ImCurrentSelection);
2910 Initializes the line control with a starting text value of \a txt.
2912 void QQuickTextInputPrivate::init(const QString &txt)
2916 updateDisplayText();
2917 m_cursor = m_text.length();
2923 Sets the password echo editing to \a editing. If password echo editing
2924 is true, then the text of the password is displayed even if the echo
2925 mode is set to QLineEdit::PasswordEchoOnEdit. Password echoing editing
2926 does not affect other echo modes.
2928 void QQuickTextInputPrivate::updatePasswordEchoEditing(bool editing)
2930 cancelPasswordEchoTimer();
2931 m_passwordEchoEditing = editing;
2932 updateDisplayText();
2938 Fixes the current text so that it is valid given any set validators.
2940 Returns true if the text was changed. Otherwise returns false.
2942 bool QQuickTextInputPrivate::fixup() // this function assumes that validate currently returns != Acceptable
2944 #ifndef QT_NO_VALIDATOR
2946 QString textCopy = m_text;
2947 int cursorCopy = m_cursor;
2948 m_validator->fixup(textCopy);
2949 if (m_validator->validate(textCopy, cursorCopy) == QValidator::Acceptable) {
2950 if (textCopy != m_text || cursorCopy != m_cursor)
2951 internalSetText(textCopy, cursorCopy);
2962 Moves the cursor to the given position \a pos. If \a mark is true will
2963 adjust the currently selected text.
2965 void QQuickTextInputPrivate::moveCursor(int pos, bool mark)
2967 Q_Q(QQuickTextInput);
2970 if (pos != m_cursor) {
2973 pos = pos > m_cursor ? nextMaskBlank(pos) : prevMaskBlank(pos);
2977 if (m_selend > m_selstart && m_cursor == m_selstart)
2979 else if (m_selend > m_selstart && m_cursor == m_selend)
2980 anchor = m_selstart;
2983 m_selstart = qMin(anchor, pos);
2984 m_selend = qMax(anchor, pos);
2989 if (mark || m_selDirty) {
2991 emit q->selectionChanged();
2993 emitCursorPositionChanged();
2994 q->updateInputMethod();
3000 Applies the given input method event \a event to the text of the line
3003 void QQuickTextInputPrivate::processInputMethodEvent(QInputMethodEvent *event)
3005 Q_Q(QQuickTextInput);
3007 int priorState = -1;
3008 bool isGettingInput = !event->commitString().isEmpty()
3009 || event->preeditString() != preeditAreaText()
3010 || event->replacementLength() > 0;
3011 bool cursorPositionChanged = false;
3012 bool selectionChange = false;
3013 m_preeditDirty = event->preeditString() != preeditAreaText();
3015 if (isGettingInput) {
3016 // If any text is being input, remove selected text.
3017 priorState = m_undoState;
3018 if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit && !m_passwordEchoEditing) {
3019 updatePasswordEchoEditing(true);
3021 m_selend = m_text.length();
3023 removeSelectedText();
3026 int c = m_cursor; // cursor position after insertion of commit string
3027 if (event->replacementStart() <= 0)
3028 c += event->commitString().length() - qMin(-event->replacementStart(), event->replacementLength());
3030 m_cursor += event->replacementStart();
3034 // insert commit string
3035 if (event->replacementLength()) {
3036 m_selstart = m_cursor;
3037 m_selend = m_selstart + event->replacementLength();
3038 m_selend = qMin(m_selend, m_text.length());
3039 removeSelectedText();
3041 if (!event->commitString().isEmpty()) {
3042 internalInsert(event->commitString());
3043 cursorPositionChanged = true;
3046 m_cursor = qBound(0, c, m_text.length());
3048 for (int i = 0; i < event->attributes().size(); ++i) {
3049 const QInputMethodEvent::Attribute &a = event->attributes().at(i);
3050 if (a.type == QInputMethodEvent::Selection) {
3051 m_cursor = qBound(0, a.start + a.length, m_text.length());
3053 m_selstart = qMax(0, qMin(a.start, m_text.length()));
3054 m_selend = m_cursor;
3055 if (m_selend < m_selstart) {
3056 qSwap(m_selstart, m_selend);
3058 selectionChange = true;
3060 m_selstart = m_selend = 0;
3062 cursorPositionChanged = true;
3066 m_textLayout.setPreeditArea(m_cursor, event->preeditString());
3068 const int oldPreeditCursor = m_preeditCursor;
3069 m_preeditCursor = event->preeditString().length();
3070 m_hideCursor = false;
3071 QList<QTextLayout::FormatRange> formats;
3072 for (int i = 0; i < event->attributes().size(); ++i) {
3073 const QInputMethodEvent::Attribute &a = event->attributes().at(i);
3074 if (a.type == QInputMethodEvent::Cursor) {
3075 m_preeditCursor = a.start;
3076 m_hideCursor = !a.length;
3077 } else if (a.type == QInputMethodEvent::TextFormat) {
3078 QTextCharFormat f = qvariant_cast<QTextFormat>(a.value).toCharFormat();
3080 QTextLayout::FormatRange o;
3081 o.start = a.start + m_cursor;
3082 o.length = a.length;
3088 m_textLayout.setAdditionalFormats(formats);
3090 updateDisplayText(/*force*/ true);
3091 if (cursorPositionChanged) {
3092 emitCursorPositionChanged();
3093 } else if (m_preeditCursor != oldPreeditCursor) {
3094 q->updateCursorRectangle();
3097 bool tentativeCommitChanged = m_tentativeCommit != event->tentativeCommitString();
3099 if (tentativeCommitChanged) {
3101 m_tentativeCommit = event->tentativeCommitString();
3104 if (isGettingInput || tentativeCommitChanged)
3105 finishChange(priorState);
3107 if (selectionChange) {
3108 emit q->selectionChanged();
3109 q->updateInputMethod(Qt::ImCursorRectangle | Qt::ImAnchorPosition
3110 | Qt::ImCursorPosition | Qt::ImCurrentSelection);
3117 Sets the selection to cover the word at the given cursor position.
3118 The word boundaries are defined by the behavior of QTextLayout::SkipWords
3121 void QQuickTextInputPrivate::selectWordAtPos(int cursor)
3123 int next = cursor + 1;
3126 int c = m_textLayout.previousCursorPosition(next, QTextLayout::SkipWords);
3127 moveCursor(c, false);
3128 // ## text layout should support end of words.
3129 int end = m_textLayout.nextCursorPosition(c, QTextLayout::SkipWords);
3130 while (end > cursor && m_text[end-1].isSpace())
3132 moveCursor(end, true);
3138 Completes a change to the line control text. If the change is not valid
3139 will undo the line control state back to the given \a validateFromState.
3141 If \a edited is true and the change is valid, will emit textEdited() in
3142 addition to textChanged(). Otherwise only emits textChanged() on a valid
3145 The \a update value is currently unused.
3147 bool QQuickTextInputPrivate::finishChange(int validateFromState, bool update, bool /*edited*/)
3149 Q_Q(QQuickTextInput);
3152 bool inputMethodAttributesChanged = m_textDirty || m_selDirty;
3153 bool alignmentChanged = false;
3157 bool wasValidInput = m_validInput;
3158 bool wasAcceptable = m_acceptableInput;
3159 m_validInput = true;
3160 m_acceptableInput = true;
3161 #ifndef QT_NO_VALIDATOR
3163 QString textCopy = m_text;
3164 int cursorCopy = m_cursor;
3165 QValidator::State state = m_validator->validate(textCopy, cursorCopy);
3166 m_validInput = state != QValidator::Invalid;
3167 m_acceptableInput = state == QValidator::Acceptable;
3169 if (m_text != textCopy) {
3170 internalSetText(textCopy, cursorCopy);
3173 m_cursor = cursorCopy;
3175 if (!m_tentativeCommit.isEmpty()) {
3176 textCopy.insert(m_cursor, m_tentativeCommit);
3177 bool validInput = m_validator->validate(textCopy, cursorCopy) != QValidator::Invalid;
3179 m_tentativeCommit.clear();
3182 m_tentativeCommit.clear();
3186 if (validateFromState >= 0 && wasValidInput && !m_validInput) {
3187 if (m_transactions.count())
3189 internalUndo(validateFromState);
3190 m_history.resize(m_undoState);
3191 if (m_modifiedState > m_undoState)
3192 m_modifiedState = -1;
3193 m_validInput = true;
3194 m_acceptableInput = wasAcceptable;
3195 m_textDirty = false;
3199 m_textDirty = false;
3200 m_preeditDirty = false;
3201 alignmentChanged = determineHorizontalAlignment();
3202 emit q->textChanged();
3205 updateDisplayText(alignmentChanged);
3207 if (m_acceptableInput != wasAcceptable)
3208 emit q->acceptableInputChanged();
3210 if (m_preeditDirty) {
3211 m_preeditDirty = false;
3212 if (determineHorizontalAlignment()) {
3213 alignmentChanged = true;
3220 emit q->selectionChanged();
3223 inputMethodAttributesChanged |= (m_cursor == m_lastCursorPos);
3224 if (inputMethodAttributesChanged)
3225 q->updateInputMethod();
3226 emitUndoRedoChanged();
3228 if (!emitCursorPositionChanged() && alignmentChanged)
3229 q->updateCursorRectangle();
3237 An internal function for setting the text of the line control.
3239 void QQuickTextInputPrivate::internalSetText(const QString &txt, int pos, bool edited)
3241 Q_Q(QQuickTextInput);
3243 QString oldText = m_text;
3245 m_text = maskString(0, txt, true);
3246 m_text += clearString(m_text.length(), m_maxLength - m_text.length());
3248 m_text = txt.isEmpty() ? txt : txt.left(m_maxLength);
3251 m_modifiedState = m_undoState = 0;
3252 m_cursor = (pos < 0 || pos > m_text.length()) ? m_text.length() : pos;
3253 m_textDirty = (oldText != m_text);
3255 bool changed = finishChange(-1, true, edited);
3256 #ifdef QT_NO_ACCESSIBILITY
3260 QAccessible::updateAccessibility(QAccessibleEvent(QAccessible::TextUpdated, q, 0));
3268 Adds the given \a command to the undo history
3269 of the line control. Does not apply the command.
3271 void QQuickTextInputPrivate::addCommand(const Command &cmd)
3273 if (m_separator && m_undoState && m_history[m_undoState - 1].type != Separator) {
3274 m_history.resize(m_undoState + 2);
3275 m_history[m_undoState++] = Command(Separator, m_cursor, 0, m_selstart, m_selend);
3277 m_history.resize(m_undoState + 1);
3279 m_separator = false;
3280 m_history[m_undoState++] = cmd;
3286 Inserts the given string \a s into the line
3289 Also adds the appropriate commands into the undo history.
3290 This function does not call finishChange(), and may leave the text
3291 in an invalid state.
3293 void QQuickTextInputPrivate::internalInsert(const QString &s)
3295 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
3296 Q_Q(QQuickTextInput);
3297 if (m_echoMode == QQuickTextInput::Password)
3298 m_passwordEchoTimer.start(qt_passwordEchoDelay, q);
3300 if (hasSelectedText())
3301 addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
3303 QString ms = maskString(m_cursor, s);
3304 for (int i = 0; i < (int) ms.length(); ++i) {
3305 addCommand (Command(DeleteSelection, m_cursor + i, m_text.at(m_cursor + i), -1, -1));
3306 addCommand(Command(Insert, m_cursor + i, ms.at(i), -1, -1));
3308 m_text.replace(m_cursor, ms.length(), ms);
3309 m_cursor += ms.length();
3310 m_cursor = nextMaskBlank(m_cursor);
3313 int remaining = m_maxLength - m_text.length();
3314 if (remaining != 0) {
3315 m_text.insert(m_cursor, s.left(remaining));
3316 for (int i = 0; i < (int) s.left(remaining).length(); ++i)
3317 addCommand(Command(Insert, m_cursor++, s.at(i), -1, -1));
3326 deletes a single character from the current text. If \a wasBackspace,
3327 the character prior to the cursor is removed. Otherwise the character
3328 after the cursor is removed.
3330 Also adds the appropriate commands into the undo history.
3331 This function does not call finishChange(), and may leave the text
3332 in an invalid state.
3334 void QQuickTextInputPrivate::internalDelete(bool wasBackspace)
3336 if (m_cursor < (int) m_text.length()) {
3337 cancelPasswordEchoTimer();
3338 if (hasSelectedText())
3339 addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
3340 addCommand(Command((CommandType)((m_maskData ? 2 : 0) + (wasBackspace ? Remove : Delete)),
3341 m_cursor, m_text.at(m_cursor), -1, -1));
3343 m_text.replace(m_cursor, 1, clearString(m_cursor, 1));
3344 addCommand(Command(Insert, m_cursor, m_text.at(m_cursor), -1, -1));
3346 m_text.remove(m_cursor, 1);
3355 removes the currently selected text from the line control.
3357 Also adds the appropriate commands into the undo history.
3358 This function does not call finishChange(), and may leave the text
3359 in an invalid state.
3361 void QQuickTextInputPrivate::removeSelectedText()
3363 if (m_selstart < m_selend && m_selend <= (int) m_text.length()) {
3364 cancelPasswordEchoTimer();
3367 addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
3368 if (m_selstart <= m_cursor && m_cursor < m_selend) {
3369 // cursor is within the selection. Split up the commands
3370 // to be able to restore the correct cursor position
3371 for (i = m_cursor; i >= m_selstart; --i)
3372 addCommand (Command(DeleteSelection, i, m_text.at(i), -1, 1));
3373 for (i = m_selend - 1; i > m_cursor; --i)
3374 addCommand (Command(DeleteSelection, i - m_cursor + m_selstart - 1, m_text.at(i), -1, -1));
3376 for (i = m_selend-1; i >= m_selstart; --i)
3377 addCommand (Command(RemoveSelection, i, m_text.at(i), -1, -1));
3380 m_text.replace(m_selstart, m_selend - m_selstart, clearString(m_selstart, m_selend - m_selstart));
3381 for (int i = 0; i < m_selend - m_selstart; ++i)
3382 addCommand(Command(Insert, m_selstart + i, m_text.at(m_selstart + i), -1, -1));
3384 m_text.remove(m_selstart, m_selend - m_selstart);
3386 if (m_cursor > m_selstart)
3387 m_cursor -= qMin(m_cursor, m_selend) - m_selstart;
3396 Parses the input mask specified by \a maskFields to generate
3397 the mask data used to handle input masks.
3399 void QQuickTextInputPrivate::parseInputMask(const QString &maskFields)
3401 int delimiter = maskFields.indexOf(QLatin1Char(';'));
3402 if (maskFields.isEmpty() || delimiter == 0) {
3404 delete [] m_maskData;
3406 m_maxLength = 32767;
3407 internalSetText(QString());
3412 if (delimiter == -1) {
3413 m_blank = QLatin1Char(' ');
3414 m_inputMask = maskFields;
3416 m_inputMask = maskFields.left(delimiter);
3417 m_blank = (delimiter + 1 < maskFields.length()) ? maskFields[delimiter + 1] : QLatin1Char(' ');
3420 // calculate m_maxLength / m_maskData length
3423 for (int i=0; i<m_inputMask.length(); i++) {
3424 c = m_inputMask.at(i);
3425 if (i > 0 && m_inputMask.at(i-1) == QLatin1Char('\\')) {
3429 if (c != QLatin1Char('\\') && c != QLatin1Char('!') &&
3430 c != QLatin1Char('<') && c != QLatin1Char('>') &&
3431 c != QLatin1Char('{') && c != QLatin1Char('}') &&
3432 c != QLatin1Char('[') && c != QLatin1Char(']'))
3436 delete [] m_maskData;
3437 m_maskData = new MaskInputData[m_maxLength];
3439 MaskInputData::Casemode m = MaskInputData::NoCaseMode;
3442 bool escape = false;
3444 for (int i = 0; i < m_inputMask.length(); i++) {
3445 c = m_inputMask.at(i);
3448 m_maskData[index].maskChar = c;
3449 m_maskData[index].separator = s;
3450 m_maskData[index].caseMode = m;
3453 } else if (c == QLatin1Char('<')) {
3454 m = MaskInputData::Lower;
3455 } else if (c == QLatin1Char('>')) {
3456 m = MaskInputData::Upper;
3457 } else if (c == QLatin1Char('!')) {
3458 m = MaskInputData::NoCaseMode;
3459 } else if (c != QLatin1Char('{') && c != QLatin1Char('}') && c != QLatin1Char('[') && c != QLatin1Char(']')) {
3460 switch (c.unicode()) {
3486 m_maskData[index].maskChar = c;
3487 m_maskData[index].separator = s;
3488 m_maskData[index].caseMode = m;
3493 internalSetText(m_text);
3500 checks if the key is valid compared to the inputMask
3502 bool QQuickTextInputPrivate::isValidInput(QChar key, QChar mask) const
3504 switch (mask.unicode()) {
3510 if (key.isLetter() || key == m_blank)
3514 if (key.isLetterOrNumber())
3518 if (key.isLetterOrNumber() || key == m_blank)
3526 if (key.isPrint() || key == m_blank)
3534 if (key.isNumber() || key == m_blank)
3538 if (key.isNumber() && key.digitValue() > 0)
3542 if ((key.isNumber() && key.digitValue() > 0) || key == m_blank)
3546 if (key.isNumber() || key == QLatin1Char('+') || key == QLatin1Char('-') || key == m_blank)
3550 if (key == QLatin1Char('0') || key == QLatin1Char('1'))
3554 if (key == QLatin1Char('0') || key == QLatin1Char('1') || key == m_blank)
3558 if (key.isNumber() || (key >= QLatin1Char('a') && key <= QLatin1Char('f')) || (key >= QLatin1Char('A') && key <= QLatin1Char('F')))
3562 if (key.isNumber() || (key >= QLatin1Char('a') && key <= QLatin1Char('f')) || (key >= QLatin1Char('A') && key <= QLatin1Char('F')) || key == m_blank)
3574 Returns true if the given text \a str is valid for any
3575 validator or input mask set for the line control.
3577 Otherwise returns false
3579 QQuickTextInputPrivate::ValidatorState QQuickTextInputPrivate::hasAcceptableInput(const QString &str) const
3581 #ifndef QT_NO_VALIDATOR
3582 QString textCopy = str;
3583 int cursorCopy = m_cursor;
3585 QValidator::State state = m_validator->validate(textCopy, cursorCopy);
3586 if (state != QValidator::Acceptable)
3587 return ValidatorState(state);
3592 return AcceptableInput;
3594 if (str.length() != m_maxLength)
3595 return InvalidInput;
3597 for (int i=0; i < m_maxLength; ++i) {
3598 if (m_maskData[i].separator) {
3599 if (str.at(i) != m_maskData[i].maskChar)
3600 return InvalidInput;
3602 if (!isValidInput(str.at(i), m_maskData[i].maskChar))
3603 return InvalidInput;
3606 return AcceptableInput;
3612 Applies the inputMask on \a str starting from position \a pos in the mask. \a clear
3613 specifies from where characters should be gotten when a separator is met in \a str - true means
3614 that blanks will be used, false that previous input is used.
3615 Calling this when no inputMask is set is undefined.
3617 QString QQuickTextInputPrivate::maskString(uint pos, const QString &str, bool clear) const
3619 if (pos >= (uint)m_maxLength)
3620 return QString::fromLatin1("");
3623 fill = clear ? clearString(0, m_maxLength) : m_text;
3626 QString s = QString::fromLatin1("");
3628 while (i < m_maxLength) {
3629 if (strIndex < str.length()) {
3630 if (m_maskData[i].separator) {
3631 s += m_maskData[i].maskChar;
3632 if (str[(int)strIndex] == m_maskData[i].maskChar)
3636 if (isValidInput(str[(int)strIndex], m_maskData[i].maskChar)) {
3637 switch (m_maskData[i].caseMode) {
3638 case MaskInputData::Upper:
3639 s += str[(int)strIndex].toUpper();
3641 case MaskInputData::Lower:
3642 s += str[(int)strIndex].toLower();
3645 s += str[(int)strIndex];
3649 // search for separator first
3650 int n = findInMask(i, true, true, str[(int)strIndex]);
3652 if (str.length() != 1 || i == 0 || (i > 0 && (!m_maskData[i-1].separator || m_maskData[i-1].maskChar != str[(int)strIndex]))) {
3653 s += fill.mid(i, n-i+1);
3654 i = n + 1; // update i to find + 1
3657 // search for valid m_blank if not
3658 n = findInMask(i, true, false, str[(int)strIndex]);
3660 s += fill.mid(i, n-i);
3661 switch (m_maskData[n].caseMode) {
3662 case MaskInputData::Upper:
3663 s += str[(int)strIndex].toUpper();
3665 case MaskInputData::Lower:
3666 s += str[(int)strIndex].toLower();
3669 s += str[(int)strIndex];
3671 i = n + 1; // updates i to find + 1
3689 Returns a "cleared" string with only separators and blank chars.
3690 Calling this when no inputMask is set is undefined.
3692 QString QQuickTextInputPrivate::clearString(uint pos, uint len) const
3694 if (pos >= (uint)m_maxLength)
3698 int end = qMin((uint)m_maxLength, pos + len);
3699 for (int i = pos; i < end; ++i)
3700 if (m_maskData[i].separator)
3701 s += m_maskData[i].maskChar;
3711 Strips blank parts of the input in a QQuickTextInputPrivate when an inputMask is set,
3712 separators are still included. Typically "127.0__.0__.1__" becomes "127.0.0.1".
3714 QString QQuickTextInputPrivate::stripString(const QString &str) const
3720 int end = qMin(m_maxLength, (int)str.length());
3721 for (int i = 0; i < end; ++i) {
3722 if (m_maskData[i].separator)
3723 s += m_maskData[i].maskChar;
3724 else if (str[i] != m_blank)
3733 searches forward/backward in m_maskData for either a separator or a m_blank
3735 int QQuickTextInputPrivate::findInMask(int pos, bool forward, bool findSeparator, QChar searchChar) const
3737 if (pos >= m_maxLength || pos < 0)
3740 int end = forward ? m_maxLength : -1;
3741 int step = forward ? 1 : -1;
3745 if (findSeparator) {
3746 if (m_maskData[i].separator && m_maskData[i].maskChar == searchChar)
3749 if (!m_maskData[i].separator) {
3750 if (searchChar.isNull())
3752 else if (isValidInput(searchChar, m_maskData[i].maskChar))
3761 void QQuickTextInputPrivate::internalUndo(int until)
3763 if (!isUndoAvailable())
3765 cancelPasswordEchoTimer();
3767 while (m_undoState && m_undoState > until) {
3768 Command& cmd = m_history[--m_undoState];
3771 m_text.remove(cmd.pos, 1);
3775 m_selstart = cmd.selStart;
3776 m_selend = cmd.selEnd;
3780 case RemoveSelection:
3781 m_text.insert(cmd.pos, cmd.uc);
3782 m_cursor = cmd.pos + 1;
3785 case DeleteSelection:
3786 m_text.insert(cmd.pos, cmd.uc);
3792 if (until < 0 && m_undoState) {
3793 Command& next = m_history[m_undoState-1];
3794 if (next.type != cmd.type && next.type < RemoveSelection
3795 && (cmd.type < RemoveSelection || next.type == Separator))
3802 void QQuickTextInputPrivate::internalRedo()
3804 if (!isRedoAvailable())
3807 while (m_undoState < (int)m_history.size()) {
3808 Command& cmd = m_history[m_undoState++];
3811 m_text.insert(cmd.pos, cmd.uc);
3812 m_cursor = cmd.pos + 1;
3815 m_selstart = cmd.selStart;
3816 m_selend = cmd.selEnd;
3821 case RemoveSelection:
3822 case DeleteSelection:
3823 m_text.remove(cmd.pos, 1);
3824 m_selstart = cmd.selStart;
3825 m_selend = cmd.selEnd;
3829 m_selstart = cmd.selStart;
3830 m_selend = cmd.selEnd;
3834 if (m_undoState < (int)m_history.size()) {
3835 Command& next = m_history[m_undoState];
3836 if (next.type != cmd.type && cmd.type < RemoveSelection && next.type != Separator
3837 && (next.type < RemoveSelection || cmd.type == Separator))
3844 void QQuickTextInputPrivate::emitUndoRedoChanged()
3846 Q_Q(QQuickTextInput);
3847 const bool previousUndo = canUndo;
3848 const bool previousRedo = canRedo;
3850 canUndo = isUndoAvailable();
3851 canRedo = isRedoAvailable();
3853 if (previousUndo != canUndo)
3854 emit q->canUndoChanged();
3855 if (previousRedo != canRedo)
3856 emit q->canRedoChanged();
3862 If the current cursor position differs from the last emitted cursor
3863 position, emits cursorPositionChanged().
3865 bool QQuickTextInputPrivate::emitCursorPositionChanged()
3867 Q_Q(QQuickTextInput);
3868 if (m_cursor != m_lastCursorPos) {
3869 m_lastCursorPos = m_cursor;
3871 q->updateCursorRectangle();
3872 emit q->cursorPositionChanged();
3873 // XXX todo - not in 4.8?
3875 resetCursorBlinkTimer();
3878 if (!hasSelectedText()) {
3879 if (lastSelectionStart != m_cursor) {
3880 lastSelectionStart = m_cursor;
3881 emit q->selectionStartChanged();
3883 if (lastSelectionEnd != m_cursor) {
3884 lastSelectionEnd = m_cursor;
3885 emit q->selectionEndChanged();
3889 #ifndef QT_NO_ACCESSIBILITY
3890 QAccessible::updateAccessibility(QAccessibleEvent(QAccessible::TextCaretMoved, q, 0));
3899 void QQuickTextInputPrivate::setCursorBlinkPeriod(int msec)
3901 Q_Q(QQuickTextInput);
3902 if (msec == m_blinkPeriod)
3905 q->killTimer(m_blinkTimer);
3908 m_blinkTimer = q->startTimer(msec / 2);
3912 if (m_blinkStatus == 1) {
3913 updateType = UpdatePaintNode;
3917 m_blinkPeriod = msec;
3920 void QQuickTextInputPrivate::resetCursorBlinkTimer()
3922 Q_Q(QQuickTextInput);
3923 if (m_blinkPeriod == 0 || m_blinkTimer == 0)
3925 q->killTimer(m_blinkTimer);
3926 m_blinkTimer = q->startTimer(m_blinkPeriod / 2);
3930 void QQuickTextInput::timerEvent(QTimerEvent *event)
3932 Q_D(QQuickTextInput);
3933 if (event->timerId() == d->m_blinkTimer) {
3934 d->m_blinkStatus = !d->m_blinkStatus;
3935 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
3937 } else if (event->timerId() == d->m_deleteAllTimer) {
3938 killTimer(d->m_deleteAllTimer);
3939 d->m_deleteAllTimer = 0;
3941 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
3942 } else if (event->timerId() == d->m_passwordEchoTimer.timerId()) {
3943 d->m_passwordEchoTimer.stop();
3944 d->updateDisplayText();
3949 void QQuickTextInputPrivate::processKeyEvent(QKeyEvent* event)
3951 Q_Q(QQuickTextInput);
3952 bool inlineCompletionAccepted = false;
3954 if (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return) {
3955 if (hasAcceptableInput(m_text) || fixup()) {
3958 if (inlineCompletionAccepted)
3965 if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit
3966 && !m_passwordEchoEditing
3968 && !event->text().isEmpty()
3969 && !(event->modifiers() & Qt::ControlModifier)) {
3970 // Clear the edit and reset to normal echo mode while editing; the
3971 // echo mode switches back when the edit loses focus
3972 // ### resets current content. dubious code; you can
3973 // navigate with keys up, down, back, and select(?), but if you press
3974 // "left" or "right" it clears?
3975 updatePasswordEchoEditing(true);
3979 bool unknown = false;
3980 bool visual = cursorMoveStyle() == Qt::VisualMoveStyle;
3984 #ifndef QT_NO_SHORTCUT
3985 else if (event == QKeySequence::Undo) {
3989 else if (event == QKeySequence::Redo) {
3993 else if (event == QKeySequence::SelectAll) {
3996 #ifndef QT_NO_CLIPBOARD
3997 else if (event == QKeySequence::Copy) {
4000 else if (event == QKeySequence::Paste) {
4002 QClipboard::Mode mode = QClipboard::Clipboard;
4006 else if (event == QKeySequence::Cut) {
4012 else if (event == QKeySequence::DeleteEndOfLine) {
4014 setSelection(m_cursor, end());
4019 #endif //QT_NO_CLIPBOARD
4020 else if (event == QKeySequence::MoveToStartOfLine || event == QKeySequence::MoveToStartOfBlock) {
4023 else if (event == QKeySequence::MoveToEndOfLine || event == QKeySequence::MoveToEndOfBlock) {
4026 else if (event == QKeySequence::SelectStartOfLine || event == QKeySequence::SelectStartOfBlock) {
4029 else if (event == QKeySequence::SelectEndOfLine || event == QKeySequence::SelectEndOfBlock) {
4032 else if (event == QKeySequence::MoveToNextChar) {
4033 if (hasSelectedText()) {
4034 moveCursor(selectionEnd(), false);
4036 cursorForward(0, visual ? 1 : (layoutDirection() == Qt::LeftToRight ? 1 : -1));
4039 else if (event == QKeySequence::SelectNextChar) {
4040 cursorForward(1, visual ? 1 : (layoutDirection() == Qt::LeftToRight ? 1 : -1));
4042 else if (event == QKeySequence::MoveToPreviousChar) {
4043 if (hasSelectedText()) {
4044 moveCursor(selectionStart(), false);
4046 cursorForward(0, visual ? -1 : (layoutDirection() == Qt::LeftToRight ? -1 : 1));
4049 else if (event == QKeySequence::SelectPreviousChar) {
4050 cursorForward(1, visual ? -1 : (layoutDirection() == Qt::LeftToRight ? -1 : 1));
4052 else if (event == QKeySequence::MoveToNextWord) {
4053 if (m_echoMode == QQuickTextInput::Normal)
4054 layoutDirection() == Qt::LeftToRight ? cursorWordForward(0) : cursorWordBackward(0);
4056 layoutDirection() == Qt::LeftToRight ? end(0) : home(0);
4058 else if (event == QKeySequence::MoveToPreviousWord) {
4059 if (m_echoMode == QQuickTextInput::Normal)
4060 layoutDirection() == Qt::LeftToRight ? cursorWordBackward(0) : cursorWordForward(0);
4061 else if (!m_readOnly) {
4062 layoutDirection() == Qt::LeftToRight ? home(0) : end(0);
4065 else if (event == QKeySequence::SelectNextWord) {
4066 if (m_echoMode == QQuickTextInput::Normal)
4067 layoutDirection() == Qt::LeftToRight ? cursorWordForward(1) : cursorWordBackward(1);
4069 layoutDirection() == Qt::LeftToRight ? end(1) : home(1);
4071 else if (event == QKeySequence::SelectPreviousWord) {
4072 if (m_echoMode == QQuickTextInput::Normal)
4073 layoutDirection() == Qt::LeftToRight ? cursorWordBackward(1) : cursorWordForward(1);
4075 layoutDirection() == Qt::LeftToRight ? home(1) : end(1);
4077 else if (event == QKeySequence::Delete) {
4081 else if (event == QKeySequence::DeleteEndOfWord) {
4083 cursorWordForward(true);
4087 else if (event == QKeySequence::DeleteStartOfWord) {
4089 cursorWordBackward(true);
4093 #endif // QT_NO_SHORTCUT
4095 bool handled = false;
4096 if (event->modifiers() & Qt::ControlModifier) {
4097 switch (event->key()) {
4098 case Qt::Key_Backspace:
4100 cursorWordBackward(true);
4108 } else { // ### check for *no* modifier
4109 switch (event->key()) {
4110 case Qt::Key_Backspace:
4122 if (event->key() == Qt::Key_Direction_L || event->key() == Qt::Key_Direction_R) {
4123 setLayoutDirection((event->key() == Qt::Key_Direction_L) ? Qt::LeftToRight : Qt::RightToLeft);
4127 if (unknown && !m_readOnly) {
4128 QString t = event->text();
4129 if (!t.isEmpty() && t.at(0).isPrint()) {