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 \o Font.Normal - the default
212 TextInput { text: "Hello"; font.weight: Font.DemiBold }
217 \qmlproperty bool QtQuick2::TextInput::font.italic
219 Sets whether the font has an italic style.
223 \qmlproperty bool QtQuick2::TextInput::font.underline
225 Sets whether the text is underlined.
229 \qmlproperty bool QtQuick2::TextInput::font.strikeout
231 Sets whether the font has a strikeout style.
235 \qmlproperty real QtQuick2::TextInput::font.pointSize
237 Sets the font size in points. The point size must be greater than zero.
241 \qmlproperty int QtQuick2::TextInput::font.pixelSize
243 Sets the font size in pixels.
245 Using this function makes the font device dependent.
246 Use \c pointSize to set the size of the font in a device independent manner.
250 \qmlproperty real QtQuick2::TextInput::font.letterSpacing
252 Sets the letter spacing for the font.
254 Letter spacing changes the default spacing between individual letters in the font.
255 A positive value increases the letter spacing by the corresponding pixels; a negative value decreases the spacing.
259 \qmlproperty real QtQuick2::TextInput::font.wordSpacing
261 Sets the word spacing for the font.
263 Word spacing changes the default spacing between individual words.
264 A positive value increases the word spacing by a corresponding amount of pixels,
265 while a negative value decreases the inter-word spacing accordingly.
269 \qmlproperty enumeration QtQuick2::TextInput::font.capitalization
271 Sets the capitalization for the text.
274 \o Font.MixedCase - This is the normal text rendering option where no capitalization change is applied.
275 \o Font.AllUppercase - This alters the text to be rendered in all uppercase type.
276 \o Font.AllLowercase - This alters the text to be rendered in all lowercase type.
277 \o Font.SmallCaps - This alters the text to be rendered in small-caps type.
278 \o Font.Capitalize - This alters the text to be rendered with the first character of each word as an uppercase character.
282 TextInput { text: "Hello"; font.capitalization: Font.AllLowercase }
286 QFont QQuickTextInput::font() const
288 Q_D(const QQuickTextInput);
289 return d->sourceFont;
292 void QQuickTextInput::setFont(const QFont &font)
294 Q_D(QQuickTextInput);
295 if (d->sourceFont == font)
298 d->sourceFont = font;
299 QFont oldFont = d->font;
301 if (d->font.pointSizeF() != -1) {
303 qreal size = qRound(d->font.pointSizeF()*2.0);
304 d->font.setPointSizeF(size/2.0);
306 if (oldFont != d->font) {
308 updateCursorRectangle();
309 updateInputMethod(Qt::ImCursorRectangle | Qt::ImFont);
311 emit fontChanged(d->sourceFont);
315 \qmlproperty color QtQuick2::TextInput::color
319 QColor QQuickTextInput::color() const
321 Q_D(const QQuickTextInput);
325 void QQuickTextInput::setColor(const QColor &c)
327 Q_D(QQuickTextInput);
330 d->textLayoutDirty = true;
331 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
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 \o TextInput.NoWrap - no wrapping will be performed. If the text contains insufficient newlines, then implicitWidth will exceed a set width.
516 \o TextInput.WordWrap - wrapping is done on word boundaries only. If a word is too long, implicitWidth will exceed a set width.
517 \o TextInput.WrapAnywhere - wrapping is done at any point on a line, even if it occurs in the middle of a word.
518 \o TextInput.Wrap - if possible, wrapping occurs at a word boundary; otherwise it will occur at the appropriate point on the line, even in the middle of a word.
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 \o DoubleValidator.StandardNotation
962 \o 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 \o TextInput.Normal - Displays the text as it is. (Default)
1114 \o TextInput.Password - Displays asterisks instead of characters.
1115 \o TextInput.NoEcho - Displays nothing.
1116 \o 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 \o 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 \o Qt.ImhSensitiveData - Typed text should not be stored by the active input method
1155 in any persistent storage like predictive user dictionary.
1156 \o Qt.ImhNoAutoUppercase - The input method should not try to automatically switch to upper case
1157 when a sentence ends.
1158 \o Qt.ImhPreferNumbers - Numbers are preferred (but not required).
1159 \o Qt.ImhPreferUppercase - Upper case letters are preferred (but not required).
1160 \o Qt.ImhPreferLowercase - Lower case letters are preferred (but not required).
1161 \o Qt.ImhNoPredictiveText - Do not use predictive text (i.e. dictionary lookup) while typing.
1163 \o Qt.ImhDate - The text editor functions as a date field.
1164 \o Qt.ImhTime - The text editor functions as a time field.
1167 Flags that restrict input (exclusive flags) are:
1170 \o Qt.ImhDigitsOnly - Only digits are allowed.
1171 \o Qt.ImhFormattedNumbersOnly - Only number input is allowed. This includes decimal point and minus sign.
1172 \o Qt.ImhUppercaseOnly - Only upper case letter input is allowed.
1173 \o Qt.ImhLowercaseOnly - Only lower case letter input is allowed.
1174 \o Qt.ImhDialableCharactersOnly - Only characters suitable for phone dialing are allowed.
1175 \o Qt.ImhEmailCharactersOnly - Only characters suitable for email addresses are allowed.
1176 \o Qt.ImhUrlCharactersOnly - Only characters suitable for URLs are allowed.
1182 \o 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 \o TextInput.CursorBetweenCharacters - Returns the position between characters that is nearest x.
1327 \o TextInput.CursorOnCharacter - Returns the position before the character that is nearest x.
1331 void QQuickTextInput::positionAt(QQmlV8Function *args) const
1333 Q_D(const QQuickTextInput);
1337 QTextLine::CursorPosition position = QTextLine::CursorBetweenCharacters;
1339 if (args->Length() < 1)
1343 v8::Local<v8::Value> arg = (*args)[i];
1344 x = arg->NumberValue();
1346 if (++i < args->Length()) {
1348 y = arg->NumberValue();
1351 if (++i < args->Length()) {
1353 position = QTextLine::CursorPosition(arg->Int32Value());
1356 int pos = d->positionAt(x, y, position);
1357 const int cursor = d->m_cursor;
1359 const int preeditLength = d->preeditAreaText().length();
1360 pos = pos > cursor + preeditLength
1361 ? pos - preeditLength
1364 args->returnValue(v8::Int32::New(pos));
1367 int QQuickTextInputPrivate::positionAt(qreal x, qreal y, QTextLine::CursorPosition position) const
1371 QTextLine line = m_textLayout.lineAt(0);
1372 for (int i = 1; i < m_textLayout.lineCount(); ++i) {
1373 QTextLine nextLine = m_textLayout.lineAt(i);
1375 if (y < (line.rect().bottom() + nextLine.y()) / 2)
1379 return line.isValid() ? line.xToCursor(x, position) : 0;
1382 void QQuickTextInput::keyPressEvent(QKeyEvent* ev)
1384 Q_D(QQuickTextInput);
1385 // Don't allow MacOSX up/down support, and we don't allow a completer.
1386 bool ignore = (ev->key() == Qt::Key_Up || ev->key() == Qt::Key_Down) && ev->modifiers() == Qt::NoModifier;
1387 if (!ignore && (d->lastSelectionStart == d->lastSelectionEnd) && (ev->key() == Qt::Key_Right || ev->key() == Qt::Key_Left)) {
1388 // Ignore when moving off the end unless there is a selection,
1389 // because then moving will do something (deselect).
1390 int cursorPosition = d->m_cursor;
1391 if (cursorPosition == 0)
1392 ignore = ev->key() == (d->layoutDirection() == Qt::LeftToRight ? Qt::Key_Left : Qt::Key_Right);
1393 if (cursorPosition == text().length())
1394 ignore = ev->key() == (d->layoutDirection() == Qt::LeftToRight ? Qt::Key_Right : Qt::Key_Left);
1399 d->processKeyEvent(ev);
1401 if (!ev->isAccepted())
1402 QQuickImplicitSizeItem::keyPressEvent(ev);
1405 void QQuickTextInput::inputMethodEvent(QInputMethodEvent *ev)
1407 Q_D(QQuickTextInput);
1408 const bool wasComposing = d->preeditAreaText().length() > 0;
1409 if (d->m_readOnly) {
1412 d->processInputMethodEvent(ev);
1414 if (!ev->isAccepted())
1415 QQuickImplicitSizeItem::inputMethodEvent(ev);
1417 if (wasComposing != (d->m_textLayout.preeditAreaText().length() > 0))
1418 emit inputMethodComposingChanged();
1421 void QQuickTextInput::mouseDoubleClickEvent(QMouseEvent *event)
1423 Q_D(QQuickTextInput);
1425 if (d->selectByMouse && event->button() == Qt::LeftButton) {
1427 int cursor = d->positionAt(event->localPos());
1428 d->selectWordAtPos(cursor);
1429 event->setAccepted(true);
1430 if (!d->hasPendingTripleClick()) {
1431 d->tripleClickStartPoint = event->localPos();
1432 d->tripleClickTimer.start();
1435 if (d->sendMouseEventToInputContext(event))
1437 QQuickImplicitSizeItem::mouseDoubleClickEvent(event);
1441 void QQuickTextInput::mousePressEvent(QMouseEvent *event)
1443 Q_D(QQuickTextInput);
1445 d->pressPos = event->localPos();
1447 if (d->focusOnPress) {
1448 bool hadActiveFocus = hasActiveFocus();
1450 // re-open input panel on press if already focused
1451 if (hasActiveFocus() && hadActiveFocus && !d->m_readOnly)
1452 openSoftwareInputPanel();
1454 if (d->selectByMouse) {
1455 setKeepMouseGrab(false);
1456 d->selectPressed = true;
1457 QPointF distanceVector = d->pressPos - d->tripleClickStartPoint;
1458 if (d->hasPendingTripleClick()
1459 && distanceVector.manhattanLength() < qApp->styleHints()->startDragDistance()) {
1460 event->setAccepted(true);
1466 if (d->sendMouseEventToInputContext(event))
1469 bool mark = (event->modifiers() & Qt::ShiftModifier) && d->selectByMouse;
1470 int cursor = d->positionAt(event->localPos());
1471 d->moveCursor(cursor, mark);
1472 event->setAccepted(true);
1475 void QQuickTextInput::mouseMoveEvent(QMouseEvent *event)
1477 Q_D(QQuickTextInput);
1479 if (d->selectPressed) {
1480 if (qAbs(int(event->localPos().x() - d->pressPos.x())) > qApp->styleHints()->startDragDistance())
1481 setKeepMouseGrab(true);
1483 if (d->composeMode()) {
1485 int startPos = d->positionAt(d->pressPos);
1486 int currentPos = d->positionAt(event->localPos());
1487 if (startPos != currentPos)
1488 d->setSelection(startPos, currentPos - startPos);
1490 moveCursorSelection(d->positionAt(event->localPos()), d->mouseSelectionMode);
1492 event->setAccepted(true);
1494 QQuickImplicitSizeItem::mouseMoveEvent(event);
1498 void QQuickTextInput::mouseReleaseEvent(QMouseEvent *event)
1500 Q_D(QQuickTextInput);
1501 if (d->sendMouseEventToInputContext(event))
1503 if (d->selectPressed) {
1504 d->selectPressed = false;
1505 setKeepMouseGrab(false);
1507 #ifndef QT_NO_CLIPBOARD
1508 if (QGuiApplication::clipboard()->supportsSelection()) {
1509 if (event->button() == Qt::LeftButton) {
1510 d->copy(QClipboard::Selection);
1511 } else if (!d->m_readOnly && event->button() == Qt::MidButton) {
1513 d->insert(QGuiApplication::clipboard()->text(QClipboard::Selection));
1517 if (!event->isAccepted())
1518 QQuickImplicitSizeItem::mouseReleaseEvent(event);
1521 bool QQuickTextInputPrivate::sendMouseEventToInputContext(QMouseEvent *event)
1523 #if !defined QT_NO_IM
1524 if (composeMode()) {
1525 int tmp_cursor = positionAt(event->localPos());
1526 int mousePos = tmp_cursor - m_cursor;
1527 if (mousePos >= 0 && mousePos <= m_textLayout.preeditAreaText().length()) {
1528 if (event->type() == QEvent::MouseButtonRelease) {
1529 qApp->inputMethod()->invokeAction(QInputMethod::Click, mousePos);
1542 void QQuickTextInput::mouseUngrabEvent()
1544 Q_D(QQuickTextInput);
1545 d->selectPressed = false;
1546 setKeepMouseGrab(false);
1549 bool QQuickTextInput::event(QEvent* ev)
1551 #ifndef QT_NO_SHORTCUT
1552 Q_D(QQuickTextInput);
1553 if (ev->type() == QEvent::ShortcutOverride) {
1556 QKeyEvent* ke = static_cast<QKeyEvent*>(ev);
1557 if (ke == QKeySequence::Copy
1558 || ke == QKeySequence::Paste
1559 || ke == QKeySequence::Cut
1560 || ke == QKeySequence::Redo
1561 || ke == QKeySequence::Undo
1562 || ke == QKeySequence::MoveToNextWord
1563 || ke == QKeySequence::MoveToPreviousWord
1564 || ke == QKeySequence::MoveToStartOfDocument
1565 || ke == QKeySequence::MoveToEndOfDocument
1566 || ke == QKeySequence::SelectNextWord
1567 || ke == QKeySequence::SelectPreviousWord
1568 || ke == QKeySequence::SelectStartOfLine
1569 || ke == QKeySequence::SelectEndOfLine
1570 || ke == QKeySequence::SelectStartOfBlock
1571 || ke == QKeySequence::SelectEndOfBlock
1572 || ke == QKeySequence::SelectStartOfDocument
1573 || ke == QKeySequence::SelectAll
1574 || ke == QKeySequence::SelectEndOfDocument) {
1576 } else if (ke->modifiers() == Qt::NoModifier || ke->modifiers() == Qt::ShiftModifier
1577 || ke->modifiers() == Qt::KeypadModifier) {
1578 if (ke->key() < Qt::Key_Escape) {
1582 switch (ke->key()) {
1583 case Qt::Key_Delete:
1586 case Qt::Key_Backspace:
1598 return QQuickImplicitSizeItem::event(ev);
1601 void QQuickTextInput::geometryChanged(const QRectF &newGeometry,
1602 const QRectF &oldGeometry)
1604 Q_D(QQuickTextInput);
1605 if (newGeometry.width() != oldGeometry.width())
1607 updateCursorRectangle();
1608 QQuickImplicitSizeItem::geometryChanged(newGeometry, oldGeometry);
1611 void QQuickTextInputPrivate::updateHorizontalScroll()
1613 Q_Q(QQuickTextInput);
1614 QTextLine currentLine = m_textLayout.lineForTextPosition(m_cursor + m_preeditCursor);
1615 const int preeditLength = m_textLayout.preeditAreaText().length();
1616 const qreal width = qMax<qreal>(0, q->width());
1617 qreal widthUsed = currentLine.isValid() ? currentLine.naturalTextWidth() : 0;
1618 int previousScroll = hscroll;
1620 if (!autoScroll || widthUsed <= width || m_echoMode == QQuickTextInput::NoEcho) {
1623 Q_ASSERT(currentLine.isValid());
1624 qreal cix = currentLine.cursorToX(m_cursor + preeditLength);
1625 if (cix - hscroll >= width) {
1626 // text doesn't fit, cursor is to the right of br (scroll right)
1627 hscroll = cix - width;
1628 } else if (cix - hscroll < 0 && hscroll < widthUsed) {
1629 // text doesn't fit, cursor is to the left of br (scroll left)
1631 } else if (widthUsed - hscroll < width) {
1632 // text doesn't fit, text document is to the left of br; align
1634 hscroll = widthUsed - width;
1636 if (preeditLength > 0) {
1637 // check to ensure long pre-edit text doesn't push the cursor
1639 cix = currentLine.cursorToX(m_cursor + qMax(0, m_preeditCursor - 1));
1644 if (previousScroll != hscroll)
1645 textLayoutDirty = true;
1648 void QQuickTextInputPrivate::updateVerticalScroll()
1650 Q_Q(QQuickTextInput);
1651 const int preeditLength = m_textLayout.preeditAreaText().length();
1652 const qreal height = qMax<qreal>(0, q->height());
1653 qreal heightUsed = boundingRect.height();
1654 qreal previousScroll = vscroll;
1656 if (!autoScroll || heightUsed <= height) {
1657 // text fits in br; use vscroll for alignment
1658 switch (vAlign & ~(Qt::AlignAbsolute|Qt::AlignHorizontal_Mask)) {
1659 case Qt::AlignBottom:
1660 vscroll = heightUsed - height;
1662 case Qt::AlignVCenter:
1663 vscroll = (heightUsed - height) / 2;
1671 QTextLine currentLine = m_textLayout.lineForTextPosition(m_cursor + preeditLength);
1672 QRectF r = currentLine.isValid() ? currentLine.rect() : QRectF();
1673 qreal top = r.top();
1674 int bottom = r.bottom();
1676 if (bottom - vscroll >= height) {
1677 // text doesn't fit, cursor is to the below the br (scroll down)
1678 vscroll = bottom - height;
1679 } else if (top - vscroll < 0 && vscroll < heightUsed) {
1680 // text doesn't fit, cursor is above br (scroll up)
1682 } else if (heightUsed - vscroll < height) {
1683 // text doesn't fit, text document is to the left of br; align
1685 vscroll = heightUsed - height;
1687 if (preeditLength > 0) {
1688 // check to ensure long pre-edit text doesn't push the cursor
1690 currentLine = m_textLayout.lineForTextPosition(m_cursor + qMax(0, m_preeditCursor - 1));
1691 top = currentLine.isValid() ? currentLine.rect().top() : 0;
1696 if (previousScroll != vscroll)
1697 textLayoutDirty = true;
1700 void QQuickTextInput::triggerPreprocess()
1702 Q_D(QQuickTextInput);
1703 if (d->updateType == QQuickTextInputPrivate::UpdateNone)
1704 d->updateType = QQuickTextInputPrivate::UpdateOnlyPreprocess;
1708 QSGNode *QQuickTextInput::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data)
1711 Q_D(QQuickTextInput);
1713 if (d->updateType != QQuickTextInputPrivate::UpdatePaintNode && oldNode != 0) {
1714 // Update done in preprocess() in the nodes
1715 d->updateType = QQuickTextInputPrivate::UpdateNone;
1719 d->updateType = QQuickTextInputPrivate::UpdateNone;
1721 QQuickTextNode *node = static_cast<QQuickTextNode *>(oldNode);
1723 node = new QQuickTextNode(QQuickItemPrivate::get(this)->sceneGraphContext(), this);
1726 if (!d->textLayoutDirty) {
1727 QSGSimpleRectNode *cursorNode = node->cursorNode();
1728 if (cursorNode != 0 && !isReadOnly()) {
1729 cursorNode->setRect(cursorRectangle());
1731 if (!d->cursorVisible || (!d->m_blinkStatus && d->m_blinkPeriod > 0)) {
1738 node->deleteContent();
1739 node->setMatrix(QMatrix4x4());
1741 QPointF offset(0, 0);
1742 if (d->autoScroll && d->m_textLayout.lineCount() > 0) {
1743 QFontMetricsF fm(d->font);
1744 // the y offset is there to keep the baseline constant in case we have script changes in the text.
1745 offset = -QPoint(d->hscroll, d->vscroll + d->m_textLayout.lineAt(0).ascent() - fm.ascent());
1747 offset = -QPoint(d->hscroll, d->vscroll);
1750 if (!d->m_textLayout.text().isEmpty() || !d->m_textLayout.preeditAreaText().isEmpty()) {
1751 node->addTextLayout(offset, &d->m_textLayout, d->color,
1752 QQuickText::Normal, QColor(), QColor(),
1753 d->selectionColor, d->selectedTextColor,
1754 d->selectionStart(),
1755 d->selectionEnd() - 1); // selectionEnd() returns first char after
1759 if (!isReadOnly() && d->cursorItem == 0) {
1760 node->setCursor(cursorRectangle(), d->color);
1761 if (!d->cursorVisible || (!d->m_blinkStatus && d->m_blinkPeriod > 0)) {
1768 d->textLayoutDirty = false;
1774 QVariant QQuickTextInput::inputMethodQuery(Qt::InputMethodQuery property) const
1776 Q_D(const QQuickTextInput);
1779 return QVariant((bool)(flags() & ItemAcceptsInputMethod));
1781 return QVariant((int) d->effectiveInputMethodHints());
1782 case Qt::ImCursorRectangle:
1783 return cursorRectangle();
1786 case Qt::ImCursorPosition:
1787 return QVariant(d->m_cursor);
1788 case Qt::ImSurroundingText:
1789 if (d->m_echoMode == PasswordEchoOnEdit && !d->m_passwordEchoEditing) {
1790 return QVariant(displayText());
1792 return QVariant(d->realText());
1794 case Qt::ImCurrentSelection:
1795 return QVariant(selectedText());
1796 case Qt::ImMaximumTextLength:
1797 return QVariant(maxLength());
1798 case Qt::ImAnchorPosition:
1799 if (d->selectionStart() == d->selectionEnd())
1800 return QVariant(d->m_cursor);
1801 else if (d->selectionStart() == d->m_cursor)
1802 return QVariant(d->selectionEnd());
1804 return QVariant(d->selectionStart());
1811 \qmlmethod void QtQuick2::TextInput::deselect()
1813 Removes active text selection.
1815 void QQuickTextInput::deselect()
1817 Q_D(QQuickTextInput);
1822 \qmlmethod void QtQuick2::TextInput::selectAll()
1824 Causes all text to be selected.
1826 void QQuickTextInput::selectAll()
1828 Q_D(QQuickTextInput);
1829 d->setSelection(0, text().length());
1833 \qmlmethod void QtQuick2::TextInput::isRightToLeft(int start, int end)
1835 Returns true if the natural reading direction of the editor text
1836 found between positions \a start and \a end is right to left.
1838 bool QQuickTextInput::isRightToLeft(int start, int end)
1841 qmlInfo(this) << "isRightToLeft(start, end) called with the end property being smaller than the start.";
1844 return text().mid(start, end - start).isRightToLeft();
1848 #ifndef QT_NO_CLIPBOARD
1850 \qmlmethod QtQuick2::TextInput::cut()
1852 Moves the currently selected text to the system clipboard.
1854 void QQuickTextInput::cut()
1856 Q_D(QQuickTextInput);
1862 \qmlmethod QtQuick2::TextInput::copy()
1864 Copies the currently selected text to the system clipboard.
1866 void QQuickTextInput::copy()
1868 Q_D(QQuickTextInput);
1873 \qmlmethod QtQuick2::TextInput::paste()
1875 Replaces the currently selected text by the contents of the system clipboard.
1877 void QQuickTextInput::paste()
1879 Q_D(QQuickTextInput);
1883 #endif // QT_NO_CLIPBOARD
1886 Undoes the last operation if undo is \l {canUndo}{available}. Deselects any
1887 current selection, and updates the selection start to the current cursor
1891 void QQuickTextInput::undo()
1893 Q_D(QQuickTextInput);
1894 if (!d->m_readOnly) {
1896 d->finishChange(-1, true);
1901 Redoes the last operation if redo is \l {canRedo}{available}.
1904 void QQuickTextInput::redo()
1906 Q_D(QQuickTextInput);
1907 if (!d->m_readOnly) {
1914 \qmlmethod void QtQuick2::TextInput::insert(int position, string text)
1916 Inserts \a text into the TextInput at position.
1919 void QQuickTextInput::insert(int position, const QString &text)
1921 Q_D(QQuickTextInput);
1922 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
1923 if (d->m_echoMode == QQuickTextInput::Password)
1924 d->m_passwordEchoTimer.start(qt_passwordEchoDelay, this);
1927 if (position < 0 || position > d->m_text.length())
1930 const int priorState = d->m_undoState;
1932 QString insertText = text;
1934 if (d->hasSelectedText()) {
1935 d->addCommand(QQuickTextInputPrivate::Command(
1936 QQuickTextInputPrivate::SetSelection, d->m_cursor, 0, d->m_selstart, d->m_selend));
1938 if (d->m_maskData) {
1939 insertText = d->maskString(position, insertText);
1940 for (int i = 0; i < insertText.length(); ++i) {
1941 d->addCommand(QQuickTextInputPrivate::Command(
1942 QQuickTextInputPrivate::DeleteSelection, position + i, d->m_text.at(position + i), -1, -1));
1943 d->addCommand(QQuickTextInputPrivate::Command(
1944 QQuickTextInputPrivate::Insert, position + i, insertText.at(i), -1, -1));
1946 d->m_text.replace(position, insertText.length(), insertText);
1947 if (!insertText.isEmpty())
1948 d->m_textDirty = true;
1949 if (position < d->m_selend && position + insertText.length() > d->m_selstart)
1950 d->m_selDirty = true;
1952 int remaining = d->m_maxLength - d->m_text.length();
1953 if (remaining != 0) {
1954 insertText = insertText.left(remaining);
1955 d->m_text.insert(position, insertText);
1956 for (int i = 0; i < insertText.length(); ++i)
1957 d->addCommand(QQuickTextInputPrivate::Command(
1958 QQuickTextInputPrivate::Insert, position + i, insertText.at(i), -1, -1));
1959 if (d->m_cursor >= position)
1960 d->m_cursor += insertText.length();
1961 if (d->m_selstart >= position)
1962 d->m_selstart += insertText.length();
1963 if (d->m_selend >= position)
1964 d->m_selend += insertText.length();
1965 d->m_textDirty = true;
1966 if (position >= d->m_selstart && position <= d->m_selend)
1967 d->m_selDirty = true;
1971 d->addCommand(QQuickTextInputPrivate::Command(
1972 QQuickTextInputPrivate::SetSelection, d->m_cursor, 0, d->m_selstart, d->m_selend));
1973 d->finishChange(priorState);
1975 if (d->lastSelectionStart != d->lastSelectionEnd) {
1976 if (d->m_selstart != d->lastSelectionStart) {
1977 d->lastSelectionStart = d->m_selstart;
1978 emit selectionStartChanged();
1980 if (d->m_selend != d->lastSelectionEnd) {
1981 d->lastSelectionEnd = d->m_selend;
1982 emit selectionEndChanged();
1988 \qmlmethod string QtQuick2::TextInput::getText(int start, int end)
1990 Removes the section of text that is between the \a start and \a end positions from the TextInput.
1993 void QQuickTextInput::remove(int start, int end)
1995 Q_D(QQuickTextInput);
1997 start = qBound(0, start, d->m_text.length());
1998 end = qBound(0, end, d->m_text.length());
2002 else if (start == end)
2005 if (start < d->m_selend && end > d->m_selstart)
2006 d->m_selDirty = true;
2008 const int priorState = d->m_undoState;
2010 d->addCommand(QQuickTextInputPrivate::Command(
2011 QQuickTextInputPrivate::SetSelection, d->m_cursor, 0, d->m_selstart, d->m_selend));
2013 if (start <= d->m_cursor && d->m_cursor < end) {
2014 // cursor is within the selection. Split up the commands
2015 // to be able to restore the correct cursor position
2016 for (int i = d->m_cursor; i >= start; --i) {
2017 d->addCommand(QQuickTextInputPrivate::Command(
2018 QQuickTextInputPrivate::DeleteSelection, i, d->m_text.at(i), -1, 1));
2020 for (int i = end - 1; i > d->m_cursor; --i) {
2021 d->addCommand(QQuickTextInputPrivate::Command(
2022 QQuickTextInputPrivate::DeleteSelection, i - d->m_cursor + start - 1, d->m_text.at(i), -1, -1));
2025 for (int i = end - 1; i >= start; --i) {
2026 d->addCommand(QQuickTextInputPrivate::Command(
2027 QQuickTextInputPrivate::RemoveSelection, i, d->m_text.at(i), -1, -1));
2030 if (d->m_maskData) {
2031 d->m_text.replace(start, end - start, d->clearString(start, end - start));
2032 for (int i = 0; i < end - start; ++i) {
2033 d->addCommand(QQuickTextInputPrivate::Command(
2034 QQuickTextInputPrivate::Insert, start + i, d->m_text.at(start + i), -1, -1));
2037 d->m_text.remove(start, end - start);
2039 if (d->m_cursor > start)
2040 d->m_cursor -= qMin(d->m_cursor, end) - start;
2041 if (d->m_selstart > start)
2042 d->m_selstart -= qMin(d->m_selstart, end) - start;
2043 if (d->m_selend > end)
2044 d->m_selend -= qMin(d->m_selend, end) - start;
2046 d->addCommand(QQuickTextInputPrivate::Command(
2047 QQuickTextInputPrivate::SetSelection, d->m_cursor, 0, d->m_selstart, d->m_selend));
2049 d->m_textDirty = true;
2050 d->finishChange(priorState);
2052 if (d->lastSelectionStart != d->lastSelectionEnd) {
2053 if (d->m_selstart != d->lastSelectionStart) {
2054 d->lastSelectionStart = d->m_selstart;
2055 emit selectionStartChanged();
2057 if (d->m_selend != d->lastSelectionEnd) {
2058 d->lastSelectionEnd = d->m_selend;
2059 emit selectionEndChanged();
2066 \qmlmethod void QtQuick2::TextInput::selectWord()
2068 Causes the word closest to the current cursor position to be selected.
2070 void QQuickTextInput::selectWord()
2072 Q_D(QQuickTextInput);
2073 d->selectWordAtPos(d->m_cursor);
2077 \qmlproperty bool QtQuick2::TextInput::smooth
2079 This property holds whether the text is smoothly scaled or transformed.
2081 Smooth filtering gives better visual quality, but is slower. If
2082 the item is displayed at its natural size, this property has no visual or
2085 \note Generally scaling artifacts are only visible if the item is stationary on
2086 the screen. A common pattern when animating an item is to disable smooth
2087 filtering at the beginning of the animation and reenable it at the conclusion.
2091 \qmlproperty string QtQuick2::TextInput::passwordCharacter
2093 This is the character displayed when echoMode is set to Password or
2094 PasswordEchoOnEdit. By default it is an asterisk.
2096 If this property is set to a string with more than one character,
2097 the first character is used. If the string is empty, the value
2098 is ignored and the property is not set.
2100 QString QQuickTextInput::passwordCharacter() const
2102 Q_D(const QQuickTextInput);
2103 return QString(d->m_passwordCharacter);
2106 void QQuickTextInput::setPasswordCharacter(const QString &str)
2108 Q_D(QQuickTextInput);
2109 if (str.length() < 1)
2111 d->m_passwordCharacter = str.constData()[0];
2112 if (d->m_echoMode == Password || d->m_echoMode == PasswordEchoOnEdit)
2113 d->updateDisplayText();
2114 emit passwordCharacterChanged();
2118 \qmlproperty string QtQuick2::TextInput::displayText
2120 This is the text displayed in the TextInput.
2122 If \l echoMode is set to TextInput::Normal, this holds the
2123 same value as the TextInput::text property. Otherwise,
2124 this property holds the text visible to the user, while
2125 the \l text property holds the actual entered text.
2127 QString QQuickTextInput::displayText() const
2129 Q_D(const QQuickTextInput);
2130 return d->m_textLayout.text();
2134 \qmlproperty bool QtQuick2::TextInput::selectByMouse
2138 If true, the user can use the mouse to select text in some
2139 platform-specific way. Note that for some platforms this may
2140 not be an appropriate interaction (eg. may conflict with how
2141 the text needs to behave inside a Flickable.
2143 bool QQuickTextInput::selectByMouse() const
2145 Q_D(const QQuickTextInput);
2146 return d->selectByMouse;
2149 void QQuickTextInput::setSelectByMouse(bool on)
2151 Q_D(QQuickTextInput);
2152 if (d->selectByMouse != on) {
2153 d->selectByMouse = on;
2154 emit selectByMouseChanged(on);
2159 \qmlproperty enum QtQuick2::TextInput::mouseSelectionMode
2161 Specifies how text should be selected using a mouse.
2164 \o TextInput.SelectCharacters - The selection is updated with individual characters. (Default)
2165 \o TextInput.SelectWords - The selection is updated with whole words.
2168 This property only applies when \l selectByMouse is true.
2171 QQuickTextInput::SelectionMode QQuickTextInput::mouseSelectionMode() const
2173 Q_D(const QQuickTextInput);
2174 return d->mouseSelectionMode;
2177 void QQuickTextInput::setMouseSelectionMode(SelectionMode mode)
2179 Q_D(QQuickTextInput);
2180 if (d->mouseSelectionMode != mode) {
2181 d->mouseSelectionMode = mode;
2182 emit mouseSelectionModeChanged(mode);
2187 \qmlproperty bool QtQuick2::TextInput::persistentSelection
2189 Whether the TextInput should keep its selection when it loses active focus to another
2190 item in the scene. By default this is set to false;
2193 bool QQuickTextInput::persistentSelection() const
2195 Q_D(const QQuickTextInput);
2196 return d->persistentSelection;
2199 void QQuickTextInput::setPersistentSelection(bool on)
2201 Q_D(QQuickTextInput);
2202 if (d->persistentSelection == on)
2204 d->persistentSelection = on;
2205 emit persistentSelectionChanged();
2209 \qmlproperty bool QtQuick2::TextInput::canPaste
2211 Returns true if the TextInput is writable and the content of the clipboard is
2212 suitable for pasting into the TextInput.
2214 bool QQuickTextInput::canPaste() const
2216 Q_D(const QQuickTextInput);
2217 if (!d->canPasteValid) {
2218 if (const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData())
2219 const_cast<QQuickTextInputPrivate *>(d)->canPaste = !d->m_readOnly && mimeData->hasText();
2220 const_cast<QQuickTextInputPrivate *>(d)->canPasteValid = true;
2226 \qmlproperty bool QtQuick2::TextInput::canUndo
2228 Returns true if the TextInput is writable and there are previous operations
2232 bool QQuickTextInput::canUndo() const
2234 Q_D(const QQuickTextInput);
2239 \qmlproperty bool QtQuick2::TextInput::canRedo
2241 Returns true if the TextInput is writable and there are \l {undo}{undone}
2242 operations that can be redone.
2245 bool QQuickTextInput::canRedo() const
2247 Q_D(const QQuickTextInput);
2252 \qmlproperty real QtQuick2::TextInput::contentWidth
2254 Returns the width of the text, including the width past the width
2255 which is covered due to insufficient wrapping if \l wrapMode is set.
2258 qreal QQuickTextInput::contentWidth() const
2260 Q_D(const QQuickTextInput);
2261 return d->boundingRect.width();
2265 \qmlproperty real QtQuick2::TextInput::contentHeight
2267 Returns the height of the text, including the height past the height
2268 that is covered if the text does not fit within the set height.
2271 qreal QQuickTextInput::contentHeight() const
2273 Q_D(const QQuickTextInput);
2274 return d->boundingRect.height();
2277 void QQuickTextInput::moveCursorSelection(int position)
2279 Q_D(QQuickTextInput);
2280 d->moveCursor(position, true);
2284 \qmlmethod void QtQuick2::TextInput::moveCursorSelection(int position, SelectionMode mode = TextInput.SelectCharacters)
2286 Moves the cursor to \a position and updates the selection according to the optional \a mode
2287 parameter. (To only move the cursor, set the \l cursorPosition property.)
2289 When this method is called it additionally sets either the
2290 selectionStart or the selectionEnd (whichever was at the previous cursor position)
2291 to the specified position. This allows you to easily extend and contract the selected
2294 The selection mode specifies whether the selection is updated on a per character or a per word
2295 basis. If not specified the selection mode will default to TextInput.SelectCharacters.
2298 \o TextInput.SelectCharacters - Sets either the selectionStart or selectionEnd (whichever was at
2299 the previous cursor position) to the specified position.
2300 \o TextInput.SelectWords - Sets the selectionStart and selectionEnd to include all
2301 words between the specified position and the previous cursor position. Words partially in the
2305 For example, take this sequence of calls:
2309 moveCursorSelection(9, TextInput.SelectCharacters)
2310 moveCursorSelection(7, TextInput.SelectCharacters)
2313 This moves the cursor to position 5, extend the selection end from 5 to 9
2314 and then retract the selection end from 9 to 7, leaving the text from position 5 to 7
2315 selected (the 6th and 7th characters).
2317 The same sequence with TextInput.SelectWords will extend the selection start to a word boundary
2318 before or on position 5 and extend the selection end to a word boundary on or past position 9.
2320 void QQuickTextInput::moveCursorSelection(int pos, SelectionMode mode)
2322 Q_D(QQuickTextInput);
2324 if (mode == SelectCharacters) {
2325 d->moveCursor(pos, true);
2326 } else if (pos != d->m_cursor){
2327 const int cursor = d->m_cursor;
2329 if (!d->hasSelectedText())
2330 anchor = d->m_cursor;
2331 else if (d->selectionStart() == d->m_cursor)
2332 anchor = d->selectionEnd();
2334 anchor = d->selectionStart();
2336 if (anchor < pos || (anchor == pos && cursor < pos)) {
2337 const QString text = this->text();
2338 QTextBoundaryFinder finder(QTextBoundaryFinder::Word, text);
2339 finder.setPosition(anchor);
2341 const QTextBoundaryFinder::BoundaryReasons reasons = finder.boundaryReasons();
2342 if (anchor < text.length() && (!(reasons & QTextBoundaryFinder::StartWord)
2343 || ((reasons & QTextBoundaryFinder::EndWord) && anchor > cursor))) {
2344 finder.toPreviousBoundary();
2346 anchor = finder.position() != -1 ? finder.position() : 0;
2348 finder.setPosition(pos);
2349 if (pos > 0 && !finder.boundaryReasons())
2350 finder.toNextBoundary();
2351 const int cursor = finder.position() != -1 ? finder.position() : text.length();
2353 d->setSelection(anchor, cursor - anchor);
2354 } else if (anchor > pos || (anchor == pos && cursor > pos)) {
2355 const QString text = this->text();
2356 QTextBoundaryFinder finder(QTextBoundaryFinder::Word, text);
2357 finder.setPosition(anchor);
2359 const QTextBoundaryFinder::BoundaryReasons reasons = finder.boundaryReasons();
2360 if (anchor > 0 && (!(reasons & QTextBoundaryFinder::EndWord)
2361 || ((reasons & QTextBoundaryFinder::StartWord) && anchor < cursor))) {
2362 finder.toNextBoundary();
2365 anchor = finder.position() != -1 ? finder.position() : text.length();
2367 finder.setPosition(pos);
2368 if (pos < text.length() && !finder.boundaryReasons())
2369 finder.toPreviousBoundary();
2370 const int cursor = finder.position() != -1 ? finder.position() : 0;
2372 d->setSelection(anchor, cursor - anchor);
2378 \qmlmethod void QtQuick2::TextInput::openSoftwareInputPanel()
2380 Opens software input panels like virtual keyboards for typing, useful for
2381 customizing when you want the input keyboard to be shown and hidden in
2384 By default the opening of input panels follows the platform style. Input panels are
2385 always closed if no editor has active focus.
2387 You can disable the automatic behavior by setting the property \c activeFocusOnPress to false
2388 and use functions openSoftwareInputPanel() and closeSoftwareInputPanel() to implement
2389 the behavior you want.
2391 Only relevant on platforms, which provide virtual keyboards.
2397 text: "Hello world!"
2398 activeFocusOnPress: false
2400 anchors.fill: parent
2402 if (!textInput.activeFocus) {
2403 textInput.forceActiveFocus()
2404 textInput.openSoftwareInputPanel();
2406 textInput.focus = false;
2409 onPressAndHold: textInput.closeSoftwareInputPanel();
2414 void QQuickTextInput::openSoftwareInputPanel()
2417 qGuiApp->inputMethod()->show();
2421 \qmlmethod void QtQuick2::TextInput::closeSoftwareInputPanel()
2423 Closes a software input panel like a virtual keyboard shown on the screen, useful
2424 for customizing when you want the input keyboard to be shown and hidden in
2427 By default the opening of input panels follows the platform style. Input panels are
2428 always closed if no editor has active focus.
2430 You can disable the automatic behavior by setting the property \c activeFocusOnPress to false
2431 and use functions openSoftwareInputPanel() and closeSoftwareInputPanel() to implement
2432 the behavior you want.
2434 Only relevant on platforms, which provide virtual keyboards.
2440 text: "Hello world!"
2441 activeFocusOnPress: false
2443 anchors.fill: parent
2445 if (!textInput.activeFocus) {
2446 textInput.forceActiveFocus();
2447 textInput.openSoftwareInputPanel();
2449 textInput.focus = false;
2452 onPressAndHold: textInput.closeSoftwareInputPanel();
2457 void QQuickTextInput::closeSoftwareInputPanel()
2460 qGuiApp->inputMethod()->hide();
2463 void QQuickTextInput::focusInEvent(QFocusEvent *event)
2465 Q_D(const QQuickTextInput);
2466 if (d->focusOnPress && !d->m_readOnly)
2467 openSoftwareInputPanel();
2468 QQuickImplicitSizeItem::focusInEvent(event);
2471 void QQuickTextInput::itemChange(ItemChange change, const ItemChangeData &value)
2473 Q_D(QQuickTextInput);
2474 if (change == ItemActiveFocusHasChanged) {
2475 bool hasFocus = value.boolValue;
2476 setCursorVisible(hasFocus); // ### refactor: && d->canvas && d->canvas->hasFocus()
2477 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
2478 if (!hasFocus && (d->m_passwordEchoEditing || d->m_passwordEchoTimer.isActive())) {
2480 if (!hasFocus && d->m_passwordEchoEditing) {
2482 d->updatePasswordEchoEditing(false);//QQuickTextInputPrivate sets it on key events, but doesn't deal with focus events
2487 if (!d->persistentSelection)
2489 disconnect(qApp->inputMethod(), SIGNAL(inputDirectionChanged(Qt::LayoutDirection)),
2490 this, SLOT(q_updateAlignment()));
2492 q_updateAlignment();
2493 connect(qApp->inputMethod(), SIGNAL(inputDirectionChanged(Qt::LayoutDirection)),
2494 this, SLOT(q_updateAlignment()));
2497 QQuickItem::itemChange(change, value);
2501 \qmlproperty bool QtQuick2::TextInput::inputMethodComposing
2504 This property holds whether the TextInput has partial text input from an
2507 While it is composing an input method may rely on mouse or key events from
2508 the TextInput to edit or commit the partial text. This property can be
2509 used to determine when to disable events handlers that may interfere with
2510 the correct operation of an input method.
2512 bool QQuickTextInput::isInputMethodComposing() const
2514 Q_D(const QQuickTextInput);
2515 return d->preeditAreaText().length() > 0;
2518 void QQuickTextInputPrivate::init()
2520 Q_Q(QQuickTextInput);
2521 q->setSmooth(smooth);
2522 q->setAcceptedMouseButtons(Qt::LeftButton);
2523 q->setFlag(QQuickItem::ItemAcceptsInputMethod);
2524 q->setFlag(QQuickItem::ItemHasContents);
2525 #ifndef QT_NO_CLIPBOARD
2526 q->connect(QGuiApplication::clipboard(), SIGNAL(dataChanged()),
2527 q, SLOT(q_canPasteChanged()));
2528 #endif // QT_NO_CLIPBOARD
2530 lastSelectionStart = 0;
2531 lastSelectionEnd = 0;
2532 determineHorizontalAlignment();
2534 if (!qmlDisableDistanceField()) {
2535 QTextOption option = m_textLayout.textOption();
2536 option.setUseDesignMetrics(true);
2537 m_textLayout.setTextOption(option);
2541 void QQuickTextInput::updateCursorRectangle()
2543 Q_D(QQuickTextInput);
2544 if (!isComponentComplete())
2547 d->updateHorizontalScroll();
2548 d->updateVerticalScroll();
2549 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
2551 emit cursorRectangleChanged();
2552 if (d->cursorItem) {
2553 QRectF r = cursorRectangle();
2554 d->cursorItem->setPos(r.topLeft());
2555 d->cursorItem->setHeight(r.height());
2557 updateInputMethod(Qt::ImCursorRectangle);
2560 void QQuickTextInput::selectionChanged()
2562 Q_D(QQuickTextInput);
2563 d->textLayoutDirty = true; //TODO: Only update rect in selection
2564 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
2566 emit selectedTextChanged();
2568 if (d->lastSelectionStart != d->selectionStart()) {
2569 d->lastSelectionStart = d->selectionStart();
2570 if (d->lastSelectionStart == -1)
2571 d->lastSelectionStart = d->m_cursor;
2572 emit selectionStartChanged();
2574 if (d->lastSelectionEnd != d->selectionEnd()) {
2575 d->lastSelectionEnd = d->selectionEnd();
2576 if (d->lastSelectionEnd == -1)
2577 d->lastSelectionEnd = d->m_cursor;
2578 emit selectionEndChanged();
2582 void QQuickTextInputPrivate::showCursor()
2584 if (textNode != 0 && textNode->cursorNode() != 0)
2585 textNode->cursorNode()->setColor(color);
2588 void QQuickTextInputPrivate::hideCursor()
2590 if (textNode != 0 && textNode->cursorNode() != 0)
2591 textNode->cursorNode()->setColor(QColor(0, 0, 0, 0));
2594 QRectF QQuickTextInput::boundingRect() const
2596 Q_D(const QQuickTextInput);
2598 int cursorWidth = d->cursorItem ? d->cursorItem->width() : 1;
2600 // Could include font max left/right bearings to either side of rectangle.
2601 QRectF r = QQuickImplicitSizeItem::boundingRect();
2602 r.setRight(r.right() + cursorWidth);
2606 void QQuickTextInput::q_canPasteChanged()
2608 Q_D(QQuickTextInput);
2609 bool old = d->canPaste;
2610 #ifndef QT_NO_CLIPBOARD
2611 if (const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData())
2612 d->canPaste = !d->m_readOnly && mimeData->hasText();
2614 d->canPaste = false;
2617 bool changed = d->canPaste != old || !d->canPasteValid;
2618 d->canPasteValid = true;
2620 emit canPasteChanged();
2624 void QQuickTextInput::q_updateAlignment()
2626 Q_D(QQuickTextInput);
2627 if (d->determineHorizontalAlignment()) {
2629 updateCursorRectangle();
2633 // ### these should come from QStyleHints
2634 const int textCursorWidth = 1;
2635 const bool fullWidthSelection = true;
2640 Updates the display text based of the current edit text
2641 If the text has changed will emit displayTextChanged()
2643 void QQuickTextInputPrivate::updateDisplayText(bool forceUpdate)
2645 QString orig = m_textLayout.text();
2647 if (m_echoMode == QQuickTextInput::NoEcho)
2648 str = QString::fromLatin1("");
2652 if (m_echoMode == QQuickTextInput::Password) {
2653 str.fill(m_passwordCharacter);
2654 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
2655 if (m_passwordEchoTimer.isActive() && m_cursor > 0 && m_cursor <= m_text.length()) {
2656 int cursor = m_cursor - 1;
2657 QChar uc = m_text.at(cursor);
2659 if (cursor > 0 && uc.unicode() >= 0xdc00 && uc.unicode() < 0xe000) {
2660 // second half of a surrogate, check if we have the first half as well,
2661 // if yes restore both at once
2662 uc = m_text.at(cursor - 1);
2663 if (uc.unicode() >= 0xd800 && uc.unicode() < 0xdc00)
2664 str[cursor - 1] = uc;
2668 } else if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit && !m_passwordEchoEditing) {
2669 str.fill(m_passwordCharacter);
2672 // replace certain non-printable characters with spaces (to avoid
2673 // drawing boxes when using fonts that don't have glyphs for such
2675 QChar* uc = str.data();
2676 for (int i = 0; i < (int)str.length(); ++i) {
2677 if ((uc[i] < 0x20 && uc[i] != 0x09)
2678 || uc[i] == QChar::LineSeparator
2679 || uc[i] == QChar::ParagraphSeparator
2680 || uc[i] == QChar::ObjectReplacementCharacter)
2681 uc[i] = QChar(0x0020);
2684 if (str != orig || forceUpdate) {
2685 m_textLayout.setText(str);
2686 updateLayout(); // polish?
2687 emit q_func()->displayTextChanged();
2691 void QQuickTextInputPrivate::updateLayout()
2693 Q_Q(QQuickTextInput);
2695 if (!q->isComponentComplete())
2698 const QRectF previousRect = boundingRect;
2700 QTextOption option = m_textLayout.textOption();
2701 option.setTextDirection(layoutDirection());
2702 option.setFlags(QTextOption::IncludeTrailingSpaces);
2703 option.setWrapMode(QTextOption::WrapMode(wrapMode));
2704 option.setAlignment(Qt::Alignment(q->effectiveHAlign()));
2705 m_textLayout.setTextOption(option);
2706 m_textLayout.setFont(font);
2708 boundingRect = QRectF();
2709 m_textLayout.beginLayout();
2710 QTextLine line = m_textLayout.createLine();
2711 qreal lineWidth = q->widthValid() ? q->width() : INT_MAX;
2713 QTextLine firstLine = line;
2715 line.setLineWidth(lineWidth);
2716 line.setPosition(QPointF(line.position().x(), height));
2717 boundingRect = boundingRect.united(line.naturalTextRect());
2719 height += line.height();
2720 line = m_textLayout.createLine();
2721 } while (line.isValid());
2722 m_textLayout.endLayout();
2724 option.setWrapMode(QTextOption::NoWrap);
2725 m_textLayout.setTextOption(option);
2727 textLayoutDirty = true;
2729 updateType = UpdatePaintNode;
2731 q->setImplicitSize(boundingRect.width(), boundingRect.height());
2733 if (previousRect != boundingRect)
2734 emit q->contentSizeChanged();
2737 #ifndef QT_NO_CLIPBOARD
2741 Copies the currently selected text into the clipboard using the given
2744 \note If the echo mode is set to a mode other than Normal then copy
2745 will not work. This is to prevent using copy as a method of bypassing
2746 password features of the line control.
2748 void QQuickTextInputPrivate::copy(QClipboard::Mode mode) const
2750 QString t = selectedText();
2751 if (!t.isEmpty() && m_echoMode == QQuickTextInput::Normal) {
2752 QGuiApplication::clipboard()->setText(t, mode);
2759 Inserts the text stored in the application clipboard into the line
2764 void QQuickTextInputPrivate::paste(QClipboard::Mode clipboardMode)
2766 QString clip = QGuiApplication::clipboard()->text(clipboardMode);
2767 if (!clip.isEmpty() || hasSelectedText()) {
2768 separate(); //make it a separate undo/redo command
2774 #endif // !QT_NO_CLIPBOARD
2779 Exits preedit mode and commits parts marked as tentative commit
2781 void QQuickTextInputPrivate::commitPreedit()
2786 qApp->inputMethod()->reset();
2788 if (!m_tentativeCommit.isEmpty()) {
2789 internalInsert(m_tentativeCommit);
2790 m_tentativeCommit.clear();
2791 finishChange(-1, true/*not used, not documented*/, false);
2794 m_preeditCursor = 0;
2795 m_textLayout.setPreeditArea(-1, QString());
2796 m_textLayout.clearAdditionalFormats();
2803 Handles the behavior for the backspace key or function.
2804 Removes the current selection if there is a selection, otherwise
2805 removes the character prior to the cursor position.
2809 void QQuickTextInputPrivate::backspace()
2811 int priorState = m_undoState;
2812 if (hasSelectedText()) {
2813 removeSelectedText();
2814 } else if (m_cursor) {
2817 m_cursor = prevMaskBlank(m_cursor);
2818 QChar uc = m_text.at(m_cursor);
2819 if (m_cursor > 0 && uc.unicode() >= 0xdc00 && uc.unicode() < 0xe000) {
2820 // second half of a surrogate, check if we have the first half as well,
2821 // if yes delete both at once
2822 uc = m_text.at(m_cursor - 1);
2823 if (uc.unicode() >= 0xd800 && uc.unicode() < 0xdc00) {
2824 internalDelete(true);
2828 internalDelete(true);
2830 finishChange(priorState);
2836 Handles the behavior for the delete key or function.
2837 Removes the current selection if there is a selection, otherwise
2838 removes the character after the cursor position.
2842 void QQuickTextInputPrivate::del()
2844 int priorState = m_undoState;
2845 if (hasSelectedText()) {
2846 removeSelectedText();
2848 int n = m_textLayout.nextCursorPosition(m_cursor) - m_cursor;
2852 finishChange(priorState);
2858 Inserts the given \a newText at the current cursor position.
2859 If there is any selected text it is removed prior to insertion of
2862 void QQuickTextInputPrivate::insert(const QString &newText)
2864 int priorState = m_undoState;
2865 removeSelectedText();
2866 internalInsert(newText);
2867 finishChange(priorState);
2873 Clears the line control text.
2875 void QQuickTextInputPrivate::clear()
2877 int priorState = m_undoState;
2879 m_selend = m_text.length();
2880 removeSelectedText();
2882 finishChange(priorState, /*update*/false, /*edited*/false);
2888 Sets \a length characters from the given \a start position as selected.
2889 The given \a start position must be within the current text for
2890 the line control. If \a length characters cannot be selected, then
2891 the selection will extend to the end of the current text.
2893 void QQuickTextInputPrivate::setSelection(int start, int length)
2895 Q_Q(QQuickTextInput);
2898 if (start < 0 || start > (int)m_text.length()){
2899 qWarning("QQuickTextInputPrivate::setSelection: Invalid start position");
2904 if (start == m_selstart && start + length == m_selend && m_cursor == m_selend)
2907 m_selend = qMin(start + length, (int)m_text.length());
2908 m_cursor = m_selend;
2909 } else if (length < 0){
2910 if (start == m_selend && start + length == m_selstart && m_cursor == m_selstart)
2912 m_selstart = qMax(start + length, 0);
2914 m_cursor = m_selstart;
2915 } else if (m_selstart != m_selend) {
2921 emitCursorPositionChanged();
2924 emit q->selectionChanged();
2925 emitCursorPositionChanged();
2926 q->updateInputMethod(Qt::ImCursorRectangle | Qt::ImAnchorPosition
2927 | Qt::ImCursorPosition | Qt::ImCurrentSelection);
2933 Initializes the line control with a starting text value of \a txt.
2935 void QQuickTextInputPrivate::init(const QString &txt)
2939 updateDisplayText();
2940 m_cursor = m_text.length();
2946 Sets the password echo editing to \a editing. If password echo editing
2947 is true, then the text of the password is displayed even if the echo
2948 mode is set to QLineEdit::PasswordEchoOnEdit. Password echoing editing
2949 does not affect other echo modes.
2951 void QQuickTextInputPrivate::updatePasswordEchoEditing(bool editing)
2953 cancelPasswordEchoTimer();
2954 m_passwordEchoEditing = editing;
2955 updateDisplayText();
2961 Fixes the current text so that it is valid given any set validators.
2963 Returns true if the text was changed. Otherwise returns false.
2965 bool QQuickTextInputPrivate::fixup() // this function assumes that validate currently returns != Acceptable
2967 #ifndef QT_NO_VALIDATOR
2969 QString textCopy = m_text;
2970 int cursorCopy = m_cursor;
2971 m_validator->fixup(textCopy);
2972 if (m_validator->validate(textCopy, cursorCopy) == QValidator::Acceptable) {
2973 if (textCopy != m_text || cursorCopy != m_cursor)
2974 internalSetText(textCopy, cursorCopy);
2985 Moves the cursor to the given position \a pos. If \a mark is true will
2986 adjust the currently selected text.
2988 void QQuickTextInputPrivate::moveCursor(int pos, bool mark)
2990 Q_Q(QQuickTextInput);
2993 if (pos != m_cursor) {
2996 pos = pos > m_cursor ? nextMaskBlank(pos) : prevMaskBlank(pos);
3000 if (m_selend > m_selstart && m_cursor == m_selstart)
3002 else if (m_selend > m_selstart && m_cursor == m_selend)
3003 anchor = m_selstart;
3006 m_selstart = qMin(anchor, pos);
3007 m_selend = qMax(anchor, pos);
3012 if (mark || m_selDirty) {
3014 emit q->selectionChanged();
3016 emitCursorPositionChanged();
3017 q->updateInputMethod();
3023 Applies the given input method event \a event to the text of the line
3026 void QQuickTextInputPrivate::processInputMethodEvent(QInputMethodEvent *event)
3028 Q_Q(QQuickTextInput);
3030 int priorState = -1;
3031 bool isGettingInput = !event->commitString().isEmpty()
3032 || event->preeditString() != preeditAreaText()
3033 || event->replacementLength() > 0;
3034 bool cursorPositionChanged = false;
3035 bool selectionChange = false;
3036 m_preeditDirty = event->preeditString() != preeditAreaText();
3038 if (isGettingInput) {
3039 // If any text is being input, remove selected text.
3040 priorState = m_undoState;
3041 if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit && !m_passwordEchoEditing) {
3042 updatePasswordEchoEditing(true);
3044 m_selend = m_text.length();
3046 removeSelectedText();
3049 int c = m_cursor; // cursor position after insertion of commit string
3050 if (event->replacementStart() <= 0)
3051 c += event->commitString().length() - qMin(-event->replacementStart(), event->replacementLength());
3053 m_cursor += event->replacementStart();
3057 // insert commit string
3058 if (event->replacementLength()) {
3059 m_selstart = m_cursor;
3060 m_selend = m_selstart + event->replacementLength();
3061 m_selend = qMin(m_selend, m_text.length());
3062 removeSelectedText();
3064 if (!event->commitString().isEmpty()) {
3065 internalInsert(event->commitString());
3066 cursorPositionChanged = true;
3069 m_cursor = qBound(0, c, m_text.length());
3071 for (int i = 0; i < event->attributes().size(); ++i) {
3072 const QInputMethodEvent::Attribute &a = event->attributes().at(i);
3073 if (a.type == QInputMethodEvent::Selection) {
3074 m_cursor = qBound(0, a.start + a.length, m_text.length());
3076 m_selstart = qMax(0, qMin(a.start, m_text.length()));
3077 m_selend = m_cursor;
3078 if (m_selend < m_selstart) {
3079 qSwap(m_selstart, m_selend);
3081 selectionChange = true;
3083 m_selstart = m_selend = 0;
3085 cursorPositionChanged = true;
3089 m_textLayout.setPreeditArea(m_cursor, event->preeditString());
3091 const int oldPreeditCursor = m_preeditCursor;
3092 m_preeditCursor = event->preeditString().length();
3093 m_hideCursor = false;
3094 QList<QTextLayout::FormatRange> formats;
3095 for (int i = 0; i < event->attributes().size(); ++i) {
3096 const QInputMethodEvent::Attribute &a = event->attributes().at(i);
3097 if (a.type == QInputMethodEvent::Cursor) {
3098 m_preeditCursor = a.start;
3099 m_hideCursor = !a.length;
3100 } else if (a.type == QInputMethodEvent::TextFormat) {
3101 QTextCharFormat f = qvariant_cast<QTextFormat>(a.value).toCharFormat();
3103 QTextLayout::FormatRange o;
3104 o.start = a.start + m_cursor;
3105 o.length = a.length;
3111 m_textLayout.setAdditionalFormats(formats);
3113 updateDisplayText(/*force*/ true);
3114 if (cursorPositionChanged) {
3115 emitCursorPositionChanged();
3116 } else if (m_preeditCursor != oldPreeditCursor) {
3117 q->updateCursorRectangle();
3120 bool tentativeCommitChanged = m_tentativeCommit != event->tentativeCommitString();
3122 if (tentativeCommitChanged) {
3124 m_tentativeCommit = event->tentativeCommitString();
3127 if (isGettingInput || tentativeCommitChanged)
3128 finishChange(priorState);
3130 if (selectionChange) {
3131 emit q->selectionChanged();
3132 q->updateInputMethod(Qt::ImCursorRectangle | Qt::ImAnchorPosition
3133 | Qt::ImCursorPosition | Qt::ImCurrentSelection);
3140 Sets the selection to cover the word at the given cursor position.
3141 The word boundaries are defined by the behavior of QTextLayout::SkipWords
3144 void QQuickTextInputPrivate::selectWordAtPos(int cursor)
3146 int next = cursor + 1;
3149 int c = m_textLayout.previousCursorPosition(next, QTextLayout::SkipWords);
3150 moveCursor(c, false);
3151 // ## text layout should support end of words.
3152 int end = m_textLayout.nextCursorPosition(c, QTextLayout::SkipWords);
3153 while (end > cursor && m_text[end-1].isSpace())
3155 moveCursor(end, true);
3161 Completes a change to the line control text. If the change is not valid
3162 will undo the line control state back to the given \a validateFromState.
3164 If \a edited is true and the change is valid, will emit textEdited() in
3165 addition to textChanged(). Otherwise only emits textChanged() on a valid
3168 The \a update value is currently unused.
3170 bool QQuickTextInputPrivate::finishChange(int validateFromState, bool update, bool /*edited*/)
3172 Q_Q(QQuickTextInput);
3175 bool inputMethodAttributesChanged = m_textDirty || m_selDirty;
3176 bool alignmentChanged = false;
3180 bool wasValidInput = m_validInput;
3181 bool wasAcceptable = m_acceptableInput;
3182 m_validInput = true;
3183 m_acceptableInput = true;
3184 #ifndef QT_NO_VALIDATOR
3186 QString textCopy = m_text;
3187 int cursorCopy = m_cursor;
3188 QValidator::State state = m_validator->validate(textCopy, cursorCopy);
3189 m_validInput = state != QValidator::Invalid;
3190 m_acceptableInput = state == QValidator::Acceptable;
3192 if (m_text != textCopy) {
3193 internalSetText(textCopy, cursorCopy);
3196 m_cursor = cursorCopy;
3198 if (!m_tentativeCommit.isEmpty()) {
3199 textCopy.insert(m_cursor, m_tentativeCommit);
3200 bool validInput = m_validator->validate(textCopy, cursorCopy) != QValidator::Invalid;
3202 m_tentativeCommit.clear();
3205 m_tentativeCommit.clear();
3209 if (validateFromState >= 0 && wasValidInput && !m_validInput) {
3210 if (m_transactions.count())
3212 internalUndo(validateFromState);
3213 m_history.resize(m_undoState);
3214 m_validInput = true;
3215 m_acceptableInput = wasAcceptable;
3216 m_textDirty = false;
3220 m_textDirty = false;
3221 m_preeditDirty = false;
3222 alignmentChanged = determineHorizontalAlignment();
3223 emit q->textChanged();
3226 updateDisplayText(alignmentChanged);
3228 if (m_acceptableInput != wasAcceptable)
3229 emit q->acceptableInputChanged();
3231 if (m_preeditDirty) {
3232 m_preeditDirty = false;
3233 if (determineHorizontalAlignment()) {
3234 alignmentChanged = true;
3241 emit q->selectionChanged();
3244 inputMethodAttributesChanged |= (m_cursor == m_lastCursorPos);
3245 if (inputMethodAttributesChanged)
3246 q->updateInputMethod();
3247 emitUndoRedoChanged();
3249 if (!emitCursorPositionChanged() && alignmentChanged)
3250 q->updateCursorRectangle();
3258 An internal function for setting the text of the line control.
3260 void QQuickTextInputPrivate::internalSetText(const QString &txt, int pos, bool edited)
3262 Q_Q(QQuickTextInput);
3264 QString oldText = m_text;
3266 m_text = maskString(0, txt, true);
3267 m_text += clearString(m_text.length(), m_maxLength - m_text.length());
3269 m_text = txt.isEmpty() ? txt : txt.left(m_maxLength);
3273 m_cursor = (pos < 0 || pos > m_text.length()) ? m_text.length() : pos;
3274 m_textDirty = (oldText != m_text);
3276 bool changed = finishChange(-1, true, edited);
3277 #ifdef QT_NO_ACCESSIBILITY
3281 QAccessible::updateAccessibility(QAccessibleEvent(QAccessible::TextUpdated, q, 0));
3289 Adds the given \a command to the undo history
3290 of the line control. Does not apply the command.
3292 void QQuickTextInputPrivate::addCommand(const Command &cmd)
3294 if (m_separator && m_undoState && m_history[m_undoState - 1].type != Separator) {
3295 m_history.resize(m_undoState + 2);
3296 m_history[m_undoState++] = Command(Separator, m_cursor, 0, m_selstart, m_selend);
3298 m_history.resize(m_undoState + 1);
3300 m_separator = false;
3301 m_history[m_undoState++] = cmd;
3307 Inserts the given string \a s into the line
3310 Also adds the appropriate commands into the undo history.
3311 This function does not call finishChange(), and may leave the text
3312 in an invalid state.
3314 void QQuickTextInputPrivate::internalInsert(const QString &s)
3316 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
3317 Q_Q(QQuickTextInput);
3318 if (m_echoMode == QQuickTextInput::Password)
3319 m_passwordEchoTimer.start(qt_passwordEchoDelay, q);
3321 if (hasSelectedText())
3322 addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
3324 QString ms = maskString(m_cursor, s);
3325 for (int i = 0; i < (int) ms.length(); ++i) {
3326 addCommand (Command(DeleteSelection, m_cursor + i, m_text.at(m_cursor + i), -1, -1));
3327 addCommand(Command(Insert, m_cursor + i, ms.at(i), -1, -1));
3329 m_text.replace(m_cursor, ms.length(), ms);
3330 m_cursor += ms.length();
3331 m_cursor = nextMaskBlank(m_cursor);
3334 int remaining = m_maxLength - m_text.length();
3335 if (remaining != 0) {
3336 m_text.insert(m_cursor, s.left(remaining));
3337 for (int i = 0; i < (int) s.left(remaining).length(); ++i)
3338 addCommand(Command(Insert, m_cursor++, s.at(i), -1, -1));
3347 deletes a single character from the current text. If \a wasBackspace,
3348 the character prior to the cursor is removed. Otherwise the character
3349 after the cursor is removed.
3351 Also adds the appropriate commands into the undo history.
3352 This function does not call finishChange(), and may leave the text
3353 in an invalid state.
3355 void QQuickTextInputPrivate::internalDelete(bool wasBackspace)
3357 if (m_cursor < (int) m_text.length()) {
3358 cancelPasswordEchoTimer();
3359 if (hasSelectedText())
3360 addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
3361 addCommand(Command((CommandType)((m_maskData ? 2 : 0) + (wasBackspace ? Remove : Delete)),
3362 m_cursor, m_text.at(m_cursor), -1, -1));
3364 m_text.replace(m_cursor, 1, clearString(m_cursor, 1));
3365 addCommand(Command(Insert, m_cursor, m_text.at(m_cursor), -1, -1));
3367 m_text.remove(m_cursor, 1);
3376 removes the currently selected text from the line control.
3378 Also adds the appropriate commands into the undo history.
3379 This function does not call finishChange(), and may leave the text
3380 in an invalid state.
3382 void QQuickTextInputPrivate::removeSelectedText()
3384 if (m_selstart < m_selend && m_selend <= (int) m_text.length()) {
3385 cancelPasswordEchoTimer();
3388 addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
3389 if (m_selstart <= m_cursor && m_cursor < m_selend) {
3390 // cursor is within the selection. Split up the commands
3391 // to be able to restore the correct cursor position
3392 for (i = m_cursor; i >= m_selstart; --i)
3393 addCommand (Command(DeleteSelection, i, m_text.at(i), -1, 1));
3394 for (i = m_selend - 1; i > m_cursor; --i)
3395 addCommand (Command(DeleteSelection, i - m_cursor + m_selstart - 1, m_text.at(i), -1, -1));
3397 for (i = m_selend-1; i >= m_selstart; --i)
3398 addCommand (Command(RemoveSelection, i, m_text.at(i), -1, -1));
3401 m_text.replace(m_selstart, m_selend - m_selstart, clearString(m_selstart, m_selend - m_selstart));
3402 for (int i = 0; i < m_selend - m_selstart; ++i)
3403 addCommand(Command(Insert, m_selstart + i, m_text.at(m_selstart + i), -1, -1));
3405 m_text.remove(m_selstart, m_selend - m_selstart);
3407 if (m_cursor > m_selstart)
3408 m_cursor -= qMin(m_cursor, m_selend) - m_selstart;
3417 Parses the input mask specified by \a maskFields to generate
3418 the mask data used to handle input masks.
3420 void QQuickTextInputPrivate::parseInputMask(const QString &maskFields)
3422 int delimiter = maskFields.indexOf(QLatin1Char(';'));
3423 if (maskFields.isEmpty() || delimiter == 0) {
3425 delete [] m_maskData;
3427 m_maxLength = 32767;
3428 internalSetText(QString());
3433 if (delimiter == -1) {
3434 m_blank = QLatin1Char(' ');
3435 m_inputMask = maskFields;
3437 m_inputMask = maskFields.left(delimiter);
3438 m_blank = (delimiter + 1 < maskFields.length()) ? maskFields[delimiter + 1] : QLatin1Char(' ');
3441 // calculate m_maxLength / m_maskData length
3444 for (int i=0; i<m_inputMask.length(); i++) {
3445 c = m_inputMask.at(i);
3446 if (i > 0 && m_inputMask.at(i-1) == QLatin1Char('\\')) {
3450 if (c != QLatin1Char('\\') && c != QLatin1Char('!') &&
3451 c != QLatin1Char('<') && c != QLatin1Char('>') &&
3452 c != QLatin1Char('{') && c != QLatin1Char('}') &&
3453 c != QLatin1Char('[') && c != QLatin1Char(']'))
3457 delete [] m_maskData;
3458 m_maskData = new MaskInputData[m_maxLength];
3460 MaskInputData::Casemode m = MaskInputData::NoCaseMode;
3463 bool escape = false;
3465 for (int i = 0; i < m_inputMask.length(); i++) {
3466 c = m_inputMask.at(i);
3469 m_maskData[index].maskChar = c;
3470 m_maskData[index].separator = s;
3471 m_maskData[index].caseMode = m;
3474 } else if (c == QLatin1Char('<')) {
3475 m = MaskInputData::Lower;
3476 } else if (c == QLatin1Char('>')) {
3477 m = MaskInputData::Upper;
3478 } else if (c == QLatin1Char('!')) {
3479 m = MaskInputData::NoCaseMode;
3480 } else if (c != QLatin1Char('{') && c != QLatin1Char('}') && c != QLatin1Char('[') && c != QLatin1Char(']')) {
3481 switch (c.unicode()) {
3507 m_maskData[index].maskChar = c;
3508 m_maskData[index].separator = s;
3509 m_maskData[index].caseMode = m;
3514 internalSetText(m_text);
3521 checks if the key is valid compared to the inputMask
3523 bool QQuickTextInputPrivate::isValidInput(QChar key, QChar mask) const
3525 switch (mask.unicode()) {
3531 if (key.isLetter() || key == m_blank)
3535 if (key.isLetterOrNumber())
3539 if (key.isLetterOrNumber() || key == m_blank)
3547 if (key.isPrint() || key == m_blank)
3555 if (key.isNumber() || key == m_blank)
3559 if (key.isNumber() && key.digitValue() > 0)
3563 if ((key.isNumber() && key.digitValue() > 0) || key == m_blank)
3567 if (key.isNumber() || key == QLatin1Char('+') || key == QLatin1Char('-') || key == m_blank)
3571 if (key == QLatin1Char('0') || key == QLatin1Char('1'))
3575 if (key == QLatin1Char('0') || key == QLatin1Char('1') || key == m_blank)
3579 if (key.isNumber() || (key >= QLatin1Char('a') && key <= QLatin1Char('f')) || (key >= QLatin1Char('A') && key <= QLatin1Char('F')))
3583 if (key.isNumber() || (key >= QLatin1Char('a') && key <= QLatin1Char('f')) || (key >= QLatin1Char('A') && key <= QLatin1Char('F')) || key == m_blank)
3595 Returns true if the given text \a str is valid for any
3596 validator or input mask set for the line control.
3598 Otherwise returns false
3600 QQuickTextInputPrivate::ValidatorState QQuickTextInputPrivate::hasAcceptableInput(const QString &str) const
3602 #ifndef QT_NO_VALIDATOR
3603 QString textCopy = str;
3604 int cursorCopy = m_cursor;
3606 QValidator::State state = m_validator->validate(textCopy, cursorCopy);
3607 if (state != QValidator::Acceptable)
3608 return ValidatorState(state);
3613 return AcceptableInput;
3615 if (str.length() != m_maxLength)
3616 return InvalidInput;
3618 for (int i=0; i < m_maxLength; ++i) {
3619 if (m_maskData[i].separator) {
3620 if (str.at(i) != m_maskData[i].maskChar)
3621 return InvalidInput;
3623 if (!isValidInput(str.at(i), m_maskData[i].maskChar))
3624 return InvalidInput;
3627 return AcceptableInput;
3633 Applies the inputMask on \a str starting from position \a pos in the mask. \a clear
3634 specifies from where characters should be gotten when a separator is met in \a str - true means
3635 that blanks will be used, false that previous input is used.
3636 Calling this when no inputMask is set is undefined.
3638 QString QQuickTextInputPrivate::maskString(uint pos, const QString &str, bool clear) const
3640 if (pos >= (uint)m_maxLength)
3641 return QString::fromLatin1("");
3644 fill = clear ? clearString(0, m_maxLength) : m_text;
3647 QString s = QString::fromLatin1("");
3649 while (i < m_maxLength) {
3650 if (strIndex < str.length()) {
3651 if (m_maskData[i].separator) {
3652 s += m_maskData[i].maskChar;
3653 if (str[(int)strIndex] == m_maskData[i].maskChar)
3657 if (isValidInput(str[(int)strIndex], m_maskData[i].maskChar)) {
3658 switch (m_maskData[i].caseMode) {
3659 case MaskInputData::Upper:
3660 s += str[(int)strIndex].toUpper();
3662 case MaskInputData::Lower:
3663 s += str[(int)strIndex].toLower();
3666 s += str[(int)strIndex];
3670 // search for separator first
3671 int n = findInMask(i, true, true, str[(int)strIndex]);
3673 if (str.length() != 1 || i == 0 || (i > 0 && (!m_maskData[i-1].separator || m_maskData[i-1].maskChar != str[(int)strIndex]))) {
3674 s += fill.mid(i, n-i+1);
3675 i = n + 1; // update i to find + 1
3678 // search for valid m_blank if not
3679 n = findInMask(i, true, false, str[(int)strIndex]);
3681 s += fill.mid(i, n-i);
3682 switch (m_maskData[n].caseMode) {
3683 case MaskInputData::Upper:
3684 s += str[(int)strIndex].toUpper();
3686 case MaskInputData::Lower:
3687 s += str[(int)strIndex].toLower();
3690 s += str[(int)strIndex];
3692 i = n + 1; // updates i to find + 1
3710 Returns a "cleared" string with only separators and blank chars.
3711 Calling this when no inputMask is set is undefined.
3713 QString QQuickTextInputPrivate::clearString(uint pos, uint len) const
3715 if (pos >= (uint)m_maxLength)
3719 int end = qMin((uint)m_maxLength, pos + len);
3720 for (int i = pos; i < end; ++i)
3721 if (m_maskData[i].separator)
3722 s += m_maskData[i].maskChar;
3732 Strips blank parts of the input in a QQuickTextInputPrivate when an inputMask is set,
3733 separators are still included. Typically "127.0__.0__.1__" becomes "127.0.0.1".
3735 QString QQuickTextInputPrivate::stripString(const QString &str) const
3741 int end = qMin(m_maxLength, (int)str.length());
3742 for (int i = 0; i < end; ++i) {
3743 if (m_maskData[i].separator)
3744 s += m_maskData[i].maskChar;
3745 else if (str[i] != m_blank)
3754 searches forward/backward in m_maskData for either a separator or a m_blank
3756 int QQuickTextInputPrivate::findInMask(int pos, bool forward, bool findSeparator, QChar searchChar) const
3758 if (pos >= m_maxLength || pos < 0)
3761 int end = forward ? m_maxLength : -1;
3762 int step = forward ? 1 : -1;
3766 if (findSeparator) {
3767 if (m_maskData[i].separator && m_maskData[i].maskChar == searchChar)
3770 if (!m_maskData[i].separator) {
3771 if (searchChar.isNull())
3773 else if (isValidInput(searchChar, m_maskData[i].maskChar))
3782 void QQuickTextInputPrivate::internalUndo(int until)
3784 if (!isUndoAvailable())
3786 cancelPasswordEchoTimer();
3788 while (m_undoState && m_undoState > until) {
3789 Command& cmd = m_history[--m_undoState];
3792 m_text.remove(cmd.pos, 1);
3796 m_selstart = cmd.selStart;
3797 m_selend = cmd.selEnd;
3801 case RemoveSelection:
3802 m_text.insert(cmd.pos, cmd.uc);
3803 m_cursor = cmd.pos + 1;
3806 case DeleteSelection:
3807 m_text.insert(cmd.pos, cmd.uc);
3813 if (until < 0 && m_undoState) {
3814 Command& next = m_history[m_undoState-1];
3815 if (next.type != cmd.type && next.type < RemoveSelection
3816 && (cmd.type < RemoveSelection || next.type == Separator))
3823 void QQuickTextInputPrivate::internalRedo()
3825 if (!isRedoAvailable())
3828 while (m_undoState < (int)m_history.size()) {
3829 Command& cmd = m_history[m_undoState++];
3832 m_text.insert(cmd.pos, cmd.uc);
3833 m_cursor = cmd.pos + 1;
3836 m_selstart = cmd.selStart;
3837 m_selend = cmd.selEnd;
3842 case RemoveSelection:
3843 case DeleteSelection:
3844 m_text.remove(cmd.pos, 1);
3845 m_selstart = cmd.selStart;
3846 m_selend = cmd.selEnd;
3850 m_selstart = cmd.selStart;
3851 m_selend = cmd.selEnd;
3855 if (m_undoState < (int)m_history.size()) {
3856 Command& next = m_history[m_undoState];
3857 if (next.type != cmd.type && cmd.type < RemoveSelection && next.type != Separator
3858 && (next.type < RemoveSelection || cmd.type == Separator))
3865 void QQuickTextInputPrivate::emitUndoRedoChanged()
3867 Q_Q(QQuickTextInput);
3868 const bool previousUndo = canUndo;
3869 const bool previousRedo = canRedo;
3871 canUndo = isUndoAvailable();
3872 canRedo = isRedoAvailable();
3874 if (previousUndo != canUndo)
3875 emit q->canUndoChanged();
3876 if (previousRedo != canRedo)
3877 emit q->canRedoChanged();
3883 If the current cursor position differs from the last emitted cursor
3884 position, emits cursorPositionChanged().
3886 bool QQuickTextInputPrivate::emitCursorPositionChanged()
3888 Q_Q(QQuickTextInput);
3889 if (m_cursor != m_lastCursorPos) {
3890 m_lastCursorPos = m_cursor;
3892 q->updateCursorRectangle();
3893 emit q->cursorPositionChanged();
3895 if (!hasSelectedText()) {
3896 if (lastSelectionStart != m_cursor) {
3897 lastSelectionStart = m_cursor;
3898 emit q->selectionStartChanged();
3900 if (lastSelectionEnd != m_cursor) {
3901 lastSelectionEnd = m_cursor;
3902 emit q->selectionEndChanged();
3906 #ifndef QT_NO_ACCESSIBILITY
3907 QAccessible::updateAccessibility(QAccessibleEvent(QAccessible::TextCaretMoved, q, 0));
3916 void QQuickTextInputPrivate::setCursorBlinkPeriod(int msec)
3918 Q_Q(QQuickTextInput);
3919 if (msec == m_blinkPeriod)
3922 q->killTimer(m_blinkTimer);
3925 m_blinkTimer = q->startTimer(msec / 2);
3929 if (m_blinkStatus == 1) {
3930 updateType = UpdatePaintNode;
3934 m_blinkPeriod = msec;
3937 void QQuickTextInput::timerEvent(QTimerEvent *event)
3939 Q_D(QQuickTextInput);
3940 if (event->timerId() == d->m_blinkTimer) {
3941 d->m_blinkStatus = !d->m_blinkStatus;
3942 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
3944 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
3945 } else if (event->timerId() == d->m_passwordEchoTimer.timerId()) {
3946 d->m_passwordEchoTimer.stop();
3947 d->updateDisplayText();
3952 void QQuickTextInputPrivate::processKeyEvent(QKeyEvent* event)
3954 Q_Q(QQuickTextInput);
3955 bool inlineCompletionAccepted = false;
3957 if (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return) {
3958 if (hasAcceptableInput(m_text) || fixup()) {
3961 if (inlineCompletionAccepted)
3968 if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit
3969 && !m_passwordEchoEditing
3971 && !event->text().isEmpty()
3972 && !(event->modifiers() & Qt::ControlModifier)) {
3973 // Clear the edit and reset to normal echo mode while editing; the
3974 // echo mode switches back when the edit loses focus
3975 // ### resets current content. dubious code; you can
3976 // navigate with keys up, down, back, and select(?), but if you press
3977 // "left" or "right" it clears?
3978 updatePasswordEchoEditing(true);
3982 bool unknown = false;
3983 bool visual = cursorMoveStyle() == Qt::VisualMoveStyle;
3987 #ifndef QT_NO_SHORTCUT
3988 else if (event == QKeySequence::Undo) {
3992 else if (event == QKeySequence::Redo) {
3996 else if (event == QKeySequence::SelectAll) {
3999 #ifndef QT_NO_CLIPBOARD
4000 else if (event == QKeySequence::Copy) {
4003 else if (event == QKeySequence::Paste) {
4005 QClipboard::Mode mode = QClipboard::Clipboard;
4009 else if (event == QKeySequence::Cut) {
4015 else if (event == QKeySequence::DeleteEndOfLine) {
4017 setSelection(m_cursor, end());
4022 #endif //QT_NO_CLIPBOARD
4023 else if (event == QKeySequence::MoveToStartOfLine || event == QKeySequence::MoveToStartOfBlock) {
4026 else if (event == QKeySequence::MoveToEndOfLine || event == QKeySequence::MoveToEndOfBlock) {
4029 else if (event == QKeySequence::SelectStartOfLine || event == QKeySequence::SelectStartOfBlock) {
4032 else if (event == QKeySequence::SelectEndOfLine || event == QKeySequence::SelectEndOfBlock) {
4035 else if (event == QKeySequence::MoveToNextChar) {
4036 if (hasSelectedText()) {
4037 moveCursor(selectionEnd(), false);
4039 cursorForward(0, visual ? 1 : (layoutDirection() == Qt::LeftToRight ? 1 : -1));
4042 else if (event == QKeySequence::SelectNextChar) {
4043 cursorForward(1, visual ? 1 : (layoutDirection() == Qt::LeftToRight ? 1 : -1));
4045 else if (event == QKeySequence::MoveToPreviousChar) {
4046 if (hasSelectedText()) {
4047 moveCursor(selectionStart(), false);
4049 cursorForward(0, visual ? -1 : (layoutDirection() == Qt::LeftToRight ? -1 : 1));
4052 else if (event == QKeySequence::SelectPreviousChar) {
4053 cursorForward(1, visual ? -1 : (layoutDirection() == Qt::LeftToRight ? -1 : 1));
4055 else if (event == QKeySequence::MoveToNextWord) {
4056 if (m_echoMode == QQuickTextInput::Normal)
4057 layoutDirection() == Qt::LeftToRight ? cursorWordForward(0) : cursorWordBackward(0);
4059 layoutDirection() == Qt::LeftToRight ? end(0) : home(0);
4061 else if (event == QKeySequence::MoveToPreviousWord) {
4062 if (m_echoMode == QQuickTextInput::Normal)
4063 layoutDirection() == Qt::LeftToRight ? cursorWordBackward(0) : cursorWordForward(0);
4064 else if (!m_readOnly) {
4065 layoutDirection() == Qt::LeftToRight ? home(0) : end(0);
4068 else if (event == QKeySequence::SelectNextWord) {
4069 if (m_echoMode == QQuickTextInput::Normal)
4070 layoutDirection() == Qt::LeftToRight ? cursorWordForward(1) : cursorWordBackward(1);
4072 layoutDirection() == Qt::LeftToRight ? end(1) : home(1);
4074 else if (event == QKeySequence::SelectPreviousWord) {
4075 if (m_echoMode == QQuickTextInput::Normal)
4076 layoutDirection() == Qt::LeftToRight ? cursorWordBackward(1) : cursorWordForward(1);
4078 layoutDirection() == Qt::LeftToRight ? home(1) : end(1);
4080 else if (event == QKeySequence::Delete) {
4084 else if (event == QKeySequence::DeleteEndOfWord) {
4086 cursorWordForward(true);
4090 else if (event == QKeySequence::DeleteStartOfWord) {
4092 cursorWordBackward(true);
4096 #endif // QT_NO_SHORTCUT
4098 bool handled = false;
4099 if (event->modifiers() & Qt::ControlModifier) {
4100 switch (event->key()) {
4101 case Qt::Key_Backspace:
4103 cursorWordBackward(true);
4111 } else { // ### check for *no* modifier
4112 switch (event->key()) {
4113 case Qt::Key_Backspace:
4125 if (event->key() == Qt::Key_Direction_L || event->key() == Qt::Key_Direction_R) {
4126 setLayoutDirection((event->key() == Qt::Key_Direction_L) ? Qt::LeftToRight : Qt::RightToLeft);
4130 if (unknown && !m_readOnly) {
4131 QString t = event->text();
4132 if (!t.isEmpty() && t.at(0).isPrint()) {