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