Fix crash in TextInput.
[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     q_canPasteChanged();
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 | Qt::ImhSensitiveData);
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 = qMax(0, qFloor(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         Q_ASSERT(currentLine.isValid());
1423         int cix = qRound(currentLine.cursorToX(m_cursor + preeditLength));
1424         if (cix - hscroll >= width) {
1425             // text doesn't fit, cursor is to the right of br (scroll right)
1426             hscroll = cix - width;
1427         } else if (cix - hscroll < 0 && hscroll < widthUsed) {
1428             // text doesn't fit, cursor is to the left of br (scroll left)
1429             hscroll = cix;
1430         } else if (widthUsed - hscroll < width) {
1431             // text doesn't fit, text document is to the left of br; align
1432             // right
1433             hscroll = widthUsed - width;
1434         }
1435         if (preeditLength > 0) {
1436             // check to ensure long pre-edit text doesn't push the cursor
1437             // off to the left
1438              cix = qRound(currentLine.cursorToX(m_cursor + qMax(0, m_preeditCursor - 1)));
1439              if (cix < hscroll)
1440                  hscroll = cix;
1441         }
1442     }
1443     if (previousScroll != hscroll)
1444         textLayoutDirty = true;
1445 }
1446
1447 void QQuickTextInputPrivate::updateVerticalScroll()
1448 {
1449     Q_Q(QQuickTextInput);
1450     const int preeditLength = m_textLayout.preeditAreaText().length();
1451     const int height = qMax(0, qFloor(q->height()));
1452     int heightUsed = boundingRect.height();
1453     int previousScroll = vscroll;
1454
1455     if (!autoScroll || heightUsed <=  height) {
1456         // text fits in br; use vscroll for alignment
1457         switch (vAlign & ~(Qt::AlignAbsolute|Qt::AlignHorizontal_Mask)) {
1458         case Qt::AlignBottom:
1459             vscroll = heightUsed - height;
1460             break;
1461         case Qt::AlignVCenter:
1462             vscroll = (heightUsed - height) / 2;
1463             break;
1464         default:
1465             // Top
1466             vscroll = 0;
1467             break;
1468         }
1469     } else {
1470         QTextLine currentLine = m_textLayout.lineForTextPosition(m_cursor + preeditLength);
1471         QRectF r = currentLine.isValid() ? currentLine.rect() : QRectF();
1472         int top = qFloor(r.top());
1473         int bottom = qCeil(r.bottom());
1474
1475         if (bottom - vscroll >= height) {
1476             // text doesn't fit, cursor is to the below the br (scroll down)
1477             vscroll = bottom - height;
1478         } else if (top - vscroll < 0 && vscroll < heightUsed) {
1479             // text doesn't fit, cursor is above br (scroll up)
1480             vscroll = top;
1481         } else if (heightUsed - vscroll < height) {
1482             // text doesn't fit, text document is to the left of br; align
1483             // right
1484             vscroll = heightUsed - height;
1485         }
1486         if (preeditLength > 0) {
1487             // check to ensure long pre-edit text doesn't push the cursor
1488             // off the top
1489             currentLine = m_textLayout.lineForTextPosition(m_cursor + qMax(0, m_preeditCursor - 1));
1490             top = currentLine.isValid() ? qRound(currentLine.rect().top()) : 0;
1491             if (top < vscroll)
1492                 vscroll = top;
1493         }
1494     }
1495     if (previousScroll != vscroll)
1496         textLayoutDirty = true;
1497 }
1498
1499 QSGNode *QQuickTextInput::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data)
1500 {
1501     Q_UNUSED(data);
1502     Q_D(QQuickTextInput);
1503
1504     QQuickTextNode *node = static_cast<QQuickTextNode *>(oldNode);
1505     if (node == 0)
1506         node = new QQuickTextNode(QQuickItemPrivate::get(this)->sceneGraphContext());
1507     d->textNode = node;
1508
1509     if (!d->textLayoutDirty) {
1510         QSGSimpleRectNode *cursorNode = node->cursorNode();
1511         if (cursorNode != 0 && !isReadOnly()) {
1512             cursorNode->setRect(cursorRectangle());
1513
1514             if (!d->cursorVisible || (!d->m_blinkStatus && d->m_blinkPeriod > 0)) {
1515                 d->hideCursor();
1516             } else {
1517                 d->showCursor();
1518             }
1519         }
1520     } else {
1521         node->deleteContent();
1522         node->setMatrix(QMatrix4x4());
1523
1524         QPoint offset = QPoint(0,0);
1525         QFontMetrics fm = QFontMetrics(d->font);
1526         if (d->autoScroll) {
1527             // the y offset is there to keep the baseline constant in case we have script changes in the text.
1528             offset = -QPoint(d->hscroll, d->vscroll + d->m_ascent - fm.ascent());
1529         } else {
1530             offset = -QPoint(d->hscroll, d->vscroll);
1531         }
1532
1533         if (!d->m_textLayout.text().isEmpty()) {
1534             node->addTextLayout(offset, &d->m_textLayout, d->color,
1535                                 QQuickText::Normal, QColor(),
1536                                 d->selectionColor, d->selectedTextColor,
1537                                 d->selectionStart(),
1538                                 d->selectionEnd() - 1); // selectionEnd() returns first char after
1539                                                                  // selection
1540         }
1541
1542         if (!isReadOnly() && d->cursorItem == 0) {
1543             node->setCursor(cursorRectangle(), d->color);
1544             if (!d->cursorVisible || (!d->m_blinkStatus && d->m_blinkPeriod > 0)) {
1545                 d->hideCursor();
1546             } else {
1547                 d->showCursor();
1548             }
1549         }
1550
1551         d->textLayoutDirty = false;
1552     }
1553
1554     return node;
1555 }
1556
1557 QVariant QQuickTextInput::inputMethodQuery(Qt::InputMethodQuery property) const
1558 {
1559     Q_D(const QQuickTextInput);
1560     switch (property) {
1561     case Qt::ImEnabled:
1562         return QVariant((bool)(flags() & ItemAcceptsInputMethod));
1563     case Qt::ImHints:
1564         return QVariant((int)inputMethodHints());
1565     case Qt::ImCursorRectangle:
1566         return cursorRectangle();
1567     case Qt::ImFont:
1568         return font();
1569     case Qt::ImCursorPosition:
1570         return QVariant(d->m_cursor);
1571     case Qt::ImSurroundingText:
1572         if (d->m_echoMode == PasswordEchoOnEdit && !d->m_passwordEchoEditing) {
1573             return QVariant(displayText());
1574         } else {
1575             return QVariant(d->realText());
1576         }
1577     case Qt::ImCurrentSelection:
1578         return QVariant(selectedText());
1579     case Qt::ImMaximumTextLength:
1580         return QVariant(maxLength());
1581     case Qt::ImAnchorPosition:
1582         if (d->selectionStart() == d->selectionEnd())
1583             return QVariant(d->m_cursor);
1584         else if (d->selectionStart() == d->m_cursor)
1585             return QVariant(d->selectionEnd());
1586         else
1587             return QVariant(d->selectionStart());
1588     default:
1589         return QVariant();
1590     }
1591 }
1592
1593 /*!
1594     \qmlmethod void QtQuick2::TextInput::deselect()
1595
1596     Removes active text selection.
1597 */
1598 void QQuickTextInput::deselect()
1599 {
1600     Q_D(QQuickTextInput);
1601     d->deselect();
1602 }
1603
1604 /*!
1605     \qmlmethod void QtQuick2::TextInput::selectAll()
1606
1607     Causes all text to be selected.
1608 */
1609 void QQuickTextInput::selectAll()
1610 {
1611     Q_D(QQuickTextInput);
1612     d->setSelection(0, text().length());
1613 }
1614
1615 /*!
1616     \qmlmethod void QtQuick2::TextInput::isRightToLeft(int start, int end)
1617
1618     Returns true if the natural reading direction of the editor text
1619     found between positions \a start and \a end is right to left.
1620 */
1621 bool QQuickTextInput::isRightToLeft(int start, int end)
1622 {
1623     if (start > end) {
1624         qmlInfo(this) << "isRightToLeft(start, end) called with the end property being smaller than the start.";
1625         return false;
1626     } else {
1627         return text().mid(start, end - start).isRightToLeft();
1628     }
1629 }
1630
1631 #ifndef QT_NO_CLIPBOARD
1632 /*!
1633     \qmlmethod QtQuick2::TextInput::cut()
1634
1635     Moves the currently selected text to the system clipboard.
1636 */
1637 void QQuickTextInput::cut()
1638 {
1639     Q_D(QQuickTextInput);
1640     d->copy();
1641     d->del();
1642 }
1643
1644 /*!
1645     \qmlmethod QtQuick2::TextInput::copy()
1646
1647     Copies the currently selected text to the system clipboard.
1648 */
1649 void QQuickTextInput::copy()
1650 {
1651     Q_D(QQuickTextInput);
1652     d->copy();
1653 }
1654
1655 /*!
1656     \qmlmethod QtQuick2::TextInput::paste()
1657
1658     Replaces the currently selected text by the contents of the system clipboard.
1659 */
1660 void QQuickTextInput::paste()
1661 {
1662     Q_D(QQuickTextInput);
1663     if (!d->m_readOnly)
1664         d->paste();
1665 }
1666 #endif // QT_NO_CLIPBOARD
1667
1668 /*!
1669     \qmlmethod void QtQuick2::TextInput::selectWord()
1670
1671     Causes the word closest to the current cursor position to be selected.
1672 */
1673 void QQuickTextInput::selectWord()
1674 {
1675     Q_D(QQuickTextInput);
1676     d->selectWordAtPos(d->m_cursor);
1677 }
1678
1679 /*!
1680     \qmlproperty bool QtQuick2::TextInput::smooth
1681
1682     This property holds whether the text is smoothly scaled or transformed.
1683
1684     Smooth filtering gives better visual quality, but is slower.  If
1685     the item is displayed at its natural size, this property has no visual or
1686     performance effect.
1687
1688     \note Generally scaling artifacts are only visible if the item is stationary on
1689     the screen.  A common pattern when animating an item is to disable smooth
1690     filtering at the beginning of the animation and reenable it at the conclusion.
1691 */
1692
1693 /*!
1694    \qmlproperty string QtQuick2::TextInput::passwordCharacter
1695
1696    This is the character displayed when echoMode is set to Password or
1697    PasswordEchoOnEdit. By default it is an asterisk.
1698
1699    If this property is set to a string with more than one character,
1700    the first character is used. If the string is empty, the value
1701    is ignored and the property is not set.
1702 */
1703 QString QQuickTextInput::passwordCharacter() const
1704 {
1705     Q_D(const QQuickTextInput);
1706     return QString(d->m_passwordCharacter);
1707 }
1708
1709 void QQuickTextInput::setPasswordCharacter(const QString &str)
1710 {
1711     Q_D(QQuickTextInput);
1712     if (str.length() < 1)
1713         return;
1714     d->m_passwordCharacter = str.constData()[0];
1715     if (d->m_echoMode == Password || d->m_echoMode == PasswordEchoOnEdit)
1716         d->updateDisplayText();
1717     emit passwordCharacterChanged();
1718 }
1719
1720 /*!
1721    \qmlproperty string QtQuick2::TextInput::displayText
1722
1723    This is the text displayed in the TextInput.
1724
1725    If \l echoMode is set to TextInput::Normal, this holds the
1726    same value as the TextInput::text property. Otherwise,
1727    this property holds the text visible to the user, while
1728    the \l text property holds the actual entered text.
1729 */
1730 QString QQuickTextInput::displayText() const
1731 {
1732     Q_D(const QQuickTextInput);
1733     return d->m_textLayout.text();
1734 }
1735
1736 /*!
1737     \qmlproperty bool QtQuick2::TextInput::selectByMouse
1738
1739     Defaults to false.
1740
1741     If true, the user can use the mouse to select text in some
1742     platform-specific way. Note that for some platforms this may
1743     not be an appropriate interaction (eg. may conflict with how
1744     the text needs to behave inside a Flickable.
1745 */
1746 bool QQuickTextInput::selectByMouse() const
1747 {
1748     Q_D(const QQuickTextInput);
1749     return d->selectByMouse;
1750 }
1751
1752 void QQuickTextInput::setSelectByMouse(bool on)
1753 {
1754     Q_D(QQuickTextInput);
1755     if (d->selectByMouse != on) {
1756         d->selectByMouse = on;
1757         emit selectByMouseChanged(on);
1758     }
1759 }
1760
1761 /*!
1762     \qmlproperty enum QtQuick2::TextInput::mouseSelectionMode
1763
1764     Specifies how text should be selected using a mouse.
1765
1766     \list
1767     \o TextInput.SelectCharacters - The selection is updated with individual characters. (Default)
1768     \o TextInput.SelectWords - The selection is updated with whole words.
1769     \endlist
1770
1771     This property only applies when \l selectByMouse is true.
1772 */
1773
1774 QQuickTextInput::SelectionMode QQuickTextInput::mouseSelectionMode() const
1775 {
1776     Q_D(const QQuickTextInput);
1777     return d->mouseSelectionMode;
1778 }
1779
1780 void QQuickTextInput::setMouseSelectionMode(SelectionMode mode)
1781 {
1782     Q_D(QQuickTextInput);
1783     if (d->mouseSelectionMode != mode) {
1784         d->mouseSelectionMode = mode;
1785         emit mouseSelectionModeChanged(mode);
1786     }
1787 }
1788
1789 /*!
1790     \qmlproperty bool QtQuick2::TextInput::canPaste
1791
1792     Returns true if the TextInput is writable and the content of the clipboard is
1793     suitable for pasting into the TextEdit.
1794 */
1795 bool QQuickTextInput::canPaste() const
1796 {
1797     Q_D(const QQuickTextInput);
1798     if (!d->canPasteValid) {
1799         if (const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData())
1800             const_cast<QQuickTextInputPrivate *>(d)->canPaste = !d->m_readOnly && mimeData->hasText();
1801         const_cast<QQuickTextInputPrivate *>(d)->canPasteValid = true;
1802     }
1803     return d->canPaste;
1804 }
1805
1806 void QQuickTextInput::moveCursorSelection(int position)
1807 {
1808     Q_D(QQuickTextInput);
1809     d->moveCursor(position, true);
1810 }
1811
1812 /*!
1813     \qmlmethod void QtQuick2::TextInput::moveCursorSelection(int position, SelectionMode mode = TextInput.SelectCharacters)
1814
1815     Moves the cursor to \a position and updates the selection according to the optional \a mode
1816     parameter.  (To only move the cursor, set the \l cursorPosition property.)
1817
1818     When this method is called it additionally sets either the
1819     selectionStart or the selectionEnd (whichever was at the previous cursor position)
1820     to the specified position. This allows you to easily extend and contract the selected
1821     text range.
1822
1823     The selection mode specifies whether the selection is updated on a per character or a per word
1824     basis.  If not specified the selection mode will default to TextInput.SelectCharacters.
1825
1826     \list
1827     \o TextEdit.SelectCharacters - Sets either the selectionStart or selectionEnd (whichever was at
1828     the previous cursor position) to the specified position.
1829     \o TextEdit.SelectWords - Sets the selectionStart and selectionEnd to include all
1830     words between the specified position and the previous cursor position.  Words partially in the
1831     range are included.
1832     \endlist
1833
1834     For example, take this sequence of calls:
1835
1836     \code
1837         cursorPosition = 5
1838         moveCursorSelection(9, TextInput.SelectCharacters)
1839         moveCursorSelection(7, TextInput.SelectCharacters)
1840     \endcode
1841
1842     This moves the cursor to position 5, extend the selection end from 5 to 9
1843     and then retract the selection end from 9 to 7, leaving the text from position 5 to 7
1844     selected (the 6th and 7th characters).
1845
1846     The same sequence with TextInput.SelectWords will extend the selection start to a word boundary
1847     before or on position 5 and extend the selection end to a word boundary on or past position 9.
1848 */
1849 void QQuickTextInput::moveCursorSelection(int pos, SelectionMode mode)
1850 {
1851     Q_D(QQuickTextInput);
1852
1853     if (mode == SelectCharacters) {
1854         d->moveCursor(pos, true);
1855     } else if (pos != d->m_cursor){
1856         const int cursor = d->m_cursor;
1857         int anchor;
1858         if (!d->hasSelectedText())
1859             anchor = d->m_cursor;
1860         else if (d->selectionStart() == d->m_cursor)
1861             anchor = d->selectionEnd();
1862         else
1863             anchor = d->selectionStart();
1864
1865         if (anchor < pos || (anchor == pos && cursor < pos)) {
1866             const QString text = this->text();
1867             QTextBoundaryFinder finder(QTextBoundaryFinder::Word, text);
1868             finder.setPosition(anchor);
1869
1870             const QTextBoundaryFinder::BoundaryReasons reasons = finder.boundaryReasons();
1871             if (anchor < text.length() && (!(reasons & QTextBoundaryFinder::StartWord)
1872                     || ((reasons & QTextBoundaryFinder::EndWord) && anchor > cursor))) {
1873                 finder.toPreviousBoundary();
1874             }
1875             anchor = finder.position() != -1 ? finder.position() : 0;
1876
1877             finder.setPosition(pos);
1878             if (pos > 0 && !finder.boundaryReasons())
1879                 finder.toNextBoundary();
1880             const int cursor = finder.position() != -1 ? finder.position() : text.length();
1881
1882             d->setSelection(anchor, cursor - anchor);
1883         } else if (anchor > pos || (anchor == pos && cursor > pos)) {
1884             const QString text = this->text();
1885             QTextBoundaryFinder finder(QTextBoundaryFinder::Word, text);
1886             finder.setPosition(anchor);
1887
1888             const QTextBoundaryFinder::BoundaryReasons reasons = finder.boundaryReasons();
1889             if (anchor > 0 && (!(reasons & QTextBoundaryFinder::EndWord)
1890                     || ((reasons & QTextBoundaryFinder::StartWord) && anchor < cursor))) {
1891                 finder.toNextBoundary();
1892             }
1893
1894             anchor = finder.position() != -1 ? finder.position() : text.length();
1895
1896             finder.setPosition(pos);
1897             if (pos < text.length() && !finder.boundaryReasons())
1898                  finder.toPreviousBoundary();
1899             const int cursor = finder.position() != -1 ? finder.position() : 0;
1900
1901             d->setSelection(anchor, cursor - anchor);
1902         }
1903     }
1904 }
1905
1906 /*!
1907     \qmlmethod void QtQuick2::TextInput::openSoftwareInputPanel()
1908
1909     Opens software input panels like virtual keyboards for typing, useful for
1910     customizing when you want the input keyboard to be shown and hidden in
1911     your application.
1912
1913     By default the opening of input panels follows the platform style. Input panels are
1914     always closed if no editor has active focus.
1915
1916     You can disable the automatic behavior by setting the property \c activeFocusOnPress to false
1917     and use functions openSoftwareInputPanel() and closeSoftwareInputPanel() to implement
1918     the behavior you want.
1919
1920     Only relevant on platforms, which provide virtual keyboards.
1921
1922     \qml
1923         import QtQuick 1.0
1924         TextInput {
1925             id: textInput
1926             text: "Hello world!"
1927             activeFocusOnPress: false
1928             MouseArea {
1929                 anchors.fill: parent
1930                 onClicked: {
1931                     if (!textInput.activeFocus) {
1932                         textInput.forceActiveFocus()
1933                         textInput.openSoftwareInputPanel();
1934                     } else {
1935                         textInput.focus = false;
1936                     }
1937                 }
1938                 onPressAndHold: textInput.closeSoftwareInputPanel();
1939             }
1940         }
1941     \endqml
1942 */
1943 void QQuickTextInput::openSoftwareInputPanel()
1944 {
1945     if (qGuiApp)
1946         qGuiApp->inputPanel()->show();
1947 }
1948
1949 /*!
1950     \qmlmethod void QtQuick2::TextInput::closeSoftwareInputPanel()
1951
1952     Closes a software input panel like a virtual keyboard shown on the screen, useful
1953     for customizing when you want the input keyboard to be shown and hidden in
1954     your application.
1955
1956     By default the opening of input panels follows the platform style. Input panels are
1957     always closed if no editor has active focus.
1958
1959     You can disable the automatic behavior by setting the property \c activeFocusOnPress to false
1960     and use functions openSoftwareInputPanel() and closeSoftwareInputPanel() to implement
1961     the behavior you want.
1962
1963     Only relevant on platforms, which provide virtual keyboards.
1964
1965     \qml
1966         import QtQuick 1.0
1967         TextInput {
1968             id: textInput
1969             text: "Hello world!"
1970             activeFocusOnPress: false
1971             MouseArea {
1972                 anchors.fill: parent
1973                 onClicked: {
1974                     if (!textInput.activeFocus) {
1975                         textInput.forceActiveFocus();
1976                         textInput.openSoftwareInputPanel();
1977                     } else {
1978                         textInput.focus = false;
1979                     }
1980                 }
1981                 onPressAndHold: textInput.closeSoftwareInputPanel();
1982             }
1983         }
1984     \endqml
1985 */
1986 void QQuickTextInput::closeSoftwareInputPanel()
1987 {
1988     if (qGuiApp)
1989         qGuiApp->inputPanel()->hide();
1990 }
1991
1992 void QQuickTextInput::focusInEvent(QFocusEvent *event)
1993 {
1994     Q_D(const QQuickTextInput);
1995     if (d->focusOnPress && !d->m_readOnly)
1996         openSoftwareInputPanel();
1997     QQuickImplicitSizeItem::focusInEvent(event);
1998 }
1999
2000 void QQuickTextInput::itemChange(ItemChange change, const ItemChangeData &value)
2001 {
2002     Q_D(QQuickTextInput);
2003     if (change == ItemActiveFocusHasChanged) {
2004         bool hasFocus = value.boolValue;
2005         d->focused = hasFocus;
2006         setCursorVisible(hasFocus); // ### refactor:  && d->canvas && d->canvas->hasFocus()
2007 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
2008         if (!hasFocus && (d->m_passwordEchoEditing || d->m_passwordEchoTimer.isActive())) {
2009 #else
2010         if (!hasFocus && d->m_passwordEchoEditing) {
2011 #endif
2012             d->updatePasswordEchoEditing(false);//QQuickTextInputPrivate sets it on key events, but doesn't deal with focus events
2013         }
2014
2015         if (!hasFocus) {
2016             d->commitPreedit();
2017             d->deselect();
2018         }
2019     }
2020     QQuickItem::itemChange(change, value);
2021 }
2022
2023 /*!
2024     \qmlproperty bool QtQuick2::TextInput::inputMethodComposing
2025
2026
2027     This property holds whether the TextInput has partial text input from an
2028     input method.
2029
2030     While it is composing an input method may rely on mouse or key events from
2031     the TextInput to edit or commit the partial text.  This property can be
2032     used to determine when to disable events handlers that may interfere with
2033     the correct operation of an input method.
2034 */
2035 bool QQuickTextInput::isInputMethodComposing() const
2036 {
2037     Q_D(const QQuickTextInput);
2038     return d->preeditAreaText().length() > 0;
2039 }
2040
2041 void QQuickTextInputPrivate::init()
2042 {
2043     Q_Q(QQuickTextInput);
2044     q->setSmooth(smooth);
2045     q->setAcceptedMouseButtons(Qt::LeftButton);
2046     q->setFlag(QQuickItem::ItemAcceptsInputMethod);
2047     q->setFlag(QQuickItem::ItemHasContents);
2048 #ifndef QT_NO_CLIPBOARD
2049     q->connect(QGuiApplication::clipboard(), SIGNAL(dataChanged()),
2050             q, SLOT(q_canPasteChanged()));
2051 #endif // QT_NO_CLIPBOARD
2052
2053     oldValidity = hasAcceptableInput(m_text);
2054     lastSelectionStart = 0;
2055     lastSelectionEnd = 0;
2056     selectedTextColor = m_palette.color(QPalette::HighlightedText);
2057     selectionColor = m_palette.color(QPalette::Highlight);
2058     determineHorizontalAlignment();
2059
2060     if (!qmlDisableDistanceField()) {
2061         QTextOption option = m_textLayout.textOption();
2062         option.setUseDesignMetrics(true);
2063         m_textLayout.setTextOption(option);
2064     }
2065 }
2066
2067 void QQuickTextInput::updateCursorRectangle()
2068 {
2069     Q_D(QQuickTextInput);
2070     if (!isComponentComplete())
2071         return;
2072
2073     d->updateHorizontalScroll();
2074     d->updateVerticalScroll();
2075     update();
2076     updateMicroFocus();
2077     emit cursorRectangleChanged();
2078     if (d->cursorItem) {
2079         QRectF r = cursorRectangle();
2080         d->cursorItem->setPos(r.topLeft());
2081         d->cursorItem->setHeight(r.height());
2082     }
2083 }
2084
2085 void QQuickTextInput::selectionChanged()
2086 {
2087     Q_D(QQuickTextInput);
2088     d->textLayoutDirty = true; //TODO: Only update rect in selection
2089     update();
2090     emit selectedTextChanged();
2091
2092     if (d->lastSelectionStart != d->selectionStart()) {
2093         d->lastSelectionStart = d->selectionStart();
2094         if (d->lastSelectionStart == -1)
2095             d->lastSelectionStart = d->m_cursor;
2096         emit selectionStartChanged();
2097     }
2098     if (d->lastSelectionEnd != d->selectionEnd()) {
2099         d->lastSelectionEnd = d->selectionEnd();
2100         if (d->lastSelectionEnd == -1)
2101             d->lastSelectionEnd = d->m_cursor;
2102         emit selectionEndChanged();
2103     }
2104 }
2105
2106 void QQuickTextInputPrivate::showCursor()
2107 {
2108     if (textNode != 0 && textNode->cursorNode() != 0)
2109         textNode->cursorNode()->setColor(color);
2110 }
2111
2112 void QQuickTextInputPrivate::hideCursor()
2113 {
2114     if (textNode != 0 && textNode->cursorNode() != 0)
2115         textNode->cursorNode()->setColor(QColor(0, 0, 0, 0));
2116 }
2117
2118 QRectF QQuickTextInput::boundingRect() const
2119 {
2120     Q_D(const QQuickTextInput);
2121
2122     QRectF r = d->boundingRect;
2123     int cursorWidth = d->cursorItem ? d->cursorItem->width() : d->m_cursorWidth;
2124
2125     // Could include font max left/right bearings to either side of rectangle.
2126
2127     r.setRight(r.right() + cursorWidth);
2128     r.translate(-d->hscroll, -d->vscroll);
2129     return r;
2130 }
2131
2132 void QQuickTextInput::q_canPasteChanged()
2133 {
2134     Q_D(QQuickTextInput);
2135     bool old = d->canPaste;
2136 #ifndef QT_NO_CLIPBOARD
2137     if (const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData())
2138         d->canPaste = !d->m_readOnly && mimeData->hasText();
2139     else
2140         d->canPaste = false;
2141 #endif
2142
2143     bool changed = d->canPaste != old || !d->canPasteValid;
2144     d->canPasteValid = true;
2145     if (changed)
2146         emit canPasteChanged();
2147
2148 }
2149
2150 // ### these should come from QStyleHints
2151 const int textCursorWidth = 1;
2152 const bool fullWidthSelection = true;
2153
2154 /*!
2155     \internal
2156
2157     Updates the display text based of the current edit text
2158     If the text has changed will emit displayTextChanged()
2159 */
2160 void QQuickTextInputPrivate::updateDisplayText(bool forceUpdate)
2161 {
2162     QString orig = m_textLayout.text();
2163     QString str;
2164     if (m_echoMode == QQuickTextInput::NoEcho)
2165         str = QString::fromLatin1("");
2166     else
2167         str = m_text;
2168
2169     if (m_echoMode == QQuickTextInput::Password) {
2170          str.fill(m_passwordCharacter);
2171 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
2172         if (m_passwordEchoTimer.isActive() && m_cursor > 0 && m_cursor <= m_text.length()) {
2173             int cursor = m_cursor - 1;
2174             QChar uc = m_text.at(cursor);
2175             str[cursor] = uc;
2176             if (cursor > 0 && uc.unicode() >= 0xdc00 && uc.unicode() < 0xe000) {
2177                 // second half of a surrogate, check if we have the first half as well,
2178                 // if yes restore both at once
2179                 uc = m_text.at(cursor - 1);
2180                 if (uc.unicode() >= 0xd800 && uc.unicode() < 0xdc00)
2181                     str[cursor - 1] = uc;
2182             }
2183         }
2184 #endif
2185     } else if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit && !m_passwordEchoEditing) {
2186         str.fill(m_passwordCharacter);
2187     }
2188
2189     // replace certain non-printable characters with spaces (to avoid
2190     // drawing boxes when using fonts that don't have glyphs for such
2191     // characters)
2192     QChar* uc = str.data();
2193     for (int i = 0; i < (int)str.length(); ++i) {
2194         if ((uc[i] < 0x20 && uc[i] != 0x09)
2195             || uc[i] == QChar::LineSeparator
2196             || uc[i] == QChar::ParagraphSeparator
2197             || uc[i] == QChar::ObjectReplacementCharacter)
2198             uc[i] = QChar(0x0020);
2199     }
2200
2201     if (str != orig || forceUpdate) {
2202         m_textLayout.setText(str);
2203         updateLayout(); // polish?
2204         emit q_func()->displayTextChanged();
2205     }
2206 }
2207
2208 void QQuickTextInputPrivate::updateLayout()
2209 {
2210     Q_Q(QQuickTextInput);
2211
2212     if (!q->isComponentComplete())
2213         return;
2214
2215     QTextOption option = m_textLayout.textOption();
2216     option.setTextDirection(m_layoutDirection);
2217     option.setFlags(QTextOption::IncludeTrailingSpaces);
2218     option.setWrapMode(QTextOption::WrapMode(wrapMode));
2219     option.setAlignment(Qt::Alignment(q->effectiveHAlign()));
2220     m_textLayout.setTextOption(option);
2221     m_textLayout.setFont(font);
2222
2223     boundingRect = QRectF();
2224     m_textLayout.beginLayout();
2225     QTextLine line = m_textLayout.createLine();
2226     qreal lineWidth = q->widthValid() ? q->width() : INT_MAX;
2227     qreal height = 0;
2228     QTextLine firstLine = line;
2229     do {
2230         line.setLineWidth(lineWidth);
2231         line.setPosition(QPointF(line.position().x(), height));
2232         boundingRect = boundingRect.united(line.naturalTextRect());
2233
2234         height += line.height();
2235         line = m_textLayout.createLine();
2236     } while (line.isValid());
2237     m_textLayout.endLayout();
2238
2239     option.setWrapMode(QTextOption::NoWrap);
2240     m_textLayout.setTextOption(option);
2241
2242     m_ascent = qRound(firstLine.ascent());
2243     textLayoutDirty = true;
2244
2245     q->update();
2246     q->setImplicitSize(qCeil(boundingRect.width()), qCeil(boundingRect.height()));
2247
2248 }
2249
2250 #ifndef QT_NO_CLIPBOARD
2251 /*!
2252     \internal
2253
2254     Copies the currently selected text into the clipboard using the given
2255     \a mode.
2256
2257     \note If the echo mode is set to a mode other than Normal then copy
2258     will not work.  This is to prevent using copy as a method of bypassing
2259     password features of the line control.
2260 */
2261 void QQuickTextInputPrivate::copy(QClipboard::Mode mode) const
2262 {
2263     QString t = selectedText();
2264     if (!t.isEmpty() && m_echoMode == QQuickTextInput::Normal) {
2265         QGuiApplication::clipboard()->setText(t, mode);
2266     }
2267 }
2268
2269 /*!
2270     \internal
2271
2272     Inserts the text stored in the application clipboard into the line
2273     control.
2274
2275     \sa insert()
2276 */
2277 void QQuickTextInputPrivate::paste(QClipboard::Mode clipboardMode)
2278 {
2279     QString clip = QGuiApplication::clipboard()->text(clipboardMode);
2280     if (!clip.isEmpty() || hasSelectedText()) {
2281         separate(); //make it a separate undo/redo command
2282         insert(clip);
2283         separate();
2284     }
2285 }
2286
2287 #endif // !QT_NO_CLIPBOARD
2288
2289 /*!
2290     \internal
2291
2292     Exits preedit mode and commits parts marked as tentative commit
2293 */
2294 void QQuickTextInputPrivate::commitPreedit()
2295 {
2296     if (!composeMode())
2297         return;
2298
2299     qApp->inputPanel()->reset();
2300
2301     if (!m_tentativeCommit.isEmpty()) {
2302         internalInsert(m_tentativeCommit);
2303         m_tentativeCommit.clear();
2304         finishChange(-1, true/*not used, not documented*/, false);
2305     }
2306
2307     m_preeditCursor = 0;
2308     m_textLayout.setPreeditArea(-1, QString());
2309     m_textLayout.clearAdditionalFormats();
2310     updateLayout();
2311 }
2312
2313 /*!
2314     \internal
2315
2316     Handles the behavior for the backspace key or function.
2317     Removes the current selection if there is a selection, otherwise
2318     removes the character prior to the cursor position.
2319
2320     \sa del()
2321 */
2322 void QQuickTextInputPrivate::backspace()
2323 {
2324     int priorState = m_undoState;
2325     if (hasSelectedText()) {
2326         removeSelectedText();
2327     } else if (m_cursor) {
2328             --m_cursor;
2329             if (m_maskData)
2330                 m_cursor = prevMaskBlank(m_cursor);
2331             QChar uc = m_text.at(m_cursor);
2332             if (m_cursor > 0 && uc.unicode() >= 0xdc00 && uc.unicode() < 0xe000) {
2333                 // second half of a surrogate, check if we have the first half as well,
2334                 // if yes delete both at once
2335                 uc = m_text.at(m_cursor - 1);
2336                 if (uc.unicode() >= 0xd800 && uc.unicode() < 0xdc00) {
2337                     internalDelete(true);
2338                     --m_cursor;
2339                 }
2340             }
2341             internalDelete(true);
2342     }
2343     finishChange(priorState);
2344 }
2345
2346 /*!
2347     \internal
2348
2349     Handles the behavior for the delete key or function.
2350     Removes the current selection if there is a selection, otherwise
2351     removes the character after the cursor position.
2352
2353     \sa del()
2354 */
2355 void QQuickTextInputPrivate::del()
2356 {
2357     int priorState = m_undoState;
2358     if (hasSelectedText()) {
2359         removeSelectedText();
2360     } else {
2361         int n = m_textLayout.nextCursorPosition(m_cursor) - m_cursor;
2362         while (n--)
2363             internalDelete();
2364     }
2365     finishChange(priorState);
2366 }
2367
2368 /*!
2369     \internal
2370
2371     Inserts the given \a newText at the current cursor position.
2372     If there is any selected text it is removed prior to insertion of
2373     the new text.
2374 */
2375 void QQuickTextInputPrivate::insert(const QString &newText)
2376 {
2377     int priorState = m_undoState;
2378     removeSelectedText();
2379     internalInsert(newText);
2380     finishChange(priorState);
2381 }
2382
2383 /*!
2384     \internal
2385
2386     Clears the line control text.
2387 */
2388 void QQuickTextInputPrivate::clear()
2389 {
2390     int priorState = m_undoState;
2391     m_selstart = 0;
2392     m_selend = m_text.length();
2393     removeSelectedText();
2394     separate();
2395     finishChange(priorState, /*update*/false, /*edited*/false);
2396 }
2397
2398 /*!
2399     \internal
2400
2401     Sets \a length characters from the given \a start position as selected.
2402     The given \a start position must be within the current text for
2403     the line control.  If \a length characters cannot be selected, then
2404     the selection will extend to the end of the current text.
2405 */
2406 void QQuickTextInputPrivate::setSelection(int start, int length)
2407 {
2408     Q_Q(QQuickTextInput);
2409     commitPreedit();
2410
2411     if (start < 0 || start > (int)m_text.length()){
2412         qWarning("QQuickTextInputPrivate::setSelection: Invalid start position");
2413         return;
2414     }
2415
2416     if (length > 0) {
2417         if (start == m_selstart && start + length == m_selend && m_cursor == m_selend)
2418             return;
2419         m_selstart = start;
2420         m_selend = qMin(start + length, (int)m_text.length());
2421         m_cursor = m_selend;
2422     } else if (length < 0){
2423         if (start == m_selend && start + length == m_selstart && m_cursor == m_selstart)
2424             return;
2425         m_selstart = qMax(start + length, 0);
2426         m_selend = start;
2427         m_cursor = m_selstart;
2428     } else if (m_selstart != m_selend) {
2429         m_selstart = 0;
2430         m_selend = 0;
2431         m_cursor = start;
2432     } else {
2433         m_cursor = start;
2434         emitCursorPositionChanged();
2435         return;
2436     }
2437     emit q->selectionChanged();
2438     emitCursorPositionChanged();
2439 }
2440
2441 /*!
2442     \internal
2443
2444     Initializes the line control with a starting text value of \a txt.
2445 */
2446 void QQuickTextInputPrivate::init(const QString &txt)
2447 {
2448     m_text = txt;
2449
2450     updateDisplayText();
2451     m_cursor = m_text.length();
2452 }
2453
2454 /*!
2455     \internal
2456
2457     Sets the password echo editing to \a editing.  If password echo editing
2458     is true, then the text of the password is displayed even if the echo
2459     mode is set to QLineEdit::PasswordEchoOnEdit.  Password echoing editing
2460     does not affect other echo modes.
2461 */
2462 void QQuickTextInputPrivate::updatePasswordEchoEditing(bool editing)
2463 {
2464     cancelPasswordEchoTimer();
2465     m_passwordEchoEditing = editing;
2466     updateDisplayText();
2467 }
2468
2469 /*!
2470     \internal
2471
2472     Fixes the current text so that it is valid given any set validators.
2473
2474     Returns true if the text was changed.  Otherwise returns false.
2475 */
2476 bool QQuickTextInputPrivate::fixup() // this function assumes that validate currently returns != Acceptable
2477 {
2478 #ifndef QT_NO_VALIDATOR
2479     if (m_validator) {
2480         QString textCopy = m_text;
2481         int cursorCopy = m_cursor;
2482         m_validator->fixup(textCopy);
2483         if (m_validator->validate(textCopy, cursorCopy) == QValidator::Acceptable) {
2484             if (textCopy != m_text || cursorCopy != m_cursor)
2485                 internalSetText(textCopy, cursorCopy);
2486             return true;
2487         }
2488     }
2489 #endif
2490     return false;
2491 }
2492
2493 /*!
2494     \internal
2495
2496     Moves the cursor to the given position \a pos.   If \a mark is true will
2497     adjust the currently selected text.
2498 */
2499 void QQuickTextInputPrivate::moveCursor(int pos, bool mark)
2500 {
2501     Q_Q(QQuickTextInput);
2502     commitPreedit();
2503
2504     if (pos != m_cursor) {
2505         separate();
2506         if (m_maskData)
2507             pos = pos > m_cursor ? nextMaskBlank(pos) : prevMaskBlank(pos);
2508     }
2509     if (mark) {
2510         int anchor;
2511         if (m_selend > m_selstart && m_cursor == m_selstart)
2512             anchor = m_selend;
2513         else if (m_selend > m_selstart && m_cursor == m_selend)
2514             anchor = m_selstart;
2515         else
2516             anchor = m_cursor;
2517         m_selstart = qMin(anchor, pos);
2518         m_selend = qMax(anchor, pos);
2519     } else {
2520         internalDeselect();
2521     }
2522     m_cursor = pos;
2523     if (mark || m_selDirty) {
2524         m_selDirty = false;
2525         emit q->selectionChanged();
2526     }
2527     emitCursorPositionChanged();
2528 }
2529
2530 /*!
2531     \internal
2532
2533     Applies the given input method event \a event to the text of the line
2534     control
2535 */
2536 void QQuickTextInputPrivate::processInputMethodEvent(QInputMethodEvent *event)
2537 {
2538     Q_Q(QQuickTextInput);
2539
2540     int priorState = -1;
2541     bool isGettingInput = !event->commitString().isEmpty()
2542             || event->preeditString() != preeditAreaText()
2543             || event->replacementLength() > 0;
2544     bool cursorPositionChanged = false;
2545     bool selectionChange = false;
2546     m_preeditDirty = event->preeditString() != preeditAreaText();
2547
2548     if (isGettingInput) {
2549         // If any text is being input, remove selected text.
2550         priorState = m_undoState;
2551         if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit && !m_passwordEchoEditing) {
2552             updatePasswordEchoEditing(true);
2553             m_selstart = 0;
2554             m_selend = m_text.length();
2555         }
2556         removeSelectedText();
2557     }
2558
2559     int c = m_cursor; // cursor position after insertion of commit string
2560     if (event->replacementStart() <= 0)
2561         c += event->commitString().length() - qMin(-event->replacementStart(), event->replacementLength());
2562
2563     m_cursor += event->replacementStart();
2564     if (m_cursor < 0)
2565         m_cursor = 0;
2566
2567     // insert commit string
2568     if (event->replacementLength()) {
2569         m_selstart = m_cursor;
2570         m_selend = m_selstart + event->replacementLength();
2571         m_selend = qMin(m_selend, m_text.length());
2572         removeSelectedText();
2573     }
2574     if (!event->commitString().isEmpty()) {
2575         internalInsert(event->commitString());
2576         cursorPositionChanged = true;
2577     }
2578
2579     m_cursor = qBound(0, c, m_text.length());
2580
2581     for (int i = 0; i < event->attributes().size(); ++i) {
2582         const QInputMethodEvent::Attribute &a = event->attributes().at(i);
2583         if (a.type == QInputMethodEvent::Selection) {
2584             m_cursor = qBound(0, a.start + a.length, m_text.length());
2585             if (a.length) {
2586                 m_selstart = qMax(0, qMin(a.start, m_text.length()));
2587                 m_selend = m_cursor;
2588                 if (m_selend < m_selstart) {
2589                     qSwap(m_selstart, m_selend);
2590                 }
2591                 selectionChange = true;
2592             } else {
2593                 m_selstart = m_selend = 0;
2594             }
2595             cursorPositionChanged = true;
2596         }
2597     }
2598 #ifndef QT_NO_IM
2599     m_textLayout.setPreeditArea(m_cursor, event->preeditString());
2600 #endif //QT_NO_IM
2601     const int oldPreeditCursor = m_preeditCursor;
2602     m_preeditCursor = event->preeditString().length();
2603     m_hideCursor = false;
2604     QList<QTextLayout::FormatRange> formats;
2605     for (int i = 0; i < event->attributes().size(); ++i) {
2606         const QInputMethodEvent::Attribute &a = event->attributes().at(i);
2607         if (a.type == QInputMethodEvent::Cursor) {
2608             m_preeditCursor = a.start;
2609             m_hideCursor = !a.length;
2610         } else if (a.type == QInputMethodEvent::TextFormat) {
2611             QTextCharFormat f = qvariant_cast<QTextFormat>(a.value).toCharFormat();
2612             if (f.isValid()) {
2613                 QTextLayout::FormatRange o;
2614                 o.start = a.start + m_cursor;
2615                 o.length = a.length;
2616                 o.format = f;
2617                 formats.append(o);
2618             }
2619         }
2620     }
2621     m_textLayout.setAdditionalFormats(formats);
2622
2623     updateDisplayText(/*force*/ true);
2624     if (cursorPositionChanged)
2625         emitCursorPositionChanged();
2626     else if (m_preeditCursor != oldPreeditCursor)
2627         q->updateCursorRectangle();
2628
2629     bool tentativeCommitChanged = m_tentativeCommit != event->tentativeCommitString();
2630
2631     if (tentativeCommitChanged) {
2632         m_textDirty = true;
2633         m_tentativeCommit = event->tentativeCommitString();
2634     }
2635
2636     if (isGettingInput || tentativeCommitChanged)
2637         finishChange(priorState);
2638
2639     if (selectionChange)
2640         emit q->selectionChanged();
2641 }
2642
2643 /*!
2644     \internal
2645
2646     Sets the selection to cover the word at the given cursor position.
2647     The word boundaries are defined by the behavior of QTextLayout::SkipWords
2648     cursor mode.
2649 */
2650 void QQuickTextInputPrivate::selectWordAtPos(int cursor)
2651 {
2652     int next = cursor + 1;
2653     if (next > end())
2654         --next;
2655     int c = m_textLayout.previousCursorPosition(next, QTextLayout::SkipWords);
2656     moveCursor(c, false);
2657     // ## text layout should support end of words.
2658     int end = m_textLayout.nextCursorPosition(c, QTextLayout::SkipWords);
2659     while (end > cursor && m_text[end-1].isSpace())
2660         --end;
2661     moveCursor(end, true);
2662 }
2663
2664 /*!
2665     \internal
2666
2667     Completes a change to the line control text.  If the change is not valid
2668     will undo the line control state back to the given \a validateFromState.
2669
2670     If \a edited is true and the change is valid, will emit textEdited() in
2671     addition to textChanged().  Otherwise only emits textChanged() on a valid
2672     change.
2673
2674     The \a update value is currently unused.
2675 */
2676 bool QQuickTextInputPrivate::finishChange(int validateFromState, bool update, bool /*edited*/)
2677 {
2678     Q_Q(QQuickTextInput);
2679
2680     Q_UNUSED(update)
2681
2682     if (m_textDirty) {
2683         // do validation
2684         bool wasValidInput = m_validInput;
2685         m_validInput = true;
2686 #ifndef QT_NO_VALIDATOR
2687         if (m_validator) {
2688             QString textCopy = m_text;
2689             int cursorCopy = m_cursor;
2690             m_validInput = (m_validator->validate(textCopy, cursorCopy) != QValidator::Invalid);
2691             if (m_validInput) {
2692                 if (m_text != textCopy) {
2693                     internalSetText(textCopy, cursorCopy);
2694                     return true;
2695                 }
2696                 m_cursor = cursorCopy;
2697
2698                 if (!m_tentativeCommit.isEmpty()) {
2699                     textCopy.insert(m_cursor, m_tentativeCommit);
2700                     bool validInput = m_validator->validate(textCopy, cursorCopy) != QValidator::Invalid;
2701                     if (!validInput)
2702                         m_tentativeCommit.clear();
2703                 }
2704             } else {
2705                 m_tentativeCommit.clear();
2706             }
2707         }
2708 #endif
2709         if (validateFromState >= 0 && wasValidInput && !m_validInput) {
2710             if (m_transactions.count())
2711                 return false;
2712             internalUndo(validateFromState);
2713             m_history.resize(m_undoState);
2714             if (m_modifiedState > m_undoState)
2715                 m_modifiedState = -1;
2716             m_validInput = true;
2717             m_textDirty = false;
2718         }
2719         updateDisplayText();
2720
2721         if (m_textDirty) {
2722             m_textDirty = false;
2723             m_preeditDirty = false;
2724             determineHorizontalAlignment();
2725             emit q->textChanged();
2726         }
2727
2728         if (m_validInput != wasValidInput)
2729             emit q->acceptableInputChanged();
2730     }
2731     if (m_preeditDirty) {
2732         m_preeditDirty = false;
2733         determineHorizontalAlignment();
2734     }
2735     if (m_selDirty) {
2736         m_selDirty = false;
2737         emit q->selectionChanged();
2738     }
2739     emitCursorPositionChanged();
2740     return true;
2741 }
2742
2743 /*!
2744     \internal
2745
2746     An internal function for setting the text of the line control.
2747 */
2748 void QQuickTextInputPrivate::internalSetText(const QString &txt, int pos, bool edited)
2749 {
2750     Q_Q(QQuickTextInput);
2751     internalDeselect();
2752     QString oldText = m_text;
2753     if (m_maskData) {
2754         m_text = maskString(0, txt, true);
2755         m_text += clearString(m_text.length(), m_maxLength - m_text.length());
2756     } else {
2757         m_text = txt.isEmpty() ? txt : txt.left(m_maxLength);
2758     }
2759     m_history.clear();
2760     m_modifiedState =  m_undoState = 0;
2761     m_cursor = (pos < 0 || pos > m_text.length()) ? m_text.length() : pos;
2762     m_textDirty = (oldText != m_text);
2763
2764     bool changed = finishChange(-1, true, edited);
2765 #ifdef QT_NO_ACCESSIBILITY
2766     Q_UNUSED(changed)
2767 #else
2768     if (changed)
2769         QAccessible::updateAccessibility(q, 0, QAccessible::TextUpdated);
2770 #endif
2771 }
2772
2773
2774 /*!
2775     \internal
2776
2777     Adds the given \a command to the undo history
2778     of the line control.  Does not apply the command.
2779 */
2780 void QQuickTextInputPrivate::addCommand(const Command &cmd)
2781 {
2782     if (m_separator && m_undoState && m_history[m_undoState - 1].type != Separator) {
2783         m_history.resize(m_undoState + 2);
2784         m_history[m_undoState++] = Command(Separator, m_cursor, 0, m_selstart, m_selend);
2785     } else {
2786         m_history.resize(m_undoState + 1);
2787     }
2788     m_separator = false;
2789     m_history[m_undoState++] = cmd;
2790 }
2791
2792 /*!
2793     \internal
2794
2795     Inserts the given string \a s into the line
2796     control.
2797
2798     Also adds the appropriate commands into the undo history.
2799     This function does not call finishChange(), and may leave the text
2800     in an invalid state.
2801 */
2802 void QQuickTextInputPrivate::internalInsert(const QString &s)
2803 {
2804 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
2805     Q_Q(QQuickTextInput);
2806     if (m_echoMode == QQuickTextInput::Password)
2807         m_passwordEchoTimer.start(qt_passwordEchoDelay, q);
2808 #endif
2809     if (hasSelectedText())
2810         addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
2811     if (m_maskData) {
2812         QString ms = maskString(m_cursor, s);
2813         for (int i = 0; i < (int) ms.length(); ++i) {
2814             addCommand (Command(DeleteSelection, m_cursor + i, m_text.at(m_cursor + i), -1, -1));
2815             addCommand(Command(Insert, m_cursor + i, ms.at(i), -1, -1));
2816         }
2817         m_text.replace(m_cursor, ms.length(), ms);
2818         m_cursor += ms.length();
2819         m_cursor = nextMaskBlank(m_cursor);
2820         m_textDirty = true;
2821     } else {
2822         int remaining = m_maxLength - m_text.length();
2823         if (remaining != 0) {
2824             m_text.insert(m_cursor, s.left(remaining));
2825             for (int i = 0; i < (int) s.left(remaining).length(); ++i)
2826                addCommand(Command(Insert, m_cursor++, s.at(i), -1, -1));
2827             m_textDirty = true;
2828         }
2829     }
2830 }
2831
2832 /*!
2833     \internal
2834
2835     deletes a single character from the current text.  If \a wasBackspace,
2836     the character prior to the cursor is removed.  Otherwise the character
2837     after the cursor is removed.
2838
2839     Also adds the appropriate commands into the undo history.
2840     This function does not call finishChange(), and may leave the text
2841     in an invalid state.
2842 */
2843 void QQuickTextInputPrivate::internalDelete(bool wasBackspace)
2844 {
2845     if (m_cursor < (int) m_text.length()) {
2846         cancelPasswordEchoTimer();
2847         if (hasSelectedText())
2848             addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
2849         addCommand(Command((CommandType)((m_maskData ? 2 : 0) + (wasBackspace ? Remove : Delete)),
2850                    m_cursor, m_text.at(m_cursor), -1, -1));
2851         if (m_maskData) {
2852             m_text.replace(m_cursor, 1, clearString(m_cursor, 1));
2853             addCommand(Command(Insert, m_cursor, m_text.at(m_cursor), -1, -1));
2854         } else {
2855             m_text.remove(m_cursor, 1);
2856         }
2857         m_textDirty = true;
2858     }
2859 }
2860
2861 /*!
2862     \internal
2863
2864     removes the currently selected text from the line control.
2865
2866     Also adds the appropriate commands into the undo history.
2867     This function does not call finishChange(), and may leave the text
2868     in an invalid state.
2869 */
2870 void QQuickTextInputPrivate::removeSelectedText()
2871 {
2872     if (m_selstart < m_selend && m_selend <= (int) m_text.length()) {
2873         cancelPasswordEchoTimer();
2874         separate();
2875         int i ;
2876         addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
2877         if (m_selstart <= m_cursor && m_cursor < m_selend) {
2878             // cursor is within the selection. Split up the commands
2879             // to be able to restore the correct cursor position
2880             for (i = m_cursor; i >= m_selstart; --i)
2881                 addCommand (Command(DeleteSelection, i, m_text.at(i), -1, 1));
2882             for (i = m_selend - 1; i > m_cursor; --i)
2883                 addCommand (Command(DeleteSelection, i - m_cursor + m_selstart - 1, m_text.at(i), -1, -1));
2884         } else {
2885             for (i = m_selend-1; i >= m_selstart; --i)
2886                 addCommand (Command(RemoveSelection, i, m_text.at(i), -1, -1));
2887         }
2888         if (m_maskData) {
2889             m_text.replace(m_selstart, m_selend - m_selstart,  clearString(m_selstart, m_selend - m_selstart));
2890             for (int i = 0; i < m_selend - m_selstart; ++i)
2891                 addCommand(Command(Insert, m_selstart + i, m_text.at(m_selstart + i), -1, -1));
2892         } else {
2893             m_text.remove(m_selstart, m_selend - m_selstart);
2894         }
2895         if (m_cursor > m_selstart)
2896             m_cursor -= qMin(m_cursor, m_selend) - m_selstart;
2897         internalDeselect();
2898         m_textDirty = true;
2899     }
2900 }
2901
2902 /*!
2903     \internal
2904
2905     Parses the input mask specified by \a maskFields to generate
2906     the mask data used to handle input masks.
2907 */
2908 void QQuickTextInputPrivate::parseInputMask(const QString &maskFields)
2909 {
2910     int delimiter = maskFields.indexOf(QLatin1Char(';'));
2911     if (maskFields.isEmpty() || delimiter == 0) {
2912         if (m_maskData) {
2913             delete [] m_maskData;
2914             m_maskData = 0;
2915             m_maxLength = 32767;
2916             internalSetText(QString());
2917         }
2918         return;
2919     }
2920
2921     if (delimiter == -1) {
2922         m_blank = QLatin1Char(' ');
2923         m_inputMask = maskFields;
2924     } else {
2925         m_inputMask = maskFields.left(delimiter);
2926         m_blank = (delimiter + 1 < maskFields.length()) ? maskFields[delimiter + 1] : QLatin1Char(' ');
2927     }
2928
2929     // calculate m_maxLength / m_maskData length
2930     m_maxLength = 0;
2931     QChar c = 0;
2932     for (int i=0; i<m_inputMask.length(); i++) {
2933         c = m_inputMask.at(i);
2934         if (i > 0 && m_inputMask.at(i-1) == QLatin1Char('\\')) {
2935             m_maxLength++;
2936             continue;
2937         }
2938         if (c != QLatin1Char('\\') && c != QLatin1Char('!') &&
2939              c != QLatin1Char('<') && c != QLatin1Char('>') &&
2940              c != QLatin1Char('{') && c != QLatin1Char('}') &&
2941              c != QLatin1Char('[') && c != QLatin1Char(']'))
2942             m_maxLength++;
2943     }
2944
2945     delete [] m_maskData;
2946     m_maskData = new MaskInputData[m_maxLength];
2947
2948     MaskInputData::Casemode m = MaskInputData::NoCaseMode;
2949     c = 0;
2950     bool s;
2951     bool escape = false;
2952     int index = 0;
2953     for (int i = 0; i < m_inputMask.length(); i++) {
2954         c = m_inputMask.at(i);
2955         if (escape) {
2956             s = true;
2957             m_maskData[index].maskChar = c;
2958             m_maskData[index].separator = s;
2959             m_maskData[index].caseMode = m;
2960             index++;
2961             escape = false;
2962         } else if (c == QLatin1Char('<')) {
2963                 m = MaskInputData::Lower;
2964         } else if (c == QLatin1Char('>')) {
2965             m = MaskInputData::Upper;
2966         } else if (c == QLatin1Char('!')) {
2967             m = MaskInputData::NoCaseMode;
2968         } else if (c != QLatin1Char('{') && c != QLatin1Char('}') && c != QLatin1Char('[') && c != QLatin1Char(']')) {
2969             switch (c.unicode()) {
2970             case 'A':
2971             case 'a':
2972             case 'N':
2973             case 'n':
2974             case 'X':
2975             case 'x':
2976             case '9':
2977             case '0':
2978             case 'D':
2979             case 'd':
2980             case '#':
2981             case 'H':
2982             case 'h':
2983             case 'B':
2984             case 'b':
2985                 s = false;
2986                 break;
2987             case '\\':
2988                 escape = true;
2989             default:
2990                 s = true;
2991                 break;
2992             }
2993
2994             if (!escape) {
2995                 m_maskData[index].maskChar = c;
2996                 m_maskData[index].separator = s;
2997                 m_maskData[index].caseMode = m;
2998                 index++;
2999             }
3000         }
3001     }
3002     internalSetText(m_text);
3003 }
3004
3005
3006 /*!
3007     \internal
3008
3009     checks if the key is valid compared to the inputMask
3010 */
3011 bool QQuickTextInputPrivate::isValidInput(QChar key, QChar mask) const
3012 {
3013     switch (mask.unicode()) {
3014     case 'A':
3015         if (key.isLetter())
3016             return true;
3017         break;
3018     case 'a':
3019         if (key.isLetter() || key == m_blank)
3020             return true;
3021         break;
3022     case 'N':
3023         if (key.isLetterOrNumber())
3024             return true;
3025         break;
3026     case 'n':
3027         if (key.isLetterOrNumber() || key == m_blank)
3028             return true;
3029         break;
3030     case 'X':
3031         if (key.isPrint())
3032             return true;
3033         break;
3034     case 'x':
3035         if (key.isPrint() || key == m_blank)
3036             return true;
3037         break;
3038     case '9':
3039         if (key.isNumber())
3040             return true;
3041         break;
3042     case '0':
3043         if (key.isNumber() || key == m_blank)
3044             return true;
3045         break;
3046     case 'D':
3047         if (key.isNumber() && key.digitValue() > 0)
3048             return true;
3049         break;
3050     case 'd':
3051         if ((key.isNumber() && key.digitValue() > 0) || key == m_blank)
3052             return true;
3053         break;
3054     case '#':
3055         if (key.isNumber() || key == QLatin1Char('+') || key == QLatin1Char('-') || key == m_blank)
3056             return true;
3057         break;
3058     case 'B':
3059         if (key == QLatin1Char('0') || key == QLatin1Char('1'))
3060             return true;
3061         break;
3062     case 'b':
3063         if (key == QLatin1Char('0') || key == QLatin1Char('1') || key == m_blank)
3064             return true;
3065         break;
3066     case 'H':
3067         if (key.isNumber() || (key >= QLatin1Char('a') && key <= QLatin1Char('f')) || (key >= QLatin1Char('A') && key <= QLatin1Char('F')))
3068             return true;
3069         break;
3070     case 'h':
3071         if (key.isNumber() || (key >= QLatin1Char('a') && key <= QLatin1Char('f')) || (key >= QLatin1Char('A') && key <= QLatin1Char('F')) || key == m_blank)
3072             return true;
3073         break;
3074     default:
3075         break;
3076     }
3077     return false;
3078 }
3079
3080 /*!
3081     \internal
3082
3083     Returns true if the given text \a str is valid for any
3084     validator or input mask set for the line control.
3085
3086     Otherwise returns false
3087 */
3088 bool QQuickTextInputPrivate::hasAcceptableInput(const QString &str) const
3089 {
3090 #ifndef QT_NO_VALIDATOR
3091     QString textCopy = str;
3092     int cursorCopy = m_cursor;
3093     if (m_validator && m_validator->validate(textCopy, cursorCopy)
3094         != QValidator::Acceptable)
3095         return false;
3096 #endif
3097
3098     if (!m_maskData)
3099         return true;
3100
3101     if (str.length() != m_maxLength)
3102         return false;
3103
3104     for (int i=0; i < m_maxLength; ++i) {
3105         if (m_maskData[i].separator) {
3106             if (str.at(i) != m_maskData[i].maskChar)
3107                 return false;
3108         } else {
3109             if (!isValidInput(str.at(i), m_maskData[i].maskChar))
3110                 return false;
3111         }
3112     }
3113     return true;
3114 }
3115
3116 /*!
3117     \internal
3118
3119     Applies the inputMask on \a str starting from position \a pos in the mask. \a clear
3120     specifies from where characters should be gotten when a separator is met in \a str - true means
3121     that blanks will be used, false that previous input is used.
3122     Calling this when no inputMask is set is undefined.
3123 */
3124 QString QQuickTextInputPrivate::maskString(uint pos, const QString &str, bool clear) const
3125 {
3126     if (pos >= (uint)m_maxLength)
3127         return QString::fromLatin1("");
3128
3129     QString fill;
3130     fill = clear ? clearString(0, m_maxLength) : m_text;
3131
3132     int strIndex = 0;
3133     QString s = QString::fromLatin1("");
3134     int i = pos;
3135     while (i < m_maxLength) {
3136         if (strIndex < str.length()) {
3137             if (m_maskData[i].separator) {
3138                 s += m_maskData[i].maskChar;
3139                 if (str[(int)strIndex] == m_maskData[i].maskChar)
3140                     strIndex++;
3141                 ++i;
3142             } else {
3143                 if (isValidInput(str[(int)strIndex], m_maskData[i].maskChar)) {
3144                     switch (m_maskData[i].caseMode) {
3145                     case MaskInputData::Upper:
3146                         s += str[(int)strIndex].toUpper();
3147                         break;
3148                     case MaskInputData::Lower:
3149                         s += str[(int)strIndex].toLower();
3150                         break;
3151                     default:
3152                         s += str[(int)strIndex];
3153                     }
3154                     ++i;
3155                 } else {
3156                     // search for separator first
3157                     int n = findInMask(i, true, true, str[(int)strIndex]);
3158                     if (n != -1) {
3159                         if (str.length() != 1 || i == 0 || (i > 0 && (!m_maskData[i-1].separator || m_maskData[i-1].maskChar != str[(int)strIndex]))) {
3160                             s += fill.mid(i, n-i+1);
3161                             i = n + 1; // update i to find + 1
3162                         }
3163                     } else {
3164                         // search for valid m_blank if not
3165                         n = findInMask(i, true, false, str[(int)strIndex]);
3166                         if (n != -1) {
3167                             s += fill.mid(i, n-i);
3168                             switch (m_maskData[n].caseMode) {
3169                             case MaskInputData::Upper:
3170                                 s += str[(int)strIndex].toUpper();
3171                                 break;
3172                             case MaskInputData::Lower:
3173                                 s += str[(int)strIndex].toLower();
3174                                 break;
3175                             default:
3176                                 s += str[(int)strIndex];
3177                             }
3178                             i = n + 1; // updates i to find + 1
3179                         }
3180                     }
3181                 }
3182                 ++strIndex;
3183             }
3184         } else
3185             break;
3186     }
3187
3188     return s;
3189 }
3190
3191
3192
3193 /*!
3194     \internal
3195
3196     Returns a "cleared" string with only separators and blank chars.
3197     Calling this when no inputMask is set is undefined.
3198 */
3199 QString QQuickTextInputPrivate::clearString(uint pos, uint len) const
3200 {
3201     if (pos >= (uint)m_maxLength)
3202         return QString();
3203
3204     QString s;
3205     int end = qMin((uint)m_maxLength, pos + len);
3206     for (int i = pos; i < end; ++i)
3207         if (m_maskData[i].separator)
3208             s += m_maskData[i].maskChar;
3209         else
3210             s += m_blank;
3211
3212     return s;
3213 }
3214
3215 /*!
3216     \internal
3217
3218     Strips blank parts of the input in a QQuickTextInputPrivate when an inputMask is set,
3219     separators are still included. Typically "127.0__.0__.1__" becomes "127.0.0.1".
3220 */
3221 QString QQuickTextInputPrivate::stripString(const QString &str) const
3222 {
3223     if (!m_maskData)
3224         return str;
3225
3226     QString s;
3227     int end = qMin(m_maxLength, (int)str.length());
3228     for (int i = 0; i < end; ++i)
3229         if (m_maskData[i].separator)
3230             s += m_maskData[i].maskChar;
3231         else
3232             if (str[i] != m_blank)
3233                 s += str[i];
3234
3235     return s;
3236 }
3237
3238 /*!
3239     \internal
3240     searches forward/backward in m_maskData for either a separator or a m_blank
3241 */
3242 int QQuickTextInputPrivate::findInMask(int pos, bool forward, bool findSeparator, QChar searchChar) const
3243 {
3244     if (pos >= m_maxLength || pos < 0)
3245         return -1;
3246
3247     int end = forward ? m_maxLength : -1;
3248     int step = forward ? 1 : -1;
3249     int i = pos;
3250
3251     while (i != end) {
3252         if (findSeparator) {
3253             if (m_maskData[i].separator && m_maskData[i].maskChar == searchChar)
3254                 return i;
3255         } else {
3256             if (!m_maskData[i].separator) {
3257                 if (searchChar.isNull())
3258                     return i;
3259                 else if (isValidInput(searchChar, m_maskData[i].maskChar))
3260                     return i;
3261             }
3262         }
3263         i += step;
3264     }
3265     return -1;
3266 }
3267
3268 void QQuickTextInputPrivate::internalUndo(int until)
3269 {
3270     if (!isUndoAvailable())
3271         return;
3272     cancelPasswordEchoTimer();
3273     internalDeselect();
3274     while (m_undoState && m_undoState > until) {
3275         Command& cmd = m_history[--m_undoState];
3276         switch (cmd.type) {
3277         case Insert:
3278             m_text.remove(cmd.pos, 1);
3279             m_cursor = cmd.pos;
3280             break;
3281         case SetSelection:
3282             m_selstart = cmd.selStart;
3283             m_selend = cmd.selEnd;
3284             m_cursor = cmd.pos;
3285             break;
3286         case Remove:
3287         case RemoveSelection:
3288             m_text.insert(cmd.pos, cmd.uc);
3289             m_cursor = cmd.pos + 1;
3290             break;
3291         case Delete:
3292         case DeleteSelection:
3293             m_text.insert(cmd.pos, cmd.uc);
3294             m_cursor = cmd.pos;
3295             break;
3296         case Separator:
3297             continue;
3298         }
3299         if (until < 0 && m_undoState) {
3300             Command& next = m_history[m_undoState-1];
3301             if (next.type != cmd.type && next.type < RemoveSelection
3302                  && (cmd.type < RemoveSelection || next.type == Separator))
3303                 break;
3304         }
3305     }
3306     m_textDirty = true;
3307     emitCursorPositionChanged();
3308 }
3309
3310 void QQuickTextInputPrivate::internalRedo()
3311 {
3312     if (!isRedoAvailable())
3313         return;
3314     internalDeselect();
3315     while (m_undoState < (int)m_history.size()) {
3316         Command& cmd = m_history[m_undoState++];
3317         switch (cmd.type) {
3318         case Insert:
3319             m_text.insert(cmd.pos, cmd.uc);
3320             m_cursor = cmd.pos + 1;
3321             break;
3322         case SetSelection:
3323             m_selstart = cmd.selStart;
3324             m_selend = cmd.selEnd;
3325             m_cursor = cmd.pos;
3326             break;
3327         case Remove:
3328         case Delete:
3329         case RemoveSelection:
3330         case DeleteSelection:
3331             m_text.remove(cmd.pos, 1);
3332             m_selstart = cmd.selStart;
3333             m_selend = cmd.selEnd;
3334             m_cursor = cmd.pos;
3335             break;
3336         case Separator:
3337             m_selstart = cmd.selStart;
3338             m_selend = cmd.selEnd;
3339             m_cursor = cmd.pos;
3340             break;
3341         }
3342         if (m_undoState < (int)m_history.size()) {
3343             Command& next = m_history[m_undoState];
3344             if (next.type != cmd.type && cmd.type < RemoveSelection && next.type != Separator
3345                  && (next.type < RemoveSelection || cmd.type == Separator))
3346                 break;
3347         }
3348     }
3349     m_textDirty = true;
3350     emitCursorPositionChanged();
3351 }
3352
3353 /*!
3354     \internal
3355
3356     If the current cursor position differs from the last emitted cursor
3357     position, emits cursorPositionChanged().
3358 */
3359 void QQuickTextInputPrivate::emitCursorPositionChanged()
3360 {
3361     Q_Q(QQuickTextInput);
3362     if (m_cursor != m_lastCursorPos) {
3363         m_lastCursorPos = m_cursor;
3364
3365         q->updateCursorRectangle();
3366         emit q->cursorPositionChanged();
3367         // XXX todo - not in 4.8?
3368     #if 0
3369         resetCursorBlinkTimer();
3370     #endif
3371
3372         if (!hasSelectedText()) {
3373             if (lastSelectionStart != m_cursor) {
3374                 lastSelectionStart = m_cursor;
3375                 emit q->selectionStartChanged();
3376             }
3377             if (lastSelectionEnd != m_cursor) {
3378                 lastSelectionEnd = m_cursor;
3379                 emit q->selectionEndChanged();
3380             }
3381         }
3382
3383 #ifndef QT_NO_ACCESSIBILITY
3384         QAccessible::updateAccessibility(q, 0, QAccessible::TextCaretMoved);
3385 #endif
3386     }
3387 }
3388
3389
3390 void QQuickTextInputPrivate::setCursorBlinkPeriod(int msec)
3391 {
3392     Q_Q(QQuickTextInput);
3393     if (msec == m_blinkPeriod)
3394         return;
3395     if (m_blinkTimer) {
3396         q->killTimer(m_blinkTimer);
3397     }
3398     if (msec) {
3399         m_blinkTimer = q->startTimer(msec / 2);
3400         m_blinkStatus = 1;
3401     } else {
3402         m_blinkTimer = 0;
3403         if (m_blinkStatus == 1)
3404             q->update();
3405     }
3406     m_blinkPeriod = msec;
3407 }
3408
3409 void QQuickTextInputPrivate::resetCursorBlinkTimer()
3410 {
3411     Q_Q(QQuickTextInput);
3412     if (m_blinkPeriod == 0 || m_blinkTimer == 0)
3413         return;
3414     q->killTimer(m_blinkTimer);
3415     m_blinkTimer = q->startTimer(m_blinkPeriod / 2);
3416     m_blinkStatus = 1;
3417 }
3418
3419 void QQuickTextInput::timerEvent(QTimerEvent *event)
3420 {
3421     Q_D(QQuickTextInput);
3422     if (event->timerId() == d->m_blinkTimer) {
3423         d->m_blinkStatus = !d->m_blinkStatus;
3424         update();
3425     } else if (event->timerId() == d->m_deleteAllTimer) {
3426         killTimer(d->m_deleteAllTimer);
3427         d->m_deleteAllTimer = 0;
3428         d->clear();
3429 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
3430     } else if (event->timerId() == d->m_passwordEchoTimer.timerId()) {
3431         d->m_passwordEchoTimer.stop();
3432         d->updateDisplayText();
3433 #endif
3434     }
3435 }
3436
3437 void QQuickTextInputPrivate::processKeyEvent(QKeyEvent* event)
3438 {
3439     Q_Q(QQuickTextInput);
3440     bool inlineCompletionAccepted = false;
3441
3442     if (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return) {
3443         if (hasAcceptableInput(m_text) || fixup()) {
3444             emit q->accepted();
3445         }
3446         if (inlineCompletionAccepted)
3447             event->accept();
3448         else
3449             event->ignore();
3450         return;
3451     }
3452
3453     if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit
3454         && !m_passwordEchoEditing
3455         && !m_readOnly
3456         && !event->text().isEmpty()
3457         && !(event->modifiers() & Qt::ControlModifier)) {
3458         // Clear the edit and reset to normal echo mode while editing; the
3459         // echo mode switches back when the edit loses focus
3460         // ### resets current content.  dubious code; you can
3461         // navigate with keys up, down, back, and select(?), but if you press
3462         // "left" or "right" it clears?
3463         updatePasswordEchoEditing(true);
3464         clear();
3465     }
3466
3467     bool unknown = false;
3468     bool visual = cursorMoveStyle() == Qt::VisualMoveStyle;
3469
3470     if (false) {
3471     }
3472 #ifndef QT_NO_SHORTCUT
3473     else if (event == QKeySequence::Undo) {
3474         if (!m_readOnly)
3475             undo();
3476     }
3477     else if (event == QKeySequence::Redo) {
3478         if (!m_readOnly)
3479             redo();
3480     }
3481     else if (event == QKeySequence::SelectAll) {
3482         selectAll();
3483     }
3484 #ifndef QT_NO_CLIPBOARD
3485     else if (event == QKeySequence::Copy) {
3486         copy();
3487     }
3488     else if (event == QKeySequence::Paste) {
3489         if (!m_readOnly) {
3490             QClipboard::Mode mode = QClipboard::Clipboard;
3491             paste(mode);
3492         }
3493     }
3494     else if (event == QKeySequence::Cut) {
3495         if (!m_readOnly) {
3496             copy();
3497             del();
3498         }
3499     }
3500     else if (event == QKeySequence::DeleteEndOfLine) {
3501         if (!m_readOnly) {
3502             setSelection(m_cursor, end());
3503             copy();
3504             del();
3505         }
3506     }
3507 #endif //QT_NO_CLIPBOARD
3508     else if (event == QKeySequence::MoveToStartOfLine || event == QKeySequence::MoveToStartOfBlock) {
3509         home(0);
3510     }
3511     else if (event == QKeySequence::MoveToEndOfLine || event == QKeySequence::MoveToEndOfBlock) {
3512         end(0);
3513     }
3514     else if (event == QKeySequence::SelectStartOfLine || event == QKeySequence::SelectStartOfBlock) {
3515         home(1);
3516     }
3517     else if (event == QKeySequence::SelectEndOfLine || event == QKeySequence::SelectEndOfBlock) {
3518         end(1);
3519     }
3520     else if (event == QKeySequence::MoveToNextChar) {
3521         if (hasSelectedText()) {
3522             moveCursor(selectionEnd(), false);
3523         } else {
3524             cursorForward(0, visual ? 1 : (layoutDirection() == Qt::LeftToRight ? 1 : -1));
3525         }
3526     }
3527     else if (event == QKeySequence::SelectNextChar) {
3528         cursorForward(1, visual ? 1 : (layoutDirection() == Qt::LeftToRight ? 1 : -1));
3529     }
3530     else if (event == QKeySequence::MoveToPreviousChar) {
3531         if (hasSelectedText()) {
3532             moveCursor(selectionStart(), false);
3533         } else {
3534             cursorForward(0, visual ? -1 : (layoutDirection() == Qt::LeftToRight ? -1 : 1));
3535         }
3536     }
3537     else if (event == QKeySequence::SelectPreviousChar) {
3538         cursorForward(1, visual ? -1 : (layoutDirection() == Qt::LeftToRight ? -1 : 1));
3539     }
3540     else if (event == QKeySequence::MoveToNextWord) {
3541         if (m_echoMode == QQuickTextInput::Normal)
3542             layoutDirection() == Qt::LeftToRight ? cursorWordForward(0) : cursorWordBackward(0);
3543         else
3544             layoutDirection() == Qt::LeftToRight ? end(0) : home(0);
3545     }
3546     else if (event == QKeySequence::MoveToPreviousWord) {
3547         if (m_echoMode == QQuickTextInput::Normal)
3548             layoutDirection() == Qt::LeftToRight ? cursorWordBackward(0) : cursorWordForward(0);
3549         else if (!m_readOnly) {
3550             layoutDirection() == Qt::LeftToRight ? home(0) : end(0);
3551         }
3552     }
3553     else if (event == QKeySequence::SelectNextWord) {
3554         if (m_echoMode == QQuickTextInput::Normal)
3555             layoutDirection() == Qt::LeftToRight ? cursorWordForward(1) : cursorWordBackward(1);
3556         else
3557             layoutDirection() == Qt::LeftToRight ? end(1) : home(1);
3558     }
3559     else if (event == QKeySequence::SelectPreviousWord) {
3560         if (m_echoMode == QQuickTextInput::Normal)
3561             layoutDirection() == Qt::LeftToRight ? cursorWordBackward(1) : cursorWordForward(1);
3562         else
3563             layoutDirection() == Qt::LeftToRight ? home(1) : end(1);
3564     }
3565     else if (event == QKeySequence::Delete) {
3566         if (!m_readOnly)
3567             del();
3568     }
3569     else if (event == QKeySequence::DeleteEndOfWord) {
3570         if (!m_readOnly) {
3571             cursorWordForward(true);
3572             del();
3573         }
3574     }
3575     else if (event == QKeySequence::DeleteStartOfWord) {
3576         if (!m_readOnly) {
3577             cursorWordBackward(true);
3578             del();
3579         }
3580     }
3581 #endif // QT_NO_SHORTCUT
3582     else {
3583         bool handled = false;
3584         if (event->modifiers() & Qt::ControlModifier) {
3585             switch (event->key()) {
3586             case Qt::Key_Backspace:
3587                 if (!m_readOnly) {
3588                     cursorWordBackward(true);
3589                     del();
3590                 }
3591                 break;
3592             default:
3593                 if (!handled)
3594                     unknown = true;
3595             }
3596         } else { // ### check for *no* modifier
3597             switch (event->key()) {
3598             case Qt::Key_Backspace:
3599                 if (!m_readOnly) {
3600                     backspace();
3601                 }
3602                 break;
3603             default:
3604                 if (!handled)
3605                     unknown = true;
3606             }
3607         }
3608     }
3609
3610     if (event->key() == Qt::Key_Direction_L || event->key() == Qt::Key_Direction_R) {
3611         setLayoutDirection((event->key() == Qt::Key_Direction_L) ? Qt::LeftToRight : Qt::RightToLeft);
3612         unknown = false;
3613     }
3614
3615     if (unknown && !m_readOnly) {
3616         QString t = event->text();
3617         if (!t.isEmpty() && t.at(0).isPrint()) {
3618             insert(t);
3619             event->accept();
3620             return;
3621         }
3622     }
3623
3624     if (unknown)
3625         event->ignore();
3626     else
3627         event->accept();
3628 }
3629
3630
3631 QT_END_NAMESPACE
3632