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