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