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