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