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->sendMouseEventToInputContext(event))
1450 if (d->selectByMouse) {
1451 setKeepMouseGrab(false);
1452 d->selectPressed = true;
1453 QPointF distanceVector = d->pressPos - d->tripleClickStartPoint;
1454 if (d->hasPendingTripleClick()
1455 && distanceVector.manhattanLength() < qApp->styleHints()->startDragDistance()) {
1456 event->setAccepted(true);
1462 bool mark = (event->modifiers() & Qt::ShiftModifier) && d->selectByMouse;
1463 int cursor = d->positionAt(event->localPos());
1464 d->moveCursor(cursor, mark);
1466 if (d->focusOnPress) {
1467 bool hadActiveFocus = hasActiveFocus();
1469 // re-open input panel on press if already focused
1470 if (hasActiveFocus() && hadActiveFocus && !d->m_readOnly)
1471 openSoftwareInputPanel();
1474 event->setAccepted(true);
1477 void QQuickTextInput::mouseMoveEvent(QMouseEvent *event)
1479 Q_D(QQuickTextInput);
1481 if (d->selectPressed) {
1482 if (qAbs(int(event->localPos().x() - d->pressPos.x())) > qApp->styleHints()->startDragDistance())
1483 setKeepMouseGrab(true);
1485 if (d->composeMode()) {
1487 int startPos = d->positionAt(d->pressPos);
1488 int currentPos = d->positionAt(event->localPos());
1489 if (startPos != currentPos)
1490 d->setSelection(startPos, currentPos - startPos);
1492 moveCursorSelection(d->positionAt(event->localPos()), d->mouseSelectionMode);
1494 event->setAccepted(true);
1496 QQuickImplicitSizeItem::mouseMoveEvent(event);
1500 void QQuickTextInput::mouseReleaseEvent(QMouseEvent *event)
1502 Q_D(QQuickTextInput);
1503 if (d->sendMouseEventToInputContext(event))
1505 if (d->selectPressed) {
1506 d->selectPressed = false;
1507 setKeepMouseGrab(false);
1509 #ifndef QT_NO_CLIPBOARD
1510 if (QGuiApplication::clipboard()->supportsSelection()) {
1511 if (event->button() == Qt::LeftButton) {
1512 d->copy(QClipboard::Selection);
1513 } else if (!d->m_readOnly && event->button() == Qt::MidButton) {
1515 d->insert(QGuiApplication::clipboard()->text(QClipboard::Selection));
1519 if (!event->isAccepted())
1520 QQuickImplicitSizeItem::mouseReleaseEvent(event);
1523 bool QQuickTextInputPrivate::sendMouseEventToInputContext(QMouseEvent *event)
1525 #if !defined QT_NO_IM
1526 if (composeMode()) {
1527 int tmp_cursor = positionAt(event->localPos());
1528 int mousePos = tmp_cursor - m_cursor;
1529 if (mousePos >= 0 && mousePos <= m_textLayout.preeditAreaText().length()) {
1530 if (event->type() == QEvent::MouseButtonRelease) {
1531 qApp->inputMethod()->invokeAction(QInputMethod::Click, mousePos);
1544 void QQuickTextInput::mouseUngrabEvent()
1546 Q_D(QQuickTextInput);
1547 d->selectPressed = false;
1548 setKeepMouseGrab(false);
1551 bool QQuickTextInput::event(QEvent* ev)
1553 #ifndef QT_NO_SHORTCUT
1554 Q_D(QQuickTextInput);
1555 if (ev->type() == QEvent::ShortcutOverride) {
1558 QKeyEvent* ke = static_cast<QKeyEvent*>(ev);
1559 if (ke == QKeySequence::Copy
1560 || ke == QKeySequence::Paste
1561 || ke == QKeySequence::Cut
1562 || ke == QKeySequence::Redo
1563 || ke == QKeySequence::Undo
1564 || ke == QKeySequence::MoveToNextWord
1565 || ke == QKeySequence::MoveToPreviousWord
1566 || ke == QKeySequence::MoveToStartOfDocument
1567 || ke == QKeySequence::MoveToEndOfDocument
1568 || ke == QKeySequence::SelectNextWord
1569 || ke == QKeySequence::SelectPreviousWord
1570 || ke == QKeySequence::SelectStartOfLine
1571 || ke == QKeySequence::SelectEndOfLine
1572 || ke == QKeySequence::SelectStartOfBlock
1573 || ke == QKeySequence::SelectEndOfBlock
1574 || ke == QKeySequence::SelectStartOfDocument
1575 || ke == QKeySequence::SelectAll
1576 || ke == QKeySequence::SelectEndOfDocument) {
1578 } else if (ke->modifiers() == Qt::NoModifier || ke->modifiers() == Qt::ShiftModifier
1579 || ke->modifiers() == Qt::KeypadModifier) {
1580 if (ke->key() < Qt::Key_Escape) {
1584 switch (ke->key()) {
1585 case Qt::Key_Delete:
1588 case Qt::Key_Backspace:
1600 return QQuickImplicitSizeItem::event(ev);
1603 void QQuickTextInput::geometryChanged(const QRectF &newGeometry,
1604 const QRectF &oldGeometry)
1606 Q_D(QQuickTextInput);
1607 if (newGeometry.width() != oldGeometry.width())
1609 updateCursorRectangle();
1610 QQuickImplicitSizeItem::geometryChanged(newGeometry, oldGeometry);
1613 void QQuickTextInputPrivate::updateHorizontalScroll()
1615 Q_Q(QQuickTextInput);
1616 QTextLine currentLine = m_textLayout.lineForTextPosition(m_cursor + m_preeditCursor);
1617 const int preeditLength = m_textLayout.preeditAreaText().length();
1618 const qreal width = qMax<qreal>(0, q->width());
1620 qreal widthUsed = 0;
1621 if (currentLine.isValid()) {
1622 cix = currentLine.cursorToX(m_cursor + preeditLength);
1623 const qreal cursorWidth = cix >= 0 ? cix : width - cix;
1624 widthUsed = qMax(currentLine.naturalTextWidth(), cursorWidth);
1626 int previousScroll = hscroll;
1628 if (!autoScroll || widthUsed <= width || m_echoMode == QQuickTextInput::NoEcho) {
1631 Q_ASSERT(currentLine.isValid());
1632 if (cix - hscroll >= width) {
1633 // text doesn't fit, cursor is to the right of br (scroll right)
1634 hscroll = cix - width;
1635 } else if (cix - hscroll < 0 && hscroll < widthUsed) {
1636 // text doesn't fit, cursor is to the left of br (scroll left)
1638 } else if (widthUsed - hscroll < width) {
1639 // text doesn't fit, text document is to the left of br; align
1641 hscroll = widthUsed - width;
1642 } else if (width - hscroll > widthUsed) {
1643 // text doesn't fit, text document is to the right of br; align
1645 hscroll = width - widthUsed;
1647 if (preeditLength > 0) {
1648 // check to ensure long pre-edit text doesn't push the cursor
1650 cix = currentLine.cursorToX(m_cursor + qMax(0, m_preeditCursor - 1));
1655 if (previousScroll != hscroll)
1656 textLayoutDirty = true;
1659 void QQuickTextInputPrivate::updateVerticalScroll()
1661 Q_Q(QQuickTextInput);
1662 const int preeditLength = m_textLayout.preeditAreaText().length();
1663 const qreal height = qMax<qreal>(0, q->height());
1664 qreal heightUsed = boundingRect.height();
1665 qreal previousScroll = vscroll;
1667 if (!autoScroll || heightUsed <= height) {
1668 // text fits in br; use vscroll for alignment
1669 switch (vAlign & ~(Qt::AlignAbsolute|Qt::AlignHorizontal_Mask)) {
1670 case Qt::AlignBottom:
1671 vscroll = heightUsed - height;
1673 case Qt::AlignVCenter:
1674 vscroll = (heightUsed - height) / 2;
1682 QTextLine currentLine = m_textLayout.lineForTextPosition(m_cursor + preeditLength);
1683 QRectF r = currentLine.isValid() ? currentLine.rect() : QRectF();
1684 qreal top = r.top();
1685 int bottom = r.bottom();
1687 if (bottom - vscroll >= height) {
1688 // text doesn't fit, cursor is to the below the br (scroll down)
1689 vscroll = bottom - height;
1690 } else if (top - vscroll < 0 && vscroll < heightUsed) {
1691 // text doesn't fit, cursor is above br (scroll up)
1693 } else if (heightUsed - vscroll < height) {
1694 // text doesn't fit, text document is to the left of br; align
1696 vscroll = heightUsed - height;
1698 if (preeditLength > 0) {
1699 // check to ensure long pre-edit text doesn't push the cursor
1701 currentLine = m_textLayout.lineForTextPosition(m_cursor + qMax(0, m_preeditCursor - 1));
1702 top = currentLine.isValid() ? currentLine.rect().top() : 0;
1707 if (previousScroll != vscroll)
1708 textLayoutDirty = true;
1711 void QQuickTextInput::triggerPreprocess()
1713 Q_D(QQuickTextInput);
1714 if (d->updateType == QQuickTextInputPrivate::UpdateNone)
1715 d->updateType = QQuickTextInputPrivate::UpdateOnlyPreprocess;
1719 QSGNode *QQuickTextInput::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data)
1722 Q_D(QQuickTextInput);
1724 if (d->updateType != QQuickTextInputPrivate::UpdatePaintNode && oldNode != 0) {
1725 // Update done in preprocess() in the nodes
1726 d->updateType = QQuickTextInputPrivate::UpdateNone;
1730 d->updateType = QQuickTextInputPrivate::UpdateNone;
1732 QQuickTextNode *node = static_cast<QQuickTextNode *>(oldNode);
1734 node = new QQuickTextNode(QQuickItemPrivate::get(this)->sceneGraphContext(), this);
1737 if (!d->textLayoutDirty) {
1738 QSGSimpleRectNode *cursorNode = node->cursorNode();
1739 if (cursorNode != 0 && !isReadOnly()) {
1740 cursorNode->setRect(cursorRectangle());
1742 if (!d->cursorVisible || (!d->m_blinkStatus && d->m_blinkPeriod > 0)) {
1749 node->deleteContent();
1750 node->setMatrix(QMatrix4x4());
1752 QPointF offset(0, 0);
1753 if (d->autoScroll && d->m_textLayout.lineCount() > 0) {
1754 QFontMetricsF fm(d->font);
1755 // the y offset is there to keep the baseline constant in case we have script changes in the text.
1756 offset = -QPoint(d->hscroll, d->vscroll + d->m_textLayout.lineAt(0).ascent() - fm.ascent());
1758 offset = -QPoint(d->hscroll, d->vscroll);
1761 if (!d->m_textLayout.text().isEmpty() || !d->m_textLayout.preeditAreaText().isEmpty()) {
1762 node->addTextLayout(offset, &d->m_textLayout, d->color,
1763 QQuickText::Normal, QColor(), QColor(),
1764 d->selectionColor, d->selectedTextColor,
1765 d->selectionStart(),
1766 d->selectionEnd() - 1); // selectionEnd() returns first char after
1770 if (!isReadOnly() && d->cursorItem == 0) {
1771 node->setCursor(cursorRectangle(), d->color);
1772 if (!d->cursorVisible || (!d->m_blinkStatus && d->m_blinkPeriod > 0)) {
1779 d->textLayoutDirty = false;
1785 QVariant QQuickTextInput::inputMethodQuery(Qt::InputMethodQuery property) const
1787 Q_D(const QQuickTextInput);
1790 return QVariant((bool)(flags() & ItemAcceptsInputMethod));
1792 return QVariant((int) d->effectiveInputMethodHints());
1793 case Qt::ImCursorRectangle:
1794 return cursorRectangle();
1797 case Qt::ImCursorPosition:
1798 return QVariant(d->m_cursor);
1799 case Qt::ImSurroundingText:
1800 if (d->m_echoMode == PasswordEchoOnEdit && !d->m_passwordEchoEditing) {
1801 return QVariant(displayText());
1803 return QVariant(d->realText());
1805 case Qt::ImCurrentSelection:
1806 return QVariant(selectedText());
1807 case Qt::ImMaximumTextLength:
1808 return QVariant(maxLength());
1809 case Qt::ImAnchorPosition:
1810 if (d->selectionStart() == d->selectionEnd())
1811 return QVariant(d->m_cursor);
1812 else if (d->selectionStart() == d->m_cursor)
1813 return QVariant(d->selectionEnd());
1815 return QVariant(d->selectionStart());
1822 \qmlmethod void QtQuick2::TextInput::deselect()
1824 Removes active text selection.
1826 void QQuickTextInput::deselect()
1828 Q_D(QQuickTextInput);
1833 \qmlmethod void QtQuick2::TextInput::selectAll()
1835 Causes all text to be selected.
1837 void QQuickTextInput::selectAll()
1839 Q_D(QQuickTextInput);
1840 d->setSelection(0, text().length());
1844 \qmlmethod void QtQuick2::TextInput::isRightToLeft(int start, int end)
1846 Returns true if the natural reading direction of the editor text
1847 found between positions \a start and \a end is right to left.
1849 bool QQuickTextInput::isRightToLeft(int start, int end)
1852 qmlInfo(this) << "isRightToLeft(start, end) called with the end property being smaller than the start.";
1855 return text().mid(start, end - start).isRightToLeft();
1859 #ifndef QT_NO_CLIPBOARD
1861 \qmlmethod QtQuick2::TextInput::cut()
1863 Moves the currently selected text to the system clipboard.
1865 void QQuickTextInput::cut()
1867 Q_D(QQuickTextInput);
1873 \qmlmethod QtQuick2::TextInput::copy()
1875 Copies the currently selected text to the system clipboard.
1877 void QQuickTextInput::copy()
1879 Q_D(QQuickTextInput);
1884 \qmlmethod QtQuick2::TextInput::paste()
1886 Replaces the currently selected text by the contents of the system clipboard.
1888 void QQuickTextInput::paste()
1890 Q_D(QQuickTextInput);
1894 #endif // QT_NO_CLIPBOARD
1897 Undoes the last operation if undo is \l {canUndo}{available}. Deselects any
1898 current selection, and updates the selection start to the current cursor
1902 void QQuickTextInput::undo()
1904 Q_D(QQuickTextInput);
1905 if (!d->m_readOnly) {
1907 d->finishChange(-1, true);
1912 Redoes the last operation if redo is \l {canRedo}{available}.
1915 void QQuickTextInput::redo()
1917 Q_D(QQuickTextInput);
1918 if (!d->m_readOnly) {
1925 \qmlmethod void QtQuick2::TextInput::insert(int position, string text)
1927 Inserts \a text into the TextInput at position.
1930 void QQuickTextInput::insert(int position, const QString &text)
1932 Q_D(QQuickTextInput);
1933 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
1934 if (d->m_echoMode == QQuickTextInput::Password)
1935 d->m_passwordEchoTimer.start(qt_passwordEchoDelay, this);
1938 if (position < 0 || position > d->m_text.length())
1941 const int priorState = d->m_undoState;
1943 QString insertText = text;
1945 if (d->hasSelectedText()) {
1946 d->addCommand(QQuickTextInputPrivate::Command(
1947 QQuickTextInputPrivate::SetSelection, d->m_cursor, 0, d->m_selstart, d->m_selend));
1949 if (d->m_maskData) {
1950 insertText = d->maskString(position, insertText);
1951 for (int i = 0; i < insertText.length(); ++i) {
1952 d->addCommand(QQuickTextInputPrivate::Command(
1953 QQuickTextInputPrivate::DeleteSelection, position + i, d->m_text.at(position + i), -1, -1));
1954 d->addCommand(QQuickTextInputPrivate::Command(
1955 QQuickTextInputPrivate::Insert, position + i, insertText.at(i), -1, -1));
1957 d->m_text.replace(position, insertText.length(), insertText);
1958 if (!insertText.isEmpty())
1959 d->m_textDirty = true;
1960 if (position < d->m_selend && position + insertText.length() > d->m_selstart)
1961 d->m_selDirty = true;
1963 int remaining = d->m_maxLength - d->m_text.length();
1964 if (remaining != 0) {
1965 insertText = insertText.left(remaining);
1966 d->m_text.insert(position, insertText);
1967 for (int i = 0; i < insertText.length(); ++i)
1968 d->addCommand(QQuickTextInputPrivate::Command(
1969 QQuickTextInputPrivate::Insert, position + i, insertText.at(i), -1, -1));
1970 if (d->m_cursor >= position)
1971 d->m_cursor += insertText.length();
1972 if (d->m_selstart >= position)
1973 d->m_selstart += insertText.length();
1974 if (d->m_selend >= position)
1975 d->m_selend += insertText.length();
1976 d->m_textDirty = true;
1977 if (position >= d->m_selstart && position <= d->m_selend)
1978 d->m_selDirty = true;
1982 d->addCommand(QQuickTextInputPrivate::Command(
1983 QQuickTextInputPrivate::SetSelection, d->m_cursor, 0, d->m_selstart, d->m_selend));
1984 d->finishChange(priorState);
1986 if (d->lastSelectionStart != d->lastSelectionEnd) {
1987 if (d->m_selstart != d->lastSelectionStart) {
1988 d->lastSelectionStart = d->m_selstart;
1989 emit selectionStartChanged();
1991 if (d->m_selend != d->lastSelectionEnd) {
1992 d->lastSelectionEnd = d->m_selend;
1993 emit selectionEndChanged();
1999 \qmlmethod string QtQuick2::TextInput::getText(int start, int end)
2001 Removes the section of text that is between the \a start and \a end positions from the TextInput.
2004 void QQuickTextInput::remove(int start, int end)
2006 Q_D(QQuickTextInput);
2008 start = qBound(0, start, d->m_text.length());
2009 end = qBound(0, end, d->m_text.length());
2013 else if (start == end)
2016 if (start < d->m_selend && end > d->m_selstart)
2017 d->m_selDirty = true;
2019 const int priorState = d->m_undoState;
2021 d->addCommand(QQuickTextInputPrivate::Command(
2022 QQuickTextInputPrivate::SetSelection, d->m_cursor, 0, d->m_selstart, d->m_selend));
2024 if (start <= d->m_cursor && d->m_cursor < end) {
2025 // cursor is within the selection. Split up the commands
2026 // to be able to restore the correct cursor position
2027 for (int i = d->m_cursor; i >= start; --i) {
2028 d->addCommand(QQuickTextInputPrivate::Command(
2029 QQuickTextInputPrivate::DeleteSelection, i, d->m_text.at(i), -1, 1));
2031 for (int i = end - 1; i > d->m_cursor; --i) {
2032 d->addCommand(QQuickTextInputPrivate::Command(
2033 QQuickTextInputPrivate::DeleteSelection, i - d->m_cursor + start - 1, d->m_text.at(i), -1, -1));
2036 for (int i = end - 1; i >= start; --i) {
2037 d->addCommand(QQuickTextInputPrivate::Command(
2038 QQuickTextInputPrivate::RemoveSelection, i, d->m_text.at(i), -1, -1));
2041 if (d->m_maskData) {
2042 d->m_text.replace(start, end - start, d->clearString(start, end - start));
2043 for (int i = 0; i < end - start; ++i) {
2044 d->addCommand(QQuickTextInputPrivate::Command(
2045 QQuickTextInputPrivate::Insert, start + i, d->m_text.at(start + i), -1, -1));
2048 d->m_text.remove(start, end - start);
2050 if (d->m_cursor > start)
2051 d->m_cursor -= qMin(d->m_cursor, end) - start;
2052 if (d->m_selstart > start)
2053 d->m_selstart -= qMin(d->m_selstart, end) - start;
2054 if (d->m_selend > end)
2055 d->m_selend -= qMin(d->m_selend, end) - start;
2057 d->addCommand(QQuickTextInputPrivate::Command(
2058 QQuickTextInputPrivate::SetSelection, d->m_cursor, 0, d->m_selstart, d->m_selend));
2060 d->m_textDirty = true;
2061 d->finishChange(priorState);
2063 if (d->lastSelectionStart != d->lastSelectionEnd) {
2064 if (d->m_selstart != d->lastSelectionStart) {
2065 d->lastSelectionStart = d->m_selstart;
2066 emit selectionStartChanged();
2068 if (d->m_selend != d->lastSelectionEnd) {
2069 d->lastSelectionEnd = d->m_selend;
2070 emit selectionEndChanged();
2077 \qmlmethod void QtQuick2::TextInput::selectWord()
2079 Causes the word closest to the current cursor position to be selected.
2081 void QQuickTextInput::selectWord()
2083 Q_D(QQuickTextInput);
2084 d->selectWordAtPos(d->m_cursor);
2088 \qmlproperty bool QtQuick2::TextInput::smooth
2090 This property holds whether the text is smoothly scaled or transformed.
2092 Smooth filtering gives better visual quality, but is slower. If
2093 the item is displayed at its natural size, this property has no visual or
2096 \note Generally scaling artifacts are only visible if the item is stationary on
2097 the screen. A common pattern when animating an item is to disable smooth
2098 filtering at the beginning of the animation and reenable it at the conclusion.
2102 \qmlproperty string QtQuick2::TextInput::passwordCharacter
2104 This is the character displayed when echoMode is set to Password or
2105 PasswordEchoOnEdit. By default it is an asterisk.
2107 If this property is set to a string with more than one character,
2108 the first character is used. If the string is empty, the value
2109 is ignored and the property is not set.
2111 QString QQuickTextInput::passwordCharacter() const
2113 Q_D(const QQuickTextInput);
2114 return QString(d->m_passwordCharacter);
2117 void QQuickTextInput::setPasswordCharacter(const QString &str)
2119 Q_D(QQuickTextInput);
2120 if (str.length() < 1)
2122 d->m_passwordCharacter = str.constData()[0];
2123 if (d->m_echoMode == Password || d->m_echoMode == PasswordEchoOnEdit)
2124 d->updateDisplayText();
2125 emit passwordCharacterChanged();
2129 \qmlproperty string QtQuick2::TextInput::displayText
2131 This is the text displayed in the TextInput.
2133 If \l echoMode is set to TextInput::Normal, this holds the
2134 same value as the TextInput::text property. Otherwise,
2135 this property holds the text visible to the user, while
2136 the \l text property holds the actual entered text.
2138 QString QQuickTextInput::displayText() const
2140 Q_D(const QQuickTextInput);
2141 return d->m_textLayout.text();
2145 \qmlproperty bool QtQuick2::TextInput::selectByMouse
2149 If true, the user can use the mouse to select text in some
2150 platform-specific way. Note that for some platforms this may
2151 not be an appropriate interaction (eg. may conflict with how
2152 the text needs to behave inside a Flickable.
2154 bool QQuickTextInput::selectByMouse() const
2156 Q_D(const QQuickTextInput);
2157 return d->selectByMouse;
2160 void QQuickTextInput::setSelectByMouse(bool on)
2162 Q_D(QQuickTextInput);
2163 if (d->selectByMouse != on) {
2164 d->selectByMouse = on;
2165 emit selectByMouseChanged(on);
2170 \qmlproperty enum QtQuick2::TextInput::mouseSelectionMode
2172 Specifies how text should be selected using a mouse.
2175 \li TextInput.SelectCharacters - The selection is updated with individual characters. (Default)
2176 \li TextInput.SelectWords - The selection is updated with whole words.
2179 This property only applies when \l selectByMouse is true.
2182 QQuickTextInput::SelectionMode QQuickTextInput::mouseSelectionMode() const
2184 Q_D(const QQuickTextInput);
2185 return d->mouseSelectionMode;
2188 void QQuickTextInput::setMouseSelectionMode(SelectionMode mode)
2190 Q_D(QQuickTextInput);
2191 if (d->mouseSelectionMode != mode) {
2192 d->mouseSelectionMode = mode;
2193 emit mouseSelectionModeChanged(mode);
2198 \qmlproperty bool QtQuick2::TextInput::persistentSelection
2200 Whether the TextInput should keep its selection when it loses active focus to another
2201 item in the scene. By default this is set to false;
2204 bool QQuickTextInput::persistentSelection() const
2206 Q_D(const QQuickTextInput);
2207 return d->persistentSelection;
2210 void QQuickTextInput::setPersistentSelection(bool on)
2212 Q_D(QQuickTextInput);
2213 if (d->persistentSelection == on)
2215 d->persistentSelection = on;
2216 emit persistentSelectionChanged();
2220 \qmlproperty bool QtQuick2::TextInput::canPaste
2222 Returns true if the TextInput is writable and the content of the clipboard is
2223 suitable for pasting into the TextInput.
2225 bool QQuickTextInput::canPaste() const
2227 Q_D(const QQuickTextInput);
2228 if (!d->canPasteValid) {
2229 if (const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData())
2230 const_cast<QQuickTextInputPrivate *>(d)->canPaste = !d->m_readOnly && mimeData->hasText();
2231 const_cast<QQuickTextInputPrivate *>(d)->canPasteValid = true;
2237 \qmlproperty bool QtQuick2::TextInput::canUndo
2239 Returns true if the TextInput is writable and there are previous operations
2243 bool QQuickTextInput::canUndo() const
2245 Q_D(const QQuickTextInput);
2250 \qmlproperty bool QtQuick2::TextInput::canRedo
2252 Returns true if the TextInput is writable and there are \l {undo}{undone}
2253 operations that can be redone.
2256 bool QQuickTextInput::canRedo() const
2258 Q_D(const QQuickTextInput);
2263 \qmlproperty real QtQuick2::TextInput::contentWidth
2265 Returns the width of the text, including the width past the width
2266 which is covered due to insufficient wrapping if \l wrapMode is set.
2269 qreal QQuickTextInput::contentWidth() const
2271 Q_D(const QQuickTextInput);
2272 return d->boundingRect.width();
2276 \qmlproperty real QtQuick2::TextInput::contentHeight
2278 Returns the height of the text, including the height past the height
2279 that is covered if the text does not fit within the set height.
2282 qreal QQuickTextInput::contentHeight() const
2284 Q_D(const QQuickTextInput);
2285 return d->boundingRect.height();
2288 void QQuickTextInput::moveCursorSelection(int position)
2290 Q_D(QQuickTextInput);
2291 d->moveCursor(position, true);
2295 \qmlmethod void QtQuick2::TextInput::moveCursorSelection(int position, SelectionMode mode = TextInput.SelectCharacters)
2297 Moves the cursor to \a position and updates the selection according to the optional \a mode
2298 parameter. (To only move the cursor, set the \l cursorPosition property.)
2300 When this method is called it additionally sets either the
2301 selectionStart or the selectionEnd (whichever was at the previous cursor position)
2302 to the specified position. This allows you to easily extend and contract the selected
2305 The selection mode specifies whether the selection is updated on a per character or a per word
2306 basis. If not specified the selection mode will default to TextInput.SelectCharacters.
2309 \li TextInput.SelectCharacters - Sets either the selectionStart or selectionEnd (whichever was at
2310 the previous cursor position) to the specified position.
2311 \li TextInput.SelectWords - Sets the selectionStart and selectionEnd to include all
2312 words between the specified position and the previous cursor position. Words partially in the
2316 For example, take this sequence of calls:
2320 moveCursorSelection(9, TextInput.SelectCharacters)
2321 moveCursorSelection(7, TextInput.SelectCharacters)
2324 This moves the cursor to position 5, extend the selection end from 5 to 9
2325 and then retract the selection end from 9 to 7, leaving the text from position 5 to 7
2326 selected (the 6th and 7th characters).
2328 The same sequence with TextInput.SelectWords will extend the selection start to a word boundary
2329 before or on position 5 and extend the selection end to a word boundary on or past position 9.
2331 void QQuickTextInput::moveCursorSelection(int pos, SelectionMode mode)
2333 Q_D(QQuickTextInput);
2335 if (mode == SelectCharacters) {
2336 d->moveCursor(pos, true);
2337 } else if (pos != d->m_cursor){
2338 const int cursor = d->m_cursor;
2340 if (!d->hasSelectedText())
2341 anchor = d->m_cursor;
2342 else if (d->selectionStart() == d->m_cursor)
2343 anchor = d->selectionEnd();
2345 anchor = d->selectionStart();
2347 if (anchor < pos || (anchor == pos && cursor < pos)) {
2348 const QString text = this->text();
2349 QTextBoundaryFinder finder(QTextBoundaryFinder::Word, text);
2350 finder.setPosition(anchor);
2352 const QTextBoundaryFinder::BoundaryReasons reasons = finder.boundaryReasons();
2353 if (anchor < text.length() && (!(reasons & QTextBoundaryFinder::StartWord)
2354 || ((reasons & QTextBoundaryFinder::EndWord) && anchor > cursor))) {
2355 finder.toPreviousBoundary();
2357 anchor = finder.position() != -1 ? finder.position() : 0;
2359 finder.setPosition(pos);
2360 if (pos > 0 && !finder.boundaryReasons())
2361 finder.toNextBoundary();
2362 const int cursor = finder.position() != -1 ? finder.position() : text.length();
2364 d->setSelection(anchor, cursor - anchor);
2365 } else if (anchor > pos || (anchor == pos && cursor > pos)) {
2366 const QString text = this->text();
2367 QTextBoundaryFinder finder(QTextBoundaryFinder::Word, text);
2368 finder.setPosition(anchor);
2370 const QTextBoundaryFinder::BoundaryReasons reasons = finder.boundaryReasons();
2371 if (anchor > 0 && (!(reasons & QTextBoundaryFinder::EndWord)
2372 || ((reasons & QTextBoundaryFinder::StartWord) && anchor < cursor))) {
2373 finder.toNextBoundary();
2376 anchor = finder.position() != -1 ? finder.position() : text.length();
2378 finder.setPosition(pos);
2379 if (pos < text.length() && !finder.boundaryReasons())
2380 finder.toPreviousBoundary();
2381 const int cursor = finder.position() != -1 ? finder.position() : 0;
2383 d->setSelection(anchor, cursor - anchor);
2389 \qmlmethod void QtQuick2::TextInput::openSoftwareInputPanel()
2391 Opens software input panels like virtual keyboards for typing, useful for
2392 customizing when you want the input keyboard to be shown and hidden in
2395 By default the opening of input panels follows the platform style. Input panels are
2396 always closed if no editor has active focus.
2398 You can disable the automatic behavior by setting the property \c activeFocusOnPress to false
2399 and use functions openSoftwareInputPanel() and closeSoftwareInputPanel() to implement
2400 the behavior you want.
2402 Only relevant on platforms, which provide virtual keyboards.
2408 text: "Hello world!"
2409 activeFocusOnPress: false
2411 anchors.fill: parent
2413 if (!textInput.activeFocus) {
2414 textInput.forceActiveFocus()
2415 textInput.openSoftwareInputPanel();
2417 textInput.focus = false;
2420 onPressAndHold: textInput.closeSoftwareInputPanel();
2425 void QQuickTextInput::openSoftwareInputPanel()
2428 qGuiApp->inputMethod()->show();
2432 \qmlmethod void QtQuick2::TextInput::closeSoftwareInputPanel()
2434 Closes a software input panel like a virtual keyboard shown on the screen, useful
2435 for customizing when you want the input keyboard to be shown and hidden in
2438 By default the opening of input panels follows the platform style. Input panels are
2439 always closed if no editor has active focus.
2441 You can disable the automatic behavior by setting the property \c activeFocusOnPress to false
2442 and use functions openSoftwareInputPanel() and closeSoftwareInputPanel() to implement
2443 the behavior you want.
2445 Only relevant on platforms, which provide virtual keyboards.
2451 text: "Hello world!"
2452 activeFocusOnPress: false
2454 anchors.fill: parent
2456 if (!textInput.activeFocus) {
2457 textInput.forceActiveFocus();
2458 textInput.openSoftwareInputPanel();
2460 textInput.focus = false;
2463 onPressAndHold: textInput.closeSoftwareInputPanel();
2468 void QQuickTextInput::closeSoftwareInputPanel()
2471 qGuiApp->inputMethod()->hide();
2474 void QQuickTextInput::focusInEvent(QFocusEvent *event)
2476 Q_D(const QQuickTextInput);
2477 if (d->focusOnPress && !d->m_readOnly)
2478 openSoftwareInputPanel();
2479 QQuickImplicitSizeItem::focusInEvent(event);
2482 void QQuickTextInput::itemChange(ItemChange change, const ItemChangeData &value)
2484 Q_D(QQuickTextInput);
2485 if (change == ItemActiveFocusHasChanged) {
2486 bool hasFocus = value.boolValue;
2487 setCursorVisible(hasFocus); // ### refactor: && d->canvas && d->canvas->hasFocus()
2488 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
2489 if (!hasFocus && (d->m_passwordEchoEditing || d->m_passwordEchoTimer.isActive())) {
2491 if (!hasFocus && d->m_passwordEchoEditing) {
2493 d->updatePasswordEchoEditing(false);//QQuickTextInputPrivate sets it on key events, but doesn't deal with focus events
2498 if (!d->persistentSelection)
2500 disconnect(qApp->inputMethod(), SIGNAL(inputDirectionChanged(Qt::LayoutDirection)),
2501 this, SLOT(q_updateAlignment()));
2503 q_updateAlignment();
2504 connect(qApp->inputMethod(), SIGNAL(inputDirectionChanged(Qt::LayoutDirection)),
2505 this, SLOT(q_updateAlignment()));
2508 QQuickItem::itemChange(change, value);
2512 \qmlproperty bool QtQuick2::TextInput::inputMethodComposing
2515 This property holds whether the TextInput has partial text input from an
2518 While it is composing an input method may rely on mouse or key events from
2519 the TextInput to edit or commit the partial text. This property can be
2520 used to determine when to disable events handlers that may interfere with
2521 the correct operation of an input method.
2523 bool QQuickTextInput::isInputMethodComposing() const
2525 Q_D(const QQuickTextInput);
2526 return d->preeditAreaText().length() > 0;
2529 void QQuickTextInputPrivate::init()
2531 Q_Q(QQuickTextInput);
2532 q->setSmooth(smooth);
2533 q->setAcceptedMouseButtons(Qt::LeftButton);
2534 q->setFlag(QQuickItem::ItemAcceptsInputMethod);
2535 q->setFlag(QQuickItem::ItemHasContents);
2536 #ifndef QT_NO_CLIPBOARD
2537 q->connect(QGuiApplication::clipboard(), SIGNAL(dataChanged()),
2538 q, SLOT(q_canPasteChanged()));
2539 #endif // QT_NO_CLIPBOARD
2541 lastSelectionStart = 0;
2542 lastSelectionEnd = 0;
2543 determineHorizontalAlignment();
2545 if (!qmlDisableDistanceField()) {
2546 QTextOption option = m_textLayout.textOption();
2547 option.setUseDesignMetrics(true);
2548 m_textLayout.setTextOption(option);
2552 void QQuickTextInput::updateCursorRectangle()
2554 Q_D(QQuickTextInput);
2555 if (!isComponentComplete())
2558 d->updateHorizontalScroll();
2559 d->updateVerticalScroll();
2560 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
2562 emit cursorRectangleChanged();
2563 if (d->cursorItem) {
2564 QRectF r = cursorRectangle();
2565 d->cursorItem->setPos(r.topLeft());
2566 d->cursorItem->setHeight(r.height());
2568 updateInputMethod(Qt::ImCursorRectangle);
2571 void QQuickTextInput::selectionChanged()
2573 Q_D(QQuickTextInput);
2574 d->textLayoutDirty = true; //TODO: Only update rect in selection
2575 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
2577 emit selectedTextChanged();
2579 if (d->lastSelectionStart != d->selectionStart()) {
2580 d->lastSelectionStart = d->selectionStart();
2581 if (d->lastSelectionStart == -1)
2582 d->lastSelectionStart = d->m_cursor;
2583 emit selectionStartChanged();
2585 if (d->lastSelectionEnd != d->selectionEnd()) {
2586 d->lastSelectionEnd = d->selectionEnd();
2587 if (d->lastSelectionEnd == -1)
2588 d->lastSelectionEnd = d->m_cursor;
2589 emit selectionEndChanged();
2593 void QQuickTextInputPrivate::showCursor()
2595 if (textNode != 0 && textNode->cursorNode() != 0)
2596 textNode->cursorNode()->setColor(color);
2599 void QQuickTextInputPrivate::hideCursor()
2601 if (textNode != 0 && textNode->cursorNode() != 0)
2602 textNode->cursorNode()->setColor(QColor(0, 0, 0, 0));
2605 QRectF QQuickTextInput::boundingRect() const
2607 Q_D(const QQuickTextInput);
2609 int cursorWidth = d->cursorItem ? d->cursorItem->width() : 1;
2611 // Could include font max left/right bearings to either side of rectangle.
2612 QRectF r = QQuickImplicitSizeItem::boundingRect();
2613 r.setRight(r.right() + cursorWidth);
2617 void QQuickTextInput::q_canPasteChanged()
2619 Q_D(QQuickTextInput);
2620 bool old = d->canPaste;
2621 #ifndef QT_NO_CLIPBOARD
2622 if (const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData())
2623 d->canPaste = !d->m_readOnly && mimeData->hasText();
2625 d->canPaste = false;
2628 bool changed = d->canPaste != old || !d->canPasteValid;
2629 d->canPasteValid = true;
2631 emit canPasteChanged();
2635 void QQuickTextInput::q_updateAlignment()
2637 Q_D(QQuickTextInput);
2638 if (d->determineHorizontalAlignment()) {
2640 updateCursorRectangle();
2644 // ### these should come from QStyleHints
2645 const int textCursorWidth = 1;
2646 const bool fullWidthSelection = true;
2651 Updates the display text based of the current edit text
2652 If the text has changed will emit displayTextChanged()
2654 void QQuickTextInputPrivate::updateDisplayText(bool forceUpdate)
2656 QString orig = m_textLayout.text();
2658 if (m_echoMode == QQuickTextInput::NoEcho)
2659 str = QString::fromLatin1("");
2663 if (m_echoMode == QQuickTextInput::Password) {
2664 str.fill(m_passwordCharacter);
2665 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
2666 if (m_passwordEchoTimer.isActive() && m_cursor > 0 && m_cursor <= m_text.length()) {
2667 int cursor = m_cursor - 1;
2668 QChar uc = m_text.at(cursor);
2670 if (cursor > 0 && uc.unicode() >= 0xdc00 && uc.unicode() < 0xe000) {
2671 // second half of a surrogate, check if we have the first half as well,
2672 // if yes restore both at once
2673 uc = m_text.at(cursor - 1);
2674 if (uc.unicode() >= 0xd800 && uc.unicode() < 0xdc00)
2675 str[cursor - 1] = uc;
2679 } else if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit && !m_passwordEchoEditing) {
2680 str.fill(m_passwordCharacter);
2683 // replace certain non-printable characters with spaces (to avoid
2684 // drawing boxes when using fonts that don't have glyphs for such
2686 QChar* uc = str.data();
2687 for (int i = 0; i < (int)str.length(); ++i) {
2688 if ((uc[i] < 0x20 && uc[i] != 0x09)
2689 || uc[i] == QChar::LineSeparator
2690 || uc[i] == QChar::ParagraphSeparator
2691 || uc[i] == QChar::ObjectReplacementCharacter)
2692 uc[i] = QChar(0x0020);
2695 if (str != orig || forceUpdate) {
2696 m_textLayout.setText(str);
2697 updateLayout(); // polish?
2698 emit q_func()->displayTextChanged();
2702 void QQuickTextInputPrivate::updateLayout()
2704 Q_Q(QQuickTextInput);
2706 if (!q->isComponentComplete())
2709 const QRectF previousRect = boundingRect;
2711 QTextOption option = m_textLayout.textOption();
2712 option.setTextDirection(layoutDirection());
2713 option.setWrapMode(QTextOption::WrapMode(wrapMode));
2714 option.setAlignment(Qt::Alignment(q->effectiveHAlign()));
2715 m_textLayout.setTextOption(option);
2716 m_textLayout.setFont(font);
2718 boundingRect = QRectF();
2719 m_textLayout.beginLayout();
2720 QTextLine line = m_textLayout.createLine();
2721 qreal lineWidth = q->widthValid() ? q->width() : INT_MAX;
2724 line.setLineWidth(lineWidth);
2725 line.setPosition(QPointF(line.position().x(), height));
2726 boundingRect = boundingRect.united(line.naturalTextRect());
2728 height += line.height();
2729 line = m_textLayout.createLine();
2730 } while (line.isValid());
2731 m_textLayout.endLayout();
2733 option.setWrapMode(QTextOption::NoWrap);
2734 m_textLayout.setTextOption(option);
2736 textLayoutDirty = true;
2738 updateType = UpdatePaintNode;
2740 q->setImplicitSize(boundingRect.width(), boundingRect.height());
2742 if (previousRect != boundingRect)
2743 emit q->contentSizeChanged();
2746 #ifndef QT_NO_CLIPBOARD
2750 Copies the currently selected text into the clipboard using the given
2753 \note If the echo mode is set to a mode other than Normal then copy
2754 will not work. This is to prevent using copy as a method of bypassing
2755 password features of the line control.
2757 void QQuickTextInputPrivate::copy(QClipboard::Mode mode) const
2759 QString t = selectedText();
2760 if (!t.isEmpty() && m_echoMode == QQuickTextInput::Normal) {
2761 QGuiApplication::clipboard()->setText(t, mode);
2768 Inserts the text stored in the application clipboard into the line
2773 void QQuickTextInputPrivate::paste(QClipboard::Mode clipboardMode)
2775 QString clip = QGuiApplication::clipboard()->text(clipboardMode);
2776 if (!clip.isEmpty() || hasSelectedText()) {
2777 separate(); //make it a separate undo/redo command
2783 #endif // !QT_NO_CLIPBOARD
2788 Exits preedit mode and commits parts marked as tentative commit
2790 void QQuickTextInputPrivate::commitPreedit()
2795 qApp->inputMethod()->reset();
2797 if (!m_tentativeCommit.isEmpty()) {
2798 internalInsert(m_tentativeCommit);
2799 m_tentativeCommit.clear();
2800 finishChange(-1, true/*not used, not documented*/, false);
2803 m_preeditCursor = 0;
2804 m_textLayout.setPreeditArea(-1, QString());
2805 m_textLayout.clearAdditionalFormats();
2812 Handles the behavior for the backspace key or function.
2813 Removes the current selection if there is a selection, otherwise
2814 removes the character prior to the cursor position.
2818 void QQuickTextInputPrivate::backspace()
2820 int priorState = m_undoState;
2821 if (hasSelectedText()) {
2822 removeSelectedText();
2823 } else if (m_cursor) {
2826 m_cursor = prevMaskBlank(m_cursor);
2827 QChar uc = m_text.at(m_cursor);
2828 if (m_cursor > 0 && uc.unicode() >= 0xdc00 && uc.unicode() < 0xe000) {
2829 // second half of a surrogate, check if we have the first half as well,
2830 // if yes delete both at once
2831 uc = m_text.at(m_cursor - 1);
2832 if (uc.unicode() >= 0xd800 && uc.unicode() < 0xdc00) {
2833 internalDelete(true);
2837 internalDelete(true);
2839 finishChange(priorState);
2845 Handles the behavior for the delete key or function.
2846 Removes the current selection if there is a selection, otherwise
2847 removes the character after the cursor position.
2851 void QQuickTextInputPrivate::del()
2853 int priorState = m_undoState;
2854 if (hasSelectedText()) {
2855 removeSelectedText();
2857 int n = m_textLayout.nextCursorPosition(m_cursor) - m_cursor;
2861 finishChange(priorState);
2867 Inserts the given \a newText at the current cursor position.
2868 If there is any selected text it is removed prior to insertion of
2871 void QQuickTextInputPrivate::insert(const QString &newText)
2873 int priorState = m_undoState;
2874 removeSelectedText();
2875 internalInsert(newText);
2876 finishChange(priorState);
2882 Clears the line control text.
2884 void QQuickTextInputPrivate::clear()
2886 int priorState = m_undoState;
2888 m_selend = m_text.length();
2889 removeSelectedText();
2891 finishChange(priorState, /*update*/false, /*edited*/false);
2897 Sets \a length characters from the given \a start position as selected.
2898 The given \a start position must be within the current text for
2899 the line control. If \a length characters cannot be selected, then
2900 the selection will extend to the end of the current text.
2902 void QQuickTextInputPrivate::setSelection(int start, int length)
2904 Q_Q(QQuickTextInput);
2907 if (start < 0 || start > (int)m_text.length()){
2908 qWarning("QQuickTextInputPrivate::setSelection: Invalid start position");
2913 if (start == m_selstart && start + length == m_selend && m_cursor == m_selend)
2916 m_selend = qMin(start + length, (int)m_text.length());
2917 m_cursor = m_selend;
2918 } else if (length < 0){
2919 if (start == m_selend && start + length == m_selstart && m_cursor == m_selstart)
2921 m_selstart = qMax(start + length, 0);
2923 m_cursor = m_selstart;
2924 } else if (m_selstart != m_selend) {
2930 emitCursorPositionChanged();
2933 emit q->selectionChanged();
2934 emitCursorPositionChanged();
2935 q->updateInputMethod(Qt::ImCursorRectangle | Qt::ImAnchorPosition
2936 | Qt::ImCursorPosition | Qt::ImCurrentSelection);
2942 Sets the password echo editing to \a editing. If password echo editing
2943 is true, then the text of the password is displayed even if the echo
2944 mode is set to QLineEdit::PasswordEchoOnEdit. Password echoing editing
2945 does not affect other echo modes.
2947 void QQuickTextInputPrivate::updatePasswordEchoEditing(bool editing)
2949 cancelPasswordEchoTimer();
2950 m_passwordEchoEditing = editing;
2951 updateDisplayText();
2957 Fixes the current text so that it is valid given any set validators.
2959 Returns true if the text was changed. Otherwise returns false.
2961 bool QQuickTextInputPrivate::fixup() // this function assumes that validate currently returns != Acceptable
2963 #ifndef QT_NO_VALIDATOR
2965 QString textCopy = m_text;
2966 int cursorCopy = m_cursor;
2967 m_validator->fixup(textCopy);
2968 if (m_validator->validate(textCopy, cursorCopy) == QValidator::Acceptable) {
2969 if (textCopy != m_text || cursorCopy != m_cursor)
2970 internalSetText(textCopy, cursorCopy);
2981 Moves the cursor to the given position \a pos. If \a mark is true will
2982 adjust the currently selected text.
2984 void QQuickTextInputPrivate::moveCursor(int pos, bool mark)
2986 Q_Q(QQuickTextInput);
2989 if (pos != m_cursor) {
2992 pos = pos > m_cursor ? nextMaskBlank(pos) : prevMaskBlank(pos);
2996 if (m_selend > m_selstart && m_cursor == m_selstart)
2998 else if (m_selend > m_selstart && m_cursor == m_selend)
2999 anchor = m_selstart;
3002 m_selstart = qMin(anchor, pos);
3003 m_selend = qMax(anchor, pos);
3008 if (mark || m_selDirty) {
3010 emit q->selectionChanged();
3012 emitCursorPositionChanged();
3013 q->updateInputMethod();
3019 Applies the given input method event \a event to the text of the line
3022 void QQuickTextInputPrivate::processInputMethodEvent(QInputMethodEvent *event)
3024 Q_Q(QQuickTextInput);
3026 int priorState = -1;
3027 bool isGettingInput = !event->commitString().isEmpty()
3028 || event->preeditString() != preeditAreaText()
3029 || event->replacementLength() > 0;
3030 bool cursorPositionChanged = false;
3031 bool selectionChange = false;
3032 m_preeditDirty = event->preeditString() != preeditAreaText();
3034 if (isGettingInput) {
3035 // If any text is being input, remove selected text.
3036 priorState = m_undoState;
3037 if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit && !m_passwordEchoEditing) {
3038 updatePasswordEchoEditing(true);
3040 m_selend = m_text.length();
3042 removeSelectedText();
3045 int c = m_cursor; // cursor position after insertion of commit string
3046 if (event->replacementStart() <= 0)
3047 c += event->commitString().length() - qMin(-event->replacementStart(), event->replacementLength());
3049 m_cursor += event->replacementStart();
3053 // insert commit string
3054 if (event->replacementLength()) {
3055 m_selstart = m_cursor;
3056 m_selend = m_selstart + event->replacementLength();
3057 m_selend = qMin(m_selend, m_text.length());
3058 removeSelectedText();
3060 if (!event->commitString().isEmpty()) {
3061 internalInsert(event->commitString());
3062 cursorPositionChanged = true;
3065 m_cursor = qBound(0, c, m_text.length());
3067 for (int i = 0; i < event->attributes().size(); ++i) {
3068 const QInputMethodEvent::Attribute &a = event->attributes().at(i);
3069 if (a.type == QInputMethodEvent::Selection) {
3070 m_cursor = qBound(0, a.start + a.length, m_text.length());
3072 m_selstart = qMax(0, qMin(a.start, m_text.length()));
3073 m_selend = m_cursor;
3074 if (m_selend < m_selstart) {
3075 qSwap(m_selstart, m_selend);
3077 selectionChange = true;
3079 m_selstart = m_selend = 0;
3081 cursorPositionChanged = true;
3085 m_textLayout.setPreeditArea(m_cursor, event->preeditString());
3087 const int oldPreeditCursor = m_preeditCursor;
3088 m_preeditCursor = event->preeditString().length();
3089 m_hideCursor = false;
3090 QList<QTextLayout::FormatRange> formats;
3091 for (int i = 0; i < event->attributes().size(); ++i) {
3092 const QInputMethodEvent::Attribute &a = event->attributes().at(i);
3093 if (a.type == QInputMethodEvent::Cursor) {
3094 m_preeditCursor = a.start;
3095 m_hideCursor = !a.length;
3096 } else if (a.type == QInputMethodEvent::TextFormat) {
3097 QTextCharFormat f = qvariant_cast<QTextFormat>(a.value).toCharFormat();
3099 QTextLayout::FormatRange o;
3100 o.start = a.start + m_cursor;
3101 o.length = a.length;
3107 m_textLayout.setAdditionalFormats(formats);
3109 updateDisplayText(/*force*/ true);
3110 if (cursorPositionChanged) {
3111 emitCursorPositionChanged();
3112 } else if (m_preeditCursor != oldPreeditCursor) {
3113 q->updateCursorRectangle();
3116 bool tentativeCommitChanged = m_tentativeCommit != event->tentativeCommitString();
3118 if (tentativeCommitChanged) {
3120 m_tentativeCommit = event->tentativeCommitString();
3123 if (isGettingInput || tentativeCommitChanged)
3124 finishChange(priorState);
3126 if (selectionChange) {
3127 emit q->selectionChanged();
3128 q->updateInputMethod(Qt::ImCursorRectangle | Qt::ImAnchorPosition
3129 | Qt::ImCursorPosition | Qt::ImCurrentSelection);
3136 Sets the selection to cover the word at the given cursor position.
3137 The word boundaries are defined by the behavior of QTextLayout::SkipWords
3140 void QQuickTextInputPrivate::selectWordAtPos(int cursor)
3142 int next = cursor + 1;
3145 int c = m_textLayout.previousCursorPosition(next, QTextLayout::SkipWords);
3146 moveCursor(c, false);
3147 // ## text layout should support end of words.
3148 int end = m_textLayout.nextCursorPosition(c, QTextLayout::SkipWords);
3149 while (end > cursor && m_text[end-1].isSpace())
3151 moveCursor(end, true);
3157 Completes a change to the line control text. If the change is not valid
3158 will undo the line control state back to the given \a validateFromState.
3160 If \a edited is true and the change is valid, will emit textEdited() in
3161 addition to textChanged(). Otherwise only emits textChanged() on a valid
3164 The \a update value is currently unused.
3166 bool QQuickTextInputPrivate::finishChange(int validateFromState, bool update, bool /*edited*/)
3168 Q_Q(QQuickTextInput);
3171 bool inputMethodAttributesChanged = m_textDirty || m_selDirty;
3172 bool alignmentChanged = false;
3176 bool wasValidInput = m_validInput;
3177 bool wasAcceptable = m_acceptableInput;
3178 m_validInput = true;
3179 m_acceptableInput = true;
3180 #ifndef QT_NO_VALIDATOR
3182 QString textCopy = m_text;
3183 int cursorCopy = m_cursor;
3184 QValidator::State state = m_validator->validate(textCopy, cursorCopy);
3185 m_validInput = state != QValidator::Invalid;
3186 m_acceptableInput = state == QValidator::Acceptable;
3188 if (m_text != textCopy) {
3189 internalSetText(textCopy, cursorCopy);
3192 m_cursor = cursorCopy;
3194 if (!m_tentativeCommit.isEmpty()) {
3195 textCopy.insert(m_cursor, m_tentativeCommit);
3196 bool validInput = m_validator->validate(textCopy, cursorCopy) != QValidator::Invalid;
3198 m_tentativeCommit.clear();
3201 m_tentativeCommit.clear();
3205 if (validateFromState >= 0 && wasValidInput && !m_validInput) {
3206 if (m_transactions.count())
3208 internalUndo(validateFromState);
3209 m_history.resize(m_undoState);
3210 m_validInput = true;
3211 m_acceptableInput = wasAcceptable;
3212 m_textDirty = false;
3216 m_textDirty = false;
3217 m_preeditDirty = false;
3218 alignmentChanged = determineHorizontalAlignment();
3219 emit q->textChanged();
3222 updateDisplayText(alignmentChanged);
3224 if (m_acceptableInput != wasAcceptable)
3225 emit q->acceptableInputChanged();
3227 if (m_preeditDirty) {
3228 m_preeditDirty = false;
3229 if (determineHorizontalAlignment()) {
3230 alignmentChanged = true;
3237 emit q->selectionChanged();
3240 inputMethodAttributesChanged |= (m_cursor == m_lastCursorPos);
3241 if (inputMethodAttributesChanged)
3242 q->updateInputMethod();
3243 emitUndoRedoChanged();
3245 if (!emitCursorPositionChanged() && alignmentChanged)
3246 q->updateCursorRectangle();
3254 An internal function for setting the text of the line control.
3256 void QQuickTextInputPrivate::internalSetText(const QString &txt, int pos, bool edited)
3259 QString oldText = m_text;
3261 m_text = maskString(0, txt, true);
3262 m_text += clearString(m_text.length(), m_maxLength - m_text.length());
3264 m_text = txt.isEmpty() ? txt : txt.left(m_maxLength);
3268 m_cursor = (pos < 0 || pos > m_text.length()) ? m_text.length() : pos;
3269 m_textDirty = (oldText != m_text);
3271 finishChange(-1, true, edited);
3278 Adds the given \a command to the undo history
3279 of the line control. Does not apply the command.
3281 void QQuickTextInputPrivate::addCommand(const Command &cmd)
3283 if (m_separator && m_undoState && m_history[m_undoState - 1].type != Separator) {
3284 m_history.resize(m_undoState + 2);
3285 m_history[m_undoState++] = Command(Separator, m_cursor, 0, m_selstart, m_selend);
3287 m_history.resize(m_undoState + 1);
3289 m_separator = false;
3290 m_history[m_undoState++] = cmd;
3296 Inserts the given string \a s into the line
3299 Also adds the appropriate commands into the undo history.
3300 This function does not call finishChange(), and may leave the text
3301 in an invalid state.
3303 void QQuickTextInputPrivate::internalInsert(const QString &s)
3305 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
3306 Q_Q(QQuickTextInput);
3307 if (m_echoMode == QQuickTextInput::Password)
3308 m_passwordEchoTimer.start(qt_passwordEchoDelay, q);
3310 if (hasSelectedText())
3311 addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
3313 QString ms = maskString(m_cursor, s);
3314 for (int i = 0; i < (int) ms.length(); ++i) {
3315 addCommand (Command(DeleteSelection, m_cursor + i, m_text.at(m_cursor + i), -1, -1));
3316 addCommand(Command(Insert, m_cursor + i, ms.at(i), -1, -1));
3318 m_text.replace(m_cursor, ms.length(), ms);
3319 m_cursor += ms.length();
3320 m_cursor = nextMaskBlank(m_cursor);
3323 int remaining = m_maxLength - m_text.length();
3324 if (remaining != 0) {
3325 m_text.insert(m_cursor, s.left(remaining));
3326 for (int i = 0; i < (int) s.left(remaining).length(); ++i)
3327 addCommand(Command(Insert, m_cursor++, s.at(i), -1, -1));
3336 deletes a single character from the current text. If \a wasBackspace,
3337 the character prior to the cursor is removed. Otherwise the character
3338 after the cursor is removed.
3340 Also adds the appropriate commands into the undo history.
3341 This function does not call finishChange(), and may leave the text
3342 in an invalid state.
3344 void QQuickTextInputPrivate::internalDelete(bool wasBackspace)
3346 if (m_cursor < (int) m_text.length()) {
3347 cancelPasswordEchoTimer();
3348 if (hasSelectedText())
3349 addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
3350 addCommand(Command((CommandType)((m_maskData ? 2 : 0) + (wasBackspace ? Remove : Delete)),
3351 m_cursor, m_text.at(m_cursor), -1, -1));
3353 m_text.replace(m_cursor, 1, clearString(m_cursor, 1));
3354 addCommand(Command(Insert, m_cursor, m_text.at(m_cursor), -1, -1));
3356 m_text.remove(m_cursor, 1);
3365 removes the currently selected text from the line control.
3367 Also adds the appropriate commands into the undo history.
3368 This function does not call finishChange(), and may leave the text
3369 in an invalid state.
3371 void QQuickTextInputPrivate::removeSelectedText()
3373 if (m_selstart < m_selend && m_selend <= (int) m_text.length()) {
3374 cancelPasswordEchoTimer();
3377 addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
3378 if (m_selstart <= m_cursor && m_cursor < m_selend) {
3379 // cursor is within the selection. Split up the commands
3380 // to be able to restore the correct cursor position
3381 for (i = m_cursor; i >= m_selstart; --i)
3382 addCommand (Command(DeleteSelection, i, m_text.at(i), -1, 1));
3383 for (i = m_selend - 1; i > m_cursor; --i)
3384 addCommand (Command(DeleteSelection, i - m_cursor + m_selstart - 1, m_text.at(i), -1, -1));
3386 for (i = m_selend-1; i >= m_selstart; --i)
3387 addCommand (Command(RemoveSelection, i, m_text.at(i), -1, -1));
3390 m_text.replace(m_selstart, m_selend - m_selstart, clearString(m_selstart, m_selend - m_selstart));
3391 for (int i = 0; i < m_selend - m_selstart; ++i)
3392 addCommand(Command(Insert, m_selstart + i, m_text.at(m_selstart + i), -1, -1));
3394 m_text.remove(m_selstart, m_selend - m_selstart);
3396 if (m_cursor > m_selstart)
3397 m_cursor -= qMin(m_cursor, m_selend) - m_selstart;
3406 Parses the input mask specified by \a maskFields to generate
3407 the mask data used to handle input masks.
3409 void QQuickTextInputPrivate::parseInputMask(const QString &maskFields)
3411 int delimiter = maskFields.indexOf(QLatin1Char(';'));
3412 if (maskFields.isEmpty() || delimiter == 0) {
3414 delete [] m_maskData;
3416 m_maxLength = 32767;
3417 internalSetText(QString());
3422 if (delimiter == -1) {
3423 m_blank = QLatin1Char(' ');
3424 m_inputMask = maskFields;
3426 m_inputMask = maskFields.left(delimiter);
3427 m_blank = (delimiter + 1 < maskFields.length()) ? maskFields[delimiter + 1] : QLatin1Char(' ');
3430 // calculate m_maxLength / m_maskData length
3433 for (int i=0; i<m_inputMask.length(); i++) {
3434 c = m_inputMask.at(i);
3435 if (i > 0 && m_inputMask.at(i-1) == QLatin1Char('\\')) {
3439 if (c != QLatin1Char('\\') && c != QLatin1Char('!') &&
3440 c != QLatin1Char('<') && c != QLatin1Char('>') &&
3441 c != QLatin1Char('{') && c != QLatin1Char('}') &&
3442 c != QLatin1Char('[') && c != QLatin1Char(']'))
3446 delete [] m_maskData;
3447 m_maskData = new MaskInputData[m_maxLength];
3449 MaskInputData::Casemode m = MaskInputData::NoCaseMode;
3452 bool escape = false;
3454 for (int i = 0; i < m_inputMask.length(); i++) {
3455 c = m_inputMask.at(i);
3458 m_maskData[index].maskChar = c;
3459 m_maskData[index].separator = s;
3460 m_maskData[index].caseMode = m;
3463 } else if (c == QLatin1Char('<')) {
3464 m = MaskInputData::Lower;
3465 } else if (c == QLatin1Char('>')) {
3466 m = MaskInputData::Upper;
3467 } else if (c == QLatin1Char('!')) {
3468 m = MaskInputData::NoCaseMode;
3469 } else if (c != QLatin1Char('{') && c != QLatin1Char('}') && c != QLatin1Char('[') && c != QLatin1Char(']')) {
3470 switch (c.unicode()) {
3496 m_maskData[index].maskChar = c;
3497 m_maskData[index].separator = s;
3498 m_maskData[index].caseMode = m;
3503 internalSetText(m_text);
3510 checks if the key is valid compared to the inputMask
3512 bool QQuickTextInputPrivate::isValidInput(QChar key, QChar mask) const
3514 switch (mask.unicode()) {
3520 if (key.isLetter() || key == m_blank)
3524 if (key.isLetterOrNumber())
3528 if (key.isLetterOrNumber() || key == m_blank)
3536 if (key.isPrint() || key == m_blank)
3544 if (key.isNumber() || key == m_blank)
3548 if (key.isNumber() && key.digitValue() > 0)
3552 if ((key.isNumber() && key.digitValue() > 0) || key == m_blank)
3556 if (key.isNumber() || key == QLatin1Char('+') || key == QLatin1Char('-') || key == m_blank)
3560 if (key == QLatin1Char('0') || key == QLatin1Char('1'))
3564 if (key == QLatin1Char('0') || key == QLatin1Char('1') || key == m_blank)
3568 if (key.isNumber() || (key >= QLatin1Char('a') && key <= QLatin1Char('f')) || (key >= QLatin1Char('A') && key <= QLatin1Char('F')))
3572 if (key.isNumber() || (key >= QLatin1Char('a') && key <= QLatin1Char('f')) || (key >= QLatin1Char('A') && key <= QLatin1Char('F')) || key == m_blank)
3584 Returns true if the given text \a str is valid for any
3585 validator or input mask set for the line control.
3587 Otherwise returns false
3589 QQuickTextInputPrivate::ValidatorState QQuickTextInputPrivate::hasAcceptableInput(const QString &str) const
3591 #ifndef QT_NO_VALIDATOR
3592 QString textCopy = str;
3593 int cursorCopy = m_cursor;
3595 QValidator::State state = m_validator->validate(textCopy, cursorCopy);
3596 if (state != QValidator::Acceptable)
3597 return ValidatorState(state);
3602 return AcceptableInput;
3604 if (str.length() != m_maxLength)
3605 return InvalidInput;
3607 for (int i=0; i < m_maxLength; ++i) {
3608 if (m_maskData[i].separator) {
3609 if (str.at(i) != m_maskData[i].maskChar)
3610 return InvalidInput;
3612 if (!isValidInput(str.at(i), m_maskData[i].maskChar))
3613 return InvalidInput;
3616 return AcceptableInput;
3622 Applies the inputMask on \a str starting from position \a pos in the mask. \a clear
3623 specifies from where characters should be gotten when a separator is met in \a str - true means
3624 that blanks will be used, false that previous input is used.
3625 Calling this when no inputMask is set is undefined.
3627 QString QQuickTextInputPrivate::maskString(uint pos, const QString &str, bool clear) const
3629 if (pos >= (uint)m_maxLength)
3630 return QString::fromLatin1("");
3633 fill = clear ? clearString(0, m_maxLength) : m_text;
3636 QString s = QString::fromLatin1("");
3638 while (i < m_maxLength) {
3639 if (strIndex < str.length()) {
3640 if (m_maskData[i].separator) {
3641 s += m_maskData[i].maskChar;
3642 if (str[(int)strIndex] == m_maskData[i].maskChar)
3646 if (isValidInput(str[(int)strIndex], m_maskData[i].maskChar)) {
3647 switch (m_maskData[i].caseMode) {
3648 case MaskInputData::Upper:
3649 s += str[(int)strIndex].toUpper();
3651 case MaskInputData::Lower:
3652 s += str[(int)strIndex].toLower();
3655 s += str[(int)strIndex];
3659 // search for separator first
3660 int n = findInMask(i, true, true, str[(int)strIndex]);
3662 if (str.length() != 1 || i == 0 || (i > 0 && (!m_maskData[i-1].separator || m_maskData[i-1].maskChar != str[(int)strIndex]))) {
3663 s += fill.mid(i, n-i+1);
3664 i = n + 1; // update i to find + 1
3667 // search for valid m_blank if not
3668 n = findInMask(i, true, false, str[(int)strIndex]);
3670 s += fill.mid(i, n-i);
3671 switch (m_maskData[n].caseMode) {
3672 case MaskInputData::Upper:
3673 s += str[(int)strIndex].toUpper();
3675 case MaskInputData::Lower:
3676 s += str[(int)strIndex].toLower();
3679 s += str[(int)strIndex];
3681 i = n + 1; // updates i to find + 1
3699 Returns a "cleared" string with only separators and blank chars.
3700 Calling this when no inputMask is set is undefined.
3702 QString QQuickTextInputPrivate::clearString(uint pos, uint len) const
3704 if (pos >= (uint)m_maxLength)
3708 int end = qMin((uint)m_maxLength, pos + len);
3709 for (int i = pos; i < end; ++i)
3710 if (m_maskData[i].separator)
3711 s += m_maskData[i].maskChar;
3721 Strips blank parts of the input in a QQuickTextInputPrivate when an inputMask is set,
3722 separators are still included. Typically "127.0__.0__.1__" becomes "127.0.0.1".
3724 QString QQuickTextInputPrivate::stripString(const QString &str) const
3730 int end = qMin(m_maxLength, (int)str.length());
3731 for (int i = 0; i < end; ++i) {
3732 if (m_maskData[i].separator)
3733 s += m_maskData[i].maskChar;
3734 else if (str[i] != m_blank)
3743 searches forward/backward in m_maskData for either a separator or a m_blank
3745 int QQuickTextInputPrivate::findInMask(int pos, bool forward, bool findSeparator, QChar searchChar) const
3747 if (pos >= m_maxLength || pos < 0)
3750 int end = forward ? m_maxLength : -1;
3751 int step = forward ? 1 : -1;
3755 if (findSeparator) {
3756 if (m_maskData[i].separator && m_maskData[i].maskChar == searchChar)
3759 if (!m_maskData[i].separator) {
3760 if (searchChar.isNull())
3762 else if (isValidInput(searchChar, m_maskData[i].maskChar))
3771 void QQuickTextInputPrivate::internalUndo(int until)
3773 if (!isUndoAvailable())
3775 cancelPasswordEchoTimer();
3777 while (m_undoState && m_undoState > until) {
3778 Command& cmd = m_history[--m_undoState];
3781 m_text.remove(cmd.pos, 1);
3785 m_selstart = cmd.selStart;
3786 m_selend = cmd.selEnd;
3790 case RemoveSelection:
3791 m_text.insert(cmd.pos, cmd.uc);
3792 m_cursor = cmd.pos + 1;
3795 case DeleteSelection:
3796 m_text.insert(cmd.pos, cmd.uc);
3802 if (until < 0 && m_undoState) {
3803 Command& next = m_history[m_undoState-1];
3804 if (next.type != cmd.type && next.type < RemoveSelection
3805 && (cmd.type < RemoveSelection || next.type == Separator))
3812 void QQuickTextInputPrivate::internalRedo()
3814 if (!isRedoAvailable())
3817 while (m_undoState < (int)m_history.size()) {
3818 Command& cmd = m_history[m_undoState++];
3821 m_text.insert(cmd.pos, cmd.uc);
3822 m_cursor = cmd.pos + 1;
3825 m_selstart = cmd.selStart;
3826 m_selend = cmd.selEnd;
3831 case RemoveSelection:
3832 case DeleteSelection:
3833 m_text.remove(cmd.pos, 1);
3834 m_selstart = cmd.selStart;
3835 m_selend = cmd.selEnd;
3839 m_selstart = cmd.selStart;
3840 m_selend = cmd.selEnd;
3844 if (m_undoState < (int)m_history.size()) {
3845 Command& next = m_history[m_undoState];
3846 if (next.type != cmd.type && cmd.type < RemoveSelection && next.type != Separator
3847 && (next.type < RemoveSelection || cmd.type == Separator))
3854 void QQuickTextInputPrivate::emitUndoRedoChanged()
3856 Q_Q(QQuickTextInput);
3857 const bool previousUndo = canUndo;
3858 const bool previousRedo = canRedo;
3860 canUndo = isUndoAvailable();
3861 canRedo = isRedoAvailable();
3863 if (previousUndo != canUndo)
3864 emit q->canUndoChanged();
3865 if (previousRedo != canRedo)
3866 emit q->canRedoChanged();
3872 If the current cursor position differs from the last emitted cursor
3873 position, emits cursorPositionChanged().
3875 bool QQuickTextInputPrivate::emitCursorPositionChanged()
3877 Q_Q(QQuickTextInput);
3878 if (m_cursor != m_lastCursorPos) {
3879 m_lastCursorPos = m_cursor;
3881 q->updateCursorRectangle();
3882 emit q->cursorPositionChanged();
3884 if (!hasSelectedText()) {
3885 if (lastSelectionStart != m_cursor) {
3886 lastSelectionStart = m_cursor;
3887 emit q->selectionStartChanged();
3889 if (lastSelectionEnd != m_cursor) {
3890 lastSelectionEnd = m_cursor;
3891 emit q->selectionEndChanged();
3901 void QQuickTextInputPrivate::setCursorBlinkPeriod(int msec)
3903 Q_Q(QQuickTextInput);
3904 if (msec == m_blinkPeriod)
3907 q->killTimer(m_blinkTimer);
3910 m_blinkTimer = q->startTimer(msec / 2);
3914 if (m_blinkStatus == 1) {
3915 updateType = UpdatePaintNode;
3919 m_blinkPeriod = msec;
3922 void QQuickTextInput::timerEvent(QTimerEvent *event)
3924 Q_D(QQuickTextInput);
3925 if (event->timerId() == d->m_blinkTimer) {
3926 d->m_blinkStatus = !d->m_blinkStatus;
3927 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
3929 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
3930 } else if (event->timerId() == d->m_passwordEchoTimer.timerId()) {
3931 d->m_passwordEchoTimer.stop();
3932 d->updateDisplayText();
3937 void QQuickTextInputPrivate::processKeyEvent(QKeyEvent* event)
3939 Q_Q(QQuickTextInput);
3940 bool inlineCompletionAccepted = false;
3942 if (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return) {
3943 if (hasAcceptableInput(m_text) || fixup()) {
3946 if (inlineCompletionAccepted)
3953 if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit
3954 && !m_passwordEchoEditing
3956 && !event->text().isEmpty()
3957 && !(event->modifiers() & Qt::ControlModifier)) {
3958 // Clear the edit and reset to normal echo mode while editing; the
3959 // echo mode switches back when the edit loses focus
3960 // ### resets current content. dubious code; you can
3961 // navigate with keys up, down, back, and select(?), but if you press
3962 // "left" or "right" it clears?
3963 updatePasswordEchoEditing(true);
3967 bool unknown = false;
3968 bool visual = cursorMoveStyle() == Qt::VisualMoveStyle;
3972 #ifndef QT_NO_SHORTCUT
3973 else if (event == QKeySequence::Undo) {
3976 else if (event == QKeySequence::Redo) {
3979 else if (event == QKeySequence::SelectAll) {
3982 #ifndef QT_NO_CLIPBOARD
3983 else if (event == QKeySequence::Copy) {
3986 else if (event == QKeySequence::Paste) {
3988 QClipboard::Mode mode = QClipboard::Clipboard;
3992 else if (event == QKeySequence::Cut) {
3998 else if (event == QKeySequence::DeleteEndOfLine) {
4000 setSelection(m_cursor, end());
4005 #endif //QT_NO_CLIPBOARD
4006 else if (event == QKeySequence::MoveToStartOfLine || event == QKeySequence::MoveToStartOfBlock) {
4009 else if (event == QKeySequence::MoveToEndOfLine || event == QKeySequence::MoveToEndOfBlock) {
4012 else if (event == QKeySequence::SelectStartOfLine || event == QKeySequence::SelectStartOfBlock) {
4015 else if (event == QKeySequence::SelectEndOfLine || event == QKeySequence::SelectEndOfBlock) {
4018 else if (event == QKeySequence::MoveToNextChar) {
4019 if (hasSelectedText()) {
4020 moveCursor(selectionEnd(), false);
4022 cursorForward(0, visual ? 1 : (layoutDirection() == Qt::LeftToRight ? 1 : -1));
4025 else if (event == QKeySequence::SelectNextChar) {
4026 cursorForward(1, visual ? 1 : (layoutDirection() == Qt::LeftToRight ? 1 : -1));
4028 else if (event == QKeySequence::MoveToPreviousChar) {
4029 if (hasSelectedText()) {
4030 moveCursor(selectionStart(), false);
4032 cursorForward(0, visual ? -1 : (layoutDirection() == Qt::LeftToRight ? -1 : 1));
4035 else if (event == QKeySequence::SelectPreviousChar) {
4036 cursorForward(1, visual ? -1 : (layoutDirection() == Qt::LeftToRight ? -1 : 1));
4038 else if (event == QKeySequence::MoveToNextWord) {
4039 if (m_echoMode == QQuickTextInput::Normal)
4040 layoutDirection() == Qt::LeftToRight ? cursorWordForward(0) : cursorWordBackward(0);
4042 layoutDirection() == Qt::LeftToRight ? end(0) : home(0);
4044 else if (event == QKeySequence::MoveToPreviousWord) {
4045 if (m_echoMode == QQuickTextInput::Normal)
4046 layoutDirection() == Qt::LeftToRight ? cursorWordBackward(0) : cursorWordForward(0);
4047 else if (!m_readOnly) {
4048 layoutDirection() == Qt::LeftToRight ? home(0) : end(0);
4051 else if (event == QKeySequence::SelectNextWord) {
4052 if (m_echoMode == QQuickTextInput::Normal)
4053 layoutDirection() == Qt::LeftToRight ? cursorWordForward(1) : cursorWordBackward(1);
4055 layoutDirection() == Qt::LeftToRight ? end(1) : home(1);
4057 else if (event == QKeySequence::SelectPreviousWord) {
4058 if (m_echoMode == QQuickTextInput::Normal)
4059 layoutDirection() == Qt::LeftToRight ? cursorWordBackward(1) : cursorWordForward(1);
4061 layoutDirection() == Qt::LeftToRight ? home(1) : end(1);
4063 else if (event == QKeySequence::Delete) {
4067 else if (event == QKeySequence::DeleteEndOfWord) {
4069 cursorWordForward(true);
4073 else if (event == QKeySequence::DeleteStartOfWord) {
4075 cursorWordBackward(true);
4079 #endif // QT_NO_SHORTCUT
4081 bool handled = false;
4082 if (event->modifiers() & Qt::ControlModifier) {
4083 switch (event->key()) {
4084 case Qt::Key_Backspace:
4086 cursorWordBackward(true);
4094 } else { // ### check for *no* modifier
4095 switch (event->key()) {
4096 case Qt::Key_Backspace:
4108 if (event->key() == Qt::Key_Direction_L || event->key() == Qt::Key_Direction_R) {
4109 setLayoutDirection((event->key() == Qt::Key_Direction_L) ? Qt::LeftToRight : Qt::RightToLeft);
4113 if (unknown && !m_readOnly) {
4114 QString t = event->text();
4115 if (!t.isEmpty() && t.at(0).isPrint()) {