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