1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the QtDeclarative module of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #include "qquicktextinput_p.h"
43 #include "qquicktextinput_p_p.h"
44 #include "qquickcanvas.h"
46 #include <private/qdeclarativeglobal_p.h>
48 #include <QtDeclarative/qdeclarativeinfo.h>
49 #include <QtGui/qevent.h>
50 #include <QTextBoundaryFinder>
51 #include "qquicktextnode_p.h"
52 #include <QtQuick/qsgsimplerectnode.h>
54 #include <QtGui/qstylehints.h>
55 #include <QtGui/qinputpanel.h>
57 #ifndef QT_NO_ACCESSIBILITY
58 #include "qaccessible.h"
63 DEFINE_BOOL_CONFIG_OPTION(qmlDisableDistanceField, QML_DISABLE_DISTANCEFIELD)
65 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
66 static const int qt_passwordEchoDelay = QT_GUI_PASSWORD_ECHO_DELAY;
70 \qmlclass TextInput QQuickTextInput
71 \inqmlmodule QtQuick 2
72 \ingroup qml-basic-visual-elements
73 \brief The TextInput item displays an editable line of text.
76 The TextInput element displays a single line of editable plain text.
78 TextInput is used to accept a line of text input. Input constraints
79 can be placed on a TextInput item (for example, through a \l validator or \l inputMask),
80 and setting \l echoMode to an appropriate value enables TextInput to be used for
81 a password input field.
83 On Mac OS X, the Up/Down key bindings for Home/End are explicitly disabled.
84 If you want such bindings (on any platform), you will need to construct them in QML.
86 \sa TextEdit, Text, {declarative/text/textselection}{Text Selection example}
88 QQuickTextInput::QQuickTextInput(QQuickItem* parent)
89 : QQuickImplicitSizeItem(*(new QQuickTextInputPrivate), parent)
95 QQuickTextInput::~QQuickTextInput()
99 void QQuickTextInput::componentComplete()
101 Q_D(QQuickTextInput);
103 QQuickImplicitSizeItem::componentComplete();
107 updateCursorRectangle();
108 if (d->cursorComponent && d->cursorComponent->isReady())
113 \qmlproperty string QtQuick2::TextInput::text
115 The text in the TextInput.
117 QString QQuickTextInput::text() const
119 Q_D(const QQuickTextInput);
121 QString content = d->m_text;
122 if (!d->m_tentativeCommit.isEmpty())
123 content.insert(d->m_cursor, d->m_tentativeCommit);
124 QString res = d->m_maskData ? d->stripString(content) : content;
125 return (res.isNull() ? QString::fromLatin1("") : res);
128 void QQuickTextInput::setText(const QString &s)
130 Q_D(QQuickTextInput);
133 if (d->composeMode())
134 qApp->inputPanel()->reset();
135 d->m_tentativeCommit.clear();
136 d->internalSetText(s, -1, false);
140 \qmlproperty int QtQuick2::TextInput::length
142 Returns the total number of characters in the TextInput item.
144 If the TextInput has an inputMask the length will include mask characters and may differ
145 from the length of the string returned by the \l text property.
147 This property can be faster than querying the length the \l text property as it doesn't
148 require any copying or conversion of the TextInput's internal string data.
151 int QQuickTextInput::length() const
153 Q_D(const QQuickTextInput);
154 return d->m_text.length();
158 \qmlmethod string QtQuick2::TextInput::getText(int start, int end)
160 Returns the section of text that is between the \a start and \a end positions.
162 If the TextInput has an inputMask the length will include mask characters.
165 QString QQuickTextInput::getText(int start, int end) const
167 Q_D(const QQuickTextInput);
172 return d->m_text.mid(start, end - start);
175 QString QQuickTextInputPrivate::realText() const
177 QString res = m_maskData ? stripString(m_text) : m_text;
178 return (res.isNull() ? QString::fromLatin1("") : res);
182 \qmlproperty string QtQuick2::TextInput::font.family
184 Sets the family name of the font.
186 The family name is case insensitive and may optionally include a foundry name, e.g. "Helvetica [Cronyx]".
187 If the family is available from more than one foundry and the foundry isn't specified, an arbitrary foundry is chosen.
188 If the family isn't available a family will be set using the font matching algorithm.
192 \qmlproperty bool QtQuick2::TextInput::font.bold
194 Sets whether the font weight is bold.
198 \qmlproperty enumeration QtQuick2::TextInput::font.weight
200 Sets the font's weight.
202 The weight can be one of:
205 \o Font.Normal - the default
212 TextInput { text: "Hello"; font.weight: Font.DemiBold }
217 \qmlproperty bool QtQuick2::TextInput::font.italic
219 Sets whether the font has an italic style.
223 \qmlproperty bool QtQuick2::TextInput::font.underline
225 Sets whether the text is underlined.
229 \qmlproperty bool QtQuick2::TextInput::font.strikeout
231 Sets whether the font has a strikeout style.
235 \qmlproperty real QtQuick2::TextInput::font.pointSize
237 Sets the font size in points. The point size must be greater than zero.
241 \qmlproperty int QtQuick2::TextInput::font.pixelSize
243 Sets the font size in pixels.
245 Using this function makes the font device dependent.
246 Use \c pointSize to set the size of the font in a device independent manner.
250 \qmlproperty real QtQuick2::TextInput::font.letterSpacing
252 Sets the letter spacing for the font.
254 Letter spacing changes the default spacing between individual letters in the font.
255 A positive value increases the letter spacing by the corresponding pixels; a negative value decreases the spacing.
259 \qmlproperty real QtQuick2::TextInput::font.wordSpacing
261 Sets the word spacing for the font.
263 Word spacing changes the default spacing between individual words.
264 A positive value increases the word spacing by a corresponding amount of pixels,
265 while a negative value decreases the inter-word spacing accordingly.
269 \qmlproperty enumeration QtQuick2::TextInput::font.capitalization
271 Sets the capitalization for the text.
274 \o Font.MixedCase - This is the normal text rendering option where no capitalization change is applied.
275 \o Font.AllUppercase - This alters the text to be rendered in all uppercase type.
276 \o Font.AllLowercase - This alters the text to be rendered in all lowercase type.
277 \o Font.SmallCaps - This alters the text to be rendered in small-caps type.
278 \o Font.Capitalize - This alters the text to be rendered with the first character of each word as an uppercase character.
282 TextInput { text: "Hello"; font.capitalization: Font.AllLowercase }
286 QFont QQuickTextInput::font() const
288 Q_D(const QQuickTextInput);
289 return d->sourceFont;
292 void QQuickTextInput::setFont(const QFont &font)
294 Q_D(QQuickTextInput);
295 if (d->sourceFont == font)
298 d->sourceFont = font;
299 QFont oldFont = d->font;
301 if (d->font.pointSizeF() != -1) {
303 qreal size = qRound(d->font.pointSizeF()*2.0);
304 d->font.setPointSizeF(size/2.0);
306 if (oldFont != d->font) {
308 updateCursorRectangle();
309 updateInputMethod(Qt::ImCursorRectangle | Qt::ImFont);
311 emit fontChanged(d->sourceFont);
315 \qmlproperty color QtQuick2::TextInput::color
319 QColor QQuickTextInput::color() const
321 Q_D(const QQuickTextInput);
325 void QQuickTextInput::setColor(const QColor &c)
327 Q_D(QQuickTextInput);
330 d->textLayoutDirty = true;
331 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
333 emit colorChanged(c);
339 \qmlproperty color QtQuick2::TextInput::selectionColor
341 The text highlight color, used behind selections.
343 QColor QQuickTextInput::selectionColor() const
345 Q_D(const QQuickTextInput);
346 return d->selectionColor;
349 void QQuickTextInput::setSelectionColor(const QColor &color)
351 Q_D(QQuickTextInput);
352 if (d->selectionColor == color)
355 d->selectionColor = color;
356 d->m_palette.setColor(QPalette::Highlight, d->selectionColor);
357 if (d->hasSelectedText()) {
358 d->textLayoutDirty = true;
359 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
362 emit selectionColorChanged(color);
365 \qmlproperty color QtQuick2::TextInput::selectedTextColor
367 The highlighted text color, used in selections.
369 QColor QQuickTextInput::selectedTextColor() const
371 Q_D(const QQuickTextInput);
372 return d->selectedTextColor;
375 void QQuickTextInput::setSelectedTextColor(const QColor &color)
377 Q_D(QQuickTextInput);
378 if (d->selectedTextColor == color)
381 d->selectedTextColor = color;
382 d->m_palette.setColor(QPalette::HighlightedText, d->selectedTextColor);
383 if (d->hasSelectedText()) {
384 d->textLayoutDirty = true;
385 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
388 emit selectedTextColorChanged(color);
392 \qmlproperty enumeration QtQuick2::TextInput::horizontalAlignment
393 \qmlproperty enumeration QtQuick2::TextInput::effectiveHorizontalAlignment
394 \qmlproperty enumeration QtQuick2::TextInput::verticalAlignment
396 Sets the horizontal alignment of the text within the TextInput item's
397 width and height. By default, the text alignment follows the natural alignment
398 of the text, for example text that is read from left to right will be aligned to
401 TextInput does not have vertical alignment, as the natural height is
402 exactly the height of the single line of text. If you set the height
403 manually to something larger, TextInput will always be top aligned
404 vertically. You can use anchors to align it however you want within
407 The valid values for \c horizontalAlignment are \c TextInput.AlignLeft, \c TextInput.AlignRight and
408 \c TextInput.AlignHCenter.
410 Valid values for \c verticalAlignment are \c TextInput.AlignTop (default),
411 \c TextInput.AlignBottom \c TextInput.AlignVCenter.
413 When using the attached property LayoutMirroring::enabled to mirror application
414 layouts, the horizontal alignment of text will also be mirrored. However, the property
415 \c horizontalAlignment will remain unchanged. To query the effective horizontal alignment
416 of TextInput, use the read-only property \c effectiveHorizontalAlignment.
418 QQuickTextInput::HAlignment QQuickTextInput::hAlign() const
420 Q_D(const QQuickTextInput);
424 void QQuickTextInput::setHAlign(HAlignment align)
426 Q_D(QQuickTextInput);
427 bool forceAlign = d->hAlignImplicit && d->effectiveLayoutMirror;
428 d->hAlignImplicit = false;
429 if (d->setHAlign(align, forceAlign) && isComponentComplete()) {
431 updateCursorRectangle();
435 void QQuickTextInput::resetHAlign()
437 Q_D(QQuickTextInput);
438 d->hAlignImplicit = true;
439 if (d->determineHorizontalAlignment() && isComponentComplete()) {
441 updateCursorRectangle();
445 QQuickTextInput::HAlignment QQuickTextInput::effectiveHAlign() const
447 Q_D(const QQuickTextInput);
448 QQuickTextInput::HAlignment effectiveAlignment = d->hAlign;
449 if (!d->hAlignImplicit && d->effectiveLayoutMirror) {
451 case QQuickTextInput::AlignLeft:
452 effectiveAlignment = QQuickTextInput::AlignRight;
454 case QQuickTextInput::AlignRight:
455 effectiveAlignment = QQuickTextInput::AlignLeft;
461 return effectiveAlignment;
464 bool QQuickTextInputPrivate::setHAlign(QQuickTextInput::HAlignment alignment, bool forceAlign)
466 Q_Q(QQuickTextInput);
467 if ((hAlign != alignment || forceAlign) && alignment <= QQuickTextInput::AlignHCenter) { // justify not supported
468 QQuickTextInput::HAlignment oldEffectiveHAlign = q->effectiveHAlign();
470 emit q->horizontalAlignmentChanged(alignment);
471 if (oldEffectiveHAlign != q->effectiveHAlign())
472 emit q->effectiveHorizontalAlignmentChanged();
478 bool QQuickTextInputPrivate::determineHorizontalAlignment()
480 if (hAlignImplicit) {
481 // if no explicit alignment has been set, follow the natural layout direction of the text
482 QString text = q_func()->text();
484 text = m_textLayout.preeditAreaText();
485 bool isRightToLeft = text.isEmpty() ? qApp->inputPanel()->inputDirection() == Qt::RightToLeft
486 : text.isRightToLeft();
487 return setHAlign(isRightToLeft ? QQuickTextInput::AlignRight : QQuickTextInput::AlignLeft);
492 QQuickTextInput::VAlignment QQuickTextInput::vAlign() const
494 Q_D(const QQuickTextInput);
498 void QQuickTextInput::setVAlign(QQuickTextInput::VAlignment alignment)
500 Q_D(QQuickTextInput);
501 if (alignment == d->vAlign)
503 d->vAlign = alignment;
504 emit verticalAlignmentChanged(d->vAlign);
505 if (isComponentComplete()) {
506 updateCursorRectangle();
511 \qmlproperty enumeration QtQuick2::TextInput::wrapMode
513 Set this property to wrap the text to the TextInput item's width.
514 The text will only wrap if an explicit width has been set.
517 \o TextInput.NoWrap - no wrapping will be performed. If the text contains insufficient newlines, then implicitWidth will exceed a set width.
518 \o TextInput.WordWrap - wrapping is done on word boundaries only. If a word is too long, implicitWidth will exceed a set width.
519 \o TextInput.WrapAnywhere - wrapping is done at any point on a line, even if it occurs in the middle of a word.
520 \o TextInput.Wrap - if possible, wrapping occurs at a word boundary; otherwise it will occur at the appropriate point on the line, even in the middle of a word.
523 The default is TextInput.NoWrap. If you set a width, consider using TextInput.Wrap.
525 QQuickTextInput::WrapMode QQuickTextInput::wrapMode() const
527 Q_D(const QQuickTextInput);
531 void QQuickTextInput::setWrapMode(WrapMode mode)
533 Q_D(QQuickTextInput);
534 if (mode == d->wrapMode)
538 updateCursorRectangle();
539 emit wrapModeChanged();
542 void QQuickTextInputPrivate::mirrorChange()
544 Q_Q(QQuickTextInput);
545 if (q->isComponentComplete()) {
546 if (!hAlignImplicit && (hAlign == QQuickTextInput::AlignRight || hAlign == QQuickTextInput::AlignLeft)) {
547 q->updateCursorRectangle();
548 emit q->effectiveHorizontalAlignmentChanged();
554 \qmlproperty bool QtQuick2::TextInput::readOnly
556 Sets whether user input can modify the contents of the TextInput.
558 If readOnly is set to true, then user input will not affect the text
559 property. Any bindings or attempts to set the text property will still
562 bool QQuickTextInput::isReadOnly() const
564 Q_D(const QQuickTextInput);
565 return d->m_readOnly;
568 void QQuickTextInput::setReadOnly(bool ro)
570 Q_D(QQuickTextInput);
571 if (d->m_readOnly == ro)
574 setFlag(QQuickItem::ItemAcceptsInputMethod, !ro);
577 d->setCursorPosition(d->end());
578 updateInputMethod(Qt::ImEnabled);
580 d->emitUndoRedoChanged();
581 emit readOnlyChanged(ro);
585 \qmlproperty int QtQuick2::TextInput::maximumLength
586 The maximum permitted length of the text in the TextInput.
588 If the text is too long, it is truncated at the limit.
590 By default, this property contains a value of 32767.
592 int QQuickTextInput::maxLength() const
594 Q_D(const QQuickTextInput);
595 return d->m_maxLength;
598 void QQuickTextInput::setMaxLength(int ml)
600 Q_D(QQuickTextInput);
601 if (d->m_maxLength == ml || d->m_maskData)
605 d->internalSetText(d->m_text, -1, false);
607 emit maximumLengthChanged(ml);
611 \qmlproperty bool QtQuick2::TextInput::cursorVisible
612 Set to true when the TextInput shows a cursor.
614 This property is set and unset when the TextInput gets active focus, so that other
615 properties can be bound to whether the cursor is currently showing. As it
616 gets set and unset automatically, when you set the value yourself you must
617 keep in mind that your value may be overwritten.
619 It can be set directly in script, for example if a KeyProxy might
620 forward keys to it and you desire it to look active when this happens
621 (but without actually giving it active focus).
623 It should not be set directly on the element, like in the below QML,
624 as the specified value will be overridden an lost on focus changes.
633 In the above snippet the cursor will still become visible when the
634 TextInput gains active focus.
636 bool QQuickTextInput::isCursorVisible() const
638 Q_D(const QQuickTextInput);
639 return d->cursorVisible;
642 void QQuickTextInput::setCursorVisible(bool on)
644 Q_D(QQuickTextInput);
645 if (d->cursorVisible == on)
647 d->cursorVisible = on;
648 d->setCursorBlinkPeriod(on ? qApp->styleHints()->cursorFlashTime() : 0);
649 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
651 emit cursorVisibleChanged(d->cursorVisible);
655 \qmlproperty int QtQuick2::TextInput::cursorPosition
656 The position of the cursor in the TextInput.
658 int QQuickTextInput::cursorPosition() const
660 Q_D(const QQuickTextInput);
664 void QQuickTextInput::setCursorPosition(int cp)
666 Q_D(QQuickTextInput);
667 if (cp < 0 || cp > text().length())
673 \qmlproperty rectangle QtQuick2::TextInput::cursorRectangle
675 The rectangle where the standard text cursor is rendered within the text input. Read only.
677 The position and height of a custom cursorDelegate are updated to follow the cursorRectangle
678 automatically when it changes. The width of the delegate is unaffected by changes in the
682 QRect QQuickTextInput::cursorRectangle() const
684 Q_D(const QQuickTextInput);
687 if (d->m_preeditCursor != -1)
688 c += d->m_preeditCursor;
689 if (d->m_echoMode == NoEcho)
691 QTextLine l = d->m_textLayout.lineForTextPosition(c);
695 qRound(l.cursorToX(c) - d->hscroll),
696 qRound(l.y() - d->vscroll),
702 \qmlproperty int QtQuick2::TextInput::selectionStart
704 The cursor position before the first character in the current selection.
706 This property is read-only. To change the selection, use select(start,end),
707 selectAll(), or selectWord().
709 \sa selectionEnd, cursorPosition, selectedText
711 int QQuickTextInput::selectionStart() const
713 Q_D(const QQuickTextInput);
714 return d->lastSelectionStart;
717 \qmlproperty int QtQuick2::TextInput::selectionEnd
719 The cursor position after the last character in the current selection.
721 This property is read-only. To change the selection, use select(start,end),
722 selectAll(), or selectWord().
724 \sa selectionStart, cursorPosition, selectedText
726 int QQuickTextInput::selectionEnd() const
728 Q_D(const QQuickTextInput);
729 return d->lastSelectionEnd;
732 \qmlmethod void QtQuick2::TextInput::select(int start, int end)
734 Causes the text from \a start to \a end to be selected.
736 If either start or end is out of range, the selection is not changed.
738 After calling this, selectionStart will become the lesser
739 and selectionEnd will become the greater (regardless of the order passed
742 \sa selectionStart, selectionEnd
744 void QQuickTextInput::select(int start, int end)
746 Q_D(QQuickTextInput);
747 if (start < 0 || end < 0 || start > d->m_text.length() || end > d->m_text.length())
749 d->setSelection(start, end-start);
753 \qmlproperty string QtQuick2::TextInput::selectedText
755 This read-only property provides the text currently selected in the
758 It is equivalent to the following snippet, but is faster and easier
762 myTextInput.text.toString().substring(myTextInput.selectionStart,
763 myTextInput.selectionEnd);
766 QString QQuickTextInput::selectedText() const
768 Q_D(const QQuickTextInput);
769 return d->selectedText();
773 \qmlproperty bool QtQuick2::TextInput::activeFocusOnPress
775 Whether the TextInput should gain active focus on a mouse press. By default this is
778 bool QQuickTextInput::focusOnPress() const
780 Q_D(const QQuickTextInput);
781 return d->focusOnPress;
784 void QQuickTextInput::setFocusOnPress(bool b)
786 Q_D(QQuickTextInput);
787 if (d->focusOnPress == b)
792 emit activeFocusOnPressChanged(d->focusOnPress);
795 \qmlproperty bool QtQuick2::TextInput::autoScroll
797 Whether the TextInput should scroll when the text is longer than the width. By default this is
800 bool QQuickTextInput::autoScroll() const
802 Q_D(const QQuickTextInput);
803 return d->autoScroll;
806 void QQuickTextInput::setAutoScroll(bool b)
808 Q_D(QQuickTextInput);
809 if (d->autoScroll == b)
813 //We need to repaint so that the scrolling is taking into account.
814 updateCursorRectangle();
815 emit autoScrollChanged(d->autoScroll);
818 #ifndef QT_NO_VALIDATOR
821 \qmlclass IntValidator QIntValidator
822 \inqmlmodule QtQuick 2
823 \ingroup qml-basic-visual-elements
825 This element provides a validator for integer values.
827 If no \l locale is set IntValidator uses the \l {QLocale::setDefault()}{default locale} to
828 interpret the number and will accept locale specific digits, group separators, and positive
829 and negative signs. In addition, IntValidator is always guaranteed to accept a number
830 formatted according to the "C" locale.
834 QQuickIntValidator::QQuickIntValidator(QObject *parent)
835 : QIntValidator(parent)
840 \qmlproperty string QtQuick2::IntValidator::locale
842 This property holds the name of the locale used to interpret the number.
847 QString QQuickIntValidator::localeName() const
849 return locale().name();
852 void QQuickIntValidator::setLocaleName(const QString &name)
854 if (locale().name() != name) {
855 setLocale(QLocale(name));
856 emit localeNameChanged();
860 void QQuickIntValidator::resetLocaleName()
862 QLocale defaultLocale;
863 if (locale() != defaultLocale) {
864 setLocale(defaultLocale);
865 emit localeNameChanged();
870 \qmlproperty int QtQuick2::IntValidator::top
872 This property holds the validator's highest acceptable value.
873 By default, this property's value is derived from the highest signed integer available (typically 2147483647).
876 \qmlproperty int QtQuick2::IntValidator::bottom
878 This property holds the validator's lowest acceptable value.
879 By default, this property's value is derived from the lowest signed integer available (typically -2147483647).
883 \qmlclass DoubleValidator QDoubleValidator
884 \inqmlmodule QtQuick 2
885 \ingroup qml-basic-visual-elements
887 This element provides a validator for non-integer numbers.
889 Input is accepted if it contains a double that is within the valid range
890 and is in the correct format.
892 Input is accepected but invalid if it contains a double that is outside
893 the range or is in the wrong format; e.g. with too many digits after the
894 decimal point or is empty.
896 Input is rejected if it is not a double.
898 Note: If the valid range consists of just positive doubles (e.g. 0.0 to
899 100.0) and input is a negative double then it is rejected. If \l notation
900 is set to DoubleValidator.StandardNotation, and the input contains more
901 digits before the decimal point than a double in the valid range may have,
902 it is also rejected. If \l notation is DoubleValidator.ScientificNotation,
903 and the input is not in the valid range, it is accecpted but invalid. The
904 value may yet become valid by changing the exponent.
907 QQuickDoubleValidator::QQuickDoubleValidator(QObject *parent)
908 : QDoubleValidator(parent)
913 \qmlproperty string QtQuick2::DoubleValidator::locale
915 This property holds the name of the locale used to interpret the number.
920 QString QQuickDoubleValidator::localeName() const
922 return locale().name();
925 void QQuickDoubleValidator::setLocaleName(const QString &name)
927 if (locale().name() != name) {
928 setLocale(QLocale(name));
929 emit localeNameChanged();
933 void QQuickDoubleValidator::resetLocaleName()
935 QLocale defaultLocale;
936 if (locale() != defaultLocale) {
937 setLocale(defaultLocale);
938 emit localeNameChanged();
943 \qmlproperty real QtQuick2::DoubleValidator::top
945 This property holds the validator's maximum acceptable value.
946 By default, this property contains a value of infinity.
949 \qmlproperty real QtQuick2::DoubleValidator::bottom
951 This property holds the validator's minimum acceptable value.
952 By default, this property contains a value of -infinity.
955 \qmlproperty int QtQuick2::DoubleValidator::decimals
957 This property holds the validator's maximum number of digits after the decimal point.
958 By default, this property contains a value of 1000.
961 \qmlproperty enumeration QtQuick2::DoubleValidator::notation
962 This property holds the notation of how a string can describe a number.
964 The possible values for this property are:
967 \o DoubleValidator.StandardNotation
968 \o DoubleValidator.ScientificNotation (default)
971 If this property is set to DoubleValidator.ScientificNotation, the written number may have an exponent part (e.g. 1.5E-2).
975 \qmlclass RegExpValidator QRegExpValidator
976 \inqmlmodule QtQuick 2
977 \ingroup qml-basic-visual-elements
979 This element provides a validator, which counts as valid any string which
980 matches a specified regular expression.
983 \qmlproperty regExp QtQuick2::RegExpValidator::regExp
985 This property holds the regular expression used for validation.
987 Note that this property should be a regular expression in JS syntax, e.g /a/ for the regular expression
990 By default, this property contains a regular expression with the pattern .* that matches any string.
994 \qmlproperty Validator QtQuick2::TextInput::validator
996 Allows you to set a validator on the TextInput. When a validator is set
997 the TextInput will only accept input which leaves the text property in
998 an acceptable or intermediate state. The accepted signal will only be sent
999 if the text is in an acceptable state when enter is pressed.
1001 Currently supported validators are IntValidator, DoubleValidator and
1002 RegExpValidator. An example of using validators is shown below, which allows
1003 input of integers between 11 and 31 into the text input:
1008 validator: IntValidator{bottom: 11; top: 31;}
1013 \sa acceptableInput, inputMask
1016 QValidator* QQuickTextInput::validator() const
1018 Q_D(const QQuickTextInput);
1019 return d->m_validator;
1022 void QQuickTextInput::setValidator(QValidator* v)
1024 Q_D(QQuickTextInput);
1025 if (d->m_validator == v)
1030 if (isComponentComplete())
1033 emit validatorChanged();
1036 #endif // QT_NO_VALIDATOR
1038 void QQuickTextInputPrivate::checkIsValid()
1040 Q_Q(QQuickTextInput);
1042 ValidatorState state = hasAcceptableInput(m_text);
1043 m_validInput = state != InvalidInput;
1044 if (state != AcceptableInput) {
1045 if (m_acceptableInput) {
1046 m_acceptableInput = false;
1047 emit q->acceptableInputChanged();
1049 } else if (!m_acceptableInput) {
1050 m_acceptableInput = true;
1051 emit q->acceptableInputChanged();
1056 \qmlproperty string QtQuick2::TextInput::inputMask
1058 Allows you to set an input mask on the TextInput, restricting the allowable
1059 text inputs. See QLineEdit::inputMask for further details, as the exact
1060 same mask strings are used by TextInput.
1062 \sa acceptableInput, validator
1064 QString QQuickTextInput::inputMask() const
1066 Q_D(const QQuickTextInput);
1067 return d->inputMask();
1070 void QQuickTextInput::setInputMask(const QString &im)
1072 Q_D(QQuickTextInput);
1073 if (d->inputMask() == im)
1076 d->setInputMask(im);
1077 emit inputMaskChanged(d->inputMask());
1081 \qmlproperty bool QtQuick2::TextInput::acceptableInput
1083 This property is always true unless a validator or input mask has been set.
1084 If a validator or input mask has been set, this property will only be true
1085 if the current text is acceptable to the validator or input mask as a final
1086 string (not as an intermediate string).
1088 bool QQuickTextInput::hasAcceptableInput() const
1090 Q_D(const QQuickTextInput);
1091 return d->hasAcceptableInput(d->m_text) == QQuickTextInputPrivate::AcceptableInput;
1095 \qmlsignal QtQuick2::TextInput::onAccepted()
1097 This handler is called when the Return or Enter key is pressed.
1098 Note that if there is a \l validator or \l inputMask set on the text
1099 input, the handler will only be emitted if the input is in an acceptable
1103 void QQuickTextInputPrivate::updateInputMethodHints()
1105 Q_Q(QQuickTextInput);
1106 Qt::InputMethodHints hints = inputMethodHints;
1107 if (m_echoMode == QQuickTextInput::Password || m_echoMode == QQuickTextInput::NoEcho)
1108 hints |= Qt::ImhHiddenText;
1109 else if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit)
1110 hints &= ~Qt::ImhHiddenText;
1111 if (m_echoMode != QQuickTextInput::Normal)
1112 hints |= (Qt::ImhNoAutoUppercase | Qt::ImhNoPredictiveText | Qt::ImhSensitiveData);
1113 q->setInputMethodHints(hints);
1116 \qmlproperty enumeration QtQuick2::TextInput::echoMode
1118 Specifies how the text should be displayed in the TextInput.
1120 \o TextInput.Normal - Displays the text as it is. (Default)
1121 \o TextInput.Password - Displays asterisks instead of characters.
1122 \o TextInput.NoEcho - Displays nothing.
1123 \o TextInput.PasswordEchoOnEdit - Displays characters as they are entered
1124 while editing, otherwise displays asterisks.
1127 QQuickTextInput::EchoMode QQuickTextInput::echoMode() const
1129 Q_D(const QQuickTextInput);
1130 return QQuickTextInput::EchoMode(d->m_echoMode);
1133 void QQuickTextInput::setEchoMode(QQuickTextInput::EchoMode echo)
1135 Q_D(QQuickTextInput);
1136 if (echoMode() == echo)
1138 d->cancelPasswordEchoTimer();
1139 d->m_echoMode = echo;
1140 d->m_passwordEchoEditing = false;
1141 d->updateInputMethodHints();
1142 d->updateDisplayText();
1143 updateCursorRectangle();
1145 emit echoModeChanged(echoMode());
1149 \qmlproperty enumeration QtQuick2::TextInput::inputMethodHints
1151 Provides hints to the input method about the expected content of the text input and how it
1154 The value is a bit-wise combination of flags, or Qt.ImhNone if no hints are set.
1156 Flags that alter behaviour are:
1159 \o Qt.ImhHiddenText - Characters should be hidden, as is typically used when entering passwords.
1160 This is automatically set when setting echoMode to \c TextInput.Password.
1161 \o Qt.ImhSensitiveData - Typed text should not be stored by the active input method
1162 in any persistent storage like predictive user dictionary.
1163 \o Qt.ImhNoAutoUppercase - The input method should not try to automatically switch to upper case
1164 when a sentence ends.
1165 \o Qt.ImhPreferNumbers - Numbers are preferred (but not required).
1166 \o Qt.ImhPreferUppercase - Upper case letters are preferred (but not required).
1167 \o Qt.ImhPreferLowercase - Lower case letters are preferred (but not required).
1168 \o Qt.ImhNoPredictiveText - Do not use predictive text (i.e. dictionary lookup) while typing.
1170 \o Qt.ImhDate - The text editor functions as a date field.
1171 \o Qt.ImhTime - The text editor functions as a time field.
1174 Flags that restrict input (exclusive flags) are:
1177 \o Qt.ImhDigitsOnly - Only digits are allowed.
1178 \o Qt.ImhFormattedNumbersOnly - Only number input is allowed. This includes decimal point and minus sign.
1179 \o Qt.ImhUppercaseOnly - Only upper case letter input is allowed.
1180 \o Qt.ImhLowercaseOnly - Only lower case letter input is allowed.
1181 \o Qt.ImhDialableCharactersOnly - Only characters suitable for phone dialing are allowed.
1182 \o Qt.ImhEmailCharactersOnly - Only characters suitable for email addresses are allowed.
1183 \o Qt.ImhUrlCharactersOnly - Only characters suitable for URLs are allowed.
1189 \o Qt.ImhExclusiveInputMask - This mask yields nonzero if any of the exclusive flags are used.
1193 Qt::InputMethodHints QQuickTextInput::imHints() const
1195 Q_D(const QQuickTextInput);
1196 return d->inputMethodHints;
1199 void QQuickTextInput::setIMHints(Qt::InputMethodHints hints)
1201 Q_D(QQuickTextInput);
1202 if (d->inputMethodHints == hints)
1204 d->inputMethodHints = hints;
1205 d->updateInputMethodHints();
1209 \qmlproperty Component QtQuick2::TextInput::cursorDelegate
1210 The delegate for the cursor in the TextInput.
1212 If you set a cursorDelegate for a TextInput, this delegate will be used for
1213 drawing the cursor instead of the standard cursor. An instance of the
1214 delegate will be created and managed by the TextInput when a cursor is
1215 needed, and the x property of delegate instance will be set so as
1216 to be one pixel before the top left of the current character.
1218 Note that the root item of the delegate component must be a QDeclarativeItem or
1219 QDeclarativeItem derived item.
1221 QDeclarativeComponent* QQuickTextInput::cursorDelegate() const
1223 Q_D(const QQuickTextInput);
1224 return d->cursorComponent;
1227 void QQuickTextInput::setCursorDelegate(QDeclarativeComponent* c)
1229 Q_D(QQuickTextInput);
1230 if (d->cursorComponent == c)
1233 d->cursorComponent = c;
1235 //note that the components are owned by something else
1236 delete d->cursorItem;
1238 d->startCreatingCursor();
1241 emit cursorDelegateChanged();
1244 void QQuickTextInputPrivate::startCreatingCursor()
1246 Q_Q(QQuickTextInput);
1247 if (cursorComponent->isReady()) {
1249 } else if (cursorComponent->isLoading()) {
1250 q->connect(cursorComponent, SIGNAL(statusChanged(int)),
1251 q, SLOT(createCursor()));
1253 qmlInfo(q, cursorComponent->errors()) << QQuickTextInput::tr("Could not load cursor delegate");
1257 void QQuickTextInput::createCursor()
1259 Q_D(QQuickTextInput);
1260 if (!isComponentComplete())
1263 if (d->cursorComponent->isError()) {
1264 qmlInfo(this, d->cursorComponent->errors()) << tr("Could not load cursor delegate");
1268 if (!d->cursorComponent->isReady())
1272 delete d->cursorItem;
1273 QDeclarativeContext *creationContext = d->cursorComponent->creationContext();
1274 QObject *object = d->cursorComponent->create(creationContext ? creationContext : qmlContext(this));
1275 d->cursorItem = qobject_cast<QQuickItem*>(object);
1276 if (!d->cursorItem) {
1278 qmlInfo(this, d->cursorComponent->errors()) << tr("Could not instantiate cursor delegate");
1282 QRectF r = cursorRectangle();
1284 QDeclarative_setParent_noEvent(d->cursorItem, this);
1285 d->cursorItem->setParentItem(this);
1286 d->cursorItem->setPos(r.topLeft());
1287 d->cursorItem->setHeight(r.height());
1291 \qmlmethod rect QtQuick2::TextInput::positionToRectangle(int pos)
1293 This function takes a character position and returns the rectangle that the
1294 cursor would occupy, if it was placed at that character position.
1296 This is similar to setting the cursorPosition, and then querying the cursor
1297 rectangle, but the cursorPosition is not changed.
1299 QRectF QQuickTextInput::positionToRectangle(int pos) const
1301 Q_D(const QQuickTextInput);
1302 if (pos > d->m_cursor)
1303 pos += d->preeditAreaText().length();
1304 QTextLine l = d->m_textLayout.lineAt(0);
1306 ? QRectF(l.cursorToX(pos) - d->hscroll, 0.0, d->m_cursorWidth, l.height())
1311 \qmlmethod int QtQuick2::TextInput::positionAt(real x, real y, CursorPosition position = CursorBetweenCharacters)
1313 This function returns the character position at
1314 x and y pixels from the top left of the textInput. Position 0 is before the
1315 first character, position 1 is after the first character but before the second,
1316 and so on until position text.length, which is after all characters.
1318 This means that for all x values before the first character this function returns 0,
1319 and for all x values after the last character this function returns text.length. If
1320 the y value is above the text the position will be that of the nearest character on
1321 the first line line and if it is below the text the position of the nearest character
1322 on the last line will be returned.
1324 The cursor position type specifies how the cursor position should be resolved.
1327 \o TextInput.CursorBetweenCharacters - Returns the position between characters that is nearest x.
1328 \o TextInput.CursorOnCharacter - Returns the position before the character that is nearest x.
1332 void QQuickTextInput::positionAt(QDeclarativeV8Function *args) const
1334 Q_D(const QQuickTextInput);
1338 QTextLine::CursorPosition position = QTextLine::CursorBetweenCharacters;
1340 if (args->Length() < 1)
1344 v8::Local<v8::Value> arg = (*args)[i];
1345 x = arg->NumberValue();
1347 if (++i < args->Length()) {
1349 y = arg->NumberValue();
1352 if (++i < args->Length()) {
1354 position = QTextLine::CursorPosition(arg->Int32Value());
1357 int pos = d->positionAt(x, y, position);
1358 const int cursor = d->m_cursor;
1360 const int preeditLength = d->preeditAreaText().length();
1361 pos = pos > cursor + preeditLength
1362 ? pos - preeditLength
1365 args->returnValue(v8::Int32::New(pos));
1368 int QQuickTextInputPrivate::positionAt(int x, int y, QTextLine::CursorPosition position) const
1372 QTextLine line = m_textLayout.lineAt(0);
1373 for (int i = 1; i < m_textLayout.lineCount(); ++i) {
1374 QTextLine nextLine = m_textLayout.lineAt(i);
1376 if (y < (line.rect().bottom() + nextLine.y()) / 2)
1380 return line.isValid() ? line.xToCursor(x, position) : 0;
1383 void QQuickTextInput::keyPressEvent(QKeyEvent* ev)
1385 Q_D(QQuickTextInput);
1386 // Don't allow MacOSX up/down support, and we don't allow a completer.
1387 bool ignore = (ev->key() == Qt::Key_Up || ev->key() == Qt::Key_Down) && ev->modifiers() == Qt::NoModifier;
1388 if (!ignore && (d->lastSelectionStart == d->lastSelectionEnd) && (ev->key() == Qt::Key_Right || ev->key() == Qt::Key_Left)) {
1389 // Ignore when moving off the end unless there is a selection,
1390 // because then moving will do something (deselect).
1391 int cursorPosition = d->m_cursor;
1392 if (cursorPosition == 0)
1393 ignore = ev->key() == (d->layoutDirection() == Qt::LeftToRight ? Qt::Key_Left : Qt::Key_Right);
1394 if (cursorPosition == text().length())
1395 ignore = ev->key() == (d->layoutDirection() == Qt::LeftToRight ? Qt::Key_Right : Qt::Key_Left);
1400 d->processKeyEvent(ev);
1402 if (!ev->isAccepted())
1403 QQuickImplicitSizeItem::keyPressEvent(ev);
1406 void QQuickTextInput::inputMethodEvent(QInputMethodEvent *ev)
1408 Q_D(QQuickTextInput);
1409 const bool wasComposing = d->preeditAreaText().length() > 0;
1410 if (d->m_readOnly) {
1413 d->processInputMethodEvent(ev);
1415 if (!ev->isAccepted())
1416 QQuickImplicitSizeItem::inputMethodEvent(ev);
1418 if (wasComposing != (d->m_textLayout.preeditAreaText().length() > 0))
1419 emit inputMethodComposingChanged();
1422 void QQuickTextInput::mouseDoubleClickEvent(QMouseEvent *event)
1424 Q_D(QQuickTextInput);
1426 if (d->selectByMouse && event->button() == Qt::LeftButton) {
1428 int cursor = d->positionAt(event->localPos());
1429 d->selectWordAtPos(cursor);
1430 event->setAccepted(true);
1431 if (!d->hasPendingTripleClick()) {
1432 d->tripleClickStartPoint = event->localPos().toPoint();
1433 d->tripleClickTimer.start();
1436 if (d->sendMouseEventToInputContext(event))
1438 QQuickImplicitSizeItem::mouseDoubleClickEvent(event);
1442 void QQuickTextInput::mousePressEvent(QMouseEvent *event)
1444 Q_D(QQuickTextInput);
1446 d->pressPos = event->localPos();
1448 if (d->focusOnPress) {
1449 bool hadActiveFocus = hasActiveFocus();
1451 // re-open input panel on press if already focused
1452 if (hasActiveFocus() && hadActiveFocus && !d->m_readOnly)
1453 openSoftwareInputPanel();
1455 if (d->selectByMouse) {
1456 setKeepMouseGrab(false);
1457 d->selectPressed = true;
1458 QPoint distanceVector = d->pressPos.toPoint() - d->tripleClickStartPoint;
1459 if (d->hasPendingTripleClick()
1460 && distanceVector.manhattanLength() < qApp->styleHints()->startDragDistance()) {
1461 event->setAccepted(true);
1467 if (d->sendMouseEventToInputContext(event))
1470 bool mark = (event->modifiers() & Qt::ShiftModifier) && d->selectByMouse;
1471 int cursor = d->positionAt(event->localPos());
1472 d->moveCursor(cursor, mark);
1473 event->setAccepted(true);
1476 void QQuickTextInput::mouseMoveEvent(QMouseEvent *event)
1478 Q_D(QQuickTextInput);
1480 if (d->selectPressed) {
1481 if (qAbs(int(event->localPos().x() - d->pressPos.x())) > qApp->styleHints()->startDragDistance())
1482 setKeepMouseGrab(true);
1484 if (d->composeMode()) {
1486 int startPos = d->positionAt(d->pressPos);
1487 int currentPos = d->positionAt(event->localPos());
1488 if (startPos != currentPos)
1489 d->setSelection(startPos, currentPos - startPos);
1491 moveCursorSelection(d->positionAt(event->localPos()), d->mouseSelectionMode);
1493 event->setAccepted(true);
1495 QQuickImplicitSizeItem::mouseMoveEvent(event);
1499 void QQuickTextInput::mouseReleaseEvent(QMouseEvent *event)
1501 Q_D(QQuickTextInput);
1502 if (d->sendMouseEventToInputContext(event))
1504 if (d->selectPressed) {
1505 d->selectPressed = false;
1506 setKeepMouseGrab(false);
1508 #ifndef QT_NO_CLIPBOARD
1509 if (QGuiApplication::clipboard()->supportsSelection()) {
1510 if (event->button() == Qt::LeftButton) {
1511 d->copy(QClipboard::Selection);
1512 } else if (!d->m_readOnly && event->button() == Qt::MidButton) {
1514 d->insert(QGuiApplication::clipboard()->text(QClipboard::Selection));
1518 if (!event->isAccepted())
1519 QQuickImplicitSizeItem::mouseReleaseEvent(event);
1522 bool QQuickTextInputPrivate::sendMouseEventToInputContext(QMouseEvent *event)
1524 #if !defined QT_NO_IM
1525 if (composeMode()) {
1526 int tmp_cursor = positionAt(event->localPos());
1527 int mousePos = tmp_cursor - m_cursor;
1528 if (mousePos >= 0 && mousePos <= m_textLayout.preeditAreaText().length()) {
1529 if (event->type() == QEvent::MouseButtonRelease) {
1530 qApp->inputPanel()->invokeAction(QInputPanel::Click, mousePos);
1543 void QQuickTextInput::mouseUngrabEvent()
1545 Q_D(QQuickTextInput);
1546 d->selectPressed = false;
1547 setKeepMouseGrab(false);
1550 bool QQuickTextInput::event(QEvent* ev)
1552 #ifndef QT_NO_SHORTCUT
1553 Q_D(QQuickTextInput);
1554 if (ev->type() == QEvent::ShortcutOverride) {
1557 QKeyEvent* ke = static_cast<QKeyEvent*>(ev);
1558 if (ke == QKeySequence::Copy
1559 || ke == QKeySequence::Paste
1560 || ke == QKeySequence::Cut
1561 || ke == QKeySequence::Redo
1562 || ke == QKeySequence::Undo
1563 || ke == QKeySequence::MoveToNextWord
1564 || ke == QKeySequence::MoveToPreviousWord
1565 || ke == QKeySequence::MoveToStartOfDocument
1566 || ke == QKeySequence::MoveToEndOfDocument
1567 || ke == QKeySequence::SelectNextWord
1568 || ke == QKeySequence::SelectPreviousWord
1569 || ke == QKeySequence::SelectStartOfLine
1570 || ke == QKeySequence::SelectEndOfLine
1571 || ke == QKeySequence::SelectStartOfBlock
1572 || ke == QKeySequence::SelectEndOfBlock
1573 || ke == QKeySequence::SelectStartOfDocument
1574 || ke == QKeySequence::SelectAll
1575 || ke == QKeySequence::SelectEndOfDocument) {
1577 } else if (ke->modifiers() == Qt::NoModifier || ke->modifiers() == Qt::ShiftModifier
1578 || ke->modifiers() == Qt::KeypadModifier) {
1579 if (ke->key() < Qt::Key_Escape) {
1583 switch (ke->key()) {
1584 case Qt::Key_Delete:
1587 case Qt::Key_Backspace:
1599 return QQuickImplicitSizeItem::event(ev);
1602 void QQuickTextInput::geometryChanged(const QRectF &newGeometry,
1603 const QRectF &oldGeometry)
1605 Q_D(QQuickTextInput);
1606 if (newGeometry.width() != oldGeometry.width())
1608 updateCursorRectangle();
1609 QQuickImplicitSizeItem::geometryChanged(newGeometry, oldGeometry);
1612 void QQuickTextInputPrivate::updateHorizontalScroll()
1614 Q_Q(QQuickTextInput);
1615 QTextLine currentLine = m_textLayout.lineForTextPosition(m_cursor + m_preeditCursor);
1616 const int preeditLength = m_textLayout.preeditAreaText().length();
1617 const int width = qMax(0, qFloor(q->width()));
1618 int widthUsed = currentLine.isValid() ? qRound(currentLine.naturalTextWidth()) : 0;
1619 int previousScroll = hscroll;
1621 if (!autoScroll || widthUsed <= width || m_echoMode == QQuickTextInput::NoEcho) {
1624 Q_ASSERT(currentLine.isValid());
1625 int cix = qRound(currentLine.cursorToX(m_cursor + preeditLength));
1626 if (cix - hscroll >= width) {
1627 // text doesn't fit, cursor is to the right of br (scroll right)
1628 hscroll = cix - width;
1629 } else if (cix - hscroll < 0 && hscroll < widthUsed) {
1630 // text doesn't fit, cursor is to the left of br (scroll left)
1632 } else if (widthUsed - hscroll < width) {
1633 // text doesn't fit, text document is to the left of br; align
1635 hscroll = widthUsed - width;
1637 if (preeditLength > 0) {
1638 // check to ensure long pre-edit text doesn't push the cursor
1640 cix = qRound(currentLine.cursorToX(m_cursor + qMax(0, m_preeditCursor - 1)));
1645 if (previousScroll != hscroll)
1646 textLayoutDirty = true;
1649 void QQuickTextInputPrivate::updateVerticalScroll()
1651 Q_Q(QQuickTextInput);
1652 const int preeditLength = m_textLayout.preeditAreaText().length();
1653 const int height = qMax(0, qFloor(q->height()));
1654 int heightUsed = boundingRect.height();
1655 int previousScroll = vscroll;
1657 if (!autoScroll || heightUsed <= height) {
1658 // text fits in br; use vscroll for alignment
1659 switch (vAlign & ~(Qt::AlignAbsolute|Qt::AlignHorizontal_Mask)) {
1660 case Qt::AlignBottom:
1661 vscroll = heightUsed - height;
1663 case Qt::AlignVCenter:
1664 vscroll = (heightUsed - height) / 2;
1672 QTextLine currentLine = m_textLayout.lineForTextPosition(m_cursor + preeditLength);
1673 QRectF r = currentLine.isValid() ? currentLine.rect() : QRectF();
1674 int top = qFloor(r.top());
1675 int bottom = qCeil(r.bottom());
1677 if (bottom - vscroll >= height) {
1678 // text doesn't fit, cursor is to the below the br (scroll down)
1679 vscroll = bottom - height;
1680 } else if (top - vscroll < 0 && vscroll < heightUsed) {
1681 // text doesn't fit, cursor is above br (scroll up)
1683 } else if (heightUsed - vscroll < height) {
1684 // text doesn't fit, text document is to the left of br; align
1686 vscroll = heightUsed - height;
1688 if (preeditLength > 0) {
1689 // check to ensure long pre-edit text doesn't push the cursor
1691 currentLine = m_textLayout.lineForTextPosition(m_cursor + qMax(0, m_preeditCursor - 1));
1692 top = currentLine.isValid() ? qRound(currentLine.rect().top()) : 0;
1697 if (previousScroll != vscroll)
1698 textLayoutDirty = true;
1701 void QQuickTextInput::triggerPreprocess()
1703 Q_D(QQuickTextInput);
1704 if (d->updateType == QQuickTextInputPrivate::UpdateNone)
1705 d->updateType = QQuickTextInputPrivate::UpdateOnlyPreprocess;
1709 QSGNode *QQuickTextInput::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data)
1712 Q_D(QQuickTextInput);
1714 if (d->updateType != QQuickTextInputPrivate::UpdatePaintNode && oldNode != 0) {
1715 // Update done in preprocess() in the nodes
1716 d->updateType = QQuickTextInputPrivate::UpdateNone;
1720 d->updateType = QQuickTextInputPrivate::UpdateNone;
1722 QQuickTextNode *node = static_cast<QQuickTextNode *>(oldNode);
1724 node = new QQuickTextNode(QQuickItemPrivate::get(this)->sceneGraphContext(), this);
1727 if (!d->textLayoutDirty) {
1728 QSGSimpleRectNode *cursorNode = node->cursorNode();
1729 if (cursorNode != 0 && !isReadOnly()) {
1730 cursorNode->setRect(cursorRectangle());
1732 if (!d->cursorVisible || (!d->m_blinkStatus && d->m_blinkPeriod > 0)) {
1739 node->deleteContent();
1740 node->setMatrix(QMatrix4x4());
1742 QPoint offset = QPoint(0,0);
1743 QFontMetrics fm = QFontMetrics(d->font);
1744 if (d->autoScroll) {
1745 // the y offset is there to keep the baseline constant in case we have script changes in the text.
1746 offset = -QPoint(d->hscroll, d->vscroll + d->m_ascent - fm.ascent());
1748 offset = -QPoint(d->hscroll, d->vscroll);
1751 if (!d->m_textLayout.text().isEmpty() || !d->m_textLayout.preeditAreaText().isEmpty()) {
1752 node->addTextLayout(offset, &d->m_textLayout, d->color,
1753 QQuickText::Normal, QColor(),
1754 d->selectionColor, d->selectedTextColor,
1755 d->selectionStart(),
1756 d->selectionEnd() - 1); // selectionEnd() returns first char after
1760 if (!isReadOnly() && d->cursorItem == 0) {
1761 node->setCursor(cursorRectangle(), d->color);
1762 if (!d->cursorVisible || (!d->m_blinkStatus && d->m_blinkPeriod > 0)) {
1769 d->textLayoutDirty = false;
1775 QVariant QQuickTextInput::inputMethodQuery(Qt::InputMethodQuery property) const
1777 Q_D(const QQuickTextInput);
1780 return QVariant((bool)(flags() & ItemAcceptsInputMethod));
1782 return QVariant((int)inputMethodHints());
1783 case Qt::ImCursorRectangle:
1784 return cursorRectangle();
1787 case Qt::ImCursorPosition:
1788 return QVariant(d->m_cursor);
1789 case Qt::ImSurroundingText:
1790 if (d->m_echoMode == PasswordEchoOnEdit && !d->m_passwordEchoEditing) {
1791 return QVariant(displayText());
1793 return QVariant(d->realText());
1795 case Qt::ImCurrentSelection:
1796 return QVariant(selectedText());
1797 case Qt::ImMaximumTextLength:
1798 return QVariant(maxLength());
1799 case Qt::ImAnchorPosition:
1800 if (d->selectionStart() == d->selectionEnd())
1801 return QVariant(d->m_cursor);
1802 else if (d->selectionStart() == d->m_cursor)
1803 return QVariant(d->selectionEnd());
1805 return QVariant(d->selectionStart());
1812 \qmlmethod void QtQuick2::TextInput::deselect()
1814 Removes active text selection.
1816 void QQuickTextInput::deselect()
1818 Q_D(QQuickTextInput);
1823 \qmlmethod void QtQuick2::TextInput::selectAll()
1825 Causes all text to be selected.
1827 void QQuickTextInput::selectAll()
1829 Q_D(QQuickTextInput);
1830 d->setSelection(0, text().length());
1834 \qmlmethod void QtQuick2::TextInput::isRightToLeft(int start, int end)
1836 Returns true if the natural reading direction of the editor text
1837 found between positions \a start and \a end is right to left.
1839 bool QQuickTextInput::isRightToLeft(int start, int end)
1842 qmlInfo(this) << "isRightToLeft(start, end) called with the end property being smaller than the start.";
1845 return text().mid(start, end - start).isRightToLeft();
1849 #ifndef QT_NO_CLIPBOARD
1851 \qmlmethod QtQuick2::TextInput::cut()
1853 Moves the currently selected text to the system clipboard.
1855 void QQuickTextInput::cut()
1857 Q_D(QQuickTextInput);
1863 \qmlmethod QtQuick2::TextInput::copy()
1865 Copies the currently selected text to the system clipboard.
1867 void QQuickTextInput::copy()
1869 Q_D(QQuickTextInput);
1874 \qmlmethod QtQuick2::TextInput::paste()
1876 Replaces the currently selected text by the contents of the system clipboard.
1878 void QQuickTextInput::paste()
1880 Q_D(QQuickTextInput);
1884 #endif // QT_NO_CLIPBOARD
1887 Undoes the last operation if undo is \l {canUndo}{available}. Deselects any
1888 current selection, and updates the selection start to the current cursor
1892 void QQuickTextInput::undo()
1894 Q_D(QQuickTextInput);
1895 if (!d->m_readOnly) {
1897 d->finishChange(-1, true);
1902 Redoes the last operation if redo is \l {canRedo}{available}.
1905 void QQuickTextInput::redo()
1907 Q_D(QQuickTextInput);
1908 if (!d->m_readOnly) {
1915 \qmlmethod void QtQuick2::TextInput::insert(int position, string text)
1917 Inserts \a text into the TextInput at position.
1920 void QQuickTextInput::insert(int position, const QString &text)
1922 Q_D(QQuickTextInput);
1923 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
1924 if (d->m_echoMode == QQuickTextInput::Password)
1925 d->m_passwordEchoTimer.start(qt_passwordEchoDelay, this);
1928 if (position < 0 || position > d->m_text.length())
1931 const int priorState = d->m_undoState;
1933 QString insertText = text;
1935 if (d->hasSelectedText()) {
1936 d->addCommand(QQuickTextInputPrivate::Command(
1937 QQuickTextInputPrivate::SetSelection, d->m_cursor, 0, d->m_selstart, d->m_selend));
1939 if (d->m_maskData) {
1940 insertText = d->maskString(position, insertText);
1941 for (int i = 0; i < insertText.length(); ++i) {
1942 d->addCommand(QQuickTextInputPrivate::Command(
1943 QQuickTextInputPrivate::DeleteSelection, position + i, d->m_text.at(position + i), -1, -1));
1944 d->addCommand(QQuickTextInputPrivate::Command(
1945 QQuickTextInputPrivate::Insert, position + i, insertText.at(i), -1, -1));
1947 d->m_text.replace(position, insertText.length(), insertText);
1948 if (!insertText.isEmpty())
1949 d->m_textDirty = true;
1950 if (position < d->m_selend && position + insertText.length() > d->m_selstart)
1951 d->m_selDirty = true;
1953 int remaining = d->m_maxLength - d->m_text.length();
1954 if (remaining != 0) {
1955 insertText = insertText.left(remaining);
1956 d->m_text.insert(position, insertText);
1957 for (int i = 0; i < insertText.length(); ++i)
1958 d->addCommand(QQuickTextInputPrivate::Command(
1959 QQuickTextInputPrivate::Insert, position + i, insertText.at(i), -1, -1));
1960 if (d->m_cursor >= position)
1961 d->m_cursor += insertText.length();
1962 if (d->m_selstart >= position)
1963 d->m_selstart += insertText.length();
1964 if (d->m_selend >= position)
1965 d->m_selend += insertText.length();
1966 d->m_textDirty = true;
1967 if (position >= d->m_selstart && position <= d->m_selend)
1968 d->m_selDirty = true;
1972 d->addCommand(QQuickTextInputPrivate::Command(
1973 QQuickTextInputPrivate::SetSelection, d->m_cursor, 0, d->m_selstart, d->m_selend));
1974 d->finishChange(priorState);
1976 if (d->lastSelectionStart != d->lastSelectionEnd) {
1977 if (d->m_selstart != d->lastSelectionStart) {
1978 d->lastSelectionStart = d->m_selstart;
1979 emit selectionStartChanged();
1981 if (d->m_selend != d->lastSelectionEnd) {
1982 d->lastSelectionEnd = d->m_selend;
1983 emit selectionEndChanged();
1989 \qmlmethod string QtQuick2::TextInput::getText(int start, int end)
1991 Removes the section of text that is between the \a start and \a end positions from the TextInput.
1994 void QQuickTextInput::remove(int start, int end)
1996 Q_D(QQuickTextInput);
1998 start = qBound(0, start, d->m_text.length());
1999 end = qBound(0, end, d->m_text.length());
2003 else if (start == end)
2006 if (start < d->m_selend && end > d->m_selstart)
2007 d->m_selDirty = true;
2009 const int priorState = d->m_undoState;
2011 d->addCommand(QQuickTextInputPrivate::Command(
2012 QQuickTextInputPrivate::SetSelection, d->m_cursor, 0, d->m_selstart, d->m_selend));
2014 if (start <= d->m_cursor && d->m_cursor < end) {
2015 // cursor is within the selection. Split up the commands
2016 // to be able to restore the correct cursor position
2017 for (int i = d->m_cursor; i >= start; --i) {
2018 d->addCommand(QQuickTextInputPrivate::Command(
2019 QQuickTextInputPrivate::DeleteSelection, i, d->m_text.at(i), -1, 1));
2021 for (int i = end - 1; i > d->m_cursor; --i) {
2022 d->addCommand(QQuickTextInputPrivate::Command(
2023 QQuickTextInputPrivate::DeleteSelection, i - d->m_cursor + start - 1, d->m_text.at(i), -1, -1));
2026 for (int i = end - 1; i >= start; --i) {
2027 d->addCommand(QQuickTextInputPrivate::Command(
2028 QQuickTextInputPrivate::RemoveSelection, i, d->m_text.at(i), -1, -1));
2031 if (d->m_maskData) {
2032 d->m_text.replace(start, end - start, d->clearString(start, end - start));
2033 for (int i = 0; i < end - start; ++i) {
2034 d->addCommand(QQuickTextInputPrivate::Command(
2035 QQuickTextInputPrivate::Insert, start + i, d->m_text.at(start + i), -1, -1));
2038 d->m_text.remove(start, end - start);
2040 if (d->m_cursor > start)
2041 d->m_cursor -= qMin(d->m_cursor, end) - start;
2042 if (d->m_selstart > start)
2043 d->m_selstart -= qMin(d->m_selstart, end) - start;
2044 if (d->m_selend > end)
2045 d->m_selend -= qMin(d->m_selend, end) - start;
2047 d->addCommand(QQuickTextInputPrivate::Command(
2048 QQuickTextInputPrivate::SetSelection, d->m_cursor, 0, d->m_selstart, d->m_selend));
2050 d->m_textDirty = true;
2051 d->finishChange(priorState);
2053 if (d->lastSelectionStart != d->lastSelectionEnd) {
2054 if (d->m_selstart != d->lastSelectionStart) {
2055 d->lastSelectionStart = d->m_selstart;
2056 emit selectionStartChanged();
2058 if (d->m_selend != d->lastSelectionEnd) {
2059 d->lastSelectionEnd = d->m_selend;
2060 emit selectionEndChanged();
2067 \qmlmethod void QtQuick2::TextInput::selectWord()
2069 Causes the word closest to the current cursor position to be selected.
2071 void QQuickTextInput::selectWord()
2073 Q_D(QQuickTextInput);
2074 d->selectWordAtPos(d->m_cursor);
2078 \qmlproperty bool QtQuick2::TextInput::smooth
2080 This property holds whether the text is smoothly scaled or transformed.
2082 Smooth filtering gives better visual quality, but is slower. If
2083 the item is displayed at its natural size, this property has no visual or
2086 \note Generally scaling artifacts are only visible if the item is stationary on
2087 the screen. A common pattern when animating an item is to disable smooth
2088 filtering at the beginning of the animation and reenable it at the conclusion.
2092 \qmlproperty string QtQuick2::TextInput::passwordCharacter
2094 This is the character displayed when echoMode is set to Password or
2095 PasswordEchoOnEdit. By default it is an asterisk.
2097 If this property is set to a string with more than one character,
2098 the first character is used. If the string is empty, the value
2099 is ignored and the property is not set.
2101 QString QQuickTextInput::passwordCharacter() const
2103 Q_D(const QQuickTextInput);
2104 return QString(d->m_passwordCharacter);
2107 void QQuickTextInput::setPasswordCharacter(const QString &str)
2109 Q_D(QQuickTextInput);
2110 if (str.length() < 1)
2112 d->m_passwordCharacter = str.constData()[0];
2113 if (d->m_echoMode == Password || d->m_echoMode == PasswordEchoOnEdit)
2114 d->updateDisplayText();
2115 emit passwordCharacterChanged();
2119 \qmlproperty string QtQuick2::TextInput::displayText
2121 This is the text displayed in the TextInput.
2123 If \l echoMode is set to TextInput::Normal, this holds the
2124 same value as the TextInput::text property. Otherwise,
2125 this property holds the text visible to the user, while
2126 the \l text property holds the actual entered text.
2128 QString QQuickTextInput::displayText() const
2130 Q_D(const QQuickTextInput);
2131 return d->m_textLayout.text();
2135 \qmlproperty bool QtQuick2::TextInput::selectByMouse
2139 If true, the user can use the mouse to select text in some
2140 platform-specific way. Note that for some platforms this may
2141 not be an appropriate interaction (eg. may conflict with how
2142 the text needs to behave inside a Flickable.
2144 bool QQuickTextInput::selectByMouse() const
2146 Q_D(const QQuickTextInput);
2147 return d->selectByMouse;
2150 void QQuickTextInput::setSelectByMouse(bool on)
2152 Q_D(QQuickTextInput);
2153 if (d->selectByMouse != on) {
2154 d->selectByMouse = on;
2155 emit selectByMouseChanged(on);
2160 \qmlproperty enum QtQuick2::TextInput::mouseSelectionMode
2162 Specifies how text should be selected using a mouse.
2165 \o TextInput.SelectCharacters - The selection is updated with individual characters. (Default)
2166 \o TextInput.SelectWords - The selection is updated with whole words.
2169 This property only applies when \l selectByMouse is true.
2172 QQuickTextInput::SelectionMode QQuickTextInput::mouseSelectionMode() const
2174 Q_D(const QQuickTextInput);
2175 return d->mouseSelectionMode;
2178 void QQuickTextInput::setMouseSelectionMode(SelectionMode mode)
2180 Q_D(QQuickTextInput);
2181 if (d->mouseSelectionMode != mode) {
2182 d->mouseSelectionMode = mode;
2183 emit mouseSelectionModeChanged(mode);
2188 \qmlproperty bool QtQuick2::TextInput::persistentSelection
2190 Whether the TextInput should keep its selection when it loses active focus to another
2191 item in the scene. By default this is set to false;
2194 bool QQuickTextInput::persistentSelection() const
2196 Q_D(const QQuickTextInput);
2197 return d->persistentSelection;
2200 void QQuickTextInput::setPersistentSelection(bool on)
2202 Q_D(QQuickTextInput);
2203 if (d->persistentSelection == on)
2205 d->persistentSelection = on;
2206 emit persistentSelectionChanged();
2210 \qmlproperty bool QtQuick2::TextInput::canPaste
2212 Returns true if the TextInput is writable and the content of the clipboard is
2213 suitable for pasting into the TextInput.
2215 bool QQuickTextInput::canPaste() const
2217 Q_D(const QQuickTextInput);
2218 if (!d->canPasteValid) {
2219 if (const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData())
2220 const_cast<QQuickTextInputPrivate *>(d)->canPaste = !d->m_readOnly && mimeData->hasText();
2221 const_cast<QQuickTextInputPrivate *>(d)->canPasteValid = true;
2227 \qmlproperty bool QtQuick2::TextInput::canUndo
2229 Returns true if the TextInput is writable and there are previous operations
2233 bool QQuickTextInput::canUndo() const
2235 Q_D(const QQuickTextInput);
2240 \qmlproperty bool QtQuick2::TextInput::canRedo
2242 Returns true if the TextInput is writable and there are \l {undo}{undone}
2243 operations that can be redone.
2246 bool QQuickTextInput::canRedo() const
2248 Q_D(const QQuickTextInput);
2252 void QQuickTextInput::moveCursorSelection(int position)
2254 Q_D(QQuickTextInput);
2255 d->moveCursor(position, true);
2259 \qmlmethod void QtQuick2::TextInput::moveCursorSelection(int position, SelectionMode mode = TextInput.SelectCharacters)
2261 Moves the cursor to \a position and updates the selection according to the optional \a mode
2262 parameter. (To only move the cursor, set the \l cursorPosition property.)
2264 When this method is called it additionally sets either the
2265 selectionStart or the selectionEnd (whichever was at the previous cursor position)
2266 to the specified position. This allows you to easily extend and contract the selected
2269 The selection mode specifies whether the selection is updated on a per character or a per word
2270 basis. If not specified the selection mode will default to TextInput.SelectCharacters.
2273 \o TextInput.SelectCharacters - Sets either the selectionStart or selectionEnd (whichever was at
2274 the previous cursor position) to the specified position.
2275 \o TextInput.SelectWords - Sets the selectionStart and selectionEnd to include all
2276 words between the specified position and the previous cursor position. Words partially in the
2280 For example, take this sequence of calls:
2284 moveCursorSelection(9, TextInput.SelectCharacters)
2285 moveCursorSelection(7, TextInput.SelectCharacters)
2288 This moves the cursor to position 5, extend the selection end from 5 to 9
2289 and then retract the selection end from 9 to 7, leaving the text from position 5 to 7
2290 selected (the 6th and 7th characters).
2292 The same sequence with TextInput.SelectWords will extend the selection start to a word boundary
2293 before or on position 5 and extend the selection end to a word boundary on or past position 9.
2295 void QQuickTextInput::moveCursorSelection(int pos, SelectionMode mode)
2297 Q_D(QQuickTextInput);
2299 if (mode == SelectCharacters) {
2300 d->moveCursor(pos, true);
2301 } else if (pos != d->m_cursor){
2302 const int cursor = d->m_cursor;
2304 if (!d->hasSelectedText())
2305 anchor = d->m_cursor;
2306 else if (d->selectionStart() == d->m_cursor)
2307 anchor = d->selectionEnd();
2309 anchor = d->selectionStart();
2311 if (anchor < pos || (anchor == pos && cursor < pos)) {
2312 const QString text = this->text();
2313 QTextBoundaryFinder finder(QTextBoundaryFinder::Word, text);
2314 finder.setPosition(anchor);
2316 const QTextBoundaryFinder::BoundaryReasons reasons = finder.boundaryReasons();
2317 if (anchor < text.length() && (!(reasons & QTextBoundaryFinder::StartWord)
2318 || ((reasons & QTextBoundaryFinder::EndWord) && anchor > cursor))) {
2319 finder.toPreviousBoundary();
2321 anchor = finder.position() != -1 ? finder.position() : 0;
2323 finder.setPosition(pos);
2324 if (pos > 0 && !finder.boundaryReasons())
2325 finder.toNextBoundary();
2326 const int cursor = finder.position() != -1 ? finder.position() : text.length();
2328 d->setSelection(anchor, cursor - anchor);
2329 } else if (anchor > pos || (anchor == pos && cursor > pos)) {
2330 const QString text = this->text();
2331 QTextBoundaryFinder finder(QTextBoundaryFinder::Word, text);
2332 finder.setPosition(anchor);
2334 const QTextBoundaryFinder::BoundaryReasons reasons = finder.boundaryReasons();
2335 if (anchor > 0 && (!(reasons & QTextBoundaryFinder::EndWord)
2336 || ((reasons & QTextBoundaryFinder::StartWord) && anchor < cursor))) {
2337 finder.toNextBoundary();
2340 anchor = finder.position() != -1 ? finder.position() : text.length();
2342 finder.setPosition(pos);
2343 if (pos < text.length() && !finder.boundaryReasons())
2344 finder.toPreviousBoundary();
2345 const int cursor = finder.position() != -1 ? finder.position() : 0;
2347 d->setSelection(anchor, cursor - anchor);
2353 \qmlmethod void QtQuick2::TextInput::openSoftwareInputPanel()
2355 Opens software input panels like virtual keyboards for typing, useful for
2356 customizing when you want the input keyboard to be shown and hidden in
2359 By default the opening of input panels follows the platform style. Input panels are
2360 always closed if no editor has active focus.
2362 You can disable the automatic behavior by setting the property \c activeFocusOnPress to false
2363 and use functions openSoftwareInputPanel() and closeSoftwareInputPanel() to implement
2364 the behavior you want.
2366 Only relevant on platforms, which provide virtual keyboards.
2372 text: "Hello world!"
2373 activeFocusOnPress: false
2375 anchors.fill: parent
2377 if (!textInput.activeFocus) {
2378 textInput.forceActiveFocus()
2379 textInput.openSoftwareInputPanel();
2381 textInput.focus = false;
2384 onPressAndHold: textInput.closeSoftwareInputPanel();
2389 void QQuickTextInput::openSoftwareInputPanel()
2392 qGuiApp->inputPanel()->show();
2396 \qmlmethod void QtQuick2::TextInput::closeSoftwareInputPanel()
2398 Closes a software input panel like a virtual keyboard shown on the screen, useful
2399 for customizing when you want the input keyboard to be shown and hidden in
2402 By default the opening of input panels follows the platform style. Input panels are
2403 always closed if no editor has active focus.
2405 You can disable the automatic behavior by setting the property \c activeFocusOnPress to false
2406 and use functions openSoftwareInputPanel() and closeSoftwareInputPanel() to implement
2407 the behavior you want.
2409 Only relevant on platforms, which provide virtual keyboards.
2415 text: "Hello world!"
2416 activeFocusOnPress: false
2418 anchors.fill: parent
2420 if (!textInput.activeFocus) {
2421 textInput.forceActiveFocus();
2422 textInput.openSoftwareInputPanel();
2424 textInput.focus = false;
2427 onPressAndHold: textInput.closeSoftwareInputPanel();
2432 void QQuickTextInput::closeSoftwareInputPanel()
2435 qGuiApp->inputPanel()->hide();
2438 void QQuickTextInput::focusInEvent(QFocusEvent *event)
2440 Q_D(const QQuickTextInput);
2441 if (d->focusOnPress && !d->m_readOnly)
2442 openSoftwareInputPanel();
2443 QQuickImplicitSizeItem::focusInEvent(event);
2446 void QQuickTextInput::itemChange(ItemChange change, const ItemChangeData &value)
2448 Q_D(QQuickTextInput);
2449 if (change == ItemActiveFocusHasChanged) {
2450 bool hasFocus = value.boolValue;
2451 d->focused = hasFocus;
2452 setCursorVisible(hasFocus); // ### refactor: && d->canvas && d->canvas->hasFocus()
2453 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
2454 if (!hasFocus && (d->m_passwordEchoEditing || d->m_passwordEchoTimer.isActive())) {
2456 if (!hasFocus && d->m_passwordEchoEditing) {
2458 d->updatePasswordEchoEditing(false);//QQuickTextInputPrivate sets it on key events, but doesn't deal with focus events
2463 if (!d->persistentSelection)
2465 disconnect(qApp->inputPanel(), SIGNAL(inputDirectionChanged(Qt::LayoutDirection)),
2466 this, SLOT(q_updateAlignment()));
2468 q_updateAlignment();
2469 connect(qApp->inputPanel(), SIGNAL(inputDirectionChanged(Qt::LayoutDirection)),
2470 this, SLOT(q_updateAlignment()));
2473 QQuickItem::itemChange(change, value);
2477 \qmlproperty bool QtQuick2::TextInput::inputMethodComposing
2480 This property holds whether the TextInput has partial text input from an
2483 While it is composing an input method may rely on mouse or key events from
2484 the TextInput to edit or commit the partial text. This property can be
2485 used to determine when to disable events handlers that may interfere with
2486 the correct operation of an input method.
2488 bool QQuickTextInput::isInputMethodComposing() const
2490 Q_D(const QQuickTextInput);
2491 return d->preeditAreaText().length() > 0;
2494 void QQuickTextInputPrivate::init()
2496 Q_Q(QQuickTextInput);
2497 q->setSmooth(smooth);
2498 q->setAcceptedMouseButtons(Qt::LeftButton);
2499 q->setFlag(QQuickItem::ItemAcceptsInputMethod);
2500 q->setFlag(QQuickItem::ItemHasContents);
2501 #ifndef QT_NO_CLIPBOARD
2502 q->connect(QGuiApplication::clipboard(), SIGNAL(dataChanged()),
2503 q, SLOT(q_canPasteChanged()));
2504 #endif // QT_NO_CLIPBOARD
2506 lastSelectionStart = 0;
2507 lastSelectionEnd = 0;
2508 selectedTextColor = m_palette.color(QPalette::HighlightedText);
2509 selectionColor = m_palette.color(QPalette::Highlight);
2510 determineHorizontalAlignment();
2512 if (!qmlDisableDistanceField()) {
2513 QTextOption option = m_textLayout.textOption();
2514 option.setUseDesignMetrics(true);
2515 m_textLayout.setTextOption(option);
2519 void QQuickTextInput::updateCursorRectangle()
2521 Q_D(QQuickTextInput);
2522 if (!isComponentComplete())
2525 d->updateHorizontalScroll();
2526 d->updateVerticalScroll();
2527 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
2529 emit cursorRectangleChanged();
2530 if (d->cursorItem) {
2531 QRectF r = cursorRectangle();
2532 d->cursorItem->setPos(r.topLeft());
2533 d->cursorItem->setHeight(r.height());
2535 updateInputMethod(Qt::ImCursorRectangle);
2538 void QQuickTextInput::selectionChanged()
2540 Q_D(QQuickTextInput);
2541 d->textLayoutDirty = true; //TODO: Only update rect in selection
2542 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
2544 emit selectedTextChanged();
2546 if (d->lastSelectionStart != d->selectionStart()) {
2547 d->lastSelectionStart = d->selectionStart();
2548 if (d->lastSelectionStart == -1)
2549 d->lastSelectionStart = d->m_cursor;
2550 emit selectionStartChanged();
2552 if (d->lastSelectionEnd != d->selectionEnd()) {
2553 d->lastSelectionEnd = d->selectionEnd();
2554 if (d->lastSelectionEnd == -1)
2555 d->lastSelectionEnd = d->m_cursor;
2556 emit selectionEndChanged();
2560 void QQuickTextInputPrivate::showCursor()
2562 if (textNode != 0 && textNode->cursorNode() != 0)
2563 textNode->cursorNode()->setColor(color);
2566 void QQuickTextInputPrivate::hideCursor()
2568 if (textNode != 0 && textNode->cursorNode() != 0)
2569 textNode->cursorNode()->setColor(QColor(0, 0, 0, 0));
2572 QRectF QQuickTextInput::boundingRect() const
2574 Q_D(const QQuickTextInput);
2576 int cursorWidth = d->cursorItem ? d->cursorItem->width() : d->m_cursorWidth;
2578 // Could include font max left/right bearings to either side of rectangle.
2579 QRectF r = QQuickImplicitSizeItem::boundingRect();
2580 r.setRight(r.right() + cursorWidth);
2584 void QQuickTextInput::q_canPasteChanged()
2586 Q_D(QQuickTextInput);
2587 bool old = d->canPaste;
2588 #ifndef QT_NO_CLIPBOARD
2589 if (const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData())
2590 d->canPaste = !d->m_readOnly && mimeData->hasText();
2592 d->canPaste = false;
2595 bool changed = d->canPaste != old || !d->canPasteValid;
2596 d->canPasteValid = true;
2598 emit canPasteChanged();
2602 void QQuickTextInput::q_updateAlignment()
2604 Q_D(QQuickTextInput);
2605 if (d->determineHorizontalAlignment()) {
2607 updateCursorRectangle();
2611 // ### these should come from QStyleHints
2612 const int textCursorWidth = 1;
2613 const bool fullWidthSelection = true;
2618 Updates the display text based of the current edit text
2619 If the text has changed will emit displayTextChanged()
2621 void QQuickTextInputPrivate::updateDisplayText(bool forceUpdate)
2623 QString orig = m_textLayout.text();
2625 if (m_echoMode == QQuickTextInput::NoEcho)
2626 str = QString::fromLatin1("");
2630 if (m_echoMode == QQuickTextInput::Password) {
2631 str.fill(m_passwordCharacter);
2632 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
2633 if (m_passwordEchoTimer.isActive() && m_cursor > 0 && m_cursor <= m_text.length()) {
2634 int cursor = m_cursor - 1;
2635 QChar uc = m_text.at(cursor);
2637 if (cursor > 0 && uc.unicode() >= 0xdc00 && uc.unicode() < 0xe000) {
2638 // second half of a surrogate, check if we have the first half as well,
2639 // if yes restore both at once
2640 uc = m_text.at(cursor - 1);
2641 if (uc.unicode() >= 0xd800 && uc.unicode() < 0xdc00)
2642 str[cursor - 1] = uc;
2646 } else if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit && !m_passwordEchoEditing) {
2647 str.fill(m_passwordCharacter);
2650 // replace certain non-printable characters with spaces (to avoid
2651 // drawing boxes when using fonts that don't have glyphs for such
2653 QChar* uc = str.data();
2654 for (int i = 0; i < (int)str.length(); ++i) {
2655 if ((uc[i] < 0x20 && uc[i] != 0x09)
2656 || uc[i] == QChar::LineSeparator
2657 || uc[i] == QChar::ParagraphSeparator
2658 || uc[i] == QChar::ObjectReplacementCharacter)
2659 uc[i] = QChar(0x0020);
2662 if (str != orig || forceUpdate) {
2663 m_textLayout.setText(str);
2664 updateLayout(); // polish?
2665 emit q_func()->displayTextChanged();
2669 void QQuickTextInputPrivate::updateLayout()
2671 Q_Q(QQuickTextInput);
2673 if (!q->isComponentComplete())
2676 QTextOption option = m_textLayout.textOption();
2677 option.setTextDirection(layoutDirection());
2678 option.setFlags(QTextOption::IncludeTrailingSpaces);
2679 option.setWrapMode(QTextOption::WrapMode(wrapMode));
2680 option.setAlignment(Qt::Alignment(q->effectiveHAlign()));
2681 m_textLayout.setTextOption(option);
2682 m_textLayout.setFont(font);
2684 boundingRect = QRectF();
2685 m_textLayout.beginLayout();
2686 QTextLine line = m_textLayout.createLine();
2687 qreal lineWidth = q->widthValid() ? q->width() : INT_MAX;
2689 QTextLine firstLine = line;
2691 line.setLineWidth(lineWidth);
2692 line.setPosition(QPointF(line.position().x(), height));
2693 boundingRect = boundingRect.united(line.naturalTextRect());
2695 height += line.height();
2696 line = m_textLayout.createLine();
2697 } while (line.isValid());
2698 m_textLayout.endLayout();
2700 option.setWrapMode(QTextOption::NoWrap);
2701 m_textLayout.setTextOption(option);
2703 m_ascent = qRound(firstLine.ascent());
2704 textLayoutDirty = true;
2706 updateType = UpdatePaintNode;
2708 q->setImplicitSize(qCeil(boundingRect.width()), qCeil(boundingRect.height()));
2712 #ifndef QT_NO_CLIPBOARD
2716 Copies the currently selected text into the clipboard using the given
2719 \note If the echo mode is set to a mode other than Normal then copy
2720 will not work. This is to prevent using copy as a method of bypassing
2721 password features of the line control.
2723 void QQuickTextInputPrivate::copy(QClipboard::Mode mode) const
2725 QString t = selectedText();
2726 if (!t.isEmpty() && m_echoMode == QQuickTextInput::Normal) {
2727 QGuiApplication::clipboard()->setText(t, mode);
2734 Inserts the text stored in the application clipboard into the line
2739 void QQuickTextInputPrivate::paste(QClipboard::Mode clipboardMode)
2741 QString clip = QGuiApplication::clipboard()->text(clipboardMode);
2742 if (!clip.isEmpty() || hasSelectedText()) {
2743 separate(); //make it a separate undo/redo command
2749 #endif // !QT_NO_CLIPBOARD
2754 Exits preedit mode and commits parts marked as tentative commit
2756 void QQuickTextInputPrivate::commitPreedit()
2761 qApp->inputPanel()->reset();
2763 if (!m_tentativeCommit.isEmpty()) {
2764 internalInsert(m_tentativeCommit);
2765 m_tentativeCommit.clear();
2766 finishChange(-1, true/*not used, not documented*/, false);
2769 m_preeditCursor = 0;
2770 m_textLayout.setPreeditArea(-1, QString());
2771 m_textLayout.clearAdditionalFormats();
2778 Handles the behavior for the backspace key or function.
2779 Removes the current selection if there is a selection, otherwise
2780 removes the character prior to the cursor position.
2784 void QQuickTextInputPrivate::backspace()
2786 int priorState = m_undoState;
2787 if (hasSelectedText()) {
2788 removeSelectedText();
2789 } else if (m_cursor) {
2792 m_cursor = prevMaskBlank(m_cursor);
2793 QChar uc = m_text.at(m_cursor);
2794 if (m_cursor > 0 && uc.unicode() >= 0xdc00 && uc.unicode() < 0xe000) {
2795 // second half of a surrogate, check if we have the first half as well,
2796 // if yes delete both at once
2797 uc = m_text.at(m_cursor - 1);
2798 if (uc.unicode() >= 0xd800 && uc.unicode() < 0xdc00) {
2799 internalDelete(true);
2803 internalDelete(true);
2805 finishChange(priorState);
2811 Handles the behavior for the delete key or function.
2812 Removes the current selection if there is a selection, otherwise
2813 removes the character after the cursor position.
2817 void QQuickTextInputPrivate::del()
2819 int priorState = m_undoState;
2820 if (hasSelectedText()) {
2821 removeSelectedText();
2823 int n = m_textLayout.nextCursorPosition(m_cursor) - m_cursor;
2827 finishChange(priorState);
2833 Inserts the given \a newText at the current cursor position.
2834 If there is any selected text it is removed prior to insertion of
2837 void QQuickTextInputPrivate::insert(const QString &newText)
2839 int priorState = m_undoState;
2840 removeSelectedText();
2841 internalInsert(newText);
2842 finishChange(priorState);
2848 Clears the line control text.
2850 void QQuickTextInputPrivate::clear()
2852 int priorState = m_undoState;
2854 m_selend = m_text.length();
2855 removeSelectedText();
2857 finishChange(priorState, /*update*/false, /*edited*/false);
2863 Sets \a length characters from the given \a start position as selected.
2864 The given \a start position must be within the current text for
2865 the line control. If \a length characters cannot be selected, then
2866 the selection will extend to the end of the current text.
2868 void QQuickTextInputPrivate::setSelection(int start, int length)
2870 Q_Q(QQuickTextInput);
2873 if (start < 0 || start > (int)m_text.length()){
2874 qWarning("QQuickTextInputPrivate::setSelection: Invalid start position");
2879 if (start == m_selstart && start + length == m_selend && m_cursor == m_selend)
2882 m_selend = qMin(start + length, (int)m_text.length());
2883 m_cursor = m_selend;
2884 } else if (length < 0){
2885 if (start == m_selend && start + length == m_selstart && m_cursor == m_selstart)
2887 m_selstart = qMax(start + length, 0);
2889 m_cursor = m_selstart;
2890 } else if (m_selstart != m_selend) {
2896 emitCursorPositionChanged();
2899 emit q->selectionChanged();
2900 emitCursorPositionChanged();
2901 q->updateInputMethod(Qt::ImCursorRectangle | Qt::ImAnchorPosition
2902 | Qt::ImCursorPosition | Qt::ImCurrentSelection);
2908 Initializes the line control with a starting text value of \a txt.
2910 void QQuickTextInputPrivate::init(const QString &txt)
2914 updateDisplayText();
2915 m_cursor = m_text.length();
2921 Sets the password echo editing to \a editing. If password echo editing
2922 is true, then the text of the password is displayed even if the echo
2923 mode is set to QLineEdit::PasswordEchoOnEdit. Password echoing editing
2924 does not affect other echo modes.
2926 void QQuickTextInputPrivate::updatePasswordEchoEditing(bool editing)
2928 cancelPasswordEchoTimer();
2929 m_passwordEchoEditing = editing;
2930 updateDisplayText();
2936 Fixes the current text so that it is valid given any set validators.
2938 Returns true if the text was changed. Otherwise returns false.
2940 bool QQuickTextInputPrivate::fixup() // this function assumes that validate currently returns != Acceptable
2942 #ifndef QT_NO_VALIDATOR
2944 QString textCopy = m_text;
2945 int cursorCopy = m_cursor;
2946 m_validator->fixup(textCopy);
2947 if (m_validator->validate(textCopy, cursorCopy) == QValidator::Acceptable) {
2948 if (textCopy != m_text || cursorCopy != m_cursor)
2949 internalSetText(textCopy, cursorCopy);
2960 Moves the cursor to the given position \a pos. If \a mark is true will
2961 adjust the currently selected text.
2963 void QQuickTextInputPrivate::moveCursor(int pos, bool mark)
2965 Q_Q(QQuickTextInput);
2968 if (pos != m_cursor) {
2971 pos = pos > m_cursor ? nextMaskBlank(pos) : prevMaskBlank(pos);
2975 if (m_selend > m_selstart && m_cursor == m_selstart)
2977 else if (m_selend > m_selstart && m_cursor == m_selend)
2978 anchor = m_selstart;
2981 m_selstart = qMin(anchor, pos);
2982 m_selend = qMax(anchor, pos);
2987 if (mark || m_selDirty) {
2989 emit q->selectionChanged();
2991 emitCursorPositionChanged();
2992 q->updateInputMethod();
2998 Applies the given input method event \a event to the text of the line
3001 void QQuickTextInputPrivate::processInputMethodEvent(QInputMethodEvent *event)
3003 Q_Q(QQuickTextInput);
3005 int priorState = -1;
3006 bool isGettingInput = !event->commitString().isEmpty()
3007 || event->preeditString() != preeditAreaText()
3008 || event->replacementLength() > 0;
3009 bool cursorPositionChanged = false;
3010 bool selectionChange = false;
3011 m_preeditDirty = event->preeditString() != preeditAreaText();
3013 if (isGettingInput) {
3014 // If any text is being input, remove selected text.
3015 priorState = m_undoState;
3016 if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit && !m_passwordEchoEditing) {
3017 updatePasswordEchoEditing(true);
3019 m_selend = m_text.length();
3021 removeSelectedText();
3024 int c = m_cursor; // cursor position after insertion of commit string
3025 if (event->replacementStart() <= 0)
3026 c += event->commitString().length() - qMin(-event->replacementStart(), event->replacementLength());
3028 m_cursor += event->replacementStart();
3032 // insert commit string
3033 if (event->replacementLength()) {
3034 m_selstart = m_cursor;
3035 m_selend = m_selstart + event->replacementLength();
3036 m_selend = qMin(m_selend, m_text.length());
3037 removeSelectedText();
3039 if (!event->commitString().isEmpty()) {
3040 internalInsert(event->commitString());
3041 cursorPositionChanged = true;
3044 m_cursor = qBound(0, c, m_text.length());
3046 for (int i = 0; i < event->attributes().size(); ++i) {
3047 const QInputMethodEvent::Attribute &a = event->attributes().at(i);
3048 if (a.type == QInputMethodEvent::Selection) {
3049 m_cursor = qBound(0, a.start + a.length, m_text.length());
3051 m_selstart = qMax(0, qMin(a.start, m_text.length()));
3052 m_selend = m_cursor;
3053 if (m_selend < m_selstart) {
3054 qSwap(m_selstart, m_selend);
3056 selectionChange = true;
3058 m_selstart = m_selend = 0;
3060 cursorPositionChanged = true;
3064 m_textLayout.setPreeditArea(m_cursor, event->preeditString());
3066 const int oldPreeditCursor = m_preeditCursor;
3067 m_preeditCursor = event->preeditString().length();
3068 m_hideCursor = false;
3069 QList<QTextLayout::FormatRange> formats;
3070 for (int i = 0; i < event->attributes().size(); ++i) {
3071 const QInputMethodEvent::Attribute &a = event->attributes().at(i);
3072 if (a.type == QInputMethodEvent::Cursor) {
3073 m_preeditCursor = a.start;
3074 m_hideCursor = !a.length;
3075 } else if (a.type == QInputMethodEvent::TextFormat) {
3076 QTextCharFormat f = qvariant_cast<QTextFormat>(a.value).toCharFormat();
3078 QTextLayout::FormatRange o;
3079 o.start = a.start + m_cursor;
3080 o.length = a.length;
3086 m_textLayout.setAdditionalFormats(formats);
3088 updateDisplayText(/*force*/ true);
3089 if (cursorPositionChanged) {
3090 emitCursorPositionChanged();
3091 } else if (m_preeditCursor != oldPreeditCursor) {
3092 q->updateCursorRectangle();
3095 bool tentativeCommitChanged = m_tentativeCommit != event->tentativeCommitString();
3097 if (tentativeCommitChanged) {
3099 m_tentativeCommit = event->tentativeCommitString();
3102 if (isGettingInput || tentativeCommitChanged)
3103 finishChange(priorState);
3105 if (selectionChange) {
3106 emit q->selectionChanged();
3107 q->updateInputMethod(Qt::ImCursorRectangle | Qt::ImAnchorPosition
3108 | Qt::ImCursorPosition | Qt::ImCurrentSelection);
3115 Sets the selection to cover the word at the given cursor position.
3116 The word boundaries are defined by the behavior of QTextLayout::SkipWords
3119 void QQuickTextInputPrivate::selectWordAtPos(int cursor)
3121 int next = cursor + 1;
3124 int c = m_textLayout.previousCursorPosition(next, QTextLayout::SkipWords);
3125 moveCursor(c, false);
3126 // ## text layout should support end of words.
3127 int end = m_textLayout.nextCursorPosition(c, QTextLayout::SkipWords);
3128 while (end > cursor && m_text[end-1].isSpace())
3130 moveCursor(end, true);
3136 Completes a change to the line control text. If the change is not valid
3137 will undo the line control state back to the given \a validateFromState.
3139 If \a edited is true and the change is valid, will emit textEdited() in
3140 addition to textChanged(). Otherwise only emits textChanged() on a valid
3143 The \a update value is currently unused.
3145 bool QQuickTextInputPrivate::finishChange(int validateFromState, bool update, bool /*edited*/)
3147 Q_Q(QQuickTextInput);
3150 bool inputMethodAttributesChanged = m_textDirty || m_selDirty;
3151 bool alignmentChanged = false;
3155 bool wasValidInput = m_validInput;
3156 bool wasAcceptable = m_acceptableInput;
3157 m_validInput = true;
3158 m_acceptableInput = true;
3159 #ifndef QT_NO_VALIDATOR
3161 QString textCopy = m_text;
3162 int cursorCopy = m_cursor;
3163 QValidator::State state = m_validator->validate(textCopy, cursorCopy);
3164 m_validInput = state != QValidator::Invalid;
3165 m_acceptableInput = state == QValidator::Acceptable;
3167 if (m_text != textCopy) {
3168 internalSetText(textCopy, cursorCopy);
3171 m_cursor = cursorCopy;
3173 if (!m_tentativeCommit.isEmpty()) {
3174 textCopy.insert(m_cursor, m_tentativeCommit);
3175 bool validInput = m_validator->validate(textCopy, cursorCopy) != QValidator::Invalid;
3177 m_tentativeCommit.clear();
3180 m_tentativeCommit.clear();
3184 if (validateFromState >= 0 && wasValidInput && !m_validInput) {
3185 if (m_transactions.count())
3187 internalUndo(validateFromState);
3188 m_history.resize(m_undoState);
3189 if (m_modifiedState > m_undoState)
3190 m_modifiedState = -1;
3191 m_validInput = true;
3192 m_acceptableInput = wasAcceptable;
3193 m_textDirty = false;
3197 m_textDirty = false;
3198 m_preeditDirty = false;
3199 alignmentChanged = determineHorizontalAlignment();
3200 emit q->textChanged();
3203 updateDisplayText(alignmentChanged);
3205 if (m_acceptableInput != wasAcceptable)
3206 emit q->acceptableInputChanged();
3208 if (m_preeditDirty) {
3209 m_preeditDirty = false;
3210 if (determineHorizontalAlignment()) {
3211 alignmentChanged = true;
3218 emit q->selectionChanged();
3221 inputMethodAttributesChanged |= (m_cursor == m_lastCursorPos);
3222 if (inputMethodAttributesChanged)
3223 q->updateInputMethod();
3224 emitUndoRedoChanged();
3226 if (!emitCursorPositionChanged() && alignmentChanged)
3227 q->updateCursorRectangle();
3235 An internal function for setting the text of the line control.
3237 void QQuickTextInputPrivate::internalSetText(const QString &txt, int pos, bool edited)
3239 Q_Q(QQuickTextInput);
3241 QString oldText = m_text;
3243 m_text = maskString(0, txt, true);
3244 m_text += clearString(m_text.length(), m_maxLength - m_text.length());
3246 m_text = txt.isEmpty() ? txt : txt.left(m_maxLength);
3249 m_modifiedState = m_undoState = 0;
3250 m_cursor = (pos < 0 || pos > m_text.length()) ? m_text.length() : pos;
3251 m_textDirty = (oldText != m_text);
3253 bool changed = finishChange(-1, true, edited);
3254 #ifdef QT_NO_ACCESSIBILITY
3258 QAccessible::updateAccessibility(QAccessibleEvent(QAccessible::TextUpdated, q, 0));
3266 Adds the given \a command to the undo history
3267 of the line control. Does not apply the command.
3269 void QQuickTextInputPrivate::addCommand(const Command &cmd)
3271 if (m_separator && m_undoState && m_history[m_undoState - 1].type != Separator) {
3272 m_history.resize(m_undoState + 2);
3273 m_history[m_undoState++] = Command(Separator, m_cursor, 0, m_selstart, m_selend);
3275 m_history.resize(m_undoState + 1);
3277 m_separator = false;
3278 m_history[m_undoState++] = cmd;
3284 Inserts the given string \a s into the line
3287 Also adds the appropriate commands into the undo history.
3288 This function does not call finishChange(), and may leave the text
3289 in an invalid state.
3291 void QQuickTextInputPrivate::internalInsert(const QString &s)
3293 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
3294 Q_Q(QQuickTextInput);
3295 if (m_echoMode == QQuickTextInput::Password)
3296 m_passwordEchoTimer.start(qt_passwordEchoDelay, q);
3298 if (hasSelectedText())
3299 addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
3301 QString ms = maskString(m_cursor, s);
3302 for (int i = 0; i < (int) ms.length(); ++i) {
3303 addCommand (Command(DeleteSelection, m_cursor + i, m_text.at(m_cursor + i), -1, -1));
3304 addCommand(Command(Insert, m_cursor + i, ms.at(i), -1, -1));
3306 m_text.replace(m_cursor, ms.length(), ms);
3307 m_cursor += ms.length();
3308 m_cursor = nextMaskBlank(m_cursor);
3311 int remaining = m_maxLength - m_text.length();
3312 if (remaining != 0) {
3313 m_text.insert(m_cursor, s.left(remaining));
3314 for (int i = 0; i < (int) s.left(remaining).length(); ++i)
3315 addCommand(Command(Insert, m_cursor++, s.at(i), -1, -1));
3324 deletes a single character from the current text. If \a wasBackspace,
3325 the character prior to the cursor is removed. Otherwise the character
3326 after the cursor is removed.
3328 Also adds the appropriate commands into the undo history.
3329 This function does not call finishChange(), and may leave the text
3330 in an invalid state.
3332 void QQuickTextInputPrivate::internalDelete(bool wasBackspace)
3334 if (m_cursor < (int) m_text.length()) {
3335 cancelPasswordEchoTimer();
3336 if (hasSelectedText())
3337 addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
3338 addCommand(Command((CommandType)((m_maskData ? 2 : 0) + (wasBackspace ? Remove : Delete)),
3339 m_cursor, m_text.at(m_cursor), -1, -1));
3341 m_text.replace(m_cursor, 1, clearString(m_cursor, 1));
3342 addCommand(Command(Insert, m_cursor, m_text.at(m_cursor), -1, -1));
3344 m_text.remove(m_cursor, 1);
3353 removes the currently selected text from the line control.
3355 Also adds the appropriate commands into the undo history.
3356 This function does not call finishChange(), and may leave the text
3357 in an invalid state.
3359 void QQuickTextInputPrivate::removeSelectedText()
3361 if (m_selstart < m_selend && m_selend <= (int) m_text.length()) {
3362 cancelPasswordEchoTimer();
3365 addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
3366 if (m_selstart <= m_cursor && m_cursor < m_selend) {
3367 // cursor is within the selection. Split up the commands
3368 // to be able to restore the correct cursor position
3369 for (i = m_cursor; i >= m_selstart; --i)
3370 addCommand (Command(DeleteSelection, i, m_text.at(i), -1, 1));
3371 for (i = m_selend - 1; i > m_cursor; --i)
3372 addCommand (Command(DeleteSelection, i - m_cursor + m_selstart - 1, m_text.at(i), -1, -1));
3374 for (i = m_selend-1; i >= m_selstart; --i)
3375 addCommand (Command(RemoveSelection, i, m_text.at(i), -1, -1));
3378 m_text.replace(m_selstart, m_selend - m_selstart, clearString(m_selstart, m_selend - m_selstart));
3379 for (int i = 0; i < m_selend - m_selstart; ++i)
3380 addCommand(Command(Insert, m_selstart + i, m_text.at(m_selstart + i), -1, -1));
3382 m_text.remove(m_selstart, m_selend - m_selstart);
3384 if (m_cursor > m_selstart)
3385 m_cursor -= qMin(m_cursor, m_selend) - m_selstart;
3394 Parses the input mask specified by \a maskFields to generate
3395 the mask data used to handle input masks.
3397 void QQuickTextInputPrivate::parseInputMask(const QString &maskFields)
3399 int delimiter = maskFields.indexOf(QLatin1Char(';'));
3400 if (maskFields.isEmpty() || delimiter == 0) {
3402 delete [] m_maskData;
3404 m_maxLength = 32767;
3405 internalSetText(QString());
3410 if (delimiter == -1) {
3411 m_blank = QLatin1Char(' ');
3412 m_inputMask = maskFields;
3414 m_inputMask = maskFields.left(delimiter);
3415 m_blank = (delimiter + 1 < maskFields.length()) ? maskFields[delimiter + 1] : QLatin1Char(' ');
3418 // calculate m_maxLength / m_maskData length
3421 for (int i=0; i<m_inputMask.length(); i++) {
3422 c = m_inputMask.at(i);
3423 if (i > 0 && m_inputMask.at(i-1) == QLatin1Char('\\')) {
3427 if (c != QLatin1Char('\\') && c != QLatin1Char('!') &&
3428 c != QLatin1Char('<') && c != QLatin1Char('>') &&
3429 c != QLatin1Char('{') && c != QLatin1Char('}') &&
3430 c != QLatin1Char('[') && c != QLatin1Char(']'))
3434 delete [] m_maskData;
3435 m_maskData = new MaskInputData[m_maxLength];
3437 MaskInputData::Casemode m = MaskInputData::NoCaseMode;
3440 bool escape = false;
3442 for (int i = 0; i < m_inputMask.length(); i++) {
3443 c = m_inputMask.at(i);
3446 m_maskData[index].maskChar = c;
3447 m_maskData[index].separator = s;
3448 m_maskData[index].caseMode = m;
3451 } else if (c == QLatin1Char('<')) {
3452 m = MaskInputData::Lower;
3453 } else if (c == QLatin1Char('>')) {
3454 m = MaskInputData::Upper;
3455 } else if (c == QLatin1Char('!')) {
3456 m = MaskInputData::NoCaseMode;
3457 } else if (c != QLatin1Char('{') && c != QLatin1Char('}') && c != QLatin1Char('[') && c != QLatin1Char(']')) {
3458 switch (c.unicode()) {
3484 m_maskData[index].maskChar = c;
3485 m_maskData[index].separator = s;
3486 m_maskData[index].caseMode = m;
3491 internalSetText(m_text);
3498 checks if the key is valid compared to the inputMask
3500 bool QQuickTextInputPrivate::isValidInput(QChar key, QChar mask) const
3502 switch (mask.unicode()) {
3508 if (key.isLetter() || key == m_blank)
3512 if (key.isLetterOrNumber())
3516 if (key.isLetterOrNumber() || key == m_blank)
3524 if (key.isPrint() || key == m_blank)
3532 if (key.isNumber() || key == m_blank)
3536 if (key.isNumber() && key.digitValue() > 0)
3540 if ((key.isNumber() && key.digitValue() > 0) || key == m_blank)
3544 if (key.isNumber() || key == QLatin1Char('+') || key == QLatin1Char('-') || key == m_blank)
3548 if (key == QLatin1Char('0') || key == QLatin1Char('1'))
3552 if (key == QLatin1Char('0') || key == QLatin1Char('1') || key == m_blank)
3556 if (key.isNumber() || (key >= QLatin1Char('a') && key <= QLatin1Char('f')) || (key >= QLatin1Char('A') && key <= QLatin1Char('F')))
3560 if (key.isNumber() || (key >= QLatin1Char('a') && key <= QLatin1Char('f')) || (key >= QLatin1Char('A') && key <= QLatin1Char('F')) || key == m_blank)
3572 Returns true if the given text \a str is valid for any
3573 validator or input mask set for the line control.
3575 Otherwise returns false
3577 QQuickTextInputPrivate::ValidatorState QQuickTextInputPrivate::hasAcceptableInput(const QString &str) const
3579 #ifndef QT_NO_VALIDATOR
3580 QString textCopy = str;
3581 int cursorCopy = m_cursor;
3583 QValidator::State state = m_validator->validate(textCopy, cursorCopy);
3584 if (state != QValidator::Acceptable)
3585 return ValidatorState(state);
3590 return AcceptableInput;
3592 if (str.length() != m_maxLength)
3593 return InvalidInput;
3595 for (int i=0; i < m_maxLength; ++i) {
3596 if (m_maskData[i].separator) {
3597 if (str.at(i) != m_maskData[i].maskChar)
3598 return InvalidInput;
3600 if (!isValidInput(str.at(i), m_maskData[i].maskChar))
3601 return InvalidInput;
3604 return AcceptableInput;
3610 Applies the inputMask on \a str starting from position \a pos in the mask. \a clear
3611 specifies from where characters should be gotten when a separator is met in \a str - true means
3612 that blanks will be used, false that previous input is used.
3613 Calling this when no inputMask is set is undefined.
3615 QString QQuickTextInputPrivate::maskString(uint pos, const QString &str, bool clear) const
3617 if (pos >= (uint)m_maxLength)
3618 return QString::fromLatin1("");
3621 fill = clear ? clearString(0, m_maxLength) : m_text;
3624 QString s = QString::fromLatin1("");
3626 while (i < m_maxLength) {
3627 if (strIndex < str.length()) {
3628 if (m_maskData[i].separator) {
3629 s += m_maskData[i].maskChar;
3630 if (str[(int)strIndex] == m_maskData[i].maskChar)
3634 if (isValidInput(str[(int)strIndex], m_maskData[i].maskChar)) {
3635 switch (m_maskData[i].caseMode) {
3636 case MaskInputData::Upper:
3637 s += str[(int)strIndex].toUpper();
3639 case MaskInputData::Lower:
3640 s += str[(int)strIndex].toLower();
3643 s += str[(int)strIndex];
3647 // search for separator first
3648 int n = findInMask(i, true, true, str[(int)strIndex]);
3650 if (str.length() != 1 || i == 0 || (i > 0 && (!m_maskData[i-1].separator || m_maskData[i-1].maskChar != str[(int)strIndex]))) {
3651 s += fill.mid(i, n-i+1);
3652 i = n + 1; // update i to find + 1
3655 // search for valid m_blank if not
3656 n = findInMask(i, true, false, str[(int)strIndex]);
3658 s += fill.mid(i, n-i);
3659 switch (m_maskData[n].caseMode) {
3660 case MaskInputData::Upper:
3661 s += str[(int)strIndex].toUpper();
3663 case MaskInputData::Lower:
3664 s += str[(int)strIndex].toLower();
3667 s += str[(int)strIndex];
3669 i = n + 1; // updates i to find + 1
3687 Returns a "cleared" string with only separators and blank chars.
3688 Calling this when no inputMask is set is undefined.
3690 QString QQuickTextInputPrivate::clearString(uint pos, uint len) const
3692 if (pos >= (uint)m_maxLength)
3696 int end = qMin((uint)m_maxLength, pos + len);
3697 for (int i = pos; i < end; ++i)
3698 if (m_maskData[i].separator)
3699 s += m_maskData[i].maskChar;
3709 Strips blank parts of the input in a QQuickTextInputPrivate when an inputMask is set,
3710 separators are still included. Typically "127.0__.0__.1__" becomes "127.0.0.1".
3712 QString QQuickTextInputPrivate::stripString(const QString &str) const
3718 int end = qMin(m_maxLength, (int)str.length());
3719 for (int i = 0; i < end; ++i) {
3720 if (m_maskData[i].separator)
3721 s += m_maskData[i].maskChar;
3722 else if (str[i] != m_blank)
3731 searches forward/backward in m_maskData for either a separator or a m_blank
3733 int QQuickTextInputPrivate::findInMask(int pos, bool forward, bool findSeparator, QChar searchChar) const
3735 if (pos >= m_maxLength || pos < 0)
3738 int end = forward ? m_maxLength : -1;
3739 int step = forward ? 1 : -1;
3743 if (findSeparator) {
3744 if (m_maskData[i].separator && m_maskData[i].maskChar == searchChar)
3747 if (!m_maskData[i].separator) {
3748 if (searchChar.isNull())
3750 else if (isValidInput(searchChar, m_maskData[i].maskChar))
3759 void QQuickTextInputPrivate::internalUndo(int until)
3761 if (!isUndoAvailable())
3763 cancelPasswordEchoTimer();
3765 while (m_undoState && m_undoState > until) {
3766 Command& cmd = m_history[--m_undoState];
3769 m_text.remove(cmd.pos, 1);
3773 m_selstart = cmd.selStart;
3774 m_selend = cmd.selEnd;
3778 case RemoveSelection:
3779 m_text.insert(cmd.pos, cmd.uc);
3780 m_cursor = cmd.pos + 1;
3783 case DeleteSelection:
3784 m_text.insert(cmd.pos, cmd.uc);
3790 if (until < 0 && m_undoState) {
3791 Command& next = m_history[m_undoState-1];
3792 if (next.type != cmd.type && next.type < RemoveSelection
3793 && (cmd.type < RemoveSelection || next.type == Separator))
3800 void QQuickTextInputPrivate::internalRedo()
3802 if (!isRedoAvailable())
3805 while (m_undoState < (int)m_history.size()) {
3806 Command& cmd = m_history[m_undoState++];
3809 m_text.insert(cmd.pos, cmd.uc);
3810 m_cursor = cmd.pos + 1;
3813 m_selstart = cmd.selStart;
3814 m_selend = cmd.selEnd;
3819 case RemoveSelection:
3820 case DeleteSelection:
3821 m_text.remove(cmd.pos, 1);
3822 m_selstart = cmd.selStart;
3823 m_selend = cmd.selEnd;
3827 m_selstart = cmd.selStart;
3828 m_selend = cmd.selEnd;
3832 if (m_undoState < (int)m_history.size()) {
3833 Command& next = m_history[m_undoState];
3834 if (next.type != cmd.type && cmd.type < RemoveSelection && next.type != Separator
3835 && (next.type < RemoveSelection || cmd.type == Separator))
3842 void QQuickTextInputPrivate::emitUndoRedoChanged()
3844 Q_Q(QQuickTextInput);
3845 const bool previousUndo = canUndo;
3846 const bool previousRedo = canRedo;
3848 canUndo = isUndoAvailable();
3849 canRedo = isRedoAvailable();
3851 if (previousUndo != canUndo)
3852 emit q->canUndoChanged();
3853 if (previousRedo != canRedo)
3854 emit q->canRedoChanged();
3860 If the current cursor position differs from the last emitted cursor
3861 position, emits cursorPositionChanged().
3863 bool QQuickTextInputPrivate::emitCursorPositionChanged()
3865 Q_Q(QQuickTextInput);
3866 if (m_cursor != m_lastCursorPos) {
3867 m_lastCursorPos = m_cursor;
3869 q->updateCursorRectangle();
3870 emit q->cursorPositionChanged();
3871 // XXX todo - not in 4.8?
3873 resetCursorBlinkTimer();
3876 if (!hasSelectedText()) {
3877 if (lastSelectionStart != m_cursor) {
3878 lastSelectionStart = m_cursor;
3879 emit q->selectionStartChanged();
3881 if (lastSelectionEnd != m_cursor) {
3882 lastSelectionEnd = m_cursor;
3883 emit q->selectionEndChanged();
3887 #ifndef QT_NO_ACCESSIBILITY
3888 QAccessible::updateAccessibility(QAccessibleEvent(QAccessible::TextCaretMoved, q, 0));
3897 void QQuickTextInputPrivate::setCursorBlinkPeriod(int msec)
3899 Q_Q(QQuickTextInput);
3900 if (msec == m_blinkPeriod)
3903 q->killTimer(m_blinkTimer);
3906 m_blinkTimer = q->startTimer(msec / 2);
3910 if (m_blinkStatus == 1) {
3911 updateType = UpdatePaintNode;
3915 m_blinkPeriod = msec;
3918 void QQuickTextInputPrivate::resetCursorBlinkTimer()
3920 Q_Q(QQuickTextInput);
3921 if (m_blinkPeriod == 0 || m_blinkTimer == 0)
3923 q->killTimer(m_blinkTimer);
3924 m_blinkTimer = q->startTimer(m_blinkPeriod / 2);
3928 void QQuickTextInput::timerEvent(QTimerEvent *event)
3930 Q_D(QQuickTextInput);
3931 if (event->timerId() == d->m_blinkTimer) {
3932 d->m_blinkStatus = !d->m_blinkStatus;
3933 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
3935 } else if (event->timerId() == d->m_deleteAllTimer) {
3936 killTimer(d->m_deleteAllTimer);
3937 d->m_deleteAllTimer = 0;
3939 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
3940 } else if (event->timerId() == d->m_passwordEchoTimer.timerId()) {
3941 d->m_passwordEchoTimer.stop();
3942 d->updateDisplayText();
3947 void QQuickTextInputPrivate::processKeyEvent(QKeyEvent* event)
3949 Q_Q(QQuickTextInput);
3950 bool inlineCompletionAccepted = false;
3952 if (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return) {
3953 if (hasAcceptableInput(m_text) || fixup()) {
3956 if (inlineCompletionAccepted)
3963 if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit
3964 && !m_passwordEchoEditing
3966 && !event->text().isEmpty()
3967 && !(event->modifiers() & Qt::ControlModifier)) {
3968 // Clear the edit and reset to normal echo mode while editing; the
3969 // echo mode switches back when the edit loses focus
3970 // ### resets current content. dubious code; you can
3971 // navigate with keys up, down, back, and select(?), but if you press
3972 // "left" or "right" it clears?
3973 updatePasswordEchoEditing(true);
3977 bool unknown = false;
3978 bool visual = cursorMoveStyle() == Qt::VisualMoveStyle;
3982 #ifndef QT_NO_SHORTCUT
3983 else if (event == QKeySequence::Undo) {
3987 else if (event == QKeySequence::Redo) {
3991 else if (event == QKeySequence::SelectAll) {
3994 #ifndef QT_NO_CLIPBOARD
3995 else if (event == QKeySequence::Copy) {
3998 else if (event == QKeySequence::Paste) {
4000 QClipboard::Mode mode = QClipboard::Clipboard;
4004 else if (event == QKeySequence::Cut) {
4010 else if (event == QKeySequence::DeleteEndOfLine) {
4012 setSelection(m_cursor, end());
4017 #endif //QT_NO_CLIPBOARD
4018 else if (event == QKeySequence::MoveToStartOfLine || event == QKeySequence::MoveToStartOfBlock) {
4021 else if (event == QKeySequence::MoveToEndOfLine || event == QKeySequence::MoveToEndOfBlock) {
4024 else if (event == QKeySequence::SelectStartOfLine || event == QKeySequence::SelectStartOfBlock) {
4027 else if (event == QKeySequence::SelectEndOfLine || event == QKeySequence::SelectEndOfBlock) {
4030 else if (event == QKeySequence::MoveToNextChar) {
4031 if (hasSelectedText()) {
4032 moveCursor(selectionEnd(), false);
4034 cursorForward(0, visual ? 1 : (layoutDirection() == Qt::LeftToRight ? 1 : -1));
4037 else if (event == QKeySequence::SelectNextChar) {
4038 cursorForward(1, visual ? 1 : (layoutDirection() == Qt::LeftToRight ? 1 : -1));
4040 else if (event == QKeySequence::MoveToPreviousChar) {
4041 if (hasSelectedText()) {
4042 moveCursor(selectionStart(), false);
4044 cursorForward(0, visual ? -1 : (layoutDirection() == Qt::LeftToRight ? -1 : 1));
4047 else if (event == QKeySequence::SelectPreviousChar) {
4048 cursorForward(1, visual ? -1 : (layoutDirection() == Qt::LeftToRight ? -1 : 1));
4050 else if (event == QKeySequence::MoveToNextWord) {
4051 if (m_echoMode == QQuickTextInput::Normal)
4052 layoutDirection() == Qt::LeftToRight ? cursorWordForward(0) : cursorWordBackward(0);
4054 layoutDirection() == Qt::LeftToRight ? end(0) : home(0);
4056 else if (event == QKeySequence::MoveToPreviousWord) {
4057 if (m_echoMode == QQuickTextInput::Normal)
4058 layoutDirection() == Qt::LeftToRight ? cursorWordBackward(0) : cursorWordForward(0);
4059 else if (!m_readOnly) {
4060 layoutDirection() == Qt::LeftToRight ? home(0) : end(0);
4063 else if (event == QKeySequence::SelectNextWord) {
4064 if (m_echoMode == QQuickTextInput::Normal)
4065 layoutDirection() == Qt::LeftToRight ? cursorWordForward(1) : cursorWordBackward(1);
4067 layoutDirection() == Qt::LeftToRight ? end(1) : home(1);
4069 else if (event == QKeySequence::SelectPreviousWord) {
4070 if (m_echoMode == QQuickTextInput::Normal)
4071 layoutDirection() == Qt::LeftToRight ? cursorWordBackward(1) : cursorWordForward(1);
4073 layoutDirection() == Qt::LeftToRight ? home(1) : end(1);
4075 else if (event == QKeySequence::Delete) {
4079 else if (event == QKeySequence::DeleteEndOfWord) {
4081 cursorWordForward(true);
4085 else if (event == QKeySequence::DeleteStartOfWord) {
4087 cursorWordBackward(true);
4091 #endif // QT_NO_SHORTCUT
4093 bool handled = false;
4094 if (event->modifiers() & Qt::ControlModifier) {
4095 switch (event->key()) {
4096 case Qt::Key_Backspace:
4098 cursorWordBackward(true);
4106 } else { // ### check for *no* modifier
4107 switch (event->key()) {
4108 case Qt::Key_Backspace:
4120 if (event->key() == Qt::Key_Direction_L || event->key() == Qt::Key_Direction_R) {
4121 setLayoutDirection((event->key() == Qt::Key_Direction_L) ? Qt::LeftToRight : Qt::RightToLeft);
4125 if (unknown && !m_readOnly) {
4126 QString t = event->text();
4127 if (!t.isEmpty() && t.at(0).isPrint()) {