Defer construction of TextEdit/TextInput delegates.
[profile/ivi/qtdeclarative.git] / src / quick / items / qquicktextinput.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the QtQml module of the Qt Toolkit.
7 **
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.
16 **
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.
20 **
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.
28 **
29 ** Other Usage
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.
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qquicktextinput_p.h"
43 #include "qquicktextinput_p_p.h"
44 #include "qquickcanvas.h"
45 #include "qquicktextutil_p.h"
46
47 #include <private/qqmlglobal_p.h>
48
49
50 #include <QtCore/qcoreapplication.h>
51 #include <QtQml/qqmlinfo.h>
52 #include <QtGui/qevent.h>
53 #include <QTextBoundaryFinder>
54 #include "qquicktextnode_p.h"
55 #include <QtQuick/qsgsimplerectnode.h>
56
57 #include <QtGui/qstylehints.h>
58 #include <QtGui/qinputmethod.h>
59
60 #ifndef QT_NO_ACCESSIBILITY
61 #include "qaccessible.h"
62 #endif
63
64 QT_BEGIN_NAMESPACE
65
66 DEFINE_BOOL_CONFIG_OPTION(qmlDisableDistanceField, QML_DISABLE_DISTANCEFIELD)
67
68 /*!
69     \qmlclass TextInput QQuickTextInput
70     \inqmlmodule QtQuick 2
71     \ingroup qml-basic-visual-elements
72     \brief The TextInput item displays an editable line of text.
73     \inherits Item
74
75     The TextInput element displays a single line of editable plain text.
76
77     TextInput is used to accept a line of text input. Input constraints
78     can be placed on a TextInput item (for example, through a \l validator or \l inputMask),
79     and setting \l echoMode to an appropriate value enables TextInput to be used for
80     a password input field.
81
82     On Mac OS X, the Up/Down key bindings for Home/End are explicitly disabled.
83     If you want such bindings (on any platform), you will need to construct them in QML.
84
85     \sa TextEdit, Text, {declarative/text/textselection}{Text Selection example}
86 */
87 QQuickTextInput::QQuickTextInput(QQuickItem* parent)
88 : QQuickImplicitSizeItem(*(new QQuickTextInputPrivate), parent)
89 {
90     Q_D(QQuickTextInput);
91     d->init();
92 }
93
94 QQuickTextInput::~QQuickTextInput()
95 {
96 }
97
98 void QQuickTextInput::componentComplete()
99 {
100     Q_D(QQuickTextInput);
101
102     QQuickImplicitSizeItem::componentComplete();
103
104     d->checkIsValid();
105     d->updateLayout();
106     updateCursorRectangle();
107     if (d->cursorComponent && isCursorVisible())
108         QQuickTextUtil::createCursor(d);
109 }
110
111 /*!
112     \qmlproperty string QtQuick2::TextInput::text
113
114     The text in the TextInput.
115 */
116 QString QQuickTextInput::text() const
117 {
118     Q_D(const QQuickTextInput);
119
120     QString content = d->m_text;
121     QString res = d->m_maskData ? d->stripString(content) : content;
122     return (res.isNull() ? QString::fromLatin1("") : res);
123 }
124
125 void QQuickTextInput::setText(const QString &s)
126 {
127     Q_D(QQuickTextInput);
128     if (s == text())
129         return;
130
131     d->cancelPreedit();
132     d->internalSetText(s, -1, false);
133 }
134
135 /*!
136     \qmlproperty int QtQuick2::TextInput::length
137
138     Returns the total number of characters in the TextInput item.
139
140     If the TextInput has an inputMask the length will include mask characters and may differ
141     from the length of the string returned by the \l text property.
142
143     This property can be faster than querying the length the \l text property as it doesn't
144     require any copying or conversion of the TextInput's internal string data.
145 */
146
147 int QQuickTextInput::length() const
148 {
149     Q_D(const QQuickTextInput);
150     return d->m_text.length();
151 }
152
153 /*!
154     \qmlmethod string QtQuick2::TextInput::getText(int start, int end)
155
156     Returns the section of text that is between the \a start and \a end positions.
157
158     If the TextInput has an inputMask the length will include mask characters.
159 */
160
161 QString QQuickTextInput::getText(int start, int end) const
162 {
163     Q_D(const QQuickTextInput);
164
165     if (start > end)
166         qSwap(start, end);
167
168     return d->m_text.mid(start, end - start);
169 }
170
171 QString QQuickTextInputPrivate::realText() const
172 {
173     QString res = m_maskData ? stripString(m_text) : m_text;
174     return (res.isNull() ? QString::fromLatin1("") : res);
175 }
176
177 /*!
178     \qmlproperty string QtQuick2::TextInput::font.family
179
180     Sets the family name of the font.
181
182     The family name is case insensitive and may optionally include a foundry name, e.g. "Helvetica [Cronyx]".
183     If the family is available from more than one foundry and the foundry isn't specified, an arbitrary foundry is chosen.
184     If the family isn't available a family will be set using the font matching algorithm.
185 */
186
187 /*!
188     \qmlproperty bool QtQuick2::TextInput::font.bold
189
190     Sets whether the font weight is bold.
191 */
192
193 /*!
194     \qmlproperty enumeration QtQuick2::TextInput::font.weight
195
196     Sets the font's weight.
197
198     The weight can be one of:
199     \list
200     \li Font.Light
201     \li Font.Normal - the default
202     \li Font.DemiBold
203     \li Font.Bold
204     \li Font.Black
205     \endlist
206
207     \qml
208     TextInput { text: "Hello"; font.weight: Font.DemiBold }
209     \endqml
210 */
211
212 /*!
213     \qmlproperty bool QtQuick2::TextInput::font.italic
214
215     Sets whether the font has an italic style.
216 */
217
218 /*!
219     \qmlproperty bool QtQuick2::TextInput::font.underline
220
221     Sets whether the text is underlined.
222 */
223
224 /*!
225     \qmlproperty bool QtQuick2::TextInput::font.strikeout
226
227     Sets whether the font has a strikeout style.
228 */
229
230 /*!
231     \qmlproperty real QtQuick2::TextInput::font.pointSize
232
233     Sets the font size in points. The point size must be greater than zero.
234 */
235
236 /*!
237     \qmlproperty int QtQuick2::TextInput::font.pixelSize
238
239     Sets the font size in pixels.
240
241     Using this function makes the font device dependent.
242     Use \c pointSize to set the size of the font in a device independent manner.
243 */
244
245 /*!
246     \qmlproperty real QtQuick2::TextInput::font.letterSpacing
247
248     Sets the letter spacing for the font.
249
250     Letter spacing changes the default spacing between individual letters in the font.
251     A positive value increases the letter spacing by the corresponding pixels; a negative value decreases the spacing.
252 */
253
254 /*!
255     \qmlproperty real QtQuick2::TextInput::font.wordSpacing
256
257     Sets the word spacing for the font.
258
259     Word spacing changes the default spacing between individual words.
260     A positive value increases the word spacing by a corresponding amount of pixels,
261     while a negative value decreases the inter-word spacing accordingly.
262 */
263
264 /*!
265     \qmlproperty enumeration QtQuick2::TextInput::font.capitalization
266
267     Sets the capitalization for the text.
268
269     \list
270     \li Font.MixedCase - This is the normal text rendering option where no capitalization change is applied.
271     \li Font.AllUppercase - This alters the text to be rendered in all uppercase type.
272     \li Font.AllLowercase - This alters the text to be rendered in all lowercase type.
273     \li Font.SmallCaps - This alters the text to be rendered in small-caps type.
274     \li Font.Capitalize - This alters the text to be rendered with the first character of each word as an uppercase character.
275     \endlist
276
277     \qml
278     TextInput { text: "Hello"; font.capitalization: Font.AllLowercase }
279     \endqml
280 */
281
282 QFont QQuickTextInput::font() const
283 {
284     Q_D(const QQuickTextInput);
285     return d->sourceFont;
286 }
287
288 void QQuickTextInput::setFont(const QFont &font)
289 {
290     Q_D(QQuickTextInput);
291     if (d->sourceFont == font)
292         return;
293
294     d->sourceFont = font;
295     QFont oldFont = d->font;
296     d->font = font;
297     if (d->font.pointSizeF() != -1) {
298         // 0.5pt resolution
299         qreal size = qRound(d->font.pointSizeF()*2.0);
300         d->font.setPointSizeF(size/2.0);
301     }
302     if (oldFont != d->font) {
303         d->updateLayout();
304         updateCursorRectangle();
305         updateInputMethod(Qt::ImCursorRectangle | Qt::ImFont);
306     }
307     emit fontChanged(d->sourceFont);
308 }
309
310 /*!
311     \qmlproperty color QtQuick2::TextInput::color
312
313     The text color.
314 */
315 QColor QQuickTextInput::color() const
316 {
317     Q_D(const QQuickTextInput);
318     return d->color;
319 }
320
321 void QQuickTextInput::setColor(const QColor &c)
322 {
323     Q_D(QQuickTextInput);
324     if (c != d->color) {
325         d->color = c;
326         d->textLayoutDirty = true;
327         d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
328         update();
329         emit colorChanged();
330     }
331 }
332
333
334 /*!
335     \qmlproperty color QtQuick2::TextInput::selectionColor
336
337     The text highlight color, used behind selections.
338 */
339 QColor QQuickTextInput::selectionColor() const
340 {
341     Q_D(const QQuickTextInput);
342     return d->selectionColor;
343 }
344
345 void QQuickTextInput::setSelectionColor(const QColor &color)
346 {
347     Q_D(QQuickTextInput);
348     if (d->selectionColor == color)
349         return;
350
351     d->selectionColor = color;
352     if (d->hasSelectedText()) {
353         d->textLayoutDirty = true;
354         d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
355         update();
356     }
357     emit selectionColorChanged();
358 }
359 /*!
360     \qmlproperty color QtQuick2::TextInput::selectedTextColor
361
362     The highlighted text color, used in selections.
363 */
364 QColor QQuickTextInput::selectedTextColor() const
365 {
366     Q_D(const QQuickTextInput);
367     return d->selectedTextColor;
368 }
369
370 void QQuickTextInput::setSelectedTextColor(const QColor &color)
371 {
372     Q_D(QQuickTextInput);
373     if (d->selectedTextColor == color)
374         return;
375
376     d->selectedTextColor = color;
377     if (d->hasSelectedText()) {
378         d->textLayoutDirty = true;
379         d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
380         update();
381     }
382     emit selectedTextColorChanged();
383 }
384
385 /*!
386     \qmlproperty enumeration QtQuick2::TextInput::horizontalAlignment
387     \qmlproperty enumeration QtQuick2::TextInput::effectiveHorizontalAlignment
388     \qmlproperty enumeration QtQuick2::TextInput::verticalAlignment
389
390     Sets the horizontal alignment of the text within the TextInput item's
391     width and height. By default, the text alignment follows the natural alignment
392     of the text, for example text that is read from left to right will be aligned to
393     the left.
394
395     TextInput does not have vertical alignment, as the natural height is
396     exactly the height of the single line of text. If you set the height
397     manually to something larger, TextInput will always be top aligned
398     vertically. You can use anchors to align it however you want within
399     another item.
400
401     The valid values for \c horizontalAlignment are \c TextInput.AlignLeft, \c TextInput.AlignRight and
402     \c TextInput.AlignHCenter.
403
404     Valid values for \c verticalAlignment are \c TextInput.AlignTop (default),
405     \c TextInput.AlignBottom \c TextInput.AlignVCenter.
406
407     When using the attached property LayoutMirroring::enabled to mirror application
408     layouts, the horizontal alignment of text will also be mirrored. However, the property
409     \c horizontalAlignment will remain unchanged. To query the effective horizontal alignment
410     of TextInput, use the read-only property \c effectiveHorizontalAlignment.
411 */
412 QQuickTextInput::HAlignment QQuickTextInput::hAlign() const
413 {
414     Q_D(const QQuickTextInput);
415     return d->hAlign;
416 }
417
418 void QQuickTextInput::setHAlign(HAlignment align)
419 {
420     Q_D(QQuickTextInput);
421     bool forceAlign = d->hAlignImplicit && d->effectiveLayoutMirror;
422     d->hAlignImplicit = false;
423     if (d->setHAlign(align, forceAlign) && isComponentComplete()) {
424         d->updateLayout();
425         updateCursorRectangle();
426     }
427 }
428
429 void QQuickTextInput::resetHAlign()
430 {
431     Q_D(QQuickTextInput);
432     d->hAlignImplicit = true;
433     if (d->determineHorizontalAlignment() && isComponentComplete()) {
434         d->updateLayout();
435         updateCursorRectangle();
436     }
437 }
438
439 QQuickTextInput::HAlignment QQuickTextInput::effectiveHAlign() const
440 {
441     Q_D(const QQuickTextInput);
442     QQuickTextInput::HAlignment effectiveAlignment = d->hAlign;
443     if (!d->hAlignImplicit && d->effectiveLayoutMirror) {
444         switch (d->hAlign) {
445         case QQuickTextInput::AlignLeft:
446             effectiveAlignment = QQuickTextInput::AlignRight;
447             break;
448         case QQuickTextInput::AlignRight:
449             effectiveAlignment = QQuickTextInput::AlignLeft;
450             break;
451         default:
452             break;
453         }
454     }
455     return effectiveAlignment;
456 }
457
458 bool QQuickTextInputPrivate::setHAlign(QQuickTextInput::HAlignment alignment, bool forceAlign)
459 {
460     Q_Q(QQuickTextInput);
461     if ((hAlign != alignment || forceAlign) && alignment <= QQuickTextInput::AlignHCenter) { // justify not supported
462         QQuickTextInput::HAlignment oldEffectiveHAlign = q->effectiveHAlign();
463         hAlign = alignment;
464         emit q->horizontalAlignmentChanged(alignment);
465         if (oldEffectiveHAlign != q->effectiveHAlign())
466             emit q->effectiveHorizontalAlignmentChanged();
467         return true;
468     }
469     return false;
470 }
471
472 Qt::LayoutDirection QQuickTextInputPrivate::textDirection() const
473 {
474     QString text = m_text;
475     if (text.isEmpty())
476         text = m_textLayout.preeditAreaText();
477
478     const QChar *character = text.constData();
479     while (!character->isNull()) {
480         switch (character->direction()) {
481         case QChar::DirL:
482             return Qt::LeftToRight;
483         case QChar::DirR:
484         case QChar::DirAL:
485         case QChar::DirAN:
486             return Qt::RightToLeft;
487         default:
488             break;
489         }
490         character++;
491     }
492     return Qt::LayoutDirectionAuto;
493 }
494
495 Qt::LayoutDirection QQuickTextInputPrivate::layoutDirection() const
496 {
497     Qt::LayoutDirection direction = m_layoutDirection;
498     if (direction == Qt::LayoutDirectionAuto) {
499         direction = textDirection();
500         if (direction == Qt::LayoutDirectionAuto)
501             direction = qApp->inputMethod()->inputDirection();
502     }
503     return (direction == Qt::LayoutDirectionAuto) ? Qt::LeftToRight : direction;
504 }
505
506 bool QQuickTextInputPrivate::determineHorizontalAlignment()
507 {
508     if (hAlignImplicit) {
509         // if no explicit alignment has been set, follow the natural layout direction of the text
510         Qt::LayoutDirection direction = textDirection();
511         if (direction == Qt::LayoutDirectionAuto)
512             direction = qApp->inputMethod()->inputDirection();
513         return setHAlign(direction == Qt::RightToLeft ? QQuickTextInput::AlignRight : QQuickTextInput::AlignLeft);
514     }
515     return false;
516 }
517
518 QQuickTextInput::VAlignment QQuickTextInput::vAlign() const
519 {
520     Q_D(const QQuickTextInput);
521     return d->vAlign;
522 }
523
524 void QQuickTextInput::setVAlign(QQuickTextInput::VAlignment alignment)
525 {
526     Q_D(QQuickTextInput);
527     if (alignment == d->vAlign)
528         return;
529     d->vAlign = alignment;
530     emit verticalAlignmentChanged(d->vAlign);
531     if (isComponentComplete()) {
532         updateCursorRectangle();
533     }
534 }
535
536 /*!
537     \qmlproperty enumeration QtQuick2::TextInput::wrapMode
538
539     Set this property to wrap the text to the TextInput item's width.
540     The text will only wrap if an explicit width has been set.
541
542     \list
543     \li TextInput.NoWrap - no wrapping will be performed. If the text contains insufficient newlines, then implicitWidth will exceed a set width.
544     \li TextInput.WordWrap - wrapping is done on word boundaries only. If a word is too long, implicitWidth will exceed a set width.
545     \li TextInput.WrapAnywhere - wrapping is done at any point on a line, even if it occurs in the middle of a word.
546     \li TextInput.Wrap - if possible, wrapping occurs at a word boundary; otherwise it will occur at the appropriate point on the line, even in the middle of a word.
547     \endlist
548
549     The default is TextInput.NoWrap. If you set a width, consider using TextInput.Wrap.
550 */
551 QQuickTextInput::WrapMode QQuickTextInput::wrapMode() const
552 {
553     Q_D(const QQuickTextInput);
554     return d->wrapMode;
555 }
556
557 void QQuickTextInput::setWrapMode(WrapMode mode)
558 {
559     Q_D(QQuickTextInput);
560     if (mode == d->wrapMode)
561         return;
562     d->wrapMode = mode;
563     d->updateLayout();
564     updateCursorRectangle();
565     emit wrapModeChanged();
566 }
567
568 void QQuickTextInputPrivate::mirrorChange()
569 {
570     Q_Q(QQuickTextInput);
571     if (q->isComponentComplete()) {
572         if (!hAlignImplicit && (hAlign == QQuickTextInput::AlignRight || hAlign == QQuickTextInput::AlignLeft)) {
573             q->updateCursorRectangle();
574             emit q->effectiveHorizontalAlignmentChanged();
575         }
576     }
577 }
578
579 /*!
580     \qmlproperty bool QtQuick2::TextInput::readOnly
581
582     Sets whether user input can modify the contents of the TextInput.
583
584     If readOnly is set to true, then user input will not affect the text
585     property. Any bindings or attempts to set the text property will still
586     work.
587 */
588 bool QQuickTextInput::isReadOnly() const
589 {
590     Q_D(const QQuickTextInput);
591     return d->m_readOnly;
592 }
593
594 void QQuickTextInput::setReadOnly(bool ro)
595 {
596     Q_D(QQuickTextInput);
597     if (d->m_readOnly == ro)
598         return;
599
600     setFlag(QQuickItem::ItemAcceptsInputMethod, !ro);
601     d->m_readOnly = ro;
602     if (!ro)
603         d->setCursorPosition(d->end());
604     updateInputMethod(Qt::ImEnabled);
605     q_canPasteChanged();
606     d->emitUndoRedoChanged();
607     emit readOnlyChanged(ro);
608 }
609
610 /*!
611     \qmlproperty int QtQuick2::TextInput::maximumLength
612     The maximum permitted length of the text in the TextInput.
613
614     If the text is too long, it is truncated at the limit.
615
616     By default, this property contains a value of 32767.
617 */
618 int QQuickTextInput::maxLength() const
619 {
620     Q_D(const QQuickTextInput);
621     return d->m_maxLength;
622 }
623
624 void QQuickTextInput::setMaxLength(int ml)
625 {
626     Q_D(QQuickTextInput);
627     if (d->m_maxLength == ml || d->m_maskData)
628         return;
629
630     d->m_maxLength = ml;
631     d->internalSetText(d->m_text, -1, false);
632
633     emit maximumLengthChanged(ml);
634 }
635
636 /*!
637     \qmlproperty bool QtQuick2::TextInput::cursorVisible
638     Set to true when the TextInput shows a cursor.
639
640     This property is set and unset when the TextInput gets active focus, so that other
641     properties can be bound to whether the cursor is currently showing. As it
642     gets set and unset automatically, when you set the value yourself you must
643     keep in mind that your value may be overwritten.
644
645     It can be set directly in script, for example if a KeyProxy might
646     forward keys to it and you desire it to look active when this happens
647     (but without actually giving it active focus).
648
649     It should not be set directly on the element, like in the below QML,
650     as the specified value will be overridden an lost on focus changes.
651
652     \code
653     TextInput {
654         text: "Text"
655         cursorVisible: false
656     }
657     \endcode
658
659     In the above snippet the cursor will still become visible when the
660     TextInput gains active focus.
661 */
662 bool QQuickTextInput::isCursorVisible() const
663 {
664     Q_D(const QQuickTextInput);
665     return d->cursorVisible;
666 }
667
668 void QQuickTextInput::setCursorVisible(bool on)
669 {
670     Q_D(QQuickTextInput);
671     if (d->cursorVisible == on)
672         return;
673     d->cursorVisible = on;
674     if (on && isComponentComplete())
675         QQuickTextUtil::createCursor(d);
676     if (!d->cursorItem) {
677         d->setCursorBlinkPeriod(on ? qApp->styleHints()->cursorFlashTime() : 0);
678         d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
679         update();
680     }
681     emit cursorVisibleChanged(d->cursorVisible);
682 }
683
684 /*!
685     \qmlproperty int QtQuick2::TextInput::cursorPosition
686     The position of the cursor in the TextInput.
687 */
688 int QQuickTextInput::cursorPosition() const
689 {
690     Q_D(const QQuickTextInput);
691     return d->m_cursor;
692 }
693
694 void QQuickTextInput::setCursorPosition(int cp)
695 {
696     Q_D(QQuickTextInput);
697     if (cp < 0 || cp > text().length())
698         return;
699     d->moveCursor(cp);
700 }
701
702 /*!
703     \qmlproperty rectangle QtQuick2::TextInput::cursorRectangle
704
705     The rectangle where the standard text cursor is rendered within the text input.  Read only.
706
707     The position and height of a custom cursorDelegate are updated to follow the cursorRectangle
708     automatically when it changes.  The width of the delegate is unaffected by changes in the
709     cursor rectangle.
710 */
711
712 QRectF QQuickTextInput::cursorRectangle() const
713 {
714     Q_D(const QQuickTextInput);
715
716     int c = d->m_cursor + d->m_preeditCursor;
717     if (d->m_echoMode == NoEcho)
718         c = 0;
719     QTextLine l = d->m_textLayout.lineForTextPosition(c);
720     if (!l.isValid())
721         return QRectF();
722     return QRectF(l.cursorToX(c) - d->hscroll, l.y() - d->vscroll, 1, l.height());
723 }
724
725 /*!
726     \qmlproperty int QtQuick2::TextInput::selectionStart
727
728     The cursor position before the first character in the current selection.
729
730     This property is read-only. To change the selection, use select(start,end),
731     selectAll(), or selectWord().
732
733     \sa selectionEnd, cursorPosition, selectedText
734 */
735 int QQuickTextInput::selectionStart() const
736 {
737     Q_D(const QQuickTextInput);
738     return d->lastSelectionStart;
739 }
740 /*!
741     \qmlproperty int QtQuick2::TextInput::selectionEnd
742
743     The cursor position after the last character in the current selection.
744
745     This property is read-only. To change the selection, use select(start,end),
746     selectAll(), or selectWord().
747
748     \sa selectionStart, cursorPosition, selectedText
749 */
750 int QQuickTextInput::selectionEnd() const
751 {
752     Q_D(const QQuickTextInput);
753     return d->lastSelectionEnd;
754 }
755 /*!
756     \qmlmethod void QtQuick2::TextInput::select(int start, int end)
757
758     Causes the text from \a start to \a end to be selected.
759
760     If either start or end is out of range, the selection is not changed.
761
762     After calling this, selectionStart will become the lesser
763     and selectionEnd will become the greater (regardless of the order passed
764     to this method).
765
766     \sa selectionStart, selectionEnd
767 */
768 void QQuickTextInput::select(int start, int end)
769 {
770     Q_D(QQuickTextInput);
771     if (start < 0 || end < 0 || start > d->m_text.length() || end > d->m_text.length())
772         return;
773     d->setSelection(start, end-start);
774 }
775
776 /*!
777     \qmlproperty string QtQuick2::TextInput::selectedText
778
779     This read-only property provides the text currently selected in the
780     text input.
781
782     It is equivalent to the following snippet, but is faster and easier
783     to use.
784
785     \js
786     myTextInput.text.toString().substring(myTextInput.selectionStart,
787         myTextInput.selectionEnd);
788     \endjs
789 */
790 QString QQuickTextInput::selectedText() const
791 {
792     Q_D(const QQuickTextInput);
793     return d->selectedText();
794 }
795
796 /*!
797     \qmlproperty bool QtQuick2::TextInput::activeFocusOnPress
798
799     Whether the TextInput should gain active focus on a mouse press. By default this is
800     set to true.
801 */
802 bool QQuickTextInput::focusOnPress() const
803 {
804     Q_D(const QQuickTextInput);
805     return d->focusOnPress;
806 }
807
808 void QQuickTextInput::setFocusOnPress(bool b)
809 {
810     Q_D(QQuickTextInput);
811     if (d->focusOnPress == b)
812         return;
813
814     d->focusOnPress = b;
815
816     emit activeFocusOnPressChanged(d->focusOnPress);
817 }
818 /*!
819     \qmlproperty bool QtQuick2::TextInput::autoScroll
820
821     Whether the TextInput should scroll when the text is longer than the width. By default this is
822     set to true.
823 */
824 bool QQuickTextInput::autoScroll() const
825 {
826     Q_D(const QQuickTextInput);
827     return d->autoScroll;
828 }
829
830 void QQuickTextInput::setAutoScroll(bool b)
831 {
832     Q_D(QQuickTextInput);
833     if (d->autoScroll == b)
834         return;
835
836     d->autoScroll = b;
837     //We need to repaint so that the scrolling is taking into account.
838     updateCursorRectangle();
839     emit autoScrollChanged(d->autoScroll);
840 }
841
842 #ifndef QT_NO_VALIDATOR
843
844 /*!
845     \qmlclass IntValidator QIntValidator
846     \inqmlmodule QtQuick 2
847     \ingroup qml-basic-visual-elements
848
849     This element provides a validator for integer values.
850
851     If no \l locale is set IntValidator uses the \l {QLocale::setDefault()}{default locale} to
852     interpret the number and will accept locale specific digits, group separators, and positive
853     and negative signs.  In addition, IntValidator is always guaranteed to accept a number
854     formatted according to the "C" locale.
855 */
856
857
858 QQuickIntValidator::QQuickIntValidator(QObject *parent)
859     : QIntValidator(parent)
860 {
861 }
862
863 /*!
864     \qmlproperty string QtQuick2::IntValidator::locale
865
866     This property holds the name of the locale used to interpret the number.
867
868     \sa QML:Qt::locale()
869 */
870
871 QString QQuickIntValidator::localeName() const
872 {
873     return locale().name();
874 }
875
876 void QQuickIntValidator::setLocaleName(const QString &name)
877 {
878     if (locale().name() != name) {
879         setLocale(QLocale(name));
880         emit localeNameChanged();
881     }
882 }
883
884 void QQuickIntValidator::resetLocaleName()
885 {
886     QLocale defaultLocale;
887     if (locale() != defaultLocale) {
888         setLocale(defaultLocale);
889         emit localeNameChanged();
890     }
891 }
892
893 /*!
894     \qmlproperty int QtQuick2::IntValidator::top
895
896     This property holds the validator's highest acceptable value.
897     By default, this property's value is derived from the highest signed integer available (typically 2147483647).
898 */
899 /*!
900     \qmlproperty int QtQuick2::IntValidator::bottom
901
902     This property holds the validator's lowest acceptable value.
903     By default, this property's value is derived from the lowest signed integer available (typically -2147483647).
904 */
905
906 /*!
907     \qmlclass DoubleValidator QDoubleValidator
908     \inqmlmodule QtQuick 2
909     \ingroup qml-basic-visual-elements
910
911     This element provides a validator for non-integer numbers.
912
913     Input is accepted if it contains a double that is within the valid range
914     and is in the  correct format.
915
916     Input is accepected but invalid if it contains a double that is outside
917     the range or is in the wrong format; e.g. with too many digits after the
918     decimal point or is empty.
919
920     Input is rejected if it is not a double.
921
922     Note: If the valid range consists of just positive doubles (e.g. 0.0 to
923     100.0) and input is a negative double then it is rejected. If \l notation
924     is set to DoubleValidator.StandardNotation, and  the input contains more
925     digits before the decimal point than a double in the valid range may have,
926     it is also rejected. If \l notation is DoubleValidator.ScientificNotation,
927     and the input is not in the valid range, it is accecpted but invalid. The
928     value may yet become valid by changing the exponent.
929 */
930
931 QQuickDoubleValidator::QQuickDoubleValidator(QObject *parent)
932     : QDoubleValidator(parent)
933 {
934 }
935
936 /*!
937     \qmlproperty string QtQuick2::DoubleValidator::locale
938
939     This property holds the name of the locale used to interpret the number.
940
941     \sa QML:Qt::locale()
942 */
943
944 QString QQuickDoubleValidator::localeName() const
945 {
946     return locale().name();
947 }
948
949 void QQuickDoubleValidator::setLocaleName(const QString &name)
950 {
951     if (locale().name() != name) {
952         setLocale(QLocale(name));
953         emit localeNameChanged();
954     }
955 }
956
957 void QQuickDoubleValidator::resetLocaleName()
958 {
959     QLocale defaultLocale;
960     if (locale() != defaultLocale) {
961         setLocale(defaultLocale);
962         emit localeNameChanged();
963     }
964 }
965
966 /*!
967     \qmlproperty real QtQuick2::DoubleValidator::top
968
969     This property holds the validator's maximum acceptable value.
970     By default, this property contains a value of infinity.
971 */
972 /*!
973     \qmlproperty real QtQuick2::DoubleValidator::bottom
974
975     This property holds the validator's minimum acceptable value.
976     By default, this property contains a value of -infinity.
977 */
978 /*!
979     \qmlproperty int QtQuick2::DoubleValidator::decimals
980
981     This property holds the validator's maximum number of digits after the decimal point.
982     By default, this property contains a value of 1000.
983 */
984 /*!
985     \qmlproperty enumeration QtQuick2::DoubleValidator::notation
986     This property holds the notation of how a string can describe a number.
987
988     The possible values for this property are:
989
990     \list
991     \li DoubleValidator.StandardNotation
992     \li DoubleValidator.ScientificNotation (default)
993     \endlist
994
995     If this property is set to DoubleValidator.ScientificNotation, the written number may have an exponent part (e.g. 1.5E-2).
996 */
997
998 /*!
999     \qmlclass RegExpValidator QRegExpValidator
1000     \inqmlmodule QtQuick 2
1001     \ingroup qml-basic-visual-elements
1002
1003     This element provides a validator, which counts as valid any string which
1004     matches a specified regular expression.
1005 */
1006 /*!
1007    \qmlproperty regExp QtQuick2::RegExpValidator::regExp
1008
1009    This property holds the regular expression used for validation.
1010
1011    Note that this property should be a regular expression in JS syntax, e.g /a/ for the regular expression
1012    matching "a".
1013
1014    By default, this property contains a regular expression with the pattern .* that matches any string.
1015 */
1016
1017 /*!
1018     \qmlproperty Validator QtQuick2::TextInput::validator
1019
1020     Allows you to set a validator on the TextInput. When a validator is set
1021     the TextInput will only accept input which leaves the text property in
1022     an acceptable or intermediate state. The accepted signal will only be sent
1023     if the text is in an acceptable state when enter is pressed.
1024
1025     Currently supported validators are IntValidator, DoubleValidator and
1026     RegExpValidator. An example of using validators is shown below, which allows
1027     input of integers between 11 and 31 into the text input:
1028
1029     \code
1030     import QtQuick 2.0
1031     TextInput{
1032         validator: IntValidator{bottom: 11; top: 31;}
1033         focus: true
1034     }
1035     \endcode
1036
1037     \sa acceptableInput, inputMask
1038 */
1039
1040 QValidator* QQuickTextInput::validator() const
1041 {
1042     Q_D(const QQuickTextInput);
1043     return d->m_validator;
1044 }
1045
1046 void QQuickTextInput::setValidator(QValidator* v)
1047 {
1048     Q_D(QQuickTextInput);
1049     if (d->m_validator == v)
1050         return;
1051
1052     d->m_validator = v;
1053
1054     if (isComponentComplete())
1055         d->checkIsValid();
1056
1057     emit validatorChanged();
1058 }
1059
1060 #endif // QT_NO_VALIDATOR
1061
1062 void QQuickTextInputPrivate::checkIsValid()
1063 {
1064     Q_Q(QQuickTextInput);
1065
1066     ValidatorState state = hasAcceptableInput(m_text);
1067     m_validInput = state != InvalidInput;
1068     if (state != AcceptableInput) {
1069         if (m_acceptableInput) {
1070             m_acceptableInput = false;
1071             emit q->acceptableInputChanged();
1072         }
1073     } else if (!m_acceptableInput) {
1074         m_acceptableInput = true;
1075         emit q->acceptableInputChanged();
1076     }
1077 }
1078
1079 /*!
1080     \qmlproperty string QtQuick2::TextInput::inputMask
1081
1082     Allows you to set an input mask on the TextInput, restricting the allowable
1083     text inputs. See QLineEdit::inputMask for further details, as the exact
1084     same mask strings are used by TextInput.
1085
1086     \sa acceptableInput, validator
1087 */
1088 QString QQuickTextInput::inputMask() const
1089 {
1090     Q_D(const QQuickTextInput);
1091     return d->inputMask();
1092 }
1093
1094 void QQuickTextInput::setInputMask(const QString &im)
1095 {
1096     Q_D(QQuickTextInput);
1097     if (d->inputMask() == im)
1098         return;
1099
1100     d->setInputMask(im);
1101     emit inputMaskChanged(d->inputMask());
1102 }
1103
1104 /*!
1105     \qmlproperty bool QtQuick2::TextInput::acceptableInput
1106
1107     This property is always true unless a validator or input mask has been set.
1108     If a validator or input mask has been set, this property will only be true
1109     if the current text is acceptable to the validator or input mask as a final
1110     string (not as an intermediate string).
1111 */
1112 bool QQuickTextInput::hasAcceptableInput() const
1113 {
1114     Q_D(const QQuickTextInput);
1115     return d->hasAcceptableInput(d->m_text) == QQuickTextInputPrivate::AcceptableInput;
1116 }
1117
1118 /*!
1119     \qmlsignal QtQuick2::TextInput::onAccepted()
1120
1121     This handler is called when the Return or Enter key is pressed.
1122     Note that if there is a \l validator or \l inputMask set on the text
1123     input, the handler will only be emitted if the input is in an acceptable
1124     state.
1125 */
1126
1127 Qt::InputMethodHints QQuickTextInputPrivate::effectiveInputMethodHints() const
1128 {
1129     Qt::InputMethodHints hints = inputMethodHints;
1130     if (m_echoMode == QQuickTextInput::Password || m_echoMode == QQuickTextInput::NoEcho)
1131         hints |= Qt::ImhHiddenText;
1132     else if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit)
1133         hints &= ~Qt::ImhHiddenText;
1134     if (m_echoMode != QQuickTextInput::Normal)
1135         hints |= (Qt::ImhNoAutoUppercase | Qt::ImhNoPredictiveText | Qt::ImhSensitiveData);
1136     return hints;
1137 }
1138 /*!
1139     \qmlproperty enumeration QtQuick2::TextInput::echoMode
1140
1141     Specifies how the text should be displayed in the TextInput.
1142     \list
1143     \li TextInput.Normal - Displays the text as it is. (Default)
1144     \li TextInput.Password - Displays asterisks instead of characters.
1145     \li TextInput.NoEcho - Displays nothing.
1146     \li TextInput.PasswordEchoOnEdit - Displays characters as they are entered
1147     while editing, otherwise displays asterisks.
1148     \endlist
1149 */
1150 QQuickTextInput::EchoMode QQuickTextInput::echoMode() const
1151 {
1152     Q_D(const QQuickTextInput);
1153     return QQuickTextInput::EchoMode(d->m_echoMode);
1154 }
1155
1156 void QQuickTextInput::setEchoMode(QQuickTextInput::EchoMode echo)
1157 {
1158     Q_D(QQuickTextInput);
1159     if (echoMode() == echo)
1160         return;
1161     d->cancelPasswordEchoTimer();
1162     d->m_echoMode = echo;
1163     d->m_passwordEchoEditing = false;
1164     updateInputMethod(Qt::ImHints);
1165     d->updateDisplayText();
1166     updateCursorRectangle();
1167
1168     emit echoModeChanged(echoMode());
1169 }
1170
1171 /*!
1172     \qmlproperty enumeration QtQuick2::TextInput::inputMethodHints
1173
1174     Provides hints to the input method about the expected content of the text input and how it
1175     should operate.
1176
1177     The value is a bit-wise combination of flags, or Qt.ImhNone if no hints are set.
1178
1179     Flags that alter behaviour are:
1180
1181     \list
1182     \li Qt.ImhHiddenText - Characters should be hidden, as is typically used when entering passwords.
1183             This is automatically set when setting echoMode to \c TextInput.Password.
1184     \li Qt.ImhSensitiveData - Typed text should not be stored by the active input method
1185             in any persistent storage like predictive user dictionary.
1186     \li Qt.ImhNoAutoUppercase - The input method should not try to automatically switch to upper case
1187             when a sentence ends.
1188     \li Qt.ImhPreferNumbers - Numbers are preferred (but not required).
1189     \li Qt.ImhPreferUppercase - Upper case letters are preferred (but not required).
1190     \li Qt.ImhPreferLowercase - Lower case letters are preferred (but not required).
1191     \li Qt.ImhNoPredictiveText - Do not use predictive text (i.e. dictionary lookup) while typing.
1192
1193     \li Qt.ImhDate - The text editor functions as a date field.
1194     \li Qt.ImhTime - The text editor functions as a time field.
1195     \endlist
1196
1197     Flags that restrict input (exclusive flags) are:
1198
1199     \list
1200     \li Qt.ImhDigitsOnly - Only digits are allowed.
1201     \li Qt.ImhFormattedNumbersOnly - Only number input is allowed. This includes decimal point and minus sign.
1202     \li Qt.ImhUppercaseOnly - Only upper case letter input is allowed.
1203     \li Qt.ImhLowercaseOnly - Only lower case letter input is allowed.
1204     \li Qt.ImhDialableCharactersOnly - Only characters suitable for phone dialing are allowed.
1205     \li Qt.ImhEmailCharactersOnly - Only characters suitable for email addresses are allowed.
1206     \li Qt.ImhUrlCharactersOnly - Only characters suitable for URLs are allowed.
1207     \endlist
1208
1209     Masks:
1210
1211     \list
1212     \li Qt.ImhExclusiveInputMask - This mask yields nonzero if any of the exclusive flags are used.
1213     \endlist
1214 */
1215
1216 Qt::InputMethodHints QQuickTextInput::inputMethodHints() const
1217 {
1218     Q_D(const QQuickTextInput);
1219     return d->inputMethodHints;
1220 }
1221
1222 void QQuickTextInput::setInputMethodHints(Qt::InputMethodHints hints)
1223 {
1224     Q_D(QQuickTextInput);
1225
1226     if (hints == d->inputMethodHints)
1227         return;
1228
1229     d->inputMethodHints = hints;
1230     updateInputMethod(Qt::ImHints);
1231     emit inputMethodHintsChanged();
1232 }
1233
1234 /*!
1235     \qmlproperty Component QtQuick2::TextInput::cursorDelegate
1236     The delegate for the cursor in the TextInput.
1237
1238     If you set a cursorDelegate for a TextInput, this delegate will be used for
1239     drawing the cursor instead of the standard cursor. An instance of the
1240     delegate will be created and managed by the TextInput when a cursor is
1241     needed, and the x property of delegate instance will be set so as
1242     to be one pixel before the top left of the current character.
1243
1244     Note that the root item of the delegate component must be a QQuickItem or
1245     QQuickItem derived item.
1246 */
1247 QQmlComponent* QQuickTextInput::cursorDelegate() const
1248 {
1249     Q_D(const QQuickTextInput);
1250     return d->cursorComponent;
1251 }
1252
1253 void QQuickTextInput::setCursorDelegate(QQmlComponent* c)
1254 {
1255     Q_D(QQuickTextInput);
1256     QQuickTextUtil::setCursorDelegate(d, c);
1257 }
1258
1259 void QQuickTextInput::createCursor()
1260 {
1261     Q_D(QQuickTextInput);
1262     d->cursorPending = true;
1263     QQuickTextUtil::createCursor(d);
1264 }
1265
1266 /*!
1267     \qmlmethod rect QtQuick2::TextInput::positionToRectangle(int pos)
1268
1269     This function takes a character position and returns the rectangle that the
1270     cursor would occupy, if it was placed at that character position.
1271
1272     This is similar to setting the cursorPosition, and then querying the cursor
1273     rectangle, but the cursorPosition is not changed.
1274 */
1275 QRectF QQuickTextInput::positionToRectangle(int pos) const
1276 {
1277     Q_D(const QQuickTextInput);
1278     if (d->m_echoMode == NoEcho)
1279         pos = 0;
1280     else if (pos > d->m_cursor)
1281         pos += d->preeditAreaText().length();
1282     QTextLine l = d->m_textLayout.lineForTextPosition(pos);
1283     return l.isValid()
1284             ? QRectF(l.cursorToX(pos) - d->hscroll, l.y() - d->vscroll, 1, l.height())
1285             : QRectF();
1286 }
1287
1288 /*!
1289     \qmlmethod int QtQuick2::TextInput::positionAt(real x, real y, CursorPosition position = CursorBetweenCharacters)
1290
1291     This function returns the character position at
1292     x and y pixels from the top left  of the textInput. Position 0 is before the
1293     first character, position 1 is after the first character but before the second,
1294     and so on until position text.length, which is after all characters.
1295
1296     This means that for all x values before the first character this function returns 0,
1297     and for all x values after the last character this function returns text.length.  If
1298     the y value is above the text the position will be that of the nearest character on
1299     the first line line and if it is below the text the position of the nearest character
1300     on the last line will be returned.
1301
1302     The cursor position type specifies how the cursor position should be resolved.
1303
1304     \list
1305     \li TextInput.CursorBetweenCharacters - Returns the position between characters that is nearest x.
1306     \li TextInput.CursorOnCharacter - Returns the position before the character that is nearest x.
1307     \endlist
1308 */
1309
1310 void QQuickTextInput::positionAt(QQmlV8Function *args) const
1311 {
1312     Q_D(const QQuickTextInput);
1313
1314     qreal x = 0;
1315     qreal y = 0;
1316     QTextLine::CursorPosition position = QTextLine::CursorBetweenCharacters;
1317
1318     if (args->Length() < 1)
1319         return;
1320
1321     int i = 0;
1322     v8::Local<v8::Value> arg = (*args)[i];
1323     x = arg->NumberValue();
1324
1325     if (++i < args->Length()) {
1326         arg = (*args)[i];
1327         y = arg->NumberValue();
1328     }
1329
1330     if (++i < args->Length()) {
1331         arg = (*args)[i];
1332         position = QTextLine::CursorPosition(arg->Int32Value());
1333     }
1334
1335     int pos = d->positionAt(x, y, position);
1336     const int cursor = d->m_cursor;
1337     if (pos > cursor) {
1338         const int preeditLength = d->preeditAreaText().length();
1339         pos = pos > cursor + preeditLength
1340                 ? pos - preeditLength
1341                 : cursor;
1342     }
1343     args->returnValue(v8::Int32::New(pos));
1344 }
1345
1346 int QQuickTextInputPrivate::positionAt(qreal x, qreal y, QTextLine::CursorPosition position) const
1347 {
1348     x += hscroll;
1349     y += vscroll;
1350     QTextLine line = m_textLayout.lineAt(0);
1351     for (int i = 1; i < m_textLayout.lineCount(); ++i) {
1352         QTextLine nextLine = m_textLayout.lineAt(i);
1353
1354         if (y < (line.rect().bottom() + nextLine.y()) / 2)
1355             break;
1356         line = nextLine;
1357     }
1358     return line.isValid() ? line.xToCursor(x, position) : 0;
1359 }
1360
1361 void QQuickTextInput::keyPressEvent(QKeyEvent* ev)
1362 {
1363     Q_D(QQuickTextInput);
1364     // Don't allow MacOSX up/down support, and we don't allow a completer.
1365     bool ignore = (ev->key() == Qt::Key_Up || ev->key() == Qt::Key_Down) && ev->modifiers() == Qt::NoModifier;
1366     if (!ignore && (d->lastSelectionStart == d->lastSelectionEnd) && (ev->key() == Qt::Key_Right || ev->key() == Qt::Key_Left)) {
1367         // Ignore when moving off the end unless there is a selection,
1368         // because then moving will do something (deselect).
1369         int cursorPosition = d->m_cursor;
1370         if (cursorPosition == 0)
1371             ignore = ev->key() == (d->layoutDirection() == Qt::LeftToRight ? Qt::Key_Left : Qt::Key_Right);
1372         if (!ignore && cursorPosition == text().length())
1373             ignore = ev->key() == (d->layoutDirection() == Qt::LeftToRight ? Qt::Key_Right : Qt::Key_Left);
1374     }
1375     if (ignore) {
1376         ev->ignore();
1377     } else {
1378         d->processKeyEvent(ev);
1379     }
1380     if (!ev->isAccepted())
1381         QQuickImplicitSizeItem::keyPressEvent(ev);
1382 }
1383
1384 void QQuickTextInput::inputMethodEvent(QInputMethodEvent *ev)
1385 {
1386     Q_D(QQuickTextInput);
1387     const bool wasComposing = d->hasImState;
1388     if (d->m_readOnly) {
1389         ev->ignore();
1390     } else {
1391         d->processInputMethodEvent(ev);
1392     }
1393     if (!ev->isAccepted())
1394         QQuickImplicitSizeItem::inputMethodEvent(ev);
1395
1396     if (wasComposing != d->hasImState)
1397         emit inputMethodComposingChanged();
1398 }
1399
1400 void QQuickTextInput::mouseDoubleClickEvent(QMouseEvent *event)
1401 {
1402     Q_D(QQuickTextInput);
1403
1404     if (d->selectByMouse && event->button() == Qt::LeftButton) {
1405         d->commitPreedit();
1406         int cursor = d->positionAt(event->localPos());
1407         d->selectWordAtPos(cursor);
1408         event->setAccepted(true);
1409         if (!d->hasPendingTripleClick()) {
1410             d->tripleClickStartPoint = event->localPos();
1411             d->tripleClickTimer.start();
1412         }
1413     } else {
1414         if (d->sendMouseEventToInputContext(event))
1415             return;
1416         QQuickImplicitSizeItem::mouseDoubleClickEvent(event);
1417     }
1418 }
1419
1420 void QQuickTextInput::mousePressEvent(QMouseEvent *event)
1421 {
1422     Q_D(QQuickTextInput);
1423
1424     d->pressPos = event->localPos();
1425
1426     if (d->sendMouseEventToInputContext(event))
1427         return;
1428
1429     if (d->selectByMouse) {
1430         setKeepMouseGrab(false);
1431         d->selectPressed = true;
1432         QPointF distanceVector = d->pressPos - d->tripleClickStartPoint;
1433         if (d->hasPendingTripleClick()
1434             && distanceVector.manhattanLength() < qApp->styleHints()->startDragDistance()) {
1435             event->setAccepted(true);
1436             selectAll();
1437             return;
1438         }
1439     }
1440
1441     bool mark = (event->modifiers() & Qt::ShiftModifier) && d->selectByMouse;
1442     int cursor = d->positionAt(event->localPos());
1443     d->moveCursor(cursor, mark);
1444
1445     if (d->focusOnPress) {
1446         bool hadActiveFocus = hasActiveFocus();
1447         forceActiveFocus();
1448         // re-open input panel on press if already focused
1449         if (hasActiveFocus() && hadActiveFocus && !d->m_readOnly)
1450             openSoftwareInputPanel();
1451     }
1452
1453     event->setAccepted(true);
1454 }
1455
1456 void QQuickTextInput::mouseMoveEvent(QMouseEvent *event)
1457 {
1458     Q_D(QQuickTextInput);
1459
1460     if (d->selectPressed) {
1461         if (qAbs(int(event->localPos().x() - d->pressPos.x())) > qApp->styleHints()->startDragDistance())
1462             setKeepMouseGrab(true);
1463
1464         if (d->composeMode()) {
1465             // start selection
1466             int startPos = d->positionAt(d->pressPos);
1467             int currentPos = d->positionAt(event->localPos());
1468             if (startPos != currentPos)
1469                 d->setSelection(startPos, currentPos - startPos);
1470         } else {
1471             moveCursorSelection(d->positionAt(event->localPos()), d->mouseSelectionMode);
1472         }
1473         event->setAccepted(true);
1474     } else {
1475         QQuickImplicitSizeItem::mouseMoveEvent(event);
1476     }
1477 }
1478
1479 void QQuickTextInput::mouseReleaseEvent(QMouseEvent *event)
1480 {
1481     Q_D(QQuickTextInput);
1482     if (d->sendMouseEventToInputContext(event))
1483         return;
1484     if (d->selectPressed) {
1485         d->selectPressed = false;
1486         setKeepMouseGrab(false);
1487     }
1488 #ifndef QT_NO_CLIPBOARD
1489     if (QGuiApplication::clipboard()->supportsSelection()) {
1490         if (event->button() == Qt::LeftButton) {
1491             d->copy(QClipboard::Selection);
1492         } else if (!d->m_readOnly && event->button() == Qt::MidButton) {
1493             d->deselect();
1494             d->insert(QGuiApplication::clipboard()->text(QClipboard::Selection));
1495         }
1496     }
1497 #endif
1498     if (!event->isAccepted())
1499         QQuickImplicitSizeItem::mouseReleaseEvent(event);
1500 }
1501
1502 bool QQuickTextInputPrivate::sendMouseEventToInputContext(QMouseEvent *event)
1503 {
1504 #if !defined QT_NO_IM
1505     if (composeMode()) {
1506         int tmp_cursor = positionAt(event->localPos());
1507         int mousePos = tmp_cursor - m_cursor;
1508         if (mousePos >= 0 && mousePos <= m_textLayout.preeditAreaText().length()) {
1509             if (event->type() == QEvent::MouseButtonRelease) {
1510                 qApp->inputMethod()->invokeAction(QInputMethod::Click, mousePos);
1511             }
1512             return true;
1513         }
1514     }
1515 #else
1516     Q_UNUSED(event);
1517     Q_UNUSED(eventType)
1518 #endif
1519
1520     return false;
1521 }
1522
1523 void QQuickTextInput::mouseUngrabEvent()
1524 {
1525     Q_D(QQuickTextInput);
1526     d->selectPressed = false;
1527     setKeepMouseGrab(false);
1528 }
1529
1530 bool QQuickTextInput::event(QEvent* ev)
1531 {
1532 #ifndef QT_NO_SHORTCUT
1533     Q_D(QQuickTextInput);
1534     if (ev->type() == QEvent::ShortcutOverride) {
1535         if (d->m_readOnly)
1536             return false;
1537         QKeyEvent* ke = static_cast<QKeyEvent*>(ev);
1538         if (ke == QKeySequence::Copy
1539             || ke == QKeySequence::Paste
1540             || ke == QKeySequence::Cut
1541             || ke == QKeySequence::Redo
1542             || ke == QKeySequence::Undo
1543             || ke == QKeySequence::MoveToNextWord
1544             || ke == QKeySequence::MoveToPreviousWord
1545             || ke == QKeySequence::MoveToStartOfDocument
1546             || ke == QKeySequence::MoveToEndOfDocument
1547             || ke == QKeySequence::SelectNextWord
1548             || ke == QKeySequence::SelectPreviousWord
1549             || ke == QKeySequence::SelectStartOfLine
1550             || ke == QKeySequence::SelectEndOfLine
1551             || ke == QKeySequence::SelectStartOfBlock
1552             || ke == QKeySequence::SelectEndOfBlock
1553             || ke == QKeySequence::SelectStartOfDocument
1554             || ke == QKeySequence::SelectAll
1555             || ke == QKeySequence::SelectEndOfDocument) {
1556             ke->accept();
1557         } else if (ke->modifiers() == Qt::NoModifier || ke->modifiers() == Qt::ShiftModifier
1558                    || ke->modifiers() == Qt::KeypadModifier) {
1559             if (ke->key() < Qt::Key_Escape) {
1560                 ke->accept();
1561                 return true;
1562             } else {
1563                 switch (ke->key()) {
1564                 case Qt::Key_Delete:
1565                 case Qt::Key_Home:
1566                 case Qt::Key_End:
1567                 case Qt::Key_Backspace:
1568                 case Qt::Key_Left:
1569                 case Qt::Key_Right:
1570                     return true;
1571                 default:
1572                     break;
1573                 }
1574             }
1575         }
1576     }
1577 #endif
1578
1579     return QQuickImplicitSizeItem::event(ev);
1580 }
1581
1582 void QQuickTextInput::geometryChanged(const QRectF &newGeometry,
1583                                   const QRectF &oldGeometry)
1584 {
1585     Q_D(QQuickTextInput);
1586     if (!d->inLayout) {
1587         if (newGeometry.width() != oldGeometry.width() && d->wrapMode != NoWrap)
1588             d->updateLayout();
1589         updateCursorRectangle();
1590     }
1591     QQuickImplicitSizeItem::geometryChanged(newGeometry, oldGeometry);
1592 }
1593
1594 void QQuickTextInputPrivate::updateHorizontalScroll()
1595 {
1596     Q_Q(QQuickTextInput);
1597     QTextLine currentLine = m_textLayout.lineForTextPosition(m_cursor + m_preeditCursor);
1598     const int preeditLength = m_textLayout.preeditAreaText().length();
1599     const qreal width = qMax<qreal>(0, q->width());
1600     qreal cix = 0;
1601     qreal widthUsed = 0;
1602     if (currentLine.isValid()) {
1603         cix = currentLine.cursorToX(m_cursor + preeditLength);
1604         const qreal cursorWidth = cix >= 0 ? cix : width - cix;
1605         widthUsed = qMax(currentLine.naturalTextWidth(), cursorWidth);
1606     }
1607     int previousScroll = hscroll;
1608
1609     if (!autoScroll || widthUsed <=  width || m_echoMode == QQuickTextInput::NoEcho) {
1610         hscroll = 0;
1611     } else {
1612         Q_ASSERT(currentLine.isValid());
1613         if (cix - hscroll >= width) {
1614             // text doesn't fit, cursor is to the right of br (scroll right)
1615             hscroll = cix - width;
1616         } else if (cix - hscroll < 0 && hscroll < widthUsed) {
1617             // text doesn't fit, cursor is to the left of br (scroll left)
1618             hscroll = cix;
1619         } else if (widthUsed - hscroll < width) {
1620             // text doesn't fit, text document is to the left of br; align
1621             // right
1622             hscroll = widthUsed - width;
1623         } else if (width - hscroll > widthUsed) {
1624             // text doesn't fit, text document is to the right of br; align
1625             // left
1626             hscroll = width - widthUsed;
1627         }
1628         if (preeditLength > 0) {
1629             // check to ensure long pre-edit text doesn't push the cursor
1630             // off to the left
1631              cix = currentLine.cursorToX(m_cursor + qMax(0, m_preeditCursor - 1));
1632              if (cix < hscroll)
1633                  hscroll = cix;
1634         }
1635     }
1636     if (previousScroll != hscroll)
1637         textLayoutDirty = true;
1638 }
1639
1640 void QQuickTextInputPrivate::updateVerticalScroll()
1641 {
1642     Q_Q(QQuickTextInput);
1643     const int preeditLength = m_textLayout.preeditAreaText().length();
1644     const qreal height = qMax<qreal>(0, q->height());
1645     qreal heightUsed = contentSize.height();
1646     qreal previousScroll = vscroll;
1647
1648     if (!autoScroll || heightUsed <=  height) {
1649         // text fits in br; use vscroll for alignment
1650         switch (vAlign & ~(Qt::AlignAbsolute|Qt::AlignHorizontal_Mask)) {
1651         case Qt::AlignBottom:
1652             vscroll = heightUsed - height;
1653             break;
1654         case Qt::AlignVCenter:
1655             vscroll = (heightUsed - height) / 2;
1656             break;
1657         default:
1658             // Top
1659             vscroll = 0;
1660             break;
1661         }
1662     } else {
1663         QTextLine currentLine = m_textLayout.lineForTextPosition(m_cursor + preeditLength);
1664         QRectF r = currentLine.isValid() ? currentLine.rect() : QRectF();
1665         qreal top = r.top();
1666         int bottom = r.bottom();
1667
1668         if (bottom - vscroll >= height) {
1669             // text doesn't fit, cursor is to the below the br (scroll down)
1670             vscroll = bottom - height;
1671         } else if (top - vscroll < 0 && vscroll < heightUsed) {
1672             // text doesn't fit, cursor is above br (scroll up)
1673             vscroll = top;
1674         } else if (heightUsed - vscroll < height) {
1675             // text doesn't fit, text document is to the left of br; align
1676             // right
1677             vscroll = heightUsed - height;
1678         }
1679         if (preeditLength > 0) {
1680             // check to ensure long pre-edit text doesn't push the cursor
1681             // off the top
1682             currentLine = m_textLayout.lineForTextPosition(m_cursor + qMax(0, m_preeditCursor - 1));
1683             top = currentLine.isValid() ? currentLine.rect().top() : 0;
1684             if (top < vscroll)
1685                 vscroll = top;
1686         }
1687     }
1688     if (previousScroll != vscroll)
1689         textLayoutDirty = true;
1690 }
1691
1692 void QQuickTextInput::triggerPreprocess()
1693 {
1694     Q_D(QQuickTextInput);
1695     if (d->updateType == QQuickTextInputPrivate::UpdateNone)
1696         d->updateType = QQuickTextInputPrivate::UpdateOnlyPreprocess;
1697     update();
1698 }
1699
1700 QSGNode *QQuickTextInput::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data)
1701 {
1702     Q_UNUSED(data);
1703     Q_D(QQuickTextInput);
1704
1705     if (d->updateType != QQuickTextInputPrivate::UpdatePaintNode && oldNode != 0) {
1706         // Update done in preprocess() in the nodes
1707         d->updateType = QQuickTextInputPrivate::UpdateNone;
1708         return oldNode;
1709     }
1710
1711     d->updateType = QQuickTextInputPrivate::UpdateNone;
1712
1713     QQuickTextNode *node = static_cast<QQuickTextNode *>(oldNode);
1714     if (node == 0)
1715         node = new QQuickTextNode(QQuickItemPrivate::get(this)->sceneGraphContext(), this);
1716     d->textNode = node;
1717
1718     if (!d->textLayoutDirty && oldNode != 0) {
1719         QSGSimpleRectNode *cursorNode = node->cursorNode();
1720         if (cursorNode != 0 && !isReadOnly()) {
1721             cursorNode->setRect(cursorRectangle());
1722
1723             if (!d->cursorVisible || (!d->m_blinkStatus && d->m_blinkPeriod > 0)) {
1724                 d->hideCursor();
1725             } else {
1726                 d->showCursor();
1727             }
1728         }
1729     } else {
1730         node->deleteContent();
1731         node->setMatrix(QMatrix4x4());
1732
1733         QPointF offset(0, 0);
1734         if (d->autoScroll && d->m_textLayout.lineCount() > 0) {
1735             QFontMetricsF fm(d->font);
1736             // the y offset is there to keep the baseline constant in case we have script changes in the text.
1737             offset = -QPoint(d->hscroll, d->vscroll + d->m_textLayout.lineAt(0).ascent() - fm.ascent());
1738         } else {
1739             offset = -QPoint(d->hscroll, d->vscroll);
1740         }
1741
1742         if (!d->m_textLayout.text().isEmpty() || !d->m_textLayout.preeditAreaText().isEmpty()) {
1743             node->addTextLayout(offset, &d->m_textLayout, d->color,
1744                                 QQuickText::Normal, QColor(), QColor(),
1745                                 d->selectionColor, d->selectedTextColor,
1746                                 d->selectionStart(),
1747                                 d->selectionEnd() - 1); // selectionEnd() returns first char after
1748                                                                  // selection
1749         }
1750
1751         if (!isReadOnly() && d->cursorItem == 0) {
1752             node->setCursor(cursorRectangle(), d->color);
1753             if (!d->cursorVisible || (!d->m_blinkStatus && d->m_blinkPeriod > 0)) {
1754                 d->hideCursor();
1755             } else {
1756                 d->showCursor();
1757             }
1758         }
1759
1760         d->textLayoutDirty = false;
1761     }
1762
1763     return node;
1764 }
1765
1766 QVariant QQuickTextInput::inputMethodQuery(Qt::InputMethodQuery property) const
1767 {
1768     Q_D(const QQuickTextInput);
1769     switch (property) {
1770     case Qt::ImEnabled:
1771         return QVariant((bool)(flags() & ItemAcceptsInputMethod));
1772     case Qt::ImHints:
1773         return QVariant((int) d->effectiveInputMethodHints());
1774     case Qt::ImCursorRectangle:
1775         return cursorRectangle();
1776     case Qt::ImFont:
1777         return font();
1778     case Qt::ImCursorPosition:
1779         return QVariant(d->m_cursor);
1780     case Qt::ImSurroundingText:
1781         if (d->m_echoMode == PasswordEchoOnEdit && !d->m_passwordEchoEditing) {
1782             return QVariant(displayText());
1783         } else {
1784             return QVariant(d->realText());
1785         }
1786     case Qt::ImCurrentSelection:
1787         return QVariant(selectedText());
1788     case Qt::ImMaximumTextLength:
1789         return QVariant(maxLength());
1790     case Qt::ImAnchorPosition:
1791         if (d->selectionStart() == d->selectionEnd())
1792             return QVariant(d->m_cursor);
1793         else if (d->selectionStart() == d->m_cursor)
1794             return QVariant(d->selectionEnd());
1795         else
1796             return QVariant(d->selectionStart());
1797     default:
1798         return QVariant();
1799     }
1800 }
1801
1802 /*!
1803     \qmlmethod void QtQuick2::TextInput::deselect()
1804
1805     Removes active text selection.
1806 */
1807 void QQuickTextInput::deselect()
1808 {
1809     Q_D(QQuickTextInput);
1810     d->deselect();
1811 }
1812
1813 /*!
1814     \qmlmethod void QtQuick2::TextInput::selectAll()
1815
1816     Causes all text to be selected.
1817 */
1818 void QQuickTextInput::selectAll()
1819 {
1820     Q_D(QQuickTextInput);
1821     d->setSelection(0, text().length());
1822 }
1823
1824 /*!
1825     \qmlmethod void QtQuick2::TextInput::isRightToLeft(int start, int end)
1826
1827     Returns true if the natural reading direction of the editor text
1828     found between positions \a start and \a end is right to left.
1829 */
1830 bool QQuickTextInput::isRightToLeft(int start, int end)
1831 {
1832     if (start > end) {
1833         qmlInfo(this) << "isRightToLeft(start, end) called with the end property being smaller than the start.";
1834         return false;
1835     } else {
1836         return text().mid(start, end - start).isRightToLeft();
1837     }
1838 }
1839
1840 #ifndef QT_NO_CLIPBOARD
1841 /*!
1842     \qmlmethod QtQuick2::TextInput::cut()
1843
1844     Moves the currently selected text to the system clipboard.
1845 */
1846 void QQuickTextInput::cut()
1847 {
1848     Q_D(QQuickTextInput);
1849     d->copy();
1850     d->del();
1851 }
1852
1853 /*!
1854     \qmlmethod QtQuick2::TextInput::copy()
1855
1856     Copies the currently selected text to the system clipboard.
1857 */
1858 void QQuickTextInput::copy()
1859 {
1860     Q_D(QQuickTextInput);
1861     d->copy();
1862 }
1863
1864 /*!
1865     \qmlmethod QtQuick2::TextInput::paste()
1866
1867     Replaces the currently selected text by the contents of the system clipboard.
1868 */
1869 void QQuickTextInput::paste()
1870 {
1871     Q_D(QQuickTextInput);
1872     if (!d->m_readOnly)
1873         d->paste();
1874 }
1875 #endif // QT_NO_CLIPBOARD
1876
1877 /*!
1878     Undoes the last operation if undo is \l {canUndo}{available}. Deselects any
1879     current selection, and updates the selection start to the current cursor
1880     position.
1881 */
1882
1883 void QQuickTextInput::undo()
1884 {
1885     Q_D(QQuickTextInput);
1886     if (!d->m_readOnly) {
1887         d->internalUndo();
1888         d->finishChange(-1, true);
1889     }
1890 }
1891
1892 /*!
1893     Redoes the last operation if redo is \l {canRedo}{available}.
1894 */
1895
1896 void QQuickTextInput::redo()
1897 {
1898     Q_D(QQuickTextInput);
1899     if (!d->m_readOnly) {
1900         d->internalRedo();
1901         d->finishChange();
1902     }
1903 }
1904
1905 /*!
1906     \qmlmethod void QtQuick2::TextInput::insert(int position, string text)
1907
1908     Inserts \a text into the TextInput at position.
1909 */
1910
1911 void QQuickTextInput::insert(int position, const QString &text)
1912 {
1913     Q_D(QQuickTextInput);
1914     if (d->m_echoMode == QQuickTextInput::Password) {
1915         int delay = qGuiApp->styleHints()->passwordMaskDelay();
1916         if (delay > 0)
1917             d->m_passwordEchoTimer.start(delay, this);
1918     }
1919     if (position < 0 || position > d->m_text.length())
1920         return;
1921
1922     const int priorState = d->m_undoState;
1923
1924     QString insertText = text;
1925
1926     if (d->hasSelectedText()) {
1927         d->addCommand(QQuickTextInputPrivate::Command(
1928                 QQuickTextInputPrivate::SetSelection, d->m_cursor, 0, d->m_selstart, d->m_selend));
1929     }
1930     if (d->m_maskData) {
1931         insertText = d->maskString(position, insertText);
1932         for (int i = 0; i < insertText.length(); ++i) {
1933             d->addCommand(QQuickTextInputPrivate::Command(
1934                     QQuickTextInputPrivate::DeleteSelection, position + i, d->m_text.at(position + i), -1, -1));
1935             d->addCommand(QQuickTextInputPrivate::Command(
1936                     QQuickTextInputPrivate::Insert, position + i, insertText.at(i), -1, -1));
1937         }
1938         d->m_text.replace(position, insertText.length(), insertText);
1939         if (!insertText.isEmpty())
1940             d->m_textDirty = true;
1941         if (position < d->m_selend && position + insertText.length() > d->m_selstart)
1942             d->m_selDirty = true;
1943     } else {
1944         int remaining = d->m_maxLength - d->m_text.length();
1945         if (remaining != 0) {
1946             insertText = insertText.left(remaining);
1947             d->m_text.insert(position, insertText);
1948             for (int i = 0; i < insertText.length(); ++i)
1949                d->addCommand(QQuickTextInputPrivate::Command(
1950                     QQuickTextInputPrivate::Insert, position + i, insertText.at(i), -1, -1));
1951             if (d->m_cursor >= position)
1952                 d->m_cursor += insertText.length();
1953             if (d->m_selstart >= position)
1954                 d->m_selstart += insertText.length();
1955             if (d->m_selend >= position)
1956                 d->m_selend += insertText.length();
1957             d->m_textDirty = true;
1958             if (position >= d->m_selstart && position <= d->m_selend)
1959                 d->m_selDirty = true;
1960         }
1961     }
1962
1963     d->addCommand(QQuickTextInputPrivate::Command(
1964             QQuickTextInputPrivate::SetSelection, d->m_cursor, 0, d->m_selstart, d->m_selend));
1965     d->finishChange(priorState);
1966
1967     if (d->lastSelectionStart != d->lastSelectionEnd) {
1968         if (d->m_selstart != d->lastSelectionStart) {
1969             d->lastSelectionStart = d->m_selstart;
1970             emit selectionStartChanged();
1971         }
1972         if (d->m_selend != d->lastSelectionEnd) {
1973             d->lastSelectionEnd = d->m_selend;
1974             emit selectionEndChanged();
1975         }
1976     }
1977 }
1978
1979 /*!
1980     \qmlmethod string QtQuick2::TextInput::getText(int start, int end)
1981
1982     Removes the section of text that is between the \a start and \a end positions from the TextInput.
1983 */
1984
1985 void QQuickTextInput::remove(int start, int end)
1986 {
1987     Q_D(QQuickTextInput);
1988
1989     start = qBound(0, start, d->m_text.length());
1990     end = qBound(0, end, d->m_text.length());
1991
1992     if (start > end)
1993         qSwap(start, end);
1994     else if (start == end)
1995         return;
1996
1997     if (start < d->m_selend && end > d->m_selstart)
1998         d->m_selDirty = true;
1999
2000     const int priorState = d->m_undoState;
2001
2002     d->addCommand(QQuickTextInputPrivate::Command(
2003             QQuickTextInputPrivate::SetSelection, d->m_cursor, 0, d->m_selstart, d->m_selend));
2004
2005     if (start <= d->m_cursor && d->m_cursor < end) {
2006         // cursor is within the selection. Split up the commands
2007         // to be able to restore the correct cursor position
2008         for (int i = d->m_cursor; i >= start; --i) {
2009             d->addCommand(QQuickTextInputPrivate::Command(
2010                     QQuickTextInputPrivate::DeleteSelection, i, d->m_text.at(i), -1, 1));
2011         }
2012         for (int i = end - 1; i > d->m_cursor; --i) {
2013             d->addCommand(QQuickTextInputPrivate::Command(
2014                     QQuickTextInputPrivate::DeleteSelection, i - d->m_cursor + start - 1, d->m_text.at(i), -1, -1));
2015         }
2016     } else {
2017         for (int i = end - 1; i >= start; --i) {
2018             d->addCommand(QQuickTextInputPrivate::Command(
2019                     QQuickTextInputPrivate::RemoveSelection, i, d->m_text.at(i), -1, -1));
2020         }
2021     }
2022     if (d->m_maskData) {
2023         d->m_text.replace(start, end - start,  d->clearString(start, end - start));
2024         for (int i = 0; i < end - start; ++i) {
2025             d->addCommand(QQuickTextInputPrivate::Command(
2026                     QQuickTextInputPrivate::Insert, start + i, d->m_text.at(start + i), -1, -1));
2027         }
2028     } else {
2029         d->m_text.remove(start, end - start);
2030
2031         if (d->m_cursor > start)
2032             d->m_cursor -= qMin(d->m_cursor, end) - start;
2033         if (d->m_selstart > start)
2034             d->m_selstart -= qMin(d->m_selstart, end) - start;
2035         if (d->m_selend > end)
2036             d->m_selend -= qMin(d->m_selend, end) - start;
2037     }
2038     d->addCommand(QQuickTextInputPrivate::Command(
2039             QQuickTextInputPrivate::SetSelection, d->m_cursor, 0, d->m_selstart, d->m_selend));
2040
2041     d->m_textDirty = true;
2042     d->finishChange(priorState);
2043
2044     if (d->lastSelectionStart != d->lastSelectionEnd) {
2045         if (d->m_selstart != d->lastSelectionStart) {
2046             d->lastSelectionStart = d->m_selstart;
2047             emit selectionStartChanged();
2048         }
2049         if (d->m_selend != d->lastSelectionEnd) {
2050             d->lastSelectionEnd = d->m_selend;
2051             emit selectionEndChanged();
2052         }
2053     }
2054 }
2055
2056
2057 /*!
2058     \qmlmethod void QtQuick2::TextInput::selectWord()
2059
2060     Causes the word closest to the current cursor position to be selected.
2061 */
2062 void QQuickTextInput::selectWord()
2063 {
2064     Q_D(QQuickTextInput);
2065     d->selectWordAtPos(d->m_cursor);
2066 }
2067
2068 /*!
2069     \qmlproperty bool QtQuick2::TextInput::smooth
2070
2071     This property holds whether the text is smoothly scaled or transformed.
2072
2073     Smooth filtering gives better visual quality, but is slower.  If
2074     the item is displayed at its natural size, this property has no visual or
2075     performance effect.
2076
2077     \note Generally scaling artifacts are only visible if the item is stationary on
2078     the screen.  A common pattern when animating an item is to disable smooth
2079     filtering at the beginning of the animation and reenable it at the conclusion.
2080 */
2081
2082 /*!
2083    \qmlproperty string QtQuick2::TextInput::passwordCharacter
2084
2085    This is the character displayed when echoMode is set to Password or
2086    PasswordEchoOnEdit. By default it is an asterisk.
2087
2088    If this property is set to a string with more than one character,
2089    the first character is used. If the string is empty, the value
2090    is ignored and the property is not set.
2091 */
2092 QString QQuickTextInput::passwordCharacter() const
2093 {
2094     Q_D(const QQuickTextInput);
2095     return QString(d->m_passwordCharacter);
2096 }
2097
2098 void QQuickTextInput::setPasswordCharacter(const QString &str)
2099 {
2100     Q_D(QQuickTextInput);
2101     if (str.length() < 1)
2102         return;
2103     d->m_passwordCharacter = str.constData()[0];
2104     if (d->m_echoMode == Password || d->m_echoMode == PasswordEchoOnEdit)
2105         d->updateDisplayText();
2106     emit passwordCharacterChanged();
2107 }
2108
2109 /*!
2110    \qmlproperty string QtQuick2::TextInput::displayText
2111
2112    This is the text displayed in the TextInput.
2113
2114    If \l echoMode is set to TextInput::Normal, this holds the
2115    same value as the TextInput::text property. Otherwise,
2116    this property holds the text visible to the user, while
2117    the \l text property holds the actual entered text.
2118 */
2119 QString QQuickTextInput::displayText() const
2120 {
2121     Q_D(const QQuickTextInput);
2122     return d->m_textLayout.text();
2123 }
2124
2125 /*!
2126     \qmlproperty bool QtQuick2::TextInput::selectByMouse
2127
2128     Defaults to false.
2129
2130     If true, the user can use the mouse to select text in some
2131     platform-specific way. Note that for some platforms this may
2132     not be an appropriate interaction (eg. may conflict with how
2133     the text needs to behave inside a Flickable.
2134 */
2135 bool QQuickTextInput::selectByMouse() const
2136 {
2137     Q_D(const QQuickTextInput);
2138     return d->selectByMouse;
2139 }
2140
2141 void QQuickTextInput::setSelectByMouse(bool on)
2142 {
2143     Q_D(QQuickTextInput);
2144     if (d->selectByMouse != on) {
2145         d->selectByMouse = on;
2146         emit selectByMouseChanged(on);
2147     }
2148 }
2149
2150 /*!
2151     \qmlproperty enum QtQuick2::TextInput::mouseSelectionMode
2152
2153     Specifies how text should be selected using a mouse.
2154
2155     \list
2156     \li TextInput.SelectCharacters - The selection is updated with individual characters. (Default)
2157     \li TextInput.SelectWords - The selection is updated with whole words.
2158     \endlist
2159
2160     This property only applies when \l selectByMouse is true.
2161 */
2162
2163 QQuickTextInput::SelectionMode QQuickTextInput::mouseSelectionMode() const
2164 {
2165     Q_D(const QQuickTextInput);
2166     return d->mouseSelectionMode;
2167 }
2168
2169 void QQuickTextInput::setMouseSelectionMode(SelectionMode mode)
2170 {
2171     Q_D(QQuickTextInput);
2172     if (d->mouseSelectionMode != mode) {
2173         d->mouseSelectionMode = mode;
2174         emit mouseSelectionModeChanged(mode);
2175     }
2176 }
2177
2178 /*!
2179     \qmlproperty bool QtQuick2::TextInput::persistentSelection
2180
2181     Whether the TextInput should keep its selection when it loses active focus to another
2182     item in the scene. By default this is set to false;
2183 */
2184
2185 bool QQuickTextInput::persistentSelection() const
2186 {
2187     Q_D(const QQuickTextInput);
2188     return d->persistentSelection;
2189 }
2190
2191 void QQuickTextInput::setPersistentSelection(bool on)
2192 {
2193     Q_D(QQuickTextInput);
2194     if (d->persistentSelection == on)
2195         return;
2196     d->persistentSelection = on;
2197     emit persistentSelectionChanged();
2198 }
2199
2200 #ifndef QT_NO_CLIPBOARD
2201 /*!
2202     \qmlproperty bool QtQuick2::TextInput::canPaste
2203
2204     Returns true if the TextInput is writable and the content of the clipboard is
2205     suitable for pasting into the TextInput.
2206 */
2207 bool QQuickTextInput::canPaste() const
2208 {
2209     Q_D(const QQuickTextInput);
2210     if (!d->canPasteValid) {
2211         if (const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData())
2212             const_cast<QQuickTextInputPrivate *>(d)->canPaste = !d->m_readOnly && mimeData->hasText();
2213         const_cast<QQuickTextInputPrivate *>(d)->canPasteValid = true;
2214     }
2215     return d->canPaste;
2216 }
2217 #endif
2218
2219 /*!
2220     \qmlproperty bool QtQuick2::TextInput::canUndo
2221
2222     Returns true if the TextInput is writable and there are previous operations
2223     that can be undone.
2224 */
2225
2226 bool QQuickTextInput::canUndo() const
2227 {
2228     Q_D(const QQuickTextInput);
2229     return d->canUndo;
2230 }
2231
2232 /*!
2233     \qmlproperty bool QtQuick2::TextInput::canRedo
2234
2235     Returns true if the TextInput is writable and there are \l {undo}{undone}
2236     operations that can be redone.
2237 */
2238
2239 bool QQuickTextInput::canRedo() const
2240 {
2241     Q_D(const QQuickTextInput);
2242     return d->canRedo;
2243 }
2244
2245 /*!
2246     \qmlproperty real QtQuick2::TextInput::contentWidth
2247
2248     Returns the width of the text, including the width past the width
2249     which is covered due to insufficient wrapping if \l wrapMode is set.
2250 */
2251
2252 qreal QQuickTextInput::contentWidth() const
2253 {
2254     Q_D(const QQuickTextInput);
2255     return d->contentSize.width();
2256 }
2257
2258 /*!
2259     \qmlproperty real QtQuick2::TextInput::contentHeight
2260
2261     Returns the height of the text, including the height past the height
2262     that is covered if the text does not fit within the set height.
2263 */
2264
2265 qreal QQuickTextInput::contentHeight() const
2266 {
2267     Q_D(const QQuickTextInput);
2268     return d->contentSize.height();
2269 }
2270
2271 void QQuickTextInput::moveCursorSelection(int position)
2272 {
2273     Q_D(QQuickTextInput);
2274     d->moveCursor(position, true);
2275 }
2276
2277 /*!
2278     \qmlmethod void QtQuick2::TextInput::moveCursorSelection(int position, SelectionMode mode = TextInput.SelectCharacters)
2279
2280     Moves the cursor to \a position and updates the selection according to the optional \a mode
2281     parameter.  (To only move the cursor, set the \l cursorPosition property.)
2282
2283     When this method is called it additionally sets either the
2284     selectionStart or the selectionEnd (whichever was at the previous cursor position)
2285     to the specified position. This allows you to easily extend and contract the selected
2286     text range.
2287
2288     The selection mode specifies whether the selection is updated on a per character or a per word
2289     basis.  If not specified the selection mode will default to TextInput.SelectCharacters.
2290
2291     \list
2292     \li TextInput.SelectCharacters - Sets either the selectionStart or selectionEnd (whichever was at
2293     the previous cursor position) to the specified position.
2294     \li TextInput.SelectWords - Sets the selectionStart and selectionEnd to include all
2295     words between the specified position and the previous cursor position.  Words partially in the
2296     range are included.
2297     \endlist
2298
2299     For example, take this sequence of calls:
2300
2301     \code
2302         cursorPosition = 5
2303         moveCursorSelection(9, TextInput.SelectCharacters)
2304         moveCursorSelection(7, TextInput.SelectCharacters)
2305     \endcode
2306
2307     This moves the cursor to position 5, extend the selection end from 5 to 9
2308     and then retract the selection end from 9 to 7, leaving the text from position 5 to 7
2309     selected (the 6th and 7th characters).
2310
2311     The same sequence with TextInput.SelectWords will extend the selection start to a word boundary
2312     before or on position 5 and extend the selection end to a word boundary on or past position 9.
2313 */
2314 void QQuickTextInput::moveCursorSelection(int pos, SelectionMode mode)
2315 {
2316     Q_D(QQuickTextInput);
2317
2318     if (mode == SelectCharacters) {
2319         d->moveCursor(pos, true);
2320     } else if (pos != d->m_cursor){
2321         const int cursor = d->m_cursor;
2322         int anchor;
2323         if (!d->hasSelectedText())
2324             anchor = d->m_cursor;
2325         else if (d->selectionStart() == d->m_cursor)
2326             anchor = d->selectionEnd();
2327         else
2328             anchor = d->selectionStart();
2329
2330         if (anchor < pos || (anchor == pos && cursor < pos)) {
2331             const QString text = this->text();
2332             QTextBoundaryFinder finder(QTextBoundaryFinder::Word, text);
2333             finder.setPosition(anchor);
2334
2335             const QTextBoundaryFinder::BoundaryReasons reasons = finder.boundaryReasons();
2336             if (anchor < text.length() && (!(reasons & QTextBoundaryFinder::StartWord)
2337                     || ((reasons & QTextBoundaryFinder::EndWord) && anchor > cursor))) {
2338                 finder.toPreviousBoundary();
2339             }
2340             anchor = finder.position() != -1 ? finder.position() : 0;
2341
2342             finder.setPosition(pos);
2343             if (pos > 0 && !finder.boundaryReasons())
2344                 finder.toNextBoundary();
2345             const int cursor = finder.position() != -1 ? finder.position() : text.length();
2346
2347             d->setSelection(anchor, cursor - anchor);
2348         } else if (anchor > pos || (anchor == pos && cursor > pos)) {
2349             const QString text = this->text();
2350             QTextBoundaryFinder finder(QTextBoundaryFinder::Word, text);
2351             finder.setPosition(anchor);
2352
2353             const QTextBoundaryFinder::BoundaryReasons reasons = finder.boundaryReasons();
2354             if (anchor > 0 && (!(reasons & QTextBoundaryFinder::EndWord)
2355                     || ((reasons & QTextBoundaryFinder::StartWord) && anchor < cursor))) {
2356                 finder.toNextBoundary();
2357             }
2358
2359             anchor = finder.position() != -1 ? finder.position() : text.length();
2360
2361             finder.setPosition(pos);
2362             if (pos < text.length() && !finder.boundaryReasons())
2363                  finder.toPreviousBoundary();
2364             const int cursor = finder.position() != -1 ? finder.position() : 0;
2365
2366             d->setSelection(anchor, cursor - anchor);
2367         }
2368     }
2369 }
2370
2371 /*!
2372     \qmlmethod void QtQuick2::TextInput::openSoftwareInputPanel()
2373
2374     Opens software input panels like virtual keyboards for typing, useful for
2375     customizing when you want the input keyboard to be shown and hidden in
2376     your application.
2377
2378     By default the opening of input panels follows the platform style. Input panels are
2379     always closed if no editor has active focus.
2380
2381     You can disable the automatic behavior by setting the property \c activeFocusOnPress to false
2382     and use functions openSoftwareInputPanel() and closeSoftwareInputPanel() to implement
2383     the behavior you want.
2384
2385     Only relevant on platforms, which provide virtual keyboards.
2386
2387     \qml
2388         import QtQuick 2.0
2389         TextInput {
2390             id: textInput
2391             text: "Hello world!"
2392             activeFocusOnPress: false
2393             MouseArea {
2394                 anchors.fill: parent
2395                 onClicked: {
2396                     if (!textInput.activeFocus) {
2397                         textInput.forceActiveFocus()
2398                         textInput.openSoftwareInputPanel();
2399                     } else {
2400                         textInput.focus = false;
2401                     }
2402                 }
2403                 onPressAndHold: textInput.closeSoftwareInputPanel();
2404             }
2405         }
2406     \endqml
2407 */
2408 void QQuickTextInput::openSoftwareInputPanel()
2409 {
2410     if (qGuiApp)
2411         qGuiApp->inputMethod()->show();
2412 }
2413
2414 /*!
2415     \qmlmethod void QtQuick2::TextInput::closeSoftwareInputPanel()
2416
2417     Closes a software input panel like a virtual keyboard shown on the screen, useful
2418     for customizing when you want the input keyboard to be shown and hidden in
2419     your application.
2420
2421     By default the opening of input panels follows the platform style. Input panels are
2422     always closed if no editor has active focus.
2423
2424     You can disable the automatic behavior by setting the property \c activeFocusOnPress to false
2425     and use functions openSoftwareInputPanel() and closeSoftwareInputPanel() to implement
2426     the behavior you want.
2427
2428     Only relevant on platforms, which provide virtual keyboards.
2429
2430     \qml
2431         import QtQuick 2.0
2432         TextInput {
2433             id: textInput
2434             text: "Hello world!"
2435             activeFocusOnPress: false
2436             MouseArea {
2437                 anchors.fill: parent
2438                 onClicked: {
2439                     if (!textInput.activeFocus) {
2440                         textInput.forceActiveFocus();
2441                         textInput.openSoftwareInputPanel();
2442                     } else {
2443                         textInput.focus = false;
2444                     }
2445                 }
2446                 onPressAndHold: textInput.closeSoftwareInputPanel();
2447             }
2448         }
2449     \endqml
2450 */
2451 void QQuickTextInput::closeSoftwareInputPanel()
2452 {
2453     if (qGuiApp)
2454         qGuiApp->inputMethod()->hide();
2455 }
2456
2457 void QQuickTextInput::focusInEvent(QFocusEvent *event)
2458 {
2459     Q_D(const QQuickTextInput);
2460     if (d->focusOnPress && !d->m_readOnly)
2461         openSoftwareInputPanel();
2462     QQuickImplicitSizeItem::focusInEvent(event);
2463 }
2464
2465 void QQuickTextInput::itemChange(ItemChange change, const ItemChangeData &value)
2466 {
2467     Q_D(QQuickTextInput);
2468     if (change == ItemActiveFocusHasChanged) {
2469         bool hasFocus = value.boolValue;
2470         setCursorVisible(hasFocus); // ### refactor:  && d->canvas && d->canvas->hasFocus()
2471         if (!hasFocus && (d->m_passwordEchoEditing || d->m_passwordEchoTimer.isActive())) {
2472             d->updatePasswordEchoEditing(false);//QQuickTextInputPrivate sets it on key events, but doesn't deal with focus events
2473         }
2474
2475         if (!hasFocus) {
2476             if (!d->persistentSelection)
2477                 d->deselect();
2478             disconnect(qApp->inputMethod(), SIGNAL(inputDirectionChanged(Qt::LayoutDirection)),
2479                        this, SLOT(q_updateAlignment()));
2480         } else {
2481             q_updateAlignment();
2482             connect(qApp->inputMethod(), SIGNAL(inputDirectionChanged(Qt::LayoutDirection)),
2483                     this, SLOT(q_updateAlignment()));
2484         }
2485     }
2486     QQuickItem::itemChange(change, value);
2487 }
2488
2489 /*!
2490     \qmlproperty bool QtQuick2::TextInput::inputMethodComposing
2491
2492
2493     This property holds whether the TextInput has partial text input from an
2494     input method.
2495
2496     While it is composing an input method may rely on mouse or key events from
2497     the TextInput to edit or commit the partial text.  This property can be
2498     used to determine when to disable events handlers that may interfere with
2499     the correct operation of an input method.
2500 */
2501 bool QQuickTextInput::isInputMethodComposing() const
2502 {
2503     Q_D(const QQuickTextInput);
2504     return d->hasImState;
2505 }
2506
2507 void QQuickTextInputPrivate::init()
2508 {
2509     Q_Q(QQuickTextInput);
2510     q->setSmooth(smooth);
2511     q->setAcceptedMouseButtons(Qt::LeftButton);
2512     q->setFlag(QQuickItem::ItemAcceptsInputMethod);
2513     q->setFlag(QQuickItem::ItemHasContents);
2514 #ifndef QT_NO_CLIPBOARD
2515     q->connect(QGuiApplication::clipboard(), SIGNAL(dataChanged()),
2516             q, SLOT(q_canPasteChanged()));
2517 #endif // QT_NO_CLIPBOARD
2518
2519     lastSelectionStart = 0;
2520     lastSelectionEnd = 0;
2521     determineHorizontalAlignment();
2522
2523     if (!qmlDisableDistanceField()) {
2524         QTextOption option = m_textLayout.textOption();
2525         option.setUseDesignMetrics(true);
2526         m_textLayout.setTextOption(option);
2527     }
2528 }
2529
2530 void QQuickTextInput::updateCursorRectangle()
2531 {
2532     Q_D(QQuickTextInput);
2533     if (!isComponentComplete())
2534         return;
2535
2536     d->updateHorizontalScroll();
2537     d->updateVerticalScroll();
2538     d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
2539     update();
2540     emit cursorRectangleChanged();
2541     if (d->cursorItem) {
2542         QRectF r = cursorRectangle();
2543         d->cursorItem->setPos(r.topLeft());
2544         d->cursorItem->setHeight(r.height());
2545     }
2546     updateInputMethod(Qt::ImCursorRectangle);
2547 }
2548
2549 void QQuickTextInput::selectionChanged()
2550 {
2551     Q_D(QQuickTextInput);
2552     d->textLayoutDirty = true; //TODO: Only update rect in selection
2553     d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
2554     update();
2555     emit selectedTextChanged();
2556
2557     if (d->lastSelectionStart != d->selectionStart()) {
2558         d->lastSelectionStart = d->selectionStart();
2559         if (d->lastSelectionStart == -1)
2560             d->lastSelectionStart = d->m_cursor;
2561         emit selectionStartChanged();
2562     }
2563     if (d->lastSelectionEnd != d->selectionEnd()) {
2564         d->lastSelectionEnd = d->selectionEnd();
2565         if (d->lastSelectionEnd == -1)
2566             d->lastSelectionEnd = d->m_cursor;
2567         emit selectionEndChanged();
2568     }
2569 }
2570
2571 void QQuickTextInputPrivate::showCursor()
2572 {
2573     if (textNode != 0 && textNode->cursorNode() != 0)
2574         textNode->cursorNode()->setColor(color);
2575 }
2576
2577 void QQuickTextInputPrivate::hideCursor()
2578 {
2579     if (textNode != 0 && textNode->cursorNode() != 0)
2580         textNode->cursorNode()->setColor(QColor(0, 0, 0, 0));
2581 }
2582
2583 QRectF QQuickTextInput::boundingRect() const
2584 {
2585     Q_D(const QQuickTextInput);
2586
2587     int cursorWidth = d->cursorItem ? 0 : 1;
2588
2589     qreal hscroll = d->hscroll;
2590     if (!d->autoScroll || d->contentSize.width() < width()) {
2591         switch (effectiveHAlign()) {
2592         case AlignLeft:
2593             break;
2594         case AlignRight:
2595             hscroll += d->contentSize.width() - width();
2596             break;
2597         case AlignHCenter:
2598             hscroll += (d->contentSize.width() - width()) / 2;
2599             break;
2600         }
2601     }
2602
2603     // Could include font max left/right bearings to either side of rectangle.
2604     QRectF r(-hscroll, -d->vscroll, d->contentSize.width(), d->contentSize.height());
2605     r.setRight(r.right() + cursorWidth);
2606     return r;
2607 }
2608
2609 QRectF QQuickTextInput::clipRect() const
2610 {
2611     Q_D(const QQuickTextInput);
2612
2613     int cursorWidth = d->cursorItem ? d->cursorItem->width() : 1;
2614
2615     // Could include font max left/right bearings to either side of rectangle.
2616     QRectF r = QQuickImplicitSizeItem::clipRect();
2617     r.setRight(r.right() + cursorWidth);
2618     return r;
2619 }
2620
2621 void QQuickTextInput::q_canPasteChanged()
2622 {
2623     Q_D(QQuickTextInput);
2624     bool old = d->canPaste;
2625 #ifndef QT_NO_CLIPBOARD
2626     if (const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData())
2627         d->canPaste = !d->m_readOnly && mimeData->hasText();
2628     else
2629         d->canPaste = false;
2630 #endif
2631
2632     bool changed = d->canPaste != old || !d->canPasteValid;
2633     d->canPasteValid = true;
2634     if (changed)
2635         emit canPasteChanged();
2636
2637 }
2638
2639 void QQuickTextInput::q_updateAlignment()
2640 {
2641     Q_D(QQuickTextInput);
2642     if (d->determineHorizontalAlignment()) {
2643         d->updateLayout();
2644         updateCursorRectangle();
2645     }
2646 }
2647
2648 // ### these should come from QStyleHints
2649 const int textCursorWidth = 1;
2650 const bool fullWidthSelection = true;
2651
2652 /*!
2653     \internal
2654
2655     Updates the display text based of the current edit text
2656     If the text has changed will emit displayTextChanged()
2657 */
2658 void QQuickTextInputPrivate::updateDisplayText(bool forceUpdate)
2659 {
2660     QString orig = m_textLayout.text();
2661     QString str;
2662     if (m_echoMode == QQuickTextInput::NoEcho)
2663         str = QString::fromLatin1("");
2664     else
2665         str = m_text;
2666
2667     if (m_echoMode == QQuickTextInput::Password) {
2668          str.fill(m_passwordCharacter);
2669         if (m_passwordEchoTimer.isActive() && m_cursor > 0 && m_cursor <= m_text.length()) {
2670             int cursor = m_cursor - 1;
2671             QChar uc = m_text.at(cursor);
2672             str[cursor] = uc;
2673             if (cursor > 0 && uc.unicode() >= 0xdc00 && uc.unicode() < 0xe000) {
2674                 // second half of a surrogate, check if we have the first half as well,
2675                 // if yes restore both at once
2676                 uc = m_text.at(cursor - 1);
2677                 if (uc.unicode() >= 0xd800 && uc.unicode() < 0xdc00)
2678                     str[cursor - 1] = uc;
2679             }
2680         }
2681     } else if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit && !m_passwordEchoEditing) {
2682         str.fill(m_passwordCharacter);
2683     }
2684
2685     // replace certain non-printable characters with spaces (to avoid
2686     // drawing boxes when using fonts that don't have glyphs for such
2687     // characters)
2688     QChar* uc = str.data();
2689     for (int i = 0; i < (int)str.length(); ++i) {
2690         if ((uc[i] < 0x20 && uc[i] != 0x09)
2691             || uc[i] == QChar::LineSeparator
2692             || uc[i] == QChar::ParagraphSeparator
2693             || uc[i] == QChar::ObjectReplacementCharacter)
2694             uc[i] = QChar(0x0020);
2695     }
2696
2697     if (str != orig || forceUpdate) {
2698         m_textLayout.setText(str);
2699         updateLayout(); // polish?
2700         emit q_func()->displayTextChanged();
2701     }
2702 }
2703
2704 qreal QQuickTextInputPrivate::getImplicitWidth() const
2705 {
2706     Q_Q(const QQuickTextInput);
2707     if (!requireImplicitWidth) {
2708         QQuickTextInputPrivate *d = const_cast<QQuickTextInputPrivate *>(this);
2709         d->requireImplicitWidth = true;
2710
2711         if (q->isComponentComplete()) {
2712             // One time cost, only incurred if implicitWidth is first requested after
2713             // componentComplete.
2714             QTextLayout layout(m_text);
2715
2716             QTextOption option = m_textLayout.textOption();
2717             option.setTextDirection(m_layoutDirection);
2718             option.setFlags(QTextOption::IncludeTrailingSpaces);
2719             option.setWrapMode(QTextOption::WrapMode(wrapMode));
2720             option.setAlignment(Qt::Alignment(q->effectiveHAlign()));
2721             layout.setTextOption(option);
2722             layout.setFont(font);
2723             layout.setPreeditArea(m_textLayout.preeditAreaPosition(), m_textLayout.preeditAreaText());
2724             layout.beginLayout();
2725
2726             QTextLine line = layout.createLine();
2727             line.setLineWidth(INT_MAX);
2728             d->implicitWidth = qCeil(line.naturalTextWidth());
2729
2730             layout.endLayout();
2731         }
2732     }
2733     return implicitWidth;
2734 }
2735
2736 void QQuickTextInputPrivate::updateLayout()
2737 {
2738     Q_Q(QQuickTextInput);
2739
2740     if (!q->isComponentComplete())
2741         return;
2742
2743
2744     QTextOption option = m_textLayout.textOption();
2745     option.setTextDirection(layoutDirection());
2746     option.setWrapMode(QTextOption::WrapMode(wrapMode));
2747     option.setAlignment(Qt::Alignment(q->effectiveHAlign()));
2748     m_textLayout.setTextOption(option);
2749     m_textLayout.setFont(font);
2750
2751     m_textLayout.beginLayout();
2752
2753     QTextLine line = m_textLayout.createLine();
2754     if (requireImplicitWidth) {
2755         line.setLineWidth(INT_MAX);
2756         const bool wasInLayout = inLayout;
2757         inLayout = true;
2758         q->setImplicitWidth(qCeil(line.naturalTextWidth()));
2759         inLayout = wasInLayout;
2760         if (inLayout)       // probably the result of a binding loop, but by letting it
2761             return;         // get this far we'll get a warning to that effect.
2762     }
2763     qreal lineWidth = q->widthValid() ? q->width() : INT_MAX;
2764     qreal height = 0;
2765     qreal width = 0;
2766     do {
2767         line.setLineWidth(lineWidth);
2768         line.setPosition(QPointF(0, height));
2769
2770         height += line.height();
2771         width = qMax(width, line.naturalTextWidth());
2772
2773         line = m_textLayout.createLine();
2774     } while (line.isValid());
2775     m_textLayout.endLayout();
2776
2777     option.setWrapMode(QTextOption::NoWrap);
2778     m_textLayout.setTextOption(option);
2779
2780     textLayoutDirty = true;
2781
2782     const QSizeF previousSize = contentSize;
2783     contentSize = QSizeF(width, height);
2784
2785     updateType = UpdatePaintNode;
2786     q->update();
2787
2788     if (!requireImplicitWidth && !q->widthValid())
2789         q->setImplicitSize(width, height);
2790     else
2791         q->setImplicitHeight(height);
2792
2793     if (previousSize != contentSize)
2794         emit q->contentSizeChanged();
2795 }
2796
2797 #ifndef QT_NO_CLIPBOARD
2798 /*!
2799     \internal
2800
2801     Copies the currently selected text into the clipboard using the given
2802     \a mode.
2803
2804     \note If the echo mode is set to a mode other than Normal then copy
2805     will not work.  This is to prevent using copy as a method of bypassing
2806     password features of the line control.
2807 */
2808 void QQuickTextInputPrivate::copy(QClipboard::Mode mode) const
2809 {
2810     QString t = selectedText();
2811     if (!t.isEmpty() && m_echoMode == QQuickTextInput::Normal) {
2812         QGuiApplication::clipboard()->setText(t, mode);
2813     }
2814 }
2815
2816 /*!
2817     \internal
2818
2819     Inserts the text stored in the application clipboard into the line
2820     control.
2821
2822     \sa insert()
2823 */
2824 void QQuickTextInputPrivate::paste(QClipboard::Mode clipboardMode)
2825 {
2826     QString clip = QGuiApplication::clipboard()->text(clipboardMode);
2827     if (!clip.isEmpty() || hasSelectedText()) {
2828         separate(); //make it a separate undo/redo command
2829         insert(clip);
2830         separate();
2831     }
2832 }
2833
2834 #endif // !QT_NO_CLIPBOARD
2835
2836 /*!
2837     \internal
2838 */
2839 void QQuickTextInputPrivate::commitPreedit()
2840 {
2841     Q_Q(QQuickTextInput);
2842
2843     if (!hasImState)
2844         return;
2845
2846     qApp->inputMethod()->commit();
2847
2848     if (!hasImState)
2849         return;
2850
2851     QInputMethodEvent ev;
2852     QCoreApplication::sendEvent(q, &ev);
2853 }
2854
2855 void QQuickTextInputPrivate::cancelPreedit()
2856 {
2857     Q_Q(QQuickTextInput);
2858
2859     if (!hasImState)
2860         return;
2861
2862     qApp->inputMethod()->reset();
2863
2864     QInputMethodEvent ev;
2865     QCoreApplication::sendEvent(q, &ev);
2866 }
2867
2868 /*!
2869     \internal
2870
2871     Handles the behavior for the backspace key or function.
2872     Removes the current selection if there is a selection, otherwise
2873     removes the character prior to the cursor position.
2874
2875     \sa del()
2876 */
2877 void QQuickTextInputPrivate::backspace()
2878 {
2879     int priorState = m_undoState;
2880     if (hasSelectedText()) {
2881         removeSelectedText();
2882     } else if (m_cursor) {
2883             --m_cursor;
2884             if (m_maskData)
2885                 m_cursor = prevMaskBlank(m_cursor);
2886             QChar uc = m_text.at(m_cursor);
2887             if (m_cursor > 0 && uc.unicode() >= 0xdc00 && uc.unicode() < 0xe000) {
2888                 // second half of a surrogate, check if we have the first half as well,
2889                 // if yes delete both at once
2890                 uc = m_text.at(m_cursor - 1);
2891                 if (uc.unicode() >= 0xd800 && uc.unicode() < 0xdc00) {
2892                     internalDelete(true);
2893                     --m_cursor;
2894                 }
2895             }
2896             internalDelete(true);
2897     }
2898     finishChange(priorState);
2899 }
2900
2901 /*!
2902     \internal
2903
2904     Handles the behavior for the delete key or function.
2905     Removes the current selection if there is a selection, otherwise
2906     removes the character after the cursor position.
2907
2908     \sa del()
2909 */
2910 void QQuickTextInputPrivate::del()
2911 {
2912     int priorState = m_undoState;
2913     if (hasSelectedText()) {
2914         removeSelectedText();
2915     } else {
2916         int n = m_textLayout.nextCursorPosition(m_cursor) - m_cursor;
2917         while (n--)
2918             internalDelete();
2919     }
2920     finishChange(priorState);
2921 }
2922
2923 /*!
2924     \internal
2925
2926     Inserts the given \a newText at the current cursor position.
2927     If there is any selected text it is removed prior to insertion of
2928     the new text.
2929 */
2930 void QQuickTextInputPrivate::insert(const QString &newText)
2931 {
2932     int priorState = m_undoState;
2933     removeSelectedText();
2934     internalInsert(newText);
2935     finishChange(priorState);
2936 }
2937
2938 /*!
2939     \internal
2940
2941     Clears the line control text.
2942 */
2943 void QQuickTextInputPrivate::clear()
2944 {
2945     int priorState = m_undoState;
2946     m_selstart = 0;
2947     m_selend = m_text.length();
2948     removeSelectedText();
2949     separate();
2950     finishChange(priorState, /*update*/false, /*edited*/false);
2951 }
2952
2953 /*!
2954     \internal
2955
2956     Sets \a length characters from the given \a start position as selected.
2957     The given \a start position must be within the current text for
2958     the line control.  If \a length characters cannot be selected, then
2959     the selection will extend to the end of the current text.
2960 */
2961 void QQuickTextInputPrivate::setSelection(int start, int length)
2962 {
2963     Q_Q(QQuickTextInput);
2964     commitPreedit();
2965
2966     if (start < 0 || start > (int)m_text.length()){
2967         qWarning("QQuickTextInputPrivate::setSelection: Invalid start position");
2968         return;
2969     }
2970
2971     if (length > 0) {
2972         if (start == m_selstart && start + length == m_selend && m_cursor == m_selend)
2973             return;
2974         m_selstart = start;
2975         m_selend = qMin(start + length, (int)m_text.length());
2976         m_cursor = m_selend;
2977     } else if (length < 0){
2978         if (start == m_selend && start + length == m_selstart && m_cursor == m_selstart)
2979             return;
2980         m_selstart = qMax(start + length, 0);
2981         m_selend = start;
2982         m_cursor = m_selstart;
2983     } else if (m_selstart != m_selend) {
2984         m_selstart = 0;
2985         m_selend = 0;
2986         m_cursor = start;
2987     } else {
2988         m_cursor = start;
2989         emitCursorPositionChanged();
2990         return;
2991     }
2992     emit q->selectionChanged();
2993     emitCursorPositionChanged();
2994     q->updateInputMethod(Qt::ImCursorRectangle | Qt::ImAnchorPosition
2995                         | Qt::ImCursorPosition | Qt::ImCurrentSelection);
2996 }
2997
2998 /*!
2999     \internal
3000
3001     Sets the password echo editing to \a editing.  If password echo editing
3002     is true, then the text of the password is displayed even if the echo
3003     mode is set to QLineEdit::PasswordEchoOnEdit.  Password echoing editing
3004     does not affect other echo modes.
3005 */
3006 void QQuickTextInputPrivate::updatePasswordEchoEditing(bool editing)
3007 {
3008     cancelPasswordEchoTimer();
3009     m_passwordEchoEditing = editing;
3010     updateDisplayText();
3011 }
3012
3013 /*!
3014     \internal
3015
3016     Fixes the current text so that it is valid given any set validators.
3017
3018     Returns true if the text was changed.  Otherwise returns false.
3019 */
3020 bool QQuickTextInputPrivate::fixup() // this function assumes that validate currently returns != Acceptable
3021 {
3022 #ifndef QT_NO_VALIDATOR
3023     if (m_validator) {
3024         QString textCopy = m_text;
3025         int cursorCopy = m_cursor;
3026         m_validator->fixup(textCopy);
3027         if (m_validator->validate(textCopy, cursorCopy) == QValidator::Acceptable) {
3028             if (textCopy != m_text || cursorCopy != m_cursor)
3029                 internalSetText(textCopy, cursorCopy);
3030             return true;
3031         }
3032     }
3033 #endif
3034     return false;
3035 }
3036
3037 /*!
3038     \internal
3039
3040     Moves the cursor to the given position \a pos.   If \a mark is true will
3041     adjust the currently selected text.
3042 */
3043 void QQuickTextInputPrivate::moveCursor(int pos, bool mark)
3044 {
3045     Q_Q(QQuickTextInput);
3046     commitPreedit();
3047
3048     if (pos != m_cursor) {
3049         separate();
3050         if (m_maskData)
3051             pos = pos > m_cursor ? nextMaskBlank(pos) : prevMaskBlank(pos);
3052     }
3053     if (mark) {
3054         int anchor;
3055         if (m_selend > m_selstart && m_cursor == m_selstart)
3056             anchor = m_selend;
3057         else if (m_selend > m_selstart && m_cursor == m_selend)
3058             anchor = m_selstart;
3059         else
3060             anchor = m_cursor;
3061         m_selstart = qMin(anchor, pos);
3062         m_selend = qMax(anchor, pos);
3063     } else {
3064         internalDeselect();
3065     }
3066     m_cursor = pos;
3067     if (mark || m_selDirty) {
3068         m_selDirty = false;
3069         emit q->selectionChanged();
3070     }
3071     emitCursorPositionChanged();
3072     q->updateInputMethod();
3073 }
3074
3075 /*!
3076     \internal
3077
3078     Applies the given input method event \a event to the text of the line
3079     control
3080 */
3081 void QQuickTextInputPrivate::processInputMethodEvent(QInputMethodEvent *event)
3082 {
3083     Q_Q(QQuickTextInput);
3084
3085     int priorState = -1;
3086     bool isGettingInput = !event->commitString().isEmpty()
3087             || event->preeditString() != preeditAreaText()
3088             || event->replacementLength() > 0;
3089     bool cursorPositionChanged = false;
3090     bool selectionChange = false;
3091     m_preeditDirty = event->preeditString() != preeditAreaText();
3092
3093     if (isGettingInput) {
3094         // If any text is being input, remove selected text.
3095         priorState = m_undoState;
3096         if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit && !m_passwordEchoEditing) {
3097             updatePasswordEchoEditing(true);
3098             m_selstart = 0;
3099             m_selend = m_text.length();
3100         }
3101         removeSelectedText();
3102     }
3103
3104     int c = m_cursor; // cursor position after insertion of commit string
3105     if (event->replacementStart() <= 0)
3106         c += event->commitString().length() - qMin(-event->replacementStart(), event->replacementLength());
3107
3108     m_cursor += event->replacementStart();
3109     if (m_cursor < 0)
3110         m_cursor = 0;
3111
3112     // insert commit string
3113     if (event->replacementLength()) {
3114         m_selstart = m_cursor;
3115         m_selend = m_selstart + event->replacementLength();
3116         m_selend = qMin(m_selend, m_text.length());
3117         removeSelectedText();
3118     }
3119     if (!event->commitString().isEmpty()) {
3120         internalInsert(event->commitString());
3121         cursorPositionChanged = true;
3122     }
3123
3124     m_cursor = qBound(0, c, m_text.length());
3125
3126     for (int i = 0; i < event->attributes().size(); ++i) {
3127         const QInputMethodEvent::Attribute &a = event->attributes().at(i);
3128         if (a.type == QInputMethodEvent::Selection) {
3129             m_cursor = qBound(0, a.start + a.length, m_text.length());
3130             if (a.length) {
3131                 m_selstart = qMax(0, qMin(a.start, m_text.length()));
3132                 m_selend = m_cursor;
3133                 if (m_selend < m_selstart) {
3134                     qSwap(m_selstart, m_selend);
3135                 }
3136                 selectionChange = true;
3137             } else {
3138                 m_selstart = m_selend = 0;
3139             }
3140             cursorPositionChanged = true;
3141         }
3142     }
3143 #ifndef QT_NO_IM
3144     m_textLayout.setPreeditArea(m_cursor, event->preeditString());
3145 #endif //QT_NO_IM
3146     const int oldPreeditCursor = m_preeditCursor;
3147     m_preeditCursor = event->preeditString().length();
3148     hasImState = !event->preeditString().isEmpty();
3149     bool cursorVisible = true;
3150     QList<QTextLayout::FormatRange> formats;
3151     for (int i = 0; i < event->attributes().size(); ++i) {
3152         const QInputMethodEvent::Attribute &a = event->attributes().at(i);
3153         if (a.type == QInputMethodEvent::Cursor) {
3154             hasImState = true;
3155             m_preeditCursor = a.start;
3156             cursorVisible = a.length != 0;
3157         } else if (a.type == QInputMethodEvent::TextFormat) {
3158             hasImState = true;
3159             QTextCharFormat f = qvariant_cast<QTextFormat>(a.value).toCharFormat();
3160             if (f.isValid()) {
3161                 QTextLayout::FormatRange o;
3162                 o.start = a.start + m_cursor;
3163                 o.length = a.length;
3164                 o.format = f;
3165                 formats.append(o);
3166             }
3167         }
3168     }
3169     m_textLayout.setAdditionalFormats(formats);
3170
3171     updateDisplayText(/*force*/ true);
3172     if (cursorPositionChanged) {
3173         emitCursorPositionChanged();
3174     } else if (m_preeditCursor != oldPreeditCursor || isGettingInput) {
3175         q->updateCursorRectangle();
3176     }
3177
3178     if (isGettingInput)
3179         finishChange(priorState);
3180
3181     q->setCursorVisible(cursorVisible);
3182
3183     if (selectionChange) {
3184         emit q->selectionChanged();
3185         q->updateInputMethod(Qt::ImCursorRectangle | Qt::ImAnchorPosition
3186                             | Qt::ImCursorPosition | Qt::ImCurrentSelection);
3187     }
3188 }
3189
3190 /*!
3191     \internal
3192
3193     Sets the selection to cover the word at the given cursor position.
3194     The word boundaries are defined by the behavior of QTextLayout::SkipWords
3195     cursor mode.
3196 */
3197 void QQuickTextInputPrivate::selectWordAtPos(int cursor)
3198 {
3199     int next = cursor + 1;
3200     if (next > end())
3201         --next;
3202     int c = m_textLayout.previousCursorPosition(next, QTextLayout::SkipWords);
3203     moveCursor(c, false);
3204     // ## text layout should support end of words.
3205     int end = m_textLayout.nextCursorPosition(c, QTextLayout::SkipWords);
3206     while (end > cursor && m_text[end-1].isSpace())
3207         --end;
3208     moveCursor(end, true);
3209 }
3210
3211 /*!
3212     \internal
3213
3214     Completes a change to the line control text.  If the change is not valid
3215     will undo the line control state back to the given \a validateFromState.
3216
3217     If \a edited is true and the change is valid, will emit textEdited() in
3218     addition to textChanged().  Otherwise only emits textChanged() on a valid
3219     change.
3220
3221     The \a update value is currently unused.
3222 */
3223 bool QQuickTextInputPrivate::finishChange(int validateFromState, bool update, bool /*edited*/)
3224 {
3225     Q_Q(QQuickTextInput);
3226
3227     Q_UNUSED(update)
3228     bool inputMethodAttributesChanged = m_textDirty || m_selDirty;
3229     bool alignmentChanged = false;
3230
3231     if (m_textDirty) {
3232         // do validation
3233         bool wasValidInput = m_validInput;
3234         bool wasAcceptable = m_acceptableInput;
3235         m_validInput = true;
3236         m_acceptableInput = true;
3237 #ifndef QT_NO_VALIDATOR
3238         if (m_validator) {
3239             QString textCopy = m_text;
3240             int cursorCopy = m_cursor;
3241             QValidator::State state = m_validator->validate(textCopy, cursorCopy);
3242             m_validInput = state != QValidator::Invalid;
3243             m_acceptableInput = state == QValidator::Acceptable;
3244             if (m_validInput) {
3245                 if (m_text != textCopy) {
3246                     internalSetText(textCopy, cursorCopy);
3247                     return true;
3248                 }
3249                 m_cursor = cursorCopy;
3250             }
3251         }
3252 #endif
3253         if (validateFromState >= 0 && wasValidInput && !m_validInput) {
3254             if (m_transactions.count())
3255                 return false;
3256             internalUndo(validateFromState);
3257             m_history.resize(m_undoState);
3258             m_validInput = true;
3259             m_acceptableInput = wasAcceptable;
3260             m_textDirty = false;
3261         }
3262
3263         if (m_textDirty) {
3264             m_textDirty = false;
3265             m_preeditDirty = false;
3266             alignmentChanged = determineHorizontalAlignment();
3267             emit q->textChanged();
3268         }
3269
3270         updateDisplayText(alignmentChanged);
3271
3272         if (m_acceptableInput != wasAcceptable)
3273             emit q->acceptableInputChanged();
3274     }
3275     if (m_preeditDirty) {
3276         m_preeditDirty = false;
3277         if (determineHorizontalAlignment()) {
3278             alignmentChanged = true;
3279             updateLayout();
3280         }
3281     }
3282
3283     if (m_selDirty) {
3284         m_selDirty = false;
3285         emit q->selectionChanged();
3286     }
3287
3288     inputMethodAttributesChanged |= (m_cursor != m_lastCursorPos);
3289     if (inputMethodAttributesChanged)
3290         q->updateInputMethod();
3291     emitUndoRedoChanged();
3292
3293     if (!emitCursorPositionChanged() && alignmentChanged)
3294         q->updateCursorRectangle();
3295
3296     return true;
3297 }
3298
3299 /*!
3300     \internal
3301
3302     An internal function for setting the text of the line control.
3303 */
3304 void QQuickTextInputPrivate::internalSetText(const QString &txt, int pos, bool edited)
3305 {
3306     Q_Q(QQuickTextInput);
3307     internalDeselect();
3308     QString oldText = m_text;
3309     if (m_maskData) {
3310         m_text = maskString(0, txt, true);
3311         m_text += clearString(m_text.length(), m_maxLength - m_text.length());
3312     } else {
3313         m_text = txt.isEmpty() ? txt : txt.left(m_maxLength);
3314     }
3315     m_history.clear();
3316     m_undoState = 0;
3317     m_cursor = (pos < 0 || pos > m_text.length()) ? m_text.length() : pos;
3318     m_textDirty = (oldText != m_text);
3319
3320     bool changed = finishChange(-1, true, edited);
3321 #ifdef QT_NO_ACCESSIBILITY
3322     Q_UNUSED(changed)
3323 #else
3324     if (changed) {
3325         QAccessibleTextUpdateEvent ev(q, 0, oldText, m_text);
3326         QAccessible::updateAccessibility(&ev);
3327     }
3328 #endif
3329 }
3330
3331
3332 /*!
3333     \internal
3334
3335     Adds the given \a command to the undo history
3336     of the line control.  Does not apply the command.
3337 */
3338 void QQuickTextInputPrivate::addCommand(const Command &cmd)
3339 {
3340     if (m_separator && m_undoState && m_history[m_undoState - 1].type != Separator) {
3341         m_history.resize(m_undoState + 2);
3342         m_history[m_undoState++] = Command(Separator, m_cursor, 0, m_selstart, m_selend);
3343     } else {
3344         m_history.resize(m_undoState + 1);
3345     }
3346     m_separator = false;
3347     m_history[m_undoState++] = cmd;
3348 }
3349
3350 /*!
3351     \internal
3352
3353     Inserts the given string \a s into the line
3354     control.
3355
3356     Also adds the appropriate commands into the undo history.
3357     This function does not call finishChange(), and may leave the text
3358     in an invalid state.
3359 */
3360 void QQuickTextInputPrivate::internalInsert(const QString &s)
3361 {
3362     Q_Q(QQuickTextInput);
3363     if (m_echoMode == QQuickTextInput::Password) {
3364         int delay = qGuiApp->styleHints()->passwordMaskDelay();
3365         if (delay > 0)
3366             m_passwordEchoTimer.start(delay, q);
3367     }
3368     if (hasSelectedText())
3369         addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
3370     if (m_maskData) {
3371         QString ms = maskString(m_cursor, s);
3372         for (int i = 0; i < (int) ms.length(); ++i) {
3373             addCommand (Command(DeleteSelection, m_cursor + i, m_text.at(m_cursor + i), -1, -1));
3374             addCommand(Command(Insert, m_cursor + i, ms.at(i), -1, -1));
3375         }
3376         m_text.replace(m_cursor, ms.length(), ms);
3377         m_cursor += ms.length();
3378         m_cursor = nextMaskBlank(m_cursor);
3379         m_textDirty = true;
3380     } else {
3381         int remaining = m_maxLength - m_text.length();
3382         if (remaining != 0) {
3383             m_text.insert(m_cursor, s.left(remaining));
3384             for (int i = 0; i < (int) s.left(remaining).length(); ++i)
3385                addCommand(Command(Insert, m_cursor++, s.at(i), -1, -1));
3386             m_textDirty = true;
3387         }
3388     }
3389 }
3390
3391 /*!
3392     \internal
3393
3394     deletes a single character from the current text.  If \a wasBackspace,
3395     the character prior to the cursor is removed.  Otherwise the character
3396     after the cursor is removed.
3397
3398     Also adds the appropriate commands into the undo history.
3399     This function does not call finishChange(), and may leave the text
3400     in an invalid state.
3401 */
3402 void QQuickTextInputPrivate::internalDelete(bool wasBackspace)
3403 {
3404     if (m_cursor < (int) m_text.length()) {
3405         cancelPasswordEchoTimer();
3406         if (hasSelectedText())
3407             addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
3408         addCommand(Command((CommandType)((m_maskData ? 2 : 0) + (wasBackspace ? Remove : Delete)),
3409                    m_cursor, m_text.at(m_cursor), -1, -1));
3410         if (m_maskData) {
3411             m_text.replace(m_cursor, 1, clearString(m_cursor, 1));
3412             addCommand(Command(Insert, m_cursor, m_text.at(m_cursor), -1, -1));
3413         } else {
3414             m_text.remove(m_cursor, 1);
3415         }
3416         m_textDirty = true;
3417     }
3418 }
3419
3420 /*!
3421     \internal
3422
3423     removes the currently selected text from the line control.
3424
3425     Also adds the appropriate commands into the undo history.
3426     This function does not call finishChange(), and may leave the text
3427     in an invalid state.
3428 */
3429 void QQuickTextInputPrivate::removeSelectedText()
3430 {
3431     if (m_selstart < m_selend && m_selend <= (int) m_text.length()) {
3432         cancelPasswordEchoTimer();
3433         separate();
3434         int i ;
3435         addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
3436         if (m_selstart <= m_cursor && m_cursor < m_selend) {
3437             // cursor is within the selection. Split up the commands
3438             // to be able to restore the correct cursor position
3439             for (i = m_cursor; i >= m_selstart; --i)
3440                 addCommand (Command(DeleteSelection, i, m_text.at(i), -1, 1));
3441             for (i = m_selend - 1; i > m_cursor; --i)
3442                 addCommand (Command(DeleteSelection, i - m_cursor + m_selstart - 1, m_text.at(i), -1, -1));
3443         } else {
3444             for (i = m_selend-1; i >= m_selstart; --i)
3445                 addCommand (Command(RemoveSelection, i, m_text.at(i), -1, -1));
3446         }
3447         if (m_maskData) {
3448             m_text.replace(m_selstart, m_selend - m_selstart,  clearString(m_selstart, m_selend - m_selstart));
3449             for (int i = 0; i < m_selend - m_selstart; ++i)
3450                 addCommand(Command(Insert, m_selstart + i, m_text.at(m_selstart + i), -1, -1));
3451         } else {
3452             m_text.remove(m_selstart, m_selend - m_selstart);
3453         }
3454         if (m_cursor > m_selstart)
3455             m_cursor -= qMin(m_cursor, m_selend) - m_selstart;
3456         internalDeselect();
3457         m_textDirty = true;
3458     }
3459 }
3460
3461 /*!
3462     \internal
3463
3464     Parses the input mask specified by \a maskFields to generate
3465     the mask data used to handle input masks.
3466 */
3467 void QQuickTextInputPrivate::parseInputMask(const QString &maskFields)
3468 {
3469     int delimiter = maskFields.indexOf(QLatin1Char(';'));
3470     if (maskFields.isEmpty() || delimiter == 0) {
3471         if (m_maskData) {
3472             delete [] m_maskData;
3473             m_maskData = 0;
3474             m_maxLength = 32767;
3475             internalSetText(QString());
3476         }
3477         return;
3478     }
3479
3480     if (delimiter == -1) {
3481         m_blank = QLatin1Char(' ');
3482         m_inputMask = maskFields;
3483     } else {
3484         m_inputMask = maskFields.left(delimiter);
3485         m_blank = (delimiter + 1 < maskFields.length()) ? maskFields[delimiter + 1] : QLatin1Char(' ');
3486     }
3487
3488     // calculate m_maxLength / m_maskData length
3489     m_maxLength = 0;
3490     QChar c = 0;
3491     for (int i=0; i<m_inputMask.length(); i++) {
3492         c = m_inputMask.at(i);
3493         if (i > 0 && m_inputMask.at(i-1) == QLatin1Char('\\')) {
3494             m_maxLength++;
3495             continue;
3496         }
3497         if (c != QLatin1Char('\\') && c != QLatin1Char('!') &&
3498              c != QLatin1Char('<') && c != QLatin1Char('>') &&
3499              c != QLatin1Char('{') && c != QLatin1Char('}') &&
3500              c != QLatin1Char('[') && c != QLatin1Char(']'))
3501             m_maxLength++;
3502     }
3503
3504     delete [] m_maskData;
3505     m_maskData = new MaskInputData[m_maxLength];
3506
3507     MaskInputData::Casemode m = MaskInputData::NoCaseMode;
3508     c = 0;
3509     bool s;
3510     bool escape = false;
3511     int index = 0;
3512     for (int i = 0; i < m_inputMask.length(); i++) {
3513         c = m_inputMask.at(i);
3514         if (escape) {
3515             s = true;
3516             m_maskData[index].maskChar = c;
3517             m_maskData[index].separator = s;
3518             m_maskData[index].caseMode = m;
3519             index++;
3520             escape = false;
3521         } else if (c == QLatin1Char('<')) {
3522                 m = MaskInputData::Lower;
3523         } else if (c == QLatin1Char('>')) {
3524             m = MaskInputData::Upper;
3525         } else if (c == QLatin1Char('!')) {
3526             m = MaskInputData::NoCaseMode;
3527         } else if (c != QLatin1Char('{') && c != QLatin1Char('}') && c != QLatin1Char('[') && c != QLatin1Char(']')) {
3528             switch (c.unicode()) {
3529             case 'A':
3530             case 'a':
3531             case 'N':
3532             case 'n':
3533             case 'X':
3534             case 'x':
3535             case '9':
3536             case '0':
3537             case 'D':
3538             case 'd':
3539             case '#':
3540             case 'H':
3541             case 'h':
3542             case 'B':
3543             case 'b':
3544                 s = false;
3545                 break;
3546             case '\\':
3547                 escape = true;
3548             default:
3549                 s = true;
3550                 break;
3551             }
3552
3553             if (!escape) {
3554                 m_maskData[index].maskChar = c;
3555                 m_maskData[index].separator = s;
3556                 m_maskData[index].caseMode = m;
3557                 index++;
3558             }
3559         }
3560     }
3561     internalSetText(m_text);
3562 }
3563
3564
3565 /*!
3566     \internal
3567
3568     checks if the key is valid compared to the inputMask
3569 */
3570 bool QQuickTextInputPrivate::isValidInput(QChar key, QChar mask) const
3571 {
3572     switch (mask.unicode()) {
3573     case 'A':
3574         if (key.isLetter())
3575             return true;
3576         break;
3577     case 'a':
3578         if (key.isLetter() || key == m_blank)
3579             return true;
3580         break;
3581     case 'N':
3582         if (key.isLetterOrNumber())
3583             return true;
3584         break;
3585     case 'n':
3586         if (key.isLetterOrNumber() || key == m_blank)
3587             return true;
3588         break;
3589     case 'X':
3590         if (key.isPrint())
3591             return true;
3592         break;
3593     case 'x':
3594         if (key.isPrint() || key == m_blank)
3595             return true;
3596         break;
3597     case '9':
3598         if (key.isNumber())
3599             return true;
3600         break;
3601     case '0':
3602         if (key.isNumber() || key == m_blank)
3603             return true;
3604         break;
3605     case 'D':
3606         if (key.isNumber() && key.digitValue() > 0)
3607             return true;
3608         break;
3609     case 'd':
3610         if ((key.isNumber() && key.digitValue() > 0) || key == m_blank)
3611             return true;
3612         break;
3613     case '#':
3614         if (key.isNumber() || key == QLatin1Char('+') || key == QLatin1Char('-') || key == m_blank)
3615             return true;
3616         break;
3617     case 'B':
3618         if (key == QLatin1Char('0') || key == QLatin1Char('1'))
3619             return true;
3620         break;
3621     case 'b':
3622         if (key == QLatin1Char('0') || key == QLatin1Char('1') || key == m_blank)
3623             return true;
3624         break;
3625     case 'H':
3626         if (key.isNumber() || (key >= QLatin1Char('a') && key <= QLatin1Char('f')) || (key >= QLatin1Char('A') && key <= QLatin1Char('F')))
3627             return true;
3628         break;
3629     case 'h':
3630         if (key.isNumber() || (key >= QLatin1Char('a') && key <= QLatin1Char('f')) || (key >= QLatin1Char('A') && key <= QLatin1Char('F')) || key == m_blank)
3631             return true;
3632         break;
3633     default:
3634         break;
3635     }
3636     return false;
3637 }
3638
3639 /*!
3640     \internal
3641
3642     Returns true if the given text \a str is valid for any
3643     validator or input mask set for the line control.
3644
3645     Otherwise returns false
3646 */
3647 QQuickTextInputPrivate::ValidatorState QQuickTextInputPrivate::hasAcceptableInput(const QString &str) const
3648 {
3649 #ifndef QT_NO_VALIDATOR
3650     QString textCopy = str;
3651     int cursorCopy = m_cursor;
3652     if (m_validator) {
3653         QValidator::State state = m_validator->validate(textCopy, cursorCopy);
3654         if (state != QValidator::Acceptable)
3655             return ValidatorState(state);
3656     }
3657 #endif
3658
3659     if (!m_maskData)
3660         return AcceptableInput;
3661
3662     if (str.length() != m_maxLength)
3663         return InvalidInput;
3664
3665     for (int i=0; i < m_maxLength; ++i) {
3666         if (m_maskData[i].separator) {
3667             if (str.at(i) != m_maskData[i].maskChar)
3668                 return InvalidInput;
3669         } else {
3670             if (!isValidInput(str.at(i), m_maskData[i].maskChar))
3671                 return InvalidInput;
3672         }
3673     }
3674     return AcceptableInput;
3675 }
3676
3677 /*!
3678     \internal
3679
3680     Applies the inputMask on \a str starting from position \a pos in the mask. \a clear
3681     specifies from where characters should be gotten when a separator is met in \a str - true means
3682     that blanks will be used, false that previous input is used.
3683     Calling this when no inputMask is set is undefined.
3684 */
3685 QString QQuickTextInputPrivate::maskString(uint pos, const QString &str, bool clear) const
3686 {
3687     if (pos >= (uint)m_maxLength)
3688         return QString::fromLatin1("");
3689
3690     QString fill;
3691     fill = clear ? clearString(0, m_maxLength) : m_text;
3692
3693     int strIndex = 0;
3694     QString s = QString::fromLatin1("");
3695     int i = pos;
3696     while (i < m_maxLength) {
3697         if (strIndex < str.length()) {
3698             if (m_maskData[i].separator) {
3699                 s += m_maskData[i].maskChar;
3700                 if (str[(int)strIndex] == m_maskData[i].maskChar)
3701                     strIndex++;
3702                 ++i;
3703             } else {
3704                 if (isValidInput(str[(int)strIndex], m_maskData[i].maskChar)) {
3705                     switch (m_maskData[i].caseMode) {
3706                     case MaskInputData::Upper:
3707                         s += str[(int)strIndex].toUpper();
3708                         break;
3709                     case MaskInputData::Lower:
3710                         s += str[(int)strIndex].toLower();
3711                         break;
3712                     default:
3713                         s += str[(int)strIndex];
3714                     }
3715                     ++i;
3716                 } else {
3717                     // search for separator first
3718                     int n = findInMask(i, true, true, str[(int)strIndex]);
3719                     if (n != -1) {
3720                         if (str.length() != 1 || i == 0 || (i > 0 && (!m_maskData[i-1].separator || m_maskData[i-1].maskChar != str[(int)strIndex]))) {
3721                             s += fill.mid(i, n-i+1);
3722                             i = n + 1; // update i to find + 1
3723                         }
3724                     } else {
3725                         // search for valid m_blank if not
3726                         n = findInMask(i, true, false, str[(int)strIndex]);
3727                         if (n != -1) {
3728                             s += fill.mid(i, n-i);
3729                             switch (m_maskData[n].caseMode) {
3730                             case MaskInputData::Upper:
3731                                 s += str[(int)strIndex].toUpper();
3732                                 break;
3733                             case MaskInputData::Lower:
3734                                 s += str[(int)strIndex].toLower();
3735                                 break;
3736                             default:
3737                                 s += str[(int)strIndex];
3738                             }
3739                             i = n + 1; // updates i to find + 1
3740                         }
3741                     }
3742                 }
3743                 ++strIndex;
3744             }
3745         } else
3746             break;
3747     }
3748
3749     return s;
3750 }
3751
3752
3753
3754 /*!
3755     \internal
3756
3757     Returns a "cleared" string with only separators and blank chars.
3758     Calling this when no inputMask is set is undefined.
3759 */
3760 QString QQuickTextInputPrivate::clearString(uint pos, uint len) const
3761 {
3762     if (pos >= (uint)m_maxLength)
3763         return QString();
3764
3765     QString s;
3766     int end = qMin((uint)m_maxLength, pos + len);
3767     for (int i = pos; i < end; ++i)
3768         if (m_maskData[i].separator)
3769             s += m_maskData[i].maskChar;
3770         else
3771             s += m_blank;
3772
3773     return s;
3774 }
3775
3776 /*!
3777     \internal
3778
3779     Strips blank parts of the input in a QQuickTextInputPrivate when an inputMask is set,
3780     separators are still included. Typically "127.0__.0__.1__" becomes "127.0.0.1".
3781 */
3782 QString QQuickTextInputPrivate::stripString(const QString &str) const
3783 {
3784     if (!m_maskData)
3785         return str;
3786
3787     QString s;
3788     int end = qMin(m_maxLength, (int)str.length());
3789     for (int i = 0; i < end; ++i) {
3790         if (m_maskData[i].separator)
3791             s += m_maskData[i].maskChar;
3792         else if (str[i] != m_blank)
3793             s += str[i];
3794     }
3795
3796     return s;
3797 }
3798
3799 /*!
3800     \internal
3801     searches forward/backward in m_maskData for either a separator or a m_blank
3802 */
3803 int QQuickTextInputPrivate::findInMask(int pos, bool forward, bool findSeparator, QChar searchChar) const
3804 {
3805     if (pos >= m_maxLength || pos < 0)
3806         return -1;
3807
3808     int end = forward ? m_maxLength : -1;
3809     int step = forward ? 1 : -1;
3810     int i = pos;
3811
3812     while (i != end) {
3813         if (findSeparator) {
3814             if (m_maskData[i].separator && m_maskData[i].maskChar == searchChar)
3815                 return i;
3816         } else {
3817             if (!m_maskData[i].separator) {
3818                 if (searchChar.isNull())
3819                     return i;
3820                 else if (isValidInput(searchChar, m_maskData[i].maskChar))
3821                     return i;
3822             }
3823         }
3824         i += step;
3825     }
3826     return -1;
3827 }
3828
3829 void QQuickTextInputPrivate::internalUndo(int until)
3830 {
3831     if (!isUndoAvailable())
3832         return;
3833     cancelPasswordEchoTimer();
3834     internalDeselect();
3835     while (m_undoState && m_undoState > until) {
3836         Command& cmd = m_history[--m_undoState];
3837         switch (cmd.type) {
3838         case Insert:
3839             m_text.remove(cmd.pos, 1);
3840             m_cursor = cmd.pos;
3841             break;
3842         case SetSelection:
3843             m_selstart = cmd.selStart;
3844             m_selend = cmd.selEnd;
3845             m_cursor = cmd.pos;
3846             break;
3847         case Remove:
3848         case RemoveSelection:
3849             m_text.insert(cmd.pos, cmd.uc);
3850             m_cursor = cmd.pos + 1;
3851             break;
3852         case Delete:
3853         case DeleteSelection:
3854             m_text.insert(cmd.pos, cmd.uc);
3855             m_cursor = cmd.pos;
3856             break;
3857         case Separator:
3858             continue;
3859         }
3860         if (until < 0 && m_undoState) {
3861             Command& next = m_history[m_undoState-1];
3862             if (next.type != cmd.type && next.type < RemoveSelection
3863                  && (cmd.type < RemoveSelection || next.type == Separator))
3864                 break;
3865         }
3866     }
3867     m_textDirty = true;
3868 }
3869
3870 void QQuickTextInputPrivate::internalRedo()
3871 {
3872     if (!isRedoAvailable())
3873         return;
3874     internalDeselect();
3875     while (m_undoState < (int)m_history.size()) {
3876         Command& cmd = m_history[m_undoState++];
3877         switch (cmd.type) {
3878         case Insert:
3879             m_text.insert(cmd.pos, cmd.uc);
3880             m_cursor = cmd.pos + 1;
3881             break;
3882         case SetSelection:
3883             m_selstart = cmd.selStart;
3884             m_selend = cmd.selEnd;
3885             m_cursor = cmd.pos;
3886             break;
3887         case Remove:
3888         case Delete:
3889         case RemoveSelection:
3890         case DeleteSelection:
3891             m_text.remove(cmd.pos, 1);
3892             m_selstart = cmd.selStart;
3893             m_selend = cmd.selEnd;
3894             m_cursor = cmd.pos;
3895             break;
3896         case Separator:
3897             m_selstart = cmd.selStart;
3898             m_selend = cmd.selEnd;
3899             m_cursor = cmd.pos;
3900             break;
3901         }
3902         if (m_undoState < (int)m_history.size()) {
3903             Command& next = m_history[m_undoState];
3904             if (next.type != cmd.type && cmd.type < RemoveSelection && next.type != Separator
3905                  && (next.type < RemoveSelection || cmd.type == Separator))
3906                 break;
3907         }
3908     }
3909     m_textDirty = true;
3910 }
3911
3912 void QQuickTextInputPrivate::emitUndoRedoChanged()
3913 {
3914     Q_Q(QQuickTextInput);
3915     const bool previousUndo = canUndo;
3916     const bool previousRedo = canRedo;
3917
3918     canUndo = isUndoAvailable();
3919     canRedo = isRedoAvailable();
3920
3921     if (previousUndo != canUndo)
3922         emit q->canUndoChanged();
3923     if (previousRedo != canRedo)
3924         emit q->canRedoChanged();
3925 }
3926
3927 /*!
3928     \internal
3929
3930     If the current cursor position differs from the last emitted cursor
3931     position, emits cursorPositionChanged().
3932 */
3933 bool QQuickTextInputPrivate::emitCursorPositionChanged()
3934 {
3935     Q_Q(QQuickTextInput);
3936     if (m_cursor != m_lastCursorPos) {
3937         m_lastCursorPos = m_cursor;
3938
3939         q->updateCursorRectangle();
3940         emit q->cursorPositionChanged();
3941
3942         if (!hasSelectedText()) {
3943             if (lastSelectionStart != m_cursor) {
3944                 lastSelectionStart = m_cursor;
3945                 emit q->selectionStartChanged();
3946             }
3947             if (lastSelectionEnd != m_cursor) {
3948                 lastSelectionEnd = m_cursor;
3949                 emit q->selectionEndChanged();
3950             }
3951         }
3952
3953 #ifndef QT_NO_ACCESSIBILITY
3954         QAccessibleTextCursorEvent ev(q, m_cursor);
3955         QAccessible::updateAccessibility(&ev);
3956 #endif
3957
3958         return true;
3959     }
3960     return false;
3961 }
3962
3963
3964 void QQuickTextInputPrivate::setCursorBlinkPeriod(int msec)
3965 {
3966     Q_Q(QQuickTextInput);
3967     if (msec == m_blinkPeriod)
3968         return;
3969     if (m_blinkTimer) {
3970         q->killTimer(m_blinkTimer);
3971     }
3972     if (msec) {
3973         m_blinkTimer = q->startTimer(msec / 2);
3974         m_blinkStatus = 1;
3975     } else {
3976         m_blinkTimer = 0;
3977         if (m_blinkStatus == 1) {
3978             updateType = UpdatePaintNode;
3979             q->update();
3980         }
3981     }
3982     m_blinkPeriod = msec;
3983 }
3984
3985 void QQuickTextInput::timerEvent(QTimerEvent *event)
3986 {
3987     Q_D(QQuickTextInput);
3988     if (event->timerId() == d->m_blinkTimer) {
3989         d->m_blinkStatus = !d->m_blinkStatus;
3990         d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
3991         update();
3992     } else if (event->timerId() == d->m_passwordEchoTimer.timerId()) {
3993         d->m_passwordEchoTimer.stop();
3994         d->updateDisplayText();
3995     }
3996 }
3997
3998 void QQuickTextInputPrivate::processKeyEvent(QKeyEvent* event)
3999 {
4000     Q_Q(QQuickTextInput);
4001     bool inlineCompletionAccepted = false;
4002
4003     if (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return) {
4004         if (hasAcceptableInput(m_text) || fixup()) {
4005             emit q->accepted();
4006         }
4007         if (inlineCompletionAccepted)
4008             event->accept();
4009         else
4010             event->ignore();
4011         return;
4012     }
4013
4014     if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit
4015         && !m_passwordEchoEditing
4016         && !m_readOnly
4017         && !event->text().isEmpty()
4018         && !(event->modifiers() & Qt::ControlModifier)) {
4019         // Clear the edit and reset to normal echo mode while editing; the
4020         // echo mode switches back when the edit loses focus
4021         // ### resets current content.  dubious code; you can
4022         // navigate with keys up, down, back, and select(?), but if you press
4023         // "left" or "right" it clears?
4024         updatePasswordEchoEditing(true);
4025         clear();
4026     }
4027
4028     bool unknown = false;
4029     bool visual = cursorMoveStyle() == Qt::VisualMoveStyle;
4030
4031     if (false) {
4032     }
4033 #ifndef QT_NO_SHORTCUT
4034     else if (event == QKeySequence::Undo) {
4035         q->undo();
4036     }
4037     else if (event == QKeySequence::Redo) {
4038         q->redo();
4039     }
4040     else if (event == QKeySequence::SelectAll) {
4041         selectAll();
4042     }
4043 #ifndef QT_NO_CLIPBOARD
4044     else if (event == QKeySequence::Copy) {
4045         copy();
4046     }
4047     else if (event == QKeySequence::Paste) {
4048         if (!m_readOnly) {
4049             QClipboard::Mode mode = QClipboard::Clipboard;
4050             paste(mode);
4051         }
4052     }
4053     else if (event == QKeySequence::Cut) {
4054         if (!m_readOnly) {
4055             copy();
4056             del();
4057         }
4058     }
4059     else if (event == QKeySequence::DeleteEndOfLine) {
4060         if (!m_readOnly) {
4061             setSelection(m_cursor, end());
4062             copy();
4063             del();
4064         }
4065     }
4066 #endif //QT_NO_CLIPBOARD
4067     else if (event == QKeySequence::MoveToStartOfLine || event == QKeySequence::MoveToStartOfBlock) {
4068         home(0);
4069     }
4070     else if (event == QKeySequence::MoveToEndOfLine || event == QKeySequence::MoveToEndOfBlock) {
4071         end(0);
4072     }
4073     else if (event == QKeySequence::SelectStartOfLine || event == QKeySequence::SelectStartOfBlock) {
4074         home(1);
4075     }
4076     else if (event == QKeySequence::SelectEndOfLine || event == QKeySequence::SelectEndOfBlock) {
4077         end(1);
4078     }
4079     else if (event == QKeySequence::MoveToNextChar) {
4080         if (hasSelectedText()) {
4081             moveCursor(selectionEnd(), false);
4082         } else {
4083             cursorForward(0, visual ? 1 : (layoutDirection() == Qt::LeftToRight ? 1 : -1));
4084         }
4085     }
4086     else if (event == QKeySequence::SelectNextChar) {
4087         cursorForward(1, visual ? 1 : (layoutDirection() == Qt::LeftToRight ? 1 : -1));
4088     }
4089     else if (event == QKeySequence::MoveToPreviousChar) {
4090         if (hasSelectedText()) {
4091             moveCursor(selectionStart(), false);
4092         } else {
4093             cursorForward(0, visual ? -1 : (layoutDirection() == Qt::LeftToRight ? -1 : 1));
4094         }
4095     }
4096     else if (event == QKeySequence::SelectPreviousChar) {
4097         cursorForward(1, visual ? -1 : (layoutDirection() == Qt::LeftToRight ? -1 : 1));
4098     }
4099     else if (event == QKeySequence::MoveToNextWord) {
4100         if (m_echoMode == QQuickTextInput::Normal)
4101             layoutDirection() == Qt::LeftToRight ? cursorWordForward(0) : cursorWordBackward(0);
4102         else
4103             layoutDirection() == Qt::LeftToRight ? end(0) : home(0);
4104     }
4105     else if (event == QKeySequence::MoveToPreviousWord) {
4106         if (m_echoMode == QQuickTextInput::Normal)
4107             layoutDirection() == Qt::LeftToRight ? cursorWordBackward(0) : cursorWordForward(0);
4108         else if (!m_readOnly) {
4109             layoutDirection() == Qt::LeftToRight ? home(0) : end(0);
4110         }
4111     }
4112     else if (event == QKeySequence::SelectNextWord) {
4113         if (m_echoMode == QQuickTextInput::Normal)
4114             layoutDirection() == Qt::LeftToRight ? cursorWordForward(1) : cursorWordBackward(1);
4115         else
4116             layoutDirection() == Qt::LeftToRight ? end(1) : home(1);
4117     }
4118     else if (event == QKeySequence::SelectPreviousWord) {
4119         if (m_echoMode == QQuickTextInput::Normal)
4120             layoutDirection() == Qt::LeftToRight ? cursorWordBackward(1) : cursorWordForward(1);
4121         else
4122             layoutDirection() == Qt::LeftToRight ? home(1) : end(1);
4123     }
4124     else if (event == QKeySequence::Delete) {
4125         if (!m_readOnly)
4126             del();
4127     }
4128     else if (event == QKeySequence::DeleteEndOfWord) {
4129         if (!m_readOnly) {
4130             cursorWordForward(true);
4131             del();
4132         }
4133     }
4134     else if (event == QKeySequence::DeleteStartOfWord) {
4135         if (!m_readOnly) {
4136             cursorWordBackward(true);
4137             del();
4138         }
4139     }
4140 #endif // QT_NO_SHORTCUT
4141     else {
4142         bool handled = false;
4143         if (event->modifiers() & Qt::ControlModifier) {
4144             switch (event->key()) {
4145             case Qt::Key_Backspace:
4146                 if (!m_readOnly) {
4147                     cursorWordBackward(true);
4148                     del();
4149                 }
4150                 break;
4151             default:
4152                 if (!handled)
4153                     unknown = true;
4154             }
4155         } else { // ### check for *no* modifier
4156             switch (event->key()) {
4157             case Qt::Key_Backspace:
4158                 if (!m_readOnly) {
4159                     backspace();
4160                 }
4161                 break;
4162             default:
4163                 if (!handled)
4164                     unknown = true;
4165             }
4166         }
4167     }
4168
4169     if (event->key() == Qt::Key_Direction_L || event->key() == Qt::Key_Direction_R) {
4170         setLayoutDirection((event->key() == Qt::Key_Direction_L) ? Qt::LeftToRight : Qt::RightToLeft);
4171         unknown = false;
4172     }
4173
4174     if (unknown && !m_readOnly) {
4175         QString t = event->text();
4176         if (!t.isEmpty() && t.at(0).isPrint()) {
4177             insert(t);
4178             event->accept();
4179             return;
4180         }
4181     }
4182
4183     if (unknown)
4184         event->ignore();
4185     else
4186         event->accept();
4187 }
4188
4189
4190 QT_END_NAMESPACE
4191