1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the QtDeclarative module of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #include "qquicktextinput_p.h"
43 #include "qquicktextinput_p_p.h"
44 #include "qquickcanvas.h"
46 #include <private/qdeclarativeglobal_p.h>
48 #include <QtDeclarative/qdeclarativeinfo.h>
49 #include <QtGui/qevent.h>
50 #include <QTextBoundaryFinder>
51 #include "qquicktextnode_p.h"
52 #include <QtQuick/qsgsimplerectnode.h>
54 #include <QtGui/qstylehints.h>
55 #include <QtGui/qinputmethod.h>
57 #ifndef QT_NO_ACCESSIBILITY
58 #include "qaccessible.h"
63 DEFINE_BOOL_CONFIG_OPTION(qmlDisableDistanceField, QML_DISABLE_DISTANCEFIELD)
65 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
66 static const int qt_passwordEchoDelay = QT_GUI_PASSWORD_ECHO_DELAY;
70 \qmlclass TextInput QQuickTextInput
71 \inqmlmodule QtQuick 2
72 \ingroup qml-basic-visual-elements
73 \brief The TextInput item displays an editable line of text.
76 The TextInput element displays a single line of editable plain text.
78 TextInput is used to accept a line of text input. Input constraints
79 can be placed on a TextInput item (for example, through a \l validator or \l inputMask),
80 and setting \l echoMode to an appropriate value enables TextInput to be used for
81 a password input field.
83 On Mac OS X, the Up/Down key bindings for Home/End are explicitly disabled.
84 If you want such bindings (on any platform), you will need to construct them in QML.
86 \sa TextEdit, Text, {declarative/text/textselection}{Text Selection example}
88 QQuickTextInput::QQuickTextInput(QQuickItem* parent)
89 : QQuickImplicitSizeItem(*(new QQuickTextInputPrivate), parent)
95 QQuickTextInput::~QQuickTextInput()
99 void QQuickTextInput::componentComplete()
101 Q_D(QQuickTextInput);
103 QQuickImplicitSizeItem::componentComplete();
107 updateCursorRectangle();
108 if (d->cursorComponent && d->cursorComponent->isReady())
113 \qmlproperty string QtQuick2::TextInput::text
115 The text in the TextInput.
117 QString QQuickTextInput::text() const
119 Q_D(const QQuickTextInput);
121 QString content = d->m_text;
122 if (!d->m_tentativeCommit.isEmpty())
123 content.insert(d->m_cursor, d->m_tentativeCommit);
124 QString res = d->m_maskData ? d->stripString(content) : content;
125 return (res.isNull() ? QString::fromLatin1("") : res);
128 void QQuickTextInput::setText(const QString &s)
130 Q_D(QQuickTextInput);
133 if (d->composeMode())
134 qApp->inputMethod()->reset();
135 d->m_tentativeCommit.clear();
136 d->internalSetText(s, -1, false);
140 \qmlproperty int QtQuick2::TextInput::length
142 Returns the total number of characters in the TextInput item.
144 If the TextInput has an inputMask the length will include mask characters and may differ
145 from the length of the string returned by the \l text property.
147 This property can be faster than querying the length the \l text property as it doesn't
148 require any copying or conversion of the TextInput's internal string data.
151 int QQuickTextInput::length() const
153 Q_D(const QQuickTextInput);
154 return d->m_text.length();
158 \qmlmethod string QtQuick2::TextInput::getText(int start, int end)
160 Returns the section of text that is between the \a start and \a end positions.
162 If the TextInput has an inputMask the length will include mask characters.
165 QString QQuickTextInput::getText(int start, int end) const
167 Q_D(const QQuickTextInput);
172 return d->m_text.mid(start, end - start);
175 QString QQuickTextInputPrivate::realText() const
177 QString res = m_maskData ? stripString(m_text) : m_text;
178 return (res.isNull() ? QString::fromLatin1("") : res);
182 \qmlproperty string QtQuick2::TextInput::font.family
184 Sets the family name of the font.
186 The family name is case insensitive and may optionally include a foundry name, e.g. "Helvetica [Cronyx]".
187 If the family is available from more than one foundry and the foundry isn't specified, an arbitrary foundry is chosen.
188 If the family isn't available a family will be set using the font matching algorithm.
192 \qmlproperty bool QtQuick2::TextInput::font.bold
194 Sets whether the font weight is bold.
198 \qmlproperty enumeration QtQuick2::TextInput::font.weight
200 Sets the font's weight.
202 The weight can be one of:
205 \o Font.Normal - the default
212 TextInput { text: "Hello"; font.weight: Font.DemiBold }
217 \qmlproperty bool QtQuick2::TextInput::font.italic
219 Sets whether the font has an italic style.
223 \qmlproperty bool QtQuick2::TextInput::font.underline
225 Sets whether the text is underlined.
229 \qmlproperty bool QtQuick2::TextInput::font.strikeout
231 Sets whether the font has a strikeout style.
235 \qmlproperty real QtQuick2::TextInput::font.pointSize
237 Sets the font size in points. The point size must be greater than zero.
241 \qmlproperty int QtQuick2::TextInput::font.pixelSize
243 Sets the font size in pixels.
245 Using this function makes the font device dependent.
246 Use \c pointSize to set the size of the font in a device independent manner.
250 \qmlproperty real QtQuick2::TextInput::font.letterSpacing
252 Sets the letter spacing for the font.
254 Letter spacing changes the default spacing between individual letters in the font.
255 A positive value increases the letter spacing by the corresponding pixels; a negative value decreases the spacing.
259 \qmlproperty real QtQuick2::TextInput::font.wordSpacing
261 Sets the word spacing for the font.
263 Word spacing changes the default spacing between individual words.
264 A positive value increases the word spacing by a corresponding amount of pixels,
265 while a negative value decreases the inter-word spacing accordingly.
269 \qmlproperty enumeration QtQuick2::TextInput::font.capitalization
271 Sets the capitalization for the text.
274 \o Font.MixedCase - This is the normal text rendering option where no capitalization change is applied.
275 \o Font.AllUppercase - This alters the text to be rendered in all uppercase type.
276 \o Font.AllLowercase - This alters the text to be rendered in all lowercase type.
277 \o Font.SmallCaps - This alters the text to be rendered in small-caps type.
278 \o Font.Capitalize - This alters the text to be rendered with the first character of each word as an uppercase character.
282 TextInput { text: "Hello"; font.capitalization: Font.AllLowercase }
286 QFont QQuickTextInput::font() const
288 Q_D(const QQuickTextInput);
289 return d->sourceFont;
292 void QQuickTextInput::setFont(const QFont &font)
294 Q_D(QQuickTextInput);
295 if (d->sourceFont == font)
298 d->sourceFont = font;
299 QFont oldFont = d->font;
301 if (d->font.pointSizeF() != -1) {
303 qreal size = qRound(d->font.pointSizeF()*2.0);
304 d->font.setPointSizeF(size/2.0);
306 if (oldFont != d->font) {
308 updateCursorRectangle();
309 updateInputMethod(Qt::ImCursorRectangle | Qt::ImFont);
311 emit fontChanged(d->sourceFont);
315 \qmlproperty color QtQuick2::TextInput::color
319 QColor QQuickTextInput::color() const
321 Q_D(const QQuickTextInput);
325 void QQuickTextInput::setColor(const QColor &c)
327 Q_D(QQuickTextInput);
330 d->textLayoutDirty = true;
331 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
333 emit colorChanged(c);
339 \qmlproperty color QtQuick2::TextInput::selectionColor
341 The text highlight color, used behind selections.
343 QColor QQuickTextInput::selectionColor() const
345 Q_D(const QQuickTextInput);
346 return d->selectionColor;
349 void QQuickTextInput::setSelectionColor(const QColor &color)
351 Q_D(QQuickTextInput);
352 if (d->selectionColor == color)
355 d->selectionColor = color;
356 d->m_palette.setColor(QPalette::Highlight, d->selectionColor);
357 if (d->hasSelectedText()) {
358 d->textLayoutDirty = true;
359 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
362 emit selectionColorChanged(color);
365 \qmlproperty color QtQuick2::TextInput::selectedTextColor
367 The highlighted text color, used in selections.
369 QColor QQuickTextInput::selectedTextColor() const
371 Q_D(const QQuickTextInput);
372 return d->selectedTextColor;
375 void QQuickTextInput::setSelectedTextColor(const QColor &color)
377 Q_D(QQuickTextInput);
378 if (d->selectedTextColor == color)
381 d->selectedTextColor = color;
382 d->m_palette.setColor(QPalette::HighlightedText, d->selectedTextColor);
383 if (d->hasSelectedText()) {
384 d->textLayoutDirty = true;
385 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
388 emit selectedTextColorChanged(color);
392 \qmlproperty enumeration QtQuick2::TextInput::horizontalAlignment
393 \qmlproperty enumeration QtQuick2::TextInput::effectiveHorizontalAlignment
394 \qmlproperty enumeration QtQuick2::TextInput::verticalAlignment
396 Sets the horizontal alignment of the text within the TextInput item's
397 width and height. By default, the text alignment follows the natural alignment
398 of the text, for example text that is read from left to right will be aligned to
401 TextInput does not have vertical alignment, as the natural height is
402 exactly the height of the single line of text. If you set the height
403 manually to something larger, TextInput will always be top aligned
404 vertically. You can use anchors to align it however you want within
407 The valid values for \c horizontalAlignment are \c TextInput.AlignLeft, \c TextInput.AlignRight and
408 \c TextInput.AlignHCenter.
410 Valid values for \c verticalAlignment are \c TextInput.AlignTop (default),
411 \c TextInput.AlignBottom \c TextInput.AlignVCenter.
413 When using the attached property LayoutMirroring::enabled to mirror application
414 layouts, the horizontal alignment of text will also be mirrored. However, the property
415 \c horizontalAlignment will remain unchanged. To query the effective horizontal alignment
416 of TextInput, use the read-only property \c effectiveHorizontalAlignment.
418 QQuickTextInput::HAlignment QQuickTextInput::hAlign() const
420 Q_D(const QQuickTextInput);
424 void QQuickTextInput::setHAlign(HAlignment align)
426 Q_D(QQuickTextInput);
427 bool forceAlign = d->hAlignImplicit && d->effectiveLayoutMirror;
428 d->hAlignImplicit = false;
429 if (d->setHAlign(align, forceAlign) && isComponentComplete()) {
431 updateCursorRectangle();
435 void QQuickTextInput::resetHAlign()
437 Q_D(QQuickTextInput);
438 d->hAlignImplicit = true;
439 if (d->determineHorizontalAlignment() && isComponentComplete()) {
441 updateCursorRectangle();
445 QQuickTextInput::HAlignment QQuickTextInput::effectiveHAlign() const
447 Q_D(const QQuickTextInput);
448 QQuickTextInput::HAlignment effectiveAlignment = d->hAlign;
449 if (!d->hAlignImplicit && d->effectiveLayoutMirror) {
451 case QQuickTextInput::AlignLeft:
452 effectiveAlignment = QQuickTextInput::AlignRight;
454 case QQuickTextInput::AlignRight:
455 effectiveAlignment = QQuickTextInput::AlignLeft;
461 return effectiveAlignment;
464 bool QQuickTextInputPrivate::setHAlign(QQuickTextInput::HAlignment alignment, bool forceAlign)
466 Q_Q(QQuickTextInput);
467 if ((hAlign != alignment || forceAlign) && alignment <= QQuickTextInput::AlignHCenter) { // justify not supported
468 QQuickTextInput::HAlignment oldEffectiveHAlign = q->effectiveHAlign();
470 emit q->horizontalAlignmentChanged(alignment);
471 if (oldEffectiveHAlign != q->effectiveHAlign())
472 emit q->effectiveHorizontalAlignmentChanged();
478 bool QQuickTextInputPrivate::determineHorizontalAlignment()
480 if (hAlignImplicit) {
481 // if no explicit alignment has been set, follow the natural layout direction of the text
482 QString text = q_func()->text();
484 text = m_textLayout.preeditAreaText();
485 bool isRightToLeft = text.isEmpty() ? qApp->inputMethod()->inputDirection() == Qt::RightToLeft
486 : text.isRightToLeft();
487 return setHAlign(isRightToLeft ? QQuickTextInput::AlignRight : QQuickTextInput::AlignLeft);
492 QQuickTextInput::VAlignment QQuickTextInput::vAlign() const
494 Q_D(const QQuickTextInput);
498 void QQuickTextInput::setVAlign(QQuickTextInput::VAlignment alignment)
500 Q_D(QQuickTextInput);
501 if (alignment == d->vAlign)
503 d->vAlign = alignment;
504 emit verticalAlignmentChanged(d->vAlign);
505 if (isComponentComplete()) {
506 updateCursorRectangle();
511 \qmlproperty enumeration QtQuick2::TextInput::wrapMode
513 Set this property to wrap the text to the TextInput item's width.
514 The text will only wrap if an explicit width has been set.
517 \o TextInput.NoWrap - no wrapping will be performed. If the text contains insufficient newlines, then implicitWidth will exceed a set width.
518 \o TextInput.WordWrap - wrapping is done on word boundaries only. If a word is too long, implicitWidth will exceed a set width.
519 \o TextInput.WrapAnywhere - wrapping is done at any point on a line, even if it occurs in the middle of a word.
520 \o TextInput.Wrap - if possible, wrapping occurs at a word boundary; otherwise it will occur at the appropriate point on the line, even in the middle of a word.
523 The default is TextInput.NoWrap. If you set a width, consider using TextInput.Wrap.
525 QQuickTextInput::WrapMode QQuickTextInput::wrapMode() const
527 Q_D(const QQuickTextInput);
531 void QQuickTextInput::setWrapMode(WrapMode mode)
533 Q_D(QQuickTextInput);
534 if (mode == d->wrapMode)
538 updateCursorRectangle();
539 emit wrapModeChanged();
542 void QQuickTextInputPrivate::mirrorChange()
544 Q_Q(QQuickTextInput);
545 if (q->isComponentComplete()) {
546 if (!hAlignImplicit && (hAlign == QQuickTextInput::AlignRight || hAlign == QQuickTextInput::AlignLeft)) {
547 q->updateCursorRectangle();
548 emit q->effectiveHorizontalAlignmentChanged();
554 \qmlproperty bool QtQuick2::TextInput::readOnly
556 Sets whether user input can modify the contents of the TextInput.
558 If readOnly is set to true, then user input will not affect the text
559 property. Any bindings or attempts to set the text property will still
562 bool QQuickTextInput::isReadOnly() const
564 Q_D(const QQuickTextInput);
565 return d->m_readOnly;
568 void QQuickTextInput::setReadOnly(bool ro)
570 Q_D(QQuickTextInput);
571 if (d->m_readOnly == ro)
574 setFlag(QQuickItem::ItemAcceptsInputMethod, !ro);
577 d->setCursorPosition(d->end());
578 updateInputMethod(Qt::ImEnabled);
580 d->emitUndoRedoChanged();
581 emit readOnlyChanged(ro);
585 \qmlproperty int QtQuick2::TextInput::maximumLength
586 The maximum permitted length of the text in the TextInput.
588 If the text is too long, it is truncated at the limit.
590 By default, this property contains a value of 32767.
592 int QQuickTextInput::maxLength() const
594 Q_D(const QQuickTextInput);
595 return d->m_maxLength;
598 void QQuickTextInput::setMaxLength(int ml)
600 Q_D(QQuickTextInput);
601 if (d->m_maxLength == ml || d->m_maskData)
605 d->internalSetText(d->m_text, -1, false);
607 emit maximumLengthChanged(ml);
611 \qmlproperty bool QtQuick2::TextInput::cursorVisible
612 Set to true when the TextInput shows a cursor.
614 This property is set and unset when the TextInput gets active focus, so that other
615 properties can be bound to whether the cursor is currently showing. As it
616 gets set and unset automatically, when you set the value yourself you must
617 keep in mind that your value may be overwritten.
619 It can be set directly in script, for example if a KeyProxy might
620 forward keys to it and you desire it to look active when this happens
621 (but without actually giving it active focus).
623 It should not be set directly on the element, like in the below QML,
624 as the specified value will be overridden an lost on focus changes.
633 In the above snippet the cursor will still become visible when the
634 TextInput gains active focus.
636 bool QQuickTextInput::isCursorVisible() const
638 Q_D(const QQuickTextInput);
639 return d->cursorVisible;
642 void QQuickTextInput::setCursorVisible(bool on)
644 Q_D(QQuickTextInput);
645 if (d->cursorVisible == on)
647 d->cursorVisible = on;
648 d->setCursorBlinkPeriod(on ? qApp->styleHints()->cursorFlashTime() : 0);
649 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
651 emit cursorVisibleChanged(d->cursorVisible);
655 \qmlproperty int QtQuick2::TextInput::cursorPosition
656 The position of the cursor in the TextInput.
658 int QQuickTextInput::cursorPosition() const
660 Q_D(const QQuickTextInput);
664 void QQuickTextInput::setCursorPosition(int cp)
666 Q_D(QQuickTextInput);
667 if (cp < 0 || cp > text().length())
673 \qmlproperty rectangle QtQuick2::TextInput::cursorRectangle
675 The rectangle where the standard text cursor is rendered within the text input. Read only.
677 The position and height of a custom cursorDelegate are updated to follow the cursorRectangle
678 automatically when it changes. The width of the delegate is unaffected by changes in the
682 QRect QQuickTextInput::cursorRectangle() const
684 Q_D(const QQuickTextInput);
687 if (d->m_preeditCursor != -1)
688 c += d->m_preeditCursor;
689 if (d->m_echoMode == NoEcho)
691 QTextLine l = d->m_textLayout.lineForTextPosition(c);
695 qRound(l.cursorToX(c) - d->hscroll),
696 qRound(l.y() - d->vscroll),
702 \qmlproperty int QtQuick2::TextInput::selectionStart
704 The cursor position before the first character in the current selection.
706 This property is read-only. To change the selection, use select(start,end),
707 selectAll(), or selectWord().
709 \sa selectionEnd, cursorPosition, selectedText
711 int QQuickTextInput::selectionStart() const
713 Q_D(const QQuickTextInput);
714 return d->lastSelectionStart;
717 \qmlproperty int QtQuick2::TextInput::selectionEnd
719 The cursor position after the last character in the current selection.
721 This property is read-only. To change the selection, use select(start,end),
722 selectAll(), or selectWord().
724 \sa selectionStart, cursorPosition, selectedText
726 int QQuickTextInput::selectionEnd() const
728 Q_D(const QQuickTextInput);
729 return d->lastSelectionEnd;
732 \qmlmethod void QtQuick2::TextInput::select(int start, int end)
734 Causes the text from \a start to \a end to be selected.
736 If either start or end is out of range, the selection is not changed.
738 After calling this, selectionStart will become the lesser
739 and selectionEnd will become the greater (regardless of the order passed
742 \sa selectionStart, selectionEnd
744 void QQuickTextInput::select(int start, int end)
746 Q_D(QQuickTextInput);
747 if (start < 0 || end < 0 || start > d->m_text.length() || end > d->m_text.length())
749 d->setSelection(start, end-start);
753 \qmlproperty string QtQuick2::TextInput::selectedText
755 This read-only property provides the text currently selected in the
758 It is equivalent to the following snippet, but is faster and easier
762 myTextInput.text.toString().substring(myTextInput.selectionStart,
763 myTextInput.selectionEnd);
766 QString QQuickTextInput::selectedText() const
768 Q_D(const QQuickTextInput);
769 return d->selectedText();
773 \qmlproperty bool QtQuick2::TextInput::activeFocusOnPress
775 Whether the TextInput should gain active focus on a mouse press. By default this is
778 bool QQuickTextInput::focusOnPress() const
780 Q_D(const QQuickTextInput);
781 return d->focusOnPress;
784 void QQuickTextInput::setFocusOnPress(bool b)
786 Q_D(QQuickTextInput);
787 if (d->focusOnPress == b)
792 emit activeFocusOnPressChanged(d->focusOnPress);
795 \qmlproperty bool QtQuick2::TextInput::autoScroll
797 Whether the TextInput should scroll when the text is longer than the width. By default this is
800 bool QQuickTextInput::autoScroll() const
802 Q_D(const QQuickTextInput);
803 return d->autoScroll;
806 void QQuickTextInput::setAutoScroll(bool b)
808 Q_D(QQuickTextInput);
809 if (d->autoScroll == b)
813 //We need to repaint so that the scrolling is taking into account.
814 updateCursorRectangle();
815 emit autoScrollChanged(d->autoScroll);
818 #ifndef QT_NO_VALIDATOR
821 \qmlclass IntValidator QIntValidator
822 \inqmlmodule QtQuick 2
823 \ingroup qml-basic-visual-elements
825 This element provides a validator for integer values.
827 If no \l locale is set IntValidator uses the \l {QLocale::setDefault()}{default locale} to
828 interpret the number and will accept locale specific digits, group separators, and positive
829 and negative signs. In addition, IntValidator is always guaranteed to accept a number
830 formatted according to the "C" locale.
834 QQuickIntValidator::QQuickIntValidator(QObject *parent)
835 : QIntValidator(parent)
840 \qmlproperty string QtQuick2::IntValidator::locale
842 This property holds the name of the locale used to interpret the number.
847 QString QQuickIntValidator::localeName() const
849 return locale().name();
852 void QQuickIntValidator::setLocaleName(const QString &name)
854 if (locale().name() != name) {
855 setLocale(QLocale(name));
856 emit localeNameChanged();
860 void QQuickIntValidator::resetLocaleName()
862 QLocale defaultLocale;
863 if (locale() != defaultLocale) {
864 setLocale(defaultLocale);
865 emit localeNameChanged();
870 \qmlproperty int QtQuick2::IntValidator::top
872 This property holds the validator's highest acceptable value.
873 By default, this property's value is derived from the highest signed integer available (typically 2147483647).
876 \qmlproperty int QtQuick2::IntValidator::bottom
878 This property holds the validator's lowest acceptable value.
879 By default, this property's value is derived from the lowest signed integer available (typically -2147483647).
883 \qmlclass DoubleValidator QDoubleValidator
884 \inqmlmodule QtQuick 2
885 \ingroup qml-basic-visual-elements
887 This element provides a validator for non-integer numbers.
889 Input is accepted if it contains a double that is within the valid range
890 and is in the correct format.
892 Input is accepected but invalid if it contains a double that is outside
893 the range or is in the wrong format; e.g. with too many digits after the
894 decimal point or is empty.
896 Input is rejected if it is not a double.
898 Note: If the valid range consists of just positive doubles (e.g. 0.0 to
899 100.0) and input is a negative double then it is rejected. If \l notation
900 is set to DoubleValidator.StandardNotation, and the input contains more
901 digits before the decimal point than a double in the valid range may have,
902 it is also rejected. If \l notation is DoubleValidator.ScientificNotation,
903 and the input is not in the valid range, it is accecpted but invalid. The
904 value may yet become valid by changing the exponent.
907 QQuickDoubleValidator::QQuickDoubleValidator(QObject *parent)
908 : QDoubleValidator(parent)
913 \qmlproperty string QtQuick2::DoubleValidator::locale
915 This property holds the name of the locale used to interpret the number.
920 QString QQuickDoubleValidator::localeName() const
922 return locale().name();
925 void QQuickDoubleValidator::setLocaleName(const QString &name)
927 if (locale().name() != name) {
928 setLocale(QLocale(name));
929 emit localeNameChanged();
933 void QQuickDoubleValidator::resetLocaleName()
935 QLocale defaultLocale;
936 if (locale() != defaultLocale) {
937 setLocale(defaultLocale);
938 emit localeNameChanged();
943 \qmlproperty real QtQuick2::DoubleValidator::top
945 This property holds the validator's maximum acceptable value.
946 By default, this property contains a value of infinity.
949 \qmlproperty real QtQuick2::DoubleValidator::bottom
951 This property holds the validator's minimum acceptable value.
952 By default, this property contains a value of -infinity.
955 \qmlproperty int QtQuick2::DoubleValidator::decimals
957 This property holds the validator's maximum number of digits after the decimal point.
958 By default, this property contains a value of 1000.
961 \qmlproperty enumeration QtQuick2::DoubleValidator::notation
962 This property holds the notation of how a string can describe a number.
964 The possible values for this property are:
967 \o DoubleValidator.StandardNotation
968 \o DoubleValidator.ScientificNotation (default)
971 If this property is set to DoubleValidator.ScientificNotation, the written number may have an exponent part (e.g. 1.5E-2).
975 \qmlclass RegExpValidator QRegExpValidator
976 \inqmlmodule QtQuick 2
977 \ingroup qml-basic-visual-elements
979 This element provides a validator, which counts as valid any string which
980 matches a specified regular expression.
983 \qmlproperty regExp QtQuick2::RegExpValidator::regExp
985 This property holds the regular expression used for validation.
987 Note that this property should be a regular expression in JS syntax, e.g /a/ for the regular expression
990 By default, this property contains a regular expression with the pattern .* that matches any string.
994 \qmlproperty Validator QtQuick2::TextInput::validator
996 Allows you to set a validator on the TextInput. When a validator is set
997 the TextInput will only accept input which leaves the text property in
998 an acceptable or intermediate state. The accepted signal will only be sent
999 if the text is in an acceptable state when enter is pressed.
1001 Currently supported validators are IntValidator, DoubleValidator and
1002 RegExpValidator. An example of using validators is shown below, which allows
1003 input of integers between 11 and 31 into the text input:
1008 validator: IntValidator{bottom: 11; top: 31;}
1013 \sa acceptableInput, inputMask
1016 QValidator* QQuickTextInput::validator() const
1018 Q_D(const QQuickTextInput);
1019 return d->m_validator;
1022 void QQuickTextInput::setValidator(QValidator* v)
1024 Q_D(QQuickTextInput);
1025 if (d->m_validator == v)
1030 if (isComponentComplete())
1033 emit validatorChanged();
1036 #endif // QT_NO_VALIDATOR
1038 void QQuickTextInputPrivate::checkIsValid()
1040 Q_Q(QQuickTextInput);
1042 ValidatorState state = hasAcceptableInput(m_text);
1043 m_validInput = state != InvalidInput;
1044 if (state != AcceptableInput) {
1045 if (m_acceptableInput) {
1046 m_acceptableInput = false;
1047 emit q->acceptableInputChanged();
1049 } else if (!m_acceptableInput) {
1050 m_acceptableInput = true;
1051 emit q->acceptableInputChanged();
1056 \qmlproperty string QtQuick2::TextInput::inputMask
1058 Allows you to set an input mask on the TextInput, restricting the allowable
1059 text inputs. See QLineEdit::inputMask for further details, as the exact
1060 same mask strings are used by TextInput.
1062 \sa acceptableInput, validator
1064 QString QQuickTextInput::inputMask() const
1066 Q_D(const QQuickTextInput);
1067 return d->inputMask();
1070 void QQuickTextInput::setInputMask(const QString &im)
1072 Q_D(QQuickTextInput);
1073 if (d->inputMask() == im)
1076 d->setInputMask(im);
1077 emit inputMaskChanged(d->inputMask());
1081 \qmlproperty bool QtQuick2::TextInput::acceptableInput
1083 This property is always true unless a validator or input mask has been set.
1084 If a validator or input mask has been set, this property will only be true
1085 if the current text is acceptable to the validator or input mask as a final
1086 string (not as an intermediate string).
1088 bool QQuickTextInput::hasAcceptableInput() const
1090 Q_D(const QQuickTextInput);
1091 return d->hasAcceptableInput(d->m_text) == QQuickTextInputPrivate::AcceptableInput;
1095 \qmlsignal QtQuick2::TextInput::onAccepted()
1097 This handler is called when the Return or Enter key is pressed.
1098 Note that if there is a \l validator or \l inputMask set on the text
1099 input, the handler will only be emitted if the input is in an acceptable
1103 void QQuickTextInputPrivate::updateInputMethodHints()
1105 Q_Q(QQuickTextInput);
1106 Qt::InputMethodHints hints = inputMethodHints;
1107 if (m_echoMode == QQuickTextInput::Password || m_echoMode == QQuickTextInput::NoEcho)
1108 hints |= Qt::ImhHiddenText;
1109 else if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit)
1110 hints &= ~Qt::ImhHiddenText;
1111 if (m_echoMode != QQuickTextInput::Normal)
1112 hints |= (Qt::ImhNoAutoUppercase | Qt::ImhNoPredictiveText | Qt::ImhSensitiveData);
1113 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->inputMethod()->invokeAction(QInputMethod::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(), 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);
2255 \qmlproperty real QtQuick2::TextInput::contentWidth
2257 Returns the width of the text, including the width past the width
2258 which is covered due to insufficient wrapping if \l wrapMode is set.
2261 qreal QQuickTextInput::contentWidth() const
2263 Q_D(const QQuickTextInput);
2264 return d->boundingRect.width();
2268 \qmlproperty real QtQuick2::TextInput::contentHeight
2270 Returns the height of the text, including the height past the height
2271 that is covered if the text does not fit within the set height.
2274 qreal QQuickTextInput::contentHeight() const
2276 Q_D(const QQuickTextInput);
2277 return d->boundingRect.height();
2280 void QQuickTextInput::moveCursorSelection(int position)
2282 Q_D(QQuickTextInput);
2283 d->moveCursor(position, true);
2287 \qmlmethod void QtQuick2::TextInput::moveCursorSelection(int position, SelectionMode mode = TextInput.SelectCharacters)
2289 Moves the cursor to \a position and updates the selection according to the optional \a mode
2290 parameter. (To only move the cursor, set the \l cursorPosition property.)
2292 When this method is called it additionally sets either the
2293 selectionStart or the selectionEnd (whichever was at the previous cursor position)
2294 to the specified position. This allows you to easily extend and contract the selected
2297 The selection mode specifies whether the selection is updated on a per character or a per word
2298 basis. If not specified the selection mode will default to TextInput.SelectCharacters.
2301 \o TextInput.SelectCharacters - Sets either the selectionStart or selectionEnd (whichever was at
2302 the previous cursor position) to the specified position.
2303 \o TextInput.SelectWords - Sets the selectionStart and selectionEnd to include all
2304 words between the specified position and the previous cursor position. Words partially in the
2308 For example, take this sequence of calls:
2312 moveCursorSelection(9, TextInput.SelectCharacters)
2313 moveCursorSelection(7, TextInput.SelectCharacters)
2316 This moves the cursor to position 5, extend the selection end from 5 to 9
2317 and then retract the selection end from 9 to 7, leaving the text from position 5 to 7
2318 selected (the 6th and 7th characters).
2320 The same sequence with TextInput.SelectWords will extend the selection start to a word boundary
2321 before or on position 5 and extend the selection end to a word boundary on or past position 9.
2323 void QQuickTextInput::moveCursorSelection(int pos, SelectionMode mode)
2325 Q_D(QQuickTextInput);
2327 if (mode == SelectCharacters) {
2328 d->moveCursor(pos, true);
2329 } else if (pos != d->m_cursor){
2330 const int cursor = d->m_cursor;
2332 if (!d->hasSelectedText())
2333 anchor = d->m_cursor;
2334 else if (d->selectionStart() == d->m_cursor)
2335 anchor = d->selectionEnd();
2337 anchor = d->selectionStart();
2339 if (anchor < pos || (anchor == pos && cursor < pos)) {
2340 const QString text = this->text();
2341 QTextBoundaryFinder finder(QTextBoundaryFinder::Word, text);
2342 finder.setPosition(anchor);
2344 const QTextBoundaryFinder::BoundaryReasons reasons = finder.boundaryReasons();
2345 if (anchor < text.length() && (!(reasons & QTextBoundaryFinder::StartWord)
2346 || ((reasons & QTextBoundaryFinder::EndWord) && anchor > cursor))) {
2347 finder.toPreviousBoundary();
2349 anchor = finder.position() != -1 ? finder.position() : 0;
2351 finder.setPosition(pos);
2352 if (pos > 0 && !finder.boundaryReasons())
2353 finder.toNextBoundary();
2354 const int cursor = finder.position() != -1 ? finder.position() : text.length();
2356 d->setSelection(anchor, cursor - anchor);
2357 } else if (anchor > pos || (anchor == pos && cursor > pos)) {
2358 const QString text = this->text();
2359 QTextBoundaryFinder finder(QTextBoundaryFinder::Word, text);
2360 finder.setPosition(anchor);
2362 const QTextBoundaryFinder::BoundaryReasons reasons = finder.boundaryReasons();
2363 if (anchor > 0 && (!(reasons & QTextBoundaryFinder::EndWord)
2364 || ((reasons & QTextBoundaryFinder::StartWord) && anchor < cursor))) {
2365 finder.toNextBoundary();
2368 anchor = finder.position() != -1 ? finder.position() : text.length();
2370 finder.setPosition(pos);
2371 if (pos < text.length() && !finder.boundaryReasons())
2372 finder.toPreviousBoundary();
2373 const int cursor = finder.position() != -1 ? finder.position() : 0;
2375 d->setSelection(anchor, cursor - anchor);
2381 \qmlmethod void QtQuick2::TextInput::openSoftwareInputPanel()
2383 Opens software input panels like virtual keyboards for typing, useful for
2384 customizing when you want the input keyboard to be shown and hidden in
2387 By default the opening of input panels follows the platform style. Input panels are
2388 always closed if no editor has active focus.
2390 You can disable the automatic behavior by setting the property \c activeFocusOnPress to false
2391 and use functions openSoftwareInputPanel() and closeSoftwareInputPanel() to implement
2392 the behavior you want.
2394 Only relevant on platforms, which provide virtual keyboards.
2400 text: "Hello world!"
2401 activeFocusOnPress: false
2403 anchors.fill: parent
2405 if (!textInput.activeFocus) {
2406 textInput.forceActiveFocus()
2407 textInput.openSoftwareInputPanel();
2409 textInput.focus = false;
2412 onPressAndHold: textInput.closeSoftwareInputPanel();
2417 void QQuickTextInput::openSoftwareInputPanel()
2420 qGuiApp->inputMethod()->show();
2424 \qmlmethod void QtQuick2::TextInput::closeSoftwareInputPanel()
2426 Closes a software input panel like a virtual keyboard shown on the screen, useful
2427 for customizing when you want the input keyboard to be shown and hidden in
2430 By default the opening of input panels follows the platform style. Input panels are
2431 always closed if no editor has active focus.
2433 You can disable the automatic behavior by setting the property \c activeFocusOnPress to false
2434 and use functions openSoftwareInputPanel() and closeSoftwareInputPanel() to implement
2435 the behavior you want.
2437 Only relevant on platforms, which provide virtual keyboards.
2443 text: "Hello world!"
2444 activeFocusOnPress: false
2446 anchors.fill: parent
2448 if (!textInput.activeFocus) {
2449 textInput.forceActiveFocus();
2450 textInput.openSoftwareInputPanel();
2452 textInput.focus = false;
2455 onPressAndHold: textInput.closeSoftwareInputPanel();
2460 void QQuickTextInput::closeSoftwareInputPanel()
2463 qGuiApp->inputMethod()->hide();
2466 void QQuickTextInput::focusInEvent(QFocusEvent *event)
2468 Q_D(const QQuickTextInput);
2469 if (d->focusOnPress && !d->m_readOnly)
2470 openSoftwareInputPanel();
2471 QQuickImplicitSizeItem::focusInEvent(event);
2474 void QQuickTextInput::itemChange(ItemChange change, const ItemChangeData &value)
2476 Q_D(QQuickTextInput);
2477 if (change == ItemActiveFocusHasChanged) {
2478 bool hasFocus = value.boolValue;
2479 d->focused = hasFocus;
2480 setCursorVisible(hasFocus); // ### refactor: && d->canvas && d->canvas->hasFocus()
2481 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
2482 if (!hasFocus && (d->m_passwordEchoEditing || d->m_passwordEchoTimer.isActive())) {
2484 if (!hasFocus && d->m_passwordEchoEditing) {
2486 d->updatePasswordEchoEditing(false);//QQuickTextInputPrivate sets it on key events, but doesn't deal with focus events
2491 if (!d->persistentSelection)
2493 disconnect(qApp->inputMethod(), SIGNAL(inputDirectionChanged(Qt::LayoutDirection)),
2494 this, SLOT(q_updateAlignment()));
2496 q_updateAlignment();
2497 connect(qApp->inputMethod(), SIGNAL(inputDirectionChanged(Qt::LayoutDirection)),
2498 this, SLOT(q_updateAlignment()));
2501 QQuickItem::itemChange(change, value);
2505 \qmlproperty bool QtQuick2::TextInput::inputMethodComposing
2508 This property holds whether the TextInput has partial text input from an
2511 While it is composing an input method may rely on mouse or key events from
2512 the TextInput to edit or commit the partial text. This property can be
2513 used to determine when to disable events handlers that may interfere with
2514 the correct operation of an input method.
2516 bool QQuickTextInput::isInputMethodComposing() const
2518 Q_D(const QQuickTextInput);
2519 return d->preeditAreaText().length() > 0;
2522 void QQuickTextInputPrivate::init()
2524 Q_Q(QQuickTextInput);
2525 q->setSmooth(smooth);
2526 q->setAcceptedMouseButtons(Qt::LeftButton);
2527 q->setFlag(QQuickItem::ItemAcceptsInputMethod);
2528 q->setFlag(QQuickItem::ItemHasContents);
2529 #ifndef QT_NO_CLIPBOARD
2530 q->connect(QGuiApplication::clipboard(), SIGNAL(dataChanged()),
2531 q, SLOT(q_canPasteChanged()));
2532 #endif // QT_NO_CLIPBOARD
2534 lastSelectionStart = 0;
2535 lastSelectionEnd = 0;
2536 selectedTextColor = m_palette.color(QPalette::HighlightedText);
2537 selectionColor = m_palette.color(QPalette::Highlight);
2538 determineHorizontalAlignment();
2540 if (!qmlDisableDistanceField()) {
2541 QTextOption option = m_textLayout.textOption();
2542 option.setUseDesignMetrics(true);
2543 m_textLayout.setTextOption(option);
2547 void QQuickTextInput::updateCursorRectangle()
2549 Q_D(QQuickTextInput);
2550 if (!isComponentComplete())
2553 d->updateHorizontalScroll();
2554 d->updateVerticalScroll();
2555 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
2557 emit cursorRectangleChanged();
2558 if (d->cursorItem) {
2559 QRectF r = cursorRectangle();
2560 d->cursorItem->setPos(r.topLeft());
2561 d->cursorItem->setHeight(r.height());
2563 updateInputMethod(Qt::ImCursorRectangle);
2566 void QQuickTextInput::selectionChanged()
2568 Q_D(QQuickTextInput);
2569 d->textLayoutDirty = true; //TODO: Only update rect in selection
2570 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
2572 emit selectedTextChanged();
2574 if (d->lastSelectionStart != d->selectionStart()) {
2575 d->lastSelectionStart = d->selectionStart();
2576 if (d->lastSelectionStart == -1)
2577 d->lastSelectionStart = d->m_cursor;
2578 emit selectionStartChanged();
2580 if (d->lastSelectionEnd != d->selectionEnd()) {
2581 d->lastSelectionEnd = d->selectionEnd();
2582 if (d->lastSelectionEnd == -1)
2583 d->lastSelectionEnd = d->m_cursor;
2584 emit selectionEndChanged();
2588 void QQuickTextInputPrivate::showCursor()
2590 if (textNode != 0 && textNode->cursorNode() != 0)
2591 textNode->cursorNode()->setColor(color);
2594 void QQuickTextInputPrivate::hideCursor()
2596 if (textNode != 0 && textNode->cursorNode() != 0)
2597 textNode->cursorNode()->setColor(QColor(0, 0, 0, 0));
2600 QRectF QQuickTextInput::boundingRect() const
2602 Q_D(const QQuickTextInput);
2604 int cursorWidth = d->cursorItem ? d->cursorItem->width() : d->m_cursorWidth;
2606 // Could include font max left/right bearings to either side of rectangle.
2607 QRectF r = QQuickImplicitSizeItem::boundingRect();
2608 r.setRight(r.right() + cursorWidth);
2612 void QQuickTextInput::q_canPasteChanged()
2614 Q_D(QQuickTextInput);
2615 bool old = d->canPaste;
2616 #ifndef QT_NO_CLIPBOARD
2617 if (const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData())
2618 d->canPaste = !d->m_readOnly && mimeData->hasText();
2620 d->canPaste = false;
2623 bool changed = d->canPaste != old || !d->canPasteValid;
2624 d->canPasteValid = true;
2626 emit canPasteChanged();
2630 void QQuickTextInput::q_updateAlignment()
2632 Q_D(QQuickTextInput);
2633 if (d->determineHorizontalAlignment()) {
2635 updateCursorRectangle();
2639 // ### these should come from QStyleHints
2640 const int textCursorWidth = 1;
2641 const bool fullWidthSelection = true;
2646 Updates the display text based of the current edit text
2647 If the text has changed will emit displayTextChanged()
2649 void QQuickTextInputPrivate::updateDisplayText(bool forceUpdate)
2651 QString orig = m_textLayout.text();
2653 if (m_echoMode == QQuickTextInput::NoEcho)
2654 str = QString::fromLatin1("");
2658 if (m_echoMode == QQuickTextInput::Password) {
2659 str.fill(m_passwordCharacter);
2660 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
2661 if (m_passwordEchoTimer.isActive() && m_cursor > 0 && m_cursor <= m_text.length()) {
2662 int cursor = m_cursor - 1;
2663 QChar uc = m_text.at(cursor);
2665 if (cursor > 0 && uc.unicode() >= 0xdc00 && uc.unicode() < 0xe000) {
2666 // second half of a surrogate, check if we have the first half as well,
2667 // if yes restore both at once
2668 uc = m_text.at(cursor - 1);
2669 if (uc.unicode() >= 0xd800 && uc.unicode() < 0xdc00)
2670 str[cursor - 1] = uc;
2674 } else if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit && !m_passwordEchoEditing) {
2675 str.fill(m_passwordCharacter);
2678 // replace certain non-printable characters with spaces (to avoid
2679 // drawing boxes when using fonts that don't have glyphs for such
2681 QChar* uc = str.data();
2682 for (int i = 0; i < (int)str.length(); ++i) {
2683 if ((uc[i] < 0x20 && uc[i] != 0x09)
2684 || uc[i] == QChar::LineSeparator
2685 || uc[i] == QChar::ParagraphSeparator
2686 || uc[i] == QChar::ObjectReplacementCharacter)
2687 uc[i] = QChar(0x0020);
2690 if (str != orig || forceUpdate) {
2691 m_textLayout.setText(str);
2692 updateLayout(); // polish?
2693 emit q_func()->displayTextChanged();
2697 void QQuickTextInputPrivate::updateLayout()
2699 Q_Q(QQuickTextInput);
2701 if (!q->isComponentComplete())
2704 const QRectF previousRect = boundingRect;
2706 QTextOption option = m_textLayout.textOption();
2707 option.setTextDirection(layoutDirection());
2708 option.setFlags(QTextOption::IncludeTrailingSpaces);
2709 option.setWrapMode(QTextOption::WrapMode(wrapMode));
2710 option.setAlignment(Qt::Alignment(q->effectiveHAlign()));
2711 m_textLayout.setTextOption(option);
2712 m_textLayout.setFont(font);
2714 boundingRect = QRectF();
2715 m_textLayout.beginLayout();
2716 QTextLine line = m_textLayout.createLine();
2717 qreal lineWidth = q->widthValid() ? q->width() : INT_MAX;
2719 QTextLine firstLine = line;
2721 line.setLineWidth(lineWidth);
2722 line.setPosition(QPointF(line.position().x(), height));
2723 boundingRect = boundingRect.united(line.naturalTextRect());
2725 height += line.height();
2726 line = m_textLayout.createLine();
2727 } while (line.isValid());
2728 m_textLayout.endLayout();
2730 option.setWrapMode(QTextOption::NoWrap);
2731 m_textLayout.setTextOption(option);
2733 m_ascent = qRound(firstLine.ascent());
2734 textLayoutDirty = true;
2736 updateType = UpdatePaintNode;
2738 q->setImplicitSize(qCeil(boundingRect.width()), qCeil(boundingRect.height()));
2740 if (previousRect != boundingRect)
2741 emit q->contentSizeChanged();
2744 #ifndef QT_NO_CLIPBOARD
2748 Copies the currently selected text into the clipboard using the given
2751 \note If the echo mode is set to a mode other than Normal then copy
2752 will not work. This is to prevent using copy as a method of bypassing
2753 password features of the line control.
2755 void QQuickTextInputPrivate::copy(QClipboard::Mode mode) const
2757 QString t = selectedText();
2758 if (!t.isEmpty() && m_echoMode == QQuickTextInput::Normal) {
2759 QGuiApplication::clipboard()->setText(t, mode);
2766 Inserts the text stored in the application clipboard into the line
2771 void QQuickTextInputPrivate::paste(QClipboard::Mode clipboardMode)
2773 QString clip = QGuiApplication::clipboard()->text(clipboardMode);
2774 if (!clip.isEmpty() || hasSelectedText()) {
2775 separate(); //make it a separate undo/redo command
2781 #endif // !QT_NO_CLIPBOARD
2786 Exits preedit mode and commits parts marked as tentative commit
2788 void QQuickTextInputPrivate::commitPreedit()
2793 qApp->inputMethod()->reset();
2795 if (!m_tentativeCommit.isEmpty()) {
2796 internalInsert(m_tentativeCommit);
2797 m_tentativeCommit.clear();
2798 finishChange(-1, true/*not used, not documented*/, false);
2801 m_preeditCursor = 0;
2802 m_textLayout.setPreeditArea(-1, QString());
2803 m_textLayout.clearAdditionalFormats();
2810 Handles the behavior for the backspace key or function.
2811 Removes the current selection if there is a selection, otherwise
2812 removes the character prior to the cursor position.
2816 void QQuickTextInputPrivate::backspace()
2818 int priorState = m_undoState;
2819 if (hasSelectedText()) {
2820 removeSelectedText();
2821 } else if (m_cursor) {
2824 m_cursor = prevMaskBlank(m_cursor);
2825 QChar uc = m_text.at(m_cursor);
2826 if (m_cursor > 0 && uc.unicode() >= 0xdc00 && uc.unicode() < 0xe000) {
2827 // second half of a surrogate, check if we have the first half as well,
2828 // if yes delete both at once
2829 uc = m_text.at(m_cursor - 1);
2830 if (uc.unicode() >= 0xd800 && uc.unicode() < 0xdc00) {
2831 internalDelete(true);
2835 internalDelete(true);
2837 finishChange(priorState);
2843 Handles the behavior for the delete key or function.
2844 Removes the current selection if there is a selection, otherwise
2845 removes the character after the cursor position.
2849 void QQuickTextInputPrivate::del()
2851 int priorState = m_undoState;
2852 if (hasSelectedText()) {
2853 removeSelectedText();
2855 int n = m_textLayout.nextCursorPosition(m_cursor) - m_cursor;
2859 finishChange(priorState);
2865 Inserts the given \a newText at the current cursor position.
2866 If there is any selected text it is removed prior to insertion of
2869 void QQuickTextInputPrivate::insert(const QString &newText)
2871 int priorState = m_undoState;
2872 removeSelectedText();
2873 internalInsert(newText);
2874 finishChange(priorState);
2880 Clears the line control text.
2882 void QQuickTextInputPrivate::clear()
2884 int priorState = m_undoState;
2886 m_selend = m_text.length();
2887 removeSelectedText();
2889 finishChange(priorState, /*update*/false, /*edited*/false);
2895 Sets \a length characters from the given \a start position as selected.
2896 The given \a start position must be within the current text for
2897 the line control. If \a length characters cannot be selected, then
2898 the selection will extend to the end of the current text.
2900 void QQuickTextInputPrivate::setSelection(int start, int length)
2902 Q_Q(QQuickTextInput);
2905 if (start < 0 || start > (int)m_text.length()){
2906 qWarning("QQuickTextInputPrivate::setSelection: Invalid start position");
2911 if (start == m_selstart && start + length == m_selend && m_cursor == m_selend)
2914 m_selend = qMin(start + length, (int)m_text.length());
2915 m_cursor = m_selend;
2916 } else if (length < 0){
2917 if (start == m_selend && start + length == m_selstart && m_cursor == m_selstart)
2919 m_selstart = qMax(start + length, 0);
2921 m_cursor = m_selstart;
2922 } else if (m_selstart != m_selend) {
2928 emitCursorPositionChanged();
2931 emit q->selectionChanged();
2932 emitCursorPositionChanged();
2933 q->updateInputMethod(Qt::ImCursorRectangle | Qt::ImAnchorPosition
2934 | Qt::ImCursorPosition | Qt::ImCurrentSelection);
2940 Initializes the line control with a starting text value of \a txt.
2942 void QQuickTextInputPrivate::init(const QString &txt)
2946 updateDisplayText();
2947 m_cursor = m_text.length();
2953 Sets the password echo editing to \a editing. If password echo editing
2954 is true, then the text of the password is displayed even if the echo
2955 mode is set to QLineEdit::PasswordEchoOnEdit. Password echoing editing
2956 does not affect other echo modes.
2958 void QQuickTextInputPrivate::updatePasswordEchoEditing(bool editing)
2960 cancelPasswordEchoTimer();
2961 m_passwordEchoEditing = editing;
2962 updateDisplayText();
2968 Fixes the current text so that it is valid given any set validators.
2970 Returns true if the text was changed. Otherwise returns false.
2972 bool QQuickTextInputPrivate::fixup() // this function assumes that validate currently returns != Acceptable
2974 #ifndef QT_NO_VALIDATOR
2976 QString textCopy = m_text;
2977 int cursorCopy = m_cursor;
2978 m_validator->fixup(textCopy);
2979 if (m_validator->validate(textCopy, cursorCopy) == QValidator::Acceptable) {
2980 if (textCopy != m_text || cursorCopy != m_cursor)
2981 internalSetText(textCopy, cursorCopy);
2992 Moves the cursor to the given position \a pos. If \a mark is true will
2993 adjust the currently selected text.
2995 void QQuickTextInputPrivate::moveCursor(int pos, bool mark)
2997 Q_Q(QQuickTextInput);
3000 if (pos != m_cursor) {
3003 pos = pos > m_cursor ? nextMaskBlank(pos) : prevMaskBlank(pos);
3007 if (m_selend > m_selstart && m_cursor == m_selstart)
3009 else if (m_selend > m_selstart && m_cursor == m_selend)
3010 anchor = m_selstart;
3013 m_selstart = qMin(anchor, pos);
3014 m_selend = qMax(anchor, pos);
3019 if (mark || m_selDirty) {
3021 emit q->selectionChanged();
3023 emitCursorPositionChanged();
3024 q->updateInputMethod();
3030 Applies the given input method event \a event to the text of the line
3033 void QQuickTextInputPrivate::processInputMethodEvent(QInputMethodEvent *event)
3035 Q_Q(QQuickTextInput);
3037 int priorState = -1;
3038 bool isGettingInput = !event->commitString().isEmpty()
3039 || event->preeditString() != preeditAreaText()
3040 || event->replacementLength() > 0;
3041 bool cursorPositionChanged = false;
3042 bool selectionChange = false;
3043 m_preeditDirty = event->preeditString() != preeditAreaText();
3045 if (isGettingInput) {
3046 // If any text is being input, remove selected text.
3047 priorState = m_undoState;
3048 if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit && !m_passwordEchoEditing) {
3049 updatePasswordEchoEditing(true);
3051 m_selend = m_text.length();
3053 removeSelectedText();
3056 int c = m_cursor; // cursor position after insertion of commit string
3057 if (event->replacementStart() <= 0)
3058 c += event->commitString().length() - qMin(-event->replacementStart(), event->replacementLength());
3060 m_cursor += event->replacementStart();
3064 // insert commit string
3065 if (event->replacementLength()) {
3066 m_selstart = m_cursor;
3067 m_selend = m_selstart + event->replacementLength();
3068 m_selend = qMin(m_selend, m_text.length());
3069 removeSelectedText();
3071 if (!event->commitString().isEmpty()) {
3072 internalInsert(event->commitString());
3073 cursorPositionChanged = true;
3076 m_cursor = qBound(0, c, m_text.length());
3078 for (int i = 0; i < event->attributes().size(); ++i) {
3079 const QInputMethodEvent::Attribute &a = event->attributes().at(i);
3080 if (a.type == QInputMethodEvent::Selection) {
3081 m_cursor = qBound(0, a.start + a.length, m_text.length());
3083 m_selstart = qMax(0, qMin(a.start, m_text.length()));
3084 m_selend = m_cursor;
3085 if (m_selend < m_selstart) {
3086 qSwap(m_selstart, m_selend);
3088 selectionChange = true;
3090 m_selstart = m_selend = 0;
3092 cursorPositionChanged = true;
3096 m_textLayout.setPreeditArea(m_cursor, event->preeditString());
3098 const int oldPreeditCursor = m_preeditCursor;
3099 m_preeditCursor = event->preeditString().length();
3100 m_hideCursor = false;
3101 QList<QTextLayout::FormatRange> formats;
3102 for (int i = 0; i < event->attributes().size(); ++i) {
3103 const QInputMethodEvent::Attribute &a = event->attributes().at(i);
3104 if (a.type == QInputMethodEvent::Cursor) {
3105 m_preeditCursor = a.start;
3106 m_hideCursor = !a.length;
3107 } else if (a.type == QInputMethodEvent::TextFormat) {
3108 QTextCharFormat f = qvariant_cast<QTextFormat>(a.value).toCharFormat();
3110 QTextLayout::FormatRange o;
3111 o.start = a.start + m_cursor;
3112 o.length = a.length;
3118 m_textLayout.setAdditionalFormats(formats);
3120 updateDisplayText(/*force*/ true);
3121 if (cursorPositionChanged) {
3122 emitCursorPositionChanged();
3123 } else if (m_preeditCursor != oldPreeditCursor) {
3124 q->updateCursorRectangle();
3127 bool tentativeCommitChanged = m_tentativeCommit != event->tentativeCommitString();
3129 if (tentativeCommitChanged) {
3131 m_tentativeCommit = event->tentativeCommitString();
3134 if (isGettingInput || tentativeCommitChanged)
3135 finishChange(priorState);
3137 if (selectionChange) {
3138 emit q->selectionChanged();
3139 q->updateInputMethod(Qt::ImCursorRectangle | Qt::ImAnchorPosition
3140 | Qt::ImCursorPosition | Qt::ImCurrentSelection);
3147 Sets the selection to cover the word at the given cursor position.
3148 The word boundaries are defined by the behavior of QTextLayout::SkipWords
3151 void QQuickTextInputPrivate::selectWordAtPos(int cursor)
3153 int next = cursor + 1;
3156 int c = m_textLayout.previousCursorPosition(next, QTextLayout::SkipWords);
3157 moveCursor(c, false);
3158 // ## text layout should support end of words.
3159 int end = m_textLayout.nextCursorPosition(c, QTextLayout::SkipWords);
3160 while (end > cursor && m_text[end-1].isSpace())
3162 moveCursor(end, true);
3168 Completes a change to the line control text. If the change is not valid
3169 will undo the line control state back to the given \a validateFromState.
3171 If \a edited is true and the change is valid, will emit textEdited() in
3172 addition to textChanged(). Otherwise only emits textChanged() on a valid
3175 The \a update value is currently unused.
3177 bool QQuickTextInputPrivate::finishChange(int validateFromState, bool update, bool /*edited*/)
3179 Q_Q(QQuickTextInput);
3182 bool inputMethodAttributesChanged = m_textDirty || m_selDirty;
3183 bool alignmentChanged = false;
3187 bool wasValidInput = m_validInput;
3188 bool wasAcceptable = m_acceptableInput;
3189 m_validInput = true;
3190 m_acceptableInput = true;
3191 #ifndef QT_NO_VALIDATOR
3193 QString textCopy = m_text;
3194 int cursorCopy = m_cursor;
3195 QValidator::State state = m_validator->validate(textCopy, cursorCopy);
3196 m_validInput = state != QValidator::Invalid;
3197 m_acceptableInput = state == QValidator::Acceptable;
3199 if (m_text != textCopy) {
3200 internalSetText(textCopy, cursorCopy);
3203 m_cursor = cursorCopy;
3205 if (!m_tentativeCommit.isEmpty()) {
3206 textCopy.insert(m_cursor, m_tentativeCommit);
3207 bool validInput = m_validator->validate(textCopy, cursorCopy) != QValidator::Invalid;
3209 m_tentativeCommit.clear();
3212 m_tentativeCommit.clear();
3216 if (validateFromState >= 0 && wasValidInput && !m_validInput) {
3217 if (m_transactions.count())
3219 internalUndo(validateFromState);
3220 m_history.resize(m_undoState);
3221 if (m_modifiedState > m_undoState)
3222 m_modifiedState = -1;
3223 m_validInput = true;
3224 m_acceptableInput = wasAcceptable;
3225 m_textDirty = false;
3229 m_textDirty = false;
3230 m_preeditDirty = false;
3231 alignmentChanged = determineHorizontalAlignment();
3232 emit q->textChanged();
3235 updateDisplayText(alignmentChanged);
3237 if (m_acceptableInput != wasAcceptable)
3238 emit q->acceptableInputChanged();
3240 if (m_preeditDirty) {
3241 m_preeditDirty = false;
3242 if (determineHorizontalAlignment()) {
3243 alignmentChanged = true;
3250 emit q->selectionChanged();
3253 inputMethodAttributesChanged |= (m_cursor == m_lastCursorPos);
3254 if (inputMethodAttributesChanged)
3255 q->updateInputMethod();
3256 emitUndoRedoChanged();
3258 if (!emitCursorPositionChanged() && alignmentChanged)
3259 q->updateCursorRectangle();
3267 An internal function for setting the text of the line control.
3269 void QQuickTextInputPrivate::internalSetText(const QString &txt, int pos, bool edited)
3271 Q_Q(QQuickTextInput);
3273 QString oldText = m_text;
3275 m_text = maskString(0, txt, true);
3276 m_text += clearString(m_text.length(), m_maxLength - m_text.length());
3278 m_text = txt.isEmpty() ? txt : txt.left(m_maxLength);
3281 m_modifiedState = m_undoState = 0;
3282 m_cursor = (pos < 0 || pos > m_text.length()) ? m_text.length() : pos;
3283 m_textDirty = (oldText != m_text);
3285 bool changed = finishChange(-1, true, edited);
3286 #ifdef QT_NO_ACCESSIBILITY
3290 QAccessible::updateAccessibility(QAccessibleEvent(QAccessible::TextUpdated, q, 0));
3298 Adds the given \a command to the undo history
3299 of the line control. Does not apply the command.
3301 void QQuickTextInputPrivate::addCommand(const Command &cmd)
3303 if (m_separator && m_undoState && m_history[m_undoState - 1].type != Separator) {
3304 m_history.resize(m_undoState + 2);
3305 m_history[m_undoState++] = Command(Separator, m_cursor, 0, m_selstart, m_selend);
3307 m_history.resize(m_undoState + 1);
3309 m_separator = false;
3310 m_history[m_undoState++] = cmd;
3316 Inserts the given string \a s into the line
3319 Also adds the appropriate commands into the undo history.
3320 This function does not call finishChange(), and may leave the text
3321 in an invalid state.
3323 void QQuickTextInputPrivate::internalInsert(const QString &s)
3325 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
3326 Q_Q(QQuickTextInput);
3327 if (m_echoMode == QQuickTextInput::Password)
3328 m_passwordEchoTimer.start(qt_passwordEchoDelay, q);
3330 if (hasSelectedText())
3331 addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
3333 QString ms = maskString(m_cursor, s);
3334 for (int i = 0; i < (int) ms.length(); ++i) {
3335 addCommand (Command(DeleteSelection, m_cursor + i, m_text.at(m_cursor + i), -1, -1));
3336 addCommand(Command(Insert, m_cursor + i, ms.at(i), -1, -1));
3338 m_text.replace(m_cursor, ms.length(), ms);
3339 m_cursor += ms.length();
3340 m_cursor = nextMaskBlank(m_cursor);
3343 int remaining = m_maxLength - m_text.length();
3344 if (remaining != 0) {
3345 m_text.insert(m_cursor, s.left(remaining));
3346 for (int i = 0; i < (int) s.left(remaining).length(); ++i)
3347 addCommand(Command(Insert, m_cursor++, s.at(i), -1, -1));
3356 deletes a single character from the current text. If \a wasBackspace,
3357 the character prior to the cursor is removed. Otherwise the character
3358 after the cursor is removed.
3360 Also adds the appropriate commands into the undo history.
3361 This function does not call finishChange(), and may leave the text
3362 in an invalid state.
3364 void QQuickTextInputPrivate::internalDelete(bool wasBackspace)
3366 if (m_cursor < (int) m_text.length()) {
3367 cancelPasswordEchoTimer();
3368 if (hasSelectedText())
3369 addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
3370 addCommand(Command((CommandType)((m_maskData ? 2 : 0) + (wasBackspace ? Remove : Delete)),
3371 m_cursor, m_text.at(m_cursor), -1, -1));
3373 m_text.replace(m_cursor, 1, clearString(m_cursor, 1));
3374 addCommand(Command(Insert, m_cursor, m_text.at(m_cursor), -1, -1));
3376 m_text.remove(m_cursor, 1);
3385 removes the currently selected text from the line control.
3387 Also adds the appropriate commands into the undo history.
3388 This function does not call finishChange(), and may leave the text
3389 in an invalid state.
3391 void QQuickTextInputPrivate::removeSelectedText()
3393 if (m_selstart < m_selend && m_selend <= (int) m_text.length()) {
3394 cancelPasswordEchoTimer();
3397 addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
3398 if (m_selstart <= m_cursor && m_cursor < m_selend) {
3399 // cursor is within the selection. Split up the commands
3400 // to be able to restore the correct cursor position
3401 for (i = m_cursor; i >= m_selstart; --i)
3402 addCommand (Command(DeleteSelection, i, m_text.at(i), -1, 1));
3403 for (i = m_selend - 1; i > m_cursor; --i)
3404 addCommand (Command(DeleteSelection, i - m_cursor + m_selstart - 1, m_text.at(i), -1, -1));
3406 for (i = m_selend-1; i >= m_selstart; --i)
3407 addCommand (Command(RemoveSelection, i, m_text.at(i), -1, -1));
3410 m_text.replace(m_selstart, m_selend - m_selstart, clearString(m_selstart, m_selend - m_selstart));
3411 for (int i = 0; i < m_selend - m_selstart; ++i)
3412 addCommand(Command(Insert, m_selstart + i, m_text.at(m_selstart + i), -1, -1));
3414 m_text.remove(m_selstart, m_selend - m_selstart);
3416 if (m_cursor > m_selstart)
3417 m_cursor -= qMin(m_cursor, m_selend) - m_selstart;
3426 Parses the input mask specified by \a maskFields to generate
3427 the mask data used to handle input masks.
3429 void QQuickTextInputPrivate::parseInputMask(const QString &maskFields)
3431 int delimiter = maskFields.indexOf(QLatin1Char(';'));
3432 if (maskFields.isEmpty() || delimiter == 0) {
3434 delete [] m_maskData;
3436 m_maxLength = 32767;
3437 internalSetText(QString());
3442 if (delimiter == -1) {
3443 m_blank = QLatin1Char(' ');
3444 m_inputMask = maskFields;
3446 m_inputMask = maskFields.left(delimiter);
3447 m_blank = (delimiter + 1 < maskFields.length()) ? maskFields[delimiter + 1] : QLatin1Char(' ');
3450 // calculate m_maxLength / m_maskData length
3453 for (int i=0; i<m_inputMask.length(); i++) {
3454 c = m_inputMask.at(i);
3455 if (i > 0 && m_inputMask.at(i-1) == QLatin1Char('\\')) {
3459 if (c != QLatin1Char('\\') && c != QLatin1Char('!') &&
3460 c != QLatin1Char('<') && c != QLatin1Char('>') &&
3461 c != QLatin1Char('{') && c != QLatin1Char('}') &&
3462 c != QLatin1Char('[') && c != QLatin1Char(']'))
3466 delete [] m_maskData;
3467 m_maskData = new MaskInputData[m_maxLength];
3469 MaskInputData::Casemode m = MaskInputData::NoCaseMode;
3472 bool escape = false;
3474 for (int i = 0; i < m_inputMask.length(); i++) {
3475 c = m_inputMask.at(i);
3478 m_maskData[index].maskChar = c;
3479 m_maskData[index].separator = s;
3480 m_maskData[index].caseMode = m;
3483 } else if (c == QLatin1Char('<')) {
3484 m = MaskInputData::Lower;
3485 } else if (c == QLatin1Char('>')) {
3486 m = MaskInputData::Upper;
3487 } else if (c == QLatin1Char('!')) {
3488 m = MaskInputData::NoCaseMode;
3489 } else if (c != QLatin1Char('{') && c != QLatin1Char('}') && c != QLatin1Char('[') && c != QLatin1Char(']')) {
3490 switch (c.unicode()) {
3516 m_maskData[index].maskChar = c;
3517 m_maskData[index].separator = s;
3518 m_maskData[index].caseMode = m;
3523 internalSetText(m_text);
3530 checks if the key is valid compared to the inputMask
3532 bool QQuickTextInputPrivate::isValidInput(QChar key, QChar mask) const
3534 switch (mask.unicode()) {
3540 if (key.isLetter() || key == m_blank)
3544 if (key.isLetterOrNumber())
3548 if (key.isLetterOrNumber() || key == m_blank)
3556 if (key.isPrint() || key == m_blank)
3564 if (key.isNumber() || key == m_blank)
3568 if (key.isNumber() && key.digitValue() > 0)
3572 if ((key.isNumber() && key.digitValue() > 0) || key == m_blank)
3576 if (key.isNumber() || key == QLatin1Char('+') || key == QLatin1Char('-') || key == m_blank)
3580 if (key == QLatin1Char('0') || key == QLatin1Char('1'))
3584 if (key == QLatin1Char('0') || key == QLatin1Char('1') || key == m_blank)
3588 if (key.isNumber() || (key >= QLatin1Char('a') && key <= QLatin1Char('f')) || (key >= QLatin1Char('A') && key <= QLatin1Char('F')))
3592 if (key.isNumber() || (key >= QLatin1Char('a') && key <= QLatin1Char('f')) || (key >= QLatin1Char('A') && key <= QLatin1Char('F')) || key == m_blank)
3604 Returns true if the given text \a str is valid for any
3605 validator or input mask set for the line control.
3607 Otherwise returns false
3609 QQuickTextInputPrivate::ValidatorState QQuickTextInputPrivate::hasAcceptableInput(const QString &str) const
3611 #ifndef QT_NO_VALIDATOR
3612 QString textCopy = str;
3613 int cursorCopy = m_cursor;
3615 QValidator::State state = m_validator->validate(textCopy, cursorCopy);
3616 if (state != QValidator::Acceptable)
3617 return ValidatorState(state);
3622 return AcceptableInput;
3624 if (str.length() != m_maxLength)
3625 return InvalidInput;
3627 for (int i=0; i < m_maxLength; ++i) {
3628 if (m_maskData[i].separator) {
3629 if (str.at(i) != m_maskData[i].maskChar)
3630 return InvalidInput;
3632 if (!isValidInput(str.at(i), m_maskData[i].maskChar))
3633 return InvalidInput;
3636 return AcceptableInput;
3642 Applies the inputMask on \a str starting from position \a pos in the mask. \a clear
3643 specifies from where characters should be gotten when a separator is met in \a str - true means
3644 that blanks will be used, false that previous input is used.
3645 Calling this when no inputMask is set is undefined.
3647 QString QQuickTextInputPrivate::maskString(uint pos, const QString &str, bool clear) const
3649 if (pos >= (uint)m_maxLength)
3650 return QString::fromLatin1("");
3653 fill = clear ? clearString(0, m_maxLength) : m_text;
3656 QString s = QString::fromLatin1("");
3658 while (i < m_maxLength) {
3659 if (strIndex < str.length()) {
3660 if (m_maskData[i].separator) {
3661 s += m_maskData[i].maskChar;
3662 if (str[(int)strIndex] == m_maskData[i].maskChar)
3666 if (isValidInput(str[(int)strIndex], m_maskData[i].maskChar)) {
3667 switch (m_maskData[i].caseMode) {
3668 case MaskInputData::Upper:
3669 s += str[(int)strIndex].toUpper();
3671 case MaskInputData::Lower:
3672 s += str[(int)strIndex].toLower();
3675 s += str[(int)strIndex];
3679 // search for separator first
3680 int n = findInMask(i, true, true, str[(int)strIndex]);
3682 if (str.length() != 1 || i == 0 || (i > 0 && (!m_maskData[i-1].separator || m_maskData[i-1].maskChar != str[(int)strIndex]))) {
3683 s += fill.mid(i, n-i+1);
3684 i = n + 1; // update i to find + 1
3687 // search for valid m_blank if not
3688 n = findInMask(i, true, false, str[(int)strIndex]);
3690 s += fill.mid(i, n-i);
3691 switch (m_maskData[n].caseMode) {
3692 case MaskInputData::Upper:
3693 s += str[(int)strIndex].toUpper();
3695 case MaskInputData::Lower:
3696 s += str[(int)strIndex].toLower();
3699 s += str[(int)strIndex];
3701 i = n + 1; // updates i to find + 1
3719 Returns a "cleared" string with only separators and blank chars.
3720 Calling this when no inputMask is set is undefined.
3722 QString QQuickTextInputPrivate::clearString(uint pos, uint len) const
3724 if (pos >= (uint)m_maxLength)
3728 int end = qMin((uint)m_maxLength, pos + len);
3729 for (int i = pos; i < end; ++i)
3730 if (m_maskData[i].separator)
3731 s += m_maskData[i].maskChar;
3741 Strips blank parts of the input in a QQuickTextInputPrivate when an inputMask is set,
3742 separators are still included. Typically "127.0__.0__.1__" becomes "127.0.0.1".
3744 QString QQuickTextInputPrivate::stripString(const QString &str) const
3750 int end = qMin(m_maxLength, (int)str.length());
3751 for (int i = 0; i < end; ++i) {
3752 if (m_maskData[i].separator)
3753 s += m_maskData[i].maskChar;
3754 else if (str[i] != m_blank)
3763 searches forward/backward in m_maskData for either a separator or a m_blank
3765 int QQuickTextInputPrivate::findInMask(int pos, bool forward, bool findSeparator, QChar searchChar) const
3767 if (pos >= m_maxLength || pos < 0)
3770 int end = forward ? m_maxLength : -1;
3771 int step = forward ? 1 : -1;
3775 if (findSeparator) {
3776 if (m_maskData[i].separator && m_maskData[i].maskChar == searchChar)
3779 if (!m_maskData[i].separator) {
3780 if (searchChar.isNull())
3782 else if (isValidInput(searchChar, m_maskData[i].maskChar))
3791 void QQuickTextInputPrivate::internalUndo(int until)
3793 if (!isUndoAvailable())
3795 cancelPasswordEchoTimer();
3797 while (m_undoState && m_undoState > until) {
3798 Command& cmd = m_history[--m_undoState];
3801 m_text.remove(cmd.pos, 1);
3805 m_selstart = cmd.selStart;
3806 m_selend = cmd.selEnd;
3810 case RemoveSelection:
3811 m_text.insert(cmd.pos, cmd.uc);
3812 m_cursor = cmd.pos + 1;
3815 case DeleteSelection:
3816 m_text.insert(cmd.pos, cmd.uc);
3822 if (until < 0 && m_undoState) {
3823 Command& next = m_history[m_undoState-1];
3824 if (next.type != cmd.type && next.type < RemoveSelection
3825 && (cmd.type < RemoveSelection || next.type == Separator))
3832 void QQuickTextInputPrivate::internalRedo()
3834 if (!isRedoAvailable())
3837 while (m_undoState < (int)m_history.size()) {
3838 Command& cmd = m_history[m_undoState++];
3841 m_text.insert(cmd.pos, cmd.uc);
3842 m_cursor = cmd.pos + 1;
3845 m_selstart = cmd.selStart;
3846 m_selend = cmd.selEnd;
3851 case RemoveSelection:
3852 case DeleteSelection:
3853 m_text.remove(cmd.pos, 1);
3854 m_selstart = cmd.selStart;
3855 m_selend = cmd.selEnd;
3859 m_selstart = cmd.selStart;
3860 m_selend = cmd.selEnd;
3864 if (m_undoState < (int)m_history.size()) {
3865 Command& next = m_history[m_undoState];
3866 if (next.type != cmd.type && cmd.type < RemoveSelection && next.type != Separator
3867 && (next.type < RemoveSelection || cmd.type == Separator))
3874 void QQuickTextInputPrivate::emitUndoRedoChanged()
3876 Q_Q(QQuickTextInput);
3877 const bool previousUndo = canUndo;
3878 const bool previousRedo = canRedo;
3880 canUndo = isUndoAvailable();
3881 canRedo = isRedoAvailable();
3883 if (previousUndo != canUndo)
3884 emit q->canUndoChanged();
3885 if (previousRedo != canRedo)
3886 emit q->canRedoChanged();
3892 If the current cursor position differs from the last emitted cursor
3893 position, emits cursorPositionChanged().
3895 bool QQuickTextInputPrivate::emitCursorPositionChanged()
3897 Q_Q(QQuickTextInput);
3898 if (m_cursor != m_lastCursorPos) {
3899 m_lastCursorPos = m_cursor;
3901 q->updateCursorRectangle();
3902 emit q->cursorPositionChanged();
3903 // XXX todo - not in 4.8?
3905 resetCursorBlinkTimer();
3908 if (!hasSelectedText()) {
3909 if (lastSelectionStart != m_cursor) {
3910 lastSelectionStart = m_cursor;
3911 emit q->selectionStartChanged();
3913 if (lastSelectionEnd != m_cursor) {
3914 lastSelectionEnd = m_cursor;
3915 emit q->selectionEndChanged();
3919 #ifndef QT_NO_ACCESSIBILITY
3920 QAccessible::updateAccessibility(QAccessibleEvent(QAccessible::TextCaretMoved, q, 0));
3929 void QQuickTextInputPrivate::setCursorBlinkPeriod(int msec)
3931 Q_Q(QQuickTextInput);
3932 if (msec == m_blinkPeriod)
3935 q->killTimer(m_blinkTimer);
3938 m_blinkTimer = q->startTimer(msec / 2);
3942 if (m_blinkStatus == 1) {
3943 updateType = UpdatePaintNode;
3947 m_blinkPeriod = msec;
3950 void QQuickTextInputPrivate::resetCursorBlinkTimer()
3952 Q_Q(QQuickTextInput);
3953 if (m_blinkPeriod == 0 || m_blinkTimer == 0)
3955 q->killTimer(m_blinkTimer);
3956 m_blinkTimer = q->startTimer(m_blinkPeriod / 2);
3960 void QQuickTextInput::timerEvent(QTimerEvent *event)
3962 Q_D(QQuickTextInput);
3963 if (event->timerId() == d->m_blinkTimer) {
3964 d->m_blinkStatus = !d->m_blinkStatus;
3965 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
3967 } else if (event->timerId() == d->m_deleteAllTimer) {
3968 killTimer(d->m_deleteAllTimer);
3969 d->m_deleteAllTimer = 0;
3971 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
3972 } else if (event->timerId() == d->m_passwordEchoTimer.timerId()) {
3973 d->m_passwordEchoTimer.stop();
3974 d->updateDisplayText();
3979 void QQuickTextInputPrivate::processKeyEvent(QKeyEvent* event)
3981 Q_Q(QQuickTextInput);
3982 bool inlineCompletionAccepted = false;
3984 if (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return) {
3985 if (hasAcceptableInput(m_text) || fixup()) {
3988 if (inlineCompletionAccepted)
3995 if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit
3996 && !m_passwordEchoEditing
3998 && !event->text().isEmpty()
3999 && !(event->modifiers() & Qt::ControlModifier)) {
4000 // Clear the edit and reset to normal echo mode while editing; the
4001 // echo mode switches back when the edit loses focus
4002 // ### resets current content. dubious code; you can
4003 // navigate with keys up, down, back, and select(?), but if you press
4004 // "left" or "right" it clears?
4005 updatePasswordEchoEditing(true);
4009 bool unknown = false;
4010 bool visual = cursorMoveStyle() == Qt::VisualMoveStyle;
4014 #ifndef QT_NO_SHORTCUT
4015 else if (event == QKeySequence::Undo) {
4019 else if (event == QKeySequence::Redo) {
4023 else if (event == QKeySequence::SelectAll) {
4026 #ifndef QT_NO_CLIPBOARD
4027 else if (event == QKeySequence::Copy) {
4030 else if (event == QKeySequence::Paste) {
4032 QClipboard::Mode mode = QClipboard::Clipboard;
4036 else if (event == QKeySequence::Cut) {
4042 else if (event == QKeySequence::DeleteEndOfLine) {
4044 setSelection(m_cursor, end());
4049 #endif //QT_NO_CLIPBOARD
4050 else if (event == QKeySequence::MoveToStartOfLine || event == QKeySequence::MoveToStartOfBlock) {
4053 else if (event == QKeySequence::MoveToEndOfLine || event == QKeySequence::MoveToEndOfBlock) {
4056 else if (event == QKeySequence::SelectStartOfLine || event == QKeySequence::SelectStartOfBlock) {
4059 else if (event == QKeySequence::SelectEndOfLine || event == QKeySequence::SelectEndOfBlock) {
4062 else if (event == QKeySequence::MoveToNextChar) {
4063 if (hasSelectedText()) {
4064 moveCursor(selectionEnd(), false);
4066 cursorForward(0, visual ? 1 : (layoutDirection() == Qt::LeftToRight ? 1 : -1));
4069 else if (event == QKeySequence::SelectNextChar) {
4070 cursorForward(1, visual ? 1 : (layoutDirection() == Qt::LeftToRight ? 1 : -1));
4072 else if (event == QKeySequence::MoveToPreviousChar) {
4073 if (hasSelectedText()) {
4074 moveCursor(selectionStart(), false);
4076 cursorForward(0, visual ? -1 : (layoutDirection() == Qt::LeftToRight ? -1 : 1));
4079 else if (event == QKeySequence::SelectPreviousChar) {
4080 cursorForward(1, visual ? -1 : (layoutDirection() == Qt::LeftToRight ? -1 : 1));
4082 else if (event == QKeySequence::MoveToNextWord) {
4083 if (m_echoMode == QQuickTextInput::Normal)
4084 layoutDirection() == Qt::LeftToRight ? cursorWordForward(0) : cursorWordBackward(0);
4086 layoutDirection() == Qt::LeftToRight ? end(0) : home(0);
4088 else if (event == QKeySequence::MoveToPreviousWord) {
4089 if (m_echoMode == QQuickTextInput::Normal)
4090 layoutDirection() == Qt::LeftToRight ? cursorWordBackward(0) : cursorWordForward(0);
4091 else if (!m_readOnly) {
4092 layoutDirection() == Qt::LeftToRight ? home(0) : end(0);
4095 else if (event == QKeySequence::SelectNextWord) {
4096 if (m_echoMode == QQuickTextInput::Normal)
4097 layoutDirection() == Qt::LeftToRight ? cursorWordForward(1) : cursorWordBackward(1);
4099 layoutDirection() == Qt::LeftToRight ? end(1) : home(1);
4101 else if (event == QKeySequence::SelectPreviousWord) {
4102 if (m_echoMode == QQuickTextInput::Normal)
4103 layoutDirection() == Qt::LeftToRight ? cursorWordBackward(1) : cursorWordForward(1);
4105 layoutDirection() == Qt::LeftToRight ? home(1) : end(1);
4107 else if (event == QKeySequence::Delete) {
4111 else if (event == QKeySequence::DeleteEndOfWord) {
4113 cursorWordForward(true);
4117 else if (event == QKeySequence::DeleteStartOfWord) {
4119 cursorWordBackward(true);
4123 #endif // QT_NO_SHORTCUT
4125 bool handled = false;
4126 if (event->modifiers() & Qt::ControlModifier) {
4127 switch (event->key()) {
4128 case Qt::Key_Backspace:
4130 cursorWordBackward(true);
4138 } else { // ### check for *no* modifier
4139 switch (event->key()) {
4140 case Qt::Key_Backspace:
4152 if (event->key() == Qt::Key_Direction_L || event->key() == Qt::Key_Direction_R) {
4153 setLayoutDirection((event->key() == Qt::Key_Direction_L) ? Qt::LeftToRight : Qt::RightToLeft);
4157 if (unknown && !m_readOnly) {
4158 QString t = event->text();
4159 if (!t.isEmpty() && t.at(0).isPrint()) {