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