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 updateInputMethod(Qt::ImCursorRectangle | Qt::ImFont);
311 emit fontChanged(d->sourceFont);
315 \qmlproperty color QtQuick2::TextInput::color
319 QColor QQuickTextInput::color() const
321 Q_D(const QQuickTextInput);
325 void QQuickTextInput::setColor(const QColor &c)
327 Q_D(QQuickTextInput);
330 d->textLayoutDirty = true;
331 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
333 emit colorChanged(c);
339 \qmlproperty color QtQuick2::TextInput::selectionColor
341 The text highlight color, used behind selections.
343 QColor QQuickTextInput::selectionColor() const
345 Q_D(const QQuickTextInput);
346 return d->selectionColor;
349 void QQuickTextInput::setSelectionColor(const QColor &color)
351 Q_D(QQuickTextInput);
352 if (d->selectionColor == color)
355 d->selectionColor = color;
356 d->m_palette.setColor(QPalette::Highlight, d->selectionColor);
357 if (d->hasSelectedText()) {
358 d->textLayoutDirty = true;
359 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
362 emit selectionColorChanged(color);
365 \qmlproperty color QtQuick2::TextInput::selectedTextColor
367 The highlighted text color, used in selections.
369 QColor QQuickTextInput::selectedTextColor() const
371 Q_D(const QQuickTextInput);
372 return d->selectedTextColor;
375 void QQuickTextInput::setSelectedTextColor(const QColor &color)
377 Q_D(QQuickTextInput);
378 if (d->selectedTextColor == color)
381 d->selectedTextColor = color;
382 d->m_palette.setColor(QPalette::HighlightedText, d->selectedTextColor);
383 if (d->hasSelectedText()) {
384 d->textLayoutDirty = true;
385 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
388 emit selectedTextColorChanged(color);
392 \qmlproperty enumeration QtQuick2::TextInput::horizontalAlignment
393 \qmlproperty enumeration QtQuick2::TextInput::effectiveHorizontalAlignment
394 \qmlproperty enumeration QtQuick2::TextInput::verticalAlignment
396 Sets the horizontal alignment of the text within the TextInput item's
397 width and height. By default, the text alignment follows the natural alignment
398 of the text, for example text that is read from left to right will be aligned to
401 TextInput does not have vertical alignment, as the natural height is
402 exactly the height of the single line of text. If you set the height
403 manually to something larger, TextInput will always be top aligned
404 vertically. You can use anchors to align it however you want within
407 The valid values for \c horizontalAlignment are \c TextInput.AlignLeft, \c TextInput.AlignRight and
408 \c TextInput.AlignHCenter.
410 Valid values for \c verticalAlignment are \c TextInput.AlignTop (default),
411 \c TextInput.AlignBottom \c TextInput.AlignVCenter.
413 When using the attached property LayoutMirroring::enabled to mirror application
414 layouts, the horizontal alignment of text will also be mirrored. However, the property
415 \c horizontalAlignment will remain unchanged. To query the effective horizontal alignment
416 of TextInput, use the read-only property \c effectiveHorizontalAlignment.
418 QQuickTextInput::HAlignment QQuickTextInput::hAlign() const
420 Q_D(const QQuickTextInput);
424 void QQuickTextInput::setHAlign(HAlignment align)
426 Q_D(QQuickTextInput);
427 bool forceAlign = d->hAlignImplicit && d->effectiveLayoutMirror;
428 d->hAlignImplicit = false;
429 if (d->setHAlign(align, forceAlign) && isComponentComplete()) {
431 updateCursorRectangle();
435 void QQuickTextInput::resetHAlign()
437 Q_D(QQuickTextInput);
438 d->hAlignImplicit = true;
439 if (d->determineHorizontalAlignment() && isComponentComplete()) {
441 updateCursorRectangle();
445 QQuickTextInput::HAlignment QQuickTextInput::effectiveHAlign() const
447 Q_D(const QQuickTextInput);
448 QQuickTextInput::HAlignment effectiveAlignment = d->hAlign;
449 if (!d->hAlignImplicit && d->effectiveLayoutMirror) {
451 case QQuickTextInput::AlignLeft:
452 effectiveAlignment = QQuickTextInput::AlignRight;
454 case QQuickTextInput::AlignRight:
455 effectiveAlignment = QQuickTextInput::AlignLeft;
461 return effectiveAlignment;
464 bool QQuickTextInputPrivate::setHAlign(QQuickTextInput::HAlignment alignment, bool forceAlign)
466 Q_Q(QQuickTextInput);
467 if ((hAlign != alignment || forceAlign) && alignment <= QQuickTextInput::AlignHCenter) { // justify not supported
468 QQuickTextInput::HAlignment oldEffectiveHAlign = q->effectiveHAlign();
470 emit q->horizontalAlignmentChanged(alignment);
471 if (oldEffectiveHAlign != q->effectiveHAlign())
472 emit q->effectiveHorizontalAlignmentChanged();
478 bool QQuickTextInputPrivate::determineHorizontalAlignment()
480 if (hAlignImplicit) {
481 // if no explicit alignment has been set, follow the natural layout direction of the text
482 QString text = q_func()->text();
484 text = m_textLayout.preeditAreaText();
485 bool isRightToLeft = text.isEmpty() ? qApp->inputPanel()->inputDirection() == Qt::RightToLeft
486 : text.isRightToLeft();
487 return setHAlign(isRightToLeft ? QQuickTextInput::AlignRight : QQuickTextInput::AlignLeft);
492 QQuickTextInput::VAlignment QQuickTextInput::vAlign() const
494 Q_D(const QQuickTextInput);
498 void QQuickTextInput::setVAlign(QQuickTextInput::VAlignment alignment)
500 Q_D(QQuickTextInput);
501 if (alignment == d->vAlign)
503 d->vAlign = alignment;
504 emit verticalAlignmentChanged(d->vAlign);
505 if (isComponentComplete()) {
506 updateCursorRectangle();
511 \qmlproperty enumeration QtQuick2::TextInput::wrapMode
513 Set this property to wrap the text to the TextInput item's width.
514 The text will only wrap if an explicit width has been set.
517 \o TextInput.NoWrap - no wrapping will be performed. If the text contains insufficient newlines, then implicitWidth will exceed a set width.
518 \o TextInput.WordWrap - wrapping is done on word boundaries only. If a word is too long, implicitWidth will exceed a set width.
519 \o TextInput.WrapAnywhere - wrapping is done at any point on a line, even if it occurs in the middle of a word.
520 \o TextInput.Wrap - if possible, wrapping occurs at a word boundary; otherwise it will occur at the appropriate point on the line, even in the middle of a word.
523 The default is TextInput.NoWrap. If you set a width, consider using TextInput.Wrap.
525 QQuickTextInput::WrapMode QQuickTextInput::wrapMode() const
527 Q_D(const QQuickTextInput);
531 void QQuickTextInput::setWrapMode(WrapMode mode)
533 Q_D(QQuickTextInput);
534 if (mode == d->wrapMode)
538 updateCursorRectangle();
539 emit wrapModeChanged();
542 void QQuickTextInputPrivate::mirrorChange()
544 Q_Q(QQuickTextInput);
545 if (q->isComponentComplete()) {
546 if (!hAlignImplicit && (hAlign == QQuickTextInput::AlignRight || hAlign == QQuickTextInput::AlignLeft)) {
547 q->updateCursorRectangle();
548 emit q->effectiveHorizontalAlignmentChanged();
554 \qmlproperty bool QtQuick2::TextInput::readOnly
556 Sets whether user input can modify the contents of the TextInput.
558 If readOnly is set to true, then user input will not affect the text
559 property. Any bindings or attempts to set the text property will still
562 bool QQuickTextInput::isReadOnly() const
564 Q_D(const QQuickTextInput);
565 return d->m_readOnly;
568 void QQuickTextInput::setReadOnly(bool ro)
570 Q_D(QQuickTextInput);
571 if (d->m_readOnly == ro)
574 setFlag(QQuickItem::ItemAcceptsInputMethod, !ro);
577 d->setCursorPosition(d->end());
578 updateInputMethod(Qt::ImEnabled);
580 d->emitUndoRedoChanged();
581 emit readOnlyChanged(ro);
585 \qmlproperty int QtQuick2::TextInput::maximumLength
586 The maximum permitted length of the text in the TextInput.
588 If the text is too long, it is truncated at the limit.
590 By default, this property contains a value of 32767.
592 int QQuickTextInput::maxLength() const
594 Q_D(const QQuickTextInput);
595 return d->m_maxLength;
598 void QQuickTextInput::setMaxLength(int ml)
600 Q_D(QQuickTextInput);
601 if (d->m_maxLength == ml || d->m_maskData)
605 d->internalSetText(d->m_text, -1, false);
607 emit maximumLengthChanged(ml);
611 \qmlproperty bool QtQuick2::TextInput::cursorVisible
612 Set to true when the TextInput shows a cursor.
614 This property is set and unset when the TextInput gets active focus, so that other
615 properties can be bound to whether the cursor is currently showing. As it
616 gets set and unset automatically, when you set the value yourself you must
617 keep in mind that your value may be overwritten.
619 It can be set directly in script, for example if a KeyProxy might
620 forward keys to it and you desire it to look active when this happens
621 (but without actually giving it active focus).
623 It should not be set directly on the element, like in the below QML,
624 as the specified value will be overridden an lost on focus changes.
633 In the above snippet the cursor will still become visible when the
634 TextInput gains active focus.
636 bool QQuickTextInput::isCursorVisible() const
638 Q_D(const QQuickTextInput);
639 return d->cursorVisible;
642 void QQuickTextInput::setCursorVisible(bool on)
644 Q_D(QQuickTextInput);
645 if (d->cursorVisible == on)
647 d->cursorVisible = on;
648 d->setCursorBlinkPeriod(on ? qApp->styleHints()->cursorFlashTime() : 0);
649 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
651 emit cursorVisibleChanged(d->cursorVisible);
655 \qmlproperty int QtQuick2::TextInput::cursorPosition
656 The position of the cursor in the TextInput.
658 int QQuickTextInput::cursorPosition() const
660 Q_D(const QQuickTextInput);
664 void QQuickTextInput::setCursorPosition(int cp)
666 Q_D(QQuickTextInput);
667 if (cp < 0 || cp > text().length())
673 \qmlproperty rectangle QtQuick2::TextInput::cursorRectangle
675 The rectangle where the standard text cursor is rendered within the text input. Read only.
677 The position and height of a custom cursorDelegate are updated to follow the cursorRectangle
678 automatically when it changes. The width of the delegate is unaffected by changes in the
682 QRect QQuickTextInput::cursorRectangle() const
684 Q_D(const QQuickTextInput);
687 if (d->m_preeditCursor != -1)
688 c += d->m_preeditCursor;
689 if (d->m_echoMode == NoEcho)
691 QTextLine l = d->m_textLayout.lineForTextPosition(c);
695 qRound(l.cursorToX(c) - d->hscroll),
696 qRound(l.y() - d->vscroll),
702 \qmlproperty int QtQuick2::TextInput::selectionStart
704 The cursor position before the first character in the current selection.
706 This property is read-only. To change the selection, use select(start,end),
707 selectAll(), or selectWord().
709 \sa selectionEnd, cursorPosition, selectedText
711 int QQuickTextInput::selectionStart() const
713 Q_D(const QQuickTextInput);
714 return d->lastSelectionStart;
717 \qmlproperty int QtQuick2::TextInput::selectionEnd
719 The cursor position after the last character in the current selection.
721 This property is read-only. To change the selection, use select(start,end),
722 selectAll(), or selectWord().
724 \sa selectionStart, cursorPosition, selectedText
726 int QQuickTextInput::selectionEnd() const
728 Q_D(const QQuickTextInput);
729 return d->lastSelectionEnd;
732 \qmlmethod void QtQuick2::TextInput::select(int start, int end)
734 Causes the text from \a start to \a end to be selected.
736 If either start or end is out of range, the selection is not changed.
738 After calling this, selectionStart will become the lesser
739 and selectionEnd will become the greater (regardless of the order passed
742 \sa selectionStart, selectionEnd
744 void QQuickTextInput::select(int start, int end)
746 Q_D(QQuickTextInput);
747 if (start < 0 || end < 0 || start > d->m_text.length() || end > d->m_text.length())
749 d->setSelection(start, end-start);
753 \qmlproperty string QtQuick2::TextInput::selectedText
755 This read-only property provides the text currently selected in the
758 It is equivalent to the following snippet, but is faster and easier
762 myTextInput.text.toString().substring(myTextInput.selectionStart,
763 myTextInput.selectionEnd);
766 QString QQuickTextInput::selectedText() const
768 Q_D(const QQuickTextInput);
769 return d->selectedText();
773 \qmlproperty bool QtQuick2::TextInput::activeFocusOnPress
775 Whether the TextInput should gain active focus on a mouse press. By default this is
778 bool QQuickTextInput::focusOnPress() const
780 Q_D(const QQuickTextInput);
781 return d->focusOnPress;
784 void QQuickTextInput::setFocusOnPress(bool b)
786 Q_D(QQuickTextInput);
787 if (d->focusOnPress == b)
792 emit activeFocusOnPressChanged(d->focusOnPress);
795 \qmlproperty bool QtQuick2::TextInput::autoScroll
797 Whether the TextInput should scroll when the text is longer than the width. By default this is
800 bool QQuickTextInput::autoScroll() const
802 Q_D(const QQuickTextInput);
803 return d->autoScroll;
806 void QQuickTextInput::setAutoScroll(bool b)
808 Q_D(QQuickTextInput);
809 if (d->autoScroll == b)
813 //We need to repaint so that the scrolling is taking into account.
814 updateCursorRectangle();
815 emit autoScrollChanged(d->autoScroll);
818 #ifndef QT_NO_VALIDATOR
821 \qmlclass IntValidator QIntValidator
822 \inqmlmodule QtQuick 2
823 \ingroup qml-basic-visual-elements
825 This element provides a validator for integer values.
827 If no \l locale is set IntValidator uses the \l {QLocale::setDefault()}{default locale} to
828 interpret the number and will accept locale specific digits, group separators, and positive
829 and negative signs. In addition, IntValidator is always guaranteed to accept a number
830 formatted according to the "C" locale.
834 QQuickIntValidator::QQuickIntValidator(QObject *parent)
835 : QIntValidator(parent)
840 \qmlproperty string QtQuick2::IntValidator::locale
842 This property holds the name of the locale used to interpret the number.
847 QString QQuickIntValidator::localeName() const
849 return locale().name();
852 void QQuickIntValidator::setLocaleName(const QString &name)
854 if (locale().name() != name) {
855 setLocale(QLocale(name));
856 emit localeNameChanged();
860 void QQuickIntValidator::resetLocaleName()
862 QLocale defaultLocale;
863 if (locale() != defaultLocale) {
864 setLocale(defaultLocale);
865 emit localeNameChanged();
870 \qmlproperty int QtQuick2::IntValidator::top
872 This property holds the validator's highest acceptable value.
873 By default, this property's value is derived from the highest signed integer available (typically 2147483647).
876 \qmlproperty int QtQuick2::IntValidator::bottom
878 This property holds the validator's lowest acceptable value.
879 By default, this property's value is derived from the lowest signed integer available (typically -2147483647).
883 \qmlclass DoubleValidator QDoubleValidator
884 \inqmlmodule QtQuick 2
885 \ingroup qml-basic-visual-elements
887 This element provides a validator for non-integer numbers.
889 Input is accepted if it contains a double that is within the valid range
890 and is in the correct format.
892 Input is accepected but invalid if it contains a double that is outside
893 the range or is in the wrong format; e.g. with too many digits after the
894 decimal point or is empty.
896 Input is rejected if it is not a double.
898 Note: If the valid range consists of just positive doubles (e.g. 0.0 to
899 100.0) and input is a negative double then it is rejected. If \l notation
900 is set to DoubleValidator.StandardNotation, and the input contains more
901 digits before the decimal point than a double in the valid range may have,
902 it is also rejected. If \l notation is DoubleValidator.ScientificNotation,
903 and the input is not in the valid range, it is accecpted but invalid. The
904 value may yet become valid by changing the exponent.
907 QQuickDoubleValidator::QQuickDoubleValidator(QObject *parent)
908 : QDoubleValidator(parent)
913 \qmlproperty string QtQuick2::DoubleValidator::locale
915 This property holds the name of the locale used to interpret the number.
920 QString QQuickDoubleValidator::localeName() const
922 return locale().name();
925 void QQuickDoubleValidator::setLocaleName(const QString &name)
927 if (locale().name() != name) {
928 setLocale(QLocale(name));
929 emit localeNameChanged();
933 void QQuickDoubleValidator::resetLocaleName()
935 QLocale defaultLocale;
936 if (locale() != defaultLocale) {
937 setLocale(defaultLocale);
938 emit localeNameChanged();
943 \qmlproperty real QtQuick2::DoubleValidator::top
945 This property holds the validator's maximum acceptable value.
946 By default, this property contains a value of infinity.
949 \qmlproperty real QtQuick2::DoubleValidator::bottom
951 This property holds the validator's minimum acceptable value.
952 By default, this property contains a value of -infinity.
955 \qmlproperty int QtQuick2::DoubleValidator::decimals
957 This property holds the validator's maximum number of digits after the decimal point.
958 By default, this property contains a value of 1000.
961 \qmlproperty enumeration QtQuick2::DoubleValidator::notation
962 This property holds the notation of how a string can describe a number.
964 The possible values for this property are:
967 \o DoubleValidator.StandardNotation
968 \o DoubleValidator.ScientificNotation (default)
971 If this property is set to DoubleValidator.ScientificNotation, the written number may have an exponent part (e.g. 1.5E-2).
975 \qmlclass RegExpValidator QRegExpValidator
976 \inqmlmodule QtQuick 2
977 \ingroup qml-basic-visual-elements
979 This element provides a validator, which counts as valid any string which
980 matches a specified regular expression.
983 \qmlproperty regExp QtQuick2::RegExpValidator::regExp
985 This property holds the regular expression used for validation.
987 Note that this property should be a regular expression in JS syntax, e.g /a/ for the regular expression
990 By default, this property contains a regular expression with the pattern .* that matches any string.
994 \qmlproperty Validator QtQuick2::TextInput::validator
996 Allows you to set a validator on the TextInput. When a validator is set
997 the TextInput will only accept input which leaves the text property in
998 an acceptable or intermediate state. The accepted signal will only be sent
999 if the text is in an acceptable state when enter is pressed.
1001 Currently supported validators are IntValidator, DoubleValidator and
1002 RegExpValidator. An example of using validators is shown below, which allows
1003 input of integers between 11 and 31 into the text input:
1008 validator: IntValidator{bottom: 11; top: 31;}
1013 \sa acceptableInput, inputMask
1016 QValidator* QQuickTextInput::validator() const
1018 Q_D(const QQuickTextInput);
1019 return d->m_validator;
1022 void QQuickTextInput::setValidator(QValidator* v)
1024 Q_D(QQuickTextInput);
1025 if (d->m_validator == v)
1030 if (isComponentComplete())
1033 emit validatorChanged();
1036 #endif // QT_NO_VALIDATOR
1038 void QQuickTextInputPrivate::checkIsValid()
1040 Q_Q(QQuickTextInput);
1042 ValidatorState state = hasAcceptableInput(m_text);
1043 m_validInput = state != InvalidInput;
1044 if (state != AcceptableInput) {
1045 if (m_acceptableInput) {
1046 m_acceptableInput = false;
1047 emit q->acceptableInputChanged();
1049 } else if (!m_acceptableInput) {
1050 m_acceptableInput = true;
1051 emit q->acceptableInputChanged();
1056 \qmlproperty string QtQuick2::TextInput::inputMask
1058 Allows you to set an input mask on the TextInput, restricting the allowable
1059 text inputs. See QLineEdit::inputMask for further details, as the exact
1060 same mask strings are used by TextInput.
1062 \sa acceptableInput, validator
1064 QString QQuickTextInput::inputMask() const
1066 Q_D(const QQuickTextInput);
1067 return d->inputMask();
1070 void QQuickTextInput::setInputMask(const QString &im)
1072 Q_D(QQuickTextInput);
1073 if (d->inputMask() == im)
1076 d->setInputMask(im);
1077 emit inputMaskChanged(d->inputMask());
1081 \qmlproperty bool QtQuick2::TextInput::acceptableInput
1083 This property is always true unless a validator or input mask has been set.
1084 If a validator or input mask has been set, this property will only be true
1085 if the current text is acceptable to the validator or input mask as a final
1086 string (not as an intermediate string).
1088 bool QQuickTextInput::hasAcceptableInput() const
1090 Q_D(const QQuickTextInput);
1091 return d->hasAcceptableInput(d->m_text) == QQuickTextInputPrivate::AcceptableInput;
1095 \qmlsignal QtQuick2::TextInput::onAccepted()
1097 This handler is called when the Return or Enter key is pressed.
1098 Note that if there is a \l validator or \l inputMask set on the text
1099 input, the handler will only be emitted if the input is in an acceptable
1103 void QQuickTextInputPrivate::updateInputMethodHints()
1105 Q_Q(QQuickTextInput);
1106 Qt::InputMethodHints hints = inputMethodHints;
1107 if (m_echoMode == QQuickTextInput::Password || m_echoMode == QQuickTextInput::NoEcho)
1108 hints |= Qt::ImhHiddenText;
1109 else if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit)
1110 hints &= ~Qt::ImhHiddenText;
1111 if (m_echoMode != QQuickTextInput::Normal)
1112 hints |= (Qt::ImhNoAutoUppercase | Qt::ImhNoPredictiveText | Qt::ImhSensitiveData);
1113 q->setInputMethodHints(hints);
1116 \qmlproperty enumeration QtQuick2::TextInput::echoMode
1118 Specifies how the text should be displayed in the TextInput.
1120 \o TextInput.Normal - Displays the text as it is. (Default)
1121 \o TextInput.Password - Displays asterisks instead of characters.
1122 \o TextInput.NoEcho - Displays nothing.
1123 \o TextInput.PasswordEchoOnEdit - Displays characters as they are entered
1124 while editing, otherwise displays asterisks.
1127 QQuickTextInput::EchoMode QQuickTextInput::echoMode() const
1129 Q_D(const QQuickTextInput);
1130 return QQuickTextInput::EchoMode(d->m_echoMode);
1133 void QQuickTextInput::setEchoMode(QQuickTextInput::EchoMode echo)
1135 Q_D(QQuickTextInput);
1136 if (echoMode() == echo)
1138 d->cancelPasswordEchoTimer();
1139 d->m_echoMode = echo;
1140 d->m_passwordEchoEditing = false;
1141 d->updateInputMethodHints();
1142 d->updateDisplayText();
1143 updateCursorRectangle();
1145 emit echoModeChanged(echoMode());
1149 \qmlproperty enumeration QtQuick2::TextInput::inputMethodHints
1151 Provides hints to the input method about the expected content of the text input and how it
1154 The value is a bit-wise combination of flags, or Qt.ImhNone if no hints are set.
1156 Flags that alter behaviour are:
1159 \o Qt.ImhHiddenText - Characters should be hidden, as is typically used when entering passwords.
1160 This is automatically set when setting echoMode to \c TextInput.Password.
1161 \o Qt.ImhSensitiveData - Typed text should not be stored by the active input method
1162 in any persistent storage like predictive user dictionary.
1163 \o Qt.ImhNoAutoUppercase - The input method should not try to automatically switch to upper case
1164 when a sentence ends.
1165 \o Qt.ImhPreferNumbers - Numbers are preferred (but not required).
1166 \o Qt.ImhPreferUppercase - Upper case letters are preferred (but not required).
1167 \o Qt.ImhPreferLowercase - Lower case letters are preferred (but not required).
1168 \o Qt.ImhNoPredictiveText - Do not use predictive text (i.e. dictionary lookup) while typing.
1170 \o Qt.ImhDate - The text editor functions as a date field.
1171 \o Qt.ImhTime - The text editor functions as a time field.
1174 Flags that restrict input (exclusive flags) are:
1177 \o Qt.ImhDigitsOnly - Only digits are allowed.
1178 \o Qt.ImhFormattedNumbersOnly - Only number input is allowed. This includes decimal point and minus sign.
1179 \o Qt.ImhUppercaseOnly - Only upper case letter input is allowed.
1180 \o Qt.ImhLowercaseOnly - Only lower case letter input is allowed.
1181 \o Qt.ImhDialableCharactersOnly - Only characters suitable for phone dialing are allowed.
1182 \o Qt.ImhEmailCharactersOnly - Only characters suitable for email addresses are allowed.
1183 \o Qt.ImhUrlCharactersOnly - Only characters suitable for URLs are allowed.
1189 \o Qt.ImhExclusiveInputMask - This mask yields nonzero if any of the exclusive flags are used.
1193 Qt::InputMethodHints QQuickTextInput::imHints() const
1195 Q_D(const QQuickTextInput);
1196 return d->inputMethodHints;
1199 void QQuickTextInput::setIMHints(Qt::InputMethodHints hints)
1201 Q_D(QQuickTextInput);
1202 if (d->inputMethodHints == hints)
1204 d->inputMethodHints = hints;
1205 d->updateInputMethodHints();
1209 \qmlproperty Component QtQuick2::TextInput::cursorDelegate
1210 The delegate for the cursor in the TextInput.
1212 If you set a cursorDelegate for a TextInput, this delegate will be used for
1213 drawing the cursor instead of the standard cursor. An instance of the
1214 delegate will be created and managed by the TextInput when a cursor is
1215 needed, and the x property of delegate instance will be set so as
1216 to be one pixel before the top left of the current character.
1218 Note that the root item of the delegate component must be a QDeclarativeItem or
1219 QDeclarativeItem derived item.
1221 QDeclarativeComponent* QQuickTextInput::cursorDelegate() const
1223 Q_D(const QQuickTextInput);
1224 return d->cursorComponent;
1227 void QQuickTextInput::setCursorDelegate(QDeclarativeComponent* c)
1229 Q_D(QQuickTextInput);
1230 if (d->cursorComponent == c)
1233 d->cursorComponent = c;
1235 //note that the components are owned by something else
1236 delete d->cursorItem;
1238 d->startCreatingCursor();
1241 emit cursorDelegateChanged();
1244 void QQuickTextInputPrivate::startCreatingCursor()
1246 Q_Q(QQuickTextInput);
1247 if (cursorComponent->isReady()) {
1249 } else if (cursorComponent->isLoading()) {
1250 q->connect(cursorComponent, SIGNAL(statusChanged(int)),
1251 q, SLOT(createCursor()));
1253 qmlInfo(q, cursorComponent->errors()) << QQuickTextInput::tr("Could not load cursor delegate");
1257 void QQuickTextInput::createCursor()
1259 Q_D(QQuickTextInput);
1260 if (!isComponentComplete())
1263 if (d->cursorComponent->isError()) {
1264 qmlInfo(this, d->cursorComponent->errors()) << tr("Could not load cursor delegate");
1268 if (!d->cursorComponent->isReady())
1272 delete d->cursorItem;
1273 QDeclarativeContext *creationContext = d->cursorComponent->creationContext();
1274 QObject *object = d->cursorComponent->create(creationContext ? creationContext : qmlContext(this));
1275 d->cursorItem = qobject_cast<QQuickItem*>(object);
1276 if (!d->cursorItem) {
1278 qmlInfo(this, d->cursorComponent->errors()) << tr("Could not instantiate cursor delegate");
1282 QRectF r = cursorRectangle();
1284 QDeclarative_setParent_noEvent(d->cursorItem, this);
1285 d->cursorItem->setParentItem(this);
1286 d->cursorItem->setPos(r.topLeft());
1287 d->cursorItem->setHeight(r.height());
1291 \qmlmethod rect QtQuick2::TextInput::positionToRectangle(int pos)
1293 This function takes a character position and returns the rectangle that the
1294 cursor would occupy, if it was placed at that character position.
1296 This is similar to setting the cursorPosition, and then querying the cursor
1297 rectangle, but the cursorPosition is not changed.
1299 QRectF QQuickTextInput::positionToRectangle(int pos) const
1301 Q_D(const QQuickTextInput);
1302 if (pos > d->m_cursor)
1303 pos += d->preeditAreaText().length();
1304 QTextLine l = d->m_textLayout.lineAt(0);
1306 ? QRectF(l.cursorToX(pos) - d->hscroll, 0.0, d->m_cursorWidth, l.height())
1311 \qmlmethod int QtQuick2::TextInput::positionAt(real x, real y, CursorPosition position = CursorBetweenCharacters)
1313 This function returns the character position at
1314 x and y pixels from the top left of the textInput. Position 0 is before the
1315 first character, position 1 is after the first character but before the second,
1316 and so on until position text.length, which is after all characters.
1318 This means that for all x values before the first character this function returns 0,
1319 and for all x values after the last character this function returns text.length. If
1320 the y value is above the text the position will be that of the nearest character on
1321 the first line line and if it is below the text the position of the nearest character
1322 on the last line will be returned.
1324 The cursor position type specifies how the cursor position should be resolved.
1327 \o TextInput.CursorBetweenCharacters - Returns the position between characters that is nearest x.
1328 \o TextInput.CursorOnCharacter - Returns the position before the character that is nearest x.
1332 void QQuickTextInput::positionAt(QDeclarativeV8Function *args) const
1334 Q_D(const QQuickTextInput);
1338 QTextLine::CursorPosition position = QTextLine::CursorBetweenCharacters;
1340 if (args->Length() < 1)
1344 v8::Local<v8::Value> arg = (*args)[i];
1345 x = arg->NumberValue();
1347 if (++i < args->Length()) {
1349 y = arg->NumberValue();
1352 if (++i < args->Length()) {
1354 position = QTextLine::CursorPosition(arg->Int32Value());
1357 int pos = d->positionAt(x, y, position);
1358 const int cursor = d->m_cursor;
1360 const int preeditLength = d->preeditAreaText().length();
1361 pos = pos > cursor + preeditLength
1362 ? pos - preeditLength
1365 args->returnValue(v8::Int32::New(pos));
1368 int QQuickTextInputPrivate::positionAt(int x, int y, QTextLine::CursorPosition position) const
1372 QTextLine line = m_textLayout.lineAt(0);
1373 for (int i = 1; i < m_textLayout.lineCount(); ++i) {
1374 QTextLine nextLine = m_textLayout.lineAt(i);
1376 if (y < (line.rect().bottom() + nextLine.y()) / 2)
1380 return line.isValid() ? line.xToCursor(x, position) : 0;
1383 void QQuickTextInput::keyPressEvent(QKeyEvent* ev)
1385 Q_D(QQuickTextInput);
1386 // Don't allow MacOSX up/down support, and we don't allow a completer.
1387 bool ignore = (ev->key() == Qt::Key_Up || ev->key() == Qt::Key_Down) && ev->modifiers() == Qt::NoModifier;
1388 if (!ignore && (d->lastSelectionStart == d->lastSelectionEnd) && (ev->key() == Qt::Key_Right || ev->key() == Qt::Key_Left)) {
1389 // Ignore when moving off the end unless there is a selection,
1390 // because then moving will do something (deselect).
1391 int cursorPosition = d->m_cursor;
1392 if (cursorPosition == 0)
1393 ignore = ev->key() == (d->layoutDirection() == Qt::LeftToRight ? Qt::Key_Left : Qt::Key_Right);
1394 if (cursorPosition == text().length())
1395 ignore = ev->key() == (d->layoutDirection() == Qt::LeftToRight ? Qt::Key_Right : Qt::Key_Left);
1400 d->processKeyEvent(ev);
1402 if (!ev->isAccepted())
1403 QQuickImplicitSizeItem::keyPressEvent(ev);
1406 void QQuickTextInput::inputMethodEvent(QInputMethodEvent *ev)
1408 Q_D(QQuickTextInput);
1409 const bool wasComposing = d->preeditAreaText().length() > 0;
1410 if (d->m_readOnly) {
1413 d->processInputMethodEvent(ev);
1415 if (!ev->isAccepted())
1416 QQuickImplicitSizeItem::inputMethodEvent(ev);
1418 if (wasComposing != (d->m_textLayout.preeditAreaText().length() > 0))
1419 emit inputMethodComposingChanged();
1422 void QQuickTextInput::mouseDoubleClickEvent(QMouseEvent *event)
1424 Q_D(QQuickTextInput);
1426 if (d->selectByMouse && event->button() == Qt::LeftButton) {
1428 int cursor = d->positionAt(event->localPos());
1429 d->selectWordAtPos(cursor);
1430 event->setAccepted(true);
1431 if (!d->hasPendingTripleClick()) {
1432 d->tripleClickStartPoint = event->localPos().toPoint();
1433 d->tripleClickTimer.start();
1436 if (d->sendMouseEventToInputContext(event))
1438 QQuickImplicitSizeItem::mouseDoubleClickEvent(event);
1442 void QQuickTextInput::mousePressEvent(QMouseEvent *event)
1444 Q_D(QQuickTextInput);
1446 d->pressPos = event->localPos();
1448 if (d->focusOnPress) {
1449 bool hadActiveFocus = hasActiveFocus();
1451 // re-open input panel on press if already focused
1452 if (hasActiveFocus() && hadActiveFocus && !d->m_readOnly)
1453 openSoftwareInputPanel();
1455 if (d->selectByMouse) {
1456 setKeepMouseGrab(false);
1457 d->selectPressed = true;
1458 QPoint distanceVector = d->pressPos.toPoint() - d->tripleClickStartPoint;
1459 if (d->hasPendingTripleClick()
1460 && distanceVector.manhattanLength() < qApp->styleHints()->startDragDistance()) {
1461 event->setAccepted(true);
1467 if (d->sendMouseEventToInputContext(event))
1470 bool mark = (event->modifiers() & Qt::ShiftModifier) && d->selectByMouse;
1471 int cursor = d->positionAt(event->localPos());
1472 d->moveCursor(cursor, mark);
1473 event->setAccepted(true);
1476 void QQuickTextInput::mouseMoveEvent(QMouseEvent *event)
1478 Q_D(QQuickTextInput);
1480 if (d->selectPressed) {
1481 if (qAbs(int(event->localPos().x() - d->pressPos.x())) > qApp->styleHints()->startDragDistance())
1482 setKeepMouseGrab(true);
1484 if (d->composeMode()) {
1486 int startPos = d->positionAt(d->pressPos);
1487 int currentPos = d->positionAt(event->localPos());
1488 if (startPos != currentPos)
1489 d->setSelection(startPos, currentPos - startPos);
1491 moveCursorSelection(d->positionAt(event->localPos()), d->mouseSelectionMode);
1493 event->setAccepted(true);
1495 QQuickImplicitSizeItem::mouseMoveEvent(event);
1499 void QQuickTextInput::mouseReleaseEvent(QMouseEvent *event)
1501 Q_D(QQuickTextInput);
1502 if (d->sendMouseEventToInputContext(event))
1504 if (d->selectPressed) {
1505 d->selectPressed = false;
1506 setKeepMouseGrab(false);
1508 #ifndef QT_NO_CLIPBOARD
1509 if (QGuiApplication::clipboard()->supportsSelection()) {
1510 if (event->button() == Qt::LeftButton) {
1511 d->copy(QClipboard::Selection);
1512 } else if (!d->m_readOnly && event->button() == Qt::MidButton) {
1514 d->insert(QGuiApplication::clipboard()->text(QClipboard::Selection));
1518 if (!event->isAccepted())
1519 QQuickImplicitSizeItem::mouseReleaseEvent(event);
1522 bool QQuickTextInputPrivate::sendMouseEventToInputContext(QMouseEvent *event)
1524 #if !defined QT_NO_IM
1525 if (composeMode()) {
1526 int tmp_cursor = positionAt(event->localPos());
1527 int mousePos = tmp_cursor - m_cursor;
1528 if (mousePos >= 0 && mousePos <= m_textLayout.preeditAreaText().length()) {
1529 if (event->type() == QEvent::MouseButtonRelease) {
1530 qApp->inputPanel()->invokeAction(QInputPanel::Click, mousePos);
1543 void QQuickTextInput::mouseUngrabEvent()
1545 Q_D(QQuickTextInput);
1546 d->selectPressed = false;
1547 setKeepMouseGrab(false);
1550 bool QQuickTextInput::event(QEvent* ev)
1552 #ifndef QT_NO_SHORTCUT
1553 Q_D(QQuickTextInput);
1554 if (ev->type() == QEvent::ShortcutOverride) {
1557 QKeyEvent* ke = static_cast<QKeyEvent*>(ev);
1558 if (ke == QKeySequence::Copy
1559 || ke == QKeySequence::Paste
1560 || ke == QKeySequence::Cut
1561 || ke == QKeySequence::Redo
1562 || ke == QKeySequence::Undo
1563 || ke == QKeySequence::MoveToNextWord
1564 || ke == QKeySequence::MoveToPreviousWord
1565 || ke == QKeySequence::MoveToStartOfDocument
1566 || ke == QKeySequence::MoveToEndOfDocument
1567 || ke == QKeySequence::SelectNextWord
1568 || ke == QKeySequence::SelectPreviousWord
1569 || ke == QKeySequence::SelectStartOfLine
1570 || ke == QKeySequence::SelectEndOfLine
1571 || ke == QKeySequence::SelectStartOfBlock
1572 || ke == QKeySequence::SelectEndOfBlock
1573 || ke == QKeySequence::SelectStartOfDocument
1574 || ke == QKeySequence::SelectAll
1575 || ke == QKeySequence::SelectEndOfDocument) {
1577 } else if (ke->modifiers() == Qt::NoModifier || ke->modifiers() == Qt::ShiftModifier
1578 || ke->modifiers() == Qt::KeypadModifier) {
1579 if (ke->key() < Qt::Key_Escape) {
1583 switch (ke->key()) {
1584 case Qt::Key_Delete:
1587 case Qt::Key_Backspace:
1599 return QQuickImplicitSizeItem::event(ev);
1602 void QQuickTextInput::geometryChanged(const QRectF &newGeometry,
1603 const QRectF &oldGeometry)
1605 Q_D(QQuickTextInput);
1606 if (newGeometry.width() != oldGeometry.width())
1608 updateCursorRectangle();
1609 QQuickImplicitSizeItem::geometryChanged(newGeometry, oldGeometry);
1612 void QQuickTextInputPrivate::updateHorizontalScroll()
1614 Q_Q(QQuickTextInput);
1615 QTextLine currentLine = m_textLayout.lineForTextPosition(m_cursor + m_preeditCursor);
1616 const int preeditLength = m_textLayout.preeditAreaText().length();
1617 const int width = qMax(0, qFloor(q->width()));
1618 int widthUsed = currentLine.isValid() ? qRound(currentLine.naturalTextWidth()) : 0;
1619 int previousScroll = hscroll;
1621 if (!autoScroll || widthUsed <= width || m_echoMode == QQuickTextInput::NoEcho) {
1624 Q_ASSERT(currentLine.isValid());
1625 int cix = qRound(currentLine.cursorToX(m_cursor + preeditLength));
1626 if (cix - hscroll >= width) {
1627 // text doesn't fit, cursor is to the right of br (scroll right)
1628 hscroll = cix - width;
1629 } else if (cix - hscroll < 0 && hscroll < widthUsed) {
1630 // text doesn't fit, cursor is to the left of br (scroll left)
1632 } else if (widthUsed - hscroll < width) {
1633 // text doesn't fit, text document is to the left of br; align
1635 hscroll = widthUsed - width;
1637 if (preeditLength > 0) {
1638 // check to ensure long pre-edit text doesn't push the cursor
1640 cix = qRound(currentLine.cursorToX(m_cursor + qMax(0, m_preeditCursor - 1)));
1645 if (previousScroll != hscroll)
1646 textLayoutDirty = true;
1649 void QQuickTextInputPrivate::updateVerticalScroll()
1651 Q_Q(QQuickTextInput);
1652 const int preeditLength = m_textLayout.preeditAreaText().length();
1653 const int height = qMax(0, qFloor(q->height()));
1654 int heightUsed = boundingRect.height();
1655 int previousScroll = vscroll;
1657 if (!autoScroll || heightUsed <= height) {
1658 // text fits in br; use vscroll for alignment
1659 switch (vAlign & ~(Qt::AlignAbsolute|Qt::AlignHorizontal_Mask)) {
1660 case Qt::AlignBottom:
1661 vscroll = heightUsed - height;
1663 case Qt::AlignVCenter:
1664 vscroll = (heightUsed - height) / 2;
1672 QTextLine currentLine = m_textLayout.lineForTextPosition(m_cursor + preeditLength);
1673 QRectF r = currentLine.isValid() ? currentLine.rect() : QRectF();
1674 int top = qFloor(r.top());
1675 int bottom = qCeil(r.bottom());
1677 if (bottom - vscroll >= height) {
1678 // text doesn't fit, cursor is to the below the br (scroll down)
1679 vscroll = bottom - height;
1680 } else if (top - vscroll < 0 && vscroll < heightUsed) {
1681 // text doesn't fit, cursor is above br (scroll up)
1683 } else if (heightUsed - vscroll < height) {
1684 // text doesn't fit, text document is to the left of br; align
1686 vscroll = heightUsed - height;
1688 if (preeditLength > 0) {
1689 // check to ensure long pre-edit text doesn't push the cursor
1691 currentLine = m_textLayout.lineForTextPosition(m_cursor + qMax(0, m_preeditCursor - 1));
1692 top = currentLine.isValid() ? qRound(currentLine.rect().top()) : 0;
1697 if (previousScroll != vscroll)
1698 textLayoutDirty = true;
1701 void QQuickTextInput::triggerPreprocess()
1703 Q_D(QQuickTextInput);
1704 if (d->updateType == QQuickTextInputPrivate::UpdateNone)
1705 d->updateType = QQuickTextInputPrivate::UpdateOnlyPreprocess;
1709 QSGNode *QQuickTextInput::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data)
1712 Q_D(QQuickTextInput);
1714 if (d->updateType != QQuickTextInputPrivate::UpdatePaintNode && oldNode != 0) {
1715 // Update done in preprocess() in the nodes
1716 d->updateType = QQuickTextInputPrivate::UpdateNone;
1720 d->updateType = QQuickTextInputPrivate::UpdateNone;
1722 QQuickTextNode *node = static_cast<QQuickTextNode *>(oldNode);
1724 node = new QQuickTextNode(QQuickItemPrivate::get(this)->sceneGraphContext(), this);
1727 if (!d->textLayoutDirty) {
1728 QSGSimpleRectNode *cursorNode = node->cursorNode();
1729 if (cursorNode != 0 && !isReadOnly()) {
1730 cursorNode->setRect(cursorRectangle());
1732 if (!d->cursorVisible || (!d->m_blinkStatus && d->m_blinkPeriod > 0)) {
1739 node->deleteContent();
1740 node->setMatrix(QMatrix4x4());
1742 QPoint offset = QPoint(0,0);
1743 QFontMetrics fm = QFontMetrics(d->font);
1744 if (d->autoScroll) {
1745 // the y offset is there to keep the baseline constant in case we have script changes in the text.
1746 offset = -QPoint(d->hscroll, d->vscroll + d->m_ascent - fm.ascent());
1748 offset = -QPoint(d->hscroll, d->vscroll);
1751 if (!d->m_textLayout.text().isEmpty() || !d->m_textLayout.preeditAreaText().isEmpty()) {
1752 node->addTextLayout(offset, &d->m_textLayout, d->color,
1753 QQuickText::Normal, QColor(),
1754 d->selectionColor, d->selectedTextColor,
1755 d->selectionStart(),
1756 d->selectionEnd() - 1); // selectionEnd() returns first char after
1760 if (!isReadOnly() && d->cursorItem == 0) {
1761 node->setCursor(cursorRectangle(), d->color);
1762 if (!d->cursorVisible || (!d->m_blinkStatus && d->m_blinkPeriod > 0)) {
1769 d->textLayoutDirty = false;
1775 QVariant QQuickTextInput::inputMethodQuery(Qt::InputMethodQuery property) const
1777 Q_D(const QQuickTextInput);
1780 return QVariant((bool)(flags() & ItemAcceptsInputMethod));
1782 return QVariant((int)inputMethodHints());
1783 case Qt::ImCursorRectangle:
1784 return cursorRectangle();
1787 case Qt::ImCursorPosition:
1788 return QVariant(d->m_cursor);
1789 case Qt::ImSurroundingText:
1790 if (d->m_echoMode == PasswordEchoOnEdit && !d->m_passwordEchoEditing) {
1791 return QVariant(displayText());
1793 return QVariant(d->realText());
1795 case Qt::ImCurrentSelection:
1796 return QVariant(selectedText());
1797 case Qt::ImMaximumTextLength:
1798 return QVariant(maxLength());
1799 case Qt::ImAnchorPosition:
1800 if (d->selectionStart() == d->selectionEnd())
1801 return QVariant(d->m_cursor);
1802 else if (d->selectionStart() == d->m_cursor)
1803 return QVariant(d->selectionEnd());
1805 return QVariant(d->selectionStart());
1812 \qmlmethod void QtQuick2::TextInput::deselect()
1814 Removes active text selection.
1816 void QQuickTextInput::deselect()
1818 Q_D(QQuickTextInput);
1823 \qmlmethod void QtQuick2::TextInput::selectAll()
1825 Causes all text to be selected.
1827 void QQuickTextInput::selectAll()
1829 Q_D(QQuickTextInput);
1830 d->setSelection(0, text().length());
1834 \qmlmethod void QtQuick2::TextInput::isRightToLeft(int start, int end)
1836 Returns true if the natural reading direction of the editor text
1837 found between positions \a start and \a end is right to left.
1839 bool QQuickTextInput::isRightToLeft(int start, int end)
1842 qmlInfo(this) << "isRightToLeft(start, end) called with the end property being smaller than the start.";
1845 return text().mid(start, end - start).isRightToLeft();
1849 #ifndef QT_NO_CLIPBOARD
1851 \qmlmethod QtQuick2::TextInput::cut()
1853 Moves the currently selected text to the system clipboard.
1855 void QQuickTextInput::cut()
1857 Q_D(QQuickTextInput);
1863 \qmlmethod QtQuick2::TextInput::copy()
1865 Copies the currently selected text to the system clipboard.
1867 void QQuickTextInput::copy()
1869 Q_D(QQuickTextInput);
1874 \qmlmethod QtQuick2::TextInput::paste()
1876 Replaces the currently selected text by the contents of the system clipboard.
1878 void QQuickTextInput::paste()
1880 Q_D(QQuickTextInput);
1884 #endif // QT_NO_CLIPBOARD
1887 Undoes the last operation if undo is \l {canUndo}{available}. Deselects any
1888 current selection, and updates the selection start to the current cursor
1892 void QQuickTextInput::undo()
1894 Q_D(QQuickTextInput);
1895 if (!d->m_readOnly) {
1897 d->finishChange(-1, true);
1902 Redoes the last operation if redo is \l {canRedo}{available}.
1905 void QQuickTextInput::redo()
1907 Q_D(QQuickTextInput);
1908 if (!d->m_readOnly) {
1915 \qmlmethod void QtQuick2::TextInput::insert(int position, string text)
1917 Inserts \a text into the TextInput at position.
1920 void QQuickTextInput::insert(int position, const QString &text)
1922 Q_D(QQuickTextInput);
1923 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
1924 if (d->m_echoMode == QQuickTextInput::Password)
1925 d->m_passwordEchoTimer.start(qt_passwordEchoDelay, this);
1928 if (position < 0 || position > d->m_text.length())
1931 const int priorState = d->m_undoState;
1933 QString insertText = text;
1935 if (d->hasSelectedText()) {
1936 d->addCommand(QQuickTextInputPrivate::Command(
1937 QQuickTextInputPrivate::SetSelection, d->m_cursor, 0, d->m_selstart, d->m_selend));
1939 if (d->m_maskData) {
1940 insertText = d->maskString(position, insertText);
1941 for (int i = 0; i < insertText.length(); ++i) {
1942 d->addCommand(QQuickTextInputPrivate::Command(
1943 QQuickTextInputPrivate::DeleteSelection, position + i, d->m_text.at(position + i), -1, -1));
1944 d->addCommand(QQuickTextInputPrivate::Command(
1945 QQuickTextInputPrivate::Insert, position + i, insertText.at(i), -1, -1));
1947 d->m_text.replace(position, insertText.length(), insertText);
1948 if (!insertText.isEmpty())
1949 d->m_textDirty = true;
1950 if (position < d->m_selend && position + insertText.length() > d->m_selstart)
1951 d->m_selDirty = true;
1953 int remaining = d->m_maxLength - d->m_text.length();
1954 if (remaining != 0) {
1955 insertText = insertText.left(remaining);
1956 d->m_text.insert(position, insertText);
1957 for (int i = 0; i < insertText.length(); ++i)
1958 d->addCommand(QQuickTextInputPrivate::Command(
1959 QQuickTextInputPrivate::Insert, position + i, insertText.at(i), -1, -1));
1960 if (d->m_cursor >= position)
1961 d->m_cursor += insertText.length();
1962 if (d->m_selstart >= position)
1963 d->m_selstart += insertText.length();
1964 if (d->m_selend >= position)
1965 d->m_selend += insertText.length();
1966 d->m_textDirty = true;
1967 if (position >= d->m_selstart && position <= d->m_selend)
1968 d->m_selDirty = true;
1972 d->addCommand(QQuickTextInputPrivate::Command(
1973 QQuickTextInputPrivate::SetSelection, d->m_cursor, 0, d->m_selstart, d->m_selend));
1974 d->finishChange(priorState);
1976 if (d->lastSelectionStart != d->lastSelectionEnd) {
1977 if (d->m_selstart != d->lastSelectionStart) {
1978 d->lastSelectionStart = d->m_selstart;
1979 emit selectionStartChanged();
1981 if (d->m_selend != d->lastSelectionEnd) {
1982 d->lastSelectionEnd = d->m_selend;
1983 emit selectionEndChanged();
1989 \qmlmethod string QtQuick2::TextInput::getText(int start, int end)
1991 Removes the section of text that is between the \a start and \a end positions from the TextInput.
1994 void QQuickTextInput::remove(int start, int end)
1996 Q_D(QQuickTextInput);
1998 start = qBound(0, start, d->m_text.length());
1999 end = qBound(0, end, d->m_text.length());
2003 else if (start == end)
2006 if (start < d->m_selend && end > d->m_selstart)
2007 d->m_selDirty = true;
2009 const int priorState = d->m_undoState;
2011 d->addCommand(QQuickTextInputPrivate::Command(
2012 QQuickTextInputPrivate::SetSelection, d->m_cursor, 0, d->m_selstart, d->m_selend));
2014 if (start <= d->m_cursor && d->m_cursor < end) {
2015 // cursor is within the selection. Split up the commands
2016 // to be able to restore the correct cursor position
2017 for (int i = d->m_cursor; i >= start; --i) {
2018 d->addCommand(QQuickTextInputPrivate::Command(
2019 QQuickTextInputPrivate::DeleteSelection, i, d->m_text.at(i), -1, 1));
2021 for (int i = end - 1; i > d->m_cursor; --i) {
2022 d->addCommand(QQuickTextInputPrivate::Command(
2023 QQuickTextInputPrivate::DeleteSelection, i - d->m_cursor + start - 1, d->m_text.at(i), -1, -1));
2026 for (int i = end - 1; i >= start; --i) {
2027 d->addCommand(QQuickTextInputPrivate::Command(
2028 QQuickTextInputPrivate::RemoveSelection, i, d->m_text.at(i), -1, -1));
2031 if (d->m_maskData) {
2032 d->m_text.replace(start, end - start, d->clearString(start, end - start));
2033 for (int i = 0; i < end - start; ++i) {
2034 d->addCommand(QQuickTextInputPrivate::Command(
2035 QQuickTextInputPrivate::Insert, start + i, d->m_text.at(start + i), -1, -1));
2038 d->m_text.remove(start, end - start);
2040 if (d->m_cursor > start)
2041 d->m_cursor -= qMin(d->m_cursor, end) - start;
2042 if (d->m_selstart > start)
2043 d->m_selstart -= qMin(d->m_selstart, end) - start;
2044 if (d->m_selend > end)
2045 d->m_selend -= qMin(d->m_selend, end) - start;
2047 d->addCommand(QQuickTextInputPrivate::Command(
2048 QQuickTextInputPrivate::SetSelection, d->m_cursor, 0, d->m_selstart, d->m_selend));
2050 d->m_textDirty = true;
2051 d->finishChange(priorState);
2053 if (d->lastSelectionStart != d->lastSelectionEnd) {
2054 if (d->m_selstart != d->lastSelectionStart) {
2055 d->lastSelectionStart = d->m_selstart;
2056 emit selectionStartChanged();
2058 if (d->m_selend != d->lastSelectionEnd) {
2059 d->lastSelectionEnd = d->m_selend;
2060 emit selectionEndChanged();
2067 \qmlmethod void QtQuick2::TextInput::selectWord()
2069 Causes the word closest to the current cursor position to be selected.
2071 void QQuickTextInput::selectWord()
2073 Q_D(QQuickTextInput);
2074 d->selectWordAtPos(d->m_cursor);
2078 \qmlproperty bool QtQuick2::TextInput::smooth
2080 This property holds whether the text is smoothly scaled or transformed.
2082 Smooth filtering gives better visual quality, but is slower. If
2083 the item is displayed at its natural size, this property has no visual or
2086 \note Generally scaling artifacts are only visible if the item is stationary on
2087 the screen. A common pattern when animating an item is to disable smooth
2088 filtering at the beginning of the animation and reenable it at the conclusion.
2092 \qmlproperty string QtQuick2::TextInput::passwordCharacter
2094 This is the character displayed when echoMode is set to Password or
2095 PasswordEchoOnEdit. By default it is an asterisk.
2097 If this property is set to a string with more than one character,
2098 the first character is used. If the string is empty, the value
2099 is ignored and the property is not set.
2101 QString QQuickTextInput::passwordCharacter() const
2103 Q_D(const QQuickTextInput);
2104 return QString(d->m_passwordCharacter);
2107 void QQuickTextInput::setPasswordCharacter(const QString &str)
2109 Q_D(QQuickTextInput);
2110 if (str.length() < 1)
2112 d->m_passwordCharacter = str.constData()[0];
2113 if (d->m_echoMode == Password || d->m_echoMode == PasswordEchoOnEdit)
2114 d->updateDisplayText();
2115 emit passwordCharacterChanged();
2119 \qmlproperty string QtQuick2::TextInput::displayText
2121 This is the text displayed in the TextInput.
2123 If \l echoMode is set to TextInput::Normal, this holds the
2124 same value as the TextInput::text property. Otherwise,
2125 this property holds the text visible to the user, while
2126 the \l text property holds the actual entered text.
2128 QString QQuickTextInput::displayText() const
2130 Q_D(const QQuickTextInput);
2131 return d->m_textLayout.text();
2135 \qmlproperty bool QtQuick2::TextInput::selectByMouse
2139 If true, the user can use the mouse to select text in some
2140 platform-specific way. Note that for some platforms this may
2141 not be an appropriate interaction (eg. may conflict with how
2142 the text needs to behave inside a Flickable.
2144 bool QQuickTextInput::selectByMouse() const
2146 Q_D(const QQuickTextInput);
2147 return d->selectByMouse;
2150 void QQuickTextInput::setSelectByMouse(bool on)
2152 Q_D(QQuickTextInput);
2153 if (d->selectByMouse != on) {
2154 d->selectByMouse = on;
2155 emit selectByMouseChanged(on);
2160 \qmlproperty enum QtQuick2::TextInput::mouseSelectionMode
2162 Specifies how text should be selected using a mouse.
2165 \o TextInput.SelectCharacters - The selection is updated with individual characters. (Default)
2166 \o TextInput.SelectWords - The selection is updated with whole words.
2169 This property only applies when \l selectByMouse is true.
2172 QQuickTextInput::SelectionMode QQuickTextInput::mouseSelectionMode() const
2174 Q_D(const QQuickTextInput);
2175 return d->mouseSelectionMode;
2178 void QQuickTextInput::setMouseSelectionMode(SelectionMode mode)
2180 Q_D(QQuickTextInput);
2181 if (d->mouseSelectionMode != mode) {
2182 d->mouseSelectionMode = mode;
2183 emit mouseSelectionModeChanged(mode);
2188 \qmlproperty bool QtQuick2::TextInput::canPaste
2190 Returns true if the TextInput is writable and the content of the clipboard is
2191 suitable for pasting into the TextInput.
2193 bool QQuickTextInput::canPaste() const
2195 Q_D(const QQuickTextInput);
2196 if (!d->canPasteValid) {
2197 if (const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData())
2198 const_cast<QQuickTextInputPrivate *>(d)->canPaste = !d->m_readOnly && mimeData->hasText();
2199 const_cast<QQuickTextInputPrivate *>(d)->canPasteValid = true;
2205 \qmlproperty bool QtQuick2::TextInput::canUndo
2207 Returns true if the TextInput is writable and there are previous operations
2211 bool QQuickTextInput::canUndo() const
2213 Q_D(const QQuickTextInput);
2218 \qmlproperty bool QtQuick2::TextInput::canRedo
2220 Returns true if the TextInput is writable and there are \l {undo}{undone}
2221 operations that can be redone.
2224 bool QQuickTextInput::canRedo() const
2226 Q_D(const QQuickTextInput);
2230 void QQuickTextInput::moveCursorSelection(int position)
2232 Q_D(QQuickTextInput);
2233 d->moveCursor(position, true);
2237 \qmlmethod void QtQuick2::TextInput::moveCursorSelection(int position, SelectionMode mode = TextInput.SelectCharacters)
2239 Moves the cursor to \a position and updates the selection according to the optional \a mode
2240 parameter. (To only move the cursor, set the \l cursorPosition property.)
2242 When this method is called it additionally sets either the
2243 selectionStart or the selectionEnd (whichever was at the previous cursor position)
2244 to the specified position. This allows you to easily extend and contract the selected
2247 The selection mode specifies whether the selection is updated on a per character or a per word
2248 basis. If not specified the selection mode will default to TextInput.SelectCharacters.
2251 \o TextInput.SelectCharacters - Sets either the selectionStart or selectionEnd (whichever was at
2252 the previous cursor position) to the specified position.
2253 \o TextInput.SelectWords - Sets the selectionStart and selectionEnd to include all
2254 words between the specified position and the previous cursor position. Words partially in the
2258 For example, take this sequence of calls:
2262 moveCursorSelection(9, TextInput.SelectCharacters)
2263 moveCursorSelection(7, TextInput.SelectCharacters)
2266 This moves the cursor to position 5, extend the selection end from 5 to 9
2267 and then retract the selection end from 9 to 7, leaving the text from position 5 to 7
2268 selected (the 6th and 7th characters).
2270 The same sequence with TextInput.SelectWords will extend the selection start to a word boundary
2271 before or on position 5 and extend the selection end to a word boundary on or past position 9.
2273 void QQuickTextInput::moveCursorSelection(int pos, SelectionMode mode)
2275 Q_D(QQuickTextInput);
2277 if (mode == SelectCharacters) {
2278 d->moveCursor(pos, true);
2279 } else if (pos != d->m_cursor){
2280 const int cursor = d->m_cursor;
2282 if (!d->hasSelectedText())
2283 anchor = d->m_cursor;
2284 else if (d->selectionStart() == d->m_cursor)
2285 anchor = d->selectionEnd();
2287 anchor = d->selectionStart();
2289 if (anchor < pos || (anchor == pos && cursor < pos)) {
2290 const QString text = this->text();
2291 QTextBoundaryFinder finder(QTextBoundaryFinder::Word, text);
2292 finder.setPosition(anchor);
2294 const QTextBoundaryFinder::BoundaryReasons reasons = finder.boundaryReasons();
2295 if (anchor < text.length() && (!(reasons & QTextBoundaryFinder::StartWord)
2296 || ((reasons & QTextBoundaryFinder::EndWord) && anchor > cursor))) {
2297 finder.toPreviousBoundary();
2299 anchor = finder.position() != -1 ? finder.position() : 0;
2301 finder.setPosition(pos);
2302 if (pos > 0 && !finder.boundaryReasons())
2303 finder.toNextBoundary();
2304 const int cursor = finder.position() != -1 ? finder.position() : text.length();
2306 d->setSelection(anchor, cursor - anchor);
2307 } else if (anchor > pos || (anchor == pos && cursor > pos)) {
2308 const QString text = this->text();
2309 QTextBoundaryFinder finder(QTextBoundaryFinder::Word, text);
2310 finder.setPosition(anchor);
2312 const QTextBoundaryFinder::BoundaryReasons reasons = finder.boundaryReasons();
2313 if (anchor > 0 && (!(reasons & QTextBoundaryFinder::EndWord)
2314 || ((reasons & QTextBoundaryFinder::StartWord) && anchor < cursor))) {
2315 finder.toNextBoundary();
2318 anchor = finder.position() != -1 ? finder.position() : text.length();
2320 finder.setPosition(pos);
2321 if (pos < text.length() && !finder.boundaryReasons())
2322 finder.toPreviousBoundary();
2323 const int cursor = finder.position() != -1 ? finder.position() : 0;
2325 d->setSelection(anchor, cursor - anchor);
2331 \qmlmethod void QtQuick2::TextInput::openSoftwareInputPanel()
2333 Opens software input panels like virtual keyboards for typing, useful for
2334 customizing when you want the input keyboard to be shown and hidden in
2337 By default the opening of input panels follows the platform style. Input panels are
2338 always closed if no editor has active focus.
2340 You can disable the automatic behavior by setting the property \c activeFocusOnPress to false
2341 and use functions openSoftwareInputPanel() and closeSoftwareInputPanel() to implement
2342 the behavior you want.
2344 Only relevant on platforms, which provide virtual keyboards.
2350 text: "Hello world!"
2351 activeFocusOnPress: false
2353 anchors.fill: parent
2355 if (!textInput.activeFocus) {
2356 textInput.forceActiveFocus()
2357 textInput.openSoftwareInputPanel();
2359 textInput.focus = false;
2362 onPressAndHold: textInput.closeSoftwareInputPanel();
2367 void QQuickTextInput::openSoftwareInputPanel()
2370 qGuiApp->inputPanel()->show();
2374 \qmlmethod void QtQuick2::TextInput::closeSoftwareInputPanel()
2376 Closes a software input panel like a virtual keyboard shown on the screen, useful
2377 for customizing when you want the input keyboard to be shown and hidden in
2380 By default the opening of input panels follows the platform style. Input panels are
2381 always closed if no editor has active focus.
2383 You can disable the automatic behavior by setting the property \c activeFocusOnPress to false
2384 and use functions openSoftwareInputPanel() and closeSoftwareInputPanel() to implement
2385 the behavior you want.
2387 Only relevant on platforms, which provide virtual keyboards.
2393 text: "Hello world!"
2394 activeFocusOnPress: false
2396 anchors.fill: parent
2398 if (!textInput.activeFocus) {
2399 textInput.forceActiveFocus();
2400 textInput.openSoftwareInputPanel();
2402 textInput.focus = false;
2405 onPressAndHold: textInput.closeSoftwareInputPanel();
2410 void QQuickTextInput::closeSoftwareInputPanel()
2413 qGuiApp->inputPanel()->hide();
2416 void QQuickTextInput::focusInEvent(QFocusEvent *event)
2418 Q_D(const QQuickTextInput);
2419 if (d->focusOnPress && !d->m_readOnly)
2420 openSoftwareInputPanel();
2421 QQuickImplicitSizeItem::focusInEvent(event);
2424 void QQuickTextInput::itemChange(ItemChange change, const ItemChangeData &value)
2426 Q_D(QQuickTextInput);
2427 if (change == ItemActiveFocusHasChanged) {
2428 bool hasFocus = value.boolValue;
2429 d->focused = hasFocus;
2430 setCursorVisible(hasFocus); // ### refactor: && d->canvas && d->canvas->hasFocus()
2431 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
2432 if (!hasFocus && (d->m_passwordEchoEditing || d->m_passwordEchoTimer.isActive())) {
2434 if (!hasFocus && d->m_passwordEchoEditing) {
2436 d->updatePasswordEchoEditing(false);//QQuickTextInputPrivate sets it on key events, but doesn't deal with focus events
2442 disconnect(qApp->inputPanel(), SIGNAL(inputDirectionChanged(Qt::LayoutDirection)),
2443 this, SLOT(q_updateAlignment()));
2445 q_updateAlignment();
2446 connect(qApp->inputPanel(), SIGNAL(inputDirectionChanged(Qt::LayoutDirection)),
2447 this, SLOT(q_updateAlignment()));
2450 QQuickItem::itemChange(change, value);
2454 \qmlproperty bool QtQuick2::TextInput::inputMethodComposing
2457 This property holds whether the TextInput has partial text input from an
2460 While it is composing an input method may rely on mouse or key events from
2461 the TextInput to edit or commit the partial text. This property can be
2462 used to determine when to disable events handlers that may interfere with
2463 the correct operation of an input method.
2465 bool QQuickTextInput::isInputMethodComposing() const
2467 Q_D(const QQuickTextInput);
2468 return d->preeditAreaText().length() > 0;
2471 void QQuickTextInputPrivate::init()
2473 Q_Q(QQuickTextInput);
2474 q->setSmooth(smooth);
2475 q->setAcceptedMouseButtons(Qt::LeftButton);
2476 q->setFlag(QQuickItem::ItemAcceptsInputMethod);
2477 q->setFlag(QQuickItem::ItemHasContents);
2478 #ifndef QT_NO_CLIPBOARD
2479 q->connect(QGuiApplication::clipboard(), SIGNAL(dataChanged()),
2480 q, SLOT(q_canPasteChanged()));
2481 #endif // QT_NO_CLIPBOARD
2483 lastSelectionStart = 0;
2484 lastSelectionEnd = 0;
2485 selectedTextColor = m_palette.color(QPalette::HighlightedText);
2486 selectionColor = m_palette.color(QPalette::Highlight);
2487 determineHorizontalAlignment();
2489 if (!qmlDisableDistanceField()) {
2490 QTextOption option = m_textLayout.textOption();
2491 option.setUseDesignMetrics(true);
2492 m_textLayout.setTextOption(option);
2496 void QQuickTextInput::updateCursorRectangle()
2498 Q_D(QQuickTextInput);
2499 if (!isComponentComplete())
2502 d->updateHorizontalScroll();
2503 d->updateVerticalScroll();
2504 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
2506 emit cursorRectangleChanged();
2507 if (d->cursorItem) {
2508 QRectF r = cursorRectangle();
2509 d->cursorItem->setPos(r.topLeft());
2510 d->cursorItem->setHeight(r.height());
2512 updateInputMethod(Qt::ImCursorRectangle);
2515 void QQuickTextInput::selectionChanged()
2517 Q_D(QQuickTextInput);
2518 d->textLayoutDirty = true; //TODO: Only update rect in selection
2519 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
2521 emit selectedTextChanged();
2523 if (d->lastSelectionStart != d->selectionStart()) {
2524 d->lastSelectionStart = d->selectionStart();
2525 if (d->lastSelectionStart == -1)
2526 d->lastSelectionStart = d->m_cursor;
2527 emit selectionStartChanged();
2529 if (d->lastSelectionEnd != d->selectionEnd()) {
2530 d->lastSelectionEnd = d->selectionEnd();
2531 if (d->lastSelectionEnd == -1)
2532 d->lastSelectionEnd = d->m_cursor;
2533 emit selectionEndChanged();
2537 void QQuickTextInputPrivate::showCursor()
2539 if (textNode != 0 && textNode->cursorNode() != 0)
2540 textNode->cursorNode()->setColor(color);
2543 void QQuickTextInputPrivate::hideCursor()
2545 if (textNode != 0 && textNode->cursorNode() != 0)
2546 textNode->cursorNode()->setColor(QColor(0, 0, 0, 0));
2549 QRectF QQuickTextInput::boundingRect() const
2551 Q_D(const QQuickTextInput);
2553 int cursorWidth = d->cursorItem ? d->cursorItem->width() : d->m_cursorWidth;
2555 // Could include font max left/right bearings to either side of rectangle.
2556 QRectF r = QQuickImplicitSizeItem::boundingRect();
2557 r.setRight(r.right() + cursorWidth);
2561 void QQuickTextInput::q_canPasteChanged()
2563 Q_D(QQuickTextInput);
2564 bool old = d->canPaste;
2565 #ifndef QT_NO_CLIPBOARD
2566 if (const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData())
2567 d->canPaste = !d->m_readOnly && mimeData->hasText();
2569 d->canPaste = false;
2572 bool changed = d->canPaste != old || !d->canPasteValid;
2573 d->canPasteValid = true;
2575 emit canPasteChanged();
2579 void QQuickTextInput::q_updateAlignment()
2581 Q_D(QQuickTextInput);
2582 if (d->determineHorizontalAlignment()) {
2584 updateCursorRectangle();
2588 // ### these should come from QStyleHints
2589 const int textCursorWidth = 1;
2590 const bool fullWidthSelection = true;
2595 Updates the display text based of the current edit text
2596 If the text has changed will emit displayTextChanged()
2598 void QQuickTextInputPrivate::updateDisplayText(bool forceUpdate)
2600 QString orig = m_textLayout.text();
2602 if (m_echoMode == QQuickTextInput::NoEcho)
2603 str = QString::fromLatin1("");
2607 if (m_echoMode == QQuickTextInput::Password) {
2608 str.fill(m_passwordCharacter);
2609 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
2610 if (m_passwordEchoTimer.isActive() && m_cursor > 0 && m_cursor <= m_text.length()) {
2611 int cursor = m_cursor - 1;
2612 QChar uc = m_text.at(cursor);
2614 if (cursor > 0 && uc.unicode() >= 0xdc00 && uc.unicode() < 0xe000) {
2615 // second half of a surrogate, check if we have the first half as well,
2616 // if yes restore both at once
2617 uc = m_text.at(cursor - 1);
2618 if (uc.unicode() >= 0xd800 && uc.unicode() < 0xdc00)
2619 str[cursor - 1] = uc;
2623 } else if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit && !m_passwordEchoEditing) {
2624 str.fill(m_passwordCharacter);
2627 // replace certain non-printable characters with spaces (to avoid
2628 // drawing boxes when using fonts that don't have glyphs for such
2630 QChar* uc = str.data();
2631 for (int i = 0; i < (int)str.length(); ++i) {
2632 if ((uc[i] < 0x20 && uc[i] != 0x09)
2633 || uc[i] == QChar::LineSeparator
2634 || uc[i] == QChar::ParagraphSeparator
2635 || uc[i] == QChar::ObjectReplacementCharacter)
2636 uc[i] = QChar(0x0020);
2639 if (str != orig || forceUpdate) {
2640 m_textLayout.setText(str);
2641 updateLayout(); // polish?
2642 emit q_func()->displayTextChanged();
2646 void QQuickTextInputPrivate::updateLayout()
2648 Q_Q(QQuickTextInput);
2650 if (!q->isComponentComplete())
2653 QTextOption option = m_textLayout.textOption();
2654 option.setTextDirection(layoutDirection());
2655 option.setFlags(QTextOption::IncludeTrailingSpaces);
2656 option.setWrapMode(QTextOption::WrapMode(wrapMode));
2657 option.setAlignment(Qt::Alignment(q->effectiveHAlign()));
2658 m_textLayout.setTextOption(option);
2659 m_textLayout.setFont(font);
2661 boundingRect = QRectF();
2662 m_textLayout.beginLayout();
2663 QTextLine line = m_textLayout.createLine();
2664 qreal lineWidth = q->widthValid() ? q->width() : INT_MAX;
2666 QTextLine firstLine = line;
2668 line.setLineWidth(lineWidth);
2669 line.setPosition(QPointF(line.position().x(), height));
2670 boundingRect = boundingRect.united(line.naturalTextRect());
2672 height += line.height();
2673 line = m_textLayout.createLine();
2674 } while (line.isValid());
2675 m_textLayout.endLayout();
2677 option.setWrapMode(QTextOption::NoWrap);
2678 m_textLayout.setTextOption(option);
2680 m_ascent = qRound(firstLine.ascent());
2681 textLayoutDirty = true;
2683 updateType = UpdatePaintNode;
2685 q->setImplicitSize(qCeil(boundingRect.width()), qCeil(boundingRect.height()));
2689 #ifndef QT_NO_CLIPBOARD
2693 Copies the currently selected text into the clipboard using the given
2696 \note If the echo mode is set to a mode other than Normal then copy
2697 will not work. This is to prevent using copy as a method of bypassing
2698 password features of the line control.
2700 void QQuickTextInputPrivate::copy(QClipboard::Mode mode) const
2702 QString t = selectedText();
2703 if (!t.isEmpty() && m_echoMode == QQuickTextInput::Normal) {
2704 QGuiApplication::clipboard()->setText(t, mode);
2711 Inserts the text stored in the application clipboard into the line
2716 void QQuickTextInputPrivate::paste(QClipboard::Mode clipboardMode)
2718 QString clip = QGuiApplication::clipboard()->text(clipboardMode);
2719 if (!clip.isEmpty() || hasSelectedText()) {
2720 separate(); //make it a separate undo/redo command
2726 #endif // !QT_NO_CLIPBOARD
2731 Exits preedit mode and commits parts marked as tentative commit
2733 void QQuickTextInputPrivate::commitPreedit()
2738 qApp->inputPanel()->reset();
2740 if (!m_tentativeCommit.isEmpty()) {
2741 internalInsert(m_tentativeCommit);
2742 m_tentativeCommit.clear();
2743 finishChange(-1, true/*not used, not documented*/, false);
2746 m_preeditCursor = 0;
2747 m_textLayout.setPreeditArea(-1, QString());
2748 m_textLayout.clearAdditionalFormats();
2755 Handles the behavior for the backspace key or function.
2756 Removes the current selection if there is a selection, otherwise
2757 removes the character prior to the cursor position.
2761 void QQuickTextInputPrivate::backspace()
2763 int priorState = m_undoState;
2764 if (hasSelectedText()) {
2765 removeSelectedText();
2766 } else if (m_cursor) {
2769 m_cursor = prevMaskBlank(m_cursor);
2770 QChar uc = m_text.at(m_cursor);
2771 if (m_cursor > 0 && uc.unicode() >= 0xdc00 && uc.unicode() < 0xe000) {
2772 // second half of a surrogate, check if we have the first half as well,
2773 // if yes delete both at once
2774 uc = m_text.at(m_cursor - 1);
2775 if (uc.unicode() >= 0xd800 && uc.unicode() < 0xdc00) {
2776 internalDelete(true);
2780 internalDelete(true);
2782 finishChange(priorState);
2788 Handles the behavior for the delete key or function.
2789 Removes the current selection if there is a selection, otherwise
2790 removes the character after the cursor position.
2794 void QQuickTextInputPrivate::del()
2796 int priorState = m_undoState;
2797 if (hasSelectedText()) {
2798 removeSelectedText();
2800 int n = m_textLayout.nextCursorPosition(m_cursor) - m_cursor;
2804 finishChange(priorState);
2810 Inserts the given \a newText at the current cursor position.
2811 If there is any selected text it is removed prior to insertion of
2814 void QQuickTextInputPrivate::insert(const QString &newText)
2816 int priorState = m_undoState;
2817 removeSelectedText();
2818 internalInsert(newText);
2819 finishChange(priorState);
2825 Clears the line control text.
2827 void QQuickTextInputPrivate::clear()
2829 int priorState = m_undoState;
2831 m_selend = m_text.length();
2832 removeSelectedText();
2834 finishChange(priorState, /*update*/false, /*edited*/false);
2840 Sets \a length characters from the given \a start position as selected.
2841 The given \a start position must be within the current text for
2842 the line control. If \a length characters cannot be selected, then
2843 the selection will extend to the end of the current text.
2845 void QQuickTextInputPrivate::setSelection(int start, int length)
2847 Q_Q(QQuickTextInput);
2850 if (start < 0 || start > (int)m_text.length()){
2851 qWarning("QQuickTextInputPrivate::setSelection: Invalid start position");
2856 if (start == m_selstart && start + length == m_selend && m_cursor == m_selend)
2859 m_selend = qMin(start + length, (int)m_text.length());
2860 m_cursor = m_selend;
2861 } else if (length < 0){
2862 if (start == m_selend && start + length == m_selstart && m_cursor == m_selstart)
2864 m_selstart = qMax(start + length, 0);
2866 m_cursor = m_selstart;
2867 } else if (m_selstart != m_selend) {
2873 emitCursorPositionChanged();
2876 emit q->selectionChanged();
2877 emitCursorPositionChanged();
2878 q->updateInputMethod(Qt::ImCursorRectangle | Qt::ImAnchorPosition
2879 | Qt::ImCursorPosition | Qt::ImCurrentSelection);
2885 Initializes the line control with a starting text value of \a txt.
2887 void QQuickTextInputPrivate::init(const QString &txt)
2891 updateDisplayText();
2892 m_cursor = m_text.length();
2898 Sets the password echo editing to \a editing. If password echo editing
2899 is true, then the text of the password is displayed even if the echo
2900 mode is set to QLineEdit::PasswordEchoOnEdit. Password echoing editing
2901 does not affect other echo modes.
2903 void QQuickTextInputPrivate::updatePasswordEchoEditing(bool editing)
2905 cancelPasswordEchoTimer();
2906 m_passwordEchoEditing = editing;
2907 updateDisplayText();
2913 Fixes the current text so that it is valid given any set validators.
2915 Returns true if the text was changed. Otherwise returns false.
2917 bool QQuickTextInputPrivate::fixup() // this function assumes that validate currently returns != Acceptable
2919 #ifndef QT_NO_VALIDATOR
2921 QString textCopy = m_text;
2922 int cursorCopy = m_cursor;
2923 m_validator->fixup(textCopy);
2924 if (m_validator->validate(textCopy, cursorCopy) == QValidator::Acceptable) {
2925 if (textCopy != m_text || cursorCopy != m_cursor)
2926 internalSetText(textCopy, cursorCopy);
2937 Moves the cursor to the given position \a pos. If \a mark is true will
2938 adjust the currently selected text.
2940 void QQuickTextInputPrivate::moveCursor(int pos, bool mark)
2942 Q_Q(QQuickTextInput);
2945 if (pos != m_cursor) {
2948 pos = pos > m_cursor ? nextMaskBlank(pos) : prevMaskBlank(pos);
2952 if (m_selend > m_selstart && m_cursor == m_selstart)
2954 else if (m_selend > m_selstart && m_cursor == m_selend)
2955 anchor = m_selstart;
2958 m_selstart = qMin(anchor, pos);
2959 m_selend = qMax(anchor, pos);
2964 if (mark || m_selDirty) {
2966 emit q->selectionChanged();
2968 emitCursorPositionChanged();
2969 q->updateInputMethod();
2975 Applies the given input method event \a event to the text of the line
2978 void QQuickTextInputPrivate::processInputMethodEvent(QInputMethodEvent *event)
2980 Q_Q(QQuickTextInput);
2982 int priorState = -1;
2983 bool isGettingInput = !event->commitString().isEmpty()
2984 || event->preeditString() != preeditAreaText()
2985 || event->replacementLength() > 0;
2986 bool cursorPositionChanged = false;
2987 bool selectionChange = false;
2988 m_preeditDirty = event->preeditString() != preeditAreaText();
2990 if (isGettingInput) {
2991 // If any text is being input, remove selected text.
2992 priorState = m_undoState;
2993 if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit && !m_passwordEchoEditing) {
2994 updatePasswordEchoEditing(true);
2996 m_selend = m_text.length();
2998 removeSelectedText();
3001 int c = m_cursor; // cursor position after insertion of commit string
3002 if (event->replacementStart() <= 0)
3003 c += event->commitString().length() - qMin(-event->replacementStart(), event->replacementLength());
3005 m_cursor += event->replacementStart();
3009 // insert commit string
3010 if (event->replacementLength()) {
3011 m_selstart = m_cursor;
3012 m_selend = m_selstart + event->replacementLength();
3013 m_selend = qMin(m_selend, m_text.length());
3014 removeSelectedText();
3016 if (!event->commitString().isEmpty()) {
3017 internalInsert(event->commitString());
3018 cursorPositionChanged = true;
3021 m_cursor = qBound(0, c, m_text.length());
3023 for (int i = 0; i < event->attributes().size(); ++i) {
3024 const QInputMethodEvent::Attribute &a = event->attributes().at(i);
3025 if (a.type == QInputMethodEvent::Selection) {
3026 m_cursor = qBound(0, a.start + a.length, m_text.length());
3028 m_selstart = qMax(0, qMin(a.start, m_text.length()));
3029 m_selend = m_cursor;
3030 if (m_selend < m_selstart) {
3031 qSwap(m_selstart, m_selend);
3033 selectionChange = true;
3035 m_selstart = m_selend = 0;
3037 cursorPositionChanged = true;
3041 m_textLayout.setPreeditArea(m_cursor, event->preeditString());
3043 const int oldPreeditCursor = m_preeditCursor;
3044 m_preeditCursor = event->preeditString().length();
3045 m_hideCursor = false;
3046 QList<QTextLayout::FormatRange> formats;
3047 for (int i = 0; i < event->attributes().size(); ++i) {
3048 const QInputMethodEvent::Attribute &a = event->attributes().at(i);
3049 if (a.type == QInputMethodEvent::Cursor) {
3050 m_preeditCursor = a.start;
3051 m_hideCursor = !a.length;
3052 } else if (a.type == QInputMethodEvent::TextFormat) {
3053 QTextCharFormat f = qvariant_cast<QTextFormat>(a.value).toCharFormat();
3055 QTextLayout::FormatRange o;
3056 o.start = a.start + m_cursor;
3057 o.length = a.length;
3063 m_textLayout.setAdditionalFormats(formats);
3065 updateDisplayText(/*force*/ true);
3066 if (cursorPositionChanged) {
3067 emitCursorPositionChanged();
3068 } else if (m_preeditCursor != oldPreeditCursor) {
3069 q->updateCursorRectangle();
3072 bool tentativeCommitChanged = m_tentativeCommit != event->tentativeCommitString();
3074 if (tentativeCommitChanged) {
3076 m_tentativeCommit = event->tentativeCommitString();
3079 if (isGettingInput || tentativeCommitChanged)
3080 finishChange(priorState);
3082 if (selectionChange) {
3083 emit q->selectionChanged();
3084 q->updateInputMethod(Qt::ImCursorRectangle | Qt::ImAnchorPosition
3085 | Qt::ImCursorPosition | Qt::ImCurrentSelection);
3092 Sets the selection to cover the word at the given cursor position.
3093 The word boundaries are defined by the behavior of QTextLayout::SkipWords
3096 void QQuickTextInputPrivate::selectWordAtPos(int cursor)
3098 int next = cursor + 1;
3101 int c = m_textLayout.previousCursorPosition(next, QTextLayout::SkipWords);
3102 moveCursor(c, false);
3103 // ## text layout should support end of words.
3104 int end = m_textLayout.nextCursorPosition(c, QTextLayout::SkipWords);
3105 while (end > cursor && m_text[end-1].isSpace())
3107 moveCursor(end, true);
3113 Completes a change to the line control text. If the change is not valid
3114 will undo the line control state back to the given \a validateFromState.
3116 If \a edited is true and the change is valid, will emit textEdited() in
3117 addition to textChanged(). Otherwise only emits textChanged() on a valid
3120 The \a update value is currently unused.
3122 bool QQuickTextInputPrivate::finishChange(int validateFromState, bool update, bool /*edited*/)
3124 Q_Q(QQuickTextInput);
3127 bool inputMethodAttributesChanged = m_textDirty || m_selDirty;
3128 bool alignmentChanged = false;
3132 bool wasValidInput = m_validInput;
3133 bool wasAcceptable = m_acceptableInput;
3134 m_validInput = true;
3135 m_acceptableInput = true;
3136 #ifndef QT_NO_VALIDATOR
3138 QString textCopy = m_text;
3139 int cursorCopy = m_cursor;
3140 QValidator::State state = m_validator->validate(textCopy, cursorCopy);
3141 m_validInput = state != QValidator::Invalid;
3142 m_acceptableInput = state == QValidator::Acceptable;
3144 if (m_text != textCopy) {
3145 internalSetText(textCopy, cursorCopy);
3148 m_cursor = cursorCopy;
3150 if (!m_tentativeCommit.isEmpty()) {
3151 textCopy.insert(m_cursor, m_tentativeCommit);
3152 bool validInput = m_validator->validate(textCopy, cursorCopy) != QValidator::Invalid;
3154 m_tentativeCommit.clear();
3157 m_tentativeCommit.clear();
3161 if (validateFromState >= 0 && wasValidInput && !m_validInput) {
3162 if (m_transactions.count())
3164 internalUndo(validateFromState);
3165 m_history.resize(m_undoState);
3166 if (m_modifiedState > m_undoState)
3167 m_modifiedState = -1;
3168 m_validInput = true;
3169 m_acceptableInput = wasAcceptable;
3170 m_textDirty = false;
3174 m_textDirty = false;
3175 m_preeditDirty = false;
3176 alignmentChanged = determineHorizontalAlignment();
3177 emit q->textChanged();
3180 updateDisplayText(alignmentChanged);
3182 if (m_acceptableInput != wasAcceptable)
3183 emit q->acceptableInputChanged();
3185 if (m_preeditDirty) {
3186 m_preeditDirty = false;
3187 if (determineHorizontalAlignment()) {
3188 alignmentChanged = true;
3195 emit q->selectionChanged();
3198 inputMethodAttributesChanged |= (m_cursor == m_lastCursorPos);
3199 if (inputMethodAttributesChanged)
3200 q->updateInputMethod();
3201 emitUndoRedoChanged();
3203 if (!emitCursorPositionChanged() && alignmentChanged)
3204 q->updateCursorRectangle();
3212 An internal function for setting the text of the line control.
3214 void QQuickTextInputPrivate::internalSetText(const QString &txt, int pos, bool edited)
3216 Q_Q(QQuickTextInput);
3218 QString oldText = m_text;
3220 m_text = maskString(0, txt, true);
3221 m_text += clearString(m_text.length(), m_maxLength - m_text.length());
3223 m_text = txt.isEmpty() ? txt : txt.left(m_maxLength);
3226 m_modifiedState = m_undoState = 0;
3227 m_cursor = (pos < 0 || pos > m_text.length()) ? m_text.length() : pos;
3228 m_textDirty = (oldText != m_text);
3230 bool changed = finishChange(-1, true, edited);
3231 #ifdef QT_NO_ACCESSIBILITY
3235 QAccessible::updateAccessibility(q, 0, QAccessible::TextUpdated);
3243 Adds the given \a command to the undo history
3244 of the line control. Does not apply the command.
3246 void QQuickTextInputPrivate::addCommand(const Command &cmd)
3248 if (m_separator && m_undoState && m_history[m_undoState - 1].type != Separator) {
3249 m_history.resize(m_undoState + 2);
3250 m_history[m_undoState++] = Command(Separator, m_cursor, 0, m_selstart, m_selend);
3252 m_history.resize(m_undoState + 1);
3254 m_separator = false;
3255 m_history[m_undoState++] = cmd;
3261 Inserts the given string \a s into the line
3264 Also adds the appropriate commands into the undo history.
3265 This function does not call finishChange(), and may leave the text
3266 in an invalid state.
3268 void QQuickTextInputPrivate::internalInsert(const QString &s)
3270 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
3271 Q_Q(QQuickTextInput);
3272 if (m_echoMode == QQuickTextInput::Password)
3273 m_passwordEchoTimer.start(qt_passwordEchoDelay, q);
3275 if (hasSelectedText())
3276 addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
3278 QString ms = maskString(m_cursor, s);
3279 for (int i = 0; i < (int) ms.length(); ++i) {
3280 addCommand (Command(DeleteSelection, m_cursor + i, m_text.at(m_cursor + i), -1, -1));
3281 addCommand(Command(Insert, m_cursor + i, ms.at(i), -1, -1));
3283 m_text.replace(m_cursor, ms.length(), ms);
3284 m_cursor += ms.length();
3285 m_cursor = nextMaskBlank(m_cursor);
3288 int remaining = m_maxLength - m_text.length();
3289 if (remaining != 0) {
3290 m_text.insert(m_cursor, s.left(remaining));
3291 for (int i = 0; i < (int) s.left(remaining).length(); ++i)
3292 addCommand(Command(Insert, m_cursor++, s.at(i), -1, -1));
3301 deletes a single character from the current text. If \a wasBackspace,
3302 the character prior to the cursor is removed. Otherwise the character
3303 after the cursor is removed.
3305 Also adds the appropriate commands into the undo history.
3306 This function does not call finishChange(), and may leave the text
3307 in an invalid state.
3309 void QQuickTextInputPrivate::internalDelete(bool wasBackspace)
3311 if (m_cursor < (int) m_text.length()) {
3312 cancelPasswordEchoTimer();
3313 if (hasSelectedText())
3314 addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
3315 addCommand(Command((CommandType)((m_maskData ? 2 : 0) + (wasBackspace ? Remove : Delete)),
3316 m_cursor, m_text.at(m_cursor), -1, -1));
3318 m_text.replace(m_cursor, 1, clearString(m_cursor, 1));
3319 addCommand(Command(Insert, m_cursor, m_text.at(m_cursor), -1, -1));
3321 m_text.remove(m_cursor, 1);
3330 removes the currently selected text from the line control.
3332 Also adds the appropriate commands into the undo history.
3333 This function does not call finishChange(), and may leave the text
3334 in an invalid state.
3336 void QQuickTextInputPrivate::removeSelectedText()
3338 if (m_selstart < m_selend && m_selend <= (int) m_text.length()) {
3339 cancelPasswordEchoTimer();
3342 addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
3343 if (m_selstart <= m_cursor && m_cursor < m_selend) {
3344 // cursor is within the selection. Split up the commands
3345 // to be able to restore the correct cursor position
3346 for (i = m_cursor; i >= m_selstart; --i)
3347 addCommand (Command(DeleteSelection, i, m_text.at(i), -1, 1));
3348 for (i = m_selend - 1; i > m_cursor; --i)
3349 addCommand (Command(DeleteSelection, i - m_cursor + m_selstart - 1, m_text.at(i), -1, -1));
3351 for (i = m_selend-1; i >= m_selstart; --i)
3352 addCommand (Command(RemoveSelection, i, m_text.at(i), -1, -1));
3355 m_text.replace(m_selstart, m_selend - m_selstart, clearString(m_selstart, m_selend - m_selstart));
3356 for (int i = 0; i < m_selend - m_selstart; ++i)
3357 addCommand(Command(Insert, m_selstart + i, m_text.at(m_selstart + i), -1, -1));
3359 m_text.remove(m_selstart, m_selend - m_selstart);
3361 if (m_cursor > m_selstart)
3362 m_cursor -= qMin(m_cursor, m_selend) - m_selstart;
3371 Parses the input mask specified by \a maskFields to generate
3372 the mask data used to handle input masks.
3374 void QQuickTextInputPrivate::parseInputMask(const QString &maskFields)
3376 int delimiter = maskFields.indexOf(QLatin1Char(';'));
3377 if (maskFields.isEmpty() || delimiter == 0) {
3379 delete [] m_maskData;
3381 m_maxLength = 32767;
3382 internalSetText(QString());
3387 if (delimiter == -1) {
3388 m_blank = QLatin1Char(' ');
3389 m_inputMask = maskFields;
3391 m_inputMask = maskFields.left(delimiter);
3392 m_blank = (delimiter + 1 < maskFields.length()) ? maskFields[delimiter + 1] : QLatin1Char(' ');
3395 // calculate m_maxLength / m_maskData length
3398 for (int i=0; i<m_inputMask.length(); i++) {
3399 c = m_inputMask.at(i);
3400 if (i > 0 && m_inputMask.at(i-1) == QLatin1Char('\\')) {
3404 if (c != QLatin1Char('\\') && c != QLatin1Char('!') &&
3405 c != QLatin1Char('<') && c != QLatin1Char('>') &&
3406 c != QLatin1Char('{') && c != QLatin1Char('}') &&
3407 c != QLatin1Char('[') && c != QLatin1Char(']'))
3411 delete [] m_maskData;
3412 m_maskData = new MaskInputData[m_maxLength];
3414 MaskInputData::Casemode m = MaskInputData::NoCaseMode;
3417 bool escape = false;
3419 for (int i = 0; i < m_inputMask.length(); i++) {
3420 c = m_inputMask.at(i);
3423 m_maskData[index].maskChar = c;
3424 m_maskData[index].separator = s;
3425 m_maskData[index].caseMode = m;
3428 } else if (c == QLatin1Char('<')) {
3429 m = MaskInputData::Lower;
3430 } else if (c == QLatin1Char('>')) {
3431 m = MaskInputData::Upper;
3432 } else if (c == QLatin1Char('!')) {
3433 m = MaskInputData::NoCaseMode;
3434 } else if (c != QLatin1Char('{') && c != QLatin1Char('}') && c != QLatin1Char('[') && c != QLatin1Char(']')) {
3435 switch (c.unicode()) {
3461 m_maskData[index].maskChar = c;
3462 m_maskData[index].separator = s;
3463 m_maskData[index].caseMode = m;
3468 internalSetText(m_text);
3475 checks if the key is valid compared to the inputMask
3477 bool QQuickTextInputPrivate::isValidInput(QChar key, QChar mask) const
3479 switch (mask.unicode()) {
3485 if (key.isLetter() || key == m_blank)
3489 if (key.isLetterOrNumber())
3493 if (key.isLetterOrNumber() || key == m_blank)
3501 if (key.isPrint() || key == m_blank)
3509 if (key.isNumber() || key == m_blank)
3513 if (key.isNumber() && key.digitValue() > 0)
3517 if ((key.isNumber() && key.digitValue() > 0) || key == m_blank)
3521 if (key.isNumber() || key == QLatin1Char('+') || key == QLatin1Char('-') || key == m_blank)
3525 if (key == QLatin1Char('0') || key == QLatin1Char('1'))
3529 if (key == QLatin1Char('0') || key == QLatin1Char('1') || key == m_blank)
3533 if (key.isNumber() || (key >= QLatin1Char('a') && key <= QLatin1Char('f')) || (key >= QLatin1Char('A') && key <= QLatin1Char('F')))
3537 if (key.isNumber() || (key >= QLatin1Char('a') && key <= QLatin1Char('f')) || (key >= QLatin1Char('A') && key <= QLatin1Char('F')) || key == m_blank)
3549 Returns true if the given text \a str is valid for any
3550 validator or input mask set for the line control.
3552 Otherwise returns false
3554 QQuickTextInputPrivate::ValidatorState QQuickTextInputPrivate::hasAcceptableInput(const QString &str) const
3556 #ifndef QT_NO_VALIDATOR
3557 QString textCopy = str;
3558 int cursorCopy = m_cursor;
3560 QValidator::State state = m_validator->validate(textCopy, cursorCopy);
3561 if (state != QValidator::Acceptable)
3562 return ValidatorState(state);
3567 return AcceptableInput;
3569 if (str.length() != m_maxLength)
3570 return InvalidInput;
3572 for (int i=0; i < m_maxLength; ++i) {
3573 if (m_maskData[i].separator) {
3574 if (str.at(i) != m_maskData[i].maskChar)
3575 return InvalidInput;
3577 if (!isValidInput(str.at(i), m_maskData[i].maskChar))
3578 return InvalidInput;
3581 return AcceptableInput;
3587 Applies the inputMask on \a str starting from position \a pos in the mask. \a clear
3588 specifies from where characters should be gotten when a separator is met in \a str - true means
3589 that blanks will be used, false that previous input is used.
3590 Calling this when no inputMask is set is undefined.
3592 QString QQuickTextInputPrivate::maskString(uint pos, const QString &str, bool clear) const
3594 if (pos >= (uint)m_maxLength)
3595 return QString::fromLatin1("");
3598 fill = clear ? clearString(0, m_maxLength) : m_text;
3601 QString s = QString::fromLatin1("");
3603 while (i < m_maxLength) {
3604 if (strIndex < str.length()) {
3605 if (m_maskData[i].separator) {
3606 s += m_maskData[i].maskChar;
3607 if (str[(int)strIndex] == m_maskData[i].maskChar)
3611 if (isValidInput(str[(int)strIndex], m_maskData[i].maskChar)) {
3612 switch (m_maskData[i].caseMode) {
3613 case MaskInputData::Upper:
3614 s += str[(int)strIndex].toUpper();
3616 case MaskInputData::Lower:
3617 s += str[(int)strIndex].toLower();
3620 s += str[(int)strIndex];
3624 // search for separator first
3625 int n = findInMask(i, true, true, str[(int)strIndex]);
3627 if (str.length() != 1 || i == 0 || (i > 0 && (!m_maskData[i-1].separator || m_maskData[i-1].maskChar != str[(int)strIndex]))) {
3628 s += fill.mid(i, n-i+1);
3629 i = n + 1; // update i to find + 1
3632 // search for valid m_blank if not
3633 n = findInMask(i, true, false, str[(int)strIndex]);
3635 s += fill.mid(i, n-i);
3636 switch (m_maskData[n].caseMode) {
3637 case MaskInputData::Upper:
3638 s += str[(int)strIndex].toUpper();
3640 case MaskInputData::Lower:
3641 s += str[(int)strIndex].toLower();
3644 s += str[(int)strIndex];
3646 i = n + 1; // updates i to find + 1
3664 Returns a "cleared" string with only separators and blank chars.
3665 Calling this when no inputMask is set is undefined.
3667 QString QQuickTextInputPrivate::clearString(uint pos, uint len) const
3669 if (pos >= (uint)m_maxLength)
3673 int end = qMin((uint)m_maxLength, pos + len);
3674 for (int i = pos; i < end; ++i)
3675 if (m_maskData[i].separator)
3676 s += m_maskData[i].maskChar;
3686 Strips blank parts of the input in a QQuickTextInputPrivate when an inputMask is set,
3687 separators are still included. Typically "127.0__.0__.1__" becomes "127.0.0.1".
3689 QString QQuickTextInputPrivate::stripString(const QString &str) const
3695 int end = qMin(m_maxLength, (int)str.length());
3696 for (int i = 0; i < end; ++i) {
3697 if (m_maskData[i].separator)
3698 s += m_maskData[i].maskChar;
3699 else if (str[i] != m_blank)
3708 searches forward/backward in m_maskData for either a separator or a m_blank
3710 int QQuickTextInputPrivate::findInMask(int pos, bool forward, bool findSeparator, QChar searchChar) const
3712 if (pos >= m_maxLength || pos < 0)
3715 int end = forward ? m_maxLength : -1;
3716 int step = forward ? 1 : -1;
3720 if (findSeparator) {
3721 if (m_maskData[i].separator && m_maskData[i].maskChar == searchChar)
3724 if (!m_maskData[i].separator) {
3725 if (searchChar.isNull())
3727 else if (isValidInput(searchChar, m_maskData[i].maskChar))
3736 void QQuickTextInputPrivate::internalUndo(int until)
3738 if (!isUndoAvailable())
3740 cancelPasswordEchoTimer();
3742 while (m_undoState && m_undoState > until) {
3743 Command& cmd = m_history[--m_undoState];
3746 m_text.remove(cmd.pos, 1);
3750 m_selstart = cmd.selStart;
3751 m_selend = cmd.selEnd;
3755 case RemoveSelection:
3756 m_text.insert(cmd.pos, cmd.uc);
3757 m_cursor = cmd.pos + 1;
3760 case DeleteSelection:
3761 m_text.insert(cmd.pos, cmd.uc);
3767 if (until < 0 && m_undoState) {
3768 Command& next = m_history[m_undoState-1];
3769 if (next.type != cmd.type && next.type < RemoveSelection
3770 && (cmd.type < RemoveSelection || next.type == Separator))
3777 void QQuickTextInputPrivate::internalRedo()
3779 if (!isRedoAvailable())
3782 while (m_undoState < (int)m_history.size()) {
3783 Command& cmd = m_history[m_undoState++];
3786 m_text.insert(cmd.pos, cmd.uc);
3787 m_cursor = cmd.pos + 1;
3790 m_selstart = cmd.selStart;
3791 m_selend = cmd.selEnd;
3796 case RemoveSelection:
3797 case DeleteSelection:
3798 m_text.remove(cmd.pos, 1);
3799 m_selstart = cmd.selStart;
3800 m_selend = cmd.selEnd;
3804 m_selstart = cmd.selStart;
3805 m_selend = cmd.selEnd;
3809 if (m_undoState < (int)m_history.size()) {
3810 Command& next = m_history[m_undoState];
3811 if (next.type != cmd.type && cmd.type < RemoveSelection && next.type != Separator
3812 && (next.type < RemoveSelection || cmd.type == Separator))
3819 void QQuickTextInputPrivate::emitUndoRedoChanged()
3821 Q_Q(QQuickTextInput);
3822 const bool previousUndo = canUndo;
3823 const bool previousRedo = canRedo;
3825 canUndo = isUndoAvailable();
3826 canRedo = isRedoAvailable();
3828 if (previousUndo != canUndo)
3829 emit q->canUndoChanged();
3830 if (previousRedo != canRedo)
3831 emit q->canRedoChanged();
3837 If the current cursor position differs from the last emitted cursor
3838 position, emits cursorPositionChanged().
3840 bool QQuickTextInputPrivate::emitCursorPositionChanged()
3842 Q_Q(QQuickTextInput);
3843 if (m_cursor != m_lastCursorPos) {
3844 m_lastCursorPos = m_cursor;
3846 q->updateCursorRectangle();
3847 emit q->cursorPositionChanged();
3848 // XXX todo - not in 4.8?
3850 resetCursorBlinkTimer();
3853 if (!hasSelectedText()) {
3854 if (lastSelectionStart != m_cursor) {
3855 lastSelectionStart = m_cursor;
3856 emit q->selectionStartChanged();
3858 if (lastSelectionEnd != m_cursor) {
3859 lastSelectionEnd = m_cursor;
3860 emit q->selectionEndChanged();
3864 #ifndef QT_NO_ACCESSIBILITY
3865 QAccessible::updateAccessibility(q, 0, QAccessible::TextCaretMoved);
3874 void QQuickTextInputPrivate::setCursorBlinkPeriod(int msec)
3876 Q_Q(QQuickTextInput);
3877 if (msec == m_blinkPeriod)
3880 q->killTimer(m_blinkTimer);
3883 m_blinkTimer = q->startTimer(msec / 2);
3887 if (m_blinkStatus == 1) {
3888 updateType = UpdatePaintNode;
3892 m_blinkPeriod = msec;
3895 void QQuickTextInputPrivate::resetCursorBlinkTimer()
3897 Q_Q(QQuickTextInput);
3898 if (m_blinkPeriod == 0 || m_blinkTimer == 0)
3900 q->killTimer(m_blinkTimer);
3901 m_blinkTimer = q->startTimer(m_blinkPeriod / 2);
3905 void QQuickTextInput::timerEvent(QTimerEvent *event)
3907 Q_D(QQuickTextInput);
3908 if (event->timerId() == d->m_blinkTimer) {
3909 d->m_blinkStatus = !d->m_blinkStatus;
3910 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
3912 } else if (event->timerId() == d->m_deleteAllTimer) {
3913 killTimer(d->m_deleteAllTimer);
3914 d->m_deleteAllTimer = 0;
3916 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
3917 } else if (event->timerId() == d->m_passwordEchoTimer.timerId()) {
3918 d->m_passwordEchoTimer.stop();
3919 d->updateDisplayText();
3924 void QQuickTextInputPrivate::processKeyEvent(QKeyEvent* event)
3926 Q_Q(QQuickTextInput);
3927 bool inlineCompletionAccepted = false;
3929 if (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return) {
3930 if (hasAcceptableInput(m_text) || fixup()) {
3933 if (inlineCompletionAccepted)
3940 if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit
3941 && !m_passwordEchoEditing
3943 && !event->text().isEmpty()
3944 && !(event->modifiers() & Qt::ControlModifier)) {
3945 // Clear the edit and reset to normal echo mode while editing; the
3946 // echo mode switches back when the edit loses focus
3947 // ### resets current content. dubious code; you can
3948 // navigate with keys up, down, back, and select(?), but if you press
3949 // "left" or "right" it clears?
3950 updatePasswordEchoEditing(true);
3954 bool unknown = false;
3955 bool visual = cursorMoveStyle() == Qt::VisualMoveStyle;
3959 #ifndef QT_NO_SHORTCUT
3960 else if (event == QKeySequence::Undo) {
3964 else if (event == QKeySequence::Redo) {
3968 else if (event == QKeySequence::SelectAll) {
3971 #ifndef QT_NO_CLIPBOARD
3972 else if (event == QKeySequence::Copy) {
3975 else if (event == QKeySequence::Paste) {
3977 QClipboard::Mode mode = QClipboard::Clipboard;
3981 else if (event == QKeySequence::Cut) {
3987 else if (event == QKeySequence::DeleteEndOfLine) {
3989 setSelection(m_cursor, end());
3994 #endif //QT_NO_CLIPBOARD
3995 else if (event == QKeySequence::MoveToStartOfLine || event == QKeySequence::MoveToStartOfBlock) {
3998 else if (event == QKeySequence::MoveToEndOfLine || event == QKeySequence::MoveToEndOfBlock) {
4001 else if (event == QKeySequence::SelectStartOfLine || event == QKeySequence::SelectStartOfBlock) {
4004 else if (event == QKeySequence::SelectEndOfLine || event == QKeySequence::SelectEndOfBlock) {
4007 else if (event == QKeySequence::MoveToNextChar) {
4008 if (hasSelectedText()) {
4009 moveCursor(selectionEnd(), false);
4011 cursorForward(0, visual ? 1 : (layoutDirection() == Qt::LeftToRight ? 1 : -1));
4014 else if (event == QKeySequence::SelectNextChar) {
4015 cursorForward(1, visual ? 1 : (layoutDirection() == Qt::LeftToRight ? 1 : -1));
4017 else if (event == QKeySequence::MoveToPreviousChar) {
4018 if (hasSelectedText()) {
4019 moveCursor(selectionStart(), false);
4021 cursorForward(0, visual ? -1 : (layoutDirection() == Qt::LeftToRight ? -1 : 1));
4024 else if (event == QKeySequence::SelectPreviousChar) {
4025 cursorForward(1, visual ? -1 : (layoutDirection() == Qt::LeftToRight ? -1 : 1));
4027 else if (event == QKeySequence::MoveToNextWord) {
4028 if (m_echoMode == QQuickTextInput::Normal)
4029 layoutDirection() == Qt::LeftToRight ? cursorWordForward(0) : cursorWordBackward(0);
4031 layoutDirection() == Qt::LeftToRight ? end(0) : home(0);
4033 else if (event == QKeySequence::MoveToPreviousWord) {
4034 if (m_echoMode == QQuickTextInput::Normal)
4035 layoutDirection() == Qt::LeftToRight ? cursorWordBackward(0) : cursorWordForward(0);
4036 else if (!m_readOnly) {
4037 layoutDirection() == Qt::LeftToRight ? home(0) : end(0);
4040 else if (event == QKeySequence::SelectNextWord) {
4041 if (m_echoMode == QQuickTextInput::Normal)
4042 layoutDirection() == Qt::LeftToRight ? cursorWordForward(1) : cursorWordBackward(1);
4044 layoutDirection() == Qt::LeftToRight ? end(1) : home(1);
4046 else if (event == QKeySequence::SelectPreviousWord) {
4047 if (m_echoMode == QQuickTextInput::Normal)
4048 layoutDirection() == Qt::LeftToRight ? cursorWordBackward(1) : cursorWordForward(1);
4050 layoutDirection() == Qt::LeftToRight ? home(1) : end(1);
4052 else if (event == QKeySequence::Delete) {
4056 else if (event == QKeySequence::DeleteEndOfWord) {
4058 cursorWordForward(true);
4062 else if (event == QKeySequence::DeleteStartOfWord) {
4064 cursorWordBackward(true);
4068 #endif // QT_NO_SHORTCUT
4070 bool handled = false;
4071 if (event->modifiers() & Qt::ControlModifier) {
4072 switch (event->key()) {
4073 case Qt::Key_Backspace:
4075 cursorWordBackward(true);
4083 } else { // ### check for *no* modifier
4084 switch (event->key()) {
4085 case Qt::Key_Backspace:
4097 if (event->key() == Qt::Key_Direction_L || event->key() == Qt::Key_Direction_R) {
4098 setLayoutDirection((event->key() == Qt::Key_Direction_L) ? Qt::LeftToRight : Qt::RightToLeft);
4102 if (unknown && !m_readOnly) {
4103 QString t = event->text();
4104 if (!t.isEmpty() && t.at(0).isPrint()) {