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