Merge master <-> api_changes
[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     \o Font.Light
205     \o Font.Normal - the default
206     \o Font.DemiBold
207     \o Font.Bold
208     \o Font.Black
209     \endlist
210
211     \qml
212     TextInput { text: "Hello"; font.weight: Font.DemiBold }
213     \endqml
214 */
215
216 /*!
217     \qmlproperty bool QtQuick2::TextInput::font.italic
218
219     Sets whether the font has an italic style.
220 */
221
222 /*!
223     \qmlproperty bool QtQuick2::TextInput::font.underline
224
225     Sets whether the text is underlined.
226 */
227
228 /*!
229     \qmlproperty bool QtQuick2::TextInput::font.strikeout
230
231     Sets whether the font has a strikeout style.
232 */
233
234 /*!
235     \qmlproperty real QtQuick2::TextInput::font.pointSize
236
237     Sets the font size in points. The point size must be greater than zero.
238 */
239
240 /*!
241     \qmlproperty int QtQuick2::TextInput::font.pixelSize
242
243     Sets the font size in pixels.
244
245     Using this function makes the font device dependent.
246     Use \c pointSize to set the size of the font in a device independent manner.
247 */
248
249 /*!
250     \qmlproperty real QtQuick2::TextInput::font.letterSpacing
251
252     Sets the letter spacing for the font.
253
254     Letter spacing changes the default spacing between individual letters in the font.
255     A positive value increases the letter spacing by the corresponding pixels; a negative value decreases the spacing.
256 */
257
258 /*!
259     \qmlproperty real QtQuick2::TextInput::font.wordSpacing
260
261     Sets the word spacing for the font.
262
263     Word spacing changes the default spacing between individual words.
264     A positive value increases the word spacing by a corresponding amount of pixels,
265     while a negative value decreases the inter-word spacing accordingly.
266 */
267
268 /*!
269     \qmlproperty enumeration QtQuick2::TextInput::font.capitalization
270
271     Sets the capitalization for the text.
272
273     \list
274     \o Font.MixedCase - This is the normal text rendering option where no capitalization change is applied.
275     \o Font.AllUppercase - This alters the text to be rendered in all uppercase type.
276     \o Font.AllLowercase - This alters the text to be rendered in all lowercase type.
277     \o Font.SmallCaps - This alters the text to be rendered in small-caps type.
278     \o Font.Capitalize - This alters the text to be rendered with the first character of each word as an uppercase character.
279     \endlist
280
281     \qml
282     TextInput { text: "Hello"; font.capitalization: Font.AllLowercase }
283     \endqml
284 */
285
286 QFont QQuickTextInput::font() const
287 {
288     Q_D(const QQuickTextInput);
289     return d->sourceFont;
290 }
291
292 void QQuickTextInput::setFont(const QFont &font)
293 {
294     Q_D(QQuickTextInput);
295     if (d->sourceFont == font)
296         return;
297
298     d->sourceFont = font;
299     QFont oldFont = d->font;
300     d->font = font;
301     if (d->font.pointSizeF() != -1) {
302         // 0.5pt resolution
303         qreal size = qRound(d->font.pointSizeF()*2.0);
304         d->font.setPointSizeF(size/2.0);
305     }
306     if (oldFont != d->font) {
307         d->updateLayout();
308         updateCursorRectangle();
309         updateInputMethod(Qt::ImCursorRectangle | Qt::ImFont);
310     }
311     emit fontChanged(d->sourceFont);
312 }
313
314 /*!
315     \qmlproperty color QtQuick2::TextInput::color
316
317     The text color.
318 */
319 QColor QQuickTextInput::color() const
320 {
321     Q_D(const QQuickTextInput);
322     return d->color;
323 }
324
325 void QQuickTextInput::setColor(const QColor &c)
326 {
327     Q_D(QQuickTextInput);
328     if (c != d->color) {
329         d->color = c;
330         d->textLayoutDirty = true;
331         d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
332         update();
333         emit colorChanged();
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     \o TextInput.NoWrap - no wrapping will be performed. If the text contains insufficient newlines, then implicitWidth will exceed a set width.
516     \o TextInput.WordWrap - wrapping is done on word boundaries only. If a word is too long, implicitWidth will exceed a set width.
517     \o TextInput.WrapAnywhere - wrapping is done at any point on a line, even if it occurs in the middle of a word.
518     \o TextInput.Wrap - if possible, wrapping occurs at a word boundary; otherwise it will occur at the appropriate point on the line, even in the middle of a word.
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     \o DoubleValidator.StandardNotation
962     \o 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     \o TextInput.Normal - Displays the text as it is. (Default)
1114     \o TextInput.Password - Displays asterisks instead of characters.
1115     \o TextInput.NoEcho - Displays nothing.
1116     \o 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     \o 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     \o Qt.ImhSensitiveData - Typed text should not be stored by the active input method
1155             in any persistent storage like predictive user dictionary.
1156     \o Qt.ImhNoAutoUppercase - The input method should not try to automatically switch to upper case
1157             when a sentence ends.
1158     \o Qt.ImhPreferNumbers - Numbers are preferred (but not required).
1159     \o Qt.ImhPreferUppercase - Upper case letters are preferred (but not required).
1160     \o Qt.ImhPreferLowercase - Lower case letters are preferred (but not required).
1161     \o Qt.ImhNoPredictiveText - Do not use predictive text (i.e. dictionary lookup) while typing.
1162
1163     \o Qt.ImhDate - The text editor functions as a date field.
1164     \o 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     \o Qt.ImhDigitsOnly - Only digits are allowed.
1171     \o Qt.ImhFormattedNumbersOnly - Only number input is allowed. This includes decimal point and minus sign.
1172     \o Qt.ImhUppercaseOnly - Only upper case letter input is allowed.
1173     \o Qt.ImhLowercaseOnly - Only lower case letter input is allowed.
1174     \o Qt.ImhDialableCharactersOnly - Only characters suitable for phone dialing are allowed.
1175     \o Qt.ImhEmailCharactersOnly - Only characters suitable for email addresses are allowed.
1176     \o Qt.ImhUrlCharactersOnly - Only characters suitable for URLs are allowed.
1177     \endlist
1178
1179     Masks:
1180
1181     \list
1182     \o 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     \o TextInput.CursorBetweenCharacters - Returns the position between characters that is nearest x.
1327     \o 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     \o TextInput.SelectCharacters - The selection is updated with individual characters. (Default)
2165     \o 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     \o TextInput.SelectCharacters - Sets either the selectionStart or selectionEnd (whichever was at
2299     the previous cursor position) to the specified position.
2300     \o 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     Initializes the line control with a starting text value of \a txt.
2934 */
2935 void QQuickTextInputPrivate::init(const QString &txt)
2936 {
2937     m_text = txt;
2938
2939     updateDisplayText();
2940     m_cursor = m_text.length();
2941 }
2942
2943 /*!
2944     \internal
2945
2946     Sets the password echo editing to \a editing.  If password echo editing
2947     is true, then the text of the password is displayed even if the echo
2948     mode is set to QLineEdit::PasswordEchoOnEdit.  Password echoing editing
2949     does not affect other echo modes.
2950 */
2951 void QQuickTextInputPrivate::updatePasswordEchoEditing(bool editing)
2952 {
2953     cancelPasswordEchoTimer();
2954     m_passwordEchoEditing = editing;
2955     updateDisplayText();
2956 }
2957
2958 /*!
2959     \internal
2960
2961     Fixes the current text so that it is valid given any set validators.
2962
2963     Returns true if the text was changed.  Otherwise returns false.
2964 */
2965 bool QQuickTextInputPrivate::fixup() // this function assumes that validate currently returns != Acceptable
2966 {
2967 #ifndef QT_NO_VALIDATOR
2968     if (m_validator) {
2969         QString textCopy = m_text;
2970         int cursorCopy = m_cursor;
2971         m_validator->fixup(textCopy);
2972         if (m_validator->validate(textCopy, cursorCopy) == QValidator::Acceptable) {
2973             if (textCopy != m_text || cursorCopy != m_cursor)
2974                 internalSetText(textCopy, cursorCopy);
2975             return true;
2976         }
2977     }
2978 #endif
2979     return false;
2980 }
2981
2982 /*!
2983     \internal
2984
2985     Moves the cursor to the given position \a pos.   If \a mark is true will
2986     adjust the currently selected text.
2987 */
2988 void QQuickTextInputPrivate::moveCursor(int pos, bool mark)
2989 {
2990     Q_Q(QQuickTextInput);
2991     commitPreedit();
2992
2993     if (pos != m_cursor) {
2994         separate();
2995         if (m_maskData)
2996             pos = pos > m_cursor ? nextMaskBlank(pos) : prevMaskBlank(pos);
2997     }
2998     if (mark) {
2999         int anchor;
3000         if (m_selend > m_selstart && m_cursor == m_selstart)
3001             anchor = m_selend;
3002         else if (m_selend > m_selstart && m_cursor == m_selend)
3003             anchor = m_selstart;
3004         else
3005             anchor = m_cursor;
3006         m_selstart = qMin(anchor, pos);
3007         m_selend = qMax(anchor, pos);
3008     } else {
3009         internalDeselect();
3010     }
3011     m_cursor = pos;
3012     if (mark || m_selDirty) {
3013         m_selDirty = false;
3014         emit q->selectionChanged();
3015     }
3016     emitCursorPositionChanged();
3017     q->updateInputMethod();
3018 }
3019
3020 /*!
3021     \internal
3022
3023     Applies the given input method event \a event to the text of the line
3024     control
3025 */
3026 void QQuickTextInputPrivate::processInputMethodEvent(QInputMethodEvent *event)
3027 {
3028     Q_Q(QQuickTextInput);
3029
3030     int priorState = -1;
3031     bool isGettingInput = !event->commitString().isEmpty()
3032             || event->preeditString() != preeditAreaText()
3033             || event->replacementLength() > 0;
3034     bool cursorPositionChanged = false;
3035     bool selectionChange = false;
3036     m_preeditDirty = event->preeditString() != preeditAreaText();
3037
3038     if (isGettingInput) {
3039         // If any text is being input, remove selected text.
3040         priorState = m_undoState;
3041         if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit && !m_passwordEchoEditing) {
3042             updatePasswordEchoEditing(true);
3043             m_selstart = 0;
3044             m_selend = m_text.length();
3045         }
3046         removeSelectedText();
3047     }
3048
3049     int c = m_cursor; // cursor position after insertion of commit string
3050     if (event->replacementStart() <= 0)
3051         c += event->commitString().length() - qMin(-event->replacementStart(), event->replacementLength());
3052
3053     m_cursor += event->replacementStart();
3054     if (m_cursor < 0)
3055         m_cursor = 0;
3056
3057     // insert commit string
3058     if (event->replacementLength()) {
3059         m_selstart = m_cursor;
3060         m_selend = m_selstart + event->replacementLength();
3061         m_selend = qMin(m_selend, m_text.length());
3062         removeSelectedText();
3063     }
3064     if (!event->commitString().isEmpty()) {
3065         internalInsert(event->commitString());
3066         cursorPositionChanged = true;
3067     }
3068
3069     m_cursor = qBound(0, c, m_text.length());
3070
3071     for (int i = 0; i < event->attributes().size(); ++i) {
3072         const QInputMethodEvent::Attribute &a = event->attributes().at(i);
3073         if (a.type == QInputMethodEvent::Selection) {
3074             m_cursor = qBound(0, a.start + a.length, m_text.length());
3075             if (a.length) {
3076                 m_selstart = qMax(0, qMin(a.start, m_text.length()));
3077                 m_selend = m_cursor;
3078                 if (m_selend < m_selstart) {
3079                     qSwap(m_selstart, m_selend);
3080                 }
3081                 selectionChange = true;
3082             } else {
3083                 m_selstart = m_selend = 0;
3084             }
3085             cursorPositionChanged = true;
3086         }
3087     }
3088 #ifndef QT_NO_IM
3089     m_textLayout.setPreeditArea(m_cursor, event->preeditString());
3090 #endif //QT_NO_IM
3091     const int oldPreeditCursor = m_preeditCursor;
3092     m_preeditCursor = event->preeditString().length();
3093     m_hideCursor = false;
3094     QList<QTextLayout::FormatRange> formats;
3095     for (int i = 0; i < event->attributes().size(); ++i) {
3096         const QInputMethodEvent::Attribute &a = event->attributes().at(i);
3097         if (a.type == QInputMethodEvent::Cursor) {
3098             m_preeditCursor = a.start;
3099             m_hideCursor = !a.length;
3100         } else if (a.type == QInputMethodEvent::TextFormat) {
3101             QTextCharFormat f = qvariant_cast<QTextFormat>(a.value).toCharFormat();
3102             if (f.isValid()) {
3103                 QTextLayout::FormatRange o;
3104                 o.start = a.start + m_cursor;
3105                 o.length = a.length;
3106                 o.format = f;
3107                 formats.append(o);
3108             }
3109         }
3110     }
3111     m_textLayout.setAdditionalFormats(formats);
3112
3113     updateDisplayText(/*force*/ true);
3114     if (cursorPositionChanged) {
3115         emitCursorPositionChanged();
3116     } else if (m_preeditCursor != oldPreeditCursor) {
3117         q->updateCursorRectangle();
3118     }
3119
3120     bool tentativeCommitChanged = m_tentativeCommit != event->tentativeCommitString();
3121
3122     if (tentativeCommitChanged) {
3123         m_textDirty = true;
3124         m_tentativeCommit = event->tentativeCommitString();
3125     }
3126
3127     if (isGettingInput || tentativeCommitChanged)
3128         finishChange(priorState);
3129
3130     if (selectionChange) {
3131         emit q->selectionChanged();
3132         q->updateInputMethod(Qt::ImCursorRectangle | Qt::ImAnchorPosition
3133                             | Qt::ImCursorPosition | Qt::ImCurrentSelection);
3134     }
3135 }
3136
3137 /*!
3138     \internal
3139
3140     Sets the selection to cover the word at the given cursor position.
3141     The word boundaries are defined by the behavior of QTextLayout::SkipWords
3142     cursor mode.
3143 */
3144 void QQuickTextInputPrivate::selectWordAtPos(int cursor)
3145 {
3146     int next = cursor + 1;
3147     if (next > end())
3148         --next;
3149     int c = m_textLayout.previousCursorPosition(next, QTextLayout::SkipWords);
3150     moveCursor(c, false);
3151     // ## text layout should support end of words.
3152     int end = m_textLayout.nextCursorPosition(c, QTextLayout::SkipWords);
3153     while (end > cursor && m_text[end-1].isSpace())
3154         --end;
3155     moveCursor(end, true);
3156 }
3157
3158 /*!
3159     \internal
3160
3161     Completes a change to the line control text.  If the change is not valid
3162     will undo the line control state back to the given \a validateFromState.
3163
3164     If \a edited is true and the change is valid, will emit textEdited() in
3165     addition to textChanged().  Otherwise only emits textChanged() on a valid
3166     change.
3167
3168     The \a update value is currently unused.
3169 */
3170 bool QQuickTextInputPrivate::finishChange(int validateFromState, bool update, bool /*edited*/)
3171 {
3172     Q_Q(QQuickTextInput);
3173
3174     Q_UNUSED(update)
3175     bool inputMethodAttributesChanged = m_textDirty || m_selDirty;
3176     bool alignmentChanged = false;
3177
3178     if (m_textDirty) {
3179         // do validation
3180         bool wasValidInput = m_validInput;
3181         bool wasAcceptable = m_acceptableInput;
3182         m_validInput = true;
3183         m_acceptableInput = true;
3184 #ifndef QT_NO_VALIDATOR
3185         if (m_validator) {
3186             QString textCopy = m_text;
3187             int cursorCopy = m_cursor;
3188             QValidator::State state = m_validator->validate(textCopy, cursorCopy);
3189             m_validInput = state != QValidator::Invalid;
3190             m_acceptableInput = state == QValidator::Acceptable;
3191             if (m_validInput) {
3192                 if (m_text != textCopy) {
3193                     internalSetText(textCopy, cursorCopy);
3194                     return true;
3195                 }
3196                 m_cursor = cursorCopy;
3197
3198                 if (!m_tentativeCommit.isEmpty()) {
3199                     textCopy.insert(m_cursor, m_tentativeCommit);
3200                     bool validInput = m_validator->validate(textCopy, cursorCopy) != QValidator::Invalid;
3201                     if (!validInput)
3202                         m_tentativeCommit.clear();
3203                 }
3204             } else {
3205                 m_tentativeCommit.clear();
3206             }
3207         }
3208 #endif
3209         if (validateFromState >= 0 && wasValidInput && !m_validInput) {
3210             if (m_transactions.count())
3211                 return false;
3212             internalUndo(validateFromState);
3213             m_history.resize(m_undoState);
3214             m_validInput = true;
3215             m_acceptableInput = wasAcceptable;
3216             m_textDirty = false;
3217         }
3218
3219         if (m_textDirty) {
3220             m_textDirty = false;
3221             m_preeditDirty = false;
3222             alignmentChanged = determineHorizontalAlignment();
3223             emit q->textChanged();
3224         }
3225
3226         updateDisplayText(alignmentChanged);
3227
3228         if (m_acceptableInput != wasAcceptable)
3229             emit q->acceptableInputChanged();
3230     }
3231     if (m_preeditDirty) {
3232         m_preeditDirty = false;
3233         if (determineHorizontalAlignment()) {
3234             alignmentChanged = true;
3235             updateLayout();
3236         }
3237     }
3238
3239     if (m_selDirty) {
3240         m_selDirty = false;
3241         emit q->selectionChanged();
3242     }
3243
3244     inputMethodAttributesChanged |= (m_cursor == m_lastCursorPos);
3245     if (inputMethodAttributesChanged)
3246         q->updateInputMethod();
3247     emitUndoRedoChanged();
3248
3249     if (!emitCursorPositionChanged() && alignmentChanged)
3250         q->updateCursorRectangle();
3251
3252     return true;
3253 }
3254
3255 /*!
3256     \internal
3257
3258     An internal function for setting the text of the line control.
3259 */
3260 void QQuickTextInputPrivate::internalSetText(const QString &txt, int pos, bool edited)
3261 {
3262     Q_Q(QQuickTextInput);
3263     internalDeselect();
3264     QString oldText = m_text;
3265     if (m_maskData) {
3266         m_text = maskString(0, txt, true);
3267         m_text += clearString(m_text.length(), m_maxLength - m_text.length());
3268     } else {
3269         m_text = txt.isEmpty() ? txt : txt.left(m_maxLength);
3270     }
3271     m_history.clear();
3272     m_undoState = 0;
3273     m_cursor = (pos < 0 || pos > m_text.length()) ? m_text.length() : pos;
3274     m_textDirty = (oldText != m_text);
3275
3276     bool changed = finishChange(-1, true, edited);
3277 #ifdef QT_NO_ACCESSIBILITY
3278     Q_UNUSED(changed)
3279 #else
3280     if (changed)
3281         QAccessible::updateAccessibility(QAccessibleEvent(QAccessible::TextUpdated, q, 0));
3282 #endif
3283 }
3284
3285
3286 /*!
3287     \internal
3288
3289     Adds the given \a command to the undo history
3290     of the line control.  Does not apply the command.
3291 */
3292 void QQuickTextInputPrivate::addCommand(const Command &cmd)
3293 {
3294     if (m_separator && m_undoState && m_history[m_undoState - 1].type != Separator) {
3295         m_history.resize(m_undoState + 2);
3296         m_history[m_undoState++] = Command(Separator, m_cursor, 0, m_selstart, m_selend);
3297     } else {
3298         m_history.resize(m_undoState + 1);
3299     }
3300     m_separator = false;
3301     m_history[m_undoState++] = cmd;
3302 }
3303
3304 /*!
3305     \internal
3306
3307     Inserts the given string \a s into the line
3308     control.
3309
3310     Also adds the appropriate commands into the undo history.
3311     This function does not call finishChange(), and may leave the text
3312     in an invalid state.
3313 */
3314 void QQuickTextInputPrivate::internalInsert(const QString &s)
3315 {
3316 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
3317     Q_Q(QQuickTextInput);
3318     if (m_echoMode == QQuickTextInput::Password)
3319         m_passwordEchoTimer.start(qt_passwordEchoDelay, q);
3320 #endif
3321     if (hasSelectedText())
3322         addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
3323     if (m_maskData) {
3324         QString ms = maskString(m_cursor, s);
3325         for (int i = 0; i < (int) ms.length(); ++i) {
3326             addCommand (Command(DeleteSelection, m_cursor + i, m_text.at(m_cursor + i), -1, -1));
3327             addCommand(Command(Insert, m_cursor + i, ms.at(i), -1, -1));
3328         }
3329         m_text.replace(m_cursor, ms.length(), ms);
3330         m_cursor += ms.length();
3331         m_cursor = nextMaskBlank(m_cursor);
3332         m_textDirty = true;
3333     } else {
3334         int remaining = m_maxLength - m_text.length();
3335         if (remaining != 0) {
3336             m_text.insert(m_cursor, s.left(remaining));
3337             for (int i = 0; i < (int) s.left(remaining).length(); ++i)
3338                addCommand(Command(Insert, m_cursor++, s.at(i), -1, -1));
3339             m_textDirty = true;
3340         }
3341     }
3342 }
3343
3344 /*!
3345     \internal
3346
3347     deletes a single character from the current text.  If \a wasBackspace,
3348     the character prior to the cursor is removed.  Otherwise the character
3349     after the cursor is removed.
3350
3351     Also adds the appropriate commands into the undo history.
3352     This function does not call finishChange(), and may leave the text
3353     in an invalid state.
3354 */
3355 void QQuickTextInputPrivate::internalDelete(bool wasBackspace)
3356 {
3357     if (m_cursor < (int) m_text.length()) {
3358         cancelPasswordEchoTimer();
3359         if (hasSelectedText())
3360             addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
3361         addCommand(Command((CommandType)((m_maskData ? 2 : 0) + (wasBackspace ? Remove : Delete)),
3362                    m_cursor, m_text.at(m_cursor), -1, -1));
3363         if (m_maskData) {
3364             m_text.replace(m_cursor, 1, clearString(m_cursor, 1));
3365             addCommand(Command(Insert, m_cursor, m_text.at(m_cursor), -1, -1));
3366         } else {
3367             m_text.remove(m_cursor, 1);
3368         }
3369         m_textDirty = true;
3370     }
3371 }
3372
3373 /*!
3374     \internal
3375
3376     removes the currently selected text from the line control.
3377
3378     Also adds the appropriate commands into the undo history.
3379     This function does not call finishChange(), and may leave the text
3380     in an invalid state.
3381 */
3382 void QQuickTextInputPrivate::removeSelectedText()
3383 {
3384     if (m_selstart < m_selend && m_selend <= (int) m_text.length()) {
3385         cancelPasswordEchoTimer();
3386         separate();
3387         int i ;
3388         addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
3389         if (m_selstart <= m_cursor && m_cursor < m_selend) {
3390             // cursor is within the selection. Split up the commands
3391             // to be able to restore the correct cursor position
3392             for (i = m_cursor; i >= m_selstart; --i)
3393                 addCommand (Command(DeleteSelection, i, m_text.at(i), -1, 1));
3394             for (i = m_selend - 1; i > m_cursor; --i)
3395                 addCommand (Command(DeleteSelection, i - m_cursor + m_selstart - 1, m_text.at(i), -1, -1));
3396         } else {
3397             for (i = m_selend-1; i >= m_selstart; --i)
3398                 addCommand (Command(RemoveSelection, i, m_text.at(i), -1, -1));
3399         }
3400         if (m_maskData) {
3401             m_text.replace(m_selstart, m_selend - m_selstart,  clearString(m_selstart, m_selend - m_selstart));
3402             for (int i = 0; i < m_selend - m_selstart; ++i)
3403                 addCommand(Command(Insert, m_selstart + i, m_text.at(m_selstart + i), -1, -1));
3404         } else {
3405             m_text.remove(m_selstart, m_selend - m_selstart);
3406         }
3407         if (m_cursor > m_selstart)
3408             m_cursor -= qMin(m_cursor, m_selend) - m_selstart;
3409         internalDeselect();
3410         m_textDirty = true;
3411     }
3412 }
3413
3414 /*!
3415     \internal
3416
3417     Parses the input mask specified by \a maskFields to generate
3418     the mask data used to handle input masks.
3419 */
3420 void QQuickTextInputPrivate::parseInputMask(const QString &maskFields)
3421 {
3422     int delimiter = maskFields.indexOf(QLatin1Char(';'));
3423     if (maskFields.isEmpty() || delimiter == 0) {
3424         if (m_maskData) {
3425             delete [] m_maskData;
3426             m_maskData = 0;
3427             m_maxLength = 32767;
3428             internalSetText(QString());
3429         }
3430         return;
3431     }
3432
3433     if (delimiter == -1) {
3434         m_blank = QLatin1Char(' ');
3435         m_inputMask = maskFields;
3436     } else {
3437         m_inputMask = maskFields.left(delimiter);
3438         m_blank = (delimiter + 1 < maskFields.length()) ? maskFields[delimiter + 1] : QLatin1Char(' ');
3439     }
3440
3441     // calculate m_maxLength / m_maskData length
3442     m_maxLength = 0;
3443     QChar c = 0;
3444     for (int i=0; i<m_inputMask.length(); i++) {
3445         c = m_inputMask.at(i);
3446         if (i > 0 && m_inputMask.at(i-1) == QLatin1Char('\\')) {
3447             m_maxLength++;
3448             continue;
3449         }
3450         if (c != QLatin1Char('\\') && c != QLatin1Char('!') &&
3451              c != QLatin1Char('<') && c != QLatin1Char('>') &&
3452              c != QLatin1Char('{') && c != QLatin1Char('}') &&
3453              c != QLatin1Char('[') && c != QLatin1Char(']'))
3454             m_maxLength++;
3455     }
3456
3457     delete [] m_maskData;
3458     m_maskData = new MaskInputData[m_maxLength];
3459
3460     MaskInputData::Casemode m = MaskInputData::NoCaseMode;
3461     c = 0;
3462     bool s;
3463     bool escape = false;
3464     int index = 0;
3465     for (int i = 0; i < m_inputMask.length(); i++) {
3466         c = m_inputMask.at(i);
3467         if (escape) {
3468             s = true;
3469             m_maskData[index].maskChar = c;
3470             m_maskData[index].separator = s;
3471             m_maskData[index].caseMode = m;
3472             index++;
3473             escape = false;
3474         } else if (c == QLatin1Char('<')) {
3475                 m = MaskInputData::Lower;
3476         } else if (c == QLatin1Char('>')) {
3477             m = MaskInputData::Upper;
3478         } else if (c == QLatin1Char('!')) {
3479             m = MaskInputData::NoCaseMode;
3480         } else if (c != QLatin1Char('{') && c != QLatin1Char('}') && c != QLatin1Char('[') && c != QLatin1Char(']')) {
3481             switch (c.unicode()) {
3482             case 'A':
3483             case 'a':
3484             case 'N':
3485             case 'n':
3486             case 'X':
3487             case 'x':
3488             case '9':
3489             case '0':
3490             case 'D':
3491             case 'd':
3492             case '#':
3493             case 'H':
3494             case 'h':
3495             case 'B':
3496             case 'b':
3497                 s = false;
3498                 break;
3499             case '\\':
3500                 escape = true;
3501             default:
3502                 s = true;
3503                 break;
3504             }
3505
3506             if (!escape) {
3507                 m_maskData[index].maskChar = c;
3508                 m_maskData[index].separator = s;
3509                 m_maskData[index].caseMode = m;
3510                 index++;
3511             }
3512         }
3513     }
3514     internalSetText(m_text);
3515 }
3516
3517
3518 /*!
3519     \internal
3520
3521     checks if the key is valid compared to the inputMask
3522 */
3523 bool QQuickTextInputPrivate::isValidInput(QChar key, QChar mask) const
3524 {
3525     switch (mask.unicode()) {
3526     case 'A':
3527         if (key.isLetter())
3528             return true;
3529         break;
3530     case 'a':
3531         if (key.isLetter() || key == m_blank)
3532             return true;
3533         break;
3534     case 'N':
3535         if (key.isLetterOrNumber())
3536             return true;
3537         break;
3538     case 'n':
3539         if (key.isLetterOrNumber() || key == m_blank)
3540             return true;
3541         break;
3542     case 'X':
3543         if (key.isPrint())
3544             return true;
3545         break;
3546     case 'x':
3547         if (key.isPrint() || key == m_blank)
3548             return true;
3549         break;
3550     case '9':
3551         if (key.isNumber())
3552             return true;
3553         break;
3554     case '0':
3555         if (key.isNumber() || key == m_blank)
3556             return true;
3557         break;
3558     case 'D':
3559         if (key.isNumber() && key.digitValue() > 0)
3560             return true;
3561         break;
3562     case 'd':
3563         if ((key.isNumber() && key.digitValue() > 0) || key == m_blank)
3564             return true;
3565         break;
3566     case '#':
3567         if (key.isNumber() || key == QLatin1Char('+') || key == QLatin1Char('-') || key == m_blank)
3568             return true;
3569         break;
3570     case 'B':
3571         if (key == QLatin1Char('0') || key == QLatin1Char('1'))
3572             return true;
3573         break;
3574     case 'b':
3575         if (key == QLatin1Char('0') || key == QLatin1Char('1') || key == m_blank)
3576             return true;
3577         break;
3578     case 'H':
3579         if (key.isNumber() || (key >= QLatin1Char('a') && key <= QLatin1Char('f')) || (key >= QLatin1Char('A') && key <= QLatin1Char('F')))
3580             return true;
3581         break;
3582     case 'h':
3583         if (key.isNumber() || (key >= QLatin1Char('a') && key <= QLatin1Char('f')) || (key >= QLatin1Char('A') && key <= QLatin1Char('F')) || key == m_blank)
3584             return true;
3585         break;
3586     default:
3587         break;
3588     }
3589     return false;
3590 }
3591
3592 /*!
3593     \internal
3594
3595     Returns true if the given text \a str is valid for any
3596     validator or input mask set for the line control.
3597
3598     Otherwise returns false
3599 */
3600 QQuickTextInputPrivate::ValidatorState QQuickTextInputPrivate::hasAcceptableInput(const QString &str) const
3601 {
3602 #ifndef QT_NO_VALIDATOR
3603     QString textCopy = str;
3604     int cursorCopy = m_cursor;
3605     if (m_validator) {
3606         QValidator::State state = m_validator->validate(textCopy, cursorCopy);
3607         if (state != QValidator::Acceptable)
3608             return ValidatorState(state);
3609     }
3610 #endif
3611
3612     if (!m_maskData)
3613         return AcceptableInput;
3614
3615     if (str.length() != m_maxLength)
3616         return InvalidInput;
3617
3618     for (int i=0; i < m_maxLength; ++i) {
3619         if (m_maskData[i].separator) {
3620             if (str.at(i) != m_maskData[i].maskChar)
3621                 return InvalidInput;
3622         } else {
3623             if (!isValidInput(str.at(i), m_maskData[i].maskChar))
3624                 return InvalidInput;
3625         }
3626     }
3627     return AcceptableInput;
3628 }
3629
3630 /*!
3631     \internal
3632
3633     Applies the inputMask on \a str starting from position \a pos in the mask. \a clear
3634     specifies from where characters should be gotten when a separator is met in \a str - true means
3635     that blanks will be used, false that previous input is used.
3636     Calling this when no inputMask is set is undefined.
3637 */
3638 QString QQuickTextInputPrivate::maskString(uint pos, const QString &str, bool clear) const
3639 {
3640     if (pos >= (uint)m_maxLength)
3641         return QString::fromLatin1("");
3642
3643     QString fill;
3644     fill = clear ? clearString(0, m_maxLength) : m_text;
3645
3646     int strIndex = 0;
3647     QString s = QString::fromLatin1("");
3648     int i = pos;
3649     while (i < m_maxLength) {
3650         if (strIndex < str.length()) {
3651             if (m_maskData[i].separator) {
3652                 s += m_maskData[i].maskChar;
3653                 if (str[(int)strIndex] == m_maskData[i].maskChar)
3654                     strIndex++;
3655                 ++i;
3656             } else {
3657                 if (isValidInput(str[(int)strIndex], m_maskData[i].maskChar)) {
3658                     switch (m_maskData[i].caseMode) {
3659                     case MaskInputData::Upper:
3660                         s += str[(int)strIndex].toUpper();
3661                         break;
3662                     case MaskInputData::Lower:
3663                         s += str[(int)strIndex].toLower();
3664                         break;
3665                     default:
3666                         s += str[(int)strIndex];
3667                     }
3668                     ++i;
3669                 } else {
3670                     // search for separator first
3671                     int n = findInMask(i, true, true, str[(int)strIndex]);
3672                     if (n != -1) {
3673                         if (str.length() != 1 || i == 0 || (i > 0 && (!m_maskData[i-1].separator || m_maskData[i-1].maskChar != str[(int)strIndex]))) {
3674                             s += fill.mid(i, n-i+1);
3675                             i = n + 1; // update i to find + 1
3676                         }
3677                     } else {
3678                         // search for valid m_blank if not
3679                         n = findInMask(i, true, false, str[(int)strIndex]);
3680                         if (n != -1) {
3681                             s += fill.mid(i, n-i);
3682                             switch (m_maskData[n].caseMode) {
3683                             case MaskInputData::Upper:
3684                                 s += str[(int)strIndex].toUpper();
3685                                 break;
3686                             case MaskInputData::Lower:
3687                                 s += str[(int)strIndex].toLower();
3688                                 break;
3689                             default:
3690                                 s += str[(int)strIndex];
3691                             }
3692                             i = n + 1; // updates i to find + 1
3693                         }
3694                     }
3695                 }
3696                 ++strIndex;
3697             }
3698         } else
3699             break;
3700     }
3701
3702     return s;
3703 }
3704
3705
3706
3707 /*!
3708     \internal
3709
3710     Returns a "cleared" string with only separators and blank chars.
3711     Calling this when no inputMask is set is undefined.
3712 */
3713 QString QQuickTextInputPrivate::clearString(uint pos, uint len) const
3714 {
3715     if (pos >= (uint)m_maxLength)
3716         return QString();
3717
3718     QString s;
3719     int end = qMin((uint)m_maxLength, pos + len);
3720     for (int i = pos; i < end; ++i)
3721         if (m_maskData[i].separator)
3722             s += m_maskData[i].maskChar;
3723         else
3724             s += m_blank;
3725
3726     return s;
3727 }
3728
3729 /*!
3730     \internal
3731
3732     Strips blank parts of the input in a QQuickTextInputPrivate when an inputMask is set,
3733     separators are still included. Typically "127.0__.0__.1__" becomes "127.0.0.1".
3734 */
3735 QString QQuickTextInputPrivate::stripString(const QString &str) const
3736 {
3737     if (!m_maskData)
3738         return str;
3739
3740     QString s;
3741     int end = qMin(m_maxLength, (int)str.length());
3742     for (int i = 0; i < end; ++i) {
3743         if (m_maskData[i].separator)
3744             s += m_maskData[i].maskChar;
3745         else if (str[i] != m_blank)
3746             s += str[i];
3747     }
3748
3749     return s;
3750 }
3751
3752 /*!
3753     \internal
3754     searches forward/backward in m_maskData for either a separator or a m_blank
3755 */
3756 int QQuickTextInputPrivate::findInMask(int pos, bool forward, bool findSeparator, QChar searchChar) const
3757 {
3758     if (pos >= m_maxLength || pos < 0)
3759         return -1;
3760
3761     int end = forward ? m_maxLength : -1;
3762     int step = forward ? 1 : -1;
3763     int i = pos;
3764
3765     while (i != end) {
3766         if (findSeparator) {
3767             if (m_maskData[i].separator && m_maskData[i].maskChar == searchChar)
3768                 return i;
3769         } else {
3770             if (!m_maskData[i].separator) {
3771                 if (searchChar.isNull())
3772                     return i;
3773                 else if (isValidInput(searchChar, m_maskData[i].maskChar))
3774                     return i;
3775             }
3776         }
3777         i += step;
3778     }
3779     return -1;
3780 }
3781
3782 void QQuickTextInputPrivate::internalUndo(int until)
3783 {
3784     if (!isUndoAvailable())
3785         return;
3786     cancelPasswordEchoTimer();
3787     internalDeselect();
3788     while (m_undoState && m_undoState > until) {
3789         Command& cmd = m_history[--m_undoState];
3790         switch (cmd.type) {
3791         case Insert:
3792             m_text.remove(cmd.pos, 1);
3793             m_cursor = cmd.pos;
3794             break;
3795         case SetSelection:
3796             m_selstart = cmd.selStart;
3797             m_selend = cmd.selEnd;
3798             m_cursor = cmd.pos;
3799             break;
3800         case Remove:
3801         case RemoveSelection:
3802             m_text.insert(cmd.pos, cmd.uc);
3803             m_cursor = cmd.pos + 1;
3804             break;
3805         case Delete:
3806         case DeleteSelection:
3807             m_text.insert(cmd.pos, cmd.uc);
3808             m_cursor = cmd.pos;
3809             break;
3810         case Separator:
3811             continue;
3812         }
3813         if (until < 0 && m_undoState) {
3814             Command& next = m_history[m_undoState-1];
3815             if (next.type != cmd.type && next.type < RemoveSelection
3816                  && (cmd.type < RemoveSelection || next.type == Separator))
3817                 break;
3818         }
3819     }
3820     m_textDirty = true;
3821 }
3822
3823 void QQuickTextInputPrivate::internalRedo()
3824 {
3825     if (!isRedoAvailable())
3826         return;
3827     internalDeselect();
3828     while (m_undoState < (int)m_history.size()) {
3829         Command& cmd = m_history[m_undoState++];
3830         switch (cmd.type) {
3831         case Insert:
3832             m_text.insert(cmd.pos, cmd.uc);
3833             m_cursor = cmd.pos + 1;
3834             break;
3835         case SetSelection:
3836             m_selstart = cmd.selStart;
3837             m_selend = cmd.selEnd;
3838             m_cursor = cmd.pos;
3839             break;
3840         case Remove:
3841         case Delete:
3842         case RemoveSelection:
3843         case DeleteSelection:
3844             m_text.remove(cmd.pos, 1);
3845             m_selstart = cmd.selStart;
3846             m_selend = cmd.selEnd;
3847             m_cursor = cmd.pos;
3848             break;
3849         case Separator:
3850             m_selstart = cmd.selStart;
3851             m_selend = cmd.selEnd;
3852             m_cursor = cmd.pos;
3853             break;
3854         }
3855         if (m_undoState < (int)m_history.size()) {
3856             Command& next = m_history[m_undoState];
3857             if (next.type != cmd.type && cmd.type < RemoveSelection && next.type != Separator
3858                  && (next.type < RemoveSelection || cmd.type == Separator))
3859                 break;
3860         }
3861     }
3862     m_textDirty = true;
3863 }
3864
3865 void QQuickTextInputPrivate::emitUndoRedoChanged()
3866 {
3867     Q_Q(QQuickTextInput);
3868     const bool previousUndo = canUndo;
3869     const bool previousRedo = canRedo;
3870
3871     canUndo = isUndoAvailable();
3872     canRedo = isRedoAvailable();
3873
3874     if (previousUndo != canUndo)
3875         emit q->canUndoChanged();
3876     if (previousRedo != canRedo)
3877         emit q->canRedoChanged();
3878 }
3879
3880 /*!
3881     \internal
3882
3883     If the current cursor position differs from the last emitted cursor
3884     position, emits cursorPositionChanged().
3885 */
3886 bool QQuickTextInputPrivate::emitCursorPositionChanged()
3887 {
3888     Q_Q(QQuickTextInput);
3889     if (m_cursor != m_lastCursorPos) {
3890         m_lastCursorPos = m_cursor;
3891
3892         q->updateCursorRectangle();
3893         emit q->cursorPositionChanged();
3894
3895         if (!hasSelectedText()) {
3896             if (lastSelectionStart != m_cursor) {
3897                 lastSelectionStart = m_cursor;
3898                 emit q->selectionStartChanged();
3899             }
3900             if (lastSelectionEnd != m_cursor) {
3901                 lastSelectionEnd = m_cursor;
3902                 emit q->selectionEndChanged();
3903             }
3904         }
3905
3906 #ifndef QT_NO_ACCESSIBILITY
3907         QAccessible::updateAccessibility(QAccessibleEvent(QAccessible::TextCaretMoved, q, 0));
3908 #endif
3909
3910         return true;
3911     }
3912     return false;
3913 }
3914
3915
3916 void QQuickTextInputPrivate::setCursorBlinkPeriod(int msec)
3917 {
3918     Q_Q(QQuickTextInput);
3919     if (msec == m_blinkPeriod)
3920         return;
3921     if (m_blinkTimer) {
3922         q->killTimer(m_blinkTimer);
3923     }
3924     if (msec) {
3925         m_blinkTimer = q->startTimer(msec / 2);
3926         m_blinkStatus = 1;
3927     } else {
3928         m_blinkTimer = 0;
3929         if (m_blinkStatus == 1) {
3930             updateType = UpdatePaintNode;
3931             q->update();
3932         }
3933     }
3934     m_blinkPeriod = msec;
3935 }
3936
3937 void QQuickTextInput::timerEvent(QTimerEvent *event)
3938 {
3939     Q_D(QQuickTextInput);
3940     if (event->timerId() == d->m_blinkTimer) {
3941         d->m_blinkStatus = !d->m_blinkStatus;
3942         d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
3943         update();
3944 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
3945     } else if (event->timerId() == d->m_passwordEchoTimer.timerId()) {
3946         d->m_passwordEchoTimer.stop();
3947         d->updateDisplayText();
3948 #endif
3949     }
3950 }
3951
3952 void QQuickTextInputPrivate::processKeyEvent(QKeyEvent* event)
3953 {
3954     Q_Q(QQuickTextInput);
3955     bool inlineCompletionAccepted = false;
3956
3957     if (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return) {
3958         if (hasAcceptableInput(m_text) || fixup()) {
3959             emit q->accepted();
3960         }
3961         if (inlineCompletionAccepted)
3962             event->accept();
3963         else
3964             event->ignore();
3965         return;
3966     }
3967
3968     if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit
3969         && !m_passwordEchoEditing
3970         && !m_readOnly
3971         && !event->text().isEmpty()
3972         && !(event->modifiers() & Qt::ControlModifier)) {
3973         // Clear the edit and reset to normal echo mode while editing; the
3974         // echo mode switches back when the edit loses focus
3975         // ### resets current content.  dubious code; you can
3976         // navigate with keys up, down, back, and select(?), but if you press
3977         // "left" or "right" it clears?
3978         updatePasswordEchoEditing(true);
3979         clear();
3980     }
3981
3982     bool unknown = false;
3983     bool visual = cursorMoveStyle() == Qt::VisualMoveStyle;
3984
3985     if (false) {
3986     }
3987 #ifndef QT_NO_SHORTCUT
3988     else if (event == QKeySequence::Undo) {
3989         if (!m_readOnly)
3990             q->undo();
3991     }
3992     else if (event == QKeySequence::Redo) {
3993         if (!m_readOnly)
3994             q->redo();
3995     }
3996     else if (event == QKeySequence::SelectAll) {
3997         selectAll();
3998     }
3999 #ifndef QT_NO_CLIPBOARD
4000     else if (event == QKeySequence::Copy) {
4001         copy();
4002     }
4003     else if (event == QKeySequence::Paste) {
4004         if (!m_readOnly) {
4005             QClipboard::Mode mode = QClipboard::Clipboard;
4006             paste(mode);
4007         }
4008     }
4009     else if (event == QKeySequence::Cut) {
4010         if (!m_readOnly) {
4011             copy();
4012             del();
4013         }
4014     }
4015     else if (event == QKeySequence::DeleteEndOfLine) {
4016         if (!m_readOnly) {
4017             setSelection(m_cursor, end());
4018             copy();
4019             del();
4020         }
4021     }
4022 #endif //QT_NO_CLIPBOARD
4023     else if (event == QKeySequence::MoveToStartOfLine || event == QKeySequence::MoveToStartOfBlock) {
4024         home(0);
4025     }
4026     else if (event == QKeySequence::MoveToEndOfLine || event == QKeySequence::MoveToEndOfBlock) {
4027         end(0);
4028     }
4029     else if (event == QKeySequence::SelectStartOfLine || event == QKeySequence::SelectStartOfBlock) {
4030         home(1);
4031     }
4032     else if (event == QKeySequence::SelectEndOfLine || event == QKeySequence::SelectEndOfBlock) {
4033         end(1);
4034     }
4035     else if (event == QKeySequence::MoveToNextChar) {
4036         if (hasSelectedText()) {
4037             moveCursor(selectionEnd(), false);
4038         } else {
4039             cursorForward(0, visual ? 1 : (layoutDirection() == Qt::LeftToRight ? 1 : -1));
4040         }
4041     }
4042     else if (event == QKeySequence::SelectNextChar) {
4043         cursorForward(1, visual ? 1 : (layoutDirection() == Qt::LeftToRight ? 1 : -1));
4044     }
4045     else if (event == QKeySequence::MoveToPreviousChar) {
4046         if (hasSelectedText()) {
4047             moveCursor(selectionStart(), false);
4048         } else {
4049             cursorForward(0, visual ? -1 : (layoutDirection() == Qt::LeftToRight ? -1 : 1));
4050         }
4051     }
4052     else if (event == QKeySequence::SelectPreviousChar) {
4053         cursorForward(1, visual ? -1 : (layoutDirection() == Qt::LeftToRight ? -1 : 1));
4054     }
4055     else if (event == QKeySequence::MoveToNextWord) {
4056         if (m_echoMode == QQuickTextInput::Normal)
4057             layoutDirection() == Qt::LeftToRight ? cursorWordForward(0) : cursorWordBackward(0);
4058         else
4059             layoutDirection() == Qt::LeftToRight ? end(0) : home(0);
4060     }
4061     else if (event == QKeySequence::MoveToPreviousWord) {
4062         if (m_echoMode == QQuickTextInput::Normal)
4063             layoutDirection() == Qt::LeftToRight ? cursorWordBackward(0) : cursorWordForward(0);
4064         else if (!m_readOnly) {
4065             layoutDirection() == Qt::LeftToRight ? home(0) : end(0);
4066         }
4067     }
4068     else if (event == QKeySequence::SelectNextWord) {
4069         if (m_echoMode == QQuickTextInput::Normal)
4070             layoutDirection() == Qt::LeftToRight ? cursorWordForward(1) : cursorWordBackward(1);
4071         else
4072             layoutDirection() == Qt::LeftToRight ? end(1) : home(1);
4073     }
4074     else if (event == QKeySequence::SelectPreviousWord) {
4075         if (m_echoMode == QQuickTextInput::Normal)
4076             layoutDirection() == Qt::LeftToRight ? cursorWordBackward(1) : cursorWordForward(1);
4077         else
4078             layoutDirection() == Qt::LeftToRight ? home(1) : end(1);
4079     }
4080     else if (event == QKeySequence::Delete) {
4081         if (!m_readOnly)
4082             del();
4083     }
4084     else if (event == QKeySequence::DeleteEndOfWord) {
4085         if (!m_readOnly) {
4086             cursorWordForward(true);
4087             del();
4088         }
4089     }
4090     else if (event == QKeySequence::DeleteStartOfWord) {
4091         if (!m_readOnly) {
4092             cursorWordBackward(true);
4093             del();
4094         }
4095     }
4096 #endif // QT_NO_SHORTCUT
4097     else {
4098         bool handled = false;
4099         if (event->modifiers() & Qt::ControlModifier) {
4100             switch (event->key()) {
4101             case Qt::Key_Backspace:
4102                 if (!m_readOnly) {
4103                     cursorWordBackward(true);
4104                     del();
4105                 }
4106                 break;
4107             default:
4108                 if (!handled)
4109                     unknown = true;
4110             }
4111         } else { // ### check for *no* modifier
4112             switch (event->key()) {
4113             case Qt::Key_Backspace:
4114                 if (!m_readOnly) {
4115                     backspace();
4116                 }
4117                 break;
4118             default:
4119                 if (!handled)
4120                     unknown = true;
4121             }
4122         }
4123     }
4124
4125     if (event->key() == Qt::Key_Direction_L || event->key() == Qt::Key_Direction_R) {
4126         setLayoutDirection((event->key() == Qt::Key_Direction_L) ? Qt::LeftToRight : Qt::RightToLeft);
4127         unknown = false;
4128     }
4129
4130     if (unknown && !m_readOnly) {
4131         QString t = event->text();
4132         if (!t.isEmpty() && t.at(0).isPrint()) {
4133             insert(t);
4134             event->accept();
4135             return;
4136         }
4137     }
4138
4139     if (unknown)
4140         event->ignore();
4141     else
4142         event->accept();
4143 }
4144
4145
4146 QT_END_NAMESPACE
4147