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