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