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