Fix clipping of TextInput contents.
[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     int cursorWidth = d->cursorItem ? d->cursorItem->width() : d->m_cursorWidth;
2311
2312     // Could include font max left/right bearings to either side of rectangle.
2313     QRectF r = QQuickImplicitSizeItem::boundingRect();
2314     r.setRight(r.right() + cursorWidth);
2315     return r;
2316 }
2317
2318 void QQuickTextInput::q_canPasteChanged()
2319 {
2320     Q_D(QQuickTextInput);
2321     bool old = d->canPaste;
2322 #ifndef QT_NO_CLIPBOARD
2323     if (const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData())
2324         d->canPaste = !d->m_readOnly && mimeData->hasText();
2325     else
2326         d->canPaste = false;
2327 #endif
2328
2329     bool changed = d->canPaste != old || !d->canPasteValid;
2330     d->canPasteValid = true;
2331     if (changed)
2332         emit canPasteChanged();
2333
2334 }
2335
2336 // ### these should come from QStyleHints
2337 const int textCursorWidth = 1;
2338 const bool fullWidthSelection = true;
2339
2340 /*!
2341     \internal
2342
2343     Updates the display text based of the current edit text
2344     If the text has changed will emit displayTextChanged()
2345 */
2346 void QQuickTextInputPrivate::updateDisplayText(bool forceUpdate)
2347 {
2348     QString orig = m_textLayout.text();
2349     QString str;
2350     if (m_echoMode == QQuickTextInput::NoEcho)
2351         str = QString::fromLatin1("");
2352     else
2353         str = m_text;
2354
2355     if (m_echoMode == QQuickTextInput::Password) {
2356          str.fill(m_passwordCharacter);
2357 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
2358         if (m_passwordEchoTimer.isActive() && m_cursor > 0 && m_cursor <= m_text.length()) {
2359             int cursor = m_cursor - 1;
2360             QChar uc = m_text.at(cursor);
2361             str[cursor] = uc;
2362             if (cursor > 0 && uc.unicode() >= 0xdc00 && uc.unicode() < 0xe000) {
2363                 // second half of a surrogate, check if we have the first half as well,
2364                 // if yes restore both at once
2365                 uc = m_text.at(cursor - 1);
2366                 if (uc.unicode() >= 0xd800 && uc.unicode() < 0xdc00)
2367                     str[cursor - 1] = uc;
2368             }
2369         }
2370 #endif
2371     } else if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit && !m_passwordEchoEditing) {
2372         str.fill(m_passwordCharacter);
2373     }
2374
2375     // replace certain non-printable characters with spaces (to avoid
2376     // drawing boxes when using fonts that don't have glyphs for such
2377     // characters)
2378     QChar* uc = str.data();
2379     for (int i = 0; i < (int)str.length(); ++i) {
2380         if ((uc[i] < 0x20 && uc[i] != 0x09)
2381             || uc[i] == QChar::LineSeparator
2382             || uc[i] == QChar::ParagraphSeparator
2383             || uc[i] == QChar::ObjectReplacementCharacter)
2384             uc[i] = QChar(0x0020);
2385     }
2386
2387     if (str != orig || forceUpdate) {
2388         m_textLayout.setText(str);
2389         updateLayout(); // polish?
2390         emit q_func()->displayTextChanged();
2391     }
2392 }
2393
2394 void QQuickTextInputPrivate::updateLayout()
2395 {
2396     Q_Q(QQuickTextInput);
2397
2398     if (!q->isComponentComplete())
2399         return;
2400
2401     QTextOption option = m_textLayout.textOption();
2402     option.setTextDirection(m_layoutDirection);
2403     option.setFlags(QTextOption::IncludeTrailingSpaces);
2404     option.setWrapMode(QTextOption::WrapMode(wrapMode));
2405     option.setAlignment(Qt::Alignment(q->effectiveHAlign()));
2406     m_textLayout.setTextOption(option);
2407     m_textLayout.setFont(font);
2408
2409     boundingRect = QRectF();
2410     m_textLayout.beginLayout();
2411     QTextLine line = m_textLayout.createLine();
2412     qreal lineWidth = q->widthValid() ? q->width() : INT_MAX;
2413     qreal height = 0;
2414     QTextLine firstLine = line;
2415     do {
2416         line.setLineWidth(lineWidth);
2417         line.setPosition(QPointF(line.position().x(), height));
2418         boundingRect = boundingRect.united(line.naturalTextRect());
2419
2420         height += line.height();
2421         line = m_textLayout.createLine();
2422     } while (line.isValid());
2423     m_textLayout.endLayout();
2424
2425     option.setWrapMode(QTextOption::NoWrap);
2426     m_textLayout.setTextOption(option);
2427
2428     m_ascent = qRound(firstLine.ascent());
2429     textLayoutDirty = true;
2430
2431     q->update();
2432     q->setImplicitSize(qCeil(boundingRect.width()), qCeil(boundingRect.height()));
2433
2434 }
2435
2436 #ifndef QT_NO_CLIPBOARD
2437 /*!
2438     \internal
2439
2440     Copies the currently selected text into the clipboard using the given
2441     \a mode.
2442
2443     \note If the echo mode is set to a mode other than Normal then copy
2444     will not work.  This is to prevent using copy as a method of bypassing
2445     password features of the line control.
2446 */
2447 void QQuickTextInputPrivate::copy(QClipboard::Mode mode) const
2448 {
2449     QString t = selectedText();
2450     if (!t.isEmpty() && m_echoMode == QQuickTextInput::Normal) {
2451         QGuiApplication::clipboard()->setText(t, mode);
2452     }
2453 }
2454
2455 /*!
2456     \internal
2457
2458     Inserts the text stored in the application clipboard into the line
2459     control.
2460
2461     \sa insert()
2462 */
2463 void QQuickTextInputPrivate::paste(QClipboard::Mode clipboardMode)
2464 {
2465     QString clip = QGuiApplication::clipboard()->text(clipboardMode);
2466     if (!clip.isEmpty() || hasSelectedText()) {
2467         separate(); //make it a separate undo/redo command
2468         insert(clip);
2469         separate();
2470     }
2471 }
2472
2473 #endif // !QT_NO_CLIPBOARD
2474
2475 /*!
2476     \internal
2477
2478     Exits preedit mode and commits parts marked as tentative commit
2479 */
2480 void QQuickTextInputPrivate::commitPreedit()
2481 {
2482     if (!composeMode())
2483         return;
2484
2485     qApp->inputPanel()->reset();
2486
2487     if (!m_tentativeCommit.isEmpty()) {
2488         internalInsert(m_tentativeCommit);
2489         m_tentativeCommit.clear();
2490         finishChange(-1, true/*not used, not documented*/, false);
2491     }
2492
2493     m_preeditCursor = 0;
2494     m_textLayout.setPreeditArea(-1, QString());
2495     m_textLayout.clearAdditionalFormats();
2496     updateLayout();
2497 }
2498
2499 /*!
2500     \internal
2501
2502     Handles the behavior for the backspace key or function.
2503     Removes the current selection if there is a selection, otherwise
2504     removes the character prior to the cursor position.
2505
2506     \sa del()
2507 */
2508 void QQuickTextInputPrivate::backspace()
2509 {
2510     int priorState = m_undoState;
2511     if (hasSelectedText()) {
2512         removeSelectedText();
2513     } else if (m_cursor) {
2514             --m_cursor;
2515             if (m_maskData)
2516                 m_cursor = prevMaskBlank(m_cursor);
2517             QChar uc = m_text.at(m_cursor);
2518             if (m_cursor > 0 && uc.unicode() >= 0xdc00 && uc.unicode() < 0xe000) {
2519                 // second half of a surrogate, check if we have the first half as well,
2520                 // if yes delete both at once
2521                 uc = m_text.at(m_cursor - 1);
2522                 if (uc.unicode() >= 0xd800 && uc.unicode() < 0xdc00) {
2523                     internalDelete(true);
2524                     --m_cursor;
2525                 }
2526             }
2527             internalDelete(true);
2528     }
2529     finishChange(priorState);
2530 }
2531
2532 /*!
2533     \internal
2534
2535     Handles the behavior for the delete key or function.
2536     Removes the current selection if there is a selection, otherwise
2537     removes the character after the cursor position.
2538
2539     \sa del()
2540 */
2541 void QQuickTextInputPrivate::del()
2542 {
2543     int priorState = m_undoState;
2544     if (hasSelectedText()) {
2545         removeSelectedText();
2546     } else {
2547         int n = m_textLayout.nextCursorPosition(m_cursor) - m_cursor;
2548         while (n--)
2549             internalDelete();
2550     }
2551     finishChange(priorState);
2552 }
2553
2554 /*!
2555     \internal
2556
2557     Inserts the given \a newText at the current cursor position.
2558     If there is any selected text it is removed prior to insertion of
2559     the new text.
2560 */
2561 void QQuickTextInputPrivate::insert(const QString &newText)
2562 {
2563     int priorState = m_undoState;
2564     removeSelectedText();
2565     internalInsert(newText);
2566     finishChange(priorState);
2567 }
2568
2569 /*!
2570     \internal
2571
2572     Clears the line control text.
2573 */
2574 void QQuickTextInputPrivate::clear()
2575 {
2576     int priorState = m_undoState;
2577     m_selstart = 0;
2578     m_selend = m_text.length();
2579     removeSelectedText();
2580     separate();
2581     finishChange(priorState, /*update*/false, /*edited*/false);
2582 }
2583
2584 /*!
2585     \internal
2586
2587     Sets \a length characters from the given \a start position as selected.
2588     The given \a start position must be within the current text for
2589     the line control.  If \a length characters cannot be selected, then
2590     the selection will extend to the end of the current text.
2591 */
2592 void QQuickTextInputPrivate::setSelection(int start, int length)
2593 {
2594     Q_Q(QQuickTextInput);
2595     commitPreedit();
2596
2597     if (start < 0 || start > (int)m_text.length()){
2598         qWarning("QQuickTextInputPrivate::setSelection: Invalid start position");
2599         return;
2600     }
2601
2602     if (length > 0) {
2603         if (start == m_selstart && start + length == m_selend && m_cursor == m_selend)
2604             return;
2605         m_selstart = start;
2606         m_selend = qMin(start + length, (int)m_text.length());
2607         m_cursor = m_selend;
2608     } else if (length < 0){
2609         if (start == m_selend && start + length == m_selstart && m_cursor == m_selstart)
2610             return;
2611         m_selstart = qMax(start + length, 0);
2612         m_selend = start;
2613         m_cursor = m_selstart;
2614     } else if (m_selstart != m_selend) {
2615         m_selstart = 0;
2616         m_selend = 0;
2617         m_cursor = start;
2618     } else {
2619         m_cursor = start;
2620         emitCursorPositionChanged();
2621         return;
2622     }
2623     emit q->selectionChanged();
2624     emitCursorPositionChanged();
2625 }
2626
2627 /*!
2628     \internal
2629
2630     Initializes the line control with a starting text value of \a txt.
2631 */
2632 void QQuickTextInputPrivate::init(const QString &txt)
2633 {
2634     m_text = txt;
2635
2636     updateDisplayText();
2637     m_cursor = m_text.length();
2638 }
2639
2640 /*!
2641     \internal
2642
2643     Sets the password echo editing to \a editing.  If password echo editing
2644     is true, then the text of the password is displayed even if the echo
2645     mode is set to QLineEdit::PasswordEchoOnEdit.  Password echoing editing
2646     does not affect other echo modes.
2647 */
2648 void QQuickTextInputPrivate::updatePasswordEchoEditing(bool editing)
2649 {
2650     cancelPasswordEchoTimer();
2651     m_passwordEchoEditing = editing;
2652     updateDisplayText();
2653 }
2654
2655 /*!
2656     \internal
2657
2658     Fixes the current text so that it is valid given any set validators.
2659
2660     Returns true if the text was changed.  Otherwise returns false.
2661 */
2662 bool QQuickTextInputPrivate::fixup() // this function assumes that validate currently returns != Acceptable
2663 {
2664 #ifndef QT_NO_VALIDATOR
2665     if (m_validator) {
2666         QString textCopy = m_text;
2667         int cursorCopy = m_cursor;
2668         m_validator->fixup(textCopy);
2669         if (m_validator->validate(textCopy, cursorCopy) == QValidator::Acceptable) {
2670             if (textCopy != m_text || cursorCopy != m_cursor)
2671                 internalSetText(textCopy, cursorCopy);
2672             return true;
2673         }
2674     }
2675 #endif
2676     return false;
2677 }
2678
2679 /*!
2680     \internal
2681
2682     Moves the cursor to the given position \a pos.   If \a mark is true will
2683     adjust the currently selected text.
2684 */
2685 void QQuickTextInputPrivate::moveCursor(int pos, bool mark)
2686 {
2687     Q_Q(QQuickTextInput);
2688     commitPreedit();
2689
2690     if (pos != m_cursor) {
2691         separate();
2692         if (m_maskData)
2693             pos = pos > m_cursor ? nextMaskBlank(pos) : prevMaskBlank(pos);
2694     }
2695     if (mark) {
2696         int anchor;
2697         if (m_selend > m_selstart && m_cursor == m_selstart)
2698             anchor = m_selend;
2699         else if (m_selend > m_selstart && m_cursor == m_selend)
2700             anchor = m_selstart;
2701         else
2702             anchor = m_cursor;
2703         m_selstart = qMin(anchor, pos);
2704         m_selend = qMax(anchor, pos);
2705     } else {
2706         internalDeselect();
2707     }
2708     m_cursor = pos;
2709     if (mark || m_selDirty) {
2710         m_selDirty = false;
2711         emit q->selectionChanged();
2712     }
2713     emitCursorPositionChanged();
2714 }
2715
2716 /*!
2717     \internal
2718
2719     Applies the given input method event \a event to the text of the line
2720     control
2721 */
2722 void QQuickTextInputPrivate::processInputMethodEvent(QInputMethodEvent *event)
2723 {
2724     Q_Q(QQuickTextInput);
2725
2726     int priorState = -1;
2727     bool isGettingInput = !event->commitString().isEmpty()
2728             || event->preeditString() != preeditAreaText()
2729             || event->replacementLength() > 0;
2730     bool cursorPositionChanged = false;
2731     bool selectionChange = false;
2732     m_preeditDirty = event->preeditString() != preeditAreaText();
2733
2734     if (isGettingInput) {
2735         // If any text is being input, remove selected text.
2736         priorState = m_undoState;
2737         if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit && !m_passwordEchoEditing) {
2738             updatePasswordEchoEditing(true);
2739             m_selstart = 0;
2740             m_selend = m_text.length();
2741         }
2742         removeSelectedText();
2743     }
2744
2745     int c = m_cursor; // cursor position after insertion of commit string
2746     if (event->replacementStart() <= 0)
2747         c += event->commitString().length() - qMin(-event->replacementStart(), event->replacementLength());
2748
2749     m_cursor += event->replacementStart();
2750     if (m_cursor < 0)
2751         m_cursor = 0;
2752
2753     // insert commit string
2754     if (event->replacementLength()) {
2755         m_selstart = m_cursor;
2756         m_selend = m_selstart + event->replacementLength();
2757         m_selend = qMin(m_selend, m_text.length());
2758         removeSelectedText();
2759     }
2760     if (!event->commitString().isEmpty()) {
2761         internalInsert(event->commitString());
2762         cursorPositionChanged = true;
2763     }
2764
2765     m_cursor = qBound(0, c, m_text.length());
2766
2767     for (int i = 0; i < event->attributes().size(); ++i) {
2768         const QInputMethodEvent::Attribute &a = event->attributes().at(i);
2769         if (a.type == QInputMethodEvent::Selection) {
2770             m_cursor = qBound(0, a.start + a.length, m_text.length());
2771             if (a.length) {
2772                 m_selstart = qMax(0, qMin(a.start, m_text.length()));
2773                 m_selend = m_cursor;
2774                 if (m_selend < m_selstart) {
2775                     qSwap(m_selstart, m_selend);
2776                 }
2777                 selectionChange = true;
2778             } else {
2779                 m_selstart = m_selend = 0;
2780             }
2781             cursorPositionChanged = true;
2782         }
2783     }
2784 #ifndef QT_NO_IM
2785     m_textLayout.setPreeditArea(m_cursor, event->preeditString());
2786 #endif //QT_NO_IM
2787     const int oldPreeditCursor = m_preeditCursor;
2788     m_preeditCursor = event->preeditString().length();
2789     m_hideCursor = false;
2790     QList<QTextLayout::FormatRange> formats;
2791     for (int i = 0; i < event->attributes().size(); ++i) {
2792         const QInputMethodEvent::Attribute &a = event->attributes().at(i);
2793         if (a.type == QInputMethodEvent::Cursor) {
2794             m_preeditCursor = a.start;
2795             m_hideCursor = !a.length;
2796         } else if (a.type == QInputMethodEvent::TextFormat) {
2797             QTextCharFormat f = qvariant_cast<QTextFormat>(a.value).toCharFormat();
2798             if (f.isValid()) {
2799                 QTextLayout::FormatRange o;
2800                 o.start = a.start + m_cursor;
2801                 o.length = a.length;
2802                 o.format = f;
2803                 formats.append(o);
2804             }
2805         }
2806     }
2807     m_textLayout.setAdditionalFormats(formats);
2808
2809     updateDisplayText(/*force*/ true);
2810     if (cursorPositionChanged)
2811         emitCursorPositionChanged();
2812     else if (m_preeditCursor != oldPreeditCursor)
2813         q->updateCursorRectangle();
2814
2815     bool tentativeCommitChanged = m_tentativeCommit != event->tentativeCommitString();
2816
2817     if (tentativeCommitChanged) {
2818         m_textDirty = true;
2819         m_tentativeCommit = event->tentativeCommitString();
2820     }
2821
2822     if (isGettingInput || tentativeCommitChanged)
2823         finishChange(priorState);
2824
2825     if (selectionChange)
2826         emit q->selectionChanged();
2827 }
2828
2829 /*!
2830     \internal
2831
2832     Sets the selection to cover the word at the given cursor position.
2833     The word boundaries are defined by the behavior of QTextLayout::SkipWords
2834     cursor mode.
2835 */
2836 void QQuickTextInputPrivate::selectWordAtPos(int cursor)
2837 {
2838     int next = cursor + 1;
2839     if (next > end())
2840         --next;
2841     int c = m_textLayout.previousCursorPosition(next, QTextLayout::SkipWords);
2842     moveCursor(c, false);
2843     // ## text layout should support end of words.
2844     int end = m_textLayout.nextCursorPosition(c, QTextLayout::SkipWords);
2845     while (end > cursor && m_text[end-1].isSpace())
2846         --end;
2847     moveCursor(end, true);
2848 }
2849
2850 /*!
2851     \internal
2852
2853     Completes a change to the line control text.  If the change is not valid
2854     will undo the line control state back to the given \a validateFromState.
2855
2856     If \a edited is true and the change is valid, will emit textEdited() in
2857     addition to textChanged().  Otherwise only emits textChanged() on a valid
2858     change.
2859
2860     The \a update value is currently unused.
2861 */
2862 bool QQuickTextInputPrivate::finishChange(int validateFromState, bool update, bool /*edited*/)
2863 {
2864     Q_Q(QQuickTextInput);
2865
2866     Q_UNUSED(update)
2867
2868     if (m_textDirty) {
2869         // do validation
2870         bool wasValidInput = m_validInput;
2871         m_validInput = true;
2872 #ifndef QT_NO_VALIDATOR
2873         if (m_validator) {
2874             QString textCopy = m_text;
2875             int cursorCopy = m_cursor;
2876             m_validInput = (m_validator->validate(textCopy, cursorCopy) != QValidator::Invalid);
2877             if (m_validInput) {
2878                 if (m_text != textCopy) {
2879                     internalSetText(textCopy, cursorCopy);
2880                     return true;
2881                 }
2882                 m_cursor = cursorCopy;
2883
2884                 if (!m_tentativeCommit.isEmpty()) {
2885                     textCopy.insert(m_cursor, m_tentativeCommit);
2886                     bool validInput = m_validator->validate(textCopy, cursorCopy) != QValidator::Invalid;
2887                     if (!validInput)
2888                         m_tentativeCommit.clear();
2889                 }
2890             } else {
2891                 m_tentativeCommit.clear();
2892             }
2893         }
2894 #endif
2895         if (validateFromState >= 0 && wasValidInput && !m_validInput) {
2896             if (m_transactions.count())
2897                 return false;
2898             internalUndo(validateFromState);
2899             m_history.resize(m_undoState);
2900             if (m_modifiedState > m_undoState)
2901                 m_modifiedState = -1;
2902             m_validInput = true;
2903             m_textDirty = false;
2904         }
2905         updateDisplayText();
2906
2907         if (m_textDirty) {
2908             m_textDirty = false;
2909             m_preeditDirty = false;
2910             determineHorizontalAlignment();
2911             emit q->textChanged();
2912         }
2913
2914         if (m_validInput != wasValidInput)
2915             emit q->acceptableInputChanged();
2916     }
2917     if (m_preeditDirty) {
2918         m_preeditDirty = false;
2919         determineHorizontalAlignment();
2920     }
2921
2922     if (m_selDirty) {
2923         m_selDirty = false;
2924         emit q->selectionChanged();
2925     }
2926     emitCursorPositionChanged();
2927
2928     return true;
2929 }
2930
2931 /*!
2932     \internal
2933
2934     An internal function for setting the text of the line control.
2935 */
2936 void QQuickTextInputPrivate::internalSetText(const QString &txt, int pos, bool edited)
2937 {
2938     Q_Q(QQuickTextInput);
2939     internalDeselect();
2940     QString oldText = m_text;
2941     if (m_maskData) {
2942         m_text = maskString(0, txt, true);
2943         m_text += clearString(m_text.length(), m_maxLength - m_text.length());
2944     } else {
2945         m_text = txt.isEmpty() ? txt : txt.left(m_maxLength);
2946     }
2947     m_history.clear();
2948     m_modifiedState =  m_undoState = 0;
2949     m_cursor = (pos < 0 || pos > m_text.length()) ? m_text.length() : pos;
2950     m_textDirty = (oldText != m_text);
2951
2952     bool changed = finishChange(-1, true, edited);
2953 #ifdef QT_NO_ACCESSIBILITY
2954     Q_UNUSED(changed)
2955 #else
2956     if (changed)
2957         QAccessible::updateAccessibility(q, 0, QAccessible::TextUpdated);
2958 #endif
2959 }
2960
2961
2962 /*!
2963     \internal
2964
2965     Adds the given \a command to the undo history
2966     of the line control.  Does not apply the command.
2967 */
2968 void QQuickTextInputPrivate::addCommand(const Command &cmd)
2969 {
2970     if (m_separator && m_undoState && m_history[m_undoState - 1].type != Separator) {
2971         m_history.resize(m_undoState + 2);
2972         m_history[m_undoState++] = Command(Separator, m_cursor, 0, m_selstart, m_selend);
2973     } else {
2974         m_history.resize(m_undoState + 1);
2975     }
2976     m_separator = false;
2977     m_history[m_undoState++] = cmd;
2978 }
2979
2980 /*!
2981     \internal
2982
2983     Inserts the given string \a s into the line
2984     control.
2985
2986     Also adds the appropriate commands into the undo history.
2987     This function does not call finishChange(), and may leave the text
2988     in an invalid state.
2989 */
2990 void QQuickTextInputPrivate::internalInsert(const QString &s)
2991 {
2992 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
2993     Q_Q(QQuickTextInput);
2994     if (m_echoMode == QQuickTextInput::Password)
2995         m_passwordEchoTimer.start(qt_passwordEchoDelay, q);
2996 #endif
2997     if (hasSelectedText())
2998         addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
2999     if (m_maskData) {
3000         QString ms = maskString(m_cursor, s);
3001         for (int i = 0; i < (int) ms.length(); ++i) {
3002             addCommand (Command(DeleteSelection, m_cursor + i, m_text.at(m_cursor + i), -1, -1));
3003             addCommand(Command(Insert, m_cursor + i, ms.at(i), -1, -1));
3004         }
3005         m_text.replace(m_cursor, ms.length(), ms);
3006         m_cursor += ms.length();
3007         m_cursor = nextMaskBlank(m_cursor);
3008         m_textDirty = true;
3009     } else {
3010         int remaining = m_maxLength - m_text.length();
3011         if (remaining != 0) {
3012             m_text.insert(m_cursor, s.left(remaining));
3013             for (int i = 0; i < (int) s.left(remaining).length(); ++i)
3014                addCommand(Command(Insert, m_cursor++, s.at(i), -1, -1));
3015             m_textDirty = true;
3016         }
3017     }
3018 }
3019
3020 /*!
3021     \internal
3022
3023     deletes a single character from the current text.  If \a wasBackspace,
3024     the character prior to the cursor is removed.  Otherwise the character
3025     after the cursor is removed.
3026
3027     Also adds the appropriate commands into the undo history.
3028     This function does not call finishChange(), and may leave the text
3029     in an invalid state.
3030 */
3031 void QQuickTextInputPrivate::internalDelete(bool wasBackspace)
3032 {
3033     if (m_cursor < (int) m_text.length()) {
3034         cancelPasswordEchoTimer();
3035         if (hasSelectedText())
3036             addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
3037         addCommand(Command((CommandType)((m_maskData ? 2 : 0) + (wasBackspace ? Remove : Delete)),
3038                    m_cursor, m_text.at(m_cursor), -1, -1));
3039         if (m_maskData) {
3040             m_text.replace(m_cursor, 1, clearString(m_cursor, 1));
3041             addCommand(Command(Insert, m_cursor, m_text.at(m_cursor), -1, -1));
3042         } else {
3043             m_text.remove(m_cursor, 1);
3044         }
3045         m_textDirty = true;
3046     }
3047 }
3048
3049 /*!
3050     \internal
3051
3052     removes the currently selected text from the line control.
3053
3054     Also adds the appropriate commands into the undo history.
3055     This function does not call finishChange(), and may leave the text
3056     in an invalid state.
3057 */
3058 void QQuickTextInputPrivate::removeSelectedText()
3059 {
3060     if (m_selstart < m_selend && m_selend <= (int) m_text.length()) {
3061         cancelPasswordEchoTimer();
3062         separate();
3063         int i ;
3064         addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
3065         if (m_selstart <= m_cursor && m_cursor < m_selend) {
3066             // cursor is within the selection. Split up the commands
3067             // to be able to restore the correct cursor position
3068             for (i = m_cursor; i >= m_selstart; --i)
3069                 addCommand (Command(DeleteSelection, i, m_text.at(i), -1, 1));
3070             for (i = m_selend - 1; i > m_cursor; --i)
3071                 addCommand (Command(DeleteSelection, i - m_cursor + m_selstart - 1, m_text.at(i), -1, -1));
3072         } else {
3073             for (i = m_selend-1; i >= m_selstart; --i)
3074                 addCommand (Command(RemoveSelection, i, m_text.at(i), -1, -1));
3075         }
3076         if (m_maskData) {
3077             m_text.replace(m_selstart, m_selend - m_selstart,  clearString(m_selstart, m_selend - m_selstart));
3078             for (int i = 0; i < m_selend - m_selstart; ++i)
3079                 addCommand(Command(Insert, m_selstart + i, m_text.at(m_selstart + i), -1, -1));
3080         } else {
3081             m_text.remove(m_selstart, m_selend - m_selstart);
3082         }
3083         if (m_cursor > m_selstart)
3084             m_cursor -= qMin(m_cursor, m_selend) - m_selstart;
3085         internalDeselect();
3086         m_textDirty = true;
3087     }
3088 }
3089
3090 /*!
3091     \internal
3092
3093     Parses the input mask specified by \a maskFields to generate
3094     the mask data used to handle input masks.
3095 */
3096 void QQuickTextInputPrivate::parseInputMask(const QString &maskFields)
3097 {
3098     int delimiter = maskFields.indexOf(QLatin1Char(';'));
3099     if (maskFields.isEmpty() || delimiter == 0) {
3100         if (m_maskData) {
3101             delete [] m_maskData;
3102             m_maskData = 0;
3103             m_maxLength = 32767;
3104             internalSetText(QString());
3105         }
3106         return;
3107     }
3108
3109     if (delimiter == -1) {
3110         m_blank = QLatin1Char(' ');
3111         m_inputMask = maskFields;
3112     } else {
3113         m_inputMask = maskFields.left(delimiter);
3114         m_blank = (delimiter + 1 < maskFields.length()) ? maskFields[delimiter + 1] : QLatin1Char(' ');
3115     }
3116
3117     // calculate m_maxLength / m_maskData length
3118     m_maxLength = 0;
3119     QChar c = 0;
3120     for (int i=0; i<m_inputMask.length(); i++) {
3121         c = m_inputMask.at(i);
3122         if (i > 0 && m_inputMask.at(i-1) == QLatin1Char('\\')) {
3123             m_maxLength++;
3124             continue;
3125         }
3126         if (c != QLatin1Char('\\') && c != QLatin1Char('!') &&
3127              c != QLatin1Char('<') && c != QLatin1Char('>') &&
3128              c != QLatin1Char('{') && c != QLatin1Char('}') &&
3129              c != QLatin1Char('[') && c != QLatin1Char(']'))
3130             m_maxLength++;
3131     }
3132
3133     delete [] m_maskData;
3134     m_maskData = new MaskInputData[m_maxLength];
3135
3136     MaskInputData::Casemode m = MaskInputData::NoCaseMode;
3137     c = 0;
3138     bool s;
3139     bool escape = false;
3140     int index = 0;
3141     for (int i = 0; i < m_inputMask.length(); i++) {
3142         c = m_inputMask.at(i);
3143         if (escape) {
3144             s = true;
3145             m_maskData[index].maskChar = c;
3146             m_maskData[index].separator = s;
3147             m_maskData[index].caseMode = m;
3148             index++;
3149             escape = false;
3150         } else if (c == QLatin1Char('<')) {
3151                 m = MaskInputData::Lower;
3152         } else if (c == QLatin1Char('>')) {
3153             m = MaskInputData::Upper;
3154         } else if (c == QLatin1Char('!')) {
3155             m = MaskInputData::NoCaseMode;
3156         } else if (c != QLatin1Char('{') && c != QLatin1Char('}') && c != QLatin1Char('[') && c != QLatin1Char(']')) {
3157             switch (c.unicode()) {
3158             case 'A':
3159             case 'a':
3160             case 'N':
3161             case 'n':
3162             case 'X':
3163             case 'x':
3164             case '9':
3165             case '0':
3166             case 'D':
3167             case 'd':
3168             case '#':
3169             case 'H':
3170             case 'h':
3171             case 'B':
3172             case 'b':
3173                 s = false;
3174                 break;
3175             case '\\':
3176                 escape = true;
3177             default:
3178                 s = true;
3179                 break;
3180             }
3181
3182             if (!escape) {
3183                 m_maskData[index].maskChar = c;
3184                 m_maskData[index].separator = s;
3185                 m_maskData[index].caseMode = m;
3186                 index++;
3187             }
3188         }
3189     }
3190     internalSetText(m_text);
3191 }
3192
3193
3194 /*!
3195     \internal
3196
3197     checks if the key is valid compared to the inputMask
3198 */
3199 bool QQuickTextInputPrivate::isValidInput(QChar key, QChar mask) const
3200 {
3201     switch (mask.unicode()) {
3202     case 'A':
3203         if (key.isLetter())
3204             return true;
3205         break;
3206     case 'a':
3207         if (key.isLetter() || key == m_blank)
3208             return true;
3209         break;
3210     case 'N':
3211         if (key.isLetterOrNumber())
3212             return true;
3213         break;
3214     case 'n':
3215         if (key.isLetterOrNumber() || key == m_blank)
3216             return true;
3217         break;
3218     case 'X':
3219         if (key.isPrint())
3220             return true;
3221         break;
3222     case 'x':
3223         if (key.isPrint() || key == m_blank)
3224             return true;
3225         break;
3226     case '9':
3227         if (key.isNumber())
3228             return true;
3229         break;
3230     case '0':
3231         if (key.isNumber() || key == m_blank)
3232             return true;
3233         break;
3234     case 'D':
3235         if (key.isNumber() && key.digitValue() > 0)
3236             return true;
3237         break;
3238     case 'd':
3239         if ((key.isNumber() && key.digitValue() > 0) || key == m_blank)
3240             return true;
3241         break;
3242     case '#':
3243         if (key.isNumber() || key == QLatin1Char('+') || key == QLatin1Char('-') || key == m_blank)
3244             return true;
3245         break;
3246     case 'B':
3247         if (key == QLatin1Char('0') || key == QLatin1Char('1'))
3248             return true;
3249         break;
3250     case 'b':
3251         if (key == QLatin1Char('0') || key == QLatin1Char('1') || key == m_blank)
3252             return true;
3253         break;
3254     case 'H':
3255         if (key.isNumber() || (key >= QLatin1Char('a') && key <= QLatin1Char('f')) || (key >= QLatin1Char('A') && key <= QLatin1Char('F')))
3256             return true;
3257         break;
3258     case 'h':
3259         if (key.isNumber() || (key >= QLatin1Char('a') && key <= QLatin1Char('f')) || (key >= QLatin1Char('A') && key <= QLatin1Char('F')) || key == m_blank)
3260             return true;
3261         break;
3262     default:
3263         break;
3264     }
3265     return false;
3266 }
3267
3268 /*!
3269     \internal
3270
3271     Returns true if the given text \a str is valid for any
3272     validator or input mask set for the line control.
3273
3274     Otherwise returns false
3275 */
3276 bool QQuickTextInputPrivate::hasAcceptableInput(const QString &str) const
3277 {
3278 #ifndef QT_NO_VALIDATOR
3279     QString textCopy = str;
3280     int cursorCopy = m_cursor;
3281     if (m_validator && m_validator->validate(textCopy, cursorCopy)
3282         != QValidator::Acceptable)
3283         return false;
3284 #endif
3285
3286     if (!m_maskData)
3287         return true;
3288
3289     if (str.length() != m_maxLength)
3290         return false;
3291
3292     for (int i=0; i < m_maxLength; ++i) {
3293         if (m_maskData[i].separator) {
3294             if (str.at(i) != m_maskData[i].maskChar)
3295                 return false;
3296         } else {
3297             if (!isValidInput(str.at(i), m_maskData[i].maskChar))
3298                 return false;
3299         }
3300     }
3301     return true;
3302 }
3303
3304 /*!
3305     \internal
3306
3307     Applies the inputMask on \a str starting from position \a pos in the mask. \a clear
3308     specifies from where characters should be gotten when a separator is met in \a str - true means
3309     that blanks will be used, false that previous input is used.
3310     Calling this when no inputMask is set is undefined.
3311 */
3312 QString QQuickTextInputPrivate::maskString(uint pos, const QString &str, bool clear) const
3313 {
3314     if (pos >= (uint)m_maxLength)
3315         return QString::fromLatin1("");
3316
3317     QString fill;
3318     fill = clear ? clearString(0, m_maxLength) : m_text;
3319
3320     int strIndex = 0;
3321     QString s = QString::fromLatin1("");
3322     int i = pos;
3323     while (i < m_maxLength) {
3324         if (strIndex < str.length()) {
3325             if (m_maskData[i].separator) {
3326                 s += m_maskData[i].maskChar;
3327                 if (str[(int)strIndex] == m_maskData[i].maskChar)
3328                     strIndex++;
3329                 ++i;
3330             } else {
3331                 if (isValidInput(str[(int)strIndex], m_maskData[i].maskChar)) {
3332                     switch (m_maskData[i].caseMode) {
3333                     case MaskInputData::Upper:
3334                         s += str[(int)strIndex].toUpper();
3335                         break;
3336                     case MaskInputData::Lower:
3337                         s += str[(int)strIndex].toLower();
3338                         break;
3339                     default:
3340                         s += str[(int)strIndex];
3341                     }
3342                     ++i;
3343                 } else {
3344                     // search for separator first
3345                     int n = findInMask(i, true, true, str[(int)strIndex]);
3346                     if (n != -1) {
3347                         if (str.length() != 1 || i == 0 || (i > 0 && (!m_maskData[i-1].separator || m_maskData[i-1].maskChar != str[(int)strIndex]))) {
3348                             s += fill.mid(i, n-i+1);
3349                             i = n + 1; // update i to find + 1
3350                         }
3351                     } else {
3352                         // search for valid m_blank if not
3353                         n = findInMask(i, true, false, str[(int)strIndex]);
3354                         if (n != -1) {
3355                             s += fill.mid(i, n-i);
3356                             switch (m_maskData[n].caseMode) {
3357                             case MaskInputData::Upper:
3358                                 s += str[(int)strIndex].toUpper();
3359                                 break;
3360                             case MaskInputData::Lower:
3361                                 s += str[(int)strIndex].toLower();
3362                                 break;
3363                             default:
3364                                 s += str[(int)strIndex];
3365                             }
3366                             i = n + 1; // updates i to find + 1
3367                         }
3368                     }
3369                 }
3370                 ++strIndex;
3371             }
3372         } else
3373             break;
3374     }
3375
3376     return s;
3377 }
3378
3379
3380
3381 /*!
3382     \internal
3383
3384     Returns a "cleared" string with only separators and blank chars.
3385     Calling this when no inputMask is set is undefined.
3386 */
3387 QString QQuickTextInputPrivate::clearString(uint pos, uint len) const
3388 {
3389     if (pos >= (uint)m_maxLength)
3390         return QString();
3391
3392     QString s;
3393     int end = qMin((uint)m_maxLength, pos + len);
3394     for (int i = pos; i < end; ++i)
3395         if (m_maskData[i].separator)
3396             s += m_maskData[i].maskChar;
3397         else
3398             s += m_blank;
3399
3400     return s;
3401 }
3402
3403 /*!
3404     \internal
3405
3406     Strips blank parts of the input in a QQuickTextInputPrivate when an inputMask is set,
3407     separators are still included. Typically "127.0__.0__.1__" becomes "127.0.0.1".
3408 */
3409 QString QQuickTextInputPrivate::stripString(const QString &str) const
3410 {
3411     if (!m_maskData)
3412         return str;
3413
3414     QString s;
3415     int end = qMin(m_maxLength, (int)str.length());
3416     for (int i = 0; i < end; ++i) {
3417         if (m_maskData[i].separator)
3418             s += m_maskData[i].maskChar;
3419         else if (str[i] != m_blank)
3420             s += str[i];
3421     }
3422
3423     return s;
3424 }
3425
3426 /*!
3427     \internal
3428     searches forward/backward in m_maskData for either a separator or a m_blank
3429 */
3430 int QQuickTextInputPrivate::findInMask(int pos, bool forward, bool findSeparator, QChar searchChar) const
3431 {
3432     if (pos >= m_maxLength || pos < 0)
3433         return -1;
3434
3435     int end = forward ? m_maxLength : -1;
3436     int step = forward ? 1 : -1;
3437     int i = pos;
3438
3439     while (i != end) {
3440         if (findSeparator) {
3441             if (m_maskData[i].separator && m_maskData[i].maskChar == searchChar)
3442                 return i;
3443         } else {
3444             if (!m_maskData[i].separator) {
3445                 if (searchChar.isNull())
3446                     return i;
3447                 else if (isValidInput(searchChar, m_maskData[i].maskChar))
3448                     return i;
3449             }
3450         }
3451         i += step;
3452     }
3453     return -1;
3454 }
3455
3456 void QQuickTextInputPrivate::internalUndo(int until)
3457 {
3458     if (!isUndoAvailable())
3459         return;
3460     cancelPasswordEchoTimer();
3461     internalDeselect();
3462     while (m_undoState && m_undoState > until) {
3463         Command& cmd = m_history[--m_undoState];
3464         switch (cmd.type) {
3465         case Insert:
3466             m_text.remove(cmd.pos, 1);
3467             m_cursor = cmd.pos;
3468             break;
3469         case SetSelection:
3470             m_selstart = cmd.selStart;
3471             m_selend = cmd.selEnd;
3472             m_cursor = cmd.pos;
3473             break;
3474         case Remove:
3475         case RemoveSelection:
3476             m_text.insert(cmd.pos, cmd.uc);
3477             m_cursor = cmd.pos + 1;
3478             break;
3479         case Delete:
3480         case DeleteSelection:
3481             m_text.insert(cmd.pos, cmd.uc);
3482             m_cursor = cmd.pos;
3483             break;
3484         case Separator:
3485             continue;
3486         }
3487         if (until < 0 && m_undoState) {
3488             Command& next = m_history[m_undoState-1];
3489             if (next.type != cmd.type && next.type < RemoveSelection
3490                  && (cmd.type < RemoveSelection || next.type == Separator))
3491                 break;
3492         }
3493     }
3494     m_textDirty = true;
3495     emitCursorPositionChanged();
3496 }
3497
3498 void QQuickTextInputPrivate::internalRedo()
3499 {
3500     if (!isRedoAvailable())
3501         return;
3502     internalDeselect();
3503     while (m_undoState < (int)m_history.size()) {
3504         Command& cmd = m_history[m_undoState++];
3505         switch (cmd.type) {
3506         case Insert:
3507             m_text.insert(cmd.pos, cmd.uc);
3508             m_cursor = cmd.pos + 1;
3509             break;
3510         case SetSelection:
3511             m_selstart = cmd.selStart;
3512             m_selend = cmd.selEnd;
3513             m_cursor = cmd.pos;
3514             break;
3515         case Remove:
3516         case Delete:
3517         case RemoveSelection:
3518         case DeleteSelection:
3519             m_text.remove(cmd.pos, 1);
3520             m_selstart = cmd.selStart;
3521             m_selend = cmd.selEnd;
3522             m_cursor = cmd.pos;
3523             break;
3524         case Separator:
3525             m_selstart = cmd.selStart;
3526             m_selend = cmd.selEnd;
3527             m_cursor = cmd.pos;
3528             break;
3529         }
3530         if (m_undoState < (int)m_history.size()) {
3531             Command& next = m_history[m_undoState];
3532             if (next.type != cmd.type && cmd.type < RemoveSelection && next.type != Separator
3533                  && (next.type < RemoveSelection || cmd.type == Separator))
3534                 break;
3535         }
3536     }
3537     m_textDirty = true;
3538     emitCursorPositionChanged();
3539 }
3540
3541 /*!
3542     \internal
3543
3544     If the current cursor position differs from the last emitted cursor
3545     position, emits cursorPositionChanged().
3546 */
3547 void QQuickTextInputPrivate::emitCursorPositionChanged()
3548 {
3549     Q_Q(QQuickTextInput);
3550     if (m_cursor != m_lastCursorPos) {
3551         m_lastCursorPos = m_cursor;
3552
3553         q->updateCursorRectangle();
3554         emit q->cursorPositionChanged();
3555         // XXX todo - not in 4.8?
3556     #if 0
3557         resetCursorBlinkTimer();
3558     #endif
3559
3560         if (!hasSelectedText()) {
3561             if (lastSelectionStart != m_cursor) {
3562                 lastSelectionStart = m_cursor;
3563                 emit q->selectionStartChanged();
3564             }
3565             if (lastSelectionEnd != m_cursor) {
3566                 lastSelectionEnd = m_cursor;
3567                 emit q->selectionEndChanged();
3568             }
3569         }
3570
3571 #ifndef QT_NO_ACCESSIBILITY
3572         QAccessible::updateAccessibility(q, 0, QAccessible::TextCaretMoved);
3573 #endif
3574     }
3575 }
3576
3577
3578 void QQuickTextInputPrivate::setCursorBlinkPeriod(int msec)
3579 {
3580     Q_Q(QQuickTextInput);
3581     if (msec == m_blinkPeriod)
3582         return;
3583     if (m_blinkTimer) {
3584         q->killTimer(m_blinkTimer);
3585     }
3586     if (msec) {
3587         m_blinkTimer = q->startTimer(msec / 2);
3588         m_blinkStatus = 1;
3589     } else {
3590         m_blinkTimer = 0;
3591         if (m_blinkStatus == 1)
3592             q->update();
3593     }
3594     m_blinkPeriod = msec;
3595 }
3596
3597 void QQuickTextInputPrivate::resetCursorBlinkTimer()
3598 {
3599     Q_Q(QQuickTextInput);
3600     if (m_blinkPeriod == 0 || m_blinkTimer == 0)
3601         return;
3602     q->killTimer(m_blinkTimer);
3603     m_blinkTimer = q->startTimer(m_blinkPeriod / 2);
3604     m_blinkStatus = 1;
3605 }
3606
3607 void QQuickTextInput::timerEvent(QTimerEvent *event)
3608 {
3609     Q_D(QQuickTextInput);
3610     if (event->timerId() == d->m_blinkTimer) {
3611         d->m_blinkStatus = !d->m_blinkStatus;
3612         update();
3613     } else if (event->timerId() == d->m_deleteAllTimer) {
3614         killTimer(d->m_deleteAllTimer);
3615         d->m_deleteAllTimer = 0;
3616         d->clear();
3617 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
3618     } else if (event->timerId() == d->m_passwordEchoTimer.timerId()) {
3619         d->m_passwordEchoTimer.stop();
3620         d->updateDisplayText();
3621 #endif
3622     }
3623 }
3624
3625 void QQuickTextInputPrivate::processKeyEvent(QKeyEvent* event)
3626 {
3627     Q_Q(QQuickTextInput);
3628     bool inlineCompletionAccepted = false;
3629
3630     if (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return) {
3631         if (hasAcceptableInput(m_text) || fixup()) {
3632             emit q->accepted();
3633         }
3634         if (inlineCompletionAccepted)
3635             event->accept();
3636         else
3637             event->ignore();
3638         return;
3639     }
3640
3641     if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit
3642         && !m_passwordEchoEditing
3643         && !m_readOnly
3644         && !event->text().isEmpty()
3645         && !(event->modifiers() & Qt::ControlModifier)) {
3646         // Clear the edit and reset to normal echo mode while editing; the
3647         // echo mode switches back when the edit loses focus
3648         // ### resets current content.  dubious code; you can
3649         // navigate with keys up, down, back, and select(?), but if you press
3650         // "left" or "right" it clears?
3651         updatePasswordEchoEditing(true);
3652         clear();
3653     }
3654
3655     bool unknown = false;
3656     bool visual = cursorMoveStyle() == Qt::VisualMoveStyle;
3657
3658     if (false) {
3659     }
3660 #ifndef QT_NO_SHORTCUT
3661     else if (event == QKeySequence::Undo) {
3662         if (!m_readOnly)
3663             undo();
3664     }
3665     else if (event == QKeySequence::Redo) {
3666         if (!m_readOnly)
3667             redo();
3668     }
3669     else if (event == QKeySequence::SelectAll) {
3670         selectAll();
3671     }
3672 #ifndef QT_NO_CLIPBOARD
3673     else if (event == QKeySequence::Copy) {
3674         copy();
3675     }
3676     else if (event == QKeySequence::Paste) {
3677         if (!m_readOnly) {
3678             QClipboard::Mode mode = QClipboard::Clipboard;
3679             paste(mode);
3680         }
3681     }
3682     else if (event == QKeySequence::Cut) {
3683         if (!m_readOnly) {
3684             copy();
3685             del();
3686         }
3687     }
3688     else if (event == QKeySequence::DeleteEndOfLine) {
3689         if (!m_readOnly) {
3690             setSelection(m_cursor, end());
3691             copy();
3692             del();
3693         }
3694     }
3695 #endif //QT_NO_CLIPBOARD
3696     else if (event == QKeySequence::MoveToStartOfLine || event == QKeySequence::MoveToStartOfBlock) {
3697         home(0);
3698     }
3699     else if (event == QKeySequence::MoveToEndOfLine || event == QKeySequence::MoveToEndOfBlock) {
3700         end(0);
3701     }
3702     else if (event == QKeySequence::SelectStartOfLine || event == QKeySequence::SelectStartOfBlock) {
3703         home(1);
3704     }
3705     else if (event == QKeySequence::SelectEndOfLine || event == QKeySequence::SelectEndOfBlock) {
3706         end(1);
3707     }
3708     else if (event == QKeySequence::MoveToNextChar) {
3709         if (hasSelectedText()) {
3710             moveCursor(selectionEnd(), false);
3711         } else {
3712             cursorForward(0, visual ? 1 : (layoutDirection() == Qt::LeftToRight ? 1 : -1));
3713         }
3714     }
3715     else if (event == QKeySequence::SelectNextChar) {
3716         cursorForward(1, visual ? 1 : (layoutDirection() == Qt::LeftToRight ? 1 : -1));
3717     }
3718     else if (event == QKeySequence::MoveToPreviousChar) {
3719         if (hasSelectedText()) {
3720             moveCursor(selectionStart(), false);
3721         } else {
3722             cursorForward(0, visual ? -1 : (layoutDirection() == Qt::LeftToRight ? -1 : 1));
3723         }
3724     }
3725     else if (event == QKeySequence::SelectPreviousChar) {
3726         cursorForward(1, visual ? -1 : (layoutDirection() == Qt::LeftToRight ? -1 : 1));
3727     }
3728     else if (event == QKeySequence::MoveToNextWord) {
3729         if (m_echoMode == QQuickTextInput::Normal)
3730             layoutDirection() == Qt::LeftToRight ? cursorWordForward(0) : cursorWordBackward(0);
3731         else
3732             layoutDirection() == Qt::LeftToRight ? end(0) : home(0);
3733     }
3734     else if (event == QKeySequence::MoveToPreviousWord) {
3735         if (m_echoMode == QQuickTextInput::Normal)
3736             layoutDirection() == Qt::LeftToRight ? cursorWordBackward(0) : cursorWordForward(0);
3737         else if (!m_readOnly) {
3738             layoutDirection() == Qt::LeftToRight ? home(0) : end(0);
3739         }
3740     }
3741     else if (event == QKeySequence::SelectNextWord) {
3742         if (m_echoMode == QQuickTextInput::Normal)
3743             layoutDirection() == Qt::LeftToRight ? cursorWordForward(1) : cursorWordBackward(1);
3744         else
3745             layoutDirection() == Qt::LeftToRight ? end(1) : home(1);
3746     }
3747     else if (event == QKeySequence::SelectPreviousWord) {
3748         if (m_echoMode == QQuickTextInput::Normal)
3749             layoutDirection() == Qt::LeftToRight ? cursorWordBackward(1) : cursorWordForward(1);
3750         else
3751             layoutDirection() == Qt::LeftToRight ? home(1) : end(1);
3752     }
3753     else if (event == QKeySequence::Delete) {
3754         if (!m_readOnly)
3755             del();
3756     }
3757     else if (event == QKeySequence::DeleteEndOfWord) {
3758         if (!m_readOnly) {
3759             cursorWordForward(true);
3760             del();
3761         }
3762     }
3763     else if (event == QKeySequence::DeleteStartOfWord) {
3764         if (!m_readOnly) {
3765             cursorWordBackward(true);
3766             del();
3767         }
3768     }
3769 #endif // QT_NO_SHORTCUT
3770     else {
3771         bool handled = false;
3772         if (event->modifiers() & Qt::ControlModifier) {
3773             switch (event->key()) {
3774             case Qt::Key_Backspace:
3775                 if (!m_readOnly) {
3776                     cursorWordBackward(true);
3777                     del();
3778                 }
3779                 break;
3780             default:
3781                 if (!handled)
3782                     unknown = true;
3783             }
3784         } else { // ### check for *no* modifier
3785             switch (event->key()) {
3786             case Qt::Key_Backspace:
3787                 if (!m_readOnly) {
3788                     backspace();
3789                 }
3790                 break;
3791             default:
3792                 if (!handled)
3793                     unknown = true;
3794             }
3795         }
3796     }
3797
3798     if (event->key() == Qt::Key_Direction_L || event->key() == Qt::Key_Direction_R) {
3799         setLayoutDirection((event->key() == Qt::Key_Direction_L) ? Qt::LeftToRight : Qt::RightToLeft);
3800         unknown = false;
3801     }
3802
3803     if (unknown && !m_readOnly) {
3804         QString t = event->text();
3805         if (!t.isEmpty() && t.at(0).isPrint()) {
3806             insert(t);
3807             event->accept();
3808             return;
3809         }
3810     }
3811
3812     if (unknown)
3813         event->ignore();
3814     else
3815         event->accept();
3816 }
3817
3818
3819 QT_END_NAMESPACE
3820