Fix QQuickTextInput::moveCursorSelection()
[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::NotAtBoundary
2382                                            || (reasons & QTextBoundaryFinder::EndOfItem))) {
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::NotAtBoundary
2400                                || (reasons & QTextBoundaryFinder::StartOfItem))) {
2401                 finder.toNextBoundary();
2402             }
2403             anchor = finder.position() != -1 ? finder.position() : text.length();
2404
2405             finder.setPosition(pos);
2406             if (pos < text.length() && !finder.boundaryReasons())
2407                  finder.toPreviousBoundary();
2408             const int cursor = finder.position() != -1 ? finder.position() : 0;
2409
2410             d->setSelection(anchor, cursor - anchor);
2411         }
2412     }
2413 }
2414
2415 void QQuickTextInput::focusInEvent(QFocusEvent *event)
2416 {
2417     Q_D(const QQuickTextInput);
2418     if (d->focusOnPress && !d->m_readOnly)
2419         qGuiApp->inputMethod()->show();
2420     QQuickImplicitSizeItem::focusInEvent(event);
2421 }
2422
2423 void QQuickTextInput::itemChange(ItemChange change, const ItemChangeData &value)
2424 {
2425     Q_D(QQuickTextInput);
2426     if (change == ItemActiveFocusHasChanged) {
2427         bool hasFocus = value.boolValue;
2428         setCursorVisible(hasFocus);
2429         if (!hasFocus && (d->m_passwordEchoEditing || d->m_passwordEchoTimer.isActive())) {
2430             d->updatePasswordEchoEditing(false);//QQuickTextInputPrivate sets it on key events, but doesn't deal with focus events
2431         }
2432
2433         if (!hasFocus) {
2434             if (!d->persistentSelection)
2435                 d->deselect();
2436             disconnect(qApp->inputMethod(), SIGNAL(inputDirectionChanged(Qt::LayoutDirection)),
2437                        this, SLOT(q_updateAlignment()));
2438         } else {
2439             q_updateAlignment();
2440             connect(qApp->inputMethod(), SIGNAL(inputDirectionChanged(Qt::LayoutDirection)),
2441                     this, SLOT(q_updateAlignment()));
2442         }
2443     }
2444     QQuickItem::itemChange(change, value);
2445 }
2446
2447 /*!
2448     \qmlproperty bool QtQuick2::TextInput::inputMethodComposing
2449
2450
2451     This property holds whether the TextInput has partial text input from an
2452     input method.
2453
2454     While it is composing an input method may rely on mouse or key events from
2455     the TextInput to edit or commit the partial text.  This property can be
2456     used to determine when to disable events handlers that may interfere with
2457     the correct operation of an input method.
2458 */
2459 bool QQuickTextInput::isInputMethodComposing() const
2460 {
2461     Q_D(const QQuickTextInput);
2462     return d->hasImState;
2463 }
2464
2465 void QQuickTextInputPrivate::init()
2466 {
2467     Q_Q(QQuickTextInput);
2468 #ifndef QT_NO_CLIPBOARD
2469     if (QGuiApplication::clipboard()->supportsSelection())
2470         q->setAcceptedMouseButtons(Qt::LeftButton | Qt::MiddleButton);
2471     else
2472 #endif
2473         q->setAcceptedMouseButtons(Qt::LeftButton);
2474
2475     q->setFlag(QQuickItem::ItemAcceptsInputMethod);
2476     q->setFlag(QQuickItem::ItemHasContents);
2477 #ifndef QT_NO_CLIPBOARD
2478     q->connect(QGuiApplication::clipboard(), SIGNAL(dataChanged()),
2479             q, SLOT(q_canPasteChanged()));
2480 #endif // QT_NO_CLIPBOARD
2481
2482     lastSelectionStart = 0;
2483     lastSelectionEnd = 0;
2484     determineHorizontalAlignment();
2485
2486     if (!qmlDisableDistanceField()) {
2487         QTextOption option = m_textLayout.textOption();
2488         option.setUseDesignMetrics(renderType != QQuickTextInput::NativeRendering);
2489         m_textLayout.setTextOption(option);
2490     }
2491 }
2492
2493 void QQuickTextInput::updateCursorRectangle()
2494 {
2495     Q_D(QQuickTextInput);
2496     if (!isComponentComplete())
2497         return;
2498
2499     d->updateHorizontalScroll();
2500     d->updateVerticalScroll();
2501     d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
2502     update();
2503     emit cursorRectangleChanged();
2504     if (d->cursorItem) {
2505         QRectF r = cursorRectangle();
2506         d->cursorItem->setPos(r.topLeft());
2507         d->cursorItem->setHeight(r.height());
2508     }
2509     updateInputMethod(Qt::ImCursorRectangle);
2510 }
2511
2512 void QQuickTextInput::selectionChanged()
2513 {
2514     Q_D(QQuickTextInput);
2515     d->textLayoutDirty = true; //TODO: Only update rect in selection
2516     d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
2517     update();
2518     emit selectedTextChanged();
2519
2520     if (d->lastSelectionStart != d->selectionStart()) {
2521         d->lastSelectionStart = d->selectionStart();
2522         if (d->lastSelectionStart == -1)
2523             d->lastSelectionStart = d->m_cursor;
2524         emit selectionStartChanged();
2525     }
2526     if (d->lastSelectionEnd != d->selectionEnd()) {
2527         d->lastSelectionEnd = d->selectionEnd();
2528         if (d->lastSelectionEnd == -1)
2529             d->lastSelectionEnd = d->m_cursor;
2530         emit selectionEndChanged();
2531     }
2532 }
2533
2534 void QQuickTextInputPrivate::showCursor()
2535 {
2536     if (textNode != 0 && textNode->cursorNode() != 0)
2537         textNode->cursorNode()->setColor(color);
2538 }
2539
2540 void QQuickTextInputPrivate::hideCursor()
2541 {
2542     if (textNode != 0 && textNode->cursorNode() != 0)
2543         textNode->cursorNode()->setColor(QColor(0, 0, 0, 0));
2544 }
2545
2546 QRectF QQuickTextInput::boundingRect() const
2547 {
2548     Q_D(const QQuickTextInput);
2549
2550     int cursorWidth = d->cursorItem ? 0 : 1;
2551
2552     qreal hscroll = d->hscroll;
2553     if (!d->autoScroll || d->contentSize.width() < width())
2554         hscroll -= QQuickTextUtil::alignedX(d->contentSize.width(), width(), effectiveHAlign());
2555
2556     // Could include font max left/right bearings to either side of rectangle.
2557     QRectF r(-hscroll, -d->vscroll, d->contentSize.width(), d->contentSize.height());
2558     r.setRight(r.right() + cursorWidth);
2559     return r;
2560 }
2561
2562 QRectF QQuickTextInput::clipRect() const
2563 {
2564     Q_D(const QQuickTextInput);
2565
2566     int cursorWidth = d->cursorItem ? d->cursorItem->width() : 1;
2567
2568     // Could include font max left/right bearings to either side of rectangle.
2569     QRectF r = QQuickImplicitSizeItem::clipRect();
2570     r.setRight(r.right() + cursorWidth);
2571     return r;
2572 }
2573
2574 void QQuickTextInput::q_canPasteChanged()
2575 {
2576     Q_D(QQuickTextInput);
2577     bool old = d->canPaste;
2578 #ifndef QT_NO_CLIPBOARD
2579     if (const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData())
2580         d->canPaste = !d->m_readOnly && mimeData->hasText();
2581     else
2582         d->canPaste = false;
2583 #endif
2584
2585     bool changed = d->canPaste != old || !d->canPasteValid;
2586     d->canPasteValid = true;
2587     if (changed)
2588         emit canPasteChanged();
2589
2590 }
2591
2592 void QQuickTextInput::q_updateAlignment()
2593 {
2594     Q_D(QQuickTextInput);
2595     if (d->determineHorizontalAlignment()) {
2596         d->updateLayout();
2597         updateCursorRectangle();
2598     }
2599 }
2600
2601 // ### these should come from QStyleHints
2602 const int textCursorWidth = 1;
2603 const bool fullWidthSelection = true;
2604
2605 /*!
2606     \internal
2607
2608     Updates the display text based of the current edit text
2609     If the text has changed will emit displayTextChanged()
2610 */
2611 void QQuickTextInputPrivate::updateDisplayText(bool forceUpdate)
2612 {
2613     QString orig = m_textLayout.text();
2614     QString str;
2615     if (m_echoMode == QQuickTextInput::NoEcho)
2616         str = QString::fromLatin1("");
2617     else
2618         str = m_text;
2619
2620     if (m_echoMode == QQuickTextInput::Password) {
2621          str.fill(m_passwordCharacter);
2622         if (m_passwordEchoTimer.isActive() && m_cursor > 0 && m_cursor <= m_text.length()) {
2623             int cursor = m_cursor - 1;
2624             QChar uc = m_text.at(cursor);
2625             str[cursor] = uc;
2626             if (cursor > 0 && uc.unicode() >= 0xdc00 && uc.unicode() < 0xe000) {
2627                 // second half of a surrogate, check if we have the first half as well,
2628                 // if yes restore both at once
2629                 uc = m_text.at(cursor - 1);
2630                 if (uc.unicode() >= 0xd800 && uc.unicode() < 0xdc00)
2631                     str[cursor - 1] = uc;
2632             }
2633         }
2634     } else if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit && !m_passwordEchoEditing) {
2635         str.fill(m_passwordCharacter);
2636     }
2637
2638     // replace certain non-printable characters with spaces (to avoid
2639     // drawing boxes when using fonts that don't have glyphs for such
2640     // characters)
2641     QChar* uc = str.data();
2642     for (int i = 0; i < (int)str.length(); ++i) {
2643         if ((uc[i] < 0x20 && uc[i] != 0x09)
2644             || uc[i] == QChar::LineSeparator
2645             || uc[i] == QChar::ParagraphSeparator
2646             || uc[i] == QChar::ObjectReplacementCharacter)
2647             uc[i] = QChar(0x0020);
2648     }
2649
2650     if (str != orig || forceUpdate) {
2651         m_textLayout.setText(str);
2652         updateLayout(); // polish?
2653         emit q_func()->displayTextChanged();
2654     }
2655 }
2656
2657 qreal QQuickTextInputPrivate::getImplicitWidth() const
2658 {
2659     Q_Q(const QQuickTextInput);
2660     if (!requireImplicitWidth) {
2661         QQuickTextInputPrivate *d = const_cast<QQuickTextInputPrivate *>(this);
2662         d->requireImplicitWidth = true;
2663
2664         if (q->isComponentComplete()) {
2665             // One time cost, only incurred if implicitWidth is first requested after
2666             // componentComplete.
2667             QTextLayout layout(m_text);
2668
2669             QTextOption option = m_textLayout.textOption();
2670             option.setTextDirection(m_layoutDirection);
2671             option.setFlags(QTextOption::IncludeTrailingSpaces);
2672             option.setWrapMode(QTextOption::WrapMode(wrapMode));
2673             option.setAlignment(Qt::Alignment(q->effectiveHAlign()));
2674             layout.setTextOption(option);
2675             layout.setFont(font);
2676             layout.setPreeditArea(m_textLayout.preeditAreaPosition(), m_textLayout.preeditAreaText());
2677             layout.beginLayout();
2678
2679             QTextLine line = layout.createLine();
2680             line.setLineWidth(INT_MAX);
2681             d->implicitWidth = qCeil(line.naturalTextWidth());
2682
2683             layout.endLayout();
2684         }
2685     }
2686     return implicitWidth;
2687 }
2688
2689 void QQuickTextInputPrivate::updateLayout()
2690 {
2691     Q_Q(QQuickTextInput);
2692
2693     if (!q->isComponentComplete())
2694         return;
2695
2696
2697     QTextOption option = m_textLayout.textOption();
2698     option.setTextDirection(layoutDirection());
2699     option.setWrapMode(QTextOption::WrapMode(wrapMode));
2700     option.setAlignment(Qt::Alignment(q->effectiveHAlign()));
2701     m_textLayout.setTextOption(option);
2702     m_textLayout.setFont(font);
2703
2704     m_textLayout.beginLayout();
2705
2706     QTextLine line = m_textLayout.createLine();
2707     if (requireImplicitWidth) {
2708         line.setLineWidth(INT_MAX);
2709         const bool wasInLayout = inLayout;
2710         inLayout = true;
2711         q->setImplicitWidth(qCeil(line.naturalTextWidth()));
2712         inLayout = wasInLayout;
2713         if (inLayout)       // probably the result of a binding loop, but by letting it
2714             return;         // get this far we'll get a warning to that effect.
2715     }
2716     qreal lineWidth = q->widthValid() ? q->width() : INT_MAX;
2717     qreal height = 0;
2718     qreal width = 0;
2719     do {
2720         line.setLineWidth(lineWidth);
2721         line.setPosition(QPointF(0, height));
2722
2723         height += line.height();
2724         width = qMax(width, line.naturalTextWidth());
2725
2726         line = m_textLayout.createLine();
2727     } while (line.isValid());
2728     m_textLayout.endLayout();
2729
2730     option.setWrapMode(QTextOption::NoWrap);
2731     m_textLayout.setTextOption(option);
2732
2733     textLayoutDirty = true;
2734
2735     const QSizeF previousSize = contentSize;
2736     contentSize = QSizeF(width, height);
2737
2738     updateType = UpdatePaintNode;
2739     q->update();
2740
2741     if (!requireImplicitWidth && !q->widthValid())
2742         q->setImplicitSize(width, height);
2743     else
2744         q->setImplicitHeight(height);
2745
2746     if (previousSize != contentSize)
2747         emit q->contentSizeChanged();
2748 }
2749
2750 #ifndef QT_NO_CLIPBOARD
2751 /*!
2752     \internal
2753
2754     Copies the currently selected text into the clipboard using the given
2755     \a mode.
2756
2757     \note If the echo mode is set to a mode other than Normal then copy
2758     will not work.  This is to prevent using copy as a method of bypassing
2759     password features of the line control.
2760 */
2761 void QQuickTextInputPrivate::copy(QClipboard::Mode mode) const
2762 {
2763     QString t = selectedText();
2764     if (!t.isEmpty() && m_echoMode == QQuickTextInput::Normal) {
2765         QGuiApplication::clipboard()->setText(t, mode);
2766     }
2767 }
2768
2769 /*!
2770     \internal
2771
2772     Inserts the text stored in the application clipboard into the line
2773     control.
2774
2775     \sa insert()
2776 */
2777 void QQuickTextInputPrivate::paste(QClipboard::Mode clipboardMode)
2778 {
2779     QString clip = QGuiApplication::clipboard()->text(clipboardMode);
2780     if (!clip.isEmpty() || hasSelectedText()) {
2781         separate(); //make it a separate undo/redo command
2782         insert(clip);
2783         separate();
2784     }
2785 }
2786
2787 #endif // !QT_NO_CLIPBOARD
2788
2789 /*!
2790     \internal
2791 */
2792 void QQuickTextInputPrivate::commitPreedit()
2793 {
2794     Q_Q(QQuickTextInput);
2795
2796     if (!hasImState)
2797         return;
2798
2799     qApp->inputMethod()->commit();
2800
2801     if (!hasImState)
2802         return;
2803
2804     QInputMethodEvent ev;
2805     QCoreApplication::sendEvent(q, &ev);
2806 }
2807
2808 void QQuickTextInputPrivate::cancelPreedit()
2809 {
2810     Q_Q(QQuickTextInput);
2811
2812     if (!hasImState)
2813         return;
2814
2815     qApp->inputMethod()->reset();
2816
2817     QInputMethodEvent ev;
2818     QCoreApplication::sendEvent(q, &ev);
2819 }
2820
2821 /*!
2822     \internal
2823
2824     Handles the behavior for the backspace key or function.
2825     Removes the current selection if there is a selection, otherwise
2826     removes the character prior to the cursor position.
2827
2828     \sa del()
2829 */
2830 void QQuickTextInputPrivate::backspace()
2831 {
2832     int priorState = m_undoState;
2833     if (separateSelection()) {
2834         removeSelectedText();
2835     } else if (m_cursor) {
2836             --m_cursor;
2837             if (m_maskData)
2838                 m_cursor = prevMaskBlank(m_cursor);
2839             QChar uc = m_text.at(m_cursor);
2840             if (m_cursor > 0 && uc.unicode() >= 0xdc00 && uc.unicode() < 0xe000) {
2841                 // second half of a surrogate, check if we have the first half as well,
2842                 // if yes delete both at once
2843                 uc = m_text.at(m_cursor - 1);
2844                 if (uc.unicode() >= 0xd800 && uc.unicode() < 0xdc00) {
2845                     internalDelete(true);
2846                     --m_cursor;
2847                 }
2848             }
2849             internalDelete(true);
2850     }
2851     finishChange(priorState);
2852 }
2853
2854 /*!
2855     \internal
2856
2857     Handles the behavior for the delete key or function.
2858     Removes the current selection if there is a selection, otherwise
2859     removes the character after the cursor position.
2860
2861     \sa del()
2862 */
2863 void QQuickTextInputPrivate::del()
2864 {
2865     int priorState = m_undoState;
2866     if (separateSelection()) {
2867         removeSelectedText();
2868     } else {
2869         int n = m_textLayout.nextCursorPosition(m_cursor) - m_cursor;
2870         while (n--)
2871             internalDelete();
2872     }
2873     finishChange(priorState);
2874 }
2875
2876 /*!
2877     \internal
2878
2879     Inserts the given \a newText at the current cursor position.
2880     If there is any selected text it is removed prior to insertion of
2881     the new text.
2882 */
2883 void QQuickTextInputPrivate::insert(const QString &newText)
2884 {
2885     int priorState = m_undoState;
2886     if (separateSelection())
2887         removeSelectedText();
2888     internalInsert(newText);
2889     finishChange(priorState);
2890 }
2891
2892 /*!
2893     \internal
2894
2895     Clears the line control text.
2896 */
2897 void QQuickTextInputPrivate::clear()
2898 {
2899     int priorState = m_undoState;
2900     separateSelection();
2901     m_selstart = 0;
2902     m_selend = m_text.length();
2903     removeSelectedText();
2904     separate();
2905     finishChange(priorState, /*update*/false, /*edited*/false);
2906 }
2907
2908 /*!
2909     \internal
2910
2911     Sets \a length characters from the given \a start position as selected.
2912     The given \a start position must be within the current text for
2913     the line control.  If \a length characters cannot be selected, then
2914     the selection will extend to the end of the current text.
2915 */
2916 void QQuickTextInputPrivate::setSelection(int start, int length)
2917 {
2918     Q_Q(QQuickTextInput);
2919     commitPreedit();
2920
2921     if (start < 0 || start > (int)m_text.length()){
2922         qWarning("QQuickTextInputPrivate::setSelection: Invalid start position");
2923         return;
2924     }
2925
2926     if (length > 0) {
2927         if (start == m_selstart && start + length == m_selend && m_cursor == m_selend)
2928             return;
2929         m_selstart = start;
2930         m_selend = qMin(start + length, (int)m_text.length());
2931         m_cursor = m_selend;
2932     } else if (length < 0){
2933         if (start == m_selend && start + length == m_selstart && m_cursor == m_selstart)
2934             return;
2935         m_selstart = qMax(start + length, 0);
2936         m_selend = start;
2937         m_cursor = m_selstart;
2938     } else if (m_selstart != m_selend) {
2939         m_selstart = 0;
2940         m_selend = 0;
2941         m_cursor = start;
2942     } else {
2943         m_cursor = start;
2944         emitCursorPositionChanged();
2945         return;
2946     }
2947     emit q->selectionChanged();
2948     emitCursorPositionChanged();
2949     q->updateInputMethod(Qt::ImCursorRectangle | Qt::ImAnchorPosition
2950                         | Qt::ImCursorPosition | Qt::ImCurrentSelection);
2951 }
2952
2953 /*!
2954     \internal
2955
2956     Sets the password echo editing to \a editing.  If password echo editing
2957     is true, then the text of the password is displayed even if the echo
2958     mode is set to QLineEdit::PasswordEchoOnEdit.  Password echoing editing
2959     does not affect other echo modes.
2960 */
2961 void QQuickTextInputPrivate::updatePasswordEchoEditing(bool editing)
2962 {
2963     cancelPasswordEchoTimer();
2964     m_passwordEchoEditing = editing;
2965     updateDisplayText();
2966 }
2967
2968 /*!
2969     \internal
2970
2971     Fixes the current text so that it is valid given any set validators.
2972
2973     Returns true if the text was changed.  Otherwise returns false.
2974 */
2975 bool QQuickTextInputPrivate::fixup() // this function assumes that validate currently returns != Acceptable
2976 {
2977 #ifndef QT_NO_VALIDATOR
2978     if (m_validator) {
2979         QString textCopy = m_text;
2980         int cursorCopy = m_cursor;
2981         m_validator->fixup(textCopy);
2982         if (m_validator->validate(textCopy, cursorCopy) == QValidator::Acceptable) {
2983             if (textCopy != m_text || cursorCopy != m_cursor)
2984                 internalSetText(textCopy, cursorCopy);
2985             return true;
2986         }
2987     }
2988 #endif
2989     return false;
2990 }
2991
2992 /*!
2993     \internal
2994
2995     Moves the cursor to the given position \a pos.   If \a mark is true will
2996     adjust the currently selected text.
2997 */
2998 void QQuickTextInputPrivate::moveCursor(int pos, bool mark)
2999 {
3000     Q_Q(QQuickTextInput);
3001     commitPreedit();
3002
3003     if (pos != m_cursor) {
3004         separate();
3005         if (m_maskData)
3006             pos = pos > m_cursor ? nextMaskBlank(pos) : prevMaskBlank(pos);
3007     }
3008     if (mark) {
3009         int anchor;
3010         if (m_selend > m_selstart && m_cursor == m_selstart)
3011             anchor = m_selend;
3012         else if (m_selend > m_selstart && m_cursor == m_selend)
3013             anchor = m_selstart;
3014         else
3015             anchor = m_cursor;
3016         m_selstart = qMin(anchor, pos);
3017         m_selend = qMax(anchor, pos);
3018     } else {
3019         internalDeselect();
3020     }
3021     m_cursor = pos;
3022     if (mark || m_selDirty) {
3023         m_selDirty = false;
3024         emit q->selectionChanged();
3025     }
3026     emitCursorPositionChanged();
3027     q->updateInputMethod();
3028 }
3029
3030 /*!
3031     \internal
3032
3033     Applies the given input method event \a event to the text of the line
3034     control
3035 */
3036 void QQuickTextInputPrivate::processInputMethodEvent(QInputMethodEvent *event)
3037 {
3038     Q_Q(QQuickTextInput);
3039
3040     int priorState = -1;
3041     bool isGettingInput = !event->commitString().isEmpty()
3042             || event->preeditString() != preeditAreaText()
3043             || event->replacementLength() > 0;
3044     bool cursorPositionChanged = false;
3045     bool selectionChange = false;
3046     m_preeditDirty = event->preeditString() != preeditAreaText();
3047
3048     if (isGettingInput) {
3049         // If any text is being input, remove selected text.
3050         priorState = m_undoState;
3051         separateSelection();
3052         if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit && !m_passwordEchoEditing) {
3053             updatePasswordEchoEditing(true);
3054             m_selstart = 0;
3055             m_selend = m_text.length();
3056         }
3057         removeSelectedText();
3058     }
3059
3060     int c = m_cursor; // cursor position after insertion of commit string
3061     if (event->replacementStart() <= 0)
3062         c += event->commitString().length() - qMin(-event->replacementStart(), event->replacementLength());
3063
3064     m_cursor += event->replacementStart();
3065     if (m_cursor < 0)
3066         m_cursor = 0;
3067
3068     // insert commit string
3069     if (event->replacementLength()) {
3070         m_selstart = m_cursor;
3071         m_selend = m_selstart + event->replacementLength();
3072         m_selend = qMin(m_selend, m_text.length());
3073         removeSelectedText();
3074     }
3075     if (!event->commitString().isEmpty()) {
3076         internalInsert(event->commitString());
3077         cursorPositionChanged = true;
3078     }
3079
3080     m_cursor = qBound(0, c, m_text.length());
3081
3082     for (int i = 0; i < event->attributes().size(); ++i) {
3083         const QInputMethodEvent::Attribute &a = event->attributes().at(i);
3084         if (a.type == QInputMethodEvent::Selection) {
3085             m_cursor = qBound(0, a.start + a.length, m_text.length());
3086             if (a.length) {
3087                 m_selstart = qMax(0, qMin(a.start, m_text.length()));
3088                 m_selend = m_cursor;
3089                 if (m_selend < m_selstart) {
3090                     qSwap(m_selstart, m_selend);
3091                 }
3092                 selectionChange = true;
3093             } else {
3094                 m_selstart = m_selend = 0;
3095             }
3096             cursorPositionChanged = true;
3097         }
3098     }
3099 #ifndef QT_NO_IM
3100     m_textLayout.setPreeditArea(m_cursor, event->preeditString());
3101 #endif //QT_NO_IM
3102     const int oldPreeditCursor = m_preeditCursor;
3103     m_preeditCursor = event->preeditString().length();
3104     hasImState = !event->preeditString().isEmpty();
3105     bool cursorVisible = true;
3106     QList<QTextLayout::FormatRange> formats;
3107     for (int i = 0; i < event->attributes().size(); ++i) {
3108         const QInputMethodEvent::Attribute &a = event->attributes().at(i);
3109         if (a.type == QInputMethodEvent::Cursor) {
3110             hasImState = true;
3111             m_preeditCursor = a.start;
3112             cursorVisible = a.length != 0;
3113         } else if (a.type == QInputMethodEvent::TextFormat) {
3114             hasImState = true;
3115             QTextCharFormat f = qvariant_cast<QTextFormat>(a.value).toCharFormat();
3116             if (f.isValid()) {
3117                 QTextLayout::FormatRange o;
3118                 o.start = a.start + m_cursor;
3119                 o.length = a.length;
3120                 o.format = f;
3121                 formats.append(o);
3122             }
3123         }
3124     }
3125     m_textLayout.setAdditionalFormats(formats);
3126
3127     updateDisplayText(/*force*/ true);
3128     if ((cursorPositionChanged && !emitCursorPositionChanged())
3129             || m_preeditCursor != oldPreeditCursor
3130             || isGettingInput) {
3131         q->updateCursorRectangle();
3132     }
3133
3134     if (isGettingInput)
3135         finishChange(priorState);
3136
3137     q->setCursorVisible(cursorVisible);
3138
3139     if (selectionChange) {
3140         emit q->selectionChanged();
3141         q->updateInputMethod(Qt::ImCursorRectangle | Qt::ImAnchorPosition
3142                             | Qt::ImCursorPosition | Qt::ImCurrentSelection);
3143     }
3144 }
3145
3146 /*!
3147     \internal
3148
3149     Sets the selection to cover the word at the given cursor position.
3150     The word boundaries are defined by the behavior of QTextLayout::SkipWords
3151     cursor mode.
3152 */
3153 void QQuickTextInputPrivate::selectWordAtPos(int cursor)
3154 {
3155     int next = cursor + 1;
3156     if (next > end())
3157         --next;
3158     int c = m_textLayout.previousCursorPosition(next, QTextLayout::SkipWords);
3159     moveCursor(c, false);
3160     // ## text layout should support end of words.
3161     int end = m_textLayout.nextCursorPosition(c, QTextLayout::SkipWords);
3162     while (end > cursor && m_text[end-1].isSpace())
3163         --end;
3164     moveCursor(end, true);
3165 }
3166
3167 /*!
3168     \internal
3169
3170     Completes a change to the line control text.  If the change is not valid
3171     will undo the line control state back to the given \a validateFromState.
3172
3173     If \a edited is true and the change is valid, will emit textEdited() in
3174     addition to textChanged().  Otherwise only emits textChanged() on a valid
3175     change.
3176
3177     The \a update value is currently unused.
3178 */
3179 bool QQuickTextInputPrivate::finishChange(int validateFromState, bool update, bool /*edited*/)
3180 {
3181     Q_Q(QQuickTextInput);
3182
3183     Q_UNUSED(update)
3184     bool inputMethodAttributesChanged = m_textDirty || m_selDirty;
3185     bool alignmentChanged = false;
3186
3187     if (m_textDirty) {
3188         // do validation
3189         bool wasValidInput = m_validInput;
3190         bool wasAcceptable = m_acceptableInput;
3191         m_validInput = true;
3192         m_acceptableInput = true;
3193 #ifndef QT_NO_VALIDATOR
3194         if (m_validator) {
3195             QString textCopy = m_text;
3196             int cursorCopy = m_cursor;
3197             QValidator::State state = m_validator->validate(textCopy, cursorCopy);
3198             m_validInput = state != QValidator::Invalid;
3199             m_acceptableInput = state == QValidator::Acceptable;
3200             if (m_validInput) {
3201                 if (m_text != textCopy) {
3202                     internalSetText(textCopy, cursorCopy);
3203                     return true;
3204                 }
3205                 m_cursor = cursorCopy;
3206             }
3207         }
3208 #endif
3209         if (validateFromState >= 0 && wasValidInput && !m_validInput) {
3210             if (m_transactions.count())
3211                 return false;
3212             internalUndo(validateFromState);
3213             m_history.resize(m_undoState);
3214             m_validInput = true;
3215             m_acceptableInput = wasAcceptable;
3216             m_textDirty = false;
3217         }
3218
3219         if (m_textDirty) {
3220             m_textDirty = false;
3221             m_preeditDirty = false;
3222             alignmentChanged = determineHorizontalAlignment();
3223             emit q->textChanged();
3224         }
3225
3226         updateDisplayText(alignmentChanged);
3227
3228         if (m_acceptableInput != wasAcceptable)
3229             emit q->acceptableInputChanged();
3230     }
3231     if (m_preeditDirty) {
3232         m_preeditDirty = false;
3233         if (determineHorizontalAlignment()) {
3234             alignmentChanged = true;
3235             updateLayout();
3236         }
3237     }
3238
3239     if (m_selDirty) {
3240         m_selDirty = false;
3241         emit q->selectionChanged();
3242     }
3243
3244     inputMethodAttributesChanged |= (m_cursor != m_lastCursorPos);
3245     if (inputMethodAttributesChanged)
3246         q->updateInputMethod();
3247     emitUndoRedoChanged();
3248
3249     if (!emitCursorPositionChanged() && alignmentChanged)
3250         q->updateCursorRectangle();
3251
3252     return true;
3253 }
3254
3255 /*!
3256     \internal
3257
3258     An internal function for setting the text of the line control.
3259 */
3260 void QQuickTextInputPrivate::internalSetText(const QString &txt, int pos, bool edited)
3261 {
3262     Q_Q(QQuickTextInput);
3263     internalDeselect();
3264     QString oldText = m_text;
3265     if (m_maskData) {
3266         m_text = maskString(0, txt, true);
3267         m_text += clearString(m_text.length(), m_maxLength - m_text.length());
3268     } else {
3269         m_text = txt.isEmpty() ? txt : txt.left(m_maxLength);
3270     }
3271     m_history.clear();
3272     m_undoState = 0;
3273     m_cursor = (pos < 0 || pos > m_text.length()) ? m_text.length() : pos;
3274     m_textDirty = (oldText != m_text);
3275
3276     bool changed = finishChange(-1, true, edited);
3277 #ifdef QT_NO_ACCESSIBILITY
3278     Q_UNUSED(changed)
3279 #else
3280     if (changed) {
3281         QAccessibleTextUpdateEvent ev(q, 0, oldText, m_text);
3282         QAccessible::updateAccessibility(&ev);
3283     }
3284 #endif
3285 }
3286
3287
3288 /*!
3289     \internal
3290
3291     Adds the given \a command to the undo history
3292     of the line control.  Does not apply the command.
3293 */
3294 void QQuickTextInputPrivate::addCommand(const Command &cmd)
3295 {
3296     if (m_separator && m_undoState && m_history[m_undoState - 1].type != Separator) {
3297         m_history.resize(m_undoState + 2);
3298         m_history[m_undoState++] = Command(Separator, m_cursor, 0, m_selstart, m_selend);
3299     } else {
3300         m_history.resize(m_undoState + 1);
3301     }
3302     m_separator = false;
3303     m_history[m_undoState++] = cmd;
3304 }
3305
3306 /*!
3307     \internal
3308
3309     Inserts the given string \a s into the line
3310     control.
3311
3312     Also adds the appropriate commands into the undo history.
3313     This function does not call finishChange(), and may leave the text
3314     in an invalid state.
3315 */
3316 void QQuickTextInputPrivate::internalInsert(const QString &s)
3317 {
3318     Q_Q(QQuickTextInput);
3319     if (m_echoMode == QQuickTextInput::Password) {
3320         int delay = qGuiApp->styleHints()->passwordMaskDelay();
3321         if (delay > 0)
3322             m_passwordEchoTimer.start(delay, q);
3323     }
3324     Q_ASSERT(!hasSelectedText());   // insert(), processInputMethodEvent() call removeSelectedText() first.
3325     if (m_maskData) {
3326         QString ms = maskString(m_cursor, s);
3327         for (int i = 0; i < (int) ms.length(); ++i) {
3328             addCommand (Command(DeleteSelection, m_cursor + i, m_text.at(m_cursor + i), -1, -1));
3329             addCommand(Command(Insert, m_cursor + i, ms.at(i), -1, -1));
3330         }
3331         m_text.replace(m_cursor, ms.length(), ms);
3332         m_cursor += ms.length();
3333         m_cursor = nextMaskBlank(m_cursor);
3334         m_textDirty = true;
3335     } else {
3336         int remaining = m_maxLength - m_text.length();
3337         if (remaining != 0) {
3338             m_text.insert(m_cursor, s.left(remaining));
3339             for (int i = 0; i < (int) s.left(remaining).length(); ++i)
3340                addCommand(Command(Insert, m_cursor++, s.at(i), -1, -1));
3341             m_textDirty = true;
3342         }
3343     }
3344 }
3345
3346 /*!
3347     \internal
3348
3349     deletes a single character from the current text.  If \a wasBackspace,
3350     the character prior to the cursor is removed.  Otherwise the character
3351     after the cursor is removed.
3352
3353     Also adds the appropriate commands into the undo history.
3354     This function does not call finishChange(), and may leave the text
3355     in an invalid state.
3356 */
3357 void QQuickTextInputPrivate::internalDelete(bool wasBackspace)
3358 {
3359     if (m_cursor < (int) m_text.length()) {
3360         cancelPasswordEchoTimer();
3361         Q_ASSERT(!hasSelectedText());   // del(), backspace() call removeSelectedText() first.
3362         addCommand(Command((CommandType)((m_maskData ? 2 : 0) + (wasBackspace ? Remove : Delete)),
3363                    m_cursor, m_text.at(m_cursor), -1, -1));
3364         if (m_maskData) {
3365             m_text.replace(m_cursor, 1, clearString(m_cursor, 1));
3366             addCommand(Command(Insert, m_cursor, m_text.at(m_cursor), -1, -1));
3367         } else {
3368             m_text.remove(m_cursor, 1);
3369         }
3370         m_textDirty = true;
3371     }
3372 }
3373
3374 /*!
3375     \internal
3376
3377     removes the currently selected text from the line control.
3378
3379     Also adds the appropriate commands into the undo history.
3380     This function does not call finishChange(), and may leave the text
3381     in an invalid state.
3382 */
3383 void QQuickTextInputPrivate::removeSelectedText()
3384 {
3385     if (m_selstart < m_selend && m_selend <= (int) m_text.length()) {
3386         cancelPasswordEchoTimer();
3387         int i ;
3388         if (m_selstart <= m_cursor && m_cursor < m_selend) {
3389             // cursor is within the selection. Split up the commands
3390             // to be able to restore the correct cursor position
3391             for (i = m_cursor; i >= m_selstart; --i)
3392                 addCommand (Command(DeleteSelection, i, m_text.at(i), -1, 1));
3393             for (i = m_selend - 1; i > m_cursor; --i)
3394                 addCommand (Command(DeleteSelection, i - m_cursor + m_selstart - 1, m_text.at(i), -1, -1));
3395         } else {
3396             for (i = m_selend-1; i >= m_selstart; --i)
3397                 addCommand (Command(RemoveSelection, i, m_text.at(i), -1, -1));
3398         }
3399         if (m_maskData) {
3400             m_text.replace(m_selstart, m_selend - m_selstart,  clearString(m_selstart, m_selend - m_selstart));
3401             for (int i = 0; i < m_selend - m_selstart; ++i)
3402                 addCommand(Command(Insert, m_selstart + i, m_text.at(m_selstart + i), -1, -1));
3403         } else {
3404             m_text.remove(m_selstart, m_selend - m_selstart);
3405         }
3406         if (m_cursor > m_selstart)
3407             m_cursor -= qMin(m_cursor, m_selend) - m_selstart;
3408         internalDeselect();
3409         m_textDirty = true;
3410     }
3411 }
3412
3413 /*!
3414     \internal
3415
3416     Adds the current selection to the undo history.
3417
3418     Returns true if there is a current selection and false otherwise.
3419 */
3420
3421 bool QQuickTextInputPrivate::separateSelection()
3422 {
3423     if (hasSelectedText()) {
3424         separate();
3425         addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
3426         return true;
3427     } else {
3428         return false;
3429     }
3430 }
3431
3432 /*!
3433     \internal
3434
3435     Parses the input mask specified by \a maskFields to generate
3436     the mask data used to handle input masks.
3437 */
3438 void QQuickTextInputPrivate::parseInputMask(const QString &maskFields)
3439 {
3440     int delimiter = maskFields.indexOf(QLatin1Char(';'));
3441     if (maskFields.isEmpty() || delimiter == 0) {
3442         if (m_maskData) {
3443             delete [] m_maskData;
3444             m_maskData = 0;
3445             m_maxLength = 32767;
3446             internalSetText(QString());
3447         }
3448         return;
3449     }
3450
3451     if (delimiter == -1) {
3452         m_blank = QLatin1Char(' ');
3453         m_inputMask = maskFields;
3454     } else {
3455         m_inputMask = maskFields.left(delimiter);
3456         m_blank = (delimiter + 1 < maskFields.length()) ? maskFields[delimiter + 1] : QLatin1Char(' ');
3457     }
3458
3459     // calculate m_maxLength / m_maskData length
3460     m_maxLength = 0;
3461     QChar c = 0;
3462     for (int i=0; i<m_inputMask.length(); i++) {
3463         c = m_inputMask.at(i);
3464         if (i > 0 && m_inputMask.at(i-1) == QLatin1Char('\\')) {
3465             m_maxLength++;
3466             continue;
3467         }
3468         if (c != QLatin1Char('\\') && c != QLatin1Char('!') &&
3469              c != QLatin1Char('<') && c != QLatin1Char('>') &&
3470              c != QLatin1Char('{') && c != QLatin1Char('}') &&
3471              c != QLatin1Char('[') && c != QLatin1Char(']'))
3472             m_maxLength++;
3473     }
3474
3475     delete [] m_maskData;
3476     m_maskData = new MaskInputData[m_maxLength];
3477
3478     MaskInputData::Casemode m = MaskInputData::NoCaseMode;
3479     c = 0;
3480     bool s;
3481     bool escape = false;
3482     int index = 0;
3483     for (int i = 0; i < m_inputMask.length(); i++) {
3484         c = m_inputMask.at(i);
3485         if (escape) {
3486             s = true;
3487             m_maskData[index].maskChar = c;
3488             m_maskData[index].separator = s;
3489             m_maskData[index].caseMode = m;
3490             index++;
3491             escape = false;
3492         } else if (c == QLatin1Char('<')) {
3493                 m = MaskInputData::Lower;
3494         } else if (c == QLatin1Char('>')) {
3495             m = MaskInputData::Upper;
3496         } else if (c == QLatin1Char('!')) {
3497             m = MaskInputData::NoCaseMode;
3498         } else if (c != QLatin1Char('{') && c != QLatin1Char('}') && c != QLatin1Char('[') && c != QLatin1Char(']')) {
3499             switch (c.unicode()) {
3500             case 'A':
3501             case 'a':
3502             case 'N':
3503             case 'n':
3504             case 'X':
3505             case 'x':
3506             case '9':
3507             case '0':
3508             case 'D':
3509             case 'd':
3510             case '#':
3511             case 'H':
3512             case 'h':
3513             case 'B':
3514             case 'b':
3515                 s = false;
3516                 break;
3517             case '\\':
3518                 escape = true;
3519             default:
3520                 s = true;
3521                 break;
3522             }
3523
3524             if (!escape) {
3525                 m_maskData[index].maskChar = c;
3526                 m_maskData[index].separator = s;
3527                 m_maskData[index].caseMode = m;
3528                 index++;
3529             }
3530         }
3531     }
3532     internalSetText(m_text);
3533 }
3534
3535
3536 /*!
3537     \internal
3538
3539     checks if the key is valid compared to the inputMask
3540 */
3541 bool QQuickTextInputPrivate::isValidInput(QChar key, QChar mask) const
3542 {
3543     switch (mask.unicode()) {
3544     case 'A':
3545         if (key.isLetter())
3546             return true;
3547         break;
3548     case 'a':
3549         if (key.isLetter() || key == m_blank)
3550             return true;
3551         break;
3552     case 'N':
3553         if (key.isLetterOrNumber())
3554             return true;
3555         break;
3556     case 'n':
3557         if (key.isLetterOrNumber() || key == m_blank)
3558             return true;
3559         break;
3560     case 'X':
3561         if (key.isPrint())
3562             return true;
3563         break;
3564     case 'x':
3565         if (key.isPrint() || key == m_blank)
3566             return true;
3567         break;
3568     case '9':
3569         if (key.isNumber())
3570             return true;
3571         break;
3572     case '0':
3573         if (key.isNumber() || key == m_blank)
3574             return true;
3575         break;
3576     case 'D':
3577         if (key.isNumber() && key.digitValue() > 0)
3578             return true;
3579         break;
3580     case 'd':
3581         if ((key.isNumber() && key.digitValue() > 0) || key == m_blank)
3582             return true;
3583         break;
3584     case '#':
3585         if (key.isNumber() || key == QLatin1Char('+') || key == QLatin1Char('-') || key == m_blank)
3586             return true;
3587         break;
3588     case 'B':
3589         if (key == QLatin1Char('0') || key == QLatin1Char('1'))
3590             return true;
3591         break;
3592     case 'b':
3593         if (key == QLatin1Char('0') || key == QLatin1Char('1') || key == m_blank)
3594             return true;
3595         break;
3596     case 'H':
3597         if (key.isNumber() || (key >= QLatin1Char('a') && key <= QLatin1Char('f')) || (key >= QLatin1Char('A') && key <= QLatin1Char('F')))
3598             return true;
3599         break;
3600     case 'h':
3601         if (key.isNumber() || (key >= QLatin1Char('a') && key <= QLatin1Char('f')) || (key >= QLatin1Char('A') && key <= QLatin1Char('F')) || key == m_blank)
3602             return true;
3603         break;
3604     default:
3605         break;
3606     }
3607     return false;
3608 }
3609
3610 /*!
3611     \internal
3612
3613     Returns true if the given text \a str is valid for any
3614     validator or input mask set for the line control.
3615
3616     Otherwise returns false
3617 */
3618 QQuickTextInputPrivate::ValidatorState QQuickTextInputPrivate::hasAcceptableInput(const QString &str) const
3619 {
3620 #ifndef QT_NO_VALIDATOR
3621     QString textCopy = str;
3622     int cursorCopy = m_cursor;
3623     if (m_validator) {
3624         QValidator::State state = m_validator->validate(textCopy, cursorCopy);
3625         if (state != QValidator::Acceptable)
3626             return ValidatorState(state);
3627     }
3628 #endif
3629
3630     if (!m_maskData)
3631         return AcceptableInput;
3632
3633     if (str.length() != m_maxLength)
3634         return InvalidInput;
3635
3636     for (int i=0; i < m_maxLength; ++i) {
3637         if (m_maskData[i].separator) {
3638             if (str.at(i) != m_maskData[i].maskChar)
3639                 return InvalidInput;
3640         } else {
3641             if (!isValidInput(str.at(i), m_maskData[i].maskChar))
3642                 return InvalidInput;
3643         }
3644     }
3645     return AcceptableInput;
3646 }
3647
3648 /*!
3649     \internal
3650
3651     Applies the inputMask on \a str starting from position \a pos in the mask. \a clear
3652     specifies from where characters should be gotten when a separator is met in \a str - true means
3653     that blanks will be used, false that previous input is used.
3654     Calling this when no inputMask is set is undefined.
3655 */
3656 QString QQuickTextInputPrivate::maskString(uint pos, const QString &str, bool clear) const
3657 {
3658     if (pos >= (uint)m_maxLength)
3659         return QString::fromLatin1("");
3660
3661     QString fill;
3662     fill = clear ? clearString(0, m_maxLength) : m_text;
3663
3664     int strIndex = 0;
3665     QString s = QString::fromLatin1("");
3666     int i = pos;
3667     while (i < m_maxLength) {
3668         if (strIndex < str.length()) {
3669             if (m_maskData[i].separator) {
3670                 s += m_maskData[i].maskChar;
3671                 if (str[(int)strIndex] == m_maskData[i].maskChar)
3672                     strIndex++;
3673                 ++i;
3674             } else {
3675                 if (isValidInput(str[(int)strIndex], m_maskData[i].maskChar)) {
3676                     switch (m_maskData[i].caseMode) {
3677                     case MaskInputData::Upper:
3678                         s += str[(int)strIndex].toUpper();
3679                         break;
3680                     case MaskInputData::Lower:
3681                         s += str[(int)strIndex].toLower();
3682                         break;
3683                     default:
3684                         s += str[(int)strIndex];
3685                     }
3686                     ++i;
3687                 } else {
3688                     // search for separator first
3689                     int n = findInMask(i, true, true, str[(int)strIndex]);
3690                     if (n != -1) {
3691                         if (str.length() != 1 || i == 0 || (i > 0 && (!m_maskData[i-1].separator || m_maskData[i-1].maskChar != str[(int)strIndex]))) {
3692                             s += fill.mid(i, n-i+1);
3693                             i = n + 1; // update i to find + 1
3694                         }
3695                     } else {
3696                         // search for valid m_blank if not
3697                         n = findInMask(i, true, false, str[(int)strIndex]);
3698                         if (n != -1) {
3699                             s += fill.mid(i, n-i);
3700                             switch (m_maskData[n].caseMode) {
3701                             case MaskInputData::Upper:
3702                                 s += str[(int)strIndex].toUpper();
3703                                 break;
3704                             case MaskInputData::Lower:
3705                                 s += str[(int)strIndex].toLower();
3706                                 break;
3707                             default:
3708                                 s += str[(int)strIndex];
3709                             }
3710                             i = n + 1; // updates i to find + 1
3711                         }
3712                     }
3713                 }
3714                 ++strIndex;
3715             }
3716         } else
3717             break;
3718     }
3719
3720     return s;
3721 }
3722
3723
3724
3725 /*!
3726     \internal
3727
3728     Returns a "cleared" string with only separators and blank chars.
3729     Calling this when no inputMask is set is undefined.
3730 */
3731 QString QQuickTextInputPrivate::clearString(uint pos, uint len) const
3732 {
3733     if (pos >= (uint)m_maxLength)
3734         return QString();
3735
3736     QString s;
3737     int end = qMin((uint)m_maxLength, pos + len);
3738     for (int i = pos; i < end; ++i)
3739         if (m_maskData[i].separator)
3740             s += m_maskData[i].maskChar;
3741         else
3742             s += m_blank;
3743
3744     return s;
3745 }
3746
3747 /*!
3748     \internal
3749
3750     Strips blank parts of the input in a QQuickTextInputPrivate when an inputMask is set,
3751     separators are still included. Typically "127.0__.0__.1__" becomes "127.0.0.1".
3752 */
3753 QString QQuickTextInputPrivate::stripString(const QString &str) const
3754 {
3755     if (!m_maskData)
3756         return str;
3757
3758     QString s;
3759     int end = qMin(m_maxLength, (int)str.length());
3760     for (int i = 0; i < end; ++i) {
3761         if (m_maskData[i].separator)
3762             s += m_maskData[i].maskChar;
3763         else if (str[i] != m_blank)
3764             s += str[i];
3765     }
3766
3767     return s;
3768 }
3769
3770 /*!
3771     \internal
3772     searches forward/backward in m_maskData for either a separator or a m_blank
3773 */
3774 int QQuickTextInputPrivate::findInMask(int pos, bool forward, bool findSeparator, QChar searchChar) const
3775 {
3776     if (pos >= m_maxLength || pos < 0)
3777         return -1;
3778
3779     int end = forward ? m_maxLength : -1;
3780     int step = forward ? 1 : -1;
3781     int i = pos;
3782
3783     while (i != end) {
3784         if (findSeparator) {
3785             if (m_maskData[i].separator && m_maskData[i].maskChar == searchChar)
3786                 return i;
3787         } else {
3788             if (!m_maskData[i].separator) {
3789                 if (searchChar.isNull())
3790                     return i;
3791                 else if (isValidInput(searchChar, m_maskData[i].maskChar))
3792                     return i;
3793             }
3794         }
3795         i += step;
3796     }
3797     return -1;
3798 }
3799
3800 void QQuickTextInputPrivate::internalUndo(int until)
3801 {
3802     if (!isUndoAvailable())
3803         return;
3804     cancelPasswordEchoTimer();
3805     internalDeselect();
3806     while (m_undoState && m_undoState > until) {
3807         Command& cmd = m_history[--m_undoState];
3808         switch (cmd.type) {
3809         case Insert:
3810             m_text.remove(cmd.pos, 1);
3811             m_cursor = cmd.pos;
3812             break;
3813         case SetSelection:
3814             m_selstart = cmd.selStart;
3815             m_selend = cmd.selEnd;
3816             m_cursor = cmd.pos;
3817             break;
3818         case Remove:
3819         case RemoveSelection:
3820             m_text.insert(cmd.pos, cmd.uc);
3821             m_cursor = cmd.pos + 1;
3822             break;
3823         case Delete:
3824         case DeleteSelection:
3825             m_text.insert(cmd.pos, cmd.uc);
3826             m_cursor = cmd.pos;
3827             break;
3828         case Separator:
3829             continue;
3830         }
3831         if (until < 0 && m_undoState) {
3832             Command& next = m_history[m_undoState-1];
3833             if (next.type != cmd.type
3834                     && next.type < RemoveSelection
3835                     && (cmd.type < RemoveSelection || next.type == Separator)) {
3836                 break;
3837             }
3838         }
3839     }
3840     separate();
3841     m_textDirty = true;
3842 }
3843
3844 void QQuickTextInputPrivate::internalRedo()
3845 {
3846     if (!isRedoAvailable())
3847         return;
3848     internalDeselect();
3849     while (m_undoState < (int)m_history.size()) {
3850         Command& cmd = m_history[m_undoState++];
3851         switch (cmd.type) {
3852         case Insert:
3853             m_text.insert(cmd.pos, cmd.uc);
3854             m_cursor = cmd.pos + 1;
3855             break;
3856         case SetSelection:
3857             m_selstart = cmd.selStart;
3858             m_selend = cmd.selEnd;
3859             m_cursor = cmd.pos;
3860             break;
3861         case Remove:
3862         case Delete:
3863         case RemoveSelection:
3864         case DeleteSelection:
3865             m_text.remove(cmd.pos, 1);
3866             m_selstart = cmd.selStart;
3867             m_selend = cmd.selEnd;
3868             m_cursor = cmd.pos;
3869             break;
3870         case Separator:
3871             m_selstart = cmd.selStart;
3872             m_selend = cmd.selEnd;
3873             m_cursor = cmd.pos;
3874             break;
3875         }
3876         if (m_undoState < (int)m_history.size()) {
3877             Command& next = m_history[m_undoState];
3878             if (next.type != cmd.type
3879                     && cmd.type < RemoveSelection
3880                     && next.type != Separator
3881                     && (next.type < RemoveSelection || cmd.type == Separator)) {
3882                 break;
3883             }
3884         }
3885     }
3886     m_textDirty = true;
3887 }
3888
3889 void QQuickTextInputPrivate::emitUndoRedoChanged()
3890 {
3891     Q_Q(QQuickTextInput);
3892     const bool previousUndo = canUndo;
3893     const bool previousRedo = canRedo;
3894
3895     canUndo = isUndoAvailable();
3896     canRedo = isRedoAvailable();
3897
3898     if (previousUndo != canUndo)
3899         emit q->canUndoChanged();
3900     if (previousRedo != canRedo)
3901         emit q->canRedoChanged();
3902 }
3903
3904 /*!
3905     \internal
3906
3907     If the current cursor position differs from the last emitted cursor
3908     position, emits cursorPositionChanged().
3909 */
3910 bool QQuickTextInputPrivate::emitCursorPositionChanged()
3911 {
3912     Q_Q(QQuickTextInput);
3913     if (m_cursor != m_lastCursorPos) {
3914         m_lastCursorPos = m_cursor;
3915
3916         q->updateCursorRectangle();
3917         emit q->cursorPositionChanged();
3918
3919         if (!hasSelectedText()) {
3920             if (lastSelectionStart != m_cursor) {
3921                 lastSelectionStart = m_cursor;
3922                 emit q->selectionStartChanged();
3923             }
3924             if (lastSelectionEnd != m_cursor) {
3925                 lastSelectionEnd = m_cursor;
3926                 emit q->selectionEndChanged();
3927             }
3928         }
3929
3930 #ifndef QT_NO_ACCESSIBILITY
3931         QAccessibleTextCursorEvent ev(q, m_cursor);
3932         QAccessible::updateAccessibility(&ev);
3933 #endif
3934
3935         return true;
3936     }
3937     return false;
3938 }
3939
3940
3941 void QQuickTextInputPrivate::setCursorBlinkPeriod(int msec)
3942 {
3943     Q_Q(QQuickTextInput);
3944     if (msec == m_blinkPeriod)
3945         return;
3946     if (m_blinkTimer) {
3947         q->killTimer(m_blinkTimer);
3948     }
3949     if (msec) {
3950         m_blinkTimer = q->startTimer(msec / 2);
3951         m_blinkStatus = 1;
3952     } else {
3953         m_blinkTimer = 0;
3954         if (m_blinkStatus == 1) {
3955             updateType = UpdatePaintNode;
3956             q->update();
3957         }
3958     }
3959     m_blinkPeriod = msec;
3960 }
3961
3962 void QQuickTextInput::timerEvent(QTimerEvent *event)
3963 {
3964     Q_D(QQuickTextInput);
3965     if (event->timerId() == d->m_blinkTimer) {
3966         d->m_blinkStatus = !d->m_blinkStatus;
3967         d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
3968         update();
3969     } else if (event->timerId() == d->m_passwordEchoTimer.timerId()) {
3970         d->m_passwordEchoTimer.stop();
3971         d->updateDisplayText();
3972         updateCursorRectangle();
3973     }
3974 }
3975
3976 void QQuickTextInputPrivate::processKeyEvent(QKeyEvent* event)
3977 {
3978     Q_Q(QQuickTextInput);
3979
3980     if (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return) {
3981         if (hasAcceptableInput(m_text) || fixup()) {
3982             emit q->accepted();
3983         }
3984         event->ignore();
3985         return;
3986     }
3987
3988     if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit
3989         && !m_passwordEchoEditing
3990         && !m_readOnly
3991         && !event->text().isEmpty()
3992         && !(event->modifiers() & Qt::ControlModifier)) {
3993         // Clear the edit and reset to normal echo mode while editing; the
3994         // echo mode switches back when the edit loses focus
3995         // ### resets current content.  dubious code; you can
3996         // navigate with keys up, down, back, and select(?), but if you press
3997         // "left" or "right" it clears?
3998         updatePasswordEchoEditing(true);
3999         clear();
4000     }
4001
4002     bool unknown = false;
4003     bool visual = cursorMoveStyle() == Qt::VisualMoveStyle;
4004
4005     if (false) {
4006     }
4007 #ifndef QT_NO_SHORTCUT
4008     else if (event == QKeySequence::Undo) {
4009         q->undo();
4010     }
4011     else if (event == QKeySequence::Redo) {
4012         q->redo();
4013     }
4014     else if (event == QKeySequence::SelectAll) {
4015         selectAll();
4016     }
4017 #ifndef QT_NO_CLIPBOARD
4018     else if (event == QKeySequence::Copy) {
4019         copy();
4020     }
4021     else if (event == QKeySequence::Paste) {
4022         if (!m_readOnly) {
4023             QClipboard::Mode mode = QClipboard::Clipboard;
4024             paste(mode);
4025         }
4026     }
4027     else if (event == QKeySequence::Cut) {
4028         if (!m_readOnly) {
4029             copy();
4030             del();
4031         }
4032     }
4033     else if (event == QKeySequence::DeleteEndOfLine) {
4034         if (!m_readOnly)
4035             deleteEndOfLine();
4036     }
4037 #endif //QT_NO_CLIPBOARD
4038     else if (event == QKeySequence::MoveToStartOfLine || event == QKeySequence::MoveToStartOfBlock) {
4039         home(0);
4040     }
4041     else if (event == QKeySequence::MoveToEndOfLine || event == QKeySequence::MoveToEndOfBlock) {
4042         end(0);
4043     }
4044     else if (event == QKeySequence::SelectStartOfLine || event == QKeySequence::SelectStartOfBlock) {
4045         home(1);
4046     }
4047     else if (event == QKeySequence::SelectEndOfLine || event == QKeySequence::SelectEndOfBlock) {
4048         end(1);
4049     }
4050     else if (event == QKeySequence::MoveToNextChar) {
4051         if (hasSelectedText()) {
4052             moveCursor(selectionEnd(), false);
4053         } else {
4054             cursorForward(0, visual ? 1 : (layoutDirection() == Qt::LeftToRight ? 1 : -1));
4055         }
4056     }
4057     else if (event == QKeySequence::SelectNextChar) {
4058         cursorForward(1, visual ? 1 : (layoutDirection() == Qt::LeftToRight ? 1 : -1));
4059     }
4060     else if (event == QKeySequence::MoveToPreviousChar) {
4061         if (hasSelectedText()) {
4062             moveCursor(selectionStart(), false);
4063         } else {
4064             cursorForward(0, visual ? -1 : (layoutDirection() == Qt::LeftToRight ? -1 : 1));
4065         }
4066     }
4067     else if (event == QKeySequence::SelectPreviousChar) {
4068         cursorForward(1, visual ? -1 : (layoutDirection() == Qt::LeftToRight ? -1 : 1));
4069     }
4070     else if (event == QKeySequence::MoveToNextWord) {
4071         if (m_echoMode == QQuickTextInput::Normal)
4072             layoutDirection() == Qt::LeftToRight ? cursorWordForward(0) : cursorWordBackward(0);
4073         else
4074             layoutDirection() == Qt::LeftToRight ? end(0) : home(0);
4075     }
4076     else if (event == QKeySequence::MoveToPreviousWord) {
4077         if (m_echoMode == QQuickTextInput::Normal)
4078             layoutDirection() == Qt::LeftToRight ? cursorWordBackward(0) : cursorWordForward(0);
4079         else if (!m_readOnly) {
4080             layoutDirection() == Qt::LeftToRight ? home(0) : end(0);
4081         }
4082     }
4083     else if (event == QKeySequence::SelectNextWord) {
4084         if (m_echoMode == QQuickTextInput::Normal)
4085             layoutDirection() == Qt::LeftToRight ? cursorWordForward(1) : cursorWordBackward(1);
4086         else
4087             layoutDirection() == Qt::LeftToRight ? end(1) : home(1);
4088     }
4089     else if (event == QKeySequence::SelectPreviousWord) {
4090         if (m_echoMode == QQuickTextInput::Normal)
4091             layoutDirection() == Qt::LeftToRight ? cursorWordBackward(1) : cursorWordForward(1);
4092         else
4093             layoutDirection() == Qt::LeftToRight ? home(1) : end(1);
4094     }
4095     else if (event == QKeySequence::Delete) {
4096         if (!m_readOnly)
4097             del();
4098     }
4099     else if (event == QKeySequence::DeleteEndOfWord) {
4100         if (!m_readOnly)
4101             deleteEndOfWord();
4102     }
4103     else if (event == QKeySequence::DeleteStartOfWord) {
4104         if (!m_readOnly)
4105             deleteStartOfWord();
4106     }
4107 #endif // QT_NO_SHORTCUT
4108     else {
4109         bool handled = false;
4110         if (event->modifiers() & Qt::ControlModifier) {
4111             switch (event->key()) {
4112             case Qt::Key_Backspace:
4113                 if (!m_readOnly)
4114                     deleteStartOfWord();
4115                 break;
4116             default:
4117                 if (!handled)
4118                     unknown = true;
4119             }
4120         } else { // ### check for *no* modifier
4121             switch (event->key()) {
4122             case Qt::Key_Backspace:
4123                 if (!m_readOnly) {
4124                     backspace();
4125                 }
4126                 break;
4127             default:
4128                 if (!handled)
4129                     unknown = true;
4130             }
4131         }
4132     }
4133
4134     if (event->key() == Qt::Key_Direction_L || event->key() == Qt::Key_Direction_R) {
4135         setLayoutDirection((event->key() == Qt::Key_Direction_L) ? Qt::LeftToRight : Qt::RightToLeft);
4136         unknown = false;
4137     }
4138
4139     if (unknown && !m_readOnly) {
4140         QString t = event->text();
4141         if (!t.isEmpty() && t.at(0).isPrint()) {
4142             insert(t);
4143             event->accept();
4144             return;
4145         }
4146     }
4147
4148     if (unknown)
4149         event->ignore();
4150     else
4151         event->accept();
4152 }
4153
4154 /*!
4155     \internal
4156
4157     Deletes the portion of the word before the current cursor position.
4158 */
4159
4160 void QQuickTextInputPrivate::deleteStartOfWord()
4161 {
4162     int priorState = m_undoState;
4163     Command cmd(SetSelection, m_cursor, 0, m_selstart, m_selend);
4164     separate();
4165     cursorWordBackward(true);
4166     addCommand(cmd);
4167     removeSelectedText();
4168     finishChange(priorState);
4169 }
4170
4171 /*!
4172     \internal
4173
4174     Deletes the portion of the word after the current cursor position.
4175 */
4176
4177 void QQuickTextInputPrivate::deleteEndOfWord()
4178 {
4179     int priorState = m_undoState;
4180     Command cmd(SetSelection, m_cursor, 0, m_selstart, m_selend);
4181     separate();
4182     cursorWordForward(true);
4183     // moveCursor (sometimes) calls separate() so we need to add the command after that so the
4184     // cursor position and selection are restored in the same undo operation as the remove.
4185     addCommand(cmd);
4186     removeSelectedText();
4187     finishChange(priorState);
4188 }
4189
4190 /*!
4191     \internal
4192
4193     Deletes all text from the cursor position to the end of the line.
4194 */
4195
4196 void QQuickTextInputPrivate::deleteEndOfLine()
4197 {
4198     int priorState = m_undoState;
4199     Command cmd(SetSelection, m_cursor, 0, m_selstart, m_selend);
4200     separate();
4201     setSelection(m_cursor, end());
4202     addCommand(cmd);
4203     removeSelectedText();
4204     finishChange(priorState);
4205 }
4206
4207 QT_END_NAMESPACE
4208