1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the QtQml module of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #include "qquicktextinput_p.h"
43 #include "qquicktextinput_p_p.h"
44 #include "qquickcanvas.h"
46 #include <private/qqmlglobal_p.h>
48 #include <QtQml/qqmlinfo.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/qinputmethod.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->inputMethod()->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 \li 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 \li Font.MixedCase - This is the normal text rendering option where no capitalization change is applied.
275 \li Font.AllUppercase - This alters the text to be rendered in all uppercase type.
276 \li Font.AllLowercase - This alters the text to be rendered in all lowercase type.
277 \li Font.SmallCaps - This alters the text to be rendered in small-caps type.
278 \li 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;
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 if (d->hasSelectedText()) {
357 d->textLayoutDirty = true;
358 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
361 emit selectionColorChanged();
364 \qmlproperty color QtQuick2::TextInput::selectedTextColor
366 The highlighted text color, used in selections.
368 QColor QQuickTextInput::selectedTextColor() const
370 Q_D(const QQuickTextInput);
371 return d->selectedTextColor;
374 void QQuickTextInput::setSelectedTextColor(const QColor &color)
376 Q_D(QQuickTextInput);
377 if (d->selectedTextColor == color)
380 d->selectedTextColor = color;
381 if (d->hasSelectedText()) {
382 d->textLayoutDirty = true;
383 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
386 emit selectedTextColorChanged();
390 \qmlproperty enumeration QtQuick2::TextInput::horizontalAlignment
391 \qmlproperty enumeration QtQuick2::TextInput::effectiveHorizontalAlignment
392 \qmlproperty enumeration QtQuick2::TextInput::verticalAlignment
394 Sets the horizontal alignment of the text within the TextInput item's
395 width and height. By default, the text alignment follows the natural alignment
396 of the text, for example text that is read from left to right will be aligned to
399 TextInput does not have vertical alignment, as the natural height is
400 exactly the height of the single line of text. If you set the height
401 manually to something larger, TextInput will always be top aligned
402 vertically. You can use anchors to align it however you want within
405 The valid values for \c horizontalAlignment are \c TextInput.AlignLeft, \c TextInput.AlignRight and
406 \c TextInput.AlignHCenter.
408 Valid values for \c verticalAlignment are \c TextInput.AlignTop (default),
409 \c TextInput.AlignBottom \c TextInput.AlignVCenter.
411 When using the attached property LayoutMirroring::enabled to mirror application
412 layouts, the horizontal alignment of text will also be mirrored. However, the property
413 \c horizontalAlignment will remain unchanged. To query the effective horizontal alignment
414 of TextInput, use the read-only property \c effectiveHorizontalAlignment.
416 QQuickTextInput::HAlignment QQuickTextInput::hAlign() const
418 Q_D(const QQuickTextInput);
422 void QQuickTextInput::setHAlign(HAlignment align)
424 Q_D(QQuickTextInput);
425 bool forceAlign = d->hAlignImplicit && d->effectiveLayoutMirror;
426 d->hAlignImplicit = false;
427 if (d->setHAlign(align, forceAlign) && isComponentComplete()) {
429 updateCursorRectangle();
433 void QQuickTextInput::resetHAlign()
435 Q_D(QQuickTextInput);
436 d->hAlignImplicit = true;
437 if (d->determineHorizontalAlignment() && isComponentComplete()) {
439 updateCursorRectangle();
443 QQuickTextInput::HAlignment QQuickTextInput::effectiveHAlign() const
445 Q_D(const QQuickTextInput);
446 QQuickTextInput::HAlignment effectiveAlignment = d->hAlign;
447 if (!d->hAlignImplicit && d->effectiveLayoutMirror) {
449 case QQuickTextInput::AlignLeft:
450 effectiveAlignment = QQuickTextInput::AlignRight;
452 case QQuickTextInput::AlignRight:
453 effectiveAlignment = QQuickTextInput::AlignLeft;
459 return effectiveAlignment;
462 bool QQuickTextInputPrivate::setHAlign(QQuickTextInput::HAlignment alignment, bool forceAlign)
464 Q_Q(QQuickTextInput);
465 if ((hAlign != alignment || forceAlign) && alignment <= QQuickTextInput::AlignHCenter) { // justify not supported
466 QQuickTextInput::HAlignment oldEffectiveHAlign = q->effectiveHAlign();
468 emit q->horizontalAlignmentChanged(alignment);
469 if (oldEffectiveHAlign != q->effectiveHAlign())
470 emit q->effectiveHorizontalAlignmentChanged();
476 bool QQuickTextInputPrivate::determineHorizontalAlignment()
478 if (hAlignImplicit) {
479 // if no explicit alignment has been set, follow the natural layout direction of the text
480 QString text = q_func()->text();
482 text = m_textLayout.preeditAreaText();
483 bool isRightToLeft = text.isEmpty() ? qApp->inputMethod()->inputDirection() == Qt::RightToLeft
484 : text.isRightToLeft();
485 return setHAlign(isRightToLeft ? QQuickTextInput::AlignRight : QQuickTextInput::AlignLeft);
490 QQuickTextInput::VAlignment QQuickTextInput::vAlign() const
492 Q_D(const QQuickTextInput);
496 void QQuickTextInput::setVAlign(QQuickTextInput::VAlignment alignment)
498 Q_D(QQuickTextInput);
499 if (alignment == d->vAlign)
501 d->vAlign = alignment;
502 emit verticalAlignmentChanged(d->vAlign);
503 if (isComponentComplete()) {
504 updateCursorRectangle();
509 \qmlproperty enumeration QtQuick2::TextInput::wrapMode
511 Set this property to wrap the text to the TextInput item's width.
512 The text will only wrap if an explicit width has been set.
515 \li TextInput.NoWrap - no wrapping will be performed. If the text contains insufficient newlines, then implicitWidth will exceed a set width.
516 \li TextInput.WordWrap - wrapping is done on word boundaries only. If a word is too long, implicitWidth will exceed a set width.
517 \li TextInput.WrapAnywhere - wrapping is done at any point on a line, even if it occurs in the middle of a word.
518 \li TextInput.Wrap - if possible, wrapping occurs at a word boundary; otherwise it will occur at the appropriate point on the line, even in the middle of a word.
521 The default is TextInput.NoWrap. If you set a width, consider using TextInput.Wrap.
523 QQuickTextInput::WrapMode QQuickTextInput::wrapMode() const
525 Q_D(const QQuickTextInput);
529 void QQuickTextInput::setWrapMode(WrapMode mode)
531 Q_D(QQuickTextInput);
532 if (mode == d->wrapMode)
536 updateCursorRectangle();
537 emit wrapModeChanged();
540 void QQuickTextInputPrivate::mirrorChange()
542 Q_Q(QQuickTextInput);
543 if (q->isComponentComplete()) {
544 if (!hAlignImplicit && (hAlign == QQuickTextInput::AlignRight || hAlign == QQuickTextInput::AlignLeft)) {
545 q->updateCursorRectangle();
546 emit q->effectiveHorizontalAlignmentChanged();
552 \qmlproperty bool QtQuick2::TextInput::readOnly
554 Sets whether user input can modify the contents of the TextInput.
556 If readOnly is set to true, then user input will not affect the text
557 property. Any bindings or attempts to set the text property will still
560 bool QQuickTextInput::isReadOnly() const
562 Q_D(const QQuickTextInput);
563 return d->m_readOnly;
566 void QQuickTextInput::setReadOnly(bool ro)
568 Q_D(QQuickTextInput);
569 if (d->m_readOnly == ro)
572 setFlag(QQuickItem::ItemAcceptsInputMethod, !ro);
575 d->setCursorPosition(d->end());
576 updateInputMethod(Qt::ImEnabled);
578 d->emitUndoRedoChanged();
579 emit readOnlyChanged(ro);
583 \qmlproperty int QtQuick2::TextInput::maximumLength
584 The maximum permitted length of the text in the TextInput.
586 If the text is too long, it is truncated at the limit.
588 By default, this property contains a value of 32767.
590 int QQuickTextInput::maxLength() const
592 Q_D(const QQuickTextInput);
593 return d->m_maxLength;
596 void QQuickTextInput::setMaxLength(int ml)
598 Q_D(QQuickTextInput);
599 if (d->m_maxLength == ml || d->m_maskData)
603 d->internalSetText(d->m_text, -1, false);
605 emit maximumLengthChanged(ml);
609 \qmlproperty bool QtQuick2::TextInput::cursorVisible
610 Set to true when the TextInput shows a cursor.
612 This property is set and unset when the TextInput gets active focus, so that other
613 properties can be bound to whether the cursor is currently showing. As it
614 gets set and unset automatically, when you set the value yourself you must
615 keep in mind that your value may be overwritten.
617 It can be set directly in script, for example if a KeyProxy might
618 forward keys to it and you desire it to look active when this happens
619 (but without actually giving it active focus).
621 It should not be set directly on the element, like in the below QML,
622 as the specified value will be overridden an lost on focus changes.
631 In the above snippet the cursor will still become visible when the
632 TextInput gains active focus.
634 bool QQuickTextInput::isCursorVisible() const
636 Q_D(const QQuickTextInput);
637 return d->cursorVisible;
640 void QQuickTextInput::setCursorVisible(bool on)
642 Q_D(QQuickTextInput);
643 if (d->cursorVisible == on)
645 d->cursorVisible = on;
646 d->setCursorBlinkPeriod(on ? qApp->styleHints()->cursorFlashTime() : 0);
647 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
649 emit cursorVisibleChanged(d->cursorVisible);
653 \qmlproperty int QtQuick2::TextInput::cursorPosition
654 The position of the cursor in the TextInput.
656 int QQuickTextInput::cursorPosition() const
658 Q_D(const QQuickTextInput);
662 void QQuickTextInput::setCursorPosition(int cp)
664 Q_D(QQuickTextInput);
665 if (cp < 0 || cp > text().length())
671 \qmlproperty rectangle QtQuick2::TextInput::cursorRectangle
673 The rectangle where the standard text cursor is rendered within the text input. Read only.
675 The position and height of a custom cursorDelegate are updated to follow the cursorRectangle
676 automatically when it changes. The width of the delegate is unaffected by changes in the
680 QRectF QQuickTextInput::cursorRectangle() const
682 Q_D(const QQuickTextInput);
685 if (d->m_preeditCursor != -1)
686 c += d->m_preeditCursor;
687 if (d->m_echoMode == NoEcho)
689 QTextLine l = d->m_textLayout.lineForTextPosition(c);
692 return QRectF(l.cursorToX(c) - d->hscroll, l.y() - d->vscroll, 1, l.height());
696 \qmlproperty int QtQuick2::TextInput::selectionStart
698 The cursor position before the first character in the current selection.
700 This property is read-only. To change the selection, use select(start,end),
701 selectAll(), or selectWord().
703 \sa selectionEnd, cursorPosition, selectedText
705 int QQuickTextInput::selectionStart() const
707 Q_D(const QQuickTextInput);
708 return d->lastSelectionStart;
711 \qmlproperty int QtQuick2::TextInput::selectionEnd
713 The cursor position after the last character in the current selection.
715 This property is read-only. To change the selection, use select(start,end),
716 selectAll(), or selectWord().
718 \sa selectionStart, cursorPosition, selectedText
720 int QQuickTextInput::selectionEnd() const
722 Q_D(const QQuickTextInput);
723 return d->lastSelectionEnd;
726 \qmlmethod void QtQuick2::TextInput::select(int start, int end)
728 Causes the text from \a start to \a end to be selected.
730 If either start or end is out of range, the selection is not changed.
732 After calling this, selectionStart will become the lesser
733 and selectionEnd will become the greater (regardless of the order passed
736 \sa selectionStart, selectionEnd
738 void QQuickTextInput::select(int start, int end)
740 Q_D(QQuickTextInput);
741 if (start < 0 || end < 0 || start > d->m_text.length() || end > d->m_text.length())
743 d->setSelection(start, end-start);
747 \qmlproperty string QtQuick2::TextInput::selectedText
749 This read-only property provides the text currently selected in the
752 It is equivalent to the following snippet, but is faster and easier
756 myTextInput.text.toString().substring(myTextInput.selectionStart,
757 myTextInput.selectionEnd);
760 QString QQuickTextInput::selectedText() const
762 Q_D(const QQuickTextInput);
763 return d->selectedText();
767 \qmlproperty bool QtQuick2::TextInput::activeFocusOnPress
769 Whether the TextInput should gain active focus on a mouse press. By default this is
772 bool QQuickTextInput::focusOnPress() const
774 Q_D(const QQuickTextInput);
775 return d->focusOnPress;
778 void QQuickTextInput::setFocusOnPress(bool b)
780 Q_D(QQuickTextInput);
781 if (d->focusOnPress == b)
786 emit activeFocusOnPressChanged(d->focusOnPress);
789 \qmlproperty bool QtQuick2::TextInput::autoScroll
791 Whether the TextInput should scroll when the text is longer than the width. By default this is
794 bool QQuickTextInput::autoScroll() const
796 Q_D(const QQuickTextInput);
797 return d->autoScroll;
800 void QQuickTextInput::setAutoScroll(bool b)
802 Q_D(QQuickTextInput);
803 if (d->autoScroll == b)
807 //We need to repaint so that the scrolling is taking into account.
808 updateCursorRectangle();
809 emit autoScrollChanged(d->autoScroll);
812 #ifndef QT_NO_VALIDATOR
815 \qmlclass IntValidator QIntValidator
816 \inqmlmodule QtQuick 2
817 \ingroup qml-basic-visual-elements
819 This element provides a validator for integer values.
821 If no \l locale is set IntValidator uses the \l {QLocale::setDefault()}{default locale} to
822 interpret the number and will accept locale specific digits, group separators, and positive
823 and negative signs. In addition, IntValidator is always guaranteed to accept a number
824 formatted according to the "C" locale.
828 QQuickIntValidator::QQuickIntValidator(QObject *parent)
829 : QIntValidator(parent)
834 \qmlproperty string QtQuick2::IntValidator::locale
836 This property holds the name of the locale used to interpret the number.
841 QString QQuickIntValidator::localeName() const
843 return locale().name();
846 void QQuickIntValidator::setLocaleName(const QString &name)
848 if (locale().name() != name) {
849 setLocale(QLocale(name));
850 emit localeNameChanged();
854 void QQuickIntValidator::resetLocaleName()
856 QLocale defaultLocale;
857 if (locale() != defaultLocale) {
858 setLocale(defaultLocale);
859 emit localeNameChanged();
864 \qmlproperty int QtQuick2::IntValidator::top
866 This property holds the validator's highest acceptable value.
867 By default, this property's value is derived from the highest signed integer available (typically 2147483647).
870 \qmlproperty int QtQuick2::IntValidator::bottom
872 This property holds the validator's lowest acceptable value.
873 By default, this property's value is derived from the lowest signed integer available (typically -2147483647).
877 \qmlclass DoubleValidator QDoubleValidator
878 \inqmlmodule QtQuick 2
879 \ingroup qml-basic-visual-elements
881 This element provides a validator for non-integer numbers.
883 Input is accepted if it contains a double that is within the valid range
884 and is in the correct format.
886 Input is accepected but invalid if it contains a double that is outside
887 the range or is in the wrong format; e.g. with too many digits after the
888 decimal point or is empty.
890 Input is rejected if it is not a double.
892 Note: If the valid range consists of just positive doubles (e.g. 0.0 to
893 100.0) and input is a negative double then it is rejected. If \l notation
894 is set to DoubleValidator.StandardNotation, and the input contains more
895 digits before the decimal point than a double in the valid range may have,
896 it is also rejected. If \l notation is DoubleValidator.ScientificNotation,
897 and the input is not in the valid range, it is accecpted but invalid. The
898 value may yet become valid by changing the exponent.
901 QQuickDoubleValidator::QQuickDoubleValidator(QObject *parent)
902 : QDoubleValidator(parent)
907 \qmlproperty string QtQuick2::DoubleValidator::locale
909 This property holds the name of the locale used to interpret the number.
914 QString QQuickDoubleValidator::localeName() const
916 return locale().name();
919 void QQuickDoubleValidator::setLocaleName(const QString &name)
921 if (locale().name() != name) {
922 setLocale(QLocale(name));
923 emit localeNameChanged();
927 void QQuickDoubleValidator::resetLocaleName()
929 QLocale defaultLocale;
930 if (locale() != defaultLocale) {
931 setLocale(defaultLocale);
932 emit localeNameChanged();
937 \qmlproperty real QtQuick2::DoubleValidator::top
939 This property holds the validator's maximum acceptable value.
940 By default, this property contains a value of infinity.
943 \qmlproperty real QtQuick2::DoubleValidator::bottom
945 This property holds the validator's minimum acceptable value.
946 By default, this property contains a value of -infinity.
949 \qmlproperty int QtQuick2::DoubleValidator::decimals
951 This property holds the validator's maximum number of digits after the decimal point.
952 By default, this property contains a value of 1000.
955 \qmlproperty enumeration QtQuick2::DoubleValidator::notation
956 This property holds the notation of how a string can describe a number.
958 The possible values for this property are:
961 \li DoubleValidator.StandardNotation
962 \li DoubleValidator.ScientificNotation (default)
965 If this property is set to DoubleValidator.ScientificNotation, the written number may have an exponent part (e.g. 1.5E-2).
969 \qmlclass RegExpValidator QRegExpValidator
970 \inqmlmodule QtQuick 2
971 \ingroup qml-basic-visual-elements
973 This element provides a validator, which counts as valid any string which
974 matches a specified regular expression.
977 \qmlproperty regExp QtQuick2::RegExpValidator::regExp
979 This property holds the regular expression used for validation.
981 Note that this property should be a regular expression in JS syntax, e.g /a/ for the regular expression
984 By default, this property contains a regular expression with the pattern .* that matches any string.
988 \qmlproperty Validator QtQuick2::TextInput::validator
990 Allows you to set a validator on the TextInput. When a validator is set
991 the TextInput will only accept input which leaves the text property in
992 an acceptable or intermediate state. The accepted signal will only be sent
993 if the text is in an acceptable state when enter is pressed.
995 Currently supported validators are IntValidator, DoubleValidator and
996 RegExpValidator. An example of using validators is shown below, which allows
997 input of integers between 11 and 31 into the text input:
1002 validator: IntValidator{bottom: 11; top: 31;}
1007 \sa acceptableInput, inputMask
1010 QValidator* QQuickTextInput::validator() const
1012 Q_D(const QQuickTextInput);
1013 return d->m_validator;
1016 void QQuickTextInput::setValidator(QValidator* v)
1018 Q_D(QQuickTextInput);
1019 if (d->m_validator == v)
1024 if (isComponentComplete())
1027 emit validatorChanged();
1030 #endif // QT_NO_VALIDATOR
1032 void QQuickTextInputPrivate::checkIsValid()
1034 Q_Q(QQuickTextInput);
1036 ValidatorState state = hasAcceptableInput(m_text);
1037 m_validInput = state != InvalidInput;
1038 if (state != AcceptableInput) {
1039 if (m_acceptableInput) {
1040 m_acceptableInput = false;
1041 emit q->acceptableInputChanged();
1043 } else if (!m_acceptableInput) {
1044 m_acceptableInput = true;
1045 emit q->acceptableInputChanged();
1050 \qmlproperty string QtQuick2::TextInput::inputMask
1052 Allows you to set an input mask on the TextInput, restricting the allowable
1053 text inputs. See QLineEdit::inputMask for further details, as the exact
1054 same mask strings are used by TextInput.
1056 \sa acceptableInput, validator
1058 QString QQuickTextInput::inputMask() const
1060 Q_D(const QQuickTextInput);
1061 return d->inputMask();
1064 void QQuickTextInput::setInputMask(const QString &im)
1066 Q_D(QQuickTextInput);
1067 if (d->inputMask() == im)
1070 d->setInputMask(im);
1071 emit inputMaskChanged(d->inputMask());
1075 \qmlproperty bool QtQuick2::TextInput::acceptableInput
1077 This property is always true unless a validator or input mask has been set.
1078 If a validator or input mask has been set, this property will only be true
1079 if the current text is acceptable to the validator or input mask as a final
1080 string (not as an intermediate string).
1082 bool QQuickTextInput::hasAcceptableInput() const
1084 Q_D(const QQuickTextInput);
1085 return d->hasAcceptableInput(d->m_text) == QQuickTextInputPrivate::AcceptableInput;
1089 \qmlsignal QtQuick2::TextInput::onAccepted()
1091 This handler is called when the Return or Enter key is pressed.
1092 Note that if there is a \l validator or \l inputMask set on the text
1093 input, the handler will only be emitted if the input is in an acceptable
1097 Qt::InputMethodHints QQuickTextInputPrivate::effectiveInputMethodHints() const
1099 Qt::InputMethodHints hints = inputMethodHints;
1100 if (m_echoMode == QQuickTextInput::Password || m_echoMode == QQuickTextInput::NoEcho)
1101 hints |= Qt::ImhHiddenText;
1102 else if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit)
1103 hints &= ~Qt::ImhHiddenText;
1104 if (m_echoMode != QQuickTextInput::Normal)
1105 hints |= (Qt::ImhNoAutoUppercase | Qt::ImhNoPredictiveText | Qt::ImhSensitiveData);
1109 \qmlproperty enumeration QtQuick2::TextInput::echoMode
1111 Specifies how the text should be displayed in the TextInput.
1113 \li TextInput.Normal - Displays the text as it is. (Default)
1114 \li TextInput.Password - Displays asterisks instead of characters.
1115 \li TextInput.NoEcho - Displays nothing.
1116 \li TextInput.PasswordEchoOnEdit - Displays characters as they are entered
1117 while editing, otherwise displays asterisks.
1120 QQuickTextInput::EchoMode QQuickTextInput::echoMode() const
1122 Q_D(const QQuickTextInput);
1123 return QQuickTextInput::EchoMode(d->m_echoMode);
1126 void QQuickTextInput::setEchoMode(QQuickTextInput::EchoMode echo)
1128 Q_D(QQuickTextInput);
1129 if (echoMode() == echo)
1131 d->cancelPasswordEchoTimer();
1132 d->m_echoMode = echo;
1133 d->m_passwordEchoEditing = false;
1134 updateInputMethod(Qt::ImHints);
1135 d->updateDisplayText();
1136 updateCursorRectangle();
1138 emit echoModeChanged(echoMode());
1142 \qmlproperty enumeration QtQuick2::TextInput::inputMethodHints
1144 Provides hints to the input method about the expected content of the text input and how it
1147 The value is a bit-wise combination of flags, or Qt.ImhNone if no hints are set.
1149 Flags that alter behaviour are:
1152 \li Qt.ImhHiddenText - Characters should be hidden, as is typically used when entering passwords.
1153 This is automatically set when setting echoMode to \c TextInput.Password.
1154 \li Qt.ImhSensitiveData - Typed text should not be stored by the active input method
1155 in any persistent storage like predictive user dictionary.
1156 \li Qt.ImhNoAutoUppercase - The input method should not try to automatically switch to upper case
1157 when a sentence ends.
1158 \li Qt.ImhPreferNumbers - Numbers are preferred (but not required).
1159 \li Qt.ImhPreferUppercase - Upper case letters are preferred (but not required).
1160 \li Qt.ImhPreferLowercase - Lower case letters are preferred (but not required).
1161 \li Qt.ImhNoPredictiveText - Do not use predictive text (i.e. dictionary lookup) while typing.
1163 \li Qt.ImhDate - The text editor functions as a date field.
1164 \li Qt.ImhTime - The text editor functions as a time field.
1167 Flags that restrict input (exclusive flags) are:
1170 \li Qt.ImhDigitsOnly - Only digits are allowed.
1171 \li Qt.ImhFormattedNumbersOnly - Only number input is allowed. This includes decimal point and minus sign.
1172 \li Qt.ImhUppercaseOnly - Only upper case letter input is allowed.
1173 \li Qt.ImhLowercaseOnly - Only lower case letter input is allowed.
1174 \li Qt.ImhDialableCharactersOnly - Only characters suitable for phone dialing are allowed.
1175 \li Qt.ImhEmailCharactersOnly - Only characters suitable for email addresses are allowed.
1176 \li Qt.ImhUrlCharactersOnly - Only characters suitable for URLs are allowed.
1182 \li Qt.ImhExclusiveInputMask - This mask yields nonzero if any of the exclusive flags are used.
1186 Qt::InputMethodHints QQuickTextInput::inputMethodHints() const
1188 Q_D(const QQuickTextInput);
1189 return d->inputMethodHints;
1192 void QQuickTextInput::setInputMethodHints(Qt::InputMethodHints hints)
1194 Q_D(QQuickTextInput);
1196 if (hints == d->inputMethodHints)
1199 d->inputMethodHints = hints;
1200 updateInputMethod(Qt::ImHints);
1201 emit inputMethodHintsChanged();
1205 \qmlproperty Component QtQuick2::TextInput::cursorDelegate
1206 The delegate for the cursor in the TextInput.
1208 If you set a cursorDelegate for a TextInput, this delegate will be used for
1209 drawing the cursor instead of the standard cursor. An instance of the
1210 delegate will be created and managed by the TextInput when a cursor is
1211 needed, and the x property of delegate instance will be set so as
1212 to be one pixel before the top left of the current character.
1214 Note that the root item of the delegate component must be a QQuickItem or
1215 QQuickItem derived item.
1217 QQmlComponent* QQuickTextInput::cursorDelegate() const
1219 Q_D(const QQuickTextInput);
1220 return d->cursorComponent;
1223 void QQuickTextInput::setCursorDelegate(QQmlComponent* c)
1225 Q_D(QQuickTextInput);
1226 if (d->cursorComponent == c)
1229 d->cursorComponent = c;
1231 //note that the components are owned by something else
1232 delete d->cursorItem;
1235 d->startCreatingCursor();
1238 emit cursorDelegateChanged();
1241 void QQuickTextInputPrivate::startCreatingCursor()
1243 Q_Q(QQuickTextInput);
1244 if (cursorComponent->isReady()) {
1246 } else if (cursorComponent->isLoading()) {
1247 q->connect(cursorComponent, SIGNAL(statusChanged(int)),
1248 q, SLOT(createCursor()));
1250 qmlInfo(q, cursorComponent->errors()) << QQuickTextInput::tr("Could not load cursor delegate");
1254 void QQuickTextInput::createCursor()
1256 Q_D(QQuickTextInput);
1257 if (!isComponentComplete())
1260 if (d->cursorComponent->isError()) {
1261 qmlInfo(this, d->cursorComponent->errors()) << tr("Could not load cursor delegate");
1265 if (!d->cursorComponent->isReady())
1269 delete d->cursorItem;
1270 QQmlContext *creationContext = d->cursorComponent->creationContext();
1271 QObject *object = d->cursorComponent->create(creationContext ? creationContext : qmlContext(this));
1272 d->cursorItem = qobject_cast<QQuickItem*>(object);
1273 if (!d->cursorItem) {
1275 qmlInfo(this, d->cursorComponent->errors()) << tr("Could not instantiate cursor delegate");
1279 QRectF r = cursorRectangle();
1281 QQml_setParent_noEvent(d->cursorItem, this);
1282 d->cursorItem->setParentItem(this);
1283 d->cursorItem->setPos(r.topLeft());
1284 d->cursorItem->setHeight(r.height());
1288 \qmlmethod rect QtQuick2::TextInput::positionToRectangle(int pos)
1290 This function takes a character position and returns the rectangle that the
1291 cursor would occupy, if it was placed at that character position.
1293 This is similar to setting the cursorPosition, and then querying the cursor
1294 rectangle, but the cursorPosition is not changed.
1296 QRectF QQuickTextInput::positionToRectangle(int pos) const
1298 Q_D(const QQuickTextInput);
1299 if (d->m_echoMode == NoEcho)
1301 else if (pos > d->m_cursor)
1302 pos += d->preeditAreaText().length();
1303 QTextLine l = d->m_textLayout.lineForTextPosition(pos);
1305 ? QRectF(l.cursorToX(pos) - d->hscroll, l.y() - d->vscroll, 1, l.height())
1310 \qmlmethod int QtQuick2::TextInput::positionAt(real x, real y, CursorPosition position = CursorBetweenCharacters)
1312 This function returns the character position at
1313 x and y pixels from the top left of the textInput. Position 0 is before the
1314 first character, position 1 is after the first character but before the second,
1315 and so on until position text.length, which is after all characters.
1317 This means that for all x values before the first character this function returns 0,
1318 and for all x values after the last character this function returns text.length. If
1319 the y value is above the text the position will be that of the nearest character on
1320 the first line line and if it is below the text the position of the nearest character
1321 on the last line will be returned.
1323 The cursor position type specifies how the cursor position should be resolved.
1326 \li TextInput.CursorBetweenCharacters - Returns the position between characters that is nearest x.
1327 \li TextInput.CursorOnCharacter - Returns the position before the character that is nearest x.
1331 void QQuickTextInput::positionAt(QQmlV8Function *args) const
1333 Q_D(const QQuickTextInput);
1337 QTextLine::CursorPosition position = QTextLine::CursorBetweenCharacters;
1339 if (args->Length() < 1)
1343 v8::Local<v8::Value> arg = (*args)[i];
1344 x = arg->NumberValue();
1346 if (++i < args->Length()) {
1348 y = arg->NumberValue();
1351 if (++i < args->Length()) {
1353 position = QTextLine::CursorPosition(arg->Int32Value());
1356 int pos = d->positionAt(x, y, position);
1357 const int cursor = d->m_cursor;
1359 const int preeditLength = d->preeditAreaText().length();
1360 pos = pos > cursor + preeditLength
1361 ? pos - preeditLength
1364 args->returnValue(v8::Int32::New(pos));
1367 int QQuickTextInputPrivate::positionAt(qreal x, qreal y, QTextLine::CursorPosition position) const
1371 QTextLine line = m_textLayout.lineAt(0);
1372 for (int i = 1; i < m_textLayout.lineCount(); ++i) {
1373 QTextLine nextLine = m_textLayout.lineAt(i);
1375 if (y < (line.rect().bottom() + nextLine.y()) / 2)
1379 return line.isValid() ? line.xToCursor(x, position) : 0;
1382 void QQuickTextInput::keyPressEvent(QKeyEvent* ev)
1384 Q_D(QQuickTextInput);
1385 // Don't allow MacOSX up/down support, and we don't allow a completer.
1386 bool ignore = (ev->key() == Qt::Key_Up || ev->key() == Qt::Key_Down) && ev->modifiers() == Qt::NoModifier;
1387 if (!ignore && (d->lastSelectionStart == d->lastSelectionEnd) && (ev->key() == Qt::Key_Right || ev->key() == Qt::Key_Left)) {
1388 // Ignore when moving off the end unless there is a selection,
1389 // because then moving will do something (deselect).
1390 int cursorPosition = d->m_cursor;
1391 if (cursorPosition == 0)
1392 ignore = ev->key() == (d->layoutDirection() == Qt::LeftToRight ? Qt::Key_Left : Qt::Key_Right);
1393 if (cursorPosition == text().length())
1394 ignore = ev->key() == (d->layoutDirection() == Qt::LeftToRight ? Qt::Key_Right : Qt::Key_Left);
1399 d->processKeyEvent(ev);
1401 if (!ev->isAccepted())
1402 QQuickImplicitSizeItem::keyPressEvent(ev);
1405 void QQuickTextInput::inputMethodEvent(QInputMethodEvent *ev)
1407 Q_D(QQuickTextInput);
1408 const bool wasComposing = d->preeditAreaText().length() > 0;
1409 if (d->m_readOnly) {
1412 d->processInputMethodEvent(ev);
1414 if (!ev->isAccepted())
1415 QQuickImplicitSizeItem::inputMethodEvent(ev);
1417 if (wasComposing != (d->m_textLayout.preeditAreaText().length() > 0))
1418 emit inputMethodComposingChanged();
1421 void QQuickTextInput::mouseDoubleClickEvent(QMouseEvent *event)
1423 Q_D(QQuickTextInput);
1425 if (d->selectByMouse && event->button() == Qt::LeftButton) {
1427 int cursor = d->positionAt(event->localPos());
1428 d->selectWordAtPos(cursor);
1429 event->setAccepted(true);
1430 if (!d->hasPendingTripleClick()) {
1431 d->tripleClickStartPoint = event->localPos();
1432 d->tripleClickTimer.start();
1435 if (d->sendMouseEventToInputContext(event))
1437 QQuickImplicitSizeItem::mouseDoubleClickEvent(event);
1441 void QQuickTextInput::mousePressEvent(QMouseEvent *event)
1443 Q_D(QQuickTextInput);
1445 d->pressPos = event->localPos();
1447 if (d->focusOnPress) {
1448 bool hadActiveFocus = hasActiveFocus();
1450 // re-open input panel on press if already focused
1451 if (hasActiveFocus() && hadActiveFocus && !d->m_readOnly)
1452 openSoftwareInputPanel();
1454 if (d->selectByMouse) {
1455 setKeepMouseGrab(false);
1456 d->selectPressed = true;
1457 QPointF distanceVector = d->pressPos - d->tripleClickStartPoint;
1458 if (d->hasPendingTripleClick()
1459 && distanceVector.manhattanLength() < qApp->styleHints()->startDragDistance()) {
1460 event->setAccepted(true);
1466 if (d->sendMouseEventToInputContext(event))
1469 bool mark = (event->modifiers() & Qt::ShiftModifier) && d->selectByMouse;
1470 int cursor = d->positionAt(event->localPos());
1471 d->moveCursor(cursor, mark);
1472 event->setAccepted(true);
1475 void QQuickTextInput::mouseMoveEvent(QMouseEvent *event)
1477 Q_D(QQuickTextInput);
1479 if (d->selectPressed) {
1480 if (qAbs(int(event->localPos().x() - d->pressPos.x())) > qApp->styleHints()->startDragDistance())
1481 setKeepMouseGrab(true);
1483 if (d->composeMode()) {
1485 int startPos = d->positionAt(d->pressPos);
1486 int currentPos = d->positionAt(event->localPos());
1487 if (startPos != currentPos)
1488 d->setSelection(startPos, currentPos - startPos);
1490 moveCursorSelection(d->positionAt(event->localPos()), d->mouseSelectionMode);
1492 event->setAccepted(true);
1494 QQuickImplicitSizeItem::mouseMoveEvent(event);
1498 void QQuickTextInput::mouseReleaseEvent(QMouseEvent *event)
1500 Q_D(QQuickTextInput);
1501 if (d->sendMouseEventToInputContext(event))
1503 if (d->selectPressed) {
1504 d->selectPressed = false;
1505 setKeepMouseGrab(false);
1507 #ifndef QT_NO_CLIPBOARD
1508 if (QGuiApplication::clipboard()->supportsSelection()) {
1509 if (event->button() == Qt::LeftButton) {
1510 d->copy(QClipboard::Selection);
1511 } else if (!d->m_readOnly && event->button() == Qt::MidButton) {
1513 d->insert(QGuiApplication::clipboard()->text(QClipboard::Selection));
1517 if (!event->isAccepted())
1518 QQuickImplicitSizeItem::mouseReleaseEvent(event);
1521 bool QQuickTextInputPrivate::sendMouseEventToInputContext(QMouseEvent *event)
1523 #if !defined QT_NO_IM
1524 if (composeMode()) {
1525 int tmp_cursor = positionAt(event->localPos());
1526 int mousePos = tmp_cursor - m_cursor;
1527 if (mousePos >= 0 && mousePos <= m_textLayout.preeditAreaText().length()) {
1528 if (event->type() == QEvent::MouseButtonRelease) {
1529 qApp->inputMethod()->invokeAction(QInputMethod::Click, mousePos);
1542 void QQuickTextInput::mouseUngrabEvent()
1544 Q_D(QQuickTextInput);
1545 d->selectPressed = false;
1546 setKeepMouseGrab(false);
1549 bool QQuickTextInput::event(QEvent* ev)
1551 #ifndef QT_NO_SHORTCUT
1552 Q_D(QQuickTextInput);
1553 if (ev->type() == QEvent::ShortcutOverride) {
1556 QKeyEvent* ke = static_cast<QKeyEvent*>(ev);
1557 if (ke == QKeySequence::Copy
1558 || ke == QKeySequence::Paste
1559 || ke == QKeySequence::Cut
1560 || ke == QKeySequence::Redo
1561 || ke == QKeySequence::Undo
1562 || ke == QKeySequence::MoveToNextWord
1563 || ke == QKeySequence::MoveToPreviousWord
1564 || ke == QKeySequence::MoveToStartOfDocument
1565 || ke == QKeySequence::MoveToEndOfDocument
1566 || ke == QKeySequence::SelectNextWord
1567 || ke == QKeySequence::SelectPreviousWord
1568 || ke == QKeySequence::SelectStartOfLine
1569 || ke == QKeySequence::SelectEndOfLine
1570 || ke == QKeySequence::SelectStartOfBlock
1571 || ke == QKeySequence::SelectEndOfBlock
1572 || ke == QKeySequence::SelectStartOfDocument
1573 || ke == QKeySequence::SelectAll
1574 || ke == QKeySequence::SelectEndOfDocument) {
1576 } else if (ke->modifiers() == Qt::NoModifier || ke->modifiers() == Qt::ShiftModifier
1577 || ke->modifiers() == Qt::KeypadModifier) {
1578 if (ke->key() < Qt::Key_Escape) {
1582 switch (ke->key()) {
1583 case Qt::Key_Delete:
1586 case Qt::Key_Backspace:
1598 return QQuickImplicitSizeItem::event(ev);
1601 void QQuickTextInput::geometryChanged(const QRectF &newGeometry,
1602 const QRectF &oldGeometry)
1604 Q_D(QQuickTextInput);
1605 if (newGeometry.width() != oldGeometry.width())
1607 updateCursorRectangle();
1608 QQuickImplicitSizeItem::geometryChanged(newGeometry, oldGeometry);
1611 void QQuickTextInputPrivate::updateHorizontalScroll()
1613 Q_Q(QQuickTextInput);
1614 QTextLine currentLine = m_textLayout.lineForTextPosition(m_cursor + m_preeditCursor);
1615 const int preeditLength = m_textLayout.preeditAreaText().length();
1616 const qreal width = qMax<qreal>(0, q->width());
1618 qreal widthUsed = 0;
1619 if (currentLine.isValid()) {
1620 cix = currentLine.cursorToX(m_cursor + preeditLength);
1621 const qreal cursorWidth = cix >= 0 ? cix : width - cix;
1622 widthUsed = qMax(currentLine.naturalTextWidth(), cursorWidth);
1624 int previousScroll = hscroll;
1626 if (!autoScroll || widthUsed <= width || m_echoMode == QQuickTextInput::NoEcho) {
1629 Q_ASSERT(currentLine.isValid());
1630 if (cix - hscroll >= width) {
1631 // text doesn't fit, cursor is to the right of br (scroll right)
1632 hscroll = cix - width;
1633 } else if (cix - hscroll < 0 && hscroll < widthUsed) {
1634 // text doesn't fit, cursor is to the left of br (scroll left)
1636 } else if (widthUsed - hscroll < width) {
1637 // text doesn't fit, text document is to the left of br; align
1639 hscroll = widthUsed - width;
1640 } else if (width - hscroll > widthUsed) {
1641 // text doesn't fit, text document is to the right of br; align
1643 hscroll = width - widthUsed;
1645 if (preeditLength > 0) {
1646 // check to ensure long pre-edit text doesn't push the cursor
1648 cix = currentLine.cursorToX(m_cursor + qMax(0, m_preeditCursor - 1));
1653 if (previousScroll != hscroll)
1654 textLayoutDirty = true;
1657 void QQuickTextInputPrivate::updateVerticalScroll()
1659 Q_Q(QQuickTextInput);
1660 const int preeditLength = m_textLayout.preeditAreaText().length();
1661 const qreal height = qMax<qreal>(0, q->height());
1662 qreal heightUsed = boundingRect.height();
1663 qreal previousScroll = vscroll;
1665 if (!autoScroll || heightUsed <= height) {
1666 // text fits in br; use vscroll for alignment
1667 switch (vAlign & ~(Qt::AlignAbsolute|Qt::AlignHorizontal_Mask)) {
1668 case Qt::AlignBottom:
1669 vscroll = heightUsed - height;
1671 case Qt::AlignVCenter:
1672 vscroll = (heightUsed - height) / 2;
1680 QTextLine currentLine = m_textLayout.lineForTextPosition(m_cursor + preeditLength);
1681 QRectF r = currentLine.isValid() ? currentLine.rect() : QRectF();
1682 qreal top = r.top();
1683 int bottom = r.bottom();
1685 if (bottom - vscroll >= height) {
1686 // text doesn't fit, cursor is to the below the br (scroll down)
1687 vscroll = bottom - height;
1688 } else if (top - vscroll < 0 && vscroll < heightUsed) {
1689 // text doesn't fit, cursor is above br (scroll up)
1691 } else if (heightUsed - vscroll < height) {
1692 // text doesn't fit, text document is to the left of br; align
1694 vscroll = heightUsed - height;
1696 if (preeditLength > 0) {
1697 // check to ensure long pre-edit text doesn't push the cursor
1699 currentLine = m_textLayout.lineForTextPosition(m_cursor + qMax(0, m_preeditCursor - 1));
1700 top = currentLine.isValid() ? currentLine.rect().top() : 0;
1705 if (previousScroll != vscroll)
1706 textLayoutDirty = true;
1709 void QQuickTextInput::triggerPreprocess()
1711 Q_D(QQuickTextInput);
1712 if (d->updateType == QQuickTextInputPrivate::UpdateNone)
1713 d->updateType = QQuickTextInputPrivate::UpdateOnlyPreprocess;
1717 QSGNode *QQuickTextInput::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data)
1720 Q_D(QQuickTextInput);
1722 if (d->updateType != QQuickTextInputPrivate::UpdatePaintNode && oldNode != 0) {
1723 // Update done in preprocess() in the nodes
1724 d->updateType = QQuickTextInputPrivate::UpdateNone;
1728 d->updateType = QQuickTextInputPrivate::UpdateNone;
1730 QQuickTextNode *node = static_cast<QQuickTextNode *>(oldNode);
1732 node = new QQuickTextNode(QQuickItemPrivate::get(this)->sceneGraphContext(), this);
1735 if (!d->textLayoutDirty) {
1736 QSGSimpleRectNode *cursorNode = node->cursorNode();
1737 if (cursorNode != 0 && !isReadOnly()) {
1738 cursorNode->setRect(cursorRectangle());
1740 if (!d->cursorVisible || (!d->m_blinkStatus && d->m_blinkPeriod > 0)) {
1747 node->deleteContent();
1748 node->setMatrix(QMatrix4x4());
1750 QPointF offset(0, 0);
1751 if (d->autoScroll && d->m_textLayout.lineCount() > 0) {
1752 QFontMetricsF fm(d->font);
1753 // the y offset is there to keep the baseline constant in case we have script changes in the text.
1754 offset = -QPoint(d->hscroll, d->vscroll + d->m_textLayout.lineAt(0).ascent() - fm.ascent());
1756 offset = -QPoint(d->hscroll, d->vscroll);
1759 if (!d->m_textLayout.text().isEmpty() || !d->m_textLayout.preeditAreaText().isEmpty()) {
1760 node->addTextLayout(offset, &d->m_textLayout, d->color,
1761 QQuickText::Normal, QColor(), QColor(),
1762 d->selectionColor, d->selectedTextColor,
1763 d->selectionStart(),
1764 d->selectionEnd() - 1); // selectionEnd() returns first char after
1768 if (!isReadOnly() && d->cursorItem == 0) {
1769 node->setCursor(cursorRectangle(), d->color);
1770 if (!d->cursorVisible || (!d->m_blinkStatus && d->m_blinkPeriod > 0)) {
1777 d->textLayoutDirty = false;
1783 QVariant QQuickTextInput::inputMethodQuery(Qt::InputMethodQuery property) const
1785 Q_D(const QQuickTextInput);
1788 return QVariant((bool)(flags() & ItemAcceptsInputMethod));
1790 return QVariant((int) d->effectiveInputMethodHints());
1791 case Qt::ImCursorRectangle:
1792 return cursorRectangle();
1795 case Qt::ImCursorPosition:
1796 return QVariant(d->m_cursor);
1797 case Qt::ImSurroundingText:
1798 if (d->m_echoMode == PasswordEchoOnEdit && !d->m_passwordEchoEditing) {
1799 return QVariant(displayText());
1801 return QVariant(d->realText());
1803 case Qt::ImCurrentSelection:
1804 return QVariant(selectedText());
1805 case Qt::ImMaximumTextLength:
1806 return QVariant(maxLength());
1807 case Qt::ImAnchorPosition:
1808 if (d->selectionStart() == d->selectionEnd())
1809 return QVariant(d->m_cursor);
1810 else if (d->selectionStart() == d->m_cursor)
1811 return QVariant(d->selectionEnd());
1813 return QVariant(d->selectionStart());
1820 \qmlmethod void QtQuick2::TextInput::deselect()
1822 Removes active text selection.
1824 void QQuickTextInput::deselect()
1826 Q_D(QQuickTextInput);
1831 \qmlmethod void QtQuick2::TextInput::selectAll()
1833 Causes all text to be selected.
1835 void QQuickTextInput::selectAll()
1837 Q_D(QQuickTextInput);
1838 d->setSelection(0, text().length());
1842 \qmlmethod void QtQuick2::TextInput::isRightToLeft(int start, int end)
1844 Returns true if the natural reading direction of the editor text
1845 found between positions \a start and \a end is right to left.
1847 bool QQuickTextInput::isRightToLeft(int start, int end)
1850 qmlInfo(this) << "isRightToLeft(start, end) called with the end property being smaller than the start.";
1853 return text().mid(start, end - start).isRightToLeft();
1857 #ifndef QT_NO_CLIPBOARD
1859 \qmlmethod QtQuick2::TextInput::cut()
1861 Moves the currently selected text to the system clipboard.
1863 void QQuickTextInput::cut()
1865 Q_D(QQuickTextInput);
1871 \qmlmethod QtQuick2::TextInput::copy()
1873 Copies the currently selected text to the system clipboard.
1875 void QQuickTextInput::copy()
1877 Q_D(QQuickTextInput);
1882 \qmlmethod QtQuick2::TextInput::paste()
1884 Replaces the currently selected text by the contents of the system clipboard.
1886 void QQuickTextInput::paste()
1888 Q_D(QQuickTextInput);
1892 #endif // QT_NO_CLIPBOARD
1895 Undoes the last operation if undo is \l {canUndo}{available}. Deselects any
1896 current selection, and updates the selection start to the current cursor
1900 void QQuickTextInput::undo()
1902 Q_D(QQuickTextInput);
1903 if (!d->m_readOnly) {
1905 d->finishChange(-1, true);
1910 Redoes the last operation if redo is \l {canRedo}{available}.
1913 void QQuickTextInput::redo()
1915 Q_D(QQuickTextInput);
1916 if (!d->m_readOnly) {
1923 \qmlmethod void QtQuick2::TextInput::insert(int position, string text)
1925 Inserts \a text into the TextInput at position.
1928 void QQuickTextInput::insert(int position, const QString &text)
1930 Q_D(QQuickTextInput);
1931 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
1932 if (d->m_echoMode == QQuickTextInput::Password)
1933 d->m_passwordEchoTimer.start(qt_passwordEchoDelay, this);
1936 if (position < 0 || position > d->m_text.length())
1939 const int priorState = d->m_undoState;
1941 QString insertText = text;
1943 if (d->hasSelectedText()) {
1944 d->addCommand(QQuickTextInputPrivate::Command(
1945 QQuickTextInputPrivate::SetSelection, d->m_cursor, 0, d->m_selstart, d->m_selend));
1947 if (d->m_maskData) {
1948 insertText = d->maskString(position, insertText);
1949 for (int i = 0; i < insertText.length(); ++i) {
1950 d->addCommand(QQuickTextInputPrivate::Command(
1951 QQuickTextInputPrivate::DeleteSelection, position + i, d->m_text.at(position + i), -1, -1));
1952 d->addCommand(QQuickTextInputPrivate::Command(
1953 QQuickTextInputPrivate::Insert, position + i, insertText.at(i), -1, -1));
1955 d->m_text.replace(position, insertText.length(), insertText);
1956 if (!insertText.isEmpty())
1957 d->m_textDirty = true;
1958 if (position < d->m_selend && position + insertText.length() > d->m_selstart)
1959 d->m_selDirty = true;
1961 int remaining = d->m_maxLength - d->m_text.length();
1962 if (remaining != 0) {
1963 insertText = insertText.left(remaining);
1964 d->m_text.insert(position, insertText);
1965 for (int i = 0; i < insertText.length(); ++i)
1966 d->addCommand(QQuickTextInputPrivate::Command(
1967 QQuickTextInputPrivate::Insert, position + i, insertText.at(i), -1, -1));
1968 if (d->m_cursor >= position)
1969 d->m_cursor += insertText.length();
1970 if (d->m_selstart >= position)
1971 d->m_selstart += insertText.length();
1972 if (d->m_selend >= position)
1973 d->m_selend += insertText.length();
1974 d->m_textDirty = true;
1975 if (position >= d->m_selstart && position <= d->m_selend)
1976 d->m_selDirty = true;
1980 d->addCommand(QQuickTextInputPrivate::Command(
1981 QQuickTextInputPrivate::SetSelection, d->m_cursor, 0, d->m_selstart, d->m_selend));
1982 d->finishChange(priorState);
1984 if (d->lastSelectionStart != d->lastSelectionEnd) {
1985 if (d->m_selstart != d->lastSelectionStart) {
1986 d->lastSelectionStart = d->m_selstart;
1987 emit selectionStartChanged();
1989 if (d->m_selend != d->lastSelectionEnd) {
1990 d->lastSelectionEnd = d->m_selend;
1991 emit selectionEndChanged();
1997 \qmlmethod string QtQuick2::TextInput::getText(int start, int end)
1999 Removes the section of text that is between the \a start and \a end positions from the TextInput.
2002 void QQuickTextInput::remove(int start, int end)
2004 Q_D(QQuickTextInput);
2006 start = qBound(0, start, d->m_text.length());
2007 end = qBound(0, end, d->m_text.length());
2011 else if (start == end)
2014 if (start < d->m_selend && end > d->m_selstart)
2015 d->m_selDirty = true;
2017 const int priorState = d->m_undoState;
2019 d->addCommand(QQuickTextInputPrivate::Command(
2020 QQuickTextInputPrivate::SetSelection, d->m_cursor, 0, d->m_selstart, d->m_selend));
2022 if (start <= d->m_cursor && d->m_cursor < end) {
2023 // cursor is within the selection. Split up the commands
2024 // to be able to restore the correct cursor position
2025 for (int i = d->m_cursor; i >= start; --i) {
2026 d->addCommand(QQuickTextInputPrivate::Command(
2027 QQuickTextInputPrivate::DeleteSelection, i, d->m_text.at(i), -1, 1));
2029 for (int i = end - 1; i > d->m_cursor; --i) {
2030 d->addCommand(QQuickTextInputPrivate::Command(
2031 QQuickTextInputPrivate::DeleteSelection, i - d->m_cursor + start - 1, d->m_text.at(i), -1, -1));
2034 for (int i = end - 1; i >= start; --i) {
2035 d->addCommand(QQuickTextInputPrivate::Command(
2036 QQuickTextInputPrivate::RemoveSelection, i, d->m_text.at(i), -1, -1));
2039 if (d->m_maskData) {
2040 d->m_text.replace(start, end - start, d->clearString(start, end - start));
2041 for (int i = 0; i < end - start; ++i) {
2042 d->addCommand(QQuickTextInputPrivate::Command(
2043 QQuickTextInputPrivate::Insert, start + i, d->m_text.at(start + i), -1, -1));
2046 d->m_text.remove(start, end - start);
2048 if (d->m_cursor > start)
2049 d->m_cursor -= qMin(d->m_cursor, end) - start;
2050 if (d->m_selstart > start)
2051 d->m_selstart -= qMin(d->m_selstart, end) - start;
2052 if (d->m_selend > end)
2053 d->m_selend -= qMin(d->m_selend, end) - start;
2055 d->addCommand(QQuickTextInputPrivate::Command(
2056 QQuickTextInputPrivate::SetSelection, d->m_cursor, 0, d->m_selstart, d->m_selend));
2058 d->m_textDirty = true;
2059 d->finishChange(priorState);
2061 if (d->lastSelectionStart != d->lastSelectionEnd) {
2062 if (d->m_selstart != d->lastSelectionStart) {
2063 d->lastSelectionStart = d->m_selstart;
2064 emit selectionStartChanged();
2066 if (d->m_selend != d->lastSelectionEnd) {
2067 d->lastSelectionEnd = d->m_selend;
2068 emit selectionEndChanged();
2075 \qmlmethod void QtQuick2::TextInput::selectWord()
2077 Causes the word closest to the current cursor position to be selected.
2079 void QQuickTextInput::selectWord()
2081 Q_D(QQuickTextInput);
2082 d->selectWordAtPos(d->m_cursor);
2086 \qmlproperty bool QtQuick2::TextInput::smooth
2088 This property holds whether the text is smoothly scaled or transformed.
2090 Smooth filtering gives better visual quality, but is slower. If
2091 the item is displayed at its natural size, this property has no visual or
2094 \note Generally scaling artifacts are only visible if the item is stationary on
2095 the screen. A common pattern when animating an item is to disable smooth
2096 filtering at the beginning of the animation and reenable it at the conclusion.
2100 \qmlproperty string QtQuick2::TextInput::passwordCharacter
2102 This is the character displayed when echoMode is set to Password or
2103 PasswordEchoOnEdit. By default it is an asterisk.
2105 If this property is set to a string with more than one character,
2106 the first character is used. If the string is empty, the value
2107 is ignored and the property is not set.
2109 QString QQuickTextInput::passwordCharacter() const
2111 Q_D(const QQuickTextInput);
2112 return QString(d->m_passwordCharacter);
2115 void QQuickTextInput::setPasswordCharacter(const QString &str)
2117 Q_D(QQuickTextInput);
2118 if (str.length() < 1)
2120 d->m_passwordCharacter = str.constData()[0];
2121 if (d->m_echoMode == Password || d->m_echoMode == PasswordEchoOnEdit)
2122 d->updateDisplayText();
2123 emit passwordCharacterChanged();
2127 \qmlproperty string QtQuick2::TextInput::displayText
2129 This is the text displayed in the TextInput.
2131 If \l echoMode is set to TextInput::Normal, this holds the
2132 same value as the TextInput::text property. Otherwise,
2133 this property holds the text visible to the user, while
2134 the \l text property holds the actual entered text.
2136 QString QQuickTextInput::displayText() const
2138 Q_D(const QQuickTextInput);
2139 return d->m_textLayout.text();
2143 \qmlproperty bool QtQuick2::TextInput::selectByMouse
2147 If true, the user can use the mouse to select text in some
2148 platform-specific way. Note that for some platforms this may
2149 not be an appropriate interaction (eg. may conflict with how
2150 the text needs to behave inside a Flickable.
2152 bool QQuickTextInput::selectByMouse() const
2154 Q_D(const QQuickTextInput);
2155 return d->selectByMouse;
2158 void QQuickTextInput::setSelectByMouse(bool on)
2160 Q_D(QQuickTextInput);
2161 if (d->selectByMouse != on) {
2162 d->selectByMouse = on;
2163 emit selectByMouseChanged(on);
2168 \qmlproperty enum QtQuick2::TextInput::mouseSelectionMode
2170 Specifies how text should be selected using a mouse.
2173 \li TextInput.SelectCharacters - The selection is updated with individual characters. (Default)
2174 \li TextInput.SelectWords - The selection is updated with whole words.
2177 This property only applies when \l selectByMouse is true.
2180 QQuickTextInput::SelectionMode QQuickTextInput::mouseSelectionMode() const
2182 Q_D(const QQuickTextInput);
2183 return d->mouseSelectionMode;
2186 void QQuickTextInput::setMouseSelectionMode(SelectionMode mode)
2188 Q_D(QQuickTextInput);
2189 if (d->mouseSelectionMode != mode) {
2190 d->mouseSelectionMode = mode;
2191 emit mouseSelectionModeChanged(mode);
2196 \qmlproperty bool QtQuick2::TextInput::persistentSelection
2198 Whether the TextInput should keep its selection when it loses active focus to another
2199 item in the scene. By default this is set to false;
2202 bool QQuickTextInput::persistentSelection() const
2204 Q_D(const QQuickTextInput);
2205 return d->persistentSelection;
2208 void QQuickTextInput::setPersistentSelection(bool on)
2210 Q_D(QQuickTextInput);
2211 if (d->persistentSelection == on)
2213 d->persistentSelection = on;
2214 emit persistentSelectionChanged();
2218 \qmlproperty bool QtQuick2::TextInput::canPaste
2220 Returns true if the TextInput is writable and the content of the clipboard is
2221 suitable for pasting into the TextInput.
2223 bool QQuickTextInput::canPaste() const
2225 Q_D(const QQuickTextInput);
2226 if (!d->canPasteValid) {
2227 if (const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData())
2228 const_cast<QQuickTextInputPrivate *>(d)->canPaste = !d->m_readOnly && mimeData->hasText();
2229 const_cast<QQuickTextInputPrivate *>(d)->canPasteValid = true;
2235 \qmlproperty bool QtQuick2::TextInput::canUndo
2237 Returns true if the TextInput is writable and there are previous operations
2241 bool QQuickTextInput::canUndo() const
2243 Q_D(const QQuickTextInput);
2248 \qmlproperty bool QtQuick2::TextInput::canRedo
2250 Returns true if the TextInput is writable and there are \l {undo}{undone}
2251 operations that can be redone.
2254 bool QQuickTextInput::canRedo() const
2256 Q_D(const QQuickTextInput);
2261 \qmlproperty real QtQuick2::TextInput::contentWidth
2263 Returns the width of the text, including the width past the width
2264 which is covered due to insufficient wrapping if \l wrapMode is set.
2267 qreal QQuickTextInput::contentWidth() const
2269 Q_D(const QQuickTextInput);
2270 return d->boundingRect.width();
2274 \qmlproperty real QtQuick2::TextInput::contentHeight
2276 Returns the height of the text, including the height past the height
2277 that is covered if the text does not fit within the set height.
2280 qreal QQuickTextInput::contentHeight() const
2282 Q_D(const QQuickTextInput);
2283 return d->boundingRect.height();
2286 void QQuickTextInput::moveCursorSelection(int position)
2288 Q_D(QQuickTextInput);
2289 d->moveCursor(position, true);
2293 \qmlmethod void QtQuick2::TextInput::moveCursorSelection(int position, SelectionMode mode = TextInput.SelectCharacters)
2295 Moves the cursor to \a position and updates the selection according to the optional \a mode
2296 parameter. (To only move the cursor, set the \l cursorPosition property.)
2298 When this method is called it additionally sets either the
2299 selectionStart or the selectionEnd (whichever was at the previous cursor position)
2300 to the specified position. This allows you to easily extend and contract the selected
2303 The selection mode specifies whether the selection is updated on a per character or a per word
2304 basis. If not specified the selection mode will default to TextInput.SelectCharacters.
2307 \li TextInput.SelectCharacters - Sets either the selectionStart or selectionEnd (whichever was at
2308 the previous cursor position) to the specified position.
2309 \li TextInput.SelectWords - Sets the selectionStart and selectionEnd to include all
2310 words between the specified position and the previous cursor position. Words partially in the
2314 For example, take this sequence of calls:
2318 moveCursorSelection(9, TextInput.SelectCharacters)
2319 moveCursorSelection(7, TextInput.SelectCharacters)
2322 This moves the cursor to position 5, extend the selection end from 5 to 9
2323 and then retract the selection end from 9 to 7, leaving the text from position 5 to 7
2324 selected (the 6th and 7th characters).
2326 The same sequence with TextInput.SelectWords will extend the selection start to a word boundary
2327 before or on position 5 and extend the selection end to a word boundary on or past position 9.
2329 void QQuickTextInput::moveCursorSelection(int pos, SelectionMode mode)
2331 Q_D(QQuickTextInput);
2333 if (mode == SelectCharacters) {
2334 d->moveCursor(pos, true);
2335 } else if (pos != d->m_cursor){
2336 const int cursor = d->m_cursor;
2338 if (!d->hasSelectedText())
2339 anchor = d->m_cursor;
2340 else if (d->selectionStart() == d->m_cursor)
2341 anchor = d->selectionEnd();
2343 anchor = d->selectionStart();
2345 if (anchor < pos || (anchor == pos && cursor < pos)) {
2346 const QString text = this->text();
2347 QTextBoundaryFinder finder(QTextBoundaryFinder::Word, text);
2348 finder.setPosition(anchor);
2350 const QTextBoundaryFinder::BoundaryReasons reasons = finder.boundaryReasons();
2351 if (anchor < text.length() && (!(reasons & QTextBoundaryFinder::StartWord)
2352 || ((reasons & QTextBoundaryFinder::EndWord) && anchor > cursor))) {
2353 finder.toPreviousBoundary();
2355 anchor = finder.position() != -1 ? finder.position() : 0;
2357 finder.setPosition(pos);
2358 if (pos > 0 && !finder.boundaryReasons())
2359 finder.toNextBoundary();
2360 const int cursor = finder.position() != -1 ? finder.position() : text.length();
2362 d->setSelection(anchor, cursor - anchor);
2363 } else if (anchor > pos || (anchor == pos && cursor > pos)) {
2364 const QString text = this->text();
2365 QTextBoundaryFinder finder(QTextBoundaryFinder::Word, text);
2366 finder.setPosition(anchor);
2368 const QTextBoundaryFinder::BoundaryReasons reasons = finder.boundaryReasons();
2369 if (anchor > 0 && (!(reasons & QTextBoundaryFinder::EndWord)
2370 || ((reasons & QTextBoundaryFinder::StartWord) && anchor < cursor))) {
2371 finder.toNextBoundary();
2374 anchor = finder.position() != -1 ? finder.position() : text.length();
2376 finder.setPosition(pos);
2377 if (pos < text.length() && !finder.boundaryReasons())
2378 finder.toPreviousBoundary();
2379 const int cursor = finder.position() != -1 ? finder.position() : 0;
2381 d->setSelection(anchor, cursor - anchor);
2387 \qmlmethod void QtQuick2::TextInput::openSoftwareInputPanel()
2389 Opens software input panels like virtual keyboards for typing, useful for
2390 customizing when you want the input keyboard to be shown and hidden in
2393 By default the opening of input panels follows the platform style. Input panels are
2394 always closed if no editor has active focus.
2396 You can disable the automatic behavior by setting the property \c activeFocusOnPress to false
2397 and use functions openSoftwareInputPanel() and closeSoftwareInputPanel() to implement
2398 the behavior you want.
2400 Only relevant on platforms, which provide virtual keyboards.
2406 text: "Hello world!"
2407 activeFocusOnPress: false
2409 anchors.fill: parent
2411 if (!textInput.activeFocus) {
2412 textInput.forceActiveFocus()
2413 textInput.openSoftwareInputPanel();
2415 textInput.focus = false;
2418 onPressAndHold: textInput.closeSoftwareInputPanel();
2423 void QQuickTextInput::openSoftwareInputPanel()
2426 qGuiApp->inputMethod()->show();
2430 \qmlmethod void QtQuick2::TextInput::closeSoftwareInputPanel()
2432 Closes a software input panel like a virtual keyboard shown on the screen, useful
2433 for customizing when you want the input keyboard to be shown and hidden in
2436 By default the opening of input panels follows the platform style. Input panels are
2437 always closed if no editor has active focus.
2439 You can disable the automatic behavior by setting the property \c activeFocusOnPress to false
2440 and use functions openSoftwareInputPanel() and closeSoftwareInputPanel() to implement
2441 the behavior you want.
2443 Only relevant on platforms, which provide virtual keyboards.
2449 text: "Hello world!"
2450 activeFocusOnPress: false
2452 anchors.fill: parent
2454 if (!textInput.activeFocus) {
2455 textInput.forceActiveFocus();
2456 textInput.openSoftwareInputPanel();
2458 textInput.focus = false;
2461 onPressAndHold: textInput.closeSoftwareInputPanel();
2466 void QQuickTextInput::closeSoftwareInputPanel()
2469 qGuiApp->inputMethod()->hide();
2472 void QQuickTextInput::focusInEvent(QFocusEvent *event)
2474 Q_D(const QQuickTextInput);
2475 if (d->focusOnPress && !d->m_readOnly)
2476 openSoftwareInputPanel();
2477 QQuickImplicitSizeItem::focusInEvent(event);
2480 void QQuickTextInput::itemChange(ItemChange change, const ItemChangeData &value)
2482 Q_D(QQuickTextInput);
2483 if (change == ItemActiveFocusHasChanged) {
2484 bool hasFocus = value.boolValue;
2485 setCursorVisible(hasFocus); // ### refactor: && d->canvas && d->canvas->hasFocus()
2486 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
2487 if (!hasFocus && (d->m_passwordEchoEditing || d->m_passwordEchoTimer.isActive())) {
2489 if (!hasFocus && d->m_passwordEchoEditing) {
2491 d->updatePasswordEchoEditing(false);//QQuickTextInputPrivate sets it on key events, but doesn't deal with focus events
2496 if (!d->persistentSelection)
2498 disconnect(qApp->inputMethod(), SIGNAL(inputDirectionChanged(Qt::LayoutDirection)),
2499 this, SLOT(q_updateAlignment()));
2501 q_updateAlignment();
2502 connect(qApp->inputMethod(), SIGNAL(inputDirectionChanged(Qt::LayoutDirection)),
2503 this, SLOT(q_updateAlignment()));
2506 QQuickItem::itemChange(change, value);
2510 \qmlproperty bool QtQuick2::TextInput::inputMethodComposing
2513 This property holds whether the TextInput has partial text input from an
2516 While it is composing an input method may rely on mouse or key events from
2517 the TextInput to edit or commit the partial text. This property can be
2518 used to determine when to disable events handlers that may interfere with
2519 the correct operation of an input method.
2521 bool QQuickTextInput::isInputMethodComposing() const
2523 Q_D(const QQuickTextInput);
2524 return d->preeditAreaText().length() > 0;
2527 void QQuickTextInputPrivate::init()
2529 Q_Q(QQuickTextInput);
2530 q->setSmooth(smooth);
2531 q->setAcceptedMouseButtons(Qt::LeftButton);
2532 q->setFlag(QQuickItem::ItemAcceptsInputMethod);
2533 q->setFlag(QQuickItem::ItemHasContents);
2534 #ifndef QT_NO_CLIPBOARD
2535 q->connect(QGuiApplication::clipboard(), SIGNAL(dataChanged()),
2536 q, SLOT(q_canPasteChanged()));
2537 #endif // QT_NO_CLIPBOARD
2539 lastSelectionStart = 0;
2540 lastSelectionEnd = 0;
2541 determineHorizontalAlignment();
2543 if (!qmlDisableDistanceField()) {
2544 QTextOption option = m_textLayout.textOption();
2545 option.setUseDesignMetrics(true);
2546 m_textLayout.setTextOption(option);
2550 void QQuickTextInput::updateCursorRectangle()
2552 Q_D(QQuickTextInput);
2553 if (!isComponentComplete())
2556 d->updateHorizontalScroll();
2557 d->updateVerticalScroll();
2558 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
2560 emit cursorRectangleChanged();
2561 if (d->cursorItem) {
2562 QRectF r = cursorRectangle();
2563 d->cursorItem->setPos(r.topLeft());
2564 d->cursorItem->setHeight(r.height());
2566 updateInputMethod(Qt::ImCursorRectangle);
2569 void QQuickTextInput::selectionChanged()
2571 Q_D(QQuickTextInput);
2572 d->textLayoutDirty = true; //TODO: Only update rect in selection
2573 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
2575 emit selectedTextChanged();
2577 if (d->lastSelectionStart != d->selectionStart()) {
2578 d->lastSelectionStart = d->selectionStart();
2579 if (d->lastSelectionStart == -1)
2580 d->lastSelectionStart = d->m_cursor;
2581 emit selectionStartChanged();
2583 if (d->lastSelectionEnd != d->selectionEnd()) {
2584 d->lastSelectionEnd = d->selectionEnd();
2585 if (d->lastSelectionEnd == -1)
2586 d->lastSelectionEnd = d->m_cursor;
2587 emit selectionEndChanged();
2591 void QQuickTextInputPrivate::showCursor()
2593 if (textNode != 0 && textNode->cursorNode() != 0)
2594 textNode->cursorNode()->setColor(color);
2597 void QQuickTextInputPrivate::hideCursor()
2599 if (textNode != 0 && textNode->cursorNode() != 0)
2600 textNode->cursorNode()->setColor(QColor(0, 0, 0, 0));
2603 QRectF QQuickTextInput::boundingRect() const
2605 Q_D(const QQuickTextInput);
2607 int cursorWidth = d->cursorItem ? d->cursorItem->width() : 1;
2609 // Could include font max left/right bearings to either side of rectangle.
2610 QRectF r = QQuickImplicitSizeItem::boundingRect();
2611 r.setRight(r.right() + cursorWidth);
2615 void QQuickTextInput::q_canPasteChanged()
2617 Q_D(QQuickTextInput);
2618 bool old = d->canPaste;
2619 #ifndef QT_NO_CLIPBOARD
2620 if (const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData())
2621 d->canPaste = !d->m_readOnly && mimeData->hasText();
2623 d->canPaste = false;
2626 bool changed = d->canPaste != old || !d->canPasteValid;
2627 d->canPasteValid = true;
2629 emit canPasteChanged();
2633 void QQuickTextInput::q_updateAlignment()
2635 Q_D(QQuickTextInput);
2636 if (d->determineHorizontalAlignment()) {
2638 updateCursorRectangle();
2642 // ### these should come from QStyleHints
2643 const int textCursorWidth = 1;
2644 const bool fullWidthSelection = true;
2649 Updates the display text based of the current edit text
2650 If the text has changed will emit displayTextChanged()
2652 void QQuickTextInputPrivate::updateDisplayText(bool forceUpdate)
2654 QString orig = m_textLayout.text();
2656 if (m_echoMode == QQuickTextInput::NoEcho)
2657 str = QString::fromLatin1("");
2661 if (m_echoMode == QQuickTextInput::Password) {
2662 str.fill(m_passwordCharacter);
2663 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
2664 if (m_passwordEchoTimer.isActive() && m_cursor > 0 && m_cursor <= m_text.length()) {
2665 int cursor = m_cursor - 1;
2666 QChar uc = m_text.at(cursor);
2668 if (cursor > 0 && uc.unicode() >= 0xdc00 && uc.unicode() < 0xe000) {
2669 // second half of a surrogate, check if we have the first half as well,
2670 // if yes restore both at once
2671 uc = m_text.at(cursor - 1);
2672 if (uc.unicode() >= 0xd800 && uc.unicode() < 0xdc00)
2673 str[cursor - 1] = uc;
2677 } else if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit && !m_passwordEchoEditing) {
2678 str.fill(m_passwordCharacter);
2681 // replace certain non-printable characters with spaces (to avoid
2682 // drawing boxes when using fonts that don't have glyphs for such
2684 QChar* uc = str.data();
2685 for (int i = 0; i < (int)str.length(); ++i) {
2686 if ((uc[i] < 0x20 && uc[i] != 0x09)
2687 || uc[i] == QChar::LineSeparator
2688 || uc[i] == QChar::ParagraphSeparator
2689 || uc[i] == QChar::ObjectReplacementCharacter)
2690 uc[i] = QChar(0x0020);
2693 if (str != orig || forceUpdate) {
2694 m_textLayout.setText(str);
2695 updateLayout(); // polish?
2696 emit q_func()->displayTextChanged();
2700 void QQuickTextInputPrivate::updateLayout()
2702 Q_Q(QQuickTextInput);
2704 if (!q->isComponentComplete())
2707 const QRectF previousRect = boundingRect;
2709 QTextOption option = m_textLayout.textOption();
2710 option.setTextDirection(layoutDirection());
2711 option.setWrapMode(QTextOption::WrapMode(wrapMode));
2712 option.setAlignment(Qt::Alignment(q->effectiveHAlign()));
2713 m_textLayout.setTextOption(option);
2714 m_textLayout.setFont(font);
2716 boundingRect = QRectF();
2717 m_textLayout.beginLayout();
2718 QTextLine line = m_textLayout.createLine();
2719 qreal lineWidth = q->widthValid() ? q->width() : INT_MAX;
2722 line.setLineWidth(lineWidth);
2723 line.setPosition(QPointF(line.position().x(), height));
2724 boundingRect = boundingRect.united(line.naturalTextRect());
2726 height += line.height();
2727 line = m_textLayout.createLine();
2728 } while (line.isValid());
2729 m_textLayout.endLayout();
2731 option.setWrapMode(QTextOption::NoWrap);
2732 m_textLayout.setTextOption(option);
2734 textLayoutDirty = true;
2736 updateType = UpdatePaintNode;
2738 q->setImplicitSize(boundingRect.width(), boundingRect.height());
2740 if (previousRect != boundingRect)
2741 emit q->contentSizeChanged();
2744 #ifndef QT_NO_CLIPBOARD
2748 Copies the currently selected text into the clipboard using the given
2751 \note If the echo mode is set to a mode other than Normal then copy
2752 will not work. This is to prevent using copy as a method of bypassing
2753 password features of the line control.
2755 void QQuickTextInputPrivate::copy(QClipboard::Mode mode) const
2757 QString t = selectedText();
2758 if (!t.isEmpty() && m_echoMode == QQuickTextInput::Normal) {
2759 QGuiApplication::clipboard()->setText(t, mode);
2766 Inserts the text stored in the application clipboard into the line
2771 void QQuickTextInputPrivate::paste(QClipboard::Mode clipboardMode)
2773 QString clip = QGuiApplication::clipboard()->text(clipboardMode);
2774 if (!clip.isEmpty() || hasSelectedText()) {
2775 separate(); //make it a separate undo/redo command
2781 #endif // !QT_NO_CLIPBOARD
2786 Exits preedit mode and commits parts marked as tentative commit
2788 void QQuickTextInputPrivate::commitPreedit()
2793 qApp->inputMethod()->reset();
2795 if (!m_tentativeCommit.isEmpty()) {
2796 internalInsert(m_tentativeCommit);
2797 m_tentativeCommit.clear();
2798 finishChange(-1, true/*not used, not documented*/, false);
2801 m_preeditCursor = 0;
2802 m_textLayout.setPreeditArea(-1, QString());
2803 m_textLayout.clearAdditionalFormats();
2810 Handles the behavior for the backspace key or function.
2811 Removes the current selection if there is a selection, otherwise
2812 removes the character prior to the cursor position.
2816 void QQuickTextInputPrivate::backspace()
2818 int priorState = m_undoState;
2819 if (hasSelectedText()) {
2820 removeSelectedText();
2821 } else if (m_cursor) {
2824 m_cursor = prevMaskBlank(m_cursor);
2825 QChar uc = m_text.at(m_cursor);
2826 if (m_cursor > 0 && uc.unicode() >= 0xdc00 && uc.unicode() < 0xe000) {
2827 // second half of a surrogate, check if we have the first half as well,
2828 // if yes delete both at once
2829 uc = m_text.at(m_cursor - 1);
2830 if (uc.unicode() >= 0xd800 && uc.unicode() < 0xdc00) {
2831 internalDelete(true);
2835 internalDelete(true);
2837 finishChange(priorState);
2843 Handles the behavior for the delete key or function.
2844 Removes the current selection if there is a selection, otherwise
2845 removes the character after the cursor position.
2849 void QQuickTextInputPrivate::del()
2851 int priorState = m_undoState;
2852 if (hasSelectedText()) {
2853 removeSelectedText();
2855 int n = m_textLayout.nextCursorPosition(m_cursor) - m_cursor;
2859 finishChange(priorState);
2865 Inserts the given \a newText at the current cursor position.
2866 If there is any selected text it is removed prior to insertion of
2869 void QQuickTextInputPrivate::insert(const QString &newText)
2871 int priorState = m_undoState;
2872 removeSelectedText();
2873 internalInsert(newText);
2874 finishChange(priorState);
2880 Clears the line control text.
2882 void QQuickTextInputPrivate::clear()
2884 int priorState = m_undoState;
2886 m_selend = m_text.length();
2887 removeSelectedText();
2889 finishChange(priorState, /*update*/false, /*edited*/false);
2895 Sets \a length characters from the given \a start position as selected.
2896 The given \a start position must be within the current text for
2897 the line control. If \a length characters cannot be selected, then
2898 the selection will extend to the end of the current text.
2900 void QQuickTextInputPrivate::setSelection(int start, int length)
2902 Q_Q(QQuickTextInput);
2905 if (start < 0 || start > (int)m_text.length()){
2906 qWarning("QQuickTextInputPrivate::setSelection: Invalid start position");
2911 if (start == m_selstart && start + length == m_selend && m_cursor == m_selend)
2914 m_selend = qMin(start + length, (int)m_text.length());
2915 m_cursor = m_selend;
2916 } else if (length < 0){
2917 if (start == m_selend && start + length == m_selstart && m_cursor == m_selstart)
2919 m_selstart = qMax(start + length, 0);
2921 m_cursor = m_selstart;
2922 } else if (m_selstart != m_selend) {
2928 emitCursorPositionChanged();
2931 emit q->selectionChanged();
2932 emitCursorPositionChanged();
2933 q->updateInputMethod(Qt::ImCursorRectangle | Qt::ImAnchorPosition
2934 | Qt::ImCursorPosition | Qt::ImCurrentSelection);
2940 Sets the password echo editing to \a editing. If password echo editing
2941 is true, then the text of the password is displayed even if the echo
2942 mode is set to QLineEdit::PasswordEchoOnEdit. Password echoing editing
2943 does not affect other echo modes.
2945 void QQuickTextInputPrivate::updatePasswordEchoEditing(bool editing)
2947 cancelPasswordEchoTimer();
2948 m_passwordEchoEditing = editing;
2949 updateDisplayText();
2955 Fixes the current text so that it is valid given any set validators.
2957 Returns true if the text was changed. Otherwise returns false.
2959 bool QQuickTextInputPrivate::fixup() // this function assumes that validate currently returns != Acceptable
2961 #ifndef QT_NO_VALIDATOR
2963 QString textCopy = m_text;
2964 int cursorCopy = m_cursor;
2965 m_validator->fixup(textCopy);
2966 if (m_validator->validate(textCopy, cursorCopy) == QValidator::Acceptable) {
2967 if (textCopy != m_text || cursorCopy != m_cursor)
2968 internalSetText(textCopy, cursorCopy);
2979 Moves the cursor to the given position \a pos. If \a mark is true will
2980 adjust the currently selected text.
2982 void QQuickTextInputPrivate::moveCursor(int pos, bool mark)
2984 Q_Q(QQuickTextInput);
2987 if (pos != m_cursor) {
2990 pos = pos > m_cursor ? nextMaskBlank(pos) : prevMaskBlank(pos);
2994 if (m_selend > m_selstart && m_cursor == m_selstart)
2996 else if (m_selend > m_selstart && m_cursor == m_selend)
2997 anchor = m_selstart;
3000 m_selstart = qMin(anchor, pos);
3001 m_selend = qMax(anchor, pos);
3006 if (mark || m_selDirty) {
3008 emit q->selectionChanged();
3010 emitCursorPositionChanged();
3011 q->updateInputMethod();
3017 Applies the given input method event \a event to the text of the line
3020 void QQuickTextInputPrivate::processInputMethodEvent(QInputMethodEvent *event)
3022 Q_Q(QQuickTextInput);
3024 int priorState = -1;
3025 bool isGettingInput = !event->commitString().isEmpty()
3026 || event->preeditString() != preeditAreaText()
3027 || event->replacementLength() > 0;
3028 bool cursorPositionChanged = false;
3029 bool selectionChange = false;
3030 m_preeditDirty = event->preeditString() != preeditAreaText();
3032 if (isGettingInput) {
3033 // If any text is being input, remove selected text.
3034 priorState = m_undoState;
3035 if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit && !m_passwordEchoEditing) {
3036 updatePasswordEchoEditing(true);
3038 m_selend = m_text.length();
3040 removeSelectedText();
3043 int c = m_cursor; // cursor position after insertion of commit string
3044 if (event->replacementStart() <= 0)
3045 c += event->commitString().length() - qMin(-event->replacementStart(), event->replacementLength());
3047 m_cursor += event->replacementStart();
3051 // insert commit string
3052 if (event->replacementLength()) {
3053 m_selstart = m_cursor;
3054 m_selend = m_selstart + event->replacementLength();
3055 m_selend = qMin(m_selend, m_text.length());
3056 removeSelectedText();
3058 if (!event->commitString().isEmpty()) {
3059 internalInsert(event->commitString());
3060 cursorPositionChanged = true;
3063 m_cursor = qBound(0, c, m_text.length());
3065 for (int i = 0; i < event->attributes().size(); ++i) {
3066 const QInputMethodEvent::Attribute &a = event->attributes().at(i);
3067 if (a.type == QInputMethodEvent::Selection) {
3068 m_cursor = qBound(0, a.start + a.length, m_text.length());
3070 m_selstart = qMax(0, qMin(a.start, m_text.length()));
3071 m_selend = m_cursor;
3072 if (m_selend < m_selstart) {
3073 qSwap(m_selstart, m_selend);
3075 selectionChange = true;
3077 m_selstart = m_selend = 0;
3079 cursorPositionChanged = true;
3083 m_textLayout.setPreeditArea(m_cursor, event->preeditString());
3085 const int oldPreeditCursor = m_preeditCursor;
3086 m_preeditCursor = event->preeditString().length();
3087 m_hideCursor = false;
3088 QList<QTextLayout::FormatRange> formats;
3089 for (int i = 0; i < event->attributes().size(); ++i) {
3090 const QInputMethodEvent::Attribute &a = event->attributes().at(i);
3091 if (a.type == QInputMethodEvent::Cursor) {
3092 m_preeditCursor = a.start;
3093 m_hideCursor = !a.length;
3094 } else if (a.type == QInputMethodEvent::TextFormat) {
3095 QTextCharFormat f = qvariant_cast<QTextFormat>(a.value).toCharFormat();
3097 QTextLayout::FormatRange o;
3098 o.start = a.start + m_cursor;
3099 o.length = a.length;
3105 m_textLayout.setAdditionalFormats(formats);
3107 updateDisplayText(/*force*/ true);
3108 if (cursorPositionChanged) {
3109 emitCursorPositionChanged();
3110 } else if (m_preeditCursor != oldPreeditCursor) {
3111 q->updateCursorRectangle();
3114 bool tentativeCommitChanged = m_tentativeCommit != event->tentativeCommitString();
3116 if (tentativeCommitChanged) {
3118 m_tentativeCommit = event->tentativeCommitString();
3121 if (isGettingInput || tentativeCommitChanged)
3122 finishChange(priorState);
3124 if (selectionChange) {
3125 emit q->selectionChanged();
3126 q->updateInputMethod(Qt::ImCursorRectangle | Qt::ImAnchorPosition
3127 | Qt::ImCursorPosition | Qt::ImCurrentSelection);
3134 Sets the selection to cover the word at the given cursor position.
3135 The word boundaries are defined by the behavior of QTextLayout::SkipWords
3138 void QQuickTextInputPrivate::selectWordAtPos(int cursor)
3140 int next = cursor + 1;
3143 int c = m_textLayout.previousCursorPosition(next, QTextLayout::SkipWords);
3144 moveCursor(c, false);
3145 // ## text layout should support end of words.
3146 int end = m_textLayout.nextCursorPosition(c, QTextLayout::SkipWords);
3147 while (end > cursor && m_text[end-1].isSpace())
3149 moveCursor(end, true);
3155 Completes a change to the line control text. If the change is not valid
3156 will undo the line control state back to the given \a validateFromState.
3158 If \a edited is true and the change is valid, will emit textEdited() in
3159 addition to textChanged(). Otherwise only emits textChanged() on a valid
3162 The \a update value is currently unused.
3164 bool QQuickTextInputPrivate::finishChange(int validateFromState, bool update, bool /*edited*/)
3166 Q_Q(QQuickTextInput);
3169 bool inputMethodAttributesChanged = m_textDirty || m_selDirty;
3170 bool alignmentChanged = false;
3174 bool wasValidInput = m_validInput;
3175 bool wasAcceptable = m_acceptableInput;
3176 m_validInput = true;
3177 m_acceptableInput = true;
3178 #ifndef QT_NO_VALIDATOR
3180 QString textCopy = m_text;
3181 int cursorCopy = m_cursor;
3182 QValidator::State state = m_validator->validate(textCopy, cursorCopy);
3183 m_validInput = state != QValidator::Invalid;
3184 m_acceptableInput = state == QValidator::Acceptable;
3186 if (m_text != textCopy) {
3187 internalSetText(textCopy, cursorCopy);
3190 m_cursor = cursorCopy;
3192 if (!m_tentativeCommit.isEmpty()) {
3193 textCopy.insert(m_cursor, m_tentativeCommit);
3194 bool validInput = m_validator->validate(textCopy, cursorCopy) != QValidator::Invalid;
3196 m_tentativeCommit.clear();
3199 m_tentativeCommit.clear();
3203 if (validateFromState >= 0 && wasValidInput && !m_validInput) {
3204 if (m_transactions.count())
3206 internalUndo(validateFromState);
3207 m_history.resize(m_undoState);
3208 m_validInput = true;
3209 m_acceptableInput = wasAcceptable;
3210 m_textDirty = false;
3214 m_textDirty = false;
3215 m_preeditDirty = false;
3216 alignmentChanged = determineHorizontalAlignment();
3217 emit q->textChanged();
3220 updateDisplayText(alignmentChanged);
3222 if (m_acceptableInput != wasAcceptable)
3223 emit q->acceptableInputChanged();
3225 if (m_preeditDirty) {
3226 m_preeditDirty = false;
3227 if (determineHorizontalAlignment()) {
3228 alignmentChanged = true;
3235 emit q->selectionChanged();
3238 inputMethodAttributesChanged |= (m_cursor == m_lastCursorPos);
3239 if (inputMethodAttributesChanged)
3240 q->updateInputMethod();
3241 emitUndoRedoChanged();
3243 if (!emitCursorPositionChanged() && alignmentChanged)
3244 q->updateCursorRectangle();
3252 An internal function for setting the text of the line control.
3254 void QQuickTextInputPrivate::internalSetText(const QString &txt, int pos, bool edited)
3257 QString oldText = m_text;
3259 m_text = maskString(0, txt, true);
3260 m_text += clearString(m_text.length(), m_maxLength - m_text.length());
3262 m_text = txt.isEmpty() ? txt : txt.left(m_maxLength);
3266 m_cursor = (pos < 0 || pos > m_text.length()) ? m_text.length() : pos;
3267 m_textDirty = (oldText != m_text);
3269 finishChange(-1, true, edited);
3276 Adds the given \a command to the undo history
3277 of the line control. Does not apply the command.
3279 void QQuickTextInputPrivate::addCommand(const Command &cmd)
3281 if (m_separator && m_undoState && m_history[m_undoState - 1].type != Separator) {
3282 m_history.resize(m_undoState + 2);
3283 m_history[m_undoState++] = Command(Separator, m_cursor, 0, m_selstart, m_selend);
3285 m_history.resize(m_undoState + 1);
3287 m_separator = false;
3288 m_history[m_undoState++] = cmd;
3294 Inserts the given string \a s into the line
3297 Also adds the appropriate commands into the undo history.
3298 This function does not call finishChange(), and may leave the text
3299 in an invalid state.
3301 void QQuickTextInputPrivate::internalInsert(const QString &s)
3303 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
3304 Q_Q(QQuickTextInput);
3305 if (m_echoMode == QQuickTextInput::Password)
3306 m_passwordEchoTimer.start(qt_passwordEchoDelay, q);
3308 if (hasSelectedText())
3309 addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
3311 QString ms = maskString(m_cursor, s);
3312 for (int i = 0; i < (int) ms.length(); ++i) {
3313 addCommand (Command(DeleteSelection, m_cursor + i, m_text.at(m_cursor + i), -1, -1));
3314 addCommand(Command(Insert, m_cursor + i, ms.at(i), -1, -1));
3316 m_text.replace(m_cursor, ms.length(), ms);
3317 m_cursor += ms.length();
3318 m_cursor = nextMaskBlank(m_cursor);
3321 int remaining = m_maxLength - m_text.length();
3322 if (remaining != 0) {
3323 m_text.insert(m_cursor, s.left(remaining));
3324 for (int i = 0; i < (int) s.left(remaining).length(); ++i)
3325 addCommand(Command(Insert, m_cursor++, s.at(i), -1, -1));
3334 deletes a single character from the current text. If \a wasBackspace,
3335 the character prior to the cursor is removed. Otherwise the character
3336 after the cursor is removed.
3338 Also adds the appropriate commands into the undo history.
3339 This function does not call finishChange(), and may leave the text
3340 in an invalid state.
3342 void QQuickTextInputPrivate::internalDelete(bool wasBackspace)
3344 if (m_cursor < (int) m_text.length()) {
3345 cancelPasswordEchoTimer();
3346 if (hasSelectedText())
3347 addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
3348 addCommand(Command((CommandType)((m_maskData ? 2 : 0) + (wasBackspace ? Remove : Delete)),
3349 m_cursor, m_text.at(m_cursor), -1, -1));
3351 m_text.replace(m_cursor, 1, clearString(m_cursor, 1));
3352 addCommand(Command(Insert, m_cursor, m_text.at(m_cursor), -1, -1));
3354 m_text.remove(m_cursor, 1);
3363 removes the currently selected text from the line control.
3365 Also adds the appropriate commands into the undo history.
3366 This function does not call finishChange(), and may leave the text
3367 in an invalid state.
3369 void QQuickTextInputPrivate::removeSelectedText()
3371 if (m_selstart < m_selend && m_selend <= (int) m_text.length()) {
3372 cancelPasswordEchoTimer();
3375 addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
3376 if (m_selstart <= m_cursor && m_cursor < m_selend) {
3377 // cursor is within the selection. Split up the commands
3378 // to be able to restore the correct cursor position
3379 for (i = m_cursor; i >= m_selstart; --i)
3380 addCommand (Command(DeleteSelection, i, m_text.at(i), -1, 1));
3381 for (i = m_selend - 1; i > m_cursor; --i)
3382 addCommand (Command(DeleteSelection, i - m_cursor + m_selstart - 1, m_text.at(i), -1, -1));
3384 for (i = m_selend-1; i >= m_selstart; --i)
3385 addCommand (Command(RemoveSelection, i, m_text.at(i), -1, -1));
3388 m_text.replace(m_selstart, m_selend - m_selstart, clearString(m_selstart, m_selend - m_selstart));
3389 for (int i = 0; i < m_selend - m_selstart; ++i)
3390 addCommand(Command(Insert, m_selstart + i, m_text.at(m_selstart + i), -1, -1));
3392 m_text.remove(m_selstart, m_selend - m_selstart);
3394 if (m_cursor > m_selstart)
3395 m_cursor -= qMin(m_cursor, m_selend) - m_selstart;
3404 Parses the input mask specified by \a maskFields to generate
3405 the mask data used to handle input masks.
3407 void QQuickTextInputPrivate::parseInputMask(const QString &maskFields)
3409 int delimiter = maskFields.indexOf(QLatin1Char(';'));
3410 if (maskFields.isEmpty() || delimiter == 0) {
3412 delete [] m_maskData;
3414 m_maxLength = 32767;
3415 internalSetText(QString());
3420 if (delimiter == -1) {
3421 m_blank = QLatin1Char(' ');
3422 m_inputMask = maskFields;
3424 m_inputMask = maskFields.left(delimiter);
3425 m_blank = (delimiter + 1 < maskFields.length()) ? maskFields[delimiter + 1] : QLatin1Char(' ');
3428 // calculate m_maxLength / m_maskData length
3431 for (int i=0; i<m_inputMask.length(); i++) {
3432 c = m_inputMask.at(i);
3433 if (i > 0 && m_inputMask.at(i-1) == QLatin1Char('\\')) {
3437 if (c != QLatin1Char('\\') && c != QLatin1Char('!') &&
3438 c != QLatin1Char('<') && c != QLatin1Char('>') &&
3439 c != QLatin1Char('{') && c != QLatin1Char('}') &&
3440 c != QLatin1Char('[') && c != QLatin1Char(']'))
3444 delete [] m_maskData;
3445 m_maskData = new MaskInputData[m_maxLength];
3447 MaskInputData::Casemode m = MaskInputData::NoCaseMode;
3450 bool escape = false;
3452 for (int i = 0; i < m_inputMask.length(); i++) {
3453 c = m_inputMask.at(i);
3456 m_maskData[index].maskChar = c;
3457 m_maskData[index].separator = s;
3458 m_maskData[index].caseMode = m;
3461 } else if (c == QLatin1Char('<')) {
3462 m = MaskInputData::Lower;
3463 } else if (c == QLatin1Char('>')) {
3464 m = MaskInputData::Upper;
3465 } else if (c == QLatin1Char('!')) {
3466 m = MaskInputData::NoCaseMode;
3467 } else if (c != QLatin1Char('{') && c != QLatin1Char('}') && c != QLatin1Char('[') && c != QLatin1Char(']')) {
3468 switch (c.unicode()) {
3494 m_maskData[index].maskChar = c;
3495 m_maskData[index].separator = s;
3496 m_maskData[index].caseMode = m;
3501 internalSetText(m_text);
3508 checks if the key is valid compared to the inputMask
3510 bool QQuickTextInputPrivate::isValidInput(QChar key, QChar mask) const
3512 switch (mask.unicode()) {
3518 if (key.isLetter() || key == m_blank)
3522 if (key.isLetterOrNumber())
3526 if (key.isLetterOrNumber() || key == m_blank)
3534 if (key.isPrint() || key == m_blank)
3542 if (key.isNumber() || key == m_blank)
3546 if (key.isNumber() && key.digitValue() > 0)
3550 if ((key.isNumber() && key.digitValue() > 0) || key == m_blank)
3554 if (key.isNumber() || key == QLatin1Char('+') || key == QLatin1Char('-') || key == m_blank)
3558 if (key == QLatin1Char('0') || key == QLatin1Char('1'))
3562 if (key == QLatin1Char('0') || key == QLatin1Char('1') || key == m_blank)
3566 if (key.isNumber() || (key >= QLatin1Char('a') && key <= QLatin1Char('f')) || (key >= QLatin1Char('A') && key <= QLatin1Char('F')))
3570 if (key.isNumber() || (key >= QLatin1Char('a') && key <= QLatin1Char('f')) || (key >= QLatin1Char('A') && key <= QLatin1Char('F')) || key == m_blank)
3582 Returns true if the given text \a str is valid for any
3583 validator or input mask set for the line control.
3585 Otherwise returns false
3587 QQuickTextInputPrivate::ValidatorState QQuickTextInputPrivate::hasAcceptableInput(const QString &str) const
3589 #ifndef QT_NO_VALIDATOR
3590 QString textCopy = str;
3591 int cursorCopy = m_cursor;
3593 QValidator::State state = m_validator->validate(textCopy, cursorCopy);
3594 if (state != QValidator::Acceptable)
3595 return ValidatorState(state);
3600 return AcceptableInput;
3602 if (str.length() != m_maxLength)
3603 return InvalidInput;
3605 for (int i=0; i < m_maxLength; ++i) {
3606 if (m_maskData[i].separator) {
3607 if (str.at(i) != m_maskData[i].maskChar)
3608 return InvalidInput;
3610 if (!isValidInput(str.at(i), m_maskData[i].maskChar))
3611 return InvalidInput;
3614 return AcceptableInput;
3620 Applies the inputMask on \a str starting from position \a pos in the mask. \a clear
3621 specifies from where characters should be gotten when a separator is met in \a str - true means
3622 that blanks will be used, false that previous input is used.
3623 Calling this when no inputMask is set is undefined.
3625 QString QQuickTextInputPrivate::maskString(uint pos, const QString &str, bool clear) const
3627 if (pos >= (uint)m_maxLength)
3628 return QString::fromLatin1("");
3631 fill = clear ? clearString(0, m_maxLength) : m_text;
3634 QString s = QString::fromLatin1("");
3636 while (i < m_maxLength) {
3637 if (strIndex < str.length()) {
3638 if (m_maskData[i].separator) {
3639 s += m_maskData[i].maskChar;
3640 if (str[(int)strIndex] == m_maskData[i].maskChar)
3644 if (isValidInput(str[(int)strIndex], m_maskData[i].maskChar)) {
3645 switch (m_maskData[i].caseMode) {
3646 case MaskInputData::Upper:
3647 s += str[(int)strIndex].toUpper();
3649 case MaskInputData::Lower:
3650 s += str[(int)strIndex].toLower();
3653 s += str[(int)strIndex];
3657 // search for separator first
3658 int n = findInMask(i, true, true, str[(int)strIndex]);
3660 if (str.length() != 1 || i == 0 || (i > 0 && (!m_maskData[i-1].separator || m_maskData[i-1].maskChar != str[(int)strIndex]))) {
3661 s += fill.mid(i, n-i+1);
3662 i = n + 1; // update i to find + 1
3665 // search for valid m_blank if not
3666 n = findInMask(i, true, false, str[(int)strIndex]);
3668 s += fill.mid(i, n-i);
3669 switch (m_maskData[n].caseMode) {
3670 case MaskInputData::Upper:
3671 s += str[(int)strIndex].toUpper();
3673 case MaskInputData::Lower:
3674 s += str[(int)strIndex].toLower();
3677 s += str[(int)strIndex];
3679 i = n + 1; // updates i to find + 1
3697 Returns a "cleared" string with only separators and blank chars.
3698 Calling this when no inputMask is set is undefined.
3700 QString QQuickTextInputPrivate::clearString(uint pos, uint len) const
3702 if (pos >= (uint)m_maxLength)
3706 int end = qMin((uint)m_maxLength, pos + len);
3707 for (int i = pos; i < end; ++i)
3708 if (m_maskData[i].separator)
3709 s += m_maskData[i].maskChar;
3719 Strips blank parts of the input in a QQuickTextInputPrivate when an inputMask is set,
3720 separators are still included. Typically "127.0__.0__.1__" becomes "127.0.0.1".
3722 QString QQuickTextInputPrivate::stripString(const QString &str) const
3728 int end = qMin(m_maxLength, (int)str.length());
3729 for (int i = 0; i < end; ++i) {
3730 if (m_maskData[i].separator)
3731 s += m_maskData[i].maskChar;
3732 else if (str[i] != m_blank)
3741 searches forward/backward in m_maskData for either a separator or a m_blank
3743 int QQuickTextInputPrivate::findInMask(int pos, bool forward, bool findSeparator, QChar searchChar) const
3745 if (pos >= m_maxLength || pos < 0)
3748 int end = forward ? m_maxLength : -1;
3749 int step = forward ? 1 : -1;
3753 if (findSeparator) {
3754 if (m_maskData[i].separator && m_maskData[i].maskChar == searchChar)
3757 if (!m_maskData[i].separator) {
3758 if (searchChar.isNull())
3760 else if (isValidInput(searchChar, m_maskData[i].maskChar))
3769 void QQuickTextInputPrivate::internalUndo(int until)
3771 if (!isUndoAvailable())
3773 cancelPasswordEchoTimer();
3775 while (m_undoState && m_undoState > until) {
3776 Command& cmd = m_history[--m_undoState];
3779 m_text.remove(cmd.pos, 1);
3783 m_selstart = cmd.selStart;
3784 m_selend = cmd.selEnd;
3788 case RemoveSelection:
3789 m_text.insert(cmd.pos, cmd.uc);
3790 m_cursor = cmd.pos + 1;
3793 case DeleteSelection:
3794 m_text.insert(cmd.pos, cmd.uc);
3800 if (until < 0 && m_undoState) {
3801 Command& next = m_history[m_undoState-1];
3802 if (next.type != cmd.type && next.type < RemoveSelection
3803 && (cmd.type < RemoveSelection || next.type == Separator))
3810 void QQuickTextInputPrivate::internalRedo()
3812 if (!isRedoAvailable())
3815 while (m_undoState < (int)m_history.size()) {
3816 Command& cmd = m_history[m_undoState++];
3819 m_text.insert(cmd.pos, cmd.uc);
3820 m_cursor = cmd.pos + 1;
3823 m_selstart = cmd.selStart;
3824 m_selend = cmd.selEnd;
3829 case RemoveSelection:
3830 case DeleteSelection:
3831 m_text.remove(cmd.pos, 1);
3832 m_selstart = cmd.selStart;
3833 m_selend = cmd.selEnd;
3837 m_selstart = cmd.selStart;
3838 m_selend = cmd.selEnd;
3842 if (m_undoState < (int)m_history.size()) {
3843 Command& next = m_history[m_undoState];
3844 if (next.type != cmd.type && cmd.type < RemoveSelection && next.type != Separator
3845 && (next.type < RemoveSelection || cmd.type == Separator))
3852 void QQuickTextInputPrivate::emitUndoRedoChanged()
3854 Q_Q(QQuickTextInput);
3855 const bool previousUndo = canUndo;
3856 const bool previousRedo = canRedo;
3858 canUndo = isUndoAvailable();
3859 canRedo = isRedoAvailable();
3861 if (previousUndo != canUndo)
3862 emit q->canUndoChanged();
3863 if (previousRedo != canRedo)
3864 emit q->canRedoChanged();
3870 If the current cursor position differs from the last emitted cursor
3871 position, emits cursorPositionChanged().
3873 bool QQuickTextInputPrivate::emitCursorPositionChanged()
3875 Q_Q(QQuickTextInput);
3876 if (m_cursor != m_lastCursorPos) {
3877 m_lastCursorPos = m_cursor;
3879 q->updateCursorRectangle();
3880 emit q->cursorPositionChanged();
3882 if (!hasSelectedText()) {
3883 if (lastSelectionStart != m_cursor) {
3884 lastSelectionStart = m_cursor;
3885 emit q->selectionStartChanged();
3887 if (lastSelectionEnd != m_cursor) {
3888 lastSelectionEnd = m_cursor;
3889 emit q->selectionEndChanged();
3899 void QQuickTextInputPrivate::setCursorBlinkPeriod(int msec)
3901 Q_Q(QQuickTextInput);
3902 if (msec == m_blinkPeriod)
3905 q->killTimer(m_blinkTimer);
3908 m_blinkTimer = q->startTimer(msec / 2);
3912 if (m_blinkStatus == 1) {
3913 updateType = UpdatePaintNode;
3917 m_blinkPeriod = msec;
3920 void QQuickTextInput::timerEvent(QTimerEvent *event)
3922 Q_D(QQuickTextInput);
3923 if (event->timerId() == d->m_blinkTimer) {
3924 d->m_blinkStatus = !d->m_blinkStatus;
3925 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
3927 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
3928 } else if (event->timerId() == d->m_passwordEchoTimer.timerId()) {
3929 d->m_passwordEchoTimer.stop();
3930 d->updateDisplayText();
3935 void QQuickTextInputPrivate::processKeyEvent(QKeyEvent* event)
3937 Q_Q(QQuickTextInput);
3938 bool inlineCompletionAccepted = false;
3940 if (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return) {
3941 if (hasAcceptableInput(m_text) || fixup()) {
3944 if (inlineCompletionAccepted)
3951 if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit
3952 && !m_passwordEchoEditing
3954 && !event->text().isEmpty()
3955 && !(event->modifiers() & Qt::ControlModifier)) {
3956 // Clear the edit and reset to normal echo mode while editing; the
3957 // echo mode switches back when the edit loses focus
3958 // ### resets current content. dubious code; you can
3959 // navigate with keys up, down, back, and select(?), but if you press
3960 // "left" or "right" it clears?
3961 updatePasswordEchoEditing(true);
3965 bool unknown = false;
3966 bool visual = cursorMoveStyle() == Qt::VisualMoveStyle;
3970 #ifndef QT_NO_SHORTCUT
3971 else if (event == QKeySequence::Undo) {
3974 else if (event == QKeySequence::Redo) {
3977 else if (event == QKeySequence::SelectAll) {
3980 #ifndef QT_NO_CLIPBOARD
3981 else if (event == QKeySequence::Copy) {
3984 else if (event == QKeySequence::Paste) {
3986 QClipboard::Mode mode = QClipboard::Clipboard;
3990 else if (event == QKeySequence::Cut) {
3996 else if (event == QKeySequence::DeleteEndOfLine) {
3998 setSelection(m_cursor, end());
4003 #endif //QT_NO_CLIPBOARD
4004 else if (event == QKeySequence::MoveToStartOfLine || event == QKeySequence::MoveToStartOfBlock) {
4007 else if (event == QKeySequence::MoveToEndOfLine || event == QKeySequence::MoveToEndOfBlock) {
4010 else if (event == QKeySequence::SelectStartOfLine || event == QKeySequence::SelectStartOfBlock) {
4013 else if (event == QKeySequence::SelectEndOfLine || event == QKeySequence::SelectEndOfBlock) {
4016 else if (event == QKeySequence::MoveToNextChar) {
4017 if (hasSelectedText()) {
4018 moveCursor(selectionEnd(), false);
4020 cursorForward(0, visual ? 1 : (layoutDirection() == Qt::LeftToRight ? 1 : -1));
4023 else if (event == QKeySequence::SelectNextChar) {
4024 cursorForward(1, visual ? 1 : (layoutDirection() == Qt::LeftToRight ? 1 : -1));
4026 else if (event == QKeySequence::MoveToPreviousChar) {
4027 if (hasSelectedText()) {
4028 moveCursor(selectionStart(), false);
4030 cursorForward(0, visual ? -1 : (layoutDirection() == Qt::LeftToRight ? -1 : 1));
4033 else if (event == QKeySequence::SelectPreviousChar) {
4034 cursorForward(1, visual ? -1 : (layoutDirection() == Qt::LeftToRight ? -1 : 1));
4036 else if (event == QKeySequence::MoveToNextWord) {
4037 if (m_echoMode == QQuickTextInput::Normal)
4038 layoutDirection() == Qt::LeftToRight ? cursorWordForward(0) : cursorWordBackward(0);
4040 layoutDirection() == Qt::LeftToRight ? end(0) : home(0);
4042 else if (event == QKeySequence::MoveToPreviousWord) {
4043 if (m_echoMode == QQuickTextInput::Normal)
4044 layoutDirection() == Qt::LeftToRight ? cursorWordBackward(0) : cursorWordForward(0);
4045 else if (!m_readOnly) {
4046 layoutDirection() == Qt::LeftToRight ? home(0) : end(0);
4049 else if (event == QKeySequence::SelectNextWord) {
4050 if (m_echoMode == QQuickTextInput::Normal)
4051 layoutDirection() == Qt::LeftToRight ? cursorWordForward(1) : cursorWordBackward(1);
4053 layoutDirection() == Qt::LeftToRight ? end(1) : home(1);
4055 else if (event == QKeySequence::SelectPreviousWord) {
4056 if (m_echoMode == QQuickTextInput::Normal)
4057 layoutDirection() == Qt::LeftToRight ? cursorWordBackward(1) : cursorWordForward(1);
4059 layoutDirection() == Qt::LeftToRight ? home(1) : end(1);
4061 else if (event == QKeySequence::Delete) {
4065 else if (event == QKeySequence::DeleteEndOfWord) {
4067 cursorWordForward(true);
4071 else if (event == QKeySequence::DeleteStartOfWord) {
4073 cursorWordBackward(true);
4077 #endif // QT_NO_SHORTCUT
4079 bool handled = false;
4080 if (event->modifiers() & Qt::ControlModifier) {
4081 switch (event->key()) {
4082 case Qt::Key_Backspace:
4084 cursorWordBackward(true);
4092 } else { // ### check for *no* modifier
4093 switch (event->key()) {
4094 case Qt::Key_Backspace:
4106 if (event->key() == Qt::Key_Direction_L || event->key() == Qt::Key_Direction_R) {
4107 setLayoutDirection((event->key() == Qt::Key_Direction_L) ? Qt::LeftToRight : Qt::RightToLeft);
4111 if (unknown && !m_readOnly) {
4112 QString t = event->text();
4113 if (!t.isEmpty() && t.at(0).isPrint()) {