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