1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the QtQml module of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #include "qquicktextinput_p.h"
43 #include "qquicktextinput_p_p.h"
44 #include "qquickcanvas.h"
46 #include <private/qqmlglobal_p.h>
48 #include <QtCore/qcoreapplication.h>
49 #include <QtQml/qqmlinfo.h>
50 #include <QtGui/qevent.h>
51 #include <QTextBoundaryFinder>
52 #include "qquicktextnode_p.h"
53 #include <QtQuick/qsgsimplerectnode.h>
55 #include <QtGui/qstylehints.h>
56 #include <QtGui/qinputmethod.h>
58 #ifndef QT_NO_ACCESSIBILITY
59 #include "qaccessible.h"
64 DEFINE_BOOL_CONFIG_OPTION(qmlDisableDistanceField, QML_DISABLE_DISTANCEFIELD)
67 \qmlclass TextInput QQuickTextInput
68 \inqmlmodule QtQuick 2
69 \ingroup qml-basic-visual-elements
70 \brief The TextInput item displays an editable line of text.
73 The TextInput element displays a single line of editable plain text.
75 TextInput is used to accept a line of text input. Input constraints
76 can be placed on a TextInput item (for example, through a \l validator or \l inputMask),
77 and setting \l echoMode to an appropriate value enables TextInput to be used for
78 a password input field.
80 On Mac OS X, the Up/Down key bindings for Home/End are explicitly disabled.
81 If you want such bindings (on any platform), you will need to construct them in QML.
83 \sa TextEdit, Text, {declarative/text/textselection}{Text Selection example}
85 QQuickTextInput::QQuickTextInput(QQuickItem* parent)
86 : QQuickImplicitSizeItem(*(new QQuickTextInputPrivate), parent)
92 QQuickTextInput::~QQuickTextInput()
96 void QQuickTextInput::componentComplete()
100 QQuickImplicitSizeItem::componentComplete();
104 updateCursorRectangle();
105 if (d->cursorComponent && d->cursorComponent->isReady())
110 \qmlproperty string QtQuick2::TextInput::text
112 The text in the TextInput.
114 QString QQuickTextInput::text() const
116 Q_D(const QQuickTextInput);
118 QString content = d->m_text;
119 QString res = d->m_maskData ? d->stripString(content) : content;
120 return (res.isNull() ? QString::fromLatin1("") : res);
123 void QQuickTextInput::setText(const QString &s)
125 Q_D(QQuickTextInput);
130 d->internalSetText(s, -1, false);
134 \qmlproperty int QtQuick2::TextInput::length
136 Returns the total number of characters in the TextInput item.
138 If the TextInput has an inputMask the length will include mask characters and may differ
139 from the length of the string returned by the \l text property.
141 This property can be faster than querying the length the \l text property as it doesn't
142 require any copying or conversion of the TextInput's internal string data.
145 int QQuickTextInput::length() const
147 Q_D(const QQuickTextInput);
148 return d->m_text.length();
152 \qmlmethod string QtQuick2::TextInput::getText(int start, int end)
154 Returns the section of text that is between the \a start and \a end positions.
156 If the TextInput has an inputMask the length will include mask characters.
159 QString QQuickTextInput::getText(int start, int end) const
161 Q_D(const QQuickTextInput);
166 return d->m_text.mid(start, end - start);
169 QString QQuickTextInputPrivate::realText() const
171 QString res = m_maskData ? stripString(m_text) : m_text;
172 return (res.isNull() ? QString::fromLatin1("") : res);
176 \qmlproperty string QtQuick2::TextInput::font.family
178 Sets the family name of the font.
180 The family name is case insensitive and may optionally include a foundry name, e.g. "Helvetica [Cronyx]".
181 If the family is available from more than one foundry and the foundry isn't specified, an arbitrary foundry is chosen.
182 If the family isn't available a family will be set using the font matching algorithm.
186 \qmlproperty bool QtQuick2::TextInput::font.bold
188 Sets whether the font weight is bold.
192 \qmlproperty enumeration QtQuick2::TextInput::font.weight
194 Sets the font's weight.
196 The weight can be one of:
199 \li Font.Normal - the default
206 TextInput { text: "Hello"; font.weight: Font.DemiBold }
211 \qmlproperty bool QtQuick2::TextInput::font.italic
213 Sets whether the font has an italic style.
217 \qmlproperty bool QtQuick2::TextInput::font.underline
219 Sets whether the text is underlined.
223 \qmlproperty bool QtQuick2::TextInput::font.strikeout
225 Sets whether the font has a strikeout style.
229 \qmlproperty real QtQuick2::TextInput::font.pointSize
231 Sets the font size in points. The point size must be greater than zero.
235 \qmlproperty int QtQuick2::TextInput::font.pixelSize
237 Sets the font size in pixels.
239 Using this function makes the font device dependent.
240 Use \c pointSize to set the size of the font in a device independent manner.
244 \qmlproperty real QtQuick2::TextInput::font.letterSpacing
246 Sets the letter spacing for the font.
248 Letter spacing changes the default spacing between individual letters in the font.
249 A positive value increases the letter spacing by the corresponding pixels; a negative value decreases the spacing.
253 \qmlproperty real QtQuick2::TextInput::font.wordSpacing
255 Sets the word spacing for the font.
257 Word spacing changes the default spacing between individual words.
258 A positive value increases the word spacing by a corresponding amount of pixels,
259 while a negative value decreases the inter-word spacing accordingly.
263 \qmlproperty enumeration QtQuick2::TextInput::font.capitalization
265 Sets the capitalization for the text.
268 \li Font.MixedCase - This is the normal text rendering option where no capitalization change is applied.
269 \li Font.AllUppercase - This alters the text to be rendered in all uppercase type.
270 \li Font.AllLowercase - This alters the text to be rendered in all lowercase type.
271 \li Font.SmallCaps - This alters the text to be rendered in small-caps type.
272 \li Font.Capitalize - This alters the text to be rendered with the first character of each word as an uppercase character.
276 TextInput { text: "Hello"; font.capitalization: Font.AllLowercase }
280 QFont QQuickTextInput::font() const
282 Q_D(const QQuickTextInput);
283 return d->sourceFont;
286 void QQuickTextInput::setFont(const QFont &font)
288 Q_D(QQuickTextInput);
289 if (d->sourceFont == font)
292 d->sourceFont = font;
293 QFont oldFont = d->font;
295 if (d->font.pointSizeF() != -1) {
297 qreal size = qRound(d->font.pointSizeF()*2.0);
298 d->font.setPointSizeF(size/2.0);
300 if (oldFont != d->font) {
302 updateCursorRectangle();
303 updateInputMethod(Qt::ImCursorRectangle | Qt::ImFont);
305 emit fontChanged(d->sourceFont);
309 \qmlproperty color QtQuick2::TextInput::color
313 QColor QQuickTextInput::color() const
315 Q_D(const QQuickTextInput);
319 void QQuickTextInput::setColor(const QColor &c)
321 Q_D(QQuickTextInput);
324 d->textLayoutDirty = true;
325 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
333 \qmlproperty color QtQuick2::TextInput::selectionColor
335 The text highlight color, used behind selections.
337 QColor QQuickTextInput::selectionColor() const
339 Q_D(const QQuickTextInput);
340 return d->selectionColor;
343 void QQuickTextInput::setSelectionColor(const QColor &color)
345 Q_D(QQuickTextInput);
346 if (d->selectionColor == color)
349 d->selectionColor = color;
350 if (d->hasSelectedText()) {
351 d->textLayoutDirty = true;
352 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
355 emit selectionColorChanged();
358 \qmlproperty color QtQuick2::TextInput::selectedTextColor
360 The highlighted text color, used in selections.
362 QColor QQuickTextInput::selectedTextColor() const
364 Q_D(const QQuickTextInput);
365 return d->selectedTextColor;
368 void QQuickTextInput::setSelectedTextColor(const QColor &color)
370 Q_D(QQuickTextInput);
371 if (d->selectedTextColor == color)
374 d->selectedTextColor = color;
375 if (d->hasSelectedText()) {
376 d->textLayoutDirty = true;
377 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
380 emit selectedTextColorChanged();
384 \qmlproperty enumeration QtQuick2::TextInput::horizontalAlignment
385 \qmlproperty enumeration QtQuick2::TextInput::effectiveHorizontalAlignment
386 \qmlproperty enumeration QtQuick2::TextInput::verticalAlignment
388 Sets the horizontal alignment of the text within the TextInput item's
389 width and height. By default, the text alignment follows the natural alignment
390 of the text, for example text that is read from left to right will be aligned to
393 TextInput does not have vertical alignment, as the natural height is
394 exactly the height of the single line of text. If you set the height
395 manually to something larger, TextInput will always be top aligned
396 vertically. You can use anchors to align it however you want within
399 The valid values for \c horizontalAlignment are \c TextInput.AlignLeft, \c TextInput.AlignRight and
400 \c TextInput.AlignHCenter.
402 Valid values for \c verticalAlignment are \c TextInput.AlignTop (default),
403 \c TextInput.AlignBottom \c TextInput.AlignVCenter.
405 When using the attached property LayoutMirroring::enabled to mirror application
406 layouts, the horizontal alignment of text will also be mirrored. However, the property
407 \c horizontalAlignment will remain unchanged. To query the effective horizontal alignment
408 of TextInput, use the read-only property \c effectiveHorizontalAlignment.
410 QQuickTextInput::HAlignment QQuickTextInput::hAlign() const
412 Q_D(const QQuickTextInput);
416 void QQuickTextInput::setHAlign(HAlignment align)
418 Q_D(QQuickTextInput);
419 bool forceAlign = d->hAlignImplicit && d->effectiveLayoutMirror;
420 d->hAlignImplicit = false;
421 if (d->setHAlign(align, forceAlign) && isComponentComplete()) {
423 updateCursorRectangle();
427 void QQuickTextInput::resetHAlign()
429 Q_D(QQuickTextInput);
430 d->hAlignImplicit = true;
431 if (d->determineHorizontalAlignment() && isComponentComplete()) {
433 updateCursorRectangle();
437 QQuickTextInput::HAlignment QQuickTextInput::effectiveHAlign() const
439 Q_D(const QQuickTextInput);
440 QQuickTextInput::HAlignment effectiveAlignment = d->hAlign;
441 if (!d->hAlignImplicit && d->effectiveLayoutMirror) {
443 case QQuickTextInput::AlignLeft:
444 effectiveAlignment = QQuickTextInput::AlignRight;
446 case QQuickTextInput::AlignRight:
447 effectiveAlignment = QQuickTextInput::AlignLeft;
453 return effectiveAlignment;
456 bool QQuickTextInputPrivate::setHAlign(QQuickTextInput::HAlignment alignment, bool forceAlign)
458 Q_Q(QQuickTextInput);
459 if ((hAlign != alignment || forceAlign) && alignment <= QQuickTextInput::AlignHCenter) { // justify not supported
460 QQuickTextInput::HAlignment oldEffectiveHAlign = q->effectiveHAlign();
462 emit q->horizontalAlignmentChanged(alignment);
463 if (oldEffectiveHAlign != q->effectiveHAlign())
464 emit q->effectiveHorizontalAlignmentChanged();
470 bool QQuickTextInputPrivate::determineHorizontalAlignment()
472 if (hAlignImplicit) {
473 // if no explicit alignment has been set, follow the natural layout direction of the text
474 QString text = q_func()->text();
476 text = m_textLayout.preeditAreaText();
477 bool isRightToLeft = text.isEmpty() ? qApp->inputMethod()->inputDirection() == Qt::RightToLeft
478 : text.isRightToLeft();
479 return setHAlign(isRightToLeft ? QQuickTextInput::AlignRight : QQuickTextInput::AlignLeft);
484 QQuickTextInput::VAlignment QQuickTextInput::vAlign() const
486 Q_D(const QQuickTextInput);
490 void QQuickTextInput::setVAlign(QQuickTextInput::VAlignment alignment)
492 Q_D(QQuickTextInput);
493 if (alignment == d->vAlign)
495 d->vAlign = alignment;
496 emit verticalAlignmentChanged(d->vAlign);
497 if (isComponentComplete()) {
498 updateCursorRectangle();
503 \qmlproperty enumeration QtQuick2::TextInput::wrapMode
505 Set this property to wrap the text to the TextInput item's width.
506 The text will only wrap if an explicit width has been set.
509 \li TextInput.NoWrap - no wrapping will be performed. If the text contains insufficient newlines, then implicitWidth will exceed a set width.
510 \li TextInput.WordWrap - wrapping is done on word boundaries only. If a word is too long, implicitWidth will exceed a set width.
511 \li TextInput.WrapAnywhere - wrapping is done at any point on a line, even if it occurs in the middle of a word.
512 \li TextInput.Wrap - if possible, wrapping occurs at a word boundary; otherwise it will occur at the appropriate point on the line, even in the middle of a word.
515 The default is TextInput.NoWrap. If you set a width, consider using TextInput.Wrap.
517 QQuickTextInput::WrapMode QQuickTextInput::wrapMode() const
519 Q_D(const QQuickTextInput);
523 void QQuickTextInput::setWrapMode(WrapMode mode)
525 Q_D(QQuickTextInput);
526 if (mode == d->wrapMode)
530 updateCursorRectangle();
531 emit wrapModeChanged();
534 void QQuickTextInputPrivate::mirrorChange()
536 Q_Q(QQuickTextInput);
537 if (q->isComponentComplete()) {
538 if (!hAlignImplicit && (hAlign == QQuickTextInput::AlignRight || hAlign == QQuickTextInput::AlignLeft)) {
539 q->updateCursorRectangle();
540 emit q->effectiveHorizontalAlignmentChanged();
546 \qmlproperty bool QtQuick2::TextInput::readOnly
548 Sets whether user input can modify the contents of the TextInput.
550 If readOnly is set to true, then user input will not affect the text
551 property. Any bindings or attempts to set the text property will still
554 bool QQuickTextInput::isReadOnly() const
556 Q_D(const QQuickTextInput);
557 return d->m_readOnly;
560 void QQuickTextInput::setReadOnly(bool ro)
562 Q_D(QQuickTextInput);
563 if (d->m_readOnly == ro)
566 setFlag(QQuickItem::ItemAcceptsInputMethod, !ro);
569 d->setCursorPosition(d->end());
570 updateInputMethod(Qt::ImEnabled);
572 d->emitUndoRedoChanged();
573 emit readOnlyChanged(ro);
577 \qmlproperty int QtQuick2::TextInput::maximumLength
578 The maximum permitted length of the text in the TextInput.
580 If the text is too long, it is truncated at the limit.
582 By default, this property contains a value of 32767.
584 int QQuickTextInput::maxLength() const
586 Q_D(const QQuickTextInput);
587 return d->m_maxLength;
590 void QQuickTextInput::setMaxLength(int ml)
592 Q_D(QQuickTextInput);
593 if (d->m_maxLength == ml || d->m_maskData)
597 d->internalSetText(d->m_text, -1, false);
599 emit maximumLengthChanged(ml);
603 \qmlproperty bool QtQuick2::TextInput::cursorVisible
604 Set to true when the TextInput shows a cursor.
606 This property is set and unset when the TextInput gets active focus, so that other
607 properties can be bound to whether the cursor is currently showing. As it
608 gets set and unset automatically, when you set the value yourself you must
609 keep in mind that your value may be overwritten.
611 It can be set directly in script, for example if a KeyProxy might
612 forward keys to it and you desire it to look active when this happens
613 (but without actually giving it active focus).
615 It should not be set directly on the element, like in the below QML,
616 as the specified value will be overridden an lost on focus changes.
625 In the above snippet the cursor will still become visible when the
626 TextInput gains active focus.
628 bool QQuickTextInput::isCursorVisible() const
630 Q_D(const QQuickTextInput);
631 return d->cursorVisible;
634 void QQuickTextInput::setCursorVisible(bool on)
636 Q_D(QQuickTextInput);
637 if (d->cursorVisible == on)
639 d->cursorVisible = on;
640 d->setCursorBlinkPeriod(on ? qApp->styleHints()->cursorFlashTime() : 0);
641 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
643 emit cursorVisibleChanged(d->cursorVisible);
647 \qmlproperty int QtQuick2::TextInput::cursorPosition
648 The position of the cursor in the TextInput.
650 int QQuickTextInput::cursorPosition() const
652 Q_D(const QQuickTextInput);
656 void QQuickTextInput::setCursorPosition(int cp)
658 Q_D(QQuickTextInput);
659 if (cp < 0 || cp > text().length())
665 \qmlproperty rectangle QtQuick2::TextInput::cursorRectangle
667 The rectangle where the standard text cursor is rendered within the text input. Read only.
669 The position and height of a custom cursorDelegate are updated to follow the cursorRectangle
670 automatically when it changes. The width of the delegate is unaffected by changes in the
674 QRectF QQuickTextInput::cursorRectangle() const
676 Q_D(const QQuickTextInput);
678 int c = d->m_cursor + d->m_preeditCursor;
679 if (d->m_echoMode == NoEcho)
681 QTextLine l = d->m_textLayout.lineForTextPosition(c);
684 return QRectF(l.cursorToX(c) - d->hscroll, l.y() - d->vscroll, 1, l.height());
688 \qmlproperty int QtQuick2::TextInput::selectionStart
690 The cursor position before the first character in the current selection.
692 This property is read-only. To change the selection, use select(start,end),
693 selectAll(), or selectWord().
695 \sa selectionEnd, cursorPosition, selectedText
697 int QQuickTextInput::selectionStart() const
699 Q_D(const QQuickTextInput);
700 return d->lastSelectionStart;
703 \qmlproperty int QtQuick2::TextInput::selectionEnd
705 The cursor position after the last character in the current selection.
707 This property is read-only. To change the selection, use select(start,end),
708 selectAll(), or selectWord().
710 \sa selectionStart, cursorPosition, selectedText
712 int QQuickTextInput::selectionEnd() const
714 Q_D(const QQuickTextInput);
715 return d->lastSelectionEnd;
718 \qmlmethod void QtQuick2::TextInput::select(int start, int end)
720 Causes the text from \a start to \a end to be selected.
722 If either start or end is out of range, the selection is not changed.
724 After calling this, selectionStart will become the lesser
725 and selectionEnd will become the greater (regardless of the order passed
728 \sa selectionStart, selectionEnd
730 void QQuickTextInput::select(int start, int end)
732 Q_D(QQuickTextInput);
733 if (start < 0 || end < 0 || start > d->m_text.length() || end > d->m_text.length())
735 d->setSelection(start, end-start);
739 \qmlproperty string QtQuick2::TextInput::selectedText
741 This read-only property provides the text currently selected in the
744 It is equivalent to the following snippet, but is faster and easier
748 myTextInput.text.toString().substring(myTextInput.selectionStart,
749 myTextInput.selectionEnd);
752 QString QQuickTextInput::selectedText() const
754 Q_D(const QQuickTextInput);
755 return d->selectedText();
759 \qmlproperty bool QtQuick2::TextInput::activeFocusOnPress
761 Whether the TextInput should gain active focus on a mouse press. By default this is
764 bool QQuickTextInput::focusOnPress() const
766 Q_D(const QQuickTextInput);
767 return d->focusOnPress;
770 void QQuickTextInput::setFocusOnPress(bool b)
772 Q_D(QQuickTextInput);
773 if (d->focusOnPress == b)
778 emit activeFocusOnPressChanged(d->focusOnPress);
781 \qmlproperty bool QtQuick2::TextInput::autoScroll
783 Whether the TextInput should scroll when the text is longer than the width. By default this is
786 bool QQuickTextInput::autoScroll() const
788 Q_D(const QQuickTextInput);
789 return d->autoScroll;
792 void QQuickTextInput::setAutoScroll(bool b)
794 Q_D(QQuickTextInput);
795 if (d->autoScroll == b)
799 //We need to repaint so that the scrolling is taking into account.
800 updateCursorRectangle();
801 emit autoScrollChanged(d->autoScroll);
804 #ifndef QT_NO_VALIDATOR
807 \qmlclass IntValidator QIntValidator
808 \inqmlmodule QtQuick 2
809 \ingroup qml-basic-visual-elements
811 This element provides a validator for integer values.
813 If no \l locale is set IntValidator uses the \l {QLocale::setDefault()}{default locale} to
814 interpret the number and will accept locale specific digits, group separators, and positive
815 and negative signs. In addition, IntValidator is always guaranteed to accept a number
816 formatted according to the "C" locale.
820 QQuickIntValidator::QQuickIntValidator(QObject *parent)
821 : QIntValidator(parent)
826 \qmlproperty string QtQuick2::IntValidator::locale
828 This property holds the name of the locale used to interpret the number.
833 QString QQuickIntValidator::localeName() const
835 return locale().name();
838 void QQuickIntValidator::setLocaleName(const QString &name)
840 if (locale().name() != name) {
841 setLocale(QLocale(name));
842 emit localeNameChanged();
846 void QQuickIntValidator::resetLocaleName()
848 QLocale defaultLocale;
849 if (locale() != defaultLocale) {
850 setLocale(defaultLocale);
851 emit localeNameChanged();
856 \qmlproperty int QtQuick2::IntValidator::top
858 This property holds the validator's highest acceptable value.
859 By default, this property's value is derived from the highest signed integer available (typically 2147483647).
862 \qmlproperty int QtQuick2::IntValidator::bottom
864 This property holds the validator's lowest acceptable value.
865 By default, this property's value is derived from the lowest signed integer available (typically -2147483647).
869 \qmlclass DoubleValidator QDoubleValidator
870 \inqmlmodule QtQuick 2
871 \ingroup qml-basic-visual-elements
873 This element provides a validator for non-integer numbers.
875 Input is accepted if it contains a double that is within the valid range
876 and is in the correct format.
878 Input is accepected but invalid if it contains a double that is outside
879 the range or is in the wrong format; e.g. with too many digits after the
880 decimal point or is empty.
882 Input is rejected if it is not a double.
884 Note: If the valid range consists of just positive doubles (e.g. 0.0 to
885 100.0) and input is a negative double then it is rejected. If \l notation
886 is set to DoubleValidator.StandardNotation, and the input contains more
887 digits before the decimal point than a double in the valid range may have,
888 it is also rejected. If \l notation is DoubleValidator.ScientificNotation,
889 and the input is not in the valid range, it is accecpted but invalid. The
890 value may yet become valid by changing the exponent.
893 QQuickDoubleValidator::QQuickDoubleValidator(QObject *parent)
894 : QDoubleValidator(parent)
899 \qmlproperty string QtQuick2::DoubleValidator::locale
901 This property holds the name of the locale used to interpret the number.
906 QString QQuickDoubleValidator::localeName() const
908 return locale().name();
911 void QQuickDoubleValidator::setLocaleName(const QString &name)
913 if (locale().name() != name) {
914 setLocale(QLocale(name));
915 emit localeNameChanged();
919 void QQuickDoubleValidator::resetLocaleName()
921 QLocale defaultLocale;
922 if (locale() != defaultLocale) {
923 setLocale(defaultLocale);
924 emit localeNameChanged();
929 \qmlproperty real QtQuick2::DoubleValidator::top
931 This property holds the validator's maximum acceptable value.
932 By default, this property contains a value of infinity.
935 \qmlproperty real QtQuick2::DoubleValidator::bottom
937 This property holds the validator's minimum acceptable value.
938 By default, this property contains a value of -infinity.
941 \qmlproperty int QtQuick2::DoubleValidator::decimals
943 This property holds the validator's maximum number of digits after the decimal point.
944 By default, this property contains a value of 1000.
947 \qmlproperty enumeration QtQuick2::DoubleValidator::notation
948 This property holds the notation of how a string can describe a number.
950 The possible values for this property are:
953 \li DoubleValidator.StandardNotation
954 \li DoubleValidator.ScientificNotation (default)
957 If this property is set to DoubleValidator.ScientificNotation, the written number may have an exponent part (e.g. 1.5E-2).
961 \qmlclass RegExpValidator QRegExpValidator
962 \inqmlmodule QtQuick 2
963 \ingroup qml-basic-visual-elements
965 This element provides a validator, which counts as valid any string which
966 matches a specified regular expression.
969 \qmlproperty regExp QtQuick2::RegExpValidator::regExp
971 This property holds the regular expression used for validation.
973 Note that this property should be a regular expression in JS syntax, e.g /a/ for the regular expression
976 By default, this property contains a regular expression with the pattern .* that matches any string.
980 \qmlproperty Validator QtQuick2::TextInput::validator
982 Allows you to set a validator on the TextInput. When a validator is set
983 the TextInput will only accept input which leaves the text property in
984 an acceptable or intermediate state. The accepted signal will only be sent
985 if the text is in an acceptable state when enter is pressed.
987 Currently supported validators are IntValidator, DoubleValidator and
988 RegExpValidator. An example of using validators is shown below, which allows
989 input of integers between 11 and 31 into the text input:
994 validator: IntValidator{bottom: 11; top: 31;}
999 \sa acceptableInput, inputMask
1002 QValidator* QQuickTextInput::validator() const
1004 Q_D(const QQuickTextInput);
1005 return d->m_validator;
1008 void QQuickTextInput::setValidator(QValidator* v)
1010 Q_D(QQuickTextInput);
1011 if (d->m_validator == v)
1016 if (isComponentComplete())
1019 emit validatorChanged();
1022 #endif // QT_NO_VALIDATOR
1024 void QQuickTextInputPrivate::checkIsValid()
1026 Q_Q(QQuickTextInput);
1028 ValidatorState state = hasAcceptableInput(m_text);
1029 m_validInput = state != InvalidInput;
1030 if (state != AcceptableInput) {
1031 if (m_acceptableInput) {
1032 m_acceptableInput = false;
1033 emit q->acceptableInputChanged();
1035 } else if (!m_acceptableInput) {
1036 m_acceptableInput = true;
1037 emit q->acceptableInputChanged();
1042 \qmlproperty string QtQuick2::TextInput::inputMask
1044 Allows you to set an input mask on the TextInput, restricting the allowable
1045 text inputs. See QLineEdit::inputMask for further details, as the exact
1046 same mask strings are used by TextInput.
1048 \sa acceptableInput, validator
1050 QString QQuickTextInput::inputMask() const
1052 Q_D(const QQuickTextInput);
1053 return d->inputMask();
1056 void QQuickTextInput::setInputMask(const QString &im)
1058 Q_D(QQuickTextInput);
1059 if (d->inputMask() == im)
1062 d->setInputMask(im);
1063 emit inputMaskChanged(d->inputMask());
1067 \qmlproperty bool QtQuick2::TextInput::acceptableInput
1069 This property is always true unless a validator or input mask has been set.
1070 If a validator or input mask has been set, this property will only be true
1071 if the current text is acceptable to the validator or input mask as a final
1072 string (not as an intermediate string).
1074 bool QQuickTextInput::hasAcceptableInput() const
1076 Q_D(const QQuickTextInput);
1077 return d->hasAcceptableInput(d->m_text) == QQuickTextInputPrivate::AcceptableInput;
1081 \qmlsignal QtQuick2::TextInput::onAccepted()
1083 This handler is called when the Return or Enter key is pressed.
1084 Note that if there is a \l validator or \l inputMask set on the text
1085 input, the handler will only be emitted if the input is in an acceptable
1089 Qt::InputMethodHints QQuickTextInputPrivate::effectiveInputMethodHints() const
1091 Qt::InputMethodHints hints = inputMethodHints;
1092 if (m_echoMode == QQuickTextInput::Password || m_echoMode == QQuickTextInput::NoEcho)
1093 hints |= Qt::ImhHiddenText;
1094 else if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit)
1095 hints &= ~Qt::ImhHiddenText;
1096 if (m_echoMode != QQuickTextInput::Normal)
1097 hints |= (Qt::ImhNoAutoUppercase | Qt::ImhNoPredictiveText | Qt::ImhSensitiveData);
1101 \qmlproperty enumeration QtQuick2::TextInput::echoMode
1103 Specifies how the text should be displayed in the TextInput.
1105 \li TextInput.Normal - Displays the text as it is. (Default)
1106 \li TextInput.Password - Displays asterisks instead of characters.
1107 \li TextInput.NoEcho - Displays nothing.
1108 \li TextInput.PasswordEchoOnEdit - Displays characters as they are entered
1109 while editing, otherwise displays asterisks.
1112 QQuickTextInput::EchoMode QQuickTextInput::echoMode() const
1114 Q_D(const QQuickTextInput);
1115 return QQuickTextInput::EchoMode(d->m_echoMode);
1118 void QQuickTextInput::setEchoMode(QQuickTextInput::EchoMode echo)
1120 Q_D(QQuickTextInput);
1121 if (echoMode() == echo)
1123 d->cancelPasswordEchoTimer();
1124 d->m_echoMode = echo;
1125 d->m_passwordEchoEditing = false;
1126 updateInputMethod(Qt::ImHints);
1127 d->updateDisplayText();
1128 updateCursorRectangle();
1130 emit echoModeChanged(echoMode());
1134 \qmlproperty enumeration QtQuick2::TextInput::inputMethodHints
1136 Provides hints to the input method about the expected content of the text input and how it
1139 The value is a bit-wise combination of flags, or Qt.ImhNone if no hints are set.
1141 Flags that alter behaviour are:
1144 \li Qt.ImhHiddenText - Characters should be hidden, as is typically used when entering passwords.
1145 This is automatically set when setting echoMode to \c TextInput.Password.
1146 \li Qt.ImhSensitiveData - Typed text should not be stored by the active input method
1147 in any persistent storage like predictive user dictionary.
1148 \li Qt.ImhNoAutoUppercase - The input method should not try to automatically switch to upper case
1149 when a sentence ends.
1150 \li Qt.ImhPreferNumbers - Numbers are preferred (but not required).
1151 \li Qt.ImhPreferUppercase - Upper case letters are preferred (but not required).
1152 \li Qt.ImhPreferLowercase - Lower case letters are preferred (but not required).
1153 \li Qt.ImhNoPredictiveText - Do not use predictive text (i.e. dictionary lookup) while typing.
1155 \li Qt.ImhDate - The text editor functions as a date field.
1156 \li Qt.ImhTime - The text editor functions as a time field.
1159 Flags that restrict input (exclusive flags) are:
1162 \li Qt.ImhDigitsOnly - Only digits are allowed.
1163 \li Qt.ImhFormattedNumbersOnly - Only number input is allowed. This includes decimal point and minus sign.
1164 \li Qt.ImhUppercaseOnly - Only upper case letter input is allowed.
1165 \li Qt.ImhLowercaseOnly - Only lower case letter input is allowed.
1166 \li Qt.ImhDialableCharactersOnly - Only characters suitable for phone dialing are allowed.
1167 \li Qt.ImhEmailCharactersOnly - Only characters suitable for email addresses are allowed.
1168 \li Qt.ImhUrlCharactersOnly - Only characters suitable for URLs are allowed.
1174 \li Qt.ImhExclusiveInputMask - This mask yields nonzero if any of the exclusive flags are used.
1178 Qt::InputMethodHints QQuickTextInput::inputMethodHints() const
1180 Q_D(const QQuickTextInput);
1181 return d->inputMethodHints;
1184 void QQuickTextInput::setInputMethodHints(Qt::InputMethodHints hints)
1186 Q_D(QQuickTextInput);
1188 if (hints == d->inputMethodHints)
1191 d->inputMethodHints = hints;
1192 updateInputMethod(Qt::ImHints);
1193 emit inputMethodHintsChanged();
1197 \qmlproperty Component QtQuick2::TextInput::cursorDelegate
1198 The delegate for the cursor in the TextInput.
1200 If you set a cursorDelegate for a TextInput, this delegate will be used for
1201 drawing the cursor instead of the standard cursor. An instance of the
1202 delegate will be created and managed by the TextInput when a cursor is
1203 needed, and the x property of delegate instance will be set so as
1204 to be one pixel before the top left of the current character.
1206 Note that the root item of the delegate component must be a QQuickItem or
1207 QQuickItem derived item.
1209 QQmlComponent* QQuickTextInput::cursorDelegate() const
1211 Q_D(const QQuickTextInput);
1212 return d->cursorComponent;
1215 void QQuickTextInput::setCursorDelegate(QQmlComponent* c)
1217 Q_D(QQuickTextInput);
1218 if (d->cursorComponent == c)
1221 d->cursorComponent = c;
1223 //note that the components are owned by something else
1224 delete d->cursorItem;
1227 d->startCreatingCursor();
1230 emit cursorDelegateChanged();
1233 void QQuickTextInputPrivate::startCreatingCursor()
1235 Q_Q(QQuickTextInput);
1236 if (cursorComponent->isReady()) {
1238 } else if (cursorComponent->isLoading()) {
1239 q->connect(cursorComponent, SIGNAL(statusChanged(int)),
1240 q, SLOT(createCursor()));
1242 qmlInfo(q, cursorComponent->errors()) << QQuickTextInput::tr("Could not load cursor delegate");
1246 void QQuickTextInput::createCursor()
1248 Q_D(QQuickTextInput);
1249 if (!isComponentComplete())
1252 if (d->cursorComponent->isError()) {
1253 qmlInfo(this, d->cursorComponent->errors()) << tr("Could not load cursor delegate");
1257 if (!d->cursorComponent->isReady())
1261 delete d->cursorItem;
1262 QQmlContext *creationContext = d->cursorComponent->creationContext();
1263 QObject *object = d->cursorComponent->create(creationContext ? creationContext : qmlContext(this));
1264 d->cursorItem = qobject_cast<QQuickItem*>(object);
1265 if (!d->cursorItem) {
1267 qmlInfo(this, d->cursorComponent->errors()) << tr("Could not instantiate cursor delegate");
1271 QRectF r = cursorRectangle();
1273 QQml_setParent_noEvent(d->cursorItem, this);
1274 d->cursorItem->setParentItem(this);
1275 d->cursorItem->setPos(r.topLeft());
1276 d->cursorItem->setHeight(r.height());
1280 \qmlmethod rect QtQuick2::TextInput::positionToRectangle(int pos)
1282 This function takes a character position and returns the rectangle that the
1283 cursor would occupy, if it was placed at that character position.
1285 This is similar to setting the cursorPosition, and then querying the cursor
1286 rectangle, but the cursorPosition is not changed.
1288 QRectF QQuickTextInput::positionToRectangle(int pos) const
1290 Q_D(const QQuickTextInput);
1291 if (d->m_echoMode == NoEcho)
1293 else if (pos > d->m_cursor)
1294 pos += d->preeditAreaText().length();
1295 QTextLine l = d->m_textLayout.lineForTextPosition(pos);
1297 ? QRectF(l.cursorToX(pos) - d->hscroll, l.y() - d->vscroll, 1, l.height())
1302 \qmlmethod int QtQuick2::TextInput::positionAt(real x, real y, CursorPosition position = CursorBetweenCharacters)
1304 This function returns the character position at
1305 x and y pixels from the top left of the textInput. Position 0 is before the
1306 first character, position 1 is after the first character but before the second,
1307 and so on until position text.length, which is after all characters.
1309 This means that for all x values before the first character this function returns 0,
1310 and for all x values after the last character this function returns text.length. If
1311 the y value is above the text the position will be that of the nearest character on
1312 the first line line and if it is below the text the position of the nearest character
1313 on the last line will be returned.
1315 The cursor position type specifies how the cursor position should be resolved.
1318 \li TextInput.CursorBetweenCharacters - Returns the position between characters that is nearest x.
1319 \li TextInput.CursorOnCharacter - Returns the position before the character that is nearest x.
1323 void QQuickTextInput::positionAt(QQmlV8Function *args) const
1325 Q_D(const QQuickTextInput);
1329 QTextLine::CursorPosition position = QTextLine::CursorBetweenCharacters;
1331 if (args->Length() < 1)
1335 v8::Local<v8::Value> arg = (*args)[i];
1336 x = arg->NumberValue();
1338 if (++i < args->Length()) {
1340 y = arg->NumberValue();
1343 if (++i < args->Length()) {
1345 position = QTextLine::CursorPosition(arg->Int32Value());
1348 int pos = d->positionAt(x, y, position);
1349 const int cursor = d->m_cursor;
1351 const int preeditLength = d->preeditAreaText().length();
1352 pos = pos > cursor + preeditLength
1353 ? pos - preeditLength
1356 args->returnValue(v8::Int32::New(pos));
1359 int QQuickTextInputPrivate::positionAt(qreal x, qreal y, QTextLine::CursorPosition position) const
1363 QTextLine line = m_textLayout.lineAt(0);
1364 for (int i = 1; i < m_textLayout.lineCount(); ++i) {
1365 QTextLine nextLine = m_textLayout.lineAt(i);
1367 if (y < (line.rect().bottom() + nextLine.y()) / 2)
1371 return line.isValid() ? line.xToCursor(x, position) : 0;
1374 void QQuickTextInput::keyPressEvent(QKeyEvent* ev)
1376 Q_D(QQuickTextInput);
1377 // Don't allow MacOSX up/down support, and we don't allow a completer.
1378 bool ignore = (ev->key() == Qt::Key_Up || ev->key() == Qt::Key_Down) && ev->modifiers() == Qt::NoModifier;
1379 if (!ignore && (d->lastSelectionStart == d->lastSelectionEnd) && (ev->key() == Qt::Key_Right || ev->key() == Qt::Key_Left)) {
1380 // Ignore when moving off the end unless there is a selection,
1381 // because then moving will do something (deselect).
1382 int cursorPosition = d->m_cursor;
1383 if (cursorPosition == 0)
1384 ignore = ev->key() == (d->layoutDirection() == Qt::LeftToRight ? Qt::Key_Left : Qt::Key_Right);
1385 if (cursorPosition == text().length())
1386 ignore = ev->key() == (d->layoutDirection() == Qt::LeftToRight ? Qt::Key_Right : Qt::Key_Left);
1391 d->processKeyEvent(ev);
1393 if (!ev->isAccepted())
1394 QQuickImplicitSizeItem::keyPressEvent(ev);
1397 void QQuickTextInput::inputMethodEvent(QInputMethodEvent *ev)
1399 Q_D(QQuickTextInput);
1400 const bool wasComposing = d->hasImState;
1401 if (d->m_readOnly) {
1404 d->processInputMethodEvent(ev);
1406 if (!ev->isAccepted())
1407 QQuickImplicitSizeItem::inputMethodEvent(ev);
1409 if (wasComposing != d->hasImState)
1410 emit inputMethodComposingChanged();
1413 void QQuickTextInput::mouseDoubleClickEvent(QMouseEvent *event)
1415 Q_D(QQuickTextInput);
1417 if (d->selectByMouse && event->button() == Qt::LeftButton) {
1419 int cursor = d->positionAt(event->localPos());
1420 d->selectWordAtPos(cursor);
1421 event->setAccepted(true);
1422 if (!d->hasPendingTripleClick()) {
1423 d->tripleClickStartPoint = event->localPos();
1424 d->tripleClickTimer.start();
1427 if (d->sendMouseEventToInputContext(event))
1429 QQuickImplicitSizeItem::mouseDoubleClickEvent(event);
1433 void QQuickTextInput::mousePressEvent(QMouseEvent *event)
1435 Q_D(QQuickTextInput);
1437 d->pressPos = event->localPos();
1439 if (d->sendMouseEventToInputContext(event))
1442 if (d->selectByMouse) {
1443 setKeepMouseGrab(false);
1444 d->selectPressed = true;
1445 QPointF distanceVector = d->pressPos - d->tripleClickStartPoint;
1446 if (d->hasPendingTripleClick()
1447 && distanceVector.manhattanLength() < qApp->styleHints()->startDragDistance()) {
1448 event->setAccepted(true);
1454 bool mark = (event->modifiers() & Qt::ShiftModifier) && d->selectByMouse;
1455 int cursor = d->positionAt(event->localPos());
1456 d->moveCursor(cursor, mark);
1458 if (d->focusOnPress) {
1459 bool hadActiveFocus = hasActiveFocus();
1461 // re-open input panel on press if already focused
1462 if (hasActiveFocus() && hadActiveFocus && !d->m_readOnly)
1463 openSoftwareInputPanel();
1466 event->setAccepted(true);
1469 void QQuickTextInput::mouseMoveEvent(QMouseEvent *event)
1471 Q_D(QQuickTextInput);
1473 if (d->selectPressed) {
1474 if (qAbs(int(event->localPos().x() - d->pressPos.x())) > qApp->styleHints()->startDragDistance())
1475 setKeepMouseGrab(true);
1477 if (d->composeMode()) {
1479 int startPos = d->positionAt(d->pressPos);
1480 int currentPos = d->positionAt(event->localPos());
1481 if (startPos != currentPos)
1482 d->setSelection(startPos, currentPos - startPos);
1484 moveCursorSelection(d->positionAt(event->localPos()), d->mouseSelectionMode);
1486 event->setAccepted(true);
1488 QQuickImplicitSizeItem::mouseMoveEvent(event);
1492 void QQuickTextInput::mouseReleaseEvent(QMouseEvent *event)
1494 Q_D(QQuickTextInput);
1495 if (d->sendMouseEventToInputContext(event))
1497 if (d->selectPressed) {
1498 d->selectPressed = false;
1499 setKeepMouseGrab(false);
1501 #ifndef QT_NO_CLIPBOARD
1502 if (QGuiApplication::clipboard()->supportsSelection()) {
1503 if (event->button() == Qt::LeftButton) {
1504 d->copy(QClipboard::Selection);
1505 } else if (!d->m_readOnly && event->button() == Qt::MidButton) {
1507 d->insert(QGuiApplication::clipboard()->text(QClipboard::Selection));
1511 if (!event->isAccepted())
1512 QQuickImplicitSizeItem::mouseReleaseEvent(event);
1515 bool QQuickTextInputPrivate::sendMouseEventToInputContext(QMouseEvent *event)
1517 #if !defined QT_NO_IM
1518 if (composeMode()) {
1519 int tmp_cursor = positionAt(event->localPos());
1520 int mousePos = tmp_cursor - m_cursor;
1521 if (mousePos >= 0 && mousePos <= m_textLayout.preeditAreaText().length()) {
1522 if (event->type() == QEvent::MouseButtonRelease) {
1523 qApp->inputMethod()->invokeAction(QInputMethod::Click, mousePos);
1536 void QQuickTextInput::mouseUngrabEvent()
1538 Q_D(QQuickTextInput);
1539 d->selectPressed = false;
1540 setKeepMouseGrab(false);
1543 bool QQuickTextInput::event(QEvent* ev)
1545 #ifndef QT_NO_SHORTCUT
1546 Q_D(QQuickTextInput);
1547 if (ev->type() == QEvent::ShortcutOverride) {
1550 QKeyEvent* ke = static_cast<QKeyEvent*>(ev);
1551 if (ke == QKeySequence::Copy
1552 || ke == QKeySequence::Paste
1553 || ke == QKeySequence::Cut
1554 || ke == QKeySequence::Redo
1555 || ke == QKeySequence::Undo
1556 || ke == QKeySequence::MoveToNextWord
1557 || ke == QKeySequence::MoveToPreviousWord
1558 || ke == QKeySequence::MoveToStartOfDocument
1559 || ke == QKeySequence::MoveToEndOfDocument
1560 || ke == QKeySequence::SelectNextWord
1561 || ke == QKeySequence::SelectPreviousWord
1562 || ke == QKeySequence::SelectStartOfLine
1563 || ke == QKeySequence::SelectEndOfLine
1564 || ke == QKeySequence::SelectStartOfBlock
1565 || ke == QKeySequence::SelectEndOfBlock
1566 || ke == QKeySequence::SelectStartOfDocument
1567 || ke == QKeySequence::SelectAll
1568 || ke == QKeySequence::SelectEndOfDocument) {
1570 } else if (ke->modifiers() == Qt::NoModifier || ke->modifiers() == Qt::ShiftModifier
1571 || ke->modifiers() == Qt::KeypadModifier) {
1572 if (ke->key() < Qt::Key_Escape) {
1576 switch (ke->key()) {
1577 case Qt::Key_Delete:
1580 case Qt::Key_Backspace:
1592 return QQuickImplicitSizeItem::event(ev);
1595 void QQuickTextInput::geometryChanged(const QRectF &newGeometry,
1596 const QRectF &oldGeometry)
1598 Q_D(QQuickTextInput);
1600 if (newGeometry.width() != oldGeometry.width() && d->wrapMode != NoWrap)
1602 updateCursorRectangle();
1604 QQuickImplicitSizeItem::geometryChanged(newGeometry, oldGeometry);
1607 void QQuickTextInputPrivate::updateHorizontalScroll()
1609 Q_Q(QQuickTextInput);
1610 QTextLine currentLine = m_textLayout.lineForTextPosition(m_cursor + m_preeditCursor);
1611 const int preeditLength = m_textLayout.preeditAreaText().length();
1612 const qreal width = qMax<qreal>(0, q->width());
1614 qreal widthUsed = 0;
1615 if (currentLine.isValid()) {
1616 cix = currentLine.cursorToX(m_cursor + preeditLength);
1617 const qreal cursorWidth = cix >= 0 ? cix : width - cix;
1618 widthUsed = qMax(currentLine.naturalTextWidth(), cursorWidth);
1620 int previousScroll = hscroll;
1622 if (!autoScroll || widthUsed <= width || m_echoMode == QQuickTextInput::NoEcho) {
1625 Q_ASSERT(currentLine.isValid());
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;
1636 } else if (width - hscroll > widthUsed) {
1637 // text doesn't fit, text document is to the right of br; align
1639 hscroll = width - widthUsed;
1641 if (preeditLength > 0) {
1642 // check to ensure long pre-edit text doesn't push the cursor
1644 cix = currentLine.cursorToX(m_cursor + qMax(0, m_preeditCursor - 1));
1649 if (previousScroll != hscroll)
1650 textLayoutDirty = true;
1653 void QQuickTextInputPrivate::updateVerticalScroll()
1655 Q_Q(QQuickTextInput);
1656 const int preeditLength = m_textLayout.preeditAreaText().length();
1657 const qreal height = qMax<qreal>(0, q->height());
1658 qreal heightUsed = boundingRect.height();
1659 qreal previousScroll = vscroll;
1661 if (!autoScroll || heightUsed <= height) {
1662 // text fits in br; use vscroll for alignment
1663 switch (vAlign & ~(Qt::AlignAbsolute|Qt::AlignHorizontal_Mask)) {
1664 case Qt::AlignBottom:
1665 vscroll = heightUsed - height;
1667 case Qt::AlignVCenter:
1668 vscroll = (heightUsed - height) / 2;
1676 QTextLine currentLine = m_textLayout.lineForTextPosition(m_cursor + preeditLength);
1677 QRectF r = currentLine.isValid() ? currentLine.rect() : QRectF();
1678 qreal top = r.top();
1679 int bottom = r.bottom();
1681 if (bottom - vscroll >= height) {
1682 // text doesn't fit, cursor is to the below the br (scroll down)
1683 vscroll = bottom - height;
1684 } else if (top - vscroll < 0 && vscroll < heightUsed) {
1685 // text doesn't fit, cursor is above br (scroll up)
1687 } else if (heightUsed - vscroll < height) {
1688 // text doesn't fit, text document is to the left of br; align
1690 vscroll = heightUsed - height;
1692 if (preeditLength > 0) {
1693 // check to ensure long pre-edit text doesn't push the cursor
1695 currentLine = m_textLayout.lineForTextPosition(m_cursor + qMax(0, m_preeditCursor - 1));
1696 top = currentLine.isValid() ? currentLine.rect().top() : 0;
1701 if (previousScroll != vscroll)
1702 textLayoutDirty = true;
1705 void QQuickTextInput::triggerPreprocess()
1707 Q_D(QQuickTextInput);
1708 if (d->updateType == QQuickTextInputPrivate::UpdateNone)
1709 d->updateType = QQuickTextInputPrivate::UpdateOnlyPreprocess;
1713 QSGNode *QQuickTextInput::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data)
1716 Q_D(QQuickTextInput);
1718 if (d->updateType != QQuickTextInputPrivate::UpdatePaintNode && oldNode != 0) {
1719 // Update done in preprocess() in the nodes
1720 d->updateType = QQuickTextInputPrivate::UpdateNone;
1724 d->updateType = QQuickTextInputPrivate::UpdateNone;
1726 QQuickTextNode *node = static_cast<QQuickTextNode *>(oldNode);
1728 node = new QQuickTextNode(QQuickItemPrivate::get(this)->sceneGraphContext(), this);
1731 if (!d->textLayoutDirty) {
1732 QSGSimpleRectNode *cursorNode = node->cursorNode();
1733 if (cursorNode != 0 && !isReadOnly()) {
1734 cursorNode->setRect(cursorRectangle());
1736 if (!d->cursorVisible || (!d->m_blinkStatus && d->m_blinkPeriod > 0)) {
1743 node->deleteContent();
1744 node->setMatrix(QMatrix4x4());
1746 QPointF offset(0, 0);
1747 if (d->autoScroll && d->m_textLayout.lineCount() > 0) {
1748 QFontMetricsF fm(d->font);
1749 // the y offset is there to keep the baseline constant in case we have script changes in the text.
1750 offset = -QPoint(d->hscroll, d->vscroll + d->m_textLayout.lineAt(0).ascent() - fm.ascent());
1752 offset = -QPoint(d->hscroll, d->vscroll);
1755 if (!d->m_textLayout.text().isEmpty() || !d->m_textLayout.preeditAreaText().isEmpty()) {
1756 node->addTextLayout(offset, &d->m_textLayout, d->color,
1757 QQuickText::Normal, QColor(), QColor(),
1758 d->selectionColor, d->selectedTextColor,
1759 d->selectionStart(),
1760 d->selectionEnd() - 1); // selectionEnd() returns first char after
1764 if (!isReadOnly() && d->cursorItem == 0) {
1765 node->setCursor(cursorRectangle(), d->color);
1766 if (!d->cursorVisible || (!d->m_blinkStatus && d->m_blinkPeriod > 0)) {
1773 d->textLayoutDirty = false;
1779 QVariant QQuickTextInput::inputMethodQuery(Qt::InputMethodQuery property) const
1781 Q_D(const QQuickTextInput);
1784 return QVariant((bool)(flags() & ItemAcceptsInputMethod));
1786 return QVariant((int) d->effectiveInputMethodHints());
1787 case Qt::ImCursorRectangle:
1788 return cursorRectangle();
1791 case Qt::ImCursorPosition:
1792 return QVariant(d->m_cursor);
1793 case Qt::ImSurroundingText:
1794 if (d->m_echoMode == PasswordEchoOnEdit && !d->m_passwordEchoEditing) {
1795 return QVariant(displayText());
1797 return QVariant(d->realText());
1799 case Qt::ImCurrentSelection:
1800 return QVariant(selectedText());
1801 case Qt::ImMaximumTextLength:
1802 return QVariant(maxLength());
1803 case Qt::ImAnchorPosition:
1804 if (d->selectionStart() == d->selectionEnd())
1805 return QVariant(d->m_cursor);
1806 else if (d->selectionStart() == d->m_cursor)
1807 return QVariant(d->selectionEnd());
1809 return QVariant(d->selectionStart());
1816 \qmlmethod void QtQuick2::TextInput::deselect()
1818 Removes active text selection.
1820 void QQuickTextInput::deselect()
1822 Q_D(QQuickTextInput);
1827 \qmlmethod void QtQuick2::TextInput::selectAll()
1829 Causes all text to be selected.
1831 void QQuickTextInput::selectAll()
1833 Q_D(QQuickTextInput);
1834 d->setSelection(0, text().length());
1838 \qmlmethod void QtQuick2::TextInput::isRightToLeft(int start, int end)
1840 Returns true if the natural reading direction of the editor text
1841 found between positions \a start and \a end is right to left.
1843 bool QQuickTextInput::isRightToLeft(int start, int end)
1846 qmlInfo(this) << "isRightToLeft(start, end) called with the end property being smaller than the start.";
1849 return text().mid(start, end - start).isRightToLeft();
1853 #ifndef QT_NO_CLIPBOARD
1855 \qmlmethod QtQuick2::TextInput::cut()
1857 Moves the currently selected text to the system clipboard.
1859 void QQuickTextInput::cut()
1861 Q_D(QQuickTextInput);
1867 \qmlmethod QtQuick2::TextInput::copy()
1869 Copies the currently selected text to the system clipboard.
1871 void QQuickTextInput::copy()
1873 Q_D(QQuickTextInput);
1878 \qmlmethod QtQuick2::TextInput::paste()
1880 Replaces the currently selected text by the contents of the system clipboard.
1882 void QQuickTextInput::paste()
1884 Q_D(QQuickTextInput);
1888 #endif // QT_NO_CLIPBOARD
1891 Undoes the last operation if undo is \l {canUndo}{available}. Deselects any
1892 current selection, and updates the selection start to the current cursor
1896 void QQuickTextInput::undo()
1898 Q_D(QQuickTextInput);
1899 if (!d->m_readOnly) {
1901 d->finishChange(-1, true);
1906 Redoes the last operation if redo is \l {canRedo}{available}.
1909 void QQuickTextInput::redo()
1911 Q_D(QQuickTextInput);
1912 if (!d->m_readOnly) {
1919 \qmlmethod void QtQuick2::TextInput::insert(int position, string text)
1921 Inserts \a text into the TextInput at position.
1924 void QQuickTextInput::insert(int position, const QString &text)
1926 Q_D(QQuickTextInput);
1927 if (d->m_echoMode == QQuickTextInput::Password) {
1928 int delay = qGuiApp->styleHints()->passwordMaskDelay();
1930 d->m_passwordEchoTimer.start(delay, this);
1932 if (position < 0 || position > d->m_text.length())
1935 const int priorState = d->m_undoState;
1937 QString insertText = text;
1939 if (d->hasSelectedText()) {
1940 d->addCommand(QQuickTextInputPrivate::Command(
1941 QQuickTextInputPrivate::SetSelection, d->m_cursor, 0, d->m_selstart, d->m_selend));
1943 if (d->m_maskData) {
1944 insertText = d->maskString(position, insertText);
1945 for (int i = 0; i < insertText.length(); ++i) {
1946 d->addCommand(QQuickTextInputPrivate::Command(
1947 QQuickTextInputPrivate::DeleteSelection, position + i, d->m_text.at(position + i), -1, -1));
1948 d->addCommand(QQuickTextInputPrivate::Command(
1949 QQuickTextInputPrivate::Insert, position + i, insertText.at(i), -1, -1));
1951 d->m_text.replace(position, insertText.length(), insertText);
1952 if (!insertText.isEmpty())
1953 d->m_textDirty = true;
1954 if (position < d->m_selend && position + insertText.length() > d->m_selstart)
1955 d->m_selDirty = true;
1957 int remaining = d->m_maxLength - d->m_text.length();
1958 if (remaining != 0) {
1959 insertText = insertText.left(remaining);
1960 d->m_text.insert(position, insertText);
1961 for (int i = 0; i < insertText.length(); ++i)
1962 d->addCommand(QQuickTextInputPrivate::Command(
1963 QQuickTextInputPrivate::Insert, position + i, insertText.at(i), -1, -1));
1964 if (d->m_cursor >= position)
1965 d->m_cursor += insertText.length();
1966 if (d->m_selstart >= position)
1967 d->m_selstart += insertText.length();
1968 if (d->m_selend >= position)
1969 d->m_selend += insertText.length();
1970 d->m_textDirty = true;
1971 if (position >= d->m_selstart && position <= d->m_selend)
1972 d->m_selDirty = true;
1976 d->addCommand(QQuickTextInputPrivate::Command(
1977 QQuickTextInputPrivate::SetSelection, d->m_cursor, 0, d->m_selstart, d->m_selend));
1978 d->finishChange(priorState);
1980 if (d->lastSelectionStart != d->lastSelectionEnd) {
1981 if (d->m_selstart != d->lastSelectionStart) {
1982 d->lastSelectionStart = d->m_selstart;
1983 emit selectionStartChanged();
1985 if (d->m_selend != d->lastSelectionEnd) {
1986 d->lastSelectionEnd = d->m_selend;
1987 emit selectionEndChanged();
1993 \qmlmethod string QtQuick2::TextInput::getText(int start, int end)
1995 Removes the section of text that is between the \a start and \a end positions from the TextInput.
1998 void QQuickTextInput::remove(int start, int end)
2000 Q_D(QQuickTextInput);
2002 start = qBound(0, start, d->m_text.length());
2003 end = qBound(0, end, d->m_text.length());
2007 else if (start == end)
2010 if (start < d->m_selend && end > d->m_selstart)
2011 d->m_selDirty = true;
2013 const int priorState = d->m_undoState;
2015 d->addCommand(QQuickTextInputPrivate::Command(
2016 QQuickTextInputPrivate::SetSelection, d->m_cursor, 0, d->m_selstart, d->m_selend));
2018 if (start <= d->m_cursor && d->m_cursor < end) {
2019 // cursor is within the selection. Split up the commands
2020 // to be able to restore the correct cursor position
2021 for (int i = d->m_cursor; i >= start; --i) {
2022 d->addCommand(QQuickTextInputPrivate::Command(
2023 QQuickTextInputPrivate::DeleteSelection, i, d->m_text.at(i), -1, 1));
2025 for (int i = end - 1; i > d->m_cursor; --i) {
2026 d->addCommand(QQuickTextInputPrivate::Command(
2027 QQuickTextInputPrivate::DeleteSelection, i - d->m_cursor + start - 1, d->m_text.at(i), -1, -1));
2030 for (int i = end - 1; i >= start; --i) {
2031 d->addCommand(QQuickTextInputPrivate::Command(
2032 QQuickTextInputPrivate::RemoveSelection, i, d->m_text.at(i), -1, -1));
2035 if (d->m_maskData) {
2036 d->m_text.replace(start, end - start, d->clearString(start, end - start));
2037 for (int i = 0; i < end - start; ++i) {
2038 d->addCommand(QQuickTextInputPrivate::Command(
2039 QQuickTextInputPrivate::Insert, start + i, d->m_text.at(start + i), -1, -1));
2042 d->m_text.remove(start, end - start);
2044 if (d->m_cursor > start)
2045 d->m_cursor -= qMin(d->m_cursor, end) - start;
2046 if (d->m_selstart > start)
2047 d->m_selstart -= qMin(d->m_selstart, end) - start;
2048 if (d->m_selend > end)
2049 d->m_selend -= qMin(d->m_selend, end) - start;
2051 d->addCommand(QQuickTextInputPrivate::Command(
2052 QQuickTextInputPrivate::SetSelection, d->m_cursor, 0, d->m_selstart, d->m_selend));
2054 d->m_textDirty = true;
2055 d->finishChange(priorState);
2057 if (d->lastSelectionStart != d->lastSelectionEnd) {
2058 if (d->m_selstart != d->lastSelectionStart) {
2059 d->lastSelectionStart = d->m_selstart;
2060 emit selectionStartChanged();
2062 if (d->m_selend != d->lastSelectionEnd) {
2063 d->lastSelectionEnd = d->m_selend;
2064 emit selectionEndChanged();
2071 \qmlmethod void QtQuick2::TextInput::selectWord()
2073 Causes the word closest to the current cursor position to be selected.
2075 void QQuickTextInput::selectWord()
2077 Q_D(QQuickTextInput);
2078 d->selectWordAtPos(d->m_cursor);
2082 \qmlproperty bool QtQuick2::TextInput::smooth
2084 This property holds whether the text is smoothly scaled or transformed.
2086 Smooth filtering gives better visual quality, but is slower. If
2087 the item is displayed at its natural size, this property has no visual or
2090 \note Generally scaling artifacts are only visible if the item is stationary on
2091 the screen. A common pattern when animating an item is to disable smooth
2092 filtering at the beginning of the animation and reenable it at the conclusion.
2096 \qmlproperty string QtQuick2::TextInput::passwordCharacter
2098 This is the character displayed when echoMode is set to Password or
2099 PasswordEchoOnEdit. By default it is an asterisk.
2101 If this property is set to a string with more than one character,
2102 the first character is used. If the string is empty, the value
2103 is ignored and the property is not set.
2105 QString QQuickTextInput::passwordCharacter() const
2107 Q_D(const QQuickTextInput);
2108 return QString(d->m_passwordCharacter);
2111 void QQuickTextInput::setPasswordCharacter(const QString &str)
2113 Q_D(QQuickTextInput);
2114 if (str.length() < 1)
2116 d->m_passwordCharacter = str.constData()[0];
2117 if (d->m_echoMode == Password || d->m_echoMode == PasswordEchoOnEdit)
2118 d->updateDisplayText();
2119 emit passwordCharacterChanged();
2123 \qmlproperty string QtQuick2::TextInput::displayText
2125 This is the text displayed in the TextInput.
2127 If \l echoMode is set to TextInput::Normal, this holds the
2128 same value as the TextInput::text property. Otherwise,
2129 this property holds the text visible to the user, while
2130 the \l text property holds the actual entered text.
2132 QString QQuickTextInput::displayText() const
2134 Q_D(const QQuickTextInput);
2135 return d->m_textLayout.text();
2139 \qmlproperty bool QtQuick2::TextInput::selectByMouse
2143 If true, the user can use the mouse to select text in some
2144 platform-specific way. Note that for some platforms this may
2145 not be an appropriate interaction (eg. may conflict with how
2146 the text needs to behave inside a Flickable.
2148 bool QQuickTextInput::selectByMouse() const
2150 Q_D(const QQuickTextInput);
2151 return d->selectByMouse;
2154 void QQuickTextInput::setSelectByMouse(bool on)
2156 Q_D(QQuickTextInput);
2157 if (d->selectByMouse != on) {
2158 d->selectByMouse = on;
2159 emit selectByMouseChanged(on);
2164 \qmlproperty enum QtQuick2::TextInput::mouseSelectionMode
2166 Specifies how text should be selected using a mouse.
2169 \li TextInput.SelectCharacters - The selection is updated with individual characters. (Default)
2170 \li TextInput.SelectWords - The selection is updated with whole words.
2173 This property only applies when \l selectByMouse is true.
2176 QQuickTextInput::SelectionMode QQuickTextInput::mouseSelectionMode() const
2178 Q_D(const QQuickTextInput);
2179 return d->mouseSelectionMode;
2182 void QQuickTextInput::setMouseSelectionMode(SelectionMode mode)
2184 Q_D(QQuickTextInput);
2185 if (d->mouseSelectionMode != mode) {
2186 d->mouseSelectionMode = mode;
2187 emit mouseSelectionModeChanged(mode);
2192 \qmlproperty bool QtQuick2::TextInput::persistentSelection
2194 Whether the TextInput should keep its selection when it loses active focus to another
2195 item in the scene. By default this is set to false;
2198 bool QQuickTextInput::persistentSelection() const
2200 Q_D(const QQuickTextInput);
2201 return d->persistentSelection;
2204 void QQuickTextInput::setPersistentSelection(bool on)
2206 Q_D(QQuickTextInput);
2207 if (d->persistentSelection == on)
2209 d->persistentSelection = on;
2210 emit persistentSelectionChanged();
2213 #ifndef QT_NO_CLIPBOARD
2215 \qmlproperty bool QtQuick2::TextInput::canPaste
2217 Returns true if the TextInput is writable and the content of the clipboard is
2218 suitable for pasting into the TextInput.
2220 bool QQuickTextInput::canPaste() const
2222 Q_D(const QQuickTextInput);
2223 if (!d->canPasteValid) {
2224 if (const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData())
2225 const_cast<QQuickTextInputPrivate *>(d)->canPaste = !d->m_readOnly && mimeData->hasText();
2226 const_cast<QQuickTextInputPrivate *>(d)->canPasteValid = true;
2233 \qmlproperty bool QtQuick2::TextInput::canUndo
2235 Returns true if the TextInput is writable and there are previous operations
2239 bool QQuickTextInput::canUndo() const
2241 Q_D(const QQuickTextInput);
2246 \qmlproperty bool QtQuick2::TextInput::canRedo
2248 Returns true if the TextInput is writable and there are \l {undo}{undone}
2249 operations that can be redone.
2252 bool QQuickTextInput::canRedo() const
2254 Q_D(const QQuickTextInput);
2259 \qmlproperty real QtQuick2::TextInput::contentWidth
2261 Returns the width of the text, including the width past the width
2262 which is covered due to insufficient wrapping if \l wrapMode is set.
2265 qreal QQuickTextInput::contentWidth() const
2267 Q_D(const QQuickTextInput);
2268 return d->boundingRect.width();
2272 \qmlproperty real QtQuick2::TextInput::contentHeight
2274 Returns the height of the text, including the height past the height
2275 that is covered if the text does not fit within the set height.
2278 qreal QQuickTextInput::contentHeight() const
2280 Q_D(const QQuickTextInput);
2281 return d->boundingRect.height();
2284 void QQuickTextInput::moveCursorSelection(int position)
2286 Q_D(QQuickTextInput);
2287 d->moveCursor(position, true);
2291 \qmlmethod void QtQuick2::TextInput::moveCursorSelection(int position, SelectionMode mode = TextInput.SelectCharacters)
2293 Moves the cursor to \a position and updates the selection according to the optional \a mode
2294 parameter. (To only move the cursor, set the \l cursorPosition property.)
2296 When this method is called it additionally sets either the
2297 selectionStart or the selectionEnd (whichever was at the previous cursor position)
2298 to the specified position. This allows you to easily extend and contract the selected
2301 The selection mode specifies whether the selection is updated on a per character or a per word
2302 basis. If not specified the selection mode will default to TextInput.SelectCharacters.
2305 \li TextInput.SelectCharacters - Sets either the selectionStart or selectionEnd (whichever was at
2306 the previous cursor position) to the specified position.
2307 \li TextInput.SelectWords - Sets the selectionStart and selectionEnd to include all
2308 words between the specified position and the previous cursor position. Words partially in the
2312 For example, take this sequence of calls:
2316 moveCursorSelection(9, TextInput.SelectCharacters)
2317 moveCursorSelection(7, TextInput.SelectCharacters)
2320 This moves the cursor to position 5, extend the selection end from 5 to 9
2321 and then retract the selection end from 9 to 7, leaving the text from position 5 to 7
2322 selected (the 6th and 7th characters).
2324 The same sequence with TextInput.SelectWords will extend the selection start to a word boundary
2325 before or on position 5 and extend the selection end to a word boundary on or past position 9.
2327 void QQuickTextInput::moveCursorSelection(int pos, SelectionMode mode)
2329 Q_D(QQuickTextInput);
2331 if (mode == SelectCharacters) {
2332 d->moveCursor(pos, true);
2333 } else if (pos != d->m_cursor){
2334 const int cursor = d->m_cursor;
2336 if (!d->hasSelectedText())
2337 anchor = d->m_cursor;
2338 else if (d->selectionStart() == d->m_cursor)
2339 anchor = d->selectionEnd();
2341 anchor = d->selectionStart();
2343 if (anchor < pos || (anchor == pos && cursor < pos)) {
2344 const QString text = this->text();
2345 QTextBoundaryFinder finder(QTextBoundaryFinder::Word, text);
2346 finder.setPosition(anchor);
2348 const QTextBoundaryFinder::BoundaryReasons reasons = finder.boundaryReasons();
2349 if (anchor < text.length() && (!(reasons & QTextBoundaryFinder::StartWord)
2350 || ((reasons & QTextBoundaryFinder::EndWord) && anchor > cursor))) {
2351 finder.toPreviousBoundary();
2353 anchor = finder.position() != -1 ? finder.position() : 0;
2355 finder.setPosition(pos);
2356 if (pos > 0 && !finder.boundaryReasons())
2357 finder.toNextBoundary();
2358 const int cursor = finder.position() != -1 ? finder.position() : text.length();
2360 d->setSelection(anchor, cursor - anchor);
2361 } else if (anchor > pos || (anchor == pos && cursor > pos)) {
2362 const QString text = this->text();
2363 QTextBoundaryFinder finder(QTextBoundaryFinder::Word, text);
2364 finder.setPosition(anchor);
2366 const QTextBoundaryFinder::BoundaryReasons reasons = finder.boundaryReasons();
2367 if (anchor > 0 && (!(reasons & QTextBoundaryFinder::EndWord)
2368 || ((reasons & QTextBoundaryFinder::StartWord) && anchor < cursor))) {
2369 finder.toNextBoundary();
2372 anchor = finder.position() != -1 ? finder.position() : text.length();
2374 finder.setPosition(pos);
2375 if (pos < text.length() && !finder.boundaryReasons())
2376 finder.toPreviousBoundary();
2377 const int cursor = finder.position() != -1 ? finder.position() : 0;
2379 d->setSelection(anchor, cursor - anchor);
2385 \qmlmethod void QtQuick2::TextInput::openSoftwareInputPanel()
2387 Opens software input panels like virtual keyboards for typing, useful for
2388 customizing when you want the input keyboard to be shown and hidden in
2391 By default the opening of input panels follows the platform style. Input panels are
2392 always closed if no editor has active focus.
2394 You can disable the automatic behavior by setting the property \c activeFocusOnPress to false
2395 and use functions openSoftwareInputPanel() and closeSoftwareInputPanel() to implement
2396 the behavior you want.
2398 Only relevant on platforms, which provide virtual keyboards.
2404 text: "Hello world!"
2405 activeFocusOnPress: false
2407 anchors.fill: parent
2409 if (!textInput.activeFocus) {
2410 textInput.forceActiveFocus()
2411 textInput.openSoftwareInputPanel();
2413 textInput.focus = false;
2416 onPressAndHold: textInput.closeSoftwareInputPanel();
2421 void QQuickTextInput::openSoftwareInputPanel()
2424 qGuiApp->inputMethod()->show();
2428 \qmlmethod void QtQuick2::TextInput::closeSoftwareInputPanel()
2430 Closes a software input panel like a virtual keyboard shown on the screen, useful
2431 for customizing when you want the input keyboard to be shown and hidden in
2434 By default the opening of input panels follows the platform style. Input panels are
2435 always closed if no editor has active focus.
2437 You can disable the automatic behavior by setting the property \c activeFocusOnPress to false
2438 and use functions openSoftwareInputPanel() and closeSoftwareInputPanel() to implement
2439 the behavior you want.
2441 Only relevant on platforms, which provide virtual keyboards.
2447 text: "Hello world!"
2448 activeFocusOnPress: false
2450 anchors.fill: parent
2452 if (!textInput.activeFocus) {
2453 textInput.forceActiveFocus();
2454 textInput.openSoftwareInputPanel();
2456 textInput.focus = false;
2459 onPressAndHold: textInput.closeSoftwareInputPanel();
2464 void QQuickTextInput::closeSoftwareInputPanel()
2467 qGuiApp->inputMethod()->hide();
2470 void QQuickTextInput::focusInEvent(QFocusEvent *event)
2472 Q_D(const QQuickTextInput);
2473 if (d->focusOnPress && !d->m_readOnly)
2474 openSoftwareInputPanel();
2475 QQuickImplicitSizeItem::focusInEvent(event);
2478 void QQuickTextInput::itemChange(ItemChange change, const ItemChangeData &value)
2480 Q_D(QQuickTextInput);
2481 if (change == ItemActiveFocusHasChanged) {
2482 bool hasFocus = value.boolValue;
2483 setCursorVisible(hasFocus); // ### refactor: && d->canvas && d->canvas->hasFocus()
2484 if (!hasFocus && (d->m_passwordEchoEditing || d->m_passwordEchoTimer.isActive())) {
2485 d->updatePasswordEchoEditing(false);//QQuickTextInputPrivate sets it on key events, but doesn't deal with focus events
2489 if (!d->persistentSelection)
2491 disconnect(qApp->inputMethod(), SIGNAL(inputDirectionChanged(Qt::LayoutDirection)),
2492 this, SLOT(q_updateAlignment()));
2494 q_updateAlignment();
2495 connect(qApp->inputMethod(), SIGNAL(inputDirectionChanged(Qt::LayoutDirection)),
2496 this, SLOT(q_updateAlignment()));
2499 QQuickItem::itemChange(change, value);
2503 \qmlproperty bool QtQuick2::TextInput::inputMethodComposing
2506 This property holds whether the TextInput has partial text input from an
2509 While it is composing an input method may rely on mouse or key events from
2510 the TextInput to edit or commit the partial text. This property can be
2511 used to determine when to disable events handlers that may interfere with
2512 the correct operation of an input method.
2514 bool QQuickTextInput::isInputMethodComposing() const
2516 Q_D(const QQuickTextInput);
2517 return d->hasImState;
2520 void QQuickTextInputPrivate::init()
2522 Q_Q(QQuickTextInput);
2523 q->setSmooth(smooth);
2524 q->setAcceptedMouseButtons(Qt::LeftButton);
2525 q->setFlag(QQuickItem::ItemAcceptsInputMethod);
2526 q->setFlag(QQuickItem::ItemHasContents);
2527 #ifndef QT_NO_CLIPBOARD
2528 q->connect(QGuiApplication::clipboard(), SIGNAL(dataChanged()),
2529 q, SLOT(q_canPasteChanged()));
2530 #endif // QT_NO_CLIPBOARD
2532 lastSelectionStart = 0;
2533 lastSelectionEnd = 0;
2534 determineHorizontalAlignment();
2536 if (!qmlDisableDistanceField()) {
2537 QTextOption option = m_textLayout.textOption();
2538 option.setUseDesignMetrics(true);
2539 m_textLayout.setTextOption(option);
2543 void QQuickTextInput::updateCursorRectangle()
2545 Q_D(QQuickTextInput);
2546 if (!isComponentComplete())
2549 d->updateHorizontalScroll();
2550 d->updateVerticalScroll();
2551 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
2553 emit cursorRectangleChanged();
2554 if (d->cursorItem) {
2555 QRectF r = cursorRectangle();
2556 d->cursorItem->setPos(r.topLeft());
2557 d->cursorItem->setHeight(r.height());
2559 updateInputMethod(Qt::ImCursorRectangle);
2562 void QQuickTextInput::selectionChanged()
2564 Q_D(QQuickTextInput);
2565 d->textLayoutDirty = true; //TODO: Only update rect in selection
2566 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
2568 emit selectedTextChanged();
2570 if (d->lastSelectionStart != d->selectionStart()) {
2571 d->lastSelectionStart = d->selectionStart();
2572 if (d->lastSelectionStart == -1)
2573 d->lastSelectionStart = d->m_cursor;
2574 emit selectionStartChanged();
2576 if (d->lastSelectionEnd != d->selectionEnd()) {
2577 d->lastSelectionEnd = d->selectionEnd();
2578 if (d->lastSelectionEnd == -1)
2579 d->lastSelectionEnd = d->m_cursor;
2580 emit selectionEndChanged();
2584 void QQuickTextInputPrivate::showCursor()
2586 if (textNode != 0 && textNode->cursorNode() != 0)
2587 textNode->cursorNode()->setColor(color);
2590 void QQuickTextInputPrivate::hideCursor()
2592 if (textNode != 0 && textNode->cursorNode() != 0)
2593 textNode->cursorNode()->setColor(QColor(0, 0, 0, 0));
2596 QRectF QQuickTextInput::boundingRect() const
2598 Q_D(const QQuickTextInput);
2600 int cursorWidth = d->cursorItem ? d->cursorItem->width() : 1;
2602 // Could include font max left/right bearings to either side of rectangle.
2603 QRectF r = QQuickImplicitSizeItem::boundingRect();
2604 r.setRight(r.right() + cursorWidth);
2608 void QQuickTextInput::q_canPasteChanged()
2610 Q_D(QQuickTextInput);
2611 bool old = d->canPaste;
2612 #ifndef QT_NO_CLIPBOARD
2613 if (const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData())
2614 d->canPaste = !d->m_readOnly && mimeData->hasText();
2616 d->canPaste = false;
2619 bool changed = d->canPaste != old || !d->canPasteValid;
2620 d->canPasteValid = true;
2622 emit canPasteChanged();
2626 void QQuickTextInput::q_updateAlignment()
2628 Q_D(QQuickTextInput);
2629 if (d->determineHorizontalAlignment()) {
2631 updateCursorRectangle();
2635 // ### these should come from QStyleHints
2636 const int textCursorWidth = 1;
2637 const bool fullWidthSelection = true;
2642 Updates the display text based of the current edit text
2643 If the text has changed will emit displayTextChanged()
2645 void QQuickTextInputPrivate::updateDisplayText(bool forceUpdate)
2647 QString orig = m_textLayout.text();
2649 if (m_echoMode == QQuickTextInput::NoEcho)
2650 str = QString::fromLatin1("");
2654 if (m_echoMode == QQuickTextInput::Password) {
2655 str.fill(m_passwordCharacter);
2656 if (m_passwordEchoTimer.isActive() && m_cursor > 0 && m_cursor <= m_text.length()) {
2657 int cursor = m_cursor - 1;
2658 QChar uc = m_text.at(cursor);
2660 if (cursor > 0 && uc.unicode() >= 0xdc00 && uc.unicode() < 0xe000) {
2661 // second half of a surrogate, check if we have the first half as well,
2662 // if yes restore both at once
2663 uc = m_text.at(cursor - 1);
2664 if (uc.unicode() >= 0xd800 && uc.unicode() < 0xdc00)
2665 str[cursor - 1] = uc;
2668 } else if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit && !m_passwordEchoEditing) {
2669 str.fill(m_passwordCharacter);
2672 // replace certain non-printable characters with spaces (to avoid
2673 // drawing boxes when using fonts that don't have glyphs for such
2675 QChar* uc = str.data();
2676 for (int i = 0; i < (int)str.length(); ++i) {
2677 if ((uc[i] < 0x20 && uc[i] != 0x09)
2678 || uc[i] == QChar::LineSeparator
2679 || uc[i] == QChar::ParagraphSeparator
2680 || uc[i] == QChar::ObjectReplacementCharacter)
2681 uc[i] = QChar(0x0020);
2684 if (str != orig || forceUpdate) {
2685 m_textLayout.setText(str);
2686 updateLayout(); // polish?
2687 emit q_func()->displayTextChanged();
2691 qreal QQuickTextInputPrivate::getImplicitWidth() const
2693 Q_Q(const QQuickTextInput);
2694 if (!requireImplicitWidth) {
2695 QQuickTextInputPrivate *d = const_cast<QQuickTextInputPrivate *>(this);
2696 d->requireImplicitWidth = true;
2698 if (q->isComponentComplete()) {
2699 // One time cost, only incurred if implicitWidth is first requested after
2700 // componentComplete.
2701 QTextLayout layout(m_text);
2703 QTextOption option = m_textLayout.textOption();
2704 option.setTextDirection(m_layoutDirection);
2705 option.setFlags(QTextOption::IncludeTrailingSpaces);
2706 option.setWrapMode(QTextOption::WrapMode(wrapMode));
2707 option.setAlignment(Qt::Alignment(q->effectiveHAlign()));
2708 layout.setTextOption(option);
2709 layout.setFont(font);
2710 layout.setPreeditArea(m_textLayout.preeditAreaPosition(), m_textLayout.preeditAreaText());
2711 layout.beginLayout();
2713 QTextLine line = layout.createLine();
2714 line.setLineWidth(INT_MAX);
2715 d->implicitWidth = qCeil(line.naturalTextWidth());
2720 return implicitWidth;
2723 void QQuickTextInputPrivate::updateLayout()
2725 Q_Q(QQuickTextInput);
2727 if (!q->isComponentComplete())
2730 const QRectF previousRect = boundingRect;
2732 QTextOption option = m_textLayout.textOption();
2733 option.setTextDirection(layoutDirection());
2734 option.setWrapMode(QTextOption::WrapMode(wrapMode));
2735 option.setAlignment(Qt::Alignment(q->effectiveHAlign()));
2736 m_textLayout.setTextOption(option);
2737 m_textLayout.setFont(font);
2739 boundingRect = QRectF();
2740 m_textLayout.beginLayout();
2741 QTextLine line = m_textLayout.createLine();
2742 if (requireImplicitWidth) {
2743 line.setLineWidth(INT_MAX);
2744 const bool wasInLayout = inLayout;
2746 q->setImplicitWidth(qCeil(line.naturalTextWidth()));
2747 inLayout = wasInLayout;
2748 if (inLayout) // probably the result of a binding loop, but by letting it
2749 return; // get this far we'll get a warning to that effect.
2751 qreal lineWidth = q->widthValid() ? q->width() : INT_MAX;
2754 line.setLineWidth(lineWidth);
2755 line.setPosition(QPointF(line.position().x(), height));
2756 boundingRect = boundingRect.united(line.naturalTextRect());
2758 height += line.height();
2759 line = m_textLayout.createLine();
2760 } while (line.isValid());
2761 m_textLayout.endLayout();
2763 option.setWrapMode(QTextOption::NoWrap);
2764 m_textLayout.setTextOption(option);
2766 textLayoutDirty = true;
2768 updateType = UpdatePaintNode;
2771 if (!requireImplicitWidth && !q->widthValid())
2772 q->setImplicitSize(qCeil(boundingRect.width()), qCeil(boundingRect.height()));
2774 q->setImplicitHeight(qCeil(boundingRect.height()));
2776 if (previousRect != boundingRect)
2777 emit q->contentSizeChanged();
2780 #ifndef QT_NO_CLIPBOARD
2784 Copies the currently selected text into the clipboard using the given
2787 \note If the echo mode is set to a mode other than Normal then copy
2788 will not work. This is to prevent using copy as a method of bypassing
2789 password features of the line control.
2791 void QQuickTextInputPrivate::copy(QClipboard::Mode mode) const
2793 QString t = selectedText();
2794 if (!t.isEmpty() && m_echoMode == QQuickTextInput::Normal) {
2795 QGuiApplication::clipboard()->setText(t, mode);
2802 Inserts the text stored in the application clipboard into the line
2807 void QQuickTextInputPrivate::paste(QClipboard::Mode clipboardMode)
2809 QString clip = QGuiApplication::clipboard()->text(clipboardMode);
2810 if (!clip.isEmpty() || hasSelectedText()) {
2811 separate(); //make it a separate undo/redo command
2817 #endif // !QT_NO_CLIPBOARD
2822 void QQuickTextInputPrivate::commitPreedit()
2824 Q_Q(QQuickTextInput);
2829 qApp->inputMethod()->commit();
2834 QInputMethodEvent ev;
2835 QCoreApplication::sendEvent(q, &ev);
2838 void QQuickTextInputPrivate::cancelPreedit()
2840 Q_Q(QQuickTextInput);
2845 qApp->inputMethod()->reset();
2847 QInputMethodEvent ev;
2848 QCoreApplication::sendEvent(q, &ev);
2854 Handles the behavior for the backspace key or function.
2855 Removes the current selection if there is a selection, otherwise
2856 removes the character prior to the cursor position.
2860 void QQuickTextInputPrivate::backspace()
2862 int priorState = m_undoState;
2863 if (hasSelectedText()) {
2864 removeSelectedText();
2865 } else if (m_cursor) {
2868 m_cursor = prevMaskBlank(m_cursor);
2869 QChar uc = m_text.at(m_cursor);
2870 if (m_cursor > 0 && uc.unicode() >= 0xdc00 && uc.unicode() < 0xe000) {
2871 // second half of a surrogate, check if we have the first half as well,
2872 // if yes delete both at once
2873 uc = m_text.at(m_cursor - 1);
2874 if (uc.unicode() >= 0xd800 && uc.unicode() < 0xdc00) {
2875 internalDelete(true);
2879 internalDelete(true);
2881 finishChange(priorState);
2887 Handles the behavior for the delete key or function.
2888 Removes the current selection if there is a selection, otherwise
2889 removes the character after the cursor position.
2893 void QQuickTextInputPrivate::del()
2895 int priorState = m_undoState;
2896 if (hasSelectedText()) {
2897 removeSelectedText();
2899 int n = m_textLayout.nextCursorPosition(m_cursor) - m_cursor;
2903 finishChange(priorState);
2909 Inserts the given \a newText at the current cursor position.
2910 If there is any selected text it is removed prior to insertion of
2913 void QQuickTextInputPrivate::insert(const QString &newText)
2915 int priorState = m_undoState;
2916 removeSelectedText();
2917 internalInsert(newText);
2918 finishChange(priorState);
2924 Clears the line control text.
2926 void QQuickTextInputPrivate::clear()
2928 int priorState = m_undoState;
2930 m_selend = m_text.length();
2931 removeSelectedText();
2933 finishChange(priorState, /*update*/false, /*edited*/false);
2939 Sets \a length characters from the given \a start position as selected.
2940 The given \a start position must be within the current text for
2941 the line control. If \a length characters cannot be selected, then
2942 the selection will extend to the end of the current text.
2944 void QQuickTextInputPrivate::setSelection(int start, int length)
2946 Q_Q(QQuickTextInput);
2949 if (start < 0 || start > (int)m_text.length()){
2950 qWarning("QQuickTextInputPrivate::setSelection: Invalid start position");
2955 if (start == m_selstart && start + length == m_selend && m_cursor == m_selend)
2958 m_selend = qMin(start + length, (int)m_text.length());
2959 m_cursor = m_selend;
2960 } else if (length < 0){
2961 if (start == m_selend && start + length == m_selstart && m_cursor == m_selstart)
2963 m_selstart = qMax(start + length, 0);
2965 m_cursor = m_selstart;
2966 } else if (m_selstart != m_selend) {
2972 emitCursorPositionChanged();
2975 emit q->selectionChanged();
2976 emitCursorPositionChanged();
2977 q->updateInputMethod(Qt::ImCursorRectangle | Qt::ImAnchorPosition
2978 | Qt::ImCursorPosition | Qt::ImCurrentSelection);
2984 Sets the password echo editing to \a editing. If password echo editing
2985 is true, then the text of the password is displayed even if the echo
2986 mode is set to QLineEdit::PasswordEchoOnEdit. Password echoing editing
2987 does not affect other echo modes.
2989 void QQuickTextInputPrivate::updatePasswordEchoEditing(bool editing)
2991 cancelPasswordEchoTimer();
2992 m_passwordEchoEditing = editing;
2993 updateDisplayText();
2999 Fixes the current text so that it is valid given any set validators.
3001 Returns true if the text was changed. Otherwise returns false.
3003 bool QQuickTextInputPrivate::fixup() // this function assumes that validate currently returns != Acceptable
3005 #ifndef QT_NO_VALIDATOR
3007 QString textCopy = m_text;
3008 int cursorCopy = m_cursor;
3009 m_validator->fixup(textCopy);
3010 if (m_validator->validate(textCopy, cursorCopy) == QValidator::Acceptable) {
3011 if (textCopy != m_text || cursorCopy != m_cursor)
3012 internalSetText(textCopy, cursorCopy);
3023 Moves the cursor to the given position \a pos. If \a mark is true will
3024 adjust the currently selected text.
3026 void QQuickTextInputPrivate::moveCursor(int pos, bool mark)
3028 Q_Q(QQuickTextInput);
3031 if (pos != m_cursor) {
3034 pos = pos > m_cursor ? nextMaskBlank(pos) : prevMaskBlank(pos);
3038 if (m_selend > m_selstart && m_cursor == m_selstart)
3040 else if (m_selend > m_selstart && m_cursor == m_selend)
3041 anchor = m_selstart;
3044 m_selstart = qMin(anchor, pos);
3045 m_selend = qMax(anchor, pos);
3050 if (mark || m_selDirty) {
3052 emit q->selectionChanged();
3054 emitCursorPositionChanged();
3055 q->updateInputMethod();
3061 Applies the given input method event \a event to the text of the line
3064 void QQuickTextInputPrivate::processInputMethodEvent(QInputMethodEvent *event)
3066 Q_Q(QQuickTextInput);
3068 int priorState = -1;
3069 bool isGettingInput = !event->commitString().isEmpty()
3070 || event->preeditString() != preeditAreaText()
3071 || event->replacementLength() > 0;
3072 bool cursorPositionChanged = false;
3073 bool selectionChange = false;
3074 m_preeditDirty = event->preeditString() != preeditAreaText();
3076 if (isGettingInput) {
3077 // If any text is being input, remove selected text.
3078 priorState = m_undoState;
3079 if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit && !m_passwordEchoEditing) {
3080 updatePasswordEchoEditing(true);
3082 m_selend = m_text.length();
3084 removeSelectedText();
3087 int c = m_cursor; // cursor position after insertion of commit string
3088 if (event->replacementStart() <= 0)
3089 c += event->commitString().length() - qMin(-event->replacementStart(), event->replacementLength());
3091 m_cursor += event->replacementStart();
3095 // insert commit string
3096 if (event->replacementLength()) {
3097 m_selstart = m_cursor;
3098 m_selend = m_selstart + event->replacementLength();
3099 m_selend = qMin(m_selend, m_text.length());
3100 removeSelectedText();
3102 if (!event->commitString().isEmpty()) {
3103 internalInsert(event->commitString());
3104 cursorPositionChanged = true;
3107 m_cursor = qBound(0, c, m_text.length());
3109 for (int i = 0; i < event->attributes().size(); ++i) {
3110 const QInputMethodEvent::Attribute &a = event->attributes().at(i);
3111 if (a.type == QInputMethodEvent::Selection) {
3112 m_cursor = qBound(0, a.start + a.length, m_text.length());
3114 m_selstart = qMax(0, qMin(a.start, m_text.length()));
3115 m_selend = m_cursor;
3116 if (m_selend < m_selstart) {
3117 qSwap(m_selstart, m_selend);
3119 selectionChange = true;
3121 m_selstart = m_selend = 0;
3123 cursorPositionChanged = true;
3127 m_textLayout.setPreeditArea(m_cursor, event->preeditString());
3129 const int oldPreeditCursor = m_preeditCursor;
3130 const bool oldCursorVisible = cursorVisible;
3131 m_preeditCursor = event->preeditString().length();
3132 hasImState = !event->preeditString().isEmpty();
3133 cursorVisible = true;
3134 QList<QTextLayout::FormatRange> formats;
3135 for (int i = 0; i < event->attributes().size(); ++i) {
3136 const QInputMethodEvent::Attribute &a = event->attributes().at(i);
3137 if (a.type == QInputMethodEvent::Cursor) {
3139 m_preeditCursor = a.start;
3140 cursorVisible = a.length != 0;
3141 } else if (a.type == QInputMethodEvent::TextFormat) {
3143 QTextCharFormat f = qvariant_cast<QTextFormat>(a.value).toCharFormat();
3145 QTextLayout::FormatRange o;
3146 o.start = a.start + m_cursor;
3147 o.length = a.length;
3153 m_textLayout.setAdditionalFormats(formats);
3155 updateDisplayText(/*force*/ true);
3156 if (cursorPositionChanged) {
3157 emitCursorPositionChanged();
3158 } else if (m_preeditCursor != oldPreeditCursor) {
3159 q->updateCursorRectangle();
3163 finishChange(priorState);
3165 if (cursorVisible != oldCursorVisible)
3166 emit q->cursorVisibleChanged(cursorVisible);
3168 if (selectionChange) {
3169 emit q->selectionChanged();
3170 q->updateInputMethod(Qt::ImCursorRectangle | Qt::ImAnchorPosition
3171 | Qt::ImCursorPosition | Qt::ImCurrentSelection);
3178 Sets the selection to cover the word at the given cursor position.
3179 The word boundaries are defined by the behavior of QTextLayout::SkipWords
3182 void QQuickTextInputPrivate::selectWordAtPos(int cursor)
3184 int next = cursor + 1;
3187 int c = m_textLayout.previousCursorPosition(next, QTextLayout::SkipWords);
3188 moveCursor(c, false);
3189 // ## text layout should support end of words.
3190 int end = m_textLayout.nextCursorPosition(c, QTextLayout::SkipWords);
3191 while (end > cursor && m_text[end-1].isSpace())
3193 moveCursor(end, true);
3199 Completes a change to the line control text. If the change is not valid
3200 will undo the line control state back to the given \a validateFromState.
3202 If \a edited is true and the change is valid, will emit textEdited() in
3203 addition to textChanged(). Otherwise only emits textChanged() on a valid
3206 The \a update value is currently unused.
3208 bool QQuickTextInputPrivate::finishChange(int validateFromState, bool update, bool /*edited*/)
3210 Q_Q(QQuickTextInput);
3213 bool inputMethodAttributesChanged = m_textDirty || m_selDirty;
3214 bool alignmentChanged = false;
3218 bool wasValidInput = m_validInput;
3219 bool wasAcceptable = m_acceptableInput;
3220 m_validInput = true;
3221 m_acceptableInput = true;
3222 #ifndef QT_NO_VALIDATOR
3224 QString textCopy = m_text;
3225 int cursorCopy = m_cursor;
3226 QValidator::State state = m_validator->validate(textCopy, cursorCopy);
3227 m_validInput = state != QValidator::Invalid;
3228 m_acceptableInput = state == QValidator::Acceptable;
3230 if (m_text != textCopy) {
3231 internalSetText(textCopy, cursorCopy);
3234 m_cursor = cursorCopy;
3238 if (validateFromState >= 0 && wasValidInput && !m_validInput) {
3239 if (m_transactions.count())
3241 internalUndo(validateFromState);
3242 m_history.resize(m_undoState);
3243 m_validInput = true;
3244 m_acceptableInput = wasAcceptable;
3245 m_textDirty = false;
3249 m_textDirty = false;
3250 m_preeditDirty = false;
3251 alignmentChanged = determineHorizontalAlignment();
3252 emit q->textChanged();
3255 updateDisplayText(alignmentChanged);
3257 if (m_acceptableInput != wasAcceptable)
3258 emit q->acceptableInputChanged();
3260 if (m_preeditDirty) {
3261 m_preeditDirty = false;
3262 if (determineHorizontalAlignment()) {
3263 alignmentChanged = true;
3270 emit q->selectionChanged();
3273 inputMethodAttributesChanged |= (m_cursor == m_lastCursorPos);
3274 if (inputMethodAttributesChanged)
3275 q->updateInputMethod();
3276 emitUndoRedoChanged();
3278 if (!emitCursorPositionChanged() && alignmentChanged)
3279 q->updateCursorRectangle();
3287 An internal function for setting the text of the line control.
3289 void QQuickTextInputPrivate::internalSetText(const QString &txt, int pos, bool edited)
3291 Q_Q(QQuickTextInput);
3293 QString oldText = m_text;
3295 m_text = maskString(0, txt, true);
3296 m_text += clearString(m_text.length(), m_maxLength - m_text.length());
3298 m_text = txt.isEmpty() ? txt : txt.left(m_maxLength);
3302 m_cursor = (pos < 0 || pos > m_text.length()) ? m_text.length() : pos;
3303 m_textDirty = (oldText != m_text);
3305 bool changed = finishChange(-1, true, edited);
3306 #ifdef QT_NO_ACCESSIBILITY
3310 QAccessibleTextUpdateEvent ev(q, 0, oldText, m_text);
3311 QAccessible::updateAccessibility(&ev);
3320 Adds the given \a command to the undo history
3321 of the line control. Does not apply the command.
3323 void QQuickTextInputPrivate::addCommand(const Command &cmd)
3325 if (m_separator && m_undoState && m_history[m_undoState - 1].type != Separator) {
3326 m_history.resize(m_undoState + 2);
3327 m_history[m_undoState++] = Command(Separator, m_cursor, 0, m_selstart, m_selend);
3329 m_history.resize(m_undoState + 1);
3331 m_separator = false;
3332 m_history[m_undoState++] = cmd;
3338 Inserts the given string \a s into the line
3341 Also adds the appropriate commands into the undo history.
3342 This function does not call finishChange(), and may leave the text
3343 in an invalid state.
3345 void QQuickTextInputPrivate::internalInsert(const QString &s)
3347 Q_Q(QQuickTextInput);
3348 if (m_echoMode == QQuickTextInput::Password) {
3349 int delay = qGuiApp->styleHints()->passwordMaskDelay();
3351 m_passwordEchoTimer.start(delay, q);
3353 if (hasSelectedText())
3354 addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
3356 QString ms = maskString(m_cursor, s);
3357 for (int i = 0; i < (int) ms.length(); ++i) {
3358 addCommand (Command(DeleteSelection, m_cursor + i, m_text.at(m_cursor + i), -1, -1));
3359 addCommand(Command(Insert, m_cursor + i, ms.at(i), -1, -1));
3361 m_text.replace(m_cursor, ms.length(), ms);
3362 m_cursor += ms.length();
3363 m_cursor = nextMaskBlank(m_cursor);
3366 int remaining = m_maxLength - m_text.length();
3367 if (remaining != 0) {
3368 m_text.insert(m_cursor, s.left(remaining));
3369 for (int i = 0; i < (int) s.left(remaining).length(); ++i)
3370 addCommand(Command(Insert, m_cursor++, s.at(i), -1, -1));
3379 deletes a single character from the current text. If \a wasBackspace,
3380 the character prior to the cursor is removed. Otherwise the character
3381 after the cursor is removed.
3383 Also adds the appropriate commands into the undo history.
3384 This function does not call finishChange(), and may leave the text
3385 in an invalid state.
3387 void QQuickTextInputPrivate::internalDelete(bool wasBackspace)
3389 if (m_cursor < (int) m_text.length()) {
3390 cancelPasswordEchoTimer();
3391 if (hasSelectedText())
3392 addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
3393 addCommand(Command((CommandType)((m_maskData ? 2 : 0) + (wasBackspace ? Remove : Delete)),
3394 m_cursor, m_text.at(m_cursor), -1, -1));
3396 m_text.replace(m_cursor, 1, clearString(m_cursor, 1));
3397 addCommand(Command(Insert, m_cursor, m_text.at(m_cursor), -1, -1));
3399 m_text.remove(m_cursor, 1);
3408 removes the currently selected text from the line control.
3410 Also adds the appropriate commands into the undo history.
3411 This function does not call finishChange(), and may leave the text
3412 in an invalid state.
3414 void QQuickTextInputPrivate::removeSelectedText()
3416 if (m_selstart < m_selend && m_selend <= (int) m_text.length()) {
3417 cancelPasswordEchoTimer();
3420 addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
3421 if (m_selstart <= m_cursor && m_cursor < m_selend) {
3422 // cursor is within the selection. Split up the commands
3423 // to be able to restore the correct cursor position
3424 for (i = m_cursor; i >= m_selstart; --i)
3425 addCommand (Command(DeleteSelection, i, m_text.at(i), -1, 1));
3426 for (i = m_selend - 1; i > m_cursor; --i)
3427 addCommand (Command(DeleteSelection, i - m_cursor + m_selstart - 1, m_text.at(i), -1, -1));
3429 for (i = m_selend-1; i >= m_selstart; --i)
3430 addCommand (Command(RemoveSelection, i, m_text.at(i), -1, -1));
3433 m_text.replace(m_selstart, m_selend - m_selstart, clearString(m_selstart, m_selend - m_selstart));
3434 for (int i = 0; i < m_selend - m_selstart; ++i)
3435 addCommand(Command(Insert, m_selstart + i, m_text.at(m_selstart + i), -1, -1));
3437 m_text.remove(m_selstart, m_selend - m_selstart);
3439 if (m_cursor > m_selstart)
3440 m_cursor -= qMin(m_cursor, m_selend) - m_selstart;
3449 Parses the input mask specified by \a maskFields to generate
3450 the mask data used to handle input masks.
3452 void QQuickTextInputPrivate::parseInputMask(const QString &maskFields)
3454 int delimiter = maskFields.indexOf(QLatin1Char(';'));
3455 if (maskFields.isEmpty() || delimiter == 0) {
3457 delete [] m_maskData;
3459 m_maxLength = 32767;
3460 internalSetText(QString());
3465 if (delimiter == -1) {
3466 m_blank = QLatin1Char(' ');
3467 m_inputMask = maskFields;
3469 m_inputMask = maskFields.left(delimiter);
3470 m_blank = (delimiter + 1 < maskFields.length()) ? maskFields[delimiter + 1] : QLatin1Char(' ');
3473 // calculate m_maxLength / m_maskData length
3476 for (int i=0; i<m_inputMask.length(); i++) {
3477 c = m_inputMask.at(i);
3478 if (i > 0 && m_inputMask.at(i-1) == QLatin1Char('\\')) {
3482 if (c != QLatin1Char('\\') && c != QLatin1Char('!') &&
3483 c != QLatin1Char('<') && c != QLatin1Char('>') &&
3484 c != QLatin1Char('{') && c != QLatin1Char('}') &&
3485 c != QLatin1Char('[') && c != QLatin1Char(']'))
3489 delete [] m_maskData;
3490 m_maskData = new MaskInputData[m_maxLength];
3492 MaskInputData::Casemode m = MaskInputData::NoCaseMode;
3495 bool escape = false;
3497 for (int i = 0; i < m_inputMask.length(); i++) {
3498 c = m_inputMask.at(i);
3501 m_maskData[index].maskChar = c;
3502 m_maskData[index].separator = s;
3503 m_maskData[index].caseMode = m;
3506 } else if (c == QLatin1Char('<')) {
3507 m = MaskInputData::Lower;
3508 } else if (c == QLatin1Char('>')) {
3509 m = MaskInputData::Upper;
3510 } else if (c == QLatin1Char('!')) {
3511 m = MaskInputData::NoCaseMode;
3512 } else if (c != QLatin1Char('{') && c != QLatin1Char('}') && c != QLatin1Char('[') && c != QLatin1Char(']')) {
3513 switch (c.unicode()) {
3539 m_maskData[index].maskChar = c;
3540 m_maskData[index].separator = s;
3541 m_maskData[index].caseMode = m;
3546 internalSetText(m_text);
3553 checks if the key is valid compared to the inputMask
3555 bool QQuickTextInputPrivate::isValidInput(QChar key, QChar mask) const
3557 switch (mask.unicode()) {
3563 if (key.isLetter() || key == m_blank)
3567 if (key.isLetterOrNumber())
3571 if (key.isLetterOrNumber() || key == m_blank)
3579 if (key.isPrint() || key == m_blank)
3587 if (key.isNumber() || key == m_blank)
3591 if (key.isNumber() && key.digitValue() > 0)
3595 if ((key.isNumber() && key.digitValue() > 0) || key == m_blank)
3599 if (key.isNumber() || key == QLatin1Char('+') || key == QLatin1Char('-') || key == m_blank)
3603 if (key == QLatin1Char('0') || key == QLatin1Char('1'))
3607 if (key == QLatin1Char('0') || key == QLatin1Char('1') || key == m_blank)
3611 if (key.isNumber() || (key >= QLatin1Char('a') && key <= QLatin1Char('f')) || (key >= QLatin1Char('A') && key <= QLatin1Char('F')))
3615 if (key.isNumber() || (key >= QLatin1Char('a') && key <= QLatin1Char('f')) || (key >= QLatin1Char('A') && key <= QLatin1Char('F')) || key == m_blank)
3627 Returns true if the given text \a str is valid for any
3628 validator or input mask set for the line control.
3630 Otherwise returns false
3632 QQuickTextInputPrivate::ValidatorState QQuickTextInputPrivate::hasAcceptableInput(const QString &str) const
3634 #ifndef QT_NO_VALIDATOR
3635 QString textCopy = str;
3636 int cursorCopy = m_cursor;
3638 QValidator::State state = m_validator->validate(textCopy, cursorCopy);
3639 if (state != QValidator::Acceptable)
3640 return ValidatorState(state);
3645 return AcceptableInput;
3647 if (str.length() != m_maxLength)
3648 return InvalidInput;
3650 for (int i=0; i < m_maxLength; ++i) {
3651 if (m_maskData[i].separator) {
3652 if (str.at(i) != m_maskData[i].maskChar)
3653 return InvalidInput;
3655 if (!isValidInput(str.at(i), m_maskData[i].maskChar))
3656 return InvalidInput;
3659 return AcceptableInput;
3665 Applies the inputMask on \a str starting from position \a pos in the mask. \a clear
3666 specifies from where characters should be gotten when a separator is met in \a str - true means
3667 that blanks will be used, false that previous input is used.
3668 Calling this when no inputMask is set is undefined.
3670 QString QQuickTextInputPrivate::maskString(uint pos, const QString &str, bool clear) const
3672 if (pos >= (uint)m_maxLength)
3673 return QString::fromLatin1("");
3676 fill = clear ? clearString(0, m_maxLength) : m_text;
3679 QString s = QString::fromLatin1("");
3681 while (i < m_maxLength) {
3682 if (strIndex < str.length()) {
3683 if (m_maskData[i].separator) {
3684 s += m_maskData[i].maskChar;
3685 if (str[(int)strIndex] == m_maskData[i].maskChar)
3689 if (isValidInput(str[(int)strIndex], m_maskData[i].maskChar)) {
3690 switch (m_maskData[i].caseMode) {
3691 case MaskInputData::Upper:
3692 s += str[(int)strIndex].toUpper();
3694 case MaskInputData::Lower:
3695 s += str[(int)strIndex].toLower();
3698 s += str[(int)strIndex];
3702 // search for separator first
3703 int n = findInMask(i, true, true, str[(int)strIndex]);
3705 if (str.length() != 1 || i == 0 || (i > 0 && (!m_maskData[i-1].separator || m_maskData[i-1].maskChar != str[(int)strIndex]))) {
3706 s += fill.mid(i, n-i+1);
3707 i = n + 1; // update i to find + 1
3710 // search for valid m_blank if not
3711 n = findInMask(i, true, false, str[(int)strIndex]);
3713 s += fill.mid(i, n-i);
3714 switch (m_maskData[n].caseMode) {
3715 case MaskInputData::Upper:
3716 s += str[(int)strIndex].toUpper();
3718 case MaskInputData::Lower:
3719 s += str[(int)strIndex].toLower();
3722 s += str[(int)strIndex];
3724 i = n + 1; // updates i to find + 1
3742 Returns a "cleared" string with only separators and blank chars.
3743 Calling this when no inputMask is set is undefined.
3745 QString QQuickTextInputPrivate::clearString(uint pos, uint len) const
3747 if (pos >= (uint)m_maxLength)
3751 int end = qMin((uint)m_maxLength, pos + len);
3752 for (int i = pos; i < end; ++i)
3753 if (m_maskData[i].separator)
3754 s += m_maskData[i].maskChar;
3764 Strips blank parts of the input in a QQuickTextInputPrivate when an inputMask is set,
3765 separators are still included. Typically "127.0__.0__.1__" becomes "127.0.0.1".
3767 QString QQuickTextInputPrivate::stripString(const QString &str) const
3773 int end = qMin(m_maxLength, (int)str.length());
3774 for (int i = 0; i < end; ++i) {
3775 if (m_maskData[i].separator)
3776 s += m_maskData[i].maskChar;
3777 else if (str[i] != m_blank)
3786 searches forward/backward in m_maskData for either a separator or a m_blank
3788 int QQuickTextInputPrivate::findInMask(int pos, bool forward, bool findSeparator, QChar searchChar) const
3790 if (pos >= m_maxLength || pos < 0)
3793 int end = forward ? m_maxLength : -1;
3794 int step = forward ? 1 : -1;
3798 if (findSeparator) {
3799 if (m_maskData[i].separator && m_maskData[i].maskChar == searchChar)
3802 if (!m_maskData[i].separator) {
3803 if (searchChar.isNull())
3805 else if (isValidInput(searchChar, m_maskData[i].maskChar))
3814 void QQuickTextInputPrivate::internalUndo(int until)
3816 if (!isUndoAvailable())
3818 cancelPasswordEchoTimer();
3820 while (m_undoState && m_undoState > until) {
3821 Command& cmd = m_history[--m_undoState];
3824 m_text.remove(cmd.pos, 1);
3828 m_selstart = cmd.selStart;
3829 m_selend = cmd.selEnd;
3833 case RemoveSelection:
3834 m_text.insert(cmd.pos, cmd.uc);
3835 m_cursor = cmd.pos + 1;
3838 case DeleteSelection:
3839 m_text.insert(cmd.pos, cmd.uc);
3845 if (until < 0 && m_undoState) {
3846 Command& next = m_history[m_undoState-1];
3847 if (next.type != cmd.type && next.type < RemoveSelection
3848 && (cmd.type < RemoveSelection || next.type == Separator))
3855 void QQuickTextInputPrivate::internalRedo()
3857 if (!isRedoAvailable())
3860 while (m_undoState < (int)m_history.size()) {
3861 Command& cmd = m_history[m_undoState++];
3864 m_text.insert(cmd.pos, cmd.uc);
3865 m_cursor = cmd.pos + 1;
3868 m_selstart = cmd.selStart;
3869 m_selend = cmd.selEnd;
3874 case RemoveSelection:
3875 case DeleteSelection:
3876 m_text.remove(cmd.pos, 1);
3877 m_selstart = cmd.selStart;
3878 m_selend = cmd.selEnd;
3882 m_selstart = cmd.selStart;
3883 m_selend = cmd.selEnd;
3887 if (m_undoState < (int)m_history.size()) {
3888 Command& next = m_history[m_undoState];
3889 if (next.type != cmd.type && cmd.type < RemoveSelection && next.type != Separator
3890 && (next.type < RemoveSelection || cmd.type == Separator))
3897 void QQuickTextInputPrivate::emitUndoRedoChanged()
3899 Q_Q(QQuickTextInput);
3900 const bool previousUndo = canUndo;
3901 const bool previousRedo = canRedo;
3903 canUndo = isUndoAvailable();
3904 canRedo = isRedoAvailable();
3906 if (previousUndo != canUndo)
3907 emit q->canUndoChanged();
3908 if (previousRedo != canRedo)
3909 emit q->canRedoChanged();
3915 If the current cursor position differs from the last emitted cursor
3916 position, emits cursorPositionChanged().
3918 bool QQuickTextInputPrivate::emitCursorPositionChanged()
3920 Q_Q(QQuickTextInput);
3921 if (m_cursor != m_lastCursorPos) {
3922 m_lastCursorPos = m_cursor;
3924 q->updateCursorRectangle();
3925 emit q->cursorPositionChanged();
3927 if (!hasSelectedText()) {
3928 if (lastSelectionStart != m_cursor) {
3929 lastSelectionStart = m_cursor;
3930 emit q->selectionStartChanged();
3932 if (lastSelectionEnd != m_cursor) {
3933 lastSelectionEnd = m_cursor;
3934 emit q->selectionEndChanged();
3938 #ifndef QT_NO_ACCESSIBILITY
3939 QAccessibleTextCursorEvent ev(q, m_cursor);
3940 QAccessible::updateAccessibility(&ev);
3949 void QQuickTextInputPrivate::setCursorBlinkPeriod(int msec)
3951 Q_Q(QQuickTextInput);
3952 if (msec == m_blinkPeriod)
3955 q->killTimer(m_blinkTimer);
3958 m_blinkTimer = q->startTimer(msec / 2);
3962 if (m_blinkStatus == 1) {
3963 updateType = UpdatePaintNode;
3967 m_blinkPeriod = msec;
3970 void QQuickTextInput::timerEvent(QTimerEvent *event)
3972 Q_D(QQuickTextInput);
3973 if (event->timerId() == d->m_blinkTimer) {
3974 d->m_blinkStatus = !d->m_blinkStatus;
3975 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
3977 } else if (event->timerId() == d->m_passwordEchoTimer.timerId()) {
3978 d->m_passwordEchoTimer.stop();
3979 d->updateDisplayText();
3983 void QQuickTextInputPrivate::processKeyEvent(QKeyEvent* event)
3985 Q_Q(QQuickTextInput);
3986 bool inlineCompletionAccepted = false;
3988 if (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return) {
3989 if (hasAcceptableInput(m_text) || fixup()) {
3992 if (inlineCompletionAccepted)
3999 if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit
4000 && !m_passwordEchoEditing
4002 && !event->text().isEmpty()
4003 && !(event->modifiers() & Qt::ControlModifier)) {
4004 // Clear the edit and reset to normal echo mode while editing; the
4005 // echo mode switches back when the edit loses focus
4006 // ### resets current content. dubious code; you can
4007 // navigate with keys up, down, back, and select(?), but if you press
4008 // "left" or "right" it clears?
4009 updatePasswordEchoEditing(true);
4013 bool unknown = false;
4014 bool visual = cursorMoveStyle() == Qt::VisualMoveStyle;
4018 #ifndef QT_NO_SHORTCUT
4019 else if (event == QKeySequence::Undo) {
4022 else if (event == QKeySequence::Redo) {
4025 else if (event == QKeySequence::SelectAll) {
4028 #ifndef QT_NO_CLIPBOARD
4029 else if (event == QKeySequence::Copy) {
4032 else if (event == QKeySequence::Paste) {
4034 QClipboard::Mode mode = QClipboard::Clipboard;
4038 else if (event == QKeySequence::Cut) {
4044 else if (event == QKeySequence::DeleteEndOfLine) {
4046 setSelection(m_cursor, end());
4051 #endif //QT_NO_CLIPBOARD
4052 else if (event == QKeySequence::MoveToStartOfLine || event == QKeySequence::MoveToStartOfBlock) {
4055 else if (event == QKeySequence::MoveToEndOfLine || event == QKeySequence::MoveToEndOfBlock) {
4058 else if (event == QKeySequence::SelectStartOfLine || event == QKeySequence::SelectStartOfBlock) {
4061 else if (event == QKeySequence::SelectEndOfLine || event == QKeySequence::SelectEndOfBlock) {
4064 else if (event == QKeySequence::MoveToNextChar) {
4065 if (hasSelectedText()) {
4066 moveCursor(selectionEnd(), false);
4068 cursorForward(0, visual ? 1 : (layoutDirection() == Qt::LeftToRight ? 1 : -1));
4071 else if (event == QKeySequence::SelectNextChar) {
4072 cursorForward(1, visual ? 1 : (layoutDirection() == Qt::LeftToRight ? 1 : -1));
4074 else if (event == QKeySequence::MoveToPreviousChar) {
4075 if (hasSelectedText()) {
4076 moveCursor(selectionStart(), false);
4078 cursorForward(0, visual ? -1 : (layoutDirection() == Qt::LeftToRight ? -1 : 1));
4081 else if (event == QKeySequence::SelectPreviousChar) {
4082 cursorForward(1, visual ? -1 : (layoutDirection() == Qt::LeftToRight ? -1 : 1));
4084 else if (event == QKeySequence::MoveToNextWord) {
4085 if (m_echoMode == QQuickTextInput::Normal)
4086 layoutDirection() == Qt::LeftToRight ? cursorWordForward(0) : cursorWordBackward(0);
4088 layoutDirection() == Qt::LeftToRight ? end(0) : home(0);
4090 else if (event == QKeySequence::MoveToPreviousWord) {
4091 if (m_echoMode == QQuickTextInput::Normal)
4092 layoutDirection() == Qt::LeftToRight ? cursorWordBackward(0) : cursorWordForward(0);
4093 else if (!m_readOnly) {
4094 layoutDirection() == Qt::LeftToRight ? home(0) : end(0);
4097 else if (event == QKeySequence::SelectNextWord) {
4098 if (m_echoMode == QQuickTextInput::Normal)
4099 layoutDirection() == Qt::LeftToRight ? cursorWordForward(1) : cursorWordBackward(1);
4101 layoutDirection() == Qt::LeftToRight ? end(1) : home(1);
4103 else if (event == QKeySequence::SelectPreviousWord) {
4104 if (m_echoMode == QQuickTextInput::Normal)
4105 layoutDirection() == Qt::LeftToRight ? cursorWordBackward(1) : cursorWordForward(1);
4107 layoutDirection() == Qt::LeftToRight ? home(1) : end(1);
4109 else if (event == QKeySequence::Delete) {
4113 else if (event == QKeySequence::DeleteEndOfWord) {
4115 cursorWordForward(true);
4119 else if (event == QKeySequence::DeleteStartOfWord) {
4121 cursorWordBackward(true);
4125 #endif // QT_NO_SHORTCUT
4127 bool handled = false;
4128 if (event->modifiers() & Qt::ControlModifier) {
4129 switch (event->key()) {
4130 case Qt::Key_Backspace:
4132 cursorWordBackward(true);
4140 } else { // ### check for *no* modifier
4141 switch (event->key()) {
4142 case Qt::Key_Backspace:
4154 if (event->key() == Qt::Key_Direction_L || event->key() == Qt::Key_Direction_R) {
4155 setLayoutDirection((event->key() == Qt::Key_Direction_L) ? Qt::LeftToRight : Qt::RightToLeft);
4159 if (unknown && !m_readOnly) {
4160 QString t = event->text();
4161 if (!t.isEmpty() && t.at(0).isPrint()) {