Propagate left key presses to the parent item when TextInput is empty.
[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 (!ignore && 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 && oldNode != 0) {
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 #ifndef QT_NO_CLIPBOARD
2214 /*!
2215     \qmlproperty bool QtQuick2::TextInput::canPaste
2216
2217     Returns true if the TextInput is writable and the content of the clipboard is
2218     suitable for pasting into the TextInput.
2219 */
2220 bool QQuickTextInput::canPaste() const
2221 {
2222     Q_D(const QQuickTextInput);
2223     if (!d->canPasteValid) {
2224         if (const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData())
2225             const_cast<QQuickTextInputPrivate *>(d)->canPaste = !d->m_readOnly && mimeData->hasText();
2226         const_cast<QQuickTextInputPrivate *>(d)->canPasteValid = true;
2227     }
2228     return d->canPaste;
2229 }
2230 #endif
2231
2232 /*!
2233     \qmlproperty bool QtQuick2::TextInput::canUndo
2234
2235     Returns true if the TextInput is writable and there are previous operations
2236     that can be undone.
2237 */
2238
2239 bool QQuickTextInput::canUndo() const
2240 {
2241     Q_D(const QQuickTextInput);
2242     return d->canUndo;
2243 }
2244
2245 /*!
2246     \qmlproperty bool QtQuick2::TextInput::canRedo
2247
2248     Returns true if the TextInput is writable and there are \l {undo}{undone}
2249     operations that can be redone.
2250 */
2251
2252 bool QQuickTextInput::canRedo() const
2253 {
2254     Q_D(const QQuickTextInput);
2255     return d->canRedo;
2256 }
2257
2258 /*!
2259     \qmlproperty real QtQuick2::TextInput::contentWidth
2260
2261     Returns the width of the text, including the width past the width
2262     which is covered due to insufficient wrapping if \l wrapMode is set.
2263 */
2264
2265 qreal QQuickTextInput::contentWidth() const
2266 {
2267     Q_D(const QQuickTextInput);
2268     return d->boundingRect.width();
2269 }
2270
2271 /*!
2272     \qmlproperty real QtQuick2::TextInput::contentHeight
2273
2274     Returns the height of the text, including the height past the height
2275     that is covered if the text does not fit within the set height.
2276 */
2277
2278 qreal QQuickTextInput::contentHeight() const
2279 {
2280     Q_D(const QQuickTextInput);
2281     return d->boundingRect.height();
2282 }
2283
2284 void QQuickTextInput::moveCursorSelection(int position)
2285 {
2286     Q_D(QQuickTextInput);
2287     d->moveCursor(position, true);
2288 }
2289
2290 /*!
2291     \qmlmethod void QtQuick2::TextInput::moveCursorSelection(int position, SelectionMode mode = TextInput.SelectCharacters)
2292
2293     Moves the cursor to \a position and updates the selection according to the optional \a mode
2294     parameter.  (To only move the cursor, set the \l cursorPosition property.)
2295
2296     When this method is called it additionally sets either the
2297     selectionStart or the selectionEnd (whichever was at the previous cursor position)
2298     to the specified position. This allows you to easily extend and contract the selected
2299     text range.
2300
2301     The selection mode specifies whether the selection is updated on a per character or a per word
2302     basis.  If not specified the selection mode will default to TextInput.SelectCharacters.
2303
2304     \list
2305     \li TextInput.SelectCharacters - Sets either the selectionStart or selectionEnd (whichever was at
2306     the previous cursor position) to the specified position.
2307     \li TextInput.SelectWords - Sets the selectionStart and selectionEnd to include all
2308     words between the specified position and the previous cursor position.  Words partially in the
2309     range are included.
2310     \endlist
2311
2312     For example, take this sequence of calls:
2313
2314     \code
2315         cursorPosition = 5
2316         moveCursorSelection(9, TextInput.SelectCharacters)
2317         moveCursorSelection(7, TextInput.SelectCharacters)
2318     \endcode
2319
2320     This moves the cursor to position 5, extend the selection end from 5 to 9
2321     and then retract the selection end from 9 to 7, leaving the text from position 5 to 7
2322     selected (the 6th and 7th characters).
2323
2324     The same sequence with TextInput.SelectWords will extend the selection start to a word boundary
2325     before or on position 5 and extend the selection end to a word boundary on or past position 9.
2326 */
2327 void QQuickTextInput::moveCursorSelection(int pos, SelectionMode mode)
2328 {
2329     Q_D(QQuickTextInput);
2330
2331     if (mode == SelectCharacters) {
2332         d->moveCursor(pos, true);
2333     } else if (pos != d->m_cursor){
2334         const int cursor = d->m_cursor;
2335         int anchor;
2336         if (!d->hasSelectedText())
2337             anchor = d->m_cursor;
2338         else if (d->selectionStart() == d->m_cursor)
2339             anchor = d->selectionEnd();
2340         else
2341             anchor = d->selectionStart();
2342
2343         if (anchor < pos || (anchor == pos && cursor < pos)) {
2344             const QString text = this->text();
2345             QTextBoundaryFinder finder(QTextBoundaryFinder::Word, text);
2346             finder.setPosition(anchor);
2347
2348             const QTextBoundaryFinder::BoundaryReasons reasons = finder.boundaryReasons();
2349             if (anchor < text.length() && (!(reasons & QTextBoundaryFinder::StartWord)
2350                     || ((reasons & QTextBoundaryFinder::EndWord) && anchor > cursor))) {
2351                 finder.toPreviousBoundary();
2352             }
2353             anchor = finder.position() != -1 ? finder.position() : 0;
2354
2355             finder.setPosition(pos);
2356             if (pos > 0 && !finder.boundaryReasons())
2357                 finder.toNextBoundary();
2358             const int cursor = finder.position() != -1 ? finder.position() : text.length();
2359
2360             d->setSelection(anchor, cursor - anchor);
2361         } else if (anchor > pos || (anchor == pos && cursor > pos)) {
2362             const QString text = this->text();
2363             QTextBoundaryFinder finder(QTextBoundaryFinder::Word, text);
2364             finder.setPosition(anchor);
2365
2366             const QTextBoundaryFinder::BoundaryReasons reasons = finder.boundaryReasons();
2367             if (anchor > 0 && (!(reasons & QTextBoundaryFinder::EndWord)
2368                     || ((reasons & QTextBoundaryFinder::StartWord) && anchor < cursor))) {
2369                 finder.toNextBoundary();
2370             }
2371
2372             anchor = finder.position() != -1 ? finder.position() : text.length();
2373
2374             finder.setPosition(pos);
2375             if (pos < text.length() && !finder.boundaryReasons())
2376                  finder.toPreviousBoundary();
2377             const int cursor = finder.position() != -1 ? finder.position() : 0;
2378
2379             d->setSelection(anchor, cursor - anchor);
2380         }
2381     }
2382 }
2383
2384 /*!
2385     \qmlmethod void QtQuick2::TextInput::openSoftwareInputPanel()
2386
2387     Opens software input panels like virtual keyboards for typing, useful for
2388     customizing when you want the input keyboard to be shown and hidden in
2389     your application.
2390
2391     By default the opening of input panels follows the platform style. Input panels are
2392     always closed if no editor has active focus.
2393
2394     You can disable the automatic behavior by setting the property \c activeFocusOnPress to false
2395     and use functions openSoftwareInputPanel() and closeSoftwareInputPanel() to implement
2396     the behavior you want.
2397
2398     Only relevant on platforms, which provide virtual keyboards.
2399
2400     \qml
2401         import QtQuick 2.0
2402         TextInput {
2403             id: textInput
2404             text: "Hello world!"
2405             activeFocusOnPress: false
2406             MouseArea {
2407                 anchors.fill: parent
2408                 onClicked: {
2409                     if (!textInput.activeFocus) {
2410                         textInput.forceActiveFocus()
2411                         textInput.openSoftwareInputPanel();
2412                     } else {
2413                         textInput.focus = false;
2414                     }
2415                 }
2416                 onPressAndHold: textInput.closeSoftwareInputPanel();
2417             }
2418         }
2419     \endqml
2420 */
2421 void QQuickTextInput::openSoftwareInputPanel()
2422 {
2423     if (qGuiApp)
2424         qGuiApp->inputMethod()->show();
2425 }
2426
2427 /*!
2428     \qmlmethod void QtQuick2::TextInput::closeSoftwareInputPanel()
2429
2430     Closes a software input panel like a virtual keyboard shown on the screen, useful
2431     for customizing when you want the input keyboard to be shown and hidden in
2432     your application.
2433
2434     By default the opening of input panels follows the platform style. Input panels are
2435     always closed if no editor has active focus.
2436
2437     You can disable the automatic behavior by setting the property \c activeFocusOnPress to false
2438     and use functions openSoftwareInputPanel() and closeSoftwareInputPanel() to implement
2439     the behavior you want.
2440
2441     Only relevant on platforms, which provide virtual keyboards.
2442
2443     \qml
2444         import QtQuick 2.0
2445         TextInput {
2446             id: textInput
2447             text: "Hello world!"
2448             activeFocusOnPress: false
2449             MouseArea {
2450                 anchors.fill: parent
2451                 onClicked: {
2452                     if (!textInput.activeFocus) {
2453                         textInput.forceActiveFocus();
2454                         textInput.openSoftwareInputPanel();
2455                     } else {
2456                         textInput.focus = false;
2457                     }
2458                 }
2459                 onPressAndHold: textInput.closeSoftwareInputPanel();
2460             }
2461         }
2462     \endqml
2463 */
2464 void QQuickTextInput::closeSoftwareInputPanel()
2465 {
2466     if (qGuiApp)
2467         qGuiApp->inputMethod()->hide();
2468 }
2469
2470 void QQuickTextInput::focusInEvent(QFocusEvent *event)
2471 {
2472     Q_D(const QQuickTextInput);
2473     if (d->focusOnPress && !d->m_readOnly)
2474         openSoftwareInputPanel();
2475     QQuickImplicitSizeItem::focusInEvent(event);
2476 }
2477
2478 void QQuickTextInput::itemChange(ItemChange change, const ItemChangeData &value)
2479 {
2480     Q_D(QQuickTextInput);
2481     if (change == ItemActiveFocusHasChanged) {
2482         bool hasFocus = value.boolValue;
2483         setCursorVisible(hasFocus); // ### refactor:  && d->canvas && d->canvas->hasFocus()
2484         if (!hasFocus && (d->m_passwordEchoEditing || d->m_passwordEchoTimer.isActive())) {
2485             d->updatePasswordEchoEditing(false);//QQuickTextInputPrivate sets it on key events, but doesn't deal with focus events
2486         }
2487
2488         if (!hasFocus) {
2489             if (!d->persistentSelection)
2490                 d->deselect();
2491             disconnect(qApp->inputMethod(), SIGNAL(inputDirectionChanged(Qt::LayoutDirection)),
2492                        this, SLOT(q_updateAlignment()));
2493         } else {
2494             q_updateAlignment();
2495             connect(qApp->inputMethod(), SIGNAL(inputDirectionChanged(Qt::LayoutDirection)),
2496                     this, SLOT(q_updateAlignment()));
2497         }
2498     }
2499     QQuickItem::itemChange(change, value);
2500 }
2501
2502 /*!
2503     \qmlproperty bool QtQuick2::TextInput::inputMethodComposing
2504
2505
2506     This property holds whether the TextInput has partial text input from an
2507     input method.
2508
2509     While it is composing an input method may rely on mouse or key events from
2510     the TextInput to edit or commit the partial text.  This property can be
2511     used to determine when to disable events handlers that may interfere with
2512     the correct operation of an input method.
2513 */
2514 bool QQuickTextInput::isInputMethodComposing() const
2515 {
2516     Q_D(const QQuickTextInput);
2517     return d->hasImState;
2518 }
2519
2520 void QQuickTextInputPrivate::init()
2521 {
2522     Q_Q(QQuickTextInput);
2523     q->setSmooth(smooth);
2524     q->setAcceptedMouseButtons(Qt::LeftButton);
2525     q->setFlag(QQuickItem::ItemAcceptsInputMethod);
2526     q->setFlag(QQuickItem::ItemHasContents);
2527 #ifndef QT_NO_CLIPBOARD
2528     q->connect(QGuiApplication::clipboard(), SIGNAL(dataChanged()),
2529             q, SLOT(q_canPasteChanged()));
2530 #endif // QT_NO_CLIPBOARD
2531
2532     lastSelectionStart = 0;
2533     lastSelectionEnd = 0;
2534     determineHorizontalAlignment();
2535
2536     if (!qmlDisableDistanceField()) {
2537         QTextOption option = m_textLayout.textOption();
2538         option.setUseDesignMetrics(true);
2539         m_textLayout.setTextOption(option);
2540     }
2541 }
2542
2543 void QQuickTextInput::updateCursorRectangle()
2544 {
2545     Q_D(QQuickTextInput);
2546     if (!isComponentComplete())
2547         return;
2548
2549     d->updateHorizontalScroll();
2550     d->updateVerticalScroll();
2551     d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
2552     update();
2553     emit cursorRectangleChanged();
2554     if (d->cursorItem) {
2555         QRectF r = cursorRectangle();
2556         d->cursorItem->setPos(r.topLeft());
2557         d->cursorItem->setHeight(r.height());
2558     }
2559     updateInputMethod(Qt::ImCursorRectangle);
2560 }
2561
2562 void QQuickTextInput::selectionChanged()
2563 {
2564     Q_D(QQuickTextInput);
2565     d->textLayoutDirty = true; //TODO: Only update rect in selection
2566     d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
2567     update();
2568     emit selectedTextChanged();
2569
2570     if (d->lastSelectionStart != d->selectionStart()) {
2571         d->lastSelectionStart = d->selectionStart();
2572         if (d->lastSelectionStart == -1)
2573             d->lastSelectionStart = d->m_cursor;
2574         emit selectionStartChanged();
2575     }
2576     if (d->lastSelectionEnd != d->selectionEnd()) {
2577         d->lastSelectionEnd = d->selectionEnd();
2578         if (d->lastSelectionEnd == -1)
2579             d->lastSelectionEnd = d->m_cursor;
2580         emit selectionEndChanged();
2581     }
2582 }
2583
2584 void QQuickTextInputPrivate::showCursor()
2585 {
2586     if (textNode != 0 && textNode->cursorNode() != 0)
2587         textNode->cursorNode()->setColor(color);
2588 }
2589
2590 void QQuickTextInputPrivate::hideCursor()
2591 {
2592     if (textNode != 0 && textNode->cursorNode() != 0)
2593         textNode->cursorNode()->setColor(QColor(0, 0, 0, 0));
2594 }
2595
2596 QRectF QQuickTextInput::boundingRect() const
2597 {
2598     Q_D(const QQuickTextInput);
2599
2600     int cursorWidth = d->cursorItem ? d->cursorItem->width() : 1;
2601
2602     // Could include font max left/right bearings to either side of rectangle.
2603     QRectF r = QQuickImplicitSizeItem::boundingRect();
2604     r.setRight(r.right() + cursorWidth);
2605     return r;
2606 }
2607
2608 void QQuickTextInput::q_canPasteChanged()
2609 {
2610     Q_D(QQuickTextInput);
2611     bool old = d->canPaste;
2612 #ifndef QT_NO_CLIPBOARD
2613     if (const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData())
2614         d->canPaste = !d->m_readOnly && mimeData->hasText();
2615     else
2616         d->canPaste = false;
2617 #endif
2618
2619     bool changed = d->canPaste != old || !d->canPasteValid;
2620     d->canPasteValid = true;
2621     if (changed)
2622         emit canPasteChanged();
2623
2624 }
2625
2626 void QQuickTextInput::q_updateAlignment()
2627 {
2628     Q_D(QQuickTextInput);
2629     if (d->determineHorizontalAlignment()) {
2630         d->updateLayout();
2631         updateCursorRectangle();
2632     }
2633 }
2634
2635 // ### these should come from QStyleHints
2636 const int textCursorWidth = 1;
2637 const bool fullWidthSelection = true;
2638
2639 /*!
2640     \internal
2641
2642     Updates the display text based of the current edit text
2643     If the text has changed will emit displayTextChanged()
2644 */
2645 void QQuickTextInputPrivate::updateDisplayText(bool forceUpdate)
2646 {
2647     QString orig = m_textLayout.text();
2648     QString str;
2649     if (m_echoMode == QQuickTextInput::NoEcho)
2650         str = QString::fromLatin1("");
2651     else
2652         str = m_text;
2653
2654     if (m_echoMode == QQuickTextInput::Password) {
2655          str.fill(m_passwordCharacter);
2656         if (m_passwordEchoTimer.isActive() && m_cursor > 0 && m_cursor <= m_text.length()) {
2657             int cursor = m_cursor - 1;
2658             QChar uc = m_text.at(cursor);
2659             str[cursor] = uc;
2660             if (cursor > 0 && uc.unicode() >= 0xdc00 && uc.unicode() < 0xe000) {
2661                 // second half of a surrogate, check if we have the first half as well,
2662                 // if yes restore both at once
2663                 uc = m_text.at(cursor - 1);
2664                 if (uc.unicode() >= 0xd800 && uc.unicode() < 0xdc00)
2665                     str[cursor - 1] = uc;
2666             }
2667         }
2668     } else if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit && !m_passwordEchoEditing) {
2669         str.fill(m_passwordCharacter);
2670     }
2671
2672     // replace certain non-printable characters with spaces (to avoid
2673     // drawing boxes when using fonts that don't have glyphs for such
2674     // characters)
2675     QChar* uc = str.data();
2676     for (int i = 0; i < (int)str.length(); ++i) {
2677         if ((uc[i] < 0x20 && uc[i] != 0x09)
2678             || uc[i] == QChar::LineSeparator
2679             || uc[i] == QChar::ParagraphSeparator
2680             || uc[i] == QChar::ObjectReplacementCharacter)
2681             uc[i] = QChar(0x0020);
2682     }
2683
2684     if (str != orig || forceUpdate) {
2685         m_textLayout.setText(str);
2686         updateLayout(); // polish?
2687         emit q_func()->displayTextChanged();
2688     }
2689 }
2690
2691 qreal QQuickTextInputPrivate::getImplicitWidth() const
2692 {
2693     Q_Q(const QQuickTextInput);
2694     if (!requireImplicitWidth) {
2695         QQuickTextInputPrivate *d = const_cast<QQuickTextInputPrivate *>(this);
2696         d->requireImplicitWidth = true;
2697
2698         if (q->isComponentComplete()) {
2699             // One time cost, only incurred if implicitWidth is first requested after
2700             // componentComplete.
2701             QTextLayout layout(m_text);
2702
2703             QTextOption option = m_textLayout.textOption();
2704             option.setTextDirection(m_layoutDirection);
2705             option.setFlags(QTextOption::IncludeTrailingSpaces);
2706             option.setWrapMode(QTextOption::WrapMode(wrapMode));
2707             option.setAlignment(Qt::Alignment(q->effectiveHAlign()));
2708             layout.setTextOption(option);
2709             layout.setFont(font);
2710             layout.setPreeditArea(m_textLayout.preeditAreaPosition(), m_textLayout.preeditAreaText());
2711             layout.beginLayout();
2712
2713             QTextLine line = layout.createLine();
2714             line.setLineWidth(INT_MAX);
2715             d->implicitWidth = qCeil(line.naturalTextWidth());
2716
2717             layout.endLayout();
2718         }
2719     }
2720     return implicitWidth;
2721 }
2722
2723 void QQuickTextInputPrivate::updateLayout()
2724 {
2725     Q_Q(QQuickTextInput);
2726
2727     if (!q->isComponentComplete())
2728         return;
2729
2730     const QRectF previousRect = boundingRect;
2731
2732     QTextOption option = m_textLayout.textOption();
2733     option.setTextDirection(layoutDirection());
2734     option.setWrapMode(QTextOption::WrapMode(wrapMode));
2735     option.setAlignment(Qt::Alignment(q->effectiveHAlign()));
2736     m_textLayout.setTextOption(option);
2737     m_textLayout.setFont(font);
2738
2739     boundingRect = QRectF();
2740     m_textLayout.beginLayout();
2741     QTextLine line = m_textLayout.createLine();
2742     if (requireImplicitWidth) {
2743         line.setLineWidth(INT_MAX);
2744         const bool wasInLayout = inLayout;
2745         inLayout = true;
2746         q->setImplicitWidth(qCeil(line.naturalTextWidth()));
2747         inLayout = wasInLayout;
2748         if (inLayout)       // probably the result of a binding loop, but by letting it
2749             return;         // get this far we'll get a warning to that effect.
2750     }
2751     qreal lineWidth = q->widthValid() ? q->width() : INT_MAX;
2752     qreal height = 0;
2753     do {
2754         line.setLineWidth(lineWidth);
2755         line.setPosition(QPointF(line.position().x(), height));
2756         boundingRect = boundingRect.united(line.naturalTextRect());
2757
2758         height += line.height();
2759         line = m_textLayout.createLine();
2760     } while (line.isValid());
2761     m_textLayout.endLayout();
2762
2763     option.setWrapMode(QTextOption::NoWrap);
2764     m_textLayout.setTextOption(option);
2765
2766     textLayoutDirty = true;
2767
2768     updateType = UpdatePaintNode;
2769     q->update();
2770
2771     if (!requireImplicitWidth && !q->widthValid())
2772         q->setImplicitSize(qCeil(boundingRect.width()), qCeil(boundingRect.height()));
2773     else
2774         q->setImplicitHeight(qCeil(boundingRect.height()));
2775
2776     if (previousRect != boundingRect)
2777         emit q->contentSizeChanged();
2778 }
2779
2780 #ifndef QT_NO_CLIPBOARD
2781 /*!
2782     \internal
2783
2784     Copies the currently selected text into the clipboard using the given
2785     \a mode.
2786
2787     \note If the echo mode is set to a mode other than Normal then copy
2788     will not work.  This is to prevent using copy as a method of bypassing
2789     password features of the line control.
2790 */
2791 void QQuickTextInputPrivate::copy(QClipboard::Mode mode) const
2792 {
2793     QString t = selectedText();
2794     if (!t.isEmpty() && m_echoMode == QQuickTextInput::Normal) {
2795         QGuiApplication::clipboard()->setText(t, mode);
2796     }
2797 }
2798
2799 /*!
2800     \internal
2801
2802     Inserts the text stored in the application clipboard into the line
2803     control.
2804
2805     \sa insert()
2806 */
2807 void QQuickTextInputPrivate::paste(QClipboard::Mode clipboardMode)
2808 {
2809     QString clip = QGuiApplication::clipboard()->text(clipboardMode);
2810     if (!clip.isEmpty() || hasSelectedText()) {
2811         separate(); //make it a separate undo/redo command
2812         insert(clip);
2813         separate();
2814     }
2815 }
2816
2817 #endif // !QT_NO_CLIPBOARD
2818
2819 /*!
2820     \internal
2821 */
2822 void QQuickTextInputPrivate::commitPreedit()
2823 {
2824     Q_Q(QQuickTextInput);
2825
2826     if (!hasImState)
2827         return;
2828
2829     qApp->inputMethod()->commit();
2830
2831     if (!hasImState)
2832         return;
2833
2834     QInputMethodEvent ev;
2835     QCoreApplication::sendEvent(q, &ev);
2836 }
2837
2838 void QQuickTextInputPrivate::cancelPreedit()
2839 {
2840     Q_Q(QQuickTextInput);
2841
2842     if (!hasImState)
2843         return;
2844
2845     qApp->inputMethod()->reset();
2846
2847     QInputMethodEvent ev;
2848     QCoreApplication::sendEvent(q, &ev);
2849 }
2850
2851 /*!
2852     \internal
2853
2854     Handles the behavior for the backspace key or function.
2855     Removes the current selection if there is a selection, otherwise
2856     removes the character prior to the cursor position.
2857
2858     \sa del()
2859 */
2860 void QQuickTextInputPrivate::backspace()
2861 {
2862     int priorState = m_undoState;
2863     if (hasSelectedText()) {
2864         removeSelectedText();
2865     } else if (m_cursor) {
2866             --m_cursor;
2867             if (m_maskData)
2868                 m_cursor = prevMaskBlank(m_cursor);
2869             QChar uc = m_text.at(m_cursor);
2870             if (m_cursor > 0 && uc.unicode() >= 0xdc00 && uc.unicode() < 0xe000) {
2871                 // second half of a surrogate, check if we have the first half as well,
2872                 // if yes delete both at once
2873                 uc = m_text.at(m_cursor - 1);
2874                 if (uc.unicode() >= 0xd800 && uc.unicode() < 0xdc00) {
2875                     internalDelete(true);
2876                     --m_cursor;
2877                 }
2878             }
2879             internalDelete(true);
2880     }
2881     finishChange(priorState);
2882 }
2883
2884 /*!
2885     \internal
2886
2887     Handles the behavior for the delete key or function.
2888     Removes the current selection if there is a selection, otherwise
2889     removes the character after the cursor position.
2890
2891     \sa del()
2892 */
2893 void QQuickTextInputPrivate::del()
2894 {
2895     int priorState = m_undoState;
2896     if (hasSelectedText()) {
2897         removeSelectedText();
2898     } else {
2899         int n = m_textLayout.nextCursorPosition(m_cursor) - m_cursor;
2900         while (n--)
2901             internalDelete();
2902     }
2903     finishChange(priorState);
2904 }
2905
2906 /*!
2907     \internal
2908
2909     Inserts the given \a newText at the current cursor position.
2910     If there is any selected text it is removed prior to insertion of
2911     the new text.
2912 */
2913 void QQuickTextInputPrivate::insert(const QString &newText)
2914 {
2915     int priorState = m_undoState;
2916     removeSelectedText();
2917     internalInsert(newText);
2918     finishChange(priorState);
2919 }
2920
2921 /*!
2922     \internal
2923
2924     Clears the line control text.
2925 */
2926 void QQuickTextInputPrivate::clear()
2927 {
2928     int priorState = m_undoState;
2929     m_selstart = 0;
2930     m_selend = m_text.length();
2931     removeSelectedText();
2932     separate();
2933     finishChange(priorState, /*update*/false, /*edited*/false);
2934 }
2935
2936 /*!
2937     \internal
2938
2939     Sets \a length characters from the given \a start position as selected.
2940     The given \a start position must be within the current text for
2941     the line control.  If \a length characters cannot be selected, then
2942     the selection will extend to the end of the current text.
2943 */
2944 void QQuickTextInputPrivate::setSelection(int start, int length)
2945 {
2946     Q_Q(QQuickTextInput);
2947     commitPreedit();
2948
2949     if (start < 0 || start > (int)m_text.length()){
2950         qWarning("QQuickTextInputPrivate::setSelection: Invalid start position");
2951         return;
2952     }
2953
2954     if (length > 0) {
2955         if (start == m_selstart && start + length == m_selend && m_cursor == m_selend)
2956             return;
2957         m_selstart = start;
2958         m_selend = qMin(start + length, (int)m_text.length());
2959         m_cursor = m_selend;
2960     } else if (length < 0){
2961         if (start == m_selend && start + length == m_selstart && m_cursor == m_selstart)
2962             return;
2963         m_selstart = qMax(start + length, 0);
2964         m_selend = start;
2965         m_cursor = m_selstart;
2966     } else if (m_selstart != m_selend) {
2967         m_selstart = 0;
2968         m_selend = 0;
2969         m_cursor = start;
2970     } else {
2971         m_cursor = start;
2972         emitCursorPositionChanged();
2973         return;
2974     }
2975     emit q->selectionChanged();
2976     emitCursorPositionChanged();
2977     q->updateInputMethod(Qt::ImCursorRectangle | Qt::ImAnchorPosition
2978                         | Qt::ImCursorPosition | Qt::ImCurrentSelection);
2979 }
2980
2981 /*!
2982     \internal
2983
2984     Sets the password echo editing to \a editing.  If password echo editing
2985     is true, then the text of the password is displayed even if the echo
2986     mode is set to QLineEdit::PasswordEchoOnEdit.  Password echoing editing
2987     does not affect other echo modes.
2988 */
2989 void QQuickTextInputPrivate::updatePasswordEchoEditing(bool editing)
2990 {
2991     cancelPasswordEchoTimer();
2992     m_passwordEchoEditing = editing;
2993     updateDisplayText();
2994 }
2995
2996 /*!
2997     \internal
2998
2999     Fixes the current text so that it is valid given any set validators.
3000
3001     Returns true if the text was changed.  Otherwise returns false.
3002 */
3003 bool QQuickTextInputPrivate::fixup() // this function assumes that validate currently returns != Acceptable
3004 {
3005 #ifndef QT_NO_VALIDATOR
3006     if (m_validator) {
3007         QString textCopy = m_text;
3008         int cursorCopy = m_cursor;
3009         m_validator->fixup(textCopy);
3010         if (m_validator->validate(textCopy, cursorCopy) == QValidator::Acceptable) {
3011             if (textCopy != m_text || cursorCopy != m_cursor)
3012                 internalSetText(textCopy, cursorCopy);
3013             return true;
3014         }
3015     }
3016 #endif
3017     return false;
3018 }
3019
3020 /*!
3021     \internal
3022
3023     Moves the cursor to the given position \a pos.   If \a mark is true will
3024     adjust the currently selected text.
3025 */
3026 void QQuickTextInputPrivate::moveCursor(int pos, bool mark)
3027 {
3028     Q_Q(QQuickTextInput);
3029     commitPreedit();
3030
3031     if (pos != m_cursor) {
3032         separate();
3033         if (m_maskData)
3034             pos = pos > m_cursor ? nextMaskBlank(pos) : prevMaskBlank(pos);
3035     }
3036     if (mark) {
3037         int anchor;
3038         if (m_selend > m_selstart && m_cursor == m_selstart)
3039             anchor = m_selend;
3040         else if (m_selend > m_selstart && m_cursor == m_selend)
3041             anchor = m_selstart;
3042         else
3043             anchor = m_cursor;
3044         m_selstart = qMin(anchor, pos);
3045         m_selend = qMax(anchor, pos);
3046     } else {
3047         internalDeselect();
3048     }
3049     m_cursor = pos;
3050     if (mark || m_selDirty) {
3051         m_selDirty = false;
3052         emit q->selectionChanged();
3053     }
3054     emitCursorPositionChanged();
3055     q->updateInputMethod();
3056 }
3057
3058 /*!
3059     \internal
3060
3061     Applies the given input method event \a event to the text of the line
3062     control
3063 */
3064 void QQuickTextInputPrivate::processInputMethodEvent(QInputMethodEvent *event)
3065 {
3066     Q_Q(QQuickTextInput);
3067
3068     int priorState = -1;
3069     bool isGettingInput = !event->commitString().isEmpty()
3070             || event->preeditString() != preeditAreaText()
3071             || event->replacementLength() > 0;
3072     bool cursorPositionChanged = false;
3073     bool selectionChange = false;
3074     m_preeditDirty = event->preeditString() != preeditAreaText();
3075
3076     if (isGettingInput) {
3077         // If any text is being input, remove selected text.
3078         priorState = m_undoState;
3079         if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit && !m_passwordEchoEditing) {
3080             updatePasswordEchoEditing(true);
3081             m_selstart = 0;
3082             m_selend = m_text.length();
3083         }
3084         removeSelectedText();
3085     }
3086
3087     int c = m_cursor; // cursor position after insertion of commit string
3088     if (event->replacementStart() <= 0)
3089         c += event->commitString().length() - qMin(-event->replacementStart(), event->replacementLength());
3090
3091     m_cursor += event->replacementStart();
3092     if (m_cursor < 0)
3093         m_cursor = 0;
3094
3095     // insert commit string
3096     if (event->replacementLength()) {
3097         m_selstart = m_cursor;
3098         m_selend = m_selstart + event->replacementLength();
3099         m_selend = qMin(m_selend, m_text.length());
3100         removeSelectedText();
3101     }
3102     if (!event->commitString().isEmpty()) {
3103         internalInsert(event->commitString());
3104         cursorPositionChanged = true;
3105     }
3106
3107     m_cursor = qBound(0, c, m_text.length());
3108
3109     for (int i = 0; i < event->attributes().size(); ++i) {
3110         const QInputMethodEvent::Attribute &a = event->attributes().at(i);
3111         if (a.type == QInputMethodEvent::Selection) {
3112             m_cursor = qBound(0, a.start + a.length, m_text.length());
3113             if (a.length) {
3114                 m_selstart = qMax(0, qMin(a.start, m_text.length()));
3115                 m_selend = m_cursor;
3116                 if (m_selend < m_selstart) {
3117                     qSwap(m_selstart, m_selend);
3118                 }
3119                 selectionChange = true;
3120             } else {
3121                 m_selstart = m_selend = 0;
3122             }
3123             cursorPositionChanged = true;
3124         }
3125     }
3126 #ifndef QT_NO_IM
3127     m_textLayout.setPreeditArea(m_cursor, event->preeditString());
3128 #endif //QT_NO_IM
3129     const int oldPreeditCursor = m_preeditCursor;
3130     const bool oldCursorVisible = cursorVisible;
3131     m_preeditCursor = event->preeditString().length();
3132     hasImState = !event->preeditString().isEmpty();
3133     cursorVisible = true;
3134     QList<QTextLayout::FormatRange> formats;
3135     for (int i = 0; i < event->attributes().size(); ++i) {
3136         const QInputMethodEvent::Attribute &a = event->attributes().at(i);
3137         if (a.type == QInputMethodEvent::Cursor) {
3138             hasImState = true;
3139             m_preeditCursor = a.start;
3140             cursorVisible = a.length != 0;
3141         } else if (a.type == QInputMethodEvent::TextFormat) {
3142             hasImState = true;
3143             QTextCharFormat f = qvariant_cast<QTextFormat>(a.value).toCharFormat();
3144             if (f.isValid()) {
3145                 QTextLayout::FormatRange o;
3146                 o.start = a.start + m_cursor;
3147                 o.length = a.length;
3148                 o.format = f;
3149                 formats.append(o);
3150             }
3151         }
3152     }
3153     m_textLayout.setAdditionalFormats(formats);
3154
3155     updateDisplayText(/*force*/ true);
3156     if (cursorPositionChanged) {
3157         emitCursorPositionChanged();
3158     } else if (m_preeditCursor != oldPreeditCursor) {
3159         q->updateCursorRectangle();
3160     }
3161
3162     if (isGettingInput)
3163         finishChange(priorState);
3164
3165     if (cursorVisible != oldCursorVisible)
3166         emit q->cursorVisibleChanged(cursorVisible);
3167
3168     if (selectionChange) {
3169         emit q->selectionChanged();
3170         q->updateInputMethod(Qt::ImCursorRectangle | Qt::ImAnchorPosition
3171                             | Qt::ImCursorPosition | Qt::ImCurrentSelection);
3172     }
3173 }
3174
3175 /*!
3176     \internal
3177
3178     Sets the selection to cover the word at the given cursor position.
3179     The word boundaries are defined by the behavior of QTextLayout::SkipWords
3180     cursor mode.
3181 */
3182 void QQuickTextInputPrivate::selectWordAtPos(int cursor)
3183 {
3184     int next = cursor + 1;
3185     if (next > end())
3186         --next;
3187     int c = m_textLayout.previousCursorPosition(next, QTextLayout::SkipWords);
3188     moveCursor(c, false);
3189     // ## text layout should support end of words.
3190     int end = m_textLayout.nextCursorPosition(c, QTextLayout::SkipWords);
3191     while (end > cursor && m_text[end-1].isSpace())
3192         --end;
3193     moveCursor(end, true);
3194 }
3195
3196 /*!
3197     \internal
3198
3199     Completes a change to the line control text.  If the change is not valid
3200     will undo the line control state back to the given \a validateFromState.
3201
3202     If \a edited is true and the change is valid, will emit textEdited() in
3203     addition to textChanged().  Otherwise only emits textChanged() on a valid
3204     change.
3205
3206     The \a update value is currently unused.
3207 */
3208 bool QQuickTextInputPrivate::finishChange(int validateFromState, bool update, bool /*edited*/)
3209 {
3210     Q_Q(QQuickTextInput);
3211
3212     Q_UNUSED(update)
3213     bool inputMethodAttributesChanged = m_textDirty || m_selDirty;
3214     bool alignmentChanged = false;
3215
3216     if (m_textDirty) {
3217         // do validation
3218         bool wasValidInput = m_validInput;
3219         bool wasAcceptable = m_acceptableInput;
3220         m_validInput = true;
3221         m_acceptableInput = true;
3222 #ifndef QT_NO_VALIDATOR
3223         if (m_validator) {
3224             QString textCopy = m_text;
3225             int cursorCopy = m_cursor;
3226             QValidator::State state = m_validator->validate(textCopy, cursorCopy);
3227             m_validInput = state != QValidator::Invalid;
3228             m_acceptableInput = state == QValidator::Acceptable;
3229             if (m_validInput) {
3230                 if (m_text != textCopy) {
3231                     internalSetText(textCopy, cursorCopy);
3232                     return true;
3233                 }
3234                 m_cursor = cursorCopy;
3235             }
3236         }
3237 #endif
3238         if (validateFromState >= 0 && wasValidInput && !m_validInput) {
3239             if (m_transactions.count())
3240                 return false;
3241             internalUndo(validateFromState);
3242             m_history.resize(m_undoState);
3243             m_validInput = true;
3244             m_acceptableInput = wasAcceptable;
3245             m_textDirty = false;
3246         }
3247
3248         if (m_textDirty) {
3249             m_textDirty = false;
3250             m_preeditDirty = false;
3251             alignmentChanged = determineHorizontalAlignment();
3252             emit q->textChanged();
3253         }
3254
3255         updateDisplayText(alignmentChanged);
3256
3257         if (m_acceptableInput != wasAcceptable)
3258             emit q->acceptableInputChanged();
3259     }
3260     if (m_preeditDirty) {
3261         m_preeditDirty = false;
3262         if (determineHorizontalAlignment()) {
3263             alignmentChanged = true;
3264             updateLayout();
3265         }
3266     }
3267
3268     if (m_selDirty) {
3269         m_selDirty = false;
3270         emit q->selectionChanged();
3271     }
3272
3273     inputMethodAttributesChanged |= (m_cursor == m_lastCursorPos);
3274     if (inputMethodAttributesChanged)
3275         q->updateInputMethod();
3276     emitUndoRedoChanged();
3277
3278     if (!emitCursorPositionChanged() && alignmentChanged)
3279         q->updateCursorRectangle();
3280
3281     return true;
3282 }
3283
3284 /*!
3285     \internal
3286
3287     An internal function for setting the text of the line control.
3288 */
3289 void QQuickTextInputPrivate::internalSetText(const QString &txt, int pos, bool edited)
3290 {
3291     Q_Q(QQuickTextInput);
3292     internalDeselect();
3293     QString oldText = m_text;
3294     if (m_maskData) {
3295         m_text = maskString(0, txt, true);
3296         m_text += clearString(m_text.length(), m_maxLength - m_text.length());
3297     } else {
3298         m_text = txt.isEmpty() ? txt : txt.left(m_maxLength);
3299     }
3300     m_history.clear();
3301     m_undoState = 0;
3302     m_cursor = (pos < 0 || pos > m_text.length()) ? m_text.length() : pos;
3303     m_textDirty = (oldText != m_text);
3304
3305     bool changed = finishChange(-1, true, edited);
3306 #ifdef QT_NO_ACCESSIBILITY
3307     Q_UNUSED(changed)
3308 #else
3309     if (changed) {
3310         QAccessibleTextUpdateEvent ev(q, 0, oldText, m_text);
3311         QAccessible::updateAccessibility(&ev);
3312     }
3313 #endif
3314 }
3315
3316
3317 /*!
3318     \internal
3319
3320     Adds the given \a command to the undo history
3321     of the line control.  Does not apply the command.
3322 */
3323 void QQuickTextInputPrivate::addCommand(const Command &cmd)
3324 {
3325     if (m_separator && m_undoState && m_history[m_undoState - 1].type != Separator) {
3326         m_history.resize(m_undoState + 2);
3327         m_history[m_undoState++] = Command(Separator, m_cursor, 0, m_selstart, m_selend);
3328     } else {
3329         m_history.resize(m_undoState + 1);
3330     }
3331     m_separator = false;
3332     m_history[m_undoState++] = cmd;
3333 }
3334
3335 /*!
3336     \internal
3337
3338     Inserts the given string \a s into the line
3339     control.
3340
3341     Also adds the appropriate commands into the undo history.
3342     This function does not call finishChange(), and may leave the text
3343     in an invalid state.
3344 */
3345 void QQuickTextInputPrivate::internalInsert(const QString &s)
3346 {
3347     Q_Q(QQuickTextInput);
3348     if (m_echoMode == QQuickTextInput::Password) {
3349         int delay = qGuiApp->styleHints()->passwordMaskDelay();
3350         if (delay > 0)
3351             m_passwordEchoTimer.start(delay, q);
3352     }
3353     if (hasSelectedText())
3354         addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
3355     if (m_maskData) {
3356         QString ms = maskString(m_cursor, s);
3357         for (int i = 0; i < (int) ms.length(); ++i) {
3358             addCommand (Command(DeleteSelection, m_cursor + i, m_text.at(m_cursor + i), -1, -1));
3359             addCommand(Command(Insert, m_cursor + i, ms.at(i), -1, -1));
3360         }
3361         m_text.replace(m_cursor, ms.length(), ms);
3362         m_cursor += ms.length();
3363         m_cursor = nextMaskBlank(m_cursor);
3364         m_textDirty = true;
3365     } else {
3366         int remaining = m_maxLength - m_text.length();
3367         if (remaining != 0) {
3368             m_text.insert(m_cursor, s.left(remaining));
3369             for (int i = 0; i < (int) s.left(remaining).length(); ++i)
3370                addCommand(Command(Insert, m_cursor++, s.at(i), -1, -1));
3371             m_textDirty = true;
3372         }
3373     }
3374 }
3375
3376 /*!
3377     \internal
3378
3379     deletes a single character from the current text.  If \a wasBackspace,
3380     the character prior to the cursor is removed.  Otherwise the character
3381     after the cursor is removed.
3382
3383     Also adds the appropriate commands into the undo history.
3384     This function does not call finishChange(), and may leave the text
3385     in an invalid state.
3386 */
3387 void QQuickTextInputPrivate::internalDelete(bool wasBackspace)
3388 {
3389     if (m_cursor < (int) m_text.length()) {
3390         cancelPasswordEchoTimer();
3391         if (hasSelectedText())
3392             addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
3393         addCommand(Command((CommandType)((m_maskData ? 2 : 0) + (wasBackspace ? Remove : Delete)),
3394                    m_cursor, m_text.at(m_cursor), -1, -1));
3395         if (m_maskData) {
3396             m_text.replace(m_cursor, 1, clearString(m_cursor, 1));
3397             addCommand(Command(Insert, m_cursor, m_text.at(m_cursor), -1, -1));
3398         } else {
3399             m_text.remove(m_cursor, 1);
3400         }
3401         m_textDirty = true;
3402     }
3403 }
3404
3405 /*!
3406     \internal
3407
3408     removes the currently selected text from the line control.
3409
3410     Also adds the appropriate commands into the undo history.
3411     This function does not call finishChange(), and may leave the text
3412     in an invalid state.
3413 */
3414 void QQuickTextInputPrivate::removeSelectedText()
3415 {
3416     if (m_selstart < m_selend && m_selend <= (int) m_text.length()) {
3417         cancelPasswordEchoTimer();
3418         separate();
3419         int i ;
3420         addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
3421         if (m_selstart <= m_cursor && m_cursor < m_selend) {
3422             // cursor is within the selection. Split up the commands
3423             // to be able to restore the correct cursor position
3424             for (i = m_cursor; i >= m_selstart; --i)
3425                 addCommand (Command(DeleteSelection, i, m_text.at(i), -1, 1));
3426             for (i = m_selend - 1; i > m_cursor; --i)
3427                 addCommand (Command(DeleteSelection, i - m_cursor + m_selstart - 1, m_text.at(i), -1, -1));
3428         } else {
3429             for (i = m_selend-1; i >= m_selstart; --i)
3430                 addCommand (Command(RemoveSelection, i, m_text.at(i), -1, -1));
3431         }
3432         if (m_maskData) {
3433             m_text.replace(m_selstart, m_selend - m_selstart,  clearString(m_selstart, m_selend - m_selstart));
3434             for (int i = 0; i < m_selend - m_selstart; ++i)
3435                 addCommand(Command(Insert, m_selstart + i, m_text.at(m_selstart + i), -1, -1));
3436         } else {
3437             m_text.remove(m_selstart, m_selend - m_selstart);
3438         }
3439         if (m_cursor > m_selstart)
3440             m_cursor -= qMin(m_cursor, m_selend) - m_selstart;
3441         internalDeselect();
3442         m_textDirty = true;
3443     }
3444 }
3445
3446 /*!
3447     \internal
3448
3449     Parses the input mask specified by \a maskFields to generate
3450     the mask data used to handle input masks.
3451 */
3452 void QQuickTextInputPrivate::parseInputMask(const QString &maskFields)
3453 {
3454     int delimiter = maskFields.indexOf(QLatin1Char(';'));
3455     if (maskFields.isEmpty() || delimiter == 0) {
3456         if (m_maskData) {
3457             delete [] m_maskData;
3458             m_maskData = 0;
3459             m_maxLength = 32767;
3460             internalSetText(QString());
3461         }
3462         return;
3463     }
3464
3465     if (delimiter == -1) {
3466         m_blank = QLatin1Char(' ');
3467         m_inputMask = maskFields;
3468     } else {
3469         m_inputMask = maskFields.left(delimiter);
3470         m_blank = (delimiter + 1 < maskFields.length()) ? maskFields[delimiter + 1] : QLatin1Char(' ');
3471     }
3472
3473     // calculate m_maxLength / m_maskData length
3474     m_maxLength = 0;
3475     QChar c = 0;
3476     for (int i=0; i<m_inputMask.length(); i++) {
3477         c = m_inputMask.at(i);
3478         if (i > 0 && m_inputMask.at(i-1) == QLatin1Char('\\')) {
3479             m_maxLength++;
3480             continue;
3481         }
3482         if (c != QLatin1Char('\\') && c != QLatin1Char('!') &&
3483              c != QLatin1Char('<') && c != QLatin1Char('>') &&
3484              c != QLatin1Char('{') && c != QLatin1Char('}') &&
3485              c != QLatin1Char('[') && c != QLatin1Char(']'))
3486             m_maxLength++;
3487     }
3488
3489     delete [] m_maskData;
3490     m_maskData = new MaskInputData[m_maxLength];
3491
3492     MaskInputData::Casemode m = MaskInputData::NoCaseMode;
3493     c = 0;
3494     bool s;
3495     bool escape = false;
3496     int index = 0;
3497     for (int i = 0; i < m_inputMask.length(); i++) {
3498         c = m_inputMask.at(i);
3499         if (escape) {
3500             s = true;
3501             m_maskData[index].maskChar = c;
3502             m_maskData[index].separator = s;
3503             m_maskData[index].caseMode = m;
3504             index++;
3505             escape = false;
3506         } else if (c == QLatin1Char('<')) {
3507                 m = MaskInputData::Lower;
3508         } else if (c == QLatin1Char('>')) {
3509             m = MaskInputData::Upper;
3510         } else if (c == QLatin1Char('!')) {
3511             m = MaskInputData::NoCaseMode;
3512         } else if (c != QLatin1Char('{') && c != QLatin1Char('}') && c != QLatin1Char('[') && c != QLatin1Char(']')) {
3513             switch (c.unicode()) {
3514             case 'A':
3515             case 'a':
3516             case 'N':
3517             case 'n':
3518             case 'X':
3519             case 'x':
3520             case '9':
3521             case '0':
3522             case 'D':
3523             case 'd':
3524             case '#':
3525             case 'H':
3526             case 'h':
3527             case 'B':
3528             case 'b':
3529                 s = false;
3530                 break;
3531             case '\\':
3532                 escape = true;
3533             default:
3534                 s = true;
3535                 break;
3536             }
3537
3538             if (!escape) {
3539                 m_maskData[index].maskChar = c;
3540                 m_maskData[index].separator = s;
3541                 m_maskData[index].caseMode = m;
3542                 index++;
3543             }
3544         }
3545     }
3546     internalSetText(m_text);
3547 }
3548
3549
3550 /*!
3551     \internal
3552
3553     checks if the key is valid compared to the inputMask
3554 */
3555 bool QQuickTextInputPrivate::isValidInput(QChar key, QChar mask) const
3556 {
3557     switch (mask.unicode()) {
3558     case 'A':
3559         if (key.isLetter())
3560             return true;
3561         break;
3562     case 'a':
3563         if (key.isLetter() || key == m_blank)
3564             return true;
3565         break;
3566     case 'N':
3567         if (key.isLetterOrNumber())
3568             return true;
3569         break;
3570     case 'n':
3571         if (key.isLetterOrNumber() || key == m_blank)
3572             return true;
3573         break;
3574     case 'X':
3575         if (key.isPrint())
3576             return true;
3577         break;
3578     case 'x':
3579         if (key.isPrint() || key == m_blank)
3580             return true;
3581         break;
3582     case '9':
3583         if (key.isNumber())
3584             return true;
3585         break;
3586     case '0':
3587         if (key.isNumber() || key == m_blank)
3588             return true;
3589         break;
3590     case 'D':
3591         if (key.isNumber() && key.digitValue() > 0)
3592             return true;
3593         break;
3594     case 'd':
3595         if ((key.isNumber() && key.digitValue() > 0) || key == m_blank)
3596             return true;
3597         break;
3598     case '#':
3599         if (key.isNumber() || key == QLatin1Char('+') || key == QLatin1Char('-') || key == m_blank)
3600             return true;
3601         break;
3602     case 'B':
3603         if (key == QLatin1Char('0') || key == QLatin1Char('1'))
3604             return true;
3605         break;
3606     case 'b':
3607         if (key == QLatin1Char('0') || key == QLatin1Char('1') || key == m_blank)
3608             return true;
3609         break;
3610     case 'H':
3611         if (key.isNumber() || (key >= QLatin1Char('a') && key <= QLatin1Char('f')) || (key >= QLatin1Char('A') && key <= QLatin1Char('F')))
3612             return true;
3613         break;
3614     case 'h':
3615         if (key.isNumber() || (key >= QLatin1Char('a') && key <= QLatin1Char('f')) || (key >= QLatin1Char('A') && key <= QLatin1Char('F')) || key == m_blank)
3616             return true;
3617         break;
3618     default:
3619         break;
3620     }
3621     return false;
3622 }
3623
3624 /*!
3625     \internal
3626
3627     Returns true if the given text \a str is valid for any
3628     validator or input mask set for the line control.
3629
3630     Otherwise returns false
3631 */
3632 QQuickTextInputPrivate::ValidatorState QQuickTextInputPrivate::hasAcceptableInput(const QString &str) const
3633 {
3634 #ifndef QT_NO_VALIDATOR
3635     QString textCopy = str;
3636     int cursorCopy = m_cursor;
3637     if (m_validator) {
3638         QValidator::State state = m_validator->validate(textCopy, cursorCopy);
3639         if (state != QValidator::Acceptable)
3640             return ValidatorState(state);
3641     }
3642 #endif
3643
3644     if (!m_maskData)
3645         return AcceptableInput;
3646
3647     if (str.length() != m_maxLength)
3648         return InvalidInput;
3649
3650     for (int i=0; i < m_maxLength; ++i) {
3651         if (m_maskData[i].separator) {
3652             if (str.at(i) != m_maskData[i].maskChar)
3653                 return InvalidInput;
3654         } else {
3655             if (!isValidInput(str.at(i), m_maskData[i].maskChar))
3656                 return InvalidInput;
3657         }
3658     }
3659     return AcceptableInput;
3660 }
3661
3662 /*!
3663     \internal
3664
3665     Applies the inputMask on \a str starting from position \a pos in the mask. \a clear
3666     specifies from where characters should be gotten when a separator is met in \a str - true means
3667     that blanks will be used, false that previous input is used.
3668     Calling this when no inputMask is set is undefined.
3669 */
3670 QString QQuickTextInputPrivate::maskString(uint pos, const QString &str, bool clear) const
3671 {
3672     if (pos >= (uint)m_maxLength)
3673         return QString::fromLatin1("");
3674
3675     QString fill;
3676     fill = clear ? clearString(0, m_maxLength) : m_text;
3677
3678     int strIndex = 0;
3679     QString s = QString::fromLatin1("");
3680     int i = pos;
3681     while (i < m_maxLength) {
3682         if (strIndex < str.length()) {
3683             if (m_maskData[i].separator) {
3684                 s += m_maskData[i].maskChar;
3685                 if (str[(int)strIndex] == m_maskData[i].maskChar)
3686                     strIndex++;
3687                 ++i;
3688             } else {
3689                 if (isValidInput(str[(int)strIndex], m_maskData[i].maskChar)) {
3690                     switch (m_maskData[i].caseMode) {
3691                     case MaskInputData::Upper:
3692                         s += str[(int)strIndex].toUpper();
3693                         break;
3694                     case MaskInputData::Lower:
3695                         s += str[(int)strIndex].toLower();
3696                         break;
3697                     default:
3698                         s += str[(int)strIndex];
3699                     }
3700                     ++i;
3701                 } else {
3702                     // search for separator first
3703                     int n = findInMask(i, true, true, str[(int)strIndex]);
3704                     if (n != -1) {
3705                         if (str.length() != 1 || i == 0 || (i > 0 && (!m_maskData[i-1].separator || m_maskData[i-1].maskChar != str[(int)strIndex]))) {
3706                             s += fill.mid(i, n-i+1);
3707                             i = n + 1; // update i to find + 1
3708                         }
3709                     } else {
3710                         // search for valid m_blank if not
3711                         n = findInMask(i, true, false, str[(int)strIndex]);
3712                         if (n != -1) {
3713                             s += fill.mid(i, n-i);
3714                             switch (m_maskData[n].caseMode) {
3715                             case MaskInputData::Upper:
3716                                 s += str[(int)strIndex].toUpper();
3717                                 break;
3718                             case MaskInputData::Lower:
3719                                 s += str[(int)strIndex].toLower();
3720                                 break;
3721                             default:
3722                                 s += str[(int)strIndex];
3723                             }
3724                             i = n + 1; // updates i to find + 1
3725                         }
3726                     }
3727                 }
3728                 ++strIndex;
3729             }
3730         } else
3731             break;
3732     }
3733
3734     return s;
3735 }
3736
3737
3738
3739 /*!
3740     \internal
3741
3742     Returns a "cleared" string with only separators and blank chars.
3743     Calling this when no inputMask is set is undefined.
3744 */
3745 QString QQuickTextInputPrivate::clearString(uint pos, uint len) const
3746 {
3747     if (pos >= (uint)m_maxLength)
3748         return QString();
3749
3750     QString s;
3751     int end = qMin((uint)m_maxLength, pos + len);
3752     for (int i = pos; i < end; ++i)
3753         if (m_maskData[i].separator)
3754             s += m_maskData[i].maskChar;
3755         else
3756             s += m_blank;
3757
3758     return s;
3759 }
3760
3761 /*!
3762     \internal
3763
3764     Strips blank parts of the input in a QQuickTextInputPrivate when an inputMask is set,
3765     separators are still included. Typically "127.0__.0__.1__" becomes "127.0.0.1".
3766 */
3767 QString QQuickTextInputPrivate::stripString(const QString &str) const
3768 {
3769     if (!m_maskData)
3770         return str;
3771
3772     QString s;
3773     int end = qMin(m_maxLength, (int)str.length());
3774     for (int i = 0; i < end; ++i) {
3775         if (m_maskData[i].separator)
3776             s += m_maskData[i].maskChar;
3777         else if (str[i] != m_blank)
3778             s += str[i];
3779     }
3780
3781     return s;
3782 }
3783
3784 /*!
3785     \internal
3786     searches forward/backward in m_maskData for either a separator or a m_blank
3787 */
3788 int QQuickTextInputPrivate::findInMask(int pos, bool forward, bool findSeparator, QChar searchChar) const
3789 {
3790     if (pos >= m_maxLength || pos < 0)
3791         return -1;
3792
3793     int end = forward ? m_maxLength : -1;
3794     int step = forward ? 1 : -1;
3795     int i = pos;
3796
3797     while (i != end) {
3798         if (findSeparator) {
3799             if (m_maskData[i].separator && m_maskData[i].maskChar == searchChar)
3800                 return i;
3801         } else {
3802             if (!m_maskData[i].separator) {
3803                 if (searchChar.isNull())
3804                     return i;
3805                 else if (isValidInput(searchChar, m_maskData[i].maskChar))
3806                     return i;
3807             }
3808         }
3809         i += step;
3810     }
3811     return -1;
3812 }
3813
3814 void QQuickTextInputPrivate::internalUndo(int until)
3815 {
3816     if (!isUndoAvailable())
3817         return;
3818     cancelPasswordEchoTimer();
3819     internalDeselect();
3820     while (m_undoState && m_undoState > until) {
3821         Command& cmd = m_history[--m_undoState];
3822         switch (cmd.type) {
3823         case Insert:
3824             m_text.remove(cmd.pos, 1);
3825             m_cursor = cmd.pos;
3826             break;
3827         case SetSelection:
3828             m_selstart = cmd.selStart;
3829             m_selend = cmd.selEnd;
3830             m_cursor = cmd.pos;
3831             break;
3832         case Remove:
3833         case RemoveSelection:
3834             m_text.insert(cmd.pos, cmd.uc);
3835             m_cursor = cmd.pos + 1;
3836             break;
3837         case Delete:
3838         case DeleteSelection:
3839             m_text.insert(cmd.pos, cmd.uc);
3840             m_cursor = cmd.pos;
3841             break;
3842         case Separator:
3843             continue;
3844         }
3845         if (until < 0 && m_undoState) {
3846             Command& next = m_history[m_undoState-1];
3847             if (next.type != cmd.type && next.type < RemoveSelection
3848                  && (cmd.type < RemoveSelection || next.type == Separator))
3849                 break;
3850         }
3851     }
3852     m_textDirty = true;
3853 }
3854
3855 void QQuickTextInputPrivate::internalRedo()
3856 {
3857     if (!isRedoAvailable())
3858         return;
3859     internalDeselect();
3860     while (m_undoState < (int)m_history.size()) {
3861         Command& cmd = m_history[m_undoState++];
3862         switch (cmd.type) {
3863         case Insert:
3864             m_text.insert(cmd.pos, cmd.uc);
3865             m_cursor = cmd.pos + 1;
3866             break;
3867         case SetSelection:
3868             m_selstart = cmd.selStart;
3869             m_selend = cmd.selEnd;
3870             m_cursor = cmd.pos;
3871             break;
3872         case Remove:
3873         case Delete:
3874         case RemoveSelection:
3875         case DeleteSelection:
3876             m_text.remove(cmd.pos, 1);
3877             m_selstart = cmd.selStart;
3878             m_selend = cmd.selEnd;
3879             m_cursor = cmd.pos;
3880             break;
3881         case Separator:
3882             m_selstart = cmd.selStart;
3883             m_selend = cmd.selEnd;
3884             m_cursor = cmd.pos;
3885             break;
3886         }
3887         if (m_undoState < (int)m_history.size()) {
3888             Command& next = m_history[m_undoState];
3889             if (next.type != cmd.type && cmd.type < RemoveSelection && next.type != Separator
3890                  && (next.type < RemoveSelection || cmd.type == Separator))
3891                 break;
3892         }
3893     }
3894     m_textDirty = true;
3895 }
3896
3897 void QQuickTextInputPrivate::emitUndoRedoChanged()
3898 {
3899     Q_Q(QQuickTextInput);
3900     const bool previousUndo = canUndo;
3901     const bool previousRedo = canRedo;
3902
3903     canUndo = isUndoAvailable();
3904     canRedo = isRedoAvailable();
3905
3906     if (previousUndo != canUndo)
3907         emit q->canUndoChanged();
3908     if (previousRedo != canRedo)
3909         emit q->canRedoChanged();
3910 }
3911
3912 /*!
3913     \internal
3914
3915     If the current cursor position differs from the last emitted cursor
3916     position, emits cursorPositionChanged().
3917 */
3918 bool QQuickTextInputPrivate::emitCursorPositionChanged()
3919 {
3920     Q_Q(QQuickTextInput);
3921     if (m_cursor != m_lastCursorPos) {
3922         m_lastCursorPos = m_cursor;
3923
3924         q->updateCursorRectangle();
3925         emit q->cursorPositionChanged();
3926
3927         if (!hasSelectedText()) {
3928             if (lastSelectionStart != m_cursor) {
3929                 lastSelectionStart = m_cursor;
3930                 emit q->selectionStartChanged();
3931             }
3932             if (lastSelectionEnd != m_cursor) {
3933                 lastSelectionEnd = m_cursor;
3934                 emit q->selectionEndChanged();
3935             }
3936         }
3937
3938 #ifndef QT_NO_ACCESSIBILITY
3939         QAccessibleTextCursorEvent ev(q, m_cursor);
3940         QAccessible::updateAccessibility(&ev);
3941 #endif
3942
3943         return true;
3944     }
3945     return false;
3946 }
3947
3948
3949 void QQuickTextInputPrivate::setCursorBlinkPeriod(int msec)
3950 {
3951     Q_Q(QQuickTextInput);
3952     if (msec == m_blinkPeriod)
3953         return;
3954     if (m_blinkTimer) {
3955         q->killTimer(m_blinkTimer);
3956     }
3957     if (msec) {
3958         m_blinkTimer = q->startTimer(msec / 2);
3959         m_blinkStatus = 1;
3960     } else {
3961         m_blinkTimer = 0;
3962         if (m_blinkStatus == 1) {
3963             updateType = UpdatePaintNode;
3964             q->update();
3965         }
3966     }
3967     m_blinkPeriod = msec;
3968 }
3969
3970 void QQuickTextInput::timerEvent(QTimerEvent *event)
3971 {
3972     Q_D(QQuickTextInput);
3973     if (event->timerId() == d->m_blinkTimer) {
3974         d->m_blinkStatus = !d->m_blinkStatus;
3975         d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
3976         update();
3977     } else if (event->timerId() == d->m_passwordEchoTimer.timerId()) {
3978         d->m_passwordEchoTimer.stop();
3979         d->updateDisplayText();
3980     }
3981 }
3982
3983 void QQuickTextInputPrivate::processKeyEvent(QKeyEvent* event)
3984 {
3985     Q_Q(QQuickTextInput);
3986     bool inlineCompletionAccepted = false;
3987
3988     if (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return) {
3989         if (hasAcceptableInput(m_text) || fixup()) {
3990             emit q->accepted();
3991         }
3992         if (inlineCompletionAccepted)
3993             event->accept();
3994         else
3995             event->ignore();
3996         return;
3997     }
3998
3999     if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit
4000         && !m_passwordEchoEditing
4001         && !m_readOnly
4002         && !event->text().isEmpty()
4003         && !(event->modifiers() & Qt::ControlModifier)) {
4004         // Clear the edit and reset to normal echo mode while editing; the
4005         // echo mode switches back when the edit loses focus
4006         // ### resets current content.  dubious code; you can
4007         // navigate with keys up, down, back, and select(?), but if you press
4008         // "left" or "right" it clears?
4009         updatePasswordEchoEditing(true);
4010         clear();
4011     }
4012
4013     bool unknown = false;
4014     bool visual = cursorMoveStyle() == Qt::VisualMoveStyle;
4015
4016     if (false) {
4017     }
4018 #ifndef QT_NO_SHORTCUT
4019     else if (event == QKeySequence::Undo) {
4020         q->undo();
4021     }
4022     else if (event == QKeySequence::Redo) {
4023         q->redo();
4024     }
4025     else if (event == QKeySequence::SelectAll) {
4026         selectAll();
4027     }
4028 #ifndef QT_NO_CLIPBOARD
4029     else if (event == QKeySequence::Copy) {
4030         copy();
4031     }
4032     else if (event == QKeySequence::Paste) {
4033         if (!m_readOnly) {
4034             QClipboard::Mode mode = QClipboard::Clipboard;
4035             paste(mode);
4036         }
4037     }
4038     else if (event == QKeySequence::Cut) {
4039         if (!m_readOnly) {
4040             copy();
4041             del();
4042         }
4043     }
4044     else if (event == QKeySequence::DeleteEndOfLine) {
4045         if (!m_readOnly) {
4046             setSelection(m_cursor, end());
4047             copy();
4048             del();
4049         }
4050     }
4051 #endif //QT_NO_CLIPBOARD
4052     else if (event == QKeySequence::MoveToStartOfLine || event == QKeySequence::MoveToStartOfBlock) {
4053         home(0);
4054     }
4055     else if (event == QKeySequence::MoveToEndOfLine || event == QKeySequence::MoveToEndOfBlock) {
4056         end(0);
4057     }
4058     else if (event == QKeySequence::SelectStartOfLine || event == QKeySequence::SelectStartOfBlock) {
4059         home(1);
4060     }
4061     else if (event == QKeySequence::SelectEndOfLine || event == QKeySequence::SelectEndOfBlock) {
4062         end(1);
4063     }
4064     else if (event == QKeySequence::MoveToNextChar) {
4065         if (hasSelectedText()) {
4066             moveCursor(selectionEnd(), false);
4067         } else {
4068             cursorForward(0, visual ? 1 : (layoutDirection() == Qt::LeftToRight ? 1 : -1));
4069         }
4070     }
4071     else if (event == QKeySequence::SelectNextChar) {
4072         cursorForward(1, visual ? 1 : (layoutDirection() == Qt::LeftToRight ? 1 : -1));
4073     }
4074     else if (event == QKeySequence::MoveToPreviousChar) {
4075         if (hasSelectedText()) {
4076             moveCursor(selectionStart(), false);
4077         } else {
4078             cursorForward(0, visual ? -1 : (layoutDirection() == Qt::LeftToRight ? -1 : 1));
4079         }
4080     }
4081     else if (event == QKeySequence::SelectPreviousChar) {
4082         cursorForward(1, visual ? -1 : (layoutDirection() == Qt::LeftToRight ? -1 : 1));
4083     }
4084     else if (event == QKeySequence::MoveToNextWord) {
4085         if (m_echoMode == QQuickTextInput::Normal)
4086             layoutDirection() == Qt::LeftToRight ? cursorWordForward(0) : cursorWordBackward(0);
4087         else
4088             layoutDirection() == Qt::LeftToRight ? end(0) : home(0);
4089     }
4090     else if (event == QKeySequence::MoveToPreviousWord) {
4091         if (m_echoMode == QQuickTextInput::Normal)
4092             layoutDirection() == Qt::LeftToRight ? cursorWordBackward(0) : cursorWordForward(0);
4093         else if (!m_readOnly) {
4094             layoutDirection() == Qt::LeftToRight ? home(0) : end(0);
4095         }
4096     }
4097     else if (event == QKeySequence::SelectNextWord) {
4098         if (m_echoMode == QQuickTextInput::Normal)
4099             layoutDirection() == Qt::LeftToRight ? cursorWordForward(1) : cursorWordBackward(1);
4100         else
4101             layoutDirection() == Qt::LeftToRight ? end(1) : home(1);
4102     }
4103     else if (event == QKeySequence::SelectPreviousWord) {
4104         if (m_echoMode == QQuickTextInput::Normal)
4105             layoutDirection() == Qt::LeftToRight ? cursorWordBackward(1) : cursorWordForward(1);
4106         else
4107             layoutDirection() == Qt::LeftToRight ? home(1) : end(1);
4108     }
4109     else if (event == QKeySequence::Delete) {
4110         if (!m_readOnly)
4111             del();
4112     }
4113     else if (event == QKeySequence::DeleteEndOfWord) {
4114         if (!m_readOnly) {
4115             cursorWordForward(true);
4116             del();
4117         }
4118     }
4119     else if (event == QKeySequence::DeleteStartOfWord) {
4120         if (!m_readOnly) {
4121             cursorWordBackward(true);
4122             del();
4123         }
4124     }
4125 #endif // QT_NO_SHORTCUT
4126     else {
4127         bool handled = false;
4128         if (event->modifiers() & Qt::ControlModifier) {
4129             switch (event->key()) {
4130             case Qt::Key_Backspace:
4131                 if (!m_readOnly) {
4132                     cursorWordBackward(true);
4133                     del();
4134                 }
4135                 break;
4136             default:
4137                 if (!handled)
4138                     unknown = true;
4139             }
4140         } else { // ### check for *no* modifier
4141             switch (event->key()) {
4142             case Qt::Key_Backspace:
4143                 if (!m_readOnly) {
4144                     backspace();
4145                 }
4146                 break;
4147             default:
4148                 if (!handled)
4149                     unknown = true;
4150             }
4151         }
4152     }
4153
4154     if (event->key() == Qt::Key_Direction_L || event->key() == Qt::Key_Direction_R) {
4155         setLayoutDirection((event->key() == Qt::Key_Direction_L) ? Qt::LeftToRight : Qt::RightToLeft);
4156         unknown = false;
4157     }
4158
4159     if (unknown && !m_readOnly) {
4160         QString t = event->text();
4161         if (!t.isEmpty() && t.at(0).isPrint()) {
4162             insert(t);
4163             event->accept();
4164             return;
4165         }
4166     }
4167
4168     if (unknown)
4169         event->ignore();
4170     else
4171         event->accept();
4172 }
4173
4174
4175 QT_END_NAMESPACE
4176