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