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