1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: http://www.qt-project.org/
7 ** This file is part of the QtDeclarative module of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #include "qquicktextinput_p.h"
43 #include "qquicktextinput_p_p.h"
44 #include "qquickcanvas.h"
46 #include <private/qdeclarativeglobal_p.h>
48 #include <QtDeclarative/qdeclarativeinfo.h>
49 #include <QtGui/qevent.h>
50 #include <QTextBoundaryFinder>
51 #include "qquicktextnode_p.h"
52 #include <QtQuick/qsgsimplerectnode.h>
54 #include <QtGui/qstylehints.h>
55 #include <QtGui/qinputpanel.h>
57 #ifndef QT_NO_ACCESSIBILITY
58 #include "qaccessible.h"
63 DEFINE_BOOL_CONFIG_OPTION(qmlDisableDistanceField, QML_DISABLE_DISTANCEFIELD)
65 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
66 static const int qt_passwordEchoDelay = QT_GUI_PASSWORD_ECHO_DELAY;
70 \qmlclass TextInput QQuickTextInput
71 \inqmlmodule QtQuick 2
72 \ingroup qml-basic-visual-elements
73 \brief The TextInput item displays an editable line of text.
76 The TextInput element displays a single line of editable plain text.
78 TextInput is used to accept a line of text input. Input constraints
79 can be placed on a TextInput item (for example, through a \l validator or \l inputMask),
80 and setting \l echoMode to an appropriate value enables TextInput to be used for
81 a password input field.
83 On Mac OS X, the Up/Down key bindings for Home/End are explicitly disabled.
84 If you want such bindings (on any platform), you will need to construct them in QML.
86 \sa TextEdit, Text, {declarative/text/textselection}{Text Selection example}
88 QQuickTextInput::QQuickTextInput(QQuickItem* parent)
89 : QQuickImplicitSizeItem(*(new QQuickTextInputPrivate), parent)
95 QQuickTextInput::~QQuickTextInput()
99 void QQuickTextInput::componentComplete()
101 Q_D(QQuickTextInput);
103 QQuickImplicitSizeItem::componentComplete();
107 updateCursorRectangle();
108 if (d->cursorComponent && d->cursorComponent->isReady())
113 \qmlproperty string QtQuick2::TextInput::text
115 The text in the TextInput.
117 QString QQuickTextInput::text() const
119 Q_D(const QQuickTextInput);
121 QString content = d->m_text;
122 if (!d->m_tentativeCommit.isEmpty())
123 content.insert(d->m_cursor, d->m_tentativeCommit);
124 QString res = d->m_maskData ? d->stripString(content) : content;
125 return (res.isNull() ? QString::fromLatin1("") : res);
128 void QQuickTextInput::setText(const QString &s)
130 Q_D(QQuickTextInput);
133 if (d->composeMode())
134 qApp->inputPanel()->reset();
135 d->m_tentativeCommit.clear();
136 d->internalSetText(s, -1, false);
140 \qmlproperty int QtQuick2::TextInput::length
142 Returns the total number of characters in the TextInput item.
144 If the TextInput has an inputMask the length will include mask characters and may differ
145 from the length of the string returned by the \l text property.
147 This property can be faster than querying the length the \l text property as it doesn't
148 require any copying or conversion of the TextInput's internal string data.
151 int QQuickTextInput::length() const
153 Q_D(const QQuickTextInput);
154 return d->m_text.length();
158 \qmlmethod string QtQuick2::TextInput::getText(int start, int end)
160 Returns the section of text that is between the \a start and \a end positions.
162 If the TextInput has an inputMask the length will include mask characters.
165 QString QQuickTextInput::getText(int start, int end) const
167 Q_D(const QQuickTextInput);
172 return d->m_text.mid(start, end - start);
175 QString QQuickTextInputPrivate::realText() const
177 QString res = m_maskData ? stripString(m_text) : m_text;
178 return (res.isNull() ? QString::fromLatin1("") : res);
182 \qmlproperty string QtQuick2::TextInput::font.family
184 Sets the family name of the font.
186 The family name is case insensitive and may optionally include a foundry name, e.g. "Helvetica [Cronyx]".
187 If the family is available from more than one foundry and the foundry isn't specified, an arbitrary foundry is chosen.
188 If the family isn't available a family will be set using the font matching algorithm.
192 \qmlproperty bool QtQuick2::TextInput::font.bold
194 Sets whether the font weight is bold.
198 \qmlproperty enumeration QtQuick2::TextInput::font.weight
200 Sets the font's weight.
202 The weight can be one of:
205 \o Font.Normal - the default
212 TextInput { text: "Hello"; font.weight: Font.DemiBold }
217 \qmlproperty bool QtQuick2::TextInput::font.italic
219 Sets whether the font has an italic style.
223 \qmlproperty bool QtQuick2::TextInput::font.underline
225 Sets whether the text is underlined.
229 \qmlproperty bool QtQuick2::TextInput::font.strikeout
231 Sets whether the font has a strikeout style.
235 \qmlproperty real QtQuick2::TextInput::font.pointSize
237 Sets the font size in points. The point size must be greater than zero.
241 \qmlproperty int QtQuick2::TextInput::font.pixelSize
243 Sets the font size in pixels.
245 Using this function makes the font device dependent.
246 Use \c pointSize to set the size of the font in a device independent manner.
250 \qmlproperty real QtQuick2::TextInput::font.letterSpacing
252 Sets the letter spacing for the font.
254 Letter spacing changes the default spacing between individual letters in the font.
255 A positive value increases the letter spacing by the corresponding pixels; a negative value decreases the spacing.
259 \qmlproperty real QtQuick2::TextInput::font.wordSpacing
261 Sets the word spacing for the font.
263 Word spacing changes the default spacing between individual words.
264 A positive value increases the word spacing by a corresponding amount of pixels,
265 while a negative value decreases the inter-word spacing accordingly.
269 \qmlproperty enumeration QtQuick2::TextInput::font.capitalization
271 Sets the capitalization for the text.
274 \o Font.MixedCase - This is the normal text rendering option where no capitalization change is applied.
275 \o Font.AllUppercase - This alters the text to be rendered in all uppercase type.
276 \o Font.AllLowercase - This alters the text to be rendered in all lowercase type.
277 \o Font.SmallCaps - This alters the text to be rendered in small-caps type.
278 \o Font.Capitalize - This alters the text to be rendered with the first character of each word as an uppercase character.
282 TextInput { text: "Hello"; font.capitalization: Font.AllLowercase }
286 QFont QQuickTextInput::font() const
288 Q_D(const QQuickTextInput);
289 return d->sourceFont;
292 void QQuickTextInput::setFont(const QFont &font)
294 Q_D(QQuickTextInput);
295 if (d->sourceFont == font)
298 d->sourceFont = font;
299 QFont oldFont = d->font;
301 if (d->font.pointSizeF() != -1) {
303 qreal size = qRound(d->font.pointSizeF()*2.0);
304 d->font.setPointSizeF(size/2.0);
306 if (oldFont != d->font) {
308 updateCursorRectangle();
309 qApp->inputPanel()->update(Qt::ImCursorRectangle | Qt::ImFont);
311 emit fontChanged(d->sourceFont);
315 \qmlproperty color QtQuick2::TextInput::color
319 QColor QQuickTextInput::color() const
321 Q_D(const QQuickTextInput);
325 void QQuickTextInput::setColor(const QColor &c)
327 Q_D(QQuickTextInput);
330 d->textLayoutDirty = true;
331 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
333 emit colorChanged(c);
339 \qmlproperty color QtQuick2::TextInput::selectionColor
341 The text highlight color, used behind selections.
343 QColor QQuickTextInput::selectionColor() const
345 Q_D(const QQuickTextInput);
346 return d->selectionColor;
349 void QQuickTextInput::setSelectionColor(const QColor &color)
351 Q_D(QQuickTextInput);
352 if (d->selectionColor == color)
355 d->selectionColor = color;
356 d->m_palette.setColor(QPalette::Highlight, d->selectionColor);
357 if (d->hasSelectedText()) {
358 d->textLayoutDirty = true;
359 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
362 emit selectionColorChanged(color);
365 \qmlproperty color QtQuick2::TextInput::selectedTextColor
367 The highlighted text color, used in selections.
369 QColor QQuickTextInput::selectedTextColor() const
371 Q_D(const QQuickTextInput);
372 return d->selectedTextColor;
375 void QQuickTextInput::setSelectedTextColor(const QColor &color)
377 Q_D(QQuickTextInput);
378 if (d->selectedTextColor == color)
381 d->selectedTextColor = color;
382 d->m_palette.setColor(QPalette::HighlightedText, d->selectedTextColor);
383 if (d->hasSelectedText()) {
384 d->textLayoutDirty = true;
385 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
388 emit selectedTextColorChanged(color);
392 \qmlproperty enumeration QtQuick2::TextInput::horizontalAlignment
393 \qmlproperty enumeration QtQuick2::TextInput::effectiveHorizontalAlignment
394 \qmlproperty enumeration QtQuick2::TextInput::verticalAlignment
396 Sets the horizontal alignment of the text within the TextInput item's
397 width and height. By default, the text alignment follows the natural alignment
398 of the text, for example text that is read from left to right will be aligned to
401 TextInput does not have vertical alignment, as the natural height is
402 exactly the height of the single line of text. If you set the height
403 manually to something larger, TextInput will always be top aligned
404 vertically. You can use anchors to align it however you want within
407 The valid values for \c horizontalAlignment are \c TextInput.AlignLeft, \c TextInput.AlignRight and
408 \c TextInput.AlignHCenter.
410 Valid values for \c verticalAlignment are \c TextInput.AlignTop (default),
411 \c TextInput.AlignBottom \c TextInput.AlignVCenter.
413 When using the attached property LayoutMirroring::enabled to mirror application
414 layouts, the horizontal alignment of text will also be mirrored. However, the property
415 \c horizontalAlignment will remain unchanged. To query the effective horizontal alignment
416 of TextInput, use the read-only property \c effectiveHorizontalAlignment.
418 QQuickTextInput::HAlignment QQuickTextInput::hAlign() const
420 Q_D(const QQuickTextInput);
424 void QQuickTextInput::setHAlign(HAlignment align)
426 Q_D(QQuickTextInput);
427 bool forceAlign = d->hAlignImplicit && d->effectiveLayoutMirror;
428 d->hAlignImplicit = false;
429 if (d->setHAlign(align, forceAlign) && isComponentComplete()) {
431 updateCursorRectangle();
435 void QQuickTextInput::resetHAlign()
437 Q_D(QQuickTextInput);
438 d->hAlignImplicit = true;
439 if (d->determineHorizontalAlignment() && isComponentComplete()) {
441 updateCursorRectangle();
445 QQuickTextInput::HAlignment QQuickTextInput::effectiveHAlign() const
447 Q_D(const QQuickTextInput);
448 QQuickTextInput::HAlignment effectiveAlignment = d->hAlign;
449 if (!d->hAlignImplicit && d->effectiveLayoutMirror) {
451 case QQuickTextInput::AlignLeft:
452 effectiveAlignment = QQuickTextInput::AlignRight;
454 case QQuickTextInput::AlignRight:
455 effectiveAlignment = QQuickTextInput::AlignLeft;
461 return effectiveAlignment;
464 bool QQuickTextInputPrivate::setHAlign(QQuickTextInput::HAlignment alignment, bool forceAlign)
466 Q_Q(QQuickTextInput);
467 if ((hAlign != alignment || forceAlign) && alignment <= QQuickTextInput::AlignHCenter) { // justify not supported
468 QQuickTextInput::HAlignment oldEffectiveHAlign = q->effectiveHAlign();
470 emit q->horizontalAlignmentChanged(alignment);
471 if (oldEffectiveHAlign != q->effectiveHAlign())
472 emit q->effectiveHorizontalAlignmentChanged();
478 bool QQuickTextInputPrivate::determineHorizontalAlignment()
480 if (hAlignImplicit) {
481 // if no explicit alignment has been set, follow the natural layout direction of the text
482 QString text = q_func()->text();
484 text = m_textLayout.preeditAreaText();
485 bool isRightToLeft = text.isEmpty() ? qApp->inputPanel()->inputDirection() == Qt::RightToLeft
486 : text.isRightToLeft();
487 return setHAlign(isRightToLeft ? QQuickTextInput::AlignRight : QQuickTextInput::AlignLeft);
492 QQuickTextInput::VAlignment QQuickTextInput::vAlign() const
494 Q_D(const QQuickTextInput);
498 void QQuickTextInput::setVAlign(QQuickTextInput::VAlignment alignment)
500 Q_D(QQuickTextInput);
501 if (alignment == d->vAlign)
503 d->vAlign = alignment;
504 emit verticalAlignmentChanged(d->vAlign);
505 if (isComponentComplete()) {
506 updateCursorRectangle();
511 \qmlproperty enumeration QtQuick2::TextInput::wrapMode
513 Set this property to wrap the text to the TextInput item's width.
514 The text will only wrap if an explicit width has been set.
517 \o TextInput.NoWrap - no wrapping will be performed. If the text contains insufficient newlines, then implicitWidth will exceed a set width.
518 \o TextInput.WordWrap - wrapping is done on word boundaries only. If a word is too long, implicitWidth will exceed a set width.
519 \o TextInput.WrapAnywhere - wrapping is done at any point on a line, even if it occurs in the middle of a word.
520 \o TextInput.Wrap - if possible, wrapping occurs at a word boundary; otherwise it will occur at the appropriate point on the line, even in the middle of a word.
523 The default is TextInput.NoWrap. If you set a width, consider using TextInput.Wrap.
525 QQuickTextInput::WrapMode QQuickTextInput::wrapMode() const
527 Q_D(const QQuickTextInput);
531 void QQuickTextInput::setWrapMode(WrapMode mode)
533 Q_D(QQuickTextInput);
534 if (mode == d->wrapMode)
538 updateCursorRectangle();
539 emit wrapModeChanged();
542 void QQuickTextInputPrivate::mirrorChange()
544 Q_Q(QQuickTextInput);
545 if (q->isComponentComplete()) {
546 if (!hAlignImplicit && (hAlign == QQuickTextInput::AlignRight || hAlign == QQuickTextInput::AlignLeft)) {
547 q->updateCursorRectangle();
548 emit q->effectiveHorizontalAlignmentChanged();
554 \qmlproperty bool QtQuick2::TextInput::readOnly
556 Sets whether user input can modify the contents of the TextInput.
558 If readOnly is set to true, then user input will not affect the text
559 property. Any bindings or attempts to set the text property will still
562 bool QQuickTextInput::isReadOnly() const
564 Q_D(const QQuickTextInput);
565 return d->m_readOnly;
568 void QQuickTextInput::setReadOnly(bool ro)
570 Q_D(QQuickTextInput);
571 if (d->m_readOnly == ro)
574 setFlag(QQuickItem::ItemAcceptsInputMethod, !ro);
577 d->setCursorPosition(d->end());
579 d->emitUndoRedoChanged();
580 emit readOnlyChanged(ro);
584 \qmlproperty int QtQuick2::TextInput::maximumLength
585 The maximum permitted length of the text in the TextInput.
587 If the text is too long, it is truncated at the limit.
589 By default, this property contains a value of 32767.
591 int QQuickTextInput::maxLength() const
593 Q_D(const QQuickTextInput);
594 return d->m_maxLength;
597 void QQuickTextInput::setMaxLength(int ml)
599 Q_D(QQuickTextInput);
600 if (d->m_maxLength == ml || d->m_maskData)
604 d->internalSetText(d->m_text, -1, false);
606 emit maximumLengthChanged(ml);
610 \qmlproperty bool QtQuick2::TextInput::cursorVisible
611 Set to true when the TextInput shows a cursor.
613 This property is set and unset when the TextInput gets active focus, so that other
614 properties can be bound to whether the cursor is currently showing. As it
615 gets set and unset automatically, when you set the value yourself you must
616 keep in mind that your value may be overwritten.
618 It can be set directly in script, for example if a KeyProxy might
619 forward keys to it and you desire it to look active when this happens
620 (but without actually giving it active focus).
622 It should not be set directly on the element, like in the below QML,
623 as the specified value will be overridden an lost on focus changes.
632 In the above snippet the cursor will still become visible when the
633 TextInput gains active focus.
635 bool QQuickTextInput::isCursorVisible() const
637 Q_D(const QQuickTextInput);
638 return d->cursorVisible;
641 void QQuickTextInput::setCursorVisible(bool on)
643 Q_D(QQuickTextInput);
644 if (d->cursorVisible == on)
646 d->cursorVisible = on;
647 d->setCursorBlinkPeriod(on ? qApp->styleHints()->cursorFlashTime() : 0);
648 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
650 emit cursorVisibleChanged(d->cursorVisible);
654 \qmlproperty int QtQuick2::TextInput::cursorPosition
655 The position of the cursor in the TextInput.
657 int QQuickTextInput::cursorPosition() const
659 Q_D(const QQuickTextInput);
663 void QQuickTextInput::setCursorPosition(int cp)
665 Q_D(QQuickTextInput);
666 if (cp < 0 || cp > text().length())
672 \qmlproperty rectangle QtQuick2::TextInput::cursorRectangle
674 The rectangle where the standard text cursor is rendered within the text input. Read only.
676 The position and height of a custom cursorDelegate are updated to follow the cursorRectangle
677 automatically when it changes. The width of the delegate is unaffected by changes in the
681 QRect QQuickTextInput::cursorRectangle() const
683 Q_D(const QQuickTextInput);
686 if (d->m_preeditCursor != -1)
687 c += d->m_preeditCursor;
688 if (d->m_echoMode == NoEcho)
690 QTextLine l = d->m_textLayout.lineForTextPosition(c);
694 qRound(l.cursorToX(c) - d->hscroll),
695 qRound(l.y() - d->vscroll),
701 \qmlproperty int QtQuick2::TextInput::selectionStart
703 The cursor position before the first character in the current selection.
705 This property is read-only. To change the selection, use select(start,end),
706 selectAll(), or selectWord().
708 \sa selectionEnd, cursorPosition, selectedText
710 int QQuickTextInput::selectionStart() const
712 Q_D(const QQuickTextInput);
713 return d->lastSelectionStart;
716 \qmlproperty int QtQuick2::TextInput::selectionEnd
718 The cursor position after the last character in the current selection.
720 This property is read-only. To change the selection, use select(start,end),
721 selectAll(), or selectWord().
723 \sa selectionStart, cursorPosition, selectedText
725 int QQuickTextInput::selectionEnd() const
727 Q_D(const QQuickTextInput);
728 return d->lastSelectionEnd;
731 \qmlmethod void QtQuick2::TextInput::select(int start, int end)
733 Causes the text from \a start to \a end to be selected.
735 If either start or end is out of range, the selection is not changed.
737 After calling this, selectionStart will become the lesser
738 and selectionEnd will become the greater (regardless of the order passed
741 \sa selectionStart, selectionEnd
743 void QQuickTextInput::select(int start, int end)
745 Q_D(QQuickTextInput);
746 if (start < 0 || end < 0 || start > d->m_text.length() || end > d->m_text.length())
748 d->setSelection(start, end-start);
752 \qmlproperty string QtQuick2::TextInput::selectedText
754 This read-only property provides the text currently selected in the
757 It is equivalent to the following snippet, but is faster and easier
761 myTextInput.text.toString().substring(myTextInput.selectionStart,
762 myTextInput.selectionEnd);
765 QString QQuickTextInput::selectedText() const
767 Q_D(const QQuickTextInput);
768 return d->selectedText();
772 \qmlproperty bool QtQuick2::TextInput::activeFocusOnPress
774 Whether the TextInput should gain active focus on a mouse press. By default this is
777 bool QQuickTextInput::focusOnPress() const
779 Q_D(const QQuickTextInput);
780 return d->focusOnPress;
783 void QQuickTextInput::setFocusOnPress(bool b)
785 Q_D(QQuickTextInput);
786 if (d->focusOnPress == b)
791 emit activeFocusOnPressChanged(d->focusOnPress);
794 \qmlproperty bool QtQuick2::TextInput::autoScroll
796 Whether the TextInput should scroll when the text is longer than the width. By default this is
799 bool QQuickTextInput::autoScroll() const
801 Q_D(const QQuickTextInput);
802 return d->autoScroll;
805 void QQuickTextInput::setAutoScroll(bool b)
807 Q_D(QQuickTextInput);
808 if (d->autoScroll == b)
812 //We need to repaint so that the scrolling is taking into account.
813 updateCursorRectangle();
814 emit autoScrollChanged(d->autoScroll);
817 #ifndef QT_NO_VALIDATOR
820 \qmlclass IntValidator QIntValidator
821 \inqmlmodule QtQuick 2
822 \ingroup qml-basic-visual-elements
824 This element provides a validator for integer values.
826 IntValidator uses the \l {QLocale::setDefault()}{default locale} to interpret the number and
827 will accept locale specific digits, group separators, and positive and negative signs. In
828 addition, IntValidator is always guaranteed to accept a number formatted according to the "C"
832 \qmlproperty int QtQuick2::IntValidator::top
834 This property holds the validator's highest acceptable value.
835 By default, this property's value is derived from the highest signed integer available (typically 2147483647).
838 \qmlproperty int QtQuick2::IntValidator::bottom
840 This property holds the validator's lowest acceptable value.
841 By default, this property's value is derived from the lowest signed integer available (typically -2147483647).
845 \qmlclass DoubleValidator QDoubleValidator
846 \inqmlmodule QtQuick 2
847 \ingroup qml-basic-visual-elements
849 This element provides a validator for non-integer numbers.
851 Input is accepted if it contains a double that is within the valid range
852 and is in the correct format.
854 Input is accepected but invalid if it contains a double that is outside
855 the range or is in the wrong format; e.g. with too many digits after the
856 decimal point or is empty.
858 Input is rejected if it is not a double.
860 Note: If the valid range consists of just positive doubles (e.g. 0.0 to
861 100.0) and input is a negative double then it is rejected. If \l notation
862 is set to DoubleValidator.StandardNotation, and the input contains more
863 digits before the decimal point than a double in the valid range may have,
864 it is also rejected. If \l notation is DoubleValidator.ScientificNotation,
865 and the input is not in the valid range, it is accecpted but invalid. The
866 value may yet become valid by changing the exponent.
870 \qmlproperty real QtQuick2::DoubleValidator::top
872 This property holds the validator's maximum acceptable value.
873 By default, this property contains a value of infinity.
876 \qmlproperty real QtQuick2::DoubleValidator::bottom
878 This property holds the validator's minimum acceptable value.
879 By default, this property contains a value of -infinity.
882 \qmlproperty int QtQuick2::DoubleValidator::decimals
884 This property holds the validator's maximum number of digits after the decimal point.
885 By default, this property contains a value of 1000.
888 \qmlproperty enumeration QtQuick2::DoubleValidator::notation
889 This property holds the notation of how a string can describe a number.
891 The possible values for this property are:
894 \o DoubleValidator.StandardNotation
895 \o DoubleValidator.ScientificNotation (default)
898 If this property is set to DoubleValidator.ScientificNotation, the written number may have an exponent part (e.g. 1.5E-2).
902 \qmlclass RegExpValidator QRegExpValidator
903 \inqmlmodule QtQuick 2
904 \ingroup qml-basic-visual-elements
906 This element provides a validator, which counts as valid any string which
907 matches a specified regular expression.
910 \qmlproperty regExp QtQuick2::RegExpValidator::regExp
912 This property holds the regular expression used for validation.
914 Note that this property should be a regular expression in JS syntax, e.g /a/ for the regular expression
917 By default, this property contains a regular expression with the pattern .* that matches any string.
921 \qmlproperty Validator QtQuick2::TextInput::validator
923 Allows you to set a validator on the TextInput. When a validator is set
924 the TextInput will only accept input which leaves the text property in
925 an acceptable or intermediate state. The accepted signal will only be sent
926 if the text is in an acceptable state when enter is pressed.
928 Currently supported validators are IntValidator, DoubleValidator and
929 RegExpValidator. An example of using validators is shown below, which allows
930 input of integers between 11 and 31 into the text input:
935 validator: IntValidator{bottom: 11; top: 31;}
940 \sa acceptableInput, inputMask
943 QValidator* QQuickTextInput::validator() const
945 Q_D(const QQuickTextInput);
946 return d->m_validator;
949 void QQuickTextInput::setValidator(QValidator* v)
951 Q_D(QQuickTextInput);
952 if (d->m_validator == v)
957 if (isComponentComplete())
960 emit validatorChanged();
963 #endif // QT_NO_VALIDATOR
965 void QQuickTextInputPrivate::checkIsValid()
967 Q_Q(QQuickTextInput);
969 ValidatorState state = hasAcceptableInput(m_text);
970 m_validInput = state != InvalidInput;
971 if (state != AcceptableInput) {
972 if (m_acceptableInput) {
973 m_acceptableInput = false;
974 emit q->acceptableInputChanged();
976 } else if (!m_acceptableInput) {
977 m_acceptableInput = true;
978 emit q->acceptableInputChanged();
983 \qmlproperty string QtQuick2::TextInput::inputMask
985 Allows you to set an input mask on the TextInput, restricting the allowable
986 text inputs. See QLineEdit::inputMask for further details, as the exact
987 same mask strings are used by TextInput.
989 \sa acceptableInput, validator
991 QString QQuickTextInput::inputMask() const
993 Q_D(const QQuickTextInput);
994 return d->inputMask();
997 void QQuickTextInput::setInputMask(const QString &im)
999 Q_D(QQuickTextInput);
1000 if (d->inputMask() == im)
1003 d->setInputMask(im);
1004 emit inputMaskChanged(d->inputMask());
1008 \qmlproperty bool QtQuick2::TextInput::acceptableInput
1010 This property is always true unless a validator or input mask has been set.
1011 If a validator or input mask has been set, this property will only be true
1012 if the current text is acceptable to the validator or input mask as a final
1013 string (not as an intermediate string).
1015 bool QQuickTextInput::hasAcceptableInput() const
1017 Q_D(const QQuickTextInput);
1018 return d->hasAcceptableInput(d->m_text) == QQuickTextInputPrivate::AcceptableInput;
1022 \qmlsignal QtQuick2::TextInput::onAccepted()
1024 This handler is called when the Return or Enter key is pressed.
1025 Note that if there is a \l validator or \l inputMask set on the text
1026 input, the handler will only be emitted if the input is in an acceptable
1030 void QQuickTextInputPrivate::updateInputMethodHints()
1032 Q_Q(QQuickTextInput);
1033 Qt::InputMethodHints hints = inputMethodHints;
1034 if (m_echoMode == QQuickTextInput::Password || m_echoMode == QQuickTextInput::NoEcho)
1035 hints |= Qt::ImhHiddenText;
1036 else if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit)
1037 hints &= ~Qt::ImhHiddenText;
1038 if (m_echoMode != QQuickTextInput::Normal)
1039 hints |= (Qt::ImhNoAutoUppercase | Qt::ImhNoPredictiveText | Qt::ImhSensitiveData);
1040 q->setInputMethodHints(hints);
1043 \qmlproperty enumeration QtQuick2::TextInput::echoMode
1045 Specifies how the text should be displayed in the TextInput.
1047 \o TextInput.Normal - Displays the text as it is. (Default)
1048 \o TextInput.Password - Displays asterisks instead of characters.
1049 \o TextInput.NoEcho - Displays nothing.
1050 \o TextInput.PasswordEchoOnEdit - Displays characters as they are entered
1051 while editing, otherwise displays asterisks.
1054 QQuickTextInput::EchoMode QQuickTextInput::echoMode() const
1056 Q_D(const QQuickTextInput);
1057 return QQuickTextInput::EchoMode(d->m_echoMode);
1060 void QQuickTextInput::setEchoMode(QQuickTextInput::EchoMode echo)
1062 Q_D(QQuickTextInput);
1063 if (echoMode() == echo)
1065 d->cancelPasswordEchoTimer();
1066 d->m_echoMode = echo;
1067 d->m_passwordEchoEditing = false;
1068 d->updateInputMethodHints();
1069 d->updateDisplayText();
1070 updateCursorRectangle();
1072 emit echoModeChanged(echoMode());
1076 \qmlproperty enumeration QtQuick2::TextInput::inputMethodHints
1078 Provides hints to the input method about the expected content of the text input and how it
1081 The value is a bit-wise combination of flags, or Qt.ImhNone if no hints are set.
1083 Flags that alter behaviour are:
1086 \o Qt.ImhHiddenText - Characters should be hidden, as is typically used when entering passwords.
1087 This is automatically set when setting echoMode to \c TextInput.Password.
1088 \o Qt.ImhSensitiveData - Typed text should not be stored by the active input method
1089 in any persistent storage like predictive user dictionary.
1090 \o Qt.ImhNoAutoUppercase - The input method should not try to automatically switch to upper case
1091 when a sentence ends.
1092 \o Qt.ImhPreferNumbers - Numbers are preferred (but not required).
1093 \o Qt.ImhPreferUppercase - Upper case letters are preferred (but not required).
1094 \o Qt.ImhPreferLowercase - Lower case letters are preferred (but not required).
1095 \o Qt.ImhNoPredictiveText - Do not use predictive text (i.e. dictionary lookup) while typing.
1097 \o Qt.ImhDate - The text editor functions as a date field.
1098 \o Qt.ImhTime - The text editor functions as a time field.
1101 Flags that restrict input (exclusive flags) are:
1104 \o Qt.ImhDigitsOnly - Only digits are allowed.
1105 \o Qt.ImhFormattedNumbersOnly - Only number input is allowed. This includes decimal point and minus sign.
1106 \o Qt.ImhUppercaseOnly - Only upper case letter input is allowed.
1107 \o Qt.ImhLowercaseOnly - Only lower case letter input is allowed.
1108 \o Qt.ImhDialableCharactersOnly - Only characters suitable for phone dialing are allowed.
1109 \o Qt.ImhEmailCharactersOnly - Only characters suitable for email addresses are allowed.
1110 \o Qt.ImhUrlCharactersOnly - Only characters suitable for URLs are allowed.
1116 \o Qt.ImhExclusiveInputMask - This mask yields nonzero if any of the exclusive flags are used.
1120 Qt::InputMethodHints QQuickTextInput::imHints() const
1122 Q_D(const QQuickTextInput);
1123 return d->inputMethodHints;
1126 void QQuickTextInput::setIMHints(Qt::InputMethodHints hints)
1128 Q_D(QQuickTextInput);
1129 if (d->inputMethodHints == hints)
1131 d->inputMethodHints = hints;
1132 d->updateInputMethodHints();
1136 \qmlproperty Component QtQuick2::TextInput::cursorDelegate
1137 The delegate for the cursor in the TextInput.
1139 If you set a cursorDelegate for a TextInput, this delegate will be used for
1140 drawing the cursor instead of the standard cursor. An instance of the
1141 delegate will be created and managed by the TextInput when a cursor is
1142 needed, and the x property of delegate instance will be set so as
1143 to be one pixel before the top left of the current character.
1145 Note that the root item of the delegate component must be a QDeclarativeItem or
1146 QDeclarativeItem derived item.
1148 QDeclarativeComponent* QQuickTextInput::cursorDelegate() const
1150 Q_D(const QQuickTextInput);
1151 return d->cursorComponent;
1154 void QQuickTextInput::setCursorDelegate(QDeclarativeComponent* c)
1156 Q_D(QQuickTextInput);
1157 if (d->cursorComponent == c)
1160 d->cursorComponent = c;
1162 //note that the components are owned by something else
1163 delete d->cursorItem;
1165 d->startCreatingCursor();
1168 emit cursorDelegateChanged();
1171 void QQuickTextInputPrivate::startCreatingCursor()
1173 Q_Q(QQuickTextInput);
1174 if (cursorComponent->isReady()) {
1176 } else if (cursorComponent->isLoading()) {
1177 q->connect(cursorComponent, SIGNAL(statusChanged(int)),
1178 q, SLOT(createCursor()));
1180 qmlInfo(q, cursorComponent->errors()) << QQuickTextInput::tr("Could not load cursor delegate");
1184 void QQuickTextInput::createCursor()
1186 Q_D(QQuickTextInput);
1187 if (!isComponentComplete())
1190 if (d->cursorComponent->isError()) {
1191 qmlInfo(this, d->cursorComponent->errors()) << tr("Could not load cursor delegate");
1195 if (!d->cursorComponent->isReady())
1199 delete d->cursorItem;
1200 QDeclarativeContext *creationContext = d->cursorComponent->creationContext();
1201 QObject *object = d->cursorComponent->create(creationContext ? creationContext : qmlContext(this));
1202 d->cursorItem = qobject_cast<QQuickItem*>(object);
1203 if (!d->cursorItem) {
1205 qmlInfo(this, d->cursorComponent->errors()) << tr("Could not instantiate cursor delegate");
1209 QRectF r = cursorRectangle();
1211 QDeclarative_setParent_noEvent(d->cursorItem, this);
1212 d->cursorItem->setParentItem(this);
1213 d->cursorItem->setPos(r.topLeft());
1214 d->cursorItem->setHeight(r.height());
1218 \qmlmethod rect QtQuick2::TextInput::positionToRectangle(int pos)
1220 This function takes a character position and returns the rectangle that the
1221 cursor would occupy, if it was placed at that character position.
1223 This is similar to setting the cursorPosition, and then querying the cursor
1224 rectangle, but the cursorPosition is not changed.
1226 QRectF QQuickTextInput::positionToRectangle(int pos) const
1228 Q_D(const QQuickTextInput);
1229 if (pos > d->m_cursor)
1230 pos += d->preeditAreaText().length();
1231 QTextLine l = d->m_textLayout.lineAt(0);
1233 ? QRectF(l.cursorToX(pos) - d->hscroll, 0.0, d->m_cursorWidth, l.height())
1238 \qmlmethod int QtQuick2::TextInput::positionAt(real x, real y, CursorPosition position = CursorBetweenCharacters)
1240 This function returns the character position at
1241 x and y pixels from the top left of the textInput. Position 0 is before the
1242 first character, position 1 is after the first character but before the second,
1243 and so on until position text.length, which is after all characters.
1245 This means that for all x values before the first character this function returns 0,
1246 and for all x values after the last character this function returns text.length. If
1247 the y value is above the text the position will be that of the nearest character on
1248 the first line line and if it is below the text the position of the nearest character
1249 on the last line will be returned.
1251 The cursor position type specifies how the cursor position should be resolved.
1254 \o TextInput.CursorBetweenCharacters - Returns the position between characters that is nearest x.
1255 \o TextInput.CursorOnCharacter - Returns the position before the character that is nearest x.
1259 void QQuickTextInput::positionAt(QDeclarativeV8Function *args) const
1261 Q_D(const QQuickTextInput);
1265 QTextLine::CursorPosition position = QTextLine::CursorBetweenCharacters;
1267 if (args->Length() < 1)
1271 v8::Local<v8::Value> arg = (*args)[i];
1272 x = arg->NumberValue();
1274 if (++i < args->Length()) {
1276 y = arg->NumberValue();
1279 if (++i < args->Length()) {
1281 position = QTextLine::CursorPosition(arg->Int32Value());
1284 int pos = d->positionAt(x, y, position);
1285 const int cursor = d->m_cursor;
1287 const int preeditLength = d->preeditAreaText().length();
1288 pos = pos > cursor + preeditLength
1289 ? pos - preeditLength
1292 args->returnValue(v8::Int32::New(pos));
1295 int QQuickTextInputPrivate::positionAt(int x, int y, QTextLine::CursorPosition position) const
1299 QTextLine line = m_textLayout.lineAt(0);
1300 for (int i = 1; i < m_textLayout.lineCount(); ++i) {
1301 QTextLine nextLine = m_textLayout.lineAt(i);
1303 if (y < (line.rect().bottom() + nextLine.y()) / 2)
1307 return line.isValid() ? line.xToCursor(x, position) : 0;
1310 void QQuickTextInput::keyPressEvent(QKeyEvent* ev)
1312 Q_D(QQuickTextInput);
1313 // Don't allow MacOSX up/down support, and we don't allow a completer.
1314 bool ignore = (ev->key() == Qt::Key_Up || ev->key() == Qt::Key_Down) && ev->modifiers() == Qt::NoModifier;
1315 if (!ignore && (d->lastSelectionStart == d->lastSelectionEnd) && (ev->key() == Qt::Key_Right || ev->key() == Qt::Key_Left)) {
1316 // Ignore when moving off the end unless there is a selection,
1317 // because then moving will do something (deselect).
1318 int cursorPosition = d->m_cursor;
1319 if (cursorPosition == 0)
1320 ignore = ev->key() == (d->layoutDirection() == Qt::LeftToRight ? Qt::Key_Left : Qt::Key_Right);
1321 if (cursorPosition == text().length())
1322 ignore = ev->key() == (d->layoutDirection() == Qt::LeftToRight ? Qt::Key_Right : Qt::Key_Left);
1327 d->processKeyEvent(ev);
1329 if (!ev->isAccepted())
1330 QQuickImplicitSizeItem::keyPressEvent(ev);
1333 void QQuickTextInput::inputMethodEvent(QInputMethodEvent *ev)
1335 Q_D(QQuickTextInput);
1336 const bool wasComposing = d->preeditAreaText().length() > 0;
1337 if (d->m_readOnly) {
1340 d->processInputMethodEvent(ev);
1342 if (!ev->isAccepted())
1343 QQuickImplicitSizeItem::inputMethodEvent(ev);
1345 if (wasComposing != (d->m_textLayout.preeditAreaText().length() > 0))
1346 emit inputMethodComposingChanged();
1349 void QQuickTextInput::mouseDoubleClickEvent(QMouseEvent *event)
1351 Q_D(QQuickTextInput);
1353 if (d->selectByMouse && event->button() == Qt::LeftButton) {
1355 int cursor = d->positionAt(event->localPos());
1356 d->selectWordAtPos(cursor);
1357 event->setAccepted(true);
1358 if (!d->hasPendingTripleClick()) {
1359 d->tripleClickStartPoint = event->localPos().toPoint();
1360 d->tripleClickTimer.start();
1363 if (d->sendMouseEventToInputContext(event))
1365 QQuickImplicitSizeItem::mouseDoubleClickEvent(event);
1369 void QQuickTextInput::mousePressEvent(QMouseEvent *event)
1371 Q_D(QQuickTextInput);
1373 d->pressPos = event->localPos();
1375 if (d->focusOnPress) {
1376 bool hadActiveFocus = hasActiveFocus();
1378 // re-open input panel on press if already focused
1379 if (hasActiveFocus() && hadActiveFocus && !d->m_readOnly)
1380 openSoftwareInputPanel();
1382 if (d->selectByMouse) {
1383 setKeepMouseGrab(false);
1384 d->selectPressed = true;
1385 QPoint distanceVector = d->pressPos.toPoint() - d->tripleClickStartPoint;
1386 if (d->hasPendingTripleClick()
1387 && distanceVector.manhattanLength() < qApp->styleHints()->startDragDistance()) {
1388 event->setAccepted(true);
1394 if (d->sendMouseEventToInputContext(event))
1397 bool mark = (event->modifiers() & Qt::ShiftModifier) && d->selectByMouse;
1398 int cursor = d->positionAt(event->localPos());
1399 d->moveCursor(cursor, mark);
1400 event->setAccepted(true);
1403 void QQuickTextInput::mouseMoveEvent(QMouseEvent *event)
1405 Q_D(QQuickTextInput);
1407 if (d->selectPressed) {
1408 if (qAbs(int(event->localPos().x() - d->pressPos.x())) > qApp->styleHints()->startDragDistance())
1409 setKeepMouseGrab(true);
1411 if (d->composeMode()) {
1413 int startPos = d->positionAt(d->pressPos);
1414 int currentPos = d->positionAt(event->localPos());
1415 if (startPos != currentPos)
1416 d->setSelection(startPos, currentPos - startPos);
1418 moveCursorSelection(d->positionAt(event->localPos()), d->mouseSelectionMode);
1420 event->setAccepted(true);
1422 QQuickImplicitSizeItem::mouseMoveEvent(event);
1426 void QQuickTextInput::mouseReleaseEvent(QMouseEvent *event)
1428 Q_D(QQuickTextInput);
1429 if (d->sendMouseEventToInputContext(event))
1431 if (d->selectPressed) {
1432 d->selectPressed = false;
1433 setKeepMouseGrab(false);
1435 #ifndef QT_NO_CLIPBOARD
1436 if (QGuiApplication::clipboard()->supportsSelection()) {
1437 if (event->button() == Qt::LeftButton) {
1438 d->copy(QClipboard::Selection);
1439 } else if (!d->m_readOnly && event->button() == Qt::MidButton) {
1441 d->insert(QGuiApplication::clipboard()->text(QClipboard::Selection));
1445 if (!event->isAccepted())
1446 QQuickImplicitSizeItem::mouseReleaseEvent(event);
1449 bool QQuickTextInputPrivate::sendMouseEventToInputContext(QMouseEvent *event)
1451 #if !defined QT_NO_IM
1452 if (composeMode()) {
1453 int tmp_cursor = positionAt(event->localPos());
1454 int mousePos = tmp_cursor - m_cursor;
1455 if (mousePos >= 0 && mousePos <= m_textLayout.preeditAreaText().length()) {
1456 if (event->type() == QEvent::MouseButtonRelease) {
1457 qApp->inputPanel()->invokeAction(QInputPanel::Click, mousePos);
1470 void QQuickTextInput::mouseUngrabEvent()
1472 Q_D(QQuickTextInput);
1473 d->selectPressed = false;
1474 setKeepMouseGrab(false);
1477 bool QQuickTextInput::event(QEvent* ev)
1479 #ifndef QT_NO_SHORTCUT
1480 Q_D(QQuickTextInput);
1481 if (ev->type() == QEvent::ShortcutOverride) {
1484 QKeyEvent* ke = static_cast<QKeyEvent*>(ev);
1485 if (ke == QKeySequence::Copy
1486 || ke == QKeySequence::Paste
1487 || ke == QKeySequence::Cut
1488 || ke == QKeySequence::Redo
1489 || ke == QKeySequence::Undo
1490 || ke == QKeySequence::MoveToNextWord
1491 || ke == QKeySequence::MoveToPreviousWord
1492 || ke == QKeySequence::MoveToStartOfDocument
1493 || ke == QKeySequence::MoveToEndOfDocument
1494 || ke == QKeySequence::SelectNextWord
1495 || ke == QKeySequence::SelectPreviousWord
1496 || ke == QKeySequence::SelectStartOfLine
1497 || ke == QKeySequence::SelectEndOfLine
1498 || ke == QKeySequence::SelectStartOfBlock
1499 || ke == QKeySequence::SelectEndOfBlock
1500 || ke == QKeySequence::SelectStartOfDocument
1501 || ke == QKeySequence::SelectAll
1502 || ke == QKeySequence::SelectEndOfDocument) {
1504 } else if (ke->modifiers() == Qt::NoModifier || ke->modifiers() == Qt::ShiftModifier
1505 || ke->modifiers() == Qt::KeypadModifier) {
1506 if (ke->key() < Qt::Key_Escape) {
1510 switch (ke->key()) {
1511 case Qt::Key_Delete:
1514 case Qt::Key_Backspace:
1526 return QQuickImplicitSizeItem::event(ev);
1529 void QQuickTextInput::geometryChanged(const QRectF &newGeometry,
1530 const QRectF &oldGeometry)
1532 Q_D(QQuickTextInput);
1533 if (newGeometry.width() != oldGeometry.width())
1535 updateCursorRectangle();
1536 QQuickImplicitSizeItem::geometryChanged(newGeometry, oldGeometry);
1539 void QQuickTextInputPrivate::updateHorizontalScroll()
1541 Q_Q(QQuickTextInput);
1542 QTextLine currentLine = m_textLayout.lineForTextPosition(m_cursor + m_preeditCursor);
1543 const int preeditLength = m_textLayout.preeditAreaText().length();
1544 const int width = qMax(0, qFloor(q->width()));
1545 int widthUsed = currentLine.isValid() ? qRound(currentLine.naturalTextWidth()) : 0;
1546 int previousScroll = hscroll;
1548 if (!autoScroll || widthUsed <= width || m_echoMode == QQuickTextInput::NoEcho) {
1551 Q_ASSERT(currentLine.isValid());
1552 int cix = qRound(currentLine.cursorToX(m_cursor + preeditLength));
1553 if (cix - hscroll >= width) {
1554 // text doesn't fit, cursor is to the right of br (scroll right)
1555 hscroll = cix - width;
1556 } else if (cix - hscroll < 0 && hscroll < widthUsed) {
1557 // text doesn't fit, cursor is to the left of br (scroll left)
1559 } else if (widthUsed - hscroll < width) {
1560 // text doesn't fit, text document is to the left of br; align
1562 hscroll = widthUsed - width;
1564 if (preeditLength > 0) {
1565 // check to ensure long pre-edit text doesn't push the cursor
1567 cix = qRound(currentLine.cursorToX(m_cursor + qMax(0, m_preeditCursor - 1)));
1572 if (previousScroll != hscroll)
1573 textLayoutDirty = true;
1576 void QQuickTextInputPrivate::updateVerticalScroll()
1578 Q_Q(QQuickTextInput);
1579 const int preeditLength = m_textLayout.preeditAreaText().length();
1580 const int height = qMax(0, qFloor(q->height()));
1581 int heightUsed = boundingRect.height();
1582 int previousScroll = vscroll;
1584 if (!autoScroll || heightUsed <= height) {
1585 // text fits in br; use vscroll for alignment
1586 switch (vAlign & ~(Qt::AlignAbsolute|Qt::AlignHorizontal_Mask)) {
1587 case Qt::AlignBottom:
1588 vscroll = heightUsed - height;
1590 case Qt::AlignVCenter:
1591 vscroll = (heightUsed - height) / 2;
1599 QTextLine currentLine = m_textLayout.lineForTextPosition(m_cursor + preeditLength);
1600 QRectF r = currentLine.isValid() ? currentLine.rect() : QRectF();
1601 int top = qFloor(r.top());
1602 int bottom = qCeil(r.bottom());
1604 if (bottom - vscroll >= height) {
1605 // text doesn't fit, cursor is to the below the br (scroll down)
1606 vscroll = bottom - height;
1607 } else if (top - vscroll < 0 && vscroll < heightUsed) {
1608 // text doesn't fit, cursor is above br (scroll up)
1610 } else if (heightUsed - vscroll < height) {
1611 // text doesn't fit, text document is to the left of br; align
1613 vscroll = heightUsed - height;
1615 if (preeditLength > 0) {
1616 // check to ensure long pre-edit text doesn't push the cursor
1618 currentLine = m_textLayout.lineForTextPosition(m_cursor + qMax(0, m_preeditCursor - 1));
1619 top = currentLine.isValid() ? qRound(currentLine.rect().top()) : 0;
1624 if (previousScroll != vscroll)
1625 textLayoutDirty = true;
1628 void QQuickTextInput::triggerPreprocess()
1630 Q_D(QQuickTextInput);
1631 if (d->updateType == QQuickTextInputPrivate::UpdateNone)
1632 d->updateType = QQuickTextInputPrivate::UpdateOnlyPreprocess;
1636 QSGNode *QQuickTextInput::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data)
1639 Q_D(QQuickTextInput);
1641 if (d->updateType != QQuickTextInputPrivate::UpdatePaintNode && oldNode != 0) {
1642 // Update done in preprocess() in the nodes
1643 d->updateType = QQuickTextInputPrivate::UpdateNone;
1647 d->updateType = QQuickTextInputPrivate::UpdateNone;
1649 QQuickTextNode *node = static_cast<QQuickTextNode *>(oldNode);
1651 node = new QQuickTextNode(QQuickItemPrivate::get(this)->sceneGraphContext(), this);
1654 if (!d->textLayoutDirty) {
1655 QSGSimpleRectNode *cursorNode = node->cursorNode();
1656 if (cursorNode != 0 && !isReadOnly()) {
1657 cursorNode->setRect(cursorRectangle());
1659 if (!d->cursorVisible || (!d->m_blinkStatus && d->m_blinkPeriod > 0)) {
1666 node->deleteContent();
1667 node->setMatrix(QMatrix4x4());
1669 QPoint offset = QPoint(0,0);
1670 QFontMetrics fm = QFontMetrics(d->font);
1671 if (d->autoScroll) {
1672 // the y offset is there to keep the baseline constant in case we have script changes in the text.
1673 offset = -QPoint(d->hscroll, d->vscroll + d->m_ascent - fm.ascent());
1675 offset = -QPoint(d->hscroll, d->vscroll);
1678 if (!d->m_textLayout.text().isEmpty() || !d->m_textLayout.preeditAreaText().isEmpty()) {
1679 node->addTextLayout(offset, &d->m_textLayout, d->color,
1680 QQuickText::Normal, QColor(),
1681 d->selectionColor, d->selectedTextColor,
1682 d->selectionStart(),
1683 d->selectionEnd() - 1); // selectionEnd() returns first char after
1687 if (!isReadOnly() && d->cursorItem == 0) {
1688 node->setCursor(cursorRectangle(), d->color);
1689 if (!d->cursorVisible || (!d->m_blinkStatus && d->m_blinkPeriod > 0)) {
1696 d->textLayoutDirty = false;
1702 QVariant QQuickTextInput::inputMethodQuery(Qt::InputMethodQuery property) const
1704 Q_D(const QQuickTextInput);
1707 return QVariant((bool)(flags() & ItemAcceptsInputMethod));
1709 return QVariant((int)inputMethodHints());
1710 case Qt::ImCursorRectangle:
1711 return cursorRectangle();
1714 case Qt::ImCursorPosition:
1715 return QVariant(d->m_cursor);
1716 case Qt::ImSurroundingText:
1717 if (d->m_echoMode == PasswordEchoOnEdit && !d->m_passwordEchoEditing) {
1718 return QVariant(displayText());
1720 return QVariant(d->realText());
1722 case Qt::ImCurrentSelection:
1723 return QVariant(selectedText());
1724 case Qt::ImMaximumTextLength:
1725 return QVariant(maxLength());
1726 case Qt::ImAnchorPosition:
1727 if (d->selectionStart() == d->selectionEnd())
1728 return QVariant(d->m_cursor);
1729 else if (d->selectionStart() == d->m_cursor)
1730 return QVariant(d->selectionEnd());
1732 return QVariant(d->selectionStart());
1739 \qmlmethod void QtQuick2::TextInput::deselect()
1741 Removes active text selection.
1743 void QQuickTextInput::deselect()
1745 Q_D(QQuickTextInput);
1750 \qmlmethod void QtQuick2::TextInput::selectAll()
1752 Causes all text to be selected.
1754 void QQuickTextInput::selectAll()
1756 Q_D(QQuickTextInput);
1757 d->setSelection(0, text().length());
1761 \qmlmethod void QtQuick2::TextInput::isRightToLeft(int start, int end)
1763 Returns true if the natural reading direction of the editor text
1764 found between positions \a start and \a end is right to left.
1766 bool QQuickTextInput::isRightToLeft(int start, int end)
1769 qmlInfo(this) << "isRightToLeft(start, end) called with the end property being smaller than the start.";
1772 return text().mid(start, end - start).isRightToLeft();
1776 #ifndef QT_NO_CLIPBOARD
1778 \qmlmethod QtQuick2::TextInput::cut()
1780 Moves the currently selected text to the system clipboard.
1782 void QQuickTextInput::cut()
1784 Q_D(QQuickTextInput);
1790 \qmlmethod QtQuick2::TextInput::copy()
1792 Copies the currently selected text to the system clipboard.
1794 void QQuickTextInput::copy()
1796 Q_D(QQuickTextInput);
1801 \qmlmethod QtQuick2::TextInput::paste()
1803 Replaces the currently selected text by the contents of the system clipboard.
1805 void QQuickTextInput::paste()
1807 Q_D(QQuickTextInput);
1811 #endif // QT_NO_CLIPBOARD
1814 Undoes the last operation if undo is \l {canUndo}{available}. Deselects any
1815 current selection, and updates the selection start to the current cursor
1819 void QQuickTextInput::undo()
1821 Q_D(QQuickTextInput);
1822 if (!d->m_readOnly) {
1824 d->finishChange(-1, true);
1829 Redoes the last operation if redo is \l {canRedo}{available}.
1832 void QQuickTextInput::redo()
1834 Q_D(QQuickTextInput);
1835 if (!d->m_readOnly) {
1842 \qmlmethod void QtQuick2::TextInput::insert(int position, string text)
1844 Inserts \a text into the TextInput at position.
1847 void QQuickTextInput::insert(int position, const QString &text)
1849 Q_D(QQuickTextInput);
1850 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
1851 if (d->m_echoMode == QQuickTextInput::Password)
1852 d->m_passwordEchoTimer.start(qt_passwordEchoDelay, this);
1855 if (position < 0 || position > d->m_text.length())
1858 const int priorState = d->m_undoState;
1860 QString insertText = text;
1862 if (d->hasSelectedText()) {
1863 d->addCommand(QQuickTextInputPrivate::Command(
1864 QQuickTextInputPrivate::SetSelection, d->m_cursor, 0, d->m_selstart, d->m_selend));
1866 if (d->m_maskData) {
1867 insertText = d->maskString(position, insertText);
1868 for (int i = 0; i < insertText.length(); ++i) {
1869 d->addCommand(QQuickTextInputPrivate::Command(
1870 QQuickTextInputPrivate::DeleteSelection, position + i, d->m_text.at(position + i), -1, -1));
1871 d->addCommand(QQuickTextInputPrivate::Command(
1872 QQuickTextInputPrivate::Insert, position + i, insertText.at(i), -1, -1));
1874 d->m_text.replace(position, insertText.length(), insertText);
1875 if (!insertText.isEmpty())
1876 d->m_textDirty = true;
1877 if (position < d->m_selend && position + insertText.length() > d->m_selstart)
1878 d->m_selDirty = true;
1880 int remaining = d->m_maxLength - d->m_text.length();
1881 if (remaining != 0) {
1882 insertText = insertText.left(remaining);
1883 d->m_text.insert(position, insertText);
1884 for (int i = 0; i < insertText.length(); ++i)
1885 d->addCommand(QQuickTextInputPrivate::Command(
1886 QQuickTextInputPrivate::Insert, position + i, insertText.at(i), -1, -1));
1887 if (d->m_cursor >= position)
1888 d->m_cursor += insertText.length();
1889 if (d->m_selstart >= position)
1890 d->m_selstart += insertText.length();
1891 if (d->m_selend >= position)
1892 d->m_selend += insertText.length();
1893 d->m_textDirty = true;
1894 if (position >= d->m_selstart && position <= d->m_selend)
1895 d->m_selDirty = true;
1899 d->addCommand(QQuickTextInputPrivate::Command(
1900 QQuickTextInputPrivate::SetSelection, d->m_cursor, 0, d->m_selstart, d->m_selend));
1901 d->finishChange(priorState);
1903 if (d->lastSelectionStart != d->lastSelectionEnd) {
1904 if (d->m_selstart != d->lastSelectionStart) {
1905 d->lastSelectionStart = d->m_selstart;
1906 emit selectionStartChanged();
1908 if (d->m_selend != d->lastSelectionEnd) {
1909 d->lastSelectionEnd = d->m_selend;
1910 emit selectionEndChanged();
1916 \qmlmethod string QtQuick2::TextInput::getText(int start, int end)
1918 Removes the section of text that is between the \a start and \a end positions from the TextInput.
1921 void QQuickTextInput::remove(int start, int end)
1923 Q_D(QQuickTextInput);
1925 start = qBound(0, start, d->m_text.length());
1926 end = qBound(0, end, d->m_text.length());
1930 else if (start == end)
1933 if (start < d->m_selend && end > d->m_selstart)
1934 d->m_selDirty = true;
1936 const int priorState = d->m_undoState;
1938 d->addCommand(QQuickTextInputPrivate::Command(
1939 QQuickTextInputPrivate::SetSelection, d->m_cursor, 0, d->m_selstart, d->m_selend));
1941 if (start <= d->m_cursor && d->m_cursor < end) {
1942 // cursor is within the selection. Split up the commands
1943 // to be able to restore the correct cursor position
1944 for (int i = d->m_cursor; i >= start; --i) {
1945 d->addCommand(QQuickTextInputPrivate::Command(
1946 QQuickTextInputPrivate::DeleteSelection, i, d->m_text.at(i), -1, 1));
1948 for (int i = end - 1; i > d->m_cursor; --i) {
1949 d->addCommand(QQuickTextInputPrivate::Command(
1950 QQuickTextInputPrivate::DeleteSelection, i - d->m_cursor + start - 1, d->m_text.at(i), -1, -1));
1953 for (int i = end - 1; i >= start; --i) {
1954 d->addCommand(QQuickTextInputPrivate::Command(
1955 QQuickTextInputPrivate::RemoveSelection, i, d->m_text.at(i), -1, -1));
1958 if (d->m_maskData) {
1959 d->m_text.replace(start, end - start, d->clearString(start, end - start));
1960 for (int i = 0; i < end - start; ++i) {
1961 d->addCommand(QQuickTextInputPrivate::Command(
1962 QQuickTextInputPrivate::Insert, start + i, d->m_text.at(start + i), -1, -1));
1965 d->m_text.remove(start, end - start);
1967 if (d->m_cursor > start)
1968 d->m_cursor -= qMin(d->m_cursor, end) - start;
1969 if (d->m_selstart > start)
1970 d->m_selstart -= qMin(d->m_selstart, end) - start;
1971 if (d->m_selend > end)
1972 d->m_selend -= qMin(d->m_selend, end) - start;
1974 d->addCommand(QQuickTextInputPrivate::Command(
1975 QQuickTextInputPrivate::SetSelection, d->m_cursor, 0, d->m_selstart, d->m_selend));
1977 d->m_textDirty = true;
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();
1994 \qmlmethod void QtQuick2::TextInput::selectWord()
1996 Causes the word closest to the current cursor position to be selected.
1998 void QQuickTextInput::selectWord()
2000 Q_D(QQuickTextInput);
2001 d->selectWordAtPos(d->m_cursor);
2005 \qmlproperty bool QtQuick2::TextInput::smooth
2007 This property holds whether the text is smoothly scaled or transformed.
2009 Smooth filtering gives better visual quality, but is slower. If
2010 the item is displayed at its natural size, this property has no visual or
2013 \note Generally scaling artifacts are only visible if the item is stationary on
2014 the screen. A common pattern when animating an item is to disable smooth
2015 filtering at the beginning of the animation and reenable it at the conclusion.
2019 \qmlproperty string QtQuick2::TextInput::passwordCharacter
2021 This is the character displayed when echoMode is set to Password or
2022 PasswordEchoOnEdit. By default it is an asterisk.
2024 If this property is set to a string with more than one character,
2025 the first character is used. If the string is empty, the value
2026 is ignored and the property is not set.
2028 QString QQuickTextInput::passwordCharacter() const
2030 Q_D(const QQuickTextInput);
2031 return QString(d->m_passwordCharacter);
2034 void QQuickTextInput::setPasswordCharacter(const QString &str)
2036 Q_D(QQuickTextInput);
2037 if (str.length() < 1)
2039 d->m_passwordCharacter = str.constData()[0];
2040 if (d->m_echoMode == Password || d->m_echoMode == PasswordEchoOnEdit)
2041 d->updateDisplayText();
2042 emit passwordCharacterChanged();
2046 \qmlproperty string QtQuick2::TextInput::displayText
2048 This is the text displayed in the TextInput.
2050 If \l echoMode is set to TextInput::Normal, this holds the
2051 same value as the TextInput::text property. Otherwise,
2052 this property holds the text visible to the user, while
2053 the \l text property holds the actual entered text.
2055 QString QQuickTextInput::displayText() const
2057 Q_D(const QQuickTextInput);
2058 return d->m_textLayout.text();
2062 \qmlproperty bool QtQuick2::TextInput::selectByMouse
2066 If true, the user can use the mouse to select text in some
2067 platform-specific way. Note that for some platforms this may
2068 not be an appropriate interaction (eg. may conflict with how
2069 the text needs to behave inside a Flickable.
2071 bool QQuickTextInput::selectByMouse() const
2073 Q_D(const QQuickTextInput);
2074 return d->selectByMouse;
2077 void QQuickTextInput::setSelectByMouse(bool on)
2079 Q_D(QQuickTextInput);
2080 if (d->selectByMouse != on) {
2081 d->selectByMouse = on;
2082 emit selectByMouseChanged(on);
2087 \qmlproperty enum QtQuick2::TextInput::mouseSelectionMode
2089 Specifies how text should be selected using a mouse.
2092 \o TextInput.SelectCharacters - The selection is updated with individual characters. (Default)
2093 \o TextInput.SelectWords - The selection is updated with whole words.
2096 This property only applies when \l selectByMouse is true.
2099 QQuickTextInput::SelectionMode QQuickTextInput::mouseSelectionMode() const
2101 Q_D(const QQuickTextInput);
2102 return d->mouseSelectionMode;
2105 void QQuickTextInput::setMouseSelectionMode(SelectionMode mode)
2107 Q_D(QQuickTextInput);
2108 if (d->mouseSelectionMode != mode) {
2109 d->mouseSelectionMode = mode;
2110 emit mouseSelectionModeChanged(mode);
2115 \qmlproperty bool QtQuick2::TextInput::canPaste
2117 Returns true if the TextInput is writable and the content of the clipboard is
2118 suitable for pasting into the TextInput.
2120 bool QQuickTextInput::canPaste() const
2122 Q_D(const QQuickTextInput);
2123 if (!d->canPasteValid) {
2124 if (const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData())
2125 const_cast<QQuickTextInputPrivate *>(d)->canPaste = !d->m_readOnly && mimeData->hasText();
2126 const_cast<QQuickTextInputPrivate *>(d)->canPasteValid = true;
2132 \qmlproperty bool QtQuick2::TextInput::canUndo
2134 Returns true if the TextInput is writable and there are previous operations
2138 bool QQuickTextInput::canUndo() const
2140 Q_D(const QQuickTextInput);
2145 \qmlproperty bool QtQuick2::TextInput::canRedo
2147 Returns true if the TextInput is writable and there are \l {undo}{undone}
2148 operations that can be redone.
2151 bool QQuickTextInput::canRedo() const
2153 Q_D(const QQuickTextInput);
2157 void QQuickTextInput::moveCursorSelection(int position)
2159 Q_D(QQuickTextInput);
2160 d->moveCursor(position, true);
2164 \qmlmethod void QtQuick2::TextInput::moveCursorSelection(int position, SelectionMode mode = TextInput.SelectCharacters)
2166 Moves the cursor to \a position and updates the selection according to the optional \a mode
2167 parameter. (To only move the cursor, set the \l cursorPosition property.)
2169 When this method is called it additionally sets either the
2170 selectionStart or the selectionEnd (whichever was at the previous cursor position)
2171 to the specified position. This allows you to easily extend and contract the selected
2174 The selection mode specifies whether the selection is updated on a per character or a per word
2175 basis. If not specified the selection mode will default to TextInput.SelectCharacters.
2178 \o TextInput.SelectCharacters - Sets either the selectionStart or selectionEnd (whichever was at
2179 the previous cursor position) to the specified position.
2180 \o TextInput.SelectWords - Sets the selectionStart and selectionEnd to include all
2181 words between the specified position and the previous cursor position. Words partially in the
2185 For example, take this sequence of calls:
2189 moveCursorSelection(9, TextInput.SelectCharacters)
2190 moveCursorSelection(7, TextInput.SelectCharacters)
2193 This moves the cursor to position 5, extend the selection end from 5 to 9
2194 and then retract the selection end from 9 to 7, leaving the text from position 5 to 7
2195 selected (the 6th and 7th characters).
2197 The same sequence with TextInput.SelectWords will extend the selection start to a word boundary
2198 before or on position 5 and extend the selection end to a word boundary on or past position 9.
2200 void QQuickTextInput::moveCursorSelection(int pos, SelectionMode mode)
2202 Q_D(QQuickTextInput);
2204 if (mode == SelectCharacters) {
2205 d->moveCursor(pos, true);
2206 } else if (pos != d->m_cursor){
2207 const int cursor = d->m_cursor;
2209 if (!d->hasSelectedText())
2210 anchor = d->m_cursor;
2211 else if (d->selectionStart() == d->m_cursor)
2212 anchor = d->selectionEnd();
2214 anchor = d->selectionStart();
2216 if (anchor < pos || (anchor == pos && cursor < pos)) {
2217 const QString text = this->text();
2218 QTextBoundaryFinder finder(QTextBoundaryFinder::Word, text);
2219 finder.setPosition(anchor);
2221 const QTextBoundaryFinder::BoundaryReasons reasons = finder.boundaryReasons();
2222 if (anchor < text.length() && (!(reasons & QTextBoundaryFinder::StartWord)
2223 || ((reasons & QTextBoundaryFinder::EndWord) && anchor > cursor))) {
2224 finder.toPreviousBoundary();
2226 anchor = finder.position() != -1 ? finder.position() : 0;
2228 finder.setPosition(pos);
2229 if (pos > 0 && !finder.boundaryReasons())
2230 finder.toNextBoundary();
2231 const int cursor = finder.position() != -1 ? finder.position() : text.length();
2233 d->setSelection(anchor, cursor - anchor);
2234 } else if (anchor > pos || (anchor == pos && cursor > pos)) {
2235 const QString text = this->text();
2236 QTextBoundaryFinder finder(QTextBoundaryFinder::Word, text);
2237 finder.setPosition(anchor);
2239 const QTextBoundaryFinder::BoundaryReasons reasons = finder.boundaryReasons();
2240 if (anchor > 0 && (!(reasons & QTextBoundaryFinder::EndWord)
2241 || ((reasons & QTextBoundaryFinder::StartWord) && anchor < cursor))) {
2242 finder.toNextBoundary();
2245 anchor = finder.position() != -1 ? finder.position() : text.length();
2247 finder.setPosition(pos);
2248 if (pos < text.length() && !finder.boundaryReasons())
2249 finder.toPreviousBoundary();
2250 const int cursor = finder.position() != -1 ? finder.position() : 0;
2252 d->setSelection(anchor, cursor - anchor);
2258 \qmlmethod void QtQuick2::TextInput::openSoftwareInputPanel()
2260 Opens software input panels like virtual keyboards for typing, useful for
2261 customizing when you want the input keyboard to be shown and hidden in
2264 By default the opening of input panels follows the platform style. Input panels are
2265 always closed if no editor has active focus.
2267 You can disable the automatic behavior by setting the property \c activeFocusOnPress to false
2268 and use functions openSoftwareInputPanel() and closeSoftwareInputPanel() to implement
2269 the behavior you want.
2271 Only relevant on platforms, which provide virtual keyboards.
2277 text: "Hello world!"
2278 activeFocusOnPress: false
2280 anchors.fill: parent
2282 if (!textInput.activeFocus) {
2283 textInput.forceActiveFocus()
2284 textInput.openSoftwareInputPanel();
2286 textInput.focus = false;
2289 onPressAndHold: textInput.closeSoftwareInputPanel();
2294 void QQuickTextInput::openSoftwareInputPanel()
2297 qGuiApp->inputPanel()->show();
2301 \qmlmethod void QtQuick2::TextInput::closeSoftwareInputPanel()
2303 Closes a software input panel like a virtual keyboard shown on the screen, useful
2304 for customizing when you want the input keyboard to be shown and hidden in
2307 By default the opening of input panels follows the platform style. Input panels are
2308 always closed if no editor has active focus.
2310 You can disable the automatic behavior by setting the property \c activeFocusOnPress to false
2311 and use functions openSoftwareInputPanel() and closeSoftwareInputPanel() to implement
2312 the behavior you want.
2314 Only relevant on platforms, which provide virtual keyboards.
2320 text: "Hello world!"
2321 activeFocusOnPress: false
2323 anchors.fill: parent
2325 if (!textInput.activeFocus) {
2326 textInput.forceActiveFocus();
2327 textInput.openSoftwareInputPanel();
2329 textInput.focus = false;
2332 onPressAndHold: textInput.closeSoftwareInputPanel();
2337 void QQuickTextInput::closeSoftwareInputPanel()
2340 qGuiApp->inputPanel()->hide();
2343 void QQuickTextInput::focusInEvent(QFocusEvent *event)
2345 Q_D(const QQuickTextInput);
2346 if (d->focusOnPress && !d->m_readOnly)
2347 openSoftwareInputPanel();
2348 QQuickImplicitSizeItem::focusInEvent(event);
2351 void QQuickTextInput::itemChange(ItemChange change, const ItemChangeData &value)
2353 Q_D(QQuickTextInput);
2354 if (change == ItemActiveFocusHasChanged) {
2355 bool hasFocus = value.boolValue;
2356 d->focused = hasFocus;
2357 setCursorVisible(hasFocus); // ### refactor: && d->canvas && d->canvas->hasFocus()
2358 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
2359 if (!hasFocus && (d->m_passwordEchoEditing || d->m_passwordEchoTimer.isActive())) {
2361 if (!hasFocus && d->m_passwordEchoEditing) {
2363 d->updatePasswordEchoEditing(false);//QQuickTextInputPrivate sets it on key events, but doesn't deal with focus events
2369 disconnect(qApp->inputPanel(), SIGNAL(inputDirectionChanged(Qt::LayoutDirection)),
2370 this, SLOT(q_updateAlignment()));
2372 q_updateAlignment();
2373 connect(qApp->inputPanel(), SIGNAL(inputDirectionChanged(Qt::LayoutDirection)),
2374 this, SLOT(q_updateAlignment()));
2377 QQuickItem::itemChange(change, value);
2381 \qmlproperty bool QtQuick2::TextInput::inputMethodComposing
2384 This property holds whether the TextInput has partial text input from an
2387 While it is composing an input method may rely on mouse or key events from
2388 the TextInput to edit or commit the partial text. This property can be
2389 used to determine when to disable events handlers that may interfere with
2390 the correct operation of an input method.
2392 bool QQuickTextInput::isInputMethodComposing() const
2394 Q_D(const QQuickTextInput);
2395 return d->preeditAreaText().length() > 0;
2398 void QQuickTextInputPrivate::init()
2400 Q_Q(QQuickTextInput);
2401 q->setSmooth(smooth);
2402 q->setAcceptedMouseButtons(Qt::LeftButton);
2403 q->setFlag(QQuickItem::ItemAcceptsInputMethod);
2404 q->setFlag(QQuickItem::ItemHasContents);
2405 #ifndef QT_NO_CLIPBOARD
2406 q->connect(QGuiApplication::clipboard(), SIGNAL(dataChanged()),
2407 q, SLOT(q_canPasteChanged()));
2408 #endif // QT_NO_CLIPBOARD
2410 lastSelectionStart = 0;
2411 lastSelectionEnd = 0;
2412 selectedTextColor = m_palette.color(QPalette::HighlightedText);
2413 selectionColor = m_palette.color(QPalette::Highlight);
2414 determineHorizontalAlignment();
2416 if (!qmlDisableDistanceField()) {
2417 QTextOption option = m_textLayout.textOption();
2418 option.setUseDesignMetrics(true);
2419 m_textLayout.setTextOption(option);
2423 void QQuickTextInput::updateCursorRectangle()
2425 Q_D(QQuickTextInput);
2426 if (!isComponentComplete())
2429 d->updateHorizontalScroll();
2430 d->updateVerticalScroll();
2431 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
2433 emit cursorRectangleChanged();
2434 if (d->cursorItem) {
2435 QRectF r = cursorRectangle();
2436 d->cursorItem->setPos(r.topLeft());
2437 d->cursorItem->setHeight(r.height());
2441 void QQuickTextInput::selectionChanged()
2443 Q_D(QQuickTextInput);
2444 d->textLayoutDirty = true; //TODO: Only update rect in selection
2445 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
2447 emit selectedTextChanged();
2449 if (d->lastSelectionStart != d->selectionStart()) {
2450 d->lastSelectionStart = d->selectionStart();
2451 if (d->lastSelectionStart == -1)
2452 d->lastSelectionStart = d->m_cursor;
2453 emit selectionStartChanged();
2455 if (d->lastSelectionEnd != d->selectionEnd()) {
2456 d->lastSelectionEnd = d->selectionEnd();
2457 if (d->lastSelectionEnd == -1)
2458 d->lastSelectionEnd = d->m_cursor;
2459 emit selectionEndChanged();
2463 void QQuickTextInputPrivate::showCursor()
2465 if (textNode != 0 && textNode->cursorNode() != 0)
2466 textNode->cursorNode()->setColor(color);
2469 void QQuickTextInputPrivate::hideCursor()
2471 if (textNode != 0 && textNode->cursorNode() != 0)
2472 textNode->cursorNode()->setColor(QColor(0, 0, 0, 0));
2475 QRectF QQuickTextInput::boundingRect() const
2477 Q_D(const QQuickTextInput);
2479 int cursorWidth = d->cursorItem ? d->cursorItem->width() : d->m_cursorWidth;
2481 // Could include font max left/right bearings to either side of rectangle.
2482 QRectF r = QQuickImplicitSizeItem::boundingRect();
2483 r.setRight(r.right() + cursorWidth);
2487 void QQuickTextInput::q_canPasteChanged()
2489 Q_D(QQuickTextInput);
2490 bool old = d->canPaste;
2491 #ifndef QT_NO_CLIPBOARD
2492 if (const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData())
2493 d->canPaste = !d->m_readOnly && mimeData->hasText();
2495 d->canPaste = false;
2498 bool changed = d->canPaste != old || !d->canPasteValid;
2499 d->canPasteValid = true;
2501 emit canPasteChanged();
2505 void QQuickTextInput::q_updateAlignment()
2507 Q_D(QQuickTextInput);
2508 if (d->determineHorizontalAlignment()) {
2510 updateCursorRectangle();
2514 // ### these should come from QStyleHints
2515 const int textCursorWidth = 1;
2516 const bool fullWidthSelection = true;
2521 Updates the display text based of the current edit text
2522 If the text has changed will emit displayTextChanged()
2524 void QQuickTextInputPrivate::updateDisplayText(bool forceUpdate)
2526 QString orig = m_textLayout.text();
2528 if (m_echoMode == QQuickTextInput::NoEcho)
2529 str = QString::fromLatin1("");
2533 if (m_echoMode == QQuickTextInput::Password) {
2534 str.fill(m_passwordCharacter);
2535 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
2536 if (m_passwordEchoTimer.isActive() && m_cursor > 0 && m_cursor <= m_text.length()) {
2537 int cursor = m_cursor - 1;
2538 QChar uc = m_text.at(cursor);
2540 if (cursor > 0 && uc.unicode() >= 0xdc00 && uc.unicode() < 0xe000) {
2541 // second half of a surrogate, check if we have the first half as well,
2542 // if yes restore both at once
2543 uc = m_text.at(cursor - 1);
2544 if (uc.unicode() >= 0xd800 && uc.unicode() < 0xdc00)
2545 str[cursor - 1] = uc;
2549 } else if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit && !m_passwordEchoEditing) {
2550 str.fill(m_passwordCharacter);
2553 // replace certain non-printable characters with spaces (to avoid
2554 // drawing boxes when using fonts that don't have glyphs for such
2556 QChar* uc = str.data();
2557 for (int i = 0; i < (int)str.length(); ++i) {
2558 if ((uc[i] < 0x20 && uc[i] != 0x09)
2559 || uc[i] == QChar::LineSeparator
2560 || uc[i] == QChar::ParagraphSeparator
2561 || uc[i] == QChar::ObjectReplacementCharacter)
2562 uc[i] = QChar(0x0020);
2565 if (str != orig || forceUpdate) {
2566 m_textLayout.setText(str);
2567 updateLayout(); // polish?
2568 emit q_func()->displayTextChanged();
2572 void QQuickTextInputPrivate::updateLayout()
2574 Q_Q(QQuickTextInput);
2576 if (!q->isComponentComplete())
2579 QTextOption option = m_textLayout.textOption();
2580 option.setTextDirection(layoutDirection());
2581 option.setFlags(QTextOption::IncludeTrailingSpaces);
2582 option.setWrapMode(QTextOption::WrapMode(wrapMode));
2583 option.setAlignment(Qt::Alignment(q->effectiveHAlign()));
2584 m_textLayout.setTextOption(option);
2585 m_textLayout.setFont(font);
2587 boundingRect = QRectF();
2588 m_textLayout.beginLayout();
2589 QTextLine line = m_textLayout.createLine();
2590 qreal lineWidth = q->widthValid() ? q->width() : INT_MAX;
2592 QTextLine firstLine = line;
2594 line.setLineWidth(lineWidth);
2595 line.setPosition(QPointF(line.position().x(), height));
2596 boundingRect = boundingRect.united(line.naturalTextRect());
2598 height += line.height();
2599 line = m_textLayout.createLine();
2600 } while (line.isValid());
2601 m_textLayout.endLayout();
2603 option.setWrapMode(QTextOption::NoWrap);
2604 m_textLayout.setTextOption(option);
2606 m_ascent = qRound(firstLine.ascent());
2607 textLayoutDirty = true;
2609 updateType = UpdatePaintNode;
2611 q->setImplicitSize(qCeil(boundingRect.width()), qCeil(boundingRect.height()));
2615 #ifndef QT_NO_CLIPBOARD
2619 Copies the currently selected text into the clipboard using the given
2622 \note If the echo mode is set to a mode other than Normal then copy
2623 will not work. This is to prevent using copy as a method of bypassing
2624 password features of the line control.
2626 void QQuickTextInputPrivate::copy(QClipboard::Mode mode) const
2628 QString t = selectedText();
2629 if (!t.isEmpty() && m_echoMode == QQuickTextInput::Normal) {
2630 QGuiApplication::clipboard()->setText(t, mode);
2637 Inserts the text stored in the application clipboard into the line
2642 void QQuickTextInputPrivate::paste(QClipboard::Mode clipboardMode)
2644 QString clip = QGuiApplication::clipboard()->text(clipboardMode);
2645 if (!clip.isEmpty() || hasSelectedText()) {
2646 separate(); //make it a separate undo/redo command
2652 #endif // !QT_NO_CLIPBOARD
2657 Exits preedit mode and commits parts marked as tentative commit
2659 void QQuickTextInputPrivate::commitPreedit()
2664 qApp->inputPanel()->reset();
2666 if (!m_tentativeCommit.isEmpty()) {
2667 internalInsert(m_tentativeCommit);
2668 m_tentativeCommit.clear();
2669 finishChange(-1, true/*not used, not documented*/, false);
2672 m_preeditCursor = 0;
2673 m_textLayout.setPreeditArea(-1, QString());
2674 m_textLayout.clearAdditionalFormats();
2681 Handles the behavior for the backspace key or function.
2682 Removes the current selection if there is a selection, otherwise
2683 removes the character prior to the cursor position.
2687 void QQuickTextInputPrivate::backspace()
2689 int priorState = m_undoState;
2690 if (hasSelectedText()) {
2691 removeSelectedText();
2692 } else if (m_cursor) {
2695 m_cursor = prevMaskBlank(m_cursor);
2696 QChar uc = m_text.at(m_cursor);
2697 if (m_cursor > 0 && uc.unicode() >= 0xdc00 && uc.unicode() < 0xe000) {
2698 // second half of a surrogate, check if we have the first half as well,
2699 // if yes delete both at once
2700 uc = m_text.at(m_cursor - 1);
2701 if (uc.unicode() >= 0xd800 && uc.unicode() < 0xdc00) {
2702 internalDelete(true);
2706 internalDelete(true);
2708 finishChange(priorState);
2714 Handles the behavior for the delete key or function.
2715 Removes the current selection if there is a selection, otherwise
2716 removes the character after the cursor position.
2720 void QQuickTextInputPrivate::del()
2722 int priorState = m_undoState;
2723 if (hasSelectedText()) {
2724 removeSelectedText();
2726 int n = m_textLayout.nextCursorPosition(m_cursor) - m_cursor;
2730 finishChange(priorState);
2736 Inserts the given \a newText at the current cursor position.
2737 If there is any selected text it is removed prior to insertion of
2740 void QQuickTextInputPrivate::insert(const QString &newText)
2742 int priorState = m_undoState;
2743 removeSelectedText();
2744 internalInsert(newText);
2745 finishChange(priorState);
2751 Clears the line control text.
2753 void QQuickTextInputPrivate::clear()
2755 int priorState = m_undoState;
2757 m_selend = m_text.length();
2758 removeSelectedText();
2760 finishChange(priorState, /*update*/false, /*edited*/false);
2766 Sets \a length characters from the given \a start position as selected.
2767 The given \a start position must be within the current text for
2768 the line control. If \a length characters cannot be selected, then
2769 the selection will extend to the end of the current text.
2771 void QQuickTextInputPrivate::setSelection(int start, int length)
2773 Q_Q(QQuickTextInput);
2776 if (start < 0 || start > (int)m_text.length()){
2777 qWarning("QQuickTextInputPrivate::setSelection: Invalid start position");
2782 if (start == m_selstart && start + length == m_selend && m_cursor == m_selend)
2785 m_selend = qMin(start + length, (int)m_text.length());
2786 m_cursor = m_selend;
2787 } else if (length < 0){
2788 if (start == m_selend && start + length == m_selstart && m_cursor == m_selstart)
2790 m_selstart = qMax(start + length, 0);
2792 m_cursor = m_selstart;
2793 } else if (m_selstart != m_selend) {
2799 emitCursorPositionChanged();
2802 emit q->selectionChanged();
2803 emitCursorPositionChanged();
2804 qApp->inputPanel()->update(Qt::ImCursorRectangle | Qt::ImAnchorPosition
2805 | Qt::ImCursorPosition | Qt::ImCurrentSelection);
2811 Initializes the line control with a starting text value of \a txt.
2813 void QQuickTextInputPrivate::init(const QString &txt)
2817 updateDisplayText();
2818 m_cursor = m_text.length();
2824 Sets the password echo editing to \a editing. If password echo editing
2825 is true, then the text of the password is displayed even if the echo
2826 mode is set to QLineEdit::PasswordEchoOnEdit. Password echoing editing
2827 does not affect other echo modes.
2829 void QQuickTextInputPrivate::updatePasswordEchoEditing(bool editing)
2831 cancelPasswordEchoTimer();
2832 m_passwordEchoEditing = editing;
2833 updateDisplayText();
2839 Fixes the current text so that it is valid given any set validators.
2841 Returns true if the text was changed. Otherwise returns false.
2843 bool QQuickTextInputPrivate::fixup() // this function assumes that validate currently returns != Acceptable
2845 #ifndef QT_NO_VALIDATOR
2847 QString textCopy = m_text;
2848 int cursorCopy = m_cursor;
2849 m_validator->fixup(textCopy);
2850 if (m_validator->validate(textCopy, cursorCopy) == QValidator::Acceptable) {
2851 if (textCopy != m_text || cursorCopy != m_cursor)
2852 internalSetText(textCopy, cursorCopy);
2863 Moves the cursor to the given position \a pos. If \a mark is true will
2864 adjust the currently selected text.
2866 void QQuickTextInputPrivate::moveCursor(int pos, bool mark)
2868 Q_Q(QQuickTextInput);
2871 if (pos != m_cursor) {
2874 pos = pos > m_cursor ? nextMaskBlank(pos) : prevMaskBlank(pos);
2878 if (m_selend > m_selstart && m_cursor == m_selstart)
2880 else if (m_selend > m_selstart && m_cursor == m_selend)
2881 anchor = m_selstart;
2884 m_selstart = qMin(anchor, pos);
2885 m_selend = qMax(anchor, pos);
2890 if (mark || m_selDirty) {
2892 emit q->selectionChanged();
2894 emitCursorPositionChanged();
2895 q->updateMicroFocus();
2901 Applies the given input method event \a event to the text of the line
2904 void QQuickTextInputPrivate::processInputMethodEvent(QInputMethodEvent *event)
2906 Q_Q(QQuickTextInput);
2908 int priorState = -1;
2909 bool isGettingInput = !event->commitString().isEmpty()
2910 || event->preeditString() != preeditAreaText()
2911 || event->replacementLength() > 0;
2912 bool cursorPositionChanged = false;
2913 bool selectionChange = false;
2914 m_preeditDirty = event->preeditString() != preeditAreaText();
2916 if (isGettingInput) {
2917 // If any text is being input, remove selected text.
2918 priorState = m_undoState;
2919 if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit && !m_passwordEchoEditing) {
2920 updatePasswordEchoEditing(true);
2922 m_selend = m_text.length();
2924 removeSelectedText();
2927 int c = m_cursor; // cursor position after insertion of commit string
2928 if (event->replacementStart() <= 0)
2929 c += event->commitString().length() - qMin(-event->replacementStart(), event->replacementLength());
2931 m_cursor += event->replacementStart();
2935 // insert commit string
2936 if (event->replacementLength()) {
2937 m_selstart = m_cursor;
2938 m_selend = m_selstart + event->replacementLength();
2939 m_selend = qMin(m_selend, m_text.length());
2940 removeSelectedText();
2942 if (!event->commitString().isEmpty()) {
2943 internalInsert(event->commitString());
2944 cursorPositionChanged = true;
2947 m_cursor = qBound(0, c, m_text.length());
2949 for (int i = 0; i < event->attributes().size(); ++i) {
2950 const QInputMethodEvent::Attribute &a = event->attributes().at(i);
2951 if (a.type == QInputMethodEvent::Selection) {
2952 m_cursor = qBound(0, a.start + a.length, m_text.length());
2954 m_selstart = qMax(0, qMin(a.start, m_text.length()));
2955 m_selend = m_cursor;
2956 if (m_selend < m_selstart) {
2957 qSwap(m_selstart, m_selend);
2959 selectionChange = true;
2961 m_selstart = m_selend = 0;
2963 cursorPositionChanged = true;
2967 m_textLayout.setPreeditArea(m_cursor, event->preeditString());
2969 const int oldPreeditCursor = m_preeditCursor;
2970 m_preeditCursor = event->preeditString().length();
2971 m_hideCursor = false;
2972 QList<QTextLayout::FormatRange> formats;
2973 for (int i = 0; i < event->attributes().size(); ++i) {
2974 const QInputMethodEvent::Attribute &a = event->attributes().at(i);
2975 if (a.type == QInputMethodEvent::Cursor) {
2976 m_preeditCursor = a.start;
2977 m_hideCursor = !a.length;
2978 } else if (a.type == QInputMethodEvent::TextFormat) {
2979 QTextCharFormat f = qvariant_cast<QTextFormat>(a.value).toCharFormat();
2981 QTextLayout::FormatRange o;
2982 o.start = a.start + m_cursor;
2983 o.length = a.length;
2989 m_textLayout.setAdditionalFormats(formats);
2991 updateDisplayText(/*force*/ true);
2992 if (cursorPositionChanged) {
2993 emitCursorPositionChanged();
2994 } else if (m_preeditCursor != oldPreeditCursor) {
2995 q->updateCursorRectangle();
2996 qApp->inputPanel()->update(Qt::ImCursorRectangle);
2999 bool tentativeCommitChanged = m_tentativeCommit != event->tentativeCommitString();
3001 if (tentativeCommitChanged) {
3003 m_tentativeCommit = event->tentativeCommitString();
3006 if (isGettingInput || tentativeCommitChanged)
3007 finishChange(priorState);
3009 if (selectionChange) {
3010 emit q->selectionChanged();
3011 qApp->inputPanel()->update(Qt::ImCursorRectangle | Qt::ImAnchorPosition
3012 | Qt::ImCursorPosition | Qt::ImCurrentSelection);
3019 Sets the selection to cover the word at the given cursor position.
3020 The word boundaries are defined by the behavior of QTextLayout::SkipWords
3023 void QQuickTextInputPrivate::selectWordAtPos(int cursor)
3025 int next = cursor + 1;
3028 int c = m_textLayout.previousCursorPosition(next, QTextLayout::SkipWords);
3029 moveCursor(c, false);
3030 // ## text layout should support end of words.
3031 int end = m_textLayout.nextCursorPosition(c, QTextLayout::SkipWords);
3032 while (end > cursor && m_text[end-1].isSpace())
3034 moveCursor(end, true);
3040 Completes a change to the line control text. If the change is not valid
3041 will undo the line control state back to the given \a validateFromState.
3043 If \a edited is true and the change is valid, will emit textEdited() in
3044 addition to textChanged(). Otherwise only emits textChanged() on a valid
3047 The \a update value is currently unused.
3049 bool QQuickTextInputPrivate::finishChange(int validateFromState, bool update, bool /*edited*/)
3051 Q_Q(QQuickTextInput);
3054 bool notifyInputPanel = m_textDirty || m_selDirty;
3055 bool alignmentChanged = false;
3059 bool wasValidInput = m_validInput;
3060 bool wasAcceptable = m_acceptableInput;
3061 m_validInput = true;
3062 m_acceptableInput = true;
3063 #ifndef QT_NO_VALIDATOR
3065 QString textCopy = m_text;
3066 int cursorCopy = m_cursor;
3067 QValidator::State state = m_validator->validate(textCopy, cursorCopy);
3068 m_validInput = state != QValidator::Invalid;
3069 m_acceptableInput = state == QValidator::Acceptable;
3071 if (m_text != textCopy) {
3072 internalSetText(textCopy, cursorCopy);
3075 m_cursor = cursorCopy;
3077 if (!m_tentativeCommit.isEmpty()) {
3078 textCopy.insert(m_cursor, m_tentativeCommit);
3079 bool validInput = m_validator->validate(textCopy, cursorCopy) != QValidator::Invalid;
3081 m_tentativeCommit.clear();
3084 m_tentativeCommit.clear();
3088 if (validateFromState >= 0 && wasValidInput && !m_validInput) {
3089 if (m_transactions.count())
3091 internalUndo(validateFromState);
3092 m_history.resize(m_undoState);
3093 if (m_modifiedState > m_undoState)
3094 m_modifiedState = -1;
3095 m_validInput = true;
3096 m_acceptableInput = wasAcceptable;
3097 m_textDirty = false;
3101 m_textDirty = false;
3102 m_preeditDirty = false;
3103 alignmentChanged = determineHorizontalAlignment();
3104 emit q->textChanged();
3107 updateDisplayText(alignmentChanged);
3109 if (m_acceptableInput != wasAcceptable)
3110 emit q->acceptableInputChanged();
3112 if (m_preeditDirty) {
3113 m_preeditDirty = false;
3114 if (determineHorizontalAlignment()) {
3115 alignmentChanged = true;
3122 emit q->selectionChanged();
3125 notifyInputPanel |= (m_cursor == m_lastCursorPos);
3126 if (notifyInputPanel)
3127 q->updateMicroFocus();
3128 emitUndoRedoChanged();
3130 if (!emitCursorPositionChanged() && alignmentChanged)
3131 q->updateCursorRectangle();
3139 An internal function for setting the text of the line control.
3141 void QQuickTextInputPrivate::internalSetText(const QString &txt, int pos, bool edited)
3143 Q_Q(QQuickTextInput);
3145 QString oldText = m_text;
3147 m_text = maskString(0, txt, true);
3148 m_text += clearString(m_text.length(), m_maxLength - m_text.length());
3150 m_text = txt.isEmpty() ? txt : txt.left(m_maxLength);
3153 m_modifiedState = m_undoState = 0;
3154 m_cursor = (pos < 0 || pos > m_text.length()) ? m_text.length() : pos;
3155 m_textDirty = (oldText != m_text);
3157 bool changed = finishChange(-1, true, edited);
3158 #ifdef QT_NO_ACCESSIBILITY
3162 QAccessible::updateAccessibility(q, 0, QAccessible::TextUpdated);
3170 Adds the given \a command to the undo history
3171 of the line control. Does not apply the command.
3173 void QQuickTextInputPrivate::addCommand(const Command &cmd)
3175 if (m_separator && m_undoState && m_history[m_undoState - 1].type != Separator) {
3176 m_history.resize(m_undoState + 2);
3177 m_history[m_undoState++] = Command(Separator, m_cursor, 0, m_selstart, m_selend);
3179 m_history.resize(m_undoState + 1);
3181 m_separator = false;
3182 m_history[m_undoState++] = cmd;
3188 Inserts the given string \a s into the line
3191 Also adds the appropriate commands into the undo history.
3192 This function does not call finishChange(), and may leave the text
3193 in an invalid state.
3195 void QQuickTextInputPrivate::internalInsert(const QString &s)
3197 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
3198 Q_Q(QQuickTextInput);
3199 if (m_echoMode == QQuickTextInput::Password)
3200 m_passwordEchoTimer.start(qt_passwordEchoDelay, q);
3202 if (hasSelectedText())
3203 addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
3205 QString ms = maskString(m_cursor, s);
3206 for (int i = 0; i < (int) ms.length(); ++i) {
3207 addCommand (Command(DeleteSelection, m_cursor + i, m_text.at(m_cursor + i), -1, -1));
3208 addCommand(Command(Insert, m_cursor + i, ms.at(i), -1, -1));
3210 m_text.replace(m_cursor, ms.length(), ms);
3211 m_cursor += ms.length();
3212 m_cursor = nextMaskBlank(m_cursor);
3215 int remaining = m_maxLength - m_text.length();
3216 if (remaining != 0) {
3217 m_text.insert(m_cursor, s.left(remaining));
3218 for (int i = 0; i < (int) s.left(remaining).length(); ++i)
3219 addCommand(Command(Insert, m_cursor++, s.at(i), -1, -1));
3228 deletes a single character from the current text. If \a wasBackspace,
3229 the character prior to the cursor is removed. Otherwise the character
3230 after the cursor is removed.
3232 Also adds the appropriate commands into the undo history.
3233 This function does not call finishChange(), and may leave the text
3234 in an invalid state.
3236 void QQuickTextInputPrivate::internalDelete(bool wasBackspace)
3238 if (m_cursor < (int) m_text.length()) {
3239 cancelPasswordEchoTimer();
3240 if (hasSelectedText())
3241 addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
3242 addCommand(Command((CommandType)((m_maskData ? 2 : 0) + (wasBackspace ? Remove : Delete)),
3243 m_cursor, m_text.at(m_cursor), -1, -1));
3245 m_text.replace(m_cursor, 1, clearString(m_cursor, 1));
3246 addCommand(Command(Insert, m_cursor, m_text.at(m_cursor), -1, -1));
3248 m_text.remove(m_cursor, 1);
3257 removes the currently selected text from the line control.
3259 Also adds the appropriate commands into the undo history.
3260 This function does not call finishChange(), and may leave the text
3261 in an invalid state.
3263 void QQuickTextInputPrivate::removeSelectedText()
3265 if (m_selstart < m_selend && m_selend <= (int) m_text.length()) {
3266 cancelPasswordEchoTimer();
3269 addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
3270 if (m_selstart <= m_cursor && m_cursor < m_selend) {
3271 // cursor is within the selection. Split up the commands
3272 // to be able to restore the correct cursor position
3273 for (i = m_cursor; i >= m_selstart; --i)
3274 addCommand (Command(DeleteSelection, i, m_text.at(i), -1, 1));
3275 for (i = m_selend - 1; i > m_cursor; --i)
3276 addCommand (Command(DeleteSelection, i - m_cursor + m_selstart - 1, m_text.at(i), -1, -1));
3278 for (i = m_selend-1; i >= m_selstart; --i)
3279 addCommand (Command(RemoveSelection, i, m_text.at(i), -1, -1));
3282 m_text.replace(m_selstart, m_selend - m_selstart, clearString(m_selstart, m_selend - m_selstart));
3283 for (int i = 0; i < m_selend - m_selstart; ++i)
3284 addCommand(Command(Insert, m_selstart + i, m_text.at(m_selstart + i), -1, -1));
3286 m_text.remove(m_selstart, m_selend - m_selstart);
3288 if (m_cursor > m_selstart)
3289 m_cursor -= qMin(m_cursor, m_selend) - m_selstart;
3298 Parses the input mask specified by \a maskFields to generate
3299 the mask data used to handle input masks.
3301 void QQuickTextInputPrivate::parseInputMask(const QString &maskFields)
3303 int delimiter = maskFields.indexOf(QLatin1Char(';'));
3304 if (maskFields.isEmpty() || delimiter == 0) {
3306 delete [] m_maskData;
3308 m_maxLength = 32767;
3309 internalSetText(QString());
3314 if (delimiter == -1) {
3315 m_blank = QLatin1Char(' ');
3316 m_inputMask = maskFields;
3318 m_inputMask = maskFields.left(delimiter);
3319 m_blank = (delimiter + 1 < maskFields.length()) ? maskFields[delimiter + 1] : QLatin1Char(' ');
3322 // calculate m_maxLength / m_maskData length
3325 for (int i=0; i<m_inputMask.length(); i++) {
3326 c = m_inputMask.at(i);
3327 if (i > 0 && m_inputMask.at(i-1) == QLatin1Char('\\')) {
3331 if (c != QLatin1Char('\\') && c != QLatin1Char('!') &&
3332 c != QLatin1Char('<') && c != QLatin1Char('>') &&
3333 c != QLatin1Char('{') && c != QLatin1Char('}') &&
3334 c != QLatin1Char('[') && c != QLatin1Char(']'))
3338 delete [] m_maskData;
3339 m_maskData = new MaskInputData[m_maxLength];
3341 MaskInputData::Casemode m = MaskInputData::NoCaseMode;
3344 bool escape = false;
3346 for (int i = 0; i < m_inputMask.length(); i++) {
3347 c = m_inputMask.at(i);
3350 m_maskData[index].maskChar = c;
3351 m_maskData[index].separator = s;
3352 m_maskData[index].caseMode = m;
3355 } else if (c == QLatin1Char('<')) {
3356 m = MaskInputData::Lower;
3357 } else if (c == QLatin1Char('>')) {
3358 m = MaskInputData::Upper;
3359 } else if (c == QLatin1Char('!')) {
3360 m = MaskInputData::NoCaseMode;
3361 } else if (c != QLatin1Char('{') && c != QLatin1Char('}') && c != QLatin1Char('[') && c != QLatin1Char(']')) {
3362 switch (c.unicode()) {
3388 m_maskData[index].maskChar = c;
3389 m_maskData[index].separator = s;
3390 m_maskData[index].caseMode = m;
3395 internalSetText(m_text);
3402 checks if the key is valid compared to the inputMask
3404 bool QQuickTextInputPrivate::isValidInput(QChar key, QChar mask) const
3406 switch (mask.unicode()) {
3412 if (key.isLetter() || key == m_blank)
3416 if (key.isLetterOrNumber())
3420 if (key.isLetterOrNumber() || key == m_blank)
3428 if (key.isPrint() || key == m_blank)
3436 if (key.isNumber() || key == m_blank)
3440 if (key.isNumber() && key.digitValue() > 0)
3444 if ((key.isNumber() && key.digitValue() > 0) || key == m_blank)
3448 if (key.isNumber() || key == QLatin1Char('+') || key == QLatin1Char('-') || key == m_blank)
3452 if (key == QLatin1Char('0') || key == QLatin1Char('1'))
3456 if (key == QLatin1Char('0') || key == QLatin1Char('1') || key == m_blank)
3460 if (key.isNumber() || (key >= QLatin1Char('a') && key <= QLatin1Char('f')) || (key >= QLatin1Char('A') && key <= QLatin1Char('F')))
3464 if (key.isNumber() || (key >= QLatin1Char('a') && key <= QLatin1Char('f')) || (key >= QLatin1Char('A') && key <= QLatin1Char('F')) || key == m_blank)
3476 Returns true if the given text \a str is valid for any
3477 validator or input mask set for the line control.
3479 Otherwise returns false
3481 QQuickTextInputPrivate::ValidatorState QQuickTextInputPrivate::hasAcceptableInput(const QString &str) const
3483 #ifndef QT_NO_VALIDATOR
3484 QString textCopy = str;
3485 int cursorCopy = m_cursor;
3487 QValidator::State state = m_validator->validate(textCopy, cursorCopy);
3488 if (state != QValidator::Acceptable)
3489 return ValidatorState(state);
3494 return AcceptableInput;
3496 if (str.length() != m_maxLength)
3497 return InvalidInput;
3499 for (int i=0; i < m_maxLength; ++i) {
3500 if (m_maskData[i].separator) {
3501 if (str.at(i) != m_maskData[i].maskChar)
3502 return InvalidInput;
3504 if (!isValidInput(str.at(i), m_maskData[i].maskChar))
3505 return InvalidInput;
3508 return AcceptableInput;
3514 Applies the inputMask on \a str starting from position \a pos in the mask. \a clear
3515 specifies from where characters should be gotten when a separator is met in \a str - true means
3516 that blanks will be used, false that previous input is used.
3517 Calling this when no inputMask is set is undefined.
3519 QString QQuickTextInputPrivate::maskString(uint pos, const QString &str, bool clear) const
3521 if (pos >= (uint)m_maxLength)
3522 return QString::fromLatin1("");
3525 fill = clear ? clearString(0, m_maxLength) : m_text;
3528 QString s = QString::fromLatin1("");
3530 while (i < m_maxLength) {
3531 if (strIndex < str.length()) {
3532 if (m_maskData[i].separator) {
3533 s += m_maskData[i].maskChar;
3534 if (str[(int)strIndex] == m_maskData[i].maskChar)
3538 if (isValidInput(str[(int)strIndex], m_maskData[i].maskChar)) {
3539 switch (m_maskData[i].caseMode) {
3540 case MaskInputData::Upper:
3541 s += str[(int)strIndex].toUpper();
3543 case MaskInputData::Lower:
3544 s += str[(int)strIndex].toLower();
3547 s += str[(int)strIndex];
3551 // search for separator first
3552 int n = findInMask(i, true, true, str[(int)strIndex]);
3554 if (str.length() != 1 || i == 0 || (i > 0 && (!m_maskData[i-1].separator || m_maskData[i-1].maskChar != str[(int)strIndex]))) {
3555 s += fill.mid(i, n-i+1);
3556 i = n + 1; // update i to find + 1
3559 // search for valid m_blank if not
3560 n = findInMask(i, true, false, str[(int)strIndex]);
3562 s += fill.mid(i, n-i);
3563 switch (m_maskData[n].caseMode) {
3564 case MaskInputData::Upper:
3565 s += str[(int)strIndex].toUpper();
3567 case MaskInputData::Lower:
3568 s += str[(int)strIndex].toLower();
3571 s += str[(int)strIndex];
3573 i = n + 1; // updates i to find + 1
3591 Returns a "cleared" string with only separators and blank chars.
3592 Calling this when no inputMask is set is undefined.
3594 QString QQuickTextInputPrivate::clearString(uint pos, uint len) const
3596 if (pos >= (uint)m_maxLength)
3600 int end = qMin((uint)m_maxLength, pos + len);
3601 for (int i = pos; i < end; ++i)
3602 if (m_maskData[i].separator)
3603 s += m_maskData[i].maskChar;
3613 Strips blank parts of the input in a QQuickTextInputPrivate when an inputMask is set,
3614 separators are still included. Typically "127.0__.0__.1__" becomes "127.0.0.1".
3616 QString QQuickTextInputPrivate::stripString(const QString &str) const
3622 int end = qMin(m_maxLength, (int)str.length());
3623 for (int i = 0; i < end; ++i) {
3624 if (m_maskData[i].separator)
3625 s += m_maskData[i].maskChar;
3626 else if (str[i] != m_blank)
3635 searches forward/backward in m_maskData for either a separator or a m_blank
3637 int QQuickTextInputPrivate::findInMask(int pos, bool forward, bool findSeparator, QChar searchChar) const
3639 if (pos >= m_maxLength || pos < 0)
3642 int end = forward ? m_maxLength : -1;
3643 int step = forward ? 1 : -1;
3647 if (findSeparator) {
3648 if (m_maskData[i].separator && m_maskData[i].maskChar == searchChar)
3651 if (!m_maskData[i].separator) {
3652 if (searchChar.isNull())
3654 else if (isValidInput(searchChar, m_maskData[i].maskChar))
3663 void QQuickTextInputPrivate::internalUndo(int until)
3665 if (!isUndoAvailable())
3667 cancelPasswordEchoTimer();
3669 while (m_undoState && m_undoState > until) {
3670 Command& cmd = m_history[--m_undoState];
3673 m_text.remove(cmd.pos, 1);
3677 m_selstart = cmd.selStart;
3678 m_selend = cmd.selEnd;
3682 case RemoveSelection:
3683 m_text.insert(cmd.pos, cmd.uc);
3684 m_cursor = cmd.pos + 1;
3687 case DeleteSelection:
3688 m_text.insert(cmd.pos, cmd.uc);
3694 if (until < 0 && m_undoState) {
3695 Command& next = m_history[m_undoState-1];
3696 if (next.type != cmd.type && next.type < RemoveSelection
3697 && (cmd.type < RemoveSelection || next.type == Separator))
3704 void QQuickTextInputPrivate::internalRedo()
3706 if (!isRedoAvailable())
3709 while (m_undoState < (int)m_history.size()) {
3710 Command& cmd = m_history[m_undoState++];
3713 m_text.insert(cmd.pos, cmd.uc);
3714 m_cursor = cmd.pos + 1;
3717 m_selstart = cmd.selStart;
3718 m_selend = cmd.selEnd;
3723 case RemoveSelection:
3724 case DeleteSelection:
3725 m_text.remove(cmd.pos, 1);
3726 m_selstart = cmd.selStart;
3727 m_selend = cmd.selEnd;
3731 m_selstart = cmd.selStart;
3732 m_selend = cmd.selEnd;
3736 if (m_undoState < (int)m_history.size()) {
3737 Command& next = m_history[m_undoState];
3738 if (next.type != cmd.type && cmd.type < RemoveSelection && next.type != Separator
3739 && (next.type < RemoveSelection || cmd.type == Separator))
3746 void QQuickTextInputPrivate::emitUndoRedoChanged()
3748 Q_Q(QQuickTextInput);
3749 const bool previousUndo = canUndo;
3750 const bool previousRedo = canRedo;
3752 canUndo = isUndoAvailable();
3753 canRedo = isRedoAvailable();
3755 if (previousUndo != canUndo)
3756 emit q->canUndoChanged();
3757 if (previousRedo != canRedo)
3758 emit q->canRedoChanged();
3764 If the current cursor position differs from the last emitted cursor
3765 position, emits cursorPositionChanged().
3767 bool QQuickTextInputPrivate::emitCursorPositionChanged()
3769 Q_Q(QQuickTextInput);
3770 if (m_cursor != m_lastCursorPos) {
3771 m_lastCursorPos = m_cursor;
3773 q->updateCursorRectangle();
3774 emit q->cursorPositionChanged();
3775 // XXX todo - not in 4.8?
3777 resetCursorBlinkTimer();
3780 if (!hasSelectedText()) {
3781 if (lastSelectionStart != m_cursor) {
3782 lastSelectionStart = m_cursor;
3783 emit q->selectionStartChanged();
3785 if (lastSelectionEnd != m_cursor) {
3786 lastSelectionEnd = m_cursor;
3787 emit q->selectionEndChanged();
3791 #ifndef QT_NO_ACCESSIBILITY
3792 QAccessible::updateAccessibility(q, 0, QAccessible::TextCaretMoved);
3801 void QQuickTextInputPrivate::setCursorBlinkPeriod(int msec)
3803 Q_Q(QQuickTextInput);
3804 if (msec == m_blinkPeriod)
3807 q->killTimer(m_blinkTimer);
3810 m_blinkTimer = q->startTimer(msec / 2);
3814 if (m_blinkStatus == 1) {
3815 updateType = UpdatePaintNode;
3819 m_blinkPeriod = msec;
3822 void QQuickTextInputPrivate::resetCursorBlinkTimer()
3824 Q_Q(QQuickTextInput);
3825 if (m_blinkPeriod == 0 || m_blinkTimer == 0)
3827 q->killTimer(m_blinkTimer);
3828 m_blinkTimer = q->startTimer(m_blinkPeriod / 2);
3832 void QQuickTextInput::timerEvent(QTimerEvent *event)
3834 Q_D(QQuickTextInput);
3835 if (event->timerId() == d->m_blinkTimer) {
3836 d->m_blinkStatus = !d->m_blinkStatus;
3837 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
3839 } else if (event->timerId() == d->m_deleteAllTimer) {
3840 killTimer(d->m_deleteAllTimer);
3841 d->m_deleteAllTimer = 0;
3843 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
3844 } else if (event->timerId() == d->m_passwordEchoTimer.timerId()) {
3845 d->m_passwordEchoTimer.stop();
3846 d->updateDisplayText();
3851 void QQuickTextInputPrivate::processKeyEvent(QKeyEvent* event)
3853 Q_Q(QQuickTextInput);
3854 bool inlineCompletionAccepted = false;
3856 if (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return) {
3857 if (hasAcceptableInput(m_text) || fixup()) {
3860 if (inlineCompletionAccepted)
3867 if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit
3868 && !m_passwordEchoEditing
3870 && !event->text().isEmpty()
3871 && !(event->modifiers() & Qt::ControlModifier)) {
3872 // Clear the edit and reset to normal echo mode while editing; the
3873 // echo mode switches back when the edit loses focus
3874 // ### resets current content. dubious code; you can
3875 // navigate with keys up, down, back, and select(?), but if you press
3876 // "left" or "right" it clears?
3877 updatePasswordEchoEditing(true);
3881 bool unknown = false;
3882 bool visual = cursorMoveStyle() == Qt::VisualMoveStyle;
3886 #ifndef QT_NO_SHORTCUT
3887 else if (event == QKeySequence::Undo) {
3891 else if (event == QKeySequence::Redo) {
3895 else if (event == QKeySequence::SelectAll) {
3898 #ifndef QT_NO_CLIPBOARD
3899 else if (event == QKeySequence::Copy) {
3902 else if (event == QKeySequence::Paste) {
3904 QClipboard::Mode mode = QClipboard::Clipboard;
3908 else if (event == QKeySequence::Cut) {
3914 else if (event == QKeySequence::DeleteEndOfLine) {
3916 setSelection(m_cursor, end());
3921 #endif //QT_NO_CLIPBOARD
3922 else if (event == QKeySequence::MoveToStartOfLine || event == QKeySequence::MoveToStartOfBlock) {
3925 else if (event == QKeySequence::MoveToEndOfLine || event == QKeySequence::MoveToEndOfBlock) {
3928 else if (event == QKeySequence::SelectStartOfLine || event == QKeySequence::SelectStartOfBlock) {
3931 else if (event == QKeySequence::SelectEndOfLine || event == QKeySequence::SelectEndOfBlock) {
3934 else if (event == QKeySequence::MoveToNextChar) {
3935 if (hasSelectedText()) {
3936 moveCursor(selectionEnd(), false);
3938 cursorForward(0, visual ? 1 : (layoutDirection() == Qt::LeftToRight ? 1 : -1));
3941 else if (event == QKeySequence::SelectNextChar) {
3942 cursorForward(1, visual ? 1 : (layoutDirection() == Qt::LeftToRight ? 1 : -1));
3944 else if (event == QKeySequence::MoveToPreviousChar) {
3945 if (hasSelectedText()) {
3946 moveCursor(selectionStart(), false);
3948 cursorForward(0, visual ? -1 : (layoutDirection() == Qt::LeftToRight ? -1 : 1));
3951 else if (event == QKeySequence::SelectPreviousChar) {
3952 cursorForward(1, visual ? -1 : (layoutDirection() == Qt::LeftToRight ? -1 : 1));
3954 else if (event == QKeySequence::MoveToNextWord) {
3955 if (m_echoMode == QQuickTextInput::Normal)
3956 layoutDirection() == Qt::LeftToRight ? cursorWordForward(0) : cursorWordBackward(0);
3958 layoutDirection() == Qt::LeftToRight ? end(0) : home(0);
3960 else if (event == QKeySequence::MoveToPreviousWord) {
3961 if (m_echoMode == QQuickTextInput::Normal)
3962 layoutDirection() == Qt::LeftToRight ? cursorWordBackward(0) : cursorWordForward(0);
3963 else if (!m_readOnly) {
3964 layoutDirection() == Qt::LeftToRight ? home(0) : end(0);
3967 else if (event == QKeySequence::SelectNextWord) {
3968 if (m_echoMode == QQuickTextInput::Normal)
3969 layoutDirection() == Qt::LeftToRight ? cursorWordForward(1) : cursorWordBackward(1);
3971 layoutDirection() == Qt::LeftToRight ? end(1) : home(1);
3973 else if (event == QKeySequence::SelectPreviousWord) {
3974 if (m_echoMode == QQuickTextInput::Normal)
3975 layoutDirection() == Qt::LeftToRight ? cursorWordBackward(1) : cursorWordForward(1);
3977 layoutDirection() == Qt::LeftToRight ? home(1) : end(1);
3979 else if (event == QKeySequence::Delete) {
3983 else if (event == QKeySequence::DeleteEndOfWord) {
3985 cursorWordForward(true);
3989 else if (event == QKeySequence::DeleteStartOfWord) {
3991 cursorWordBackward(true);
3995 #endif // QT_NO_SHORTCUT
3997 bool handled = false;
3998 if (event->modifiers() & Qt::ControlModifier) {
3999 switch (event->key()) {
4000 case Qt::Key_Backspace:
4002 cursorWordBackward(true);
4010 } else { // ### check for *no* modifier
4011 switch (event->key()) {
4012 case Qt::Key_Backspace:
4024 if (event->key() == Qt::Key_Direction_L || event->key() == Qt::Key_Direction_R) {
4025 setLayoutDirection((event->key() == Qt::Key_Direction_L) ? Qt::LeftToRight : Qt::RightToLeft);
4029 if (unknown && !m_readOnly) {
4030 QString t = event->text();
4031 if (!t.isEmpty() && t.at(0).isPrint()) {