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