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