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 If no \l locale is set IntValidator uses the \l {QLocale::setDefault()}{default locale} to
827 interpret the number and will accept locale specific digits, group separators, and positive
828 and negative signs. In addition, IntValidator is always guaranteed to accept a number
829 formatted according to the "C" locale.
833 QQuickIntValidator::QQuickIntValidator(QObject *parent)
834 : QIntValidator(parent)
839 \qmlproperty string QtQuick2::IntValidator::locale
841 This property holds the name of the locale used to interpret the number.
846 QString QQuickIntValidator::localeName() const
848 return locale().name();
851 void QQuickIntValidator::setLocaleName(const QString &name)
853 if (locale().name() != name) {
854 setLocale(QLocale(name));
855 emit localeNameChanged();
859 void QQuickIntValidator::resetLocaleName()
861 QLocale defaultLocale;
862 if (locale() != defaultLocale) {
863 setLocale(defaultLocale);
864 emit localeNameChanged();
869 \qmlproperty int QtQuick2::IntValidator::top
871 This property holds the validator's highest acceptable value.
872 By default, this property's value is derived from the highest signed integer available (typically 2147483647).
875 \qmlproperty int QtQuick2::IntValidator::bottom
877 This property holds the validator's lowest acceptable value.
878 By default, this property's value is derived from the lowest signed integer available (typically -2147483647).
882 \qmlclass DoubleValidator QDoubleValidator
883 \inqmlmodule QtQuick 2
884 \ingroup qml-basic-visual-elements
886 This element provides a validator for non-integer numbers.
888 Input is accepted if it contains a double that is within the valid range
889 and is in the correct format.
891 Input is accepected but invalid if it contains a double that is outside
892 the range or is in the wrong format; e.g. with too many digits after the
893 decimal point or is empty.
895 Input is rejected if it is not a double.
897 Note: If the valid range consists of just positive doubles (e.g. 0.0 to
898 100.0) and input is a negative double then it is rejected. If \l notation
899 is set to DoubleValidator.StandardNotation, and the input contains more
900 digits before the decimal point than a double in the valid range may have,
901 it is also rejected. If \l notation is DoubleValidator.ScientificNotation,
902 and the input is not in the valid range, it is accecpted but invalid. The
903 value may yet become valid by changing the exponent.
906 QQuickDoubleValidator::QQuickDoubleValidator(QObject *parent)
907 : QDoubleValidator(parent)
912 \qmlproperty string QtQuick2::DoubleValidator::locale
914 This property holds the name of the locale used to interpret the number.
919 QString QQuickDoubleValidator::localeName() const
921 return locale().name();
924 void QQuickDoubleValidator::setLocaleName(const QString &name)
926 if (locale().name() != name) {
927 setLocale(QLocale(name));
928 emit localeNameChanged();
932 void QQuickDoubleValidator::resetLocaleName()
934 QLocale defaultLocale;
935 if (locale() != defaultLocale) {
936 setLocale(defaultLocale);
937 emit localeNameChanged();
942 \qmlproperty real QtQuick2::DoubleValidator::top
944 This property holds the validator's maximum acceptable value.
945 By default, this property contains a value of infinity.
948 \qmlproperty real QtQuick2::DoubleValidator::bottom
950 This property holds the validator's minimum acceptable value.
951 By default, this property contains a value of -infinity.
954 \qmlproperty int QtQuick2::DoubleValidator::decimals
956 This property holds the validator's maximum number of digits after the decimal point.
957 By default, this property contains a value of 1000.
960 \qmlproperty enumeration QtQuick2::DoubleValidator::notation
961 This property holds the notation of how a string can describe a number.
963 The possible values for this property are:
966 \o DoubleValidator.StandardNotation
967 \o DoubleValidator.ScientificNotation (default)
970 If this property is set to DoubleValidator.ScientificNotation, the written number may have an exponent part (e.g. 1.5E-2).
974 \qmlclass RegExpValidator QRegExpValidator
975 \inqmlmodule QtQuick 2
976 \ingroup qml-basic-visual-elements
978 This element provides a validator, which counts as valid any string which
979 matches a specified regular expression.
982 \qmlproperty regExp QtQuick2::RegExpValidator::regExp
984 This property holds the regular expression used for validation.
986 Note that this property should be a regular expression in JS syntax, e.g /a/ for the regular expression
989 By default, this property contains a regular expression with the pattern .* that matches any string.
993 \qmlproperty Validator QtQuick2::TextInput::validator
995 Allows you to set a validator on the TextInput. When a validator is set
996 the TextInput will only accept input which leaves the text property in
997 an acceptable or intermediate state. The accepted signal will only be sent
998 if the text is in an acceptable state when enter is pressed.
1000 Currently supported validators are IntValidator, DoubleValidator and
1001 RegExpValidator. An example of using validators is shown below, which allows
1002 input of integers between 11 and 31 into the text input:
1007 validator: IntValidator{bottom: 11; top: 31;}
1012 \sa acceptableInput, inputMask
1015 QValidator* QQuickTextInput::validator() const
1017 Q_D(const QQuickTextInput);
1018 return d->m_validator;
1021 void QQuickTextInput::setValidator(QValidator* v)
1023 Q_D(QQuickTextInput);
1024 if (d->m_validator == v)
1029 if (isComponentComplete())
1032 emit validatorChanged();
1035 #endif // QT_NO_VALIDATOR
1037 void QQuickTextInputPrivate::checkIsValid()
1039 Q_Q(QQuickTextInput);
1041 ValidatorState state = hasAcceptableInput(m_text);
1042 m_validInput = state != InvalidInput;
1043 if (state != AcceptableInput) {
1044 if (m_acceptableInput) {
1045 m_acceptableInput = false;
1046 emit q->acceptableInputChanged();
1048 } else if (!m_acceptableInput) {
1049 m_acceptableInput = true;
1050 emit q->acceptableInputChanged();
1055 \qmlproperty string QtQuick2::TextInput::inputMask
1057 Allows you to set an input mask on the TextInput, restricting the allowable
1058 text inputs. See QLineEdit::inputMask for further details, as the exact
1059 same mask strings are used by TextInput.
1061 \sa acceptableInput, validator
1063 QString QQuickTextInput::inputMask() const
1065 Q_D(const QQuickTextInput);
1066 return d->inputMask();
1069 void QQuickTextInput::setInputMask(const QString &im)
1071 Q_D(QQuickTextInput);
1072 if (d->inputMask() == im)
1075 d->setInputMask(im);
1076 emit inputMaskChanged(d->inputMask());
1080 \qmlproperty bool QtQuick2::TextInput::acceptableInput
1082 This property is always true unless a validator or input mask has been set.
1083 If a validator or input mask has been set, this property will only be true
1084 if the current text is acceptable to the validator or input mask as a final
1085 string (not as an intermediate string).
1087 bool QQuickTextInput::hasAcceptableInput() const
1089 Q_D(const QQuickTextInput);
1090 return d->hasAcceptableInput(d->m_text) == QQuickTextInputPrivate::AcceptableInput;
1094 \qmlsignal QtQuick2::TextInput::onAccepted()
1096 This handler is called when the Return or Enter key is pressed.
1097 Note that if there is a \l validator or \l inputMask set on the text
1098 input, the handler will only be emitted if the input is in an acceptable
1102 void QQuickTextInputPrivate::updateInputMethodHints()
1104 Q_Q(QQuickTextInput);
1105 Qt::InputMethodHints hints = inputMethodHints;
1106 if (m_echoMode == QQuickTextInput::Password || m_echoMode == QQuickTextInput::NoEcho)
1107 hints |= Qt::ImhHiddenText;
1108 else if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit)
1109 hints &= ~Qt::ImhHiddenText;
1110 if (m_echoMode != QQuickTextInput::Normal)
1111 hints |= (Qt::ImhNoAutoUppercase | Qt::ImhNoPredictiveText | Qt::ImhSensitiveData);
1112 q->setInputMethodHints(hints);
1115 \qmlproperty enumeration QtQuick2::TextInput::echoMode
1117 Specifies how the text should be displayed in the TextInput.
1119 \o TextInput.Normal - Displays the text as it is. (Default)
1120 \o TextInput.Password - Displays asterisks instead of characters.
1121 \o TextInput.NoEcho - Displays nothing.
1122 \o TextInput.PasswordEchoOnEdit - Displays characters as they are entered
1123 while editing, otherwise displays asterisks.
1126 QQuickTextInput::EchoMode QQuickTextInput::echoMode() const
1128 Q_D(const QQuickTextInput);
1129 return QQuickTextInput::EchoMode(d->m_echoMode);
1132 void QQuickTextInput::setEchoMode(QQuickTextInput::EchoMode echo)
1134 Q_D(QQuickTextInput);
1135 if (echoMode() == echo)
1137 d->cancelPasswordEchoTimer();
1138 d->m_echoMode = echo;
1139 d->m_passwordEchoEditing = false;
1140 d->updateInputMethodHints();
1141 d->updateDisplayText();
1142 updateCursorRectangle();
1144 emit echoModeChanged(echoMode());
1148 \qmlproperty enumeration QtQuick2::TextInput::inputMethodHints
1150 Provides hints to the input method about the expected content of the text input and how it
1153 The value is a bit-wise combination of flags, or Qt.ImhNone if no hints are set.
1155 Flags that alter behaviour are:
1158 \o Qt.ImhHiddenText - Characters should be hidden, as is typically used when entering passwords.
1159 This is automatically set when setting echoMode to \c TextInput.Password.
1160 \o Qt.ImhSensitiveData - Typed text should not be stored by the active input method
1161 in any persistent storage like predictive user dictionary.
1162 \o Qt.ImhNoAutoUppercase - The input method should not try to automatically switch to upper case
1163 when a sentence ends.
1164 \o Qt.ImhPreferNumbers - Numbers are preferred (but not required).
1165 \o Qt.ImhPreferUppercase - Upper case letters are preferred (but not required).
1166 \o Qt.ImhPreferLowercase - Lower case letters are preferred (but not required).
1167 \o Qt.ImhNoPredictiveText - Do not use predictive text (i.e. dictionary lookup) while typing.
1169 \o Qt.ImhDate - The text editor functions as a date field.
1170 \o Qt.ImhTime - The text editor functions as a time field.
1173 Flags that restrict input (exclusive flags) are:
1176 \o Qt.ImhDigitsOnly - Only digits are allowed.
1177 \o Qt.ImhFormattedNumbersOnly - Only number input is allowed. This includes decimal point and minus sign.
1178 \o Qt.ImhUppercaseOnly - Only upper case letter input is allowed.
1179 \o Qt.ImhLowercaseOnly - Only lower case letter input is allowed.
1180 \o Qt.ImhDialableCharactersOnly - Only characters suitable for phone dialing are allowed.
1181 \o Qt.ImhEmailCharactersOnly - Only characters suitable for email addresses are allowed.
1182 \o Qt.ImhUrlCharactersOnly - Only characters suitable for URLs are allowed.
1188 \o Qt.ImhExclusiveInputMask - This mask yields nonzero if any of the exclusive flags are used.
1192 Qt::InputMethodHints QQuickTextInput::imHints() const
1194 Q_D(const QQuickTextInput);
1195 return d->inputMethodHints;
1198 void QQuickTextInput::setIMHints(Qt::InputMethodHints hints)
1200 Q_D(QQuickTextInput);
1201 if (d->inputMethodHints == hints)
1203 d->inputMethodHints = hints;
1204 d->updateInputMethodHints();
1208 \qmlproperty Component QtQuick2::TextInput::cursorDelegate
1209 The delegate for the cursor in the TextInput.
1211 If you set a cursorDelegate for a TextInput, this delegate will be used for
1212 drawing the cursor instead of the standard cursor. An instance of the
1213 delegate will be created and managed by the TextInput when a cursor is
1214 needed, and the x property of delegate instance will be set so as
1215 to be one pixel before the top left of the current character.
1217 Note that the root item of the delegate component must be a QDeclarativeItem or
1218 QDeclarativeItem derived item.
1220 QDeclarativeComponent* QQuickTextInput::cursorDelegate() const
1222 Q_D(const QQuickTextInput);
1223 return d->cursorComponent;
1226 void QQuickTextInput::setCursorDelegate(QDeclarativeComponent* c)
1228 Q_D(QQuickTextInput);
1229 if (d->cursorComponent == c)
1232 d->cursorComponent = c;
1234 //note that the components are owned by something else
1235 delete d->cursorItem;
1237 d->startCreatingCursor();
1240 emit cursorDelegateChanged();
1243 void QQuickTextInputPrivate::startCreatingCursor()
1245 Q_Q(QQuickTextInput);
1246 if (cursorComponent->isReady()) {
1248 } else if (cursorComponent->isLoading()) {
1249 q->connect(cursorComponent, SIGNAL(statusChanged(int)),
1250 q, SLOT(createCursor()));
1252 qmlInfo(q, cursorComponent->errors()) << QQuickTextInput::tr("Could not load cursor delegate");
1256 void QQuickTextInput::createCursor()
1258 Q_D(QQuickTextInput);
1259 if (!isComponentComplete())
1262 if (d->cursorComponent->isError()) {
1263 qmlInfo(this, d->cursorComponent->errors()) << tr("Could not load cursor delegate");
1267 if (!d->cursorComponent->isReady())
1271 delete d->cursorItem;
1272 QDeclarativeContext *creationContext = d->cursorComponent->creationContext();
1273 QObject *object = d->cursorComponent->create(creationContext ? creationContext : qmlContext(this));
1274 d->cursorItem = qobject_cast<QQuickItem*>(object);
1275 if (!d->cursorItem) {
1277 qmlInfo(this, d->cursorComponent->errors()) << tr("Could not instantiate cursor delegate");
1281 QRectF r = cursorRectangle();
1283 QDeclarative_setParent_noEvent(d->cursorItem, this);
1284 d->cursorItem->setParentItem(this);
1285 d->cursorItem->setPos(r.topLeft());
1286 d->cursorItem->setHeight(r.height());
1290 \qmlmethod rect QtQuick2::TextInput::positionToRectangle(int pos)
1292 This function takes a character position and returns the rectangle that the
1293 cursor would occupy, if it was placed at that character position.
1295 This is similar to setting the cursorPosition, and then querying the cursor
1296 rectangle, but the cursorPosition is not changed.
1298 QRectF QQuickTextInput::positionToRectangle(int pos) const
1300 Q_D(const QQuickTextInput);
1301 if (pos > d->m_cursor)
1302 pos += d->preeditAreaText().length();
1303 QTextLine l = d->m_textLayout.lineAt(0);
1305 ? QRectF(l.cursorToX(pos) - d->hscroll, 0.0, d->m_cursorWidth, l.height())
1310 \qmlmethod int QtQuick2::TextInput::positionAt(real x, real y, CursorPosition position = CursorBetweenCharacters)
1312 This function returns the character position at
1313 x and y pixels from the top left of the textInput. Position 0 is before the
1314 first character, position 1 is after the first character but before the second,
1315 and so on until position text.length, which is after all characters.
1317 This means that for all x values before the first character this function returns 0,
1318 and for all x values after the last character this function returns text.length. If
1319 the y value is above the text the position will be that of the nearest character on
1320 the first line line and if it is below the text the position of the nearest character
1321 on the last line will be returned.
1323 The cursor position type specifies how the cursor position should be resolved.
1326 \o TextInput.CursorBetweenCharacters - Returns the position between characters that is nearest x.
1327 \o TextInput.CursorOnCharacter - Returns the position before the character that is nearest x.
1331 void QQuickTextInput::positionAt(QDeclarativeV8Function *args) const
1333 Q_D(const QQuickTextInput);
1337 QTextLine::CursorPosition position = QTextLine::CursorBetweenCharacters;
1339 if (args->Length() < 1)
1343 v8::Local<v8::Value> arg = (*args)[i];
1344 x = arg->NumberValue();
1346 if (++i < args->Length()) {
1348 y = arg->NumberValue();
1351 if (++i < args->Length()) {
1353 position = QTextLine::CursorPosition(arg->Int32Value());
1356 int pos = d->positionAt(x, y, position);
1357 const int cursor = d->m_cursor;
1359 const int preeditLength = d->preeditAreaText().length();
1360 pos = pos > cursor + preeditLength
1361 ? pos - preeditLength
1364 args->returnValue(v8::Int32::New(pos));
1367 int QQuickTextInputPrivate::positionAt(int x, int y, QTextLine::CursorPosition position) const
1371 QTextLine line = m_textLayout.lineAt(0);
1372 for (int i = 1; i < m_textLayout.lineCount(); ++i) {
1373 QTextLine nextLine = m_textLayout.lineAt(i);
1375 if (y < (line.rect().bottom() + nextLine.y()) / 2)
1379 return line.isValid() ? line.xToCursor(x, position) : 0;
1382 void QQuickTextInput::keyPressEvent(QKeyEvent* ev)
1384 Q_D(QQuickTextInput);
1385 // Don't allow MacOSX up/down support, and we don't allow a completer.
1386 bool ignore = (ev->key() == Qt::Key_Up || ev->key() == Qt::Key_Down) && ev->modifiers() == Qt::NoModifier;
1387 if (!ignore && (d->lastSelectionStart == d->lastSelectionEnd) && (ev->key() == Qt::Key_Right || ev->key() == Qt::Key_Left)) {
1388 // Ignore when moving off the end unless there is a selection,
1389 // because then moving will do something (deselect).
1390 int cursorPosition = d->m_cursor;
1391 if (cursorPosition == 0)
1392 ignore = ev->key() == (d->layoutDirection() == Qt::LeftToRight ? Qt::Key_Left : Qt::Key_Right);
1393 if (cursorPosition == text().length())
1394 ignore = ev->key() == (d->layoutDirection() == Qt::LeftToRight ? Qt::Key_Right : Qt::Key_Left);
1399 d->processKeyEvent(ev);
1401 if (!ev->isAccepted())
1402 QQuickImplicitSizeItem::keyPressEvent(ev);
1405 void QQuickTextInput::inputMethodEvent(QInputMethodEvent *ev)
1407 Q_D(QQuickTextInput);
1408 const bool wasComposing = d->preeditAreaText().length() > 0;
1409 if (d->m_readOnly) {
1412 d->processInputMethodEvent(ev);
1414 if (!ev->isAccepted())
1415 QQuickImplicitSizeItem::inputMethodEvent(ev);
1417 if (wasComposing != (d->m_textLayout.preeditAreaText().length() > 0))
1418 emit inputMethodComposingChanged();
1421 void QQuickTextInput::mouseDoubleClickEvent(QMouseEvent *event)
1423 Q_D(QQuickTextInput);
1425 if (d->selectByMouse && event->button() == Qt::LeftButton) {
1427 int cursor = d->positionAt(event->localPos());
1428 d->selectWordAtPos(cursor);
1429 event->setAccepted(true);
1430 if (!d->hasPendingTripleClick()) {
1431 d->tripleClickStartPoint = event->localPos().toPoint();
1432 d->tripleClickTimer.start();
1435 if (d->sendMouseEventToInputContext(event))
1437 QQuickImplicitSizeItem::mouseDoubleClickEvent(event);
1441 void QQuickTextInput::mousePressEvent(QMouseEvent *event)
1443 Q_D(QQuickTextInput);
1445 d->pressPos = event->localPos();
1447 if (d->focusOnPress) {
1448 bool hadActiveFocus = hasActiveFocus();
1450 // re-open input panel on press if already focused
1451 if (hasActiveFocus() && hadActiveFocus && !d->m_readOnly)
1452 openSoftwareInputPanel();
1454 if (d->selectByMouse) {
1455 setKeepMouseGrab(false);
1456 d->selectPressed = true;
1457 QPoint distanceVector = d->pressPos.toPoint() - d->tripleClickStartPoint;
1458 if (d->hasPendingTripleClick()
1459 && distanceVector.manhattanLength() < qApp->styleHints()->startDragDistance()) {
1460 event->setAccepted(true);
1466 if (d->sendMouseEventToInputContext(event))
1469 bool mark = (event->modifiers() & Qt::ShiftModifier) && d->selectByMouse;
1470 int cursor = d->positionAt(event->localPos());
1471 d->moveCursor(cursor, mark);
1472 event->setAccepted(true);
1475 void QQuickTextInput::mouseMoveEvent(QMouseEvent *event)
1477 Q_D(QQuickTextInput);
1479 if (d->selectPressed) {
1480 if (qAbs(int(event->localPos().x() - d->pressPos.x())) > qApp->styleHints()->startDragDistance())
1481 setKeepMouseGrab(true);
1483 if (d->composeMode()) {
1485 int startPos = d->positionAt(d->pressPos);
1486 int currentPos = d->positionAt(event->localPos());
1487 if (startPos != currentPos)
1488 d->setSelection(startPos, currentPos - startPos);
1490 moveCursorSelection(d->positionAt(event->localPos()), d->mouseSelectionMode);
1492 event->setAccepted(true);
1494 QQuickImplicitSizeItem::mouseMoveEvent(event);
1498 void QQuickTextInput::mouseReleaseEvent(QMouseEvent *event)
1500 Q_D(QQuickTextInput);
1501 if (d->sendMouseEventToInputContext(event))
1503 if (d->selectPressed) {
1504 d->selectPressed = false;
1505 setKeepMouseGrab(false);
1507 #ifndef QT_NO_CLIPBOARD
1508 if (QGuiApplication::clipboard()->supportsSelection()) {
1509 if (event->button() == Qt::LeftButton) {
1510 d->copy(QClipboard::Selection);
1511 } else if (!d->m_readOnly && event->button() == Qt::MidButton) {
1513 d->insert(QGuiApplication::clipboard()->text(QClipboard::Selection));
1517 if (!event->isAccepted())
1518 QQuickImplicitSizeItem::mouseReleaseEvent(event);
1521 bool QQuickTextInputPrivate::sendMouseEventToInputContext(QMouseEvent *event)
1523 #if !defined QT_NO_IM
1524 if (composeMode()) {
1525 int tmp_cursor = positionAt(event->localPos());
1526 int mousePos = tmp_cursor - m_cursor;
1527 if (mousePos >= 0 && mousePos <= m_textLayout.preeditAreaText().length()) {
1528 if (event->type() == QEvent::MouseButtonRelease) {
1529 qApp->inputPanel()->invokeAction(QInputPanel::Click, mousePos);
1542 void QQuickTextInput::mouseUngrabEvent()
1544 Q_D(QQuickTextInput);
1545 d->selectPressed = false;
1546 setKeepMouseGrab(false);
1549 bool QQuickTextInput::event(QEvent* ev)
1551 #ifndef QT_NO_SHORTCUT
1552 Q_D(QQuickTextInput);
1553 if (ev->type() == QEvent::ShortcutOverride) {
1556 QKeyEvent* ke = static_cast<QKeyEvent*>(ev);
1557 if (ke == QKeySequence::Copy
1558 || ke == QKeySequence::Paste
1559 || ke == QKeySequence::Cut
1560 || ke == QKeySequence::Redo
1561 || ke == QKeySequence::Undo
1562 || ke == QKeySequence::MoveToNextWord
1563 || ke == QKeySequence::MoveToPreviousWord
1564 || ke == QKeySequence::MoveToStartOfDocument
1565 || ke == QKeySequence::MoveToEndOfDocument
1566 || ke == QKeySequence::SelectNextWord
1567 || ke == QKeySequence::SelectPreviousWord
1568 || ke == QKeySequence::SelectStartOfLine
1569 || ke == QKeySequence::SelectEndOfLine
1570 || ke == QKeySequence::SelectStartOfBlock
1571 || ke == QKeySequence::SelectEndOfBlock
1572 || ke == QKeySequence::SelectStartOfDocument
1573 || ke == QKeySequence::SelectAll
1574 || ke == QKeySequence::SelectEndOfDocument) {
1576 } else if (ke->modifiers() == Qt::NoModifier || ke->modifiers() == Qt::ShiftModifier
1577 || ke->modifiers() == Qt::KeypadModifier) {
1578 if (ke->key() < Qt::Key_Escape) {
1582 switch (ke->key()) {
1583 case Qt::Key_Delete:
1586 case Qt::Key_Backspace:
1598 return QQuickImplicitSizeItem::event(ev);
1601 void QQuickTextInput::geometryChanged(const QRectF &newGeometry,
1602 const QRectF &oldGeometry)
1604 Q_D(QQuickTextInput);
1605 if (newGeometry.width() != oldGeometry.width())
1607 updateCursorRectangle();
1608 QQuickImplicitSizeItem::geometryChanged(newGeometry, oldGeometry);
1611 void QQuickTextInputPrivate::updateHorizontalScroll()
1613 Q_Q(QQuickTextInput);
1614 QTextLine currentLine = m_textLayout.lineForTextPosition(m_cursor + m_preeditCursor);
1615 const int preeditLength = m_textLayout.preeditAreaText().length();
1616 const int width = qMax(0, qFloor(q->width()));
1617 int widthUsed = currentLine.isValid() ? qRound(currentLine.naturalTextWidth()) : 0;
1618 int previousScroll = hscroll;
1620 if (!autoScroll || widthUsed <= width || m_echoMode == QQuickTextInput::NoEcho) {
1623 Q_ASSERT(currentLine.isValid());
1624 int cix = qRound(currentLine.cursorToX(m_cursor + preeditLength));
1625 if (cix - hscroll >= width) {
1626 // text doesn't fit, cursor is to the right of br (scroll right)
1627 hscroll = cix - width;
1628 } else if (cix - hscroll < 0 && hscroll < widthUsed) {
1629 // text doesn't fit, cursor is to the left of br (scroll left)
1631 } else if (widthUsed - hscroll < width) {
1632 // text doesn't fit, text document is to the left of br; align
1634 hscroll = widthUsed - width;
1636 if (preeditLength > 0) {
1637 // check to ensure long pre-edit text doesn't push the cursor
1639 cix = qRound(currentLine.cursorToX(m_cursor + qMax(0, m_preeditCursor - 1)));
1644 if (previousScroll != hscroll)
1645 textLayoutDirty = true;
1648 void QQuickTextInputPrivate::updateVerticalScroll()
1650 Q_Q(QQuickTextInput);
1651 const int preeditLength = m_textLayout.preeditAreaText().length();
1652 const int height = qMax(0, qFloor(q->height()));
1653 int heightUsed = boundingRect.height();
1654 int previousScroll = vscroll;
1656 if (!autoScroll || heightUsed <= height) {
1657 // text fits in br; use vscroll for alignment
1658 switch (vAlign & ~(Qt::AlignAbsolute|Qt::AlignHorizontal_Mask)) {
1659 case Qt::AlignBottom:
1660 vscroll = heightUsed - height;
1662 case Qt::AlignVCenter:
1663 vscroll = (heightUsed - height) / 2;
1671 QTextLine currentLine = m_textLayout.lineForTextPosition(m_cursor + preeditLength);
1672 QRectF r = currentLine.isValid() ? currentLine.rect() : QRectF();
1673 int top = qFloor(r.top());
1674 int bottom = qCeil(r.bottom());
1676 if (bottom - vscroll >= height) {
1677 // text doesn't fit, cursor is to the below the br (scroll down)
1678 vscroll = bottom - height;
1679 } else if (top - vscroll < 0 && vscroll < heightUsed) {
1680 // text doesn't fit, cursor is above br (scroll up)
1682 } else if (heightUsed - vscroll < height) {
1683 // text doesn't fit, text document is to the left of br; align
1685 vscroll = heightUsed - height;
1687 if (preeditLength > 0) {
1688 // check to ensure long pre-edit text doesn't push the cursor
1690 currentLine = m_textLayout.lineForTextPosition(m_cursor + qMax(0, m_preeditCursor - 1));
1691 top = currentLine.isValid() ? qRound(currentLine.rect().top()) : 0;
1696 if (previousScroll != vscroll)
1697 textLayoutDirty = true;
1700 void QQuickTextInput::triggerPreprocess()
1702 Q_D(QQuickTextInput);
1703 if (d->updateType == QQuickTextInputPrivate::UpdateNone)
1704 d->updateType = QQuickTextInputPrivate::UpdateOnlyPreprocess;
1708 QSGNode *QQuickTextInput::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data)
1711 Q_D(QQuickTextInput);
1713 if (d->updateType != QQuickTextInputPrivate::UpdatePaintNode && oldNode != 0) {
1714 // Update done in preprocess() in the nodes
1715 d->updateType = QQuickTextInputPrivate::UpdateNone;
1719 d->updateType = QQuickTextInputPrivate::UpdateNone;
1721 QQuickTextNode *node = static_cast<QQuickTextNode *>(oldNode);
1723 node = new QQuickTextNode(QQuickItemPrivate::get(this)->sceneGraphContext(), this);
1726 if (!d->textLayoutDirty) {
1727 QSGSimpleRectNode *cursorNode = node->cursorNode();
1728 if (cursorNode != 0 && !isReadOnly()) {
1729 cursorNode->setRect(cursorRectangle());
1731 if (!d->cursorVisible || (!d->m_blinkStatus && d->m_blinkPeriod > 0)) {
1738 node->deleteContent();
1739 node->setMatrix(QMatrix4x4());
1741 QPoint offset = QPoint(0,0);
1742 QFontMetrics fm = QFontMetrics(d->font);
1743 if (d->autoScroll) {
1744 // the y offset is there to keep the baseline constant in case we have script changes in the text.
1745 offset = -QPoint(d->hscroll, d->vscroll + d->m_ascent - fm.ascent());
1747 offset = -QPoint(d->hscroll, d->vscroll);
1750 if (!d->m_textLayout.text().isEmpty() || !d->m_textLayout.preeditAreaText().isEmpty()) {
1751 node->addTextLayout(offset, &d->m_textLayout, d->color,
1752 QQuickText::Normal, QColor(),
1753 d->selectionColor, d->selectedTextColor,
1754 d->selectionStart(),
1755 d->selectionEnd() - 1); // selectionEnd() returns first char after
1759 if (!isReadOnly() && d->cursorItem == 0) {
1760 node->setCursor(cursorRectangle(), d->color);
1761 if (!d->cursorVisible || (!d->m_blinkStatus && d->m_blinkPeriod > 0)) {
1768 d->textLayoutDirty = false;
1774 QVariant QQuickTextInput::inputMethodQuery(Qt::InputMethodQuery property) const
1776 Q_D(const QQuickTextInput);
1779 return QVariant((bool)(flags() & ItemAcceptsInputMethod));
1781 return QVariant((int)inputMethodHints());
1782 case Qt::ImCursorRectangle:
1783 return cursorRectangle();
1786 case Qt::ImCursorPosition:
1787 return QVariant(d->m_cursor);
1788 case Qt::ImSurroundingText:
1789 if (d->m_echoMode == PasswordEchoOnEdit && !d->m_passwordEchoEditing) {
1790 return QVariant(displayText());
1792 return QVariant(d->realText());
1794 case Qt::ImCurrentSelection:
1795 return QVariant(selectedText());
1796 case Qt::ImMaximumTextLength:
1797 return QVariant(maxLength());
1798 case Qt::ImAnchorPosition:
1799 if (d->selectionStart() == d->selectionEnd())
1800 return QVariant(d->m_cursor);
1801 else if (d->selectionStart() == d->m_cursor)
1802 return QVariant(d->selectionEnd());
1804 return QVariant(d->selectionStart());
1811 \qmlmethod void QtQuick2::TextInput::deselect()
1813 Removes active text selection.
1815 void QQuickTextInput::deselect()
1817 Q_D(QQuickTextInput);
1822 \qmlmethod void QtQuick2::TextInput::selectAll()
1824 Causes all text to be selected.
1826 void QQuickTextInput::selectAll()
1828 Q_D(QQuickTextInput);
1829 d->setSelection(0, text().length());
1833 \qmlmethod void QtQuick2::TextInput::isRightToLeft(int start, int end)
1835 Returns true if the natural reading direction of the editor text
1836 found between positions \a start and \a end is right to left.
1838 bool QQuickTextInput::isRightToLeft(int start, int end)
1841 qmlInfo(this) << "isRightToLeft(start, end) called with the end property being smaller than the start.";
1844 return text().mid(start, end - start).isRightToLeft();
1848 #ifndef QT_NO_CLIPBOARD
1850 \qmlmethod QtQuick2::TextInput::cut()
1852 Moves the currently selected text to the system clipboard.
1854 void QQuickTextInput::cut()
1856 Q_D(QQuickTextInput);
1862 \qmlmethod QtQuick2::TextInput::copy()
1864 Copies the currently selected text to the system clipboard.
1866 void QQuickTextInput::copy()
1868 Q_D(QQuickTextInput);
1873 \qmlmethod QtQuick2::TextInput::paste()
1875 Replaces the currently selected text by the contents of the system clipboard.
1877 void QQuickTextInput::paste()
1879 Q_D(QQuickTextInput);
1883 #endif // QT_NO_CLIPBOARD
1886 Undoes the last operation if undo is \l {canUndo}{available}. Deselects any
1887 current selection, and updates the selection start to the current cursor
1891 void QQuickTextInput::undo()
1893 Q_D(QQuickTextInput);
1894 if (!d->m_readOnly) {
1896 d->finishChange(-1, true);
1901 Redoes the last operation if redo is \l {canRedo}{available}.
1904 void QQuickTextInput::redo()
1906 Q_D(QQuickTextInput);
1907 if (!d->m_readOnly) {
1914 \qmlmethod void QtQuick2::TextInput::insert(int position, string text)
1916 Inserts \a text into the TextInput at position.
1919 void QQuickTextInput::insert(int position, const QString &text)
1921 Q_D(QQuickTextInput);
1922 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
1923 if (d->m_echoMode == QQuickTextInput::Password)
1924 d->m_passwordEchoTimer.start(qt_passwordEchoDelay, this);
1927 if (position < 0 || position > d->m_text.length())
1930 const int priorState = d->m_undoState;
1932 QString insertText = text;
1934 if (d->hasSelectedText()) {
1935 d->addCommand(QQuickTextInputPrivate::Command(
1936 QQuickTextInputPrivate::SetSelection, d->m_cursor, 0, d->m_selstart, d->m_selend));
1938 if (d->m_maskData) {
1939 insertText = d->maskString(position, insertText);
1940 for (int i = 0; i < insertText.length(); ++i) {
1941 d->addCommand(QQuickTextInputPrivate::Command(
1942 QQuickTextInputPrivate::DeleteSelection, position + i, d->m_text.at(position + i), -1, -1));
1943 d->addCommand(QQuickTextInputPrivate::Command(
1944 QQuickTextInputPrivate::Insert, position + i, insertText.at(i), -1, -1));
1946 d->m_text.replace(position, insertText.length(), insertText);
1947 if (!insertText.isEmpty())
1948 d->m_textDirty = true;
1949 if (position < d->m_selend && position + insertText.length() > d->m_selstart)
1950 d->m_selDirty = true;
1952 int remaining = d->m_maxLength - d->m_text.length();
1953 if (remaining != 0) {
1954 insertText = insertText.left(remaining);
1955 d->m_text.insert(position, insertText);
1956 for (int i = 0; i < insertText.length(); ++i)
1957 d->addCommand(QQuickTextInputPrivate::Command(
1958 QQuickTextInputPrivate::Insert, position + i, insertText.at(i), -1, -1));
1959 if (d->m_cursor >= position)
1960 d->m_cursor += insertText.length();
1961 if (d->m_selstart >= position)
1962 d->m_selstart += insertText.length();
1963 if (d->m_selend >= position)
1964 d->m_selend += insertText.length();
1965 d->m_textDirty = true;
1966 if (position >= d->m_selstart && position <= d->m_selend)
1967 d->m_selDirty = true;
1971 d->addCommand(QQuickTextInputPrivate::Command(
1972 QQuickTextInputPrivate::SetSelection, d->m_cursor, 0, d->m_selstart, d->m_selend));
1973 d->finishChange(priorState);
1975 if (d->lastSelectionStart != d->lastSelectionEnd) {
1976 if (d->m_selstart != d->lastSelectionStart) {
1977 d->lastSelectionStart = d->m_selstart;
1978 emit selectionStartChanged();
1980 if (d->m_selend != d->lastSelectionEnd) {
1981 d->lastSelectionEnd = d->m_selend;
1982 emit selectionEndChanged();
1988 \qmlmethod string QtQuick2::TextInput::getText(int start, int end)
1990 Removes the section of text that is between the \a start and \a end positions from the TextInput.
1993 void QQuickTextInput::remove(int start, int end)
1995 Q_D(QQuickTextInput);
1997 start = qBound(0, start, d->m_text.length());
1998 end = qBound(0, end, d->m_text.length());
2002 else if (start == end)
2005 if (start < d->m_selend && end > d->m_selstart)
2006 d->m_selDirty = true;
2008 const int priorState = d->m_undoState;
2010 d->addCommand(QQuickTextInputPrivate::Command(
2011 QQuickTextInputPrivate::SetSelection, d->m_cursor, 0, d->m_selstart, d->m_selend));
2013 if (start <= d->m_cursor && d->m_cursor < end) {
2014 // cursor is within the selection. Split up the commands
2015 // to be able to restore the correct cursor position
2016 for (int i = d->m_cursor; i >= start; --i) {
2017 d->addCommand(QQuickTextInputPrivate::Command(
2018 QQuickTextInputPrivate::DeleteSelection, i, d->m_text.at(i), -1, 1));
2020 for (int i = end - 1; i > d->m_cursor; --i) {
2021 d->addCommand(QQuickTextInputPrivate::Command(
2022 QQuickTextInputPrivate::DeleteSelection, i - d->m_cursor + start - 1, d->m_text.at(i), -1, -1));
2025 for (int i = end - 1; i >= start; --i) {
2026 d->addCommand(QQuickTextInputPrivate::Command(
2027 QQuickTextInputPrivate::RemoveSelection, i, d->m_text.at(i), -1, -1));
2030 if (d->m_maskData) {
2031 d->m_text.replace(start, end - start, d->clearString(start, end - start));
2032 for (int i = 0; i < end - start; ++i) {
2033 d->addCommand(QQuickTextInputPrivate::Command(
2034 QQuickTextInputPrivate::Insert, start + i, d->m_text.at(start + i), -1, -1));
2037 d->m_text.remove(start, end - start);
2039 if (d->m_cursor > start)
2040 d->m_cursor -= qMin(d->m_cursor, end) - start;
2041 if (d->m_selstart > start)
2042 d->m_selstart -= qMin(d->m_selstart, end) - start;
2043 if (d->m_selend > end)
2044 d->m_selend -= qMin(d->m_selend, end) - start;
2046 d->addCommand(QQuickTextInputPrivate::Command(
2047 QQuickTextInputPrivate::SetSelection, d->m_cursor, 0, d->m_selstart, d->m_selend));
2049 d->m_textDirty = true;
2050 d->finishChange(priorState);
2052 if (d->lastSelectionStart != d->lastSelectionEnd) {
2053 if (d->m_selstart != d->lastSelectionStart) {
2054 d->lastSelectionStart = d->m_selstart;
2055 emit selectionStartChanged();
2057 if (d->m_selend != d->lastSelectionEnd) {
2058 d->lastSelectionEnd = d->m_selend;
2059 emit selectionEndChanged();
2066 \qmlmethod void QtQuick2::TextInput::selectWord()
2068 Causes the word closest to the current cursor position to be selected.
2070 void QQuickTextInput::selectWord()
2072 Q_D(QQuickTextInput);
2073 d->selectWordAtPos(d->m_cursor);
2077 \qmlproperty bool QtQuick2::TextInput::smooth
2079 This property holds whether the text is smoothly scaled or transformed.
2081 Smooth filtering gives better visual quality, but is slower. If
2082 the item is displayed at its natural size, this property has no visual or
2085 \note Generally scaling artifacts are only visible if the item is stationary on
2086 the screen. A common pattern when animating an item is to disable smooth
2087 filtering at the beginning of the animation and reenable it at the conclusion.
2091 \qmlproperty string QtQuick2::TextInput::passwordCharacter
2093 This is the character displayed when echoMode is set to Password or
2094 PasswordEchoOnEdit. By default it is an asterisk.
2096 If this property is set to a string with more than one character,
2097 the first character is used. If the string is empty, the value
2098 is ignored and the property is not set.
2100 QString QQuickTextInput::passwordCharacter() const
2102 Q_D(const QQuickTextInput);
2103 return QString(d->m_passwordCharacter);
2106 void QQuickTextInput::setPasswordCharacter(const QString &str)
2108 Q_D(QQuickTextInput);
2109 if (str.length() < 1)
2111 d->m_passwordCharacter = str.constData()[0];
2112 if (d->m_echoMode == Password || d->m_echoMode == PasswordEchoOnEdit)
2113 d->updateDisplayText();
2114 emit passwordCharacterChanged();
2118 \qmlproperty string QtQuick2::TextInput::displayText
2120 This is the text displayed in the TextInput.
2122 If \l echoMode is set to TextInput::Normal, this holds the
2123 same value as the TextInput::text property. Otherwise,
2124 this property holds the text visible to the user, while
2125 the \l text property holds the actual entered text.
2127 QString QQuickTextInput::displayText() const
2129 Q_D(const QQuickTextInput);
2130 return d->m_textLayout.text();
2134 \qmlproperty bool QtQuick2::TextInput::selectByMouse
2138 If true, the user can use the mouse to select text in some
2139 platform-specific way. Note that for some platforms this may
2140 not be an appropriate interaction (eg. may conflict with how
2141 the text needs to behave inside a Flickable.
2143 bool QQuickTextInput::selectByMouse() const
2145 Q_D(const QQuickTextInput);
2146 return d->selectByMouse;
2149 void QQuickTextInput::setSelectByMouse(bool on)
2151 Q_D(QQuickTextInput);
2152 if (d->selectByMouse != on) {
2153 d->selectByMouse = on;
2154 emit selectByMouseChanged(on);
2159 \qmlproperty enum QtQuick2::TextInput::mouseSelectionMode
2161 Specifies how text should be selected using a mouse.
2164 \o TextInput.SelectCharacters - The selection is updated with individual characters. (Default)
2165 \o TextInput.SelectWords - The selection is updated with whole words.
2168 This property only applies when \l selectByMouse is true.
2171 QQuickTextInput::SelectionMode QQuickTextInput::mouseSelectionMode() const
2173 Q_D(const QQuickTextInput);
2174 return d->mouseSelectionMode;
2177 void QQuickTextInput::setMouseSelectionMode(SelectionMode mode)
2179 Q_D(QQuickTextInput);
2180 if (d->mouseSelectionMode != mode) {
2181 d->mouseSelectionMode = mode;
2182 emit mouseSelectionModeChanged(mode);
2187 \qmlproperty bool QtQuick2::TextInput::canPaste
2189 Returns true if the TextInput is writable and the content of the clipboard is
2190 suitable for pasting into the TextInput.
2192 bool QQuickTextInput::canPaste() const
2194 Q_D(const QQuickTextInput);
2195 if (!d->canPasteValid) {
2196 if (const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData())
2197 const_cast<QQuickTextInputPrivate *>(d)->canPaste = !d->m_readOnly && mimeData->hasText();
2198 const_cast<QQuickTextInputPrivate *>(d)->canPasteValid = true;
2204 \qmlproperty bool QtQuick2::TextInput::canUndo
2206 Returns true if the TextInput is writable and there are previous operations
2210 bool QQuickTextInput::canUndo() const
2212 Q_D(const QQuickTextInput);
2217 \qmlproperty bool QtQuick2::TextInput::canRedo
2219 Returns true if the TextInput is writable and there are \l {undo}{undone}
2220 operations that can be redone.
2223 bool QQuickTextInput::canRedo() const
2225 Q_D(const QQuickTextInput);
2229 void QQuickTextInput::moveCursorSelection(int position)
2231 Q_D(QQuickTextInput);
2232 d->moveCursor(position, true);
2236 \qmlmethod void QtQuick2::TextInput::moveCursorSelection(int position, SelectionMode mode = TextInput.SelectCharacters)
2238 Moves the cursor to \a position and updates the selection according to the optional \a mode
2239 parameter. (To only move the cursor, set the \l cursorPosition property.)
2241 When this method is called it additionally sets either the
2242 selectionStart or the selectionEnd (whichever was at the previous cursor position)
2243 to the specified position. This allows you to easily extend and contract the selected
2246 The selection mode specifies whether the selection is updated on a per character or a per word
2247 basis. If not specified the selection mode will default to TextInput.SelectCharacters.
2250 \o TextInput.SelectCharacters - Sets either the selectionStart or selectionEnd (whichever was at
2251 the previous cursor position) to the specified position.
2252 \o TextInput.SelectWords - Sets the selectionStart and selectionEnd to include all
2253 words between the specified position and the previous cursor position. Words partially in the
2257 For example, take this sequence of calls:
2261 moveCursorSelection(9, TextInput.SelectCharacters)
2262 moveCursorSelection(7, TextInput.SelectCharacters)
2265 This moves the cursor to position 5, extend the selection end from 5 to 9
2266 and then retract the selection end from 9 to 7, leaving the text from position 5 to 7
2267 selected (the 6th and 7th characters).
2269 The same sequence with TextInput.SelectWords will extend the selection start to a word boundary
2270 before or on position 5 and extend the selection end to a word boundary on or past position 9.
2272 void QQuickTextInput::moveCursorSelection(int pos, SelectionMode mode)
2274 Q_D(QQuickTextInput);
2276 if (mode == SelectCharacters) {
2277 d->moveCursor(pos, true);
2278 } else if (pos != d->m_cursor){
2279 const int cursor = d->m_cursor;
2281 if (!d->hasSelectedText())
2282 anchor = d->m_cursor;
2283 else if (d->selectionStart() == d->m_cursor)
2284 anchor = d->selectionEnd();
2286 anchor = d->selectionStart();
2288 if (anchor < pos || (anchor == pos && cursor < pos)) {
2289 const QString text = this->text();
2290 QTextBoundaryFinder finder(QTextBoundaryFinder::Word, text);
2291 finder.setPosition(anchor);
2293 const QTextBoundaryFinder::BoundaryReasons reasons = finder.boundaryReasons();
2294 if (anchor < text.length() && (!(reasons & QTextBoundaryFinder::StartWord)
2295 || ((reasons & QTextBoundaryFinder::EndWord) && anchor > cursor))) {
2296 finder.toPreviousBoundary();
2298 anchor = finder.position() != -1 ? finder.position() : 0;
2300 finder.setPosition(pos);
2301 if (pos > 0 && !finder.boundaryReasons())
2302 finder.toNextBoundary();
2303 const int cursor = finder.position() != -1 ? finder.position() : text.length();
2305 d->setSelection(anchor, cursor - anchor);
2306 } else if (anchor > pos || (anchor == pos && cursor > pos)) {
2307 const QString text = this->text();
2308 QTextBoundaryFinder finder(QTextBoundaryFinder::Word, text);
2309 finder.setPosition(anchor);
2311 const QTextBoundaryFinder::BoundaryReasons reasons = finder.boundaryReasons();
2312 if (anchor > 0 && (!(reasons & QTextBoundaryFinder::EndWord)
2313 || ((reasons & QTextBoundaryFinder::StartWord) && anchor < cursor))) {
2314 finder.toNextBoundary();
2317 anchor = finder.position() != -1 ? finder.position() : text.length();
2319 finder.setPosition(pos);
2320 if (pos < text.length() && !finder.boundaryReasons())
2321 finder.toPreviousBoundary();
2322 const int cursor = finder.position() != -1 ? finder.position() : 0;
2324 d->setSelection(anchor, cursor - anchor);
2330 \qmlmethod void QtQuick2::TextInput::openSoftwareInputPanel()
2332 Opens software input panels like virtual keyboards for typing, useful for
2333 customizing when you want the input keyboard to be shown and hidden in
2336 By default the opening of input panels follows the platform style. Input panels are
2337 always closed if no editor has active focus.
2339 You can disable the automatic behavior by setting the property \c activeFocusOnPress to false
2340 and use functions openSoftwareInputPanel() and closeSoftwareInputPanel() to implement
2341 the behavior you want.
2343 Only relevant on platforms, which provide virtual keyboards.
2349 text: "Hello world!"
2350 activeFocusOnPress: false
2352 anchors.fill: parent
2354 if (!textInput.activeFocus) {
2355 textInput.forceActiveFocus()
2356 textInput.openSoftwareInputPanel();
2358 textInput.focus = false;
2361 onPressAndHold: textInput.closeSoftwareInputPanel();
2366 void QQuickTextInput::openSoftwareInputPanel()
2369 qGuiApp->inputPanel()->show();
2373 \qmlmethod void QtQuick2::TextInput::closeSoftwareInputPanel()
2375 Closes a software input panel like a virtual keyboard shown on the screen, useful
2376 for customizing when you want the input keyboard to be shown and hidden in
2379 By default the opening of input panels follows the platform style. Input panels are
2380 always closed if no editor has active focus.
2382 You can disable the automatic behavior by setting the property \c activeFocusOnPress to false
2383 and use functions openSoftwareInputPanel() and closeSoftwareInputPanel() to implement
2384 the behavior you want.
2386 Only relevant on platforms, which provide virtual keyboards.
2392 text: "Hello world!"
2393 activeFocusOnPress: false
2395 anchors.fill: parent
2397 if (!textInput.activeFocus) {
2398 textInput.forceActiveFocus();
2399 textInput.openSoftwareInputPanel();
2401 textInput.focus = false;
2404 onPressAndHold: textInput.closeSoftwareInputPanel();
2409 void QQuickTextInput::closeSoftwareInputPanel()
2412 qGuiApp->inputPanel()->hide();
2415 void QQuickTextInput::focusInEvent(QFocusEvent *event)
2417 Q_D(const QQuickTextInput);
2418 if (d->focusOnPress && !d->m_readOnly)
2419 openSoftwareInputPanel();
2420 QQuickImplicitSizeItem::focusInEvent(event);
2423 void QQuickTextInput::itemChange(ItemChange change, const ItemChangeData &value)
2425 Q_D(QQuickTextInput);
2426 if (change == ItemActiveFocusHasChanged) {
2427 bool hasFocus = value.boolValue;
2428 d->focused = hasFocus;
2429 setCursorVisible(hasFocus); // ### refactor: && d->canvas && d->canvas->hasFocus()
2430 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
2431 if (!hasFocus && (d->m_passwordEchoEditing || d->m_passwordEchoTimer.isActive())) {
2433 if (!hasFocus && d->m_passwordEchoEditing) {
2435 d->updatePasswordEchoEditing(false);//QQuickTextInputPrivate sets it on key events, but doesn't deal with focus events
2441 disconnect(qApp->inputPanel(), SIGNAL(inputDirectionChanged(Qt::LayoutDirection)),
2442 this, SLOT(q_updateAlignment()));
2444 q_updateAlignment();
2445 connect(qApp->inputPanel(), SIGNAL(inputDirectionChanged(Qt::LayoutDirection)),
2446 this, SLOT(q_updateAlignment()));
2449 QQuickItem::itemChange(change, value);
2453 \qmlproperty bool QtQuick2::TextInput::inputMethodComposing
2456 This property holds whether the TextInput has partial text input from an
2459 While it is composing an input method may rely on mouse or key events from
2460 the TextInput to edit or commit the partial text. This property can be
2461 used to determine when to disable events handlers that may interfere with
2462 the correct operation of an input method.
2464 bool QQuickTextInput::isInputMethodComposing() const
2466 Q_D(const QQuickTextInput);
2467 return d->preeditAreaText().length() > 0;
2470 void QQuickTextInputPrivate::init()
2472 Q_Q(QQuickTextInput);
2473 q->setSmooth(smooth);
2474 q->setAcceptedMouseButtons(Qt::LeftButton);
2475 q->setFlag(QQuickItem::ItemAcceptsInputMethod);
2476 q->setFlag(QQuickItem::ItemHasContents);
2477 #ifndef QT_NO_CLIPBOARD
2478 q->connect(QGuiApplication::clipboard(), SIGNAL(dataChanged()),
2479 q, SLOT(q_canPasteChanged()));
2480 #endif // QT_NO_CLIPBOARD
2482 lastSelectionStart = 0;
2483 lastSelectionEnd = 0;
2484 selectedTextColor = m_palette.color(QPalette::HighlightedText);
2485 selectionColor = m_palette.color(QPalette::Highlight);
2486 determineHorizontalAlignment();
2488 if (!qmlDisableDistanceField()) {
2489 QTextOption option = m_textLayout.textOption();
2490 option.setUseDesignMetrics(true);
2491 m_textLayout.setTextOption(option);
2495 void QQuickTextInput::updateCursorRectangle()
2497 Q_D(QQuickTextInput);
2498 if (!isComponentComplete())
2501 d->updateHorizontalScroll();
2502 d->updateVerticalScroll();
2503 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
2505 emit cursorRectangleChanged();
2506 if (d->cursorItem) {
2507 QRectF r = cursorRectangle();
2508 d->cursorItem->setPos(r.topLeft());
2509 d->cursorItem->setHeight(r.height());
2513 void QQuickTextInput::selectionChanged()
2515 Q_D(QQuickTextInput);
2516 d->textLayoutDirty = true; //TODO: Only update rect in selection
2517 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
2519 emit selectedTextChanged();
2521 if (d->lastSelectionStart != d->selectionStart()) {
2522 d->lastSelectionStart = d->selectionStart();
2523 if (d->lastSelectionStart == -1)
2524 d->lastSelectionStart = d->m_cursor;
2525 emit selectionStartChanged();
2527 if (d->lastSelectionEnd != d->selectionEnd()) {
2528 d->lastSelectionEnd = d->selectionEnd();
2529 if (d->lastSelectionEnd == -1)
2530 d->lastSelectionEnd = d->m_cursor;
2531 emit selectionEndChanged();
2535 void QQuickTextInputPrivate::showCursor()
2537 if (textNode != 0 && textNode->cursorNode() != 0)
2538 textNode->cursorNode()->setColor(color);
2541 void QQuickTextInputPrivate::hideCursor()
2543 if (textNode != 0 && textNode->cursorNode() != 0)
2544 textNode->cursorNode()->setColor(QColor(0, 0, 0, 0));
2547 QRectF QQuickTextInput::boundingRect() const
2549 Q_D(const QQuickTextInput);
2551 int cursorWidth = d->cursorItem ? d->cursorItem->width() : d->m_cursorWidth;
2553 // Could include font max left/right bearings to either side of rectangle.
2554 QRectF r = QQuickImplicitSizeItem::boundingRect();
2555 r.setRight(r.right() + cursorWidth);
2559 void QQuickTextInput::q_canPasteChanged()
2561 Q_D(QQuickTextInput);
2562 bool old = d->canPaste;
2563 #ifndef QT_NO_CLIPBOARD
2564 if (const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData())
2565 d->canPaste = !d->m_readOnly && mimeData->hasText();
2567 d->canPaste = false;
2570 bool changed = d->canPaste != old || !d->canPasteValid;
2571 d->canPasteValid = true;
2573 emit canPasteChanged();
2577 void QQuickTextInput::q_updateAlignment()
2579 Q_D(QQuickTextInput);
2580 if (d->determineHorizontalAlignment()) {
2582 updateCursorRectangle();
2586 // ### these should come from QStyleHints
2587 const int textCursorWidth = 1;
2588 const bool fullWidthSelection = true;
2593 Updates the display text based of the current edit text
2594 If the text has changed will emit displayTextChanged()
2596 void QQuickTextInputPrivate::updateDisplayText(bool forceUpdate)
2598 QString orig = m_textLayout.text();
2600 if (m_echoMode == QQuickTextInput::NoEcho)
2601 str = QString::fromLatin1("");
2605 if (m_echoMode == QQuickTextInput::Password) {
2606 str.fill(m_passwordCharacter);
2607 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
2608 if (m_passwordEchoTimer.isActive() && m_cursor > 0 && m_cursor <= m_text.length()) {
2609 int cursor = m_cursor - 1;
2610 QChar uc = m_text.at(cursor);
2612 if (cursor > 0 && uc.unicode() >= 0xdc00 && uc.unicode() < 0xe000) {
2613 // second half of a surrogate, check if we have the first half as well,
2614 // if yes restore both at once
2615 uc = m_text.at(cursor - 1);
2616 if (uc.unicode() >= 0xd800 && uc.unicode() < 0xdc00)
2617 str[cursor - 1] = uc;
2621 } else if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit && !m_passwordEchoEditing) {
2622 str.fill(m_passwordCharacter);
2625 // replace certain non-printable characters with spaces (to avoid
2626 // drawing boxes when using fonts that don't have glyphs for such
2628 QChar* uc = str.data();
2629 for (int i = 0; i < (int)str.length(); ++i) {
2630 if ((uc[i] < 0x20 && uc[i] != 0x09)
2631 || uc[i] == QChar::LineSeparator
2632 || uc[i] == QChar::ParagraphSeparator
2633 || uc[i] == QChar::ObjectReplacementCharacter)
2634 uc[i] = QChar(0x0020);
2637 if (str != orig || forceUpdate) {
2638 m_textLayout.setText(str);
2639 updateLayout(); // polish?
2640 emit q_func()->displayTextChanged();
2644 void QQuickTextInputPrivate::updateLayout()
2646 Q_Q(QQuickTextInput);
2648 if (!q->isComponentComplete())
2651 QTextOption option = m_textLayout.textOption();
2652 option.setTextDirection(layoutDirection());
2653 option.setFlags(QTextOption::IncludeTrailingSpaces);
2654 option.setWrapMode(QTextOption::WrapMode(wrapMode));
2655 option.setAlignment(Qt::Alignment(q->effectiveHAlign()));
2656 m_textLayout.setTextOption(option);
2657 m_textLayout.setFont(font);
2659 boundingRect = QRectF();
2660 m_textLayout.beginLayout();
2661 QTextLine line = m_textLayout.createLine();
2662 qreal lineWidth = q->widthValid() ? q->width() : INT_MAX;
2664 QTextLine firstLine = line;
2666 line.setLineWidth(lineWidth);
2667 line.setPosition(QPointF(line.position().x(), height));
2668 boundingRect = boundingRect.united(line.naturalTextRect());
2670 height += line.height();
2671 line = m_textLayout.createLine();
2672 } while (line.isValid());
2673 m_textLayout.endLayout();
2675 option.setWrapMode(QTextOption::NoWrap);
2676 m_textLayout.setTextOption(option);
2678 m_ascent = qRound(firstLine.ascent());
2679 textLayoutDirty = true;
2681 updateType = UpdatePaintNode;
2683 q->setImplicitSize(qCeil(boundingRect.width()), qCeil(boundingRect.height()));
2687 #ifndef QT_NO_CLIPBOARD
2691 Copies the currently selected text into the clipboard using the given
2694 \note If the echo mode is set to a mode other than Normal then copy
2695 will not work. This is to prevent using copy as a method of bypassing
2696 password features of the line control.
2698 void QQuickTextInputPrivate::copy(QClipboard::Mode mode) const
2700 QString t = selectedText();
2701 if (!t.isEmpty() && m_echoMode == QQuickTextInput::Normal) {
2702 QGuiApplication::clipboard()->setText(t, mode);
2709 Inserts the text stored in the application clipboard into the line
2714 void QQuickTextInputPrivate::paste(QClipboard::Mode clipboardMode)
2716 QString clip = QGuiApplication::clipboard()->text(clipboardMode);
2717 if (!clip.isEmpty() || hasSelectedText()) {
2718 separate(); //make it a separate undo/redo command
2724 #endif // !QT_NO_CLIPBOARD
2729 Exits preedit mode and commits parts marked as tentative commit
2731 void QQuickTextInputPrivate::commitPreedit()
2736 qApp->inputPanel()->reset();
2738 if (!m_tentativeCommit.isEmpty()) {
2739 internalInsert(m_tentativeCommit);
2740 m_tentativeCommit.clear();
2741 finishChange(-1, true/*not used, not documented*/, false);
2744 m_preeditCursor = 0;
2745 m_textLayout.setPreeditArea(-1, QString());
2746 m_textLayout.clearAdditionalFormats();
2753 Handles the behavior for the backspace key or function.
2754 Removes the current selection if there is a selection, otherwise
2755 removes the character prior to the cursor position.
2759 void QQuickTextInputPrivate::backspace()
2761 int priorState = m_undoState;
2762 if (hasSelectedText()) {
2763 removeSelectedText();
2764 } else if (m_cursor) {
2767 m_cursor = prevMaskBlank(m_cursor);
2768 QChar uc = m_text.at(m_cursor);
2769 if (m_cursor > 0 && uc.unicode() >= 0xdc00 && uc.unicode() < 0xe000) {
2770 // second half of a surrogate, check if we have the first half as well,
2771 // if yes delete both at once
2772 uc = m_text.at(m_cursor - 1);
2773 if (uc.unicode() >= 0xd800 && uc.unicode() < 0xdc00) {
2774 internalDelete(true);
2778 internalDelete(true);
2780 finishChange(priorState);
2786 Handles the behavior for the delete key or function.
2787 Removes the current selection if there is a selection, otherwise
2788 removes the character after the cursor position.
2792 void QQuickTextInputPrivate::del()
2794 int priorState = m_undoState;
2795 if (hasSelectedText()) {
2796 removeSelectedText();
2798 int n = m_textLayout.nextCursorPosition(m_cursor) - m_cursor;
2802 finishChange(priorState);
2808 Inserts the given \a newText at the current cursor position.
2809 If there is any selected text it is removed prior to insertion of
2812 void QQuickTextInputPrivate::insert(const QString &newText)
2814 int priorState = m_undoState;
2815 removeSelectedText();
2816 internalInsert(newText);
2817 finishChange(priorState);
2823 Clears the line control text.
2825 void QQuickTextInputPrivate::clear()
2827 int priorState = m_undoState;
2829 m_selend = m_text.length();
2830 removeSelectedText();
2832 finishChange(priorState, /*update*/false, /*edited*/false);
2838 Sets \a length characters from the given \a start position as selected.
2839 The given \a start position must be within the current text for
2840 the line control. If \a length characters cannot be selected, then
2841 the selection will extend to the end of the current text.
2843 void QQuickTextInputPrivate::setSelection(int start, int length)
2845 Q_Q(QQuickTextInput);
2848 if (start < 0 || start > (int)m_text.length()){
2849 qWarning("QQuickTextInputPrivate::setSelection: Invalid start position");
2854 if (start == m_selstart && start + length == m_selend && m_cursor == m_selend)
2857 m_selend = qMin(start + length, (int)m_text.length());
2858 m_cursor = m_selend;
2859 } else if (length < 0){
2860 if (start == m_selend && start + length == m_selstart && m_cursor == m_selstart)
2862 m_selstart = qMax(start + length, 0);
2864 m_cursor = m_selstart;
2865 } else if (m_selstart != m_selend) {
2871 emitCursorPositionChanged();
2874 emit q->selectionChanged();
2875 emitCursorPositionChanged();
2876 qApp->inputPanel()->update(Qt::ImCursorRectangle | Qt::ImAnchorPosition
2877 | Qt::ImCursorPosition | Qt::ImCurrentSelection);
2883 Initializes the line control with a starting text value of \a txt.
2885 void QQuickTextInputPrivate::init(const QString &txt)
2889 updateDisplayText();
2890 m_cursor = m_text.length();
2896 Sets the password echo editing to \a editing. If password echo editing
2897 is true, then the text of the password is displayed even if the echo
2898 mode is set to QLineEdit::PasswordEchoOnEdit. Password echoing editing
2899 does not affect other echo modes.
2901 void QQuickTextInputPrivate::updatePasswordEchoEditing(bool editing)
2903 cancelPasswordEchoTimer();
2904 m_passwordEchoEditing = editing;
2905 updateDisplayText();
2911 Fixes the current text so that it is valid given any set validators.
2913 Returns true if the text was changed. Otherwise returns false.
2915 bool QQuickTextInputPrivate::fixup() // this function assumes that validate currently returns != Acceptable
2917 #ifndef QT_NO_VALIDATOR
2919 QString textCopy = m_text;
2920 int cursorCopy = m_cursor;
2921 m_validator->fixup(textCopy);
2922 if (m_validator->validate(textCopy, cursorCopy) == QValidator::Acceptable) {
2923 if (textCopy != m_text || cursorCopy != m_cursor)
2924 internalSetText(textCopy, cursorCopy);
2935 Moves the cursor to the given position \a pos. If \a mark is true will
2936 adjust the currently selected text.
2938 void QQuickTextInputPrivate::moveCursor(int pos, bool mark)
2940 Q_Q(QQuickTextInput);
2943 if (pos != m_cursor) {
2946 pos = pos > m_cursor ? nextMaskBlank(pos) : prevMaskBlank(pos);
2950 if (m_selend > m_selstart && m_cursor == m_selstart)
2952 else if (m_selend > m_selstart && m_cursor == m_selend)
2953 anchor = m_selstart;
2956 m_selstart = qMin(anchor, pos);
2957 m_selend = qMax(anchor, pos);
2962 if (mark || m_selDirty) {
2964 emit q->selectionChanged();
2966 emitCursorPositionChanged();
2967 q->updateMicroFocus();
2973 Applies the given input method event \a event to the text of the line
2976 void QQuickTextInputPrivate::processInputMethodEvent(QInputMethodEvent *event)
2978 Q_Q(QQuickTextInput);
2980 int priorState = -1;
2981 bool isGettingInput = !event->commitString().isEmpty()
2982 || event->preeditString() != preeditAreaText()
2983 || event->replacementLength() > 0;
2984 bool cursorPositionChanged = false;
2985 bool selectionChange = false;
2986 m_preeditDirty = event->preeditString() != preeditAreaText();
2988 if (isGettingInput) {
2989 // If any text is being input, remove selected text.
2990 priorState = m_undoState;
2991 if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit && !m_passwordEchoEditing) {
2992 updatePasswordEchoEditing(true);
2994 m_selend = m_text.length();
2996 removeSelectedText();
2999 int c = m_cursor; // cursor position after insertion of commit string
3000 if (event->replacementStart() <= 0)
3001 c += event->commitString().length() - qMin(-event->replacementStart(), event->replacementLength());
3003 m_cursor += event->replacementStart();
3007 // insert commit string
3008 if (event->replacementLength()) {
3009 m_selstart = m_cursor;
3010 m_selend = m_selstart + event->replacementLength();
3011 m_selend = qMin(m_selend, m_text.length());
3012 removeSelectedText();
3014 if (!event->commitString().isEmpty()) {
3015 internalInsert(event->commitString());
3016 cursorPositionChanged = true;
3019 m_cursor = qBound(0, c, m_text.length());
3021 for (int i = 0; i < event->attributes().size(); ++i) {
3022 const QInputMethodEvent::Attribute &a = event->attributes().at(i);
3023 if (a.type == QInputMethodEvent::Selection) {
3024 m_cursor = qBound(0, a.start + a.length, m_text.length());
3026 m_selstart = qMax(0, qMin(a.start, m_text.length()));
3027 m_selend = m_cursor;
3028 if (m_selend < m_selstart) {
3029 qSwap(m_selstart, m_selend);
3031 selectionChange = true;
3033 m_selstart = m_selend = 0;
3035 cursorPositionChanged = true;
3039 m_textLayout.setPreeditArea(m_cursor, event->preeditString());
3041 const int oldPreeditCursor = m_preeditCursor;
3042 m_preeditCursor = event->preeditString().length();
3043 m_hideCursor = false;
3044 QList<QTextLayout::FormatRange> formats;
3045 for (int i = 0; i < event->attributes().size(); ++i) {
3046 const QInputMethodEvent::Attribute &a = event->attributes().at(i);
3047 if (a.type == QInputMethodEvent::Cursor) {
3048 m_preeditCursor = a.start;
3049 m_hideCursor = !a.length;
3050 } else if (a.type == QInputMethodEvent::TextFormat) {
3051 QTextCharFormat f = qvariant_cast<QTextFormat>(a.value).toCharFormat();
3053 QTextLayout::FormatRange o;
3054 o.start = a.start + m_cursor;
3055 o.length = a.length;
3061 m_textLayout.setAdditionalFormats(formats);
3063 updateDisplayText(/*force*/ true);
3064 if (cursorPositionChanged) {
3065 emitCursorPositionChanged();
3066 } else if (m_preeditCursor != oldPreeditCursor) {
3067 q->updateCursorRectangle();
3068 qApp->inputPanel()->update(Qt::ImCursorRectangle);
3071 bool tentativeCommitChanged = m_tentativeCommit != event->tentativeCommitString();
3073 if (tentativeCommitChanged) {
3075 m_tentativeCommit = event->tentativeCommitString();
3078 if (isGettingInput || tentativeCommitChanged)
3079 finishChange(priorState);
3081 if (selectionChange) {
3082 emit q->selectionChanged();
3083 qApp->inputPanel()->update(Qt::ImCursorRectangle | Qt::ImAnchorPosition
3084 | Qt::ImCursorPosition | Qt::ImCurrentSelection);
3091 Sets the selection to cover the word at the given cursor position.
3092 The word boundaries are defined by the behavior of QTextLayout::SkipWords
3095 void QQuickTextInputPrivate::selectWordAtPos(int cursor)
3097 int next = cursor + 1;
3100 int c = m_textLayout.previousCursorPosition(next, QTextLayout::SkipWords);
3101 moveCursor(c, false);
3102 // ## text layout should support end of words.
3103 int end = m_textLayout.nextCursorPosition(c, QTextLayout::SkipWords);
3104 while (end > cursor && m_text[end-1].isSpace())
3106 moveCursor(end, true);
3112 Completes a change to the line control text. If the change is not valid
3113 will undo the line control state back to the given \a validateFromState.
3115 If \a edited is true and the change is valid, will emit textEdited() in
3116 addition to textChanged(). Otherwise only emits textChanged() on a valid
3119 The \a update value is currently unused.
3121 bool QQuickTextInputPrivate::finishChange(int validateFromState, bool update, bool /*edited*/)
3123 Q_Q(QQuickTextInput);
3126 bool notifyInputPanel = m_textDirty || m_selDirty;
3127 bool alignmentChanged = false;
3131 bool wasValidInput = m_validInput;
3132 bool wasAcceptable = m_acceptableInput;
3133 m_validInput = true;
3134 m_acceptableInput = true;
3135 #ifndef QT_NO_VALIDATOR
3137 QString textCopy = m_text;
3138 int cursorCopy = m_cursor;
3139 QValidator::State state = m_validator->validate(textCopy, cursorCopy);
3140 m_validInput = state != QValidator::Invalid;
3141 m_acceptableInput = state == QValidator::Acceptable;
3143 if (m_text != textCopy) {
3144 internalSetText(textCopy, cursorCopy);
3147 m_cursor = cursorCopy;
3149 if (!m_tentativeCommit.isEmpty()) {
3150 textCopy.insert(m_cursor, m_tentativeCommit);
3151 bool validInput = m_validator->validate(textCopy, cursorCopy) != QValidator::Invalid;
3153 m_tentativeCommit.clear();
3156 m_tentativeCommit.clear();
3160 if (validateFromState >= 0 && wasValidInput && !m_validInput) {
3161 if (m_transactions.count())
3163 internalUndo(validateFromState);
3164 m_history.resize(m_undoState);
3165 if (m_modifiedState > m_undoState)
3166 m_modifiedState = -1;
3167 m_validInput = true;
3168 m_acceptableInput = wasAcceptable;
3169 m_textDirty = false;
3173 m_textDirty = false;
3174 m_preeditDirty = false;
3175 alignmentChanged = determineHorizontalAlignment();
3176 emit q->textChanged();
3179 updateDisplayText(alignmentChanged);
3181 if (m_acceptableInput != wasAcceptable)
3182 emit q->acceptableInputChanged();
3184 if (m_preeditDirty) {
3185 m_preeditDirty = false;
3186 if (determineHorizontalAlignment()) {
3187 alignmentChanged = true;
3194 emit q->selectionChanged();
3197 notifyInputPanel |= (m_cursor == m_lastCursorPos);
3198 if (notifyInputPanel)
3199 q->updateMicroFocus();
3200 emitUndoRedoChanged();
3202 if (!emitCursorPositionChanged() && alignmentChanged)
3203 q->updateCursorRectangle();
3211 An internal function for setting the text of the line control.
3213 void QQuickTextInputPrivate::internalSetText(const QString &txt, int pos, bool edited)
3215 Q_Q(QQuickTextInput);
3217 QString oldText = m_text;
3219 m_text = maskString(0, txt, true);
3220 m_text += clearString(m_text.length(), m_maxLength - m_text.length());
3222 m_text = txt.isEmpty() ? txt : txt.left(m_maxLength);
3225 m_modifiedState = m_undoState = 0;
3226 m_cursor = (pos < 0 || pos > m_text.length()) ? m_text.length() : pos;
3227 m_textDirty = (oldText != m_text);
3229 bool changed = finishChange(-1, true, edited);
3230 #ifdef QT_NO_ACCESSIBILITY
3234 QAccessible::updateAccessibility(q, 0, QAccessible::TextUpdated);
3242 Adds the given \a command to the undo history
3243 of the line control. Does not apply the command.
3245 void QQuickTextInputPrivate::addCommand(const Command &cmd)
3247 if (m_separator && m_undoState && m_history[m_undoState - 1].type != Separator) {
3248 m_history.resize(m_undoState + 2);
3249 m_history[m_undoState++] = Command(Separator, m_cursor, 0, m_selstart, m_selend);
3251 m_history.resize(m_undoState + 1);
3253 m_separator = false;
3254 m_history[m_undoState++] = cmd;
3260 Inserts the given string \a s into the line
3263 Also adds the appropriate commands into the undo history.
3264 This function does not call finishChange(), and may leave the text
3265 in an invalid state.
3267 void QQuickTextInputPrivate::internalInsert(const QString &s)
3269 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
3270 Q_Q(QQuickTextInput);
3271 if (m_echoMode == QQuickTextInput::Password)
3272 m_passwordEchoTimer.start(qt_passwordEchoDelay, q);
3274 if (hasSelectedText())
3275 addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
3277 QString ms = maskString(m_cursor, s);
3278 for (int i = 0; i < (int) ms.length(); ++i) {
3279 addCommand (Command(DeleteSelection, m_cursor + i, m_text.at(m_cursor + i), -1, -1));
3280 addCommand(Command(Insert, m_cursor + i, ms.at(i), -1, -1));
3282 m_text.replace(m_cursor, ms.length(), ms);
3283 m_cursor += ms.length();
3284 m_cursor = nextMaskBlank(m_cursor);
3287 int remaining = m_maxLength - m_text.length();
3288 if (remaining != 0) {
3289 m_text.insert(m_cursor, s.left(remaining));
3290 for (int i = 0; i < (int) s.left(remaining).length(); ++i)
3291 addCommand(Command(Insert, m_cursor++, s.at(i), -1, -1));
3300 deletes a single character from the current text. If \a wasBackspace,
3301 the character prior to the cursor is removed. Otherwise the character
3302 after the cursor is removed.
3304 Also adds the appropriate commands into the undo history.
3305 This function does not call finishChange(), and may leave the text
3306 in an invalid state.
3308 void QQuickTextInputPrivate::internalDelete(bool wasBackspace)
3310 if (m_cursor < (int) m_text.length()) {
3311 cancelPasswordEchoTimer();
3312 if (hasSelectedText())
3313 addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
3314 addCommand(Command((CommandType)((m_maskData ? 2 : 0) + (wasBackspace ? Remove : Delete)),
3315 m_cursor, m_text.at(m_cursor), -1, -1));
3317 m_text.replace(m_cursor, 1, clearString(m_cursor, 1));
3318 addCommand(Command(Insert, m_cursor, m_text.at(m_cursor), -1, -1));
3320 m_text.remove(m_cursor, 1);
3329 removes the currently selected text from the line control.
3331 Also adds the appropriate commands into the undo history.
3332 This function does not call finishChange(), and may leave the text
3333 in an invalid state.
3335 void QQuickTextInputPrivate::removeSelectedText()
3337 if (m_selstart < m_selend && m_selend <= (int) m_text.length()) {
3338 cancelPasswordEchoTimer();
3341 addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
3342 if (m_selstart <= m_cursor && m_cursor < m_selend) {
3343 // cursor is within the selection. Split up the commands
3344 // to be able to restore the correct cursor position
3345 for (i = m_cursor; i >= m_selstart; --i)
3346 addCommand (Command(DeleteSelection, i, m_text.at(i), -1, 1));
3347 for (i = m_selend - 1; i > m_cursor; --i)
3348 addCommand (Command(DeleteSelection, i - m_cursor + m_selstart - 1, m_text.at(i), -1, -1));
3350 for (i = m_selend-1; i >= m_selstart; --i)
3351 addCommand (Command(RemoveSelection, i, m_text.at(i), -1, -1));
3354 m_text.replace(m_selstart, m_selend - m_selstart, clearString(m_selstart, m_selend - m_selstart));
3355 for (int i = 0; i < m_selend - m_selstart; ++i)
3356 addCommand(Command(Insert, m_selstart + i, m_text.at(m_selstart + i), -1, -1));
3358 m_text.remove(m_selstart, m_selend - m_selstart);
3360 if (m_cursor > m_selstart)
3361 m_cursor -= qMin(m_cursor, m_selend) - m_selstart;
3370 Parses the input mask specified by \a maskFields to generate
3371 the mask data used to handle input masks.
3373 void QQuickTextInputPrivate::parseInputMask(const QString &maskFields)
3375 int delimiter = maskFields.indexOf(QLatin1Char(';'));
3376 if (maskFields.isEmpty() || delimiter == 0) {
3378 delete [] m_maskData;
3380 m_maxLength = 32767;
3381 internalSetText(QString());
3386 if (delimiter == -1) {
3387 m_blank = QLatin1Char(' ');
3388 m_inputMask = maskFields;
3390 m_inputMask = maskFields.left(delimiter);
3391 m_blank = (delimiter + 1 < maskFields.length()) ? maskFields[delimiter + 1] : QLatin1Char(' ');
3394 // calculate m_maxLength / m_maskData length
3397 for (int i=0; i<m_inputMask.length(); i++) {
3398 c = m_inputMask.at(i);
3399 if (i > 0 && m_inputMask.at(i-1) == QLatin1Char('\\')) {
3403 if (c != QLatin1Char('\\') && c != QLatin1Char('!') &&
3404 c != QLatin1Char('<') && c != QLatin1Char('>') &&
3405 c != QLatin1Char('{') && c != QLatin1Char('}') &&
3406 c != QLatin1Char('[') && c != QLatin1Char(']'))
3410 delete [] m_maskData;
3411 m_maskData = new MaskInputData[m_maxLength];
3413 MaskInputData::Casemode m = MaskInputData::NoCaseMode;
3416 bool escape = false;
3418 for (int i = 0; i < m_inputMask.length(); i++) {
3419 c = m_inputMask.at(i);
3422 m_maskData[index].maskChar = c;
3423 m_maskData[index].separator = s;
3424 m_maskData[index].caseMode = m;
3427 } else if (c == QLatin1Char('<')) {
3428 m = MaskInputData::Lower;
3429 } else if (c == QLatin1Char('>')) {
3430 m = MaskInputData::Upper;
3431 } else if (c == QLatin1Char('!')) {
3432 m = MaskInputData::NoCaseMode;
3433 } else if (c != QLatin1Char('{') && c != QLatin1Char('}') && c != QLatin1Char('[') && c != QLatin1Char(']')) {
3434 switch (c.unicode()) {
3460 m_maskData[index].maskChar = c;
3461 m_maskData[index].separator = s;
3462 m_maskData[index].caseMode = m;
3467 internalSetText(m_text);
3474 checks if the key is valid compared to the inputMask
3476 bool QQuickTextInputPrivate::isValidInput(QChar key, QChar mask) const
3478 switch (mask.unicode()) {
3484 if (key.isLetter() || key == m_blank)
3488 if (key.isLetterOrNumber())
3492 if (key.isLetterOrNumber() || key == m_blank)
3500 if (key.isPrint() || key == m_blank)
3508 if (key.isNumber() || key == m_blank)
3512 if (key.isNumber() && key.digitValue() > 0)
3516 if ((key.isNumber() && key.digitValue() > 0) || key == m_blank)
3520 if (key.isNumber() || key == QLatin1Char('+') || key == QLatin1Char('-') || key == m_blank)
3524 if (key == QLatin1Char('0') || key == QLatin1Char('1'))
3528 if (key == QLatin1Char('0') || key == QLatin1Char('1') || key == m_blank)
3532 if (key.isNumber() || (key >= QLatin1Char('a') && key <= QLatin1Char('f')) || (key >= QLatin1Char('A') && key <= QLatin1Char('F')))
3536 if (key.isNumber() || (key >= QLatin1Char('a') && key <= QLatin1Char('f')) || (key >= QLatin1Char('A') && key <= QLatin1Char('F')) || key == m_blank)
3548 Returns true if the given text \a str is valid for any
3549 validator or input mask set for the line control.
3551 Otherwise returns false
3553 QQuickTextInputPrivate::ValidatorState QQuickTextInputPrivate::hasAcceptableInput(const QString &str) const
3555 #ifndef QT_NO_VALIDATOR
3556 QString textCopy = str;
3557 int cursorCopy = m_cursor;
3559 QValidator::State state = m_validator->validate(textCopy, cursorCopy);
3560 if (state != QValidator::Acceptable)
3561 return ValidatorState(state);
3566 return AcceptableInput;
3568 if (str.length() != m_maxLength)
3569 return InvalidInput;
3571 for (int i=0; i < m_maxLength; ++i) {
3572 if (m_maskData[i].separator) {
3573 if (str.at(i) != m_maskData[i].maskChar)
3574 return InvalidInput;
3576 if (!isValidInput(str.at(i), m_maskData[i].maskChar))
3577 return InvalidInput;
3580 return AcceptableInput;
3586 Applies the inputMask on \a str starting from position \a pos in the mask. \a clear
3587 specifies from where characters should be gotten when a separator is met in \a str - true means
3588 that blanks will be used, false that previous input is used.
3589 Calling this when no inputMask is set is undefined.
3591 QString QQuickTextInputPrivate::maskString(uint pos, const QString &str, bool clear) const
3593 if (pos >= (uint)m_maxLength)
3594 return QString::fromLatin1("");
3597 fill = clear ? clearString(0, m_maxLength) : m_text;
3600 QString s = QString::fromLatin1("");
3602 while (i < m_maxLength) {
3603 if (strIndex < str.length()) {
3604 if (m_maskData[i].separator) {
3605 s += m_maskData[i].maskChar;
3606 if (str[(int)strIndex] == m_maskData[i].maskChar)
3610 if (isValidInput(str[(int)strIndex], m_maskData[i].maskChar)) {
3611 switch (m_maskData[i].caseMode) {
3612 case MaskInputData::Upper:
3613 s += str[(int)strIndex].toUpper();
3615 case MaskInputData::Lower:
3616 s += str[(int)strIndex].toLower();
3619 s += str[(int)strIndex];
3623 // search for separator first
3624 int n = findInMask(i, true, true, str[(int)strIndex]);
3626 if (str.length() != 1 || i == 0 || (i > 0 && (!m_maskData[i-1].separator || m_maskData[i-1].maskChar != str[(int)strIndex]))) {
3627 s += fill.mid(i, n-i+1);
3628 i = n + 1; // update i to find + 1
3631 // search for valid m_blank if not
3632 n = findInMask(i, true, false, str[(int)strIndex]);
3634 s += fill.mid(i, n-i);
3635 switch (m_maskData[n].caseMode) {
3636 case MaskInputData::Upper:
3637 s += str[(int)strIndex].toUpper();
3639 case MaskInputData::Lower:
3640 s += str[(int)strIndex].toLower();
3643 s += str[(int)strIndex];
3645 i = n + 1; // updates i to find + 1
3663 Returns a "cleared" string with only separators and blank chars.
3664 Calling this when no inputMask is set is undefined.
3666 QString QQuickTextInputPrivate::clearString(uint pos, uint len) const
3668 if (pos >= (uint)m_maxLength)
3672 int end = qMin((uint)m_maxLength, pos + len);
3673 for (int i = pos; i < end; ++i)
3674 if (m_maskData[i].separator)
3675 s += m_maskData[i].maskChar;
3685 Strips blank parts of the input in a QQuickTextInputPrivate when an inputMask is set,
3686 separators are still included. Typically "127.0__.0__.1__" becomes "127.0.0.1".
3688 QString QQuickTextInputPrivate::stripString(const QString &str) const
3694 int end = qMin(m_maxLength, (int)str.length());
3695 for (int i = 0; i < end; ++i) {
3696 if (m_maskData[i].separator)
3697 s += m_maskData[i].maskChar;
3698 else if (str[i] != m_blank)
3707 searches forward/backward in m_maskData for either a separator or a m_blank
3709 int QQuickTextInputPrivate::findInMask(int pos, bool forward, bool findSeparator, QChar searchChar) const
3711 if (pos >= m_maxLength || pos < 0)
3714 int end = forward ? m_maxLength : -1;
3715 int step = forward ? 1 : -1;
3719 if (findSeparator) {
3720 if (m_maskData[i].separator && m_maskData[i].maskChar == searchChar)
3723 if (!m_maskData[i].separator) {
3724 if (searchChar.isNull())
3726 else if (isValidInput(searchChar, m_maskData[i].maskChar))
3735 void QQuickTextInputPrivate::internalUndo(int until)
3737 if (!isUndoAvailable())
3739 cancelPasswordEchoTimer();
3741 while (m_undoState && m_undoState > until) {
3742 Command& cmd = m_history[--m_undoState];
3745 m_text.remove(cmd.pos, 1);
3749 m_selstart = cmd.selStart;
3750 m_selend = cmd.selEnd;
3754 case RemoveSelection:
3755 m_text.insert(cmd.pos, cmd.uc);
3756 m_cursor = cmd.pos + 1;
3759 case DeleteSelection:
3760 m_text.insert(cmd.pos, cmd.uc);
3766 if (until < 0 && m_undoState) {
3767 Command& next = m_history[m_undoState-1];
3768 if (next.type != cmd.type && next.type < RemoveSelection
3769 && (cmd.type < RemoveSelection || next.type == Separator))
3776 void QQuickTextInputPrivate::internalRedo()
3778 if (!isRedoAvailable())
3781 while (m_undoState < (int)m_history.size()) {
3782 Command& cmd = m_history[m_undoState++];
3785 m_text.insert(cmd.pos, cmd.uc);
3786 m_cursor = cmd.pos + 1;
3789 m_selstart = cmd.selStart;
3790 m_selend = cmd.selEnd;
3795 case RemoveSelection:
3796 case DeleteSelection:
3797 m_text.remove(cmd.pos, 1);
3798 m_selstart = cmd.selStart;
3799 m_selend = cmd.selEnd;
3803 m_selstart = cmd.selStart;
3804 m_selend = cmd.selEnd;
3808 if (m_undoState < (int)m_history.size()) {
3809 Command& next = m_history[m_undoState];
3810 if (next.type != cmd.type && cmd.type < RemoveSelection && next.type != Separator
3811 && (next.type < RemoveSelection || cmd.type == Separator))
3818 void QQuickTextInputPrivate::emitUndoRedoChanged()
3820 Q_Q(QQuickTextInput);
3821 const bool previousUndo = canUndo;
3822 const bool previousRedo = canRedo;
3824 canUndo = isUndoAvailable();
3825 canRedo = isRedoAvailable();
3827 if (previousUndo != canUndo)
3828 emit q->canUndoChanged();
3829 if (previousRedo != canRedo)
3830 emit q->canRedoChanged();
3836 If the current cursor position differs from the last emitted cursor
3837 position, emits cursorPositionChanged().
3839 bool QQuickTextInputPrivate::emitCursorPositionChanged()
3841 Q_Q(QQuickTextInput);
3842 if (m_cursor != m_lastCursorPos) {
3843 m_lastCursorPos = m_cursor;
3845 q->updateCursorRectangle();
3846 emit q->cursorPositionChanged();
3847 // XXX todo - not in 4.8?
3849 resetCursorBlinkTimer();
3852 if (!hasSelectedText()) {
3853 if (lastSelectionStart != m_cursor) {
3854 lastSelectionStart = m_cursor;
3855 emit q->selectionStartChanged();
3857 if (lastSelectionEnd != m_cursor) {
3858 lastSelectionEnd = m_cursor;
3859 emit q->selectionEndChanged();
3863 #ifndef QT_NO_ACCESSIBILITY
3864 QAccessible::updateAccessibility(q, 0, QAccessible::TextCaretMoved);
3873 void QQuickTextInputPrivate::setCursorBlinkPeriod(int msec)
3875 Q_Q(QQuickTextInput);
3876 if (msec == m_blinkPeriod)
3879 q->killTimer(m_blinkTimer);
3882 m_blinkTimer = q->startTimer(msec / 2);
3886 if (m_blinkStatus == 1) {
3887 updateType = UpdatePaintNode;
3891 m_blinkPeriod = msec;
3894 void QQuickTextInputPrivate::resetCursorBlinkTimer()
3896 Q_Q(QQuickTextInput);
3897 if (m_blinkPeriod == 0 || m_blinkTimer == 0)
3899 q->killTimer(m_blinkTimer);
3900 m_blinkTimer = q->startTimer(m_blinkPeriod / 2);
3904 void QQuickTextInput::timerEvent(QTimerEvent *event)
3906 Q_D(QQuickTextInput);
3907 if (event->timerId() == d->m_blinkTimer) {
3908 d->m_blinkStatus = !d->m_blinkStatus;
3909 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
3911 } else if (event->timerId() == d->m_deleteAllTimer) {
3912 killTimer(d->m_deleteAllTimer);
3913 d->m_deleteAllTimer = 0;
3915 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
3916 } else if (event->timerId() == d->m_passwordEchoTimer.timerId()) {
3917 d->m_passwordEchoTimer.stop();
3918 d->updateDisplayText();
3923 void QQuickTextInputPrivate::processKeyEvent(QKeyEvent* event)
3925 Q_Q(QQuickTextInput);
3926 bool inlineCompletionAccepted = false;
3928 if (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return) {
3929 if (hasAcceptableInput(m_text) || fixup()) {
3932 if (inlineCompletionAccepted)
3939 if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit
3940 && !m_passwordEchoEditing
3942 && !event->text().isEmpty()
3943 && !(event->modifiers() & Qt::ControlModifier)) {
3944 // Clear the edit and reset to normal echo mode while editing; the
3945 // echo mode switches back when the edit loses focus
3946 // ### resets current content. dubious code; you can
3947 // navigate with keys up, down, back, and select(?), but if you press
3948 // "left" or "right" it clears?
3949 updatePasswordEchoEditing(true);
3953 bool unknown = false;
3954 bool visual = cursorMoveStyle() == Qt::VisualMoveStyle;
3958 #ifndef QT_NO_SHORTCUT
3959 else if (event == QKeySequence::Undo) {
3963 else if (event == QKeySequence::Redo) {
3967 else if (event == QKeySequence::SelectAll) {
3970 #ifndef QT_NO_CLIPBOARD
3971 else if (event == QKeySequence::Copy) {
3974 else if (event == QKeySequence::Paste) {
3976 QClipboard::Mode mode = QClipboard::Clipboard;
3980 else if (event == QKeySequence::Cut) {
3986 else if (event == QKeySequence::DeleteEndOfLine) {
3988 setSelection(m_cursor, end());
3993 #endif //QT_NO_CLIPBOARD
3994 else if (event == QKeySequence::MoveToStartOfLine || event == QKeySequence::MoveToStartOfBlock) {
3997 else if (event == QKeySequence::MoveToEndOfLine || event == QKeySequence::MoveToEndOfBlock) {
4000 else if (event == QKeySequence::SelectStartOfLine || event == QKeySequence::SelectStartOfBlock) {
4003 else if (event == QKeySequence::SelectEndOfLine || event == QKeySequence::SelectEndOfBlock) {
4006 else if (event == QKeySequence::MoveToNextChar) {
4007 if (hasSelectedText()) {
4008 moveCursor(selectionEnd(), false);
4010 cursorForward(0, visual ? 1 : (layoutDirection() == Qt::LeftToRight ? 1 : -1));
4013 else if (event == QKeySequence::SelectNextChar) {
4014 cursorForward(1, visual ? 1 : (layoutDirection() == Qt::LeftToRight ? 1 : -1));
4016 else if (event == QKeySequence::MoveToPreviousChar) {
4017 if (hasSelectedText()) {
4018 moveCursor(selectionStart(), false);
4020 cursorForward(0, visual ? -1 : (layoutDirection() == Qt::LeftToRight ? -1 : 1));
4023 else if (event == QKeySequence::SelectPreviousChar) {
4024 cursorForward(1, visual ? -1 : (layoutDirection() == Qt::LeftToRight ? -1 : 1));
4026 else if (event == QKeySequence::MoveToNextWord) {
4027 if (m_echoMode == QQuickTextInput::Normal)
4028 layoutDirection() == Qt::LeftToRight ? cursorWordForward(0) : cursorWordBackward(0);
4030 layoutDirection() == Qt::LeftToRight ? end(0) : home(0);
4032 else if (event == QKeySequence::MoveToPreviousWord) {
4033 if (m_echoMode == QQuickTextInput::Normal)
4034 layoutDirection() == Qt::LeftToRight ? cursorWordBackward(0) : cursorWordForward(0);
4035 else if (!m_readOnly) {
4036 layoutDirection() == Qt::LeftToRight ? home(0) : end(0);
4039 else if (event == QKeySequence::SelectNextWord) {
4040 if (m_echoMode == QQuickTextInput::Normal)
4041 layoutDirection() == Qt::LeftToRight ? cursorWordForward(1) : cursorWordBackward(1);
4043 layoutDirection() == Qt::LeftToRight ? end(1) : home(1);
4045 else if (event == QKeySequence::SelectPreviousWord) {
4046 if (m_echoMode == QQuickTextInput::Normal)
4047 layoutDirection() == Qt::LeftToRight ? cursorWordBackward(1) : cursorWordForward(1);
4049 layoutDirection() == Qt::LeftToRight ? home(1) : end(1);
4051 else if (event == QKeySequence::Delete) {
4055 else if (event == QKeySequence::DeleteEndOfWord) {
4057 cursorWordForward(true);
4061 else if (event == QKeySequence::DeleteStartOfWord) {
4063 cursorWordBackward(true);
4067 #endif // QT_NO_SHORTCUT
4069 bool handled = false;
4070 if (event->modifiers() & Qt::ControlModifier) {
4071 switch (event->key()) {
4072 case Qt::Key_Backspace:
4074 cursorWordBackward(true);
4082 } else { // ### check for *no* modifier
4083 switch (event->key()) {
4084 case Qt::Key_Backspace:
4096 if (event->key() == Qt::Key_Direction_L || event->key() == Qt::Key_Direction_R) {
4097 setLayoutDirection((event->key() == Qt::Key_Direction_L) ? Qt::LeftToRight : Qt::RightToLeft);
4101 if (unknown && !m_readOnly) {
4102 QString t = event->text();
4103 if (!t.isEmpty() && t.at(0).isPrint()) {