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