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