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