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