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