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